aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriains <iains@138bc75d-0d04-0410-961f-82ee72b054a4>2019-10-14 09:28:45 +0000
committeriains <iains@138bc75d-0d04-0410-961f-82ee72b054a4>2019-10-14 09:28:45 +0000
commit141de8c42dac86ecb74cdde1bf3d404047713bda (patch)
tree52692a6e37fbd9707690fdae682f66650c3c59c1
parentf956f06189641260c728bf2ed9195d5bca7e9391 (diff)
parentbb3f72175a401d6956b711b4a867ff058a1dcb8c (diff)
c++-coroutines - merge trunk r276952.c++-coroutines
2019-10-14 Iain Sandoe <iain@sandoe.co.uk> Merge trunk r276952. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/c++-coroutines@276957 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--ChangeLog5
-rw-r--r--ChangeLog.coroutines4
-rw-r--r--MAINTAINERS1
-rw-r--r--gcc/ChangeLog841
-rw-r--r--gcc/DATESTAMP2
-rw-r--r--gcc/Makefile.in2
-rw-r--r--gcc/REVISION2
-rw-r--r--gcc/ada/ChangeLog280
-rw-r--r--gcc/ada/atree.adb24
-rw-r--r--gcc/ada/atree.ads21
-rw-r--r--gcc/ada/bindgen.adb104
-rw-r--r--gcc/ada/doc/gnat_ugn/about_this_guide.rst6
-rw-r--r--gcc/ada/doc/gnat_ugn/building_executable_programs_with_gnat.rst4
-rw-r--r--gcc/ada/doc/gnat_ugn/getting_started_with_gnat.rst6
-rw-r--r--gcc/ada/doc/gnat_ugn/gnat_and_program_execution.rst4
-rw-r--r--gcc/ada/einfo.adb15
-rw-r--r--gcc/ada/einfo.ads13
-rw-r--r--gcc/ada/errout.ads4
-rw-r--r--gcc/ada/exp_ch3.adb3
-rw-r--r--gcc/ada/exp_ch4.adb6
-rw-r--r--gcc/ada/exp_ch6.adb7
-rw-r--r--gcc/ada/exp_ch7.adb462
-rw-r--r--gcc/ada/exp_ch9.adb7
-rw-r--r--gcc/ada/exp_util.adb14
-rw-r--r--gcc/ada/freeze.adb1
-rw-r--r--gcc/ada/gcc-interface/decl.c73
-rw-r--r--gcc/ada/gcc-interface/trans.c33
-rw-r--r--gcc/ada/gcc-interface/utils.c15
-rw-r--r--gcc/ada/gnat1drv.adb18
-rw-r--r--gcc/ada/gnat_ugn.texi22
-rw-r--r--gcc/ada/gnatls.adb5
-rw-r--r--gcc/ada/impunit.adb4
-rw-r--r--gcc/ada/inline.adb126
-rw-r--r--gcc/ada/lib-writ.ads3
-rw-r--r--gcc/ada/libgnat/a-cbdlli.adb6
-rw-r--r--gcc/ada/libgnat/a-cbhama.adb10
-rw-r--r--gcc/ada/libgnat/a-cbhase.adb10
-rw-r--r--gcc/ada/libgnat/a-cbmutr.adb6
-rw-r--r--gcc/ada/libgnat/a-cborma.adb10
-rw-r--r--gcc/ada/libgnat/a-cborse.adb10
-rw-r--r--gcc/ada/libgnat/a-cdlili.adb6
-rw-r--r--gcc/ada/libgnat/a-cidlli.adb6
-rw-r--r--gcc/ada/libgnat/a-cihama.adb10
-rw-r--r--gcc/ada/libgnat/a-cihase.adb10
-rw-r--r--gcc/ada/libgnat/a-cimutr.adb6
-rw-r--r--gcc/ada/libgnat/a-ciorma.adb10
-rw-r--r--gcc/ada/libgnat/a-ciorse.adb10
-rw-r--r--gcc/ada/libgnat/a-cobove.adb10
-rw-r--r--gcc/ada/libgnat/a-cohama.adb10
-rw-r--r--gcc/ada/libgnat/a-cohase.adb10
-rw-r--r--gcc/ada/libgnat/a-coinve.adb10
-rw-r--r--gcc/ada/libgnat/a-comutr.adb6
-rw-r--r--gcc/ada/libgnat/a-conhel.adb4
-rw-r--r--gcc/ada/libgnat/a-convec.adb10
-rw-r--r--gcc/ada/libgnat/a-coorma.adb10
-rw-r--r--gcc/ada/libgnat/a-coorse.adb10
-rw-r--r--gcc/ada/libgnat/a-ststio.ads1
-rw-r--r--gcc/ada/libgnat/g-exptty.ads2
-rw-r--r--gcc/ada/opt.ads3
-rw-r--r--gcc/ada/rtsfind.adb62
-rw-r--r--gcc/ada/sem_aggr.adb57
-rw-r--r--gcc/ada/sem_cat.adb12
-rw-r--r--gcc/ada/sem_ch12.adb38
-rw-r--r--gcc/ada/sem_ch13.adb56
-rw-r--r--gcc/ada/sem_ch3.adb6
-rw-r--r--gcc/ada/sem_ch6.adb8
-rw-r--r--gcc/ada/sem_ch7.adb2
-rw-r--r--gcc/ada/sem_ch8.adb6
-rw-r--r--gcc/ada/sem_elab.adb16
-rw-r--r--gcc/ada/sem_prag.adb30
-rw-r--r--gcc/ada/sem_res.adb2
-rw-r--r--gcc/ada/sem_util.adb59
-rw-r--r--gcc/ada/sem_util.ads23
-rw-r--r--gcc/ada/sem_warn.adb14
-rw-r--r--gcc/ada/sinfo.adb38
-rw-r--r--gcc/ada/sinfo.ads21
-rw-r--r--gcc/ada/terminals.c2
-rw-r--r--gcc/ada/treepr.adb8
-rw-r--r--gcc/ada/treepr.ads4
-rw-r--r--gcc/builtins.c2
-rw-r--r--gcc/c-family/ChangeLog70
-rw-r--r--gcc/c-family/c-attribs.c15
-rw-r--r--gcc/c-family/c-common.c53
-rw-r--r--gcc/c-family/c-common.h5
-rw-r--r--gcc/c-family/c-cppbuiltin.c22
-rw-r--r--gcc/c-family/c-omp.c457
-rw-r--r--gcc/c-family/c-opts.c17
-rw-r--r--gcc/c-family/c.opt12
-rw-r--r--gcc/c/ChangeLog44
-rw-r--r--gcc/c/c-decl.c5
-rw-r--r--gcc/c/c-objc-common.c130
-rw-r--r--gcc/c/c-parser.c567
-rw-r--r--gcc/calls.c8
-rw-r--r--gcc/cgraph.c2
-rw-r--r--gcc/cgraph.h22
-rw-r--r--gcc/combine.c1
-rw-r--r--gcc/common.opt20
-rw-r--r--gcc/common/config/s390/s390-common.c4
-rw-r--r--gcc/config.gcc13
-rw-r--r--gcc/config.in6
-rw-r--r--gcc/config/alpha/alpha.c3
-rw-r--r--gcc/config/arm/arm.h5
-rw-r--r--gcc/config/avr/avr.md2
-rw-r--r--gcc/config/darwin-protos.h2
-rw-r--r--gcc/config/darwin.c510
-rw-r--r--gcc/config/darwin.h47
-rw-r--r--gcc/config/i386/darwin.h6
-rw-r--r--gcc/config/i386/i386-expand.c220
-rw-r--r--gcc/config/i386/i386-features.c63
-rw-r--r--gcc/config/i386/i386-protos.h6
-rw-r--r--gcc/config/i386/i386.c2
-rw-r--r--gcc/config/i386/predicates.md5
-rw-r--r--gcc/config/i386/sse.md13
-rw-r--r--gcc/config/msp430/constraints.md10
-rw-r--r--gcc/config/msp430/driver-msp430.c13
-rw-r--r--gcc/config/msp430/msp430-protos.h2
-rw-r--r--gcc/config/msp430/msp430.c243
-rw-r--r--gcc/config/msp430/msp430.h13
-rw-r--r--gcc/config/msp430/msp430.md262
-rw-r--r--gcc/config/msp430/msp430.opt12
-rw-r--r--gcc/config/msp430/predicates.md10
-rw-r--r--gcc/config/msp430/t-msp43011
-rw-r--r--gcc/config/pa/pa.c165
-rw-r--r--gcc/config/pa/pa.h2
-rw-r--r--gcc/config/rs6000/darwin.h3
-rw-r--r--gcc/config/rs6000/rs6000.c51
-rw-r--r--gcc/config/s390/2827.md14
-rw-r--r--gcc/config/s390/2964.md13
-rw-r--r--gcc/config/s390/3906.md17
-rw-r--r--gcc/config/s390/8561.md111
-rw-r--r--gcc/config/s390/driver-native.c4
-rw-r--r--gcc/config/s390/s390-builtins.def18
-rw-r--r--gcc/config/s390/s390-c.c15
-rw-r--r--gcc/config/s390/s390-modes.def8
-rw-r--r--gcc/config/s390/s390-opts.h2
-rw-r--r--gcc/config/s390/s390-protos.h1
-rw-r--r--gcc/config/s390/s390.c160
-rw-r--r--gcc/config/s390/s390.h18
-rw-r--r--gcc/config/s390/s390.md183
-rw-r--r--gcc/config/s390/s390.opt5
-rw-r--r--gcc/config/s390/vector.md195
-rw-r--r--gcc/config/s390/vx-builtins.md6
-rw-r--r--gcc/config/sh/sh.c8
-rw-r--r--gcc/config/sh/sh.h2
-rw-r--r--gcc/config/sh/sh.md90
-rwxr-xr-xgcc/configure99
-rw-r--r--gcc/configure.ac28
-rw-r--r--gcc/cp/ChangeLog596
-rw-r--r--gcc/cp/call.c260
-rw-r--r--gcc/cp/class.c3
-rw-r--r--gcc/cp/config-lang.in1
-rw-r--r--gcc/cp/constexpr.c26
-rw-r--r--gcc/cp/constraint.cc3739
-rw-r--r--gcc/cp/cp-gimplify.c25
-rw-r--r--gcc/cp/cp-objcp-common.c9
-rw-r--r--gcc/cp/cp-tree.def71
-rw-r--r--gcc/cp/cp-tree.h372
-rw-r--r--gcc/cp/cxx-pretty-print.c197
-rw-r--r--gcc/cp/decl.c179
-rw-r--r--gcc/cp/decl2.c16
-rw-r--r--gcc/cp/error.c202
-rw-r--r--gcc/cp/lambda.c4
-rw-r--r--gcc/cp/logic.cc1183
-rw-r--r--gcc/cp/method.c7
-rw-r--r--gcc/cp/name-lookup.c11
-rw-r--r--gcc/cp/parser.c1500
-rw-r--r--gcc/cp/parser.h3
-rw-r--r--gcc/cp/pt.c964
-rw-r--r--gcc/cp/search.c5
-rw-r--r--gcc/cp/semantics.c64
-rw-r--r--gcc/cp/typeck.c225
-rw-r--r--gcc/cp/typeck2.c5
-rw-r--r--gcc/diagnostic-color.c20
-rw-r--r--gcc/diagnostic-format-json.cc11
-rw-r--r--gcc/diagnostic-url.h36
-rw-r--r--gcc/diagnostic.c25
-rw-r--r--gcc/diagnostic.h7
-rw-r--r--gcc/doc/avr-mmcu.texi2
-rw-r--r--gcc/doc/extend.texi27
-rw-r--r--gcc/doc/invoke.texi84
-rw-r--r--gcc/doc/lto.texi9
-rw-r--r--gcc/doc/passes.texi272
-rw-r--r--gcc/doc/sourcebuild.texi3
-rw-r--r--gcc/expr.c3
-rw-r--r--gcc/fold-const.c3
-rw-r--r--gcc/fortran/ChangeLog92
-rw-r--r--gcc/fortran/array.c21
-rw-r--r--gcc/fortran/check.c165
-rw-r--r--gcc/fortran/decl.c16
-rw-r--r--gcc/fortran/expr.c3
-rw-r--r--gcc/fortran/f95-lang.c2
-rw-r--r--gcc/fortran/match.h2
-rw-r--r--gcc/fortran/openmp.c13
-rw-r--r--gcc/fortran/parse.c104
-rw-r--r--gcc/fortran/resolve.c45
-rw-r--r--gcc/fortran/simplify.c10
-rw-r--r--gcc/fortran/trans-decl.c3
-rw-r--r--gcc/fortran/trans-expr.c7
-rw-r--r--gcc/fortran/trans-openmp.c35
-rw-r--r--gcc/fortran/trans.h1
-rw-r--r--gcc/function-abi.cc29
-rw-r--r--gcc/function-abi.h1
-rw-r--r--gcc/gcc.c5
-rw-r--r--gcc/gengtype-lex.l2
-rw-r--r--gcc/ggc-none.c5
-rw-r--r--gcc/ggc-page.c45
-rw-r--r--gcc/ggc.h3
-rw-r--r--gcc/gimple-expr.c25
-rw-r--r--gcc/gimple-expr.h1
-rw-r--r--gcc/gimple-fold.c36
-rw-r--r--gcc/gimple-iterator.h31
-rw-r--r--gcc/gimple-ssa-sprintf.c44
-rw-r--r--gcc/gimple-streamer-out.c10
-rw-r--r--gcc/gimple.c14
-rw-r--r--gcc/gimplify.c5
-rw-r--r--gcc/ginclude/float.h47
-rw-r--r--gcc/go/gofrontend/MERGE2
-rw-r--r--gcc/go/gofrontend/go-encode-id.cc13
-rw-r--r--gcc/go/gofrontend/go-encode-id.h8
-rw-r--r--gcc/go/gofrontend/gogo.cc5
-rw-r--r--gcc/ipa-icf.c11
-rw-r--r--gcc/ipa-prop.c17
-rw-r--r--gcc/ipa-prop.h1
-rw-r--r--gcc/ipa-reference.c35
-rw-r--r--gcc/ira-lives.c86
-rw-r--r--gcc/langhooks-def.h2
-rw-r--r--gcc/langhooks.h9
-rw-r--r--gcc/lto-streamer-out.c110
-rw-r--r--gcc/lto-streamer.h1
-rw-r--r--gcc/lto/ChangeLog21
-rw-r--r--gcc/lto/lto-common.c13
-rw-r--r--gcc/lto/lto.c8
-rw-r--r--gcc/machmode.h87
-rw-r--r--gcc/match.pd58
-rw-r--r--gcc/objc/ChangeLog9
-rw-r--r--gcc/objc/objc-next-metadata-tags.h4
-rw-r--r--gcc/objc/objc-next-runtime-abi-02.c6
-rw-r--r--gcc/omp-general.c8
-rw-r--r--gcc/omp-general.h1
-rw-r--r--gcc/omp-low.c38
-rw-r--r--gcc/optabs-tree.c39
-rw-r--r--gcc/optabs.c19
-rw-r--r--gcc/optabs.h6
-rw-r--r--gcc/opts-diagnostic.h3
-rw-r--r--gcc/opts-global.c1
-rw-r--r--gcc/opts.c43
-rw-r--r--gcc/passes.c37
-rw-r--r--gcc/po/ChangeLog4
-rw-r--r--gcc/po/fi.po64
-rw-r--r--gcc/pretty-print.c65
-rw-r--r--gcc/pretty-print.h6
-rw-r--r--gcc/testsuite/ChangeLog477
-rw-r--r--gcc/testsuite/c-c++-common/Waddress-1.c8
-rw-r--r--gcc/testsuite/c-c++-common/Wpointer-compare-1.c40
-rw-r--r--gcc/testsuite/c-c++-common/Wshift-count-negative-1.c4
-rw-r--r--gcc/testsuite/c-c++-common/Wshift-count-overflow-1.c4
-rw-r--r--gcc/testsuite/c-c++-common/Wshift-negative-value-1.c6
-rw-r--r--gcc/testsuite/c-c++-common/Wshift-negative-value-2.c6
-rw-r--r--gcc/testsuite/c-c++-common/Wshift-negative-value-5.c6
-rw-r--r--gcc/testsuite/c-c++-common/diagnostic-format-json-2.c1
-rw-r--r--gcc/testsuite/c-c++-common/diagnostic-format-json-3.c1
-rw-r--r--gcc/testsuite/c-c++-common/diagnostic-format-json-4.c10
-rw-r--r--gcc/testsuite/c-c++-common/gomp/declare-variant-1.c54
-rw-r--r--gcc/testsuite/c-c++-common/gomp/declare-variant-2.c151
-rw-r--r--gcc/testsuite/c-c++-common/gomp/declare-variant-3.c141
-rw-r--r--gcc/testsuite/c-c++-common/gomp/declare-variant-4.c22
-rw-r--r--gcc/testsuite/c-c++-common/gomp/declare-variant-5.c36
-rw-r--r--gcc/testsuite/c-c++-common/gomp/declare-variant-6.c35
-rw-r--r--gcc/testsuite/c-c++-common/gomp/declare-variant-7.c37
-rw-r--r--gcc/testsuite/c-c++-common/gomp/pr91987.c26
-rw-r--r--gcc/testsuite/c-c++-common/pr48418.c16
-rw-r--r--gcc/testsuite/c-c++-common/pr65830.c8
-rw-r--r--gcc/testsuite/c-c++-common/pr69764.c12
-rw-r--r--gcc/testsuite/g++.dg/Wclass-memaccess-5.C18
-rw-r--r--gcc/testsuite/g++.dg/concepts/alias1.C16
-rw-r--r--gcc/testsuite/g++.dg/concepts/alias2.C14
-rw-r--r--gcc/testsuite/g++.dg/concepts/alias3.C14
-rw-r--r--gcc/testsuite/g++.dg/concepts/alias4.C20
-rw-r--r--gcc/testsuite/g++.dg/concepts/auto1.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/auto3.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/auto4.C4
-rw-r--r--gcc/testsuite/g++.dg/concepts/class-deduction1.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/class.C53
-rw-r--r--gcc/testsuite/g++.dg/concepts/class1.C15
-rw-r--r--gcc/testsuite/g++.dg/concepts/class2.C15
-rw-r--r--gcc/testsuite/g++.dg/concepts/class3.C15
-rw-r--r--gcc/testsuite/g++.dg/concepts/class4.C22
-rw-r--r--gcc/testsuite/g++.dg/concepts/class5.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/class6.C4
-rw-r--r--gcc/testsuite/g++.dg/concepts/debug1.C8
-rw-r--r--gcc/testsuite/g++.dg/concepts/decl-diagnose.C8
-rw-r--r--gcc/testsuite/g++.dg/concepts/deduction-constraint1.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/diagnostic1.C12
-rw-r--r--gcc/testsuite/g++.dg/concepts/disjunction1.C60
-rw-r--r--gcc/testsuite/g++.dg/concepts/dr1430.C9
-rw-r--r--gcc/testsuite/g++.dg/concepts/equiv.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/equiv2.C12
-rw-r--r--gcc/testsuite/g++.dg/concepts/explicit-inst4.C18
-rw-r--r--gcc/testsuite/g++.dg/concepts/explicit-spec3.C14
-rw-r--r--gcc/testsuite/g++.dg/concepts/expression.C12
-rw-r--r--gcc/testsuite/g++.dg/concepts/expression2.C12
-rw-r--r--gcc/testsuite/g++.dg/concepts/expression3.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/feature-macro.C6
-rw-r--r--gcc/testsuite/g++.dg/concepts/fn-concept1.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/fn-concept2.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/fn-generic-member-ool.C1
-rw-r--r--gcc/testsuite/g++.dg/concepts/fn1.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/fn10.C4
-rw-r--r--gcc/testsuite/g++.dg/concepts/fn2.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/fn3.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/fn4.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/fn5.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/fn6.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/fn7.C4
-rw-r--r--gcc/testsuite/g++.dg/concepts/fn8.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/fn9.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/generic-fn-err.C8
-rw-r--r--gcc/testsuite/g++.dg/concepts/generic-fn.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/iconv1.C21
-rw-r--r--gcc/testsuite/g++.dg/concepts/inherit-ctor1.C28
-rw-r--r--gcc/testsuite/g++.dg/concepts/inherit-ctor3.C9
-rw-r--r--gcc/testsuite/g++.dg/concepts/inherit-ctor4.C19
-rw-r--r--gcc/testsuite/g++.dg/concepts/intro1.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/intro2.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/intro3.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/intro4.C12
-rw-r--r--gcc/testsuite/g++.dg/concepts/intro5.C9
-rw-r--r--gcc/testsuite/g++.dg/concepts/intro6.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/intro7.C6
-rw-r--r--gcc/testsuite/g++.dg/concepts/locations1.C4
-rw-r--r--gcc/testsuite/g++.dg/concepts/memtmpl1.C16
-rw-r--r--gcc/testsuite/g++.dg/concepts/partial-concept-id1.C33
-rw-r--r--gcc/testsuite/g++.dg/concepts/partial-concept-id2.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/partial-spec5.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/placeholder1.C35
-rw-r--r--gcc/testsuite/g++.dg/concepts/placeholder2.C23
-rw-r--r--gcc/testsuite/g++.dg/concepts/placeholder3.C6
-rw-r--r--gcc/testsuite/g++.dg/concepts/placeholder4.C6
-rw-r--r--gcc/testsuite/g++.dg/concepts/placeholder5.C8
-rw-r--r--gcc/testsuite/g++.dg/concepts/placeholder6.C7
-rw-r--r--gcc/testsuite/g++.dg/concepts/pr65634.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/pr65636.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/pr65681.C65
-rw-r--r--gcc/testsuite/g++.dg/concepts/pr65848.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/pr67249.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/pr67544.C3
-rw-r--r--gcc/testsuite/g++.dg/concepts/pr67595.C8
-rw-r--r--gcc/testsuite/g++.dg/concepts/pr67655.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/pr68434.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/pr71127.C7
-rw-r--r--gcc/testsuite/g++.dg/concepts/pr71128.C4
-rw-r--r--gcc/testsuite/g++.dg/concepts/pr71131.C7
-rw-r--r--gcc/testsuite/g++.dg/concepts/pr71385.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/pr84330.C7
-rw-r--r--gcc/testsuite/g++.dg/concepts/pr85065.C6
-rw-r--r--gcc/testsuite/g++.dg/concepts/req-neg1.C11
-rw-r--r--gcc/testsuite/g++.dg/concepts/req1.C29
-rw-r--r--gcc/testsuite/g++.dg/concepts/req10.C19
-rw-r--r--gcc/testsuite/g++.dg/concepts/req11.C29
-rw-r--r--gcc/testsuite/g++.dg/concepts/req12.C26
-rw-r--r--gcc/testsuite/g++.dg/concepts/req13.C14
-rw-r--r--gcc/testsuite/g++.dg/concepts/req16.C20
-rw-r--r--gcc/testsuite/g++.dg/concepts/req18.C18
-rw-r--r--gcc/testsuite/g++.dg/concepts/req19.C14
-rw-r--r--gcc/testsuite/g++.dg/concepts/req2.C20
-rw-r--r--gcc/testsuite/g++.dg/concepts/req20.C21
-rw-r--r--gcc/testsuite/g++.dg/concepts/req3.C17
-rw-r--r--gcc/testsuite/g++.dg/concepts/req4.C19
-rw-r--r--gcc/testsuite/g++.dg/concepts/req5.C19
-rw-r--r--gcc/testsuite/g++.dg/concepts/req6.C19
-rw-r--r--gcc/testsuite/g++.dg/concepts/req7.C25
-rw-r--r--gcc/testsuite/g++.dg/concepts/req8.C17
-rw-r--r--gcc/testsuite/g++.dg/concepts/req9.C25
-rw-r--r--gcc/testsuite/g++.dg/concepts/template-parm1.C35
-rw-r--r--gcc/testsuite/g++.dg/concepts/template-parm10.C18
-rw-r--r--gcc/testsuite/g++.dg/concepts/template-parm11.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/template-parm12.C4
-rw-r--r--gcc/testsuite/g++.dg/concepts/template-parm2.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/template-parm3.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/template-parm4.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/template-parm5.C20
-rw-r--r--gcc/testsuite/g++.dg/concepts/template-parm6.C42
-rw-r--r--gcc/testsuite/g++.dg/concepts/template-parm7.C45
-rw-r--r--gcc/testsuite/g++.dg/concepts/template-parm9.C19
-rw-r--r--gcc/testsuite/g++.dg/concepts/template-template-parm1.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/var-concept1.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/var-concept2.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/var-concept3.C15
-rw-r--r--gcc/testsuite/g++.dg/concepts/var-concept4.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/var-concept5.C6
-rw-r--r--gcc/testsuite/g++.dg/concepts/var-concept6.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/var-concept7.C4
-rw-r--r--gcc/testsuite/g++.dg/concepts/var-templ1.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/var-templ2.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/var-templ3.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/variadic1.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/variadic2.C9
-rw-r--r--gcc/testsuite/g++.dg/concepts/variadic3.C2
-rw-r--r--gcc/testsuite/g++.dg/concepts/variadic4.C11
-rw-r--r--gcc/testsuite/g++.dg/conversion/qual1.C51
-rw-r--r--gcc/testsuite/g++.dg/conversion/qual2.C14
-rw-r--r--gcc/testsuite/g++.dg/conversion/qual3.C53
-rw-r--r--gcc/testsuite/g++.dg/conversion/ref2.C29
-rw-r--r--gcc/testsuite/g++.dg/conversion/ref3.C4
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/auto52.C2
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr10.C16
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/initlist-array1.C (renamed from gcc/testsuite/g++.dg/cpp0x/initlist-arrray1.C)0
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/initlist-array3.C3
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/initlist-array7.C21
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/initlist-array8.C35
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/lambda/lambda-err2.C2
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/nullptr37.C72
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/scoped_enum10.C37
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/scoped_enum11.C35
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/scoped_enum9.C11
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/eval-order6.C20
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/eval-order7.C23
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/eval-order8.C20
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/array-conv1.C33
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/array-conv10.C22
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/array-conv11.C23
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/array-conv12.C12
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/array-conv13.C17
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/array-conv14.C17
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/array-conv15.C23
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/array-conv16.C16
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/array-conv17.C39
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/array-conv2.C26
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/array-conv3.C26
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/array-conv4.C24
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/array-conv5.C24
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/array-conv6.C28
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/array-conv7.C34
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/array-conv8.C26
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/array-conv9.C27
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-access1.C15
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-alias.C25
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-alias2.C12
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-class.C115
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-cmath.C4
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-complete1.C11
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-constrained-parm.C (renamed from gcc/testsuite/g++.dg/concepts/constrained-parm.C)5
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-decltype.C67
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-defarg1.C7
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-dep1.C5
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-dr1430.C14
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-explicit-inst1.C (renamed from gcc/testsuite/g++.dg/concepts/explicit-inst1.C)11
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-explicit-inst2.C (renamed from gcc/testsuite/g++.dg/concepts/explicit-inst2.C)7
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-explicit-inst3.C (renamed from gcc/testsuite/g++.dg/concepts/explicit-inst3.C)13
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-explicit-inst4.C17
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-explicit-spec1.C (renamed from gcc/testsuite/g++.dg/concepts/explicit-spec1.C)7
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-explicit-spec2.C (renamed from gcc/testsuite/g++.dg/concepts/explicit-spec2.C)5
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-explicit-spec3.C13
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-explicit-spec4.C (renamed from gcc/testsuite/g++.dg/concepts/explicit-spec4.C)13
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-explicit-spec5.C (renamed from gcc/testsuite/g++.dg/concepts/explicit-spec5.C)9
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-explicit-spec6.C (renamed from gcc/testsuite/g++.dg/concepts/explicit-spec6.C)3
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-feature-macro.C5
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-fn1.C248
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-fn2.C111
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-fn3.C49
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-fnparm1.C10
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-friend1.C (renamed from gcc/testsuite/g++.dg/concepts/friend1.C)7
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-friend2.C (renamed from gcc/testsuite/g++.dg/concepts/friend2.C)5
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-friend3.C20
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-iconv1.C22
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor2.C (renamed from gcc/testsuite/g++.dg/concepts/inherit-ctor2.C)7
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor4.C18
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor5.C18
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-lambda1.C (renamed from gcc/testsuite/g++.dg/concepts/lambda1.C)15
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-locations1.C22
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-member-concept.C21
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-memfun-err.C (renamed from gcc/testsuite/g++.dg/concepts/memfun-err.C)16
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-memfun.C (renamed from gcc/testsuite/g++.dg/concepts/memfun.C)45
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-memtmpl1.C17
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-memtmpl2.C15
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-nested1.C13
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-noexcept1.C25
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-p1141.C98
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec.C (renamed from gcc/testsuite/g++.dg/concepts/partial-spec.C)2
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec2.C (renamed from gcc/testsuite/g++.dg/concepts/partial-spec2.C)15
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec3.C (renamed from gcc/testsuite/g++.dg/concepts/partial-spec3.C)2
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec4.C (renamed from gcc/testsuite/g++.dg/concepts/partial-spec4.C)5
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec5.C12
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec6.C (renamed from gcc/testsuite/g++.dg/concepts/partial-spec6.C)7
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-placeholder1.C14
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr58500.C (renamed from gcc/testsuite/g++.dg/concepts/pr58500.C)0
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr58534.C (renamed from gcc/testsuite/g++.dg/concepts/pr58534.C)0
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr58535.C (renamed from gcc/testsuite/g++.dg/concepts/pr58535.C)0
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr58536.C (renamed from gcc/testsuite/g++.dg/concepts/pr58536.C)0
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr58548.C (renamed from gcc/testsuite/g++.dg/concepts/pr58548.C)0
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr58549.C (renamed from gcc/testsuite/g++.dg/concepts/pr58549.C)0
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr59200.C (renamed from gcc/testsuite/g++.dg/concepts/regress/alias-decl-42.C)3
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr60052.C (renamed from gcc/testsuite/g++.dg/concepts/pr60052.C)0
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr60053.C (renamed from gcc/testsuite/g++.dg/concepts/pr60053.C)0
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr60064.C (renamed from gcc/testsuite/g++.dg/concepts/pr60064.C)0
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr60065.C (renamed from gcc/testsuite/g++.dg/concepts/pr60065.C)0
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr60377.C (renamed from gcc/testsuite/g++.dg/concepts/pr60377.C)0
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr60390.C (renamed from gcc/testsuite/g++.dg/concepts/pr60390.C)0
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr60391.C (renamed from gcc/testsuite/g++.dg/concepts/pr60391.C)0
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr60573.C (renamed from gcc/testsuite/g++.dg/concepts/pr60573.C)0
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr65552.C (renamed from gcc/testsuite/g++.dg/concepts/pr65552.C)8
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr65575.C (renamed from gcc/testsuite/g++.dg/concepts/pr65575.C)11
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr65634.C18
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr65636.C8
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr65848.C59
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr65854.C (renamed from gcc/testsuite/g++.dg/concepts/pr65854.C)11
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr66091.C (renamed from gcc/testsuite/g++.dg/concepts/pr66091.C)5
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr66844.C16
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr66962.C80
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr67070.C51
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr67147.C25
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr67148.C121
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr67178.C26
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr67210.C10
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr67217.C8
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr67225-1.C32
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr67225-2.C36
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr67225-3.C21
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr67225-4.C14
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr67225-5.C17
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr67319.C24
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr67427.C22
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr67654.C30
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr67658.C14
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr67684.C63
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr67685.C7
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr67692.C13
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr67697.C15
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr67719.C15
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr67774.C26
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr67825.C20
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr67860.C61
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr67862.C162
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr67969.C32
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr68093-1.C13
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr68093-2.C14
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr68372.C48
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr68434.C18
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr68683.C (renamed from gcc/testsuite/g++.dg/concepts/pr68683.C)8
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr68812.C34
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr69235.C48
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr71368.C (renamed from gcc/testsuite/g++.dg/concepts/pr71368.C)12
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr71385.C14
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr71965.C (renamed from gcc/testsuite/g++.dg/concepts/pr71965.C)11
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr72415.C (renamed from gcc/testsuite/g++.dg/concepts/memfun2.C)2
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr78752.C18
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr79759.C7
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr80471.C (renamed from gcc/testsuite/g++.dg/concepts/pr80471.C)0
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr80746.C14
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr80773.C33
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr82507.C17
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr82740.C32
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr84140.C38
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr84551.C11
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-2.C (renamed from gcc/testsuite/g++.dg/concepts/pr84979-2.C)0
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-3.C (renamed from gcc/testsuite/g++.dg/concepts/pr84979-3.C)0
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr84979.C (renamed from gcc/testsuite/g++.dg/concepts/pr84979.C)0
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr84980.C (renamed from gcc/testsuite/g++.dg/concepts/pr84980.C)4
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr85265.C (renamed from gcc/testsuite/g++.dg/concepts/pr85265.C)3
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr85706.C (renamed from gcc/testsuite/g++.dg/concepts/class-deduction2.C)0
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr85808.C19
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr86269.C19
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr87441.C10
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-requires1.C71
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-requires10.C32
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-requires11.C (renamed from gcc/testsuite/g++.dg/concepts/req17.C)10
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-requires12.C21
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-requires13.C20
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-requires14.C24
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-requires15.C15
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-requires16.C47
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-requires17.C11
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-requires2.C74
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-requires3.C32
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-requires4.C15
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-requires5.C45
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-requires6.C34
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-requires7.C (renamed from gcc/testsuite/g++.dg/concepts/req14.C)9
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-requires8.C17
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-requires9.C (renamed from gcc/testsuite/g++.dg/concepts/req15.C)3
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-sfinae1.C10
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-template-parm1.C19
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-template-parm10.C10
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-template-parm2.C15
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-template-parm5.C9
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-template-parm6.C44
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-template-parm8.C (renamed from gcc/testsuite/g++.dg/concepts/template-parm8.C)11
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-template-parm9.C18
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-traits1.C (renamed from gcc/testsuite/g++.dg/concepts/traits1.C)41
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-traits2.C (renamed from gcc/testsuite/g++.dg/concepts/traits2.C)41
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-ts1.C49
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-ts2.C260
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-ts3.C251
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-ts4.C34
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-ts5.C (renamed from gcc/testsuite/g++.dg/concepts/member-concept.C)4
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-ts6.C72
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-using1.C17
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts.C57
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts1.C27
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts2.C69
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts3.C48
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts4.C10
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/cond-triv2.C30
-rw-r--r--gcc/testsuite/g++.dg/diagnostic/not-a-function-template-1.C9
-rw-r--r--gcc/testsuite/g++.dg/expr/cond17.C11
-rw-r--r--gcc/testsuite/g++.dg/gomp/this-1.C4
-rw-r--r--gcc/testsuite/g++.dg/pr92022.C13
-rw-r--r--gcc/testsuite/g++.dg/template/builtin2.C5
-rw-r--r--gcc/testsuite/g++.dg/template/crash107.C4
-rw-r--r--gcc/testsuite/g++.dg/template/crash126.C2
-rw-r--r--gcc/testsuite/g++.dg/template/crash129.C2
-rw-r--r--gcc/testsuite/g++.dg/template/dependent-expr1.C8
-rw-r--r--gcc/testsuite/g++.dg/template/error17.C2
-rw-r--r--gcc/testsuite/g++.dg/warn/Wextra-3.C8
-rw-r--r--gcc/testsuite/g++.dg/warn/Wfloat-equal-1.C8
-rw-r--r--gcc/testsuite/g++.dg/warn/Wstring-literal-comparison-1.C2
-rw-r--r--gcc/testsuite/g++.dg/warn/Wstring-literal-comparison-2.C2
-rw-r--r--gcc/testsuite/g++.dg/warn/pointer-integer-comparison.C12
-rw-r--r--gcc/testsuite/g++.old-deja/g++.bugs/900321_01.C2
-rw-r--r--gcc/testsuite/g++.old-deja/g++.jason/crash8.C2
-rw-r--r--gcc/testsuite/gcc.c-torture/compile/pr92063.c7
-rw-r--r--gcc/testsuite/gcc.dg/Wstring-compare-2.c127
-rw-r--r--gcc/testsuite/gcc.dg/Wstring-compare.c181
-rw-r--r--gcc/testsuite/gcc.dg/Wstringop-overflow-12.c2
-rw-r--r--gcc/testsuite/gcc.dg/Wstringop-overflow-19.c27
-rw-r--r--gcc/testsuite/gcc.dg/builtins-18.c1
-rw-r--r--gcc/testsuite/gcc.dg/builtins-20.c1
-rw-r--r--gcc/testsuite/gcc.dg/builtins-53.c1
-rw-r--r--gcc/testsuite/gcc.dg/builtins-55.c1
-rw-r--r--gcc/testsuite/gcc.dg/builtins-67.c1
-rw-r--r--gcc/testsuite/gcc.dg/c11-float-dfp-1.c5
-rw-r--r--gcc/testsuite/gcc.dg/c2x-float-no-dfp-1.c101
-rw-r--r--gcc/testsuite/gcc.dg/c2x-float-no-dfp-2.c9
-rw-r--r--gcc/testsuite/gcc.dg/c99-tgmath-1.c1
-rw-r--r--gcc/testsuite/gcc.dg/c99-tgmath-2.c1
-rw-r--r--gcc/testsuite/gcc.dg/c99-tgmath-3.c1
-rw-r--r--gcc/testsuite/gcc.dg/c99-tgmath-4.c1
-rw-r--r--gcc/testsuite/gcc.dg/dfp/c11-constants-1.c13
-rw-r--r--gcc/testsuite/gcc.dg/dfp/c11-constants-2.c13
-rw-r--r--gcc/testsuite/gcc.dg/dfp/c11-keywords-1.c7
-rw-r--r--gcc/testsuite/gcc.dg/dfp/c11-keywords-2.c7
-rw-r--r--gcc/testsuite/gcc.dg/dfp/c2x-constants-1.c13
-rw-r--r--gcc/testsuite/gcc.dg/dfp/c2x-constants-2.c13
-rw-r--r--gcc/testsuite/gcc.dg/dfp/c2x-float-dfp-1.c103
-rw-r--r--gcc/testsuite/gcc.dg/dfp/c2x-float-dfp-2.c8
-rw-r--r--gcc/testsuite/gcc.dg/dfp/c2x-float-dfp-3.c103
-rw-r--r--gcc/testsuite/gcc.dg/dfp/c2x-keywords-1.c7
-rw-r--r--gcc/testsuite/gcc.dg/dfp/c2x-keywords-2.c7
-rw-r--r--gcc/testsuite/gcc.dg/dfp/constants-c99.c2
-rw-r--r--gcc/testsuite/gcc.dg/dfp/constants-pedantic.c14
-rw-r--r--gcc/testsuite/gcc.dg/dfp/keywords-c89.c4
-rw-r--r--gcc/testsuite/gcc.dg/dfp/keywords-c99.c4
-rw-r--r--gcc/testsuite/gcc.dg/dfp/keywords-ignored-c99.c15
-rw-r--r--gcc/testsuite/gcc.dg/dfp/tr24732-float-dfp-1.c106
-rw-r--r--gcc/testsuite/gcc.dg/dfp/ts18661-2-float-dfp-1.c8
-rw-r--r--gcc/testsuite/gcc.dg/diag-aka-5.h22
-rw-r--r--gcc/testsuite/gcc.dg/diag-aka-5a.c135
-rw-r--r--gcc/testsuite/gcc.dg/diag-aka-5b.c134
-rw-r--r--gcc/testsuite/gcc.dg/gomp/declare-variant-1.c41
-rw-r--r--gcc/testsuite/gcc.dg/gomp/declare-variant-2.c22
-rw-r--r--gcc/testsuite/gcc.dg/ipa/inline-8.c1
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-icf-5.c1
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-icf-7.c1
-rw-r--r--gcc/testsuite/gcc.dg/nextafter-2.c1
-rw-r--r--gcc/testsuite/gcc.dg/pr42427.c1
-rw-r--r--gcc/testsuite/gcc.dg/pr78965.c1
-rw-r--r--gcc/testsuite/gcc.dg/pr91860-1.c18
-rw-r--r--gcc/testsuite/gcc.dg/pr91860-2.c13
-rw-r--r--gcc/testsuite/gcc.dg/pr91860-3.c15
-rw-r--r--gcc/testsuite/gcc.dg/pr91860-4.c24
-rw-r--r--gcc/testsuite/gcc.dg/single-precision-constant.c1
-rw-r--r--gcc/testsuite/gcc.dg/strcmpopt_3.c20
-rw-r--r--gcc/testsuite/gcc.dg/strcmpopt_6.c207
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-65.c53
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-66.c38
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-69.c126
-rw-r--r--gcc/testsuite/gcc.dg/torture/20191011-1.c32
-rw-r--r--gcc/testsuite/gcc.dg/torture/builtin-convert-1.c1
-rw-r--r--gcc/testsuite/gcc.dg/torture/builtin-convert-2.c1
-rw-r--r--gcc/testsuite/gcc.dg/torture/builtin-convert-3.c1
-rw-r--r--gcc/testsuite/gcc.dg/torture/builtin-convert-4.c1
-rw-r--r--gcc/testsuite/gcc.dg/torture/builtin-fp-int-inexact-c2x.c6
-rw-r--r--gcc/testsuite/gcc.dg/torture/builtin-fp-int-inexact.c1
-rw-r--r--gcc/testsuite/gcc.dg/torture/builtin-integral-1.c1
-rw-r--r--gcc/testsuite/gcc.dg/torture/builtin-power-1.c1
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/copy-sign-1.c1
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/evrp4.c2
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/minmax-2.c1
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/mult-abs-2.c1
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/popcount4.c22
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/popcount4l.c30
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/popcount4ll.c19
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/redundant-assign-zero-1.c2
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/redundant-assign-zero-2.c2
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-82.c25
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-83.c32
-rw-r--r--gcc/testsuite/gcc.dg/vect/pr65947-1.c2
-rw-r--r--gcc/testsuite/gcc.dg/vect/pr65947-13.c2
-rw-r--r--gcc/testsuite/gcc.dg/vect/pr65947-14.c2
-rw-r--r--gcc/testsuite/gcc.dg/vect/pr65947-4.c2
-rw-r--r--gcc/testsuite/gcc.dg/vect/pr80631-1.c2
-rw-r--r--gcc/testsuite/gcc.dg/vect/pr80631-2.c2
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-outer-call-1.c22
-rw-r--r--gcc/testsuite/gcc.target/aarch64/diag_aka_1.c5
-rw-r--r--gcc/testsuite/gcc.target/aarch64/torture/simd-abi-9.c2
-rw-r--r--gcc/testsuite/gcc.target/i386/20060512-1.c16
-rw-r--r--gcc/testsuite/gcc.target/i386/20060512-3.c7
-rw-r--r--gcc/testsuite/gcc.target/i386/387-builtin-fp-int-inexact.c1
-rw-r--r--gcc/testsuite/gcc.target/i386/387-rint-inline-1.c1
-rw-r--r--gcc/testsuite/gcc.target/i386/387-rint-inline-2.c1
-rw-r--r--gcc/testsuite/gcc.target/i386/conversion.c1
-rw-r--r--gcc/testsuite/gcc.target/i386/indirect-thunk-1.c2
-rw-r--r--gcc/testsuite/gcc.target/i386/indirect-thunk-2.c2
-rw-r--r--gcc/testsuite/gcc.target/i386/indirect-thunk-3.c2
-rw-r--r--gcc/testsuite/gcc.target/i386/indirect-thunk-4.c2
-rw-r--r--gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c2
-rw-r--r--gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c2
-rw-r--r--gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c2
-rw-r--r--gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c2
-rw-r--r--gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c2
-rw-r--r--gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c2
-rw-r--r--gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c2
-rw-r--r--gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c2
-rw-r--r--gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c2
-rw-r--r--gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c2
-rw-r--r--gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c2
-rw-r--r--gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c2
-rw-r--r--gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c2
-rw-r--r--gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c2
-rw-r--r--gcc/testsuite/gcc.target/i386/pr32219-2.c2
-rw-r--r--gcc/testsuite/gcc.target/i386/pr32219-3.c2
-rw-r--r--gcc/testsuite/gcc.target/i386/pr32219-4.c2
-rw-r--r--gcc/testsuite/gcc.target/i386/pr32219-7.c2
-rw-r--r--gcc/testsuite/gcc.target/i386/pr32219-8.c2
-rw-r--r--gcc/testsuite/gcc.target/i386/pr47312.c1
-rw-r--r--gcc/testsuite/gcc.target/i386/pr71801.c2
-rw-r--r--gcc/testsuite/gcc.target/i386/pr91994.c35
-rw-r--r--gcc/testsuite/gcc.target/i386/ret-thunk-14.c2
-rw-r--r--gcc/testsuite/gcc.target/i386/ret-thunk-15.c2
-rw-r--r--gcc/testsuite/gcc.target/i386/ret-thunk-9.c2
-rw-r--r--gcc/testsuite/gcc.target/i386/sse2-builtin-fp-int-inexact.c1
-rw-r--r--gcc/testsuite/gcc.target/i386/sse2-rint-inline-1.c1
-rw-r--r--gcc/testsuite/gcc.target/i386/sse2-rint-inline-2.c1
-rw-r--r--gcc/testsuite/gcc.target/i386/sse4_1-builtin-fp-int-inexact.c1
-rw-r--r--gcc/testsuite/gcc.target/i386/sse4_1-rint-inline.c1
-rw-r--r--gcc/testsuite/gcc.target/msp430/430x-insns.c1646
-rw-r--r--gcc/testsuite/gcc.target/msp430/data-attributes-2.c4
-rw-r--r--gcc/testsuite/gcc.target/msp430/msp430.exp8
-rw-r--r--gcc/testsuite/gcc.target/msp430/object-attributes-430.c14
-rw-r--r--gcc/testsuite/gcc.target/msp430/object-attributes-default.c16
-rw-r--r--gcc/testsuite/gcc.target/msp430/object-attributes-mlarge-any-region.c14
-rw-r--r--gcc/testsuite/gcc.target/msp430/object-attributes-mlarge.c15
-rw-r--r--gcc/testsuite/gcc.target/s390/s390.exp8
-rw-r--r--gcc/testsuite/gcc.target/s390/vector/vec-scalar-cmp-1.c8
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-double-quiet-eq.c8
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-double-quiet-ge.c8
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-double-quiet-gt.c8
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-double-quiet-le.c8
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-double-quiet-lt.c8
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-double-quiet-ordered.c10
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-double-quiet-uneq.c10
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-double-quiet-unordered.c11
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-eq-z13-finite.c10
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-eq-z13.c9
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-eq.c11
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-ge-z13-finite.c10
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-ge-z13.c9
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-ge.c8
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-gt-z13-finite.c10
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-gt-z13.c9
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-gt.c8
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-le-z13-finite.c10
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-le-z13.c9
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-le.c8
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-lt-z13-finite.c10
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-lt-z13.c9
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-lt.c8
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-ltgt-z13-finite.c9
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-ltgt-z13.c9
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-ltgt.c9
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-double-smax-z13.F9011
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-double-smax.F908
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-double-smin-z13.F9011
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-double-smin.F908
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-float-quiet-eq.c8
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-float-quiet-ge.c8
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-float-quiet-gt.c8
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-float-quiet-le.c8
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-float-quiet-lt.c8
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-float-quiet-ordered.c10
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-float-quiet-uneq.c10
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-float-quiet-unordered.c11
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-float-signaling-eq.c11
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-float-signaling-ge.c8
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-float-signaling-gt.c8
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-float-signaling-le.c8
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-float-signaling-lt.c8
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-float-signaling-ltgt.c9
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-fortran.h7
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-long-double-signaling-ge.c8
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-long-double-signaling-gt.c8
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-long-double-signaling-le.c8
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-long-double-signaling-lt.c8
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec.h43
-rw-r--r--gcc/testsuite/gfortran.dg/auto_in_equiv_3.f9063
-rw-r--r--gcc/testsuite/gfortran.dg/diagnostic-format-json-2.F901
-rw-r--r--gcc/testsuite/gfortran.dg/diagnostic-format-json-3.F901
-rw-r--r--gcc/testsuite/gfortran.dg/function_kinds_5.f901
-rw-r--r--gcc/testsuite/gfortran.dg/gnu_logical_2.f9012
-rw-r--r--gcc/testsuite/gfortran.dg/goacc/continuation-free-form.f954
-rw-r--r--gcc/testsuite/gfortran.dg/impure_assignment_2.f902
-rw-r--r--gcc/testsuite/gfortran.dg/minmaxloc_14.f9012
-rw-r--r--gcc/testsuite/gfortran.dg/pr81509_2.f902
-rw-r--r--gcc/testsuite/gfortran.dg/pr85543.f901
-rw-r--r--gcc/testsuite/gfortran.dg/pr91649.f9023
-rw-r--r--gcc/testsuite/gfortran.dg/pr91715.f905
-rw-r--r--gcc/testsuite/gfortran.dg/pr91801.f907
-rw-r--r--gcc/testsuite/gfortran.dg/pr92018.f908
-rw-r--r--gcc/testsuite/gfortran.dg/pr92019.f909
-rw-r--r--gcc/testsuite/gfortran.dg/pr92050.f9053
-rw-r--r--gcc/testsuite/gnat.dg/array38.adb11
-rw-r--r--gcc/testsuite/gnat.dg/array38_pkg.adb8
-rw-r--r--gcc/testsuite/gnat.dg/array38_pkg.ads18
-rw-r--r--gcc/testsuite/gnat.dg/specs/size_clause4.ads20
-rw-r--r--gcc/testsuite/jit.dg/test-error-array-bounds.c5
-rw-r--r--gcc/testsuite/lib/g++-dg.exp2
-rw-r--r--gcc/testsuite/lib/prune.exp2
-rw-r--r--gcc/testsuite/lib/target-supports.exp40
-rw-r--r--gcc/timevar.def5
-rw-r--r--gcc/toplev.c3
-rw-r--r--gcc/tree-dfa.c10
-rw-r--r--gcc/tree-dfa.h2
-rw-r--r--gcc/tree-eh.c19
-rw-r--r--gcc/tree-if-conv.c24
-rw-r--r--gcc/tree-sra.c4
-rw-r--r--gcc/tree-ssa-dse.c24
-rw-r--r--gcc/tree-ssa-dse.h36
-rw-r--r--gcc/tree-ssa-forwprop.c7
-rw-r--r--gcc/tree-ssa-math-opts.c2
-rw-r--r--gcc/tree-ssa-phiopt.c6
-rw-r--r--gcc/tree-ssa-sccvn.c114
-rw-r--r--gcc/tree-ssa-strlen.c692
-rw-r--r--gcc/tree-vect-data-refs.c23
-rw-r--r--gcc/tree-vect-loop.c874
-rw-r--r--gcc/tree-vect-patterns.c8
-rw-r--r--gcc/tree-vect-slp.c11
-rw-r--r--gcc/tree-vect-stmts.c131
-rw-r--r--gcc/tree-vectorizer.c2
-rw-r--r--gcc/tree-vectorizer.h30
-rw-r--r--gcc/tree-vrp.c277
-rw-r--r--gcc/tree-vrp.h28
-rw-r--r--libcpp/ChangeLog15
-rw-r--r--libcpp/expr.c17
-rw-r--r--libcpp/include/cpplib.h7
-rw-r--r--libcpp/init.c49
-rw-r--r--libgcc/ChangeLog9
-rw-r--r--libgcc/config/pa/lib2funcs.S12
-rw-r--r--libgcc/config/pa/milli64.S23
-rw-r--r--libgfortran/ChangeLog7
-rw-r--r--libgfortran/runtime/minimal.c260
-rw-r--r--libgomp/ChangeLog29
-rw-r--r--libgomp/target.c24
-rw-r--r--libgomp/testsuite/libgomp.fortran/fortran.exp6
-rw-r--r--libgomp/testsuite/libgomp.fortran/target-simd.f9026
-rw-r--r--libgomp/testsuite/libgomp.fortran/use_device_addr-1.f901196
-rw-r--r--libgomp/testsuite/libgomp.fortran/use_device_addr-2.f901196
-rw-r--r--libgomp/testsuite/libgomp.oacc-c-c++-common/data-firstprivate-1.c165
-rw-r--r--libgomp/testsuite/libgomp.oacc-fortran/fortran.exp6
-rw-r--r--libstdc++-v3/ChangeLog140
-rw-r--r--libstdc++-v3/doc/Makefile.am7
-rw-r--r--libstdc++-v3/doc/Makefile.in7
-rw-r--r--libstdc++-v3/doc/html/manual/documentation_hacking.html7
-rw-r--r--libstdc++-v3/doc/html/manual/memory.html2
-rw-r--r--libstdc++-v3/doc/xml/manual/allocator.xml3
-rw-r--r--libstdc++-v3/doc/xml/manual/documentation_hacking.xml9
-rw-r--r--libstdc++-v3/include/Makefile.am7
-rw-r--r--libstdc++-v3/include/Makefile.in7
-rw-r--r--libstdc++-v3/include/bits/charconv.h10
-rw-r--r--libstdc++-v3/include/precompiled/stdc++.h2
-rw-r--r--libstdc++-v3/include/std/concepts351
-rw-r--r--libstdc++-v3/include/std/type_traits11
-rw-r--r--libstdc++-v3/include/std/version3
-rw-r--r--libstdc++-v3/include/tr2/dynamic_bitset295
-rw-r--r--libstdc++-v3/include/tr2/dynamic_bitset.tcc2
-rwxr-xr-xlibstdc++-v3/scripts/create_testsuite_files2
-rw-r--r--libstdc++-v3/src/c++98/locale.cc73
-rw-r--r--libstdc++-v3/src/c++98/locale_init.cc3
-rw-r--r--libstdc++-v3/testsuite/23_containers/span/lwg3255.cc3
-rw-r--r--libstdc++-v3/testsuite/libstdc++-dg/conformance.exp1
-rw-r--r--libstdc++-v3/testsuite/std/concepts/concepts.callable/invocable.cc45
-rw-r--r--libstdc++-v3/testsuite/std/concepts/concepts.callable/regular_invocable.cc45
-rw-r--r--libstdc++-v3/testsuite/std/concepts/concepts.callable/relation.cc48
-rw-r--r--libstdc++-v3/testsuite/std/concepts/concepts.callable/strictweakorder.cc48
-rw-r--r--libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.arithmetic/floating_point.cc58
-rw-r--r--libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.arithmetic/integral.cc73
-rw-r--r--libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.arithmetic/signed_integral.cc73
-rw-r--r--libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.arithmetic/unsigned_integral.cc73
-rw-r--r--libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.assignable/1.cc85
-rw-r--r--libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.common/1.cc73
-rw-r--r--libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.commonref/1.cc71
-rw-r--r--libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.constructible/1.cc89
-rw-r--r--libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.convertible/1.cc77
-rw-r--r--libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.copyconstructible/1.cc63
-rw-r--r--libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.defaultconstructible/1.cc63
-rw-r--r--libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.derived/1.cc50
-rw-r--r--libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.destructible/1.cc57
-rw-r--r--libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.moveconstructible/1.cc63
-rw-r--r--libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.same/1.cc66
-rw-r--r--libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.swappable/swap.cc78
-rw-r--r--libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.swappable/swappable.cc38
-rw-r--r--libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.swappable/swappable_with.cc80
-rw-r--r--libstdc++-v3/testsuite/std/concepts/concepts.object/copyable.cc108
-rw-r--r--libstdc++-v3/testsuite/std/concepts/concepts.object/movable.cc81
-rw-r--r--libstdc++-v3/testsuite/std/concepts/concepts.object/regular.cc64
-rw-r--r--libstdc++-v3/testsuite/std/concepts/concepts.object/semiregular.cc51
-rw-r--r--libstdc++-v3/testsuite/tr2/dynamic_bitset/cmp.cc50
-rw-r--r--libstdc++-v3/testsuite/tr2/dynamic_bitset/cons.cc105
-rw-r--r--libstdc++-v3/testsuite/tr2/dynamic_bitset/copy.cc55
-rw-r--r--libstdc++-v3/testsuite/tr2/dynamic_bitset/move.cc53
-rw-r--r--libstdc++-v3/testsuite/tr2/dynamic_bitset/pr92059.cc36
920 files changed, 30801 insertions, 8868 deletions
diff --git a/ChangeLog b/ChangeLog
index fb901e4a39e..90413f57284 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2019-10-08 Thomas Schwinge <thomas@codesourcery.com>
+
+ * MAINTAINERS: Add back Trevor Smigiel; move into Write After
+ Approval section.
+
2019-10-01 Frederik Harwath <frederik@codesourcery.com>
* MAINTAINERS: Add myself to Write After Approval
diff --git a/ChangeLog.coroutines b/ChangeLog.coroutines
index a271b19e9dc..9c4d5683a57 100644
--- a/ChangeLog.coroutines
+++ b/ChangeLog.coroutines
@@ -1,3 +1,7 @@
+2019-10-14 Iain Sandoe <iain@sandoe.co.uk>
+
+ Merge trunk r276952.
+
2019-10-11 Iain Sandoe <iain@sandoe.co.uk>
libstdc++-v3/
diff --git a/MAINTAINERS b/MAINTAINERS
index bd6a7d44c5a..78f17c35e9e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -585,6 +585,7 @@ Sharad Singhai <singhai@google.com>
Johannes Singler <singler@kit.edu>
Franz Sirl <franz.sirl-kernel@lauterbach.com>
Jan Sjodin <jan.sjodin@amd.com>
+Trevor Smigiel <trevor_smigiel@playstation.sony.com>
Edward Smith-Rowland <3dw4rd@verizon.net>
Jayant Sonar <rsonar.jayant@gmail.com>
Anatoly Sokolov <aesok@post.ru>
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index ef1eb5973cc..e755803b12c 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,842 @@
+2019-10-14 Richard Sandiford <richard.sandiford@arm.com>
+
+ * function-abi.h (expr_callee_abi): Declare.
+ * function-abi.cc (expr_callee_abi): New function.
+
+2019-10-14 Aldy Hernandez <aldyh@redhat.com>
+
+ * tree-vrp.c (value_range_base::set): Normalize unsigned ~[0,0]
+ into [1,MAX].
+ * tree-vrp.h (value_range_base::nonzero_p): Adjust for unsigned
+ non-zero being represented as [1,MAX].
+
+2019-10-14 Xiong Hu Luo <luoxhu@linux.ibm.com>
+
+ * tree-sra.c (dump_access): Add missing braces.
+
+2019-10-13 Iain Sandoe <iain@sandoe.co.uk>
+
+ * config/darwin.c (machopic_indirection_name): Rework the
+ function to emit linker-visible symbols only for indirections
+ in the data section. Clean up the code and update comments.
+
+2019-10-13 Iain Sandoe <iain@sandoe.co.uk>
+
+ * config/darwin.c (machopic_indirect_data_reference): Remove
+ redundant code.
+
+2019-10-13 Nathan Sidwell <nathan@acm.org>
+
+ * gengtype-lex.l (CXX_KEYWORD): Add 'mutable'.
+
+2019-10-13 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ * doc/sourcebuild.texi (Test Directives, Add Options): Remove
+ c99_runtime.
+
+2019-10-12 Jan Hubicka <hubicka@ucw.cz>
+
+ * lto-streamer-out.c (collect_block_tree_leafs): Renumber statements
+ so non-virutal are before virutals.
+ (output_function): Avoid body modifications.
+
+2019-10-12 John David Anglin <danglin@gcc.gnu.org>
+
+ * config/pa/pa.c (pa_output_call): Load descriptor address to register
+ %r22. Load function address before global pointer.
+ (pa_attr_length_indirect_call): Adjust length of inline versions of
+ $$dyncall.
+ (pa_output_indirect_call): Remove fast inline version of $$dyncall
+ before normal cases. Update inline $$dyncall sequences to preserve
+ function descriptor address in register %r22.
+ (TRAMPOLINE_CODE_SIZE): Adjust.
+ (pa_asm_trampoline_template): Revise 32-bit trampoline. Don't assume
+ register %r22 contains trampoline address.
+ (pa_trampoline_init): Adjust offsets.
+ (pa_trampoline_adjust_address): Likewise.
+ * config/pa/pa.h (TRAMPOLINE_SIZE): Adjust 32-bit size.
+
+2019-10-12 Iain Sandoe <iain@sandoe.co.uk>
+
+ PR target/67183
+ * config/darwin.c (machopic_indirection): New field to flag
+ non-lazy-symbol-pointers in the data section.
+ (machopic_indirection_name): Compute if an indirection should
+ appear in the data section.
+ (machopic_output_data_section_indirection): New callback split
+ from machopic_output_indirection.
+ (machopic_output_stub_indirection): Likewise.
+ (machopic_output_indirection): Retain the code for non-lazy
+ symbol pointers in their regular section.
+ (machopic_finish): Use the new callbacks to order the indirection
+ output.
+
+2019-10-12 Iain Sandoe <iain@sandoe.co.uk>
+
+ * config/darwin-protos.h (machopic_finish): Delete.
+ * config/darwin.c (machopic_finish): Make static.
+
+2019-10-12 Iain Sandoe <iain@sandoe.co.uk>
+
+ * config/darwin.c (darwin_file_end): Only emit empty CTOR/DTOR
+ sections when building kernel extension code.
+
+2019-10-12 Palmer Dabbelt <palmer@sifive.com>
+
+ * doc/extend.texi (Alternate Keywords): Change "-std=c11" to "a
+ later standard."
+
+2019-10-12 John David Anglin <danglin@gcc.gnu.org>
+
+ * gcc/config/pa/pa.c (pa_option_override): Remove trailing comma
+ from warning.
+
+2019-10-12 Jakub Jelinek <jakub@redhat.com>
+
+ PR middle-end/92063
+ * tree-eh.c (operation_could_trap_helper_p) <case COND_EXPR>
+ <case VEC_COND_EXPR>: Return false with *handled = false.
+ (tree_could_trap_p): For {,VEC_}COND_EXPR return false instead of
+ recursing on the first operand.
+ * fold-const.c (simple_operand_p_2): Use generic_expr_could_trap_p
+ instead of tree_could_trap_p.
+ * tree-ssa-sccvn.c (vn_nary_may_trap): Formatting fixes.
+
+2019-10-11 Jim Wilson <jimw@sifive.com>
+
+ PR rtl-optimization/91860
+ * combine.c (subst): If new_rtx is a constant, also check for
+ SIGN_EXTEND when deciding whether to call simplify_unary_operation.
+
+2019-10-11 Richard Sandiford <richard.sandiford@arm.com>
+
+ * expr.c (store_expr): Use rtx_to_poly_int64 rather than
+ INTVAL when calling store_bit_field.
+
+2019-10-11 Wilco Dijkstra <wdijkstr@arm.com>
+
+ * config/arm/arm.h (HONOR_REG_ALLOC_ORDER): Set when optimizing for
+ size.
+
+2019-10-11 Bernd Edlinger <bernd.edlinger@hotmail.de>
+
+ * tree-vect-loop.c (vect_analyze_loop_operations): Adjust call to
+ vectorizable_live_operation.
+ (vectorizable_live_operation): Adjust parameters.
+ * tree-vect-stmts.c (vect_init_vector,
+ vect_gen_widened_results_half): Fix typo in function comment.
+ (can_vectorize_live_stmts): Adjust function comment.
+ Adjust parameters. Adjust call to vectorizable_live_operation.
+ (vect_analyze_stmt): Adjust call to can_vectorize_live_stmts.
+ (vect_transform_stmt): Adjust function comment. Adjust call to
+ can_vectorize_live_stmts.
+ * tree-vectorizer.h (vectorizable_live_operation): Adjust parameters.
+
+2019-10-11 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/90883
+ PR tree-optimization/91091
+ * tree-ssa-sccvn.c (vn_reference_lookup_3): Use correct
+ alias-sets both for recording VN table entries and continuing
+ walking after translating through copies. Handle same-sized
+ reads from SSA names by returning the plain SSA name.
+ (eliminate_dom_walker::eliminate_stmt): Properly handle
+ non-size precision stores in redundant store elimination.
+
+2019-10-11 Jan Hubicka <hubicka@ucw.cz>
+
+ * ggc-page.c (release_pages): Output statistics when !quiet_flag.
+ (ggc_collect): Dump later to not interfere with release_page dump.
+ (ggc_trim): New function.
+ * ggc-none.c (ggc_trim): New.
+ * ggc.h (ggc_trim): Declare.
+
+2019-10-11 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/92066
+ PR tree-optimization/92046
+ * tree-vect-data-refs.c (vect_enhance_data_refs_alignment):
+ Fix bogus cost model check.
+
+2019-10-11 Tobias Burnus <tobias@codesourcery.com>
+
+ * langhooks-def.h (LANG_HOOKS_OMP_IS_ALLOCATABLE_OR_PTR): Define.
+ (LANG_HOOKS_DECLS): Add it.
+ * langhooks.h (lang_hooks_for_decls): Add omp_is_allocatable_or_ptr;
+ update comment for omp_is_optional_argument.
+ * omp-general.c (omp_is_allocatable_or_ptr): New.
+ * omp-general.h (omp_is_allocatable_or_ptr): Declare.
+ * omp-low.c (scan_sharing_clauses, lower_omp_target): Handle
+ Fortran's optional arguments and allocatable/pointer scalars
+ with use_device_addr.
+
+2019-10-11 Ilya Leoshkevich <iii@linux.ibm.com>
+
+ PR target/77918
+ * config/s390/2827.md: Add new opcodes.
+ * config/s390/2964.md: Likewise.
+ * config/s390/3906.md: Likewise.
+ * config/s390/8561.md: Likewise.
+ * config/s390/s390-builtins.def (s390_vfchesb): Use
+ the new vec_cmpgev4sf_quiet_nocc.
+ (s390_vfchedb): Use the new vec_cmpgev2df_quiet_nocc.
+ (s390_vfchsb): Use the new vec_cmpgtv4sf_quiet_nocc.
+ (s390_vfchdb): Use the new vec_cmpgtv2df_quiet_nocc.
+ (vec_cmplev4sf): Use the new vec_cmplev4sf_quiet_nocc.
+ (vec_cmplev2df): Use the new vec_cmplev2df_quiet_nocc.
+ (vec_cmpltv4sf): Use the new vec_cmpltv4sf_quiet_nocc.
+ (vec_cmpltv2df): Use the new vec_cmpltv2df_quiet_nocc.
+ * config/s390/s390-modes.def (CCSFPS): New mode.
+ * config/s390/s390.c (s390_match_ccmode_set): Support CCSFPS.
+ (s390_select_ccmode): Return CCSFPS for LT, LE, GT, GE and LTGT.
+ (s390_branch_condition_mask): Reuse CCS for CCSFPS.
+ (s390_expand_vec_compare): Use non-signaling patterns where
+ necessary.
+ (s390_reverse_condition): Support CCSFPS.
+ * config/s390/s390.md (*cmp<mode>_ccsfps): New pattern.
+ * config/s390/vector.md: (VFCMP_HW_OP): Remove.
+ (asm_fcmp_op): Likewise.
+ (*smaxv2df3_vx): Use pattern for quiet comparison.
+ (*sminv2df3_vx): Likewise.
+ (*vec_cmp<VFCMP_HW_OP:code><mode>_nocc): Remove.
+ (*vec_cmpeq<mode>_quiet_nocc): New pattern.
+ (vec_cmpgt<mode>_quiet_nocc): Likewise.
+ (vec_cmplt<mode>_quiet_nocc): New expander.
+ (vec_cmpge<mode>_quiet_nocc): New pattern.
+ (vec_cmple<mode>_quiet_nocc): New expander.
+ (*vec_cmpeq<mode>_signaling_nocc): New pattern.
+ (*vec_cmpgt<mode>_signaling_nocc): Likewise.
+ (*vec_cmpgt<mode>_signaling_finite_nocc): Likewise.
+ (*vec_cmpge<mode>_signaling_nocc): Likewise.
+ (*vec_cmpge<mode>_signaling_finite_nocc): Likewise.
+ (vec_cmpungt<mode>): New expander.
+ (vec_cmpunge<mode>): Likewise.
+ (vec_cmpuneq<mode>): Use quiet patterns.
+ (vec_cmpltgt<mode>): Allow only on z14+.
+ (vec_cmpordered<mode>): Use quiet patterns.
+ (vec_cmpunordered<mode>): Likewise.
+ (VEC_CMP_EXPAND): Add ungt and unge.
+
+2019-10-11 Jan Hubicka <hubicka@ucw.cz>
+
+ * gimple-streamer-out.c (output_gimple_stmt): Add explicit function
+ parameter.
+ * lto-streamer-out.c: Include tree-dfa.h.
+ (output_cfg): Do not use cfun.
+ (lto_prepare_function_for_streaming): New.
+ (output_function): Do not push cfun; do not initialize loop optimizer.
+ * lto-streamer.h (lto_prepare_function_for_streaming): Declare.
+ * passes.c (ipa_write_summaries): Use it.
+ (ipa_write_optimization_summaries): Do not modify bodies.
+ * tree-dfa.c (renumber_gimple_stmt_uids): Add function parameter.
+ * tree.dfa.h (renumber_gimple_stmt_uids): Update prototype.
+ * tree-ssa-dse.c (pass_dse::execute): Update use of
+ renumber_gimple_stmt_uids.
+ * tree-ssa-math-opts.c (pass_optimize_widening_mul::execute): Likewise.
+
+2019-10-11 Kewen Lin <linkw@gcc.gnu.org>
+
+ * config/rs6000/rs6000.c (rs6000_builtin_vectorization_cost): Lower
+ vec_promote_demote cost to 1 for non-Power7 VSX architectures.
+
+2019-10-10 Joseph Myers <joseph@codesourcery.com>
+
+ * ginclude/float.h [!__DEC32_MANT_DIG__]: Do not define DFP
+ macros.
+ [__STDC_WANT_IEC_60559_DFP_EXT__ || __STDC_VERSION__ > 201710L]:
+ Also define DFP macros for these conditions.
+ [!__STDC_WANT_DEC_FP__] (DEC32_SUBNORMAL_MIN, DEC64_SUBNORMAL_MIN,
+ DEC128_SUBNORMAL_MIN): Do not define.
+ [__STDC_WANT_IEC_60559_DFP_EXT__ || __STDC_VERSION__ > 201710L]
+ (DEC32_TRUE_MIN, DEC64_TRUE_MIN, DEC128_TRUE_MIN): New macros.
+
+2019-10-10 Xiong Hu Luo <luoxhu@linux.ibm.com>
+ Sandra Loosemore <sandra@codesourcery.com>
+
+ PR middle-end/26241
+ * doc/lto.texi (IPA): Reference to the IPA passes.
+ * doc/passes.texi (Pass manager): Add node IPA passes and
+ description for each IPA pass.
+
+2019-10-10 Jan Hubicka <hubicka@ucw.cz>
+
+ * ipa-reference.c: Do not include splay-tree.h
+ (reference_vars_to_consider): Turn to hash map.
+ (get_static_name, ipa_init, analyze_function, propagate,
+ stream_out_bitmap, ipa_reference_write_optimization_summary,
+ ipa_reference_write_optimization_summary): Update.
+
+2019-10-10 Jan Hubicka <hubicka@ucw.cz>
+
+ * ipa-reference.c (propagate): Fix releasing of IPA summaries.
+
+2019-10-10 Iain Sandoe <iain@sandoe.co.uk>
+
+ * config/darwin.c: Lookup Objective C metadata and force indirection
+ for IVAR refs.
+
+2019-10-10 Michael Meissner <meissner@linux.ibm.com>
+
+ * config/rs6000/rs6000.c (quad_address_p): Add check for prefixed
+ addresses.
+ (mem_operand_gpr): Add check for prefixed addresses.
+ (mem_operand_ds_form): Add check for prefixed addresses.
+ (rs6000_legitimate_offset_address_p): If we support prefixed
+ addresses, check for a 34-bit offset instead of 16-bit.
+ (rs6000_legitimate_address_p): Add check for prefixed addresses.
+ Do not allow load/store with update if the address is prefixed.
+ (rs6000_mode_dependent_address): If we support prefixed
+ addresses, check for a 34-bit offset instead of 16-bit.
+
+2019-10-10 Ilya Leoshkevich <iii@linux.ibm.com>
+
+ PR target/77918
+ * config/s390/vector.md (vcond_comparison_operator): New
+ predicate.
+ (vcond<V_HW:mode><V_HW2:mode>): Use vcond_comparison_operator.
+
+2019-10-10 David Malcolm <dmalcolm@redhat.com>
+
+ PR 87488
+ * Makefile.in (CFLAGS-opts.o): Pass in DOCUMENTATION_ROOT_URL via
+ -D.
+ * configure.ac (--with-documentation-root-url): New option.
+ * configure: Regenerate.
+ * diagnostic-format-json.cc (json_end_diagnostic): If there is an
+ option URL, add it as a new string field of the diagnostic option.
+ * diagnostic.c (diagnostic_initialize): Initialize get_option_url.
+ (print_option_information): If get_option_url is non-NULL, call
+ it, and if the result is non-NULL, potentially emit an escape
+ sequence to markup the option text with the resulting URL.
+ * diagnostic.h (diagnostic_context::get_option_url): New callback.
+ * doc/invoke.texi (-fdiagnostics-format=): Add "option_url" to
+ example of JSON output.
+ * opts-diagnostic.h (get_option_url): New decl.
+ * opts.c (get_option_url): New function.
+ * toplev.c (general_init): Initialize the get_option_url callback.
+
+2019-10-10 David Malcolm <dmalcolm@redhat.com>
+
+ PR 87488
+ * common.opt (fdiagnostics-urls=): New option.
+ (diagnostic-url.h): Add SourceInclude.
+ (diagnostic_url_rule): New enum.
+ * diagnostic-color.c: Include "diagnostic-url.h".
+ (diagnostic_urls_enabled_p): New function.
+ * diagnostic-url.h: New file.
+ * diagnostic.c: Include "diagnostic-url.h".
+ (diagnostic_urls_init): New function.
+ * diagnostic.h (diagnostic_urls_init): New decl.
+ * doc/invoke.texi (Diagnostic Message Formatting Options): Add
+ -fdiagnostics-urls to the list.
+ (-fdiagnostics-urls): New option.
+ * gcc.c (driver_handle_option): Handle OPT_fdiagnostics_urls_.
+ (driver::global_initializations): Call diagnostic_urls_init.
+ * opts-global.c (init_options_once): Likewise.
+ * opts.c (common_handle_option): Handle OPT_fdiagnostics_urls_.
+ * pretty-print.c (pretty_printer::pretty_printer): Initialize
+ show_urls.
+ (pp_begin_url): New function.
+ (pp_end_url): New function.
+ (selftest::test_urls): New selftest.
+ (selftest::pretty_print_c_tests): Call it.
+ * pretty-print.h (pretty_printer::show_urls): New field.
+ (pp_begin_url): New decl.
+ (pp_end_url): New decl.
+
+2019-10-10 Uroš Bizjak <ubizjak@gmail.com>
+
+ PR target/92022
+ * config/alpha/alpha.c (alpha_handle_trap_shadows): Skip DEBUG_INSN.
+
+2019-10-10 Oleg Endo <olegendo@gcc.gnu.org>
+
+ PR target/88630
+ * config/sh/sh.h (TARGET_FPU_SH4_300): New macro.
+ * config/sh/sh.c (sh_option_override): Enable fsca and fsrra insns
+ also for TARGET_FPU_SH4_300.
+ (sh_emit_mode_set): Check for TARGET_FPU_SH4_300 instead of
+ TARGET_SH4_300.
+ * config/sh/sh.md (toggle_pr): Add TARGET_FPU_SH4_300 condition.
+ (negsf2): Expand to either negsf2_fpscr or negsf2_no_fpscr.
+ (*negsf2_i): Split into ...
+ (negsf2_fpscr, negsf2_no_fpscr): ... these new patterns.
+ (abssf2): Expand to either abssf2_fpsc or abssf2_no_fpsc.
+ (**abssf2_i): Split into ...
+ (abssf2_fpscr, abssf2_no_fpscr): ... these new patterns.
+ (negdf2): Expand to either negdf2_fpscr or negdf2_no_fpscr.
+ (*negdf2_i): Split into ...
+ (negdf2_fpscr, negdf2_no_fpscr): ... these new patterns.
+ (absdf2): Expand to either absdf2_fpscr or absdf2_no_fpsc.
+ (**abssf2_i): Split into ...
+ (absdf2_fpscr, absdf2_no_fpscr): ... these new patterns.
+
+2019-10-10 Richard Biener <rguenther@suse.de>
+
+ PR middle-end/92046
+ * opts.c (finish_options): Do not influence global --params
+ from options that are adjustable per function.
+ * tree-vect-data-refs.c (vect_enhance_data_refs_alignment):
+ Apply --param adjustment based on active cost-model.
+ * tree-ssa-phiopt.c (cond_if_else_store_replacement): Disable
+ further store-sinking when vectorization or if-conversion
+ are not enabled.
+
+2019-10-10 Jan Hubicka <hubicka@ucw.cz>
+
+ PR middle-end/92037
+ * cgraph.c (symbol_table_test::symbol_table_test): Use ggc_alloc
+ rather than ggc_alloc_cleared to alloc symbol table.
+ * toplev.c (general_init): Likewise.
+ * cgraph.h (symbol_table): Explicitly construct every field.
+
+2019-10-10 Andreas Krebbel <krebbel@linux.ibm.com>
+
+ * common/config/s390/s390-common.c (PF_ARCH13): Rename to...
+ (PF_Z15): ... this.
+ * config.gcc: Add z15 as option for --with-arch and --with-tune
+ configure switches.
+ * config/s390/s390-c.c (s390_resolve_overloaded_builtin): Add
+ error reporting for unsupported builtins.
+ * config/s390/s390-opts.h (enum processor_type): Rename
+ PROCESSOR_8561_ARCH13 to PROCESSOR_8561_Z15.
+ * config/s390/8561.md: Rename arch13 to z15 throughout the file.
+ * config/s390/driver-native.c (s390_host_detect_local_cpu):
+ Likewise.
+ * config/s390/s390-builtins.def: Likewise.
+ * config/s390/s390.c (processor_table): Add z15 as option and keep arch13 as alternative.
+ (s390_expand_builtin): Add missing check for unsupported builtins.
+ (s390_canonicalize_comparison): Rename TARGET_ARCH13 to TARGET_Z15.
+ (s390_rtx_costs): Likewise.
+ (s390_get_sched_attrmask): Rename arch13 to z15.
+ (s390_get_unit_mask): Likewise.
+ (s390_is_fpd): Likewise.
+ (s390_is_fxd): Likewise.
+ * config/s390/s390.h (enum processor_flags): Likewise.
+ * config/s390/s390.md: Likewise.
+ * config/s390/vector.md: Likewise.
+ * config/s390/vx-builtins.md: Likewise.
+ * config/s390/s390.opt: Add z15 to processor_type value.
+
+2019-10-10 Andreas Krebbel <krebbel@linux.ibm.com>
+
+ PR target/91035
+ * config/s390/s390-protos.h (s390_output_split_stack_data): Add
+ prototype.
+ * config/s390/s390.md (UNSPECV_SPLIT_STACK_DATA): Remove.
+ ("split_stack_data", "split_stack_call")
+ ("split_stack_call_<mode>", "split_stack_cond_call")
+ ("split_stack_cond_call_<mode>"): Remove.
+ ("@split_stack_call<mode>", "@split_stack_cond_call<mode>"): New
+ insn definition.
+ * config/s390/s390.c (s390_output_split_stack_data): New function.
+ (s390_expand_split_stack_prologue): Use the merged expander.
+
+2019-10-09 Martin Sebor <msebor@redhat.com>
+
+ PR tree-optimization/90879
+ * builtins.c (check_access): Avoid using maxbound when null.
+ * calls.c (maybe_warn_nonstring_arg): Adjust to get_range_strlen change.
+ * doc/invoke.texi (-Wstring-compare): Document new warning option.
+ * gimple-fold.c (get_range_strlen_tree): Make setting maxbound
+ conditional.
+ (get_range_strlen): Overwrite initial maxbound when non-null.
+ * gimple-ssa-sprintf.c (get_string_length): Adjust to get_range_strlen
+ changes.
+ * tree-ssa-strlen.c (maybe_diag_stxncpy_trunc): Same.
+ (used_only_for_zero_equality): New function.
+ (handle_builtin_memcmp): Call it.
+ (determine_min_objsize): Return an integer instead of tree.
+ (get_len_or_size, strxcmp_eqz_result): New functions.
+ (maybe_warn_pointless_strcmp): New function.
+ (handle_builtin_string_cmp): Call it. Fold zero-equality of strcmp
+ between a longer string and a smaller array.
+ (get_range_strlen_dynamic): Overwrite initial maxbound when non-null.
+
+2019-10-09 Iain Sandoe <iain@sandoe.co.uk>
+
+ * config/darwin.c (darwin_override_options): Make the check for
+ Objective-C ABI version more specific for 64bit code.
+
+2019-10-09 Iain Sandoe <iain@sandoe.co.uk>
+
+ * config/darwin.c (machopic_indirect_data_reference): Set flag to
+ indicate that the new symbol is an indirection.
+ (machopic_indirect_call_target): Likewise.
+ * config/darwin.h (MACHO_SYMBOL_FLAG_INDIRECTION): New.
+ (MACHO_SYMBOL_INDIRECTION_P): New.
+ (MACHO_SYMBOL_FLAG_STATIC): Adjust bit number.
+
+2019-10-08 Jason Merrill <jason@redhat.com>
+
+ * doc/invoke.texi: Document -fconcepts-ts.
+
+2019-10-09 Richard Biener <rguenther@suse.de>
+
+ * tree-vect-loop.c (vect_is_simple_reduction): Simplify and
+ allow stmts other than GIMPLE_ASSIGN in nested cycles.
+
+2019-10-08 Richard Biener <rguenther@suse.de>
+
+ * tree-vectorizer.h (_stmt_vec_info::reduc_vectype_in): New.
+ (_stmt_vec_info::force_single_cycle): Likewise.
+ (STMT_VINFO_FORCE_SINGLE_CYCLE): New.
+ (STMT_VINFO_REDUC_VECTYPE_IN): Likewise.
+ * tree-vect-loop.c (vectorizable_reduction): Set
+ STMT_VINFO_REDUC_VECTYPE_IN and STMT_VINFO_FORCE_SINGLE_CYCLE.
+ (vect_transform_reduction): Use them to remove redundant code.
+ (vect_transform_cycle_phi): Likewise.
+
+2019-10-08 Dmitrij Pochepko <dmitrij.pochepko@bell-sw.com>
+
+ PR tree-optimization/90836
+ * gcc/match.pd (popcount): New pattern.
+
+2019-10-08 Martin Sebor <msebor@redhat.com>
+
+ PR middle-end/92026
+ PR middle-end/92014
+ * tree-ssa-strlen.c (count_nonzero_bytes): Avoid recursing for MEM_REF
+ again once nbytes has been set. Set the access size when not yet set.
+
+2019-10-08 Iain Sandoe <iain@sandoe.co.uk>
+
+ * config/darwin.c (machopic_select_section): Remove dead code for
+ old Objective-C section selection method, replace with unreachable.
+
+2019-10-08 Iain Sandoe <iain@sandoe.co.uk>
+
+ * config/darwin.c (machopic_indirect_data_reference): Check for
+ required indirections before making direct access to defined
+ values.
+ (machopic_output_indirection): Place the indirected pointes for
+ required indirections into the non-lazy symbol pointers section.
+ (darwin_encode_section_info):
+ * config/darwin.h (MACHO_SYMBOL_FLAG_MUST_INDIRECT): New.
+ (MACHO_SYMBOL_MUST_INDIRECT_P): New.
+
+2019-10-08 Uroš Bizjak <ubizjak@gmail.com>
+
+ PR target/91994
+ * config/i386/i386.c (x86_avx_u128_mode_needed): Use SSE_REG
+ instead of ALL_SSE_REG to check if function call preserves some
+ 256-bit SSE registers.
+
+2019-10-08 Tulio Magno Quites Machado Filho <tuliom@linux.ibm.com>
+
+ * config.gcc: Move -L usage from LINK_OS_EXTRA_SPEC32 and
+ LINK_OS_EXTRA_SPEC64 to MD_STARTFILE_PREFIX and
+ MD_STARTFILE_PREFIX_1 when using --with-advance-toolchain.
+
+2019-10-08 Richard Biener <rguenther@suse.de>
+
+ * tree-vectorizer.h (_stmt_vec_info::v_reduc_type): Remove.
+ (_stmt_vec_info::is_reduc_info): Add.
+ (STMT_VINFO_VEC_REDUCTION_TYPE): Remove.
+ (vectorizable_condition): Remove.
+ (vectorizable_shift): Likewise.
+ (vectorizable_reduction): Adjust.
+ (info_for_reduction): New.
+ * tree-vect-loop.c (vect_force_simple_reduction): Fold into...
+ (vect_analyze_scalar_cycles_1): ... here.
+ (vect_analyze_loop_operations): Adjust.
+ (needs_fold_left_reduction_p): Simplify for single caller.
+ (vect_is_simple_reduction): Likewise. Remove stmt restriction
+ for nested cycles not part of double reductions.
+ (vect_model_reduction_cost): Pass in the reduction type.
+ (info_for_reduction): New function.
+ (vect_create_epilog_for_reduction): Use it, access reduction
+ meta off the stmt info it returns. Use STMT_VINFO_REDUC_TYPE
+ instead of STMT_VINFO_VEC_REDUCTION_TYPE.
+ (vectorize_fold_left_reduction): Remove pointless assert.
+ (vectorizable_reduction): Analyze the full reduction when
+ visiting the outermost PHI. Simplify. Use STMT_VINFO_REDUC_TYPE
+ instead of STMT_VINFO_VEC_REDUCTION_TYPE. Direct reduction
+ stmt code-generation to vectorizable_* in most cases. Verify
+ code-generation only for cases handled by
+ vect_transform_reductuon.
+ (vect_transform_reduction): Use info_for_reduction to get at
+ reduction meta. Simplify.
+ (vect_transform_cycle_phi): Likewise.
+ (vectorizable_live_operation): Likewise.
+ * tree-vect-patterns.c (vect_reassociating_reduction_p): Look
+ at the PHI node for STMT_VINFO_REDUC_TYPE.
+ * tree-vect-slp.c (vect_schedule_slp_instance): Remove no
+ longer necessary code.
+ * tree-vect-stmts.c (vectorizable_shift): Make static again.
+ (vectorizable_condition): Likewise. Get at reduction related
+ info via info_for_reduction.
+ (vect_analyze_stmt): Adjust.
+ (vect_transform_stmt): Likewise.
+ * tree-vectorizer.c (vec_info::new_stmt_vec_info): Initialize
+ STMT_VINFO_REDUC_TYPE instead of STMT_VINFO_VEC_REDUCTION_TYPE.
+
+2019-10-08 Joseph Myers <joseph@codesourcery.com>
+
+ * doc/invoke.texi (-ffp-int-builtin-inexact): Document
+ -fno-fp-int-builtin-inexact default for C2X.
+
+2019-10-07 Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org>
+ Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/91532
+ * tree-if-conv.c: Include tree-ssa-dse.h.
+ (ifcvt_local_dce): Change param from bb to loop,
+ and call dse_classify_store.
+ (tree_if_conversion): Pass loop instead of loop->header as arg
+ to ifcvt_local_dce.
+ * tree-ssa-dse.c: Include tree-ssa-dse.h.
+ (delete_dead_or_redundant_assignment): Remove static qualifier from
+ declaration, and add prototype in tree-ssa-dse.h.
+ (dse_store_status): Move to tree-ssa-dse.h.
+ (dse_classify_store): Remove static qualifier and add new tree param
+ stop_at_vuse, and add prototype in tree-ssa-dse.h.
+ * tree-ssa-dse.h: New header.
+
+2019-10-07 Iain Sandoe <iain@sandoe.co.uk>
+
+ * config/darwin.c (machopic_output_indirection): Don't put
+ hidden symbol indirections into the .data section, use the
+ non-lazy symbol pointers section as normal.
+ (darwin_encode_section_info): Record if a symbol is hidden.
+ * config/darwin.h (MACHO_SYMBOL_FLAG_HIDDEN_VIS): New.
+ (MACHO_SYMBOL_HIDDEN_VIS_P): New.
+
+2019-10-07 Iain Sandoe <iain@sandoe.co.uk>
+
+ * config/darwin.c (machopic_symbol_defined_p): Use symbol flag
+ predicates instead of accessing bits directly.
+ (machopic_indirect_call_target): Likewise.
+ (machopic_output_indirection): Likewise.
+ (darwin_encode_section_info): Improve description. Use renamed
+ symbol flags. Use predicate macros for variables and functions.
+ * config/darwin.h:
+ Rename MACHO_SYMBOL_VARIABLE to MACHO_SYMBOL_FLAG_VARIABLE.
+ Rename MACHO_SYMBOL_DEFINED to MACHO_SYMBOL_FLAG_DEFINED.
+ Rename MACHO_SYMBOL_STATIC to MACHO_SYMBOL_FLAG_STATIC.
+ (MACHO_SYMBOL_VARIABLE_P): New.
+ (MACHO_SYMBOL_DEFINED_P):New.
+ (MACHO_SYMBOL_STATIC_P): New.
+ * config/i386/darwin.h (MACHO_SYMBOL_FLAG_VARIABLE): Delete.
+ (SYMBOL_FLAG_SUBT_DEP): New.
+ * config/rs6000/darwin.h (SYMBOL_FLAG_SUBT_DEP): New.
+
+2019-10-07 Jozef Lawrynowicz <jozef.l@mittosystems.com>
+
+ * config/msp430/msp430.c (msp430_file_end): s/msp_/msp430_/
+ (msp430_expand_epilogue): Likewise.
+ * config/msp430/predicates.md: Likewise.
+ * config/msp430/msp430.md: Likewise.
+ Replace blocks of 8 spaces with tabs.
+
+2019-10-07 Jozef Lawrynowicz <jozef.l@mittosystems.com>
+
+ * config/msp430/msp430-protos.h (msp430_split_addsi): New prototype.
+ * config/msp430/msp430.c (msp430_split_addsi): New.
+ * config/msp430/msp430.md: Call msp430_split_addsi () instead of using
+ a block of C code for splitting addsi.
+
+2019-10-07 Uroš Bizjak <ubizjak@gmail.com>
+
+ * config/i386/i386-expand.c (ix86_expand_floorceildf_32,
+ ix86_expand_rounddf_32): Reorder functions.
+ * config/i386/i386-protos.h: Update.
+
+2019-10-07 Jozef Lawrynowicz <jozef.l@mittosystems.com>
+
+ * config.in: Regenerate.
+ * config/msp430/constraints.md: Fix docstring for "Ys" constraint.
+ Add new "Yx" constraint.
+ * config/msp430/driver-msp430.c (msp430_propagate_region_opt): New spec
+ function.
+ * config/msp430/msp430-protos.h (msp430_op_not_in_high_mem): New
+ prototype.
+ * config/msp430/msp430.c (msp430_option_override): Allow the lower
+ code/data region to be selected in the small memory model.
+ (msp430_section_attr): Don't warn if the "section" and "lower"
+ attributes are used together.
+ (msp430_handle_generic_attribute): Likewise.
+ (msp430_var_in_low_mem): New function.
+ (TARGET_ENCODE_SECTION_INFO): Define.
+ (msp430_encode_section_info): New function.
+ (gen_prefix): Return early in the small memory model.
+ Require TARGET_USE_LOWER_REGION_PREFIX to be set before adding the
+ ".lower" prefix if -m{code,data}-region=lower have been passed.
+ (msp430_output_aligned_decl_common): Emit common symbols when
+ -mdata-region=lower is passed unless TARGET_USE_LOWER_REGION_PREFIX is
+ set.
+ (TARGET_ASM_FILE_END): Define.
+ (msp430_file_end): New function.
+ (msp430_do_not_relax_short_jumps): Allow relaxation when
+ function will be in the lower region.
+ (msp430_op_not_in_high_mem): New function.
+ (msp430_print_operand): Check "msp430_op_not_in_high_mem" for
+ the 'X' operand selector.
+ Clarify comment for 'x' operand selector.
+ * config/msp430/msp430.h (LINK_SPEC): Propagate
+ -m{code,data}-region to the linker via spec function
+ msp430_propagate_region_opt.
+ (msp430_propagate_region_opt): New prototype.
+ (EXTRA_SPEC_FUNCTIONS): Add msp430_propagate_region_opt.
+ (SYMBOL_FLAG_LOW_MEM): Define.
+ * config/msp430/msp430.md (addsipsi3): Add missing "%X" operand
+ selector.
+ (zero_extendqihi2): Fix operand number used by "%X" selector.
+ (zero_extendqisi2): Likewise.
+ (zero_extendhisi2): Likewise.
+ (movqi): Use "Yx" constraint in place of "%X" operand selector.
+ (movhi): Likewise.
+ (addqi3): Likewise.
+ (addhi3): Likewise.
+ (addsi3): Likewise.
+ (addhi3_cy): Likewise.
+ (addchi4_cy): Likewise.
+ (subqi3): Likewise.
+ (subhi3): Likewise.
+ (subsi3): Likewise.
+ (bic<mode>3): Likewise.
+ (and<mode>3): Likewise.
+ (ior<mode>3): Likewise.
+ (xor<mode>3): Likewise.
+ (slli_1): Add missing "%X" operand selector.
+ (slll_1): Likewise.
+ (slll_2): Likewise.
+ (srai_1): Likewise.
+ (sral_1): Likewise.
+ (sral_2): Likewise.
+ (srli_1): Likewise.
+ (srll_1): Likewise.
+ (cbranchqi4_real): Use "Yx" constraint in place of "%X" operand
+ selector.
+ (cbranchhi4_real): Likewise.
+ (cbranchqi4_reversed): Likewise.
+ (cbranchhi4_reversed): Likewise.
+ (*bitbranch<mode>4): Likewise.
+ (*bitbranch<mode>4_z): Remove unnecessary "%x" operand selector.
+ * config/msp430/msp430.opt (mcode-region=): Set default to
+ MSP430_REGION_LOWER. Improve docstring.
+ (mdata-region=): Likewise.
+ (muse-lower-region-prefix): New option.
+ * config/msp430/t-msp430 (MULTILIB_OPTIONS): Add
+ mdata-region=none multilib.
+ (MULTILIB_MATCHES): Set mdata-region={upper,either} to match
+ mdata-region=none multilib.
+ MULTILIB_EXCEPTIONS: Remove.
+ MULTILIB_REQUIRED: Define.
+ * configure: Regenerate.
+ * configure.ac: Define HAVE_AS_GNU_ATTRIBUTE and
+ HAVE_AS_MSPABI_ATTRIBUTE if GAS version >= 2.33.50.
+ * doc/extend.texi: Clarify comment for {upper,lower,either}
+ function attributes.
+ Add separate description for "lower" variable attribute.
+
+2019-10-07 Ilya Leoshkevich <iii@linux.ibm.com>
+
+ PR target/77918
+ * optabs-tree.c (vcond_icode_p): New function.
+ (vcond_eq_icode_p): Likewise.
+ (expand_vec_cond_expr_p): Use vcond_icode_p and
+ vcond_eq_icode_p.
+ * optabs.c (can_vcond_compare_p): New function.
+ * optabs.h (can_vcond_compare_p): Likewise.
+
+2019-10-07 Ilya Leoshkevich <iii@linux.ibm.com>
+
+ PR target/77918
+ * gimple-expr.c (gimple_cond_get_ops_from_tree): Assert that the
+ caller passes a non-trapping condition.
+ (is_gimple_condexpr): Allow trapping conditions.
+ (is_gimple_condexpr_1): New helper function.
+ (is_gimple_condexpr_for_cond): New function, acts like old
+ is_gimple_condexpr.
+ * gimple-expr.h (is_gimple_condexpr_for_cond): New function.
+ * gimple.c (gimple_could_trap_p_1): Handle COND_EXPR and
+ VEC_COND_EXPR. Fix an issue with statements like i = (fp < 1.).
+ * gimplify.c (gimplify_cond_expr): Use
+ is_gimple_condexpr_for_cond.
+ (gimplify_expr): Allow is_gimple_condexpr_for_cond.
+ * tree-eh.c (operation_could_trap_p): Assert on COND_EXPR and
+ VEC_COND_EXPR.
+ (tree_could_trap_p): Handle COND_EXPR and VEC_COND_EXPR.
+ * tree-ssa-forwprop.c (forward_propagate_into_gimple_cond): Use
+ is_gimple_condexpr_for_cond, remove pointless tmp check
+ (forward_propagate_into_cond): Remove pointless tmp check.
+
+2019-10-07 Vladislav Ivanishin <vlad@ispras.ru>
+
+ * gimple-iterator.h (gsi_next_nonvirtual_phi): Change the semantics to
+ match that of other gsi_next_* functions. Adjust the comment.
+ (gsi_start_nonvirtual_phis): New function.
+ * ipa-icf.c (sem_function::compare_phi_node): Update uses of
+ gsi_next_nonvirtual_phi accordingly. (No functional change.)
+
+2019-10-07 Vladislav Ivanishin <vlad@ispras.ru>
+
+ * doc/invoke.texi (-Wuninitialized): Don't mention the clobbered by
+ setjmp situation here. Fix a verb's ending: "the exact variables or
+ elements for which there are warnings depends" -> "... depend".
+
+2019-10-07 Aldy Hernandez <aldyh@redhat.com>
+
+ * ipa-prop.c (ipa_vr::nonzero_p): Add TYPE_UNSIGNED check.
+
+2019-10-07 Aldy Hernandez <aldyh@redhat.com>
+
+ * ipa-prop.c (ipa_vr::nonzero_p): New.
+ (ipcp_update_vr): Use nonzero_p instead of open-coding check for
+ non-zero range.
+ * ipa-prop.h (class ipa_vr): Add nonzero_p.
+ * tree-vrp.c (range_has_numeric_bounds_p): New.
+ (range_int_cst_p): Use range_has_numeric_bounds_p.
+ (get_range_op_handler): New.
+ (supported_types_p): New.
+ (defined_ranges_p): New.
+ (drop_undefines_to_varying): New.
+ (range_fold_binary_symbolics_p): New.
+ (range_fold_unary_symbolics_p): New.
+ (range_fold_unary_expr): Extract out into above functions.
+ (range_fold_binary_expr): Same.
+ (value_range_base::normalize_addresses): New.
+ (value_range_base::normalize_symbolics): Normalize addresses.
+ * tree-vrp.h (class value_range_base): Add normalize_addresses.
+
+2019-10-07 Aldy Hernandez <aldyh@redhat.com>
+
+ * tree-vrp.c (value_range_base::singleton_p): Use
+ value_range_base::num_pairs instead of vrp_val_is* to check
+ if a range has one sub-range.
+
+2019-10-07 Richard Sandiford <richard.sandiford@arm.com>
+
+ * ira-lives.c (check_and_make_def_conflict): Handle cases in which
+ DEF is not a true earlyclobber but is tied to a specific input
+ operand, and so is effectively earlyclobber wrt inputs that have
+ different values.
+ (make_early_clobber_and_input_conflicts): Pass this case to the above.
+
+2019-10-07 Richard Sandiford <richard.sandiford@arm.com>
+
+ * machmode.h (opt_mode): Mark constructors with CONSTEXPR.
+ (pod_mode): Mark operators likewise.
+ (scalar_int_mode): Mark non-default constructors and
+ operators with CONSTEXPR.
+ (scalar_float_mode, scalar_mode, complex_mode): Likewise.
+ (fixed_size_mode): Likewise.
+
+2019-10-07 Richard Sandiford <richard.sandiford@arm.com>
+
+ PR target/91994
+ * config/i386/sse.md (avx_vzeroupper): Turn into a define_expand
+ and wrap the unspec_volatile in a parallel.
+ (*avx_vzeroupper): New define_insn. Use a match_parallel around
+ the unspec_volatile.
+ * config/i386/predicates.md (vzeroupper_pattern): Expect the
+ unspec_volatile to be wrapped in a parallel.
+ * config/i386/i386-features.c (ix86_add_reg_usage_to_vzeroupper)
+ (ix86_add_reg_usage_to_vzerouppers): New functions.
+ (rest_of_handle_insert_vzeroupper): Use them to add register
+ usage information to the vzeroupper instructions.
+
2019-10-07 Richard Biener <rguenther@suse.de>
PR tree-optimization/91975
@@ -148,7 +987,7 @@
2019-10-04 Aldy Hernandez <aldyh@redhat.com>
- (value_range_from_overflowed_bounds): Rename from
+ * range-op.o (value_range_from_overflowed_bounds): Rename from
adjust_overflow_bound.
(value_range_with_overflow): Rename from
create_range_with_overflow.
diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP
index 19cc9745a1a..d6c8807ea6f 100644
--- a/gcc/DATESTAMP
+++ b/gcc/DATESTAMP
@@ -1 +1 @@
-20191007
+20191014
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 13641d4f11c..d09fe7b17cd 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -2143,6 +2143,8 @@ lto-wrapper$(exeext): $(LTO_WRAPPER_OBJS) libcommon-target.a $(LIBDEPS)
$(LTO_WRAPPER_OBJS) libcommon-target.a $(LIBS)
mv -f T$@ $@
+CFLAGS-opts.o += -DDOCUMENTATION_ROOT_URL=\"@DOCUMENTATION_ROOT_URL@\"
+
# Files used by all variants of C or by the stand-alone pre-processor.
CFLAGS-c-family/c-opts.o += @TARGET_SYSTEM_ROOT_DEFINE@
diff --git a/gcc/REVISION b/gcc/REVISION
index 477c0ad2e72..9c56aacadde 100644
--- a/gcc/REVISION
+++ b/gcc/REVISION
@@ -1 +1 @@
-[c++-coroutines revision 276647]
+[c++-coroutines revision 276863]
diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog
index 0463038f63a..e66f11133ea 100644
--- a/gcc/ada/ChangeLog
+++ b/gcc/ada/ChangeLog
@@ -1,3 +1,283 @@
+2019-10-12 Eric Botcazou <ebotcazou@adacore.com>
+
+ PR ada/91995
+ * sem_ch8.adb (Chain_Use_Clause): Remove second argument in calls
+ to Defining_Entity.
+ * sem_elab.adb (Find_Unit_Entity): Likewise. Deal with N_Subunit
+ here in lieu of in Defining_Entity.
+ * sem_util.ads (Defining_Entity): Remove 2nd and 3th parameters.
+ * sem_util.adb (Defining_Entity): Remove 2nd and 3th parameters,
+ and adjust accordingly. Deal with N_Compilation_Unit.
+
+2019-10-11 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gcc-interface/decl.c (elaborate_reference_1): Specifically deal with
+ pointer displacement.
+
+ * gcc-interface/decl.c (components_to_record): Use proper name.
+
+ * gcc-interface/trans.c (Sloc_to_locus): Use standard types.
+
+2019-10-11 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gcc-interface/decl.c (gnat_to_gnu_field): Adjust again the packing
+ for a field without strict alignment and with an oversized clause.
+
+2019-10-11 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gcc-interface/decl.c (annotate_value) <INTEGER_CST>: Really test the
+ sign of the value when deciding to build a NEGATE_EXPR.
+ <PLUS_EXPR>: Remove redundant line.
+ <BIT_AND_EXPR>: Do the negation here.
+
+2019-10-11 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gcc-interface/decl.c (Gigi_Equivalent_Type) <E_Array_Subtype>: New
+ case. Return the base type if the subtype is not constrained.
+
+2019-10-11 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gcc-interface/decl.c (gnat_to_gnu_entity) <E_Named_{Integer|Real}>:
+ New case to deal with the definition of named numbers.
+ <E_Variable>: Minor tweaks. Set DECL_IGNORED_P on the CONST_DECL
+ if a corresponding variable is built.
+ * gcc-interface/trans.c (gnat_to_gnu) <N_Integer_Literal>: Return
+ error_mark_node instead of aborting on overflow for named numbers.
+ <N_Number_Declaration>: Reuse the <N_Object_Declaration> case and
+ deal with error_mark_node specifically.
+ * gcc-interface/utils.c (create_var_decl): Do not set DECL_IGNORED_P
+ on CONST_DECLs.
+ (gnat_write_global_declarations): Output global constants.
+
+2019-10-10 Gary Dismukes <dismukes@adacore.com>
+
+ * exp_ch7.adb (Check_Unnesting_In_Decls_Or_Stmts): When
+ encountering a loop at the top level of a package declaration
+ list (that is, within the declarations of a package spec or
+ body) that has nested subprograms, call Unnest_Loop to create a
+ new library-level procedure that will contain the loop, to allow
+ for proper handling of up-level references from within nested
+ subprograms, such as to loop parameters.
+ (Unnest_Loop): New procedure that takes a loop statement and
+ creates a new procedure body to enclose the loop statement,
+ along with generating a call to the procedure.
+
+2019-10-10 Arnaud Charlet <charlet@adacore.com>
+
+ * freeze.adb (Freeze_Subprogram): Ensure constructor is a C++
+ constructor.
+
+2019-10-10 Gary Dismukes <dismukes@adacore.com>
+
+ * libgnat/a-ststio.ads (File_Type): Apply pragma
+ Preelaborable_Initialization to the type.
+
+2019-10-10 Yannick Moy <moy@adacore.com>
+
+ * inline.adb (Can_Be_Inlined_In_GNATprove_Mode): Do not peek
+ under private types whose completion is SPARK_Mode Off.
+
+2019-10-10 Gary Dismukes <dismukes@adacore.com>
+
+ * exp_ch4.adb, sem_cat.adb, sem_ch12.adb, sem_ch3.adb,
+ sem_ch6.adb, sem_prag.adb, sem_util.adb, sem_util.ads: Minor
+ typo fixes.
+
+2019-10-10 Ed Schonberg <schonberg@adacore.com>
+
+ * sem_warn.adb (Warn_On_Useless_Assignment): Do not warn if the
+ second assignment is at the same source position as the first.
+
+2019-10-10 Gary Dismukes <dismukes@adacore.com>
+
+ * sem_util.adb (Enclosing_Subprogram): Handle the case of
+ E_Entry_Family, returning the entry family's associated
+ Protected_Body_Subprogram (as was already done for E_Entry).
+ * exp_ch9.adb (Expand_N_Accept_Statement): Call Reset_Scopes_To
+ on the block created for an accept statement to reset the scopes
+ of any local entities to the block scope.
+
+2019-10-10 Ed Schonberg <schonberg@adacore.com>
+
+ * sem_ch12.adb (Analyze_Formal_Package_Declaration): Propagate
+ an aspect specification for Abstract_State from generic package
+ to formal package, so that it is available when analyzing the
+ constructed formal.
+
+2019-10-10 Eric Botcazou <ebotcazou@adacore.com>
+
+ * sem_ch6.adb (Set_Actual_Subtypes): Put the freeze node of the
+ actual subtype after its declaration when the type of the formal
+ has a predicate.
+
+2019-10-10 Eric Botcazou <ebotcazou@adacore.com>
+
+ * sem_ch13.adb (Adjust_Record_For_Reverse_Bit_Order): Do not use
+ the Esize of the component to compute its layout, but only the
+ Component_Clause. Do not issue a warning for the _Tag
+ component. Also set the Esize of the component at the end of
+ the layout.
+ (Analyze_Record_Representation_Clause): Remove Hbit local
+ variable. Lay out the Original_Record_Component only if it's
+ distinct from the component.
+ (Check_Record_Representation_Clause): Fix off-by-one bug for the
+ Last_Bit of the artificial clause built for the _Tag component.
+
+2019-10-10 Bob Duff <duff@adacore.com>
+
+ * treepr.ads, treepr.adb (ppar): New procedure.
+
+2019-10-10 Bob Duff <duff@adacore.com>
+
+ * sem_aggr.adb (Resolve_Aggregate): Add missing cases in the
+ Others_Allowed => True case -- N_Case_Expression_Alternative and
+ N_If_Expression. Use Nkind_In.
+ * atree.adb, atree.ads, sinfo.adb, sinfo.ads (Nkind_In): New
+ 16-parameter version.
+
+2019-10-10 Ed Schonberg <schonberg@adacore.com>
+
+ * sem_aggr.adb (Resolve_Array_Aggregate): Set properly the
+ Predicated_Parent link of an itype created for an aggregate, so
+ that the predicate_function of the parent can support proofs on
+ the object that it initializes.
+
+2019-10-10 Eric Botcazou <ebotcazou@adacore.com>
+
+ * sem_ch3.adb (Analyze_Number_Declaration): Set
+ Debug_Info_Needed in the case where the expression is an integer
+ literal.
+
+2019-10-10 Yannick Moy <moy@adacore.com>
+
+ * inline.adb (Can_Be_Inlined_In_GNATprove_Mode): Add subprograms
+ with deep parameter or result type as not candidates for
+ inlining.
+
+2019-10-10 Vadim Godunko <godunko@adacore.com>
+
+ * libgnat/g-exptty.ads (TTY_Process_Descriptor): Set default
+ value for Process.
+
+2019-10-10 Bob Duff <duff@adacore.com>
+
+ * sem_prag.adb (Defer_Compile_Time_Warning_Error_To_BE): In
+ addition to saving the pragma for further processing, copy the
+ pragma into the main unit if necessary.
+
+2019-10-10 Bob Duff <duff@adacore.com>
+
+ * einfo.ads, einfo.adb (Invariants_Ignored): New flag on types.
+ This leaves just one unused flag.
+ * sem_prag.adb (Invariant): Set the flag if appropriate.
+ * exp_util.adb (Make_Invariant_Call): Check the flag.
+
+2019-10-10 Arnaud Charlet <charlet@adacore.com>
+
+ * gnat1drv.adb (Gnat1drv): Skip code generation when handling an
+ incomplete unit with -gnatceg.
+
+2019-10-10 Gary Dismukes <dismukes@adacore.com>
+
+ * exp_ch7.adb (Check_Unnesting_Elaboration_Code): Various
+ cleanups.
+ (Set_Elab_Proc): New procedure to create the defining identifier
+ for a procedure created to encapsulate top-level blocks
+ occurring as a part of library package elaboration.
+ (First_Local_Scope): Function replaced by
+ Reset_Scopes_To_Elab_Proc.
+ (Reset_Scopes_To_Elab_Proc): New recursive procedure based on
+ First_Local_Scope, which it replaces, that is called to traverse
+ the statements of a library package body to locate top-level
+ blocks and determine whether they contain nested subprograms
+ that might address library-level objects of the package. Such
+ blocks (and loops) and certain top-level subprograms within the
+ statements will have their Scope reset here to match an
+ encapsulating procedure created by
+ Check_Unnesting_Elaboration_Code that will contain the
+ statements.
+ (Check_Unnesting_In_Decls_Or_Stmts): Code for handling blocks
+ factored out into Unnest_Block. Add handling for package
+ declarations and bodies, making recursive calls for
+ visible/private declarations, body declarations, statements, and
+ exception handlers. Also remove test for Is_Compilation_Unit:
+ caller tests for Is_Library_Level_Entity instead. Also, this
+ proc's name was changed from Check_Unnesting_In_Declarations.
+ (Check_Unnesting_In_Handlers): New procedure to traverse a
+ sequence of exception handlers, calling
+ Check_Unnesting_In_Decls_Or_Stmts on the statements of each
+ handler.
+ (Expand_N_Package_Body): Call Check_Unnesting_* routines only
+ when Unnest_Subprogram_Mode is set and the current scope is a
+ library-level entity (which includes packages and instantiations
+ nested directly within a library unit).
+ (Expand_N_Package_Declaration): Call Check_Unnesting_* routines
+ only when Unnest_Subprogram_Mode is set and the current scope is
+ a library-level entity (which includes packages and
+ instantiations nested directly within a library unit).
+ (Unnest_Block): New procedure factored out of
+ Check_Unnesting_In_Decls_Or_Stmts, for creating a new procedure
+ to replace a block statement and resetting the Scope fields of
+ the block's top-level entities.
+
+2019-10-10 Anthony Leonardo Gracio <leonardo@adacore.com>
+
+ * doc/gnat_ugn/about_this_guide.rst,
+ doc/gnat_ugn/building_executable_programs_with_gnat.rst,
+ doc/gnat_ugn/getting_started_with_gnat.rst,
+ doc/gnat_ugn/gnat_and_program_execution.rst, errout.ads,
+ exp_ch3.adb, gnatls.adb, impunit.adb, lib-writ.ads, opt.ads,
+ sem_ch7.adb, sem_prag.adb, sem_res.adb, sem_warn.adb,
+ terminals.c: Replace GPS by GNAT Studio.
+ * gnat_ugn.texi: Regenerate.
+
+2019-10-10 Ed Schonberg <schonberg@adacore.com>
+
+ * exp_ch6.adb (Expand_Simple_Function_Return_Statement): If the
+ function to which the return statement applies is an
+ Ignored_Ghost_Function, do not indicate that it uses the
+ secondary stack when the return type is unconstrained.
+
+2019-10-10 Bob Duff <duff@adacore.com>
+
+ * libgnat/a-cbdlli.adb, libgnat/a-cbhama.adb,
+ libgnat/a-cbhase.adb, libgnat/a-cbmutr.adb,
+ libgnat/a-cborma.adb, libgnat/a-cborse.adb,
+ libgnat/a-cdlili.adb, libgnat/a-cidlli.adb,
+ libgnat/a-cihama.adb, libgnat/a-cihase.adb,
+ libgnat/a-cimutr.adb, libgnat/a-ciorma.adb,
+ libgnat/a-ciorse.adb, libgnat/a-cobove.adb,
+ libgnat/a-cohama.adb, libgnat/a-cohase.adb,
+ libgnat/a-coinve.adb, libgnat/a-comutr.adb,
+ libgnat/a-conhel.adb, libgnat/a-convec.adb,
+ libgnat/a-coorma.adb, libgnat/a-coorse.adb (Reference,
+ Constant_Reference): Use Busy instead of Lock, so we forbid
+ tampering with cursors, rather than tampering with elements.
+
+2019-10-10 Ed Schonberg <schonberg@adacore.com>
+
+ * sem_cat.adb (Set_Categorization_From_Pragma): Do not modify
+ any visibility settings if there are no compilation_unit pragmas
+ following the package declaration. Add comments for future
+ cleanup.
+
+2019-10-10 Patrick Bernardi <bernardi@adacore.com>
+
+ * bindgen.adb (System_Secondary_Stack_Package_In_Closure):
+ Renamed flag System_Secondary_Stack_Used to be clearer of what
+ it represents.
+ (Gen_Adainit): Refactor secondary stack related code to make it
+ clearer.
+ * rtsfind.adb (Load_RTU): Don't set Sec_Stack_Used flag here
+ (RTE): Set Sec_Stack_Used if the System.Secondary_Stack is
+ referenced, but not if we're ignoring ghost code.
+
+2019-10-10 Piotr Trojanek <trojanek@adacore.com>
+
+ * sem_prag.adb (Analyze_Global_In_Decl_Part): Simplify previous
+ test, just like in a recent commit we simplified a similar test
+ for Depends contract.
+
2019-10-04 Joseph Myers <joseph@codesourcery.com>
* gcc-interface/utils.c (flag_isoc2x): New variable.
diff --git a/gcc/ada/atree.adb b/gcc/ada/atree.adb
index 15219413394..ef1d885c76c 100644
--- a/gcc/ada/atree.adb
+++ b/gcc/ada/atree.adb
@@ -1924,6 +1924,30 @@ package body Atree is
V11);
end Nkind_In;
+ function Nkind_In
+ (N : Node_Id;
+ V1 : Node_Kind;
+ V2 : Node_Kind;
+ V3 : Node_Kind;
+ V4 : Node_Kind;
+ V5 : Node_Kind;
+ V6 : Node_Kind;
+ V7 : Node_Kind;
+ V8 : Node_Kind;
+ V9 : Node_Kind;
+ V10 : Node_Kind;
+ V11 : Node_Kind;
+ V12 : Node_Kind;
+ V13 : Node_Kind;
+ V14 : Node_Kind;
+ V15 : Node_Kind;
+ V16 : Node_Kind) return Boolean
+ is
+ begin
+ return Nkind_In (Nkind (N), V1, V2, V3, V4, V5, V6, V7, V8, V9, V10,
+ V11, V12, V13, V14, V15, V16);
+ end Nkind_In;
+
--------
-- No --
--------
diff --git a/gcc/ada/atree.ads b/gcc/ada/atree.ads
index 7de8a9ec926..e6617e9d4be 100644
--- a/gcc/ada/atree.ads
+++ b/gcc/ada/atree.ads
@@ -780,6 +780,27 @@ package Atree is
V10 : Node_Kind;
V11 : Node_Kind) return Boolean;
+ -- 12..15-parameter versions are not yet needed
+
+ function Nkind_In
+ (N : Node_Id;
+ V1 : Node_Kind;
+ V2 : Node_Kind;
+ V3 : Node_Kind;
+ V4 : Node_Kind;
+ V5 : Node_Kind;
+ V6 : Node_Kind;
+ V7 : Node_Kind;
+ V8 : Node_Kind;
+ V9 : Node_Kind;
+ V10 : Node_Kind;
+ V11 : Node_Kind;
+ V12 : Node_Kind;
+ V13 : Node_Kind;
+ V14 : Node_Kind;
+ V15 : Node_Kind;
+ V16 : Node_Kind) return Boolean;
+
pragma Inline (Nkind_In);
-- Inline all above functions
diff --git a/gcc/ada/bindgen.adb b/gcc/ada/bindgen.adb
index e60cb7a7590..9ac50fe35ef 100644
--- a/gcc/ada/bindgen.adb
+++ b/gcc/ada/bindgen.adb
@@ -81,7 +81,7 @@ package body Bindgen is
-- domains just before calling the main procedure from the environment
-- task.
- System_Secondary_Stack_Used : Boolean := False;
+ System_Secondary_Stack_Package_In_Closure : Boolean := False;
-- Flag indicating whether the unit System.Secondary_Stack is in the
-- closure of the partition. This is set by Resolve_Binder_Options, and
-- is used to initialize the package in cases where the run-time brings
@@ -585,29 +585,33 @@ package body Bindgen is
WBI ("");
end if;
- -- A restricted run-time may attempt to initialize the main task's
- -- secondary stack even if the stack is not used. Consequently,
- -- the binder needs to initialize Binder_Sec_Stacks_Count anytime
- -- System.Secondary_Stack is in the enclosure of the partition.
+ if System_Secondary_Stack_Package_In_Closure then
+ -- System.Secondary_Stack is in the closure of the program
+ -- because the program uses the secondary stack or the restricted
+ -- run-time is unconditionally calling SS_Init. In both cases,
+ -- SS_Init needs to know the number of secondary stacks created by
+ -- the binder.
- if System_Secondary_Stack_Used then
WBI (" Binder_Sec_Stacks_Count : Natural;");
WBI (" pragma Import (Ada, Binder_Sec_Stacks_Count, " &
"""__gnat_binder_ss_count"");");
WBI ("");
- end if;
- if Sec_Stack_Used then
- WBI (" Default_Secondary_Stack_Size : " &
- "System.Parameters.Size_Type;");
- WBI (" pragma Import (C, Default_Secondary_Stack_Size, " &
- """__gnat_default_ss_size"");");
+ -- Import secondary stack pool variables if the secondary stack
+ -- used. They are not referenced otherwise.
- WBI (" Default_Sized_SS_Pool : System.Address;");
- WBI (" pragma Import (Ada, Default_Sized_SS_Pool, " &
- """__gnat_default_ss_pool"");");
+ if Sec_Stack_Used then
+ WBI (" Default_Secondary_Stack_Size : " &
+ "System.Parameters.Size_Type;");
+ WBI (" pragma Import (C, Default_Secondary_Stack_Size, " &
+ """__gnat_default_ss_size"");");
- WBI ("");
+ WBI (" Default_Sized_SS_Pool : System.Address;");
+ WBI (" pragma Import (Ada, Default_Sized_SS_Pool, " &
+ """__gnat_default_ss_pool"");");
+
+ WBI ("");
+ end if;
end if;
WBI (" begin");
@@ -642,48 +646,49 @@ package body Bindgen is
WBI (" null;");
end if;
- -- Generate default-sized secondary stack pool and set secondary
- -- stack globals.
-
- if Sec_Stack_Used then
+ -- Generate the default-sized secondary stack pool if the secondary
+ -- stack is used by the program.
- -- Elaborate the body of the binder to initialize the default-
- -- sized secondary stack pool.
+ if System_Secondary_Stack_Package_In_Closure then
+ if Sec_Stack_Used then
+ -- Elaborate the body of the binder to initialize the default-
+ -- sized secondary stack pool.
- WBI ("");
- WBI (" " & Get_Ada_Main_Name & "'Elab_Body;");
+ WBI ("");
+ WBI (" " & Get_Ada_Main_Name & "'Elab_Body;");
- -- Generate the default-sized secondary stack pool and set the
- -- related secondary stack globals.
+ -- Generate the default-sized secondary stack pool and set the
+ -- related secondary stack globals.
- Set_String (" Default_Secondary_Stack_Size := ");
+ Set_String (" Default_Secondary_Stack_Size := ");
- if Opt.Default_Sec_Stack_Size /= Opt.No_Stack_Size then
- Set_Int (Opt.Default_Sec_Stack_Size);
- else
- Set_String ("System.Parameters.Runtime_Default_Sec_Stack_Size");
- end if;
+ if Opt.Default_Sec_Stack_Size /= Opt.No_Stack_Size then
+ Set_Int (Opt.Default_Sec_Stack_Size);
+ else
+ Set_String
+ ("System.Parameters.Runtime_Default_Sec_Stack_Size");
+ end if;
- Set_Char (';');
- Write_Statement_Buffer;
+ Set_Char (';');
+ Write_Statement_Buffer;
- Set_String (" Binder_Sec_Stacks_Count := ");
- Set_Int (Num_Sec_Stacks);
- Set_Char (';');
- Write_Statement_Buffer;
+ Set_String (" Binder_Sec_Stacks_Count := ");
+ Set_Int (Num_Sec_Stacks);
+ Set_Char (';');
+ Write_Statement_Buffer;
- WBI (" Default_Sized_SS_Pool := " &
- "Sec_Default_Sized_Stacks'Address;");
- WBI ("");
+ WBI (" Default_Sized_SS_Pool := " &
+ "Sec_Default_Sized_Stacks'Address;");
+ WBI ("");
- -- When a restricted run-time initializes the main task's secondary
- -- stack but the program does not use it, no secondary stack is
- -- generated. Binder_Sec_Stacks_Count is set to zero so the run-time
- -- is aware that the lack of pre-allocated secondary stack is
- -- expected.
+ else
+ -- The presence of System.Secondary_Stack in the closure of the
+ -- program implies the restricted run-time is unconditionally
+ -- calling SS_Init. Let SS_Init know that no stacks were
+ -- created.
- elsif System_Secondary_Stack_Used then
- WBI (" Binder_Sec_Stacks_Count := 0;");
+ WBI (" Binder_Sec_Stacks_Count := 0;");
+ end if;
end if;
-- Normal case (standard library not suppressed). Set all global values
@@ -3086,7 +3091,8 @@ package body Bindgen is
-- Ditto for the use of System.Secondary_Stack
Check_Package
- (System_Secondary_Stack_Used, "system.secondary_stack%s");
+ (System_Secondary_Stack_Package_In_Closure,
+ "system.secondary_stack%s");
-- Ditto for use of an SMP bareboard runtime
diff --git a/gcc/ada/doc/gnat_ugn/about_this_guide.rst b/gcc/ada/doc/gnat_ugn/about_this_guide.rst
index d322b9dba21..1ab2f4cfa38 100644
--- a/gcc/ada/doc/gnat_ugn/about_this_guide.rst
+++ b/gcc/ada/doc/gnat_ugn/about_this_guide.rst
@@ -90,11 +90,11 @@ following documents:
* :title:`GNAT Reference_Manual`, which contains all reference material for the GNAT
implementation of Ada.
-* :title:`Using the GNAT Programming Studio`, which describes the GPS
+* :title:`Using GNAT Studio`, which describes the GNAT Studio
Integrated Development Environment.
-* :title:`GNAT Programming Studio Tutorial`, which introduces the
- main GPS features through examples.
+* :title:`GNAT Studio Tutorial`, which introduces the
+ main GNAT Studio features through examples.
* :title:`Debugging with GDB`,
for all details on the use of the GNU source-level debugger.
diff --git a/gcc/ada/doc/gnat_ugn/building_executable_programs_with_gnat.rst b/gcc/ada/doc/gnat_ugn/building_executable_programs_with_gnat.rst
index 6f134525462..457646a83be 100644
--- a/gcc/ada/doc/gnat_ugn/building_executable_programs_with_gnat.rst
+++ b/gcc/ada/doc/gnat_ugn/building_executable_programs_with_gnat.rst
@@ -2377,7 +2377,7 @@ file) and have the following form:
The first integer after the file name is the line number in the file,
and the second integer is the column number within the line.
-``GPS`` can parse the error messages
+``GNAT Studio`` can parse the error messages
and point to the referenced character.
The following switches provide control over the error message
format:
@@ -5139,7 +5139,7 @@ checks to be performed. The following checks are defined:
.. end of switch description (leave this comment to ease automatic parsing for
-.. GPS
+.. GNAT Studio
In the above rules, appearing in column one is always permitted, that is,
counts as meeting either a requirement for a required preceding space,
diff --git a/gcc/ada/doc/gnat_ugn/getting_started_with_gnat.rst b/gcc/ada/doc/gnat_ugn/getting_started_with_gnat.rst
index 756e301c118..34dc35504ab 100644
--- a/gcc/ada/doc/gnat_ugn/getting_started_with_gnat.rst
+++ b/gcc/ada/doc/gnat_ugn/getting_started_with_gnat.rst
@@ -9,11 +9,11 @@ Getting Started with GNAT
This chapter describes how to use GNAT's command line interface to build
executable Ada programs.
On most platforms a visually oriented Integrated Development Environment
-is also available, the GNAT Programming Studio (GPS).
-GPS offers a graphical "look and feel", support for development in
+is also available, the GNAT Programming Studio (GNAT Studio).
+GNAT Studio offers a graphical "look and feel", support for development in
other programming languages, comprehensive browsing features, and
many other capabilities.
-For information on GPS please refer to
+For information on GNAT Studio please refer to
:title:`Using the GNAT Programming Studio`.
diff --git a/gcc/ada/doc/gnat_ugn/gnat_and_program_execution.rst b/gcc/ada/doc/gnat_ugn/gnat_and_program_execution.rst
index 56ee1033eb8..cae61e9d62e 100644
--- a/gcc/ada/doc/gnat_ugn/gnat_and_program_execution.rst
+++ b/gcc/ada/doc/gnat_ugn/gnat_and_program_execution.rst
@@ -116,9 +116,9 @@ Running GDB
This section describes how to initiate the debugger.
-The debugger can be launched from a ``GPS`` menu or
+The debugger can be launched from a ``GNAT Studio`` menu or
directly from the command line. The description below covers the latter use.
-All the commands shown can be used in the ``GPS`` debug console window,
+All the commands shown can be used in the ``GNAT Studio`` debug console window,
but there are usually more GUI-based ways to achieve the same effect.
The command to run ``GDB`` is
diff --git a/gcc/ada/einfo.adb b/gcc/ada/einfo.adb
index dcbeac5780c..98b508f6590 100644
--- a/gcc/ada/einfo.adb
+++ b/gcc/ada/einfo.adb
@@ -629,8 +629,8 @@ package body Einfo is
-- Is_Activation_Record Flag305
-- Needs_Activation_Record Flag306
-- Is_Loop_Parameter Flag307
+ -- Invariants_Ignored Flag308
- -- (unused) Flag308
-- (unused) Flag309
-- Note: Flag310-317 are defined in atree.ads/adb, but not yet in atree.h
@@ -2077,6 +2077,12 @@ package body Einfo is
return Node21 (Id);
end Interface_Name;
+ function Invariants_Ignored (Id : E) return B is
+ begin
+ pragma Assert (Is_Type (Id));
+ return Flag308 (Id);
+ end Invariants_Ignored;
+
function Is_Abstract_Subprogram (Id : E) return B is
begin
pragma Assert (Is_Overloadable (Id));
@@ -5278,6 +5284,12 @@ package body Einfo is
Set_Node21 (Id, V);
end Set_Interface_Name;
+ procedure Set_Invariants_Ignored (Id : E; V : B := True) is
+ begin
+ pragma Assert (Is_Type (Id));
+ Set_Flag308 (Id, V);
+ end Set_Invariants_Ignored;
+
procedure Set_Is_Abstract_Subprogram (Id : E; V : B := True) is
begin
pragma Assert (Is_Overloadable (Id));
@@ -9785,6 +9797,7 @@ package body Einfo is
W ("In_Package_Body", Flag48 (Id));
W ("In_Private_Part", Flag45 (Id));
W ("In_Use", Flag8 (Id));
+ W ("Invariants_Ignored", Flag308 (Id));
W ("Is_Abstract_Subprogram", Flag19 (Id));
W ("Is_Abstract_Type", Flag146 (Id));
W ("Is_Access_Constant", Flag69 (Id));
diff --git a/gcc/ada/einfo.ads b/gcc/ada/einfo.ads
index 3e968a29bd8..536663142cc 100644
--- a/gcc/ada/einfo.ads
+++ b/gcc/ada/einfo.ads
@@ -1739,7 +1739,7 @@ package Einfo is
-- Has_Inherited_Invariants (Flag291) [base type only]
-- Defined in all type entities. Set on private extensions and derived
--- types which inherit at least on class-wide invariant from a parent or
+-- types which inherit at least one class-wide invariant from a parent or
-- an interface type. The flag is also set on the full view of a private
-- extension for completeness.
@@ -1841,7 +1841,7 @@ package Einfo is
-- when the type is subject to pragma Default_Initial_Condition.
-- Has_Own_Invariants (Flag232) [base type only]
--- Defined in all type entities. Set on any type which defines at least
+-- Defined in all type entities. Set on any type that defines at least
-- one invariant of its own. The flag is also set on the full view of a
-- private type for completeness.
@@ -2259,6 +2259,11 @@ package Einfo is
-- implemented by a tagged type that are not already implemented by the
-- ancestors (Ada 2005: AI-251).
+-- Invariants_Ignored (Flag308)
+-- Defined on all types. Indicates whether the type declaration is in
+-- a context where Assertion_Policy is Ignore, in which case no checks
+-- (static or dynamic) must be generated for objects of the type.
+
-- Invariant_Procedure (synthesized)
-- Defined in types and subtypes. Set for private types and their full
-- views if one or more [class-wide] invariants apply to the type, or
@@ -7272,6 +7277,7 @@ package Einfo is
function Interface_Alias (Id : E) return E;
function Interface_Name (Id : E) return N;
function Interfaces (Id : E) return L;
+ function Invariants_Ignored (Id : E) return B;
function Is_Abstract_Subprogram (Id : E) return B;
function Is_Abstract_Type (Id : E) return B;
function Is_Access_Constant (Id : E) return B;
@@ -7973,6 +7979,7 @@ package Einfo is
procedure Set_Interface_Alias (Id : E; V : E);
procedure Set_Interface_Name (Id : E; V : N);
procedure Set_Interfaces (Id : E; V : L);
+ procedure Set_Invariants_Ignored (Id : E; V : B := True);
procedure Set_Is_Abstract_Subprogram (Id : E; V : B := True);
procedure Set_Is_Abstract_Type (Id : E; V : B := True);
procedure Set_Is_Access_Constant (Id : E; V : B := True);
@@ -8801,6 +8808,7 @@ package Einfo is
pragma Inline (Interface_Alias);
pragma Inline (Interface_Name);
pragma Inline (Interfaces);
+ pragma Inline (Invariants_Ignored);
pragma Inline (Is_Abstract_Subprogram);
pragma Inline (Is_Abstract_Type);
pragma Inline (Is_Access_Constant);
@@ -9338,6 +9346,7 @@ package Einfo is
pragma Inline (Set_Interface_Alias);
pragma Inline (Set_Interface_Name);
pragma Inline (Set_Interfaces);
+ pragma Inline (Set_Invariants_Ignored);
pragma Inline (Set_Is_Abstract_Subprogram);
pragma Inline (Set_Is_Abstract_Type);
pragma Inline (Set_Is_Access_Constant);
diff --git a/gcc/ada/errout.ads b/gcc/ada/errout.ads
index 9a54c7c68b6..37db3e585ff 100644
--- a/gcc/ada/errout.ads
+++ b/gcc/ada/errout.ads
@@ -647,8 +647,8 @@ package Errout is
-- CODEFIX Facility --
-----------------------
- -- The GPS and GNATBench IDE's have a codefix facility that allows for
- -- automatic correction of a subset of the errors and warnings issued
+ -- The GNAT Studio and GNATBench IDE's have a codefix facility that allows
+ -- for automatic correction of a subset of the errors and warnings issued
-- by the compiler. This is done by recognizing the text of specific
-- messages using appropriate matching patterns.
diff --git a/gcc/ada/exp_ch3.adb b/gcc/ada/exp_ch3.adb
index 18c6aafe294..82a58b788bf 100644
--- a/gcc/ada/exp_ch3.adb
+++ b/gcc/ada/exp_ch3.adb
@@ -6335,7 +6335,8 @@ package body Exp_Ch3 is
-- would otherwise make two copies. The RM allows removing redunant
-- Adjust/Finalize calls, but does not allow insertion of extra ones.
- -- This part is disabled for now, because it breaks GPS builds
+ -- This part is disabled for now, because it breaks GNAT Studio
+ -- builds
(False -- ???
and then Nkind (Expr_Q) = N_Explicit_Dereference
diff --git a/gcc/ada/exp_ch4.adb b/gcc/ada/exp_ch4.adb
index 82145b42a19..158dcb59cc5 100644
--- a/gcc/ada/exp_ch4.adb
+++ b/gcc/ada/exp_ch4.adb
@@ -9577,9 +9577,9 @@ package body Exp_Ch4 is
Typ : constant Entity_Id := Etype (Left_Opnd (N));
begin
- -- Case of elementary type with standard operator. But if
- -- unnesting, handle elementary types whose Equivalent_Types are
- -- records because there may be padding or undefined fields.
+ -- Case of elementary type with standard operator. But if unnesting,
+ -- handle elementary types whose Equivalent_Types are records because
+ -- there may be padding or undefined fields.
if Is_Elementary_Type (Typ)
and then Sloc (Entity (N)) = Standard_Location
diff --git a/gcc/ada/exp_ch6.adb b/gcc/ada/exp_ch6.adb
index c569ca33af7..b31132281bf 100644
--- a/gcc/ada/exp_ch6.adb
+++ b/gcc/ada/exp_ch6.adb
@@ -6895,7 +6895,12 @@ package body Exp_Ch6 is
elsif Is_Thunk (Current_Scope) and then Is_Incomplete_Type (Exptyp) then
return;
- elsif not Requires_Transient_Scope (R_Type) then
+ -- A return statement from a Ghost function does not use the secondary
+ -- stack (or any other one).
+
+ elsif not Requires_Transient_Scope (R_Type)
+ or else Is_Ignored_Ghost_Entity (Scope_Id)
+ then
-- Mutable records with variable-length components are not returned
-- on the sec-stack, so we need to make sure that the back end will
diff --git a/gcc/ada/exp_ch7.adb b/gcc/ada/exp_ch7.adb
index b00fc9291d0..297e27dcf23 100644
--- a/gcc/ada/exp_ch7.adb
+++ b/gcc/ada/exp_ch7.adb
@@ -364,20 +364,47 @@ package body Exp_Ch7 is
procedure Check_Unnesting_Elaboration_Code (N : Node_Id);
-- The statement part of a package body that is a compilation unit may
- -- contain blocks that declare local subprograms. In Subprogram_Unnesting
+ -- contain blocks that declare local subprograms. In Subprogram_Unnesting_
-- Mode such subprograms must be handled as nested inside the (implicit)
-- elaboration procedure that executes that statement part. To handle
-- properly uplevel references we construct that subprogram explicitly,
-- to contain blocks and inner subprograms, The statement part becomes
-- a call to this subprogram. This is only done if blocks are present
- -- in the statement list of the body.
-
- procedure Check_Unnesting_In_Declarations (Decls : List_Id);
- -- Similarly, the declarations in the package body may have created
- -- blocks with nested subprograms. Such a block must be transformed into a
- -- procedure followed by a call to it, so that unnesting can handle uplevel
- -- references within these nested subprograms (typically generated
- -- subprograms to handle finalization actions).
+ -- in the statement list of the body. (It would be nice to unify this
+ -- procedure with Check_Unnesting_In_Decls_Or_Stmts, if possible, since
+ -- they're doing very similar work, but are structured differently. ???)
+
+ procedure Check_Unnesting_In_Decls_Or_Stmts (Decls_Or_Stmts : List_Id);
+ -- Similarly, the declarations or statements in library-level packages may
+ -- have created blocks blocks with nested subprograms. Such a block must be
+ -- transformed into a procedure followed by a call to it, so that unnesting
+ -- can handle uplevel references within these nested subprograms (typically
+ -- subprograms that handle finalization actions). This also applies to
+ -- nested packages, including instantiations, in which case it must
+ -- recursively process inner bodies.
+
+ procedure Check_Unnesting_In_Handlers (N : Node_Id);
+ -- Similarly, check for blocks with nested subprograms occurring within
+ -- a set of exception handlers associated with a package body N.
+
+ procedure Unnest_Block (Decl : Node_Id);
+ -- Blocks that contain nested subprograms with up-level references need to
+ -- create activation records for them. We do this by rewriting the block as
+ -- a procedure, followed by a call to it in the same declarative list, to
+ -- replicate the semantics of the original block.
+ --
+ -- A common source for such block is a transient block created for a
+ -- construct (declaration, assignment, etc.) that involves controlled
+ -- actions or secondary-stack management, in which case the nested
+ -- subprogram is a finalizer.
+
+ procedure Unnest_Loop (Loop_Stmt : Node_Id);
+ -- Top-level Loops that contain nested subprograms with up-level references
+ -- need to have activation records. We do this by rewriting the loop as a
+ -- procedure containing the loop, followed by a call to the procedure in
+ -- the same library-level declarative list, to replicate the semantics of
+ -- the original loop. Such loops can occur due to aggregate expansions and
+ -- other constructs.
procedure Check_Visibly_Controlled
(Prim : Final_Primitives;
@@ -4020,27 +4047,39 @@ package body Exp_Ch7 is
--------------------------------------
procedure Check_Unnesting_Elaboration_Code (N : Node_Id) is
- Loc : constant Source_Ptr := Sloc (N);
- First_Ent : Entity_Id := Empty;
- Loop_Id : Entity_Id := Empty;
-
- function First_Local_Scope (L : List_Id) return Entity_Id;
- -- Find first entity in the elaboration code of the body that contains
- -- or represents a subprogram body. A body can appear within a block or
- -- a loop or can appear by itself if generated for an object declaration
- -- that involves controlled actions. The first such entity encountered
- -- is used to reset the scopes of all entities that become local to the
- -- new elaboration procedure. This is needed for subsequent unnesting,
- -- which depends on the scope links to determine the nesting level of
- -- each subprogram.
+ Loc : constant Source_Ptr := Sloc (N);
+ Block_Elab_Proc : Entity_Id := Empty;
+
+ procedure Set_Block_Elab_Proc;
+ -- Create a defining identifier for a procedure that will replace
+ -- a block with nested subprograms (unless it has already been created,
+ -- in which case this is a no-op).
+
+ procedure Set_Block_Elab_Proc is
+ begin
+ if No (Block_Elab_Proc) then
+ Block_Elab_Proc :=
+ Make_Defining_Identifier (Loc, Chars => New_Internal_Name ('I'));
+ end if;
+ end Set_Block_Elab_Proc;
+
+ procedure Reset_Scopes_To_Block_Elab_Proc (L : List_Id);
+ -- Find entities in the elaboration code of a library package body that
+ -- contain or represent a subprogram body. A body can appear within a
+ -- block or a loop or can appear by itself if generated for an object
+ -- declaration that involves controlled actions. The first such entity
+ -- forces creation of a new procedure entity (via Set_Block_Elab_Proc)
+ -- that will be used to reset the scopes of all entities that become
+ -- local to the new elaboration procedure. This is needed for subsequent
+ -- unnesting actions, which depend on proper setting of the Scope links
+ -- to determine the nesting level of each subprogram.
-----------------------
-- Find_Local_Scope --
-----------------------
- function First_Local_Scope (L : List_Id) return Entity_Id is
+ procedure Reset_Scopes_To_Block_Elab_Proc (L : List_Id) is
Id : Entity_Id;
- Scop : Entity_Id;
Stat : Node_Id;
begin
@@ -4050,41 +4089,36 @@ package body Exp_Ch7 is
when N_Block_Statement =>
Id := Entity (Identifier (Stat));
- if No (First_Ent) then
- First_Ent := Id;
- end if;
+ -- The Scope of this block needs to be reset to the new
+ -- procedure if the block contains nested subprograms.
if Present (Id) and then Contains_Subprogram (Id) then
- return Id;
+ Set_Block_Elab_Proc;
+ Set_Scope (Id, Block_Elab_Proc);
end if;
when N_Loop_Statement =>
Id := Entity (Identifier (Stat));
- if No (First_Ent) then
- First_Ent := Id;
- end if;
-
- if Contains_Subprogram (Id) then
+ if Present (Id) and then Contains_Subprogram (Id) then
if Scope (Id) = Current_Scope then
- Loop_Id := Id;
+ Set_Block_Elab_Proc;
+ Set_Scope (Id, Block_Elab_Proc);
end if;
-
- return Id;
end if;
- when N_If_Statement =>
- Scop := First_Local_Scope (Then_Statements (Stat));
+ -- We traverse the loop's statements as well, which may
+ -- include other block (etc.) statements that need to have
+ -- their Scope set to Block_Elab_Proc. (Is this really the
+ -- case, or do such nested blocks refer to the loop scope
+ -- rather than the loop's enclosing scope???.)
- if Present (Scop) then
- return Scop;
- end if;
+ Reset_Scopes_To_Block_Elab_Proc (Statements (Stat));
- Scop := First_Local_Scope (Else_Statements (Stat));
+ when N_If_Statement =>
+ Reset_Scopes_To_Block_Elab_Proc (Then_Statements (Stat));
- if Present (Scop) then
- return Scop;
- end if;
+ Reset_Scopes_To_Block_Elab_Proc (Else_Statements (Stat));
declare
Elif : Node_Id;
@@ -4092,11 +4126,8 @@ package body Exp_Ch7 is
begin
Elif := First (Elsif_Parts (Stat));
while Present (Elif) loop
- Scop := First_Local_Scope (Statements (Elif));
-
- if Present (Scop) then
- return Scop;
- end if;
+ Reset_Scopes_To_Block_Elab_Proc
+ (Then_Statements (Elif));
Next (Elif);
end loop;
@@ -4109,24 +4140,19 @@ package body Exp_Ch7 is
begin
Alt := First (Alternatives (Stat));
while Present (Alt) loop
- Scop := First_Local_Scope (Statements (Alt));
-
- if Present (Scop) then
- return Scop;
- end if;
+ Reset_Scopes_To_Block_Elab_Proc (Statements (Alt));
Next (Alt);
end loop;
end;
+ -- Reset the Scope of a subprogram occurring at the top level
+
when N_Subprogram_Body =>
Id := Defining_Entity (Stat);
- if No (First_Ent) then
- First_Ent := Id;
- end if;
-
- return Id;
+ Set_Block_Elab_Proc;
+ Set_Scope (Id, Block_Elab_Proc);
when others =>
null;
@@ -4134,67 +4160,52 @@ package body Exp_Ch7 is
Next (Stat);
end loop;
-
- return Empty;
- end First_Local_Scope;
+ end Reset_Scopes_To_Block_Elab_Proc;
-- Local variables
H_Seq : constant Node_Id := Handled_Statement_Sequence (N);
Elab_Body : Node_Id;
Elab_Call : Node_Id;
- Elab_Proc : Entity_Id;
- Ent : Entity_Id;
-- Start of processing for Check_Unnesting_Elaboration_Code
begin
- if Unnest_Subprogram_Mode
- and then Present (H_Seq)
- and then Is_Compilation_Unit (Current_Scope)
- then
- Ent := First_Local_Scope (Statements (H_Seq));
+ if Present (H_Seq) then
+ Reset_Scopes_To_Block_Elab_Proc (Statements (H_Seq));
- -- There msy be subprograms declared in the exception handlers
+ -- There may be subprograms declared in the exception handlers
-- of the current body.
- if No (Ent) and then Present (Exception_Handlers (H_Seq)) then
+ if Present (Exception_Handlers (H_Seq)) then
declare
Handler : Node_Id := First (Exception_Handlers (H_Seq));
begin
while Present (Handler) loop
- Ent := First_Local_Scope (Statements (Handler));
- if Present (Ent) then
- First_Ent := Ent;
- exit;
- end if;
+ Reset_Scopes_To_Block_Elab_Proc (Statements (Handler));
Next (Handler);
end loop;
end;
end if;
- if Present (Ent) then
- Elab_Proc :=
- Make_Defining_Identifier (Loc,
- Chars => New_Internal_Name ('I'));
-
+ if Present (Block_Elab_Proc) then
Elab_Body :=
Make_Subprogram_Body (Loc,
Specification =>
Make_Procedure_Specification (Loc,
- Defining_Unit_Name => Elab_Proc),
+ Defining_Unit_Name => Block_Elab_Proc),
Declarations => New_List,
Handled_Statement_Sequence =>
Relocate_Node (Handled_Statement_Sequence (N)));
Elab_Call :=
Make_Procedure_Call_Statement (Loc,
- Name => New_Occurrence_Of (Elab_Proc, Loc));
+ Name => New_Occurrence_Of (Block_Elab_Proc, Loc));
Append_To (Declarations (N), Elab_Body);
Analyze (Elab_Body);
- Set_Has_Nested_Subprogram (Elab_Proc);
+ Set_Has_Nested_Subprogram (Block_Elab_Proc);
Set_Handled_Statement_Sequence (N,
Make_Handled_Sequence_Of_Statements (Loc,
@@ -4202,85 +4213,98 @@ package body Exp_Ch7 is
Analyze (Elab_Call);
- -- The scope of all blocks and loops in the elaboration code is
- -- now the constructed elaboration procedure. Nested subprograms
- -- within those blocks will have activation records if they
- -- contain references to entities in the enclosing block or
- -- the package itself.
-
- Ent := First_Ent;
- while Present (Ent) loop
- Set_Scope (Ent, Elab_Proc);
- Next_Entity (Ent);
- end loop;
-
- if Present (Loop_Id) then
- Set_Scope (Loop_Id, Elab_Proc);
- end if;
+ -- Could we reset the scopes of entities associated with the new
+ -- procedure here via a loop over entities rather than doing it in
+ -- the recursive Reset_Scopes_To_Elab_Proc procedure???
end if;
end if;
end Check_Unnesting_Elaboration_Code;
- -------------------------------------
- -- Check_Unnesting_In_Declarations --
- -------------------------------------
+ ---------------------------------------
+ -- Check_Unnesting_In_Decls_Or_Stmts --
+ ---------------------------------------
- procedure Check_Unnesting_In_Declarations (Decls : List_Id) is
- Decl : Node_Id;
- Ent : Entity_Id;
- Loc : Source_Ptr;
- Local_Body : Node_Id;
- Local_Call : Node_Id;
- Local_Proc : Entity_Id;
+ procedure Check_Unnesting_In_Decls_Or_Stmts (Decls_Or_Stmts : List_Id) is
+ Decl_Or_Stmt : Node_Id;
begin
- Local_Call := Empty;
-
if Unnest_Subprogram_Mode
- and then Present (Decls)
- and then Is_Compilation_Unit (Current_Scope)
+ and then Present (Decls_Or_Stmts)
then
- Decl := First (Decls);
- while Present (Decl) loop
- if Nkind (Decl) = N_Block_Statement
- and then Contains_Subprogram (Entity (Identifier (Decl)))
+ Decl_Or_Stmt := First (Decls_Or_Stmts);
+ while Present (Decl_Or_Stmt) loop
+ if Nkind (Decl_Or_Stmt) = N_Block_Statement
+ and then Contains_Subprogram (Entity (Identifier (Decl_Or_Stmt)))
then
- Ent := First_Entity (Entity (Identifier (Decl)));
- Loc := Sloc (Decl);
- Local_Proc :=
- Make_Defining_Identifier (Loc,
- Chars => New_Internal_Name ('P'));
-
- Local_Body :=
- Make_Subprogram_Body (Loc,
- Specification =>
- Make_Procedure_Specification (Loc,
- Defining_Unit_Name => Local_Proc),
- Declarations => Declarations (Decl),
- Handled_Statement_Sequence =>
- Handled_Statement_Sequence (Decl));
+ Unnest_Block (Decl_Or_Stmt);
- Rewrite (Decl, Local_Body);
- Analyze (Decl);
- Set_Has_Nested_Subprogram (Local_Proc);
+ elsif Nkind (Decl_Or_Stmt) = N_Loop_Statement then
+ declare
+ Id : constant Entity_Id :=
+ Entity (Identifier (Decl_Or_Stmt));
- Local_Call :=
- Make_Procedure_Call_Statement (Loc,
- Name => New_Occurrence_Of (Local_Proc, Loc));
+ begin
+ -- When a top-level loop within declarations of a library
+ -- package spec or body contains nested subprograms, we wrap
+ -- it in a procedure to handle possible up-level references
+ -- to entities associated with the loop (such as loop
+ -- parameters).
+
+ if Present (Id) and then Contains_Subprogram (Id) then
+ Unnest_Loop (Decl_Or_Stmt);
+ end if;
+ end;
- Insert_After (Decl, Local_Call);
- Analyze (Local_Call);
+ elsif Nkind (Decl_Or_Stmt) = N_Package_Declaration
+ and then not Modify_Tree_For_C
+ then
+ Check_Unnesting_In_Decls_Or_Stmts
+ (Visible_Declarations (Specification (Decl_Or_Stmt)));
+ Check_Unnesting_In_Decls_Or_Stmts
+ (Private_Declarations (Specification (Decl_Or_Stmt)));
- while Present (Ent) loop
- Set_Scope (Ent, Local_Proc);
- Next_Entity (Ent);
- end loop;
+ elsif Nkind (Decl_Or_Stmt) = N_Package_Body
+ and then not Modify_Tree_For_C
+ then
+ Check_Unnesting_In_Decls_Or_Stmts (Declarations (Decl_Or_Stmt));
+ if Present (Statements
+ (Handled_Statement_Sequence (Decl_Or_Stmt)))
+ then
+ Check_Unnesting_In_Decls_Or_Stmts (Statements
+ (Handled_Statement_Sequence (Decl_Or_Stmt)));
+ Check_Unnesting_In_Handlers (Decl_Or_Stmt);
+ end if;
end if;
- Next (Decl);
+ Next (Decl_Or_Stmt);
end loop;
end if;
- end Check_Unnesting_In_Declarations;
+ end Check_Unnesting_In_Decls_Or_Stmts;
+
+ ---------------------------------
+ -- Check_Unnesting_In_Handlers --
+ ---------------------------------
+
+ procedure Check_Unnesting_In_Handlers (N : Node_Id) is
+ Stmt_Seq : constant Node_Id := Handled_Statement_Sequence (N);
+
+ begin
+ if Present (Stmt_Seq)
+ and then Present (Exception_Handlers (Stmt_Seq))
+ then
+ declare
+ Handler : Node_Id := First (Exception_Handlers (Stmt_Seq));
+ begin
+ while Present (Handler) loop
+ if Present (Statements (Handler)) then
+ Check_Unnesting_In_Decls_Or_Stmts (Statements (Handler));
+ end if;
+
+ Next (Handler);
+ end loop;
+ end;
+ end if;
+ end Check_Unnesting_In_Handlers;
------------------------------
-- Check_Visibly_Controlled --
@@ -5036,8 +5060,20 @@ package body Exp_Ch7 is
-- end of the body statements.
Expand_Pragma_Initial_Condition (Spec_Id, N);
- Check_Unnesting_Elaboration_Code (N);
- Check_Unnesting_In_Declarations (Declarations (N));
+
+ -- If this is a library-level package and unnesting is enabled,
+ -- check for the presence of blocks with nested subprograms occurring
+ -- in elaboration code, and generate procedures to encapsulate the
+ -- blocks in case the nested subprograms make up-level references.
+
+ if Unnest_Subprogram_Mode
+ and then
+ Is_Library_Level_Entity (Current_Scope)
+ then
+ Check_Unnesting_Elaboration_Code (N);
+ Check_Unnesting_In_Decls_Or_Stmts (Declarations (N));
+ Check_Unnesting_In_Handlers (N);
+ end if;
Pop_Scope;
end if;
@@ -5196,8 +5232,17 @@ package body Exp_Ch7 is
Set_Finalizer (Id, Fin_Id);
end if;
- Check_Unnesting_In_Declarations (Visible_Declarations (Spec));
- Check_Unnesting_In_Declarations (Private_Declarations (Spec));
+ -- If this is a library-level package and unnesting is enabled,
+ -- check for the presence of blocks with nested subprograms occurring
+ -- in elaboration code, and generate procedures to encapsulate the
+ -- blocks in case the nested subprograms make up-level references.
+
+ if Unnest_Subprogram_Mode
+ and then Is_Library_Level_Entity (Current_Scope)
+ then
+ Check_Unnesting_In_Decls_Or_Stmts (Visible_Declarations (Spec));
+ Check_Unnesting_In_Decls_Or_Stmts (Private_Declarations (Spec));
+ end if;
end Expand_N_Package_Declaration;
----------------------------
@@ -9180,6 +9225,123 @@ package body Exp_Ch7 is
Store_Actions_In_Scope (Cleanup, L);
end Store_Cleanup_Actions_In_Scope;
+ ------------------
+ -- Unnest_Block --
+ ------------------
+
+ procedure Unnest_Block (Decl : Node_Id) is
+ Loc : constant Source_Ptr := Sloc (Decl);
+ Ent : Entity_Id;
+ Local_Body : Node_Id;
+ Local_Call : Node_Id;
+ Local_Proc : Entity_Id;
+ Local_Scop : Entity_Id;
+
+ begin
+ Local_Scop := Entity (Identifier (Decl));
+ Ent := First_Entity (Local_Scop);
+
+ Local_Proc :=
+ Make_Defining_Identifier (Loc,
+ Chars => New_Internal_Name ('P'));
+
+ Local_Body :=
+ Make_Subprogram_Body (Loc,
+ Specification =>
+ Make_Procedure_Specification (Loc,
+ Defining_Unit_Name => Local_Proc),
+ Declarations => Declarations (Decl),
+ Handled_Statement_Sequence =>
+ Handled_Statement_Sequence (Decl));
+
+ Rewrite (Decl, Local_Body);
+ Analyze (Decl);
+ Set_Has_Nested_Subprogram (Local_Proc);
+
+ Local_Call :=
+ Make_Procedure_Call_Statement (Loc,
+ Name => New_Occurrence_Of (Local_Proc, Loc));
+
+ Insert_After (Decl, Local_Call);
+ Analyze (Local_Call);
+
+ -- The new subprogram has the same scope as the original block
+
+ Set_Scope (Local_Proc, Scope (Local_Scop));
+
+ -- And the entity list of the new procedure is that of the block
+
+ Set_First_Entity (Local_Proc, Ent);
+
+ -- Reset the scopes of all the entities to the new procedure
+
+ while Present (Ent) loop
+ Set_Scope (Ent, Local_Proc);
+ Next_Entity (Ent);
+ end loop;
+ end Unnest_Block;
+
+ -----------------
+ -- Unnest_Loop --
+ -----------------
+
+ procedure Unnest_Loop (Loop_Stmt : Node_Id) is
+ Loc : constant Source_Ptr := Sloc (Loop_Stmt);
+ Ent : Entity_Id;
+ Local_Body : Node_Id;
+ Local_Call : Node_Id;
+ Local_Proc : Entity_Id;
+ Local_Scop : Entity_Id;
+ Loop_Copy : constant Node_Id :=
+ Relocate_Node (Loop_Stmt);
+ begin
+ Local_Scop := Entity (Identifier (Loop_Stmt));
+ Ent := First_Entity (Local_Scop);
+
+ Local_Proc :=
+ Make_Defining_Identifier (Loc,
+ Chars => New_Internal_Name ('P'));
+
+ Local_Body :=
+ Make_Subprogram_Body (Loc,
+ Specification =>
+ Make_Procedure_Specification (Loc,
+ Defining_Unit_Name => Local_Proc),
+ Declarations => Empty_List,
+ Handled_Statement_Sequence =>
+ Make_Handled_Sequence_Of_Statements (Loc,
+ Statements => New_List (Loop_Copy)));
+
+ Set_First_Real_Statement
+ (Handled_Statement_Sequence (Local_Body), Loop_Copy);
+
+ Rewrite (Loop_Stmt, Local_Body);
+ Analyze (Loop_Stmt);
+
+ Set_Has_Nested_Subprogram (Local_Proc);
+
+ Local_Call :=
+ Make_Procedure_Call_Statement (Loc,
+ Name => New_Occurrence_Of (Local_Proc, Loc));
+
+ Insert_After (Loop_Stmt, Local_Call);
+ Analyze (Local_Call);
+
+ -- New procedure has the same scope as the original loop, and the scope
+ -- of the loop is the new procedure.
+
+ Set_Scope (Local_Proc, Scope (Local_Scop));
+ Set_Scope (Local_Scop, Local_Proc);
+
+ -- The entity list of the new procedure is that of the loop
+
+ Set_First_Entity (Local_Proc, Ent);
+
+ -- Note that the entities associated with the loop don't need to have
+ -- their Scope fields reset, since they're still associated with the
+ -- same loop entity that now belongs to the copied loop statement.
+ end Unnest_Loop;
+
--------------------------------
-- Wrap_Transient_Declaration --
--------------------------------
diff --git a/gcc/ada/exp_ch9.adb b/gcc/ada/exp_ch9.adb
index 99bd8d211cb..720c1a9a237 100644
--- a/gcc/ada/exp_ch9.adb
+++ b/gcc/ada/exp_ch9.adb
@@ -6624,6 +6624,13 @@ package body Exp_Ch9 is
Declarations => Declarations (N),
Handled_Statement_Sequence => Build_Accept_Body (N));
+ -- Reset the Scope of local entities associated with the accept
+ -- statement (that currently reference the entry scope) to the
+ -- block scope, to avoid having references to the locals treated
+ -- as up-level references.
+
+ Reset_Scopes_To (Block, Blkent);
+
-- For the analysis of the generated declarations, the parent node
-- must be properly set.
diff --git a/gcc/ada/exp_util.adb b/gcc/ada/exp_util.adb
index 6306320c0cd..36c900b2a28 100644
--- a/gcc/ada/exp_util.adb
+++ b/gcc/ada/exp_util.adb
@@ -9388,10 +9388,16 @@ package body Exp_Util is
Proc_Id := Invariant_Procedure (Typ);
pragma Assert (Present (Proc_Id));
- return
- Make_Procedure_Call_Statement (Loc,
- Name => New_Occurrence_Of (Proc_Id, Loc),
- Parameter_Associations => New_List (Relocate_Node (Expr)));
+ -- Ignore the invariant if that policy is in effect
+
+ if Invariants_Ignored (Typ) then
+ return Make_Null_Statement (Loc);
+ else
+ return
+ Make_Procedure_Call_Statement (Loc,
+ Name => New_Occurrence_Of (Proc_Id, Loc),
+ Parameter_Associations => New_List (Relocate_Node (Expr)));
+ end if;
end Make_Invariant_Call;
------------------------
diff --git a/gcc/ada/freeze.adb b/gcc/ada/freeze.adb
index 93e91b2a9ba..5e1b77511c6 100644
--- a/gcc/ada/freeze.adb
+++ b/gcc/ada/freeze.adb
@@ -8780,6 +8780,7 @@ package body Freeze is
-- (either in pragma CPP_Constructor or in a pragma import).
if Is_Constructor (E)
+ and then Convention (E) = Convention_CPP
and then
(No (Interface_Name (E))
or else String_Equal
diff --git a/gcc/ada/gcc-interface/decl.c b/gcc/ada/gcc-interface/decl.c
index 77c6c9f12e7..29c5a8e7821 100644
--- a/gcc/ada/gcc-interface/decl.c
+++ b/gcc/ada/gcc-interface/decl.c
@@ -585,6 +585,29 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition)
gcc_unreachable ();
}
+ case E_Named_Integer:
+ case E_Named_Real:
+ {
+ tree gnu_ext_name = NULL_TREE;
+
+ if (Is_Public (gnat_entity))
+ gnu_ext_name = create_concat_name (gnat_entity, NULL);
+
+ /* All references are supposed to be folded in the front-end. */
+ gcc_assert (definition && gnu_expr);
+
+ gnu_type = gnat_to_gnu_type (Etype (gnat_entity));
+ gnu_expr = convert (gnu_type, gnu_expr);
+
+ /* Build a CONST_DECL for debugging purposes exclusively. */
+ gnu_decl
+ = create_var_decl (gnu_entity_name, gnu_ext_name, gnu_type,
+ gnu_expr, true, Is_Public (gnat_entity),
+ false, false, false, artificial_p,
+ debug_info_p, NULL, gnat_entity, true);
+ }
+ break;
+
case E_Constant:
/* Ignore constant definitions already marked with the error node. See
the N_Object_Declaration case of gnat_to_gnu for the rationale. */
@@ -1519,18 +1542,16 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition)
/* If this is a constant and we are defining it or it generates a real
symbol at the object level and we are referencing it, we may want
or need to have a true variable to represent it:
- - if optimization isn't enabled, for debugging purposes,
- if the constant is public and not overlaid on something else,
- if its address is taken,
- - if either itself or its type is aliased. */
+ - if it is aliased,
+ - if optimization isn't enabled, for debugging purposes. */
if (TREE_CODE (gnu_decl) == CONST_DECL
&& (definition || Sloc (gnat_entity) > Standard_Location)
- && ((!optimize && debug_info_p)
- || (Is_Public (gnat_entity)
- && No (Address_Clause (gnat_entity)))
+ && ((Is_Public (gnat_entity) && No (Address_Clause (gnat_entity)))
|| Address_Taken (gnat_entity)
|| Is_Aliased (gnat_entity)
- || Is_Aliased (gnat_type)))
+ || (!optimize && debug_info_p)))
{
tree gnu_corr_var
= create_var_decl (gnu_entity_name, gnu_ext_name, gnu_type,
@@ -1540,6 +1561,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition)
attr_list, gnat_entity, false);
SET_DECL_CONST_CORRESPONDING_VAR (gnu_decl, gnu_corr_var);
+ DECL_IGNORED_P (gnu_decl) = 1;
}
/* If this is a constant, even if we don't need a true variable, we
@@ -5004,6 +5026,11 @@ Gigi_Equivalent_Type (Entity_Id gnat_entity)
gnat_equiv = Etype (gnat_entity);
break;
+ case E_Array_Subtype:
+ if (!Is_Constrained (gnat_entity))
+ gnat_equiv = Etype (gnat_entity);
+ break;
+
case E_Class_Wide_Type:
gnat_equiv = Root_Type (gnat_entity);
break;
@@ -6755,6 +6782,15 @@ elaborate_reference_1 (tree ref, void *data)
elaborate_reference_1 (TREE_OPERAND (ref, 0), data),
TREE_OPERAND (ref, 1), NULL_TREE);
+ /* If this is the displacement of a pointer, elaborate the pointer and then
+ displace the result. The actual purpose here is to drop the location on
+ the expression, which may be problematic if replicated on references. */
+ if (TREE_CODE (ref) == POINTER_PLUS_EXPR
+ && TREE_CODE (TREE_OPERAND (ref, 1)) == INTEGER_CST)
+ return build2 (POINTER_PLUS_EXPR, TREE_TYPE (ref),
+ elaborate_reference_1 (TREE_OPERAND (ref, 0), data),
+ TREE_OPERAND (ref, 1));
+
sprintf (suffix, "EXP%d", ++er->n);
return
elaborate_expression_1 (ref, er->entity, suffix, er->definition, false);
@@ -7202,10 +7238,17 @@ gnat_to_gnu_field (Entity_Id gnat_field, tree gnu_record_type, int packed,
&& INTEGRAL_TYPE_P (TREE_TYPE (TYPE_FIELDS (gnu_field_type))))
gnu_field_type = TREE_TYPE (TYPE_FIELDS (gnu_field_type));
+ orig_field_type = gnu_field_type;
gnu_field_type
= make_type_from_size (gnu_field_type, gnu_size,
Has_Biased_Representation (gnat_field));
+ /* If the type has been extended, we may need to cap the alignment. */
+ if (!needs_strict_alignment
+ && gnu_field_type != orig_field_type
+ && tree_int_cst_lt (TYPE_SIZE (orig_field_type), gnu_size))
+ packed = adjust_packed (gnu_field_type, gnu_record_type, packed);
+
orig_field_type = gnu_field_type;
gnu_field_type = maybe_pad_type (gnu_field_type, gnu_size, 0, gnat_field,
false, false, definition, true);
@@ -7889,7 +7932,7 @@ components_to_record (Node_Id gnat_component_list, Entity_Id gnat_record_type,
&& !(Is_Packed (gnat_record_type)
? has_non_packed_fixed_size_field
: Optimize_Alignment_Space (gnat_record_type))
- && !debug__debug_flag_dot_r);
+ && !Debug_Flag_Dot_R);
const bool w_reorder
= (Convention (gnat_record_type) == Convention_Ada
&& Warn_On_Questionable_Layout
@@ -8260,9 +8303,8 @@ annotate_value (tree gnu_size)
{
case INTEGER_CST:
/* For negative values, build NEGATE_EXPR of the opposite. Such values
- can appear for discriminants in expressions for variants. Note that,
- sizetype being unsigned, we don't directly use tree_int_cst_sgn. */
- if (tree_int_cst_sign_bit (gnu_size))
+ can appear for discriminants in expressions for variants. */
+ if (tree_int_cst_sgn (gnu_size) < 0)
{
tree t = wide_int_to_tree (sizetype, -wi::to_wide (gnu_size));
tcode = Negate_Expr;
@@ -8340,9 +8382,8 @@ annotate_value (tree gnu_size)
&& tree_int_cst_sign_bit (TREE_OPERAND (gnu_size, 1)))
{
tcode = Minus_Expr;
- ops[0] = annotate_value (TREE_OPERAND (gnu_size, 0));
- wide_int op1 = -wi::to_wide (TREE_OPERAND (gnu_size, 1));
- ops[1] = annotate_value (wide_int_to_tree (sizetype, op1));
+ wide_int wop1 = -wi::to_wide (TREE_OPERAND (gnu_size, 1));
+ ops[1] = annotate_value (wide_int_to_tree (sizetype, wop1));
break;
}
@@ -8383,9 +8424,9 @@ annotate_value (tree gnu_size)
Such values can appear in expressions with aligning patterns. */
if (TREE_CODE (TREE_OPERAND (gnu_size, 1)) == INTEGER_CST)
{
- wide_int op1 = wi::sext (wi::to_wide (TREE_OPERAND (gnu_size, 1)),
- TYPE_PRECISION (sizetype));
- ops[1] = annotate_value (wide_int_to_tree (sizetype, op1));
+ wide_int wop1 = -wi::to_wide (TREE_OPERAND (gnu_size, 1));
+ tree op1 = wide_int_to_tree (sizetype, wop1);
+ ops[1] = annotate_value (build1 (NEGATE_EXPR, sizetype, op1));
}
break;
diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c
index 7b842d40f7e..61e05d52a54 100644
--- a/gcc/ada/gcc-interface/trans.c
+++ b/gcc/ada/gcc-interface/trans.c
@@ -6881,11 +6881,17 @@ gnat_to_gnu (Node_Id gnat_node)
gnu_result = UI_To_gnu (Intval (gnat_node), gnu_type);
/* If the result overflows (meaning it doesn't fit in its base type),
- abort. We would like to check that the value is within the range
- of the subtype, but that causes problems with subtypes whose usage
- will raise Constraint_Error and with biased representation, so
- we don't. */
- gcc_assert (!TREE_OVERFLOW (gnu_result));
+ abort, unless this is for a named number because that's not fatal.
+ We would like to check that the value is within the range of the
+ subtype, but that causes problems with subtypes whose usage will
+ raise Constraint_Error and also with biased representation. */
+ if (TREE_OVERFLOW (gnu_result))
+ {
+ if (Nkind (Parent (gnat_node)) == N_Number_Declaration)
+ gnu_result = error_mark_node;
+ else
+ gcc_unreachable ();
+ }
}
break;
@@ -7030,6 +7036,7 @@ gnat_to_gnu (Node_Id gnat_node)
break;
case N_Object_Declaration:
+ case N_Number_Declaration:
case N_Exception_Declaration:
gnat_temp = Defining_Entity (gnat_node);
gnu_result = alloc_stmt_list ();
@@ -7052,8 +7059,15 @@ gnat_to_gnu (Node_Id gnat_node)
gnu_expr = gnat_to_gnu (Expression (gnat_node));
- if (type_annotate_only && TREE_CODE (gnu_expr) == ERROR_MARK)
- gnu_expr = NULL_TREE;
+ if (TREE_CODE (gnu_expr) == ERROR_MARK)
+ {
+ /* If this is a named number for which we cannot manipulate
+ the value, just skip the declaration altogether. */
+ if (kind == N_Number_Declaration)
+ break;
+ else if (type_annotate_only)
+ gnu_expr = NULL_TREE;
+ }
}
else
gnu_expr = NULL_TREE;
@@ -7163,7 +7177,6 @@ gnat_to_gnu (Node_Id gnat_node)
gnu_result = alloc_stmt_list ();
break;
- case N_Number_Declaration:
case N_Package_Renaming_Declaration:
/* These are fully handled in the front end. */
/* ??? For package renamings, find a way to use GENERIC namespaces so
@@ -10835,8 +10848,8 @@ Sloc_to_locus (Source_Ptr Sloc, location_t *locus, bool clear_column,
}
Source_File_Index file = Get_Source_File_Index (Sloc);
- Logical_Line_Number line = Get_Logical_Line_Number (Sloc);
- Column_Number column = (clear_column ? 0 : Get_Column_Number (Sloc));
+ Line_Number_Type line = Get_Logical_Line_Number (Sloc);
+ Column_Number_Type column = (clear_column ? 0 : Get_Column_Number (Sloc));
line_map_ordinary *map = LINEMAPS_ORDINARY_MAP_AT (line_table, file - 1);
/* We can have zero if pragma Source_Reference is in effect. */
diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c
index d2891f250a7..e14645ae216 100644
--- a/gcc/ada/gcc-interface/utils.c
+++ b/gcc/ada/gcc-interface/utils.c
@@ -2731,13 +2731,11 @@ create_var_decl (tree name, tree asm_name, tree type, tree init,
&& !have_global_bss_p ())
DECL_COMMON (var_decl) = 1;
- /* Do not emit debug info for a CONST_DECL if optimization isn't enabled,
- since we will create an associated variable. Likewise for an external
- constant whose initializer is not absolute, because this would mean a
- global relocation in a read-only section which runs afoul of the PE-COFF
- run-time relocation mechanism. */
+ /* Do not emit debug info if not requested, or for an external constant whose
+ initializer is not absolute because this would require a global relocation
+ in a read-only section which runs afoul of the PE-COFF run-time relocation
+ mechanism. */
if (!debug_info_p
- || (TREE_CODE (var_decl) == CONST_DECL && !optimize)
|| (extern_flag
&& constant_p
&& init
@@ -5840,6 +5838,11 @@ gnat_write_global_declarations (void)
&& DECL_FUNCTION_IS_DEF (iter))
debug_hooks->early_global_decl (iter);
+ /* Output global constants. */
+ FOR_EACH_VEC_SAFE_ELT (global_decls, i, iter)
+ if (TREE_CODE (iter) == CONST_DECL && !DECL_IGNORED_P (iter))
+ debug_hooks->early_global_decl (iter);
+
/* Then output the global variables. We need to do that after the debug
information for global types is emitted so that they are finalized. Skip
external global variables, unless we need to emit debug info for them:
diff --git a/gcc/ada/gnat1drv.adb b/gcc/ada/gnat1drv.adb
index af07a065276..7d507aaf4fe 100644
--- a/gcc/ada/gnat1drv.adb
+++ b/gcc/ada/gnat1drv.adb
@@ -1412,11 +1412,25 @@ begin
-- It is not an error to analyze in CodePeer mode a spec which requires
-- a body, in order to generate SCIL for this spec.
- -- Ditto for Generate_C_Code mode and generate a C header for a spec.
- elsif CodePeer_Mode or Generate_C_Code then
+ elsif CodePeer_Mode then
Back_End_Mode := Generate_Object;
+ -- Differentiate use of -gnatceg to generate a C header from an Ada spec
+ -- to the CCG case (standard.h found) where C code generation should
+ -- only be performed on full units.
+
+ elsif Generate_C_Code then
+ Name_Len := 10;
+ Name_Buffer (1 .. Name_Len) := "standard.h";
+
+ if Find_File (Name_Find, Osint.Source, Full_Name => True) = No_File
+ then
+ Back_End_Mode := Generate_Object;
+ else
+ Back_End_Mode := Skip;
+ end if;
+
-- It is not an error to analyze in GNATprove mode a spec which requires
-- a body, when the body is not available. During frame condition
-- generation, the corresponding ALI file is generated. During
diff --git a/gcc/ada/gnat_ugn.texi b/gcc/ada/gnat_ugn.texi
index 5db9c76eb15..a1ef122b356 100644
--- a/gcc/ada/gnat_ugn.texi
+++ b/gcc/ada/gnat_ugn.texi
@@ -21,7 +21,7 @@
@copying
@quotation
-GNAT User's Guide for Native Platforms , Sep 14, 2019
+GNAT User's Guide for Native Platforms , Oct 09, 2019
AdaCore
@@ -682,12 +682,12 @@ material for the several revisions of the Ada language standard.
implementation of Ada.
@item
-@cite{Using the GNAT Programming Studio}, which describes the GPS
+@cite{Using GNAT Studio}, which describes the GNAT Studio
Integrated Development Environment.
@item
-@cite{GNAT Programming Studio Tutorial}, which introduces the
-main GPS features through examples.
+@cite{GNAT Studio Tutorial}, which introduces the
+main GNAT Studio features through examples.
@item
@cite{Debugging with GDB},
@@ -897,11 +897,11 @@ the '\' character should be used instead.
This chapter describes how to use GNAT's command line interface to build
executable Ada programs.
On most platforms a visually oriented Integrated Development Environment
-is also available, the GNAT Programming Studio (GPS).
-GPS offers a graphical "look and feel", support for development in
+is also available, the GNAT Programming Studio (GNAT Studio).
+GNAT Studio offers a graphical "look and feel", support for development in
other programming languages, comprehensive browsing features, and
many other capabilities.
-For information on GPS please refer to
+For information on GNAT Studio please refer to
@cite{Using the GNAT Programming Studio}.
@menu
@@ -10446,7 +10446,7 @@ e.adb:4:20: ";" should be "is"
The first integer after the file name is the line number in the file,
and the second integer is the column number within the line.
-@code{GPS} can parse the error messages
+@code{GNAT Studio} can parse the error messages
and point to the referenced character.
The following switches provide control over the error message
format:
@@ -14110,7 +14110,7 @@ if any.
@c end of switch description (leave this comment to ease automatic parsing for
-@c GPS
+@c GNAT Studio
In the above rules, appearing in column one is always permitted, that is,
counts as meeting either a requirement for a required preceding space,
@@ -19394,9 +19394,9 @@ variables, and more generally to report on the state of execution.
This section describes how to initiate the debugger.
-The debugger can be launched from a @code{GPS} menu or
+The debugger can be launched from a @code{GNAT Studio} menu or
directly from the command line. The description below covers the latter use.
-All the commands shown can be used in the @code{GPS} debug console window,
+All the commands shown can be used in the @code{GNAT Studio} debug console window,
but there are usually more GUI-based ways to achieve the same effect.
The command to run @code{GDB} is
diff --git a/gcc/ada/gnatls.adb b/gcc/ada/gnatls.adb
index 4c4a0196c9d..b5782aa40c2 100644
--- a/gcc/ada/gnatls.adb
+++ b/gcc/ada/gnatls.adb
@@ -53,8 +53,9 @@ with GNAT.OS_Lib; use GNAT.OS_Lib;
procedure Gnatls is
pragma Ident (Gnat_Static_Version_String);
- -- NOTE : The following string may be used by other tools, such as GPS. So
- -- it can only be modified if these other uses are checked and coordinated.
+ -- NOTE : The following string may be used by other tools, such as
+ -- GNAT Studio. So it can only be modified if these other uses are checked
+ -- and coordinated.
Project_Search_Path : constant String := "Project Search Path:";
-- Label displayed in verbose mode before the directories in the project
diff --git a/gcc/ada/impunit.adb b/gcc/ada/impunit.adb
index 7e67569d5db..7048ab46e99 100644
--- a/gcc/ada/impunit.adb
+++ b/gcc/ada/impunit.adb
@@ -32,8 +32,8 @@ with Namet; use Namet;
with Opt; use Opt;
with Uname; use Uname;
--- Note: this package body is used by GPS and GNATBench to supply a list of
--- entries for help on available library routines.
+-- Note: this package body is used by GNAT Studio and GNATBench to supply a
+-- list of entries for help on available library routines.
package body Impunit is
diff --git a/gcc/ada/inline.adb b/gcc/ada/inline.adb
index dab2275b766..0d80ab220ba 100644
--- a/gcc/ada/inline.adb
+++ b/gcc/ada/inline.adb
@@ -1493,6 +1493,12 @@ package body Inline is
(Spec_Id : Entity_Id;
Body_Id : Entity_Id) return Boolean
is
+ function Has_Formal_Or_Result_Of_Deep_Type
+ (Id : Entity_Id) return Boolean;
+ -- Returns true if the subprogram has at least one formal parameter or
+ -- a return type of a deep type: either an access type or a composite
+ -- type containing an access type.
+
function Has_Formal_With_Discriminant_Dependent_Fields
(Id : Entity_Id) return Boolean;
-- Returns true if the subprogram has at least one formal parameter of
@@ -1518,6 +1524,118 @@ package body Inline is
-- knowledge of the SPARK boundary is needed to determine exactly
-- traversal functions.
+ ---------------------------------------
+ -- Has_Formal_Or_Result_Of_Deep_Type --
+ ---------------------------------------
+
+ function Has_Formal_Or_Result_Of_Deep_Type
+ (Id : Entity_Id) return Boolean
+ is
+ function Is_Deep (Typ : Entity_Id) return Boolean;
+ -- Return True if Typ is deep: either an access type or a composite
+ -- type containing an access type.
+
+ -------------
+ -- Is_Deep --
+ -------------
+
+ function Is_Deep (Typ : Entity_Id) return Boolean is
+ begin
+ case Type_Kind'(Ekind (Typ)) is
+ when Access_Kind =>
+ return True;
+
+ when E_Array_Type
+ | E_Array_Subtype
+ =>
+ return Is_Deep (Component_Type (Typ));
+
+ when Record_Kind =>
+ declare
+ Comp : Entity_Id := First_Component_Or_Discriminant (Typ);
+ begin
+ while Present (Comp) loop
+ if Is_Deep (Etype (Comp)) then
+ return True;
+ end if;
+ Next_Component_Or_Discriminant (Comp);
+ end loop;
+ end;
+ return False;
+
+ when Scalar_Kind
+ | E_String_Literal_Subtype
+ | Concurrent_Kind
+ | Incomplete_Kind
+ | E_Exception_Type
+ | E_Subprogram_Type
+ =>
+ return False;
+
+ when E_Private_Type
+ | E_Private_Subtype
+ | E_Limited_Private_Type
+ | E_Limited_Private_Subtype
+ =>
+ -- Conservatively consider that the type might be deep if
+ -- its completion has not been seen yet.
+
+ if No (Underlying_Type (Typ)) then
+ return True;
+
+ -- Do not peek under a private type if its completion has
+ -- SPARK_Mode Off. In such a case, a deep type is considered
+ -- by GNATprove to be not deep.
+
+ elsif Present (Full_View (Typ))
+ and then Present (SPARK_Pragma (Full_View (Typ)))
+ and then Get_SPARK_Mode_From_Annotation
+ (SPARK_Pragma (Full_View (Typ))) = Off
+ then
+ return False;
+
+ -- Otherwise peek under the private type.
+
+ else
+ return Is_Deep (Underlying_Type (Typ));
+ end if;
+ end case;
+ end Is_Deep;
+
+ -- Local variables
+
+ Subp_Id : constant Entity_Id := Ultimate_Alias (Id);
+ Formal : Entity_Id;
+ Formal_Typ : Entity_Id;
+
+ -- Start of processing for Has_Formal_Or_Result_Of_Deep_Type
+
+ begin
+ -- Inspect all parameters of the subprogram looking for a formal
+ -- of a deep type.
+
+ Formal := First_Formal (Subp_Id);
+ while Present (Formal) loop
+ Formal_Typ := Etype (Formal);
+
+ if Is_Deep (Formal_Typ) then
+ return True;
+ end if;
+
+ Next_Formal (Formal);
+ end loop;
+
+ -- Check whether this is a function whose return type is deep
+
+ if Ekind (Subp_Id) = E_Function
+ and then Is_Deep (Etype (Subp_Id))
+ then
+ return True;
+ end if;
+
+ return False;
+ end Has_Formal_Or_Result_Of_Deep_Type;
+
---------------------------------------------------
-- Has_Formal_With_Discriminant_Dependent_Fields --
---------------------------------------------------
@@ -1777,6 +1895,14 @@ package body Inline is
elsif Has_Formal_With_Discriminant_Dependent_Fields (Id) then
return False;
+ -- Do not inline subprograms with a formal parameter or return type of
+ -- a deep type, as in that case inlining might generate code that
+ -- violates borrow-checking rules of SPARK 3.10 even if the original
+ -- code did not.
+
+ elsif Has_Formal_Or_Result_Of_Deep_Type (Id) then
+ return False;
+
-- Do not inline subprograms which may be traversal functions. Such
-- inlining introduces temporary variables of named access type for
-- which assignments are move instead of borrow/observe, possibly
diff --git a/gcc/ada/lib-writ.ads b/gcc/ada/lib-writ.ads
index 7248a61e86f..5045b91f0fc 100644
--- a/gcc/ada/lib-writ.ads
+++ b/gcc/ada/lib-writ.ads
@@ -56,7 +56,8 @@ package Lib.Writ is
-- incompatible with new versions of the compiler. Any changes to ali file
-- formats must be carefully evaluated to understand any such possible
-- conflicts, and in particular, it is very undesirable to create conflicts
- -- between older versions of GPS and newer versions of the compiler.
+ -- between older versions of GNAT Studio and newer versions of the
+ -- compiler.
-- If the following guidelines are respected, downward compatibility
-- problems (old tools reading new ali files) should be minimized:
diff --git a/gcc/ada/libgnat/a-cbdlli.adb b/gcc/ada/libgnat/a-cbdlli.adb
index 4dea2e64d2f..9a2282b2d85 100644
--- a/gcc/ada/libgnat/a-cbdlli.adb
+++ b/gcc/ada/libgnat/a-cbdlli.adb
@@ -304,7 +304,7 @@ package body Ada.Containers.Bounded_Doubly_Linked_Lists is
(Element => N.Element'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Constant_Reference;
@@ -1448,7 +1448,7 @@ package body Ada.Containers.Bounded_Doubly_Linked_Lists is
TC : constant Tamper_Counts_Access := Container.TC'Unrestricted_Access;
begin
return R : constant Reference_Control_Type := (Controlled with TC) do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end Pseudo_Reference;
@@ -1564,7 +1564,7 @@ package body Ada.Containers.Bounded_Doubly_Linked_Lists is
(Element => N.Element'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Reference;
diff --git a/gcc/ada/libgnat/a-cbhama.adb b/gcc/ada/libgnat/a-cbhama.adb
index 74e3d95748a..d5cc8206222 100644
--- a/gcc/ada/libgnat/a-cbhama.adb
+++ b/gcc/ada/libgnat/a-cbhama.adb
@@ -213,7 +213,7 @@ package body Ada.Containers.Bounded_Hashed_Maps is
(Element => N.Element'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Constant_Reference;
@@ -239,7 +239,7 @@ package body Ada.Containers.Bounded_Hashed_Maps is
(Element => N.Element'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Constant_Reference;
@@ -853,7 +853,7 @@ package body Ada.Containers.Bounded_Hashed_Maps is
Container.TC'Unrestricted_Access;
begin
return R : constant Reference_Control_Type := (Controlled with TC) do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end Pseudo_Reference;
@@ -987,7 +987,7 @@ package body Ada.Containers.Bounded_Hashed_Maps is
(Element => N.Element'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Reference;
@@ -1012,7 +1012,7 @@ package body Ada.Containers.Bounded_Hashed_Maps is
(Element => N.Element'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Reference;
diff --git a/gcc/ada/libgnat/a-cbhase.adb b/gcc/ada/libgnat/a-cbhase.adb
index 390e82bb485..1fa2c21c00d 100644
--- a/gcc/ada/libgnat/a-cbhase.adb
+++ b/gcc/ada/libgnat/a-cbhase.adb
@@ -231,7 +231,7 @@ package body Ada.Containers.Bounded_Hashed_Sets is
(Element => N.Element'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Constant_Reference;
@@ -1077,7 +1077,7 @@ package body Ada.Containers.Bounded_Hashed_Sets is
Container.TC'Unrestricted_Access;
begin
return R : constant Reference_Control_Type := (Controlled with TC) do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end Pseudo_Reference;
@@ -1606,7 +1606,7 @@ package body Ada.Containers.Bounded_Hashed_Sets is
(Element => N.Element'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Constant_Reference;
@@ -1787,7 +1787,7 @@ package body Ada.Containers.Bounded_Hashed_Sets is
Old_Pos => Position,
Old_Hash => Hash (Key (Position))))
do
- Lock (Container.TC);
+ Busy (Container.TC);
end return;
end;
end Reference_Preserving_Key;
@@ -1816,7 +1816,7 @@ package body Ada.Containers.Bounded_Hashed_Sets is
Old_Pos => P,
Old_Hash => Hash (Key)))
do
- Lock (Container.TC);
+ Busy (Container.TC);
end return;
end;
end Reference_Preserving_Key;
diff --git a/gcc/ada/libgnat/a-cbmutr.adb b/gcc/ada/libgnat/a-cbmutr.adb
index 4c0f8fe1c29..ad9edaaa142 100644
--- a/gcc/ada/libgnat/a-cbmutr.adb
+++ b/gcc/ada/libgnat/a-cbmutr.adb
@@ -600,7 +600,7 @@ package body Ada.Containers.Bounded_Multiway_Trees is
(Element => Container.Elements (Position.Node)'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Constant_Reference;
@@ -2291,7 +2291,7 @@ package body Ada.Containers.Bounded_Multiway_Trees is
TC : constant Tamper_Counts_Access := Container.TC'Unrestricted_Access;
begin
return R : constant Reference_Control_Type := (Controlled with TC) do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end Pseudo_Reference;
@@ -2490,7 +2490,7 @@ package body Ada.Containers.Bounded_Multiway_Trees is
(Element => Container.Elements (Position.Node)'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Reference;
diff --git a/gcc/ada/libgnat/a-cborma.adb b/gcc/ada/libgnat/a-cborma.adb
index e4e4b57dc72..005bca5d0c2 100644
--- a/gcc/ada/libgnat/a-cborma.adb
+++ b/gcc/ada/libgnat/a-cborma.adb
@@ -420,7 +420,7 @@ package body Ada.Containers.Bounded_Ordered_Maps is
(Element => N.Element'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Constant_Reference;
@@ -445,7 +445,7 @@ package body Ada.Containers.Bounded_Ordered_Maps is
(Element => N.Element'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Constant_Reference;
@@ -1256,7 +1256,7 @@ package body Ada.Containers.Bounded_Ordered_Maps is
Container.TC'Unrestricted_Access;
begin
return R : constant Reference_Control_Type := (Controlled with TC) do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end Pseudo_Reference;
@@ -1376,7 +1376,7 @@ package body Ada.Containers.Bounded_Ordered_Maps is
(Element => N.Element'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Reference;
@@ -1401,7 +1401,7 @@ package body Ada.Containers.Bounded_Ordered_Maps is
(Element => N.Element'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Reference;
diff --git a/gcc/ada/libgnat/a-cborse.adb b/gcc/ada/libgnat/a-cborse.adb
index 7b983781e60..b55304810b9 100644
--- a/gcc/ada/libgnat/a-cborse.adb
+++ b/gcc/ada/libgnat/a-cborse.adb
@@ -420,7 +420,7 @@ package body Ada.Containers.Bounded_Ordered_Sets is
(Element => N.Element'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Constant_Reference;
@@ -741,7 +741,7 @@ package body Ada.Containers.Bounded_Ordered_Sets is
(Element => N.Element'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Constant_Reference;
@@ -937,7 +937,7 @@ package body Ada.Containers.Bounded_Ordered_Sets is
Pos => Position,
Old_Key => new Key_Type'(Key (Position))))
do
- Lock (Container.TC);
+ Busy (Container.TC);
end return;
end;
end Reference_Preserving_Key;
@@ -965,7 +965,7 @@ package body Ada.Containers.Bounded_Ordered_Sets is
Pos => Find (Container, Key),
Old_Key => new Key_Type'(Key)))
do
- Lock (Container.TC);
+ Busy (Container.TC);
end return;
end;
end Reference_Preserving_Key;
@@ -1598,7 +1598,7 @@ package body Ada.Containers.Bounded_Ordered_Sets is
Container.TC'Unrestricted_Access;
begin
return R : constant Reference_Control_Type := (Controlled with TC) do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end Pseudo_Reference;
diff --git a/gcc/ada/libgnat/a-cdlili.adb b/gcc/ada/libgnat/a-cdlili.adb
index 9122d574d4f..949fb0f5dac 100644
--- a/gcc/ada/libgnat/a-cdlili.adb
+++ b/gcc/ada/libgnat/a-cdlili.adb
@@ -255,7 +255,7 @@ package body Ada.Containers.Doubly_Linked_Lists is
(Element => Position.Node.Element'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Constant_Reference;
@@ -1226,7 +1226,7 @@ package body Ada.Containers.Doubly_Linked_Lists is
TC : constant Tamper_Counts_Access := Container.TC'Unrestricted_Access;
begin
return R : constant Reference_Control_Type := (Controlled with TC) do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end Pseudo_Reference;
@@ -1357,7 +1357,7 @@ package body Ada.Containers.Doubly_Linked_Lists is
(Element => Position.Node.Element'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Reference;
diff --git a/gcc/ada/libgnat/a-cidlli.adb b/gcc/ada/libgnat/a-cidlli.adb
index fd480457395..65e4c10fcee 100644
--- a/gcc/ada/libgnat/a-cidlli.adb
+++ b/gcc/ada/libgnat/a-cidlli.adb
@@ -280,7 +280,7 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
(Element => Position.Node.Element,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Constant_Reference;
@@ -1263,7 +1263,7 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
TC : constant Tamper_Counts_Access := Container.TC'Unrestricted_Access;
begin
return R : constant Reference_Control_Type := (Controlled with TC) do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end Pseudo_Reference;
@@ -1405,7 +1405,7 @@ package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
(Element => Position.Node.Element,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Reference;
diff --git a/gcc/ada/libgnat/a-cihama.adb b/gcc/ada/libgnat/a-cihama.adb
index 0971a006ea9..b33246d3546 100644
--- a/gcc/ada/libgnat/a-cihama.adb
+++ b/gcc/ada/libgnat/a-cihama.adb
@@ -220,7 +220,7 @@ package body Ada.Containers.Indefinite_Hashed_Maps is
(Element => Position.Node.Element.all'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Constant_Reference;
@@ -249,7 +249,7 @@ package body Ada.Containers.Indefinite_Hashed_Maps is
(Element => Node.Element.all'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Constant_Reference;
@@ -911,7 +911,7 @@ package body Ada.Containers.Indefinite_Hashed_Maps is
Container.HT.TC'Unrestricted_Access;
begin
return R : constant Reference_Control_Type := (Controlled with TC) do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end Pseudo_Reference;
@@ -1057,7 +1057,7 @@ package body Ada.Containers.Indefinite_Hashed_Maps is
(Element => Position.Node.Element.all'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Reference;
@@ -1086,7 +1086,7 @@ package body Ada.Containers.Indefinite_Hashed_Maps is
(Element => Node.Element.all'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Reference;
diff --git a/gcc/ada/libgnat/a-cihase.adb b/gcc/ada/libgnat/a-cihase.adb
index ce158d2ab42..bec48d06e6f 100644
--- a/gcc/ada/libgnat/a-cihase.adb
+++ b/gcc/ada/libgnat/a-cihase.adb
@@ -239,7 +239,7 @@ package body Ada.Containers.Indefinite_Hashed_Sets is
(Element => Position.Node.Element.all'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Constant_Reference;
@@ -1229,7 +1229,7 @@ package body Ada.Containers.Indefinite_Hashed_Sets is
Container.HT.TC'Unrestricted_Access;
begin
return R : constant Reference_Control_Type := (Controlled with TC) do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end Pseudo_Reference;
@@ -2044,7 +2044,7 @@ package body Ada.Containers.Indefinite_Hashed_Sets is
(Element => Node.Element.all'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Constant_Reference;
@@ -2232,7 +2232,7 @@ package body Ada.Containers.Indefinite_Hashed_Sets is
Old_Pos => Position,
Old_Hash => Hash (Key (Position))))
do
- Lock (HT.TC);
+ Busy (HT.TC);
end return;
end;
end Reference_Preserving_Key;
@@ -2266,7 +2266,7 @@ package body Ada.Containers.Indefinite_Hashed_Sets is
Old_Pos => P,
Old_Hash => Hash (Key)))
do
- Lock (HT.TC);
+ Busy (HT.TC);
end return;
end;
end Reference_Preserving_Key;
diff --git a/gcc/ada/libgnat/a-cimutr.adb b/gcc/ada/libgnat/a-cimutr.adb
index 18bfff07308..c5cf2212096 100644
--- a/gcc/ada/libgnat/a-cimutr.adb
+++ b/gcc/ada/libgnat/a-cimutr.adb
@@ -488,7 +488,7 @@ package body Ada.Containers.Indefinite_Multiway_Trees is
(Element => Position.Node.Element.all'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Constant_Reference;
@@ -1847,7 +1847,7 @@ package body Ada.Containers.Indefinite_Multiway_Trees is
TC : constant Tamper_Counts_Access := Container.TC'Unrestricted_Access;
begin
return R : constant Reference_Control_Type := (Controlled with TC) do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end Pseudo_Reference;
@@ -2044,7 +2044,7 @@ package body Ada.Containers.Indefinite_Multiway_Trees is
(Element => Position.Node.Element.all'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Reference;
diff --git a/gcc/ada/libgnat/a-ciorma.adb b/gcc/ada/libgnat/a-ciorma.adb
index 5cc35908e8f..818a2ae0f60 100644
--- a/gcc/ada/libgnat/a-ciorma.adb
+++ b/gcc/ada/libgnat/a-ciorma.adb
@@ -374,7 +374,7 @@ package body Ada.Containers.Indefinite_Ordered_Maps is
(Element => Position.Node.Element.all'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Constant_Reference;
@@ -402,7 +402,7 @@ package body Ada.Containers.Indefinite_Ordered_Maps is
(Element => Node.Element.all'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Constant_Reference;
@@ -1250,7 +1250,7 @@ package body Ada.Containers.Indefinite_Ordered_Maps is
Container.Tree.TC'Unrestricted_Access;
begin
return R : constant Reference_Control_Type := (Controlled with TC) do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end Pseudo_Reference;
@@ -1387,7 +1387,7 @@ package body Ada.Containers.Indefinite_Ordered_Maps is
(Element => Position.Node.Element.all'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Reference;
@@ -1415,7 +1415,7 @@ package body Ada.Containers.Indefinite_Ordered_Maps is
(Element => Node.Element.all'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Reference;
diff --git a/gcc/ada/libgnat/a-ciorse.adb b/gcc/ada/libgnat/a-ciorse.adb
index d979e88db2e..7cc7dca87cd 100644
--- a/gcc/ada/libgnat/a-ciorse.adb
+++ b/gcc/ada/libgnat/a-ciorse.adb
@@ -394,7 +394,7 @@ package body Ada.Containers.Indefinite_Ordered_Sets is
(Element => Position.Node.Element.all'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Constant_Reference;
@@ -788,7 +788,7 @@ package body Ada.Containers.Indefinite_Ordered_Sets is
(Element => Node.Element.all'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Constant_Reference;
@@ -1017,7 +1017,7 @@ package body Ada.Containers.Indefinite_Ordered_Sets is
Pos => Position,
Old_Key => new Key_Type'(Key (Position))))
do
- Lock (Tree.TC);
+ Busy (Tree.TC);
end return;
end;
end Reference_Preserving_Key;
@@ -1049,7 +1049,7 @@ package body Ada.Containers.Indefinite_Ordered_Sets is
Pos => Find (Container, Key),
Old_Key => new Key_Type'(Key)))
do
- Lock (Tree.TC);
+ Busy (Tree.TC);
end return;
end;
end Reference_Preserving_Key;
@@ -1688,7 +1688,7 @@ package body Ada.Containers.Indefinite_Ordered_Sets is
Container.Tree.TC'Unrestricted_Access;
begin
return R : constant Reference_Control_Type := (Controlled with TC) do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end Pseudo_Reference;
diff --git a/gcc/ada/libgnat/a-cobove.adb b/gcc/ada/libgnat/a-cobove.adb
index 3e48bc60e8a..75087949af8 100644
--- a/gcc/ada/libgnat/a-cobove.adb
+++ b/gcc/ada/libgnat/a-cobove.adb
@@ -402,7 +402,7 @@ package body Ada.Containers.Bounded_Vectors is
(Element => A (J)'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Constant_Reference;
@@ -426,7 +426,7 @@ package body Ada.Containers.Bounded_Vectors is
(Element => A (J)'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Constant_Reference;
@@ -2067,7 +2067,7 @@ package body Ada.Containers.Bounded_Vectors is
TC : constant Tamper_Counts_Access := Container.TC'Unrestricted_Access;
begin
return R : constant Reference_Control_Type := (Controlled with TC) do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end Pseudo_Reference;
@@ -2183,7 +2183,7 @@ package body Ada.Containers.Bounded_Vectors is
(Element => A (J)'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Reference;
@@ -2207,7 +2207,7 @@ package body Ada.Containers.Bounded_Vectors is
(Element => A (J)'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Reference;
diff --git a/gcc/ada/libgnat/a-cohama.adb b/gcc/ada/libgnat/a-cohama.adb
index 0eb6e7ea315..e7da0204af8 100644
--- a/gcc/ada/libgnat/a-cohama.adb
+++ b/gcc/ada/libgnat/a-cohama.adb
@@ -213,7 +213,7 @@ package body Ada.Containers.Hashed_Maps is
(Element => Position.Node.Element'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Constant_Reference;
@@ -238,7 +238,7 @@ package body Ada.Containers.Hashed_Maps is
(Element => Node.Element'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Constant_Reference;
@@ -836,7 +836,7 @@ package body Ada.Containers.Hashed_Maps is
Container.HT.TC'Unrestricted_Access;
begin
return R : constant Reference_Control_Type := (Controlled with TC) do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end Pseudo_Reference;
@@ -937,7 +937,7 @@ package body Ada.Containers.Hashed_Maps is
(Element => Position.Node.Element'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Reference;
@@ -962,7 +962,7 @@ package body Ada.Containers.Hashed_Maps is
(Element => Node.Element'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Reference;
diff --git a/gcc/ada/libgnat/a-cohase.adb b/gcc/ada/libgnat/a-cohase.adb
index 37e55b80229..61ebf87d2f1 100644
--- a/gcc/ada/libgnat/a-cohase.adb
+++ b/gcc/ada/libgnat/a-cohase.adb
@@ -223,7 +223,7 @@ package body Ada.Containers.Hashed_Sets is
(Element => Position.Node.Element'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Constant_Reference;
@@ -1119,7 +1119,7 @@ package body Ada.Containers.Hashed_Sets is
Container.HT.TC'Unrestricted_Access;
begin
return R : constant Reference_Control_Type := (Controlled with TC) do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end Pseudo_Reference;
@@ -1839,7 +1839,7 @@ package body Ada.Containers.Hashed_Sets is
(Element => Node.Element'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Constant_Reference;
@@ -2025,7 +2025,7 @@ package body Ada.Containers.Hashed_Sets is
Old_Pos => Position,
Old_Hash => Hash (Key (Position))))
do
- Lock (HT.TC);
+ Busy (HT.TC);
end return;
end;
end Reference_Preserving_Key;
@@ -2055,7 +2055,7 @@ package body Ada.Containers.Hashed_Sets is
Old_Pos => P,
Old_Hash => Hash (Key)))
do
- Lock (HT.TC);
+ Busy (HT.TC);
end return;
end;
end Reference_Preserving_Key;
diff --git a/gcc/ada/libgnat/a-coinve.adb b/gcc/ada/libgnat/a-coinve.adb
index 22608c17c65..0dfe1c63e89 100644
--- a/gcc/ada/libgnat/a-coinve.adb
+++ b/gcc/ada/libgnat/a-coinve.adb
@@ -324,7 +324,7 @@ package body Ada.Containers.Indefinite_Vectors is
(Element => Container.Elements.EA (Position.Index),
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Constant_Reference;
@@ -348,7 +348,7 @@ package body Ada.Containers.Indefinite_Vectors is
(Element => Container.Elements.EA (Index),
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Constant_Reference;
@@ -2586,7 +2586,7 @@ package body Ada.Containers.Indefinite_Vectors is
TC : constant Tamper_Counts_Access := Container.TC'Unrestricted_Access;
begin
return R : constant Reference_Control_Type := (Controlled with TC) do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end Pseudo_Reference;
@@ -2718,7 +2718,7 @@ package body Ada.Containers.Indefinite_Vectors is
(Element => Container.Elements.EA (Position.Index),
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Reference;
@@ -2742,7 +2742,7 @@ package body Ada.Containers.Indefinite_Vectors is
(Element => Container.Elements.EA (Index),
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Reference;
diff --git a/gcc/ada/libgnat/a-comutr.adb b/gcc/ada/libgnat/a-comutr.adb
index 59ed12b8f56..9e6a00e8e3b 100644
--- a/gcc/ada/libgnat/a-comutr.adb
+++ b/gcc/ada/libgnat/a-comutr.adb
@@ -469,7 +469,7 @@ package body Ada.Containers.Multiway_Trees is
(Element => Position.Node.Element'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Constant_Reference;
@@ -1830,7 +1830,7 @@ package body Ada.Containers.Multiway_Trees is
TC : constant Tamper_Counts_Access := Container.TC'Unrestricted_Access;
begin
return R : constant Reference_Control_Type := (Controlled with TC) do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end Pseudo_Reference;
@@ -2023,7 +2023,7 @@ package body Ada.Containers.Multiway_Trees is
(Element => Position.Node.Element'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Reference;
diff --git a/gcc/ada/libgnat/a-conhel.adb b/gcc/ada/libgnat/a-conhel.adb
index 29085300f39..06af0dabf7e 100644
--- a/gcc/ada/libgnat/a-conhel.adb
+++ b/gcc/ada/libgnat/a-conhel.adb
@@ -38,7 +38,7 @@ package body Ada.Containers.Helpers is
procedure Adjust (Control : in out Reference_Control_Type) is
begin
if Control.T_Counts /= null then
- Lock (Control.T_Counts.all);
+ Busy (Control.T_Counts.all);
end if;
end Adjust;
@@ -60,7 +60,7 @@ package body Ada.Containers.Helpers is
procedure Finalize (Control : in out Reference_Control_Type) is
begin
if Control.T_Counts /= null then
- Unlock (Control.T_Counts.all);
+ Unbusy (Control.T_Counts.all);
Control.T_Counts := null;
end if;
end Finalize;
diff --git a/gcc/ada/libgnat/a-convec.adb b/gcc/ada/libgnat/a-convec.adb
index e15ab5d06a8..f5e2eb42287 100644
--- a/gcc/ada/libgnat/a-convec.adb
+++ b/gcc/ada/libgnat/a-convec.adb
@@ -294,7 +294,7 @@ package body Ada.Containers.Vectors is
(Element => Container.Elements.EA (Position.Index)'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Constant_Reference;
@@ -316,7 +316,7 @@ package body Ada.Containers.Vectors is
(Element => Container.Elements.EA (Index)'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Constant_Reference;
@@ -2293,7 +2293,7 @@ package body Ada.Containers.Vectors is
TC : constant Tamper_Counts_Access := Container.TC'Unrestricted_Access;
begin
return R : constant Reference_Control_Type := (Controlled with TC) do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end Pseudo_Reference;
@@ -2409,7 +2409,7 @@ package body Ada.Containers.Vectors is
(Element => Container.Elements.EA (Position.Index)'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Reference;
@@ -2431,7 +2431,7 @@ package body Ada.Containers.Vectors is
(Element => Container.Elements.EA (Index)'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Reference;
diff --git a/gcc/ada/libgnat/a-coorma.adb b/gcc/ada/libgnat/a-coorma.adb
index 8275802ccd9..e49ae902476 100644
--- a/gcc/ada/libgnat/a-coorma.adb
+++ b/gcc/ada/libgnat/a-coorma.adb
@@ -336,7 +336,7 @@ package body Ada.Containers.Ordered_Maps is
(Element => Position.Node.Element'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Constant_Reference;
@@ -361,7 +361,7 @@ package body Ada.Containers.Ordered_Maps is
(Element => Node.Element'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Constant_Reference;
@@ -1180,7 +1180,7 @@ package body Ada.Containers.Ordered_Maps is
Container.Tree.TC'Unrestricted_Access;
begin
return R : constant Reference_Control_Type := (Controlled with TC) do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end Pseudo_Reference;
@@ -1307,7 +1307,7 @@ package body Ada.Containers.Ordered_Maps is
(Element => Position.Node.Element'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Reference;
@@ -1332,7 +1332,7 @@ package body Ada.Containers.Ordered_Maps is
(Element => Node.Element'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Reference;
diff --git a/gcc/ada/libgnat/a-coorse.adb b/gcc/ada/libgnat/a-coorse.adb
index 462f7f30e6a..d2f8a58f910 100644
--- a/gcc/ada/libgnat/a-coorse.adb
+++ b/gcc/ada/libgnat/a-coorse.adb
@@ -349,7 +349,7 @@ package body Ada.Containers.Ordered_Sets is
(Element => Position.Node.Element'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Constant_Reference;
@@ -706,7 +706,7 @@ package body Ada.Containers.Ordered_Sets is
(Element => Node.Element'Access,
Control => (Controlled with TC))
do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end;
end Constant_Reference;
@@ -903,7 +903,7 @@ package body Ada.Containers.Ordered_Sets is
Pos => Position,
Old_Key => new Key_Type'(Key (Position))))
do
- Lock (Tree.TC);
+ Busy (Tree.TC);
end return;
end;
end Reference_Preserving_Key;
@@ -931,7 +931,7 @@ package body Ada.Containers.Ordered_Sets is
Pos => Find (Container, Key),
Old_Key => new Key_Type'(Key)))
do
- Lock (Tree.TC);
+ Busy (Tree.TC);
end return;
end;
end Reference_Preserving_Key;
@@ -1550,7 +1550,7 @@ package body Ada.Containers.Ordered_Sets is
Container.Tree.TC'Unrestricted_Access;
begin
return R : constant Reference_Control_Type := (Controlled with TC) do
- Lock (TC.all);
+ Busy (TC.all);
end return;
end Pseudo_Reference;
diff --git a/gcc/ada/libgnat/a-ststio.ads b/gcc/ada/libgnat/a-ststio.ads
index 5314ce85305..30be1586bd0 100644
--- a/gcc/ada/libgnat/a-ststio.ads
+++ b/gcc/ada/libgnat/a-ststio.ads
@@ -42,6 +42,7 @@ package Ada.Streams.Stream_IO is
type Stream_Access is access all Root_Stream_Type'Class;
type File_Type is limited private with Default_Initial_Condition;
+ pragma Preelaborable_Initialization (File_Type);
type File_Mode is (In_File, Out_File, Append_File);
diff --git a/gcc/ada/libgnat/g-exptty.ads b/gcc/ada/libgnat/g-exptty.ads
index 81068a69ed7..f61ea6215b4 100644
--- a/gcc/ada/libgnat/g-exptty.ads
+++ b/gcc/ada/libgnat/g-exptty.ads
@@ -139,7 +139,7 @@ private
Still_Active : constant Integer := -1;
type TTY_Process_Descriptor is new Process_Descriptor with record
- Process : System.Address;
+ Process : System.Address := System.Null_Address;
-- Underlying structure used in C
Exit_Status : Integer := Still_Active;
-- Hold the exit status of the process.
diff --git a/gcc/ada/opt.ads b/gcc/ada/opt.ads
index a07db751c11..1f068dcf4fc 100644
--- a/gcc/ada/opt.ads
+++ b/gcc/ada/opt.ads
@@ -501,7 +501,8 @@ package Opt is
Display_Compilation_Progress : Boolean := False;
-- GNATMAKE, GPRBUILD
-- Set True (-d switch) to display information on progress while compiling
- -- files. Internal flag to be used in conjunction with an IDE (e.g GPS).
+ -- files. Internal flag to be used in conjunction with an IDE
+ -- (e.g GNAT Studio).
type Distribution_Stub_Mode_Type is
-- GNAT
diff --git a/gcc/ada/rtsfind.adb b/gcc/ada/rtsfind.adb
index dc77590a9e8..65cc8bc3853 100644
--- a/gcc/ada/rtsfind.adb
+++ b/gcc/ada/rtsfind.adb
@@ -949,22 +949,16 @@ package body Rtsfind is
Install_Ghost_Region (None, Empty);
Install_SPARK_Mode (None, Empty);
- -- Note if secondary stack is used
-
- if U_Id = System_Secondary_Stack then
- Opt.Sec_Stack_Used := True;
- end if;
-
- -- Otherwise we need to load the unit, First build unit name
- -- from the enumeration literal name in type RTU_Id.
+ -- Otherwise we need to load the unit, First build unit name from the
+ -- enumeration literal name in type RTU_Id.
U.Uname := Get_Unit_Name (U_Id);
U.First_Implicit_With := Empty;
- -- Now do the load call, note that setting Error_Node to Empty is
- -- a signal to Load_Unit that we will regard a failure to find the
- -- file as a fatal error, and that it should not output any kind
- -- of diagnostics, since we will take care of it here.
+ -- Now do the load call, note that setting Error_Node to Empty is a
+ -- signal to Load_Unit that we will regard a failure to find the file as
+ -- a fatal error, and that it should not output any kind of diagnostics,
+ -- since we will take care of it here.
-- We save style checking switches and turn off style checking for
-- loading the unit, since we don't want any style checking.
@@ -1245,21 +1239,6 @@ package body Rtsfind is
---------
function RTE (E : RE_Id) return Entity_Id is
- U_Id : constant RTU_Id := RE_Unit_Table (E);
- U : RT_Unit_Table_Record renames RT_Unit_Table (U_Id);
-
- Lib_Unit : Node_Id;
- Pkg_Ent : Entity_Id;
- Ename : Name_Id;
-
- -- The following flag is used to disable front-end inlining when RTE
- -- is invoked. This prevents the analysis of other runtime bodies when
- -- a particular spec is loaded through Rtsfind. This is both efficient,
- -- and it prevents spurious visibility conflicts between use-visible
- -- user entities, and entities in run-time packages.
-
- Save_Front_End_Inlining : Boolean;
-
procedure Check_RPC;
-- Reject programs that make use of distribution features not supported
-- on the current target. Also check that the PCS is compatible with the
@@ -1351,6 +1330,22 @@ package body Rtsfind is
return Ent;
end Find_Local_Entity;
+ -- Local variables
+
+ U_Id : constant RTU_Id := RE_Unit_Table (E);
+ U : RT_Unit_Table_Record renames RT_Unit_Table (U_Id);
+
+ Ename : Name_Id;
+ Lib_Unit : Node_Id;
+ Pkg_Ent : Entity_Id;
+
+ Save_Front_End_Inlining : constant Boolean := Front_End_Inlining;
+ -- This flag is used to disable front-end inlining when RTE is invoked.
+ -- This prevents the analysis of other runtime bodies when a particular
+ -- spec is loaded through Rtsfind. This is both efficient, and prevents
+ -- spurious visibility conflicts between use-visible user entities, and
+ -- entities in run-time packages.
+
-- Start of processing for RTE
begin
@@ -1372,7 +1367,6 @@ package body Rtsfind is
return Check_CRT (E, Find_Local_Entity (E));
end if;
- Save_Front_End_Inlining := Front_End_Inlining;
Front_End_Inlining := False;
-- Load unit if unit not previously loaded
@@ -1435,9 +1429,19 @@ package body Rtsfind is
end if;
<<Found>>
- Maybe_Add_With (U);
+ -- Record whether the secondary stack is in use in order to generate
+ -- the proper binder code. No action is taken when the secondary stack
+ -- is pulled within an ignored Ghost context because all this code will
+ -- disappear.
+
+ if U_Id = System_Secondary_Stack and then Ghost_Mode /= Ignore then
+ Sec_Stack_Used := True;
+ end if;
+
+ Maybe_Add_With (U);
Front_End_Inlining := Save_Front_End_Inlining;
+
return Check_CRT (E, RE_Table (E));
end RTE;
diff --git a/gcc/ada/sem_aggr.adb b/gcc/ada/sem_aggr.adb
index 87fe050bb4c..d6d7c5967ae 100644
--- a/gcc/ada/sem_aggr.adb
+++ b/gcc/ada/sem_aggr.adb
@@ -614,10 +614,17 @@ package body Sem_Aggr is
if Has_Predicates (Typ) then
Set_Has_Predicates (Itype);
+ -- If the base type has a predicate, capture the predicated parent
+ -- or the existing predicate function for SPARK use.
+
if Present (Predicate_Function (Typ)) then
Set_Predicate_Function (Itype, Predicate_Function (Typ));
- else
+
+ elsif Is_Itype (Typ) then
Set_Predicated_Parent (Itype, Predicated_Parent (Typ));
+
+ else
+ Set_Predicated_Parent (Itype, Typ);
end if;
end if;
@@ -886,7 +893,6 @@ package body Sem_Aggr is
procedure Resolve_Aggregate (N : Node_Id; Typ : Entity_Id) is
Loc : constant Source_Ptr := Sloc (N);
- Pkind : constant Node_Kind := Nkind (Parent (N));
Aggr_Subtyp : Entity_Id;
-- The actual aggregate subtype. This is not necessarily the same as Typ
@@ -1071,16 +1077,17 @@ package body Sem_Aggr is
-- permit it, or the aggregate type is unconstrained, an OTHERS
-- choice is not allowed (except that it is always allowed on the
-- right-hand side of an assignment statement; in this case the
- -- constrainedness of the type doesn't matter).
+ -- constrainedness of the type doesn't matter, because an array
+ -- object is always constrained).
-- If expansion is disabled (generic context, or semantics-only
-- mode) actual subtypes cannot be constructed, and the type of an
-- object may be its unconstrained nominal type. However, if the
- -- context is an assignment, we assume that OTHERS is allowed,
- -- because the target of the assignment will have a constrained
- -- subtype when fully compiled. Ditto if the context is an
- -- initialization procedure where a component may have a predicate
- -- function that carries the base type.
+ -- context is an assignment statement, OTHERS is allowed, because
+ -- the target of the assignment will have a constrained subtype
+ -- when fully compiled. Ditto if the context is an initialization
+ -- procedure where a component may have a predicate function that
+ -- carries the base type.
-- Note that there is no node for Explicit_Actual_Parameter.
-- To test for this context we therefore have to test for node
@@ -1094,24 +1101,26 @@ package body Sem_Aggr is
Set_Etype (N, Aggr_Typ); -- May be overridden later on
- if Pkind = N_Assignment_Statement
+ if Nkind (Parent (N)) = N_Assignment_Statement
or else Inside_Init_Proc
or else (Is_Constrained (Typ)
- and then
- (Pkind = N_Parameter_Association or else
- Pkind = N_Function_Call or else
- Pkind = N_Procedure_Call_Statement or else
- Pkind = N_Generic_Association or else
- Pkind = N_Formal_Object_Declaration or else
- Pkind = N_Simple_Return_Statement or else
- Pkind = N_Object_Declaration or else
- Pkind = N_Component_Declaration or else
- Pkind = N_Parameter_Specification or else
- Pkind = N_Qualified_Expression or else
- Pkind = N_Reference or else
- Pkind = N_Aggregate or else
- Pkind = N_Extension_Aggregate or else
- Pkind = N_Component_Association))
+ and then Nkind_In (Parent (N),
+ N_Parameter_Association,
+ N_Function_Call,
+ N_Procedure_Call_Statement,
+ N_Generic_Association,
+ N_Formal_Object_Declaration,
+ N_Simple_Return_Statement,
+ N_Object_Declaration,
+ N_Component_Declaration,
+ N_Parameter_Specification,
+ N_Qualified_Expression,
+ N_Reference,
+ N_Aggregate,
+ N_Extension_Aggregate,
+ N_Component_Association,
+ N_Case_Expression_Alternative,
+ N_If_Expression))
then
Aggr_Resolved :=
Resolve_Array_Aggregate
diff --git a/gcc/ada/sem_cat.adb b/gcc/ada/sem_cat.adb
index 663dca4ea85..833df88b146 100644
--- a/gcc/ada/sem_cat.adb
+++ b/gcc/ada/sem_cat.adb
@@ -721,9 +721,15 @@ package body Sem_Cat is
-- The purpose is to set categorization flags before analyzing the
-- unit itself, so as to diagnose violations of categorization as
-- we process each declaration, even though the pragma appears after
- -- the unit.
-
- if Nkind (P) /= N_Compilation_Unit then
+ -- the unit. This processing is only needed if compilation unit pragmas
+ -- are present.
+ -- Note: This code may be incorrect in the unlikely case a child generic
+ -- unit is instantiated as a child of its (nongeneric) parent, so that
+ -- generic and instance are siblings.
+
+ if Nkind (P) /= N_Compilation_Unit
+ or else No (First (Pragmas_After (Aux_Decls_Node (P))))
+ then
return;
end if;
diff --git a/gcc/ada/sem_ch12.adb b/gcc/ada/sem_ch12.adb
index 4e74f9a6e9f..8c3559f98df 100644
--- a/gcc/ada/sem_ch12.adb
+++ b/gcc/ada/sem_ch12.adb
@@ -2925,6 +2925,41 @@ package body Sem_Ch12 is
Set_Ekind (Formal, E_Package);
Set_Etype (Formal, Standard_Void_Type);
Set_Inner_Instances (Formal, New_Elmt_List);
+
+ -- It is unclear that any aspects can apply to a formal package
+ -- declaration, given that they look like a hidden conformance
+ -- requirement on the corresponding actual. However, Abstract_State
+ -- must be treated specially because it generates declarations that
+ -- must appear before other declarations in the specification and
+ -- must be analyzed at once.
+
+ if Present (Aspect_Specifications (Gen_Decl)) then
+ if No (Aspect_Specifications (N)) then
+ Set_Aspect_Specifications (N, New_List);
+ Set_Has_Aspects (N);
+ end if;
+
+ declare
+ ASN : Node_Id := First (Aspect_Specifications (Gen_Decl));
+ New_A : Node_Id;
+
+ begin
+ while Present (ASN) loop
+ if Get_Aspect_Id (ASN) = Aspect_Abstract_State then
+ New_A :=
+ Copy_Generic_Node (ASN, Empty, Instantiating => True);
+ Set_Entity (New_A, Formal);
+ Set_Analyzed (New_A, False);
+ Append (New_A, Aspect_Specifications (N));
+ Analyze_Aspect_Specifications (N, Formal);
+ exit;
+ end if;
+
+ Next (ASN);
+ end loop;
+ end;
+ end if;
+
Push_Scope (Formal);
-- Manually set the SPARK_Mode from the context because the package
@@ -3023,6 +3058,9 @@ package body Sem_Ch12 is
<<Leave>>
if Has_Aspects (N) then
+ -- Unclear that any other aspects may appear here, snalyze them
+ -- for completion, given that the grammar allows their appearance.
+
Analyze_Aspect_Specifications (N, Pack_Id);
end if;
diff --git a/gcc/ada/sem_ch13.adb b/gcc/ada/sem_ch13.adb
index 354d068117a..67ec0df6c7a 100644
--- a/gcc/ada/sem_ch13.adb
+++ b/gcc/ada/sem_ch13.adb
@@ -360,11 +360,11 @@ package body Sem_Ch13 is
Num_CC : Natural;
begin
- -- Processing here used to depend on Ada version: the behavior was
- -- changed by AI95-0133. However this AI is a Binding interpretation,
- -- so we now implement it even in Ada 95 mode. The original behavior
- -- from unamended Ada 95 is still available for compatibility under
- -- debugging switch -gnatd.
+ -- The processing done here used to depend on the Ada version, but the
+ -- behavior has been changed by AI95-0133. However this AI is a Binding
+ -- Interpretation, so we now implement it even in Ada 95 mode. But the
+ -- original behavior from unamended Ada 95 is available for the sake of
+ -- compatibility under the debugging switch -gnatd.p in Ada 95 mode.
if Ada_Version < Ada_2005 and then Debug_Flag_Dot_P then
Adjust_Record_For_Reverse_Bit_Order_Ada_95 (R);
@@ -376,6 +376,11 @@ package body Sem_Ch13 is
-- same byte offset and processing them together. Same approach is still
-- valid in later versions including Ada 2012.
+ -- Note that component clauses found on record types may be inherited,
+ -- in which case the layout of the component with such a clause still
+ -- has to be done at this point. Therefore, the processing done here
+ -- must exclusively rely on the Component_Clause of the component.
+
-- This first loop through components does two things. First it deals
-- with the case of components with component clauses whose length is
-- greater than the maximum machine scalar size (either accepting them
@@ -616,13 +621,19 @@ package body Sem_Ch13 is
Comp : constant Entity_Id := Comps (C);
CC : constant Node_Id := Component_Clause (Comp);
+ FB : constant Uint := Static_Integer (First_Bit (CC));
LB : constant Uint := Static_Integer (Last_Bit (CC));
- NFB : constant Uint := MSS - Uint_1 - LB;
- NLB : constant Uint := NFB + Esize (Comp) - 1;
+ NFB : constant Uint := MSS - 1 - LB;
+ NLB : constant Uint := NFB + LB - FB;
Pos : constant Uint := Static_Integer (Position (CC));
begin
- if Warn_On_Reverse_Bit_Order then
+ -- Do not warn for the artificial clause built for the tag
+ -- in Check_Record_Representation_Clause if it is inherited.
+
+ if Warn_On_Reverse_Bit_Order
+ and then Chars (Comp) /= Name_uTag
+ then
Error_Msg_Uint_1 := MSS;
Error_Msg_N
("info: reverse bit order in machine scalar of "
@@ -642,8 +653,9 @@ package body Sem_Ch13 is
end if;
Set_Component_Bit_Offset (Comp, Pos * SSU + NFB);
- Set_Normalized_Position (Comp, Pos + NFB / SSU);
+ Set_Esize (Comp, 1 + (NLB - NFB));
Set_Normalized_First_Bit (Comp, NFB mod SSU);
+ Set_Normalized_Position (Comp, Pos + NFB / SSU);
end;
end loop;
end loop;
@@ -6937,7 +6949,6 @@ package body Sem_Ch13 is
CC : Node_Id;
Comp : Entity_Id;
Fbit : Uint;
- Hbit : Uint := Uint_0;
Lbit : Uint;
Ocomp : Entity_Id;
Posit : Uint;
@@ -7263,6 +7274,9 @@ package body Sem_Ch13 is
Set_Normalized_First_Bit (Comp, Fbit mod SSU);
Set_Normalized_Position (Comp, Fbit / SSU);
+ Set_Normalized_Position_Max
+ (Comp, Normalized_Position (Comp));
+
if Warn_On_Overridden_Size
and then Has_Size_Clause (Etype (Comp))
and then RM_Size (Etype (Comp)) /= Esize (Comp)
@@ -7272,16 +7286,6 @@ package body Sem_Ch13 is
Component_Name (CC), Etype (Comp));
end if;
- -- This information is also set in the corresponding
- -- component of the base type, found by accessing the
- -- Original_Record_Component link if it is present.
-
- Ocomp := Original_Record_Component (Comp);
-
- if Hbit < Lbit then
- Hbit := Lbit;
- end if;
-
Check_Size
(Component_Name (CC),
Etype (Comp),
@@ -7291,12 +7295,18 @@ package body Sem_Ch13 is
Set_Biased
(Comp, First_Node (CC), "component clause", Biased);
- if Present (Ocomp) then
+ -- This information is also set in the corresponding
+ -- component of the base type, found by accessing the
+ -- Original_Record_Component link if it is present.
+
+ Ocomp := Original_Record_Component (Comp);
+
+ if Present (Ocomp) and then Ocomp /= Comp then
Set_Component_Clause (Ocomp, CC);
Set_Component_Bit_Offset (Ocomp, Fbit);
+ Set_Esize (Ocomp, 1 + (Lbit - Fbit));
Set_Normalized_First_Bit (Ocomp, Fbit mod SSU);
Set_Normalized_Position (Ocomp, Fbit / SSU);
- Set_Esize (Ocomp, 1 + (Lbit - Fbit));
Set_Normalized_Position_Max
(Ocomp, Normalized_Position (Ocomp));
@@ -10616,7 +10626,7 @@ package body Sem_Ch13 is
First_Bit => Make_Integer_Literal (Loc, Uint_0),
Last_Bit =>
Make_Integer_Literal (Loc,
- UI_From_Int (System_Address_Size))));
+ UI_From_Int (System_Address_Size - 1))));
Ccount := Ccount + 1;
end if;
diff --git a/gcc/ada/sem_ch3.adb b/gcc/ada/sem_ch3.adb
index e304e72dcfa..b12f69b994c 100644
--- a/gcc/ada/sem_ch3.adb
+++ b/gcc/ada/sem_ch3.adb
@@ -3522,6 +3522,8 @@ package body Sem_Ch3 is
Set_Etype (Id, Universal_Integer);
Set_Ekind (Id, E_Named_Integer);
Set_Is_Frozen (Id, True);
+
+ Set_Debug_Info_Needed (Id);
return;
end if;
@@ -13454,8 +13456,8 @@ package body Sem_Ch3 is
-- After expansion of discriminated task types, the value
-- of the discriminant may be converted to a run-time type
-- for restricted run-times. Propagate the value of the
- -- discriminant ss well, so that e.g. the secondary stack
- -- component has a static constraint. Necessry for LLVM.
+ -- discriminant as well, so that e.g. the secondary stack
+ -- component has a static constraint. Necessary for LLVM.
elsif Nkind (Expr) = N_Type_Conversion
and then Is_Discriminant (Expression (Expr))
diff --git a/gcc/ada/sem_ch6.adb b/gcc/ada/sem_ch6.adb
index eb6768d3ae2..5af3b7b7e19 100644
--- a/gcc/ada/sem_ch6.adb
+++ b/gcc/ada/sem_ch6.adb
@@ -4262,11 +4262,11 @@ package body Sem_Ch6 is
-- object can then be used instead of the formal in case it is used
-- in an actual to a call to a nested subprogram.
- -- This method is used to suppliment our "small integer model" for
- -- accessibility check generation (for more information see
+ -- This method is used to supplement our "small integer model" for
+ -- accessibility-check generation (for more information see
-- Dynamic_Accessibility_Level).
- -- Because we allow accesibility values greater than our expected value
+ -- Because we allow accessibility values greater than our expected value
-- passing along the same extra accessibility formal as an actual
-- to a nested subprogram becomes a problem because high values mean
-- different things to the callee even though they are the same to the
@@ -12038,7 +12038,7 @@ package body Sem_Ch6 is
-- predicate may come from an explicit aspect of be inherited.
elsif Has_Predicates (T) then
- Insert_List_Before_And_Analyze (Decl,
+ Insert_List_After_And_Analyze (Decl,
Freeze_Entity (Defining_Identifier (Decl), N));
end if;
diff --git a/gcc/ada/sem_ch7.adb b/gcc/ada/sem_ch7.adb
index db6bffd9674..313cb4eaaa3 100644
--- a/gcc/ada/sem_ch7.adb
+++ b/gcc/ada/sem_ch7.adb
@@ -1271,7 +1271,7 @@ package body Sem_Ch7 is
procedure Generate_Parent_References;
-- For a child unit, generate references to parent units, for
- -- GPS navigation purposes.
+ -- GNAT Studio navigation purposes.
function Is_Public_Child (Child, Unit : Entity_Id) return Boolean;
-- Child and Unit are entities of compilation units. True if Child
diff --git a/gcc/ada/sem_ch8.adb b/gcc/ada/sem_ch8.adb
index 5d03f835c8b..38cbf1cd26b 100644
--- a/gcc/ada/sem_ch8.adb
+++ b/gcc/ada/sem_ch8.adb
@@ -4290,16 +4290,14 @@ package body Sem_Ch8 is
-- Common case for compilation unit
- elsif Defining_Entity (N => Parent (N),
- Empty_On_Errors => True) = Current_Scope
- then
+ elsif Defining_Entity (Parent (N)) = Current_Scope then
null;
else
-- If declaration appears in some other scope, it must be in some
-- parent unit when compiling a child.
- Pack := Defining_Entity (Parent (N), Empty_On_Errors => True);
+ Pack := Defining_Entity (Parent (N));
if not In_Open_Scopes (Pack) then
null;
diff --git a/gcc/ada/sem_elab.adb b/gcc/ada/sem_elab.adb
index 2dbf54da555..0c71f5910d5 100644
--- a/gcc/ada/sem_elab.adb
+++ b/gcc/ada/sem_elab.adb
@@ -9103,13 +9103,23 @@ package body Sem_Elab is
N_Procedure_Instantiation)
and then Nkind (Context) = N_Compilation_Unit
then
- return
- Related_Instance (Defining_Entity (N, Concurrent_Subunit => True));
+ return Related_Instance (Defining_Entity (N));
+
+ -- The unit denotes a concurrent body acting as a subunit. Such bodies
+ -- are generally rewritten into null statements. The proper entity is
+ -- that of the "original node".
+
+ elsif Nkind (N) = N_Subunit
+ and then Nkind (Proper_Body (N)) = N_Null_Statement
+ and then Nkind_In (Original_Node (Proper_Body (N)), N_Protected_Body,
+ N_Task_Body)
+ then
+ return Defining_Entity (Original_Node (Proper_Body (N)));
-- Otherwise the proper entity is the defining entity
else
- return Defining_Entity (N, Concurrent_Subunit => True);
+ return Defining_Entity (N);
end if;
end Find_Unit_Entity;
diff --git a/gcc/ada/sem_prag.adb b/gcc/ada/sem_prag.adb
index 5f7e6e5d842..7b36f8e3923 100644
--- a/gcc/ada/sem_prag.adb
+++ b/gcc/ada/sem_prag.adb
@@ -2429,8 +2429,7 @@ package body Sem_Prag is
-- Constant related checks
elsif Ekind (Item_Id) = E_Constant
- and then
- not Is_Access_Type (Underlying_Type (Etype (Item_Id)))
+ and then not Is_Access_Type (Etype (Item_Id))
then
-- Unless it is of an access type, a constant is a read-only
@@ -8195,15 +8194,16 @@ package body Sem_Prag is
Set_Convention_From_Pragma (E);
-- Treat a pragma Import as an implicit body, and pragma import
- -- as implicit reference (for navigation in GPS).
+ -- as implicit reference (for navigation in GNAT Studio).
if Prag_Id = Pragma_Import then
Generate_Reference (E, Id, 'b');
-- For exported entities we restrict the generation of references
-- to entities exported to foreign languages since entities
- -- exported to Ada do not provide further information to GPS and
- -- add undesired references to the output of the gnatxref tool.
+ -- exported to Ada do not provide further information to
+ -- GNAT Studio and add undesired references to the output of the
+ -- gnatxref tool.
elsif Prag_Id = Pragma_Export
and then Convention (E) /= Convention_Ada
@@ -13093,7 +13093,7 @@ package body Sem_Prag is
-- Infer the type to use for a string literal or a concatentation
-- of operands whose types can be inferred. For such expressions,
-- returns the "narrowest" of the three predefined string types
- -- that can represent the characters occuring in the expression.
+ -- that can represent the characters occurring in the expression.
-- For other expressions, returns Empty.
function Preferred_String_Type (Expr : Node_Id) return Entity_Id is
@@ -18816,6 +18816,15 @@ package body Sem_Prag is
Set_Has_Own_Invariants (Typ);
+ -- Set the Invariants_Ignored flag if that policy is in effect
+
+ Set_Invariants_Ignored (Typ,
+ Present (Check_Policy_List)
+ and then
+ (Policy_In_Effect (Name_Invariant) = Name_Ignore
+ and then
+ Policy_In_Effect (Name_Type_Invariant) = Name_Ignore));
+
-- If the invariant is class-wide, then it can be inherited by
-- derived or interface implementing types. The type is said to
-- have "inheritable" invariants.
@@ -32188,6 +32197,15 @@ package body Sem_Prag is
(New_Val => CTWE_Entry'(Eloc => Sloc (Arg1),
Scope => Current_Scope,
Prag => N));
+
+ -- If the Boolean expression contains T'Size, and we're not in the main
+ -- unit being compiled, then we need to copy the pragma into the main
+ -- unit, because otherwise T'Size might never be computed, leaving it
+ -- as 0.
+
+ if not In_Extended_Main_Code_Unit (N) then
+ Insert_Library_Level_Action (New_Copy_Tree (N));
+ end if;
end Defer_Compile_Time_Warning_Error_To_BE;
------------------------------------------
diff --git a/gcc/ada/sem_res.adb b/gcc/ada/sem_res.adb
index 28d1352afb3..4a50b0982ea 100644
--- a/gcc/ada/sem_res.adb
+++ b/gcc/ada/sem_res.adb
@@ -6845,7 +6845,7 @@ package body Sem_Res is
end if;
-- If this is a dispatching call, generate the appropriate reference,
- -- for better source navigation in GPS.
+ -- for better source navigation in GNAT Studio.
if Is_Overloadable (Nam)
and then Present (Controlling_Argument (N))
diff --git a/gcc/ada/sem_util.adb b/gcc/ada/sem_util.adb
index 95699199e3f..4de41d3e6dd 100644
--- a/gcc/ada/sem_util.adb
+++ b/gcc/ada/sem_util.adb
@@ -5867,11 +5867,7 @@ package body Sem_Util is
-- Defining_Entity --
---------------------
- function Defining_Entity
- (N : Node_Id;
- Empty_On_Errors : Boolean := False;
- Concurrent_Subunit : Boolean := False) return Entity_Id
- is
+ function Defining_Entity (N : Node_Id) return Entity_Id is
begin
case Nkind (N) is
when N_Abstract_Subprogram_Declaration
@@ -5922,24 +5918,11 @@ package body Sem_Util is
=>
return Defining_Identifier (N);
- when N_Subunit =>
- declare
- Bod : constant Node_Id := Proper_Body (N);
- Orig_Bod : constant Node_Id := Original_Node (Bod);
-
- begin
- -- Retrieve the entity of the original protected or task body
- -- if requested by the caller.
+ when N_Compilation_Unit =>
+ return Defining_Entity (Unit (N));
- if Concurrent_Subunit
- and then Nkind (Bod) = N_Null_Statement
- and then Nkind_In (Orig_Bod, N_Protected_Body, N_Task_Body)
- then
- return Defining_Entity (Orig_Bod);
- else
- return Defining_Entity (Bod);
- end if;
- end;
+ when N_Subunit =>
+ return Defining_Entity (Proper_Body (N));
when N_Function_Instantiation
| N_Function_Specification
@@ -5965,14 +5948,10 @@ package body Sem_Util is
-- can continue semantic analysis.
elsif Nam = Error then
- if Empty_On_Errors then
- return Empty;
- else
- Err := Make_Temporary (Sloc (N), 'T');
- Set_Defining_Unit_Name (N, Err);
+ Err := Make_Temporary (Sloc (N), 'T');
+ Set_Defining_Unit_Name (N, Err);
- return Err;
- end if;
+ return Err;
-- If not an entity, get defining identifier
@@ -5987,11 +5966,7 @@ package body Sem_Util is
return Entity (Identifier (N));
when others =>
- if Empty_On_Errors then
- return Empty;
- else
- raise Program_Error;
- end if;
+ raise Program_Error;
end case;
end Defining_Entity;
@@ -6997,17 +6972,17 @@ package body Sem_Util is
elsif Ekind_In (Dyn_Scop, E_Block, E_Loop, E_Return_Statement) then
return Enclosing_Subprogram (Dyn_Scop);
- elsif Ekind (Dyn_Scop) = E_Entry then
+ elsif Ekind_In (Dyn_Scop, E_Entry, E_Entry_Family) then
- -- For a task entry, return the enclosing subprogram of the
- -- task itself.
+ -- For a task entry or entry family, return the enclosing subprogram
+ -- of the task itself.
if Ekind (Scope (Dyn_Scop)) = E_Task_Type then
return Enclosing_Subprogram (Dyn_Scop);
- -- A protected entry is rewritten as a protected procedure which is
- -- the desired enclosing subprogram. This is relevant when unnesting
- -- a procedure local to an entry body.
+ -- A protected entry or entry family is rewritten as a protected
+ -- procedure which is the desired enclosing subprogram. This is
+ -- relevant when unnesting a procedure local to an entry body.
else
return Protected_Body_Subprogram (Dyn_Scop);
@@ -9071,8 +9046,8 @@ package body Sem_Util is
-- components are being gathered for an aggregate, in which case
-- the caller must check Report_Errors.
--
- -- In Ada2020 the above rules are relaxed. A non-static governing
- -- discriminant is ok as long as it has a static subtype and
+ -- In Ada 2020 the above rules are relaxed. A nonstatic governing
+ -- discriminant is OK as long as it has a static subtype and
-- every value of that subtype (and there must be at least one)
-- selects the same variant.
diff --git a/gcc/ada/sem_util.ads b/gcc/ada/sem_util.ads
index b41b8750fd2..dc5e57b0bf6 100644
--- a/gcc/ada/sem_util.ads
+++ b/gcc/ada/sem_util.ads
@@ -554,10 +554,7 @@ package Sem_Util is
-- in the case of a descendant of a generic formal type (returns Int'Last
-- instead of 0).
- function Defining_Entity
- (N : Node_Id;
- Empty_On_Errors : Boolean := False;
- Concurrent_Subunit : Boolean := False) return Entity_Id;
+ function Defining_Entity (N : Node_Id) return Entity_Id;
-- Given a declaration N, returns the associated defining entity. If the
-- declaration has a specification, the entity is obtained from the
-- specification. If the declaration has a defining unit name, then the
@@ -568,22 +565,6 @@ package Sem_Util is
-- local entities declared during loop expansion. These entities need
-- debugging information, generated through Qualify_Entity_Names, and
-- the loop declaration must be placed in the table Name_Qualify_Units.
- --
- -- Set flag Empty_On_Error to change the behavior of this routine as
- -- follows:
- --
- -- * True - A declaration that lacks a defining entity returns Empty.
- -- A node that does not allow for a defining entity returns Empty.
- --
- -- * False - A declaration that lacks a defining entity is given a new
- -- internally generated entity which is subsequently returned. A node
- -- that does not allow for a defining entity raises Program_Error.
- --
- -- The former semantics is appropriate for the back end; the latter
- -- semantics is appropriate for the front end.
- --
- -- Set flag Concurrent_Subunit to handle rewritings of concurrent bodies
- -- which act as subunits. Such bodies are generally rewritten as null.
function Denotes_Discriminant
(N : Node_Id;
@@ -2991,7 +2972,7 @@ package Sem_Util is
function Choice_List_Intervals (Discrete_Choices : List_Id)
return Discrete_Interval_List;
-- Given a discrete choice list, returns the (unique) interval
- -- list representing the chosen values..
+ -- list representing the chosen values.
function Is_Subset (Subset, Of_Set : Discrete_Interval_List)
return Boolean;
diff --git a/gcc/ada/sem_warn.adb b/gcc/ada/sem_warn.adb
index 8f85057dc0d..04e7acfb65e 100644
--- a/gcc/ada/sem_warn.adb
+++ b/gcc/ada/sem_warn.adb
@@ -821,10 +821,10 @@ package body Sem_Warn is
function Generic_Body_Formal (E : Entity_Id) return Entity_Id;
-- Warnings on unused formals of subprograms are placed on the entity
-- in the subprogram body, which seems preferable because it suggests
- -- a better codefix for GPS. The analysis of generic subprogram bodies
- -- uses a different circuitry, so the choice for the proper placement
- -- of the warning in the generic case takes place here, by finding the
- -- body entity that corresponds to a formal in a spec.
+ -- a better codefix for GNAT Studio. The analysis of generic subprogram
+ -- bodies uses a different circuitry, so the choice for the proper
+ -- placement of the warning in the generic case takes place here, by
+ -- finding the body entity that corresponds to a formal in a spec.
procedure May_Need_Initialized_Actual (Ent : Entity_Id);
-- If an entity of a generic type has default initialization, then the
@@ -4546,9 +4546,15 @@ package body Sem_Warn is
-- to capture the value. We are not going to capture any value, but
-- the warning message depends on the same kind of conditions.
+ -- If the assignment appears as an out-parameter in a call within an
+ -- expression function it may be detected twice: once when expression
+ -- itself is analyzed, and once when the constructed body is analyzed.
+ -- We don't want to emit a spurious warning in this case.
+
if Is_Assignable (Ent)
and then not Is_Return_Object (Ent)
and then Present (Last_Assignment (Ent))
+ and then Last_Assignment (Ent) /= N
and then not Is_Imported (Ent)
and then not Is_Exported (Ent)
and then Safe_To_Capture_Value (N, Ent)
diff --git a/gcc/ada/sinfo.adb b/gcc/ada/sinfo.adb
index d24938c2ed7..2689ebe2810 100644
--- a/gcc/ada/sinfo.adb
+++ b/gcc/ada/sinfo.adb
@@ -7295,6 +7295,44 @@ package body Sinfo is
T = V11;
end Nkind_In;
+ function Nkind_In
+ (T : Node_Kind;
+ V1 : Node_Kind;
+ V2 : Node_Kind;
+ V3 : Node_Kind;
+ V4 : Node_Kind;
+ V5 : Node_Kind;
+ V6 : Node_Kind;
+ V7 : Node_Kind;
+ V8 : Node_Kind;
+ V9 : Node_Kind;
+ V10 : Node_Kind;
+ V11 : Node_Kind;
+ V12 : Node_Kind;
+ V13 : Node_Kind;
+ V14 : Node_Kind;
+ V15 : Node_Kind;
+ V16 : Node_Kind) return Boolean
+ is
+ begin
+ return T = V1 or else
+ T = V2 or else
+ T = V3 or else
+ T = V4 or else
+ T = V5 or else
+ T = V6 or else
+ T = V7 or else
+ T = V8 or else
+ T = V9 or else
+ T = V10 or else
+ T = V11 or else
+ T = V12 or else
+ T = V13 or else
+ T = V14 or else
+ T = V15 or else
+ T = V16;
+ end Nkind_In;
+
--------------------------
-- Pragma_Name_Unmapped --
--------------------------
diff --git a/gcc/ada/sinfo.ads b/gcc/ada/sinfo.ads
index dc8280076d2..5a920669b62 100644
--- a/gcc/ada/sinfo.ads
+++ b/gcc/ada/sinfo.ads
@@ -11574,6 +11574,27 @@ package Sinfo is
V10 : Node_Kind;
V11 : Node_Kind) return Boolean;
+ -- 12..15-parameter versions are not yet needed
+
+ function Nkind_In
+ (T : Node_Kind;
+ V1 : Node_Kind;
+ V2 : Node_Kind;
+ V3 : Node_Kind;
+ V4 : Node_Kind;
+ V5 : Node_Kind;
+ V6 : Node_Kind;
+ V7 : Node_Kind;
+ V8 : Node_Kind;
+ V9 : Node_Kind;
+ V10 : Node_Kind;
+ V11 : Node_Kind;
+ V12 : Node_Kind;
+ V13 : Node_Kind;
+ V14 : Node_Kind;
+ V15 : Node_Kind;
+ V16 : Node_Kind) return Boolean;
+
pragma Inline (Nkind_In);
-- Inline all above functions
diff --git a/gcc/ada/terminals.c b/gcc/ada/terminals.c
index 0ce3fb788f9..af4417fab90 100644
--- a/gcc/ada/terminals.c
+++ b/gcc/ada/terminals.c
@@ -170,7 +170,7 @@ struct TTY_Process {
BOOL usePipe;
};
-/* Control whether create_child cause the process to inherit GPS'
+/* Control whether create_child cause the process to inherit GNAT Studio'
error mode setting. The default is 1, to minimize the possibility of
subprocesses blocking when accessing unmounted drives. */
static int Vw32_start_process_inherit_error_mode = 1;
diff --git a/gcc/ada/treepr.adb b/gcc/ada/treepr.adb
index 959b990254a..55ecbdbb07c 100644
--- a/gcc/ada/treepr.adb
+++ b/gcc/ada/treepr.adb
@@ -242,6 +242,14 @@ package body Treepr is
function par (N : Union_Id) return Node_Or_Entity_Id renames p;
+ procedure ppar (N : Union_Id) is
+ begin
+ if N /= Empty_List_Or_Node then
+ pp (N);
+ ppar (Union_Id (p (N)));
+ end if;
+ end ppar;
+
--------
-- pe --
--------
diff --git a/gcc/ada/treepr.ads b/gcc/ada/treepr.ads
index a2992509d06..a63329b581d 100644
--- a/gcc/ada/treepr.ads
+++ b/gcc/ada/treepr.ads
@@ -82,6 +82,10 @@ package Treepr is
-- the definition of Union_Id. Historically this was only for printing
-- nodes, hence the name.
+ procedure ppar (N : Union_Id);
+ pragma Export (Ada, ppar);
+ -- Print the node, its parent, its parent's parent, and so on
+
procedure pt (N : Union_Id);
procedure ppp (N : Union_Id);
pragma Export (Ada, pt);
diff --git a/gcc/builtins.c b/gcc/builtins.c
index a1dc83c0b24..5d811f113c9 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -3334,7 +3334,7 @@ check_access (tree exp, tree, tree, tree dstwrite,
c_strlen_data lendata = { };
get_range_strlen (srcstr, &lendata, /* eltsize = */ 1);
range[0] = lendata.minlen;
- range[1] = lendata.maxbound;
+ range[1] = lendata.maxbound ? lendata.maxbound : lendata.maxlen;
if (range[0] && (!maxread || TREE_CODE (maxread) == INTEGER_CST))
{
if (maxread && tree_int_cst_le (maxread, range[0]))
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index 7deaff065cf..cb3b9cfa98e 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,73 @@
+2019-10-14 Richard Sandiford <richard.sandiford@arm.com>
+
+ * c-common.h (user_facing_original_type_p): Declare.
+ * c-common.c: Include c-spellcheck.h.
+ (user_facing_original_type_p): New function.
+
+2019-10-12 Jakub Jelinek <jakub@redhat.com>
+
+ * c-common.h (c_omp_mark_declare_variant,
+ c_omp_context_selector_matches): Declare.
+ * c-omp.c: Include attribs.h, gimplify.h, cgraph.h, symbol-summary.h
+ and hsa-common.h.
+ (c_omp_get_context_selector): Support second argument NULL.
+ (c_omp_mark_declare_variant, c_omp_context_selector_matches): New
+ functions.
+ * c-attribs.c (c_common_attribute_table): Remove "omp declare variant"
+ attribute, add "omp declare variant base" and
+ "omp declare variant variant" attributes.
+
+2019-10-11 Joseph Myers <joseph@codesourcery.com>
+
+ * c.opt (Wc11-c2x-compat): Add CPP(cpp_warn_c11_c2x_compat)
+ CppReason(CPP_W_C11_C2X_COMPAT).
+
+2019-10-11 Joseph Myers <joseph@codesourcery.com>
+
+ * c-common.c (c_common_reswords): Do not use D_EXT for _Decimal32,
+ _Decimal64 and _Decimal128.
+
+2019-10-10 Joseph Myers <joseph@codesourcery.com>
+
+ * c-cppbuiltin.c (c_cpp_builtins): Do not define macros for DFP
+ types if DFP not supported.
+
+2019-10-10 Jakub Jelinek <jakub@redhat.com>
+
+ * c-common.h (c_omp_check_context_selector,
+ c_omp_get_context_selector): Declare.
+ * c-omp.c (c_omp_declare_simd_clauses_to_numbers): Fix spelling
+ in diagnostic message.
+ (c_omp_check_context_selector, c_omp_get_context_selector): New
+ functions.
+ * c-attribs.c (c_common_attribute_table): Add "omp declare variant"
+ attribute.
+ (handle_omp_declare_variant_attribute): New function.
+
+2019-10-09 Martin Sebor <msebor@redhat.com>
+
+ PR tree-optimization/90879
+ * c.opt (-Wstring-compare): New option.
+
+2019-10-08 Andrew Sutton <asutton@lock3software.com>
+ Jason Merrill <jason@redhat.com>
+
+ Update the concepts implementation to conform to the C++20
+ specification, improve compile times, and generally clean up
+ the implementation.
+
+ * c-cppbuiltin.c (c_cpp_builtins): Use new feature test values for
+ concepts when -std=c++2a. Bump __cpp_concepts to 201907.
+ * c.opt: Add -Wconcepts-ts.
+ * c-opts.c (c_common_post_options): Warn when -fconcepts is used
+ with -std=c++2a. Disable warning for -fconcepts in C++20 mode.
+ (set_std_cxx2a): Enable concepts by default.
+
+2019-10-08 Joseph Myers <joseph@codesourcery.com>
+
+ * c-opts.c (c_common_post_options): Set
+ -fno-fp-int-builtin-inexact for C2X.
+
2019-10-05 Jakub Jelinek <jakub@redhat.com>
PR c++/91369 - Implement P0784R7: constexpr new
diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index 6500b998321..ea273f89a8e 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -140,6 +140,8 @@ static tree handle_warn_unused_attribute (tree *, tree, tree, int, bool *);
static tree handle_returns_nonnull_attribute (tree *, tree, tree, int, bool *);
static tree handle_omp_declare_simd_attribute (tree *, tree, tree, int,
bool *);
+static tree handle_omp_declare_variant_attribute (tree *, tree, tree, int,
+ bool *);
static tree handle_simd_attribute (tree *, tree, tree, int, bool *);
static tree handle_omp_declare_target_attribute (tree *, tree, tree, int,
bool *);
@@ -442,6 +444,10 @@ const struct attribute_spec c_common_attribute_table[] =
handle_returns_nonnull_attribute, NULL },
{ "omp declare simd", 0, -1, true, false, false, false,
handle_omp_declare_simd_attribute, NULL },
+ { "omp declare variant base", 0, -1, true, false, false, false,
+ handle_omp_declare_variant_attribute, NULL },
+ { "omp declare variant variant", 0, -1, true, false, false, false,
+ handle_omp_declare_variant_attribute, NULL },
{ "simd", 0, 1, true, false, false, false,
handle_simd_attribute, NULL },
{ "omp declare target", 0, -1, true, false, false, false,
@@ -3064,6 +3070,15 @@ handle_omp_declare_simd_attribute (tree *, tree, tree, int, bool *)
return NULL_TREE;
}
+/* Handle an "omp declare variant {base,variant}" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_omp_declare_variant_attribute (tree *, tree, tree, int, bool *)
+{
+ return NULL_TREE;
+}
+
/* Handle a "simd" attribute. */
static tree
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index a4aca439994..0c03dd001b9 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -48,6 +48,7 @@ along with GCC; see the file COPYING3. If not see
#include "gimplify.h"
#include "substring-locations.h"
#include "spellcheck.h"
+#include "c-spellcheck.h"
#include "selftest.h"
cpp_reader *parse_in; /* Declared in c-pragma.h. */
@@ -351,9 +352,9 @@ const struct c_common_resword c_common_reswords[] =
{ "_Float32x", RID_FLOAT32X, D_CONLY },
{ "_Float64x", RID_FLOAT64X, D_CONLY },
{ "_Float128x", RID_FLOAT128X, D_CONLY },
- { "_Decimal32", RID_DFLOAT32, D_CONLY | D_EXT },
- { "_Decimal64", RID_DFLOAT64, D_CONLY | D_EXT },
- { "_Decimal128", RID_DFLOAT128, D_CONLY | D_EXT },
+ { "_Decimal32", RID_DFLOAT32, D_CONLY },
+ { "_Decimal64", RID_DFLOAT64, D_CONLY },
+ { "_Decimal128", RID_DFLOAT128, D_CONLY },
{ "_Fract", RID_FRACT, D_CONLY | D_EXT },
{ "_Accum", RID_ACCUM, D_CONLY | D_EXT },
{ "_Sat", RID_SAT, D_CONLY | D_EXT },
@@ -7718,6 +7719,52 @@ set_underlying_type (tree x)
}
}
+/* Return true if it is worth exposing the DECL_ORIGINAL_TYPE of TYPE to
+ the user in diagnostics, false if it would be better to use TYPE itself.
+ TYPE is known to satisfy typedef_variant_p. */
+
+bool
+user_facing_original_type_p (const_tree type)
+{
+ gcc_assert (typedef_variant_p (type));
+ tree decl = TYPE_NAME (type);
+
+ /* Look through any typedef in "user" code. */
+ if (!DECL_IN_SYSTEM_HEADER (decl) && !DECL_IS_BUILTIN (decl))
+ return true;
+
+ /* If the original type is also named and is in the user namespace,
+ assume it too is a user-facing type. */
+ tree orig_type = DECL_ORIGINAL_TYPE (decl);
+ if (tree orig_id = TYPE_IDENTIFIER (orig_type))
+ if (!name_reserved_for_implementation_p (IDENTIFIER_POINTER (orig_id)))
+ return true;
+
+ switch (TREE_CODE (orig_type))
+ {
+ /* Don't look through to an anonymous vector type, since the syntax
+ we use for them in diagnostics isn't real C or C++ syntax.
+ And if ORIG_TYPE is named but in the implementation namespace,
+ TYPE is likely to be more meaningful to the user. */
+ case VECTOR_TYPE:
+ return false;
+
+ /* Don't expose anonymous tag types that are presumably meant to be
+ known by their typedef name. Also don't expose tags that are in
+ the implementation namespace, such as:
+
+ typedef struct __foo foo; */
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case ENUMERAL_TYPE:
+ return false;
+
+ /* Look through to anything else. */
+ default:
+ return true;
+ }
+}
+
/* Record the types used by the current global variable declaration
being parsed, so that we can decide later to emit their debug info.
Those types are in types_used_by_cur_var_decl, and we are going to
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index cb6c199dab1..e28b6675b46 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1068,6 +1068,7 @@ extern tree builtin_type_for_size (int, bool);
extern void c_common_mark_addressable_vec (tree);
extern void set_underlying_type (tree);
+extern bool user_facing_original_type_p (const_tree);
extern void record_types_used_by_current_var_decl (tree);
extern vec<tree, va_gc> *make_tree_vector (void);
extern void release_tree_vector (vec<tree, va_gc> *);
@@ -1194,6 +1195,10 @@ extern tree c_omp_declare_simd_clauses_to_numbers (tree, tree);
extern void c_omp_declare_simd_clauses_to_decls (tree, tree);
extern bool c_omp_predefined_variable (tree);
extern enum omp_clause_default_kind c_omp_predetermined_sharing (tree);
+extern tree c_omp_check_context_selector (location_t, tree);
+extern tree c_omp_get_context_selector (tree, const char *, const char *);
+extern void c_omp_mark_declare_variant (location_t, tree, tree);
+extern int c_omp_context_selector_matches (tree);
/* Return next tree in the chain for chain_next walking of tree nodes. */
static inline tree
diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c
index d9b5e95b925..8202bfb5ed4 100644
--- a/gcc/c-family/c-cppbuiltin.c
+++ b/gcc/c-family/c-cppbuiltin.c
@@ -992,7 +992,13 @@ c_cpp_builtins (cpp_reader *pfile)
cpp_define (pfile, "__cpp_constexpr_dynamic_alloc=201907");
}
if (flag_concepts)
- cpp_define (pfile, "__cpp_concepts=201507");
+ {
+ if (cxx_dialect >= cxx2a)
+ /* FIXME: Update this to the value required by the IS. */
+ cpp_define (pfile, "__cpp_concepts=201907");
+ else
+ cpp_define (pfile, "__cpp_concepts=201507");
+ }
if (flag_coroutines)
cpp_define (pfile, "__cpp_coroutines=201908"); /* n4830, C++20 WD */
if (flag_tm)
@@ -1147,10 +1153,16 @@ c_cpp_builtins (cpp_reader *pfile)
csuffix, FLOATN_NX_TYPE_NODE (i));
}
- /* For decfloat.h. */
- builtin_define_decimal_float_constants ("DEC32", "DF", dfloat32_type_node);
- builtin_define_decimal_float_constants ("DEC64", "DD", dfloat64_type_node);
- builtin_define_decimal_float_constants ("DEC128", "DL", dfloat128_type_node);
+ /* For float.h. */
+ if (targetm.decimal_float_supported_p ())
+ {
+ builtin_define_decimal_float_constants ("DEC32", "DF",
+ dfloat32_type_node);
+ builtin_define_decimal_float_constants ("DEC64", "DD",
+ dfloat64_type_node);
+ builtin_define_decimal_float_constants ("DEC128", "DL",
+ dfloat128_type_node);
+ }
/* For fixed-point fibt, ibit, max, min, and epsilon. */
if (targetm.fixed_point_supported_p ())
diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c
index 0048289b691..339818817e2 100644
--- a/gcc/c-family/c-omp.c
+++ b/gcc/c-family/c-omp.c
@@ -32,6 +32,11 @@ along with GCC; see the file COPYING3. If not see
#include "omp-general.h"
#include "gomp-constants.h"
#include "memmodel.h"
+#include "attribs.h"
+#include "gimplify.h"
+#include "cgraph.h"
+#include "symbol-summary.h"
+#include "hsa-common.h"
/* Complete a #pragma oacc wait construct. LOC is the location of
@@ -2011,7 +2016,7 @@ c_omp_declare_simd_clauses_to_numbers (tree parms, tree clauses)
if (arg == NULL_TREE)
{
error_at (OMP_CLAUSE_LOCATION (c),
- "%qD is not an function argument", decl);
+ "%qD is not a function argument", decl);
continue;
}
OMP_CLAUSE_DECL (c) = build_int_cst (integer_type_node, idx);
@@ -2026,7 +2031,7 @@ c_omp_declare_simd_clauses_to_numbers (tree parms, tree clauses)
if (arg == NULL_TREE)
{
error_at (OMP_CLAUSE_LOCATION (c),
- "%qD is not an function argument", decl);
+ "%qD is not a function argument", decl);
continue;
}
OMP_CLAUSE_LINEAR_STEP (c)
@@ -2120,3 +2125,451 @@ c_omp_predetermined_sharing (tree decl)
return OMP_CLAUSE_DEFAULT_UNSPECIFIED;
}
+
+/* Diagnose errors in an OpenMP context selector, return CTX if
+ it is correct or error_mark_node otherwise. */
+
+tree
+c_omp_check_context_selector (location_t loc, tree ctx)
+{
+ /* Each trait-set-selector-name can only be specified once.
+ There are just 4 set names. */
+ for (tree t1 = ctx; t1; t1 = TREE_CHAIN (t1))
+ for (tree t2 = TREE_CHAIN (t1); t2; t2 = TREE_CHAIN (t2))
+ if (TREE_PURPOSE (t1) == TREE_PURPOSE (t2))
+ {
+ error_at (loc, "selector set %qs specified more than once",
+ IDENTIFIER_POINTER (TREE_PURPOSE (t1)));
+ return error_mark_node;
+ }
+ for (tree t = ctx; t; t = TREE_CHAIN (t))
+ {
+ /* Each trait-selector-name can only be specified once. */
+ if (list_length (TREE_VALUE (t)) < 5)
+ {
+ for (tree t1 = TREE_VALUE (t); t1; t1 = TREE_CHAIN (t1))
+ for (tree t2 = TREE_CHAIN (t1); t2; t2 = TREE_CHAIN (t2))
+ if (TREE_PURPOSE (t1) == TREE_PURPOSE (t2))
+ {
+ error_at (loc,
+ "selector %qs specified more than once in set %qs",
+ IDENTIFIER_POINTER (TREE_PURPOSE (t1)),
+ IDENTIFIER_POINTER (TREE_PURPOSE (t)));
+ return error_mark_node;
+ }
+ }
+ else
+ {
+ hash_set<tree> pset;
+ for (tree t1 = TREE_VALUE (t); t1; t1 = TREE_CHAIN (t1))
+ if (pset.add (TREE_PURPOSE (t1)))
+ {
+ error_at (loc,
+ "selector %qs specified more than once in set %qs",
+ IDENTIFIER_POINTER (TREE_PURPOSE (t1)),
+ IDENTIFIER_POINTER (TREE_PURPOSE (t)));
+ return error_mark_node;
+ }
+ }
+
+ static const char *const kind[] = {
+ "host", "nohost", "cpu", "gpu", "fpga", "any", NULL };
+ static const char *const vendor[] = {
+ "amd", "arm", "bsc", "cray", "fujitsu", "gnu", "ibm", "intel",
+ "llvm", "pgi", "ti", "unknown", NULL };
+ static const char *const extension[] = { NULL };
+ static const char *const atomic_default_mem_order[] = {
+ "seq_cst", "relaxed", "acq_rel", NULL };
+ struct known_properties { const char *set; const char *selector;
+ const char *const *props; };
+ known_properties props[] = {
+ { "device", "kind", kind },
+ { "implementation", "vendor", vendor },
+ { "implementation", "extension", extension },
+ { "implementation", "atomic_default_mem_order",
+ atomic_default_mem_order } };
+ for (tree t1 = TREE_VALUE (t); t1; t1 = TREE_CHAIN (t1))
+ for (unsigned i = 0; i < ARRAY_SIZE (props); i++)
+ if (!strcmp (IDENTIFIER_POINTER (TREE_PURPOSE (t1)),
+ props[i].selector)
+ && !strcmp (IDENTIFIER_POINTER (TREE_PURPOSE (t)),
+ props[i].set))
+ for (tree t2 = TREE_VALUE (t1); t2; t2 = TREE_CHAIN (t2))
+ for (unsigned j = 0; ; j++)
+ {
+ if (props[i].props[j] == NULL)
+ {
+ if (!strcmp (IDENTIFIER_POINTER (TREE_PURPOSE (t2)),
+ " score"))
+ break;
+ if (props[i].props == atomic_default_mem_order)
+ {
+ error_at (loc,
+ "incorrect property %qs of %qs selector",
+ IDENTIFIER_POINTER (TREE_PURPOSE (t2)),
+ "atomic_default_mem_order");
+ return error_mark_node;
+ }
+ else
+ warning_at (loc, 0,
+ "unknown property %qs of %qs selector",
+ IDENTIFIER_POINTER (TREE_PURPOSE (t2)),
+ props[i].selector);
+ break;
+ }
+ else if (!strcmp (IDENTIFIER_POINTER (TREE_PURPOSE (t2)),
+ props[i].props[j]))
+ {
+ if (props[i].props == atomic_default_mem_order
+ && t2 != TREE_VALUE (t1))
+ {
+ tree t3 = TREE_VALUE (t1);
+ if (!strcmp (IDENTIFIER_POINTER (TREE_PURPOSE (t3)),
+ " score")
+ && t2 == TREE_CHAIN (TREE_VALUE (t1)))
+ break;
+ error_at (loc,
+ "%qs selector must have a single property",
+ "atomic_default_mem_order");
+ return error_mark_node;
+ }
+ break;
+ }
+ }
+ }
+ return ctx;
+}
+
+/* From context selector CTX, return trait-selector with name SEL in
+ trait-selector-set with name SET if any, or NULL_TREE if not found.
+ If SEL is NULL, return the list of trait-selectors in SET. */
+
+tree
+c_omp_get_context_selector (tree ctx, const char *set, const char *sel)
+{
+ tree setid = get_identifier (set);
+ tree selid = sel ? get_identifier (sel) : NULL_TREE;
+ for (tree t1 = ctx; t1; t1 = TREE_CHAIN (t1))
+ if (TREE_PURPOSE (t1) == setid)
+ {
+ if (sel == NULL)
+ return TREE_VALUE (t1);
+ for (tree t2 = TREE_VALUE (t1); t2; t2 = TREE_CHAIN (t2))
+ if (TREE_PURPOSE (t2) == selid)
+ return t2;
+ }
+ return NULL_TREE;
+}
+
+/* Register VARIANT as variant of some base function marked with
+ #pragma omp declare variant. CONSTRUCT is corresponding construct
+ selector set. */
+
+void
+c_omp_mark_declare_variant (location_t loc, tree variant, tree construct)
+{
+ tree attr = lookup_attribute ("omp declare variant variant",
+ DECL_ATTRIBUTES (variant));
+ if (attr == NULL_TREE)
+ {
+ attr = tree_cons (get_identifier ("omp declare variant variant"),
+ unshare_expr (construct),
+ DECL_ATTRIBUTES (variant));
+ DECL_ATTRIBUTES (variant) = attr;
+ return;
+ }
+ tree t1 = TREE_VALUE (attr);
+ tree t2 = construct;
+ tree simd = get_identifier ("simd");
+ while (t1 && t2)
+ {
+ if (TREE_PURPOSE (t1) != TREE_PURPOSE (t2))
+ break;
+ if (TREE_PURPOSE (t1) == simd)
+ {
+ if ((TREE_VALUE (t1) == NULL_TREE)
+ != (TREE_VALUE (t2) == NULL_TREE))
+ break;
+ if (TREE_VALUE (t1))
+ {
+ struct declare_variant_simd_data {
+ bool inbranch, notinbranch;
+ tree simdlen;
+ auto_vec<tree,16> data_sharing;
+ auto_vec<tree,16> aligned;
+ declare_variant_simd_data ()
+ : inbranch(false), notinbranch(false), simdlen(NULL_TREE) {}
+ } data[2];
+ unsigned int i;
+ for (i = 0; i < 2; i++)
+ for (tree c = TREE_VALUE (i ? t2 : t1);
+ c; c = OMP_CLAUSE_CHAIN (c))
+ {
+ vec<tree> *v;
+ switch (OMP_CLAUSE_CODE (c))
+ {
+ case OMP_CLAUSE_INBRANCH:
+ data[i].inbranch = true;
+ continue;
+ case OMP_CLAUSE_NOTINBRANCH:
+ data[i].notinbranch = true;
+ continue;
+ case OMP_CLAUSE_SIMDLEN:
+ data[i].simdlen = OMP_CLAUSE_SIMDLEN_EXPR (c);
+ continue;
+ case OMP_CLAUSE_UNIFORM:
+ case OMP_CLAUSE_LINEAR:
+ v = &data[i].data_sharing;
+ break;
+ case OMP_CLAUSE_ALIGNED:
+ v = &data[i].aligned;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ unsigned HOST_WIDE_INT argno
+ = tree_to_uhwi (OMP_CLAUSE_DECL (c));
+ if (argno >= v->length ())
+ v->safe_grow_cleared (argno + 1);
+ (*v)[argno] = c;
+ }
+ if (data[0].inbranch != data[1].inbranch
+ || data[0].notinbranch != data[1].notinbranch
+ || !simple_cst_equal (data[0].simdlen,
+ data[1].simdlen)
+ || (data[0].data_sharing.length ()
+ != data[1].data_sharing.length ())
+ || (data[0].aligned.length ()
+ != data[1].aligned.length ()))
+ break;
+ tree c1, c2;
+ FOR_EACH_VEC_ELT (data[0].data_sharing, i, c1)
+ {
+ c2 = data[1].data_sharing[i];
+ if ((c1 == NULL_TREE) != (c2 == NULL_TREE))
+ break;
+ if (c1 == NULL_TREE)
+ continue;
+ if (OMP_CLAUSE_CODE (c1) != OMP_CLAUSE_CODE (c2))
+ break;
+ if (OMP_CLAUSE_CODE (c1) != OMP_CLAUSE_LINEAR)
+ continue;
+ if (OMP_CLAUSE_LINEAR_VARIABLE_STRIDE (c1)
+ != OMP_CLAUSE_LINEAR_VARIABLE_STRIDE (c2))
+ break;
+ if (OMP_CLAUSE_LINEAR_KIND (c1)
+ != OMP_CLAUSE_LINEAR_KIND (c2))
+ break;
+ if (!simple_cst_equal (OMP_CLAUSE_LINEAR_STEP (c1),
+ OMP_CLAUSE_LINEAR_STEP (c2)))
+ break;
+ }
+ if (i < data[0].data_sharing.length ())
+ break;
+ FOR_EACH_VEC_ELT (data[0].aligned, i, c1)
+ {
+ c2 = data[1].aligned[i];
+ if ((c1 == NULL_TREE) != (c2 == NULL_TREE))
+ break;
+ if (c1 == NULL_TREE)
+ continue;
+ if (!simple_cst_equal (OMP_CLAUSE_ALIGNED_ALIGNMENT (c1),
+ OMP_CLAUSE_ALIGNED_ALIGNMENT (c2)))
+ break;
+ }
+ if (i < data[0].aligned.length ())
+ break;
+ }
+ }
+ t1 = TREE_CHAIN (t1);
+ t2 = TREE_CHAIN (t2);
+ }
+ if (t1 || t2)
+ error_at (loc, "%qD used as a variant with incompatible %<constructor%> "
+ "selector sets", variant);
+}
+
+/* Return 1 if context selector matches the current OpenMP context, 0
+ if it does not and -1 if it is unknown and need to be determined later.
+ Some properties can be checked right away during parsing (this routine),
+ others need to wait until the whole TU is parsed, others need to wait until
+ IPA, others until vectorization. */
+
+int
+c_omp_context_selector_matches (tree ctx)
+{
+ int ret = 1;
+ for (tree t1 = ctx; t1; t1 = TREE_CHAIN (t1))
+ {
+ char set = IDENTIFIER_POINTER (TREE_PURPOSE (t1))[0];
+ if (set == 'c')
+ {
+ /* For now, ignore the construct set. While something can be
+ determined already during parsing, we don't know until end of TU
+ whether additional constructs aren't added through declare variant
+ unless "omp declare variant variant" attribute exists already
+ (so in most of the cases), and we'd need to maintain set of
+ surrounding OpenMP constructs, which is better handled during
+ gimplification. */
+ ret = -1;
+ continue;
+ }
+ for (tree t2 = TREE_VALUE (t1); t2; t2 = TREE_CHAIN (t2))
+ {
+ const char *sel = IDENTIFIER_POINTER (TREE_PURPOSE (t2));
+ switch (*sel)
+ {
+ case 'v':
+ if (set == 'i' && !strcmp (sel, "vendor"))
+ for (tree t3 = TREE_VALUE (t2); t3; t3 = TREE_CHAIN (t3))
+ {
+ const char *prop = IDENTIFIER_POINTER (TREE_PURPOSE (t3));
+ if (!strcmp (prop, " score") || !strcmp (prop, "gnu"))
+ continue;
+ return 0;
+ }
+ break;
+ case 'e':
+ if (set == 'i' && !strcmp (sel, "extension"))
+ /* We don't support any extensions right now. */
+ return 0;
+ break;
+ case 'a':
+ if (set == 'i' && !strcmp (sel, "atomic_default_mem_order"))
+ {
+ enum omp_memory_order omo
+ = ((enum omp_memory_order)
+ (omp_requires_mask
+ & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER));
+ if (omo == OMP_MEMORY_ORDER_UNSPECIFIED)
+ {
+ /* We don't know yet, until end of TU. */
+ ret = -1;
+ break;
+ }
+ tree t3 = TREE_VALUE (t2);
+ const char *prop = IDENTIFIER_POINTER (TREE_PURPOSE (t3));
+ if (!strcmp (prop, " score"))
+ {
+ t3 = TREE_CHAIN (t3);
+ prop = IDENTIFIER_POINTER (TREE_PURPOSE (t3));
+ }
+ if (!strcmp (prop, "relaxed")
+ && omo != OMP_MEMORY_ORDER_RELAXED)
+ return 0;
+ else if (!strcmp (prop, "seq_cst")
+ && omo != OMP_MEMORY_ORDER_SEQ_CST)
+ return 0;
+ else if (!strcmp (prop, "acq_rel")
+ && omo != OMP_MEMORY_ORDER_ACQ_REL)
+ return 0;
+ }
+ if (set == 'd' && !strcmp (sel, "arch"))
+ /* For now, need a target hook. */
+ ret = -1;
+ break;
+ case 'u':
+ if (set == 'i' && !strcmp (sel, "unified_address"))
+ {
+ if ((omp_requires_mask & OMP_REQUIRES_UNIFIED_ADDRESS) == 0)
+ ret = -1;
+ break;
+ }
+ if (set == 'i' && !strcmp (sel, "unified_shared_memory"))
+ {
+ if ((omp_requires_mask
+ & OMP_REQUIRES_UNIFIED_SHARED_MEMORY) == 0)
+ ret = -1;
+ break;
+ }
+ break;
+ case 'd':
+ if (set == 'i' && !strcmp (sel, "dynamic_allocators"))
+ {
+ if ((omp_requires_mask
+ & OMP_REQUIRES_DYNAMIC_ALLOCATORS) == 0)
+ ret = -1;
+ break;
+ }
+ break;
+ case 'r':
+ if (set == 'i' && !strcmp (sel, "reverse_offload"))
+ {
+ if ((omp_requires_mask & OMP_REQUIRES_REVERSE_OFFLOAD) == 0)
+ ret = -1;
+ break;
+ }
+ break;
+ case 'k':
+ if (set == 'd' && !strcmp (sel, "kind"))
+ for (tree t3 = TREE_VALUE (t2); t3; t3 = TREE_CHAIN (t3))
+ {
+ const char *prop = IDENTIFIER_POINTER (TREE_PURPOSE (t3));
+ if (!strcmp (prop, "any"))
+ continue;
+ if (!strcmp (prop, "fpga"))
+ return 0; /* Right now GCC doesn't support any fpgas. */
+ if (!strcmp (prop, "host"))
+ {
+ if (ENABLE_OFFLOADING || hsa_gen_requested_p ())
+ ret = -1;
+ continue;
+ }
+ if (!strcmp (prop, "nohost"))
+ {
+ if (ENABLE_OFFLOADING || hsa_gen_requested_p ())
+ ret = -1;
+ else
+ return 0;
+ continue;
+ }
+ if (!strcmp (prop, "cpu") || !strcmp (prop, "gpu"))
+ {
+ bool maybe_gpu = false;
+ if (hsa_gen_requested_p ())
+ maybe_gpu = true;
+ else if (ENABLE_OFFLOADING)
+ for (const char *c = getenv ("OFFLOAD_TARGET_NAMES");
+ c; )
+ {
+ if (!strncmp (c, "nvptx", strlen ("nvptx"))
+ || !strncmp (c, "amdgcn", strlen ("amdgcn")))
+ {
+ maybe_gpu = true;
+ break;
+ }
+ else if ((c = strchr (c, ',')))
+ c++;
+ }
+ if (!maybe_gpu)
+ {
+ if (prop[0] == 'g')
+ return 0;
+ }
+ else
+ ret = -1;
+ continue;
+ }
+ /* Any other kind doesn't match. */
+ return 0;
+ }
+ break;
+ case 'i':
+ if (set == 'd' && !strcmp (sel, "isa"))
+ /* For now, need a target hook. */
+ ret = -1;
+ break;
+ case 'c':
+ if (set == 'u' && !strcmp (sel, "condition"))
+ for (tree t3 = TREE_VALUE (t2); t3; t3 = TREE_CHAIN (t3))
+ if (TREE_PURPOSE (t3) == NULL_TREE
+ && integer_zerop (TREE_VALUE (t3)))
+ return 0;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ return ret;
+}
diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c
index 949d96a7839..0fffe60b140 100644
--- a/gcc/c-family/c-opts.c
+++ b/gcc/c-family/c-opts.c
@@ -826,6 +826,12 @@ c_common_post_options (const char **pfilename)
else
flag_permitted_flt_eval_methods = PERMITTED_FLT_EVAL_METHODS_C11;
+ /* C2X Annex F does not permit certain built-in functions to raise
+ "inexact". */
+ if (flag_isoc2x
+ && !global_options_set.x_flag_fp_int_builtin_inexact)
+ flag_fp_int_builtin_inexact = 0;
+
/* By default we use C99 inline semantics in GNU99 or C99 mode. C99
inline semantics are not supported in GNU89 or C89 mode. */
if (flag_gnu89_inline == -1)
@@ -1028,6 +1034,16 @@ c_common_post_options (const char **pfilename)
if (warn_return_type == -1 && c_dialect_cxx ())
warn_return_type = 1;
+ /* C++2a is the final version of concepts. We still use -fconcepts
+ to know when concepts are enabled. Note that -fconcepts-ts can
+ be used to include additional features, although modified to
+ work with the standard. */
+ if (cxx_dialect >= cxx2a)
+ flag_concepts = 1;
+ else if (flag_concepts)
+ /* For -std=c++17 -fconcepts, imply -fconcepts-ts. */
+ flag_concepts_ts = 1;
+
if (num_in_fnames > 1)
error ("too many filenames given; type %<%s %s%> for usage",
progname, "--help");
@@ -1707,6 +1723,7 @@ set_std_cxx2a (int iso)
flag_isoc94 = 1;
flag_isoc99 = 1;
flag_isoc11 = 1;
+ /* C++2a includes concepts. */
cxx_dialect = cxx2a;
lang_hooks.name = "GNU C++17"; /* Pretend C++17 until standardization. */
}
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index c4025ded4b3..c72a84a4965 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -367,7 +367,7 @@ C ObjC C++ ObjC++ CPP(warn_builtin_macro_redefined) CppReason(CPP_W_BUILTIN_MACR
Warn when a built-in preprocessor macro is undefined or redefined.
Wc11-c2x-compat
-C ObjC Var(warn_c11_c2x_compat) Init(-1) Warning
+C ObjC CPP(cpp_warn_c11_c2x_compat) CppReason(CPP_W_C11_C2X_COMPAT) Var(warn_c11_c2x_compat) Init(-1) Warning
Warn about features not present in ISO C11, but present in ISO C2X.
Wc90-c99-compat
@@ -795,6 +795,12 @@ Wsizeof-array-argument
C ObjC C++ ObjC++ Var(warn_sizeof_array_argument) Warning Init(1)
Warn when sizeof is applied on a parameter declared as an array.
+Wstring-compare
+C ObjC C++ LTO ObjC++ Warning Var(warn_string_compare) Warning LangEnabledBy(C ObjC C++ ObjC++, Wextra)
+Warn about calls to strcmp and strncmp used in equality expressions that
+are necessarily true or false due to the length of one and size of the other
+argument.
+
Wstringop-overflow
C ObjC C++ LTO ObjC++ Warning Alias(Wstringop-overflow=, 2, 0)
Warn about buffer overflow in string manipulation functions like memcpy
@@ -1427,6 +1433,10 @@ fconcepts
C++ ObjC++ Var(flag_concepts)
Enable support for C++ concepts.
+fconcepts-ts
+C++ ObjC++ Var(flag_concepts_ts) Init(0)
+Enable certain features present in the Concepts TS.
+
fcond-mismatch
C ObjC C++ ObjC++
Allow the arguments of the '?' operator to have different types.
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog
index 0f263f78e4b..23310ce0e43 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -1,3 +1,47 @@
+2019-10-14 Richard Sandiford <richard.sandiford@arm.com>
+
+ * c-objc-common.c (useful_aka_type_p): Replace with...
+ (get_aka_type): ...this new function. Given the original type,
+ decide which aka type to print (if any). Only look through typedefs
+ if user_facing_original_type_p.
+ (print_type): Update accordingly.
+
+2019-10-14 Jakub Jelinek <jakub@redhat.com>
+
+ * c-parser.c (c_parser_omp_all_clauses): Change bool NESTED_P argument
+ into int NESTED, if it is 2, diagnose missing commas in between
+ clauses.
+ (c_parser_omp_context_selector): Pass 2 as last argument to
+ c_parser_omp_all_clauses.
+
+2019-10-12 Jakub Jelinek <jakub@redhat.com>
+
+ * c-parser.c (c_parser_omp_context_selector): Improve error recovery.
+ For simd properties, put them directly into TREE_VALUE.
+ (c_finish_omp_declare_variant): Call c_omp_mark_declare_variant.
+ If c_omp_context_selector_matches is 0, don't add attribute, otherwise
+ add "omp declare variant base" attribute rather than
+ "omp declare variant".
+
+2019-10-11 Joseph Myers <joseph@codesourcery.com>
+
+ * c-decl.c (declspecs_add_type): Use pedwarn_c11 for DFP types.
+
+2019-10-10 Jakub Jelinek <jakub@redhat.com>
+
+ * c-parser.c (c_parser_omp_all_clauses): Add NESTED_P argument, if
+ true, terminate processing on closing paren and don't skip to end of
+ pragma line.
+ (c_parser_omp_declare_simd): Handle also declare variant.
+ (omp_construct_selectors, omp_device_selectors,
+ omp_implementation_selectors, omp_user_selectors): New variables.
+ (c_parser_omp_context_selector,
+ c_parser_omp_context_selector_specification,
+ c_finish_omp_declare_variant): New functions.
+ (c_finish_omp_declare_simd): Handle both declare simd and
+ declare variant.
+ (c_parser_omp_declare): Handle declare variant.
+
2019-10-02 Joseph Myers <joseph@codesourcery.com>
* c-parser.c (c_parser_asm_statement): Handle CPP_SCOPE like two
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index 132fa3edb27..f67033b82d2 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -10959,8 +10959,9 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs,
error_at (loc,
("decimal floating-point not supported "
"for this target"));
- pedwarn (loc, OPT_Wpedantic,
- "ISO C does not support decimal floating-point");
+ pedwarn_c11 (loc, OPT_Wpedantic,
+ "ISO C does not support decimal floating-point "
+ "before C2X");
return specs;
case RID_FRACT:
case RID_ACCUM:
diff --git a/gcc/c/c-objc-common.c b/gcc/c/c-objc-common.c
index e1f3b2ee436..10d72c57dfb 100644
--- a/gcc/c/c-objc-common.c
+++ b/gcc/c/c-objc-common.c
@@ -28,6 +28,8 @@ along with GCC; see the file COPYING3. If not see
#include "langhooks.h"
#include "c-objc-common.h"
#include "gcc-rich-location.h"
+#include "stringpool.h"
+#include "attribs.h"
static bool c_tree_printer (pretty_printer *, text_info *, const char *,
int, bool, bool, bool, bool *, const char **);
@@ -62,71 +64,120 @@ c_objc_common_init (void)
return c_common_init ();
}
-/* Return true if it's worth saying that TYPE1 is also known as TYPE2. */
+/* Decide whether it's worth saying that TYPE is also known as some other
+ type. Return the other type if so, otherwise return TYPE. */
-static bool
-useful_aka_type_p (tree type1, tree type2)
+static tree
+get_aka_type (tree type)
{
- if (type1 == type2)
- return false;
-
- if (type1 == error_mark_node || type2 == error_mark_node)
- return false;
-
- if (TREE_CODE (type1) != TREE_CODE (type2))
- return true;
+ if (type == error_mark_node)
+ return type;
- if (typedef_variant_p (type1))
+ tree result;
+ if (typedef_variant_p (type))
{
/* Saying that "foo" is also known as "struct foo" or
"struct <anonymous>" is unlikely to be useful, since users of
structure-like types would already know that they're structures.
The same applies to unions and enums; in general, printing the
tag is only useful if it has a different name. */
- tree_code code = TREE_CODE (type2);
- tree id2 = TYPE_IDENTIFIER (type2);
+ tree orig_type = DECL_ORIGINAL_TYPE (TYPE_NAME (type));
+ tree_code code = TREE_CODE (orig_type);
+ tree orig_id = TYPE_IDENTIFIER (orig_type);
if ((code == RECORD_TYPE || code == UNION_TYPE || code == ENUMERAL_TYPE)
- && (!id2 || TYPE_IDENTIFIER (type1) == id2))
- return false;
+ && (!orig_id || TYPE_IDENTIFIER (type) == orig_id))
+ return type;
- return true;
+ if (!user_facing_original_type_p (type))
+ return type;
+
+ result = get_aka_type (orig_type);
}
else
{
- switch (TREE_CODE (type1))
+ tree canonical = TYPE_CANONICAL (type);
+ if (canonical && TREE_CODE (type) != TREE_CODE (canonical))
+ return canonical;
+
+ /* Recursive calls might choose a middle ground between TYPE
+ (which has no typedefs stripped) and CANONICAL (which has
+ all typedefs stripped). So try to reuse TYPE or CANONICAL if
+ convenient, but be prepared to create a new type if necessary. */
+ switch (TREE_CODE (type))
{
case POINTER_TYPE:
case REFERENCE_TYPE:
- return useful_aka_type_p (TREE_TYPE (type1), TREE_TYPE (type2));
+ {
+ tree target_type = get_aka_type (TREE_TYPE (type));
+
+ if (target_type == TREE_TYPE (type))
+ return type;
+
+ if (canonical && target_type == TREE_TYPE (canonical))
+ return canonical;
+
+ result = (TREE_CODE (type) == POINTER_TYPE
+ ? build_pointer_type (target_type)
+ : build_reference_type (target_type));
+ break;
+ }
case ARRAY_TYPE:
- return (useful_aka_type_p (TYPE_DOMAIN (type1), TYPE_DOMAIN (type2))
- || useful_aka_type_p (TREE_TYPE (type1), TREE_TYPE (type2)));
+ {
+ tree element_type = get_aka_type (TREE_TYPE (type));
+ tree index_type = (TYPE_DOMAIN (type)
+ ? get_aka_type (TYPE_DOMAIN (type))
+ : NULL_TREE);
+
+ if (element_type == TREE_TYPE (type)
+ && index_type == TYPE_DOMAIN (type))
+ return type;
+
+ if (canonical
+ && element_type == TREE_TYPE (canonical)
+ && index_type == TYPE_DOMAIN (canonical))
+ return canonical;
+
+ result = build_array_type (element_type, index_type,
+ TYPE_TYPELESS_STORAGE (type));
+ break;
+ }
case FUNCTION_TYPE:
{
- tree args1 = TYPE_ARG_TYPES (type1);
- tree args2 = TYPE_ARG_TYPES (type2);
- while (args1 != args2)
+ tree return_type = get_aka_type (TREE_TYPE (type));
+
+ tree args = TYPE_ARG_TYPES (type);
+ if (args == error_mark_node)
+ return type;
+
+ auto_vec<tree, 32> arg_types;
+ bool type_ok_p = true;
+ while (args && args != void_list_node)
{
- /* Although this shouldn't happen, it seems to wrong to assert
- for it in a diagnostic routine. */
- if (!args1 || args1 == void_type_node)
- return true;
- if (!args2 || args2 == void_type_node)
- return true;
- if (useful_aka_type_p (TREE_VALUE (args1), TREE_VALUE (args2)))
- return true;
- args1 = TREE_CHAIN (args1);
- args2 = TREE_CHAIN (args2);
+ tree arg_type = get_aka_type (TREE_VALUE (args));
+ arg_types.safe_push (arg_type);
+ type_ok_p &= (arg_type == TREE_VALUE (args));
+ args = TREE_CHAIN (args);
}
- return useful_aka_type_p (TREE_TYPE (type1), TREE_TYPE (type2));
+
+ if (type_ok_p && return_type == TREE_TYPE (type))
+ return type;
+
+ unsigned int i;
+ tree arg_type;
+ FOR_EACH_VEC_ELT_REVERSE (arg_types, i, arg_type)
+ args = tree_cons (NULL_TREE, arg_type, args);
+ result = build_function_type (return_type, args);
+ break;
}
default:
- return true;
+ return canonical ? canonical : type;
}
}
+ return build_type_attribute_qual_variant (result, TYPE_ATTRIBUTES (type),
+ TYPE_QUALS (type));
}
/* Print T to CPP. */
@@ -150,11 +201,12 @@ print_type (c_pretty_printer *cpp, tree t, bool *quoted)
stripped version. But sometimes the stripped version looks
exactly the same, so we don't want it after all. To avoid
printing it in that case, we play ugly obstack games. */
- if (TYPE_CANONICAL (t) && useful_aka_type_p (t, TYPE_CANONICAL (t)))
+ tree aka_type = get_aka_type (t);
+ if (aka_type != t)
{
c_pretty_printer cpp2;
/* Print the stripped version into a temporary printer. */
- cpp2.type_id (TYPE_CANONICAL (t));
+ cpp2.type_id (aka_type);
struct obstack *ob2 = cpp2.buffer->obstack;
/* Get the stripped version from the temporary printer. */
const char *aka = (char *) obstack_base (ob2);
@@ -174,7 +226,7 @@ print_type (c_pretty_printer *cpp, tree t, bool *quoted)
pp_c_whitespace (cpp);
if (*quoted)
pp_begin_quote (cpp, pp_show_color (cpp));
- cpp->type_id (TYPE_CANONICAL (t));
+ cpp->type_id (aka_type);
if (*quoted)
pp_end_quote (cpp, pp_show_color (cpp));
pp_right_brace (cpp);
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 6957297b3a5..15095dd3214 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -15213,11 +15213,16 @@ c_parser_oacc_all_clauses (c_parser *parser, omp_clause_mask mask,
}
/* Parse all OpenMP clauses. The set clauses allowed by the directive
- is a bitmask in MASK. Return the list of clauses found. */
+ is a bitmask in MASK. Return the list of clauses found.
+ FINISH_P set if c_finish_omp_clauses should be called.
+ NESTED non-zero if clauses should be terminated by closing paren instead
+ of end of pragma. If it is 2, additionally commas are required in between
+ the clauses. */
static tree
c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask,
- const char *where, bool finish_p = true)
+ const char *where, bool finish_p = true,
+ int nested = 0)
{
tree clauses = NULL;
bool first = true;
@@ -15229,8 +15234,18 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask,
const char *c_name;
tree prev = clauses;
- if (!first && c_parser_next_token_is (parser, CPP_COMMA))
- c_parser_consume_token (parser);
+ if (nested && c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ break;
+
+ if (!first)
+ {
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ c_parser_consume_token (parser);
+ else if (nested == 2)
+ error_at (c_parser_peek_token (parser)->location,
+ "clauses in %<simd%> trait should be separated "
+ "by %<,%>");
+ }
here = c_parser_peek_token (parser)->location;
c_kind = c_parser_omp_clause_name (parser);
@@ -15513,7 +15528,8 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask,
}
saw_error:
- c_parser_skip_to_pragma_eol (parser);
+ if (!nested)
+ c_parser_skip_to_pragma_eol (parser);
if (finish_p)
{
@@ -18919,7 +18935,11 @@ check_clauses:
}
/* OpenMP 4.0:
- # pragma omp declare simd declare-simd-clauses[optseq] new-line */
+ # pragma omp declare simd declare-simd-clauses[optseq] new-line
+
+ OpenMP 5.0:
+ # pragma omp declare variant (identifier) match(context-selector) new-line
+ */
#define OMP_DECLARE_SIMD_CLAUSE_MASK \
( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SIMDLEN) \
@@ -18932,6 +18952,12 @@ check_clauses:
static void
c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
{
+ c_token *token = c_parser_peek_token (parser);
+ gcc_assert (token->type == CPP_NAME);
+ tree kind = token->value;
+ gcc_assert (strcmp (IDENTIFIER_POINTER (kind), "simd") == 0
+ || strcmp (IDENTIFIER_POINTER (kind), "variant") == 0);
+
auto_vec<c_token> clauses;
while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
{
@@ -18949,17 +18975,14 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
while (c_parser_next_token_is (parser, CPP_PRAGMA))
{
- if (c_parser_peek_token (parser)->pragma_kind
- != PRAGMA_OMP_DECLARE
+ if (c_parser_peek_token (parser)->pragma_kind != PRAGMA_OMP_DECLARE
|| c_parser_peek_2nd_token (parser)->type != CPP_NAME
- || strcmp (IDENTIFIER_POINTER
- (c_parser_peek_2nd_token (parser)->value),
- "simd") != 0)
+ || c_parser_peek_2nd_token (parser)->value != kind)
{
- c_parser_error (parser,
- "%<#pragma omp declare simd%> must be followed by "
- "function declaration or definition or another "
- "%<#pragma omp declare simd%>");
+ error ("%<#pragma omp declare %s%> must be followed by "
+ "function declaration or definition or another "
+ "%<#pragma omp declare %s%>",
+ IDENTIFIER_POINTER (kind), IDENTIFIER_POINTER (kind));
return;
}
c_parser_consume_pragma (parser);
@@ -19007,8 +19030,9 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
case pragma_struct:
case pragma_param:
case pragma_stmt:
- c_parser_error (parser, "%<#pragma omp declare simd%> must be followed by "
- "function declaration or definition");
+ error ("%<#pragma omp declare %s%> must be followed by "
+ "function declaration or definition",
+ IDENTIFIER_POINTER (kind));
break;
case pragma_compound:
if (c_parser_next_token_is (parser, CPP_KEYWORD)
@@ -19034,38 +19058,480 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
NULL, clauses);
break;
}
- c_parser_error (parser, "%<#pragma omp declare simd%> must be followed by "
- "function declaration or definition");
+ error ("%<#pragma omp declare %s%> must be followed by "
+ "function declaration or definition",
+ IDENTIFIER_POINTER (kind));
break;
default:
gcc_unreachable ();
}
}
-/* Finalize #pragma omp declare simd clauses after FNDECL has been parsed,
- and put that into "omp declare simd" attribute. */
+static const char *const omp_construct_selectors[] = {
+ "simd", "target", "teams", "parallel", "for", NULL };
+static const char *const omp_device_selectors[] = {
+ "kind", "isa", "arch", NULL };
+static const char *const omp_implementation_selectors[] = {
+ "vendor", "extension", "atomic_default_mem_order", "unified_address",
+ "unified_shared_memory", "dynamic_allocators", "reverse_offload", NULL };
+static const char *const omp_user_selectors[] = {
+ "condition", NULL };
+
+/* OpenMP 5.0:
+
+ trait-selector:
+ trait-selector-name[([trait-score:]trait-property[,trait-property[,...]])]
+
+ trait-score:
+ score(score-expression) */
+
+static tree
+c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
+{
+ tree ret = NULL_TREE;
+ do
+ {
+ tree selector;
+ if (c_parser_next_token_is (parser, CPP_KEYWORD)
+ || c_parser_next_token_is (parser, CPP_NAME))
+ selector = c_parser_peek_token (parser)->value;
+ else
+ {
+ c_parser_error (parser, "expected trait selector name");
+ return error_mark_node;
+ }
+
+ tree properties = NULL_TREE;
+ const char *const *selectors = NULL;
+ bool allow_score = true;
+ bool allow_user = false;
+ int property_limit = 0;
+ enum { CTX_PROPERTY_NONE, CTX_PROPERTY_USER, CTX_PROPERTY_IDLIST,
+ CTX_PROPERTY_EXPR, CTX_PROPERTY_SIMD } property_kind
+ = CTX_PROPERTY_NONE;
+ switch (IDENTIFIER_POINTER (set)[0])
+ {
+ case 'c': /* construct */
+ selectors = omp_construct_selectors;
+ allow_score = false;
+ property_limit = 1;
+ property_kind = CTX_PROPERTY_SIMD;
+ break;
+ case 'd': /* device */
+ selectors = omp_device_selectors;
+ allow_score = false;
+ allow_user = true;
+ property_limit = 3;
+ property_kind = CTX_PROPERTY_IDLIST;
+ break;
+ case 'i': /* implementation */
+ selectors = omp_implementation_selectors;
+ allow_user = true;
+ property_limit = 3;
+ property_kind = CTX_PROPERTY_IDLIST;
+ break;
+ case 'u': /* user */
+ selectors = omp_user_selectors;
+ property_limit = 1;
+ property_kind = CTX_PROPERTY_EXPR;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ for (int i = 0; ; i++)
+ {
+ if (selectors[i] == NULL)
+ {
+ if (allow_user)
+ {
+ property_kind = CTX_PROPERTY_USER;
+ break;
+ }
+ else
+ {
+ error_at (c_parser_peek_token (parser)->location,
+ "selector %qs not allowed for context selector "
+ "set %qs", IDENTIFIER_POINTER (selector),
+ IDENTIFIER_POINTER (set));
+ c_parser_consume_token (parser);
+ return error_mark_node;
+ }
+ }
+ if (i == property_limit)
+ property_kind = CTX_PROPERTY_NONE;
+ if (strcmp (selectors[i], IDENTIFIER_POINTER (selector)) == 0)
+ break;
+ }
+
+ c_parser_consume_token (parser);
+
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ {
+ if (property_kind == CTX_PROPERTY_NONE)
+ {
+ error_at (c_parser_peek_token (parser)->location,
+ "selector %qs does not accept any properties",
+ IDENTIFIER_POINTER (selector));
+ return error_mark_node;
+ }
+
+ matching_parens parens;
+ parens.require_open (parser);
+
+ c_token *token = c_parser_peek_token (parser);
+ if (allow_score
+ && c_parser_next_token_is (parser, CPP_NAME)
+ && strcmp (IDENTIFIER_POINTER (token->value), "score") == 0
+ && c_parser_peek_2nd_token (parser)->type == CPP_OPEN_PAREN)
+ {
+ c_parser_consume_token (parser);
+
+ matching_parens parens2;
+ parens2.require_open (parser);
+ tree score = c_parser_expr_no_commas (parser, NULL).value;
+ parens2.skip_until_found_close (parser);
+ c_parser_require (parser, CPP_COLON, "expected %<:%>");
+ if (score != error_mark_node)
+ {
+ mark_exp_read (score);
+ score = c_fully_fold (score, false, NULL);
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (score))
+ || !tree_fits_shwi_p (score))
+ error_at (token->location, "score argument must be "
+ "constant integer expression");
+ else
+ properties = tree_cons (get_identifier (" score"),
+ score, properties);
+ }
+ token = c_parser_peek_token (parser);
+ }
+
+ switch (property_kind)
+ {
+ tree t;
+ case CTX_PROPERTY_USER:
+ do
+ {
+ t = c_parser_expr_no_commas (parser, NULL).value;
+ if (TREE_CODE (t) == STRING_CST)
+ properties = tree_cons (NULL_TREE, t, properties);
+ else if (t != error_mark_node)
+ {
+ mark_exp_read (t);
+ t = c_fully_fold (t, false, NULL);
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (t))
+ || !tree_fits_shwi_p (t))
+ error_at (token->location, "property must be "
+ "constant integer expression or string "
+ "literal");
+ else
+ properties = tree_cons (NULL_TREE, t, properties);
+ }
+ else
+ return error_mark_node;
+
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ c_parser_consume_token (parser);
+ else
+ break;
+ }
+ while (1);
+ break;
+ case CTX_PROPERTY_IDLIST:
+ do
+ {
+ tree prop;
+ if (c_parser_next_token_is (parser, CPP_KEYWORD)
+ || c_parser_next_token_is (parser, CPP_NAME))
+ prop = c_parser_peek_token (parser)->value;
+ else
+ {
+ c_parser_error (parser, "expected identifier");
+ return error_mark_node;
+ }
+ c_parser_consume_token (parser);
+
+ properties = tree_cons (prop, NULL_TREE, properties);
+
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ c_parser_consume_token (parser);
+ else
+ break;
+ }
+ while (1);
+ break;
+ case CTX_PROPERTY_EXPR:
+ t = c_parser_expr_no_commas (parser, NULL).value;
+ if (t != error_mark_node)
+ {
+ mark_exp_read (t);
+ t = c_fully_fold (t, false, NULL);
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (t))
+ || !tree_fits_shwi_p (t))
+ error_at (token->location, "property must be "
+ "constant integer expression");
+ else
+ properties = tree_cons (NULL_TREE, t, properties);
+ }
+ else
+ return error_mark_node;
+ break;
+ case CTX_PROPERTY_SIMD:
+ if (parms == NULL_TREE)
+ {
+ error_at (token->location, "properties for %<simd%> "
+ "selector may not be specified in "
+ "%<metadirective%>");
+ return error_mark_node;
+ }
+ tree c;
+ c = c_parser_omp_all_clauses (parser,
+ OMP_DECLARE_SIMD_CLAUSE_MASK,
+ "simd", true, 2);
+ c = c_omp_declare_simd_clauses_to_numbers (parms
+ == error_mark_node
+ ? NULL_TREE : parms,
+ c);
+ properties = c;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ parens.skip_until_found_close (parser);
+ properties = nreverse (properties);
+ }
+ else if (property_kind == CTX_PROPERTY_IDLIST
+ || property_kind == CTX_PROPERTY_EXPR)
+ {
+ c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>");
+ return error_mark_node;
+ }
+
+ ret = tree_cons (selector, properties, ret);
+
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ c_parser_consume_token (parser);
+ else
+ break;
+ }
+ while (1);
+
+ return nreverse (ret);
+}
+
+/* OpenMP 5.0:
+
+ trait-set-selector[,trait-set-selector[,...]]
+
+ trait-set-selector:
+ trait-set-selector-name = { trait-selector[, trait-selector[, ...]] }
+
+ trait-set-selector-name:
+ constructor
+ device
+ implementation
+ user */
+
+static tree
+c_parser_omp_context_selector_specification (c_parser *parser, tree parms)
+{
+ tree ret = NULL_TREE;
+ do
+ {
+ const char *setp = "";
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ setp = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ switch (setp[0])
+ {
+ case 'c':
+ if (strcmp (setp, "construct") == 0)
+ setp = NULL;
+ break;
+ case 'd':
+ if (strcmp (setp, "device") == 0)
+ setp = NULL;
+ break;
+ case 'i':
+ if (strcmp (setp, "implementation") == 0)
+ setp = NULL;
+ break;
+ case 'u':
+ if (strcmp (setp, "user") == 0)
+ setp = NULL;
+ break;
+ default:
+ break;
+ }
+ if (setp)
+ {
+ c_parser_error (parser, "expected %<construct%>, %<device%>, "
+ "%<implementation%> or %<user%>");
+ return error_mark_node;
+ }
+
+ tree set = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+
+ if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
+ return error_mark_node;
+
+ matching_braces braces;
+ if (!braces.require_open (parser))
+ return error_mark_node;
+
+ tree selectors = c_parser_omp_context_selector (parser, set, parms);
+ if (selectors == error_mark_node)
+ ret = error_mark_node;
+ else if (ret != error_mark_node)
+ ret = tree_cons (set, selectors, ret);
+
+ braces.skip_until_found_close (parser);
+
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ c_parser_consume_token (parser);
+ else
+ break;
+ }
+ while (1);
+
+ if (ret == error_mark_node)
+ return ret;
+ return nreverse (ret);
+}
+
+/* Finalize #pragma omp declare variant after FNDECL has been parsed, and put
+ that into "omp declare variant base" attribute. */
+
+static void
+c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms)
+{
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ {
+ fail:
+ c_parser_skip_to_pragma_eol (parser, false);
+ return;
+ }
+
+ if (c_parser_next_token_is_not (parser, CPP_NAME)
+ || c_parser_peek_token (parser)->id_kind != C_ID_ID)
+ {
+ c_parser_error (parser, "expected identifier");
+ goto fail;
+ }
+
+ c_token *token = c_parser_peek_token (parser);
+ tree variant = lookup_name (token->value);
+
+ if (variant == NULL_TREE)
+ {
+ undeclared_variable (token->location, token->value);
+ variant = error_mark_node;
+ }
+
+ c_parser_consume_token (parser);
+
+ parens.require_close (parser);
+
+ const char *clause = "";
+ location_t match_loc = c_parser_peek_token (parser)->location;
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ clause = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp (clause, "match"))
+ {
+ c_parser_error (parser, "expected %<match%>");
+ goto fail;
+ }
+
+ c_parser_consume_token (parser);
+
+ if (!parens.require_open (parser))
+ goto fail;
+
+ if (parms == NULL_TREE)
+ parms = error_mark_node;
+
+ tree ctx = c_parser_omp_context_selector_specification (parser, parms);
+ if (ctx == error_mark_node)
+ goto fail;
+ ctx = c_omp_check_context_selector (match_loc, ctx);
+ if (ctx != error_mark_node && variant != error_mark_node)
+ {
+ if (TREE_CODE (variant) != FUNCTION_DECL)
+ {
+ error_at (token->location, "variant %qD is not a function", variant);
+ variant = error_mark_node;
+ }
+ else if (c_omp_get_context_selector (ctx, "construct", "simd")
+ == NULL_TREE
+ && !comptypes (TREE_TYPE (fndecl), TREE_TYPE (variant)))
+ {
+ error_at (token->location, "variant %qD and base %qD have "
+ "incompatible types", variant, fndecl);
+ variant = error_mark_node;
+ }
+ else if (fndecl_built_in_p (variant)
+ && (strncmp (IDENTIFIER_POINTER (DECL_NAME (variant)),
+ "__builtin_", strlen ("__builtin_")) == 0
+ || strncmp (IDENTIFIER_POINTER (DECL_NAME (variant)),
+ "__sync_", strlen ("__sync_")) == 0
+ || strncmp (IDENTIFIER_POINTER (DECL_NAME (variant)),
+ "__atomic_", strlen ("__atomic_")) == 0))
+ {
+ error_at (token->location, "variant %qD is a built-in", variant);
+ variant = error_mark_node;
+ }
+ if (variant != error_mark_node)
+ {
+ C_DECL_USED (variant) = 1;
+ tree construct = c_omp_get_context_selector (ctx, "construct", NULL);
+ c_omp_mark_declare_variant (match_loc, variant, construct);
+ if (c_omp_context_selector_matches (ctx))
+ {
+ tree attr
+ = tree_cons (get_identifier ("omp declare variant base"),
+ build_tree_list (variant, ctx),
+ DECL_ATTRIBUTES (fndecl));
+ DECL_ATTRIBUTES (fndecl) = attr;
+ }
+ }
+ }
+
+ parens.require_close (parser);
+ c_parser_skip_to_pragma_eol (parser);
+}
+
+/* Finalize #pragma omp declare simd or #pragma omp declare variant
+ clauses after FNDECL has been parsed, and put that into "omp declare simd"
+ or "omp declare variant base" attribute. */
static void
c_finish_omp_declare_simd (c_parser *parser, tree fndecl, tree parms,
vec<c_token> clauses)
{
- /* Normally first token is CPP_NAME "simd". CPP_EOF there indicates
- error has been reported and CPP_PRAGMA that c_finish_omp_declare_simd
- has already processed the tokens. */
+ /* Normally first token is CPP_NAME "simd" or "variant". CPP_EOF there
+ indicates error has been reported and CPP_PRAGMA that
+ c_finish_omp_declare_simd has already processed the tokens. */
if (clauses.exists () && clauses[0].type == CPP_EOF)
return;
+ const char *kind = "simd";
+ if (clauses.exists ()
+ && (clauses[0].type == CPP_NAME || clauses[0].type == CPP_PRAGMA))
+ kind = IDENTIFIER_POINTER (clauses[0].value);
+ gcc_assert (strcmp (kind, "simd") == 0 || strcmp (kind, "variant") == 0);
if (fndecl == NULL_TREE || TREE_CODE (fndecl) != FUNCTION_DECL)
{
- error ("%<#pragma omp declare simd%> not immediately followed by "
- "a function declaration or definition");
+ error ("%<#pragma omp declare %s%> not immediately followed by "
+ "a function declaration or definition", kind);
clauses[0].type = CPP_EOF;
return;
}
if (clauses.exists () && clauses[0].type != CPP_NAME)
{
error_at (DECL_SOURCE_LOCATION (fndecl),
- "%<#pragma omp declare simd%> not immediately followed by "
- "a single function declaration or definition");
+ "%<#pragma omp declare %s%> not immediately followed by "
+ "a single function declaration or definition", kind);
clauses[0].type = CPP_EOF;
return;
}
@@ -19075,7 +19541,6 @@ c_finish_omp_declare_simd (c_parser *parser, tree fndecl, tree parms,
unsigned int tokens_avail = parser->tokens_avail;
gcc_assert (parser->tokens == &parser->tokens_buf[0]);
-
parser->tokens = clauses.address ();
parser->tokens_avail = clauses.length ();
@@ -19085,19 +19550,27 @@ c_finish_omp_declare_simd (c_parser *parser, tree fndecl, tree parms,
{
c_token *token = c_parser_peek_token (parser);
gcc_assert (token->type == CPP_NAME
- && strcmp (IDENTIFIER_POINTER (token->value), "simd") == 0);
+ && strcmp (IDENTIFIER_POINTER (token->value), kind) == 0);
c_parser_consume_token (parser);
parser->in_pragma = true;
- tree c = NULL_TREE;
- c = c_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK,
- "#pragma omp declare simd");
- c = c_omp_declare_simd_clauses_to_numbers (parms, c);
- if (c != NULL_TREE)
- c = tree_cons (NULL_TREE, c, NULL_TREE);
- c = build_tree_list (get_identifier ("omp declare simd"), c);
- TREE_CHAIN (c) = DECL_ATTRIBUTES (fndecl);
- DECL_ATTRIBUTES (fndecl) = c;
+ if (strcmp (kind, "simd") == 0)
+ {
+ tree c;
+ c = c_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK,
+ "#pragma omp declare simd");
+ c = c_omp_declare_simd_clauses_to_numbers (parms, c);
+ if (c != NULL_TREE)
+ c = tree_cons (NULL_TREE, c, NULL_TREE);
+ c = build_tree_list (get_identifier ("omp declare simd"), c);
+ TREE_CHAIN (c) = DECL_ATTRIBUTES (fndecl);
+ DECL_ATTRIBUTES (fndecl) = c;
+ }
+ else
+ {
+ gcc_assert (strcmp (kind, "variant") == 0);
+ c_finish_omp_declare_variant (parser, fndecl, parms);
+ }
}
parser->tokens = &parser->tokens_buf[0];
@@ -19612,7 +20085,10 @@ c_parser_omp_declare_reduction (c_parser *parser, enum pragma_context context)
#pragma omp declare simd declare-simd-clauses[optseq] new-line
#pragma omp declare reduction (reduction-id : typename-list : expression) \
initializer-clause[opt] new-line
- #pragma omp declare target new-line */
+ #pragma omp declare target new-line
+
+ OpenMP 5.0
+ #pragma omp declare variant (identifier) match (context-selector) */
static void
c_parser_omp_declare (c_parser *parser, enum pragma_context context)
@@ -19645,10 +20121,17 @@ c_parser_omp_declare (c_parser *parser, enum pragma_context context)
c_parser_omp_declare_target (parser);
return;
}
+ if (strcmp (p, "variant") == 0)
+ {
+ /* c_parser_consume_token (parser); done in
+ c_parser_omp_declare_simd. */
+ c_parser_omp_declare_simd (parser, context);
+ return;
+ }
}
- c_parser_error (parser, "expected %<simd%> or %<reduction%> "
- "or %<target%>");
+ c_parser_error (parser, "expected %<simd%>, %<reduction%>, "
+ "%<target%> or %<variant%>");
c_parser_skip_to_pragma_eol (parser);
}
diff --git a/gcc/calls.c b/gcc/calls.c
index 51ad55f15a9..ae904473d0d 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -1614,6 +1614,10 @@ maybe_warn_nonstring_arg (tree fndecl, tree exp)
if (!get_attr_nonstring_decl (arg))
{
c_strlen_data lendata = { };
+ /* Set MAXBOUND to an arbitrary non-null non-integer
+ node as a request to have it set to the length of
+ the longest string in a PHI. */
+ lendata.maxbound = arg;
get_range_strlen (arg, &lendata, /* eltsize = */ 1);
maxlen = lendata.maxbound;
}
@@ -1639,6 +1643,10 @@ maybe_warn_nonstring_arg (tree fndecl, tree exp)
if (!get_attr_nonstring_decl (arg))
{
c_strlen_data lendata = { };
+ /* Set MAXBOUND to an arbitrary non-null non-integer
+ node as a request to have it set to the length of
+ the longest string in a PHI. */
+ lendata.maxbound = arg;
get_range_strlen (arg, &lendata, /* eltsize = */ 1);
maxlen = lendata.maxbound;
}
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index 0c3c6e7cac4..8b752d83809 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -3835,7 +3835,7 @@ symbol_table_test::symbol_table_test ()
{
gcc_assert (saved_symtab == NULL);
saved_symtab = symtab;
- symtab = new (ggc_cleared_alloc <symbol_table> ()) symbol_table ();
+ symtab = new (ggc_alloc <symbol_table> ()) symbol_table ();
}
/* Destructor. Restore the old value of symtab. */
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 73b2be6d26d..733d616fb8c 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -2095,9 +2095,19 @@ public:
friend struct cgraph_node;
friend struct cgraph_edge;
- symbol_table (): cgraph_max_uid (1), cgraph_max_summary_id (0),
- edges_max_uid (1), edges_max_summary_id (0),
- cgraph_released_summary_ids (), edge_released_summary_ids ()
+ symbol_table ():
+ cgraph_count (0), cgraph_max_uid (1), cgraph_max_summary_id (0),
+ edges_count (0), edges_max_uid (1), edges_max_summary_id (0),
+ cgraph_released_summary_ids (), edge_released_summary_ids (),
+ nodes (NULL), asmnodes (NULL), asm_last_node (NULL),
+ order (0), global_info_ready (false), state (PARSING),
+ function_flags_ready (false), cpp_implicit_aliases_done (false),
+ section_hash (NULL), assembler_name_hash (NULL), init_priority_hash (NULL),
+ dump_file (NULL), ipa_clones_dump_file (NULL), cloned_nodes (),
+ m_first_edge_removal_hook (NULL), m_first_cgraph_removal_hook (NULL),
+ m_first_edge_duplicated_hook (NULL), m_first_cgraph_duplicated_hook (NULL),
+ m_first_cgraph_insertion_hook (NULL), m_first_varpool_insertion_hook (NULL),
+ m_first_varpool_removal_hook (NULL)
{
}
@@ -2343,6 +2353,9 @@ public:
/* Vector of released summary IDS for cgraph nodes. */
vec<int> GTY ((skip)) edge_released_summary_ids;
+ /* Return symbol used to separate symbol name from suffix. */
+ static char symbol_suffix_separator ();
+
symtab_node* GTY(()) nodes;
asm_node* GTY(()) asmnodes;
asm_node* GTY(()) asm_last_node;
@@ -2372,9 +2385,6 @@ public:
FILE* GTY ((skip)) dump_file;
- /* Return symbol used to separate symbol name from suffix. */
- static char symbol_suffix_separator ();
-
FILE* GTY ((skip)) ipa_clones_dump_file;
hash_set <const cgraph_node *> GTY ((skip)) cloned_nodes;
diff --git a/gcc/combine.c b/gcc/combine.c
index d295a81abf9..92e4e5e6898 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -5680,6 +5680,7 @@ subst (rtx x, rtx from, rtx to, int in_dest, int in_cond, int unique_copy)
}
else if (CONST_SCALAR_INT_P (new_rtx)
&& (GET_CODE (x) == ZERO_EXTEND
+ || GET_CODE (x) == SIGN_EXTEND
|| GET_CODE (x) == FLOAT
|| GET_CODE (x) == UNSIGNED_FLOAT))
{
diff --git a/gcc/common.opt b/gcc/common.opt
index 1b9e0f3c802..124e8cf3ebe 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1281,6 +1281,26 @@ Enum(diagnostic_color_rule) String(always) Value(DIAGNOSTICS_COLOR_YES)
EnumValue
Enum(diagnostic_color_rule) String(auto) Value(DIAGNOSTICS_COLOR_AUTO)
+fdiagnostics-urls=
+Driver Common Joined RejectNegative Var(flag_diagnostics_show_urls) Enum(diagnostic_url_rule) Init(DIAGNOSTICS_URL_AUTO)
+-fdiagnostics-urls=[never|always|auto] Embed URLs in diagnostics.
+
+; Required for these enum values.
+SourceInclude
+diagnostic-url.h
+
+Enum
+Name(diagnostic_url_rule) Type(int)
+
+EnumValue
+Enum(diagnostic_url_rule) String(never) Value(DIAGNOSTICS_URL_NO)
+
+EnumValue
+Enum(diagnostic_url_rule) String(always) Value(DIAGNOSTICS_URL_YES)
+
+EnumValue
+Enum(diagnostic_url_rule) String(auto) Value(DIAGNOSTICS_URL_AUTO)
+
fdiagnostics-format=
Common Joined RejectNegative Enum(diagnostics_output_format)
-fdiagnostics-format=[text|json] Select output format.
diff --git a/gcc/common/config/s390/s390-common.c b/gcc/common/config/s390/s390-common.c
index f9c3a95f897..2e1914e3768 100644
--- a/gcc/common/config/s390/s390-common.c
+++ b/gcc/common/config/s390/s390-common.c
@@ -47,9 +47,9 @@ EXPORTED_CONST int processor_flags_table[] =
/* z14 */ PF_IEEE_FLOAT | PF_ZARCH | PF_LONG_DISPLACEMENT
| PF_EXTIMM | PF_DFP | PF_Z10 | PF_Z196 | PF_ZEC12 | PF_TX
| PF_Z13 | PF_VX | PF_VXE | PF_Z14,
- /* arch13 */ PF_IEEE_FLOAT | PF_ZARCH | PF_LONG_DISPLACEMENT
+ /* z15 */ PF_IEEE_FLOAT | PF_ZARCH | PF_LONG_DISPLACEMENT
| PF_EXTIMM | PF_DFP | PF_Z10 | PF_Z196 | PF_ZEC12 | PF_TX
- | PF_Z13 | PF_VX | PF_VXE | PF_Z14 | PF_VXE2 | PF_ARCH13
+ | PF_Z13 | PF_VX | PF_VXE | PF_Z14 | PF_VXE2 | PF_Z15
};
/* Change optimizations to be performed, depending on the
diff --git a/gcc/config.gcc b/gcc/config.gcc
index 481bc9586a7..bdc2253f8ef 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -4782,14 +4782,12 @@ case "${target}" in
echo "#undef LINK_OS_EXTRA_SPEC32"
echo "#define LINK_OS_EXTRA_SPEC32" \
"\"%(link_os_new_dtags)" \
- "-rpath $prefix/lib -rpath $at/lib" \
- "-L $prefix/lib -L $at/lib\""
+ "-rpath $prefix/lib -rpath $at/lib\""
echo
echo "#undef LINK_OS_EXTRA_SPEC64"
echo "#define LINK_OS_EXTRA_SPEC64" \
"\"%(link_os_new_dtags)" \
- "-rpath $prefix/lib64 -rpath $at/lib64" \
- "-L $prefix/lib64 -L $at/lib64\""
+ "-rpath $prefix/lib64 -rpath $at/lib64\""
echo
echo "#undef LINK_OS_NEW_DTAGS_SPEC"
echo "#define LINK_OS_NEW_DTAGS_SPEC" \
@@ -4802,7 +4800,10 @@ case "${target}" in
echo "#define MD_EXEC_PREFIX \"$at/bin/\""
echo
echo "#undef MD_STARTFILE_PREFIX"
- echo "#define MD_STARTFILE_PREFIX \"$at/lib/\"") \
+ echo "#define MD_STARTFILE_PREFIX \"$prefix/lib/\""
+ echo
+ echo "#undef MD_STARTFILE_PREFIX_1"
+ echo "#define MD_STARTFILE_PREFIX_1 \"$at/lib/\"") \
> advance-toolchain.h
else
echo "Unknown advance-toolchain $with_advance_toolchain"
@@ -4825,7 +4826,7 @@ case "${target}" in
for which in arch tune; do
eval "val=\$with_$which"
case ${val} in
- "" | native | z900 | z990 | z9-109 | z9-ec | z10 | z196 | zEC12 | z13 | z14 | arch5 | arch6 | arch7 | arch8 | arch9 | arch10 | arch11 | arch12 | arch13 )
+ "" | native | z900 | z990 | z9-109 | z9-ec | z10 | z196 | zEC12 | z13 | z14 | z15 | arch5 | arch6 | arch7 | arch8 | arch9 | arch10 | arch11 | arch12 | arch13 )
# OK
;;
*)
diff --git a/gcc/config.in b/gcc/config.in
index 13fd7959dd7..9b54a4715db 100644
--- a/gcc/config.in
+++ b/gcc/config.in
@@ -553,6 +553,12 @@
#endif
+/* Define if your assembler supports .mspabi_attribute. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_AS_MSPABI_ATTRIBUTE
+#endif
+
+
/* Define if the assembler understands -mnan=. */
#ifndef USED_FOR_TARGET
#undef HAVE_AS_NAN
diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c
index f01305b3c1a..a7d5454b574 100644
--- a/gcc/config/alpha/alpha.c
+++ b/gcc/config/alpha/alpha.c
@@ -8708,6 +8708,9 @@ alpha_handle_trap_shadows (void)
case CODE_LABEL:
goto close_shadow;
+ case DEBUG_INSN:
+ break;
+
default:
gcc_unreachable ();
}
diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
index 8b67c9c3657..5fad1e5bcc2 100644
--- a/gcc/config/arm/arm.h
+++ b/gcc/config/arm/arm.h
@@ -1068,9 +1068,8 @@ extern int arm_regs_in_sequence[];
/* Use different register alloc ordering for Thumb. */
#define ADJUST_REG_ALLOC_ORDER arm_order_regs_for_local_alloc ()
-/* Tell IRA to use the order we define rather than messing it up with its
- own cost calculations. */
-#define HONOR_REG_ALLOC_ORDER 1
+/* Tell IRA to use the order we define when optimizing for size. */
+#define HONOR_REG_ALLOC_ORDER optimize_function_for_size_p (cfun)
/* Interrupt functions can only use registers that have already been
saved by the prologue, even if they would normally be
diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md
index e85bf49632d..f711d4e3dc6 100644
--- a/gcc/config/avr/avr.md
+++ b/gcc/config/avr/avr.md
@@ -344,7 +344,7 @@
})
-;; Defining nonlocal_goto_receiver means we must also define this.
+;; Defining nonlocal_goto_receiver means we must also define this
;; even though its function is identical to that in builtins.c
(define_expand "nonlocal_goto"
diff --git a/gcc/config/darwin-protos.h b/gcc/config/darwin-protos.h
index e5614b627d7..afeca81f807 100644
--- a/gcc/config/darwin-protos.h
+++ b/gcc/config/darwin-protos.h
@@ -53,8 +53,6 @@ extern void darwin_set_default_type_attributes (tree);
#endif /* TREE_CODE */
-extern void machopic_finish (FILE *);
-
extern int machopic_reloc_rw_mask (void);
extern section *machopic_select_section (tree, int, unsigned HOST_WIDE_INT);
diff --git a/gcc/config/darwin.c b/gcc/config/darwin.c
index 56739823946..8635fc2b441 100644
--- a/gcc/config/darwin.c
+++ b/gcc/config/darwin.c
@@ -76,7 +76,7 @@ along with GCC; see the file COPYING3. If not see
setting the second word in the .non_lazy_symbol_pointer data
structure to symbol. See indirect_data for the code that handles
the extra indirection, and machopic_output_indirection and its use
- of MACHO_SYMBOL_STATIC for the code that handles @code{static}
+ of MACHO_SYMBOL_FLAG_STATIC for the code that handles @code{static}
symbol indirection. */
typedef struct GTY(()) cdtor_record {
@@ -249,7 +249,7 @@ name_needs_quotes (const char *name)
int
machopic_symbol_defined_p (rtx sym_ref)
{
- if (SYMBOL_REF_FLAGS (sym_ref) & MACHO_SYMBOL_FLAG_DEFINED)
+ if (MACHO_SYMBOL_DEFINED_P (sym_ref))
return true;
/* If a symbol references local and is not an extern to this
@@ -258,7 +258,7 @@ machopic_symbol_defined_p (rtx sym_ref)
{
/* If the symbol references a variable and the variable is a
common symbol, then this symbol is not defined. */
- if (SYMBOL_REF_FLAGS (sym_ref) & MACHO_SYMBOL_FLAG_VARIABLE)
+ if (MACHO_SYMBOL_VARIABLE_P (sym_ref))
{
tree decl = SYMBOL_REF_DECL (sym_ref);
if (!decl)
@@ -454,6 +454,13 @@ typedef struct GTY ((for_user)) machopic_indirection
bool stub_p;
/* True iff this stub or pointer has been referenced. */
bool used;
+ /* True iff a non-lazy symbol pointer should be emitted into the .data
+ section, rather than the non-lazy symbol pointers section. The cases
+ for which this occurred seem to have been unintentional, and later
+ toolchains emit all of the indirections to the 'usual' section. We
+ are keeping this in case it is necessary to preserve compatibility with
+ older toolchains. */
+ bool nlsp_in_data_section;
} machopic_indirection;
struct indirection_hasher : ggc_ptr_hash<machopic_indirection>
@@ -488,7 +495,7 @@ indirection_hasher::equal (machopic_indirection *s, const char *k)
/* Return the name of the non-lazy pointer (if STUB_P is false) or
stub (if STUB_B is true) corresponding to the given name.
- If we have a situation like:
+ PR71767 - If we have a situation like:
global_weak_symbol:
....
@@ -497,36 +504,22 @@ Lnon_weak_local:
ld64 will be unable to split this into two atoms (because the "L" makes
the second symbol 'invisible'). This means that legitimate direct accesses
- to the second symbol will appear to be non-allowed direct accesses to an
- atom of type weak, global which are not allowed.
+ to the second symbol will appear to be direct accesses to an atom of type
+ weak, global which are not allowed.
- To avoid this, we make the indirections have a leading 'l' (lower-case L)
- which has a special meaning: linker can see this and use it to determine
- atoms, but it is not placed into the final symbol table.
-
- The implementation here is somewhat heavy-handed in that it will also mark
- indirections to the __IMPORT,__pointers section the same way which is
- really unnecessary, since ld64 _can_ split those into atoms as they are
- fixed size. FIXME: determine if this is a penalty worth extra code to
- fix.
+ To avoid this, we make any data-section indirections have a leading 'l'
+ (lower-case L) which has a special meaning: linker can see this and use
+ it to determine atoms, but it is not placed into the final symbol table.
+ Symbols in the non-lazy symbol pointers section (or stubs) do not have this
+ problem because ld64 already knows the size of each entry.
*/
const char *
machopic_indirection_name (rtx sym_ref, bool stub_p)
{
- char *buffer;
const char *name = XSTR (sym_ref, 0);
- size_t namelen = strlen (name);
- machopic_indirection *p;
- bool needs_quotes;
- const char *suffix;
- char L_or_l = 'L';
- const char *prefix = user_label_prefix;
- const char *quote = "";
- tree id;
-
- id = maybe_get_identifier (name);
+ tree id = maybe_get_identifier (name);
if (id)
{
tree id_orig = id;
@@ -534,43 +527,47 @@ machopic_indirection_name (rtx sym_ref, bool stub_p)
while (IDENTIFIER_TRANSPARENT_ALIAS (id))
id = TREE_CHAIN (id);
if (id != id_orig)
- {
- name = IDENTIFIER_POINTER (id);
- namelen = strlen (name);
- }
+ name = IDENTIFIER_POINTER (id);
}
+ const char *prefix = user_label_prefix;
+ /* If we are emitting the label 'verbatim' then omit the U_L_P and count
+ the name without the leading '*'. */
if (name[0] == '*')
{
prefix = "";
++name;
- --namelen;
- }
-
- needs_quotes = name_needs_quotes (name);
- if (needs_quotes)
- {
- quote = "\"";
- }
-
- if (stub_p)
- suffix = STUB_SUFFIX;
- else
- {
- suffix = NON_LAZY_POINTER_SUFFIX;
- /* Let the linker see this. */
- L_or_l = 'l';
}
- buffer = XALLOCAVEC (char, 2 /* strlen ("&L") or ("&l") */
- + strlen (prefix)
- + namelen
- + strlen (suffix)
- + 2 * strlen (quote)
- + 1 /* '\0' */);
+ /* Here we are undoing a number of causes that placed some indirections
+ (apparently erroneously) into the .data section. Specifically, some
+ symbols that are ABI mandated indirections and some hidden symbols
+ were being placed there - which cause difficulties with later
+ versions of ld64. Iff (after these checks) some symbol still gets an
+ indirection in the data section, we want to adjust the indirection
+ name to be linker visible to deal with PR71767 (notes above). */
+ bool nlsp_in_data_section =
+ ! MACHO_SYMBOL_MUST_INDIRECT_P (sym_ref)
+ && ! MACHO_SYMBOL_HIDDEN_VIS_P (sym_ref)
+ && (machopic_symbol_defined_p (sym_ref) || SYMBOL_REF_LOCAL_P (sym_ref))
+ && ! indirect_data (sym_ref);
+
+ const char *suffix = stub_p ? STUB_SUFFIX : NON_LAZY_POINTER_SUFFIX;
+ /* If the indirection is in the data section, let the linker see it. */
+ char L_or_l = (!stub_p && nlsp_in_data_section) ? 'l' : 'L';
+ /* We have mangled symbols with spaces and punctuation which typically
+ need surrounding in quotes for the assembler to consume them. */
+ const char *quote = name_needs_quotes (name) ? "\"" : "";
+ char *buffer = XALLOCAVEC (char, 2 /* strlen ("&L") or ("&l") */
+ + strlen (prefix)
+ + strlen (name)
+ + strlen (suffix)
+ + 2 * strlen (quote)
+ + 1 /* '\0' */);
/* Construct the name of the non-lazy pointer or stub. */
- sprintf (buffer, "&%s%c%s%s%s%s", quote, L_or_l, prefix, name, suffix, quote);
+ sprintf (buffer, "&%s%c%s%s%s%s", quote, L_or_l, prefix, name,
+ suffix, quote);
if (!machopic_indirections)
machopic_indirections = hash_table<indirection_hasher>::create_ggc (37);
@@ -579,10 +576,9 @@ machopic_indirection_name (rtx sym_ref, bool stub_p)
= machopic_indirections->find_slot_with_hash (buffer,
htab_hash_string (buffer),
INSERT);
+ machopic_indirection *p;
if (*slot)
- {
- p = *slot;
- }
+ p = *slot;
else
{
p = ggc_alloc<machopic_indirection> ();
@@ -590,6 +586,7 @@ machopic_indirection_name (rtx sym_ref, bool stub_p)
p->ptr_name = xstrdup (buffer);
p->stub_p = stub_p;
p->used = false;
+ p->nlsp_in_data_section = nlsp_in_data_section;
*slot = p;
}
@@ -665,7 +662,7 @@ machopic_indirect_data_reference (rtx orig, rtx reg)
/* some other cpu -- writeme! */
gcc_unreachable ();
}
- else if (defined)
+ else if (defined && ! MACHO_SYMBOL_MUST_INDIRECT_P (orig))
{
rtx offset = NULL;
if (DARWIN_PPC || HAVE_lo_sum)
@@ -707,6 +704,7 @@ machopic_indirect_data_reference (rtx orig, rtx reg)
machopic_indirection_name (orig, /*stub_p=*/false)));
SYMBOL_REF_DATA (ptr_ref) = SYMBOL_REF_DATA (orig);
+ SYMBOL_REF_FLAGS (ptr_ref) |= MACHO_SYMBOL_FLAG_INDIRECTION;
ptr_ref = gen_const_mem (Pmode, ptr_ref);
machopic_define_symbol (ptr_ref);
@@ -740,21 +738,6 @@ machopic_indirect_data_reference (rtx orig, rtx reg)
else if (GET_CODE (orig) == PLUS)
{
rtx base, result;
- /* When the target is i386, this code prevents crashes due to the
- compiler's ignorance on how to move the PIC base register to
- other registers. (The reload phase sometimes introduces such
- insns.) */
- if (GET_CODE (XEXP (orig, 0)) == REG
- && REGNO (XEXP (orig, 0)) == PIC_OFFSET_TABLE_REGNUM
- /* Prevent the same register from being erroneously used
- as both the base and index registers. */
- && (DARWIN_X86 && (GET_CODE (XEXP (orig, 1)) == CONST))
- && reg)
- {
- emit_move_insn (reg, XEXP (orig, 0));
- XEXP (ptr_ref, 0) = reg;
- return ptr_ref;
- }
/* Legitimize both operands of the PLUS. */
base = machopic_indirect_data_reference (XEXP (orig, 0), reg);
@@ -797,8 +780,7 @@ machopic_indirect_call_target (rtx target)
if (MACHOPIC_INDIRECT
&& GET_CODE (XEXP (target, 0)) == SYMBOL_REF
- && !(SYMBOL_REF_FLAGS (XEXP (target, 0))
- & MACHO_SYMBOL_FLAG_DEFINED))
+ && ! MACHO_SYMBOL_DEFINED_P (XEXP (target, 0)))
{
rtx sym_ref = XEXP (target, 0);
const char *stub_name = machopic_indirection_name (sym_ref,
@@ -807,6 +789,7 @@ machopic_indirect_call_target (rtx target)
XEXP (target, 0) = gen_rtx_SYMBOL_REF (mode, stub_name);
SYMBOL_REF_DATA (XEXP (target, 0)) = SYMBOL_REF_DATA (sym_ref);
+ SYMBOL_REF_FLAGS (XEXP (target, 0)) |= MACHO_SYMBOL_FLAG_INDIRECTION;
MEM_READONLY_P (target) = 1;
MEM_NOTRAP_P (target) = 1;
}
@@ -1068,129 +1051,160 @@ machopic_legitimize_pic_address (rtx orig, machine_mode mode, rtx reg)
return pic_ref;
}
-/* Output the stub or non-lazy pointer in *SLOT, if it has been used.
- DATA is the FILE* for assembly output. Called from
- htab_traverse. */
+/* Callbacks to output the stub or non-lazy pointers.
+ Each works on the item in *SLOT,if it has been used.
+ DATA is the FILE* for assembly output.
+ Called from htab_traverses, invoked from machopic_finish(). */
int
-machopic_output_indirection (machopic_indirection **slot, FILE *asm_out_file)
+machopic_output_data_section_indirection (machopic_indirection **slot,
+ FILE *asm_out_file)
{
machopic_indirection *p = *slot;
- rtx symbol;
- const char *sym_name;
- const char *ptr_name;
- if (!p->used)
+ if (!p->used || !p->nlsp_in_data_section)
return 1;
- symbol = p->symbol;
- sym_name = XSTR (symbol, 0);
- ptr_name = p->ptr_name;
+ rtx symbol = p->symbol;
+ /* The original symbol name. */
+ const char *sym_name = XSTR (symbol, 0);
+ /* The name of the indirection symbol. */
+ const char *ptr_name = p->ptr_name;
- if (p->stub_p)
- {
- char *sym;
- char *stub;
- tree id;
+ switch_to_section (data_section);
+ assemble_align (GET_MODE_ALIGNMENT (Pmode));
+ assemble_label (asm_out_file, ptr_name);
+ assemble_integer (gen_rtx_SYMBOL_REF (Pmode, sym_name),
+ GET_MODE_SIZE (Pmode),
+ GET_MODE_ALIGNMENT (Pmode), 1);
- id = maybe_get_identifier (sym_name);
- if (id)
- {
- tree id_orig = id;
+ return 1;
+}
- while (IDENTIFIER_TRANSPARENT_ALIAS (id))
- id = TREE_CHAIN (id);
- if (id != id_orig)
- sym_name = IDENTIFIER_POINTER (id);
- }
+int
+machopic_output_stub_indirection (machopic_indirection **slot,
+ FILE *asm_out_file)
+{
+ machopic_indirection *p = *slot;
- sym = XALLOCAVEC (char, strlen (sym_name) + 2);
- if (sym_name[0] == '*' || sym_name[0] == '&')
- strcpy (sym, sym_name + 1);
- else if (sym_name[0] == '-' || sym_name[0] == '+')
- strcpy (sym, sym_name);
- else
- sprintf (sym, "%s%s", user_label_prefix, sym_name);
+ if (!p->used || !p->stub_p)
+ return 1;
- stub = XALLOCAVEC (char, strlen (ptr_name) + 2);
- if (ptr_name[0] == '*' || ptr_name[0] == '&')
- strcpy (stub, ptr_name + 1);
- else
- sprintf (stub, "%s%s", user_label_prefix, ptr_name);
+ rtx symbol = p->symbol;
+ /* The original symbol name. */
+ const char *sym_name = XSTR (symbol, 0);
+ /* The name of the stub symbol. */
+ const char *ptr_name = p->ptr_name;
- machopic_output_stub (asm_out_file, sym, stub);
- }
- else if (! indirect_data (symbol)
- && (machopic_symbol_defined_p (symbol)
- || SYMBOL_REF_LOCAL_P (symbol)))
+ tree id = maybe_get_identifier (sym_name);
+ if (id)
{
- switch_to_section (data_section);
- assemble_align (GET_MODE_ALIGNMENT (Pmode));
- assemble_label (asm_out_file, ptr_name);
- assemble_integer (gen_rtx_SYMBOL_REF (Pmode, sym_name),
- GET_MODE_SIZE (Pmode),
- GET_MODE_ALIGNMENT (Pmode), 1);
+ tree id_orig = id;
+
+ while (IDENTIFIER_TRANSPARENT_ALIAS (id))
+ id = TREE_CHAIN (id);
+ if (id != id_orig)
+ sym_name = IDENTIFIER_POINTER (id);
}
+
+ char *sym = XALLOCAVEC (char, strlen (sym_name) + 2);
+ if (sym_name[0] == '*' || sym_name[0] == '&')
+ strcpy (sym, sym_name + 1);
+ else if (sym_name[0] == '-' || sym_name[0] == '+')
+ strcpy (sym, sym_name);
else
- {
- rtx init = const0_rtx;
+ sprintf (sym, "%s%s", user_label_prefix, sym_name);
- switch_to_section (darwin_sections[machopic_nl_symbol_ptr_section]);
+ char *stub = XALLOCAVEC (char, strlen (ptr_name) + 2);
+ if (ptr_name[0] == '*' || ptr_name[0] == '&')
+ strcpy (stub, ptr_name + 1);
+ else
+ sprintf (stub, "%s%s", user_label_prefix, ptr_name);
+
+ machopic_output_stub (asm_out_file, sym, stub);
+
+ return 1;
+}
+
+int
+machopic_output_indirection (machopic_indirection **slot, FILE *asm_out_file)
+{
+ machopic_indirection *p = *slot;
+
+ if (!p->used || p->stub_p || p->nlsp_in_data_section)
+ return 1;
+
+ rtx symbol = p->symbol;
+ /* The original symbol name. */
+ const char *sym_name = XSTR (symbol, 0);
+ /* The nonlazy-stub symbol name. */
+ const char *ptr_name = p->ptr_name;
+
+ switch_to_section (darwin_sections[machopic_nl_symbol_ptr_section]);
+
+ /* Mach-O symbols are passed around in code through indirect references and
+ the original symbol_ref hasn't passed through the generic handling and
+ reference-catching in output_operand, so we need to manually mark weak
+ references as such. */
+
+ if (SYMBOL_REF_WEAK (symbol))
+ {
+ tree decl = SYMBOL_REF_DECL (symbol);
+ gcc_checking_assert (DECL_P (decl));
- /* Mach-O symbols are passed around in code through indirect
- references and the original symbol_ref hasn't passed through
- the generic handling and reference-catching in
- output_operand, so we need to manually mark weak references
- as such. */
- if (SYMBOL_REF_WEAK (symbol))
+ if (decl != NULL_TREE
+ && DECL_EXTERNAL (decl) && TREE_PUBLIC (decl)
+ /* Handle only actual external-only definitions, not
+ e.g. extern inline code or variables for which
+ storage has been allocated. */
+ && !TREE_STATIC (decl))
{
- tree decl = SYMBOL_REF_DECL (symbol);
- gcc_assert (DECL_P (decl));
-
- if (decl != NULL_TREE
- && DECL_EXTERNAL (decl) && TREE_PUBLIC (decl)
- /* Handle only actual external-only definitions, not
- e.g. extern inline code or variables for which
- storage has been allocated. */
- && !TREE_STATIC (decl))
- {
- fputs ("\t.weak_reference ", asm_out_file);
- assemble_name (asm_out_file, sym_name);
- fputc ('\n', asm_out_file);
- }
+ fputs ("\t.weak_reference ", asm_out_file);
+ assemble_name (asm_out_file, sym_name);
+ fputc ('\n', asm_out_file);
}
+ }
- assemble_name (asm_out_file, ptr_name);
- fprintf (asm_out_file, ":\n");
+ assemble_name (asm_out_file, ptr_name);
+ fprintf (asm_out_file, ":\n");
- fprintf (asm_out_file, "\t.indirect_symbol ");
- assemble_name (asm_out_file, sym_name);
- fprintf (asm_out_file, "\n");
+ fprintf (asm_out_file, "\t.indirect_symbol ");
+ assemble_name (asm_out_file, sym_name);
+ fprintf (asm_out_file, "\n");
- /* Variables that are marked with MACHO_SYMBOL_STATIC need to
- have their symbol name instead of 0 in the second entry of
- the non-lazy symbol pointer data structure when they are
- defined. This allows the runtime to rebind newer instances
- of the translation unit with the original instance of the
- symbol. */
+ /* Variables that are marked with MACHO_SYMBOL_FLAG_STATIC need to
+ have their symbol name instead of 0 in the second entry of
+ the non-lazy symbol pointer data structure when they are
+ defined. This allows the runtime to rebind newer instances
+ of the translation unit with the original instance of the
+ symbol. */
- if ((SYMBOL_REF_FLAGS (symbol) & MACHO_SYMBOL_STATIC)
- && machopic_symbol_defined_p (symbol))
- init = gen_rtx_SYMBOL_REF (Pmode, sym_name);
+ rtx init = const0_rtx;
+ if (MACHO_SYMBOL_STATIC_P (symbol) && machopic_symbol_defined_p (symbol))
+ init = gen_rtx_SYMBOL_REF (Pmode, sym_name);
- assemble_integer (init, GET_MODE_SIZE (Pmode),
- GET_MODE_ALIGNMENT (Pmode), 1);
- }
+ assemble_integer (init, GET_MODE_SIZE (Pmode),
+ GET_MODE_ALIGNMENT (Pmode), 1);
return 1;
}
-void
+static void
machopic_finish (FILE *asm_out_file)
{
- if (machopic_indirections)
- machopic_indirections
- ->traverse_noresize<FILE *, machopic_output_indirection> (asm_out_file);
+ if (!machopic_indirections)
+ return;
+
+ /* First output an symbol indirections that have been placed into .data
+ (we don't expect these now). */
+ machopic_indirections->traverse_noresize
+ <FILE *, machopic_output_data_section_indirection> (asm_out_file);
+
+ machopic_indirections->traverse_noresize
+ <FILE *, machopic_output_stub_indirection> (asm_out_file);
+
+ machopic_indirections->traverse_noresize
+ <FILE *, machopic_output_indirection> (asm_out_file);
}
int
@@ -1205,25 +1219,51 @@ machopic_operand_p (rtx op)
&& XINT (XEXP (op, 0), 1) == UNSPEC_MACHOPIC_OFFSET);
}
-/* This function records whether a given name corresponds to a defined
- or undefined function or variable, for machopic_classify_ident to
- use later. */
+/* This function:
+ computes and caches a series of flags that characterise the symbol's
+ properties that affect Mach-O code gen (including accidental cases
+ from older toolchains).
+
+ TODO:
+ Here we also need to do enough analysis to determine if a symbol's
+ name needs to be made linker-visible. This is more tricky - since
+ it depends on whether we've previously seen a global weak definition
+ in the same section.
+ */
void
-darwin_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED)
+darwin_encode_section_info (tree decl, rtx rtl, int first)
{
- rtx sym_ref;
+ /* Careful not to prod global register variables. */
+ if (!MEM_P (rtl))
+ return;
- /* Do the standard encoding things first. */
+ /* Do the standard encoding things first; this sets:
+ SYMBOL_FLAG_FUNCTION,
+ SYMBOL_FLAG_LOCAL, (binds_local_p)
+ TLS_MODEL, SYMBOL_FLAG_SMALL
+ SYMBOL_FLAG_EXTERNAL. */
default_encode_section_info (decl, rtl, first);
- if (TREE_CODE (decl) != FUNCTION_DECL && TREE_CODE (decl) != VAR_DECL)
+ if (! VAR_OR_FUNCTION_DECL_P (decl))
return;
- sym_ref = XEXP (rtl, 0);
- if (TREE_CODE (decl) == VAR_DECL)
+ rtx sym_ref = XEXP (rtl, 0);
+ if (VAR_P (decl))
SYMBOL_REF_FLAGS (sym_ref) |= MACHO_SYMBOL_FLAG_VARIABLE;
+ /* Only really common if there's no initialiser. */
+ bool really_common_p = (DECL_COMMON (decl)
+ && (DECL_INITIAL (decl) == NULL
+ || (!in_lto_p
+ && DECL_INITIAL (decl) == error_mark_node)));
+
+ /* For Darwin, if we have specified visibility and it's not the default
+ that's counted 'hidden'. */
+ if (DECL_VISIBILITY_SPECIFIED (decl)
+ && DECL_VISIBILITY (decl) != VISIBILITY_DEFAULT)
+ SYMBOL_REF_FLAGS (sym_ref) |= MACHO_SYMBOL_FLAG_HIDDEN_VIS;
+
if (!DECL_EXTERNAL (decl)
&& (!TREE_PUBLIC (decl) || !DECL_WEAK (decl))
&& ! lookup_attribute ("weakref", DECL_ATTRIBUTES (decl))
@@ -1234,7 +1274,24 @@ darwin_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED)
SYMBOL_REF_FLAGS (sym_ref) |= MACHO_SYMBOL_FLAG_DEFINED;
if (! TREE_PUBLIC (decl))
- SYMBOL_REF_FLAGS (sym_ref) |= MACHO_SYMBOL_STATIC;
+ SYMBOL_REF_FLAGS (sym_ref) |= MACHO_SYMBOL_FLAG_STATIC;
+
+ /* Short cut check for Darwin 'must indirect' rules. */
+ if (really_common_p
+ || (DECL_WEAK (decl) && ! MACHO_SYMBOL_HIDDEN_VIS_P (sym_ref))
+ || lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)))
+ SYMBOL_REF_FLAGS (sym_ref) |= MACHO_SYMBOL_FLAG_MUST_INDIRECT;
+
+#if DARWIN_PPC
+ /* Objective C V2 (m64) IVAR offset refs from Apple GCC-4.x have an
+ indirection for m64 code on PPC. Historically, these indirections
+ also appear in the .data section. */
+ tree o2meta = lookup_attribute ("OBJC2META", DECL_ATTRIBUTES (decl));
+ o2meta = o2meta ? TREE_VALUE (o2meta) : NULL_TREE;
+
+ if (o2meta && strncmp (IDENTIFIER_POINTER (o2meta), "V2_IVRF",7) == 0)
+ SYMBOL_REF_FLAGS (sym_ref) |= MACHO_SYMBOL_FLAG_MUST_INDIRECT;
+#endif
}
void
@@ -1663,83 +1720,14 @@ machopic_select_section (tree decl,
else
return base_section;
}
- /* c) legacy meta-data selection. */
- else if (TREE_CODE (decl) == VAR_DECL
+ else if (flag_next_runtime
+ && VAR_P (decl)
&& DECL_NAME (decl)
&& TREE_CODE (DECL_NAME (decl)) == IDENTIFIER_NODE
&& IDENTIFIER_POINTER (DECL_NAME (decl))
- && flag_next_runtime
&& !strncmp (IDENTIFIER_POINTER (DECL_NAME (decl)), "_OBJC_", 6))
- {
- const char *name = IDENTIFIER_POINTER (DECL_NAME (decl));
- static bool warned_objc_46 = false;
- /* We shall assert that zero-sized objects are an error in ObjC
- meta-data. */
- gcc_assert (tree_to_uhwi (DECL_SIZE_UNIT (decl)) != 0);
-
- /* ??? This mechanism for determining the metadata section is
- broken when LTO is in use, since the frontend that generated
- the data is not identified. We will keep the capability for
- the short term - in case any non-Objective-C programs are using
- it to place data in specified sections. */
- if (!warned_objc_46)
- {
- location_t loc = DECL_SOURCE_LOCATION (decl);
- warning_at (loc, 0, "the use of _OBJC_-prefixed variable names"
- " to select meta-data sections is deprecated at 4.6"
- " and will be removed in 4.7");
- warned_objc_46 = true;
- }
-
- if (!strncmp (name, "_OBJC_CLASS_METHODS_", 20))
- return darwin_sections[objc_cls_meth_section];
- else if (!strncmp (name, "_OBJC_INSTANCE_METHODS_", 23))
- return darwin_sections[objc_inst_meth_section];
- else if (!strncmp (name, "_OBJC_CATEGORY_CLASS_METHODS_", 29))
- return darwin_sections[objc_cat_cls_meth_section];
- else if (!strncmp (name, "_OBJC_CATEGORY_INSTANCE_METHODS_", 32))
- return darwin_sections[objc_cat_inst_meth_section];
- else if (!strncmp (name, "_OBJC_CLASS_VARIABLES_", 22))
- return darwin_sections[objc_class_vars_section];
- else if (!strncmp (name, "_OBJC_INSTANCE_VARIABLES_", 25))
- return darwin_sections[objc_instance_vars_section];
- else if (!strncmp (name, "_OBJC_CLASS_PROTOCOLS_", 22))
- return darwin_sections[objc_cat_cls_meth_section];
- else if (!strncmp (name, "_OBJC_CLASS_NAME_", 17))
- return darwin_sections[objc_class_names_section];
- else if (!strncmp (name, "_OBJC_METH_VAR_NAME_", 20))
- return darwin_sections[objc_meth_var_names_section];
- else if (!strncmp (name, "_OBJC_METH_VAR_TYPE_", 20))
- return darwin_sections[objc_meth_var_types_section];
- else if (!strncmp (name, "_OBJC_CLASS_REFERENCES", 22))
- return darwin_sections[objc_cls_refs_section];
- else if (!strncmp (name, "_OBJC_CLASS_", 12))
- return darwin_sections[objc_class_section];
- else if (!strncmp (name, "_OBJC_METACLASS_", 16))
- return darwin_sections[objc_meta_class_section];
- else if (!strncmp (name, "_OBJC_CATEGORY_", 15))
- return darwin_sections[objc_category_section];
- else if (!strncmp (name, "_OBJC_SELECTOR_REFERENCES", 25))
- return darwin_sections[objc_selector_refs_section];
- else if (!strncmp (name, "_OBJC_SELECTOR_FIXUP", 20))
- return darwin_sections[objc_selector_fixup_section];
- else if (!strncmp (name, "_OBJC_SYMBOLS", 13))
- return darwin_sections[objc_symbols_section];
- else if (!strncmp (name, "_OBJC_MODULES", 13))
- return darwin_sections[objc_module_info_section];
- else if (!strncmp (name, "_OBJC_IMAGE_INFO", 16))
- return darwin_sections[objc_image_info_section];
- else if (!strncmp (name, "_OBJC_PROTOCOL_INSTANCE_METHODS_", 32))
- return darwin_sections[objc_cat_inst_meth_section];
- else if (!strncmp (name, "_OBJC_PROTOCOL_CLASS_METHODS_", 29))
- return darwin_sections[objc_cat_cls_meth_section];
- else if (!strncmp (name, "_OBJC_PROTOCOL_REFS_", 20))
- return darwin_sections[objc_cat_cls_meth_section];
- else if (!strncmp (name, "_OBJC_PROTOCOL_", 15))
- return darwin_sections[objc_protocol_section];
- else
- return base_section;
- }
+ /* c) legacy meta-data selection was deprecated at 4.6, removed now. */
+ gcc_unreachable ();
return base_section;
}
@@ -2954,8 +2942,9 @@ darwin_file_end (void)
}
machopic_finish (asm_out_file);
- if (lang_GNU_CXX ())
+ if (flag_apple_kext)
{
+ /* These sections are only used for kernel code. */
switch_to_section (darwin_sections[constructor_section]);
switch_to_section (darwin_sections[destructor_section]);
ASM_OUTPUT_ALIGN (asm_out_file, 1);
@@ -3148,18 +3137,19 @@ darwin_override_options (void)
: (generating_for_darwin_version >= 9) ? 1
: 0);
- /* Objective-C family ABI 2 is only valid for next/m64 at present. */
if (global_options_set.x_flag_objc_abi && flag_next_runtime)
{
- if (TARGET_64BIT && global_options.x_flag_objc_abi < 2)
- error_at (UNKNOWN_LOCATION, "%<-fobjc-abi-version%> must be greater"
- " than or equal to 2 for %<-m64%> targets"
- " with %<-fnext-runtime%>");
- if (!TARGET_64BIT && global_options.x_flag_objc_abi >= 2)
- error_at (UNKNOWN_LOCATION, "%<-fobjc-abi-version%> %d is not"
- " supported on %<-m32%> targets with"
- " %<-fnext-runtime%>",
- global_options.x_flag_objc_abi);
+ if (TARGET_64BIT && global_options.x_flag_objc_abi != 2)
+ /* The Objective-C family ABI 2 is the only valid version NeXT/m64. */
+ error_at (UNKNOWN_LOCATION,
+ "%<-fobjc-abi-version%> 2 must be used for 64 bit targets"
+ " with %<-fnext-runtime%>");
+ else if (!TARGET_64BIT && global_options.x_flag_objc_abi >= 2)
+ /* ABI versions 0 and 1 are the only valid versions NeXT/m32. */
+ error_at (UNKNOWN_LOCATION,
+ "%<-fobjc-abi-version%> %d is not supported for 32 bit"
+ " targets with %<-fnext-runtime%>",
+ global_options.x_flag_objc_abi);
}
/* Don't emit DWARF3/4 unless specifically selected. This is a
diff --git a/gcc/config/darwin.h b/gcc/config/darwin.h
index 93dc638f8bb..f331fa1aa89 100644
--- a/gcc/config/darwin.h
+++ b/gcc/config/darwin.h
@@ -812,21 +812,52 @@ extern GTY(()) section * darwin_sections[NUM_DARWIN_SECTIONS];
#undef TARGET_ASM_MARK_DECL_PRESERVED
#define TARGET_ASM_MARK_DECL_PRESERVED darwin_mark_decl_preserved
-/* Set on a symbol with SYMBOL_FLAG_FUNCTION or
- MACHO_SYMBOL_FLAG_VARIABLE to indicate that the function or
- variable has been defined in this translation unit.
- When porting Mach-O to new architectures you need to make
- sure these aren't clobbered by the backend. */
+/* Any port using this header needs to define the first available
+ subtarget symbol bit: SYMBOL_FLAG_SUBT_DEP. */
-#define MACHO_SYMBOL_FLAG_VARIABLE (SYMBOL_FLAG_MACH_DEP)
-#define MACHO_SYMBOL_FLAG_DEFINED ((SYMBOL_FLAG_MACH_DEP) << 1)
+/* Is a variable. */
+#define MACHO_SYMBOL_FLAG_VARIABLE (SYMBOL_FLAG_SUBT_DEP)
+#define MACHO_SYMBOL_VARIABLE_P(RTX) \
+ ((SYMBOL_REF_FLAGS (RTX) & MACHO_SYMBOL_FLAG_VARIABLE) != 0)
+
+/* Set on a symbol that must be indirected, even when there is a
+ definition in the TU. The ABI mandates that common symbols are so
+ indirected, as are weak. If 'fix-and-continue' is operational then
+ data symbols might also be. */
+
+#define MACHO_SYMBOL_FLAG_MUST_INDIRECT ((SYMBOL_FLAG_SUBT_DEP) << 1)
+#define MACHO_SYMBOL_MUST_INDIRECT_P(RTX) \
+ ((SYMBOL_REF_FLAGS (RTX) & MACHO_SYMBOL_FLAG_MUST_INDIRECT) != 0)
+
+/* Set on a symbol with SYMBOL_FLAG_FUNCTION or MACHO_SYMBOL_FLAG_VARIABLE
+ to indicate that the function or variable is considered defined in this
+ translation unit. */
+
+#define MACHO_SYMBOL_FLAG_DEFINED ((SYMBOL_FLAG_SUBT_DEP) << 2)
+#define MACHO_SYMBOL_DEFINED_P(RTX) \
+ ((SYMBOL_REF_FLAGS (RTX) & MACHO_SYMBOL_FLAG_DEFINED) != 0)
+
+/* Set on a symbol that has specified non-default visibility. */
+
+#define MACHO_SYMBOL_FLAG_HIDDEN_VIS ((SYMBOL_FLAG_SUBT_DEP) << 3)
+#define MACHO_SYMBOL_HIDDEN_VIS_P(RTX) \
+ ((SYMBOL_REF_FLAGS (RTX) & MACHO_SYMBOL_FLAG_HIDDEN_VIS) != 0)
+
+/* Set on a symbol that is a pic stub or symbol indirection (i.e. the
+ L_xxxxx${stub,non_lazy_ptr,lazy_ptr}. */
+
+#define MACHO_SYMBOL_FLAG_INDIRECTION ((SYMBOL_FLAG_SUBT_DEP) << 5)
+#define MACHO_SYMBOL_INDIRECTION_P(RTX) \
+ ((SYMBOL_REF_FLAGS (RTX) & MACHO_SYMBOL_FLAG_INDIRECTION) != 0)
/* Set on a symbol to indicate when fix-and-continue style code
generation is being used and the symbol refers to a static symbol
that should be rebound from new instances of a translation unit to
the original instance of the data. */
-#define MACHO_SYMBOL_STATIC ((SYMBOL_FLAG_MACH_DEP) << 2)
+#define MACHO_SYMBOL_FLAG_STATIC ((SYMBOL_FLAG_SUBT_DEP) << 6)
+#define MACHO_SYMBOL_STATIC_P(RTX) \
+ ((SYMBOL_REF_FLAGS (RTX) & MACHO_SYMBOL_FLAG_STATIC) != 0)
/* Symbolic names for various things we might know about a symbol. */
diff --git a/gcc/config/i386/darwin.h b/gcc/config/i386/darwin.h
index 385d2536920..bdb36f00959 100644
--- a/gcc/config/i386/darwin.h
+++ b/gcc/config/i386/darwin.h
@@ -324,10 +324,8 @@ along with GCC; see the file COPYING3. If not see
} \
}
-/* This needs to move since i386 uses the first flag and other flags are
- used in Mach-O. */
-#undef MACHO_SYMBOL_FLAG_VARIABLE
-#define MACHO_SYMBOL_FLAG_VARIABLE ((SYMBOL_FLAG_MACH_DEP) << 3)
+/* First available SYMBOL flag bit for use by subtargets. */
+#define SYMBOL_FLAG_SUBT_DEP (SYMBOL_FLAG_MACH_DEP << 5)
#undef MACHOPIC_NL_SYMBOL_PTR_SECTION
#define MACHOPIC_NL_SYMBOL_PTR_SECTION \
diff --git a/gcc/config/i386/i386-expand.c b/gcc/config/i386/i386-expand.c
index 5e377d6dc5f..6d3d14c37dd 100644
--- a/gcc/config/i386/i386-expand.c
+++ b/gcc/config/i386/i386-expand.c
@@ -15903,71 +15903,8 @@ ix86_expand_rint (rtx operand0, rtx operand1)
emit_move_insn (operand0, res);
}
-/* Expand SSE2 sequence for computing floor or ceil from OPERAND1 storing
- into OPERAND0. */
-void
-ix86_expand_floorceildf_32 (rtx operand0, rtx operand1, bool do_floor)
-{
- /* C code for the stuff we expand below.
- double xa = fabs (x), x2;
- if (!isless (xa, TWO52))
- return x;
- xa = xa + TWO52 - TWO52;
- x2 = copysign (xa, x);
- Compensate. Floor:
- if (x2 > x)
- x2 -= 1;
- Compensate. Ceil:
- if (x2 < x)
- x2 += 1;
- if (HONOR_SIGNED_ZEROS (mode))
- x2 = copysign (x2, x);
- return x2;
- */
- machine_mode mode = GET_MODE (operand0);
- rtx xa, TWO52, tmp, one, res, mask;
- rtx_code_label *label;
-
- TWO52 = ix86_gen_TWO52 (mode);
-
- /* Temporary for holding the result, initialized to the input
- operand to ease control flow. */
- res = gen_reg_rtx (mode);
- emit_move_insn (res, operand1);
-
- /* xa = abs (operand1) */
- xa = ix86_expand_sse_fabs (res, &mask);
-
- /* if (!isless (xa, TWO52)) goto label; */
- label = ix86_expand_sse_compare_and_jump (UNLE, TWO52, xa, false);
-
- /* xa = xa + TWO52 - TWO52; */
- xa = expand_simple_binop (mode, PLUS, xa, TWO52, NULL_RTX, 0, OPTAB_DIRECT);
- xa = expand_simple_binop (mode, MINUS, xa, TWO52, xa, 0, OPTAB_DIRECT);
-
- /* xa = copysign (xa, operand1) */
- ix86_sse_copysign_to_positive (xa, xa, res, mask);
-
- /* generate 1.0 */
- one = force_reg (mode, const_double_from_real_value (dconst1, mode));
-
- /* Compensate: xa = xa - (xa > operand1 ? 1 : 0) */
- tmp = ix86_expand_sse_compare_mask (UNGT, xa, res, !do_floor);
- emit_insn (gen_rtx_SET (tmp, gen_rtx_AND (mode, one, tmp)));
- tmp = expand_simple_binop (mode, do_floor ? MINUS : PLUS,
- xa, tmp, NULL_RTX, 0, OPTAB_DIRECT);
- if (!do_floor && HONOR_SIGNED_ZEROS (mode))
- ix86_sse_copysign_to_positive (tmp, tmp, res, mask);
- emit_move_insn (res, tmp);
-
- emit_label (label);
- LABEL_NUSES (label) = 1;
-
- emit_move_insn (operand0, res);
-}
-
-/* Expand SSE2 sequence for computing floor or ceil from OPERAND1 storing
- into OPERAND0. */
+/* Expand SSE2 sequence for computing floor or ceil
+ from OPERAND1 storing into OPERAND0. */
void
ix86_expand_floorceil (rtx operand0, rtx operand1, bool do_floor)
{
@@ -16027,30 +15964,30 @@ ix86_expand_floorceil (rtx operand0, rtx operand1, bool do_floor)
emit_move_insn (operand0, res);
}
-/* Expand SSE sequence for computing round from OPERAND1 storing
- into OPERAND0. Sequence that works without relying on DImode truncation
- via cvttsd2siq that is only available on 64bit targets. */
+/* Expand SSE2 sequence for computing floor or ceil from OPERAND1 storing
+ into OPERAND0 without relying on DImode truncation via cvttsd2siq
+ that is only available on 64bit targets. */
void
-ix86_expand_rounddf_32 (rtx operand0, rtx operand1)
+ix86_expand_floorceildf_32 (rtx operand0, rtx operand1, bool do_floor)
{
/* C code for the stuff we expand below.
- double xa = fabs (x), xa2, x2;
+ double xa = fabs (x), x2;
if (!isless (xa, TWO52))
return x;
- Using the absolute value and copying back sign makes
- -0.0 -> -0.0 correct.
- xa2 = xa + TWO52 - TWO52;
- Compensate.
- dxa = xa2 - xa;
- if (dxa <= -0.5)
- xa2 += 1;
- else if (dxa > 0.5)
- xa2 -= 1;
- x2 = copysign (xa2, x);
- return x2;
+ xa = xa + TWO52 - TWO52;
+ x2 = copysign (xa, x);
+ Compensate. Floor:
+ if (x2 > x)
+ x2 -= 1;
+ Compensate. Ceil:
+ if (x2 < x)
+ x2 += 1;
+ if (HONOR_SIGNED_ZEROS (mode))
+ x2 = copysign (x2, x);
+ return x2;
*/
machine_mode mode = GET_MODE (operand0);
- rtx xa, xa2, dxa, TWO52, tmp, half, mhalf, one, res, mask;
+ rtx xa, TWO52, tmp, one, res, mask;
rtx_code_label *label;
TWO52 = ix86_gen_TWO52 (mode);
@@ -16066,31 +16003,24 @@ ix86_expand_rounddf_32 (rtx operand0, rtx operand1)
/* if (!isless (xa, TWO52)) goto label; */
label = ix86_expand_sse_compare_and_jump (UNLE, TWO52, xa, false);
- /* xa2 = xa + TWO52 - TWO52; */
- xa2 = expand_simple_binop (mode, PLUS, xa, TWO52, NULL_RTX, 0, OPTAB_DIRECT);
- xa2 = expand_simple_binop (mode, MINUS, xa2, TWO52, xa2, 0, OPTAB_DIRECT);
-
- /* dxa = xa2 - xa; */
- dxa = expand_simple_binop (mode, MINUS, xa2, xa, NULL_RTX, 0, OPTAB_DIRECT);
+ /* xa = xa + TWO52 - TWO52; */
+ xa = expand_simple_binop (mode, PLUS, xa, TWO52, NULL_RTX, 0, OPTAB_DIRECT);
+ xa = expand_simple_binop (mode, MINUS, xa, TWO52, xa, 0, OPTAB_DIRECT);
- /* generate 0.5, 1.0 and -0.5 */
- half = force_reg (mode, const_double_from_real_value (dconsthalf, mode));
- one = expand_simple_binop (mode, PLUS, half, half, NULL_RTX, 0, OPTAB_DIRECT);
- mhalf = expand_simple_binop (mode, MINUS, half, one, NULL_RTX,
- 0, OPTAB_DIRECT);
+ /* xa = copysign (xa, operand1) */
+ ix86_sse_copysign_to_positive (xa, xa, res, mask);
- /* Compensate. */
- /* xa2 = xa2 - (dxa > 0.5 ? 1 : 0) */
- tmp = ix86_expand_sse_compare_mask (UNGT, dxa, half, false);
- emit_insn (gen_rtx_SET (tmp, gen_rtx_AND (mode, tmp, one)));
- xa2 = expand_simple_binop (mode, MINUS, xa2, tmp, NULL_RTX, 0, OPTAB_DIRECT);
- /* xa2 = xa2 + (dxa <= -0.5 ? 1 : 0) */
- tmp = ix86_expand_sse_compare_mask (UNGE, mhalf, dxa, false);
- emit_insn (gen_rtx_SET (tmp, gen_rtx_AND (mode, tmp, one)));
- xa2 = expand_simple_binop (mode, PLUS, xa2, tmp, NULL_RTX, 0, OPTAB_DIRECT);
+ /* generate 1.0 */
+ one = force_reg (mode, const_double_from_real_value (dconst1, mode));
- /* res = copysign (xa2, operand1) */
- ix86_sse_copysign_to_positive (res, xa2, force_reg (mode, operand1), mask);
+ /* Compensate: xa = xa - (xa > operand1 ? 1 : 0) */
+ tmp = ix86_expand_sse_compare_mask (UNGT, xa, res, !do_floor);
+ emit_insn (gen_rtx_SET (tmp, gen_rtx_AND (mode, one, tmp)));
+ tmp = expand_simple_binop (mode, do_floor ? MINUS : PLUS,
+ xa, tmp, NULL_RTX, 0, OPTAB_DIRECT);
+ if (!do_floor && HONOR_SIGNED_ZEROS (mode))
+ ix86_sse_copysign_to_positive (tmp, tmp, res, mask);
+ emit_move_insn (res, tmp);
emit_label (label);
LABEL_NUSES (label) = 1;
@@ -16098,8 +16028,8 @@ ix86_expand_rounddf_32 (rtx operand0, rtx operand1)
emit_move_insn (operand0, res);
}
-/* Expand SSE sequence for computing trunc from OPERAND1 storing
- into OPERAND0. */
+/* Expand SSE sequence for computing trunc
+ from OPERAND1 storing into OPERAND0. */
void
ix86_expand_trunc (rtx operand0, rtx operand1)
{
@@ -16144,7 +16074,8 @@ ix86_expand_trunc (rtx operand0, rtx operand1)
}
/* Expand SSE sequence for computing trunc from OPERAND1 storing
- into OPERAND0. */
+ into OPERAND0 without relying on DImode truncation via cvttsd2siq
+ that is only available on 64bit targets. */
void
ix86_expand_truncdf_32 (rtx operand0, rtx operand1)
{
@@ -16201,8 +16132,8 @@ ix86_expand_truncdf_32 (rtx operand0, rtx operand1)
emit_move_insn (operand0, res);
}
-/* Expand SSE sequence for computing round from OPERAND1 storing
- into OPERAND0. */
+/* Expand SSE sequence for computing round
+ from OPERAND1 storing into OPERAND0. */
void
ix86_expand_round (rtx operand0, rtx operand1)
{
@@ -16251,6 +16182,77 @@ ix86_expand_round (rtx operand0, rtx operand1)
emit_move_insn (operand0, res);
}
+/* Expand SSE sequence for computing round from OPERAND1 storing
+ into OPERAND0 without relying on DImode truncation via cvttsd2siq
+ that is only available on 64bit targets. */
+void
+ix86_expand_rounddf_32 (rtx operand0, rtx operand1)
+{
+ /* C code for the stuff we expand below.
+ double xa = fabs (x), xa2, x2;
+ if (!isless (xa, TWO52))
+ return x;
+ Using the absolute value and copying back sign makes
+ -0.0 -> -0.0 correct.
+ xa2 = xa + TWO52 - TWO52;
+ Compensate.
+ dxa = xa2 - xa;
+ if (dxa <= -0.5)
+ xa2 += 1;
+ else if (dxa > 0.5)
+ xa2 -= 1;
+ x2 = copysign (xa2, x);
+ return x2;
+ */
+ machine_mode mode = GET_MODE (operand0);
+ rtx xa, xa2, dxa, TWO52, tmp, half, mhalf, one, res, mask;
+ rtx_code_label *label;
+
+ TWO52 = ix86_gen_TWO52 (mode);
+
+ /* Temporary for holding the result, initialized to the input
+ operand to ease control flow. */
+ res = gen_reg_rtx (mode);
+ emit_move_insn (res, operand1);
+
+ /* xa = abs (operand1) */
+ xa = ix86_expand_sse_fabs (res, &mask);
+
+ /* if (!isless (xa, TWO52)) goto label; */
+ label = ix86_expand_sse_compare_and_jump (UNLE, TWO52, xa, false);
+
+ /* xa2 = xa + TWO52 - TWO52; */
+ xa2 = expand_simple_binop (mode, PLUS, xa, TWO52, NULL_RTX, 0, OPTAB_DIRECT);
+ xa2 = expand_simple_binop (mode, MINUS, xa2, TWO52, xa2, 0, OPTAB_DIRECT);
+
+ /* dxa = xa2 - xa; */
+ dxa = expand_simple_binop (mode, MINUS, xa2, xa, NULL_RTX, 0, OPTAB_DIRECT);
+
+ /* generate 0.5, 1.0 and -0.5 */
+ half = force_reg (mode, const_double_from_real_value (dconsthalf, mode));
+ one = expand_simple_binop (mode, PLUS, half, half, NULL_RTX, 0, OPTAB_DIRECT);
+ mhalf = expand_simple_binop (mode, MINUS, half, one, NULL_RTX,
+ 0, OPTAB_DIRECT);
+
+ /* Compensate. */
+ /* xa2 = xa2 - (dxa > 0.5 ? 1 : 0) */
+ tmp = ix86_expand_sse_compare_mask (UNGT, dxa, half, false);
+ emit_insn (gen_rtx_SET (tmp, gen_rtx_AND (mode, tmp, one)));
+ xa2 = expand_simple_binop (mode, MINUS, xa2, tmp, NULL_RTX, 0, OPTAB_DIRECT);
+ /* xa2 = xa2 + (dxa <= -0.5 ? 1 : 0) */
+ tmp = ix86_expand_sse_compare_mask (UNGE, mhalf, dxa, false);
+ emit_insn (gen_rtx_SET (tmp, gen_rtx_AND (mode, tmp, one)));
+ xa2 = expand_simple_binop (mode, PLUS, xa2, tmp, NULL_RTX, 0, OPTAB_DIRECT);
+
+ /* res = copysign (xa2, operand1) */
+ ix86_sse_copysign_to_positive (res, xa2, force_reg (mode, operand1), mask);
+
+ emit_label (label);
+ LABEL_NUSES (label) = 1;
+
+ emit_move_insn (operand0, res);
+}
+
/* Expand SSE sequence for computing round
from OP1 storing into OP0 using sse4 round insn. */
void
diff --git a/gcc/config/i386/i386-features.c b/gcc/config/i386/i386-features.c
index 9b297bac191..4781a33a545 100644
--- a/gcc/config/i386/i386-features.c
+++ b/gcc/config/i386/i386-features.c
@@ -1757,6 +1757,68 @@ convert_scalars_to_vector (bool timode_p)
return 0;
}
+/* Modify the vzeroupper pattern in INSN so that it describes the effect
+ that the instruction has on the SSE registers. LIVE_REGS are the set
+ of registers that are live across the instruction.
+
+ For a live register R we use:
+
+ (set (reg:V2DF R) (reg:V2DF R))
+
+ which preserves the low 128 bits but clobbers the upper bits.
+ For a dead register we just use:
+
+ (clobber (reg:V2DF R))
+
+ which invalidates any previous contents of R and stops R from becoming
+ live across the vzeroupper in future. */
+
+static void
+ix86_add_reg_usage_to_vzeroupper (rtx_insn *insn, bitmap live_regs)
+{
+ rtx pattern = PATTERN (insn);
+ unsigned int nregs = TARGET_64BIT ? 16 : 8;
+ rtvec vec = rtvec_alloc (nregs + 1);
+ RTVEC_ELT (vec, 0) = XVECEXP (pattern, 0, 0);
+ for (unsigned int i = 0; i < nregs; ++i)
+ {
+ unsigned int regno = GET_SSE_REGNO (i);
+ rtx reg = gen_rtx_REG (V2DImode, regno);
+ if (bitmap_bit_p (live_regs, regno))
+ RTVEC_ELT (vec, i + 1) = gen_rtx_SET (reg, reg);
+ else
+ RTVEC_ELT (vec, i + 1) = gen_rtx_CLOBBER (VOIDmode, reg);
+ }
+ XVEC (pattern, 0) = vec;
+ df_insn_rescan (insn);
+}
+
+/* Walk the vzeroupper instructions in the function and annotate them
+ with the effect that they have on the SSE registers. */
+
+static void
+ix86_add_reg_usage_to_vzerouppers (void)
+{
+ basic_block bb;
+ rtx_insn *insn;
+ auto_bitmap live_regs;
+
+ df_analyze ();
+ FOR_EACH_BB_FN (bb, cfun)
+ {
+ bitmap_copy (live_regs, df_get_live_out (bb));
+ df_simulate_initialize_backwards (bb, live_regs);
+ FOR_BB_INSNS_REVERSE (bb, insn)
+ {
+ if (!NONDEBUG_INSN_P (insn))
+ continue;
+ if (vzeroupper_pattern (PATTERN (insn), VOIDmode))
+ ix86_add_reg_usage_to_vzeroupper (insn, live_regs);
+ df_simulate_one_insn_backwards (bb, insn, live_regs);
+ }
+ }
+}
+
static unsigned int
rest_of_handle_insert_vzeroupper (void)
{
@@ -1773,6 +1835,7 @@ rest_of_handle_insert_vzeroupper (void)
/* Call optimize_mode_switching. */
g->get_passes ()->execute_pass_mode_switching ();
+ ix86_add_reg_usage_to_vzerouppers ();
return 0;
}
diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
index 4d6e76d5580..c07dfe50855 100644
--- a/gcc/config/i386/i386-protos.h
+++ b/gcc/config/i386/i386-protos.h
@@ -193,11 +193,11 @@ extern void ix86_expand_lfloorceil (rtx, rtx, bool);
extern void ix86_expand_rint (rtx, rtx);
extern void ix86_expand_floorceil (rtx, rtx, bool);
extern void ix86_expand_floorceildf_32 (rtx, rtx, bool);
-extern void ix86_expand_round_sse4 (rtx, rtx);
-extern void ix86_expand_round (rtx, rtx);
-extern void ix86_expand_rounddf_32 (rtx, rtx);
extern void ix86_expand_trunc (rtx, rtx);
extern void ix86_expand_truncdf_32 (rtx, rtx);
+extern void ix86_expand_round (rtx, rtx);
+extern void ix86_expand_rounddf_32 (rtx, rtx);
+extern void ix86_expand_round_sse4 (rtx, rtx);
extern void ix86_expand_vecop_qihi (enum rtx_code, rtx, rtx, rtx);
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 083e2280d00..1a272d99451 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -13530,7 +13530,7 @@ ix86_avx_u128_mode_needed (rtx_insn *insn)
modes wider than 256 bits. It's only safe to issue a
vzeroupper if all SSE registers are clobbered. */
const function_abi &abi = insn_callee_abi (insn);
- if (!hard_reg_set_subset_p (reg_class_contents[ALL_SSE_REGS],
+ if (!hard_reg_set_subset_p (reg_class_contents[SSE_REGS],
abi.mode_clobbers (V4DImode)))
return AVX_U128_ANY;
diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md
index 72f8e7eae3c..31f1ceabc3a 100644
--- a/gcc/config/i386/predicates.md
+++ b/gcc/config/i386/predicates.md
@@ -1441,8 +1441,9 @@
;; return true if OP is a vzeroupper pattern.
(define_predicate "vzeroupper_pattern"
- (and (match_code "unspec_volatile")
- (match_test "XINT (op, 1) == UNSPECV_VZEROUPPER")))
+ (and (match_code "parallel")
+ (match_code "unspec_volatile" "a")
+ (match_test "XINT (XVECEXP (op, 0, 0), 1) == UNSPECV_VZEROUPPER")))
;; Return true if OP is an addsub vec_merge operation
(define_predicate "addsub_vm_operator"
diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md
index c7f539fb88f..07922a1bf97 100644
--- a/gcc/config/i386/sse.md
+++ b/gcc/config/i386/sse.md
@@ -19622,9 +19622,16 @@
(set_attr "mode" "OI")])
;; Clear the upper 128bits of AVX registers, equivalent to a NOP
-;; if the upper 128bits are unused.
-(define_insn "avx_vzeroupper"
- [(unspec_volatile [(const_int 0)] UNSPECV_VZEROUPPER)]
+;; if the upper 128bits are unused. Initially we expand the instructions
+;; as though they had no effect on the SSE registers, but later add SETs and
+;; CLOBBERs to the PARALLEL to model the real effect.
+(define_expand "avx_vzeroupper"
+ [(parallel [(unspec_volatile [(const_int 0)] UNSPECV_VZEROUPPER)])]
+ "TARGET_AVX")
+
+(define_insn "*avx_vzeroupper"
+ [(match_parallel 0 "vzeroupper_pattern"
+ [(unspec_volatile [(const_int 0)] UNSPECV_VZEROUPPER)])]
"TARGET_AVX"
"vzeroupper"
[(set_attr "type" "sse")
diff --git a/gcc/config/msp430/constraints.md b/gcc/config/msp430/constraints.md
index 7ef249d4ac2..4422b2b6454 100644
--- a/gcc/config/msp430/constraints.md
+++ b/gcc/config/msp430/constraints.md
@@ -69,9 +69,11 @@
;; These are memory references that are safe to use without the X suffix,
-;; because we know/assume they need not index across the 64k boundary.
+;; because we know/assume they need not index across the 64K boundary.
+;; Note that for a PSImode memory operand, we always need to use the X suffix,
+;; regardless of what this constraint decides.
(define_constraint "Ys"
- "Memory reference, stack only."
+ "Memory reference, indexed or indirect register addressing modes."
(and (match_code "mem")
(ior
(and (match_code "plus" "0")
@@ -93,3 +95,7 @@
(match_test ("REGNO (XEXP (XEXP (op, 0), 0)) != SP_REGNO")))
))))
+(define_constraint "Yx"
+ "Memory reference, in lower memory below address 0x10000."
+ (and (match_code "mem")
+ (match_test "msp430_op_not_in_high_mem (op)")))
diff --git a/gcc/config/msp430/driver-msp430.c b/gcc/config/msp430/driver-msp430.c
index 0a3d1e14c0a..c37b169ff8b 100644
--- a/gcc/config/msp430/driver-msp430.c
+++ b/gcc/config/msp430/driver-msp430.c
@@ -149,3 +149,16 @@ msp430_select_hwmult_lib (int argc ATTRIBUTE_UNUSED,
return "-lmul_none";
}
+
+/* Spec function. Propagate -m{code,data}-region= to the linker, unless the
+ lower region has been specified without -muse-lower-region-prefix also being
+ used. */
+const char *
+msp430_propagate_region_opt (int argc, const char **argv)
+{
+ if (strcmp (argv[0], "lower") != 0)
+ return argv[0];
+ else if ((argc == 2) && (strcmp (argv[1], "-muse-lower-region-prefix") == 0))
+ return argv[0]; /* argv[0] == "lower". */
+ return "none";
+}
diff --git a/gcc/config/msp430/msp430-protos.h b/gcc/config/msp430/msp430-protos.h
index 267b6f59471..37ca48297ac 100644
--- a/gcc/config/msp430/msp430-protos.h
+++ b/gcc/config/msp430/msp430-protos.h
@@ -44,8 +44,10 @@ void msp430_output_labelref (FILE *, const char *);
void msp430_register_pragmas (void);
rtx msp430_return_addr_rtx (int);
void msp430_split_movsi (rtx *);
+int msp430_split_addsi (rtx *);
void msp430_start_function (FILE *, const char *, tree);
rtx msp430_subreg (machine_mode, rtx, machine_mode, int);
bool msp430_use_f5_series_hwmult (void);
+bool msp430_op_not_in_high_mem (rtx op);
#endif /* GCC_MSP430_PROTOS_H */
diff --git a/gcc/config/msp430/msp430.c b/gcc/config/msp430/msp430.c
index 64308239593..ae763faada3 100644
--- a/gcc/config/msp430/msp430.c
+++ b/gcc/config/msp430/msp430.c
@@ -35,6 +35,7 @@
#include "tm_p.h"
#include "regs.h"
#include "emit-rtl.h"
+#include "varasm.h"
#include "diagnostic-core.h"
#include "fold-const.h"
#include "stor-layout.h"
@@ -82,7 +83,7 @@ struct GTY(()) machine_function
};
/* This is our init_machine_status, as set in
- msp_option_override. */
+ msp430_option_override. */
static struct machine_function *
msp430_init_machine_status (void)
{
@@ -263,9 +264,6 @@ msp430_option_override (void)
else if (!TARGET_LARGE && msp430_code_region == MSP430_REGION_UPPER)
error ("%<-mcode-region=upper%> requires the large memory model "
"(%<-mlarge%>)");
- else if (!TARGET_LARGE && msp430_code_region == MSP430_REGION_LOWER)
- error ("%<-mcode-region=lower%> requires the large memory model "
- "(%<-mlarge%>)");
if (!TARGET_LARGE && msp430_data_region == MSP430_REGION_EITHER)
error ("%<-mdata-region=either%> requires the large memory model "
@@ -273,10 +271,6 @@ msp430_option_override (void)
else if (!TARGET_LARGE && msp430_data_region == MSP430_REGION_UPPER)
error ("%<-mdata-region=upper%> requires the large memory model "
"(%<-mlarge%>)");
- else if (!TARGET_LARGE && msp430_data_region == MSP430_REGION_LOWER)
- error ("%<-mdata-region=lower%> requires the large memory model "
- "(%<-mlarge%>)");
-
if (flag_exceptions || flag_non_call_exceptions
|| flag_unwind_tables || flag_asynchronous_unwind_tables)
@@ -1386,7 +1380,7 @@ msp430_section_attr (tree * node,
if (has_attr (ATTR_NOINIT, *node))
message = G_("ignoring attribute %qE because it conflicts with "
"attribute %<noinit%>");
- else if (has_attr ("section", *node))
+ else if (has_attr ("section", *node) && !TREE_NAME_EQ (name, "lower"))
message = G_("ignoring attribute %qE because it conflicts with "
"attribute %<section%>");
/* It does not make sense to use upper/lower/either attributes without
@@ -1564,12 +1558,14 @@ msp430_handle_generic_attribute (tree *node,
{
const char *message = NULL;
+ /* The front end has set up an exclusion between the "noinit" and "section"
+ attributes. */
if (!(TREE_NAME_EQ (name, ATTR_NOINIT) || TREE_NAME_EQ (name, "section")))
return NULL_TREE;
- /* The front end has set up an exclusion between the "noinit" and "section"
- attributes. */
- if (has_attr (ATTR_LOWER, *node))
+ /* We allow the "lower" attribute to be used on variables with the "section"
+ attribute. */
+ if (has_attr (ATTR_LOWER, *node) && !TREE_NAME_EQ (name, "section"))
message = G_("ignoring attribute %qE because it conflicts with "
"attribute %<lower%>");
else if (has_attr (ATTR_UPPER, *node))
@@ -1591,6 +1587,55 @@ msp430_handle_generic_attribute (tree *node,
return NULL_TREE;
}
+/* Given a non-automatic VAR_DECL which can possibly have a section, return
+ true if the variable will definitely be placed in the lower memory
+ region (below address 0x10000). */
+static bool
+msp430_var_in_low_mem (tree decl)
+{
+ gcc_assert (VAR_P (decl));
+
+ /* "noinit" variables are always placed in the lower memory region. */
+ if (has_attr (ATTR_UPPER, decl)
+ || has_attr (ATTR_EITHER, decl)
+ || has_attr (ATTR_PERSIST, decl)
+ /* Unless the variable is marked with the lower or noinit attribute, we
+ cannot assume that it is in the lower region if it is marked with the
+ section attribute or -mdata-region={upper,either,none} have been
+ passed.
+ The noinit and section attributes conflict. */
+ || (!has_attr (ATTR_LOWER, decl) && !has_attr (ATTR_NOINIT, decl)
+ && (has_attr ("section", decl)
+ || msp430_data_region == MSP430_REGION_UPPER
+ || msp430_data_region == MSP430_REGION_EITHER
+ || msp430_data_region == MSP430_REGION_ANY)))
+ return false;
+ return true;
+}
+
+#undef TARGET_ENCODE_SECTION_INFO
+#define TARGET_ENCODE_SECTION_INFO msp430_encode_section_info
+
+/* Encode whether a SYMBOL_REF is definitely in the lower memory region. */
+static void
+msp430_encode_section_info (tree decl, rtx rtl, int first)
+{
+ rtx symbol;
+ default_encode_section_info (decl, rtl, first);
+
+ /* Careful not to prod global register variables. */
+ if (!MEM_P (rtl))
+ return;
+ symbol = XEXP (rtl, 0);
+ if (GET_CODE (symbol) != SYMBOL_REF)
+ return;
+
+ if (VAR_P (decl)
+ && (TREE_STATIC (decl) || DECL_EXTERNAL (decl))
+ && msp430_var_in_low_mem (decl))
+ SYMBOL_REF_FLAGS (symbol) = SYMBOL_FLAG_LOW_MEM;
+}
+
#undef TARGET_ASM_FUNCTION_PROLOGUE
#define TARGET_ASM_FUNCTION_PROLOGUE msp430_start_function
@@ -1744,15 +1789,17 @@ gen_prefix (tree decl)
if (has_section_name (".lowtext", decl))
return NULL;
- /* If the object has __attribute__((lower)) then use the ".lower." prefix. */
+ /* Memory regions require the large memory model. */
+ if (!TARGET_LARGE)
+ return NULL;
+
+ /* Note that we always apply the lower prefix when the attribute has been
+ used. But we only apply the lower prefix when the lower region has been
+ specified by a command line option if -muse-lower-region-prefix has also
+ been passed. */
if (has_attr (ATTR_LOWER, decl))
return lower_prefix;
- /* If we are compiling for the MSP430 then we do not support the upper
- region. */
- if (! msp430x)
- return NULL;
-
if (has_attr (ATTR_UPPER, decl))
return upper_prefix;
@@ -1761,7 +1808,8 @@ gen_prefix (tree decl)
if (TREE_CODE (decl) == FUNCTION_DECL)
{
- if (msp430_code_region == MSP430_REGION_LOWER)
+ if ((msp430_code_region == MSP430_REGION_LOWER)
+ && TARGET_USE_LOWER_REGION_PREFIX)
return lower_prefix;
if (msp430_code_region == MSP430_REGION_UPPER)
@@ -1772,7 +1820,8 @@ gen_prefix (tree decl)
}
else
{
- if (msp430_data_region == MSP430_REGION_LOWER)
+ if ((msp430_data_region == MSP430_REGION_LOWER)
+ && TARGET_USE_LOWER_REGION_PREFIX)
return lower_prefix;
if (msp430_data_region == MSP430_REGION_UPPER)
@@ -1966,7 +2015,6 @@ msp430_unique_section (tree decl, int reloc)
/* Emit a declaration of a common symbol.
If a data region is in use then put the symbol into the
equivalent .bss section instead. */
-
void
msp430_output_aligned_decl_common (FILE * stream,
const tree decl,
@@ -1976,7 +2024,9 @@ msp430_output_aligned_decl_common (FILE * stream,
{
/* Only emit a common symbol if the variable does not have a specific section
assigned. */
- if (msp430_data_region == MSP430_REGION_ANY
+ if ((msp430_data_region == MSP430_REGION_ANY
+ || ((msp430_data_region == MSP430_REGION_LOWER)
+ && !TARGET_USE_LOWER_REGION_PREFIX))
&& !(decl != NULL_TREE && DECL_SECTION_NAME (decl))
&& !has_attr (ATTR_EITHER, decl)
&& !has_attr (ATTR_LOWER, decl)
@@ -2021,6 +2071,80 @@ msp430_output_aligned_decl_common (FILE * stream,
}
}
+#undef TARGET_ASM_FILE_END
+#define TARGET_ASM_FILE_END msp430_file_end
+
+/* Emit MSPABI and GNU object attributes.
+ Tags and values for MSPABI attributes are:
+ OFBA_MSPABI_Tag_ISA 4
+ MSP430 1
+ MSP430X 2
+ OFBA_MSPABI_Tag_Code_Model 6
+ Small 1
+ Large 2
+ OFBA_MSPABI_Tag_Data_Model 8
+ Small 1
+ Large 2
+ Restricted 3 (Unused by GNU)
+ OFBA_MSPABI_Tag_enum_size 10 (Unused by GNU)
+ Note that Code_Model and Data_Model are always equal for GNU.
+ We define a new .gnu_attribute to keep track of the data region used.
+ Tag_GNU_MSP430_Data_Region 4
+ LOWER 1
+ ANY 2
+ See binutils-gdb/include/elf/msp430.h for the full details. */
+static void
+msp430_file_end (void)
+{
+#ifdef HAVE_AS_GNU_ATTRIBUTE
+ /* Enum for tag names. */
+ enum
+ {
+ OFBA_MSPABI_Tag_ISA = 4,
+ OFBA_MSPABI_Tag_Code_Model = 6,
+ OFBA_MSPABI_Tag_Data_Model = 8,
+ Tag_GNU_MSP430_Data_Region = 4
+ };
+ /* Enum for tag values. */
+ enum
+ {
+ OFBA_MSPABI_Val_ISA_MSP430 = 1,
+ OFBA_MSPABI_Val_ISA_MSP430X = 2,
+ OFBA_MSPABI_Val_Model_Small = 1,
+ OFBA_MSPABI_Val_Model_Large = 2,
+ Tag_GNU_MSP430_Data_Region_Lower = 1,
+ Tag_GNU_MSP430_Data_Region_Any = 2
+ };
+ /* .mspabi_attribute is a GNU assembler directive only. The assembler will
+ construct a .MSP430.attributes section based on the options it is invoked
+ with. The values it reads from these directives are used for validating
+ those options. */
+ const char *msp430_attr = ".mspabi_attribute";
+ const char *gnu_attr = ".gnu_attribute";
+
+ /* Emit .mspabi_attribute directive for OFBA_MSPABI_Tag_ISA. */
+ fprintf (asm_out_file, "\t%s %d, %d\n", msp430_attr, OFBA_MSPABI_Tag_ISA,
+ msp430x ? OFBA_MSPABI_Val_ISA_MSP430X : OFBA_MSPABI_Val_ISA_MSP430);
+ /* Emit .mspabi_attribute directive for OFBA_MSPABI_Tag_Code_Model. */
+ fprintf (asm_out_file, "\t%s %d, %d\n", msp430_attr,
+ OFBA_MSPABI_Tag_Code_Model,
+ TARGET_LARGE ? OFBA_MSPABI_Val_Model_Large
+ : OFBA_MSPABI_Val_Model_Small);
+ /* Emit .mspabi_attribute directive for OFBA_MSPABI_Tag_Data_Model. */
+ fprintf (asm_out_file, "\t%s %d, %d\n", msp430_attr,
+ OFBA_MSPABI_Tag_Data_Model,
+ TARGET_LARGE ? OFBA_MSPABI_Val_Model_Large
+ : OFBA_MSPABI_Val_Model_Small);
+#ifdef HAVE_AS_MSPABI_ATTRIBUTE
+ /* Emit .gnu_attribute directive for Tag_GNU_MSP430_Data_Region. */
+ fprintf (asm_out_file, "\t%s %d, %d\n", gnu_attr, Tag_GNU_MSP430_Data_Region,
+ msp430_data_region == MSP430_REGION_LOWER
+ ? Tag_GNU_MSP430_Data_Region_Lower
+ : Tag_GNU_MSP430_Data_Region_Any);
+#endif
+#endif
+}
+
bool
msp430_do_not_relax_short_jumps (void)
{
@@ -2031,9 +2155,7 @@ msp430_do_not_relax_short_jumps (void)
end up in a low section. */
return
msp430_code_region == MSP430_REGION_EITHER
- || msp430_code_region == MSP430_REGION_LOWER
- || has_attr (ATTR_EITHER, current_function_decl)
- || has_attr (ATTR_LOWER, current_function_decl);
+ || has_attr (ATTR_EITHER, current_function_decl);
}
enum msp430_builtin
@@ -2484,7 +2606,7 @@ msp430_expand_epilogue (int is_eh)
else if (is_reentrant_func ())
emit_insn (gen_enable_interrupts ());
- emit_jump_insn (gen_msp_return ());
+ emit_jump_insn (gen_msp430_return ());
}
/* Implements EH_RETURN_STACKADJ_RTX. Saved and used later in
@@ -2721,6 +2843,29 @@ msp430_subreg (machine_mode mode, rtx r, machine_mode omode, int byte)
return rv;
}
+int
+msp430_split_addsi (rtx *operands)
+{
+ operands[3] = msp430_subreg (HImode, operands[0], SImode, 0);
+ operands[4] = msp430_subreg (HImode, operands[1], SImode, 0);
+ operands[5] = msp430_subreg (HImode, operands[2], SImode, 0);
+ operands[6] = msp430_subreg (HImode, operands[0], SImode, 2);
+ operands[7] = msp430_subreg (HImode, operands[1], SImode, 2);
+ operands[8] = msp430_subreg (HImode, operands[2], SImode, 2);
+
+ /* BZ 64160: Do not use this splitter when the dest partially overlaps the
+ source. */
+ if (reg_overlap_mentioned_p (operands[3], operands[7])
+ || reg_overlap_mentioned_p (operands[3], operands[8]))
+ return 1;
+
+ if (GET_CODE (operands[5]) == CONST_INT)
+ operands[9] = GEN_INT (INTVAL (operands[5]) & 0xffff);
+ else
+ operands[9] = gen_rtx_ZERO_EXTEND (SImode, operands[5]);
+ return 0;
+}
+
/* Called by movsi_x to generate the HImode operands. */
void
msp430_split_movsi (rtx *operands)
@@ -3074,6 +3219,36 @@ msp430_print_operand_addr (FILE * file, machine_mode /*mode*/, rtx addr)
msp430_print_operand_raw (file, addr);
}
+/* Determine whether an RTX is definitely not a MEM referencing an address in
+ the upper memory region. Returns true if we've decided the address will be
+ in the lower memory region, or the RTX is not a MEM. Returns false
+ otherwise. */
+bool
+msp430_op_not_in_high_mem (rtx op)
+{
+ rtx op0;
+
+ if (!TARGET_LARGE || !MEM_P (op))
+ return true;
+
+ op0 = XEXP (op, 0);
+
+ if (SYMBOL_REF_P (op0) && (SYMBOL_REF_FLAGS (op0) & SYMBOL_FLAG_LOW_MEM))
+ /* msp430_encode_section_info decided this mem will be in lower
+ memory. */
+ return true;
+
+ /* Catch (mem (const (plus ((symbol_ref) (const_int))))) e.g. &addr+2. */
+ if ((GET_CODE (op0) == CONST)
+ && (GET_CODE (XEXP (op0, 0)) == PLUS)
+ && (SYMBOL_REF_P (XEXP (XEXP (op0, 0), 0)))
+ && (SYMBOL_REF_FLAGS (XEXP (XEXP (op0, 0), 0)) & SYMBOL_FLAG_LOW_MEM))
+ return true;
+
+ /* Return false when undecided. */
+ return false;
+}
+
#undef TARGET_PRINT_OPERAND
#define TARGET_PRINT_OPERAND msp430_print_operand
@@ -3245,15 +3420,21 @@ msp430_print_operand (FILE * file, rtx op, int letter)
case 'X':
/* This is used to turn, for example, an ADD opcode into an ADDX
- opcode when we're using 20-bit addresses. */
- if (TARGET_LARGE || GET_MODE (op) == PSImode)
+ opcode when we're using 20-bit addresses.
+ This can be used for insns which have only one operand which might be
+ a mem.
+ If an insn has two different operands which could be memory operands,
+ then the "Yx" constraint must be used to determine if the X suffix is
+ required by checking both operands. */
+ if (GET_MODE (op) == PSImode
+ || !msp430_op_not_in_high_mem (op))
fprintf (file, "X");
- /* We don't care which operand we use, but we want 'X' in the MD
- file, so we do it this way. */
return;
case 'x':
- /* Similarly, but only for PSImodes. BIC, for example, needs this. */
+ /* Similarly, but only for PSImodes. BIC, and other insn patterns using
+ the QHI mode iterator (which includes, QI, HI, and PSImode) use
+ this. */
if (GET_MODE (op) == PSImode)
fprintf (file, "X");
return;
diff --git a/gcc/config/msp430/msp430.h b/gcc/config/msp430/msp430.h
index 3449bd429ae..f885de2bb2f 100644
--- a/gcc/config/msp430/msp430.h
+++ b/gcc/config/msp430/msp430.h
@@ -71,7 +71,10 @@ extern bool msp430x;
is enabled (the GDB testsuite relies upon unused entities not being
deleted). */
#define LINK_SPEC "%{mrelax:--relax} %{mlarge:%{!r:%{!g:--gc-sections}}} " \
- "%{mcode-region=*:--code-region=%*} %{mdata-region=*:--data-region=%*}"
+ "%{mcode-region=*:--code-region=%:" \
+ "msp430_propagate_region_opt(%* %{muse-lower-region-prefix})} " \
+ "%{mdata-region=*:--data-region=%:" \
+ "msp430_propagate_region_opt(%* %{muse-lower-region-prefix})} " \
#define DRIVER_SELF_SPECS \
" %{!mlarge:%{mcode-region=*:%{mdata-region=*:%e-mcode-region and " \
@@ -90,12 +93,16 @@ extern const char * msp430_select_hwmult_lib (int, const char **);
extern const char * msp430_select_cpu (int, const char **);
extern const char * msp430_set_driver_var (int, const char **);
extern const char * msp430_check_path_for_devices (int, const char **);
+extern const char *msp430_propagate_region_opt (int, const char **);
+/* There must be a trailing comma after the last item, see gcc.c
+ "static_spec_functions". */
# define EXTRA_SPEC_FUNCTIONS \
{ "msp430_hwmult_lib", msp430_select_hwmult_lib }, \
{ "msp430_select_cpu", msp430_select_cpu }, \
{ "msp430_set_driver_var", msp430_set_driver_var }, \
- { "msp430_check_path_for_devices", msp430_check_path_for_devices },
+ { "msp430_check_path_for_devices", msp430_check_path_for_devices }, \
+ { "msp430_propagate_region_opt", msp430_propagate_region_opt },
/* Specify the libraries to include on the linker command line.
@@ -482,3 +489,5 @@ typedef struct
#define ASM_OUTPUT_ALIGNED_DECL_COMMON(FILE, DECL, NAME, SIZE, ALIGN) \
msp430_output_aligned_decl_common ((FILE), (DECL), (NAME), (SIZE), (ALIGN))
+
+#define SYMBOL_FLAG_LOW_MEM (SYMBOL_FLAG_MACH_DEP << 0)
diff --git a/gcc/config/msp430/msp430.md b/gcc/config/msp430/msp430.md
index f6d688950cb..ebd9c85fbb6 100644
--- a/gcc/config/msp430/msp430.md
+++ b/gcc/config/msp430/msp430.md
@@ -183,29 +183,29 @@
)
(define_insn "movqi_topbyte"
- [(set (match_operand:QI 0 "msp_nonimmediate_operand" "=r")
- (subreg:QI (match_operand:PSI 1 "msp_general_operand" "r") 2))]
+ [(set (match_operand:QI 0 "msp430_nonimmediate_operand" "=r")
+ (subreg:QI (match_operand:PSI 1 "msp430_general_operand" "r") 2))]
"msp430x"
"PUSHM.A\t#1,%1 { POPM.W\t#1,%0 { POPM.W\t#1,%0"
)
(define_insn "movqi"
- [(set (match_operand:QI 0 "msp_nonimmediate_operand" "=rYs,rm")
- (match_operand:QI 1 "msp_general_operand" "riYs,rmi"))]
+ [(set (match_operand:QI 0 "msp430_nonimmediate_operand" "=rYsYx,rm")
+ (match_operand:QI 1 "msp430_general_operand" "riYsYx,rmi"))]
""
"@
MOV.B\t%1, %0
- MOV%X0.B\t%1, %0"
+ MOVX.B\t%1, %0"
)
(define_insn "movhi"
- [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=r,rYs,rm")
- (match_operand:HI 1 "msp_general_operand" "N,riYs,rmi"))]
+ [(set (match_operand:HI 0 "msp430_nonimmediate_operand" "=r,rYsYx,rm")
+ (match_operand:HI 1 "msp430_general_operand" "N,riYsYx,rmi"))]
""
"@
MOV.B\t%1, %0
MOV.W\t%1, %0
- MOV%X0.W\t%1, %0"
+ MOVX.W\t%1, %0"
)
(define_expand "movsi"
@@ -241,10 +241,10 @@
"msp430_split_movsi (operands);"
)
-;; Some MOVX.A cases can be done with MOVA, this is only a few of them.
+;; FIXME: Some MOVX.A cases can be done with MOVA, this is only a few of them.
(define_insn "movpsi"
- [(set (match_operand:PSI 0 "msp_nonimmediate_operand" "=r,r,r,Ya,rm")
- (match_operand:PSI 1 "msp_general_operand" "N,O,riYa,r,rmi"))]
+ [(set (match_operand:PSI 0 "msp430_nonimmediate_operand" "=r,r,r,Ya,rm")
+ (match_operand:PSI 1 "msp430_general_operand" "N,O,riYa,r,rmi"))]
""
"@
MOV.B\t%1, %0
@@ -279,9 +279,9 @@
;; Math
(define_insn "addpsi3"
- [(set (match_operand:PSI 0 "msp_nonimmediate_operand" "=r,rm")
- (plus:PSI (match_operand:PSI 1 "msp_nonimmediate_operand" "%0,0")
- (match_operand:PSI 2 "msp_general_operand" "rLs,rmi")))]
+ [(set (match_operand:PSI 0 "msp430_nonimmediate_operand" "=r,rm")
+ (plus:PSI (match_operand:PSI 1 "msp430_nonimmediate_operand" "%0,0")
+ (match_operand:PSI 2 "msp430_general_operand" "rLs,rmi")))]
""
"@
ADDA\t%2, %0
@@ -289,23 +289,23 @@
)
(define_insn "addqi3"
- [(set (match_operand:QI 0 "msp_nonimmediate_operand" "=rYs,rm")
- (plus:QI (match_operand:QI 1 "msp_nonimmediate_operand" "%0,0")
- (match_operand:QI 2 "msp_general_operand" "riYs,rmi")))]
+ [(set (match_operand:QI 0 "msp430_nonimmediate_operand" "=rYsYx,rm")
+ (plus:QI (match_operand:QI 1 "msp430_nonimmediate_operand" "%0,0")
+ (match_operand:QI 2 "msp430_general_operand" "riYsYx,rmi")))]
""
"@
ADD.B\t%2, %0
- ADD%X0.B\t%2, %0"
+ ADDX.B\t%2, %0"
)
(define_insn "addhi3"
- [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=rYs,rm")
- (plus:HI (match_operand:HI 1 "msp_nonimmediate_operand" "%0,0")
- (match_operand:HI 2 "msp_general_operand" "riYs,rmi")))]
+ [(set (match_operand:HI 0 "msp430_nonimmediate_operand" "=rYsYx,rm")
+ (plus:HI (match_operand:HI 1 "msp430_nonimmediate_operand" "%0,0")
+ (match_operand:HI 2 "msp430_general_operand" "riYsYx,rmi")))]
""
"@
ADD.W\t%2, %0
- ADD%X0.W\t%2, %0"
+ ADDX.W\t%2, %0"
)
; This pattern is needed in order to avoid reload problems.
@@ -317,17 +317,17 @@
(plus:SI (match_operand:SI 1 "register_operand" "0")
(match_operand 2 "general_operand" "rmi")))]
""
- "ADD.W\t%L2, %L0 { ADDC.W\t%H2, %H0 { PUSH.W\t%H0 { PUSH.W\t%L0 { POPM.A\t#1, %0"
+ "ADD%X2.W\t%L2, %L0 { ADDC%X2.W\t%H2, %H0 { PUSH.W\t%H0 { PUSH.W\t%L0 { POPM.A\t#1, %0"
)
(define_insn "addsi3"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=&r,rm")
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=&rYsYx,rm")
(plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
- (match_operand:SI 2 "general_operand" "r,mi")))]
+ (match_operand:SI 2 "general_operand" "rYsYxi,mi")))]
""
"@
ADD\t%L2, %L0 { ADDC\t%H2, %H0
- ADD%X0\t%L2, %L0 { ADDC%X0\t%H2, %H0"
+ ADDX\t%L2, %L0 { ADDCX\t%H2, %H0"
)
; Version of addhi that exposes the carry operations, for SImode adds.
@@ -358,9 +358,9 @@
; that are not single_set() very well.
(define_insn "addhi3_cy"
- [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=r,rm")
- (plus:HI (match_operand:HI 1 "msp_nonimmediate_operand" "%0,0")
- (match_operand:HI 2 "msp_nonimmediate_operand" "r,rm")))
+ [(set (match_operand:HI 0 "msp430_nonimmediate_operand" "=rYsYx,rm")
+ (plus:HI (match_operand:HI 1 "msp430_nonimmediate_operand" "%0,0")
+ (match_operand:HI 2 "msp430_nonimmediate_operand" "rYsYxi,rm")))
(set (reg:BI CARRY)
(truncate:BI (lshiftrt:SI (plus:SI (zero_extend:SI (match_dup 1))
(zero_extend:SI (match_dup 2)))
@@ -369,7 +369,7 @@
""
"@
ADD\t%2, %1 ; cy
- ADD%X0\t%2, %1 ; cy"
+ ADDX\t%2, %1 ; cy"
)
(define_insn "addhi3_cy_i"
@@ -389,15 +389,15 @@
; Version of addhi that adds the carry, for SImode adds.
(define_insn "addchi4_cy"
- [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=r,rm")
- (plus:HI (plus:HI (match_operand:HI 1 "msp_nonimmediate_operand" "%0,0")
- (match_operand:HI 2 "msp_general_operand" "ri,rmi"))
+ [(set (match_operand:HI 0 "msp430_nonimmediate_operand" "=rYsYx,rm")
+ (plus:HI (plus:HI (match_operand:HI 1 "msp430_nonimmediate_operand" "%0,0")
+ (match_operand:HI 2 "msp430_general_operand" "riYsYx,rmi"))
(zero_extend:HI (reg:BI CARRY))))
]
""
"@
ADDC\t%2, %1
- ADDC%X0\t%2, %1"
+ ADDCX\t%2, %1"
)
; Split an SImode add into two HImode adds, keeping track of the carry
@@ -423,23 +423,9 @@
(zero_extend:HI (reg:BI CARRY))))
]
"
- operands[3] = msp430_subreg (HImode, operands[0], SImode, 0);
- operands[4] = msp430_subreg (HImode, operands[1], SImode, 0);
- operands[5] = msp430_subreg (HImode, operands[2], SImode, 0);
- operands[6] = msp430_subreg (HImode, operands[0], SImode, 2);
- operands[7] = msp430_subreg (HImode, operands[1], SImode, 2);
- operands[8] = msp430_subreg (HImode, operands[2], SImode, 2);
-
- /* BZ 64160: Do not use this splitter when the dest partially overlaps the source. */
- if (reg_overlap_mentioned_p (operands[3], operands[7])
- || reg_overlap_mentioned_p (operands[3], operands[8]))
- FAIL;
-
- if (GET_CODE (operands[5]) == CONST_INT)
- operands[9] = GEN_INT (INTVAL (operands[5]) & 0xffff);
- else
- operands[9] = gen_rtx_ZERO_EXTEND (SImode, operands[5]);
- "
+ if (msp430_split_addsi (operands))
+ FAIL;
+ "
)
@@ -458,41 +444,43 @@
;; Alternatives 2 and 3 are to handle cases generated by reload.
(define_insn "subqi3"
- [(set (match_operand:QI 0 "nonimmediate_operand" "=rYs, rm, &?r, ?&r")
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=rYsYx, rm, &?r, ?&r")
(minus:QI (match_operand:QI 1 "general_operand" "0, 0, !r, !i")
- (match_operand:QI 2 "general_operand" " riYs, rmi, rmi, r")))]
+ (match_operand:QI 2 "general_operand" " riYsYx, rmi, rmi, r")))]
""
"@
SUB.B\t%2, %0
- SUB%X0.B\t%2, %0
- MOV%X0.B\t%1, %0 { SUB%X0.B\t%2, %0
+ SUBX.B\t%2, %0
+ MOV%X2.B\t%1, %0 { SUB%X2.B\t%2, %0
MOV%X0.B\t%1, %0 { SUB%X0.B\t%2, %0"
)
;; Alternatives 2 and 3 are to handle cases generated by reload.
(define_insn "subhi3"
- [(set (match_operand:HI 0 "nonimmediate_operand" "=rYs, rm, &?r, ?&r")
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=rYsYx, rm, &?r, ?&r")
(minus:HI (match_operand:HI 1 "general_operand" "0, 0, !r, !i")
- (match_operand:HI 2 "general_operand" " riYs, rmi, rmi, r")))]
+ (match_operand:HI 2 "general_operand" " riYsYx, rmi, rmi, r")))]
""
"@
SUB.W\t%2, %0
- SUB%X0.W\t%2, %0
- MOV%X0.W\t%1, %0 { SUB%X0.W\t%2, %0
+ SUBX.W\t%2, %0
+ MOV%X2.W\t%1, %0 { SUB%X2.W\t%2, %0
MOV%X0.W\t%1, %0 { SUB%X0.W\t%2, %0"
)
(define_insn "subsi3"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=&rm")
- (minus:SI (match_operand:SI 1 "nonimmediate_operand" "0")
- (match_operand:SI 2 "general_operand" "rmi")))]
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=&rYsYx,m")
+ (minus:SI (match_operand:SI 1 "nonimmediate_operand" "0,0")
+ (match_operand:SI 2 "general_operand" "riYsYx,mi")))]
""
- "SUB%X0\t%L2, %L0 { SUBC%X0\t%H2, %H0"
+ "@
+ SUB\t%L2, %L0 { SUBC\t%H2, %H0
+ SUBX\t%L2, %L0 { SUBCX\t%H2, %H0"
)
(define_insn "*bic<mode>_cg"
- [(set (match_operand:QHI 0 "msp_nonimmediate_operand" "=rYs,m")
- (and:QHI (match_operand:QHI 1 "msp_general_operand" "0,0")
+ [(set (match_operand:QHI 0 "msp430_nonimmediate_operand" "=rYs,m")
+ (and:QHI (match_operand:QHI 1 "msp430_general_operand" "0,0")
(match_operand 2 "msp430_inv_constgen_operator" "n,n")))]
""
"@
@@ -501,50 +489,50 @@
)
(define_insn "bic<mode>3"
- [(set (match_operand:QHI 0 "msp_nonimmediate_operand" "=rYs,rm")
- (and:QHI (not:QHI (match_operand:QHI 1 "msp_general_operand" "rYs,rmn"))
- (match_operand:QHI 2 "msp_nonimmediate_operand" "0,0")))]
+ [(set (match_operand:QHI 0 "msp430_nonimmediate_operand" "=rYsYx,rm")
+ (and:QHI (not:QHI (match_operand:QHI 1 "msp430_general_operand" "rYsYx,rmn"))
+ (match_operand:QHI 2 "msp430_nonimmediate_operand" "0,0")))]
""
"@
BIC%x0%b0\t%1, %0
- BIC%X0%b0\t%1, %0"
+ BICX%b0\t%1, %0"
)
(define_insn "and<mode>3"
- [(set (match_operand:QHI 0 "msp_nonimmediate_operand" "=r,rYs,rm")
- (and:QHI (match_operand:QHI 1 "msp_nonimmediate_operand" "%0,0,0")
- (match_operand:QHI 2 "msp_general_operand" "N,riYs,rmi")))]
+ [(set (match_operand:QHI 0 "msp430_nonimmediate_operand" "=r,rYsYx,rm")
+ (and:QHI (match_operand:QHI 1 "msp430_nonimmediate_operand" "%0,0,0")
+ (match_operand:QHI 2 "msp430_general_operand" "N,riYsYx,rmi")))]
""
"@
AND%x0.B\t%2, %0
AND%x0%b0\t%2, %0
- AND%X0%b0\t%2, %0"
+ ANDX%b0\t%2, %0"
)
(define_insn "ior<mode>3"
- [(set (match_operand:QHI 0 "msp_nonimmediate_operand" "=rYs,rm")
- (ior:QHI (match_operand:QHI 1 "msp_nonimmediate_operand" "%0,0")
- (match_operand:QHI 2 "msp_general_operand" "riYs,rmi")))]
+ [(set (match_operand:QHI 0 "msp430_nonimmediate_operand" "=rYsYx,rm")
+ (ior:QHI (match_operand:QHI 1 "msp430_nonimmediate_operand" "%0,0")
+ (match_operand:QHI 2 "msp430_general_operand" "riYsYx,rmi")))]
""
"@
BIS%x0%b0\t%2, %0
- BIS%X0%b0\t%2, %0"
+ BISX%b0\t%2, %0"
)
(define_insn "xor<mode>3"
- [(set (match_operand:QHI 0 "msp_nonimmediate_operand" "=rYs,rm")
- (xor:QHI (match_operand:QHI 1 "msp_nonimmediate_operand" "%0,0")
- (match_operand:QHI 2 "msp_general_operand" "riYs,rmi")))]
+ [(set (match_operand:QHI 0 "msp430_nonimmediate_operand" "=rYsYx,rm")
+ (xor:QHI (match_operand:QHI 1 "msp430_nonimmediate_operand" "%0,0")
+ (match_operand:QHI 2 "msp430_general_operand" "riYsYx,rmi")))]
""
"@
XOR%x0%b0\t%2, %0
- XOR%X0%b0\t%2, %0"
+ XORX%b0\t%2, %0"
)
;; Macro : XOR #~0, %0
(define_insn "one_cmpl<mode>2"
- [(set (match_operand:QHI 0 "msp_nonimmediate_operand" "=rYs,m")
- (not:QHI (match_operand:QHI 1 "msp_nonimmediate_operand" "0,0")))]
+ [(set (match_operand:QHI 0 "msp430_nonimmediate_operand" "=rYs,m")
+ (not:QHI (match_operand:QHI 1 "msp430_nonimmediate_operand" "0,0")))]
""
"@
INV%x0%b0\t%0
@@ -552,8 +540,8 @@
)
(define_insn "extendqihi2"
- [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=rYs,m")
- (sign_extend:HI (match_operand:QI 1 "msp_nonimmediate_operand" "0,0")))]
+ [(set (match_operand:HI 0 "msp430_nonimmediate_operand" "=rYs,m")
+ (sign_extend:HI (match_operand:QI 1 "msp430_nonimmediate_operand" "0,0")))]
""
"@
SXT%X0\t%0
@@ -561,13 +549,13 @@
)
(define_insn "zero_extendqihi2"
- [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=rYs,r,r,m")
- (zero_extend:HI (match_operand:QI 1 "msp_nonimmediate_operand" "0,rYs,m,0")))]
+ [(set (match_operand:HI 0 "msp430_nonimmediate_operand" "=rYs,r,r,m")
+ (zero_extend:HI (match_operand:QI 1 "msp430_nonimmediate_operand" "0,rYs,m,0")))]
""
"@
AND\t#0xff, %0
MOV.B\t%1, %0
- MOV%X0.B\t%1, %0
+ MOV%X1.B\t%1, %0
AND%X0\t#0xff, %0"
)
@@ -583,8 +571,8 @@
)
(define_insn "zero_extendhipsi2"
- [(set (match_operand:PSI 0 "msp_nonimmediate_operand" "=r,m")
- (zero_extend:PSI (match_operand:HI 1 "msp_nonimmediate_operand" "rm,r")))]
+ [(set (match_operand:PSI 0 "msp430_nonimmediate_operand" "=r,m")
+ (zero_extend:PSI (match_operand:HI 1 "msp430_nonimmediate_operand" "rm,r")))]
""
"@
MOVX\t%1, %0
@@ -592,7 +580,7 @@
)
(define_insn "truncpsihi2"
- [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=rm")
+ [(set (match_operand:HI 0 "msp430_nonimmediate_operand" "=rm")
(truncate:HI (match_operand:PSI 1 "register_operand" "r")))]
""
"MOVX\t%1, %0"
@@ -621,7 +609,7 @@
[(set (match_operand:SI 0 "nonimmediate_operand" "=r")
(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "rm")))]
""
- "MOV.B\t%1,%L0 { CLR\t%H0"
+ "MOV%X1.B\t%1,%L0 { CLR\t%H0"
)
(define_insn "zero_extendhisi2"
@@ -629,7 +617,7 @@
(zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0,r")))]
""
"@
- MOV.W\t#0,%H0
+ MOV%X0.W\t#0,%H0
MOV.W\t%1,%L0 { MOV.W\t#0,%H0"
)
@@ -782,7 +770,7 @@
(ashift:HI (match_operand:HI 1 "general_operand" "0")
(const_int 1)))]
""
- "RLA.W\t%0" ;; Note - this is a macro for ADD
+ "RLA%X0.W\t%0" ;; Note - this is a macro for ADD
)
(define_insn "430x_shift_left"
@@ -802,7 +790,7 @@
(ashift:SI (match_operand:SI 1 "general_operand" "0")
(const_int 1)))]
""
- "RLA.W\t%L0 { RLC.W\t%H0"
+ "RLA%X0.W\t%L0 { RLC%X0.W\t%H0"
)
(define_insn "slll_2"
@@ -810,7 +798,7 @@
(ashift:SI (match_operand:SI 1 "general_operand" "0")
(const_int 2)))]
""
- "RLA.W\t%L0 { RLC.W\t%H0 { RLA.W\t%L0 { RLC.W\t%H0"
+ "RLA%X0.W\t%L0 { RLC%X0.W\t%H0 { RLA%X0.W\t%L0 { RLC%X0.W\t%H0"
)
(define_expand "ashlsi3"
@@ -863,11 +851,11 @@
)
(define_insn "srai_1"
- [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=rm")
- (ashiftrt:HI (match_operand:HI 1 "msp_general_operand" "0")
+ [(set (match_operand:HI 0 "msp430_nonimmediate_operand" "=rm")
+ (ashiftrt:HI (match_operand:HI 1 "msp430_general_operand" "0")
(const_int 1)))]
""
- "RRA.W\t%0"
+ "RRA%X0.W\t%0"
)
(define_insn "430x_arithmetic_shift_right"
@@ -903,7 +891,7 @@
(ashiftrt:SI (match_operand:SI 1 "general_operand" "0")
(const_int 1)))]
""
- "RRA.W\t%H0 { RRC.W\t%L0"
+ "RRA%X0.W\t%H0 { RRC%X0.W\t%L0"
)
(define_insn "sral_2"
@@ -911,7 +899,7 @@
(ashiftrt:SI (match_operand:SI 1 "general_operand" "0")
(const_int 2)))]
""
- "RRA.W\t%H0 { RRC.W\t%L0 { RRA.W\t%H0 { RRC.W\t%L0"
+ "RRA%X0.W\t%H0 { RRC%X0.W\t%L0 { RRA%X0.W\t%H0 { RRC%X0.W\t%L0"
)
(define_expand "ashrsi3"
@@ -968,7 +956,7 @@
(lshiftrt:HI (match_operand:HI 1 "general_operand" "0")
(const_int 1)))]
""
- "CLRC { RRC.W\t%0"
+ "CLRC { RRC%X0.W\t%0"
)
(define_insn "430x_logical_shift_right"
@@ -994,7 +982,7 @@
(lshiftrt:SI (match_operand:SI 1 "general_operand" "0")
(const_int 1)))]
""
- "CLRC { RRC.W\t%H0 { RRC.W\t%L0"
+ "CLRC { RRC%X0.W\t%H0 { RRC%X0.W\t%L0"
)
(define_insn "srll_2x"
@@ -1106,7 +1094,7 @@
"CALL%Q0\t%1"
)
-(define_insn "msp_return"
+(define_insn "msp430_return"
[(return)]
""
{ return msp430_is_interrupt_func () ? "RETI" : (TARGET_LARGE ? "RETA" : "RET"); }
@@ -1188,8 +1176,8 @@
(define_insn "cbranchqi4_real"
[(set (pc) (if_then_else
(match_operator 0 "msp430_cmp_operator"
- [(match_operand:QI 1 "nonimmediate_operand" "rYs,rm")
- (match_operand:QI 2 "general_operand" "rYsi,rmi")])
+ [(match_operand:QI 1 "nonimmediate_operand" "rYsYx,rm")
+ (match_operand:QI 2 "general_operand" "rYsYxi,rmi")])
(label_ref (match_operand 3 "" ""))
(pc)))
(clobber (reg:BI CARRY))
@@ -1197,14 +1185,14 @@
""
"@
CMP.B\t%2, %1 { J%0\t%l3
- CMP%X0.B\t%2, %1 { J%0\t%l3"
+ CMPX.B\t%2, %1 { J%0\t%l3"
)
(define_insn "cbranchhi4_real"
[(set (pc) (if_then_else
(match_operator 0 "msp430_cmp_operator"
- [(match_operand:HI 1 "nonimmediate_operand" "rYs,rm")
- (match_operand:HI 2 "general_operand" "rYsi,rmi")])
+ [(match_operand:HI 1 "nonimmediate_operand" "rYsYx,rm")
+ (match_operand:HI 2 "general_operand" "rYsYxi,rmi")])
(label_ref (match_operand 3 "" ""))
(pc)))
(clobber (reg:BI CARRY))
@@ -1222,12 +1210,12 @@
{
return which_alternative == 0 ?
\"CMP.W\t%2, %1 { J%r0 1f { BRA #%l3 { 1:\" :
- \"CMP%X0.W\t%2, %1 { J%r0 1f { BRA #%l3 { 1:\";
+ \"CMPX.W\t%2, %1 { J%r0 1f { BRA #%l3 { 1:\";
}
return which_alternative == 0 ?
\"CMP.W\t%2, %1 { J%0\t%l3\" :
- \"CMP%X0.W\t%2, %1 { J%0\t%l3\";
+ \"CMPX.W\t%2, %1 { J%0\t%l3\";
"
[(set (attr "length")
(if_then_else
@@ -1257,8 +1245,8 @@
(define_insn "cbranchqi4_reversed"
[(set (pc) (if_then_else
(match_operator 0 "msp430_reversible_cmp_operator"
- [(match_operand:QI 1 "general_operand" "rYsi,rmi")
- (match_operand:QI 2 "general_operand" "rYs,rm")])
+ [(match_operand:QI 1 "general_operand" "rYsYxi,rmi")
+ (match_operand:QI 2 "general_operand" "rYsYx,rm")])
(label_ref (match_operand 3 "" ""))
(pc)))
(clobber (reg:BI CARRY))
@@ -1266,14 +1254,14 @@
""
"@
CMP.B\t%1, %2 { J%R0\t%l3
- CMP%X0.B\t%1, %2 { J%R0\t%l3"
+ CMPX.B\t%1, %2 { J%R0\t%l3"
)
(define_insn "cbranchhi4_reversed"
[(set (pc) (if_then_else
(match_operator 0 "msp430_reversible_cmp_operator"
- [(match_operand:HI 1 "general_operand" "rYsi,rmi")
- (match_operand:HI 2 "general_operand" "rYs,rm")])
+ [(match_operand:HI 1 "general_operand" "rYsYxi,rmi")
+ (match_operand:HI 2 "general_operand" "rYsYx,rm")])
(label_ref (match_operand 3 "" ""))
(pc)))
(clobber (reg:BI CARRY))
@@ -1281,13 +1269,13 @@
""
"@
CMP.W\t%1, %2 { J%R0\t%l3
- CMP%X0.W\t%1, %2 { J%R0\t%l3"
+ CMPX.W\t%1, %2 { J%R0\t%l3"
)
(define_insn "*bitbranch<mode>4"
[(set (pc) (if_then_else
- (ne (and:QHI (match_operand:QHI 0 "msp_nonimmediate_operand" "rYs,rm")
- (match_operand:QHI 1 "msp_general_operand" "rYsi,rmi"))
+ (ne (and:QHI (match_operand:QHI 0 "msp430_nonimmediate_operand" "rYsYx,rm")
+ (match_operand:QHI 1 "msp430_general_operand" "rYsYxi,rmi"))
(const_int 0))
(label_ref (match_operand 2 "" ""))
(pc)))
@@ -1296,46 +1284,52 @@
""
"@
BIT%x0%b0\t%1, %0 { JNE\t%l2
- BIT%X0%b0\t%1, %0 { JNE\t%l2"
+ BITX%b0\t%1, %0 { JNE\t%l2"
)
(define_insn "*bitbranch<mode>4"
[(set (pc) (if_then_else
- (eq (and:QHI (match_operand:QHI 0 "msp_nonimmediate_operand" "rm")
- (match_operand:QHI 1 "msp_general_operand" "rmi"))
+ (eq (and:QHI (match_operand:QHI 0 "msp430_nonimmediate_operand" "rYsYx,rm")
+ (match_operand:QHI 1 "msp430_general_operand" "rYsYxi,rmi"))
(const_int 0))
(label_ref (match_operand 2 "" ""))
(pc)))
(clobber (reg:BI CARRY))
]
""
- "BIT%x0%b0\t%1, %0 { JEQ\t%l2"
+ "@
+ BIT%x0%b0\t%1, %0 { JEQ\t%l2
+ BITX%b0\t%1, %0 { JEQ\t%l2"
)
(define_insn "*bitbranch<mode>4"
[(set (pc) (if_then_else
- (eq (and:QHI (match_operand:QHI 0 "msp_nonimmediate_operand" "rm")
- (match_operand:QHI 1 "msp_general_operand" "rmi"))
+ (eq (and:QHI (match_operand:QHI 0 "msp430_nonimmediate_operand" "rYsYx,rm")
+ (match_operand:QHI 1 "msp430_general_operand" "rYsYxi,rmi"))
(const_int 0))
(pc)
(label_ref (match_operand 2 "" ""))))
(clobber (reg:BI CARRY))
]
""
- "BIT%X0%b0\t%1, %0 { JNE\t%l2"
+ "@
+ BIT%x0%b0\t%1, %0 { JNE\t%l2
+ BITX%b0\t%1, %0 { JNE\t%l2"
)
(define_insn "*bitbranch<mode>4"
[(set (pc) (if_then_else
- (ne (and:QHI (match_operand:QHI 0 "msp_nonimmediate_operand" "rm")
- (match_operand:QHI 1 "msp_general_operand" "rmi"))
+ (ne (and:QHI (match_operand:QHI 0 "msp430_nonimmediate_operand" "rYsYx,rm")
+ (match_operand:QHI 1 "msp430_general_operand" "rYsYxi,rmi"))
(const_int 0))
(pc)
(label_ref (match_operand 2 "" ""))))
(clobber (reg:BI CARRY))
]
""
- "BIT%X0%b0\t%1, %0 { JEQ\t%l2"
+ "@
+ BIT%x0%b0\t%1, %0 { JEQ\t%l2
+ BITX%b0\t%1, %0 { JEQ\t%l2"
)
;;------------------------------------------------------------
@@ -1343,7 +1337,7 @@
(define_insn "*bitbranch<mode>4_z"
[(set (pc) (if_then_else
- (ne (zero_extract:HI (match_operand:QHI 0 "msp_nonimmediate_operand" "rYs,rm")
+ (ne (zero_extract:HI (match_operand:QHI 0 "msp430_nonimmediate_operand" "rYs,rm")
(const_int 1)
(match_operand 1 "msp430_bitpos" "i,i"))
(const_int 0))
@@ -1359,7 +1353,7 @@
(define_insn "*bitbranch<mode>4_z"
[(set (pc) (if_then_else
- (eq (zero_extract:HI (match_operand:QHI 0 "msp_nonimmediate_operand" "rm")
+ (eq (zero_extract:HI (match_operand:QHI 0 "msp430_nonimmediate_operand" "rm")
(const_int 1)
(match_operand 1 "msp430_bitpos" "i"))
(const_int 0))
@@ -1368,12 +1362,12 @@
(clobber (reg:BI CARRY))
]
""
- "BIT%x0%X0%b0\t%p1, %0 { JEQ\t%l2"
+ "BIT%X0%b0\t%p1, %0 { JEQ\t%l2"
)
(define_insn "*bitbranch<mode>4_z"
[(set (pc) (if_then_else
- (eq (zero_extract:HI (match_operand:QHI 0 "msp_nonimmediate_operand" "rm")
+ (eq (zero_extract:HI (match_operand:QHI 0 "msp430_nonimmediate_operand" "rm")
(const_int 1)
(match_operand 1 "msp430_bitpos" "i"))
(const_int 0))
@@ -1387,7 +1381,7 @@
(define_insn "*bitbranch<mode>4_z"
[(set (pc) (if_then_else
- (ne (zero_extract:HI (match_operand:QHI 0 "msp_nonimmediate_operand" "rm")
+ (ne (zero_extract:HI (match_operand:QHI 0 "msp430_nonimmediate_operand" "rm")
(const_int 1)
(match_operand 1 "msp430_bitpos" "i"))
(const_int 0))
diff --git a/gcc/config/msp430/msp430.opt b/gcc/config/msp430/msp430.opt
index cbbe0faa6a2..2db2906ca11 100644
--- a/gcc/config/msp430/msp430.opt
+++ b/gcc/config/msp430/msp430.opt
@@ -67,12 +67,16 @@ EnumValue
Enum(msp430_hwmult_types) String(f5series) Value(MSP430_HWMULT_F5SERIES)
mcode-region=
-Target Joined RejectNegative Report ToLower Var(msp430_code_region) Enum(msp430_regions) Init(MSP430_REGION_ANY)
-Specify whether functions should be placed into low or high memory.
+Target Joined RejectNegative Report ToLower Var(msp430_code_region) Enum(msp430_regions) Init(MSP430_REGION_LOWER)
+Specify whether functions should be placed into the lower or upper memory regions, or if they should be shuffled between the regions (either) for best fit (default: lower).
mdata-region=
-Target Joined RejectNegative Report ToLower Var(msp430_data_region) Enum(msp430_regions) Init(MSP430_REGION_ANY)
-Specify whether variables should be placed into low or high memory.
+Target Joined RejectNegative Report ToLower Var(msp430_data_region) Enum(msp430_regions) Init(MSP430_REGION_LOWER)
+Specify whether variables should be placed into the lower or upper memory regions, or if they should be shuffled between the regions (either) for best fit (default: lower).
+
+muse-lower-region-prefix
+Target Mask(USE_LOWER_REGION_PREFIX) Report
+Add the .lower prefix to section names when compiling with -m{code,data}-region=lower (disabled by default).
Enum
Name(msp430_regions) Type(enum msp430_regions)
diff --git a/gcc/config/msp430/predicates.md b/gcc/config/msp430/predicates.md
index 1bfd33da524..751548c4ae8 100644
--- a/gcc/config/msp430/predicates.md
+++ b/gcc/config/msp430/predicates.md
@@ -18,7 +18,7 @@
;; along with GCC; see the file COPYING3. If not see
;; <http://www.gnu.org/licenses/>.
-(define_predicate "msp_volatile_memory_operand"
+(define_predicate "msp430_volatile_memory_operand"
(and (match_code "mem")
(match_test ("memory_address_addr_space_p (GET_MODE (op), XEXP (op, 0), MEM_ADDR_SPACE (op))")))
)
@@ -26,16 +26,16 @@
; TRUE for any valid general operand. We do this because
; general_operand refuses to match volatile memory refs.
-(define_predicate "msp_general_operand"
+(define_predicate "msp430_general_operand"
(ior (match_operand 0 "general_operand")
- (match_operand 0 "msp_volatile_memory_operand"))
+ (match_operand 0 "msp430_volatile_memory_operand"))
)
; Likewise for nonimmediate_operand.
-(define_predicate "msp_nonimmediate_operand"
+(define_predicate "msp430_nonimmediate_operand"
(ior (match_operand 0 "nonimmediate_operand")
- (match_operand 0 "msp_volatile_memory_operand"))
+ (match_operand 0 "msp430_volatile_memory_operand"))
)
(define_predicate "ubyte_operand"
diff --git a/gcc/config/msp430/t-msp430 b/gcc/config/msp430/t-msp430
index b9565103e9a..f8ba7751123 100644
--- a/gcc/config/msp430/t-msp430
+++ b/gcc/config/msp430/t-msp430
@@ -28,17 +28,22 @@ msp430-devices.o: $(srcdir)/config/msp430/msp430-devices.c \
# Enable multilibs:
-MULTILIB_OPTIONS = mcpu=msp430 mlarge
-MULTILIB_DIRNAMES = 430 large
+MULTILIB_OPTIONS = mcpu=msp430 mlarge mdata-region=none
+MULTILIB_DIRNAMES = 430 large full-memory-range
# Match -mcpu=430
MULTILIB_MATCHES = mcpu?msp430=mcpu?430
+# These options are equivalent in terms of the multilib required for them
+MULTILIB_MATCHES += mdata-region?none=mdata-region?upper
+MULTILIB_MATCHES += mdata-region?none=mdata-region?either
# The correct multilib for a given mmcu is selected without the need for
# hard-coded data here, because DRIVER_SELF_SPECS will place the correct
# -mcpu option for a given mcu onto the command line.
-MULTILIB_EXCEPTIONS = mcpu=msp430/mlarge
+MULTILIB_REQUIRED = mcpu=msp430
+MULTILIB_REQUIRED += mlarge
+MULTILIB_REQUIRED += mlarge/mdata-region=none
MULTILIB_EXTRA_OPTS =
diff --git a/gcc/config/pa/pa.c b/gcc/config/pa/pa.c
index 4f48c416e2d..d8aff717ed8 100644
--- a/gcc/config/pa/pa.c
+++ b/gcc/config/pa/pa.c
@@ -535,7 +535,7 @@ pa_option_override (void)
if (! TARGET_GAS && write_symbols != NO_DEBUG)
{
- warning (0, "%<-g%> is only supported when using GAS on this processor,");
+ warning (0, "%<-g%> is only supported when using GAS on this processor");
warning (0, "%<-g%> option disabled");
write_symbols = NO_DEBUG;
}
@@ -8027,20 +8027,22 @@ pa_output_call (rtx_insn *insn, rtx call_dest, int sibcall)
{
output_asm_insn ("addil LT'%0,%%r19", xoperands);
output_asm_insn ("ldw RT'%0(%%r1),%%r1", xoperands);
- output_asm_insn ("ldw 0(%%r1),%%r1", xoperands);
+ output_asm_insn ("ldw 0(%%r1),%%r22", xoperands);
}
else
{
output_asm_insn ("addil LR'%0-$global$,%%r27",
xoperands);
- output_asm_insn ("ldw RR'%0-$global$(%%r1),%%r1",
+ output_asm_insn ("ldw RR'%0-$global$(%%r1),%%r22",
xoperands);
}
- output_asm_insn ("bb,>=,n %%r1,30,.+16", xoperands);
- output_asm_insn ("depi 0,31,2,%%r1", xoperands);
- output_asm_insn ("ldw 4(%%sr0,%%r1),%%r19", xoperands);
- output_asm_insn ("ldw 0(%%sr0,%%r1),%%r1", xoperands);
+ output_asm_insn ("bb,>=,n %%r22,30,.+16", xoperands);
+ output_asm_insn ("depi 0,31,2,%%r22", xoperands);
+ /* Should this be an ordered load to ensure the target
+ address is loaded before the global pointer? */
+ output_asm_insn ("ldw 0(%%r22),%%r1", xoperands);
+ output_asm_insn ("ldw 4(%%r22),%%r19", xoperands);
if (!sibcall && !TARGET_PA_20)
{
@@ -8133,10 +8135,6 @@ pa_attr_length_indirect_call (rtx_insn *insn)
if (TARGET_PORTABLE_RUNTIME)
return 16;
- /* Inline version of $$dyncall. */
- if ((TARGET_NO_SPACE_REGS || TARGET_PA_20) && !optimize_size)
- return 20;
-
if (!TARGET_LONG_CALLS
&& ((TARGET_PA_20 && !TARGET_SOM && distance < 7600000)
|| distance < MAX_PCREL17F_OFFSET))
@@ -8146,12 +8144,15 @@ pa_attr_length_indirect_call (rtx_insn *insn)
if (!flag_pic)
return 12;
- /* Inline version of $$dyncall. */
- if (TARGET_NO_SPACE_REGS || TARGET_PA_20)
- return 20;
-
+ /* Inline versions of $$dyncall. */
if (!optimize_size)
- return 36;
+ {
+ if (TARGET_NO_SPACE_REGS)
+ return 28;
+
+ if (TARGET_PA_20)
+ return 32;
+ }
/* Long PIC pc-relative call. */
return 20;
@@ -8189,22 +8190,6 @@ pa_output_indirect_call (rtx_insn *insn, rtx call_dest)
return "blr %%r0,%%r2\n\tbv,n %%r0(%%r31)";
}
- /* Maybe emit a fast inline version of $$dyncall. */
- if ((TARGET_NO_SPACE_REGS || TARGET_PA_20) && !optimize_size)
- {
- output_asm_insn ("bb,>=,n %%r22,30,.+12\n\t"
- "ldw 2(%%r22),%%r19\n\t"
- "ldw -2(%%r22),%%r22", xoperands);
- pa_output_arg_descriptor (insn);
- if (TARGET_NO_SPACE_REGS)
- {
- if (TARGET_PA_20)
- return "bve,l,n (%%r22),%%r2\n\tnop";
- return "ble 0(%%sr4,%%r22)\n\tcopy %%r31,%%r2";
- }
- return "bve,l (%%r22),%%r2\n\tstw %%r2,-24(%%sp)";
- }
-
/* Now the normal case -- we can reach $$dyncall directly or
we're sure that we can get there via a long-branch stub.
@@ -8233,35 +8218,40 @@ pa_output_indirect_call (rtx_insn *insn, rtx call_dest)
return "ble R'$$dyncall(%%sr4,%%r2)\n\tcopy %%r31,%%r2";
}
- /* Maybe emit a fast inline version of $$dyncall. The long PIC
- pc-relative call sequence is five instructions. The inline PA 2.0
- version of $$dyncall is also five instructions. The PA 1.X versions
- are longer but still an overall win. */
- if (TARGET_NO_SPACE_REGS || TARGET_PA_20 || !optimize_size)
+ /* The long PIC pc-relative call sequence is five instructions. So,
+ let's use an inline version of $$dyncall when the calling sequence
+ has a roughly similar number of instructions and we are not optimizing
+ for size. We need two instructions to load the return pointer plus
+ the $$dyncall implementation. */
+ if (!optimize_size)
{
- output_asm_insn ("bb,>=,n %%r22,30,.+12\n\t"
- "ldw 2(%%r22),%%r19\n\t"
- "ldw -2(%%r22),%%r22", xoperands);
if (TARGET_NO_SPACE_REGS)
{
pa_output_arg_descriptor (insn);
- if (TARGET_PA_20)
- return "bve,l,n (%%r22),%%r2\n\tnop";
- return "ble 0(%%sr4,%%r22)\n\tcopy %%r31,%%r2";
+ output_asm_insn ("bl .+8,%rp\b\t"
+ "ldo 20(%r2),%r2\n\t"
+ "extru,<> %r22,30,1,%r0\n\t"
+ "bv,n %%r0(%r22)\n\t"
+ "ldw -2(%%r22),%%r21\n\t"
+ "bv %%r0(%r21)\n\t"
+ "ldw 2(%%r22),%%r19", xoperands);
+ return "";
}
if (TARGET_PA_20)
{
pa_output_arg_descriptor (insn);
- return "bve,l (%%r22),%%r2\n\tstw %%r2,-24(%%sp)";
+ output_asm_insn ("bl .+8,%%r2\b\t"
+ "ldo 24(%%r2),%%r2\n\t"
+ "stw %%r2,-24(%%sp)\n\t"
+ "extru,<> %r22,30,1,%r0\n\t"
+ "bve,n (%%r22)\n\t"
+ "ldw -2(%%r22),%%r21\n\t"
+ "bve (%%r21)\n\t"
+ "ldw 2(%%r22),%%r19", xoperands);
+ return "";
}
- output_asm_insn ("bl .+8,%%r2\n\t"
- "ldo 16(%%r2),%%r2\n\t"
- "ldsid (%%r22),%%r1\n\t"
- "mtsp %%r1,%%sr0", xoperands);
- pa_output_arg_descriptor (insn);
- return "be 0(%%sr0,%%r22)\n\tstw %%r2,-24(%%sp)";
}
-
+
/* We need a long PIC call to $$dyncall. */
xoperands[0] = gen_rtx_SYMBOL_REF (Pmode, "$$dyncall");
xoperands[1] = gen_rtx_REG (Pmode, 2);
@@ -10025,7 +10015,7 @@ pa_modes_tieable_p (machine_mode mode1, machine_mode mode2)
/* Length in units of the trampoline instruction code. */
-#define TRAMPOLINE_CODE_SIZE (TARGET_64BIT ? 24 : (TARGET_PA_20 ? 32 : 40))
+#define TRAMPOLINE_CODE_SIZE (TARGET_64BIT ? 24 : (TARGET_PA_20 ? 36 : 48))
/* Output assembler code for a block containing the constant parts
@@ -10046,27 +10036,46 @@ pa_asm_trampoline_template (FILE *f)
{
if (!TARGET_64BIT)
{
- fputs ("\tldw 36(%r22),%r21\n", f);
- fputs ("\tbb,>=,n %r21,30,.+16\n", f);
- if (ASSEMBLER_DIALECT == 0)
- fputs ("\tdepi 0,31,2,%r21\n", f);
- else
- fputs ("\tdepwi 0,31,2,%r21\n", f);
- fputs ("\tldw 4(%r21),%r19\n", f);
- fputs ("\tldw 0(%r21),%r21\n", f);
if (TARGET_PA_20)
{
- fputs ("\tbve (%r21)\n", f);
- fputs ("\tldw 40(%r22),%r29\n", f);
+ fputs ("\tmfia %r20\n", f);
+ fputs ("\tldw 48(%r20),%r22\n", f);
+ fputs ("\tcopy %r22,%r21\n", f);
+ fputs ("\tbb,>=,n %r22,30,.+16\n", f);
+ fputs ("\tdepwi 0,31,2,%r22\n", f);
+ fputs ("\tldw 0(%r22),%r21\n", f);
+ fputs ("\tldw 4(%r22),%r19\n", f);
+ fputs ("\tbve (%r21)\n", f);
+ fputs ("\tldw 52(%r1),%r29\n", f);
+ fputs ("\t.word 0\n", f);
fputs ("\t.word 0\n", f);
fputs ("\t.word 0\n", f);
}
else
{
+ if (ASSEMBLER_DIALECT == 0)
+ {
+ fputs ("\tbl .+8,%r20\n", f);
+ fputs ("\tdepi 0,31,2,%r20\n", f);
+ }
+ else
+ {
+ fputs ("\tb,l .+8,%r20\n", f);
+ fputs ("\tdepwi 0,31,2,%r20\n", f);
+ }
+ fputs ("\tldw 40(%r20),%r22\n", f);
+ fputs ("\tcopy %r22,%r21\n", f);
+ fputs ("\tbb,>=,n %r22,30,.+16\n", f);
+ if (ASSEMBLER_DIALECT == 0)
+ fputs ("\tdepi 0,31,2,%r22\n", f);
+ else
+ fputs ("\tdepwi 0,31,2,%r22\n", f);
+ fputs ("\tldw 0(%r22),%r21\n", f);
+ fputs ("\tldw 4(%r22),%r19\n", f);
fputs ("\tldsid (%r21),%r1\n", f);
fputs ("\tmtsp %r1,%sr0\n", f);
- fputs ("\tbe 0(%sr0,%r21)\n", f);
- fputs ("\tldw 40(%r22),%r29\n", f);
+ fputs ("\tbe 0(%sr0,%r21)\n", f);
+ fputs ("\tldw 44(%r20),%r29\n", f);
}
fputs ("\t.word 0\n", f);
fputs ("\t.word 0\n", f);
@@ -10080,11 +10089,11 @@ pa_asm_trampoline_template (FILE *f)
fputs ("\t.dword 0\n", f);
fputs ("\t.dword 0\n", f);
fputs ("\tmfia %r31\n", f);
- fputs ("\tldd 24(%r31),%r1\n", f);
- fputs ("\tldd 24(%r1),%r27\n", f);
- fputs ("\tldd 16(%r1),%r1\n", f);
- fputs ("\tbve (%r1)\n", f);
+ fputs ("\tldd 24(%r31),%r27\n", f);
fputs ("\tldd 32(%r31),%r31\n", f);
+ fputs ("\tldd 16(%r27),%r1\n", f);
+ fputs ("\tbve (%r1)\n", f);
+ fputs ("\tldd 24(%r27),%r27\n", f);
fputs ("\t.dword 0 ; fptr\n", f);
fputs ("\t.dword 0 ; static link\n", f);
}
@@ -10094,10 +10103,10 @@ pa_asm_trampoline_template (FILE *f)
FNADDR is an RTX for the address of the function's pure code.
CXT is an RTX for the static chain value for the function.
- Move the function address to the trampoline template at offset 36.
- Move the static chain value to trampoline template at offset 40.
- Move the trampoline address to trampoline template at offset 44.
- Move r19 to trampoline template at offset 48. The latter two
+ Move the function address to the trampoline template at offset 48.
+ Move the static chain value to trampoline template at offset 52.
+ Move the trampoline address to trampoline template at offset 56.
+ Move r19 to trampoline template at offset 60. The latter two
words create a plabel for the indirect call to the trampoline.
A similar sequence is used for the 64-bit port but the plabel is
@@ -10123,15 +10132,15 @@ pa_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
if (!TARGET_64BIT)
{
- tmp = adjust_address (m_tramp, Pmode, 36);
+ tmp = adjust_address (m_tramp, Pmode, 48);
emit_move_insn (tmp, fnaddr);
- tmp = adjust_address (m_tramp, Pmode, 40);
+ tmp = adjust_address (m_tramp, Pmode, 52);
emit_move_insn (tmp, chain_value);
/* Create a fat pointer for the trampoline. */
- tmp = adjust_address (m_tramp, Pmode, 44);
+ tmp = adjust_address (m_tramp, Pmode, 56);
emit_move_insn (tmp, r_tramp);
- tmp = adjust_address (m_tramp, Pmode, 48);
+ tmp = adjust_address (m_tramp, Pmode, 60);
emit_move_insn (tmp, gen_rtx_REG (Pmode, 19));
/* fdc and fic only use registers for the address to flush,
@@ -10190,13 +10199,13 @@ pa_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
/* Perform any machine-specific adjustment in the address of the trampoline.
ADDR contains the address that was passed to pa_trampoline_init.
- Adjust the trampoline address to point to the plabel at offset 44. */
+ Adjust the trampoline address to point to the plabel at offset 56. */
static rtx
pa_trampoline_adjust_address (rtx addr)
{
if (!TARGET_64BIT)
- addr = memory_address (Pmode, plus_constant (Pmode, addr, 46));
+ addr = memory_address (Pmode, plus_constant (Pmode, addr, 58));
return addr;
}
diff --git a/gcc/config/pa/pa.h b/gcc/config/pa/pa.h
index 1a43e5caadc..4d6c425a085 100644
--- a/gcc/config/pa/pa.h
+++ b/gcc/config/pa/pa.h
@@ -688,7 +688,7 @@ extern int may_call_alloca;
/* Length in units of the trampoline for entering a nested function. */
-#define TRAMPOLINE_SIZE (TARGET_64BIT ? 72 : 52)
+#define TRAMPOLINE_SIZE (TARGET_64BIT ? 72 : 64)
/* Alignment required by the trampoline. */
diff --git a/gcc/config/rs6000/darwin.h b/gcc/config/rs6000/darwin.h
index a626325c2d0..1081967bd61 100644
--- a/gcc/config/rs6000/darwin.h
+++ b/gcc/config/rs6000/darwin.h
@@ -506,6 +506,9 @@ do { \
this will need to be modified similar to the x86 case. */
#define TARGET_FOLD_BUILTIN SUBTARGET_FOLD_BUILTIN
+/* First available SYMBOL flag bit for use by subtargets. */
+#define SYMBOL_FLAG_SUBT_DEP (SYMBOL_FLAG_MACH_DEP)
+
/* Use standard DWARF numbering for DWARF debugging information. */
#define RS6000_USE_DWARF_NUMBERING
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index a4a38822b43..d1434a9f743 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -4781,10 +4781,11 @@ rs6000_builtin_vectorization_cost (enum vect_cost_for_stmt type_of_cost,
return 1;
case vec_promote_demote:
- if (TARGET_VSX)
- return 4;
- else
- return 1;
+ /* Power7 has only one permute/pack unit, make it a bit expensive. */
+ if (TARGET_VSX && rs6000_tune == PROCESSOR_POWER7)
+ return 4;
+ else
+ return 1;
case cond_branch_taken:
return 3;
@@ -7250,6 +7251,13 @@ quad_address_p (rtx addr, machine_mode mode, bool strict)
if (VECTOR_MODE_P (mode) && !mode_supports_dq_form (mode))
return false;
+ /* Is this a valid prefixed address? If the bottom four bits of the offset
+ are non-zero, we could use a prefixed instruction (which does not have the
+ DQ-form constraint that the traditional instruction had) instead of
+ forcing the unaligned offset to a GPR. */
+ if (address_is_prefixed (addr, mode, NON_PREFIXED_DQ))
+ return true;
+
if (GET_CODE (addr) != PLUS)
return false;
@@ -7351,6 +7359,13 @@ mem_operand_gpr (rtx op, machine_mode mode)
&& legitimate_indirect_address_p (XEXP (addr, 0), false))
return true;
+ /* Allow prefixed instructions if supported. If the bottom two bits of the
+ offset are non-zero, we could use a prefixed instruction (which does not
+ have the DS-form constraint that the traditional instruction had) instead
+ of forcing the unaligned offset to a GPR. */
+ if (address_is_prefixed (addr, mode, NON_PREFIXED_DS))
+ return true;
+
/* Don't allow non-offsettable addresses. See PRs 83969 and 84279. */
if (!rs6000_offsettable_memref_p (op, mode, false))
return false;
@@ -7385,6 +7400,13 @@ mem_operand_ds_form (rtx op, machine_mode mode)
int extra;
rtx addr = XEXP (op, 0);
+ /* Allow prefixed instructions if supported. If the bottom two bits of the
+ offset are non-zero, we could use a prefixed instruction (which does not
+ have the DS-form constraint that the traditional instruction had) instead
+ of forcing the unaligned offset to a GPR. */
+ if (address_is_prefixed (addr, mode, NON_PREFIXED_DS))
+ return true;
+
if (!offsettable_address_p (false, mode, addr))
return false;
@@ -7754,7 +7776,10 @@ rs6000_legitimate_offset_address_p (machine_mode mode, rtx x,
break;
}
- return SIGNED_16BIT_OFFSET_EXTRA_P (offset, extra);
+ if (TARGET_PREFIXED_ADDR)
+ return SIGNED_34BIT_OFFSET_EXTRA_P (offset, extra);
+ else
+ return SIGNED_16BIT_OFFSET_EXTRA_P (offset, extra);
}
bool
@@ -8651,6 +8676,11 @@ rs6000_legitimate_address_p (machine_mode mode, rtx x, bool reg_ok_strict)
&& mode_supports_pre_incdec_p (mode)
&& legitimate_indirect_address_p (XEXP (x, 0), reg_ok_strict))
return 1;
+
+ /* Handle prefixed addresses (PC-relative or 34-bit offset). */
+ if (address_is_prefixed (x, mode, NON_PREFIXED_DEFAULT))
+ return 1;
+
/* Handle restricted vector d-form offsets in ISA 3.0. */
if (quad_offset_p)
{
@@ -8709,7 +8739,11 @@ rs6000_legitimate_address_p (machine_mode mode, rtx x, bool reg_ok_strict)
|| (!avoiding_indexed_address_p (mode)
&& legitimate_indexed_address_p (XEXP (x, 1), reg_ok_strict)))
&& rtx_equal_p (XEXP (XEXP (x, 1), 0), XEXP (x, 0)))
- return 1;
+ {
+ /* There is no prefixed version of the load/store with update. */
+ rtx addr = XEXP (x, 1);
+ return !address_is_prefixed (addr, mode, NON_PREFIXED_DEFAULT);
+ }
if (reg_offset_p && !quad_offset_p
&& legitimate_lo_sum_address_p (mode, x, reg_ok_strict))
return 1;
@@ -8773,7 +8807,10 @@ rs6000_mode_dependent_address (const_rtx addr)
{
HOST_WIDE_INT val = INTVAL (XEXP (addr, 1));
HOST_WIDE_INT extra = TARGET_POWERPC64 ? 8 : 12;
- return !SIGNED_16BIT_OFFSET_EXTRA_P (val, extra);
+ if (TARGET_PREFIXED_ADDR)
+ return !SIGNED_34BIT_OFFSET_EXTRA_P (val, extra);
+ else
+ return !SIGNED_16BIT_OFFSET_EXTRA_P (val, extra);
}
break;
diff --git a/gcc/config/s390/2827.md b/gcc/config/s390/2827.md
index 3f63f82284d..aafe8e27339 100644
--- a/gcc/config/s390/2827.md
+++ b/gcc/config/s390/2827.md
@@ -44,7 +44,7 @@
(define_insn_reservation "zEC12_normal_fp" 8
(and (eq_attr "cpu" "zEC12")
- (eq_attr "mnemonic" "lnebr,sdbr,sebr,clfxtr,adbr,aebr,celfbr,clfebr,lpebr,msebr,lndbr,clfdbr,cebr,maebr,ltebr,clfdtr,cdlgbr,cxlftr,lpdbr,cdfbr,lcebr,clfxbr,msdbr,cdbr,madbr,meebr,clgxbr,clgdtr,ledbr,cegbr,cdlftr,cdlgtr,mdbr,clgebr,ltdbr,cdlfbr,cdgbr,clgxtr,lcdbr,celgbr,clgdbr,ldebr,cefbr,fidtr,fixtr,madb,msdb,mseb,fiebra,fidbra,aeb,mdb,seb,cdb,tcdb,sdb,adb,tceb,maeb,ceb,meeb,ldeb")) "nothing")
+ (eq_attr "mnemonic" "lnebr,sdbr,sebr,clfxtr,adbr,aebr,celfbr,clfebr,lpebr,msebr,lndbr,clfdbr,cebr,maebr,ltebr,clfdtr,cdlgbr,cxlftr,lpdbr,cdfbr,lcebr,clfxbr,msdbr,cdbr,madbr,meebr,clgxbr,clgdtr,ledbr,cegbr,cdlftr,cdlgtr,mdbr,clgebr,ltdbr,cdlfbr,cdgbr,clgxtr,lcdbr,celgbr,clgdbr,ldebr,cefbr,fidtr,fixtr,madb,msdb,mseb,fiebra,fidbra,aeb,mdb,seb,cdb,tcdb,sdb,adb,tceb,maeb,ceb,meeb,ldeb,keb,kebr,kdb,kdbr")) "nothing")
(define_insn_reservation "zEC12_cgdbr" 2
(and (eq_attr "cpu" "zEC12")
@@ -426,6 +426,10 @@
(and (eq_attr "cpu" "zEC12")
(eq_attr "mnemonic" "cxbr")) "nothing")
+(define_insn_reservation "zEC12_kxbr" 18
+ (and (eq_attr "cpu" "zEC12")
+ (eq_attr "mnemonic" "kxbr")) "nothing")
+
(define_insn_reservation "zEC12_ddbr" 36
(and (eq_attr "cpu" "zEC12")
(eq_attr "mnemonic" "ddbr")) "nothing")
@@ -578,10 +582,18 @@
(and (eq_attr "cpu" "zEC12")
(eq_attr "mnemonic" "cdtr")) "nothing")
+(define_insn_reservation "zEC12_kdtr" 11
+ (and (eq_attr "cpu" "zEC12")
+ (eq_attr "mnemonic" "kdtr")) "nothing")
+
(define_insn_reservation "zEC12_cxtr" 14
(and (eq_attr "cpu" "zEC12")
(eq_attr "mnemonic" "cxtr")) "nothing")
+(define_insn_reservation "zEC12_kxtr" 14
+ (and (eq_attr "cpu" "zEC12")
+ (eq_attr "mnemonic" "kxtr")) "nothing")
+
(define_insn_reservation "zEC12_slbg" 3
(and (eq_attr "cpu" "zEC12")
(eq_attr "mnemonic" "slbg")) "nothing")
diff --git a/gcc/config/s390/2964.md b/gcc/config/s390/2964.md
index a7897bcf58a..4396e3ba1c0 100644
--- a/gcc/config/s390/2964.md
+++ b/gcc/config/s390/2964.md
@@ -69,7 +69,7 @@ ng,ni,niy,ntstg,ny,o,og,oi,oiy,oy,s,sar,sdb,seb,sfpc,sg,sgf,sh,shy,sl,\
slb,slbg,slg,slgf,sly,sqdb,sqeb,st,stc,stcy,std,stdy,ste,stey,stg,stgrl,\
sth,sthrl,sthy,stoc,stocg,strl,strv,strvg,strvh,sty,sy,tabort,tm,tmy,vl,\
vlbb,vleb,vlef,vleg,vleh,vll,vllezb,vllezf,vllezg,vllezh,vllezlf,vlrepb,\
-vlrepf,vlrepg,vlreph,vst,vstl,x,xg,xi,xiy,xy")
+vlrepf,vlrepg,vlreph,vst,vstl,x,xg,xi,xiy,xy,kdb")
(const_int 1)] (const_int 0)))
(define_attr "z13_unit_vfu" ""
@@ -109,7 +109,8 @@ vuplhh,vuplhw,vupllb,vupllf,vupllh,vx,vzero,wcdgb,wcdlgb,wcgdb,wclgdb,wfadb,\
wfasb,wfaxb,wfcdb,wfcedb,wfcesb,wfcexbs,wfchdb,wfchedb,wfchesb,wfchexb,\
wfchexbs,wfchsb,wfchxb,wfchxbs,wfcsb,wfisb,wfixb,wflcdb,wflcsb,wflcxb,wflld,\
wflndb,wflnsb,wflnxb,wflpdb,wflpsb,wflpxb,wfmadb,wfmasb,wfmaxb,wfmdb,wfmsb,\
-wfmsdb,wfmssb,wfmsxb,wfmxb,wfsdb,wfssb,wfsxb,wldeb,wledb")
+wfmsdb,wfmssb,wfmsxb,wfmxb,wfsdb,wfssb,wfsxb,wldeb,wledb,kebr,kdb,kdbr,kxbr,\
+kdtr,kxtr,wfkdb,wfksb")
(const_int 1)] (const_int 0)))
(define_attr "z13_cracked" ""
@@ -131,7 +132,7 @@ stmg,stmy,tbegin,tbeginc")
cxtr,dlgr,dlr,dr,dsgfr,dsgr,dxbr,dxtr,fixbr,fixbra,fixtr,flogr,lcxbr,lnxbr,\
lpxbr,ltxbr,ltxtr,lxdb,lxdbr,lxdtr,lxeb,lxebr,m,madb,maeb,maebr,mfy,ml,mlg,\
mlgr,mlr,mr,msdb,mseb,msebr,mvc,mxbr,mxtr,oc,sfpc,slb,slbg,slbgr,slbr,\
-sqxbr,sxbr,sxtr,tabort,tcxb,tdcxt,tend,xc")
+sqxbr,sxbr,sxtr,tabort,tcxb,tdcxt,tend,xc,kxbr,kxtr")
(const_int 1)] (const_int 0)))
(define_attr "z13_endgroup" ""
@@ -198,7 +199,7 @@ vchlhs,vfcedbs,vfcesbs,vfchdbs,vfchedbs,vfchesbs,vfchsbs,vfeeb,vfeef,vfeeh,\
vfeneb,vfenef,vfeneh,vfenezb,vfenezf,vfenezh,vftcidb,vftcisb,vistrb,vistrf,\
vistrh,vllezb,vllezf,vllezg,vllezh,vllezlf,vlrepb,vlrepf,vlrepg,vlreph,vlvgp,\
vpklsfs,vpklsgs,vpklshs,vpksfs,vpksgs,vpkshs,vslb,vsrab,vsrlb,wfcdb,wfcexbs,\
-wfchexbs,wfchxbs,wfcsb")) "nothing")
+wfchexbs,wfchxbs,wfcsb,kebr,kdb,kdbr,wfkdb,wfksb")) "nothing")
(define_insn_reservation "z13_3" 3
(and (eq_attr "cpu" "z13")
@@ -232,7 +233,7 @@ wfmdb,wfmsb,wfmsdb,wfmssb,wfmsxb,wfmxb,wfsdb,wfssb,wfsxb,wldeb,wledb")) "nothing
(and (eq_attr "cpu" "z13")
(eq_attr "mnemonic" "adtr,cdtr,fidtr,ldetr,msg,msgr,sdtr,tdcdt,tdcet,\
vcdgb,vcdlgb,vcgdb,vclgdb,vfadb,vfasb,vfidb,vfisb,vfmadb,vfmasb,vfmdb,vfmsb,\
-vfmsdb,vfmssb,vfsdb,vfssb,vldeb,vledb")) "nothing")
+vfmsdb,vfmssb,vfsdb,vfssb,vldeb,vledb,kdtr")) "nothing")
(define_insn_reservation "z13_8" 8
(and (eq_attr "cpu" "z13")
@@ -254,7 +255,7 @@ celgbr,flogr,m,madb,maeb,maebr,mfy,ml,mlr,mr,msdb,mseb,msebr")) "nothing")
(define_insn_reservation "z13_12" 12
(and (eq_attr "cpu" "z13")
(eq_attr "mnemonic" "cfdbr,cfebr,cgdbr,cgebr,clfdbr,clfebr,clgdbr,\
-clgebr,cxbr,cxtr,mlg,mlgr,tcxb,tdcxt")) "nothing")
+clgebr,cxbr,cxtr,mlg,mlgr,tcxb,tdcxt,kxbr,kxtr")) "nothing")
(define_insn_reservation "z13_13" 13
(and (eq_attr "cpu" "z13")
diff --git a/gcc/config/s390/3906.md b/gcc/config/s390/3906.md
index 8cb4565ee22..1212d8b61f1 100644
--- a/gcc/config/s390/3906.md
+++ b/gcc/config/s390/3906.md
@@ -71,7 +71,7 @@ sgh,sh,shy,sl,slb,slbg,slg,slgf,sly,sqdb,sqeb,st,stc,stcy,std,stdy,ste,\
stey,stg,stgrl,sth,sthrl,sthy,stoc,stocg,strl,strv,strvg,strvh,sty,sy,\
tabort,tm,tmy,vl,vlbb,vleb,vlef,vleg,vleh,vll,vllezb,vllezf,vllezg,vllezh,\
vllezlf,vlrepb,vlrepf,vlrepg,vlreph,vlrl,vlrlr,vst,vstl,vstrl,vstrlr,x,xg,xi,\
-xiy,xy")
+xiy,xy,kdb")
(const_int 1)] (const_int 0)))
(define_attr "z14_unit_vfu" ""
@@ -113,7 +113,8 @@ wfadb,wfasb,wfaxb,wfcdb,wfcedb,wfcesb,wfcexbs,wfchdb,wfchedb,wfchesb,\
wfchexb,wfchexbs,wfchsb,wfchxb,wfchxbs,wfcsb,wfisb,wfixb,wflcdb,wflcsb,wflcxb,\
wflld,wflndb,wflnsb,wflnxb,wflpdb,wflpsb,wflpxb,wfmadb,wfmasb,wfmaxb,\
wfmaxxb,wfmdb,wfminxb,wfmsb,wfmsdb,wfmssb,wfmsxb,wfmxb,wfnmaxb,wfnmsxb,wfsdb,\
-wfssb,wfsxb,wldeb,wledb")
+wfssb,wfsxb,wldeb,wledb,kebr,kdb,kdbr,kxbr,kdtr,kxtr,wfkdb,wfksb,vfkesb,\
+vfkedb,vfkhsb,vfkhdb,wfkhxb,vfkhesb,vfkhedb,wfkhexb")
(const_int 1)] (const_int 0)))
(define_attr "z14_cracked" ""
@@ -135,7 +136,7 @@ stmg,stmy,tbegin,tbeginc")
cxtr,dlgr,dlr,dr,dsgfr,dsgr,dxbr,dxtr,fixbr,fixbra,fixtr,flogr,lcxbr,lnxbr,\
lpxbr,ltxbr,ltxtr,lxdb,lxdbr,lxdtr,lxeb,lxebr,m,madb,maeb,maebr,mfy,mg,mgrk,\
ml,mlg,mlgr,mlr,mr,msdb,mseb,msebr,mvc,mxbr,mxtr,oc,ppa,sfpc,slb,slbg,\
-slbgr,slbr,sqxbr,sxbr,sxtr,tabort,tcxb,tdcxt,tend,xc")
+slbgr,slbr,sqxbr,sxbr,sxtr,tabort,tcxb,tdcxt,tend,xc,kxbr,kxtr")
(const_int 1)] (const_int 0)))
(define_attr "z14_endgroup" ""
@@ -192,7 +193,8 @@ vrepig,vrepih,vsb,vsbiq,vscbib,vscbif,vscbig,vscbih,vscbiq,vsegb,vsegf,vsegh,\
vsel,vsf,vsg,vsh,vsl,vslb,vsldb,vsq,vsra,vsrab,vsrl,vsrlb,vuphb,vuphf,\
vuphh,vuplb,vuplf,vuplhb,vuplhf,vuplhh,vuplhw,vupllb,vupllf,vupllh,vx,vzero,\
wfcedb,wfcesb,wfchdb,wfchedb,wfchesb,wfchexb,wfchsb,wfchxb,wflcdb,wflcsb,\
-wflcxb,wflndb,wflnsb,wflnxb,wflpdb,wflpsb,wflpxb,wfmaxxb,wfminxb,xi,xiy")) "nothing")
+wflcxb,wflndb,wflnsb,wflnxb,wflpdb,wflpsb,wflpxb,wfmaxxb,wfminxb,xi,xiy,\
+vfkesb,vfkedb,vfkhsb,vfkhdb,wfkhxb,vfkhesb,vfkhedb,wfkhexb")) "nothing")
(define_insn_reservation "z14_2" 2
(and (eq_attr "cpu" "z14")
@@ -204,7 +206,7 @@ vchlhs,vfcedbs,vfcesbs,vfchdbs,vfchedbs,vfchesbs,vfchsbs,vfeeb,vfeef,vfeeh,\
vfeneb,vfenef,vfeneh,vfenezb,vfenezf,vfenezh,vftcidb,vftcisb,vistrb,vistrf,\
vistrh,vlgvf,vlgvg,vlgvh,vllezb,vllezf,vllezg,vllezh,vllezlf,vlrepb,vlrepf,\
vlrepg,vlreph,vlrl,vlvgp,vpklsfs,vpklsgs,vpklshs,vpksfs,vpksgs,vpkshs,wfcdb,\
-wfcexbs,wfchexbs,wfchxbs,wfcsb")) "nothing")
+wfcexbs,wfchexbs,wfchxbs,wfcsb,kebr,kdb,kdbr,wfkdb,wfksb")) "nothing")
(define_insn_reservation "z14_3" 3
(and (eq_attr "cpu" "z14")
@@ -238,7 +240,8 @@ wfmasb,wfmdb,wfmsb,wfmsdb,wfmssb,wfsdb,wfssb,wldeb,wledb")) "nothing")
(define_insn_reservation "z14_7" 7
(and (eq_attr "cpu" "z14")
(eq_attr "mnemonic" "adtr,cdtr,fidtr,ldetr,msgrkc,sdtr,tdcdt,tdcet,\
-vfasb,vfisb,vfmasb,vfmsb,vfmssb,vfnmssb,vfssb,vgef,vgeg,wflld")) "nothing")
+vfasb,vfisb,vfmasb,vfmsb,vfmssb,vfnmssb,vfssb,vgef,vgeg,wflld,kdtr"))
+"nothing")
(define_insn_reservation "z14_8" 8
(and (eq_attr "cpu" "z14")
@@ -261,7 +264,7 @@ celgbr,madb,maeb,maebr,msdb,mseb,msebr,vscef,vsceg")) "nothing")
(define_insn_reservation "z14_12" 12
(and (eq_attr "cpu" "z14")
(eq_attr "mnemonic" "cfdbr,cfebr,cgdbr,cgebr,clfdbr,clfebr,clgdbr,\
-clgebr,cxbr,cxtr,tcxb,tdcxt")) "nothing")
+clgebr,cxbr,cxtr,tcxb,tdcxt,kxbr,kxtr")) "nothing")
(define_insn_reservation "z14_13" 13
(and (eq_attr "cpu" "z14")
diff --git a/gcc/config/s390/8561.md b/gcc/config/s390/8561.md
index e5a345f4dba..6bb0386e780 100644
--- a/gcc/config/s390/8561.md
+++ b/gcc/config/s390/8561.md
@@ -1,4 +1,4 @@
-;; Scheduling description for arch13.
+;; Scheduling description for z15.
;; Copyright (C) 2019 Free Software Foundation, Inc.
;; Contributed by Robin Dapp (rdapp@linux.ibm.com)
;; This file is part of GCC.
@@ -17,12 +17,12 @@
;; along with GCC; see the file COPYING3. If not see
;; <http://www.gnu.org/licenses/>.
-(define_attr "arch13_unit_fpd" ""
+(define_attr "z15_unit_fpd" ""
(cond [(eq_attr "mnemonic" "ddb,ddbr,deb,debr,dxbr,sqdb,sqdbr,sqeb,\
sqebr,sqxbr,vfddb,vfdsb,vfsqdb,vfsqsb,wfddb,wfdsb,wfdxb,wfsqdb,wfsqxb")
(const_int 1)] (const_int 0)))
-(define_attr "arch13_unit_fxa" ""
+(define_attr "z15_unit_fxa" ""
(cond [(eq_attr "mnemonic" "a,afi,ag,agf,agfi,agfr,agh,aghi,aghik,\
agr,agrk,ah,ahi,ahik,ahy,al,alc,alcg,alcgr,alcr,alfi,alg,algf,algfi,algfr,\
alghsik,algr,algrk,alhsik,alr,alrk,aly,ar,ark,ay,bras,brasl,etnd,exrl,flogr,\
@@ -39,7 +39,7 @@ slgrk,sll,sllg,sllk,slr,slrk,sly,sr,sra,srag,srak,srk,srl,srlg,srlk,sy,x,xg,\
xgr,xgrk,xihf,xilf,xr,xrk,xy")
(const_int 1)] (const_int 0)))
-(define_attr "arch13_unit_fxb" ""
+(define_attr "z15_unit_fxb" ""
(cond [(eq_attr "mnemonic" "agsi,algsi,alsi,asi,b,bc,bcr,bi,br,brcl,\
c,cfi,cg,cgf,cgfi,cgfr,cgfrl,cgh,cghi,cghrl,cghsi,cgit,cgr,cgrl,cgrt,ch,\
chi,chrl,chsi,chy,cit,cl,clfhsi,clfi,clfit,clg,clgf,clgfi,clgfr,clgfrl,\
@@ -52,11 +52,11 @@ tmhl,tml,tmlh,tmll,tmy,vlgvb,vlgvf,vlgvg,vlgvh,vlr,vlvgb,vlvgf,vlvgg,vlvgh,\
vlvgp,vst,vstef,vsteg,vstl,vstrl,vstrlr,xi,xiy")
(const_int 1)] (const_int 0)))
-(define_attr "arch13_unit_fxd" ""
+(define_attr "z15_unit_fxd" ""
(cond [(eq_attr "mnemonic" "dlgr,dlr,dr,dsgfr,dsgr")
(const_int 1)] (const_int 0)))
-(define_attr "arch13_unit_lsu" ""
+(define_attr "z15_unit_lsu" ""
(cond [(eq_attr "mnemonic" "a,adb,aeb,ag,agf,agh,agsi,ah,ahy,al,alc,\
alcg,alg,algf,algsi,alsi,aly,asi,ay,c,cdb,ceb,cg,cgf,cgfrl,cgh,cghrl,cghsi,\
cgrl,ch,chrl,chsi,chy,cl,clc,clfhsi,clg,clgf,clgfrl,clghrl,clghsi,clgrl,\
@@ -70,10 +70,10 @@ sar,sdb,seb,sfpc,sg,sgf,sgh,sh,shy,sl,slb,slbg,slg,slgf,sly,sqdb,sqeb,st,\
stc,stcy,std,stdy,ste,stey,stg,stgrl,sth,sthrl,sthy,stoc,stocg,strl,strv,\
strvg,strvh,sty,sy,tabort,tm,tmy,vl,vlbb,vleb,vlef,vleg,vleh,vll,vllezb,\
vllezf,vllezg,vllezh,vllezlf,vlrepb,vlrepf,vlrepg,vlreph,vlrl,vlrlr,vst,\
-vstef,vsteg,vstl,vstrl,vstrlr,x,xg,xi,xiy,xy")
+vstef,vsteg,vstl,vstrl,vstrlr,x,xg,xi,xiy,xy,keb,kdb")
(const_int 1)] (const_int 0)))
-(define_attr "arch13_unit_vfu" ""
+(define_attr "z15_unit_vfu" ""
(cond [(eq_attr "mnemonic" "adb,adbr,adtr,aeb,aebr,axbr,axtr,cdb,\
cdbr,cdtr,ceb,cebr,cpsdr,cxbr,cxtr,ddtr,dxtr,fidbr,fidbra,fidtr,fiebr,\
fiebra,fixbr,fixbra,fixtr,lcdbr,lcebr,lcxbr,ldeb,ldebr,ldetr,le,ledbr,ledtr,\
@@ -112,10 +112,12 @@ vupllf,vupllh,vx,vzero,wfadb,wfasb,wfaxb,wfcdb,wfcedb,wfcesb,wfcexb,wfcexbs,\
wfchdb,wfchedb,wfchesb,wfchexb,wfchexbs,wfchsb,wfchxb,wfchxbs,wfcsb,wfidb,\
wfisb,wfixb,wflcdb,wflcsb,wflcxb,wflld,wflndb,wflnsb,wflnxb,wflpdb,wflpsb,\
wflpxb,wfmadb,wfmasb,wfmaxb,wfmaxxb,wfmdb,wfminxb,wfmsb,wfmsdb,wfmssb,wfmsxb,\
-wfmxb,wfnmaxb,wfnmsxb,wfsdb,wfssb,wfsxb,wldeb,wledb")
+wfmxb,wfnmaxb,wfnmsxb,wfsdb,wfssb,wfsxb,wldeb,wledb,keb,kebr,kdb,kdbr,kxbr,\
+kdtr,kxtr,wfkdb,wfksb,vfkesb,vfkedb,wfkexb,vfkhsb,vfkhdb,wfkhxb,vfkhesb,\
+vfkhedb,wfkhexb")
(const_int 1)] (const_int 0)))
-(define_attr "arch13_cracked" ""
+(define_attr "z15_cracked" ""
(cond [(eq_attr "mnemonic" "bas,basr,cdfbr,cdftr,cdgbr,cdgtr,cdlfbr,\
cdlftr,cdlgbr,cdlgtr,cefbr,cegbr,celfbr,celgbr,cfdbr,cfebr,cfxbr,cgdbr,cgdtr,\
cgebr,cgxbr,cgxtr,chhsi,clfdbr,clfdtr,clfebr,clfxbr,clfxtr,clgdbr,clgdtr,\
@@ -123,25 +125,25 @@ clgebr,clgxbr,clgxtr,cs,csg,csy,d,efpc,ex,lcgfr,lngfr,lpgfr,lpq,lxr,lzxr,\
rxsbg,stpq,vgef,vgeg,vscef,vsceg,vsteb,vsteh")
(const_int 1)] (const_int 0)))
-(define_attr "arch13_expanded" ""
+(define_attr "z15_expanded" ""
(cond [(eq_attr "mnemonic" "cds,cdsg,cdsy,cxfbr,cxftr,cxgbr,cxgtr,\
cxlfbr,cxlftr,cxlgbr,cxlgtr,dl,dlg,dsg,dsgf,lam,lm,lmg,lmy,sldl,srda,srdl,\
stam,stm,stmg,stmy,tbegin,tbeginc")
(const_int 1)] (const_int 0)))
-(define_attr "arch13_groupalone" ""
+(define_attr "z15_groupalone" ""
(cond [(eq_attr "mnemonic" "alc,alcg,alcgr,alcr,axbr,axtr,clc,cxbr,\
cxtr,dlgr,dlr,dr,dsgfr,dsgr,dxbr,dxtr,fixbr,fixbra,fixtr,flogr,lcxbr,lnxbr,\
lpxbr,ltxbr,ltxtr,lxdb,lxdbr,lxdtr,lxeb,lxebr,m,madb,maeb,maebr,mfy,mg,mgrk,\
ml,mlg,mlgr,mlr,mr,msdb,mseb,msebr,mvc,mxbr,mxtr,nc,oc,ppa,sfpc,slb,slbg,\
-slbgr,slbr,sqxbr,sxbr,sxtr,tabort,tcxb,tdcxt,tend,xc")
+slbgr,slbr,sqxbr,sxbr,sxtr,tabort,tcxb,tdcxt,tend,xc,kxbr,kxtr")
(const_int 1)] (const_int 0)))
-(define_attr "arch13_endgroup" ""
+(define_attr "z15_endgroup" ""
(cond [(eq_attr "mnemonic" "bras,brasl,exrl,ipm")
(const_int 1)] (const_int 0)))
-(define_attr "arch13_groupoftwo" ""
+(define_attr "z15_groupoftwo" ""
(cond [(eq_attr "mnemonic" "vacccq,vacq,vfmadb,vfmasb,vfmsdb,vfmssb,\
vfnmadb,vfnmasb,vfnmsdb,vfnmssb,vgfmab,vgfmaf,vgfmag,vgfmah,vmaeb,vmaef,vmaeh,\
vmahb,vmahf,vmahh,vmalb,vmaleb,vmalef,vmaleh,vmalf,vmalhb,vmalhf,vmalhh,\
@@ -149,8 +151,8 @@ vmalhw,vmalob,vmalof,vmaloh,vmaob,vmaof,vmaoh,vmslg,vperm,vsbcbiq,vsbiq,vsel,\
wfmadb,wfmasb,wfmaxb,wfmsdb,wfmssb,wfmsxb,wfnmaxb,wfnmsxb")
(const_int 1)] (const_int 0)))
-(define_insn_reservation "arch13_0" 0
- (and (eq_attr "cpu" "arch13")
+(define_insn_reservation "z15_0" 0
+ (and (eq_attr "cpu" "z15")
(eq_attr "mnemonic" "a,afi,ag,agfi,aghi,aghik,agr,agrk,ahi,ahik,al,\
alfi,alg,algf,algfi,algfr,alghsik,algr,algrk,alhsik,alr,alrk,aly,ar,ark,ay,\
b,bc,bcr,bi,br,bras,brasl,brcl,c,cfi,cg,cgfi,cghi,cghsi,cgit,cgr,cgrl,\
@@ -168,8 +170,8 @@ sllk,slr,slrk,sly,sr,sra,srag,srak,srda,srdl,srk,srl,srlg,srlk,sy,tm,tmh,\
tmhh,tmhl,tml,tmlh,tmll,tmy,vlr,vlvgb,vlvgf,vlvgg,vlvgh,x,xg,xgr,xgrk,xihf,\
xilf,xr,xrk,xy")) "nothing")
-(define_insn_reservation "arch13_1" 1
- (and (eq_attr "cpu" "arch13")
+(define_insn_reservation "z15_1" 1
+ (and (eq_attr "cpu" "z15")
(eq_attr "mnemonic" "agf,agfr,agh,agsi,ah,ahy,algsi,alsi,asi,cgf,\
cgfr,cgfrl,cgh,cghrl,ch,chrl,chy,clm,clmy,cpsdr,laa,laag,lan,lang,lao,laog,\
lax,laxg,le,ler,ley,loc,locg,locghi,locgr,lochi,locr,mvghi,mvhhi,mvhi,mvi,\
@@ -194,10 +196,11 @@ vsel,vsf,vsg,vsh,vsl,vslb,vsldb,vsq,vsra,vsrab,vsrl,vsrlb,vuphb,vuphf,\
vuphh,vuplb,vuplf,vuplhb,vuplhf,vuplhh,vuplhw,vupllb,vupllf,vupllh,vx,vzero,\
wfcedb,wfcesb,wfcexb,wfchdb,wfchedb,wfchesb,wfchexb,wfchsb,wfchxb,wflcdb,\
wflcsb,wflcxb,wflndb,wflnsb,wflnxb,wflpdb,wflpsb,wflpxb,wfmaxxb,wfminxb,xi,\
-xiy")) "nothing")
+xiy,vfkesb,vfkedb,wfkexb,vfkhsb,vfkhdb,wfkhxb,vfkhesb,vfkhedb,wfkhexb"))
+"nothing")
-(define_insn_reservation "arch13_2" 2
- (and (eq_attr "cpu" "arch13")
+(define_insn_reservation "z15_2" 2
+ (and (eq_attr "cpu" "z15")
(eq_attr "mnemonic" "cdb,cdbr,ceb,cebr,ear,ipm,l,lcbb,lcdbr,lcebr,ld,\
lde,ldy,lg,lgdr,lgrl,llc,llgc,llgf,llgfrl,llgh,llghrl,llgt,llh,llhrl,lm,\
lmg,lmy,lndbr,lnebr,lpdbr,lpebr,lrl,ltdbr,ltebr,ly,popcnt,sar,tcdb,tceb,\
@@ -206,10 +209,11 @@ vchlhs,vfcedbs,vfcesbs,vfchdbs,vfchedbs,vfchesbs,vfchsbs,vfeeb,vfeef,vfeeh,\
vfeneb,vfenef,vfeneh,vfenezb,vfenezf,vfenezh,vftcidb,vftcisb,vistrb,vistrf,\
vistrh,vlgvb,vlgvf,vlgvg,vlgvh,vllezb,vllezf,vllezg,vllezh,vllezlf,vlrepb,\
vlrepf,vlrepg,vlreph,vlrl,vlvgp,vpklsfs,vpklsgs,vpklshs,vpksfs,vpksgs,vpkshs,\
-wfcdb,wfcexbs,wfchexbs,wfchxbs,wfcsb")) "nothing")
+wfcdb,wfcexbs,wfchexbs,wfchxbs,wfcsb,keb,kebr,kdb,kdbr,wfkdb,wfksb"))
+"nothing")
-(define_insn_reservation "arch13_3" 3
- (and (eq_attr "cpu" "arch13")
+(define_insn_reservation "z15_3" 3
+ (and (eq_attr "cpu" "z15")
(eq_attr "mnemonic" "cds,cdsy,mgh,mghi,mh,mhi,mhy,std,stdy,ste,stey,\
vcksm,vfeezbs,vfeezfs,vfeezhs,vgfmab,vgfmaf,vgfmag,vgfmah,vgfmb,vgfmf,vgfmg,\
vgfmh,vistrbs,vistrfs,vistrhs,vl,vlbb,vll,vlrlr,vmaeb,vmaef,vmaeh,vmahb,\
@@ -218,14 +222,14 @@ vmalob,vmalof,vmaloh,vmaob,vmaof,vmaoh,vmeb,vmef,vmeh,vmhb,vmhf,vmhh,vmlb,\
vmleb,vmlef,vmleh,vmlf,vmlhb,vmlhf,vmlhh,vmlhw,vmlob,vmlof,vmloh,vmob,vmof,\
vmoh,vsumb,vsumgf,vsumgh,vsumh,vsumqf,vsumqg,vtm")) "nothing")
-(define_insn_reservation "arch13_4" 4
- (and (eq_attr "cpu" "arch13")
+(define_insn_reservation "z15_4" 4
+ (and (eq_attr "cpu" "z15")
(eq_attr "mnemonic" "bas,basr,chhsi,clc,ex,lam,lcgfr,lngfr,lpgfr,lxr,\
lzxr,ms,msfi,msgf,msgfi,msgfr,msr,msy,mvc,nc,oc,ppa,rxsbg,tabort,tbegin,\
tbeginc,tend,vst,vstef,vsteg,vstl,vstrl,vstrlr,xc")) "nothing")
-(define_insn_reservation "arch13_5" 5
- (and (eq_attr "cpu" "arch13")
+(define_insn_reservation "z15_5" 5
+ (and (eq_attr "cpu" "z15")
(eq_attr "mnemonic" "adb,adbr,aeb,aebr,alc,alcg,alcgr,alcr,cs,csg,\
csy,fidbr,fidbra,fiebr,fiebra,ldeb,ldebr,ledbr,madbr,mdb,mdbr,meeb,meebr,\
msdbr,msrkc,sdb,sdbr,seb,sebr,slb,slbg,slbgr,slbr,stm,stmg,stmy,vfadb,vfasb,\
@@ -233,53 +237,54 @@ vfidb,vfisb,vfmadb,vfmasb,vfmdb,vfmsb,vfmsdb,vfmssb,vfnmadb,vfnmasb,vfnmsdb,\
vfnmssb,vfsdb,vfssb,vldeb,vledb,vmslg,wfadb,wfasb,wfidb,wfisb,wflld,wfmadb,\
wfmasb,wfmdb,wfmsb,wfmsdb,wfmssb,wfsdb,wfssb,wldeb,wledb")) "nothing")
-(define_insn_reservation "arch13_6" 6
- (and (eq_attr "cpu" "arch13")
+(define_insn_reservation "z15_6" 6
+ (and (eq_attr "cpu" "z15")
(eq_attr "mnemonic" "msg,msgr,sfpc")) "nothing")
-(define_insn_reservation "arch13_7" 7
- (and (eq_attr "cpu" "arch13")
+(define_insn_reservation "z15_7" 7
+ (and (eq_attr "cpu" "z15")
(eq_attr "mnemonic" "adtr,cdtr,fidtr,ldetr,ltdtr,msgrkc,sdtr,tdcdt,\
-tdcet,vgef,vgeg")) "nothing")
+tdcet,vgef,vgeg,kdtr")) "nothing")
-(define_insn_reservation "arch13_8" 8
- (and (eq_attr "cpu" "arch13")
+(define_insn_reservation "z15_8" 8
+ (and (eq_attr "cpu" "z15")
(eq_attr "mnemonic" "cdsg,flogr,lpq,stpq,vsteb,vsteh")) "nothing")
-(define_insn_reservation "arch13_9" 9
- (and (eq_attr "cpu" "arch13")
+(define_insn_reservation "z15_9" 9
+ (and (eq_attr "cpu" "z15")
(eq_attr "mnemonic" "cdfbr,cdgbr,cdlfbr,cdlgbr,cefbr,cegbr,celfbr,\
celgbr,cxfbr,cxgbr,cxlfbr,cxlgbr,m,madb,maeb,maebr,mfy,ml,mlr,mr,msdb,mseb,\
msebr,stam,wfaxb,wfixb,wfsxb")) "nothing")
-(define_insn_reservation "arch13_10" 10
- (and (eq_attr "cpu" "arch13")
+(define_insn_reservation "z15_10" 10
+ (and (eq_attr "cpu" "z15")
(eq_attr "mnemonic" "lxdb,lxdbr,lxeb,lxebr,vscef,vsceg")) "nothing")
-(define_insn_reservation "arch13_11" 11
- (and (eq_attr "cpu" "arch13")
+(define_insn_reservation "z15_11" 11
+ (and (eq_attr "cpu" "z15")
(eq_attr "mnemonic" "cfdbr,cfebr,cgdbr,cgebr,clfdbr,clfebr,clgdbr,\
clgebr,mg,mgrk,mlg,mlgr")) "nothing")
-(define_insn_reservation "arch13_12" 12
- (and (eq_attr "cpu" "arch13")
-(eq_attr "mnemonic" "cxbr,cxftr,cxlftr,cxtr,tcxb,tdcxt")) "nothing")
+(define_insn_reservation "z15_12" 12
+ (and (eq_attr "cpu" "z15")
+(eq_attr "mnemonic" "cxbr,cxftr,cxlftr,cxtr,tcxb,tdcxt,kxbr,kxtr"))
+"nothing")
-(define_insn_reservation "arch13_13" 13
- (and (eq_attr "cpu" "arch13")
+(define_insn_reservation "z15_13" 13
+ (and (eq_attr "cpu" "z15")
(eq_attr "mnemonic" "axbr,axtr,fixbr,fixbra,fixtr,lcxbr,lnxbr,lpxbr,\
ltxbr,ltxtr,lxdtr,sxbr,sxtr")) "nothing")
-(define_insn_reservation "arch13_14" 14
- (and (eq_attr "cpu" "arch13")
+(define_insn_reservation "z15_14" 14
+ (and (eq_attr "cpu" "z15")
(eq_attr "mnemonic" "cfxbr,cgxbr,clfxbr,clgxbr,ledtr")) "nothing")
-(define_insn_reservation "arch13_16" 16
- (and (eq_attr "cpu" "arch13")
+(define_insn_reservation "z15_16" 16
+ (and (eq_attr "cpu" "z15")
(eq_attr "mnemonic" "cdftr,cdlftr")) "nothing")
-(define_insn_reservation "arch13_20" 20
- (and (eq_attr "cpu" "arch13")
+(define_insn_reservation "z15_20" 20
+ (and (eq_attr "cpu" "z15")
(eq_attr "mnemonic" "cdgtr,cdlgtr,cgdtr,cgxtr,clfdtr,clfxtr,clgdtr,\
clgxtr,cxgtr,cxlgtr,d,ddb,ddbr,ddtr,deb,debr,dl,dlg,dlgr,dlr,dr,dsg,dsgf,\
dsgfr,dsgr,dxbr,dxtr,efpc,mdtr,mxbr,mxtr,sqdb,sqdbr,sqeb,sqebr,sqxbr,vfddb,\
diff --git a/gcc/config/s390/driver-native.c b/gcc/config/s390/driver-native.c
index a386d633a87..6bc7d590668 100644
--- a/gcc/config/s390/driver-native.c
+++ b/gcc/config/s390/driver-native.c
@@ -121,10 +121,10 @@ s390_host_detect_local_cpu (int argc, const char **argv)
break;
case 0x8561:
case 0x8562:
- cpu = "arch13";
+ cpu = "z15";
break;
default:
- cpu = "arch13";
+ cpu = "z15";
break;
}
}
diff --git a/gcc/config/s390/s390-builtins.def b/gcc/config/s390/s390-builtins.def
index cfc69651b0d..a6519dae3a0 100644
--- a/gcc/config/s390/s390-builtins.def
+++ b/gcc/config/s390/s390-builtins.def
@@ -281,7 +281,7 @@
#define B_HTM (1 << 1) /* Builtins requiring the transactional execution facility. */
#define B_VX (1 << 2) /* Builtins requiring the z13 vector extensions. */
#define B_VXE (1 << 3) /* Builtins requiring the z14 vector extensions. */
-#define B_VXE2 (1 << 4) /* Builtins requiring the arch13 vector extensions. */
+#define B_VXE2 (1 << 4) /* Builtins requiring the z15 vector extensions. */
#define B_DEP (1 << 5) /* Builtin has been deprecated and a warning should be issued. */
/* B_DEF defines a standard (not overloaded) builtin
@@ -1495,8 +1495,8 @@ B_DEF (vec_cmpgev4si, vec_cmpgev4si, 0,
B_DEF (vec_cmpgeuv4si, vec_cmpgeuv4si, 0, B_INT | B_VX, 0, BT_FN_V4SI_UV4SI_UV4SI)
B_DEF (vec_cmpgev2di, vec_cmpgev2di, 0, B_INT | B_VX, 0, BT_FN_V2DI_UV2DI_UV2DI)
B_DEF (vec_cmpgeuv2di, vec_cmpgeuv2di, 0, B_INT | B_VX, 0, BT_FN_V2DI_UV2DI_UV2DI)
-B_DEF (s390_vfchesb, vec_cmpgev4sf, 0, B_VXE, 0, BT_FN_V4SI_V4SF_V4SF)
-B_DEF (s390_vfchedb, vec_cmpgev2df, 0, B_VX, 0, BT_FN_V2DI_V2DF_V2DF)
+B_DEF (s390_vfchesb, vec_cmpgev4sf_quiet_nocc,0, B_VXE, 0, BT_FN_V4SI_V4SF_V4SF)
+B_DEF (s390_vfchedb, vec_cmpgev2df_quiet_nocc,0, B_VX, 0, BT_FN_V2DI_V2DF_V2DF)
OB_DEF (s390_vec_cmpgt, s390_vec_cmpgt_s8, s390_vec_cmpgt_dbl, B_VX, BT_FN_OV4SI_OV4SI_OV4SI)
OB_DEF_VAR (s390_vec_cmpgt_s8, s390_vchb, 0, 0, BT_OV_BV16QI_V16QI_V16QI)
@@ -1518,8 +1518,8 @@ B_DEF (s390_vchf, vec_cmpgtv4si, 0,
B_DEF (s390_vchlf, vec_cmpgtuv4si, 0, B_VX, 0, BT_FN_V4SI_UV4SI_UV4SI)
B_DEF (s390_vchg, vec_cmpgtv2di, 0, B_VX, 0, BT_FN_V2DI_V2DI_V2DI)
B_DEF (s390_vchlg, vec_cmpgtuv2di, 0, B_VX, 0, BT_FN_V2DI_UV2DI_UV2DI)
-B_DEF (s390_vfchsb, vec_cmpgtv4sf, 0, B_VXE, 0, BT_FN_V4SI_V4SF_V4SF)
-B_DEF (s390_vfchdb, vec_cmpgtv2df, 0, B_VX, 0, BT_FN_V2DI_V2DF_V2DF)
+B_DEF (s390_vfchsb, vec_cmpgtv4sf_quiet_nocc,0, B_VXE, 0, BT_FN_V4SI_V4SF_V4SF)
+B_DEF (s390_vfchdb, vec_cmpgtv2df_quiet_nocc,0, B_VX, 0, BT_FN_V2DI_V2DF_V2DF)
OB_DEF (s390_vec_cmple, s390_vec_cmple_s8, s390_vec_cmple_dbl, B_VX, BT_FN_OV4SI_OV4SI_OV4SI)
OB_DEF_VAR (s390_vec_cmple_s8, vec_cmplev16qi, 0, 0, BT_OV_BV16QI_V16QI_V16QI)
@@ -1541,8 +1541,8 @@ B_DEF (vec_cmplev4si, vec_cmplev4si, 0,
B_DEF (vec_cmpleuv4si, vec_cmpleuv4si, 0, B_INT | B_VX, 0, BT_FN_V4SI_UV4SI_UV4SI)
B_DEF (vec_cmplev2di, vec_cmplev2di, 0, B_INT | B_VX, 0, BT_FN_V2DI_UV2DI_UV2DI)
B_DEF (vec_cmpleuv2di, vec_cmpleuv2di, 0, B_INT | B_VX, 0, BT_FN_V2DI_UV2DI_UV2DI)
-B_DEF (vec_cmplev4sf, vec_cmplev4sf, 0, B_INT | B_VXE, 0, BT_FN_V4SI_V4SF_V4SF)
-B_DEF (vec_cmplev2df, vec_cmplev2df, 0, B_INT | B_VX, 0, BT_FN_V2DI_V2DF_V2DF)
+B_DEF (vec_cmplev4sf, vec_cmplev4sf_quiet_nocc,0, B_INT | B_VXE, 0, BT_FN_V4SI_V4SF_V4SF)
+B_DEF (vec_cmplev2df, vec_cmplev2df_quiet_nocc,0, B_INT | B_VX, 0, BT_FN_V2DI_V2DF_V2DF)
OB_DEF (s390_vec_cmplt, s390_vec_cmplt_s8, s390_vec_cmplt_dbl, B_VX, BT_FN_OV4SI_OV4SI_OV4SI)
OB_DEF_VAR (s390_vec_cmplt_s8, vec_cmpltv16qi, 0, 0, BT_OV_BV16QI_V16QI_V16QI)
@@ -1564,8 +1564,8 @@ B_DEF (vec_cmpltv4si, vec_cmpltv4si, 0,
B_DEF (vec_cmpltuv4si, vec_cmpltuv4si, 0, B_INT | B_VX, 0, BT_FN_V4SI_UV4SI_UV4SI)
B_DEF (vec_cmpltv2di, vec_cmpltv2di, 0, B_INT | B_VX, 0, BT_FN_V2DI_UV2DI_UV2DI)
B_DEF (vec_cmpltuv2di, vec_cmpltuv2di, 0, B_INT | B_VX, 0, BT_FN_V2DI_UV2DI_UV2DI)
-B_DEF (vec_cmpltv4sf, vec_cmpltv4sf, 0, B_INT | B_VXE, 0, BT_FN_V4SI_V4SF_V4SF)
-B_DEF (vec_cmpltv2df, vec_cmpltv2df, 0, B_INT | B_VX, 0, BT_FN_V2DI_V2DF_V2DF)
+B_DEF (vec_cmpltv4sf, vec_cmpltv4sf_quiet_nocc,0, B_INT | B_VXE, 0, BT_FN_V4SI_V4SF_V4SF)
+B_DEF (vec_cmpltv2df, vec_cmpltv2df_quiet_nocc,0, B_INT | B_VX, 0, BT_FN_V2DI_V2DF_V2DF)
OB_DEF (s390_vec_cntlz, s390_vec_cntlz_s8, s390_vec_cntlz_u64, B_VX, BT_FN_OV4SI_OV4SI)
OB_DEF_VAR (s390_vec_cntlz_s8, s390_vclzb, 0, 0, BT_OV_UV16QI_V16QI)
diff --git a/gcc/config/s390/s390-c.c b/gcc/config/s390/s390-c.c
index fd98a392517..629c79dbdbd 100644
--- a/gcc/config/s390/s390-c.c
+++ b/gcc/config/s390/s390-c.c
@@ -905,6 +905,12 @@ s390_resolve_overloaded_builtin (location_t loc,
return error_mark_node;
}
+ if (!TARGET_VXE2 && (ob_flags & B_VXE2))
+ {
+ error_at (loc, "%qF requires z15 or higher", ob_fndecl);
+ return error_mark_node;
+ }
+
ob_fcode -= S390_BUILTIN_MAX;
for (b_arg_chain = TYPE_ARG_TYPES (TREE_TYPE (ob_fndecl));
@@ -983,6 +989,15 @@ s390_resolve_overloaded_builtin (location_t loc,
return error_mark_node;
}
+
+ if (!TARGET_VXE2
+ && bflags_overloaded_builtin_var[last_match_index] & B_VXE2)
+ {
+ error_at (loc, "%qs matching variant requires z15 or higher",
+ IDENTIFIER_POINTER (DECL_NAME (ob_fndecl)));
+ return error_mark_node;
+ }
+
if (bflags_overloaded_builtin_var[last_match_index] & B_DEP)
warning_at (loc, 0, "%qs matching variant is deprecated.",
IDENTIFIER_POINTER (DECL_NAME (ob_fndecl)));
diff --git a/gcc/config/s390/s390-modes.def b/gcc/config/s390/s390-modes.def
index 7b7c1141449..a5e8b94f7c3 100644
--- a/gcc/config/s390/s390-modes.def
+++ b/gcc/config/s390/s390-modes.def
@@ -52,6 +52,8 @@ CCS: EQ LT GT UNORDERED (LTGFR, LTGR, LTR, ICM/Y,
ADB/R, AEB/R, SDB/R, SEB/R,
SRAG, SRA, SRDA)
CCSR: EQ GT LT UNORDERED (CGF/R, CH/Y)
+CCSFPS: EQ LT GT UNORDERED (KEB/R, KDB/R, KXBR, KDTR,
+ KXTR, WFK)
Condition codes resulting from add with overflow
@@ -140,6 +142,11 @@ around. The following both modes can be considered as CCS and CCU modes with
exchanged operands.
+CCSFPS
+
+This mode is used for signaling rtxes: LT, LE, GT, GE and LTGT.
+
+
CCL1, CCL2
These modes represent the result of overflow checks.
@@ -226,6 +233,7 @@ CC_MODE (CCU);
CC_MODE (CCUR);
CC_MODE (CCS);
CC_MODE (CCSR);
+CC_MODE (CCSFPS);
CC_MODE (CCT);
CC_MODE (CCT1);
CC_MODE (CCT2);
diff --git a/gcc/config/s390/s390-opts.h b/gcc/config/s390/s390-opts.h
index ab41cb883f3..502edea719b 100644
--- a/gcc/config/s390/s390-opts.h
+++ b/gcc/config/s390/s390-opts.h
@@ -37,7 +37,7 @@ enum processor_type
PROCESSOR_2827_ZEC12,
PROCESSOR_2964_Z13,
PROCESSOR_3906_Z14,
- PROCESSOR_8561_ARCH13,
+ PROCESSOR_8561_Z15,
PROCESSOR_NATIVE,
PROCESSOR_max
};
diff --git a/gcc/config/s390/s390-protos.h b/gcc/config/s390/s390-protos.h
index ae70b2fee18..f760f152932 100644
--- a/gcc/config/s390/s390-protos.h
+++ b/gcc/config/s390/s390-protos.h
@@ -146,6 +146,7 @@ extern int s390_branch_condition_mask (rtx);
extern int s390_compare_and_branch_condition_mask (rtx);
extern bool s390_extzv_shift_ok (int, int, unsigned HOST_WIDE_INT);
extern void s390_asm_output_function_label (FILE *, const char *, tree);
+extern void s390_output_split_stack_data (rtx, rtx, rtx, rtx);
enum s390_indirect_branch_type
{
diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index 062cbd8099d..9fed7d3b99f 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -337,7 +337,7 @@ const struct s390_processor processor_table[] =
{ "zEC12", "zEC12", PROCESSOR_2827_ZEC12, &zEC12_cost, 10 },
{ "z13", "z13", PROCESSOR_2964_Z13, &zEC12_cost, 11 },
{ "z14", "arch12", PROCESSOR_3906_Z14, &zEC12_cost, 12 },
- { "arch13", "", PROCESSOR_8561_ARCH13, &zEC12_cost, 13 },
+ { "z15", "arch13", PROCESSOR_8561_Z15, &zEC12_cost, 13 },
{ "native", "", PROCESSOR_NATIVE, NULL, 0 }
};
@@ -811,6 +811,12 @@ s390_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
error ("Builtin %qF requires z14 or higher.", fndecl);
return const0_rtx;
}
+
+ if ((bflags & B_VXE2) && !TARGET_VXE2)
+ {
+ error ("Builtin %qF requires z15 or higher.", fndecl);
+ return const0_rtx;
+ }
}
if (fcode >= S390_OVERLOADED_BUILTIN_VAR_OFFSET
&& fcode < S390_ALL_BUILTIN_MAX)
@@ -1376,6 +1382,7 @@ s390_match_ccmode_set (rtx set, machine_mode req_mode)
case E_CCZ1mode:
case E_CCSmode:
case E_CCSRmode:
+ case E_CCSFPSmode:
case E_CCUmode:
case E_CCURmode:
case E_CCOmode:
@@ -1559,6 +1566,12 @@ s390_select_ccmode (enum rtx_code code, rtx op0, rtx op1)
else
return CCAPmode;
}
+
+ /* Fall through. */
+ case LTGT:
+ if (HONOR_NANS (op0) || HONOR_NANS (op1))
+ return CCSFPSmode;
+
/* Fall through. */
case UNORDERED:
case ORDERED:
@@ -1567,7 +1580,6 @@ s390_select_ccmode (enum rtx_code code, rtx op0, rtx op1)
case UNLT:
case UNGE:
case UNGT:
- case LTGT:
if ((GET_CODE (op0) == SIGN_EXTEND || GET_CODE (op0) == ZERO_EXTEND)
&& GET_CODE (op1) != CONST_INT)
return CCSRmode;
@@ -1796,7 +1808,7 @@ s390_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
}
/* ~a==b -> ~(a^b)==0 ~a!=b -> ~(a^b)!=0 */
- if (TARGET_ARCH13
+ if (TARGET_Z15
&& (*code == EQ || *code == NE)
&& (GET_MODE (*op0) == DImode || GET_MODE (*op0) == SImode)
&& GET_CODE (*op0) == NOT)
@@ -1808,7 +1820,7 @@ s390_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
}
/* a&b == -1 -> ~a|~b == 0 a|b == -1 -> ~a&~b == 0 */
- if (TARGET_ARCH13
+ if (TARGET_Z15
&& (*code == EQ || *code == NE)
&& (GET_CODE (*op0) == AND || GET_CODE (*op0) == IOR)
&& (GET_MODE (*op0) == DImode || GET_MODE (*op0) == SImode)
@@ -2082,6 +2094,7 @@ s390_branch_condition_mask (rtx code)
break;
case E_CCSmode:
+ case E_CCSFPSmode:
switch (GET_CODE (code))
{
case EQ: return CC0;
@@ -3582,7 +3595,7 @@ s390_rtx_costs (rtx x, machine_mode mode, int outer_code,
/* It is a real IF-THEN-ELSE. An additional move will be
needed to implement that. */
- if (!TARGET_ARCH13
+ if (!TARGET_Z15
&& reload_completed
&& !rtx_equal_p (dst, then)
&& !rtx_equal_p (dst, els))
@@ -3604,7 +3617,7 @@ s390_rtx_costs (rtx x, machine_mode mode, int outer_code,
case IOR:
/* nnrk, nngrk */
- if (TARGET_ARCH13
+ if (TARGET_Z15
&& (mode == SImode || mode == DImode)
&& GET_CODE (XEXP (x, 0)) == NOT
&& GET_CODE (XEXP (x, 1)) == NOT)
@@ -3651,7 +3664,7 @@ s390_rtx_costs (rtx x, machine_mode mode, int outer_code,
case AND:
/* nork, nogrk */
- if (TARGET_ARCH13
+ if (TARGET_Z15
&& (mode == SImode || mode == DImode)
&& GET_CODE (XEXP (x, 0)) == NOT
&& GET_CODE (XEXP (x, 1)) == NOT)
@@ -3823,7 +3836,7 @@ s390_rtx_costs (rtx x, machine_mode mode, int outer_code,
*total = COSTS_N_INSNS (1);
/* nxrk, nxgrk ~(a^b)==0 */
- if (TARGET_ARCH13
+ if (TARGET_Z15
&& GET_CODE (XEXP (x, 0)) == NOT
&& XEXP (x, 1) == const0_rtx
&& GET_CODE (XEXP (XEXP (x, 0), 0)) == XOR
@@ -3838,7 +3851,7 @@ s390_rtx_costs (rtx x, machine_mode mode, int outer_code,
}
/* nnrk, nngrk, nork, nogrk */
- if (TARGET_ARCH13
+ if (TARGET_Z15
&& (GET_CODE (XEXP (x, 0)) == AND || GET_CODE (XEXP (x, 0)) == IOR)
&& XEXP (x, 1) == const0_rtx
&& (GET_MODE (XEXP (x, 0)) == SImode || GET_MODE (XEXP (x, 0)) == DImode)
@@ -6504,18 +6517,23 @@ s390_expand_vec_compare (rtx target, enum rtx_code cond,
{
/* NE a != b -> !(a == b) */
case NE: cond = EQ; neg_p = true; break;
- /* UNGT a u> b -> !(b >= a) */
- case UNGT: cond = GE; neg_p = true; swap_p = true; break;
- /* UNGE a u>= b -> !(b > a) */
- case UNGE: cond = GT; neg_p = true; swap_p = true; break;
- /* LE: a <= b -> b >= a */
+ case UNGT:
+ emit_insn (gen_vec_cmpungt (target, cmp_op1, cmp_op2));
+ return;
+ case UNGE:
+ emit_insn (gen_vec_cmpunge (target, cmp_op1, cmp_op2));
+ return;
case LE: cond = GE; swap_p = true; break;
- /* UNLE: a u<= b -> !(a > b) */
- case UNLE: cond = GT; neg_p = true; break;
+ /* UNLE: (a u<= b) -> (b u>= a). */
+ case UNLE:
+ emit_insn (gen_vec_cmpunge (target, cmp_op2, cmp_op1));
+ return;
/* LT: a < b -> b > a */
case LT: cond = GT; swap_p = true; break;
- /* UNLT: a u< b -> !(a >= b) */
- case UNLT: cond = GE; neg_p = true; break;
+ /* UNLT: (a u< b) -> (b u> a). */
+ case UNLT:
+ emit_insn (gen_vec_cmpungt (target, cmp_op2, cmp_op1));
+ return;
case UNEQ:
emit_insn (gen_vec_cmpuneq (target, cmp_op1, cmp_op2));
return;
@@ -6678,7 +6696,7 @@ s390_reverse_condition (machine_mode mode, enum rtx_code code)
{
/* Reversal of FP compares takes care -- an ordered compare
becomes an unordered compare and vice versa. */
- if (mode == CCVFALLmode || mode == CCVFANYmode)
+ if (mode == CCVFALLmode || mode == CCVFANYmode || mode == CCSFPSmode)
return reverse_condition_maybe_unordered (code);
else if (mode == CCVIALLmode || mode == CCVIANYmode)
return reverse_condition (code);
@@ -11600,6 +11618,44 @@ static GTY(()) rtx morestack_ref;
#define SPLIT_STACK_AVAILABLE 1024
+/* Emit the parmblock for __morestack into .rodata section. It
+ consists of 3 pointer size entries:
+ - frame size
+ - size of stack arguments
+ - offset between parm block and __morestack return label */
+
+void
+s390_output_split_stack_data (rtx parm_block, rtx call_done,
+ rtx frame_size, rtx args_size)
+{
+ rtx ops[] = { parm_block, call_done };
+
+ switch_to_section (targetm.asm_out.function_rodata_section
+ (current_function_decl));
+
+ if (TARGET_64BIT)
+ output_asm_insn (".align\t8", NULL);
+ else
+ output_asm_insn (".align\t4", NULL);
+
+ (*targetm.asm_out.internal_label) (asm_out_file, "L",
+ CODE_LABEL_NUMBER (parm_block));
+ if (TARGET_64BIT)
+ {
+ output_asm_insn (".quad\t%0", &frame_size);
+ output_asm_insn (".quad\t%0", &args_size);
+ output_asm_insn (".quad\t%1-%0", ops);
+ }
+ else
+ {
+ output_asm_insn (".long\t%0", &frame_size);
+ output_asm_insn (".long\t%0", &args_size);
+ output_asm_insn (".long\t%1-%0", ops);
+ }
+
+ switch_to_section (current_function_section ());
+}
+
/* Emit -fsplit-stack prologue, which goes before the regular function
prologue. */
@@ -11677,16 +11733,8 @@ s390_expand_split_stack_prologue (void)
call_done = gen_label_rtx ();
parm_base = gen_label_rtx ();
-
- /* Emit the parameter block. */
- tmp = gen_split_stack_data (parm_base, call_done,
- GEN_INT (frame_size),
- GEN_INT (args_size));
- insn = emit_insn (tmp);
- add_reg_note (insn, REG_LABEL_OPERAND, call_done);
- LABEL_NUSES (call_done)++;
- add_reg_note (insn, REG_LABEL_OPERAND, parm_base);
LABEL_NUSES (parm_base)++;
+ LABEL_NUSES (call_done)++;
/* %r1 = litbase. */
insn = emit_move_insn (r1, gen_rtx_LABEL_REF (VOIDmode, parm_base));
@@ -11696,15 +11744,29 @@ s390_expand_split_stack_prologue (void)
/* Now, we need to call __morestack. It has very special calling
conventions: it preserves param/return/static chain registers for
calling main function body, and looks for its own parameters at %r1. */
+ if (cc != NULL)
+ tmp = gen_split_stack_cond_call (Pmode,
+ morestack_ref,
+ parm_base,
+ call_done,
+ GEN_INT (frame_size),
+ GEN_INT (args_size),
+ cc);
+ else
+ tmp = gen_split_stack_call (Pmode,
+ morestack_ref,
+ parm_base,
+ call_done,
+ GEN_INT (frame_size),
+ GEN_INT (args_size));
+
+ insn = emit_jump_insn (tmp);
+ JUMP_LABEL (insn) = call_done;
+ add_reg_note (insn, REG_LABEL_OPERAND, parm_base);
+ add_reg_note (insn, REG_LABEL_OPERAND, call_done);
if (cc != NULL)
{
- tmp = gen_split_stack_cond_call (morestack_ref, cc, call_done);
-
- insn = emit_jump_insn (tmp);
- JUMP_LABEL (insn) = call_done;
- LABEL_NUSES (call_done)++;
-
/* Mark the jump as very unlikely to be taken. */
add_reg_br_prob_note (insn,
profile_probability::very_unlikely ());
@@ -11720,10 +11782,6 @@ s390_expand_split_stack_prologue (void)
}
else
{
- tmp = gen_split_stack_call (morestack_ref, call_done);
- insn = emit_jump_insn (tmp);
- JUMP_LABEL (insn) = call_done;
- LABEL_NUSES (call_done)++;
emit_barrier ();
}
@@ -14488,16 +14546,16 @@ s390_get_sched_attrmask (rtx_insn *insn)
if (get_attr_z14_groupoftwo (insn))
mask |= S390_SCHED_ATTR_MASK_GROUPOFTWO;
break;
- case PROCESSOR_8561_ARCH13:
- if (get_attr_arch13_cracked (insn))
+ case PROCESSOR_8561_Z15:
+ if (get_attr_z15_cracked (insn))
mask |= S390_SCHED_ATTR_MASK_CRACKED;
- if (get_attr_arch13_expanded (insn))
+ if (get_attr_z15_expanded (insn))
mask |= S390_SCHED_ATTR_MASK_EXPANDED;
- if (get_attr_arch13_endgroup (insn))
+ if (get_attr_z15_endgroup (insn))
mask |= S390_SCHED_ATTR_MASK_ENDGROUP;
- if (get_attr_arch13_groupalone (insn))
+ if (get_attr_z15_groupalone (insn))
mask |= S390_SCHED_ATTR_MASK_GROUPALONE;
- if (get_attr_arch13_groupoftwo (insn))
+ if (get_attr_z15_groupoftwo (insn))
mask |= S390_SCHED_ATTR_MASK_GROUPOFTWO;
break;
default:
@@ -14535,15 +14593,15 @@ s390_get_unit_mask (rtx_insn *insn, int *units)
if (get_attr_z14_unit_vfu (insn))
mask |= 1 << 3;
break;
- case PROCESSOR_8561_ARCH13:
+ case PROCESSOR_8561_Z15:
*units = 4;
- if (get_attr_arch13_unit_lsu (insn))
+ if (get_attr_z15_unit_lsu (insn))
mask |= 1 << 0;
- if (get_attr_arch13_unit_fxa (insn))
+ if (get_attr_z15_unit_fxa (insn))
mask |= 1 << 1;
- if (get_attr_arch13_unit_fxb (insn))
+ if (get_attr_z15_unit_fxb (insn))
mask |= 1 << 2;
- if (get_attr_arch13_unit_vfu (insn))
+ if (get_attr_z15_unit_vfu (insn))
mask |= 1 << 3;
break;
default:
@@ -14559,7 +14617,7 @@ s390_is_fpd (rtx_insn *insn)
return false;
return get_attr_z13_unit_fpd (insn) || get_attr_z14_unit_fpd (insn)
- || get_attr_arch13_unit_fpd (insn);
+ || get_attr_z15_unit_fpd (insn);
}
static bool
@@ -14569,7 +14627,7 @@ s390_is_fxd (rtx_insn *insn)
return false;
return get_attr_z13_unit_fxd (insn) || get_attr_z14_unit_fxd (insn)
- || get_attr_arch13_unit_fxd (insn);
+ || get_attr_z15_unit_fxd (insn);
}
/* Returns TRUE if INSN is a long-running instruction. */
diff --git a/gcc/config/s390/s390.h b/gcc/config/s390/s390.h
index 2658e95f917..dc38b2ed6b9 100644
--- a/gcc/config/s390/s390.h
+++ b/gcc/config/s390/s390.h
@@ -41,12 +41,12 @@ enum processor_flags
PF_Z14 = 2048,
PF_VXE = 4096,
PF_VXE2 = 8192,
- PF_ARCH13 = 16384
+ PF_Z15 = 16384
};
/* This is necessary to avoid a warning about comparing different enum
types. */
-#define s390_tune_attr ((enum attr_cpu)(s390_tune > PROCESSOR_8561_ARCH13 ? PROCESSOR_8561_ARCH13 : s390_tune ))
+#define s390_tune_attr ((enum attr_cpu)(s390_tune > PROCESSOR_8561_Z15 ? PROCESSOR_8561_Z15 : s390_tune ))
/* These flags indicate that the generated code should run on a cpu
providing the respective hardware facility regardless of the
@@ -100,10 +100,10 @@ enum processor_flags
(s390_arch_flags & PF_VXE)
#define TARGET_CPU_VXE_P(opts) \
(opts->x_s390_arch_flags & PF_VXE)
-#define TARGET_CPU_ARCH13 \
- (s390_arch_flags & PF_ARCH13)
-#define TARGET_CPU_ARCH13_P(opts) \
- (opts->x_s390_arch_flags & PF_ARCH13)
+#define TARGET_CPU_Z15 \
+ (s390_arch_flags & PF_Z15)
+#define TARGET_CPU_Z15_P(opts) \
+ (opts->x_s390_arch_flags & PF_Z15)
#define TARGET_CPU_VXE2 \
(s390_arch_flags & PF_VXE2)
#define TARGET_CPU_VXE2_P(opts) \
@@ -160,9 +160,9 @@ enum processor_flags
(TARGET_VX && TARGET_CPU_VXE)
#define TARGET_VXE_P(opts) \
(TARGET_VX_P (opts) && TARGET_CPU_VXE_P (opts))
-#define TARGET_ARCH13 (TARGET_ZARCH && TARGET_CPU_ARCH13)
-#define TARGET_ARCH13_P(opts) \
- (TARGET_ZARCH_P (opts->x_target_flags) && TARGET_CPU_ARCH13_P (opts))
+#define TARGET_Z15 (TARGET_ZARCH && TARGET_CPU_Z15)
+#define TARGET_Z15_P(opts) \
+ (TARGET_ZARCH_P (opts->x_target_flags) && TARGET_CPU_Z15_P (opts))
#define TARGET_VXE2 \
(TARGET_VX && TARGET_CPU_VXE2)
#define TARGET_VXE2_P(opts) \
diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md
index e4516f6c378..4f7bde6616b 100644
--- a/gcc/config/s390/s390.md
+++ b/gcc/config/s390/s390.md
@@ -298,7 +298,6 @@
; Split stack support
UNSPECV_SPLIT_STACK_CALL
- UNSPECV_SPLIT_STACK_DATA
UNSPECV_OSC_BREAK
])
@@ -513,11 +512,11 @@
;; Processor type. This attribute must exactly match the processor_type
;; enumeration in s390.h.
-(define_attr "cpu" "z900,z990,z9_109,z9_ec,z10,z196,zEC12,z13,z14,arch13"
+(define_attr "cpu" "z900,z990,z9_109,z9_ec,z10,z196,zEC12,z13,z14,z15"
(const (symbol_ref "s390_tune_attr")))
(define_attr "cpu_facility"
- "standard,ieee,zarch,cpu_zarch,longdisp,extimm,dfp,z10,z196,zEC12,vx,z13,z14,vxe,arch13,vxe2"
+ "standard,ieee,zarch,cpu_zarch,longdisp,extimm,dfp,z10,z196,zEC12,vx,z13,z14,vxe,z15,vxe2"
(const_string "standard"))
(define_attr "enabled" ""
@@ -575,8 +574,8 @@
(match_test "TARGET_VXE"))
(const_int 1)
- (and (eq_attr "cpu_facility" "arch13")
- (match_test "TARGET_ARCH13"))
+ (and (eq_attr "cpu_facility" "z15")
+ (match_test "TARGET_Z15"))
(const_int 1)
(and (eq_attr "cpu_facility" "vxe2")
@@ -613,7 +612,7 @@
;; Pipeline description for z14
(include "3906.md")
-;; Pipeline description for arch13
+;; Pipeline description for z15
(include "8561.md")
;; Predicates
@@ -642,7 +641,7 @@
(define_mode_iterator DD_DF [DF DD])
(define_mode_iterator TD_TF [TF TD])
-; 32 bit int<->fp conversion instructions are available since VXE2 (arch13).
+; 32 bit int<->fp conversion instructions are available since VXE2 (z15).
(define_mode_iterator VX_CONV_BFP [DF (SF "TARGET_VXE2")])
(define_mode_iterator VX_CONV_INT [DI (SI "TARGET_VXE2")])
@@ -1424,6 +1423,20 @@
(set_attr "cpu_facility" "*,*,vx,vxe")
(set_attr "enabled" "*,<DSF>,<DF>,<SF>")])
+(define_insn "*cmp<mode>_ccsfps"
+ [(set (reg CC_REGNUM)
+ (compare (match_operand:FP 0 "register_operand" "f,f,v,v")
+ (match_operand:FP 1 "general_operand" "f,R,v,v")))]
+ "s390_match_ccmode (insn, CCSFPSmode) && TARGET_HARD_FLOAT"
+ "@
+ k<xde><bt>r\t%0,%1
+ k<xde>b\t%0,%1
+ wfkdb\t%0,%1
+ wfksb\t%0,%1"
+ [(set_attr "op_type" "RRE,RXE,VRR,VRR")
+ (set_attr "cpu_facility" "*,*,vx,vxe")
+ (set_attr "enabled" "*,<DSF>,<DF>,<SF>")])
+
; Compare and Branch instructions
; cij, cgij, crj, cgrj, cfi, cgfi, cr, cgr
@@ -6861,7 +6874,7 @@
stoc<g>%C1\t%3,%0
stoc<g>%D1\t%4,%0"
[(set_attr "op_type" "RRF,RRF,RRF,RSY,RSY,RIE,RIE,RSY,RSY")
- (set_attr "cpu_facility" "*,*,arch13,*,*,z13,z13,*,*")])
+ (set_attr "cpu_facility" "*,*,z15,*,*,z13,z13,*,*")])
;;
;;- Multiply instructions.
@@ -7712,7 +7725,7 @@
(and:GPR (not:GPR (match_operand:GPR 1 "nonimmediate_operand" ""))
(match_operand:GPR 2 "general_operand" "")))
(clobber (reg:CC CC_REGNUM))]
- "!TARGET_ARCH13
+ "!TARGET_Z15
&& ! reload_completed
&& (GET_CODE (operands[0]) != MEM
/* Ensure that s390_logical_operator_ok_p will succeed even
@@ -8069,7 +8082,7 @@
(set (match_operand:GPR 0 "register_operand" "=d")
(ANDOR:GPR (not:GPR (match_dup 1))
(match_dup 2)))]
- "TARGET_ARCH13 && s390_match_ccmode(insn, CCTmode)"
+ "TARGET_Z15 && s390_match_ccmode(insn, CCTmode)"
"<ANDOR:noxa>c<GPR:g>rk\t%0,%2,%1"
[(set_attr "op_type" "RRF")])
@@ -8081,7 +8094,7 @@
(match_operand:GPR 2 "register_operand" "d"))
(const_int 0)))
(clobber (match_scratch:GPR 0 "=d"))]
- "TARGET_ARCH13 && s390_match_ccmode(insn, CCTmode)"
+ "TARGET_Z15 && s390_match_ccmode(insn, CCTmode)"
"<ANDOR:noxa>c<GPR:g>rk\t%0,%2,%1"
[(set_attr "op_type" "RRF")])
@@ -8091,7 +8104,7 @@
(ANDOR:GPR (not:GPR (match_operand:GPR 1 "register_operand" "d"))
(match_operand:GPR 2 "register_operand" "d")))
(clobber (reg:CC CC_REGNUM))]
- "TARGET_ARCH13"
+ "TARGET_Z15"
"<ANDOR:noxa>c<GPR:g>rk\t%0,%2,%1"
[(set_attr "op_type" "RRF")])
@@ -8109,7 +8122,7 @@
(set (match_operand:GPR 0 "register_operand" "=d")
(ANDOR:GPR (not:GPR (match_dup 1))
(not:GPR (match_dup 2))))]
- "TARGET_ARCH13 && s390_match_ccmode(insn, CCTmode)"
+ "TARGET_Z15 && s390_match_ccmode(insn, CCTmode)"
"n<ANDOR:inv_no><GPR:g>rk\t%0,%1,%2"
[(set_attr "op_type" "RRF")])
@@ -8121,7 +8134,7 @@
(not:GPR (match_operand:GPR 2 "register_operand" "d")))
(const_int 0)))
(clobber (match_scratch:GPR 0 "=d"))]
- "TARGET_ARCH13 && s390_match_ccmode(insn, CCTmode)"
+ "TARGET_Z15 && s390_match_ccmode(insn, CCTmode)"
"n<ANDOR:inv_no><GPR:g>rk\t%0,%1,%2"
[(set_attr "op_type" "RRF")])
@@ -8131,7 +8144,7 @@
(ANDOR:GPR (not:GPR (match_operand:GPR 1 "register_operand" "d"))
(not:GPR (match_operand:GPR 2 "register_operand" "d"))))
(clobber (reg:CC CC_REGNUM))]
- "TARGET_ARCH13"
+ "TARGET_Z15"
"n<ANDOR:inv_no><GPR:g>rk\t%0,%1,%2"
[(set_attr "op_type" "RRF")])
@@ -8515,7 +8528,7 @@
(set (match_operand:GPR 0 "register_operand" "=d")
(xor:GPR (not:GPR (match_dup 1))
(match_dup 2)))]
- "TARGET_ARCH13 && s390_match_ccmode(insn, CCTmode)"
+ "TARGET_Z15 && s390_match_ccmode(insn, CCTmode)"
"nx<GPR:g>rk\t%0,%1,%2"
[(set_attr "op_type" "RRF")])
@@ -8527,7 +8540,7 @@
(match_operand:GPR 2 "register_operand" "d")))
(const_int 0)))
(clobber (match_scratch:GPR 0 "=d"))]
- "TARGET_ARCH13 && s390_match_ccmode(insn, CCTmode)"
+ "TARGET_Z15 && s390_match_ccmode(insn, CCTmode)"
"nx<GPR:g>rk\t%0,%1,%2"
[(set_attr "op_type" "RRF")])
@@ -8537,7 +8550,7 @@
(not:GPR (xor:GPR (match_operand:GPR 1 "register_operand" "d")
(match_operand:GPR 2 "register_operand" "d"))))
(clobber (reg:CC CC_REGNUM))]
- "TARGET_ARCH13"
+ "TARGET_Z15"
"nx<GPR:g>rk\t%0,%1,%2"
[(set_attr "op_type" "RRF")])
@@ -11496,34 +11509,34 @@
; Population count instruction
;
-(define_insn "*popcountdi_arch13_cc"
+(define_insn "*popcountdi_z15_cc"
[(set (reg CC_REGNUM)
(compare (popcount:DI (match_operand:DI 1 "register_operand" "d"))
(const_int 0)))
(set (match_operand:DI 0 "register_operand" "=d")
(match_dup 1))]
- "TARGET_ARCH13 && s390_match_ccmode (insn, CCTmode)"
+ "TARGET_Z15 && s390_match_ccmode (insn, CCTmode)"
"popcnt\t%0,%1,8"
[(set_attr "op_type" "RRF")])
-(define_insn "*popcountdi_arch13_cconly"
+(define_insn "*popcountdi_z15_cconly"
[(set (reg CC_REGNUM)
(compare (popcount:DI (match_operand:DI 1 "register_operand" "d"))
(const_int 0)))
(clobber (match_scratch:DI 0 "=d"))]
- "TARGET_ARCH13 && s390_match_ccmode(insn, CCTmode)"
+ "TARGET_Z15 && s390_match_ccmode(insn, CCTmode)"
"popcnt\t%0,%1,8"
[(set_attr "op_type" "RRF")])
-(define_insn "*popcountdi_arch13"
+(define_insn "*popcountdi_z15"
[(set (match_operand:DI 0 "register_operand" "=d")
(popcount:DI (match_operand:DI 1 "register_operand" "d")))
(clobber (reg:CC CC_REGNUM))]
- "TARGET_ARCH13"
+ "TARGET_Z15"
"popcnt\t%0,%1,8"
[(set_attr "op_type" "RRF")])
-; The pre-arch13 popcount instruction counts the bits of op1 in 8 byte
+; The pre-z15 popcount instruction counts the bits of op1 in 8 byte
; portions and stores the result in the corresponding bytes in op0.
(define_insn "*popcount<mode>_z196"
[(set (match_operand:INT 0 "register_operand" "=d")
@@ -11567,7 +11580,7 @@
(clobber (reg:CC CC_REGNUM))])]
"TARGET_Z196"
{
- if (!TARGET_ARCH13)
+ if (!TARGET_Z15)
{
emit_insn (gen_popcountdi2_z196 (operands[0], operands[1]));
DONE;
@@ -11598,7 +11611,7 @@
; popcount always counts on the full 64 bit. With the z196 version
; counting bits per byte we just ignore the upper 4 bytes. With the
-; arch13 version we have to zero out the upper 32 bits first.
+; z15 version we have to zero out the upper 32 bits first.
(define_expand "popcountsi2"
[(set (match_dup 2)
(zero_extend:DI (match_operand:SI 1 "register_operand")))
@@ -11608,7 +11621,7 @@
(subreg:SI (match_dup 3) 4))]
"TARGET_Z196"
{
- if (!TARGET_ARCH13)
+ if (!TARGET_Z15)
{
emit_insn (gen_popcountsi2_z196 (operands[0], operands[1]));
DONE;
@@ -11646,7 +11659,7 @@
(subreg:HI (match_dup 3) 6))]
"TARGET_Z196"
{
- if (!TARGET_ARCH13)
+ if (!TARGET_Z15)
{
emit_insn (gen_popcounthi2_z196 (operands[0], operands[1]));
DONE;
@@ -11661,7 +11674,7 @@
; For popcount on a single byte the old z196 style popcount
; instruction is ideal. Since it anyway does a byte-wise popcount we
; just use it instead of zero extending the QImode input to DImode and
-; using the arch13 popcount variant.
+; using the z15 popcount variant.
(define_expand "popcountqi2"
[; popcnt op0, op1
(parallel [(set (match_operand:QI 0 "register_operand" "")
@@ -12000,99 +12013,59 @@
DONE;
})
-;; __morestack parameter block for split stack prologue. Parameters are:
-;; parameter block label, label to be called by __morestack, frame size,
-;; stack parameter size.
-
-(define_insn "split_stack_data"
- [(unspec_volatile [(match_operand 0 "" "X")
- (match_operand 1 "" "X")
- (match_operand 2 "const_int_operand" "X")
- (match_operand 3 "const_int_operand" "X")]
- UNSPECV_SPLIT_STACK_DATA)]
- ""
-{
- switch_to_section (targetm.asm_out.function_rodata_section
- (current_function_decl));
-
- if (TARGET_64BIT)
- output_asm_insn (".align\t8", operands);
- else
- output_asm_insn (".align\t4", operands);
- (*targetm.asm_out.internal_label) (asm_out_file, "L",
- CODE_LABEL_NUMBER (operands[0]));
- if (TARGET_64BIT)
- {
- output_asm_insn (".quad\t%2", operands);
- output_asm_insn (".quad\t%3", operands);
- output_asm_insn (".quad\t%1-%0", operands);
- }
- else
- {
- output_asm_insn (".long\t%2", operands);
- output_asm_insn (".long\t%3", operands);
- output_asm_insn (".long\t%1-%0", operands);
- }
-
- switch_to_section (current_function_section ());
- return "";
-}
- [(set_attr "length" "0")])
-
-
-;; A jg with minimal fuss for use in split stack prologue.
+;; Call to __morestack used by the split stack support
-(define_expand "split_stack_call"
- [(match_operand 0 "bras_sym_operand" "X")
- (match_operand 1 "" "")]
- ""
-{
- if (TARGET_64BIT)
- emit_jump_insn (gen_split_stack_call_di (operands[0], operands[1]));
- else
- emit_jump_insn (gen_split_stack_call_si (operands[0], operands[1]));
- DONE;
-})
+; The insn has 3 parts:
+; 1. A jump to the call done label. The jump will be done as part of
+; __morestack and will not be explicitly emitted to the insn stream.
+; 2. The call of __morestack including a use for r1 which is supposed to
+; point to the parameter block for __morestack.
+; 3. 3 USES whose values together with the call done label will be
+; used to emit the parameter block to the .rodata section. This
+; needs to be tied into the same insn as 1. since the call done
+; label is emitted also as part of the parm block. In order to
+; allow the edge to the BB with the call done label to be
+; redirected both need to make use of the same label_ref.
-(define_insn "split_stack_call_<mode>"
- [(set (pc) (label_ref (match_operand 1 "" "")))
+(define_insn "@split_stack_call<mode>"
+ [(set (pc) (label_ref (match_operand 2 "" ""))) ; call done label
(set (reg:P 1) (unspec_volatile [(match_operand 0 "bras_sym_operand" "X")
(reg:P 1)]
- UNSPECV_SPLIT_STACK_CALL))]
+ UNSPECV_SPLIT_STACK_CALL))
+ (use (label_ref (match_operand 1 "" "X"))) ; parm block label
+ (use (match_operand 3 "const_int_operand" "X")) ; frame size
+ (use (match_operand 4 "const_int_operand" "X"))] ; arg size
""
- "jg\t%0"
+{
+ s390_output_split_stack_data (operands[1], operands[2], operands[3], operands[4]);
+ return "jg\t%0";
+}
[(set_attr "op_type" "RIL")
(set_attr "type" "branch")])
-;; Also a conditional one.
+; As above but with a conditional jump
-(define_expand "split_stack_cond_call"
- [(match_operand 0 "bras_sym_operand" "X")
- (match_operand 1 "" "")
- (match_operand 2 "" "")]
- ""
-{
- if (TARGET_64BIT)
- emit_jump_insn (gen_split_stack_cond_call_di (operands[0], operands[1], operands[2]));
- else
- emit_jump_insn (gen_split_stack_cond_call_si (operands[0], operands[1], operands[2]));
- DONE;
-})
-
-(define_insn "split_stack_cond_call_<mode>"
+(define_insn "@split_stack_cond_call<mode>"
[(set (pc)
(if_then_else
- (match_operand 1 "" "")
- (label_ref (match_operand 2 "" ""))
+ (match_operand 5 "" "") ; condition
+ (label_ref (match_operand 2 "" "")) ; call done label
(pc)))
(set (reg:P 1) (unspec_volatile [(match_operand 0 "bras_sym_operand" "X")
(reg:P 1)]
- UNSPECV_SPLIT_STACK_CALL))]
+ UNSPECV_SPLIT_STACK_CALL))
+ (use (label_ref (match_operand 1 "" "X"))) ; parm block label
+ (use (match_operand 3 "const_int_operand" "X")) ; frame size
+ (use (match_operand 4 "const_int_operand" "X"))] ; arg size
""
- "jg%C1\t%0"
+{
+ s390_output_split_stack_data (operands[1], operands[2], operands[3], operands[4]);
+ return "jg%C5\t%0";
+}
[(set_attr "op_type" "RIL")
(set_attr "type" "branch")])
+
(define_insn "osc_break"
[(unspec_volatile [(const_int 0)] UNSPECV_OSC_BREAK)]
""
diff --git a/gcc/config/s390/s390.opt b/gcc/config/s390/s390.opt
index 639f1679a56..6a6e1f75736 100644
--- a/gcc/config/s390/s390.opt
+++ b/gcc/config/s390/s390.opt
@@ -110,7 +110,10 @@ EnumValue
Enum(processor_type) String(arch12) Value(PROCESSOR_3906_Z14)
EnumValue
-Enum(processor_type) String(arch13) Value(PROCESSOR_8561_ARCH13)
+Enum(processor_type) String(z15) Value(PROCESSOR_8561_Z15)
+
+EnumValue
+Enum(processor_type) String(arch13) Value(PROCESSOR_8561_Z15)
EnumValue
Enum(processor_type) String(native) Value(PROCESSOR_NATIVE) DriverOnly
diff --git a/gcc/config/s390/vector.md b/gcc/config/s390/vector.md
index 451d07de287..d40e310f9e7 100644
--- a/gcc/config/s390/vector.md
+++ b/gcc/config/s390/vector.md
@@ -70,7 +70,7 @@
(define_mode_iterator V_128_NOSINGLE [V16QI V8HI V4SI V4SF V2DI V2DF])
-; 32 bit int<->fp vector conversion instructions are available since VXE2 (arch13).
+; 32 bit int<->fp vector conversion instructions are available since VXE2 (z15).
(define_mode_iterator VX_VEC_CONV_BFP [V2DF (V4SF "TARGET_VXE2")])
(define_mode_iterator VX_VEC_CONV_INT [V2DI (V4SI "TARGET_VXE2")])
@@ -168,10 +168,6 @@
(define_mode_attr vec_halfnumelts
[(V4SF "V2SF") (V4SI "V2SI")])
-; The comparisons not setting CC iterate over the rtx code.
-(define_code_iterator VFCMP_HW_OP [eq gt ge])
-(define_code_attr asm_fcmp_op [(eq "e") (gt "h") (ge "he")])
-
; Comparison operators on int and fp compares which are directly
@@ -614,10 +610,30 @@
operands[2] = GEN_INT (GET_MODE_NUNITS (<MODE>mode) - 1);
})
+(define_predicate "vcond_comparison_operator"
+ (match_operand 0 "comparison_operator")
+{
+ if (!HONOR_NANS (GET_MODE (XEXP (op, 0)))
+ && !HONOR_NANS (GET_MODE (XEXP (op, 1))))
+ return true;
+ switch (GET_CODE (op))
+ {
+ case LE:
+ case LT:
+ case GE:
+ case GT:
+ case LTGT:
+ /* Signaling vector comparisons are supported only on z14+. */
+ return TARGET_Z14;
+ default:
+ return true;
+ }
+})
+
(define_expand "vcond<V_HW:mode><V_HW2:mode>"
[(set (match_operand:V_HW 0 "register_operand" "")
(if_then_else:V_HW
- (match_operator 3 "comparison_operator"
+ (match_operator 3 "vcond_comparison_operator"
[(match_operand:V_HW2 4 "register_operand" "")
(match_operand:V_HW2 5 "nonmemory_operand" "")])
(match_operand:V_HW 1 "nonmemory_operand" "")
@@ -1357,7 +1373,8 @@
"#"
"&& 1"
[(set (match_dup 3)
- (gt:V2DI (match_dup 1) (match_dup 2)))
+ (not:V2DI
+ (unge:V2DI (match_dup 2) (match_dup 1))))
(set (match_dup 0)
(if_then_else:V2DF
(eq (match_dup 3) (match_dup 4))
@@ -1392,7 +1409,8 @@
"#"
"&& 1"
[(set (match_dup 3)
- (gt:V2DI (match_dup 1) (match_dup 2)))
+ (not:V2DI
+ (unge:V2DI (match_dup 2) (match_dup 1))))
(set (match_dup 0)
(if_then_else:V2DF
(eq (match_dup 3) (match_dup 4))
@@ -1446,27 +1464,134 @@
;; Floating point compares
;;
-; EQ, GT, GE
-; vfcesb, vfcedb, wfcexb, vfchsb, vfchdb, wfchxb, vfchesb, vfchedb, wfchexb
-(define_insn "*vec_cmp<VFCMP_HW_OP:code><mode>_nocc"
- [(set (match_operand:<tointvec> 0 "register_operand" "=v")
- (VFCMP_HW_OP:<tointvec> (match_operand:VFT 1 "register_operand" "v")
- (match_operand:VFT 2 "register_operand" "v")))]
- "TARGET_VX"
- "<vw>fc<VFCMP_HW_OP:asm_fcmp_op><sdx>b\t%v0,%v1,%v2"
+; vfcesb, vfcedb, wfcexb: non-signaling "==" comparison (a == b)
+(define_insn "*vec_cmpeq<mode>_quiet_nocc"
+ [(set (match_operand:<tointvec> 0 "register_operand" "=v")
+ (eq:<tointvec> (match_operand:VFT 1 "register_operand" "v")
+ (match_operand:VFT 2 "register_operand" "v")))]
+ "TARGET_VX"
+ "<vw>fce<sdx>b\t%v0,%v1,%v2"
+ [(set_attr "op_type" "VRR")])
+
+; vfchsb, vfchdb, wfchxb: non-signaling > comparison (!(b u>= a))
+(define_insn "vec_cmpgt<mode>_quiet_nocc"
+ [(set (match_operand:<tointvec> 0 "register_operand" "=v")
+ (not:<tointvec>
+ (unge:<tointvec> (match_operand:VFT 2 "register_operand" "v")
+ (match_operand:VFT 1 "register_operand" "v"))))]
+ "TARGET_VX"
+ "<vw>fch<sdx>b\t%v0,%v1,%v2"
+ [(set_attr "op_type" "VRR")])
+
+(define_expand "vec_cmplt<mode>_quiet_nocc"
+ [(set (match_operand:<tointvec> 0 "register_operand" "=v")
+ (not:<tointvec>
+ (unge:<tointvec> (match_operand:VFT 1 "register_operand" "v")
+ (match_operand:VFT 2 "register_operand" "v"))))]
+ "TARGET_VX")
+
+; vfchesb, vfchedb, wfchexb: non-signaling >= comparison (!(a u< b))
+(define_insn "vec_cmpge<mode>_quiet_nocc"
+ [(set (match_operand:<tointvec> 0 "register_operand" "=v")
+ (not:<tointvec>
+ (unlt:<tointvec> (match_operand:VFT 1 "register_operand" "v")
+ (match_operand:VFT 2 "register_operand" "v"))))]
+ "TARGET_VX"
+ "<vw>fche<sdx>b\t%v0,%v1,%v2"
+ [(set_attr "op_type" "VRR")])
+
+(define_expand "vec_cmple<mode>_quiet_nocc"
+ [(set (match_operand:<tointvec> 0 "register_operand" "=v")
+ (not:<tointvec>
+ (unlt:<tointvec> (match_operand:VFT 2 "register_operand" "v")
+ (match_operand:VFT 1 "register_operand" "v"))))]
+ "TARGET_VX")
+
+; vfkesb, vfkedb, wfkexb: signaling == comparison ((a >= b) & (b >= a))
+(define_insn "*vec_cmpeq<mode>_signaling_nocc"
+ [(set (match_operand:<tointvec> 0 "register_operand" "=v")
+ (and:<tointvec>
+ (ge:<tointvec> (match_operand:VFT 1 "register_operand" "v")
+ (match_operand:VFT 2 "register_operand" "v"))
+ (ge:<tointvec> (match_dup 2)
+ (match_dup 1))))]
+ "TARGET_VXE"
+ "<vw>fke<sdx>b\t%v0,%v1,%v2"
+ [(set_attr "op_type" "VRR")])
+
+; vfkhsb, vfkhdb, wfkhxb: signaling > comparison (a > b)
+(define_insn "*vec_cmpgt<mode>_signaling_nocc"
+ [(set (match_operand:<tointvec> 0 "register_operand" "=v")
+ (gt:<tointvec> (match_operand:VFT 1 "register_operand" "v")
+ (match_operand:VFT 2 "register_operand" "v")))]
+ "TARGET_VXE"
+ "<vw>fkh<sdx>b\t%v0,%v1,%v2"
+ [(set_attr "op_type" "VRR")])
+
+(define_insn "*vec_cmpgt<mode>_signaling_finite_nocc"
+ [(set (match_operand:<tointvec> 0 "register_operand" "=v")
+ (gt:<tointvec> (match_operand:VFT 1 "register_operand" "v")
+ (match_operand:VFT 2 "register_operand" "v")))]
+ "TARGET_VX && !TARGET_VXE && flag_finite_math_only"
+ "<vw>fch<sdx>b\t%v0,%v1,%v2"
+ [(set_attr "op_type" "VRR")])
+
+; vfkhesb, vfkhedb, wfkhexb: signaling >= comparison (a >= b)
+(define_insn "*vec_cmpge<mode>_signaling_nocc"
+ [(set (match_operand:<tointvec> 0 "register_operand" "=v")
+ (ge:<tointvec> (match_operand:VFT 1 "register_operand" "v")
+ (match_operand:VFT 2 "register_operand" "v")))]
+ "TARGET_VXE"
+ "<vw>fkhe<sdx>b\t%v0,%v1,%v2"
+ [(set_attr "op_type" "VRR")])
+
+(define_insn "*vec_cmpge<mode>_signaling_finite_nocc"
+ [(set (match_operand:<tointvec> 0 "register_operand" "=v")
+ (ge:<tointvec> (match_operand:VFT 1 "register_operand" "v")
+ (match_operand:VFT 2 "register_operand" "v")))]
+ "TARGET_VX && !TARGET_VXE && flag_finite_math_only"
+ "<vw>fche<sdx>b\t%v0,%v1,%v2"
[(set_attr "op_type" "VRR")])
; Expanders for not directly supported comparisons
+; Signaling comparisons must be expressed via signaling rtxes only,
+; and quiet comparisons must be expressed via quiet rtxes only.
+
+; UNGT a u> b -> !!(b u< a)
+(define_expand "vec_cmpungt<mode>"
+ [(set (match_operand:<tointvec> 0 "register_operand" "=v")
+ (not:<tointvec>
+ (unlt:<tointvec> (match_operand:VFT 2 "register_operand" "v")
+ (match_operand:VFT 1 "register_operand" "v"))))
+ (set (match_dup 0)
+ (not:<tointvec> (match_dup 0)))]
+ "TARGET_VX")
+
+; UNGE a u>= b -> !!(a u>= b)
+(define_expand "vec_cmpunge<mode>"
+ [(set (match_operand:<tointvec> 0 "register_operand" "=v")
+ (not:<tointvec>
+ (unge:<tointvec> (match_operand:VFT 1 "register_operand" "v")
+ (match_operand:VFT 2 "register_operand" "v"))))
+ (set (match_dup 0)
+ (not:<tointvec> (match_dup 0)))]
+ "TARGET_VX")
-; UNEQ a u== b -> !(a > b | b > a)
+; UNEQ a u== b -> !(!(a u>= b) | !(b u>= a))
(define_expand "vec_cmpuneq<mode>"
- [(set (match_operand:<tointvec> 0 "register_operand" "=v")
- (gt:<tointvec> (match_operand:VFT 1 "register_operand" "v")
- (match_operand:VFT 2 "register_operand" "v")))
- (set (match_dup 3)
- (gt:<tointvec> (match_dup 2) (match_dup 1)))
- (set (match_dup 0) (ior:<tointvec> (match_dup 0) (match_dup 3)))
- (set (match_dup 0) (not:<tointvec> (match_dup 0)))]
+ [(set (match_operand:<tointvec> 0 "register_operand" "=v")
+ (not:<tointvec>
+ (unge:<tointvec> (match_operand:VFT 1 "register_operand" "v")
+ (match_operand:VFT 2 "register_operand" "v"))))
+ (set (match_dup 3)
+ (not:<tointvec>
+ (unge:<tointvec> (match_dup 2)
+ (match_dup 1))))
+ (set (match_dup 0)
+ (ior:<tointvec> (match_dup 0)
+ (match_dup 3)))
+ (set (match_dup 0)
+ (not:<tointvec> (match_dup 0)))]
"TARGET_VX"
{
operands[3] = gen_reg_rtx (<tointvec>mode);
@@ -1479,18 +1604,24 @@
(match_operand:VFT 2 "register_operand" "v")))
(set (match_dup 3) (gt:<tointvec> (match_dup 2) (match_dup 1)))
(set (match_dup 0) (ior:<tointvec> (match_dup 0) (match_dup 3)))]
- "TARGET_VX"
+ "TARGET_VXE"
{
operands[3] = gen_reg_rtx (<tointvec>mode);
})
-; ORDERED (a, b): a >= b | b > a
+; ORDERED (a, b): !(a u< b) | !(a u>= b)
(define_expand "vec_cmpordered<mode>"
- [(set (match_operand:<tointvec> 0 "register_operand" "=v")
- (ge:<tointvec> (match_operand:VFT 1 "register_operand" "v")
- (match_operand:VFT 2 "register_operand" "v")))
- (set (match_dup 3) (gt:<tointvec> (match_dup 2) (match_dup 1)))
- (set (match_dup 0) (ior:<tointvec> (match_dup 0) (match_dup 3)))]
+ [(set (match_operand:<tointvec> 0 "register_operand" "=v")
+ (not:<tointvec>
+ (unlt:<tointvec> (match_operand:VFT 1 "register_operand" "v")
+ (match_operand:VFT 2 "register_operand" "v"))))
+ (set (match_dup 3)
+ (not:<tointvec>
+ (unge:<tointvec> (match_dup 1)
+ (match_dup 2))))
+ (set (match_dup 0)
+ (ior:<tointvec> (match_dup 0)
+ (match_dup 3)))]
"TARGET_VX"
{
operands[3] = gen_reg_rtx (<tointvec>mode);
@@ -1510,7 +1641,7 @@
})
(define_code_iterator VEC_CMP_EXPAND
- [uneq ltgt ordered unordered])
+ [ungt unge uneq ltgt ordered unordered])
(define_expand "vec_cmp<code>"
[(match_operand 0 "register_operand" "")
diff --git a/gcc/config/s390/vx-builtins.md b/gcc/config/s390/vx-builtins.md
index c71aae032ee..4b6079aa4fd 100644
--- a/gcc/config/s390/vx-builtins.md
+++ b/gcc/config/s390/vx-builtins.md
@@ -2147,7 +2147,7 @@
"<vw>fmax<sdx>b\t%v0,%v1,%v2,%b3"
[(set_attr "op_type" "VRR")])
-; The element reversal builtins introduced with arch13 have been made
+; The element reversal builtins introduced with z15 have been made
; available also for older CPUs down to z13.
(define_expand "eltswap<mode>"
[(set (match_operand:VEC_HW 0 "nonimmediate_operand" "")
@@ -2181,8 +2181,8 @@
vster<bhfgq>\t%v1,%v0"
[(set_attr "op_type" "*,VRX,VRX")])
-; arch13 has instructions for doing element reversal from mem to reg
-; or the other way around. For reg to reg or on pre arch13 machines
+; z15 has instructions for doing element reversal from mem to reg
+; or the other way around. For reg to reg or on pre z15 machines
; we have to emulate it with vector permute.
(define_insn_and_split "*eltswap<mode>_emu"
[(set (match_operand:VEC_HW 0 "nonimmediate_operand" "=vR")
diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c
index ffab94f4dba..521bc0966cc 100644
--- a/gcc/config/sh/sh.c
+++ b/gcc/config/sh/sh.c
@@ -958,11 +958,13 @@ sh_option_override (void)
if (flag_unsafe_math_optimizations)
{
/* Enable fsca insn for SH4A if not otherwise specified by the user. */
- if (global_options_set.x_TARGET_FSCA == 0 && TARGET_SH4A_FP)
+ if (global_options_set.x_TARGET_FSCA == 0
+ && (TARGET_SH4A_FP || TARGET_FPU_SH4_300))
TARGET_FSCA = 1;
/* Enable fsrra insn for SH4A if not otherwise specified by the user. */
- if (global_options_set.x_TARGET_FSRRA == 0 && TARGET_SH4A_FP)
+ if (global_options_set.x_TARGET_FSRRA == 0
+ && (TARGET_SH4A_FP || TARGET_FPU_SH4_300))
TARGET_FSRRA = 1;
}
@@ -12490,7 +12492,7 @@ static void
sh_emit_mode_set (int entity ATTRIBUTE_UNUSED, int mode,
int prev_mode, HARD_REG_SET regs_live ATTRIBUTE_UNUSED)
{
- if ((TARGET_SH4A_FP || TARGET_SH4_300)
+ if ((TARGET_SH4A_FP || TARGET_FPU_SH4_300)
&& prev_mode != FP_MODE_NONE && prev_mode != mode)
{
emit_insn (gen_toggle_pr ());
diff --git a/gcc/config/sh/sh.h b/gcc/config/sh/sh.h
index 3e3848893f7..cacc674f0b2 100644
--- a/gcc/config/sh/sh.h
+++ b/gcc/config/sh/sh.h
@@ -69,6 +69,8 @@ extern int code_for_indirect_jump_scratch;
FPU is disabled (which makes it compatible with SH4al-dsp). */
#define TARGET_SH4A_FP (TARGET_SH4A && TARGET_FPU_ANY)
+/* True if the FPU is a SH4-300 variant. */
+#define TARGET_FPU_SH4_300 (TARGET_FPU_ANY && TARGET_SH4_300)
/* This is not used by the SH2E calling convention */
#define TARGET_VARARGS_PRETEND_ARGS(FUN_DECL) \
diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md
index ed70e344dfa..e687cf22a39 100644
--- a/gcc/config/sh/sh.md
+++ b/gcc/config/sh/sh.md
@@ -9163,7 +9163,7 @@
(xor:SI (reg:SI FPSCR_REG) (const_int FPSCR_PR)))
(set (reg:SI FPSCR_MODES_REG)
(unspec_volatile:SI [(const_int 0)] UNSPECV_FPSCR_MODES))]
- "TARGET_SH4A_FP"
+ "TARGET_SH4A_FP || TARGET_FPU_SH4_300"
"fpchg"
[(set_attr "type" "fpscr_toggle")])
@@ -9391,15 +9391,31 @@
(define_expand "negsf2"
[(set (match_operand:SF 0 "fp_arith_reg_operand")
(neg:SF (match_operand:SF 1 "fp_arith_reg_operand")))]
- "TARGET_SH2E")
+ "TARGET_FPU_ANY"
+{
+ if (TARGET_FPU_SH4_300)
+ emit_insn (gen_negsf2_fpscr (operands[0], operands[1]));
+ else
+ emit_insn (gen_negsf2_no_fpscr (operands[0], operands[1]));
+ DONE;
+})
-(define_insn "*negsf2_i"
+(define_insn "negsf2_no_fpscr"
[(set (match_operand:SF 0 "fp_arith_reg_operand" "=f")
(neg:SF (match_operand:SF 1 "fp_arith_reg_operand" "0")))]
- "TARGET_SH2E"
+ "TARGET_FPU_ANY && !TARGET_FPU_SH4_300"
"fneg %0"
[(set_attr "type" "fmove")])
+(define_insn "negsf2_fpscr"
+ [(set (match_operand:SF 0 "fp_arith_reg_operand" "=f")
+ (neg:SF (match_operand:SF 1 "fp_arith_reg_operand" "0")))
+ (use (reg:SI FPSCR_MODES_REG))]
+ "TARGET_FPU_SH4_300"
+ "fneg %0"
+ [(set_attr "type" "fmove")
+ (set_attr "fp_mode" "single")])
+
(define_expand "sqrtsf2"
[(set (match_operand:SF 0 "fp_arith_reg_operand" "")
(sqrt:SF (match_operand:SF 1 "fp_arith_reg_operand" "")))]
@@ -9489,15 +9505,31 @@
(define_expand "abssf2"
[(set (match_operand:SF 0 "fp_arith_reg_operand")
(abs:SF (match_operand:SF 1 "fp_arith_reg_operand")))]
- "TARGET_SH2E")
+ "TARGET_FPU_ANY"
+{
+ if (TARGET_FPU_SH4_300)
+ emit_insn (gen_abssf2_fpscr (operands[0], operands[1]));
+ else
+ emit_insn (gen_abssf2_no_fpscr (operands[0], operands[1]));
+ DONE;
+})
-(define_insn "*abssf2_i"
+(define_insn "abssf2_no_fpscr"
[(set (match_operand:SF 0 "fp_arith_reg_operand" "=f")
(abs:SF (match_operand:SF 1 "fp_arith_reg_operand" "0")))]
- "TARGET_SH2E"
+ "TARGET_FPU_ANY && !TARGET_FPU_SH4_300"
"fabs %0"
[(set_attr "type" "fmove")])
+(define_insn "abssf2_fpscr"
+ [(set (match_operand:SF 0 "fp_arith_reg_operand" "=f")
+ (abs:SF (match_operand:SF 1 "fp_arith_reg_operand" "0")))
+ (use (reg:SI FPSCR_MODES_REG))]
+ "TARGET_FPU_SH4_300"
+ "fabs %0"
+ [(set_attr "type" "fmove")
+ (set_attr "fp_mode" "single")])
+
(define_expand "adddf3"
[(set (match_operand:DF 0 "fp_arith_reg_operand" "")
(plus:DF (match_operand:DF 1 "fp_arith_reg_operand" "")
@@ -9673,12 +9705,28 @@
(define_expand "negdf2"
[(set (match_operand:DF 0 "fp_arith_reg_operand")
(neg:DF (match_operand:DF 1 "fp_arith_reg_operand")))]
- "TARGET_FPU_DOUBLE")
+ "TARGET_FPU_DOUBLE"
+{
+ if (TARGET_FPU_SH4_300)
+ emit_insn (gen_negdf2_fpscr (operands[0], operands[1]));
+ else
+ emit_insn (gen_negdf2_no_fpscr (operands[0], operands[1]));
+ DONE;
+})
-(define_insn "*negdf2_i"
+(define_insn "negdf2_fpscr"
+ [(set (match_operand:DF 0 "fp_arith_reg_operand" "=f")
+ (neg:DF (match_operand:DF 1 "fp_arith_reg_operand" "0")))
+ (use (reg:SI FPSCR_MODES_REG))]
+ "TARGET_FPU_SH4_300"
+ "fneg %0"
+ [(set_attr "type" "fmove")
+ (set_attr "fp_mode" "double")])
+
+(define_insn "negdf2_no_fpscr"
[(set (match_operand:DF 0 "fp_arith_reg_operand" "=f")
(neg:DF (match_operand:DF 1 "fp_arith_reg_operand" "0")))]
- "TARGET_FPU_DOUBLE"
+ "TARGET_FPU_DOUBLE && !TARGET_FPU_SH4_300"
"fneg %0"
[(set_attr "type" "fmove")])
@@ -9704,15 +9752,31 @@
(define_expand "absdf2"
[(set (match_operand:DF 0 "fp_arith_reg_operand")
(abs:DF (match_operand:DF 1 "fp_arith_reg_operand")))]
- "TARGET_FPU_DOUBLE")
+ "TARGET_FPU_DOUBLE"
+{
+ if (TARGET_FPU_SH4_300)
+ emit_insn (gen_absdf2_fpscr (operands[0], operands[1]));
+ else
+ emit_insn (gen_absdf2_no_fpscr (operands[0], operands[1]));
+ DONE;
+})
-(define_insn "*absdf2_i"
+(define_insn "absdf2_no_fpscr"
[(set (match_operand:DF 0 "fp_arith_reg_operand" "=f")
(abs:DF (match_operand:DF 1 "fp_arith_reg_operand" "0")))]
- "TARGET_FPU_DOUBLE"
+ "TARGET_FPU_DOUBLE && !TARGET_FPU_SH4_300"
"fabs %0"
[(set_attr "type" "fmove")])
+(define_insn "absdf2_fpscr"
+ [(set (match_operand:DF 0 "fp_arith_reg_operand" "=f")
+ (abs:DF (match_operand:DF 1 "fp_arith_reg_operand" "0")))
+ (use (reg:SI FPSCR_MODES_REG))]
+ "TARGET_FPU_SH4_300"
+ "fabs %0"
+ [(set_attr "type" "fmove")
+ (set_attr "fp_mode" "double")])
+
(define_expand "extendsfdf2"
[(set (match_operand:DF 0 "fp_arith_reg_operand" "")
(float_extend:DF (match_operand:SF 1 "fpul_operand" "")))]
diff --git a/gcc/configure b/gcc/configure
index cf65b53df55..83ac234ecf1 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -815,6 +815,7 @@ accel_dir_suffix
real_target_noncanonical
enable_as_accelerator
gnat_install_lib
+DOCUMENTATION_ROOT_URL
REPORT_BUGS_TEXI
REPORT_BUGS_TO
PKGVERSION
@@ -960,6 +961,7 @@ enable_gcov
with_specs
with_pkgversion
with_bugurl
+with_documentation_root_url
enable_languages
with_multilib_list
with_zstd
@@ -1788,6 +1790,8 @@ Optional Packages:
--with-specs=SPECS add SPECS to driver command-line processing
--with-pkgversion=PKG Use PKG in the version string in place of "GCC"
--with-bugurl=URL Direct users to URL to report a bug
+ --with-documentation-root-url=URL
+ Root for documentation URLs
--with-multilib-list select multilibs (AArch64, SH and x86-64 only)
--with-zstd=PATH specify prefix directory for installed zstd library.
Equivalent to --with-zstd-include=PATH/include plus
@@ -7804,6 +7808,23 @@ fi
+# Allow overriding the default URL for documentation
+
+# Check whether --with-documentation-root-url was given.
+if test "${with_documentation_root_url+set}" = set; then :
+ withval=$with_documentation_root_url; case "$withval" in
+ yes) as_fn_error $? "documentation root URL not specified" "$LINENO" 5 ;;
+ no) as_fn_error $? "documentation root URL not specified" "$LINENO" 5 ;;
+ *) DOCUMENTATION_ROOT_URL="$withval"
+ ;;
+ esac
+else
+ DOCUMENTATION_ROOT_URL="https://gcc.gnu.org/onlinedocs/gcc/"
+
+fi
+
+
+
# Sanity check enable_languages in case someone does not run the toplevel
# configure # script.
# Check whether --enable-languages was given.
@@ -18832,7 +18853,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 18835 "configure"
+#line 18856 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -18938,7 +18959,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 18941 "configure"
+#line 18962 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -27775,6 +27796,80 @@ fi
as_fn_error $? "Requesting --with-nan= requires assembler support for -mnan=" "$LINENO" 5
fi
;;
+ msp430-*-*)
+ # Earlier GAS versions generically support .gnu_attribute, but the
+ # msp430 assembler will not do anything with it.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for .gnu_attribute support" >&5
+$as_echo_n "checking assembler for .gnu_attribute support... " >&6; }
+if ${gcc_cv_as_msp430_gnu_attribute+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ gcc_cv_as_msp430_gnu_attribute=no
+ if test $in_tree_gas = yes; then
+ if test $gcc_cv_gas_vers -ge `expr \( \( 2 \* 1000 \) + 33 \) \* 1000 + 50`
+ then gcc_cv_as_msp430_gnu_attribute=yes
+fi
+ elif test x$gcc_cv_as != x; then
+ $as_echo '.gnu_attribute 4,1' > conftest.s
+ if { ac_try='$gcc_cv_as $gcc_cv_as_flags -o conftest.o conftest.s >&5'
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }
+ then
+ gcc_cv_as_msp430_gnu_attribute=yes
+ else
+ echo "configure: failed program was" >&5
+ cat conftest.s >&5
+ fi
+ rm -f conftest.o conftest.s
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_msp430_gnu_attribute" >&5
+$as_echo "$gcc_cv_as_msp430_gnu_attribute" >&6; }
+if test $gcc_cv_as_msp430_gnu_attribute = yes; then
+
+$as_echo "#define HAVE_AS_GNU_ATTRIBUTE 1" >>confdefs.h
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for .mspabi_attribute support" >&5
+$as_echo_n "checking assembler for .mspabi_attribute support... " >&6; }
+if ${gcc_cv_as_msp430_mspabi_attribute+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ gcc_cv_as_msp430_mspabi_attribute=no
+ if test $in_tree_gas = yes; then
+ if test $gcc_cv_gas_vers -ge `expr \( \( 2 \* 1000 \) + 33 \) \* 1000 + 50`
+ then gcc_cv_as_msp430_mspabi_attribute=yes
+fi
+ elif test x$gcc_cv_as != x; then
+ $as_echo '.mspabi_attribute 4,1' > conftest.s
+ if { ac_try='$gcc_cv_as $gcc_cv_as_flags -o conftest.o conftest.s >&5'
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }
+ then
+ gcc_cv_as_msp430_mspabi_attribute=yes
+ else
+ echo "configure: failed program was" >&5
+ cat conftest.s >&5
+ fi
+ rm -f conftest.o conftest.s
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_msp430_mspabi_attribute" >&5
+$as_echo "$gcc_cv_as_msp430_mspabi_attribute" >&6; }
+if test $gcc_cv_as_msp430_mspabi_attribute = yes; then
+
+$as_echo "#define HAVE_AS_MSPABI_ATTRIBUTE 1" >>confdefs.h
+
+fi
+
+ ;;
riscv*-*-*)
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for .attribute support" >&5
$as_echo_n "checking assembler for .attribute support... " >&6; }
diff --git a/gcc/configure.ac b/gcc/configure.ac
index 034947de344..aa7e16f5020 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -962,6 +962,20 @@ ACX_PKGVERSION([GCC])
# '\#' needed to escape hash to Make
ACX_BUGURL([https://gcc.gnu.org/wiki/cxx-coroutines\#Bugs])
+# Allow overriding the default URL for documentation
+AC_ARG_WITH(documentation-root-url,
+ AS_HELP_STRING([--with-documentation-root-url=URL],
+ [Root for documentation URLs]),
+ [case "$withval" in
+ yes) AC_MSG_ERROR([documentation root URL not specified]) ;;
+ no) AC_MSG_ERROR([documentation root URL not specified]) ;;
+ *) DOCUMENTATION_ROOT_URL="$withval"
+ ;;
+ esac],
+ DOCUMENTATION_ROOT_URL="https://gcc.gnu.org/onlinedocs/gcc/"
+)
+AC_SUBST(DOCUMENTATION_ROOT_URL)
+
# Sanity check enable_languages in case someone does not run the toplevel
# configure # script.
AC_ARG_ENABLE(languages,
@@ -4951,6 +4965,20 @@ pointers into PC-relative form.])
[Requesting --with-nan= requires assembler support for -mnan=])
fi
;;
+ msp430-*-*)
+ # Earlier GAS versions generically support .gnu_attribute, but the
+ # msp430 assembler will not do anything with it.
+ gcc_GAS_CHECK_FEATURE([.gnu_attribute support],
+ gcc_cv_as_msp430_gnu_attribute, [2,33,50],,
+ [.gnu_attribute 4,1],,
+ [AC_DEFINE(HAVE_AS_GNU_ATTRIBUTE, 1,
+ [Define if your assembler supports .gnu_attribute.])])
+ gcc_GAS_CHECK_FEATURE([.mspabi_attribute support],
+ gcc_cv_as_msp430_mspabi_attribute, [2,33,50],,
+ [.mspabi_attribute 4,1],,
+ [AC_DEFINE(HAVE_AS_MSPABI_ATTRIBUTE, 1,
+ [Define if your assembler supports .mspabi_attribute.])])
+ ;;
riscv*-*-*)
gcc_GAS_CHECK_FEATURE([.attribute support],
gcc_cv_as_riscv_attribute, [2,32,0],,
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index b40825ee869..af084974cf8 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,599 @@
+2019-10-14 Jakub Jelinek <jakub@redhat.com>
+
+ * parser.c (cp_parser_omp_all_clauses): Change bool NESTED_P argument
+ into int NESTED, if it is 2, diagnose missing commas in between
+ clauses.
+ (cp_parser_omp_context_selector): Pass 2 as last argument to
+ cp_parser_omp_all_clauses.
+
+2019-10-12 Jakub Jelinek <jakub@redhat.com>
+
+ * parser.c (cp_parser_omp_context_selector): Improve error recovery.
+ For simd properties, put them directly into TREE_VALUE.
+ (cp_finish_omp_declare_variant): Add "omp declare variant base"
+ attribute rather than "omp declare variant".
+
+2019-10-11 Marek Polacek <polacek@redhat.com>
+
+ PR c++/92049 - extra error with -fchecking=2.
+ * pt.c (build_non_dependent_expr): Call fold_non_dependent_expr
+ with tf_none.
+
+2019-10-11 Paolo Carlini <paolo.carlini@oracle.com>
+
+ * typeck.c (cp_build_binary_op): Do not handle RROTATE_EXPR and
+ LROTATE_EXPR.
+ * constexpr.c (cxx_eval_constant_expression): Likewise.
+ (potential_constant_expression_1): Likewise.
+ * pt.c (tsubst_copy): Likewise.
+
+2019-10-11 Jason Merrill <jason@redhat.com>
+
+ * decl2.c (mark_used): Don't clobber DECL_SOURCE_LOCATION on
+ explicitly defaulted functions.
+ * method.c (synthesize_method): Likewise.
+
+2019-10-11 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/91987
+ * decl2.c (grok_array_decl): For -fstrong-eval-order, when array ref
+ operands have been swapped and at least one operand has side-effects,
+ revert the swapping before calling build_array_ref.
+ * typeck.c (cp_build_array_ref): For non-ARRAY_TYPE array ref with
+ side-effects on the index operand, if -fstrong-eval-order use
+ save_expr around the array operand.
+ (cp_build_binary_op): For shifts with side-effects in the second
+ operand, wrap first operand into SAVE_EXPR and evaluate it before
+ the shift.
+ * semantics.c (handle_omp_array_sections_1): Temporarily disable
+ flag_strong_eval_order during OMP_CLAUSE_REDUCTION array section
+ processing.
+ * cp-gimplify.c (gimplify_to_rvalue): New function.
+ (cp_gimplify_expr): Use it.
+
+2019-10-10 Marek Polacek <polacek@redhat.com>
+
+ * typeck.c (comp_ptr_ttypes_real): Change the return type to bool.
+ Use false instead of 0.
+
+2019-10-10 Jakub Jelinek <jakub@redhat.com>
+
+ * parser.h (struct cp_omp_declare_simd_data): Add variant_p member.
+ * parser.c (cp_ensure_no_omp_declare_simd): Handle both declare simd
+ and declare variant.
+ (cp_parser_oacc_all_clauses): Formatting fix.
+ (cp_parser_omp_all_clauses): Add NESTED_P argument, if true, terminate
+ processing on closing paren and don't skip to end of pragma line.
+ (cp_parser_omp_declare_simd): Add VARIANT_P argument. Handle also
+ declare variant.
+ (omp_construct_selectors, omp_device_selectors,
+ omp_implementation_selectors, omp_user_selectors): New variables.
+ (cp_parser_omp_context_selector,
+ cp_parser_omp_context_selector_specification,
+ cp_finish_omp_declare_variant): New functions.
+ (cp_parser_late_parsing_omp_declare_simd): Handle also declare variant.
+ (cp_parser_omp_declare): Handle declare variant.
+
+2019-10-09 Jason Merrill <jason@redhat.com>
+
+ * cp-tree.h (template_info_decl_check): Check ENABLE_TREE_CHECKING.
+
+2019-10-09 Marek Polacek <polacek@redhat.com>
+
+ PR c++/91364 - P0388R4: Permit conversions to arrays of unknown bound.
+ PR c++/69531 - DR 1307: Differently bounded array parameters.
+ PR c++/88128 - DR 330: Qual convs and pointers to arrays of pointers.
+ * call.c (build_array_conv): Build ck_identity at the beginning
+ of the conversion.
+ (standard_conversion): Pass bounds_none to comp_ptr_ttypes_const.
+ (maybe_warn_array_conv): New.
+ (convert_like_real): Call it. Add an error message about converting
+ from arrays of unknown bounds.
+ (conv_get_original_expr): New.
+ (nelts_initialized_by_list_init): New.
+ (conv_binds_to_array_of_unknown_bound): New.
+ (compare_ics): Implement list-initialization ranking based on
+ array sizes, as specified in DR 1307 and P0388R.
+ * cp-tree.h (comp_ptr_ttypes_const): Adjust declaration.
+ (compare_bounds_t): New enum.
+ * typeck.c (comp_array_types): New bool and compare_bounds_t
+ parameters. Use them.
+ (structural_comptypes): Adjust the call to comp_array_types.
+ (similar_type_p): Handle ARRAY_TYPE.
+ (build_const_cast_1): Pass bounds_none to comp_ptr_ttypes_const.
+ (comp_ptr_ttypes_real): Don't check cv-quals of ARRAY_TYPEs. Use
+ comp_array_types to compare array types. Look through arrays as per
+ DR 330.
+ (comp_ptr_ttypes_const): Use comp_array_types to compare array types.
+ Look through arrays as per DR 330.
+
+2019-10-09 Marek Polacek <polacek@redhat.com>
+
+ PR c++/92032 - DR 1601: Promotion of enum with fixed underlying type.
+ * call.c (standard_conversion): When converting an enumeration with
+ a fixed underlying type to the underlying type, give it the cr_promotion
+ rank.
+ (compare_ics): Implement a tiebreaker as per CWG 1601.
+
+2019-10-08 Andrew Sutton <asutton@lock3software.com>
+ Jason Merrill <jason@redhat.com>
+
+ Update the concepts implementation to conform to the C++20
+ specification, improve compile times, and generally clean up
+ the implementation.
+ * call.c (build_new_function_call): Don't evaluate concepts here.
+ (constraint_failure): Don't record the template.
+ (print_z_candidate): Don't extract the template.
+ * class.c (add_method): When overloading, hide ineligible special
+ member fns.
+ (check_methods): Set TYPE_HAS_COMPLEX_* here.
+ * constexpr.c (cxx_eval_constant_expression): Evaluate concepts.
+ (maybe_initialize_fundef_copies_table): Remove.
+ (get_fundef_copy): Use hash_map_safe_get_or_insert.
+ (clear_cv_and_fold_caches): Clear the satisfaction cache.
+ * constraint.cc (known_non_bool_p): New.
+ (parsing_constraint_expression_sentinel): Renamed from
+ expanding_constraint_sentinel.
+ (check_constraint_operands): New.
+ (check_constraint_atom): New.
+ (finish_constraint_binary_op): New.
+ (finish_constraint_or_expr): Likewise.
+ (finish_constraint_and_expr): Likewise.
+ (finish_constraint_primary_expr): Likewise.
+ (combine_constraint_expressions): New.
+ (finish_requires_expr): Add location parm.
+ (get_concept_definition): Return the initializer of concept definitions.
+ (get_template_head_requirements): New.
+ (get_trailing_function_requirements): New.
+ (deduce_constrained_parameter): Check if the identifier or template-id
+ is a concept definition.
+ (resolve_concept_definition_check): Removed.
+ (resolve_variable_concept_check): Removed.
+ (resolve_concept_check): New.
+ (resolve_constraint_check): Handle concept definitions.
+ converting arguments.
+ (function_concept_check_p): Removed.
+ (variable_concept_check_p): Removed.
+ (unpack_concept_check): New.
+ (get_concept_check_template): New.
+ (build_call_check): Moved and renamed to build_function_check.
+ (build_concept_check_arguments): make static.
+ (build_function_check): Always do overload resolution
+ in order to force conversion of template arguments (i.e., actually
+ check that the use of a concept is valid).
+ (build_standard_check): Renamed from build_real_concept_check.
+ (build_real_concept_check): Build checks for C++2a concepts by
+ (build_wildcard_concept_check): New.
+ (build_concept_check): Use build_real_concept_check. New overload.
+ (build_constraints): Save expressions, not normalized constraints.
+ (build_concept_id): New. Pass tf_warning_or_error.
+ (build_type_constraint): New.
+ (finish_type_constraints): New.
+ (associate_classtype_constraints): Also add constraints to union
+ types. Note the original declaration in errors. Don't return
+ error_mark_node in order to avoid an assertion later.
+ (push_down_pack_expansion): Remove.
+ (finish_shorthand_constraint): Make fold expressions, not naked
+ parameter packs. Always apply the constraint to each template argument.
+ (check_introduction_list): New. Fail if not enough
+ names are introduced.
+ (finish_template_introduction): Don't normalize constraints. Pass
+ tsubst flags. Check for insufficient introductions.
+ (placeholder_extract_concept_and_args): Handle the template-id case.
+ Unpack function concept checks correctly.
+ (tsubst_simple_requirement): Return errors if they occur. Don't
+ process as a template.
+ (tsubst_type_requirement): Likewise.
+ (type_deducible_p): New. Wrap the input expression in parens for the
+ purpose of deduction.
+ (expression_convertible_t): New.
+ (tsubst_compound_requirement): Use new deduction, conversion predicates.
+ (tsubst_nested_requirement): Return errors if they occur. Don't
+ process as a template. Instantiate and evaluate the nested requirement.
+ (tsubst_valid_expression_requirement): New.
+ (tsubst_simple_requirement): Use tsubst_valid_expression_requirement.
+ (tsubst_compound_requirement): Use tsubst_valid_expression_requirement.
+ (check_constaint_variables): New.
+ (tsubst_constraint_variables): Check that type substitutions are valid.
+ (tsubst_requires_expr): Likewise. Produce new requires-exprs during
+ template substitution. Copy the previous local specialization stack,
+ so references to non-local parameters can be found. Use cp_unevaluated.
+ (tsubst_constraint): New. Don't evaluate concept checks.
+ (subst_info): New.
+ (norm_info): New. Used to build a normalization tree for concept check
+ diagnostics.
+ (debug_parameter_mapping): New.
+ (debug_argument_list): New.
+ (expand_concept): Removed.
+ (normalize_logical_operation): Pass subst_info through call.
+ (normalize_pack_expansion): Remove.
+ (normalize_simple_requirement): Removed
+ (normalize_type_requirement): Removed
+ (normalize_compound_requirement): Removed
+ (normalize_nested_requirement): Removed
+ (normalize_requirement): Removed
+ (normalize_requirements): Removed
+ (normalize_requires_expression): Removed
+ (normalize_variable_concept_check): Removed.
+ (normalize_function_concept_check): Removed.
+ (normalize_concept_check): Merged all normalize_*_check here.
+ Substitute through written template arguments before normalizing the
+ definition. Only substitute the innermost template arguments.
+ (check_for_logical_overloads): Delete.
+ (map_arguments): New. Associate template parameters with arguments.
+ (build_parameter_mapping): New. Extract used parameters.
+ (normalize_expression): Rewrite.
+ (normalize_conjunction): Removed
+ (normalize_disjunction): Removed
+ (normalize_predicate_constraint): Removed
+ (normalize_parameterized_constraint): Removed
+ (normalized_map): New variable.
+ (get_normalized_constraints): New entry point for normalization.
+ Establishes a timer.
+ (get_normalized_constraints_from_info): New.
+ (get_normalized_constraints_from_decl): New. Turn on template processing
+ prior to normalization. Handle inheriting ctors. Build the
+ normalization arguments from the full set of template parameters of the
+ most general template. This guarantees that we have no concrete arguments
+ in the parameter mapping (e.g., from template members of class
+ templates). Cache normalizations.
+ (normalize_concept_definition): New. Cache normalizations.
+ (normalize_template_requirements): New.
+ (normalize_nontemplate_requirements): New.
+ (normalize_constraint_expression): New.
+ (tsubst_parameter_mapping): New.
+ (get_mapped_args): New.
+ (parameter_mapping_equivalent_p): New. Use template_args_equal.
+ (atomic_constraints_identical_p): New.
+ (hash_atomic_constraint): New.
+ (satisfying_constraint_p): New. Guard against recursive evaluation of
+ constraints during satisfaction.
+ (satisfy_conjunction): New.
+ (satisfy_disjunction): New.
+ (sat_entry): New class for hashing satisfaction results.
+ (sat_hasher): New hash traits.
+ (sat_cache): New.
+ (get_satisfaction): New. Returns cached satisfaction result.
+ (save_satisfaction): New. Caches a satisfaction result.
+ (clear_satisfaction_cache): New.
+ (satisfaction_cache): New. Helps manage satisfaction cache requests.
+ (decl_satisfied_cache): New.
+ (satisfy_atom): New.
+ (satisfy_constraint_r): New.
+ (satisfy_constraint): Use new satisfaction algorithm.
+ (evaluate_concept_check): New.
+ (evaluate_concept): Removed.
+ (evaluate_function_concept): Removed.
+ (evaluate_variable_concept): Removed.
+ (satisfy_constraint_expression): New.
+ (constraint_expression_satisfied_p): New.
+ (constraints_satisfied_p): Use strip_inheriting_ctors. Use
+ push_/pop_access_scope.
+ (more_constrained): Normalize before calling out to subsumption. Allow
+ classes as arguments.
+ (strictly_subsumes): Allow non-templates as arguments. Accept a new
+ template argument.
+ (weakly_subsumes): New.
+ (at_least_as_constrained): Removed.
+ (diagnose_other_expression): Removed.
+ (diagnose_predicate_constraint): Removed.
+ (diagnose_pack_expansion): Removed.
+ (diagnose_check_constraint): Removed.
+ (diagnose_logical_constraint): Removed.
+ (diagnose_expression_constraint): Removed.
+ (diagnose_type_constraint): Removed.
+ (diagnose_implicit_conversion_constraint): Removed.
+ (diagnose_argument_deduction_constraint): Removed.
+ (diagnose_exception_constraint): Removed.
+ (diagnose_parameterized_constraint): Removed.
+ (diagnose_argument_deduction_constraint): Removed.
+ (diagnose_argument_deduction_constraint): Removed.
+ (diagnose_argument_deduction_constraint): Removed.
+ (diagnose_trait_expr): New.
+ (diagnose_requires_expr): New.
+ (diagnose_atomic_constraint): New.
+ (diagnose_valid_expression) Stop wrongly diagnosing valid expressions.
+ Don't substitute as if in template decls. This causes substitution
+ to generate expressions that aren't suitable for use with the noexcept
+ routines.
+ (diagnose_valid_type) Likewise.
+ (diagnose_compound_requirement) Actually emit diagnostics for
+ the causes of errors.Call force_paren_expr_uneval.
+ (diagnose_declaration_constraints): Turn on template processing to
+ suppress certain analyses.
+ * cp-objcp-common.c (cp_common_init_ts): Make concepts typed.
+ (cp_get_debug_type): Use hash_map_safe_*.
+ * cp-tree.h: New function declarations for semantic actions, other
+ facilities. Remove declaration no longer used or needed. Remove
+ unused _CONSTR macros.
+ (LANG_DECL_HAS_MIN): Add CONCEPT_DECL.
+ (template_info_decl_check): Factor macro check into an inline function.
+ (DECL_TEMPLATE_INFO): Use new check facility.
+ (finish_concept_definition): New. Don't invalid concept declarations
+ with invalid initializers.
+ (find_template_parameters): New.
+ (concept_definition_p): New.
+ (concept_check_p): New.
+ (variable_concept_check_p): New.
+ (force_paren_expr_uneval): New.
+ (ovl_iterator::using_p): A USING_DECL by itself was also
+ introduced by a using-declaration.
+ (struct tree_template_info): Use tree_base instead of
+ tree_common. Add tmpl and args fields.
+ (TI_TEMPLATE, TI_ARGS): Adjust.
+ (DECLTYPE_FOR_INIT_CAPTURE): Remove.
+ (CONSTR_CHECK, CONSTR_INFO, CONSTR_EXPR, CONSTR_CONTEXT): New.
+ (ATOMIC_CONSTR_MAP, TRAIT_EXPR_LOCATION): New.
+ (struct tree_trait_expr): Add locus field.
+ (enum tsubst_flags): Add tf_norm as a hint to generate normalization
+ context when diagnosing constraint failure.
+ * cp-tree.def: Remove unused _CONSTR nodes and rename PRED_CONSTR
+ to ATOMIC_CONSTR.
+ (CONCEPT_DECL): New.
+ * cxx-pretty-print.c: Remove constraint printing code.
+ (pp_cxx_concept_definition): New.
+ (pp_cxx_template_declaration): Print concept definitions.
+ (pp_cxx_check_constraint): Update printing for concept definitions.
+ (pp_cxx_nested_name_specifier): Fix a weird
+ case where we're printing '::::' for concepts.
+ (simple_type_specifier): Print requirements for placeholder types.
+ (pp_cxx_constrained_type_spec): Print the associated requirements of
+ a placeholder type.
+ (pp_cxx_compound_requirement): Add space before the '->'.
+ (pp_cxx_parameter_mapping): Print the parameter mapping.
+ (pp_cxx_atomic_constraint): Use the function above.
+ * decl.c (redeclaration_error_message): New error for concepts.
+ (grokdeclarator): Check for and disallow decltype(auto) in parameter
+ declarations.
+ (grokfndecl): Don't normalize constraints. Add check for constraints
+ on declaration.
+ (grokvardecl): Don't normalize constraints.
+ (grok_special_member_properties): Don't set TYPE_HAS_COMPLEX_*.
+ (function_requirements_equivalent_p): New. Compare trailing
+ requires clauses. Compare combined constraints in pre-C++20 mode.
+ (decls_match): Compare trailing requires clauses. Compare template
+ heads for function templates. Remove old constraint comparison.
+ Simplify comparison of functions, function templates.
+ (duplicate_function_template_decls): New. Refactor a nasty if
+ condition into a single predicate.
+ (require_deduced_type): Don't complain if we already complained about
+ deduction failure.
+ (finish_function): Perform auto deduction to ensure that constraints
+ are checked even when functions contain no return statements. Only do
+ auto deduction if we haven't previously seen any return statements.
+ This prevents multiple diagnostics of the same error.
+ (store_decomp_type): Remove.
+ (cp_finish_decomp): Use hash_map_safe_put.
+ * error.c: Remove constraint printing code.
+ (dump_decl): Dump concept definitions. Handle wildcard declarations.
+ (dump_template_decl): Likewise.
+ (dump_type): Print associated requirements for placeholder
+ types.
+ (rebuild_concept_check): New.
+ (maybe_print_single_constraint_context): New.
+ (maybe_print_constraint_context): Recursively print nested contexts.
+ * init.c (get_nsdmi): Use hash_map_safe_*.
+ * lambda.c (maybe_add_lambda_conv_op): Bail if deduction failed.
+ (add_capture): Copy parameter packs from init.
+ (lambda_capture_field_type): Always use auto for init-capture.
+ * logic.cc: Completely rewrite.
+ (constraint_hash): New.
+ (clause/ctor): Save atoms in the hash table.
+ (replace): Save atoms during replacement.
+ (insert): Save atoms during insertion.
+ (contains): Only search the hash table for containment.
+ (clause): Keep a hash of atomic constraints.
+ (clause::clause): Explicitly copy the hash table when copying.
+ (disjunction_p, conjunction_p, atomic_p, dnf_size, cnf_size): New.
+ (diagnose_constraint_size): New.
+ (subsumes_constraints_nonnull): Compare the sizes of normalized formula
+ to determine the cheapest decomposition.
+ * name-lookup.c (diagnose_name_conflict): Diagnose name issues with
+ concepts.
+ (matching_fn_p): Check constraints.
+ (push_class_level_binding_1): Move overloaded functions case down,
+ accept FUNCTION_DECL as target_decl.
+ * parser.c (enum required_token): New required token for auto.
+ (make_location): Add overload taking lexer as last parm.
+ (cp_parser_required_error): Diagnose missing auto.
+ (cp_parser_diagnose_ungrouped_constraint_plain): New.
+ (cp_parser_diagnose_ungrouped_constraint_plain): New.
+ (cp_parser_constraint_primary_expression): New. Tentatively parse the
+ primary expression. If that fails tentatively parse a lower
+ precedence expression in order to diagnose the error.
+ (cp_parser_check_non_logical_constraint): New. Performs a trial
+ parse of the right-hand-side of non-logical operators in order to
+ generate good diagnostics.
+ (cp_parser_constraint_logical_and_expression): New.
+ (cp_parser_constraint_logical_or_expression): New.
+ (cp_parser_requires_clause_expression): New.
+ (cp_parser_requires_clause): Renamed to cp_parser_constraint_expression.
+ (cp_parser_requires_clause_opt): Parse the requires-clause differently
+ in -fconcepts and -std=c++2a modes.
+ (cp_parser_requirement_list): Rename to cp_parser_requirement_seq.
+ Rewrite so that semicolons are parsed
+ along with requirements, not the sequence.
+ (cp_parser_simple_requirement): Expect a semicolon at end.
+ (cp_parser_compound_requirement): Expect a semicolon at end. Only
+ allow trailing-return-type with -fconcepts-ts.
+ (cp_parser_nested_requirement): Expect a semicolon at end. Parse
+ constraint-expressions.
+ (cp_parser_concept_definition): New. Don't fail parsing the concept
+ definition if the initializer is ill-formed. Don't declare the concept
+ before parsing the initializer.
+ (cp_parser_constraint_expression): Declare earlier.
+ (cp_parser_type_requirement): Current scope is not valid.
+ (cp_parser_requires_expression): Commit to the tentative parse.
+ (cp_parser_decl_specifier_seq): Warn when concept appears to be used
+ as a decl-specifier.
+ (cp_parser_template_declaration_after_parameters): Parse concept
+ definitions.
+ (cp_parser_template_id): Don't try to resolve a concept template-id yet.
+ (cp_parser_template_id_expr): Resolve it as a concept check.
+ (cp_parser_decl_specifier_seq): Warn on 'concept bool'.
+ (cp_parser_type_parameter): Combine expressions not
+ constraints.
+ (cp_parser_explicit_template_declaration): Combine expressions not
+ constraints.
+ (cp_parser_maybe_concept_name): Removed.
+ (cp_parser_simple_type_specifier): Handle an error condition of
+ a bad constrained type specifier. Expect auto or decltype after
+ a concept name. Also handle the case where we have a template-id
+ as a concept check.
+ (cp_parser_template_introduction): Diagnose errors on invalid
+ introductions. Give up if it doesn't start with a concept name.
+ Pedwarn if not -fconcepts-ts.
+ (synthesize_implicit_template_parm): Don't do consistent binding.
+ Use a new flag for constrained parameters. Combine expressions,
+ not constraints. Fail if we get a placeholder in block scope.
+ Placeholders that do not constrain types are not allowed in parameter
+ declarations, so don't handle them.
+ (cp_parser_placeholder_type_specifier): New. Implement parsing of
+ placeholder type specifiers following a concept name or partial
+ concept check. Disallow decltype(auto) parameters.
+ (cp_parser_nested_name_specifier_opt): If the token is already
+ CPP_NESTED_NAME_SPECIFIER, leave it alone.
+ (cp_parser_id_expression, cp_parser_unqualified_id): Call
+ cp_parser_template_id_expr.
+ (cp_parser_placeholder_type_specifier): Add tentative parm. Don't
+ expect a WILDCARD_DECL.
+ (cp_parser_trait_expr): Pass trait_loc down.
+ (cp_parser_postfix_expression): Do set location of dependent member
+ call.
+ * pt.c (finish_concept_definition): New.
+ (push_template_decl_real): Handle concept definitions.
+ (start_concept_definition): Let push_template_decl_real handle the
+ creation of the template.
+ (get_constraints): Return null if the table hasn't been initialized.
+ (tsubst_copy_and_build): Build template-id expressions for concept
+ checks.
+ [TRAIT_EXPR]: Pass trait_loc down.
+ (lookup_template_class_1): Add the template name to the constraint
+ failure diagnostic.
+ (lookup_and_finish_template_variable): Build concept checks
+ with the correct arguments.
+ (tsubst_function_decl): Don't substitute through constraints.
+ Always associate constraints with functions.
+ (template_parm_level_and_index): Make non-static.
+ (for_each_template_parm_r): Handle requires expressions.
+ (keep_template_parm): New.
+ (find_template_parameters): New.
+ (more_specialized_fn): Change how winners and losers are chosen.
+ (make_constrained_auto): Don't normalize constraints.
+ (template_parameters_equivalent_p): New. Compare template
+ parameters. Add a comparison for implicitly vs. explicitly declared
+ parameters.
+ (template_parameter_lists_equivalent_p): New. Compare template
+ parameter lists.
+ (template_requirements_equivalent_p): New.
+ (template_heads_equivalent_p): New. Compare template heads.
+ (template_parameter_constraints_equivalent_p): New.
+ (is_compatible_template_arg): Use weakly_subsumes.
+ (maybe_new_partial_specialization): Use new constraint comparison
+ for finding specializations.
+ (process_partial_specialization): Pass main template as argument.
+ (more_specialized_partial_spec): Don't immediately return when
+ detecting a winner.
+ (make_constrained_auto): Handle concept definitions.
+ (do_auto_deduction): Update auto deduction for new concept model.
+ Extract the function concept correctly; rename constr to check to
+ reflect the kind of node.
+ (tsubst): Adjust wildcard argument during substitution.
+ [DECLTYPE_TYPE]: Remove init-capture handling.
+ (tsubst_copy_and_build): Build concept checks, not template ids.
+ Defer checks of function concepts. Handle concepts before variable
+ templates. Handle calls to function concepts explicitly.
+ (coerce_template_parms): Use concept_definition_p. Handle a deduction
+ error where a potentially empty pack can be supplied after the last
+ parameter of a concept.
+ (finish_template_variable): Don't process concepts here.
+ (instantiation_dependent_r): Use concept_check_p.
+ (tsubst_template_args): Make non-static.
+ (make_constrained_placeholder_type): New. Refactored from
+ make_constrained_auto.
+ (make_constrained_auto) Use make_constrained_placeholder_type.
+ (make_constrained_decltype_auto) New.
+ (tsubst_function_parms): New.
+ (value_dependent_expression_p) [TEMPLATE_ID_EXPR]: Use
+ concept_definition_p.
+ (push_access_scope, pop_access_scope): No longer static.
+ (tsubst_template_parm): Substitute TEMPLATE_PARM_CONSTRAINTS.
+ (tsubst_friend_function): Use tsubst_constraint. Use generic_targs_for.
+ (get_underlying_template) Use generic_targs_for.
+ (uses_parameter_packs): Return tree.
+ (gen_elem_of_pack_expansion_instantiation): Don't push
+ local_specialization_stack.
+ (prepend_one_capture): New.
+ (tsubst_lambda_expr): Use prepend_one_capture. Don't touch
+ local_specializations.
+ (template_parms_level_to_args): No longer static.
+ (add_outermost_template_args): Likewise.
+ (find_template_parameter_info): New. Provide context for finding
+ template parameters.
+ (keep_template_parm): Don't keep parameters declared at depth levels
+ greater than those of the template parameters of the source declaration.
+ Don't propagate cv-qualified types. Return 0, so we find all template
+ parameters, not the just first.
+ (any_template_parm_r): New. Handle cases that are mishandled by
+ for_each_template_parm_r.
+ (generic_targs_for): Factor out of coerce_template_args_for_ttp.
+ (tsubst_argument_pack): Factor out of tsubst_template_args.
+ (constraint_sat_entry): Removed.
+ (constraint_sat_hasher): Removed.
+ (concept_spec_entry): Removed.
+ (concept_spec_hasher): Removed.
+ (constraint_memos): Removed.
+ (concept_memos): Removed.
+ (lookup_constraint_satisfaction): Removed.
+ (memoize_constraint_satisfaction): Removed.
+ (lookup_concept_satisfaction): Removed.
+ (memoize_concept_satisfaction): Removed.
+ (concept_expansions): Removed.
+ (get_concept_expansion): Removed.
+ (save_concept_expansion): Removed.
+ (init_constraint_processing): Remove initialization of non-existing
+ resources.
+ (find_template_requirement): New. Search for the sub-requirement
+ within the associated constraints.
+ (convert_generic_types_to_packs): Also transform the associated
+ constraint and update the current template requirements.
+ (store_defaulted_ttp, lookup_defaulted_ttp): Remove.
+ (add_defaults_to_ttp): Use hash_map_safe_*.
+ * semantics.c (finish_call_expr): Diagnose calls to concepts.
+ Handle concept checks explicitly.
+ (finish_id_expression): Evaluate variable concepts as part of
+ id-expression processing. Don't treat variable concepts as variables,
+ and don't process function concepts as plain id-expressions.
+ (force_paren_expr): Add even_uneval parm.
+ (finish_trait_expr): Add location parm.
+ * tree.c (special_memfn_p): New.
+ (cp_expr_location): Handle TRAIT_EXPR.
+ * typeck.c (check_return_expr): Actually use the diagnostic kind
+ when performing return-type deduction.
+ * typeck2.c (build_functional_cast): Don't rely on the location of
+ 'auto'.
+
+2019-10-09 Paolo Carlini <paolo.carlini@oracle.com>
+
+ * decl.c (grok_ctor_properties): Use DECL_SOURCE_LOCATION.
+ * typeck.c (cp_build_binary_op): Use the op_location_t argument
+ in many error messages.
+
+2019-10-08 Martin Sebor <msebor@redhat.com>
+
+ PR c++/92001
+ * call.c (maybe_warn_class_memaccess): Handle arrays.
+
+2019-10-07 Paolo Carlini <paolo.carlini@oracle.com>
+
+ * call.c (resolve_args): Use cp_expr_loc_or_input_loc in one place.
+ * decl.c (grokdeclarator): Use id_loc in one place.
+ * decl2.c (build_anon_union_vars): Use DECL_SOURCE_LOCATION.
+ * parser.c (cp_parser_delete_expression): Fix the location of the
+ returned expression.
+ (cp_parser_throw_expression): Likewise.
+ * pt.c (determine_specialization): Use DECL_SOURCE_LOCATION.
+
2019-10-05 Jakub Jelinek <jakub@redhat.com>
PR c++/91369 - Implement P0784R7: constexpr new
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 07f07c91307..76c68b947f2 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -122,7 +122,8 @@ struct conversion {
of using this field directly. */
conversion *next;
/* The expression at the beginning of the conversion chain. This
- variant is used only if KIND is ck_identity or ck_ambig. */
+ variant is used only if KIND is ck_identity or ck_ambig. You can
+ use conv_get_original_expr to get this expression. */
tree expr;
/* The array of conversions for an initializer_list, so this
variant is used only when KIN D is ck_list. */
@@ -223,6 +224,8 @@ static void add_candidates (tree, tree, const vec<tree, va_gc> *, tree, tree,
tsubst_flags_t);
static conversion *merge_conversion_sequences (conversion *, conversion *);
static tree build_temp (tree, tree, int, diagnostic_t *, tsubst_flags_t);
+static conversion *build_identity_conv (tree, tree);
+static inline bool conv_binds_to_array_of_unknown_bound (conversion *);
/* Returns nonzero iff the destructor name specified in NAME matches BASETYPE.
NAME can take many forms... */
@@ -717,24 +720,12 @@ inherited_ctor_rejection (void)
return r;
}
-// Build a constraint failure record, saving information into the
-// template_instantiation field of the rejection. If FN is not a template
-// declaration, the TMPL member is the FN declaration and TARGS is empty.
+/* Build a constraint failure record. */
static struct rejection_reason *
-constraint_failure (tree fn)
+constraint_failure (void)
{
struct rejection_reason *r = alloc_rejection (rr_constraint_failure);
- if (tree ti = DECL_TEMPLATE_INFO (fn))
- {
- r->u.template_instantiation.tmpl = TI_TEMPLATE (ti);
- r->u.template_instantiation.targs = TI_ARGS (ti);
- }
- else
- {
- r->u.template_instantiation.tmpl = fn;
- r->u.template_instantiation.targs = NULL_TREE;
- }
return r;
}
@@ -1078,7 +1069,7 @@ build_array_conv (tree type, tree ctor, int flags, tsubst_flags_t complain)
c->rank = rank;
c->user_conv_p = user;
c->bad_p = bad;
- c->u.next = NULL;
+ c->u.next = build_identity_conv (TREE_TYPE (ctor), ctor);
return c;
}
@@ -1378,7 +1369,7 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
if (same_type_p (from, to))
/* OK */;
- else if (c_cast_p && comp_ptr_ttypes_const (to, from))
+ else if (c_cast_p && comp_ptr_ttypes_const (to, from, bounds_either))
/* In a C-style cast, we ignore CV-qualification because we
are allowed to perform a static_cast followed by a
const_cast. */
@@ -1484,8 +1475,18 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
conv = build_conv (ck_std, to, conv);
- /* Give this a better rank if it's a promotion. */
- if (same_type_p (to, type_promotes_to (from))
+ tree underlying_type = NULL_TREE;
+ if (TREE_CODE (from) == ENUMERAL_TYPE
+ && ENUM_FIXED_UNDERLYING_TYPE_P (from))
+ underlying_type = ENUM_UNDERLYING_TYPE (from);
+
+ /* Give this a better rank if it's a promotion.
+
+ To handle CWG 1601, also bump the rank if we are converting
+ an enumeration with a fixed underlying type to the underlying
+ type. */
+ if ((same_type_p (to, type_promotes_to (from))
+ || (underlying_type && same_type_p (to, underlying_type)))
&& next_conversion (conv)->rank <= cr_promotion)
conv->rank = cr_promotion;
}
@@ -1670,7 +1671,14 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags,
maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS);
/* DR 1288: Otherwise, if the initializer list has a single element
of type E and ... [T's] referenced type is reference-related to E,
- the object or reference is initialized from that element... */
+ the object or reference is initialized from that element...
+
+ ??? With P0388R4, we should bind 't' directly to U{}:
+ using U = A[2];
+ A (&&t)[] = {U{}};
+ because A[] and A[2] are reference-related. But we don't do it
+ because grok_reference_init has deduced the array size (to 1), and
+ A[1] and A[2] aren't reference-related. */
if (CONSTRUCTOR_NELTS (expr) == 1)
{
tree elt = CONSTRUCTOR_ELT (expr, 0)->value;
@@ -2251,10 +2259,9 @@ add_function_candidate (struct z_candidate **candidates,
/* Second, for a function to be viable, its constraints must be
satisfied. */
- if (flag_concepts && viable
- && !constraints_satisfied_p (fn))
+ if (flag_concepts && viable && !constraints_satisfied_p (fn))
{
- reason = constraint_failure (fn);
+ reason = constraint_failure ();
viable = false;
}
@@ -3730,11 +3737,7 @@ print_z_candidate (location_t loc, const char *msgstr,
"class type is invalid");
break;
case rr_constraint_failure:
- {
- tree tmpl = r->u.template_instantiation.tmpl;
- tree args = r->u.template_instantiation.targs;
- diagnose_constraints (cloc, tmpl, args);
- }
+ diagnose_constraints (cloc, fn, NULL_TREE);
break;
case rr_inherited_ctor:
inform (cloc, " an inherited constructor is not a candidate for "
@@ -4382,7 +4385,8 @@ resolve_args (vec<tree, va_gc> *args, tsubst_flags_t complain)
else if (VOID_TYPE_P (TREE_TYPE (arg)))
{
if (complain & tf_error)
- error ("invalid use of void expression");
+ error_at (cp_expr_loc_or_input_loc (arg),
+ "invalid use of void expression");
return NULL;
}
else if (invalid_nonstatic_memfn_p (EXPR_LOCATION (arg), arg, complain))
@@ -4532,25 +4536,7 @@ build_new_function_call (tree fn, vec<tree, va_gc> **args,
through flags so that later we can use it to decide whether to warn
about peculiar null pointer conversion. */
if (TREE_CODE (fn) == TEMPLATE_ID_EXPR)
- {
- /* If overload resolution selects a specialization of a
- function concept for non-dependent template arguments,
- the expression is true if the constraints are satisfied
- and false otherwise.
-
- NOTE: This is an extension of Concepts Lite TS that
- allows constraints to be used in expressions. */
- if (flag_concepts && !processing_template_decl)
- {
- tree tmpl = DECL_TI_TEMPLATE (cand->fn);
- tree targs = DECL_TI_ARGS (cand->fn);
- tree decl = DECL_TEMPLATE_RESULT (tmpl);
- if (DECL_DECLARED_CONCEPT_P (decl))
- return evaluate_function_concept (decl, targs);
- }
-
- flags |= LOOKUP_EXPLICIT_TMPL_ARGS;
- }
+ flags |= LOOKUP_EXPLICIT_TMPL_ARGS;
result = build_over_call (cand, flags, complain);
}
@@ -6995,6 +6981,27 @@ maybe_inform_about_fndecl_for_bogus_argument_init (tree fn, int argnum)
" initializing argument %P of %qD", argnum, fn);
}
+/* Maybe warn about C++20 Conversions to arrays of unknown bound. C is
+ the conversion, EXPR is the expression we're converting. */
+
+static void
+maybe_warn_array_conv (location_t loc, conversion *c, tree expr)
+{
+ if (cxx_dialect >= cxx2a)
+ return;
+
+ tree type = TREE_TYPE (expr);
+ type = strip_pointer_operator (type);
+
+ if (TREE_CODE (type) != ARRAY_TYPE
+ || TYPE_DOMAIN (type) == NULL_TREE)
+ return;
+
+ if (conv_binds_to_array_of_unknown_bound (c))
+ pedwarn (loc, OPT_Wpedantic, "conversions to arrays of unknown bound "
+ "are only available with %<-std=c++2a%> or %<-std=gnu++2a%>");
+}
+
/* Perform the conversions in CONVS on the expression EXPR. FN and
ARGNUM are used for diagnostics. ARGNUM is zero based, -1
indicates the `this' argument of a method. INNER is nonzero when
@@ -7414,8 +7421,20 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
error_at (loc, "cannot bind non-const lvalue reference of "
"type %qH to an rvalue of type %qI", totype, extype);
else if (!reference_compatible_p (TREE_TYPE (totype), extype))
- error_at (loc, "binding reference of type %qH to %qI "
- "discards qualifiers", totype, extype);
+ {
+ /* If we're converting from T[] to T[N], don't talk
+ about discarding qualifiers. (Converting from T[N] to
+ T[] is allowed by P0388R4.) */
+ if (TREE_CODE (extype) == ARRAY_TYPE
+ && TYPE_DOMAIN (extype) == NULL_TREE
+ && TREE_CODE (TREE_TYPE (totype)) == ARRAY_TYPE
+ && TYPE_DOMAIN (TREE_TYPE (totype)) != NULL_TREE)
+ error_at (loc, "cannot bind reference of type %qH to %qI "
+ "due to different array bounds", totype, extype);
+ else
+ error_at (loc, "binding reference of type %qH to %qI "
+ "discards qualifiers", totype, extype);
+ }
else
gcc_unreachable ();
maybe_print_user_conv_context (convs);
@@ -7423,6 +7442,8 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
return error_mark_node;
}
+ else if (complain & tf_warning)
+ maybe_warn_array_conv (loc, convs, expr);
/* If necessary, create a temporary.
@@ -7506,7 +7527,10 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
case ck_qual:
/* Warn about deprecated conversion if appropriate. */
if (complain & tf_warning)
- string_conv_p (totype, expr, 1);
+ {
+ string_conv_p (totype, expr, 1);
+ maybe_warn_array_conv (loc, convs, expr);
+ }
break;
case ck_ptr:
@@ -8923,7 +8947,9 @@ maybe_warn_class_memaccess (location_t loc, tree fndecl,
unsigned srcidx = !dstidx;
tree dest = (*args)[dstidx];
- if (!TREE_TYPE (dest) || !INDIRECT_TYPE_P (TREE_TYPE (dest)))
+ if (!TREE_TYPE (dest)
+ || (TREE_CODE (TREE_TYPE (dest)) != ARRAY_TYPE
+ && !INDIRECT_TYPE_P (TREE_TYPE (dest))))
return;
tree srctype = NULL_TREE;
@@ -10096,6 +10122,50 @@ maybe_handle_ref_bind (conversion **ics)
return NULL;
}
+/* Get the expression at the beginning of the conversion chain C. */
+
+static tree
+conv_get_original_expr (conversion *c)
+{
+ for (; c; c = next_conversion (c))
+ if (c->kind == ck_identity || c->kind == ck_ambig)
+ return c->u.expr;
+ return NULL_TREE;
+}
+
+/* Return a tree representing the number of elements initialized by the
+ list-initialization C. The caller must check that C converts to an
+ array type. */
+
+static tree
+nelts_initialized_by_list_init (conversion *c)
+{
+ /* If the array we're converting to has a dimension, we'll use that. */
+ if (TYPE_DOMAIN (c->type))
+ return array_type_nelts_top (c->type);
+ else
+ {
+ /* Otherwise, we look at how many elements the constructor we're
+ initializing from has. */
+ tree ctor = conv_get_original_expr (c);
+ return size_int (CONSTRUCTOR_NELTS (ctor));
+ }
+}
+
+/* True iff C is a conversion that binds a reference or a pointer to
+ an array of unknown bound. */
+
+static inline bool
+conv_binds_to_array_of_unknown_bound (conversion *c)
+{
+ /* ck_ref_bind won't have the reference stripped. */
+ tree type = non_reference (c->type);
+ /* ck_qual won't have the pointer stripped. */
+ type = strip_pointer_operator (type);
+ return (TREE_CODE (type) == ARRAY_TYPE
+ && TYPE_DOMAIN (type) == NULL_TREE);
+}
+
/* Compare two implicit conversion sequences according to the rules set out in
[over.ics.rank]. Return values:
@@ -10209,6 +10279,38 @@ compare_ics (conversion *ics1, conversion *ics2)
if (f1 != f2)
return 0;
}
+ /* List-initialization sequence L1 is a better conversion sequence than
+ list-initialization sequence L2 if
+
+ -- L1 and L2 convert to arrays of the same element type, and either
+ the number of elements n1 initialized by L1 is less than the number
+ of elements n2 initialized by L2, or n1=n2 and L2 converts to an array
+ of unknown bound and L1 does not. (Added in CWG 1307 and extended by
+ P0388R4.) */
+ else if (t1->kind == ck_aggr
+ && TREE_CODE (t1->type) == ARRAY_TYPE
+ && TREE_CODE (t2->type) == ARRAY_TYPE)
+ {
+ /* The type of the array elements must be the same. */
+ if (!same_type_p (TREE_TYPE (t1->type), TREE_TYPE (t2->type)))
+ return 0;
+
+ tree n1 = nelts_initialized_by_list_init (t1);
+ tree n2 = nelts_initialized_by_list_init (t2);
+ if (tree_int_cst_lt (n1, n2))
+ return 1;
+ else if (tree_int_cst_lt (n2, n1))
+ return -1;
+ /* The n1 == n2 case. */
+ bool c1 = conv_binds_to_array_of_unknown_bound (t1);
+ bool c2 = conv_binds_to_array_of_unknown_bound (t2);
+ if (c1 && !c2)
+ return -1;
+ else if (!c1 && c2)
+ return 1;
+ else
+ return 0;
+ }
else
{
/* For ambiguous or aggregate conversions, use the target type as
@@ -10504,6 +10606,28 @@ compare_ics (conversion *ics1, conversion *ics2)
if (same_type_ignoring_top_level_qualifiers_p (to_type1, to_type2))
{
+ /* Per P0388R4:
+
+ void f (int(&)[]), // (1)
+ f (int(&)[1]), // (2)
+ f (int*); // (3)
+
+ (2) is better than (1), but (3) should be equal to (1) and to
+ (2). For that reason we don't use ck_qual for (1) which would
+ give it the cr_exact rank while (3) remains ck_identity.
+ Therefore we compare (1) and (2) here. For (1) we'll have
+
+ ck_ref_bind <- ck_identity
+ int[] & int[1]
+
+ so to handle this we must look at ref_conv. */
+ bool c1 = conv_binds_to_array_of_unknown_bound (ref_conv1);
+ bool c2 = conv_binds_to_array_of_unknown_bound (ref_conv2);
+ if (c1 && !c2)
+ return -1;
+ else if (!c1 && c2)
+ return 1;
+
int q1 = cp_type_quals (TREE_TYPE (ref_conv1->type));
int q2 = cp_type_quals (TREE_TYPE (ref_conv2->type));
if (ref_conv1->bad_p)
@@ -10518,6 +10642,31 @@ compare_ics (conversion *ics1, conversion *ics2)
}
}
+ /* [over.ics.rank]
+
+ Per CWG 1601:
+ -- A conversion that promotes an enumeration whose underlying type
+ is fixed to its underlying type is better than one that promotes to
+ the promoted underlying type, if the two are different. */
+ if (ics1->rank == cr_promotion
+ && ics2->rank == cr_promotion
+ && UNSCOPED_ENUM_P (from_type1)
+ && ENUM_FIXED_UNDERLYING_TYPE_P (from_type1)
+ && same_type_p (from_type1, from_type2))
+ {
+ tree utype = ENUM_UNDERLYING_TYPE (from_type1);
+ tree prom = type_promotes_to (from_type1);
+ if (!same_type_p (utype, prom))
+ {
+ if (same_type_p (to_type1, utype)
+ && same_type_p (to_type2, prom))
+ return 1;
+ else if (same_type_p (to_type2, utype)
+ && same_type_p (to_type1, prom))
+ return -1;
+ }
+ }
+
/* Neither conversion sequence is better than the other. */
return 0;
}
@@ -10838,8 +10987,11 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn,
return winner;
}
- // C++ Concepts
- // or, if not that, F1 is more constrained than F2.
+ /* Concepts: ... or, if not that, F1 is more constrained than F2.
+
+ FIXME: For function templates with no winner, this subsumption may
+ be computed a separate time. This needs to be validated, and if
+ so, the redundant check removed. */
if (flag_concepts && DECL_P (cand1->fn) && DECL_P (cand2->fn))
{
winner = more_constrained (cand1->fn, cand2->fn);
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 4abcfaf4c1d..b6afdc487e7 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -7189,6 +7189,9 @@ finish_struct_1 (tree t)
/* Finish debugging output for this type. */
rest_of_type_compilation (t, ! LOCAL_CLASS_P (t));
+ /* Recalculate satisfaction that might depend on completeness. */
+ clear_satisfaction_cache ();
+
if (TYPE_TRANSPARENT_AGGR (t))
{
tree field = first_field (t);
diff --git a/gcc/cp/config-lang.in b/gcc/cp/config-lang.in
index 6e5f04677d6..adfe1b2415d 100644
--- a/gcc/cp/config-lang.in
+++ b/gcc/cp/config-lang.in
@@ -39,6 +39,7 @@ gtfiles="\
\$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-format.c \
\$(srcdir)/c-family/c-cppbuiltin.c \$(srcdir)/c-family/c-pragma.c \
\$(srcdir)/cp/call.c \$(srcdir)/cp/class.c \$(srcdir)/cp/constexpr.c \
+\$(srcdir)/cp/constraint.cc \
\$(srcdir)/cp/cp-gimplify.c \
\$(srcdir)/cp/cp-lang.c \$(srcdir)/cp/cp-objcp-common.c \
\$(srcdir)/cp/decl.c \$(srcdir)/cp/decl2.c \
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 18ad0d76ee1..9e8177ca33e 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -5115,8 +5115,6 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
case MAX_EXPR:
case LSHIFT_EXPR:
case RSHIFT_EXPR:
- case LROTATE_EXPR:
- case RROTATE_EXPR:
case BIT_IOR_EXPR:
case BIT_XOR_EXPR:
case BIT_AND_EXPR:
@@ -5523,7 +5521,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
'!requires (T t) { ... }' which is not transformed into
a constraint. */
if (!processing_template_decl)
- return evaluate_constraint_expression (t, NULL_TREE);
+ return satisfy_constraint_expression (t);
else
*non_constant_p = true;
return t;
@@ -5539,6 +5537,20 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
r = void_node;
break;
+ case TEMPLATE_ID_EXPR:
+ {
+ /* We can evaluate template-id that refers to a concept only if
+ the template arguments are non-dependent. */
+ if (!concept_definition_p (TREE_OPERAND (t, 0)))
+ internal_error ("unexpected template-id %qE", t);
+
+ if (!processing_template_decl)
+ return satisfy_constraint_expression (t);
+ else
+ *non_constant_p = true;
+ return t;
+ }
+
case ASM_EXPR:
if (!ctx->quiet)
inline_asm_in_constexpr_error (cp_expr_loc_or_input_loc (t));
@@ -5980,13 +5992,15 @@ clear_cv_cache (void)
cv_cache->empty ();
}
-/* Dispose of the whole CV_CACHE and FOLD_CACHE. */
+/* Dispose of the whole CV_CACHE, FOLD_CACHE, and satisfaction caches. */
void
-clear_cv_and_fold_caches (void)
+clear_cv_and_fold_caches (bool sat /*= true*/)
{
clear_cv_cache ();
clear_fold_cache ();
+ if (sat)
+ clear_satisfaction_cache ();
}
/* Internal function handling expressions in templates for
@@ -7087,8 +7101,6 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
case MAX_EXPR:
case LSHIFT_EXPR:
case RSHIFT_EXPR:
- case LROTATE_EXPR:
- case RROTATE_EXPR:
case BIT_IOR_EXPR:
case BIT_XOR_EXPR:
case BIT_AND_EXPR:
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c7a172cce4d..db4a81858f6 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -46,89 +46,189 @@ along with GCC; see the file COPYING3. If not see
#include "toplev.h"
#include "type-utils.h"
+static tree satisfaction_value (tree t);
+
+/* When we're parsing or substuting a constraint expression, we have slightly
+ different expression semantics. In particular, we don't want to reduce a
+ concept-id to a satisfaction value. */
+
+processing_constraint_expression_sentinel::
+processing_constraint_expression_sentinel ()
+{
+ ++scope_chain->x_processing_constraint;
+}
+
+processing_constraint_expression_sentinel::
+~processing_constraint_expression_sentinel ()
+{
+ --scope_chain->x_processing_constraint;
+}
+
+bool
+processing_constraint_expression_p ()
+{
+ return scope_chain->x_processing_constraint != 0;
+}
+
/*---------------------------------------------------------------------------
- Operations on constraints
+ Constraint expressions
---------------------------------------------------------------------------*/
-/* Returns true if C is a constraint tree code. Note that ERROR_MARK
- is a valid constraint. */
+/* Information provided to substitution. */
+
+struct subst_info
+{
+ subst_info (tsubst_flags_t cmp, tree in)
+ : complain (cmp), in_decl (in)
+ { }
+
+ /* True if we should not diagnose errors. */
+ bool quiet() const
+ {
+ return complain == tf_none;
+ }
+
+ /* True if we should diagnose errors. */
+ bool noisy() const
+ {
+ return !quiet ();
+ }
+
+ tsubst_flags_t complain;
+ tree in_decl;
+};
+
+/* True if T is known to be some type other than bool. Note that this
+ is false for dependent types and errors. */
static inline bool
-constraint_p (tree_code c)
+known_non_bool_p (tree t)
{
- return ((PRED_CONSTR <= c && c <= DISJ_CONSTR)
- || c == EXPR_PACK_EXPANSION
- || c == ERROR_MARK);
+ return (t && !WILDCARD_TYPE_P (t) && TREE_CODE (t) != BOOLEAN_TYPE);
}
-/* Returns true if T is a constraint. Note that error_mark_node
- is a valid constraint. */
+static bool
+check_constraint_atom (cp_expr expr)
+{
+ if (known_non_bool_p (TREE_TYPE (expr)))
+ {
+ error_at (expr.get_location (),
+ "constraint expression does not have type %<bool%>");
+ return false;
+ }
-bool
-constraint_p (tree t)
+ /* Check that we're using function concepts correctly. */
+ if (concept_check_p (expr))
+ {
+ tree id = unpack_concept_check (expr);
+ tree tmpl = TREE_OPERAND (id, 0);
+ if (OVL_P (tmpl) && TREE_CODE (expr) == TEMPLATE_ID_EXPR)
+ {
+ error_at (EXPR_LOC_OR_LOC (expr, input_location),
+ "function concept must be called");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool
+check_constraint_operands (location_t, cp_expr lhs, cp_expr rhs)
{
- return constraint_p (TREE_CODE (t));
+ return check_constraint_atom (lhs) && check_constraint_atom (rhs);
}
-/* Returns the conjunction of two constraints A and B. Note that
- conjoining a non-null constraint with NULL_TREE is an identity
- operation. That is, for non-null A,
+/* Validate the semantic properties of the constraint expression. */
- conjoin_constraints(a, NULL_TREE) == a
+static cp_expr
+finish_constraint_binary_op (location_t loc,
+ tree_code code,
+ cp_expr lhs,
+ cp_expr rhs)
+{
+ gcc_assert (processing_constraint_expression_p ());
+ if (lhs == error_mark_node || rhs == error_mark_node)
+ return error_mark_node;
+ if (!check_constraint_operands (loc, lhs, rhs))
+ return error_mark_node;
+ tree overload;
+ tree expr = build_x_binary_op (loc, code,
+ lhs, TREE_CODE (lhs),
+ rhs, TREE_CODE (rhs),
+ &overload, tf_none);
+ /* When either operand is dependent, the overload set may be non-empty. */
+ if (expr == error_mark_node)
+ return error_mark_node;
+ SET_EXPR_LOCATION (expr, loc);
+ return expr;
+}
- and
+cp_expr
+finish_constraint_or_expr (location_t loc, cp_expr lhs, cp_expr rhs)
+{
+ return finish_constraint_binary_op (loc, TRUTH_ORIF_EXPR, lhs, rhs);
+}
+
+cp_expr
+finish_constraint_and_expr (location_t loc, cp_expr lhs, cp_expr rhs)
+{
+ return finish_constraint_binary_op (loc, TRUTH_ANDIF_EXPR, lhs, rhs);
+}
- conjoin_constraints (NULL_TREE, a) == a
+cp_expr
+finish_constraint_primary_expr (cp_expr expr)
+{
+ if (expr == error_mark_node)
+ return error_mark_node;
+ if (!check_constraint_atom (expr))
+ return cp_expr (error_mark_node, expr.get_location ());
+ return expr;
+}
- If both A and B are NULL_TREE, the result is also NULL_TREE. */
+/* Combine two constraint-expressions with a logical-and. */
tree
-conjoin_constraints (tree a, tree b)
-{
- gcc_assert (a ? constraint_p (a) : true);
- gcc_assert (b ? constraint_p (b) : true);
- if (a)
- return b ? build_nt (CONJ_CONSTR, a, b) : a;
- else if (b)
- return b;
- else
- return NULL_TREE;
+combine_constraint_expressions (tree lhs, tree rhs)
+{
+ processing_constraint_expression_sentinel pce;
+ if (!lhs)
+ return rhs;
+ if (!rhs)
+ return lhs;
+ return finish_constraint_and_expr (input_location, lhs, rhs);
}
-/* Transform the vector of expressions in the T into a conjunction
- of requirements. T must be a TREE_VEC. */
+/* Extract the template-id from a concept check. For standard and variable
+ checks, this is simply T. For function concept checks, this is the
+ called function. */
tree
-conjoin_constraints (tree t)
+unpack_concept_check (tree t)
{
- gcc_assert (TREE_CODE (t) == TREE_VEC);
- tree r = NULL_TREE;
- for (int i = 0; i < TREE_VEC_LENGTH (t); ++i)
- r = conjoin_constraints (r, TREE_VEC_ELT (t, i));
- return r;
+ gcc_assert (concept_check_p (t));
+
+ if (TREE_CODE (t) == CALL_EXPR)
+ t = CALL_EXPR_FN (t);
+
+ gcc_assert (TREE_CODE (t) == TEMPLATE_ID_EXPR);
+ return t;
}
-/* Returns true if T is a call expression to a function
- concept. */
+/* Extract the TEMPLATE_DECL from a concept check. */
-bool
-function_concept_check_p (tree t)
+tree
+get_concept_check_template (tree t)
{
- gcc_assert (TREE_CODE (t) == CALL_EXPR);
- tree fn = CALL_EXPR_FN (t);
- if (fn != NULL_TREE
- && TREE_CODE (fn) == TEMPLATE_ID_EXPR)
- {
- tree f1 = OVL_FIRST (TREE_OPERAND (fn, 0));
- if (TREE_CODE (f1) == TEMPLATE_DECL
- && DECL_DECLARED_CONCEPT_P (DECL_TEMPLATE_RESULT (f1)))
- return true;
- }
- return false;
+ tree id = unpack_concept_check (t);
+ tree tmpl = TREE_OPERAND (id, 0);
+ if (OVL_P (tmpl))
+ tmpl = OVL_FIRST (tmpl);
+ return tmpl;
}
-/* Returns true if any of the arguments in the template
- argument list is a wildcard or wildcard pack. */
+/* Returns true if any of the arguments in the template argument list is
+ a wildcard or wildcard pack. */
bool
contains_wildcard_p (tree args)
@@ -142,38 +242,6 @@ contains_wildcard_p (tree args)
return false;
}
-/* Build a new call expression, but don't actually generate a
- new function call. We just want the tree, not the semantics. */
-
-inline tree
-build_call_check (tree id)
-{
- ++processing_template_decl;
- vec<tree, va_gc> *fargs = make_tree_vector();
- tree call = finish_call_expr (id, &fargs, false, false, tf_none);
- release_tree_vector (fargs);
- --processing_template_decl;
- return call;
-}
-
-/* Build an expression that will check a variable concept. If any
- argument contains a wildcard, don't try to finish the variable
- template because we can't substitute into a non-existent
- declaration. */
-
-tree
-build_variable_check (tree id)
-{
- gcc_assert (TREE_CODE (id) == TEMPLATE_ID_EXPR);
- if (contains_wildcard_p (TREE_OPERAND (id, 1)))
- return id;
-
- ++processing_template_decl;
- tree var = finish_template_variable (id);
- --processing_template_decl;
- return var;
-}
-
/*---------------------------------------------------------------------------
Resolution of qualified concept names
---------------------------------------------------------------------------*/
@@ -200,13 +268,12 @@ build_variable_check (tree id)
the complete set of arguments substituted into the parameter list. */
static tree
-resolve_constraint_check (tree ovl, tree args)
+resolve_function_concept_overload (tree ovl, tree args)
{
int nerrs = 0;
tree cands = NULL_TREE;
for (lkp_iterator iter (ovl); iter; ++iter)
{
- // Get the next template overload.
tree tmpl = *iter;
if (TREE_CODE (tmpl) != TEMPLATE_DECL)
continue;
@@ -252,7 +319,7 @@ resolve_constraint_check (tree ovl, tree args)
does not denote a constraint check, return NULL. */
tree
-resolve_constraint_check (tree call)
+resolve_function_concept_check (tree call)
{
gcc_assert (TREE_CODE (call) == CALL_EXPR);
@@ -279,37 +346,40 @@ resolve_constraint_check (tree call)
}
tree args = TREE_OPERAND (target, 1);
- return resolve_constraint_check (ovl, args);
+ return resolve_function_concept_overload (ovl, args);
}
-/* Returns a pair containing the checked variable concept
- and its associated prototype parameter. The result
- is a TREE_LIST whose TREE_VALUE is the variable concept
- and whose TREE_PURPOSE is the prototype parameter. */
+/* Returns a pair containing the checked concept and its associated
+ prototype parameter. The result is a TREE_LIST whose TREE_VALUE
+ is the concept (non-template) and whose TREE_PURPOSE contains
+ the converted template arguments, including the deduced prototype
+ parameter (in position 0). */
tree
-resolve_variable_concept_check (tree id)
+resolve_concept_check (tree check)
{
+ gcc_assert (concept_check_p (check));
+ tree id = unpack_concept_check (check);
tree tmpl = TREE_OPERAND (id, 0);
- tree args = TREE_OPERAND (id, 1);
- if (!variable_concept_p (tmpl))
- return NULL_TREE;
+ /* If this is an overloaded function concept, perform overload
+ resolution (this only happens when deducing prototype parameters
+ and template introductions). */
+ if (TREE_CODE (tmpl) == OVERLOAD)
+ {
+ if (OVL_CHAIN (tmpl))
+ return resolve_function_concept_check (check);
+ tmpl = OVL_FIRST (tmpl);
+ }
- /* Make sure that we have the right parameters before
- assuming that it works. Note that failing to deduce
- will result in diagnostics. */
+ tree args = TREE_OPERAND (id, 1);
tree parms = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (tmpl));
++processing_template_decl;
tree result = coerce_template_parms (parms, args, tmpl);
--processing_template_decl;
- if (result != error_mark_node)
- {
- tree decl = DECL_TEMPLATE_RESULT (tmpl);
- return build_tree_list (result, decl);
- }
- else
+ if (result == error_mark_node)
return error_mark_node;
+ return build_tree_list (result, DECL_TEMPLATE_RESULT (tmpl));
}
/* Given a call expression or template-id expression to a concept EXPR
@@ -321,14 +391,7 @@ resolve_variable_concept_check (tree id)
bool
deduce_constrained_parameter (tree expr, tree& check, tree& proto)
{
- tree info = NULL_TREE;
- if (TREE_CODE (expr) == TEMPLATE_ID_EXPR)
- info = resolve_variable_concept_check (expr);
- else if (TREE_CODE (expr) == CALL_EXPR)
- info = resolve_constraint_check (expr);
- else
- gcc_unreachable ();
-
+ tree info = resolve_concept_check (expr);
if (info && info != error_mark_node)
{
check = TREE_VALUE (info);
@@ -338,6 +401,7 @@ deduce_constrained_parameter (tree expr, tree& check, tree& proto)
proto = TREE_TYPE (arg);
return true;
}
+
check = proto = NULL_TREE;
return false;
}
@@ -346,127 +410,39 @@ deduce_constrained_parameter (tree expr, tree& check, tree& proto)
deduce the concept being checked and return the template arguments.
Returns NULL_TREE if deduction fails. */
static tree
-deduce_concept_introduction (tree expr)
+deduce_concept_introduction (tree check)
{
- tree info = NULL_TREE;
- if (TREE_CODE (expr) == TEMPLATE_ID_EXPR)
- info = resolve_variable_concept_check (expr);
- else if (TREE_CODE (expr) == CALL_EXPR)
- info = resolve_constraint_check (expr);
- else
- gcc_unreachable ();
-
+ tree info = resolve_concept_check (check);
if (info && info != error_mark_node)
return TREE_PURPOSE (info);
return NULL_TREE;
}
-namespace {
-
-/*---------------------------------------------------------------------------
- Constraint implication learning
----------------------------------------------------------------------------*/
-
-/* The implication context determines how we memoize concept checks.
- Given two checks C1 and C2, the direction of implication depends
- on whether we are learning implications of a conjunction or disjunction.
- For example:
-
- template<typename T> concept bool C = ...;
- template<typenaem T> concept bool D = C<T> && true;
-
- From this, we can learn that D<T> implies C<T>. We cannot learn,
- without further testing, that C<T> does not imply D<T>. If, for
- example, C<T> were defined as true, then these constraints would
- be logically equivalent.
-
- In rare cases, we may start with a logical equivalence. For example:
-
- template<typename T> concept bool C = ...;
- template<typename T> concept bool D = C<T>;
-
- Here, we learn that C<T> implies D<T> and vice versa. */
-
-enum implication_context
-{
- conjunction_cxt, /* C1 implies C2. */
- disjunction_cxt, /* C2 implies C1. */
- equivalence_cxt /* C1 implies C2, C2 implies C1. */
-};
-
-void learn_implications(tree, tree, implication_context);
+/* Build a constrained placeholder type where SPEC is a type-constraint.
+ SPEC can be anything were concept_definition_p is true.
-void
-learn_implication (tree parent, tree child, implication_context cxt)
-{
- switch (cxt)
- {
- case conjunction_cxt:
- save_subsumption_result (parent, child, true);
- break;
- case disjunction_cxt:
- save_subsumption_result (child, parent, true);
- break;
- case equivalence_cxt:
- save_subsumption_result (parent, child, true);
- save_subsumption_result (child, parent, true);
- break;
- }
-}
+ If DECLTYPE_P is true, then the placeholder is decltype(auto).
-void
-learn_logical_operation (tree parent, tree constr, implication_context cxt)
-{
- learn_implications (parent, TREE_OPERAND (constr, 0), cxt);
- learn_implications (parent, TREE_OPERAND (constr, 1), cxt);
-}
+ Returns a pair whose FIRST is the concept being checked and whose
+ SECOND is the prototype parameter. */
-void
-learn_implications (tree parent, tree constr, implication_context cxt)
+tree_pair
+finish_type_constraints (tree spec, tree args, tsubst_flags_t complain)
{
- switch (TREE_CODE (constr))
- {
- case CHECK_CONSTR:
- return learn_implication (parent, constr, cxt);
-
- case CONJ_CONSTR:
- if (cxt == disjunction_cxt)
- return;
- return learn_logical_operation (parent, constr, cxt);
-
- case DISJ_CONSTR:
- if (cxt == conjunction_cxt)
- return;
- return learn_logical_operation (parent, constr, cxt);
+ gcc_assert (concept_definition_p (spec));
- default:
- break;
- }
-}
-
-/* Quickly scan the top-level constraints of CONSTR to learn and
- cache logical relations between concepts. The search does not
- include conjunctions of disjunctions or vice versa. */
-
-void
-learn_implications (tree tmpl, tree args, tree constr)
-{
- /* Don't memoize relations between non-dependent arguemnts. It's not
- helpful. */
- if (!uses_template_parms (args))
- return;
+ /* Build an initial concept check. */
+ tree check = build_type_constraint (spec, args, complain);
+ if (check == error_mark_node)
+ return std::make_pair (error_mark_node, NULL_TREE);
- /* Build a check constraint for the purpose of caching. */
- tree parent = build_nt (CHECK_CONSTR, tmpl, args);
+ /* Extract the concept and prototype parameter from the check. */
+ tree con;
+ tree proto;
+ if (!deduce_constrained_parameter (check, con, proto))
+ return std::make_pair (error_mark_node, NULL_TREE);
- /* Start learning based on the kind of the top-level contraint. */
- if (TREE_CODE (constr) == CONJ_CONSTR)
- return learn_logical_operation (parent, constr, conjunction_cxt);
- else if (TREE_CODE (constr) == DISJ_CONSTR)
- return learn_logical_operation (parent, constr, disjunction_cxt);
- else if (TREE_CODE (constr) == CHECK_CONSTR)
- /* This is the rare concept alias case. */
- return learn_implication (parent, constr, equivalence_cxt);
+ return std::make_pair (con, proto);
}
/*---------------------------------------------------------------------------
@@ -475,7 +451,7 @@ learn_implications (tree tmpl, tree args, tree constr)
/* Returns the expression of a function concept. */
-tree
+static tree
get_returned_expression (tree fn)
{
/* Extract the body of the function minus the return expression. */
@@ -492,323 +468,230 @@ get_returned_expression (tree fn)
/* Returns the initializer of a variable concept. */
-tree
+static tree
get_variable_initializer (tree var)
{
tree init = DECL_INITIAL (var);
if (!init)
return error_mark_node;
+ if (BRACE_ENCLOSED_INITIALIZER_P (init)
+ && CONSTRUCTOR_NELTS (init) == 1)
+ init = CONSTRUCTOR_ELT (init, 0)->value;
return init;
}
/* Returns the definition of a variable or function concept. */
-tree
+static tree
get_concept_definition (tree decl)
{
- if (VAR_P (decl))
- return get_variable_initializer (decl);
- else if (TREE_CODE (decl) == FUNCTION_DECL)
- return get_returned_expression (decl);
- gcc_unreachable ();
-}
-
-int expansion_level = 0;
-
-class expanding_concept_sentinel
-{
-public:
- expanding_concept_sentinel ()
- {
- ++expansion_level;
- }
-
- ~expanding_concept_sentinel()
- {
- --expansion_level;
- }
-};
-
-
-} /* namespace */
-
-/* Returns true when a concept is being expanded. */
-
-bool
-expanding_concept()
-{
- return expansion_level > 0;
-}
-
-/* Expand a concept declaration (not a template) and its arguments to
- a constraint defined by the concept's initializer or definition. */
-
-tree
-expand_concept (tree decl, tree args)
-{
- expanding_concept_sentinel sentinel;
+ if (TREE_CODE (decl) == OVERLOAD)
+ decl = OVL_FIRST (decl);
if (TREE_CODE (decl) == TEMPLATE_DECL)
decl = DECL_TEMPLATE_RESULT (decl);
- tree tmpl = DECL_TI_TEMPLATE (decl);
-
- /* Check for a previous specialization. */
- if (tree spec = get_concept_expansion (tmpl, args))
- return spec;
- /* Substitute the arguments to form a new definition expression. */
- tree def = get_concept_definition (decl);
-
- ++processing_template_decl;
- tree result = tsubst_expr (def, args, tf_none, NULL_TREE, true);
- --processing_template_decl;
- if (result == error_mark_node)
- return error_mark_node;
-
- /* And lastly, normalize it, check for implications, and save
- the specialization for later. */
- tree norm = normalize_expression (result);
- learn_implications (tmpl, args, norm);
- return save_concept_expansion (tmpl, args, norm);
+ if (TREE_CODE (decl) == CONCEPT_DECL)
+ return DECL_INITIAL (decl);
+ if (VAR_P (decl))
+ return get_variable_initializer (decl);
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ return get_returned_expression (decl);
+ gcc_unreachable ();
}
-
/*---------------------------------------------------------------------------
- Stepwise normalization of expressions
+ Normalization of expressions
This set of functions will transform an expression into a constraint
-in a sequence of steps. Normalization does not not look into concept
-definitions.
+in a sequence of steps.
---------------------------------------------------------------------------*/
-/* Transform a logical-or or logical-and expression into either
- a conjunction or disjunction. */
-
-tree
-normalize_logical_operation (tree t, tree_code c)
-{
- tree t0 = normalize_expression (TREE_OPERAND (t, 0));
- tree t1 = normalize_expression (TREE_OPERAND (t, 1));
- return build_nt (c, t0, t1);
-}
-
-/* A simple requirement T introduces an expression constraint
- for its expression. */
-
-inline tree
-normalize_simple_requirement (tree t)
-{
- return build_nt (EXPR_CONSTR, TREE_OPERAND (t, 0));
-}
-
-/* A type requirement T introduce a type constraint for its type. */
-
-inline tree
-normalize_type_requirement (tree t)
-{
- return build_nt (TYPE_CONSTR, TREE_OPERAND (t, 0));
-}
-
-/* A compound requirement T introduces a conjunction of constraints
- depending on its form. The conjunction always includes an
- expression constraint for the expression of the requirement.
- If a trailing return type was specified, the conjunction includes
- either an implicit conversion constraint or an argument deduction
- constraint. If the noexcept specifier is present, the conjunction
- includes an exception constraint. */
-
-tree
-normalize_compound_requirement (tree t)
+void
+debug_parameter_mapping (tree map)
{
- tree expr = TREE_OPERAND (t, 0);
- tree constr = build_nt (EXPR_CONSTR, TREE_OPERAND (t, 0));
-
- /* If a type is given, append an implicit conversion or
- argument deduction constraint. */
- if (tree type = TREE_OPERAND (t, 1))
+ for (tree p = map; p; p = TREE_CHAIN (p))
{
- tree type_constr;
- /* TODO: We should be extracting a list of auto nodes
- from type_uses_auto, not a single node */
- if (tree placeholder = type_uses_auto (type))
- type_constr = build_nt (DEDUCT_CONSTR, expr, type, placeholder);
+ tree parm = TREE_VALUE (p);
+ tree arg = TREE_PURPOSE (p);
+ if (TYPE_P (parm))
+ verbatim ("MAP %qD TO %qT", TEMPLATE_TYPE_DECL (parm), arg);
else
- type_constr = build_nt (ICONV_CONSTR, expr, type);
- constr = conjoin_constraints (constr, type_constr);
+ verbatim ("MAP %qD TO %qE", TEMPLATE_PARM_DECL (parm), arg);
+ // debug_tree (parm);
+ // debug_tree (arg);
}
+}
- /* If noexcept is present, append an exception constraint. */
- if (COMPOUND_REQ_NOEXCEPT_P (t))
+void
+debug_argument_list (tree args)
+{
+ for (int i = 0; i < TREE_VEC_LENGTH (args); ++i)
{
- tree except = build_nt (EXCEPT_CONSTR, expr);
- constr = conjoin_constraints (constr, except);
+ tree arg = TREE_VEC_ELT (args, i);
+ if (TYPE_P (arg))
+ verbatim ("ARG %qT", arg);
+ else
+ verbatim ("ARG %qE", arg);
}
-
- return constr;
}
-/* A nested requirement T introduces a conjunction of constraints
- corresponding to its constraint-expression.
+/* Associate each parameter in PARMS with its corresponding template
+ argument in ARGS. */
- If the result of transforming T is error_mark_node, the resulting
- constraint is a predicate constraint whose operand is also
- error_mark_node. This preserves the constraint structure, but
- will guarantee that the constraint is never satisfied. */
-
-inline tree
-normalize_nested_requirement (tree t)
+static tree
+map_arguments (tree parms, tree args)
{
- return normalize_expression (TREE_OPERAND (t, 0));
+ for (tree p = parms; p; p = TREE_CHAIN (p))
+ {
+ int level;
+ int index;
+ template_parm_level_and_index (TREE_VALUE (p), &level, &index);
+ TREE_PURPOSE (p) = TMPL_ARG (args, level, index);
+ }
+ return parms;
}
-/* Transform a requirement T into one or more constraints. */
+/* Build the parameter mapping for EXPR using ARGS. */
-tree
-normalize_requirement (tree t)
+static tree
+build_parameter_mapping (tree expr, tree args, tree decl)
{
- switch (TREE_CODE (t))
+ int depth = 0;
+ if (decl)
{
- case SIMPLE_REQ:
- return normalize_simple_requirement (t);
-
- case TYPE_REQ:
- return normalize_type_requirement (t);
-
- case COMPOUND_REQ:
- return normalize_compound_requirement (t);
-
- case NESTED_REQ:
- return normalize_nested_requirement (t);
-
- default:
- gcc_unreachable ();
+ gcc_assert (TREE_CODE (decl) == TEMPLATE_DECL);
+ tree parms = DECL_TEMPLATE_PARMS (decl);
+ depth = TREE_INT_CST_LOW (TREE_PURPOSE (parms));
}
- return error_mark_node;
+ tree parms = find_template_parameters (expr, depth);
+ tree map = map_arguments (parms, args);
+ return map;
}
-/* Transform a sequence of requirements into a conjunction of
- constraints. */
+/* True if the parameter mappings of two atomic constraints are equivalent. */
-tree
-normalize_requirements (tree t)
+static bool
+parameter_mapping_equivalent_p (tree t1, tree t2)
{
- tree result = NULL_TREE;
- for (; t; t = TREE_CHAIN (t))
+ tree map1 = ATOMIC_CONSTR_MAP (t1);
+ tree map2 = ATOMIC_CONSTR_MAP (t2);
+ while (map1 && map2)
{
- tree constr = normalize_requirement (TREE_VALUE (t));
- result = conjoin_constraints (result, constr);
+ tree arg1 = TREE_PURPOSE (map1);
+ tree arg2 = TREE_PURPOSE (map2);
+ if (!template_args_equal (arg1, arg2))
+ return false;
+ map1 = TREE_CHAIN (map1);
+ map2 = TREE_CHAIN (map2);
}
- return result;
+ return true;
}
-/* The normal form of a requires-expression is a parameterized
- constraint having the same parameters and a conjunction of
- constraints representing the normal form of requirements. */
+/* Provides additional context for normalization. */
-tree
-normalize_requires_expression (tree t)
+struct norm_info : subst_info
{
- tree operand = normalize_requirements (TREE_OPERAND (t, 1));
- if (tree parms = TREE_OPERAND (t, 0))
- return build_nt (PARM_CONSTR, parms, operand);
- else
- return operand;
-}
+ norm_info(tsubst_flags_t complain)
+ : subst_info (tf_warning_or_error | complain, NULL_TREE),
+ context()
+ {}
-/* For a template-id referring to a variable concept, returns
- a check constraint. Otherwise, returns a predicate constraint. */
-
-tree
-normalize_template_id_expression (tree t)
-{
- if (tree info = resolve_variable_concept_check (t))
- {
- if (info == error_mark_node)
- {
- /* We get this when the template arguments don't match
- the variable concept. */
- error ("invalid reference to concept %qE", t);
- return error_mark_node;
- }
+ /* Construct a top-level context for DECL. */
- tree decl = TREE_VALUE (info);
- tree args = TREE_PURPOSE (info);
- return build_nt (CHECK_CONSTR, decl, args);
- }
+ norm_info (tree in_decl, tsubst_flags_t complain)
+ : subst_info (tf_warning_or_error | complain, in_decl),
+ context (make_context (in_decl))
+ {}
- /* Check that we didn't refer to a function concept like a variable. */
- tree fn = OVL_FIRST (TREE_OPERAND (t, 0));
- if (TREE_CODE (fn) == TEMPLATE_DECL
- && DECL_DECLARED_CONCEPT_P (DECL_TEMPLATE_RESULT (fn)))
- {
- error_at (location_of (t),
- "invalid reference to function concept %qD", fn);
- return error_mark_node;
- }
+ bool generate_diagnostics() const
+ {
+ return complain & tf_norm;
+ }
- return build_nt (PRED_CONSTR, t);
-}
+ tree make_context(tree in_decl)
+ {
+ if (generate_diagnostics ())
+ return build_tree_list (NULL_TREE, in_decl);
+ return NULL_TREE;
+ }
-/* For a call expression to a function concept, returns a check
- constraint. Otherwise, returns a predicate constraint. */
+ void update_context(tree expr, tree args)
+ {
+ if (generate_diagnostics ())
+ {
+ tree map = build_parameter_mapping (expr, args, in_decl);
+ context = tree_cons (map, expr, context);
+ }
+ in_decl = get_concept_check_template (expr);
+ }
-tree
-normalize_call_expression (tree t)
-{
- /* Try to resolve this function call as a concept. If not, then
- it can be returned as a predicate constraint. */
- tree check = resolve_constraint_check (t);
- if (!check)
- return build_nt (PRED_CONSTR, t);
- if (check == error_mark_node)
- {
- /* TODO: Improve diagnostics. We could report why the reference
- is invalid. */
- error ("invalid reference to concept %qE", t);
- return error_mark_node;
- }
+ /* Provides information about the source of a constraint. This is a
+ TREE_LIST whose VALUE is either a concept check or a constrained
+ declaration. The PURPOSE, for concept checks is a parameter mapping
+ for that check. */
- tree fn = TREE_VALUE (check);
- tree args = TREE_PURPOSE (check);
- return build_nt (CHECK_CONSTR, fn, args);
-}
+ tree context;
+};
-/* If T is a call to an overloaded && or || operator, diagnose that
- as a non-SFINAEable error. Returns true if an error is emitted.
+static tree normalize_expression (tree, tree, norm_info);
- TODO: It would be better to diagnose this at the point of definition,
- if possible. Perhaps we should immediately do a first-pass normalization
- of a concept definition to catch obvious non-dependent errors like
- this. */
+/* Transform a logical-or or logical-and expression into either
+ a conjunction or disjunction. */
-bool
-check_for_logical_overloads (tree t)
+static tree
+normalize_logical_operation (tree t, tree args, tree_code c, norm_info info)
{
- if (TREE_CODE (t) != CALL_EXPR)
- return false;
+ tree t0 = normalize_expression (TREE_OPERAND (t, 0), args, info);
+ tree t1 = normalize_expression (TREE_OPERAND (t, 1), args, info);
- tree fn = CALL_EXPR_FN (t);
+ /* Build a new info object for the constraint. */
+ tree ci = info.generate_diagnostics()
+ ? build_tree_list (t, info.context)
+ : NULL_TREE;
- /* For member calls, try extracting the function from the
- component ref. */
- if (TREE_CODE (fn) == COMPONENT_REF)
- {
- fn = TREE_OPERAND (fn, 1);
- if (TREE_CODE (fn) == BASELINK)
- fn = BASELINK_FUNCTIONS (fn);
- }
+ return build2 (c, ci, t0, t1);
+}
- if (TREE_CODE (fn) != FUNCTION_DECL)
- return false;
+static tree
+normalize_concept_check (tree check, tree args, norm_info info)
+{
+ tree id = unpack_concept_check (check);
+ tree tmpl = TREE_OPERAND (id, 0);
+ tree targs = TREE_OPERAND (id, 1);
- if (DECL_OVERLOADED_OPERATOR_P (fn))
+ /* A function concept is wrapped in an overload. */
+ if (TREE_CODE (tmpl) == OVERLOAD)
{
- location_t loc = cp_expr_loc_or_input_loc (t);
- error_at (loc, "constraint %qE, uses overloaded operator", t);
- return true;
+ /* TODO: Can we diagnose this error during parsing? */
+ if (TREE_CODE (check) == TEMPLATE_ID_EXPR)
+ error_at (EXPR_LOC_OR_LOC (check, input_location),
+ "function concept must be called");
+ tmpl = OVL_FIRST (tmpl);
}
- return false;
+ /* Substitute through the arguments of the concept check. */
+ targs = tsubst_template_args (targs, args, info.complain, info.in_decl);
+ if (targs == error_mark_node)
+ return error_mark_node;
+
+ /* Build the substitution for the concept definition. */
+ tree parms = TREE_VALUE (DECL_TEMPLATE_PARMS (tmpl));
+ /* Turn on template processing; coercing non-type template arguments
+ will automatically assume they're non-dependent. */
+ ++processing_template_decl;
+ tree subst = coerce_template_parms (parms, targs, tmpl);
+ --processing_template_decl;
+ if (subst == error_mark_node)
+ return error_mark_node;
+
+ /* The concept may have been ill-formed. */
+ tree def = get_concept_definition (DECL_TEMPLATE_RESULT (tmpl));
+ if (def == error_mark_node)
+ return error_mark_node;
+
+ info.update_context (check, args);
+ return normalize_expression (def, subst, info);
}
/* The normal form of an atom depends on the expression. The normal
@@ -817,269 +700,236 @@ check_for_logical_overloads (tree t)
concept is a check constraint for that concept. Otherwise, the
constraint is a predicate constraint. */
-tree
-normalize_atom (tree t)
+static tree
+normalize_atom (tree t, tree args, norm_info info)
{
- /* We can get constraints pushed down through pack expansions, so
- just return them. */
- if (constraint_p (t))
- return t;
+ /* Concept checks are not atomic. */
+ if (concept_check_p (t))
+ return normalize_concept_check (t, args, info);
- tree type = TREE_TYPE (t);
- if (!type || type_unknown_p (t) || TREE_CODE (type) == TEMPLATE_TYPE_PARM)
- ;
- else if (!dependent_type_p (type))
- {
- if (check_for_logical_overloads (t))
- return error_mark_node;
+ /* Build the parameter mapping for the atom. */
+ tree map = build_parameter_mapping (t, args, info.in_decl);
- type = cv_unqualified (type);
- if (!same_type_p (type, boolean_type_node))
- {
- error ("predicate constraint %q+E does not have type %<bool%>", t);
- return error_mark_node;
- }
- }
+ /* Build a new info object for the atom. */
+ tree ci = build_tree_list (t, info.context);
- if (TREE_CODE (t) == TEMPLATE_ID_EXPR)
- return normalize_template_id_expression (t);
- if (TREE_CODE (t) == CALL_EXPR)
- return normalize_call_expression (t);
- return build_nt (PRED_CONSTR, t);
+ return build1 (ATOMIC_CONSTR, ci, map);
}
-/* Push down the pack expansion EXP into the leaves of the constraint PAT. */
+/* Returns the normal form of an expression. */
-tree
-push_down_pack_expansion (tree exp, tree pat)
+static tree
+normalize_expression (tree t, tree args, norm_info info)
{
- switch (TREE_CODE (pat))
+ if (!t)
+ return NULL_TREE;
+
+ if (t == error_mark_node)
+ return error_mark_node;
+
+ switch (TREE_CODE (t))
{
- case CONJ_CONSTR:
- case DISJ_CONSTR:
- {
- pat = copy_node (pat);
- TREE_OPERAND (pat, 0)
- = push_down_pack_expansion (exp, TREE_OPERAND (pat, 0));
- TREE_OPERAND (pat, 1)
- = push_down_pack_expansion (exp, TREE_OPERAND (pat, 1));
- return pat;
- }
+ case TRUTH_ANDIF_EXPR:
+ return normalize_logical_operation (t, args, CONJ_CONSTR, info);
+ case TRUTH_ORIF_EXPR:
+ return normalize_logical_operation (t, args, DISJ_CONSTR, info);
default:
- {
- exp = copy_node (exp);
- SET_PACK_EXPANSION_PATTERN (exp, pat);
- return exp;
- }
+ return normalize_atom (t, args, info);
}
}
-/* Transform a pack expansion into a constraint. First we transform the
- pattern of the pack expansion, then we push the pack expansion down into the
- leaves of the constraint so that partial ordering will work. */
+/* Cache of the normalized form of constraints. Marked as deletable because it
+ can all be recalculated. */
+static GTY((deletable)) hash_map<tree,tree> *normalized_map;
-tree
-normalize_pack_expansion (tree t)
+static tree
+get_normalized_constraints (tree t, tree args, norm_info info)
{
- tree pat = normalize_expression (PACK_EXPANSION_PATTERN (t));
- return push_down_pack_expansion (t, pat);
+ auto_timevar time (TV_CONSTRAINT_NORM);
+ return normalize_expression (t, args, info);
}
-/* Transform an expression into a constraint. */
+/* Returns the normalized constraints from a constraint-info object
+ or NULL_TREE if the constraints are null. ARGS provide the initial
+ arguments for normalization and IN_DECL provides the declaration
+ to which the constraints belong. */
-tree
-normalize_any_expression (tree t)
+static tree
+get_normalized_constraints_from_info (tree ci, tree args, tree in_decl,
+ bool diag = false)
{
- switch (TREE_CODE (t))
- {
- case TRUTH_ANDIF_EXPR:
- return normalize_logical_operation (t, CONJ_CONSTR);
+ if (ci == NULL_TREE)
+ return NULL_TREE;
- case TRUTH_ORIF_EXPR:
- return normalize_logical_operation (t, DISJ_CONSTR);
+ /* Substitution errors during normalization are fatal. */
+ ++processing_template_decl;
+ norm_info info (in_decl, diag ? tf_norm : tf_none);
+ tree t = get_normalized_constraints (CI_ASSOCIATED_CONSTRAINTS (ci),
+ args, info);
+ --processing_template_decl;
- case REQUIRES_EXPR:
- return normalize_requires_expression (t);
+ return t;
+}
- case BIND_EXPR:
- return normalize_expression (BIND_EXPR_BODY (t));
+/* Returns the normalized constraints for the declaration D. */
- case EXPR_PACK_EXPANSION:
- return normalize_pack_expansion (t);
+static tree
+get_normalized_constraints_from_decl (tree d, bool diag = false)
+{
+ tree tmpl;
+ tree decl;
- default:
- /* All other constraints are atomic. */
- return normalize_atom (t);
- }
-}
+ /* For inherited constructors, consider the original declaration;
+ it has the correct template information attached. */
+ d = strip_inheriting_ctors (d);
-/* Transform a statement into an expression. */
-tree
-normalize_any_statement (tree t)
-{
- switch (TREE_CODE (t))
+ if (TREE_CODE (d) == TEMPLATE_DECL)
{
- case RETURN_EXPR:
- return normalize_expression (TREE_OPERAND (t, 0));
- default:
- gcc_unreachable ();
+ tmpl = d;
+ decl = DECL_TEMPLATE_RESULT (tmpl);
}
- return error_mark_node;
-}
-
-/* Reduction rules for the declaration T. */
-
-tree
-normalize_any_declaration (tree t)
-{
- switch (TREE_CODE (t))
+ else
{
- case VAR_DECL:
- return normalize_atom (t);
- default:
- gcc_unreachable ();
+ if (tree ti = DECL_TEMPLATE_INFO (d))
+ tmpl = TI_TEMPLATE (ti);
+ else
+ tmpl = NULL_TREE;
+ decl = d;
}
- return error_mark_node;
-}
-/* Returns the normal form of a constraint expression. */
+ /* Get the most general template for the declaration, and compute
+ arguments from that. This ensures that the arguments used for
+ normalization are always template parameters and not arguments
+ used for outer specializations. For example:
-tree
-normalize_expression (tree t)
-{
- if (!t)
- return NULL_TREE;
+ template<typename T>
+ struct S {
+ template<typename U> requires C<T, U> void f(U);
+ };
- if (t == error_mark_node)
- return error_mark_node;
+ S<int>::f(0);
- switch (TREE_CODE_CLASS (TREE_CODE (t)))
- {
- case tcc_unary:
- case tcc_binary:
- case tcc_expression:
- case tcc_vl_exp:
- return normalize_any_expression (t);
+ When we normalize the requirements for S<int>::f, we want the
+ arguments to be {T, U}, not {int, U}. One reason for this is that
+ accepting the latter causes the template parameter level of U
+ to be reduced in a way that makes it overly difficult substitute
+ concrete arguments (i.e., eventually {int, int} during satisfaction. */
+ if (tmpl)
+ {
+ if (DECL_LANG_SPECIFIC(tmpl) && !DECL_TEMPLATE_SPECIALIZATION (tmpl))
+ tmpl = most_general_template (tmpl);
+ }
- case tcc_statement:
- return normalize_any_statement (t);
+ /* If we're not diagnosing errors, use cached constraints, if any. */
+ if (!diag)
+ if (tree *p = hash_map_safe_get (normalized_map, tmpl))
+ return *p;
- case tcc_declaration:
- return normalize_any_declaration (t);
+ tree args = generic_targs_for (tmpl);
+ tree ci = get_constraints (decl);
+ tree norm = get_normalized_constraints_from_info (ci, args, tmpl, diag);
- case tcc_exceptional:
- case tcc_constant:
- case tcc_reference:
- case tcc_comparison:
- /* These are all atomic predicate constraints. */
- return normalize_atom (t);
+ if (!diag)
+ hash_map_safe_put<hm_ggc> (normalized_map, tmpl, norm);
- default:
- /* Unhandled node kind. */
- gcc_unreachable ();
- }
- return error_mark_node;
+ return norm;
}
+/* Returns the normal form of TMPL's definition. */
-/*---------------------------------------------------------------------------
- Constraint normalization
----------------------------------------------------------------------------*/
-
-tree normalize_constraint (tree);
+static tree
+normalize_concept_definition (tree tmpl)
+{
+ if (tree *p = hash_map_safe_get (normalized_map, tmpl))
+ return *p;
+ gcc_assert (concept_definition_p (tmpl));
+ if (OVL_P (tmpl))
+ tmpl = OVL_FIRST (tmpl);
+ gcc_assert (TREE_CODE (tmpl) == TEMPLATE_DECL);
+ tree args = generic_targs_for (tmpl);
+ tree def = get_concept_definition (DECL_TEMPLATE_RESULT (tmpl));
+ ++processing_template_decl;
+ norm_info info (tmpl, tf_none);
+ tree norm = get_normalized_constraints (def, args, info);
+ --processing_template_decl;
+ hash_map_safe_put<hm_ggc> (normalized_map, tmpl, norm);
+ return norm;
+}
-/* The normal form of the disjunction T0 /\ T1 is the conjunction
- of the normal form of T0 and the normal form of T1. */
+/* Returns the normal form of TMPL's requirements. */
-inline tree
-normalize_conjunction (tree t)
+static tree
+normalize_template_requirements (tree tmpl, bool diag = false)
{
- tree t0 = normalize_constraint (TREE_OPERAND (t, 0));
- tree t1 = normalize_constraint (TREE_OPERAND (t, 1));
- return build_nt (CONJ_CONSTR, t0, t1);
+ return get_normalized_constraints_from_decl (tmpl, diag);
}
-/* The normal form of the disjunction T0 \/ T1 is the disjunction
- of the normal form of T0 and the normal form of T1. */
+/* Returns the normal form of TMPL's requirements. */
-inline tree
-normalize_disjunction (tree t)
+static tree
+normalize_nontemplate_requirements (tree decl, bool diag = false)
{
- tree t0 = normalize_constraint (TREE_OPERAND (t, 0));
- tree t1 = normalize_constraint (TREE_OPERAND (t, 1));
- return build_nt (DISJ_CONSTR, t0, t1);
+ return get_normalized_constraints_from_decl (decl, diag);
}
-/* A predicate constraint is normalized in two stages. First all
- references specializations of concepts are replaced by their
- substituted definitions. Then, the resulting expression is
- transformed into a constraint by transforming && expressions
- into conjunctions and || into disjunctions. */
+/* Normalize an EXPR as a constraint. */
-tree
-normalize_predicate_constraint (tree t)
+static tree
+normalize_constraint_expression (tree expr, bool diag = false)
{
+ if (!expr || expr == error_mark_node)
+ return expr;
+
+ /* For concept checks, use the supplied template arguments as those used
+ for normalization. Otherwise, there are no template arguments. */
+ tree args;
+ if (concept_check_p (expr))
+ {
+ tree id = unpack_concept_check (expr);
+ args = TREE_OPERAND (id, 1);
+ }
+ else
+ args = NULL_TREE;
+
++processing_template_decl;
- tree expr = PRED_CONSTR_EXPR (t);
- tree constr = normalize_expression (expr);
+ norm_info info (diag ? tf_norm : tf_none);
+ tree norm = get_normalized_constraints (expr, args, info);
--processing_template_decl;
- return constr;
+ return norm;
}
-/* The normal form of a parameterized constraint is the normal
- form of its operand. */
+/* 17.4.1.2p2. Two constraints are identical if they are formed
+ from the same expression and the targets of the parameter mapping
+ are equivalent. */
-tree
-normalize_parameterized_constraint (tree t)
+bool
+atomic_constraints_identical_p (tree t1, tree t2)
{
- tree parms = PARM_CONSTR_PARMS (t);
- tree operand = normalize_constraint (PARM_CONSTR_OPERAND (t));
- return build_nt (PARM_CONSTR, parms, operand);
-}
+ if (ATOMIC_CONSTR_EXPR (t1) != ATOMIC_CONSTR_EXPR (t2))
+ return false;
-/* Normalize the constraint T by reducing it so that it is
- comprised of only conjunctions and disjunctions of atomic
- constraints. */
+ if (!parameter_mapping_equivalent_p (t1, t2))
+ return false;
-tree
-normalize_constraint (tree t)
-{
- if (!t)
- return NULL_TREE;
+ return true;
+}
- if (t == error_mark_node)
- return t;
+hashval_t
+hash_atomic_constraint (tree t)
+{
+ /* Hash the identity of the expression. */
+ hashval_t val = htab_hash_pointer (ATOMIC_CONSTR_EXPR (t));
- switch (TREE_CODE (t))
+ /* Hash the targets of the parameter map. */
+ tree p = ATOMIC_CONSTR_MAP (t);
+ while (p)
{
- case CONJ_CONSTR:
- return normalize_conjunction (t);
-
- case DISJ_CONSTR:
- return normalize_disjunction (t);
-
- case PRED_CONSTR:
- return normalize_predicate_constraint (t);
-
- case PARM_CONSTR:
- return normalize_parameterized_constraint (t);
-
- case EXPR_CONSTR:
- case TYPE_CONSTR:
- case ICONV_CONSTR:
- case DEDUCT_CONSTR:
- case EXCEPT_CONSTR:
- /* These constraints are defined to be atomic. */
- return t;
-
- default:
- /* CONSTR was not a constraint. */
- gcc_unreachable();
+ val = iterative_hash_template_arg (TREE_PURPOSE (p), val);
+ p = TREE_CHAIN (p);
}
- return error_mark_node;
-}
-
+ return val;
+}
// -------------------------------------------------------------------------- //
// Constraint Semantic Processing
@@ -1093,7 +943,7 @@ current_template_constraints (void)
{
if (!current_template_parms)
return NULL_TREE;
- tree tmpl_constr = TEMPLATE_PARM_CONSTRAINTS (current_template_parms);
+ tree tmpl_constr = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
return build_constraints (tmpl_constr, NULL_TREE);
}
@@ -1104,7 +954,7 @@ current_template_constraints (void)
tree
associate_classtype_constraints (tree type)
{
- if (!type || type == error_mark_node || TREE_CODE (type) != RECORD_TYPE)
+ if (!type || type == error_mark_node || !CLASS_TYPE_P (type))
return type;
/* An explicit class template specialization has no template parameters. */
@@ -1124,9 +974,11 @@ associate_classtype_constraints (tree type)
{
if (!equivalent_constraints (ci, orig_ci))
{
- // FIXME: Improve diagnostics.
- error ("%qT does not match any declaration", type);
- return error_mark_node;
+ error ("%qT does not match original declaration", type);
+ tree tmpl = CLASSTYPE_TI_TEMPLATE (type);
+ location_t loc = DECL_SOURCE_LOCATION (tmpl);
+ inform (loc, "original template declaration here");
+ /* Fall through, so that we define the type anyway. */
}
return type;
}
@@ -1135,17 +987,14 @@ associate_classtype_constraints (tree type)
return type;
}
-namespace {
+/* Create an empty constraint info block. */
-// Create an empty constraint info block.
-inline tree_constraint_info*
+static inline tree_constraint_info*
build_constraint_info ()
{
return (tree_constraint_info *)make_node (CONSTRAINT_INFO);
}
-} // namespace
-
/* Build a constraint-info object that contains the associated constraints
of a declaration. This also includes the declaration's template
requirements (TREQS) and any trailing requirements for a function
@@ -1155,27 +1004,46 @@ build_constraint_info ()
this returns NULL_TREE, indicating an unconstrained declaration. */
tree
-build_constraints (tree tmpl_reqs, tree decl_reqs)
+build_constraints (tree tr, tree dr)
{
- gcc_assert (tmpl_reqs ? constraint_p (tmpl_reqs) : true);
- gcc_assert (decl_reqs ? constraint_p (decl_reqs) : true);
-
- if (!tmpl_reqs && !decl_reqs)
+ if (!tr && !dr)
return NULL_TREE;
tree_constraint_info* ci = build_constraint_info ();
- ci->template_reqs = tmpl_reqs;
- ci->declarator_reqs = decl_reqs;
- ci->associated_constr = conjoin_constraints (tmpl_reqs, decl_reqs);
+ ci->template_reqs = tr;
+ ci->declarator_reqs = dr;
+ ci->associated_constr = combine_constraint_expressions (tr, dr);
return (tree)ci;
}
-namespace {
+/* Returns the template-head requires clause for the template
+ declaration T or NULL_TREE if none. */
+
+tree
+get_template_head_requirements (tree t)
+{
+ tree ci = get_constraints (t);
+ if (!ci)
+ return NULL_TREE;
+ return CI_TEMPLATE_REQS (ci);
+}
+
+/* Returns the trailing requires clause of the declarator of
+ a template declaration T or NULL_TREE if none. */
+
+tree
+get_trailing_function_requirements (tree t)
+{
+ tree ci = get_constraints (t);
+ if (!ci)
+ return NULL_TREE;
+ return CI_DECLARATOR_REQS (ci);
+}
/* Construct a sequence of template arguments by prepending
ARG to REST. Either ARG or REST may be null. */
-tree
+static tree
build_concept_check_arguments (tree arg, tree rest)
{
gcc_assert (rest ? TREE_CODE (rest) == TREE_VEC : true);
@@ -1199,27 +1067,155 @@ build_concept_check_arguments (tree arg, tree rest)
return args;
}
-} // namespace
+/* Builds an id-expression of the form `C<Args...>()` where C is a function
+ concept. */
+
+static tree
+build_function_check (tree tmpl, tree args, tsubst_flags_t /*complain*/)
+{
+ if (TREE_CODE (tmpl) == TEMPLATE_DECL)
+ {
+ /* If we just got a template, wrap it in an overload so it looks like any
+ other template-id. */
+ tmpl = ovl_make (tmpl);
+ TREE_TYPE (tmpl) = boolean_type_node;
+ }
+
+ /* Perform function concept resolution now so we always have a single
+ function of the overload set (even if we started with only one; the
+ resolution function converts template arguments). Note that we still
+ wrap this in an overload set so we don't upset other parts of the
+ compiler that expect template-ids referring to function concepts
+ to have an overload set. */
+ tree info = resolve_function_concept_overload (tmpl, args);
+ if (info == error_mark_node)
+ return error_mark_node;
+ if (!info)
+ {
+ error ("no matching concepts for %qE", tmpl);
+ return error_mark_node;
+ }
+ args = TREE_PURPOSE (info);
+ tmpl = DECL_TI_TEMPLATE (TREE_VALUE (info));
+
+ /* Rebuild the singleton overload set; mark the type bool. */
+ tmpl = ovl_make (tmpl, NULL_TREE);
+ TREE_TYPE (tmpl) = boolean_type_node;
+
+ /* Build the id-expression around the overload set. */
+ tree id = build2 (TEMPLATE_ID_EXPR, boolean_type_node, tmpl, args);
+
+ /* Finally, build the call expression around the overload. */
+ ++processing_template_decl;
+ vec<tree, va_gc> *fargs = make_tree_vector ();
+ tree call = build_min_nt_call_vec (id, fargs);
+ release_tree_vector (fargs);
+ --processing_template_decl;
-/* Construct an expression that checks the concept given by
- TARGET. The TARGET must be:
+ return call;
+}
- - an OVERLOAD referring to one or more function concepts
- - a BASELINK referring to an overload set of the above, or
- - a TEMPLTATE_DECL referring to a variable concept.
+/* Builds an id-expression of the form `C<Args...>` where C is a variable
+ concept. */
+
+static tree
+build_variable_check (tree tmpl, tree args, tsubst_flags_t complain)
+{
+ gcc_assert (variable_concept_p (tmpl));
+ gcc_assert (TREE_CODE (tmpl) == TEMPLATE_DECL);
+ tree parms = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (tmpl));
+ args = coerce_template_parms (parms, args, tmpl, complain);
+ if (args == error_mark_node)
+ return error_mark_node;
+ return build2 (TEMPLATE_ID_EXPR, boolean_type_node, tmpl, args);
+}
+
+/* Builds an id-expression of the form `C<Args...>` where C is a standard
+ concept. */
+
+static tree
+build_standard_check (tree tmpl, tree args, tsubst_flags_t complain)
+{
+ gcc_assert (standard_concept_p (tmpl));
+ gcc_assert (TREE_CODE (tmpl) == TEMPLATE_DECL);
+ tree parms = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (tmpl));
+ args = coerce_template_parms (parms, args, tmpl, complain);
+ if (args == error_mark_node)
+ return error_mark_node;
+ return build2 (TEMPLATE_ID_EXPR, boolean_type_node, tmpl, args);
+}
+
+/* Construct an expression that checks TARGET using ARGS. */
- ARG and REST are the explicit template arguments for the
- eventual concept check. */
tree
-build_concept_check (tree target, tree arg, tree rest)
+build_concept_check (tree target, tree args, tsubst_flags_t complain)
{
+ return build_concept_check (target, NULL_TREE, args, complain);
+}
+
+/* Construct an expression that checks the concept given by DECL. If
+ concept_definition_p (DECL) is false, this returns null. */
+
+tree
+build_concept_check (tree decl, tree arg, tree rest, tsubst_flags_t complain)
+{
+ if (arg == NULL_TREE && rest == NULL_TREE)
+ {
+ tree id = build_nt (TEMPLATE_ID_EXPR, decl, rest);
+ error ("invalid use concept %qE", id);
+ return error_mark_node;
+ }
+
tree args = build_concept_check_arguments (arg, rest);
- if (variable_template_p (target))
- return build_variable_check (lookup_template_variable (target, args));
- else
- return build_call_check (lookup_template_function (target, args));
+
+ if (standard_concept_p (decl))
+ return build_standard_check (decl, args, complain);
+ if (variable_concept_p (decl))
+ return build_variable_check (decl, args, complain);
+ if (function_concept_p (decl))
+ return build_function_check (decl, args, complain);
+
+ return error_mark_node;
+}
+
+/* Build a template-id that can participate in a concept check. */
+
+static tree
+build_concept_id (tree decl, tree args)
+{
+ tree check = build_concept_check (decl, args, tf_warning_or_error);
+ if (check == error_mark_node)
+ return error_mark_node;
+ return unpack_concept_check (check);
}
+/* Build a template-id that can participate in a concept check, preserving
+ the source location of the original template-id. */
+
+tree
+build_concept_id (tree expr)
+{
+ gcc_assert (TREE_CODE (expr) == TEMPLATE_ID_EXPR);
+ tree id = build_concept_id (TREE_OPERAND (expr, 0), TREE_OPERAND (expr, 1));
+ protected_set_expr_location (id, cp_expr_location (expr));
+ return id;
+}
+
+/* Build as template-id with a placeholder that can be used as a
+ type constraint.
+
+ Note that this will diagnose errors if the initial concept check
+ cannot be built. */
+
+tree
+build_type_constraint (tree decl, tree args, tsubst_flags_t complain)
+{
+ tree wildcard = build_nt (WILDCARD_DECL);
+ tree check = build_concept_check (decl, wildcard, args, complain);
+ if (check == error_mark_node)
+ return error_mark_node;
+ return unpack_concept_check (check);
+}
/* Returns a TYPE_DECL that contains sufficient information to
build a template parameter of the same kind as PROTO and
@@ -1240,17 +1236,13 @@ build_constrained_parameter (tree cnc, tree proto, tree args)
return decl;
}
-/* Create a constraint expression for the given DECL that
- evaluates the requirements specified by CONSTR, a TYPE_DECL
- that contains all the information necessary to build the
- requirements (see finish_concept_name for the layout of
- that TYPE_DECL).
-
- Note that the constraints are neither reduced nor decomposed.
- That is done only after the requires clause has been parsed
- (or not).
+/* Create a constraint expression for the given DECL that evaluates the
+ requirements specified by CONSTR, a TYPE_DECL that contains all the
+ information necessary to build the requirements (see finish_concept_name
+ for the layout of that TYPE_DECL).
- This will always return a CHECK_CONSTR. */
+ Note that the constraints are neither reduced nor decomposed. That is
+ done only after the requires clause has been parsed (or not). */
tree
finish_shorthand_constraint (tree decl, tree constr)
{
@@ -1265,41 +1257,46 @@ finish_shorthand_constraint (tree decl, tree constr)
tree con = CONSTRAINED_PARM_CONCEPT (constr);
tree args = CONSTRAINED_PARM_EXTRA_ARGS (constr);
- /* If the parameter declaration is variadic, but the concept
- is not then we need to apply the concept to every element
- in the pack. */
- bool is_proto_pack = template_parameter_pack_p (proto);
- bool is_decl_pack = template_parameter_pack_p (decl);
- bool apply_to_all_p = is_decl_pack && !is_proto_pack;
+ /* The TS lets use shorthand to constrain a pack of arguments, but the
+ standard does not.
+
+ For the TS, consider:
+
+ template<C... Ts> struct s;
+
+ If C is variadic (and because Ts is a pack), we associate the
+ constraint C<Ts...>. In all other cases, we associate
+ the constraint (C<Ts> && ...).
+
+ The standard behavior cannot be overridden by -fconcepts-ts. */
+ bool variadic_concept_p = template_parameter_pack_p (proto);
+ bool declared_pack_p = template_parameter_pack_p (decl);
+ bool apply_to_each_p = (cxx_dialect >= cxx2a) ? true : !variadic_concept_p;
/* Get the argument and overload used for the requirement
and adjust it if we're going to expand later. */
tree arg = template_parm_to_arg (build_tree_list (NULL_TREE, decl));
- if (apply_to_all_p)
+ if (apply_to_each_p && declared_pack_p)
arg = PACK_EXPANSION_PATTERN (TREE_VEC_ELT (ARGUMENT_PACK_ARGS (arg), 0));
- /* Build the concept check. If it the constraint needs to be
- applied to all elements of the parameter pack, then make
- the constraint an expansion. */
+ /* Build the concept constraint-expression. */
tree tmpl = DECL_TI_TEMPLATE (con);
- tree check = VAR_P (con) ? tmpl : ovl_make (tmpl);
- check = build_concept_check (check, arg, args);
-
- /* Make the check a pack expansion if needed.
+ tree check = tmpl;
+ if (TREE_CODE (con) == FUNCTION_DECL)
+ check = ovl_make (tmpl);
+ check = build_concept_check (check, arg, args, tf_warning_or_error);
- FIXME: We should be making a fold expression. */
- if (apply_to_all_p)
- {
- check = make_pack_expansion (check);
- TREE_TYPE (check) = boolean_type_node;
- }
+ /* Make the check a fold-expression if needed. */
+ if (apply_to_each_p && declared_pack_p)
+ check = finish_left_unary_fold_expr (check, TRUTH_ANDIF_EXPR);
- return normalize_expression (check);
+ return check;
}
/* Returns a conjunction of shorthand requirements for the template
parameter list PARMS. Note that the requirements are stored in
the TYPE of each tree node. */
+
tree
get_shorthand_constraints (tree parms)
{
@@ -1309,94 +1306,219 @@ get_shorthand_constraints (tree parms)
{
tree parm = TREE_VEC_ELT (parms, i);
tree constr = TEMPLATE_PARM_CONSTRAINTS (parm);
- result = conjoin_constraints (result, constr);
+ result = combine_constraint_expressions (result, constr);
}
return result;
}
-// Returns and chains a new parameter for PARAMETER_LIST which will conform
-// to the prototype given by SRC_PARM. The new parameter will have its
-// identifier and location set according to IDENT and PARM_LOC respectively.
+/* Get the deduced wildcard from a DEDUCED placeholder. If the deduced
+ wildcard is a pack, return the first argument of that pack. */
+
+static tree
+get_deduced_wildcard (tree wildcard)
+{
+ if (ARGUMENT_PACK_P (wildcard))
+ wildcard = TREE_VEC_ELT (ARGUMENT_PACK_ARGS (wildcard), 0);
+ gcc_assert (TREE_CODE (wildcard) == WILDCARD_DECL);
+ return wildcard;
+}
+
+/* Returns the prototype parameter for the nth deduced wildcard. */
+
static tree
-process_introduction_parm (tree parameter_list, tree src_parm)
+get_introduction_prototype (tree wildcards, int index)
{
- // If we have a pack, we should have a single pack argument which is the
- // placeholder we want to look at.
- bool is_parameter_pack = ARGUMENT_PACK_P (src_parm);
- if (is_parameter_pack)
- src_parm = TREE_VEC_ELT (ARGUMENT_PACK_ARGS (src_parm), 0);
+ return TREE_TYPE (get_deduced_wildcard (TREE_VEC_ELT (wildcards, index)));
+}
- // At this point we should have a wildcard, but we want to
- // grab the associated decl from it. Also grab the stored
- // identifier and location that should be chained to it in
- // a PARM_DECL.
- gcc_assert (TREE_CODE (src_parm) == WILDCARD_DECL);
+/* Introduce a type template parameter. */
- tree ident = DECL_NAME (src_parm);
- location_t parm_loc = DECL_SOURCE_LOCATION (src_parm);
+static tree
+introduce_type_template_parameter (tree wildcard, bool& non_type_p)
+{
+ non_type_p = false;
+ return finish_template_type_parm (class_type_node, DECL_NAME (wildcard));
+}
- // If we expect a pack and the deduced template is not a pack, or if the
- // template is using a pack and we didn't declare a pack, throw an error.
- if (is_parameter_pack != WILDCARD_PACK_P (src_parm))
- {
- error_at (parm_loc, "cannot match pack for introduced parameter");
- tree err_parm = build_tree_list (error_mark_node, error_mark_node);
- return chainon (parameter_list, err_parm);
- }
+/* Introduce a template template parameter. */
+
+static tree
+introduce_template_template_parameter (tree wildcard, bool& non_type_p)
+{
+ non_type_p = false;
+ begin_template_parm_list ();
+ current_template_parms = DECL_TEMPLATE_PARMS (TREE_TYPE (wildcard));
+ end_template_parm_list ();
+ return finish_template_template_parm (class_type_node, DECL_NAME (wildcard));
+}
+
+/* Introduce a template non-type parameter. */
+
+static tree
+introduce_nontype_template_parameter (tree wildcard, bool& non_type_p)
+{
+ non_type_p = true;
+ tree parm = copy_decl (TREE_TYPE (wildcard));
+ DECL_NAME (parm) = DECL_NAME (wildcard);
+ return parm;
+}
- src_parm = TREE_TYPE (src_parm);
+/* Introduce a single template parameter. */
+
+static tree
+build_introduced_template_parameter (tree wildcard, bool& non_type_p)
+{
+ tree proto = TREE_TYPE (wildcard);
tree parm;
- bool is_non_type;
- if (TREE_CODE (src_parm) == TYPE_DECL)
+ if (TREE_CODE (proto) == TYPE_DECL)
+ parm = introduce_type_template_parameter (wildcard, non_type_p);
+ else if (TREE_CODE (proto) == TEMPLATE_DECL)
+ parm = introduce_template_template_parameter (wildcard, non_type_p);
+ else
+ parm = introduce_nontype_template_parameter (wildcard, non_type_p);
+
+ /* Wrap in a TREE_LIST for process_template_parm. Note that introduced
+ parameters do not retain the defaults from the source parameter. */
+ return build_tree_list (NULL_TREE, parm);
+}
+
+/* Introduce a single template parameter. */
+
+static tree
+introduce_template_parameter (tree parms, tree wildcard)
+{
+ gcc_assert (!ARGUMENT_PACK_P (wildcard));
+ tree proto = TREE_TYPE (wildcard);
+ location_t loc = DECL_SOURCE_LOCATION (wildcard);
+
+ /* Diagnose the case where we have C{...Args}. */
+ if (WILDCARD_PACK_P (wildcard))
{
- is_non_type = false;
- parm = finish_template_type_parm (class_type_node, ident);
+ tree id = DECL_NAME (wildcard);
+ error_at (loc, "%qE cannot be introduced with an ellipsis %<...%>", id);
+ inform (DECL_SOURCE_LOCATION (proto), "prototype declared here");
}
- else if (TREE_CODE (src_parm) == TEMPLATE_DECL)
+
+ bool non_type_p;
+ tree parm = build_introduced_template_parameter (wildcard, non_type_p);
+ return process_template_parm (parms, loc, parm, non_type_p, false);
+}
+
+/* Introduce a template parameter pack. */
+
+static tree
+introduce_template_parameter_pack (tree parms, tree wildcard)
+{
+ bool non_type_p;
+ tree parm = build_introduced_template_parameter (wildcard, non_type_p);
+ location_t loc = DECL_SOURCE_LOCATION (wildcard);
+ return process_template_parm (parms, loc, parm, non_type_p, true);
+}
+
+/* Introduce the nth template parameter. */
+
+static tree
+introduce_template_parameter (tree parms, tree wildcards, int& index)
+{
+ tree deduced = TREE_VEC_ELT (wildcards, index++);
+ return introduce_template_parameter (parms, deduced);
+}
+
+/* Introduce either a template parameter pack or a list of template
+ parameters. */
+
+static tree
+introduce_template_parameters (tree parms, tree wildcards, int& index)
+{
+ /* If the prototype was a parameter, we better have deduced an
+ argument pack, and that argument must be the last deduced value
+ in the wildcard vector. */
+ tree deduced = TREE_VEC_ELT (wildcards, index++);
+ gcc_assert (ARGUMENT_PACK_P (deduced));
+ gcc_assert (index == TREE_VEC_LENGTH (wildcards));
+
+ /* Introduce each element in the pack. */
+ tree args = ARGUMENT_PACK_ARGS (deduced);
+ for (int i = 0; i < TREE_VEC_LENGTH (args); ++i)
{
- is_non_type = false;
- begin_template_parm_list ();
- current_template_parms = DECL_TEMPLATE_PARMS (src_parm);
- end_template_parm_list ();
- parm = finish_template_template_parm (class_type_node, ident);
+ tree arg = TREE_VEC_ELT (args, i);
+ if (WILDCARD_PACK_P (arg))
+ parms = introduce_template_parameter_pack (parms, arg);
+ else
+ parms = introduce_template_parameter (parms, arg);
}
+
+ return parms;
+}
+
+/* Builds the template parameter list PARMS by chaining introduced
+ parameters from the WILDCARD vector. INDEX is the position of
+ the current parameter. */
+
+static tree
+process_introduction_parms (tree parms, tree wildcards, int& index)
+{
+ tree proto = get_introduction_prototype (wildcards, index);
+ if (template_parameter_pack_p (proto))
+ return introduce_template_parameters (parms, wildcards, index);
else
- {
- is_non_type = true;
+ return introduce_template_parameter (parms, wildcards, index);
+}
- // Since we don't have a declarator, so we can copy the source
- // parameter and change the name and eventually the location.
- parm = copy_decl (src_parm);
- DECL_NAME (parm) = ident;
- }
+/* Ensure that all template parameters have been introduced for the concept
+ named in CHECK. If not, emit a diagnostic.
- // Wrap in a TREE_LIST for process_template_parm. Introductions do not
- // retain the defaults from the source template.
- parm = build_tree_list (NULL_TREE, parm);
+ Note that implicitly introducing a parameter with a default argument
+ creates a case where a parameter is declared, but unnamed, making
+ it unusable in the definition. */
+
+static bool
+check_introduction_list (tree intros, tree check)
+{
+ check = unpack_concept_check (check);
+ tree tmpl = TREE_OPERAND (check, 0);
+ if (OVL_P (tmpl))
+ tmpl = OVL_FIRST (tmpl);
+
+ tree parms = DECL_INNERMOST_TEMPLATE_PARMS (tmpl);
+ if (TREE_VEC_LENGTH (intros) < TREE_VEC_LENGTH (parms))
+ {
+ error_at (input_location, "all template parameters of %qD must "
+ "be introduced", tmpl);
+ return false;
+ }
- return process_template_parm (parameter_list, parm_loc, parm,
- is_non_type, is_parameter_pack);
+ return true;
}
-/* Associates a constraint check to the current template based
- on the introduction parameters. INTRO_LIST must be a TREE_VEC
- of WILDCARD_DECLs containing a chained PARM_DECL which
- contains the identifier as well as the source location.
- TMPL_DECL is the decl for the concept being used. If we
- take a concept, C, this will form a check in the form of
- C<INTRO_LIST> filling in any extra arguments needed by the
- defaults deduced.
+/* Associates a constraint check to the current template based on the
+ introduction parameters. INTRO_LIST must be a TREE_VEC of WILDCARD_DECLs
+ containing a chained PARM_DECL which contains the identifier as well as
+ the source location. TMPL_DECL is the decl for the concept being used.
+ If we take a concept, C, this will form a check in the form of
+ C<INTRO_LIST> filling in any extra arguments needed by the defaults
+ deduced.
+
+ Returns NULL_TREE if no concept could be matched and error_mark_node if
+ an error occurred when matching. */
- Returns NULL_TREE if no concept could be matched and
- error_mark_node if an error occurred when matching. */
tree
-finish_template_introduction (tree tmpl_decl, tree intro_list)
+finish_template_introduction (tree tmpl_decl,
+ tree intro_list,
+ location_t intro_loc)
{
- /* Deduce the concept check. */
- tree expr = build_concept_check (tmpl_decl, NULL_TREE, intro_list);
+ /* Build a concept check to deduce the actual parameters. */
+ tree expr = build_concept_check (tmpl_decl, intro_list, tf_none);
if (expr == error_mark_node)
- return NULL_TREE;
+ {
+ error_at (intro_loc, "cannot deduce template parameters from "
+ "introduction list");
+ return error_mark_node;
+ }
+
+ if (!check_introduction_list (intro_list, expr))
+ return error_mark_node;
tree parms = deduce_concept_introduction (expr);
if (!parms)
@@ -1406,9 +1528,15 @@ finish_template_introduction (tree tmpl_decl, tree intro_list)
tree parm_list = NULL_TREE;
begin_template_parm_list ();
int nargs = MIN (TREE_VEC_LENGTH (parms), TREE_VEC_LENGTH (intro_list));
- for (int n = 0; n < nargs; ++n)
- parm_list = process_introduction_parm (parm_list, TREE_VEC_ELT (parms, n));
+ for (int n = 0; n < nargs; )
+ parm_list = process_introduction_parms (parm_list, parms, n);
parm_list = end_template_parm_list (parm_list);
+
+ /* Update the number of arguments to reflect the number of deduced
+ template parameter introductions. */
+ nargs = TREE_VEC_LENGTH (parm_list);
+
+ /* Determine if any errors occurred during matching. */
for (int i = 0; i < TREE_VEC_LENGTH (parm_list); ++i)
if (TREE_VALUE (TREE_VEC_ELT (parm_list, i)) == error_mark_node)
{
@@ -1417,7 +1545,7 @@ finish_template_introduction (tree tmpl_decl, tree intro_list)
}
/* Build a concept check for our constraint. */
- tree check_args = make_tree_vec (TREE_VEC_LENGTH (parms));
+ tree check_args = make_tree_vec (nargs);
int n = 0;
for (; n < TREE_VEC_LENGTH (parm_list); ++n)
{
@@ -1431,22 +1559,33 @@ finish_template_introduction (tree tmpl_decl, tree intro_list)
for (; n < TREE_VEC_LENGTH (parms); ++n)
TREE_VEC_ELT (check_args, n) = TREE_VEC_ELT (parms, n);
- /* Associate the constraint. */
- tree check = build_concept_check (tmpl_decl, NULL_TREE, check_args);
- tree constr = normalize_expression (check);
- TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = constr;
+ /* Associate the constraint. */
+ tree check = build_concept_check (tmpl_decl,
+ check_args,
+ tf_warning_or_error);
+ TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = check;
return parm_list;
}
-/* Given the predicate constraint T from a constrained-type-specifier, extract
+/* Given the concept check T from a constrained-type-specifier, extract
its TMPL and ARGS. FIXME why do we need two different forms of
constrained-type-specifier? */
void
placeholder_extract_concept_and_args (tree t, tree &tmpl, tree &args)
{
+ if (concept_check_p (t))
+ {
+ t = unpack_concept_check (t);
+ tmpl = TREE_OPERAND (t, 0);
+ if (TREE_CODE (tmpl) == OVERLOAD)
+ tmpl = OVL_FIRST (tmpl);
+ args = TREE_OPERAND (t, 1);
+ return;
+ }
+
if (TREE_CODE (t) == TYPE_DECL)
{
/* A constrained parameter. Build a constraint check
@@ -1457,20 +1596,10 @@ placeholder_extract_concept_and_args (tree t, tree &tmpl, tree &args)
placeholder_extract_concept_and_args (check, tmpl, args);
return;
}
-
- if (TREE_CODE (t) == CHECK_CONSTR)
- {
- tree decl = CHECK_CONSTR_CONCEPT (t);
- tmpl = DECL_TI_TEMPLATE (decl);
- args = CHECK_CONSTR_ARGS (t);
- return;
- }
-
- gcc_unreachable ();
}
/* Returns true iff the placeholders C1 and C2 are equivalent. C1
- and C2 can be either CHECK_CONSTR or TEMPLATE_TYPE_PARM. */
+ and C2 can be either TEMPLATE_TYPE_PARM or template-ids. */
bool
equivalent_placeholder_constraints (tree c1, tree c2)
@@ -1515,7 +1644,7 @@ equivalent_placeholder_constraints (tree c1, tree c2)
return true;
}
-/* Return a hash value for the placeholder PRED_CONSTR C. */
+/* Return a hash value for the placeholder ATOMIC_CONSTR C. */
hashval_t
hash_placeholder_constraint (tree c)
@@ -1532,178 +1661,215 @@ hash_placeholder_constraint (tree c)
return val;
}
-/*---------------------------------------------------------------------------
- Constraint substitution
----------------------------------------------------------------------------*/
+/* Substitute through the simple requirement. */
-/* The following functions implement substitution rules for constraints.
- Substitution without checking constraints happens only in the
- instantiation of class templates. For example:
+static tree
+tsubst_valid_expression_requirement (tree t, tree args, subst_info info)
+{
+ return tsubst_expr (t, args, info.complain, info.in_decl, false);
+}
- template<C1 T> struct S {
- void f(T) requires C2<T>;
- void g(T) requires T::value;
- };
- S<int> s; // error instantiating S<int>::g(T)
+/* Substitute through the simple requirement. */
- When we instantiate S, we substitute into its member declarations,
- including their constraints. However, those constraints are not
- checked. Substituting int into C2<T> yields C2<int>, and substituting
- into T::value yields a substitution failure, making the program
- ill-formed.
+static tree
+tsubst_simple_requirement (tree t, tree args, subst_info info)
+{
+ tree t0 = TREE_OPERAND (t, 0);
+ tree expr = tsubst_valid_expression_requirement (t0, args, info);
+ if (expr == error_mark_node)
+ return error_mark_node;
+ return finish_simple_requirement (EXPR_LOCATION (t), expr);
+}
- Note that we only ever substitute into the associated constraints
- of a declaration. That is, substitution is defined only for predicate
- constraints and conjunctions. */
+/* Substitute through the type requirement. */
-/* Substitute into the predicate constraints. Returns error_mark_node
- if the substitution into the expression fails. */
-tree
-tsubst_predicate_constraint (tree t, tree args,
- tsubst_flags_t complain, tree in_decl)
+static tree
+tsubst_type_requirement (tree t, tree args, subst_info info)
{
- tree expr = PRED_CONSTR_EXPR (t);
- ++processing_template_decl;
- tree result = tsubst_expr (expr, args, complain, in_decl, false);
- --processing_template_decl;
- return build_nt (PRED_CONSTR, result);
+ tree t0 = TREE_OPERAND (t, 0);
+ tree type = tsubst (t0, args, info.complain, info.in_decl);
+ if (type == error_mark_node)
+ return error_mark_node;
+ return finish_type_requirement (EXPR_LOCATION (t), type);
}
-/* Substitute into a check constraint. */
+/* True if TYPE can be deduced from EXPR.
-tree
-tsubst_check_constraint (tree t, tree args,
- tsubst_flags_t complain, tree in_decl)
+ FIXME: C++20 compound requirement constraints should be normalized and then
+ satisfied rather than substituted. */
+
+static bool
+type_deducible_p (tree expr, tree type, tree placeholder, tree args,
+ subst_info info)
{
- tree decl = CHECK_CONSTR_CONCEPT (t);
- tree tmpl = DECL_TI_TEMPLATE (decl);
- tree targs = CHECK_CONSTR_ARGS (t);
+ /* Make sure deduction is performed against ( EXPR ), so that
+ references are preserved in the result. */
+ expr = force_paren_expr_uneval (expr);
- /* Substitute through by building an template-id expression
- and then substituting into that. */
- tree expr = build_nt (TEMPLATE_ID_EXPR, tmpl, targs);
- ++processing_template_decl;
- tree result = tsubst_expr (expr, args, complain, in_decl, false);
- --processing_template_decl;
+ /* Replace the constraints with the instantiated constraints. This
+ substitutes args into any template parameters in the trailing
+ result type. */
+ tree saved_constr = PLACEHOLDER_TYPE_CONSTRAINTS (placeholder);
+ PLACEHOLDER_TYPE_CONSTRAINTS (placeholder)
+ = tsubst_constraint (saved_constr,
+ args,
+ info.complain | tf_partial,
+ info.in_decl);
- if (result == error_mark_node)
- return error_mark_node;
+ /* Temporarily unlink the canonical type. */
+ tree saved_type = TYPE_CANONICAL (placeholder);
+ TYPE_CANONICAL (placeholder) = NULL_TREE;
- /* Extract the results and rebuild the check constraint. */
- decl = DECL_TEMPLATE_RESULT (TREE_OPERAND (result, 0));
- args = TREE_OPERAND (result, 1);
+ tree deduced_type
+ = do_auto_deduction (type,
+ expr,
+ placeholder,
+ info.complain,
+ adc_requirement);
- return build_nt (CHECK_CONSTR, decl, args);
+ PLACEHOLDER_TYPE_CONSTRAINTS (placeholder) = saved_constr;
+ TYPE_CANONICAL (placeholder) = saved_type;
+
+ if (deduced_type == error_mark_node)
+ return false;
+
+ return true;
}
-/* Substitute into the conjunction of constraints. Returns
- error_mark_node if substitution into either operand fails. */
+/* True if EXPR can not be converted to TYPE. */
-tree
-tsubst_logical_operator (tree t, tree args,
- tsubst_flags_t complain, tree in_decl)
+static bool
+expression_convertible_p (tree expr, tree type, subst_info info)
{
- tree t0 = TREE_OPERAND (t, 0);
- tree r0 = tsubst_constraint (t0, args, complain, in_decl);
- if (r0 == error_mark_node)
- return error_mark_node;
- tree t1 = TREE_OPERAND (t, 1);
- tree r1 = tsubst_constraint (t1, args, complain, in_decl);
- if (r1 == error_mark_node)
- return error_mark_node;
- return build_nt (TREE_CODE (t), r0, r1);
+ tree conv =
+ perform_direct_initialization_if_possible (type, expr, false,
+ info.complain);
+ if (conv == error_mark_node)
+ return false;
+ if (conv == NULL_TREE)
+ {
+ if (info.complain & tf_error)
+ {
+ location_t loc = EXPR_LOC_OR_LOC (expr, input_location);
+ error_at (loc, "cannot convert %qE to %qT", expr, type);
+ }
+ return false;
+ }
+ return true;
}
-namespace {
-/* Substitute ARGS into the expression constraint T. */
+/* Substitute through the compound requirement. */
-tree
-tsubst_expr_constr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
+static tree
+tsubst_compound_requirement (tree t, tree args, subst_info info)
{
- cp_unevaluated guard;
- tree expr = EXPR_CONSTR_EXPR (t);
- tree ret = tsubst_expr (expr, args, complain, in_decl, false);
- if (ret == error_mark_node)
+ tree t0 = TREE_OPERAND (t, 0);
+ tree t1 = TREE_OPERAND (t, 1);
+ tree expr = tsubst_valid_expression_requirement (t0, args, info);
+ if (expr == error_mark_node)
return error_mark_node;
- return build_nt (EXPR_CONSTR, ret);
-}
-/* Substitute ARGS into the type constraint T. */
+ /* Check the noexcept condition. */
+ bool noexcept_p = COMPOUND_REQ_NOEXCEPT_P (t);
+ if (noexcept_p && !expr_noexcept_p (expr, tf_none))
+ return error_mark_node;
-tree
-tsubst_type_constr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
-{
- tree type = TYPE_CONSTR_TYPE (t);
- tree ret = tsubst (type, args, complain, in_decl);
- if (ret == error_mark_node)
+ /* Substitute through the type expression, if any. */
+ tree type = tsubst (t1, args, info.complain, info.in_decl);
+ if (type == error_mark_node)
return error_mark_node;
- return build_nt (TYPE_CONSTR, ret);
-}
-/* Substitute ARGS into the implicit conversion constraint T. */
+ /* Check expression against the result type. */
+ if (type)
+ {
+ if (tree placeholder = type_uses_auto (type))
+ {
+ if (!type_deducible_p (expr, type, placeholder, args, info))
+ return error_mark_node;
+ }
+ else if (!expression_convertible_p (expr, type, info))
+ return error_mark_node;
+ }
-tree
-tsubst_implicit_conversion_constr (tree t, tree args, tsubst_flags_t complain,
- tree in_decl)
-{
- cp_unevaluated guard;
- tree expr = ICONV_CONSTR_EXPR (t);
- tree type = ICONV_CONSTR_TYPE (t);
- tree new_expr = tsubst_expr (expr, args, complain, in_decl, false);
- if (new_expr == error_mark_node)
- return error_mark_node;
- tree new_type = tsubst (type, args, complain, in_decl);
- if (new_type == error_mark_node)
- return error_mark_node;
- return build_nt (ICONV_CONSTR, new_expr, new_type);
+ return finish_compound_requirement (EXPR_LOCATION (t),
+ expr, type, noexcept_p);
}
-/* Substitute ARGS into the argument deduction constraint T. */
-
-tree
-tsubst_argument_deduction_constr (tree t, tree args, tsubst_flags_t complain,
- tree in_decl)
-{
- cp_unevaluated guard;
- tree expr = DEDUCT_CONSTR_EXPR (t);
- tree pattern = DEDUCT_CONSTR_PATTERN (t);
- tree autos = DEDUCT_CONSTR_PLACEHOLDER(t);
- tree new_expr = tsubst_expr (expr, args, complain, in_decl, false);
- if (new_expr == error_mark_node)
- return error_mark_node;
- /* It seems like substituting through the pattern will not affect the
- placeholders. We should (?) be able to reuse the existing list
- without any problems. If not, then we probably want to create a
- new list of placeholders and then instantiate the pattern using
- those. */
- tree new_pattern = tsubst (pattern, args, complain, in_decl);
- if (new_pattern == error_mark_node)
+static tree
+tsubst_nested_requirement (tree t, tree args, subst_info info)
+{
+ tree t0 = TREE_OPERAND (t, 0);
+ tree expr = tsubst_expr (t0, args, info.complain, info.in_decl, false);
+ if (expr == error_mark_node)
return error_mark_node;
- return build_nt (DEDUCT_CONSTR, new_expr, new_pattern, autos);
+
+ /* Ensure that concrete results are satisfied. */
+ if (!uses_template_parms (args))
+ {
+ /* FIXME satisfy_constraint_expression (t0, args, info) */
+
+ /* [17.4.1.2] ... lvalue-to-value conversion is performed as necessary,
+ and EXPR shall be a constant expression of type bool. */
+ tree result = force_rvalue (expr, tf_error);
+ if (result == error_mark_node)
+ return error_mark_node;
+
+ /* FIXME: The expression must have boolean type. */
+ if (cv_unqualified (TREE_TYPE (result)) != boolean_type_node)
+ return error_mark_node;
+
+ /* Compute the value of the expression. */
+ result = satisfaction_value (cxx_constant_value (result));
+ if (result == error_mark_node || result == boolean_false_node)
+ return error_mark_node;
+ }
+
+ return finish_nested_requirement (EXPR_LOCATION (t), expr);
}
-/* Substitute ARGS into the exception constraint T. */
+/* Substitute ARGS into the requirement T. */
-tree
-tsubst_exception_constr (tree t, tree args, tsubst_flags_t complain,
- tree in_decl)
+static tree
+tsubst_requirement (tree t, tree args, subst_info info)
{
- cp_unevaluated guard;
- tree expr = EXCEPT_CONSTR_EXPR (t);
- tree ret = tsubst_expr (expr, args, complain, in_decl, false);
- if (ret == error_mark_node)
- return error_mark_node;
- return build_nt (EXCEPT_CONSTR, ret);
+ iloc_sentinel loc_s (cp_expr_location (t));
+ switch (TREE_CODE (t))
+ {
+ case SIMPLE_REQ:
+ return tsubst_simple_requirement (t, args, info);
+ case TYPE_REQ:
+ return tsubst_type_requirement (t, args, info);
+ case COMPOUND_REQ:
+ return tsubst_compound_requirement (t, args, info);
+ case NESTED_REQ:
+ return tsubst_nested_requirement (t, args, info);
+ default:
+ break;
+ }
+ gcc_unreachable ();
}
-/* A subroutine of tsubst_constraint_variables. Register local
- specializations for each of parameter in PARMS and its
- corresponding substituted constraint variable in VARS.
- Returns VARS. */
+/* Substitute ARGS into the list of requirements T. Note that
+ substitution failures here result in ill-formed programs. */
-tree
+static tree
+tsubst_requirement_body (tree t, tree args, subst_info info)
+{
+ tree result = NULL_TREE;
+ while (t)
+ {
+ tree req = tsubst_requirement (TREE_VALUE (t), args, info);
+ if (req == error_mark_node)
+ return error_mark_node;
+ result = tree_cons (NULL_TREE, req, result);
+ t = TREE_CHAIN (t);
+ }
+ return nreverse (result);
+}
+
+static tree
declare_constraint_vars (tree parms, tree vars)
{
tree s = vars;
@@ -1723,6 +1889,24 @@ declare_constraint_vars (tree parms, tree vars)
return vars;
}
+/* Substitute through as if checking function parameter types. This
+ will diagnose common parameter type errors. Returns error_mark_node
+ if an error occurred. */
+
+static tree
+check_constaint_variables (tree t, tree args, subst_info info)
+{
+ tree types = NULL_TREE;
+ tree p = t;
+ while (p && !VOID_TYPE_P (p))
+ {
+ types = tree_cons (NULL_TREE, TREE_TYPE (p), types);
+ p = TREE_CHAIN (p);
+ }
+ types = chainon (nreverse (types), void_list_node);
+ return tsubst_function_parms (types, args, info.complain, info.in_decl);
+}
+
/* A subroutine of tsubst_parameterized_constraint. Substitute ARGS
into the parameter list T, producing a sequence of constraint
variables, declared in the current scope.
@@ -1731,171 +1915,81 @@ declare_constraint_vars (tree parms, tree vars)
prior to calling this function since this substitution will
declare the substituted parameters. */
-tree
-tsubst_constraint_variables (tree t, tree args,
- tsubst_flags_t complain, tree in_decl)
+static tree
+tsubst_constraint_variables (tree t, tree args, subst_info info)
{
+ /* Perform a trial substitution to check for type errors. */
+ tree parms = check_constaint_variables (t, args, info);
+ if (parms == error_mark_node)
+ return error_mark_node;
+
/* Clear cp_unevaluated_operand across tsubst so that we get a proper chain
of PARM_DECLs. */
int saved_unevaluated_operand = cp_unevaluated_operand;
cp_unevaluated_operand = 0;
- tree vars = tsubst (t, args, complain, in_decl);
+ tree vars = tsubst (t, args, info.complain, info.in_decl);
cp_unevaluated_operand = saved_unevaluated_operand;
if (vars == error_mark_node)
return error_mark_node;
return declare_constraint_vars (t, vars);
}
-/* Substitute ARGS into the parameterized constraint T. */
-
-tree
-tsubst_parameterized_constraint (tree t, tree args,
- tsubst_flags_t complain, tree in_decl)
-{
- local_specialization_stack stack;
- tree vars = tsubst_constraint_variables (PARM_CONSTR_PARMS (t),
- args, complain, in_decl);
- if (vars == error_mark_node)
- return error_mark_node;
- tree expr = tsubst_constraint (PARM_CONSTR_OPERAND (t), args,
- complain, in_decl);
- if (expr == error_mark_node)
- return error_mark_node;
- return build_nt (PARM_CONSTR, vars, expr);
-}
-
-/* Substitute ARGS into the simple requirement T. Note that
- substitution may result in an ill-formed expression without
- causing the program to be ill-formed. In such cases, the
- requirement wraps an error_mark_node. */
-
-inline tree
-tsubst_simple_requirement (tree t, tree args,
- tsubst_flags_t complain, tree in_decl)
-{
- ++processing_template_decl;
- tree expr = tsubst_expr (TREE_OPERAND (t, 0), args, complain, in_decl, false);
- --processing_template_decl;
- return finish_simple_requirement (expr);
-}
-
-/* Substitute ARGS into the type requirement T. Note that
- substitution may result in an ill-formed type without
- causing the program to be ill-formed. In such cases, the
- requirement wraps an error_mark_node. */
+/* Substitute ARGS into the requires-expression T. [8.4.7]p6. The
+ substitution of template arguments into a requires-expression
+ may result in the formation of invalid types or expressions
+ in its requirements ... In such cases, the expression evaluates
+ to false; it does not cause the program to be ill-formed.
-inline tree
-tsubst_type_requirement (tree t, tree args,
- tsubst_flags_t complain, tree in_decl)
-{
- ++processing_template_decl;
- tree type = tsubst (TREE_OPERAND (t, 0), args, complain, in_decl);
- --processing_template_decl;
- return finish_type_requirement (type);
-}
-
-/* Substitute args into the compound requirement T. If substituting
- into either the expression or the type fails, the corresponding
- operands in the resulting node will be error_mark_node. This
- preserves a requirement for the purpose of partial ordering, but
- it will never be satisfied. */
-
-tree
-tsubst_compound_requirement (tree t, tree args,
- tsubst_flags_t complain, tree in_decl)
-{
- ++processing_template_decl;
- tree expr = tsubst_expr (TREE_OPERAND (t, 0), args, complain, in_decl, false);
- tree type = tsubst (TREE_OPERAND (t, 1), args, complain, in_decl);
- --processing_template_decl;
- bool noexcept_p = COMPOUND_REQ_NOEXCEPT_P (t);
- return finish_compound_requirement (expr, type, noexcept_p);
-}
-
-/* Substitute ARGS into the nested requirement T. */
-
-tree
-tsubst_nested_requirement (tree t, tree args,
- tsubst_flags_t complain, tree in_decl)
-{
- ++processing_template_decl;
- tree expr = tsubst_expr (TREE_OPERAND (t, 0), args, complain, in_decl, false);
- --processing_template_decl;
- return finish_nested_requirement (expr);
-}
-
-/* Substitute ARGS into the requirement T. */
+ However, there are cases where substitution must produce a
+ new requires-expression, that is not a template constraint.
+ For example:
-inline tree
-tsubst_requirement (tree t, tree args, tsubst_flags_t complain, tree in_decl)
-{
- switch (TREE_CODE (t))
- {
- case SIMPLE_REQ:
- return tsubst_simple_requirement (t, args, complain, in_decl);
- case TYPE_REQ:
- return tsubst_type_requirement (t, args, complain, in_decl);
- case COMPOUND_REQ:
- return tsubst_compound_requirement (t, args, complain, in_decl);
- case NESTED_REQ:
- return tsubst_nested_requirement (t, args, complain, in_decl);
- default:
- gcc_unreachable ();
- }
- return error_mark_node;
-}
+ template<typename T>
+ class X {
+ template<typename U>
+ static constexpr bool var = requires (U u) { T::fn(u); };
+ };
-/* Substitute ARGS into the list of requirements T. Note that
- substitution failures here result in ill-formed programs. */
+ In the instantiation of X<Y> (assuming Y defines fn), then the
+ instantiated requires-expression would include Y::fn(u). If any
+ substitution in the requires-expression fails, we can immediately
+ fold the expression to false, as would be the case e.g., when
+ instantiation X<int>. */
tree
-tsubst_requirement_body (tree t, tree args,
- tsubst_flags_t complain, tree in_decl)
+tsubst_requires_expr (tree t, tree args,
+ tsubst_flags_t complain, tree in_decl)
{
- tree r = NULL_TREE;
- while (t)
- {
- tree e = tsubst_requirement (TREE_VALUE (t), args, complain, in_decl);
- if (e == error_mark_node)
- return error_mark_node;
- r = tree_cons (NULL_TREE, e, r);
- t = TREE_CHAIN (t);
- }
- /* Ensure that the order of constraints is the same as the original. */
- return nreverse (r);
-}
+ local_specialization_stack stack (lss_copy);
-} /* namespace */
+ subst_info info (complain, in_decl);
-/* Substitute ARGS into the requires expression T. Note that this
- results in the re-declaration of local parameters when
- substituting through the parameter list. If either substitution
- fails, the program is ill-formed. */
-
-tree
-tsubst_requires_expr (tree t, tree args,
- tsubst_flags_t complain, tree in_decl)
-{
- local_specialization_stack stack;
+ /* A requires-expression is an unevaluated context. */
+ cp_unevaluated u;
tree parms = TREE_OPERAND (t, 0);
if (parms)
{
- parms = tsubst_constraint_variables (parms, args, complain, in_decl);
+ parms = tsubst_constraint_variables (parms, args, info);
if (parms == error_mark_node)
- return error_mark_node;
+ return boolean_false_node;
}
tree reqs = TREE_OPERAND (t, 1);
- reqs = tsubst_requirement_body (reqs, args, complain, in_decl);
+ reqs = tsubst_requirement_body (reqs, args, info);
if (reqs == error_mark_node)
- return error_mark_node;
+ return boolean_false_node;
- return finish_requires_expr (parms, reqs);
+ /* In certain cases, produce a new requires-expression.
+ Otherwise the value of the expression is true. */
+ if (processing_template_decl && uses_template_parms (args))
+ return finish_requires_expr (cp_expr_location (t), parms, reqs);
+
+ return boolean_true_node;
}
/* Substitute ARGS into the constraint information CI, producing a new
- constraint record. */
+ constraint record. */
tree
tsubst_constraint_info (tree t, tree args,
@@ -1904,378 +1998,418 @@ tsubst_constraint_info (tree t, tree args,
if (!t || t == error_mark_node || !check_constraint_info (t))
return NULL_TREE;
- tree tmpl_constr = NULL_TREE;
- if (tree r = CI_TEMPLATE_REQS (t))
- tmpl_constr = tsubst_constraint (r, args, complain, in_decl);
+ tree tr = tsubst_constraint (CI_TEMPLATE_REQS (t), args, complain, in_decl);
+ tree dr = tsubst_constraint (CI_DECLARATOR_REQS (t), args, complain, in_decl);
+ return build_constraints (tr, dr);
+}
- tree decl_constr = NULL_TREE;
- if (tree r = CI_DECLARATOR_REQS (t))
- decl_constr = tsubst_constraint (r, args, complain, in_decl);
+/* Substitute through a parameter mapping, in order to get the actual
+ arguments used to instantiate an atomic constraint. This may fail
+ if the substitution into arguments produces something ill-formed. */
- return build_constraints (tmpl_constr, decl_constr);
-}
+static tree
+tsubst_parameter_mapping (tree map, tree args, subst_info info)
+{
+ if (!map)
+ return NULL_TREE;
-/* Substitute ARGS into the constraint T. */
+ tsubst_flags_t complain = info.complain;
+ tree in_decl = info.in_decl;
+
+ tree result = NULL_TREE;
+ for (tree p = map; p; p = TREE_CHAIN (p))
+ {
+ if (p == error_mark_node)
+ return error_mark_node;
+ tree parm = TREE_VALUE (p);
+ tree arg = TREE_PURPOSE (p);
+ tree new_arg = NULL_TREE;
+ if (TYPE_P (arg))
+ {
+ /* If a template parameter is declared with a placeholder, we can
+ get those in the argument list if decltype is applied to the
+ placeholder. For example:
+
+ template<auto T>
+ requires C<decltype(T)>
+ void f() { }
+
+ The normalized argument for C will be an auto type, so we'll
+ need to deduce the actual argument from the corresponding
+ initializer (whatever argument is provided for T), and use
+ that result in the instantiated parameter mapping. */
+ if (tree auto_node = type_uses_auto (arg))
+ {
+ int level;
+ int index;
+ template_parm_level_and_index (parm, &level, &index);
+ tree init = TMPL_ARG (args, level, index);
+ new_arg = do_auto_deduction (arg, init, auto_node,
+ complain, adc_variable_type,
+ make_tree_vec (0));
+ }
+ }
+ else if (ARGUMENT_PACK_P (arg))
+ new_arg = tsubst_argument_pack (arg, args, complain, in_decl);
+ if (!new_arg)
+ new_arg = tsubst_template_arg (arg, args, complain, in_decl);
+ if (new_arg == error_mark_node)
+ return error_mark_node;
+
+ result = tree_cons (new_arg, parm, result);
+ }
+ return nreverse (result);
+}
tree
-tsubst_constraint (tree t, tree args, tsubst_flags_t complain, tree in_decl)
+tsubst_parameter_mapping (tree map, tree args, tsubst_flags_t complain, tree in_decl)
{
- if (t == NULL_TREE || t == error_mark_node)
- return t;
- switch (TREE_CODE (t))
- {
- case PRED_CONSTR:
- return tsubst_predicate_constraint (t, args, complain, in_decl);
- case CHECK_CONSTR:
- return tsubst_check_constraint (t, args, complain, in_decl);
- case CONJ_CONSTR:
- case DISJ_CONSTR:
- return tsubst_logical_operator (t, args, complain, in_decl);
- case PARM_CONSTR:
- return tsubst_parameterized_constraint (t, args, complain, in_decl);
- case EXPR_CONSTR:
- return tsubst_expr_constr (t, args, complain, in_decl);
- case TYPE_CONSTR:
- return tsubst_type_constr (t, args, complain, in_decl);
- case ICONV_CONSTR:
- return tsubst_implicit_conversion_constr (t, args, complain, in_decl);
- case DEDUCT_CONSTR:
- return tsubst_argument_deduction_constr (t, args, complain, in_decl);
- case EXCEPT_CONSTR:
- return tsubst_exception_constr (t, args, complain, in_decl);
- default:
- gcc_unreachable ();
- }
- return error_mark_node;
+ return tsubst_parameter_mapping (map, args, subst_info (complain, in_decl));
}
/*---------------------------------------------------------------------------
Constraint satisfaction
---------------------------------------------------------------------------*/
-/* The following functions determine if a constraint, when
- substituting template arguments, is satisfied. For convenience,
- satisfaction reduces a constraint to either true or false (and
- nothing else). */
-
-namespace {
-
-tree satisfy_constraint_1 (tree, tree, tsubst_flags_t, tree);
+/* Hash functions for satisfaction entries. */
-/* Check the constraint pack expansion. */
-
-tree
-satisfy_pack_expansion (tree t, tree args,
- tsubst_flags_t complain, tree in_decl)
+struct GTY((for_user)) sat_entry
{
- /* Get the vector of satisfaction results.
- gen_elem_of_pack_expansion_instantiation will check that each element of
- the expansion is satisfied. */
- tree exprs = tsubst_pack_expansion (t, args, complain, in_decl);
+ tree constr;
+ tree args;
+ tree result;
+};
- if (exprs == error_mark_node)
- return boolean_false_node;
+struct sat_hasher : ggc_ptr_hash<sat_entry>
+{
+ static hashval_t hash (sat_entry *e)
+ {
+ hashval_t value = hash_atomic_constraint (e->constr);
+ return iterative_hash_template_arg (e->args, value);
+ }
- /* TODO: It might be better to normalize each expanded term
- and evaluate them separately. That would provide better
- opportunities for diagnostics. */
- for (int i = 0; i < TREE_VEC_LENGTH (exprs); ++i)
- if (TREE_VEC_ELT (exprs, i) != boolean_true_node)
- return boolean_false_node;
- return boolean_true_node;
-}
+ static bool equal (sat_entry *e1, sat_entry *e2)
+ {
+ if (!atomic_constraints_identical_p (e1->constr, e2->constr))
+ return false;
+ return template_args_equal (e1->args, e2->args);
+ }
+};
-/* A predicate constraint is satisfied if its expression evaluates
- to true. If substitution into that node fails, the constraint
- is not satisfied ([temp.constr.pred]).
+/* Cache the result of satisfy_atom. */
+static GTY((deletable)) hash_table<sat_hasher> *sat_cache;
- Note that a predicate constraint is a constraint expression
- of type bool. If neither of those are true, the program is
- ill-formed; they are not SFINAE'able errors. */
+/* Cache the result of constraints_satisfied_p. */
+static GTY((deletable)) hash_map<tree,bool> *decl_satisfied_cache;
-tree
-satisfy_predicate_constraint (tree t, tree args,
- tsubst_flags_t complain, tree in_decl)
+static tree
+get_satisfaction (tree constr, tree args)
{
- tree expr = TREE_OPERAND (t, 0);
-
- /* We should never have a naked pack expansion in a predicate constraint. */
- gcc_assert (TREE_CODE (expr) != EXPR_PACK_EXPANSION);
-
- /* If substitution into the expression fails, the constraint
- is not satisfied. */
- expr = tsubst_expr (expr, args, complain, in_decl, false);
- if (expr == error_mark_node)
- return boolean_false_node;
+ if (!sat_cache)
+ return NULL_TREE;
+ sat_entry elt = { constr, args, NULL_TREE };
+ sat_entry* found = sat_cache->find (&elt);
+ if (found)
+ return found->result;
+ else
+ return NULL_TREE;
+}
- /* A predicate constraint shall have type bool. In some
- cases, substitution gives us const-qualified bool, which
- is also acceptable. */
- tree type = cv_unqualified (TREE_TYPE (expr));
- if (!same_type_p (type, boolean_type_node))
- {
- error_at (cp_expr_loc_or_input_loc (expr),
- "constraint %qE does not have type %qT",
- expr, boolean_type_node);
- return boolean_false_node;
- }
+static void
+save_satisfaction (tree constr, tree args, tree result)
+{
+ if (!sat_cache)
+ sat_cache = hash_table<sat_hasher>::create_ggc (31);
+ sat_entry elt = {constr, args, result};
+ sat_entry** slot = sat_cache->find_slot (&elt, INSERT);
+ sat_entry* entry = ggc_alloc<sat_entry> ();
+ *entry = elt;
+ *slot = entry;
+}
- return cxx_constant_value (expr);
+void
+clear_satisfaction_cache ()
+{
+ if (sat_cache)
+ sat_cache->empty ();
+ if (decl_satisfied_cache)
+ decl_satisfied_cache->empty ();
}
-/* A concept check constraint like C<CARGS> is satisfied if substituting ARGS
- into CARGS succeeds and C is satisfied for the resulting arguments. */
+/* A tool to help manage satisfaction caching in satisfy_constraint_r.
+ Note the cache is only used when not diagnosing errors. */
-tree
-satisfy_check_constraint (tree t, tree args,
- tsubst_flags_t complain, tree in_decl)
+struct satisfaction_cache
{
- tree decl = CHECK_CONSTR_CONCEPT (t);
- tree tmpl = DECL_TI_TEMPLATE (decl);
- tree cargs = CHECK_CONSTR_ARGS (t);
+ satisfaction_cache (tree constr, tree args, tsubst_flags_t complain)
+ : constr(constr), args(args), complain(complain)
+ { }
- /* Instantiate the concept check arguments. */
- tree targs = tsubst (cargs, args, tf_none, NULL_TREE);
- if (targs == error_mark_node)
- return boolean_false_node;
+ tree get ()
+ {
+ if (complain == tf_none)
+ return get_satisfaction (constr, args);
+ return NULL_TREE;
+ }
- /* Search for a previous value. */
- if (tree prev = lookup_concept_satisfaction (tmpl, targs))
- return prev;
+ tree save (tree result)
+ {
+ if (complain == tf_none)
+ save_satisfaction (constr, args, result);
+ return result;
+ }
- /* Expand the concept; failure here implies non-satisfaction. */
- tree def = expand_concept (decl, targs);
- if (def == error_mark_node)
- return memoize_concept_satisfaction (tmpl, args, boolean_false_node);
+ tree constr;
+ tree args;
+ tsubst_flags_t complain;
+};
- /* Recursively satisfy the constraint. */
- tree result = satisfy_constraint_1 (def, targs, complain, in_decl);
- return memoize_concept_satisfaction (tmpl, targs, result);
-}
+static int satisfying_constraint = 0;
-/* Check an expression constraint. The constraint is satisfied if
- substitution succeeds ([temp.constr.expr]).
+/* Returns true if we are currently satisfying a constraint.
- Note that the expression is unevaluated. */
+ This is used to guard against recursive calls to evaluate_concept_check
+ during template argument substitution.
-tree
-satisfy_expression_constraint (tree t, tree args,
- tsubst_flags_t complain, tree in_decl)
-{
- cp_unevaluated guard;
- deferring_access_check_sentinel deferring;
+ TODO: Do we need this now that we fully normalize prior to evaluation?
+ I think not. */
- tree expr = EXPR_CONSTR_EXPR (t);
- tree check = tsubst_expr (expr, args, complain, in_decl, false);
- if (check == error_mark_node)
- return boolean_false_node;
- if (!perform_deferred_access_checks (tf_none))
- return boolean_false_node;
- return boolean_true_node;
+bool
+satisfying_constraint_p ()
+{
+ return satisfying_constraint;
}
-/* Check a type constraint. The constraint is satisfied if
- substitution succeeds. */
+/* Substitute ARGS into constraint-expression T during instantiation of
+ a member of a class template. */
-inline tree
-satisfy_type_constraint (tree t, tree args,
- tsubst_flags_t complain, tree in_decl)
+tree
+tsubst_constraint (tree t, tree args, tsubst_flags_t complain, tree in_decl)
{
- deferring_access_check_sentinel deferring;
- tree type = TYPE_CONSTR_TYPE (t);
- gcc_assert (TYPE_P (type) || type == error_mark_node);
- tree check = tsubst (type, args, complain, in_decl);
- if (error_operand_p (check))
- return boolean_false_node;
- if (!perform_deferred_access_checks (complain))
- return boolean_false_node;
- return boolean_true_node;
+ /* We also don't want to evaluate concept-checks when substituting the
+ constraint-expressions of a declaration. */
+ processing_constraint_expression_sentinel s;
+ tree expr = tsubst_expr (t, args, complain, in_decl, false);
+ return expr;
}
-/* Check an implicit conversion constraint. */
+static tree satisfy_constraint_r (tree, tree, subst_info info);
-tree
-satisfy_implicit_conversion_constraint (tree t, tree args,
- tsubst_flags_t complain, tree in_decl)
-{
- /* Don't tsubst as if we're processing a template. If we try
- to we can end up generating template-like expressions
- (e.g., modop-exprs) that aren't properly typed. */
- tree expr =
- tsubst_expr (ICONV_CONSTR_EXPR (t), args, complain, in_decl, false);
- if (expr == error_mark_node)
- return boolean_false_node;
-
- /* Get the transformed target type. */
- tree type = tsubst (ICONV_CONSTR_TYPE (t), args, complain, in_decl);
- if (type == error_mark_node)
- return boolean_false_node;
+/* Compute the satisfaction of a conjunction. */
- /* Attempt the conversion as a direct initialization
- of the form TYPE <unspecified> = EXPR. */
- tree conv =
- perform_direct_initialization_if_possible (type, expr, false, complain);
- if (conv == NULL_TREE || conv == error_mark_node)
- return boolean_false_node;
- else
- return boolean_true_node;
+static tree
+satisfy_conjunction (tree t, tree args, subst_info info)
+{
+ tree lhs = satisfy_constraint_r (TREE_OPERAND (t, 0), args, info);
+ if (lhs == error_mark_node || lhs == boolean_false_node)
+ return lhs;
+ return satisfy_constraint_r (TREE_OPERAND (t, 1), args, info);
}
-/* Check an argument deduction constraint. */
+/* Compute the satisfaction of a disjunction. */
-tree
-satisfy_argument_deduction_constraint (tree t, tree args,
- tsubst_flags_t complain, tree in_decl)
+static tree
+satisfy_disjunction (tree t, tree args, subst_info info)
{
- /* Substitute through the expression. */
- tree expr = DEDUCT_CONSTR_EXPR (t);
- tree init = tsubst_expr (expr, args, complain, in_decl, false);
- if (expr == error_mark_node)
- return boolean_false_node;
+ /* Evaluate the operands quietly. */
+ subst_info quiet (tf_none, NULL_TREE);
- /* Perform auto or decltype(auto) deduction to get the result. */
- tree pattern = DEDUCT_CONSTR_PATTERN (t);
- tree placeholder = DEDUCT_CONSTR_PLACEHOLDER (t);
- tree constr = PLACEHOLDER_TYPE_CONSTRAINTS (placeholder);
- tree type_canonical = TYPE_CANONICAL (placeholder);
- PLACEHOLDER_TYPE_CONSTRAINTS (placeholder)
- = tsubst_constraint (constr, args, complain|tf_partial, in_decl);
- TYPE_CANONICAL (placeholder) = NULL_TREE;
- tree type = do_auto_deduction (pattern, init, placeholder,
- complain, adc_requirement);
- PLACEHOLDER_TYPE_CONSTRAINTS (placeholder) = constr;
- TYPE_CANONICAL (placeholder) = type_canonical;
- if (type == error_mark_node)
- return boolean_false_node;
+ /* Register the constraint for diagnostics, if needed. */
+ diagnosing_failed_constraint failure (t, args, info.noisy ());
- return boolean_true_node;
+ tree lhs = satisfy_constraint_r (TREE_OPERAND (t, 0), args, quiet);
+ if (lhs == boolean_true_node)
+ return boolean_true_node;
+ tree rhs = satisfy_constraint_r (TREE_OPERAND (t, 1), args, quiet);
+ if (rhs != boolean_true_node && info.noisy ())
+ {
+ location_t loc = cp_expr_location (CONSTR_EXPR (t));
+ inform (loc, "neither operand of the disjunction is satisfied");
+ /* TODO: Replay the LHS and RHS to find failures in both branches. */
+ // satisfy_constraint_r (TREE_OPERAND (t, 0), args, info);
+ // satisfy_constraint_r (TREE_OPERAND (t, 1), args, info);
+ }
+ return rhs;
}
-/* Check an exception constraint. An exception constraint for an
- expression e is satisfied when noexcept(e) is true. */
+/* Ensures that T is a truth value and not (accidentally, as sometimes
+ happens) an integer value. */
tree
-satisfy_exception_constraint (tree t, tree args,
- tsubst_flags_t complain, tree in_decl)
+satisfaction_value (tree t)
{
- tree expr = EXCEPT_CONSTR_EXPR (t);
- tree check = tsubst_expr (expr, args, complain, in_decl, false);
- if (check == error_mark_node)
- return boolean_false_node;
-
- if (expr_noexcept_p (check, complain))
+ if (t == error_mark_node)
+ return t;
+ if (t == boolean_true_node || t == integer_one_node)
return boolean_true_node;
- else
+ if (t == boolean_false_node || t == integer_zero_node)
return boolean_false_node;
+
+ /* Anything else should be invalid. */
+ gcc_assert (false);
}
-/* Check a parameterized constraint. */
+/* Build a new template argument list with template arguments corresponding
+ to the parameters used in an atomic constraint. */
tree
-satisfy_parameterized_constraint (tree t, tree args,
- tsubst_flags_t complain, tree in_decl)
+get_mapped_args (tree map)
{
- local_specialization_stack stack;
- tree parms = PARM_CONSTR_PARMS (t);
- tree vars = tsubst_constraint_variables (parms, args, complain, in_decl);
- if (vars == error_mark_node)
- return boolean_false_node;
- tree constr = PARM_CONSTR_OPERAND (t);
- return satisfy_constraint_1 (constr, args, complain, in_decl);
-}
-
-/* Check that the conjunction of constraints is satisfied. Note
- that if left operand is not satisfied, the right operand
- is not checked.
+ /* If there's no map, then there are no arguments. */
+ if (!map)
+ return NULL_TREE;
- FIXME: Check that this wouldn't result in a user-defined
- operator. Note that this error is partially diagnosed in
- satisfy_predicate_constraint. It would be nice to diagnose
- the overload, but I don't think it's strictly necessary. */
+ /* Find the mapped parameter with the highest level. */
+ int count = 0;
+ for (tree p = map; p; p = TREE_CHAIN (p))
+ {
+ int level;
+ int index;
+ template_parm_level_and_index (TREE_VALUE (p), &level, &index);
+ if (level > count)
+ count = level;
+ }
-tree
-satisfy_conjunction (tree t, tree args, tsubst_flags_t complain, tree in_decl)
-{
- tree t0 = satisfy_constraint_1 (TREE_OPERAND (t, 0), args, complain, in_decl);
- if (t0 == boolean_false_node)
- return boolean_false_node;
- return satisfy_constraint_1 (TREE_OPERAND (t, 1), args, complain, in_decl);
-}
+ /* Place each argument at its corresponding position in the argument
+ list. Note that the list will be sparse (not all arguments supplied),
+ but instantiation is guaranteed to only use the parameters in the
+ mapping, so null arguments would never be used. */
+ auto_vec< auto_vec<tree> > lists (count);
+ lists.quick_grow_cleared (count);
+ for (tree p = map; p; p = TREE_CHAIN (p))
+ {
+ int level;
+ int index;
+ template_parm_level_and_index (TREE_VALUE (p), &level, &index);
+
+ /* Insert the argument into its corresponding position. */
+ auto_vec<tree> &list = lists[level - 1];
+ if (index >= (int)list.length ())
+ list.safe_grow_cleared (index + 1);
+ list[index] = TREE_PURPOSE (p);
+ }
-/* Check that the disjunction of constraints is satisfied. Note
- that if the left operand is satisfied, the right operand is not
- checked. */
+ /* Build the actual argument list. */
+ tree args = make_tree_vec (lists.length ());
+ for (unsigned i = 0; i != lists.length (); ++i)
+ {
+ auto_vec<tree> &list = lists[i];
+ tree level = make_tree_vec (list.length ());
+ for (unsigned j = 0; j < list.length(); ++j)
+ TREE_VEC_ELT (level, j) = list[j];
+ SET_TMPL_ARGS_LEVEL (args, i + 1, level);
+ }
+ SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (args, 0);
-tree
-satisfy_disjunction (tree t, tree args, tsubst_flags_t complain, tree in_decl)
-{
- tree t0 = satisfy_constraint_1 (TREE_OPERAND (t, 0), args, complain, in_decl);
- if (t0 == boolean_true_node)
- return boolean_true_node;
- return satisfy_constraint_1 (TREE_OPERAND (t, 1), args, complain, in_decl);
+ return args;
}
-/* Dispatch to an appropriate satisfaction routine depending on the
- tree code of T. */
+static void diagnose_atomic_constraint (tree, tree, subst_info);
-tree
-satisfy_constraint_1 (tree t, tree args, tsubst_flags_t complain, tree in_decl)
+/* Compute the satisfaction of an atomic constraint. */
+
+static tree
+satisfy_atom (tree t, tree args, subst_info info)
{
- gcc_assert (!processing_template_decl);
+ satisfaction_cache cache (t, args, info.complain);
+ if (tree r = cache.get ())
+ return r;
- if (!t)
- return boolean_false_node;
+ /* Perform substitution quietly. */
+ subst_info quiet (tf_none, NULL_TREE);
- if (t == error_mark_node)
- return boolean_false_node;
-
- switch (TREE_CODE (t))
- {
- case PRED_CONSTR:
- return satisfy_predicate_constraint (t, args, complain, in_decl);
+ /* In case there is a diagnostic, we want to establish the context
+ prior to printing errors. If no errors occur, this context is
+ removed before returning. */
+ diagnosing_failed_constraint failure (t, args, info.noisy ());
- case CHECK_CONSTR:
- return satisfy_check_constraint (t, args, complain, in_decl);
+ /* Instantiate the parameter mapping, so that we map directly to
+ the arguments provided to the instantiation. */
+ tree map = tsubst_parameter_mapping (ATOMIC_CONSTR_MAP (t), args, quiet);
+ if (map == error_mark_node)
+ {
+ /* If instantiation of the parameter mapping fails, the program
+ is ill-formed. */
+ if (info.noisy())
+ tsubst_parameter_mapping (ATOMIC_CONSTR_MAP (t), args, info);
+ return cache.save (boolean_false_node);
+ }
- case EXPR_CONSTR:
- return satisfy_expression_constraint (t, args, complain, in_decl);
+ /* Rebuild the argument vector from the parameter mapping. */
+ args = get_mapped_args (map);
- case TYPE_CONSTR:
- return satisfy_type_constraint (t, args, complain, in_decl);
+ /* Apply the parameter mapping (i.e., just substitute). */
+ tree expr = ATOMIC_CONSTR_EXPR (t);
+ tree result = tsubst_expr (expr, args, quiet.complain, quiet.in_decl, false);
+ if (result == error_mark_node)
+ {
+ /* If substitution results in an invalid type or expression, the constraint
+ is not satisfied. Replay the substitution. */
+ if (info.noisy ())
+ tsubst_expr (expr, args, info.complain, info.in_decl, false);
+ return cache.save (boolean_false_node);
+ }
- case ICONV_CONSTR:
- return satisfy_implicit_conversion_constraint (t, args, complain, in_decl);
+ location_t loc = cp_expr_location (expr);
- case DEDUCT_CONSTR:
- return satisfy_argument_deduction_constraint (t, args, complain, in_decl);
+ /* [17.4.1.2] ... lvalue-to-value conversion is performed as necessary,
+ and EXPR shall be a constant expression of type bool. */
+ result = force_rvalue (result, tf_error);
+ if (result == error_mark_node)
+ {
+ if (info.noisy ())
+ inform (loc, "cannot convert constraint to rvalue");
+ return cache.save (error_mark_node);
+ }
+ if (!same_type_p (TREE_TYPE (result), boolean_type_node))
+ {
+ if (info.noisy ())
+ inform (loc, "constraint does not have type %<bool%>");
+ return cache.save (error_mark_node);
+ }
- case EXCEPT_CONSTR:
- return satisfy_exception_constraint (t, args, complain, in_decl);
+ /* Compute the value of the constraint. */
+ result = satisfaction_value (cxx_constant_value (result));
+ if (result == boolean_false_node && info.noisy ())
+ diagnose_atomic_constraint (t, args, info);
- case PARM_CONSTR:
- return satisfy_parameterized_constraint (t, args, complain, in_decl);
+ return cache.save (result);
+}
- case CONJ_CONSTR:
- return satisfy_conjunction (t, args, complain, in_decl);
+/* Determine if the normalized constraint T is satisfied.
+ Returns boolean_true_node if the expression/constraint is
+ satisfied, boolean_false_node if not, and error_mark_node
+ if the there was an error evaluating the constraint.
- case DISJ_CONSTR:
- return satisfy_disjunction (t, args, complain, in_decl);
+ The parameter mapping of atomic constraints is simply the
+ set of template arguments that will be substituted into
+ the expression, regardless of template parameters appearing
+ withing. Whether a template argument is used in the atomic
+ constraint only matters for subsumption. */
- case EXPR_PACK_EXPANSION:
- return satisfy_pack_expansion (t, args, complain, in_decl);
+static tree
+satisfy_constraint_r (tree t, tree args, subst_info info)
+{
+ if (t == error_mark_node)
+ return error_mark_node;
- default:
- gcc_unreachable ();
- }
- return boolean_false_node;
+ switch (TREE_CODE (t))
+ {
+ case CONJ_CONSTR:
+ return satisfy_conjunction (t, args, info);
+ case DISJ_CONSTR:
+ return satisfy_disjunction (t, args, info);
+ case ATOMIC_CONSTR:
+ return satisfy_atom (t, args, info);
+ default:
+ gcc_unreachable ();
+ }
}
-/* Check that the constraint is satisfied, according to the rules
- for that constraint. Note that each satisfy_* function returns
- true or false, depending on whether it is satisfied or not. */
+/* Check that the normalized constraint T is satisfied for ARGS. */
-tree
-satisfy_constraint (tree t, tree args)
+static tree
+satisfy_constraint (tree t, tree args, subst_info info)
{
auto_timevar time (TV_CONSTRAINT_SAT);
@@ -2283,146 +2417,199 @@ satisfy_constraint (tree t, tree args)
to non-dependent terms, so we want to ensure full checking here. */
processing_template_decl_sentinel proc (true);
- /* Avoid early exit in tsubst and tsubst_copy from null args; since earlier
- substitution was done with processing_template_decl forced on, there will
- be expressions that still need semantic processing, possibly buried in
- decltype or a template argument. */
+ /* We need to check access during satisfaction. */
+ deferring_access_check_sentinel acs (dk_no_deferred);
+
+ /* Avoid early exit in tsubst and tsubst_copy from null args. */
if (args == NULL_TREE)
args = make_tree_vec (1);
- return satisfy_constraint_1 (t, args, tf_none, NULL_TREE);
+ return satisfy_constraint_r (t, args, info);
}
-/* Check the associated constraints in CI against the given
- ARGS, returning true when the constraints are satisfied
- and false otherwise. */
+/* Check the normalized constraints T against ARGS, returning a satisfaction
+ value (either true, false, or error). */
-tree
-satisfy_associated_constraints (tree ci, tree args)
+static tree
+satisfy_associated_constraints (tree t, tree args, subst_info info)
{
/* If there are no constraints then this is trivially satisfied. */
- if (!ci)
+ if (!t)
return boolean_true_node;
/* If any arguments depend on template parameters, we can't
- check constraints. */
+ check constraints. Pretend they're satisfied for now. */
if (args && uses_template_parms (args))
return boolean_true_node;
- /* Check if we've seen a previous result. */
- if (tree prev = lookup_constraint_satisfaction (ci, args))
- return prev;
-
- /* Actually test for satisfaction. */
- tree result = satisfy_constraint (CI_ASSOCIATED_CONSTRAINTS (ci), args);
- return memoize_constraint_satisfaction (ci, args, result);
+ return satisfy_constraint (t, args, info);
}
-} /* namespace */
-
-/* Evaluate the given constraint, returning boolean_true_node
- if the constraint is satisfied and boolean_false_node
- otherwise. */
+/* Evaluate EXPR as a constraint expression using ARGS, returning a
+ satisfaction value. */
-tree
-evaluate_constraints (tree constr, tree args)
+static tree
+satisfy_constraint_expression (tree expr, tree args, subst_info info)
{
- gcc_assert (constraint_p (constr));
- return satisfy_constraint (constr, args);
+ /* Normalize the expression before satisfaction testing. */
+ tree norm;
+ if (args == NULL_TREE && concept_check_p (expr))
+ {
+ tree id = unpack_concept_check (expr);
+ args = TREE_OPERAND (id, 1);
+ tree tmpl = get_concept_check_template (id);
+ norm = normalize_concept_definition (tmpl);
+ }
+ else
+ norm = normalize_constraint_expression (expr);
+ return satisfy_constraint (norm, args, info);
}
-/* Evaluate the function concept FN by substituting its own args
- into its definition and evaluating that as the result. Returns
- boolean_true_node if the constraints are satisfied and
- boolean_false_node otherwise. */
+/* Used to evaluate concept checks and requires-expressions during
+ constant expression evaluation. */
tree
-evaluate_function_concept (tree fn, tree args)
+satisfy_constraint_expression (tree expr)
{
- tree constr = build_nt (CHECK_CONSTR, fn, args);
- return satisfy_constraint (constr, args);
+ subst_info info (tf_none, NULL_TREE);
+ return satisfy_constraint_expression (expr, NULL_TREE, info);
}
-/* Evaluate the variable concept VAR by substituting its own args into
- its initializer and checking the resulting constraint. Returns
- boolean_true_node if the constraints are satisfied and
- boolean_false_node otherwise. */
+/* True if T is satisfied for ARGS. */
-tree
-evaluate_variable_concept (tree var, tree args)
+static bool
+constraint_expression_satisfied_p (tree t, tree args, subst_info info)
{
- tree constr = build_nt (CHECK_CONSTR, var, args);
- return satisfy_constraint (constr, args);
+ tree r = satisfy_constraint_expression (t, args, info);
+ return r == boolean_true_node;
}
-/* Evaluate the given expression as if it were a predicate
- constraint. Returns boolean_true_node if the constraint
- is satisfied and boolean_false_node otherwise. */
-
-tree
-evaluate_constraint_expression (tree expr, tree args)
+static bool
+constraints_satisfied_p (tree t, subst_info info)
{
- tree constr = normalize_expression (expr);
- return satisfy_constraint (constr, args);
-}
+ if (!DECL_P (t))
+ return constraint_expression_satisfied_p (t, NULL_TREE, info);
-/* Returns true if the DECL's constraints are satisfied.
- This is used in cases where a declaration is formed but
- before it is used (e.g., overload resolution). */
+ /* For inherited constructors, consider the original declaration;
+ it has the correct template information attached. */
+ if (flag_new_inheriting_ctors)
+ t = strip_inheriting_ctors (t);
+
+ /* Update the declaration for diagnostics. */
+ info.in_decl = t;
+
+ if (info.quiet ())
+ if (bool *p = hash_map_safe_get (decl_satisfied_cache, t))
+ return *p;
-bool
-constraints_satisfied_p (tree decl)
-{
/* Get the constraints to check for satisfaction. This depends
on whether we're looking at a template specialization or not. */
- tree ci;
+ tree norm = NULL_TREE;
tree args = NULL_TREE;
- if (tree ti = DECL_TEMPLATE_INFO (decl))
+ tree ti = DECL_TEMPLATE_INFO (t);
+ if (ti)
{
tree tmpl = TI_TEMPLATE (ti);
- ci = get_constraints (tmpl);
- int depth = TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl));
- args = get_innermost_template_args (TI_ARGS (ti), depth);
+ norm = normalize_template_requirements (tmpl, info.noisy ());
+
+ /* The initial parameter mapping is the complete set of
+ template arguments substituted into the declaration. */
+ args = TI_ARGS (ti);
}
else
{
- ci = get_constraints (decl);
+ /* These should be empty until we allow constraints on non-templates. */
+ norm = normalize_nontemplate_requirements (t, info.noisy ());
}
- tree eval = satisfy_associated_constraints (ci, args);
- return eval == boolean_true_node;
+ bool r = true;
+ if (norm)
+ {
+ push_access_scope (t);
+ tree eval = satisfy_associated_constraints (norm, args, info);
+ pop_access_scope (t);
+ r = (eval == boolean_true_node);
+ }
+
+ if (info.quiet ())
+ hash_map_safe_put<hm_ggc> (decl_satisfied_cache, t, r);
+
+ return r;
}
-/* Returns true if the constraints are satisfied by ARGS.
- Here, T can be either a constraint or a constrained
- declaration. */
+/* Returns true if the T's constraints are satisfied, of if T is an expression,
+ if T is satisfied. This is used in cases where the arguments can be
+ determined from the declaration or expression.
+
+ Note that T is typically a template specialization. */
bool
-constraints_satisfied_p (tree t, tree args)
+constraints_satisfied_p (tree t)
{
- tree eval;
- if (constraint_p (t))
- eval = evaluate_constraints (t, args);
- else
- eval = satisfy_associated_constraints (get_constraints (t), args);
- return eval == boolean_true_node;
+ subst_info info (tf_none, NULL_TREE);
+ return constraints_satisfied_p (t, info);
}
-namespace
+/* Returns true if the expression or constrained declaration T is
+ satisfied by ARGS. In this case, we don't have a specialization
+ where we can cache the results (e.g., alias templates). */
+
+static bool
+constraints_satisfied_p (tree t, tree args, subst_info info)
{
+ if (!DECL_P (t))
+ return constraint_expression_satisfied_p (t, args, info);
-/* Normalize EXPR and determine if the resulting constraint is
- satisfied by ARGS. Returns true if and only if the constraint
- is satisfied. This is used extensively by diagnostics to
- determine causes for failure. */
+ /* Update the declaration for diagnostics. */
+ info.in_decl = t;
-inline bool
-constraint_expression_satisfied_p (tree expr, tree args)
+ gcc_assert (TREE_CODE (t) == TEMPLATE_DECL);
+ if (tree norm = normalize_template_requirements (t, info.noisy ()))
+ {
+ tree pattern = DECL_TEMPLATE_RESULT (t);
+ push_access_scope (pattern);
+ tree eval = satisfy_associated_constraints (norm, args, info);
+ pop_access_scope (pattern);
+ return eval == boolean_true_node;
+ }
+
+ return true;
+}
+
+bool
+constraints_satisfied_p (tree t, tree args)
{
- return evaluate_constraint_expression (expr, args) == boolean_true_node;
+ subst_info info (tf_none, NULL);
+ return constraints_satisfied_p (t, args, info);
}
-} /* namespace */
+/* Evaluate a concept check of the form C<ARGS>, returning either TRUE
+ or FALSE. If ARGS contains any template parameters, this returns the
+ check. If satisfaction yields a hard error, diagnose the error. */
+
+tree
+evaluate_concept_check (tree check, tsubst_flags_t complain)
+{
+ /* FIXME we ought to be able to pass complain into subst_info rather
+ than repeat satisfaction, but currently that will complain about
+ non-satisfaction as well as errors. */
+ if (check == error_mark_node)
+ return error_mark_node;
+
+ gcc_assert (concept_check_p (check));
+
+ subst_info info (tf_none, NULL_TREE);
+ tree result = satisfy_constraint_expression (check, NULL_TREE, info);
+ if (result == error_mark_node && (complain & tf_error))
+ {
+ location_t loc = cp_expr_loc_or_input_loc (check);
+ error_at (loc, "concept satisfaction failed");
+ info.complain = complain;
+ satisfy_constraint_expression (check, NULL_TREE, info);
+ }
+
+ return result;
+}
/*---------------------------------------------------------------------------
Semantic analysis of requires-expressions
@@ -2430,8 +2617,9 @@ constraint_expression_satisfied_p (tree expr, tree args)
/* Finish a requires expression for the given PARMS (possibly
null) and the non-empty sequence of requirements. */
+
tree
-finish_requires_expr (tree parms, tree reqs)
+finish_requires_expr (location_t loc, tree parms, tree reqs)
{
/* Modify the declared parameters by removing their context
so they don't refer to the enclosing scope and explicitly
@@ -2446,41 +2634,53 @@ finish_requires_expr (tree parms, tree reqs)
tree r = build_min (REQUIRES_EXPR, boolean_type_node, parms, reqs);
TREE_SIDE_EFFECTS (r) = false;
TREE_CONSTANT (r) = true;
+ SET_EXPR_LOCATION (r, loc);
return r;
}
-/* Construct a requirement for the validity of EXPR. */
+/* Construct a requirement for the validity of EXPR. */
+
tree
-finish_simple_requirement (tree expr)
+finish_simple_requirement (location_t loc, tree expr)
{
- return build_nt (SIMPLE_REQ, expr);
+ tree r = build_nt (SIMPLE_REQ, expr);
+ SET_EXPR_LOCATION (r, loc);
+ return r;
}
-/* Construct a requirement for the validity of TYPE. */
+/* Construct a requirement for the validity of TYPE. */
+
tree
-finish_type_requirement (tree type)
+finish_type_requirement (location_t loc, tree type)
{
- return build_nt (TYPE_REQ, type);
+ tree r = build_nt (TYPE_REQ, type);
+ SET_EXPR_LOCATION (r, loc);
+ return r;
}
/* Construct a requirement for the validity of EXPR, along with
its properties. if TYPE is non-null, then it specifies either
an implicit conversion or argument deduction constraint,
depending on whether any placeholders occur in the type name.
- NOEXCEPT_P is true iff the noexcept keyword was specified. */
+ NOEXCEPT_P is true iff the noexcept keyword was specified. */
+
tree
-finish_compound_requirement (tree expr, tree type, bool noexcept_p)
+finish_compound_requirement (location_t loc, tree expr, tree type, bool noexcept_p)
{
tree req = build_nt (COMPOUND_REQ, expr, type);
+ SET_EXPR_LOCATION (req, loc);
COMPOUND_REQ_NOEXCEPT_P (req) = noexcept_p;
return req;
}
-/* Finish a nested requirement. */
+/* Finish a nested requirement. */
+
tree
-finish_nested_requirement (tree expr)
+finish_nested_requirement (location_t loc, tree expr)
{
- return build_nt (NESTED_REQ, expr);
+ tree r = build_nt (NESTED_REQ, expr);
+ SET_EXPR_LOCATION (r, loc);
+ return r;
}
/* Check that FN satisfies the structural requirements of a
@@ -2500,7 +2700,7 @@ check_function_concept (tree fn)
if (TREE_CODE (body) == CLEANUP_POINT_EXPR)
body = TREE_OPERAND (body, 0);
- /* Check that the definition is written correctly. */
+ /* Check that the definition is written correctly. */
if (TREE_CODE (body) != RETURN_EXPR)
{
location_t loc = DECL_SOURCE_LOCATION (fn);
@@ -2580,108 +2780,93 @@ subsumes_constraints (tree a, tree b)
return subsumes (a, b);
}
-/* Returns true when the the constraints in A subsume those in B, but
- the constraints in B do not subsume the constraints in A. */
+/* Returns true when the the constraints in CI (with arguments
+ ARGS) strictly subsume the associated constraints of TMPL. */
bool
-strictly_subsumes (tree a, tree b)
+strictly_subsumes (tree ci, tree args, tree tmpl)
{
- return subsumes (a, b) && !subsumes (b, a);
+ tree n1 = get_normalized_constraints_from_info (ci, args, NULL_TREE);
+ tree n2 = get_normalized_constraints_from_decl (tmpl);
+
+ return subsumes (n1, n2) && !subsumes (n2, n1);
+}
+
+/* REturns true when the constraints in CI (with arguments ARGS) subsume
+ the associated constraints of TMPL. */
+
+bool
+weakly_subsumes (tree ci, tree args, tree tmpl)
+{
+ tree n1 = get_normalized_constraints_from_info (ci, args, NULL_TREE);
+ tree n2 = get_normalized_constraints_from_decl (tmpl);
+
+ return subsumes (n1, n2);
}
/* Determines which of the declarations, A or B, is more constrained.
That is, which declaration's constraints subsume but are not subsumed
by the other's?
- Returns 1 if A is more constrained than B, -1 if B is more constrained
- than A, and 0 otherwise. */
+ Returns 1 if D1 is more constrained than D2, -1 if D2 is more constrained
+ than D1, and 0 otherwise. */
int
more_constrained (tree d1, tree d2)
{
- tree c1 = get_constraints (d1);
- tree c2 = get_constraints (d2);
+ tree n1 = get_normalized_constraints_from_decl (d1);
+ tree n2 = get_normalized_constraints_from_decl (d2);
+
int winner = 0;
- if (subsumes_constraints (c1, c2))
+ if (subsumes (n1, n2))
++winner;
- if (subsumes_constraints (c2, c1))
+ if (subsumes (n2, n1))
--winner;
return winner;
}
-/* Returns true if D1 is at least as constrained as D2. That is, the
- associated constraints of D1 subsume those of D2, or both declarations
- are unconstrained. */
-
-bool
-at_least_as_constrained (tree d1, tree d2)
-{
- tree c1 = get_constraints (d1);
- tree c2 = get_constraints (d2);
- return subsumes_constraints (c1, c2);
-}
-
-
/*---------------------------------------------------------------------------
Constraint diagnostics
-
-FIXME: Normalize expressions into constraints before evaluating them.
-This should be the general pattern for all such diagnostics.
---------------------------------------------------------------------------*/
-/* The number of detailed constraint failures. */
-
-int constraint_errors = 0;
-
-/* Do not generate errors after diagnosing this number of constraint
- failures.
-
- FIXME: This is a really arbitrary number. Provide better control of
- constraint diagnostics with a command line option. */
-
-int constraint_thresh = 20;
-
-
-/* Returns true if we should elide the diagnostic for a constraint failure.
- This is the case when the number of errors has exceeded the pre-configured
- threshold. */
-
-inline bool
-elide_constraint_failure_p ()
-{
- bool ret = constraint_thresh <= constraint_errors;
- ++constraint_errors;
- return ret;
-}
-
-/* Returns the number of undiagnosed errors. */
-
-inline int
-undiagnosed_constraint_failures ()
-{
- return constraint_errors - constraint_thresh;
+/* Returns the best location to diagnose a constraint error. */
+
+static location_t
+get_constraint_error_location (tree t)
+{
+ /* If we have a specific location give it. */
+ tree expr = CONSTR_EXPR (t);
+ if (location_t loc = cp_expr_location (expr))
+ return loc;
+
+ /* If the constraint is normalized from a requires-clause, give
+ the location as that of the constrained declaration. */
+ tree cxt = CONSTR_CONTEXT (t);
+ tree src = TREE_VALUE (cxt);
+ if (!src)
+ /* TODO: This only happens for constrained non-template declarations. */
+ return input_location;
+ if (DECL_P (src))
+ return DECL_SOURCE_LOCATION (src);
+
+ /* Otherwise, give the location as the defining concept. */
+ gcc_assert (concept_check_p (src));
+ tree id = unpack_concept_check (src);
+ tree tmpl = TREE_OPERAND (id, 0);
+ if (OVL_P (tmpl))
+ tmpl = OVL_FIRST (tmpl);
+ return DECL_SOURCE_LOCATION (tmpl);
}
-/* The diagnosis of constraints performs a combination of normalization
- and satisfaction testing. We recursively walk through the conjunction or
- disjunction of associated constraints, testing each sub-constraint in
- turn. */
-
-namespace {
-
-void diagnose_constraint (location_t, tree, tree, tree);
-
-/* Emit a specific diagnostics for a failed trait. */
+/* Emit a diagnostic for a failed trait. */
void
-diagnose_trait_expression (location_t loc, tree, tree cur, tree args)
+diagnose_trait_expr (tree expr, tree args)
{
- if (constraint_expression_satisfied_p (cur, args))
- return;
- if (elide_constraint_failure_p())
- return;
+ location_t loc = cp_expr_location (expr);
- tree expr = PRED_CONSTR_EXPR (cur);
+ /* Build a "fake" version of the instantiated trait, so we can
+ get the instantiated types from result. */
++processing_template_decl;
expr = tsubst_expr (expr, args, tf_none, NULL_TREE, false);
--processing_template_decl;
@@ -2758,390 +2943,224 @@ diagnose_trait_expression (location_t loc, tree, tree cur, tree args)
}
}
-/* Diagnose the expression of a predicate constraint. */
-
-void
-diagnose_other_expression (location_t loc, tree, tree cur, tree args)
+static tree
+diagnose_valid_expression (tree expr, tree args, tree in_decl)
{
- if (constraint_expression_satisfied_p (cur, args))
- return;
- if (elide_constraint_failure_p())
- return;
- inform (loc, "%qE evaluated to false", cur);
-}
+ tree result = tsubst_expr (expr, args, tf_none, in_decl, false);
+ if (result != error_mark_node)
+ return result;
-/* Do our best to infer meaning from predicates. */
+ location_t loc = cp_expr_loc_or_input_loc (expr);
+ inform (loc, "the required expression %qE is invalid", expr);
-inline void
-diagnose_predicate_constraint (location_t loc, tree orig, tree cur, tree args)
-{
- if (TREE_CODE (PRED_CONSTR_EXPR (cur)) == TRAIT_EXPR)
- diagnose_trait_expression (loc, orig, cur, args);
- else
- diagnose_other_expression (loc, orig, cur, args);
-}
+ /* TODO: Replay the substitution to diagnose the error? */
+ // tsubst_expr (expr, args, tf_error, in_decl, false);
-/* Diagnose a failed pack expansion, possibly containing constraints. */
+ return error_mark_node;
+}
-void
-diagnose_pack_expansion (location_t loc, tree, tree cur, tree args)
+static tree
+diagnose_valid_type (tree type, tree args, tree in_decl)
{
- if (constraint_expression_satisfied_p (cur, args))
- return;
- if (elide_constraint_failure_p())
- return;
-
- /* Make sure that we don't have naked packs that we don't expect. */
- if (!same_type_p (TREE_TYPE (cur), boolean_type_node))
- {
- inform (loc, "invalid pack expansion in constraint %qE", cur);
- return;
- }
+ tree result = tsubst (type, args, tf_none, in_decl);
+ if (result != error_mark_node)
+ return result;
- inform (loc, "in the expansion of %qE", cur);
+ location_t loc = cp_expr_loc_or_input_loc (type);
+ inform (loc, "the required type %qT is invalid", type);
- /* Get the vector of expanded arguments. Note that n must not
- be 0 since this constraint is not satisfied. */
- ++processing_template_decl;
- tree exprs = tsubst_pack_expansion (cur, args, tf_none, NULL_TREE);
- --processing_template_decl;
- if (exprs == error_mark_node)
- {
- /* TODO: This error message could be better. */
- inform (loc, " substitution failure occurred during expansion");
- return;
- }
+ /* TODO: Replay the substitution to diagnose the error? */
+ // tsubst (type, args, tf_error, in_decl);
- /* Check each expanded constraint separately. */
- int n = TREE_VEC_LENGTH (exprs);
- for (int i = 0; i < n; ++i)
- {
- tree expr = TREE_VEC_ELT (exprs, i);
- if (!constraint_expression_satisfied_p (expr, args))
- inform (loc, " %qE was not satisfied", expr);
- }
+ return error_mark_node;
}
-/* Diagnose a potentially unsatisfied concept check constraint DECL<CARGS>.
- Parameters are as for diagnose_constraint. */
-
-void
-diagnose_check_constraint (location_t loc, tree orig, tree cur, tree args)
+static void
+diagnose_simple_requirement (tree req, tree args, tree in_decl)
{
- if (constraints_satisfied_p (cur, args))
- return;
-
- tree decl = CHECK_CONSTR_CONCEPT (cur);
- tree cargs = CHECK_CONSTR_ARGS (cur);
- tree tmpl = DECL_TI_TEMPLATE (decl);
- tree check = build_nt (CHECK_CONSTR, decl, cargs);
-
- /* Instantiate the concept check arguments. */
- tree targs = tsubst (cargs, args, tf_none, NULL_TREE);
- if (targs == error_mark_node)
- {
- if (elide_constraint_failure_p ())
- return;
- inform (loc, "invalid use of the concept %qE", check);
- tsubst (cargs, args, tf_warning_or_error, NULL_TREE);
- return;
- }
-
- tree sub = build_tree_list (tmpl, targs);
- /* Update to the expanded definitions. */
- cur = expand_concept (decl, targs);
- if (cur == error_mark_node)
- {
- if (elide_constraint_failure_p ())
- return;
- inform (loc, "in the expansion of concept %<%E %S%>", check, sub);
- cur = get_concept_definition (decl);
- tsubst_expr (cur, targs, tf_warning_or_error, NULL_TREE, false);
- return;
- }
-
- orig = get_concept_definition (CHECK_CONSTR_CONCEPT (orig));
- orig = normalize_expression (orig);
-
- location_t dloc = DECL_SOURCE_LOCATION (decl);
- inform (dloc, "within %qS", sub);
- diagnose_constraint (dloc, orig, cur, targs);
+ diagnose_valid_expression (TREE_OPERAND (req, 0), args, in_decl);
}
-/* Diagnose a potentially unsatisfied conjunction or disjunction. Parameters
- are as for diagnose_constraint. */
-
-void
-diagnose_logical_constraint (location_t loc, tree orig, tree cur, tree args)
+static void
+diagnose_compound_requirement (tree req, tree args, tree in_decl)
{
- tree t0 = TREE_OPERAND (cur, 0);
- tree t1 = TREE_OPERAND (cur, 1);
- if (!constraints_satisfied_p (t0, args))
- diagnose_constraint (loc, TREE_OPERAND (orig, 0), t0, args);
- else if (TREE_CODE (orig) == TRUTH_ORIF_EXPR)
+ tree expr = TREE_OPERAND (req, 0);
+ expr = diagnose_valid_expression (expr, args, in_decl);
+ if (expr == error_mark_node)
return;
- if (!constraints_satisfied_p (t1, args))
- diagnose_constraint (loc, TREE_OPERAND (orig, 1), t1, args);
-}
-/* Diagnose a potential expression constraint failure. */
+ location_t loc = cp_expr_loc_or_input_loc (expr);
-void
-diagnose_expression_constraint (location_t loc, tree orig, tree cur, tree args)
-{
- if (constraints_satisfied_p (cur, args))
- return;
- if (elide_constraint_failure_p())
+ /* Check the noexcept condition. */
+ if (COMPOUND_REQ_NOEXCEPT_P (req) && !expr_noexcept_p (expr, tf_none))
+ inform (loc, "%qE is not %<noexcept%>", expr);
+
+ tree type = TREE_OPERAND (req, 1);
+ type = diagnose_valid_type (type, args, in_decl);
+ if (type == error_mark_node)
return;
- tree expr = EXPR_CONSTR_EXPR (orig);
- inform (loc, "the required expression %qE would be ill-formed", expr);
+ if (type)
+ {
+ subst_info quiet (tf_none, in_decl);
+ subst_info noisy (tf_error, in_decl);
- // TODO: We should have a flag that controls this substitution.
- // I'm finding it very useful for resolving concept check errors.
+ /* Check the expression against the result type. */
+ if (tree placeholder = type_uses_auto (type))
+ {
+ if (!type_deducible_p (expr, type, placeholder, args, quiet))
+ {
+ tree orig_expr = TREE_OPERAND (req, 0);
+ inform (loc, "type deduction from %qE failed", orig_expr);
+
+ /* Further explain the reason for the error. */
+ type_deducible_p (expr, type, placeholder, args, noisy);
+ }
+ }
+ else if (!expression_convertible_p (expr, type, quiet))
+ {
+ tree orig_expr = TREE_OPERAND (req, 0);
+ inform (loc, "cannot convert %qE to %qT", orig_expr, type);
- // inform (input_location, "==== BEGIN DUMP ====");
- // tsubst_expr (EXPR_CONSTR_EXPR (orig), args, tf_warning_or_error, NULL_TREE, false);
- // inform (input_location, "==== END DUMP ====");
+ /* Further explain the reason for the error. */
+ expression_convertible_p (expr, type, noisy);
+ }
+ }
}
-/* Diagnose a potentially failed type constraint. */
-
-void
-diagnose_type_constraint (location_t loc, tree orig, tree cur, tree args)
+static void
+diagnose_type_requirement (tree req, tree args, tree in_decl)
{
- if (constraints_satisfied_p (cur, args))
- return;
- if (elide_constraint_failure_p())
- return;
-
- tree type = TYPE_CONSTR_TYPE (orig);
- inform (loc, "the required type %qT would be ill-formed", type);
+ tree type = TREE_OPERAND (req, 0);
+ diagnose_valid_type (type, args, in_decl);
}
-/* Diagnose a potentially unsatisfied conversion constraint. */
-
-void
-diagnose_implicit_conversion_constraint (location_t loc, tree orig, tree cur,
- tree args)
+static void
+diagnose_nested_requirement (tree req, tree args)
{
- if (constraints_satisfied_p (cur, args))
- return;
-
- /* The expression and type will previously have been substituted into,
- and therefore may already be an error. Also, we will have already
- diagnosed substitution failures into an expression since this must be
- part of a compound requirement. */
- tree expr = ICONV_CONSTR_EXPR (cur);
- if (error_operand_p (expr))
+ tree expr = TREE_OPERAND (req, 0);
+ if (constraints_satisfied_p (expr, args))
return;
+ location_t loc = cp_expr_location (expr);
+ inform (loc, "nested requirement %qE is not satisfied", expr);
- /* Don't elide a previously diagnosed failure. */
- if (elide_constraint_failure_p())
- return;
-
- tree type = ICONV_CONSTR_TYPE (cur);
- if (error_operand_p (type))
- {
- inform (loc, "substitution into type %qT failed",
- ICONV_CONSTR_TYPE (orig));
- return;
- }
-
- inform(loc, "%qE is not implicitly convertible to %qT", expr, type);
+ /* TODO: Replay the substitution to diagnose the error? */
+ // subst_info noisy (tf_warning_or_error, NULL_TREE);
+ // constraints_satisfied_p (expr, args, noisy);
}
-/* Diagnose an argument deduction constraint. */
-
-void
-diagnose_argument_deduction_constraint (location_t loc, tree orig, tree cur,
- tree args)
+static void
+diagnose_requirement (tree req, tree args, tree in_decl)
{
- if (constraints_satisfied_p (cur, args))
- return;
-
- /* The expression and type will previously have been substituted into,
- and therefore may already be an error. Also, we will have already
- diagnosed substution failures into an expression since this must be
- part of a compound requirement. */
- tree expr = DEDUCT_CONSTR_EXPR (cur);
- if (error_operand_p (expr))
- return;
-
- /* Don't elide a previously diagnosed failure. */
- if (elide_constraint_failure_p ())
- return;
-
- tree pattern = DEDUCT_CONSTR_PATTERN (cur);
- if (error_operand_p (pattern))
+ iloc_sentinel loc_s (cp_expr_location (req));
+ switch (TREE_CODE (req))
{
- inform (loc, "substitution into type %qT failed",
- DEDUCT_CONSTR_PATTERN (orig));
- return;
+ case SIMPLE_REQ:
+ return diagnose_simple_requirement (req, args, in_decl);
+ case COMPOUND_REQ:
+ return diagnose_compound_requirement (req, args, in_decl);
+ case TYPE_REQ:
+ return diagnose_type_requirement (req, args, in_decl);
+ case NESTED_REQ:
+ return diagnose_nested_requirement (req, args);
+ default:
+ gcc_unreachable ();
}
-
- inform (loc, "unable to deduce placeholder type %qT from %qE",
- pattern, expr);
}
-/* Diagnose an exception constraint. */
-
-void
-diagnose_exception_constraint (location_t loc, tree orig, tree cur, tree args)
+static void
+diagnose_requires_expr (tree expr, tree args, tree in_decl)
{
- if (constraints_satisfied_p (cur, args))
- return;
- if (elide_constraint_failure_p ())
- return;
+ local_specialization_stack stack (lss_copy);
+ tree parms = TREE_OPERAND (expr, 0);
+ tree body = TREE_OPERAND (expr, 1);
- /* Rebuild a noexcept expression. */
- tree expr = EXCEPT_CONSTR_EXPR (cur);
- if (error_operand_p (expr))
+ cp_unevaluated u;
+ subst_info info (tf_warning_or_error, NULL_TREE);
+ tree vars = tsubst_constraint_variables (parms, args, info);
+ if (vars == error_mark_node)
return;
- inform (loc, "%qE evaluated to false", EXCEPT_CONSTR_EXPR (orig));
+ tree p = body;
+ while (p)
+ {
+ tree req = TREE_VALUE (p);
+ diagnose_requirement (req, args, in_decl);
+ p = TREE_CHAIN (p);
+ }
}
-/* Diagnose a potentially unsatisfied parameterized constraint. */
+/* Diagnose a substitution failure in the atomic constraint T. Note that
+ ARGS have been previously instantiated through the parameter map. */
-void
-diagnose_parameterized_constraint (location_t loc, tree orig, tree cur,
- tree args)
+static void
+diagnose_atomic_constraint (tree t, tree args, subst_info info)
{
- if (constraints_satisfied_p (cur, args))
- return;
-
- local_specialization_stack stack;
- tree parms = PARM_CONSTR_PARMS (cur);
- tree vars = tsubst_constraint_variables (parms, args, tf_warning_or_error,
- NULL_TREE);
- if (vars == error_mark_node)
+ /* If the constraint is already ill-formed, we've previously diagnosed
+ the reason. We should still say why the constraints aren't satisfied. */
+ if (t == error_mark_node)
{
- if (elide_constraint_failure_p ())
- return;
-
- /* TODO: Check which variable failed and use orig to diagnose
- that substitution error. */
- inform (loc, "failed to instantiate constraint variables");
+ location_t loc;
+ if (info.in_decl)
+ loc = DECL_SOURCE_LOCATION (info.in_decl);
+ else
+ loc = input_location;
+ inform (loc, "invalid constraints");
return;
}
- /* TODO: It would be better write these in a list. */
- while (vars)
- {
- inform (loc, " with %q#D", vars);
- vars = TREE_CHAIN (vars);
- }
- orig = PARM_CONSTR_OPERAND (orig);
- cur = PARM_CONSTR_OPERAND (cur);
- return diagnose_constraint (loc, orig, cur, args);
-}
+ location_t loc = get_constraint_error_location (t);
+ iloc_sentinel loc_s (loc);
-/* Diagnose the constraint CUR for the given ARGS. This is only ever invoked
- on the associated constraints, so we can only have conjunctions of
- predicate constraints. The ORIGinal (dependent) constructs follow
- the current constraints to enable better diagnostics. Note that ORIG
- and CUR must be the same kinds of node, except when CUR is an error. */
-
-void
-diagnose_constraint (location_t loc, tree orig, tree cur, tree args)
-{
- switch (TREE_CODE (cur))
+ /* Generate better diagnostics for certain kinds of expressions. */
+ tree expr = ATOMIC_CONSTR_EXPR (t);
+ STRIP_ANY_LOCATION_WRAPPER (expr);
+ switch (TREE_CODE (expr))
{
- case EXPR_CONSTR:
- diagnose_expression_constraint (loc, orig, cur, args);
- break;
-
- case TYPE_CONSTR:
- diagnose_type_constraint (loc, orig, cur, args);
- break;
-
- case ICONV_CONSTR:
- diagnose_implicit_conversion_constraint (loc, orig, cur, args);
- break;
-
- case DEDUCT_CONSTR:
- diagnose_argument_deduction_constraint (loc, orig, cur, args);
- break;
-
- case EXCEPT_CONSTR:
- diagnose_exception_constraint (loc, orig, cur, args);
- break;
-
- case CONJ_CONSTR:
- case DISJ_CONSTR:
- diagnose_logical_constraint (loc, orig, cur, args);
- break;
-
- case PRED_CONSTR:
- diagnose_predicate_constraint (loc, orig, cur, args);
- break;
-
- case PARM_CONSTR:
- diagnose_parameterized_constraint (loc, orig, cur, args);
- break;
-
- case CHECK_CONSTR:
- diagnose_check_constraint (loc, orig, cur, args);
+ case TRAIT_EXPR:
+ diagnose_trait_expr (expr, args);
break;
-
- case EXPR_PACK_EXPANSION:
- diagnose_pack_expansion (loc, orig, cur, args);
+ case REQUIRES_EXPR:
+ diagnose_requires_expr (expr, args, info.in_decl);
break;
-
- case ERROR_MARK:
- /* TODO: Can we improve the diagnostic with the original? */
- inform (input_location, "ill-formed constraint");
+ case INTEGER_CST:
+ /* This must be either 0 or false. */
+ inform (loc, "%qE is never satisfied", expr);
break;
-
default:
- gcc_unreachable ();
- break;
+ inform (loc, "the expression %qE evaluated to %<false%>", expr);
}
}
-/* Diagnose the reason(s) why ARGS do not satisfy the constraints
- of declaration DECL. */
-
-void
-diagnose_declaration_constraints (location_t loc, tree decl, tree args)
+diagnosing_failed_constraint::
+diagnosing_failed_constraint (tree t, tree args, bool diag)
+ : diagnosing_error (diag)
{
- inform (loc, " constraints not satisfied");
-
- /* Constraints are attached to the template. */
- if (tree ti = DECL_TEMPLATE_INFO (decl))
- {
- decl = TI_TEMPLATE (ti);
- if (!args)
- args = TI_ARGS (ti);
- }
-
- /* Recursively diagnose the associated constraints. */
- tree ci = get_constraints (decl);
- tree t = CI_ASSOCIATED_CONSTRAINTS (ci);
- diagnose_constraint (loc, t, t, args);
+ if (diagnosing_error)
+ current_failed_constraint = tree_cons (args, t, current_failed_constraint);
}
-} // namespace
+diagnosing_failed_constraint::
+~diagnosing_failed_constraint ()
+{
+ if (diagnosing_error && current_failed_constraint)
+ current_failed_constraint = TREE_CHAIN (current_failed_constraint);
+}
-/* Emit diagnostics detailing the failure ARGS to satisfy the
- constraints of T. Here, T can be either a constraint
- or a declaration. */
+/* Emit diagnostics detailing the failure ARGS to satisfy the constraints
+ of T. Here, T can be either a constraint or a declaration. */
void
diagnose_constraints (location_t loc, tree t, tree args)
{
- constraint_errors = 0;
+ inform (loc, "constraints not satisfied");
- if (constraint_p (t))
- diagnose_constraint (loc, t, t, args);
- else if (DECL_P (t))
- diagnose_declaration_constraints (loc, t, args);
+ /* Replay satisfaction, but diagnose errors. */
+ subst_info info (tf_warning_or_error, NULL_TREE);
+ if (!args)
+ constraints_satisfied_p (t, info);
else
- gcc_unreachable ();
-
- /* Note the number of elided failures. */
- int n = undiagnosed_constraint_failures ();
- if (n > 0)
- inform (loc, "... and %d more constraint errors not shown", n);
+ constraints_satisfied_p (t, args, info);
}
+
+#include "gt-cp-constraint.h"
diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
index 65453929d31..154fa70ec06 100644
--- a/gcc/cp/cp-gimplify.c
+++ b/gcc/cp/cp-gimplify.c
@@ -638,6 +638,22 @@ lvalue_has_side_effects (tree e)
return TREE_SIDE_EFFECTS (e);
}
+/* Gimplify *EXPR_P as rvalue into an expression that can't be modified
+ by expressions with side-effects in other operands. */
+
+static enum gimplify_status
+gimplify_to_rvalue (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
+ bool (*gimple_test_f) (tree))
+{
+ enum gimplify_status t
+ = gimplify_expr (expr_p, pre_p, post_p, gimple_test_f, fb_rvalue);
+ if (t == GS_ERROR)
+ return GS_ERROR;
+ else if (is_gimple_variable (*expr_p) && TREE_CODE (*expr_p) != SSA_NAME)
+ *expr_p = get_initialized_tmp_var (*expr_p, pre_p, NULL);
+ return t;
+}
+
/* Do C++-specific gimplification. Args are as for gimplify_expr. */
int
@@ -823,15 +839,10 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
&& cp_get_callee_fndecl_nofold (*expr_p) == NULL_TREE)
{
enum gimplify_status t
- = gimplify_expr (&CALL_EXPR_FN (*expr_p), pre_p, NULL,
- is_gimple_call_addr, fb_rvalue);
+ = gimplify_to_rvalue (&CALL_EXPR_FN (*expr_p), pre_p, NULL,
+ is_gimple_call_addr);
if (t == GS_ERROR)
ret = GS_ERROR;
- else if (is_gimple_variable (CALL_EXPR_FN (*expr_p))
- && TREE_CODE (CALL_EXPR_FN (*expr_p)) != SSA_NAME)
- CALL_EXPR_FN (*expr_p)
- = get_initialized_tmp_var (CALL_EXPR_FN (*expr_p), pre_p,
- NULL);
}
if (!CALL_EXPR_FN (*expr_p))
/* Internal function call. */;
diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c
index ac6a904cffb..a3ce574818c 100644
--- a/gcc/cp/cp-objcp-common.c
+++ b/gcc/cp/cp-objcp-common.c
@@ -381,6 +381,7 @@ cp_common_init_ts (void)
/* New decls. */
MARK_TS_DECL_COMMON (TEMPLATE_DECL);
MARK_TS_DECL_COMMON (WILDCARD_DECL);
+ MARK_TS_DECL_COMMON (CONCEPT_DECL);
MARK_TS_DECL_NON_COMMON (USING_DECL);
@@ -458,17 +459,11 @@ cp_common_init_ts (void)
MARK_TS_EXP (CHECK_CONSTR);
MARK_TS_EXP (COMPOUND_REQ);
MARK_TS_EXP (CONJ_CONSTR);
- MARK_TS_EXP (DEDUCT_CONSTR);
MARK_TS_EXP (DISJ_CONSTR);
- MARK_TS_EXP (EXCEPT_CONSTR);
- MARK_TS_EXP (EXPR_CONSTR);
- MARK_TS_EXP (ICONV_CONSTR);
+ MARK_TS_EXP (ATOMIC_CONSTR);
MARK_TS_EXP (NESTED_REQ);
- MARK_TS_EXP (PARM_CONSTR);
- MARK_TS_EXP (PRED_CONSTR);
MARK_TS_EXP (REQUIRES_EXPR);
MARK_TS_EXP (SIMPLE_REQ);
- MARK_TS_EXP (TYPE_CONSTR);
MARK_TS_EXP (TYPE_REQ);
MARK_TS_EXP (CO_AWAIT_EXPR);
diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
index 61e491b4ac1..c61815d770b 100644
--- a/gcc/cp/cp-tree.def
+++ b/gcc/cp/cp-tree.def
@@ -507,6 +507,11 @@ DEFTREECODE (OMP_DEPOBJ, "omp_depobj", tcc_statement, 2)
/* Extensions for Concepts. */
+/* Concept definition. This is not entirely different than a VAR_DECL
+ except that a) it must be a template, and b) doesn't have the wide
+ range of value and linkage options available to variables. */
+DEFTREECODE (CONCEPT_DECL, "concept_decl", tcc_declaration, 0)
+
/* Used to represent information associated with constrained declarations. */
DEFTREECODE (CONSTRAINT_INFO, "constraint_info", tcc_exceptional, 0)
@@ -541,10 +546,24 @@ DEFTREECODE (NESTED_REQ, "nested_req", tcc_expression, 1)
The operands of a constraint can be either types or expressions.
Unlike expressions, constraints do not have a type. */
-/* A predicate constraint evaluates an expression E.
+/* An atomic constraint evaluates an expression E. The operand of the
+ constraint is its parameter mapping. The actual expression is stored
+ in the context.
+
+ ATOMIC_CONSTR_INFO provides source info to support diagnostics.
+ ATOMIC_CONSTR_EXPR has the expression to be evaluated.
+ ATOMIC_CONSTR_PARMS is the parameter mapping for the atomic constraint
+ and is stored in the type field. */
+DEFTREECODE (ATOMIC_CONSTR, "atomic_constr", tcc_expression, 1)
+
+/* The conjunction and disjunction of two constraints, respectively.
+ Operands are accessed using TREE_OPERAND. The third operand provides
+ source info for diagnostics.
- PRED_CONSTR_EXPR has the expression to be evaluated. */
-DEFTREECODE (PRED_CONSTR, "pred_constr", tcc_expression, 1)
+ CONJ_CONSTR_INFO and DISJ_CONSTR_INFO provide access to the source
+ information of constraints, which is stored in the TREE_TYPE. */
+DEFTREECODE (CONJ_CONSTR, "conj_constr", tcc_expression, 2)
+DEFTREECODE (DISJ_CONSTR, "disj_constr", tcc_expression, 2)
/* A check constraint represents the checking of a concept
C. It has two operands: the template defining the concept
@@ -554,52 +573,6 @@ DEFTREECODE (PRED_CONSTR, "pred_constr", tcc_expression, 1)
CHECK_CONSTR_ARGUMENTS are the template arguments */
DEFTREECODE (CHECK_CONSTR, "check_constr", tcc_expression, 2)
-/* An expression constraint determines the validity of a expression E.
-
- EXPR_CONST_EXPR has the expression being validated. */
-DEFTREECODE (EXPR_CONSTR, "expr_constr", tcc_expression, 1)
-
-/* A type constraint determines the validity of a type T. Note that
-
- TYPE_CONST_TYPE has the type being validated */
-DEFTREECODE (TYPE_CONSTR, "type_constr", tcc_expression, 1)
-
-/* An implicit conversion constraint determines if an expression
- E is implicitly convertible to a type T. Note that T may
- be dependent but does not contain any placeholders.
-
- ICONV_CONSTR_EXPR has the expression E.
- ICONV_CONSTR_TYPE has the type T.
- */
-DEFTREECODE (ICONV_CONSTR, "iconv_constr", tcc_expression, 2)
-
-/* An argument deduction constraint determines if the type of an
- expression E can be deduced from a type pattern T. Note that
- T must contain at least one place holder.
-
- DEDUCT_CONSTR_EXPR has the expression E
- DEDUCT_CONSTR_PATTERN has the type pattern T.
- DEDUCT_CONSTR_PLACEHOLDERS has the list of placeholder nodes in T. */
-DEFTREECODE (DEDUCT_CONSTR, "deduct_constr", tcc_expression, 3)
-
-/* An exception constraint determines if, for an expression E,
- noexcept(E) is true.
-
- EXCEPT_CONSTR_EXPR has the expression E. */
-DEFTREECODE (EXCEPT_CONSTR, "except_constr", tcc_expression, 1)
-
-/* A parameterized constraint declares constraint variables, which
- are used in expression, type, and exception constraints.
-
- PARM_CONSTR_PARMS has a TREE_LIST of parameter declarations.
- PARM_CONSTR_OPERAND has the nested constraint. */
-DEFTREECODE (PARM_CONSTR, "parm_constr", tcc_expression, 2)
-
-/* The conjunction and disjunction of two constraints, respectively.
- Operands are accessed using TREE_OPERAND. */
-DEFTREECODE (CONJ_CONSTR, "conj_constr", tcc_expression, 2)
-DEFTREECODE (DISJ_CONSTR, "disj_constr", tcc_expression, 2)
-
/* The co_await expression is used to support coroutines.
Op 0 is the cast expresssion (potentially modified by the
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index e074b6a2feb..8926d2e4e12 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -593,15 +593,46 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
TREE_CHECK(NODE,BOUND_TEMPLATE_TEMPLATE_PARM)
#if defined ENABLE_TREE_CHECKING && (GCC_VERSION >= 2007)
+
+/* Returns t iff the node can have a TEMPLATE_INFO field. */
+
+inline tree
+template_info_decl_check (const_tree t, const char* f, int l, const char* fn)
+{
+ switch (TREE_CODE (t))
+ {
+ case VAR_DECL:
+ case FUNCTION_DECL:
+ case FIELD_DECL:
+ case TYPE_DECL:
+ case CONCEPT_DECL:
+ case TEMPLATE_DECL:
+ return const_cast<tree>(t);
+ default:
+ break;
+ }
+ tree_check_failed (t, f, l, fn,
+ VAR_DECL, FUNCTION_DECL, FIELD_DECL, TYPE_DECL,
+ CONCEPT_DECL, TEMPLATE_DECL, 0);
+ gcc_unreachable ();
+}
+
+#define TEMPLATE_INFO_DECL_CHECK(NODE) \
+ template_info_decl_check ((NODE), __FILE__, __LINE__, __FUNCTION__)
+
#define THUNK_FUNCTION_CHECK(NODE) __extension__ \
({ __typeof (NODE) const __t = (NODE); \
if (TREE_CODE (__t) != FUNCTION_DECL || !__t->decl_common.lang_specific \
|| !__t->decl_common.lang_specific->u.fn.thunk_p) \
tree_check_failed (__t, __FILE__, __LINE__, __FUNCTION__, 0); \
__t; })
-#else
+
+#else /* ENABLE_TREE_CHECKING */
+
+#define TEMPLATE_INFO_DECL_CHECK(NODE) (NODE)
#define THUNK_FUNCTION_CHECK(NODE) (NODE)
-#endif
+
+#endif /* ENABLE_TREE_CHECKING */
/* Language-dependent contents of an identifier. */
@@ -1522,57 +1553,45 @@ check_constraint_info (tree t)
#define PLACEHOLDER_TYPE_CONSTRAINTS(NODE) \
DECL_SIZE_UNIT (TYPE_NAME (NODE))
-/* The expression evaluated by the predicate constraint. */
-#define PRED_CONSTR_EXPR(NODE) \
- TREE_OPERAND (TREE_CHECK (NODE, PRED_CONSTR), 0)
+/* Valid for any normalized constraint. */
+#define CONSTR_CHECK(NODE) \
+ TREE_CHECK3 (NODE, ATOMIC_CONSTR, CONJ_CONSTR, DISJ_CONSTR)
-/* The concept of a concept check. */
-#define CHECK_CONSTR_CONCEPT(NODE) \
- TREE_OPERAND (TREE_CHECK (NODE, CHECK_CONSTR), 0)
+/* The CONSTR_INFO stores normalization data for a constraint. It refers to
+ the original expression and the expression or declaration
+ from which the constraint was normalized.
-/* The template arguments of a concept check. */
-#define CHECK_CONSTR_ARGS(NODE) \
- TREE_OPERAND (TREE_CHECK (NODE, CHECK_CONSTR), 1)
-
-/* The expression validated by the predicate constraint. */
-#define EXPR_CONSTR_EXPR(NODE) \
- TREE_OPERAND (TREE_CHECK (NODE, EXPR_CONSTR), 0)
-
-/* The type validated by the predicate constraint. */
-#define TYPE_CONSTR_TYPE(NODE) \
- TREE_OPERAND (TREE_CHECK (NODE, TYPE_CONSTR), 0)
+ This is TREE_LIST whose TREE_PURPOSE is the original expression and whose
+ TREE_VALUE is a list of contexts. */
+#define CONSTR_INFO(NODE) \
+ TREE_TYPE (CONSTR_CHECK (NODE))
-/* In an implicit conversion constraint, the source expression. */
-#define ICONV_CONSTR_EXPR(NODE) \
- TREE_OPERAND (TREE_CHECK (NODE, ICONV_CONSTR), 0)
+/* The expression evaluated by the constraint. */
+#define CONSTR_EXPR(NODE) \
+ TREE_PURPOSE (CONSTR_INFO (NODE))
-/* In an implicit conversion constraint, the target type. */
-#define ICONV_CONSTR_TYPE(NODE) \
- TREE_OPERAND (TREE_CHECK (NODE, ICONV_CONSTR), 1)
+/* The expression or declaration from which this constraint was normalized.
+ This is a TREE_LIST whose TREE_VALUE is either a template-id expression
+ denoting a concept check or the declaration introducing the constraint.
+ These are chained to other context objects. */
+#define CONSTR_CONTEXT(NODE) \
+ TREE_VALUE (CONSTR_INFO (NODE))
-/* In an argument deduction constraint, the source expression. */
-#define DEDUCT_CONSTR_EXPR(NODE) \
- TREE_OPERAND (TREE_CHECK (NODE, DEDUCT_CONSTR), 0)
+/* The parameter mapping for an atomic constraint. */
+#define ATOMIC_CONSTR_MAP(NODE) \
+ TREE_OPERAND (TREE_CHECK (NODE, ATOMIC_CONSTR), 0)
-/* In an argument deduction constraint, the target type pattern. */
-#define DEDUCT_CONSTR_PATTERN(NODE) \
- TREE_OPERAND (TREE_CHECK (NODE, DEDUCT_CONSTR), 1)
+/* The expression of an atomic constraint. */
+#define ATOMIC_CONSTR_EXPR(NODE) \
+ CONSTR_EXPR (ATOMIC_CONSTR_CHECK (NODE))
-/* In an argument deduction constraint, the list of placeholder nodes. */
-#define DEDUCT_CONSTR_PLACEHOLDER(NODE) \
- TREE_OPERAND (TREE_CHECK (NODE, DEDUCT_CONSTR), 2)
-
-/* The expression of an exception constraint. */
-#define EXCEPT_CONSTR_EXPR(NODE) \
- TREE_OPERAND (TREE_CHECK (NODE, EXCEPT_CONSTR), 0)
-
-/* In a parameterized constraint, the local parameters. */
-#define PARM_CONSTR_PARMS(NODE) \
- TREE_OPERAND (TREE_CHECK (NODE, PARM_CONSTR), 0)
+/* The concept of a concept check. */
+#define CHECK_CONSTR_CONCEPT(NODE) \
+ TREE_OPERAND (TREE_CHECK (NODE, CHECK_CONSTR), 0)
-/* In a parameterized constraint, the operand. */
-#define PARM_CONSTR_OPERAND(NODE) \
- TREE_OPERAND (TREE_CHECK (NODE, PARM_CONSTR), 1)
+/* The template arguments of a concept check. */
+#define CHECK_CONSTR_ARGS(NODE) \
+ TREE_OPERAND (TREE_CHECK (NODE, CHECK_CONSTR), 1)
/* Whether a PARM_DECL represents a local parameter in a
requires-expression. */
@@ -1663,6 +1682,7 @@ struct GTY(()) saved_scope {
int x_processing_template_decl;
int x_processing_specialization;
+ int x_processing_constraint;
int suppress_location_wrappers;
BOOL_BITFIELD x_processing_explicit_instantiation : 1;
BOOL_BITFIELD need_pop_function_context : 1;
@@ -2627,7 +2647,8 @@ struct GTY(()) lang_decl_base {
|| TREE_CODE (NODE) == CONST_DECL \
|| TREE_CODE (NODE) == TYPE_DECL \
|| TREE_CODE (NODE) == TEMPLATE_DECL \
- || TREE_CODE (NODE) == USING_DECL)
+ || TREE_CODE (NODE) == USING_DECL \
+ || TREE_CODE (NODE) == CONCEPT_DECL)
/* DECL_LANG_SPECIFIC for the above codes. */
@@ -3384,8 +3405,8 @@ struct GTY(()) lang_decl {
&& TREE_CODE (TYPE_NAME (NODE)) == TYPE_DECL \
&& TYPE_DECL_ALIAS_P (TYPE_NAME (NODE)))
-/* If non-NULL for a VAR_DECL, FUNCTION_DECL, TYPE_DECL or
- TEMPLATE_DECL, the entity is either a template specialization (if
+/* If non-NULL for a VAR_DECL, FUNCTION_DECL, TYPE_DECL, TEMPLATE_DECL,
+ or CONCEPT_DECL, the entity is either a template specialization (if
DECL_USE_TEMPLATE is nonzero) or the abstract instance of the
template itself.
@@ -3404,7 +3425,7 @@ struct GTY(()) lang_decl {
global function f. In this case, DECL_TEMPLATE_INFO for S<int>::f
will be non-NULL, but DECL_USE_TEMPLATE will be zero. */
#define DECL_TEMPLATE_INFO(NODE) \
- (DECL_LANG_SPECIFIC (VAR_TEMPL_TYPE_FIELD_OR_FUNCTION_DECL_CHECK (NODE)) \
+ (DECL_LANG_SPECIFIC (TEMPLATE_INFO_DECL_CHECK (NODE)) \
->u.min.template_info)
/* For a lambda capture proxy, its captured variable. */
@@ -5264,6 +5285,8 @@ enum tsubst_flags {
declaration. */
tf_no_cleanup = 1 << 10, /* Do not build a cleanup
(build_target_expr and friends) */
+ tf_norm = 1 << 11, /* Build diagnostic information during
+ constraint normalization. */
/* Convenient substitution flags combinations. */
tf_warning_or_error = tf_warning | tf_error
};
@@ -6163,43 +6186,6 @@ class_of_this_parm (const_tree fntype)
return TREE_TYPE (type_of_this_parm (fntype));
}
-/* True iff T is a variable template declaration. */
-inline bool
-variable_template_p (tree t)
-{
- if (TREE_CODE (t) != TEMPLATE_DECL)
- return false;
- if (!PRIMARY_TEMPLATE_P (t))
- return false;
- if (tree r = DECL_TEMPLATE_RESULT (t))
- return VAR_P (r);
- return false;
-}
-
-/* True iff T is a variable concept definition. That is, T is
- a variable template declared with the concept specifier. */
-inline bool
-variable_concept_p (tree t)
-{
- if (TREE_CODE (t) != TEMPLATE_DECL)
- return false;
- if (tree r = DECL_TEMPLATE_RESULT (t))
- return VAR_P (r) && DECL_DECLARED_CONCEPT_P (r);
- return false;
-}
-
-/* True iff T is a concept definition. That is, T is a variable or function
- template declared with the concept specifier. */
-inline bool
-concept_template_p (tree t)
-{
- if (TREE_CODE (t) != TEMPLATE_DECL)
- return false;
- if (tree r = DECL_TEMPLATE_RESULT (t))
- return VAR_OR_FUNCTION_DECL_P (r) && DECL_DECLARED_CONCEPT_P (r);
- return false;
-}
-
/* A parameter list indicating for a function with no parameters,
e.g "int f(void)". */
extern cp_parameter_declarator *no_parameters;
@@ -6656,6 +6642,9 @@ extern void finish_eh_spec_block (tree, tree);
extern tree build_eh_type_type (tree);
extern tree cp_protect_cleanup_actions (void);
extern tree create_try_catch_expr (tree, tree);
+extern tree template_parms_to_args (tree);
+extern tree template_parms_level_to_args (tree);
+extern tree generic_targs_for (tree);
/* in expr.c */
extern tree cplus_expand_constant (tree);
@@ -6789,6 +6778,8 @@ extern void maybe_show_extern_c_location (void);
extern bool literal_integer_zerop (const_tree);
/* in pt.c */
+extern void push_access_scope (tree);
+extern void pop_access_scope (tree);
extern bool check_template_shadow (tree);
extern bool check_auto_in_tmpl_args (tree, tree);
extern tree get_innermost_template_args (tree, int);
@@ -6808,6 +6799,8 @@ extern int num_template_headers_for_class (tree);
extern void check_template_variable (tree);
extern tree make_auto (void);
extern tree make_decltype_auto (void);
+extern tree make_constrained_auto (tree, tree);
+extern tree make_constrained_decltype_auto (tree, tree);
extern tree make_template_placeholder (tree);
extern bool template_placeholder_p (tree);
extern tree do_auto_deduction (tree, tree, tree,
@@ -6834,6 +6827,7 @@ extern bool check_default_tmpl_args (tree, tree, bool, bool, int);
extern tree push_template_decl (tree);
extern tree push_template_decl_real (tree, bool);
extern tree add_inherited_template_parms (tree, tree);
+extern void template_parm_level_and_index (tree, int*, int*);
extern bool redeclare_class_template (tree, tree, tree);
extern tree lookup_template_class (tree, tree, tree, tree,
int, tsubst_flags_t);
@@ -6858,6 +6852,7 @@ extern bool always_instantiate_p (tree);
extern bool maybe_instantiate_noexcept (tree, tsubst_flags_t = tf_warning_or_error);
extern tree instantiate_decl (tree, bool, bool);
extern int comp_template_parms (const_tree, const_tree);
+extern bool template_heads_equivalent_p (const_tree, const_tree);
extern bool builtin_pack_fn_p (tree);
extern tree uses_parameter_packs (tree);
extern bool template_parameter_pack_p (const_tree);
@@ -6886,7 +6881,11 @@ extern tree tsubst_copy_and_build (tree, tree, tsubst_flags_t,
tree, bool, bool);
extern tree tsubst_expr (tree, tree, tsubst_flags_t,
tree, bool);
-extern tree tsubst_pack_expansion (tree, tree, tsubst_flags_t, tree);
+extern tree tsubst_pack_expansion (tree, tree, tsubst_flags_t, tree);
+extern tree tsubst_argument_pack (tree, tree, tsubst_flags_t, tree);
+extern tree tsubst_template_args (tree, tree, tsubst_flags_t, tree);
+extern tree tsubst_template_arg (tree, tree, tsubst_flags_t, tree);
+extern tree tsubst_function_parms (tree, tree, tsubst_flags_t, tree);
extern tree most_general_template (tree);
extern tree get_mostly_instantiated_function_type (tree);
extern bool problematic_instantiation_changed (void);
@@ -6955,6 +6954,7 @@ extern bool deduction_guide_p (const_tree);
extern bool copy_guide_p (const_tree);
extern bool template_guide_p (const_tree);
extern void store_explicit_specifier (tree, tree);
+extern tree add_outermost_template_args (tree, tree);
/* in rtti.c */
/* A vector of all tinfo decls that haven't been emitted yet. */
@@ -7119,7 +7119,9 @@ extern tree finish_asm_stmt (location_t, int, tree, tree,
extern tree finish_label_stmt (tree);
extern void finish_label_decl (tree);
extern cp_expr finish_parenthesized_expr (cp_expr);
-extern tree force_paren_expr (tree);
+extern tree force_paren_expr (tree, bool = false);
+inline tree force_paren_expr_uneval (tree t)
+{ return force_paren_expr (t, true); }
extern tree maybe_undo_parenthesized_ref (tree);
extern tree maybe_strip_ref_conversion (tree);
extern tree finish_non_static_data_member (tree, tree, tree);
@@ -7416,6 +7418,10 @@ extern void cxx_print_error_function (diagnostic_context *,
struct diagnostic_info *);
/* in typeck.c */
+/* Says how we should behave when comparing two arrays one of which
+ has unknown bounds. */
+enum compare_bounds_t { bounds_none, bounds_either, bounds_first };
+
extern bool cxx_mark_addressable (tree, bool = false);
extern int string_conv_p (const_tree, const_tree, int);
extern tree cp_truthvalue_conversion (tree);
@@ -7506,7 +7512,7 @@ extern tree convert_for_initialization (tree, tree, tree, int,
impl_conv_rhs, tree, int,
tsubst_flags_t);
extern int comp_ptr_ttypes (tree, tree);
-extern bool comp_ptr_ttypes_const (tree, tree);
+extern bool comp_ptr_ttypes_const (tree, tree, compare_bounds_t);
extern bool error_type_p (const_tree);
extern bool ptr_reasonably_similar (const_tree, const_tree);
extern tree build_ptrmemfunc (tree, tree, int, bool,
@@ -7703,69 +7709,97 @@ typedef void cp_binding_oracle_function (enum cp_oracle_request, tree identifier
extern cp_binding_oracle_function *cp_binding_oracle;
+/* Set during diagnostics to record the failed constraint. This is a
+ TREE_LIST whose VALUE is the constraint and whose PURPOSE are the
+ instantiation arguments Defined in pt.c. */
+
+extern tree current_failed_constraint;
+
+/* An RAII class to manage the failed constraint. */
+
+struct diagnosing_failed_constraint
+{
+ diagnosing_failed_constraint (tree, tree, bool);
+ ~diagnosing_failed_constraint ();
+
+ bool diagnosing_error;
+};
+
/* in constraint.cc */
-extern void init_constraint_processing ();
-extern bool constraint_p (tree);
-extern tree conjoin_constraints (tree, tree);
-extern tree conjoin_constraints (tree);
+
+extern void init_constraint_processing ();
+extern cp_expr finish_constraint_or_expr (location_t, cp_expr, cp_expr);
+extern cp_expr finish_constraint_and_expr (location_t, cp_expr, cp_expr);
+extern cp_expr finish_constraint_primary_expr (cp_expr);
+extern tree finish_concept_definition (cp_expr, tree);
+extern tree combine_constraint_expressions (tree, tree);
extern tree get_constraints (tree);
extern void set_constraints (tree, tree);
extern void remove_constraints (tree);
extern tree current_template_constraints (void);
extern tree associate_classtype_constraints (tree);
extern tree build_constraints (tree, tree);
+extern tree get_template_head_requirements (tree);
+extern tree get_trailing_function_requirements (tree);
extern tree get_shorthand_constraints (tree);
-extern tree build_concept_check (tree, tree, tree = NULL_TREE);
+
+extern tree build_concept_id (tree);
+extern tree build_type_constraint (tree, tree, tsubst_flags_t);
+extern tree build_concept_check (tree, tree, tsubst_flags_t);
+extern tree build_concept_check (tree, tree, tree, tsubst_flags_t);
+
+extern tree_pair finish_type_constraints (tree, tree, tsubst_flags_t);
extern tree build_constrained_parameter (tree, tree, tree = NULL_TREE);
-extern tree make_constrained_auto (tree, tree);
extern void placeholder_extract_concept_and_args (tree, tree&, tree&);
extern bool equivalent_placeholder_constraints (tree, tree);
extern hashval_t hash_placeholder_constraint (tree);
extern bool deduce_constrained_parameter (tree, tree&, tree&);
extern tree resolve_constraint_check (tree);
extern tree check_function_concept (tree);
-extern tree finish_template_introduction (tree, tree);
+extern tree finish_template_introduction (tree, tree, location_t loc);
extern bool valid_requirements_p (tree);
extern tree finish_concept_name (tree);
extern tree finish_shorthand_constraint (tree, tree);
-extern tree finish_requires_expr (tree, tree);
-extern tree finish_simple_requirement (tree);
-extern tree finish_type_requirement (tree);
-extern tree finish_compound_requirement (tree, tree, bool);
-extern tree finish_nested_requirement (tree);
+extern tree finish_requires_expr (location_t, tree, tree);
+extern tree finish_simple_requirement (location_t, tree);
+extern tree finish_type_requirement (location_t, tree);
+extern tree finish_compound_requirement (location_t, tree, tree, bool);
+extern tree finish_nested_requirement (location_t, tree);
extern void check_constrained_friend (tree, tree);
extern tree tsubst_requires_expr (tree, tree, tsubst_flags_t, tree);
extern tree tsubst_constraint (tree, tree, tsubst_flags_t, tree);
extern tree tsubst_constraint_info (tree, tree, tsubst_flags_t, tree);
-extern bool function_concept_check_p (tree);
-extern tree normalize_expression (tree);
-extern tree expand_concept (tree, tree);
-extern bool expanding_concept ();
-extern tree evaluate_constraints (tree, tree);
-extern tree evaluate_function_concept (tree, tree);
-extern tree evaluate_variable_concept (tree, tree);
-extern tree evaluate_constraint_expression (tree, tree);
+extern tree tsubst_parameter_mapping (tree, tree, tsubst_flags_t, tree);
+extern tree get_mapped_args (tree);
+
+struct processing_constraint_expression_sentinel
+{
+ processing_constraint_expression_sentinel ();
+ ~processing_constraint_expression_sentinel ();
+};
+
+extern bool processing_constraint_expression_p ();
+
+extern tree unpack_concept_check (tree);
+extern tree evaluate_concept_check (tree, tsubst_flags_t);
+extern tree satisfy_constraint_expression (tree);
extern bool constraints_satisfied_p (tree);
extern bool constraints_satisfied_p (tree, tree);
-extern tree lookup_constraint_satisfaction (tree, tree);
-extern tree memoize_constraint_satisfaction (tree, tree, tree);
-extern tree lookup_concept_satisfaction (tree, tree);
-extern tree memoize_concept_satisfaction (tree, tree, tree);
-extern tree get_concept_expansion (tree, tree);
-extern tree save_concept_expansion (tree, tree, tree);
+extern void clear_satisfaction_cache ();
extern bool* lookup_subsumption_result (tree, tree);
extern bool save_subsumption_result (tree, tree, bool);
-
+extern tree find_template_parameters (tree, int);
extern bool equivalent_constraints (tree, tree);
extern bool equivalently_constrained (tree, tree);
extern bool subsumes_constraints (tree, tree);
-extern bool strictly_subsumes (tree, tree);
+extern bool strictly_subsumes (tree, tree, tree);
+extern bool weakly_subsumes (tree, tree, tree);
extern int more_constrained (tree, tree);
-
+extern bool atomic_constraints_identical_p (tree, tree);
+extern hashval_t hash_atomic_constraint (tree);
extern void diagnose_constraints (location_t, tree, tree);
/* in logic.cc */
-extern tree decompose_conclusions (tree);
extern bool subsumes (tree, tree);
/* In class.c */
@@ -7815,7 +7849,7 @@ extern bool var_in_maybe_constexpr_fn (tree);
extern void explain_invalid_constexpr_fn (tree);
extern vec<tree> cx_error_context (void);
extern tree fold_sizeof_expr (tree);
-extern void clear_cv_and_fold_caches (void);
+extern void clear_cv_and_fold_caches (bool = true);
extern tree unshare_constructor (tree CXX_MEM_STAT_INFO);
/* In cp-ubsan.c */
@@ -7868,6 +7902,104 @@ null_node_p (const_tree expr)
return expr == null_node;
}
+/* True iff T is a variable template declaration. */
+inline bool
+variable_template_p (tree t)
+{
+ if (TREE_CODE (t) != TEMPLATE_DECL)
+ return false;
+ if (!PRIMARY_TEMPLATE_P (t))
+ return false;
+ if (tree r = DECL_TEMPLATE_RESULT (t))
+ return VAR_P (r);
+ return false;
+}
+
+/* True iff T is a standard concept definition. This will return
+ true for both the template and underlying declaration. */
+
+inline bool
+standard_concept_p (tree t)
+{
+ if (TREE_CODE (t) == TEMPLATE_DECL)
+ t = DECL_TEMPLATE_RESULT (t);
+ return TREE_CODE (t) == CONCEPT_DECL;
+}
+
+/* True iff T is a variable concept definition. This will return
+ true for both the template and the underlying declaration. */
+
+inline bool
+variable_concept_p (tree t)
+{
+ if (TREE_CODE (t) == TEMPLATE_DECL)
+ t = DECL_TEMPLATE_RESULT (t);
+ return VAR_P (t) && DECL_DECLARED_CONCEPT_P (t);
+}
+
+/* True iff T is a function concept definition or an overload set
+ containing multiple function concepts. This will return true for
+ both the template and the underlying declaration. */
+
+inline bool
+function_concept_p (tree t)
+{
+ if (TREE_CODE (t) == OVERLOAD)
+ t = OVL_FIRST (t);
+ if (TREE_CODE (t) == TEMPLATE_DECL)
+ t = DECL_TEMPLATE_RESULT (t);
+ return TREE_CODE (t) == FUNCTION_DECL && DECL_DECLARED_CONCEPT_P (t);
+}
+
+/* True iff T is a standard, variable, or function concept. */
+
+inline bool
+concept_definition_p (tree t)
+{
+ if (t == error_mark_node)
+ return false;
+
+ /* Adjust for function concept overloads. */
+ if (TREE_CODE (t) == OVERLOAD)
+ t = OVL_FIRST (t);
+
+ /* See through templates. */
+ if (TREE_CODE (t) == TEMPLATE_DECL)
+ t = DECL_TEMPLATE_RESULT (t);
+
+ /* The obvious and easy case. */
+ if (TREE_CODE (t) == CONCEPT_DECL)
+ return true;
+
+ /* Definitely not a concept. */
+ if (!VAR_OR_FUNCTION_DECL_P (t))
+ return false;
+ if (!DECL_LANG_SPECIFIC (t))
+ return false;
+
+ return DECL_DECLARED_CONCEPT_P (t);
+}
+
+/* Same as above, but for const trees. */
+
+inline bool
+concept_definition_p (const_tree t)
+{
+ return concept_definition_p (const_cast<tree> (t));
+}
+
+/* True if t is an expression that checks a concept. */
+
+inline bool
+concept_check_p (const_tree t)
+{
+ if (TREE_CODE (t) == CALL_EXPR)
+ t = CALL_EXPR_FN (t);
+ if (t && TREE_CODE (t) == TEMPLATE_ID_EXPR)
+ return concept_definition_p (TREE_OPERAND (t, 0));
+ return false;
+}
+
#if CHECKING_P
namespace selftest {
extern void run_cp_tests (void);
diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c
index 038f3009039..2a129a3bff7 100644
--- a/gcc/cp/cxx-pretty-print.c
+++ b/gcc/cp/cxx-pretty-print.c
@@ -38,6 +38,7 @@ static void pp_cxx_typeid_expression (cxx_pretty_printer *, tree);
static void pp_cxx_unary_left_fold_expression (cxx_pretty_printer *, tree);
static void pp_cxx_unary_right_fold_expression (cxx_pretty_printer *, tree);
static void pp_cxx_binary_fold_expression (cxx_pretty_printer *, tree);
+static void pp_cxx_concept_definition (cxx_pretty_printer *, tree);
static inline void
@@ -237,7 +238,14 @@ pp_cxx_template_keyword_if_needed (cxx_pretty_printer *pp, tree scope, tree t)
static void
pp_cxx_nested_name_specifier (cxx_pretty_printer *pp, tree t)
{
- if (!SCOPE_FILE_SCOPE_P (t) && t != pp->enclosing_scope)
+ /* FIXME: When diagnosing references to concepts (especially as types?)
+ we end up adding too many '::' to the name. This is partially due
+ to the fact that pp->enclosing_namespace is null. */
+ if (t == global_namespace)
+ {
+ pp_cxx_colon_colon (pp);
+ }
+ else if (!SCOPE_FILE_SCOPE_P (t) && t != pp->enclosing_scope)
{
tree scope = get_containing_scope (t);
pp_cxx_nested_name_specifier (pp, scope);
@@ -1214,7 +1222,7 @@ cxx_pretty_printer::expression (tree t)
}
}
break;
-
+
case LAMBDA_EXPR:
pp_cxx_ws_string (this, "<lambda>");
break;
@@ -1223,14 +1231,8 @@ cxx_pretty_printer::expression (tree t)
pp_cxx_trait_expression (this, t);
break;
- case PRED_CONSTR:
+ case ATOMIC_CONSTR:
case CHECK_CONSTR:
- case EXPR_CONSTR:
- case TYPE_CONSTR:
- case ICONV_CONSTR:
- case DEDUCT_CONSTR:
- case EXCEPT_CONSTR:
- case PARM_CONSTR:
case CONJ_CONSTR:
case DISJ_CONSTR:
pp_cxx_constraint (this, t);
@@ -1349,6 +1351,8 @@ cxx_pretty_printer::simple_type_specifier (tree t)
case TEMPLATE_PARM_INDEX:
case BOUND_TEMPLATE_TEMPLATE_PARM:
pp_cxx_unqualified_id (this, t);
+ if (tree c = PLACEHOLDER_TYPE_CONSTRAINTS (t))
+ pp_cxx_constrained_type_spec (this, c);
break;
case TYPENAME_TYPE:
@@ -1876,7 +1880,7 @@ pp_cxx_template_argument_list (cxx_pretty_printer *pp, tree t)
{
if (argpack)
arg = TREE_VEC_ELT (argpack, idx);
-
+
if (need_comma)
pp_cxx_separate_with (pp, ',');
else
@@ -2302,24 +2306,28 @@ pp_cxx_canonical_template_parameter (cxx_pretty_printer *pp, tree parm)
void
pp_cxx_constrained_type_spec (cxx_pretty_printer *pp, tree c)
{
- tree t, a;
+ pp_cxx_whitespace (pp);
+ pp_cxx_left_bracket (pp);
+ pp->translate_string ("requires");
+ pp_cxx_whitespace (pp);
if (c == error_mark_node)
{
- pp_cxx_ws_string(pp, "<unsatisfied-constrained-placeholder>");
+ pp_cxx_ws_string(pp, "<unsatisfied-type-constraint>");
return;
}
+ tree t, a;
placeholder_extract_concept_and_args (c, t, a);
pp->id_expression (t);
- if (TREE_VEC_LENGTH (a) > 1)
- {
- pp_cxx_begin_template_argument_list (pp);
- tree args = make_tree_vec (TREE_VEC_LENGTH (a) - 1);
- for (int i = TREE_VEC_LENGTH (a) - 1; i > 0; --i)
- TREE_VEC_ELT (args, i-1) = TREE_VEC_ELT (a, i);
- pp_cxx_template_argument_list (pp, args);
- ggc_free (args);
- pp_cxx_end_template_argument_list (pp);
- }
+ pp_cxx_begin_template_argument_list (pp);
+ pp_cxx_ws_string (pp, "<placeholder>");
+ pp_cxx_separate_with (pp, ',');
+ tree args = make_tree_vec (TREE_VEC_LENGTH (a) - 1);
+ for (int i = 0; i < TREE_VEC_LENGTH (a) - 1; ++i)
+ TREE_VEC_ELT (args, i) = TREE_VEC_ELT (a, i + 1);
+ pp_cxx_template_argument_list (pp, args);
+ ggc_free (args);
+ pp_cxx_end_template_argument_list (pp);
+ pp_cxx_right_bracket (pp);
}
/*
@@ -2358,6 +2366,8 @@ pp_cxx_template_declaration (cxx_pretty_printer *pp, tree t)
if (TREE_CODE (t) == FUNCTION_DECL && DECL_SAVED_TREE (t))
pp_cxx_function_definition (pp, t);
+ else if (TREE_CODE (t) == CONCEPT_DECL)
+ pp_cxx_concept_definition (pp, t);
else
pp_cxx_simple_declaration (pp, t);
}
@@ -2374,6 +2384,17 @@ pp_cxx_explicit_instantiation (cxx_pretty_printer *pp, tree t)
pp_unsupported_tree (pp, t);
}
+static void
+pp_cxx_concept_definition (cxx_pretty_printer *pp, tree t)
+{
+ pp_cxx_unqualified_id (pp, DECL_NAME (t));
+ pp_cxx_whitespace (pp);
+ pp_cxx_ws_string (pp, "=");
+ pp_cxx_whitespace (pp);
+ pp->expression (DECL_INITIAL (t));
+ pp_cxx_semicolon (pp);
+}
+
/*
declaration:
block-declaration
@@ -2841,6 +2862,7 @@ pp_cxx_compound_requirement (cxx_pretty_printer *pp, tree t)
if (tree type = TREE_OPERAND (t, 1))
{
+ pp_cxx_whitespace (pp);
pp_cxx_ws_string (pp, "->");
pp->type_id (type);
}
@@ -2858,12 +2880,6 @@ pp_cxx_nested_requirement (cxx_pretty_printer *pp, tree t)
}
void
-pp_cxx_predicate_constraint (cxx_pretty_printer *pp, tree t)
-{
- pp->expression (TREE_OPERAND (t, 0));
-}
-
-void
pp_cxx_check_constraint (cxx_pretty_printer *pp, tree t)
{
tree decl = CHECK_CONSTR_CONCEPT (t);
@@ -2871,7 +2887,9 @@ pp_cxx_check_constraint (cxx_pretty_printer *pp, tree t)
tree args = CHECK_CONSTR_ARGS (t);
tree id = build_nt (TEMPLATE_ID_EXPR, tmpl, args);
- if (VAR_P (decl))
+ if (TREE_CODE (decl) == CONCEPT_DECL)
+ pp->expression (id);
+ else if (VAR_P (decl))
pp->expression (id);
else if (TREE_CODE (decl) == FUNCTION_DECL)
{
@@ -2884,77 +2902,60 @@ pp_cxx_check_constraint (cxx_pretty_printer *pp, tree t)
gcc_unreachable ();
}
-void
-pp_cxx_expression_constraint (cxx_pretty_printer *pp, tree t)
-{
- pp_string (pp, "<valid-expression ");
- pp_cxx_left_paren (pp);
- pp->expression (TREE_OPERAND (t, 0));
- pp_cxx_right_paren (pp);
- pp_string (pp, ">");
-}
+/* Output the "[with ...]" clause for a parameter mapping of an atomic
+ constraint. */
-void
-pp_cxx_type_constraint (cxx_pretty_printer *pp, tree t)
+static void
+pp_cxx_parameter_mapping (cxx_pretty_printer *pp, tree map)
{
- pp_string (pp, "<valid-type ");
- pp->type_id (TREE_OPERAND (t, 0));
- pp_string (pp, ">");
-}
+ for (tree p = map; p; p = TREE_CHAIN (p))
+ {
+ tree parm = TREE_VALUE (p);
+ tree arg = TREE_PURPOSE (p);
-void
-pp_cxx_implicit_conversion_constraint (cxx_pretty_printer *pp, tree t)
-{
- pp_string (pp, "<implicitly-conversion ");
- pp_cxx_left_paren (pp);
- pp->expression (ICONV_CONSTR_EXPR (t));
- pp_cxx_right_paren (pp);
- pp_cxx_ws_string (pp, "to");
- pp->type_id (ICONV_CONSTR_TYPE (t));
- pp_string (pp, ">");
-}
+ if (TYPE_P (parm))
+ pp->type_id (parm);
+ else
+ pp_cxx_tree_identifier (pp, DECL_NAME (TEMPLATE_PARM_DECL (parm)));
-void
-pp_cxx_argument_deduction_constraint (cxx_pretty_printer *pp, tree t)
-{
- pp_string (pp, "<argument-deduction ");
- pp_cxx_left_paren (pp);
- pp->expression (DEDUCT_CONSTR_EXPR (t));
- pp_cxx_right_paren (pp);
- pp_cxx_ws_string (pp, "as");
- pp->expression (DEDUCT_CONSTR_PATTERN (t));
- pp_string (pp, ">");
-}
+ pp_cxx_whitespace (pp);
+ pp_equal (pp);
+ pp_cxx_whitespace (pp);
-void
-pp_cxx_exception_constraint (cxx_pretty_printer *pp, tree t)
-{
- pp_cxx_ws_string (pp, "noexcept");
- pp_cxx_whitespace (pp);
- pp_cxx_left_paren (pp);
- pp->expression (TREE_OPERAND (t, 0));
- pp_cxx_right_paren (pp);
+ if (TYPE_P (arg) || DECL_TEMPLATE_TEMPLATE_PARM_P (arg))
+ pp->type_id (arg);
+ else
+ pp->expression (arg);
+
+ if (TREE_CHAIN (p) != NULL_TREE)
+ pp_cxx_separate_with (pp, ';');
+ }
}
void
-pp_cxx_parameterized_constraint (cxx_pretty_printer *pp, tree t)
+pp_cxx_atomic_constraint (cxx_pretty_printer *pp, tree t)
{
- pp_left_paren (pp);
- pp_string (pp, "<requires ");
- if (tree parms = PARM_CONSTR_PARMS (t))
+ /* Emit the expression. */
+ pp->expression (ATOMIC_CONSTR_EXPR (t));
+
+ /* Emit the parameter mapping. */
+ tree map = ATOMIC_CONSTR_MAP (t);
+ if (map && map != error_mark_node)
{
- pp_cxx_parameter_declaration_clause (pp, parms);
pp_cxx_whitespace (pp);
- }
- pp_cxx_constraint (pp, PARM_CONSTR_OPERAND (t));
- pp_string (pp, ">");
+ pp_cxx_left_bracket (pp);
+ pp->translate_string ("with");
+ pp_cxx_whitespace (pp);
+ pp_cxx_parameter_mapping (pp, map);
+ pp_cxx_right_bracket (pp);
+ }
}
void
pp_cxx_conjunction (cxx_pretty_printer *pp, tree t)
{
pp_cxx_constraint (pp, TREE_OPERAND (t, 0));
- pp_string (pp, " and ");
+ pp_string (pp, " /\\ ");
pp_cxx_constraint (pp, TREE_OPERAND (t, 1));
}
@@ -2962,7 +2963,7 @@ void
pp_cxx_disjunction (cxx_pretty_printer *pp, tree t)
{
pp_cxx_constraint (pp, TREE_OPERAND (t, 0));
- pp_string (pp, " or ");
+ pp_string (pp, " \\/ ");
pp_cxx_constraint (pp, TREE_OPERAND (t, 1));
}
@@ -2974,38 +2975,14 @@ pp_cxx_constraint (cxx_pretty_printer *pp, tree t)
switch (TREE_CODE (t))
{
- case PRED_CONSTR:
- pp_cxx_predicate_constraint (pp, t);
+ case ATOMIC_CONSTR:
+ pp_cxx_atomic_constraint (pp, t);
break;
case CHECK_CONSTR:
pp_cxx_check_constraint (pp, t);
break;
- case EXPR_CONSTR:
- pp_cxx_expression_constraint (pp, t);
- break;
-
- case TYPE_CONSTR:
- pp_cxx_type_constraint (pp, t);
- break;
-
- case ICONV_CONSTR:
- pp_cxx_implicit_conversion_constraint (pp, t);
- break;
-
- case DEDUCT_CONSTR:
- pp_cxx_argument_deduction_constraint (pp, t);
- break;
-
- case EXCEPT_CONSTR:
- pp_cxx_exception_constraint (pp, t);
- break;
-
- case PARM_CONSTR:
- pp_cxx_parameterized_constraint (pp, t);
- break;
-
case CONJ_CONSTR:
pp_cxx_conjunction (pp, t);
break;
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 9ea53e7160e..65f451df903 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -920,6 +920,31 @@ determine_local_discriminator (tree decl)
}
+
+/* Returns true if functions FN1 and FN2 have equivalent trailing
+ requires clauses. */
+
+static bool
+function_requirements_equivalent_p (tree newfn, tree oldfn)
+{
+ /* In the concepts TS, the combined constraints are compared. */
+ if (cxx_dialect < cxx2a)
+ {
+ tree ci1 = get_constraints (oldfn);
+ tree ci2 = get_constraints (newfn);
+ tree req1 = ci1 ? CI_ASSOCIATED_CONSTRAINTS (ci1) : NULL_TREE;
+ tree req2 = ci2 ? CI_ASSOCIATED_CONSTRAINTS (ci2) : NULL_TREE;
+ return cp_tree_equal (req1, req2);
+ }
+
+ /* Compare only trailing requirements. */
+ tree reqs1 = get_trailing_function_requirements (newfn);
+ tree reqs2 = get_trailing_function_requirements (oldfn);
+ if ((reqs1 != NULL_TREE) != (reqs2 != NULL_TREE))
+ return false;
+ return cp_tree_equal (reqs1, reqs2);
+}
+
/* Subroutine of duplicate_decls: return truthvalue of whether
or not types of these decls match.
@@ -999,6 +1024,12 @@ decls_match (tree newdecl, tree olddecl, bool record_versions /* = true */)
else
types_match = 0;
+ /* Two function declarations match if either has a requires-clause
+ then both have a requires-clause and their constraints-expressions
+ are equivalent. */
+ if (types_match && flag_concepts)
+ types_match = function_requirements_equivalent_p (newdecl, olddecl);
+
/* The decls dont match if they correspond to two different versions
of the same function. Disallow extern "C" functions to be
versions for now. */
@@ -1013,23 +1044,21 @@ decls_match (tree newdecl, tree olddecl, bool record_versions /* = true */)
}
else if (TREE_CODE (newdecl) == TEMPLATE_DECL)
{
+ if (!template_heads_equivalent_p (newdecl, olddecl))
+ return 0;
+
tree oldres = DECL_TEMPLATE_RESULT (olddecl);
tree newres = DECL_TEMPLATE_RESULT (newdecl);
if (TREE_CODE (newres) != TREE_CODE (oldres))
return 0;
- if (!comp_template_parms (DECL_TEMPLATE_PARMS (newdecl),
- DECL_TEMPLATE_PARMS (olddecl)))
- return 0;
-
- if (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == TYPE_DECL)
- types_match = (same_type_p (TREE_TYPE (oldres), TREE_TYPE (newres))
- && equivalently_constrained (olddecl, newdecl));
+ /* Two template types match if they are the same. Otherwise, compare
+ the underlying declarations. */
+ if (TREE_CODE (newres) == TYPE_DECL)
+ types_match = same_type_p (TREE_TYPE (newres), TREE_TYPE (oldres));
else
- // We don't need to check equivalently_constrained for variable and
- // function templates because we check it on the results.
- types_match = decls_match (oldres, newres);
+ types_match = decls_match (newres, oldres);
}
else
{
@@ -1057,11 +1086,6 @@ decls_match (tree newdecl, tree olddecl, bool record_versions /* = true */)
COMPARE_REDECLARATION);
}
- // Normal functions can be constrained, as can variable partial
- // specializations.
- if (types_match && VAR_OR_FUNCTION_DECL_P (newdecl))
- types_match = equivalently_constrained (newdecl, olddecl);
-
return types_match;
}
@@ -1336,6 +1360,46 @@ merge_attribute_bits (tree newdecl, tree olddecl)
&& lookup_attribute ("gnu_inline", \
DECL_ATTRIBUTES (fn)))
+/* A subroutine of duplicate_decls. Emits a diagnostic when newdecl
+ ambiguates olddecl. Returns true if an error occurs. */
+
+static bool
+duplicate_function_template_decls (tree newdecl, tree olddecl)
+{
+
+ tree newres = DECL_TEMPLATE_RESULT (newdecl);
+ tree oldres = DECL_TEMPLATE_RESULT (olddecl);
+ /* Function template declarations can be differentiated by parameter
+ and return type. */
+ if (compparms (TYPE_ARG_TYPES (TREE_TYPE (oldres)),
+ TYPE_ARG_TYPES (TREE_TYPE (newres)))
+ && same_type_p (TREE_TYPE (TREE_TYPE (newdecl)),
+ TREE_TYPE (TREE_TYPE (olddecl))))
+ {
+ /* ... and also by their template-heads and requires-clauses. */
+ if (template_heads_equivalent_p (newdecl, olddecl)
+ && function_requirements_equivalent_p (newres, oldres))
+ {
+ error ("ambiguating new declaration %q+#D", newdecl);
+ inform (DECL_SOURCE_LOCATION (olddecl),
+ "old declaration %q#D", olddecl);
+ return true;
+ }
+
+ /* FIXME: The types are the same but the are differences
+ in either the template heads or function requirements.
+ We should be able to diagnose a set of common errors
+ stemming from these declarations. For example:
+
+ template<typename T> requires C void f(...);
+ template<typename T> void f(...) requires C;
+
+ These are functionally equivalent but not equivalent. */
+ }
+
+ return false;
+}
+
/* If NEWDECL is a redeclaration of OLDDECL, merge the declarations.
If the redeclaration is invalid, a diagnostic is issued, and the
error_mark_node is returned. Otherwise, OLDDECL is returned.
@@ -1644,11 +1708,14 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
if (TREE_CODE (newdecl) == TEMPLATE_DECL)
{
+ tree oldres = DECL_TEMPLATE_RESULT (olddecl);
+ tree newres = DECL_TEMPLATE_RESULT (newdecl);
+
/* The name of a class template may not be declared to refer to
any other template, class, function, object, namespace, value,
or type in the same scope. */
- if (TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)) == TYPE_DECL
- || TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == TYPE_DECL)
+ if (TREE_CODE (oldres) == TYPE_DECL
+ || TREE_CODE (newres) == TYPE_DECL)
{
error_at (newdecl_loc,
"conflicting declaration of template %q#D", newdecl);
@@ -1656,24 +1723,13 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
"previous declaration %q#D", olddecl);
return error_mark_node;
}
- else if (TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)) == FUNCTION_DECL
- && TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == FUNCTION_DECL
- && compparms (TYPE_ARG_TYPES (TREE_TYPE (DECL_TEMPLATE_RESULT (olddecl))),
- TYPE_ARG_TYPES (TREE_TYPE (DECL_TEMPLATE_RESULT (newdecl))))
- && comp_template_parms (DECL_TEMPLATE_PARMS (newdecl),
- DECL_TEMPLATE_PARMS (olddecl))
- /* Template functions can be disambiguated by
- return type. */
- && same_type_p (TREE_TYPE (TREE_TYPE (newdecl)),
- TREE_TYPE (TREE_TYPE (olddecl)))
- /* Template functions can also be disambiguated by
- constraints. */
- && equivalently_constrained (olddecl, newdecl))
+
+ else if (TREE_CODE (oldres) == FUNCTION_DECL
+ && TREE_CODE (newres) == FUNCTION_DECL)
{
- error_at (newdecl_loc, "ambiguating new declaration %q#D",
- newdecl);
- inform (olddecl_loc,
- "old declaration %q#D", olddecl);
+ if (duplicate_function_template_decls (newdecl, olddecl))
+ return error_mark_node;
+ return NULL_TREE;
}
else if (check_concept_refinement (olddecl, newdecl))
return error_mark_node;
@@ -2916,6 +2972,9 @@ redeclaration_error_message (tree newdecl, tree olddecl)
return NULL;
}
+ if (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == CONCEPT_DECL)
+ return G_("redefinition of %q#D");
+
if (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) != FUNCTION_DECL
|| (DECL_TEMPLATE_RESULT (newdecl)
== DECL_TEMPLATE_RESULT (olddecl)))
@@ -8985,12 +9044,12 @@ grokfndecl (tree ctype,
tree tmpl_reqs = NULL_TREE;
if (processing_template_decl > template_class_depth (ctype))
tmpl_reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
-
- /* Adjust the required expression into a constraint. */
- if (decl_reqs)
- decl_reqs = normalize_expression (decl_reqs);
-
tree ci = build_constraints (tmpl_reqs, decl_reqs);
+ if (concept_p && ci)
+ {
+ error_at (location, "a function concept cannot be constrained");
+ ci = NULL_TREE;
+ }
set_constraints (decl, ci);
}
@@ -9630,12 +9689,18 @@ grokvardecl (tree type,
if (!same_type_ignoring_top_level_qualifiers_p (type, boolean_type_node))
error_at (declspecs->locations[ds_type_spec],
"concept must have type %<bool%>");
+ if (TEMPLATE_PARMS_CONSTRAINTS (current_template_parms))
+ {
+ error_at (location, "a variable concept cannot be constrained");
+ TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = NULL_TREE;
+ }
}
else if (flag_concepts
&& processing_template_decl > template_class_depth (scope))
{
tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
tree ci = build_constraints (reqs, NULL_TREE);
+
set_constraints (decl, ci);
}
@@ -12543,12 +12608,18 @@ grokdeclarator (const cp_declarator *declarator,
if (ctype || in_namespace)
error ("cannot use %<::%> in parameter declaration");
- if (type_uses_auto (type)
- && !(cxx_dialect >= cxx17 && template_parm_flag))
+ tree auto_node = type_uses_auto (type);
+ if (auto_node && !(cxx_dialect >= cxx17 && template_parm_flag))
{
if (cxx_dialect >= cxx14)
- error_at (typespec_loc,
- "%<auto%> parameter not permitted in this context");
+ {
+ if (decl_context == PARM && AUTO_IS_DECLTYPE (auto_node))
+ error_at (typespec_loc,
+ "cannot declare a parameter with %<decltype(auto)%>");
+ else
+ error_at (typespec_loc,
+ "%<auto%> parameter not permitted in this context");
+ }
else
error_at (typespec_loc, "parameter declared %<auto%>");
type = error_mark_node;
@@ -12754,8 +12825,8 @@ grokdeclarator (const cp_declarator *declarator,
tree tmpl = TREE_OPERAND (unqualified_id, 0);
if (variable_template_p (tmpl))
{
- error ("specialization of variable template %qD "
- "declared as function", tmpl);
+ error_at (id_loc, "specialization of variable template "
+ "%qD declared as function", tmpl);
inform (DECL_SOURCE_LOCATION (tmpl),
"variable template declared here");
return error_mark_node;
@@ -13738,7 +13809,8 @@ grok_ctor_properties (const_tree ctype, const_tree decl)
or implicitly defined), there's no need to worry about their
existence. Theoretically, they should never even be
instantiated, but that's hard to forestall. */
- error ("invalid constructor; you probably meant %<%T (const %T&)%>",
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "invalid constructor; you probably meant %<%T (const %T&)%>",
ctype, ctype);
return false;
}
@@ -16403,8 +16475,17 @@ finish_function (bool inline_p)
if (!processing_template_decl && FNDECL_USED_AUTO (fndecl)
&& TREE_TYPE (fntype) == DECL_SAVED_AUTO_RETURN_TYPE (fndecl))
{
- if (is_auto (DECL_SAVED_AUTO_RETURN_TYPE (fndecl)))
+ if (is_auto (DECL_SAVED_AUTO_RETURN_TYPE (fndecl))
+ && !current_function_returns_value
+ && !current_function_returns_null)
{
+ /* We haven't applied return type deduction because we haven't
+ seen any return statements. Do that now. */
+ tree node = type_uses_auto (DECL_SAVED_AUTO_RETURN_TYPE (fndecl));
+ do_auto_deduction (DECL_SAVED_AUTO_RETURN_TYPE (fndecl),
+ void_node, node, tf_warning_or_error,
+ adc_return_type);
+
apply_deduced_return_type (fndecl, void_type_node);
fntype = TREE_TYPE (fndecl);
}
@@ -17001,7 +17082,9 @@ require_deduced_type (tree decl, tsubst_flags_t complain)
{
if (undeduced_auto_decl (decl))
{
- if (complain & tf_error)
+ if (TREE_NO_WARNING (decl) && seen_error ())
+ /* We probably already complained about deduction failure. */;
+ else if (complain & tf_error)
error ("use of %qD before deduction of %<auto%>", decl);
return false;
}
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 8f935e8656d..6d5e973b487 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -405,6 +405,7 @@ grok_array_decl (location_t loc, tree array_expr, tree index_exp,
else
{
tree p1, p2, i1, i2;
+ bool swapped = false;
/* Otherwise, create an ARRAY_REF for a pointer or array type.
It is a little-known fact that, if `a' is an array and `i' is
@@ -431,7 +432,7 @@ grok_array_decl (location_t loc, tree array_expr, tree index_exp,
if (p1 && i2)
array_expr = p1, index_exp = i2;
else if (i1 && p2)
- array_expr = p2, index_exp = i1;
+ swapped = true, array_expr = p2, index_exp = i1;
else
{
error_at (loc, "invalid types %<%T[%T]%> for array subscript",
@@ -447,7 +448,12 @@ grok_array_decl (location_t loc, tree array_expr, tree index_exp,
else
array_expr = mark_lvalue_use_nonread (array_expr);
index_exp = mark_rvalue_use (index_exp);
- expr = build_array_ref (input_location, array_expr, index_exp);
+ if (swapped
+ && flag_strong_eval_order == 2
+ && (TREE_SIDE_EFFECTS (array_expr) || TREE_SIDE_EFFECTS (index_exp)))
+ expr = build_array_ref (input_location, index_exp, array_expr);
+ else
+ expr = build_array_ref (input_location, array_expr, index_exp);
}
if (processing_template_decl && expr != error_mark_node)
{
@@ -1608,7 +1614,8 @@ build_anon_union_vars (tree type, tree object)
just give an error. */
if (TREE_CODE (type) != UNION_TYPE)
{
- error ("anonymous struct not inside named type");
+ error_at (DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (type)),
+ "anonymous struct not inside named type");
return error_mark_node;
}
@@ -5581,7 +5588,8 @@ mark_used (tree decl, tsubst_flags_t complain)
/* Remember the current location for a function we will end up
synthesizing. Then we can inform the user where it was
required in the case of error. */
- DECL_SOURCE_LOCATION (decl) = input_location;
+ if (DECL_ARTIFICIAL (decl))
+ DECL_SOURCE_LOCATION (decl) = input_location;
/* Synthesizing an implicitly defined member function will result in
garbage collection. We must treat this situation as if we were
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 56201345429..1fd87d2abea 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -98,6 +98,7 @@ static void print_instantiation_full_context (diagnostic_context *);
static void print_instantiation_partial_context (diagnostic_context *,
struct tinst_level *,
location_t);
+static void maybe_print_constraint_context (diagnostic_context *);
static void cp_diagnostic_starter (diagnostic_context *, diagnostic_info *);
static void cp_print_error_function (diagnostic_context *, diagnostic_info *);
@@ -545,9 +546,7 @@ dump_type (cxx_pretty_printer *pp, tree t, int flags)
case TEMPLATE_TYPE_PARM:
pp_cxx_cv_qualifier_seq (pp, t);
- if (tree c = PLACEHOLDER_TYPE_CONSTRAINTS (t))
- pp_cxx_constrained_type_spec (pp, c);
- else if (template_placeholder_p (t))
+ if (template_placeholder_p (t))
{
t = TREE_TYPE (CLASS_PLACEHOLDER_TEMPLATE (t));
pp_cxx_tree_identifier (pp, TYPE_IDENTIFIER (t));
@@ -558,6 +557,9 @@ dump_type (cxx_pretty_printer *pp, tree t, int flags)
else
pp_cxx_canonical_template_parameter
(pp, TEMPLATE_TYPE_PARM_INDEX (t));
+ /* If this is a constrained placeholder, add the requirements. */
+ if (tree c = PLACEHOLDER_TYPE_CONSTRAINTS (t))
+ pp_cxx_constrained_type_spec (pp, c);
break;
/* This is not always necessary for pointers and such, but doing this
@@ -1284,6 +1286,15 @@ dump_decl (cxx_pretty_printer *pp, tree t, int flags)
dump_template_decl (pp, t, flags);
break;
+ case CONCEPT_DECL:
+ pp_cxx_ws_string (pp, "concept");
+ dump_decl_name (pp, DECL_NAME (t), flags);
+ break;
+
+ case WILDCARD_DECL:
+ pp_string (pp, "<wildcard>");
+ break;
+
case TEMPLATE_ID_EXPR:
{
tree name = TREE_OPERAND (t, 0);
@@ -1448,7 +1459,9 @@ dump_template_decl (cxx_pretty_printer *pp, tree t, int flags)
else if (DECL_TEMPLATE_RESULT (t)
&& (VAR_P (DECL_TEMPLATE_RESULT (t))
/* Alias template. */
- || DECL_TYPE_TEMPLATE_P (t)))
+ || DECL_TYPE_TEMPLATE_P (t)
+ /* Concept definition. &*/
+ || TREE_CODE (DECL_TEMPLATE_RESULT (t)) == CONCEPT_DECL))
dump_decl (pp, DECL_TEMPLATE_RESULT (t), flags | TFF_TEMPLATE_NAME);
else
{
@@ -2082,6 +2095,7 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
case TEMPLATE_DECL:
case NAMESPACE_DECL:
case LABEL_DECL:
+ case WILDCARD_DECL:
case OVERLOAD:
case TYPE_DECL:
case IDENTIFIER_NODE:
@@ -2848,18 +2862,14 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
pp_cxx_nested_requirement (cxx_pp, t);
break;
- case PRED_CONSTR:
+ case ATOMIC_CONSTR:
case CHECK_CONSTR:
- case EXPR_CONSTR:
- case TYPE_CONSTR:
- case ICONV_CONSTR:
- case DEDUCT_CONSTR:
- case EXCEPT_CONSTR:
- case PARM_CONSTR:
case CONJ_CONSTR:
case DISJ_CONSTR:
- pp_cxx_constraint (cxx_pp, t);
- break;
+ {
+ pp_cxx_constraint (cxx_pp, t);
+ break;
+ }
case PLACEHOLDER_EXPR:
pp_string (pp, M_("*this"));
@@ -3326,6 +3336,7 @@ cp_diagnostic_starter (diagnostic_context *context,
cp_print_error_function (context, diagnostic);
maybe_print_instantiation_context (context);
maybe_print_constexpr_context (context);
+ maybe_print_constraint_context (context);
pp_set_prefix (context->printer, diagnostic_build_prefix (context,
diagnostic));
}
@@ -3650,6 +3661,171 @@ maybe_print_constexpr_context (diagnostic_context *context)
}
+static void
+print_location (diagnostic_context *context, location_t loc)
+{
+ expanded_location xloc = expand_location (loc);
+ if (context->show_column)
+ pp_verbatim (context->printer, _("%r%s:%d:%d:%R "),
+ "locus", xloc.file, xloc.line, xloc.column);
+ else
+ pp_verbatim (context->printer, _("%r%s:%d:%R "),
+ "locus", xloc.file, xloc.line);
+}
+
+/* Instantiate the concept check for the purpose of diagnosing an error. */
+
+static tree
+rebuild_concept_check (tree expr, tree map, tree args)
+{
+ /* Instantiate the parameter mapping for the template-id. */
+ map = tsubst_parameter_mapping (map, args, tf_none, NULL_TREE);
+ if (map == error_mark_node)
+ return error_mark_node;
+ args = get_mapped_args (map);
+
+ /* Rebuild the template id using substituted arguments. Substituting
+ directly through the expression will trigger recursive satisfaction,
+ so don't do that. */
+ tree id = unpack_concept_check (expr);
+ args = tsubst_template_args (TREE_OPERAND (id, 1), args, tf_none, NULL_TREE);
+ if (args == error_mark_node)
+ return error_mark_node;
+ return build_nt (TEMPLATE_ID_EXPR, TREE_OPERAND (id, 0), args);
+}
+
+static void
+print_constrained_decl_info (diagnostic_context *context, tree decl)
+{
+ print_location (context, DECL_SOURCE_LOCATION (decl));
+ pp_verbatim (context->printer, "required by the constraints of %q#D\n", decl);
+}
+
+static void
+print_concept_check_info (diagnostic_context *context, tree expr, tree map, tree args)
+{
+ gcc_assert (concept_check_p (expr));
+
+ tree id = unpack_concept_check (expr);
+ tree tmpl = TREE_OPERAND (id, 0);
+ if (OVL_P (tmpl))
+ tmpl = OVL_FIRST (tmpl);
+ tree check = rebuild_concept_check (expr, map, args);
+ if (check == error_mark_node)
+ check = expr;
+
+ print_location (context, DECL_SOURCE_LOCATION (tmpl));
+ pp_verbatim (context->printer, "required for the satisfaction of %qE\n", check);
+}
+
+/* Diagnose the entry point into the satisfaction error. Returns the next
+ context, if any. */
+
+static tree
+print_constraint_context_head (diagnostic_context *context, tree cxt, tree args)
+{
+ tree src = TREE_VALUE (cxt);
+ if (!src)
+ {
+ print_location (context, input_location);
+ pp_verbatim (context->printer, "required for constraint satisfaction\n");
+ return NULL_TREE;
+ }
+ if (DECL_P (src))
+ {
+ print_constrained_decl_info (context, src);
+ return NULL_TREE;
+ }
+ else
+ {
+ print_concept_check_info (context, src, TREE_PURPOSE (cxt), args);
+ return TREE_CHAIN (cxt);
+ }
+}
+
+static void
+print_requires_expression_info (diagnostic_context *context, tree constr, tree args)
+{
+
+ tree expr = ATOMIC_CONSTR_EXPR (constr);
+ tree map = ATOMIC_CONSTR_MAP (constr);
+ map = tsubst_parameter_mapping (map, args, tf_none, NULL_TREE);
+ if (map == error_mark_node)
+ return;
+ args = get_mapped_args (map);
+
+ print_location (context, cp_expr_loc_or_input_loc (expr));
+ pp_verbatim (context->printer, "in requirements ");
+
+ tree parms = TREE_OPERAND (expr, 0);
+ if (parms)
+ pp_verbatim (context->printer, "with ");
+ while (parms)
+ {
+ tree next = TREE_CHAIN (parms);
+
+ TREE_CHAIN (parms) = NULL_TREE;
+ cp_unevaluated u;
+ tree p = tsubst (parms, args, tf_none, NULL_TREE);
+ pp_verbatim (context->printer, "%q#D", p);
+ TREE_CHAIN (parms) = next;
+
+ if (next)
+ pp_separate_with_comma ((cxx_pretty_printer *)context->printer);
+
+ parms = next;
+ }
+
+ pp_verbatim (context->printer, "\n");
+}
+
+void
+maybe_print_single_constraint_context (diagnostic_context *context, tree failed)
+{
+ if (!failed)
+ return;
+
+ tree constr = TREE_VALUE (failed);
+ if (!constr || constr == error_mark_node)
+ return;
+ tree cxt = CONSTR_CONTEXT (constr);
+ if (!cxt)
+ return;
+ tree args = TREE_PURPOSE (failed);
+
+ /* Print the stack of requirements. */
+ cxt = print_constraint_context_head (context, cxt, args);
+ while (cxt && !DECL_P (TREE_VALUE (cxt)))
+ {
+ tree expr = TREE_VALUE (cxt);
+ tree map = TREE_PURPOSE (cxt);
+ print_concept_check_info (context, expr, map, args);
+ cxt = TREE_CHAIN (cxt);
+ }
+
+ /* For certain constraints, we can provide additional context. */
+ if (TREE_CODE (constr) == ATOMIC_CONSTR
+ && TREE_CODE (ATOMIC_CONSTR_EXPR (constr)) == REQUIRES_EXPR)
+ print_requires_expression_info (context, constr, args);
+}
+
+void
+maybe_print_constraint_context (diagnostic_context *context)
+{
+ if (!current_failed_constraint)
+ return;
+
+ tree cur = current_failed_constraint;
+
+ /* Recursively print nested contexts. */
+ current_failed_constraint = TREE_CHAIN (current_failed_constraint);
+ if (current_failed_constraint)
+ maybe_print_constraint_context (context);
+
+ /* Print this context. */
+ maybe_print_single_constraint_context (context, cur);
+}
+
/* Return true iff TYPE_A and TYPE_B are template types that are
meaningful to compare. */
diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index c4fed168269..b503e9743cf 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -1040,9 +1040,9 @@ maybe_add_lambda_conv_op (tree type)
bool const generic_lambda_p = generic_lambda_fn_p (callop);
- if (!generic_lambda_p && DECL_INITIAL (callop) == NULL_TREE)
+ if (!generic_lambda_p && undeduced_auto_decl (callop))
{
- /* If the op() wasn't instantiated due to errors, give up. */
+ /* If the op() wasn't deduced due to errors, give up. */
gcc_assert (errorcount || sorrycount);
return;
}
diff --git a/gcc/cp/logic.cc b/gcc/cp/logic.cc
index 13cc3212436..2d4abaf6edd 100644
--- a/gcc/cp/logic.cc
+++ b/gcc/cp/logic.cc
@@ -47,729 +47,736 @@ along with GCC; see the file COPYING3. If not see
#include "toplev.h"
#include "type-utils.h"
-namespace {
+/* Hash functions for atomic constrains. */
-// Helper algorithms
-
-template<typename I>
-inline I
-next (I iter)
+struct constraint_hash : default_hash_traits<tree>
{
- return ++iter;
-}
+ static hashval_t hash (tree t)
+ {
+ return hash_atomic_constraint (t);
+ }
-template<typename I, typename P>
-inline bool
-any_p (I first, I last, P pred)
-{
- while (first != last)
- {
- if (pred(*first))
- return true;
- ++first;
- }
- return false;
-}
+ static bool equal (tree t1, tree t2)
+ {
+ return atomic_constraints_identical_p (t1, t2);
+ }
+};
-bool prove_implication (tree, tree);
+/* A conjunctive or disjunctive clause.
-/*---------------------------------------------------------------------------
- Proof state
----------------------------------------------------------------------------*/
+ Each clause maintains an iterator that refers to the current
+ term, which is used in the linear decomposition of a formula
+ into CNF or DNF. */
-struct term_entry
+struct clause
{
- tree t;
-};
+ typedef std::list<tree>::iterator iterator;
+ typedef std::list<tree>::const_iterator const_iterator;
-/* Hashing function and equality for constraint entries. */
+ /* Initialize a clause with an initial term. */
-struct term_hasher : ggc_ptr_hash<term_entry>
-{
- static hashval_t hash (term_entry *e)
+ clause (tree t)
{
- return iterative_hash_template_arg (e->t, 0);
+ m_terms.push_back (t);
+ if (TREE_CODE (t) == ATOMIC_CONSTR)
+ m_set.add (t);
+
+ m_current = m_terms.begin ();
}
- static bool equal (term_entry *e1, term_entry *e2)
+ /* Create a copy of the current term. The current
+ iterator is set to point to the same position in the
+ copied list of terms. */
+
+ clause (clause const& c)
+ : m_terms (c.m_terms), m_set (c.m_set), m_current (m_terms.begin ())
{
- return cp_tree_equal (e1->t, e2->t);
+ std::advance (m_current, std::distance (c.begin (), c.current ()));
}
-};
-/* A term list is a list of atomic constraints. It is used
- to maintain the lists of assumptions and conclusions in a
- proof goal.
+ /* Returns true when all terms are atoms. */
- Each term list maintains an iterator that refers to the current
- term. This can be used by various tactics to support iteration
- and stateful manipulation of the list. */
-class term_list
-{
-public:
- typedef std::list<tree>::iterator iterator;
+ bool done () const
+ {
+ return m_current == end ();
+ }
- term_list ();
- term_list (tree);
+ /* Advance to the next term. */
- bool includes (tree);
- iterator insert (iterator, tree);
- iterator push_back (tree);
- iterator erase (iterator);
- iterator replace (iterator, tree);
- iterator replace (iterator, tree, tree);
+ void advance ()
+ {
+ gcc_assert (!done ());
+ ++m_current;
+ }
- iterator begin() { return seq.begin(); }
- iterator end() { return seq.end(); }
+ /* Replaces the current term at position ITER with T. If
+ T is an atomic constraint that already appears in the
+ clause, remove but do not replace ITER. Returns a pair
+ containing an iterator to the replace object or past
+ the erased object and a boolean value which is true if
+ an object was erased. */
- std::list<tree> seq;
- hash_table<term_hasher> tab;
-};
+ std::pair<iterator, bool> replace (iterator iter, tree t)
+ {
+ gcc_assert (TREE_CODE (*iter) != ATOMIC_CONSTR);
+ if (TREE_CODE (t) == ATOMIC_CONSTR)
+ {
+ if (m_set.add (t))
+ return std::make_pair (m_terms.erase (iter), true);
+ }
+ *iter = t;
+ return std::make_pair (iter, false);
+ }
-inline
-term_list::term_list ()
- : seq(), tab (11)
-{
-}
+ /* Inserts T before ITER in the list of terms. If T has
+ already is an atomic constraint that already appears in
+ the clause, no action is taken, and the current iterator
+ is returned. Returns a pair of an iterator to the inserted
+ object or ITER if no insertion occurred and a boolean
+ value which is true if an object was inserted. */
-/* Initialize a term list with an initial term. */
+ std::pair<iterator, bool> insert (iterator iter, tree t)
+ {
+ if (TREE_CODE (t) == ATOMIC_CONSTR)
+ {
+ if (m_set.add (t))
+ return std::make_pair (iter, false);
+ }
+ return std::make_pair (m_terms.insert (iter, t), true);
+ }
-inline
-term_list::term_list (tree t)
- : seq (), tab (11)
-{
- push_back (t);
-}
+ /* Replaces the current term with T. In the case where the
+ current term is erased (because T is redundant), update
+ the position of the current term to the next term. */
-/* Returns true if T is the in the tree. */
+ void replace (tree t)
+ {
+ m_current = replace (m_current, t).first;
+ }
-inline bool
-term_list::includes (tree t)
-{
- term_entry ent = {t};
- return tab.find (&ent);
-}
+ /* Replace the current term with T1 and T2, in that order. */
-/* Append a term to the list. */
-inline term_list::iterator
-term_list::push_back (tree t)
-{
- return insert (end(), t);
-}
+ void replace (tree t1, tree t2)
+ {
+ /* Replace the current term with t1. Ensure that iter points
+ to the term before which t2 will be inserted. Update the
+ current term as needed. */
+ std::pair<iterator, bool> rep = replace (m_current, t1);
+ if (rep.second)
+ m_current = rep.first;
+ else
+ ++rep.first;
-/* Insert a new (unseen) term T into the list before the proposition
- indicated by ITER. Returns the iterator to the newly inserted
- element. */
+ /* Insert the t2. Make this the current term if we erased
+ the prior term. */
+ std::pair<iterator, bool> ins = insert (rep.first, t2);
+ if (rep.second && ins.second)
+ m_current = ins.first;
+ }
-term_list::iterator
-term_list::insert (iterator iter, tree t)
-{
- gcc_assert (!includes (t));
- iter = seq.insert (iter, t);
- term_entry ent = {t};
- term_entry** slot = tab.find_slot (&ent, INSERT);
- term_entry* ptr = ggc_alloc<term_entry> ();
- *ptr = ent;
- *slot = ptr;
- return iter;
-}
+ /* Returns true if the clause contains the term T. */
-/* Remove an existing term from the list. Returns an iterator referring
- to the element after the removed term. This may be end(). */
+ bool contains (tree t)
+ {
+ gcc_assert (TREE_CODE (t) == ATOMIC_CONSTR);
+ return m_set.contains (t);
+ }
-term_list::iterator
-term_list::erase (iterator iter)
-{
- gcc_assert (includes (*iter));
- term_entry ent = {*iter};
- tab.remove_elt (&ent);
- iter = seq.erase (iter);
- return iter;
-}
-/* Replace the given term with that specified. If the term has
- been previously seen, do not insert the term. Returns the
- first iterator past the current term. */
+ /* Returns an iterator to the first clause in the formula. */
-term_list::iterator
-term_list::replace (iterator iter, tree t)
-{
- iter = erase (iter);
- if (!includes (t))
- insert (iter, t);
- return iter;
-}
+ iterator begin ()
+ {
+ return m_terms.begin ();
+ }
+ /* Returns an iterator to the first clause in the formula. */
-/* Replace the term at the given position by the supplied T1
- followed by t2. This is used in certain logical operators to
- load a list of assumptions or conclusions. */
+ const_iterator begin () const
+ {
+ return m_terms.begin ();
+ }
-term_list::iterator
-term_list::replace (iterator iter, tree t1, tree t2)
-{
- iter = erase (iter);
- if (!includes (t1))
- insert (iter, t1);
- if (!includes (t2))
- insert (iter, t2);
- return iter;
-}
+ /* Returns an iterator past the last clause in the formula. */
+
+ iterator end ()
+ {
+ return m_terms.end ();
+ }
-/* A goal (or subgoal) models a sequent of the form
- 'A |- C' where A and C are lists of assumptions and
- conclusions written as propositions in the constraint
- language (i.e., lists of trees). */
+ /* Returns an iterator past the last clause in the formula. */
-class proof_goal
-{
-public:
- term_list assumptions;
- term_list conclusions;
+ const_iterator end () const
+ {
+ return m_terms.end ();
+ }
+
+ /* Returns the current iterator. */
+
+ const_iterator current () const
+ {
+ return m_current;
+ }
+
+ std::list<tree> m_terms; /* The list of terms. */
+ hash_set<tree, false, constraint_hash> m_set; /* The set of atomic constraints. */
+ iterator m_current; /* The current term. */
};
+
/* A proof state owns a list of goals and tracks the
current sub-goal. The class also provides facilities
for managing subgoals and constructing term lists. */
-class proof_state : public std::list<proof_goal>
+struct formula
{
-public:
- proof_state ();
+ typedef std::list<clause>::iterator iterator;
+ typedef std::list<clause>::const_iterator const_iterator;
- iterator branch (iterator i);
- iterator discharge (iterator i);
-};
+ /* Construct a formula with an initial formula in a
+ single clause. */
-/* Initialize the state with a single empty goal, and set that goal
- as the current subgoal. */
-
-inline
-proof_state::proof_state ()
- : std::list<proof_goal> (1)
-{ }
+ formula (tree t)
+ {
+ /* This should call emplace_back(). There's a an extra copy being
+ invoked by using push_back(). */
+ m_clauses.push_back (t);
+ m_current = m_clauses.begin ();
+ }
+ /* Returns true when all clauses are atomic. */
+ bool done () const
+ {
+ return m_current == end ();
+ }
-/* Branch the current goal by creating a new subgoal, returning a
- reference to the new object. This does not update the current goal. */
+ /* Advance to the next term. */
+ void advance ()
+ {
+ gcc_assert (!done ());
+ ++m_current;
+ }
-inline proof_state::iterator
-proof_state::branch (iterator i)
-{
- gcc_assert (i != end());
- proof_goal& g = *i;
- return insert (++i, g);
-}
+ /* Insert a copy of clause into the formula. This corresponds
+ to a distribution of one logical operation over the other. */
-/* Discharge the current goal, setting it equal to the
- next non-satisfied goal. */
+ clause& branch ()
+ {
+ gcc_assert (!done ());
+ m_clauses.push_back (*m_current);
+ return m_clauses.back ();
+ }
-inline proof_state::iterator
-proof_state::discharge (iterator i)
-{
- gcc_assert (i != end());
- return erase (i);
-}
+ /* Returns the position of the current clause. */
+ iterator current ()
+ {
+ return m_current;
+ }
-/*---------------------------------------------------------------------------
- Debugging
----------------------------------------------------------------------------*/
+ /* Returns an iterator to the first clause in the formula. */
-// void
-// debug (term_list& ts)
-// {
-// for (term_list::iterator i = ts.begin(); i != ts.end(); ++i)
-// verbatim (" # %E", *i);
-// }
-//
-// void
-// debug (proof_goal& g)
-// {
-// debug (g.assumptions);
-// verbatim (" |-");
-// debug (g.conclusions);
-// }
+ iterator begin ()
+ {
+ return m_clauses.begin ();
+ }
-/*---------------------------------------------------------------------------
- Atomicity of constraints
----------------------------------------------------------------------------*/
+ /* Returns an iterator to the first clause in the formula. */
-/* Returns true if T is not an atomic constraint. */
+ const_iterator begin () const
+ {
+ return m_clauses.begin ();
+ }
-bool
-non_atomic_constraint_p (tree t)
-{
- switch (TREE_CODE (t))
- {
- case PRED_CONSTR:
- case EXPR_CONSTR:
- case TYPE_CONSTR:
- case ICONV_CONSTR:
- case DEDUCT_CONSTR:
- case EXCEPT_CONSTR:
- /* A pack expansion isn't atomic, but it can't decompose to prove an
- atom, so it shouldn't cause analyze_atom to return undecided. */
- case EXPR_PACK_EXPANSION:
- return false;
- case CHECK_CONSTR:
- case PARM_CONSTR:
- case CONJ_CONSTR:
- case DISJ_CONSTR:
- return true;
- default:
- gcc_unreachable ();
- }
-}
+ /* Returns an iterator past the last clause in the formula. */
-/* Returns true if any constraints in T are not atomic. */
+ iterator end ()
+ {
+ return m_clauses.end ();
+ }
-bool
-any_non_atomic_constraints_p (term_list& t)
-{
- return any_p (t.begin(), t.end(), non_atomic_constraint_p);
-}
+ /* Returns an iterator past the last clause in the formula. */
-/*---------------------------------------------------------------------------
- Proof validations
----------------------------------------------------------------------------*/
+ const_iterator end () const
+ {
+ return m_clauses.end ();
+ }
-enum proof_result
-{
- invalid,
- valid,
- undecided
+ std::list<clause> m_clauses; /* The list of clauses. */
+ iterator m_current; /* The current clause. */
};
-proof_result check_term (term_list&, tree);
-
-
-proof_result
-analyze_atom (term_list& ts, tree t)
+void
+debug (clause& c)
{
- /* FIXME: Hook into special cases, if any. */
- /*
- term_list::iterator iter = ts.begin();
- term_list::iterator end = ts.end();
- while (iter != end)
- {
- ++iter;
- }
- */
-
- if (non_atomic_constraint_p (t))
- return undecided;
- if (any_non_atomic_constraints_p (ts))
- return undecided;
- return invalid;
+ for (clause::iterator i = c.begin(); i != c.end(); ++i)
+ verbatim (" # %E", *i);
}
-/* Search for a pack expansion in the list of assumptions that would
- make this expansion valid. */
-
-proof_result
-analyze_pack (term_list& ts, tree t)
+void
+debug (formula& f)
{
- tree c1 = normalize_expression (PACK_EXPANSION_PATTERN (t));
- term_list::iterator iter = ts.begin();
- term_list::iterator end = ts.end();
- while (iter != end)
+ for (formula::iterator i = f.begin(); i != f.end(); ++i)
{
- if (TREE_CODE (*iter) == TREE_CODE (t))
- {
- tree c2 = normalize_expression (PACK_EXPANSION_PATTERN (*iter));
- if (prove_implication (c2, c1))
- return valid;
- else
- return invalid;
- }
- ++iter;
+ verbatim ("(((");
+ debug (*i);
+ verbatim (")))");
}
- return invalid;
}
-/* Search for concept checks in TS that we know subsume T. */
+/* The logical rules used to analyze a logical formula. The
+ "left" and "right" refer to the position of formula in a
+ sequent (as in sequent calculus). */
-proof_result
-search_known_subsumptions (term_list& ts, tree t)
+enum rules
{
- for (term_list::iterator i = ts.begin(); i != ts.end(); ++i)
- if (TREE_CODE (*i) == CHECK_CONSTR)
- {
- if (bool* b = lookup_subsumption_result (*i, t))
- return *b ? valid : invalid;
- }
- return undecided;
-}
+ left, right
+};
-/* Determine if the terms in TS provide sufficient support for proving
- the proposition T. If any term in TS is a concept check that is known
- to subsume T, then the proof is valid. Otherwise, we have to expand T
- and continue searching for support. */
+/* Distribution counting. */
-proof_result
-analyze_check (term_list& ts, tree t)
+static inline bool
+disjunction_p (tree t)
{
- proof_result r = search_known_subsumptions (ts, t);
- if (r != undecided)
- return r;
-
- tree tmpl = CHECK_CONSTR_CONCEPT (t);
- tree args = CHECK_CONSTR_ARGS (t);
- tree c = expand_concept (tmpl, args);
- return check_term (ts, c);
+ return TREE_CODE (t) == DISJ_CONSTR;
}
-/* Recursively check constraints of the parameterized constraint. */
-
-proof_result
-analyze_parameterized (term_list& ts, tree t)
+static inline bool
+conjunction_p (tree t)
{
- return check_term (ts, PARM_CONSTR_OPERAND (t));
+ return TREE_CODE (t) == CONJ_CONSTR;
}
-proof_result
-analyze_conjunction (term_list& ts, tree t)
+static inline bool
+atomic_p (tree t)
{
- proof_result r = check_term (ts, TREE_OPERAND (t, 0));
- if (r == invalid || r == undecided)
- return r;
- return check_term (ts, TREE_OPERAND (t, 1));
+ return TREE_CODE (t) == ATOMIC_CONSTR;
}
-proof_result
-analyze_disjunction (term_list& ts, tree t)
-{
- proof_result r = check_term (ts, TREE_OPERAND (t, 0));
- if (r == valid)
- return r;
- return check_term (ts, TREE_OPERAND (t, 1));
-}
+/* Recursively count the number of clauses produced when converting T
+ to DNF. Returns a pair containing the number of clauses and a bool
+ value signifying that the the tree would be rewritten as a result of
+ distributing. In general, a conjunction for which this flag is set
+ is considered a disjunction for the purpose of counting. */
-proof_result
-analyze_term (term_list& ts, tree t)
+static std::pair<int, bool>
+dnf_size_r (tree t)
{
- switch (TREE_CODE (t))
- {
- case CHECK_CONSTR:
- return analyze_check (ts, t);
+ if (atomic_p (t))
+ /* Atomic constraints produce no clauses. */
+ return std::make_pair (0, false);
- case PARM_CONSTR:
- return analyze_parameterized (ts, t);
+ /* For compound constraints, recursively count clauses and unpack
+ the results. */
+ tree lhs = TREE_OPERAND (t, 0);
+ tree rhs = TREE_OPERAND (t, 1);
+ std::pair<int, bool> p1 = dnf_size_r (lhs);
+ std::pair<int, bool> p2 = dnf_size_r (rhs);
+ int n1 = p1.first, n2 = p2.first;
+ bool d1 = p1.second, d2 = p2.second;
- case CONJ_CONSTR:
- return analyze_conjunction (ts, t);
- case DISJ_CONSTR:
- return analyze_disjunction (ts, t);
-
- case PRED_CONSTR:
- case EXPR_CONSTR:
- case TYPE_CONSTR:
- case ICONV_CONSTR:
- case DEDUCT_CONSTR:
- case EXCEPT_CONSTR:
- return analyze_atom (ts, t);
-
- case EXPR_PACK_EXPANSION:
- return analyze_pack (ts, t);
-
- case ERROR_MARK:
- /* Encountering an error anywhere in a constraint invalidates
- the proof, since the constraint is ill-formed. */
- return invalid;
- default:
- gcc_unreachable ();
+ if (disjunction_p (t))
+ {
+ /* Matches constraints of the form P \/ Q. Disjunctions contribute
+ linearly to the number of constraints. When both P and Q are
+ disjunctions, clauses are added. When only one of P and Q
+ is a disjunction, an additional clause is produced. When neither
+ P nor Q are disjunctions, two clauses are produced. */
+ if (disjunction_p (lhs))
+ {
+ if (disjunction_p (rhs) || (conjunction_p (rhs) && d2))
+ /* Both P and Q are disjunctions. */
+ return std::make_pair (n1 + n2, d1 | d2);
+ else
+ /* Only LHS is a disjunction. */
+ return std::make_pair (1 + n1 + n2, d1 | d2);
+ gcc_unreachable ();
+ }
+ if (conjunction_p (lhs))
+ {
+ if ((disjunction_p (rhs) && d1) || (conjunction_p (rhs) && d1 && d2))
+ /* Both P and Q are disjunctions. */
+ return std::make_pair (n1 + n2, d1 | d2);
+ if (disjunction_p (rhs)
+ || (conjunction_p (rhs) && d1 != d2)
+ || (atomic_p (rhs) && d1))
+ /* Either LHS or RHS is a disjunction. */
+ return std::make_pair (1 + n1 + n2, d1 | d2);
+ else
+ /* Neither LHS nor RHS is a disjunction. */
+ return std::make_pair (2, false);
+ }
+ if (atomic_p (lhs))
+ {
+ if (disjunction_p (rhs) || (conjunction_p (rhs) && d2))
+ /* Only RHS is a disjunction. */
+ return std::make_pair (1 + n1 + n2, d1 | d2);
+ else
+ /* Neither LHS nor RHS is a disjunction. */
+ return std::make_pair (2, false);
+ }
+ }
+ else /* conjunction_p (t) */
+ {
+ /* Matches constraints of the form P /\ Q, possibly resulting
+ in the distribution of one side over the other. When both
+ P and Q are disjunctions, the number of clauses are multiplied.
+ When only one of P and Q is a disjunction, the the number of
+ clauses are added. Otherwise, neither side is a disjunction and
+ no clauses are created. */
+ if (disjunction_p (lhs))
+ {
+ if (disjunction_p (rhs) || (conjunction_p (rhs) && d2))
+ /* Both P and Q are disjunctions. */
+ return std::make_pair (n1 * n2, true);
+ else
+ /* Only LHS is a disjunction. */
+ return std::make_pair (n1 + n2, true);
+ gcc_unreachable ();
+ }
+ if (conjunction_p (lhs))
+ {
+ if ((disjunction_p (rhs) && d1) || (conjunction_p (rhs) && d1 && d2))
+ /* Both P and Q are disjunctions. */
+ return std::make_pair (n1 * n2, true);
+ if (disjunction_p (rhs)
+ || (conjunction_p (rhs) && d1 != d2)
+ || (atomic_p (rhs) && d1))
+ /* Either LHS or RHS is a disjunction. */
+ return std::make_pair (n1 + n2, true);
+ else
+ /* Neither LHS nor RHS is a disjunction. */
+ return std::make_pair (0, false);
+ }
+ if (atomic_p (lhs))
+ {
+ if (disjunction_p (rhs) || (conjunction_p (rhs) && d2))
+ /* Only RHS is a disjunction. */
+ return std::make_pair (n1 + n2, true);
+ else
+ /* Neither LHS nor RHS is a disjunction. */
+ return std::make_pair (0, false);
+ }
}
+ gcc_unreachable ();
}
-/* Check if a single term can be proven from a set of assumptions.
- If the proof is not valid, then it is incomplete when either
- the given term is non-atomic or any term in the list of assumptions
- is not-atomic. */
+/* Recursively count the number of clauses produced when converting T
+ to CNF. Returns a pair containing the number of clauses and a bool
+ value signifying that the the tree would be rewritten as a result of
+ distributing. In general, a disjunction for which this flag is set
+ is considered a conjunction for the purpose of counting. */
-proof_result
-check_term (term_list& ts, tree t)
+static std::pair<int, bool>
+cnf_size_r (tree t)
{
- /* Try the easy way; search for an equivalent term. */
- if (ts.includes (t))
- return valid;
+ if (atomic_p (t))
+ /* Atomic constraints produce no clauses. */
+ return std::make_pair (0, false);
- /* The hard way; actually consider what the term means. */
- return analyze_term (ts, t);
-}
+ /* For compound constraints, recursively count clauses and unpack
+ the results. */
+ tree lhs = TREE_OPERAND (t, 0);
+ tree rhs = TREE_OPERAND (t, 1);
+ std::pair<int, bool> p1 = cnf_size_r (lhs);
+ std::pair<int, bool> p2 = cnf_size_r (rhs);
+ int n1 = p1.first, n2 = p2.first;
+ bool d1 = p1.second, d2 = p2.second;
-/* Check to see if any term is proven by the assumptions in the
- proof goal. The proof is valid if the proof of any term is valid.
- If validity cannot be determined, but any particular
- check was undecided, then this goal is undecided. */
-
-proof_result
-check_goal (proof_goal& g)
-{
- term_list::iterator iter = g.conclusions.begin ();
- term_list::iterator end = g.conclusions.end ();
- bool incomplete = false;
- while (iter != end)
+ if (disjunction_p (t))
{
- proof_result r = check_term (g.assumptions, *iter);
- if (r == valid)
- return r;
- if (r == undecided)
- incomplete = true;
- ++iter;
+ /* Matches constraints of the form P \/ Q, possibly resulting
+ in the distribution of one side over the other. When both
+ P and Q are conjunctions, the number of clauses are multiplied.
+ When only one of P and Q is a conjunction, the the number of
+ clauses are added. Otherwise, neither side is a conjunction and
+ no clauses are created. */
+ if (disjunction_p (lhs))
+ {
+ if ((disjunction_p (rhs) && d1 && d2) || (conjunction_p (rhs) && d1))
+ /* Both P and Q are conjunctions. */
+ return std::make_pair (n1 * n2, true);
+ if ((disjunction_p (rhs) && d1 != d2)
+ || conjunction_p (rhs)
+ || (atomic_p (rhs) && d1))
+ /* Either LHS or RHS is a conjunction. */
+ return std::make_pair (n1 + n2, true);
+ else
+ /* Neither LHS nor RHS is a conjunction. */
+ return std::make_pair (0, false);
+ gcc_unreachable ();
+ }
+ if (conjunction_p (lhs))
+ {
+ if ((disjunction_p (rhs) && d2) || conjunction_p (rhs))
+ /* Both LHS and RHS are conjunctions. */
+ return std::make_pair (n1 * n2, true);
+ else
+ /* Only LHS is a conjunction. */
+ return std::make_pair (n1 + n2, true);
+ }
+ if (atomic_p (lhs))
+ {
+ if ((disjunction_p (rhs) && d2) || conjunction_p (rhs))
+ /* Only RHS is a disjunction. */
+ return std::make_pair (n1 + n2, true);
+ else
+ /* Neither LHS nor RHS is a disjunction. */
+ return std::make_pair (0, false);
+ }
}
-
- /* Was the proof complete? */
- if (incomplete)
- return undecided;
- else
- return invalid;
-}
-
-/* Check if the the proof is valid. This is the case when all
- goals can be discharged. If any goal is invalid, then the
- entire proof is invalid. Otherwise, the proof is undecided. */
-
-proof_result
-check_proof (proof_state& p)
-{
- proof_state::iterator iter = p.begin();
- proof_state::iterator end = p.end();
- while (iter != end)
+ else /* conjunction_p (t) */
{
- proof_result r = check_goal (*iter);
- if (r == invalid)
- return r;
- if (r == valid)
- iter = p.discharge (iter);
- else
- ++iter;
+ /* Matches constraints of the form P /\ Q. Conjunctions contribute
+ linearly to the number of constraints. When both P and Q are
+ conjunctions, clauses are added. When only one of P and Q
+ is a conjunction, an additional clause is produced. When neither
+ P nor Q are conjunctions, two clauses are produced. */
+ if (disjunction_p (lhs))
+ {
+ if ((disjunction_p (rhs) && d1 && d2) || (conjunction_p (rhs) && d1))
+ /* Both P and Q are conjunctions. */
+ return std::make_pair (n1 + n2, d1 | d2);
+ if ((disjunction_p (rhs) && d1 != d2)
+ || conjunction_p (rhs)
+ || (atomic_p (rhs) && d1))
+ /* Either LHS or RHS is a conjunction. */
+ return std::make_pair (1 + n1 + n2, d1 | d2);
+ else
+ /* Neither LHS nor RHS is a conjunction. */
+ return std::make_pair (2, false);
+ gcc_unreachable ();
+ }
+ if (conjunction_p (lhs))
+ {
+ if ((disjunction_p (rhs) && d2) || conjunction_p (rhs))
+ /* Both LHS and RHS are conjunctions. */
+ return std::make_pair (n1 + n2, d1 | d2);
+ else
+ /* Only LHS is a conjunction. */
+ return std::make_pair (1 + n1 + n2, d1 | d2);
+ }
+ if (atomic_p (lhs))
+ {
+ if ((disjunction_p (rhs) && d2) || conjunction_p (rhs))
+ /* Only RHS is a disjunction. */
+ return std::make_pair (1 + n1 + n2, d1 | d2);
+ else
+ /* Neither LHS nor RHS is a disjunction. */
+ return std::make_pair (2, false);
+ }
}
-
- /* If all goals are discharged, then the proof is valid. */
- if (p.empty())
- return valid;
- else
- return undecided;
+ gcc_unreachable ();
}
-/*---------------------------------------------------------------------------
- Left logical rules
----------------------------------------------------------------------------*/
+/* Count the number conjunctive clauses that would be created
+ when rewriting T to DNF. */
-term_list::iterator
-load_check_assumption (term_list& ts, term_list::iterator i)
+static int
+dnf_size (tree t)
{
- tree decl = CHECK_CONSTR_CONCEPT (*i);
- tree tmpl = DECL_TI_TEMPLATE (decl);
- tree args = CHECK_CONSTR_ARGS (*i);
- return ts.replace(i, expand_concept (tmpl, args));
+ std::pair<int, bool> result = dnf_size_r (t);
+ return result.first == 0 ? 1 : result.first;
}
-term_list::iterator
-load_parameterized_assumption (term_list& ts, term_list::iterator i)
-{
- return ts.replace(i, PARM_CONSTR_OPERAND(*i));
-}
-term_list::iterator
-load_conjunction_assumption (term_list& ts, term_list::iterator i)
+/* Count the number disjunctive clauses that would be created
+ when rewriting T to CNF. */
+
+static int
+cnf_size (tree t)
{
- tree t1 = TREE_OPERAND (*i, 0);
- tree t2 = TREE_OPERAND (*i, 1);
- return ts.replace(i, t1, t2);
+ std::pair<int, bool> result = cnf_size_r (t);
+ return result.first == 0 ? 1 : result.first;
}
-/* Examine the terms in the list, and apply left-logical rules to move
- terms into the set of assumptions. */
+
+/* A left-conjunction is replaced by its operands. */
void
-load_assumptions (proof_goal& g)
+replace_term (clause& c, tree t)
{
- term_list::iterator iter = g.assumptions.begin();
- term_list::iterator end = g.assumptions.end();
- while (iter != end)
- {
- switch (TREE_CODE (*iter))
- {
- case CHECK_CONSTR:
- iter = load_check_assumption (g.assumptions, iter);
- break;
- case PARM_CONSTR:
- iter = load_parameterized_assumption (g.assumptions, iter);
- break;
- case CONJ_CONSTR:
- iter = load_conjunction_assumption (g.assumptions, iter);
- break;
- default:
- ++iter;
- break;
- }
- }
+ tree t1 = TREE_OPERAND (t, 0);
+ tree t2 = TREE_OPERAND (t, 1);
+ return c.replace (t1, t2);
}
-/* In each subgoal, load constraints into the assumption set. */
+/* Create a new clause in the formula by copying the current
+ clause. In the current clause, the term at CI is replaced
+ by the first operand, and in the new clause, it is replaced
+ by the second. */
void
-load_assumptions(proof_state& p)
+branch_clause (formula& f, clause& c1, tree t)
{
- proof_state::iterator iter = p.begin();
- while (iter != p.end())
- {
- load_assumptions (*iter);
- ++iter;
- }
+ tree t1 = TREE_OPERAND (t, 0);
+ tree t2 = TREE_OPERAND (t, 1);
+ clause& c2 = f.branch ();
+ c1.replace (t1);
+ c2.replace (t2);
}
-void
-explode_disjunction (proof_state& p, proof_state::iterator gi, term_list::iterator ti1)
-{
- tree t1 = TREE_OPERAND (*ti1, 0);
- tree t2 = TREE_OPERAND (*ti1, 1);
+/* Decompose t1 /\ t2 according to the rules R. */
- /* Erase the current term from the goal. */
- proof_goal& g1 = *gi;
- proof_goal& g2 = *p.branch (gi);
+inline void
+decompose_conjuntion (formula& f, clause& c, tree t, rules r)
+{
+ if (r == left)
+ replace_term (c, t);
+ else
+ branch_clause (f, c, t);
+}
- /* Get an iterator to the equivalent position in th enew goal. */
- int n = std::distance (g1.assumptions.begin (), ti1);
- term_list::iterator ti2 = g2.assumptions.begin ();
- std::advance (ti2, n);
+/* Decompose t1 \/ t2 according to the rules R. */
- /* Replace the disjunction in both branches. */
- g1.assumptions.replace (ti1, t1);
- g2.assumptions.replace (ti2, t2);
+inline void
+decompose_disjunction (formula& f, clause& c, tree t, rules r)
+{
+ if (r == right)
+ replace_term (c, t);
+ else
+ branch_clause (f, c, t);
}
+/* An atomic constraint is already decomposed. */
+inline void
+decompose_atom (clause& c)
+{
+ c.advance ();
+}
-/* Search the assumptions of the goal for the first disjunction. */
+/* Decompose a term of clause C (in formula F) according to the
+ logical rules R. */
-bool
-explode_goal (proof_state& p, proof_state::iterator gi)
+void
+decompose_term (formula& f, clause& c, tree t, rules r)
{
- term_list& ts = gi->assumptions;
- term_list::iterator ti = ts.begin();
- term_list::iterator end = ts.end();
- while (ti != end)
+ switch (TREE_CODE (t))
{
- if (TREE_CODE (*ti) == DISJ_CONSTR)
- {
- explode_disjunction (p, gi, ti);
- return true;
- }
- else ++ti;
+ case CONJ_CONSTR:
+ return decompose_conjuntion (f, c, t, r);
+ case DISJ_CONSTR:
+ return decompose_disjunction (f, c, t, r);
+ default:
+ return decompose_atom (c);
}
- return false;
}
-/* Search for the first goal with a disjunction, and then branch
- creating a clone of that subgoal. */
+/* Decompose C (in F) using the logical rules R until it
+ is comprised of only atomic constraints. */
void
-explode_assumptions (proof_state& p)
+decompose_clause (formula& f, clause& c, rules r)
{
- proof_state::iterator iter = p.begin();
- proof_state::iterator end = p.end();
- while (iter != end)
- {
- if (explode_goal (p, iter))
- return;
- ++iter;
- }
+ while (!c.done ())
+ decompose_term (f, c, *c.current (), r);
+ f.advance ();
}
+/* Decompose the logical formula F according to the logical
+ rules determined by R. The result is a formula containing
+ clauses that contain only atomic terms. */
-/*---------------------------------------------------------------------------
- Right logical rules
----------------------------------------------------------------------------*/
-
-term_list::iterator
-load_disjunction_conclusion (term_list& g, term_list::iterator i)
+void
+decompose_formula (formula& f, rules r)
{
- tree t1 = TREE_OPERAND (*i, 0);
- tree t2 = TREE_OPERAND (*i, 1);
- return g.replace(i, t1, t2);
+ while (!f.done ())
+ decompose_clause (f, *f.current (), r);
}
-/* Apply logical rules to the right hand side. This will load the
- conclusion set with all tpp-level disjunctions. */
+/* Fully decomposing T into a list of sequents, each comprised of
+ a list of atomic constraints, as if T were an antecedent. */
-void
-load_conclusions (proof_goal& g)
+static formula
+decompose_antecedents (tree t)
{
- term_list::iterator iter = g.conclusions.begin();
- term_list::iterator end = g.conclusions.end();
- while (iter != end)
- {
- if (TREE_CODE (*iter) == DISJ_CONSTR)
- iter = load_disjunction_conclusion (g.conclusions, iter);
- else
- ++iter;
- }
+ formula f (t);
+ decompose_formula (f, left);
+ return f;
}
-void
-load_conclusions (proof_state& p)
+/* Fully decomposing T into a list of sequents, each comprised of
+ a list of atomic constraints, as if T were a consequent. */
+
+static formula
+decompose_consequents (tree t)
{
- proof_state::iterator iter = p.begin();
- while (iter != p.end())
- {
- load_conclusions (*iter);
- ++iter;
- }
+ formula f (t);
+ decompose_formula (f, right);
+ return f;
}
+static bool derive_proof (clause&, tree, rules);
-/*---------------------------------------------------------------------------
- High-level proof tactics
----------------------------------------------------------------------------*/
+/* Derive a proof of both operands of T. */
-/* Given two constraints A and C, try to derive a proof that
- A implies C. */
+static bool
+derive_proof_for_both_operands (clause& c, tree t, rules r)
+{
+ if (!derive_proof (c, TREE_OPERAND (t, 0), r))
+ return false;
+ return derive_proof (c, TREE_OPERAND (t, 1), r);
+}
-bool
-prove_implication (tree a, tree c)
+/* Derive a proof of either operand of T. */
+
+static bool
+derive_proof_for_either_operand (clause& c, tree t, rules r)
{
- /* Quick accept. */
- if (cp_tree_equal (a, c))
+ if (derive_proof (c, TREE_OPERAND (t, 0), r))
return true;
+ return derive_proof (c, TREE_OPERAND (t, 1), r);
+}
- /* Build the initial proof state. */
- proof_state proof;
- proof_goal& goal = proof.front();
- goal.assumptions.push_back(a);
- goal.conclusions.push_back(c);
-
- /* Perform an initial right-expansion in the off-chance that the right
- hand side contains disjunctions. */
- load_conclusions (proof);
+/* Derive a proof of the atomic constraint T in clause C. */
- int step_max = 1 << 10;
- int step_count = 0; /* FIXME: We shouldn't have this. */
- std::size_t branch_limit = 1024; /* FIXME: This needs to be configurable. */
- while (step_count < step_max && proof.size() < branch_limit)
- {
- /* Determine if we can prove that the assumptions entail the
- conclusions. If so, we're done. */
- load_assumptions (proof);
+static bool
+derive_atomic_proof (clause& c, tree t)
+{
+ return c.contains (t);
+}
- /* Can we solve the proof based on this? */
- proof_result r = check_proof (proof);
- if (r != undecided)
- return r == valid;
+/* Derive a proof of T from the terms in C. */
- /* If not, then we need to dig into disjunctions. */
- explode_assumptions (proof);
+static bool
+derive_proof (clause& c, tree t, rules r)
+{
+ switch (TREE_CODE (t))
+ {
+ case CONJ_CONSTR:
+ if (r == left)
+ return derive_proof_for_both_operands (c, t, r);
+ else
+ return derive_proof_for_either_operand (c, t, r);
+ case DISJ_CONSTR:
+ if (r == left)
+ return derive_proof_for_either_operand (c, t, r);
+ else
+ return derive_proof_for_both_operands (c, t, r);
+ default:
+ return derive_atomic_proof (c, t);
+ }
+}
- ++step_count;
- }
+/* Derive a proof of T from disjunctive clauses in F. */
- if (step_count == step_max)
- error ("subsumption failed to resolve");
+static bool
+derive_proofs (formula& f, tree t, rules r)
+{
+ for (formula::iterator i = f.begin(); i != f.end(); ++i)
+ if (!derive_proof (*i, t, r))
+ return false;
+ return true;
+}
- if (proof.size() == branch_limit)
- error ("exceeded maximum number of branches");
+/* The largest number of clauses in CNF or DNF we accept as input
+ for subsumption. This an upper bound of 2^16 expressions. */
+static int max_problem_size = 16;
+static inline bool
+diagnose_constraint_size (tree t)
+{
+ error_at (input_location, "%qE exceeds the maximum constraint complexity", t);
return false;
}
@@ -777,31 +784,51 @@ prove_implication (tree a, tree c)
This is done by deriving a proof of the conclusions on the RIGHT
from the assumptions on the LEFT assumptions. */
-bool
-subsumes_constraints_nonnull (tree left, tree right)
+static bool
+subsumes_constraints_nonnull (tree lhs, tree rhs)
{
- gcc_assert (check_constraint_info (left));
- gcc_assert (check_constraint_info (right));
-
auto_timevar time (TV_CONSTRAINT_SUB);
- tree a = CI_ASSOCIATED_CONSTRAINTS (left);
- tree c = CI_ASSOCIATED_CONSTRAINTS (right);
- return prove_implication (a, c);
-}
-} /* namespace */
+ int n1 = dnf_size (lhs);
+ int n2 = cnf_size (rhs);
+
+ /* Make sure we haven't exceeded the largest acceptable problem. */
+ if (std::min (n1, n2) >= max_problem_size)
+ {
+ if (n1 < n2)
+ diagnose_constraint_size (lhs);
+ else
+ diagnose_constraint_size (rhs);
+ return false;
+ }
+
+ /* Decompose the smaller of the two formulas, and recursively
+ check the implication using the larger. Note that for
+ constraints that are largely comprised of conjunctions the
+ it will usually be the case that n1 <= n2. */
+ if (n1 <= n2)
+ {
+ formula dnf = decompose_antecedents (lhs);
+ return derive_proofs (dnf, rhs, left);
+ }
+ else
+ {
+ formula cnf = decompose_consequents (rhs);
+ return derive_proofs (cnf, lhs, right);
+ }
+}
/* Returns true if the LEFT constraints subsume the RIGHT
constraints. */
bool
-subsumes (tree left, tree right)
+subsumes (tree lhs, tree rhs)
{
- if (left == right)
+ if (lhs == rhs)
return true;
- if (!left)
+ if (!lhs || lhs == error_mark_node)
return false;
- if (!right)
+ if (!rhs || rhs == error_mark_node)
return true;
- return subsumes_constraints_nonnull (left, right);
+ return subsumes_constraints_nonnull (lhs, rhs);
}
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 01bf534aef2..73a01147ff9 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -892,7 +892,7 @@ synthesize_method (tree fndecl)
/* Reset the source location, we might have been previously
deferred, and thus have saved where we were first needed. */
- if (!DECL_INHERITED_CTOR (fndecl))
+ if (DECL_ARTIFICIAL (fndecl) && !DECL_INHERITED_CTOR (fndecl))
DECL_SOURCE_LOCATION (fndecl)
= DECL_SOURCE_LOCATION (TYPE_NAME (DECL_CONTEXT (fndecl)));
@@ -953,8 +953,9 @@ synthesize_method (tree fndecl)
pop_deferring_access_checks ();
if (error_count != errorcount || warning_count != warningcount + werrorcount)
- inform (input_location, "synthesized method %qD first required here",
- fndecl);
+ if (DECL_ARTIFICIAL (fndecl))
+ inform (input_location, "synthesized method %qD first required here",
+ fndecl);
}
/* Build a reference to type TYPE with cv-quals QUALS, which is an
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index ff6d5ee6984..57ab129c9ec 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -2268,7 +2268,13 @@ diagnose_name_conflict (tree decl, tree bval)
&& (TREE_CODE (decl) != TYPE_DECL
|| DECL_ARTIFICIAL (decl) == DECL_ARTIFICIAL (bval))
&& CP_DECL_CONTEXT (decl) == CP_DECL_CONTEXT (bval))
- error ("redeclaration of %q#D", decl);
+ {
+ if (concept_definition_p (decl))
+ error ("redeclaration of %q#D with different template parameters",
+ decl);
+ else
+ error ("redeclaration of %q#D", decl);
+ }
else
error ("%q#D conflicts with a previous declaration", decl);
@@ -2334,6 +2340,9 @@ matching_fn_p (tree one, tree two)
return false;
}
+ if (!equivalently_constrained (one, two))
+ return false;
+
return true;
}
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 61f535e65c0..3b74d8f67be 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -169,6 +169,7 @@ enum required_token {
RT_TRY, /* try */
RT_CATCH, /* catch */
RT_THROW, /* throw */
+ RT_AUTO, /* auto */
RT_LABEL, /* __label__ */
RT_AT_TRY, /* @try */
RT_AT_SYNCHRONIZED, /* @synchronized */
@@ -1377,8 +1378,9 @@ cp_ensure_no_omp_declare_simd (cp_parser *parser)
{
if (parser->omp_declare_simd && !parser->omp_declare_simd->error_seen)
{
- error ("%<#pragma omp declare simd%> not immediately followed by "
- "function declaration or definition");
+ error ("%<#pragma omp declare %s%> not immediately followed by "
+ "function declaration or definition",
+ parser->omp_declare_simd->variant_p ? "variant" : "simd");
parser->omp_declare_simd = NULL;
}
}
@@ -2198,6 +2200,8 @@ static tree cp_parser_type_specifier
int *, bool *);
static tree cp_parser_simple_type_specifier
(cp_parser *, cp_decl_specifier_seq *, cp_parser_flags);
+static tree cp_parser_placeholder_type_specifier
+ (cp_parser *, location_t, tree, bool);
static tree cp_parser_type_name
(cp_parser *, bool);
static tree cp_parser_nonclass_name
@@ -2371,6 +2375,8 @@ static tree cp_parser_type_parameter
(cp_parser *, bool *);
static tree cp_parser_template_id
(cp_parser *, bool, bool, enum tag_types, bool);
+static tree cp_parser_template_id_expr
+ (cp_parser *, bool, bool, bool);
static tree cp_parser_template_name
(cp_parser *, bool, bool, bool, enum tag_types, bool *);
static tree cp_parser_template_argument_list
@@ -2446,7 +2452,9 @@ static void cp_parser_label_declaration
/* Concept Extensions */
-static tree cp_parser_requires_clause
+static tree cp_parser_concept_definition
+ (cp_parser *);
+static tree cp_parser_constraint_expression
(cp_parser *);
static tree cp_parser_requires_clause_opt
(cp_parser *);
@@ -2456,7 +2464,7 @@ static tree cp_parser_requirement_parameter_list
(cp_parser *);
static tree cp_parser_requirement_body
(cp_parser *);
-static tree cp_parser_requirement_list
+static tree cp_parser_requirement_seq
(cp_parser *);
static tree cp_parser_requirement
(cp_parser *);
@@ -2695,11 +2703,6 @@ static bool cp_parser_init_statement_p
static bool cp_parser_skip_to_closing_square_bracket
(cp_parser *);
-/* Concept-related syntactic transformations */
-
-static tree cp_parser_maybe_concept_name (cp_parser *, tree);
-static tree cp_parser_maybe_partial_concept_id (cp_parser *, tree, tree);
-
// -------------------------------------------------------------------------- //
// Unevaluated Operand Guard
//
@@ -4882,6 +4885,8 @@ class token_pair
m_open_loc);
}
+ location_t open_location () const { return m_open_loc; }
+
private:
location_t m_open_loc;
};
@@ -4956,7 +4961,7 @@ cp_parser_statement_expr (cp_parser *parser)
This returns the tree code corresponding to the matched operator
as an int. When the current token matches a compound assignment
- opertor, the resulting tree code is the negative value of the
+ operator, the resulting tree code is the negative value of the
non-assignment operator. */
static int
@@ -5912,11 +5917,10 @@ cp_parser_id_expression (cp_parser *parser,
cp_parser_parse_tentatively (parser);
/* Try a template-id. */
- id = cp_parser_template_id (parser,
- /*template_keyword_p=*/false,
- /*check_dependency_p=*/true,
- none_type,
- declarator_p);
+ id = cp_parser_template_id_expr (parser,
+ /*template_keyword_p=*/false,
+ /*check_dependency_p=*/true,
+ declarator_p);
/* If that worked, we're done. */
if (cp_parser_parse_definitely (parser))
return id;
@@ -5991,10 +5995,9 @@ cp_parser_unqualified_id (cp_parser* parser,
template-id. */
cp_parser_parse_tentatively (parser);
/* Try a template-id. */
- id = cp_parser_template_id (parser, template_keyword_p,
- check_dependency_p,
- none_type,
- declarator_p);
+ id = cp_parser_template_id_expr (parser, template_keyword_p,
+ check_dependency_p,
+ declarator_p);
/* If it worked, we're done. */
if (cp_parser_parse_definitely (parser))
return id;
@@ -6003,10 +6006,9 @@ cp_parser_unqualified_id (cp_parser* parser,
}
case CPP_TEMPLATE_ID:
- return cp_parser_template_id (parser, template_keyword_p,
- check_dependency_p,
- none_type,
- declarator_p);
+ return cp_parser_template_id_expr (parser, template_keyword_p,
+ check_dependency_p,
+ declarator_p);
case CPP_COMPL:
{
@@ -6247,10 +6249,9 @@ cp_parser_unqualified_id (cp_parser* parser,
/* This could be a template-id, so we try that first. */
cp_parser_parse_tentatively (parser);
/* Try a template-id. */
- id = cp_parser_template_id (parser, template_keyword_p,
- /*check_dependency_p=*/true,
- none_type,
- declarator_p);
+ id = cp_parser_template_id_expr (parser, template_keyword_p,
+ /*check_dependency_p=*/true,
+ declarator_p);
/* If that worked, we're done. */
if (cp_parser_parse_definitely (parser))
return id;
@@ -9039,6 +9040,7 @@ cp_parser_delete_expression (cp_parser* parser)
bool global_scope_p;
bool array_p;
tree expression;
+ location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
/* Look for the optional `::' operator. */
global_scope_p
@@ -9068,8 +9070,18 @@ cp_parser_delete_expression (cp_parser* parser)
if (cp_parser_non_integral_constant_expression (parser, NIC_DEL))
return error_mark_node;
- return delete_sanity (expression, NULL_TREE, array_p, global_scope_p,
- tf_warning_or_error);
+ /* Construct a location e.g.:
+ delete [ ] ptr
+ ^~~~~~~~~~~~~~
+ with caret == start at the start of the "delete" token, and
+ the end at the end of the final token we consumed. */
+ location_t combined_loc = make_location (start_loc, start_loc,
+ parser->lexer);
+ expression = delete_sanity (expression, NULL_TREE, array_p,
+ global_scope_p, tf_warning_or_error);
+ protected_set_expr_location (expression, combined_loc);
+
+ return expression;
}
/* Returns 1 if TOKEN may start a cast-expression and isn't '++', '--',
@@ -9652,6 +9664,8 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
current.lhs = error_mark_node;
else
{
+ current.lhs.maybe_add_location_wrapper ();
+ rhs.maybe_add_location_wrapper ();
current.lhs
= build_min (current.tree_type,
TREE_CODE_CLASS (current.tree_type)
@@ -14083,10 +14097,26 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
case RID_CONCEPT:
ds = ds_concept;
cp_lexer_consume_token (parser->lexer);
+
+ /* Warn for concept as a decl-specifier. We'll rewrite these as
+ concept declarations later. */
+ if (!flag_concepts_ts)
+ {
+ cp_token *next = cp_lexer_peek_token (parser->lexer);
+ if (next->keyword == RID_BOOL)
+ pedwarn (next->location, 0, "the %<bool%> keyword is not "
+ "allowed in a C++20 concept definition");
+ else
+ pedwarn (token->location, 0, "C++20 concept definition syntax "
+ "is %<concept <name> = <expr>%> ");
+ }
+
/* In C++20 a concept definition is just 'concept name = expr;'
- Support that syntax by pretending we've seen 'bool'. */
+ Support that syntax as a TS extension by pretending we've seen
+ the 'bool' specifier. */
if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)
- && cp_lexer_nth_token_is (parser->lexer, 2, CPP_EQ))
+ && cp_lexer_nth_token_is (parser->lexer, 2, CPP_EQ)
+ && !decl_specs->any_type_specifiers_p)
{
cp_parser_set_decl_spec_type (decl_specs, boolean_type_node,
token, /*type_definition*/false);
@@ -15827,15 +15857,15 @@ get_unqualified_id (cp_declarator *declarator)
return NULL_TREE;
}
-/* Returns true if DECL represents a constrained-parameter. */
+/* Returns true if TYPE would declare a constrained constrained-parameter. */
static inline bool
-is_constrained_parameter (tree decl)
+is_constrained_parameter (tree type)
{
- return (decl
- && TREE_CODE (decl) == TYPE_DECL
- && CONSTRAINED_PARM_CONCEPT (decl)
- && DECL_P (CONSTRAINED_PARM_CONCEPT (decl)));
+ return (type
+ && TREE_CODE (type) == TYPE_DECL
+ && CONSTRAINED_PARM_CONCEPT (type)
+ && DECL_P (CONSTRAINED_PARM_CONCEPT (type)));
}
/* Returns true if PARM declares a constrained-parameter. */
@@ -15921,8 +15951,8 @@ cp_parser_constrained_template_template_parm (cp_parser *parser,
declarator. */
static tree
-constrained_non_type_template_parm (bool *is_non_type,
- cp_parameter_declarator *parm)
+cp_parser_constrained_non_type_template_parm (bool *is_non_type,
+ cp_parameter_declarator *parm)
{
*is_non_type = true;
cp_declarator *decl = parm->declarator;
@@ -15939,20 +15969,13 @@ constrained_non_type_template_parm (bool *is_non_type,
static tree
finish_constrained_parameter (cp_parser *parser,
cp_parameter_declarator *parmdecl,
- bool *is_non_type,
- bool *is_parameter_pack)
+ bool *is_non_type)
{
tree decl = parmdecl->decl_specifiers.type;
tree id = get_unqualified_id (parmdecl->declarator);
tree def = parmdecl->default_argument;
tree proto = DECL_INITIAL (decl);
- /* A template parameter constrained by a variadic concept shall also
- be declared as a template parameter pack. */
- bool is_variadic = template_parameter_pack_p (proto);
- if (is_variadic && !*is_parameter_pack)
- cp_parser_error (parser, "variadic constraint introduced without %<...%>");
-
/* Build the parameter. Return an error if the declarator was invalid. */
tree parm;
if (TREE_CODE (proto) == TYPE_DECL)
@@ -15961,7 +15984,7 @@ finish_constrained_parameter (cp_parser *parser,
parm = cp_parser_constrained_template_template_parm (parser, proto, id,
parmdecl);
else
- parm = constrained_non_type_template_parm (is_non_type, parmdecl);
+ parm = cp_parser_constrained_non_type_template_parm (is_non_type, parmdecl);
if (parm == error_mark_node)
return error_mark_node;
@@ -15976,14 +15999,13 @@ finish_constrained_parameter (cp_parser *parser,
/* Returns true if the parsed type actually represents the declaration
of a type template-parameter. */
-static inline bool
+static bool
declares_constrained_type_template_parameter (tree type)
{
return (is_constrained_parameter (type)
&& TREE_CODE (TREE_TYPE (type)) == TEMPLATE_TYPE_PARM);
}
-
/* Returns true if the parsed type actually represents the declaration of
a template template-parameter. */
@@ -16159,12 +16181,11 @@ cp_parser_template_parameter (cp_parser* parser, bool *is_non_type,
cp_lexer_consume_token (parser->lexer);
}
- // The parameter may have been constrained.
+ /* The parameter may have been constrained type parameter. */
if (is_constrained_parameter (parameter_declarator))
return finish_constrained_parameter (parser,
parameter_declarator,
- is_non_type,
- is_parameter_pack);
+ is_non_type);
// Now we're sure that the parameter is a non-type parameter.
*is_non_type = true;
@@ -16290,8 +16311,8 @@ cp_parser_type_parameter (cp_parser* parser, bool *is_parameter_pack)
if (flag_concepts)
{
tree reqs = get_shorthand_constraints (current_template_parms);
- if (tree r = cp_parser_requires_clause_opt (parser))
- reqs = conjoin_constraints (reqs, normalize_expression (r));
+ if (tree dreqs = cp_parser_requires_clause_opt (parser))
+ reqs = combine_constraint_expressions (reqs, dreqs);
TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = reqs;
}
@@ -16397,6 +16418,7 @@ cp_parser_template_id (cp_parser *parser,
/* If the next token corresponds to a template-id, there is no need
to reparse it. */
cp_token *token = cp_lexer_peek_token (parser->lexer);
+
if (token->type == CPP_TEMPLATE_ID)
{
cp_lexer_consume_token (parser->lexer);
@@ -16539,7 +16561,7 @@ cp_parser_template_id (cp_parser *parser,
= make_location (token->location, token->location, parser->lexer);
/* Check for concepts autos where they don't belong. We could
- identify types in some cases of idnetifier TEMPL, looking ahead
+ identify types in some cases of identifier TEMPL, looking ahead
for a CPP_SCOPE, but that would buy us nothing: we accept auto in
types. We reject them in functions, but if what we have is an
identifier, even with none_type we can't conclude it's NOT a
@@ -16565,11 +16587,13 @@ cp_parser_template_id (cp_parser *parser,
template_id
= finish_template_type (templ, arguments, entering_scope);
}
- /* A template-like identifier may be a partial concept id. */
- else if (flag_concepts
- && (template_id = (cp_parser_maybe_partial_concept_id
- (parser, templ, arguments))))
- return template_id;
+ else if (concept_definition_p (templ))
+ {
+ /* The caller will decide whether this is a concept check or type
+ constraint. */
+ template_id = build2_loc (combined_loc, TEMPLATE_ID_EXPR,
+ boolean_type_node, templ, arguments);
+ }
else if (variable_template_p (templ))
{
template_id = lookup_template_variable (templ, arguments);
@@ -16626,6 +16650,23 @@ cp_parser_template_id (cp_parser *parser,
return template_id;
}
+/* Like cp_parser_template_id, called in non-type context. */
+
+static tree
+cp_parser_template_id_expr (cp_parser *parser,
+ bool template_keyword_p,
+ bool check_dependency_p,
+ bool is_declaration)
+{
+ tree x = cp_parser_template_id (parser, template_keyword_p, check_dependency_p,
+ none_type, is_declaration);
+ if (TREE_CODE (x) == TEMPLATE_ID_EXPR
+ && concept_check_p (x))
+ /* We didn't check the arguments in cp_parser_template_id; do that now. */
+ return build_concept_id (x);
+ return x;
+}
+
/* Parse a template-name.
template-name:
@@ -17046,11 +17087,7 @@ cp_parser_template_argument (cp_parser* parser)
/*check_dependency=*/true,
/*ambiguous_decls=*/NULL,
argument_start_token->location);
- /* Handle a constrained-type-specifier for a non-type template
- parameter. */
- if (tree decl = cp_parser_maybe_concept_name (parser, argument))
- argument = decl;
- else if (TREE_CODE (argument) != TEMPLATE_DECL
+ if (TREE_CODE (argument) != TEMPLATE_DECL
&& TREE_CODE (argument) != UNBOUND_CLASS_TEMPLATE)
cp_parser_error (parser, "expected template-name");
}
@@ -17799,7 +17836,7 @@ cp_parser_simple_type_specifier (cp_parser* parser,
else if (!flag_concepts)
pedwarn (token->location, 0,
"use of %<auto%> in parameter declaration "
- "only available with %<-fconcepts%>");
+ "only available with %<-fconcepts-ts%>");
}
else
type = make_auto ();
@@ -17915,6 +17952,10 @@ cp_parser_simple_type_specifier (cp_parser* parser,
if (flags & CP_PARSER_FLAGS_OPTIONAL)
cp_parser_parse_tentatively (parser);
+ /* Remember current tentative parsing state -- if we know we need
+ a type, we can give better diagnostics here. */
+ bool tent = cp_parser_parsing_tentatively (parser);
+
token = cp_lexer_peek_token (parser->lexer);
/* Look for the optional `::' operator. */
@@ -17969,13 +18010,44 @@ cp_parser_simple_type_specifier (cp_parser* parser,
type = NULL_TREE;
}
+ if (!type && flag_concepts && decl_specs)
+ {
+ /* Try for a type-constraint with template arguments. We check
+ decl_specs here to avoid trying this for a functional cast. */
+
+ cp_parser_parse_tentatively (parser);
+
+ type = cp_parser_template_id (parser,
+ /*template_keyword_p=*/false,
+ /*check_dependency_p=*/true,
+ none_type,
+ /*is_declaration=*/false);
+ if (type && concept_check_p (type))
+ {
+ location_t loc = EXPR_LOCATION (type);
+ type = cp_parser_placeholder_type_specifier (parser, loc,
+ type, tent);
+ if (tent && type == error_mark_node)
+ /* Perhaps it's a concept-check expression. */
+ cp_parser_simulate_error (parser);
+ }
+ else
+ cp_parser_simulate_error (parser);
+
+ if (!cp_parser_parse_definitely (parser))
+ type = NULL_TREE;
+ }
+
if (!type && cxx_dialect >= cxx17)
{
- /* Try class template argument deduction. */
+ /* Try class template argument deduction or type-constraint without
+ template arguments. */
tree name = cp_parser_identifier (parser);
if (name && TREE_CODE (name) == IDENTIFIER_NODE
&& parser->scope != error_mark_node)
{
+ location_t loc
+ = cp_lexer_previous_token (parser->lexer)->location;
tree tmpl = cp_parser_lookup_name (parser, name,
none_type,
/*is_template=*/false,
@@ -17987,6 +18059,9 @@ cp_parser_simple_type_specifier (cp_parser* parser,
&& (DECL_CLASS_TEMPLATE_P (tmpl)
|| DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl)))
type = make_template_placeholder (tmpl);
+ else if (flag_concepts && tmpl && concept_definition_p (tmpl))
+ type = cp_parser_placeholder_type_specifier (parser, loc,
+ tmpl, tent);
else
{
type = error_mark_node;
@@ -18058,6 +18133,140 @@ cp_parser_simple_type_specifier (cp_parser* parser,
return type;
}
+/* Parse the remainder of a placholder-type-specifier.
+
+ placeholder-type-specifier:
+ type-constraint_opt auto
+ type-constraint_opt decltype(auto)
+
+ The raw form of the constraint is parsed in cp_parser_simple_type_specifier
+ and passed as TMPL. This function converts TMPL to an actual type-constraint,
+ parses the placeholder type, and performs some contextual syntactic analysis.
+
+ LOC provides the location of the template name.
+
+ TENTATIVE is true if the type-specifier parsing is tentative; in that case,
+ don't give an error if TMPL isn't a valid type-constraint, as the template-id
+ might actually be a concept-check,
+
+ Note that the Concepts TS allows the auto or decltype(auto) to be
+ omitted in a constrained-type-specifier. */
+
+tree
+cp_parser_placeholder_type_specifier (cp_parser *parser, location_t loc,
+ tree tmpl, bool tentative)
+{
+ if (tmpl == error_mark_node)
+ return error_mark_node;
+
+ tree orig_tmpl = tmpl;
+
+ /* Get the arguments as written for subsequent analysis. */
+ tree args = NULL_TREE;
+ if (TREE_CODE (tmpl) == TEMPLATE_ID_EXPR)
+ {
+ args = TREE_OPERAND (tmpl, 1);
+ tmpl = TREE_OPERAND (tmpl, 0);
+ }
+ if (args == NULL_TREE)
+ /* A concept-name with no arguments can't be an expression. */
+ tentative = false;
+
+ tsubst_flags_t complain = tentative ? tf_none : tf_warning_or_error;
+
+ /* Get the concept and prototype parameter for the constraint. */
+ tree_pair info = finish_type_constraints (tmpl, args, complain);
+ tree con = info.first;
+ tree proto = info.second;
+ if (con == error_mark_node)
+ return error_mark_node;
+
+ /* As per the standard, require auto or decltype(auto), except in some
+ cases (template parameter lists, -fconcepts-ts enabled). */
+ cp_token *placeholder = NULL, *open_paren = NULL, *close_paren = NULL;
+ if (cxx_dialect >= cxx2a)
+ {
+ if (cp_lexer_next_token_is_keyword (parser->lexer, RID_AUTO))
+ placeholder = cp_lexer_consume_token (parser->lexer);
+ else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_DECLTYPE))
+ {
+ placeholder = cp_lexer_consume_token (parser->lexer);
+ open_paren = cp_parser_require (parser, CPP_OPEN_PAREN,
+ RT_OPEN_PAREN);
+ cp_parser_require_keyword (parser, RID_AUTO, RT_AUTO);
+ close_paren = cp_parser_require (parser, CPP_CLOSE_PAREN,
+ RT_CLOSE_PAREN,
+ open_paren->location);
+ }
+ }
+
+ /* A type constraint constrains a contextually determined type or type
+ parameter pack. However, the the Concepts TS does allow concepts
+ to introduce non-type and template template parameters. */
+ if (TREE_CODE (proto) != TYPE_DECL)
+ {
+ if (!flag_concepts_ts
+ || !processing_template_parmlist)
+ {
+ error_at (loc, "%qE does not constrain a type", DECL_NAME (con));
+ inform (DECL_SOURCE_LOCATION (con), "concept defined here");
+ return error_mark_node;
+ }
+ }
+
+ /* In a template parameter list, a type-parameter can be introduced
+ by type-constraints alone. */
+ if (processing_template_parmlist && !placeholder)
+ return build_constrained_parameter (con, proto, args);
+
+ /* Diagnose issues placeholder issues. */
+ if (!flag_concepts_ts
+ && !parser->in_result_type_constraint_p
+ && !placeholder)
+ {
+ tree id = build_nt (TEMPLATE_ID_EXPR, tmpl, args);
+ tree expr = DECL_P (orig_tmpl) ? DECL_NAME (con) : id;
+ error_at (input_location,
+ "expected %<auto%> or %<decltype(auto)%> after %qE", expr);
+ /* Fall through. This is an error of omission. */
+ }
+ else if (parser->in_result_type_constraint_p && placeholder)
+ {
+ /* A trailing return type only allows type-constraints. */
+ error_at (input_location,
+ "unexpected placeholder in constrained result type");
+ }
+
+ /* In a parameter-declaration-clause, a placeholder-type-specifier
+ results in an invented template parameter. */
+ if (parser->auto_is_implicit_function_template_parm_p)
+ {
+ if (placeholder && token_is_decltype (placeholder))
+ {
+ location_t loc = make_location (placeholder->location,
+ placeholder->location,
+ close_paren->location);
+ error_at (loc, "cannot declare a parameter with %<decltype(auto)%>");
+ return error_mark_node;
+ }
+ tree parm = build_constrained_parameter (con, proto, args);
+ return synthesize_implicit_template_parm (parser, parm);
+ }
+
+ /* Determine if the type should be deduced using template argument
+ deduction or decltype deduction. Note that the latter is always
+ used for type-constraints in trailing return types. */
+ bool decltype_p = placeholder
+ ? placeholder->keyword == RID_DECLTYPE
+ : parser->in_result_type_constraint_p;
+
+ /* Otherwise, this is the type of a variable or return type. */
+ if (decltype_p)
+ return make_constrained_decltype_auto (con, args);
+ else
+ return make_constrained_auto (con, args);
+}
+
/* Parse a type-name.
type-name:
@@ -18130,8 +18339,6 @@ cp_parser_type_name (cp_parser* parser, bool typename_keyword_p)
&& TREE_CODE (type_decl) == TYPE_DECL
&& TYPE_DECL_ALIAS_P (type_decl))
gcc_assert (DECL_TEMPLATE_INSTANTIATION (type_decl));
- else if (is_constrained_parameter (type_decl))
- /* Don't do anything. */ ;
else
cp_parser_simulate_error (parser);
@@ -18143,105 +18350,6 @@ cp_parser_type_name (cp_parser* parser, bool typename_keyword_p)
return type_decl;
}
-/* Check if DECL and ARGS can form a constrained-type-specifier.
- If ARGS is non-null, we try to form a concept check of the
- form DECL<?, ARGS> where ? is a wildcard that matches any
- kind of template argument. If ARGS is NULL, then we try to
- form a concept check of the form DECL<?>. */
-
-static tree
-cp_parser_maybe_constrained_type_specifier (cp_parser *parser,
- tree decl, tree args)
-{
- gcc_assert (args ? TREE_CODE (args) == TREE_VEC : true);
-
- /* If we a constrained-type-specifier cannot be deduced. */
- if (parser->prevent_constrained_type_specifiers)
- return NULL_TREE;
-
- /* A constrained type specifier can only be found in an
- overload set or as a reference to a template declaration.
-
- FIXME: This might be masking a bug. It's possible that
- that the deduction below is causing template specializations
- to be formed with the wildcard as an argument. */
- if (TREE_CODE (decl) != OVERLOAD && TREE_CODE (decl) != TEMPLATE_DECL)
- return NULL_TREE;
-
- /* Try to build a call expression that evaluates the
- concept. This can fail if the overload set refers
- only to non-templates. */
- tree placeholder = build_nt (WILDCARD_DECL);
- tree check = build_concept_check (decl, placeholder, args);
- if (check == error_mark_node)
- return NULL_TREE;
-
- /* Deduce the checked constraint and the prototype parameter.
-
- FIXME: In certain cases, failure to deduce should be a
- diagnosable error. */
- tree conc;
- tree proto;
- if (!deduce_constrained_parameter (check, conc, proto))
- return NULL_TREE;
-
- /* In template parameter scope, this results in a constrained
- parameter. Return a descriptor of that parm. */
- if (processing_template_parmlist)
- return build_constrained_parameter (conc, proto, args);
-
- /* In a parameter-declaration-clause, constrained-type
- specifiers result in invented template parameters. */
- if (parser->auto_is_implicit_function_template_parm_p)
- {
- tree x = build_constrained_parameter (conc, proto, args);
- return synthesize_implicit_template_parm (parser, x);
- }
- else
- {
- /* Otherwise, we're in a context where the constrained
- type name is deduced and the constraint applies
- after deduction. */
- return make_constrained_auto (conc, args);
- }
-
- return NULL_TREE;
-}
-
-/* If DECL refers to a concept, return a TYPE_DECL representing
- the result of using the constrained type specifier in the
- current context. DECL refers to a concept if
-
- - it is an overload set containing a function concept taking a single
- type argument, or
-
- - it is a variable concept taking a single type argument. */
-
-static tree
-cp_parser_maybe_concept_name (cp_parser* parser, tree decl)
-{
- if (flag_concepts
- && (TREE_CODE (decl) == OVERLOAD
- || BASELINK_P (decl)
- || variable_concept_p (decl)))
- return cp_parser_maybe_constrained_type_specifier (parser, decl, NULL_TREE);
- else
- return NULL_TREE;
-}
-
-/* Check if DECL and ARGS form a partial-concept-id. If so,
- assign ID to the resulting constrained placeholder.
-
- Returns true if the partial-concept-id designates a placeholder
- and false otherwise. Note that *id is set to NULL_TREE in
- this case. */
-
-static tree
-cp_parser_maybe_partial_concept_id (cp_parser *parser, tree decl, tree args)
-{
- return cp_parser_maybe_constrained_type_specifier (parser, decl, args);
-}
-
/* Parse a non-class type-name, that is, either an enum-name, a typedef-name,
or a concept-name.
@@ -18272,10 +18380,6 @@ cp_parser_nonclass_name (cp_parser* parser)
type_decl = strip_using_decl (type_decl);
- /* If we found an overload set, then it may refer to a concept-name. */
- if (tree decl = cp_parser_maybe_concept_name (parser, type_decl))
- type_decl = decl;
-
if (TREE_CODE (type_decl) != TYPE_DECL
&& (objc_is_id (identifier) || objc_is_class_name (identifier)))
{
@@ -25865,6 +25969,7 @@ cp_parser_throw_expression (cp_parser* parser)
{
tree expression;
cp_token* token;
+ location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
cp_parser_require_keyword (parser, RID_THROW, RT_THROW);
token = cp_lexer_peek_token (parser->lexer);
@@ -25880,7 +25985,17 @@ cp_parser_throw_expression (cp_parser* parser)
else
expression = cp_parser_assignment_expression (parser);
- return build_throw (expression);
+ /* Construct a location e.g.:
+ throw x
+ ^~~~~~~
+ with caret == start at the start of the "throw" token, and
+ the end at the end of the final token we consumed. */
+ location_t combined_loc = make_location (start_loc, start_loc,
+ parser->lexer);
+ expression = build_throw (expression);
+ protected_set_expr_location (expression, combined_loc);
+
+ return expression;
}
/* Parse a yield-expression.
@@ -26937,30 +27052,279 @@ cp_parser_label_declaration (cp_parser* parser)
}
// -------------------------------------------------------------------------- //
+// Concept definitions
+
+static tree
+cp_parser_concept_definition (cp_parser *parser)
+{
+ gcc_assert (cp_lexer_next_token_is_keyword (parser->lexer, RID_CONCEPT));
+ cp_lexer_consume_token (parser->lexer);
+
+ cp_expr id = cp_parser_identifier (parser);
+ if (id == error_mark_node)
+ {
+ cp_parser_skip_to_end_of_statement (parser);
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+ return NULL_TREE;
+ }
+
+ if (!cp_parser_require (parser, CPP_EQ, RT_EQ))
+ {
+ cp_parser_skip_to_end_of_statement (parser);
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+ return error_mark_node;
+ }
+
+ processing_constraint_expression_sentinel parsing_constraint;
+ tree init = cp_parser_constraint_expression (parser);
+ if (init == error_mark_node)
+ cp_parser_skip_to_end_of_statement (parser);
+
+ /* Consume the trailing ';'. Diagnose the problem if it isn't there,
+ but continue as if it were. */
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+
+ return finish_concept_definition (id, init);
+}
+
+// -------------------------------------------------------------------------- //
// Requires Clause
-// Parse a requires clause.
-//
-// requires-clause:
-// 'requires' logical-or-expression
-//
-// The required logical-or-expression must be a constant expression. Note
-// that we don't check that the expression is constepxr here. We defer until
-// we analyze constraints and then, we only check atomic constraints.
+/* Diagnose an expression that should appear in ()'s within a requires-clause
+ and suggest where to place those parentheses. */
+
+static void
+cp_parser_diagnose_ungrouped_constraint_plain (location_t loc)
+{
+ error_at (loc, "expression after %<requires%> must be enclosed "
+ "in parentheses");
+}
+
+static void
+cp_parser_diagnose_ungrouped_constraint_rich (location_t loc)
+{
+ gcc_rich_location richloc (loc);
+ richloc.add_fixit_insert_before ("(");
+ richloc.add_fixit_insert_after (")");
+ error_at (&richloc, "expression after %<requires%> must be enclosed "
+ "in parentheses");
+}
+
+/* Parse a primary expression within a constraint. */
+
+static cp_expr
+cp_parser_constraint_primary_expression (cp_parser *parser)
+{
+ cp_parser_parse_tentatively (parser);
+ cp_id_kind idk;
+ location_t loc = input_location;
+ cp_expr expr = cp_parser_primary_expression (parser,
+ /*address_p=*/false,
+ /*cast_p=*/false,
+ /*template_arg_p=*/false,
+ &idk);
+ expr.maybe_add_location_wrapper ();
+ if (expr != error_mark_node)
+ expr = finish_constraint_primary_expr (expr);
+ if (cp_parser_parse_definitely (parser))
+ return expr;
+
+ /* Retry the parse at a lower precedence. If that succeeds, diagnose the
+ error, but return the expression as if it were valid. */
+ cp_parser_parse_tentatively (parser);
+ expr = cp_parser_simple_cast_expression (parser);
+ if (cp_parser_parse_definitely (parser))
+ {
+ cp_parser_diagnose_ungrouped_constraint_rich (expr.get_location());
+ return expr;
+ }
+
+ /* Otherwise, something has gone wrong, but we can't generate a more
+ meaningful diagnostic or recover. */
+ cp_parser_diagnose_ungrouped_constraint_plain (loc);
+ return error_mark_node;
+}
+
+/* Examine the token following EXPR. If it is an operator in a non-logical
+ binary expression, diagnose that as an error. Returns ERROR_MARK_NODE. */
+
+static cp_expr
+cp_parser_check_non_logical_constraint (cp_parser *parser, cp_expr lhs)
+{
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+ switch (token->type)
+ {
+ default:
+ return lhs;
+
+ /* Arithmetic operators. */
+ case CPP_PLUS:
+ case CPP_MINUS:
+ case CPP_MULT:
+ case CPP_DIV:
+ case CPP_MOD:
+ /* Bitwise operators. */
+ case CPP_AND:
+ case CPP_OR:
+ case CPP_XOR:
+ case CPP_RSHIFT:
+ case CPP_LSHIFT:
+ /* Relational operators. */
+ /* FIXME: Handle '<=>'. */
+ case CPP_EQ_EQ:
+ case CPP_NOT_EQ:
+ case CPP_LESS:
+ case CPP_GREATER:
+ case CPP_LESS_EQ:
+ case CPP_GREATER_EQ:
+ /* Conditional operator */
+ case CPP_QUERY:
+ /* Pointer-to-member. */
+ case CPP_DOT_STAR:
+ case CPP_DEREF_STAR:
+ /* Assignment operators. */
+ case CPP_PLUS_EQ:
+ case CPP_MINUS_EQ:
+ case CPP_MULT_EQ:
+ case CPP_DIV_EQ:
+ case CPP_MOD_EQ:
+ case CPP_AND_EQ:
+ case CPP_OR_EQ:
+ case CPP_XOR_EQ:
+ case CPP_RSHIFT_EQ:
+ case CPP_LSHIFT_EQ:
+ break;
+
+ case CPP_EQ: {
+ /* An equal sign may be part of the the definition of a function,
+ and not an assignment operator, when parsing the expression
+ for a trailing requires-clause. For example:
+
+ template<typename T>
+ struct S {
+ S() requires C<T> = default;
+ }
+
+ This is not an error. */
+ if (cp_lexer_nth_token_is_keyword (parser->lexer, 2, RID_DELETE)
+ || cp_lexer_nth_token_is_keyword (parser->lexer, 2, RID_DEFAULT))
+ return lhs;
+
+ break;
+ }
+ }
+
+ /* Try to parse the RHS as either the remainder of a conditional-expression
+ or a logical-or-expression so we can form a good diagnostic. */
+ cp_parser_parse_tentatively (parser);
+ cp_expr rhs;
+ if (token->type == CPP_QUERY)
+ rhs = cp_parser_question_colon_clause (parser, lhs);
+ else
+ {
+ cp_lexer_consume_token (parser->lexer);
+ rhs = cp_parser_binary_expression (parser, false, false, false,
+ PREC_NOT_OPERATOR, NULL);
+ }
+
+ /* If we couldn't parse the RHS, then emit the best diagnostic we can. */
+ if (!cp_parser_parse_definitely (parser))
+ {
+ cp_parser_diagnose_ungrouped_constraint_plain (token->location);
+ return error_mark_node;
+ }
+
+ /* Otherwise, emit a fixit for the complete binary expression. */
+ location_t loc = make_location (token->location,
+ lhs.get_start(),
+ rhs.get_finish());
+ cp_parser_diagnose_ungrouped_constraint_rich (loc);
+ return error_mark_node;
+}
+
+/* Parse a constraint-logical-and-expression.
+
+ constraint-logical-and-expression:
+ primary-expression
+ constraint-logical-and-expression '&&' primary-expression */
+
+static cp_expr
+cp_parser_constraint_logical_and_expression (cp_parser *parser)
+{
+ cp_expr lhs = cp_parser_constraint_primary_expression (parser);
+ while (cp_lexer_next_token_is (parser->lexer, CPP_AND_AND))
+ {
+ cp_token *op = cp_lexer_consume_token (parser->lexer);
+ tree rhs = cp_parser_constraint_primary_expression (parser);
+ lhs = finish_constraint_and_expr (op->location, lhs, rhs);
+ }
+ return cp_parser_check_non_logical_constraint (parser, lhs);
+}
+
+/* Parse a constraint-logical-or-expression.
+
+ constraint-logical-or-expression:
+ constraint-logical-and-expression
+ constraint-logical-or-expression '||' constraint-logical-and-expression */
+
+static cp_expr
+cp_parser_constraint_logical_or_expression (cp_parser *parser)
+{
+ cp_expr lhs = cp_parser_constraint_logical_and_expression (parser);
+ while (cp_lexer_next_token_is (parser->lexer, CPP_OR_OR))
+ {
+ cp_token *op = cp_lexer_consume_token (parser->lexer);
+ cp_expr rhs = cp_parser_constraint_logical_and_expression (parser);
+ lhs = finish_constraint_or_expr (op->location, lhs, rhs);
+ }
+ return cp_parser_check_non_logical_constraint (parser, lhs);
+}
+
+/* Parse the expression after a requires-clause. This has a different grammar
+ than that in the concepts TS. */
+
static tree
-cp_parser_requires_clause (cp_parser *parser)
+cp_parser_requires_clause_expression (cp_parser *parser)
{
- // Parse the requires clause so that it is not automatically folded.
+ processing_constraint_expression_sentinel parsing_constraint;
++processing_template_decl;
- tree expr = cp_parser_binary_expression (parser, false, false,
- PREC_NOT_OPERATOR, NULL);
+ cp_expr expr = cp_parser_constraint_logical_or_expression (parser);
if (check_for_bare_parameter_packs (expr))
expr = error_mark_node;
--processing_template_decl;
return expr;
}
-// Optionally parse a requires clause:
+/* Parse a expression after a requires clause.
+
+ constraint-expression:
+ logical-or-expression
+
+ The required logical-or-expression must be a constant expression. Note
+ that we don't check that the expression is constepxr here. We defer until
+ we analyze constraints and then, we only check atomic constraints. */
+
+static tree
+cp_parser_constraint_expression (cp_parser *parser)
+{
+ processing_constraint_expression_sentinel parsing_constraint;
+ ++processing_template_decl;
+ cp_expr expr = cp_parser_binary_expression (parser, false, true,
+ PREC_NOT_OPERATOR, NULL);
+ if (check_for_bare_parameter_packs (expr))
+ expr = error_mark_node;
+ --processing_template_decl;
+ expr.maybe_add_location_wrapper ();
+ return expr;
+}
+
+/* Optionally parse a requires clause:
+
+ requires-clause:
+ `requires` constraint-logical-or-expression.
+ [ConceptsTS]
+ `requires constraint-expression. */
+
static tree
cp_parser_requires_clause_opt (cp_parser *parser)
{
@@ -26971,17 +27335,21 @@ cp_parser_requires_clause_opt (cp_parser *parser)
&& tok->u.value == ridpointers[RID_REQUIRES])
{
error_at (cp_lexer_peek_token (parser->lexer)->location,
- "%<requires%> only available with %<-fconcepts%>");
+ "%<requires%> only available with "
+ "%<-std=c++2a%> or %<-fconcepts%>");
/* Parse and discard the requires-clause. */
cp_lexer_consume_token (parser->lexer);
- cp_parser_requires_clause (parser);
+ cp_parser_constraint_expression (parser);
}
return NULL_TREE;
}
cp_lexer_consume_token (parser->lexer);
- return cp_parser_requires_clause (parser);
-}
+ if (!flag_concepts_ts)
+ return cp_parser_requires_clause_expression (parser);
+ else
+ return cp_parser_constraint_expression (parser);
+}
/*---------------------------------------------------------------------------
Requires expressions
@@ -26991,6 +27359,7 @@ cp_parser_requires_clause_opt (cp_parser *parser)
requirement-expression:
'requires' requirement-parameter-list [opt] requirement-body */
+
static tree
cp_parser_requires_expression (cp_parser *parser)
{
@@ -27008,6 +27377,9 @@ cp_parser_requires_expression (cp_parser *parser)
return error_mark_node;
}
+ /* This is definitely a requires-expression. */
+ cp_parser_commit_to_tentative_parse (parser);
+
tree parms, reqs;
{
/* Local parameters are delared as variables within the scope
@@ -27048,13 +27420,15 @@ cp_parser_requires_expression (cp_parser *parser)
/* This needs to happen after pop_bindings_and_leave_scope, as it reverses
the parm chain. */
grokparms (parms, &parms);
- return finish_requires_expr (parms, reqs);
+ loc = make_location (loc, loc, parser->lexer);
+ return finish_requires_expr (loc, parms, reqs);
}
/* Parse a parameterized requirement.
requirement-parameter-list:
'(' parameter-declaration-clause ')' */
+
static tree
cp_parser_requirement_parameter_list (cp_parser *parser)
{
@@ -27082,7 +27456,7 @@ cp_parser_requirement_body (cp_parser *parser)
if (!braces.require_open (parser))
return error_mark_node;
- tree reqs = cp_parser_requirement_list (parser);
+ tree reqs = cp_parser_requirement_seq (parser);
if (!braces.require_close (parser))
return error_mark_node;
@@ -27090,34 +27464,28 @@ cp_parser_requirement_body (cp_parser *parser)
return reqs;
}
-/* Parse a list of requirements.
+/* Parse a sequence of requirements.
- requirement-list:
+ requirement-seq:
requirement
- requirement-list ';' requirement[opt] */
+ requirement-seq requirement */
+
static tree
-cp_parser_requirement_list (cp_parser *parser)
+cp_parser_requirement_seq (cp_parser *parser)
{
tree result = NULL_TREE;
- while (true)
+ do
{
tree req = cp_parser_requirement (parser);
- if (req == error_mark_node)
- return error_mark_node;
+ if (req != error_mark_node)
+ result = tree_cons (NULL_TREE, req, result);
+ } while (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_BRACE));
- result = tree_cons (NULL_TREE, req, result);
-
- /* If we see a semi-colon, consume it. */
- if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
- cp_lexer_consume_token (parser->lexer);
-
- /* Stop processing at the end of the list. */
- if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE))
- break;
- }
+ /* If there are no valid requirements, this is not a valid expression. */
+ if (!result)
+ return error_mark_node;
- /* Reverse the order of requirements so they are analyzed in
- declaration order. */
+ /* Reverse the order of requirements so they are analyzed in order. */
return nreverse (result);
}
@@ -27128,6 +27496,7 @@ cp_parser_requirement_list (cp_parser *parser)
compound-requirement
type-requirement
nested-requirement */
+
static tree
cp_parser_requirement (cp_parser *parser)
{
@@ -27145,17 +27514,26 @@ cp_parser_requirement (cp_parser *parser)
simple-requirement:
expression ';' */
+
static tree
cp_parser_simple_requirement (cp_parser *parser)
{
- tree expr = cp_parser_expression (parser, NULL, false, false);
+ location_t start = cp_lexer_peek_token (parser->lexer)->location;
+ cp_expr expr = cp_parser_expression (parser, NULL, false, false);
+ if (expr == error_mark_node)
+ cp_parser_skip_to_end_of_statement (parser);
+
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+
if (!expr || expr == error_mark_node)
return error_mark_node;
- if (!cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON))
- return error_mark_node;
+ /* Sometimes we don't get locations, so use the cached token location
+ as a reasonable approximation. */
+ if (expr.get_location() == UNKNOWN_LOCATION)
+ expr.set_location (start);
- return finish_simple_requirement (expr);
+ return finish_simple_requirement (expr.get_location (), expr);
}
/* Parse a type requirement
@@ -27166,16 +27544,18 @@ cp_parser_simple_requirement (cp_parser *parser)
required-type-name:
type-name
'template' [opt] simple-template-id */
+
static tree
cp_parser_type_requirement (cp_parser *parser)
{
- cp_lexer_consume_token (parser->lexer);
+ cp_token *start_tok = cp_lexer_consume_token (parser->lexer);
+ location_t loc = cp_lexer_peek_token (parser->lexer)->location;
// Save the scope before parsing name specifiers.
tree saved_scope = parser->scope;
tree saved_object_scope = parser->object_scope;
tree saved_qualifying_scope = parser->qualifying_scope;
- cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/true);
+ cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false);
cp_parser_nested_name_specifier_opt (parser,
/*typename_keyword_p=*/true,
/*check_dependency_p=*/false,
@@ -27207,18 +27587,20 @@ cp_parser_type_requirement (cp_parser *parser)
if (type == error_mark_node)
cp_parser_skip_to_end_of_statement (parser);
- if (!cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON))
- return error_mark_node;
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+
if (type == error_mark_node)
return error_mark_node;
- return finish_type_requirement (type);
+ loc = make_location (loc, start_tok->location, parser->lexer);
+ return finish_type_requirement (loc, type);
}
/* Parse a compound requirement
compound-requirement:
'{' expression '}' 'noexcept' [opt] trailing-return-type [opt] ';' */
+
static tree
cp_parser_compound_requirement (cp_parser *parser)
{
@@ -27227,12 +27609,26 @@ cp_parser_compound_requirement (cp_parser *parser)
if (!braces.require_open (parser))
return error_mark_node;
+ cp_token *expr_token = cp_lexer_peek_token (parser->lexer);
+
tree expr = cp_parser_expression (parser, NULL, false, false);
- if (!expr || expr == error_mark_node)
- return error_mark_node;
+ if (expr == error_mark_node)
+ cp_parser_skip_to_closing_brace (parser);
if (!braces.require_close (parser))
- return error_mark_node;
+ {
+ cp_parser_skip_to_end_of_statement (parser);
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+ return error_mark_node;
+ }
+
+ /* If the expression was invalid, skip the remainder of the requirement. */
+ if (!expr || expr == error_mark_node)
+ {
+ cp_parser_skip_to_end_of_statement (parser);
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+ return error_mark_node;
+ }
/* Parse the optional noexcept. */
bool noexcept_p = false;
@@ -27247,29 +27643,69 @@ cp_parser_compound_requirement (cp_parser *parser)
if (cp_lexer_next_token_is (parser->lexer, CPP_DEREF))
{
cp_lexer_consume_token (parser->lexer);
+ cp_token *tok = cp_lexer_peek_token (parser->lexer);
+
bool saved_result_type_constraint_p = parser->in_result_type_constraint_p;
parser->in_result_type_constraint_p = true;
+ /* C++2a allows either a type-id or a type-constraint. Parsing
+ a type-id will subsume the parsing for a type-constraint but
+ allow for more syntactic forms (e.g., const C<T>*). */
type = cp_parser_trailing_type_id (parser);
parser->in_result_type_constraint_p = saved_result_type_constraint_p;
if (type == error_mark_node)
return error_mark_node;
+
+ location_t type_loc = make_location (tok->location, tok->location,
+ parser->lexer);
+
+ /* Check that we haven't written something like 'const C<T>*'. */
+ if (type_uses_auto (type))
+ {
+ if (!is_auto (type))
+ {
+ error_at (type_loc,
+ "result type is not a plain type-constraint");
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+ return error_mark_node;
+ }
+ }
+ else if (!flag_concepts_ts)
+ /* P1452R2 removed the trailing-return-type option. */
+ error_at (type_loc,
+ "return-type-requirement is not a type-constraint");
}
- return finish_compound_requirement (expr, type, noexcept_p);
+ location_t loc = make_location (expr_token->location,
+ braces.open_location (),
+ parser->lexer);
+
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+
+ if (expr == error_mark_node || type == error_mark_node)
+ return error_mark_node;
+
+ return finish_compound_requirement (loc, expr, type, noexcept_p);
}
/* Parse a nested requirement. This is the same as a requires clause.
nested-requirement:
requires-clause */
+
static tree
cp_parser_nested_requirement (cp_parser *parser)
{
- cp_lexer_consume_token (parser->lexer);
- tree req = cp_parser_requires_clause (parser);
+ gcc_assert (cp_lexer_next_token_is_keyword (parser->lexer, RID_REQUIRES));
+ cp_token *tok = cp_lexer_consume_token (parser->lexer);
+ location_t loc = cp_lexer_peek_token (parser->lexer)->location;
+ tree req = cp_parser_constraint_expression (parser);
+ if (req == error_mark_node)
+ cp_parser_skip_to_end_of_statement (parser);
+ loc = make_location (loc, tok->location, parser->lexer);
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
if (req == error_mark_node)
return error_mark_node;
- return finish_nested_requirement (req);
+ return finish_nested_requirement (loc, req);
}
/* Support Functions */
@@ -28196,6 +28632,11 @@ cp_parser_template_declaration_after_parameters (cp_parser* parser,
else if (cxx_dialect >= cxx11
&& cp_lexer_next_token_is_keyword (parser->lexer, RID_USING))
decl = cp_parser_alias_declaration (parser);
+ else if (cxx_dialect >= cxx2a /* Implies flag_concept. */
+ && cp_lexer_next_token_is_keyword (parser->lexer, RID_CONCEPT)
+ && !cp_lexer_nth_token_is_keyword (parser->lexer, 2, RID_BOOL))
+ /* Allow 'concept bool' to be handled as per the TS. */
+ decl = cp_parser_concept_definition (parser);
else
{
/* There are no access checks when parsing a template, as we do not
@@ -28315,6 +28756,8 @@ cp_parser_template_introduction (cp_parser* parser, bool member_p)
tree saved_object_scope = parser->object_scope;
tree saved_qualifying_scope = parser->qualifying_scope;
+ cp_token *start_token = cp_lexer_peek_token (parser->lexer);
+
/* Look for the optional `::' operator. */
cp_parser_global_scope_opt (parser,
/*current_scope_valid_p=*/false);
@@ -28336,12 +28779,14 @@ cp_parser_template_introduction (cp_parser* parser, bool member_p)
parser->object_scope = saved_object_scope;
parser->qualifying_scope = saved_qualifying_scope;
- if (concept_name == error_mark_node)
+ if (concept_name == error_mark_node
+ || (seen_error () && !concept_definition_p (tmpl_decl)))
cp_parser_simulate_error (parser);
/* Look for opening brace for introduction. */
matching_braces braces;
braces.require_open (parser);
+ location_t open_loc = input_location;
if (!cp_parser_parse_definitely (parser))
return false;
@@ -28372,15 +28817,26 @@ cp_parser_template_introduction (cp_parser* parser, bool member_p)
}
/* Build and associate the constraint. */
- tree parms = finish_template_introduction (tmpl_decl, introduction_list);
+ location_t introduction_loc = make_location (open_loc,
+ start_token->location,
+ parser->lexer);
+ tree parms = finish_template_introduction (tmpl_decl,
+ introduction_list,
+ introduction_loc);
if (parms && parms != error_mark_node)
{
+ if (!flag_concepts_ts)
+ pedwarn (introduction_loc, 0, "template-introductions"
+ " are not part of C++20 concepts [-fconcepts-ts]");
+
cp_parser_template_declaration_after_parameters (parser, parms,
member_p);
return true;
}
- error_at (token->location, "no matching concept for template-introduction");
+ if (parms == NULL_TREE)
+ error_at (token->location, "no matching concept for template-introduction");
+
return true;
}
@@ -28448,8 +28904,8 @@ cp_parser_explicit_template_declaration (cp_parser* parser, bool member_p)
if (flag_concepts)
{
tree reqs = get_shorthand_constraints (current_template_parms);
- if (tree r = cp_parser_requires_clause_opt (parser))
- reqs = conjoin_constraints (reqs, normalize_expression (r));
+ if (tree treqs = cp_parser_requires_clause_opt (parser))
+ reqs = combine_constraint_expressions (reqs, treqs);
TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = reqs;
}
@@ -29686,6 +30142,9 @@ cp_parser_required_error (cp_parser *parser,
case RT_THROW:
gmsgid = G_("expected %<throw%>");
break;
+ case RT_AUTO:
+ gmsgid = G_("expected %<auto%>");
+ break;
case RT_LABEL:
gmsgid = G_("expected %<__label__%>");
break;
@@ -35496,8 +35955,8 @@ cp_parser_oacc_clause_async (cp_parser *parser, tree list)
static tree
cp_parser_oacc_all_clauses (cp_parser *parser, omp_clause_mask mask,
- const char *where, cp_token *pragma_tok,
- bool finish_p = true)
+ const char *where, cp_token *pragma_tok,
+ bool finish_p = true)
{
tree clauses = NULL;
bool first = true;
@@ -35693,13 +36152,16 @@ cp_parser_oacc_all_clauses (cp_parser *parser, omp_clause_mask mask,
}
/* Parse all OpenMP clauses. The set clauses allowed by the directive
- is a bitmask in MASK. Return the list of clauses found; the result
- of clause default goes in *pdefault. */
+ is a bitmask in MASK. Return the list of clauses found.
+ FINISH_P set if finish_omp_clauses should be called.
+ NESTED non-zero if clauses should be terminated by closing paren instead
+ of end of pragma. If it is 2, additionally commas are required in between
+ the clauses. */
static tree
cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask,
const char *where, cp_token *pragma_tok,
- bool finish_p = true)
+ bool finish_p = true, int nested = 0)
{
tree clauses = NULL;
bool first = true;
@@ -35714,8 +36176,18 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask,
const char *c_name;
tree prev = clauses;
- if (!first && cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
- cp_lexer_consume_token (parser->lexer);
+ if (nested && cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN))
+ break;
+
+ if (!first)
+ {
+ if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+ cp_lexer_consume_token (parser->lexer);
+ else if (nested == 2)
+ error_at (cp_lexer_peek_token (parser->lexer)->location,
+ "clauses in %<simd%> trait should be separated "
+ "by %<,%>");
+ }
token = cp_lexer_peek_token (parser->lexer);
c_kind = cp_parser_omp_clause_name (parser);
@@ -36033,7 +36505,8 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask,
}
}
saw_error:
- cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+ if (!nested)
+ cp_parser_skip_to_pragma_eol (parser, pragma_tok);
if (finish_p)
{
if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNIFORM)) != 0)
@@ -39859,7 +40332,8 @@ cp_parser_oacc_wait (cp_parser *parser, cp_token *pragma_tok)
static void
cp_parser_omp_declare_simd (cp_parser *parser, cp_token *pragma_tok,
- enum pragma_context context)
+ enum pragma_context context,
+ bool variant_p)
{
bool first_p = parser->omp_declare_simd == NULL;
cp_omp_declare_simd_data data;
@@ -39867,12 +40341,22 @@ cp_parser_omp_declare_simd (cp_parser *parser, cp_token *pragma_tok,
{
data.error_seen = false;
data.fndecl_seen = false;
+ data.variant_p = variant_p;
data.tokens = vNULL;
data.clauses = NULL_TREE;
/* It is safe to take the address of a local variable; it will only be
used while this scope is live. */
parser->omp_declare_simd = &data;
}
+ else if (parser->omp_declare_simd->variant_p != variant_p)
+ {
+ error_at (pragma_tok->location,
+ "%<#pragma omp declare %s%> followed by "
+ "%<#pragma omp declare %s%>",
+ parser->omp_declare_simd->variant_p ? "variant" : "simd",
+ parser->omp_declare_simd->variant_p ? "simd" : "variant");
+ parser->omp_declare_simd->error_seen = true;
+ }
/* Store away all pragma tokens. */
while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)
@@ -39908,13 +40392,430 @@ cp_parser_omp_declare_simd (cp_parser *parser, cp_token *pragma_tok,
&& !parser->omp_declare_simd->error_seen
&& !parser->omp_declare_simd->fndecl_seen)
error_at (pragma_tok->location,
- "%<#pragma omp declare simd%> not immediately followed by "
- "function declaration or definition");
+ "%<#pragma omp declare %s%> not immediately followed by "
+ "function declaration or definition",
+ parser->omp_declare_simd->variant_p ? "variant" : "simd");
data.tokens.release ();
parser->omp_declare_simd = NULL;
}
}
+static const char *const omp_construct_selectors[] = {
+ "simd", "target", "teams", "parallel", "for", NULL };
+static const char *const omp_device_selectors[] = {
+ "kind", "isa", "arch", NULL };
+static const char *const omp_implementation_selectors[] = {
+ "vendor", "extension", "atomic_default_mem_order", "unified_address",
+ "unified_shared_memory", "dynamic_allocators", "reverse_offload", NULL };
+static const char *const omp_user_selectors[] = {
+ "condition", NULL };
+
+/* OpenMP 5.0:
+
+ trait-selector:
+ trait-selector-name[([trait-score:]trait-property[,trait-property[,...]])]
+
+ trait-score:
+ score(score-expression) */
+
+static tree
+cp_parser_omp_context_selector (cp_parser *parser, tree set, bool has_parms_p)
+{
+ tree ret = NULL_TREE;
+ do
+ {
+ tree selector;
+ if (cp_lexer_next_token_is (parser->lexer, CPP_KEYWORD)
+ || cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ selector = cp_lexer_peek_token (parser->lexer)->u.value;
+ else
+ {
+ cp_parser_error (parser, "expected trait selector name");
+ return error_mark_node;
+ }
+
+ tree properties = NULL_TREE;
+ const char *const *selectors = NULL;
+ bool allow_score = true;
+ bool allow_user = false;
+ int property_limit = 0;
+ enum { CTX_PROPERTY_NONE, CTX_PROPERTY_USER, CTX_PROPERTY_IDLIST,
+ CTX_PROPERTY_EXPR, CTX_PROPERTY_SIMD } property_kind
+ = CTX_PROPERTY_NONE;
+ switch (IDENTIFIER_POINTER (set)[0])
+ {
+ case 'c': /* construct */
+ selectors = omp_construct_selectors;
+ allow_score = false;
+ property_limit = 1;
+ property_kind = CTX_PROPERTY_SIMD;
+ break;
+ case 'd': /* device */
+ selectors = omp_device_selectors;
+ allow_score = false;
+ allow_user = true;
+ property_limit = 3;
+ property_kind = CTX_PROPERTY_IDLIST;
+ break;
+ case 'i': /* implementation */
+ selectors = omp_implementation_selectors;
+ allow_user = true;
+ property_limit = 3;
+ property_kind = CTX_PROPERTY_IDLIST;
+ break;
+ case 'u': /* user */
+ selectors = omp_user_selectors;
+ property_limit = 1;
+ property_kind = CTX_PROPERTY_EXPR;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ for (int i = 0; ; i++)
+ {
+ if (selectors[i] == NULL)
+ {
+ if (allow_user)
+ {
+ property_kind = CTX_PROPERTY_USER;
+ break;
+ }
+ else
+ {
+ error ("selector %qs not allowed for context selector "
+ "set %qs", IDENTIFIER_POINTER (selector),
+ IDENTIFIER_POINTER (set));
+ cp_lexer_consume_token (parser->lexer);
+ return error_mark_node;
+ }
+ }
+ if (i == property_limit)
+ property_kind = CTX_PROPERTY_NONE;
+ if (strcmp (selectors[i], IDENTIFIER_POINTER (selector)) == 0)
+ break;
+ }
+
+ cp_lexer_consume_token (parser->lexer);
+
+ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
+ {
+ if (property_kind == CTX_PROPERTY_NONE)
+ {
+ error ("selector %qs does not accept any properties",
+ IDENTIFIER_POINTER (selector));
+ return error_mark_node;
+ }
+
+ matching_parens parens;
+ parens.consume_open (parser);
+
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+ if (allow_score
+ && cp_lexer_next_token_is (parser->lexer, CPP_NAME)
+ && strcmp (IDENTIFIER_POINTER (token->u.value), "score") == 0
+ && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_PAREN))
+ {
+ cp_lexer_save_tokens (parser->lexer);
+ cp_lexer_consume_token (parser->lexer);
+ cp_lexer_consume_token (parser->lexer);
+ if (cp_parser_skip_to_closing_parenthesis (parser, false, false,
+ true)
+ && cp_lexer_next_token_is (parser->lexer, CPP_COLON))
+ {
+ cp_lexer_rollback_tokens (parser->lexer);
+ cp_lexer_consume_token (parser->lexer);
+
+ matching_parens parens2;
+ parens2.require_open (parser);
+ tree score = cp_parser_constant_expression (parser);
+ if (!parens2.require_close (parser))
+ cp_parser_skip_to_closing_parenthesis (parser, true,
+ false, true);
+ cp_parser_require (parser, CPP_COLON, RT_COLON);
+ if (score != error_mark_node)
+ {
+ score = fold_non_dependent_expr (score);
+ if (!value_dependent_expression_p (score)
+ && (!INTEGRAL_TYPE_P (TREE_TYPE (score))
+ || !tree_fits_shwi_p (score)))
+ error_at (token->location, "score argument must be "
+ "constant integer expression");
+ else
+ properties = tree_cons (get_identifier (" score"),
+ score, properties);
+ }
+ }
+ else
+ cp_lexer_rollback_tokens (parser->lexer);
+
+ token = cp_lexer_peek_token (parser->lexer);
+ }
+
+ switch (property_kind)
+ {
+ tree t;
+ case CTX_PROPERTY_USER:
+ do
+ {
+ t = cp_parser_constant_expression (parser);
+ if (t != error_mark_node)
+ {
+ t = fold_non_dependent_expr (t);
+ if (TREE_CODE (t) == STRING_CST)
+ properties = tree_cons (NULL_TREE, t, properties);
+ else if (!value_dependent_expression_p (t)
+ && (!INTEGRAL_TYPE_P (TREE_TYPE (t))
+ || !tree_fits_shwi_p (t)))
+ error_at (token->location, "property must be "
+ "constant integer expression or string "
+ "literal");
+ else
+ properties = tree_cons (NULL_TREE, t, properties);
+ }
+ else
+ return error_mark_node;
+
+ if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+ cp_lexer_consume_token (parser->lexer);
+ else
+ break;
+ }
+ while (1);
+ break;
+ case CTX_PROPERTY_IDLIST:
+ do
+ {
+ tree prop;
+ if (cp_lexer_next_token_is (parser->lexer, CPP_KEYWORD)
+ || cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ prop = cp_lexer_peek_token (parser->lexer)->u.value;
+ else
+ {
+ cp_parser_error (parser, "expected identifier");
+ return error_mark_node;
+ }
+ cp_lexer_consume_token (parser->lexer);
+
+ properties = tree_cons (prop, NULL_TREE, properties);
+
+ if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+ cp_lexer_consume_token (parser->lexer);
+ else
+ break;
+ }
+ while (1);
+ break;
+ case CTX_PROPERTY_EXPR:
+ t = cp_parser_constant_expression (parser);
+ if (t != error_mark_node)
+ {
+ t = fold_non_dependent_expr (t);
+ if (!value_dependent_expression_p (t)
+ && (!INTEGRAL_TYPE_P (TREE_TYPE (t))
+ || !tree_fits_shwi_p (t)))
+ error_at (token->location, "property must be "
+ "constant integer expression");
+ else
+ properties = tree_cons (NULL_TREE, t, properties);
+ }
+ else
+ return error_mark_node;
+ break;
+ case CTX_PROPERTY_SIMD:
+ if (!has_parms_p)
+ {
+ error_at (token->location, "properties for %<simd%> "
+ "selector may not be specified in "
+ "%<metadirective%>");
+ return error_mark_node;
+ }
+ properties
+ = cp_parser_omp_all_clauses (parser,
+ OMP_DECLARE_SIMD_CLAUSE_MASK,
+ "simd", NULL, true, 2);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ if (!parens.require_close (parser))
+ cp_parser_skip_to_closing_parenthesis (parser, true, false, true);
+
+ properties = nreverse (properties);
+ }
+ else if (property_kind == CTX_PROPERTY_IDLIST
+ || property_kind == CTX_PROPERTY_EXPR)
+ {
+ cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN);
+ return error_mark_node;
+ }
+
+ ret = tree_cons (selector, properties, ret);
+
+ if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+ cp_lexer_consume_token (parser->lexer);
+ else
+ break;
+ }
+ while (1);
+
+ return nreverse (ret);
+}
+
+/* OpenMP 5.0:
+
+ trait-set-selector[,trait-set-selector[,...]]
+
+ trait-set-selector:
+ trait-set-selector-name = { trait-selector[, trait-selector[, ...]] }
+
+ trait-set-selector-name:
+ constructor
+ device
+ implementation
+ user */
+
+static tree
+cp_parser_omp_context_selector_specification (cp_parser *parser,
+ bool has_parms_p)
+{
+ tree ret = NULL_TREE;
+ do
+ {
+ const char *setp = "";
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ setp
+ = IDENTIFIER_POINTER (cp_lexer_peek_token (parser->lexer)->u.value);
+ switch (setp[0])
+ {
+ case 'c':
+ if (strcmp (setp, "construct") == 0)
+ setp = NULL;
+ break;
+ case 'd':
+ if (strcmp (setp, "device") == 0)
+ setp = NULL;
+ break;
+ case 'i':
+ if (strcmp (setp, "implementation") == 0)
+ setp = NULL;
+ break;
+ case 'u':
+ if (strcmp (setp, "user") == 0)
+ setp = NULL;
+ break;
+ default:
+ break;
+ }
+ if (setp)
+ {
+ cp_parser_error (parser, "expected %<construct%>, %<device%>, "
+ "%<implementation%> or %<user%>");
+ return error_mark_node;
+ }
+
+ tree set = cp_lexer_peek_token (parser->lexer)->u.value;
+ cp_lexer_consume_token (parser->lexer);
+
+ if (!cp_parser_require (parser, CPP_EQ, RT_EQ))
+ return error_mark_node;
+
+ matching_braces braces;
+ if (!braces.require_open (parser))
+ return error_mark_node;
+
+ tree selectors
+ = cp_parser_omp_context_selector (parser, set, has_parms_p);
+ if (selectors == error_mark_node)
+ {
+ cp_parser_skip_to_closing_brace (parser);
+ ret = error_mark_node;
+ }
+ else if (ret != error_mark_node)
+ ret = tree_cons (set, selectors, ret);
+
+ braces.require_close (parser);
+
+ if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+ cp_lexer_consume_token (parser->lexer);
+ else
+ break;
+ }
+ while (1);
+
+ if (ret == error_mark_node)
+ return ret;
+ return nreverse (ret);
+}
+
+/* Finalize #pragma omp declare variant after a fndecl has been parsed, and put
+ that into "omp declare variant base" attribute. */
+
+static tree
+cp_finish_omp_declare_variant (cp_parser *parser, cp_token *pragma_tok,
+ tree attrs)
+{
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ {
+ fail:
+ cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+ return attrs;
+ }
+
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+ tree variant;
+ tree name = cp_parser_id_expression (parser, /*template_p=*/false,
+ /*check_dependency_p=*/true,
+ /*template_p=*/NULL,
+ /*declarator_p=*/false,
+ /*optional_p=*/false);
+ if (identifier_p (name))
+ variant = cp_parser_lookup_name_simple (parser, name, token->location);
+ else
+ variant = name;
+ if (variant == error_mark_node)
+ {
+ cp_parser_name_lookup_error (parser, name, variant, NLE_NULL,
+ token->location);
+ variant = error_mark_node;
+ }
+
+ parens.require_close (parser);
+
+ const char *clause = "";
+ location_t match_loc = cp_lexer_peek_token (parser->lexer)->location;
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ clause = IDENTIFIER_POINTER (cp_lexer_peek_token (parser->lexer)->u.value);
+ if (strcmp (clause, "match"))
+ {
+ cp_parser_error (parser, "expected %<match%>");
+ goto fail;
+ }
+
+ cp_lexer_consume_token (parser->lexer);
+
+ if (!parens.require_open (parser))
+ goto fail;
+
+ tree ctx = cp_parser_omp_context_selector_specification (parser, true);
+ if (ctx == error_mark_node)
+ goto fail;
+ ctx = c_omp_check_context_selector (match_loc, ctx);
+ if (ctx != error_mark_node && variant != error_mark_node)
+ {
+ attrs = tree_cons (get_identifier ("omp declare variant base"),
+ build_tree_list (variant, ctx), attrs);
+ if (processing_template_decl)
+ ATTR_IS_DEPENDENT (attrs) = 1;
+ }
+
+ parens.require_close (parser);
+ cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+ return attrs;
+}
+
+
/* Finalize #pragma omp declare simd clauses after direct declarator has
been parsed, and put that into "omp declare simd" attribute. */
@@ -39927,8 +40828,9 @@ cp_parser_late_parsing_omp_declare_simd (cp_parser *parser, tree attrs)
if (!data->error_seen && data->fndecl_seen)
{
- error ("%<#pragma omp declare simd%> not immediately followed by "
- "a single function declaration or definition");
+ error ("%<#pragma omp declare %s%> not immediately followed by "
+ "a single function declaration or definition",
+ data->variant_p ? "variant" : "simd");
data->error_seen = true;
}
if (data->error_seen)
@@ -39942,17 +40844,28 @@ cp_parser_late_parsing_omp_declare_simd (cp_parser *parser, tree attrs)
parser->lexer->in_pragma = true;
gcc_assert (cp_lexer_peek_token (parser->lexer)->type == CPP_PRAGMA);
cp_token *pragma_tok = cp_lexer_consume_token (parser->lexer);
+ tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+ const char *kind = IDENTIFIER_POINTER (id);
cp_lexer_consume_token (parser->lexer);
- cl = cp_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK,
- "#pragma omp declare simd", pragma_tok);
+ if (strcmp (kind, "simd") == 0)
+ {
+ cl = cp_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK,
+ "#pragma omp declare simd",
+ pragma_tok);
+ if (cl)
+ cl = tree_cons (NULL_TREE, cl, NULL_TREE);
+ c = build_tree_list (get_identifier ("omp declare simd"), cl);
+ TREE_CHAIN (c) = attrs;
+ if (processing_template_decl)
+ ATTR_IS_DEPENDENT (c) = 1;
+ attrs = c;
+ }
+ else
+ {
+ gcc_assert (strcmp (kind, "variant") == 0);
+ attrs = cp_finish_omp_declare_variant (parser, pragma_tok, attrs);
+ }
cp_parser_pop_lexer (parser);
- if (cl)
- cl = tree_cons (NULL_TREE, cl, NULL_TREE);
- c = build_tree_list (get_identifier ("omp declare simd"), cl);
- TREE_CHAIN (c) = attrs;
- if (processing_template_decl)
- ATTR_IS_DEPENDENT (c) = 1;
- attrs = c;
}
data->fndecl_seen = true;
@@ -40516,7 +41429,10 @@ cp_parser_omp_declare_reduction (cp_parser *parser, cp_token *pragma_tok,
#pragma omp declare simd declare-simd-clauses[optseq] new-line
#pragma omp declare reduction (reduction-id : typename-list : expression) \
initializer-clause[opt] new-line
- #pragma omp declare target new-line */
+ #pragma omp declare target new-line
+
+ OpenMP 5.0
+ #pragma omp declare variant (identifier) match (context-selector) */
static bool
cp_parser_omp_declare (cp_parser *parser, cp_token *pragma_tok,
@@ -40531,7 +41447,14 @@ cp_parser_omp_declare (cp_parser *parser, cp_token *pragma_tok,
{
cp_lexer_consume_token (parser->lexer);
cp_parser_omp_declare_simd (parser, pragma_tok,
- context);
+ context, false);
+ return true;
+ }
+ if (flag_openmp && strcmp (p, "variant") == 0)
+ {
+ cp_lexer_consume_token (parser->lexer);
+ cp_parser_omp_declare_simd (parser, pragma_tok,
+ context, true);
return true;
}
cp_ensure_no_omp_declare_simd (parser);
@@ -40554,8 +41477,8 @@ cp_parser_omp_declare (cp_parser *parser, cp_token *pragma_tok,
return false;
}
}
- cp_parser_error (parser, "expected %<simd%> or %<reduction%> "
- "or %<target%>");
+ cp_parser_error (parser, "expected %<simd%>, %<reduction%>, "
+ "%<target%> or %<variant%>");
cp_parser_require_pragma_eol (parser, pragma_tok);
return false;
}
@@ -41964,36 +42887,15 @@ make_generic_type_name ()
static tree
synthesize_implicit_template_parm (cp_parser *parser, tree constr)
{
- gcc_assert (current_binding_level->kind == sk_function_parms);
-
- /* Before committing to modifying any scope, if we're in an
- implicit template scope, and we're trying to synthesize a
- constrained parameter, try to find a previous parameter with
- the same name. This is the same-type rule for abbreviated
- function templates.
-
- NOTE: We can generate implicit parameters when tentatively
- parsing a nested name specifier, only to reject that parse
- later. However, matching the same template-id as part of a
- direct-declarator should generate an identical template
- parameter, so this rule will merge them. */
- if (parser->implicit_template_scope && constr)
- {
- tree t = parser->implicit_template_parms;
- while (t)
- {
- if (equivalent_placeholder_constraints (TREE_TYPE (t), constr))
- {
- tree d = TREE_VALUE (t);
- if (TREE_CODE (d) == PARM_DECL)
- /* Return the TEMPLATE_PARM_INDEX. */
- d = DECL_INITIAL (d);
- return d;
- }
- t = TREE_CHAIN (t);
- }
+ /* A requires-clause is not a function and cannot have placeholders. */
+ if (current_binding_level->kind == sk_block)
+ {
+ error ("placeholder type not allowed in this context");
+ return error_mark_node;
}
+ gcc_assert (current_binding_level->kind == sk_function_parms);
+
/* We are either continuing a function template that already contains implicit
template parameters, creating a new fully-implicit function template, or
extending an existing explicit function template with implicit template
@@ -42104,18 +43006,9 @@ synthesize_implicit_template_parm (cp_parser *parser, tree constr)
tree synth_tmpl_parm;
bool non_type = false;
- if (proto == NULL_TREE || TREE_CODE (proto) == TYPE_DECL)
- synth_tmpl_parm
- = finish_template_type_parm (class_type_node, synth_id);
- else if (TREE_CODE (proto) == TEMPLATE_DECL)
- synth_tmpl_parm
- = finish_constrained_template_template_parm (proto, synth_id);
- else
- {
- synth_tmpl_parm = copy_decl (proto);
- DECL_NAME (synth_tmpl_parm) = synth_id;
- non_type = true;
- }
+ /* Synthesize the type template parameter. */
+ gcc_assert(!proto || TREE_CODE (proto) == TYPE_DECL);
+ synth_tmpl_parm = finish_template_type_parm (class_type_node, synth_id);
/* Attach the constraint to the parm before processing. */
tree node = build_tree_list (NULL_TREE, synth_tmpl_parm);
@@ -42127,6 +43020,13 @@ synthesize_implicit_template_parm (cp_parser *parser, tree constr)
/*non_type=*/non_type,
/*param_pack=*/false);
+ /* Mark the synthetic declaration "virtual". This is used when
+ comparing template-heads to determine if whether an abbreviated
+ function template is equivalent to an explicit template.
+
+ Note that DECL_ARTIFICIAL is used elsewhere for template parameters. */
+ DECL_VIRTUAL_P (TREE_VALUE (new_parm)) = true;
+
// Chain the new parameter to the list of implicit parameters.
if (parser->implicit_template_parms)
parser->implicit_template_parms
@@ -42165,7 +43065,7 @@ synthesize_implicit_template_parm (cp_parser *parser, tree constr)
if (tree req = TEMPLATE_PARM_CONSTRAINTS (tree_last (new_parm)))
{
tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
- reqs = conjoin_constraints (reqs, req);
+ reqs = combine_constraint_expressions (reqs, req);
TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = reqs;
}
diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h
index 2890788f489..91b5916622d 100644
--- a/gcc/cp/parser.h
+++ b/gcc/cp/parser.h
@@ -202,10 +202,11 @@ struct GTY (()) cp_parser_context {
};
-/* Helper data structure for parsing #pragma omp declare simd. */
+/* Helper data structure for parsing #pragma omp declare {simd,variant}. */
struct cp_omp_declare_simd_data {
bool error_seen; /* Set if error has been reported. */
bool fndecl_seen; /* Set if one fn decl/definition has been seen already. */
+ bool variant_p; /* Set for #pragma omp declare variant. */
vec<cp_token_cache_ptr> tokens;
tree clauses;
};
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index c36cd1d7e72..8900e888f24 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -135,8 +135,6 @@ enum template_base_result {
tbr_success
};
-static void push_access_scope (tree);
-static void pop_access_scope (tree);
static bool resolve_overloaded_unification (tree, tree, tree, tree,
unification_kind_t, int,
bool);
@@ -153,7 +151,6 @@ static tree coerce_innermost_template_parms (tree, tree, tree, tsubst_flags_t,
bool, bool);
static void tsubst_enum (tree, tree, tree);
static tree add_to_template_args (tree, tree);
-static tree add_outermost_template_args (tree, tree);
static bool check_instantiated_args (tree, tree, tsubst_flags_t);
static int check_non_deducible_conversion (tree, tree, int, int,
struct conversion **, bool);
@@ -183,12 +180,9 @@ static int can_complete_type_without_circularity (tree);
static tree get_bindings (tree, tree, tree, bool);
static int template_decl_level (tree);
static int check_cv_quals_for_unify (int, tree, tree);
-static void template_parm_level_and_index (tree, int*, int*);
static int unify_pack_expansion (tree, tree, tree,
tree, unification_kind_t, bool, bool);
static tree copy_template_args (tree);
-static tree tsubst_template_arg (tree, tree, tsubst_flags_t, tree);
-static tree tsubst_template_args (tree, tree, tsubst_flags_t, tree);
static tree tsubst_template_parms (tree, tree, tsubst_flags_t);
static tree most_specialized_partial_spec (tree, tsubst_flags_t);
static tree tsubst_aggr_type (tree, tree, tsubst_flags_t, tree, int);
@@ -232,7 +226,7 @@ static tree enclosing_instantiation_of (tree tctx);
template, VAR_DECL for static member variable, or TYPE_DECL for
alias template (needed by instantiate_decl). */
-static void
+void
push_access_scope (tree t)
{
gcc_assert (VAR_OR_FUNCTION_DECL_P (t)
@@ -255,7 +249,7 @@ push_access_scope (tree t)
/* Restore the scope set up by push_access_scope. T is the node we
are processing. */
-static void
+void
pop_access_scope (tree t)
{
if (TREE_CODE (t) == FUNCTION_DECL)
@@ -582,7 +576,7 @@ add_to_template_args (tree args, tree extra_args)
template arguments used to attain the full instantiation from the
partial instantiation. */
-static tree
+tree
add_outermost_template_args (tree args, tree extra_args)
{
tree new_args;
@@ -2137,7 +2131,8 @@ determine_specialization (tree template_id,
if (TREE_CODE (decl) == FUNCTION_DECL && !is_overloaded_fn (fns))
{
- error ("%qD is not a function template", fns);
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "%qD is not a function template", fns);
return error_mark_node;
}
else if (VAR_P (decl) && !variable_template_p (fns))
@@ -2416,7 +2411,8 @@ determine_specialization (tree template_id,
error ("template-id %qD for %q+D does not match any template "
"declaration", template_id, decl);
if (header_count && header_count != template_count + 1)
- inform (input_location, "saw %d %<template<>%>, need %d for "
+ inform (DECL_SOURCE_LOCATION (decl),
+ "saw %d %<template<>%>, need %d for "
"specializing a member function template",
header_count, template_count + 1);
else
@@ -3303,6 +3299,153 @@ comp_template_parms (const_tree parms1, const_tree parms2)
return 1;
}
+/* Returns true if two template parameters are declared with
+ equivalent constraints. */
+
+static bool
+template_parameter_constraints_equivalent_p (const_tree parm1, const_tree parm2)
+{
+ tree req1 = TREE_TYPE (parm1);
+ tree req2 = TREE_TYPE (parm2);
+ if (!req1 != !req2)
+ return false;
+ if (req1)
+ return cp_tree_equal (req1, req2);
+ return true;
+}
+
+/* Returns true when two template parameters are equivalent. */
+
+static bool
+template_parameters_equivalent_p (const_tree parm1, const_tree parm2)
+{
+ tree decl1 = TREE_VALUE (parm1);
+ tree decl2 = TREE_VALUE (parm2);
+
+ /* If either of the template parameters are invalid, assume
+ they match for the sake of error recovery. */
+ if (error_operand_p (decl1) || error_operand_p (decl2))
+ return true;
+
+ /* ... they declare parameters of the same kind. */
+ if (TREE_CODE (decl1) != TREE_CODE (decl2))
+ return false;
+
+ /* ... one parameter was introduced by a parameter declaration, then
+ both are. This case arises as a result of eagerly rewriting declarations
+ during parsing. */
+ if (DECL_VIRTUAL_P (decl1) != DECL_VIRTUAL_P (decl2))
+ return false;
+
+ /* ... if either declares a pack, they both do. */
+ if (template_parameter_pack_p (decl1) != template_parameter_pack_p (decl2))
+ return false;
+
+ if (TREE_CODE (decl1) == PARM_DECL)
+ {
+ /* ... if they declare non-type parameters, the types are equivalent. */
+ if (!same_type_p (TREE_TYPE (decl1), TREE_TYPE (decl2)))
+ return false;
+ }
+ else if (TREE_CODE (decl2) == TEMPLATE_DECL)
+ {
+ /* ... if they declare template template parameters, their template
+ parameter lists are equivalent. */
+ if (!template_heads_equivalent_p (decl1, decl2))
+ return false;
+ }
+
+ /* ... if they are declared with a qualified-concept name, they both
+ are, and those names are equivalent. */
+ return template_parameter_constraints_equivalent_p (parm1, parm2);
+}
+
+/* Returns true if two template parameters lists are equivalent.
+ Two template parameter lists are equivalent if they have the
+ same length and their corresponding parameters are equivalent.
+
+ PARMS1 and PARMS2 are TREE_LISTs containing TREE_VECs: the
+ data structure returned by DECL_TEMPLATE_PARMS.
+
+ This is generally the same implementation as comp_template_parms
+ except that it also the concept names and arguments used to
+ introduce parameters. */
+
+static bool
+template_parameter_lists_equivalent_p (const_tree parms1, const_tree parms2)
+{
+ if (parms1 == parms2)
+ return true;
+
+ const_tree p1 = parms1;
+ const_tree p2 = parms2;
+ while (p1 != NULL_TREE && p2 != NULL_TREE)
+ {
+ tree list1 = TREE_VALUE (p1);
+ tree list2 = TREE_VALUE (p2);
+
+ if (TREE_VEC_LENGTH (list1) != TREE_VEC_LENGTH (list2))
+ return 0;
+
+ for (int i = 0; i < TREE_VEC_LENGTH (list2); ++i)
+ {
+ tree parm1 = TREE_VEC_ELT (list1, i);
+ tree parm2 = TREE_VEC_ELT (list2, i);
+ if (!template_parameters_equivalent_p (parm1, parm2))
+ return false;
+ }
+
+ p1 = TREE_CHAIN (p1);
+ p2 = TREE_CHAIN (p2);
+ }
+
+ if ((p1 != NULL_TREE) != (p2 != NULL_TREE))
+ return false;
+
+ return true;
+}
+
+/* Return true if the requires-clause of the template parameter lists are
+ equivalent and false otherwise. */
+static bool
+template_requirements_equivalent_p (const_tree parms1, const_tree parms2)
+{
+ tree req1 = TEMPLATE_PARMS_CONSTRAINTS (parms1);
+ tree req2 = TEMPLATE_PARMS_CONSTRAINTS (parms2);
+ if ((req1 != NULL_TREE) != (req2 != NULL_TREE))
+ return false;
+ if (!cp_tree_equal (req1, req2))
+ return false;
+ return true;
+}
+
+/* Returns true if two template heads are equivalent. 17.6.6.1p6:
+ Two template heads are equivalent if their template parameter
+ lists are equivalent and their requires clauses are equivalent.
+
+ In pre-C++20, this is equivalent to calling comp_template_parms
+ for the template parameters of TMPL1 and TMPL2. */
+
+bool
+template_heads_equivalent_p (const_tree tmpl1, const_tree tmpl2)
+{
+ tree parms1 = DECL_TEMPLATE_PARMS (tmpl1);
+ tree parms2 = DECL_TEMPLATE_PARMS (tmpl2);
+
+ /* Don't change the matching rules for pre-C++20. */
+ if (cxx_dialect < cxx2a)
+ return comp_template_parms (parms1, parms2);
+
+ /* ... have the same number of template parameters, and their
+ corresponding parameters are equivalent. */
+ if (!template_parameter_lists_equivalent_p (parms1, parms2))
+ return false;
+
+ /* ... if either has a requires-clause, they both do and their
+ corresponding constraint-expressions are equivalent. */
+ return template_requirements_equivalent_p (parms1, parms2);
+}
+
/* Determine whether PARM is a parameter pack. */
bool
@@ -4570,7 +4713,7 @@ template_parm_to_arg (tree t)
/* Given a single level of template parameters (a TREE_VEC), return it
as a set of template arguments. */
-static tree
+tree
template_parms_level_to_args (tree parms)
{
tree a = copy_node (parms);
@@ -4588,7 +4731,7 @@ template_parms_level_to_args (tree parms)
arguments. The template parameters are represented as a TREE_VEC, in
the form documented in cp-tree.h for template arguments. */
-static tree
+tree
template_parms_to_args (tree parms)
{
tree header;
@@ -4624,6 +4767,26 @@ current_template_args (void)
return template_parms_to_args (current_template_parms);
}
+/* Return the fully generic arguments for of TMPL, i.e. what
+ current_template_args would be while parsing it. */
+
+tree
+generic_targs_for (tree tmpl)
+{
+ if (tmpl == NULL_TREE)
+ return NULL_TREE;
+ if (DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl)
+ || DECL_TEMPLATE_SPECIALIZATION (tmpl))
+ /* DECL_TEMPLATE_RESULT doesn't have the arguments we want. For a template
+ template parameter, it has no TEMPLATE_INFO; for a partial
+ specialization, it has the arguments for the primary template, and we
+ want the arguments for the partial specialization. */;
+ else if (tree result = DECL_TEMPLATE_RESULT (tmpl))
+ if (tree ti = get_template_info (result))
+ return TI_ARGS (ti);
+ return template_parms_to_args (DECL_TEMPLATE_PARMS (tmpl));
+}
+
/* Update the declared TYPE by doing any lookups which were thought to be
dependent, but are not now that we know the SCOPE of the declarator. */
@@ -4853,7 +5016,7 @@ process_partial_specialization (tree decl)
if (comp_template_args (inner_args, INNERMOST_TEMPLATE_ARGS (main_args))
&& (!flag_concepts
|| !strictly_subsumes (current_template_constraints (),
- get_constraints (maintmpl))))
+ inner_args, maintmpl)))
{
if (!flag_concepts)
error ("partial specialization %q+D does not specialize "
@@ -5562,6 +5725,8 @@ push_template_decl_real (tree decl, bool is_friend)
gcc_assert (!DECL_ARTIFICIAL (decl));
else if (VAR_P (decl))
/* C++14 variable template. */;
+ else if (TREE_CODE (decl) == CONCEPT_DECL)
+ /* C++2a concept definitions. */;
else
{
error ("template declaration of %q#D", decl);
@@ -5964,6 +6129,19 @@ redeclare_class_template (tree type, tree parms, tree cons)
return false;
}
+ /* The parameters can be declared to introduce different
+ constraints. */
+ tree p1 = TREE_VEC_ELT (tmpl_parms, i);
+ tree p2 = TREE_VEC_ELT (parms, i);
+ if (!template_parameter_constraints_equivalent_p (p1, p2))
+ {
+ error ("declaration of template parameter %q+#D with different "
+ "constraints", parm);
+ inform (DECL_SOURCE_LOCATION (tmpl_parm),
+ "original declaration appeared here");
+ return false;
+ }
+
if (tmpl_default != NULL_TREE && parm_default != NULL_TREE)
{
/* We have in [temp.param]:
@@ -5997,13 +6175,18 @@ redeclare_class_template (tree type, tree parms, tree cons)
TEMPLATE_TYPE_PARM_FOR_CLASS (TREE_TYPE (parm)) = true;
}
- // Cannot redeclare a class template with a different set of constraints.
- if (!equivalent_constraints (get_constraints (tmpl), cons))
+ tree ci = get_constraints (tmpl);
+ tree req1 = ci ? CI_TEMPLATE_REQS (ci) : NULL_TREE;
+ tree req2 = cons ? CI_TEMPLATE_REQS (cons) : NULL_TREE;
+
+ /* Two classes with different constraints declare different entities. */
+ if (!cp_tree_equal (req1, req2))
{
error_at (input_location, "redeclaration %q#D with different "
"constraints", tmpl);
inform (DECL_SOURCE_LOCATION (tmpl),
"original declaration appeared here");
+ return false;
}
return true;
@@ -6212,8 +6395,7 @@ get_underlying_template (tree tmpl)
!= num_innermost_template_parms (underlying)))
break;
- tree alias_args = INNERMOST_TEMPLATE_ARGS
- (template_parms_to_args (DECL_TEMPLATE_PARMS (tmpl)));
+ tree alias_args = INNERMOST_TEMPLATE_ARGS (generic_targs_for (tmpl));
if (!comp_template_args (TI_ARGS (tinfo), alias_args))
break;
@@ -7320,14 +7502,7 @@ coerce_template_args_for_ttp (tree templ, tree arglist,
tree outer = DECL_CONTEXT (templ);
if (outer)
- {
- if (DECL_TEMPLATE_SPECIALIZATION (outer))
- /* We want arguments for the partial specialization, not arguments for
- the primary template. */
- outer = template_parms_to_args (DECL_TEMPLATE_PARMS (outer));
- else
- outer = TI_ARGS (get_template_info (DECL_TEMPLATE_RESULT (outer)));
- }
+ outer = generic_targs_for (outer);
else if (current_template_parms)
{
/* This is an argument of the current template, so we haven't set
@@ -7785,8 +7960,6 @@ is_compatible_template_arg (tree parm, tree arg)
if (parm_cons == NULL_TREE)
return true;
- tree arg_cons = get_constraints (arg);
-
/* If the template parameter is constrained, we need to rewrite its
constraints in terms of the ARG's template parameters. This ensures
that all of the template parameter types will have the same depth.
@@ -7794,17 +7967,18 @@ is_compatible_template_arg (tree parm, tree arg)
Note that this is only valid when coerce_template_template_parm is
true for the innermost template parameters of PARM and ARG. In other
words, because coercion is successful, this conversion will be valid. */
+ tree new_args = NULL_TREE;
if (parm_cons)
{
- tree args = template_parms_to_args (DECL_TEMPLATE_PARMS (arg));
- parm_cons = tsubst_constraint_info (parm_cons,
- INNERMOST_TEMPLATE_ARGS (args),
+ tree aparms = DECL_INNERMOST_TEMPLATE_PARMS (arg);
+ new_args = template_parms_level_to_args (aparms);
+ parm_cons = tsubst_constraint_info (parm_cons, new_args,
tf_none, NULL_TREE);
if (parm_cons == error_mark_node)
return false;
}
- return subsumes (parm_cons, arg_cons);
+ return weakly_subsumes (parm_cons, new_args, arg);
}
// Convert a placeholder argument into a binding to the original
@@ -8424,7 +8598,7 @@ coerce_template_parms (tree parms,
template (DR 1430). */
else if (in_decl
&& (DECL_ALIAS_TEMPLATE_P (in_decl)
- || concept_template_p (in_decl))
+ || concept_definition_p (in_decl))
&& variadic_args_p
&& nargs - variadic_args_p < nparms - variadic_p)
{
@@ -8598,6 +8772,7 @@ coerce_template_parms (tree parms,
if (arg == error_mark_node)
lost++;
+
TREE_VEC_ELT (new_inner_args, arg_idx - pack_adjust) = arg;
}
@@ -8615,6 +8790,32 @@ coerce_template_parms (tree parms,
/* We had some pack expansion arguments that will only work if the packs
are empty, but wait until instantiation time to complain.
See variadic-ttp3.C. */
+
+ /* Except that we can't provide empty packs to alias templates or
+ concepts when there are no corresponding parameters. Basically,
+ we can get here with this:
+
+ template<typename T> concept C = true;
+
+ template<typename... Args>
+ requires C<Args...>
+ void f();
+
+ When parsing C<Args...>, we try to form a concept check of
+ C<?, Args...>. Without the extra check for substituting an empty
+ pack past the last parameter, we can accept the check as valid.
+
+ FIXME: This may be valid for alias templates (but I doubt it).
+
+ FIXME: The error could be better also. */
+ if (in_decl && concept_definition_p (in_decl))
+ {
+ if (complain & tf_error)
+ error_at (location_of (TREE_VEC_ELT (args, arg_idx)),
+ "too many arguments");
+ return error_mark_node;
+ }
+
int len = nparms + (nargs - arg_idx);
tree args = make_tree_vec (len);
int i = 0;
@@ -9450,7 +9651,7 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context,
if (complain & tf_error)
{
auto_diagnostic_group d;
- error ("template constraint failure");
+ error ("template constraint failure for %qD", gen_tmpl);
diagnose_constraints (input_location, gen_tmpl, arglist);
}
return error_mark_node;
@@ -9783,13 +9984,12 @@ lookup_template_class (tree d1, tree arglist, tree in_decl, tree context,
tree
lookup_template_variable (tree templ, tree arglist)
{
+ if (flag_concepts && variable_concept_p (templ))
+ return build_concept_check (templ, arglist, tf_none);
+
/* The type of the expression is NULL_TREE since the template-id could refer
to an explicit or partial specialization. */
- tree type = NULL_TREE;
- if (flag_concepts && variable_concept_p (templ))
- /* Except that concepts are always bool. */
- type = boolean_type_node;
- return build2 (TEMPLATE_ID_EXPR, type, templ, arglist);
+ return build2 (TEMPLATE_ID_EXPR, NULL_TREE, templ, arglist);
}
/* Instantiate a variable declaration from a TEMPLATE_ID_EXPR for use. */
@@ -9800,12 +10000,6 @@ finish_template_variable (tree var, tsubst_flags_t complain)
tree templ = TREE_OPERAND (var, 0);
tree arglist = TREE_OPERAND (var, 1);
- /* We never want to return a VAR_DECL for a variable concept, since they
- aren't instantiated. In a template, leave the TEMPLATE_ID_EXPR alone. */
- bool concept_p = flag_concepts && variable_concept_p (templ);
- if (concept_p && processing_template_decl)
- return var;
-
tree tmpl_args = DECL_TI_ARGS (DECL_TEMPLATE_RESULT (templ));
arglist = add_outermost_template_args (tmpl_args, arglist);
@@ -9826,19 +10020,6 @@ finish_template_variable (tree var, tsubst_flags_t complain)
return error_mark_node;
}
- /* If a template-id refers to a specialization of a variable
- concept, then the expression is true if and only if the
- concept's constraints are satisfied by the given template
- arguments.
-
- NOTE: This is an extension of Concepts Lite TS that
- allows constraints to be used in expressions. */
- if (concept_p)
- {
- tree decl = DECL_TEMPLATE_RESULT (templ);
- return evaluate_variable_concept (decl, arglist);
- }
-
return instantiate_template (templ, arglist, complain);
}
@@ -10039,6 +10220,26 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d)
return error_mark_node;
break;
+ case SCOPE_REF:
+ if (pfd->include_nondeduced_p)
+ WALK_SUBTREE (TREE_OPERAND (t, 0));
+ break;
+
+ case REQUIRES_EXPR:
+ {
+ if (!fn)
+ return error_mark_node;
+
+ /* Recursively walk the type of each constraint variable. */
+ tree p = TREE_OPERAND (t, 0);
+ while (p)
+ {
+ WALK_SUBTREE (TREE_TYPE (p));
+ p = TREE_CHAIN (p);
+ }
+ }
+ break;
+
default:
break;
}
@@ -10102,6 +10303,119 @@ for_each_template_parm (tree t, tree_fn_t fn, void* data,
return result;
}
+struct find_template_parameter_info
+{
+ explicit find_template_parameter_info (int d)
+ : max_depth (d)
+ {}
+
+ hash_set<tree> visited;
+ hash_set<tree> parms;
+ int max_depth;
+};
+
+/* Appends the declaration of T to the list in DATA. */
+
+static int
+keep_template_parm (tree t, void* data)
+{
+ find_template_parameter_info *ftpi = (find_template_parameter_info*)data;
+
+ /* Template parameters declared within the expression are not part of
+ the parameter mapping. For example, in this concept:
+
+ template<typename T>
+ concept C = requires { <expr> } -> same_as<int>;
+
+ the return specifier same_as<int> declares a new decltype parameter
+ that must not be part of the parameter mapping. The same is true
+ for generic lambda parameters, lambda template parameters, etc. */
+ int level;
+ int index;
+ template_parm_level_and_index (t, &level, &index);
+ if (level > ftpi->max_depth)
+ return 0;
+
+ /* Arguments like const T yield parameters like const T. This means that
+ a template-id like X<T, const T> would yield two distinct parameters:
+ T and const T. Adjust types to their unqualified versions. */
+ if (TYPE_P (t))
+ t = TYPE_MAIN_VARIANT (t);
+ ftpi->parms.add (t);
+
+ return 0;
+}
+
+/* Ensure that we recursively examine certain terms that are not normally
+ visited in for_each_template_parm_r. */
+
+static int
+any_template_parm_r (tree t, void *data)
+{
+ find_template_parameter_info *ftpi = (find_template_parameter_info*)data;
+
+#define WALK_SUBTREE(NODE) \
+ do \
+ { \
+ for_each_template_parm (NODE, keep_template_parm, data, \
+ &ftpi->visited, true, \
+ any_template_parm_r); \
+ } \
+ while (0)
+
+ switch (TREE_CODE (t))
+ {
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case ENUMERAL_TYPE:
+ /* Search for template parameters in type aliases. */
+ if (alias_template_specialization_p (t))
+ {
+ tree tinfo = TYPE_ALIAS_TEMPLATE_INFO (t);
+ WALK_SUBTREE (TI_ARGS (tinfo));
+ }
+ break;
+
+ case TEMPLATE_TYPE_PARM:
+ /* Type constraints of a placeholder type may contain parameters. */
+ if (is_auto (t))
+ if (tree constr = PLACEHOLDER_TYPE_CONSTRAINTS (t))
+ WALK_SUBTREE (constr);
+ break;
+
+ case TEMPLATE_ID_EXPR:
+ /* Search through references to variable templates. */
+ WALK_SUBTREE (TREE_OPERAND (t, 0));
+ WALK_SUBTREE (TREE_OPERAND (t, 1));
+ break;
+
+ case CONSTRUCTOR:
+ if (TREE_TYPE (t))
+ WALK_SUBTREE (TREE_TYPE (t));
+ break;
+ default:
+ break;
+ }
+
+ /* Keep walking. */
+ return 0;
+}
+
+/* Returns a list of unique template parameters found within T. */
+
+tree
+find_template_parameters (tree t, int depth)
+{
+ find_template_parameter_info ftpi (depth);
+ for_each_template_parm (t, keep_template_parm, &ftpi, &ftpi.visited,
+ /*include_nondeduced*/true, any_template_parm_r);
+ tree list = NULL_TREE;
+ for (hash_set<tree>::iterator iter = ftpi.parms.begin();
+ iter != ftpi.parms.end(); ++iter)
+ list = tree_cons (NULL_TREE, *iter, list);
+ return list;
+}
+
/* Returns true if T depends on any template parameter. */
int
@@ -10429,6 +10743,30 @@ tsubst_friend_function (tree decl, tree args)
DECL_USE_TEMPLATE (DECL_TEMPLATE_RESULT (new_friend)) = 0;
DECL_SAVED_TREE (DECL_TEMPLATE_RESULT (new_friend))
= DECL_SAVED_TREE (DECL_TEMPLATE_RESULT (decl));
+
+ /* Attach the template requirements to the new declaration
+ for declaration matching. We need to rebuild the requirements
+ so that parameter levels match. */
+ if (tree ci = get_constraints (decl))
+ {
+ tree parms = DECL_TEMPLATE_PARMS (new_friend);
+ tree args = generic_targs_for (new_friend);
+ tree treqs = tsubst_constraint (CI_TEMPLATE_REQS (ci), args,
+ tf_warning_or_error, NULL_TREE);
+ tree freqs = tsubst_constraint (CI_DECLARATOR_REQS (ci), args,
+ tf_warning_or_error, NULL_TREE);
+
+ /* Update the constraints -- these won't really be valid for
+ checking, but that's not what we need them for. These ensure
+ that the declared function can find the friend during
+ declaration matching. */
+ tree new_ci = get_constraints (new_friend);
+ CI_TEMPLATE_REQS (new_ci) = treqs;
+ CI_DECLARATOR_REQS (new_ci) = freqs;
+
+ /* Also update the template parameter list. */
+ TEMPLATE_PARMS_CONSTRAINTS (parms) = treqs;
+ }
}
/* The mangled name for the NEW_FRIEND is incorrect. The function
@@ -11527,7 +11865,7 @@ instantiate_class_template (tree type)
return ret;
}
-static tree
+tree
tsubst_template_arg (tree t, tree args, tsubst_flags_t complain, tree in_decl)
{
tree r;
@@ -11545,6 +11883,7 @@ tsubst_template_arg (tree t, tree args, tsubst_flags_t complain, tree in_decl)
if (!(complain & tf_warning))
--c_inhibit_evaluation_warnings;
}
+
return r;
}
@@ -11768,14 +12107,6 @@ gen_elem_of_pack_expansion_instantiation (tree pattern,
t = tsubst_decl (pattern, args, complain);
else if (pattern == error_mark_node)
t = error_mark_node;
- else if (constraint_p (pattern))
- {
- if (processing_template_decl)
- t = tsubst_constraint (pattern, args, complain, in_decl);
- else
- t = (constraints_satisfied_p (pattern, args)
- ? boolean_true_node : boolean_false_node);
- }
else if (!TYPE_P (pattern))
t = tsubst_expr (pattern, args, complain, in_decl,
/*integral_constant_expression_p=*/false);
@@ -12255,7 +12586,6 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
{
int idx;
template_parm_level_and_index (parm_pack, &level, &idx);
-
if (level <= levels)
arg_pack = TMPL_ARG (args, level, idx);
}
@@ -12309,6 +12639,10 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
/* We can't substitute for this parameter pack. We use a flag as
well as the missing_level counter because function parameter
packs don't have a level. */
+ if (!(processing_template_decl || is_auto (parm_pack)))
+ {
+ gcc_unreachable ();
+ }
gcc_assert (processing_template_decl || is_auto (parm_pack));
unsubstituted_packs = true;
}
@@ -12517,9 +12851,33 @@ copy_template_args (tree t)
return new_vec;
}
+/* Substitute ARGS into the *_ARGUMENT_PACK orig_arg. */
+
+tree
+tsubst_argument_pack (tree orig_arg, tree args, tsubst_flags_t complain,
+ tree in_decl)
+{
+ /* Substitute into each of the arguments. */
+ tree new_arg = TYPE_P (orig_arg)
+ ? cxx_make_type (TREE_CODE (orig_arg))
+ : make_node (TREE_CODE (orig_arg));
+
+ tree pack_args = tsubst_template_args (ARGUMENT_PACK_ARGS (orig_arg),
+ args, complain, in_decl);
+ if (pack_args == error_mark_node)
+ new_arg = error_mark_node;
+ else
+ SET_ARGUMENT_PACK_ARGS (new_arg, pack_args);
+
+ if (TREE_CODE (new_arg) == NONTYPE_ARGUMENT_PACK)
+ TREE_CONSTANT (new_arg) = TREE_CONSTANT (orig_arg);
+
+ return new_arg;
+}
+
/* Substitute ARGS into the vector or list of template arguments T. */
-static tree
+tree
tsubst_template_args (tree t, tree args, tsubst_flags_t complain, tree in_decl)
{
tree orig_t = t;
@@ -12554,22 +12912,7 @@ tsubst_template_args (tree t, tree args, tsubst_flags_t complain, tree in_decl)
expanded_len_adjust += TREE_VEC_LENGTH (new_arg) - 1;
}
else if (ARGUMENT_PACK_P (orig_arg))
- {
- /* Substitute into each of the arguments. */
- new_arg = TYPE_P (orig_arg)
- ? cxx_make_type (TREE_CODE (orig_arg))
- : make_node (TREE_CODE (orig_arg));
-
- tree pack_args = tsubst_template_args (ARGUMENT_PACK_ARGS (orig_arg),
- args, complain, in_decl);
- if (pack_args == error_mark_node)
- new_arg = error_mark_node;
- else
- SET_ARGUMENT_PACK_ARGS (new_arg, pack_args);
-
- if (TREE_CODE (new_arg) == NONTYPE_ARGUMENT_PACK)
- TREE_CONSTANT (new_arg) = TREE_CONSTANT (orig_arg);
- }
+ new_arg = tsubst_argument_pack (orig_arg, args, complain, in_decl);
else
new_arg = tsubst_template_arg (orig_arg, args, complain, in_decl);
@@ -12702,6 +13045,7 @@ tsubst_template_parm (tree t, tree args, tsubst_flags_t complain)
default_value = TREE_PURPOSE (t);
parm_decl = TREE_VALUE (t);
+ tree constraint = TEMPLATE_PARM_CONSTRAINTS (t);
parm_decl = tsubst (parm_decl, args, complain, NULL_TREE);
if (TREE_CODE (parm_decl) == PARM_DECL
@@ -12709,8 +13053,11 @@ tsubst_template_parm (tree t, tree args, tsubst_flags_t complain)
parm_decl = error_mark_node;
default_value = tsubst_template_arg (default_value, args,
complain, NULL_TREE);
+ constraint = tsubst_constraint (constraint, args, complain, NULL_TREE);
- return build_tree_list (default_value, parm_decl);
+ tree r = build_tree_list (default_value, parm_decl);
+ TEMPLATE_PARM_CONSTRAINTS (r) = constraint;
+ return r;
}
/* Substitute the ARGS into the indicated aggregate (or enumeration)
@@ -13136,14 +13483,11 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t complain,
&& !grok_op_properties (r, /*complain=*/false))
return error_mark_node;
- /* When instantiating a constrained member, substitute
- into the constraints to create a new constraint. */
+ /* Associate the constraints directly with the instantiation. We
+ don't substitute through the constraints; that's only done when
+ they are checked. */
if (tree ci = get_constraints (t))
- if (member)
- {
- ci = tsubst_constraint_info (ci, argvec, complain, NULL_TREE);
- set_constraints (r, ci);
- }
+ set_constraints (r, ci);
if (DECL_FRIEND_P (t) && DECL_FRIEND_CONTEXT (t))
SET_DECL_FRIEND_CONTEXT (r,
@@ -13999,6 +14343,17 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
return r;
}
+/* Substitute into the complete parameter type list PARMS. */
+
+tree
+tsubst_function_parms (tree parms,
+ tree args,
+ tsubst_flags_t complain,
+ tree in_decl)
+{
+ return tsubst_arg_types (parms, args, NULL_TREE, complain, in_decl);
+}
+
/* Substitute into the ARG_TYPES of a function type.
If END is a TREE_CHAIN, leave it and any following types
un-substituted. */
@@ -14563,6 +14918,14 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
if (code == TEMPLATE_TYPE_PARM)
{
int quals;
+
+ /* When building concept checks for the purpose of
+ deducing placeholders, we can end up with wildcards
+ where types are expected. Adjust this to the deduced
+ value. */
+ if (TREE_CODE (arg) == WILDCARD_DECL)
+ arg = TREE_TYPE (TREE_TYPE (arg));
+
gcc_assert (TYPE_P (arg));
quals = cp_type_quals (arg) | cp_type_quals (t);
@@ -14694,10 +15057,10 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
if (TREE_CODE (t) == TEMPLATE_TYPE_PARM)
{
- /* Propagate constraints on placeholders. */
+ /* Propagate constraints on placeholders since they are
+ only instantiated during satisfaction. */
if (tree constr = PLACEHOLDER_TYPE_CONSTRAINTS (t))
- PLACEHOLDER_TYPE_CONSTRAINTS (r)
- = tsubst_constraint (constr, args, complain, in_decl);
+ PLACEHOLDER_TYPE_CONSTRAINTS (r) = constr;
else if (tree pl = CLASS_PLACEHOLDER_TEMPLATE (t))
{
pl = tsubst_copy (pl, args, complain, in_decl);
@@ -15945,8 +16308,6 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
case TRUTH_OR_EXPR:
case RSHIFT_EXPR:
case LSHIFT_EXPR:
- case RROTATE_EXPR:
- case LROTATE_EXPR:
case EQ_EXPR:
case NE_EXPR:
case MAX_EXPR:
@@ -18366,6 +18727,28 @@ tsubst_copy_and_build (tree t,
RETURN (templ);
}
+ if (concept_definition_p (templ))
+ {
+ tree check = build_concept_check (templ, targs, complain);
+ if (check == error_mark_node)
+ RETURN (error_mark_node);
+
+ tree id = unpack_concept_check (check);
+
+ /* If we built a function concept check, return the underlying
+ template-id. So we can evaluate it as a function call. */
+ if (function_concept_p (TREE_OPERAND (id, 0)))
+ RETURN (id);
+
+ /* Evaluate the concept, if needed. */
+ tree args = TREE_OPERAND (id, 1);
+ if (!uses_template_parms (args)
+ && !processing_constraint_expression_p ())
+ RETURN (evaluate_concept_check (check, complain));
+
+ RETURN (check);
+ }
+
if (variable_template_p (templ))
RETURN (lookup_and_finish_template_variable (templ, targs, complain));
@@ -18549,8 +18932,6 @@ tsubst_copy_and_build (tree t,
case TRUTH_OR_EXPR:
case RSHIFT_EXPR:
case LSHIFT_EXPR:
- case RROTATE_EXPR:
- case LROTATE_EXPR:
case EQ_EXPR:
case NE_EXPR:
case MAX_EXPR:
@@ -19130,6 +19511,25 @@ tsubst_copy_and_build (tree t,
/*fn_p=*/NULL,
complain));
}
+ else if (concept_check_p (function))
+ {
+ /* FUNCTION is a template-id referring to a concept definition. */
+ tree id = unpack_concept_check (function);
+ tree tmpl = TREE_OPERAND (id, 0);
+ tree args = TREE_OPERAND (id, 1);
+
+ /* Calls to standard and variable concepts should have been
+ previously diagnosed. */
+ gcc_assert (function_concept_p (tmpl));
+
+ /* Ensure the result is wrapped as a call expression. */
+ ret = build_concept_check (tmpl, args, tf_warning_or_error);
+
+ /* Possibly evaluate the check if it is non-dependent. */
+ if (!uses_template_parms (args)
+ && !processing_constraint_expression_p ())
+ ret = evaluate_concept_check (ret, complain);
+ }
else
ret = finish_call_expr (function, &call_args,
/*disallow_virtual=*/qualified_p,
@@ -23221,10 +23621,11 @@ more_specialized_fn (tree pat1, tree pat2, int len)
constrained template. */
if (!lose1 && !lose2)
{
- tree c1 = get_constraints (DECL_TEMPLATE_RESULT (pat1));
- tree c2 = get_constraints (DECL_TEMPLATE_RESULT (pat2));
- lose1 = !subsumes_constraints (c1, c2);
- lose2 = !subsumes_constraints (c2, c1);
+ int winner = more_constrained (decl1, decl2);
+ if (winner > 0)
+ lose2 = true;
+ else if (winner < 0)
+ lose1 = true;
}
/* All things being equal, if the next argument is a pack expansion
@@ -23296,7 +23697,7 @@ more_specialized_partial_spec (tree tmpl, tree pat1, tree pat2)
/* If both deductions succeed, the partial ordering selects the more
constrained template. */
if (!winner && any_deductions)
- return more_constrained (tmpl1, tmpl2);
+ winner = more_constrained (tmpl1, tmpl2);
/* In the case of a tie where at least one of the templates
has a parameter pack at the end, the template with the most
@@ -25731,7 +26132,7 @@ value_dependent_expression_p (tree expression)
}
case TEMPLATE_ID_EXPR:
- return variable_concept_p (TREE_OPERAND (expression, 0));
+ return concept_definition_p (TREE_OPERAND (expression, 0));
case CONSTRUCTOR:
{
@@ -26131,14 +26532,14 @@ instantiation_dependent_r (tree *tp, int *walk_subtrees,
return *tp;
case CALL_EXPR:
- /* Treat calls to function concepts as dependent. */
- if (function_concept_check_p (*tp))
+ /* Treat concept checks as dependent. */
+ if (concept_check_p (*tp))
return *tp;
break;
case TEMPLATE_ID_EXPR:
- /* And variable concepts. */
- if (variable_concept_p (TREE_OPERAND (*tp, 0)))
+ /* Treat concept checks as dependent. */
+ if (concept_check_p (*tp))
return *tp;
break;
@@ -26676,9 +27077,9 @@ build_non_dependent_expr (tree expr)
/* Don't do this during nsdmi parsing as it can lead to
unexpected recursive instantiations. */
&& !parsing_nsdmi ()
- /* Don't do this during concept expansion either and for
+ /* Don't do this during concept processing either and for
the same reason. */
- && !expanding_concept ())
+ && !processing_constraint_expression_p ())
fold_non_dependent_expr (expr, tf_none);
STRIP_ANY_LOCATION_WRAPPER (expr);
@@ -26774,8 +27175,7 @@ static tree
make_auto_1 (tree name, bool set_canonical)
{
tree au = cxx_make_type (TEMPLATE_TYPE_PARM);
- TYPE_NAME (au) = build_decl (input_location,
- TYPE_DECL, name, au);
+ TYPE_NAME (au) = build_decl (input_location, TYPE_DECL, name, au);
TYPE_STUB_DECL (au) = TYPE_NAME (au);
TEMPLATE_TYPE_PARM_INDEX (au) = build_template_parm_index
(0, processing_template_decl + 1, processing_template_decl + 1,
@@ -26820,31 +27220,87 @@ template_placeholder_p (tree t)
return is_auto (t) && CLASS_PLACEHOLDER_TEMPLATE (t);
}
-/* Make a "constrained auto" type-specifier. This is an
- auto type with constraints that must be associated after
- deduction. The constraint is formed from the given
- CONC and its optional sequence of arguments, which are
- non-null if written as partial-concept-id. */
+/* Make a "constrained auto" type-specifier. This is an auto or
+ decltype(auto) type with constraints that must be associated after
+ deduction. The constraint is formed from the given concept CON
+ and its optional sequence of template arguments ARGS.
-tree
-make_constrained_auto (tree con, tree args)
-{
- tree type = make_auto_1 (auto_identifier, false);
+ TYPE must be the result of make_auto_type or make_decltype_auto_type. */
+static tree
+make_constrained_placeholder_type (tree type, tree con, tree args)
+{
/* Build the constraint. */
tree tmpl = DECL_TI_TEMPLATE (con);
- tree expr = VAR_P (con) ? tmpl : ovl_make (tmpl);
- expr = build_concept_check (expr, type, args);
+ tree expr = tmpl;
+ if (TREE_CODE (con) == FUNCTION_DECL)
+ expr = ovl_make (tmpl);
+ expr = build_concept_check (expr, type, args, tf_warning_or_error);
- tree constr = normalize_expression (expr);
- PLACEHOLDER_TYPE_CONSTRAINTS (type) = constr;
+ PLACEHOLDER_TYPE_CONSTRAINTS (type) = expr;
/* Our canonical type depends on the constraint. */
TYPE_CANONICAL (type) = canonical_type_parameter (type);
/* Attach the constraint to the type declaration. */
- tree decl = TYPE_NAME (type);
- return decl;
+ return TYPE_NAME (type);
+}
+
+/* Make a "constrained auto" type-specifier. */
+
+tree
+make_constrained_auto (tree con, tree args)
+{
+ tree type = make_auto_1 (auto_identifier, false);
+ return make_constrained_placeholder_type (type, con, args);
+}
+
+/* Make a "constrained decltype(auto)" type-specifier. */
+
+tree
+make_constrained_decltype_auto (tree con, tree args)
+{
+ tree type = make_auto_1 (decltype_auto_identifier, false);
+ /* FIXME: I don't know why this isn't done in make_auto_1. */
+ AUTO_IS_DECLTYPE (type) = true;
+ return make_constrained_placeholder_type (type, con, args);
+}
+
+/* Build and return a concept definition. Like other templates, the
+ CONCEPT_DECL node is wrapped by a TEMPLATE_DECL. This returns the
+ the TEMPLATE_DECL. */
+
+tree
+finish_concept_definition (cp_expr id, tree init)
+{
+ gcc_assert (identifier_p (id));
+ gcc_assert (processing_template_decl);
+
+ location_t loc = id.get_location();
+
+ /* A concept-definition shall not have associated constraints. */
+ if (TEMPLATE_PARMS_CONSTRAINTS (current_template_parms))
+ {
+ error_at (loc, "a concept cannot be constrained");
+ TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = NULL_TREE;
+ }
+
+ /* A concept-definition shall appear in namespace scope. Templates
+ aren't allowed in block scope, so we only need to check for class
+ scope. */
+ if (TYPE_P (current_scope()) || !DECL_NAMESPACE_SCOPE_P (current_scope ()))
+ {
+ error_at (loc, "concept %qE not in namespace scope", *id);
+ return error_mark_node;
+ }
+
+ /* Initially build the concept declaration; it's type is bool. */
+ tree decl = build_lang_decl_loc (loc, CONCEPT_DECL, *id, boolean_type_node);
+ DECL_CONTEXT (decl) = current_scope ();
+ DECL_INITIAL (decl) = init;
+
+ /* Push the enclosing template. */
+ return push_template_decl (decl);
}
/* Given type ARG, return std::initializer_list<ARG>. */
@@ -27675,13 +28131,17 @@ do_auto_deduction (tree type, tree init, tree auto_node,
/* Check any placeholder constraints against the deduced type. */
if (flag_concepts && !processing_template_decl)
- if (tree constr = NON_ERROR (PLACEHOLDER_TYPE_CONSTRAINTS (auto_node)))
+ if (tree check = NON_ERROR (PLACEHOLDER_TYPE_CONSTRAINTS (auto_node)))
{
/* Use the deduced type to check the associated constraints. If we
have a partial-concept-id, rebuild the argument list so that
we check using the extra arguments. */
- gcc_assert (TREE_CODE (constr) == CHECK_CONSTR);
- tree cargs = CHECK_CONSTR_ARGS (constr);
+ check = unpack_concept_check (check);
+ gcc_assert (TREE_CODE (check) == TEMPLATE_ID_EXPR);
+ tree cdecl = TREE_OPERAND (check, 0);
+ if (OVL_P (cdecl))
+ cdecl = OVL_FIRST (cdecl);
+ tree cargs = TREE_OPERAND (check, 1);
if (TREE_VEC_LENGTH (cargs) > 1)
{
cargs = copy_node (cargs);
@@ -27689,7 +28149,11 @@ do_auto_deduction (tree type, tree init, tree auto_node,
}
else
cargs = targs;
- if (!constraints_satisfied_p (constr, cargs))
+
+ /* Rebuild the check using the deduced arguments. */
+ check = build_concept_check (cdecl, cargs, tf_none);
+
+ if (!constraints_satisfied_p (check, cargs))
{
if (complain & tf_warning_or_error)
{
@@ -27714,7 +28178,7 @@ do_auto_deduction (tree type, tree init, tree auto_node,
"placeholder constraints");
break;
}
- diagnose_constraints (input_location, constr, targs);
+ diagnose_constraints (input_location, check, targs);
}
return error_mark_node;
}
@@ -27955,6 +28419,23 @@ append_type_to_template_for_access_check (tree templ,
scope, location);
}
+/* Recursively walk over && expressions searching for EXPR. Return a reference
+ to that expression. */
+
+static tree *find_template_requirement (tree *t, tree key)
+{
+ if (*t == key)
+ return t;
+ if (TREE_CODE (*t) == TRUTH_ANDIF_EXPR)
+ {
+ if (tree *p = find_template_requirement (&TREE_OPERAND (*t, 0), key))
+ return p;
+ if (tree *p = find_template_requirement (&TREE_OPERAND (*t, 1), key))
+ return p;
+ }
+ return 0;
+}
+
/* Convert the generic type parameters in PARM that match the types given in the
range [START_IDX, END_IDX) from the current_template_parms into generic type
packs. */
@@ -27976,9 +28457,8 @@ convert_generic_types_to_packs (tree parm, int start_idx, int end_idx)
/* Create a distinct parameter pack type from the current parm and add it
to the replacement args to tsubst below into the generic function
parameter. */
-
- tree o = TREE_TYPE (TREE_VALUE
- (TREE_VEC_ELT (current, i)));
+ tree node = TREE_VEC_ELT (current, i);
+ tree o = TREE_TYPE (TREE_VALUE (node));
tree t = copy_type (o);
TEMPLATE_TYPE_PARM_INDEX (t)
= reduce_template_parm_level (TEMPLATE_TYPE_PARM_INDEX (o),
@@ -27989,7 +28469,26 @@ convert_generic_types_to_packs (tree parm, int start_idx, int end_idx)
TEMPLATE_TYPE_PARAMETER_PACK (t) = true;
TYPE_CANONICAL (t) = canonical_type_parameter (t);
TREE_VEC_ELT (replacement, i) = t;
- TREE_VALUE (TREE_VEC_ELT (current, i)) = TREE_CHAIN (t);
+
+ /* Replace the current template parameter with new pack. */
+ TREE_VALUE (node) = TREE_CHAIN (t);
+
+ /* Surgically adjust the associated constraint of adjusted parameter
+ and it's corresponding contribution to the current template
+ requirements. */
+ if (tree constr = TEMPLATE_PARM_CONSTRAINTS (node))
+ {
+ tree id = unpack_concept_check (constr);
+ TREE_VEC_ELT (TREE_OPERAND (id, 1), 0) = template_parm_to_arg (t);
+ tree fold = finish_left_unary_fold_expr (constr, TRUTH_ANDIF_EXPR);
+ TEMPLATE_PARM_CONSTRAINTS (node) = fold;
+
+ /* If there was a constraint, we also need to replace that in
+ the template requirements, which we've already built. */
+ tree *reqs = &TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
+ reqs = find_template_requirement (reqs, constr);
+ *reqs = fold;
+ }
}
for (int i = end_idx, e = TREE_VEC_LENGTH (current); i < e; ++i)
@@ -28006,27 +28505,6 @@ convert_generic_types_to_packs (tree parm, int start_idx, int end_idx)
return tsubst (parm, replacement, tf_none, NULL_TREE);
}
-/* Entries in the decl_constraint hash table. */
-struct GTY((for_user)) constr_entry
-{
- tree decl;
- tree ci;
-};
-
-/* Hashing function and equality for constraint entries. */
-struct constr_hasher : ggc_ptr_hash<constr_entry>
-{
- static hashval_t hash (constr_entry *e)
- {
- return (hashval_t)DECL_UID (e->decl);
- }
-
- static bool equal (constr_entry *e1, constr_entry *e2)
- {
- return e1->decl == e2->decl;
- }
-};
-
/* A mapping from declarations to constraint information. Note that
both templates and their underlying declarations are mapped to the
same constraint information.
@@ -28034,7 +28512,7 @@ struct constr_hasher : ggc_ptr_hash<constr_entry>
FIXME: This is defined in pt.c because garbage collection
code is not being generated for constraint.cc. */
-static GTY (()) hash_table<constr_hasher> *decl_constraints;
+static GTY ((cache)) tree_cache_map *decl_constraints;
/* Returns the template constraints of declaration T. If T is not
constrained, return NULL_TREE. Note that T must be non-null. */
@@ -28044,14 +28522,15 @@ get_constraints (tree t)
{
if (!flag_concepts)
return NULL_TREE;
+ if (!decl_constraints)
+ return NULL_TREE;
gcc_assert (DECL_P (t));
if (TREE_CODE (t) == TEMPLATE_DECL)
t = DECL_TEMPLATE_RESULT (t);
- constr_entry elt = { t, NULL_TREE };
- constr_entry* found = decl_constraints->find (&elt);
+ tree* found = decl_constraints->get (t);
if (found)
- return found->ci;
+ return *found;
else
return NULL_TREE;
}
@@ -28069,12 +28548,8 @@ set_constraints (tree t, tree ci)
gcc_assert (t && flag_concepts);
if (TREE_CODE (t) == TEMPLATE_DECL)
t = DECL_TEMPLATE_RESULT (t);
- gcc_assert (!get_constraints (t));
- constr_entry elt = {t, ci};
- constr_entry** slot = decl_constraints->find_slot (&elt, INSERT);
- constr_entry* entry = ggc_alloc<constr_entry> ();
- *entry = elt;
- *slot = entry;
+ bool found = hash_map_safe_put<hm_ggc> (decl_constraints, t, ci);
+ gcc_assert (!found);
}
/* Remove the associated constraints of the declaration T. */
@@ -28086,149 +28561,8 @@ remove_constraints (tree t)
if (TREE_CODE (t) == TEMPLATE_DECL)
t = DECL_TEMPLATE_RESULT (t);
- constr_entry elt = {t, NULL_TREE};
- constr_entry** slot = decl_constraints->find_slot (&elt, NO_INSERT);
- if (slot)
- decl_constraints->clear_slot (slot);
-}
-
-/* Memoized satisfaction results for declarations. This
- maps the pair (constraint_info, arguments) to the result computed
- by constraints_satisfied_p. */
-
-struct GTY((for_user)) constraint_sat_entry
-{
- tree ci;
- tree args;
- tree result;
-};
-
-/* Hashing function and equality for constraint entries. */
-
-struct constraint_sat_hasher : ggc_ptr_hash<constraint_sat_entry>
-{
- static hashval_t hash (constraint_sat_entry *e)
- {
- hashval_t val = iterative_hash_object(e->ci, 0);
- return iterative_hash_template_arg (e->args, val);
- }
-
- static bool equal (constraint_sat_entry *e1, constraint_sat_entry *e2)
- {
- return e1->ci == e2->ci && comp_template_args (e1->args, e2->args);
- }
-};
-
-/* Memoized satisfaction results for concept checks. */
-
-struct GTY((for_user)) concept_spec_entry
-{
- tree tmpl;
- tree args;
- tree result;
-};
-
-/* Hashing function and equality for constraint entries. */
-
-struct concept_spec_hasher : ggc_ptr_hash<concept_spec_entry>
-{
- static hashval_t hash (concept_spec_entry *e)
- {
- return hash_tmpl_and_args (e->tmpl, e->args);
- }
-
- static bool equal (concept_spec_entry *e1, concept_spec_entry *e2)
- {
- ++comparing_specializations;
- bool eq = e1->tmpl == e2->tmpl && comp_template_args (e1->args, e2->args);
- --comparing_specializations;
- return eq;
- }
-};
-
-static GTY (()) hash_table<constraint_sat_hasher> *constraint_memos;
-static GTY (()) hash_table<concept_spec_hasher> *concept_memos;
-
-/* Search for a memoized satisfaction result. Returns one of the
- truth value nodes if previously memoized, or NULL_TREE otherwise. */
-
-tree
-lookup_constraint_satisfaction (tree ci, tree args)
-{
- constraint_sat_entry elt = { ci, args, NULL_TREE };
- constraint_sat_entry* found = constraint_memos->find (&elt);
- if (found)
- return found->result;
- else
- return NULL_TREE;
-}
-
-/* Memoize the result of a satisfication test. Returns the saved result. */
-
-tree
-memoize_constraint_satisfaction (tree ci, tree args, tree result)
-{
- constraint_sat_entry elt = {ci, args, result};
- constraint_sat_entry** slot = constraint_memos->find_slot (&elt, INSERT);
- constraint_sat_entry* entry = ggc_alloc<constraint_sat_entry> ();
- *entry = elt;
- *slot = entry;
- return result;
-}
-
-/* Search for a memoized satisfaction result for a concept. */
-
-tree
-lookup_concept_satisfaction (tree tmpl, tree args)
-{
- concept_spec_entry elt = { tmpl, args, NULL_TREE };
- concept_spec_entry* found = concept_memos->find (&elt);
- if (found)
- return found->result;
- else
- return NULL_TREE;
-}
-
-/* Memoize the result of a concept check. Returns the saved result. */
-
-tree
-memoize_concept_satisfaction (tree tmpl, tree args, tree result)
-{
- concept_spec_entry elt = {tmpl, args, result};
- concept_spec_entry** slot = concept_memos->find_slot (&elt, INSERT);
- concept_spec_entry* entry = ggc_alloc<concept_spec_entry> ();
- *entry = elt;
- *slot = entry;
- return result;
-}
-
-static GTY (()) hash_table<concept_spec_hasher> *concept_expansions;
-
-/* Returns a prior concept specialization. This returns the substituted
- and normalized constraints defined by the concept. */
-
-tree
-get_concept_expansion (tree tmpl, tree args)
-{
- concept_spec_entry elt = { tmpl, args, NULL_TREE };
- concept_spec_entry* found = concept_expansions->find (&elt);
- if (found)
- return found->result;
- else
- return NULL_TREE;
-}
-
-/* Save a concept expansion for later. */
-
-tree
-save_concept_expansion (tree tmpl, tree args, tree def)
-{
- concept_spec_entry elt = {tmpl, args, def};
- concept_spec_entry** slot = concept_expansions->find_slot (&elt, INSERT);
- concept_spec_entry* entry = ggc_alloc<concept_spec_entry> ();
- *entry = elt;
- *slot = entry;
- return def;
+ if (decl_constraints)
+ decl_constraints->remove (t);
}
static hashval_t
@@ -28325,13 +28659,11 @@ init_constraint_processing (void)
if (!flag_concepts)
return;
- decl_constraints = hash_table<constr_hasher>::create_ggc(37);
- constraint_memos = hash_table<constraint_sat_hasher>::create_ggc(37);
- concept_memos = hash_table<concept_spec_hasher>::create_ggc(37);
- concept_expansions = hash_table<concept_spec_hasher>::create_ggc(37);
subsumption_table = hash_table<subsumption_hasher>::create_ggc(37);
}
+GTY(()) tree current_failed_constraint;
+
/* __integer_pack(N) in a pack expansion expands to a sequence of numbers from
0..N-1. */
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index b441af8ff09..5bc8679efd5 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -835,7 +835,10 @@ accessible_p (tree type, tree decl, bool consider_local_p)
in default arguments for template parameters), and access
checking should be performed in the outermost parameter list. */
if (processing_template_decl
- && !expanding_concept ()
+ /* FIXME CWG has been talking about doing access checking in the context
+ of the constraint-expression, rather than the constrained declaration,
+ in which case we would want to remove this test. */
+ && !processing_constraint_expression_p ()
&& (!processing_template_parmlist || processing_template_decl > 1))
return 1;
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 5a8c4d237e0..f93bb934850 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -1788,10 +1788,10 @@ finish_mem_initializers (tree mem_inits)
/* Obfuscate EXPR if it looks like an id-expression or member access so
that the call to finish_decltype in do_auto_deduction will give the
- right result. */
+ right result. If EVEN_UNEVAL, do this even in unevaluated context. */
tree
-force_paren_expr (tree expr)
+force_paren_expr (tree expr, bool even_uneval)
{
/* This is only needed for decltype(auto) in C++14. */
if (cxx_dialect < cxx14)
@@ -1799,7 +1799,7 @@ force_paren_expr (tree expr)
/* If we're in unevaluated context, we can't be deducing a
return/initializer type, so we don't need to mess with this. */
- if (cp_unevaluated_operand)
+ if (cp_unevaluated_operand && !even_uneval)
return expr;
if (!DECL_P (tree_strip_any_location_wrapper (expr))
@@ -2589,6 +2589,27 @@ finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual,
/*fn_p=*/NULL,
complain);
}
+ else if (concept_check_p (fn))
+ {
+ /* FN is actually a template-id referring to a concept definition. */
+ tree id = unpack_concept_check (fn);
+ tree tmpl = TREE_OPERAND (id, 0);
+ tree args = TREE_OPERAND (id, 1);
+
+ if (!function_concept_p (tmpl))
+ {
+ error_at (EXPR_LOC_OR_LOC (fn, input_location),
+ "cannot call a concept as a function");
+ return error_mark_node;
+ }
+
+ /* Ensure the result is wrapped as a call expression. */
+ result = build_concept_check (tmpl, args, tf_warning_or_error);
+
+ /* Evaluate the check if it is non-dependent. */
+ if (!uses_template_parms (args))
+ result = evaluate_concept_check (result, complain);
+ }
else if (is_overloaded_fn (fn))
{
/* If the function is an overloaded builtin, resolve it. */
@@ -3833,9 +3854,10 @@ finish_id_expression_1 (tree id_expression,
if (! error_operand_p (decl)
&& !dependent_p
&& integral_constant_expression_p
- && ! decl_constant_var_p (decl)
+ && !decl_constant_var_p (decl)
&& TREE_CODE (decl) != CONST_DECL
- && ! builtin_valid_in_constant_expr_p (decl))
+ && !builtin_valid_in_constant_expr_p (decl)
+ && !concept_check_p (decl))
{
if (!allow_non_integral_constant_expression_p)
{
@@ -3851,12 +3873,23 @@ finish_id_expression_1 (tree id_expression,
decl = wrap;
else if (TREE_CODE (decl) == TEMPLATE_ID_EXPR
&& !dependent_p
- && variable_template_p (TREE_OPERAND (decl, 0)))
+ && variable_template_p (TREE_OPERAND (decl, 0))
+ && !concept_check_p (decl))
{
decl = finish_template_variable (decl);
mark_used (decl);
decl = convert_from_reference (decl);
}
+ else if (concept_check_p (decl))
+ {
+ /* If this is a standard or variable concept check, potentially
+ evaluate it. Function concepts need to be called as functions,
+ so don't try evaluating them here. */
+ tree tmpl = TREE_OPERAND (decl, 0);
+ tree args = TREE_OPERAND (decl, 1);
+ if (!function_concept_p (tmpl) && !uses_template_parms (args))
+ decl = evaluate_concept_check (decl, tf_warning_or_error);
+ }
else if (scope)
{
if (TREE_CODE (decl) == SCOPE_REF)
@@ -3929,6 +3962,16 @@ finish_id_expression_1 (tree id_expression,
decl = baselink_for_fns (decl);
}
+ else if (concept_check_p (decl))
+ {
+ /* If this is a standard or variable concept check, potentially
+ evaluate it. Function concepts need to be called as functions,
+ so don't try evaluating them here. */
+ tree tmpl = TREE_OPERAND (decl, 0);
+ tree args = TREE_OPERAND (decl, 1);
+ if (!function_concept_p (tmpl) && !uses_template_parms (args))
+ decl = evaluate_concept_check (decl, tf_warning_or_error);
+ }
else
{
if (DECL_P (decl) && DECL_NONLOCAL (decl)
@@ -5017,6 +5060,15 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types,
TREE_PURPOSE (t) = lb;
low_bound = lb;
}
+ /* Temporarily disable -fstrong-eval-order for array reductions.
+ The SAVE_EXPR and COMPOUND_EXPR added if low_bound has side-effects
+ is something the middle-end can't cope with and more importantly,
+ it needs to be the actual base variable that is privatized, not some
+ temporary assigned previous value of it. That, together with OpenMP
+ saying how many times the side-effects are evaluated is unspecified,
+ makes int *a, *b; ... reduction(+:a[a = b, 3:10]) really unspecified. */
+ warning_sentinel s (flag_strong_eval_order,
+ OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION);
ret = grok_array_decl (OMP_CLAUSE_LOCATION (c), ret, low_bound, false);
return ret;
}
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index d549450a605..141d86f50c9 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -52,9 +52,9 @@ static tree cp_pointer_int_sum (location_t, enum tree_code, tree, tree,
tsubst_flags_t);
static tree rationalize_conditional_expr (enum tree_code, tree,
tsubst_flags_t);
-static int comp_ptr_ttypes_real (tree, tree, int);
+static bool comp_ptr_ttypes_real (tree, tree, int);
static bool comp_except_types (tree, tree, bool);
-static bool comp_array_types (const_tree, const_tree, bool);
+static bool comp_array_types (const_tree, const_tree, compare_bounds_t, bool);
static tree pointer_diff (location_t, tree, tree, tree, tsubst_flags_t, tree *);
static tree get_delta_difference (tree, tree, bool, bool, tsubst_flags_t);
static void casts_away_constness_r (tree *, tree *, tsubst_flags_t);
@@ -1084,11 +1084,15 @@ comp_except_specs (const_tree t1, const_tree t2, int exact)
return exact == ce_derived || base == NULL_TREE || length == list_length (t1);
}
-/* Compare the array types T1 and T2. ALLOW_REDECLARATION is true if
- [] can match [size]. */
+/* Compare the array types T1 and T2. CB says how we should behave when
+ comparing array bounds: bounds_none doesn't allow dimensionless arrays,
+ bounds_either says than any array can be [], bounds_first means that
+ onlt T1 can be an array with unknown bounds. STRICT is true if
+ qualifiers must match when comparing the types of the array elements. */
static bool
-comp_array_types (const_tree t1, const_tree t2, bool allow_redeclaration)
+comp_array_types (const_tree t1, const_tree t2, compare_bounds_t cb,
+ bool strict)
{
tree d1;
tree d2;
@@ -1098,7 +1102,9 @@ comp_array_types (const_tree t1, const_tree t2, bool allow_redeclaration)
return true;
/* The type of the array elements must be the same. */
- if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+ if (strict
+ ? !same_type_p (TREE_TYPE (t1), TREE_TYPE (t2))
+ : !similar_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
return false;
d1 = TYPE_DOMAIN (t1);
@@ -1119,8 +1125,10 @@ comp_array_types (const_tree t1, const_tree t2, bool allow_redeclaration)
declarations for an array object can specify
array types that differ by the presence or absence of a major
array bound (_dcl.array_). */
- if (!d1 || !d2)
- return allow_redeclaration;
+ if (!d1 && d2)
+ return cb >= bounds_either;
+ else if (d1 && !d2)
+ return cb == bounds_either;
/* Check that the dimensions are the same. */
@@ -1368,7 +1376,9 @@ structural_comptypes (tree t1, tree t2, int strict)
case ARRAY_TYPE:
/* Target types must match incl. qualifiers. */
- if (!comp_array_types (t1, t2, !!(strict & COMPARE_REDECLARATION)))
+ if (!comp_array_types (t1, t2, ((strict & COMPARE_REDECLARATION)
+ ? bounds_either : bounds_none),
+ /*strict=*/true))
return false;
break;
@@ -1549,10 +1559,10 @@ similar_type_p (tree type1, tree type2)
if (same_type_ignoring_top_level_qualifiers_p (type1, type2))
return true;
- /* FIXME This ought to handle ARRAY_TYPEs too. */
if ((TYPE_PTR_P (type1) && TYPE_PTR_P (type2))
- || (TYPE_PTRDATAMEM_P (type1) && TYPE_PTRDATAMEM_P (type2)))
- return comp_ptr_ttypes_const (type1, type2);
+ || (TYPE_PTRDATAMEM_P (type1) && TYPE_PTRDATAMEM_P (type2))
+ || (TREE_CODE (type1) == ARRAY_TYPE && TREE_CODE (type2) == ARRAY_TYPE))
+ return comp_ptr_ttypes_const (type1, type2, bounds_either);
return false;
}
@@ -3550,6 +3560,10 @@ cp_build_array_ref (location_t loc, tree array, tree idx,
{
tree ar = cp_default_conversion (array, complain);
tree ind = cp_default_conversion (idx, complain);
+ tree first = NULL_TREE;
+
+ if (flag_strong_eval_order == 2 && TREE_SIDE_EFFECTS (ind))
+ ar = first = save_expr (ar);
/* Put the integer in IND to simplify error checking. */
if (TREE_CODE (TREE_TYPE (ar)) == INTEGER_TYPE)
@@ -3573,11 +3587,10 @@ cp_build_array_ref (location_t loc, tree array, tree idx,
warn_array_subscript_with_type_char (loc, idx);
- ret = cp_build_indirect_ref (cp_build_binary_op (input_location,
- PLUS_EXPR, ar, ind,
- complain),
- RO_ARRAY_INDEXING,
- complain);
+ ret = cp_build_binary_op (input_location, PLUS_EXPR, ar, ind, complain);
+ if (first)
+ ret = build2_loc (loc, COMPOUND_EXPR, TREE_TYPE (ret), first, ret);
+ ret = cp_build_indirect_ref (ret, RO_ARRAY_INDEXING, complain);
protected_set_expr_location (ret, loc);
if (non_lvalue)
ret = non_lvalue_loc (loc, ret);
@@ -4475,7 +4488,8 @@ cp_build_binary_op (const op_location_t &location,
if (t != error_mark_node)
{
if (complain & tf_error)
- permerror (input_location, "assuming cast to type %qT from overloaded function",
+ permerror (location,
+ "assuming cast to type %qT from overloaded function",
TREE_TYPE (t));
op0 = t;
}
@@ -4486,7 +4500,8 @@ cp_build_binary_op (const op_location_t &location,
if (t != error_mark_node)
{
if (complain & tf_error)
- permerror (input_location, "assuming cast to type %qT from overloaded function",
+ permerror (location,
+ "assuming cast to type %qT from overloaded function",
TREE_TYPE (t));
op1 = t;
}
@@ -4809,16 +4824,16 @@ cp_build_binary_op (const op_location_t &location,
{
if ((complain & tf_warning)
&& c_inhibit_evaluation_warnings == 0)
- warning (OPT_Wshift_count_negative,
- "right shift count is negative");
+ warning_at (location, OPT_Wshift_count_negative,
+ "right shift count is negative");
}
else
{
if (compare_tree_int (const_op1, TYPE_PRECISION (type0)) >= 0
&& (complain & tf_warning)
&& c_inhibit_evaluation_warnings == 0)
- warning (OPT_Wshift_count_overflow,
- "right shift count >= width of type");
+ warning_at (location, OPT_Wshift_count_overflow,
+ "right shift count >= width of type");
}
}
/* Avoid converting op1 to result_type later. */
@@ -4856,24 +4871,24 @@ cp_build_binary_op (const op_location_t &location,
&& tree_int_cst_sgn (const_op0) < 0
&& (complain & tf_warning)
&& c_inhibit_evaluation_warnings == 0)
- warning (OPT_Wshift_negative_value,
- "left shift of negative value");
+ warning_at (location, OPT_Wshift_negative_value,
+ "left shift of negative value");
if (TREE_CODE (const_op1) == INTEGER_CST)
{
if (tree_int_cst_lt (const_op1, integer_zero_node))
{
if ((complain & tf_warning)
&& c_inhibit_evaluation_warnings == 0)
- warning (OPT_Wshift_count_negative,
- "left shift count is negative");
+ warning_at (location, OPT_Wshift_count_negative,
+ "left shift count is negative");
}
else if (compare_tree_int (const_op1,
TYPE_PRECISION (type0)) >= 0)
{
if ((complain & tf_warning)
&& c_inhibit_evaluation_warnings == 0)
- warning (OPT_Wshift_count_overflow,
- "left shift count >= width of type");
+ warning_at (location, OPT_Wshift_count_overflow,
+ "left shift count >= width of type");
}
else if (TREE_CODE (const_op0) == INTEGER_CST
&& (complain & tf_warning))
@@ -4884,35 +4899,6 @@ cp_build_binary_op (const op_location_t &location,
}
break;
- case RROTATE_EXPR:
- case LROTATE_EXPR:
- if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
- {
- result_type = type0;
- if (TREE_CODE (op1) == INTEGER_CST)
- {
- if (tree_int_cst_lt (op1, integer_zero_node))
- {
- if (complain & tf_warning)
- warning (0, (code == LROTATE_EXPR)
- ? G_("left rotate count is negative")
- : G_("right rotate count is negative"));
- }
- else if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
- {
- if (complain & tf_warning)
- warning (0, (code == LROTATE_EXPR)
- ? G_("left rotate count >= width of type")
- : G_("right rotate count >= width of type"));
- }
- }
- /* Convert the shift-count to an integer, regardless of
- size of value being shifted. */
- if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
- op1 = cp_convert (integer_type_node, op1, complain);
- }
- break;
-
case EQ_EXPR:
case NE_EXPR:
if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE)
@@ -4920,8 +4906,9 @@ cp_build_binary_op (const op_location_t &location,
if ((complain & tf_warning)
&& c_inhibit_evaluation_warnings == 0
&& (FLOAT_TYPE_P (type0) || FLOAT_TYPE_P (type1)))
- warning (OPT_Wfloat_equal,
- "comparing floating-point with %<==%> or %<!=%> is unsafe");
+ warning_at (location, OPT_Wfloat_equal,
+ "comparing floating-point with %<==%> "
+ "or %<!=%> is unsafe");
if (complain & tf_warning)
{
tree stripped_orig_op0 = tree_strip_any_location_wrapper (orig_op0);
@@ -4930,8 +4917,9 @@ cp_build_binary_op (const op_location_t &location,
&& !integer_zerop (cp_fully_fold (op1)))
|| (TREE_CODE (stripped_orig_op1) == STRING_CST
&& !integer_zerop (cp_fully_fold (op0))))
- warning (OPT_Waddress, "comparison with string literal results "
- "in unspecified behavior");
+ warning_at (location, OPT_Waddress,
+ "comparison with string literal results in "
+ "unspecified behavior");
}
build_type = boolean_type_node;
@@ -4955,11 +4943,11 @@ cp_build_binary_op (const op_location_t &location,
if (char_type_p (TREE_TYPE (orig_op1)))
{
auto_diagnostic_group d;
- if (warning (OPT_Wpointer_compare,
- "comparison between pointer and zero character "
- "constant"))
- inform (input_location,
- "did you mean to dereference the pointer?");
+ if (warning_at (location, OPT_Wpointer_compare,
+ "comparison between pointer and zero character "
+ "constant"))
+ inform (location,
+ "did you mean to dereference the pointer?");
}
warn_for_null_address (location, op0, complain);
}
@@ -4978,10 +4966,10 @@ cp_build_binary_op (const op_location_t &location,
if (char_type_p (TREE_TYPE (orig_op0)))
{
auto_diagnostic_group d;
- if (warning (OPT_Wpointer_compare,
+ if (warning_at (location, OPT_Wpointer_compare,
"comparison between pointer and zero character "
"constant"))
- inform (input_location,
+ inform (location,
"did you mean to dereference the pointer?");
}
warn_for_null_address (location, op1, complain);
@@ -4996,8 +4984,9 @@ cp_build_binary_op (const op_location_t &location,
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
{
result_type = type0;
- if (complain & tf_error)
- permerror (input_location, "ISO C++ forbids comparison between pointer and integer");
+ if (complain & tf_error)
+ permerror (location, "ISO C++ forbids comparison between "
+ "pointer and integer");
else
return error_mark_node;
}
@@ -5005,7 +4994,8 @@ cp_build_binary_op (const op_location_t &location,
{
result_type = type1;
if (complain & tf_error)
- permerror (input_location, "ISO C++ forbids comparison between pointer and integer");
+ permerror (location, "ISO C++ forbids comparison between "
+ "pointer and integer");
else
return error_mark_node;
}
@@ -5191,8 +5181,9 @@ cp_build_binary_op (const op_location_t &location,
|| TREE_CODE (orig_op1) == STRING_CST)
{
if (complain & tf_warning)
- warning (OPT_Waddress, "comparison with string literal results "
- "in unspecified behavior");
+ warning_at (location, OPT_Waddress,
+ "comparison with string literal results "
+ "in unspecified behavior");
}
if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE)
@@ -5267,15 +5258,15 @@ cp_build_binary_op (const op_location_t &location,
{
result_type = type0;
if (extra_warnings && (complain & tf_warning))
- warning (OPT_Wextra,
- "ordered comparison of pointer with integer zero");
+ warning_at (location, OPT_Wextra,
+ "ordered comparison of pointer with integer zero");
}
else if (code1 == POINTER_TYPE && null_ptr_cst_p (orig_op0))
{
result_type = type1;
if (extra_warnings && (complain & tf_warning))
- warning (OPT_Wextra,
- "ordered comparison of pointer with integer zero");
+ warning_at (location, OPT_Wextra,
+ "ordered comparison of pointer with integer zero");
}
else if (null_ptr_cst_p (orig_op0) && null_ptr_cst_p (orig_op1))
/* One of the operands must be of nullptr_t type. */
@@ -5284,16 +5275,18 @@ cp_build_binary_op (const op_location_t &location,
{
result_type = type0;
if (complain & tf_error)
- permerror (input_location, "ISO C++ forbids comparison between pointer and integer");
- else
+ permerror (location, "ISO C++ forbids comparison between "
+ "pointer and integer");
+ else
return error_mark_node;
}
else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
{
result_type = type1;
if (complain & tf_error)
- permerror (input_location, "ISO C++ forbids comparison between pointer and integer");
- else
+ permerror (location, "ISO C++ forbids comparison between "
+ "pointer and integer");
+ else
return error_mark_node;
}
@@ -5555,6 +5548,17 @@ cp_build_binary_op (const op_location_t &location,
if (build_type == NULL_TREE)
build_type = result_type;
+ if (doing_shift
+ && flag_strong_eval_order == 2
+ && TREE_SIDE_EFFECTS (op1)
+ && !processing_template_decl)
+ {
+ /* In C++17, in both op0 << op1 and op0 >> op1 op0 is sequenced before
+ op1, so if op1 has side-effects, use SAVE_EXPR around op0. */
+ op0 = cp_save_expr (op0);
+ instrument_expr = op0;
+ }
+
if (sanitize_flags_p ((SANITIZE_SHIFT
| SANITIZE_DIVIDE | SANITIZE_FLOAT_DIVIDE))
&& current_function_decl != NULL_TREE
@@ -5566,6 +5570,7 @@ cp_build_binary_op (const op_location_t &location,
op1 = cp_save_expr (op1);
op0 = fold_non_dependent_expr (op0, complain);
op1 = fold_non_dependent_expr (op1, complain);
+ tree instrument_expr1 = NULL_TREE;
if (doing_div_or_mod
&& sanitize_flags_p (SANITIZE_DIVIDE | SANITIZE_FLOAT_DIVIDE))
{
@@ -5578,10 +5583,15 @@ cp_build_binary_op (const op_location_t &location,
cop0 = cp_convert (orig_type, op0, complain);
if (TREE_TYPE (cop1) != orig_type)
cop1 = cp_convert (orig_type, op1, complain);
- instrument_expr = ubsan_instrument_division (location, cop0, cop1);
+ instrument_expr1 = ubsan_instrument_division (location, cop0, cop1);
}
else if (doing_shift && sanitize_flags_p (SANITIZE_SHIFT))
- instrument_expr = ubsan_instrument_shift (location, code, op0, op1);
+ instrument_expr1 = ubsan_instrument_shift (location, code, op0, op1);
+ if (instrument_expr != NULL)
+ instrument_expr = add_stmt_to_compound (instrument_expr,
+ instrument_expr1);
+ else
+ instrument_expr = instrument_expr1;
}
result = build2_loc (location, resultcode, build_type, op0, op1);
@@ -7858,7 +7868,7 @@ build_const_cast_1 (tree dst_type, tree expr, tsubst_flags_t complain,
if (TYPE_PTR_P (src_type) || TYPE_PTRDATAMEM_P (src_type))
{
- if (comp_ptr_ttypes_const (dst_type, src_type))
+ if (comp_ptr_ttypes_const (dst_type, src_type, bounds_none))
{
if (valid_p)
{
@@ -9635,7 +9645,8 @@ check_return_expr (tree retval, bool *no_warning)
if (!retval)
retval = void_node;
auto_node = type_uses_auto (pattern);
- type = do_auto_deduction (pattern, retval, auto_node);
+ type = do_auto_deduction (pattern, retval, auto_node,
+ tf_warning_or_error, adc_return_type);
}
if (type == error_mark_node)
@@ -9883,7 +9894,7 @@ check_return_expr (tree retval, bool *no_warning)
If CONSTP is positive, then all outer pointers have been
const-qualified. */
-static int
+static bool
comp_ptr_ttypes_real (tree to, tree from, int constp)
{
bool to_more_cv_qualified = false;
@@ -9892,24 +9903,25 @@ comp_ptr_ttypes_real (tree to, tree from, int constp)
for (; ; to = TREE_TYPE (to), from = TREE_TYPE (from))
{
if (TREE_CODE (to) != TREE_CODE (from))
- return 0;
+ return false;
if (TREE_CODE (from) == OFFSET_TYPE
&& !same_type_p (TYPE_OFFSET_BASETYPE (from),
TYPE_OFFSET_BASETYPE (to)))
- return 0;
+ return false;
- /* Const and volatile mean something different for function types,
- so the usual checks are not appropriate. */
- if (!FUNC_OR_METHOD_TYPE_P (to))
+ /* Const and volatile mean something different for function and
+ array types, so the usual checks are not appropriate. We'll
+ check the array type elements in further iterations. */
+ if (!FUNC_OR_METHOD_TYPE_P (to) && TREE_CODE (to) != ARRAY_TYPE)
{
if (!at_least_as_qualified_p (to, from))
- return 0;
+ return false;
if (!at_least_as_qualified_p (from, to))
{
if (constp == 0)
- return 0;
+ return false;
to_more_cv_qualified = true;
}
@@ -9920,7 +9932,17 @@ comp_ptr_ttypes_real (tree to, tree from, int constp)
if (VECTOR_TYPE_P (to))
is_opaque_pointer = vector_targets_convertible_p (to, from);
- if (!TYPE_PTR_P (to) && !TYPE_PTRDATAMEM_P (to))
+ /* P0388R4 allows a conversion from int[N] to int[] but not the
+ other way round. When both arrays have bounds but they do
+ not match, then no conversion is possible. */
+ if (TREE_CODE (to) == ARRAY_TYPE
+ && !comp_array_types (to, from, bounds_first, /*strict=*/false))
+ return false;
+
+ if (!TYPE_PTR_P (to)
+ && !TYPE_PTRDATAMEM_P (to)
+ /* CWG 330 says we need to look through arrays. */
+ && TREE_CODE (to) != ARRAY_TYPE)
return ((constp >= 0 || to_more_cv_qualified)
&& (is_opaque_pointer
|| same_type_ignoring_top_level_qualifiers_p (to, from)));
@@ -10023,10 +10045,10 @@ ptr_reasonably_similar (const_tree to, const_tree from)
/* Return true if TO and FROM (both of which are POINTER_TYPEs or
pointer-to-member types) are the same, ignoring cv-qualification at
- all levels. */
+ all levels. CB says how we should behave when comparing array bounds. */
bool
-comp_ptr_ttypes_const (tree to, tree from)
+comp_ptr_ttypes_const (tree to, tree from, compare_bounds_t cb)
{
bool is_opaque_pointer = false;
@@ -10043,7 +10065,14 @@ comp_ptr_ttypes_const (tree to, tree from)
if (VECTOR_TYPE_P (to))
is_opaque_pointer = vector_targets_convertible_p (to, from);
- if (!TYPE_PTR_P (to))
+ if (TREE_CODE (to) == ARRAY_TYPE
+ /* Ignore cv-qualification, but if we see e.g. int[3] and int[4],
+ we must fail. */
+ && !comp_array_types (to, from, cb, /*strict=*/false))
+ return false;
+
+ /* CWG 330 says we need to look through arrays. */
+ if (!TYPE_PTR_P (to) && TREE_CODE (to) != ARRAY_TYPE)
return (is_opaque_pointer
|| same_type_ignoring_top_level_qualifiers_p (to, from));
}
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 54d6b848157..2402c38fdf3 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -923,7 +923,7 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
return split_nonconstant_init (decl, value);
/* DECL may change value; purge caches. */
- clear_cv_and_fold_caches ();
+ clear_cv_and_fold_caches (TREE_STATIC (decl));
/* If the value is a constant, just put it in DECL_INITIAL. If DECL
is an automatic variable, the middle end will turn this into a
@@ -2242,8 +2242,7 @@ build_functional_cast (tree exp, tree parms, tsubst_flags_t complain)
if (!CLASS_PLACEHOLDER_TEMPLATE (anode))
{
if (complain & tf_error)
- error_at (DECL_SOURCE_LOCATION (TEMPLATE_TYPE_DECL (anode)),
- "invalid use of %qT", anode);
+ error ("invalid use of %qT", anode);
return error_mark_node;
}
else if (!parms)
diff --git a/gcc/diagnostic-color.c b/gcc/diagnostic-color.c
index 69e759ff6e8..abc919f6383 100644
--- a/gcc/diagnostic-color.c
+++ b/gcc/diagnostic-color.c
@@ -19,6 +19,7 @@
#include "config.h"
#include "system.h"
#include "diagnostic-color.h"
+#include "diagnostic-url.h"
#ifdef __MINGW32__
# include <windows.h>
@@ -236,3 +237,22 @@ colorize_init (diagnostic_color_rule_t rule)
gcc_unreachable ();
}
}
+
+/* Determine if URLs should be enabled, based on RULE.
+ This reuses the logic for colorization. */
+
+bool
+diagnostic_urls_enabled_p (diagnostic_url_rule_t rule)
+{
+ switch (rule)
+ {
+ case DIAGNOSTICS_URL_NO:
+ return false;
+ case DIAGNOSTICS_URL_YES:
+ return true;
+ case DIAGNOSTICS_URL_AUTO:
+ return should_colorize ();
+ default:
+ gcc_unreachable ();
+ }
+}
diff --git a/gcc/diagnostic-format-json.cc b/gcc/diagnostic-format-json.cc
index 53c3b630b1c..eb999521a54 100644
--- a/gcc/diagnostic-format-json.cc
+++ b/gcc/diagnostic-format-json.cc
@@ -154,6 +154,17 @@ json_end_diagnostic (diagnostic_context *context, diagnostic_info *diagnostic,
free (option_text);
}
+ if (context->get_option_url)
+ {
+ char *option_url = context->get_option_url (context,
+ diagnostic->option_index);
+ if (option_url)
+ {
+ diag_obj->set ("option_url", new json::string (option_url));
+ free (option_url);
+ }
+ }
+
/* If we've already emitted a diagnostic within this auto_diagnostic_group,
then add diag_obj to its "children" array. */
if (cur_group)
diff --git a/gcc/diagnostic-url.h b/gcc/diagnostic-url.h
new file mode 100644
index 00000000000..ce0de459f32
--- /dev/null
+++ b/gcc/diagnostic-url.h
@@ -0,0 +1,36 @@
+/* Copyright (C) 2019 Free Software Foundation, Inc.
+ Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_DIAGNOSTIC_URL_H
+#define GCC_DIAGNOSTIC_URL_H
+
+/* Whether to add URLs to diagnostics:
+ - DIAGNOSTICS_URL_NO: never
+ - DIAGNOSTICS_URL_YES: always
+ - DIAGNOSTICS_URL_AUTO: depending on the output stream. */
+typedef enum
+{
+ DIAGNOSTICS_URL_NO = 0,
+ DIAGNOSTICS_URL_YES = 1,
+ DIAGNOSTICS_URL_AUTO = 2
+} diagnostic_url_rule_t;
+
+extern bool diagnostic_urls_enabled_p (diagnostic_url_rule_t);
+
+#endif /* ! GCC_DIAGNOSTIC_URL_H */
diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c
index 1b3306cd73e..a29bcf155e2 100644
--- a/gcc/diagnostic.c
+++ b/gcc/diagnostic.c
@@ -31,6 +31,7 @@ along with GCC; see the file COPYING3. If not see
#include "backtrace.h"
#include "diagnostic.h"
#include "diagnostic-color.h"
+#include "diagnostic-url.h"
#include "edit-context.h"
#include "selftest.h"
#include "selftest-diagnostic.h"
@@ -199,6 +200,7 @@ diagnostic_initialize (diagnostic_context *context, int n_opts)
context->option_enabled = NULL;
context->option_state = NULL;
context->option_name = NULL;
+ context->get_option_url = NULL;
context->last_location = UNKNOWN_LOCATION;
context->last_module = 0;
context->x_data = NULL;
@@ -246,6 +248,18 @@ diagnostic_color_init (diagnostic_context *context, int value /*= -1 */)
= colorize_init ((diagnostic_color_rule_t) value);
}
+/* Initialize URL support within CONTEXT based on VALUE, handling "auto". */
+
+void
+diagnostic_urls_init (diagnostic_context *context, int value /*= -1 */)
+{
+ if (value < 0)
+ value = DIAGNOSTICS_COLOR_DEFAULT;
+
+ context->printer->show_urls
+ = diagnostic_urls_enabled_p ((diagnostic_url_rule_t) value);
+}
+
/* Do any cleaning up required after the last diagnostic is emitted. */
void
@@ -899,11 +913,22 @@ print_option_information (diagnostic_context *context,
if (option_text)
{
+ char *option_url = NULL;
+ if (context->get_option_url)
+ option_url = context->get_option_url (context,
+ diagnostic->option_index);
pretty_printer *pp = context->printer;
pp_string (pp, " [");
pp_string (pp, colorize_start (pp_show_color (pp),
diagnostic_kind_color[diagnostic->kind]));
+ if (option_url)
+ pp_begin_url (pp, option_url);
pp_string (pp, option_text);
+ if (option_url)
+ {
+ pp_end_url (pp);
+ free (option_url);
+ }
pp_string (pp, colorize_stop (pp_show_color (pp)));
pp_character (pp, ']');
free (option_text);
diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h
index 530acb45b38..91e4c509605 100644
--- a/gcc/diagnostic.h
+++ b/gcc/diagnostic.h
@@ -194,6 +194,12 @@ struct diagnostic_context
May be passed 0 as well as the index of a particular option. */
char *(*option_name) (diagnostic_context *, int, diagnostic_t, diagnostic_t);
+ /* Client hook to return a URL describing the option that controls
+ a diagnostic. Returns malloced memory. May return NULL if no URL
+ is available. May be passed 0 as well as the index of a
+ particular option. */
+ char *(*get_option_url) (diagnostic_context *, int);
+
/* Auxiliary data for client. */
void *x_data;
@@ -331,6 +337,7 @@ diagnostic_override_option_index (diagnostic_info *info, int optidx)
/* Diagnostic related functions. */
extern void diagnostic_initialize (diagnostic_context *, int);
extern void diagnostic_color_init (diagnostic_context *, int value = -1);
+extern void diagnostic_urls_init (diagnostic_context *, int value = -1);
extern void diagnostic_finish (diagnostic_context *);
extern void diagnostic_report_current_module (diagnostic_context *, location_t);
extern void diagnostic_show_locus (diagnostic_context *,
diff --git a/gcc/doc/avr-mmcu.texi b/gcc/doc/avr-mmcu.texi
index ea0161ecccb..99cd93cb23b 100644
--- a/gcc/doc/avr-mmcu.texi
+++ b/gcc/doc/avr-mmcu.texi
@@ -21,7 +21,7 @@
@*@var{mcu}@tie{}= @code{ata5272}, @code{ata6616c}, @code{attiny13}, @code{attiny13a}, @code{attiny2313}, @code{attiny2313a}, @code{attiny24}, @code{attiny24a}, @code{attiny25}, @code{attiny261}, @code{attiny261a}, @code{attiny43u}, @code{attiny4313}, @code{attiny44}, @code{attiny44a}, @code{attiny441}, @code{attiny45}, @code{attiny461}, @code{attiny461a}, @code{attiny48}, @code{attiny828}, @code{attiny84}, @code{attiny84a}, @code{attiny841}, @code{attiny85}, @code{attiny861}, @code{attiny861a}, @code{attiny87}, @code{attiny88}, @code{at86rf401}.
@item avr3
-``Classic'' devices with 16@tie{}KiB up to 64@tie{}KiB of program memory.
+``Classic'' devices with 16@tie{}KiB up to 64@tie{}KiB of program memory.
@*@var{mcu}@tie{}= @code{at43usb355}, @code{at76c711}.
@item avr31
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 64fccfe9b87..9df4cc2a722 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -5206,7 +5206,7 @@ On the MSP430 target these attributes can be used to specify whether
the function or variable should be placed into low memory, high
memory, or the placement should be left to the linker to decide. The
attributes are only significant if compiling for the MSP430X
-architecture.
+architecture in the large memory model.
The attributes work in conjunction with a linker script that has been
augmented to specify where to place sections with a @code{.lower} and
@@ -7537,15 +7537,30 @@ value will be retained across resets. The linker script being used to
create the application should ensure that persistent data is correctly
placed.
-@item lower
-@itemx upper
+@item upper
@itemx either
-@cindex @code{lower} variable attribute, MSP430
@cindex @code{upper} variable attribute, MSP430
@cindex @code{either} variable attribute, MSP430
These attributes are the same as the MSP430 function attributes of the
same name (@pxref{MSP430 Function Attributes}).
-These attributes can be applied to both functions and variables.
+
+@item lower
+@cindex @code{lower} variable attribute, MSP430
+This option behaves mostly the same as the MSP430 function attribute of the
+same name (@pxref{MSP430 Function Attributes}), but it has some additional
+functionality.
+
+If @option{-mdata-region=}@{@code{upper,either,none}@} has been passed, or
+the @code{section} attribute is applied to a variable, the compiler will
+generate 430X instructions to handle it. This is because the compiler has
+to assume that the variable could get placed in the upper memory region
+(above address 0xFFFF). Marking the variable with the @code{lower} attribute
+informs the compiler that the variable will be placed in lower memory so it
+is safe to use 430 instructions to handle it.
+
+In the case of the @code{section} attribute, the section name given
+will be used, and the @code{.lower} prefix will not be added.
+
@end table
@node Nvidia PTX Variable Attributes
@@ -10739,7 +10754,7 @@ a general-purpose header file that should be usable by all programs,
including ISO C programs. The keywords @code{asm}, @code{typeof} and
@code{inline} are not available in programs compiled with
@option{-ansi} or @option{-std} (although @code{inline} can be used in a
-program compiled with @option{-std=c99} or @option{-std=c11}). The
+program compiled with @option{-std=c99} or a later standard). The
ISO C99 keyword
@code{restrict} is only available when @option{-std=gnu99} (which will
eventually be the default) or @option{-std=c99} (or the equivalent
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index d1024a1d465..1544da53319 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -273,6 +273,7 @@ Objective-C and Objective-C++ Dialects}.
@gccoptlist{-fmessage-length=@var{n} @gol
-fdiagnostics-show-location=@r{[}once@r{|}every-line@r{]} @gol
-fdiagnostics-color=@r{[}auto@r{|}never@r{|}always@r{]} @gol
+-fdiagnostics-urls=@r{[}auto@r{|}never@r{|}always@r{]} @gol
-fdiagnostics-format=@r{[}text@r{|}json@r{]} @gol
-fno-diagnostics-show-option -fno-diagnostics-show-caret @gol
-fno-diagnostics-show-labels -fno-diagnostics-show-line-numbers @gol
@@ -349,6 +350,7 @@ Objective-C and Objective-C++ Dialects}.
-Wsizeof-pointer-memaccess -Wsizeof-array-argument @gol
-Wstack-protector -Wstack-usage=@var{byte-size} -Wstrict-aliasing @gol
-Wstrict-aliasing=n -Wstrict-overflow -Wstrict-overflow=@var{n} @gol
+-Wstring-compare @gol
-Wstringop-overflow=@var{n} -Wstringop-truncation -Wsubobject-linkage @gol
-Wsuggest-attribute=@r{[}pure@r{|}const@r{|}noreturn@r{|}format@r{|}malloc@r{]} @gol
-Wsuggest-final-types @gol -Wsuggest-final-methods -Wsuggest-override @gol
@@ -2512,14 +2514,17 @@ exhaustion is signalled by throwing @code{std::bad_alloc}. See also
@samp{new (nothrow)}.
@item -fconcepts
+@itemx -fconcepts-ts
@opindex fconcepts
-Enable support for the C++ Extensions for Concepts Technical
-Specification, ISO 19217 (2015), which allows code like
+@opindex fconcepts-ts
+Below @option{-std=c++2a}, @option{-fconcepts} enables support for the
+C++ Extensions for Concepts Technical Specification, ISO 19217 (2015).
-@smallexample
-template <class T> concept bool Addable = requires (T t) @{ t + t; @};
-template <Addable T> T add (T a, T b) @{ return a + b; @}
-@end smallexample
+With @option{-std=c++2a} and above, Concepts are part of the language
+standard, so @option{-fconcepts} defaults to on. But the standard
+specification of Concepts differs significantly from the TS, so some
+constructs that were allowed in the TS but didn't make it into the
+standard can still be enabled by @option{-fconcepts-ts}.
@item -fconstexpr-depth=@var{n}
@opindex fconstexpr-depth
@@ -3908,6 +3913,18 @@ SGR substring for highlighting mismatching types within template
arguments in the C++ frontend.
@end table
+@item -fdiagnostics-urls[=@var{WHEN}]
+@opindex fdiagnostics-urls
+@cindex urls
+Use escape sequences to embed URLs in diagnostics. For example, when
+@option{-fdiagnostics-show-option} emits text showing the command-line
+option controlling a diagnostic, embed a URL for documentation of that
+option.
+
+@var{WHEN} is @samp{never}, @samp{always}, or @samp{auto}.
+The default is @samp{auto}, which means to use URL escape sequences only
+when the standard error is a terminal.
+
@item -fno-diagnostics-show-option
@opindex fno-diagnostics-show-option
@opindex fdiagnostics-show-option
@@ -4103,6 +4120,7 @@ might be printed in JSON form (after formatting) like this:
],
"message": "this \u2018if\u2019 clause does not guard...",
"option": "-Wmisleading-indentation",
+ "option_url": "https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#index-Wmisleading-indentation",
"children": [
@{
"kind": "note",
@@ -4486,6 +4504,7 @@ name is still supported, but the newer name is more descriptive.)
-Wold-style-declaration @r{(C only)} @gol
-Woverride-init @gol
-Wsign-compare @r{(C only)} @gol
+-Wstring-compare @gol
-Wredundant-move @r{(only for C++)} @gol
-Wtype-limits @gol
-Wuninitialized @gol
@@ -5582,21 +5601,20 @@ either specify @option{-Wextra -Wunused} (note that @option{-Wall} implies
@item -Wuninitialized
@opindex Wuninitialized
@opindex Wno-uninitialized
-Warn if an automatic variable is used without first being initialized
-or if a variable may be clobbered by a @code{setjmp} call. In C++,
-warn if a non-static reference or non-static @code{const} member
-appears in a class without constructors.
+Warn if an automatic variable is used without first being initialized.
+In C++, warn if a non-static reference or non-static @code{const}
+member appears in a class without constructors.
If you want to warn about code that uses the uninitialized value of the
variable in its own initializer, use the @option{-Winit-self} option.
-These warnings occur for individual uninitialized or clobbered
-elements of structure, union or array variables as well as for
-variables that are uninitialized or clobbered as a whole. They do
-not occur for variables or elements declared @code{volatile}. Because
-these warnings depend on optimization, the exact variables or elements
-for which there are warnings depends on the precise optimization
-options and version of GCC used.
+These warnings occur for individual uninitialized elements of
+structure, union or array variables as well as for variables that are
+uninitialized as a whole. They do not occur for variables or elements
+declared @code{volatile}. Because these warnings depend on
+optimization, the exact variables or elements for which there are
+warnings depend on the precise optimization options and version of GCC
+used.
Note that there may be no warning about a variable that is used only
to compute a value that itself is never used, because such
@@ -5802,6 +5820,30 @@ comparisons, so this warning level gives a very large number of
false positives.
@end table
+@item -Wstring-compare
+@opindex Wstring-compare
+@opindex Wno-string-compare
+Warn for calls to @code{strcmp} and @code{strncmp} whose result is
+determined to be either zero or non-zero in tests for such equality
+owing to the length of one argument being greater than the size of
+the array the other argument is stored in (or the bound in the case
+of @code{strncmp}). Such calls could be mistakes. For example,
+the call to @code{strcmp} below is diagnosed because its result is
+necessarily non-zero irrespective of the contents of the array @code{a}.
+
+@smallexample
+extern char a[4];
+void f (char *d)
+@{
+ strcpy (d, "string");
+ @dots{}
+ if (0 == strcmp (a, d)) // cannot be true
+ puts ("a and d are the same");
+@}
+@end smallexample
+
+@option{-Wstring-compare} is enabled by @option{-Wextra}.
+
@item -Wstringop-overflow
@itemx -Wstringop-overflow=@var{type}
@opindex Wstringop-overflow
@@ -10814,12 +10856,12 @@ Do not allow the built-in functions @code{ceil}, @code{floor},
double} variants, to generate code that raises the ``inexact''
floating-point exception for noninteger arguments. ISO C99 and C11
allow these functions to raise the ``inexact'' exception, but ISO/IEC
-TS 18661-1:2014, the C bindings to IEEE 754-2008, does not allow these
-functions to do so.
+TS 18661-1:2014, the C bindings to IEEE 754-2008, as integrated into
+ISO C2X, does not allow these functions to do so.
The default is @option{-ffp-int-builtin-inexact}, allowing the
-exception to be raised. This option does nothing unless
-@option{-ftrapping-math} is in effect.
+exception to be raised, unless C2X or a later C standard is selected.
+This option does nothing unless @option{-ftrapping-math} is in effect.
Even if @option{-fno-fp-int-builtin-inexact} is used, if the functions
generate a call to a library function then the ``inexact'' exception
diff --git a/gcc/doc/lto.texi b/gcc/doc/lto.texi
index 771e8278e50..09f0184e6a8 100644
--- a/gcc/doc/lto.texi
+++ b/gcc/doc/lto.texi
@@ -350,10 +350,11 @@ while the @emph{Read summary}, @emph{Execute}, and
@end itemize
To simplify development, the GCC pass manager differentiates
-between normal inter-procedural passes and small inter-procedural
-passes. A @emph{small inter-procedural pass}
-(@code{SIMPLE_IPA_PASS}) is a pass that does
-everything at once and thus it cannot be executed during WPA in
+between normal inter-procedural passes (@pxref{Regular IPA passes}),
+small inter-procedural passes (@pxref{Small IPA passes})
+and late inter-procedural passes (@pxref{Late IPA passes}).
+A small or late IPA pass (@code{SIMPLE_IPA_PASS}) does
+everything at once and thus cannot be executed during WPA in
WHOPR mode. It defines only the @emph{Execute} stage and during
this stage it accesses and modifies the function bodies. Such
passes are useful for optimization at LGEN or LTRANS time and are
diff --git a/gcc/doc/passes.texi b/gcc/doc/passes.texi
index 6edb9a0bfb7..889fa0f9004 100644
--- a/gcc/doc/passes.texi
+++ b/gcc/doc/passes.texi
@@ -20,6 +20,7 @@ where near complete.
* Parsing pass:: The language front end turns text into bits.
* Gimplification pass:: The bits are turned into something we can optimize.
* Pass manager:: Sequencing the optimization passes.
+* IPA passes:: Inter-procedural optimizations.
* Tree SSA passes:: Optimizations on a high-level representation.
* RTL passes:: Optimizations on a low-level representation.
* Optimization info:: Dumping optimization information from passes.
@@ -178,6 +179,277 @@ TODO: describe the global variables set up by the pass manager,
and a brief description of how a new pass should use it.
I need to look at what info RTL passes use first@enddots{}
+@node IPA passes
+@section Inter-procedural optimization passes
+@cindex IPA passes
+@cindex inter-procedural optimization passes
+
+The inter-procedural optimization (IPA) passes use call graph
+information to perform transformations across function boundaries.
+IPA is a critical part of link-time optimization (LTO) and
+whole-program (WHOPR) optimization, and these passes are structured
+with the needs of LTO and WHOPR in mind by dividing their operations
+into stages. For detailed discussion of the LTO/WHOPR IPA pass stages
+and interfaces, see @ref{IPA}.
+
+The following briefly describes the inter-procedural optimization (IPA)
+passes, which are split into small IPA passes, regular IPA passes,
+and late IPA passes, according to the LTO/WHOPR processing model.
+
+@menu
+* Small IPA passes::
+* Regular IPA passes::
+* Late IPA passes::
+@end menu
+
+@node Small IPA passes
+@subsection Small IPA passes
+@cindex small IPA passes
+A small IPA pass is a pass derived from @code{simple_ipa_opt_pass}.
+As described in @ref{IPA}, it does everything at once and
+defines only the @emph{Execute} stage. During this
+stage it accesses and modifies the function bodies.
+No @code{generate_summary}, @code{read_summary}, or @code{write_summary}
+hooks are defined.
+
+@itemize @bullet
+@item IPA free lang data
+
+This pass frees resources that are used by the front end but are
+not needed once it is done. It is located in @file{tree.c} and is described by
+@code{pass_ipa_free_lang_data}.
+
+@item IPA function and variable visibility
+
+This is a local function pass handling visibilities of all symbols. This
+happens before LTO streaming, so @option{-fwhole-program} should be ignored
+at this level. It is located in @file{ipa-visibility.c} and is described by
+@code{pass_ipa_function_and_variable_visibility}.
+
+@item IPA remove symbols
+
+This pass performs reachability analysis and reclaims all unreachable nodes.
+It is located in @file{passes.c} and is described by
+@code{pass_ipa_remove_symbols}.
+
+@item IPA OpenACC
+
+This is a pass group for OpenACC processing. It is located in
+@file{tree-ssa-loop.c} and is described by @code{pass_ipa_oacc}.
+
+@item IPA points-to analysis
+
+This is a tree-based points-to analysis pass. The idea behind this analyzer
+is to generate set constraints from the program, then solve the resulting
+constraints in order to generate the points-to sets. It is located in
+@file{tree-ssa-structalias.c} and is described by @code{pass_ipa_pta}.
+
+@item IPA OpenACC kernels
+
+This is a pass group for processing OpenACC kernels regions. It is a
+subpass of the IPA OpenACC pass group that runs on offloaded functions
+containing OpenACC kernels loops. It is located in
+@file{tree-ssa-loop.c} and is described by
+@code{pass_ipa_oacc_kernels}.
+
+@item Target clone
+
+This is a pass for parsing functions with multiple target attributes.
+It is located in @file{multiple_target.c} and is described by
+@code{pass_target_clone}.
+
+@item IPA auto profile
+
+This pass uses AutoFDO profiling data to annotate the control flow graph.
+It is located in @file{auto-profile.c} and is described by
+@code{pass_ipa_auto_profile}.
+
+@item IPA tree profile
+
+This pass does profiling for all functions in the call graph.
+It calculates branch
+probabilities and basic block execution counts. It is located
+in @file{tree-profile.c} and is described by @code{pass_ipa_tree_profile}.
+
+@item IPA free function summary
+
+This pass is a small IPA pass when argument @code{small_p} is true.
+It releases inline function summaries and call summaries.
+It is located in @file{ipa-fnsummary.c} and is described by
+@code{pass_ipa_free_free_fn_summary}.
+
+@item IPA increase alignment
+
+This pass increases the alignment of global arrays to improve
+vectorization. It is located in @file{tree-vectorizer.c}
+and is described by @code{pass_ipa_increase_alignment}.
+
+@item IPA transactional memory
+
+This pass is for transactional memory support.
+It is located in @file{trans-mem.c} and is described by
+@code{pass_ipa_tm}.
+
+@item IPA lower emulated TLS
+
+This pass lowers thread-local storage (TLS) operations
+to emulation functions provided by libgcc.
+It is located in @file{tree-emutls.c} and is described by
+@code{pass_ipa_lower_emutls}.
+
+@end itemize
+
+@node Regular IPA passes
+@subsection Regular IPA passes
+@cindex regular IPA passes
+
+A regular IPA pass is a pass derived from @code{ipa_opt_pass_d} that
+is executed in WHOPR compilation. Regular IPA passes may have summary
+hooks implemented in any of the LGEN, WPA or LTRANS stages (@pxref{IPA}).
+
+@itemize @bullet
+@item IPA whole program visibility
+
+This pass performs various optimizations involving symbol visibility
+with @option{-fwhole-program}, including symbol privatization,
+discovering local functions, and dismantling comdat groups. It is
+located in @file{ipa-visibility.c} and is described by
+@code{pass_ipa_whole_program_visibility}.
+
+@item IPA profile
+
+The IPA profile pass propagates profiling frequencies across the call
+graph. It is located in @file{ipa-profile.c} and is described by
+@code{pass_ipa_profile}.
+
+@item IPA identical code folding
+
+This is the inter-procedural identical code folding pass.
+The goal of this transformation is to discover functions
+and read-only variables that have exactly the same semantics. It is
+located in @file{ipa-icf.c} and is described by @code{pass_ipa_icf}.
+
+@item IPA devirtualization
+
+This pass performs speculative devirtualization based on the type
+inheritance graph. When a polymorphic call has only one likely target
+in the unit, it is turned into a speculative call. It is located in
+@file{ipa-devirt.c} and is described by @code{pass_ipa_devirt}.
+
+@item IPA constant propagation
+
+The goal of this pass is to discover functions that are always invoked
+with some arguments with the same known constant values and to modify
+the functions accordingly. It can also do partial specialization and
+type-based devirtualization. It is located in @file{ipa-cp.c} and is
+described by @code{pass_ipa_cp}.
+
+@item IPA scalar replacement of aggregates
+
+This pass can replace an aggregate parameter with a set of other parameters
+representing part of the original, turning those passed by reference
+into new ones which pass the value directly. It also removes unused
+function return values and unused function parameters. This pass is
+located in @file{ipa-sra.c} and is described by @code{pass_ipa_sra}.
+
+@item IPA constructor/destructor merge
+
+This pass merges multiple constructors and destructors for static
+objects into single functions. It's only run at LTO time unless the
+target doesn't support constructors and destructors natively. The
+pass is located in @file{ipa.c} and is described by
+@code{pass_ipa_cdtor_merge}.
+
+@item IPA HSA
+
+This pass is part of the GCC support for HSA (Heterogeneous System
+Architecture) accelerators. It is responsible for creation of HSA
+clones and emitting HSAIL instructions for them. It is located in
+@file{ipa-hsa.c} and is described by @code{pass_ipa_hsa}.
+
+@item IPA function summary
+
+This pass provides function analysis for inter-procedural passes.
+It collects estimates of function body size, execution time, and frame
+size for each function. It also estimates information about function
+calls: call statement size, time and how often the parameters change
+for each call. It is located in @file{ipa-fnsummary.c} and is
+described by @code{pass_ipa_fn_summary}.
+
+@item IPA inline
+
+The IPA inline pass handles function inlining with whole-program
+knowledge. Small functions that are candidates for inlining are
+ordered in increasing badness, bounded by unit growth parameters.
+Unreachable functions are removed from the call graph. Functions called
+once and not exported from the unit are inlined. This pass is located in
+@file{ipa-inline.c} and is described by @code{pass_ipa_inline}.
+
+@item IPA pure/const analysis
+
+This pass marks functions as being either const (@code{TREE_READONLY}) or
+pure (@code{DECL_PURE_P}). The per-function information is produced
+by @code{pure_const_generate_summary}, then the global information is computed
+by performing a transitive closure over the call graph. It is located in
+@file{ipa-pure-const.c} and is described by @code{pass_ipa_pure_const}.
+
+@item IPA free function summary
+
+This pass is a regular IPA pass when argument @code{small_p} is false.
+It releases inline function summaries and call summaries.
+It is located in @file{ipa-fnsummary.c} and is described by
+@code{pass_ipa_free_fn_summary}.
+
+@item IPA reference
+
+This pass gathers information about how variables whose scope is
+confined to the compilation unit are used. It is located in
+@file{ipa-reference.c} and is described by @code{pass_ipa_reference}.
+
+@item IPA single use
+
+This pass checks whether variables are used by a single function.
+It is located in @file{ipa.c} and is described by
+@code{pass_ipa_single_use}.
+
+@item IPA comdats
+
+This pass looks for static symbols that are used exclusively
+within one comdat group, and moves them into that comdat group. It is
+located in @file{ipa-comdats.c} and is described by
+@code{pass_ipa_comdats}.
+
+@end itemize
+
+@node Late IPA passes
+@subsection Late IPA passes
+@cindex late IPA passes
+
+Late IPA passes are simple IPA passes executed after
+the regular passes. In WHOPR mode the passes are executed after
+partitioning and thus see just parts of the compiled unit.
+
+@itemize @bullet
+@item Materialize all clones
+
+Once all functions from compilation unit are in memory, produce all clones
+and update all calls. It is located in @file{ipa.c} and is described by
+@code{pass_materialize_all_clones}.
+
+@item IPA points-to analysis
+
+Points-to analysis; this is the same as the points-to-analysis pass
+run with the small IPA passes (@pxref{Small IPA passes}).
+
+@item OpenMP simd clone
+
+This is the OpenMP constructs' SIMD clone pass. It creates the appropriate
+SIMD clones for functions tagged as elemental SIMD functions.
+It is located in @file{omp-simd-clone.c} and is described by
+@code{pass_omp_simd_clone}.
+
+@end itemize
+
@node Tree SSA passes
@section Tree SSA passes
diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi
index 56967928de6..42a10cf2243 100644
--- a/gcc/doc/sourcebuild.texi
+++ b/gcc/doc/sourcebuild.texi
@@ -2528,9 +2528,6 @@ instructions, if this is supported by the target; see the
Add the target-specific flags needed to enable functions to bind
locally when using pic/PIC passes in the testsuite.
-@item c99_runtime
-Add the target-specific flags needed to access the C99 runtime.
-
@item float@var{n}
Add the target-specific flags needed to use the @code{_Float@var{n}} type.
diff --git a/gcc/expr.c b/gcc/expr.c
index 124144d9b1e..b54bf1d3dc5 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -5790,7 +5790,8 @@ store_expr (tree exp, rtx target, int call_param_p,
copy_blkmode_from_reg (target, temp, TREE_TYPE (exp));
else
store_bit_field (target,
- INTVAL (expr_size (exp)) * BITS_PER_UNIT,
+ rtx_to_poly_int64 (expr_size (exp))
+ * BITS_PER_UNIT,
0, 0, 0, GET_MODE (temp), temp, reverse);
}
else
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index a99dafec589..58b967e48fe 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -4447,8 +4447,7 @@ simple_operand_p_2 (tree exp)
{
enum tree_code code;
- if (TREE_SIDE_EFFECTS (exp)
- || tree_could_trap_p (exp))
+ if (TREE_SIDE_EFFECTS (exp) || generic_expr_could_trap_p (exp))
return false;
while (CONVERT_EXPR_P (exp))
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index 84ee818a49d..2892011b740 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,3 +1,94 @@
+2019-10-13 Damian Rouson <damain@sourceryinstitue.org>
+
+ PR fortran/91513
+ * resolve.c (resolve_ordinary_assign): Improved error message.
+
+2019-10-13 Steven G. Kargl <kargl@gcc.gnu.org>
+
+ PR fortran/90297
+ * resolve.c (resolve_typebound_function): Remove code with no
+ functional effect.
+
+2019-10-13 Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ PR fortran/92017
+ * expr.c (simplify_parameter_variable): Set the character length
+ of the result expression from the original expression if
+ necessary.
+
+2019-10-11 Steven G. Kargl <kargl@gcc.gnu.org>
+
+ PR fortran/91649
+ check.c (gfc_check_findloc): Additional checking for valid arguments
+
+2019-10-11 Steven G. Kargl <kargl@gcc.gnu.org>
+
+ PR fortran/91715
+ * decl.c (gfc_match_prefix): If matching a type-spec returns an error,
+ it's an error so re-act correctly.
+
+2019-10-11 Steven G. Kargl <kargl@gcc.gnu.org>
+
+ PR fortran/92018
+ * check.c (reset_boz): New function.
+ (illegal_boz_arg, boz_args_check, gfc_check_complex, gfc_check_float,
+ gfc_check_transfer): Use it.
+ (gfc_check_dshift): Use reset_boz, and re-arrange the checking to
+ help suppress possible run-on errors.
+ (gfc_check_and): Restore checks for valid argument types. Use
+ reset_boz, and re-arrange the checking to help suppress possible
+ run-on errors.
+ * resolve.c (resolve_function): Actual arguments cannot be BOZ in
+ a function reference.
+
+2019-10-11 Steven G. Kargl <kargl@gcc.gnu.org>
+
+ PR fortran/92019
+ * array.c (match_subscript): BOZ cannot be an array subscript.
+
+2019-10-11 Tobias Burnus <tobias@codesourcery.com>
+
+ PR fortran/92050
+ * trans-expr.c (gfc_conv_procedure_call): Handle code generated
+ by -fcheck=all.
+
+2019-10-11 Tobias Burnus <tobias@codesourcery.com>
+
+ * f95-lang.c (LANG_HOOKS_OMP_IS_ALLOCATABLE_OR_PTR): Re-define to
+ gfc_omp_is_allocatable_or_ptr.
+ * trans-decl.c (create_function_arglist): Set GFC_DECL_OPTIONAL_ARGUMENT
+ only if not passed by value.
+ * trans-openmp.c (gfc_omp_is_allocatable_or_ptr): New.
+ (gfc_trans_omp_clauses): For MAP, handle (present) optional arguments;
+ for target update, handle allocatable/pointer scalars.
+ * trans.h (gfc_omp_is_allocatable_or_ptr): Declare.
+
+2019-10-10 Tobias Burnus <tobias@codesourcery.com>
+
+ * trans-openmp.c (gfc_trans_omp_clauses): Actually pass use_device_addr
+ on to the middle end.
+
+2019-10-08 Steven G. Kargl <kargl@gcc.gnu.org>
+
+ PR fortran/91801
+ * simplify.c (gfc_simplify_reshape): Convert a gcc_assert into a
+ gfc_error as a user can easily hit the condition.
+
+2019-10-08 Tobias Burnus <tobias@codesourcery.com>
+
+ * parse.c (parse_executable): Add missing ST_OMP_TARGET_SIMD.
+
+2019-10-08 Tobias Burnus <tobias@codesourcery.com>
+
+ * match.h (gfc_match_omp_eos_error): Renamed from gfc_match_omp_eos.
+ * openmp.c (gfc_match_omp_eos): Make static.
+ (gfc_match_omp_eos_error): New.
+ * parse.c (matchs, matchdo, matchds): Do as done for 'matcho' -
+ if error occurred after OpenMP/OpenACC directive matched, do not
+ try other directives.
+ (decode_oacc_directive, decode_omp_directive): Call new function
+ instead.
+
2019-10-05 Steven G. Kargl <kargl@gcc.gnu.org>
PR fortran/47045
@@ -153,7 +244,6 @@
(lang_decl): Add new optional_arg field.
(GFC_DECL_OPTIONAL_ARGUMENT): New macro.
->>>>>>> .r276463
2019-10-01 David Malcolm <dmalcolm@redhat.com>
* error.c (gfc_diagnostic_starter): Clear the prefix before
diff --git a/gcc/fortran/array.c b/gcc/fortran/array.c
index 3a504ebfea8..cbeece44ecf 100644
--- a/gcc/fortran/array.c
+++ b/gcc/fortran/array.c
@@ -66,6 +66,7 @@ match_subscript (gfc_array_ref *ar, int init, bool match_star)
match m = MATCH_ERROR;
bool star = false;
int i;
+ bool saw_boz = false;
i = ar->dimen + ar->codimen;
@@ -91,6 +92,12 @@ match_subscript (gfc_array_ref *ar, int init, bool match_star)
else if (!star)
m = gfc_match_expr (&ar->start[i]);
+ if (ar->start[i] && ar->start[i]->ts.type == BT_BOZ)
+ {
+ gfc_error ("Invalid BOZ literal constant used in subscript at %C");
+ saw_boz = true;
+ }
+
if (m == MATCH_NO)
gfc_error ("Expected array subscript at %C");
if (m != MATCH_YES)
@@ -117,6 +124,12 @@ end_element:
else
m = gfc_match_expr (&ar->end[i]);
+ if (ar->end[i] && ar->end[i]->ts.type == BT_BOZ)
+ {
+ gfc_error ("Invalid BOZ literal constant used in subscript at %C");
+ saw_boz = true;
+ }
+
if (m == MATCH_ERROR)
return MATCH_ERROR;
@@ -132,6 +145,12 @@ end_element:
m = init ? gfc_match_init_expr (&ar->stride[i])
: gfc_match_expr (&ar->stride[i]);
+ if (ar->stride[i] && ar->stride[i]->ts.type == BT_BOZ)
+ {
+ gfc_error ("Invalid BOZ literal constant used in subscript at %C");
+ saw_boz = true;
+ }
+
if (m == MATCH_NO)
gfc_error ("Expected array subscript stride at %C");
if (m != MATCH_YES)
@@ -142,7 +161,7 @@ matched:
if (star)
ar->dimen_type[i] = DIMEN_STAR;
- return MATCH_YES;
+ return (saw_boz ? MATCH_ERROR : MATCH_YES);
}
diff --git a/gcc/fortran/check.c b/gcc/fortran/check.c
index 87a81969062..d2a4949e12b 100644
--- a/gcc/fortran/check.c
+++ b/gcc/fortran/check.c
@@ -34,6 +34,24 @@ along with GCC; see the file COPYING3. If not see
#include "constructor.h"
#include "target-memory.h"
+
+/* Reset a BOZ to a zero value. This is used to prevent run-on errors
+ from resolve.c(resolve_function). */
+
+static void
+reset_boz (gfc_expr *x)
+{
+ /* Clear boz info. */
+ x->boz.rdx = 0;
+ x->boz.len = 0;
+ free (x->boz.str);
+
+ x->ts.type = BT_INTEGER;
+ x->ts.kind = gfc_default_integer_kind;
+ mpz_init (x->value.integer);
+ mpz_set_ui (x->value.integer, 0);
+}
+
/* A BOZ literal constant can appear in a limited number of contexts.
gfc_invalid_boz() is a helper function to simplify error/warning
generation. gfortran accepts the nonstandard 'X' for 'Z', and gfortran
@@ -63,6 +81,7 @@ illegal_boz_arg (gfc_expr *x)
{
gfc_error ("BOZ literal constant at %L cannot be an actual argument "
"to %qs", &x->where, gfc_current_intrinsic);
+ reset_boz (x);
return true;
}
@@ -79,6 +98,8 @@ boz_args_check(gfc_expr *i, gfc_expr *j)
gfc_error ("Arguments of %qs at %L and %L cannot both be BOZ "
"literal constants", gfc_current_intrinsic, &i->where,
&j->where);
+ reset_boz (i);
+ reset_boz (j);
return false;
}
@@ -2399,7 +2420,10 @@ gfc_check_complex (gfc_expr *x, gfc_expr *y)
{
if (gfc_invalid_boz ("BOZ constant at %L cannot appear in the COMPLEX "
"intrinsic subprogram", &x->where))
- return false;
+ {
+ reset_boz (x);
+ return false;
+ }
if (y->ts.type == BT_INTEGER && !gfc_boz2int (x, y->ts.kind))
return false;
if (y->ts.type == BT_REAL && !gfc_boz2real (x, y->ts.kind))
@@ -2410,7 +2434,10 @@ gfc_check_complex (gfc_expr *x, gfc_expr *y)
{
if (gfc_invalid_boz ("BOZ constant at %L cannot appear in the COMPLEX "
"intrinsic subprogram", &y->where))
- return false;
+ {
+ reset_boz (y);
+ return false;
+ }
if (x->ts.type == BT_INTEGER && !gfc_boz2int (y, x->ts.kind))
return false;
if (x->ts.type == BT_REAL && !gfc_boz2real (y, x->ts.kind))
@@ -2674,20 +2701,32 @@ gfc_check_dshift (gfc_expr *i, gfc_expr *j, gfc_expr *shift)
if (!boz_args_check (i, j))
return false;
- /* If i is BOZ and j is integer, convert i to type of j. */
- if (i->ts.type == BT_BOZ && j->ts.type == BT_INTEGER
- && !gfc_boz2int (i, j->ts.kind))
- return false;
-
- /* If j is BOZ and i is integer, convert j to type of i. */
- if (j->ts.type == BT_BOZ && i->ts.type == BT_INTEGER
- && !gfc_boz2int (j, i->ts.kind))
- return false;
-
- if (!type_check (i, 0, BT_INTEGER))
- return false;
+ /* If i is BOZ and j is integer, convert i to type of j. If j is not
+ an integer, clear the BOZ; otherwise, check that i is an integer. */
+ if (i->ts.type == BT_BOZ)
+ {
+ if (j->ts.type != BT_INTEGER)
+ reset_boz (i);
+ else if (!gfc_boz2int (i, j->ts.kind))
+ return false;
+ }
+ else if (!type_check (i, 0, BT_INTEGER))
+ {
+ if (j->ts.type == BT_BOZ)
+ reset_boz (j);
+ return false;
+ }
- if (!type_check (j, 1, BT_INTEGER))
+ /* If j is BOZ and i is integer, convert j to type of i. If i is not
+ an integer, clear the BOZ; otherwise, check that i is an integer. */
+ if (j->ts.type == BT_BOZ)
+ {
+ if (i->ts.type != BT_INTEGER)
+ reset_boz (j);
+ else if (!gfc_boz2int (j, i->ts.kind))
+ return false;
+ }
+ else if (!type_check (j, 1, BT_INTEGER))
return false;
if (!same_type_check (i, 0, j, 1))
@@ -2860,7 +2899,10 @@ gfc_check_float (gfc_expr *a)
{
if (gfc_invalid_boz ("BOZ literal constant at %L cannot appear in the "
"FLOAT intrinsic subprogram", &a->where))
- return false;
+ {
+ reset_boz (a);
+ return false;
+ }
if (!gfc_boz2int (a, gfc_default_integer_kind))
return false;
}
@@ -3879,26 +3921,27 @@ bool
gfc_check_findloc (gfc_actual_arglist *ap)
{
gfc_expr *a, *v, *m, *d, *k, *b;
+ bool a1, v1;
a = ap->expr;
if (!intrinsic_type_check (a, 0) || !array_check (a, 0))
return false;
v = ap->next->expr;
- if (!scalar_check (v,1))
+ if (!intrinsic_type_check (v, 1) || !scalar_check (v,1))
return false;
- /* Check if the type is compatible. */
+ /* Check if the type are both logical. */
+ a1 = a->ts.type == BT_LOGICAL;
+ v1 = v->ts.type == BT_LOGICAL;
+ if ((a1 && !v1) || (!a1 && v1))
+ goto incompat;
- if ((a->ts.type == BT_LOGICAL && v->ts.type != BT_LOGICAL)
- || (a->ts.type != BT_LOGICAL && v->ts.type == BT_LOGICAL))
- {
- gfc_error ("Argument %qs of %qs intrinsic at %L must be in type "
- "conformance to argument %qs at %L",
- gfc_current_intrinsic_arg[0]->name,
- gfc_current_intrinsic, &a->where,
- gfc_current_intrinsic_arg[1]->name, &v->where);
- }
+ /* Check if the type are both character. */
+ a1 = a->ts.type == BT_CHARACTER;
+ v1 = v->ts.type == BT_CHARACTER;
+ if ((a1 && !v1) || (!a1 && v1))
+ goto incompat;
d = ap->next->next->expr;
m = ap->next->next->next->expr;
@@ -3946,6 +3989,14 @@ gfc_check_findloc (gfc_actual_arglist *ap)
return false;
return true;
+
+incompat:
+ gfc_error ("Argument %qs of %qs intrinsic at %L must be in type "
+ "conformance to argument %qs at %L",
+ gfc_current_intrinsic_arg[0]->name,
+ gfc_current_intrinsic, &a->where,
+ gfc_current_intrinsic_arg[1]->name, &v->where);
+ return false;
}
@@ -6126,7 +6177,11 @@ gfc_check_transfer (gfc_expr *source, gfc_expr *mold, gfc_expr *size)
if (size != NULL)
{
if (!type_check (size, 2, BT_INTEGER))
- return false;
+ {
+ if (size->ts.type == BT_BOZ)
+ reset_boz (size);
+ return false;
+ }
if (!scalar_check (size, 2))
return false;
@@ -7286,19 +7341,61 @@ gfc_check_system_sub (gfc_expr *cmd, gfc_expr *status)
bool
gfc_check_and (gfc_expr *i, gfc_expr *j)
{
+ if (i->ts.type != BT_INTEGER
+ && i->ts.type != BT_LOGICAL
+ && i->ts.type != BT_BOZ)
+ {
+ gfc_error ("%qs argument of %qs intrinsic at %L must be INTEGER, "
+ "LOGICAL, or a BOZ literal constant",
+ gfc_current_intrinsic_arg[0]->name,
+ gfc_current_intrinsic, &i->where);
+ return false;
+ }
+
+ if (j->ts.type != BT_INTEGER
+ && j->ts.type != BT_LOGICAL
+ && j->ts.type != BT_BOZ)
+ {
+ gfc_error ("%qs argument of %qs intrinsic at %L must be INTEGER, "
+ "LOGICAL, or a BOZ literal constant",
+ gfc_current_intrinsic_arg[1]->name,
+ gfc_current_intrinsic, &j->where);
+ return false;
+ }
+
/* i and j cannot both be BOZ literal constants. */
if (!boz_args_check (i, j))
return false;
/* If i is BOZ and j is integer, convert i to type of j. */
- if (i->ts.type == BT_BOZ && j->ts.type == BT_INTEGER
- && !gfc_boz2int (i, j->ts.kind))
- return false;
+ if (i->ts.type == BT_BOZ)
+ {
+ if (j->ts.type != BT_INTEGER)
+ {
+ gfc_error ("%qs argument of %qs intrinsic at %L must be INTEGER",
+ gfc_current_intrinsic_arg[1]->name,
+ gfc_current_intrinsic, &j->where);
+ reset_boz (i);
+ return false;
+ }
+ if (!gfc_boz2int (i, j->ts.kind))
+ return false;
+ }
/* If j is BOZ and i is integer, convert j to type of i. */
- if (j->ts.type == BT_BOZ && i->ts.type == BT_INTEGER
- && !gfc_boz2int (j, i->ts.kind))
- return false;
+ if (j->ts.type == BT_BOZ)
+ {
+ if (i->ts.type != BT_INTEGER)
+ {
+ gfc_error ("%qs argument of %qs intrinsic at %L must be INTEGER",
+ gfc_current_intrinsic_arg[0]->name,
+ gfc_current_intrinsic, &j->where);
+ reset_boz (j);
+ return false;
+ }
+ if (!gfc_boz2int (j, i->ts.kind))
+ return false;
+ }
if (!same_type_check (i, 0, j, 1, false))
return false;
diff --git a/gcc/fortran/decl.c b/gcc/fortran/decl.c
index 9b604c8e7c3..9cda824ac05 100644
--- a/gcc/fortran/decl.c
+++ b/gcc/fortran/decl.c
@@ -6202,13 +6202,17 @@ gfc_match_prefix (gfc_typespec *ts)
found_prefix = true;
}
- if (!seen_type && ts != NULL
- && gfc_match_decl_type_spec (ts, 0) == MATCH_YES
- && gfc_match_space () == MATCH_YES)
+ if (!seen_type && ts != NULL)
{
-
- seen_type = true;
- found_prefix = true;
+ match m;
+ m = gfc_match_decl_type_spec (ts, 0);
+ if (m == MATCH_ERROR)
+ goto error;
+ if (m == MATCH_YES && gfc_match_space () == MATCH_YES)
+ {
+ seen_type = true;
+ found_prefix = true;
+ }
}
if (gfc_match ("elemental% ") == MATCH_YES)
diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c
index 9f638fe4dc3..c508890d68d 100644
--- a/gcc/fortran/expr.c
+++ b/gcc/fortran/expr.c
@@ -2066,6 +2066,9 @@ simplify_parameter_variable (gfc_expr *p, int type)
e->rank = p->rank;
+ if (e->ts.type == BT_CHARACTER && e->ts.u.cl == NULL)
+ e->ts.u.cl = gfc_new_charlen (gfc_current_ns, p->ts.u.cl);
+
/* Do not copy subobject refs for constant. */
if (e->expr_type != EXPR_CONSTANT && p->ref != NULL)
e->ref = gfc_copy_ref (p->ref);
diff --git a/gcc/fortran/f95-lang.c b/gcc/fortran/f95-lang.c
index 2467cd968af..0f72ab9e3b4 100644
--- a/gcc/fortran/f95-lang.c
+++ b/gcc/fortran/f95-lang.c
@@ -113,6 +113,7 @@ static const struct attribute_spec gfc_attribute_table[] =
#undef LANG_HOOKS_TYPE_FOR_MODE
#undef LANG_HOOKS_TYPE_FOR_SIZE
#undef LANG_HOOKS_INIT_TS
+#undef LANG_HOOKS_OMP_IS_ALLOCATABLE_OR_PTR
#undef LANG_HOOKS_OMP_IS_OPTIONAL_ARGUMENT
#undef LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE
#undef LANG_HOOKS_OMP_PREDETERMINED_SHARING
@@ -146,6 +147,7 @@ static const struct attribute_spec gfc_attribute_table[] =
#define LANG_HOOKS_TYPE_FOR_MODE gfc_type_for_mode
#define LANG_HOOKS_TYPE_FOR_SIZE gfc_type_for_size
#define LANG_HOOKS_INIT_TS gfc_init_ts
+#define LANG_HOOKS_OMP_IS_ALLOCATABLE_OR_PTR gfc_omp_is_allocatable_or_ptr
#define LANG_HOOKS_OMP_IS_OPTIONAL_ARGUMENT gfc_omp_is_optional_argument
#define LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE gfc_omp_privatize_by_reference
#define LANG_HOOKS_OMP_PREDETERMINED_SHARING gfc_omp_predetermined_sharing
diff --git a/gcc/fortran/match.h b/gcc/fortran/match.h
index 1bd78b14338..611d7964645 100644
--- a/gcc/fortran/match.h
+++ b/gcc/fortran/match.h
@@ -151,7 +151,7 @@ match gfc_match_oacc_exit_data (void);
match gfc_match_oacc_routine (void);
/* OpenMP directive matchers. */
-match gfc_match_omp_eos (void);
+match gfc_match_omp_eos_error (void);
match gfc_match_omp_atomic (void);
match gfc_match_omp_barrier (void);
match gfc_match_omp_cancel (void);
diff --git a/gcc/fortran/openmp.c b/gcc/fortran/openmp.c
index 7df7384c187..cd28384589c 100644
--- a/gcc/fortran/openmp.c
+++ b/gcc/fortran/openmp.c
@@ -31,7 +31,7 @@ along with GCC; see the file COPYING3. If not see
/* Match an end of OpenMP directive. End of OpenMP directive is optional
whitespace, followed by '\n' or comment '!'. */
-match
+static match
gfc_match_omp_eos (void)
{
locus old_loc;
@@ -57,6 +57,17 @@ gfc_match_omp_eos (void)
return MATCH_NO;
}
+match
+gfc_match_omp_eos_error (void)
+{
+ if (gfc_match_omp_eos() == MATCH_YES)
+ return MATCH_YES;
+
+ gfc_error ("Unexpected junk at %C");
+ return MATCH_ERROR;
+}
+
+
/* Free an omp_clauses structure. */
void
diff --git a/gcc/fortran/parse.c b/gcc/fortran/parse.c
index 4d343450555..15f6bf2937c 100644
--- a/gcc/fortran/parse.c
+++ b/gcc/fortran/parse.c
@@ -674,15 +674,15 @@ decode_oacc_directive (void)
match ("declare", gfc_match_oacc_declare, ST_OACC_DECLARE);
break;
case 'e':
- matcha ("end atomic", gfc_match_omp_eos, ST_OACC_END_ATOMIC);
- matcha ("end data", gfc_match_omp_eos, ST_OACC_END_DATA);
- matcha ("end host_data", gfc_match_omp_eos, ST_OACC_END_HOST_DATA);
- matcha ("end kernels loop", gfc_match_omp_eos, ST_OACC_END_KERNELS_LOOP);
- matcha ("end kernels", gfc_match_omp_eos, ST_OACC_END_KERNELS);
- matcha ("end loop", gfc_match_omp_eos, ST_OACC_END_LOOP);
- matcha ("end parallel loop", gfc_match_omp_eos,
+ matcha ("end atomic", gfc_match_omp_eos_error, ST_OACC_END_ATOMIC);
+ matcha ("end data", gfc_match_omp_eos_error, ST_OACC_END_DATA);
+ matcha ("end host_data", gfc_match_omp_eos_error, ST_OACC_END_HOST_DATA);
+ matcha ("end kernels loop", gfc_match_omp_eos_error, ST_OACC_END_KERNELS_LOOP);
+ matcha ("end kernels", gfc_match_omp_eos_error, ST_OACC_END_KERNELS);
+ matcha ("end loop", gfc_match_omp_eos_error, ST_OACC_END_LOOP);
+ matcha ("end parallel loop", gfc_match_omp_eos_error,
ST_OACC_END_PARALLEL_LOOP);
- matcha ("end parallel", gfc_match_omp_eos, ST_OACC_END_PARALLEL);
+ matcha ("end parallel", gfc_match_omp_eos_error, ST_OACC_END_PARALLEL);
matcha ("enter data", gfc_match_oacc_enter_data, ST_OACC_ENTER_DATA);
matcha ("exit data", gfc_match_oacc_exit_data, ST_OACC_EXIT_DATA);
break;
@@ -738,14 +738,17 @@ decode_oacc_directive (void)
and if spec_only, goto do_spec_only without actually matching. */
#define matchs(keyword, subr, st) \
do { \
+ match m2; \
if (spec_only && gfc_match (keyword) == MATCH_YES) \
goto do_spec_only; \
- if (match_word_omp_simd (keyword, subr, &old_locus, \
- &simd_matched) == MATCH_YES) \
+ if ((m2 = match_word_omp_simd (keyword, subr, &old_locus, \
+ &simd_matched)) == MATCH_YES) \
{ \
ret = st; \
goto finish; \
} \
+ else if (m2 == MATCH_ERROR) \
+ goto error_handling; \
else \
undo_new_statement (); \
} while (0)
@@ -776,12 +779,15 @@ decode_oacc_directive (void)
/* Like match, but set a flag simd_matched if keyword matched. */
#define matchds(keyword, subr, st) \
do { \
- if (match_word_omp_simd (keyword, subr, &old_locus, \
- &simd_matched) == MATCH_YES) \
+ match m2; \
+ if ((m2 = match_word_omp_simd (keyword, subr, &old_locus, \
+ &simd_matched)) == MATCH_YES) \
{ \
ret = st; \
goto finish; \
} \
+ else if (m2 == MATCH_ERROR) \
+ goto error_handling; \
else \
undo_new_statement (); \
} while (0)
@@ -789,14 +795,17 @@ decode_oacc_directive (void)
/* Like match, but don't match anything if not -fopenmp. */
#define matchdo(keyword, subr, st) \
do { \
+ match m2; \
if (!flag_openmp) \
; \
- else if (match_word (keyword, subr, &old_locus) \
+ else if ((m2 = match_word (keyword, subr, &old_locus)) \
== MATCH_YES) \
{ \
ret = st; \
goto finish; \
} \
+ else if (m2 == MATCH_ERROR) \
+ goto error_handling; \
else \
undo_new_statement (); \
} while (0)
@@ -889,63 +898,63 @@ decode_omp_directive (void)
matcho ("do", gfc_match_omp_do, ST_OMP_DO);
break;
case 'e':
- matcho ("end atomic", gfc_match_omp_eos, ST_OMP_END_ATOMIC);
+ matcho ("end atomic", gfc_match_omp_eos_error, ST_OMP_END_ATOMIC);
matcho ("end critical", gfc_match_omp_end_critical, ST_OMP_END_CRITICAL);
- matchs ("end distribute parallel do simd", gfc_match_omp_eos,
+ matchs ("end distribute parallel do simd", gfc_match_omp_eos_error,
ST_OMP_END_DISTRIBUTE_PARALLEL_DO_SIMD);
- matcho ("end distribute parallel do", gfc_match_omp_eos,
+ matcho ("end distribute parallel do", gfc_match_omp_eos_error,
ST_OMP_END_DISTRIBUTE_PARALLEL_DO);
- matchs ("end distribute simd", gfc_match_omp_eos,
+ matchs ("end distribute simd", gfc_match_omp_eos_error,
ST_OMP_END_DISTRIBUTE_SIMD);
- matcho ("end distribute", gfc_match_omp_eos, ST_OMP_END_DISTRIBUTE);
+ matcho ("end distribute", gfc_match_omp_eos_error, ST_OMP_END_DISTRIBUTE);
matchs ("end do simd", gfc_match_omp_end_nowait, ST_OMP_END_DO_SIMD);
matcho ("end do", gfc_match_omp_end_nowait, ST_OMP_END_DO);
- matchs ("end simd", gfc_match_omp_eos, ST_OMP_END_SIMD);
- matcho ("end master", gfc_match_omp_eos, ST_OMP_END_MASTER);
- matchs ("end ordered", gfc_match_omp_eos, ST_OMP_END_ORDERED);
- matchs ("end parallel do simd", gfc_match_omp_eos,
+ matchs ("end simd", gfc_match_omp_eos_error, ST_OMP_END_SIMD);
+ matcho ("end master", gfc_match_omp_eos_error, ST_OMP_END_MASTER);
+ matchs ("end ordered", gfc_match_omp_eos_error, ST_OMP_END_ORDERED);
+ matchs ("end parallel do simd", gfc_match_omp_eos_error,
ST_OMP_END_PARALLEL_DO_SIMD);
- matcho ("end parallel do", gfc_match_omp_eos, ST_OMP_END_PARALLEL_DO);
- matcho ("end parallel sections", gfc_match_omp_eos,
+ matcho ("end parallel do", gfc_match_omp_eos_error, ST_OMP_END_PARALLEL_DO);
+ matcho ("end parallel sections", gfc_match_omp_eos_error,
ST_OMP_END_PARALLEL_SECTIONS);
- matcho ("end parallel workshare", gfc_match_omp_eos,
+ matcho ("end parallel workshare", gfc_match_omp_eos_error,
ST_OMP_END_PARALLEL_WORKSHARE);
- matcho ("end parallel", gfc_match_omp_eos, ST_OMP_END_PARALLEL);
+ matcho ("end parallel", gfc_match_omp_eos_error, ST_OMP_END_PARALLEL);
matcho ("end sections", gfc_match_omp_end_nowait, ST_OMP_END_SECTIONS);
matcho ("end single", gfc_match_omp_end_single, ST_OMP_END_SINGLE);
- matcho ("end target data", gfc_match_omp_eos, ST_OMP_END_TARGET_DATA);
- matchs ("end target parallel do simd", gfc_match_omp_eos,
+ matcho ("end target data", gfc_match_omp_eos_error, ST_OMP_END_TARGET_DATA);
+ matchs ("end target parallel do simd", gfc_match_omp_eos_error,
ST_OMP_END_TARGET_PARALLEL_DO_SIMD);
- matcho ("end target parallel do", gfc_match_omp_eos,
+ matcho ("end target parallel do", gfc_match_omp_eos_error,
ST_OMP_END_TARGET_PARALLEL_DO);
- matcho ("end target parallel", gfc_match_omp_eos,
+ matcho ("end target parallel", gfc_match_omp_eos_error,
ST_OMP_END_TARGET_PARALLEL);
- matchs ("end target simd", gfc_match_omp_eos, ST_OMP_END_TARGET_SIMD);
+ matchs ("end target simd", gfc_match_omp_eos_error, ST_OMP_END_TARGET_SIMD);
matchs ("end target teams distribute parallel do simd",
- gfc_match_omp_eos,
+ gfc_match_omp_eos_error,
ST_OMP_END_TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD);
- matcho ("end target teams distribute parallel do", gfc_match_omp_eos,
+ matcho ("end target teams distribute parallel do", gfc_match_omp_eos_error,
ST_OMP_END_TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO);
- matchs ("end target teams distribute simd", gfc_match_omp_eos,
+ matchs ("end target teams distribute simd", gfc_match_omp_eos_error,
ST_OMP_END_TARGET_TEAMS_DISTRIBUTE_SIMD);
- matcho ("end target teams distribute", gfc_match_omp_eos,
+ matcho ("end target teams distribute", gfc_match_omp_eos_error,
ST_OMP_END_TARGET_TEAMS_DISTRIBUTE);
- matcho ("end target teams", gfc_match_omp_eos, ST_OMP_END_TARGET_TEAMS);
- matcho ("end target", gfc_match_omp_eos, ST_OMP_END_TARGET);
- matcho ("end taskgroup", gfc_match_omp_eos, ST_OMP_END_TASKGROUP);
- matchs ("end taskloop simd", gfc_match_omp_eos,
+ matcho ("end target teams", gfc_match_omp_eos_error, ST_OMP_END_TARGET_TEAMS);
+ matcho ("end target", gfc_match_omp_eos_error, ST_OMP_END_TARGET);
+ matcho ("end taskgroup", gfc_match_omp_eos_error, ST_OMP_END_TASKGROUP);
+ matchs ("end taskloop simd", gfc_match_omp_eos_error,
ST_OMP_END_TASKLOOP_SIMD);
- matcho ("end taskloop", gfc_match_omp_eos, ST_OMP_END_TASKLOOP);
- matcho ("end task", gfc_match_omp_eos, ST_OMP_END_TASK);
- matchs ("end teams distribute parallel do simd", gfc_match_omp_eos,
+ matcho ("end taskloop", gfc_match_omp_eos_error, ST_OMP_END_TASKLOOP);
+ matcho ("end task", gfc_match_omp_eos_error, ST_OMP_END_TASK);
+ matchs ("end teams distribute parallel do simd", gfc_match_omp_eos_error,
ST_OMP_END_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD);
- matcho ("end teams distribute parallel do", gfc_match_omp_eos,
+ matcho ("end teams distribute parallel do", gfc_match_omp_eos_error,
ST_OMP_END_TEAMS_DISTRIBUTE_PARALLEL_DO);
- matchs ("end teams distribute simd", gfc_match_omp_eos,
+ matchs ("end teams distribute simd", gfc_match_omp_eos_error,
ST_OMP_END_TEAMS_DISTRIBUTE_SIMD);
- matcho ("end teams distribute", gfc_match_omp_eos,
+ matcho ("end teams distribute", gfc_match_omp_eos_error,
ST_OMP_END_TEAMS_DISTRIBUTE);
- matcho ("end teams", gfc_match_omp_eos, ST_OMP_END_TEAMS);
+ matcho ("end teams", gfc_match_omp_eos_error, ST_OMP_END_TEAMS);
matcho ("end workshare", gfc_match_omp_end_nowait,
ST_OMP_END_WORKSHARE);
break;
@@ -979,7 +988,7 @@ decode_omp_directive (void)
break;
case 's':
matcho ("sections", gfc_match_omp_sections, ST_OMP_SECTIONS);
- matcho ("section", gfc_match_omp_eos, ST_OMP_SECTION);
+ matcho ("section", gfc_match_omp_eos_error, ST_OMP_SECTION);
matcho ("single", gfc_match_omp_single, ST_OMP_SINGLE);
break;
case 't':
@@ -5525,6 +5534,7 @@ parse_executable (gfc_statement st)
case ST_OMP_SIMD:
case ST_OMP_TARGET_PARALLEL_DO:
case ST_OMP_TARGET_PARALLEL_DO_SIMD:
+ case ST_OMP_TARGET_SIMD:
case ST_OMP_TARGET_TEAMS_DISTRIBUTE:
case ST_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO:
case ST_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD:
diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c
index 20ecafd944e..93f2d0aa761 100644
--- a/gcc/fortran/resolve.c
+++ b/gcc/fortran/resolve.c
@@ -3243,19 +3243,14 @@ resolve_function (gfc_expr *expr)
return t;
/* Walk the argument list looking for invalid BOZ. */
- if (expr->value.function.esym)
- {
- gfc_actual_arglist *a;
-
- for (a = expr->value.function.actual; a; a = a->next)
- if (a->expr && a->expr->ts.type == BT_BOZ)
- {
- gfc_error ("A BOZ literal constant at %L cannot appear as an "
- "actual argument in a function reference",
- &a->expr->where);
- return false;
- }
- }
+ for (arg = expr->value.function.actual; arg; arg = arg->next)
+ if (arg->expr && arg->expr->ts.type == BT_BOZ)
+ {
+ gfc_error ("A BOZ literal constant at %L cannot appear as an "
+ "actual argument in a function reference",
+ &arg->expr->where);
+ return false;
+ }
temp = need_full_assumed_size;
need_full_assumed_size = 0;
@@ -6553,21 +6548,6 @@ resolve_typebound_function (gfc_expr* e)
overridable = !e->value.compcall.tbp->non_overridable;
if (expr && expr->ts.type == BT_CLASS && e->value.compcall.name)
{
- /* If the base_object is not a variable, the corresponding actual
- argument expression must be stored in e->base_expression so
- that the corresponding tree temporary can be used as the base
- object in gfc_conv_procedure_call. */
- if (expr->expr_type != EXPR_VARIABLE)
- {
- gfc_actual_arglist *args;
-
- for (args= e->value.function.actual; args; args = args->next)
- {
- if (expr == args->expr)
- expr = args->expr;
- }
- }
-
/* Since the typebound operators are generic, we have to ensure
that any delays in resolution are corrected and that the vtab
is present. */
@@ -10789,9 +10769,12 @@ resolve_ordinary_assign (gfc_code *code, gfc_namespace *ns)
"component in a PURE procedure",
&rhs->where);
else
- gfc_error ("The impure variable at %L is assigned to "
- "a derived type variable with a POINTER "
- "component in a PURE procedure (12.6)",
+ /* F2008, C1283 (4). */
+ gfc_error ("In a pure subprogram an INTENT(IN) dummy argument "
+ "shall not be used as the expr at %L of an intrinsic "
+ "assignment statement in which the variable is of a "
+ "derived type if the derived type has a pointer "
+ "component at any level of component selection.",
&rhs->where);
return rval;
}
diff --git a/gcc/fortran/simplify.c b/gcc/fortran/simplify.c
index 8c1577ec269..fa5aefe20c6 100644
--- a/gcc/fortran/simplify.c
+++ b/gcc/fortran/simplify.c
@@ -6762,7 +6762,15 @@ gfc_simplify_reshape (gfc_expr *source, gfc_expr *shape_exp,
gfc_extract_int (e, &order[i]);
- gcc_assert (order[i] >= 1 && order[i] <= rank);
+ if (order[i] < 1 || order[i] > rank)
+ {
+ gfc_error ("Element with a value of %d in ORDER at %L must be "
+ "in the range [1, ..., %d] for the RESHAPE intrinsic "
+ "near %L", order[i], &order_exp->where, rank,
+ &shape_exp->where);
+ return &gfc_bad_expr;
+ }
+
order[i]--;
if (x[order[i]] != 0)
{
diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c
index b701f493440..3ad802e5d83 100644
--- a/gcc/fortran/trans-decl.c
+++ b/gcc/fortran/trans-decl.c
@@ -2691,8 +2691,9 @@ create_function_arglist (gfc_symbol * sym)
&& (!f->sym->attr.proc_pointer
&& f->sym->attr.flavor != FL_PROCEDURE))
DECL_BY_REFERENCE (parm) = 1;
- if (f->sym->attr.optional)
+ if (f->sym->attr.optional && !f->sym->attr.value)
{
+ /* With value, the argument is passed as is. */
gfc_allocate_lang_decl (parm);
GFC_DECL_OPTIONAL_ARGUMENT (parm) = 1;
}
diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c
index 965ab7786a1..65238ff623d 100644
--- a/gcc/fortran/trans-expr.c
+++ b/gcc/fortran/trans-expr.c
@@ -7031,8 +7031,11 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
gfc_allocate_lang_decl (result);
GFC_DECL_SAVED_DESCRIPTOR (result) = parmse.expr;
gfc_free_expr (class_expr);
- gcc_assert (parmse.pre.head == NULL_TREE
- && parmse.post.head == NULL_TREE);
+ /* -fcheck= can add diagnostic code, which has to be placed before
+ the call. */
+ if (parmse.pre.head != NULL)
+ gfc_add_expr_to_block (&se->pre, parmse.pre.head);
+ gcc_assert (parmse.post.head == NULL_TREE);
}
/* Follow the function call with the argument post block. */
diff --git a/gcc/fortran/trans-openmp.c b/gcc/fortran/trans-openmp.c
index f83bab4850e..dad11a24430 100644
--- a/gcc/fortran/trans-openmp.c
+++ b/gcc/fortran/trans-openmp.c
@@ -47,7 +47,21 @@ along with GCC; see the file COPYING3. If not see
int ompws_flags;
-/* True if OpenMP should treat this DECL as an optional argument. */
+/* True if OpenMP should regard this DECL as being a scalar which has Fortran's
+ allocatable or pointer attribute. */
+
+bool
+gfc_omp_is_allocatable_or_ptr (const_tree decl)
+{
+ return (DECL_P (decl)
+ && (GFC_DECL_GET_SCALAR_POINTER (decl)
+ || GFC_DECL_GET_SCALAR_ALLOCATABLE (decl)));
+}
+
+/* True if OpenMP should treat this DECL as an optional argument; note: for
+ arguments with VALUE attribute, the DECL is identical to nonoptional
+ arguments; hence, we return false here. To check whether the variable is
+ present, use the DECL which is passed as hidden argument. */
bool
gfc_omp_is_optional_argument (const_tree decl)
@@ -1887,6 +1901,9 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
case OMP_LIST_USE_DEVICE_PTR:
clause_code = OMP_CLAUSE_USE_DEVICE_PTR;
goto add_clause;
+ case OMP_LIST_USE_DEVICE_ADDR:
+ clause_code = OMP_CLAUSE_USE_DEVICE_ADDR;
+ goto add_clause;
case OMP_LIST_IS_DEVICE_PTR:
clause_code = OMP_CLAUSE_IS_DEVICE_PTR;
goto add_clause;
@@ -2170,7 +2187,8 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
OMP_CLAUSE_DECL (node4) = decl;
OMP_CLAUSE_SIZE (node4) = size_int (0);
decl = build_fold_indirect_ref (decl);
- if (TREE_CODE (TREE_TYPE (orig_decl)) == REFERENCE_TYPE
+ if ((TREE_CODE (TREE_TYPE (orig_decl)) == REFERENCE_TYPE
+ || gfc_omp_is_optional_argument (orig_decl))
&& (GFC_DECL_GET_SCALAR_POINTER (orig_decl)
|| GFC_DECL_GET_SCALAR_ALLOCATABLE (orig_decl)))
{
@@ -2414,7 +2432,11 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
{
tree decl = gfc_trans_omp_variable (n->sym, false);
if (gfc_omp_privatize_by_reference (decl))
- decl = build_fold_indirect_ref (decl);
+ {
+ if (gfc_omp_is_allocatable_or_ptr (decl))
+ decl = build_fold_indirect_ref (decl);
+ decl = build_fold_indirect_ref (decl);
+ }
else if (DECL_P (decl))
TREE_ADDRESSABLE (decl) = 1;
if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (decl)))
@@ -2436,7 +2458,12 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
OMP_CLAUSE_SIZE (node), elemsz);
}
else
- OMP_CLAUSE_DECL (node) = decl;
+ {
+ OMP_CLAUSE_DECL (node) = decl;
+ if (gfc_omp_is_allocatable_or_ptr (decl))
+ OMP_CLAUSE_SIZE (node)
+ = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (decl)));
+ }
}
else
{
diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h
index 405e88dd1c4..e96b22acc68 100644
--- a/gcc/fortran/trans.h
+++ b/gcc/fortran/trans.h
@@ -786,6 +786,7 @@ struct array_descr_info;
bool gfc_get_array_descr_info (const_tree, struct array_descr_info *);
/* In trans-openmp.c */
+bool gfc_omp_is_allocatable_or_ptr (const_tree);
bool gfc_omp_is_optional_argument (const_tree);
bool gfc_omp_privatize_by_reference (const_tree);
enum omp_clause_default_kind gfc_omp_predetermined_sharing (tree);
diff --git a/gcc/function-abi.cc b/gcc/function-abi.cc
index eee789a29e8..b4a18396367 100644
--- a/gcc/function-abi.cc
+++ b/gcc/function-abi.cc
@@ -229,3 +229,32 @@ insn_callee_abi (const rtx_insn *insn)
return default_function_abi;
}
+
+/* Return the ABI of the function called by CALL_EXPR EXP. Return the
+ default ABI for erroneous calls. */
+
+function_abi
+expr_callee_abi (const_tree exp)
+{
+ gcc_assert (TREE_CODE (exp) == CALL_EXPR);
+
+ if (tree fndecl = get_callee_fndecl (exp))
+ return fndecl_abi (fndecl);
+
+ tree callee = CALL_EXPR_FN (exp);
+ if (callee == error_mark_node)
+ return default_function_abi;
+
+ tree type = TREE_TYPE (callee);
+ if (type == error_mark_node)
+ return default_function_abi;
+
+ if (POINTER_TYPE_P (type))
+ {
+ type = TREE_TYPE (type);
+ if (type == error_mark_node)
+ return default_function_abi;
+ }
+
+ return fntype_abi (type);
+}
diff --git a/gcc/function-abi.h b/gcc/function-abi.h
index 9bb4d1768b3..96a49dfbea6 100644
--- a/gcc/function-abi.h
+++ b/gcc/function-abi.h
@@ -315,5 +315,6 @@ call_clobbered_in_region_p (unsigned int abis, const_hard_reg_set mask,
extern const predefined_function_abi &fntype_abi (const_tree);
extern function_abi fndecl_abi (const_tree);
extern function_abi insn_callee_abi (const rtx_insn *);
+extern function_abi expr_callee_abi (const_tree);
#endif
diff --git a/gcc/gcc.c b/gcc/gcc.c
index 1216cdd505a..c45a1df656b 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -4041,6 +4041,10 @@ driver_handle_option (struct gcc_options *opts,
diagnostic_color_init (dc, value);
break;
+ case OPT_fdiagnostics_urls_:
+ diagnostic_urls_init (dc, value);
+ break;
+
case OPT_fdiagnostics_format_:
diagnostic_output_format_init (dc,
(enum diagnostics_output_format)value);
@@ -7443,6 +7447,7 @@ driver::global_initializations ()
diagnostic_initialize (global_dc, 0);
diagnostic_color_init (global_dc);
+ diagnostic_urls_init (global_dc);
#ifdef GCC_DRIVER_HOST_INITIALIZATION
/* Perform host dependent initialization when needed. */
diff --git a/gcc/gengtype-lex.l b/gcc/gengtype-lex.l
index 1188691f785..57527495505 100644
--- a/gcc/gengtype-lex.l
+++ b/gcc/gengtype-lex.l
@@ -58,7 +58,7 @@ ITYPE {IWORD}({WS}{IWORD})*
/* Include '::' in identifiers to capture C++ scope qualifiers. */
ID {CID}({HWS}::{HWS}{CID})*
EOID [^[:alnum:]_]
-CXX_KEYWORD inline|public:|private:|protected:|template|operator|friend|static
+CXX_KEYWORD inline|public:|private:|protected:|template|operator|friend|static|mutable
%x in_struct in_struct_comment in_comment
%option warn noyywrap nounput nodefault perf-report
diff --git a/gcc/ggc-none.c b/gcc/ggc-none.c
index 6edec27868c..737429f9e49 100644
--- a/gcc/ggc-none.c
+++ b/gcc/ggc-none.c
@@ -72,3 +72,8 @@ void
ggc_grow (void)
{
}
+
+void
+ggc_trim (void)
+{
+}
diff --git a/gcc/ggc-page.c b/gcc/ggc-page.c
index 220f20c5cfe..4560206ac2e 100644
--- a/gcc/ggc-page.c
+++ b/gcc/ggc-page.c
@@ -529,7 +529,6 @@ static void clear_page_group_in_use (page_group *, char *);
#endif
static struct page_entry * alloc_page (unsigned);
static void free_page (struct page_entry *);
-static void release_pages (void);
static void clear_marks (void);
static void sweep_pages (void);
static void ggc_recalculate_in_use_p (page_entry *);
@@ -1016,6 +1015,8 @@ free_page (page_entry *entry)
static void
release_pages (void)
{
+ size_t n1 = 0;
+ size_t n2 = 0;
#ifdef USING_MADVISE
page_entry *p, *start_p;
char *start;
@@ -1061,6 +1062,7 @@ release_pages (void)
else
G.free_pages = p;
G.bytes_mapped -= mapped_len;
+ n1 += len;
continue;
}
prev = newprev;
@@ -1092,6 +1094,7 @@ release_pages (void)
/* Don't count those pages as mapped to not touch the garbage collector
unnecessarily. */
G.bytes_mapped -= len;
+ n2 += len;
while (start_p != p)
{
start_p->discarded = true;
@@ -1124,6 +1127,7 @@ release_pages (void)
}
munmap (start, len);
+ n1 += len;
G.bytes_mapped -= len;
}
@@ -1152,10 +1156,20 @@ release_pages (void)
*gp = g->next;
G.bytes_mapped -= g->alloc_size;
free (g->allocation);
+ n1 += g->alloc_size;
}
else
gp = &g->next;
#endif
+ if (!quiet_flag && (n1 || n2))
+ {
+ fprintf (stderr, " {GC");
+ if (n1)
+ fprintf (stderr, " released %luk", (unsigned long)(n1 / 1024));
+ if (n2)
+ fprintf (stderr, " madv_dontneed %luk", (unsigned long)(n2 / 1024));
+ fprintf (stderr, "}");
+ }
}
/* This table provides a fast way to determine ceil(log_2(size)) for
@@ -2178,19 +2192,22 @@ ggc_collect (void)
return;
timevar_push (TV_GC);
- if (!quiet_flag)
- fprintf (stderr, " {GC %luk -> ", (unsigned long) G.allocated / 1024);
if (GGC_DEBUG_LEVEL >= 2)
fprintf (G.debug_file, "BEGIN COLLECTING\n");
/* Zero the total allocated bytes. This will be recalculated in the
sweep phase. */
+ size_t allocated = G.allocated;
G.allocated = 0;
/* Release the pages we freed the last time we collected, but didn't
reuse in the interim. */
release_pages ();
+ /* Output this later so we do not interfere with release_pages. */
+ if (!quiet_flag)
+ fprintf (stderr, " {GC %luk -> ", (unsigned long) allocated / 1024);
+
/* Indicate that we've seen collections at this context depth. */
G.context_depth_collections = ((unsigned long)1 << (G.context_depth + 1)) - 1;
@@ -2221,9 +2238,25 @@ ggc_collect (void)
fprintf (G.debug_file, "END COLLECTING\n");
}
-/* Assume that all GGC memory is reachable and grow the limits for next collection.
- With checking, trigger GGC so -Q compilation outputs how much of memory really is
- reachable. */
+/* Return free pages to the system. */
+
+void
+ggc_trim ()
+{
+ timevar_push (TV_GC);
+ G.allocated = 0;
+ sweep_pages ();
+ release_pages ();
+ if (!quiet_flag)
+ fprintf (stderr, " {GC trimmed to %luk, %luk mapped}",
+ (unsigned long) G.allocated / 1024,
+ (unsigned long) G.bytes_mapped / 1024);
+ timevar_pop (TV_GC);
+}
+
+/* Assume that all GGC memory is reachable and grow the limits for next
+ collection. With checking, trigger GGC so -Q compilation outputs how much
+ of memory really is reachable. */
void
ggc_grow (void)
diff --git a/gcc/ggc.h b/gcc/ggc.h
index 60273f2e57d..31606dc843f 100644
--- a/gcc/ggc.h
+++ b/gcc/ggc.h
@@ -243,6 +243,9 @@ extern const char *ggc_alloc_string (const char *contents, int length
function is called, not during allocations. */
extern void ggc_collect (void);
+/* Return unused memory pages to the system. */
+extern void ggc_trim (void);
+
/* Assume that all GGC memory is reachable and grow the limits for next collection. */
extern void ggc_grow (void);
diff --git a/gcc/gimple-expr.c b/gcc/gimple-expr.c
index 4082828e198..1738af186d7 100644
--- a/gcc/gimple-expr.c
+++ b/gcc/gimple-expr.c
@@ -574,6 +574,7 @@ gimple_cond_get_ops_from_tree (tree cond, enum tree_code *code_p,
|| TREE_CODE (cond) == TRUTH_NOT_EXPR
|| is_gimple_min_invariant (cond)
|| SSA_VAR_P (cond));
+ gcc_checking_assert (!tree_could_throw_p (cond));
extract_ops_from_tree (cond, code_p, lhs_p, rhs_p);
@@ -605,17 +606,33 @@ is_gimple_lvalue (tree t)
|| TREE_CODE (t) == BIT_FIELD_REF);
}
-/* Return true if T is a GIMPLE condition. */
+/* Helper for is_gimple_condexpr and is_gimple_condexpr_for_cond. */
-bool
-is_gimple_condexpr (tree t)
+static bool
+is_gimple_condexpr_1 (tree t, bool allow_traps)
{
return (is_gimple_val (t) || (COMPARISON_CLASS_P (t)
- && !tree_could_throw_p (t)
+ && (allow_traps || !tree_could_throw_p (t))
&& is_gimple_val (TREE_OPERAND (t, 0))
&& is_gimple_val (TREE_OPERAND (t, 1))));
}
+/* Return true if T is a GIMPLE condition. */
+
+bool
+is_gimple_condexpr (tree t)
+{
+ return is_gimple_condexpr_1 (t, true);
+}
+
+/* Like is_gimple_condexpr, but does not allow T to trap. */
+
+bool
+is_gimple_condexpr_for_cond (tree t)
+{
+ return is_gimple_condexpr_1 (t, false);
+}
+
/* Return true if T is a gimple address. */
bool
diff --git a/gcc/gimple-expr.h b/gcc/gimple-expr.h
index 1ad1432bd17..0925aeb0f57 100644
--- a/gcc/gimple-expr.h
+++ b/gcc/gimple-expr.h
@@ -41,6 +41,7 @@ extern void gimple_cond_get_ops_from_tree (tree, enum tree_code *, tree *,
tree *);
extern bool is_gimple_lvalue (tree);
extern bool is_gimple_condexpr (tree);
+extern bool is_gimple_condexpr_for_cond (tree);
extern bool is_gimple_address (const_tree);
extern bool is_gimple_invariant_address (const_tree);
extern bool is_gimple_ip_invariant_address (const_tree);
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index 8d642de2f67..a085ab2beaf 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -1348,6 +1348,10 @@ get_range_strlen_tree (tree arg, bitmap *visited, strlen_range_kind rkind,
}
}
+ /* Set if VAL represents the maximum length based on array size (set
+ when exact length cannot be determined). */
+ bool maxbound = false;
+
if (!val && rkind == SRK_LENRANGE)
{
if (TREE_CODE (arg) == ADDR_EXPR)
@@ -1443,6 +1447,7 @@ get_range_strlen_tree (tree arg, bitmap *visited, strlen_range_kind rkind,
pdata->minlen = ssize_int (0);
}
}
+ maxbound = true;
}
if (!val)
@@ -1456,25 +1461,23 @@ get_range_strlen_tree (tree arg, bitmap *visited, strlen_range_kind rkind,
&& tree_int_cst_lt (val, pdata->minlen)))
pdata->minlen = val;
- if (pdata->maxbound)
+ if (pdata->maxbound && TREE_CODE (pdata->maxbound) == INTEGER_CST)
{
/* Adjust the tighter (more optimistic) string length bound
if necessary and proceed to adjust the more conservative
bound. */
if (TREE_CODE (val) == INTEGER_CST)
{
- if (TREE_CODE (pdata->maxbound) == INTEGER_CST)
- {
- if (tree_int_cst_lt (pdata->maxbound, val))
- pdata->maxbound = val;
- }
- else
- pdata->maxbound = build_all_ones_cst (size_type_node);
+ if (tree_int_cst_lt (pdata->maxbound, val))
+ pdata->maxbound = val;
}
else
pdata->maxbound = val;
}
- else
+ else if (pdata->maxbound || maxbound)
+ /* Set PDATA->MAXBOUND only if it either isn't INTEGER_CST or
+ if VAL corresponds to the maximum length determined based
+ on the type of the object. */
pdata->maxbound = val;
if (tight_bound)
@@ -1655,8 +1658,11 @@ get_range_strlen (tree arg, bitmap *visited,
/* Try to obtain the range of the lengths of the string(s) referenced
by ARG, or the size of the largest array ARG refers to if the range
- of lengths cannot be determined, and store all in *PDATA. ELTSIZE
- is the expected size of the string element in bytes: 1 for char and
+ of lengths cannot be determined, and store all in *PDATA which must
+ be zero-initialized on input except PDATA->MAXBOUND may be set to
+ a non-null tree node other than INTEGER_CST to request to have it
+ set to the length of the longest string in a PHI. ELTSIZE is
+ the expected size of the string element in bytes: 1 for char and
some power of 2 for wide characters.
Return true if the range [PDATA->MINLEN, PDATA->MAXLEN] is suitable
for optimization. Returning false means that a nonzero PDATA->MINLEN
@@ -1668,6 +1674,7 @@ bool
get_range_strlen (tree arg, c_strlen_data *pdata, unsigned eltsize)
{
bitmap visited = NULL;
+ tree maxbound = pdata->maxbound;
if (!get_range_strlen (arg, &visited, SRK_LENRANGE, pdata, eltsize))
{
@@ -1680,9 +1687,10 @@ get_range_strlen (tree arg, c_strlen_data *pdata, unsigned eltsize)
else if (!pdata->minlen)
pdata->minlen = ssize_int (0);
- /* Unless its null, leave the more conservative MAXBOUND unchanged. */
- if (!pdata->maxbound)
- pdata->maxbound = pdata->maxlen;
+ /* If it's unchanged from it initial non-null value, set the conservative
+ MAXBOUND to SIZE_MAX. Otherwise leave it null (if it is null). */
+ if (maxbound && pdata->maxbound == maxbound)
+ pdata->maxbound = build_all_ones_cst (size_type_node);
if (visited)
BITMAP_FREE (visited);
diff --git a/gcc/gimple-iterator.h b/gcc/gimple-iterator.h
index ee6f5b1f54d..ccd93d936be 100644
--- a/gcc/gimple-iterator.h
+++ b/gcc/gimple-iterator.h
@@ -325,28 +325,31 @@ gsi_one_nondebug_before_end_p (gimple_stmt_iterator i)
return gsi_end_p (i);
}
-/* Iterates I statement iterator to the next non-virtual statement. */
+/* Advance I statement iterator to the next non-virtual GIMPLE_PHI
+ statement. */
static inline void
gsi_next_nonvirtual_phi (gphi_iterator *i)
{
- gphi *phi;
-
- if (gsi_end_p (*i))
- return;
-
- phi = i->phi ();
- gcc_assert (phi != NULL);
-
- while (virtual_operand_p (gimple_phi_result (phi)))
+ do
{
gsi_next (i);
+ }
+ while (!gsi_end_p (*i) && virtual_operand_p (gimple_phi_result (i->phi ())));
+}
- if (gsi_end_p (*i))
- return;
+/* Return a new iterator pointing to the first non-virtual phi statement in
+ basic block BB. */
- phi = i->phi ();
- }
+static inline gphi_iterator
+gsi_start_nonvirtual_phis (basic_block bb)
+{
+ gphi_iterator i = gsi_start_phis (bb);
+
+ if (!gsi_end_p (i) && virtual_operand_p (gimple_phi_result (i.phi ())))
+ gsi_next_nonvirtual_phi (&i);
+
+ return i;
}
/* Return the basic block associated with this iterator. */
diff --git a/gcc/gimple-ssa-sprintf.c b/gcc/gimple-ssa-sprintf.c
index b11d7989d5e..b548bbd95e3 100644
--- a/gcc/gimple-ssa-sprintf.c
+++ b/gcc/gimple-ssa-sprintf.c
@@ -1974,8 +1974,11 @@ get_string_length (tree str, unsigned eltsize, const vr_values *vr)
if (!str)
return fmtresult ();
- /* Try to determine the dynamic string length first. */
+ /* Try to determine the dynamic string length first.
+ Set MAXBOUND to an arbitrary non-null non-integer node as a request
+ to have it set to the length of the longest string in a PHI. */
c_strlen_data lendata = { };
+ lendata.maxbound = str;
if (eltsize == 1)
get_range_strlen_dynamic (str, &lendata, vr);
else
@@ -1988,26 +1991,27 @@ get_string_length (tree str, unsigned eltsize, const vr_values *vr)
get_range_strlen (str, &lendata, eltsize);
}
- /* LENDATA.MAXBOUND is null when LENDATA.MIN corresponds to the shortest
- string referenced by STR. Otherwise, if it's not equal to .MINLEN it
- corresponds to the bound of the largest array STR refers to, if known,
- or it's SIZE_MAX otherwise. */
+ /* If LENDATA.MAXBOUND is not equal to .MINLEN it corresponds to the bound
+ of the largest array STR refers to, if known, or it's set to SIZE_MAX
+ otherwise. */
/* Return the default result when nothing is known about the string. */
- if (lendata.maxbound)
+ if ((lendata.maxbound && !tree_fits_uhwi_p (lendata.maxbound))
+ || !tree_fits_uhwi_p (lendata.maxlen))
{
- if (integer_all_onesp (lendata.maxbound)
- && integer_all_onesp (lendata.maxlen))
- return fmtresult ();
-
- if (!tree_fits_uhwi_p (lendata.maxbound)
- || !tree_fits_uhwi_p (lendata.maxlen))
- return fmtresult ();
-
- unsigned HOST_WIDE_INT lenmax = tree_to_uhwi (max_object_size ()) - 2;
- if (lenmax <= tree_to_uhwi (lendata.maxbound)
- && lenmax <= tree_to_uhwi (lendata.maxlen))
- return fmtresult ();
+ fmtresult res;
+ res.nonstr = lendata.decl;
+ return res;
+ }
+
+ unsigned HOST_WIDE_INT lenmax = tree_to_uhwi (max_object_size ()) - 2;
+ if (integer_zerop (lendata.minlen)
+ && (!lendata.maxbound || lenmax <= tree_to_uhwi (lendata.maxbound))
+ && lenmax <= tree_to_uhwi (lendata.maxlen))
+ {
+ fmtresult res;
+ res.nonstr = lendata.decl;
+ return res;
}
HOST_WIDE_INT min
@@ -2056,9 +2060,9 @@ get_string_length (tree str, unsigned eltsize, const vr_values *vr)
{
/* When the upper bound is unknown (it can be zero or excessive)
set the likely length to the greater of 1. If MAXBOUND is
- set, also reset the length of the lower bound to zero. */
+ known, also reset the length of the lower bound to zero. */
res.range.likely = res.range.min ? res.range.min : warn_level > 1;
- if (lendata.maxbound)
+ if (lendata.maxbound && !integer_all_onesp (lendata.maxbound))
res.range.min = 0;
}
diff --git a/gcc/gimple-streamer-out.c b/gcc/gimple-streamer-out.c
index 34b8d6fda7d..7185c07f36b 100644
--- a/gcc/gimple-streamer-out.c
+++ b/gcc/gimple-streamer-out.c
@@ -57,7 +57,7 @@ output_phi (struct output_block *ob, gphi *phi)
/* Emit statement STMT on the main stream of output block OB. */
static void
-output_gimple_stmt (struct output_block *ob, gimple *stmt)
+output_gimple_stmt (struct output_block *ob, struct function *fn, gimple *stmt)
{
unsigned i;
enum gimple_code code;
@@ -80,7 +80,7 @@ output_gimple_stmt (struct output_block *ob, gimple *stmt)
as_a <gassign *> (stmt)),
1);
bp_pack_value (&bp, gimple_has_volatile_ops (stmt), 1);
- hist = gimple_histogram_value (cfun, stmt);
+ hist = gimple_histogram_value (fn, stmt);
bp_pack_value (&bp, hist != NULL, 1);
bp_pack_var_len_unsigned (&bp, stmt->subcode);
@@ -139,7 +139,7 @@ output_gimple_stmt (struct output_block *ob, gimple *stmt)
so that we do not have to deal with type mismatches on
merged symbols during IL read in. The first operand
of GIMPLE_DEBUG must be a decl, not MEM_REF, though. */
- if (op && (i || !is_gimple_debug (stmt)))
+ if (!flag_wpa && op && (i || !is_gimple_debug (stmt)))
{
basep = &op;
if (TREE_CODE (*basep) == ADDR_EXPR)
@@ -147,7 +147,7 @@ output_gimple_stmt (struct output_block *ob, gimple *stmt)
while (handled_component_p (*basep))
basep = &TREE_OPERAND (*basep, 0);
if (VAR_P (*basep)
- && !auto_var_in_fn_p (*basep, current_function_decl)
+ && !auto_var_in_fn_p (*basep, fn->decl)
&& !DECL_REGISTER (*basep))
{
bool volatilep = TREE_THIS_VOLATILE (*basep);
@@ -228,7 +228,7 @@ output_bb (struct output_block *ob, basic_block bb, struct function *fn)
print_gimple_stmt (streamer_dump_file, stmt, 0, TDF_SLIM);
}
- output_gimple_stmt (ob, stmt);
+ output_gimple_stmt (ob, fn, stmt);
/* Emit the EH region holding STMT. */
region = lookup_stmt_eh_lp_fn (fn, stmt);
diff --git a/gcc/gimple.c b/gcc/gimple.c
index 8e828a5f169..a874c29454c 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -2149,10 +2149,22 @@ gimple_could_trap_p_1 (gimple *s, bool include_mem, bool include_stores)
return false;
case GIMPLE_ASSIGN:
- t = gimple_expr_type (s);
op = gimple_assign_rhs_code (s);
+
+ /* For COND_EXPR and VEC_COND_EXPR only the condition may trap. */
+ if (op == COND_EXPR || op == VEC_COND_EXPR)
+ return tree_could_trap_p (gimple_assign_rhs1 (s));
+
+ /* For comparisons we need to check rhs operand types instead of rhs type
+ (which is BOOLEAN_TYPE). */
+ if (TREE_CODE_CLASS (op) == tcc_comparison)
+ t = TREE_TYPE (gimple_assign_rhs1 (s));
+ else
+ t = gimple_expr_type (s);
+
if (get_gimple_rhs_class (op) == GIMPLE_BINARY_RHS)
div = gimple_assign_rhs2 (s);
+
return (operation_could_trap_p (op, FLOAT_TYPE_P (t),
(INTEGRAL_TYPE_P (t)
&& TYPE_OVERFLOW_TRAPS (t)),
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 88d6571976f..836706961f3 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -4142,8 +4142,8 @@ gimplify_cond_expr (tree *expr_p, gimple_seq *pre_p, fallback_t fallback)
/* Now do the normal gimplification. */
/* Gimplify condition. */
- ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, NULL, is_gimple_condexpr,
- fb_rvalue);
+ ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, NULL,
+ is_gimple_condexpr_for_cond, fb_rvalue);
if (ret == GS_ERROR)
return GS_ERROR;
gcc_assert (TREE_OPERAND (expr, 0) != NULL_TREE);
@@ -12976,6 +12976,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
else if (gimple_test_f == is_gimple_val
|| gimple_test_f == is_gimple_call_addr
|| gimple_test_f == is_gimple_condexpr
+ || gimple_test_f == is_gimple_condexpr_for_cond
|| gimple_test_f == is_gimple_mem_rhs
|| gimple_test_f == is_gimple_mem_rhs_or_call
|| gimple_test_f == is_gimple_reg_rhs
diff --git a/gcc/ginclude/float.h b/gcc/ginclude/float.h
index 4767d7b9dfb..dc91c75603e 100644
--- a/gcc/ginclude/float.h
+++ b/gcc/ginclude/float.h
@@ -426,9 +426,13 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#endif /* __STDC_WANT_IEC_60559_TYPES_EXT__. */
-#ifdef __STDC_WANT_DEC_FP__
-/* Draft Technical Report 24732, extension for decimal floating-point
- arithmetic: Characteristic of decimal floating types <float.h>. */
+#ifdef __DEC32_MANT_DIG__
+#if (defined __STDC_WANT_DEC_FP__ \
+ || defined __STDC_WANT_IEC_60559_DFP_EXT__ \
+ || (defined __STDC_VERSION__ && __STDC_VERSION__ > 201710L))
+/* C2X; formerly Technical Report 24732, extension for decimal
+ floating-point arithmetic: Characteristic of decimal floating types
+ <float.h>, and TS 18661-2. */
/* Number of base-FLT_RADIX digits in the significand, p. */
#undef DEC32_MANT_DIG
@@ -480,14 +484,6 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#define DEC64_MIN __DEC64_MIN__
#define DEC128_MIN __DEC128_MIN__
-/* Minimum subnormal positive floating-point number. */
-#undef DEC32_SUBNORMAL_MIN
-#undef DEC64_SUBNORMAL_MIN
-#undef DEC128_SUBNORMAL_MIN
-#define DEC32_SUBNORMAL_MIN __DEC32_SUBNORMAL_MIN__
-#define DEC64_SUBNORMAL_MIN __DEC64_SUBNORMAL_MIN__
-#define DEC128_SUBNORMAL_MIN __DEC128_SUBNORMAL_MIN__
-
/* The floating-point expression evaluation method.
-1 indeterminate
0 evaluate all operations and constants just to the range and
@@ -502,6 +498,33 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#undef DEC_EVAL_METHOD
#define DEC_EVAL_METHOD __DEC_EVAL_METHOD__
-#endif /* __STDC_WANT_DEC_FP__ */
+#endif /* __STDC_WANT_DEC_FP__ || __STDC_WANT_IEC_60559_DFP_EXT__ || C2X. */
+
+#ifdef __STDC_WANT_DEC_FP__
+
+/* Minimum subnormal positive floating-point number. */
+#undef DEC32_SUBNORMAL_MIN
+#undef DEC64_SUBNORMAL_MIN
+#undef DEC128_SUBNORMAL_MIN
+#define DEC32_SUBNORMAL_MIN __DEC32_SUBNORMAL_MIN__
+#define DEC64_SUBNORMAL_MIN __DEC64_SUBNORMAL_MIN__
+#define DEC128_SUBNORMAL_MIN __DEC128_SUBNORMAL_MIN__
+
+#endif /* __STDC_WANT_DEC_FP__. */
+
+#if (defined __STDC_WANT_IEC_60559_DFP_EXT__ \
+ || (defined __STDC_VERSION__ && __STDC_VERSION__ > 201710L))
+
+/* Minimum subnormal positive floating-point number. */
+#undef DEC32_TRUE_MIN
+#undef DEC64_TRUE_MIN
+#undef DEC128_TRUE_MIN
+#define DEC32_TRUE_MIN __DEC32_SUBNORMAL_MIN__
+#define DEC64_TRUE_MIN __DEC64_SUBNORMAL_MIN__
+#define DEC128_TRUE_MIN __DEC128_SUBNORMAL_MIN__
+
+#endif /* __STDC_WANT_IEC_60559_DFP_EXT__ || C2X. */
+
+#endif /* __DEC32_MANT_DIG__ */
#endif /* _FLOAT_H___ */
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index 1508eb16650..1c90e55e9b1 100644
--- a/gcc/go/gofrontend/MERGE
+++ b/gcc/go/gofrontend/MERGE
@@ -1,4 +1,4 @@
-ddfb845fad1f2e8b84383f262ed5ea5be7b3e35a
+f174fdad69cad42309984dfa108d80f2ae8a9f78
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
diff --git a/gcc/go/gofrontend/go-encode-id.cc b/gcc/go/gofrontend/go-encode-id.cc
index 7c7aa13ea1c..550da9759f6 100644
--- a/gcc/go/gofrontend/go-encode-id.cc
+++ b/gcc/go/gofrontend/go-encode-id.cc
@@ -253,3 +253,16 @@ go_mangle_struct_tag(const std::string& tag)
}
return ret;
}
+
+// Encode a package path.
+
+std::string
+go_mangle_pkgpath(const std::string& pkgpath)
+{
+ std::string s = pkgpath;
+ for (size_t i = s.find('.');
+ i != std::string::npos;
+ i = s.find('.', i + 1))
+ s.replace(i, 1, ".x2e"); // 0x2e is the ASCII encoding for '.'
+ return s;
+}
diff --git a/gcc/go/gofrontend/go-encode-id.h b/gcc/go/gofrontend/go-encode-id.h
index 70126bae9d1..2d09b0c545d 100644
--- a/gcc/go/gofrontend/go-encode-id.h
+++ b/gcc/go/gofrontend/go-encode-id.h
@@ -34,4 +34,12 @@ go_selectively_encode_id(const std::string &id);
extern std::string
go_mangle_struct_tag(const std::string& tag);
+// Encode a package path. A package path can contain any arbitrary
+// character, including '.'. go_encode_id expects that any '.' will
+// be inserted by name mangling in a controlled manner. So first
+// translate any '.' using the same .x encoding as used by
+// go_mangle_struct_tag.
+extern std::string
+go_mangle_pkgpath(const std::string& pkgpath);
+
#endif // !defined(GO_ENCODE_ID_H)
diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc
index a79cfc3a9a7..1ee49dcfa9c 100644
--- a/gcc/go/gofrontend/gogo.cc
+++ b/gcc/go/gofrontend/gogo.cc
@@ -298,7 +298,7 @@ void
Gogo::set_pkgpath(const std::string& arg)
{
go_assert(!this->pkgpath_set_);
- this->pkgpath_ = arg;
+ this->pkgpath_ = go_mangle_pkgpath(arg);
this->pkgpath_set_ = true;
this->pkgpath_from_option_ = true;
}
@@ -396,7 +396,8 @@ Gogo::set_package_name(const std::string& package_name,
{
if (!this->prefix_from_option_)
this->prefix_ = "go";
- this->pkgpath_ = this->prefix_ + '.' + package_name;
+ this->pkgpath_ = (go_mangle_pkgpath(this->prefix_) + '.'
+ + package_name);
this->pkgpath_symbol_ = (Gogo::pkgpath_for_symbol(this->prefix_) + '.'
+ Gogo::pkgpath_for_symbol(package_name));
}
diff --git a/gcc/ipa-icf.c b/gcc/ipa-icf.c
index 009aeb487dd..8bf0f7c6dd5 100644
--- a/gcc/ipa-icf.c
+++ b/gcc/ipa-icf.c
@@ -1688,13 +1688,10 @@ sem_function::compare_phi_node (basic_block bb1, basic_block bb2)
gcc_assert (bb1 != NULL);
gcc_assert (bb2 != NULL);
- si2 = gsi_start_phis (bb2);
- for (si1 = gsi_start_phis (bb1); !gsi_end_p (si1);
- gsi_next (&si1))
+ si2 = gsi_start_nonvirtual_phis (bb2);
+ for (si1 = gsi_start_nonvirtual_phis (bb1); !gsi_end_p (si1);
+ gsi_next_nonvirtual_phi (&si1))
{
- gsi_next_nonvirtual_phi (&si1);
- gsi_next_nonvirtual_phi (&si2);
-
if (gsi_end_p (si1) && gsi_end_p (si2))
break;
@@ -1731,7 +1728,7 @@ sem_function::compare_phi_node (basic_block bb1, basic_block bb2)
return return_false ();
}
- gsi_next (&si2);
+ gsi_next_nonvirtual_phi (&si2);
}
return true;
diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index e79add12b1e..5020f4a44d5 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -5109,6 +5109,19 @@ ipcp_update_bits (struct cgraph_node *node)
}
}
+bool
+ipa_vr::nonzero_p (tree expr_type) const
+{
+ if (type == VR_ANTI_RANGE && wi::eq_p (min, 0) && wi::eq_p (max, 0))
+ return true;
+
+ unsigned prec = TYPE_PRECISION (expr_type);
+ return (type == VR_RANGE
+ && TYPE_UNSIGNED (expr_type)
+ && wi::eq_p (min, wi::one (prec))
+ && wi::eq_p (max, wi::max_value (prec, TYPE_SIGN (expr_type))));
+}
+
/* Update value range of formal parameters as described in
ipcp_transformation. */
@@ -5181,9 +5194,7 @@ ipcp_update_vr (struct cgraph_node *node)
TYPE_SIGN (type)));
}
else if (POINTER_TYPE_P (TREE_TYPE (ddef))
- && vr[i].type == VR_ANTI_RANGE
- && wi::eq_p (vr[i].min, 0)
- && wi::eq_p (vr[i].max, 0))
+ && vr[i].nonzero_p (TREE_TYPE (ddef)))
{
if (dump_file)
fprintf (dump_file, "Setting nonnull for %u\n", i);
diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h
index 0ff80854284..eb3397a6d81 100644
--- a/gcc/ipa-prop.h
+++ b/gcc/ipa-prop.h
@@ -165,6 +165,7 @@ public:
enum value_range_kind type;
wide_int min;
wide_int max;
+ bool nonzero_p (tree) const;
};
/* A jump function for a callsite represents the values passed as actual
diff --git a/gcc/ipa-reference.c b/gcc/ipa-reference.c
index 78737aa9e3f..977eb2d0fd8 100644
--- a/gcc/ipa-reference.c
+++ b/gcc/ipa-reference.c
@@ -46,7 +46,6 @@ along with GCC; see the file COPYING3. If not see
#include "cgraph.h"
#include "data-streamer.h"
#include "calls.h"
-#include "splay-tree.h"
#include "ipa-utils.h"
#include "ipa-reference.h"
#include "symbol-summary.h"
@@ -92,9 +91,11 @@ struct ipa_reference_vars_info_d
typedef struct ipa_reference_vars_info_d *ipa_reference_vars_info_t;
-/* This splay tree contains all of the static variables that are
+/* This map contains all of the static variables that are
being considered by the compilation level alias analysis. */
-static splay_tree reference_vars_to_consider;
+typedef hash_map<int_hash <unsigned int, -1U>, tree>
+ reference_vars_to_consider_t;
+static reference_vars_to_consider_t *reference_vars_to_consider;
/* Set of all interesting module statics. A bit is set for every module
static we are considering. This is added to the local info when asm
@@ -272,9 +273,7 @@ is_proper_for_analysis (tree t)
static const char *
get_static_name (int index)
{
- splay_tree_node stn =
- splay_tree_lookup (reference_vars_to_consider, index);
- return fndecl_name ((tree)(stn->value));
+ return fndecl_name (*reference_vars_to_consider->get (index));
}
/* Dump a set of static vars to FILE. */
@@ -416,7 +415,7 @@ ipa_init (void)
ipa_init_p = true;
if (dump_file)
- reference_vars_to_consider = splay_tree_new (splay_tree_compare_ints, 0, 0);
+ reference_vars_to_consider = new reference_vars_to_consider_t(251);
bitmap_obstack_initialize (&local_info_obstack);
bitmap_obstack_initialize (&optimization_summary_obstack);
@@ -476,9 +475,8 @@ analyze_function (struct cgraph_node *fn)
&& bitmap_set_bit (all_module_statics, ipa_reference_var_uid (var)))
{
if (dump_file)
- splay_tree_insert (reference_vars_to_consider,
- ipa_reference_var_uid (var),
- (splay_tree_value)var);
+ reference_vars_to_consider->put (ipa_reference_var_uid (var),
+ var);
}
switch (ref->use)
{
@@ -891,15 +889,14 @@ propagate (void)
bitmap_obstack_release (&local_info_obstack);
- if (ipa_ref_var_info_summaries == NULL)
+ if (ipa_ref_var_info_summaries != NULL)
{
delete ipa_ref_var_info_summaries;
ipa_ref_var_info_summaries = NULL;
}
- ipa_ref_var_info_summaries = NULL;
if (dump_file)
- splay_tree_delete (reference_vars_to_consider);
+ delete reference_vars_to_consider;
reference_vars_to_consider = NULL;
return remove_p ? TODO_remove_functions : 0;
}
@@ -969,8 +966,7 @@ stream_out_bitmap (struct lto_simple_output_block *ob,
return;
EXECUTE_IF_AND_IN_BITMAP (bits, ltrans_statics, 0, index, bi)
{
- tree decl = (tree)splay_tree_lookup (reference_vars_to_consider,
- index)->value;
+ tree decl = *reference_vars_to_consider->get (index);
lto_output_var_decl_index (ob->decl_state, ob->main_stream, decl);
}
}
@@ -988,7 +984,7 @@ ipa_reference_write_optimization_summary (void)
auto_bitmap ltrans_statics;
int i;
- reference_vars_to_consider = splay_tree_new (splay_tree_compare_ints, 0, 0);
+ reference_vars_to_consider = new reference_vars_to_consider_t (251);
/* See what variables we are interested in. */
for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
@@ -1002,9 +998,8 @@ ipa_reference_write_optimization_summary (void)
{
tree decl = vnode->decl;
bitmap_set_bit (ltrans_statics, ipa_reference_var_uid (decl));
- splay_tree_insert (reference_vars_to_consider,
- ipa_reference_var_uid (decl),
- (splay_tree_value)decl);
+ reference_vars_to_consider->put
+ (ipa_reference_var_uid (decl), decl);
ltrans_statics_bitcount ++;
}
}
@@ -1046,7 +1041,7 @@ ipa_reference_write_optimization_summary (void)
}
}
lto_destroy_simple_output_block (ob);
- splay_tree_delete (reference_vars_to_consider);
+ delete reference_vars_to_consider;
}
/* Deserialize the ipa info for lto. */
diff --git a/gcc/ira-lives.c b/gcc/ira-lives.c
index cce73a1c3d4..098b0e73953 100644
--- a/gcc/ira-lives.c
+++ b/gcc/ira-lives.c
@@ -633,9 +633,28 @@ check_and_make_def_use_conflict (rtx dreg, rtx orig_dreg,
/* Check and make if necessary conflicts for definition DEF of class
DEF_CL of the current insn with input operands. Process only
- constraints of alternative ALT. */
+ constraints of alternative ALT.
+
+ One of three things is true when this function is called:
+
+ (1) DEF is an earlyclobber for alternative ALT. Input operands then
+ conflict with DEF in ALT unless they explicitly match DEF via 0-9
+ constraints.
+
+ (2) DEF matches (via 0-9 constraints) an operand that is an
+ earlyclobber for alternative ALT. Other input operands then
+ conflict with DEF in ALT.
+
+ (3) [FOR_TIE_P] Some input operand X matches DEF for alternative ALT.
+ Input operands with a different value from X then conflict with
+ DEF in ALT.
+
+ However, there's still a judgement call to make when deciding
+ whether a conflict in ALT is important enough to be reflected
+ in the pan-alternative allocno conflict set. */
static void
-check_and_make_def_conflict (int alt, int def, enum reg_class def_cl)
+check_and_make_def_conflict (int alt, int def, enum reg_class def_cl,
+ bool for_tie_p)
{
int use, use_match;
ira_allocno_t a;
@@ -669,14 +688,40 @@ check_and_make_def_conflict (int alt, int def, enum reg_class def_cl)
if (use == def || recog_data.operand_type[use] == OP_OUT)
continue;
+ /* An earlyclobber on DEF doesn't apply to an input operand X if X
+ explicitly matches DEF, but it applies to other input operands
+ even if they happen to be the same value as X.
+
+ In contrast, if an input operand X is tied to a non-earlyclobber
+ DEF, there's no conflict with other input operands that have the
+ same value as X. */
+ if (op_alt[use].matches == def
+ || (for_tie_p
+ && rtx_equal_p (recog_data.operand[use],
+ recog_data.operand[op_alt[def].matched])))
+ continue;
+
if (op_alt[use].anything_ok)
use_cl = ALL_REGS;
else
use_cl = op_alt[use].cl;
+ if (use_cl == NO_REGS)
+ continue;
+
+ /* If DEF is simply a tied operand, ignore cases in which this
+ alternative requires USE to have a likely-spilled class.
+ Adding a conflict would just constrain USE further if DEF
+ happens to be allocated first. */
+ if (for_tie_p && targetm.class_likely_spilled_p (use_cl))
+ continue;
/* If there's any alternative that allows USE to match DEF, do not
record a conflict. If that causes us to create an invalid
- instruction due to the earlyclobber, reload must fix it up. */
+ instruction due to the earlyclobber, reload must fix it up.
+
+ Likewise, if we're treating a tied DEF like a partial earlyclobber,
+ do not record a conflict if there's another alternative in which
+ DEF is neither tied nor earlyclobber. */
for (alt1 = 0; alt1 < recog_data.n_alternatives; alt1++)
{
if (!TEST_BIT (preferred_alternatives, alt1))
@@ -691,6 +736,12 @@ check_and_make_def_conflict (int alt, int def, enum reg_class def_cl)
&& recog_data.constraints[use - 1][0] == '%'
&& op_alt1[use - 1].matches == def))
break;
+ if (for_tie_p
+ && !op_alt1[def].earlyclobber
+ && op_alt1[def].matched < 0
+ && alternative_class (op_alt1, def) != NO_REGS
+ && alternative_class (op_alt1, use) != NO_REGS)
+ break;
}
if (alt1 < recog_data.n_alternatives)
@@ -701,8 +752,7 @@ check_and_make_def_conflict (int alt, int def, enum reg_class def_cl)
if ((use_match = op_alt[use].matches) >= 0)
{
- if (use_match == def)
- continue;
+ gcc_checking_assert (use_match != def);
if (op_alt[use_match].anything_ok)
use_cl = ALL_REGS;
@@ -717,7 +767,11 @@ check_and_make_def_conflict (int alt, int def, enum reg_class def_cl)
/* Make conflicts of early clobber pseudo registers of the current
insn with its inputs. Avoid introducing unnecessary conflicts by
checking classes of the constraints and pseudos because otherwise
- significant code degradation is possible for some targets. */
+ significant code degradation is possible for some targets.
+
+ For these purposes, tying an input to an output makes that output act
+ like an earlyclobber for inputs with a different value, since the output
+ register then has a predetermined purpose on input to the instruction. */
static void
make_early_clobber_and_input_conflicts (void)
{
@@ -732,15 +786,19 @@ make_early_clobber_and_input_conflicts (void)
if (TEST_BIT (preferred_alternatives, alt))
for (def = 0; def < n_operands; def++)
{
- def_cl = NO_REGS;
- if (op_alt[def].earlyclobber)
+ if (op_alt[def].anything_ok)
+ def_cl = ALL_REGS;
+ else
+ def_cl = op_alt[def].cl;
+ if (def_cl != NO_REGS)
{
- if (op_alt[def].anything_ok)
- def_cl = ALL_REGS;
- else
- def_cl = op_alt[def].cl;
- check_and_make_def_conflict (alt, def, def_cl);
+ if (op_alt[def].earlyclobber)
+ check_and_make_def_conflict (alt, def, def_cl, false);
+ else if (op_alt[def].matched >= 0
+ && !targetm.class_likely_spilled_p (def_cl))
+ check_and_make_def_conflict (alt, def, def_cl, true);
}
+
if ((def_match = op_alt[def].matches) >= 0
&& (op_alt[def_match].earlyclobber
|| op_alt[def].earlyclobber))
@@ -749,7 +807,7 @@ make_early_clobber_and_input_conflicts (void)
def_cl = ALL_REGS;
else
def_cl = op_alt[def_match].cl;
- check_and_make_def_conflict (alt, def, def_cl);
+ check_and_make_def_conflict (alt, def, def_cl, false);
}
}
}
diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h
index 55d5fe01495..c5dc83d1cc8 100644
--- a/gcc/langhooks-def.h
+++ b/gcc/langhooks-def.h
@@ -236,6 +236,7 @@ extern tree lhd_unit_size_without_reusable_padding (tree);
#define LANG_HOOKS_WARN_UNUSED_GLOBAL_DECL lhd_warn_unused_global_decl
#define LANG_HOOKS_POST_COMPILATION_PARSING_CLEANUPS NULL
#define LANG_HOOKS_DECL_OK_FOR_SIBCALL lhd_decl_ok_for_sibcall
+#define LANG_HOOKS_OMP_IS_ALLOCATABLE_OR_PTR hook_bool_const_tree_false
#define LANG_HOOKS_OMP_IS_OPTIONAL_ARGUMENT hook_bool_const_tree_false
#define LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE hook_bool_const_tree_false
#define LANG_HOOKS_OMP_PREDETERMINED_SHARING lhd_omp_predetermined_sharing
@@ -262,6 +263,7 @@ extern tree lhd_unit_size_without_reusable_padding (tree);
LANG_HOOKS_WARN_UNUSED_GLOBAL_DECL, \
LANG_HOOKS_POST_COMPILATION_PARSING_CLEANUPS, \
LANG_HOOKS_DECL_OK_FOR_SIBCALL, \
+ LANG_HOOKS_OMP_IS_ALLOCATABLE_OR_PTR, \
LANG_HOOKS_OMP_IS_OPTIONAL_ARGUMENT, \
LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE, \
LANG_HOOKS_OMP_PREDETERMINED_SHARING, \
diff --git a/gcc/langhooks.h b/gcc/langhooks.h
index 9d2714a5b1d..97e3186a41d 100644
--- a/gcc/langhooks.h
+++ b/gcc/langhooks.h
@@ -222,7 +222,14 @@ struct lang_hooks_for_decls
/* True if this decl may be called via a sibcall. */
bool (*ok_for_sibcall) (const_tree);
- /* True if OpenMP should treat DECL as a Fortran optional argument. */
+ /* True if OpenMP should regard this DECL as being a scalar which has Fortran's
+ allocatable or pointer attribute. */
+ bool (*omp_is_allocatable_or_ptr) (const_tree);
+
+ /* True if OpenMP should treat DECL as a Fortran optional argument; note: for
+ arguments with VALUE attribute, the DECL is identical to nonoptional
+ arguments; hence, we return false here. To check whether the variable is
+ present, use the DECL which is passed as hidden argument. */
bool (*omp_is_optional_argument) (const_tree);
/* True if OpenMP should privatize what this DECL points to rather
diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c
index d85b03a6c4a..285c010abdf 100644
--- a/gcc/lto-streamer-out.c
+++ b/gcc/lto-streamer-out.c
@@ -43,6 +43,7 @@ along with GCC; see the file COPYING3. If not see
#include "debug.h"
#include "omp-offload.h"
#include "print-tree.h"
+#include "tree-dfa.h"
static void lto_write_tree (struct output_block*, tree, bool);
@@ -1893,7 +1894,7 @@ output_cfg (struct output_block *ob, struct function *fn)
streamer_write_hwi (ob, -1);
- bb = ENTRY_BLOCK_PTR_FOR_FN (cfun);
+ bb = ENTRY_BLOCK_PTR_FOR_FN (fn);
while (bb->next_bb)
{
streamer_write_hwi (ob, bb->next_bb->index);
@@ -1902,9 +1903,6 @@ output_cfg (struct output_block *ob, struct function *fn)
streamer_write_hwi (ob, -1);
- /* ??? The cfgloop interface is tied to cfun. */
- gcc_assert (cfun == fn);
-
/* Output the number of loops. */
streamer_write_uhwi (ob, number_of_loops (fn));
@@ -2062,6 +2060,62 @@ collect_block_tree_leafs (tree root, vec<tree> &leafs)
collect_block_tree_leafs (BLOCK_SUBBLOCKS (root), leafs);
}
+/* This performs function body modifications that are needed for streaming
+ to work. */
+
+void
+lto_prepare_function_for_streaming (struct cgraph_node *node)
+{
+ struct function *fn = DECL_STRUCT_FUNCTION (node->decl);
+ basic_block bb;
+
+ if (number_of_loops (fn))
+ {
+ push_cfun (fn);
+ loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
+ loop_optimizer_finalize ();
+ pop_cfun ();
+ }
+ /* We will renumber the statements. The code that does this uses
+ the same ordering that we use for serializing them so we can use
+ the same code on the other end and not have to write out the
+ statement numbers. We do not assign UIDs to PHIs here because
+ virtual PHIs get re-computed on-the-fly which would make numbers
+ inconsistent. */
+ set_gimple_stmt_max_uid (fn, 0);
+ FOR_ALL_BB_FN (bb, fn)
+ {
+ for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
+ gsi_next (&gsi))
+ {
+ gphi *stmt = gsi.phi ();
+
+ /* Virtual PHIs are not going to be streamed. */
+ if (!virtual_operand_p (gimple_phi_result (stmt)))
+ gimple_set_uid (stmt, inc_gimple_stmt_max_uid (fn));
+ }
+ for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi);
+ gsi_next (&gsi))
+ {
+ gimple *stmt = gsi_stmt (gsi);
+ gimple_set_uid (stmt, inc_gimple_stmt_max_uid (fn));
+ }
+ }
+ /* To avoid keeping duplicate gimple IDs in the statements, renumber
+ virtual phis now. */
+ FOR_ALL_BB_FN (bb, fn)
+ {
+ for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
+ gsi_next (&gsi))
+ {
+ gphi *stmt = gsi.phi ();
+ if (virtual_operand_p (gimple_phi_result (stmt)))
+ gimple_set_uid (stmt, inc_gimple_stmt_max_uid (fn));
+ }
+ }
+
+}
+
/* Output the body of function NODE->DECL. */
static void
@@ -2085,9 +2139,6 @@ output_function (struct cgraph_node *node)
gcc_assert (current_function_decl == NULL_TREE && cfun == NULL);
- /* Set current_function_decl and cfun. */
- push_cfun (fn);
-
/* Make string 0 be a NULL string. */
streamer_write_char_stream (ob->string_stream, 0);
@@ -2124,9 +2175,6 @@ output_function (struct cgraph_node *node)
debug info. */
if (gimple_has_body_p (function))
{
- /* Fixup loops if required to match discovery done in the reader. */
- loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
-
streamer_write_uhwi (ob, 1);
output_struct_function_base (ob, fn);
@@ -2136,45 +2184,6 @@ output_function (struct cgraph_node *node)
/* Output any exception handling regions. */
output_eh_regions (ob, fn);
-
- /* We will renumber the statements. The code that does this uses
- the same ordering that we use for serializing them so we can use
- the same code on the other end and not have to write out the
- statement numbers. We do not assign UIDs to PHIs here because
- virtual PHIs get re-computed on-the-fly which would make numbers
- inconsistent. */
- set_gimple_stmt_max_uid (cfun, 0);
- FOR_ALL_BB_FN (bb, cfun)
- {
- for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
- gsi_next (&gsi))
- {
- gphi *stmt = gsi.phi ();
-
- /* Virtual PHIs are not going to be streamed. */
- if (!virtual_operand_p (gimple_phi_result (stmt)))
- gimple_set_uid (stmt, inc_gimple_stmt_max_uid (cfun));
- }
- for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi);
- gsi_next (&gsi))
- {
- gimple *stmt = gsi_stmt (gsi);
- gimple_set_uid (stmt, inc_gimple_stmt_max_uid (cfun));
- }
- }
- /* To avoid keeping duplicate gimple IDs in the statements, renumber
- virtual phis now. */
- FOR_ALL_BB_FN (bb, cfun)
- {
- for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
- gsi_next (&gsi))
- {
- gphi *stmt = gsi.phi ();
- if (virtual_operand_p (gimple_phi_result (stmt)))
- gimple_set_uid (stmt, inc_gimple_stmt_max_uid (cfun));
- }
- }
-
/* Output the code for the function. */
FOR_ALL_BB_FN (bb, fn)
output_bb (ob, bb, fn);
@@ -2183,9 +2192,6 @@ output_function (struct cgraph_node *node)
streamer_write_record_start (ob, LTO_null);
output_cfg (ob, fn);
-
- loop_optimizer_finalize ();
- pop_cfun ();
}
else
streamer_write_uhwi (ob, 0);
diff --git a/gcc/lto-streamer.h b/gcc/lto-streamer.h
index ddf3de0708d..9f787c4bd1e 100644
--- a/gcc/lto-streamer.h
+++ b/gcc/lto-streamer.h
@@ -909,6 +909,7 @@ void lto_output_decl_state_refs (struct output_block *,
struct lto_out_decl_state *);
void lto_output_location (struct output_block *, struct bitpack_d *, location_t);
void lto_output_init_mode_table (void);
+void lto_prepare_function_for_streaming (cgraph_node *);
/* In lto-cgraph.c */
diff --git a/gcc/lto/ChangeLog b/gcc/lto/ChangeLog
index e4102320795..bb4e57ef131 100644
--- a/gcc/lto/ChangeLog
+++ b/gcc/lto/ChangeLog
@@ -1,3 +1,24 @@
+2019-10-12 Jan Hubicka <hubicka@ucw.cz>
+
+ * lto-common.c (read_cgraph_and_symbols): Grow ggc memory use after
+ summary streaming.
+
+2019-10-12 Jan Hubicka <hubicka@ucw.cz>
+
+ * lto.c (lto_wpa_write_files): Do not update bodies of clones.
+
+2019-10-11 Jan Hubicka <hubicka@ucw.cz>
+
+ * lto.c (lto_wpa_write_files): Call ggc_trim.
+
+2019-10-11 Jan Hubicka <hubicka@ucw.cz>
+
+ * lto.c (lto_wpa_write_files): Prepare all bodies for streaming.
+
+2019-10-10 Richard Biener <rguenther@suse.de>
+
+ * lto-common.c (unify_scc): Do not merge anonymous NAMESPACE_DECLs.
+
2019-10-04 Joseph Myers <joseph@codesourcery.com>
* lto-lang.c (flag_isoc2x): New variable.
diff --git a/gcc/lto/lto-common.c b/gcc/lto/lto-common.c
index 9a17933d094..967f2285a73 100644
--- a/gcc/lto/lto-common.c
+++ b/gcc/lto/lto-common.c
@@ -1646,11 +1646,13 @@ unify_scc (class data_in *data_in, unsigned from,
tree t = streamer_tree_cache_get_tree (cache, from + i);
scc->entries[i] = t;
/* Do not merge SCCs with local entities inside them. Also do
- not merge TRANSLATION_UNIT_DECLs and anonymous namespace types. */
+ not merge TRANSLATION_UNIT_DECLs and anonymous namespaces
+ and types therein types. */
if (TREE_CODE (t) == TRANSLATION_UNIT_DECL
|| (VAR_OR_FUNCTION_DECL_P (t)
&& !(TREE_PUBLIC (t) || DECL_EXTERNAL (t)))
|| TREE_CODE (t) == LABEL_DECL
+ || (TREE_CODE (t) == NAMESPACE_DECL && !DECL_NAME (t))
|| (TYPE_P (t)
&& type_with_linkage_p (TYPE_MAIN_VARIANT (t))
&& type_in_anonymous_namespace_p (TYPE_MAIN_VARIANT (t))))
@@ -2779,7 +2781,6 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames)
/* At this stage we know that majority of GGC memory is reachable.
Growing the limits prevents unnecesary invocation of GGC. */
ggc_grow ();
- ggc_collect ();
/* Set the hooks so that all of the ipa passes can read in their data. */
lto_set_in_hooks (all_file_decl_data, get_section_data, free_section_data);
@@ -2850,7 +2851,11 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames)
if (tree_with_vars)
ggc_free (tree_with_vars);
tree_with_vars = NULL;
- ggc_collect ();
+ /* During WPA we want to prevent ggc collecting by default. Grow limits
+ until after the IPA summaries are streamed in. Basically all IPA memory
+ is explcitly managed by ggc_free and ggc collect is not useful.
+ Exception are the merged declarations. */
+ ggc_grow ();
timevar_pop (TV_IPA_LTO_DECL_MERGE);
/* Each pass will set the appropriate timer. */
@@ -2864,6 +2869,8 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames)
else
ipa_read_summaries ();
+ ggc_grow ();
+
for (i = 0; all_file_decl_data[i]; i++)
{
gcc_assert (all_file_decl_data[i]->symtab_node_encoder);
diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c
index af3590cdad8..4f404ec08f8 100644
--- a/gcc/lto/lto.c
+++ b/gcc/lto/lto.c
@@ -304,6 +304,14 @@ lto_wpa_write_files (void)
timevar_push (TV_WHOPR_WPA_IO);
+ cgraph_node *node;
+ /* Do body modifications needed for streaming before we fork out
+ worker processes. */
+ FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
+ if (!node->clone_of && gimple_has_body_p (node->decl))
+ lto_prepare_function_for_streaming (node);
+
+ ggc_trim ();
/* Generate a prefix for the LTRANS unit files. */
blen = strlen (ltrans_output_list);
temp_filename = (char *) xmalloc (blen + sizeof ("2147483648.o"));
diff --git a/gcc/machmode.h b/gcc/machmode.h
index 005ec80e89d..64ac213fbac 100644
--- a/gcc/machmode.h
+++ b/gcc/machmode.h
@@ -244,11 +244,11 @@ class opt_mode
public:
enum from_int { dummy = MAX_MACHINE_MODE };
- ALWAYS_INLINE opt_mode () : m_mode (E_VOIDmode) {}
- ALWAYS_INLINE opt_mode (const T &m) : m_mode (m) {}
+ ALWAYS_INLINE CONSTEXPR opt_mode () : m_mode (E_VOIDmode) {}
+ ALWAYS_INLINE CONSTEXPR opt_mode (const T &m) : m_mode (m) {}
template<typename U>
- ALWAYS_INLINE opt_mode (const U &m) : m_mode (T (m)) {}
- ALWAYS_INLINE opt_mode (from_int m) : m_mode (machine_mode (m)) {}
+ ALWAYS_INLINE CONSTEXPR opt_mode (const U &m) : m_mode (T (m)) {}
+ ALWAYS_INLINE CONSTEXPR opt_mode (from_int m) : m_mode (machine_mode (m)) {}
machine_mode else_void () const;
machine_mode else_blk () const { return else_mode (BLKmode); }
@@ -324,8 +324,12 @@ struct pod_mode
typedef typename T::measurement_type measurement_type;
machine_mode m_mode;
- ALWAYS_INLINE operator machine_mode () const { return m_mode; }
- ALWAYS_INLINE operator T () const { return from_int (m_mode); }
+ ALWAYS_INLINE CONSTEXPR
+ operator machine_mode () const { return m_mode; }
+
+ ALWAYS_INLINE CONSTEXPR
+ operator T () const { return from_int (m_mode); }
+
ALWAYS_INLINE pod_mode &operator = (const T &m) { m_mode = m; return *this; }
};
@@ -403,8 +407,11 @@ public:
typedef unsigned short measurement_type;
ALWAYS_INLINE scalar_int_mode () {}
- ALWAYS_INLINE scalar_int_mode (from_int m) : m_mode (machine_mode (m)) {}
- ALWAYS_INLINE operator machine_mode () const { return m_mode; }
+
+ ALWAYS_INLINE CONSTEXPR
+ scalar_int_mode (from_int m) : m_mode (machine_mode (m)) {}
+
+ ALWAYS_INLINE CONSTEXPR operator machine_mode () const { return m_mode; }
static bool includes_p (machine_mode);
@@ -428,8 +435,11 @@ public:
typedef unsigned short measurement_type;
ALWAYS_INLINE scalar_float_mode () {}
- ALWAYS_INLINE scalar_float_mode (from_int m) : m_mode (machine_mode (m)) {}
- ALWAYS_INLINE operator machine_mode () const { return m_mode; }
+
+ ALWAYS_INLINE CONSTEXPR
+ scalar_float_mode (from_int m) : m_mode (machine_mode (m)) {}
+
+ ALWAYS_INLINE CONSTEXPR operator machine_mode () const { return m_mode; }
static bool includes_p (machine_mode);
@@ -453,11 +463,20 @@ public:
typedef unsigned short measurement_type;
ALWAYS_INLINE scalar_mode () {}
- ALWAYS_INLINE scalar_mode (from_int m) : m_mode (machine_mode (m)) {}
- ALWAYS_INLINE scalar_mode (const scalar_int_mode &m) : m_mode (m) {}
- ALWAYS_INLINE scalar_mode (const scalar_float_mode &m) : m_mode (m) {}
- ALWAYS_INLINE scalar_mode (const scalar_int_mode_pod &m) : m_mode (m) {}
- ALWAYS_INLINE operator machine_mode () const { return m_mode; }
+
+ ALWAYS_INLINE CONSTEXPR
+ scalar_mode (from_int m) : m_mode (machine_mode (m)) {}
+
+ ALWAYS_INLINE CONSTEXPR
+ scalar_mode (const scalar_int_mode &m) : m_mode (m) {}
+
+ ALWAYS_INLINE CONSTEXPR
+ scalar_mode (const scalar_float_mode &m) : m_mode (m) {}
+
+ ALWAYS_INLINE CONSTEXPR
+ scalar_mode (const scalar_int_mode_pod &m) : m_mode (m) {}
+
+ ALWAYS_INLINE CONSTEXPR operator machine_mode () const { return m_mode; }
static bool includes_p (machine_mode);
@@ -494,8 +513,11 @@ public:
typedef unsigned short measurement_type;
ALWAYS_INLINE complex_mode () {}
- ALWAYS_INLINE complex_mode (from_int m) : m_mode (machine_mode (m)) {}
- ALWAYS_INLINE operator machine_mode () const { return m_mode; }
+
+ ALWAYS_INLINE CONSTEXPR
+ complex_mode (from_int m) : m_mode (machine_mode (m)) {}
+
+ ALWAYS_INLINE CONSTEXPR operator machine_mode () const { return m_mode; }
static bool includes_p (machine_mode);
@@ -764,14 +786,29 @@ public:
typedef unsigned short measurement_type;
ALWAYS_INLINE fixed_size_mode () {}
- ALWAYS_INLINE fixed_size_mode (from_int m) : m_mode (machine_mode (m)) {}
- ALWAYS_INLINE fixed_size_mode (const scalar_mode &m) : m_mode (m) {}
- ALWAYS_INLINE fixed_size_mode (const scalar_int_mode &m) : m_mode (m) {}
- ALWAYS_INLINE fixed_size_mode (const scalar_float_mode &m) : m_mode (m) {}
- ALWAYS_INLINE fixed_size_mode (const scalar_mode_pod &m) : m_mode (m) {}
- ALWAYS_INLINE fixed_size_mode (const scalar_int_mode_pod &m) : m_mode (m) {}
- ALWAYS_INLINE fixed_size_mode (const complex_mode &m) : m_mode (m) {}
- ALWAYS_INLINE operator machine_mode () const { return m_mode; }
+
+ ALWAYS_INLINE CONSTEXPR
+ fixed_size_mode (from_int m) : m_mode (machine_mode (m)) {}
+
+ ALWAYS_INLINE CONSTEXPR
+ fixed_size_mode (const scalar_mode &m) : m_mode (m) {}
+
+ ALWAYS_INLINE CONSTEXPR
+ fixed_size_mode (const scalar_int_mode &m) : m_mode (m) {}
+
+ ALWAYS_INLINE CONSTEXPR
+ fixed_size_mode (const scalar_float_mode &m) : m_mode (m) {}
+
+ ALWAYS_INLINE CONSTEXPR
+ fixed_size_mode (const scalar_mode_pod &m) : m_mode (m) {}
+
+ ALWAYS_INLINE CONSTEXPR
+ fixed_size_mode (const scalar_int_mode_pod &m) : m_mode (m) {}
+
+ ALWAYS_INLINE CONSTEXPR
+ fixed_size_mode (const complex_mode &m) : m_mode (m) {}
+
+ ALWAYS_INLINE CONSTEXPR operator machine_mode () const { return m_mode; }
static bool includes_p (machine_mode);
diff --git a/gcc/match.pd b/gcc/match.pd
index e3ac06c8ef5..2c82287f216 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -5689,6 +5689,64 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(cmp (popcount @0) integer_zerop)
(rep @0 { build_zero_cst (TREE_TYPE (@0)); }))))
+#if GIMPLE
+/* 64- and 32-bits branchless implementations of popcount are detected:
+
+ int popcount64c (uint64_t x)
+ {
+ x -= (x >> 1) & 0x5555555555555555ULL;
+ x = (x & 0x3333333333333333ULL) + ((x >> 2) & 0x3333333333333333ULL);
+ x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0fULL;
+ return (x * 0x0101010101010101ULL) >> 56;
+ }
+
+ int popcount32c (uint32_t x)
+ {
+ x -= (x >> 1) & 0x55555555;
+ x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
+ x = (x + (x >> 4)) & 0x0f0f0f0f;
+ return (x * 0x01010101) >> 24;
+ } */
+(simplify
+ (rshift
+ (mult
+ (bit_and
+ (plus:c
+ (rshift @8 INTEGER_CST@5)
+ (plus:c@8
+ (bit_and @6 INTEGER_CST@7)
+ (bit_and
+ (rshift
+ (minus@6
+ @0
+ (bit_and
+ (rshift @0 INTEGER_CST@4)
+ INTEGER_CST@11))
+ INTEGER_CST@10)
+ INTEGER_CST@9)))
+ INTEGER_CST@3)
+ INTEGER_CST@2)
+ INTEGER_CST@1)
+ /* Check constants and optab. */
+ (with
+ {
+ unsigned prec = TYPE_PRECISION (type);
+ int shift = 64 - prec;
+ const unsigned HOST_WIDE_INT c1 = 0x0101010101010101ULL >> shift,
+ c2 = 0x0F0F0F0F0F0F0F0FULL >> shift,
+ c3 = 0x3333333333333333ULL >> shift,
+ c4 = 0x5555555555555555ULL >> shift;
+ }
+ (if (prec <= 64 && TYPE_UNSIGNED (type) && tree_to_uhwi (@4) == 1
+ && tree_to_uhwi (@10) == 2 && tree_to_uhwi (@5) == 4
+ && tree_to_uhwi (@1) == prec - 8 && tree_to_uhwi (@2) == c1
+ && tree_to_uhwi (@3) == c2 && tree_to_uhwi (@9) == c3
+ && tree_to_uhwi (@7) == c3 && tree_to_uhwi (@11) == c4
+ && direct_internal_fn_supported_p (IFN_POPCOUNT, type,
+ OPTIMIZE_FOR_BOTH))
+ (convert (IFN_POPCOUNT:type @0)))))
+#endif
+
/* Simplify:
a = a1 op a2
diff --git a/gcc/objc/ChangeLog b/gcc/objc/ChangeLog
index 2b8f889f9f8..7919c3e6f54 100644
--- a/gcc/objc/ChangeLog
+++ b/gcc/objc/ChangeLog
@@ -1,3 +1,12 @@
+2019-10-10 Iain Sandoe <iain@sandoe.co.uk>
+
+ * objc-next-metadata-tags.h (OCTI_RT_META_IVAR_REF): New.
+ (meta_ivar_ref): New.
+ * objc-next-runtime-abi-02.c
+ (next_runtime_abi_02_init_metadata_attributes): Create the
+ IVAR ref metadata identifier.
+ (ivar_offset_ref): Tag IVAR refs with specific metadata.
+
2019-06-05 Martin Sebor <msebor@redhat.com>
* objc-act.c (objc_build_setter_call): Adjust quoting and hyphenation.
diff --git a/gcc/objc/objc-next-metadata-tags.h b/gcc/objc/objc-next-metadata-tags.h
index 1822aa7d615..933f08c3ab5 100644
--- a/gcc/objc/objc-next-metadata-tags.h
+++ b/gcc/objc/objc-next-metadata-tags.h
@@ -74,6 +74,8 @@ enum objc_runtime_tree_index
OCTI_RT_META_CONST_STR,
+ OCTI_RT_META_IVAR_REF,
+
OCTI_RT_META_MAX
};
@@ -167,6 +169,8 @@ enum objc_runtime_tree_index
#define meta_const_str objc_rt_trees[OCTI_RT_META_CONST_STR]
+#define meta_ivar_ref objc_rt_trees[OCTI_RT_META_IVAR_REF]
+
#define OBJCMETA(DECL,VERS,KIND) \
if (VERS) \
DECL_ATTRIBUTES (DECL) = build_tree_list ((VERS), (KIND));
diff --git a/gcc/objc/objc-next-runtime-abi-02.c b/gcc/objc/objc-next-runtime-abi-02.c
index aa1cbde5010..3e38b7dc11c 100644
--- a/gcc/objc/objc-next-runtime-abi-02.c
+++ b/gcc/objc/objc-next-runtime-abi-02.c
@@ -345,6 +345,8 @@ next_runtime_abi_02_init_metadata_attributes (void)
meta_ehtype = get_identifier ("V2_EHTY");
meta_const_str = get_identifier ("V2_CSTR");
+
+ meta_ivar_ref = get_identifier ("V2_IVRF");
}
static void next_runtime_02_initialize (void)
@@ -2795,8 +2797,8 @@ ivar_offset_ref (tree class_name, tree field_decl)
else
decl = create_hidden_decl (TREE_TYPE (size_zero_node), buf);
- /* Make sure it ends up in an ObjC section. */
- OBJCMETA (decl, objc_meta, meta_base);
+ /* Identify so that we can indirect these where the ABI requires. */
+ OBJCMETA (decl, objc_meta, meta_ivar_ref);
e.decl = decl;
e.offset = byte_position (field_decl);
diff --git a/gcc/omp-general.c b/gcc/omp-general.c
index 5ef6e251698..1a78a70bd57 100644
--- a/gcc/omp-general.c
+++ b/gcc/omp-general.c
@@ -48,6 +48,14 @@ omp_find_clause (tree clauses, enum omp_clause_code kind)
return NULL_TREE;
}
+/* True if OpenMP should regard this DECL as being a scalar which has Fortran's
+ allocatable or pointer attribute. */
+bool
+omp_is_allocatable_or_ptr (tree decl)
+{
+ return lang_hooks.decls.omp_is_allocatable_or_ptr (decl);
+}
+
/* Return true if DECL is a Fortran optional argument. */
bool
diff --git a/gcc/omp-general.h b/gcc/omp-general.h
index bbaa7b11707..7cd1d216fc0 100644
--- a/gcc/omp-general.h
+++ b/gcc/omp-general.h
@@ -73,6 +73,7 @@ struct omp_for_data
#define OACC_FN_ATTRIB "oacc function"
extern tree omp_find_clause (tree clauses, enum omp_clause_code kind);
+extern bool omp_is_allocatable_or_ptr (tree decl);
extern bool omp_is_optional_argument (tree decl);
extern bool omp_is_reference (tree decl);
extern void omp_adjust_for_condition (location_t loc, enum tree_code *cond_code,
diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index ca7dfdb83a1..279b6ef893a 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -1241,7 +1241,8 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
case OMP_CLAUSE_USE_DEVICE_ADDR:
decl = OMP_CLAUSE_DECL (c);
if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_USE_DEVICE_ADDR
- && !omp_is_reference (decl))
+ && !omp_is_reference (decl)
+ && !omp_is_allocatable_or_ptr (decl))
|| TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
install_var_field (decl, true, 11, ctx);
else
@@ -11483,7 +11484,8 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
DECL_HAS_VALUE_EXPR_P (new_var) = 1;
}
else if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_USE_DEVICE_ADDR
- && !omp_is_reference (var))
+ && !omp_is_reference (var)
+ && !omp_is_allocatable_or_ptr (var))
|| TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE)
{
tree new_var = lookup_decl (var, ctx);
@@ -11678,7 +11680,18 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
}
else
{
- var = build_fold_addr_expr (var);
+ /* While MAP is handled explicitly by the FE,
+ for 'target update', only the identified is passed. */
+ if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FROM
+ || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TO)
+ && (omp_is_allocatable_or_ptr (var)
+ && omp_is_optional_argument (var)))
+ var = build_fold_indirect_ref (var);
+ else if ((OMP_CLAUSE_CODE (c) != OMP_CLAUSE_FROM
+ && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_TO)
+ || (!omp_is_allocatable_or_ptr (var)
+ && !omp_is_optional_argument (var)))
+ var = build_fold_addr_expr (var);
gimplify_assign (x, var, &ilist);
}
}
@@ -11865,16 +11878,22 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
}
type = TREE_TYPE (ovar);
if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_USE_DEVICE_ADDR
- && !omp_is_reference (ovar))
+ && !omp_is_reference (ovar)
+ && !omp_is_allocatable_or_ptr (ovar))
|| TREE_CODE (type) == ARRAY_TYPE)
var = build_fold_addr_expr (var);
else
{
- if (omp_is_reference (ovar) || omp_is_optional_argument (ovar))
+ if (omp_is_reference (ovar)
+ || omp_is_optional_argument (ovar)
+ || omp_is_allocatable_or_ptr (ovar))
{
type = TREE_TYPE (type);
if (TREE_CODE (type) != ARRAY_TYPE
- && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_USE_DEVICE_ADDR)
+ && ((OMP_CLAUSE_CODE (c) != OMP_CLAUSE_USE_DEVICE_ADDR
+ && !omp_is_allocatable_or_ptr (ovar))
+ || (omp_is_reference (ovar)
+ && omp_is_allocatable_or_ptr (ovar))))
var = build_simple_mem_ref (var);
var = fold_convert (TREE_TYPE (x), var);
}
@@ -12045,7 +12064,8 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
gimple_build_assign (new_var, x));
}
else if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_USE_DEVICE_ADDR
- && !omp_is_reference (var))
+ && !omp_is_reference (var)
+ && !omp_is_allocatable_or_ptr (var))
|| TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE)
{
tree new_var = lookup_decl (var, ctx);
@@ -12065,7 +12085,9 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
{
type = TREE_TYPE (type);
if (TREE_CODE (type) != ARRAY_TYPE
- && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_USE_DEVICE_ADDR)
+ && (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_USE_DEVICE_ADDR
+ || (omp_is_reference (var)
+ && omp_is_allocatable_or_ptr (var))))
{
tree v = create_tmp_var_raw (type, get_name (var));
gimple_add_tmp_var (v);
diff --git a/gcc/optabs-tree.c b/gcc/optabs-tree.c
index 8157798cc71..a5ecbf075b5 100644
--- a/gcc/optabs-tree.c
+++ b/gcc/optabs-tree.c
@@ -23,7 +23,10 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "target.h"
#include "insn-codes.h"
+#include "rtl.h"
#include "tree.h"
+#include "memmodel.h"
+#include "optabs.h"
#include "optabs-tree.h"
#include "stor-layout.h"
@@ -329,6 +332,31 @@ expand_vec_cmp_expr_p (tree value_type, tree mask_type, enum tree_code code)
return false;
}
+/* Return true iff vcond_optab/vcondu_optab can handle a vector
+ comparison for code CODE, comparing operands of type CMP_OP_TYPE and
+ producing a result of type VALUE_TYPE. */
+
+static bool
+vcond_icode_p (tree value_type, tree cmp_op_type, enum tree_code code)
+{
+ return can_vcond_compare_p (get_rtx_code (code, TYPE_UNSIGNED (cmp_op_type)),
+ TYPE_MODE (value_type), TYPE_MODE (cmp_op_type));
+}
+
+/* Return true iff vcondeq_optab can handle a vector comparison for code CODE,
+ comparing operands of type CMP_OP_TYPE and producing a result of type
+ VALUE_TYPE. */
+
+static bool
+vcond_eq_icode_p (tree value_type, tree cmp_op_type, enum tree_code code)
+{
+ if (code != EQ_EXPR && code != NE_EXPR)
+ return false;
+
+ return get_vcond_eq_icode (TYPE_MODE (value_type), TYPE_MODE (cmp_op_type))
+ != CODE_FOR_nothing;
+}
+
/* Return TRUE iff, appropriate vector insns are available
for vector cond expr with vector type VALUE_TYPE and a comparison
with operand vector types in CMP_OP_TYPE. */
@@ -347,14 +375,13 @@ expand_vec_cond_expr_p (tree value_type, tree cmp_op_type, enum tree_code code)
|| maybe_ne (GET_MODE_NUNITS (value_mode), GET_MODE_NUNITS (cmp_op_mode)))
return false;
- if (get_vcond_icode (TYPE_MODE (value_type), TYPE_MODE (cmp_op_type),
- TYPE_UNSIGNED (cmp_op_type)) == CODE_FOR_nothing
- && ((code != EQ_EXPR && code != NE_EXPR)
- || get_vcond_eq_icode (TYPE_MODE (value_type),
- TYPE_MODE (cmp_op_type)) == CODE_FOR_nothing))
+ if (TREE_CODE_CLASS (code) != tcc_comparison)
+ /* This may happen, for example, if code == SSA_NAME, in which case we
+ cannot be certain whether a vector insn is available. */
return false;
- return true;
+ return vcond_icode_p (value_type, cmp_op_type, code)
+ || vcond_eq_icode_p (value_type, cmp_op_type, code);
}
/* Use the current target and options to initialize
diff --git a/gcc/optabs.c b/gcc/optabs.c
index 35921e691f9..d6701df158c 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -3819,6 +3819,25 @@ can_compare_p (enum rtx_code code, machine_mode mode,
return 0;
}
+/* Return whether the backend can emit a vector comparison for code CODE,
+ comparing operands of mode CMP_OP_MODE and producing a result with
+ VALUE_MODE. */
+
+bool
+can_vcond_compare_p (enum rtx_code code, machine_mode value_mode,
+ machine_mode cmp_op_mode)
+{
+ enum insn_code icode;
+ bool unsigned_p = (code == LTU || code == LEU || code == GTU || code == GEU);
+ rtx reg1 = alloca_raw_REG (cmp_op_mode, LAST_VIRTUAL_REGISTER + 1);
+ rtx reg2 = alloca_raw_REG (cmp_op_mode, LAST_VIRTUAL_REGISTER + 2);
+ rtx test = alloca_rtx_fmt_ee (code, value_mode, reg1, reg2);
+
+ return (icode = get_vcond_icode (value_mode, cmp_op_mode, unsigned_p))
+ != CODE_FOR_nothing
+ && insn_operand_matches (icode, 3, test);
+}
+
/* This function is called when we are going to emit a compare instruction that
compares the values found in X and Y, using the rtl operator COMPARISON.
diff --git a/gcc/optabs.h b/gcc/optabs.h
index 897bb5d4443..b1348ce85c9 100644
--- a/gcc/optabs.h
+++ b/gcc/optabs.h
@@ -242,6 +242,12 @@ enum can_compare_purpose
(without splitting it into pieces). */
extern int can_compare_p (enum rtx_code, machine_mode,
enum can_compare_purpose);
+
+/* Return whether the backend can emit a vector comparison for code CODE,
+ comparing operands of mode CMP_OP_MODE and producing a result with
+ VALUE_MODE. */
+extern bool can_vcond_compare_p (enum rtx_code, machine_mode, machine_mode);
+
extern rtx prepare_operand (enum insn_code, rtx, int, machine_mode,
machine_mode, int);
/* Emit a pair of rtl insns to compare two rtx's and to jump
diff --git a/gcc/opts-diagnostic.h b/gcc/opts-diagnostic.h
index 08110afe3e0..3f58ae91bf6 100644
--- a/gcc/opts-diagnostic.h
+++ b/gcc/opts-diagnostic.h
@@ -22,4 +22,7 @@ along with GCC; see the file COPYING3. If not see
extern char *option_name (diagnostic_context *context, int option_index,
diagnostic_t orig_diag_kind, diagnostic_t diag_kind);
+
+extern char *get_option_url (diagnostic_context *context, int option_index);
+
#endif
diff --git a/gcc/opts-global.c b/gcc/opts-global.c
index 7c5bd16c7ea..b51c2fbc21c 100644
--- a/gcc/opts-global.c
+++ b/gcc/opts-global.c
@@ -255,6 +255,7 @@ init_options_once (void)
construct their pretty-printers means that all previous settings
are overriden. */
diagnostic_color_init (global_dc);
+ diagnostic_urls_init (global_dc);
}
/* Decode command-line options to an array, like
diff --git a/gcc/opts.c b/gcc/opts.c
index 2df03519192..32869ca4919 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -1123,24 +1123,6 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
&& !opts_set->x_flag_reorder_functions)
opts->x_flag_reorder_functions = 1;
- /* Tune vectorization related parametees according to cost model. */
- if (opts->x_flag_vect_cost_model == VECT_COST_MODEL_CHEAP)
- {
- maybe_set_param_value (PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS,
- 6, opts->x_param_values, opts_set->x_param_values);
- maybe_set_param_value (PARAM_VECT_MAX_VERSION_FOR_ALIGNMENT_CHECKS,
- 0, opts->x_param_values, opts_set->x_param_values);
- maybe_set_param_value (PARAM_VECT_MAX_PEELING_FOR_ALIGNMENT,
- 0, opts->x_param_values, opts_set->x_param_values);
- }
-
- /* Set PARAM_MAX_STORES_TO_SINK to 0 if either vectorization or if-conversion
- is disabled. */
- if ((!opts->x_flag_tree_loop_vectorize && !opts->x_flag_tree_slp_vectorize)
- || !opts->x_flag_tree_loop_if_convert)
- maybe_set_param_value (PARAM_MAX_STORES_TO_SINK, 0,
- opts->x_param_values, opts_set->x_param_values);
-
/* The -gsplit-dwarf option requires -ggnu-pubnames. */
if (opts->x_dwarf_split_debug_info)
opts->x_debug_generate_pub_sections = 2;
@@ -2492,6 +2474,10 @@ common_handle_option (struct gcc_options *opts,
diagnostic_color_init (dc, value);
break;
+ case OPT_fdiagnostics_urls_:
+ diagnostic_urls_init (dc, value);
+ break;
+
case OPT_fdiagnostics_format_:
diagnostic_output_format_init (dc,
(enum diagnostics_output_format)value);
@@ -3232,3 +3218,24 @@ option_name (diagnostic_context *context, int option_index,
else
return NULL;
}
+
+/* Return malloced memory for a URL describing the option OPTION_INDEX
+ which enabled a diagnostic (context CONTEXT). */
+
+char *
+get_option_url (diagnostic_context *, int option_index)
+{
+ if (option_index)
+ /* DOCUMENTATION_ROOT_URL should be supplied via -D by the Makefile
+ (see --with-documentation-root-url).
+
+ Expect an anchor of the form "index-Wfoo" e.g.
+ <a name="index-Wformat"></a>, and thus an id within
+ the URL of "#index-Wformat". */
+ return concat (DOCUMENTATION_ROOT_URL,
+ "Warning-Options.html",
+ "#index", cl_options[option_index].opt_text,
+ NULL);
+ else
+ return NULL;
+}
diff --git a/gcc/passes.c b/gcc/passes.c
index f715c67ab65..863605da292 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -2705,20 +2705,12 @@ ipa_write_summaries (void)
{
struct cgraph_node *node = order[i];
- if (gimple_has_body_p (node->decl))
+ if (node->definition && node->need_lto_streaming)
{
- /* When streaming out references to statements as part of some IPA
- pass summary, the statements need to have uids assigned and the
- following does that for all the IPA passes here. Naturally, this
- ordering then matches the one IPA-passes get in their stmt_fixup
- hooks. */
-
- push_cfun (DECL_STRUCT_FUNCTION (node->decl));
- renumber_gimple_stmt_uids ();
- pop_cfun ();
+ if (gimple_has_body_p (node->decl))
+ lto_prepare_function_for_streaming (node);
+ lto_set_symtab_encoder_in_partition (encoder, node);
}
- if (node->definition && node->need_lto_streaming)
- lto_set_symtab_encoder_in_partition (encoder, node);
}
FOR_EACH_DEFINED_FUNCTION (node)
@@ -2786,28 +2778,13 @@ void
ipa_write_optimization_summaries (lto_symtab_encoder_t encoder)
{
struct lto_out_decl_state *state = lto_new_out_decl_state ();
- lto_symtab_encoder_iterator lsei;
state->symtab_node_encoder = encoder;
lto_output_init_mode_table ();
lto_push_out_decl_state (state);
- for (lsei = lsei_start_function_in_partition (encoder);
- !lsei_end_p (lsei); lsei_next_function_in_partition (&lsei))
- {
- struct cgraph_node *node = lsei_cgraph_node (lsei);
- /* When streaming out references to statements as part of some IPA
- pass summary, the statements need to have uids assigned.
-
- For functions newly born at WPA stage we need to initialize
- the uids here. */
- if (node->definition
- && gimple_has_body_p (node->decl))
- {
- push_cfun (DECL_STRUCT_FUNCTION (node->decl));
- renumber_gimple_stmt_uids ();
- pop_cfun ();
- }
- }
+
+ /* Be sure that we did not forget to renumber stmt uids. */
+ gcc_checking_assert (flag_wpa);
gcc_assert (flag_wpa);
pass_manager *passes = g->get_passes ();
diff --git a/gcc/po/ChangeLog b/gcc/po/ChangeLog
index b597c8dec81..6f8902e1dfb 100644
--- a/gcc/po/ChangeLog
+++ b/gcc/po/ChangeLog
@@ -1,3 +1,7 @@
+2019-10-11 Joseph Myers <joseph@codesourcery.com>
+
+ * fi.po: Update.
+
2019-09-30 Joseph Myers <joseph@codesourcery.com>
* es.po: Update.
diff --git a/gcc/po/fi.po b/gcc/po/fi.po
index c66de8afab4..b4b27c40017 100644
--- a/gcc/po/fi.po
+++ b/gcc/po/fi.po
@@ -33,7 +33,7 @@ msgstr ""
"Project-Id-Version: gcc 9.1.0\n"
"Report-Msgid-Bugs-To: https://gcc.gnu.org/bugs/\n"
"POT-Creation-Date: 2019-05-02 20:28+0000\n"
-"PO-Revision-Date: 2019-05-29 18:58+0300\n"
+"PO-Revision-Date: 2019-10-11 20:03+0300\n"
"Last-Translator: Lauri Nurmi <lanurmi@iki.fi>\n"
"Language-Team: Finnish <translation-team-fi@lists.sourceforge.net>\n"
"Language: fi\n"
@@ -67,9 +67,9 @@ msgid "[cannot find %s]"
msgstr "lähdetiedostoa %s ei löydy"
#: collect2.c:1632
-#, fuzzy, c-format
+#, c-format
msgid "collect2 version %s\n"
-msgstr "gcc-versio %s %s\n"
+msgstr "collect2-versio %s\n"
#: collect2.c:1737
#, c-format
@@ -118,9 +118,9 @@ msgid "const/copy propagation disabled"
msgstr "const-/kopioinnin-eteneminen poistettu käytöstä"
#: diagnostic.c:145
-#, fuzzy, c-format
+#, c-format
msgid "%s: all warnings being treated as errors"
-msgstr "Käsittele kaikki varoitukset virheinä"
+msgstr "%s: kaikki varoitukset käsitellään virheinä"
#: diagnostic.c:150
#, c-format
@@ -6142,9 +6142,8 @@ msgid "gfortran does not support -E without -cpp"
msgstr "gfortran ei tue valitsinta -E ilman valitsinta -cpp"
#: objc/lang-specs.h:30 objc/lang-specs.h:41
-#, fuzzy
msgid "GNU Objective C no longer supports traditional compilation"
-msgstr "GCC ei enää tue valitsinta -traditional ilman valitsinta -E"
+msgstr "GNU Objective C ei enää tue perinteistä kääntämistä"
#: objc/lang-specs.h:55
msgid "objc-cpp-output is deprecated; please use objective-c-cpp-output instead"
@@ -6688,9 +6687,8 @@ msgid "Conform to the ISO Fortran 95 standard."
msgstr "Noudata ISO Fortran 95 -standardia"
#: fortran/lang.opt:827
-#, fuzzy
msgid "Conform to nothing in particular."
-msgstr "Älä noudata mitään erityisesti"
+msgstr "Älä noudata mitään erityisesti."
#: fortran/lang.opt:831
msgid "Accept extensions to support legacy code."
@@ -6732,24 +6730,20 @@ msgid "-I <dir>\tAdd <dir> to the end of the main include path."
msgstr "-isystem <hakemisto>\tLisää <hakemisto> järjestelmän include-polun alkuun"
#: c-family/c.opt:217
-#, fuzzy
msgid "Generate make dependencies."
-msgstr "Luo make-riippuvuudet"
+msgstr "Luo make-riippuvuudet."
#: c-family/c.opt:221
-#, fuzzy
msgid "Generate make dependencies and compile."
-msgstr "Luo make-riippuvuudet ja käännä"
+msgstr "Luo make-riippuvuudet ja käännä."
#: c-family/c.opt:225
-#, fuzzy
msgid "-MF <file>\tWrite dependency output to the given file."
-msgstr "Kirjoita riippuvuustuloste annettuun tiedostoon"
+msgstr "-MF <tiedosto>\tKirjoita riippuvuustuloste annettuun tiedostoon."
#: c-family/c.opt:229
-#, fuzzy
msgid "Treat missing header files as generated files."
-msgstr "Käsittele puuttuvia otsikkotiedostoja luotavina tiedostoina"
+msgstr "Käsittele puuttuvia otsikkotiedostoja luotavina tiedostoina."
#: c-family/c.opt:233
msgid "Like -M but ignore system header files."
@@ -6773,9 +6767,8 @@ msgid "-MT <target>\tAdd an unquoted target."
msgstr ""
#: c-family/c.opt:253
-#, fuzzy
msgid "Do not generate #line directives."
-msgstr "Älä luo #line-direktiivejä"
+msgstr "Älä luo #line-direktiivejä."
#: c-family/c.opt:257
#, fuzzy
@@ -6817,11 +6810,9 @@ msgstr ""
msgid "Enable most warning messages."
msgstr "Subject: Fetchmailin varoitus liian suuresta viestistä"
-# vähän fuzzy
#: c-family/c.opt:308
-#, fuzzy
msgid "Warn on any use of alloca."
-msgstr "Varoita pragmain väärästä käytöstä."
+msgstr "Varoita kaikesta allocan käytöstä."
#: c-family/c.opt:312
#, fuzzy
@@ -6931,9 +6922,8 @@ msgstr "Varoita ”char”-tyypillä indeksoinnista."
#: c-family/c.opt:1369 c-family/c.opt:1373 c-family/c.opt:1377
#: c-family/c.opt:1381 c-family/c.opt:1385 c-family/c.opt:1389
#: config/i386/i386.opt:967
-#, fuzzy
msgid "Deprecated in GCC 9. This switch has no effect."
-msgstr "Vanhentunut. Tämä valitsin ei vaikuta mihinkään."
+msgstr "Vanhentunut GCC 9:ssä. Tämä valitsin ei vaikuta mihinkään."
#: c-family/c.opt:429
msgid "Warn about variables that might be changed by \"longjmp\" or \"vfork\"."
@@ -6964,9 +6954,8 @@ msgid "Warn when all constructors and destructors are private."
msgstr "Varoita kun kaikki muodostimet ja hajottimet ovat yksityisiä."
#: c-family/c.opt:461
-#, fuzzy
msgid "Warn about dangling else."
-msgstr "Varoita implisiittisistä funktioesittelyistä."
+msgstr "Varoita orvosta elsestä."
#: c-family/c.opt:465
msgid "Warn about __TIME__, __DATE__ and __TIMESTAMP__ usage."
@@ -7119,9 +7108,8 @@ msgid "Warn whenever type qualifiers are ignored."
msgstr "Varoita tyyppimääreiden huomiotta jättämisestä."
#: c-family/c.opt:622
-#, fuzzy
msgid "Warn whenever attributes are ignored."
-msgstr "Varoita tyyppimääreiden huomiotta jättämisestä."
+msgstr "Varoita attribuuttien huomiotta jättämisestä."
#: c-family/c.opt:626
#, fuzzy
@@ -7196,9 +7184,8 @@ msgid "Warn when a string or character literal is followed by a ud-suffix which
msgstr ""
#: c-family/c.opt:701
-#, fuzzy
msgid "Warn when a logical operator is suspiciously always evaluating to true or false."
-msgstr "Varoita vertailusta, joka on aina tosi tai aina epätosi."
+msgstr "Varoita, kun looginen operaattori on aina tosi tai aina epätosi."
#: c-family/c.opt:705
msgid "Warn when logical not is used on the left hand side operand of a comparison."
@@ -7429,9 +7416,8 @@ msgid "Warn about packed bit-fields whose offset changed in GCC 4.4."
msgstr "Varoita pakatuista bittikentistä, joiden siirrososoite vaihtui GCC 4.4:ssä"
#: c-family/c.opt:955
-#, fuzzy
msgid "Warn about possibly missing parentheses."
-msgstr "Varoita mahdollisesti puuttuvista sulkeista"
+msgstr "Varoita mahdollisesti puuttuvista sulkeista."
#: c-family/c.opt:963
msgid "Warn about calling std::move on a local object in a return statement preventing copy elision."
@@ -7975,9 +7961,8 @@ msgid "Enable OpenMP's SIMD directives."
msgstr "Luokittelematon lause IF-lauseessa kohdassa %C"
#: c-family/c.opt:1681
-#, fuzzy
msgid "Recognize C++ keywords like \"compl\" and \"xor\"."
-msgstr "Tunnista C++:n avainsanat kuten ”compl” ja ”xor”"
+msgstr "Tunnista C++:n avainsanat kuten ”compl” ja ”xor”."
#: c-family/c.opt:1692
msgid "Look for and use PCH files even when preprocessing."
@@ -8732,9 +8717,8 @@ msgid "Set the maximum amount for a single stack increment operation."
msgstr ""
#: config/mcore/mcore.opt:75
-#, fuzzy
msgid "Always treat bitfields as int-sized."
-msgstr "Käsittele bittikenttiä aina int-kokoisina"
+msgstr "Käsittele bittikenttiä aina int-kokoisina."
#: config/linux-android.opt:23
msgid "Generate code for the Android platform."
@@ -19730,7 +19714,7 @@ msgstr "%qs-attribuuttia ei huomioida %qs:lle"
#: cgraphunit.c:976 c/c-decl.c:11507
#, fuzzy, gcc-internal-format
msgid "%q+F used but never defined"
-msgstr "nimike %q+D määritelty mutta käytettämättä"
+msgstr "nimike %q+D määritelty mutta käyttämättä"
#: cgraphunit.c:978 c/c-decl.c:11517
#, fuzzy, gcc-internal-format
@@ -29294,7 +29278,7 @@ msgstr "%<X<=Y<=Z%> -tyylisillä vertailuilla on eri merkitys kuin matematiikass
#: c-family/c-warn.c:2021
#, gcc-internal-format
msgid "label %q+D defined but not used"
-msgstr "nimike %q+D määritelty mutta käytettämättä"
+msgstr "nimike %q+D määritelty mutta käyttämättä"
#: c-family/c-warn.c:2023
#, gcc-internal-format
@@ -68642,7 +68626,7 @@ msgstr "(%qs:n alustuksen lähistöllä)"
#, fuzzy
#~ msgid "variable %q+D set but not used"
-#~ msgstr "nimike %q+D määritelty mutta käytettämättä"
+#~ msgstr "nimike %q+D määritelty mutta käyttämättä"
#~ msgid "jump to label %q+D"
#~ msgstr "hyppy nimiöön %q+D"
@@ -68659,7 +68643,7 @@ msgstr "(%qs:n alustuksen lähistöllä)"
#, fuzzy
#~ msgid "parameter %q+D set but not used"
-#~ msgstr "nimike %q+D määritelty mutta käytettämättä"
+#~ msgstr "nimike %q+D määritelty mutta käyttämättä"
#~ msgid "%q+D declared here"
#~ msgstr "%q+D esitelty täällä"
diff --git a/gcc/pretty-print.c b/gcc/pretty-print.c
index 2b6c58532b3..c57a3dbd887 100644
--- a/gcc/pretty-print.c
+++ b/gcc/pretty-print.c
@@ -1579,7 +1579,8 @@ pretty_printer::pretty_printer (int maximum_length)
emitted_prefix (),
need_newline (),
translate_identifiers (true),
- show_color ()
+ show_color (),
+ show_urls (false)
{
pp_line_cutoff (this) = maximum_length;
/* By default, we emit prefixes once per message. */
@@ -2028,6 +2029,41 @@ identifier_to_locale (const char *ident)
}
}
+/* Support for encoding URLs.
+ See egmontkob/Hyperlinks_in_Terminal_Emulators.md
+ ( https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda ).
+
+ > A hyperlink is opened upon encountering an OSC 8 escape sequence with
+ > the target URI. The syntax is
+ >
+ > OSC 8 ; params ; URI ST
+ >
+ > A hyperlink is closed with the same escape sequence, omitting the
+ > parameters and the URI but keeping the separators:
+ >
+ > OSC 8 ; ; ST
+ >
+ > OSC (operating system command) is typically ESC ]. */
+
+/* If URL-printing is enabled, write an "open URL" escape sequence to PP
+ for the given URL. */
+
+void
+pp_begin_url (pretty_printer *pp, const char *url)
+{
+ if (pp->show_urls)
+ pp_printf (pp, "\33]8;;%s\33\\", url);
+}
+
+/* If URL-printing is enabled, write a "close URL" escape sequence to PP. */
+
+void
+pp_end_url (pretty_printer *pp)
+{
+ if (pp->show_urls)
+ pp_string (pp, "\33]8;;\33\\");
+}
+
#if CHECKING_P
namespace selftest {
@@ -2312,6 +2348,32 @@ test_prefixes_and_wrapping ()
}
+/* Verify that URL-printing works as expected. */
+
+void
+test_urls ()
+{
+ {
+ pretty_printer pp;
+ pp.show_urls = false;
+ pp_begin_url (&pp, "http://example.com");
+ pp_string (&pp, "This is a link");
+ pp_end_url (&pp);
+ ASSERT_STREQ ("This is a link",
+ pp_formatted_text (&pp));
+ }
+
+ {
+ pretty_printer pp;
+ pp.show_urls = true;
+ pp_begin_url (&pp, "http://example.com");
+ pp_string (&pp, "This is a link");
+ pp_end_url (&pp);
+ ASSERT_STREQ ("\33]8;;http://example.com\33\\This is a link\33]8;;\33\\",
+ pp_formatted_text (&pp));
+ }
+}
+
/* Run all of the selftests within this file. */
void
@@ -2320,6 +2382,7 @@ pretty_print_c_tests ()
test_basic_printing ();
test_pp_format ();
test_prefixes_and_wrapping ();
+ test_urls ();
}
} // namespace selftest
diff --git a/gcc/pretty-print.h b/gcc/pretty-print.h
index 2d03b3f9e8d..c73fc308d50 100644
--- a/gcc/pretty-print.h
+++ b/gcc/pretty-print.h
@@ -273,6 +273,9 @@ public:
/* Nonzero means that text should be colorized. */
bool show_color;
+
+ /* Nonzero means that URLs should be emitted. */
+ bool show_urls;
};
static inline const char *
@@ -393,6 +396,9 @@ extern void pp_maybe_space (pretty_printer *);
extern void pp_begin_quote (pretty_printer *, bool);
extern void pp_end_quote (pretty_printer *, bool);
+extern void pp_begin_url (pretty_printer *pp, const char *url);
+extern void pp_end_url (pretty_printer *pp);
+
/* Switch into verbatim mode and return the old mode. */
static inline pp_wrapping_mode_t
pp_set_verbatim_wrapping_ (pretty_printer *pp)
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index e8e006061ec..7385c334505 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,480 @@
+2019-10-14 Richard Sandiford <richard.sandiford@arm.com>
+
+ * gcc.dg/diag-aka-5.h: New test.
+ * gcc.dg/diag-aka-5a.c: Likewise.
+ * gcc.dg/diag-aka-5b.c: Likewise.
+ * gcc.target/aarch64/diag_aka_1.c (f): Expect an aka to be printed
+ for myvec.
+
+2019-10-14 Jakub Jelinek <jakub@redhat.com>
+
+ * c-c++-common/gomp/declare-variant-7.c: Add tests for clauses not
+ separated by commas in simd selector trait properties.
+
+2019-10-14 Aldy Hernandez <aldyh@redhat.com>
+
+ * gcc.dg/tree-ssa/evrp4.c: Adjust for unsigned non-zero being
+ [1,MAX].
+
+2019-10-13 Iain Sandoe <iain@sandoe.co.uk>
+
+ * gcc.target/i386/indirect-thunk-1.c: Allow 'l' or 'L' in
+ indirection label prefix, for Darwin.
+ * gcc.target/i386/indirect-thunk-2.c: Likewise.
+ * gcc.target/i386/indirect-thunk-3.c: Likewise.
+ * gcc.target/i386/indirect-thunk-4.c: Likewise.
+ * gcc.target/i386/indirect-thunk-attr-1.c: Likewise.
+ * gcc.target/i386/indirect-thunk-attr-2.c: Likewise.
+ * gcc.target/i386/indirect-thunk-attr-3.c: Likewise.
+ * gcc.target/i386/indirect-thunk-attr-4.c: Likewise.
+ * gcc.target/i386/indirect-thunk-attr-5.c: Likewise.
+ * gcc.target/i386/indirect-thunk-attr-6.c: Likewise.
+ * gcc.target/i386/indirect-thunk-extern-1.c: Likewise.
+ * gcc.target/i386/indirect-thunk-extern-2.c: Likewise.
+ * gcc.target/i386/indirect-thunk-extern-3.c: Likewise.
+ * gcc.target/i386/indirect-thunk-extern-4.c: Likewise.
+ * gcc.target/i386/indirect-thunk-inline-1.c: Likewise.
+ * gcc.target/i386/indirect-thunk-inline-2.c: Likewise.
+ * gcc.target/i386/indirect-thunk-inline-3.c: Likewise.
+ * gcc.target/i386/indirect-thunk-inline-4.c: Likewise.
+ * gcc.target/i386/pr32219-2.c: Likewise.
+ * gcc.target/i386/pr32219-3.c: Likewise.
+ * gcc.target/i386/pr32219-4.c: Likewise.
+ * gcc.target/i386/pr32219-7.c: Likewise.
+ * gcc.target/i386/pr32219-8.c: Likewise.
+ * gcc.target/i386/ret-thunk-14.c: Likewise.
+ * gcc.target/i386/ret-thunk-15.c: Likewise.
+ * gcc.target/i386/ret-thunk-9.c: Likewise.
+
+2019-10-13 Damian Rouson <damain@sourceryinstitue.org>
+
+ PR fortran/91513
+ * gfortran.dg/impure_assignment_2.f90: Update dg-error regex.
+
+2019-10-13 Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ PR fortran/92017
+ * gfortran.dg/minmaxloc_14.f90: New test.
+
+2019-10-13 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ * lib/target-supports.exp (add_options_for_c99_runtime): Remove.
+ (check_effective_target_c99_runtime): Remove call to
+ add_options_for_c99_runtime.
+
+ * gcc.dg/builtins-18.c: Remove dg-add-options c99_runtime.
+ * gcc.dg/builtins-20.c: Likewise.
+ * gcc.dg/builtins-53.c: Likewise.
+ * gcc.dg/builtins-55.c: Likewise.
+ * gcc.dg/builtins-67.c: Likewise.
+ * gcc.dg/c99-tgmath-1.c: Likewise.
+ * gcc.dg/c99-tgmath-2.c: Likewise.
+ * gcc.dg/c99-tgmath-3.c: Likewise.
+ * gcc.dg/c99-tgmath-4.c: Likewise.
+ * gcc.dg/ipa/inline-8.c: Likewise.
+ * gcc.dg/ipa/ipa-icf-5.c: Likewise.
+ * gcc.dg/ipa/ipa-icf-7.c: Likewise.
+ * gcc.dg/nextafter-2.c: Likewise.
+ * gcc.dg/pr42427.c: Likewise.
+ * gcc.dg/pr78965.c: Likewise.
+ * gcc.dg/single-precision-constant.c: Likewise.
+ * gcc.dg/torture/builtin-convert-1.c: Likewise.
+ * gcc.dg/torture/builtin-convert-2.c: Likewise.
+ * gcc.dg/torture/builtin-convert-3.c: Likewise.
+ * gcc.dg/torture/builtin-convert-4.c: Likewise.
+ * gcc.dg/torture/builtin-fp-int-inexact.c: Likewise.
+ * gcc.dg/torture/builtin-fp-int-inexact-c2x.c: Likewise.
+ * gcc.dg/torture/builtin-integral-1.c: Likewise.
+ * gcc.dg/torture/builtin-power-1.c: Likewise.
+ * gcc.dg/tree-ssa/copy-sign-1.c: Likewise.
+ * gcc.dg/tree-ssa/minmax-2.c: Likewise.
+ * gcc.dg/tree-ssa/mult-abs-2.c: Likewise.
+ * gcc.target/i386/387-builtin-fp-int-inexact.c: Likewise.
+ * gcc.target/i386/387-rint-inline-1.c: Likewise.
+ * gcc.target/i386/387-rint-inline-2.c: Likewise.
+ * gcc.target/i386/conversion.c: Likewise.
+ * gcc.target/i386/pr47312.c: Likewise.
+ * gcc.target/i386/sse2-builtin-fp-int-inexact.c: Likewise.
+ * gcc.target/i386/sse2-rint-inline-1.c: Likewise.
+ * gcc.target/i386/sse2-rint-inline-2.c: Likewise.
+ * gcc.target/i386/sse4_1-builtin-fp-int-inexact.c: Likewise.
+ * gcc.target/i386/sse4_1-rint-inline.c: Likewise.
+
+2019-10-12 Jakub Jelinek <jakub@redhat.com>
+
+ PR middle-end/92063
+ * gcc.c-torture/compile/pr92063.c: New test.
+
+ * c-c++-common/gomp/declare-variant-2.c: Adjust for error recovery
+ improvements. Add new tests.
+ * c-c++-common/gomp/declare-variant-4.c: New test.
+ * c-c++-common/gomp/declare-variant-5.c: New test.
+ * c-c++-common/gomp/declare-variant-6.c: New test.
+ * c-c++-common/gomp/declare-variant-7.c: New test.
+
+2019-10-11 Joseph Myers <joseph@codesourcery.com>
+
+ * gcc.dg/dfp/c11-constants-1.c, gcc.dg/dfp/c11-constants-2.c,
+ gcc.dg/dfp/c2x-constants-1.c, gcc.dg/dfp/c2x-constants-2.c: New
+ tests.
+ * gcc.dg/dfp/constants-pedantic.c: Use -std=gnu17 explicitly.
+ Update expected diagnostics.
+
+2019-10-11 Marek Polacek <polacek@redhat.com>
+
+ PR c++/92070 - bogus error with -fchecking=2.
+ * g++.dg/expr/cond17.C: New test.
+
+2019-10-11 Marek Polacek <polacek@redhat.com>
+
+ PR c++/92049 - extra error with -fchecking=2.
+ * g++.dg/template/builtin2.C: New test.
+
+2019-10-11 Jim Wilson <jimw@sifive.com>
+
+ PR rtl-optimization/91860
+ * gcc.dg/pr91860-1.c: New testcase.
+ * gcc.dg/pr91860-2.c: New testcase.
+ * gcc.dg/pr91860-3.c: New testcase.
+ * gcc.dg/pr91860-4.c: New testcase.
+
+2019-10-11 Steven G. Kargl <kargl@gcc.gnu.org>
+
+ PR fortran/91649
+ * gfortran.dg/pr91649.f90: New test.
+
+2019-10-11 Steven G. Kargl <kargl@gcc.gnu.org>
+
+ PR fortran/91715
+ * gfortran.dg/function_kinds_5.f90: Prune run-on error.
+ * gfortran.dg/pr85543.f90: Ditto.
+ * gfortran.dg/pr91715.f90: New test.
+
+2019-10-11 Steven G. Kargl <kargl@gcc.gnu.org>
+
+ PR fortran/92018
+ * gfortran.dg/gnu_logical_2.f90: Update dg-error regex.
+ * gfortran.dg/pr81509_2.f90: Ditto.
+ * gfortran.dg/pr92018.f90: New test.
+
+2019-10-11 Steven G. Kargl <kargl@gcc.gnu.org>
+
+ PR fortran/92019
+ * gfortran.dg/pr92019.f90: New test.
+
+2019-10-11 Joseph Myers <joseph@codesourcery.com>
+
+ * gcc.dg/dfp/c11-keywords-1.c, gcc.dg/dfp/c11-keywords-2.c,
+ gcc.dg/dfp/c2x-keywords-1.c, gcc.dg/dfp/c2x-keywords-2.c: New
+ tests.
+ * gcc.dg/dfp/keywords-ignored-c99.c: Remove test.
+ * gcc.dg/dfp/constants-c99.c, gcc.dg/dfp/keywords-c89.c,
+ gcc.dg/dfp/keywords-c99.c: Use -pedantic-errors.
+
+2019-10-11 Tobias Burnus <tobias@codesourcery.com>
+
+ PR fortran/92050
+ * gfortran.dg/pr92050.f90: New.
+
+2019-10-11 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/90883
+ PR tree-optimization/91091
+ * gcc.dg/torture/20191011-1.c: New testcase.
+ * gcc.dg/tree-ssa/ssa-fre-82.c: Likewise.
+ * gcc.dg/tree-ssa/ssa-fre-83.c: Likewise.
+ * gcc.dg/tree-ssa/redundant-assign-zero-1.c: Disable FRE.
+ * gcc.dg/tree-ssa/redundant-assign-zero-2.c: Likewise.
+
+2019-10-11 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gnat.dg/specs/size_clause4.ads: New test.
+
+2019-10-11 Ilya Leoshkevich <iii@linux.ibm.com>
+
+ PR target/77918
+ * gcc.target/s390/s390.exp: Enable Fortran tests.
+ * gcc.target/s390/zvector/autovec-double-quiet-eq.c: New test.
+ * gcc.target/s390/zvector/autovec-double-quiet-ge.c: New test.
+ * gcc.target/s390/zvector/autovec-double-quiet-gt.c: New test.
+ * gcc.target/s390/zvector/autovec-double-quiet-le.c: New test.
+ * gcc.target/s390/zvector/autovec-double-quiet-lt.c: New test.
+ * gcc.target/s390/zvector/autovec-double-quiet-ordered.c: New test.
+ * gcc.target/s390/zvector/autovec-double-quiet-uneq.c: New test.
+ * gcc.target/s390/zvector/autovec-double-quiet-unordered.c: New test.
+ * gcc.target/s390/zvector/autovec-double-signaling-eq-z13-finite.c: New test.
+ * gcc.target/s390/zvector/autovec-double-signaling-eq-z13.c: New test.
+ * gcc.target/s390/zvector/autovec-double-signaling-eq.c: New test.
+ * gcc.target/s390/zvector/autovec-double-signaling-ge-z13-finite.c: New test.
+ * gcc.target/s390/zvector/autovec-double-signaling-ge-z13.c: New test.
+ * gcc.target/s390/zvector/autovec-double-signaling-ge.c: New test.
+ * gcc.target/s390/zvector/autovec-double-signaling-gt-z13-finite.c: New test.
+ * gcc.target/s390/zvector/autovec-double-signaling-gt-z13.c: New test.
+ * gcc.target/s390/zvector/autovec-double-signaling-gt.c: New test.
+ * gcc.target/s390/zvector/autovec-double-signaling-le-z13-finite.c: New test.
+ * gcc.target/s390/zvector/autovec-double-signaling-le-z13.c: New test.
+ * gcc.target/s390/zvector/autovec-double-signaling-le.c: New test.
+ * gcc.target/s390/zvector/autovec-double-signaling-lt-z13-finite.c: New test.
+ * gcc.target/s390/zvector/autovec-double-signaling-lt-z13.c: New test.
+ * gcc.target/s390/zvector/autovec-double-signaling-lt.c: New test.
+ * gcc.target/s390/zvector/autovec-double-signaling-ltgt-z13-finite.c: New test.
+ * gcc.target/s390/zvector/autovec-double-signaling-ltgt-z13.c: New test.
+ * gcc.target/s390/zvector/autovec-double-signaling-ltgt.c: New test.
+ * gcc.target/s390/zvector/autovec-double-smax-z13.F90: New test.
+ * gcc.target/s390/zvector/autovec-double-smax.F90: New test.
+ * gcc.target/s390/zvector/autovec-double-smin-z13.F90: New test.
+ * gcc.target/s390/zvector/autovec-double-smin.F90: New test.
+ * gcc.target/s390/zvector/autovec-float-quiet-eq.c: New test.
+ * gcc.target/s390/zvector/autovec-float-quiet-ge.c: New test.
+ * gcc.target/s390/zvector/autovec-float-quiet-gt.c: New test.
+ * gcc.target/s390/zvector/autovec-float-quiet-le.c: New test.
+ * gcc.target/s390/zvector/autovec-float-quiet-lt.c: New test.
+ * gcc.target/s390/zvector/autovec-float-quiet-ordered.c: New test.
+ * gcc.target/s390/zvector/autovec-float-quiet-uneq.c: New test.
+ * gcc.target/s390/zvector/autovec-float-quiet-unordered.c: New test.
+ * gcc.target/s390/zvector/autovec-float-signaling-eq.c: New test.
+ * gcc.target/s390/zvector/autovec-float-signaling-ge.c: New test.
+ * gcc.target/s390/zvector/autovec-float-signaling-gt.c: New test.
+ * gcc.target/s390/zvector/autovec-float-signaling-le.c: New test.
+ * gcc.target/s390/zvector/autovec-float-signaling-lt.c: New test.
+ * gcc.target/s390/zvector/autovec-float-signaling-ltgt.c: New test.
+ * gcc.target/s390/zvector/autovec-fortran.h: New test.
+ * gcc.target/s390/zvector/autovec-long-double-signaling-ge.c: New test.
+ * gcc.target/s390/zvector/autovec-long-double-signaling-gt.c: New test.
+ * gcc.target/s390/zvector/autovec-long-double-signaling-le.c: New test.
+ * gcc.target/s390/zvector/autovec-long-double-signaling-lt.c: New test.
+ * gcc.target/s390/zvector/autovec.h: New test.
+
+2019-10-11 Ilya Leoshkevich <iii@linux.ibm.com>
+
+ * gcc.target/s390/vector/vec-scalar-cmp-1.c: Adjust
+ expectations.
+
+2019-10-11 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gnat.dg/array38.adb: New test.
+ * gnat.dg/array38_pkg.ad[sb]: New helper.
+
+2019-10-11 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/91987
+ * g++.dg/cpp1z/eval-order6.C: New test.
+ * g++.dg/cpp1z/eval-order7.C: New test.
+ * g++.dg/cpp1z/eval-order8.C: New test.
+ * c-c++-common/gomp/pr91987.c: New test.
+
+2019-10-10 Joseph Myers <joseph@codesourcery.com>
+
+ * gcc.dg/c11-float-dfp-1.c, gcc.dg/c2x-float-no-dfp-1.c,
+ gcc.dg/c2x-float-no-dfp-2.c, gcc.dg/dfp/c2x-float-dfp-1.c,
+ gcc.dg/dfp/c2x-float-dfp-2.c, gcc.dg/dfp/c2x-float-dfp-3.c,
+ gcc.dg/dfp/tr24732-float-dfp-1.c,
+ gcc.dg/dfp/ts18661-2-float-dfp-1.c: New tests.
+
+2019-10-10 David Malcolm <dmalcolm@redhat.com>
+
+ PR 87488
+ * c-c++-common/diagnostic-format-json-2.c: Expect an "option_url"
+ field.
+ * c-c++-common/diagnostic-format-json-3.c: Likewise.
+ * gfortran.dg/diagnostic-format-json-2.F90: Likewise.
+ * gfortran.dg/diagnostic-format-json-3.F90: Likewise.
+ * jit.dg/test-error-array-bounds.c (create_code): Ensure that
+ error messages don't contain escaped URLs.
+
+2019-10-10 David Malcolm <dmalcolm@redhat.com>
+
+ PR 87488
+ * lib/prune.exp (TEST_ALWAYS_FLAGS): Add -fdiagnostics-urls=never.
+
+2019-10-10 Uroš Bizjak <ubizjak@gmail.com>
+
+ PR target/92022
+ * g++.dg/pr92022.C: New test.
+
+2019-10-10 Jakub Jelinek <jakub@redhat.com>
+
+ * c-c++-common/gomp/declare-variant-1.c: New test.
+ * c-c++-common/gomp/declare-variant-2.c: New test.
+ * c-c++-common/gomp/declare-variant-3.c: New test.
+ * g++.dg/gomp/this-1.C: Adjust for diagnostic message spelling fix.
+ * gcc.dg/gomp/declare-variant-1.c: New test.
+ * gcc.dg/gomp/declare-variant-2.c: New test.
+
+2019-10-09 Martin Sebor <msebor@redhat.com>
+
+ PR tree-optimization/90879
+ * gcc.dg/Wstring-compare-2.c: New test.
+ * gcc.dg/Wstring-compare.c: New test.
+ * gcc.dg/strcmpopt_3.c: Scan the optmized dump instead of strlen.
+ * gcc.dg/strcmpopt_6.c: New test.
+ * gcc.dg/strlenopt-65.c: Remove uinnecessary declarations, add
+ test cases.
+ * gcc.dg/strlenopt-66.c: Run it.
+ * gcc.dg/strlenopt-68.c: New test.
+
+2019-10-09 Marek Polacek <polacek@redhat.com>
+
+ PR c++/91364 - P0388R4: Permit conversions to arrays of unknown bound.
+ PR c++/69531 - DR 1307: Differently bounded array parameters.
+ PR c++/88128 - DR 330: Qual convs and pointers to arrays of pointers.
+ * g++.dg/conversion/qual1.C: New test.
+ * g++.dg/conversion/qual2.C: New test.
+ * g++.dg/conversion/qual3.C: New test.
+ * g++.dg/conversion/ref2.C: New test.
+ * g++.dg/conversion/ref3.C: New test.
+ * g++.dg/cpp0x/initlist-array3.C: Remove dg-error.
+ * g++.dg/cpp0x/initlist-array7.C: New test.
+ * g++.dg/cpp0x/initlist-array8.C: New test.
+ * g++.dg/cpp2a/array-conv1.C: New test.
+ * g++.dg/cpp2a/array-conv10.C: New test.
+ * g++.dg/cpp2a/array-conv11.C: New test.
+ * g++.dg/cpp2a/array-conv12.C: New test.
+ * g++.dg/cpp2a/array-conv13.C: New test.
+ * g++.dg/cpp2a/array-conv14.C: New test.
+ * g++.dg/cpp2a/array-conv15.C: New test.
+ * g++.dg/cpp2a/array-conv16.C: New test.
+ * g++.dg/cpp2a/array-conv17.C: New test.
+ * g++.dg/cpp2a/array-conv2.C: New test.
+ * g++.dg/cpp2a/array-conv3.C: New test.
+ * g++.dg/cpp2a/array-conv4.C: New test.
+ * g++.dg/cpp2a/array-conv5.C: New test.
+ * g++.dg/cpp2a/array-conv6.C: New test.
+ * g++.dg/cpp2a/array-conv7.C: New test.
+ * g++.dg/cpp2a/array-conv8.C: New test.
+ * g++.dg/cpp2a/array-conv9.C: New test.
+ * g++.old-deja/g++.bugs/900321_01.C: Adjust dg-error.
+
+2019-10-09 Marek Polacek <polacek@redhat.com>
+
+ PR c++/92032 - DR 1601: Promotion of enum with fixed underlying type.
+ * g++.dg/cpp0x/scoped_enum10.C: New test.
+ * g++.dg/cpp0x/scoped_enum11.C: New test.
+
+2019-10-08 Andrew Sutton <asutton@lock3software.com>
+
+ * lib/target-supports.exp (check_effective_target_concepts): Check
+ for std=c++2a.
+
+2019-10-09 Paolo Carlini <paolo.carlini@oracle.com>
+
+ * c-c++-common/Waddress-1.c: Test locations too.
+ * c-c++-common/Wpointer-compare-1.c: Likewise.
+ * c-c++-common/Wshift-count-negative-1.c: Likewise.
+ * c-c++-common/Wshift-count-overflow-1.c: Likewise.
+ * c-c++-common/Wshift-negative-value-1.c: Likewise.
+ * c-c++-common/Wshift-negative-value-2.c: Likewise.
+ * c-c++-common/Wshift-negative-value-5.c: Likewise.
+ * c-c++-common/pr48418.c: Likewise.
+ * c-c++-common/pr65830.c: Likewise.
+ * c-c++-common/pr69764.c: Likewise.
+ * g++.dg/cpp0x/constexpr-array-ptr10.C: Likewise.
+ * g++.dg/cpp0x/nullptr37.C: Likewise.
+ * g++.dg/template/crash126.C: Likewise.
+ * g++.dg/template/crash129.C: Likewise.
+ * g++.dg/warn/Wextra-3.C: Likewise.
+ * g++.dg/warn/Wfloat-equal-1.C: Likewise.
+ * g++.dg/warn/Wstring-literal-comparison-1.C: Likewise.
+ * g++.dg/warn/Wstring-literal-comparison-2.C: Likewise.
+ * g++.dg/warn/pointer-integer-comparison.C: Likewise.
+ * g++.old-deja/g++.jason/crash8.C: Likewise.
+
+2019-10-09 Richard Biener <rguenther@suse.de>
+
+ * gcc.dg/vect/vect-outer-call-1.c: New testcase.
+
+2019-10-08 Alexandre Oliva <oliva@adacore.com>
+
+ * gcc.target/i386/20060512-1.c (sse2_test): Use a
+ call-clobbered register variable for stack-disaligning push
+ and pop. Require a frame pointer.
+ * gcc.target/i386/20060512-3.c (sse2_test): Likewise.
+
+2019-10-08 Martin Sebor <msebor@redhat.com>
+
+ PR c++/92001
+ * g++.dg/Wclass-memaccess-5.C: New test.
+
+2019-10-08 Dmitrij Pochepko <dmitrij.pochepko@bell-sw.com>
+
+ PR tree-optimization/90836
+ * lib/target-supports.exp (check_effective_target_popcount)
+ (check_effective_target_popcountll): New effective targets.
+ * gcc.dg/tree-ssa/popcount4.c: New test.
+ * gcc.dg/tree-ssa/popcount4l.c: New test.
+ * gcc.dg/tree-ssa/popcount4ll.c: New test.
+
+2019-10-08 Martin Sebor <msebor@redhat.com>
+
+ PR middle-end/92014
+ * gcc.dg/Wstringop-overflow-19.c: New test.
+
+2019-10-08 Steven G. Kargl <kargl@gcc.gnu.org>
+
+ PR fortran/91801
+ * gfortran.dg/pr91801.f90: New test.
+
+2019-10-08 Marek Polacek <polacek@redhat.com>
+
+ DR 685 - Integral promotion of enum ignores fixed underlying type.
+ * g++.dg/cpp0x/scoped_enum9.C: New test.
+
+2019-10-08 Martin Sebor <msebor@redhat.com>
+
+ PR tetsuite/92025
+ * gcc.dg/Wstringop-overflow-12.c: Remove xfail.
+
+2019-10-08 Richard Biener <rguenther@suse.de>
+
+ * gcc.dg/vect/pr65947-1.c: Adjust.
+ * gcc.dg/vect/pr65947-13.c: Likewise.
+ * gcc.dg/vect/pr65947-14.c: Likewise.
+ * gcc.dg/vect/pr65947-4.c: Likewise.
+ * gcc.dg/vect/pr80631-1.c: Likewise.
+ * gcc.dg/vect/pr80631-2.c: Likewise.
+
+2019-10-08 Tobias Burnus <tobias@codesourcery.com>
+
+ * gfortran.dg/goacc/continuation-free-form.f95: Update dg-error.
+
+2019-10-08 Richard Sandiford <richard.sandiford@arm.com>
+
+ * gcc.target/aarch64/torture/simd-abi-9.c: Require LP64 for
+ the function body test.
+
+2019-10-08 Joseph Myers <joseph@codesourcery.com>
+
+ * gcc.dg/torture/builtin-fp-int-inexact-c2x.c: New test.
+
+2019-10-07 Jozef Lawrynowicz <jozef.l@mittosystems.com>
+
+ * gcc.target/msp430/430x-insns.c: New test.
+ * gcc.target/msp430/data-attributes-2.c: Remove dg-warning
+ directives for conflicts between the "section" and "lower" attributes.
+ * gcc.target/msp430/msp430.exp
+ (check_effective_target_msp430_region_not_lower): New.
+ (check_effective_target_msp430_region_lower): New.
+ * gcc.target/msp430/object-attributes-430.c: New test.
+ * gcc.target/msp430/object-attributes-default.c: New test.
+ * gcc.target/msp430/object-attributes-mlarge-any-region.c: New test.
+ * gcc.target/msp430/object-attributes-mlarge.c: New test.
+
+2019-10-07 Jakub Jelinek <jakub@redhat.com>
+
+ * gcc.target/i386/pr71801.c (uuidcache_init): Fix up size of d array.
+
+2019-10-07 Paolo Carlini <paolo.carlini@oracle.com>
+
+ * g++.dg/diagnostic/not-a-function-template-1.C: New.
+ * g++.dg/template/crash107.C: Adjust expected location.
+ * g++.dg/template/dependent-expr1.C: Check locations.
+ * g++.dg/template/error17.C: Check location.
+
+2019-10-07 Richard Sandiford <richard.sandiford@arm.com>
+
+ PR target/91994
+ * gcc.target/i386/pr91994.c: New test.
+
2019-10-07 Richard Biener <rguenther@suse.de>
PR tree-optimization/91975
diff --git a/gcc/testsuite/c-c++-common/Waddress-1.c b/gcc/testsuite/c-c++-common/Waddress-1.c
index 8df5d2f6fec..9790a319881 100644
--- a/gcc/testsuite/c-c++-common/Waddress-1.c
+++ b/gcc/testsuite/c-c++-common/Waddress-1.c
@@ -8,8 +8,8 @@ int
foo ()
{
return "foo1" != (void *) 0 /* { dg-bogus "comparison with string literal results in unspecified behavior" } */
- && "foo2" != (const char *) ((void *) 0) /* { dg-bogus "comparison with string literal results in unspecified behavior" } */
- && "foo3" != (const char *) ((void *) (10 - 10)) /* { dg-bogus "comparison with string literal results in unspecified behavior" } */
- && "foo4" != (const char *) ((void *) (&e - &e)) /* { dg-warning "comparison with string literal results in unspecified behavior" "" { target c } } */
- && "foo5" != "foo6"; /* { dg-warning "comparison with string literal results in unspecified behavior" } */
+ && "foo2" != (const char *) ((void *) 0) /* { dg-bogus "comparison with string literal results in unspecified behavior" } */
+ && "foo3" != (const char *) ((void *) (10 - 10)) /* { dg-bogus "comparison with string literal results in unspecified behavior" } */
+ && "foo4" != (const char *) ((void *) (&e - &e)) /* { dg-warning "15:comparison with string literal results in unspecified behavior" "" { target c } } */
+ && "foo5" != "foo6"; /* { dg-warning "15:comparison with string literal results in unspecified behavior" } */
}
diff --git a/gcc/testsuite/c-c++-common/Wpointer-compare-1.c b/gcc/testsuite/c-c++-common/Wpointer-compare-1.c
index 440341ed9ed..808a0fd51a7 100644
--- a/gcc/testsuite/c-c++-common/Wpointer-compare-1.c
+++ b/gcc/testsuite/c-c++-common/Wpointer-compare-1.c
@@ -8,25 +8,25 @@ f1 (int *p, int **q)
{
int r = 0;
- r += p == '\0'; /* { dg-warning "comparison between pointer and zero character" } */
- r += p == L'\0'; /* { dg-warning "comparison between pointer and zero character" } */
- r += p != '\0'; /* { dg-warning "comparison between pointer and zero character" } */
- r += p != L'\0'; /* { dg-warning "comparison between pointer and zero character" } */
+ r += p == '\0'; /* { dg-warning "10:comparison between pointer and zero character" } */
+ r += p == L'\0'; /* { dg-warning "10:comparison between pointer and zero character" } */
+ r += p != '\0'; /* { dg-warning "10:comparison between pointer and zero character" } */
+ r += p != L'\0'; /* { dg-warning "10:comparison between pointer and zero character" } */
- r += '\0' == p; /* { dg-warning "comparison between pointer and zero character" } */
- r += L'\0' == p; /* { dg-warning "comparison between pointer and zero character" } */
- r += '\0' != p; /* { dg-warning "comparison between pointer and zero character" } */
- r += L'\0' != p; /* { dg-warning "comparison between pointer and zero character" } */
+ r += '\0' == p; /* { dg-warning "13:comparison between pointer and zero character" } */
+ r += L'\0' == p; /* { dg-warning "14:comparison between pointer and zero character" } */
+ r += '\0' != p; /* { dg-warning "13:comparison between pointer and zero character" } */
+ r += L'\0' != p; /* { dg-warning "14:comparison between pointer and zero character" } */
- r += q == '\0'; /* { dg-warning "comparison between pointer and zero character" } */
- r += q == L'\0'; /* { dg-warning "comparison between pointer and zero character" } */
- r += q != '\0'; /* { dg-warning "comparison between pointer and zero character" } */
- r += q != L'\0'; /* { dg-warning "comparison between pointer and zero character" } */
+ r += q == '\0'; /* { dg-warning "10:comparison between pointer and zero character" } */
+ r += q == L'\0'; /* { dg-warning "10:comparison between pointer and zero character" } */
+ r += q != '\0'; /* { dg-warning "10:comparison between pointer and zero character" } */
+ r += q != L'\0'; /* { dg-warning "10:comparison between pointer and zero character" } */
- r += '\0' == q; /* { dg-warning "comparison between pointer and zero character" } */
- r += L'\0' == q; /* { dg-warning "comparison between pointer and zero character" } */
- r += '\0' != q; /* { dg-warning "comparison between pointer and zero character" } */
- r += L'\0' != q; /* { dg-warning "comparison between pointer and zero character" } */
+ r += '\0' == q; /* { dg-warning "13:comparison between pointer and zero character" } */
+ r += L'\0' == q; /* { dg-warning "14:comparison between pointer and zero character" } */
+ r += '\0' != q; /* { dg-warning "13:comparison between pointer and zero character" } */
+ r += L'\0' != q; /* { dg-warning "14:comparison between pointer and zero character" } */
return r;
}
@@ -55,11 +55,11 @@ f3 (int *p)
{
int r = 0;
- r += p == (char) 0; /* { dg-warning "comparison between pointer and zero character" } */
- r += p != (char) 0; /* { dg-warning "comparison between pointer and zero character" } */
+ r += p == (char) 0; /* { dg-warning "10:comparison between pointer and zero character" } */
+ r += p != (char) 0; /* { dg-warning "10:comparison between pointer and zero character" } */
- r += (char) 0 == p; /* { dg-warning "comparison between pointer and zero character" } */
- r += (char) 0 != p; /* { dg-warning "comparison between pointer and zero character" } */
+ r += (char) 0 == p; /* { dg-warning "17:comparison between pointer and zero character" } */
+ r += (char) 0 != p; /* { dg-warning "17:comparison between pointer and zero character" } */
return r;
}
diff --git a/gcc/testsuite/c-c++-common/Wshift-count-negative-1.c b/gcc/testsuite/c-c++-common/Wshift-count-negative-1.c
index d8833936a2b..6807b985339 100644
--- a/gcc/testsuite/c-c++-common/Wshift-count-negative-1.c
+++ b/gcc/testsuite/c-c++-common/Wshift-count-negative-1.c
@@ -3,6 +3,6 @@
void foo()
{
- unsigned i1 = 1U << -1; /* { dg-warning "left shift count is negative" } */
- unsigned i2 = 1U >> -1; /* { dg-warning "right shift count is negative" } */
+ unsigned i1 = 1U << -1; /* { dg-warning "20:left shift count is negative" } */
+ unsigned i2 = 1U >> -1; /* { dg-warning "20:right shift count is negative" } */
}
diff --git a/gcc/testsuite/c-c++-common/Wshift-count-overflow-1.c b/gcc/testsuite/c-c++-common/Wshift-count-overflow-1.c
index 4d29d578625..47225e4aacb 100644
--- a/gcc/testsuite/c-c++-common/Wshift-count-overflow-1.c
+++ b/gcc/testsuite/c-c++-common/Wshift-count-overflow-1.c
@@ -3,6 +3,6 @@
void foo()
{
- unsigned i1 = 1U << (sizeof(unsigned) * __CHAR_BIT__); /* { dg-warning "left shift count >= width of type" } */
- unsigned i2 = 1U >> (sizeof(unsigned) * __CHAR_BIT__); /* { dg-warning "right shift count >= width of type" } */
+ unsigned i1 = 1U << (sizeof(unsigned) * __CHAR_BIT__); /* { dg-warning "20:left shift count >= width of type" } */
+ unsigned i2 = 1U >> (sizeof(unsigned) * __CHAR_BIT__); /* { dg-warning "20:right shift count >= width of type" } */
}
diff --git a/gcc/testsuite/c-c++-common/Wshift-negative-value-1.c b/gcc/testsuite/c-c++-common/Wshift-negative-value-1.c
index 7df1804615d..d58d8b9b002 100644
--- a/gcc/testsuite/c-c++-common/Wshift-negative-value-1.c
+++ b/gcc/testsuite/c-c++-common/Wshift-negative-value-1.c
@@ -6,7 +6,7 @@
enum E {
A = 0 << 1,
B = 1 << 1,
- C = -1 << 1, /* { dg-warning "left shift of negative value|not an integer constant" } */
+ C = -1 << 1, /* { dg-warning "10:left shift of negative value|not an integer constant" } */
/* { dg-error "left operand of shift expression" "shift" { target c++ } .-1 } */
D = 0 >> 1,
E = 1 >> 1,
@@ -23,10 +23,10 @@ left (int x)
int r = 0;
r += z << x;
r += o << x;
- r += m << x; /* { dg-warning "left shift of negative value" } */
+ r += m << x; /* { dg-warning "10:left shift of negative value" } */
r += 0 << x;
r += 1 << x;
- r += -1 << x; /* { dg-warning "left shift of negative value" } */
+ r += -1 << x; /* { dg-warning "11:left shift of negative value" } */
r += -1U << x;
return r;
}
diff --git a/gcc/testsuite/c-c++-common/Wshift-negative-value-2.c b/gcc/testsuite/c-c++-common/Wshift-negative-value-2.c
index 3a60ed7e1b8..9f435e8958d 100644
--- a/gcc/testsuite/c-c++-common/Wshift-negative-value-2.c
+++ b/gcc/testsuite/c-c++-common/Wshift-negative-value-2.c
@@ -6,7 +6,7 @@
enum E {
A = 0 << 1,
B = 1 << 1,
- C = -1 << 1, /* { dg-warning "left shift of negative value" } */
+ C = -1 << 1, /* { dg-warning "10:left shift of negative value" } */
/* { dg-error "not an integer constant" "no constant" { target c++ } .-1 } */
/* { dg-error "left operand of shift expression" "shift" { target c++ } .-2 } */
D = 0 >> 1,
@@ -24,10 +24,10 @@ left (int x)
int r = 0;
r += z << x;
r += o << x;
- r += m << x; /* { dg-warning "left shift of negative value" } */
+ r += m << x; /* { dg-warning "10:left shift of negative value" } */
r += 0 << x;
r += 1 << x;
- r += -1 << x; /* { dg-warning "left shift of negative value" } */
+ r += -1 << x; /* { dg-warning "11:left shift of negative value" } */
r += -1U << x;
return r;
}
diff --git a/gcc/testsuite/c-c++-common/Wshift-negative-value-5.c b/gcc/testsuite/c-c++-common/Wshift-negative-value-5.c
index 74ecd1e2867..3c3e74cf89a 100644
--- a/gcc/testsuite/c-c++-common/Wshift-negative-value-5.c
+++ b/gcc/testsuite/c-c++-common/Wshift-negative-value-5.c
@@ -7,7 +7,7 @@
enum E {
A = 0 << 1,
B = 1 << 1,
- C = -1 << 1, /* { dg-warning "left shift of negative value" } */
+ C = -1 << 1, /* { dg-warning "10:left shift of negative value" } */
D = 0 >> 1,
E = 1 >> 1,
F = -1 >> 1
@@ -23,10 +23,10 @@ left (int x)
int r = 0;
r += z << x;
r += o << x;
- r += m << x; /* { dg-warning "left shift of negative value" } */
+ r += m << x; /* { dg-warning "10:left shift of negative value" } */
r += 0 << x;
r += 1 << x;
- r += -1 << x; /* { dg-warning "left shift of negative value" } */
+ r += -1 << x; /* { dg-warning "11:left shift of negative value" } */
r += -1U << x;
return r;
}
diff --git a/gcc/testsuite/c-c++-common/diagnostic-format-json-2.c b/gcc/testsuite/c-c++-common/diagnostic-format-json-2.c
index 239c75ed769..557ccf8378b 100644
--- a/gcc/testsuite/c-c++-common/diagnostic-format-json-2.c
+++ b/gcc/testsuite/c-c++-common/diagnostic-format-json-2.c
@@ -10,6 +10,7 @@
/* { dg-regexp "\"kind\": \"warning\"" } */
/* { dg-regexp "\"message\": \"#warning message\"" } */
/* { dg-regexp "\"option\": \"-Wcpp\"" } */
+/* { dg-regexp "\"option_url\": \"https:\[^\n\r\"\]*#index-Wcpp\"" } */
/* { dg-regexp "\"caret\": \{" } */
/* { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-2.c\"" } */
diff --git a/gcc/testsuite/c-c++-common/diagnostic-format-json-3.c b/gcc/testsuite/c-c++-common/diagnostic-format-json-3.c
index 1c54ecacc9f..378205c5bf5 100644
--- a/gcc/testsuite/c-c++-common/diagnostic-format-json-3.c
+++ b/gcc/testsuite/c-c++-common/diagnostic-format-json-3.c
@@ -10,6 +10,7 @@
/* { dg-regexp "\"kind\": \"error\"" } */
/* { dg-regexp "\"message\": \"#warning message\"" } */
/* { dg-regexp "\"option\": \"-Werror=cpp\"" } */
+/* { dg-regexp "\"option_url\": \"https:\[^\n\r\"\]*#index-Wcpp\"" } */
/* { dg-regexp "\"caret\": \{" } */
/* { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-3.c\"" } */
diff --git a/gcc/testsuite/c-c++-common/diagnostic-format-json-4.c b/gcc/testsuite/c-c++-common/diagnostic-format-json-4.c
index 1c3b0343b6f..2738be6548f 100644
--- a/gcc/testsuite/c-c++-common/diagnostic-format-json-4.c
+++ b/gcc/testsuite/c-c++-common/diagnostic-format-json-4.c
@@ -30,13 +30,12 @@ int test (void)
/* { dg-regexp "\"line\": 8" } */
/* { dg-regexp "\"column\": 10" } */
-/* { dg-regexp "\"locations\": \[\[\{\}, \]*\]" } */
-
/* The outer diagnostic. */
/* { dg-regexp "\"kind\": \"warning\"" } */
/* { dg-regexp "\"message\": \"this 'if' clause does not guard...\"" } */
/* { dg-regexp "\"option\": \"-Wmisleading-indentation\"" } */
+/* { dg-regexp "\"option_url\": \"https:\[^\n\r\"\]*#index-Wmisleading-indentation\"" } */
/* { dg-regexp "\"caret\": \{" } */
/* { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-4.c\"" } */
@@ -48,6 +47,13 @@ int test (void)
/* { dg-regexp "\"line\": 6" } */
/* { dg-regexp "\"column\": 4" } */
+/* More from the nested diagnostic (we can't guarantee what order the
+ "file" keys are consumed). */
+
+/* { dg-regexp "\"locations\": \[\[\{\}, \]*\]" } */
+
+/* More from the outer diagnostic. */
+
/* { dg-regexp "\"locations\": \[\[\{\}, \]*\]" } */
/* { dg-regexp "\"children\": \[\[\{\}, \]*\]" } */
diff --git a/gcc/testsuite/c-c++-common/gomp/declare-variant-1.c b/gcc/testsuite/c-c++-common/gomp/declare-variant-1.c
new file mode 100644
index 00000000000..8b3cd7fed9f
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/declare-variant-1.c
@@ -0,0 +1,54 @@
+int foo (int, int, int *);
+int bar (int, int, int *);
+#pragma omp declare variant (foo) \
+ match (construct={parallel,for},\
+ device={isa(avx512f,avx512vl),kind(host,cpu)},\
+ implementation={vendor(score(0):gnu),unified_shared_memory},\
+ user={condition(score(0):0)})
+#pragma omp declare variant (bar) \
+ match (device={arch(x86_64,powerpc64),isa(avx512f,popcntb)}, \
+ implementation={atomic_default_mem_order(seq_cst),made_up_selector("foo", 13, "bar")}, \
+ user={condition(3-3)})
+int baz (int, int, int *);
+
+int
+qux (void)
+{
+ int i = 3;
+ return baz (1, 2, &i);
+}
+
+int quux (int);
+
+void
+corge (void)
+{
+ int i;
+ #pragma omp declare variant (quux) match (construct={parallel,for})
+ extern int waldo (int);
+ waldo (5);
+ #pragma omp parallel for
+ for (i = 0; i < 3; i++)
+ waldo (6);
+ #pragma omp parallel
+ #pragma omp taskgroup
+ #pragma omp for
+ for (i = 0; i < 3; i++)
+ waldo (7);
+ #pragma omp parallel
+ #pragma omp master
+ waldo (8);
+}
+
+#pragma omp declare variant (bar) match \
+ (implementation={atomic_default_mem_order(relaxed), \
+ unified_address, unified_shared_memory, \
+ dynamic_allocators, reverse_offload})
+int baz2 (int x, int y, int *z)
+{
+ return x + y + *z;
+}
+
+#pragma omp declare variant (bar) match \
+ (implementation={atomic_default_mem_order(score(3): acq_rel)})
+int baz3 (int, int, int *);
diff --git a/gcc/testsuite/c-c++-common/gomp/declare-variant-2.c b/gcc/testsuite/c-c++-common/gomp/declare-variant-2.c
new file mode 100644
index 00000000000..f058f57e687
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/declare-variant-2.c
@@ -0,0 +1,151 @@
+void f0 (void);
+void f1 (void);
+#pragma omp declare variant /* { dg-error "expected '\\(' before end of line" } */
+void f2 (void);
+#pragma omp declare variant ( /* { dg-error "" } */
+void f3 (void);
+#pragma omp declare variant () /* { dg-error "" } */
+void f4 (void);
+#pragma omp declare variant match(user={condition(0)}) /* { dg-error "expected '\\(' before 'match'" } */
+void f5 (void);
+#pragma omp declare variant (f1) /* { dg-error "expected 'match' before end of line" } */
+void f6 (void);
+#pragma omp declare variant (f1) simd /* { dg-error "expected 'match' before 'simd'" } */
+void f7 (void);
+#pragma omp declare variant (f1) match /* { dg-error "expected '\\(' before end of line" } */
+void f8 (void);
+#pragma omp declare variant (f1) match( /* { dg-error "expected 'construct', 'device', 'implementation' or 'user' before end of line" } */
+void f9 (void);
+#pragma omp declare variant (f1) match() /* { dg-error "expected 'construct', 'device', 'implementation' or 'user' before '\\)' token" } */
+void f10 (void);
+#pragma omp declare variant (f1) match(foo) /* { dg-error "expected 'construct', 'device', 'implementation' or 'user' before 'foo'" } */
+void f11 (void);
+#pragma omp declare variant (f1) match(something={something}) /* { dg-error "expected 'construct', 'device', 'implementation' or 'user' before 'something'" } */
+void f12 (void);
+#pragma omp declare variant (f1) match(user) /* { dg-error "expected '=' before '\\)' token" } */
+void f13 (void);
+#pragma omp declare variant (f1) match(user=) /* { dg-error "expected '\\\{' before '\\)' token" } */
+void f14 (void);
+#pragma omp declare variant (f1) match(user= /* { dg-error "expected '\\\{' before end of line" } */
+void f15 (void);
+#pragma omp declare variant (f1) match(user={) /* { dg-error "expected trait selector name before '\\)' token" } */
+void f16 (void); /* { dg-error "expected '\\\}' before" "" { target c++ } .-1 } */
+#pragma omp declare variant (f1) match(user={}) /* { dg-error "expected trait selector name before '\\\}' token" } */
+void f17 (void);
+#pragma omp declare variant (f1) match(user={condition}) /* { dg-error "expected '\\(' before '\\\}' token" } */
+void f18 (void);
+#pragma omp declare variant (f1) match(user={condition(}) /* { dg-error "expected \[^\n\r]*expression before '\\\}' token" } */
+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 constant integer expression" "" { target { c || c++11 } } } */
+void f21 (void); /* { dg-error "cannot appear in a constant-expression" "" { target c++98_only } .-1 } */
+#pragma omp declare variant (f1) match(user={condition(1, 2, 3)}) /* { dg-error "expected '\\)' before ',' token" } */
+void f22 (void);
+#pragma omp declare variant (f1) match(construct={master}) /* { dg-error "selector 'master' not allowed for context selector set 'construct'" } */
+void f23 (void);
+#pragma omp declare variant (f1) match(construct={teams,parallel,master,for}) /* { dg-error "selector 'master' not allowed for context selector set 'construct'" } */
+void f24 (void); /* { dg-error "expected '\\\}' before ',' token" "" { target c } .-1 } */
+#pragma omp declare variant (f1) match(construct={parallel(1 /* { dg-error "selector 'parallel' does not accept any properties" } */
+void f25 (void); /* { dg-error "expected '\\\}' before end of line" "" { target c++ } .-1 } */
+ /* { dg-error "expected '\\\}' before '\\(' token" "" { target c } .-2 } */
+#pragma omp declare variant (f1) match(construct={parallel(1)}) /* { dg-error "selector 'parallel' does not accept any properties" } */
+void f26 (void); /* { dg-error "expected '\\\}' before '\\(' token" "" { target c } .-1 } */
+#pragma omp declare variant (f0) match(construct={simd(12)}) /* { dg-error "expected \[^\n\r]* clause before" } */
+void f27 (void); /* { dg-error "'\\)' before numeric constant" "" { target c++ } .-1 } */
+#pragma omp declare variant (f1) match(construct={parallel},construct={for}) /* { dg-error "selector set 'construct' specified more than once" } */
+void f28 (void);
+#pragma omp declare variant (f1) match(construct={parallel},construct={parallel}) /* { dg-error "selector set 'construct' specified more than once" } */
+void f29 (void);
+#pragma omp declare variant (f1) match(user={condition(0)},construct={target},user={condition(0)}) /* { dg-error "selector set 'user' specified more than once" } */
+void f30 (void);
+#pragma omp declare variant (f1) match(user={condition(0)},user={condition(1)}) /* { dg-error "selector set 'user' specified more than once" } */
+void f31 (void);
+#pragma omp declare variant (f1) match(device={kind}) /* { dg-error "expected '\\(' before '\\\}' token" } */
+void f32 (void);
+#pragma omp declare variant (f1) match(device={isa}) /* { dg-error "expected '\\(' before '\\\}' token" } */
+void f33 (void);
+#pragma omp declare variant (f1) match(device={arch}) /* { dg-error "expected '\\(' before '\\\}' token" } */
+void f34 (void);
+#pragma omp declare variant (f1) match(device={kind,isa,arch}) /* { dg-error "expected '\\(' before ',' token" } */
+void f35 (void);
+#pragma omp declare variant (f1) match(device={kind(}) /* { dg-error "expected identifier before '\\\}' token" } */
+void f36 (void);
+#pragma omp declare variant (f1) match(device={kind(unknown)}) /* { dg-warning "unknown property 'unknown' of 'kind' selector" } */
+void f37 (void);
+#pragma omp declare variant (f1) match(device={kind(unknown,foobar)}) /* { dg-warning "unknown property 'unknown' of 'kind' selector" } */
+void f38 (void); /* { dg-warning "unknown property 'foobar' of 'kind' selector" "" { target *-*-* } .-1 } */
+#pragma omp declare variant (f1) match(device={isa(1)}) /* { dg-error "expected identifier before numeric constant" } */
+void f39 (void);
+#pragma omp declare variant (f1) match(device={arch(17)}) /* { dg-error "expected identifier before numeric constant" } */
+void f40 (void);
+#pragma omp declare variant (f1) match(device={foobar(3)})
+void f41 (void);
+#pragma omp declare variant (f1) match(device={arch(x86_64)},device={isa(avx512vl)}) /* { dg-error "selector set 'device' specified more than once" } */
+void f42 (void);
+#pragma omp declare variant (f1) match(implementation={foobar(3)})
+void f43 (void);
+#pragma omp declare variant (f1) match(implementation={vendor}) /* { dg-error "expected '\\(' before '\\\}' token" } */
+void f44 (void);
+#pragma omp declare variant (f1) match(implementation={extension}) /* { dg-error "expected '\\(' before '\\\}' token" } */
+void f45 (void);
+#pragma omp declare variant (f1) match(implementation={vendor()}) /* { dg-error "expected identifier before '\\)' token" } */
+void f45 (void);
+#pragma omp declare variant (f1) match(implementation={vendor(123-234)}) /* { dg-error "expected identifier before numeric constant" } */
+void f46 (void);
+#pragma omp declare variant (f1) match(implementation={vendor("x86_64")}) /* { dg-error "expected identifier before string constant" } */
+void f47 (void);
+#pragma omp declare variant (f1) match(implementation={unified_address(yes)}) /* { dg-error "selector 'unified_address' does not accept any properties" } */
+void f48 (void); /* { dg-error "expected '\\\}' before '\\(' token" "" { target c } .-1 } */
+#pragma omp declare variant (f1) match(implementation={unified_shared_memory(no)}) /* { dg-error "selector 'unified_shared_memory' does not accept any properties" } */
+void f49 (void); /* { dg-error "expected '\\\}' before '\\(' token" "" { target c } .-1 } */
+#pragma omp declare variant (f1) match(implementation={dynamic_allocators(42)}) /* { dg-error "selector 'dynamic_allocators' does not accept any properties" } */
+void f50 (void); /* { dg-error "expected '\\\}' before '\\(' token" "" { target c } .-1 } */
+#pragma omp declare variant (f1) match(implementation={reverse_offload()}) /* { dg-error "selector 'reverse_offload' does not accept any properties" } */
+void f51 (void); /* { dg-error "expected '\\\}' before '\\(' token" "" { target c } .-1 } */
+#pragma omp declare variant (f1) match(implementation={atomic_default_mem_order}) /* { dg-error "expected '\\(' before '\\\}' token" } */
+void f52 (void);
+#pragma omp declare variant (f1) match(implementation={atomic_default_mem_order(acquire)}) /* { dg-error "incorrect property 'acquire' of 'atomic_default_mem_order' selector" } */
+void f53 (void);
+#pragma omp declare variant (f1) match(implementation={atomic_default_mem_order(release)}) /* { dg-error "incorrect property 'release' of 'atomic_default_mem_order' selector" } */
+void f54 (void);
+#pragma omp declare variant (f1) match(implementation={atomic_default_mem_order(foobar)}) /* { dg-error "incorrect property 'foobar' of 'atomic_default_mem_order' selector" } */
+void f55 (void);
+#pragma omp declare variant (f1) match(implementation={atomic_default_mem_order(relaxed,seq_cst)}) /* { dg-error "'atomic_default_mem_order' selector must have a single property" } */
+void f56 (void);
+#pragma omp declare variant (f1) match(implementation={atomic_default_mem_order(relaxed)},implementation={atomic_default_mem_order(relaxed)}) /* { dg-error "selector set 'implementation' specified more than once" } */
+void f57 (void);
+#pragma omp declare variant (f1) match(user={foobar(3)}) /* { dg-error "selector 'foobar' not allowed for context selector set 'user'" } */
+void f58 (void); /* { dg-error "expected '\\\}' before '\\(' token" "" { target c } .-1 } */
+#pragma omp declare variant (f1) match(construct={foobar(3)}) /* { dg-error "selector 'foobar' not allowed for context selector set 'construct'" } */
+void f59 (void); /* { dg-error "expected '\\\}' before '\\(' token" "" { target c } .-1 } */
+#pragma omp declare variant (f1) match(construct={parallel},foobar={bar}) /* { dg-error "expected 'construct', 'device', 'implementation' or 'user' before 'foobar'" } */
+void f60 (void);
+#pragma omp declare variant (f1) match(construct={parallel,parallel}) /* { dg-error "selector 'parallel' specified more than once in set 'construct'" } */
+void f61 (void);
+#pragma omp declare variant (f1) match(construct={target,parallel,for,simd,parallel}) /* { dg-error "selector 'parallel' specified more than once in set 'construct'" } */
+void f62 (void);
+#pragma omp declare variant (f1) match(construct={target,teams,teams}) /* { dg-error "selector 'teams' specified more than once in set 'construct'" } */
+void f63 (void);
+#pragma omp declare variant (f1) match(construct={single}) /* { dg-error "selector 'single' not allowed for context selector set 'construct'" } */
+void f64 (void);
+#pragma omp declare variant (f1) match(construct={taskgroup}) /* { dg-error "selector 'taskgroup' not allowed for context selector set 'construct'" } */
+void f65 (void);
+#pragma omp declare variant (f1) match(construct={do}) /* { dg-error "selector 'do' not allowed for context selector set 'construct'" } */
+void f66 (void);
+#pragma omp declare variant (f1) match(construct={threadprivate}) /* { dg-error "selector 'threadprivate' not allowed for context selector set 'construct'" } */
+void f67 (void);
+#pragma omp declare variant (f1) match(construct={critical}) /* { dg-error "selector 'critical' not allowed for context selector set 'construct'" } */
+void f68 (void);
+#pragma omp declare variant (f1) match(construct={task}) /* { dg-error "selector 'task' not allowed for context selector set 'construct'" } */
+void f69 (void);
+#pragma omp declare variant (f1) match(construct={taskloop}) /* { dg-error "selector 'taskloop' not allowed for context selector set 'construct'" } */
+void f70 (void);
+#pragma omp declare variant (f1) match(construct={sections}) /* { dg-error "selector 'sections' not allowed for context selector set 'construct'" } */
+void f71 (void);
+#pragma omp declare variant (f1) match(construct={section}) /* { dg-error "selector 'section' not allowed for context selector set 'construct'" } */
+void f72 (void);
+#pragma omp declare variant (f1) match(construct={workshare}) /* { dg-error "selector 'workshare' not allowed for context selector set 'construct'" } */
+void f73 (void);
+#pragma omp declare variant (f1) match(construct={requires}) /* { dg-error "selector 'requires' not allowed for context selector set 'construct'" } */
+void f74 (void);
diff --git a/gcc/testsuite/c-c++-common/gomp/declare-variant-3.c b/gcc/testsuite/c-c++-common/gomp/declare-variant-3.c
new file mode 100644
index 00000000000..34a2a06db1b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/declare-variant-3.c
@@ -0,0 +1,141 @@
+void f1 (void);
+#pragma omp declare variant (f1) match (construct={target})
+void f2 (void);
+void f3 (void);
+#pragma omp declare variant (f3) match (construct={teams})
+void f4 (void);
+void f5 (void);
+#pragma omp declare variant (f5) match (construct={parallel})
+void f6 (void);
+void f7 (void);
+#pragma omp declare variant (f7) match (construct={for})
+void f8 (void);
+void f9 (void);
+#pragma omp declare variant (f9) match (construct={target,teams,parallel,for})
+void f10 (void);
+void f11 (void);
+#pragma omp declare variant (f11) match (construct={teams,for,parallel})
+void f12 (void);
+void f13 (void);
+#pragma omp declare variant (f13) match (device={kind(any)})
+void f14 (void);
+#pragma omp declare variant (f13) match (device={kind(host)})
+void f15 (void);
+#pragma omp declare variant (f13) match (device={kind(nohost)})
+void f16 (void);
+#pragma omp declare variant (f13) match (device={kind(cpu)})
+void f17 (void);
+#pragma omp declare variant (f13) match (device={kind(gpu)})
+void f18 (void);
+#pragma omp declare variant (f13) match (device={kind(fpga)})
+void f19 (void);
+#pragma omp declare variant (f13) match (device={kind(any,any)})
+void f20 (void);
+#pragma omp declare variant (f13) match (device={kind(host,nohost)})
+void f21 (void);
+#pragma omp declare variant (f13) match (device={kind(cpu,gpu,fpga)})
+void f22 (void);
+#pragma omp declare variant (f13) match (device={kind(any,cpu,nohost)})
+void f23 (void);
+#pragma omp declare variant (f13) match (device={isa(avx)})
+void f24 (void);
+#pragma omp declare variant (f13) match (device={isa(sse4,avx512f,avx512vl,avx512bw)})
+void f25 (void);
+#pragma omp declare variant (f13) match (device={arch(x86_64)})
+void f26 (void);
+#pragma omp declare variant (f13) match (device={arch(riscv64)})
+void f27 (void);
+#pragma omp declare variant (f13) match (device={arch(nvptx)})
+void f28 (void);
+#pragma omp declare variant (f13) match (device={arch(x86_64),isa(avx512f,avx512vl),kind(cpu)})
+void f29 (void);
+#pragma omp declare variant (f13) match (implementation={vendor(amd)})
+void f30 (void);
+#pragma omp declare variant (f13) match (implementation={vendor(arm)})
+void f31 (void);
+#pragma omp declare variant (f13) match (implementation={vendor(bsc)})
+void f32 (void);
+#pragma omp declare variant (f13) match (implementation={vendor(cray)})
+void f33 (void);
+#pragma omp declare variant (f13) match (implementation={vendor(fujitsu)})
+void f34 (void);
+#pragma omp declare variant (f13) match (implementation={vendor(gnu)})
+void f35 (void);
+#pragma omp declare variant (f13) match (implementation={vendor(ibm)})
+void f36 (void);
+#pragma omp declare variant (f13) match (implementation={vendor(intel)})
+void f37 (void);
+#pragma omp declare variant (f13) match (implementation={vendor(llvm)})
+void f38 (void);
+#pragma omp declare variant (f13) match (implementation={vendor(pgi)})
+void f39 (void);
+#pragma omp declare variant (f13) match (implementation={vendor(ti)})
+void f40 (void);
+#pragma omp declare variant (f13) match (implementation={vendor(unknown)})
+void f41 (void);
+#pragma omp declare variant (f13) match (implementation={vendor(gnu,llvm,intel,ibm)})
+void f42 (void);
+#pragma omp declare variant (f13) match (implementation={extension(my_cute_extension)}) /* { dg-warning "unknown property 'my_cute_extension' of 'extension' selector" } */
+void f43 (void);
+#pragma omp declare variant (f13) match (implementation={extension(some_other_ext,another_ext)}) /* { dg-warning "unknown property 'some_other_ext' of 'extension' selector" } */
+void f44 (void); /* { dg-warning "unknown property 'another_ext' of 'extension' selector" "" { target *-*-* } .-1 } */
+#pragma omp declare variant (f13) match (implementation={unified_shared_memory})
+void f45 (void);
+#pragma omp declare variant (f13) match (implementation={unified_address})
+void f46 (void);
+#pragma omp declare variant (f13) match (implementation={dynamic_allocators})
+void f47 (void);
+#pragma omp declare variant (f13) match (implementation={reverse_offload})
+void f48 (void);
+#pragma omp declare variant (f13) match (implementation={atomic_default_mem_order(seq_cst)})
+void f49 (void);
+#pragma omp declare variant (f13) match (implementation={atomic_default_mem_order(relaxed)})
+void f50 (void);
+#pragma omp declare variant (f13) match (implementation={atomic_default_mem_order(acq_rel)})
+void f51 (void);
+#pragma omp declare variant (f14) match (implementation={atomic_default_mem_order(acq_rel),vendor(gnu),unified_address,extension(foobar)}) /* { dg-warning "unknown property 'foobar' of 'extension' selector" } */
+void f52 (void);
+#pragma omp declare variant (f13) match (implementation={vendor(score(3):amd)})
+void f53 (void);
+#pragma omp declare variant (f13) match (implementation={vendor(score(4):arm)})
+void f54 (void);
+#pragma omp declare variant (f13) match (implementation={vendor(score(5):bsc)})
+void f55 (void);
+#pragma omp declare variant (f13) match (implementation={vendor(score(6):cray)})
+void f56 (void);
+#pragma omp declare variant (f13) match (implementation={vendor(score(7):fujitsu)})
+void f57 (void);
+#pragma omp declare variant (f13) match (implementation={vendor(score(8):gnu)})
+void f58 (void);
+#pragma omp declare variant (f13) match (implementation={vendor(score(9):ibm)})
+void f59 (void);
+#pragma omp declare variant (f13) match (implementation={vendor(score(10):intel)})
+void f60 (void);
+#pragma omp declare variant (f13) match (implementation={vendor(score(11):llvm)})
+void f61 (void);
+#pragma omp declare variant (f13) match (implementation={vendor(score(12):pgi)})
+void f62 (void);
+#pragma omp declare variant (f13) match (implementation={vendor(score(13):ti)})
+void f63 (void);
+#pragma omp declare variant (f13) match (implementation={vendor(score(14):unknown)})
+void f64 (void);
+#pragma omp declare variant (f13) match (implementation={vendor(score(15):gnu,llvm,intel,ibm)})
+void f65 (void);
+#pragma omp declare variant (f13) match (implementation={extension(score(16):my_cute_extension)}) /* { dg-warning "unknown property 'my_cute_extension' of 'extension' selector" } */
+void f66 (void);
+#pragma omp declare variant (f13) match (implementation={extension(score(17):some_other_ext,another_ext)}) /* { dg-warning "unknown property 'some_other_ext' of 'extension' selector" } */
+void f67 (void); /* { dg-warning "unknown property 'another_ext' of 'extension' selector" "" { target *-*-* } .-1 } */
+#pragma omp declare variant (f13) match (implementation={atomic_default_mem_order(score(18):seq_cst)})
+void f68 (void);
+#pragma omp declare variant (f13) match (implementation={atomic_default_mem_order(score(19):relaxed)})
+void f69 (void);
+#pragma omp declare variant (f13) match (implementation={atomic_default_mem_order(score(20):acq_rel)})
+void f70 (void);
+#pragma omp declare variant (f13) match (implementation={atomic_default_mem_order(score(21):acq_rel),vendor(score(22):gnu),unified_address,extension(score(22):foobar)}) /* { dg-warning "unknown property 'foobar' of 'extension' selector" } */
+void f71 (void);
+#pragma omp declare variant (f13) match (user={condition(0)})
+void f72 (void);
+#pragma omp declare variant (f13) match (user={condition(272-272*1)})
+void f73 (void);
+#pragma omp declare variant (f13) match (user={condition(score(25):1)})
+void f74 (void);
diff --git a/gcc/testsuite/c-c++-common/gomp/declare-variant-4.c b/gcc/testsuite/c-c++-common/gomp/declare-variant-4.c
new file mode 100644
index 00000000000..add373006ad
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/declare-variant-4.c
@@ -0,0 +1,22 @@
+double f1 (int, long, float);
+double f2 (int, long, float);
+double f3 (int, long, float);
+double f4 (int, long, float);
+double f5 (int, long, float);
+
+#pragma omp declare variant (f1) match (user={condition(1)})
+#pragma omp declare variant (f2) match (user={condition(score(1):1)})
+#pragma omp declare variant (f3) match (user={condition(score(3):1)})
+#pragma omp declare variant (f4) match (user={condition(score(2):1)})
+#pragma omp declare variant (f5) match (implementation={vendor(gnu)})
+double
+f6 (int x, long y, float z)
+{
+ return z + x + y;
+}
+
+double
+test (int x)
+{
+ return f6 (x, x, 3.5f);
+}
diff --git a/gcc/testsuite/c-c++-common/gomp/declare-variant-5.c b/gcc/testsuite/c-c++-common/gomp/declare-variant-5.c
new file mode 100644
index 00000000000..6ebf09457c0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/declare-variant-5.c
@@ -0,0 +1,36 @@
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+/* { dg-additional-options "-mavx2" } */
+
+typedef float __v4sf __attribute__((vector_size (16)));
+typedef int __v4si __attribute__((vector_size (16)));
+typedef float __v8sf __attribute__((vector_size (32)));
+typedef int __v8si __attribute__((vector_size (32)));
+__v4si f1 (__v4sf, __v4sf, float *);
+__v8si f2 (__v8sf, __v8sf, float *);
+__v4si f3 (__v4si, int, __v4si);
+
+#pragma omp declare variant (f1) match (construct={parallel,for,simd(simdlen(4),notinbranch,uniform(z),aligned(z:4 * sizeof (*z)))})
+#pragma omp declare variant (f2) match (construct={for,simd(uniform(z),simdlen(8),notinbranch)})
+int f4 (float x, float y, float *z);
+
+#pragma omp declare variant (f3) match (construct={simd(simdlen(4),inbranch,linear(y:1))})
+int f5 (int x, int y);
+
+void
+test (int *x, float *y, float *z, float *w)
+{
+ #pragma omp parallel
+ #pragma omp for simd aligned (w:4 * sizeof (float))
+ for (int i = 0; i < 1024; i++)
+ x[i] = f4 (y[i], z[i], w);
+ #pragma omp parallel for simd aligned (w:4 * sizeof (float)) simdlen(4)
+ for (int i = 1024; i < 2048; i++)
+ x[i] = f4 (y[i], z[i], w);
+ #pragma omp simd aligned (w:4 * sizeof (float))
+ for (int i = 2048; i < 4096; i++)
+ x[i] = f4 (y[i], z[i], w);
+ #pragma omp simd
+ for (int i = 4096; i < 8192; i++)
+ if (x[i] > 10)
+ x[i] = f5 (x[i], i);
+}
diff --git a/gcc/testsuite/c-c++-common/gomp/declare-variant-6.c b/gcc/testsuite/c-c++-common/gomp/declare-variant-6.c
new file mode 100644
index 00000000000..67c5a00bd8a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/declare-variant-6.c
@@ -0,0 +1,35 @@
+double f1 (int, long, float);
+double f2 (int, long, float);
+#pragma omp declare variant (f1) match (user={condition(0)},construct={parallel})
+double f3 (int, long, float);
+#pragma omp declare variant (f1) match (construct={parallel},user={condition(score(1):1)})
+double f4 (int, long, float);
+double f5 (int, long, float);
+#pragma omp declare variant (f5) match (user={condition(0)})
+double f6 (int, long, float);
+#pragma omp declare variant (f5) match (construct={parallel},user={condition(score(1):1)}) /* { dg-error "'f5' used as a variant with incompatible 'constructor' selector sets" "" { target c } } */
+double f7 (int, long, float);
+double f8 (int, long, float);
+#pragma omp declare variant (f8) match (user={condition(0)},construct={for})
+double f9 (int, long, float);
+#pragma omp declare variant (f8) match (user={condition(1)}) /* { dg-error "'f8' used as a variant with incompatible 'constructor' selector sets" "" { target c } } */
+double f10 (int, long, float);
+double f11 (int, long, float);
+#pragma omp declare variant (f11) match (construct={target,teams,parallel,for})
+double f12 (int, long, float);
+#pragma omp declare variant (f11) match (user={condition(score(1):1)},construct={target,teams,parallel,for})
+double f13 (int, long, float);
+#pragma omp declare variant (f11) match (implementation={vendor(gnu)},construct={target,teams,parallel}) /* { dg-error "'f11' used as a variant with incompatible 'constructor' selector sets" "" { target c } } */
+double f14 (int, long, float);
+#pragma omp declare variant (f11) match (device={kind(any)},construct={teams,parallel}) /* { dg-error "'f11' used as a variant with incompatible 'constructor' selector sets" "" { target c } } */
+double f15 (int, long, float);
+double f16 (int, long, float);
+#pragma omp declare variant (f16) match (construct={teams,parallel})
+double f17 (int, long, float);
+#pragma omp declare variant (f16) match(construct={teams,parallel,for}) /* { dg-error "'f16' used as a variant with incompatible 'constructor' selector sets" "" { target c } } */
+double f18 (int, long, float);
+double f19 (int, long, float);
+#pragma omp declare variant (f19) match (construct={parallel})
+double f20 (int, long, float);
+#pragma omp declare variant (f19) match (construct={for},implementation={vendor(gnu,llvm)}) /* { dg-error "'f19' used as a variant with incompatible 'constructor' selector sets" "" { target c } } */
+double f21 (int, long, float);
diff --git a/gcc/testsuite/c-c++-common/gomp/declare-variant-7.c b/gcc/testsuite/c-c++-common/gomp/declare-variant-7.c
new file mode 100644
index 00000000000..1df63384dff
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/declare-variant-7.c
@@ -0,0 +1,37 @@
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+/* { dg-additional-options "-mavx2" } */
+
+typedef float __v4sf __attribute__((vector_size (16)));
+typedef int __v4si __attribute__((vector_size (16)));
+typedef float __v8sf __attribute__((vector_size (32)));
+typedef int __v8si __attribute__((vector_size (32)));
+__v4si f1 (__v4sf, __v4sf, float *);
+__v8si f2 (__v8sf, __v8sf, float *);
+__v4si f3 (__v4si, int, __v4si);
+
+#pragma omp declare variant (f1) match (construct={parallel,for,simd(simdlen(4),notinbranch,uniform(z),aligned(z:4 * sizeof (*z)))})
+int f4 (float x, float y, float *z);
+#pragma omp declare variant (f1) match (construct={parallel,for,simd(uniform(w),simdlen(8*2-12),aligned(w:4*sizeof (float)),notinbranch)})
+int f5 (float u, float v, float *w);
+#pragma omp declare variant (f1) match (construct={parallel,for,simd(linear(w),notinbranch,simdlen(4),aligned(w:4*sizeof (float)))}) /* { dg-error "'f1' used as a variant with incompatible 'constructor' selector sets" "" { target c } } */
+int f6 (float u, float v, float *w);
+#pragma omp declare variant (f1) match (construct={parallel,for,simd(uniform(w),notinbranch,simdlen(4),aligned(w:2*sizeof (float)))}) /* { dg-error "'f1' used as a variant with incompatible 'constructor' selector sets" "" { target c } } */
+int f7 (float u, float v, float *w);
+#pragma omp declare variant (f1) match (construct={parallel,for,simd(uniform(w),notinbranch,simdlen(4),aligned(w))}) /* { dg-error "'f1' used as a variant with incompatible 'constructor' selector sets" "" { target c } } */
+int f8 (float u, float v, float *w);
+#pragma omp declare variant (f2) match (construct={for,simd(uniform(z),simdlen(8),notinbranch)})
+int f9 (float x, float y, float *z);
+#pragma omp declare variant (f2) match (construct={for,simd(notinbranch,simdlen(2+2+4),uniform (q))})
+int f10 (float x, float y, float *q);
+#pragma omp declare variant (f2) match (construct={for,simd(linear(z:2),simdlen(8),notinbranch)}) /* { dg-error "'f2' used as a variant with incompatible 'constructor' selector sets" "" { target c } } */
+int f11 (float x, float y, float *z);
+#pragma omp declare variant (f3) match (construct={simd(simdlen(4),inbranch,linear(y:1))})
+int f12 (int x, int y);
+#pragma omp declare variant (f3) match (construct={simd(inbranch, simdlen (5-1), linear (q:4-3))})
+int f13 (int x, int q);
+#pragma omp declare variant (f3) match (construct={simd(inbranch,simdlen(4),linear(q:2))}) /* { dg-error "'f3' used as a variant with incompatible 'constructor' selector sets" "" { target c } } */
+int f14 (int x, int q);
+#pragma omp declare variant (f3) match (construct={simd(inbranch simdlen (4) linear (q:1))}) /* { dg-error "clauses in 'simd' trait should be separated by ','" } */
+int f15 (int x, int q);
+#pragma omp declare variant (f3) match (construct={simd(inbranch, simdlen (5-1) linear (q:4-3))}) /* { dg-error "clauses in 'simd' trait should be separated by ','" } */
+int f16 (int x, int q);
diff --git a/gcc/testsuite/c-c++-common/gomp/pr91987.c b/gcc/testsuite/c-c++-common/gomp/pr91987.c
new file mode 100644
index 00000000000..516bb8091fd
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/pr91987.c
@@ -0,0 +1,26 @@
+/* PR c++/91987 */
+
+int bar (void);
+void baz (int *);
+#pragma omp declare target to (baz)
+
+void
+foo (int *a, int (*b)[10][10])
+{
+ #pragma omp target map(a[bar ()])
+ baz (a);
+ #pragma omp target map(a[bar ():1])
+ baz (a);
+ #pragma omp target map(a[10:bar ()])
+ baz (a);
+ #pragma omp task depend(inout:a[10:bar ()])
+ baz (a);
+ #pragma omp task depend(inout:a[10:bar ()])
+ baz (a);
+ #pragma omp parallel reduction(+:a[bar ():2])
+ baz (a);
+ #pragma omp parallel reduction(+:a[2:bar ()])
+ baz (a);
+ #pragma omp parallel reduction(+:b[bar ():2][bar ():10][bar ():10])
+ baz (a);
+}
diff --git a/gcc/testsuite/c-c++-common/pr48418.c b/gcc/testsuite/c-c++-common/pr48418.c
index 95ff855b89c..173285449bf 100644
--- a/gcc/testsuite/c-c++-common/pr48418.c
+++ b/gcc/testsuite/c-c++-common/pr48418.c
@@ -8,13 +8,13 @@ foo (int x)
const int a = sizeof (int) * __CHAR_BIT__;
const int b = -7;
int c = 0;
- c += x << a; /* { dg-warning "left shift count >= width of type" } */
- c += x << b; /* { dg-warning "left shift count is negative" } */
- c += x << (sizeof (int) * __CHAR_BIT__); /* { dg-warning "left shift count >= width of type" } */
- c += x << -7; /* { dg-warning "left shift count is negative" } */
- c += x >> a; /* { dg-warning "right shift count >= width of type" } */
- c += x >> b; /* { dg-warning "right shift count is negative" } */
- c += x >> (sizeof (int) * __CHAR_BIT__); /* { dg-warning "right shift count >= width of type" } */
- c += x >> -7; /* { dg-warning "right shift count is negative" } */
+ c += x << a; /* { dg-warning "10:left shift count >= width of type" } */
+ c += x << b; /* { dg-warning "10:left shift count is negative" } */
+ c += x << (sizeof (int) * __CHAR_BIT__); /* { dg-warning "10:left shift count >= width of type" } */
+ c += x << -7; /* { dg-warning "10:left shift count is negative" } */
+ c += x >> a; /* { dg-warning "10:right shift count >= width of type" } */
+ c += x >> b; /* { dg-warning "10:right shift count is negative" } */
+ c += x >> (sizeof (int) * __CHAR_BIT__); /* { dg-warning "10:right shift count >= width of type" } */
+ c += x >> -7; /* { dg-warning "10:right shift count is negative" } */
return c;
}
diff --git a/gcc/testsuite/c-c++-common/pr65830.c b/gcc/testsuite/c-c++-common/pr65830.c
index e115f181275..73eb97cff9e 100644
--- a/gcc/testsuite/c-c++-common/pr65830.c
+++ b/gcc/testsuite/c-c++-common/pr65830.c
@@ -8,9 +8,9 @@ foo (int x)
const int a = sizeof (int) * __CHAR_BIT__;
const int b = -7;
int c = 0;
- c += x << a; /* { dg-bogus "left shift count >= width of type" } */
- c += x << b; /* { dg-bogus "left shift count is negative" } */
- c += x >> a; /* { dg-bogus "right shift count >= width of type" } */
- c += x >> b; /* { dg-bogus "right shift count is negative" } */
+ c += x << a; /* { dg-bogus "10:left shift count >= width of type" } */
+ c += x << b; /* { dg-bogus "10:left shift count is negative" } */
+ c += x >> a; /* { dg-bogus "10:right shift count >= width of type" } */
+ c += x >> b; /* { dg-bogus "10:right shift count is negative" } */
return c;
}
diff --git a/gcc/testsuite/c-c++-common/pr69764.c b/gcc/testsuite/c-c++-common/pr69764.c
index 79623ec7373..146f2585850 100644
--- a/gcc/testsuite/c-c++-common/pr69764.c
+++ b/gcc/testsuite/c-c++-common/pr69764.c
@@ -4,35 +4,35 @@
unsigned char
fn1 (unsigned char a)
{
- return a >> ~6; /* { dg-warning "right shift count is negative" } */
+ return a >> ~6; /* { dg-warning "12:right shift count is negative" } */
}
unsigned short
fn2 (unsigned short a)
{
- return a >> ~6; /* { dg-warning "right shift count is negative" } */
+ return a >> ~6; /* { dg-warning "12:right shift count is negative" } */
}
unsigned int
fn3 (unsigned int a)
{
- return a >> ~6; /* { dg-warning "right shift count is negative" } */
+ return a >> ~6; /* { dg-warning "12:right shift count is negative" } */
}
unsigned char
fn4 (unsigned char a)
{
- return a >> 0xff03; /* { dg-warning "right shift count >= width of type" } */
+ return a >> 0xff03; /* { dg-warning "12:right shift count >= width of type" } */
}
unsigned short
fn5 (unsigned short a)
{
- return a >> 0xff03; /* { dg-warning "right shift count >= width of type" } */
+ return a >> 0xff03; /* { dg-warning "12:right shift count >= width of type" } */
}
unsigned int
fn6 (unsigned int a)
{
- return a >> 0xff03; /* { dg-warning "right shift count >= width of type" } */
+ return a >> 0xff03; /* { dg-warning "12:right shift count >= width of type" } */
}
diff --git a/gcc/testsuite/g++.dg/Wclass-memaccess-5.C b/gcc/testsuite/g++.dg/Wclass-memaccess-5.C
new file mode 100644
index 00000000000..d0fffead56d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/Wclass-memaccess-5.C
@@ -0,0 +1,18 @@
+/* PR c++/92001 - missing -Wclass-memaccess with array as first argument
+ to memset
+ { dg-do compile }
+ { dg-options "-Wall" } */
+
+extern "C" void* memset (void*, int, __SIZE_TYPE__);
+
+struct S { S (); };
+
+void test_array_access (S *p, S (*pa)[2], S (&r)[3])
+{
+ S a[1];
+ memset (a, 0, sizeof a); // { dg-warning "-Wclass-memaccess" }
+
+ memset (*pa, 0, sizeof *pa); // { dg-warning "-Wclass-memaccess" }
+
+ memset (r, 0, sizeof r); // { dg-warning "-Wclass-memaccess" }
+}
diff --git a/gcc/testsuite/g++.dg/concepts/alias1.C b/gcc/testsuite/g++.dg/concepts/alias1.C
deleted file mode 100644
index 279a4787576..00000000000
--- a/gcc/testsuite/g++.dg/concepts/alias1.C
+++ /dev/null
@@ -1,16 +0,0 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-template<typename T>
- concept bool C() { return __is_class(T); }
-
-template<typename T>
- requires C<T>()
- using X = T*;
-
-struct S { };
-
-int main()
-{
- X<S> x1;
-}
diff --git a/gcc/testsuite/g++.dg/concepts/alias2.C b/gcc/testsuite/g++.dg/concepts/alias2.C
deleted file mode 100644
index 06ffb1af529..00000000000
--- a/gcc/testsuite/g++.dg/concepts/alias2.C
+++ /dev/null
@@ -1,14 +0,0 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-template<typename T>
- concept bool C() { return __is_class(T); }
-
-template<C T> using X = T*;
-
-struct S { };
-
-int main()
-{
- X<S> x1;
-}
diff --git a/gcc/testsuite/g++.dg/concepts/alias3.C b/gcc/testsuite/g++.dg/concepts/alias3.C
deleted file mode 100644
index 2901c041881..00000000000
--- a/gcc/testsuite/g++.dg/concepts/alias3.C
+++ /dev/null
@@ -1,14 +0,0 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-template<typename T>
- concept bool C() { return __is_class(T); }
-
-template<typename T>
- requires C<T>()
- using X = T*;
-
-int main()
-{
- X<int> x1; // { dg-error "constraint|invalid" }
-}
diff --git a/gcc/testsuite/g++.dg/concepts/alias4.C b/gcc/testsuite/g++.dg/concepts/alias4.C
deleted file mode 100644
index 2c9f5defeb0..00000000000
--- a/gcc/testsuite/g++.dg/concepts/alias4.C
+++ /dev/null
@@ -1,20 +0,0 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-template<typename T>
- concept bool C() { return __is_class(T); }
-
-template<typename T>
- requires C<T>()
- using X = T*;
-
-// BUG: Alias templates are expanded at the point of use, regardless
-// of whether or not they are dependent. This causes T* to be substituted
-// without acutally checking the constraints.
-template<typename T>
- using Y = X<T>;
-
-int main()
-{
- Y<int> y1; // { dg-error "" "" { xfail *-*-* } }
-}
diff --git a/gcc/testsuite/g++.dg/concepts/auto1.C b/gcc/testsuite/g++.dg/concepts/auto1.C
index 2682940cedd..e05330610fc 100644
--- a/gcc/testsuite/g++.dg/concepts/auto1.C
+++ b/gcc/testsuite/g++.dg/concepts/auto1.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template <class T1, class T2> class A { };
diff --git a/gcc/testsuite/g++.dg/concepts/auto3.C b/gcc/testsuite/g++.dg/concepts/auto3.C
index abfb2019125..27a6afa4ed9 100644
--- a/gcc/testsuite/g++.dg/concepts/auto3.C
+++ b/gcc/testsuite/g++.dg/concepts/auto3.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template <class...> class tuple {};
diff --git a/gcc/testsuite/g++.dg/concepts/auto4.C b/gcc/testsuite/g++.dg/concepts/auto4.C
index 4eb2ae8f7d5..8bf3fa9b1ce 100644
--- a/gcc/testsuite/g++.dg/concepts/auto4.C
+++ b/gcc/testsuite/g++.dg/concepts/auto4.C
@@ -1,6 +1,6 @@
// PR c++/85006
-// { dg-do compile { target c++17 } }
-// { dg-additional-options "-fconcepts" }
+// { dg-do compile { target c++17_only } }
+// { dg-options "-fconcepts" }
template<typename... Ts> struct A {};
diff --git a/gcc/testsuite/g++.dg/concepts/class-deduction1.C b/gcc/testsuite/g++.dg/concepts/class-deduction1.C
index 936dd6826f0..33597007752 100644
--- a/gcc/testsuite/g++.dg/concepts/class-deduction1.C
+++ b/gcc/testsuite/g++.dg/concepts/class-deduction1.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template <class T>
diff --git a/gcc/testsuite/g++.dg/concepts/class.C b/gcc/testsuite/g++.dg/concepts/class.C
deleted file mode 100644
index dc5523e2407..00000000000
--- a/gcc/testsuite/g++.dg/concepts/class.C
+++ /dev/null
@@ -1,53 +0,0 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-template<typename T>
- concept bool Class() { return __is_class(T); }
-
-template<typename T>
- concept bool Union() { return __is_union(T); }
-
-
-// Check ordering of specializations
-template<typename T>
- concept bool One() { return sizeof(T) >= 4; }
-
-template<typename T>
- concept bool Two() { return One<T>() && sizeof(T) >= 8; }
-
-// Check non-overlapping specializations
-template<typename T>
- struct S1 { static const int value = 0; };
-
-template<Class T>
- struct S1<T> { static const int value = 1; };
-
-template<Union T>
- struct S1<T> { static const int value = 2; };
-
-struct S { };
-union U { };
-
-static_assert(S1<int>::value == 0, "");
-static_assert(S1<S>::value == 1, "");
-static_assert(S1<U>::value == 2, "");
-
-
-// Check ordering of partial specializaitons
-template<typename T>
- struct S2 { static const int value = 0; };
-
-template<One T>
- struct S2<T> { static const int value = 1; };
-
-template<Two T>
- struct S2<T> { static const int value = 2; };
-
-struct one_type { char x[4]; };
-struct two_type { char x[8]; };
-
-static_assert(S2<char>::value == 0, "");
-static_assert(S2<one_type>::value == 1, "");
-static_assert(S2<two_type>::value == 2, "");
-
-int main() { }
diff --git a/gcc/testsuite/g++.dg/concepts/class1.C b/gcc/testsuite/g++.dg/concepts/class1.C
deleted file mode 100644
index a738e6e82cd..00000000000
--- a/gcc/testsuite/g++.dg/concepts/class1.C
+++ /dev/null
@@ -1,15 +0,0 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-template<typename T>
- concept bool C() { return __is_class(T); }
-
-template<typename T>
- requires C<T>()
- struct S { };
-
-struct X { };
-
-S<X> sx;
-
-int main() { }
diff --git a/gcc/testsuite/g++.dg/concepts/class2.C b/gcc/testsuite/g++.dg/concepts/class2.C
deleted file mode 100644
index ec8718114a7..00000000000
--- a/gcc/testsuite/g++.dg/concepts/class2.C
+++ /dev/null
@@ -1,15 +0,0 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-template<typename T>
- concept bool C() { return __is_class(T); }
-
-template<typename T>
- requires C<T>()
- struct S { };
-
-struct X { };
-
-S<int> sx; // { dg-error "constraint|invalid" }
-
-int main() { }
diff --git a/gcc/testsuite/g++.dg/concepts/class3.C b/gcc/testsuite/g++.dg/concepts/class3.C
deleted file mode 100644
index 256370df46d..00000000000
--- a/gcc/testsuite/g++.dg/concepts/class3.C
+++ /dev/null
@@ -1,15 +0,0 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-template<typename T>
- concept bool C() { return __is_class(T); }
-
-// Check class redeclaration with alternative spellings.
-template<typename T> requires C<T>() struct S;
-template<C T> struct S { };
-
-struct X { };
-
-// S<X> sx;
-
-int main() { }
diff --git a/gcc/testsuite/g++.dg/concepts/class4.C b/gcc/testsuite/g++.dg/concepts/class4.C
deleted file mode 100644
index b583e55411d..00000000000
--- a/gcc/testsuite/g++.dg/concepts/class4.C
+++ /dev/null
@@ -1,22 +0,0 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-template<typename T>
- concept bool Class() { return __is_class(T); }
-
-template<typename T>
- concept bool Union() { return __is_union(T); }
-
-// Check non-overlapping specializations
-template<typename T> struct S1 { static const int value = 0; };
-template<Class T> struct S1<T> { static const int value = 1; };
-template<Union T> struct S1<T> { static const int value = 2; };
-
-struct S { };
-union U { };
-
-static_assert(S1<int>::value == 0, "");
-static_assert(S1<S>::value == 1, "");
-static_assert(S1<U>::value == 2, "");
-
-int main() { }
diff --git a/gcc/testsuite/g++.dg/concepts/class5.C b/gcc/testsuite/g++.dg/concepts/class5.C
index 7bf620edc5c..ac9d7e83e9d 100644
--- a/gcc/testsuite/g++.dg/concepts/class5.C
+++ b/gcc/testsuite/g++.dg/concepts/class5.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template<typename T>
diff --git a/gcc/testsuite/g++.dg/concepts/class6.C b/gcc/testsuite/g++.dg/concepts/class6.C
index bdd60918c8e..f2345b19b04 100644
--- a/gcc/testsuite/g++.dg/concepts/class6.C
+++ b/gcc/testsuite/g++.dg/concepts/class6.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template<typename T>
@@ -15,5 +15,3 @@ struct one_type { char x[4]; };
// Constraints are checked even when decls are not instantiatied.
S4<one_type>* x4b; // { dg-error "constraint|invalid" }
-
-int main() { }
diff --git a/gcc/testsuite/g++.dg/concepts/debug1.C b/gcc/testsuite/g++.dg/concepts/debug1.C
index 87f2ac90b20..b9a544486ac 100644
--- a/gcc/testsuite/g++.dg/concepts/debug1.C
+++ b/gcc/testsuite/g++.dg/concepts/debug1.C
@@ -1,11 +1,11 @@
// PR c++/84551
-// { dg-do compile { target c++17 } }
-// { dg-options "-g -O -fconcepts" }
+// { dg-do compile { target c++17_only } }
+// { dg-options "-fconcepts" }
template<typename> concept bool C() { return true; }
-template<template<typename T> requires C<T>() class> struct A {};
+template<template<typename T> requires C<T>() class TT> struct A {};
-template<typename> requires true struct B {};
+template<typename U> requires C<U>() struct B {};
A<B> a;
diff --git a/gcc/testsuite/g++.dg/concepts/decl-diagnose.C b/gcc/testsuite/g++.dg/concepts/decl-diagnose.C
index 019a8ce1130..6a461a50366 100644
--- a/gcc/testsuite/g++.dg/concepts/decl-diagnose.C
+++ b/gcc/testsuite/g++.dg/concepts/decl-diagnose.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
typedef concept int CINT; // { dg-error "'concept' cannot appear in a typedef declaration" }
@@ -12,10 +12,10 @@ concept bool f3(); // { dg-error "14:concept .f3. has no definition" }
struct X
{
template<typename T>
- concept int f4() { return 0; } // { dg-error "return type|member function" }
- concept bool f5() { return true; } // { dg-error "member function" }
+ concept int f4() { return 0; } // { dg-error "cannot be a member" }
+ concept f5 = true; // { dg-error "declared 'concept'" }
template<typename T>
- static concept bool f6() { return true; } // { dg-error "a concept cannot be a member function" }
+ static concept f6 = true; // { dg-error "declared 'concept'" }
static concept bool x; // { dg-error "declared 'concept'" }
// { dg-error "uninitialized 'const" "" { target *-*-* } .-1 }
concept int x2; // { dg-error "declared 'concept'" }
diff --git a/gcc/testsuite/g++.dg/concepts/deduction-constraint1.C b/gcc/testsuite/g++.dg/concepts/deduction-constraint1.C
index bebbda1a1fa..eba57713089 100644
--- a/gcc/testsuite/g++.dg/concepts/deduction-constraint1.C
+++ b/gcc/testsuite/g++.dg/concepts/deduction-constraint1.C
@@ -1,5 +1,5 @@
// PR c++/67007
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template <class U>
diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic1.C b/gcc/testsuite/g++.dg/concepts/diagnostic1.C
index 9bb15060573..ced56d400ba 100644
--- a/gcc/testsuite/g++.dg/concepts/diagnostic1.C
+++ b/gcc/testsuite/g++.dg/concepts/diagnostic1.C
@@ -1,19 +1,19 @@
// PR c++/67159
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template <class T, class U>
concept bool SameAs = __is_same_as(T, U);
template <class T>
-concept bool R1 = requires (T& t) {
- { t.begin() } -> T
- { t.end() } -> SameAs<T*>;
+concept bool R1 = requires (T& t) { // { dg-message "in requirements" }
+ { t.begin() } -> T; // { dg-error "no match" }
+ { t.end() } -> SameAs<T*>; // { dg-error "does not satisfy" }
};
template <class T>
-concept bool R2 = requires (T& t) {
- { t.end() } -> SameAs<T*>;
+concept bool R2 = requires (T& t) { // { dg-message "in requirements" }
+ { t.end() } -> SameAs<T*>; // { dg-error "does not satisfy" }
};
struct foo {
diff --git a/gcc/testsuite/g++.dg/concepts/disjunction1.C b/gcc/testsuite/g++.dg/concepts/disjunction1.C
deleted file mode 100644
index 930adf405c9..00000000000
--- a/gcc/testsuite/g++.dg/concepts/disjunction1.C
+++ /dev/null
@@ -1,60 +0,0 @@
-// PR c++/66962
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-template <typename> struct remove_cv;
-template <typename> struct is_reference;
-template <typename> void declval();
-template <typename> struct is_constructible;
-template <typename> struct is_nothrow_constructible;
-template <typename _Tp> using remove_cv_t = typename remove_cv<_Tp>::type;
-template <typename> struct Trans_NS_extension_apply_list;
-template <typename T> using _t = typename T::type;
-template <class> void ImplicitlyConvertibleTo();
-template <class> void Assignable();
-template <class T, class... Args> int ConstructibleObject = requires { T{}; };
-template <class T, class... Args>
-concept bool BindableReference =
- is_reference<T>::value &&is_constructible<T>::value;
-template <class T, class... Args> concept bool Constructible() {
- return ConstructibleObject<T> || BindableReference<T, Args...>;
-}
-template <class T> concept bool DefaultConstructible() {
- return Constructible<T>() && requires { new T[0]; };
-}
-template <class T> concept bool MoveConstructible() {
- return Constructible<T>() && ImplicitlyConvertibleTo<T>;
-}
-template <class T> concept bool Movable() {
- return MoveConstructible<T>() && Assignable<T &&>;
-}
-template <class, class> int Swappable_ = requires { 0; };
-template <class T, class U> int Swappable();
-template <class T> concept bool Dereferencable = requires{{0}};
-template <Dereferencable R> using RvalueReferenceType = decltype(0);
-template <class T> int IsValueType;
-template <class> struct value_type;
-template <class T>
-requires IsValueType<
- _t<value_type<remove_cv_t<T>>>> using ValueType =
- _t<value_type<remove_cv_t<T>>>;
-template <class I> concept bool Readable() {
- return Movable<I>() && DefaultConstructible<I>() &&
- Dereferencable<const I> && requires{{0}};
-}
-template <class Out, class T> concept bool MoveWritable() {
- return Movable<Out>() && DefaultConstructible<Out>() &&
- Dereferencable<Out>;
-}
-template <class In, class Out> concept bool IndirectlyMovable() {
- return Readable<In>() && Movable<ValueType<In>>() &&
- Constructible<ValueType<In>>() &&
- MoveWritable<Out, RvalueReferenceType<In>>() &&
- MoveWritable<Out, ValueType<In>>();
-}
-IndirectlyMovable { In, Out }
-int is_nothrow_indirectly_movable_v =
- is_nothrow_constructible<ValueType<In>>::value;
-template <Readable R1, Readable R2>
- requires IndirectlyMovable<R1, R2>() &&
- IndirectlyMovable<R2, R1>() void iter_swap2();
diff --git a/gcc/testsuite/g++.dg/concepts/dr1430.C b/gcc/testsuite/g++.dg/concepts/dr1430.C
index f865d5ec2c7..6f5bab1e106 100644
--- a/gcc/testsuite/g++.dg/concepts/dr1430.C
+++ b/gcc/testsuite/g++.dg/concepts/dr1430.C
@@ -1,5 +1,5 @@
// PR c++/66092
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
#include <type_traits>
@@ -29,11 +29,14 @@ template <typename T, typename U, typename... Args>
concept bool Similar = true;
template <typename... Args>
-requires Same<Args...>() // { dg-error "invalid reference" }
+requires Same<Args...>() // { dg-error "" "" { xfail *-*-* } }
void foo( Args... args ) {}
+// FIXME: The new method of building concept checks is suppressing the
+// diagnostic for the invalid substitution. This produces an invalid
+// requires-clause, which still prevents the function from being resolved.
template <typename... Args>
-requires Similar<Args...> // { dg-error "invalid reference" }
+requires Similar<Args...> // { dg-error "pack expansion" }
void bar( Args... args ) {}
int main()
diff --git a/gcc/testsuite/g++.dg/concepts/equiv.C b/gcc/testsuite/g++.dg/concepts/equiv.C
index faec3543461..640c2b5ec0d 100644
--- a/gcc/testsuite/g++.dg/concepts/equiv.C
+++ b/gcc/testsuite/g++.dg/concepts/equiv.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do link { target c++17_only } }
// { dg-options "-fconcepts" }
// Check equivalence of short- and longhand declarations.
diff --git a/gcc/testsuite/g++.dg/concepts/equiv2.C b/gcc/testsuite/g++.dg/concepts/equiv2.C
index 2094ca9f388..dff719b86a5 100644
--- a/gcc/testsuite/g++.dg/concepts/equiv2.C
+++ b/gcc/testsuite/g++.dg/concepts/equiv2.C
@@ -1,4 +1,4 @@
-// { dg-do run { target c++17 } }
+// { dg-do link { target c++17_only } }
// { dg-options "-fconcepts" }
@@ -21,9 +21,9 @@ int main() {
void f1(C, C) { }
-template<C T>
-void f2(T, T) { }
+template<C T1, C T2>
+void f2(T1, T2) { }
-template<typename T>
- requires C<T>
-void f3(T, T) { }
+template<typename T, typename U>
+ requires C<T> && C<U>
+void f3(T, U) { }
diff --git a/gcc/testsuite/g++.dg/concepts/explicit-inst4.C b/gcc/testsuite/g++.dg/concepts/explicit-inst4.C
deleted file mode 100644
index 20f43770539..00000000000
--- a/gcc/testsuite/g++.dg/concepts/explicit-inst4.C
+++ /dev/null
@@ -1,18 +0,0 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-template<typename T>
- concept bool C() { return __is_class(T); }
-
-template<typename T>
- concept bool D() { return C<T>() && __is_empty(T); }
-
-template<typename T>
- struct S {
- void g() requires C<T>() { } // #1
- void g() requires D<T>() { } // #2
- };
-
-template void S<int>::g(); // { dg-error "match" }
-
-int main() { }
diff --git a/gcc/testsuite/g++.dg/concepts/explicit-spec3.C b/gcc/testsuite/g++.dg/concepts/explicit-spec3.C
deleted file mode 100644
index fd48da1c280..00000000000
--- a/gcc/testsuite/g++.dg/concepts/explicit-spec3.C
+++ /dev/null
@@ -1,14 +0,0 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-template<typename T>
- concept bool C() { return __is_class(T); }
-
-template<C T> struct S;
-
-struct X { };
-
-// Not a valid explicit specialization, int does not satisfy C.
-template<> struct S<int> { }; // { dg-error "constraint" }
-
-int main() { }
diff --git a/gcc/testsuite/g++.dg/concepts/expression.C b/gcc/testsuite/g++.dg/concepts/expression.C
index 33dad0a47a6..ba4c48d7dcc 100644
--- a/gcc/testsuite/g++.dg/concepts/expression.C
+++ b/gcc/testsuite/g++.dg/concepts/expression.C
@@ -1,6 +1,8 @@
-// { dg-do run { target c++17 } }
+// { dg-do run { target c++17_only } }
// { dg-options "-fconcepts" }
+// TODO: ICE on gimplify 16?
+
#include <cassert>
#include <iostream>
@@ -8,13 +10,9 @@ template<typename T>
concept bool C1 = __is_class(T);
template<typename T>
- concept bool C2() { return __is_class(T); }
-
-template<typename T>
- concept bool C3() { return requires (T a) { ++a; }; }
+ concept bool C3 = requires (T a) { ++a; };
int main() {
if (C1<int>) assert(false);
- if (C2<int>()) assert(false);
- if (!C3<int>()) assert(false);
+ if (!C3<int>) assert(false);
}
diff --git a/gcc/testsuite/g++.dg/concepts/expression2.C b/gcc/testsuite/g++.dg/concepts/expression2.C
index c5447df1d87..1cff60542f5 100644
--- a/gcc/testsuite/g++.dg/concepts/expression2.C
+++ b/gcc/testsuite/g++.dg/concepts/expression2.C
@@ -1,16 +1,16 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template<typename T>
concept bool C1()
{
- return requires (T t) { t.f(); };
+ return requires (T t) { t.f(); }; // { dg-message "in requirements" }
}
template<typename T>
concept bool C2()
{
- return requires { typename T::type; };
+ return requires { typename T::type; }; // { dg-message "in requirements" }
}
template<typename T>
@@ -22,7 +22,7 @@ template<typename T>
void f2(T x) { }
// Note that these declarations are private and therefore
-// cannot satisify the constraints.
+// cannot satisfy the constraints.
class S
{
using type = int;
@@ -31,12 +31,12 @@ class S
int main()
{
- f1(s); // { dg-error "cannot call" }
+ f1(s); // { dg-error "cannot call|private" }
f2(s); // { dg-error "" }
// When used in non-SFINAE contexts, make sure that we fail
// the constraint check before emitting the access check
- // failures. The context is being presented constistently
+ // failures. The context is being presented consistently
// in both cases.
static_assert(C1<S>(), ""); // { dg-error "failed" }
static_assert(C2<S>(), ""); // { dg-error "" }
diff --git a/gcc/testsuite/g++.dg/concepts/expression3.C b/gcc/testsuite/g++.dg/concepts/expression3.C
index 26b829d338d..67646811284 100644
--- a/gcc/testsuite/g++.dg/concepts/expression3.C
+++ b/gcc/testsuite/g++.dg/concepts/expression3.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template<typename T>
diff --git a/gcc/testsuite/g++.dg/concepts/feature-macro.C b/gcc/testsuite/g++.dg/concepts/feature-macro.C
deleted file mode 100644
index d3d9b5420a8..00000000000
--- a/gcc/testsuite/g++.dg/concepts/feature-macro.C
+++ /dev/null
@@ -1,6 +0,0 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-#ifndef __cpp_concepts
-#error __cpp_concepts not defined
-#endif
diff --git a/gcc/testsuite/g++.dg/concepts/fn-concept1.C b/gcc/testsuite/g++.dg/concepts/fn-concept1.C
index a4ade7c628d..d1b4c0c59f3 100644
--- a/gcc/testsuite/g++.dg/concepts/fn-concept1.C
+++ b/gcc/testsuite/g++.dg/concepts/fn-concept1.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template<typename T>
diff --git a/gcc/testsuite/g++.dg/concepts/fn-concept2.C b/gcc/testsuite/g++.dg/concepts/fn-concept2.C
index 0d70728abe8..899988c37a3 100644
--- a/gcc/testsuite/g++.dg/concepts/fn-concept2.C
+++ b/gcc/testsuite/g++.dg/concepts/fn-concept2.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template<typename T>
diff --git a/gcc/testsuite/g++.dg/concepts/fn-generic-member-ool.C b/gcc/testsuite/g++.dg/concepts/fn-generic-member-ool.C
index b664ccf3da1..245380388fa 100644
--- a/gcc/testsuite/g++.dg/concepts/fn-generic-member-ool.C
+++ b/gcc/testsuite/g++.dg/concepts/fn-generic-member-ool.C
@@ -1,4 +1,3 @@
-// Out-of-line generic member function definitions.
// { dg-do compile { target c++14 } }
// { dg-additional-options "-fconcepts" }
diff --git a/gcc/testsuite/g++.dg/concepts/fn1.C b/gcc/testsuite/g++.dg/concepts/fn1.C
index 17f14b9a46b..f23c057ab6b 100644
--- a/gcc/testsuite/g++.dg/concepts/fn1.C
+++ b/gcc/testsuite/g++.dg/concepts/fn1.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template<typename T>
diff --git a/gcc/testsuite/g++.dg/concepts/fn10.C b/gcc/testsuite/g++.dg/concepts/fn10.C
index 6993f34a89f..8d0a2e1d202 100644
--- a/gcc/testsuite/g++.dg/concepts/fn10.C
+++ b/gcc/testsuite/g++.dg/concepts/fn10.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
// Test that constraint satisfaction checks work even when
@@ -40,7 +40,7 @@ template <typename T>
template <typename T>
concept bool Concept()
{
- return requires( T t ) {
+ return requires( T t ) { // { dg-message "in requirements" }
requires Float<decltype( project(t) )>();
};
}
diff --git a/gcc/testsuite/g++.dg/concepts/fn2.C b/gcc/testsuite/g++.dg/concepts/fn2.C
index 250e0a8713a..debb3238a6e 100644
--- a/gcc/testsuite/g++.dg/concepts/fn2.C
+++ b/gcc/testsuite/g++.dg/concepts/fn2.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template<typename T>
diff --git a/gcc/testsuite/g++.dg/concepts/fn3.C b/gcc/testsuite/g++.dg/concepts/fn3.C
index bc0e126c96c..07b8e3a89ba 100644
--- a/gcc/testsuite/g++.dg/concepts/fn3.C
+++ b/gcc/testsuite/g++.dg/concepts/fn3.C
@@ -1,4 +1,4 @@
-// { dg-do run { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
#include <cassert>
diff --git a/gcc/testsuite/g++.dg/concepts/fn4.C b/gcc/testsuite/g++.dg/concepts/fn4.C
index 830a1747865..bbaac46c9ff 100644
--- a/gcc/testsuite/g++.dg/concepts/fn4.C
+++ b/gcc/testsuite/g++.dg/concepts/fn4.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template<typename T>
diff --git a/gcc/testsuite/g++.dg/concepts/fn5.C b/gcc/testsuite/g++.dg/concepts/fn5.C
index 018b12f86e1..7714788c3c0 100644
--- a/gcc/testsuite/g++.dg/concepts/fn5.C
+++ b/gcc/testsuite/g++.dg/concepts/fn5.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
// Check shorthand notation.
diff --git a/gcc/testsuite/g++.dg/concepts/fn6.C b/gcc/testsuite/g++.dg/concepts/fn6.C
index 97155f8eb86..031e87fdf23 100644
--- a/gcc/testsuite/g++.dg/concepts/fn6.C
+++ b/gcc/testsuite/g++.dg/concepts/fn6.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
// Redefinition errors.
diff --git a/gcc/testsuite/g++.dg/concepts/fn7.C b/gcc/testsuite/g++.dg/concepts/fn7.C
index 0052f1aee73..869cb9c9391 100644
--- a/gcc/testsuite/g++.dg/concepts/fn7.C
+++ b/gcc/testsuite/g++.dg/concepts/fn7.C
@@ -1,8 +1,6 @@
-// { dg-do link { target c++17 } }
+// { dg-do link { target c++14 } }
// { dg-options "-fconcepts" }
-// FIXME: What is this actually testing?
-
void f() requires true { }
int main() { }
diff --git a/gcc/testsuite/g++.dg/concepts/fn8.C b/gcc/testsuite/g++.dg/concepts/fn8.C
index a3daf4e1bad..ffcce4f0220 100644
--- a/gcc/testsuite/g++.dg/concepts/fn8.C
+++ b/gcc/testsuite/g++.dg/concepts/fn8.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template<typename T>
diff --git a/gcc/testsuite/g++.dg/concepts/fn9.C b/gcc/testsuite/g++.dg/concepts/fn9.C
index 84ed77ce1c1..2f5e88b945c 100644
--- a/gcc/testsuite/g++.dg/concepts/fn9.C
+++ b/gcc/testsuite/g++.dg/concepts/fn9.C
@@ -1,4 +1,4 @@
-// { dg-do run { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
#include <cassert>
diff --git a/gcc/testsuite/g++.dg/concepts/generic-fn-err.C b/gcc/testsuite/g++.dg/concepts/generic-fn-err.C
index 5a9556531e7..816072d8d3a 100644
--- a/gcc/testsuite/g++.dg/concepts/generic-fn-err.C
+++ b/gcc/testsuite/g++.dg/concepts/generic-fn-err.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template<typename T>
@@ -10,10 +10,10 @@ template<int N>
template<template<typename> class X>
concept bool Template() { return true; }
-struct S { };
+void f1(Int) { } // { dg-error "does not constrain a type" }
+void f2(Template) { } // { dg-error "does not constrain a type" }
-void f1(Int) { } // { dg-error "" }
-void f2(Template) { } // { dg-error "" }
+struct S { };
struct S1 {
void f1(auto x) { }
diff --git a/gcc/testsuite/g++.dg/concepts/generic-fn.C b/gcc/testsuite/g++.dg/concepts/generic-fn.C
index 3b10327a493..257608a57a7 100644
--- a/gcc/testsuite/g++.dg/concepts/generic-fn.C
+++ b/gcc/testsuite/g++.dg/concepts/generic-fn.C
@@ -1,4 +1,4 @@
-// { dg-do run { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
#include <cassert>
diff --git a/gcc/testsuite/g++.dg/concepts/iconv1.C b/gcc/testsuite/g++.dg/concepts/iconv1.C
deleted file mode 100644
index e99254f3c27..00000000000
--- a/gcc/testsuite/g++.dg/concepts/iconv1.C
+++ /dev/null
@@ -1,21 +0,0 @@
-// PR c++/67240
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-int foo(int x)
-{
- return x;
-}
-
-template <typename T>
-concept bool C1 = requires (T x) {
- {foo(x)} -> int&;
-};
-
-template <typename T>
-concept bool C2 = requires (T x) {
- {foo(x)} -> void;
-};
-
-static_assert( C1<int> ); // { dg-error "assert" }
-static_assert( C2<int> ); // { dg-error "assert" }
diff --git a/gcc/testsuite/g++.dg/concepts/inherit-ctor1.C b/gcc/testsuite/g++.dg/concepts/inherit-ctor1.C
index 4b3f5619331..b137791bbb6 100644
--- a/gcc/testsuite/g++.dg/concepts/inherit-ctor1.C
+++ b/gcc/testsuite/g++.dg/concepts/inherit-ctor1.C
@@ -1,23 +1,33 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template<typename T>
- concept bool C() { return __is_class(T); }
+ concept bool C = __is_class(T);
+
+struct X { };
template<typename T>
- struct S1 { S1(double) requires C<T>() { } };
+ struct Base {
+ Base(double) requires C<T> { }
+ };
-struct S2 : S1<int> {
- using S1<int>::S1;
+struct Ok1 : Base<X> {
+ using Base<X>::Base;
+};
+
+struct Err1 : Base<int> {
+ using Base<int>::Base;
};
template<typename T>
- struct S3 : S1<T> {
- using S1<T>::S1;
+ struct Generic : Base<T> {
+ using Base<T>::Base;
};
-struct X { };
int main() {
- S3<X> s(0.0);
+ Ok1 x1(0.0);
+ Err1 x2(0.0); // { dg-error "no matching" }
+ Generic<X> x3(0.0);
+ Generic<int> x4(0.0); // { dg-error "no matching" }
}
diff --git a/gcc/testsuite/g++.dg/concepts/inherit-ctor3.C b/gcc/testsuite/g++.dg/concepts/inherit-ctor3.C
index 6f046323346..abfe96e8240 100644
--- a/gcc/testsuite/g++.dg/concepts/inherit-ctor3.C
+++ b/gcc/testsuite/g++.dg/concepts/inherit-ctor3.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template<typename T>
@@ -11,12 +11,13 @@ template<typename T>
};
template<typename T>
- struct S2 : S1<T> {
- using S1<T>::S1;
+ struct S2 : S1<T> { // { dg-error "no matching function" }
+ using S1<T>::S1; // { dg-error "no matching function" }
};
struct X { } x;
int main() {
- S2<X> s = x;
+ S2<X> s1(0); // { dg-error "use of deleted function" }
+ S2<X> s2; // { dg-error "use of deleted function" }
}
diff --git a/gcc/testsuite/g++.dg/concepts/inherit-ctor4.C b/gcc/testsuite/g++.dg/concepts/inherit-ctor4.C
deleted file mode 100644
index 43df6e67186..00000000000
--- a/gcc/testsuite/g++.dg/concepts/inherit-ctor4.C
+++ /dev/null
@@ -1,19 +0,0 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-template<typename T>
- concept bool C() { return __is_class(T); }
-
-template<typename T>
- struct S1 {
- template<C U> S1(U x) { }
- };
-
-template<typename T>
- struct S2 : S1<T> {
- using S1<T>::S1;
- };
-
-int main() {
- S2<int> s(0); // { dg-error "no matching function" }
-}
diff --git a/gcc/testsuite/g++.dg/concepts/intro1.C b/gcc/testsuite/g++.dg/concepts/intro1.C
index 84fa6dbbed4..5f9bb7e08f0 100644
--- a/gcc/testsuite/g++.dg/concepts/intro1.C
+++ b/gcc/testsuite/g++.dg/concepts/intro1.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template<typename T>
diff --git a/gcc/testsuite/g++.dg/concepts/intro2.C b/gcc/testsuite/g++.dg/concepts/intro2.C
index 9c7c1733c6d..206777d1b94 100644
--- a/gcc/testsuite/g++.dg/concepts/intro2.C
+++ b/gcc/testsuite/g++.dg/concepts/intro2.C
@@ -1,4 +1,4 @@
-// { dg-do run { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
#include <cassert>
diff --git a/gcc/testsuite/g++.dg/concepts/intro3.C b/gcc/testsuite/g++.dg/concepts/intro3.C
index 5e93f313270..f02f1bea247 100644
--- a/gcc/testsuite/g++.dg/concepts/intro3.C
+++ b/gcc/testsuite/g++.dg/concepts/intro3.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template<typename ... T>
diff --git a/gcc/testsuite/g++.dg/concepts/intro4.C b/gcc/testsuite/g++.dg/concepts/intro4.C
index a7e513535aa..0b275e14bf2 100644
--- a/gcc/testsuite/g++.dg/concepts/intro4.C
+++ b/gcc/testsuite/g++.dg/concepts/intro4.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template<typename ... T>
@@ -18,11 +18,11 @@ template<int N>
template<typename T, typename U = int>
concept bool C5() { return __is_class(U); }
-C1{...A, B} void f1() {}; // { dg-error "no matching|wrong number" }
-C1{A} void f2() {} // { dg-error "cannot match pack|no matching concept" }
-C2{A, B} void f3() {}; // { dg-error "cannot match pack|no matching concept" }
-C3{...A} void f4() {}; // { dg-error "cannot match pack|no matching concept" }
-C4{A} void f5() {}; // { dg-error "no matching concept" }
+C1{...A, B} void f1() {}; // { dg-error "cannot deduce template parameters" }
+C1{A} void f2() {}
+C2{A, B} void f3() {};
+C3{...A} void f4() {}; // { dg-error "cannot be introduced" }
+C4{A} void f5() {}; // { dg-error "cannot deduce template parameters" }
C5{A, B} void f6() {};
int main()
diff --git a/gcc/testsuite/g++.dg/concepts/intro5.C b/gcc/testsuite/g++.dg/concepts/intro5.C
index e7cd7a48066..bbfef7bed9e 100644
--- a/gcc/testsuite/g++.dg/concepts/intro5.C
+++ b/gcc/testsuite/g++.dg/concepts/intro5.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template<typename T, typename U = int>
@@ -7,10 +7,5 @@ template<typename T, typename U = int>
return sizeof(U) == sizeof(int);
}
-C{A} void f1() {}
+C{A} void f1() {} // { dg-error "all template parameters" }
-int main()
-{
- f1<char>();
- return 0;
-}
diff --git a/gcc/testsuite/g++.dg/concepts/intro6.C b/gcc/testsuite/g++.dg/concepts/intro6.C
index 57b325a0e38..233c5bcec7b 100644
--- a/gcc/testsuite/g++.dg/concepts/intro6.C
+++ b/gcc/testsuite/g++.dg/concepts/intro6.C
@@ -1,5 +1,5 @@
// PR c++/67003
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
namespace X {
diff --git a/gcc/testsuite/g++.dg/concepts/intro7.C b/gcc/testsuite/g++.dg/concepts/intro7.C
index d5bdc7e2789..343fe7a9824 100644
--- a/gcc/testsuite/g++.dg/concepts/intro7.C
+++ b/gcc/testsuite/g++.dg/concepts/intro7.C
@@ -1,14 +1,14 @@
// PR c++/66985
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template <template <class> class T>
-concept bool _Valid = requires { typename T<int>; };
+concept bool Valid = requires { typename T<int>; };
template <template <class> class T>
struct __defer { };
-_Valid{T}
+Valid{T}
struct __defer<T> {
using type = T<int>;
};
diff --git a/gcc/testsuite/g++.dg/concepts/locations1.C b/gcc/testsuite/g++.dg/concepts/locations1.C
index 33c3b6227c7..fbad42f6952 100644
--- a/gcc/testsuite/g++.dg/concepts/locations1.C
+++ b/gcc/testsuite/g++.dg/concepts/locations1.C
@@ -1,5 +1,5 @@
-// { dg-do compile { target c++17 } }
-// { dg-additional-options "-fconcepts" }
+// { dg-do compile { target c++17_only } }
+// { dg-options "-fconcepts" }
struct S
{
diff --git a/gcc/testsuite/g++.dg/concepts/memtmpl1.C b/gcc/testsuite/g++.dg/concepts/memtmpl1.C
deleted file mode 100644
index dc00a07a22b..00000000000
--- a/gcc/testsuite/g++.dg/concepts/memtmpl1.C
+++ /dev/null
@@ -1,16 +0,0 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-template <class T>
-struct A {
- template <class U>
- requires sizeof(T) == 1
- static void f(U);
- template <class U>
- requires sizeof(T) == 2
- static void f(U);
- void g()
- {
- f(42);
- }
-};
diff --git a/gcc/testsuite/g++.dg/concepts/partial-concept-id1.C b/gcc/testsuite/g++.dg/concepts/partial-concept-id1.C
index 5f0f3468ea1..6b66b78fb8b 100644
--- a/gcc/testsuite/g++.dg/concepts/partial-concept-id1.C
+++ b/gcc/testsuite/g++.dg/concepts/partial-concept-id1.C
@@ -1,27 +1,37 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template<typename T>
- concept bool Type() { return true; }
+ concept bool Type = true;
template<typename T, typename U>
- concept bool Same() { return __is_same_as(T, U); }
+ concept bool Same = __is_same_as(T, U);
template<typename T, typename U>
- concept bool C1() { return true; }
+ concept bool C1 = true;
template<typename T, typename... Args>
- concept bool C2() { return true; }
+ concept bool C2 = true;
+
+template<typename T, typename U>
+ concept bool C3 = __is_same_as(T, int) && __is_same_as(U, double);
template<Same<int> T> struct S1 { };
template<typename T, Same<T> U> struct S2 { };
-void f(Same<int> q) { }
-void g(Type a, Same<decltype(a)> b) { }
+template<Same<int> Q>
+void f(Q q) { }
+template<Type A, Same<decltype(A{})> B>
+void g(A a, B b) { }
-void h0(Same<int>* a) { }
-void h1(C1<int>* a) { }
-void h2(C2<char, short, int, long>* a) { }
+template<Same<int> A>
+void h0(A* a) { }
+template<C1<int> A>
+void h1(A* a) { }
+template<C2<char, short, int, long> A>
+void h2(A* a) { }
+template<C3<double> A>
+void h3(A* a) { }
int main() {
S1<int> s1;
@@ -30,5 +40,6 @@ int main() {
g(0, 1);
h0((int*)0);
h1((int*)0);
- h2((int*)0);
+ // h2((int*)0);
+ h3((int*)0);
}
diff --git a/gcc/testsuite/g++.dg/concepts/partial-concept-id2.C b/gcc/testsuite/g++.dg/concepts/partial-concept-id2.C
index e51894bb1c0..2c14576f374 100644
--- a/gcc/testsuite/g++.dg/concepts/partial-concept-id2.C
+++ b/gcc/testsuite/g++.dg/concepts/partial-concept-id2.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
// Make sure that we check partial concept ids
diff --git a/gcc/testsuite/g++.dg/concepts/partial-spec5.C b/gcc/testsuite/g++.dg/concepts/partial-spec5.C
index a5b853cfb3f..bec6715ea65 100644
--- a/gcc/testsuite/g++.dg/concepts/partial-spec5.C
+++ b/gcc/testsuite/g++.dg/concepts/partial-spec5.C
@@ -1,5 +1,5 @@
// PR c++/67138
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template <class T>
diff --git a/gcc/testsuite/g++.dg/concepts/placeholder1.C b/gcc/testsuite/g++.dg/concepts/placeholder1.C
deleted file mode 100644
index edd00033603..00000000000
--- a/gcc/testsuite/g++.dg/concepts/placeholder1.C
+++ /dev/null
@@ -1,35 +0,0 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-template<typename T, typename U>
-struct is_same
-{
- static constexpr bool value = false;
-};
-
-template<typename T>
-struct is_same<T, T>
-{
- static constexpr bool value = true;
-};
-
-template<class T, class U>
-concept bool Same = is_same<T, U>::value;
-
-template<typename T>
-concept bool C1 = true;
-
-template<typename T, typename U>
-concept bool C2 = true;
-
-template<typename T>
-concept bool C3() { return true; }
-
-template<typename T, typename U>
-concept bool C4() { return true; }
-
-C1 c1 = 0;
-C2<int> c2 = 0;
-C3 c3 = 0;
-C4<int> c4 = 0;
-Same<int> s1 = 'a'; // { dg-error "does not satisfy|is_same" }
diff --git a/gcc/testsuite/g++.dg/concepts/placeholder2.C b/gcc/testsuite/g++.dg/concepts/placeholder2.C
index 3d6fc813a6a..0c6f91abcaf 100644
--- a/gcc/testsuite/g++.dg/concepts/placeholder2.C
+++ b/gcc/testsuite/g++.dg/concepts/placeholder2.C
@@ -1,9 +1,6 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
-// Check argument deduction constraints.
-// TODO: We shoul have more of these...
-
template<typename T>
concept bool C1 = sizeof(T) == 0;
@@ -12,22 +9,16 @@ concept bool C2 = __is_same_as(T, U);
template<typename T>
-concept bool D1()
-{
- return requires (T t) { { t } -> C1; };
-}
+concept bool D1 = requires (T t) { { t } -> C1; };
template<typename T>
-concept bool D2()
-{
- return requires (T t) { { t } -> C2<void>; };
-}
+concept bool D2 = requires (T t) { { t } -> C2<void>; };
-void f1(D1) { }
-void f2(D2) { }
+void f1(auto D1) { } // OK: D1 is declared as a parameter
+void f2(auto D2) { } // OK: D2 is declared as a parameter
int main()
{
- f1(0); // { dg-error "cannot call" }
- f2(0); // { dg-error "cannot call" }
+ f1(0);
+ f2(0);
}
diff --git a/gcc/testsuite/g++.dg/concepts/placeholder3.C b/gcc/testsuite/g++.dg/concepts/placeholder3.C
index 93f0c0d161f..4f8600bd07f 100644
--- a/gcc/testsuite/g++.dg/concepts/placeholder3.C
+++ b/gcc/testsuite/g++.dg/concepts/placeholder3.C
@@ -1,5 +1,5 @@
// PR c++/66218
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template <class T, class U>
@@ -7,8 +7,8 @@ concept bool Same = __is_same_as(T, U);
template <class T>
concept bool C =
- requires {
- { 0 } -> Same<T>;
+ requires { // { dg-message "in requirements" }
+ { 0 } -> Same<T>; // { dg-error "does not satisfy" }
};
template <C c>
diff --git a/gcc/testsuite/g++.dg/concepts/placeholder4.C b/gcc/testsuite/g++.dg/concepts/placeholder4.C
index d1308137c04..2b5afbbc6f2 100644
--- a/gcc/testsuite/g++.dg/concepts/placeholder4.C
+++ b/gcc/testsuite/g++.dg/concepts/placeholder4.C
@@ -1,5 +1,5 @@
// PR c++/66218
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template <class T, class U>
@@ -7,8 +7,8 @@ concept bool Same = __is_same_as(T, U);
template <class T>
concept bool C =
- requires {
- { 0 } -> Same<T>;
+ requires { // { dg-message "in requirements" }
+ { 0 } -> Same<T>; // { dg-error "does not satisfy" }
};
template <class T>
diff --git a/gcc/testsuite/g++.dg/concepts/placeholder5.C b/gcc/testsuite/g++.dg/concepts/placeholder5.C
index 245e27a75ed..7881a40a22a 100644
--- a/gcc/testsuite/g++.dg/concepts/placeholder5.C
+++ b/gcc/testsuite/g++.dg/concepts/placeholder5.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template <class T, class U>
@@ -8,11 +8,11 @@ const int i = 0;
template <class T>
concept bool C =
requires {
- { &i } -> const Same<T>*;
+ { &i } -> const Same<T>*; // { dg-error "not a plain type-constraint" }
};
template <C c>
constexpr bool f() { return true; }
-static_assert(f<double>(), ""); // { dg-error "" }
-static_assert(f<int>(), "");
+static_assert(f<double>(), ""); // { dg-error "cannot call|as type" }
+static_assert(f<int>(), ""); // { dg-error "cannot call|as type" }
diff --git a/gcc/testsuite/g++.dg/concepts/placeholder6.C b/gcc/testsuite/g++.dg/concepts/placeholder6.C
index 51282d93a5d..20b9c931648 100644
--- a/gcc/testsuite/g++.dg/concepts/placeholder6.C
+++ b/gcc/testsuite/g++.dg/concepts/placeholder6.C
@@ -1,11 +1,8 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template <int I> struct B { static const int i = I; };
template <int I> concept bool Few = I < 10;
-constexpr int g(B<Few> b) { return b.i; }
+constexpr int g(B<Few> b); // { dg-error "does not constrain a type|invalid" }
-#define SA(X) static_assert((X),#X)
-SA(g(B<2>{}) == 2);
-SA(g(B<10>{}) == 10); // { dg-error "" }
diff --git a/gcc/testsuite/g++.dg/concepts/pr65634.C b/gcc/testsuite/g++.dg/concepts/pr65634.C
index e383653b6a3..5fcb38a5bf4 100644
--- a/gcc/testsuite/g++.dg/concepts/pr65634.C
+++ b/gcc/testsuite/g++.dg/concepts/pr65634.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template<typename T>
diff --git a/gcc/testsuite/g++.dg/concepts/pr65636.C b/gcc/testsuite/g++.dg/concepts/pr65636.C
index 2aec0e545d2..f927c9abefc 100644
--- a/gcc/testsuite/g++.dg/concepts/pr65636.C
+++ b/gcc/testsuite/g++.dg/concepts/pr65636.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
using TD = int;
diff --git a/gcc/testsuite/g++.dg/concepts/pr65681.C b/gcc/testsuite/g++.dg/concepts/pr65681.C
index 0d8a69d0bd1..67153d63dfb 100644
--- a/gcc/testsuite/g++.dg/concepts/pr65681.C
+++ b/gcc/testsuite/g++.dg/concepts/pr65681.C
@@ -1,66 +1,45 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template<typename T>
-concept bool C()
-{
- return requires (T t) { t.mf(); };
-}
+concept bool C = requires (T t) { t.mf(); };
template<typename T>
-concept bool CA1()
-{
- return C<typename T::ca1_type>();
-}
+concept bool CA1 = C<typename T::ca1_type>;
template<typename T>
-concept bool CA2()
-{
- return CA1<T>() && requires () { typename T::ca2_type; };
-}
+concept bool CA2 = CA1<T> && requires () { typename T::ca2_type; };
template<typename T>
-concept bool CA3()
-{
- return CA2<T>() && requires () { typename T::ca3_type; };
-}
+concept bool CA3 = CA2<T> && requires () { typename T::ca3_type; };
template<typename T>
-concept bool CB1()
-{
- return requires () { typename T::cb1_type; };
-}
+concept bool CB1 = requires () { typename T::cb1_type; };
template<typename T>
-concept bool CB2()
-{
- return CB1<T>() && requires () { typename T::cb2_type; };
-}
+concept bool CB2 = CB1<T> && requires () { typename T::cb2_type; };
template<typename T>
-concept bool CB3()
-{
- return CB2<T>() && requires () { typename T::cb3_type; };
-}
+concept bool CB3 = CB2<T> && requires () { typename T::cb3_type; };
struct MC { void mf(); };
-static_assert(C<MC>(), "");
+static_assert(C<MC>, "");
struct MA1 { using ca1_type = MC; };
struct MA2 : MA1 { using ca2_type = int; };
struct MA3 : MA2 { using ca3_type = int; };
-static_assert(CA1<MA1>(), "");
-static_assert(CA2<MA2>(), "");
-static_assert(CA3<MA3>(), "");
+static_assert(CA1<MA1>, "");
+static_assert(CA2<MA2>, "");
+static_assert(CA3<MA3>, "");
struct MB1 { using cb1_type = int; };
struct MB2 : MB1 { using cb2_type = int; };
struct MB3 : MB2 { using cb3_type = int; };
-static_assert(CB1<MB1>(), "");
-static_assert(CB2<MB2>(), "");
-static_assert(CB3<MB3>(), "");
+static_assert(CB1<MB1>, "");
+static_assert(CB2<MB2>, "");
+static_assert(CB3<MB3>, "");
template<typename T1, typename T2>
@@ -73,29 +52,19 @@ struct S<T1, T2> // Specialization #1
};
template<CA1 T1, CB2 T2>
- requires !CA2<T1>()
+ requires (!CA2<T1>)
struct S<T1, T2> // Specialization #2
{
static constexpr int value = 2;
};
template<CA2 T1, CB3 T2>
- requires !CA3<T1>()
+ requires (!CA3<T1>)
struct S<T1, T2> // Specialization #3
{
static constexpr int value = 3;
};
-S<MA1,MB1> s11;
-S<MA1,MB2> s12;
-S<MA1,MB3> s13;
-S<MA2,MB1> s21;
-S<MA2,MB2> s22;
-S<MA2,MB3> s23;
-S<MA3,MB1> s31;
-S<MA3,MB2> s32;
-S<MA3,MB3> s33;
-
static_assert(S<MA1,MB1>::value == 1, "");
static_assert(S<MA1,MB2>::value == 2, "");
static_assert(S<MA1,MB3>::value == 2, "");
diff --git a/gcc/testsuite/g++.dg/concepts/pr65848.C b/gcc/testsuite/g++.dg/concepts/pr65848.C
index 067801844dc..ea3077d84fb 100644
--- a/gcc/testsuite/g++.dg/concepts/pr65848.C
+++ b/gcc/testsuite/g++.dg/concepts/pr65848.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
// Performance test... This should be fast.
diff --git a/gcc/testsuite/g++.dg/concepts/pr67249.C b/gcc/testsuite/g++.dg/concepts/pr67249.C
index a0eca9ba8c0..382eba110a6 100644
--- a/gcc/testsuite/g++.dg/concepts/pr67249.C
+++ b/gcc/testsuite/g++.dg/concepts/pr67249.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template<class T> concept bool C1 = true;
diff --git a/gcc/testsuite/g++.dg/concepts/pr67544.C b/gcc/testsuite/g++.dg/concepts/pr67544.C
index af4f677644a..600176027b8 100644
--- a/gcc/testsuite/g++.dg/concepts/pr67544.C
+++ b/gcc/testsuite/g++.dg/concepts/pr67544.C
@@ -1,4 +1,5 @@
-// { dg-additional-options "-fconcepts" }
+// { dg-do compile { target c++11 } }
+// { dg-options "-fconcepts" }
template <typename T> struct A
{
diff --git a/gcc/testsuite/g++.dg/concepts/pr67595.C b/gcc/testsuite/g++.dg/concepts/pr67595.C
index 7b5d712512e..7199e0517d4 100644
--- a/gcc/testsuite/g++.dg/concepts/pr67595.C
+++ b/gcc/testsuite/g++.dg/concepts/pr67595.C
@@ -1,10 +1,10 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
-template <class X> concept bool allocatable = requires{{new X}->X * };
+template <class X> concept bool allocatable = requires{{new X}->X *; };
template <class X> concept bool semiregular = allocatable<X>;
-template <class X> concept bool readable = requires{requires semiregular<X>};
-template <class> int weak_input_iterator = requires{{0}->readable};
+template <class X> concept bool readable = requires{requires semiregular<X>;};
+template <class> int weak_input_iterator = requires{{0}->readable;};
template <class X> bool input_iterator{weak_input_iterator<X>}; // { dg-warning "narrowing conversion" }
template <class X> bool forward_iterator{input_iterator<X>};
template <class X> bool bidirectional_iterator{forward_iterator<X>};
diff --git a/gcc/testsuite/g++.dg/concepts/pr67655.C b/gcc/testsuite/g++.dg/concepts/pr67655.C
index b1554218aad..ddd069c7987 100644
--- a/gcc/testsuite/g++.dg/concepts/pr67655.C
+++ b/gcc/testsuite/g++.dg/concepts/pr67655.C
@@ -1,7 +1,7 @@
// { dg-do compile { target c++11 } }
// { dg-additional-options "-fconcepts" }
-template<class... Xs>
+template<class... Xs>
void consume(Xs&&...) {}
template<class... Xs>
diff --git a/gcc/testsuite/g++.dg/concepts/pr68434.C b/gcc/testsuite/g++.dg/concepts/pr68434.C
index fc458989c34..16868ba042c 100644
--- a/gcc/testsuite/g++.dg/concepts/pr68434.C
+++ b/gcc/testsuite/g++.dg/concepts/pr68434.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template <class>
diff --git a/gcc/testsuite/g++.dg/concepts/pr71127.C b/gcc/testsuite/g++.dg/concepts/pr71127.C
index 3ec6514b467..224eaa3d2f7 100644
--- a/gcc/testsuite/g++.dg/concepts/pr71127.C
+++ b/gcc/testsuite/g++.dg/concepts/pr71127.C
@@ -1,6 +1,7 @@
-// { dg-do compile { target c++14 } }
-// { dg-additional-options "-fconcepts" }
+// { dg-do compile { target c++17_only } }
+// { dg-options "-fconcepts" }
template<template<typename> class T>
concept bool C = T<int>::value;
-C c = 1; // { dg-error "invalid reference to concept" }
+
+C c = 1; // { dg-error "does not constrain a type" }
diff --git a/gcc/testsuite/g++.dg/concepts/pr71128.C b/gcc/testsuite/g++.dg/concepts/pr71128.C
index 8b4eb41f7ad..a150e37d78d 100644
--- a/gcc/testsuite/g++.dg/concepts/pr71128.C
+++ b/gcc/testsuite/g++.dg/concepts/pr71128.C
@@ -1,5 +1,5 @@
-// { dg-do compile { target c++14 } }
-// { dg-additional-options "-fconcepts" }
+// { dg-do compile { target c++17_only } }
+// { dg-options "-fconcepts" }
template<typename T>
concept bool C() { return true; }
diff --git a/gcc/testsuite/g++.dg/concepts/pr71131.C b/gcc/testsuite/g++.dg/concepts/pr71131.C
index 02f1999672d..675d66d9d75 100644
--- a/gcc/testsuite/g++.dg/concepts/pr71131.C
+++ b/gcc/testsuite/g++.dg/concepts/pr71131.C
@@ -1,6 +1,7 @@
-// { dg-do compile { target c++14 } }
-// { dg-additional-options "-fconcepts" }
+// { dg-do compile { target c++17_only } }
+// { dg-options "-fconcepts" }
template<template<typename> class T>
concept bool C = true;
-C c = 1; // { dg-error "invalid reference to concept" }
+
+C c = 1; // { dg-error "does not constrain a type" }
diff --git a/gcc/testsuite/g++.dg/concepts/pr71385.C b/gcc/testsuite/g++.dg/concepts/pr71385.C
index 42d21f57161..fb754253612 100644
--- a/gcc/testsuite/g++.dg/concepts/pr71385.C
+++ b/gcc/testsuite/g++.dg/concepts/pr71385.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template<class T>
diff --git a/gcc/testsuite/g++.dg/concepts/pr84330.C b/gcc/testsuite/g++.dg/concepts/pr84330.C
index 975ee8941db..0c2f45602d1 100644
--- a/gcc/testsuite/g++.dg/concepts/pr84330.C
+++ b/gcc/testsuite/g++.dg/concepts/pr84330.C
@@ -1,12 +1,15 @@
// PR c++/84330
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
struct A
{
- template<typename T> requires sizeof(T) >> 0 void foo(T); // { dg-error "predicate constraint" }
+ template<typename T>
+ requires (sizeof(T) >> 0)
+ void foo(T);
void bar()
{
- foo(0); // { dg-error "no matching" }
+ foo(0); // { dg-error "no matching function" }
}
};
diff --git a/gcc/testsuite/g++.dg/concepts/pr85065.C b/gcc/testsuite/g++.dg/concepts/pr85065.C
index 861a838dd29..52a42647948 100644
--- a/gcc/testsuite/g++.dg/concepts/pr85065.C
+++ b/gcc/testsuite/g++.dg/concepts/pr85065.C
@@ -1,6 +1,6 @@
-// { dg-do compile { target c++14 } }
-// { dg-additional-options "-fconcepts" }
+// { dg-do compile { target c++17_only } }
+// { dg-options "-fconcepts" }
template<int> concept bool C = true;
-C c = 0; // { dg-error "invalid reference to concept" }
+C c = 0; // { dg-error "does not constrain a type" }
diff --git a/gcc/testsuite/g++.dg/concepts/req-neg1.C b/gcc/testsuite/g++.dg/concepts/req-neg1.C
deleted file mode 100644
index 637f9932870..00000000000
--- a/gcc/testsuite/g++.dg/concepts/req-neg1.C
+++ /dev/null
@@ -1,11 +0,0 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-void f1(int a) requires true; // OK
-auto f2(int a) -> bool requires true; // OK
-auto f3(int a) requires true -> bool; // { dg-error "" } requires-clause precedes trailing-return-type
-typedef void fn_t() requires true; // { dg-error "typedef" }
-void (*pf)() requires true; // { dg-error "non-function" }
-void (*fn(int))() requires false; // { dg-error "return type" }
-void g(int (*)() requires true); // { dg-error "parameter|non-function" }
-auto* p = new (void(*)(char) requires true); // { dg-error "type-id" }
diff --git a/gcc/testsuite/g++.dg/concepts/req1.C b/gcc/testsuite/g++.dg/concepts/req1.C
deleted file mode 100644
index fedea73587c..00000000000
--- a/gcc/testsuite/g++.dg/concepts/req1.C
+++ /dev/null
@@ -1,29 +0,0 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-template<typename T>
- concept bool Class () { return __is_class(T); }
-
-// Allow a requires-expression with no parms.
-template<typename T>
- concept bool C = requires { typename T::type; };
-
-void f1(auto a) requires Class<decltype(a)>() { }
-void f2(auto a) requires requires (decltype(a) x) { -x; } { }
-
-struct S { } s;
-
-// Allow non-type template parms as constraints.
-template<bool B> requires B struct S0; // OK
-
-template<int N> requires N struct S1 { }; // { dg-error "does not have type" }
-template<int N> requires N == 0 struct S2 { }; // OK
-
-template<typename T, T X> requires X struct S3 { }; // OK
-S3<int, 0> s3a; // { dg-error "constraint failure|does not have type" }
-S3<bool, false> s3b; // { dg-error "constraint failure" }
-
-int main() {
- f1(s);
- f2(0);
-}
diff --git a/gcc/testsuite/g++.dg/concepts/req10.C b/gcc/testsuite/g++.dg/concepts/req10.C
deleted file mode 100644
index 949859ccce0..00000000000
--- a/gcc/testsuite/g++.dg/concepts/req10.C
+++ /dev/null
@@ -1,19 +0,0 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-// Test that standard conversions are checked with
-// implicit conversion constraints.
-
-template<typename T, typename U>
-concept bool C()
-{
- return requires(T& t) { {t} -> U&; };
-}
-
-struct B { };
-class D : B { };
-
-int main()
-{
- static_assert(C<D, B>(), ""); // { dg-error "failed" }
-}
diff --git a/gcc/testsuite/g++.dg/concepts/req11.C b/gcc/testsuite/g++.dg/concepts/req11.C
deleted file mode 100644
index 8891cce08a9..00000000000
--- a/gcc/testsuite/g++.dg/concepts/req11.C
+++ /dev/null
@@ -1,29 +0,0 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-// Check that we can evaluate constant requires-expressions
-// as constant expressions, for the curious case when they
-// appear within predicate constraints.
-
-template<typename... Ts> struct variant { };
-
-template<typename T>
-concept bool Streamable()
-{
- return requires (T t) { t; };
-}
-
-template<typename T>
-concept bool Range()
-{
- return requires (T t) { t; };
-}
-
-template<class T>
- requires Streamable<T>() and not Range<T>()
-void print(const T& x) { }
-
-int main()
-{
- print("hello"); // { dg-error "cannot call" }
-}
diff --git a/gcc/testsuite/g++.dg/concepts/req12.C b/gcc/testsuite/g++.dg/concepts/req12.C
deleted file mode 100644
index c6b345a08e9..00000000000
--- a/gcc/testsuite/g++.dg/concepts/req12.C
+++ /dev/null
@@ -1,26 +0,0 @@
-// PR c++/66218
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-#include <type_traits>
-
-template <class T, class U>
-concept bool Same =
- std::is_same<T, U>::value;
-
-template <class T>
-concept bool C =
- requires(T t) {
- { t } -> Same<T>;
- };
-
-template <class>
-constexpr bool f() { return false; }
-template <C>
-constexpr bool f() { return true; }
-
-static_assert(f<char>(), "");
-static_assert(f<int>(), "");
-static_assert(f<double>(), "");
-
-int main() {}
diff --git a/gcc/testsuite/g++.dg/concepts/req13.C b/gcc/testsuite/g++.dg/concepts/req13.C
deleted file mode 100644
index 4fd2312ef8c..00000000000
--- a/gcc/testsuite/g++.dg/concepts/req13.C
+++ /dev/null
@@ -1,14 +0,0 @@
-// PR c++/66758
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-template <class T, class...Args>
-concept bool Constructible =
- requires(Args&&...args) {
- T{ ((Args&&)(args))... };
- new T{((Args&&)(args))...};
- };
-
-template <Constructible T> struct A { };
-A<int> a;
-
diff --git a/gcc/testsuite/g++.dg/concepts/req16.C b/gcc/testsuite/g++.dg/concepts/req16.C
deleted file mode 100644
index ca04d60180c..00000000000
--- a/gcc/testsuite/g++.dg/concepts/req16.C
+++ /dev/null
@@ -1,20 +0,0 @@
-// PR c++/66988
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-#include <type_traits>
-
-template <template <class> class T, class U>
-concept bool _Valid = requires { typename T<U>; };
-
-template <class T>
-using __t = typename T::type;
-
-template <class T>
-struct __has_type : std::false_type { };
-
-template <class T>
- requires _Valid<__t, T>
-struct __has_type<T> : std::true_type { };
-
-static_assert(!__has_type<int>(), "");
diff --git a/gcc/testsuite/g++.dg/concepts/req18.C b/gcc/testsuite/g++.dg/concepts/req18.C
deleted file mode 100644
index cccfaed7bb6..00000000000
--- a/gcc/testsuite/g++.dg/concepts/req18.C
+++ /dev/null
@@ -1,18 +0,0 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-template <class> struct all_same {
- static constexpr bool value = 1;
-};
-template <class T> concept bool Assignable
-= requires(T t)
-{
- requires all_same<decltype(t = 0)>::value;
-};
-
-template <class I> requires !Assignable<I>
-int dispatch();
-template <Assignable>
-void dispatch();
-
-int main() { dispatch<int *>(); }
diff --git a/gcc/testsuite/g++.dg/concepts/req19.C b/gcc/testsuite/g++.dg/concepts/req19.C
deleted file mode 100644
index 97cd9e52fe2..00000000000
--- a/gcc/testsuite/g++.dg/concepts/req19.C
+++ /dev/null
@@ -1,14 +0,0 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-struct B
-{
- template <class T> void f(T t)
- requires requires (T tt) { tt; }
- { }
-};
-
-int main()
-{
- B().f(42);
-}
diff --git a/gcc/testsuite/g++.dg/concepts/req2.C b/gcc/testsuite/g++.dg/concepts/req2.C
deleted file mode 100644
index b32845a96c9..00000000000
--- a/gcc/testsuite/g++.dg/concepts/req2.C
+++ /dev/null
@@ -1,20 +0,0 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-template<typename T>
- concept bool Class () { return __is_class(T); }
-
-void f1(auto a) requires Class<decltype(a)>() { }
-
-// FIXME: This is generating excess errors related to pretty
-// printing the trailing requires expression.
-void f2(auto a)
- requires requires (decltype(a) x) { -x; }
-{ }
-
-struct S { } s;
-
-int main() {
- f1(0); // { dg-error "cannot call" }
- f2((void*)0); // { dg-error "cannot call" }
-}
diff --git a/gcc/testsuite/g++.dg/concepts/req20.C b/gcc/testsuite/g++.dg/concepts/req20.C
deleted file mode 100644
index bd6b0f98390..00000000000
--- a/gcc/testsuite/g++.dg/concepts/req20.C
+++ /dev/null
@@ -1,21 +0,0 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-template <class T> concept bool C = true;
-
-template <class T>
-requires C<typename T::foo>
-void f(T t) { }
-
-void f(...);
-
-template <class T>
-requires C<T>
-void g(T t) { }
-
-int main()
-{
- f(42);
- g(42);
-}
-
diff --git a/gcc/testsuite/g++.dg/concepts/req3.C b/gcc/testsuite/g++.dg/concepts/req3.C
deleted file mode 100644
index 8ce58e56ebf..00000000000
--- a/gcc/testsuite/g++.dg/concepts/req3.C
+++ /dev/null
@@ -1,17 +0,0 @@
-// { dg-do run { target c++17 } }
-// { dg-options "-fconcepts" }
-
-template<typename T>
- concept bool Class () { return __is_class(T); }
-
-struct Test {
- void f(auto a) requires Class<decltype(a)>();
-} test;
-
-struct S { }s;
-
-int main() {
- test.f(s);
-}
-
-void Test::f(auto a) requires Class<decltype(a)>() { }
diff --git a/gcc/testsuite/g++.dg/concepts/req4.C b/gcc/testsuite/g++.dg/concepts/req4.C
deleted file mode 100644
index fcc13c6dcea..00000000000
--- a/gcc/testsuite/g++.dg/concepts/req4.C
+++ /dev/null
@@ -1,19 +0,0 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-struct fool {
- constexpr fool operator&&(fool) const { return {}; }
- constexpr fool operator||(fool) const { return {}; }
-};
-
-template<typename T> constexpr fool p1() { return {}; }
-template<typename T> constexpr fool p2() { return {}; }
-
-template<typename T>
- concept bool C() { return p1<T>() && p2<T>(); }
-
-template<C T> void f(T x) { }
-
-int main() {
- f(0); // { dg-error "cannot call|uses overloaded operator" }
-}
diff --git a/gcc/testsuite/g++.dg/concepts/req5.C b/gcc/testsuite/g++.dg/concepts/req5.C
deleted file mode 100644
index 7ad1cab9e93..00000000000
--- a/gcc/testsuite/g++.dg/concepts/req5.C
+++ /dev/null
@@ -1,19 +0,0 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-struct fool { };
-
-constexpr fool operator&&(fool, fool) { return {}; }
-constexpr fool operator||(fool, fool) { return {}; }
-
-template<typename T> constexpr fool p1() { return {}; }
-template<typename T> constexpr fool p2() { return {}; }
-
-template<typename T>
- concept bool C() { return p1<T>() && p2<T>(); }
-
-template<C T> void f(T x) { }
-
-int main() {
- f(0); // { dg-error "cannot call|uses overloaded operator" }
-}
diff --git a/gcc/testsuite/g++.dg/concepts/req6.C b/gcc/testsuite/g++.dg/concepts/req6.C
deleted file mode 100644
index dd7dbdd9239..00000000000
--- a/gcc/testsuite/g++.dg/concepts/req6.C
+++ /dev/null
@@ -1,19 +0,0 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-struct X { };
-int operator==(X, X) { return 0; }
-
-template<typename T>
- concept bool C1() { return X(); } // { dg-error "bool" }
-
-template<C1 T>
- void h(T) { } // OK until used.
-
-void f()
-{
- h(0); // { dg-error "does not have|cannot call" }
-}
-
-template<typename T>
- concept bool C2() { return X() == X(); } // OK
diff --git a/gcc/testsuite/g++.dg/concepts/req7.C b/gcc/testsuite/g++.dg/concepts/req7.C
deleted file mode 100644
index a6cfb4bf56d..00000000000
--- a/gcc/testsuite/g++.dg/concepts/req7.C
+++ /dev/null
@@ -1,25 +0,0 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-#include <vector>
-
-using namespace std;
-
-template<typename T>
- struct Sequence : std::false_type { };
-
-template<typename T>
- struct Predicate : std::false_type { };
-
-template<typename Seq, typename Fn>
- requires Sequence<Seq>{} and Predicate<Fn>{}
- bool all(const Seq& seq, Fn fn) {
- for(const auto& x : seq)
- if (not fn(x))
- return false;
- return true;
- }
-
-int main() {
- all(vector<int>{0, 2}, true); // { dg-error "not|bool" }
-}
diff --git a/gcc/testsuite/g++.dg/concepts/req8.C b/gcc/testsuite/g++.dg/concepts/req8.C
deleted file mode 100644
index 201be37e9c7..00000000000
--- a/gcc/testsuite/g++.dg/concepts/req8.C
+++ /dev/null
@@ -1,17 +0,0 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-// Check that type requirements are normalized correctly.
-
-template<typename T>
- concept bool Has_member_type() {
- return requires() { typename T::type; };
- }
-
-template<typename T>
- concept bool Concept() {
- return true && Has_member_type<T>();
- }
-
-template<Concept T>
- void foo( T t ) { }
diff --git a/gcc/testsuite/g++.dg/concepts/req9.C b/gcc/testsuite/g++.dg/concepts/req9.C
deleted file mode 100644
index 497154cd11f..00000000000
--- a/gcc/testsuite/g++.dg/concepts/req9.C
+++ /dev/null
@@ -1,25 +0,0 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-template<typename T>
-struct S1 {};
-
-template<typename T>
-concept bool C() { return requires(T x) { { x.fn() } -> S1<T>; }; }
-
-template<C U>
-void fn(U x)
-{
- x.fn();
-}
-
-struct S2
-{
- auto fn() const { return S1<S2>(); }
-};
-
-int main()
-{
- fn(S2{});
- return 0;
-}
diff --git a/gcc/testsuite/g++.dg/concepts/template-parm1.C b/gcc/testsuite/g++.dg/concepts/template-parm1.C
deleted file mode 100644
index 192226f6ae2..00000000000
--- a/gcc/testsuite/g++.dg/concepts/template-parm1.C
+++ /dev/null
@@ -1,35 +0,0 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-template<typename T>
- concept bool C1 = __is_same_as(T, int);
-
-template<int N>
- concept bool C2 = N == 0;
-
-template<template<typename> class X>
- concept bool C3 = true;
-
-template<typename> struct Foo;
-
-// Type template parameters
-template<C1 T = int> struct S1 { };
-template<C1 = int> struct S2;
-template<C1 T> struct S2 { };
-
-// Non-type template parameters
-template<C2 N = 0> struct S3 { };
-template<C2 = 0> struct S4;
-template<C2 N> struct S4 { };
-
-// Template template parameters
-template<C3 X = Foo> struct S5 { };
-template<C3 = Foo> struct S6;
-template<C3 X> struct S6 { };
-
-S1<> s1;
-S2<> s2;
-S3<> s3;
-S4<> s4;
-S5<> s5;
-S6<> s6;
diff --git a/gcc/testsuite/g++.dg/concepts/template-parm10.C b/gcc/testsuite/g++.dg/concepts/template-parm10.C
deleted file mode 100644
index 33bf372d646..00000000000
--- a/gcc/testsuite/g++.dg/concepts/template-parm10.C
+++ /dev/null
@@ -1,18 +0,0 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-template<int N, class T>
- concept bool P() { return true; }
-
-template<template<typename> class X, class T>
- concept bool Q() { return true; }
-
-template<P<int> N> void f() { }
-template<Q<int> X> void g() { }
-
-template<typename> struct S { };
-
-int main() {
- f<0>();
- g<S>();
-}
diff --git a/gcc/testsuite/g++.dg/concepts/template-parm11.C b/gcc/testsuite/g++.dg/concepts/template-parm11.C
index 04e11e2e697..07ad6e284e9 100644
--- a/gcc/testsuite/g++.dg/concepts/template-parm11.C
+++ b/gcc/testsuite/g++.dg/concepts/template-parm11.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template<typename T>
diff --git a/gcc/testsuite/g++.dg/concepts/template-parm12.C b/gcc/testsuite/g++.dg/concepts/template-parm12.C
index 8745bb1d921..cb3e2c6b55a 100644
--- a/gcc/testsuite/g++.dg/concepts/template-parm12.C
+++ b/gcc/testsuite/g++.dg/concepts/template-parm12.C
@@ -1,6 +1,6 @@
-// Conceptized version of template/ttp23.C
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
+// Conceptized version of template/ttp23.C
template <class T> concept bool Foo = true;
diff --git a/gcc/testsuite/g++.dg/concepts/template-parm2.C b/gcc/testsuite/g++.dg/concepts/template-parm2.C
index adecc12f0f9..d708fd06f01 100644
--- a/gcc/testsuite/g++.dg/concepts/template-parm2.C
+++ b/gcc/testsuite/g++.dg/concepts/template-parm2.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template<typename T>
diff --git a/gcc/testsuite/g++.dg/concepts/template-parm3.C b/gcc/testsuite/g++.dg/concepts/template-parm3.C
index 3d37e9c4c25..028149c13dc 100644
--- a/gcc/testsuite/g++.dg/concepts/template-parm3.C
+++ b/gcc/testsuite/g++.dg/concepts/template-parm3.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template<typename T>
diff --git a/gcc/testsuite/g++.dg/concepts/template-parm4.C b/gcc/testsuite/g++.dg/concepts/template-parm4.C
index f546a758c06..d93dbc7f2dc 100644
--- a/gcc/testsuite/g++.dg/concepts/template-parm4.C
+++ b/gcc/testsuite/g++.dg/concepts/template-parm4.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template<typename T>
diff --git a/gcc/testsuite/g++.dg/concepts/template-parm5.C b/gcc/testsuite/g++.dg/concepts/template-parm5.C
deleted file mode 100644
index cd93c60778a..00000000000
--- a/gcc/testsuite/g++.dg/concepts/template-parm5.C
+++ /dev/null
@@ -1,20 +0,0 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-template<typename T>
- concept bool C1 = __is_same_as(T, int);
-
-template<int N>
- concept bool C2 = N == 0;
-
-template<template<typename> class X>
- concept bool C3 = true;
-
-template<typename> struct Foo;
-
-template<C1... Ts = int> struct S1; // { dg-error "default argument" }
-template<C1... = int> struct S2; // { dg-error "default argument" }
-template<C2... Ns = 0> struct S3; // { dg-error "default argument" }
-template<C2... = 0> struct S4; // { dg-error "default argument" }
-template<C3... Ts = Foo> struct S5; // { dg-error "default argument" }
-template<C3... = Foo> struct S6; // { dg-error "default argument" }
diff --git a/gcc/testsuite/g++.dg/concepts/template-parm6.C b/gcc/testsuite/g++.dg/concepts/template-parm6.C
deleted file mode 100644
index 9efe4094f21..00000000000
--- a/gcc/testsuite/g++.dg/concepts/template-parm6.C
+++ /dev/null
@@ -1,42 +0,0 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-template<typename... Ts> struct are_same;
-
-template<>
- struct are_same<> {
- static constexpr bool value = true;
- };
-
-template<typename T>
- struct are_same<T> {
- static constexpr bool value = true;
- };
-
-template<typename T, typename U, typename... Ts>
- struct are_same<T, U, Ts...> {
- static constexpr bool value =
- __is_same_as(T, U) && are_same<U, Ts...>::value;
- };
-
-constexpr bool all_of() { return true; }
-constexpr bool all_of(bool b) { return b; }
-
-template<typename... Ts>
- constexpr bool all_of(bool a, bool b, Ts... args) {
- return (a && b) && all_of(b, args...);
- }
-
-template<typename... Ts>
- concept bool C1 = are_same<Ts...>::value;
-
-template<bool... Bs>
- concept bool C2 = all_of(Bs...);
-
-template<C1... Ts> struct S1 { };
-template<C1...> struct S2 { };
-template<C2... Bs> struct S4 { };
-template<C2...> struct S5 { };
-
-S1<int, int, int> s1;
-S4<true, true, true> s4;
diff --git a/gcc/testsuite/g++.dg/concepts/template-parm7.C b/gcc/testsuite/g++.dg/concepts/template-parm7.C
deleted file mode 100644
index 1dfa0d16ee5..00000000000
--- a/gcc/testsuite/g++.dg/concepts/template-parm7.C
+++ /dev/null
@@ -1,45 +0,0 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-template<typename... Ts> struct are_same;
-
-template<>
- struct are_same<> {
- static constexpr bool value = true;
- };
-
-template<typename T>
- struct are_same<T> {
- static constexpr bool value = true;
- };
-
-template<typename T, typename U, typename... Ts>
- struct are_same<T, U, Ts...> {
- static constexpr bool value =
- __is_same_as(T, U) && are_same<U, Ts...>::value;
- };
-
-constexpr bool all_of() { return true; }
-constexpr bool all_of(bool b) { return b; }
-
-template<typename... Ts>
- constexpr bool all_of(bool a, bool b, Ts... args) {
- return (a && b) && all_of(b, args...);
- }
-
-
-template<typename... Ts>
- concept bool C1 = are_same<Ts...>::value;
-
-template<bool... Bs>
- concept bool C2 = all_of(Bs...);
-
-template<C1... Ts> struct S1 { }; // OK
-S1<int, int, char> s1; // { dg-error "constraint failure|invalid type" }
-template<C1 Ts> struct S2 { }; // { dg-error "variadic constraint" }
-
-template<C2... Bs> struct S3 { }; // OK
-S3<true, true, false> s3; // { dg-error "constraint failure|invalid type" }
-template<C2 Bs> struct S4 { }; // { dg-error "variadic constraint" }
-
-int main() { }
diff --git a/gcc/testsuite/g++.dg/concepts/template-parm9.C b/gcc/testsuite/g++.dg/concepts/template-parm9.C
deleted file mode 100644
index 64308cdd6e6..00000000000
--- a/gcc/testsuite/g++.dg/concepts/template-parm9.C
+++ /dev/null
@@ -1,19 +0,0 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
-template<typename T>
- concept bool C() { return __is_class(T); }
-
-template<typename T>
- concept bool D() { return C<T>() and __is_empty(T); }
-
-template<template<typename Q> requires C<Q>() class X>
- struct S { };
-
-template<typename A> requires true struct T0 { };
-template<typename A> requires D<A>() struct T1 { };
-
-S<T0> x3; // { dg-error "constraint mismatch|invalid type" }
-S<T1> x4; // { dg-error "constraint mismatch|invalid type" }
-
-int main() { }
diff --git a/gcc/testsuite/g++.dg/concepts/template-template-parm1.C b/gcc/testsuite/g++.dg/concepts/template-template-parm1.C
index 6c4dc2cec31..d701859d127 100644
--- a/gcc/testsuite/g++.dg/concepts/template-template-parm1.C
+++ b/gcc/testsuite/g++.dg/concepts/template-template-parm1.C
@@ -1,5 +1,5 @@
// PR c++/66937
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
#include <tuple>
diff --git a/gcc/testsuite/g++.dg/concepts/var-concept1.C b/gcc/testsuite/g++.dg/concepts/var-concept1.C
index 90a88d83cc9..21a4915551b 100644
--- a/gcc/testsuite/g++.dg/concepts/var-concept1.C
+++ b/gcc/testsuite/g++.dg/concepts/var-concept1.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template<typename T>
diff --git a/gcc/testsuite/g++.dg/concepts/var-concept2.C b/gcc/testsuite/g++.dg/concepts/var-concept2.C
index c16d3e4a57e..4ff00a008b9 100644
--- a/gcc/testsuite/g++.dg/concepts/var-concept2.C
+++ b/gcc/testsuite/g++.dg/concepts/var-concept2.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template<typename T>
diff --git a/gcc/testsuite/g++.dg/concepts/var-concept3.C b/gcc/testsuite/g++.dg/concepts/var-concept3.C
index f3d642b1a53..144c0ea1a24 100644
--- a/gcc/testsuite/g++.dg/concepts/var-concept3.C
+++ b/gcc/testsuite/g++.dg/concepts/var-concept3.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template<typename T>
@@ -12,12 +12,19 @@ template<typename T>
template<typename U>
- requires C1<U>() // { dg-error "" }
+ requires C1<U>() // { dg-error "cannot be used as a function" }
void f1(U) { }
template<typename U>
- requires C2<U> // { dg-error "invalid reference" }
+ requires C2<U> // { dg-error "must be called" }
void f2(U) { }
template<C3 T> // { dg-error "not a type" }
- void f(T) { } // { dg-error "" }
+ void f(T) { } // { dg-error "declared void|not declared" }
+
+void foo()
+{
+ struct S { } s;
+ f2(s);
+ // f2(0);
+}
diff --git a/gcc/testsuite/g++.dg/concepts/var-concept4.C b/gcc/testsuite/g++.dg/concepts/var-concept4.C
index 3864c9db99c..a7839ee5f85 100644
--- a/gcc/testsuite/g++.dg/concepts/var-concept4.C
+++ b/gcc/testsuite/g++.dg/concepts/var-concept4.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template<typename T, typename U>
diff --git a/gcc/testsuite/g++.dg/concepts/var-concept5.C b/gcc/testsuite/g++.dg/concepts/var-concept5.C
index b1e9cb5379c..d8fa2984f15 100644
--- a/gcc/testsuite/g++.dg/concepts/var-concept5.C
+++ b/gcc/testsuite/g++.dg/concepts/var-concept5.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template<typename T1, typename T2>
@@ -8,8 +8,8 @@ template<typename T1, typename T2, typename T3>
concept bool C2 = true;
-template<C1 T> // { dg-error "not a type" }
+template<C1 T> // { dg-error "wrong number of template arguments" }
constexpr bool f1( ) { return true; }
-template<C2<int> T> // { dg-error "expected|not a type" }
+template<C2<int> T> // { dg-error "wrong number of template arguments" }
constexpr bool f2( ) { return true; }
diff --git a/gcc/testsuite/g++.dg/concepts/var-concept6.C b/gcc/testsuite/g++.dg/concepts/var-concept6.C
index 8f5ac629538..80984a7ab1e 100644
--- a/gcc/testsuite/g++.dg/concepts/var-concept6.C
+++ b/gcc/testsuite/g++.dg/concepts/var-concept6.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template <class T>
diff --git a/gcc/testsuite/g++.dg/concepts/var-concept7.C b/gcc/testsuite/g++.dg/concepts/var-concept7.C
index 8371b373f64..2cfe2666e16 100644
--- a/gcc/testsuite/g++.dg/concepts/var-concept7.C
+++ b/gcc/testsuite/g++.dg/concepts/var-concept7.C
@@ -1,6 +1,6 @@
// PR c++/85133
-// { dg-do compile { target c++17 } }
-// { dg-additional-options "-fconcepts" }
+// { dg-do compile { target c++17_only } }
+// { dg-options "-fconcepts" }
template<typename> concept bool C; // { dg-error "no initializer" }
diff --git a/gcc/testsuite/g++.dg/concepts/var-templ1.C b/gcc/testsuite/g++.dg/concepts/var-templ1.C
index b69d7d8d6a2..4ac578f88bc 100644
--- a/gcc/testsuite/g++.dg/concepts/var-templ1.C
+++ b/gcc/testsuite/g++.dg/concepts/var-templ1.C
@@ -1,5 +1,5 @@
// PR c++/67117
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template <class T>
diff --git a/gcc/testsuite/g++.dg/concepts/var-templ2.C b/gcc/testsuite/g++.dg/concepts/var-templ2.C
index ffe5f1ffe05..1b8890a789b 100644
--- a/gcc/testsuite/g++.dg/concepts/var-templ2.C
+++ b/gcc/testsuite/g++.dg/concepts/var-templ2.C
@@ -1,5 +1,5 @@
// PR c++/67139
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template <class T>
diff --git a/gcc/testsuite/g++.dg/concepts/var-templ3.C b/gcc/testsuite/g++.dg/concepts/var-templ3.C
index 22f07eef827..cc5ee5fa8e6 100644
--- a/gcc/testsuite/g++.dg/concepts/var-templ3.C
+++ b/gcc/testsuite/g++.dg/concepts/var-templ3.C
@@ -1,5 +1,5 @@
// PR c++/68666
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
struct A {
diff --git a/gcc/testsuite/g++.dg/concepts/variadic1.C b/gcc/testsuite/g++.dg/concepts/variadic1.C
index 4c0f437c32c..c3bc7f61513 100644
--- a/gcc/testsuite/g++.dg/concepts/variadic1.C
+++ b/gcc/testsuite/g++.dg/concepts/variadic1.C
@@ -1,5 +1,5 @@
// PR c++/66712
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template <class T, class...Args>
diff --git a/gcc/testsuite/g++.dg/concepts/variadic2.C b/gcc/testsuite/g++.dg/concepts/variadic2.C
index 4675d97ca18..7b220097f98 100644
--- a/gcc/testsuite/g++.dg/concepts/variadic2.C
+++ b/gcc/testsuite/g++.dg/concepts/variadic2.C
@@ -1,17 +1,18 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template <class T> concept bool Copyable = requires (T t) { T(t); };
template <class T> concept bool Constructable = requires { T(); };
template <class T> concept bool Both = Copyable<T> && Constructable<T>;
-template <Copyable... Ts>
+template <Copyable... Ts> // requires (Copyable<Ts> && ...)
constexpr int f(Ts...) { return 0; } // #1
-template <Both... Ts>
+template <Both... Ts> // requires (Both<Ts> && ...)
constexpr int f(Ts...) { return 1; } // #2
int main()
{
- static_assert(f(42) == 1);
+ static_assert(f(42) == 1); // { dg-error "ambiguous" }
+ // The associated constraints of the two functions are incomparable.
}
diff --git a/gcc/testsuite/g++.dg/concepts/variadic3.C b/gcc/testsuite/g++.dg/concepts/variadic3.C
index f980e991775..bd2f381a1a8 100644
--- a/gcc/testsuite/g++.dg/concepts/variadic3.C
+++ b/gcc/testsuite/g++.dg/concepts/variadic3.C
@@ -1,5 +1,5 @@
// PR c++/70036
-// { dg-do compile { target c++14 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template <class T> concept bool C = true;
diff --git a/gcc/testsuite/g++.dg/concepts/variadic4.C b/gcc/testsuite/g++.dg/concepts/variadic4.C
index e0f7903cac5..d6eea49b958 100644
--- a/gcc/testsuite/g++.dg/concepts/variadic4.C
+++ b/gcc/testsuite/g++.dg/concepts/variadic4.C
@@ -1,5 +1,5 @@
// PR c++/73456
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
template<typename...> struct list {};
@@ -7,13 +7,14 @@ template<typename...> struct list {};
template<typename Seq>
concept bool Sequence = true;
-template<Sequence... Seqs>
+template<Sequence... Seqs> // requires (Sequence<Seqs> && ...)
struct zip;
template<Sequence... Seqs>
- requires requires { typename list<Seqs...>; }
-// main.cpp:12:8: internal compiler error: in non_atomic_constraint_p, at cp/logic.cc:315
-struct zip<Seqs...> {};
+ requires requires { typename list<Seqs...>; } // && (Sequence<Seqs> && ...)
+struct zip<Seqs...> {}; // { dg-error "does not specialize" }
+// The constraints of the specialization and the sequence are not
+// comparable; the specializations are unordered.
int main()
{
diff --git a/gcc/testsuite/g++.dg/conversion/qual1.C b/gcc/testsuite/g++.dg/conversion/qual1.C
new file mode 100644
index 00000000000..5022da9da47
--- /dev/null
+++ b/gcc/testsuite/g++.dg/conversion/qual1.C
@@ -0,0 +1,51 @@
+// PR c++/88128 - Implement DR 330: Qualification conversions and pointers to
+// arrays of pointers.
+
+int *a[4];
+const int *const(*ap1)[4] = &a;
+/* if at some level k the P2 is more cv-qualified than P1, then there
+ must be a const at every single level (other than level zero) of P2
+ up until k. */
+const int *(*ap2)[4] = &a; // { dg-error "cannot convert" }
+int *const(*ap3)[4] = &a;
+int *(*ap4)[4] = &a;
+int *(*const ap5)[4] = &a;
+const int *const(*const ap6)[4] = &a;
+int *const(*const ap7)[4] = &a;
+int *(*const ap8)[4] = &a;
+
+const int *b[4];
+const int *const(*bp1)[4] = &b;
+const int *(*bp2)[4] = &b;
+int *const(*bp3)[4] = &b; // { dg-error "cannot convert" }
+int *(*bp4)[4] = &b; // { dg-error "cannot convert" }
+int *(*const bp5)[4] = &b; // { dg-error "cannot convert" }
+const int *const(*const bp6)[4] = &b;
+int *const(*const bp7)[4] = &b; // { dg-error "cannot convert" }
+int *(*const bp8)[4] = &b; // { dg-error "cannot convert" }
+
+int *c[2][3];
+int const *const (*cp1)[3] = c;
+int const *(*cp2)[3] = c; // { dg-error "cannot convert" }
+int const *const (*const cp3)[3] = c;
+int *const (*cp4)[3] = c;
+int *(*cp5)[3] = c;
+
+double *const (*d)[3];
+double const *const (*e)[3] = d;
+int *(*f)[3];
+const int *const (*g)[3] = f;
+
+// From PR88128.
+int* (*xx)[];
+const int* const(*yy)[] = xx;
+
+// From DR 330.
+int main()
+{
+ double *array2D[2][3];
+
+ double * (*array2DPtr1)[3] = array2D;
+ double * const (*array2DPtr2)[3] = array2DPtr1;
+ double const * const (*array2DPtr3)[3] = array2DPtr2;
+}
diff --git a/gcc/testsuite/g++.dg/conversion/qual2.C b/gcc/testsuite/g++.dg/conversion/qual2.C
new file mode 100644
index 00000000000..8a063a03e79
--- /dev/null
+++ b/gcc/testsuite/g++.dg/conversion/qual2.C
@@ -0,0 +1,14 @@
+// PR c++/88128 - DR 330: Qual convs and pointers to arrays of pointers.
+
+// Make sure we don't accept different bounds.
+
+int *a[4];
+const int *const(*ap1)[5] = &a; // { dg-error "cannot convert" }
+
+int *(*b)[3];
+const int *const (*bp1)[3] = &b; // { dg-error "cannot convert" }
+const int *const (*bp2)[4] = &b; // { dg-error "cannot convert" }
+int *(*bp3)[4] = &b; // { dg-error "cannot convert" }
+
+int *c[2][3];
+int const *const (*cp1)[4] = c; // { dg-error "cannot convert" }
diff --git a/gcc/testsuite/g++.dg/conversion/qual3.C b/gcc/testsuite/g++.dg/conversion/qual3.C
new file mode 100644
index 00000000000..4b466d9ea5d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/conversion/qual3.C
@@ -0,0 +1,53 @@
+// PR c++/88128 - DR 330: Qual convs and pointers to arrays of pointers.
+// { dg-do compile { target c++17 } }
+
+using P = int *(*)[3];
+using Q = const int *const (*)[3];
+using Qi = const int *[3];
+using Q2 = Qi const *;
+using R = const int *const (*)[4];
+using S = const int *const (*)[];
+using T = const int *(*)[];
+
+void
+f (P p, Q q, Q2 q2, R r, S s, T t)
+{
+ q = p;
+ q2 = p;
+ r = p; // { dg-error "cannot convert" }
+ t = p; // { dg-error "cannot convert" }
+ s = t;
+ t = s; // { dg-error "invalid conversion" }
+
+ // Test const_cast.
+ const_cast<P>(q);
+ const_cast<P>(q2);
+ const_cast<Q>(p);
+ const_cast<Q2>(p);
+ const_cast<S>(p); // { dg-error "invalid .const_cast." }
+ const_cast<P>(s); // { dg-error "invalid .const_cast." }
+ const_cast<S>(q); // { dg-error "invalid .const_cast." }
+ const_cast<S>(q2); // { dg-error "invalid .const_cast." }
+ const_cast<Q>(s); // { dg-error "invalid .const_cast." }
+ const_cast<Q2>(s); // { dg-error "invalid .const_cast." }
+ const_cast<T>(s);
+ const_cast<S>(t);
+ const_cast<T>(q); // { dg-error "invalid .const_cast." }
+ const_cast<Q>(t); // { dg-error "invalid .const_cast." }
+
+ // Test reinterpret_cast.
+ reinterpret_cast<P>(q); // { dg-error "casts away qualifiers" }
+ reinterpret_cast<P>(q2); // { dg-error "casts away qualifiers" }
+ reinterpret_cast<Q>(p);
+ reinterpret_cast<Q2>(p);
+ reinterpret_cast<S>(p);
+ reinterpret_cast<P>(s); // { dg-error "casts away qualifiers" }
+ reinterpret_cast<S>(q);
+ reinterpret_cast<S>(q2);
+ reinterpret_cast<Q>(s);
+ reinterpret_cast<Q2>(s);
+ reinterpret_cast<T>(s); // { dg-error "casts away qualifiers" }
+ reinterpret_cast<S>(t);
+ reinterpret_cast<T>(q); // { dg-error "casts away qualifiers" }
+ reinterpret_cast<Q>(t);
+}
diff --git a/gcc/testsuite/g++.dg/conversion/ref2.C b/gcc/testsuite/g++.dg/conversion/ref2.C
new file mode 100644
index 00000000000..418e711946f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/conversion/ref2.C
@@ -0,0 +1,29 @@
+// PR c++/88128 - Implement DR 330: Qualification conversions and pointers to
+// arrays of pointers.
+
+int *ar[4];
+/* if at some level k the P2 is more cv-qualified than P1, then there
+ must be a const at every single level (other than level zero) of P2
+ up until k. */
+const int *(&arp)[4] = ar; // { dg-error "discards qualifiers" }
+const int *const(&arp2)[4] = ar;
+int *const(&arp3)[4] = ar;
+int *(&arp4)[4] = ar;
+
+const int *br[4];
+const int *(&brp)[4] = br;
+const int *const(&brp2)[4] = br;
+int *const(&brp3)[4] = br; // { dg-error "discards qualifiers" }
+int *(&brp4)[4] = br; // { dg-error "discards qualifiers" }
+
+int *c[2][3];
+int const *const (&cp1)[3] = *c;
+int const *(&cp2)[3] = *c; // { dg-error "discards qualifiers" }
+int *const (&cp3)[3] = *c;
+int *(&cp4)[3] = *c;
+
+double *const (*d)[3];
+double const *const (&e)[3] = *d;
+
+int *(*f)[3];
+const int *const (&g)[3] = *f;
diff --git a/gcc/testsuite/g++.dg/conversion/ref3.C b/gcc/testsuite/g++.dg/conversion/ref3.C
new file mode 100644
index 00000000000..ca5326ce8e8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/conversion/ref3.C
@@ -0,0 +1,4 @@
+int a[2];
+const int (&rc)[2] = a;
+volatile int (&rv)[2] = a;
+const volatile int (&rcv)[2] = a;
diff --git a/gcc/testsuite/g++.dg/cpp0x/auto52.C b/gcc/testsuite/g++.dg/cpp0x/auto52.C
index d33f927a63e..c277d33d002 100644
--- a/gcc/testsuite/g++.dg/cpp0x/auto52.C
+++ b/gcc/testsuite/g++.dg/cpp0x/auto52.C
@@ -3,4 +3,4 @@
using T = auto() -> int;
using U = void() -> int; // { dg-error "11:.type name. function with trailing return type not declared with .auto." }
-using W = auto(); // { dg-error "11:invalid use of .auto." }
+using W = auto(); // { dg-error "11:.*auto." }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr10.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr10.C
index 2ff7c4d3920..b1d47cf2cbd 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr10.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr10.C
@@ -19,18 +19,18 @@ constexpr int *p0 = &i;
constexpr bool b0 = p0; // { dg-warning "address of .A::i." }
constexpr bool b1 = p0 == 0; // { dg-warning "address of .A::i." }
constexpr bool b2 = p0 != 0; // { dg-warning "address of .A::i." }
-constexpr bool b3 = p0 < 0; // { dg-warning "ordered comparison" }
-constexpr bool b4 = p0 <= 0; // { dg-warning "ordered comparison" }
-constexpr bool b5 = p0 > 0; // { dg-warning "ordered comparison" }
-constexpr bool b6 = p0 >= 0; // { dg-warning "ordered comparison" }
+constexpr bool b3 = p0 < 0; // { dg-warning "25:ordered comparison" }
+constexpr bool b4 = p0 <= 0; // { dg-warning "25:ordered comparison" }
+constexpr bool b5 = p0 > 0; // { dg-warning "25:ordered comparison" }
+constexpr bool b6 = p0 >= 0; // { dg-warning "25:ordered comparison" }
constexpr bool b7 = !p0; // { dg-warning "address of .A::i." }
constexpr bool b8 = 0 == p0; // { dg-warning "address of .A::i." }
constexpr bool b9 = 0 != p0; // { dg-warning "address of .A::i." }
-constexpr bool b10 = 0 < p0; // { dg-warning "ordered comparison" }
-constexpr bool b11 = 0 <= p0; // { dg-warning "ordered comparison" }
-constexpr bool b12 = 0 > p0; // { dg-warning "ordered comparison" }
-constexpr bool b13 = 0 >= p0; // { dg-warning "ordered comparison" }
+constexpr bool b10 = 0 < p0; // { dg-warning "24:ordered comparison" }
+constexpr bool b11 = 0 <= p0; // { dg-warning "24:ordered comparison" }
+constexpr bool b12 = 0 > p0; // { dg-warning "24:ordered comparison" }
+constexpr bool b13 = 0 >= p0; // { dg-warning "24:ordered comparison" }
}
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-arrray1.C b/gcc/testsuite/g++.dg/cpp0x/initlist-array1.C
index 925ab16bead..925ab16bead 100644
--- a/gcc/testsuite/g++.dg/cpp0x/initlist-arrray1.C
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist-array1.C
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-array3.C b/gcc/testsuite/g++.dg/cpp0x/initlist-array3.C
index 1a94f4ed55b..4140cd92d7b 100644
--- a/gcc/testsuite/g++.dg/cpp0x/initlist-array3.C
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist-array3.C
@@ -6,5 +6,6 @@ void composite (int const (&) [3]);
int main ()
{
- composite({0,1}); // { dg-error "ambiguous" }
+ // Not ambiguous since CWG 1307.
+ composite({0,1});
}
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-array7.C b/gcc/testsuite/g++.dg/cpp0x/initlist-array7.C
new file mode 100644
index 00000000000..7a689c6675f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist-array7.C
@@ -0,0 +1,21 @@
+// PR c++/69531 - DR 1307, Overload resolution based on size of array init-list.
+// { dg-do run { target c++11 } }
+
+int f(int const(&)[2]) { return 1; }
+int f(int const(&)[3]) { return 2; }
+
+int
+main ()
+{
+ if (f({}) != 1)
+ __builtin_abort ();
+
+ if (f({1}) != 1)
+ __builtin_abort ();
+
+ if (f({1, 2}) != 1)
+ __builtin_abort ();
+
+ if (f({1, 2, 3}) != 2)
+ __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-array8.C b/gcc/testsuite/g++.dg/cpp0x/initlist-array8.C
new file mode 100644
index 00000000000..ac2774e06b4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist-array8.C
@@ -0,0 +1,35 @@
+// PR c++/69531 - DR 1307, Overload resolution based on size of array init-list.
+// { dg-do run { target c++2a } }
+
+int f(int (&)[1][1]) { return 1; }
+int f(int (&)[1][2]) { return 2; }
+
+int g(int (&&)[2][1]) { return 1; }
+int g(int (&&)[2][2]) { return 2; }
+
+int h(int (&&)[][1]) { return 1; }
+int h(int (&&)[][2]) { return 2; }
+
+int
+main ()
+{
+ int arr1[1][1];
+ int arr2[1][2];
+
+ if (f(arr1) != 1)
+ __builtin_abort ();
+ if (f(arr2) != 2)
+ __builtin_abort ();
+
+ if (g({ { 1, 2 }, { 3 } }) != 2)
+ __builtin_abort ();
+
+ if (g({ { 1, 2 }, { 3, 4 } }) != 2)
+ __builtin_abort ();
+
+ if (h({ { 1, 2 }, { 3 } }) != 2)
+ __builtin_abort ();
+
+ if (h({ { 1, 2 }, { 3, 4 } }) != 2)
+ __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-err2.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-err2.C
index aaa80f47000..3399ce7c866 100644
--- a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-err2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-err2.C
@@ -6,7 +6,7 @@ int main()
auto a = []() { return true; };
auto b = []() { return a(); }; // { dg-error "'a' is not captured" }
int c, d;
- while (b() && c < d) // { dg-error "could not convert" }
+ while (b() && c < d)
{
}
}
diff --git a/gcc/testsuite/g++.dg/cpp0x/nullptr37.C b/gcc/testsuite/g++.dg/cpp0x/nullptr37.C
index e746a285404..6bcc8e81e20 100644
--- a/gcc/testsuite/g++.dg/cpp0x/nullptr37.C
+++ b/gcc/testsuite/g++.dg/cpp0x/nullptr37.C
@@ -6,41 +6,41 @@ f1 (int *p, int **q)
{
int r = 0;
- r += p == '\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
- r += p == L'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
- r += p == u'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
- r += p == U'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
- r += p != '\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
- r += p != L'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
- r += p != u'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
- r += p != U'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+ r += p == '\0'; // { dg-error "10:ISO C\\+\\+ forbids comparison between pointer and integer" }
+ r += p == L'\0'; // { dg-error "10:ISO C\\+\\+ forbids comparison between pointer and integer" }
+ r += p == u'\0'; // { dg-error "10:ISO C\\+\\+ forbids comparison between pointer and integer" }
+ r += p == U'\0'; // { dg-error "10:ISO C\\+\\+ forbids comparison between pointer and integer" }
+ r += p != '\0'; // { dg-error "10:ISO C\\+\\+ forbids comparison between pointer and integer" }
+ r += p != L'\0'; // { dg-error "10:ISO C\\+\\+ forbids comparison between pointer and integer" }
+ r += p != u'\0'; // { dg-error "10:ISO C\\+\\+ forbids comparison between pointer and integer" }
+ r += p != U'\0'; // { dg-error "10:ISO C\\+\\+ forbids comparison between pointer and integer" }
- r += '\0' == p; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
- r += L'\0' == p; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
- r += u'\0' == p; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
- r += U'\0' == p; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
- r += '\0' != p; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
- r += L'\0' != p; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
- r += u'\0' != p; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
- r += U'\0' != p; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+ r += '\0' == p; // { dg-error "13:ISO C\\+\\+ forbids comparison between pointer and integer" }
+ r += L'\0' == p; // { dg-error "14:ISO C\\+\\+ forbids comparison between pointer and integer" }
+ r += u'\0' == p; // { dg-error "14:ISO C\\+\\+ forbids comparison between pointer and integer" }
+ r += U'\0' == p; // { dg-error "14:ISO C\\+\\+ forbids comparison between pointer and integer" }
+ r += '\0' != p; // { dg-error "13:ISO C\\+\\+ forbids comparison between pointer and integer" }
+ r += L'\0' != p; // { dg-error "14:ISO C\\+\\+ forbids comparison between pointer and integer" }
+ r += u'\0' != p; // { dg-error "14:ISO C\\+\\+ forbids comparison between pointer and integer" }
+ r += U'\0' != p; // { dg-error "14:ISO C\\+\\+ forbids comparison between pointer and integer" }
- r += q == '\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
- r += q == L'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
- r += q == u'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
- r += q == U'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
- r += q != '\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
- r += q != L'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
- r += q != u'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
- r += q != U'\0'; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+ r += q == '\0'; // { dg-error "10:ISO C\\+\\+ forbids comparison between pointer and integer" }
+ r += q == L'\0'; // { dg-error "10:ISO C\\+\\+ forbids comparison between pointer and integer" }
+ r += q == u'\0'; // { dg-error "10:ISO C\\+\\+ forbids comparison between pointer and integer" }
+ r += q == U'\0'; // { dg-error "10:ISO C\\+\\+ forbids comparison between pointer and integer" }
+ r += q != '\0'; // { dg-error "10:ISO C\\+\\+ forbids comparison between pointer and integer" }
+ r += q != L'\0'; // { dg-error "10:ISO C\\+\\+ forbids comparison between pointer and integer" }
+ r += q != u'\0'; // { dg-error "10:ISO C\\+\\+ forbids comparison between pointer and integer" }
+ r += q != U'\0'; // { dg-error "10:ISO C\\+\\+ forbids comparison between pointer and integer" }
- r += '\0' == q; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
- r += L'\0' == q; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
- r += u'\0' == q; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
- r += U'\0' == q; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
- r += '\0' != q; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
- r += L'\0' != q; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
- r += u'\0' != q; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
- r += U'\0' != q; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+ r += '\0' == q; // { dg-error "13:ISO C\\+\\+ forbids comparison between pointer and integer" }
+ r += L'\0' == q; // { dg-error "14:ISO C\\+\\+ forbids comparison between pointer and integer" }
+ r += u'\0' == q; // { dg-error "14:ISO C\\+\\+ forbids comparison between pointer and integer" }
+ r += U'\0' == q; // { dg-error "14:ISO C\\+\\+ forbids comparison between pointer and integer" }
+ r += '\0' != q; // { dg-error "13:ISO C\\+\\+ forbids comparison between pointer and integer" }
+ r += L'\0' != q; // { dg-error "14:ISO C\\+\\+ forbids comparison between pointer and integer" }
+ r += u'\0' != q; // { dg-error "14:ISO C\\+\\+ forbids comparison between pointer and integer" }
+ r += U'\0' != q; // { dg-error "14:ISO C\\+\\+ forbids comparison between pointer and integer" }
return r;
}
@@ -68,11 +68,11 @@ f3 (int *p)
{
int r = 0;
- r += p == (char) 0; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
- r += p != (char) 0; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+ r += p == (char) 0; // { dg-error "10:ISO C\\+\\+ forbids comparison between pointer and integer" }
+ r += p != (char) 0; // { dg-error "10:ISO C\\+\\+ forbids comparison between pointer and integer" }
- r += (char) 0 == p; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
- r += (char) 0 != p; // { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" }
+ r += (char) 0 == p; // { dg-error "17:ISO C\\+\\+ forbids comparison between pointer and integer" }
+ r += (char) 0 != p; // { dg-error "17:ISO C\\+\\+ forbids comparison between pointer and integer" }
return r;
}
diff --git a/gcc/testsuite/g++.dg/cpp0x/scoped_enum10.C b/gcc/testsuite/g++.dg/cpp0x/scoped_enum10.C
new file mode 100644
index 00000000000..054b90850d8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/scoped_enum10.C
@@ -0,0 +1,37 @@
+// PR c++/92032 - DR 1601: Promotion of enumeration with fixed underlying type.
+// { dg-do compile { target c++11 } }
+
+enum E : char { e };
+enum F : int { f };
+enum G : long { g };
+enum H : unsigned { h };
+
+int f1(char);
+void f1(int);
+
+void f2(int);
+int f2(char);
+
+int f3(int);
+void f3(short);
+
+int f4(long);
+void f4(int);
+
+void f5(unsigned);
+int f5(int);
+
+int f6(unsigned);
+void f6(int);
+
+void
+test ()
+{
+ int r = 0;
+ r += f1 (e);
+ r += f2 (e);
+ r += f3 (f);
+ r += f4 (g);
+ r += f5 (f);
+ r += f6 (h);
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/scoped_enum11.C b/gcc/testsuite/g++.dg/cpp0x/scoped_enum11.C
new file mode 100644
index 00000000000..e6dcfbac9d8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/scoped_enum11.C
@@ -0,0 +1,35 @@
+// PR c++/92032 - DR 1601: Promotion of enumeration with fixed underlying type.
+// { dg-do compile { target c++11 } }
+
+enum E1 : long { e1 };
+enum E2 : short { e2 };
+
+int f1(short);
+void f1(int);
+
+void f2(int);
+int f2(short);
+
+void f3(int);
+int f3(long);
+
+int f4(short);
+void f4(long);
+
+int f5(int);
+void f5(long);
+
+int f6(unsigned int); // { dg-message "candidate" }
+void f6(long); // { dg-message "candidate" }
+
+void
+fn ()
+{
+ int r = 0;
+ r += f1 (e2);
+ r += f2 (e2);
+ r += f3 (e1);
+ r += f4 (e2);
+ r += f5 (e2);
+ r += f6 (e2); // { dg-error "ambiguous" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/scoped_enum9.C b/gcc/testsuite/g++.dg/cpp0x/scoped_enum9.C
new file mode 100644
index 00000000000..f38f26dc35b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/scoped_enum9.C
@@ -0,0 +1,11 @@
+// DR 685 - Integral promotion of enumeration ignores fixed underlying type.
+// { dg-do compile { target c++11 } }
+
+enum E: long { e };
+
+void f(int);
+int f(long);
+
+void g() {
+ int k = f(e);
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/eval-order6.C b/gcc/testsuite/g++.dg/cpp1z/eval-order6.C
new file mode 100644
index 00000000000..c8fb0b6dc9c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/eval-order6.C
@@ -0,0 +1,20 @@
+// PR c++/91987
+// { dg-do run }
+// { dg-options "-fstrong-eval-order" }
+
+int
+foo ()
+{
+ int x = 5;
+ int r = x << (x = 3, 2);
+ if (x != 3)
+ __builtin_abort ();
+ return r;
+}
+
+int
+main ()
+{
+ if (foo () != (5 << 2))
+ __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/eval-order7.C b/gcc/testsuite/g++.dg/cpp1z/eval-order7.C
new file mode 100644
index 00000000000..c6f3cc25027
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/eval-order7.C
@@ -0,0 +1,23 @@
+// PR c++/91987
+// { dg-do run }
+// { dg-options "-fstrong-eval-order" }
+
+int a[4] = { 1, 2, 3, 4 };
+int b[4] = { 5, 6, 7, 8 };
+
+int
+foo ()
+{
+ int *x = a;
+ int r = x[(x = b, 3)];
+ if (x != b)
+ __builtin_abort ();
+ return r;
+}
+
+int
+main ()
+{
+ if (foo () != 4)
+ __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/eval-order8.C b/gcc/testsuite/g++.dg/cpp1z/eval-order8.C
new file mode 100644
index 00000000000..a8a4240f1b3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/eval-order8.C
@@ -0,0 +1,20 @@
+// PR c++/91987
+// { dg-do run }
+// { dg-options "-fstrong-eval-order" }
+
+int a[4] = { 1, 2, 3, 4 };
+int b;
+
+int
+main ()
+{
+ int *x = a;
+ b = 1;
+ int r = (b = 4, x)[(b *= 2, 3)];
+ if (b != 8 || r != 4)
+ __builtin_abort ();
+ b = 1;
+ r = (b = 3, 2)[(b *= 2, x)];
+ if (b != 6 || r != 3)
+ __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/array-conv1.C b/gcc/testsuite/g++.dg/cpp2a/array-conv1.C
new file mode 100644
index 00000000000..e90b340b0d6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/array-conv1.C
@@ -0,0 +1,33 @@
+// PR c++/91364 - Implement P0388R4: Permit conversions to arrays of unknown bound.
+// { dg-do compile { target c++17 } }
+// { dg-options "-Wpedantic" }
+// C++17, because that has CWG 393.
+
+void f(int(&)[]);
+void fp(int(*)[]);
+void f2(int(&)[][10]);
+void fp2(int(*)[][10]);
+int arr[10];
+int arr2[10][10];
+
+void
+g ()
+{
+ f (arr); // { dg-warning "conversions to arrays of unknown bound are only available" "" { target c++17_down } }
+ fp (&arr); // { dg-warning "conversions to arrays of unknown bound are only available" "" { target c++17_down } }
+ f2 (arr2);// { dg-warning "conversions to arrays of unknown bound are only available" "" { target c++17_down } }
+ fp2 (&arr2);// { dg-warning "conversions to arrays of unknown bound are only available" "" { target c++17_down } }
+}
+
+int(&r1)[] = arr;// { dg-warning "conversions to arrays of unknown bound are only available" "" { target c++17_down } }
+int(&r2)[10] = arr;
+int(&r3)[][10] = arr2;// { dg-warning "conversions to arrays of unknown bound are only available" "" { target c++17_down } }
+/* Note that
+ int (&r)[10][] = arr2;
+ is invalid. */
+int(&r4)[10][10] = arr2;
+
+int(*p1)[] = &arr;// { dg-warning "conversions to arrays of unknown bound are only available" "" { target c++17_down } }
+int(*p2)[10] = &arr;
+int(*p3)[][10] = &arr2;// { dg-warning "conversions to arrays of unknown bound are only available" "" { target c++17_down } }
+int(*p4)[10][10] = &arr2;
diff --git a/gcc/testsuite/g++.dg/cpp2a/array-conv10.C b/gcc/testsuite/g++.dg/cpp2a/array-conv10.C
new file mode 100644
index 00000000000..1ee1a771f63
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/array-conv10.C
@@ -0,0 +1,22 @@
+// PR c++/91364 - Implement P0388R4: Permit conversions to arrays of unknown bound.
+// { dg-do compile { target c++17 } }
+// { dg-options "-Wpedantic" }
+
+// The other direction: converting from int[] to int(&)[3] is forbidden.
+
+extern int a[];
+extern int (*b)[];
+extern int (&c)[];
+int (&y)[] = a;
+int (&x)[3] = y; // { dg-error "cannot bind reference" }
+int (&z)[3] = a; // { dg-error "cannot bind reference" }
+
+void f(int (*)[3]);
+void f2(int (&)[3]);
+
+void
+test ()
+{
+ f(b); // { dg-error "cannot convert" }
+ f2(c); // { dg-error "cannot bind reference" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/array-conv11.C b/gcc/testsuite/g++.dg/cpp2a/array-conv11.C
new file mode 100644
index 00000000000..a072b29191d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/array-conv11.C
@@ -0,0 +1,23 @@
+// PR c++/91364 - Implement P0388R4: Permit conversions to arrays of unknown bound.
+// { dg-do compile { target c++2a } }
+// { dg-options "-Wpedantic" }
+
+// Test flexible array member. Here we're binding int[] to int[]. This worked
+// even before P0388R4.
+
+typedef int T[];
+extern T arr;
+T &t1 = arr;
+
+struct S {
+ int i;
+ int a[]; // { dg-warning "flexible array member" }
+};
+
+void f (int (&)[]);
+
+void
+test (S s)
+{
+ f (s.a);
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/array-conv12.C b/gcc/testsuite/g++.dg/cpp2a/array-conv12.C
new file mode 100644
index 00000000000..1156ea32df5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/array-conv12.C
@@ -0,0 +1,12 @@
+// PR c++/91364 - Implement P0388R4: Permit conversions to arrays of unknown bound.
+// { dg-do compile { target c++2a } }
+// { dg-options "-Wpedantic" }
+
+int arr[1] = { 42 };
+int(&r)[]{arr};
+int(&r2)[] = {arr};
+int(&&r3)[]{};
+int(&&r4)[]{42};
+int(&&r5)[] = {};
+int(&&r6)[] = {42};
+int(&r7)[](arr); // { dg-warning "conversions to arrays of unknown bound are only available" "" { target c++17_down } }
diff --git a/gcc/testsuite/g++.dg/cpp2a/array-conv13.C b/gcc/testsuite/g++.dg/cpp2a/array-conv13.C
new file mode 100644
index 00000000000..9908b7e9118
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/array-conv13.C
@@ -0,0 +1,17 @@
+// PR c++/91364 - Implement P0388R4: Permit conversions to arrays of unknown bound.
+// { dg-do compile { target c++2a } }
+
+template <typename T> void foo(T);
+
+template <typename F, typename T, typename = decltype(foo<T>(F()))>
+void test(int) { }
+
+// No other overload, so if the above fails because of the conversion,
+// we fail.
+
+void
+fn ()
+{
+ test<int(*)[2], int(*)[]>(0);
+ test<int(*)[], int(*)[]>(0);
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/array-conv14.C b/gcc/testsuite/g++.dg/cpp2a/array-conv14.C
new file mode 100644
index 00000000000..793e85d7b1c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/array-conv14.C
@@ -0,0 +1,17 @@
+// PR c++/91364 - Implement P0388R4: Permit conversions to arrays of unknown bound.
+// { dg-do compile { target c++2a } }
+
+void f(const int(*)[]);
+void fb(const int(*)[3]);
+void f2(const int(&)[]);
+void fb2(const int(&)[3]);
+
+void
+g ()
+{
+ int arr[3];
+ f(&arr);
+ fb(&arr);
+ f2(arr);
+ fb2(arr);
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/array-conv15.C b/gcc/testsuite/g++.dg/cpp2a/array-conv15.C
new file mode 100644
index 00000000000..033a74683a7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/array-conv15.C
@@ -0,0 +1,23 @@
+// PR c++/69531 - DR 1307, Overload resolution based on size of array init-list.
+// { dg-do run { target c++2a } }
+
+int f(int, int const(&)[2]) { return 1; }
+int f(double, int const(&)[2]) { return 2; }
+
+int f2(int, int const(&)[1]) { return 1; }
+int f2(int, int const(&)[2]) { return 2; }
+
+int f3(int, int const(&)[]) { return 1; }
+int f3(double, int const(&)[]) { return 2; }
+
+int main ()
+{
+ if (f (1, {1}) != 1)
+ __builtin_abort ();
+
+ if (f2 (1, {1}) != 1)
+ __builtin_abort ();
+
+ if (f3 (1, {1}) != 1)
+ __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/array-conv16.C b/gcc/testsuite/g++.dg/cpp2a/array-conv16.C
new file mode 100644
index 00000000000..bfb39d1c12c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/array-conv16.C
@@ -0,0 +1,16 @@
+// PR c++/91364 - P0388R4: Permit conversions to arrays of unknown bound.
+// { dg-do compile { target c++2a } }
+
+using P = int *(*)[3];
+using S = const int *const (*)[];
+using Q = const int *const (*)[3];
+using Qi = const int *[3];
+using Q2 = Qi const *;
+
+void
+f (P p, S s, Q q, Q2 q2)
+{
+ s = p;
+ s = q;
+ s = q2;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/array-conv17.C b/gcc/testsuite/g++.dg/cpp2a/array-conv17.C
new file mode 100644
index 00000000000..3313ed466fb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/array-conv17.C
@@ -0,0 +1,39 @@
+// PR c++/91364 - P0388R4: Permit conversions to arrays of unknown bound.
+// { dg-do compile { target c++2a } }
+
+// As conversion/qual1.C, but with [].
+
+int *a[4];
+const int *const(*ap1)[] = &a;
+/* if at some level k the P2 is more cv-qualified than P1, then there
+ must be a const at every single level (other than level zero) of P2
+ up until k. */
+const int *(*ap2)[] = &a; // { dg-error "cannot convert" }
+int *const(*ap3)[] = &a;
+int *(*ap4)[] = &a;
+int *(*const ap5)[] = &a;
+const int *const(*const ap6)[] = &a;
+int *const(*const ap7)[] = &a;
+int *(*const ap8)[] = &a;
+
+const int *b[4];
+const int *const(*bp1)[] = &b;
+const int *(*bp2)[] = &b;
+int *const(*bp3)[] = &b; // { dg-error "cannot convert" }
+int *(*bp4)[] = &b; // { dg-error "cannot convert" }
+int *(*const bp5)[] = &b; // { dg-error "cannot convert" }
+const int *const(*const bp6)[] = &b;
+int *const(*const bp7)[] = &b; // { dg-error "cannot convert" }
+int *(*const bp8)[] = &b; // { dg-error "cannot convert" }
+
+int *c[2][3];
+int const *const (*cp1)[] = c;
+int const *(*cp2)[] = c; // { dg-error "cannot convert" }
+int const *const (*const cp3)[] = c;
+int *const (*cp4)[] = c;
+int *(*cp5)[] = c;
+
+double *const (*d)[3];
+double const *const (*e)[] = d;
+int *(*f)[3];
+const int *const (*g)[] = f;
diff --git a/gcc/testsuite/g++.dg/cpp2a/array-conv2.C b/gcc/testsuite/g++.dg/cpp2a/array-conv2.C
new file mode 100644
index 00000000000..5245d830f1f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/array-conv2.C
@@ -0,0 +1,26 @@
+// PR c++/91364 - Implement P0388R4: Permit conversions to arrays of unknown bound.
+// { dg-do compile { target c++2a } }
+
+struct A {
+ A();
+ A(const A(&)[2]);
+};
+
+using T = A[];
+using U = A[2];
+
+// t binds directly to U{} now. Before it bound indirectly to a temporary
+// A{U{}}. ??? But we don't do it now; see reference_binding and the
+// BRACE_ENCLOSED_INITIALIZER_P block.
+A (&&t)[] = {U{}};
+
+U u{};
+
+T &
+foo ()
+{
+ // This didn't compile before P0388R4: invalid initialization of non-const
+ // reference of type 'A (&)[]' from an rvalue of type
+ // '<brace-enclosed initializer list>'.
+ return {u};
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/array-conv3.C b/gcc/testsuite/g++.dg/cpp2a/array-conv3.C
new file mode 100644
index 00000000000..3d92b401247
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/array-conv3.C
@@ -0,0 +1,26 @@
+// PR c++/91364 - Implement P0388R4: Permit conversions to arrays of unknown bound.
+// { dg-do run { target c++2a } }
+
+// Ranking of reference initialization conversions
+
+int f(int(&)[]) { return 1; } // (1)
+int f(int(&)[1]) { return 2; } // (2)
+
+int h(int(*)[]) { return 1; } // (a)
+int h(int(*)[1]) { return 2; } // (b)
+
+// From P0388R4:
+// (2) and (b) should clearly be better than (1) and (a), respectively,
+// as the former overloads are more restricted.
+// (a) should be worse than (b), which is implied by (a) necessitating
+// a qualification conversion in that case.
+
+int
+main ()
+{
+ int arr[1];
+ if (f(arr) != 2)
+ __builtin_abort ();
+ if (h(&arr) != 2)
+ __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/array-conv4.C b/gcc/testsuite/g++.dg/cpp2a/array-conv4.C
new file mode 100644
index 00000000000..979c69b0555
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/array-conv4.C
@@ -0,0 +1,24 @@
+// PR c++/91364 - Implement P0388R4: Permit conversions to arrays of unknown bound.
+// { dg-do compile { target c++2a } }
+
+// Ranking of reference initialization conversions
+
+void f(int(&)[]) {} // (1)
+//void f(int(&)[1]) { } // (2)
+void f(int*) { } // (3)
+
+//void f2(int(&)[]) { } // (1)
+void f2(int(&)[1]) { } // (2)
+void f2(int*) { } // (3)
+
+// From P0388R4:
+// (3) should be equal to (1) (as it is to (2))
+// Check that we get "ambiguous overload" errors.
+
+void
+doit ()
+{
+ int arr[1];
+ f(arr); // { dg-error "ambiguous" }
+ f2(arr); // { dg-error "ambiguous" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/array-conv5.C b/gcc/testsuite/g++.dg/cpp2a/array-conv5.C
new file mode 100644
index 00000000000..34678f5cead
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/array-conv5.C
@@ -0,0 +1,24 @@
+// PR c++/91364 - Implement P0388R4: Permit conversions to arrays of unknown bound.
+// { dg-do run { target c++2a } }
+
+// Ranking of list-initialization sequences
+int b(int (&&)[] ) { return 1; } // #1
+int b(long (&&)[] ) { return 2; } // #2
+int b(int (&&)[1]) { return 3; } // #3
+int b(long (&&)[1]) { return 4; } // #4
+int b(int (&&)[2]) { return 5; } // #5
+
+/* Here,
+ -- #1, #3 and #5 should rank better than both #2 and #4, as no promotion
+ is necessitated.
+ -- #1 should rank worse than #3, being far less specialized.
+ -- #1 should rank better than #5, as the latter requires a larger array
+ temporary. (#3 also ranks better than #5 for the same reason--cf. core
+ issue 1307). */
+
+int
+main ()
+{
+ if (b({1}) != 3)
+ __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/array-conv6.C b/gcc/testsuite/g++.dg/cpp2a/array-conv6.C
new file mode 100644
index 00000000000..c2389c82273
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/array-conv6.C
@@ -0,0 +1,28 @@
+// PR c++/91364 - Implement P0388R4: Permit conversions to arrays of unknown bound.
+// { dg-do run { target c++2a } }
+
+// Ranking of reference initialization conversions
+
+int f1(const int(&)[]) { return 1; }
+int f1(const int(&)[1]) { return 2; }
+
+int f2(const int(&)[]) { return 1; }
+int f2(int(&)[1]) { return 2; }
+
+int f3(int(&)[]) { return 1; }
+int f3(const int(&)[1]) { return 2; }
+
+const int arr[1] = { 42 };
+
+int
+main ()
+{
+ if (f1(arr) != 2)
+ __builtin_abort ();
+
+ if (f2(arr) != 1)
+ __builtin_abort ();
+
+ if (f3(arr) != 2)
+ __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/array-conv7.C b/gcc/testsuite/g++.dg/cpp2a/array-conv7.C
new file mode 100644
index 00000000000..07c709ff10f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/array-conv7.C
@@ -0,0 +1,34 @@
+// PR c++/69531 - DR 1307, Overload resolution based on size of array init-list.
+// { dg-do run { target c++2a } }
+
+int f(int const(&)[]) { return 1; }
+int f(int const(&)[2]) { return 2; }
+
+int f2(int const(&)[]) { return 1; }
+int f2(int const(&)[1]) { return 2; }
+
+int f3(int const(&)[]) { return 1; }
+int f3(int const(&)[1]) { return 2; }
+int f3(int const(&)[2]) { return 3; }
+
+int main ()
+{
+ if (f ({}) != 1)
+ __builtin_abort ();
+ if (f ({1}) != 1)
+ __builtin_abort ();
+ if (f ({1, 2}) != 2)
+ __builtin_abort ();
+
+ if (f2 ({}) != 1)
+ __builtin_abort ();
+ if (f2 ({1}) != 2)
+ __builtin_abort ();
+
+ if (f3 ({}) != 1)
+ __builtin_abort ();
+ if (f3 ({1}) != 2)
+ __builtin_abort ();
+ if (f3 ({1, 2}) != 3)
+ __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/array-conv8.C b/gcc/testsuite/g++.dg/cpp2a/array-conv8.C
new file mode 100644
index 00000000000..635c7679a21
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/array-conv8.C
@@ -0,0 +1,26 @@
+// PR c++/69531 - DR 1307, Overload resolution based on size of array init-list.
+// { dg-do run { target c++2a } }
+// Example from [over.ics.rank].
+
+int f(int (&&)[] ) { return 1; } // #1
+int f(double (&&)[] ) { return 2; } // #2
+int f(int (&&)[2]) { return 3; } // #3
+
+int
+main ()
+{
+ // Calls #1: Better than #2 due to conversion, better than #3 due to bounds.
+ if (f({1}) != 1)
+ __builtin_abort ();
+ // Calls #2: Identity conversion is better than floating-integral conversion.
+ if (f({1.0}) != 2)
+ __builtin_abort ();
+ // Calls #2: Identity conversion is better than floating-integral conversion.
+ if (f({1.0, 2.0}) != 2)
+ __builtin_abort ();
+ // Calls #3: Converting to array of known bound is better than to unknown
+ // bound, and an identity conversion is better than floating-integral
+ // conversion.
+ if (f({1, 2}) != 3)
+ __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/array-conv9.C b/gcc/testsuite/g++.dg/cpp2a/array-conv9.C
new file mode 100644
index 00000000000..82f615db2e7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/array-conv9.C
@@ -0,0 +1,27 @@
+// PR c++/91364 - Implement P0388R4: Permit conversions to arrays of unknown bound.
+// { dg-do compile { target c++2a } }
+
+int arr[1];
+extern int arr2[];
+
+void
+test ()
+{
+ int (&r)[1] = const_cast<int(&)[1]>(arr);
+ int (&r2)[] = const_cast<int(&)[]>(arr); // { dg-error "invalid" }
+ int (&r3)[1] = (int(&)[1]) arr;
+ int (&r4)[] = (int(&)[]) arr;
+ int (&r5)[1] = static_cast<int(&)[1]>(arr);
+ int (&r6)[] = static_cast<int(&)[]>(arr);
+
+ // Try c_cast_p.
+ int(*p1)[] = (int(*)[]) &arr;
+ int(*p2)[1] = (int(*)[]) &arr; // { dg-error "cannot convert" }
+ int(*p3)[] = (int(*)[1]) &arr;
+ int(*p4)[] = (int(*)[1]) &arr2;
+ int(*p5)[] = (int(*)[]) (int(*)[1]) &arr;
+ int(*p6)[] = (int(*)[1]) (int(*)[]) &arr;
+ int(*p7)[] = static_cast<int(*)[]>(&arr);
+ int(*p8)[] = static_cast<int(*)[1]>(&arr);
+ int(*p9)[] = static_cast<int(*)[1]>(&arr2); // { dg-error "invalid" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-access1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-access1.C
new file mode 100644
index 00000000000..bbb1be0c2b4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-access1.C
@@ -0,0 +1,15 @@
+// { dg-do compile { target concepts } }
+
+class A
+{
+ static void f(int);
+public:
+ template <class T> void g(T t)
+ requires requires { f(t); }
+ {}
+};
+
+int main()
+{
+ A().g(42);
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-alias.C b/gcc/testsuite/g++.dg/cpp2a/concepts-alias.C
new file mode 100644
index 00000000000..6b2ab0d8046
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-alias.C
@@ -0,0 +1,25 @@
+// { dg-do compile { target c++2a } }
+
+template<typename T>
+concept Class = __is_class(T);
+
+template<typename T>
+ requires Class<T>
+using X = T*;
+
+// BUG: Alias templates are expanded at the point of use, regardless
+// of whether or not they are dependent. This causes T* to be substituted
+// without acutally checking the constraints. See the declaration of y1
+// below.
+template<typename T>
+using Y = X<T>;
+
+template<Class T> using Z = T*;
+
+struct S { };
+
+X<S> x1; // OK
+X<int> x2; // { dg-error "template constraint failure" }
+Y<int> y1; // { dg-error "" "" { xfail *-*-* } }
+Z<S> z1; // ok
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-alias2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-alias2.C
new file mode 100644
index 00000000000..b7840305602
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-alias2.C
@@ -0,0 +1,12 @@
+// { dg-do compile { target concepts } }
+
+using Bool = bool;
+template <class T>
+const Bool b = true;
+
+template <class T>
+concept BoolC = b<T>;
+
+template <BoolC T> struct A { };
+
+A<int> a;
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-class.C b/gcc/testsuite/g++.dg/cpp2a/concepts-class.C
new file mode 100644
index 00000000000..aca5c44c48f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-class.C
@@ -0,0 +1,115 @@
+// { dg-do compile { target c++2a } }
+
+template<typename T>
+concept Class = __is_class(T);
+
+template<typename T>
+concept Union = __is_union(T);
+
+template<typename T>
+concept One = sizeof(T) >= 4;
+
+template<typename T>
+concept Two = One<T> && sizeof(T) >= 8;
+
+// Basic checks
+template<typename T> requires true struct ok { };
+template<typename T> requires false struct err { };
+
+ok<int> ok1;
+err<int> err1; // { dg-error "template constraint failure" }
+err<int>* err2; // { dg-error "template constraint failure" }
+
+// Redeclarations
+template<typename T>
+ requires Class<T>
+struct S1;
+
+template<Class T> // { dg-error "template parameter | different constraints" }
+struct S1 { };
+
+template<typename T>
+ requires Class<T>
+struct S2;
+
+template<typename T>
+ requires Union<T>
+struct S2; // { dg-error "redeclaration | different constraints" }
+
+
+// Check non-overlapping specializations
+template<typename T>
+struct S3 { static const int value = 0; };
+
+template<typename T>
+ requires Class<T>
+struct S3<T> { static const int value = 1; };
+
+template<typename T>
+ requires Union<T>
+struct S3<T> { static const int value = 2; };
+
+struct S { };
+union U { };
+
+static_assert(S3<int>::value == 0, "");
+static_assert(S3<S>::value == 1, "");
+static_assert(S3<U>::value == 2, "");
+
+// Check ordering of partial specializations
+template<typename T>
+struct S4 { static const int value = 0; };
+
+template<typename T>
+ requires One<T>
+struct S4<T> { static const int value = 1; };
+
+template<typename T>
+ requires Two<T>
+struct S4<T> { static const int value = 2; };
+
+struct one_type { char x[4]; };
+struct two_type { char x[8]; };
+
+static_assert(S4<char>::value == 0, "");
+static_assert(S4<one_type>::value == 1, "");
+static_assert(S4<two_type>::value == 2, "");
+
+// Specializations are more specialized.
+template<typename T> requires Two<T> struct S5 { };
+template<typename T> requires One<T> struct S5<T> { }; // { dg-error "does not specialize" }
+
+// Constraints are checked even when decls are not instantiatied.
+S5<one_type>* x4b; // { dg-error "constraint|invalid" }
+
+// Deduction guides
+template <class T>
+concept IsInt = __is_same_as(T,int);
+
+template<typename T>
+struct A
+{
+ int i;
+ A(...);
+};
+
+template<typename I>
+ requires IsInt<I>
+A(I) -> A<I>;
+
+A a(1);
+A a2(1.0); // { dg-error "class template argument deduction | no matching function for call" }
+
+
+template<typename T>
+struct S6
+{
+ template<typename U>
+ requires true
+ struct Inner;
+};
+
+template<typename T>
+template<typename U>
+struct S6<T>::Inner { }; // { dg-error "does not match" }
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-cmath.C b/gcc/testsuite/g++.dg/cpp2a/concepts-cmath.C
new file mode 100644
index 00000000000..b090c3a3719
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-cmath.C
@@ -0,0 +1,4 @@
+// { dg-do compile { target c++2a } }
+
+#include <cmath>
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-complete1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-complete1.C
new file mode 100644
index 00000000000..25c4ca064ce
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-complete1.C
@@ -0,0 +1,11 @@
+// { dg-do compile { target c++2a } }
+
+template <class T> concept has_mem_type = requires { typename T::type; };
+
+template <has_mem_type T> int f () { return 0; }
+template <class T> char f() { return 0; }
+
+struct A;
+static_assert (sizeof (f<A>()) == 1);
+struct A { typedef int type; };
+static_assert (sizeof (f<A>()) > 1);
diff --git a/gcc/testsuite/g++.dg/concepts/constrained-parm.C b/gcc/testsuite/g++.dg/cpp2a/concepts-constrained-parm.C
index c2b6614aeea..bb7e31d8b6c 100644
--- a/gcc/testsuite/g++.dg/concepts/constrained-parm.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-constrained-parm.C
@@ -1,8 +1,7 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
+// { dg-do compile { target c++2a } }
template<typename T>
- concept bool C() { return __is_class(T); }
+ concept C = __is_class(T);
template<const C T> struct S1 { }; // { dg-error "cv-qualified" }
template<volatile C T> struct S2 { }; // { dg-error "cv-qualified" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-decltype.C b/gcc/testsuite/g++.dg/cpp2a/concepts-decltype.C
new file mode 100644
index 00000000000..db3cfdf3cb2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-decltype.C
@@ -0,0 +1,67 @@
+// { dg-do compile { target c++2a } }
+
+// Tests constrained decltype(auto).
+
+template<typename T>
+concept Type = true;
+
+template<typename T>
+concept Int = __is_same_as(T, int);
+
+template<typename T, typename U>
+concept SameAs = __is_same_as(T, U);
+
+template<typename T, typename U>
+ requires SameAs<T, U>
+constexpr bool check = true;
+
+int z = 0;
+const int cz = 0;
+
+Type decltype(auto) x1 = 0;
+static_assert(check<decltype(x1), int>);
+Type decltype(auto) x2 = z;
+static_assert(check<decltype(x2), int>);
+Type decltype(auto) x3 = (z);
+static_assert(check<decltype(x3), int&>);
+Type decltype(auto) x4 = cz;
+static_assert(check<decltype(x4), const int>);
+Type decltype(auto) x5 = (cz);
+static_assert(check<decltype(x5), const int&>);
+
+Type decltype(auto) f1() { return 0; }
+static_assert(check<decltype(f1()), int>);
+Type decltype(auto) f2() { return z; }
+static_assert(check<decltype(f2()), int>);
+Type decltype(auto) f3() { return (z); }
+static_assert(check<decltype(f3()), int&>);
+Type decltype(auto) f4() { return cz; }
+static_assert(check<decltype(f4()), int>); // Top-level const is removed?
+Type decltype(auto) f5() { return (cz); }
+static_assert(check<decltype(f5()), const int&>);
+
+bool b = true;
+const bool cb = true;
+
+Int decltype(auto) b1 = true; // { dg-error "deduced initializer" }
+Int decltype(auto) b2 = (b); // { dg-error "deduced initializer" }
+Int decltype(auto) b3 = (cb); // { dg-error "deduced initializer" }
+
+Int decltype(auto) g1() { } // { dg-error "deduced return type" }
+Int decltype(auto) g2() { return; } // { dg-error "deduced return type" }
+Int decltype(auto) g3() { return true; } // { dg-error "deduced return type" }
+int g4(Type decltype(auto) x) { return 0; } // { dg-error "cannot declare" }
+int g5(decltype(auto) x) { return 0; } // { dg-error "cannot declare" }
+
+template<Type decltype(auto) X, typename T>
+ requires SameAs<decltype(X), T>
+constexpr bool deduced_as = true;
+
+constexpr int Z = 10;
+
+static_assert(deduced_as<0, int>);
+static_assert(deduced_as<0, int&>); // { dg-error "invalid variable template" }
+static_assert(deduced_as<Z, const int>);
+static_assert(deduced_as<(Z), const int>); // { dg-error "invalid variable template" }
+static_assert(deduced_as<(Z), const int&>);
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-defarg1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-defarg1.C
new file mode 100644
index 00000000000..c3ed30914d8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-defarg1.C
@@ -0,0 +1,7 @@
+// { dg-do compile { target concepts } }
+
+template<typename T, typename U = T> concept C3 = true;
+template<class T> struct s1
+{
+ template <C3<T> U> void f() { }
+};
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-dep1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-dep1.C
new file mode 100644
index 00000000000..b4f611333bf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-dep1.C
@@ -0,0 +1,5 @@
+// { dg-do compile { target concepts } }
+
+template <class T> concept True = true;
+template <class T, int I = static_cast<int>(True<T>)> struct A { };
+template <class T> struct B: A<T> { };
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-dr1430.C b/gcc/testsuite/g++.dg/cpp2a/concepts-dr1430.C
new file mode 100644
index 00000000000..f39921fcec7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-dr1430.C
@@ -0,0 +1,14 @@
+// PR c++/66092
+// { dg-do compile { target c++2a } }
+
+template <typename T, typename U, typename... Args>
+ concept Similar = true;
+
+template <typename... Args>
+ requires Similar<Args...> // { dg-error "pack expansion" }
+void foo( Args... args ) {}
+
+int main()
+{
+ foo(1, 2, 3); // { dg-error "cannot call" }
+}
diff --git a/gcc/testsuite/g++.dg/concepts/explicit-inst1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-explicit-inst1.C
index 99bd72e069c..14d994c9b04 100644
--- a/gcc/testsuite/g++.dg/concepts/explicit-inst1.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-explicit-inst1.C
@@ -1,11 +1,13 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
+// { dg-do compile { target c++2a } }
+// { dg-final { scan-assembler "_Z1gI1XEvT_" } }
+// { dg-final { scan-assembler "_Z1gI1YEvT_" } }
+// { dg-final { scan-assembler "_Z1gIiEvT_" } }
template<typename T>
- concept bool C() { return __is_class(T); }
+ concept C = __is_class(T);
template<typename T>
- concept bool D() { return C<T>() && __is_empty(T); }
+ concept D = C<T> && __is_empty(T);
struct X { };
struct Y { int n; };
@@ -14,7 +16,6 @@ template<typename T> void g(T) { } // #1
template<C T> void g(T) { } // #2
template<D T> void g(T) { } // #3
-// FIXME: How do I test that these generate the right symbols?
template void g(int); // Instantiate #1
template void g(X); // Instantitae #3
template void g(Y); // Instantiate #2
diff --git a/gcc/testsuite/g++.dg/concepts/explicit-inst2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-explicit-inst2.C
index ea313876f01..6074bc78682 100644
--- a/gcc/testsuite/g++.dg/concepts/explicit-inst2.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-explicit-inst2.C
@@ -1,11 +1,10 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
+// { dg-do compile { target c++2a } }
template<typename T>
- concept bool C() { return __is_class(T); }
+ concept C = __is_class(T);
template<typename T>
- concept bool D() { return C<T>() && __is_empty(T); }
+ concept D = C<T> && __is_empty(T);
struct X { };
struct Y { int n; };
diff --git a/gcc/testsuite/g++.dg/concepts/explicit-inst3.C b/gcc/testsuite/g++.dg/cpp2a/concepts-explicit-inst3.C
index 18d3c496f38..03ec9e9a698 100644
--- a/gcc/testsuite/g++.dg/concepts/explicit-inst3.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-explicit-inst3.C
@@ -1,11 +1,10 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
+// { dg-do compile { target c++2a } }
template<typename T>
- concept bool C() { return __is_class(T); }
+ concept C = __is_class(T);
template<typename T>
- concept bool D() { return C<T>() && __is_empty(T); }
+ concept D = C<T> && __is_empty(T);
struct X { };
struct Y { int n; };
@@ -13,10 +12,10 @@ struct Y { int n; };
template<typename T>
struct S {
void f() { } // #1
- void f() requires C<T>() { } // #2
+ void f() requires C<T> { } // #2
- void g() requires C<T>() { } // #1
- void g() requires D<T>() { } // #2
+ void g() requires C<T> { } // #1
+ void g() requires D<T> { } // #2
};
template void S<int>::f(); // #1
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-explicit-inst4.C b/gcc/testsuite/g++.dg/cpp2a/concepts-explicit-inst4.C
new file mode 100644
index 00000000000..81bc081abbb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-explicit-inst4.C
@@ -0,0 +1,17 @@
+// { dg-do compile { target c++2a } }
+
+template<typename T>
+ concept C = __is_class(T);
+
+template<typename T>
+ concept D = C<T> && __is_empty(T);
+
+template<typename T>
+ struct S {
+ void g() requires C<T> { } // #1
+ void g() requires D<T> { } // #2
+ };
+
+template void S<int>::g(); // { dg-error "match" }
+
+int main() { }
diff --git a/gcc/testsuite/g++.dg/concepts/explicit-spec1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-explicit-spec1.C
index bff06f21b6f..d54bcdb3211 100644
--- a/gcc/testsuite/g++.dg/concepts/explicit-spec1.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-explicit-spec1.C
@@ -1,13 +1,12 @@
-// { dg-do run { target c++17 } }
-// { dg-options "-fconcepts" }
+// { dg-do run { target c++2a } }
#include <cassert>
template<typename T>
- concept bool C() { return __is_class(T); }
+ concept C = __is_class(T);
template<typename T>
- concept bool D() { return C<T>() && __is_empty(T); }
+ concept D = C<T> && __is_empty(T);
struct X { } x;
struct Y { int n; } y;
diff --git a/gcc/testsuite/g++.dg/concepts/explicit-spec2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-explicit-spec2.C
index ca8b8a037bc..4103714b004 100644
--- a/gcc/testsuite/g++.dg/concepts/explicit-spec2.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-explicit-spec2.C
@@ -1,8 +1,7 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
+// { dg-do compile { target c++2a } }
template<typename T>
- concept bool C() { return __is_class(T); }
+ concept C = __is_class(T);
struct X { };
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-explicit-spec3.C b/gcc/testsuite/g++.dg/cpp2a/concepts-explicit-spec3.C
new file mode 100644
index 00000000000..76c6fb9bd34
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-explicit-spec3.C
@@ -0,0 +1,13 @@
+// { dg-do compile { target c++2a } }
+
+template<typename T>
+ concept C = __is_class(T);
+
+template<C T> struct S;
+
+struct X { };
+
+// Not a valid explicit specialization, int does not satisfy C.
+template<> struct S<int> { }; // { dg-error "constraint failure" }
+
+int main() { }
diff --git a/gcc/testsuite/g++.dg/concepts/explicit-spec4.C b/gcc/testsuite/g++.dg/cpp2a/concepts-explicit-spec4.C
index 75a2dec6f49..0634eafb248 100644
--- a/gcc/testsuite/g++.dg/concepts/explicit-spec4.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-explicit-spec4.C
@@ -1,13 +1,12 @@
-// { dg-do run { target c++17 } }
-// { dg-options "-fconcepts" }
+// { dg-do run { target c++2a } }
#include <cassert>
template<typename T>
- concept bool C() { return __is_class(T); }
+ concept C = __is_class(T);
template<typename T>
- concept bool D() { return C<T>() && __is_empty(T); }
+ concept D = C<T> && __is_empty(T);
struct X { } x;
struct Y { int n; } y;
@@ -17,10 +16,10 @@ int called = 0;
template<typename T>
struct S {
void f() { called = 0; } // #1
- void f() requires C<T>() { called = 0; } // #2
+ void f() requires C<T> { called = 0; } // #2
- void g() requires C<T>() { } // #1
- void g() requires D<T>() { } // #2
+ void g() requires C<T> { } // #1
+ void g() requires D<T> { } // #2
};
template<> void S<int>::f() { called = 1; } // Spec of #1
diff --git a/gcc/testsuite/g++.dg/concepts/explicit-spec5.C b/gcc/testsuite/g++.dg/cpp2a/concepts-explicit-spec5.C
index d83eec11bc2..b682b0d8846 100644
--- a/gcc/testsuite/g++.dg/concepts/explicit-spec5.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-explicit-spec5.C
@@ -1,13 +1,12 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
+// { dg-do compile { target c++2a } }
#include <cassert>
template<typename T>
- concept bool C() { return __is_class(T); }
+ concept C = __is_class(T);
template<typename T>
- concept bool D() { return C<T>() && __is_empty(T); }
+ concept D = C<T> && __is_empty(T);
struct X { } x;
struct Y { int n; } y;
@@ -16,7 +15,7 @@ int called = 0;
template<typename T>
struct S {
- void f() requires C<T>();
+ void f() requires C<T>;
};
template<> void S<int>::f() { called = 1; } // { dg-error "match" }
diff --git a/gcc/testsuite/g++.dg/concepts/explicit-spec6.C b/gcc/testsuite/g++.dg/cpp2a/concepts-explicit-spec6.C
index b5487072e22..13f04d77594 100644
--- a/gcc/testsuite/g++.dg/concepts/explicit-spec6.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-explicit-spec6.C
@@ -1,5 +1,4 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
+// { dg-do compile { target c++2a } }
template<typename T>
struct A {
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-feature-macro.C b/gcc/testsuite/g++.dg/cpp2a/concepts-feature-macro.C
new file mode 100644
index 00000000000..56fbb683868
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-feature-macro.C
@@ -0,0 +1,5 @@
+// { dg-do compile { target c++2a } }
+
+#ifndef __cpp_concepts
+#error __cpp_concepts not defined
+#endif
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-fn1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-fn1.C
new file mode 100644
index 00000000000..33f3a7490bb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-fn1.C
@@ -0,0 +1,248 @@
+// { dg-do compile { target c++2a } }
+
+template<typename T>
+concept Type = true;
+
+template<typename T>
+concept False = false;
+
+template<typename T>
+concept Class = __is_class(T);
+
+template<typename T>
+concept EmptyClass = Class<T> && __is_empty(T);
+
+template<typename T, typename U>
+concept Classes = __is_class(T) && __is_class (U);
+
+struct empty { };
+
+struct nonempty { int n; };
+
+static_assert(Type<int>);
+static_assert(False<int>); // { dg-error "static assertion failed" }
+
+// Basic checks
+
+template<typename T>
+ requires Type<T>
+int fn1(T t) { return 0; }
+
+template<typename T>
+ requires False<T>
+int fn2(T t) { return 0; }
+
+void driver()
+{
+ fn1(0); // OK
+ fn2(0); // { dg-error "cannot call function" }
+}
+
+// Ordering
+
+template<typename T>
+concept Cf = requires (T t) { t.f(); };
+
+template<typename T>
+concept Cfg = Cf<T> && requires (T t) { t.g(); };
+
+template<typename T>
+concept Cf2 = requires (T t) { t.f(); };
+
+template<typename T>
+constexpr int algo(T t) { return 0; }
+
+template<typename T> requires Cf<T>
+constexpr int algo(T t) { return 1; }
+
+template<typename T> requires Cfg<T>
+constexpr int algo(T t) { return 2; }
+
+template<typename T> requires Cf<T>
+constexpr int ambig(T t) { return 1; }
+
+template<typename T> requires Cf2<T>
+constexpr int ambig(T t) { return 1; }
+
+struct T1 {
+ void f() { }
+};
+
+struct T2 : T1 {
+ void g() { }
+};
+
+void driver_0()
+{
+ T1 x;
+ T2 y;
+ static_assert(algo(0) == 0);
+ static_assert(algo(x) == 1);
+ static_assert(algo(y) == 2);
+ ambig(x); // { dg-error "call of overload | is ambiguous" }
+}
+
+template<typename T>
+struct S
+{
+ void f() requires Class<T> { }
+
+ template<typename U>
+ struct Inner
+ {
+ void g() requires Classes<T, U> { }
+ };
+
+ template<typename U> requires Classes<T, U> void h(U) { }
+};
+
+struct X { };
+
+void driver_1()
+{
+ S<X> s1;
+ s1.f(); // OK
+ s1.h(s1); // OK
+ s1.h(0); // { dg-error "no matching function" }
+
+ S<int> s2;
+ s2.f(); // { dg-error "no matching function" }
+
+ S<X>::Inner<X> si1;
+ si1.g();
+
+ S<X>::Inner<int> si2;
+ si2.g(); // { dg-error "no matching function" }
+}
+
+// Check constraints on non-dependent arguments, even when in a
+// dependent context.
+
+template<typename T> requires Class<T> void f1(T x) { }
+
+// fn1-2.C -- Dependent checks
+template<typename T>
+void caller_1(T x)
+{
+ f1(x); // Unchecked dependent arg.
+ f1(empty{}); // Checked non-dependent arg, but OK
+ f1(0); // { dg-error "cannot call function" }
+}
+
+// fn3.c -- Ordering
+template<typename T>
+ requires Class<T>
+constexpr int f2(T x) { return 1; }
+
+template<typename T>
+ requires EmptyClass<T>
+constexpr int f2(T x) { return 2; }
+
+template<typename T>
+constexpr int f3(T x) requires Class<T> { return 1; }
+
+template<typename T>
+constexpr int f3(T x) requires EmptyClass<T> { return 2; }
+
+void driver_2()
+{
+ f2(0); // { dg-error "no matching function" }
+ static_assert (f2(empty{}) == 2);
+ static_assert (f2(nonempty{}) == 1);
+ f3(0); // { dg-error "no matching function" }
+ static_assert (f3(empty{}) == 2);
+ static_assert (f3(nonempty{}) == 1);
+}
+
+// fn8.C -- Address of overloaded functions
+template<typename T> requires Type<T> void ok(T) { }
+template<typename T> requires Class<T> void err(T) { }
+
+auto p1 = &ok<int>;
+auto p2 = &err<int>; // { dg-error "no matches" }
+void (*p3)(int) = &ok<int>;
+void (*p4)(int) = &err<int>; // { dg-error "no matches" }
+void (*p5)(int) = &ok;
+void (*p6)(int) = &err; // { dg-error "no matches" }
+
+template<typename T> void g(T x) { }
+
+void driver_3 ()
+{
+ g(&ok<int>);
+ g(&err<int>); // { dg-error "no matches" }
+}
+
+
+struct S2 {
+ template<typename T> requires Type<T> int ok(T) { return 0; }
+ template<typename T> requires Class<T> int err(T) { return 0; }
+};
+
+auto p7 = &S2::ok<int>;
+auto p8 = &S2::err<int>; // { dg-error "no matches" }
+int (S2::*p9)(int) = &S2::ok<int>;
+int (S2::*p10)(int) = &S2::err<int>; // { dg-error "no matches" }
+int (S2::*p11)(int) = &S2::ok;
+int (S2::*p12)(int) = &S2::err; // { dg-error "no matches" }
+
+// fn9.C -- Ordering with function address
+template<typename T>
+ requires Class<T>
+constexpr int fn(T) { return 1; }
+
+template<typename T>
+ requires EmptyClass<T>
+constexpr int fn(T) { return 2; }
+
+struct S3
+{
+ template<typename T>
+ requires Class<T>
+ constexpr int fn(T) const { return 1; }
+
+ template<typename T>
+ requires EmptyClass<T>
+ constexpr int fn(T) const { return 2; }
+};
+
+void driver_5 () {
+ struct X { };
+ struct Y { X x; };
+
+ constexpr X x;
+ constexpr Y y;
+ constexpr S3 s;
+
+ constexpr auto p1 = &fn<X>; // Empty f
+ static_assert (p1(x) == 2);
+
+ constexpr auto p2 = &fn<Y>; // Class f
+ static_assert(p2(y) == 1);
+
+ constexpr auto p3 = &S3::fn<X>; // Empty f
+ static_assert((s.*p3)(x) == 2);
+
+ constexpr auto p4 = &S3::fn<Y>; // Empty f
+ static_assert((s.*p4)(y) == 1);
+}
+
+
+// Redeclarations
+
+// FIXME: This should be a diagnosable error. The programmer has moved
+// the requirements from the template-head to the declarator.
+template<typename T> requires Type<T> void f3();
+template<typename T> void f3() requires Type<T>;
+
+void driver_4()
+{
+ f3<int>(); // { dg-error "call of overload | ambiguous" }
+}
+
+template<template<typename T> requires true class X> void f4();
+template<template<typename T> class X> void f4(); // OK: different declarations
+
+template<typename T> requires Type<T> void def() { }
+template<typename T> requires Type<T> void def() { } // { dg-error "redefinition" }
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-fn2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-fn2.C
new file mode 100644
index 00000000000..ddf99aa9933
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-fn2.C
@@ -0,0 +1,111 @@
+// { dg-do run { target c++2a } }
+
+#define assert(E) if (!(E)) __builtin_abort();
+
+template<typename T>
+ concept C = __is_class(T);
+
+template<typename T>
+ concept D = __is_empty(T);
+
+struct X { } x;
+struct Y { int n; } y;
+
+int called = 0;
+
+// Test constrained member definitions
+template<typename T>
+ struct S1 {
+ void f1() requires C<T> { }
+
+ void f2() requires C<T> { called = 1; }
+ void f2() requires (!C<T>) { called = 2; }
+
+ void f3() { called = 1; }
+ void f3() requires C<T> { called = 2; }
+ void f3() requires C<T> && D<T> { called = 3; }
+
+ void g1() requires C<T> && true;
+
+ void g2() requires C<T>;
+ void g2() requires (!C<T>);
+
+ void g3();
+ void g3() requires C<T>;
+ void g3() requires C<T> and D<T>;
+
+ template<C U> void h1(U u) { called = 1; }
+ template<C U> void h2(U u);
+ template<C U> void h3(U u) requires D<U>;
+ };
+
+template<C T>
+ struct S2 {
+ void f(T) requires D<T>;
+ };
+
+
+int main() {
+ S1<X> sx;
+ S1<Y> sy;
+ S1<int> si;
+
+ // Defined in-class
+ sx.f1();
+ sx.f2(); assert(called == 1);
+ sx.f3(); assert(called == 3);
+
+ sy.f1();
+ sy.f2(); assert(called == 1);
+ sy.f3(); assert(called == 2);
+
+ si.f2(); assert(called == 2);
+ si.f3(); assert(called == 1);
+
+ // Member function template tests
+ S1<int> s1i;
+ s1i.h1(x); assert(called == 1);
+ s1i.h2(x); assert(called == 2);
+ s1i.h3(x); assert(called == 3);
+
+ // Defined out of class.
+ sx.g1();
+ sx.g2(); assert(called == 1);
+ sx.g3(); assert(called == 3);
+
+ sy.g1();
+ sy.g2(); assert(called == 1);
+ sy.g3(); assert(called == 2);
+
+ si.g2(); assert(called == 2);
+ si.g3(); assert(called == 1);
+}
+
+template<typename T>
+ void S1<T>::g1() requires C<T> and true { }
+
+template<typename T>
+ void S1<T>::g2() requires C<T> { called = 1; }
+
+template<typename T>
+ void S1<T>::g2() requires (!C<T>) { called = 2; }
+
+template<typename T>
+ void S1<T>::g3() { called = 1; }
+
+template<typename T>
+ void S1<T>::g3() requires C<T> { called = 2; }
+
+template<typename T>
+ void S1<T>::g3() requires C<T> and D<T> { called = 3; }
+
+template<typename T>
+ template<C U>
+ void S1<T>::h2(U u) { called = 2; }
+
+template<typename T>
+ template<C U>
+ void S1<T>::h3(U u) requires D<U> { called = 3; }
+
+template<C T>
+ void S2<T>::f(T t) requires D<T> { called = 4; }
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-fn3.C b/gcc/testsuite/g++.dg/cpp2a/concepts-fn3.C
new file mode 100644
index 00000000000..e73ae23881a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-fn3.C
@@ -0,0 +1,49 @@
+// { dg-do compile { target c++2a } }
+
+template<typename T>
+concept type = true;
+
+template<typename T, typename U>
+concept same_as = __is_same_as(T, U);
+
+template<typename T>
+concept integral = __is_same_as(T, int);
+
+template<typename... Ts>
+concept all_integral = (integral<Ts> && ...);
+
+void f1(integral auto... args) { }
+void f2(all_integral auto... args) { }
+
+template<type T> requires true
+void f3(T, integral auto... args) { }
+
+template<type T>
+struct S
+{
+ void f1(integral auto... args) { }
+ void f2(all_integral auto... args) { }
+
+ template<type U> requires true
+ void f3(U, integral auto... args) { }
+};
+
+int main()
+{
+ f1(1, 2, 3);
+ f1(1, 2, 3u); // { dg-error "cannot call" }
+ f2(1, 2, 3);
+ f2(1, 2, 3u); // { dg-error "cannot call" }
+ f3(1, 2, 3);
+ f3(1, 2, 3u); // { dg-error "cannot call" }
+ f3(1u, 2, 3);
+
+ S<void> s;
+ s.f1(1, 2, 3);
+ s.f1(1, 2, 3u); // { dg-error "no matching function" }
+ s.f2(1, 2, 3);
+ s.f2(1, 2, 3u); // { dg-error "no matching function" }
+ s.f3(1, 2, 3);
+ s.f3(1, 2, 3u); // { dg-error "no matching function" }
+ s.f3(1u, 2, 3);
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-fnparm1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-fnparm1.C
new file mode 100644
index 00000000000..586b510c796
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-fnparm1.C
@@ -0,0 +1,10 @@
+// { dg-do compile { target concepts } }
+
+template <class T> void f(T t)
+ requires requires { static_cast<T&&>(t); }
+{}
+
+int main()
+{
+ f(42);
+}
diff --git a/gcc/testsuite/g++.dg/concepts/friend1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-friend1.C
index 9050b557b3b..da97575687f 100644
--- a/gcc/testsuite/g++.dg/concepts/friend1.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-friend1.C
@@ -1,8 +1,7 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
+// { dg-do compile { target c++2a } }
template<typename T>
- concept bool Eq() { return requires(T t) { t == t; }; }
+ concept Eq = requires(T t) { t == t; }; // { dg-message "in requirements" }
struct Nt {
template<Eq T> friend void f(T) { }
@@ -15,7 +14,7 @@ template<Eq T>
template<typename T>
struct S {
- friend bool operator==(S, S) requires Eq<T>() { return true; }
+ friend bool operator==(S, S) requires Eq<T> { return true; }
friend void proc<>(S*); // { dg-error "does not match any template declaration" }
};
diff --git a/gcc/testsuite/g++.dg/concepts/friend2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-friend2.C
index 8ef600222e5..6aa9d961779 100644
--- a/gcc/testsuite/g++.dg/concepts/friend2.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-friend2.C
@@ -1,8 +1,7 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
+// { dg-do compile { target c++2a } }
template<typename T>
- concept bool Eq() { return requires(T t) { t == t; }; }
+ concept Eq = requires(T t) { t == t; }; // { dg-message "in requirements" }
template<Eq T> struct Foo { };
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-friend3.C b/gcc/testsuite/g++.dg/cpp2a/concepts-friend3.C
new file mode 100644
index 00000000000..4f49358ed7d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-friend3.C
@@ -0,0 +1,20 @@
+// { dg-do compile { target concepts } }
+
+template <class T> concept True = true;
+
+template <True U> struct B { int i = ++U::x; };
+template <True U> void f() { ++U::x; }
+
+template <class V> class C
+{
+ static int x;
+
+ template <True U> friend struct B;
+ template <True U> friend void f();
+};
+
+int main()
+{
+ f<C<int>>();
+ B<C<int>>();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-iconv1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-iconv1.C
new file mode 100644
index 00000000000..cc2ce7e321d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-iconv1.C
@@ -0,0 +1,22 @@
+// PR c++/67240
+// { dg-do compile { target c++2a } }
+
+template <class T, class U> concept Same = __is_same_as(T,U);
+
+int foo(int x)
+{
+ return x;
+}
+
+template <typename T>
+concept C1 = requires (T x) {
+ {foo(x)} -> Same<int&>;
+};
+
+template <typename T>
+concept C2 = requires (T x) {
+ {foo(x)} -> Same<void>;
+};
+
+static_assert( C1<int> ); // { dg-error "assert" }
+static_assert( C2<int> ); // { dg-error "assert" }
diff --git a/gcc/testsuite/g++.dg/concepts/inherit-ctor2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor2.C
index cb81d13e6d9..aa244bc04c1 100644
--- a/gcc/testsuite/g++.dg/concepts/inherit-ctor2.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor2.C
@@ -1,12 +1,11 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
+// { dg-do compile { target c++2a } }
template<typename T>
- concept bool C() { return __is_class(T); }
+ concept C = __is_class(T);
template<typename T>
struct S1 {
- S1(double) requires C<T>() { }
+ S1(double) requires C<T> { }
};
template<typename T>
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor4.C b/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor4.C
new file mode 100644
index 00000000000..75190eb3413
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor4.C
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++2a } }
+
+template<typename T>
+ concept C = __is_class(T);
+
+template<typename T>
+ struct S1 {
+ template<C U> S1(U x) { }
+ };
+
+template<typename T>
+ struct S2 : S1<T> {
+ using S1<T>::S1; // { dg-error "no matching function" }
+ };
+
+int main() {
+ S2<int> s(0); // { dg-error "use of deleted function" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor5.C b/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor5.C
new file mode 100644
index 00000000000..2044ab59f4c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor5.C
@@ -0,0 +1,18 @@
+// { dg-do compile { target concepts } }
+
+template <class T> struct A
+{
+ constexpr A(T) requires (sizeof(T) > 1) {}
+
+ A(T);
+};
+
+template <class T> struct B: A<T>
+{
+ using A<T>::A;
+};
+
+int main()
+{
+ constexpr B<int> b = 42;
+}
diff --git a/gcc/testsuite/g++.dg/concepts/lambda1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda1.C
index a77e65459b7..ef1968899f6 100644
--- a/gcc/testsuite/g++.dg/concepts/lambda1.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda1.C
@@ -1,6 +1,5 @@
// PR c++/82565
-// { dg-do compile { target c++14 } }
-// { dg-additional-options -fconcepts }
+// { dg-do compile { target c++2a } }
struct string
{
@@ -9,18 +8,20 @@ struct string
bool empty() const;
};
+template<class From, class To>
+concept convertible_to = requires(From (&f)(), void (&g)(To)) { g(f()); };
+
template<typename T, typename ReturnType>
-concept bool Concept() {
- return requires(T t, const string& s) {
- { t(s) } -> ReturnType;
+concept Concept =
+ requires(T t, const string& s) {
+ { t(s) } -> convertible_to<ReturnType>;
};
-}
struct test {
string _str;
template<typename Visitor>
- requires Concept<Visitor, bool>()
+ requires Concept<Visitor, bool>
decltype(auto) visit(Visitor&& visitor) const {
return visitor(_str);
}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-locations1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-locations1.C
new file mode 100644
index 00000000000..6c81c1476ab
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-locations1.C
@@ -0,0 +1,22 @@
+// { dg-do compile { target c++2a } }
+
+struct S
+{
+ concept S(); // { dg-error "3:a constructor cannot be .concept." }
+ // { dg-error "concept definition syntax" "" { target *-*-* } .-1 }
+ concept int s = 1; // { dg-error "3:non-static data member .s. declared .concept." }
+ // { dg-error "concept definition syntax" "" { target *-*-* } .-1 }
+ concept void foo(); // { dg-error "3:a concept cannot be a member function" }
+ // { dg-error "concept definition syntax" "" { target *-*-* } .-1 }
+ concept ~S(); // { dg-error "3:a destructor cannot be .concept." }
+ // { dg-error "concept definition syntax" "" { target *-*-* } .-1 }
+};
+
+typedef concept int my_int; // { dg-error "9:.concept. cannot appear in a typedef declaration" }
+// { dg-error "concept definition syntax" "" { target *-*-* } .-1 }
+
+void bar(concept int); // { dg-error "10:a parameter cannot be declared .concept." }
+// { dg-error "concept definition syntax" "" { target *-*-* } .-1 }
+
+concept int i = 0; // { dg-error "1:a non-template variable cannot be .concept." }
+// { dg-error "concept definition syntax" "" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-member-concept.C b/gcc/testsuite/g++.dg/cpp2a/concepts-member-concept.C
new file mode 100644
index 00000000000..f3a2d064dbd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-member-concept.C
@@ -0,0 +1,21 @@
+// { dg-do compile { target c++2a } }
+
+// FIXME: Diagnostics should be better.
+
+struct Base {
+ template<typename T>
+ static concept D = __is_same_as(T, int); // { dg-error "static data member" }
+
+ template<typename T, typename U>
+ static concept E = __is_same_as(T, U); // { dg-error "static data member" }
+
+ template<typename T>
+ concept C1 = __is_same_as(T, int); // { dg-error "not in namespace scope" }
+};
+
+union U {
+ template<typename T>
+ concept C = true; // // { dg-error "not in namespace scope" }
+};
+
+// { dg-excess-errors "deprecated" }
diff --git a/gcc/testsuite/g++.dg/concepts/memfun-err.C b/gcc/testsuite/g++.dg/cpp2a/concepts-memfun-err.C
index 6e1ad00c5cf..acfa188af21 100644
--- a/gcc/testsuite/g++.dg/concepts/memfun-err.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-memfun-err.C
@@ -1,12 +1,10 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
-
+// { dg-do compile { target c++2a } }
template<typename T>
- concept bool C() { return __is_class(T); }
+ concept C = __is_class(T);
template<typename T>
- concept bool D() { return __is_empty(T); }
+ concept D = __is_empty(T);
struct X { } x;
struct Y { int n; } y;
@@ -16,15 +14,15 @@ int called = 0;
// Test constrained member definitions
template<typename T>
struct S1 { // { dg-message "defined here" }
- void f1() requires C<T>() { }
- void g1() requires C<T>() and true;
+ void f1() requires C<T> { }
+ void g1() requires C<T> and true;
template<C U> void h1(U u) { called = 1; }
- void g2() requires C<T>(); // { dg-message "candidate" }
+ void g2() requires C<T>; // { dg-message "candidate" }
};
template<typename T>
- void S1<T>::g2() requires D<T>() { } // { dg-error "no declaration matches" }
+ void S1<T>::g2() requires D<T> { } // { dg-error "no declaration matches" }
int main() {
S1<X> sx;
diff --git a/gcc/testsuite/g++.dg/concepts/memfun.C b/gcc/testsuite/g++.dg/cpp2a/concepts-memfun.C
index 818c7e61c8a..f6ad5196352 100644
--- a/gcc/testsuite/g++.dg/concepts/memfun.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-memfun.C
@@ -1,13 +1,12 @@
-// { dg-do run { target c++17 } }
-// { dg-options "-fconcepts" }
+// { dg-do run { target c++2a } }
#include <cassert>
template<typename T>
- concept bool C() { return __is_class(T); }
+ concept C = __is_class(T);
template<typename T>
- concept bool D() { return __is_empty(T); }
+ concept D = __is_empty(T);
struct X { } x;
struct Y { int n; } y;
@@ -17,32 +16,32 @@ int called = 0;
// Test constrained member definitions
template<typename T>
struct S1 {
- void f1() requires C<T>() { }
+ void f1() requires C<T> { }
- void f2() requires C<T>() { called = 1; }
- void f2() requires not C<T>() { called = 2; }
+ void f2() requires C<T> { called = 1; }
+ void f2() requires (not C<T>) { called = 2; }
void f3() { called = 1; }
- void f3() requires C<T>() { called = 2; }
- void f3() requires C<T>() and D<T>() { called = 3; }
+ void f3() requires C<T> { called = 2; }
+ void f3() requires C<T> and D<T> { called = 3; }
- void g1() requires C<T>() and true;
+ void g1() requires C<T> and true;
- void g2() requires C<T>();
- void g2() requires not C<T>();
+ void g2() requires C<T>;
+ void g2() requires (not C<T>);
void g3();
- void g3() requires C<T>();
- void g3() requires C<T>() and D<T>();
+ void g3() requires C<T>;
+ void g3() requires C<T> and D<T>;
template<C U> void h1(U u) { called = 1; }
template<C U> void h2(U u);
- template<C U> void h3(U u) requires D<U>();
+ template<C U> void h3(U u) requires D<U>;
};
template<C T>
struct S2 {
- void f(T) requires D<T>();
+ void f(T) requires D<T>;
};
@@ -83,22 +82,22 @@ int main() {
}
template<typename T>
- void S1<T>::g1() requires C<T>() and true { }
+ void S1<T>::g1() requires C<T> and true { }
template<typename T>
- void S1<T>::g2() requires C<T>() { called = 1; }
+ void S1<T>::g2() requires C<T> { called = 1; }
template<typename T>
- void S1<T>::g2() requires not C<T>() { called = 2; }
+ void S1<T>::g2() requires (not C<T>) { called = 2; }
template<typename T>
void S1<T>::g3() { called = 1; }
template<typename T>
- void S1<T>::g3() requires C<T>() { called = 2; }
+ void S1<T>::g3() requires C<T> { called = 2; }
template<typename T>
- void S1<T>::g3() requires C<T>() and D<T>() { called = 3; }
+ void S1<T>::g3() requires C<T> and D<T> { called = 3; }
template<typename T>
template<C U>
@@ -106,7 +105,7 @@ template<typename T>
template<typename T>
template<C U>
- void S1<T>::h3(U u) requires D<U>() { called = 3; }
+ void S1<T>::h3(U u) requires D<U> { called = 3; }
template<C T>
- void S2<T>::f(T t) requires D<T>() { called = 4; }
+ void S2<T>::f(T t) requires D<T> { called = 4; }
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-memtmpl1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-memtmpl1.C
new file mode 100644
index 00000000000..ee28d5b7754
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-memtmpl1.C
@@ -0,0 +1,17 @@
+// { dg-do compile { target c++2a } }
+
+template <class T>
+struct A {
+ template <class U>
+ requires (sizeof(T) == 1)
+ static void f(U);
+
+ template <class U>
+ requires (sizeof(T) == 2)
+ static void f(U);
+
+ void g()
+ {
+ f(42);
+ }
+};
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-memtmpl2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-memtmpl2.C
new file mode 100644
index 00000000000..f60b220702d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-memtmpl2.C
@@ -0,0 +1,15 @@
+// { dg-do compile { target concepts } }
+
+template <class T, class U> concept NotSame = !__is_same_as (T, U);
+
+template <class T, class X>
+struct A
+{
+ template <NotSame<A> U> void f(U) { }
+ template <class U> void f(U);
+};
+
+int main()
+{
+ A<int,int>().f<char>(0);
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-nested1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-nested1.C
new file mode 100644
index 00000000000..8fc965fa800
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-nested1.C
@@ -0,0 +1,13 @@
+// { dg-do compile { target concepts } }
+
+namespace N { template <class T> concept True = true; }
+template <class T> struct A { };
+
+template <class T>
+requires N::True<T> && requires { typename A<T>; }
+void f();
+
+int main()
+{
+ f<int>();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-noexcept1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-noexcept1.C
new file mode 100644
index 00000000000..e5a9b72b4fd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-noexcept1.C
@@ -0,0 +1,25 @@
+// { dg-do compile { target c++2a } }
+
+void f1(int);
+void f2(int) noexcept;
+
+template<typename T>
+concept C1 = requires (T t) { // { dg-message "in requirements" }
+ { f1(t) } noexcept;
+};
+
+template<typename T>
+concept C2 = requires (T t) {
+ { f2(t) } noexcept;
+};
+
+template<C1 T>
+void g1(T t);
+
+template<C2 T>
+void g2(T t);
+
+void test() {
+ g1(0); // { dg-error "cannot call" }
+ g2(0);
+} \ No newline at end of file
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-p1141.C b/gcc/testsuite/g++.dg/cpp2a/concepts-p1141.C
new file mode 100644
index 00000000000..deb409aa12c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-p1141.C
@@ -0,0 +1,98 @@
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+template<typename T>
+concept Type = true;
+
+template<typename T>
+concept Bottom = false;
+
+template<typename T>
+concept Class = __is_class(T);
+
+template<auto N>
+concept Number = true;
+
+template<template<typename> class T>
+concept Template = true;
+
+struct empty { };
+
+Type x1 = 0; // { dg-error "expected 'auto'" }
+Type auto x2 = 0;
+
+Number x3 = 0; // { dg-error "does not constrain a type" }
+Template x4 = 0; // { dg-error "does not constrain a type" }
+
+Type const& x5 = 0; // { dg-error "expected 'auto'" }
+const Type& x6 = 0; // { dg-error "expected 'auto'" }
+Type auto const& x7 = 0;
+const Type auto& x8 = 0;
+Type const auto& x9 = 0; // { dg-error "expected 'auto'|two or more data types" }
+
+template<Type T> // OK: T is a type parameter.
+void f1(T);
+
+template<Number N> // { dg-error "does not constrain a type" }
+void f2();
+
+template<Template X> // { dg-error "does not constrain a type" }
+void f3();
+
+template<Type auto N> // OK: N is a non-type parameter.
+void f4() { }
+
+template<Bottom auto N> // OK: but never usable.
+void f5();
+
+void driver() {
+ f4<0>();
+ f5<0>(); // { dg-error "no matching function for call | constraints not satisfied" }
+}
+
+Type f6() { return 0; } // { dg-error "expected 'auto'" }
+static_assert(__is_same_as(decltype(f6), int()));
+
+Type auto f7() { return 0; }
+static_assert(__is_same_as(decltype(f7), int()));
+
+Type f8() { return 0; } // { dg-error "expected 'auto'" }
+auto f9() -> Type { return 0; } // { dg-error "expected 'auto'" }
+
+Type f10() { } // { dg-error "expected 'auto'" }
+auto f11() -> Type { } // { dg-error "expected" }
+
+Number f12(); // { dg-error "does not constrain a type" }
+auto f13() -> Number; // { dg-error "does not constrain a type" }
+
+Template f14(); // { dg-error "does not constrain a type" }
+auto f15() -> Template; // { dg-error "does not constrain a type" }
+
+Type f16() { return 0; } // { dg-error "expected 'auto'" }
+auto f17() -> Type { return 0; } // { dg-error "expected 'auto'" }
+
+// Abbreviated function templates
+
+void f18(Class x) { } // { dg-error "expected 'auto'" }
+void f19(Class auto x) { }
+void f20(Class auto x, Class auto y) { }
+
+void driver_1()
+{
+ f19(0); // { dg-error "cannot call function" }
+ f19(empty{});
+ f20(0, empty{}); // { dg-error "cannot call function" }
+ f20(empty{}, empty{});
+}
+
+// Abbreviated function redeclarations
+
+// Functionally equivalent but not equivalent.
+void f21(Class auto x);
+template<Class T> void f21(T x);
+
+void driver_2()
+{
+ f21(empty{}); // { dg-error "call of overload | ambiguous" }
+}
+
diff --git a/gcc/testsuite/g++.dg/concepts/partial-spec.C b/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec.C
index 0ff8ec2fa1a..25b4e2a4000 100644
--- a/gcc/testsuite/g++.dg/concepts/partial-spec.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
// { dg-options "-fconcepts" }
// Check that constraints don't break unconstrained partial
diff --git a/gcc/testsuite/g++.dg/concepts/partial-spec2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec2.C
index 2449c37fc99..566d8dd55b6 100644
--- a/gcc/testsuite/g++.dg/concepts/partial-spec2.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec2.C
@@ -1,6 +1,11 @@
// PR c++/67084
// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
+// { dg-additional-options "-fconcepts" }
+
+template <class T>
+concept True = true;
+template <class T>
+concept False = false;
template <class T>
constexpr bool p = false;
@@ -9,11 +14,11 @@ template <class T>
constexpr bool p<T*> = false;
template <class T>
- requires true
+ requires True<T>
constexpr bool p<T*> = false;
template <class T>
- requires true && T() == 0
+ requires True<T> && (T() == 0)
constexpr bool p<T*> = true;
template <class T>
@@ -23,11 +28,11 @@ template <class T>
constexpr bool q<T*> = true;
template <class T>
- requires false
+ requires False<T>
constexpr bool q<T*> = false;
template <class T>
- requires false && T() != 0
+ requires False<T> && (T() != 0)
constexpr bool q<T*> = false;
static_assert (p<int*>,"");
diff --git a/gcc/testsuite/g++.dg/concepts/partial-spec3.C b/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec3.C
index d4071814909..2970af100f9 100644
--- a/gcc/testsuite/g++.dg/concepts/partial-spec3.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec3.C
@@ -1,5 +1,5 @@
// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
+// { dg-additional-options "-fconcepts" }
template <class T> struct A { };
template <class T> requires false struct A<T*> { };
diff --git a/gcc/testsuite/g++.dg/concepts/partial-spec4.C b/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec4.C
index 70461b4370f..5ba3ab19c23 100644
--- a/gcc/testsuite/g++.dg/concepts/partial-spec4.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec4.C
@@ -1,7 +1,6 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
+// { dg-do compile { target c++2a } }
-template <class T> concept bool is_int = __is_same_as(T,int);
+template <class T> concept is_int = __is_same_as(T,int);
template <class T> struct A { };
template <is_int T> struct A<T*> {
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec5.C b/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec5.C
new file mode 100644
index 00000000000..f33f74969b7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec5.C
@@ -0,0 +1,12 @@
+// PR c++/67138
+// { dg-do compile { target c++2a } }
+
+template <class T>
+concept Auto = true;
+
+template <Auto T>
+struct test {};
+
+template <Auto T>
+ requires requires (T t) { t + t; }
+struct test<T> {};
diff --git a/gcc/testsuite/g++.dg/concepts/partial-spec6.C b/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec6.C
index 1d80ee36e5c..2bb4bacb2ef 100644
--- a/gcc/testsuite/g++.dg/concepts/partial-spec6.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec6.C
@@ -1,9 +1,8 @@
// PR c++/67152
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
+// { dg-do compile { target c++2a } }
template <class T>
-concept bool HasType = requires { typename T::type; };
+concept HasType = requires { typename T::type; };
template<class T>
struct trait {
@@ -19,7 +18,7 @@ trait<has_type>::type foo() {}
// constraint so this partial specialization would not have been
// selected.
template<class T>
- requires !HasType<T>
+ requires (!HasType<T>)
struct trait<T> {
using type = void;
};
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder1.C
new file mode 100644
index 00000000000..cbea81d6b21
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder1.C
@@ -0,0 +1,14 @@
+// { dg-do compile { target c++2a } }
+
+template<class T, class U>
+concept Same = __is_same_as(T, U);
+
+template<typename T>
+concept C1 = true;
+
+template<typename T, typename U>
+concept C2 = true;
+
+C1 auto c1 = 0;
+C2<int> auto c2 = 0;
+Same<int> auto s1 = 'a'; // { dg-error "does not satisfy|is_same" }
diff --git a/gcc/testsuite/g++.dg/concepts/pr58500.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr58500.C
index cb74072a570..cb74072a570 100644
--- a/gcc/testsuite/g++.dg/concepts/pr58500.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr58500.C
diff --git a/gcc/testsuite/g++.dg/concepts/pr58534.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr58534.C
index b2c3caac63c..b2c3caac63c 100644
--- a/gcc/testsuite/g++.dg/concepts/pr58534.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr58534.C
diff --git a/gcc/testsuite/g++.dg/concepts/pr58535.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr58535.C
index 3e212a0ffd7..3e212a0ffd7 100644
--- a/gcc/testsuite/g++.dg/concepts/pr58535.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr58535.C
diff --git a/gcc/testsuite/g++.dg/concepts/pr58536.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr58536.C
index 99c7ebee309..99c7ebee309 100644
--- a/gcc/testsuite/g++.dg/concepts/pr58536.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr58536.C
diff --git a/gcc/testsuite/g++.dg/concepts/pr58548.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr58548.C
index cd3e6fdb2dc..cd3e6fdb2dc 100644
--- a/gcc/testsuite/g++.dg/concepts/pr58548.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr58548.C
diff --git a/gcc/testsuite/g++.dg/concepts/pr58549.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr58549.C
index 6b66afc1ad2..6b66afc1ad2 100644
--- a/gcc/testsuite/g++.dg/concepts/pr58549.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr58549.C
diff --git a/gcc/testsuite/g++.dg/concepts/regress/alias-decl-42.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr59200.C
index 6d5a4d5fdea..995672c0694 100644
--- a/gcc/testsuite/g++.dg/concepts/regress/alias-decl-42.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr59200.C
@@ -1,5 +1,6 @@
// PR c++/59200
-// { dg-options "-std=c++17 -fconcepts" }
+// { dg-do compile { target c++17 } }
+// { dg-additional-options "-fconcepts" }
struct A
{
diff --git a/gcc/testsuite/g++.dg/concepts/pr60052.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr60052.C
index c5bc28efd07..c5bc28efd07 100644
--- a/gcc/testsuite/g++.dg/concepts/pr60052.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr60052.C
diff --git a/gcc/testsuite/g++.dg/concepts/pr60053.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr60053.C
index 20cf1216b0e..20cf1216b0e 100644
--- a/gcc/testsuite/g++.dg/concepts/pr60053.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr60053.C
diff --git a/gcc/testsuite/g++.dg/concepts/pr60064.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr60064.C
index b82b560d1f5..b82b560d1f5 100644
--- a/gcc/testsuite/g++.dg/concepts/pr60064.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr60064.C
diff --git a/gcc/testsuite/g++.dg/concepts/pr60065.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr60065.C
index b2b1aea433e..b2b1aea433e 100644
--- a/gcc/testsuite/g++.dg/concepts/pr60065.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr60065.C
diff --git a/gcc/testsuite/g++.dg/concepts/pr60377.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr60377.C
index 5b1871735c8..5b1871735c8 100644
--- a/gcc/testsuite/g++.dg/concepts/pr60377.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr60377.C
diff --git a/gcc/testsuite/g++.dg/concepts/pr60390.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr60390.C
index a453d1d61a3..a453d1d61a3 100644
--- a/gcc/testsuite/g++.dg/concepts/pr60390.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr60390.C
diff --git a/gcc/testsuite/g++.dg/concepts/pr60391.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr60391.C
index 5c5ca2c2381..5c5ca2c2381 100644
--- a/gcc/testsuite/g++.dg/concepts/pr60391.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr60391.C
diff --git a/gcc/testsuite/g++.dg/concepts/pr60573.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr60573.C
index 42cda21ef74..42cda21ef74 100644
--- a/gcc/testsuite/g++.dg/concepts/pr60573.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr60573.C
diff --git a/gcc/testsuite/g++.dg/concepts/pr65552.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr65552.C
index 318fdccfbdc..5af2a40e9a3 100644
--- a/gcc/testsuite/g++.dg/concepts/pr65552.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr65552.C
@@ -1,13 +1,11 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
+// { dg-do compile { target c++2a } }
template<typename T>
-concept bool Concept() {
- return requires () {
+concept Concept =
+ requires () {
typename T::member_type1;
typename T::member_type2;
};
-}
struct model {
using member_type1 = int;
diff --git a/gcc/testsuite/g++.dg/concepts/pr65575.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr65575.C
index efaf958121b..3bfde5e2c75 100644
--- a/gcc/testsuite/g++.dg/concepts/pr65575.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr65575.C
@@ -1,5 +1,6 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
+// PR c++/65575
+// { dg-do compile { target c++17_only } }
+// { dg-additional-options "-fconcepts" }
template<typename T>
concept bool C = false;
@@ -11,12 +12,10 @@ auto f4() -> int& requires false;
auto f5() -> int* requires false;
auto f6() -> int requires false;
-int (*p)() requires true; // { dg-error "" }
-int (&p)() requires true; // { dg-error "" }
+int (*p1)() requires true; // { dg-error "" }
+int (&p2)() requires true; // { dg-error "" }
int g(int (*)() requires true); // { dg-error "" }
-int f() { return 0; }
-
int
main()
{
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr65634.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr65634.C
new file mode 100644
index 00000000000..52f24ec90be
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr65634.C
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++2a } }
+
+template<typename T>
+concept C1 =
+ requires () {
+ { T::smf() } noexcept;
+ };
+
+struct M1 {
+ static void smf() noexcept;
+};
+template<typename T>
+concept C2 = C1<typename T::type>;
+
+struct M2 {
+ using type = M1;
+};
+static_assert(C2<M2>, "");
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr65636.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr65636.C
new file mode 100644
index 00000000000..b99a3433f6c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr65636.C
@@ -0,0 +1,8 @@
+// { dg-do compile { target c++2a } }
+
+using TD = int;
+
+template<typename T>
+concept C = requires () { typename TD; };
+
+static_assert(C<int>, "");
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr65848.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr65848.C
new file mode 100644
index 00000000000..b246d254bc3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr65848.C
@@ -0,0 +1,59 @@
+// { dg-do compile { target c++2a } }
+
+// Performance test... This should be fast.
+
+#include <type_traits>
+
+template<typename T>
+concept Destructible = std::is_destructible<T>::value;
+template<typename T, typename... Args>
+concept Constructible = Destructible<T> && std::is_constructible<T, Args...>::value;
+template<typename T>
+concept Move_constructible = Constructible<T, T&&>;
+template<typename T>
+concept Copy_constructible = Move_constructible<T> && Constructible<T, const T&>;
+template<typename T, typename U>
+concept Assignable = std::is_assignable<T, U>::value;
+template<typename T>
+concept Move_assignable = Assignable<T&, T&&>;
+template<typename T>
+concept Copy_assignable = Move_assignable<T> && Assignable<T&, const T&>;
+template<typename T>
+concept Copyable = Copy_constructible<T> && Copy_assignable<T>;
+
+template<typename T>
+concept C1 = Copyable<T>;
+template<typename T>
+concept C2 = C1<T>;
+template<typename T>
+concept C3 = C2<T>;
+template<typename T>
+concept C4 = C3<T>;
+template<typename T>
+concept C5 = C4<T>;
+template<typename T>
+concept C6 = C5<T>;
+template<typename T>
+concept C7 = C6<T>;
+template<typename T>
+concept C8 = C7<T>;
+template<typename T>
+concept C9 = C8<T>;
+template<typename T>
+concept C10 = C9<T>;
+template<typename T>
+concept C11 = C10<T>;
+
+struct S1 {};
+struct S2 {};
+struct S3 {};
+struct S4 {};
+struct S5 {};
+struct S6 {};
+
+static_assert(C11<S1>, "");
+static_assert(C11<S2>, "");
+static_assert(C11<S3>, "");
+static_assert(C11<S4>, "");
+static_assert(C11<S5>, "");
+static_assert(C11<S6>, "");
diff --git a/gcc/testsuite/g++.dg/concepts/pr65854.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr65854.C
index 28eac885a46..a21073c4d67 100644
--- a/gcc/testsuite/g++.dg/concepts/pr65854.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr65854.C
@@ -1,5 +1,5 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
+// PR c++/65854
+// { dg-do compile { target c++2a } }
// Handle alias templates in type requirements.
@@ -13,13 +13,10 @@ template<typename T1, typename T2>
using Alias1 = typename BTT<T1, T2>::type;
template<typename T1, typename T2>
-concept bool C()
-{
- return requires() { typename Alias1<T1, T2>; };
-}
+concept C = requires() { typename Alias1<T1, T2>; }; // { dg-message "in requirements" }
template<typename T1, typename T2>
- requires C<T1, T2>()
+ requires C<T1, T2>
int f();
auto i = f<char, int>(); // { dg-error "cannot call function" }
diff --git a/gcc/testsuite/g++.dg/concepts/pr66091.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr66091.C
index a71cd7b8bee..ea51e31817e 100644
--- a/gcc/testsuite/g++.dg/concepts/pr66091.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr66091.C
@@ -1,5 +1,6 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
+// PR c++/66091
+// { dg-do compile { target c++17_only } }
+// { dg-additional-options "-fconcepts" }
template<typename T>
concept bool C1()
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr66844.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr66844.C
new file mode 100644
index 00000000000..64baab1dca0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr66844.C
@@ -0,0 +1,16 @@
+// PR c++/66844
+// { dg-do compile { target c++2a } }
+
+template <class T, class U>
+concept Same = __is_same_as(T, U);
+
+template <class T>
+concept C = requires (T t) { // { dg-error "invalid parameter|in requirements" }
+ requires Same<decltype(t),void>;
+ };
+
+template <typename T>
+ requires C<T>
+constexpr bool is_c() { return true; }
+
+static_assert(is_c<void>(), ""); // { dg-error "cannot call" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr66962.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr66962.C
new file mode 100644
index 00000000000..ca57a0915f1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr66962.C
@@ -0,0 +1,80 @@
+// PR c++/66962
+// { dg-do compile { target c++2a } }
+
+template <typename> struct remove_cv;
+template <typename> struct is_reference;
+template <typename> void declval();
+template <typename> struct is_constructible;
+template <typename> struct is_nothrow_constructible;
+template <typename _Tp> using remove_cv_t = typename remove_cv<_Tp>::type;
+template <typename> struct Trans_NS_extension_apply_list;
+template <typename T> using _t = typename T::type;
+template <class> void ImplicitlyConvertibleTo();
+template <class> void Assignable();
+template <class T, class... Args> int ConstructibleObject = requires { T{}; };
+
+template <class T, class... Args>
+concept BindableReference =
+ is_reference<T>::value && is_constructible<T>::value;
+
+template <class T, class... Args>
+concept Constructible =
+ ConstructibleObject<T> || BindableReference<T, Args...>;
+
+template <class T>
+concept DefaultConstructible =
+ Constructible<T> && requires { new T[0]; };
+
+template <class T>
+concept MoveConstructible =
+ Constructible<T> && ImplicitlyConvertibleTo<T>;
+
+template <class T>
+concept Movable =
+ MoveConstructible<T> && Assignable<T &&>;
+
+template <class, class>
+int Swappable_ = requires { 0; };
+
+template <class T, class U>
+int Swappable();
+
+template <class T>
+concept Dereferencable = requires{{0};};
+
+template <Dereferencable R>
+using RvalueReferenceType = decltype(0);
+
+template <class T>
+int IsValueType;
+
+template <class>
+struct value_type;
+
+template <class T>
+ requires IsValueType<_t<value_type<remove_cv_t<T>>>>
+using ValueType = _t<value_type<remove_cv_t<T>>>;
+
+template <class I>
+concept Readable =
+ Movable<I> && DefaultConstructible<I> && Dereferencable<const I> && requires{{0};};
+
+template <class Out, class T>
+concept MoveWritable =
+ Movable<Out> && DefaultConstructible<Out> && Dereferencable<Out>;
+
+template <class In, class Out>
+concept IndirectlyMovable =
+ Readable<In> &&
+ Movable<ValueType<In>> &&
+ Constructible<ValueType<In>> &&
+ MoveWritable<Out, RvalueReferenceType<In>> &&
+ MoveWritable<Out, ValueType<In>>;
+
+template<typename In, typename Out>
+ requires IndirectlyMovable<In, Out>
+int is_nothrow_indirectly_movable_v = is_nothrow_constructible<ValueType<In>>::value;
+
+template <Readable R1, Readable R2>
+ requires IndirectlyMovable<R1, R2> && IndirectlyMovable<R2, R1>
+void iter_swap2();
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr67070.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67070.C
new file mode 100644
index 00000000000..548cb402fac
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67070.C
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++2a } }
+
+template <class T>
+concept C1 =
+ requires { typename T::type; } && T::type::value;
+
+template <class T>
+concept C2 =
+ requires {
+ typename T::Type;
+ requires T::Type::value;
+ };
+
+template <class T>
+ requires (!C1<T>)
+void f1() { }
+
+template <class T>
+ requires (!C2<T>)
+void f2() { }
+
+struct S { };
+
+void test()
+{
+ f1<S>();
+ f2<S>();
+}
+
+// ------------------
+
+
+template<typename T>
+concept C = requires (T t) { t.f(); };
+
+template<typename A, typename B>
+ requires (!(C<A> && C<B>))
+void g1() { }
+
+template<typename A, typename B>
+ requires (!C<A> || !C<B>)
+void g2() { }
+
+struct X {
+ void f();
+};
+
+void test2() {
+ g1<X, X>(); // { dg-error "cannot call" }
+ g2<X, X>(); // { dg-error "cannot call" }
+} \ No newline at end of file
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr67147.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67147.C
new file mode 100644
index 00000000000..db8c37e2191
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67147.C
@@ -0,0 +1,25 @@
+// PR c++/67147
+// { dg-do compile { target c++2a } }
+
+template <class F, class I1, class I2 = I1>
+concept IndirectCallableRelation = true;
+
+template <class, class, class = void>
+constexpr bool indirect_relation() { return false; }
+
+// FIXME: The original bug was found using the introducer syntax.
+
+template<typename F, typename I1>
+ requires IndirectCallableRelation<F, I1>
+constexpr bool indirect_relation() { return true; }
+
+template<typename F, typename I1, typename I2>
+ requires IndirectCallableRelation<F, I1, I2>
+constexpr bool indirect_relation() { return true; }
+
+// This was added to the discussion thread as a minimum repro.
+
+template<typename T, int = sizeof(T)>
+concept C1 = true;
+
+template <C1 T> int test();
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr67148.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67148.C
new file mode 100644
index 00000000000..c5939960a14
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67148.C
@@ -0,0 +1,121 @@
+// PR c++/67148
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+
+namespace std
+{
+ template<typename T>
+ T declval();
+
+ typedef unsigned int size_t;
+ typedef int ptrdiff_t;
+ typedef decltype(nullptr) nullptr_t;
+ template<typename _Tp, _Tp... _Idx>
+ struct integer_sequence
+ {
+ typedef _Tp value_type;
+ static constexpr size_t size() { return sizeof...(_Idx); }
+ };
+
+ template <class T, T Value>
+ struct integral_constant {
+ using type = integral_constant;
+ using value_type = T;
+ constexpr operator T() const { return Value; }
+ constexpr T operator()() const { return Value; }
+ static constexpr T value {Value};
+ };
+ template <class T, T Value>
+ constexpr T integral_constant<T, Value>::value;
+ using true_type = integral_constant<bool, true>;
+ using false_type = integral_constant<bool, false>;
+
+ template <class T, class U>
+ struct is_same : false_type {};
+ template <class T>
+ struct is_same<T,T> : true_type {};
+}
+
+namespace meta
+{
+ inline namespace v1
+ {
+ template <typename T>
+ using _t = typename T::type;
+ template <bool... Bools>
+ using and_c = std::is_same<std::integer_sequence<bool, Bools...>,
+ std::integer_sequence<bool, (Bools || true)...>>;
+ }
+}
+
+namespace stl2 { inline namespace v1 {
+using std::declval;
+namespace detail {
+template <class...>
+struct all_same : std::true_type {};
+template <class T, class...Rest>
+struct all_same<T, Rest...> :
+ meta::and_c<__is_same_as(T, Rest)...> {};
+}
+template <class...Ts>
+concept bool Same() {
+ return detail::all_same<Ts...>::value;
+}
+template <class F, class...Args>
+using ResultType = decltype(declval<F>()(declval<Args>()...));
+template <class>
+struct value_type {};
+template <class T>
+struct value_type<T*> {
+ using type = T;
+};
+template <class T>
+using ValueType =
+ typename value_type<T>::type;
+
+template <class F, class...Args>
+concept bool Function() {
+ return requires (F& f, Args&&...args) {
+ f((Args&&)args...);
+ requires Same<decltype(f((Args&&)args...)), ResultType<F, Args...> >();
+ };
+}
+
+template <class, class...> struct __function : std::false_type {};
+Function{F, ...Args} struct __function<F, Args...> : std::true_type {};
+
+template <class F, class I1, class I2>
+concept bool IndirectCallable() {
+ return Function<F, ValueType<I1>, ValueType<I2>>();
+}
+
+template <class F, class I1, class I2>
+concept bool IndirectCallable2() {
+ return __function<F, ValueType<I1>, ValueType<I2>>::value;
+}
+
+namespace ext { namespace models {
+template <class, class, class>
+constexpr bool indirect_callable() { return false; }
+IndirectCallable{F, I1, I2}
+constexpr bool indirect_callable() { return true; }
+
+template <class, class, class>
+constexpr bool indirect_callable2() { return false; }
+IndirectCallable2{F, I1, I2}
+constexpr bool indirect_callable2() { return true; }
+}}
+}}
+
+namespace models = stl2::ext::models;
+
+template <class T = void>
+struct plus {
+ T operator()(T, T) const;
+};
+
+static_assert((models::indirect_callable<::plus<int>, int*, int*>()));
+static_assert((models::indirect_callable2<::plus<int>, int*, int*>()));
+
+static_assert((models::indirect_callable<::plus<int>, int**, int*>())); // { dg-error "static assertion failed" }
+static_assert((models::indirect_callable2<::plus<int>, int**, int*>())); // { dg-error "static assertion failed" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr67178.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67178.C
new file mode 100644
index 00000000000..f76f2e3fc86
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67178.C
@@ -0,0 +1,26 @@
+// PR c++/67178
+// { dg-do compile { target c++2a } }
+
+template<typename T>
+concept c = true;
+
+template<typename T>
+concept C0 = requires (auto x) { // { dg-error "placeholder type" }
+ x;
+};
+
+template<typename T>
+concept C1 = requires (C1 auto x) { // { dg-error "not been declared|placeholder|two or more|in requirements" }
+ x; // { dg-error "not declared" }
+ { x } -> c; // { dg-error "not declared|does not satisfy" }
+};
+
+template<typename T>
+ requires C1<T>
+void f(T) {}
+
+int main() {
+ f(1); // { dg-error "cannot call" }
+}
+
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr67210.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67210.C
new file mode 100644
index 00000000000..044e677363c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67210.C
@@ -0,0 +1,10 @@
+// PR c++/67210
+// { dg-do compile { target c++2a } }
+
+template <class T, class U>
+concept C = true;
+
+template <class T>
+struct A {};
+
+void f(A<C<int> auto >) {}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr67217.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67217.C
new file mode 100644
index 00000000000..35618aed5d3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67217.C
@@ -0,0 +1,8 @@
+// PR c++/67217
+// { dg-do compile { target c++2a } }
+
+template <class T>
+ requires __is_same_as(T, double)
+union A {};
+
+int main() { A<int>{}; } // { dg-error "template constraint failure" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr67225-1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67225-1.C
new file mode 100644
index 00000000000..1c5d73a33d0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67225-1.C
@@ -0,0 +1,32 @@
+// PR c++/67225
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+
+template <class T, class U>
+concept bool Same()
+{
+ return true;
+}
+
+template <class T> struct WrapT {T t;};
+
+template <class T>
+concept bool Destructible()
+{
+ return requires(T t, const T ct, WrapT<T>& wt) // { dg-message "in requirements" }
+ {
+ {wt.~WrapT()} noexcept;
+ // {&t} -> Same<T*>; // #1
+ //{&t} -> T*; // #2
+ };
+}
+
+template <Destructible T>
+void f() {}
+
+struct Y {private: ~Y();};
+
+int main()
+{
+ f<Y>(); // { dg-error "cannot call" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr67225-2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67225-2.C
new file mode 100644
index 00000000000..62181768dcc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67225-2.C
@@ -0,0 +1,36 @@
+// PR c++/67225
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+
+template<typename Target>
+// template<typename Target, typename... Ts>
+concept bool has_resize ()
+{
+ return requires (Target tgt)
+ {
+ { tgt.resize () };
+ };
+}
+
+template<typename Target>
+void resize (Target tgt)
+{
+ if constexpr (has_resize<Target> ())
+ {
+ tgt.resize ();
+ }
+}
+
+class MyClass
+{
+ private:
+ int foo (int i)
+ {
+ return i * 2;
+ }
+};
+
+int main ()
+{
+ return MyClass {}.foo (7); // { dg-error "private within this context" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr67225-3.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67225-3.C
new file mode 100644
index 00000000000..d08efb661f0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67225-3.C
@@ -0,0 +1,21 @@
+// PR c++/67225
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+
+template <class>
+concept bool Dummy = true;
+
+template <typename>
+class example {
+ template <Dummy U>
+ friend auto func();
+};
+
+class test {
+ test() = default;
+};
+
+int main()
+{
+ test t; // { dg-error "private within this context" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr67225-4.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67225-4.C
new file mode 100644
index 00000000000..0ef5ed87264
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67225-4.C
@@ -0,0 +1,14 @@
+// PR c++/67225
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+
+template <class, class>
+concept bool C1 = true;
+
+template <class>
+concept bool C2 = requires { { 42 } -> C1<int>; };
+
+int main() {
+ class A { int x; } a;
+ a.x = 42; // { dg-error "private within this context" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr67225-5.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67225-5.C
new file mode 100644
index 00000000000..9a25831f4a2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67225-5.C
@@ -0,0 +1,17 @@
+// PR c++/67225
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+
+template<typename A, typename T>
+concept bool SomeConcept = true;
+
+template <typename T>
+void breaker(SomeConcept<int>);
+
+class SomeClass {
+ int privateMember;
+};
+
+int main() {
+ return SomeClass().privateMember; // { dg-error "private within this context" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr67319.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67319.C
new file mode 100644
index 00000000000..6eb1c440ed4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67319.C
@@ -0,0 +1,24 @@
+// PR c++/67319
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+
+template <typename T>
+concept bool Any()
+{
+ return requires (T t) { +t; };
+}
+
+struct my_struct
+{
+ template <Any... Args>
+ auto sample(Args... args) -> void;
+};
+
+int main()
+{
+ my_struct{}.sample();
+ my_struct{}.sample(0);
+ my_struct{}.sample(0, 'a');
+ my_struct{}.sample(nullptr); // { dg-error "" }
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr67427.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67427.C
new file mode 100644
index 00000000000..fcad30183d6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67427.C
@@ -0,0 +1,22 @@
+// PR c++/67427
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+
+template <class S, class I>
+concept bool Sentinel =
+ requires (I i) { i; };
+
+template <class I, class S>
+concept bool SizedIteratorRange =
+ Sentinel<S, I> && true;
+
+Sentinel{S, I}
+void distance(I first, S last) {}
+
+template <class I, class S>
+ requires SizedIteratorRange<I, S>
+void distance(I first, S last) {}
+
+int main() {
+ distance(42, 43); // { dg-error "ambiguous" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr67654.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67654.C
new file mode 100644
index 00000000000..27ee205a7fc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67654.C
@@ -0,0 +1,30 @@
+// PR c++/67427
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+
+template <bool... Values> struct and_c_impl {
+ static constexpr bool value = true;
+};
+
+template <bool ValueFirst, bool... ValuesRest>
+struct and_c_impl<ValueFirst, ValuesRest...> {
+ static constexpr bool value = ValueFirst && and_c_impl<ValuesRest...>::value;
+};
+
+template <bool... Values> constexpr bool and_c() {
+ return and_c_impl<Values...>::value;
+}
+
+template<class T> concept bool C() {
+ return true;
+}
+
+template<class... Tx>
+struct A {
+ A() requires and_c<C<Tx>()...>() = default;
+};
+
+int main() {
+ A<int, double> a;
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr67658.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67658.C
new file mode 100644
index 00000000000..087f4fc83ae
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67658.C
@@ -0,0 +1,14 @@
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+
+template<class T> concept bool C1() { return false; }
+template<C1 T> concept bool C2() { return true; } // { dg-error "cannot be constrained" }
+
+void f(C2 x) {
+}
+
+struct A {} a;
+
+int main() {
+ f(a);
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr67684.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67684.C
new file mode 100644
index 00000000000..35e92954414
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67684.C
@@ -0,0 +1,63 @@
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+
+template<class T>
+class A {
+ public:
+ template<int I, class S>
+ requires I > 0
+ friend int f1(const A<S>&);
+
+ template<int I, class S>
+ friend int f2(const A<S>&) requires I > 0;
+
+ private:
+ int x = 2;
+};
+
+template<int I, class S>
+ requires I > 0
+int f1(const A<S>& a) {
+ return a.x;
+}
+
+template<int I, class S>
+int f2(const A<S>& a) requires I > 0 {
+ return a.x;
+}
+
+class B {
+ public:
+ template<int I>
+ requires I > 0
+ friend int f3(const B&);
+
+ template<int I>
+ friend int f4(const B&) requires I > 0;
+
+ private:
+ int x = 2;
+};
+
+template<int I>
+ requires I > 0
+int f3(const B& a) {
+ return a.x;
+}
+
+template<int I>
+int f4(const B& a) requires I > 0 {
+ return a.x;
+}
+
+int main() {
+ A<double> a;
+ f1<2>(a);
+ f2<2>(a);
+
+ B b;
+ f3<2>(b);
+ f4<2>(b);
+
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr67685.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67685.C
new file mode 100644
index 00000000000..82f068e50e2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67685.C
@@ -0,0 +1,7 @@
+// PR c++/67685
+// { dg-do compile { target c++14 } }
+// { dg-additional-options "-fconcepts" }
+
+void f(auto i) {requires {i;};}
+
+int main() {f(0);}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr67692.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67692.C
new file mode 100644
index 00000000000..139ecd6d798
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67692.C
@@ -0,0 +1,13 @@
+// { dg-do compile { target c++2a } }
+
+template<class T>
+bool f(T x) {
+ return requires(T x) {
+ ++x;
+ };
+}
+
+int main() {
+ f(3);
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr67697.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67697.C
new file mode 100644
index 00000000000..44c077b16a1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67697.C
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+
+template<class X>
+concept bool C() {
+ return requires(X x, bool b) {
+ requires b; // { dg-error "not a constant expression" }
+ x++;
+ };
+}
+
+int main() {
+ C<int>();
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr67719.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67719.C
new file mode 100644
index 00000000000..d28b44559bd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67719.C
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+
+template<class X> concept bool C() {
+ return __is_same_as(X, int) || __is_same_as(X, long);
+}
+
+template<C... Tx>
+struct Ax {};
+
+int main() {
+ Ax<int, long> a;
+ Ax<int, long, void> b; // { dg-error "template constraint failure" }
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr67774.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67774.C
new file mode 100644
index 00000000000..d363c59f6d5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67774.C
@@ -0,0 +1,26 @@
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+
+#include <type_traits>
+#include <utility>
+#include <iostream>
+
+template <class X> concept bool cpt_RealScalar() {
+ return std::is_floating_point<X>::value;
+}
+
+namespace detail {
+template <class, class> constexpr bool k_evaluator_impl = false;
+
+template <std::size_t... Indexes, class E>
+constexpr bool k_evaluator_impl<std::index_sequence<Indexes...>, E> = true;
+}
+
+template <class X, std::size_t K> concept bool cpt_KEvaluator =
+ detail::k_evaluator_impl<std::make_index_sequence<K>, X>;
+
+int main() {
+ auto f = [](int, int, int) -> double { return 3; };
+ std::cout << cpt_KEvaluator<decltype(f)> << '\n'; // { dg-error "wrong number of template arguments" }
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr67825.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67825.C
new file mode 100644
index 00000000000..95698e99978
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67825.C
@@ -0,0 +1,20 @@
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+
+struct A {
+ template <class T>
+ double operator()(T x) const {
+ return 0;
+ }
+};
+
+template <class X> concept bool C() {
+ return requires {
+ &X::operator();
+ };
+}
+
+int main() {
+ static_assert(C<A>());
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr67860.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67860.C
new file mode 100644
index 00000000000..8bad0319a05
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67860.C
@@ -0,0 +1,61 @@
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+
+#include <type_traits>
+
+inline constexpr bool and_impl() { return true; }
+
+template <class OperandFirst, class... OperandsRest>
+constexpr bool and_impl(OperandFirst operand_first,
+ OperandsRest... operands_rest) {
+ return operand_first && and_impl(operands_rest...);
+}
+
+template <class... Operands> constexpr bool and_(Operands... operands) {
+ return and_impl(operands...);
+}
+
+template <class X> concept bool C() { return true; }
+
+// v1
+template<int, class... Xs>
+ requires and_(C<Xs>()...)
+constexpr int f(const Xs&... xs) {
+ return 0;
+}
+
+// v2
+template<int, class... Xs>
+constexpr int f(const Xs&... xs) {
+ return 1;
+}
+
+int main() {
+ static_assert(f<10>(3.0, 2.0f) == 0);
+ return 0;
+}
+
+// 2nd example
+
+template <typename T, typename... Us>
+concept bool AreType() {
+ return (std::is_same<T,Us>::value && ...);
+ // return true; gives the same overloaded error
+}
+
+// Function with constraint
+template<typename T, AreType<T>... Us>
+constexpr bool isValid(Us... us) {
+ return true;
+}
+
+// Function with no constraint
+template<typename T, typename... U>
+constexpr bool isValid(U... u) {
+ return false;
+}
+
+int main2() {
+ static_assert(isValid<int>(1)); // also isValid<int>(1, 2, 3); etc
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr67862.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67862.C
new file mode 100644
index 00000000000..222e5280913
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67862.C
@@ -0,0 +1,162 @@
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+
+typedef int size_t;
+template <typename _Tp> struct A { static constexpr _Tp value = 1; };
+template <typename _Tp> _Tp declval();
+template <typename _From, typename _To> struct __is_convertible_helper {
+ template <typename, typename> static A<bool> __test(int);
+ typedef decltype(__test<_From, _To>(0)) type;
+};
+template <typename, typename>
+struct is_convertible : __is_convertible_helper<int, int>::type {};
+template <typename> struct remove_reference;
+template <typename _Tp> struct remove_reference<_Tp &> { typedef _Tp type; };
+struct base;
+struct general;
+template <typename _Tp, _Tp...> struct B;
+template <typename _Tp, _Tp> using make_integer_sequence = B<int>;
+template <size_t... _Idx> using index_sequence = B<size_t, _Idx...>;
+template <size_t _Num>
+using make_index_sequence = make_integer_sequence<size_t, _Num>;
+template <bool...> struct and_c_impl { static constexpr bool value = true; };
+template <bool...> constexpr bool and_c() { return and_c_impl<>::value; }
+
+template <class X, class Y> concept bool cpt_Convertible() {
+ return is_convertible<X, Y>::value;
+}
+
+template <class T> using uncvref_t = typename remove_reference<T>::type;
+struct Plus;
+using index_t = int;
+template <class> bool cpt_Index;
+template <class... Extents>
+requires and_c<cpt_Index<Extents>()...>() class Dimensionality;
+namespace detail_concept {
+template <class> bool match_dimensionality;
+template <class... Extents>
+constexpr bool match_dimensionality<Dimensionality<Extents...>> = true;
+}
+template <class X> concept bool cpt_Dimensionality() {
+ return detail_concept::match_dimensionality<X>;
+}
+
+template <class X> concept bool cpt_Shaped() { return requires(X x){{x};}; }
+
+template <class X> concept bool cpt_Dimensioned() { return cpt_Shaped<X>(); }
+
+template <class... Extents>
+requires and_c<cpt_Index<Extents>()...>() class Dimensionality {
+public:
+ static constexpr size_t num_dimensions = sizeof...(Extents);
+};
+template <index_t...> using DimensionalityC = Dimensionality<>;
+template <class> struct dimensionality_type_impl;
+template <cpt_Dimensioned X> struct dimensionality_type_impl<X> {
+ using type = uncvref_t<decltype(declval<X>().dimensionality())>;
+};
+template <cpt_Dimensioned X>
+using dimensionality_type = typename dimensionality_type_impl<X>::type;
+template <class Functor, class... Expressibles>
+requires requires(Functor functor, Expressibles... expressibles) {
+ map_expressions_impl(functor, expressibles...);
+}
+
+decltype(auto) map_impl(Functor, Expressibles...);
+void cpt_ContinualScalar();
+template <class> concept bool cpt_Scalar() { return cpt_ContinualScalar; }
+
+template <class X> concept bool cpt_FlatEvaluator() {
+ return requires(X x){{x}->cpt_Scalar;};
+}
+
+template <class, class> bool k_evaluator_impl;
+template <size_t... Indexes, class Evaluator>
+constexpr bool k_evaluator_impl<index_sequence<Indexes...>, Evaluator> = true;
+template <class X, size_t K> concept bool cpt_KEvaluator() {
+ return k_evaluator_impl<make_index_sequence<K>, X>;
+}
+
+template <class X, size_t K> concept bool cpt_KCompatibleEvaluator() {
+ return cpt_KEvaluator<X, K>();
+}
+
+template <class X> concept bool cpt_Structure() {
+ return cpt_Convertible<X, base>();
+}
+
+template <cpt_Dimensionality Dimensionality, cpt_Structure,
+ cpt_KCompatibleEvaluator<Dimensionality::num_dimensions> Evaluator>
+class NumericArrayExpression;
+namespace detail_concept {
+
+template <class> bool match_numeric_array_expression;
+
+template <cpt_Dimensionality Dimensionality,
+ cpt_Structure Structure,
+ cpt_KCompatibleEvaluator<Dimensionality::num_dimensions> Evaluator>
+constexpr bool match_numeric_array_expression<
+ NumericArrayExpression<Dimensionality, Structure, Evaluator>> = true;
+
+}
+template <class X> concept bool cpt_NumericArrayExpression() {
+ return detail_concept::match_numeric_array_expression<X>;
+}
+
+namespace expression_traits {
+namespace detail_expression_traits {
+template <class...> struct first_numeric_array_expression_impl;
+template <cpt_NumericArrayExpression ExpressionFirst, class... ExpressionsRest>
+struct first_numeric_array_expression_impl<ExpressionFirst,
+ ExpressionsRest...> {
+ using type = ExpressionFirst;
+};
+}
+template <class... Expressions>
+using first_numeric_array_expression =
+ typename detail_expression_traits::first_numeric_array_expression_impl<
+ Expressions...>::type;
+template <class... Expressions>
+using first_expression_dimensionality =
+ dimensionality_type<first_numeric_array_expression<Expressions...>>;
+}
+template <cpt_Dimensionality Dimensionality, cpt_Structure,
+ cpt_KCompatibleEvaluator<Dimensionality::num_dimensions> Evaluator>
+class NumericArrayExpression {
+public:
+ NumericArrayExpression(Dimensionality, Evaluator) {}
+ Dimensionality &dimensionality();
+};
+
+template <cpt_Structure Structure, cpt_Dimensionality Dimensionality,
+ cpt_KCompatibleEvaluator<Dimensionality::num_dimensions> Evaluator>
+auto make_numeric_array_expression(Dimensionality dimensionality,
+ Evaluator evaluator) {
+ return NumericArrayExpression<Dimensionality, Structure, Evaluator>(
+ dimensionality, evaluator);
+}
+
+template <size_t, class Functor, class... Evaluators>
+auto make_map_evaluator_impl(Functor) requires
+ and_(cpt_FlatEvaluator<Evaluators>()...);
+template <class Functor, class... Expressions>
+requires
+requires(Expressions... expressions,
+ expression_traits::first_expression_dimensionality<Expressions...>
+ dimensionality) {
+ make_map_evaluator_impl<decltype(dimensionality)::num_dimensions>(
+ expressions...);
+}
+
+decltype(auto) map_expressions_impl(Functor, Expressions...);
+template <class Functor, class... Expressibles> concept bool cpt_Mappable() {
+ return requires(Functor functor, Expressibles... expressibles) {
+ map_impl(functor, expressibles...);
+ };
+}
+
+void ____C_A_T_C_H____T_E_S_T____8() {
+ auto e1 = make_numeric_array_expression<general>(DimensionalityC<>(), [] {});
+ using E1 = decltype(e1);
+ cpt_Mappable<Plus, E1>();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr67969.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67969.C
new file mode 100644
index 00000000000..4f2ab510389
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67969.C
@@ -0,0 +1,32 @@
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+template <class, class>
+class NumericArray {};
+
+template <class>
+constexpr bool match_numeric_array = false;
+template <class Scalar, class Shape>
+constexpr bool
+ match_numeric_array<NumericArray<Scalar, Shape>> =
+ true;
+template <class T>
+concept bool cpt_NumericArrayContainer() {
+ return match_numeric_array<T>;
+}
+
+template <class X>
+concept bool cpt_NumericArray() {
+ return requires{requires cpt_NumericArrayContainer<X>();};
+}
+
+
+template <class X>
+requires !cpt_NumericArray<X>() auto func(int, X) {}
+
+template <class X>
+requires cpt_NumericArray<X>() auto func(int, X) {}
+
+int main() {
+ NumericArray<double, int> v5;
+ func(0, v5);
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr68093-1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr68093-1.C
new file mode 100644
index 00000000000..bc4ddee5770
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr68093-1.C
@@ -0,0 +1,13 @@
+// { dg-do compile { target c++2a } }
+template <typename t>
+struct S
+{
+ template <typename t2>
+ requires false
+ friend void foobar(S, t2) {}
+};
+
+int main()
+{
+ foobar(S<double>{}, int{}); // { dg-error "cannot call" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr68093-2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr68093-2.C
new file mode 100644
index 00000000000..91e3c80653d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr68093-2.C
@@ -0,0 +1,14 @@
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+template <class T>
+concept bool True = true;
+
+template <class T>
+struct S {
+ friend bool operator==(S, int) requires True<T> { return true; }
+ friend bool operator==(S, int) requires !True<T> { return true; }
+};
+
+int main() {
+ S<int> s;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr68372.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr68372.C
new file mode 100644
index 00000000000..d1416ebc99c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr68372.C
@@ -0,0 +1,48 @@
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+
+template<typename F>
+concept bool FCallable()
+{
+ return requires(F)
+ {
+ F::f();
+ };
+}
+
+class Test1
+{
+public:
+ template<FCallable P, FCallable... Pp>
+ static void g()
+ {
+ (Pp::f(), ...);
+ }
+};
+
+class A
+{
+public:
+ static void f() {}
+};
+
+template<typename X> concept bool C = true;
+
+template<C... X>
+void bar(X...)
+{}
+
+struct foo
+{
+ template<C... X>
+ void bar(X...)
+ {}
+};
+
+int main()
+{
+ Test1::template g<A>();
+ bar();
+ foo {}.bar();
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr68434.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr68434.C
new file mode 100644
index 00000000000..23ecf4de2bc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr68434.C
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++2a } }
+
+template <class>
+concept C1 = true;
+
+template <class>
+concept C2 = true;
+
+template <class Expr>
+concept C3 =
+ requires (Expr expr) {
+ {expr}->C1;
+ {expr}->C2;
+ };
+
+template<C3 T>
+auto f (T);
+
diff --git a/gcc/testsuite/g++.dg/concepts/pr68683.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr68683.C
index ff7709e40aa..f11d69f75fd 100644
--- a/gcc/testsuite/g++.dg/concepts/pr68683.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr68683.C
@@ -1,5 +1,5 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
+// PR c++/68683
+// { dg-do compile { target c++2a } }
template <typename, typename>
struct is_same {
@@ -7,10 +7,10 @@ struct is_same {
};
template <typename T, typename U>
-concept bool Same = is_same<T, U>::value;
+concept Same = is_same<T, U>::value;
template <typename T>
-concept bool Integral = requires {
+concept Integral = requires {
{ T () } -> Same<typename T::value_type>;
};
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr68812.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr68812.C
new file mode 100644
index 00000000000..2d809e85914
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr68812.C
@@ -0,0 +1,34 @@
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+
+namespace zero
+{
+ template<int... s>
+ struct S
+ {
+ template<int... f>
+ requires(... and (s == f))
+ static void F()
+ {
+ }
+ };
+
+ void foo(S<>) {}
+}
+
+namespace one
+{
+ template<typename X, typename Y> concept bool Foo = true;
+
+ template<typename... T>
+ struct foo
+ {
+ template<typename... U>
+ foo(U...)
+ requires (Foo<T, U> && ...)
+ {}
+ };
+
+ void bar(foo<int, long, double>) {}
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr69235.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr69235.C
new file mode 100644
index 00000000000..5e96d0e7b7d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr69235.C
@@ -0,0 +1,48 @@
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+
+template<typename T>
+concept bool Boolean()
+{
+ return requires(T t)
+ {
+ { t } -> bool;
+ };
+}
+
+template<typename T>
+concept bool C()
+{
+ return requires (T t)
+ {
+ { t } -> Boolean;
+ };
+}
+
+template<typename T>
+struct X;
+
+template<typename T>
+ requires ! C<typename T::type>()
+struct X<T>
+{
+ using type = int;
+};
+
+template<typename T>
+ requires C<typename T::type>()
+struct X<T>
+{
+ using type = int;
+};
+
+struct S
+{
+ using type = char;
+};
+
+void f()
+{
+ X<S>::type x;
+}
+
diff --git a/gcc/testsuite/g++.dg/concepts/pr71368.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr71368.C
index 5cd2b54cd7c..c67e632d443 100644
--- a/gcc/testsuite/g++.dg/concepts/pr71368.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr71368.C
@@ -1,14 +1,16 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
+// PR c++/71368
+// { dg-do compile { target c++2a } }
+
+template <class T, class U> concept Same = __is_same_as(T,U);
struct inner;
-template<typename X> concept bool CompoundReq = requires {
+template<typename X> concept CompoundReq = requires {
// fine with concrete type in trailing type, i.e. inner& instead of X&
- { X::inner_member() } -> X&;
+ { X::inner_member() } -> Same<X&>;
};
-template<typename X> concept bool Concept = requires {
+template<typename X> concept Concept = requires {
{ X::outer_member() } -> CompoundReq;
};
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr71385.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr71385.C
new file mode 100644
index 00000000000..f31997c920d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr71385.C
@@ -0,0 +1,14 @@
+// { dg-do compile { target c++2a } }
+
+template<class From, class To>
+concept convertible_to = requires(From (&f)(), void (&g)(To)) { g(f()); };
+
+template<class T>
+concept Addable =
+ requires(T x){
+ {x + x} -> convertible_to<T>;
+ };
+
+int main(){
+ Addable auto t = 0;
+}
diff --git a/gcc/testsuite/g++.dg/concepts/pr71965.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr71965.C
index 6bfaef19211..4619cf993af 100644
--- a/gcc/testsuite/g++.dg/concepts/pr71965.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr71965.C
@@ -1,13 +1,10 @@
-// { dg-do compile { target c++14 } }
-// { dg-options "-fconcepts" }
+// { dg-do compile { target c++2a } }
template <class T>
-concept bool Destructible() {
- return false;
-}
+concept Destructible = false;
template <class T, class...Args>
-concept bool ConstructibleObject =
+concept ConstructibleObject =
// Concept evaluation should short-circuit even the template
// substitution, so we shouldn't even substitute into the requires
// constraint and the unimplemented multi-dimensional new T{...}
@@ -15,7 +12,7 @@ concept bool ConstructibleObject =
// sorry() message we used to for such constructs when asked not
// to issue errors, this shouldn't be a problem for this and
// similar cases.
- Destructible<T>() && requires (Args&&...args) {
+ Destructible<T> && requires (Args&&...args) {
new T{ (Args&&)args... };
};
diff --git a/gcc/testsuite/g++.dg/concepts/memfun2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr72415.C
index 78a2cf7bada..04bdc514fb9 100644
--- a/gcc/testsuite/g++.dg/concepts/memfun2.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr72415.C
@@ -2,7 +2,7 @@
// { dg-do compile { target c++17 } }
// { dg-options "-fconcepts" }
-template<int... Indices>
+template<int... Xs>
struct indices {};
template<typename Dummy>
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr78752.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr78752.C
new file mode 100644
index 00000000000..40eeaa7d57b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr78752.C
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+
+#include <type_traits>
+
+template <class T, class U>
+concept bool Same = std::is_same<T, U>::value;
+
+struct test {
+ template <Same<int>... Ints>
+ void func(Ints... ints) {}
+};
+
+int main()
+{
+ test t;
+ t.func(1, 2, 3);
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr79759.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr79759.C
new file mode 100644
index 00000000000..a99103c97dd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr79759.C
@@ -0,0 +1,7 @@
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+
+template<typename T, T N>
+concept bool C0() { return true; }
+
+void f(C0<0>);
diff --git a/gcc/testsuite/g++.dg/concepts/pr80471.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr80471.C
index d5fa5a536d3..d5fa5a536d3 100644
--- a/gcc/testsuite/g++.dg/concepts/pr80471.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr80471.C
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr80746.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr80746.C
new file mode 100644
index 00000000000..69e2fbec4d8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr80746.C
@@ -0,0 +1,14 @@
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+
+template<typename T, typename T::type>
+concept bool C = true;
+
+template<C<0> T> class ct {};
+
+struct S
+{
+ using type = int;
+};
+
+template class ct<S>;
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr80773.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr80773.C
new file mode 100644
index 00000000000..34b96c59582
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr80773.C
@@ -0,0 +1,33 @@
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+
+template<typename F>
+concept bool FCallable()
+{
+ return requires(F)
+ {
+ F::f();
+ };
+}
+
+class Test1
+{
+public:
+ template<FCallable P, FCallable... Pp>
+ static void g()
+ {
+ (Pp::f(), ...);
+ }
+};
+
+class A
+{
+public:
+ static void f() {}
+};
+
+int main()
+{
+ Test1::template g<A>();
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr82507.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr82507.C
new file mode 100644
index 00000000000..f7438552ca9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr82507.C
@@ -0,0 +1,17 @@
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+
+template<class I>
+concept bool True = true;
+
+template<class T>
+concept bool HasType = requires { typename T::type; };
+
+template<class T>
+struct S
+{
+ void foo() requires HasType<T> && True<typename T::type>;
+};
+
+S<int> s;
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr82740.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr82740.C
new file mode 100644
index 00000000000..6e0f062c14b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr82740.C
@@ -0,0 +1,32 @@
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+
+template<class T>
+concept bool C = requires(const T& t) { t.foo(); };
+
+template<class T>
+struct Base
+{
+ constexpr T const& derived() const
+ {
+ return static_cast<T const&>(*this);
+ }
+ constexpr bool bar() const
+ requires requires(const T& t) { t.foo(); }
+ {
+ derived().foo();
+ return true;
+ }
+};
+
+template<class T>
+struct Derived : Base<Derived<T>>
+{
+ constexpr void foo() const {}
+};
+
+int main()
+{
+ static_assert(Derived<int>{}.bar());
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr84140.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84140.C
new file mode 100644
index 00000000000..d901ab20cbf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84140.C
@@ -0,0 +1,38 @@
+// { dg-do run { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+
+template<class, class> constexpr bool is_same_v = false;
+template<class T> constexpr bool is_same_v<T, T> = true;
+
+template<class T, class U>
+concept bool Same = is_same_v<T, U>;
+
+template<class T, class U>
+concept bool Diff = requires(T& t, U& u) { u - t; };
+
+template<class I, class S>
+int distance(I, S) { return 0; }
+
+template<class I, Diff<I> S>
+int distance(I first, S last)
+{
+ return last - first;
+}
+
+template<class T>
+struct I
+{
+ template<class U>
+ requires Same<T, U>
+ friend int operator-(I const&, I<U> const&)
+ {
+ static_assert(Same<T, U>);
+ return 42;
+ }
+};
+
+int main()
+{
+ return distance(I<int>{}, I<void>{});
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr84551.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84551.C
new file mode 100644
index 00000000000..e40796f4975
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84551.C
@@ -0,0 +1,11 @@
+// PR c++/84551
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-g -O" }
+
+template<typename> concept C = true;
+
+template<template<typename T> requires C<T> class TT> struct A {};
+
+template<typename U> requires true struct B {};
+
+A<B> a; // { dg-error "" }
diff --git a/gcc/testsuite/g++.dg/concepts/pr84979-2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-2.C
index ce69a0f8ac5..ce69a0f8ac5 100644
--- a/gcc/testsuite/g++.dg/concepts/pr84979-2.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-2.C
diff --git a/gcc/testsuite/g++.dg/concepts/pr84979-3.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-3.C
index 3809c2d3033..3809c2d3033 100644
--- a/gcc/testsuite/g++.dg/concepts/pr84979-3.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-3.C
diff --git a/gcc/testsuite/g++.dg/concepts/pr84979.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979.C
index 9bd40df103a..9bd40df103a 100644
--- a/gcc/testsuite/g++.dg/concepts/pr84979.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979.C
diff --git a/gcc/testsuite/g++.dg/concepts/pr84980.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84980.C
index 619c0bd140b..1703de05f07 100644
--- a/gcc/testsuite/g++.dg/concepts/pr84980.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84980.C
@@ -1,6 +1,4 @@
-// { dg-do compile { target c++14 } }
+// { dg-do compile { target c++17_only } }
// { dg-additional-options "-fconcepts" }
template<T> concept bool C = true; // { dg-error "has not been declared" }
-
-template<C...> struct A;
diff --git a/gcc/testsuite/g++.dg/concepts/pr85265.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr85265.C
index 86124ceb712..96aac69ed6a 100644
--- a/gcc/testsuite/g++.dg/concepts/pr85265.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr85265.C
@@ -1,4 +1,5 @@
-// { dg-do compile { target c++14 } }
+// PR c++/85265
+// { dg-do compile { target c++17_only } }
// { dg-additional-options "-fconcepts" }
template<typename> concept bool C = true;
diff --git a/gcc/testsuite/g++.dg/concepts/class-deduction2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr85706.C
index e0718d1d0cf..e0718d1d0cf 100644
--- a/gcc/testsuite/g++.dg/concepts/class-deduction2.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr85706.C
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr85808.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr85808.C
new file mode 100644
index 00000000000..bcba830bc0d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr85808.C
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+
+namespace X
+{
+ template<class> constexpr bool x = true;
+}
+
+template<int> using helper = void;
+
+template<typename T>
+concept bool C =
+ requires
+ {
+ requires X::x<T>;
+ typename helper<T{}>;
+ };
+
+static_assert(C<int>);
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr86269.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr86269.C
new file mode 100644
index 00000000000..4428ee1796c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr86269.C
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+#include <type_traits>
+
+template<typename t2, typename t = std::remove_reference_t<t2>>
+concept bool IntegralOrIntegralRef = std::is_integral_v<t>;
+
+template<IntegralOrIntegralRef t>
+auto foo(t && v)
+{
+ return v;
+}
+
+int main()
+{
+ int i = 7;
+ foo(8);
+ return foo(i);
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr87441.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr87441.C
new file mode 100644
index 00000000000..bcd4ba54071
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr87441.C
@@ -0,0 +1,10 @@
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+
+template<typename X, typename Y = X>
+concept bool HasBinaryAdd = requires(X x, Y y)
+{
+ {x + y} -> decltype(x + y);
+};
+
+void proc(HasBinaryAdd x, HasBinaryAdd y);
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-requires1.C
new file mode 100644
index 00000000000..f1603af8015
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires1.C
@@ -0,0 +1,71 @@
+// { dg-do compile { target c++2a } }
+
+template<typename T>
+concept Class = __is_class(T);
+
+// Allow a requires-expression with no parms.
+template<typename T>
+concept C = requires { typename T::type; };
+
+void f1(int a) requires true; // OK
+auto f2(int a) -> bool requires true; // OK
+auto f3(int a) requires true -> bool; // { dg-error "" } requires-clause precedes trailing-return-type
+typedef void fn_t() requires true; // { dg-error "typedef" }
+void (*pf)() requires true; // { dg-error "non-function" }
+void (*fn(int))() requires false; // { dg-error "return type" }
+void g(int (*)() requires true); // { dg-error "parameter|non-function" }
+auto* p = new (void(*)(char) requires true); // { dg-error "type-id" }
+void f4(auto a) requires Class<decltype(a)> { }
+void f5(auto a) requires requires (decltype(a) x) { -x; } { } // { dg-message "in requirements" }
+
+struct Test {
+ void f(auto a) requires Class<decltype(a)>;
+} test;
+
+void driver_1() {
+ struct S { } s;
+ f4(s);
+ f5(0);
+ f5((void*)0); // { dg-error "cannot call" }
+ test.f(s);
+}
+
+void Test::f(auto a) requires Class<decltype(a)> { }
+
+template<bool B> requires B struct S0; // OK
+
+template<int N> requires N struct S1 { }; // { dg-error "does not have type" }
+S1<1> x0; // { dg-error "template constraint failure|does not have type" }
+
+template<int N> requires N == 0 struct S2 { }; // { dg-error "does not have type|must be enclosed" }
+
+template<int N> requires (N == 0) struct S3 { }; // OK
+
+template<typename T, T X> requires X struct S4 { }; // OK
+S4<int, 0> x1; // { dg-error "template constraint failure|does not have type" }
+S4<bool, true> x2; // OK
+S4<bool, false> x3; // { dg-error "template constraint failure" }
+
+
+// req11.C
+template<typename T>
+concept Streamable = requires (T t) { t; };
+
+template<typename T>
+concept Range = requires (T t) { t; };
+
+// FIXME: There are two syntax errors here when there should be
+// just one.Note that !Range<T> is not a primary-expression and needs to
+// be wrapped in parens to be syntactically valid.
+template<class T>
+ requires Streamable<T> && !Range<T> // { dg-error "must be enclosed" }
+void print1(const T& x) { }
+
+template<class T>
+ requires Streamable<T> && (!Range<T>)
+void print2(const T& x) { }
+
+void driver_3()
+{
+ print2("hello"); // { dg-error "cannot call" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires10.C b/gcc/testsuite/g++.dg/cpp2a/concepts-requires10.C
new file mode 100644
index 00000000000..bb0e3b0667f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires10.C
@@ -0,0 +1,32 @@
+// PR c++/66988
+// { dg-do compile { target c++2a } }
+
+template<bool B>
+struct bool_constant {
+ static constexpr bool value = B;
+ constexpr operator bool() const { return value; }
+};
+
+using true_type = bool_constant<true>;
+using false_type = bool_constant<false>;
+
+template <template <class> class T, class U>
+concept _Valid = requires { typename T<U>; };
+
+template <class T>
+using nested_type = typename T::type;
+
+template <class T>
+struct has_nested_type : false_type { };
+
+template <class T>
+ requires _Valid<nested_type, T>
+struct has_nested_type<T> : true_type { };
+
+struct Nested
+{
+ using type = int;
+};
+
+static_assert(!has_nested_type<int>());
+static_assert(has_nested_type<Nested>());
diff --git a/gcc/testsuite/g++.dg/concepts/req17.C b/gcc/testsuite/g++.dg/cpp2a/concepts-requires11.C
index 472cfef34a0..be6409ebad8 100644
--- a/gcc/testsuite/g++.dg/concepts/req17.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires11.C
@@ -1,20 +1,20 @@
// PR c++/67018
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
+// { dg-do compile { target c++2a } }
template <typename T>
constexpr bool Val = true;
template <class I>
-concept bool InputIterator = requires (I i) {
- requires Val <decltype(i++)>;
+concept InputIterator = requires (I i) {
+ requires Val<decltype(i++)>;
};
template <class I>
-concept bool ForwardIterator = InputIterator<I> && true;
+concept ForwardIterator = InputIterator<I> && true;
template<InputIterator>
constexpr bool f() { return false; }
+
template<ForwardIterator>
constexpr bool f() { return true; }
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires12.C b/gcc/testsuite/g++.dg/cpp2a/concepts-requires12.C
new file mode 100644
index 00000000000..c8e3cfd5c63
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires12.C
@@ -0,0 +1,21 @@
+// { dg-do compile { target c++2a } }
+
+template <class> struct all_same {
+ static constexpr bool value = true;
+};
+
+template <class T>
+concept Assignable = requires(T t)
+{
+ requires all_same<decltype(t = 0)>::value;
+};
+
+template <class I>
+ requires (!Assignable<I>)
+int dispatch();
+
+template <class I>
+ requires Assignable<I>
+void dispatch();
+
+int main() { dispatch<int *>(); }
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires13.C b/gcc/testsuite/g++.dg/cpp2a/concepts-requires13.C
new file mode 100644
index 00000000000..8ba38625834
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires13.C
@@ -0,0 +1,20 @@
+// { dg-do compile { target c++2a } }
+
+template <class T> concept C = true;
+
+template <class T>
+ requires C<typename T::foo>
+void f(T t) { }
+
+void f(...);
+
+template <class T>
+ requires C<T>
+void g(T t) { }
+
+int main()
+{
+ f(42);
+ g(42);
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires14.C b/gcc/testsuite/g++.dg/cpp2a/concepts-requires14.C
new file mode 100644
index 00000000000..e2893c061de
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires14.C
@@ -0,0 +1,24 @@
+// { dg-do compile { target c++2a } }
+
+template<typename T>
+concept A = sizeof(T) >= 4;
+
+template<typename T>
+concept B = __is_class(T);
+
+template<A T>
+void ok1(T a) {
+ return;
+}
+
+template<typename T>
+ requires B<T>
+void ok2(T a) {
+ return;
+}
+
+template<A T>
+ requires B<T>
+void fun(T a) {
+ return;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires15.C b/gcc/testsuite/g++.dg/cpp2a/concepts-requires15.C
new file mode 100644
index 00000000000..81d919682dc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires15.C
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++2a } }
+
+struct string;
+
+template<typename T>
+concept C = string; // { dg-error "expected primary-expression" }
+
+template<C T>
+void fun(T s) { }
+
+int main(int, char **) {
+ fun((int *)0); // { dg-error "cannot call function" }
+ return 0;
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires16.C b/gcc/testsuite/g++.dg/cpp2a/concepts-requires16.C
new file mode 100644
index 00000000000..209c91657aa
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires16.C
@@ -0,0 +1,47 @@
+// { dg-do compile { target c++2a } }
+
+// A poor mans Integral concept.
+template<typename T>
+concept Integral = __is_same_as(T, int);
+
+template<int N>
+concept Nonnegative = N >= 0;
+
+template<typename... Args>
+concept UnaryPack = (sizeof...(Args) == 1);
+
+template<typename... Args>
+ requires Integral<Args...> // { dg-error "non-pack parameter" }
+void f1();
+
+template<typename... Args>
+ requires Integral<Args>... // { dg-error "parameter packs not expanded|expected unqualified-id" }
+void f2();
+
+template<typename... Args>
+ requires (Integral<Args> && ...)
+void f3() { }
+
+template<Integral... Args>
+void f4() { }
+
+// FIXME: This syntax is likely to be made invalid.
+template<Nonnegative... Args> // { dg-error "does not constrain a type" }
+void f5() { }
+
+template<UnaryPack Arg> // requires UnaryPack<Arg>
+void f6() { }
+
+template<UnaryPack... Args> // requires (... && UnaryPack<Args>)
+void f7() { }
+
+void driver()
+{
+ f1<int, int>(); // { dg-error "cannot call function" }
+ f3<int, int>();
+ f3<int, void>(); // { dg-error "cannot call function" }
+ f4<int, int>();
+ f4<int, void>(); // { dg-error "cannot call function" }
+ f7<int>();
+ f7<int, int>();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires17.C b/gcc/testsuite/g++.dg/cpp2a/concepts-requires17.C
new file mode 100644
index 00000000000..1ec1d59fc84
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires17.C
@@ -0,0 +1,11 @@
+// { dg-do compile { target c++2a } }
+
+template<typename T>
+concept Type = true;
+
+template<typename T>
+concept C =
+ requires (T a) {
+ { a.f() } -> Type; // OK
+ { a.g() } -> const Type*; // { dg-error "not a plain type-constraint" }
+ };
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-requires2.C
new file mode 100644
index 00000000000..45bb423af65
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires2.C
@@ -0,0 +1,74 @@
+// { dg-do compile { target c++2a } }
+
+// Test the types of atomic constraints
+
+// req5.C
+struct fool {
+ constexpr fool operator&&(fool) const { return {}; }
+ constexpr fool operator||(fool) const { return {}; }
+};
+
+template<typename T> constexpr fool p1() { return {}; }
+template<typename T> constexpr fool p2() { return {}; }
+
+template<typename T>
+concept Bad = p1<T>() && p2<T>();
+
+template<typename T> requires Bad<T> void bad(T x) { }
+
+void driver_2()
+{
+ bad(0); // { dg-error "cannot call" }
+}
+
+// req6.C
+struct X { };
+int operator==(X, X) { return 0; }
+
+template<typename T>
+concept C1 = (X());
+
+template<typename T>
+concept C2 = (X() == X());
+
+template<typename T>
+ requires C1<T>
+void h1(T) { }
+
+template<typename T>
+ requires C2<T>
+void h2(T);
+
+void driver_3()
+{
+ h1(0); // { dg-error "cannot call" }
+ h2(0); // { dg-error "cannot call" }
+}
+
+// req7.C
+template<bool B>
+struct boolean_constant
+{
+ constexpr operator bool() const { return B; }
+};
+
+using true_type = boolean_constant<true>;
+using false_type = boolean_constant<false>;
+
+template<typename T>
+struct dependent_true : true_type { };
+
+template<typename T>
+struct dependent_false : false_type { };
+
+template<typename T>
+ requires (dependent_true<T>{}) // { dg-message "bool" }
+struct S5 { };
+
+template<typename T>
+ requires (dependent_false<T>{}) // { dg-message "bool" }
+struct S6 { };
+
+S5<int> x5; // { dg-error "template constraint failure" }
+S6<int> x6; // { dg-error "template constraint failure" }
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires3.C b/gcc/testsuite/g++.dg/cpp2a/concepts-requires3.C
new file mode 100644
index 00000000000..bbcba0d5806
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires3.C
@@ -0,0 +1,32 @@
+// { dg-do compile { target c++2a } }
+
+// Test basic expression requirements
+
+// req13.C
+
+template<class T, class...Args>
+concept Constructible =
+ requires(Args&&...args) {
+ T {((Args&&)(args))...};
+ new T{((Args&&)(args))...};
+ };
+
+template<typename T>
+ requires Constructible<T>
+struct A { };
+
+A<int> a;
+
+// req19.C
+
+struct B
+{
+ template <class T>
+ void f(T t) requires requires (T tt) { tt; }
+ { }
+};
+
+int main()
+{
+ B().f(42);
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires4.C b/gcc/testsuite/g++.dg/cpp2a/concepts-requires4.C
new file mode 100644
index 00000000000..61aa72d0452
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires4.C
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++2a } }
+
+// Test associated type requirements
+
+// req8.C
+
+template<typename T>
+concept Has_member_type = requires { typename T::type; };
+
+template<typename T>
+concept Concept = true && Has_member_type<T>;
+
+template<typename T>
+ requires Concept<T>
+void foo(T t) { }
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires5.C b/gcc/testsuite/g++.dg/cpp2a/concepts-requires5.C
new file mode 100644
index 00000000000..fe37ed48e79
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires5.C
@@ -0,0 +1,45 @@
+// { dg-do compile { target c++2a } }
+// { dg-additional-options -fconcepts-ts }
+
+// Test conversion requirements (not in C++20)
+
+// req9.C
+
+template<typename T>
+struct S1 { };
+
+template<typename T>
+concept C = requires(T x) { { x.fn() } -> S1<T>; };
+
+template<typename U>
+ requires C<U>
+void fn(U x)
+{
+ x.fn();
+}
+
+struct S2
+{
+ auto fn() const { return S1<S2>(); }
+};
+
+int driver_1()
+{
+ fn(S2{});
+ return 0;
+}
+
+// req10.C
+// Test implicit conversion requirements
+
+template<typename T, typename U>
+concept ConvertibleTo = requires(T& t) { {t} -> U&; };
+
+struct B { };
+class D : /*private*/ B { };
+
+void driver_2()
+{
+ static_assert(ConvertibleTo<D, B>()); // { dg-error "cannot be used as a function" }
+ static_assert(ConvertibleTo<D, B>); // { dg-error "static assertion failed" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires6.C b/gcc/testsuite/g++.dg/cpp2a/concepts-requires6.C
new file mode 100644
index 00000000000..20df78bebf1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires6.C
@@ -0,0 +1,34 @@
+// { dg-do compile { target c++2a } }
+
+// Test deduction requirements.
+
+// req12.C
+
+template <typename T, typename U>
+concept SameAs = __is_same_as(T, U);
+
+template <typename T>
+concept C1 = requires(T t) { // { dg-message "in requirements" }
+ { t } -> SameAs<T>; // NOTE: t deduced as decltype((t))
+ // { dg-error "does not satisfy placeholder constraints" "" { target *-*-* } .-1 }
+};
+
+template <typename T>
+ requires C1<T>
+constexpr bool f1() { return true; }
+
+static_assert(f1<char>()); // { dg-error "cannot call" }
+static_assert(f1<int>()); // { dg-error "cannot call" }
+static_assert(f1<double>()); // { dg-error "cannot call" }
+
+
+template <typename T>
+concept C2 = requires(T t) {
+ { t } -> SameAs<T&>; // NOTE: t deduced as decltype((t))
+};
+
+template <typename T>
+ requires C2<T>
+constexpr bool f2() { return true; }
+
+static_assert(f2<int>()); // OK
diff --git a/gcc/testsuite/g++.dg/concepts/req14.C b/gcc/testsuite/g++.dg/cpp2a/concepts-requires7.C
index 6e60b6f194f..89057c42441 100644
--- a/gcc/testsuite/g++.dg/concepts/req14.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires7.C
@@ -1,14 +1,15 @@
// PR c++/66758
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
+// { dg-do compile { target c++2a } }
template <class T, class U>
-concept bool C = requires (T t, U u) { t + u; };
+concept C = requires (T t, U u) { t + u; };
template <class T, class U>
-requires C<T,U>
+ requires C<T,U>
void f(T t, U u) { t + u; }
+struct non_addable { };
+
int main()
{
using T = decltype(f(42, 24));
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires8.C b/gcc/testsuite/g++.dg/cpp2a/concepts-requires8.C
new file mode 100644
index 00000000000..f10e4bcdb9a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires8.C
@@ -0,0 +1,17 @@
+// { dg-do compile { target c++2a } }
+
+template <class T, class U>
+concept C = requires (T t, U u) { t + u; }; // { dg-message "in requirements" }
+
+template <class T, class U>
+ requires C<T,U>
+void f(T t, U u) { t + u; }
+
+struct non_addable { };
+
+int main()
+{
+ // FIXME: This diagnostic is being emitted twice, when it should
+ // be emitted just once.
+ using U = decltype(f(42, non_addable{})); // { dg-error "cannot call function" }
+}
diff --git a/gcc/testsuite/g++.dg/concepts/req15.C b/gcc/testsuite/g++.dg/cpp2a/concepts-requires9.C
index 385d51da8cd..3594176627f 100644
--- a/gcc/testsuite/g++.dg/concepts/req15.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires9.C
@@ -1,6 +1,5 @@
// PR c++/66832
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
+// { dg-do compile { target c++2a } }
template <class T, class U, unsigned N>
requires requires (T& t, U &u) { t.foo(); u.foo(); }
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-sfinae1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-sfinae1.C
new file mode 100644
index 00000000000..87b5d750f66
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-sfinae1.C
@@ -0,0 +1,10 @@
+// { dg-do compile { target concepts } }
+
+template <class T> struct A
+{
+ static const int x = 42;
+};
+
+template <class T> concept R42 = A<T&>::x == 42;
+
+static_assert (!R42<void>);
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-template-parm1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-template-parm1.C
new file mode 100644
index 00000000000..4ff401a98e9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-template-parm1.C
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++2a } }
+
+template<typename T>
+concept Int = __is_same_as(T, int);
+
+// Type template parameters
+template<Int T = int> struct S1 { };
+template<Int = int> struct S2;
+template<Int T> struct S2 { };
+
+// Non-type template parameters
+template<Int auto N = 0> struct S3 { };
+template<Int auto = 0> struct S4;
+template<Int auto N> struct S4 { };
+
+S1<> s1;
+S2<> s2;
+S3<> s3;
+S4<> s4;
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-template-parm10.C b/gcc/testsuite/g++.dg/cpp2a/concepts-template-parm10.C
new file mode 100644
index 00000000000..239b485f717
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-template-parm10.C
@@ -0,0 +1,10 @@
+// { dg-do compile { target c++2a } }
+
+template <class>
+concept Dummy = true;
+
+template <typename>
+class example {
+ template <Dummy<> U>
+ friend auto func();
+};
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-template-parm2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-template-parm2.C
new file mode 100644
index 00000000000..7c1d69b38d1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-template-parm2.C
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++2a } }
+
+template<typename T>
+ concept Int = __is_same_as(T, int);
+
+template<typename> struct Foo;
+
+// Instantiation of default arguments happens at the point of
+// instantiation for the class.
+
+template<Int T = char> struct S1 { };
+template<Int auto X = false> struct S2 { };
+
+S1<> s1; // { dg-error "constraint failure" }
+S2<> s2; // { dg-error "placeholder constraints not satisfied" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-template-parm5.C b/gcc/testsuite/g++.dg/cpp2a/concepts-template-parm5.C
new file mode 100644
index 00000000000..78b6f1c799b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-template-parm5.C
@@ -0,0 +1,9 @@
+// { dg-do compile { target c++2a } }
+
+template<typename T>
+ concept Int = __is_same_as(T, int);
+
+template<Int... Ts = int> struct S1; // { dg-error "default argument" }
+template<Int... = int> struct S2; // { dg-error "default argument" }
+template<Int auto... Ns = 0> struct S3; // { dg-error "default argument" }
+template<Int auto... = 0> struct S4; // { dg-error "default argument" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-template-parm6.C b/gcc/testsuite/g++.dg/cpp2a/concepts-template-parm6.C
new file mode 100644
index 00000000000..47c8ef72c90
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-template-parm6.C
@@ -0,0 +1,44 @@
+// { dg-do compile { target c++2a } }
+
+template<typename... Ts> struct are_same;
+
+template<>
+ struct are_same<> {
+ static constexpr bool value = true;
+ };
+
+template<typename T>
+ struct are_same<T> {
+ static constexpr bool value = true;
+ };
+
+template<typename T, typename U, typename... Ts>
+ struct are_same<T, U, Ts...> {
+ static constexpr bool value =
+ __is_same_as(T, U) && are_same<U, Ts...>::value;
+ };
+
+template<typename... Ts>
+concept Same = are_same<Ts...>::value;
+
+template<typename T>
+concept Int = __is_same_as(T, int);
+
+// NOTE: The use of Same is misleading; it constraints each T, not
+// the pack of Ts.
+template<Same... Ts> struct S1 { }; // requires (C<Ts> && ...)
+S1<int, int, int> s1;
+S1<int, int, bool> s2;
+
+// // NOTE: The use of Same is misleading; it constraints each deduced
+// // type, not the pack of Ts.
+template<Same auto... Xs> struct S2 { }; // requires (C<X> && ...) with each X deduced
+S2<true, true, true> s3;
+S2<true, true, 'a'> s4; // OK
+
+template<Int... Ts> struct S3 { }; // requires (C<Ts> && ...)
+S3<int, int, char> x0; // { dg-error "template constraint failure" }
+
+template<Int auto... Xs> struct S4 { }; // requires (C<X> && ...) with each X deduced
+S4<0, 1, 2, 'a'> x1; // { dg-error "placeholder constraints not satisfied" }
+
diff --git a/gcc/testsuite/g++.dg/concepts/template-parm8.C b/gcc/testsuite/g++.dg/cpp2a/concepts-template-parm8.C
index 63c45124222..adcffed060c 100644
--- a/gcc/testsuite/g++.dg/concepts/template-parm8.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-template-parm8.C
@@ -1,13 +1,12 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
+// { dg-do compile { target c++2a } }
template<typename T>
- concept bool C() { return __is_class(T); }
+ concept C = __is_class(T);
template<typename T>
- concept bool D() { return C<T>() and __is_empty(T); }
+ concept D = C<T> and __is_empty(T);
-template<template<typename Q> requires C<Q>() class X>
+template<template<typename Q> requires C<Q> class X>
struct S { };
// An unconstrained template can be used as an argument for any
@@ -16,7 +15,7 @@ template<typename A> struct T0 { };
S<T0> x1;
// Matching constraints are valid.
-template<typename A> requires C<A>() struct T1 { };
+template<typename A> requires C<A> struct T1 { };
S<T1> x2;
int main() { }
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-template-parm9.C b/gcc/testsuite/g++.dg/cpp2a/concepts-template-parm9.C
new file mode 100644
index 00000000000..d578b354084
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-template-parm9.C
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++2a } }
+
+template<typename T>
+ concept C = __is_class(T);
+
+template<typename T>
+ concept D = C<T> and __is_empty(T);
+
+template<template<typename Q> requires C<Q> class X>
+ struct S { };
+
+template<typename A> requires true struct T0 { };
+template<typename A> requires D<A> struct T1 { };
+
+S<T0> x3; // { dg-error "constraint mismatch|invalid type" }
+S<T1> x4; // { dg-error "constraint mismatch|invalid type" }
+
+int main() { }
diff --git a/gcc/testsuite/g++.dg/concepts/traits1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-traits1.C
index 27610e25a54..0ea529ef4a6 100644
--- a/gcc/testsuite/g++.dg/concepts/traits1.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-traits1.C
@@ -1,62 +1,61 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
+// { dg-options "-std=c++2a" }
template<typename T>
- concept bool Nothrow_assignable() { return __has_nothrow_assign(T); }
+ concept Nothrow_assignable = __has_nothrow_assign(T);
template<typename T>
- concept bool Nothrow_constructible() { return __has_nothrow_constructor(T); }
+ concept Nothrow_constructible = __has_nothrow_constructor(T);
template<typename T>
- concept bool Nothrow_copyable() { return __has_nothrow_copy(T); }
+ concept Nothrow_copyable = __has_nothrow_copy(T);
template<typename T>
- concept bool Trivially_assignable() { return __has_trivial_assign(T); }
+ concept Trivially_assignable = __has_trivial_assign(T);
template<typename T>
- concept bool Trivially_constructible() { return __has_trivial_constructor(T); }
+ concept Trivially_constructible = __has_trivial_constructor(T);
template<typename T>
- concept bool Trivially_copyable() { return __has_trivial_copy(T); }
+ concept Trivially_copyable = __has_trivial_copy(T);
template<typename T>
- concept bool Trivially_destructible() { return __has_trivial_destructor(T); }
+ concept Trivially_destructible = __has_trivial_destructor(T);
template<typename T>
- concept bool Dynamically_destructible() { return __has_virtual_destructor(T); }
+ concept Dynamically_destructible = __has_virtual_destructor(T);
template<typename T>
- concept bool Abstract() { return __is_abstract(T); }
+ concept Abstract = __is_abstract(T);
template<typename T>
- concept bool Polymorphic() { return __is_polymorphic(T); }
+ concept Polymorphic = __is_polymorphic(T);
template<typename T>
- concept bool Class() { return __is_class(T); }
+ concept Class = __is_class(T);
template<typename T>
- concept bool Empty() { return __is_empty(T); }
+ concept Empty = __is_empty(T);
template<typename T>
- concept bool Enum() { return __is_enum(T); }
+ concept Enum = __is_enum(T);
template<typename T>
- concept bool Final() { return __is_final(T); }
+ concept Final = __is_final(T);
template<typename T>
- concept bool Literal_type() { return __is_literal_type(T); }
+ concept Literal_type = __is_literal_type(T);
template<typename T>
- concept bool Pod() { return __is_pod(T); }
+ concept Pod = __is_pod(T);
template<typename T>
- concept bool Standard_layout() { return __is_standard_layout(T); }
+ concept Standard_layout = __is_standard_layout(T);
template<typename T>
- concept bool Trivial() { return __is_trivial(T); }
+ concept Trivial = __is_trivial(T);
template<typename T>
- concept bool Union() { return __is_union(T); }
+ concept Union = __is_union(T);
template<Nothrow_assignable T> void f1() { }
template<Nothrow_copyable T> void f2() { }
diff --git a/gcc/testsuite/g++.dg/concepts/traits2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-traits2.C
index 71dcfd37e6a..1dc5ffe9c00 100644
--- a/gcc/testsuite/g++.dg/concepts/traits2.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-traits2.C
@@ -1,62 +1,61 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
+// { dg-do compile { target c++2a } }
template<typename T>
- concept bool Nothrow_assignable() { return __has_nothrow_assign(T); }
+ concept Nothrow_assignable = __has_nothrow_assign(T);
template<typename T>
- concept bool Nothrow_constructible() { return __has_nothrow_constructor(T); }
+ concept Nothrow_constructible = __has_nothrow_constructor(T);
template<typename T>
- concept bool Nothrow_copyable() { return __has_nothrow_copy(T); }
+ concept Nothrow_copyable = __has_nothrow_copy(T);
template<typename T>
- concept bool Trivially_assignable() { return __has_trivial_assign(T); }
+ concept Trivially_assignable = __has_trivial_assign(T);
template<typename T>
- concept bool Trivially_constructible() { return __has_trivial_constructor(T); }
+ concept Trivially_constructible = __has_trivial_constructor(T);
template<typename T>
- concept bool Trivially_copyable() { return __has_trivial_copy(T); }
+ concept Trivially_copyable = __has_trivial_copy(T);
template<typename T>
- concept bool Trivially_destructible() { return __has_trivial_destructor(T); }
+ concept Trivially_destructible = __has_trivial_destructor(T);
template<typename T>
- concept bool Dynamically_destructible() { return __has_virtual_destructor(T); }
+ concept Dynamically_destructible = __has_virtual_destructor(T);
template<typename T>
- concept bool Abstract() { return __is_abstract(T); }
+ concept Abstract = __is_abstract(T);
template<typename T>
- concept bool Polymorphic() { return __is_polymorphic(T); }
+ concept Polymorphic = __is_polymorphic(T);
template<typename T>
- concept bool Class() { return __is_class(T); }
+ concept Class = __is_class(T);
template<typename T>
- concept bool Empty() { return __is_empty(T); }
+ concept Empty = __is_empty(T);
template<typename T>
- concept bool Enum() { return __is_enum(T); }
+ concept Enum = __is_enum(T);
template<typename T>
- concept bool Final() { return __is_final(T); }
+ concept Final = __is_final(T);
template<typename T>
- concept bool Literal_type() { return __is_literal_type(T); }
+ concept Literal_type = __is_literal_type(T);
template<typename T>
- concept bool Pod() { return __is_pod(T); }
+ concept Pod = __is_pod(T);
template<typename T>
- concept bool Standard_layout() { return __is_standard_layout(T); }
+ concept Standard_layout = __is_standard_layout(T);
template<typename T>
- concept bool Trivial() { return __is_trivial(T); }
+ concept Trivial = __is_trivial(T);
template<typename T>
- concept bool Union() { return __is_union(T); }
+ concept Union = __is_union(T);
template<Nothrow_assignable T> void f1();
template<Nothrow_copyable T> void f2();
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-ts1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-ts1.C
new file mode 100644
index 00000000000..b819ad4a1a2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-ts1.C
@@ -0,0 +1,49 @@
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+
+// This tests the terse notation.
+
+template<typename T>
+concept True = true;
+
+template<typename T>
+concept False = false;
+
+template<typename T, typename U>
+concept SameAs = __is_same_as(T, U);
+
+True x1 = 0;
+False x2 = 0; // { dg-error "deduced initializer does not satisfy" }
+
+void f1(True t) { }
+void f2(False t) { }
+void f3(SameAs<int> q) { }
+void f4(True a, SameAs<decltype(a)> b) { }
+
+True f5() { return 0; }
+False f6() { return 0; } // { dg-error "deduced return type" }
+SameAs<int> f7() { return 0; }
+SameAs<int> f8() { return 'a'; } // { dg-error "deduced return type" }
+auto f9() -> True { return 0; }
+auto f10() -> False { return 0; } // { dg-error "deduced return type" }
+auto f11() -> SameAs<int> { return 0; }
+auto f12() -> SameAs<char> { return 0; } // { dg-error "deduced return type" }
+auto f13(int n) -> SameAs<decltype(n)> { return n; }
+auto f14(int n) -> SameAs<decltype(n)> { return 'a'; } // { dg-error "deduced return type" }
+auto f15(auto x) -> SameAs<decltype(x)> { return 0; } // { dg-error "deduced return type" }
+
+void driver()
+{
+ f1(0);
+ f2(0); // { dg-error "cannot call" }
+ f3(0);
+ f3('a'); // { dg-error "cannot call" }
+ f4(0, 0);
+ f4(0, 'a'); // { dg-error "cannot call" }
+ f15(0);
+ f15('a'); // { dg-message "" }
+}
+
+template<class T> concept bool C1() { return false; }
+template<C1 T> concept bool C2() { return true; } // { dg-error "cannot be constrained" }
+template<C1 T> concept bool C3 = true; // { dg-error "cannot be constrained" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-ts2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-ts2.C
new file mode 100644
index 00000000000..9d2dbeee7f3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-ts2.C
@@ -0,0 +1,260 @@
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+
+// Basic tests using function concepts.
+
+template<typename T>
+concept bool Type() { return true; }
+
+template<typename T>
+concept bool False() { return false; }
+
+template<typename T>
+concept bool Class() { return __is_class(T); }
+
+template<typename T>
+concept bool EmptyClass() { return Class<T>() && __is_empty(T); }
+
+template<typename T, typename U>
+concept bool Classes() { return __is_class(T) && __is_class (U); }
+
+struct empty { };
+
+struct nonempty { int n; };
+
+static_assert(Type<int>());
+static_assert(False<int>()); // { dg-error "static assertion failed" }
+
+// Basic checks
+
+template<typename T>
+ requires (Type<T>())
+int fn1(T t) { return 0; }
+
+template<typename T>
+ requires (False<T>())
+int fn2(T t) { return 0; }
+
+void driver()
+{
+ fn1(0); // OK
+ fn2(0); // { dg-error "cannot call function" }
+}
+
+// Ordering
+
+template<typename T>
+concept bool Cf() { return requires (T t) { t.f(); }; }
+
+template<typename T>
+concept bool Cfg() { return Cf<T>() && requires (T t) { t.g(); }; }
+
+template<typename T>
+concept bool Cf2() { return requires (T t) { t.f(); }; }
+
+template<typename T>
+constexpr int algo(T t) { return 0; }
+
+template<typename T> requires (Cf<T>())
+constexpr int algo(T t) { return 1; }
+
+template<typename T> requires (Cfg<T>())
+constexpr int algo(T t) { return 2; }
+
+template<typename T> requires (Cf<T>())
+constexpr int ambig(T t) { return 1; }
+
+template<typename T> requires (Cf2<T>())
+constexpr int ambig(T t) { return 1; }
+
+struct T1 {
+ void f() { }
+};
+
+struct T2 : T1 {
+ void g() { }
+};
+
+void driver_0()
+{
+ T1 x;
+ T2 y;
+ static_assert(algo(0) == 0);
+ static_assert(algo(x) == 1);
+ static_assert(algo(y) == 2);
+ ambig(x); // { dg-error "call of overload | is ambiguous" }
+}
+
+template<typename T>
+struct S
+{
+ void f() requires (Class<T>()) { }
+
+ template<typename U>
+ struct Inner
+ {
+ void g() requires (Classes<T, U>()) { }
+ };
+
+ template<typename U> requires (Classes<T, U>()) void h(U) { }
+};
+
+struct X { };
+
+void driver_1()
+{
+ S<X> s1;
+ s1.f(); // OK
+ s1.h(s1); // OK
+ s1.h(0); // { dg-error "no matching function" }
+
+ S<int> s2;
+ s2.f(); // { dg-error "no matching function" }
+
+ S<X>::Inner<X> si1;
+ si1.g();
+
+ S<X>::Inner<int> si2;
+ si2.g(); // { dg-error "no matching function" }
+}
+
+// Check constraints on non-dependent arguments, even when in a
+// dependent context.
+
+template<typename T> requires (Class<T>()) void f1(T x) { }
+
+// fn1-2.C -- Dependent checks
+template<typename T>
+void caller_1(T x)
+{
+ f1(x); // Unchecked dependent arg.
+ f1(empty{}); // Checked non-dependent arg, but OK
+ f1(0); // { dg-error "cannot call function" }
+}
+
+// fn3.c -- Ordering
+template<typename T>
+ requires (Class<T>())
+constexpr int f2(T x) { return 1; }
+
+template<typename T>
+ requires (EmptyClass<T>())
+constexpr int f2(T x) { return 2; }
+
+template<typename T>
+constexpr int f3(T x) requires (Class<T>()) { return 1; }
+
+template<typename T>
+constexpr int f3(T x) requires (EmptyClass<T>()) { return 2; }
+
+void driver_2()
+{
+ f2(0); // { dg-error "no matching function" }
+ static_assert (f2(empty{}) == 2);
+ static_assert (f2(nonempty{}) == 1);
+ f3(0); // { dg-error "no matching function" }
+ static_assert (f3(empty{}) == 2);
+ static_assert (f3(nonempty{}) == 1);
+}
+
+// fn8.C -- Address of overloaded functions
+template<typename T> requires (Type<T>()) void ok(T) { }
+template<typename T> requires (Class<T>()) void err(T) { }
+
+auto p1 = &ok<int>;
+auto p2 = &err<int>; // { dg-error "no matches" }
+void (*p3)(int) = &ok<int>;
+void (*p4)(int) = &err<int>; // { dg-error "no matches" }
+void (*p5)(int) = &ok;
+void (*p6)(int) = &err; // { dg-error "no matches" }
+
+template<typename T> void g(T x) { }
+
+void driver_3 ()
+{
+ g(&ok<int>);
+ g(&err<int>); // { dg-error "no matches" }
+}
+
+
+struct S2 {
+ template<typename T> requires (Type<T>()) int ok(T) { return 0; }
+ template<typename T> requires (Class<T>()) int err(T) { return 0; }
+};
+
+auto p7 = &S2::ok<int>;
+auto p8 = &S2::err<int>; // { dg-error "no matches" }
+int (S2::*p9)(int) = &S2::ok<int>;
+int (S2::*p10)(int) = &S2::err<int>; // { dg-error "no matches" }
+int (S2::*p11)(int) = &S2::ok;
+int (S2::*p12)(int) = &S2::err; // { dg-error "no matches" }
+
+// fn9.C -- Ordering with function address
+template<typename T>
+ requires (Class<T>())
+constexpr int fn(T) { return 1; }
+
+template<typename T>
+ requires (EmptyClass<T>())
+constexpr int fn(T) { return 2; }
+
+struct S3
+{
+ template<typename T>
+ requires (Class<T>())
+ constexpr int fn(T) const { return 1; }
+
+ template<typename T>
+ requires (EmptyClass<T>())
+ constexpr int fn(T) const { return 2; }
+};
+
+void driver_5 () {
+ struct X { };
+ struct Y { X x; };
+
+ constexpr X x;
+ constexpr Y y;
+ constexpr S3 s;
+
+ constexpr auto p1 = &fn<X>; // Empty f
+ static_assert (p1(x) == 2);
+
+ constexpr auto p2 = &fn<Y>; // Class f
+ static_assert(p2(y) == 1);
+
+ constexpr auto p3 = &S3::fn<X>; // Empty f
+ static_assert((s.*p3)(x) == 2);
+
+ constexpr auto p4 = &S3::fn<Y>; // Empty f
+ static_assert((s.*p4)(y) == 1);
+}
+
+
+// Redeclarations
+
+// FIXME: This should be a diagnosable error. The programmer has moved
+// the requirements from the template-head to the declarator.
+template<typename T> requires (Type<T>()) void f3();
+template<typename T> void f3() requires (Type<T>());
+
+void driver_4()
+{
+ f3<int>(); // { dg-error "call of overload | ambiguous" }
+}
+
+template<template<typename T> requires true class X> void f4();
+template<template<typename T> class X> void f4(); // OK: different declarations
+
+template<typename T> requires (Type<T>()) void def() { }
+template<typename T> requires (Type<T>()) void def() { } // { dg-error "redefinition" }
+
+// fn-concept1.C
+
+template<typename T>
+concept bool Tuple() { // { dg-error "multiple statements" }
+ static_assert(T::value, "");
+ return true;
+}
+
+void f(Tuple&);
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-ts3.C b/gcc/testsuite/g++.dg/cpp2a/concepts-ts3.C
new file mode 100644
index 00000000000..c1f4ba9c700
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-ts3.C
@@ -0,0 +1,251 @@
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+
+// Basic tests using variable concepts.
+
+template<typename T>
+concept bool Type = true;
+
+template<typename T>
+concept bool False = false;
+
+template<typename T>
+concept bool Class = __is_class(T);
+
+template<typename T>
+concept bool EmptyClass = Class<T> && __is_empty(T);
+
+template<typename T, typename U>
+concept bool Classes = __is_class(T) && __is_class (U);
+
+struct empty { };
+
+struct nonempty { int n; };
+
+static_assert(Type<int>);
+static_assert(False<int>); // { dg-error "static assertion failed" }
+
+// Basic checks
+
+template<typename T>
+ requires Type<T>
+int fn1(T t) { return 0; }
+
+template<typename T>
+ requires False<T>
+int fn2(T t) { return 0; }
+
+void driver()
+{
+ fn1(0); // OK
+ fn2(0); // { dg-error "cannot call function" }
+}
+
+// Ordering
+
+template<typename T>
+concept bool Cf = requires (T t) { t.f(); };
+
+template<typename T>
+concept bool Cfg = Cf<T> && requires (T t) { t.g(); };
+
+template<typename T>
+concept bool Cf2 = requires (T t) { t.f(); };
+
+template<typename T>
+constexpr int algo(T t) { return 0; }
+
+template<typename T> requires Cf<T>
+constexpr int algo(T t) { return 1; }
+
+template<typename T> requires Cfg<T>
+constexpr int algo(T t) { return 2; }
+
+template<typename T> requires Cf<T>
+constexpr int ambig(T t) { return 1; }
+
+template<typename T> requires Cf2<T>
+constexpr int ambig(T t) { return 1; }
+
+struct T1 {
+ void f() { }
+};
+
+struct T2 : T1 {
+ void g() { }
+};
+
+void driver_0()
+{
+ T1 x;
+ T2 y;
+ static_assert(algo(0) == 0);
+ static_assert(algo(x) == 1);
+ static_assert(algo(y) == 2);
+ ambig(x); // { dg-error "call of overload | is ambiguous" }
+}
+
+template<typename T>
+struct S
+{
+ void f() requires Class<T> { }
+
+ template<typename U>
+ struct Inner
+ {
+ void g() requires Classes<T, U> { }
+ };
+
+ template<typename U> requires Classes<T, U> void h(U) { }
+};
+
+struct X { };
+
+void driver_1()
+{
+ S<X> s1;
+ s1.f(); // OK
+ s1.h(s1); // OK
+ s1.h(0); // { dg-error "no matching function" }
+
+ S<int> s2;
+ s2.f(); // { dg-error "no matching function" }
+
+ S<X>::Inner<X> si1;
+ si1.g();
+
+ S<X>::Inner<int> si2;
+ si2.g(); // { dg-error "no matching function" }
+}
+
+// Check constraints on non-dependent arguments, even when in a
+// dependent context.
+
+template<typename T> requires Class<T> void f1(T x) { }
+
+// fn1-2.C -- Dependent checks
+template<typename T>
+void caller_1(T x)
+{
+ f1(x); // Unchecked dependent arg.
+ f1(empty{}); // Checked non-dependent arg, but OK
+ f1(0); // { dg-error "cannot call function" }
+}
+
+// fn3.c -- Ordering
+template<typename T>
+ requires Class<T>
+constexpr int f2(T x) { return 1; }
+
+template<typename T>
+ requires EmptyClass<T>
+constexpr int f2(T x) { return 2; }
+
+template<typename T>
+constexpr int f3(T x) requires Class<T> { return 1; }
+
+template<typename T>
+constexpr int f3(T x) requires EmptyClass<T> { return 2; }
+
+void driver_2()
+{
+ f2(0); // { dg-error "no matching function" }
+ static_assert (f2(empty{}) == 2);
+ static_assert (f2(nonempty{}) == 1);
+ f3(0); // { dg-error "no matching function" }
+ static_assert (f3(empty{}) == 2);
+ static_assert (f3(nonempty{}) == 1);
+}
+
+// fn8.C -- Address of overloaded functions
+template<typename T> requires Type<T> void ok(T) { }
+template<typename T> requires Class<T> void err(T) { }
+
+auto p1 = &ok<int>;
+auto p2 = &err<int>; // { dg-error "no matches" }
+void (*p3)(int) = &ok<int>;
+void (*p4)(int) = &err<int>; // { dg-error "no matches" }
+void (*p5)(int) = &ok;
+void (*p6)(int) = &err; // { dg-error "no matches" }
+
+template<typename T> void g(T x) { }
+
+void driver_3 ()
+{
+ g(&ok<int>);
+ g(&err<int>); // { dg-error "no matches" }
+}
+
+
+struct S2 {
+ template<typename T> requires Type<T> int ok(T) { return 0; }
+ template<typename T> requires Class<T> int err(T) { return 0; }
+};
+
+auto p7 = &S2::ok<int>;
+auto p8 = &S2::err<int>; // { dg-error "no matches" }
+int (S2::*p9)(int) = &S2::ok<int>;
+int (S2::*p10)(int) = &S2::err<int>; // { dg-error "no matches" }
+int (S2::*p11)(int) = &S2::ok;
+int (S2::*p12)(int) = &S2::err; // { dg-error "no matches" }
+
+// fn9.C -- Ordering with function address
+template<typename T>
+ requires Class<T>
+constexpr int fn(T) { return 1; }
+
+template<typename T>
+ requires EmptyClass<T>
+constexpr int fn(T) { return 2; }
+
+struct S3
+{
+ template<typename T>
+ requires Class<T>
+ constexpr int fn(T) const { return 1; }
+
+ template<typename T>
+ requires EmptyClass<T>
+ constexpr int fn(T) const { return 2; }
+};
+
+void driver_5 () {
+ struct X { };
+ struct Y { X x; };
+
+ constexpr X x;
+ constexpr Y y;
+ constexpr S3 s;
+
+ constexpr auto p1 = &fn<X>; // Empty f
+ static_assert (p1(x) == 2);
+
+ constexpr auto p2 = &fn<Y>; // Class f
+ static_assert(p2(y) == 1);
+
+ constexpr auto p3 = &S3::fn<X>; // Empty f
+ static_assert((s.*p3)(x) == 2);
+
+ constexpr auto p4 = &S3::fn<Y>; // Empty f
+ static_assert((s.*p4)(y) == 1);
+}
+
+
+// Redeclarations
+
+// FIXME: This should be a diagnosable error. The programmer has moved
+// the requirements from the template-head to the declarator.
+template<typename T> requires Type<T> void f3();
+template<typename T> void f3() requires Type<T>;
+
+void driver_4()
+{
+ f3<int>(); // { dg-error "call of overload | ambiguous" }
+}
+
+template<template<typename T> requires true class X> void f4();
+template<template<typename T> class X> void f4(); // OK: different declarations
+
+template<typename T> requires Type<T> void def() { }
+template<typename T> requires Type<T> void def() { } // { dg-error "redefinition" }
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-ts4.C b/gcc/testsuite/g++.dg/cpp2a/concepts-ts4.C
new file mode 100644
index 00000000000..3d720e86f3b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-ts4.C
@@ -0,0 +1,34 @@
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+
+// Basic tests for introduction syntax.
+
+template<typename T>
+concept True = true;
+
+template<typename T>
+concept False = false;
+
+template<typename T, typename U>
+concept Same = __is_same_as(T, U);
+
+template<int N>
+concept Pos = N >= 0;
+
+True{T} void f1(T) { }
+False{T} void f2(T) { }
+Same{X, Y} void same();
+Pos{N} void fn();
+
+void driver()
+{
+ f1(0);
+ f2(0); // { dg-error "cannot call function" }
+
+ same<int, int>();
+ same<int, char>(); // { dg-error "cannot call function" }
+
+ fn<0>(); // OK
+ fn<-1>(); // { dg-error "cannot call function" }
+ fn<int>(); // { dg-error "no matching function" }
+}
diff --git a/gcc/testsuite/g++.dg/concepts/member-concept.C b/gcc/testsuite/g++.dg/cpp2a/concepts-ts5.C
index ef577a19d07..cdc40df4387 100644
--- a/gcc/testsuite/g++.dg/concepts/member-concept.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-ts5.C
@@ -1,5 +1,5 @@
-// { dg-do compile { target c++17 } }
-// { dg-options "-fconcepts" }
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
struct Base {
template<typename T>
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-ts6.C b/gcc/testsuite/g++.dg/cpp2a/concepts-ts6.C
new file mode 100644
index 00000000000..bf665aa6308
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-ts6.C
@@ -0,0 +1,72 @@
+// { dg-do compile { target c++2a } }
+// { dg-additional-options "-fconcepts-ts" }
+
+template<typename T, int N, typename... Xs> concept bool C1 = true;
+
+template<template<typename> class X> concept bool C2 = true;
+
+template<typename... Ts> concept bool C3 = true;
+
+C1{A, B, ...C} struct S1 { };
+
+C2{T} void f();
+
+C2{...Ts} void g(); // { dg-error "cannot be introduced" }
+
+C3{...Ts} struct S2 { };
+C3{T, U, V} struct S3 { };
+C3{...Ts, U} struct S4 { }; // { dg-error "cannot deduce template parameters" }
+
+template<typename> struct X { };
+
+void driver1() {
+ S1<int, 0, char, bool, float> s1a;
+ S1<0, 0, char, bool, float> s1b; // { dg-error "type/value mismatch" }
+
+ f<X>();
+ f<int>(); // { dg-error "no matching function for call" }
+
+ S2<int> s2a;
+ S2<char, signed char, unsigned char> s2b;
+ S2<0> s2c; // { dg-error "type/value mismatch" }
+
+ S3<int, int, int> s3a;
+ S3<int, int> s3b; // { dg-error "wrong number of template arguments" }
+}
+
+template<typename... Args>
+struct all_same;
+
+template<typename T, typename U, typename... Args>
+struct all_same<T, U, Args...>
+{
+ static constexpr bool value = __is_same_as(T, U) && all_same<U, Args...>::value;
+};
+
+template<typename T>
+struct all_same<T>
+{
+ static constexpr bool value = true;
+};
+
+template<>
+struct all_same<>
+{
+ static constexpr bool value = true;
+};
+
+template<typename... Ts>
+concept AllSame = all_same<Ts...>::value;
+
+AllSame{...Ts} struct S5 { };
+AllSame{T, U} struct S6 { };
+
+void driver2()
+{
+ S5<int, int> s5a;
+ S5<int, int, int, int> s5b;
+ S5<int, int, int, char> s5c; // { dg-error "template constraint failure" }
+ S6<void, void> s6a;
+ S6<void, int> s6c; // { dg-error "template constraint failure" }
+ S6<void, void, void> s6b; // { dg-error "wrong number of template arguments" }
+} \ No newline at end of file
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-using1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-using1.C
new file mode 100644
index 00000000000..733382db0f5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-using1.C
@@ -0,0 +1,17 @@
+// PR c++/79591
+// { dg-do compile { target c++2a } }
+
+template <class> concept True = true;
+
+// Fine.
+namespace X {
+ void f(auto) {}
+ void f(True auto) {}
+}
+
+void f(auto) {}
+namespace Y {
+ void f(True auto) {}
+ using ::f;
+ // error: 'template<class auto:3> void f(auto:3)' conflicts with a previous declaration
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts.C b/gcc/testsuite/g++.dg/cpp2a/concepts.C
new file mode 100644
index 00000000000..5839207177c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts.C
@@ -0,0 +1,57 @@
+// { dg-do compile { target c++2a } }
+
+// Change in grammar for the expression trailing `requires`.
+template<typename T>
+ requires true != false // { dg-error "must be enclosed" }
+void f1(T)
+{ }
+
+template<typename T>
+void f3(T) requires true != false // { dg-error "must be enclosed" }
+{ }
+
+template<typename T>
+ requires requires {
+ requires true == false; // OK: logical-or-expressions allowed here.
+ }
+void f3(T)
+{ }
+
+template<typename T>
+concept bool C1 = true; // { dg-error "bool" }
+template<typename T>
+bool concept C2 = true; // { dg-error "concept definition syntax" }
+
+template<typename T>
+concept C3 = true; // OK
+template<typename T>
+concept C3 = true; // { dg-error "redefinition" }
+template<typename T, typename U>
+concept C3 = true; // { dg-error "different template parameters" }
+template<int>
+concept C3 = true; // { dg-error "different template parameters" }
+int C3 = 0; // { dg-error "different kind of entity" }
+
+int C4 = 0;
+template<typename T>
+concept C4 = true; // { dg-error "different kind of entity" }
+
+// Concepts as expressions
+
+template<typename T>
+concept True = true;
+
+template<typename T>
+concept False = false;
+
+static_assert(True<int>);
+static_assert(False<int>); // { dg-error "static assertion failed" }
+
+void f4(True auto);
+
+template<True T> concept C5 = true; // { dg-error "cannot be constrained" }
+
+
+template<typename T>
+concept Recursive = Recursive<T>; // { dg-error "not declared|expected" }
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts1.C b/gcc/testsuite/g++.dg/cpp2a/concepts1.C
new file mode 100644
index 00000000000..f22464a9c54
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts1.C
@@ -0,0 +1,27 @@
+// { dg-do compile { target c++2a } }
+
+template<typename T>
+concept Class = __is_class(T);
+
+template<Class T>
+void f1(T) { }
+
+struct empty { };
+
+// Redeclarations involving brief template parameters.
+
+template<Class T>
+void decl1(T);
+
+template<typename T>
+ requires Class<T>
+void decl1(T);
+
+void driver_1()
+{
+ f1(0); // { dg-error "cannot call function" }
+ f1(empty{});
+
+ decl1(empty{}); // { dg-error "call of overload | ambiguous" }
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts2.C b/gcc/testsuite/g++.dg/cpp2a/concepts2.C
new file mode 100644
index 00000000000..d3b45f7ddaa
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts2.C
@@ -0,0 +1,69 @@
+// { dg-do compile { target c++2a } }
+
+template<typename T>
+concept True = true;
+
+template<typename T>
+concept False = false;
+
+template<typename T>
+concept Int = __is_same_as(T, int);
+
+static_assert(True<int>);
+static_assert(!False<int>);
+static_assert(False<int>); // { dg-error "static assertion failed" }
+
+constexpr bool will_be_true() {
+ if (True<int>)
+ return true;
+ return false;
+}
+
+constexpr bool will_be_false() {
+ if (!False<int>)
+ return true;
+ return false;
+}
+
+static_assert(will_be_true());
+static_assert(will_be_false());
+
+template<typename T>
+constexpr bool is_int() {
+ if (Int<T>)
+ return true;
+ return false;
+}
+
+static_assert(is_int<int>());
+static_assert(is_int<void>()); // { dg-error "static assertion failed" }
+
+template<typename T>
+constexpr bool f1() {
+ if (Int<int>) // Note: always true.
+ return true;
+ return false;
+}
+static_assert(f1<int>());
+static_assert(f1<void>());
+
+
+template<typename T>
+constexpr bool f2() {
+ if constexpr (Int<int>) // Note: always true.
+ return true;
+ return false;
+}
+static_assert(f2<int>());
+static_assert(f2<void>());
+
+template<typename T>
+concept C = true;
+
+int driver() {
+ bool c_int = (C<int>);
+ if((C<int>))
+ ;
+ return c_int;
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts3.C b/gcc/testsuite/g++.dg/cpp2a/concepts3.C
new file mode 100644
index 00000000000..d9624268082
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts3.C
@@ -0,0 +1,48 @@
+// { dg-do compile { target c++2a } }
+
+template <class T, class U> concept same_as = __is_same_as(T,U);
+
+template<typename T>
+concept C1 = requires (T& t) { // { dg-message "in requirements" }
+ t.~T();
+};
+
+template<typename T>
+concept C2 = requires (T& t) { // { dg-message "in requirements" }
+ { t.~T() } -> same_as<void>;
+};
+
+template<typename T>
+concept C3 = requires { // { dg-message "in requirements" }
+ typename T::type;
+};
+
+class S1
+{
+ ~S1() { }
+ using type = int;
+};
+
+void driver() {
+ static_assert(C1<S1>, ""); // { dg-error "static assertion failed" }
+ static_assert(C2<S1>, ""); // { dg-error "static assertion failed" }
+ static_assert(C3<S1>, ""); // { dg-error "static assertion failed" }
+}
+
+template<typename T>
+ requires C1<T>
+void f1() { }
+
+template<typename T>
+ requires C2<T>
+void f2() { }
+
+template<typename T>
+ requires C3<T>
+void f3() { }
+
+void driver2() {
+ f1<S1>(); // { dg-error "cannot call|is private" }
+ f2<S1>(); // { dg-error "cannot call|is private" }
+ f3<S1>(); // { dg-error "cannot call|is private" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts4.C b/gcc/testsuite/g++.dg/cpp2a/concepts4.C
new file mode 100644
index 00000000000..388fad7514b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts4.C
@@ -0,0 +1,10 @@
+// { dg-do compile { target c++2a } }
+
+template <class T> struct A { static const int x = 42; };
+
+template <class Ta> concept A42 = A<Ta>::x == 42;
+template <class Tv> concept Void = __is_same_as(Tv, void);
+template <class Tb, class Ub> concept A42b = Void<Tb> || A42<Ub>;
+template <class Tc> concept R42c = A42b<Tc, Tc&>;
+
+static_assert (R42c<void>);
diff --git a/gcc/testsuite/g++.dg/cpp2a/cond-triv2.C b/gcc/testsuite/g++.dg/cpp2a/cond-triv2.C
new file mode 100644
index 00000000000..554f8a3328a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/cond-triv2.C
@@ -0,0 +1,30 @@
+// PR c++/67348
+// { dg-do compile { target c++2a } }
+
+#include <type_traits>
+#include <vector>
+using namespace std;
+
+template <class...Ts>
+ requires (is_destructible<Ts>::value && ...)
+struct variant {
+ ~variant() { /* ... */ }
+ ~variant()
+ requires (is_trivially_destructible<Ts>::value && ...) = default;
+
+ variant(variant&&) { /* ... */ }
+ variant(variant&&)
+ requires (is_trivially_move_constructible<Ts>::value && ...) = default;
+
+ variant& operator=(variant&&) { /* ... */ }
+ variant& operator=(variant&&)
+ requires (is_trivially_move_assignable<Ts>::value && ...) = default;
+
+ // ...similar treatment for copy construction / assignment...
+};
+
+static_assert(is_trivially_destructible<variant<int, float>>());
+static_assert(!is_trivially_destructible<variant<int, vector<int>>>());
+
+static_assert(is_trivially_move_constructible<variant<int, float>>());
+static_assert(!is_trivially_move_constructible<variant<int, vector<int>>>());
diff --git a/gcc/testsuite/g++.dg/diagnostic/not-a-function-template-1.C b/gcc/testsuite/g++.dg/diagnostic/not-a-function-template-1.C
new file mode 100644
index 00000000000..caf8afa2697
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/not-a-function-template-1.C
@@ -0,0 +1,9 @@
+// { dg-do compile { target c++14 } }
+
+template<typename> int A; // { dg-message "24:variable template" }
+
+template int A<>(); // { dg-error "14:template<class>" }
+
+struct B {
+ friend int A<>(); // { dg-error "14:specialization" }
+};
diff --git a/gcc/testsuite/g++.dg/expr/cond17.C b/gcc/testsuite/g++.dg/expr/cond17.C
new file mode 100644
index 00000000000..1999c376dd1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/expr/cond17.C
@@ -0,0 +1,11 @@
+// PR c++/92070 - bogus error with -fchecking=2.
+// { dg-additional-options "-fchecking=2" }
+
+struct a;
+struct b {
+ static a c();
+};
+struct a : b {};
+template <class> struct d {
+ void e() { 0 ? b() : b::c(); }
+};
diff --git a/gcc/testsuite/g++.dg/gomp/this-1.C b/gcc/testsuite/g++.dg/gomp/this-1.C
index 0e2dd8caa23..30ab8b3903c 100644
--- a/gcc/testsuite/g++.dg/gomp/this-1.C
+++ b/gcc/testsuite/g++.dg/gomp/this-1.C
@@ -3,7 +3,7 @@
struct S
{
- #pragma omp declare simd linear(this) // { dg-error "is not an function argument" }
+ #pragma omp declare simd linear(this) // { dg-error "is not a function argument" }
static void foo ();
void bar ();
};
@@ -35,7 +35,7 @@ S::bar ()
template <int N>
struct T
{
- #pragma omp declare simd linear(this) // { dg-error "is not an function argument" }
+ #pragma omp declare simd linear(this) // { dg-error "is not a function argument" }
static void foo ();
void bar ();
};
diff --git a/gcc/testsuite/g++.dg/pr92022.C b/gcc/testsuite/g++.dg/pr92022.C
new file mode 100644
index 00000000000..066d984ffc5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr92022.C
@@ -0,0 +1,13 @@
+// { dg-do compile { target alpha*-*-* } }
+// { dg-options "-O1 -g -fno-var-tracking -mcpu=ev4 -mieee" }
+
+struct a {
+ a(long);
+};
+long b;
+void c() {
+ a d(1);
+ double e = b;
+ for (; b;)
+ d = e;
+}
diff --git a/gcc/testsuite/g++.dg/template/builtin2.C b/gcc/testsuite/g++.dg/template/builtin2.C
new file mode 100644
index 00000000000..4e9089a2313
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/builtin2.C
@@ -0,0 +1,5 @@
+// PR c++/92049 - extra error with -fchecking=2.
+// { dg-do compile { target c++11 } }
+// { dg-additional-options "-fchecking=2" }
+
+#include "builtin1.C"
diff --git a/gcc/testsuite/g++.dg/template/crash107.C b/gcc/testsuite/g++.dg/template/crash107.C
index cecf9013244..3b0b4e8211f 100644
--- a/gcc/testsuite/g++.dg/template/crash107.C
+++ b/gcc/testsuite/g++.dg/template/crash107.C
@@ -6,8 +6,8 @@
template<typename FP_> struct Vec { // { dg-message "note" }
Vec& operator^=(Vec& rhs) {
union {
- struct {FP_ x,y,z;};
- }; // { dg-error "anonymous struct" }
+ struct {FP_ x,y,z;}; // { dg-error "20:anonymous struct" }
+ };
X = y*rhs.z() - z*rhs.y(); // { dg-error "not declared|no member" }
}
Vec& operator^(Vec& rhs) {
diff --git a/gcc/testsuite/g++.dg/template/crash126.C b/gcc/testsuite/g++.dg/template/crash126.C
index 903cab85cd2..892bc45353e 100644
--- a/gcc/testsuite/g++.dg/template/crash126.C
+++ b/gcc/testsuite/g++.dg/template/crash126.C
@@ -4,7 +4,7 @@ template < class T, class > struct A
{
A ();
A (A &);
- A (A < T, T >); // { dg-error "invalid constructor" }
+ A (A < T, T >); // { dg-error "3:invalid constructor" }
};
void f ()
diff --git a/gcc/testsuite/g++.dg/template/crash129.C b/gcc/testsuite/g++.dg/template/crash129.C
index 9f56b809b26..3bb9e573fed 100644
--- a/gcc/testsuite/g++.dg/template/crash129.C
+++ b/gcc/testsuite/g++.dg/template/crash129.C
@@ -1,5 +1,5 @@
// PR c++/79626
template <class a, class> struct b
-{ b(); b(b &); b(b< a, a >); }; // { dg-error "invalid constructor" }
+{ b(); b(b &); b(b< a, a >); }; // { dg-error "16:invalid constructor" }
int c(b< int, int >(b< int, int >()); // { dg-error "" }
diff --git a/gcc/testsuite/g++.dg/template/dependent-expr1.C b/gcc/testsuite/g++.dg/template/dependent-expr1.C
index 79649861ba4..eda7526e1b1 100644
--- a/gcc/testsuite/g++.dg/template/dependent-expr1.C
+++ b/gcc/testsuite/g++.dg/template/dependent-expr1.C
@@ -19,11 +19,11 @@ namespace std
Foo (sizeof (x));
Foo (__alignof__ (I));
Foo (__alignof__ (x));
- Foo (x->~I ()); // { dg-error "" }
+ Foo (x->~I ()); // { dg-error "16:invalid" }
// Foo (typeid (I));
- Foo (delete x); // { dg-error "" }
- Foo (delete[] x); // { dg-error "" }
- Foo (throw x); // { dg-error "" }
+ Foo (delete x); // { dg-error "10:invalid" }
+ Foo (delete[] x); // { dg-error "10:invalid" }
+ Foo (throw x); // { dg-error "10:invalid" }
}
}
diff --git a/gcc/testsuite/g++.dg/template/error17.C b/gcc/testsuite/g++.dg/template/error17.C
index 30a693f84d1..5b3281a1779 100644
--- a/gcc/testsuite/g++.dg/template/error17.C
+++ b/gcc/testsuite/g++.dg/template/error17.C
@@ -5,5 +5,5 @@ void
foo()
{
union { struct { }; }; // { dg-error "prohibits anonymous struct" "anon" }
- // { dg-error "not inside" "not inside" { target *-*-* } .-1 }
+ // { dg-error "18:anonymous struct not inside" "not inside" { target *-*-* } .-1 }
}
diff --git a/gcc/testsuite/g++.dg/warn/Wextra-3.C b/gcc/testsuite/g++.dg/warn/Wextra-3.C
index 04fdbba9076..1bf2a6e4977 100644
--- a/gcc/testsuite/g++.dg/warn/Wextra-3.C
+++ b/gcc/testsuite/g++.dg/warn/Wextra-3.C
@@ -3,7 +3,7 @@
extern void* p;
-int f1() { return ( p < 0 ? 1 : 0 ); } // { dg-warning "ordered comparison" }
-int f2() { return ( p <= 0 ? 1 : 0 ); } // { dg-warning "ordered comparison" }
-int f3() { return ( p > 0 ? 1 : 0 ); } // { dg-warning "ordered comparison" }
-int f4() { return ( p >= 0 ? 1 : 0 ); } // { dg-warning "ordered comparison" }
+int f1() { return ( p < 0 ? 1 : 0 ); } // { dg-warning "23:ordered comparison" }
+int f2() { return ( p <= 0 ? 1 : 0 ); } // { dg-warning "23:ordered comparison" }
+int f3() { return ( p > 0 ? 1 : 0 ); } // { dg-warning "23:ordered comparison" }
+int f4() { return ( p >= 0 ? 1 : 0 ); } // { dg-warning "23:ordered comparison" }
diff --git a/gcc/testsuite/g++.dg/warn/Wfloat-equal-1.C b/gcc/testsuite/g++.dg/warn/Wfloat-equal-1.C
index 1b23611bdc0..1da04886665 100644
--- a/gcc/testsuite/g++.dg/warn/Wfloat-equal-1.C
+++ b/gcc/testsuite/g++.dg/warn/Wfloat-equal-1.C
@@ -4,7 +4,7 @@
double a, b;
_Complex double c, d;
-int f(void) { return a == b; } /* { dg-warning "comparing floating-point" } */
-int g(void) { return c == d; } /* { dg-warning "comparing floating-point" } */
-int h(void) { return a != b; } /* { dg-warning "comparing floating-point" } */
-int i(void) { return c != d; } /* { dg-warning "comparing floating-point" } */
+int f(void) { return a == b; } /* { dg-warning "24:comparing floating-point" } */
+int g(void) { return c == d; } /* { dg-warning "24:comparing floating-point" } */
+int h(void) { return a != b; } /* { dg-warning "24:comparing floating-point" } */
+int i(void) { return c != d; } /* { dg-warning "24:comparing floating-point" } */
diff --git a/gcc/testsuite/g++.dg/warn/Wstring-literal-comparison-1.C b/gcc/testsuite/g++.dg/warn/Wstring-literal-comparison-1.C
index 97e317644d5..866364277ac 100644
--- a/gcc/testsuite/g++.dg/warn/Wstring-literal-comparison-1.C
+++ b/gcc/testsuite/g++.dg/warn/Wstring-literal-comparison-1.C
@@ -4,7 +4,7 @@
int test1(char *ptr)
{
- return ptr == "foo"; /* { dg-warning "comparison with string" } */
+ return ptr == "foo"; /* { dg-warning "14:comparison with string" } */
}
int test2()
diff --git a/gcc/testsuite/g++.dg/warn/Wstring-literal-comparison-2.C b/gcc/testsuite/g++.dg/warn/Wstring-literal-comparison-2.C
index 3eb91eeca49..fed4c5a37e8 100644
--- a/gcc/testsuite/g++.dg/warn/Wstring-literal-comparison-2.C
+++ b/gcc/testsuite/g++.dg/warn/Wstring-literal-comparison-2.C
@@ -4,7 +4,7 @@
int test1(char *ptr)
{
- return ptr == "foo"; /* { dg-warning "comparison with string" } */
+ return ptr == "foo"; /* { dg-warning "14:comparison with string" } */
}
int test2()
diff --git a/gcc/testsuite/g++.dg/warn/pointer-integer-comparison.C b/gcc/testsuite/g++.dg/warn/pointer-integer-comparison.C
index c6b75a7fc12..a0683ca3746 100644
--- a/gcc/testsuite/g++.dg/warn/pointer-integer-comparison.C
+++ b/gcc/testsuite/g++.dg/warn/pointer-integer-comparison.C
@@ -3,24 +3,24 @@
int foo (int i, void *p)
{
- if (i == p) // { dg-warning "ISO C.. forbids comparison between pointer and integer" }
+ if (i == p) // { dg-warning "9:ISO C.. forbids comparison between pointer and integer" }
return 0;
- else if (i != p) // { dg-warning "ISO C.. forbids comparison between pointer and integer" }
+ else if (i != p) // { dg-warning "14:ISO C.. forbids comparison between pointer and integer" }
return 1;
}
int bar (int i, void *p)
{
- if (i < p) // { dg-warning "ISO C.. forbids comparison between pointer and integer" }
+ if (i < p) // { dg-warning "9:ISO C.. forbids comparison between pointer and integer" }
return 0;
- else if (i >= p) // { dg-warning "ISO C.. forbids comparison between pointer and integer" }
+ else if (i >= p) // { dg-warning "14:ISO C.. forbids comparison between pointer and integer" }
return 1;
}
int baz (int i, void *p)
{
- if (i <= p) // { dg-warning "ISO C.. forbids comparison between pointer and integer" }
+ if (i <= p) // { dg-warning "9:ISO C.. forbids comparison between pointer and integer" }
return 0;
- else if (i > p) // { dg-warning "ISO C.. forbids comparison between pointer and integer" }
+ else if (i > p) // { dg-warning "14:ISO C.. forbids comparison between pointer and integer" }
return 1;
}
diff --git a/gcc/testsuite/g++.old-deja/g++.bugs/900321_01.C b/gcc/testsuite/g++.old-deja/g++.bugs/900321_01.C
index 6b52783c09b..c3b1ab56282 100644
--- a/gcc/testsuite/g++.old-deja/g++.bugs/900321_01.C
+++ b/gcc/testsuite/g++.old-deja/g++.bugs/900321_01.C
@@ -20,7 +20,7 @@ void function_0 ()
{
// we miss the first two because typeck.c (comp_array_types) deems
// it okay if one of the sizes is null
- ptr_to_array_of_ints = ptr_to_array_of_3_ints; // { dg-error "" }
+ ptr_to_array_of_ints = ptr_to_array_of_3_ints; // { dg-error "conversions to arrays" "" { target c++17_down } }
ptr_to_array_of_3_ints = ptr_to_array_of_ints; // { dg-error "" }
ptr_to_array_of_3_ints = ptr_to_array_of_5_ints; // { dg-error "" }
diff --git a/gcc/testsuite/g++.old-deja/g++.jason/crash8.C b/gcc/testsuite/g++.old-deja/g++.jason/crash8.C
index 061652db225..317627a6941 100644
--- a/gcc/testsuite/g++.old-deja/g++.jason/crash8.C
+++ b/gcc/testsuite/g++.old-deja/g++.jason/crash8.C
@@ -1,7 +1,7 @@
// { dg-do assemble }
struct A {
A();
- A(A); // { dg-error "" } copy ctor must take reference
+ A(A); // { dg-error "3:invalid constructor" } copy ctor must take reference
};
int main()
{
diff --git a/gcc/testsuite/gcc.c-torture/compile/pr92063.c b/gcc/testsuite/gcc.c-torture/compile/pr92063.c
new file mode 100644
index 00000000000..bb704abe0ef
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/compile/pr92063.c
@@ -0,0 +1,7 @@
+/* PR middle-end/92063 */
+
+int
+foo (int a, int b, int *c, short *d)
+{
+ return (c[0] ? b : 0) == 'y' && ((a ? d[0] : c[0]) ? b : 0) == 'c';
+}
diff --git a/gcc/testsuite/gcc.dg/Wstring-compare-2.c b/gcc/testsuite/gcc.dg/Wstring-compare-2.c
new file mode 100644
index 00000000000..e6ca2a69999
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstring-compare-2.c
@@ -0,0 +1,127 @@
+/* PR tree-optimization/90879 - fold zero-equality of strcmp between
+ a longer string and a smaller array
+ Test for a warning for strcmp of a longer string against smaller
+ array.
+ { dg-do compile }
+ { dg-options "-O2 -Wall -Wstring-compare -Wno-stringop-truncation -ftrack-macro-expansion=0" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+extern void* memcpy (void*, const void*, size_t);
+
+extern int strcmp (const char*, const char*);
+extern size_t strlen (const char*);
+extern char* strcpy (char*, const char*);
+extern char* strncpy (char*, const char*, size_t);
+extern int strncmp (const char*, const char*, size_t);
+
+void sink (int, ...);
+#define sink(...) sink (__LINE__, __VA_ARGS__)
+
+
+extern char a1[1], a2[2], a3[3], a4[4], a5[5], a6[6], a7[7], a8[8], a9[9];
+
+#define T(a, b) sink (0 == strcmp (a, b))
+
+
+void test_string_cst (void)
+{
+ const char *s1 = "1", *s2 = "12";
+
+ T (s1, a1); // { dg-warning ".strcmp. of a string of length 1 and an array of size 1 evaluates to nonzero" }
+ T (s1, a2);
+ T (s1, a3);
+
+ T (a1, s1); // { dg-warning ".strcmp. of a string of length 1 and an array of size 1 evaluates to nonzero" }
+ T (a2, s1);
+ T (a3, s1);
+
+ T (s2, a1); // { dg-warning ".strcmp. of a string of length 2 and an array of size 1 evaluates to nonzero" }
+ T (s2, a2); // { dg-warning ".strcmp. of a string of length 2 and an array of size 2 evaluates to nonzero" }
+ T (s2, a3);
+
+ T (a1, s2); // { dg-warning ".strcmp. of a string of length 2 and an array of size 1 evaluates to nonzero" }
+ T (a2, s2); // { dg-warning ".strcmp. of a string of length 2 and an array of size 2 evaluates to nonzero" }
+ T (a3, s2);
+}
+
+
+void test_string_cst_off_cst (void)
+{
+ const char *s1 = "1", *s2 = "12", *s3 = "123", *s4 = "1234";
+
+ T (s1, a2 + 1); // { dg-warning ".strcmp. of a string of length 1 and an array of size 1 evaluates to nonzero" }
+ T (a2 + 1, s1); // { dg-warning ".strcmp. of a string of length 1 and an array of size 1 evaluates to nonzero" }
+
+
+ T (s3 + 1, a2); // { dg-warning ".strcmp. of a string of length 2 and an array of size 2 evaluates to nonzero" }
+ T (s3 + 1, a3);
+
+ T (s2, a4 + 1);
+ T (s2, a4 + 2); // { dg-warning ".strcmp. of a string of length 2 and an array of size 2 evaluates to nonzero" }
+
+ T (s4, a4 + 1); // { dg-warning ".strcmp. of a string of length 4 and an array of size 3 evaluates to nonzero" }
+ T (s3, a5 + 1);
+}
+
+
+/* Use strncpy below rather than memcpy until PR 91183 is resolved. */
+
+#undef T
+#define T(s, n, a) \
+ do { \
+ char arr[32]; \
+ sink (arr); \
+ strncpy (arr, s, n < 0 ? strlen (s) + 1: n); \
+ sink (0 == strcmp (arr, a)); \
+ } while (0)
+
+void test_string_exact_length (void)
+{
+ const char *s1 = "1", *s2 = "12";
+
+ T (s1, -1, a1); // { dg-warning ".strcmp. of a string of length 1 and an array of size 1 evaluates to nonzero" }
+ T (s1, -1, a2);
+ T (s1, -1, a3);
+
+ T (s2, -1, a1); // { dg-warning ".strcmp. of a string of length 2 and an array of size 1 evaluates to nonzero" }
+ T (s2, -1, a2); // { dg-warning ".strcmp. of a string of length 2 and an array of size 2 evaluates to nonzero" }
+ T (s2, -1, a3);
+}
+
+
+void test_string_min_length (void)
+{
+ const char *s1 = "1", *s2 = "12";
+
+ T (s1, 1, a1); // { dg-warning ".strcmp. of a string of length 1 or more and an array of size 1 evaluates to nonzero" }
+ T (s1, 1, a2);
+ T (s1, 1, a3);
+
+ T (s2, 2, a1); // { dg-warning ".strcmp. of a string of length 2 or more and an array of size 1 evaluates to nonzero" }
+ T (s2, 2, a2); // { dg-warning ".strcmp. of a string of length 2 or more and an array of size 2 evaluates to nonzero" }
+ T (s2, 2, a3);
+}
+
+
+int test_strncmp_str_lit_var (const char *s, long n)
+{
+ if (strncmp (s, "123456", n) == 0) // { dg-bogus "\\\[-Wstring-compare" }
+ return 1;
+
+ return 0;
+}
+
+int test_strlen_strncmp_str_lit_var (const char *s, long n)
+{
+ if (__builtin_strlen (s) < n)
+ return -1;
+
+ if (n == 6)
+ if (strncmp (s, "123456", n) == 0) // { dg-bogus "\\\[-Wstring-compare" }
+ return 1;
+
+ return 0;
+}
+
+
diff --git a/gcc/testsuite/gcc.dg/Wstring-compare.c b/gcc/testsuite/gcc.dg/Wstring-compare.c
new file mode 100644
index 00000000000..0ca492db0ab
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstring-compare.c
@@ -0,0 +1,181 @@
+/* PR tree-optimization/90879 - fold zero-equality of strcmp between
+ a longer string and a smaller array
+ { dg-do compile }
+ { dg-options "-O2 -Wall -Wextra -ftrack-macro-expansion=0" } */
+
+#include "strlenopt.h"
+
+#define T(a, b) sink (0 == strcmp (a, b), a, b)
+
+void sink (int, ...);
+
+struct S { char a4[4], c; };
+
+extern char a4[4];
+extern char a5[5];
+extern char b4[4];
+
+/* Verify that comparison of string literals with arrays with unknown
+ content but size that prevents them from comparing equal is diagnosed. */
+
+void strcmp_array_lit (void)
+{
+ if (strcmp (a4, "1234")) // { dg-warning "'strcmp' of a string of length 4 and an array of size 4 evaluates to nonzero" }
+ // { dg-bogus "in this expreession" "unwanted note" { target *-*-* } .-1 }
+ sink (0, a4);
+
+ int cmp;
+ cmp = strcmp (a4, "1234"); // { dg-warning "'strcmp' of a string of length 4 and an array of size 4 evaluates to nonzero" }
+ if (cmp) // { dg-message "in this expression" }
+ sink (0, a4);
+
+ T (a4, "4321"); // { dg-warning "'strcmp' of a string of length 4 and an array of size 4 evaluates to nonzero " }
+ T (a4, "12345"); // { dg-warning "length 5 and an array of size 4 " }
+ T (a4, "123456"); // { dg-warning "length 6 and an array of size 4 " }
+ T ("1234", a4); // { dg-warning "length 4 and an array of size 4 " }
+ T ("12345", a4); // { dg-warning "length 5 and an array of size 4 " }
+ T ("123456", a4); // { dg-warning "length 6 and an array of size 4 " }
+}
+
+
+void strcmp_array_pstr (void)
+{
+ const char *s4 = "1234";
+
+ {
+ if (strcmp (a4, s4)) // { dg-warning "'strcmp' of a string of length 4 and an array of size 4 evaluates to nonzero" }
+ // { dg-bogus "in this expreession" "unwanted note" { target *-*-* } .-1 }
+ sink (1, a4);
+ else
+ sink (0, a4);
+ }
+
+ {
+ int c;
+ c = strcmp (a4, s4); // { dg-warning "'strcmp' of a string of length 4 and an array of size 4 evaluates to nonzero" }
+ if (c) // { dg-message "in this expression" }
+ sink (1, a4);
+ else
+ sink (0, a4);
+ }
+
+ const char *t4 = "4321";
+ const char *s5 = "12345";
+ const char *s6 = "123456";
+
+ T (a4, t4); // { dg-warning "'strcmp' of a string of length 4 and an array of size 4 evaluates to nonzero " }
+ T (a4, s5); // { dg-warning "length 5 and an array of size 4 " }
+ T (a4, s6); // { dg-warning "length 6 and an array of size 4 " }
+ T (s4, a4); // { dg-warning "length 4 and an array of size 4 " }
+ T (s5, a4); // { dg-warning "length 5 and an array of size 4 " }
+ T (s6, a4); // { dg-warning "length 6 and an array of size 4 " }
+}
+
+
+void strcmp_array_cond_pstr (int i)
+{
+ const char *s4 = i ? "1234" : "4321";
+ T (a4, s4); // { dg-warning "'strcmp' of a string of length 4 and an array of size 4 evaluates to nonzero " }
+ T (a5, s4);
+}
+
+void strcmp_array_copy (void)
+{
+ char s[8];
+
+ {
+ strcpy (s, "1234");
+ if (strcmp (a4, s)) // { dg-warning "'strcmp' of a string of length 4 and an array of size 4 evaluates to nonzero" }
+ // { dg-bogus "in this expreession" "unwanted note" { target *-*-* } .-1 }
+ sink (1, a4);
+ else
+ sink (0, a4);
+ }
+
+ {
+ strcpy (s, "1234");
+
+ int c;
+ c = strcmp (a4, s); // { dg-warning "'strcmp' of a string of length 4 and an array of size 4 evaluates to nonzero" }
+ if (c) // { dg-message "in this expression" }
+ sink (1, a4);
+ else
+ sink (0, a4);
+ }
+
+ strcpy (s, "4321");
+ T (a4, s); // { dg-warning "'strcmp' of a string of length 4 and an array of size 4 evaluates to nonzero " }
+ strcpy (s, "12345");
+ T (a4, s); // { dg-warning "length 5 and an array of size 4 " }
+ strcpy (s, "123456");
+ T (a4, s); // { dg-warning "length 6 and an array of size 4 " }
+ strcpy (s, "4321");
+ T (s, a4); // { dg-warning "length 4 and an array of size 4 " }
+ strcpy (s, "54321");
+ T (s, a4); // { dg-warning "length 5 and an array of size 4 " }
+ strcpy (s, "654321");
+ T (s, a4); // { dg-warning "length 6 and an array of size 4 " }
+}
+
+
+void strcmp_member_array_lit (const struct S *p)
+{
+ T (p->a4, "1234"); // { dg-warning "length 4 and an array of size 4 " }
+}
+
+
+#undef T
+#define T(a, b, n) sink (0 == strncmp (a, b, n), a, b)
+
+void strncmp_array_lit (void)
+{
+ if (strncmp (a4, "12345", 5)) // { dg-warning "'strncmp' of a string of length 5, an array of size 4 and bound of 5 evaluates to nonzero" }
+ // { dg-bogus "in this expreession" "unwanted note" { target *-*-* } .-1 }
+ sink (0, a4);
+
+ int cmp;
+ cmp = strncmp (a4, "54321", 5); // { dg-warning "'strncmp' of a string of length 5, an array of size 4 and bound of 5 evaluates to nonzero" }
+ if (cmp) // { dg-message "in this expression" }
+ sink (0, a4);
+
+ // Verify no warning when the bound is the same as the array size.
+ T (a4, "4321", 4);
+ T (a4, "654321", 4);
+
+ T (a4, "12345", 5); // { dg-warning "length 5, an array of size 4 and bound of 5 " }
+ T (a4, "123456", 6); // { dg-warning "length 6, an array of size 4 and bound of 6" }
+
+ T ("1234", a4, 4);
+ T ("12345", a4, 4);
+
+ T ("12345", a4, 5); // { dg-warning "length 5, an array of size 4 and bound of 5 " }
+ T ("123456", a4, 6); // { dg-warning "length 6, an array of size 4 and bound of 6 " }
+}
+
+
+void strncmp_strarray_copy (void)
+{
+ {
+ char a[] = "1234";
+ char b[6];
+ strcpy (b, "12345");
+ if (strncmp (a, b, 5)) // { dg-warning "'strncmp' of strings of length 4 and 5 and bound of 5 evaluates to nonzero" }
+ // { dg-bogus "in this expreession" "unwanted note" { target *-*-* } .-1 }
+ sink (0, a, b);
+ }
+
+ {
+ char a[] = "4321";
+ char b[6];
+ strcpy (b, "54321");
+ int cmp;
+ cmp = strncmp (a, b, 5); // { dg-warning "'strncmp' of strings of length 4 and 5 and bound of 5 evaluates to nonzero" }
+ if (cmp) // { dg-message "in this expression" }
+ sink (0, a, b);
+ }
+
+ strcpy (a4, "abc");
+ T (a4, "54321", 5); // { dg-warning "'strncmp' of strings of length 3 and 5 and bound of 5 evaluates to nonzero " }
+}
+
+
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-12.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-12.c
index 04fa114f48c..5a05f5cf7cf 100644
--- a/gcc/testsuite/gcc.dg/Wstringop-overflow-12.c
+++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-12.c
@@ -39,7 +39,7 @@ void test_memcpy_array_cst_range_off (const void *s)
T (d + SR (-7, -1), 1);
T (d + SR (-2, -1), 3); /* { dg-warning "writing 3 bytes into a region of size 2 " "pr85350" { xfail *-*-* } } */
- T (d + UR (1, 2), 1); /* { dg-warning "writing 1 byte into a region of size 0 " "pr89350" { xfail *-*-* } } */
+ T (d + UR (1, 2), 1); /* { dg-warning "writing 1 byte into a region of size 0 " } */
}
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-19.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-19.c
new file mode 100644
index 00000000000..cf866b3f1ee
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-19.c
@@ -0,0 +1,27 @@
+/* PR middle-end/92014 - bogus warning: writing 8 bytes into a region
+ of size 1 in timezone/zic.c
+ { dg-do compile }
+ { dg-options "-O2 -Wall" } */
+
+struct
+{
+ char *s1, *s2;
+ char c;
+} z;
+
+
+void f (char **a, int i, int j)
+{
+ char * cp = __builtin_strchr (a[i], '%');
+
+ if (cp && *++cp != 's')
+ return;
+
+ z.s1 = __builtin_strdup (a[i]);
+ if (!z.s1) __builtin_abort ();
+
+ z.s2 = __builtin_strdup (a[j]);
+ if (!z.s2) __builtin_abort ();
+
+ z.c = cp ? *cp : '\0'; // { dg-bogus "\\\[-Wstringop-overflow" }
+}
diff --git a/gcc/testsuite/gcc.dg/builtins-18.c b/gcc/testsuite/gcc.dg/builtins-18.c
index 9afaca23ada..4501cc14bce 100644
--- a/gcc/testsuite/gcc.dg/builtins-18.c
+++ b/gcc/testsuite/gcc.dg/builtins-18.c
@@ -7,7 +7,6 @@
/* { dg-do link } */
/* { dg-options "-O2 -ffast-math" } */
-/* { dg-add-options c99_runtime } */
#include "builtins-config.h"
diff --git a/gcc/testsuite/gcc.dg/builtins-20.c b/gcc/testsuite/gcc.dg/builtins-20.c
index 2b634286583..8f864f62495 100644
--- a/gcc/testsuite/gcc.dg/builtins-20.c
+++ b/gcc/testsuite/gcc.dg/builtins-20.c
@@ -7,7 +7,6 @@
/* { dg-do link } */
/* { dg-options "-O2 -ffast-math" } */
-/* { dg-add-options c99_runtime } */
#include "builtins-config.h"
diff --git a/gcc/testsuite/gcc.dg/builtins-53.c b/gcc/testsuite/gcc.dg/builtins-53.c
index 9a50bf5ad3c..e01908c26a7 100644
--- a/gcc/testsuite/gcc.dg/builtins-53.c
+++ b/gcc/testsuite/gcc.dg/builtins-53.c
@@ -10,7 +10,6 @@
/* { dg-do compile } */
/* { dg-options "-O2 -ffast-math" } */
-/* { dg-add-options c99_runtime } */
#include "builtins-config.h"
diff --git a/gcc/testsuite/gcc.dg/builtins-55.c b/gcc/testsuite/gcc.dg/builtins-55.c
index 0db7976a480..76786fb6b80 100644
--- a/gcc/testsuite/gcc.dg/builtins-55.c
+++ b/gcc/testsuite/gcc.dg/builtins-55.c
@@ -1,6 +1,5 @@
/* { dg-do link } */
/* { dg-options "-O2 -ffast-math" } */
-/* { dg-add-options c99_runtime } */
#include "builtins-config.h"
diff --git a/gcc/testsuite/gcc.dg/builtins-67.c b/gcc/testsuite/gcc.dg/builtins-67.c
index 0992fe1597f..36b7886b16a 100644
--- a/gcc/testsuite/gcc.dg/builtins-67.c
+++ b/gcc/testsuite/gcc.dg/builtins-67.c
@@ -2,7 +2,6 @@
/* { dg-do link } */
/* { dg-options "-ffast-math -lm" } */
-/* { dg-add-options c99_runtime } */
/* Bionic doesn't have rintl */
/* { dg-require-effective-target non_bionic } */
diff --git a/gcc/testsuite/gcc.dg/c11-float-dfp-1.c b/gcc/testsuite/gcc.dg/c11-float-dfp-1.c
new file mode 100644
index 00000000000..8d86b1bf238
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c11-float-dfp-1.c
@@ -0,0 +1,5 @@
+/* Test DFP macros not defined in <float.h> for C11. */
+/* { dg-do compile } */
+/* { dg-options "-std=c11" } */
+
+#include "c2x-float-no-dfp-1.c"
diff --git a/gcc/testsuite/gcc.dg/c2x-float-no-dfp-1.c b/gcc/testsuite/gcc.dg/c2x-float-no-dfp-1.c
new file mode 100644
index 00000000000..73610c8524c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-float-no-dfp-1.c
@@ -0,0 +1,101 @@
+/* Test DFP macros not defined in <float.h> if no DFP support. */
+/* { dg-do compile { target { ! dfp } } } */
+/* { dg-options "-std=c2x" } */
+
+#include <float.h>
+
+#ifdef DEC32_MANT_DIG
+# error "DEC32_MANT_DIG defined"
+#endif
+
+#ifdef DEC64_MANT_DIG
+# error "DEC64_MANT_DIG defined"
+#endif
+
+#ifdef DEC128_MANT_DIG
+# error "DEC128_MANT_DIG defined"
+#endif
+
+#ifdef DEC32_MIN_EXP
+# error "DEC32_MIN_EXP defined"
+#endif
+
+#ifdef DEC64_MIN_EXP
+# error "DEC64_MIN_EXP defined"
+#endif
+
+#ifdef DEC128_MIN_EXP
+# error "DEC128_MIN_EXP defined"
+#endif
+
+#ifdef DEC32_MAX_EXP
+# error "DEC32_MAX_EXP defined"
+#endif
+
+#ifdef DEC64_MAX_EXP
+# error "DEC64_MAX_EXP defined"
+#endif
+
+#ifdef DEC128_MAX_EXP
+# error "DEC128_MAX_EXP defined"
+#endif
+
+#ifdef DEC32_MAX
+# error "DEC32_MAX defined"
+#endif
+
+#ifdef DEC64_MAX
+# error "DEC64_MAX defined"
+#endif
+
+#ifdef DEC128_MAX
+# error "DEC128_MAX defined"
+#endif
+
+#ifdef DEC32_EPSILON
+# error "DEC32_EPSILON defined"
+#endif
+
+#ifdef DEC64_EPSILON
+# error "DEC64_EPSILON defined"
+#endif
+
+#ifdef DEC128_EPSILON
+# error "DEC128_EPSILON defined"
+#endif
+
+#ifdef DEC32_MIN
+# error "DEC32_MIN defined"
+#endif
+
+#ifdef DEC64_MIN
+# error "DEC64_MIN defined"
+#endif
+
+#ifdef DEC128_MIN
+# error "DEC128_MIN defined"
+#endif
+
+#ifdef DEC32_TRUE_MIN
+# error "DEC32_TRUE_MIN defined"
+#endif
+
+#ifdef DEC64_TRUE_MIN
+# error "DEC64_TRUE_MIN defined"
+#endif
+
+#ifdef DEC128_TRUE_MIN
+# error "DEC128_TRUE_MIN defined"
+#endif
+
+#ifdef DEC32_SUBNORMAL_MIN
+# error "DEC32_SUBNORMAL_MIN defined"
+#endif
+
+#ifdef DEC64_SUBNORMAL_MIN
+# error "DEC64_SUBNORMAL_MIN defined"
+#endif
+
+#ifdef DEC128_SUBNORMAL_MIN
+# error "DEC128_SUBNORMAL_MIN defined"
+#endif
diff --git a/gcc/testsuite/gcc.dg/c2x-float-no-dfp-2.c b/gcc/testsuite/gcc.dg/c2x-float-no-dfp-2.c
new file mode 100644
index 00000000000..730ce89c4cc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-float-no-dfp-2.c
@@ -0,0 +1,9 @@
+/* Test DFP macros not defined in <float.h> if no DFP support. Test
+ with feature test macros defined. */
+/* { dg-do compile { target { ! dfp } } } */
+/* { dg-options "-std=c2x" } */
+
+#define __STDC_WANT_DEC_FP__
+#define __STDC_WANT_IEC_60559_DFP_EXT__
+
+#include "c2x-float-no-dfp-1.c"
diff --git a/gcc/testsuite/gcc.dg/c99-tgmath-1.c b/gcc/testsuite/gcc.dg/c99-tgmath-1.c
index cfa02a91d33..cfcba8369d5 100644
--- a/gcc/testsuite/gcc.dg/c99-tgmath-1.c
+++ b/gcc/testsuite/gcc.dg/c99-tgmath-1.c
@@ -2,7 +2,6 @@
/* Origin: Matt Austern <austern@apple.com>
/* { dg-do preprocess { target c99_runtime } } */
/* { dg-options "-std=iso9899:1999" } */
-/* { dg-add-options c99_runtime } */
/* { dg-require-effective-target tgmath_h } */
/* Test that tgmath defines the macros it's supposed to. */
diff --git a/gcc/testsuite/gcc.dg/c99-tgmath-2.c b/gcc/testsuite/gcc.dg/c99-tgmath-2.c
index 1a1153cc6ea..7b0cfa4c6dd 100644
--- a/gcc/testsuite/gcc.dg/c99-tgmath-2.c
+++ b/gcc/testsuite/gcc.dg/c99-tgmath-2.c
@@ -2,7 +2,6 @@
/* Origin: Matt Austern <austern@apple.com>
/* { dg-do compile { target c99_runtime } } */
/* { dg-options "-std=iso9899:1999" } */
-/* { dg-add-options c99_runtime } */
/* { dg-require-effective-target tgmath_h } */
/* Test that invoking type-generic sin on a float invokes sinf. */
diff --git a/gcc/testsuite/gcc.dg/c99-tgmath-3.c b/gcc/testsuite/gcc.dg/c99-tgmath-3.c
index a595cf68559..8ed8b30f8ab 100644
--- a/gcc/testsuite/gcc.dg/c99-tgmath-3.c
+++ b/gcc/testsuite/gcc.dg/c99-tgmath-3.c
@@ -2,7 +2,6 @@
/* Origin: Matt Austern <austern@apple.com>
/* { dg-do compile { target c99_runtime } } */
/* { dg-options "-std=iso9899:1999" } */
-/* { dg-add-options c99_runtime } */
/* { dg-require-effective-target tgmath_h } */
/* Test that invoking type-generic exp on a complex invokes cexp. */
diff --git a/gcc/testsuite/gcc.dg/c99-tgmath-4.c b/gcc/testsuite/gcc.dg/c99-tgmath-4.c
index c05a1c59ebc..f66bcdffaea 100644
--- a/gcc/testsuite/gcc.dg/c99-tgmath-4.c
+++ b/gcc/testsuite/gcc.dg/c99-tgmath-4.c
@@ -2,7 +2,6 @@
/* Origin: Matt Austern <austern@apple.com>
/* { dg-do compile { target c99_runtime } } */
/* { dg-options "-std=iso9899:1999" } */
-/* { dg-add-options c99_runtime } */
/* { dg-require-effective-target tgmath_h } */
/* Test that invoking type-generic pow on complex float invokes cpowf. */
diff --git a/gcc/testsuite/gcc.dg/dfp/c11-constants-1.c b/gcc/testsuite/gcc.dg/dfp/c11-constants-1.c
new file mode 100644
index 00000000000..472ed25f8cf
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/dfp/c11-constants-1.c
@@ -0,0 +1,13 @@
+/* Test that DFP constants are diagnosed in C11 mode: -pedantic. */
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -pedantic" } */
+
+int a = (int) 1.1DF; /* { dg-warning "C2X feature" } */
+int b = (int) 2.df; /* { dg-warning "C2X feature" } */
+int c = (int) .33DD; /* { dg-warning "C2X feature" } */
+int d = (int) 2e1dd; /* { dg-warning "C2X feature" } */
+int e = (int) .3e2DL; /* { dg-warning "C2X feature" } */
+int f = (int) 4.5e3dl; /* { dg-warning "C2X feature" } */
+int g = (int) 5.e0DF; /* { dg-warning "C2X feature" } */
+int h = (int) 1e+2df; /* { dg-warning "C2X feature" } */
+int i = (int) 1000e-3DL; /* { dg-warning "C2X feature" } */
diff --git a/gcc/testsuite/gcc.dg/dfp/c11-constants-2.c b/gcc/testsuite/gcc.dg/dfp/c11-constants-2.c
new file mode 100644
index 00000000000..79b20a2c386
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/dfp/c11-constants-2.c
@@ -0,0 +1,13 @@
+/* Test that DFP constants are diagnosed in C11 mode: -pedantic-errors. */
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -pedantic-errors" } */
+
+int a = (int) 1.1DF; /* { dg-error "C2X feature" } */
+int b = (int) 2.df; /* { dg-error "C2X feature" } */
+int c = (int) .33DD; /* { dg-error "C2X feature" } */
+int d = (int) 2e1dd; /* { dg-error "C2X feature" } */
+int e = (int) .3e2DL; /* { dg-error "C2X feature" } */
+int f = (int) 4.5e3dl; /* { dg-error "C2X feature" } */
+int g = (int) 5.e0DF; /* { dg-error "C2X feature" } */
+int h = (int) 1e+2df; /* { dg-error "C2X feature" } */
+int i = (int) 1000e-3DL; /* { dg-error "C2X feature" } */
diff --git a/gcc/testsuite/gcc.dg/dfp/c11-keywords-1.c b/gcc/testsuite/gcc.dg/dfp/c11-keywords-1.c
new file mode 100644
index 00000000000..5a5c862cde1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/dfp/c11-keywords-1.c
@@ -0,0 +1,7 @@
+/* Test that _Decimal* keywords diagnosed in C11 mode: -pedantic. */
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -pedantic" } */
+
+_Decimal32 d32; /* { dg-warning "ISO C does not support" } */
+_Decimal64 d64; /* { dg-warning "ISO C does not support" } */
+_Decimal128 d128; /* { dg-warning "ISO C does not support" } */
diff --git a/gcc/testsuite/gcc.dg/dfp/c11-keywords-2.c b/gcc/testsuite/gcc.dg/dfp/c11-keywords-2.c
new file mode 100644
index 00000000000..7c7f3d9b4b1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/dfp/c11-keywords-2.c
@@ -0,0 +1,7 @@
+/* Test that _Decimal* keywords diagnosed in C11 mode: -pedantic-errors. */
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -pedantic-errors" } */
+
+_Decimal32 d32; /* { dg-error "ISO C does not support" } */
+_Decimal64 d64; /* { dg-error "ISO C does not support" } */
+_Decimal128 d128; /* { dg-error "ISO C does not support" } */
diff --git a/gcc/testsuite/gcc.dg/dfp/c2x-constants-1.c b/gcc/testsuite/gcc.dg/dfp/c2x-constants-1.c
new file mode 100644
index 00000000000..337550602fc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/dfp/c2x-constants-1.c
@@ -0,0 +1,13 @@
+/* Test that DFP constants are accepted in C2X mode. */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+int a = (int) 1.1DF;
+int b = (int) 2.df;
+int c = (int) .33DD;
+int d = (int) 2e1dd;
+int e = (int) .3e2DL;
+int f = (int) 4.5e3dl;
+int g = (int) 5.e0DF;
+int h = (int) 1e+2df;
+int i = (int) 1000e-3DL;
diff --git a/gcc/testsuite/gcc.dg/dfp/c2x-constants-2.c b/gcc/testsuite/gcc.dg/dfp/c2x-constants-2.c
new file mode 100644
index 00000000000..eed35f29cd4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/dfp/c2x-constants-2.c
@@ -0,0 +1,13 @@
+/* Test that DFP constants are accepted in C2X mode: compat warnings. */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -Wc11-c2x-compat" } */
+
+int a = (int) 1.1DF; /* { dg-warning "C2X feature" } */
+int b = (int) 2.df; /* { dg-warning "C2X feature" } */
+int c = (int) .33DD; /* { dg-warning "C2X feature" } */
+int d = (int) 2e1dd; /* { dg-warning "C2X feature" } */
+int e = (int) .3e2DL; /* { dg-warning "C2X feature" } */
+int f = (int) 4.5e3dl; /* { dg-warning "C2X feature" } */
+int g = (int) 5.e0DF; /* { dg-warning "C2X feature" } */
+int h = (int) 1e+2df; /* { dg-warning "C2X feature" } */
+int i = (int) 1000e-3DL; /* { dg-warning "C2X feature" } */
diff --git a/gcc/testsuite/gcc.dg/dfp/c2x-float-dfp-1.c b/gcc/testsuite/gcc.dg/dfp/c2x-float-dfp-1.c
new file mode 100644
index 00000000000..ee5e6789617
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/dfp/c2x-float-dfp-1.c
@@ -0,0 +1,103 @@
+/* Test DFP macros defined in <float.h> with DFP support. */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x" } */
+
+#include <float.h>
+
+#ifndef DEC32_MANT_DIG
+# error "DEC32_MANT_DIG not defined"
+#endif
+
+#ifndef DEC64_MANT_DIG
+# error "DEC64_MANT_DIG not defined"
+#endif
+
+#ifndef DEC128_MANT_DIG
+# error "DEC128_MANT_DIG not defined"
+#endif
+
+#ifndef DEC32_MIN_EXP
+# error "DEC32_MIN_EXP not defined"
+#endif
+
+#ifndef DEC64_MIN_EXP
+# error "DEC64_MIN_EXP not defined"
+#endif
+
+#ifndef DEC128_MIN_EXP
+# error "DEC128_MIN_EXP not defined"
+#endif
+
+#ifndef DEC32_MAX_EXP
+# error "DEC32_MAX_EXP not defined"
+#endif
+
+#ifndef DEC64_MAX_EXP
+# error "DEC64_MAX_EXP not defined"
+#endif
+
+#ifndef DEC128_MAX_EXP
+# error "DEC128_MAX_EXP not defined"
+#endif
+
+#ifndef DEC32_MAX
+# error "DEC32_MAX not defined"
+#endif
+
+#ifndef DEC64_MAX
+# error "DEC64_MAX not defined"
+#endif
+
+#ifndef DEC128_MAX
+# error "DEC128_MAX not defined"
+#endif
+
+#ifndef DEC32_EPSILON
+# error "DEC32_EPSILON not defined"
+#endif
+
+#ifndef DEC64_EPSILON
+# error "DEC64_EPSILON not defined"
+#endif
+
+#ifndef DEC128_EPSILON
+# error "DEC128_EPSILON not defined"
+#endif
+
+#ifndef DEC32_MIN
+# error "DEC32_MIN not defined"
+#endif
+
+#ifndef DEC64_MIN
+# error "DEC64_MIN not defined"
+#endif
+
+#ifndef DEC128_MIN
+# error "DEC128_MIN not defined"
+#endif
+
+#ifndef DEC32_TRUE_MIN
+# error "DEC32_TRUE_MIN not defined"
+#endif
+
+#ifndef DEC64_TRUE_MIN
+# error "DEC64_TRUE_MIN not defined"
+#endif
+
+#ifndef DEC128_TRUE_MIN
+# error "DEC128_TRUE_MIN not defined"
+#endif
+
+/* These macros from TR 24732 should not be defined. */
+
+#ifdef DEC32_SUBNORMAL_MIN
+# error "DEC32_SUBNORMAL_MIN defined"
+#endif
+
+#ifdef DEC64_SUBNORMAL_MIN
+# error "DEC64_SUBNORMAL_MIN defined"
+#endif
+
+#ifdef DEC128_SUBNORMAL_MIN
+# error "DEC128_SUBNORMAL_MIN defined"
+#endif
diff --git a/gcc/testsuite/gcc.dg/dfp/c2x-float-dfp-2.c b/gcc/testsuite/gcc.dg/dfp/c2x-float-dfp-2.c
new file mode 100644
index 00000000000..9ba5690e686
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/dfp/c2x-float-dfp-2.c
@@ -0,0 +1,8 @@
+/* Test DFP macros defined in <float.h> with DFP support. TS 18661-2
+ feature test macro does not change what is defined. */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x" } */
+
+#define __STDC_WANT_IEC_60559_DFP_EXT__
+
+#include "c2x-float-dfp-1.c"
diff --git a/gcc/testsuite/gcc.dg/dfp/c2x-float-dfp-3.c b/gcc/testsuite/gcc.dg/dfp/c2x-float-dfp-3.c
new file mode 100644
index 00000000000..00b51a4c3f5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/dfp/c2x-float-dfp-3.c
@@ -0,0 +1,103 @@
+/* Test DFP macros defined in <float.h> with DFP support. TR 24732
+ feature test macro causes *_SUBNORMAL_MIN macros to be defined. */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x" } */
+
+#define __STDC_WANT_DEC_FP__
+#include <float.h>
+
+#ifndef DEC32_MANT_DIG
+# error "DEC32_MANT_DIG not defined"
+#endif
+
+#ifndef DEC64_MANT_DIG
+# error "DEC64_MANT_DIG not defined"
+#endif
+
+#ifndef DEC128_MANT_DIG
+# error "DEC128_MANT_DIG not defined"
+#endif
+
+#ifndef DEC32_MIN_EXP
+# error "DEC32_MIN_EXP not defined"
+#endif
+
+#ifndef DEC64_MIN_EXP
+# error "DEC64_MIN_EXP not defined"
+#endif
+
+#ifndef DEC128_MIN_EXP
+# error "DEC128_MIN_EXP not defined"
+#endif
+
+#ifndef DEC32_MAX_EXP
+# error "DEC32_MAX_EXP not defined"
+#endif
+
+#ifndef DEC64_MAX_EXP
+# error "DEC64_MAX_EXP not defined"
+#endif
+
+#ifndef DEC128_MAX_EXP
+# error "DEC128_MAX_EXP not defined"
+#endif
+
+#ifndef DEC32_MAX
+# error "DEC32_MAX not defined"
+#endif
+
+#ifndef DEC64_MAX
+# error "DEC64_MAX not defined"
+#endif
+
+#ifndef DEC128_MAX
+# error "DEC128_MAX not defined"
+#endif
+
+#ifndef DEC32_EPSILON
+# error "DEC32_EPSILON not defined"
+#endif
+
+#ifndef DEC64_EPSILON
+# error "DEC64_EPSILON not defined"
+#endif
+
+#ifndef DEC128_EPSILON
+# error "DEC128_EPSILON not defined"
+#endif
+
+#ifndef DEC32_MIN
+# error "DEC32_MIN not defined"
+#endif
+
+#ifndef DEC64_MIN
+# error "DEC64_MIN not defined"
+#endif
+
+#ifndef DEC128_MIN
+# error "DEC128_MIN not defined"
+#endif
+
+#ifndef DEC32_TRUE_MIN
+# error "DEC32_TRUE_MIN not defined"
+#endif
+
+#ifndef DEC64_TRUE_MIN
+# error "DEC64_TRUE_MIN not defined"
+#endif
+
+#ifndef DEC128_TRUE_MIN
+# error "DEC128_TRUE_MIN not defined"
+#endif
+
+#ifndef DEC32_SUBNORMAL_MIN
+# error "DEC32_SUBNORMAL_MIN not defined"
+#endif
+
+#ifndef DEC64_SUBNORMAL_MIN
+# error "DEC64_SUBNORMAL_MIN not defined"
+#endif
+
+#ifndef DEC128_SUBNORMAL_MIN
+# error "DEC128_SUBNORMAL_MIN not defined"
+#endif
diff --git a/gcc/testsuite/gcc.dg/dfp/c2x-keywords-1.c b/gcc/testsuite/gcc.dg/dfp/c2x-keywords-1.c
new file mode 100644
index 00000000000..a3a1da536f0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/dfp/c2x-keywords-1.c
@@ -0,0 +1,7 @@
+/* Test that _Decimal* keywords are accepted in C2X mode. */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+_Decimal32 d32;
+_Decimal64 d64;
+_Decimal128 d128;
diff --git a/gcc/testsuite/gcc.dg/dfp/c2x-keywords-2.c b/gcc/testsuite/gcc.dg/dfp/c2x-keywords-2.c
new file mode 100644
index 00000000000..9655dd0cf02
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/dfp/c2x-keywords-2.c
@@ -0,0 +1,7 @@
+/* Test that _Decimal* keywords are accepted in C2X mode: compat warnings. */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -Wc11-c2x-compat" } */
+
+_Decimal32 d32; /* { dg-warning "ISO C does not support" } */
+_Decimal64 d64; /* { dg-warning "ISO C does not support" } */
+_Decimal128 d128; /* { dg-warning "ISO C does not support" } */
diff --git a/gcc/testsuite/gcc.dg/dfp/constants-c99.c b/gcc/testsuite/gcc.dg/dfp/constants-c99.c
index 6a48bf501f0..5a135c53492 100644
--- a/gcc/testsuite/gcc.dg/dfp/constants-c99.c
+++ b/gcc/testsuite/gcc.dg/dfp/constants-c99.c
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-std=c99 -Wno-overflow" } */
+/* { dg-options "-std=c99 -Wno-overflow -pedantic-errors" } */
/* N1150 6: Constants.
C99 6.4.4.2: Floating constants. */
diff --git a/gcc/testsuite/gcc.dg/dfp/constants-pedantic.c b/gcc/testsuite/gcc.dg/dfp/constants-pedantic.c
index be81b0fc44a..1d85fedad73 100644
--- a/gcc/testsuite/gcc.dg/dfp/constants-pedantic.c
+++ b/gcc/testsuite/gcc.dg/dfp/constants-pedantic.c
@@ -1,14 +1,14 @@
/* { dg-do compile } */
-/* { dg-options "-pedantic" } */
+/* { dg-options "-std=gnu17 -pedantic" } */
/* N1150 6: Constants.
C99 6.4.4.2: Floating constants. */
#include "dfp-dbg.h"
-_Decimal32 a = 1.1df; /* { dg-warning "GCC extension|ISO C" } */
-_Decimal32 b = -.003DF; /* { dg-warning "GCC extension|ISO C" } */
-_Decimal64 c = 11e-1dl; /* { dg-warning "GCC extension|ISO C" } */
-_Decimal64 d = -.3DL; /* { dg-warning "GCC extension|ISO C" } */
-_Decimal128 e = 000.3e0dl; /* { dg-warning "GCC extension|ISO C" } */
-_Decimal128 f = 3000300030003e0DL; /* { dg-warning "GCC extension|ISO C" } */
+_Decimal32 a = 1.1df; /* { dg-warning "C2X feature|ISO C" } */
+_Decimal32 b = -.003DF; /* { dg-warning "C2X feature|ISO C" } */
+_Decimal64 c = 11e-1dl; /* { dg-warning "C2X feature|ISO C" } */
+_Decimal64 d = -.3DL; /* { dg-warning "C2X feature|ISO C" } */
+_Decimal128 e = 000.3e0dl; /* { dg-warning "C2X feature|ISO C" } */
+_Decimal128 f = 3000300030003e0DL; /* { dg-warning "C2X feature|ISO C" } */
diff --git a/gcc/testsuite/gcc.dg/dfp/keywords-c89.c b/gcc/testsuite/gcc.dg/dfp/keywords-c89.c
index 8c96d60c7dd..a67c3d63c0b 100644
--- a/gcc/testsuite/gcc.dg/dfp/keywords-c89.c
+++ b/gcc/testsuite/gcc.dg/dfp/keywords-c89.c
@@ -1,7 +1,7 @@
/* { dg-do compile } */
-/* { dg-options "-std=c89" } */
+/* { dg-options "-std=c89 -pedantic-errors" } */
-/* Decimal float keywords are not recognized in C89 mode. */
+/* Decimal float keywords are diagnosed in pedantic C89 mode. */
_Decimal32 x; /* { dg-error "" } */
_Decimal64 y; /* { dg-error "" } */
diff --git a/gcc/testsuite/gcc.dg/dfp/keywords-c99.c b/gcc/testsuite/gcc.dg/dfp/keywords-c99.c
index 8a62fb93e82..f51900e3808 100644
--- a/gcc/testsuite/gcc.dg/dfp/keywords-c99.c
+++ b/gcc/testsuite/gcc.dg/dfp/keywords-c99.c
@@ -1,7 +1,7 @@
/* { dg-do compile } */
-/* { dg-options "-std=c99" } */
+/* { dg-options "-std=c99 -pedantic-errors" } */
-/* Decimal float keywords are not recognized in C99 mode. */
+/* Decimal float keywords are diagnosed in pedantic C99 mode. */
_Decimal32 x; /* { dg-error "" } */
_Decimal64 y; /* { dg-error "" } */
diff --git a/gcc/testsuite/gcc.dg/dfp/keywords-ignored-c99.c b/gcc/testsuite/gcc.dg/dfp/keywords-ignored-c99.c
deleted file mode 100644
index a4258aaa8ae..00000000000
--- a/gcc/testsuite/gcc.dg/dfp/keywords-ignored-c99.c
+++ /dev/null
@@ -1,15 +0,0 @@
-/* { dg-do compile } */
-/* { dg-options "-std=c99" } */
-
-/* Decimal float keywords are not reserved for c99. */
-
-int _Decimal32 (void)
-{
- return 0;
-}
-
-int foo (int i)
-{
- int _Decimal64 = i * 2;
- return _Decimal64;
-}
diff --git a/gcc/testsuite/gcc.dg/dfp/tr24732-float-dfp-1.c b/gcc/testsuite/gcc.dg/dfp/tr24732-float-dfp-1.c
new file mode 100644
index 00000000000..c196816ac4c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/dfp/tr24732-float-dfp-1.c
@@ -0,0 +1,106 @@
+/* Test DFP macros defined in <float.h> with DFP support. TR 24732
+ feature test macro causes SUBNORMAL_MIN macros to be defined but
+ not TRUE_MIN ones. */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu99" } */
+
+#define __STDC_WANT_DEC_FP__
+#include <float.h>
+
+#ifndef DEC32_MANT_DIG
+# error "DEC32_MANT_DIG not defined"
+#endif
+
+#ifndef DEC64_MANT_DIG
+# error "DEC64_MANT_DIG not defined"
+#endif
+
+#ifndef DEC128_MANT_DIG
+# error "DEC128_MANT_DIG not defined"
+#endif
+
+#ifndef DEC32_MIN_EXP
+# error "DEC32_MIN_EXP not defined"
+#endif
+
+#ifndef DEC64_MIN_EXP
+# error "DEC64_MIN_EXP not defined"
+#endif
+
+#ifndef DEC128_MIN_EXP
+# error "DEC128_MIN_EXP not defined"
+#endif
+
+#ifndef DEC32_MAX_EXP
+# error "DEC32_MAX_EXP not defined"
+#endif
+
+#ifndef DEC64_MAX_EXP
+# error "DEC64_MAX_EXP not defined"
+#endif
+
+#ifndef DEC128_MAX_EXP
+# error "DEC128_MAX_EXP not defined"
+#endif
+
+#ifndef DEC32_MAX
+# error "DEC32_MAX not defined"
+#endif
+
+#ifndef DEC64_MAX
+# error "DEC64_MAX not defined"
+#endif
+
+#ifndef DEC128_MAX
+# error "DEC128_MAX not defined"
+#endif
+
+#ifndef DEC32_EPSILON
+# error "DEC32_EPSILON not defined"
+#endif
+
+#ifndef DEC64_EPSILON
+# error "DEC64_EPSILON not defined"
+#endif
+
+#ifndef DEC128_EPSILON
+# error "DEC128_EPSILON not defined"
+#endif
+
+#ifndef DEC32_MIN
+# error "DEC32_MIN not defined"
+#endif
+
+#ifndef DEC64_MIN
+# error "DEC64_MIN not defined"
+#endif
+
+#ifndef DEC128_MIN
+# error "DEC128_MIN not defined"
+#endif
+
+#ifndef DEC32_SUBNORMAL_MIN
+# error "DEC32_SUBNORMAL_MIN not defined"
+#endif
+
+#ifndef DEC64_SUBNORMAL_MIN
+# error "DEC64_SUBNORMAL_MIN not defined"
+#endif
+
+#ifndef DEC128_SUBNORMAL_MIN
+# error "DEC128_SUBNORMAL_MIN not defined"
+#endif
+
+/* These macros from C2X should not be defined. */
+
+#ifdef DEC32_TRUE_MIN
+# error "DEC32_TRUE_MIN defined"
+#endif
+
+#ifdef DEC64_TRUE_MIN
+# error "DEC64_TRUE_MIN defined"
+#endif
+
+#ifdef DEC128_TRUE_MIN
+# error "DEC128_TRUE_MIN defined"
+#endif
diff --git a/gcc/testsuite/gcc.dg/dfp/ts18661-2-float-dfp-1.c b/gcc/testsuite/gcc.dg/dfp/ts18661-2-float-dfp-1.c
new file mode 100644
index 00000000000..f0a08246688
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/dfp/ts18661-2-float-dfp-1.c
@@ -0,0 +1,8 @@
+/* Test DFP macros defined in <float.h> with DFP support. TS 18661-2
+ feature test macro causes same macros to be defined as for C2X. */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu99" } */
+
+#define __STDC_WANT_IEC_60559_DFP_EXT__
+
+#include "c2x-float-dfp-1.c"
diff --git a/gcc/testsuite/gcc.dg/diag-aka-5.h b/gcc/testsuite/gcc.dg/diag-aka-5.h
new file mode 100644
index 00000000000..0c7404d7664
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/diag-aka-5.h
@@ -0,0 +1,22 @@
+#ifdef IS_SYSTEM_HEADER
+#pragma GCC system_header
+#endif
+
+typedef enum __internal_enum { A, B } user_enum;
+typedef user_enum *user_enum_ptr;
+
+typedef struct __internal_struct { int i; } user_struct;
+typedef user_struct user_struct_copy;
+typedef user_struct *user_struct_ptr;
+
+typedef union __internal_union { int i; } user_union;
+typedef user_union user_union_copy;
+typedef user_union *user_union_ptr;
+
+typedef unsigned int user_vector __attribute__((__vector_size__(16)));
+typedef user_vector user_vector_copy;
+typedef user_vector *user_vector_ptr;
+
+typedef int user_int;
+typedef user_int user_int_copy;
+typedef user_int *user_int_ptr;
diff --git a/gcc/testsuite/gcc.dg/diag-aka-5a.c b/gcc/testsuite/gcc.dg/diag-aka-5a.c
new file mode 100644
index 00000000000..8768a79204a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/diag-aka-5a.c
@@ -0,0 +1,135 @@
+#define IS_SYSTEM_HEADER
+#include "diag-aka-5.h"
+
+typedef user_enum user_enum_copy;
+
+struct s { int i; };
+
+user_enum ue1;
+user_enum_copy ue2;
+user_enum_ptr ue_ptr1;
+user_enum *ue_ptr2;
+const user_enum *const_ue_ptr1;
+const user_enum_copy *const_ue_ptr2;
+volatile user_enum *volatile_ue_ptr1;
+volatile user_enum_copy *volatile_ue_ptr2;
+__extension__ _Atomic user_enum *atomic_ue_ptr1;
+__extension__ _Atomic user_enum_copy *atomic_ue_ptr2;
+user_enum (*ue_array_ptr1)[10];
+user_enum_copy (*ue_array_ptr2)[10];
+user_enum (*ue_fn_ptr1) (void);
+void (*ue_fn_ptr2) (user_enum);
+void (*ue_fn_ptr3) (user_enum, ...);
+user_enum_copy (*ue_fn_ptr4) (void);
+void (*ue_fn_ptr5) (user_enum_copy);
+void (*ue_fn_ptr6) (user_enum_copy, ...);
+user_enum (*__attribute__((__transaction_unsafe__)) unsafe_ue_fn_ptr1) (void);
+user_enum_copy (*__attribute__((__transaction_unsafe__)) unsafe_ue_fn_ptr2) (void);
+
+user_struct us1;
+user_struct_copy us2;
+user_struct_ptr us_ptr1;
+user_struct *us_ptr2;
+const user_struct *const_us_ptr1;
+const user_struct_copy *const_us_ptr2;
+
+user_union uu1;
+user_union_copy uu2;
+user_union_ptr uu_ptr1;
+user_union *uu_ptr2;
+const user_union *const_uu_ptr1;
+const user_union_copy *const_uu_ptr2;
+
+user_vector uv1;
+user_vector_copy uv2;
+user_vector_ptr uv_ptr1;
+user_vector *uv_ptr2;
+const user_vector *const_uv_ptr1;
+const user_vector_copy *const_uv_ptr2;
+
+user_int ui1;
+user_int_copy ui2;
+user_int_ptr ui_ptr1;
+user_int *ui_ptr2;
+const user_int *const_ui_ptr1;
+const user_int_copy *const_ui_ptr2;
+volatile user_int *volatile_ui_ptr1;
+volatile user_int_copy *volatile_ui_ptr2;
+__extension__ _Atomic user_int *atomic_ui_ptr1;
+__extension__ _Atomic user_int_copy *atomic_ui_ptr2;
+user_int (*ui_array_ptr1)[10];
+user_int_copy (*ui_array_ptr2)[10];
+user_int (*ui_fn_ptr1) (void);
+void (*ui_fn_ptr2) (user_int);
+void (*ui_fn_ptr3) (user_int, ...);
+user_int_copy (*ui_fn_ptr4) (void);
+void (*ui_fn_ptr5) (user_int_copy);
+void (*ui_fn_ptr6) (user_int_copy, ...);
+user_int (*__attribute__((__transaction_unsafe__)) unsafe_ui_fn_ptr1) (void);
+user_int_copy (*__attribute__((__transaction_unsafe__)) unsafe_ui_fn_ptr2) (void);
+
+void f (struct s s)
+{
+ ue1 = s; /* { dg-error {assigning to type 'user_enum' from type 'struct s'} } */
+ ue2 = s; /* { dg-error {assigning to type 'user_enum_copy' {aka 'user_enum'} from type 'struct s'} } */
+ ue_ptr1 = &s; /* { dg-error {assignment to 'user_enum_ptr' {aka 'user_enum \*'} from incompatible pointer type 'struct s \*'} } */
+ ue_ptr2 = &s; /* { dg-error {assignment to 'user_enum \*' from incompatible pointer type 'struct s \*'} } */
+ const_ue_ptr1 = &s; /* { dg-error {assignment to 'const user_enum \*' from incompatible pointer type 'struct s \*'} } */
+ const_ue_ptr2 = &s; /* { dg-error {assignment to 'const user_enum_copy \*' {aka 'const user_enum \*'} from incompatible pointer type 'struct s \*'} } */
+ volatile_ue_ptr1 = &s; /* { dg-error {assignment to 'volatile user_enum \*' from incompatible pointer type 'struct s \*'} } */
+ volatile_ue_ptr2 = &s; /* { dg-error {assignment to 'volatile user_enum_copy \*' {aka 'volatile user_enum \*'} from incompatible pointer type 'struct s \*'} } */
+ atomic_ue_ptr1 = &s; /* { dg-error {assignment to '_Atomic user_enum \*' from incompatible pointer type 'struct s \*'} } */
+ atomic_ue_ptr2 = &s; /* { dg-error {assignment to '_Atomic user_enum_copy \*' {aka '_Atomic user_enum \*'} from incompatible pointer type 'struct s \*'} } */
+ ue_array_ptr1 = &s; /* { dg-error {assignment to 'user_enum \(\*\)\[10\]' from incompatible pointer type 'struct s \*'} } */
+ ue_array_ptr2 = &s; /* { dg-error {assignment to 'user_enum_copy \(\*\)\[10\]' {aka 'user_enum \(\*\)\[10\]'} from incompatible pointer type 'struct s \*'} } */
+ ue_fn_ptr1 = &s; /* { dg-error {assignment to 'user_enum \(\*\)\(void\)' from incompatible pointer type 'struct s \*'} } */
+ ue_fn_ptr2 = &s; /* { dg-error {assignment to 'void \(\*\)\(user_enum\)' from incompatible pointer type 'struct s \*'} } */
+ ue_fn_ptr3 = &s; /* { dg-error {assignment to 'void \(\*\)\(user_enum, \.\.\.\)' from incompatible pointer type 'struct s \*'} } */
+ ue_fn_ptr4 = &s; /* { dg-error {assignment to 'user_enum_copy \(\*\)\(void\)' {aka 'user_enum \(\*\)\(void\)'} from incompatible pointer type 'struct s \*'} } */
+ ue_fn_ptr5 = &s; /* { dg-error {assignment to 'void \(\*\)\(user_enum_copy\)' {aka 'void \(\*\)\(user_enum\)'} from incompatible pointer type 'struct s \*'} } */
+ ue_fn_ptr6 = &s; /* { dg-error {assignment to 'void \(\*\)\(user_enum_copy, \.\.\.\)' {aka 'void \(\*\)\(user_enum, \.\.\.\)'} from incompatible pointer type 'struct s \*'} } */
+ unsafe_ue_fn_ptr1 = &s; /* { dg-error {assignment to 'user_enum \(__attribute__\(\(transaction_unsafe\)\) \*\)\(void\)' from incompatible pointer type 'struct s \*'} } */
+ unsafe_ue_fn_ptr2 = &s; /* { dg-error {assignment to 'user_enum_copy \(__attribute__\(\(transaction_unsafe\)\) \*\)\(void\)' {aka 'user_enum \(__attribute__\(\(transaction_unsafe\)\) \*\)\(void\)'} from incompatible pointer type 'struct s \*'} } */
+
+ us1 = s; /* { dg-error {assigning to type 'user_struct' from type 'struct s'} } */
+ us2 = s; /* { dg-error {assigning to type 'user_struct_copy' {aka 'user_struct'} from type 'struct s'} } */
+ us_ptr1 = &s; /* { dg-error {assignment to 'user_struct_ptr' {aka 'user_struct \*'} from incompatible pointer type 'struct s \*'} } */
+ us_ptr2 = &s; /* { dg-error {assignment to 'user_struct \*' from incompatible pointer type 'struct s \*'} } */
+ const_us_ptr1 = &s; /* { dg-error {assignment to 'const user_struct \*' from incompatible pointer type 'struct s \*'} } */
+ const_us_ptr2 = &s; /* { dg-error {assignment to 'const user_struct_copy \*' {aka 'const user_struct \*'} from incompatible pointer type 'struct s \*'} } */
+
+ uu1 = s; /* { dg-error {assigning to type 'user_union' from type 'struct s'} } */
+ uu2 = s; /* { dg-error {assigning to type 'user_union_copy' {aka 'user_union'} from type 'struct s'} } */
+ uu_ptr1 = &s; /* { dg-error {assignment to 'user_union_ptr' {aka 'user_union \*'} from incompatible pointer type 'struct s \*'} } */
+ uu_ptr2 = &s; /* { dg-error {assignment to 'user_union \*' from incompatible pointer type 'struct s \*'} } */
+ const_uu_ptr1 = &s; /* { dg-error {assignment to 'const user_union \*' from incompatible pointer type 'struct s \*'} } */
+ const_uu_ptr2 = &s; /* { dg-error {assignment to 'const user_union_copy \*' {aka 'const user_union \*'} from incompatible pointer type 'struct s \*'} } */
+
+ uv1 = s; /* { dg-error {assigning to type 'user_vector' from type 'struct s'} } */
+ uv2 = s; /* { dg-error {assigning to type 'user_vector_copy' {aka 'user_vector'} from type 'struct s'} } */
+ uv_ptr1 = &s; /* { dg-error {assignment to 'user_vector_ptr' {aka 'user_vector \*'} from incompatible pointer type 'struct s \*'} } */
+ uv_ptr2 = &s; /* { dg-error {assignment to 'user_vector \*' from incompatible pointer type 'struct s \*'} } */
+ const_uv_ptr1 = &s; /* { dg-error {assignment to 'const user_vector \*' from incompatible pointer type 'struct s \*'} } */
+ const_uv_ptr2 = &s; /* { dg-error {assignment to 'const user_vector_copy \*' {aka 'const user_vector \*'} from incompatible pointer type 'struct s \*'} } */
+
+ ui1 = s; /* { dg-error {assigning to type 'user_int' {aka 'int'} from type 'struct s'} } */
+ ui2 = s; /* { dg-error {assigning to type 'user_int_copy' {aka 'int'} from type 'struct s'} } */
+ ui_ptr1 = &s; /* { dg-error {assignment to 'user_int_ptr' {aka 'int \*'} from incompatible pointer type 'struct s \*'} } */
+ ui_ptr2 = &s; /* { dg-error {assignment to 'user_int \*' {aka 'int \*'} from incompatible pointer type 'struct s \*'} } */
+ const_ui_ptr1 = &s; /* { dg-error {assignment to 'const user_int \*' {aka 'const int \*'} from incompatible pointer type 'struct s \*'} } */
+ const_ui_ptr2 = &s; /* { dg-error {assignment to 'const user_int_copy \*' {aka 'const int \*'} from incompatible pointer type 'struct s \*'} } */
+ volatile_ui_ptr1 = &s; /* { dg-error {assignment to 'volatile user_int \*' {aka 'volatile int \*'} from incompatible pointer type 'struct s \*'} } */
+ volatile_ui_ptr2 = &s; /* { dg-error {assignment to 'volatile user_int_copy \*' {aka 'volatile int \*'} from incompatible pointer type 'struct s \*'} } */
+ atomic_ui_ptr1 = &s; /* { dg-error {assignment to '_Atomic user_int \*' {aka '_Atomic int \*'} from incompatible pointer type 'struct s \*'} } */
+ atomic_ui_ptr2 = &s; /* { dg-error {assignment to '_Atomic user_int_copy \*' {aka '_Atomic int \*'} from incompatible pointer type 'struct s \*'} } */
+ ui_array_ptr1 = &s; /* { dg-error {assignment to 'user_int \(\*\)\[10\]' {aka 'int \(\*\)\[10\]'} from incompatible pointer type 'struct s \*'} } */
+ ui_array_ptr2 = &s; /* { dg-error {assignment to 'user_int_copy \(\*\)\[10\]' {aka 'int \(\*\)\[10\]'} from incompatible pointer type 'struct s \*'} } */
+ ui_fn_ptr1 = &s; /* { dg-error {assignment to 'user_int \(\*\)\(void\)' {aka 'int \(\*\)\(void\)'} from incompatible pointer type 'struct s \*'} } */
+ ui_fn_ptr2 = &s; /* { dg-error {assignment to 'void \(\*\)\(user_int\)' {aka 'void \(\*\)\(int\)'} from incompatible pointer type 'struct s \*'} } */
+ ui_fn_ptr3 = &s; /* { dg-error {assignment to 'void \(\*\)\(user_int, \.\.\.\)' {aka 'void \(\*\)\(int, \.\.\.\)'} from incompatible pointer type 'struct s \*'} } */
+ ui_fn_ptr4 = &s; /* { dg-error {assignment to 'user_int_copy \(\*\)\(void\)' {aka 'int \(\*\)\(void\)'} from incompatible pointer type 'struct s \*'} } */
+ ui_fn_ptr5 = &s; /* { dg-error {assignment to 'void \(\*\)\(user_int_copy\)' {aka 'void \(\*\)\(int\)'} from incompatible pointer type 'struct s \*'} } */
+ ui_fn_ptr6 = &s; /* { dg-error {assignment to 'void \(\*\)\(user_int_copy, \.\.\.\)' {aka 'void \(\*\)\(int, \.\.\.\)'} from incompatible pointer type 'struct s \*'} } */
+ unsafe_ui_fn_ptr1 = &s; /* { dg-error {assignment to 'user_int \(__attribute__\(\(transaction_unsafe\)\) \*\)\(void\)' {aka 'int \(__attribute__\(\(transaction_unsafe\)\) \*\)\(void\)'} from incompatible pointer type 'struct s \*'} } */
+ unsafe_ui_fn_ptr2 = &s; /* { dg-error {assignment to 'user_int_copy \(__attribute__\(\(transaction_unsafe\)\) \*\)\(void\)' {aka 'int \(__attribute__\(\(transaction_unsafe\)\) \*\)\(void\)'} from incompatible pointer type 'struct s \*'} } */
+}
diff --git a/gcc/testsuite/gcc.dg/diag-aka-5b.c b/gcc/testsuite/gcc.dg/diag-aka-5b.c
new file mode 100644
index 00000000000..e0ec7c816a2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/diag-aka-5b.c
@@ -0,0 +1,134 @@
+#include "diag-aka-5.h"
+
+typedef user_enum user_enum_copy;
+
+struct s { int i; };
+
+user_enum ue1;
+user_enum_copy ue2;
+user_enum_ptr ue_ptr1;
+user_enum *ue_ptr2;
+const user_enum *const_ue_ptr1;
+const user_enum_copy *const_ue_ptr2;
+volatile user_enum *volatile_ue_ptr1;
+volatile user_enum_copy *volatile_ue_ptr2;
+__extension__ _Atomic user_enum *atomic_ue_ptr1;
+__extension__ _Atomic user_enum_copy *atomic_ue_ptr2;
+user_enum (*ue_array_ptr1)[10];
+user_enum_copy (*ue_array_ptr2)[10];
+user_enum (*ue_fn_ptr1) (void);
+void (*ue_fn_ptr2) (user_enum);
+void (*ue_fn_ptr3) (user_enum, ...);
+user_enum_copy (*ue_fn_ptr4) (void);
+void (*ue_fn_ptr5) (user_enum_copy);
+void (*ue_fn_ptr6) (user_enum_copy, ...);
+user_enum (*__attribute__((__transaction_unsafe__)) unsafe_ue_fn_ptr1) (void);
+user_enum_copy (*__attribute__((__transaction_unsafe__)) unsafe_ue_fn_ptr2) (void);
+
+user_struct us1;
+user_struct_copy us2;
+user_struct_ptr us_ptr1;
+user_struct *us_ptr2;
+const user_struct *const_us_ptr1;
+const user_struct_copy *const_us_ptr2;
+
+user_union uu1;
+user_union_copy uu2;
+user_union_ptr uu_ptr1;
+user_union *uu_ptr2;
+const user_union *const_uu_ptr1;
+const user_union_copy *const_uu_ptr2;
+
+user_vector uv1;
+user_vector_copy uv2;
+user_vector_ptr uv_ptr1;
+user_vector *uv_ptr2;
+const user_vector *const_uv_ptr1;
+const user_vector_copy *const_uv_ptr2;
+
+user_int ui1;
+user_int_copy ui2;
+user_int_ptr ui_ptr1;
+user_int *ui_ptr2;
+const user_int *const_ui_ptr1;
+const user_int_copy *const_ui_ptr2;
+volatile user_int *volatile_ui_ptr1;
+volatile user_int_copy *volatile_ui_ptr2;
+__extension__ _Atomic user_int *atomic_ui_ptr1;
+__extension__ _Atomic user_int_copy *atomic_ui_ptr2;
+user_int (*ui_array_ptr1)[10];
+user_int_copy (*ui_array_ptr2)[10];
+user_int (*ui_fn_ptr1) (void);
+void (*ui_fn_ptr2) (user_int);
+void (*ui_fn_ptr3) (user_int, ...);
+user_int_copy (*ui_fn_ptr4) (void);
+void (*ui_fn_ptr5) (user_int_copy);
+void (*ui_fn_ptr6) (user_int_copy, ...);
+user_int (*__attribute__((__transaction_unsafe__)) unsafe_ui_fn_ptr1) (void);
+user_int_copy (*__attribute__((__transaction_unsafe__)) unsafe_ui_fn_ptr2) (void);
+
+void f (struct s s)
+{
+ ue1 = s; /* { dg-error {assigning to type 'user_enum' {aka 'enum __internal_enum'} from type 'struct s'} } */
+ ue2 = s; /* { dg-error {assigning to type 'user_enum_copy' {aka 'enum __internal_enum'} from type 'struct s'} } */
+ ue_ptr1 = &s; /* { dg-error {assignment to 'user_enum_ptr' {aka 'enum __internal_enum \*'} from incompatible pointer type 'struct s \*'} } */
+ ue_ptr2 = &s; /* { dg-error {assignment to 'user_enum \*' {aka 'enum __internal_enum \*'} from incompatible pointer type 'struct s \*'} } */
+ const_ue_ptr1 = &s; /* { dg-error {assignment to 'const user_enum \*' {aka 'const enum __internal_enum \*'} from incompatible pointer type 'struct s \*'} } */
+ const_ue_ptr2 = &s; /* { dg-error {assignment to 'const user_enum_copy \*' {aka 'const enum __internal_enum \*'} from incompatible pointer type 'struct s \*'} } */
+ volatile_ue_ptr1 = &s; /* { dg-error {assignment to 'volatile user_enum \*' {aka 'volatile enum __internal_enum \*'} from incompatible pointer type 'struct s \*'} } */
+ volatile_ue_ptr2 = &s; /* { dg-error {assignment to 'volatile user_enum_copy \*' {aka 'volatile enum __internal_enum \*'} from incompatible pointer type 'struct s \*'} } */
+ atomic_ue_ptr1 = &s; /* { dg-error {assignment to '_Atomic user_enum \*' {aka '_Atomic enum __internal_enum \*'} from incompatible pointer type 'struct s \*'} } */
+ atomic_ue_ptr2 = &s; /* { dg-error {assignment to '_Atomic user_enum_copy \*' {aka '_Atomic enum __internal_enum \*'} from incompatible pointer type 'struct s \*'} } */
+ ue_array_ptr1 = &s; /* { dg-error {assignment to 'user_enum \(\*\)\[10\]' {aka 'enum __internal_enum \(\*\)\[10\]'} from incompatible pointer type 'struct s \*'} } */
+ ue_array_ptr2 = &s; /* { dg-error {assignment to 'user_enum_copy \(\*\)\[10\]' {aka 'enum __internal_enum \(\*\)\[10\]'} from incompatible pointer type 'struct s \*'} } */
+ ue_fn_ptr1 = &s; /* { dg-error {assignment to 'user_enum \(\*\)\(void\)' {aka 'enum __internal_enum \(\*\)\(void\)'} from incompatible pointer type 'struct s \*'} } */
+ ue_fn_ptr2 = &s; /* { dg-error {assignment to 'void \(\*\)\(user_enum\)' {aka 'void \(\*\)\(enum __internal_enum\)'} from incompatible pointer type 'struct s \*'} } */
+ ue_fn_ptr3 = &s; /* { dg-error {assignment to 'void \(\*\)\(user_enum, \.\.\.\)' {aka 'void \(\*\)\(enum __internal_enum, \.\.\.\)'} from incompatible pointer type 'struct s \*'} } */
+ ue_fn_ptr4 = &s; /* { dg-error {assignment to 'user_enum_copy \(\*\)\(void\)' {aka 'enum __internal_enum \(\*\)\(void\)'} from incompatible pointer type 'struct s \*'} } */
+ ue_fn_ptr5 = &s; /* { dg-error {assignment to 'void \(\*\)\(user_enum_copy\)' {aka 'void \(\*\)\(enum __internal_enum\)'} from incompatible pointer type 'struct s \*'} } */
+ ue_fn_ptr6 = &s; /* { dg-error {assignment to 'void \(\*\)\(user_enum_copy, \.\.\.\)' {aka 'void \(\*\)\(enum __internal_enum, \.\.\.\)'} from incompatible pointer type 'struct s \*'} } */
+ unsafe_ue_fn_ptr1 = &s; /* { dg-error {assignment to 'user_enum \(__attribute__\(\(transaction_unsafe\)\) \*\)\(void\)' {aka 'enum __internal_enum \(__attribute__\(\(transaction_unsafe\)\) \*\)\(void\)'} from incompatible pointer type 'struct s \*'} } */
+ unsafe_ue_fn_ptr2 = &s; /* { dg-error {assignment to 'user_enum_copy \(__attribute__\(\(transaction_unsafe\)\) \*\)\(void\)' {aka 'enum __internal_enum \(__attribute__\(\(transaction_unsafe\)\) \*\)\(void\)'} from incompatible pointer type 'struct s \*'} } */
+
+ us1 = s; /* { dg-error {assigning to type 'user_struct' {aka 'struct __internal_struct'} from type 'struct s'} } */
+ us2 = s; /* { dg-error {assigning to type 'user_struct_copy' {aka 'struct __internal_struct'} from type 'struct s'} } */
+ us_ptr1 = &s; /* { dg-error {assignment to 'user_struct_ptr' {aka 'struct __internal_struct \*'} from incompatible pointer type 'struct s \*'} } */
+ us_ptr2 = &s; /* { dg-error {assignment to 'user_struct \*' {aka 'struct __internal_struct \*'} from incompatible pointer type 'struct s \*'} } */
+ const_us_ptr1 = &s; /* { dg-error {assignment to 'const user_struct \*' {aka 'const struct __internal_struct \*'} from incompatible pointer type 'struct s \*'} } */
+ const_us_ptr2 = &s; /* { dg-error {assignment to 'const user_struct_copy \*' {aka 'const struct __internal_struct \*'} from incompatible pointer type 'struct s \*'} } */
+
+ uu1 = s; /* { dg-error {assigning to type 'user_union' {aka 'union __internal_union'} from type 'struct s'} } */
+ uu2 = s; /* { dg-error {assigning to type 'user_union_copy' {aka 'union __internal_union'} from type 'struct s'} } */
+ uu_ptr1 = &s; /* { dg-error {assignment to 'user_union_ptr' {aka 'union __internal_union \*'} from incompatible pointer type 'struct s \*'} } */
+ uu_ptr2 = &s; /* { dg-error {assignment to 'user_union \*' {aka 'union __internal_union \*'} from incompatible pointer type 'struct s \*'} } */
+ const_uu_ptr1 = &s; /* { dg-error {assignment to 'const user_union \*' {aka 'const union __internal_union \*'} from incompatible pointer type 'struct s \*'} } */
+ const_uu_ptr2 = &s; /* { dg-error {assignment to 'const user_union_copy \*' {aka 'const union __internal_union \*'} from incompatible pointer type 'struct s \*'} } */
+
+ uv1 = s; /* { dg-error {assigning to type 'user_vector' {aka '__vector\([48]\) unsigned int'} from type 'struct s'} } */
+ uv2 = s; /* { dg-error {assigning to type 'user_vector_copy' {aka '__vector\([48]\) unsigned int'} from type 'struct s'} } */
+ uv_ptr1 = &s; /* { dg-error {assignment to 'user_vector_ptr' {aka '__vector\([48]\) unsigned int \*'} from incompatible pointer type 'struct s \*'} } */
+ uv_ptr2 = &s; /* { dg-error {assignment to 'user_vector \*' {aka '__vector\([48]\) unsigned int \*'} from incompatible pointer type 'struct s \*'} } */
+ const_uv_ptr1 = &s; /* { dg-error {assignment to 'const user_vector \*' {aka 'const __vector\([48]\) unsigned int \*'} from incompatible pointer type 'struct s \*'} } */
+ const_uv_ptr2 = &s; /* { dg-error {assignment to 'const user_vector_copy \*' {aka 'const __vector\([48]\) unsigned int \*'} from incompatible pointer type 'struct s \*'} } */
+
+ ui1 = s; /* { dg-error {assigning to type 'user_int' {aka 'int'} from type 'struct s'} } */
+ ui2 = s; /* { dg-error {assigning to type 'user_int_copy' {aka 'int'} from type 'struct s'} } */
+ ui_ptr1 = &s; /* { dg-error {assignment to 'user_int_ptr' {aka 'int \*'} from incompatible pointer type 'struct s \*'} } */
+ ui_ptr2 = &s; /* { dg-error {assignment to 'user_int \*' {aka 'int \*'} from incompatible pointer type 'struct s \*'} } */
+ const_ui_ptr1 = &s; /* { dg-error {assignment to 'const user_int \*' {aka 'const int \*'} from incompatible pointer type 'struct s \*'} } */
+ const_ui_ptr2 = &s; /* { dg-error {assignment to 'const user_int_copy \*' {aka 'const int \*'} from incompatible pointer type 'struct s \*'} } */
+ volatile_ui_ptr1 = &s; /* { dg-error {assignment to 'volatile user_int \*' {aka 'volatile int \*'} from incompatible pointer type 'struct s \*'} } */
+ volatile_ui_ptr2 = &s; /* { dg-error {assignment to 'volatile user_int_copy \*' {aka 'volatile int \*'} from incompatible pointer type 'struct s \*'} } */
+ atomic_ui_ptr1 = &s; /* { dg-error {assignment to '_Atomic user_int \*' {aka '_Atomic int \*'} from incompatible pointer type 'struct s \*'} } */
+ atomic_ui_ptr2 = &s; /* { dg-error {assignment to '_Atomic user_int_copy \*' {aka '_Atomic int \*'} from incompatible pointer type 'struct s \*'} } */
+ ui_array_ptr1 = &s; /* { dg-error {assignment to 'user_int \(\*\)\[10\]' {aka 'int \(\*\)\[10\]'} from incompatible pointer type 'struct s \*'} } */
+ ui_array_ptr2 = &s; /* { dg-error {assignment to 'user_int_copy \(\*\)\[10\]' {aka 'int \(\*\)\[10\]'} from incompatible pointer type 'struct s \*'} } */
+ ui_fn_ptr1 = &s; /* { dg-error {assignment to 'user_int \(\*\)\(void\)' {aka 'int \(\*\)\(void\)'} from incompatible pointer type 'struct s \*'} } */
+ ui_fn_ptr2 = &s; /* { dg-error {assignment to 'void \(\*\)\(user_int\)' {aka 'void \(\*\)\(int\)'} from incompatible pointer type 'struct s \*'} } */
+ ui_fn_ptr3 = &s; /* { dg-error {assignment to 'void \(\*\)\(user_int, \.\.\.\)' {aka 'void \(\*\)\(int, \.\.\.\)'} from incompatible pointer type 'struct s \*'} } */
+ ui_fn_ptr4 = &s; /* { dg-error {assignment to 'user_int_copy \(\*\)\(void\)' {aka 'int \(\*\)\(void\)'} from incompatible pointer type 'struct s \*'} } */
+ ui_fn_ptr5 = &s; /* { dg-error {assignment to 'void \(\*\)\(user_int_copy\)' {aka 'void \(\*\)\(int\)'} from incompatible pointer type 'struct s \*'} } */
+ ui_fn_ptr6 = &s; /* { dg-error {assignment to 'void \(\*\)\(user_int_copy, \.\.\.\)' {aka 'void \(\*\)\(int, \.\.\.\)'} from incompatible pointer type 'struct s \*'} } */
+ unsafe_ui_fn_ptr1 = &s; /* { dg-error {assignment to 'user_int \(__attribute__\(\(transaction_unsafe\)\) \*\)\(void\)' {aka 'int \(__attribute__\(\(transaction_unsafe\)\) \*\)\(void\)'} from incompatible pointer type 'struct s \*'} } */
+ unsafe_ui_fn_ptr2 = &s; /* { dg-error {assignment to 'user_int_copy \(__attribute__\(\(transaction_unsafe\)\) \*\)\(void\)' {aka 'int \(__attribute__\(\(transaction_unsafe\)\) \*\)\(void\)'} from incompatible pointer type 'struct s \*'} } */
+}
diff --git a/gcc/testsuite/gcc.dg/gomp/declare-variant-1.c b/gcc/testsuite/gcc.dg/gomp/declare-variant-1.c
new file mode 100644
index 00000000000..9b20cfef8c7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gomp/declare-variant-1.c
@@ -0,0 +1,41 @@
+/* Test parsing of #pragma omp declare variant */
+/* { dg-do compile } */
+
+int fn0 (int);
+int fn6 (int);
+
+#pragma omp declare variant (fn0) match (user={condition(0)})
+int a; /* { dg-error "not immediately followed by a function declaration or definition" } */
+
+#pragma omp declare variant (fn0) match (user={condition(0)})
+int fn1 (int a), fn2 (int a); /* { dg-error "not immediately followed by a single function declaration or definition" } */
+
+#pragma omp declare variant (fn0) match (user={condition(0)})
+int b, fn3 (int a); /* { dg-error "not immediately followed by a function declaration or definition" } */
+
+#pragma omp declare variant (fn0) match (user={condition(0)})
+int fn4 (int a), c; /* { dg-error "not immediately followed by a function declaration or definition" } */
+
+int t;
+
+#pragma omp declare variant (fn0) match (user={condition(0)})
+#pragma omp declare variant (fn6) match (implementation={vendor(unknown)})
+#pragma omp threadprivate(t) /* { dg-error "must be followed by function declaration or definition or another" } */
+int fn5 (int a);
+
+#pragma omp declare variant (1 + 2) match (user={condition(0)}) /* { dg-error "expected identifier before numeric constant" } */
+int fn7 (int);
+
+#pragma omp declare variant (t) match (user={condition(0)}) /* { dg-error "variant 't' is not a function" } */
+int fn8 (int);
+
+long fn9 (char, short);
+
+#pragma omp declare variant (fn9) match (implementation={vendor(unknown)}) /* { dg-error "variant 'fn9' and base 'fn10' have incompatible types" } */
+int fn10 (int, long long);
+
+#pragma omp declare variant (memcpy) match (implementation={vendor(llvm)}) /* { dg-error "'memcpy' undeclared here" } */
+void *fn11 (void *, const void *, __SIZE_TYPE__);
+
+#pragma omp declare variant (__builtin_memmove) match (implementation={vendor(gnu)}) /* { dg-error "variant '__builtin_memmove' is a built-in" } */
+void *fn12 (void *, const void *, __SIZE_TYPE__);
diff --git a/gcc/testsuite/gcc.dg/gomp/declare-variant-2.c b/gcc/testsuite/gcc.dg/gomp/declare-variant-2.c
new file mode 100644
index 00000000000..701d83b0ec3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gomp/declare-variant-2.c
@@ -0,0 +1,22 @@
+/* Test parsing of #pragma omp declare variant */
+/* { dg-do compile } */
+
+int f0 (int, int *, int);
+
+int
+f1 (int x)
+{
+ if (x)
+ #pragma omp declare variant (fn0) match (user={condition(0)})
+ extern int f3 (int a, int *b, int c); /* { dg-error "must be followed by function declaration or definition" } */
+ while (x < 10)
+ #pragma omp declare variant (fn0) match (user={condition(0)})
+ extern int f4 (int a, int *b, int c); /* { dg-error "must be followed by function declaration or definition" } */
+ {
+lab:
+ #pragma omp declare variant (fn0) match (user={condition(0)})
+ extern int f5 (int a, int *b, int c); /* { dg-error "must be followed by function declaration or definition" } */
+ x++; /* { dg-error "expected expression before" "" { target *-*-* } .-1 } */
+ }
+ return x;
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/inline-8.c b/gcc/testsuite/gcc.dg/ipa/inline-8.c
index df4a64deff9..388283ca213 100644
--- a/gcc/testsuite/gcc.dg/ipa/inline-8.c
+++ b/gcc/testsuite/gcc.dg/ipa/inline-8.c
@@ -3,7 +3,6 @@
/* { dg-do run } */
/* { dg-require-effective-target c99_runtime } */
/* { dg-options "-O2" } */
-/* { dg-add-options c99_runtime } */
#include <math.h>
extern int isnanf (float);
/* Can't be inlined because isnanf will be optimized out. */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-icf-5.c b/gcc/testsuite/gcc.dg/ipa/ipa-icf-5.c
index 40d71740f65..1125bbd80c5 100644
--- a/gcc/testsuite/gcc.dg/ipa/ipa-icf-5.c
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-icf-5.c
@@ -1,6 +1,5 @@
/* { dg-do compile { target c99_runtime } } */
/* { dg-options "-O2 -fdump-ipa-icf-optimized" } */
-/* { dg-add-options c99_runtime } */
#include <complex.h>
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-icf-7.c b/gcc/testsuite/gcc.dg/ipa/ipa-icf-7.c
index 87a6d261b3b..d498b10255b 100644
--- a/gcc/testsuite/gcc.dg/ipa/ipa-icf-7.c
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-icf-7.c
@@ -1,6 +1,5 @@
/* { dg-do compile { target c99_runtime } } */
/* { dg-options "-O2 -fdump-ipa-icf-optimized" } */
-/* { dg-add-options c99_runtime } */
#include <complex.h>
diff --git a/gcc/testsuite/gcc.dg/nextafter-2.c b/gcc/testsuite/gcc.dg/nextafter-2.c
index 0bde721b338..e51ae94be0c 100644
--- a/gcc/testsuite/gcc.dg/nextafter-2.c
+++ b/gcc/testsuite/gcc.dg/nextafter-2.c
@@ -3,7 +3,6 @@
/* { dg-require-effective-target c99_runtime } */
/* { dg-options "-O2 -fno-builtin" } */
/* { dg-add-options ieee } */
-/* { dg-add-options c99_runtime } */
#include <stdlib.h>
diff --git a/gcc/testsuite/gcc.dg/pr42427.c b/gcc/testsuite/gcc.dg/pr42427.c
index cb290fea3f1..b5a51cc3221 100644
--- a/gcc/testsuite/gcc.dg/pr42427.c
+++ b/gcc/testsuite/gcc.dg/pr42427.c
@@ -1,6 +1,5 @@
/* { dg-do assemble { target c99_runtime } } */
/* { dg-options "-O2 -fexceptions -fnon-call-exceptions -fpeel-loops" } */
-/* { dg-add-options c99_runtime } */
/* { dg-require-effective-target ilp32 } */
/* { dg-require-effective-target exceptions } */
diff --git a/gcc/testsuite/gcc.dg/pr78965.c b/gcc/testsuite/gcc.dg/pr78965.c
index 9ae1ad4a56c..43da70b29e1 100644
--- a/gcc/testsuite/gcc.dg/pr78965.c
+++ b/gcc/testsuite/gcc.dg/pr78965.c
@@ -1,7 +1,6 @@
/* PR tree-optimization/78965 */
/* { dg-do run { target c99_runtime } } */
/* { dg-options "-O2" } */
-/* { dg-add-options c99_runtime } */
int
main ()
diff --git a/gcc/testsuite/gcc.dg/pr91860-1.c b/gcc/testsuite/gcc.dg/pr91860-1.c
new file mode 100644
index 00000000000..e715040e33d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr91860-1.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-Og -fipa-cp -g --param=max-combine-insns=3" } */
+
+char a;
+int b;
+
+static void
+bar (short d)
+{
+ d <<= __builtin_sub_overflow (0, d, &a);
+ b = __builtin_bswap16 (~d);
+}
+
+void
+foo (void)
+{
+ bar (21043);
+}
diff --git a/gcc/testsuite/gcc.dg/pr91860-2.c b/gcc/testsuite/gcc.dg/pr91860-2.c
new file mode 100644
index 00000000000..7b44e648ca6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr91860-2.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-Og -fexpensive-optimizations -fno-tree-fre -g --param=max-combine-insns=4" } */
+
+unsigned a, b, c;
+void
+foo (void)
+{
+ unsigned short e;
+ __builtin_mul_overflow (0, b, &a);
+ __builtin_sub_overflow (59347, 9, &e);
+ e <<= a & 5;
+ c = e;
+}
diff --git a/gcc/testsuite/gcc.dg/pr91860-3.c b/gcc/testsuite/gcc.dg/pr91860-3.c
new file mode 100644
index 00000000000..2b488cc9048
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr91860-3.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-Og -g2 --param=max-combine-insns=3" } */
+
+int a, b;
+
+void
+foo (void)
+{
+ unsigned short d = 46067;
+ int e = e;
+ d <<= __builtin_mul_overflow (~0, e, &a);
+ d |= -68719476735;
+ b = d;
+}
+
diff --git a/gcc/testsuite/gcc.dg/pr91860-4.c b/gcc/testsuite/gcc.dg/pr91860-4.c
new file mode 100644
index 00000000000..36f2bd55c64
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr91860-4.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target int128 } */
+/* { dg-options "-O2 -g" } */
+
+typedef unsigned char u8;
+typedef unsigned int u32;
+typedef unsigned __int128 u128;
+
+u32 b, c;
+
+static inline
+u128 bar (u8 d, u128 e)
+{
+ __builtin_memset (11 + (char *) &e, b, 1);
+ d <<= e & 7;
+ d = d | d > 0;
+ return d + e;
+}
+
+void
+foo (void)
+{
+ c = bar (~0, 5);
+}
diff --git a/gcc/testsuite/gcc.dg/single-precision-constant.c b/gcc/testsuite/gcc.dg/single-precision-constant.c
index ffd893d93ad..f1a9dc846a9 100644
--- a/gcc/testsuite/gcc.dg/single-precision-constant.c
+++ b/gcc/testsuite/gcc.dg/single-precision-constant.c
@@ -4,7 +4,6 @@
/* { dg-do run } */
/* { dg-options "-fsingle-precision-constant" } */
-/* { dg-add-options c99_runtime } */
#include <math.h>
#include <float.h>
diff --git a/gcc/testsuite/gcc.dg/strcmpopt_3.c b/gcc/testsuite/gcc.dg/strcmpopt_3.c
index 571646ce001..35941bee575 100644
--- a/gcc/testsuite/gcc.dg/strcmpopt_3.c
+++ b/gcc/testsuite/gcc.dg/strcmpopt_3.c
@@ -1,31 +1,31 @@
/* { dg-do run } */
-/* { dg-options "-O2 -fdump-tree-strlen" } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
-__attribute__ ((noinline)) int
-f1 (void)
-{
+__attribute__ ((noinline)) int
+f1 (void)
+{
char *s0= "abcd";
char s[8];
__builtin_strcpy (s, s0);
- return __builtin_strcmp(s, "abc") != 0;
+ return __builtin_strcmp (s, "abc") != 0;
}
__attribute__ ((noinline)) int
-f2 (void)
-{
+f2 (void)
+{
char *s0 = "ab";
char s[8];
__builtin_strcpy (s, s0);
- return __builtin_strcmp("abc", s) != 0;
+ return __builtin_strcmp ("abc", s) != 0;
}
int main (void)
{
- if (f1 () != 1
+ if (f1 () != 1
|| f2 () != 1)
__builtin_abort ();
return 0;
}
-/* { dg-final { scan-tree-dump-times "strcmp" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcmp" 0 "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/strcmpopt_6.c b/gcc/testsuite/gcc.dg/strcmpopt_6.c
new file mode 100644
index 00000000000..cb99294e5fa
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strcmpopt_6.c
@@ -0,0 +1,207 @@
+/* Verify that strcmp and strncmp calls with mixed constant and
+ non-constant strings are evaluated correctly.
+ { dg-do run }
+ { dg-options "-O2" } */
+
+#include "strlenopt.h"
+
+#define A(expr) \
+ ((expr) \
+ ? (void)0 \
+ : (__builtin_printf ("assertion failed on line %i: %s\n", \
+ __LINE__, #expr), \
+ __builtin_abort ()))
+
+__attribute__ ((noclone, noinline)) int
+test_strlen_gt2_strcmp_abcd (const char *s)
+{
+ if (strlen (s) < 3)
+ return -1;
+
+ return strcmp (s, "abcd") == 0;
+}
+
+__attribute__ ((noclone, noinline)) int
+test_strlen_lt6_strcmp_abcd (const char *s)
+{
+ if (strlen (s) > 5)
+ return -1;
+
+ return strcmp (s, "abcd") == 0;
+}
+
+__attribute__ ((noclone, noinline)) int
+test_strcpy_strcmp_abc (const char *s)
+{
+ char a[4];
+ strcpy (a, s);
+ return strcmp (a, "abc") == 0;
+}
+
+__attribute__ ((noclone, noinline)) int
+test_strcpy_abc_strcmp (const char *s)
+{
+ char a[4], b[6];
+ strcpy (a, "abc");
+ strcpy (b, s);
+ return strcmp (a, b) == 0;
+}
+
+/* Exercise strcmp of two strings between 1 and 3 characters long
+ stored in arrays of the same known size. */
+char ga4[4], gb4[4];
+
+__attribute__ ((noclone, noinline)) int
+test_store_0_nulterm_strcmp_same_size_arrays (void)
+{
+ ga4[0] = gb4[0] = 'x';
+ ga4[3] = gb4[3] = '\0';
+ return strcmp (ga4, gb4) == 0;
+}
+
+__attribute__ ((noclone, noinline)) int
+test_store_0_nulterm_strncmp_bound_2_same_size_arrays (void)
+{
+ ga4[0] = gb4[0] = 'x';
+ ga4[3] = gb4[3] = '\0';
+ return strncmp (ga4, gb4, 2) == 0;
+}
+
+__attribute__ ((noclone, noinline)) int
+test_store_0_nulterm_strncmp_bound_equal_same_size_arrays (void)
+{
+ ga4[0] = gb4[0] = 'x';
+ ga4[3] = gb4[3] = '\0';
+ return strncmp (ga4, gb4, 4) == 0;
+}
+
+/* Exercise strcmp of two strings between 0 and 3 characters long
+ stored in arrays of the same known size. */
+
+__attribute__ ((noclone, noinline)) int
+test_nulterm_strcmp_same_size_arrays (void)
+{
+ ga4[3] = gb4[3] = '\0';
+ return strcmp (ga4, gb4) == 0;
+}
+
+/* Exercise strcmp of two strings between 1 and 3 and 1 and 4 characters
+ long, respectively, stored in arrays of known but different sizes. */
+char gc5[5];
+
+__attribute__ ((noclone, noinline)) int
+test_store_0_nulterm_strcmp_arrays (void)
+{
+ ga4[0] = gc5[0] = 'x';
+ ga4[3] = gc5[4] = '\0';
+ return strcmp (ga4, gc5) == 0;
+}
+
+/* Exercise strcmp of two strings between 0 and 3 and 1 and 4 characters
+ long, respectively, stored in arrays of known but different sizes. */
+
+__attribute__ ((noclone, noinline)) int
+test_nulterm_strcmp_arrays (void)
+{
+ ga4[3] = gc5[4] = '\0';
+ return strcmp (ga4, gc5) == 0;
+}
+
+
+__attribute__ ((noclone, noinline)) int
+test_strcpy_strncmp_abcd (const char *s)
+{
+ char a[6];
+ strcpy (a, s);
+ return strcmp (a, "abcd") == 0;
+}
+
+__attribute__ ((noclone, noinline)) int
+test_strcpy_abcd_strncmp_3 (const char *s)
+{
+ char a[6], b[8];
+ strcpy (a, "abcd");
+ strcpy (b, s);
+ return strncmp (a, b, 3) == 0;
+}
+
+__attribute__ ((noclone, noinline)) int
+test_strcpy_abcd_strncmp_4 (const char *s)
+{
+ char a[6], b[8];
+ strcpy (a, "abcd");
+ strcpy (b, s);
+ return strncmp (a, b, 4) == 0;
+}
+
+
+int main (void)
+{
+ test_strlen_gt2_strcmp_abcd ("abcd");
+ test_strlen_lt6_strcmp_abcd ("abcd");
+
+ A (0 == test_strcpy_strcmp_abc ("ab"));
+ A (0 != test_strcpy_strcmp_abc ("abc"));
+ A (0 == test_strcpy_strcmp_abc ("abcd"));
+
+ A (0 == test_strcpy_abc_strcmp ("ab"));
+ A (0 != test_strcpy_abc_strcmp ("abc"));
+ A (0 == test_strcpy_abc_strcmp ("abcd"));
+
+ strcpy (ga4, "abc"); strcpy (gb4, "abd");
+ A (0 == test_store_0_nulterm_strcmp_same_size_arrays ());
+ strcpy (ga4, "abd"); strcpy (gb4, "abc");
+ A (0 == test_store_0_nulterm_strcmp_same_size_arrays ());
+ strcpy (ga4, "abc"); strcpy (gb4, "abc");
+ A (0 != test_store_0_nulterm_strcmp_same_size_arrays ());
+
+ strcpy (ga4, "abc"); strcpy (gb4, "acd");
+ A (0 == test_store_0_nulterm_strncmp_bound_2_same_size_arrays ());
+ strcpy (ga4, "acd"); strcpy (gb4, "abc");
+ A (0 == test_store_0_nulterm_strncmp_bound_2_same_size_arrays ());
+ strcpy (ga4, "abc"); strcpy (gb4, "abc");
+ A (0 != test_store_0_nulterm_strncmp_bound_2_same_size_arrays ());
+
+ strcpy (ga4, "abc"); strcpy (gb4, "abd");
+ A (0 == test_store_0_nulterm_strncmp_bound_equal_same_size_arrays ());
+ strcpy (ga4, "abd"); strcpy (gb4, "abc");
+ A (0 == test_store_0_nulterm_strncmp_bound_equal_same_size_arrays ());
+ strcpy (ga4, "abc"); strcpy (gb4, "abc");
+ A (0 != test_store_0_nulterm_strncmp_bound_equal_same_size_arrays ());
+
+ strcpy (ga4, "abc"); strcpy (gb4, "abd");
+ A (0 == test_nulterm_strcmp_same_size_arrays ());
+ strcpy (ga4, "abd"); strcpy (gb4, "abc");
+ A (0 == test_nulterm_strcmp_same_size_arrays ());
+ strcpy (ga4, "abc"); strcpy (gb4, "abc");
+ A (0 != test_nulterm_strcmp_same_size_arrays ());
+
+ strcpy (ga4, "abc"); strcpy (gc5, "abcd");
+ A (0 == test_store_0_nulterm_strcmp_arrays ());
+ strcpy (ga4, "abd"); strcpy (gc5, "abcd");
+ A (0 == test_store_0_nulterm_strcmp_arrays ());
+ strcpy (ga4, "abc"); strcpy (gc5, "abc");
+ A (0 != test_store_0_nulterm_strcmp_arrays ());
+
+ strcpy (ga4, "abc"); strcpy (gc5, "abcd");
+ A (0 == test_nulterm_strcmp_arrays ());
+ strcpy (ga4, "abd"); strcpy (gc5, "abc");
+ A (0 == test_nulterm_strcmp_arrays ());
+ strcpy (ga4, "abc"); strcpy (gc5, "abc");
+ A (0 != test_nulterm_strcmp_arrays ());
+
+ A (0 == test_strcpy_strncmp_abcd ("ab"));
+ A (0 == test_strcpy_strncmp_abcd ("abc"));
+ A (0 != test_strcpy_strncmp_abcd ("abcd"));
+ A (0 == test_strcpy_strncmp_abcd ("abcde"));
+
+ A (0 == test_strcpy_abcd_strncmp_3 ("ab"));
+ A (0 != test_strcpy_abcd_strncmp_3 ("abc"));
+ A (0 != test_strcpy_abcd_strncmp_3 ("abcd"));
+ A (0 != test_strcpy_abcd_strncmp_3 ("abcde"));
+
+ A (0 == test_strcpy_abcd_strncmp_4 ("ab"));
+ A (0 == test_strcpy_abcd_strncmp_4 ("abc"));
+ A (0 != test_strcpy_abcd_strncmp_4 ("abcd"));
+ A (0 != test_strcpy_abcd_strncmp_4 ("abcde"));
+}
diff --git a/gcc/testsuite/gcc.dg/strlenopt-65.c b/gcc/testsuite/gcc.dg/strlenopt-65.c
index a34d178faa1..521d7ac2b42 100644
--- a/gcc/testsuite/gcc.dg/strlenopt-65.c
+++ b/gcc/testsuite/gcc.dg/strlenopt-65.c
@@ -1,17 +1,10 @@
/* PRE tree-optimization/90626 - fold strcmp(a, b) == 0 to zero when
one string length is exact and the other is unequal
{ dg-do compile }
- { dg-options "-O2 -Wall -fdump-tree-optimized" } */
+ { dg-options "-O2 -Wall -Wno-string-compare -fdump-tree-optimized -ftrack-macro-expansion=0" } */
#include "strlenopt.h"
-typedef __SIZE_TYPE__ size_t;
-
-extern void abort (void);
-extern void* memcpy (void *, const void *, size_t);
-extern int strcmp (const char *, const char *);
-extern int strncmp (const char *, const char *, size_t);
-
#define CAT(x, y) x ## y
#define CONCAT(x, y) CAT (x, y)
#define FAILNAME(name) CONCAT (call_ ## name ##_on_line_, __LINE__)
@@ -142,21 +135,45 @@ void test_strcmp_keep (const char *s, const char *t)
#undef CMPFUNC
#define CMPFUNC(a, b, dummy) strcmp (a, b)
- KEEP ("1", "1", a, b, -1);
+ KEEP ("123", "123\0", a, b, /* bnd = */ -1);
+ KEEP ("123\0", "123", a, b, -1);
+
+ {
+ char a[8], b[8];
+ sink (a, b);
+ strcpy (a, s);
+ strcpy (b, t);
+ TEST_KEEP (0 == strcmp (a, b));
+ }
+}
+
+
+void test_strncmp_keep (const char *s, const char *t)
+{
+#undef CMPFUNC
+#define CMPFUNC(a, b, n) strncmp (a, b, n)
+
+ KEEP ("1", "1", a, b, 2);
- KEEP ("1\0", "1", a, b, -1);
- KEEP ("1", "1\0", a, b, -1);
+ KEEP ("1\0", "1", a, b, 2);
+ KEEP ("1", "1\0", a, b, 2);
- KEEP ("12\0", "12", a, b, -1);
- KEEP ("12", "12\0", a, b, -1);
+ KEEP ("12\0", "12", a, b, 2);
+ KEEP ("12", "12\0", a, b, 2);
- KEEP ("111\0", "111", a, b, -1);
- KEEP ("112", "112\0", a, b, -1);
+ KEEP ("111\0", "111", a, b, 3);
+ KEEP ("112", "112\0", a, b, 3);
- KEEP (s, t, a, b, -1);
+ {
+ char a[8], b[8];
+ sink (a, b);
+ strcpy (a, s);
+ strcpy (b, t);
+ TEST_KEEP (0 == strncmp (a, b, sizeof a));
+ }
}
/* { dg-final { scan-tree-dump-times "call_in_true_branch_not_eliminated_" 0 "optimized" } }
- { dg-final { scan-tree-dump-times "call_made_in_true_branch_on_line_1\[0-9\]\[0-9\]\[0-9\]" 8 "optimized" } }
- { dg-final { scan-tree-dump-times "call_made_in_false_branch_on_line_1\[0-9\]\[0-9\]\[0-9\]" 8 "optimized" } } */
+ { dg-final { scan-tree-dump-times "call_made_in_true_branch_on_line_1\[0-9\]\[0-9\]\[0-9\]" 11 "optimized" } }
+ { dg-final { scan-tree-dump-times "call_made_in_false_branch_on_line_1\[0-9\]\[0-9\]\[0-9\]" 11 "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/strlenopt-66.c b/gcc/testsuite/gcc.dg/strlenopt-66.c
index 5dc10a07d3d..4ba31a845b0 100644
--- a/gcc/testsuite/gcc.dg/strlenopt-66.c
+++ b/gcc/testsuite/gcc.dg/strlenopt-66.c
@@ -1,6 +1,6 @@
/* PRE tree-optimization/90626 - fold strcmp(a, b) == 0 to zero when
one string length is exact and the other is unequal
- { dg-do compile }
+ { dg-do run }
{ dg-options "-O2 -Wall -fdump-tree-optimized" } */
#include "strlenopt.h"
@@ -65,8 +65,44 @@ test_strncmp (void)
A (0 < strncmp (b, a, 5));
}
+
+__attribute__ ((noclone, noinline, noipa)) void
+test_strncmp_a4_cond_s5_s2_2 (const char *s, int i)
+{
+ char a4[4];
+ strcpy (a4, s);
+ A (0 == strncmp (a4, i ? "12345" : "12", 2));
+}
+
+
+__attribute__ ((noclone, noinline, noipa)) void
+test_strncmp_a4_cond_a5_s2_5 (const char *s, const char *t, int i)
+{
+ char a4[4], a5[5];
+ strcpy (a4, s);
+ strcpy (a5, t);
+ A (0 == strncmp (a4, i ? a5 : "12", 5));
+}
+
+__attribute__ ((noclone, noinline, noipa)) void
+test_strncmp_a4_cond_a5_a3_n (const char *s1, const char *s2, const char *s3,
+ int i, unsigned n)
+{
+ char a3[3], a4[4], a5[5];
+ strcpy (a3, s1);
+ strcpy (a4, s2);
+ strcpy (a5, s3);
+ A (0 == strncmp (a4, i ? a5 : a3, n));
+}
+
+
int main (void)
{
test_strcmp ();
test_strncmp ();
+ test_strncmp_a4_cond_s5_s2_2 ("12", 0);
+ test_strncmp_a4_cond_a5_s2_5 ("12", "1234", 0);
+
+ test_strncmp_a4_cond_a5_a3_n ("12", "123", "1234", 0, 2);
+ test_strncmp_a4_cond_a5_a3_n ("123", "12", "12", 1, 3);
}
diff --git a/gcc/testsuite/gcc.dg/strlenopt-69.c b/gcc/testsuite/gcc.dg/strlenopt-69.c
new file mode 100644
index 00000000000..46ceb9ddb05
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-69.c
@@ -0,0 +1,126 @@
+/* PR tree-optimization/90879 - fold zero-equality of strcmp between
+ a longer string and a smaller array
+ { dg-do compile }
+ { dg-options "-O2 -Wall -Wno-string-compare -fdump-tree-optimized -ftrack-macro-expansion=0" } */
+
+#include "strlenopt.h"
+
+#define A(expr) \
+ ((expr) \
+ ? (void)0 \
+ : (__builtin_printf ("assertion failed on line %i: %s\n", \
+ __LINE__, #expr), \
+ __builtin_abort ()))
+
+void clobber (void*, ...);
+
+struct S { char a4[4], c; };
+
+extern char a4[4];
+extern char b4[4];
+
+/* Verify that comparison of string literals with arrays with unknown
+ content but size that prevents them from comparing equal is folded
+ to a constant. */
+
+void test_array_lit (void)
+{
+ A (strcmp (a4, "1234")); clobber (a4);
+ A (strcmp (a4, "12345")); clobber (a4);
+ A (strcmp (a4, "123456")); clobber (a4);
+ A (strcmp ("1234", a4)); clobber (a4);
+ A (strcmp ("12345", a4)); clobber (a4);
+ A (strcmp ("123456", a4)); clobber (a4);
+}
+
+void test_memarray_lit (struct S *p)
+{
+ A (strcmp (p->a4, "1234"));
+ A (strcmp (p->a4, "12345"));
+ A (strcmp (p->a4, "123456"));
+
+ A (strcmp ("1234", p->a4));
+ A (strcmp ("12345", p->a4));
+ A (strcmp ("123456", p->a4));
+}
+
+/* Verify that the equality of empty strings is folded. */
+
+void test_empty_string (void)
+{
+ A (0 == strcmp ("", ""));
+
+ *a4 = '\0';
+ A (0 == strcmp (a4, ""));
+ A (0 == strcmp ("", a4));
+ A (0 == strcmp (a4, a4));
+
+ char s[8] = "";
+ A (0 == strcmp (a4, s));
+
+ a4[1] = '\0';
+ b4[1] = '\0';
+ A (0 == strcmp (a4 + 1, b4 + 1));
+
+ a4[2] = '\0';
+ b4[2] = '\0';
+ A (0 == strcmp (&a4[2], &b4[2]));
+
+ clobber (a4, b4);
+
+ memset (a4, 0, sizeof a4);
+ memset (b4, 0, sizeof b4);
+ A (0 == strcmp (a4, b4));
+}
+
+/* Verify that comparison of dynamically created strings with unknown
+ arrays is folded. */
+
+void test_array_copy (void)
+{
+ char s[8];
+ strcpy (s, "1234");
+ A (strcmp (a4, s));
+
+ strcpy (s, "12345");
+ A (strlen (s) == 5);
+ A (strcmp (a4, s)); clobber (a4);
+
+ strcpy (s, "123456");
+ A (strcmp (a4, s)); clobber (a4);
+
+ strcpy (s, "1234");
+ A (strcmp (s, a4)); clobber (a4);
+
+ strcpy (s, "12345");
+ A (strcmp (s, a4)); clobber (a4);
+
+ strcpy (s, "123456");
+ A (strcmp (s, a4)); clobber (a4);
+}
+
+
+void test_array_bounded (void)
+{
+ A (strncmp (a4, "12345", 5)); clobber (a4);
+ A (strncmp ("54321", a4, 5)); clobber (a4);
+
+ A (strncmp (a4, "123456", 5)); clobber (a4);
+ A (strncmp ("654321", a4, 5)); clobber (a4);
+}
+
+void test_array_copy_bounded (void)
+{
+ char s[8];
+ strcpy (s, "12345");
+ A (strncmp (a4, s, 5)); clobber (a4);
+ strcpy (s, "54321");
+ A (strncmp (s, a4, 5)); clobber (a4);
+
+ strcpy (s, "123456");
+ A (strncmp (a4, s, 5)); clobber (a4);
+ strcpy (s, "654321");
+ A (strncmp (s, a4, 5)); clobber (a4);
+}
+
+/* { dg-final { scan-tree-dump-not "abort|strcmp|strncmp" "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/torture/20191011-1.c b/gcc/testsuite/gcc.dg/torture/20191011-1.c
new file mode 100644
index 00000000000..c00b27d8389
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/20191011-1.c
@@ -0,0 +1,32 @@
+/* { dg-do run } */
+/* { dg-additional-options "-fgimple -fstrict-aliasing" } */
+
+#if __SIZEOF_INT__ != __SIZEOF_FLOAT__
+int main() { return 0; }
+#else
+struct X { int i; };
+float f;
+
+int __GIMPLE (ssa,startwith("fre")) __attribute__((noipa))
+foo (float *p)
+{
+ struct X x;
+ float tem;
+ int _2;
+
+ __BB(2):
+ f = 0.0f;
+ __MEM <float> (p_1(D)) = 1.0f;
+ x = __VIEW_CONVERT <struct X> (f);
+ _2 = x.i;
+ return _2;
+}
+
+int
+main()
+{
+ if (foo (&f) == 0)
+ __builtin_abort ();
+ return 0;
+}
+#endif
diff --git a/gcc/testsuite/gcc.dg/torture/builtin-convert-1.c b/gcc/testsuite/gcc.dg/torture/builtin-convert-1.c
index eecd2b3d275..31aadffe9f2 100644
--- a/gcc/testsuite/gcc.dg/torture/builtin-convert-1.c
+++ b/gcc/testsuite/gcc.dg/torture/builtin-convert-1.c
@@ -7,7 +7,6 @@
/* { dg-do link } */
/* { dg-options "-ffast-math" } */
-/* { dg-add-options c99_runtime } */
/* { dg-require-effective-target c99_runtime } */
#include "../builtins-config.h"
diff --git a/gcc/testsuite/gcc.dg/torture/builtin-convert-2.c b/gcc/testsuite/gcc.dg/torture/builtin-convert-2.c
index 167ecddcb9a..385098619af 100644
--- a/gcc/testsuite/gcc.dg/torture/builtin-convert-2.c
+++ b/gcc/testsuite/gcc.dg/torture/builtin-convert-2.c
@@ -7,7 +7,6 @@
/* { dg-do link } */
/* { dg-options "-ffast-math" } */
-/* { dg-add-options c99_runtime } */
#include "../builtins-config.h"
diff --git a/gcc/testsuite/gcc.dg/torture/builtin-convert-3.c b/gcc/testsuite/gcc.dg/torture/builtin-convert-3.c
index 2034b4190cf..520871f421b 100644
--- a/gcc/testsuite/gcc.dg/torture/builtin-convert-3.c
+++ b/gcc/testsuite/gcc.dg/torture/builtin-convert-3.c
@@ -7,7 +7,6 @@
/* { dg-do link } */
/* { dg-options "-ffast-math" } */
-/* { dg-add-options c99_runtime } */
#include "../builtins-config.h"
diff --git a/gcc/testsuite/gcc.dg/torture/builtin-convert-4.c b/gcc/testsuite/gcc.dg/torture/builtin-convert-4.c
index acf89cef843..f201f156613 100644
--- a/gcc/testsuite/gcc.dg/torture/builtin-convert-4.c
+++ b/gcc/testsuite/gcc.dg/torture/builtin-convert-4.c
@@ -7,7 +7,6 @@
/* { dg-do compile } */
/* { dg-options "-ftrapping-math -fdump-tree-original" } */
-/* { dg-add-options c99_runtime } */
#include "../builtins-config.h"
diff --git a/gcc/testsuite/gcc.dg/torture/builtin-fp-int-inexact-c2x.c b/gcc/testsuite/gcc.dg/torture/builtin-fp-int-inexact-c2x.c
new file mode 100644
index 00000000000..739a78cb6fb
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/builtin-fp-int-inexact-c2x.c
@@ -0,0 +1,6 @@
+/* Test C2X enables -fno-fp-int-builtin-inexact. */
+/* { dg-do run } */
+/* { dg-options "-std=c2x" } */
+/* { dg-require-effective-target fenv_exceptions } */
+
+#include "builtin-fp-int-inexact.c"
diff --git a/gcc/testsuite/gcc.dg/torture/builtin-fp-int-inexact.c b/gcc/testsuite/gcc.dg/torture/builtin-fp-int-inexact.c
index 80458fa6274..b192d38a730 100644
--- a/gcc/testsuite/gcc.dg/torture/builtin-fp-int-inexact.c
+++ b/gcc/testsuite/gcc.dg/torture/builtin-fp-int-inexact.c
@@ -1,7 +1,6 @@
/* Test -fno-fp-int-builtin-inexact. */
/* { dg-do run } */
/* { dg-options "-fno-fp-int-builtin-inexact" } */
-/* { dg-add-options c99_runtime } */
/* { dg-require-effective-target fenv_exceptions } */
#include <fenv.h>
diff --git a/gcc/testsuite/gcc.dg/torture/builtin-integral-1.c b/gcc/testsuite/gcc.dg/torture/builtin-integral-1.c
index 74d4ab047c6..f6ac248620d 100644
--- a/gcc/testsuite/gcc.dg/torture/builtin-integral-1.c
+++ b/gcc/testsuite/gcc.dg/torture/builtin-integral-1.c
@@ -10,7 +10,6 @@
that various math functions are marked const/pure and can be
folded. */
/* { dg-options "-ffinite-math-only -fno-math-errno" } */
-/* { dg-add-options c99_runtime } */
/* { dg-require-effective-target c99_runtime } */
/* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */
diff --git a/gcc/testsuite/gcc.dg/torture/builtin-power-1.c b/gcc/testsuite/gcc.dg/torture/builtin-power-1.c
index 9e7c25adb3d..e422b0c187c 100644
--- a/gcc/testsuite/gcc.dg/torture/builtin-power-1.c
+++ b/gcc/testsuite/gcc.dg/torture/builtin-power-1.c
@@ -7,7 +7,6 @@
/* { dg-do link } */
/* { dg-options "-ffast-math" } */
-/* { dg-add-options c99_runtime } */
/* { dg-skip-if "PR44214" { *-*-* } { "-O0" } { "" } } */
#include "../builtins-config.h"
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/copy-sign-1.c b/gcc/testsuite/gcc.dg/tree-ssa/copy-sign-1.c
index de3e7b242ce..c36112a6567 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/copy-sign-1.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/copy-sign-1.c
@@ -1,7 +1,6 @@
/* { dg-do compile } */
/* { dg-require-effective-target c99_runtime } */
/* { dg-options "-O2 -ffast-math -fdump-tree-gimple" } */
-/* { dg-add-options c99_runtime } */
float f(float x)
{
return (x > 0.f ? -1.f : 1.f);
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp4.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp4.c
index ebb87ed38b0..ba2f6b9b430 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/evrp4.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp4.c
@@ -17,4 +17,4 @@ int bar (struct st *s)
foo (&s->a);
}
-/* { dg-final { scan-tree-dump "\~\\\[0B, 0B\\\]" "evrp" } } */
+/* { dg-final { scan-tree-dump "\\\[1B, -1B\\\]" "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/minmax-2.c b/gcc/testsuite/gcc.dg/tree-ssa/minmax-2.c
index 87ff94cef1f..8990c188e05 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/minmax-2.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/minmax-2.c
@@ -1,6 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O -fstrict-overflow -fdump-tree-optimized" } */
-/* { dg-add-options c99_runtime } */
/* { dg-require-effective-target c99_runtime } */
static int max(int a,int b){return (a<b)?b:a;}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/mult-abs-2.c b/gcc/testsuite/gcc.dg/tree-ssa/mult-abs-2.c
index d74ba2fe630..a41f1baf256 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/mult-abs-2.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/mult-abs-2.c
@@ -1,7 +1,6 @@
/* { dg-do compile } */
/* { dg-require-effective-target c99_runtime } */
/* { dg-options "-O2 -ffast-math -fdump-tree-gimple" } */
-/* { dg-add-options c99_runtime } */
float f(float x)
{
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/popcount4.c b/gcc/testsuite/gcc.dg/tree-ssa/popcount4.c
new file mode 100644
index 00000000000..bfb563bb975
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/popcount4.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target popcount } */
+/* { dg-require-effective-target int32plus } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+const unsigned m1 = 0x55555555UL;
+const unsigned m2 = 0x33333333UL;
+const unsigned m4 = 0x0F0F0F0FUL;
+const unsigned h01 = 0x01010101UL;
+const int shift = 24;
+
+int popcount64c(unsigned x)
+{
+ x -= (x >> 1) & m1;
+ x = (x & m2) + ((x >> 2) & m2);
+ x = (x + (x >> 4)) & m4;
+ return (x * h01) >> shift;
+}
+
+/* { dg-final { scan-tree-dump-times "\.POPCOUNT" 1 "optimized" } } */
+
+
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/popcount4l.c b/gcc/testsuite/gcc.dg/tree-ssa/popcount4l.c
new file mode 100644
index 00000000000..69fb2d1134d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/popcount4l.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target popcountl } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+#if __SIZEOF_LONG__ == 4
+const unsigned long m1 = 0x55555555UL;
+const unsigned long m2 = 0x33333333UL;
+const unsigned long m4 = 0x0F0F0F0FUL;
+const unsigned long h01 = 0x01010101UL;
+const int shift = 24;
+#else
+const unsigned long m1 = 0x5555555555555555UL;
+const unsigned long m2 = 0x3333333333333333UL;
+const unsigned long m4 = 0x0f0f0f0f0f0f0f0fUL;
+const unsigned long h01 = 0x0101010101010101UL;
+const int shift = 56;
+#endif
+
+
+int popcount64c(unsigned long x)
+{
+ x -= (x >> 1) & m1;
+ x = (x & m2) + ((x >> 2) & m2);
+ x = (x + (x >> 4)) & m4;
+ return (x * h01) >> shift;
+}
+
+/* { dg-final { scan-tree-dump-times "\.POPCOUNT" 1 "optimized" } } */
+
+
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/popcount4ll.c b/gcc/testsuite/gcc.dg/tree-ssa/popcount4ll.c
new file mode 100644
index 00000000000..191d957c688
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/popcount4ll.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target popcountll } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+const unsigned long long m1 = 0x5555555555555555ULL;
+const unsigned long long m2 = 0x3333333333333333ULL;
+const unsigned long long m4 = 0x0F0F0F0F0F0F0F0FULL;
+const unsigned long long h01 = 0x0101010101010101ULL;
+const int shift = 56;
+
+int popcount64c(unsigned long long x)
+{
+ x -= (x >> 1) & m1;
+ x = (x & m2) + ((x >> 2) & m2);
+ x = (x + (x >> 4)) & m4;
+ return (x * h01) >> shift;
+}
+
+/* { dg-final { scan-tree-dump-times "\.POPCOUNT" 1 "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/redundant-assign-zero-1.c b/gcc/testsuite/gcc.dg/tree-ssa/redundant-assign-zero-1.c
index b8d01d1644b..eadf1814916 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/redundant-assign-zero-1.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/redundant-assign-zero-1.c
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-dse-details" } */
+/* { dg-options "-O2 -fno-tree-fre -fdump-tree-dse-details" } */
void blah (char *);
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/redundant-assign-zero-2.c b/gcc/testsuite/gcc.dg/tree-ssa/redundant-assign-zero-2.c
index 8cefa6f0cb7..4a5b7804922 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/redundant-assign-zero-2.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/redundant-assign-zero-2.c
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-dse-details" } */
+/* { dg-options "-O2 -fno-tree-fre -fdump-tree-dse-details" } */
#include <string.h>
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-82.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-82.c
new file mode 100644
index 00000000000..e245488b80d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-82.c
@@ -0,0 +1,25 @@
+/* { dg-do run } */
+/* { dg-options "-O -fdump-tree-fre1-details" } */
+
+struct S { _Bool x; };
+
+void
+foo (struct S *s)
+{
+ __builtin_memset (s, 1, sizeof (struct S));
+ s->x = 1;
+}
+
+int
+main ()
+{
+ struct S s;
+ foo (&s);
+ char c;
+ __builtin_memcpy (&c, &s.x, 1);
+ if (c != 1)
+ __builtin_abort ();
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump "Deleted redundant store" "fre1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-83.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-83.c
new file mode 100644
index 00000000000..cf6be229377
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-83.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-fre1-details" } */
+
+struct X
+{
+ int a : 1;
+ int b : 1;
+} x;
+
+void foo (int v)
+{
+ x.a = 1;
+ x.b = v;
+ x.a = 1;
+ x.b = v;
+}
+
+struct Y
+{
+ _Bool a;
+ _Bool b;
+} y;
+
+void bar (int v)
+{
+ y.a = 1;
+ y.b = v;
+ y.a = 1;
+ y.b = v;
+}
+
+/* { dg-final { scan-tree-dump-times "Deleted redundant store" 4 "fre1" } } */
diff --git a/gcc/testsuite/gcc.dg/vect/pr65947-1.c b/gcc/testsuite/gcc.dg/vect/pr65947-1.c
index 879819d576a..b81baed914c 100644
--- a/gcc/testsuite/gcc.dg/vect/pr65947-1.c
+++ b/gcc/testsuite/gcc.dg/vect/pr65947-1.c
@@ -42,4 +42,4 @@ main (void)
/* { dg-final { scan-tree-dump-times "LOOP VECTORIZED" 2 "vect" } } */
/* { dg-final { scan-tree-dump-times "optimizing condition reduction with FOLD_EXTRACT_LAST" 4 "vect" { target vect_fold_extract_last } } } */
-/* { dg-final { scan-tree-dump-times "condition expression based on integer induction." 4 "vect" { target { ! vect_fold_extract_last } } } } */
+/* { dg-final { scan-tree-dump-times "condition expression based on integer induction." 2 "vect" { target { ! vect_fold_extract_last } } } } */
diff --git a/gcc/testsuite/gcc.dg/vect/pr65947-13.c b/gcc/testsuite/gcc.dg/vect/pr65947-13.c
index e1d3ff52f5c..4ad5262019a 100644
--- a/gcc/testsuite/gcc.dg/vect/pr65947-13.c
+++ b/gcc/testsuite/gcc.dg/vect/pr65947-13.c
@@ -41,5 +41,5 @@ main (void)
}
/* { dg-final { scan-tree-dump-times "LOOP VECTORIZED" 2 "vect" } } */
-/* { dg-final { scan-tree-dump-times "condition expression based on integer induction." 4 "vect" { xfail vect_fold_extract_last } } } */
+/* { dg-final { scan-tree-dump-times "condition expression based on integer induction." 2 "vect" { xfail vect_fold_extract_last } } } */
/* { dg-final { scan-tree-dump-times "optimizing condition reduction with FOLD_EXTRACT_LAST" 4 "vect" { target vect_fold_extract_last } } } */
diff --git a/gcc/testsuite/gcc.dg/vect/pr65947-14.c b/gcc/testsuite/gcc.dg/vect/pr65947-14.c
index 9f1e4e1eb6a..d0194f237d4 100644
--- a/gcc/testsuite/gcc.dg/vect/pr65947-14.c
+++ b/gcc/testsuite/gcc.dg/vect/pr65947-14.c
@@ -42,4 +42,4 @@ main (void)
/* { dg-final { scan-tree-dump-times "LOOP VECTORIZED" 2 "vect" } } */
/* { dg-final { scan-tree-dump-times "optimizing condition reduction with FOLD_EXTRACT_LAST" 4 "vect" { target vect_fold_extract_last } } } */
-/* { dg-final { scan-tree-dump-times "condition expression based on integer induction." 4 "vect" { target { ! vect_fold_extract_last } } } } */
+/* { dg-final { scan-tree-dump-times "condition expression based on integer induction." 2 "vect" { target { ! vect_fold_extract_last } } } } */
diff --git a/gcc/testsuite/gcc.dg/vect/pr65947-4.c b/gcc/testsuite/gcc.dg/vect/pr65947-4.c
index 186e03a6346..40557104715 100644
--- a/gcc/testsuite/gcc.dg/vect/pr65947-4.c
+++ b/gcc/testsuite/gcc.dg/vect/pr65947-4.c
@@ -42,5 +42,5 @@ main (void)
/* { dg-final { scan-tree-dump-times "LOOP VECTORIZED" 2 "vect" } } */
/* { dg-final { scan-tree-dump-times "optimizing condition reduction with FOLD_EXTRACT_LAST" 4 "vect" { target vect_fold_extract_last } } } */
-/* { dg-final { scan-tree-dump-times "condition expression based on integer induction." 4 "vect" { target { ! vect_fold_extract_last } } } } */
+/* { dg-final { scan-tree-dump-times "condition expression based on integer induction." 2 "vect" { target { ! vect_fold_extract_last } } } } */
diff --git a/gcc/testsuite/gcc.dg/vect/pr80631-1.c b/gcc/testsuite/gcc.dg/vect/pr80631-1.c
index f2405198a10..b531fe6dbf9 100644
--- a/gcc/testsuite/gcc.dg/vect/pr80631-1.c
+++ b/gcc/testsuite/gcc.dg/vect/pr80631-1.c
@@ -73,4 +73,4 @@ main ()
/* { dg-final { scan-tree-dump-times "LOOP VECTORIZED" 5 "vect" { target vect_condition } } } */
/* { dg-final { scan-tree-dump-times "optimizing condition reduction with FOLD_EXTRACT_LAST" 10 "vect" { target vect_fold_extract_last } } } */
-/* { dg-final { scan-tree-dump-times "condition expression based on integer induction." 10 "vect" { target { { ! vect_fold_extract_last } && vect_condition } } } } */
+/* { dg-final { scan-tree-dump-times "condition expression based on integer induction." 5 "vect" { target { { ! vect_fold_extract_last } && vect_condition } } } } */
diff --git a/gcc/testsuite/gcc.dg/vect/pr80631-2.c b/gcc/testsuite/gcc.dg/vect/pr80631-2.c
index b334ca2345b..07f1a721e47 100644
--- a/gcc/testsuite/gcc.dg/vect/pr80631-2.c
+++ b/gcc/testsuite/gcc.dg/vect/pr80631-2.c
@@ -72,5 +72,5 @@ main ()
}
/* { dg-final { scan-tree-dump-times "LOOP VECTORIZED" 5 "vect" { target vect_condition } } } */
-/* { dg-final { scan-tree-dump-times "condition expression based on integer induction." 10 "vect" { target vect_condition xfail vect_fold_extract_last } } } */
+/* { dg-final { scan-tree-dump-times "condition expression based on integer induction." 5 "vect" { target vect_condition xfail vect_fold_extract_last } } } */
/* { dg-final { scan-tree-dump-times "optimizing condition reduction with FOLD_EXTRACT_LAST" 10 "vect" { target vect_fold_extract_last } } } */
diff --git a/gcc/testsuite/gcc.dg/vect/vect-outer-call-1.c b/gcc/testsuite/gcc.dg/vect/vect-outer-call-1.c
new file mode 100644
index 00000000000..f26d4220532
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-outer-call-1.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target vect_float } */
+/* { dg-additional-options "-fno-math-errno" } */
+
+void
+foo (float * __restrict x, float *y, int n, int m)
+{
+ if (m > 0)
+ for (int i = 0; i < n; ++i)
+ {
+ float tem = x[i], tem1;
+ for (int j = 0; j < m; ++j)
+ {
+ tem += y[j];
+ tem1 = tem;
+ tem = __builtin_sqrtf (tem);
+ }
+ x[i] = tem - tem1;
+ }
+}
+
+/* { dg-final { scan-tree-dump "OUTER LOOP VECTORIZED" "vect" { target { vect_call_sqrtf } } } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/diag_aka_1.c b/gcc/testsuite/gcc.target/aarch64/diag_aka_1.c
index 59e24f48bd5..98dffead6a8 100644
--- a/gcc/testsuite/gcc.target/aarch64/diag_aka_1.c
+++ b/gcc/testsuite/gcc.target/aarch64/diag_aka_1.c
@@ -8,7 +8,6 @@ void f (float x)
__Int8x8_t *ptr1 = &x; /* { dg-error {initialization of '__Int8x8_t \*' from incompatible pointer type 'float \*'} } */
int8x8_t y2 = x; /* { dg-error {incompatible types when initializing type 'int8x8_t' using type 'float'} } */
int8x8_t *ptr2 = &x; /* { dg-error {initialization of 'int8x8_t \*' from incompatible pointer type 'float \*'} } */
- /* ??? For these it would be better to print an aka for 'int16x4_t'. */
- myvec y3 = x; /* { dg-error {incompatible types when initializing type 'myvec' using type 'float'} } */
- myvec *ptr3 = &x; /* { dg-error {initialization of 'myvec \*' from incompatible pointer type 'float \*'} } */
+ myvec y3 = x; /* { dg-error {incompatible types when initializing type 'myvec' {aka 'int16x4_t'} using type 'float'} } */
+ myvec *ptr3 = &x; /* { dg-error {initialization of 'myvec \*' {aka 'int16x4_t \*'} from incompatible pointer type 'float \*'} } */
}
diff --git a/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-9.c b/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-9.c
index aaa0316d1d2..1119d004b3e 100644
--- a/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-9.c
+++ b/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-9.c
@@ -6,7 +6,7 @@
int callee (void);
/*
-** caller:
+** caller: { target lp64 }
** ldr (w[0-9]+), \[x0\]
** cbn?z \1, [^\n]*
** ...
diff --git a/gcc/testsuite/gcc.target/i386/20060512-1.c b/gcc/testsuite/gcc.target/i386/20060512-1.c
index ec163a9bc51..fe95f6d52fa 100644
--- a/gcc/testsuite/gcc.target/i386/20060512-1.c
+++ b/gcc/testsuite/gcc.target/i386/20060512-1.c
@@ -7,11 +7,11 @@
#include <emmintrin.h>
#ifdef __x86_64__
-# define PUSH "pushq %rsi"
-# define POP "popq %rsi"
+# define REG "rcx"
+# define WIDTH "q"
#else
-# define PUSH "pushl %esi"
-# define POP "popl %esi"
+# define REG "ecx"
+# define WIDTH "l"
#endif
__m128i __attribute__ ((__noinline__))
@@ -30,13 +30,15 @@ self_aligning_function (int x, int y)
int g_1 = 20;
int g_2 = 22;
-static void
+static void __attribute__ ((__optimize__ ("-fno-omit-frame-pointer")))
sse2_test (void)
{
int result;
- asm (PUSH); /* Misalign runtime stack. */
+ register int __attribute__ ((__mode__ (__word__))) reg asm (REG);
+ asm volatile ("push" WIDTH "\t%0" /* Disalign runtime stack. */
+ : : "r" (reg) : "memory");
result = self_aligning_function (g_1, g_2);
if (result != 42)
abort ();
- asm (POP);
+ asm volatile ("pop" WIDTH "\t%0" : "=r" (reg));
}
diff --git a/gcc/testsuite/gcc.target/i386/20060512-3.c b/gcc/testsuite/gcc.target/i386/20060512-3.c
index 3370b9ec25a..0cebb47f6e9 100644
--- a/gcc/testsuite/gcc.target/i386/20060512-3.c
+++ b/gcc/testsuite/gcc.target/i386/20060512-3.c
@@ -23,13 +23,14 @@ self_aligning_function (int x, int y)
int g_1 = 20;
int g_2 = 22;
-static void
+static void __attribute__ ((__optimize__ ("-fno-omit-frame-pointer")))
sse2_test (void)
{
int result;
- asm ("pushl %esi"); /* Disalign runtime stack. */
+ register int reg asm ("ecx");
+ asm ("pushl\t%0": : "r" (reg) : "memory"); /* Disalign runtime stack. */
result = self_aligning_function (g_1, g_2);
if (result != 42)
abort ();
- asm ("popl %esi");
+ asm ("popl\t%0" : "=r" (reg));
}
diff --git a/gcc/testsuite/gcc.target/i386/387-builtin-fp-int-inexact.c b/gcc/testsuite/gcc.target/i386/387-builtin-fp-int-inexact.c
index 752b487825e..89983c3e4a4 100644
--- a/gcc/testsuite/gcc.target/i386/387-builtin-fp-int-inexact.c
+++ b/gcc/testsuite/gcc.target/i386/387-builtin-fp-int-inexact.c
@@ -1,7 +1,6 @@
/* Test -fno-fp-int-builtin-inexact for 387. */
/* { dg-do run } */
/* { dg-options "-O2 -mfancy-math-387 -mfpmath=387 -fno-fp-int-builtin-inexact" } */
-/* { dg-add-options c99_runtime } */
/* { dg-require-effective-target fenv_exceptions } */
#include "../../gcc.dg/torture/builtin-fp-int-inexact.c"
diff --git a/gcc/testsuite/gcc.target/i386/387-rint-inline-1.c b/gcc/testsuite/gcc.target/i386/387-rint-inline-1.c
index 522edff611a..06906d6932d 100644
--- a/gcc/testsuite/gcc.target/i386/387-rint-inline-1.c
+++ b/gcc/testsuite/gcc.target/i386/387-rint-inline-1.c
@@ -2,7 +2,6 @@
should be expanded when spurious "inexact" allowed. */
/* { dg-do compile } */
/* { dg-options "-O2 -mfancy-math-387 -mfpmath=387 -ffp-int-builtin-inexact" } */
-/* { dg-add-options c99_runtime } */
#define TEST(FN, TYPE) \
do \
diff --git a/gcc/testsuite/gcc.target/i386/387-rint-inline-2.c b/gcc/testsuite/gcc.target/i386/387-rint-inline-2.c
index be765a7a39f..4cb82193916 100644
--- a/gcc/testsuite/gcc.target/i386/387-rint-inline-2.c
+++ b/gcc/testsuite/gcc.target/i386/387-rint-inline-2.c
@@ -2,7 +2,6 @@
should be expanded even when spurious "inexact" not allowed. */
/* { dg-do compile } */
/* { dg-options "-O2 -mfancy-math-387 -mfpmath=387 -fno-fp-int-builtin-inexact" } */
-/* { dg-add-options c99_runtime } */
#define TEST(FN, TYPE) \
do \
diff --git a/gcc/testsuite/gcc.target/i386/conversion.c b/gcc/testsuite/gcc.target/i386/conversion.c
index c1718f02736..bc7121119ba 100644
--- a/gcc/testsuite/gcc.target/i386/conversion.c
+++ b/gcc/testsuite/gcc.target/i386/conversion.c
@@ -2,7 +2,6 @@
/* { dg-do link } */
/* { dg-options "-ffast-math" } */
-/* { dg-add-options c99_runtime } */
#include "../../gcc.dg/builtins-config.h"
diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
index 052d24dabdf..e2914a8333c 100644
--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
@@ -14,7 +14,7 @@ male_indirect_jump (long offset)
/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*dispatch" { target *-*-linux* } } } */
/* { dg-final { scan-assembler {movq[ \t]*_dispatch} { target { lp64 && *-*-darwin* } } } } */
-/* { dg-final { scan-assembler {movl[ \t]*l_dispatch\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
+/* { dg-final { scan-assembler {movl[ \t]*[Ll]_dispatch\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
/* { dg-final { scan-assembler "jmp\[ \t\]*_?__x86_indirect_thunk_(r|e)ax" } } */
/* { dg-final { scan-assembler {jmp[ \t]*\.?LIND} } } */
/* { dg-final { scan-assembler {call[ \t]*\.?LIND} } } */
diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
index 2cfbd728b4b..d2b7c74b143 100644
--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
@@ -14,7 +14,7 @@ male_indirect_jump (long offset)
/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*dispatch" { target *-*-linux* } } } */
/* { dg-final { scan-assembler {movq[ \t]*_dispatch} { target { lp64 && *-*-darwin* } } } } */
-/* { dg-final { scan-assembler {movl[ \t]*l_dispatch\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
+/* { dg-final { scan-assembler {movl[ \t]*[Ll]_dispatch\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
/* { dg-final { scan-assembler "jmp\[ \t\]*_?__x86_indirect_thunk_(r|e)ax" } } */
/* { dg-final { scan-assembler {jmp[ \t]*\.?LIND} } } */
/* { dg-final { scan-assembler {call[ \t]*\.?LIND} } } */
diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
index 59bb08613b7..129fb2125f0 100644
--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
@@ -15,7 +15,7 @@ male_indirect_jump (long offset)
/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*dispatch" { target *-*-linux* } } } */
/* { dg-final { scan-assembler {movq[ \t]*_dispatch} { target { lp64 && *-*-darwin* } } } } */
-/* { dg-final { scan-assembler {movl[ \t]*l_dispatch\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
+/* { dg-final { scan-assembler {movl[ \t]*[Ll]_dispatch\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
/* { dg-final { scan-assembler "call\[ \t\]*_?__x86_indirect_thunk_(r|e)ax" } } */
/* { dg-final { scan-assembler {jmp[ \t]*\.?LIND} } } */
/* { dg-final { scan-assembler {call[ \t]*\.?LIND} } } */
diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
index 59640fab8f1..01996fb029f 100644
--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
@@ -15,7 +15,7 @@ male_indirect_jump (long offset)
/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*dispatch" { target *-*-linux* } } } */
/* { dg-final { scan-assembler {movq[ \t]*_dispatch} { target { lp64 && *-*-darwin* } } } } */
-/* { dg-final { scan-assembler {movl[ \t]*l_dispatch\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
+/* { dg-final { scan-assembler {movl[ \t]*[Ll]_dispatch\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
/* { dg-final { scan-assembler "call\[ \t\]*_?__x86_indirect_thunk_(r|e)ax" } } */
/* { dg-final { scan-assembler {jmp[ \t]*\.?LIND} } } */
/* { dg-final { scan-assembler {call[ \t]*\.?LIND} } } */
diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
index 8620bf1d836..1493e18243b 100644
--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
@@ -17,7 +17,7 @@ male_indirect_jump (long offset)
/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*dispatch" { target *-*-linux* } } } */
/* { dg-final { scan-assembler {movq[ \t]*_dispatch} { target { lp64 && *-*-darwin* } } } } */
-/* { dg-final { scan-assembler {movl[ \t]*l_dispatch\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
+/* { dg-final { scan-assembler {movl[ \t]*[Ll]_dispatch\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
/* { dg-final { scan-assembler "jmp\[ \t\]*_?__x86_indirect_thunk_(r|e)ax" } } */
/* { dg-final { scan-assembler {jmp[ \t]*\.?LIND} } } */
/* { dg-final { scan-assembler {call[ \t]*\.?LIND} } } */
diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
index 42e83416965..3ddd4980b69 100644
--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
@@ -15,7 +15,7 @@ male_indirect_jump (long offset)
/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*dispatch" { target *-*-linux* } } } */
/* { dg-final { scan-assembler {movq[ \t]*_dispatch} { target { lp64 && *-*-darwin* } } } } */
-/* { dg-final { scan-assembler {movl[ \t]*l_dispatch\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
+/* { dg-final { scan-assembler {movl[ \t]*[Ll]_dispatch\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
/* { dg-final { scan-assembler "jmp\[ \t\]*_?__x86_indirect_thunk_(r|e)ax" } } */
/* { dg-final { scan-assembler {jmp[ \t]*\.?LIND} } } */
/* { dg-final { scan-assembler {call[ \t]*\.?LIND} } } */
diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
index 6a9c51337d9..43d5f95b4fb 100644
--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
@@ -17,7 +17,7 @@ male_indirect_jump (long offset)
/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*dispatch" { target *-*-linux* } } } */
/* { dg-final { scan-assembler {movq[ \t]*_dispatch} { target { lp64 && *-*-darwin* } } } } */
-/* { dg-final { scan-assembler {movl[ \t]*l_dispatch\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
+/* { dg-final { scan-assembler {movl[ \t]*[Ll]_dispatch\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
/* { dg-final { scan-assembler-times {jmp[ \t]*\.?LIND} 2 } } */
/* { dg-final { scan-assembler-times {call[ \t]*\.?LIND} 2 } } */
/* { dg-final { scan-assembler {\tpause} } } */
diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
index 85ec57b5a8d..bf62636c63c 100644
--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
@@ -16,7 +16,7 @@ male_indirect_jump (long offset)
/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*dispatch" { target *-*-linux* } } } */
/* { dg-final { scan-assembler {movq[ \t]*_dispatch} { target { lp64 && *-*-darwin* } } } } */
-/* { dg-final { scan-assembler {movl[ \t]*l_dispatch\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
+/* { dg-final { scan-assembler {movl[ \t]*[Ll]_dispatch\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
/* { dg-final { scan-assembler-times {jmp[ \t]*\.?LIND} 2 } } */
/* { dg-final { scan-assembler-times {call[ \t]*\.?LIND} 2 } } */
/* { dg-final { scan-assembler {\tpause} } } */
diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
index db1d8fb9979..27ba82932e4 100644
--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
@@ -17,7 +17,7 @@ male_indirect_jump (long offset)
/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*dispatch" { target *-*-linux* } } } */
/* { dg-final { scan-assembler {movq[ \t]*_dispatch} { target { lp64 && *-*-darwin* } } } } */
-/* { dg-final { scan-assembler {movl[ \t]*l_dispatch\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
+/* { dg-final { scan-assembler {movl[ \t]*[Ll]_dispatch\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
/* { dg-final { scan-assembler "call\[ \t\]*_?__x86_indirect_thunk_(r|e)ax" } } */
/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
/* { dg-final { scan-assembler-not {jmp[ \t]*\.?LIND} } } */
diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
index 24fc43b3ba5..bdf15d36bac 100644
--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
@@ -16,7 +16,7 @@ male_indirect_jump (long offset)
/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*dispatch" { target *-*-linux* } } } */
/* { dg-final { scan-assembler {movq[ \t]*_dispatch} { target { lp64 && *-*-darwin* } } } } */
-/* { dg-final { scan-assembler {movl[ \t]*l_dispatch\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
+/* { dg-final { scan-assembler {movl[ \t]*[Ll]_dispatch\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
/* { dg-final { scan-assembler "call\[ \t\]*_?__x86_indirect_thunk_(r|e)ax" } } */
/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
/* { dg-final { scan-assembler-not {jmp[ \t]*\.?LIND} } } */
diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
index 3dc02f80ff5..c30c331c23b 100644
--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
@@ -14,7 +14,7 @@ male_indirect_jump (long offset)
/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*dispatch" { target *-*-linux* } } } */
/* { dg-final { scan-assembler {movq[ \t]*_dispatch} { target { lp64 && *-*-darwin* } } } } */
-/* { dg-final { scan-assembler {movl[ \t]*l_dispatch\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
+/* { dg-final { scan-assembler {movl[ \t]*[Ll]_dispatch\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
/* { dg-final { scan-assembler "jmp\[ \t\]*_?__x86_indirect_thunk_(r|e)ax" } } */
/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
/* { dg-final { scan-assembler-not {jmp[ \t]*\.?LIND} } } */
diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
index c4adae23dd3..7edd7313027 100644
--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
@@ -14,7 +14,7 @@ male_indirect_jump (long offset)
/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*dispatch" { target *-*-linux* } } } */
/* { dg-final { scan-assembler {movq[ \t]*_dispatch} { target { lp64 && *-*-darwin* } } } } */
-/* { dg-final { scan-assembler {movl[ \t]*l_dispatch\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
+/* { dg-final { scan-assembler {movl[ \t]*[Ll]_dispatch\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
/* { dg-final { scan-assembler "jmp\[ \t\]*_?__x86_indirect_thunk_(r|e)ax" } } */
/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
/* { dg-final { scan-assembler-not {jmp[ \t]*\.?LIND} } } */
diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
index b800b40b055..8e391797c5e 100644
--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
@@ -15,7 +15,7 @@ male_indirect_jump (long offset)
/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*dispatch" { target *-*-linux* } } } */
/* { dg-final { scan-assembler {movq[ \t]*_dispatch} { target { lp64 && *-*-darwin* } } } } */
-/* { dg-final { scan-assembler {movl[ \t]*l_dispatch\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
+/* { dg-final { scan-assembler {movl[ \t]*[Ll]_dispatch\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
/* { dg-final { scan-assembler "call\[ \t\]*_?__x86_indirect_thunk_(r|e)ax" } } */
/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
/* { dg-final { scan-assembler-not {jmp[ \t]*\.?LIND} } } */
diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
index f68902ddc25..6033d13e8a7 100644
--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
@@ -15,6 +15,6 @@ male_indirect_jump (long offset)
/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*dispatch" { target *-*-linux* } } } */
/* { dg-final { scan-assembler {movq[ \t]*_dispatch} { target { lp64 && *-*-darwin* } } } } */
-/* { dg-final { scan-assembler {movl[ \t]*l_dispatch\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
+/* { dg-final { scan-assembler {movl[ \t]*[Ll]_dispatch\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
/* { dg-final { scan-assembler "call\[ \t\]*_?__x86_indirect_thunk_(r|e)ax" } } */
/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
index 7301490d49c..ef3577d2934 100644
--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
@@ -14,7 +14,7 @@ male_indirect_jump (long offset)
/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*dispatch" { target *-*-linux* } } } */
/* { dg-final { scan-assembler {movq[ \t]*_dispatch} { target { lp64 && *-*-darwin* } } } } */
-/* { dg-final { scan-assembler {movl[ \t]*l_dispatch\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
+/* { dg-final { scan-assembler {movl[ \t]*[Ll]_dispatch\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
/* { dg-final { scan-assembler {jmp[ \t]*\.?LIND} } } */
/* { dg-final { scan-assembler {call[ \t]*\.?LIND} } } */
/* { dg-final { scan-assembler {\tpause} } } */
diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
index ef1ba02978d..f26a5fb9015 100644
--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
@@ -14,7 +14,7 @@ male_indirect_jump (long offset)
/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*dispatch" { target *-*-linux* } } } */
/* { dg-final { scan-assembler {movq[ \t]*_dispatch} { target { lp64 && *-*-darwin* } } } } */
-/* { dg-final { scan-assembler {movl[ \t]*l_dispatch\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
+/* { dg-final { scan-assembler {movl[ \t]*[Ll]_dispatch\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
/* { dg-final { scan-assembler {jmp[ \t]*\.?LIND} } } */
/* { dg-final { scan-assembler {call[ \t]*\.?LIND} } } */
/* { dg-final { scan-assembler {\tpause} } } */
diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
index 58de8f0393e..3b8a1eeaffb 100644
--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
@@ -15,7 +15,7 @@ male_indirect_jump (long offset)
/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*dispatch" { target *-*-linux* } } } */
/* { dg-final { scan-assembler {movq[ \t]*_dispatch} { target { lp64 && *-*-darwin* } } } } */
-/* { dg-final { scan-assembler {movl[ \t]*l_dispatch\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
+/* { dg-final { scan-assembler {movl[ \t]*[Ll]_dispatch\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
/* { dg-final { scan-assembler-times {jmp[ \t]*\.?LIND} 2 } } */
/* { dg-final { scan-assembler-times {call[ \t]*\.?LIND} 2 } } */
/* { dg-final { scan-assembler-times {\tpause} 1 } } */
diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
index 3be3ce07527..40d31803a2e 100644
--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
@@ -15,7 +15,7 @@ male_indirect_jump (long offset)
/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*dispatch" { target *-*-linux* } } } */
/* { dg-final { scan-assembler {movq[ \t]*_dispatch} { target { lp64 && *-*-darwin* } } } } */
-/* { dg-final { scan-assembler {movl[ \t]*l_dispatch\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
+/* { dg-final { scan-assembler {movl[ \t]*[Ll]_dispatch\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
/* { dg-final { scan-assembler-times {jmp[ \t]*\.?LIND} 2 } } */
/* { dg-final { scan-assembler-times {call[ \t]*\.?LIND} 2 } } */
/* { dg-final { scan-assembler-times {\tpause} 1 } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr32219-2.c b/gcc/testsuite/gcc.target/i386/pr32219-2.c
index cb587db47aa..b6212f7dd4c 100644
--- a/gcc/testsuite/gcc.target/i386/pr32219-2.c
+++ b/gcc/testsuite/gcc.target/i386/pr32219-2.c
@@ -20,5 +20,5 @@ foo ()
/* { dg-final { scan-assembler "movl\[ \t\]xxx@GOT\\(%\[^,\]*\\), %" { target { ia32 && { ! *-*-darwin* } } } } } */
/* Darwin m32 defaults to PIC but common symbols need to be indirected. */
-/* { dg-final { scan-assembler {movl[ \t]l_xxx\$non_lazy_ptr-L1\$pb\(%eax\),[ \t]%eax} { target { ia32 && *-*-darwin* } } } } */
+/* { dg-final { scan-assembler {movl[ \t][Ll]_xxx\$non_lazy_ptr-L1\$pb\(%eax\),[ \t]%eax} { target { ia32 && *-*-darwin* } } } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr32219-3.c b/gcc/testsuite/gcc.target/i386/pr32219-3.c
index f9cfca7d72c..a1b0df28d0d 100644
--- a/gcc/testsuite/gcc.target/i386/pr32219-3.c
+++ b/gcc/testsuite/gcc.target/i386/pr32219-3.c
@@ -24,4 +24,4 @@ foo ()
/* For Darwin, we need PIC to allow PIE, but also we must indirect weak symbols so that
they can be indirected. Again, dyld knows how to deal with this. */
-/* { dg-final { scan-assembler {movl[ \t]l_xxx\$non_lazy_ptr-L1\$pb\(%eax\),[ \t]%eax} { target { ia32 && *-*-darwin* } } } } */
+/* { dg-final { scan-assembler {movl[ \t][Ll]_xxx\$non_lazy_ptr-L1\$pb\(%eax\),[ \t]%eax} { target { ia32 && *-*-darwin* } } } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr32219-4.c b/gcc/testsuite/gcc.target/i386/pr32219-4.c
index 0ac0674ae17..31d0710b7ed 100644
--- a/gcc/testsuite/gcc.target/i386/pr32219-4.c
+++ b/gcc/testsuite/gcc.target/i386/pr32219-4.c
@@ -21,4 +21,4 @@ foo ()
/* { dg-final { scan-assembler "movl\[ \t\]xxx@GOT\\(%\[^,\]*\\), %" { target { ia32 && { ! *-*-darwin* } } } } } */
/* Darwin m32 equivalent (indirect and PIC). */
-/* { dg-final { scan-assembler {movl[ \t]l_xxx\$non_lazy_ptr-L1\$pb\(%eax\),[ \t]%eax} { target { ia32 && *-*-darwin* } } } } */
+/* { dg-final { scan-assembler {movl[ \t][Ll]_xxx\$non_lazy_ptr-L1\$pb\(%eax\),[ \t]%eax} { target { ia32 && *-*-darwin* } } } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr32219-7.c b/gcc/testsuite/gcc.target/i386/pr32219-7.c
index 469e9e38b07..20fef8dd063 100644
--- a/gcc/testsuite/gcc.target/i386/pr32219-7.c
+++ b/gcc/testsuite/gcc.target/i386/pr32219-7.c
@@ -23,4 +23,4 @@ foo ()
/* { dg-final { scan-assembler-not "movl\[ \t\]xxx@GOT\\(%\[^,\]*\\), %eax" { target { ia32 && { ! *-*-darwin* } } } } } */
/* Darwin m32 equivalent (indirect and PIC). */
-/* { dg-final { scan-assembler {movl[ \t]l_xxx\$non_lazy_ptr-L1\$pb\(%eax\),[ \t]%eax} { target { ia32 && *-*-darwin* } } } } */
+/* { dg-final { scan-assembler {movl[ \t][Ll]_xxx\$non_lazy_ptr-L1\$pb\(%eax\),[ \t]%eax} { target { ia32 && *-*-darwin* } } } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr32219-8.c b/gcc/testsuite/gcc.target/i386/pr32219-8.c
index 75eb287fc59..767928f049e 100644
--- a/gcc/testsuite/gcc.target/i386/pr32219-8.c
+++ b/gcc/testsuite/gcc.target/i386/pr32219-8.c
@@ -21,4 +21,4 @@ foo ()
/* { dg-final { scan-assembler "movl\[ \t\]xxx@GOT\\(%\[^,\]*\\), %" { target { ia32 && { ! *-*-darwin* } } } } } */
/* Darwin m32 default to PIC but needs indirection for the weak symbol. */
-/* { dg-final { scan-assembler {movl[ \t]l_xxx\$non_lazy_ptr-L1\$pb\(%eax\),[ \t]%eax} { target { ia32 && *-*-darwin* } } } } */
+/* { dg-final { scan-assembler {movl[ \t][Ll]_xxx\$non_lazy_ptr-L1\$pb\(%eax\),[ \t]%eax} { target { ia32 && *-*-darwin* } } } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr47312.c b/gcc/testsuite/gcc.target/i386/pr47312.c
index 03769a1cf81..ec4b51cb921 100644
--- a/gcc/testsuite/gcc.target/i386/pr47312.c
+++ b/gcc/testsuite/gcc.target/i386/pr47312.c
@@ -4,7 +4,6 @@
/* { dg-require-effective-target xop } */
/* { dg-require-effective-target c99_runtime } */
/* { dg-options "-O -flto -mno-sse3 -mxop" } */
-/* { dg-add-options c99_runtime } */
extern double fma (double, double, double);
extern float fmaf (float, float, float);
diff --git a/gcc/testsuite/gcc.target/i386/pr71801.c b/gcc/testsuite/gcc.target/i386/pr71801.c
index 6c87522f31d..4f1cb190233 100644
--- a/gcc/testsuite/gcc.target/i386/pr71801.c
+++ b/gcc/testsuite/gcc.target/i386/pr71801.c
@@ -16,7 +16,7 @@ static int get_label_uuid(char *p1) {
}
void uuidcache_addentry(char *p1) { __builtin_memcpy(&c, p1, sizeof(c)); }
void uuidcache_init() {
- char d[1];
+ char d[sizeof(a) + sizeof(c)];
get_label_uuid(d);
uuidcache_addentry(d);
}
diff --git a/gcc/testsuite/gcc.target/i386/pr91994.c b/gcc/testsuite/gcc.target/i386/pr91994.c
new file mode 100644
index 00000000000..033be68e7d0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr91994.c
@@ -0,0 +1,35 @@
+/* { dg-do run } */
+/* { dg-require-effective-target avx } */
+/* { dg-options "-O2 -mavx -mvzeroupper" } */
+
+#include "avx-check.h"
+
+#include <immintrin.h>
+
+__m256i x1, x2, x3;
+
+__attribute__ ((noinline))
+static void
+foo (void)
+{
+ x1 = x2;
+}
+
+void
+bar (void)
+{
+ __m256i x = x1;
+ foo ();
+ x3 = x;
+}
+
+__attribute__ ((noinline))
+void
+avx_test (void)
+{
+ __m256i x = _mm256_set1_epi8 (3);
+ x1 = x;
+ bar ();
+ if (__builtin_memcmp (&x3, &x, sizeof (x)))
+ __builtin_abort ();
+}
diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-14.c b/gcc/testsuite/gcc.target/i386/ret-thunk-14.c
index 3eaddee8c34..881f541772c 100644
--- a/gcc/testsuite/gcc.target/i386/ret-thunk-14.c
+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-14.c
@@ -19,6 +19,6 @@ foo (void)
/* { dg-final { scan-assembler {call[ \t]*\.?LIND} } } */
/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*bar" { target *-*-linux* } } } */
/* { dg-final { scan-assembler {movq[ \t]*_bar} { target { lp64 && *-*-darwin* } } } } */
-/* { dg-final { scan-assembler {movl[ \t]*l_bar\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
+/* { dg-final { scan-assembler {movl[ \t]*[Ll]_bar\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
/* { dg-final { scan-assembler "call\[ \t\]*_?__x86_indirect_thunk_(r|e)ax" } } */
/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" } } */
diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-15.c b/gcc/testsuite/gcc.target/i386/ret-thunk-15.c
index 2793f72cdc1..5687440bf31 100644
--- a/gcc/testsuite/gcc.target/i386/ret-thunk-15.c
+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-15.c
@@ -19,6 +19,6 @@ foo (void)
/* { dg-final { scan-assembler-times {\tlfence} 1 } } */
/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*bar" { target *-*-linux* } } } */
/* { dg-final { scan-assembler {movq[ \t]*_bar} { target { lp64 && *-*-darwin* } } } } */
-/* { dg-final { scan-assembler {movl[ \t]*l_bar\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
+/* { dg-final { scan-assembler {movl[ \t]*[Ll]_bar\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
/* { dg-final { scan-assembler "call\[ \t\]*_?__x86_indirect_thunk_(r|e)ax" } } */
/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" } } */
diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-9.c b/gcc/testsuite/gcc.target/i386/ret-thunk-9.c
index 63af6741e05..3d4497000dc 100644
--- a/gcc/testsuite/gcc.target/i386/ret-thunk-9.c
+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-9.c
@@ -17,7 +17,7 @@ foo (void)
/* { dg-final { scan-assembler "_?__x86_return_thunk:" } } */
/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*bar" { target *-*-linux* } } } */
/* { dg-final { scan-assembler {movq[ \t]*_bar} { target { lp64 && *-*-darwin* } } } } */
-/* { dg-final { scan-assembler {movl[ \t]*l_bar\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
+/* { dg-final { scan-assembler {movl[ \t]*[Ll]_bar\$non_lazy_ptr-L[0-9]+\$pb} { target { ia32 && *-*-darwin* } } } } */
/* { dg-final { scan-assembler-times {\tpause} 2 } } */
/* { dg-final { scan-assembler-times {\tlfence} 2 } } */
/* { dg-final { scan-assembler "call\[ \t\]*_?__x86_indirect_thunk_(r|e)ax" } } */
diff --git a/gcc/testsuite/gcc.target/i386/sse2-builtin-fp-int-inexact.c b/gcc/testsuite/gcc.target/i386/sse2-builtin-fp-int-inexact.c
index 10015972049..2226e6a231b 100644
--- a/gcc/testsuite/gcc.target/i386/sse2-builtin-fp-int-inexact.c
+++ b/gcc/testsuite/gcc.target/i386/sse2-builtin-fp-int-inexact.c
@@ -1,7 +1,6 @@
/* Test -fno-fp-int-builtin-inexact for SSE 2. */
/* { dg-do run } */
/* { dg-options "-O2 -msse2 -mfpmath=sse -fno-fp-int-builtin-inexact" } */
-/* { dg-add-options c99_runtime } */
/* { dg-require-effective-target fenv_exceptions } */
/* { dg-require-effective-target sse2 } */
diff --git a/gcc/testsuite/gcc.target/i386/sse2-rint-inline-1.c b/gcc/testsuite/gcc.target/i386/sse2-rint-inline-1.c
index 06baed2046a..23c979771cc 100644
--- a/gcc/testsuite/gcc.target/i386/sse2-rint-inline-1.c
+++ b/gcc/testsuite/gcc.target/i386/sse2-rint-inline-1.c
@@ -2,7 +2,6 @@
should be expanded when spurious "inexact" allowed. */
/* { dg-do compile } */
/* { dg-options "-O2 -msse2 -mfpmath=sse -ffp-int-builtin-inexact" } */
-/* { dg-add-options c99_runtime } */
/* { dg-require-effective-target sse2 } */
#define TEST(FN, TYPE) \
diff --git a/gcc/testsuite/gcc.target/i386/sse2-rint-inline-2.c b/gcc/testsuite/gcc.target/i386/sse2-rint-inline-2.c
index 3ebf7a7af69..28968259dc4 100644
--- a/gcc/testsuite/gcc.target/i386/sse2-rint-inline-2.c
+++ b/gcc/testsuite/gcc.target/i386/sse2-rint-inline-2.c
@@ -2,7 +2,6 @@
should be expanded even when spurious "inexact" not allowed. */
/* { dg-do compile } */
/* { dg-options "-O2 -msse2 -mfpmath=sse -fno-fp-int-builtin-inexact" } */
-/* { dg-add-options c99_runtime } */
/* { dg-require-effective-target sse2 } */
#define TEST(FN, TYPE) \
diff --git a/gcc/testsuite/gcc.target/i386/sse4_1-builtin-fp-int-inexact.c b/gcc/testsuite/gcc.target/i386/sse4_1-builtin-fp-int-inexact.c
index 4c9244d0544..c1c8a19d4db 100644
--- a/gcc/testsuite/gcc.target/i386/sse4_1-builtin-fp-int-inexact.c
+++ b/gcc/testsuite/gcc.target/i386/sse4_1-builtin-fp-int-inexact.c
@@ -1,7 +1,6 @@
/* Test -fno-fp-int-builtin-inexact for SSE 4.1. */
/* { dg-do run } */
/* { dg-options "-O2 -msse4.1 -mfpmath=sse -fno-fp-int-builtin-inexact" } */
-/* { dg-add-options c99_runtime } */
/* { dg-require-effective-target fenv_exceptions } */
/* { dg-require-effective-target sse4 } */
diff --git a/gcc/testsuite/gcc.target/i386/sse4_1-rint-inline.c b/gcc/testsuite/gcc.target/i386/sse4_1-rint-inline.c
index 6d60da33cb7..995c14cefa1 100644
--- a/gcc/testsuite/gcc.target/i386/sse4_1-rint-inline.c
+++ b/gcc/testsuite/gcc.target/i386/sse4_1-rint-inline.c
@@ -2,7 +2,6 @@
when spurious "inexact" not allowed. */
/* { dg-do compile } */
/* { dg-options "-O2 -msse4.1 -mfpmath=sse -fno-fp-int-builtin-inexact" } */
-/* { dg-add-options c99_runtime } */
/* { dg-require-effective-target sse4 } */
#define TEST(FN, TYPE) \
diff --git a/gcc/testsuite/gcc.target/msp430/430x-insns.c b/gcc/testsuite/gcc.target/msp430/430x-insns.c
new file mode 100644
index 00000000000..a67f778371a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/msp430/430x-insns.c
@@ -0,0 +1,1646 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-mcpu=msp430" "-mcpu=430" "-msmall" } { "" } } */
+/* { dg-options "-O1 -mlarge" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+/* The purpose of this test is to check that all insn patters in msp430.md
+ which use the "Yx" constraint work as expected.
+ So when both of the operands are in lower memory, a 430 instruction is
+ generated, and when at least one of the operands might be in upper memory,
+ a 430X instruction is generated.
+ We do not need to extensively test the situation where one of the operands
+ in an insn is not a mem (i.e. it is a register or immediate). A single test
+ will verify that the constraint correctly assumes that a reg
+ or immediate does not itself require a 430X instruction. */
+
+typedef char qi;
+typedef int hi;
+/* For insns which use the QHI mode iterator (therefore accepting QI, HI and
+ PSI modes), we also check the PSImode version. All insns should be 430x
+ in that case. */
+typedef __int20 psi;
+typedef long si;
+
+#define ATTR_EITHER __attribute__((either))
+#define ATTR_LOWER __attribute__((lower))
+
+/* Use these to generate 430X insns. */
+qi ATTR_EITHER eqi1, eqi2, eqi3, eqi4, eqi5, eqi6;
+hi ATTR_EITHER ehi1, ehi2, ehi3, ehi4, ehi5, ehi6;
+psi ATTR_EITHER epsi1, epsi2, epsi3, epsi4, epsi5, epsi6;
+si ATTR_EITHER esi1, esi2, esi3, esi4, esi5, esi6;
+
+/* Use these to generate 430 insns. */
+qi ATTR_LOWER lqi1, lqi2, lqi3, lqi4, lqi5, lqi6;
+hi ATTR_LOWER lhi1, lhi2, lhi3, lhi4, lhi5, lhi6;
+psi ATTR_LOWER lpsi1, lpsi2, lpsi3, lpsi4, lpsi5, lpsi6;
+si ATTR_LOWER lsi1, lsi2, lsi3, lsi4, lsi5, lsi6;
+
+/* The default data region is "lower", so these behave the same as the above
+ "l*" variables unless -mdata-region={upper,either,none} is passed. */
+qi qi1, qi2, qi3, qi4, qi5, qi6;
+hi hi1, hi2, hi3, hi4, hi5, hi6;
+psi psi1, psi2, psi3, psi4, psi5, psi6;
+si si1, si2, si3, si4, si5, si6;
+
+qi use_qi(qi a);
+hi use_hi(hi a);
+psi use_psi(psi a);
+si use_si(si a);
+
+#define USE_MODE(MODE) use_ ## MODE
+#define USE_MODE_N(MODE,N) use_ ## N ## MODE
+
+#define E_VAR(MODE,N) e ## MODE ## N
+#define L_VAR(MODE,N) l ## MODE ## N
+#define VAR(MODE,N) MODE ## N
+
+#define REG_VAR(MODE,N) MODE ## r ## N
+
+/* Verify that a register operand does not influence whether a 430X instruction
+ is used or not. */
+/*
+** register_operand: { target msp430_region_lower }
+** ...
+** MOV.B &lqi1, R12
+** ...
+** MOV.B &qi1, R12
+** ...
+** MOVX.B &eqi1, R12
+** ...
+*/
+/*
+** register_operand: { target msp430_region_not_lower }
+** ...
+** MOV.B &lqi1, R12
+** ...
+** MOVX.B &qi1, R12
+** ...
+** MOVX.B &eqi1, R12
+** ...
+*/
+
+void
+register_operand (void)
+{
+ use_qi (lqi1);
+ use_qi (qi1);
+ use_qi (eqi1);
+}
+
+/* Verify that an immediate operand does not influence whether a 430X instruction
+ is used or not. */
+/*
+** immediate_operand: { target msp430_region_lower }
+** ...
+** MOV.B #1, &lqi1
+** MOV.B #2, &qi1
+** MOVX.B #3, &eqi1
+** ...
+*/
+/*
+** immediate_operand: { target msp430_region_not_lower }
+** ...
+** MOV.B #1, &lqi1
+** MOVX.B #2, &qi1
+** MOVX.B #3, &eqi1
+** ...
+*/
+void
+immediate_operand (void)
+{
+ lqi1 = 1;
+ qi1 = 2;
+ eqi1 = 3;
+}
+
+/* Verify that variables marked with the noinit, persistent, section and lower
+ attributes have the appropriate format instructions generated to handle
+ them. */
+int __attribute__((persistent)) pp = 10;
+int __attribute__((noinit)) nn;
+int __attribute__((section(".data.foo"))) s;
+int __attribute__((section(".data.foo"),lower)) sl1;
+int __attribute__((lower,section(".data.foo"))) sl2;
+
+/*
+** attrs:
+** ...
+** MOVX.W #1, &pp
+** MOV.W #2, &nn
+** MOVX.W #3, &s
+** MOV.W #4, &sl1
+** MOV.W #5, &sl2
+** ...
+*/
+void
+attrs (void)
+{
+ pp = 1;
+ nn = 2;
+ s = 3;
+ sl1 = 4;
+ sl2 = 5;
+}
+
+#define MOV_INSNS(MODE) \
+ E_VAR(MODE, 1) = E_VAR(MODE, 2); \
+ E_VAR(MODE, 3) = L_VAR(MODE, 1); \
+ E_VAR(MODE, 4) = VAR(MODE, 1); \
+ L_VAR(MODE, 4) = E_VAR(MODE, 5); \
+ VAR(MODE, 5) = E_VAR(MODE, 6); \
+ L_VAR(MODE, 2) = L_VAR(MODE, 3); \
+ L_VAR(MODE, 5) = VAR(MODE, 2); \
+ VAR(MODE, 3) = VAR(MODE, 4); \
+ VAR(MODE, 6) = L_VAR(MODE, 6);
+
+
+/*
+** movqi: { target msp430_region_lower }
+** ...
+** MOVX.B &eqi2, &eqi1
+** MOVX.B &lqi1, &eqi3
+** MOVX.B &qi1, &eqi4
+** MOVX.B &eqi5, &lqi4
+** MOVX.B &eqi6, &qi5
+** MOV.B &lqi3, &lqi2
+** MOV.B &qi2, &lqi5
+** MOV.B &qi4, &qi3
+** MOV.B &lqi6, &qi6
+** ...
+*/
+/*
+** movqi: { target msp430_region_not_lower }
+** ...
+** MOVX.B &eqi2, &eqi1
+** MOVX.B &lqi1, &eqi3
+** MOVX.B &qi1, &eqi4
+** MOVX.B &eqi5, &lqi4
+** MOVX.B &eqi6, &qi5
+** MOV.B &lqi3, &lqi2
+** MOVX.B &qi2, &lqi5
+** MOVX.B &qi4, &qi3
+** MOVX.B &lqi6, &qi6
+** ...
+*/
+void
+movqi (void)
+{
+ MOV_INSNS (qi)
+}
+
+/*
+** movhi: { target msp430_region_lower }
+** ...
+** MOVX.W &ehi2, &ehi1
+** MOVX.W &lhi1, &ehi3
+** MOVX.W &hi1, &ehi4
+** MOVX.W &ehi5, &lhi4
+** MOVX.W &ehi6, &hi5
+** MOV.W &lhi3, &lhi2
+** MOV.W &hi2, &lhi5
+** MOV.W &hi4, &hi3
+** MOV.W &lhi6, &hi6
+** ...
+*/
+/*
+** movhi: { target msp430_region_not_lower }
+** ...
+** MOVX.W &ehi2, &ehi1
+** MOVX.W &lhi1, &ehi3
+** MOVX.W &hi1, &ehi4
+** MOVX.W &ehi5, &lhi4
+** MOVX.W &ehi6, &hi5
+** MOV.W &lhi3, &lhi2
+** MOVX.W &hi2, &lhi5
+** MOVX.W &hi4, &hi3
+** MOVX.W &lhi6, &hi6
+** ...
+*/
+void
+movhi (void)
+{
+ MOV_INSNS (hi)
+}
+
+/* There is no specific movsi3 pattern defined for msp430, but we check
+ this is synthesized correctly anyway. */
+/*
+** movsi: { target msp430_region_lower }
+** ...
+** MOVX.W &esi2, &esi1
+** MOVX.W &esi2\+2, &esi1\+2
+** MOVX.W &lsi1, &esi3
+** MOVX.W &lsi1\+2, &esi3\+2
+** MOVX.W &si1, &esi4
+** MOVX.W &si1\+2, &esi4\+2
+** MOVX.W &esi5, &lsi4
+** MOVX.W &esi5\+2, &lsi4\+2
+** MOVX.W &esi6, &si5
+** MOVX.W &esi6\+2, &si5\+2
+** MOV.W &lsi3, &lsi2
+** MOV.W &lsi3\+2, &lsi2\+2
+** MOV.W &si2, &lsi5
+** MOV.W &si2\+2, &lsi5\+2
+** MOV.W &si4, &si3
+** MOV.W &si4\+2, &si3\+2
+** MOV.W &lsi6, &si6
+** MOV.W &lsi6\+2, &si6\+2
+** ...
+*/
+/*
+** movsi: { target msp430_region_not_lower }
+** ...
+** MOVX.W &esi2, &esi1
+** MOVX.W &esi2\+2, &esi1\+2
+** MOVX.W &lsi1, &esi3
+** MOVX.W &lsi1\+2, &esi3\+2
+** MOVX.W &si1, &esi4
+** MOVX.W &si1\+2, &esi4\+2
+** MOVX.W &esi5, &lsi4
+** MOVX.W &esi5\+2, &lsi4\+2
+** MOVX.W &esi6, &si5
+** MOVX.W &esi6\+2, &si5\+2
+** MOV.W &lsi3, &lsi2
+** MOV.W &lsi3\+2, &lsi2\+2
+** MOVX.W &si2, &lsi5
+** MOVX.W &si2\+2, &lsi5\+2
+** MOVX.W &si4, &si3
+** MOVX.W &si4\+2, &si3\+2
+** MOVX.W &lsi6, &si6
+** MOVX.W &lsi6\+2, &si6\+2
+** ...
+*/
+void
+movsi (void)
+{
+ MOV_INSNS (si)
+}
+
+#define ADD_INSNS(MODE) \
+ E_VAR(MODE,1) += E_VAR(MODE,2); \
+ E_VAR(MODE,3) += L_VAR(MODE,1); \
+ E_VAR(MODE,4) += VAR(MODE,1); \
+ L_VAR(MODE,2) += E_VAR(MODE,5); \
+ VAR(MODE,3) += E_VAR(MODE,6); \
+ L_VAR(MODE,3) += L_VAR(MODE,4); \
+ L_VAR(MODE,5) += VAR(MODE,2); \
+ VAR(MODE,4) += L_VAR(MODE,6); \
+ VAR(MODE,5) += VAR(MODE,6);
+
+/*
+** addqi3: { target msp430_region_lower }
+** ...
+** ADDX.B &eqi2, &eqi1
+** ADDX.B &lqi1, &eqi3
+** ADDX.B &qi1, &eqi4
+** ADDX.B &eqi5, &lqi2
+** ADDX.B &eqi6, &qi3
+** ADD.B &lqi4, &lqi3
+** ADD.B &qi2, &lqi5
+** ADD.B &lqi6, &qi4
+** ADD.B &qi6, &qi5
+** ...
+*/
+/*
+** addqi3: { target msp430_region_not_lower }
+** ...
+** ADDX.B &eqi2, &eqi1
+** ADDX.B &lqi1, &eqi3
+** ADDX.B &qi1, &eqi4
+** ADDX.B &eqi5, &lqi2
+** ADDX.B &eqi6, &qi3
+** ADD.B &lqi4, &lqi3
+** ADDX.B &qi2, &lqi5
+** ADDX.B &lqi6, &qi4
+** ADDX.B &qi6, &qi5
+** ...
+*/
+void
+addqi3 (void)
+{
+ ADD_INSNS(qi)
+}
+
+/*
+** addhi3: { target msp430_region_lower }
+** ...
+** ADDX.W &ehi2, &ehi1
+** ADDX.W &lhi1, &ehi3
+** ADDX.W &hi1, &ehi4
+** ADDX.W &ehi5, &lhi2
+** ADDX.W &ehi6, &hi3
+** ADD.W &lhi4, &lhi3
+** ADD.W &hi2, &lhi5
+** ADD.W &lhi6, &hi4
+** ADD.W &hi6, &hi5
+** ...
+*/
+/*
+** addhi3: { target msp430_region_not_lower }
+** ...
+** ADDX.W &ehi2, &ehi1
+** ADDX.W &lhi1, &ehi3
+** ADDX.W &hi1, &ehi4
+** ADDX.W &ehi5, &lhi2
+** ADDX.W &ehi6, &hi3
+** ADD.W &lhi4, &lhi3
+** ADDX.W &hi2, &lhi5
+** ADDX.W &lhi6, &hi4
+** ADDX.W &hi6, &hi5
+** ...
+*/
+void
+addhi3 (void)
+{
+ ADD_INSNS(hi)
+}
+
+/*
+** addsi3: { target msp430_region_lower }
+** ...
+** ADDX &esi2, &esi1 { ADDCX &esi2\+2, &esi1\+2
+** ADDX &lsi1, &esi3 { ADDCX &lsi1\+2, &esi3\+2
+** ADDX &si1, &esi4 { ADDCX &si1\+2, &esi4\+2
+** ADDX &esi5, &lsi2 { ADDCX &esi5\+2, &lsi2\+2
+** ADDX &esi6, &si3 { ADDCX &esi6\+2, &si3\+2
+** ADD &lsi4, &lsi3 { ADDC &lsi4\+2, &lsi3\+2
+** ADD &si2, &lsi5 { ADDC &si2\+2, &lsi5\+2
+** ADD &lsi6, &si4 { ADDC &lsi6\+2, &si4\+2
+** ADD &si6, &si5 { ADDC &si6\+2, &si5\+2
+** ...
+*/
+/*
+** addsi3: { target msp430_region_not_lower }
+** ...
+** ADDX &esi2, &esi1 { ADDCX &esi2\+2, &esi1\+2
+** ADDX &lsi1, &esi3 { ADDCX &lsi1\+2, &esi3\+2
+** ADDX &si1, &esi4 { ADDCX &si1\+2, &esi4\+2
+** ADDX &esi5, &lsi2 { ADDCX &esi5\+2, &lsi2\+2
+** ADDX &esi6, &si3 { ADDCX &esi6\+2, &si3\+2
+** ADD &lsi4, &lsi3 { ADDC &lsi4\+2, &lsi3\+2
+** ADDX &si2, &lsi5 { ADDCX &si2\+2, &lsi5\+2
+** ADDX &lsi6, &si4 { ADDCX &lsi6\+2, &si4\+2
+** ADDX &si6, &si5 { ADDCX &si6\+2, &si5\+2
+** ...
+*/
+void
+addsi3 (void)
+{
+ ADD_INSNS(si)
+}
+
+#define SUB_INSNS(MODE) \
+ E_VAR(MODE,1) -= E_VAR(MODE,2); \
+ E_VAR(MODE,3) -= L_VAR(MODE,1); \
+ E_VAR(MODE,4) -= VAR(MODE,1); \
+ L_VAR(MODE,2) -= E_VAR(MODE,5); \
+ VAR(MODE,3) -= E_VAR(MODE,6); \
+ L_VAR(MODE,3) -= L_VAR(MODE,4); \
+ L_VAR(MODE,5) -= VAR(MODE,2); \
+ VAR(MODE,4) -= L_VAR(MODE,6); \
+ VAR(MODE,5) -= VAR(MODE,6);
+
+/*
+** subqi3: { target msp430_region_lower }
+** ...
+** SUBX.B &eqi2, &eqi1
+** SUBX.B &lqi1, &eqi3
+** SUBX.B &qi1, &eqi4
+** SUBX.B &eqi5, &lqi2
+** SUBX.B &eqi6, &qi3
+** SUB.B &lqi4, &lqi3
+** SUB.B &qi2, &lqi5
+** SUB.B &lqi6, &qi4
+** SUB.B &qi6, &qi5
+** ...
+*/
+/*
+** subqi3: { target msp430_region_not_lower }
+** ...
+** SUBX.B &eqi2, &eqi1
+** SUBX.B &lqi1, &eqi3
+** SUBX.B &qi1, &eqi4
+** SUBX.B &eqi5, &lqi2
+** SUBX.B &eqi6, &qi3
+** SUB.B &lqi4, &lqi3
+** SUBX.B &qi2, &lqi5
+** SUBX.B &lqi6, &qi4
+** SUBX.B &qi6, &qi5
+** ...
+*/
+void
+subqi3 (void)
+{
+ SUB_INSNS(qi)
+}
+
+/*
+** subhi3: { target msp430_region_lower }
+** ...
+** SUBX.W &ehi2, &ehi1
+** SUBX.W &lhi1, &ehi3
+** SUBX.W &hi1, &ehi4
+** SUBX.W &ehi5, &lhi2
+** SUBX.W &ehi6, &hi3
+** SUB.W &lhi4, &lhi3
+** SUB.W &hi2, &lhi5
+** SUB.W &lhi6, &hi4
+** SUB.W &hi6, &hi5
+** ...
+*/
+/*
+** subhi3: { target msp430_region_not_lower }
+** ...
+** SUBX.W &ehi2, &ehi1
+** SUBX.W &lhi1, &ehi3
+** SUBX.W &hi1, &ehi4
+** SUBX.W &ehi5, &lhi2
+** SUBX.W &ehi6, &hi3
+** SUB.W &lhi4, &lhi3
+** SUBX.W &hi2, &lhi5
+** SUBX.W &lhi6, &hi4
+** SUBX.W &hi6, &hi5
+** ...
+*/
+void
+subhi3 (void)
+{
+ SUB_INSNS(hi)
+}
+
+/*
+** subsi3: { target msp430_region_lower }
+** ...
+** SUBX &esi2, &esi1 { SUBCX &esi2\+2, &esi1\+2
+** SUBX &lsi1, &esi3 { SUBCX &lsi1\+2, &esi3\+2
+** SUBX &si1, &esi4 { SUBCX &si1\+2, &esi4\+2
+** SUBX &esi5, &lsi2 { SUBCX &esi5\+2, &lsi2\+2
+** SUBX &esi6, &si3 { SUBCX &esi6\+2, &si3\+2
+** SUB &lsi4, &lsi3 { SUBC &lsi4\+2, &lsi3\+2
+** SUB &si2, &lsi5 { SUBC &si2\+2, &lsi5\+2
+** SUB &lsi6, &si4 { SUBC &lsi6\+2, &si4\+2
+** SUB &si6, &si5 { SUBC &si6\+2, &si5\+2
+** ...
+*/
+/*
+** subsi3: { target msp430_region_not_lower }
+** ...
+** SUBX &esi2, &esi1 { SUBCX &esi2\+2, &esi1\+2
+** SUBX &lsi1, &esi3 { SUBCX &lsi1\+2, &esi3\+2
+** SUBX &si1, &esi4 { SUBCX &si1\+2, &esi4\+2
+** SUBX &esi5, &lsi2 { SUBCX &esi5\+2, &lsi2\+2
+** SUBX &esi6, &si3 { SUBCX &esi6\+2, &si3\+2
+** SUB &lsi4, &lsi3 { SUBC &lsi4\+2, &lsi3\+2
+** SUBX &si2, &lsi5 { SUBCX &si2\+2, &lsi5\+2
+** SUBX &lsi6, &si4 { SUBCX &lsi6\+2, &si4\+2
+** SUBX &si6, &si5 { SUBCX &si6\+2, &si5\+2
+** ...
+*/
+void
+subsi3 (void)
+{
+ SUB_INSNS(si)
+}
+
+#define BIC_INSN(MODE) \
+ E_VAR(MODE,1) &= (E_VAR(MODE,2) ^ E_VAR(MODE,1)); \
+ E_VAR(MODE,3) &= (L_VAR(MODE,1) ^ E_VAR(MODE,3)); \
+ E_VAR(MODE,4) &= (VAR(MODE,1) ^ E_VAR(MODE,4)); \
+ L_VAR(MODE,2) &= (E_VAR(MODE,5) ^ L_VAR(MODE,2)); \
+ VAR(MODE,2) &= (E_VAR(MODE,6) ^ VAR(MODE,2)); \
+ L_VAR(MODE,3) &= (L_VAR(MODE,4) ^ L_VAR(MODE,3)); \
+ L_VAR(MODE,5) &= (VAR(MODE,3) ^ L_VAR(MODE,5)); \
+ VAR(MODE,4) &= (L_VAR(MODE,6) ^ VAR(MODE,4)); \
+ VAR(MODE,5) &= (VAR(MODE,6) ^ VAR(MODE,5)); \
+
+/*
+** bicqi3: { target msp430_region_lower }
+** ...
+** BICX.B &eqi2, &eqi1
+** BICX.B &lqi1, &eqi3
+** BICX.B &qi1, &eqi4
+** BICX.B &eqi5, &lqi2
+** BICX.B &eqi6, &qi2
+** BIC.B &lqi4, &lqi3
+** BIC.B &qi3, &lqi5
+** BIC.B &lqi6, &qi4
+** BIC.B &qi6, &qi5
+** ...
+*/
+/*
+** bicqi3: { target msp430_region_not_lower }
+** ...
+** BICX.B &eqi2, &eqi1
+** BICX.B &lqi1, &eqi3
+** BICX.B &qi1, &eqi4
+** BICX.B &eqi5, &lqi2
+** BICX.B &eqi6, &qi2
+** BIC.B &lqi4, &lqi3
+** BICX.B &qi3, &lqi5
+** BICX.B &lqi6, &qi4
+** BICX.B &qi6, &qi5
+** ...
+*/
+void
+bicqi3 (void)
+{
+ BIC_INSN(qi)
+}
+
+/*
+** bichi3: { target msp430_region_lower }
+** ...
+** BICX.W &ehi2, &ehi1
+** BICX.W &lhi1, &ehi3
+** BICX.W &hi1, &ehi4
+** BICX.W &ehi5, &lhi2
+** BICX.W &ehi6, &hi2
+** BIC.W &lhi4, &lhi3
+** BIC.W &hi3, &lhi5
+** BIC.W &lhi6, &hi4
+** BIC.W &hi6, &hi5
+** ...
+*/
+/*
+** bichi3: { target msp430_region_not_lower }
+** ...
+** BICX.W &ehi2, &ehi1
+** BICX.W &lhi1, &ehi3
+** BICX.W &hi1, &ehi4
+** BICX.W &ehi5, &lhi2
+** BICX.W &ehi6, &hi2
+** BIC.W &lhi4, &lhi3
+** BICX.W &hi3, &lhi5
+** BICX.W &lhi6, &hi4
+** BICX.W &hi6, &hi5
+** ...
+*/
+void
+bichi3 (void)
+{
+ BIC_INSN(hi)
+}
+
+/*
+** bicpsi3:
+** ...
+** BICX.A &epsi2, &epsi1
+** BICX.A &lpsi1, &epsi3
+** BICX.A &psi1, &epsi4
+** BICX.A &epsi5, &lpsi2
+** BICX.A &epsi6, &psi2
+** BICX.A &lpsi4, &lpsi3
+** BICX.A &psi3, &lpsi5
+** BICX.A &lpsi6, &psi4
+** BICX.A &psi6, &psi5
+** ...
+*/
+void
+bicpsi3 (void)
+{
+ BIC_INSN(psi)
+}
+
+/* There is no specific bicsi3 pattern defined for msp430, but we check
+ this is synthesized correctly anyway. */
+/*
+** bicsi3: { target msp430_region_lower }
+** ...
+** BICX.W &esi2, &esi1
+** BICX.W &esi2\+2, &esi1\+2
+** BICX.W &lsi1, &esi3
+** BICX.W &lsi1\+2, &esi3\+2
+** BICX.W &si1, &esi4
+** BICX.W &si1\+2, &esi4\+2
+** BICX.W &esi5, &lsi2
+** BICX.W &esi5\+2, &lsi2\+2
+** BICX.W &esi6, &si2
+** BICX.W &esi6\+2, &si2\+2
+** BIC.W &lsi4, &lsi3
+** BIC.W &lsi4\+2, &lsi3\+2
+** BIC.W &si3, &lsi5
+** BIC.W &si3\+2, &lsi5\+2
+** BIC.W &lsi6, &si4
+** BIC.W &lsi6\+2, &si4\+2
+** BIC.W &si6, &si5
+** BIC.W &si6\+2, &si5\+2
+** ...
+*/
+/*
+** bicsi3: { target msp430_region_not_lower }
+** ...
+** BICX.W &esi2, &esi1
+** BICX.W &esi2\+2, &esi1\+2
+** BICX.W &lsi1, &esi3
+** BICX.W &lsi1\+2, &esi3\+2
+** BICX.W &si1, &esi4
+** BICX.W &si1\+2, &esi4\+2
+** BICX.W &esi5, &lsi2
+** BICX.W &esi5\+2, &lsi2\+2
+** BICX.W &esi6, &si2
+** BICX.W &esi6\+2, &si2\+2
+** BIC.W &lsi4, &lsi3
+** BIC.W &lsi4\+2, &lsi3\+2
+** BICX.W &si3, &lsi5
+** BICX.W &si3\+2, &lsi5\+2
+** BICX.W &lsi6, &si4
+** BICX.W &lsi6\+2, &si4\+2
+** BICX.W &si6, &si5
+** BICX.W &si6\+2, &si5\+2
+** ...
+*/
+void
+bicsi3 (void)
+{
+ BIC_INSN(si)
+}
+
+#define BIC_CG_INSN(MODE) \
+ E_VAR(MODE,1) &= (1 ^ E_VAR(MODE,1)); \
+ E_VAR(MODE,2) &= (2 ^ E_VAR(MODE,2)); \
+ L_VAR(MODE,1) &= (4 ^ L_VAR(MODE,1)); \
+ VAR(MODE,1) &= (8 ^ VAR(MODE,1)); \
+
+/*
+** bic_cg_qi3: { target msp430_region_lower }
+** ...
+** BICX.B #1, &eqi1
+** BICX.B #2, &eqi2
+** BIC.B #4, &lqi1
+** BIC.B #8, &qi1
+** ...
+*/
+/*
+** bic_cg_qi3: { target msp430_region_not_lower }
+** ...
+** BICX.B #1, &eqi1
+** BICX.B #2, &eqi2
+** BIC.B #4, &lqi1
+** BICX.B #8, &qi1
+** ...
+*/
+void
+bic_cg_qi3 (void)
+{
+ BIC_CG_INSN(qi)
+}
+
+/*
+** bic_cg_hi3: { target msp430_region_lower }
+** ...
+** BICX.W #1, &ehi1
+** BICX.W #2, &ehi2
+** BIC.W #4, &lhi1
+** BIC.W #8, &hi1
+** ...
+*/
+/*
+** bic_cg_hi3: { target msp430_region_not_lower }
+** ...
+** BICX.W #1, &ehi1
+** BICX.W #2, &ehi2
+** BIC.W #4, &lhi1
+** BICX.W #8, &hi1
+** ...
+*/
+void
+bic_cg_hi3 (void)
+{
+ BIC_CG_INSN(hi)
+}
+
+/*
+** bic_cg_psi3:
+** ...
+** BICX.A #1, &epsi1
+** BICX.A #2, &epsi2
+** BICX.A #4, &lpsi1
+** BICX.A #8, &psi1
+** ...
+*/
+void
+bic_cg_psi3 (void)
+{
+ BIC_CG_INSN(psi)
+}
+
+/* There is no specific bic_cg_si3 pattern defined for msp430, but we check
+ this is synthesized correctly anyway. */
+/*
+** bic_cg_si3: { target msp430_region_lower }
+** ...
+** BICX.W #1, &esi1
+** BICX.W #2, &esi2
+** BIC.W #4, &lsi1
+** BIC.W #8, &si1
+** ...
+*/
+/*
+** bic_cg_si3: { target msp430_region_not_lower }
+** ...
+** BICX.W #1, &esi1
+** BICX.W #2, &esi2
+** BIC.W #4, &lsi1
+** BICX.W #8, &si1
+** ...
+*/
+void
+bic_cg_si3 (void)
+{
+ BIC_CG_INSN(si)
+}
+
+#define AND_INSN(MODE) \
+ E_VAR(MODE,1) &= E_VAR(MODE,2); \
+ E_VAR(MODE,3) &= L_VAR(MODE,1); \
+ E_VAR(MODE,4) &= VAR(MODE,1); \
+ L_VAR(MODE,2) &= E_VAR(MODE,5); \
+ VAR(MODE,2) &= E_VAR(MODE,6); \
+ L_VAR(MODE,3) &= L_VAR(MODE,4); \
+ L_VAR(MODE,5) &= VAR(MODE,3); \
+ VAR(MODE,4) &= VAR(MODE,5); \
+ VAR(MODE,6) &= L_VAR(MODE,6);
+
+/*
+** andqi3: { target msp430_region_lower }
+** ...
+** ANDX.B &eqi2, &eqi1
+** ANDX.B &lqi1, &eqi3
+** ANDX.B &qi1, &eqi4
+** ANDX.B &eqi5, &lqi2
+** ANDX.B &eqi6, &qi2
+** AND.B &lqi4, &lqi3
+** AND.B &qi3, &lqi5
+** AND.B &qi5, &qi4
+** AND.B &lqi6, &qi6
+** ...
+*/
+/*
+** andqi3: { target msp430_region_not_lower }
+** ...
+** ANDX.B &eqi2, &eqi1
+** ANDX.B &lqi1, &eqi3
+** ANDX.B &qi1, &eqi4
+** ANDX.B &eqi5, &lqi2
+** ANDX.B &eqi6, &qi2
+** AND.B &lqi4, &lqi3
+** ANDX.B &qi3, &lqi5
+** ANDX.B &qi5, &qi4
+** ANDX.B &lqi6, &qi6
+** ...
+*/
+void
+andqi3 (void)
+{
+ AND_INSN(qi)
+}
+
+/*
+** andhi3: { target msp430_region_lower }
+** ...
+** ANDX.W &ehi2, &ehi1
+** ANDX.W &lhi1, &ehi3
+** ANDX.W &hi1, &ehi4
+** ANDX.W &ehi5, &lhi2
+** ANDX.W &ehi6, &hi2
+** AND.W &lhi4, &lhi3
+** AND.W &hi3, &lhi5
+** AND.W &hi5, &hi4
+** AND.W &lhi6, &hi6
+** ...
+*/
+/*
+** andhi3: { target msp430_region_not_lower }
+** ...
+** ANDX.W &ehi2, &ehi1
+** ANDX.W &lhi1, &ehi3
+** ANDX.W &hi1, &ehi4
+** ANDX.W &ehi5, &lhi2
+** ANDX.W &ehi6, &hi2
+** AND.W &lhi4, &lhi3
+** ANDX.W &hi3, &lhi5
+** ANDX.W &hi5, &hi4
+** ANDX.W &lhi6, &hi6
+** ...
+*/
+void
+andhi3 (void)
+{
+ AND_INSN(hi)
+}
+
+/*
+** andpsi3:
+** ...
+** ANDX.A &epsi2, &epsi1
+** ANDX.A &lpsi1, &epsi3
+** ANDX.A &psi1, &epsi4
+** ANDX.A &epsi5, &lpsi2
+** ANDX.A &epsi6, &psi2
+** ANDX.A &lpsi4, &lpsi3
+** ANDX.A &psi3, &lpsi5
+** ANDX.A &psi5, &psi4
+** ANDX.A &lpsi6, &psi6
+** ...
+*/
+void
+andpsi3 (void)
+{
+ AND_INSN(psi)
+}
+
+/* There is no specific andsi3 pattern defined for msp430, but we check
+ this is synthesized correctly anyway. */
+/*
+** andsi3: { target msp430_region_lower }
+** ...
+** ANDX.W &esi2, &esi1
+** ANDX.W &esi2\+2, &esi1\+2
+** ANDX.W &lsi1, &esi3
+** ANDX.W &lsi1\+2, &esi3\+2
+** ANDX.W &si1, &esi4
+** ANDX.W &si1\+2, &esi4\+2
+** ANDX.W &esi5, &lsi2
+** ANDX.W &esi5\+2, &lsi2\+2
+** ANDX.W &esi6, &si2
+** ANDX.W &esi6\+2, &si2\+2
+** AND.W &lsi4, &lsi3
+** AND.W &lsi4\+2, &lsi3\+2
+** AND.W &si3, &lsi5
+** AND.W &si3\+2, &lsi5\+2
+** AND.W &si5, &si4
+** AND.W &si5\+2, &si4\+2
+** AND.W &lsi6, &si6
+** AND.W &lsi6\+2, &si6\+2
+** ...
+*/
+/*
+** andsi3: { target msp430_region_not_lower }
+** ...
+** ANDX.W &esi2, &esi1
+** ANDX.W &esi2\+2, &esi1\+2
+** ANDX.W &lsi1, &esi3
+** ANDX.W &lsi1\+2, &esi3\+2
+** ANDX.W &si1, &esi4
+** ANDX.W &si1\+2, &esi4\+2
+** ANDX.W &esi5, &lsi2
+** ANDX.W &esi5\+2, &lsi2\+2
+** ANDX.W &esi6, &si2
+** ANDX.W &esi6\+2, &si2\+2
+** AND.W &lsi4, &lsi3
+** AND.W &lsi4\+2, &lsi3\+2
+** ANDX.W &si3, &lsi5
+** ANDX.W &si3\+2, &lsi5\+2
+** ANDX.W &si5, &si4
+** ANDX.W &si5\+2, &si4\+2
+** ANDX.W &lsi6, &si6
+** ANDX.W &lsi6\+2, &si6\+2
+** ...
+*/
+void
+andsi3 (void)
+{
+ AND_INSN(si)
+}
+
+#define IOR_INSN(MODE) \
+ E_VAR(MODE,1) |= E_VAR(MODE,2); \
+ E_VAR(MODE,3) |= L_VAR(MODE,1); \
+ E_VAR(MODE,4) |= VAR(MODE,1); \
+ L_VAR(MODE,2) |= E_VAR(MODE,5); \
+ VAR(MODE,2) |= E_VAR(MODE,6); \
+ L_VAR(MODE,3) |= L_VAR(MODE,4); \
+ L_VAR(MODE,5) |= VAR(MODE,3); \
+ VAR(MODE,4) |= VAR(MODE,5); \
+ VAR(MODE,6) |= L_VAR(MODE,6);
+
+/*
+** iorqi3: { target msp430_region_lower }
+** ...
+** BISX.B &eqi2, &eqi1
+** BISX.B &lqi1, &eqi3
+** BISX.B &qi1, &eqi4
+** BISX.B &eqi5, &lqi2
+** BISX.B &eqi6, &qi2
+** BIS.B &lqi4, &lqi3
+** BIS.B &qi3, &lqi5
+** BIS.B &qi5, &qi4
+** BIS.B &lqi6, &qi6
+** ...
+*/
+/*
+** iorqi3: { target msp430_region_not_lower }
+** ...
+** BISX.B &eqi2, &eqi1
+** BISX.B &lqi1, &eqi3
+** BISX.B &qi1, &eqi4
+** BISX.B &eqi5, &lqi2
+** BISX.B &eqi6, &qi2
+** BIS.B &lqi4, &lqi3
+** BISX.B &qi3, &lqi5
+** BISX.B &qi5, &qi4
+** BISX.B &lqi6, &qi6
+** ...
+*/
+void
+iorqi3 (void)
+{
+ IOR_INSN(qi)
+}
+
+/*
+** iorhi3: { target msp430_region_lower }
+** ...
+** BISX.W &ehi2, &ehi1
+** BISX.W &lhi1, &ehi3
+** BISX.W &hi1, &ehi4
+** BISX.W &ehi5, &lhi2
+** BISX.W &ehi6, &hi2
+** BIS.W &lhi4, &lhi3
+** BIS.W &hi3, &lhi5
+** BIS.W &hi5, &hi4
+** BIS.W &lhi6, &hi6
+** ...
+*/
+/*
+** iorhi3: { target msp430_region_not_lower }
+** ...
+** BISX.W &ehi2, &ehi1
+** BISX.W &lhi1, &ehi3
+** BISX.W &hi1, &ehi4
+** BISX.W &ehi5, &lhi2
+** BISX.W &ehi6, &hi2
+** BIS.W &lhi4, &lhi3
+** BISX.W &hi3, &lhi5
+** BISX.W &hi5, &hi4
+** BISX.W &lhi6, &hi6
+** ...
+*/
+void
+iorhi3 (void)
+{
+ IOR_INSN(hi)
+}
+
+/*
+** iorpsi3:
+** ...
+** BISX.A &epsi2, &epsi1
+** BISX.A &lpsi1, &epsi3
+** BISX.A &psi1, &epsi4
+** BISX.A &epsi5, &lpsi2
+** BISX.A &epsi6, &psi2
+** BISX.A &lpsi4, &lpsi3
+** BISX.A &psi3, &lpsi5
+** BISX.A &psi5, &psi4
+** BISX.A &lpsi6, &psi6
+** ...
+*/
+void
+iorpsi3 (void)
+{
+ IOR_INSN(psi)
+}
+
+/* There is no specific iorsi3 pattern defined for msp430, but we check
+ this is synthesized correctly anyway. */
+/*
+** iorsi3: { target msp430_region_lower }
+** ...
+** BISX.W &esi2, &esi1
+** BISX.W &esi2\+2, &esi1\+2
+** BISX.W &lsi1, &esi3
+** BISX.W &lsi1\+2, &esi3\+2
+** BISX.W &si1, &esi4
+** BISX.W &si1\+2, &esi4\+2
+** BISX.W &esi5, &lsi2
+** BISX.W &esi5\+2, &lsi2\+2
+** BISX.W &esi6, &si2
+** BISX.W &esi6\+2, &si2\+2
+** BIS.W &lsi4, &lsi3
+** BIS.W &lsi4\+2, &lsi3\+2
+** BIS.W &si3, &lsi5
+** BIS.W &si3\+2, &lsi5\+2
+** BIS.W &si5, &si4
+** BIS.W &si5\+2, &si4\+2
+** BIS.W &lsi6, &si6
+** BIS.W &lsi6\+2, &si6\+2
+** ...
+*/
+/*
+** iorsi3: { target msp430_region_not_lower }
+** ...
+** BISX.W &esi2, &esi1
+** BISX.W &esi2\+2, &esi1\+2
+** BISX.W &lsi1, &esi3
+** BISX.W &lsi1\+2, &esi3\+2
+** BISX.W &si1, &esi4
+** BISX.W &si1\+2, &esi4\+2
+** BISX.W &esi5, &lsi2
+** BISX.W &esi5\+2, &lsi2\+2
+** BISX.W &esi6, &si2
+** BISX.W &esi6\+2, &si2\+2
+** BIS.W &lsi4, &lsi3
+** BIS.W &lsi4\+2, &lsi3\+2
+** BISX.W &si3, &lsi5
+** BISX.W &si3\+2, &lsi5\+2
+** BISX.W &si5, &si4
+** BISX.W &si5\+2, &si4\+2
+** BISX.W &lsi6, &si6
+** BISX.W &lsi6\+2, &si6\+2
+** ...
+*/
+void
+iorsi3 (void)
+{
+ IOR_INSN(si)
+}
+
+#define XOR_INSN(MODE) \
+ E_VAR(MODE,1) ^= E_VAR(MODE,2); \
+ E_VAR(MODE,3) ^= L_VAR(MODE,1); \
+ E_VAR(MODE,4) ^= VAR(MODE,1); \
+ L_VAR(MODE,2) ^= E_VAR(MODE,5); \
+ VAR(MODE,2) ^= E_VAR(MODE,6); \
+ L_VAR(MODE,3) ^= L_VAR(MODE,4); \
+ L_VAR(MODE,5) ^= VAR(MODE,3); \
+ VAR(MODE,4) ^= VAR(MODE,5); \
+ VAR(MODE,6) ^= L_VAR(MODE,6);
+
+/*
+** xorqi3: { target msp430_region_lower }
+** ...
+** XORX.B &eqi2, &eqi1
+** XORX.B &lqi1, &eqi3
+** XORX.B &qi1, &eqi4
+** XORX.B &eqi5, &lqi2
+** XORX.B &eqi6, &qi2
+** XOR.B &lqi4, &lqi3
+** XOR.B &qi3, &lqi5
+** XOR.B &qi5, &qi4
+** XOR.B &lqi6, &qi6
+** ...
+*/
+/*
+** xorqi3: { target msp430_region_not_lower }
+** ...
+** XORX.B &eqi2, &eqi1
+** XORX.B &lqi1, &eqi3
+** XORX.B &qi1, &eqi4
+** XORX.B &eqi5, &lqi2
+** XORX.B &eqi6, &qi2
+** XOR.B &lqi4, &lqi3
+** XORX.B &qi3, &lqi5
+** XORX.B &qi5, &qi4
+** XORX.B &lqi6, &qi6
+** ...
+*/
+void
+xorqi3 (void)
+{
+ XOR_INSN(qi)
+}
+
+/*
+** xorhi3: { target msp430_region_lower }
+** ...
+** XORX.W &ehi2, &ehi1
+** XORX.W &lhi1, &ehi3
+** XORX.W &hi1, &ehi4
+** XORX.W &ehi5, &lhi2
+** XORX.W &ehi6, &hi2
+** XOR.W &lhi4, &lhi3
+** XOR.W &hi3, &lhi5
+** XOR.W &hi5, &hi4
+** XOR.W &lhi6, &hi6
+** ...
+*/
+/*
+** xorhi3: { target msp430_region_not_lower }
+** ...
+** XORX.W &ehi2, &ehi1
+** XORX.W &lhi1, &ehi3
+** XORX.W &hi1, &ehi4
+** XORX.W &ehi5, &lhi2
+** XORX.W &ehi6, &hi2
+** XOR.W &lhi4, &lhi3
+** XORX.W &hi3, &lhi5
+** XORX.W &hi5, &hi4
+** XORX.W &lhi6, &hi6
+** ...
+*/
+void
+xorhi3 (void)
+{
+ XOR_INSN(hi)
+}
+
+/*
+** xorpsi3:
+** ...
+** XORX.A &epsi2, &epsi1
+** XORX.A &lpsi1, &epsi3
+** XORX.A &psi1, &epsi4
+** XORX.A &epsi5, &lpsi2
+** XORX.A &epsi6, &psi2
+** XORX.A &lpsi4, &lpsi3
+** XORX.A &psi3, &lpsi5
+** XORX.A &psi5, &psi4
+** XORX.A &lpsi6, &psi6
+** ...
+*/
+void
+xorpsi3 (void)
+{
+ XOR_INSN(psi)
+}
+
+/* There is no specific xorsi3 pattern defined for msp430, but we check
+ this is synthesized correctly anyway. */
+/*
+** xorsi3: { target msp430_region_lower }
+** ...
+** XORX.W &esi2, &esi1
+** XORX.W &esi2\+2, &esi1\+2
+** XORX.W &lsi1, &esi3
+** XORX.W &lsi1\+2, &esi3\+2
+** XORX.W &si1, &esi4
+** XORX.W &si1\+2, &esi4\+2
+** XORX.W &esi5, &lsi2
+** XORX.W &esi5\+2, &lsi2\+2
+** XORX.W &esi6, &si2
+** XORX.W &esi6\+2, &si2\+2
+** XOR.W &lsi4, &lsi3
+** XOR.W &lsi4\+2, &lsi3\+2
+** XOR.W &si3, &lsi5
+** XOR.W &si3\+2, &lsi5\+2
+** XOR.W &si5, &si4
+** XOR.W &si5\+2, &si4\+2
+** XOR.W &lsi6, &si6
+** XOR.W &lsi6\+2, &si6\+2
+** ...
+*/
+/*
+** xorsi3: { target msp430_region_not_lower }
+** ...
+** XORX.W &esi2, &esi1
+** XORX.W &esi2\+2, &esi1\+2
+** XORX.W &lsi1, &esi3
+** XORX.W &lsi1\+2, &esi3\+2
+** XORX.W &si1, &esi4
+** XORX.W &si1\+2, &esi4\+2
+** XORX.W &esi5, &lsi2
+** XORX.W &esi5\+2, &lsi2\+2
+** XORX.W &esi6, &si2
+** XORX.W &esi6\+2, &si2\+2
+** XOR.W &lsi4, &lsi3
+** XOR.W &lsi4\+2, &lsi3\+2
+** XORX.W &si3, &lsi5
+** XORX.W &si3\+2, &lsi5\+2
+** XORX.W &si5, &si4
+** XORX.W &si5\+2, &si4\+2
+** XORX.W &lsi6, &si6
+** XORX.W &lsi6\+2, &si6\+2
+** ...
+*/
+void
+xorsi3 (void)
+{
+ XOR_INSN(si)
+}
+
+#define DO1 \
+{ \
+ qi z; \
+ z += use_qi(z); \
+ use_qi(z); \
+}
+
+#define DO2 \
+{ \
+ hi z; \
+ z += use_hi(z); \
+ use_hi(z); \
+}
+
+#define DO3 \
+{ \
+ si z; \
+ z += use_si(z); \
+ use_si(z); \
+}
+
+#define CBRANCH_INSN(MODE) \
+ if (E_VAR(MODE,1) == E_VAR(MODE,2)) \
+ DO1 \
+ else if (E_VAR(MODE,3) == L_VAR(MODE,1)) \
+ DO2 \
+ else if (E_VAR(MODE,4) == VAR(MODE,1)) \
+ DO1 \
+ else if (L_VAR(MODE,2) == E_VAR(MODE,5)) \
+ DO2 \
+ else if (VAR(MODE,2) == E_VAR(MODE,6)) \
+ DO1 \
+ else if (L_VAR(MODE,3) == L_VAR(MODE,4)) \
+ DO2 \
+ else if (L_VAR(MODE,5) == VAR(MODE,3)) \
+ DO2 \
+ else if (VAR(MODE,4) == VAR(MODE,5)) \
+ DO1 \
+ else if (VAR(MODE,6) == L_VAR(MODE,6)) \
+ DO2
+
+/*
+** cbranchqi4_real: { target msp430_region_lower }
+** ...
+** CMPX.B &eqi2, &eqi1 { JEQ .L[0-9]+
+** CMPX.B &lqi1, &eqi3 { JEQ .L[0-9]+
+** CMPX.B &qi1, &eqi4 { JEQ .L[0-9]+
+** CMPX.B &eqi5, &lqi2 { JEQ .L[0-9]+
+** CMPX.B &eqi6, &qi2 { JEQ .L[0-9]+
+** CMP.B &lqi4, &lqi3 { JEQ .L[0-9]+
+** CMP.B &qi3, &lqi5 { JEQ .L[0-9]+
+** CMP.B &qi5, &qi4 { JEQ .L[0-9]+
+** CMP.B &lqi6, &qi6 { JNE .L[0-9]+
+** ...
+*/
+/*
+** cbranchqi4_real: { target msp430_region_not_lower }
+** ...
+** CMPX.B &eqi2, &eqi1 { JEQ .L[0-9]+
+** CMPX.B &lqi1, &eqi3 { JEQ .L[0-9]+
+** CMPX.B &qi1, &eqi4 { JEQ .L[0-9]+
+** CMPX.B &eqi5, &lqi2 { JEQ .L[0-9]+
+** CMPX.B &eqi6, &qi2 { JEQ .L[0-9]+
+** CMP.B &lqi4, &lqi3 { JEQ .L[0-9]+
+** CMPX.B &qi3, &lqi5 { JEQ .L[0-9]+
+** CMPX.B &qi5, &qi4 { JEQ .L[0-9]+
+** CMPX.B &lqi6, &qi6 { JNE .L[0-9]+
+** ...
+*/
+void
+cbranchqi4_real (void)
+{
+ CBRANCH_INSN(qi)
+}
+
+/*
+** cbranchhi4_real: { target msp430_region_lower }
+** ...
+** CMPX.W &ehi2, &ehi1 { JEQ .L[0-9]+
+** CMPX.W &lhi1, &ehi3 { JEQ .L[0-9]+
+** CMPX.W &hi1, &ehi4 { JEQ .L[0-9]+
+** CMPX.W &ehi5, &lhi2 { JEQ .L[0-9]+
+** CMPX.W &ehi6, &hi2 { JEQ .L[0-9]+
+** CMP.W &lhi4, &lhi3 { JEQ .L[0-9]+
+** CMP.W &hi3, &lhi5 { JEQ .L[0-9]+
+** CMP.W &hi5, &hi4 { JEQ .L[0-9]+
+** CMP.W &lhi6, &hi6 { JNE .L[0-9]+
+** ...
+*/
+/*
+** cbranchhi4_real: { target msp430_region_not_lower }
+** ...
+** CMPX.W &ehi2, &ehi1 { JEQ .L[0-9]+
+** CMPX.W &lhi1, &ehi3 { JEQ .L[0-9]+
+** CMPX.W &hi1, &ehi4 { JEQ .L[0-9]+
+** CMPX.W &ehi5, &lhi2 { JEQ .L[0-9]+
+** CMPX.W &ehi6, &hi2 { JEQ .L[0-9]+
+** CMP.W &lhi4, &lhi3 { JEQ .L[0-9]+
+** CMPX.W &hi3, &lhi5 { JEQ .L[0-9]+
+** CMPX.W &hi5, &hi4 { JEQ .L[0-9]+
+** CMPX.W &lhi6, &hi6 { JNE .L[0-9]+
+** ...
+*/
+void
+cbranchhi4_real (void)
+{
+ CBRANCH_INSN(hi)
+}
+
+/* There is no specific cbranchsi4_real pattern defined for msp430, but we
+ check this is synthesized correctly anyway. */
+/*
+** cbranchsi4_real: { target msp430_region_lower }
+** ...
+** CMPX.W &esi2, &esi1 { JEQ .L[0-9]+
+** CMPX.W &lsi1, &esi3 { JEQ .L[0-9]+
+** CMPX.W &si1, &esi4 { JEQ .L[0-9]+
+** CMPX.W &esi5, &lsi2 { JEQ .L[0-9]+
+** CMPX.W &esi6, &si2 { JEQ .L[0-9]+
+** CMP.W &lsi4, &lsi3 { JEQ .L[0-9]+
+** CMP.W &si3, &lsi5 { JEQ .L[0-9]+
+** CMP.W &si5, &si4 { JEQ .L[0-9]+
+** CMP.W &lsi6, &si6 { JNE .L[0-9]+
+** CMP.W &lsi6\+2, &si6\+2 { JNE .L[0-9]+
+** ...
+** CMPX.W &esi2\+2, &esi1\+2 { JNE .L[0-9]+
+** ...
+** CMPX.W &lsi1\+2, &esi3\+2 { JNE .L[0-9]+
+** ...
+** CMPX.W &si1\+2, &esi4\+2 { JNE .L[0-9]+
+** ...
+** CMPX.W &esi5\+2, &lsi2\+2 { JNE .L[0-9]+
+** ...
+** CMPX.W &esi6\+2, &si2\+2 { JNE .L[0-9]+
+** ...
+** CMP.W &lsi4\+2, &lsi3\+2 { JNE .L[0-9]+
+** ...
+** CMP.W &si3\+2, &lsi5\+2 { JNE .L[0-9]+
+** ...
+** CMP.W &si5\+2, &si4\+2 { JNE .L[0-9]+
+** ...
+*/
+/*
+** cbranchsi4_real: { target msp430_region_not_lower }
+** ...
+** CMPX.W &esi2, &esi1 { JEQ .L[0-9]+
+** CMPX.W &lsi1, &esi3 { JEQ .L[0-9]+
+** CMPX.W &si1, &esi4 { JEQ .L[0-9]+
+** CMPX.W &esi5, &lsi2 { JEQ .L[0-9]+
+** CMPX.W &esi6, &si2 { JEQ .L[0-9]+
+** CMP.W &lsi4, &lsi3 { JEQ .L[0-9]+
+** CMPX.W &si3, &lsi5 { JEQ .L[0-9]+
+** CMPX.W &si5, &si4 { JEQ .L[0-9]+
+** CMPX.W &lsi6, &si6 { JNE .L[0-9]+
+** CMPX.W &lsi6\+2, &si6\+2 { JNE .L[0-9]+
+** ...
+** CMPX.W &esi2\+2, &esi1\+2 { JNE .L[0-9]+
+** ...
+** CMPX.W &lsi1\+2, &esi3\+2 { JNE .L[0-9]+
+** ...
+** CMPX.W &si1\+2, &esi4\+2 { JNE .L[0-9]+
+** ...
+** CMPX.W &esi5\+2, &lsi2\+2 { JNE .L[0-9]+
+** ...
+** CMPX.W &esi6\+2, &si2\+2 { JNE .L[0-9]+
+** ...
+** CMP.W &lsi4\+2, &lsi3\+2 { JNE .L[0-9]+
+** ...
+** CMPX.W &si3\+2, &lsi5\+2 { JNE .L[0-9]+
+** ...
+** CMPX.W &si5\+2, &si4\+2 { JNE .L[0-9]+
+** ...
+*/
+void
+cbranchsi4_real (void)
+{
+ CBRANCH_INSN(si)
+}
+
+#define CBRANCH_REVERSE_INSN(MODE) \
+ if (E_VAR(MODE,1) > E_VAR(MODE,2)) \
+ DO1 \
+ else if (E_VAR(MODE,3) > L_VAR(MODE,1)) \
+ DO2 \
+ else if (E_VAR(MODE,4) > VAR(MODE,1)) \
+ DO1 \
+ else if (L_VAR(MODE,2) > E_VAR(MODE,5)) \
+ DO2 \
+ else if (VAR(MODE,2) > E_VAR(MODE,6)) \
+ DO1 \
+ else if (L_VAR(MODE,3) > L_VAR(MODE,4)) \
+ DO2 \
+ else if (L_VAR(MODE,5) > VAR(MODE,3)) \
+ DO2 \
+ else if (VAR(MODE,4) > VAR(MODE,5)) \
+ DO1 \
+ else if (VAR(MODE,6) > L_VAR(MODE,6)) \
+ DO2
+
+/*
+** cbranchqi4_reversed: { target msp430_region_lower }
+** ...
+** CMPX.B &eqi1, &eqi2 { JLO .L[0-9]+
+** CMPX.B &eqi3, &lqi1 { JLO .L[0-9]+
+** CMPX.B &eqi4, &qi1 { JLO .L[0-9]+
+** CMPX.B &lqi2, &eqi5 { JLO .L[0-9]+
+** CMPX.B &qi2, &eqi6 { JLO .L[0-9]+
+** CMP.B &lqi3, &lqi4 { JLO .L[0-9]+
+** CMP.B &lqi5, &qi3 { JLO .L[0-9]+
+** CMP.B &qi4, &qi5 { JLO .L[0-9]+
+** CMP.B &qi6, &lqi6 { JHS .L[0-9]+
+** ...
+*/
+/*
+** cbranchqi4_reversed: { target msp430_region_not_lower }
+** ...
+** CMPX.B &eqi1, &eqi2 { JLO .L[0-9]+
+** CMPX.B &eqi3, &lqi1 { JLO .L[0-9]+
+** CMPX.B &eqi4, &qi1 { JLO .L[0-9]+
+** CMPX.B &lqi2, &eqi5 { JLO .L[0-9]+
+** CMPX.B &qi2, &eqi6 { JLO .L[0-9]+
+** CMP.B &lqi3, &lqi4 { JLO .L[0-9]+
+** CMPX.B &lqi5, &qi3 { JLO .L[0-9]+
+** CMPX.B &qi4, &qi5 { JLO .L[0-9]+
+** CMPX.B &qi6, &lqi6 { JHS .L[0-9]+
+** ...
+*/
+void
+cbranchqi4_reversed (void)
+{
+ CBRANCH_REVERSE_INSN(qi)
+}
+
+/*
+** cbranchhi4_reversed: { target msp430_region_lower }
+** ...
+** CMPX.W &ehi1, &ehi2 { JL .L[0-9]+
+** CMPX.W &ehi3, &lhi1 { JL .L[0-9]+
+** CMPX.W &ehi4, &hi1 { JL .L[0-9]+
+** CMPX.W &lhi2, &ehi5 { JL .L[0-9]+
+** CMPX.W &hi2, &ehi6 { JL .L[0-9]+
+** CMP.W &lhi3, &lhi4 { JL .L[0-9]+
+** CMP.W &lhi5, &hi3 { JL .L[0-9]+
+** CMP.W &hi4, &hi5 { JL .L[0-9]+
+** CMP.W &hi6, &lhi6 { JGE .L[0-9]+
+** ...
+*/
+/*
+** cbranchhi4_reversed: { target msp430_region_not_lower }
+** ...
+** CMPX.W &ehi1, &ehi2 { JL .L[0-9]+
+** CMPX.W &ehi3, &lhi1 { JL .L[0-9]+
+** CMPX.W &ehi4, &hi1 { JL .L[0-9]+
+** CMPX.W &lhi2, &ehi5 { JL .L[0-9]+
+** CMPX.W &hi2, &ehi6 { JL .L[0-9]+
+** CMP.W &lhi3, &lhi4 { JL .L[0-9]+
+** CMPX.W &lhi5, &hi3 { JL .L[0-9]+
+** CMPX.W &hi4, &hi5 { JL .L[0-9]+
+** CMPX.W &hi6, &lhi6 { JGE .L[0-9]+
+** ...
+*/
+void
+cbranchhi4_reversed (void)
+{
+ CBRANCH_REVERSE_INSN(hi)
+}
+
+/* There is no specific cbranchsi4_reversed pattern defined for msp430, but
+ we check this is synthesized correctly anyway.
+ This output assembly for this one is quite long and convoluted so we only
+ check part of it. */
+/*
+** cbranchsi4_reversed: { target msp430_region_lower }
+** ...
+** CMPX.W &esi1\+2, &esi2\+2 { JL .L[0-9]+
+** CMPX.W &esi2\+2, &esi1\+2 { JEQ .L[0-9]+
+** CMPX.W &esi3\+2, &lsi1\+2 { JL .L[0-9]+
+** CMPX.W &lsi1\+2, &esi3\+2 { JEQ .L[0-9]+
+** CMPX.W &esi4\+2, &si1\+2 { JL .L[0-9]+
+** CMPX.W &si1\+2, &esi4\+2 { JEQ .L[0-9]+
+** CMPX.W &lsi2\+2, &esi5\+2 { JL .L[0-9]+
+** CMPX.W &esi5\+2, &lsi2\+2 { JEQ .L[0-9]+
+** CMPX.W &si2\+2, &esi6\+2 { JL .L[0-9]+
+** CMPX.W &esi6\+2, &si2\+2 { JEQ .L[0-9]+
+** CMP.W &lsi3\+2, &lsi4\+2 { JL .L[0-9]+
+** CMP.W &lsi4\+2, &lsi3\+2 { JEQ .L[0-9]+
+** CMP.W &lsi5\+2, &si3\+2 { JL .L[0-9]+
+** CMP.W &si3\+2, &lsi5\+2 { JEQ .L[0-9]+
+** CMP.W &si4\+2, &si5\+2 { JL .L[0-9]+
+** CMP.W &si5\+2, &si4\+2 { JEQ .L[0-9]+
+** CMP.W &si6\+2, &lsi6\+2 { JL .L[0-9]+
+** CMP.W &lsi6\+2, &si6\+2 { JNE .L[0-9]+
+** ...
+*/
+/*
+** cbranchsi4_reversed: { target msp430_region_not_lower }
+** ...
+** CMPX.W &esi1\+2, &esi2\+2 { JL .L[0-9]+
+** CMPX.W &esi2\+2, &esi1\+2 { JEQ .L[0-9]+
+** CMPX.W &esi3\+2, &lsi1\+2 { JL .L[0-9]+
+** CMPX.W &lsi1\+2, &esi3\+2 { JEQ .L[0-9]+
+** CMPX.W &esi4\+2, &si1\+2 { JL .L[0-9]+
+** CMPX.W &si1\+2, &esi4\+2 { JEQ .L[0-9]+
+** CMPX.W &lsi2\+2, &esi5\+2 { JL .L[0-9]+
+** CMPX.W &esi5\+2, &lsi2\+2 { JEQ .L[0-9]+
+** CMPX.W &si2\+2, &esi6\+2 { JL .L[0-9]+
+** CMPX.W &esi6\+2, &si2\+2 { JEQ .L[0-9]+
+** CMP.W &lsi3\+2, &lsi4\+2 { JL .L[0-9]+
+** CMP.W &lsi4\+2, &lsi3\+2 { JEQ .L[0-9]+
+** CMPX.W &lsi5\+2, &si3\+2 { JL .L[0-9]+
+** CMPX.W &si3\+2, &lsi5\+2 { JEQ .L[0-9]+
+** CMPX.W &si4\+2, &si5\+2 { JL .L[0-9]+
+** CMPX.W &si5\+2, &si4\+2 { JEQ .L[0-9]+
+** CMPX.W &si6\+2, &lsi6\+2 { JL .L[0-9]+
+** CMPX.W &lsi6\+2, &si6\+2 { JNE .L[0-9]+
+** ...
+*/
+void
+cbranchsi4_reversed (void)
+{
+ CBRANCH_REVERSE_INSN(si)
+}
+
+#define BITBRANCH_NE_INSN(MODE) \
+ if (E_VAR(MODE,1) & E_VAR(MODE,2)) \
+ DO1 \
+ else if (E_VAR(MODE,3) & L_VAR(MODE,1)) \
+ DO2 \
+ else if (E_VAR(MODE,4) & VAR(MODE,1)) \
+ DO1 \
+ else if (L_VAR(MODE,2) & E_VAR(MODE,5)) \
+ DO2 \
+ else if (VAR(MODE,2) & E_VAR(MODE,6)) \
+ DO1 \
+ else if (L_VAR(MODE,3) & L_VAR(MODE,4)) \
+ DO2 \
+ else if (L_VAR(MODE,5) & VAR(MODE,3)) \
+ DO2 \
+ else if (VAR(MODE,4) & VAR(MODE,5)) \
+ DO1 \
+ else if (VAR(MODE,6) & L_VAR(MODE,6)) \
+ DO2
+/*
+** bitbranchqi4: { target msp430_region_lower }
+** ...
+** BITX.B &eqi2, &eqi1 { JNE .L[0-9]+
+** BITX.B &lqi1, &eqi3 { JNE .L[0-9]+
+** BITX.B &qi1, &eqi4 { JNE .L[0-9]+
+** BITX.B &eqi5, &lqi2 { JNE .L[0-9]+
+** BITX.B &eqi6, &qi2 { JNE .L[0-9]+
+** BIT.B &lqi4, &lqi3 { JNE .L[0-9]+
+** BIT.B &qi3, &lqi5 { JNE .L[0-9]+
+** BIT.B &qi5, &qi4 { JNE .L[0-9]+
+** BIT.B &lqi6, &qi6 { JEQ .L[0-9]+
+** ...
+*/
+/*
+** bitbranchqi4: { target msp430_region_not_lower }
+** ...
+** BITX.B &eqi2, &eqi1 { JNE .L[0-9]+
+** BITX.B &lqi1, &eqi3 { JNE .L[0-9]+
+** BITX.B &qi1, &eqi4 { JNE .L[0-9]+
+** BITX.B &eqi5, &lqi2 { JNE .L[0-9]+
+** BITX.B &eqi6, &qi2 { JNE .L[0-9]+
+** BIT.B &lqi4, &lqi3 { JNE .L[0-9]+
+** BITX.B &qi3, &lqi5 { JNE .L[0-9]+
+** BITX.B &qi5, &qi4 { JNE .L[0-9]+
+** BITX.B &lqi6, &qi6 { JEQ .L[0-9]+
+** ...
+*/
+void
+bitbranchqi4 (void)
+{
+ BITBRANCH_NE_INSN(qi)
+}
+
+/*
+** bitbranchhi4: { target msp430_region_lower }
+** ...
+** BITX.W &ehi2, &ehi1 { JNE .L[0-9]+
+** BITX.W &lhi1, &ehi3 { JNE .L[0-9]+
+** BITX.W &hi1, &ehi4 { JNE .L[0-9]+
+** BITX.W &ehi5, &lhi2 { JNE .L[0-9]+
+** BITX.W &ehi6, &hi2 { JNE .L[0-9]+
+** BIT.W &lhi4, &lhi3 { JNE .L[0-9]+
+** BIT.W &hi3, &lhi5 { JNE .L[0-9]+
+** BIT.W &hi5, &hi4 { JNE .L[0-9]+
+** BIT.W &lhi6, &hi6 { JEQ .L[0-9]+
+** ...
+*/
+/*
+** bitbranchhi4: { target msp430_region_not_lower }
+** ...
+** BITX.W &ehi2, &ehi1 { JNE .L[0-9]+
+** BITX.W &lhi1, &ehi3 { JNE .L[0-9]+
+** BITX.W &hi1, &ehi4 { JNE .L[0-9]+
+** BITX.W &ehi5, &lhi2 { JNE .L[0-9]+
+** BITX.W &ehi6, &hi2 { JNE .L[0-9]+
+** BIT.W &lhi4, &lhi3 { JNE .L[0-9]+
+** BITX.W &hi3, &lhi5 { JNE .L[0-9]+
+** BITX.W &hi5, &hi4 { JNE .L[0-9]+
+** BITX.W &lhi6, &hi6 { JEQ .L[0-9]+
+** ...
+*/
+void
+bitbranchhi4 (void)
+{
+ BITBRANCH_NE_INSN(hi)
+}
+
+/*
+** bitbranchpsi4:
+** ...
+** BITX.A &epsi2, &epsi1 { JNE .L[0-9]+
+** BITX.A &lpsi1, &epsi3 { JNE .L[0-9]+
+** BITX.A &psi1, &epsi4 { JNE .L[0-9]+
+** BITX.A &epsi5, &lpsi2 { JNE .L[0-9]+
+** BITX.A &epsi6, &psi2 { JNE .L[0-9]+
+** BITX.A &lpsi4, &lpsi3 { JNE .L[0-9]+
+** BITX.A &psi3, &lpsi5 { JNE .L[0-9]+
+** BITX.A &psi5, &psi4 { JNE .L[0-9]+
+** BITX.A &lpsi6, &psi6 { JEQ .L[0-9]+
+** ...
+*/
+void
+bitbranchpsi4 (void)
+{
+ BITBRANCH_NE_INSN(psi)
+}
+
+
+/* "bitbranch" using SImode operands is omitted since the resulting assembly
+ uses many temporary registers to perform the bitwise and comparison
+ operations. */
diff --git a/gcc/testsuite/gcc.target/msp430/data-attributes-2.c b/gcc/testsuite/gcc.target/msp430/data-attributes-2.c
index d049194425d..6113e99f052 100644
--- a/gcc/testsuite/gcc.target/msp430/data-attributes-2.c
+++ b/gcc/testsuite/gcc.target/msp430/data-attributes-2.c
@@ -27,7 +27,7 @@ int __attribute__((lower,upper)) lu = 20; /* { dg-warning "ignoring attribute 'u
int __attribute__((lower,either)) le = 20; /* { dg-warning "ignoring attribute 'either' because it conflicts with attribute 'lower'" } */
int __attribute__((lower,persistent)) lp = 20; /* { dg-warning "ignoring attribute 'persistent' because it conflicts with attribute 'lower'" } */
int __attribute__((lower,noinit)) ln; /* { dg-warning "ignoring attribute 'noinit' because it conflicts with attribute 'lower'" } */
-int __attribute__((lower,section(".data.foo"))) ls = 30; /* { dg-warning "ignoring attribute 'section' because it conflicts with attribute 'lower'" } */
+int __attribute__((lower,section(".data.foo"))) ls = 30;
int __attribute__((upper)) u = 20;
int __attribute__((upper,lower)) ul = 20; /* { dg-warning "ignoring attribute 'lower' because it conflicts with attribute 'upper'" } */
@@ -46,6 +46,6 @@ int __attribute__((either,section(".data.foo"))) es = 30; /* { dg-warning "ignor
int __attribute__((section(".data.foo"))) s = 20;
int __attribute__((section(".data.foo"),noinit)) sn; /* { dg-warning "ignoring attribute 'noinit' because it conflicts with attribute 'section'" } */
int __attribute__((section(".data.foo"),persistent)) sp = 20; /* { dg-warning "ignoring attribute 'persistent' because it conflicts with attribute 'section'" } */
-int __attribute__((section(".data.foo"),lower)) sl = 2; /* { dg-warning "ignoring attribute 'lower' because it conflicts with attribute 'section'" } */
+int __attribute__((section(".data.foo"),lower)) sl = 2;
int __attribute__((section(".data.foo"),upper)) su = 20; /* { dg-warning "ignoring attribute 'upper' because it conflicts with attribute 'section'" } */
int __attribute__((section(".data.foo"),either)) se = 2; /* { dg-warning "ignoring attribute 'either' because it conflicts with attribute 'section'" } */
diff --git a/gcc/testsuite/gcc.target/msp430/msp430.exp b/gcc/testsuite/gcc.target/msp430/msp430.exp
index b97f4dcdc16..bcc56861abc 100644
--- a/gcc/testsuite/gcc.target/msp430/msp430.exp
+++ b/gcc/testsuite/gcc.target/msp430/msp430.exp
@@ -36,6 +36,14 @@ proc check_effective_target_msp430_mlarge_selected { } {
return [check-flags [list "" { *-*-* } { "-mlarge" } { "" } ]]
}
+proc check_effective_target_msp430_region_not_lower { } {
+ return [check-flags [list "" { *-*-* } { "-mdata-region=none" "-mdata-region=upper" "-mdata-region=either" } { "" } ]]
+}
+
+proc check_effective_target_msp430_region_lower { } {
+ return [check-flags [list "" { *-*-* } { "*" } { "-mdata-region=none" "-mdata-region=upper" "-mdata-region=either" } ]]
+}
+
proc check_effective_target_msp430_hwmul_not_none { } {
return [check-flags [list "" { *-*-* } \
{ "-mhwmult=16bit" "-mhwmult=32bit" "-mhwmult=f5series" } { "" } ]]
diff --git a/gcc/testsuite/gcc.target/msp430/object-attributes-430.c b/gcc/testsuite/gcc.target/msp430/object-attributes-430.c
new file mode 100644
index 00000000000..4296be22edb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/msp430/object-attributes-430.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-mcpu=msp430x" "-mlarge" } { "" } } */
+/* { dg-options "-mcpu=msp430" } */
+/* { dg-final { scan-assembler ".mspabi_attribute 4, 1" } } */
+/* { dg-final { scan-assembler ".mspabi_attribute 6, 1" } } */
+/* { dg-final { scan-assembler ".mspabi_attribute 8, 1" } } */
+/* { dg-final { scan-assembler ".gnu_attribute 4, 1" } } */
+
+int
+main (void)
+{
+ while (1);
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/msp430/object-attributes-default.c b/gcc/testsuite/gcc.target/msp430/object-attributes-default.c
new file mode 100644
index 00000000000..39c1f3eab44
--- /dev/null
+++ b/gcc/testsuite/gcc.target/msp430/object-attributes-default.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-final { scan-assembler ".mspabi_attribute 4, 1" { target msp430_430_selected } } } */
+/* { dg-final { scan-assembler ".mspabi_attribute 4, 2" { target msp430_430x_selected } } } */
+/* { dg-final { scan-assembler ".mspabi_attribute 6, 1" { target { ! msp430_mlarge_selected } } } } */
+/* { dg-final { scan-assembler ".mspabi_attribute 8, 1" { target { ! msp430_mlarge_selected } } } } */
+/* { dg-final { scan-assembler ".mspabi_attribute 6, 2" { target msp430_mlarge_selected } } } */
+/* { dg-final { scan-assembler ".mspabi_attribute 8, 2" { target msp430_mlarge_selected } } } */
+/* { dg-final { scan-assembler ".gnu_attribute 4, 1" { target { ! msp430_region_not_lower } } } } */
+/* { dg-final { scan-assembler ".gnu_attribute 4, 2" { target msp430_region_not_lower } } } */
+
+int
+main (void)
+{
+ while (1);
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/msp430/object-attributes-mlarge-any-region.c b/gcc/testsuite/gcc.target/msp430/object-attributes-mlarge-any-region.c
new file mode 100644
index 00000000000..2aa8bfb3663
--- /dev/null
+++ b/gcc/testsuite/gcc.target/msp430/object-attributes-mlarge-any-region.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-mcpu=msp430" "-mdata-region=lower" } { "" } } */
+/* { dg-options "-mlarge -mdata-region=none" } */
+/* { dg-final { scan-assembler ".mspabi_attribute 4, 2" } } */
+/* { dg-final { scan-assembler ".mspabi_attribute 6, 2" } } */
+/* { dg-final { scan-assembler ".mspabi_attribute 8, 2" } } */
+/* { dg-final { scan-assembler ".gnu_attribute 4, 2" } } */
+
+int
+main (void)
+{
+ while (1);
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/msp430/object-attributes-mlarge.c b/gcc/testsuite/gcc.target/msp430/object-attributes-mlarge.c
new file mode 100644
index 00000000000..06738ea795a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/msp430/object-attributes-mlarge.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-mcpu=msp430" } { "" } } */
+/* { dg-options "-mlarge" } */
+/* { dg-final { scan-assembler ".mspabi_attribute 4, 2" } } */
+/* { dg-final { scan-assembler ".mspabi_attribute 6, 2" } } */
+/* { dg-final { scan-assembler ".mspabi_attribute 8, 2" } } */
+/* { dg-final { scan-assembler ".gnu_attribute 4, 1" { target msp430_region_lower } } } */
+/* { dg-final { scan-assembler ".gnu_attribute 4, 2" { target { ! msp430_region_lower } } } } */
+
+int
+main (void)
+{
+ while (1);
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/s390/s390.exp b/gcc/testsuite/gcc.target/s390/s390.exp
index 86f7e4398eb..925eb568832 100644
--- a/gcc/testsuite/gcc.target/s390/s390.exp
+++ b/gcc/testsuite/gcc.target/s390/s390.exp
@@ -27,6 +27,7 @@ if ![istarget s390*-*-*] then {
# Load support procs.
load_lib gcc-dg.exp
load_lib target-supports.exp
+load_lib gfortran-dg.exp
# Return 1 if the the assembler understands .machine and .machinemode. The
# target attribute needs that feature to work.
@@ -193,6 +194,10 @@ global DEFAULT_CFLAGS
if ![info exists DEFAULT_CFLAGS] then {
set DEFAULT_CFLAGS " -ansi -pedantic-errors"
}
+global DEFAULT_FFLAGS
+if ![info exists DEFAULT_FFLAGS] then {
+ set DEFAULT_FFLAGS " -pedantic-errors"
+}
# Initialize `dg'.
dg-init
@@ -209,6 +214,9 @@ dg-runtest [lsort [prune [glob -nocomplain $srcdir/$subdir/*.{c,S}] \
dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*vector*/*.{c,S}]] \
"" $DEFAULT_CFLAGS
+gfortran-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*vector*/*.F90]] \
+ "" $DEFAULT_FFLAGS
+
dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/target-attribute/*.{c,S}]] \
"" $DEFAULT_CFLAGS
diff --git a/gcc/testsuite/gcc.target/s390/vector/vec-scalar-cmp-1.c b/gcc/testsuite/gcc.target/s390/vector/vec-scalar-cmp-1.c
index ea51d0c86af..073d574aa5e 100644
--- a/gcc/testsuite/gcc.target/s390/vector/vec-scalar-cmp-1.c
+++ b/gcc/testsuite/gcc.target/s390/vector/vec-scalar-cmp-1.c
@@ -34,7 +34,7 @@ gt (double a, double b)
return a > b;
}
-/* { dg-final { scan-assembler "gt:\n\[^:\]*\twfcdb\t%v\[0-9\]*,%v\[0-9\]*\n\t\[^:\]+\tlochinh\t%r2,0" } } */
+/* { dg-final { scan-assembler "gt:\n\[^:\]*\twfkdb\t%v\[0-9\]*,%v\[0-9\]*\n\t\[^:\]+\tlochinh\t%r2,0" } } */
int
ge (double a, double b)
@@ -45,7 +45,7 @@ ge (double a, double b)
return a >= b;
}
-/* { dg-final { scan-assembler "ge:\n\[^:\]*\twfcdb\t%v\[0-9\]*,%v\[0-9\]*\n\t\[^:\]+\tlochinhe\t%r2,0" } } */
+/* { dg-final { scan-assembler "ge:\n\[^:\]*\twfkdb\t%v\[0-9\]*,%v\[0-9\]*\n\t\[^:\]+\tlochinhe\t%r2,0" } } */
int
lt (double a, double b)
@@ -56,7 +56,7 @@ lt (double a, double b)
return a < b;
}
-/* { dg-final { scan-assembler "lt:\n\[^:\]*\twfcdb\t%v\[0-9\]*,%v\[0-9\]*\n\t\[^:\]+\tlochinl\t%r2,0" } } */
+/* { dg-final { scan-assembler "lt:\n\[^:\]*\twfkdb\t%v\[0-9\]*,%v\[0-9\]*\n\t\[^:\]+\tlochinl\t%r2,0" } } */
int
le (double a, double b)
@@ -67,4 +67,4 @@ le (double a, double b)
return a <= b;
}
-/* { dg-final { scan-assembler "le:\n\[^:\]*\twfcdb\t%v\[0-9\]*,%v\[0-9\]*\n\t\[^:\]+\tlochinle\t%r2,0" } } */
+/* { dg-final { scan-assembler "le:\n\[^:\]*\twfkdb\t%v\[0-9\]*,%v\[0-9\]*\n\t\[^:\]+\tlochinle\t%r2,0" } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-double-quiet-eq.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-quiet-eq.c
new file mode 100644
index 00000000000..46bef83cfa3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-quiet-eq.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z13 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_DOUBLE (QUIET_EQ);
+
+/* { dg-final { scan-assembler {\n\tvfcedb\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-double-quiet-ge.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-quiet-ge.c
new file mode 100644
index 00000000000..4dbbd8f6728
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-quiet-ge.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z13 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_DOUBLE (QUIET_GE);
+
+/* { dg-final { scan-assembler {\n\tvfchedb\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-double-quiet-gt.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-quiet-gt.c
new file mode 100644
index 00000000000..57f7cefb578
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-quiet-gt.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z13 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_DOUBLE (QUIET_GT);
+
+/* { dg-final { scan-assembler {\n\tvfchdb\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-double-quiet-le.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-quiet-le.c
new file mode 100644
index 00000000000..3de425ca760
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-quiet-le.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z13 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_DOUBLE (QUIET_LE);
+
+/* { dg-final { scan-assembler {\n\tvfchedb\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-double-quiet-lt.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-quiet-lt.c
new file mode 100644
index 00000000000..0817846944d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-quiet-lt.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z13 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_DOUBLE (QUIET_LT);
+
+/* { dg-final { scan-assembler {\n\tvfchdb\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-double-quiet-ordered.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-quiet-ordered.c
new file mode 100644
index 00000000000..65b0240073c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-quiet-ordered.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z13 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_DOUBLE (QUIET_ORDERED);
+
+/* { dg-final { scan-assembler {\n\tvfchedb\t} } } */
+/* { dg-final { scan-assembler {\n\tvfchdb\t} } } */
+/* { dg-final { scan-assembler {\n\tvo\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-double-quiet-uneq.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-quiet-uneq.c
new file mode 100644
index 00000000000..3d6da30beac
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-quiet-uneq.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z13 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_DOUBLE (QUIET_UNEQ);
+
+/* { dg-final { scan-assembler-times {\n\tvfchdb\t} 2 } } */
+/* { dg-final { scan-assembler {\n\tvo\t} } } */
+/* { dg-final { scan-assembler {\n\tvx\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-double-quiet-unordered.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-quiet-unordered.c
new file mode 100644
index 00000000000..1f6fb781f64
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-quiet-unordered.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z13 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_DOUBLE (QUIET_UNORDERED);
+
+/* { dg-final { scan-assembler {\n\tvfchedb\t} } } */
+/* { dg-final { scan-assembler {\n\tvfchdb\t} } } */
+/* combine prefers to reorder vsel args instead of using vno. */
+/* { dg-final { scan-assembler {\n\tvo\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-eq-z13-finite.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-eq-z13-finite.c
new file mode 100644
index 00000000000..461ff8d7024
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-eq-z13-finite.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z13 -mzvector -ffinite-math-only -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_DOUBLE (SIGNALING_EQ);
+
+/* We can use non-signaling vector comparison instructions with
+ -ffinite-math-only. */
+/* { dg-final { scan-assembler {\n\tvfcedb\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-eq-z13.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-eq-z13.c
new file mode 100644
index 00000000000..1806fa8c60e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-eq-z13.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z13 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_DOUBLE (SIGNALING_EQ);
+
+/* z13 does not have signaling vector comparison instructions. */
+/* { dg-final { scan-assembler {\n\tkdbr\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-eq.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-eq.c
new file mode 100644
index 00000000000..a8402b9f705
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-eq.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z14 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_DOUBLE (SIGNALING_EQ);
+
+/* The vectorizer produces <= and ==, which rtl passes cannot turn into vfkedb
+ yet. */
+/* { dg-final { scan-assembler {\n\tvfcedb\t} } } */
+/* { dg-final { scan-assembler {\n\tvfkhedb\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-ge-z13-finite.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-ge-z13-finite.c
new file mode 100644
index 00000000000..518f5d7a645
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-ge-z13-finite.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z13 -mzvector -ffinite-math-only -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_DOUBLE (SIGNALING_GE);
+
+/* We can use non-signaling vector comparison instructions with
+ -ffinite-math-only. */
+/* { dg-final { scan-assembler {\n\tvfchedb\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-ge-z13.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-ge-z13.c
new file mode 100644
index 00000000000..1e1737fd269
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-ge-z13.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z13 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_DOUBLE (SIGNALING_GE);
+
+/* z13 does not have signaling vector comparison instructions. */
+/* { dg-final { scan-assembler {\n\tkdb\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-ge.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-ge.c
new file mode 100644
index 00000000000..49172f55ac9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-ge.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z14 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_DOUBLE (SIGNALING_GE);
+
+/* { dg-final { scan-assembler {\n\tvfkhedb\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-gt-z13-finite.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-gt-z13-finite.c
new file mode 100644
index 00000000000..cf54adabed7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-gt-z13-finite.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z13 -mzvector -ffinite-math-only -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_DOUBLE (SIGNALING_GT);
+
+/* We can use non-signaling vector comparison instructions with
+ -ffinite-math-only. */
+/* { dg-final { scan-assembler {\n\tvfchdb\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-gt-z13.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-gt-z13.c
new file mode 100644
index 00000000000..8a9e03af1a4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-gt-z13.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z13 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_DOUBLE (SIGNALING_GT);
+
+/* z13 does not have signaling vector comparison instructions. */
+/* { dg-final { scan-assembler {\n\tkdb\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-gt.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-gt.c
new file mode 100644
index 00000000000..af62e1fd005
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-gt.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z14 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_DOUBLE (SIGNALING_GT);
+
+/* { dg-final { scan-assembler {\n\tvfkhdb\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-le-z13-finite.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-le-z13-finite.c
new file mode 100644
index 00000000000..100366e8f1a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-le-z13-finite.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z13 -mzvector -ffinite-math-only -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_DOUBLE (SIGNALING_LE);
+
+/* We can use non-signaling vector comparison instructions with
+ -ffinite-math-only. */
+/* { dg-final { scan-assembler {\n\tvfchedb\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-le-z13.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-le-z13.c
new file mode 100644
index 00000000000..c0714efc1d9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-le-z13.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z13 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_DOUBLE (SIGNALING_LE);
+
+/* z13 does not have signaling vector comparison instructions. */
+/* { dg-final { scan-assembler {\n\tkdb\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-le.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-le.c
new file mode 100644
index 00000000000..33266d41681
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-le.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z14 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_DOUBLE (SIGNALING_LE);
+
+/* { dg-final { scan-assembler {\n\tvfkhedb\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-lt-z13-finite.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-lt-z13-finite.c
new file mode 100644
index 00000000000..f587364af09
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-lt-z13-finite.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z13 -mzvector -ffinite-math-only -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_DOUBLE (SIGNALING_LT);
+
+/* We can use non-signaling vector comparison instructions with
+ -ffinite-math-only. */
+/* { dg-final { scan-assembler {\n\tvfchdb\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-lt-z13.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-lt-z13.c
new file mode 100644
index 00000000000..18e81be845b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-lt-z13.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z13 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_DOUBLE (SIGNALING_LT);
+
+/* z13 does not have signaling vector comparison instructions. */
+/* { dg-final { scan-assembler {\n\tkdb\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-lt.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-lt.c
new file mode 100644
index 00000000000..1ceea1bdbc6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-lt.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z14 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_DOUBLE (SIGNALING_LT);
+
+/* { dg-final { scan-assembler {\n\tvfkhdb\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-ltgt-z13-finite.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-ltgt-z13-finite.c
new file mode 100644
index 00000000000..8ee3cce5e95
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-ltgt-z13-finite.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z13 -mzvector -ffinite-math-only -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_DOUBLE (SIGNALING_LTGT);
+
+/* ltgt is the same as eq with -ffinite-math-only. */
+/* { dg-final { scan-assembler {\n\tvfcedb\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-ltgt-z13.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-ltgt-z13.c
new file mode 100644
index 00000000000..d270887c3df
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-ltgt-z13.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z13 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_DOUBLE (SIGNALING_LTGT);
+
+/* z13 does not have signaling vector comparison instructions. */
+/* { dg-final { scan-assembler {\n\tkdb\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-ltgt.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-ltgt.c
new file mode 100644
index 00000000000..9dfae8f2f7e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-ltgt.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z14 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_DOUBLE (SIGNALING_LTGT);
+
+/* { dg-final { scan-assembler-times {\n\tvfkhdb\t} 2 } } */
+/* { dg-final { scan-assembler {\n\tvo\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-double-smax-z13.F90 b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-smax-z13.F90
new file mode 100644
index 00000000000..8a23566e8b9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-smax-z13.F90
@@ -0,0 +1,11 @@
+! { dg-do compile }
+! { dg-options "-ffree-line-length-256 -O3 -march=z13 -mzvector -mzarch" }
+
+#include "autovec-fortran.h"
+
+AUTOVEC_FORTRAN (max)
+
+! Fortran's max does not specify whether or not an exception should be raised in
+! face of qNaNs, and neither does gcc's smax. Vectorize max using quiet
+! comparison, because that's the only one we have on z13.
+! { dg-final { scan-assembler {\n\tvfchdb\t} } }
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-double-smax.F90 b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-smax.F90
new file mode 100644
index 00000000000..c877053136f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-smax.F90
@@ -0,0 +1,8 @@
+! { dg-do compile }
+! { dg-options "-ffree-line-length-256 -O3 -march=z14 -mzvector -mzarch" }
+
+#include "autovec-fortran.h"
+
+AUTOVEC_FORTRAN (max)
+
+! { dg-final { scan-assembler {\n\tvfmaxdb\t} } }
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-double-smin-z13.F90 b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-smin-z13.F90
new file mode 100644
index 00000000000..37711f96176
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-smin-z13.F90
@@ -0,0 +1,11 @@
+! { dg-do compile }
+! { dg-options "-ffree-line-length-256 -O3 -march=z13 -mzvector -mzarch" }
+
+#include "autovec-fortran.h"
+
+AUTOVEC_FORTRAN (min)
+
+! Fortran's min does not specify whether or not an exception should be raised in
+! face of qNaNs, and neither does gcc's smin. Vectorize min using quiet
+! comparison, because that's the only one we have on z13.
+! { dg-final { scan-assembler {\n\tvfchdb\t} } }
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-double-smin.F90 b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-smin.F90
new file mode 100644
index 00000000000..25d6213fa79
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-smin.F90
@@ -0,0 +1,8 @@
+! { dg-do compile }
+! { dg-options "-ffree-line-length-256 -O3 -march=z14 -mzvector -mzarch" }
+
+#include "autovec-fortran.h"
+
+AUTOVEC_FORTRAN (min)
+
+! { dg-final { scan-assembler {\n\tvfmindb\t} } }
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-float-quiet-eq.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-float-quiet-eq.c
new file mode 100644
index 00000000000..216063f0086
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-float-quiet-eq.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z14 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_FLOAT (QUIET_EQ);
+
+/* { dg-final { scan-assembler {\n\tvfcesb\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-float-quiet-ge.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-float-quiet-ge.c
new file mode 100644
index 00000000000..eddf8d66658
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-float-quiet-ge.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z14 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_FLOAT (QUIET_GE);
+
+/* { dg-final { scan-assembler {\n\tvfchesb\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-float-quiet-gt.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-float-quiet-gt.c
new file mode 100644
index 00000000000..69fbb25d6b2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-float-quiet-gt.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z14 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_FLOAT (QUIET_GT);
+
+/* { dg-final { scan-assembler {\n\tvfchsb\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-float-quiet-le.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-float-quiet-le.c
new file mode 100644
index 00000000000..49374e478f4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-float-quiet-le.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z14 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_FLOAT (QUIET_LE);
+
+/* { dg-final { scan-assembler {\n\tvfchesb\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-float-quiet-lt.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-float-quiet-lt.c
new file mode 100644
index 00000000000..403534cb799
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-float-quiet-lt.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z14 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_FLOAT (QUIET_LT);
+
+/* { dg-final { scan-assembler {\n\tvfchsb\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-float-quiet-ordered.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-float-quiet-ordered.c
new file mode 100644
index 00000000000..ae799fbfa98
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-float-quiet-ordered.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z14 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_FLOAT (QUIET_UNORDERED);
+
+/* { dg-final { scan-assembler {\n\tvfchesb\t} } } */
+/* { dg-final { scan-assembler {\n\tvfchsb\t} } } */
+/* { dg-final { scan-assembler {\n\tvo\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-float-quiet-uneq.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-float-quiet-uneq.c
new file mode 100644
index 00000000000..1df53a99bc8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-float-quiet-uneq.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z14 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_FLOAT (QUIET_UNEQ);
+
+/* { dg-final { scan-assembler-times {\n\tvfchsb\t} 2 } } */
+/* { dg-final { scan-assembler {\n\tvo\t} } } */
+/* { dg-final { scan-assembler {\n\tvx\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-float-quiet-unordered.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-float-quiet-unordered.c
new file mode 100644
index 00000000000..3eb44da7484
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-float-quiet-unordered.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z14 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_FLOAT (QUIET_UNORDERED);
+
+/* { dg-final { scan-assembler {\n\tvfchesb\t} } } */
+/* { dg-final { scan-assembler {\n\tvfchsb\t} } } */
+/* combine prefers to reorder vsel args instead of using vno. */
+/* { dg-final { scan-assembler {\n\tvo\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-float-signaling-eq.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-float-signaling-eq.c
new file mode 100644
index 00000000000..7dd91a5e6f3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-float-signaling-eq.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z14 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_FLOAT (SIGNALING_EQ);
+
+/* The vectorizer produces <= and ==, which rtl passes cannot turn into vfkesb
+ yet. */
+/* { dg-final { scan-assembler {\n\tvfcesb\t} } } */
+/* { dg-final { scan-assembler {\n\tvfkhesb\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-float-signaling-ge.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-float-signaling-ge.c
new file mode 100644
index 00000000000..884203b42c9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-float-signaling-ge.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z14 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_FLOAT (SIGNALING_GE);
+
+/* { dg-final { scan-assembler {\n\tvfkhesb\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-float-signaling-gt.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-float-signaling-gt.c
new file mode 100644
index 00000000000..8e4401e3b23
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-float-signaling-gt.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z14 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_FLOAT (SIGNALING_GT);
+
+/* { dg-final { scan-assembler {\n\tvfkhsb\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-float-signaling-le.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-float-signaling-le.c
new file mode 100644
index 00000000000..14ff8b49b4d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-float-signaling-le.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z14 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_FLOAT (SIGNALING_LE);
+
+/* { dg-final { scan-assembler {\n\tvfkhesb\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-float-signaling-lt.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-float-signaling-lt.c
new file mode 100644
index 00000000000..420c7ca5930
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-float-signaling-lt.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z14 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_FLOAT (SIGNALING_LT);
+
+/* { dg-final { scan-assembler {\n\tvfkhsb\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-float-signaling-ltgt.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-float-signaling-ltgt.c
new file mode 100644
index 00000000000..c34cf091608
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-float-signaling-ltgt.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z14 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_FLOAT (SIGNALING_LTGT);
+
+/* { dg-final { scan-assembler-times {\n\tvfkhsb\t} 2 } } */
+/* { dg-final { scan-assembler {\n\tvo\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-fortran.h b/gcc/testsuite/gcc.target/s390/zvector/autovec-fortran.h
new file mode 100644
index 00000000000..8e44cb2dd31
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-fortran.h
@@ -0,0 +1,7 @@
+#define AUTOVEC_FORTRAN(OP) subroutine f (r, x, y); \
+ real(kind=kind (1.0d0)) :: r(1000000), x(1000000), y(1000000); \
+ integer :: i; \
+ do i = 1, 1000000; \
+ r(i) = OP (x(i), y(i)); \
+ end do; \
+end
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-long-double-signaling-ge.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-long-double-signaling-ge.c
new file mode 100644
index 00000000000..e4d01b5ccf9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-long-double-signaling-ge.c
@@ -0,0 +1,8 @@
+/* { dg-do compile { target int128 } } */
+/* { dg-options "-O3 -march=z14 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_LONG_DOUBLE (SIGNALING_GE);
+
+/* { dg-final { scan-assembler {\n\twfkhexb\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-long-double-signaling-gt.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-long-double-signaling-gt.c
new file mode 100644
index 00000000000..b9417ac5112
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-long-double-signaling-gt.c
@@ -0,0 +1,8 @@
+/* { dg-do compile { target int128 } } */
+/* { dg-options "-O3 -march=z14 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_LONG_DOUBLE (SIGNALING_GT);
+
+/* { dg-final { scan-assembler {\n\twfkhxb\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-long-double-signaling-le.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-long-double-signaling-le.c
new file mode 100644
index 00000000000..1a76b1d8ff1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-long-double-signaling-le.c
@@ -0,0 +1,8 @@
+/* { dg-do compile { target int128 } } */
+/* { dg-options "-O3 -march=z14 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_LONG_DOUBLE (SIGNALING_LE);
+
+/* { dg-final { scan-assembler {\n\twfkhexb\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-long-double-signaling-lt.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-long-double-signaling-lt.c
new file mode 100644
index 00000000000..0a1c5cd56d6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-long-double-signaling-lt.c
@@ -0,0 +1,8 @@
+/* { dg-do compile { target int128 } } */
+/* { dg-options "-O3 -march=z14 -mzvector -mzarch" } */
+
+#include "autovec.h"
+
+AUTOVEC_LONG_DOUBLE (SIGNALING_LT);
+
+/* { dg-final { scan-assembler {\n\twfkhxb\t} } } */
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec.h b/gcc/testsuite/gcc.target/s390/zvector/autovec.h
new file mode 100644
index 00000000000..d7977a13335
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec.h
@@ -0,0 +1,43 @@
+#ifndef AUTOVEC_H
+#define AUTOVEC_H 1
+
+#define QUIET_EQ(x, y) ((x) == (y))
+#define QUIET_GE __builtin_isgreaterequal
+#define QUIET_GT __builtin_isgreater
+#define QUIET_LE __builtin_islessequal
+#define QUIET_LT __builtin_isless
+#define QUIET_ORDERED(x, y) (!__builtin_isunordered ((x), (y)))
+#define QUIET_UNEQ(x, y) (__builtin_isless ((x), (y)) \
+ || __builtin_isgreater ((x), (y)))
+#define QUIET_UNORDERED __builtin_isunordered
+#define SIGNALING_EQ(x, y) (((x) <= (y)) && ((x) >= (y)))
+#define SIGNALING_GE(x, y) ((x) >= (y))
+#define SIGNALING_GT(x, y) ((x) > (y))
+#define SIGNALING_LE(x, y) ((x) <= (y))
+#define SIGNALING_LT(x, y) ((x) < (y))
+#define SIGNALING_LTGT(x, y) (((x) < (y)) || ((x) > (y)))
+
+#define AUTOVEC(RESULT_TYPE, OP_TYPE, OP) void \
+f (RESULT_TYPE *r, const OP_TYPE *x, const OP_TYPE *y) \
+{ \
+ int i; \
+\
+ for (i = 0; i < 1000000; i++) \
+ { \
+ OP_TYPE xi = x[i], yi = y[i]; \
+\
+ r[i] = OP (xi, yi); \
+ } \
+}
+
+#define AUTOVEC_DOUBLE(OP) AUTOVEC (long long, double, OP)
+
+#define AUTOVEC_FLOAT(OP) AUTOVEC (int, float, OP)
+
+#ifdef __SIZEOF_INT128__
+typedef __int128 v1ti __attribute__ ((vector_size (16)));
+typedef long double v1tf __attribute__ ((vector_size (16)));
+#define AUTOVEC_LONG_DOUBLE(OP) AUTOVEC (v1ti, v1tf, OP)
+#endif
+
+#endif
diff --git a/gcc/testsuite/gfortran.dg/auto_in_equiv_3.f90 b/gcc/testsuite/gfortran.dg/auto_in_equiv_3.f90
deleted file mode 100644
index 57c384d1772..00000000000
--- a/gcc/testsuite/gfortran.dg/auto_in_equiv_3.f90
+++ /dev/null
@@ -1,63 +0,0 @@
-! { dg-do run }
-! { dg-options "-fdec-static -fno-automatic" }
-
-! Contributed by Mark Eggleston <mark.eggleston@codethink.com>
-
-! Storage is NOT on the static unless explicitly specified using the
-! DEC extension "automatic". The address of the first local variable
-! is used to determine that storage for the automatic local variable
-! is different to that of a local variable with no attributes. The
-! contents of the local variable in suba should be overwritten by the
-! call to subb.
-!
-program test
- integer :: dummy
- integer, parameter :: address = kind(loc(dummy))
- integer(address) :: ad1
- integer(address) :: ad2
- integer(address) :: ad3
- logical :: ok
-
- call suba(0, ad1)
- call subb(0, ad2)
- call suba(1, ad1)
- call subc(0, ad3)
- ok = (ad1.eq.ad3).and.(ad1.ne.ad2)
- if (.not.ok) stop 4
-
-contains
- subroutine suba(option, addr)
- integer, intent(in) :: option
- integer(address), intent(out) :: addr
- integer, automatic :: a
- integer :: b
- equivalence (a, b)
- addr = loc(a)
- if (option.eq.0) then
- ! initialise a and c
- a = 9
- if (a.ne.b) stop 1
- if (loc(a).ne.loc(b)) stop 2
- else
- ! a should've been overwritten
- if (a.eq.9) stop 3
- end if
- end subroutine suba
-
- subroutine subb(dummy, addr)
- integer, intent(in) :: dummy
- integer(address), intent(out) :: addr
- integer :: x
- addr = loc(x)
- x = 77
- end subroutine subb
-
- subroutine subc(dummy, addr)
- integer, intent(in) :: dummy
- integer(address), intent(out) :: addr
- integer, automatic :: y
- addr = loc(y)
- y = 77
- end subroutine subc
-
-end program test
diff --git a/gcc/testsuite/gfortran.dg/diagnostic-format-json-2.F90 b/gcc/testsuite/gfortran.dg/diagnostic-format-json-2.F90
index a6d27d9e16a..bebcf68d431 100644
--- a/gcc/testsuite/gfortran.dg/diagnostic-format-json-2.F90
+++ b/gcc/testsuite/gfortran.dg/diagnostic-format-json-2.F90
@@ -10,6 +10,7 @@
! { dg-regexp "\"kind\": \"warning\"" }
! { dg-regexp "\"message\": \"#warning message\"" }
! { dg-regexp "\"option\": \"-Wcpp\"" }
+! { dg-regexp "\"option_url\": \"\[^\n\r\"\]*#index-Wcpp\"" }
! { dg-regexp "\"caret\": \{" }
! { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-2.F90\"" }
diff --git a/gcc/testsuite/gfortran.dg/diagnostic-format-json-3.F90 b/gcc/testsuite/gfortran.dg/diagnostic-format-json-3.F90
index 702a937d9c6..7ab78eb570b 100644
--- a/gcc/testsuite/gfortran.dg/diagnostic-format-json-3.F90
+++ b/gcc/testsuite/gfortran.dg/diagnostic-format-json-3.F90
@@ -10,6 +10,7 @@
! { dg-regexp "\"kind\": \"error\"" }
! { dg-regexp "\"message\": \"#warning message\"" }
! { dg-regexp "\"option\": \"-Werror=cpp\"" }
+! { dg-regexp "\"option_url\": \"\[^\n\r\"\]*#index-Wcpp\"" }
! { dg-regexp "\"caret\": \{" }
! { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-3.F90\"" }
diff --git a/gcc/testsuite/gfortran.dg/function_kinds_5.f90 b/gcc/testsuite/gfortran.dg/function_kinds_5.f90
index e48484ec30d..106431fe206 100644
--- a/gcc/testsuite/gfortran.dg/function_kinds_5.f90
+++ b/gcc/testsuite/gfortran.dg/function_kinds_5.f90
@@ -8,3 +8,4 @@
real (bad_kind(0d0)) function foo () ! { dg-error "must be an intrinsic function" }
foo = real (kind (foo))
end function
+! { dg-prune-output "Bad kind expression for function" }
diff --git a/gcc/testsuite/gfortran.dg/gnu_logical_2.f90 b/gcc/testsuite/gfortran.dg/gnu_logical_2.f90
index a7b31b4a7e2..0e24c722cc6 100644
--- a/gcc/testsuite/gfortran.dg/gnu_logical_2.f90
+++ b/gcc/testsuite/gfortran.dg/gnu_logical_2.f90
@@ -7,22 +7,22 @@
print *, and(i,i)
print *, and(l,l)
- print *, and(i,r) ! { dg-error "must be the same type" }
- print *, and(c,l) ! { dg-error "must be the same type" }
+ print *, and(i,r) ! { dg-error "must be INTEGER, LOGICAL, or a BOZ" }
+ print *, and(c,l) ! { dg-error "must be INTEGER, LOGICAL, or a BOZ" }
print *, and(i,l) ! { dg-error "must be the same type" }
print *, and(l,i) ! { dg-error "must be the same type" }
print *, or(i,i)
print *, or(l,l)
- print *, or(i,r) ! { dg-error "must be the same type" }
- print *, or(c,l) ! { dg-error "must be the same type" }
+ print *, or(i,r) ! { dg-error "must be INTEGER, LOGICAL, or a BOZ" }
+ print *, or(c,l) ! { dg-error "must be INTEGER, LOGICAL, or a BOZ" }
print *, or(i,l) ! { dg-error "must be the same type" }
print *, or(l,i) ! { dg-error "must be the same type" }
print *, xor(i,i)
print *, xor(l,l)
- print *, xor(i,r) ! { dg-error "must be the same type" }
- print *, xor(c,l) ! { dg-error "must be the same type" }
+ print *, xor(i,r) ! { dg-error "must be INTEGER, LOGICAL, or a BOZ" }
+ print *, xor(c,l) ! { dg-error "must be INTEGER, LOGICAL, or a BOZ" }
print *, xor(i,l) ! { dg-error "must be the same type" }
print *, xor(l,i) ! { dg-error "must be the same type" }
diff --git a/gcc/testsuite/gfortran.dg/goacc/continuation-free-form.f95 b/gcc/testsuite/gfortran.dg/goacc/continuation-free-form.f95
index 1c9a3f33526..b904f7bf77d 100644
--- a/gcc/testsuite/gfortran.dg/goacc/continuation-free-form.f95
+++ b/gcc/testsuite/gfortran.dg/goacc/continuation-free-form.f95
@@ -16,8 +16,8 @@ program test
x = x + 0.3
enddo
! continuation must begin with sentinel
- !$acc end parallel & ! { dg-error "Unclassifiable OpenACC directive" }
+ !$acc end parallel & ! { dg-error "Unexpected junk" }
! loop
print *, x
-end \ No newline at end of file
+end
diff --git a/gcc/testsuite/gfortran.dg/impure_assignment_2.f90 b/gcc/testsuite/gfortran.dg/impure_assignment_2.f90
index 38d841d7a5d..1c1da4b9ee3 100644
--- a/gcc/testsuite/gfortran.dg/impure_assignment_2.f90
+++ b/gcc/testsuite/gfortran.dg/impure_assignment_2.f90
@@ -40,7 +40,7 @@ CONTAINS
PURE FUNCTION give_next3(node)
TYPE(node_type), intent(in) :: node
TYPE(node_type) :: give_next
- give_next = node ! { dg-error "impure variable" }
+ give_next = node ! { dg-error "pure subprogram" }
END FUNCTION
END MODULE pr20863
diff --git a/gcc/testsuite/gfortran.dg/minmaxloc_14.f90 b/gcc/testsuite/gfortran.dg/minmaxloc_14.f90
new file mode 100644
index 00000000000..d24d03f0af4
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/minmaxloc_14.f90
@@ -0,0 +1,12 @@
+! { dg-do compile }
+! PR 92017 - this used to cause an ICE due do a missing charlen.
+! Original test case by Gerhard Steinmetz.
+
+program p
+ character(3), parameter :: a(4) = 'abc'
+ integer, parameter :: b(1) = minloc(a)
+ integer, parameter :: c = minloc(a, dim=1)
+ integer, parameter :: bb(1) = maxloc(a)
+ integer, parameter :: c2 = maxloc(a,dim=1)
+end program p
+
diff --git a/gcc/testsuite/gfortran.dg/pr81509_2.f90 b/gcc/testsuite/gfortran.dg/pr81509_2.f90
index a0618cc49b2..719feb5c510 100644
--- a/gcc/testsuite/gfortran.dg/pr81509_2.f90
+++ b/gcc/testsuite/gfortran.dg/pr81509_2.f90
@@ -13,6 +13,6 @@ k = ieor(z'ade',i)
k = ior(i,z'1111')
k = ior(i,k) ! { dg-error "different kind type parameters" }
k = and(i,k) ! { dg-error "must be the same type" }
-k = and(a,z'1234') ! { dg-error "must be the same type" }
+k = and(a,z'1234') ! { dg-error "must be INTEGER" }
end program foo
diff --git a/gcc/testsuite/gfortran.dg/pr85543.f90 b/gcc/testsuite/gfortran.dg/pr85543.f90
index d3f83276a7f..b0faa8d5927 100644
--- a/gcc/testsuite/gfortran.dg/pr85543.f90
+++ b/gcc/testsuite/gfortran.dg/pr85543.f90
@@ -6,3 +6,4 @@ contains
real(z()) function f() ! { dg-error "in initialization expression at" }
end
end
+! { dg-prune-output "Bad kind expression for function" }
diff --git a/gcc/testsuite/gfortran.dg/pr91649.f90 b/gcc/testsuite/gfortran.dg/pr91649.f90
new file mode 100644
index 00000000000..0e6acb9ac8d
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr91649.f90
@@ -0,0 +1,23 @@
+! { dg-do compile }
+! PR fortran/91649
+! Code originally contributed by Gerhard Steinmetz
+subroutine p
+ logical :: back = .true.
+ integer :: x(1) = findloc([1, 2, 1], '1', back=back) ! { dg-error "must be in type conformance" }
+ print *, x
+end
+
+subroutine q
+ type t
+ end type
+ logical :: back = .false.
+ integer :: x(1) = findloc([1, 2, 1], t(), back=back) ! { dg-error "must be of intrinsic type" }
+ print *, x
+end
+
+subroutine s
+ character(4) :: c = '1234'
+ integer :: x(1) = findloc([1, 2, 1], c, back=.true.) ! { dg-error "must be in type conformance" }
+ print *, x
+end
+
diff --git a/gcc/testsuite/gfortran.dg/pr91715.f90 b/gcc/testsuite/gfortran.dg/pr91715.f90
new file mode 100644
index 00000000000..a3d9b8d1d9a
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr91715.f90
@@ -0,0 +1,5 @@
+! { dg-do compile }
+! PR fortran/91715
+! Code contributed Gerhard Steinmetz
+character(1function f() ! { dg-error "Syntax error in CHARACTER" }
+end
diff --git a/gcc/testsuite/gfortran.dg/pr91801.f90 b/gcc/testsuite/gfortran.dg/pr91801.f90
new file mode 100644
index 00000000000..d2d82b88464
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr91801.f90
@@ -0,0 +1,7 @@
+! { dg-do compile }
+! PR fortran/91801
+! Code contributed by Gerhard Steinmetz
+program p
+ integer, parameter :: a(2) = [2,0] ! { dg-error "Element with a value of" }
+ print *, reshape([1,2,3,4,5,6], [2,3], order=a) ! { dg-error "for the RESHAPE intrinsic near" }
+end
diff --git a/gcc/testsuite/gfortran.dg/pr92018.f90 b/gcc/testsuite/gfortran.dg/pr92018.f90
new file mode 100644
index 00000000000..6c90d2f6762
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr92018.f90
@@ -0,0 +1,8 @@
+! { dg-do compile }
+! PR fortran/92018
+subroutine sub (f)
+ integer :: f
+ print *, f(b'11') ! { dg-error "cannot appear as an actual" }
+ print *, f(o'11') ! { dg-error "cannot appear as an actual" }
+ print *, f(z'11') ! { dg-error "cannot appear as an actual" }
+end
diff --git a/gcc/testsuite/gfortran.dg/pr92019.f90 b/gcc/testsuite/gfortran.dg/pr92019.f90
new file mode 100644
index 00000000000..488774ba82f
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr92019.f90
@@ -0,0 +1,9 @@
+! { dg-do compile }
+! PR fortran/92019
+program foo
+ integer :: a(4) = [1, 2, 3, 4]
+ print *, a(z'1') ! { dg-error "Invalid BOZ literal constant" }
+ print *, a(1:z'3') ! { dg-error "Invalid BOZ literal constant" }
+ print *, a(1:2:z'2') ! { dg-error "Invalid BOZ literal constant" }
+ print *, a([z'2',z'1']) ! { dg-error "cannot appear in an array constructor" }
+end program foo
diff --git a/gcc/testsuite/gfortran.dg/pr92050.f90 b/gcc/testsuite/gfortran.dg/pr92050.f90
new file mode 100644
index 00000000000..64193878d8f
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr92050.f90
@@ -0,0 +1,53 @@
+! { dg-do run }
+! { dg-options "-fcheck=all" }
+! { dg-shouldfail "above upper bound" }
+!
+! PR fortran/92050
+!
+!
+module buggy
+ implicit none (type, external)
+
+ type :: par
+ contains
+ procedure, public :: fun => fun_par
+ end type par
+
+ type comp
+ class(par), allocatable :: p
+ end type comp
+
+ type foo
+ type(comp), allocatable :: m(:)
+ end type foo
+
+contains
+
+ function fun_par(this)
+ class(par) :: this
+ integer :: fun_par(1)
+ fun_par = 42
+ end function fun_par
+
+ subroutine update_foo(this)
+ class(foo) :: this
+ write(*,*) this%m(1)%p%fun()
+ end subroutine update_foo
+
+ subroutine bad_update_foo(this)
+ class(foo) :: this
+ write(*,*) this%m(2)%p%fun()
+ end subroutine bad_update_foo
+end module buggy
+
+program main
+ use buggy
+ implicit none (type, external)
+ type(foo) :: x
+ allocate(x%m(1))
+ allocate(x%m(1)%p)
+ call update_foo(x)
+ call bad_update_foo(x)
+end program main
+
+! { dg-output "At line 39 of file .*pr92050.f90.*Fortran runtime error: Index '2' of dimension 1 of array 'this%m' above upper bound of 1" }
diff --git a/gcc/testsuite/gnat.dg/array38.adb b/gcc/testsuite/gnat.dg/array38.adb
new file mode 100644
index 00000000000..fe37b653eaa
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/array38.adb
@@ -0,0 +1,11 @@
+-- { dg-do compile }
+
+with Array38_Pkg; use Array38_Pkg;
+
+procedure Array38 is
+
+ function My_F is new F (Index, Byte, Bytes, Integer);
+
+begin
+ null;
+end;
diff --git a/gcc/testsuite/gnat.dg/array38_pkg.adb b/gcc/testsuite/gnat.dg/array38_pkg.adb
new file mode 100644
index 00000000000..ebaa66eba8e
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/array38_pkg.adb
@@ -0,0 +1,8 @@
+package body Array38_Pkg is
+
+ function F (Data : Array_Type) return Value_Type is
+ begin
+ return Value_Type'First;
+ end;
+
+end Array38_Pkg;
diff --git a/gcc/testsuite/gnat.dg/array38_pkg.ads b/gcc/testsuite/gnat.dg/array38_pkg.ads
new file mode 100644
index 00000000000..17c3ef47892
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/array38_pkg.ads
@@ -0,0 +1,18 @@
+package Array38_Pkg is
+
+ type Byte is mod 2**8;
+
+ type Length is new Natural;
+ subtype Index is Length range 1 .. Length'Last;
+
+ type Bytes is array (Index range <>) of Byte with
+ Predicate => Bytes'Length > 0;
+
+ generic
+ type Index_Type is (<>);
+ type Element_Type is (<>);
+ type Array_Type is array (Index_Type range <>) of Element_Type;
+ type Value_Type is (<>);
+ function F (Data : Array_Type) return Value_Type;
+
+end Array38_Pkg;
diff --git a/gcc/testsuite/gnat.dg/specs/size_clause4.ads b/gcc/testsuite/gnat.dg/specs/size_clause4.ads
new file mode 100644
index 00000000000..4aa8c8fca78
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/specs/size_clause4.ads
@@ -0,0 +1,20 @@
+-- { dg-do compile }
+
+with System;
+
+package Size_Clause4 is
+
+ type Rec is record
+ A1 : System.Address;
+ A2 : System.Address;
+ I : aliased Integer;
+ end record;
+
+ for Rec use record
+ A1 at 0 range 0 .. 63;
+ A2 at 8 range 0 .. 63;
+ I at 16 range 0 .. 31;
+ end record;
+ for Rec'Size use 160;
+
+end Size_Clause4;
diff --git a/gcc/testsuite/jit.dg/test-error-array-bounds.c b/gcc/testsuite/jit.dg/test-error-array-bounds.c
index 889c51737a4..cd9361fba1d 100644
--- a/gcc/testsuite/jit.dg/test-error-array-bounds.c
+++ b/gcc/testsuite/jit.dg/test-error-array-bounds.c
@@ -20,9 +20,10 @@ create_code (gcc_jit_context *ctxt, void *user_data)
gcc_jit_context_add_command_line_option (ctxt, "-Warray-bounds");
gcc_jit_context_add_command_line_option (ctxt, "-ftree-vrp");
- /* Ensure that the error message doesn't contain colorization codes,
- even if run at a TTY. */
+ /* Ensure that the error message doesn't contain colorization codes
+ or escaped URLs, even if run at a TTY. */
gcc_jit_context_add_command_line_option (ctxt, "-fdiagnostics-color=never");
+ gcc_jit_context_add_command_line_option (ctxt, "-fdiagnostics-urls=never");
gcc_jit_type *char_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CHAR);
diff --git a/gcc/testsuite/lib/g++-dg.exp b/gcc/testsuite/lib/g++-dg.exp
index ddeb4a2adc7..77f29db1660 100644
--- a/gcc/testsuite/lib/g++-dg.exp
+++ b/gcc/testsuite/lib/g++-dg.exp
@@ -52,7 +52,7 @@ proc g++-dg-runtest { testcases flags default-extra-flags } {
if { [llength $gpp_std_list] > 0 } {
set std_list $gpp_std_list
} else {
- set std_list { 98 14 17 }
+ set std_list { 98 14 17 2a }
}
set option_list { }
foreach x $std_list {
diff --git a/gcc/testsuite/lib/prune.exp b/gcc/testsuite/lib/prune.exp
index 812c59e6fee..a9beef48ecb 100644
--- a/gcc/testsuite/lib/prune.exp
+++ b/gcc/testsuite/lib/prune.exp
@@ -21,7 +21,7 @@ load_lib multiline.exp
if ![info exists TEST_ALWAYS_FLAGS] {
set TEST_ALWAYS_FLAGS ""
}
-set TEST_ALWAYS_FLAGS "-fno-diagnostics-show-caret -fno-diagnostics-show-line-numbers -fdiagnostics-color=never $TEST_ALWAYS_FLAGS"
+set TEST_ALWAYS_FLAGS "-fno-diagnostics-show-caret -fno-diagnostics-show-line-numbers -fdiagnostics-color=never -fdiagnostics-urls=never $TEST_ALWAYS_FLAGS"
proc prune_gcc_output { text } {
global srcdir
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index a7b76b69b75..6f224fa8141 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -6933,6 +6933,29 @@ proc check_effective_target_popcountl { } {
} "" ]
}
+# Return 1 if the target supports popcount on long long.
+
+proc check_effective_target_popcountll { } {
+ return [check_no_messages_and_pattern popcountll "!\\(call" rtl-expand {
+ int foo (long long b)
+ {
+ return __builtin_popcountll (b);
+ }
+ } "" ]
+}
+
+
+# Return 1 if the target supports popcount on int.
+
+proc check_effective_target_popcount { } {
+ return [check_no_messages_and_pattern popcount "!\\(call" rtl-expand {
+ int foo (int b)
+ {
+ return __builtin_popcount (b);
+ }
+ } "" ]
+}
+
# Return 1 if the target supports atomic operations on "long long"
# and can execute them.
#
@@ -7455,18 +7478,6 @@ proc check_effective_target_fd_truncate { } {
return [check_runtime chsize $prog]
}
-# Add to FLAGS all the target-specific flags needed to access the c99 runtime.
-
-proc add_options_for_c99_runtime { flags } {
- if { [istarget *-*-solaris2*] } {
- return "$flags -std=c99"
- }
- if { [istarget powerpc-*-darwin*] } {
- return "$flags -mmacosx-version-min=10.3"
- }
- return $flags
-}
-
# Add to FLAGS all the target-specific flags needed to enable
# full IEEE compliance mode.
@@ -7548,8 +7559,7 @@ proc check_effective_target_c99_runtime { } {
#error !HAVE_C99_RUNTIME
#endif
}
- check_no_compiler_messages_nocache c99_runtime assembly \
- $contents [add_options_for_c99_runtime ""]
+ check_no_compiler_messages_nocache c99_runtime assembly $contents
}]
}
@@ -8561,7 +8571,7 @@ proc check_effective_target_c++2a { } {
# Check for C++ Concepts TS support, i.e. -fconcepts flag.
proc check_effective_target_concepts { } {
- return [check-flags { "" { } { -fconcepts } }]
+ return [check-flags { "" { } { -fconcepts -std=*2a } }]
}
# Return 1 if expensive testcases should be run.
diff --git a/gcc/timevar.def b/gcc/timevar.def
index 3551a433b1f..357fcfd65c5 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -141,8 +141,9 @@ DEFTIMEVAR (TV_PARSE_INLINE , "parser inl. func. body")
DEFTIMEVAR (TV_PARSE_INMETH , "parser inl. meth. body")
DEFTIMEVAR (TV_TEMPLATE_INST , "template instantiation")
DEFTIMEVAR (TV_CONSTEXPR , "constant expression evaluation")
-DEFTIMEVAR (TV_CONSTRAINT_SAT , "constraint satisfaction")
-DEFTIMEVAR (TV_CONSTRAINT_SUB , "constraint subsumption")
+DEFTIMEVAR (TV_CONSTRAINT_NORM , "constraint normalization")
+DEFTIMEVAR (TV_CONSTRAINT_SAT , "constraint satisfaction")
+DEFTIMEVAR (TV_CONSTRAINT_SUB , "constraint subsumption")
DEFTIMEVAR (TV_FLATTEN_INLINING , "flatten inlining")
DEFTIMEVAR (TV_EARLY_INLINING , "early inlining heuristics")
DEFTIMEVAR (TV_INLINE_PARAMETERS , "inline parameters")
diff --git a/gcc/toplev.c b/gcc/toplev.c
index d741a66f385..1c7002f5c37 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -1110,6 +1110,7 @@ general_init (const char *argv0, bool init_signals)
global_dc->option_enabled = option_enabled;
global_dc->option_state = &global_options;
global_dc->option_name = option_name;
+ global_dc->get_option_url = get_option_url;
if (init_signals)
{
@@ -1170,7 +1171,7 @@ general_init (const char *argv0, bool init_signals)
/* Create the passes. */
g->set_passes (new gcc::pass_manager (g));
- symtab = new (ggc_cleared_alloc <symbol_table> ()) symbol_table ();
+ symtab = new (ggc_alloc <symbol_table> ()) symbol_table ();
statistics_early_init ();
debuginfo_early_init ();
diff --git a/gcc/tree-dfa.c b/gcc/tree-dfa.c
index 9ba627c90b5..64991ba92fa 100644
--- a/gcc/tree-dfa.c
+++ b/gcc/tree-dfa.c
@@ -61,23 +61,23 @@ static void collect_dfa_stats (struct dfa_stats_d *);
/* Renumber all of the gimple stmt uids. */
void
-renumber_gimple_stmt_uids (void)
+renumber_gimple_stmt_uids (struct function *fun)
{
basic_block bb;
- set_gimple_stmt_max_uid (cfun, 0);
- FOR_ALL_BB_FN (bb, cfun)
+ set_gimple_stmt_max_uid (fun, 0);
+ FOR_ALL_BB_FN (bb, fun)
{
gimple_stmt_iterator bsi;
for (bsi = gsi_start_phis (bb); !gsi_end_p (bsi); gsi_next (&bsi))
{
gimple *stmt = gsi_stmt (bsi);
- gimple_set_uid (stmt, inc_gimple_stmt_max_uid (cfun));
+ gimple_set_uid (stmt, inc_gimple_stmt_max_uid (fun));
}
for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi))
{
gimple *stmt = gsi_stmt (bsi);
- gimple_set_uid (stmt, inc_gimple_stmt_max_uid (cfun));
+ gimple_set_uid (stmt, inc_gimple_stmt_max_uid (fun));
}
}
}
diff --git a/gcc/tree-dfa.h b/gcc/tree-dfa.h
index 98810080c65..aa4ab7eb946 100644
--- a/gcc/tree-dfa.h
+++ b/gcc/tree-dfa.h
@@ -20,7 +20,7 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_TREE_DFA_H
#define GCC_TREE_DFA_H
-extern void renumber_gimple_stmt_uids (void);
+extern void renumber_gimple_stmt_uids (struct function *);
extern void renumber_gimple_stmt_uids_in_blocks (basic_block *, int);
extern void dump_variable (FILE *, tree);
extern void debug_variable (tree);
diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c
index 1aba7333631..54502e6f93c 100644
--- a/gcc/tree-eh.c
+++ b/gcc/tree-eh.c
@@ -2499,6 +2499,14 @@ operation_could_trap_helper_p (enum tree_code op,
/* Constructing an object cannot trap. */
return false;
+ case COND_EXPR:
+ case VEC_COND_EXPR:
+ /* Whether *COND_EXPR can trap depends on whether the
+ first argument can trap, so signal it as not handled.
+ Whether lhs is floating or not doesn't matter. */
+ *handled = false;
+ return false;
+
default:
/* Any floating arithmetic may trap. */
if (fp_operation && flag_trapping_math)
@@ -2523,6 +2531,10 @@ operation_could_trap_p (enum tree_code op, bool fp_operation, bool honor_trapv,
bool honor_snans = fp_operation && flag_signaling_nans != 0;
bool handled;
+ /* This function cannot tell whether or not COND_EXPR and VEC_COND_EXPR could
+ trap, because that depends on the respective condition op. */
+ gcc_assert (op != COND_EXPR && op != VEC_COND_EXPR);
+
if (TREE_CODE_CLASS (op) != tcc_comparison
&& TREE_CODE_CLASS (op) != tcc_unary
&& TREE_CODE_CLASS (op) != tcc_binary)
@@ -2610,6 +2622,13 @@ tree_could_trap_p (tree expr)
if (!expr)
return false;
+ /* In COND_EXPR and VEC_COND_EXPR only the condition may trap, but
+ they won't appear as operands in GIMPLE form, so this is just for the
+ GENERIC uses where it needs to recurse on the operands and so
+ *COND_EXPR itself doesn't trap. */
+ if (TREE_CODE (expr) == COND_EXPR || TREE_CODE (expr) == VEC_COND_EXPR)
+ return false;
+
code = TREE_CODE (expr);
t = TREE_TYPE (expr);
diff --git a/gcc/tree-if-conv.c b/gcc/tree-if-conv.c
index 822aae5b83f..af49813b0d1 100644
--- a/gcc/tree-if-conv.c
+++ b/gcc/tree-if-conv.c
@@ -120,6 +120,7 @@ along with GCC; see the file COPYING3. If not see
#include "fold-const.h"
#include "tree-ssa-sccvn.h"
#include "tree-cfgcleanup.h"
+#include "tree-ssa-dse.h"
/* Only handle PHIs with no more arguments unless we are asked to by
simd pragma. */
@@ -2873,7 +2874,7 @@ ifcvt_split_critical_edges (class loop *loop, bool aggressive_if_conv)
loop vectorization. */
static void
-ifcvt_local_dce (basic_block bb)
+ifcvt_local_dce (class loop *loop)
{
gimple *stmt;
gimple *stmt1;
@@ -2890,6 +2891,10 @@ ifcvt_local_dce (basic_block bb)
replace_uses_by (name_pair->first, name_pair->second);
redundant_ssa_names.release ();
+ /* The loop has a single BB only. */
+ basic_block bb = loop->header;
+ tree latch_vdef = NULL_TREE;
+
worklist.create (64);
/* Consider all phi as live statements. */
for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
@@ -2897,6 +2902,8 @@ ifcvt_local_dce (basic_block bb)
phi = gsi_stmt (gsi);
gimple_set_plf (phi, GF_PLF_2, true);
worklist.safe_push (phi);
+ if (virtual_operand_p (gimple_phi_result (phi)))
+ latch_vdef = PHI_ARG_DEF_FROM_EDGE (phi, loop_latch_edge (loop));
}
/* Consider load/store statements, CALL and COND as live. */
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
@@ -2960,6 +2967,19 @@ ifcvt_local_dce (basic_block bb)
while (!gsi_end_p (gsi))
{
stmt = gsi_stmt (gsi);
+ if (gimple_store_p (stmt))
+ {
+ tree lhs = gimple_get_lhs (stmt);
+ ao_ref write;
+ ao_ref_init (&write, lhs);
+
+ if (dse_classify_store (&write, stmt, false, NULL, NULL, latch_vdef)
+ == DSE_STORE_DEAD)
+ delete_dead_or_redundant_assignment (&gsi, "dead");
+ gsi_next (&gsi);
+ continue;
+ }
+
if (gimple_plf (stmt, GF_PLF_2))
{
gsi_next (&gsi);
@@ -3070,7 +3090,7 @@ tree_if_conversion (class loop *loop, vec<gimple *> *preds)
todo |= do_rpo_vn (cfun, loop_preheader_edge (loop), exit_bbs);
/* Delete dead predicate computations. */
- ifcvt_local_dce (loop->header);
+ ifcvt_local_dce (loop);
BITMAP_FREE (exit_bbs);
todo |= TODO_cleanup_cfg;
diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c
index c462ca46e7d..3f104238d93 100644
--- a/gcc/tree-sra.c
+++ b/gcc/tree-sra.c
@@ -392,7 +392,7 @@ dump_access (FILE *f, struct access *access, bool grp)
"grp_hint = %d, grp_covered = %d, "
"grp_unscalarizable_region = %d, grp_unscalarized_data = %d, "
"grp_same_access_path = %d, grp_partial_lhs = %d, "
- "grp_to_be_replaced = %d, grp_to_be_debug_replaced = %d\n",
+ "grp_to_be_replaced = %d, grp_to_be_debug_replaced = %d}\n",
access->grp_read, access->grp_write, access->grp_assignment_read,
access->grp_assignment_write, access->grp_scalar_read,
access->grp_scalar_write, access->grp_total_scalarization,
@@ -402,7 +402,7 @@ dump_access (FILE *f, struct access *access, bool grp)
access->grp_to_be_replaced, access->grp_to_be_debug_replaced);
else
fprintf (f, ", write = %d, grp_total_scalarization = %d, "
- "grp_partial_lhs = %d\n",
+ "grp_partial_lhs = %d}\n",
access->write, access->grp_total_scalarization,
access->grp_partial_lhs);
}
diff --git a/gcc/tree-ssa-dse.c b/gcc/tree-ssa-dse.c
index ba67884a825..25cd4709b31 100644
--- a/gcc/tree-ssa-dse.c
+++ b/gcc/tree-ssa-dse.c
@@ -36,6 +36,7 @@ along with GCC; see the file COPYING3. If not see
#include "params.h"
#include "alias.h"
#include "tree-ssa-loop.h"
+#include "tree-ssa-dse.h"
/* This file implements dead store elimination.
@@ -76,21 +77,13 @@ along with GCC; see the file COPYING3. If not see
fact, they are the same transformation applied to different views of
the CFG. */
-static void delete_dead_or_redundant_assignment (gimple_stmt_iterator *, const char *);
+void delete_dead_or_redundant_assignment (gimple_stmt_iterator *, const char *);
static void delete_dead_or_redundant_call (gimple_stmt_iterator *, const char *);
/* Bitmap of blocks that have had EH statements cleaned. We should
remove their dead edges eventually. */
static bitmap need_eh_cleanup;
-/* Return value from dse_classify_store */
-enum dse_store_status
-{
- DSE_STORE_LIVE,
- DSE_STORE_MAYBE_PARTIAL_DEAD,
- DSE_STORE_DEAD
-};
-
/* STMT is a statement that may write into memory. Analyze it and
initialize WRITE to describe how STMT affects memory.
@@ -662,10 +655,10 @@ dse_optimize_redundant_stores (gimple *stmt)
if only clobber statements influenced the classification result.
Returns the classification. */
-static dse_store_status
+dse_store_status
dse_classify_store (ao_ref *ref, gimple *stmt,
bool byte_tracking_enabled, sbitmap live_bytes,
- bool *by_clobber_p = NULL)
+ bool *by_clobber_p, tree stop_at_vuse)
{
gimple *temp;
int cnt = 0;
@@ -701,6 +694,11 @@ dse_classify_store (ao_ref *ref, gimple *stmt,
}
else
defvar = gimple_vdef (temp);
+
+ /* If we're instructed to stop walking at region boundary, do so. */
+ if (defvar == stop_at_vuse)
+ return DSE_STORE_LIVE;
+
auto_vec<gimple *, 10> defs;
gimple *phi_def = NULL;
FOR_EACH_IMM_USE_STMT (use_stmt, ui, defvar)
@@ -901,7 +899,7 @@ delete_dead_or_redundant_call (gimple_stmt_iterator *gsi, const char *type)
/* Delete a dead store at GSI, which is a gimple assignment. */
-static void
+void
delete_dead_or_redundant_assignment (gimple_stmt_iterator *gsi, const char *type)
{
gimple *stmt = gsi_stmt (*gsi);
@@ -1115,7 +1113,7 @@ pass_dse::execute (function *fun)
{
need_eh_cleanup = BITMAP_ALLOC (NULL);
- renumber_gimple_stmt_uids ();
+ renumber_gimple_stmt_uids (cfun);
/* We might consider making this a property of each pass so that it
can be [re]computed on an as-needed basis. Particularly since
diff --git a/gcc/tree-ssa-dse.h b/gcc/tree-ssa-dse.h
new file mode 100644
index 00000000000..a5eccbd746d
--- /dev/null
+++ b/gcc/tree-ssa-dse.h
@@ -0,0 +1,36 @@
+/* Support routines for dead store elimination.
+ Copyright (C) 2019 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_TREE_SSA_DSE_H
+#define GCC_TREE_SSA_DSE_H
+
+/* Return value from dse_classify_store */
+enum dse_store_status
+{
+ DSE_STORE_LIVE,
+ DSE_STORE_MAYBE_PARTIAL_DEAD,
+ DSE_STORE_DEAD
+};
+
+dse_store_status dse_classify_store (ao_ref *, gimple *, bool, sbitmap,
+ bool * = NULL, tree = NULL);
+
+void delete_dead_or_redundant_assignment (gimple_stmt_iterator *, const char *);
+
+#endif /* GCC_TREE_SSA_DSE_H */
diff --git a/gcc/tree-ssa-forwprop.c b/gcc/tree-ssa-forwprop.c
index a1e22c93631..fe55ca958b4 100644
--- a/gcc/tree-ssa-forwprop.c
+++ b/gcc/tree-ssa-forwprop.c
@@ -527,9 +527,10 @@ forward_propagate_into_gimple_cond (gcond *stmt)
tmp = forward_propagate_into_comparison_1 (stmt, code,
boolean_type_node,
rhs1, rhs2);
- if (tmp)
+ if (tmp
+ && is_gimple_condexpr_for_cond (tmp))
{
- if (dump_file && tmp)
+ if (dump_file)
{
fprintf (dump_file, " Replaced '");
print_gimple_expr (dump_file, stmt, 0);
@@ -607,7 +608,7 @@ forward_propagate_into_cond (gimple_stmt_iterator *gsi_p)
if (tmp
&& is_gimple_condexpr (tmp))
{
- if (dump_file && tmp)
+ if (dump_file)
{
fprintf (dump_file, " Replaced '");
print_generic_expr (dump_file, cond);
diff --git a/gcc/tree-ssa-math-opts.c b/gcc/tree-ssa-math-opts.c
index 5fea155b71b..013ef93e7ad 100644
--- a/gcc/tree-ssa-math-opts.c
+++ b/gcc/tree-ssa-math-opts.c
@@ -3850,7 +3850,7 @@ pass_optimize_widening_mul::execute (function *fun)
memset (&widen_mul_stats, 0, sizeof (widen_mul_stats));
calculate_dominance_info (CDI_DOMINATORS);
- renumber_gimple_stmt_uids ();
+ renumber_gimple_stmt_uids (cfun);
math_opts_dom_walker (&cfg_changed).walk (ENTRY_BLOCK_PTR_FOR_FN (cfun));
diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c
index b64bde695f4..38bb8b24155 100644
--- a/gcc/tree-ssa-phiopt.c
+++ b/gcc/tree-ssa-phiopt.c
@@ -2467,7 +2467,11 @@ cond_if_else_store_replacement (basic_block then_bb, basic_block else_bb,
then_assign, else_assign);
}
- if (MAX_STORES_TO_SINK == 0)
+ /* If either vectorization or if-conversion is disabled then do
+ not sink any stores. */
+ if (MAX_STORES_TO_SINK == 0
+ || (!flag_tree_loop_vectorize && !flag_tree_slp_vectorize)
+ || !flag_tree_loop_if_convert)
return false;
/* Find data references. */
diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c
index 44b8c67b198..57331ab44dc 100644
--- a/gcc/tree-ssa-sccvn.c
+++ b/gcc/tree-ssa-sccvn.c
@@ -1877,8 +1877,10 @@ vn_walk_cb_data::push_partial_def (const pd_data &pd, tree vuse,
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file,
"Successfully combined %u partial definitions\n", ndefs);
+ /* ??? If we track partial defs alias-set we could use that if it
+ is the same for all. Use zero for now. */
return vn_reference_lookup_or_insert_for_pieces
- (first_vuse, vr->set, vr->type, vr->operands, val);
+ (first_vuse, 0, vr->type, vr->operands, val);
}
else
{
@@ -2331,9 +2333,7 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
}
}
- /* If we are looking for redundant stores do not create new hashtable
- entries from aliasing defs with made up alias-sets. */
- if (*disambiguate_only > TR_TRANSLATE || !data->tbaa_p)
+ if (*disambiguate_only > TR_TRANSLATE)
return (void *)-1;
/* If we cannot constrain the size of the reference we cannot
@@ -2449,7 +2449,7 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
return (void *)-1;
}
return vn_reference_lookup_or_insert_for_pieces
- (vuse, vr->set, vr->type, vr->operands, val);
+ (vuse, 0, vr->type, vr->operands, val);
}
/* For now handle clearing memory with partial defs. */
else if (known_eq (ref->size, maxsize)
@@ -2499,7 +2499,7 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
{
tree val = build_zero_cst (vr->type);
return vn_reference_lookup_or_insert_for_pieces
- (vuse, vr->set, vr->type, vr->operands, val);
+ (vuse, get_alias_set (lhs), vr->type, vr->operands, val);
}
else if (known_eq (ref->size, maxsize)
&& maxsize.is_constant (&maxsizei)
@@ -2614,7 +2614,7 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
if (val)
return vn_reference_lookup_or_insert_for_pieces
- (vuse, vr->set, vr->type, vr->operands, val);
+ (vuse, get_alias_set (lhs), vr->type, vr->operands, val);
}
}
else if (ranges_known_overlap_p (offseti, maxsizei, offset2i, size2i))
@@ -2672,23 +2672,26 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
according to endianness. */
&& (! INTEGRAL_TYPE_P (vr->type)
|| known_eq (ref->size, TYPE_PRECISION (vr->type)))
- && multiple_p (ref->size, BITS_PER_UNIT)
- && (! INTEGRAL_TYPE_P (TREE_TYPE (def_rhs))
- || type_has_mode_precision_p (TREE_TYPE (def_rhs))))
+ && multiple_p (ref->size, BITS_PER_UNIT))
{
- gimple_match_op op (gimple_match_cond::UNCOND,
- BIT_FIELD_REF, vr->type,
- vn_valueize (def_rhs),
- bitsize_int (ref->size),
- bitsize_int (offset - offset2));
- tree val = vn_nary_build_or_lookup (&op);
- if (val
- && (TREE_CODE (val) != SSA_NAME
- || ! SSA_NAME_OCCURS_IN_ABNORMAL_PHI (val)))
+ if (known_eq (ref->size, size2))
+ return vn_reference_lookup_or_insert_for_pieces
+ (vuse, get_alias_set (lhs), vr->type, vr->operands,
+ SSA_VAL (def_rhs));
+ else if (! INTEGRAL_TYPE_P (TREE_TYPE (def_rhs))
+ || type_has_mode_precision_p (TREE_TYPE (def_rhs)))
{
- vn_reference_t res = vn_reference_lookup_or_insert_for_pieces
- (vuse, vr->set, vr->type, vr->operands, val);
- return res;
+ gimple_match_op op (gimple_match_cond::UNCOND,
+ BIT_FIELD_REF, vr->type,
+ vn_valueize (def_rhs),
+ bitsize_int (ref->size),
+ bitsize_int (offset - offset2));
+ tree val = vn_nary_build_or_lookup (&op);
+ if (val
+ && (TREE_CODE (val) != SSA_NAME
+ || ! SSA_NAME_OCCURS_IN_ABNORMAL_PHI (val)))
+ return vn_reference_lookup_or_insert_for_pieces
+ (vuse, get_alias_set (lhs), vr->type, vr->operands, val);
}
}
}
@@ -2770,7 +2773,8 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
}
/* Now re-write REF to be based on the rhs of the assignment. */
- copy_reference_ops_from_ref (gimple_assign_rhs1 (def_stmt), &rhs);
+ tree rhs1 = gimple_assign_rhs1 (def_stmt);
+ copy_reference_ops_from_ref (rhs1, &rhs);
/* Apply an extra offset to the inner MEM_REF of the RHS. */
if (maybe_ne (extra_off, 0))
@@ -2806,7 +2810,7 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
{
if (data->partial_defs.is_empty ())
return vn_reference_lookup_or_insert_for_pieces
- (vuse, vr->set, vr->type, vr->operands, val);
+ (vuse, get_alias_set (rhs1), vr->type, vr->operands, val);
/* This is the only interesting case for partial-def handling
coming from targets that like to gimplify init-ctors as
aggregate copies from constant data like aarch64 for
@@ -2829,7 +2833,8 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
return (void *)-1;
/* Adjust *ref from the new operands. */
- if (!ao_ref_init_from_vn_reference (&r, vr->set, vr->type, vr->operands))
+ if (!ao_ref_init_from_vn_reference (&r, get_alias_set (rhs1),
+ vr->type, vr->operands))
return (void *)-1;
/* This can happen with bitfields. */
if (maybe_ne (ref->size, r.size))
@@ -2990,10 +2995,10 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
tree val = fully_constant_vn_reference_p (vr);
if (val)
return vn_reference_lookup_or_insert_for_pieces
- (vuse, vr->set, vr->type, vr->operands, val);
+ (vuse, 0, vr->type, vr->operands, val);
/* Adjust *ref from the new operands. */
- if (!ao_ref_init_from_vn_reference (&r, vr->set, vr->type, vr->operands))
+ if (!ao_ref_init_from_vn_reference (&r, 0, vr->type, vr->operands))
return (void *)-1;
/* This can happen with bitfields. */
if (maybe_ne (ref->size, r.size))
@@ -5100,18 +5105,15 @@ vn_nary_may_trap (vn_nary_op_t nary)
honor_nans = flag_trapping_math && !flag_finite_math_only;
honor_snans = flag_signaling_nans != 0;
}
- else if (INTEGRAL_TYPE_P (type)
- && TYPE_OVERFLOW_TRAPS (type))
+ else if (INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_TRAPS (type))
honor_trapv = true;
}
if (nary->length >= 2)
rhs2 = nary->op[1];
ret = operation_could_trap_helper_p (nary->opcode, fp_operation,
- honor_trapv,
- honor_nans, honor_snans, rhs2,
- &handled);
- if (handled
- && ret)
+ honor_trapv, honor_nans, honor_snans,
+ rhs2, &handled);
+ if (handled && ret)
return true;
for (i = 0; i < nary->length; ++i)
@@ -5539,8 +5541,48 @@ eliminate_dom_walker::eliminate_stmt (basic_block b, gimple_stmt_iterator *gsi)
tree val;
tree rhs = gimple_assign_rhs1 (stmt);
vn_reference_t vnresult;
- val = vn_reference_lookup (lhs, gimple_vuse (stmt), VN_WALKREWRITE,
- &vnresult, false);
+ /* ??? gcc.dg/torture/pr91445.c shows that we lookup a boolean
+ typed load of a byte known to be 0x11 as 1 so a store of
+ a boolean 1 is detected as redundant. Because of this we
+ have to make sure to lookup with a ref where its size
+ matches the precision. */
+ tree lookup_lhs = lhs;
+ if (INTEGRAL_TYPE_P (TREE_TYPE (lhs))
+ && (TREE_CODE (lhs) != COMPONENT_REF
+ || !DECL_BIT_FIELD_TYPE (TREE_OPERAND (lhs, 1)))
+ && !type_has_mode_precision_p (TREE_TYPE (lhs)))
+ {
+ if (TREE_CODE (lhs) == COMPONENT_REF
+ || TREE_CODE (lhs) == MEM_REF)
+ {
+ tree ltype = build_nonstandard_integer_type
+ (TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (lhs))),
+ TYPE_UNSIGNED (TREE_TYPE (lhs)));
+ if (TREE_CODE (lhs) == COMPONENT_REF)
+ {
+ tree foff = component_ref_field_offset (lhs);
+ tree f = TREE_OPERAND (lhs, 1);
+ if (!poly_int_tree_p (foff))
+ lookup_lhs = NULL_TREE;
+ else
+ lookup_lhs = build3 (BIT_FIELD_REF, ltype,
+ TREE_OPERAND (lhs, 0),
+ TYPE_SIZE (TREE_TYPE (lhs)),
+ bit_from_pos
+ (foff, DECL_FIELD_BIT_OFFSET (f)));
+ }
+ else
+ lookup_lhs = build2 (MEM_REF, ltype,
+ TREE_OPERAND (lhs, 0),
+ TREE_OPERAND (lhs, 1));
+ }
+ else
+ lookup_lhs = NULL_TREE;
+ }
+ val = NULL_TREE;
+ if (lookup_lhs)
+ val = vn_reference_lookup (lookup_lhs, gimple_vuse (stmt), VN_WALK,
+ &vnresult, false);
if (TREE_CODE (rhs) == SSA_NAME)
rhs = VN_INFO (rhs)->valnum;
if (val
diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c
index d68df19aa82..ef2717d6a29 100644
--- a/gcc/tree-ssa-strlen.c
+++ b/gcc/tree-ssa-strlen.c
@@ -915,6 +915,7 @@ get_range_strlen_dynamic (tree src, c_strlen_data *pdata, bitmap *visited,
&& tree_int_cst_lt (pdata->maxlen, argdata.maxlen)))
pdata->maxlen = argdata.maxlen;
if (!pdata->maxbound
+ || TREE_CODE (pdata->maxbound) != INTEGER_CST
|| (argdata.maxbound
&& tree_int_cst_lt (pdata->maxbound,
argdata.maxbound)
@@ -1042,6 +1043,7 @@ get_range_strlen_dynamic (tree src, c_strlen_data *pdata,
const vr_values *rvals)
{
bitmap visited = NULL;
+ tree maxbound = pdata->maxbound;
unsigned limit = PARAM_VALUE (PARAM_SSA_NAME_DEF_CHAIN_LIMIT);
if (!get_range_strlen_dynamic (src, pdata, &visited, rvals, &limit))
@@ -1055,6 +1057,11 @@ get_range_strlen_dynamic (tree src, c_strlen_data *pdata,
else if (!pdata->minlen)
pdata->minlen = ssize_int (0);
+ /* If it's unchanged from it initial non-null value, set the conservative
+ MAXBOUND to SIZE_MAX. Otherwise leave it null (if it is null). */
+ if (maxbound && pdata->maxbound == maxbound)
+ pdata->maxbound = build_all_ones_cst (size_type_node);
+
if (visited)
BITMAP_FREE (visited);
}
@@ -2454,6 +2461,9 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt)
else
{
c_strlen_data lendata = { };
+ /* Set MAXBOUND to an arbitrary non-null non-integer node as a request
+ to have it set to the length of the longest string in a PHI. */
+ lendata.maxbound = src;
get_range_strlen (src, &lendata, /* eltsize = */1);
if (TREE_CODE (lendata.minlen) == INTEGER_CST
&& TREE_CODE (lendata.maxbound) == INTEGER_CST)
@@ -3226,51 +3236,78 @@ handle_builtin_memset (gimple_stmt_iterator *gsi)
return true;
}
-/* Handle a call to memcmp. We try to handle small comparisons by
- converting them to load and compare, and replacing the call to memcmp
- with a __builtin_memcmp_eq call where possible.
- return true when call is transformed, return false otherwise. */
+/* Return a pointer to the first such equality expression if RES is used
+ only in expressions testing its equality to zero, and null otherwise. */
-static bool
-handle_builtin_memcmp (gimple_stmt_iterator *gsi)
+static gimple *
+used_only_for_zero_equality (tree res)
{
- gcall *stmt2 = as_a <gcall *> (gsi_stmt (*gsi));
- tree res = gimple_call_lhs (stmt2);
- tree arg1 = gimple_call_arg (stmt2, 0);
- tree arg2 = gimple_call_arg (stmt2, 1);
- tree len = gimple_call_arg (stmt2, 2);
- unsigned HOST_WIDE_INT leni;
+ gimple *first_use = NULL;
+
use_operand_p use_p;
imm_use_iterator iter;
- if (!res)
- return false;
-
FOR_EACH_IMM_USE_FAST (use_p, iter, res)
{
- gimple *ustmt = USE_STMT (use_p);
+ gimple *use_stmt = USE_STMT (use_p);
- if (is_gimple_debug (ustmt))
- continue;
- if (gimple_code (ustmt) == GIMPLE_ASSIGN)
+ if (is_gimple_debug (use_stmt))
+ continue;
+ if (gimple_code (use_stmt) == GIMPLE_ASSIGN)
{
- gassign *asgn = as_a <gassign *> (ustmt);
- tree_code code = gimple_assign_rhs_code (asgn);
- if ((code != EQ_EXPR && code != NE_EXPR)
- || !integer_zerop (gimple_assign_rhs2 (asgn)))
- return false;
+ tree_code code = gimple_assign_rhs_code (use_stmt);
+ if (code == COND_EXPR)
+ {
+ tree cond_expr = gimple_assign_rhs1 (use_stmt);
+ if ((TREE_CODE (cond_expr) != EQ_EXPR
+ && (TREE_CODE (cond_expr) != NE_EXPR))
+ || !integer_zerop (TREE_OPERAND (cond_expr, 1)))
+ return NULL;
+ }
+ else if (code == EQ_EXPR || code == NE_EXPR)
+ {
+ if (!integer_zerop (gimple_assign_rhs2 (use_stmt)))
+ return NULL;
+ }
+ else
+ return NULL;
}
- else if (gimple_code (ustmt) == GIMPLE_COND)
+ else if (gimple_code (use_stmt) == GIMPLE_COND)
{
- tree_code code = gimple_cond_code (ustmt);
+ tree_code code = gimple_cond_code (use_stmt);
if ((code != EQ_EXPR && code != NE_EXPR)
- || !integer_zerop (gimple_cond_rhs (ustmt)))
- return false;
+ || !integer_zerop (gimple_cond_rhs (use_stmt)))
+ return NULL;
}
else
- return false;
+ return NULL;
+
+ if (!first_use)
+ first_use = use_stmt;
}
+ return first_use;
+}
+
+/* Handle a call to memcmp. We try to handle small comparisons by
+ converting them to load and compare, and replacing the call to memcmp
+ with a __builtin_memcmp_eq call where possible.
+ return true when call is transformed, return false otherwise. */
+
+static bool
+handle_builtin_memcmp (gimple_stmt_iterator *gsi)
+{
+ gcall *stmt = as_a <gcall *> (gsi_stmt (*gsi));
+ tree res = gimple_call_lhs (stmt);
+
+ if (!res || !used_only_for_zero_equality (res))
+ return false;
+
+ tree arg1 = gimple_call_arg (stmt, 0);
+ tree arg2 = gimple_call_arg (stmt, 1);
+ tree len = gimple_call_arg (stmt, 2);
+ unsigned HOST_WIDE_INT leni;
+
if (tree_fits_uhwi_p (len)
&& (leni = tree_to_uhwi (len)) <= GET_MODE_SIZE (word_mode)
&& pow2p_hwi (leni))
@@ -3283,7 +3320,7 @@ handle_builtin_memcmp (gimple_stmt_iterator *gsi)
if (int_mode_for_size (leni, 1).exists (&mode)
&& (align >= leni || !targetm.slow_unaligned_access (mode, align)))
{
- location_t loc = gimple_location (stmt2);
+ location_t loc = gimple_location (stmt);
tree type, off;
type = build_nonstandard_integer_type (leni, 1);
gcc_assert (known_eq (GET_MODE_BITSIZE (TYPE_MODE (type)), leni));
@@ -3307,78 +3344,10 @@ handle_builtin_memcmp (gimple_stmt_iterator *gsi)
}
}
- gimple_call_set_fndecl (stmt2, builtin_decl_explicit (BUILT_IN_MEMCMP_EQ));
+ gimple_call_set_fndecl (stmt, builtin_decl_explicit (BUILT_IN_MEMCMP_EQ));
return true;
}
-/* If IDX1 and IDX2 refer to strings A and B of unequal lengths, return
- the result of 0 == strncmp (A, B, N) (which is the same as strcmp for
- sufficiently large N). Otherwise return false. */
-
-static bool
-strxcmp_unequal (int idx1, int idx2, unsigned HOST_WIDE_INT n)
-{
- unsigned HOST_WIDE_INT len1;
- unsigned HOST_WIDE_INT len2;
-
- bool nulterm1;
- bool nulterm2;
-
- if (idx1 < 0)
- {
- len1 = ~idx1;
- nulterm1 = true;
- }
- else if (strinfo *si = get_strinfo (idx1))
- {
- if (tree_fits_uhwi_p (si->nonzero_chars))
- {
- len1 = tree_to_uhwi (si->nonzero_chars);
- nulterm1 = si->full_string_p;
- }
- else
- return false;
- }
- else
- return false;
-
- if (idx2 < 0)
- {
- len2 = ~idx2;
- nulterm2 = true;
- }
- else if (strinfo *si = get_strinfo (idx2))
- {
- if (tree_fits_uhwi_p (si->nonzero_chars))
- {
- len2 = tree_to_uhwi (si->nonzero_chars);
- nulterm2 = si->full_string_p;
- }
- else
- return false;
- }
- else
- return false;
-
- /* N is set to UHWI_MAX for strcmp and less to strncmp. Adjust
- the length of each string to consider to be no more than N. */
- if (len1 > n)
- len1 = n;
- if (len2 > n)
- len2 = n;
-
- if ((len1 < len2 && nulterm1)
- || (len2 < len1 && nulterm2))
- /* The string lengths are definitely unequal and the result can
- be folded to one (since it's used for comparison with zero). */
- return true;
-
- /* The string lengths may be equal or unequal. Even when equal and
- both strings nul-terminated, without the string contents there's
- no way to determine whether they are equal. */
- return false;
-}
-
/* Given an index to the strinfo vector, compute the string length
for the corresponding string. Return -1 when unknown. */
@@ -3407,15 +3376,16 @@ compute_string_length (int idx)
/* Determine the minimum size of the object referenced by DEST expression
which must have a pointer type.
- Return the minimum size of the object if successful or NULL when the size
- cannot be determined. */
-static tree
+ Return the minimum size of the object if successful or HWI_M1U when
+ the size cannot be determined. */
+
+static unsigned HOST_WIDE_INT
determine_min_objsize (tree dest)
{
unsigned HOST_WIDE_INT size = 0;
if (compute_builtin_object_size (dest, 2, &size))
- return build_int_cst (sizetype, size);
+ return size;
/* Try to determine the size of the object through the RHS
of the assign statement. */
@@ -3423,11 +3393,11 @@ determine_min_objsize (tree dest)
{
gimple *stmt = SSA_NAME_DEF_STMT (dest);
if (!is_gimple_assign (stmt))
- return NULL_TREE;
+ return HOST_WIDE_INT_M1U;
if (!gimple_assign_single_p (stmt)
&& !gimple_assign_unary_nop_p (stmt))
- return NULL_TREE;
+ return HOST_WIDE_INT_M1U;
dest = gimple_assign_rhs1 (stmt);
return determine_min_objsize (dest);
@@ -3435,7 +3405,7 @@ determine_min_objsize (tree dest)
/* Try to determine the size of the object from its type. */
if (TREE_CODE (dest) != ADDR_EXPR)
- return NULL_TREE;
+ return HOST_WIDE_INT_M1U;
tree type = TREE_TYPE (dest);
if (TREE_CODE (type) == POINTER_TYPE)
@@ -3443,196 +3413,388 @@ determine_min_objsize (tree dest)
type = TYPE_MAIN_VARIANT (type);
- /* We cannot determine the size of the array if it's a flexible array,
- which is declared at the end of a structure. */
- if (TREE_CODE (type) == ARRAY_TYPE
- && !array_at_struct_end_p (dest))
+ /* The size of a flexible array cannot be determined. Otherwise,
+ for arrays with more than one element, return the size of its
+ type. GCC itself misuses arrays of both zero and one elements
+ as flexible array members so they are excluded as well. */
+ if (TREE_CODE (type) != ARRAY_TYPE
+ || !array_at_struct_end_p (dest))
{
- tree size_t = TYPE_SIZE_UNIT (type);
- if (size_t && TREE_CODE (size_t) == INTEGER_CST
- && !integer_zerop (size_t))
- return size_t;
+ tree type_size = TYPE_SIZE_UNIT (type);
+ if (type_size && TREE_CODE (type_size) == INTEGER_CST
+ && !integer_onep (type_size)
+ && !integer_zerop (type_size))
+ return tree_to_uhwi (type_size);
}
- return NULL_TREE;
+ return HOST_WIDE_INT_M1U;
}
-/* Handle a call to strcmp or strncmp. When the result is ONLY used to do
- equality test against zero:
-
- A. When the lengths of both arguments are constant and it's a strcmp:
- * if the lengths are NOT equal, we can safely fold the call
- to a non-zero value.
- * otherwise, do nothing now.
-
- B. When the length of one argument is constant, try to replace the call
- with a __builtin_str(n)cmp_eq call where possible, i.e:
-
- strncmp (s, STR, C) (!)= 0 in which, s is a pointer to a string, STR
- is a string with constant length , C is a constant.
- if (C <= strlen(STR) && sizeof_array(s) > C)
- {
- replace this call with
- strncmp_eq (s, STR, C) (!)= 0
- }
- if (C > strlen(STR)
- {
- it can be safely treated as a call to strcmp (s, STR) (!)= 0
- can handled by the following strcmp.
- }
-
- strcmp (s, STR) (!)= 0 in which, s is a pointer to a string, STR
- is a string with constant length.
- if (sizeof_array(s) > strlen(STR))
- {
- replace this call with
- strcmp_eq (s, STR, strlen(STR)+1) (!)= 0
- }
-
- Return true when the call is transformed, return false otherwise.
- */
+/* Given strinfo IDX for ARG, set LENRNG[] to the range of lengths
+ of the string(s) referenced by ARG if it can be determined.
+ If the length cannot be determined, set *SIZE to the size of
+ the array the string is stored in, if any. If no such array is
+ known, set *SIZE to -1. When the strings are nul-terminated set
+ *NULTERM to true, otherwise to false. Return true on success. */
static bool
-handle_builtin_string_cmp (gimple_stmt_iterator *gsi)
+get_len_or_size (tree arg, int idx, unsigned HOST_WIDE_INT lenrng[2],
+ unsigned HOST_WIDE_INT *size, bool *nulterm)
{
- gcall *stmt = as_a <gcall *> (gsi_stmt (*gsi));
- tree res = gimple_call_lhs (stmt);
- use_operand_p use_p;
- imm_use_iterator iter;
- tree arg1 = gimple_call_arg (stmt, 0);
- tree arg2 = gimple_call_arg (stmt, 1);
- int idx1 = get_stridx (arg1);
- int idx2 = get_stridx (arg2);
- HOST_WIDE_INT length = -1;
- bool is_ncmp = false;
-
- if (!res)
- return false;
+ /* Set so that both LEN and ~LEN are invalid lengths, i.e.,
+ maximum possible length + 1. */
+ lenrng[0] = lenrng[1] = HOST_WIDE_INT_MAX;
- /* When both arguments are unknown, do nothing. */
- if (idx1 == 0 && idx2 == 0)
- return false;
+ *size = HOST_WIDE_INT_M1U;
- /* Handle strncmp function. */
- if (gimple_call_num_args (stmt) == 3)
+ if (idx < 0)
{
- tree len = gimple_call_arg (stmt, 2);
- if (tree_fits_shwi_p (len))
- length = tree_to_shwi (len);
-
- is_ncmp = true;
+ /* IDX is the inverted constant string length. */
+ lenrng[0] = ~idx;
+ lenrng[1] = lenrng[0];
+ *nulterm = true;
}
-
- /* For strncmp, if the length argument is NOT known, do nothing. */
- if (is_ncmp && length < 0)
- return false;
-
- /* When the result is ONLY used to do equality test against zero. */
- FOR_EACH_IMM_USE_FAST (use_p, iter, res)
+ else if (idx == 0)
+ ; /* Handled below. */
+ else if (strinfo *si = get_strinfo (idx))
{
- gimple *use_stmt = USE_STMT (use_p);
+ if (!si->nonzero_chars)
+ arg = si->ptr;
+ else if (tree_fits_uhwi_p (si->nonzero_chars))
+ {
+ lenrng[0] = tree_to_uhwi (si->nonzero_chars);
+ *nulterm = si->full_string_p;
+ /* Set the upper bound only if the string is known to be
+ nul-terminated, otherwise leave it at maximum + 1. */
+ if (*nulterm)
+ lenrng[1] = lenrng[0];
+ }
+ else if (TREE_CODE (si->nonzero_chars) == SSA_NAME)
+ {
+ wide_int min, max;
+ value_range_kind rng = get_range_info (si->nonzero_chars, &min, &max);
+ if (rng == VR_RANGE)
+ {
+ lenrng[0] = min.to_uhwi ();
+ lenrng[1] = max.to_uhwi ();
+ *nulterm = si->full_string_p;
+ }
+ }
+ else if (si->ptr)
+ arg = si->ptr;
+ }
- if (is_gimple_debug (use_stmt))
- continue;
- if (gimple_code (use_stmt) == GIMPLE_ASSIGN)
+ if (lenrng[0] == HOST_WIDE_INT_MAX)
+ {
+ /* Compute the minimum and maximum real or possible lengths. */
+ c_strlen_data lendata = { };
+ if (get_range_strlen (arg, &lendata, /* eltsize = */1))
{
- tree_code code = gimple_assign_rhs_code (use_stmt);
- if (code == COND_EXPR)
+ if (tree_fits_shwi_p (lendata.maxlen) && !lendata.maxbound)
{
- tree cond_expr = gimple_assign_rhs1 (use_stmt);
- if ((TREE_CODE (cond_expr) != EQ_EXPR
- && (TREE_CODE (cond_expr) != NE_EXPR))
- || !integer_zerop (TREE_OPERAND (cond_expr, 1)))
- return false;
+ lenrng[0] = tree_to_shwi (lendata.minlen);
+ lenrng[1] = tree_to_shwi (lendata.maxlen);
+ *nulterm = true;
}
- else if (code == EQ_EXPR || code == NE_EXPR)
+ else if (lendata.maxbound && tree_fits_shwi_p (lendata.maxbound))
{
- if (!integer_zerop (gimple_assign_rhs2 (use_stmt)))
- return false;
- }
- else
- return false;
+ /* Set *SIZE to the conservative LENDATA.MAXBOUND which
+ is a conservative estimate of the longest string based
+ on the sizes of the arrays referenced by ARG. */
+ *size = tree_to_uhwi (lendata.maxbound) + 1;
+ *nulterm = false;
+ }
}
- else if (gimple_code (use_stmt) == GIMPLE_COND)
+ else
{
- tree_code code = gimple_cond_code (use_stmt);
- if ((code != EQ_EXPR && code != NE_EXPR)
- || !integer_zerop (gimple_cond_rhs (use_stmt)))
- return false;
+ /* Set *SIZE to the size of the smallest object referenced
+ by ARG if ARG denotes a single object, or to HWI_M1U
+ otherwise. */
+ *size = determine_min_objsize (arg);
+ *nulterm = false;
}
- else
- return false;
}
- /* When the lengths of the arguments are known to be unequal
- we can safely fold the call to a non-zero value for strcmp;
- otherwise, do nothing now. */
- if (idx1 != 0 && idx2 != 0)
- {
- if (strxcmp_unequal (idx1, idx2, length))
- {
- replace_call_with_value (gsi, integer_one_node);
- return true;
- }
- return false;
+ return lenrng[0] != HOST_WIDE_INT_MAX || *size != HOST_WIDE_INT_M1U;
+}
+
+/* If IDX1 and IDX2 refer to strings A and B of unequal lengths, return
+ the result of 0 == strncmp (A, B, BOUND) (which is the same as strcmp
+ for a sufficiently large BOUND). If the result is based on the length
+ of one string being greater than the longest string that would fit in
+ the array pointer to by the argument, set *PLEN and *PSIZE to
+ the corresponding length (or its complement when the string is known
+ to be at least as long and need not be nul-terminated) and size.
+ Otherwise return null. */
+
+static tree
+strxcmp_eqz_result (tree arg1, int idx1, tree arg2, int idx2,
+ unsigned HOST_WIDE_INT bound, unsigned HOST_WIDE_INT len[2],
+ unsigned HOST_WIDE_INT *psize)
+{
+ /* Determine the range the length of each string is in and whether it's
+ known to be nul-terminated, or the size of the array it's stored in. */
+ bool nul1, nul2;
+ unsigned HOST_WIDE_INT siz1, siz2;
+ unsigned HOST_WIDE_INT len1rng[2], len2rng[2];
+ if (!get_len_or_size (arg1, idx1, len1rng, &siz1, &nul1)
+ || !get_len_or_size (arg2, idx2, len2rng, &siz2, &nul2))
+ return NULL_TREE;
+
+ /* BOUND is set to HWI_M1U for strcmp and less to strncmp, and LENiRNG
+ to HWI_MAX when invalid. Adjust the length of each string to consider
+ to be no more than BOUND. */
+ if (len1rng[0] < HOST_WIDE_INT_MAX && len1rng[0] > bound)
+ len1rng[0] = bound;
+ if (len1rng[1] < HOST_WIDE_INT_MAX && len1rng[1] > bound)
+ len1rng[1] = bound;
+ if (len2rng[0] < HOST_WIDE_INT_MAX && len2rng[0] > bound)
+ len2rng[0] = bound;
+ if (len2rng[1] < HOST_WIDE_INT_MAX && len2rng[1] > bound)
+ len2rng[1] = bound;
+
+ /* Two empty strings are equal. */
+ if (len1rng[1] == 0 && len2rng[1] == 0)
+ return integer_one_node;
+
+ /* The strings are definitely unequal when the lower bound of the length
+ of one of them is greater than the length of the longest string that
+ would fit into the other array. */
+ if (len1rng[0] == HOST_WIDE_INT_MAX
+ && len2rng[0] != HOST_WIDE_INT_MAX
+ && ((len2rng[0] < bound && len2rng[0] >= siz1)
+ || len2rng[0] > siz1))
+ {
+ *psize = siz1;
+ len[0] = len1rng[0];
+ /* Set LEN[0] to the lower bound of ARG1's length when it's
+ nul-terminated or to the complement of its minimum length
+ otherwise, */
+ len[1] = nul2 ? len2rng[0] : ~len2rng[0];
+ return integer_zero_node;
+ }
+
+ if (len2rng[0] == HOST_WIDE_INT_MAX
+ && len1rng[0] != HOST_WIDE_INT_MAX
+ && ((len1rng[0] < bound && len1rng[0] >= siz2)
+ || len1rng[0] > siz2))
+ {
+ *psize = siz2;
+ len[0] = nul1 ? len1rng[0] : ~len1rng[0];
+ len[1] = len2rng[0];
+ return integer_zero_node;
+ }
+
+ /* The strings are also definitely unequal when their lengths are unequal
+ and at least one is nul-terminated. */
+ if (len1rng[0] != HOST_WIDE_INT_MAX
+ && len2rng[0] != HOST_WIDE_INT_MAX
+ && ((len1rng[1] < len2rng[0] && nul1)
+ || (len2rng[1] < len1rng[0] && nul2)))
+ {
+ if (bound <= len1rng[0] || bound <= len2rng[0])
+ *psize = bound;
+ else
+ *psize = HOST_WIDE_INT_M1U;
+
+ len[0] = len1rng[0];
+ len[1] = len2rng[0];
+ return integer_zero_node;
}
- /* When the length of one argument is constant. */
- tree var_string = NULL_TREE;
- HOST_WIDE_INT const_string_leni = -1;
+ /* The string lengths may be equal or unequal. Even when equal and
+ both strings nul-terminated, without the string contents there's
+ no way to determine whether they are equal. */
+ return NULL_TREE;
+}
- if (idx1)
+/* Diagnose pointless calls to strcmp or strncmp STMT with string
+ arguments of lengths LEN or size SIZ and (for strncmp) BOUND,
+ whose result is used in equality expressions that evaluate to
+ a constant due to one argument being longer than the size of
+ the other. */
+
+static void
+maybe_warn_pointless_strcmp (gimple *stmt, HOST_WIDE_INT bound,
+ unsigned HOST_WIDE_INT len[2],
+ unsigned HOST_WIDE_INT siz)
+{
+ gimple *use = used_only_for_zero_equality (gimple_call_lhs (stmt));
+ if (!use)
+ return;
+
+ bool at_least = false;
+
+ /* Excessive LEN[i] indicates a lower bound. */
+ if (len[0] > HOST_WIDE_INT_MAX)
{
- const_string_leni = compute_string_length (idx1);
- var_string = arg2;
+ at_least = true;
+ len[0] = ~len[0];
}
- else
+
+ if (len[1] > HOST_WIDE_INT_MAX)
{
- gcc_checking_assert (idx2);
- const_string_leni = compute_string_length (idx2);
- var_string = arg1;
+ at_least = true;
+ len[1] = ~len[1];
}
- if (const_string_leni < 0)
- return false;
+ unsigned HOST_WIDE_INT minlen = MIN (len[0], len[1]);
- unsigned HOST_WIDE_INT var_sizei = 0;
- /* try to determine the minimum size of the object pointed by var_string. */
- tree size = determine_min_objsize (var_string);
+ /* FIXME: Include a note pointing to the declaration of the smaller
+ array. */
+ location_t stmt_loc = gimple_location (stmt);
+ tree callee = gimple_call_fndecl (stmt);
+ bool warned = false;
+ if (siz <= minlen && bound == -1)
+ warned = warning_at (stmt_loc, OPT_Wstring_compare,
+ (at_least
+ ? G_("%G%qD of a string of length %wu or more and "
+ "an array of size %wu evaluates to nonzero")
+ : G_("%G%qD of a string of length %wu and an array "
+ "of size %wu evaluates to nonzero")),
+ stmt, callee, minlen, siz);
+ else if (!at_least && siz <= HOST_WIDE_INT_MAX)
+ {
+ if (len[0] != HOST_WIDE_INT_MAX && len[1] != HOST_WIDE_INT_MAX)
+ warned = warning_at (stmt_loc, OPT_Wstring_compare,
+ "%G%qD of strings of length %wu and %wu "
+ "and bound of %wu evaluates to nonzero",
+ stmt, callee, len[0], len[1], bound);
+ else
+ warned = warning_at (stmt_loc, OPT_Wstring_compare,
+ "%G%qD of a string of length %wu, an array "
+ "of size %wu and bound of %wu evaluates to "
+ "nonzero",
+ stmt, callee, minlen, siz, bound);
+ }
+
+ if (warned)
+ {
+ location_t use_loc = gimple_location (use);
+ if (LOCATION_LINE (stmt_loc) != LOCATION_LINE (use_loc))
+ inform (use_loc, "in this expression");
+ }
+}
- if (!size)
- return false;
- if (tree_fits_uhwi_p (size))
- var_sizei = tree_to_uhwi (size);
+/* Optimize a call to strcmp or strncmp either by folding it to a constant
+ when possible or by transforming the latter to the former. Warn about
+ calls where the length of one argument is greater than the size of
+ the array to which the other argument points if the latter's length
+ is not known. Return true when the call has been transformed into
+ another and false otherwise. */
+
+static bool
+handle_builtin_string_cmp (gimple_stmt_iterator *gsi)
+{
+ gcall *stmt = as_a <gcall *> (gsi_stmt (*gsi));
+ tree lhs = gimple_call_lhs (stmt);
- if (var_sizei == 0)
+ if (!lhs)
return false;
- /* For strncmp, if length > const_string_leni , this call can be safely
- transformed to a strcmp. */
- if (is_ncmp && length > const_string_leni)
- is_ncmp = false;
+ tree arg1 = gimple_call_arg (stmt, 0);
+ tree arg2 = gimple_call_arg (stmt, 1);
+ int idx1 = get_stridx (arg1);
+ int idx2 = get_stridx (arg2);
- unsigned HOST_WIDE_INT final_length
- = is_ncmp ? length : const_string_leni + 1;
+ /* For strncmp set to the the value of the third argument if known. */
+ HOST_WIDE_INT bound = -1;
- /* Replace strcmp or strncmp with the corresponding str(n)cmp_eq. */
- if (var_sizei > final_length)
+ /* Extract the strncmp bound. */
+ if (gimple_call_num_args (stmt) == 3)
{
- tree fn
- = (is_ncmp
- ? builtin_decl_implicit (BUILT_IN_STRNCMP_EQ)
- : builtin_decl_implicit (BUILT_IN_STRCMP_EQ));
- if (!fn)
+ tree len = gimple_call_arg (stmt, 2);
+ if (tree_fits_shwi_p (len))
+ bound = tree_to_shwi (len);
+
+ /* If the bound argument is NOT known, do nothing. */
+ if (bound < 0)
return false;
- tree const_string_len = build_int_cst (size_type_node, final_length);
- update_gimple_call (gsi, fn, 3, arg1, arg2, const_string_len);
}
+
+ {
+ /* Set to the length of one argument (or its complement if it's
+ the lower bound of a range) and the size of the array storing
+ the other if the result is based on the former being equal to
+ or greater than the latter. */
+ unsigned HOST_WIDE_INT len[2] = { HOST_WIDE_INT_MAX, HOST_WIDE_INT_MAX };
+ unsigned HOST_WIDE_INT siz = HOST_WIDE_INT_M1U;
+
+ /* Try to determine if the two strings are either definitely equal
+ or definitely unequal and if so, either fold the result to zero
+ (when equal) or set the range of the result to ~[0, 0] otherwise. */
+ if (tree eqz = strxcmp_eqz_result (arg1, idx1, arg2, idx2, bound,
+ len, &siz))
+ {
+ if (integer_zerop (eqz))
+ {
+ maybe_warn_pointless_strcmp (stmt, bound, len, siz);
+
+ /* When the lengths of the first two string arguments are
+ known to be unequal set the range of the result to non-zero.
+ This allows the call to be eliminated if its result is only
+ used in tests for equality to zero. */
+ wide_int zero = wi::zero (TYPE_PRECISION (TREE_TYPE (lhs)));
+ set_range_info (lhs, VR_ANTI_RANGE, zero, zero);
+ return false;
+ }
+ /* When the two strings are definitely equal (such as when they
+ are both empty) fold the call to the constant result. */
+ replace_call_with_value (gsi, integer_zero_node);
+ return true;
+ }
+ }
+
+ /* Return if nothing is known about the strings pointed to by ARG1
+ and ARG2. */
+ if (idx1 == 0 && idx2 == 0)
+ return false;
+
+ /* Determine either the length or the size of each of the strings,
+ whichever is available. */
+ HOST_WIDE_INT cstlen1 = -1, cstlen2 = -1;
+ HOST_WIDE_INT arysiz1 = -1, arysiz2 = -1;
+
+ if (idx1)
+ cstlen1 = compute_string_length (idx1) + 1;
else
+ arysiz1 = determine_min_objsize (arg1);
+
+ /* Bail if neither the string length nor the size of the array
+ it is stored in can be determined. */
+ if (cstlen1 < 0 && arysiz1 < 0)
return false;
- return true;
+ /* Repeat for the second argument. */
+ if (idx2)
+ cstlen2 = compute_string_length (idx2) + 1;
+ else
+ arysiz2 = determine_min_objsize (arg2);
+
+ if (cstlen2 < 0 && arysiz2 < 0)
+ return false;
+
+ /* The exact number of characters to compare. */
+ HOST_WIDE_INT cmpsiz = bound < 0 ? cstlen1 < 0 ? cstlen2 : cstlen1 : bound;
+ /* The size of the array in which the unknown string is stored. */
+ HOST_WIDE_INT varsiz = arysiz1 < 0 ? arysiz2 : arysiz1;
+
+ if (cmpsiz < varsiz && used_only_for_zero_equality (lhs))
+ {
+ /* If the known length is less than the size of the other array
+ and the strcmp result is only used to test equality to zero,
+ transform the call to the equivalent _eq call. */
+ if (tree fn = builtin_decl_implicit (bound < 0 ? BUILT_IN_STRCMP_EQ
+ : BUILT_IN_STRNCMP_EQ))
+ {
+ tree n = build_int_cst (size_type_node, cmpsiz);
+ update_gimple_call (gsi, fn, 3, arg1, arg2, n);
+ return true;
+ }
+ }
+
+ return false;
}
/* Handle a POINTER_PLUS_EXPR statement.
@@ -3741,13 +3903,16 @@ int ssa_name_limit_t::next_ssa_name (tree ssa_name)
return 0;
}
-/* Determine the minimum and maximum number of leading non-zero bytes
+/* Determines the minimum and maximum number of leading non-zero bytes
in the representation of EXP and set LENRANGE[0] and LENRANGE[1]
- to each. Set LENRANGE[2] to the total number of bytes in
- the representation. Set *NULTREM if the representation contains
- a zero byte, and set *ALLNUL if all the bytes are zero. Avoid
- recursing deeper than the limits in SNLIM allow. Return true
- on success and false otherwise. */
+ to each. Sets LENRANGE[2] to the total number of bytes in
+ the representation. Sets *NULTREM if the representation contains
+ a zero byte, and sets *ALLNUL if all the bytes are zero.
+ OFFSET and NBYTES are the offset into the representation and
+ the size of the access to it determined from a MEM_REF or zero
+ for other expressions.
+ Avoid recursing deeper than the limits in SNLIM allow.
+ Returns true on success and false otherwise. */
static bool
count_nonzero_bytes (tree exp, unsigned HOST_WIDE_INT offset,
@@ -3769,15 +3934,13 @@ count_nonzero_bytes (tree exp, unsigned HOST_WIDE_INT offset,
return false;
len -= offset;
- size -= offset;
-
- if (size < nbytes)
- return false;
if (len < lenrange[0])
lenrange[0] = len;
if (lenrange[1] < len)
lenrange[1] = len;
+ if (lenrange[2] < nbytes)
+ lenrange[2] = nbytes;
if (!si->full_string_p)
*nulterm = false;
@@ -3843,6 +4006,9 @@ count_nonzero_bytes (tree exp, unsigned HOST_WIDE_INT offset,
if (TREE_CODE (exp) == MEM_REF)
{
+ if (nbytes)
+ return false;
+
tree arg = TREE_OPERAND (exp, 0);
tree off = TREE_OPERAND (exp, 1);
@@ -3910,8 +4076,10 @@ count_nonzero_bytes (tree exp, unsigned HOST_WIDE_INT offset,
lenrange[0] = 0;
prep = NULL;
}
- else
+ else if (!nbytes)
nbytes = repsize;
+ else if (nbytes < repsize)
+ return false;
}
if (!nbytes)
diff --git a/gcc/tree-vect-data-refs.c b/gcc/tree-vect-data-refs.c
index 6390b1949b5..9a4c01d2860 100644
--- a/gcc/tree-vect-data-refs.c
+++ b/gcc/tree-vect-data-refs.c
@@ -2075,6 +2075,8 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
{
unsigned max_allowed_peel
= PARAM_VALUE (PARAM_VECT_MAX_PEELING_FOR_ALIGNMENT);
+ if (flag_vect_cost_model == VECT_COST_MODEL_CHEAP)
+ max_allowed_peel = 0;
if (max_allowed_peel != (unsigned)-1)
{
unsigned max_peel = npeel;
@@ -2168,15 +2170,16 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
/* (2) Versioning to force alignment. */
/* Try versioning if:
- 1) optimize loop for speed
+ 1) optimize loop for speed and the cost-model is not cheap
2) there is at least one unsupported misaligned data ref with an unknown
misalignment, and
3) all misaligned data refs with a known misalignment are supported, and
4) the number of runtime alignment checks is within reason. */
- do_versioning =
- optimize_loop_nest_for_speed_p (loop)
- && (!loop->inner); /* FORNOW */
+ do_versioning
+ = (optimize_loop_nest_for_speed_p (loop)
+ && !loop->inner /* FORNOW */
+ && flag_vect_cost_model != VECT_COST_MODEL_CHEAP);
if (do_versioning)
{
@@ -3641,13 +3644,15 @@ vect_prune_runtime_alias_test_list (loop_vec_info loop_vinfo)
dump_printf_loc (MSG_NOTE, vect_location,
"improved number of alias checks from %d to %d\n",
may_alias_ddrs.length (), count);
- if ((int) count > PARAM_VALUE (PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS))
+ unsigned limit = PARAM_VALUE (PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS);
+ if (flag_simd_cost_model == VECT_COST_MODEL_CHEAP)
+ limit = default_param_value
+ (PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS) * 6 / 10;
+ if (count > limit)
return opt_result::failure_at
(vect_location,
- "number of versioning for alias "
- "run-time tests exceeds %d "
- "(--param vect-max-version-for-alias-checks)\n",
- PARAM_VALUE (PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS));
+ "number of versioning for alias run-time tests exceeds %d "
+ "(--param vect-max-version-for-alias-checks)\n", limit);
return opt_result::success ();
}
diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c
index 3db4a5cdf78..cb95ea36298 100644
--- a/gcc/tree-vect-loop.c
+++ b/gcc/tree-vect-loop.c
@@ -154,8 +154,8 @@ along with GCC; see the file COPYING3. If not see
*/
static void vect_estimate_min_profitable_iters (loop_vec_info, int *, int *);
-static stmt_vec_info vect_force_simple_reduction (loop_vec_info, stmt_vec_info,
- bool *, bool);
+static stmt_vec_info vect_is_simple_reduction (loop_vec_info, stmt_vec_info,
+ bool *);
/* Subroutine of vect_determine_vf_for_stmt that handles only one
statement. VECTYPE_MAYBE_SET_P is true if STMT_VINFO_VECTYPE
@@ -561,19 +561,19 @@ vect_analyze_scalar_cycles_1 (loop_vec_info loop_vinfo, class loop *loop)
&& STMT_VINFO_DEF_TYPE (stmt_vinfo) == vect_unknown_def_type);
stmt_vec_info reduc_stmt_info
- = vect_force_simple_reduction (loop_vinfo, stmt_vinfo,
- &double_reduc, false);
+ = vect_is_simple_reduction (loop_vinfo, stmt_vinfo, &double_reduc);
if (reduc_stmt_info)
{
- if (double_reduc)
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_NOTE, vect_location,
+ STMT_VINFO_REDUC_DEF (stmt_vinfo) = reduc_stmt_info;
+ STMT_VINFO_REDUC_DEF (reduc_stmt_info) = stmt_vinfo;
+ if (double_reduc)
+ {
+ if (dump_enabled_p ())
+ dump_printf_loc (MSG_NOTE, vect_location,
"Detected double reduction.\n");
STMT_VINFO_DEF_TYPE (stmt_vinfo) = vect_double_reduction_def;
- STMT_VINFO_DEF_TYPE (reduc_stmt_info)
- = vect_double_reduction_def;
+ STMT_VINFO_DEF_TYPE (reduc_stmt_info) = vect_double_reduction_def;
}
else
{
@@ -1558,8 +1558,7 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo)
== vect_double_reduction_def)
|| STMT_VINFO_DEF_TYPE (stmt_info) == vect_nested_cycle)
&& ! PURE_SLP_STMT (stmt_info))
- ok = vectorizable_reduction (stmt_info, NULL, NULL, NULL, NULL,
- &cost_vec);
+ ok = vectorizable_reduction (stmt_info, NULL, NULL, &cost_vec);
}
/* SLP PHIs are tested by vect_slp_analyze_node_operations. */
@@ -1567,7 +1566,7 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo)
&& STMT_VINFO_LIVE_P (stmt_info)
&& !PURE_SLP_STMT (stmt_info))
ok = vectorizable_live_operation (stmt_info, NULL, NULL, NULL,
- -1, NULL, &cost_vec);
+ -1, false, &cost_vec);
if (!ok)
return opt_result::failure_at (phi,
@@ -2554,8 +2553,7 @@ vect_valid_reduction_input_p (stmt_vec_info def_stmt_info)
overflow must wrap. */
static bool
-needs_fold_left_reduction_p (tree type, tree_code code,
- bool need_wrapping_integral_overflow)
+needs_fold_left_reduction_p (tree type, tree_code code)
{
/* CHECKME: check for !flag_finite_math_only too? */
if (SCALAR_FLOAT_TYPE_P (type))
@@ -2573,10 +2571,6 @@ needs_fold_left_reduction_p (tree type, tree_code code,
{
if (!operation_no_trapping_overflow (type, code))
return true;
- if (need_wrapping_integral_overflow
- && !TYPE_OVERFLOW_WRAPS (type)
- && operation_can_overflow (code))
- return true;
return false;
}
@@ -2752,9 +2746,7 @@ check_reduction_path (dump_user_location_t loc, loop_p loop, gphi *phi,
static stmt_vec_info
vect_is_simple_reduction (loop_vec_info loop_info, stmt_vec_info phi_info,
- bool *double_reduc,
- bool need_wrapping_integral_overflow,
- enum vect_reduction_type *v_reduc_type)
+ bool *double_reduc)
{
gphi *phi = as_a <gphi *> (phi_info->stmt);
class loop *loop = (gimple_bb (phi))->loop_father;
@@ -2764,13 +2756,11 @@ vect_is_simple_reduction (loop_vec_info loop_info, stmt_vec_info phi_info,
enum tree_code orig_code, code;
tree op1, op2, op3 = NULL_TREE, op4 = NULL_TREE;
tree type;
- tree name;
imm_use_iterator imm_iter;
use_operand_p use_p;
- bool phi_def;
*double_reduc = false;
- *v_reduc_type = TREE_CODE_REDUCTION;
+ STMT_VINFO_REDUC_TYPE (phi_info) = TREE_CODE_REDUCTION;
tree phi_name = PHI_RESULT (phi);
/* ??? If there are no uses of the PHI result the inner loop reduction
@@ -2799,44 +2789,24 @@ vect_is_simple_reduction (loop_vec_info loop_info, stmt_vec_info phi_info,
phi_use_stmt = use_stmt;
}
- edge latch_e = loop_latch_edge (loop);
- tree loop_arg = PHI_ARG_DEF_FROM_EDGE (phi, latch_e);
- if (TREE_CODE (loop_arg) != SSA_NAME)
+ tree latch_def = PHI_ARG_DEF_FROM_EDGE (phi, loop_latch_edge (loop));
+ if (TREE_CODE (latch_def) != SSA_NAME)
{
if (dump_enabled_p ())
dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "reduction: not ssa_name: %T\n", loop_arg);
+ "reduction: not ssa_name: %T\n", latch_def);
return NULL;
}
- stmt_vec_info def_stmt_info = loop_info->lookup_def (loop_arg);
+ stmt_vec_info def_stmt_info = loop_info->lookup_def (latch_def);
if (!def_stmt_info
|| !flow_bb_inside_loop_p (loop, gimple_bb (def_stmt_info->stmt)))
return NULL;
- if (gassign *def_stmt = dyn_cast <gassign *> (def_stmt_info->stmt))
- {
- name = gimple_assign_lhs (def_stmt);
- phi_def = false;
- }
- else if (gphi *def_stmt = dyn_cast <gphi *> (def_stmt_info->stmt))
- {
- name = PHI_RESULT (def_stmt);
- phi_def = true;
- }
- else
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "reduction: unhandled reduction operation: %G",
- def_stmt_info->stmt);
- return NULL;
- }
-
unsigned nlatch_def_loop_uses = 0;
auto_vec<gphi *, 3> lcphis;
bool inner_loop_of_double_reduc = false;
- FOR_EACH_IMM_USE_FAST (use_p, imm_iter, name)
+ FOR_EACH_IMM_USE_FAST (use_p, imm_iter, latch_def)
{
gimple *use_stmt = USE_STMT (use_p);
if (is_gimple_debug (use_stmt))
@@ -2854,11 +2824,21 @@ vect_is_simple_reduction (loop_vec_info loop_info, stmt_vec_info phi_info,
}
}
+ /* If we are vectorizing an inner reduction we are executing that
+ in the original order only in case we are not dealing with a
+ double reduction. */
+ if (nested_in_vect_loop && !inner_loop_of_double_reduc)
+ {
+ if (dump_enabled_p ())
+ report_vect_op (MSG_NOTE, def_stmt_info->stmt,
+ "detected nested cycle: ");
+ return def_stmt_info;
+ }
+
/* If this isn't a nested cycle or if the nested cycle reduction value
is used ouside of the inner loop we cannot handle uses of the reduction
value. */
- if ((!nested_in_vect_loop || inner_loop_of_double_reduc)
- && (nlatch_def_loop_uses > 1 || nphi_def_loop_uses > 1))
+ if (nlatch_def_loop_uses > 1 || nphi_def_loop_uses > 1)
{
if (dump_enabled_p ())
dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
@@ -2868,9 +2848,8 @@ vect_is_simple_reduction (loop_vec_info loop_info, stmt_vec_info phi_info,
/* If DEF_STMT is a phi node itself, we expect it to have a single argument
defined in the inner loop. */
- if (phi_def)
+ if (gphi *def_stmt = dyn_cast <gphi *> (def_stmt_info->stmt))
{
- gphi *def_stmt = as_a <gphi *> (def_stmt_info->stmt);
op1 = PHI_ARG_DEF (def_stmt, 0);
if (gimple_phi_num_args (def_stmt) != 1
@@ -2903,51 +2882,16 @@ vect_is_simple_reduction (loop_vec_info loop_info, stmt_vec_info phi_info,
return NULL;
}
- /* If we are vectorizing an inner reduction we are executing that
- in the original order only in case we are not dealing with a
- double reduction. */
- bool check_reduction = true;
- if (flow_loop_nested_p (vect_loop, loop))
+ gassign *def_stmt = dyn_cast <gassign *> (def_stmt_info->stmt);
+ if (!def_stmt)
{
- gphi *lcphi;
- unsigned i;
- check_reduction = false;
- FOR_EACH_VEC_ELT (lcphis, i, lcphi)
- FOR_EACH_IMM_USE_FAST (use_p, imm_iter, gimple_phi_result (lcphi))
- {
- gimple *use_stmt = USE_STMT (use_p);
- if (is_gimple_debug (use_stmt))
- continue;
- if (! flow_bb_inside_loop_p (vect_loop, gimple_bb (use_stmt)))
- check_reduction = true;
- }
- }
-
- gassign *def_stmt = as_a <gassign *> (def_stmt_info->stmt);
- code = orig_code = gimple_assign_rhs_code (def_stmt);
-
- if (nested_in_vect_loop && !check_reduction)
- {
- /* FIXME: Even for non-reductions code generation is funneled
- through vectorizable_reduction for the stmt defining the
- PHI latch value. So we have to artificially restrict ourselves
- for the supported operations. */
- switch (get_gimple_rhs_class (code))
- {
- case GIMPLE_BINARY_RHS:
- case GIMPLE_TERNARY_RHS:
- break;
- default:
- /* Not supported by vectorizable_reduction. */
- if (dump_enabled_p ())
- report_vect_op (MSG_MISSED_OPTIMIZATION, def_stmt,
- "nested cycle: not handled operation: ");
- return NULL;
- }
if (dump_enabled_p ())
- report_vect_op (MSG_NOTE, def_stmt, "detected nested cycle: ");
- return def_stmt_info;
+ dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+ "reduction: unhandled reduction operation: %G",
+ def_stmt_info->stmt);
+ return NULL;
}
+ code = orig_code = gimple_assign_rhs_code (def_stmt);
/* We can handle "res -= x[i]", which is non-associative by
simply rewriting this into "res += -x[i]". Avoid changing
@@ -2959,7 +2903,7 @@ vect_is_simple_reduction (loop_vec_info loop_info, stmt_vec_info phi_info,
if (code == COND_EXPR)
{
if (! nested_in_vect_loop)
- *v_reduc_type = COND_REDUCTION;
+ STMT_VINFO_REDUC_TYPE (phi_info) = COND_REDUCTION;
op3 = gimple_assign_rhs1 (def_stmt);
if (COMPARISON_CLASS_P (op3))
@@ -3042,11 +2986,9 @@ vect_is_simple_reduction (loop_vec_info loop_info, stmt_vec_info phi_info,
vectorizing an outer-loop: the inner-loop is executed sequentially,
and therefore vectorizing reductions in the inner-loop during
outer-loop vectorization is safe. */
- if (check_reduction
- && *v_reduc_type == TREE_CODE_REDUCTION
- && needs_fold_left_reduction_p (type, code,
- need_wrapping_integral_overflow))
- *v_reduc_type = FOLD_LEFT_REDUCTION;
+ if (STMT_VINFO_REDUC_TYPE (phi_info) == TREE_CODE_REDUCTION
+ && needs_fold_left_reduction_p (type, code))
+ STMT_VINFO_REDUC_TYPE (phi_info) = FOLD_LEFT_REDUCTION;
/* Reduction is safe. We're dealing with one of the following:
1) integer arithmetic and no trapv
@@ -3091,9 +3033,9 @@ vect_is_simple_reduction (loop_vec_info loop_info, stmt_vec_info phi_info,
return def_stmt_info;
}
- /* Look for the expression computing loop_arg from loop PHI result. */
+ /* Look for the expression computing latch_def from loop PHI result. */
auto_vec<std::pair<ssa_op_iter, use_operand_p> > path;
- if (check_reduction_path (vect_location, loop, phi, loop_arg, code,
+ if (check_reduction_path (vect_location, loop, phi, latch_def, code,
path))
{
/* Try building an SLP reduction chain for which the additional
@@ -3142,30 +3084,6 @@ vect_is_simple_reduction (loop_vec_info loop_info, stmt_vec_info phi_info,
return NULL;
}
-/* Wrapper around vect_is_simple_reduction, which will modify code
- in-place if it enables detection of more reductions. Arguments
- as there. */
-
-static stmt_vec_info
-vect_force_simple_reduction (loop_vec_info loop_info, stmt_vec_info phi_info,
- bool *double_reduc,
- bool need_wrapping_integral_overflow)
-{
- enum vect_reduction_type v_reduc_type;
- stmt_vec_info def_info
- = vect_is_simple_reduction (loop_info, phi_info, double_reduc,
- need_wrapping_integral_overflow,
- &v_reduc_type);
- if (def_info)
- {
- STMT_VINFO_REDUC_TYPE (phi_info) = v_reduc_type;
- STMT_VINFO_REDUC_DEF (phi_info) = def_info;
- STMT_VINFO_REDUC_TYPE (def_info) = v_reduc_type;
- STMT_VINFO_REDUC_DEF (def_info) = phi_info;
- }
- return def_info;
-}
-
/* Calculate cost of peeling the loop PEEL_ITERS_PROLOGUE times. */
int
vect_get_known_peeling_cost (loop_vec_info loop_vinfo, int peel_iters_prologue,
@@ -3754,6 +3672,7 @@ have_whole_vector_shift (machine_mode mode)
static void
vect_model_reduction_cost (stmt_vec_info stmt_info, internal_fn reduc_fn,
+ vect_reduction_type reduction_type,
int ncopies, stmt_vector_for_cost *cost_vec)
{
int prologue_cost = 0, epilogue_cost = 0, inside_cost;
@@ -3768,8 +3687,6 @@ vect_model_reduction_cost (stmt_vec_info stmt_info, internal_fn reduc_fn,
loop = LOOP_VINFO_LOOP (loop_vinfo);
/* Condition reductions generate two reductions in the loop. */
- vect_reduction_type reduction_type
- = STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info);
if (reduction_type == COND_REDUCTION)
ncopies *= 2;
@@ -4208,6 +4125,32 @@ get_initial_defs_for_reduction (slp_tree slp_node,
gsi_insert_seq_on_edge_immediate (pe, ctor_seq);
}
+/* For a statement STMT_INFO taking part in a reduction operation return
+ the stmt_vec_info the meta information is stored on. */
+
+stmt_vec_info
+info_for_reduction (stmt_vec_info stmt_info)
+{
+ stmt_info = vect_orig_stmt (stmt_info);
+ gcc_assert (STMT_VINFO_REDUC_DEF (stmt_info));
+ if (!is_a <gphi *> (stmt_info->stmt))
+ stmt_info = STMT_VINFO_REDUC_DEF (stmt_info);
+ gphi *phi = as_a <gphi *> (stmt_info->stmt);
+ if (STMT_VINFO_DEF_TYPE (stmt_info) == vect_double_reduction_def)
+ {
+ if (gimple_phi_num_args (phi) == 1)
+ stmt_info = STMT_VINFO_REDUC_DEF (stmt_info);
+ }
+ else if (STMT_VINFO_DEF_TYPE (stmt_info) == vect_nested_cycle)
+ {
+ edge pe = loop_preheader_edge (gimple_bb (phi)->loop_father);
+ stmt_vec_info info
+ = stmt_info->vinfo->lookup_def (PHI_ARG_DEF_FROM_EDGE (phi, pe));
+ if (info && STMT_VINFO_DEF_TYPE (info) == vect_double_reduction_def)
+ stmt_info = info;
+ }
+ return stmt_info;
+}
/* Function vect_create_epilog_for_reduction
@@ -4261,6 +4204,8 @@ vect_create_epilog_for_reduction (stmt_vec_info stmt_info,
slp_tree slp_node,
slp_instance slp_node_instance)
{
+ stmt_vec_info reduc_info = info_for_reduction (stmt_info);
+ gcc_assert (reduc_info->is_reduc_info);
loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_info);
/* For double reductions we need to get at the inner loop reduction
stmt which has the meta info attached. Our stmt_info is that of the
@@ -4278,8 +4223,8 @@ vect_create_epilog_for_reduction (stmt_vec_info stmt_info,
}
gphi *reduc_def_stmt
= as_a <gphi *> (STMT_VINFO_REDUC_DEF (vect_orig_stmt (stmt_info))->stmt);
- enum tree_code code = STMT_VINFO_REDUC_CODE (stmt_info);
- internal_fn reduc_fn = STMT_VINFO_REDUC_FN (stmt_info);
+ enum tree_code code = STMT_VINFO_REDUC_CODE (reduc_info);
+ internal_fn reduc_fn = STMT_VINFO_REDUC_FN (reduc_info);
tree neutral_op = NULL_TREE;
if (slp_node)
neutral_op
@@ -4345,15 +4290,14 @@ vect_create_epilog_for_reduction (stmt_vec_info stmt_info,
loop_preheader_edge (loop));
/* Optimize: for induction condition reduction, if we can't use zero
for induc_val, use initial_def. */
- if (STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info)
- == INTEGER_INDUC_COND_REDUCTION)
- induc_val = STMT_VINFO_VEC_INDUC_COND_INITIAL_VAL (stmt_info);
+ if (STMT_VINFO_REDUC_TYPE (reduc_info) == INTEGER_INDUC_COND_REDUCTION)
+ induc_val = STMT_VINFO_VEC_INDUC_COND_INITIAL_VAL (reduc_info);
else if (double_reduc)
;
else if (nested_in_vect_loop)
;
else
- adjustment_def = STMT_VINFO_REDUC_EPILOGUE_ADJUSTMENT (stmt_info);
+ adjustment_def = STMT_VINFO_REDUC_EPILOGUE_ADJUSTMENT (reduc_info);
}
unsigned vec_num;
@@ -4383,7 +4327,7 @@ vect_create_epilog_for_reduction (stmt_vec_info stmt_info,
The first match will be a 1 to allow 0 to be used for non-matching
indexes. If there are no matches at all then the vector will be all
zeroes. */
- if (STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) == COND_REDUCTION)
+ if (STMT_VINFO_REDUC_TYPE (reduc_info) == COND_REDUCTION)
{
tree indx_before_incr, indx_after_incr;
poly_uint64 nunits_out = TYPE_VECTOR_SUBPARTS (vectype);
@@ -4616,7 +4560,7 @@ vect_create_epilog_for_reduction (stmt_vec_info stmt_info,
else
new_phi_result = PHI_RESULT (new_phis[0]);
- if (STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) == COND_REDUCTION
+ if (STMT_VINFO_REDUC_TYPE (reduc_info) == COND_REDUCTION
&& reduc_fn != IFN_LAST)
{
/* For condition reductions, we have a vector (NEW_PHI_RESULT) containing
@@ -4725,7 +4669,7 @@ vect_create_epilog_for_reduction (stmt_vec_info stmt_info,
gsi_insert_seq_before (&exit_gsi, stmts, GSI_SAME_STMT);
scalar_results.safe_push (new_temp);
}
- else if (STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) == COND_REDUCTION
+ else if (STMT_VINFO_REDUC_TYPE (reduc_info) == COND_REDUCTION
&& reduc_fn == IFN_LAST)
{
/* Condition reduction without supported IFN_REDUC_MAX. Generate
@@ -4838,8 +4782,7 @@ vect_create_epilog_for_reduction (stmt_vec_info stmt_info,
gimple_set_lhs (epilog_stmt, new_temp);
gsi_insert_before (&exit_gsi, epilog_stmt, GSI_SAME_STMT);
- if ((STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info)
- == INTEGER_INDUC_COND_REDUCTION)
+ if ((STMT_VINFO_REDUC_TYPE (reduc_info) == INTEGER_INDUC_COND_REDUCTION)
&& induc_val)
{
/* Earlier we set the initial value to be a vector if induc_val
@@ -5201,8 +5144,7 @@ vect_create_epilog_for_reduction (stmt_vec_info stmt_info,
scalar_results.safe_push (new_temp);
}
- if ((STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info)
- == INTEGER_INDUC_COND_REDUCTION)
+ if ((STMT_VINFO_REDUC_TYPE (reduc_info) == INTEGER_INDUC_COND_REDUCTION)
&& induc_val)
{
/* Earlier we set the initial value to be a vector if induc_val
@@ -5486,8 +5428,6 @@ vectorize_fold_left_reduction (stmt_vec_info stmt_info,
gcc_assert (!nested_in_vect_loop_p (loop, stmt_info));
gcc_assert (ncopies == 1);
gcc_assert (TREE_CODE_LENGTH (code) == binary_op);
- gcc_assert (STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info)
- == FOLD_LEFT_REDUCTION);
if (slp_node)
gcc_assert (known_eq (TYPE_VECTOR_SUBPARTS (vectype_out),
@@ -5762,8 +5702,7 @@ build_vect_cond_expr (enum tree_code code, tree vop[3], tree mask,
does *NOT* necessarily hold for reduction patterns. */
bool
-vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
- stmt_vec_info *vec_stmt, slp_tree slp_node,
+vectorizable_reduction (stmt_vec_info stmt_info, slp_tree slp_node,
slp_instance slp_node_instance,
stmt_vector_for_cost *cost_vec)
{
@@ -5774,9 +5713,7 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
class loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
enum tree_code code;
internal_fn reduc_fn;
- machine_mode vec_mode;
int op_type;
- optab optab;
enum vect_def_type dt, cond_reduc_dt = vect_unknown_def_type;
stmt_vec_info cond_stmt_vinfo = NULL;
tree scalar_type;
@@ -5799,6 +5736,69 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
&& STMT_VINFO_DEF_TYPE (stmt_info) != vect_nested_cycle)
return false;
+ /* The stmt we store reduction analysis meta on. */
+ stmt_vec_info reduc_info = info_for_reduction (stmt_info);
+ reduc_info->is_reduc_info = true;
+
+ if (STMT_VINFO_DEF_TYPE (stmt_info) == vect_nested_cycle)
+ {
+ if (is_a <gphi *> (stmt_info->stmt))
+ {
+ /* Analysis for double-reduction is done on the outer
+ loop PHI, nested cycles have no further restrictions. */
+ STMT_VINFO_TYPE (stmt_info) = cycle_phi_info_type;
+ /* For nested cycles we want to let regular vectorizable_*
+ routines handle code-generation. */
+ if (STMT_VINFO_DEF_TYPE (reduc_info) != vect_double_reduction_def)
+ {
+ stmt_info = STMT_VINFO_REDUC_DEF (stmt_info);
+ STMT_VINFO_DEF_TYPE (stmt_info) = vect_internal_def;
+ STMT_VINFO_DEF_TYPE (vect_stmt_to_vectorize (stmt_info))
+ = vect_internal_def;
+ }
+ }
+ else
+ STMT_VINFO_TYPE (stmt_info) = reduc_vec_info_type;
+ return true;
+ }
+
+ stmt_vec_info orig_stmt_of_analysis = stmt_info;
+ if (STMT_VINFO_DEF_TYPE (stmt_info) == vect_reduction_def
+ || STMT_VINFO_DEF_TYPE (stmt_info) == vect_double_reduction_def)
+ {
+ if (!is_a <gphi *> (stmt_info->stmt))
+ {
+ STMT_VINFO_TYPE (stmt_info) = reduc_vec_info_type;
+ return true;
+ }
+ if (slp_node)
+ {
+ slp_node_instance->reduc_phis = slp_node;
+ /* ??? We're leaving slp_node to point to the PHIs, we only
+ need it to get at the number of vector stmts which wasn't
+ yet initialized for the instance root. */
+ }
+ if (STMT_VINFO_DEF_TYPE (stmt_info) == vect_reduction_def)
+ stmt_info = vect_stmt_to_vectorize (STMT_VINFO_REDUC_DEF (stmt_info));
+ else /* STMT_VINFO_DEF_TYPE (stmt_info) == vect_double_reduction_def */
+ {
+ use_operand_p use_p;
+ gimple *use_stmt;
+ bool res = single_imm_use (gimple_phi_result (stmt_info->stmt),
+ &use_p, &use_stmt);
+ gcc_assert (res);
+ stmt_info = loop_vinfo->lookup_stmt (use_stmt);
+ stmt_info = vect_stmt_to_vectorize (STMT_VINFO_REDUC_DEF (stmt_info));
+ }
+ /* STMT_VINFO_REDUC_DEF doesn't point to the first but the last
+ element. */
+ if (slp_node && REDUC_GROUP_FIRST_ELEMENT (stmt_info))
+ {
+ gcc_assert (!REDUC_GROUP_NEXT_ELEMENT (stmt_info));
+ stmt_info = REDUC_GROUP_FIRST_ELEMENT (stmt_info);
+ }
+ }
+
if (nested_in_vect_loop_p (loop, stmt_info))
{
loop = loop->inner;
@@ -5809,18 +5809,6 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
gcc_assert (slp_node
&& REDUC_GROUP_FIRST_ELEMENT (stmt_info) == stmt_info);
- if (is_a <gphi *> (stmt_info->stmt))
- {
- /* Analysis is fully done on the reduction stmt invocation. */
- gcc_assert (! vec_stmt);
-
- if (slp_node)
- slp_node_instance->reduc_phis = slp_node;
-
- STMT_VINFO_TYPE (stmt_info) = cycle_phi_info_type;
- return true;
- }
-
/* 1. Is vectorizable reduction? */
/* Not supportable if the reduction variable is used in the loop, unless
it's a reduction chain. */
@@ -5898,13 +5886,10 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
The last use is the reduction variable. In case of nested cycle this
assumption is not true: we use reduc_index to record the index of the
reduction variable. */
- stmt_vec_info reduc_def_info;
- if (orig_stmt_info)
- reduc_def_info = STMT_VINFO_REDUC_DEF (orig_stmt_info);
- else
- reduc_def_info = STMT_VINFO_REDUC_DEF (stmt_info);
- gcc_assert (reduc_def_info);
- gphi *reduc_def_phi = as_a <gphi *> (reduc_def_info->stmt);
+ stmt_vec_info phi_info = STMT_VINFO_REDUC_DEF (vect_orig_stmt (stmt_info));
+ /* PHIs should not participate in patterns. */
+ gcc_assert (!STMT_VINFO_RELATED_STMT (phi_info));
+ gphi *reduc_def_phi = as_a <gphi *> (phi_info->stmt);
tree reduc_def = PHI_RESULT (reduc_def_phi);
int reduc_index = -1;
for (i = 0; i < op_type; i++)
@@ -5965,15 +5950,19 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
}
}
}
-
if (!vectype_in)
vectype_in = vectype_out;
+ STMT_VINFO_REDUC_VECTYPE_IN (reduc_info) = vectype_in;
+ /* For the SSA cycle we store on each participating stmt the operand index
+ where the cycle continues. Store the one relevant for the actual
+ operation in the reduction meta. */
+ STMT_VINFO_REDUC_IDX (reduc_info) = reduc_index;
/* When vectorizing a reduction chain w/o SLP the reduction PHI is not
directy used in stmt. */
if (reduc_index == -1)
{
- if (STMT_VINFO_REDUC_TYPE (stmt_info) == FOLD_LEFT_REDUCTION)
+ if (STMT_VINFO_REDUC_TYPE (phi_info) == FOLD_LEFT_REDUCTION)
{
if (dump_enabled_p ())
dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
@@ -5998,17 +5987,10 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
return false;
}
- /* PHIs should not participate in patterns. */
- gcc_assert (!STMT_VINFO_RELATED_STMT (reduc_def_info));
- enum vect_reduction_type v_reduc_type
- = STMT_VINFO_REDUC_TYPE (reduc_def_info);
- stmt_vec_info tmp = STMT_VINFO_REDUC_DEF (reduc_def_info);
-
- if (!vec_stmt)
- STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) = v_reduc_type;
+ enum vect_reduction_type v_reduc_type = STMT_VINFO_REDUC_TYPE (phi_info);
+ STMT_VINFO_REDUC_TYPE (reduc_info) = v_reduc_type;
/* If we have a condition reduction, see if we can simplify it further. */
- if (v_reduc_type == COND_REDUCTION
- && !vec_stmt)
+ if (v_reduc_type == COND_REDUCTION)
{
/* TODO: We can't yet handle reduction chains, since we need to treat
each COND_EXPR in the chain specially, not just the last one.
@@ -6037,7 +6019,7 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
"optimizing condition reduction with"
" FOLD_EXTRACT_LAST.\n");
- STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) = EXTRACT_LAST_REDUCTION;
+ STMT_VINFO_REDUC_TYPE (reduc_info) = EXTRACT_LAST_REDUCTION;
}
else if (cond_reduc_dt == vect_induction_def)
{
@@ -6077,12 +6059,14 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
}
if (cond_reduc_val)
{
- STMT_VINFO_VEC_COND_REDUC_CODE (stmt_info)
- = cond_reduc_op_code;
- STMT_VINFO_VEC_INDUC_COND_INITIAL_VAL (stmt_info)
+ if (dump_enabled_p ())
+ dump_printf_loc (MSG_NOTE, vect_location,
+ "condition expression based on "
+ "integer induction.\n");
+ STMT_VINFO_VEC_COND_REDUC_CODE (reduc_info) = cond_reduc_op_code;
+ STMT_VINFO_VEC_INDUC_COND_INITIAL_VAL (reduc_info)
= cond_reduc_val;
- STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info)
- = INTEGER_INDUC_COND_REDUCTION;
+ STMT_VINFO_REDUC_TYPE (reduc_info) = INTEGER_INDUC_COND_REDUCTION;
}
}
else if (cond_reduc_dt == vect_constant_def)
@@ -6107,30 +6091,21 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
"condition expression based on "
"compile time constant.\n");
/* Record reduction code at analysis stage. */
- STMT_VINFO_VEC_COND_REDUC_CODE (stmt_info)
+ STMT_VINFO_VEC_COND_REDUC_CODE (reduc_info)
= integer_onep (e) ? MAX_EXPR : MIN_EXPR;
- STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info)
- = CONST_COND_REDUCTION;
+ STMT_VINFO_REDUC_TYPE (reduc_info) = CONST_COND_REDUCTION;
}
}
}
}
- if (STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) == INTEGER_INDUC_COND_REDUCTION
- && dump_enabled_p ())
- dump_printf_loc (MSG_NOTE, vect_location,
- "condition expression based on "
- "integer induction.\n");
- if (orig_stmt_info)
- gcc_assert (tmp == orig_stmt_info
- || REDUC_GROUP_FIRST_ELEMENT (tmp) == orig_stmt_info);
- else
+ if (REDUC_GROUP_FIRST_ELEMENT (stmt_info))
/* We changed STMT to be the first stmt in reduction chain, hence we
check that in this case the first element in the chain is STMT. */
- gcc_assert (tmp == stmt_info
- || REDUC_GROUP_FIRST_ELEMENT (tmp) == stmt_info);
+ gcc_assert (REDUC_GROUP_FIRST_ELEMENT (STMT_VINFO_REDUC_DEF (phi_info))
+ == vect_orig_stmt (stmt_info));
- if (STMT_VINFO_LIVE_P (reduc_def_info))
+ if (STMT_VINFO_LIVE_P (phi_info))
return false;
if (slp_node)
@@ -6140,25 +6115,16 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
gcc_assert (ncopies >= 1);
- vec_mode = TYPE_MODE (vectype_in);
poly_uint64 nunits_out = TYPE_VECTOR_SUBPARTS (vectype_out);
if (nested_cycle)
{
- basic_block def_bb = gimple_bb (reduc_def_phi);
- class loop *def_stmt_loop = def_bb->loop_father;
- tree def_arg = PHI_ARG_DEF_FROM_EDGE (reduc_def_phi,
- loop_preheader_edge (def_stmt_loop));
- stmt_vec_info def_arg_stmt_info = loop_vinfo->lookup_def (def_arg);
- if (def_arg_stmt_info
- && (STMT_VINFO_DEF_TYPE (def_arg_stmt_info)
- == vect_double_reduction_def))
- double_reduc = true;
- gcc_assert (!double_reduc || STMT_VINFO_RELEVANT (stmt_info) == vect_used_in_outer_by_reduction);
+ gcc_assert (STMT_VINFO_DEF_TYPE (reduc_info)
+ == vect_double_reduction_def);
+ double_reduc = true;
}
- vect_reduction_type reduction_type
- = STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info);
+ vect_reduction_type reduction_type = STMT_VINFO_REDUC_TYPE (reduc_info);
if ((double_reduc || reduction_type != TREE_CODE_REDUCTION)
&& ncopies > 1)
{
@@ -6169,78 +6135,6 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
return false;
}
- if (code == COND_EXPR)
- {
- /* Only call during the analysis stage, otherwise we'll lose
- STMT_VINFO_TYPE. */
- gcc_assert (nested_cycle || reduc_index > 0);
- if (!vec_stmt && !vectorizable_condition (stmt_info, gsi, NULL,
- true, reduc_index,
- NULL, cost_vec))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "unsupported condition in reduction\n");
- return false;
- }
- }
- else if (code == LSHIFT_EXPR || code == RSHIFT_EXPR
- || code == LROTATE_EXPR || code == RROTATE_EXPR)
- {
- /* Only call during the analysis stage, otherwise we'll lose
- STMT_VINFO_TYPE. We only support this for nested cycles
- without double reductions at the moment. */
- if (!nested_cycle
- || double_reduc
- || (!vec_stmt && !vectorizable_shift (stmt_info, gsi, NULL,
- NULL, cost_vec)))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "unsupported shift or rotation in reduction\n");
- return false;
- }
- }
- else
- {
- /* 4. Supportable by target? */
-
- /* 4.1. check support for the operation in the loop */
- optab = optab_for_tree_code (code, vectype_in, optab_default);
- if (!optab)
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "no optab.\n");
-
- return false;
- }
-
- if (optab_handler (optab, vec_mode) == CODE_FOR_nothing)
- {
- if (dump_enabled_p ())
- dump_printf (MSG_NOTE, "op not supported by target.\n");
-
- if (maybe_ne (GET_MODE_SIZE (vec_mode), UNITS_PER_WORD)
- || !vect_worthwhile_without_simd_p (loop_vinfo, code))
- return false;
-
- if (dump_enabled_p ())
- dump_printf (MSG_NOTE, "proceeding using word mode.\n");
- }
-
- /* Worthwhile without SIMD support? */
- if (!VECTOR_MODE_P (TYPE_MODE (vectype_in))
- && !vect_worthwhile_without_simd_p (loop_vinfo, code))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not worthwhile without SIMD support.\n");
-
- return false;
- }
- }
-
/* 4.2. Check support for the epilog operation.
If STMT represents a reduction pattern, then the type of the
@@ -6285,7 +6179,6 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
reduction variable, and get the tree-code from orig_stmt. */
orig_code = gimple_assign_rhs_code (orig_stmt_info->stmt);
gcc_assert (vectype_out);
- vec_mode = TYPE_MODE (vectype_out);
}
else
{
@@ -6301,11 +6194,11 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
if (reduction_type == CONST_COND_REDUCTION
|| reduction_type == INTEGER_INDUC_COND_REDUCTION)
{
- orig_code = STMT_VINFO_VEC_COND_REDUC_CODE (stmt_info);
+ orig_code = STMT_VINFO_VEC_COND_REDUC_CODE (reduc_info);
gcc_assert (orig_code == MAX_EXPR || orig_code == MIN_EXPR);
}
}
- STMT_VINFO_REDUC_CODE (stmt_info) = orig_code;
+ STMT_VINFO_REDUC_CODE (reduc_info) = orig_code;
reduc_fn = IFN_LAST;
@@ -6353,7 +6246,7 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
OPTIMIZE_FOR_SPEED))
reduc_fn = IFN_REDUC_MAX;
}
- STMT_VINFO_REDUC_FN (stmt_info) = reduc_fn;
+ STMT_VINFO_REDUC_FN (reduc_info) = reduc_fn;
if (reduction_type != EXTRACT_LAST_REDUCTION
&& (!nested_cycle || double_reduc)
@@ -6436,7 +6329,7 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
which each SLP statement has its own initial value and in which
that value needs to be repeated for every instance of the
statement within the initial vector. */
- unsigned int group_size = SLP_TREE_SCALAR_STMTS (slp_node).length ();
+ unsigned int group_size = SLP_INSTANCE_GROUP_SIZE (slp_node_instance);
scalar_mode elt_mode = SCALAR_TYPE_MODE (TREE_TYPE (vectype_out));
if (!neutral_op
&& !can_duplicate_and_interleave_p (group_size, elt_mode))
@@ -6467,22 +6360,8 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
constant fits the type in the pattern recognition pass. */
if (code == DOT_PROD_EXPR
&& !types_compatible_p (TREE_TYPE (ops[0]), TREE_TYPE (ops[1])))
- {
- gcc_unreachable ();
- /* No testcase for this. PR49478. */
- if (TREE_CODE (ops[0]) == INTEGER_CST)
- ops[0] = fold_convert (TREE_TYPE (ops[1]), ops[0]);
- else if (TREE_CODE (ops[1]) == INTEGER_CST)
- ops[1] = fold_convert (TREE_TYPE (ops[0]), ops[1]);
- else
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "invalid types in dot-prod\n");
-
- return false;
- }
- }
+ /* No testcase for this. PR49478. */
+ gcc_unreachable ();
if (reduction_type == COND_REDUCTION)
{
@@ -6549,7 +6428,53 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
&& (!STMT_VINFO_IN_PATTERN_P (use_stmt_info)
|| !STMT_VINFO_PATTERN_DEF_SEQ (use_stmt_info))
&& vect_stmt_to_vectorize (use_stmt_info) == stmt_info)
- single_defuse_cycle = true;
+ STMT_VINFO_FORCE_SINGLE_CYCLE (reduc_info) = single_defuse_cycle = true;
+
+ if (single_defuse_cycle
+ || code == DOT_PROD_EXPR
+ || code == WIDEN_SUM_EXPR
+ || code == SAD_EXPR)
+ {
+ gcc_assert (code != COND_EXPR);
+
+ /* 4. Supportable by target? */
+
+ /* 4.1. check support for the operation in the loop */
+ optab optab = optab_for_tree_code (code, vectype_in, optab_default);
+ if (!optab)
+ {
+ if (dump_enabled_p ())
+ dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+ "no optab.\n");
+
+ return false;
+ }
+
+ machine_mode vec_mode = TYPE_MODE (vectype_in);
+ if (optab_handler (optab, vec_mode) == CODE_FOR_nothing)
+ {
+ if (dump_enabled_p ())
+ dump_printf (MSG_NOTE, "op not supported by target.\n");
+
+ if (maybe_ne (GET_MODE_SIZE (vec_mode), UNITS_PER_WORD)
+ || !vect_worthwhile_without_simd_p (loop_vinfo, code))
+ return false;
+
+ if (dump_enabled_p ())
+ dump_printf (MSG_NOTE, "proceeding using word mode.\n");
+ }
+
+ /* Worthwhile without SIMD support? */
+ if (!VECTOR_MODE_P (TYPE_MODE (vectype_in))
+ && !vect_worthwhile_without_simd_p (loop_vinfo, code))
+ {
+ if (dump_enabled_p ())
+ dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+ "not worthwhile without SIMD support.\n");
+
+ return false;
+ }
+ }
/* If the reduction stmt is one of the patterns that have lane
reduction embedded we cannot handle the case of ! single_defuse_cycle. */
@@ -6575,10 +6500,8 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
vec_loop_masks *masks = &LOOP_VINFO_MASKS (loop_vinfo);
bool mask_by_cond_expr = use_mask_by_cond_expr_p (code, cond_fn, vectype_in);
- /* transformation not required. */
- gcc_assert (!vec_stmt);
-
- vect_model_reduction_cost (stmt_info, reduc_fn, ncopies, cost_vec);
+ vect_model_reduction_cost (stmt_info, reduc_fn, reduction_type, ncopies,
+ cost_vec);
if (loop_vinfo && LOOP_VINFO_CAN_FULLY_MASK_P (loop_vinfo))
{
if (reduction_type != FOLD_LEFT_REDUCTION
@@ -6609,7 +6532,18 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
&& reduction_type == FOLD_LEFT_REDUCTION)
dump_printf_loc (MSG_NOTE, vect_location,
"using an in-order (fold-left) reduction.\n");
- STMT_VINFO_TYPE (stmt_info) = reduc_vec_info_type;
+ STMT_VINFO_TYPE (orig_stmt_of_analysis) = cycle_phi_info_type;
+ /* All but single defuse-cycle optimized, lane-reducing and fold-left
+ reductions go through their own vectorizable_* routines. */
+ if (!single_defuse_cycle
+ && code != DOT_PROD_EXPR
+ && code != WIDEN_SUM_EXPR
+ && code != SAD_EXPR
+ && reduction_type != FOLD_LEFT_REDUCTION)
+ {
+ STMT_VINFO_DEF_TYPE (stmt_info) = vect_internal_def;
+ STMT_VINFO_DEF_TYPE (vect_orig_stmt (stmt_info)) = vect_internal_def;
+ }
return true;
}
@@ -6621,51 +6555,37 @@ vect_transform_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
stmt_vec_info *vec_stmt, slp_tree slp_node)
{
tree vectype_out = STMT_VINFO_VECTYPE (stmt_info);
- tree vectype_in = NULL_TREE;
loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_info);
class loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
- enum tree_code code;
- int op_type;
- bool is_simple_use;
int i;
int ncopies;
- bool single_defuse_cycle = false;
int j;
- tree ops[3];
- bool nested_cycle = false;
int vec_num;
+ stmt_vec_info reduc_info = info_for_reduction (stmt_info);
+ gcc_assert (reduc_info->is_reduc_info);
+
if (nested_in_vect_loop_p (loop, stmt_info))
{
loop = loop->inner;
- nested_cycle = true;
+ gcc_assert (STMT_VINFO_DEF_TYPE (reduc_info) == vect_double_reduction_def);
}
gassign *stmt = as_a <gassign *> (stmt_info->stmt);
+ enum tree_code code = gimple_assign_rhs_code (stmt);
+ int op_type = TREE_CODE_LENGTH (code);
/* Flatten RHS. */
- switch (get_gimple_rhs_class (gimple_assign_rhs_code (stmt)))
+ tree ops[3];
+ switch (get_gimple_rhs_class (code))
{
- case GIMPLE_BINARY_RHS:
- code = gimple_assign_rhs_code (stmt);
- op_type = TREE_CODE_LENGTH (code);
- gcc_assert (op_type == binary_op);
- ops[0] = gimple_assign_rhs1 (stmt);
- ops[1] = gimple_assign_rhs2 (stmt);
- break;
-
case GIMPLE_TERNARY_RHS:
- code = gimple_assign_rhs_code (stmt);
- op_type = TREE_CODE_LENGTH (code);
- gcc_assert (op_type == ternary_op);
+ ops[2] = gimple_assign_rhs3 (stmt);
+ /* Fall thru. */
+ case GIMPLE_BINARY_RHS:
ops[0] = gimple_assign_rhs1 (stmt);
ops[1] = gimple_assign_rhs2 (stmt);
- ops[2] = gimple_assign_rhs3 (stmt);
break;
-
- case GIMPLE_UNARY_RHS:
- return false;
-
default:
gcc_unreachable ();
}
@@ -6674,121 +6594,21 @@ vect_transform_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
The last use is the reduction variable. In case of nested cycle this
assumption is not true: we use reduc_index to record the index of the
reduction variable. */
- stmt_vec_info reduc_def_info
- = STMT_VINFO_REDUC_DEF (vect_orig_stmt (stmt_info));
- gcc_assert (reduc_def_info);
- gphi *reduc_def_phi = as_a <gphi *> (reduc_def_info->stmt);
- tree reduc_def = PHI_RESULT (reduc_def_phi);
- int reduc_index = -1;
- for (i = 0; i < op_type; i++)
- {
- /* The condition of COND_EXPR is checked in vectorizable_condition(). */
- if (i == 0 && code == COND_EXPR)
- continue;
-
- stmt_vec_info def_stmt_info;
- enum vect_def_type dt;
- tree tem;
- is_simple_use = vect_is_simple_use (ops[i], loop_vinfo, &dt, &tem,
- &def_stmt_info);
- gcc_assert (is_simple_use);
- if (dt == vect_reduction_def
- && ops[i] == reduc_def)
- {
- reduc_index = i;
- continue;
- }
- else if (tem)
- {
- /* To properly compute ncopies we are interested in the widest
- input type in case we're looking at a widening accumulation. */
- if (!vectype_in
- || (GET_MODE_SIZE (SCALAR_TYPE_MODE (TREE_TYPE (vectype_in)))
- < GET_MODE_SIZE (SCALAR_TYPE_MODE (TREE_TYPE (tem)))))
- vectype_in = tem;
- }
-
- if (dt == vect_nested_cycle
- && ops[i] == reduc_def)
- {
- reduc_index = i;
- }
- }
-
- if (!vectype_in)
- vectype_in = vectype_out;
-
- if (STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) == INTEGER_INDUC_COND_REDUCTION
- && dump_enabled_p ())
- dump_printf_loc (MSG_NOTE, vect_location,
- "condition expression based on "
- "integer induction.\n");
+ stmt_vec_info phi_info = STMT_VINFO_REDUC_DEF (vect_orig_stmt (stmt_info));
+ gphi *reduc_def_phi = as_a <gphi *> (phi_info->stmt);
+ int reduc_index = STMT_VINFO_REDUC_IDX (reduc_info);
+ tree vectype_in = STMT_VINFO_REDUC_VECTYPE_IN (reduc_info);
if (slp_node)
- ncopies = 1;
- else
- ncopies = vect_get_num_copies (loop_vinfo, vectype_in);
-
- vect_reduction_type reduction_type
- = STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info);
-
- /* In case of widenning multiplication by a constant, we update the type
- of the constant to be the type of the other operand. We check that the
- constant fits the type in the pattern recognition pass. */
- if (code == DOT_PROD_EXPR
- && !types_compatible_p (TREE_TYPE (ops[0]), TREE_TYPE (ops[1])))
{
- gcc_unreachable ();
- /* No testcase for this. PR49478. */
- if (TREE_CODE (ops[0]) == INTEGER_CST)
- ops[0] = fold_convert (TREE_TYPE (ops[1]), ops[0]);
- else if (TREE_CODE (ops[1]) == INTEGER_CST)
- ops[1] = fold_convert (TREE_TYPE (ops[0]), ops[1]);
+ ncopies = 1;
+ vec_num = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node);
}
-
- /* In case the vectorization factor (VF) is bigger than the number
- of elements that we can fit in a vectype (nunits), we have to generate
- more than one vector stmt - i.e - we need to "unroll" the
- vector stmt by a factor VF/nunits. For more details see documentation
- in vectorizable_operation. */
-
- /* If the reduction is used in an outer loop we need to generate
- VF intermediate results, like so (e.g. for ncopies=2):
- r0 = phi (init, r0)
- r1 = phi (init, r1)
- r0 = x0 + r0;
- r1 = x1 + r1;
- (i.e. we generate VF results in 2 registers).
- In this case we have a separate def-use cycle for each copy, and therefore
- for each copy we get the vector def for the reduction variable from the
- respective phi node created for this copy.
-
- Otherwise (the reduction is unused in the loop nest), we can combine
- together intermediate results, like so (e.g. for ncopies=2):
- r = phi (init, r)
- r = x0 + r;
- r = x1 + r;
- (i.e. we generate VF/2 results in a single register).
- In this case for each copy we get the vector def for the reduction variable
- from the vectorized reduction operation generated in the previous iteration.
-
- This only works when we see both the reduction PHI and its only consumer
- in vectorizable_reduction and there are no intermediate stmts
- participating. */
- stmt_vec_info use_stmt_info;
- tree reduc_phi_result = gimple_phi_result (reduc_def_phi);
- if (ncopies > 1
- && (STMT_VINFO_RELEVANT (stmt_info) <= vect_used_only_live)
- && (use_stmt_info = loop_vinfo->lookup_single_use (reduc_phi_result))
- && (!STMT_VINFO_IN_PATTERN_P (use_stmt_info)
- || !STMT_VINFO_PATTERN_DEF_SEQ (use_stmt_info))
- && vect_stmt_to_vectorize (use_stmt_info) == stmt_info)
- single_defuse_cycle = true;
-
- if (slp_node)
- vec_num = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node);
else
- vec_num = 1;
+ {
+ ncopies = vect_get_num_copies (loop_vinfo, vectype_in);
+ vec_num = 1;
+ }
internal_fn cond_fn = get_conditional_internal_fn (code);
vec_loop_masks *masks = &LOOP_VINFO_MASKS (loop_vinfo);
@@ -6812,20 +6632,20 @@ vect_transform_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
bool masked_loop_p = LOOP_VINFO_FULLY_MASKED_P (loop_vinfo);
+ vect_reduction_type reduction_type = STMT_VINFO_REDUC_TYPE (reduc_info);
if (reduction_type == FOLD_LEFT_REDUCTION)
{
- internal_fn reduc_fn = STMT_VINFO_REDUC_FN (stmt_info);
+ internal_fn reduc_fn = STMT_VINFO_REDUC_FN (reduc_info);
return vectorize_fold_left_reduction
(stmt_info, gsi, vec_stmt, slp_node, reduc_def_phi, code,
reduc_fn, ops, vectype_in, reduc_index, masks);
}
- if (reduction_type == EXTRACT_LAST_REDUCTION)
- {
- gcc_assert (!slp_node && reduc_index > 0);
- return vectorizable_condition (stmt_info, gsi, vec_stmt,
- true, reduc_index, NULL, NULL);
- }
+ bool single_defuse_cycle = STMT_VINFO_FORCE_SINGLE_CYCLE (reduc_info);
+ gcc_assert (single_defuse_cycle
+ || code == DOT_PROD_EXPR
+ || code == WIDEN_SUM_EXPR
+ || code == SAD_EXPR);
/* Create the destination vector */
tree scalar_dest = gimple_assign_lhs (stmt);
@@ -6842,20 +6662,6 @@ vect_transform_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
for (j = 0; j < ncopies; j++)
{
- if (code == COND_EXPR)
- {
- gcc_assert (!slp_node && (nested_cycle || reduc_index > 0));
- vectorizable_condition (stmt_info, gsi, vec_stmt, true,
- reduc_index, NULL, NULL);
- break;
- }
- if (code == LSHIFT_EXPR
- || code == RSHIFT_EXPR)
- {
- vectorizable_shift (stmt_info, gsi, vec_stmt, slp_node, NULL);
- break;
- }
-
/* Handle uses. */
if (j == 0)
{
@@ -6995,10 +6801,8 @@ vect_transform_cycle_phi (stmt_vec_info stmt_info, stmt_vec_info *vec_stmt,
slp_tree slp_node, slp_instance slp_node_instance)
{
tree vectype_out = STMT_VINFO_VECTYPE (stmt_info);
- tree vectype_in = NULL_TREE;
loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_info);
class loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
- enum vect_def_type dt;
int i;
int ncopies;
stmt_vec_info prev_phi_info;
@@ -7012,43 +6816,18 @@ vect_transform_cycle_phi (stmt_vec_info stmt_info, stmt_vec_info *vec_stmt,
nested_cycle = true;
}
- gphi *phi = as_a <gphi *> (stmt_info->stmt);
- tree phi_result = gimple_phi_result (phi);
-
- if (STMT_VINFO_REDUC_TYPE (stmt_info) == FOLD_LEFT_REDUCTION)
- /* Leave the scalar phi in place. Note that checking
- STMT_VINFO_VEC_REDUCTION_TYPE (as below) only works
- for reductions involving a single statement. */
- return true;
-
stmt_vec_info reduc_stmt_info = STMT_VINFO_REDUC_DEF (stmt_info);
reduc_stmt_info = vect_stmt_to_vectorize (reduc_stmt_info);
+ stmt_vec_info reduc_info = info_for_reduction (stmt_info);
+ gcc_assert (reduc_info->is_reduc_info);
- if (STMT_VINFO_VEC_REDUCTION_TYPE (reduc_stmt_info)
- == EXTRACT_LAST_REDUCTION)
+ if (STMT_VINFO_REDUC_TYPE (reduc_info) == EXTRACT_LAST_REDUCTION
+ || STMT_VINFO_REDUC_TYPE (reduc_info) == FOLD_LEFT_REDUCTION)
/* Leave the scalar phi in place. */
return true;
- if (gassign *reduc_stmt = dyn_cast <gassign *> (reduc_stmt_info->stmt))
- for (unsigned k = 1; k < gimple_num_ops (reduc_stmt); ++k)
- {
- tree op = gimple_op (reduc_stmt, k);
- if (op == phi_result)
- continue;
- if (k == 1 && gimple_assign_rhs_code (reduc_stmt) == COND_EXPR)
- continue;
- bool is_simple_use = vect_is_simple_use (op, loop_vinfo, &dt);
- gcc_assert (is_simple_use);
- if (dt == vect_constant_def || dt == vect_external_def)
- continue;
- if (!vectype_in
- || (GET_MODE_SIZE (SCALAR_TYPE_MODE (TREE_TYPE (vectype_in)))
- < GET_MODE_SIZE (SCALAR_TYPE_MODE (TREE_TYPE (op)))))
- vectype_in = get_vectype_for_scalar_type (TREE_TYPE (op));
- break;
- }
- /* For a nested cycle we might end up with an operation like
- phi_result * phi_result. */
+ tree vectype_in = STMT_VINFO_REDUC_VECTYPE_IN (reduc_info);
+ /* For a nested cycle we do not fill the above. */
if (!vectype_in)
vectype_in = STMT_VINFO_VECTYPE (stmt_info);
gcc_assert (vectype_in);
@@ -7067,19 +6846,15 @@ vect_transform_cycle_phi (stmt_vec_info stmt_info, stmt_vec_info *vec_stmt,
ncopies = vect_get_num_copies (loop_vinfo, vectype_in);
}
- /* Check whether we can use a single PHI node and accumulate
+ /* Check whether we should use a single PHI node and accumulate
vectors to one before the backedge. */
- stmt_vec_info use_stmt_info;
- if (ncopies > 1
- && STMT_VINFO_RELEVANT (reduc_stmt_info) <= vect_used_only_live
- && (use_stmt_info = loop_vinfo->lookup_single_use (phi_result))
- && (!STMT_VINFO_IN_PATTERN_P (use_stmt_info)
- || !STMT_VINFO_PATTERN_DEF_SEQ (use_stmt_info))
- && vect_stmt_to_vectorize (use_stmt_info) == reduc_stmt_info)
+ if (STMT_VINFO_FORCE_SINGLE_CYCLE (reduc_info))
ncopies = 1;
/* Create the destination vector */
- tree vec_dest = vect_create_destination_var (phi_result, vectype_out);
+ gphi *phi = as_a <gphi *> (stmt_info->stmt);
+ tree vec_dest = vect_create_destination_var (gimple_phi_result (phi),
+ vectype_out);
/* Get the loop-entry arguments. */
tree vec_initial_def;
@@ -7091,8 +6866,7 @@ vect_transform_cycle_phi (stmt_vec_info stmt_info, stmt_vec_info *vec_stmt,
stmt_vec_info first = REDUC_GROUP_FIRST_ELEMENT (reduc_stmt_info);
tree neutral_op
= neutral_op_for_slp_reduction (slp_node,
- STMT_VINFO_REDUC_CODE
- (first ? first : reduc_stmt_info),
+ STMT_VINFO_REDUC_CODE (reduc_info),
first != NULL);
get_initial_defs_for_reduction (slp_node_instance->reduc_phis,
&vec_initial_defs, vec_num,
@@ -7107,27 +6881,20 @@ vect_transform_cycle_phi (stmt_vec_info stmt_info, stmt_vec_info *vec_stmt,
/* Optimize: if initial_def is for REDUC_MAX smaller than the base
and we can't use zero for induc_val, use initial_def. Similarly
for REDUC_MIN and initial_def larger than the base. */
- if (STMT_VINFO_VEC_REDUCTION_TYPE (reduc_stmt_info)
- == INTEGER_INDUC_COND_REDUCTION)
+ if (STMT_VINFO_REDUC_TYPE (reduc_info) == INTEGER_INDUC_COND_REDUCTION)
{
- tree induc_val
- = STMT_VINFO_VEC_INDUC_COND_INITIAL_VAL (reduc_stmt_info);
+ tree induc_val = STMT_VINFO_VEC_INDUC_COND_INITIAL_VAL (reduc_info);
if (TREE_CODE (initial_def) == INTEGER_CST
- && (STMT_VINFO_VEC_REDUCTION_TYPE (reduc_stmt_info)
- == INTEGER_INDUC_COND_REDUCTION)
&& !integer_zerop (induc_val)
- && (((STMT_VINFO_VEC_COND_REDUC_CODE (reduc_stmt_info)
- == MAX_EXPR)
+ && (((STMT_VINFO_VEC_COND_REDUC_CODE (reduc_info) == MAX_EXPR)
&& tree_int_cst_lt (initial_def, induc_val))
- || ((STMT_VINFO_VEC_COND_REDUC_CODE (reduc_stmt_info)
- == MIN_EXPR)
+ || ((STMT_VINFO_VEC_COND_REDUC_CODE (reduc_info) == MIN_EXPR)
&& tree_int_cst_lt (induc_val, initial_def))))
{
induc_val = initial_def;
/* Communicate we used the initial_def to epilouge
generation. */
- STMT_VINFO_VEC_INDUC_COND_INITIAL_VAL (reduc_stmt_info)
- = NULL_TREE;
+ STMT_VINFO_VEC_INDUC_COND_INITIAL_VAL (reduc_info) = NULL_TREE;
}
vec_initial_def = build_vector_from_val (vectype_out, induc_val);
}
@@ -7142,24 +6909,13 @@ vect_transform_cycle_phi (stmt_vec_info stmt_info, stmt_vec_info *vec_stmt,
{
tree adjustment_def = NULL_TREE;
tree *adjustment_defp = &adjustment_def;
- enum tree_code code = STMT_VINFO_REDUC_CODE (reduc_stmt_info);
- /* ??? For the outer loop PHI we have to do a bit of searching
- to find the stmt with the code. reduc_stmt_info here is the
- loop-closed PHI of the inner reduction which means we can look
- at its single-arg def. */
+ enum tree_code code = STMT_VINFO_REDUC_CODE (reduc_info);
if (STMT_VINFO_DEF_TYPE (stmt_info) == vect_double_reduction_def)
- {
- tree def = gimple_phi_arg_def
- (as_a <gphi *> (reduc_stmt_info->stmt), 0);
- code = STMT_VINFO_REDUC_CODE
- (vect_stmt_to_vectorize (loop_vinfo->lookup_def (def)));
- adjustment_defp = NULL;
- }
+ adjustment_defp = NULL;
vec_initial_def
= get_initial_def_for_reduction (reduc_stmt_info, code,
initial_def, adjustment_defp);
- STMT_VINFO_REDUC_EPILOGUE_ADJUSTMENT (reduc_stmt_info)
- = adjustment_def;
+ STMT_VINFO_REDUC_EPILOGUE_ADJUSTMENT (reduc_info) = adjustment_def;
}
vec_initial_defs.create (1);
vec_initial_defs.quick_push (vec_initial_def);
@@ -7872,9 +7628,9 @@ vectorizable_induction (stmt_vec_info stmt_info,
bool
vectorizable_live_operation (stmt_vec_info stmt_info,
- gimple_stmt_iterator *gsi ATTRIBUTE_UNUSED,
+ gimple_stmt_iterator *gsi,
slp_tree slp_node, slp_instance slp_node_instance,
- int slp_index, stmt_vec_info *vec_stmt,
+ int slp_index, bool vec_stmt_p,
stmt_vector_for_cost *)
{
loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_info);
@@ -7894,30 +7650,26 @@ vectorizable_live_operation (stmt_vec_info stmt_info,
/* The last stmt of a reduction is live and vectorized via
vect_create_epilog_for_reduction. vectorizable_reduction assessed
validity so just trigger the transform here. */
- if (STMT_VINFO_DEF_TYPE (stmt_info) == vect_reduction_def
- || STMT_VINFO_DEF_TYPE (stmt_info) == vect_double_reduction_def)
+ if (STMT_VINFO_REDUC_DEF (vect_orig_stmt (stmt_info)))
{
- if (!vec_stmt)
+ if (!vec_stmt_p)
return true;
- if (STMT_VINFO_DEF_TYPE (stmt_info) == vect_reduction_def)
+ if (slp_node)
{
- if (STMT_VINFO_REDUC_TYPE (stmt_info) == FOLD_LEFT_REDUCTION
- || (STMT_VINFO_REDUC_TYPE (stmt_info) == COND_REDUCTION
- && (STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info)
- == EXTRACT_LAST_REDUCTION)))
+ /* For reduction chains the meta-info is attached to
+ the group leader. */
+ if (REDUC_GROUP_FIRST_ELEMENT (stmt_info))
+ stmt_info = REDUC_GROUP_FIRST_ELEMENT (stmt_info);
+ /* For SLP reductions we vectorize the epilogue for
+ all involved stmts together. */
+ else if (slp_index != 0)
return true;
- if (slp_node)
- {
- /* For reduction chains the meta-info is attached to
- the group leader. */
- if (REDUC_GROUP_FIRST_ELEMENT (stmt_info))
- stmt_info = REDUC_GROUP_FIRST_ELEMENT (stmt_info);
- /* For SLP reductions we vectorize the epilogue for
- all involved stmts together. */
- else if (slp_index != 0)
- return true;
- }
}
+ stmt_vec_info reduc_info = info_for_reduction (stmt_info);
+ gcc_assert (reduc_info->is_reduc_info);
+ if (STMT_VINFO_REDUC_TYPE (reduc_info) == FOLD_LEFT_REDUCTION
+ || STMT_VINFO_REDUC_TYPE (reduc_info) == EXTRACT_LAST_REDUCTION)
+ return true;
vect_create_epilog_for_reduction (stmt_info, slp_node,
slp_node_instance);
return true;
@@ -7969,7 +7721,7 @@ vectorizable_live_operation (stmt_vec_info stmt_info,
}
}
- if (!vec_stmt)
+ if (!vec_stmt_p)
{
/* No transformation required. */
if (LOOP_VINFO_CAN_FULLY_MASK_P (loop_vinfo))
diff --git a/gcc/tree-vect-patterns.c b/gcc/tree-vect-patterns.c
index 09db74bdd77..f9c74087893 100644
--- a/gcc/tree-vect-patterns.c
+++ b/gcc/tree-vect-patterns.c
@@ -838,9 +838,11 @@ vect_convert_output (stmt_vec_info stmt_info, tree type, gimple *pattern_stmt,
static bool
vect_reassociating_reduction_p (stmt_vec_info stmt_vinfo)
{
- return (STMT_VINFO_DEF_TYPE (stmt_vinfo) == vect_reduction_def
- ? STMT_VINFO_REDUC_TYPE (stmt_vinfo) != FOLD_LEFT_REDUCTION
- : REDUC_GROUP_FIRST_ELEMENT (stmt_vinfo) != NULL);
+ if (STMT_VINFO_DEF_TYPE (stmt_vinfo) == vect_reduction_def)
+ return (STMT_VINFO_REDUC_TYPE (STMT_VINFO_REDUC_DEF (stmt_vinfo))
+ != FOLD_LEFT_REDUCTION);
+ else
+ return REDUC_GROUP_FIRST_ELEMENT (stmt_vinfo) != NULL;
}
/* As above, but also require it to have code CODE and to be a reduction
diff --git a/gcc/tree-vect-slp.c b/gcc/tree-vect-slp.c
index 9b86b67734a..77b18ba36d0 100644
--- a/gcc/tree-vect-slp.c
+++ b/gcc/tree-vect-slp.c
@@ -3957,17 +3957,6 @@ vect_schedule_slp_instance (slp_tree node, slp_instance instance,
stmt_vec_info last_stmt_info = vect_find_last_scalar_stmt_in_slp (node);
si = gsi_for_stmt (last_stmt_info->stmt);
- /* Mark the first element of the reduction chain as reduction to properly
- transform the node. In the analysis phase only the last element of the
- chain is marked as reduction. */
- if (!STMT_VINFO_GROUPED_ACCESS (stmt_info)
- && REDUC_GROUP_FIRST_ELEMENT (stmt_info)
- && REDUC_GROUP_FIRST_ELEMENT (stmt_info) == stmt_info)
- {
- STMT_VINFO_DEF_TYPE (stmt_info) = vect_reduction_def;
- STMT_VINFO_TYPE (stmt_info) = reduc_vec_info_type;
- }
-
/* Handle two-operation SLP nodes by vectorizing the group with
both operations and then performing a merge. */
if (SLP_TREE_TWO_OPERATORS (node))
diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c
index cac7410387b..e606945d536 100644
--- a/gcc/tree-vect-stmts.c
+++ b/gcc/tree-vect-stmts.c
@@ -1449,7 +1449,7 @@ vect_init_vector_1 (stmt_vec_info stmt_vinfo, gimple *new_stmt,
Insert a new stmt (INIT_STMT) that initializes a new variable of type
TYPE with the value VAL. If TYPE is a vector type and VAL does not have
vector type a vector with all elements equal to VAL is created first.
- Place the initialization at BSI if it is not NULL. Otherwise, place the
+ Place the initialization at GSI if it is not NULL. Otherwise, place the
initialization at the loop preheader.
Return the DEF of INIT_STMT.
It will be used in the vectorization of STMT_INFO. */
@@ -4484,7 +4484,7 @@ vectorizable_simd_clone_call (stmt_vec_info stmt_info,
Create a vector stmt whose code, type, number of arguments, and result
variable are CODE, OP_TYPE, and VEC_DEST, and its arguments are
- VEC_OPRND0 and VEC_OPRND1. The new vector stmt is to be inserted at BSI.
+ VEC_OPRND0 and VEC_OPRND1. The new vector stmt is to be inserted at GSI.
In the case that CODE is a CALL_EXPR, this means that a call to DECL
needs to be created (DECL is a function-decl of a target-builtin).
STMT_INFO is the original scalar stmt that we are vectorizing. */
@@ -5501,7 +5501,7 @@ vect_supportable_shift (enum tree_code code, tree scalar_type)
stmt to replace it, put it in VEC_STMT, and insert it at GSI.
Return true if STMT_INFO is vectorizable in this way. */
-bool
+static bool
vectorizable_shift (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
stmt_vec_info *vec_stmt, slp_tree slp_node,
stmt_vector_for_cost *cost_vec)
@@ -9776,10 +9776,9 @@ vect_is_simple_cond (tree cond, vec_info *vinfo,
Return true if STMT_INFO is vectorizable in this way. */
-bool
+static bool
vectorizable_condition (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
- stmt_vec_info *vec_stmt, bool for_reduction,
- int reduc_index,
+ stmt_vec_info *vec_stmt,
slp_tree slp_node, stmt_vector_for_cost *cost_vec)
{
vec_info *vinfo = stmt_info->vinfo;
@@ -9812,17 +9811,36 @@ vectorizable_condition (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
return false;
- if (for_reduction && STMT_SLP_TYPE (stmt_info))
+ /* Is vectorizable conditional operation? */
+ gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt);
+ if (!stmt)
+ return false;
+
+ code = gimple_assign_rhs_code (stmt);
+ if (code != COND_EXPR)
return false;
- vect_reduction_type reduction_type
- = STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info);
- if (!for_reduction)
+ stmt_vec_info reduc_info = NULL;
+ int reduc_index = -1;
+ vect_reduction_type reduction_type = TREE_CODE_REDUCTION;
+ bool for_reduction
+ = STMT_VINFO_REDUC_DEF (vect_orig_stmt (stmt_info)) != NULL;
+ if (for_reduction)
+ {
+ if (STMT_SLP_TYPE (stmt_info))
+ return false;
+ reduc_info = info_for_reduction (stmt_info);
+ reduction_type = STMT_VINFO_REDUC_TYPE (reduc_info);
+ reduc_index = STMT_VINFO_REDUC_IDX (stmt_info);
+ gcc_assert (reduction_type != EXTRACT_LAST_REDUCTION
+ || reduc_index != -1);
+ }
+ else
{
if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def)
return false;
- /* FORNOW: not yet supported. */
+ /* FORNOW: only supported as part of a reduction. */
if (STMT_VINFO_LIVE_P (stmt_info))
{
if (dump_enabled_p ())
@@ -9832,16 +9850,6 @@ vectorizable_condition (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
}
}
- /* Is vectorizable conditional operation? */
- gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt);
- if (!stmt)
- return false;
-
- code = gimple_assign_rhs_code (stmt);
-
- if (code != COND_EXPR)
- return false;
-
tree vectype = STMT_VINFO_VECTYPE (stmt_info);
tree vectype1 = NULL_TREE, vectype2 = NULL_TREE;
@@ -10466,12 +10474,12 @@ vectorizable_comparison (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
/* If SLP_NODE is nonnull, return true if vectorizable_live_operation
can handle all live statements in the node. Otherwise return true
if STMT_INFO is not live or if vectorizable_live_operation can handle it.
- GSI and VEC_STMT are as for vectorizable_live_operation. */
+ GSI and VEC_STMT_P are as for vectorizable_live_operation. */
static bool
can_vectorize_live_stmts (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
slp_tree slp_node, slp_instance slp_node_instance,
- stmt_vec_info *vec_stmt,
+ bool vec_stmt_p,
stmt_vector_for_cost *cost_vec)
{
if (slp_node)
@@ -10483,14 +10491,14 @@ can_vectorize_live_stmts (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
if (STMT_VINFO_LIVE_P (slp_stmt_info)
&& !vectorizable_live_operation (slp_stmt_info, gsi, slp_node,
slp_node_instance, i,
- vec_stmt, cost_vec))
+ vec_stmt_p, cost_vec))
return false;
}
}
else if (STMT_VINFO_LIVE_P (stmt_info)
&& !vectorizable_live_operation (stmt_info, gsi, slp_node,
slp_node_instance, -1,
- vec_stmt, cost_vec))
+ vec_stmt_p, cost_vec))
return false;
return true;
@@ -10665,12 +10673,10 @@ vect_analyze_stmt (stmt_vec_info stmt_info, bool *need_to_vectorize,
|| vectorizable_load (stmt_info, NULL, NULL, node, node_instance,
cost_vec)
|| vectorizable_store (stmt_info, NULL, NULL, node, cost_vec)
- || vectorizable_reduction (stmt_info, NULL, NULL, node,
- node_instance, cost_vec)
+ || vectorizable_reduction (stmt_info, node, node_instance, cost_vec)
|| vectorizable_induction (stmt_info, NULL, NULL, node, cost_vec)
|| vectorizable_shift (stmt_info, NULL, NULL, node, cost_vec)
- || vectorizable_condition (stmt_info, NULL, NULL, false, -1, node,
- cost_vec)
+ || vectorizable_condition (stmt_info, NULL, NULL, node, cost_vec)
|| vectorizable_comparison (stmt_info, NULL, NULL, node,
cost_vec)
|| vectorizable_lc_phi (stmt_info, NULL, node));
@@ -10689,8 +10695,7 @@ vect_analyze_stmt (stmt_vec_info stmt_info, bool *need_to_vectorize,
|| vectorizable_load (stmt_info, NULL, NULL, node, node_instance,
cost_vec)
|| vectorizable_store (stmt_info, NULL, NULL, node, cost_vec)
- || vectorizable_condition (stmt_info, NULL, NULL, false, -1, node,
- cost_vec)
+ || vectorizable_condition (stmt_info, NULL, NULL, node, cost_vec)
|| vectorizable_comparison (stmt_info, NULL, NULL, node,
cost_vec));
}
@@ -10707,7 +10712,7 @@ vect_analyze_stmt (stmt_vec_info stmt_info, bool *need_to_vectorize,
&& STMT_VINFO_TYPE (stmt_info) != reduc_vec_info_type
&& STMT_VINFO_TYPE (stmt_info) != lc_phi_info_type
&& !can_vectorize_live_stmts (stmt_info, NULL, node, node_instance,
- NULL, cost_vec))
+ false, cost_vec))
return opt_result::failure_at (stmt_info->stmt,
"not vectorized:"
" live stmt not supported: %G",
@@ -10719,7 +10724,7 @@ vect_analyze_stmt (stmt_vec_info stmt_info, bool *need_to_vectorize,
/* Function vect_transform_stmt.
- Create a vectorized stmt to replace STMT_INFO, and insert it at BSI. */
+ Create a vectorized stmt to replace STMT_INFO, and insert it at GSI. */
bool
vect_transform_stmt (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
@@ -10796,8 +10801,7 @@ vect_transform_stmt (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
break;
case condition_vec_info_type:
- done = vectorizable_condition (stmt_info, gsi, &vec_stmt, false, -1,
- slp_node, NULL);
+ done = vectorizable_condition (stmt_info, gsi, &vec_stmt, slp_node, NULL);
gcc_assert (done);
break;
@@ -10895,20 +10899,22 @@ vect_transform_stmt (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
/* If this stmt defines a value used on a backedge, update the
vectorized PHIs. */
stmt_vec_info orig_stmt_info = vect_orig_stmt (stmt_info);
- if (!slp_node && STMT_VINFO_REDUC_DEF (orig_stmt_info)
- && STMT_VINFO_REDUC_TYPE (orig_stmt_info) != FOLD_LEFT_REDUCTION
- && (STMT_VINFO_REDUC_TYPE (orig_stmt_info) != COND_REDUCTION
- || (STMT_VINFO_VEC_REDUCTION_TYPE (orig_stmt_info)
- != EXTRACT_LAST_REDUCTION))
- && is_a <gphi *> (STMT_VINFO_REDUC_DEF (orig_stmt_info)->stmt))
- {
- gphi *phi = as_a <gphi *> (STMT_VINFO_REDUC_DEF (orig_stmt_info)->stmt);
- if (dominated_by_p (CDI_DOMINATORS,
- gimple_bb (orig_stmt_info->stmt), gimple_bb (phi)))
+ stmt_vec_info reduc_info;
+ if (STMT_VINFO_REDUC_DEF (orig_stmt_info)
+ && (reduc_info = info_for_reduction (orig_stmt_info))
+ && STMT_VINFO_REDUC_TYPE (reduc_info) != FOLD_LEFT_REDUCTION
+ && STMT_VINFO_REDUC_TYPE (reduc_info) != EXTRACT_LAST_REDUCTION)
+ {
+ gphi *phi;
+ if (!slp_node
+ && (phi = dyn_cast <gphi *>
+ (STMT_VINFO_REDUC_DEF (orig_stmt_info)->stmt))
+ && dominated_by_p (CDI_DOMINATORS,
+ gimple_bb (orig_stmt_info->stmt), gimple_bb (phi)))
{
edge e = loop_latch_edge (gimple_bb (phi)->loop_father);
stmt_vec_info phi_info
- = STMT_VINFO_VEC_STMT (STMT_VINFO_REDUC_DEF (orig_stmt_info));
+ = STMT_VINFO_VEC_STMT (STMT_VINFO_REDUC_DEF (orig_stmt_info));
stmt_vec_info vec_stmt = STMT_VINFO_VEC_STMT (stmt_info);
do
{
@@ -10921,30 +10927,25 @@ vect_transform_stmt (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
while (phi_info);
gcc_assert (!vec_stmt);
}
- }
- else if (slp_node && STMT_VINFO_REDUC_DEF (orig_stmt_info)
- /* Going back and forth via STMT_VINFO_REDUC_DEF gets us to the
- stmt with the reduction meta in case of reduction groups. */
- && (STMT_VINFO_REDUC_TYPE
- (STMT_VINFO_REDUC_DEF (STMT_VINFO_REDUC_DEF (orig_stmt_info)))
- != FOLD_LEFT_REDUCTION)
- && slp_node != slp_node_instance->reduc_phis)
- {
- slp_tree phi_node = slp_node_instance->reduc_phis;
- gphi *phi = as_a <gphi *> (SLP_TREE_SCALAR_STMTS (phi_node)[0]->stmt);
- edge e = loop_latch_edge (gimple_bb (phi)->loop_father);
- gcc_assert (SLP_TREE_VEC_STMTS (phi_node).length ()
- == SLP_TREE_VEC_STMTS (slp_node).length ());
- for (unsigned i = 0; i < SLP_TREE_VEC_STMTS (phi_node).length (); ++i)
- add_phi_arg (as_a <gphi *> (SLP_TREE_VEC_STMTS (phi_node)[i]->stmt),
- gimple_get_lhs (SLP_TREE_VEC_STMTS (slp_node)[i]->stmt),
- e, gimple_phi_arg_location (phi, e->dest_idx));
+ else if (slp_node
+ && slp_node != slp_node_instance->reduc_phis)
+ {
+ slp_tree phi_node = slp_node_instance->reduc_phis;
+ gphi *phi = as_a <gphi *> (SLP_TREE_SCALAR_STMTS (phi_node)[0]->stmt);
+ edge e = loop_latch_edge (gimple_bb (phi)->loop_father);
+ gcc_assert (SLP_TREE_VEC_STMTS (phi_node).length ()
+ == SLP_TREE_VEC_STMTS (slp_node).length ());
+ for (unsigned i = 0; i < SLP_TREE_VEC_STMTS (phi_node).length (); ++i)
+ add_phi_arg (as_a <gphi *> (SLP_TREE_VEC_STMTS (phi_node)[i]->stmt),
+ gimple_get_lhs (SLP_TREE_VEC_STMTS (slp_node)[i]->stmt),
+ e, gimple_phi_arg_location (phi, e->dest_idx));
+ }
}
/* Handle stmts whose DEF is used outside the loop-nest that is
being vectorized. */
done = can_vectorize_live_stmts (stmt_info, gsi, slp_node,
- slp_node_instance, &vec_stmt, NULL);
+ slp_node_instance, true, NULL);
gcc_assert (done);
return false;
diff --git a/gcc/tree-vectorizer.c b/gcc/tree-vectorizer.c
index 800c99fea26..3e8637f070d 100644
--- a/gcc/tree-vectorizer.c
+++ b/gcc/tree-vectorizer.c
@@ -637,7 +637,7 @@ vec_info::new_stmt_vec_info (gimple *stmt)
STMT_VINFO_TYPE (res) = undef_vec_info_type;
STMT_VINFO_RELEVANT (res) = vect_unused_in_scope;
STMT_VINFO_VECTORIZABLE (res) = true;
- STMT_VINFO_VEC_REDUCTION_TYPE (res) = TREE_CODE_REDUCTION;
+ STMT_VINFO_REDUC_TYPE (res) = TREE_CODE_REDUCTION;
STMT_VINFO_VEC_COND_REDUC_CODE (res) = ERROR_MARK;
STMT_VINFO_REDUC_CODE (res) = ERROR_MARK;
STMT_VINFO_REDUC_FN (res) = IFN_LAST;
diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h
index 837fb5ab525..291304fe95e 100644
--- a/gcc/tree-vectorizer.h
+++ b/gcc/tree-vectorizer.h
@@ -933,9 +933,6 @@ public:
for loop vectorization. */
vect_memory_access_type memory_access_type;
- /* For reduction loops, this is the type of reduction. */
- enum vect_reduction_type v_reduc_type;
-
/* For CONST_COND_REDUCTION and INTEGER_INDUC_COND_REDUCTION, the
reduction code. */
enum tree_code cond_reduc_code;
@@ -947,7 +944,7 @@ public:
tree reduc_epilogue_adjustment;
/* On a reduction PHI the reduction type as detected by
- vect_force_simple_reduction. */
+ vect_is_simple_reduction and vectorizable_reduction. */
enum vect_reduction_type reduc_type;
/* The original reduction code, to be used in the epilogue. */
@@ -964,6 +961,15 @@ public:
corresponding PHI. */
stmt_vec_info reduc_def;
+ /* The vector input type relevant for reduction vectorization. */
+ tree reduc_vectype_in;
+
+ /* Whether we force a single cycle PHI during reduction vectorization. */
+ bool force_single_cycle;
+
+ /* Whether on this stmt reduction meta is recorded. */
+ bool is_reduc_info;
+
/* The number of scalar stmt references from active SLP instances. */
unsigned int num_slp_uses;
@@ -1046,11 +1052,11 @@ STMT_VINFO_BB_VINFO (stmt_vec_info stmt_vinfo)
#define STMT_VINFO_STRIDED_P(S) (S)->strided_p
#define STMT_VINFO_MEMORY_ACCESS_TYPE(S) (S)->memory_access_type
#define STMT_VINFO_SIMD_LANE_ACCESS_P(S) (S)->simd_lane_access_p
-#define STMT_VINFO_VEC_REDUCTION_TYPE(S) (S)->v_reduc_type
#define STMT_VINFO_VEC_COND_REDUC_CODE(S) (S)->cond_reduc_code
#define STMT_VINFO_VEC_INDUC_COND_INITIAL_VAL(S) (S)->induc_cond_initial_val
#define STMT_VINFO_REDUC_EPILOGUE_ADJUSTMENT(S) (S)->reduc_epilogue_adjustment
#define STMT_VINFO_REDUC_IDX(S) (S)->reduc_idx
+#define STMT_VINFO_FORCE_SINGLE_CYCLE(S) (S)->force_single_cycle
#define STMT_VINFO_DR_WRT_VEC_LOOP(S) (S)->dr_wrt_vec_loop
#define STMT_VINFO_DR_BASE_ADDRESS(S) (S)->dr_wrt_vec_loop.base_address
@@ -1084,6 +1090,7 @@ STMT_VINFO_BB_VINFO (stmt_vec_info stmt_vinfo)
#define STMT_VINFO_REDUC_CODE(S) (S)->reduc_code
#define STMT_VINFO_REDUC_FN(S) (S)->reduc_fn
#define STMT_VINFO_REDUC_DEF(S) (S)->reduc_def
+#define STMT_VINFO_REDUC_VECTYPE_IN(S) (S)->reduc_vectype_in
#define STMT_VINFO_SLP_VECT_ONLY(S) (S)->slp_vect_only_p
#define DR_GROUP_FIRST_ELEMENT(S) \
@@ -1556,12 +1563,6 @@ extern bool vect_transform_stmt (stmt_vec_info, gimple_stmt_iterator *,
extern void vect_remove_stores (stmt_vec_info);
extern opt_result vect_analyze_stmt (stmt_vec_info, bool *, slp_tree,
slp_instance, stmt_vector_for_cost *);
-extern bool vectorizable_condition (stmt_vec_info, gimple_stmt_iterator *,
- stmt_vec_info *, bool, int, slp_tree,
- stmt_vector_for_cost *);
-extern bool vectorizable_shift (stmt_vec_info, gimple_stmt_iterator *,
- stmt_vec_info *, slp_tree,
- stmt_vector_for_cost *);
extern void vect_get_load_cost (stmt_vec_info, int, bool,
unsigned int *, unsigned int *,
stmt_vector_for_cost *,
@@ -1644,6 +1645,7 @@ extern void vect_record_loop_mask (loop_vec_info, vec_loop_masks *,
unsigned int, tree);
extern tree vect_get_loop_mask (gimple_stmt_iterator *, vec_loop_masks *,
unsigned int, tree, unsigned int);
+extern stmt_vec_info info_for_reduction (stmt_vec_info);
/* Drive for loop transformation stage. */
extern class loop *vect_transform_loop (loop_vec_info);
@@ -1651,10 +1653,8 @@ extern opt_loop_vec_info vect_analyze_loop_form (class loop *,
vec_info_shared *);
extern bool vectorizable_live_operation (stmt_vec_info, gimple_stmt_iterator *,
slp_tree, slp_instance, int,
- stmt_vec_info *,
- stmt_vector_for_cost *);
-extern bool vectorizable_reduction (stmt_vec_info, gimple_stmt_iterator *,
- stmt_vec_info *, slp_tree, slp_instance,
+ bool, stmt_vector_for_cost *);
+extern bool vectorizable_reduction (stmt_vec_info, slp_tree, slp_instance,
stmt_vector_for_cost *);
extern bool vectorizable_induction (stmt_vec_info, gimple_stmt_iterator *,
stmt_vec_info *, slp_tree,
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index a2ab4a21925..cffa0508340 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -379,10 +379,7 @@ value_range_base::singleton_p (tree *result) const
}
return false;
}
-
- /* An anti-range that includes an extreme, is just a range with
- one sub-range. Use the one sub-range. */
- if (vrp_val_is_min (m_min, true) || vrp_val_is_max (m_max, true))
+ if (num_pairs () == 1)
{
value_range_base vr0, vr1;
ranges_from_anti_range (this, &vr0, &vr1, true);
@@ -803,13 +800,13 @@ value_range_base::set (enum value_range_kind kind, tree min, tree max)
kind = VR_RANGE;
}
else if (is_min
- /* As a special exception preserve non-null ranges. */
- && !(TYPE_UNSIGNED (TREE_TYPE (min))
- && integer_zerop (max)))
+ /* Allow non-zero pointers to be normalized to [1,MAX]. */
+ || (POINTER_TYPE_P (TREE_TYPE (min))
+ && integer_zerop (min)))
{
tree one = build_int_cst (TREE_TYPE (max), 1);
min = int_const_binop (PLUS_EXPR, max, one);
- max = vrp_val_max (TREE_TYPE (max));
+ max = vrp_val_max (TREE_TYPE (max), true);
kind = VR_RANGE;
}
else if (is_max)
@@ -913,15 +910,21 @@ vrp_bitmap_equal_p (const_bitmap b1, const_bitmap b2)
&& bitmap_equal_p (b1, b2)));
}
+static bool
+range_has_numeric_bounds_p (const value_range_base *vr)
+{
+ return (vr->min ()
+ && TREE_CODE (vr->min ()) == INTEGER_CST
+ && TREE_CODE (vr->max ()) == INTEGER_CST);
+}
+
/* Return true if max and min of VR are INTEGER_CST. It's not necessary
a singleton. */
bool
range_int_cst_p (const value_range_base *vr)
{
- return (vr->kind () == VR_RANGE
- && TREE_CODE (vr->min ()) == INTEGER_CST
- && TREE_CODE (vr->max ()) == INTEGER_CST);
+ return (vr->kind () == VR_RANGE && range_has_numeric_bounds_p (vr));
}
/* Return true if VR is a INTEGER_CST singleton. */
@@ -1763,119 +1766,102 @@ extract_range_from_plus_minus_expr (value_range_base *vr,
vr->set (kind, min, max);
}
-/* Normalize a value_range for use in range_ops and return it. */
+/* Return the range-ops handler for CODE and EXPR_TYPE. If no
+ suitable operator is found, return NULL and set VR to VARYING. */
-static value_range_base
-normalize_for_range_ops (const value_range_base &vr)
+static const range_operator *
+get_range_op_handler (value_range_base *vr,
+ enum tree_code code,
+ tree expr_type)
{
- tree type = vr.type ();
+ const range_operator *op = range_op_handler (code, expr_type);
+ if (!op)
+ vr->set_varying (expr_type);
+ return op;
+}
+
+/* If the types passed are supported, return TRUE, otherwise set VR to
+ VARYING and return FALSE. */
- /* This will return ~[0,0] for [&var, &var]. */
- if (POINTER_TYPE_P (type) && !range_includes_zero_p (&vr))
+static bool
+supported_types_p (value_range_base *vr,
+ tree type0,
+ tree type1 = NULL)
+{
+ if (!value_range_base::supports_type_p (type0)
+ || (type1 && !value_range_base::supports_type_p (type1)))
{
- value_range_base temp;
- temp.set_nonzero (type);
- return temp;
+ vr->set_varying (type0);
+ return false;
}
- if (vr.symbolic_p ())
- return normalize_for_range_ops (vr.normalize_symbolics ());
- if (TREE_CODE (vr.min ()) == INTEGER_CST
- && TREE_CODE (vr.max ()) == INTEGER_CST)
- return vr;
- /* Anything not strictly numeric at this point becomes varying. */
- return value_range_base (vr.type ());
+ return true;
}
-/* Fold a binary expression of two value_range's with range-ops. */
+/* If any of the ranges passed are defined, return TRUE, otherwise set
+ VR to UNDEFINED and return FALSE. */
-void
-range_fold_binary_expr (value_range_base *vr,
- enum tree_code code,
- tree expr_type,
- const value_range_base *vr0_,
- const value_range_base *vr1_)
+static bool
+defined_ranges_p (value_range_base *vr,
+ const value_range_base *vr0,
+ const value_range_base *vr1 = NULL)
{
- if (!value_range_base::supports_type_p (expr_type)
- || (!vr0_->undefined_p ()
- && !value_range_base::supports_type_p (vr0_->type ()))
- || (!vr1_->undefined_p ()
- && !value_range_base::supports_type_p (vr1_->type ())))
- {
- vr->set_varying (expr_type);
- return;
- }
- if (vr0_->undefined_p () && vr1_->undefined_p ())
+ if (vr0->undefined_p () && (!vr1 || vr1->undefined_p ()))
{
vr->set_undefined ();
- return;
- }
- range_operator *op = range_op_handler (code, expr_type);
- if (!op)
- {
- vr->set_varying (expr_type);
- return;
+ return false;
}
+ return true;
+}
- /* Mimic any behavior users of extract_range_from_binary_expr may
- expect. */
- value_range_base vr0 = *vr0_, vr1 = *vr1_;
- if (vr0.undefined_p ())
- vr0.set_varying (expr_type);
- else if (vr1.undefined_p ())
- vr1.set_varying (expr_type);
+static value_range_base
+drop_undefines_to_varying (const value_range_base *vr, tree expr_type)
+{
+ if (vr->undefined_p ())
+ return value_range_base (expr_type);
+ else
+ return *vr;
+}
+
+/* If any operand is symbolic, perform a binary operation on them and
+ return TRUE, otherwise return FALSE. */
- /* Handle symbolics. */
- if (vr0.symbolic_p () || vr1.symbolic_p ())
+static bool
+range_fold_binary_symbolics_p (value_range_base *vr,
+ tree_code code,
+ tree expr_type,
+ const value_range_base *vr0,
+ const value_range_base *vr1)
+{
+ if (vr0->symbolic_p () || vr1->symbolic_p ())
{
if ((code == PLUS_EXPR || code == MINUS_EXPR))
{
- extract_range_from_plus_minus_expr (vr, code, expr_type,
- &vr0, &vr1);
- return;
+ extract_range_from_plus_minus_expr (vr, code, expr_type, vr0, vr1);
+ return true;
}
if (POINTER_TYPE_P (expr_type) && code == POINTER_PLUS_EXPR)
{
- extract_range_from_pointer_plus_expr (vr, code, expr_type,
- &vr0, &vr1);
- return;
+ extract_range_from_pointer_plus_expr (vr, code, expr_type, vr0, vr1);
+ return true;
}
+ const range_operator *op = get_range_op_handler (vr, code, expr_type);
+ *vr = op->fold_range (expr_type,
+ vr0->normalize_symbolics (),
+ vr1->normalize_symbolics ());
+ return true;
}
-
- /* Do the range-ops dance. */
- value_range_base n0 = normalize_for_range_ops (vr0);
- value_range_base n1 = normalize_for_range_ops (vr1);
- *vr = op->fold_range (expr_type, n0, n1);
+ return false;
}
-/* Fold a unary expression of a value_range with range-ops. */
+/* If operand is symbolic, perform a unary operation on it and return
+ TRUE, otherwise return FALSE. */
-void
-range_fold_unary_expr (value_range_base *vr,
- enum tree_code code, tree expr_type,
- const value_range_base *vr0,
- tree vr0_type)
+static bool
+range_fold_unary_symbolics_p (value_range_base *vr,
+ tree_code code,
+ tree expr_type,
+ const value_range_base *vr0)
{
- /* Mimic any behavior users of extract_range_from_unary_expr may
- expect. */
- if (!value_range_base::supports_type_p (expr_type)
- || !value_range_base::supports_type_p (vr0_type))
- {
- vr->set_varying (expr_type);
- return;
- }
- if (vr0->undefined_p ())
- {
- vr->set_undefined ();
- return;
- }
- range_operator *op = range_op_handler (code, expr_type);
- if (!op)
- {
- vr->set_varying (expr_type);
- return;
- }
-
- /* Handle symbolics. */
if (vr0->symbolic_p ())
{
if (code == NEGATE_EXPR)
@@ -1884,7 +1870,7 @@ range_fold_unary_expr (value_range_base *vr,
value_range_base zero;
zero.set_zero (vr0->type ());
range_fold_binary_expr (vr, MINUS_EXPR, expr_type, &zero, vr0);
- return;
+ return true;
}
if (code == BIT_NOT_EXPR)
{
@@ -1892,30 +1878,64 @@ range_fold_unary_expr (value_range_base *vr,
value_range_base minusone;
minusone.set (build_int_cst (vr0->type (), -1));
range_fold_binary_expr (vr, MINUS_EXPR, expr_type, &minusone, vr0);
- return;
+ return true;
}
+ const range_operator *op = get_range_op_handler (vr, code, expr_type);
*vr = op->fold_range (expr_type,
- normalize_for_range_ops (*vr0),
+ vr0->normalize_symbolics (),
value_range_base (expr_type));
- return;
- }
- if (CONVERT_EXPR_CODE_P (code) && (POINTER_TYPE_P (expr_type)
- || POINTER_TYPE_P (vr0->type ())))
- {
- /* This handles symbolic conversions such such as [25, x_4]. */
- if (!range_includes_zero_p (vr0))
- vr->set_nonzero (expr_type);
- else if (vr0->zero_p ())
- vr->set_zero (expr_type);
- else
- vr->set_varying (expr_type);
- return;
+ return true;
}
+ return false;
+}
+
+/* Perform a binary operation on a pair of ranges. */
+
+void
+range_fold_binary_expr (value_range_base *vr,
+ enum tree_code code,
+ tree expr_type,
+ const value_range_base *vr0_,
+ const value_range_base *vr1_)
+{
+ if (!supported_types_p (vr, expr_type)
+ || !defined_ranges_p (vr, vr0_, vr1_))
+ return;
+ const range_operator *op = get_range_op_handler (vr, code, expr_type);
+ if (!op)
+ return;
+
+ value_range_base vr0 = drop_undefines_to_varying (vr0_, expr_type);
+ value_range_base vr1 = drop_undefines_to_varying (vr1_, expr_type);
+ if (range_fold_binary_symbolics_p (vr, code, expr_type, &vr0, &vr1))
+ return;
+
+ *vr = op->fold_range (expr_type,
+ vr0.normalize_addresses (),
+ vr1.normalize_addresses ());
+}
+
+/* Perform a unary operation on a range. */
+
+void
+range_fold_unary_expr (value_range_base *vr,
+ enum tree_code code, tree expr_type,
+ const value_range_base *vr0,
+ tree vr0_type)
+{
+ if (!supported_types_p (vr, expr_type, vr0_type)
+ || !defined_ranges_p (vr, vr0))
+ return;
+ const range_operator *op = get_range_op_handler (vr, code, expr_type);
+ if (!op)
+ return;
- /* Do the range-ops dance. */
- value_range_base n0 = normalize_for_range_ops (*vr0);
- value_range_base n1 (expr_type);
- *vr = op->fold_range (expr_type, n0, n1);
+ if (range_fold_unary_symbolics_p (vr, code, expr_type, vr0))
+ return;
+
+ *vr = op->fold_range (expr_type,
+ vr0->normalize_addresses (),
+ value_range_base (expr_type));
}
/* Given a COND_EXPR COND of the form 'V OP W', and an SSA name V,
@@ -6000,7 +6020,24 @@ value_range::union_ (const value_range *other)
}
}
-/* Normalize symbolics into constants. */
+/* Normalize addresses into constants. */
+
+value_range_base
+value_range_base::normalize_addresses () const
+{
+ if (!POINTER_TYPE_P (type ()) || range_has_numeric_bounds_p (this))
+ return *this;
+
+ if (!range_includes_zero_p (this))
+ {
+ gcc_checking_assert (TREE_CODE (m_min) == ADDR_EXPR
+ || TREE_CODE (m_max) == ADDR_EXPR);
+ return range_nonzero (type ());
+ }
+ return value_range_base (type ());
+}
+
+/* Normalize symbolics and addresses into constants. */
value_range_base
value_range_base::normalize_symbolics () const
@@ -6011,7 +6048,7 @@ value_range_base::normalize_symbolics () const
bool min_symbolic = !is_gimple_min_invariant (min ());
bool max_symbolic = !is_gimple_min_invariant (max ());
if (!min_symbolic && !max_symbolic)
- return *this;
+ return normalize_addresses ();
// [SYM, SYM] -> VARYING
if (min_symbolic && max_symbolic)
diff --git a/gcc/tree-vrp.h b/gcc/tree-vrp.h
index d20d0043ba3..4bfdfeb8f79 100644
--- a/gcc/tree-vrp.h
+++ b/gcc/tree-vrp.h
@@ -86,6 +86,7 @@ public:
static bool supports_type_p (tree);
value_range_base normalize_symbolics () const;
+ value_range_base normalize_addresses () const;
static const unsigned int m_max_pairs = 2;
bool contains_p (tree) const;
@@ -244,16 +245,6 @@ value_range_base::zero_p () const
&& integer_zerop (m_max));
}
-/* Return TRUE if range is nonzero. */
-
-inline bool
-value_range_base::nonzero_p () const
-{
- return (m_kind == VR_ANTI_RANGE
- && integer_zerop (m_min)
- && integer_zerop (m_max));
-}
-
extern void dump_value_range (FILE *, const value_range *);
extern void dump_value_range (FILE *, const value_range_base *);
@@ -321,6 +312,23 @@ extern tree get_single_symbol (tree, bool *, tree *);
extern void maybe_set_nonzero_bits (edge, tree);
extern value_range_kind determine_value_range (tree, wide_int *, wide_int *);
+/* Return TRUE if range is nonzero. */
+
+inline bool
+value_range_base::nonzero_p () const
+{
+ if (m_kind == VR_ANTI_RANGE
+ && !TYPE_UNSIGNED (type ())
+ && integer_zerop (m_min)
+ && integer_zerop (m_max))
+ return true;
+
+ return (m_kind == VR_RANGE
+ && TYPE_UNSIGNED (type ())
+ && integer_onep (m_min)
+ && vrp_val_is_max (m_max, true));
+}
+
/* Return TRUE if *VR includes the value zero. */
inline bool
diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog
index f3237fbd38f..e8d2e488588 100644
--- a/libcpp/ChangeLog
+++ b/libcpp/ChangeLog
@@ -1,3 +1,18 @@
+2019-10-11 Joseph Myers <joseph@codesourcery.com>
+
+ * include/cpplib.h (struct cpp_options): Add dfp_constants and
+ cpp_warn_c11_c2x_compat.
+ (enum cpp_warning_reason): Add CPP_W_C11_C2X_COMPAT.
+ * init.c (struct lang_flags): Add dfp_constants.
+ (lang_defaults): Set dfp_constants to 1 for GNUC2X and STDC2X and
+ 0 for other languages.
+ (cpp_set_lang): Set dfp_constants from language.
+ (cpp_create_reader): Set cpp_warn_c11_c2x_compat to -1.
+ * expr.c (interpret_float_suffix): Mention DFP constants as C2X in
+ comment.
+ (cpp_classify_number): Do not diagnose DFP constants for languages
+ setting dfp_constants, unless cpp_warn_c11_c2x_compat.
+
2019-10-04 Nathan Sidwell <nathan@acm.org>
PR preprocessor/91991
diff --git a/libcpp/expr.c b/libcpp/expr.c
index 4b514b17d9c..65baafe3f1e 100644
--- a/libcpp/expr.c
+++ b/libcpp/expr.c
@@ -98,8 +98,8 @@ interpret_float_suffix (cpp_reader *pfile, const uchar *s, size_t len)
flags = 0;
f = d = l = w = q = i = fn = fnx = fn_bits = 0;
- /* The following decimal float suffixes, from TR 24732:2009 and TS
- 18661-2:2015, are supported:
+ /* The following decimal float suffixes, from TR 24732:2009, TS
+ 18661-2:2015 and C2X, are supported:
df, DF - _Decimal32.
dd, DD - _Decimal64.
@@ -744,9 +744,16 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token,
cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0,
"fixed-point constants are a GCC extension");
- if ((result & CPP_N_DFLOAT) && CPP_PEDANTIC (pfile))
- cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0,
- "decimal float constants are a GCC extension");
+ if (result & CPP_N_DFLOAT)
+ {
+ if (CPP_PEDANTIC (pfile) && !CPP_OPTION (pfile, dfp_constants))
+ cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0,
+ "decimal float constants are a C2X feature");
+ else if (CPP_OPTION (pfile, cpp_warn_c11_c2x_compat) > 0)
+ cpp_warning_with_line (pfile, CPP_W_C11_C2X_COMPAT,
+ virtual_location, 0,
+ "decimal float constants are a C2X feature");
+ }
result |= CPP_N_FLOATING;
}
diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h
index ccbcfde6dc4..224369b93ad 100644
--- a/libcpp/include/cpplib.h
+++ b/libcpp/include/cpplib.h
@@ -480,6 +480,9 @@ struct cpp_options
/* Nonzero for C++ 2014 Standard digit separators. */
unsigned char digit_separators;
+ /* Nonzero for C2X decimal floating-point constants. */
+ unsigned char dfp_constants;
+
/* Nonzero for C++2a __VA_OPT__ feature. */
unsigned char va_opt;
@@ -508,6 +511,9 @@ struct cpp_options
/* True if warn about differences between C90 and C99. */
signed char cpp_warn_c90_c99_compat;
+ /* True if warn about differences between C11 and C2X. */
+ signed char cpp_warn_c11_c2x_compat;
+
/* True if warn about differences between C++98 and C++11. */
bool cpp_warn_cxx11_compat;
@@ -607,6 +613,7 @@ enum cpp_warning_reason {
CPP_W_DATE_TIME,
CPP_W_PEDANTIC,
CPP_W_C90_C99_COMPAT,
+ CPP_W_C11_C2X_COMPAT,
CPP_W_CXX11_COMPAT,
CPP_W_EXPANSION_TO_DEFINED
};
diff --git a/libcpp/init.c b/libcpp/init.c
index c932598b5fb..4bcec7be3e5 100644
--- a/libcpp/init.c
+++ b/libcpp/init.c
@@ -93,32 +93,33 @@ struct lang_flags
char utf8_char_literals;
char va_opt;
char scope;
+ char dfp_constants;
};
static const struct lang_flags lang_defaults[] =
-{ /* c99 c++ xnum xid c11 std digr ulit rlit udlit bincst digsep trig u8chlit vaopt scope*/
- /* GNUC89 */ { 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1 },
- /* GNUC99 */ { 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1 },
- /* GNUC11 */ { 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1 },
- /* GNUC17 */ { 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1 },
- /* GNUC2X */ { 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1 },
- /* STDC89 */ { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 },
- /* STDC94 */ { 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0 },
- /* STDC99 */ { 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0 },
- /* STDC11 */ { 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0 },
- /* STDC17 */ { 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0 },
- /* STDC2X */ { 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1 },
- /* GNUCXX */ { 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1 },
- /* CXX98 */ { 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1 },
- /* GNUCXX11 */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1 },
- /* CXX11 */ { 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1 },
- /* GNUCXX14 */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1 },
- /* CXX14 */ { 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1 },
- /* GNUCXX17 */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1 },
- /* CXX17 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1 },
- /* GNUCXX2A */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1 },
- /* CXX2A */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1 },
- /* ASM */ { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+{ /* c99 c++ xnum xid c11 std digr ulit rlit udlit bincst digsep trig u8chlit vaopt scope dfp */
+ /* GNUC89 */ { 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0 },
+ /* GNUC99 */ { 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0 },
+ /* GNUC11 */ { 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0 },
+ /* GNUC17 */ { 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0 },
+ /* GNUC2X */ { 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1 },
+ /* STDC89 */ { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
+ /* STDC94 */ { 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
+ /* STDC99 */ { 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
+ /* STDC11 */ { 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
+ /* STDC17 */ { 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
+ /* STDC2X */ { 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1 },
+ /* GNUCXX */ { 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0 },
+ /* CXX98 */ { 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0 },
+ /* GNUCXX11 */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0 },
+ /* CXX11 */ { 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0 },
+ /* GNUCXX14 */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0 },
+ /* CXX14 */ { 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0 },
+ /* GNUCXX17 */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0 },
+ /* CXX17 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0 },
+ /* GNUCXX2A */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0 },
+ /* CXX2A */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0 },
+ /* ASM */ { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
/* Sets internal flags correctly for a given language. */
@@ -145,6 +146,7 @@ cpp_set_lang (cpp_reader *pfile, enum c_lang lang)
CPP_OPTION (pfile, utf8_char_literals) = l->utf8_char_literals;
CPP_OPTION (pfile, va_opt) = l->va_opt;
CPP_OPTION (pfile, scope) = l->scope;
+ CPP_OPTION (pfile, dfp_constants) = l->dfp_constants;
}
/* Initialize library global state. */
@@ -193,6 +195,7 @@ cpp_create_reader (enum c_lang lang, cpp_hash_table *table,
CPP_OPTION (pfile, warn_trigraphs) = 2;
CPP_OPTION (pfile, warn_endif_labels) = 1;
CPP_OPTION (pfile, cpp_warn_c90_c99_compat) = -1;
+ CPP_OPTION (pfile, cpp_warn_c11_c2x_compat) = -1;
CPP_OPTION (pfile, cpp_warn_cxx11_compat) = 0;
CPP_OPTION (pfile, cpp_warn_deprecated) = 1;
CPP_OPTION (pfile, cpp_warn_long_long) = 0;
diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog
index 815118dbf83..4d2a32ccb97 100644
--- a/libgcc/ChangeLog
+++ b/libgcc/ChangeLog
@@ -1,3 +1,12 @@
+2019-10-12 John David Anglin <danglin@gcc.gnu.org>
+
+ * config/pa/lib2funcs.S (__gcc_plt_call): Load branch target to %r21.
+ Load PIC register after branch target. Fix white space.
+ * config/pa/milli64.S ($$dyncall): Separate LINUX and non LINUX
+ implementations. Load PIC register after branch target. Don't
+ clobber function pointer when it points to function descriptor.
+ Use nullification instead of branch in LINUX implementation.
+
2019-10-03 John David Anglin <danglin@gcc.gnu.org>
* config/pa/fptr.c: Disable -Warray-bounds warning.
diff --git a/libgcc/config/pa/lib2funcs.S b/libgcc/config/pa/lib2funcs.S
index b401b6157da..a2db5b3d3ac 100644
--- a/libgcc/config/pa/lib2funcs.S
+++ b/libgcc/config/pa/lib2funcs.S
@@ -55,13 +55,13 @@ __gcc_plt_call
; An inline version of dyncall so we don't have to worry
; about long calls to millicode, PIC and other complexities.
bb,>=,n %r22,30,L$foo
- depi 0,31,2,%r22
- ldw 4(%r22),%r19
- ldw 0(%r22),%r22
+ depi 0,31,2,%r22
+ ldw 0(%r22),%r21
+ ldw 4(%r22),%r19
L$foo
- ldsid (%r22),%r1
- mtsp %r1,%sr0
- ble 0(%sr0,%r22)
+ ldsid (%r21),%r1
+ mtsp %r1,%sr0
+ ble 0(%sr0,%r21)
copy %r31,%r2
ldw -8(%r30),%r2
diff --git a/libgcc/config/pa/milli64.S b/libgcc/config/pa/milli64.S
index 1e46f5018b9..36040e9e78d 100644
--- a/libgcc/config/pa/milli64.S
+++ b/libgcc/config/pa/milli64.S
@@ -222,19 +222,26 @@ GSYM($$dyncall)
.proc
.callinfo millicode
.entry
- bb,>=,n %r22,30,LREF(1) ; branch if not plabel address
- depi 0,31,2,%r22 ; clear the two least significant bits
- ldw 4(%r22),%r19 ; load new LTP value
- ldw 0(%r22),%r22 ; load address of target
-LSYM(1)
#ifdef LINUX
- bv %r0(%r22) ; branch to the real target
+ extru,<> %r22,30,1,%r0 ; nullify if plabel bit set
+ bv,n %r0(%r22) ; branch to target
+ ldw -2(%r22),%r21 ; load address of target
+ bv %r0(%r21) ; branch to the real target
+ ldw 2(%r22),%r19 ; load new LTP value
#else
+ bb,>=,n %r22,30,LREF(1) ; branch if not plabel address
+ ldw -2(%r22),%r21 ; load address of target to r21
+ ldsid (%sr0,%r21),%r1 ; get the "space ident" selected by r21
+ ldw 2(%r22),%r19 ; load new LTP value
+ mtsp %r1,%sr0 ; move that space identifier into sr0
+ be 0(%sr0,%r21) ; branch to the real target
+ stw %r2,-24(%r30) ; save return address into frame marker
+LSYM(1)
ldsid (%sr0,%r22),%r1 ; get the "space ident" selected by r22
mtsp %r1,%sr0 ; move that space identifier into sr0
- be 0(%sr0,%r22) ; branch to the real target
-#endif
+ be 0(%sr0,%r22) ; branch to the target
stw %r2,-24(%r30) ; save return address into frame marker
+#endif
.exit
.procend
#endif
diff --git a/libgfortran/ChangeLog b/libgfortran/ChangeLog
index 7736e5da937..c5a45333042 100644
--- a/libgfortran/ChangeLog
+++ b/libgfortran/ChangeLog
@@ -1,3 +1,10 @@
+2019-10-08 Thomas Schwinge <thomas@codesourcery.com>
+
+ PR fortran/68401
+ * runtime/minimal.c (os_error_at): New function.
+
+ * runtime/minimal.c: Revise.
+
2019-10-05 Paul Thomas <pault@gcc.gnu.org>
PR fortran/91926
diff --git a/libgfortran/runtime/minimal.c b/libgfortran/runtime/minimal.c
index c1993b99be7..bdaf878ffcb 100644
--- a/libgfortran/runtime/minimal.c
+++ b/libgfortran/runtime/minimal.c
@@ -23,13 +23,38 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
<http://www.gnu.org/licenses/>. */
#include "libgfortran.h"
-#include <string.h>
+#include <string.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
+
+#if __nvptx__
+/* Map "exit" to "abort"; see PR85463 '[nvptx] "exit" in offloaded region
+ doesn't terminate process'. */
+# undef exit
+# define exit(status) do { (void) (status); abort (); } while (0)
+#endif
+
+
+#if __nvptx__
+/* 'printf' is all we have. */
+# undef estr_vprintf
+# define estr_vprintf vprintf
+#else
+# error TODO
+#endif
+
+
+/* runtime/environ.c */
+
+options_t options;
+
+
+/* runtime/main.c */
+
/* Stupid function to be sure the constructor is always linked in, even
in the case of static linking. See PR libfortran/22298 for details. */
void
@@ -38,11 +63,126 @@ stupid_function_name_for_static_linking (void)
return;
}
-options_t options;
static int argc_save;
static char **argv_save;
+
+/* Set the saved values of the command line arguments. */
+
+void
+set_args (int argc, char **argv)
+{
+ argc_save = argc;
+ argv_save = argv;
+}
+iexport(set_args);
+
+
+/* Retrieve the saved values of the command line arguments. */
+
+void
+get_args (int *argc, char ***argv)
+{
+ *argc = argc_save;
+ *argv = argv_save;
+}
+
+
+/* runtime/error.c */
+
+/* Write a null-terminated C string to standard error. This function
+ is async-signal-safe. */
+
+ssize_t
+estr_write (const char *str)
+{
+ return write (STDERR_FILENO, str, strlen (str));
+}
+
+
+/* printf() like function for for printing to stderr. Uses a stack
+ allocated buffer and doesn't lock stderr, so it should be safe to
+ use from within a signal handler. */
+
+int
+st_printf (const char * format, ...)
+{
+ int written;
+ va_list ap;
+ va_start (ap, format);
+ written = estr_vprintf (format, ap);
+ va_end (ap);
+ return written;
+}
+
+
+/* sys_abort()-- Terminate the program showing backtrace and dumping
+ core. */
+
+void
+sys_abort (void)
+{
+ /* If backtracing is enabled, print backtrace and disable signal
+ handler for ABRT. */
+ if (options.backtrace == 1
+ || (options.backtrace == -1 && compile_options.backtrace == 1))
+ {
+ estr_write ("\nProgram aborted.\n");
+ }
+
+ abort();
+}
+
+
+/* Exit in case of error termination. If backtracing is enabled, print
+ backtrace, then exit. */
+
+void
+exit_error (int status)
+{
+ if (options.backtrace == 1
+ || (options.backtrace == -1 && compile_options.backtrace == 1))
+ {
+ estr_write ("\nError termination.\n");
+ }
+ exit (status);
+}
+
+
+/* show_locus()-- Print a line number and filename describing where
+ * something went wrong */
+
+void
+show_locus (st_parameter_common *cmp)
+{
+ char *filename;
+
+ if (!options.locus || cmp == NULL || cmp->filename == NULL)
+ return;
+
+ if (cmp->unit > 0)
+ {
+ filename = /* TODO filename_from_unit (cmp->unit) */ NULL;
+
+ if (filename != NULL)
+ {
+ st_printf ("At line %d of file %s (unit = %d, file = '%s')\n",
+ (int) cmp->line, cmp->filename, (int) cmp->unit, filename);
+ free (filename);
+ }
+ else
+ {
+ st_printf ("At line %d of file %s (unit = %d)\n",
+ (int) cmp->line, cmp->filename, (int) cmp->unit);
+ }
+ return;
+ }
+
+ st_printf ("At line %d of file %s\n", (int) cmp->line, cmp->filename);
+}
+
+
/* recursion_check()-- It's possible for additional errors to occur
* during fatal error processing. We detect this condition here and
* exit with code 4 immediately. */
@@ -70,11 +210,33 @@ void
os_error (const char *message)
{
recursion_check ();
- printf ("Operating system error: ");
- printf ("%s\n", message);
- exit (1);
+ estr_write ("Operating system error: ");
+ estr_write (message);
+ estr_write ("\n");
+ exit_error (1);
}
-iexport(os_error);
+iexport(os_error); /* TODO, DEPRECATED, ABI: Should not be exported
+ anymore when bumping so version. */
+
+
+/* Improved version of os_error with a printf style format string and
+ a locus. */
+
+void
+os_error_at (const char *where, const char *message, ...)
+{
+ va_list ap;
+
+ recursion_check ();
+ estr_write (where);
+ estr_write (": ");
+ va_start (ap, message);
+ estr_vprintf (message, ap);
+ va_end (ap);
+ estr_write ("\n");
+ exit_error (1);
+}
+iexport(os_error_at);
/* void runtime_error()-- These are errors associated with an
@@ -86,12 +248,12 @@ runtime_error (const char *message, ...)
va_list ap;
recursion_check ();
- printf ("Fortran runtime error: ");
+ estr_write ("Fortran runtime error: ");
va_start (ap, message);
- vprintf (message, ap);
+ estr_vprintf (message, ap);
va_end (ap);
- printf ("\n");
- exit (2);
+ estr_write ("\n");
+ exit_error (2);
}
iexport(runtime_error);
@@ -104,13 +266,13 @@ runtime_error_at (const char *where, const char *message, ...)
va_list ap;
recursion_check ();
- printf ("%s", where);
- printf ("\nFortran runtime error: ");
+ estr_write (where);
+ estr_write ("\nFortran runtime error: ");
va_start (ap, message);
- vprintf (message, ap);
+ estr_vprintf (message, ap);
va_end (ap);
- printf ("\n");
- exit (2);
+ estr_write ("\n");
+ exit_error (2);
}
iexport(runtime_error_at);
@@ -120,12 +282,12 @@ runtime_warning_at (const char *where, const char *message, ...)
{
va_list ap;
- printf ("%s", where);
- printf ("\nFortran runtime warning: ");
+ estr_write (where);
+ estr_write ("\nFortran runtime warning: ");
va_start (ap, message);
- vprintf (message, ap);
+ estr_vprintf (message, ap);
va_end (ap);
- printf ("\n");
+ estr_write ("\n");
}
iexport(runtime_warning_at);
@@ -137,9 +299,10 @@ void
internal_error (st_parameter_common *cmp, const char *message)
{
recursion_check ();
- printf ("Internal Error: ");
- printf ("%s", message);
- printf ("\n");
+ show_locus (cmp);
+ estr_write ("Internal Error: ");
+ estr_write (message);
+ estr_write ("\n");
/* This function call is here to get the main.o object file included
when linking statically. This works because error.o is supposed to
@@ -147,45 +310,7 @@ internal_error (st_parameter_common *cmp, const char *message)
because hopefully it doesn't happen too often). */
stupid_function_name_for_static_linking();
- exit (3);
-}
-
-
-/* Set the saved values of the command line arguments. */
-
-void
-set_args (int argc, char **argv)
-{
- argc_save = argc;
- argv_save = argv;
-}
-iexport(set_args);
-
-
-/* Retrieve the saved values of the command line arguments. */
-
-void
-get_args (int *argc, char ***argv)
-{
- *argc = argc_save;
- *argv = argv_save;
-}
-
-/* sys_abort()-- Terminate the program showing backtrace and dumping
- core. */
-
-void
-sys_abort (void)
-{
- /* If backtracing is enabled, print backtrace and disable signal
- handler for ABRT. */
- if (options.backtrace == 1
- || (options.backtrace == -1 && compile_options.backtrace == 1))
- {
- printf ("\nProgram aborted.\n");
- }
-
- abort();
+ exit_error (3);
}
@@ -193,18 +318,7 @@ sys_abort (void)
#undef report_exception
#define report_exception() do {} while (0)
-#undef st_printf
-#define st_printf printf
-#undef estr_write
-#define estr_write(X) write(STDERR_FILENO, (X), strlen (X))
-#if __nvptx__
-/* Map "exit" to "abort"; see PR85463 '[nvptx] "exit" in offloaded region
- doesn't terminate process'. */
-#undef exit
-#define exit(...) do { abort (); } while (0)
-#endif
-#undef exit_error
-#define exit_error(...) do { abort (); } while (0)
+
/* A numeric STOP statement. */
diff --git a/libgomp/ChangeLog b/libgomp/ChangeLog
index 2059e053457..8a3c98b8f94 100644
--- a/libgomp/ChangeLog
+++ b/libgomp/ChangeLog
@@ -1,3 +1,32 @@
+2019-10-11 Tobias Burnus <tobias@codesourcery.com>
+
+ * testsuite/libgomp.fortran/use_device_addr-1.f90: New.
+ * testsuite/libgomp.fortran/use_device_addr-2.f90: New.
+
+2019-10-09 Thomas Schwinge <thomas@codesourcery.com>
+
+ PR middle-end/92036
+ * testsuite/libgomp.oacc-c-c++-common/data-firstprivate-1.c: New
+ file.
+
+2019-10-09 Tobias Burnus <tobias@codesourcery.com>
+
+ PR testsuite/91884
+ * testsuite/libgomp.fortran/fortran.exp: Conditionally
+ add -lquadmath.
+ * testsuite/libgomp.oacc-fortran/fortran.exp: Ditto.
+
+2019-10-09 Jakub Jelinek <jakub@redhat.com>
+
+ PR libgomp/92028
+ * target.c (gomp_map_vars_internal): Readd the previous
+ GOMP_MAP_USE_DEVICE_PTR handling code in the first loop,
+ though do that just in the !not_found_cnt case.
+
+2019-10-08 Tobias Burnus <tobias@codesourcery.com>
+
+ * gfortran.dg/gomp/target-simd.f90: New.
+
2019-10-02 Julian Brown <julian@codesourcery.com>
Cesar Philippidis <cesar@codesourcery.com>
diff --git a/libgomp/target.c b/libgomp/target.c
index a83cb48108a..84d6daa76ca 100644
--- a/libgomp/target.c
+++ b/libgomp/target.c
@@ -593,6 +593,30 @@ gomp_map_vars_internal (struct gomp_device_descr *devicep,
tgt->list[i].key = NULL;
if (!not_found_cnt)
{
+ /* In OpenMP < 5.0 and OpenACC the mapping has to be done
+ on a separate construct prior to using use_device_{addr,ptr}.
+ In OpenMP 5.0, map directives need to be ordered by the
+ middle-end before the use_device_* clauses. If
+ !not_found_cnt, all mappings requested (if any) are already
+ mapped, so use_device_{addr,ptr} can be resolved right away.
+ Otherwise, if not_found_cnt, gomp_map_lookup might fail
+ now but would succeed after performing the mappings in the
+ following loop. We can't defer this always to the second
+ loop, because it is not even invoked when !not_found_cnt
+ after the first loop. */
+ cur_node.host_start = (uintptr_t) hostaddrs[i];
+ cur_node.host_end = cur_node.host_start;
+ splay_tree_key n = gomp_map_lookup (mem_map, &cur_node);
+ if (n == NULL)
+ {
+ gomp_mutex_unlock (&devicep->lock);
+ gomp_fatal ("use_device_ptr pointer wasn't mapped");
+ }
+ cur_node.host_start -= n->host_start;
+ hostaddrs[i]
+ = (void *) (n->tgt->tgt_start + n->tgt_offset
+ + cur_node.host_start);
+ tgt->list[i].offset = ~(uintptr_t) 0;
}
else
tgt->list[i].offset = 0;
diff --git a/libgomp/testsuite/libgomp.fortran/fortran.exp b/libgomp/testsuite/libgomp.fortran/fortran.exp
index d848ed4d47f..eb701311b6a 100644
--- a/libgomp/testsuite/libgomp.fortran/fortran.exp
+++ b/libgomp/testsuite/libgomp.fortran/fortran.exp
@@ -54,11 +54,17 @@ if { $lang_test_file_found } {
# Allow for spec subsitution.
lappend ALWAYS_CFLAGS "additional_flags=-B${blddir}/${quadmath_library_path}/"
set ld_library_path "$always_ld_library_path:${blddir}/${lang_library_path}:${blddir}/${quadmath_library_path}"
+ append lang_link_flags " -lquadmath"
} else {
set ld_library_path "$always_ld_library_path:${blddir}/${lang_library_path}"
}
} else {
set ld_library_path "$always_ld_library_path"
+ if { [check_no_compiler_messages has_libquadmath executable {
+ int main() {return 0;}
+ } "-lgfortran -lquadmath"] } then {
+ append lang_link_flags " -lquadmath"
+ }
}
append ld_library_path [gcc-set-multilib-library-path $GCC_UNDER_TEST]
set_ld_library_path_env_vars
diff --git a/libgomp/testsuite/libgomp.fortran/target-simd.f90 b/libgomp/testsuite/libgomp.fortran/target-simd.f90
new file mode 100644
index 00000000000..d49ae74af8f
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/target-simd.f90
@@ -0,0 +1,26 @@
+! { dg-do run }
+
+program test
+ implicit none
+ real, allocatable :: a(:), b(:)
+ integer :: i
+
+ a = [(i, i = 1, 100)]
+ allocate(b, mold=a)
+ b = 0
+
+ !$omp target simd map(to:a) map(from:b)
+ do i = 0, size(a)
+ b(i) = 5.0 * a(i)
+ end do
+
+ if (any (b - 5.0 *a > 10.0*epsilon(a))) call abort()
+
+ !$omp target simd map(to:a) map(from:b)
+ do i = 0, size(a)
+ b(i) = 2.0 * a(i)
+ end do
+ !$omp end target simd
+
+ if (any (b - 2.0 *a > 10.0*epsilon(a))) call abort()
+end program test
diff --git a/libgomp/testsuite/libgomp.fortran/use_device_addr-1.f90 b/libgomp/testsuite/libgomp.fortran/use_device_addr-1.f90
new file mode 100644
index 00000000000..2e5ce60d47c
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/use_device_addr-1.f90
@@ -0,0 +1,1196 @@
+! Comprehensive run-time test for use_device_addr
+!
+! Differs from use_device_addr-2.f90 by using a 8-byte variable (c_double)
+!
+! This test case assumes that a 'var' appearing in 'use_device_addr' is
+! only used as 'c_loc(var)' - such that only the actual data is used/usable
+! on the device - and not meta data ((dynamic) type information, 'present()'
+! status, array shape).
+!
+! Untested in this test case are:
+! - arrays with array descriptor
+! - polymorphic variables
+! - absent optional arguments
+!
+module target_procs
+ use iso_c_binding
+ implicit none (type, external)
+ private
+ public :: copy3_array, copy3_scalar
+contains
+ subroutine copy3_array_int(from_ptr, to_ptr, N)
+ !$omp declare target
+ real(c_double) :: from_ptr(:)
+ real(c_double) :: to_ptr(:)
+ integer, value :: N
+ integer :: i
+
+ !$omp parallel do
+ do i = 1, N
+ to_ptr(i) = 3 * from_ptr(i)
+ end do
+ !$omp end parallel do
+ end subroutine copy3_array_int
+
+ subroutine copy3_scalar_int(from, to)
+ !$omp declare target
+ real(c_double) :: from, to
+
+ to = 3 * from
+ end subroutine copy3_scalar_int
+
+
+ subroutine copy3_array(from, to, N)
+ type(c_ptr), value :: from, to
+ integer, value :: N
+ real(c_double), pointer :: from_ptr(:), to_ptr(:)
+
+ call c_f_pointer(from, from_ptr, shape=[N])
+ call c_f_pointer(to, to_ptr, shape=[N])
+
+ call do_offload_scalar(from_ptr,to_ptr)
+ contains
+ subroutine do_offload_scalar(from_r, to_r)
+ real(c_double), target :: from_r(:), to_r(:)
+ ! The extra function is needed as is_device_ptr
+ ! requires non-value, non-pointer dummy arguments
+
+ !$omp target is_device_ptr(from_r, to_r)
+ call copy3_array_int(from_r, to_r, N)
+ !$omp end target
+ end subroutine do_offload_scalar
+ end subroutine copy3_array
+
+ subroutine copy3_scalar(from, to)
+ type(c_ptr), value, target :: from, to
+ real(c_double), pointer :: from_ptr(:), to_ptr(:)
+
+ ! Standard-conform detour of using an array as at time of writing
+ ! is_device_ptr below does not handle scalars
+ call c_f_pointer(from, from_ptr, shape=[1])
+ call c_f_pointer(to, to_ptr, shape=[1])
+
+ call do_offload_scalar(from_ptr,to_ptr)
+ contains
+ subroutine do_offload_scalar(from_r, to_r)
+ real(c_double), target :: from_r(:), to_r(:)
+ ! The extra function is needed as is_device_ptr
+ ! requires non-value, non-pointer dummy arguments
+
+ !$omp target is_device_ptr(from_r, to_r)
+ call copy3_scalar_int(from_r(1), to_r(1))
+ !$omp end target
+ end subroutine do_offload_scalar
+ end subroutine copy3_scalar
+end module target_procs
+
+
+
+! Test local dummy arguments (w/o optional)
+module test_dummies
+ use iso_c_binding
+ use target_procs
+ implicit none (type, external)
+ private
+ public :: test_dummy_call_1, test_dummy_call_2
+contains
+ subroutine test_dummy_call_1()
+ integer, parameter :: N = 1000
+
+ ! scalars
+ real(c_double), target :: aa, bb
+ real(c_double), target, allocatable :: cc, dd
+ real(c_double), pointer :: ee, ff
+
+ ! non-descriptor arrays
+ real(c_double), target :: gg(N), hh(N)
+
+ allocate(cc, dd, ee, ff)
+
+ aa = 11.0_c_double
+ bb = 22.0_c_double
+ cc = 33.0_c_double
+ dd = 44.0_c_double
+ ee = 55.0_c_double
+ ff = 66.0_c_double
+ gg = 77.0_c_double
+ hh = 88.0_c_double
+
+ call test_dummy_callee_1(aa, bb, cc, dd, ee, ff, gg, hh, N)
+ deallocate(ee, ff) ! pointers, only
+ end subroutine test_dummy_call_1
+
+ subroutine test_dummy_callee_1(aa, bb, cc, dd, ee, ff, gg, hh, N)
+ ! scalars
+ real(c_double), target :: aa, bb
+ real(c_double), target, allocatable :: cc, dd
+ real(c_double), pointer :: ee, ff
+
+ ! non-descriptor arrays
+ real(c_double), target :: gg(N), hh(N)
+ integer, value :: N
+
+ !$omp target data map(to:aa) map(from:bb) use_device_addr(aa,bb)
+ call copy3_scalar(c_loc(aa), c_loc(bb))
+ !$omp end target data
+ if (abs(aa - 11.0_c_double) > 10.0_c_double * epsilon(aa)) stop 1
+ if (abs(3.0_c_double * aa - bb) > 10.0_c_double * epsilon(aa)) stop 1
+
+ !$omp target data map(to:cc) map(from:dd) use_device_addr(cc,dd)
+ call copy3_scalar(c_loc(cc), c_loc(dd))
+ !$omp end target data
+ if (abs(cc - 33.0_c_double) > 10.0_c_double * epsilon(cc)) stop 1
+ if (abs(3.0_c_double * cc - dd) > 10.0_c_double * epsilon(cc)) stop 1
+
+ !$omp target data map(to:ee) map(from:ff) use_device_addr(ee,ff)
+ call copy3_scalar(c_loc(ee), c_loc(ff))
+ !$omp end target data
+ if (abs(ee - 55.0_c_double) > 10.0_c_double * epsilon(ee)) stop 1
+ if (abs(3.0_c_double * ee - ff) > 10.0_c_double * epsilon(ee)) stop 1
+
+
+ !$omp target data map(to:gg) map(from:hh) use_device_addr(gg,hh)
+ call copy3_array(c_loc(gg), c_loc(hh), N)
+ !$omp end target data
+ if (any(abs(gg - 77.0_c_double) > 10.0_c_double * epsilon(gg))) stop 1
+ if (any(abs(3.0_c_double * gg - hh) > 10.0_c_double * epsilon(gg))) stop 1
+ end subroutine test_dummy_callee_1
+
+ ! Save device ptr - and recall pointer
+ subroutine test_dummy_call_2()
+ integer, parameter :: N = 1000
+
+ ! scalars
+ real(c_double), target :: aa, bb
+ real(c_double), target, allocatable :: cc, dd
+ real(c_double), pointer :: ee, ff
+
+ ! non-descriptor arrays
+ real(c_double), target :: gg(N), hh(N)
+
+ type(c_ptr) :: c_aptr, c_bptr, c_cptr, c_dptr, c_eptr, c_fptr, c_gptr, c_hptr
+ real(c_double), pointer :: aptr, bptr, cptr, dptr, eptr, fptr
+ real(c_double), pointer :: gptr(:), hptr(:)
+
+ allocate(cc, dd, ee, ff)
+ call test_dummy_callee_2(aa, bb, cc, dd, ee, ff, gg, hh, &
+ c_aptr, c_bptr, c_cptr, c_dptr, c_eptr, c_fptr, c_gptr, c_hptr, &
+ aptr, bptr, cptr, dptr, eptr, fptr, gptr, hptr, &
+ N)
+ deallocate(ee, ff)
+ end subroutine test_dummy_call_2
+
+ subroutine test_dummy_callee_2(aa, bb, cc, dd, ee, ff, gg, hh, &
+ c_aptr, c_bptr, c_cptr, c_dptr, c_eptr, c_fptr, c_gptr, c_hptr, &
+ aptr, bptr, cptr, dptr, eptr, fptr, gptr, hptr, &
+ N)
+ ! scalars
+ real(c_double), target :: aa, bb
+ real(c_double), target, allocatable :: cc, dd
+ real(c_double), pointer :: ee, ff
+
+ ! non-descriptor arrays
+ real(c_double), target :: gg(N), hh(N)
+
+ type(c_ptr) :: c_aptr, c_bptr, c_cptr, c_dptr, c_eptr, c_fptr, c_gptr, c_hptr
+ real(c_double), pointer :: aptr, bptr, cptr, dptr, eptr, fptr
+ real(c_double), pointer :: gptr(:), hptr(:)
+
+ integer, value :: N
+
+ real(c_double) :: dummy
+
+ aa = 111.0_c_double
+ bb = 222.0_c_double
+ cc = 333.0_c_double
+ dd = 444.0_c_double
+ ee = 555.0_c_double
+ ff = 666.0_c_double
+ gg = 777.0_c_double
+ hh = 888.0_c_double
+
+ !$omp target data map(to:aa) map(from:bb)
+ !$omp target data map(alloc:dummy) use_device_addr(aa,bb)
+ c_aptr = c_loc(aa)
+ c_bptr = c_loc(bb)
+ aptr => aa
+ bptr => bb
+ !$omp end target data
+
+ ! check c_loc ptr once
+ call copy3_scalar(c_aptr, c_bptr)
+ !$omp target update from(bb)
+ if (abs(aa - 111.0_c_double) > 10.0_c_double * epsilon(aa)) stop 1
+ if (abs(3.0_c_double * aa - bb) > 10.0_c_double * epsilon(aa)) stop 1
+
+ ! check c_loc ptr again after target-value modification
+ aa = 1111.0_c_double
+ !$omp target update to(aa)
+ call copy3_scalar(c_aptr, c_bptr)
+ !$omp target update from(bb)
+ if (abs(aa - 1111.0_c_double) > 10.0_c_double * epsilon(aa)) stop 1
+ if (abs(3.0_c_double * aa - bb) > 10.0_c_double * epsilon(aa)) stop 1
+
+ ! check Fortran pointer after target-value modification
+ aa = 11111.0_c_double
+ !$omp target update to(aa)
+ call copy3_scalar(c_loc(aptr), c_loc(bptr))
+ !$omp target update from(bb)
+ if (abs(aa - 11111.0_c_double) > 10.0_c_double * epsilon(aa)) stop 1
+ if (abs(3.0_c_double * aa - bb) > 10.0_c_double * epsilon(aa)) stop 1
+ !$omp end target data
+
+ if (abs(aa - 11111.0_c_double) > 10.0_c_double * epsilon(aa)) stop 1
+ if (abs(3.0_c_double * aa - bb) > 10.0_c_double * epsilon(aa)) stop 1
+
+
+ !$omp target data map(to:cc) map(from:dd)
+ !$omp target data map(alloc:dummy) use_device_addr(cc,dd)
+ c_cptr = c_loc(cc)
+ c_dptr = c_loc(dd)
+ cptr => cc
+ dptr => dd
+ !$omp end target data
+
+ ! check c_loc ptr once
+ call copy3_scalar(c_cptr, c_dptr)
+ !$omp target update from(dd)
+ if (abs(cc - 333.0_c_double) > 10.0_c_double * epsilon(cc)) stop 1
+ if (abs(3.0_c_double * cc - dd) > 10.0_c_double * epsilon(cc)) stop 1
+
+ ! check c_loc ptr again after target-value modification
+ cc = 3333.0_c_double
+ !$omp target update to(cc)
+ call copy3_scalar(c_cptr, c_dptr)
+ !$omp target update from(dd)
+ if (abs(cc - 3333.0_c_double) > 10.0_c_double * epsilon(cc)) stop 1
+ if (abs(3.0_c_double * cc - dd) > 10.0_c_double * epsilon(cc)) stop 1
+
+ ! check Fortran pointer after target-value modification
+ cc = 33333.0_c_double
+ !$omp target update to(cc)
+ call copy3_scalar(c_loc(cptr), c_loc(dptr))
+ !$omp target update from(dd)
+ if (abs(cc - 33333.0_c_double) > 10.0_c_double * epsilon(cc)) stop 1
+ if (abs(3.0_c_double * cc - dd) > 10.0_c_double * epsilon(cc)) stop 1
+ !$omp end target data
+
+ if (abs(cc - 33333.0_c_double) > 10.0_c_double * epsilon(dd)) stop 1
+ if (abs(3.0_c_double * cc - dd) > 10.0_c_double * epsilon(dd)) stop 1
+
+
+ !$omp target data map(to:ee) map(from:ff)
+ !$omp target data map(alloc:dummy) use_device_addr(ee,ff)
+ c_eptr = c_loc(ee)
+ c_fptr = c_loc(ff)
+ eptr => ee
+ fptr => ff
+ !$omp end target data
+
+ ! check c_loc ptr once
+ call copy3_scalar(c_eptr, c_fptr)
+ !$omp target update from(ff)
+ if (abs(ee - 555.0_c_double) > 10.0_c_double * epsilon(ee)) stop 1
+ if (abs(3.0_c_double * ee - ff) > 10.0_c_double * epsilon(ee)) stop 1
+
+ ! check c_loc ptr again after target-value modification
+ ee = 5555.0_c_double
+ !$omp target update to(ee)
+ call copy3_scalar(c_eptr, c_fptr)
+ !$omp target update from(ff)
+ if (abs(ee - 5555.0_c_double) > 10.0_c_double * epsilon(ee)) stop 1
+ if (abs(3.0_c_double * ee - ff) > 10.0_c_double * epsilon(ee)) stop 1
+
+ ! check Fortran pointer after target-value modification
+ ee = 55555.0_c_double
+ !$omp target update to(ee)
+ call copy3_scalar(c_loc(eptr), c_loc(fptr))
+ !$omp target update from(ff)
+ if (abs(ee - 55555.0_c_double) > 10.0_c_double * epsilon(ee)) stop 1
+ if (abs(3.0_c_double * ee - ff) > 10.0_c_double * epsilon(ff)) stop 1
+ !$omp end target data
+
+ if (abs(ee - 55555.0_c_double) > 10.0_c_double * epsilon(ee)) stop 1
+ if (abs(3.0_c_double * ee - ff) > 10.0_c_double * epsilon(ee)) stop 1
+
+
+ !$omp target data map(to:gg) map(from:hh)
+ !$omp target data map(alloc:dummy) use_device_addr(gg,hh)
+ c_gptr = c_loc(gg)
+ c_hptr = c_loc(hh)
+ gptr => gg
+ hptr => hh
+ !$omp end target data
+
+ ! check c_loc ptr once
+ call copy3_array(c_gptr, c_hptr, N)
+ !$omp target update from(hh)
+ if (any(abs(gg - 777.0_c_double) > 10.0_c_double * epsilon(gg))) stop 1
+ if (any(abs(3.0_c_double * gg - hh) > 10.0_c_double * epsilon(hh))) stop 1
+
+ ! check c_loc ptr again after target-value modification
+ gg = 7777.0_c_double
+ !$omp target update to(gg)
+ call copy3_array(c_gptr, c_hptr, N)
+ !$omp target update from(hh)
+ if (any(abs(gg - 7777.0_c_double) > 10.0_c_double * epsilon(gg))) stop 1
+ if (any(abs(3.0_c_double * gg - hh) > 10.0_c_double * epsilon(gg))) stop 1
+
+ ! check Fortran pointer after target-value modification
+ gg = 77777.0_c_double
+ !$omp target update to(gg)
+ call copy3_array(c_loc(gptr), c_loc(hptr), N)
+ !$omp target update from(hh)
+ if (any(abs(gg - 77777.0_c_double) > 10.0_c_double * epsilon(gg))) stop 1
+ if (any(abs(3.0_c_double * gg - hh) > 10.0_c_double * epsilon(gg))) stop 1
+ !$omp end target data
+
+ if (any(abs(gg - 77777.0_c_double) > 10.0_c_double * epsilon(gg))) stop 1
+ if (any(abs(3.0_c_double * gg - hh) > 10.0_c_double * epsilon(gg))) stop 1
+ end subroutine test_dummy_callee_2
+end module test_dummies
+
+
+
+! Test local dummy arguments + VALUE (w/o optional)
+module test_dummies_value
+ use iso_c_binding
+ use target_procs
+ implicit none (type, external)
+ private
+ public :: test_dummy_val_call_1, test_dummy_val_call_2
+contains
+ subroutine test_dummy_val_call_1()
+ ! scalars - with value, neither allocatable nor pointer no dimension permitted
+ real(c_double), target :: aa, bb
+
+ aa = 11.0_c_double
+ bb = 22.0_c_double
+
+ call test_dummy_val_callee_1(aa, bb)
+ end subroutine test_dummy_val_call_1
+
+ subroutine test_dummy_val_callee_1(aa, bb)
+ ! scalars
+ real(c_double), value, target :: aa, bb
+
+ !$omp target data map(to:aa) map(from:bb) use_device_addr(aa,bb)
+ call copy3_scalar(c_loc(aa), c_loc(bb))
+ !$omp end target data
+ if (abs(aa - 11.0_c_double) > 10.0_c_double * epsilon(aa)) stop 1
+ if (abs(3.0_c_double * aa - bb) > 10.0_c_double * epsilon(aa)) stop 1
+ end subroutine test_dummy_val_callee_1
+
+ ! Save device ptr - and recall pointer
+ subroutine test_dummy_val_call_2()
+ ! scalars - with value, neither allocatable nor pointer no dimension permitted
+ real(c_double), target :: aa, bb
+ type(c_ptr) :: c_aptr, c_bptr
+ real(c_double), pointer :: aptr, bptr
+
+ call test_dummy_val_callee_2(aa, bb, c_aptr, c_bptr, aptr, bptr)
+ end subroutine test_dummy_val_call_2
+
+ subroutine test_dummy_val_callee_2(aa, bb, c_aptr, c_bptr, aptr, bptr)
+ real(c_double), value, target :: aa, bb
+ type(c_ptr), value :: c_aptr, c_bptr
+ real(c_double), pointer :: aptr, bptr
+
+ real(c_double) :: dummy
+
+ aa = 111.0_c_double
+ bb = 222.0_c_double
+
+ !$omp target data map(to:aa) map(from:bb)
+ !$omp target data map(alloc:dummy) use_device_addr(aa,bb)
+ c_aptr = c_loc(aa)
+ c_bptr = c_loc(bb)
+ aptr => aa
+ bptr => bb
+ !$omp end target data
+
+ ! check c_loc ptr once
+ call copy3_scalar(c_aptr, c_bptr)
+ !$omp target update from(bb)
+ if (abs(aa - 111.0_c_double) > 10.0_c_double * epsilon(aa)) stop 1
+ if (abs(3.0_c_double * aa - bb) > 10.0_c_double * epsilon(aa)) stop 1
+
+ ! check c_loc ptr again after target-value modification
+ aa = 1111.0_c_double
+ !$omp target update to(aa)
+ call copy3_scalar(c_aptr, c_bptr)
+ !$omp target update from(bb)
+ if (abs(aa - 1111.0_c_double) > 10.0_c_double * epsilon(aa)) stop 1
+ if (abs(3.0_c_double * aa - bb) > 10.0_c_double * epsilon(aa)) stop 1
+
+ ! check Fortran pointer after target-value modification
+ aa = 11111.0_c_double
+ !$omp target update to(aa)
+ call copy3_scalar(c_loc(aptr), c_loc(bptr))
+ !$omp target update from(bb)
+ if (abs(aa - 11111.0_c_double) > 10.0_c_double * epsilon(aa)) stop 1
+ if (abs(3.0_c_double * aa - bb) > 10.0_c_double * epsilon(aa)) stop 1
+ !$omp end target data
+
+ if (abs(aa - 11111.0_c_double) > 10.0_c_double * epsilon(aa)) stop 1
+ if (abs(3.0_c_double * aa - bb) > 10.0_c_double * epsilon(aa)) stop 1
+ end subroutine test_dummy_val_callee_2
+end module test_dummies_value
+
+
+
+! Test local dummy arguments + OPTIONAL
+! Values present and ptr associated to nonzero
+module test_dummies_opt
+ use iso_c_binding
+ use target_procs
+ implicit none (type, external)
+ private
+ public :: test_dummy_opt_call_1, test_dummy_opt_call_2
+contains
+ subroutine test_dummy_opt_call_1()
+ integer, parameter :: N = 1000
+
+ ! scalars
+ real(c_double), target :: aa, bb
+ real(c_double), target, allocatable :: cc, dd
+ real(c_double), pointer :: ee, ff
+
+ ! non-descriptor arrays
+ real(c_double), target :: gg(N), hh(N)
+
+ allocate(cc, dd, ee, ff)
+
+ aa = 11.0_c_double
+ bb = 22.0_c_double
+ cc = 33.0_c_double
+ dd = 44.0_c_double
+ ee = 55.0_c_double
+ ff = 66.0_c_double
+ gg = 77.0_c_double
+ hh = 88.0_c_double
+
+ call test_dummy_opt_callee_1(aa, bb, cc, dd, ee, ff, gg, hh, N)
+ deallocate(ee, ff) ! pointers, only
+ end subroutine test_dummy_opt_call_1
+
+ subroutine test_dummy_opt_callee_1(aa, bb, cc, dd, ee, ff, gg, hh, N)
+ ! scalars
+ real(c_double), optional, target :: aa, bb
+ real(c_double), optional, target, allocatable :: cc, dd
+ real(c_double), optional, pointer :: ee, ff
+
+ ! non-descriptor arrays
+ real(c_double), optional, target :: gg(N), hh(N)
+ integer, value :: N
+
+ ! All shall be present - and pointing to non-NULL
+ if (.not.present(aa) .or. .not.present(bb)) stop 1
+ if (.not.present(cc) .or. .not.present(dd)) stop 1
+ if (.not.present(ee) .or. .not.present(ff)) stop 1
+ if (.not.present(gg) .or. .not.present(hh)) stop 1
+
+ if (.not.associated(ee) .or. .not.associated(ff)) stop 1
+
+ !$omp target data map(to:aa) map(from:bb) use_device_addr(aa,bb)
+ if (.not.present(aa) .or. .not.present(bb)) stop 1
+ if (.not.c_associated(c_loc(aa)) .or. .not.c_associated(c_loc(bb))) stop 1
+ call copy3_scalar(c_loc(aa), c_loc(bb))
+ !$omp end target data
+ if (abs(aa - 11.0_c_double) > 10.0_c_double * epsilon(aa)) stop 1
+ if (abs(3.0_c_double * aa - bb) > 10.0_c_double * epsilon(aa)) stop 1
+
+ !$omp target data map(to:cc) map(from:dd) use_device_addr(cc,dd)
+ if (.not.present(cc) .or. .not.present(dd)) stop 1
+ if (.not.c_associated(c_loc(cc)) .or. .not.c_associated(c_loc(dd))) stop 1
+ call copy3_scalar(c_loc(cc), c_loc(dd))
+ !$omp end target data
+ if (abs(cc - 33.0_c_double) > 10.0_c_double * epsilon(cc)) stop 1
+ if (abs(3.0_c_double * cc - dd) > 10.0_c_double * epsilon(cc)) stop 1
+
+ !$omp target data map(to:ee) map(from:ff) use_device_addr(ee,ff)
+ if (.not.present(ee) .or. .not.present(ff)) stop 1
+ if (.not.associated(ee) .or. .not.associated(ff)) stop 1
+ if (.not.c_associated(c_loc(ee)) .or. .not.c_associated(c_loc(ff))) stop 1
+ call copy3_scalar(c_loc(ee), c_loc(ff))
+ !$omp end target data
+ if (abs(ee - 55.0_c_double) > 10.0_c_double * epsilon(ee)) stop 1
+ if (abs(3.0_c_double * ee - ff) > 10.0_c_double * epsilon(ee)) stop 1
+
+ !$omp target data map(to:gg) map(from:hh) use_device_addr(gg,hh)
+ if (.not.present(gg) .or. .not.present(hh)) stop 1
+ if (.not.c_associated(c_loc(gg)) .or. .not.c_associated(c_loc(hh))) stop 1
+ call copy3_array(c_loc(gg), c_loc(hh), N)
+ !$omp end target data
+ if (any(abs(gg - 77.0_c_double) > 10.0_c_double * epsilon(gg))) stop 1
+ if (any(abs(3.0_c_double * gg - hh) > 10.0_c_double * epsilon(gg))) stop 1
+ end subroutine test_dummy_opt_callee_1
+
+ ! Save device ptr - and recall pointer
+ subroutine test_dummy_opt_call_2()
+ integer, parameter :: N = 1000
+
+ ! scalars
+ real(c_double), target :: aa, bb
+ real(c_double), target, allocatable :: cc, dd
+ real(c_double), pointer :: ee, ff
+
+ ! non-descriptor arrays
+ real(c_double), target :: gg(N), hh(N)
+
+ type(c_ptr) :: c_aptr, c_bptr, c_cptr, c_dptr, c_eptr, c_fptr, c_gptr, c_hptr
+ real(c_double), pointer :: aptr, bptr, cptr, dptr, eptr, fptr
+ real(c_double), pointer :: gptr(:), hptr(:)
+
+ allocate(cc, dd, ee, ff)
+ call test_dummy_opt_callee_2(aa, bb, cc, dd, ee, ff, gg, hh, &
+ c_aptr, c_bptr, c_cptr, c_dptr, c_eptr, c_fptr, c_gptr, c_hptr, &
+ aptr, bptr, cptr, dptr, eptr, fptr, gptr, hptr, &
+ N)
+ deallocate(ee, ff)
+ end subroutine test_dummy_opt_call_2
+
+ subroutine test_dummy_opt_callee_2(aa, bb, cc, dd, ee, ff, gg, hh, &
+ c_aptr, c_bptr, c_cptr, c_dptr, c_eptr, c_fptr, c_gptr, c_hptr, &
+ aptr, bptr, cptr, dptr, eptr, fptr, gptr, hptr, &
+ N)
+ ! scalars
+ real(c_double), optional, target :: aa, bb
+ real(c_double), optional, target, allocatable :: cc, dd
+ real(c_double), optional, pointer :: ee, ff
+
+ ! non-descriptor arrays
+ real(c_double), optional, target :: gg(N), hh(N)
+
+ type(c_ptr) :: c_aptr, c_bptr, c_cptr, c_dptr, c_eptr, c_fptr, c_gptr, c_hptr
+ real(c_double), optional, pointer :: aptr, bptr, cptr, dptr, eptr, fptr
+ real(c_double), optional, pointer :: gptr(:), hptr(:)
+
+ integer, value :: N
+
+ real(c_double) :: dummy
+
+ ! All shall be present - and pointing to non-NULL
+ if (.not.present(aa) .or. .not.present(bb)) stop 1
+ if (.not.present(cc) .or. .not.present(dd)) stop 1
+ if (.not.present(ee) .or. .not.present(ff)) stop 1
+ if (.not.present(gg) .or. .not.present(hh)) stop 1
+
+ if (.not.associated(ee) .or. .not.associated(ff)) stop 1
+
+ aa = 111.0_c_double
+ bb = 222.0_c_double
+ cc = 333.0_c_double
+ dd = 444.0_c_double
+ ee = 555.0_c_double
+ ff = 666.0_c_double
+ gg = 777.0_c_double
+ hh = 888.0_c_double
+
+ !$omp target data map(to:aa) map(from:bb)
+ !$omp target data map(alloc:dummy) use_device_addr(aa,bb)
+ if (.not.present(aa) .or. .not.present(bb)) stop 1
+ if (.not.c_associated(c_loc(aa)) .or. .not.c_associated(c_loc(bb))) stop 1
+ c_aptr = c_loc(aa)
+ c_bptr = c_loc(bb)
+ aptr => aa
+ bptr => bb
+ if (.not.c_associated(c_aptr) .or. .not.c_associated(c_bptr)) stop 1
+ if (.not.associated(aptr) .or. .not.associated(bptr)) stop 1
+ !$omp end target data
+
+ if (.not.present(aa) .or. .not.present(bb)) stop 1
+ if (.not.c_associated(c_loc(aa)) .or. .not.c_associated(c_loc(bb))) stop 1
+ if (.not.c_associated(c_aptr) .or. .not.c_associated(c_bptr)) stop 1
+ if (.not.associated(aptr) .or. .not.associated(bptr)) stop 1
+
+ ! check c_loc ptr once
+ call copy3_scalar(c_aptr, c_bptr)
+ !$omp target update from(bb)
+ if (abs(aa - 111.0_c_double) > 10.0_c_double * epsilon(aa)) stop 1
+ if (abs(3.0_c_double * aa - bb) > 10.0_c_double * epsilon(aa)) stop 1
+
+ ! check c_loc ptr again after target-value modification
+ aa = 1111.0_c_double
+ !$omp target update to(aa)
+ call copy3_scalar(c_aptr, c_bptr)
+ !$omp target update from(bb)
+ if (abs(aa - 1111.0_c_double) > 10.0_c_double * epsilon(aa)) stop 1
+ if (abs(3.0_c_double * aa - bb) > 10.0_c_double * epsilon(aa)) stop 1
+
+ ! check Fortran pointer after target-value modification
+ aa = 11111.0_c_double
+ !$omp target update to(aa)
+ call copy3_scalar(c_loc(aptr), c_loc(bptr))
+ !$omp target update from(bb)
+ if (abs(aa - 11111.0_c_double) > 10.0_c_double * epsilon(aa)) stop 1
+ if (abs(3.0_c_double * aa - bb) > 10.0_c_double * epsilon(aa)) stop 1
+ !$omp end target data
+
+ if (abs(aa - 11111.0_c_double) > 10.0_c_double * epsilon(aa)) stop 1
+ if (abs(3.0_c_double * aa - bb) > 10.0_c_double * epsilon(aa)) stop 1
+
+
+ !$omp target data map(to:cc) map(from:dd)
+ !$omp target data map(alloc:dummy) use_device_addr(cc,dd)
+ if (.not.present(cc) .or. .not.present(dd)) stop 1
+ if (.not.c_associated(c_loc(cc)) .or. .not.c_associated(c_loc(dd))) stop 1
+ c_cptr = c_loc(cc)
+ c_dptr = c_loc(dd)
+ cptr => cc
+ dptr => dd
+ if (.not.c_associated(c_cptr) .or. .not.c_associated(c_dptr)) stop 1
+ if (.not.associated(cptr) .or. .not.associated(dptr)) stop 1
+ !$omp end target data
+ if (.not.present(cc) .or. .not.present(dd)) stop 1
+ if (.not.c_associated(c_loc(cc)) .or. .not.c_associated(c_loc(dd))) stop 1
+ if (.not.c_associated(c_cptr) .or. .not.c_associated(c_dptr)) stop 1
+ if (.not.associated(cptr) .or. .not.associated(dptr)) stop 1
+
+ ! check c_loc ptr once
+ call copy3_scalar(c_cptr, c_dptr)
+ !$omp target update from(dd)
+ if (abs(cc - 333.0_c_double) > 10.0_c_double * epsilon(cc)) stop 1
+ if (abs(3.0_c_double * cc - dd) > 10.0_c_double * epsilon(cc)) stop 1
+
+ ! check c_loc ptr again after target-value modification
+ cc = 3333.0_c_double
+ !$omp target update to(cc)
+ call copy3_scalar(c_cptr, c_dptr)
+ !$omp target update from(dd)
+ if (abs(cc - 3333.0_c_double) > 10.0_c_double * epsilon(cc)) stop 1
+ if (abs(3.0_c_double * cc - dd) > 10.0_c_double * epsilon(cc)) stop 1
+
+ ! check Fortran pointer after target-value modification
+ cc = 33333.0_c_double
+ !$omp target update to(cc)
+ call copy3_scalar(c_loc(cptr), c_loc(dptr))
+ !$omp target update from(dd)
+ if (abs(cc - 33333.0_c_double) > 10.0_c_double * epsilon(cc)) stop 1
+ if (abs(3.0_c_double * cc - dd) > 10.0_c_double * epsilon(cc)) stop 1
+ !$omp end target data
+
+ if (abs(cc - 33333.0_c_double) > 10.0_c_double * epsilon(dd)) stop 1
+ if (abs(3.0_c_double * cc - dd) > 10.0_c_double * epsilon(dd)) stop 1
+
+
+ !$omp target data map(to:ee) map(from:ff)
+ !$omp target data map(alloc:dummy) use_device_addr(ee,ff)
+ if (.not.present(ee) .or. .not.present(ff)) stop 1
+ if (.not.associated(ee) .or. .not.associated(ff)) stop 1
+ if (.not.c_associated(c_loc(ee)) .or. .not.c_associated(c_loc(ff))) stop 1
+ c_eptr = c_loc(ee)
+ c_fptr = c_loc(ff)
+ eptr => ee
+ fptr => ff
+ if (.not.c_associated(c_eptr) .or. .not.c_associated(c_fptr)) stop 1
+ if (.not.associated(eptr) .or. .not.associated(fptr)) stop 1
+ !$omp end target data
+ if (.not.present(ee) .or. .not.present(ff)) stop 1
+ if (.not.associated(ee) .or. .not.associated(ff)) stop 1
+ if (.not.c_associated(c_loc(ee)) .or. .not.c_associated(c_loc(ff))) stop 1
+ if (.not.c_associated(c_eptr) .or. .not.c_associated(c_fptr)) stop 1
+ if (.not.associated(eptr) .or. .not.associated(fptr)) stop 1
+
+ ! check c_loc ptr once
+ call copy3_scalar(c_eptr, c_fptr)
+ !$omp target update from(ff)
+ if (abs(ee - 555.0_c_double) > 10.0_c_double * epsilon(ee)) stop 1
+ if (abs(3.0_c_double * ee - ff) > 10.0_c_double * epsilon(ee)) stop 1
+
+ ! check c_loc ptr again after target-value modification
+ ee = 5555.0_c_double
+ !$omp target update to(ee)
+ call copy3_scalar(c_eptr, c_fptr)
+ !$omp target update from(ff)
+ if (abs(ee - 5555.0_c_double) > 10.0_c_double * epsilon(ee)) stop 1
+ if (abs(3.0_c_double * ee - ff) > 10.0_c_double * epsilon(ee)) stop 1
+
+ ! check Fortran pointer after target-value modification
+ ee = 55555.0_c_double
+ !$omp target update to(ee)
+ call copy3_scalar(c_loc(eptr), c_loc(fptr))
+ !$omp target update from(ff)
+ if (abs(ee - 55555.0_c_double) > 10.0_c_double * epsilon(ee)) stop 1
+ if (abs(3.0_c_double * ee - ff) > 10.0_c_double * epsilon(ff)) stop 1
+ !$omp end target data
+
+ if (abs(ee - 55555.0_c_double) > 10.0_c_double * epsilon(ee)) stop 1
+ if (abs(3.0_c_double * ee - ff) > 10.0_c_double * epsilon(ee)) stop 1
+
+
+ !$omp target data map(to:gg) map(from:hh)
+ !$omp target data map(alloc:dummy) use_device_addr(gg,hh)
+ if (.not.present(gg) .or. .not.present(hh)) stop 1
+ if (.not.c_associated(c_loc(gg)) .or. .not.c_associated(c_loc(hh))) stop 1
+ c_gptr = c_loc(gg)
+ c_hptr = c_loc(hh)
+ gptr => gg
+ hptr => hh
+ if (.not.c_associated(c_gptr) .or. .not.c_associated(c_hptr)) stop 1
+ if (.not.associated(gptr) .or. .not.associated(hptr)) stop 1
+ !$omp end target data
+ if (.not.present(gg) .or. .not.present(hh)) stop 1
+ if (.not.c_associated(c_loc(gg)) .or. .not.c_associated(c_loc(hh))) stop 1
+ if (.not.c_associated(c_gptr) .or. .not.c_associated(c_hptr)) stop 1
+ if (.not.associated(gptr) .or. .not.associated(hptr)) stop 1
+
+ ! check c_loc ptr once
+ call copy3_array(c_gptr, c_hptr, N)
+ !$omp target update from(hh)
+ if (any(abs(gg - 777.0_c_double) > 10.0_c_double * epsilon(gg))) stop 1
+ if (any(abs(3.0_c_double * gg - hh) > 10.0_c_double * epsilon(hh))) stop 1
+
+ ! check c_loc ptr again after target-value modification
+ gg = 7777.0_c_double
+ !$omp target update to(gg)
+ call copy3_array(c_gptr, c_hptr, N)
+ !$omp target update from(hh)
+ if (any(abs(gg - 7777.0_c_double) > 10.0_c_double * epsilon(gg))) stop 1
+ if (any(abs(3.0_c_double * gg - hh) > 10.0_c_double * epsilon(gg))) stop 1
+
+ ! check Fortran pointer after target-value modification
+ gg = 77777.0_c_double
+ !$omp target update to(gg)
+ call copy3_array(c_loc(gptr), c_loc(hptr), N)
+ !$omp target update from(hh)
+ if (any(abs(gg - 77777.0_c_double) > 10.0_c_double * epsilon(gg))) stop 1
+ if (any(abs(3.0_c_double * gg - hh) > 10.0_c_double * epsilon(gg))) stop 1
+ !$omp end target data
+
+ if (any(abs(gg - 77777.0_c_double) > 10.0_c_double * epsilon(gg))) stop 1
+ if (any(abs(3.0_c_double * gg - hh) > 10.0_c_double * epsilon(gg))) stop 1
+ end subroutine test_dummy_opt_callee_2
+end module test_dummies_opt
+
+
+
+! Test local dummy arguments + OPTIONAL + VALUE
+! Values present
+module test_dummies_opt_value
+ use iso_c_binding
+ use target_procs
+ implicit none (type, external)
+ private
+ public :: test_dummy_opt_val_call_1, test_dummy_opt_val_call_2
+contains
+ subroutine test_dummy_opt_val_call_1()
+ ! scalars - with value, neither allocatable nor pointer no dimension permitted
+ real(c_double), target :: aa, bb
+
+ aa = 11.0_c_double
+ bb = 22.0_c_double
+
+ call test_dummy_opt_val_callee_1(aa, bb)
+ end subroutine test_dummy_opt_val_call_1
+
+ subroutine test_dummy_opt_val_callee_1(aa, bb)
+ ! scalars
+ real(c_double), optional, value, target :: aa, bb
+
+ if (.not.present(aa) .or. .not.present(bb)) stop 1
+
+ !$omp target data map(to:aa) map(from:bb) use_device_addr(aa,bb)
+ if (.not.present(aa) .or. .not.present(bb)) stop 1
+ if (.not.c_associated(c_loc(aa)) .or. .not.c_associated(c_loc(bb))) stop 1
+ call copy3_scalar(c_loc(aa), c_loc(bb))
+ !$omp end target data
+ if (abs(aa - 11.0_c_double) > 10.0_c_double * epsilon(aa)) stop 1
+ if (abs(3.0_c_double * aa - bb) > 10.0_c_double * epsilon(aa)) stop 1
+ end subroutine test_dummy_opt_val_callee_1
+
+ ! Save device ptr - and recall pointer
+ subroutine test_dummy_opt_val_call_2()
+ ! scalars - with value, neither allocatable nor pointer no dimension permitted
+ real(c_double), target :: aa, bb
+ type(c_ptr) :: c_aptr, c_bptr
+ real(c_double), pointer :: aptr, bptr
+
+ call test_dummy_opt_val_callee_2(aa, bb, c_aptr, c_bptr, aptr, bptr)
+ end subroutine test_dummy_opt_val_call_2
+
+ subroutine test_dummy_opt_val_callee_2(aa, bb, c_aptr, c_bptr, aptr, bptr)
+ real(c_double), optional, value, target :: aa, bb
+ type(c_ptr), optional, value :: c_aptr, c_bptr
+ real(c_double), optional, pointer :: aptr, bptr
+
+ real(c_double) :: dummy
+
+ if (.not.present(aa) .or. .not.present(bb)) stop 1
+ if (.not.present(c_aptr) .or. .not.present(c_bptr)) stop 1
+ if (.not.present(aptr) .or. .not.present(bptr)) stop 1
+
+ aa = 111.0_c_double
+ bb = 222.0_c_double
+
+ !$omp target data map(to:aa) map(from:bb)
+ if (.not.present(aa) .or. .not.present(bb)) stop 1
+ if (.not.present(c_aptr) .or. .not.present(c_bptr)) stop 1
+ if (.not.present(aptr) .or. .not.present(bptr)) stop 1
+
+ !$omp target data map(alloc:dummy) use_device_addr(aa,bb)
+ if (.not.present(aa) .or. .not.present(bb)) stop 1
+ if (.not.present(c_aptr) .or. .not.present(c_bptr)) stop 1
+ if (.not.present(aptr) .or. .not.present(bptr)) stop 1
+
+ c_aptr = c_loc(aa)
+ c_bptr = c_loc(bb)
+ aptr => aa
+ bptr => bb
+ if (.not.c_associated(c_aptr) .or. .not.c_associated(c_bptr)) stop 1
+ if (.not.associated(aptr) .or. .not.associated(bptr)) stop 1
+ !$omp end target data
+
+ ! check c_loc ptr once
+ call copy3_scalar(c_aptr, c_bptr)
+ !$omp target update from(bb)
+ if (abs(aa - 111.0_c_double) > 10.0_c_double * epsilon(aa)) stop 1
+ if (abs(3.0_c_double * aa - bb) > 10.0_c_double * epsilon(aa)) stop 1
+
+ ! check c_loc ptr again after target-value modification
+ aa = 1111.0_c_double
+ !$omp target update to(aa)
+ call copy3_scalar(c_aptr, c_bptr)
+ !$omp target update from(bb)
+ if (abs(aa - 1111.0_c_double) > 10.0_c_double * epsilon(aa)) stop 1
+ if (abs(3.0_c_double * aa - bb) > 10.0_c_double * epsilon(aa)) stop 1
+
+ ! check Fortran pointer after target-value modification
+ aa = 11111.0_c_double
+ !$omp target update to(aa)
+ call copy3_scalar(c_loc(aptr), c_loc(bptr))
+ !$omp target update from(bb)
+ if (abs(aa - 11111.0_c_double) > 10.0_c_double * epsilon(aa)) stop 1
+ if (abs(3.0_c_double * aa - bb) > 10.0_c_double * epsilon(aa)) stop 1
+ !$omp end target data
+
+ if (abs(aa - 11111.0_c_double) > 10.0_c_double * epsilon(aa)) stop 1
+ if (abs(3.0_c_double * aa - bb) > 10.0_c_double * epsilon(aa)) stop 1
+ end subroutine test_dummy_opt_val_callee_2
+end module test_dummies_opt_value
+
+
+
+! Test nullptr
+module test_nullptr
+ use iso_c_binding
+ implicit none (type, external)
+ private
+ public :: test_nullptr_1
+contains
+ subroutine test_nullptr_1()
+ ! scalars
+ real(c_double), pointer :: aa, bb
+ real(c_double), pointer :: ee, ff
+
+ type(c_ptr) :: c_aptr, c_bptr, c_eptr, c_fptr
+ real(c_double), pointer :: aptr, bptr, eptr, fptr
+
+ aa => null()
+ bb => null()
+ ee => null()
+ ff => null()
+
+ if (associated(aa) .or. associated(bb)) stop 1
+ !$omp target data map(to:aa) map(from:bb) use_device_addr(aa,bb)
+ if (c_associated(c_loc(aa)) .or. c_associated(c_loc(bb))) stop 1
+ c_aptr = c_loc(aa)
+ c_bptr = c_loc(bb)
+ aptr => aa
+ bptr => bb
+ if (c_associated(c_aptr) .or. c_associated(c_bptr)) stop 1
+ if (associated(aptr) .or. associated(bptr, bb)) stop 1
+ !$omp end target data
+ if (c_associated(c_aptr) .or. c_associated(c_bptr)) stop 1
+ if (associated(aptr) .or. associated(bptr, bb)) stop 1
+
+ call test_dummy_opt_nullptr_callee_1(ee, ff, c_eptr, c_fptr, eptr, fptr)
+ end subroutine test_nullptr_1
+
+ subroutine test_dummy_opt_nullptr_callee_1(ee, ff, c_eptr, c_fptr, eptr, fptr)
+ ! scalars
+ real(c_double), optional, pointer :: ee, ff
+
+ type(c_ptr), optional :: c_eptr, c_fptr
+ real(c_double), optional, pointer :: eptr, fptr
+
+ if (.not.present(ee) .or. .not.present(ff)) stop 1
+ if (associated(ee) .or. associated(ff)) stop 1
+
+ !$omp target data map(to:ee) map(from:ff) use_device_addr(ee,ff)
+ if (.not.present(ee) .or. .not.present(ff)) stop 1
+ if (associated(ee) .or. associated(ff)) stop 1
+ if (c_associated(c_loc(ee)) .or. c_associated(c_loc(ff))) stop 1
+ c_eptr = c_loc(ee)
+ c_fptr = c_loc(ff)
+ eptr => ee
+ fptr => ff
+ if (c_associated(c_eptr) .or. c_associated(c_fptr)) stop 1
+ if (associated(eptr) .or. associated(fptr)) stop 1
+ !$omp end target data
+
+ if (c_associated(c_eptr) .or. c_associated(c_fptr)) stop 1
+ if (associated(eptr) .or. associated(fptr)) stop 1
+ end subroutine test_dummy_opt_nullptr_callee_1
+end module test_nullptr
+
+
+
+! Test local variables
+module tests
+ use iso_c_binding
+ use target_procs
+ implicit none (type, external)
+ private
+ public :: test_main_1, test_main_2
+contains
+ ! map + use_device_addr + c_loc
+ subroutine test_main_1()
+ integer, parameter :: N = 1000
+
+ ! scalars
+ real(c_double), target :: aa, bb
+ real(c_double), target, allocatable :: cc, dd
+ real(c_double), pointer :: ee, ff
+
+ ! non-descriptor arrays
+ real(c_double), target :: gg(N), hh(N)
+
+ allocate(cc, dd, ee, ff)
+
+
+ aa = 11.0_c_double
+ bb = 22.0_c_double
+ cc = 33.0_c_double
+ dd = 44.0_c_double
+ ee = 55.0_c_double
+ ff = 66.0_c_double
+ gg = 77.0_c_double
+ hh = 88.0_c_double
+
+ !$omp target data map(to:aa) map(from:bb) use_device_addr(aa,bb)
+ call copy3_scalar(c_loc(aa), c_loc(bb))
+ !$omp end target data
+ if (abs(aa - 11.0_c_double) > 10.0_c_double * epsilon(aa)) stop 1
+ if (abs(3.0_c_double * aa - bb) > 10.0_c_double * epsilon(aa)) stop 1
+
+ !$omp target data map(to:cc) map(from:dd) use_device_addr(cc,dd)
+ call copy3_scalar(c_loc(cc), c_loc(dd))
+ !$omp end target data
+ if (abs(cc - 33.0_c_double) > 10.0_c_double * epsilon(cc)) stop 1
+ if (abs(3.0_c_double * cc - dd) > 10.0_c_double * epsilon(cc)) stop 1
+
+ !$omp target data map(to:ee) map(from:ff) use_device_addr(ee,ff)
+ call copy3_scalar(c_loc(ee), c_loc(ff))
+ !$omp end target data
+ if (abs(ee - 55.0_c_double) > 10.0_c_double * epsilon(ee)) stop 1
+ if (abs(3.0_c_double * ee - ff) > 10.0_c_double * epsilon(ee)) stop 1
+
+
+ !$omp target data map(to:gg) map(from:hh) use_device_addr(gg,hh)
+ call copy3_array(c_loc(gg), c_loc(hh), N)
+ !$omp end target data
+ if (any(abs(gg - 77.0_c_double) > 10.0_c_double * epsilon(gg))) stop 1
+ if (any(abs(3.0_c_double * gg - hh) > 10.0_c_double * epsilon(gg))) stop 1
+
+ deallocate(ee, ff) ! pointers, only
+ end subroutine test_main_1
+
+ ! Save device ptr - and recall pointer
+ subroutine test_main_2
+ integer, parameter :: N = 1000
+
+ ! scalars
+ real(c_double), target :: aa, bb
+ real(c_double), target, allocatable :: cc, dd
+ real(c_double), pointer :: ee, ff
+
+ ! non-descriptor arrays
+ real(c_double), target :: gg(N), hh(N)
+
+ real(c_double) :: dummy
+ type(c_ptr) :: c_aptr, c_bptr, c_cptr, c_dptr, c_eptr, c_fptr, c_gptr, c_hptr
+ real(c_double), pointer :: aptr, bptr, cptr, dptr, eptr, fptr
+ real(c_double), pointer :: gptr(:), hptr(:)
+
+ allocate(cc, dd, ee, ff)
+
+ aa = 111.0_c_double
+ bb = 222.0_c_double
+ cc = 333.0_c_double
+ dd = 444.0_c_double
+ ee = 555.0_c_double
+ ff = 666.0_c_double
+ gg = 777.0_c_double
+ hh = 888.0_c_double
+
+ !$omp target data map(to:aa) map(from:bb)
+ !$omp target data map(alloc:dummy) use_device_addr(aa,bb)
+ c_aptr = c_loc(aa)
+ c_bptr = c_loc(bb)
+ aptr => aa
+ bptr => bb
+ !$omp end target data
+
+ ! check c_loc ptr once
+ call copy3_scalar(c_aptr, c_bptr)
+ !$omp target update from(bb)
+ if (abs(aa - 111.0_c_double) > 10.0_c_double * epsilon(aa)) stop 1
+ if (abs(3.0_c_double * aa - bb) > 10.0_c_double * epsilon(aa)) stop 1
+
+ ! check c_loc ptr again after target-value modification
+ aa = 1111.0_c_double
+ !$omp target update to(aa)
+ call copy3_scalar(c_aptr, c_bptr)
+ !$omp target update from(bb)
+ if (abs(aa - 1111.0_c_double) > 10.0_c_double * epsilon(aa)) stop 1
+ if (abs(3.0_c_double * aa - bb) > 10.0_c_double * epsilon(aa)) stop 1
+
+ ! check Fortran pointer after target-value modification
+ aa = 11111.0_c_double
+ !$omp target update to(aa)
+ call copy3_scalar(c_loc(aptr), c_loc(bptr))
+ !$omp target update from(bb)
+ if (abs(aa - 11111.0_c_double) > 10.0_c_double * epsilon(aa)) stop 1
+ if (abs(3.0_c_double * aa - bb) > 10.0_c_double * epsilon(aa)) stop 1
+ !$omp end target data
+
+ if (abs(aa - 11111.0_c_double) > 10.0_c_double * epsilon(aa)) stop 1
+ if (abs(3.0_c_double * aa - bb) > 10.0_c_double * epsilon(aa)) stop 1
+
+
+ !$omp target data map(to:cc) map(from:dd)
+ !$omp target data map(alloc:dummy) use_device_addr(cc,dd)
+ c_cptr = c_loc(cc)
+ c_dptr = c_loc(dd)
+ cptr => cc
+ dptr => dd
+ !$omp end target data
+
+ ! check c_loc ptr once
+ call copy3_scalar(c_cptr, c_dptr)
+ !$omp target update from(dd)
+ if (abs(cc - 333.0_c_double) > 10.0_c_double * epsilon(cc)) stop 1
+ if (abs(3.0_c_double * cc - dd) > 10.0_c_double * epsilon(cc)) stop 1
+
+ ! check c_loc ptr again after target-value modification
+ cc = 3333.0_c_double
+ !$omp target update to(cc)
+ call copy3_scalar(c_cptr, c_dptr)
+ !$omp target update from(dd)
+ if (abs(cc - 3333.0_c_double) > 10.0_c_double * epsilon(cc)) stop 1
+ if (abs(3.0_c_double * cc - dd) > 10.0_c_double * epsilon(cc)) stop 1
+
+ ! check Fortran pointer after target-value modification
+ cc = 33333.0_c_double
+ !$omp target update to(cc)
+ call copy3_scalar(c_loc(cptr), c_loc(dptr))
+ !$omp target update from(dd)
+ if (abs(cc - 33333.0_c_double) > 10.0_c_double * epsilon(cc)) stop 1
+ if (abs(3.0_c_double * cc - dd) > 10.0_c_double * epsilon(cc)) stop 1
+ !$omp end target data
+
+ if (abs(cc - 33333.0_c_double) > 10.0_c_double * epsilon(dd)) stop 1
+ if (abs(3.0_c_double * cc - dd) > 10.0_c_double * epsilon(dd)) stop 1
+
+
+ !$omp target data map(to:ee) map(from:ff)
+ !$omp target data map(alloc:dummy) use_device_addr(ee,ff)
+ c_eptr = c_loc(ee)
+ c_fptr = c_loc(ff)
+ eptr => ee
+ fptr => ff
+ !$omp end target data
+
+ ! check c_loc ptr once
+ call copy3_scalar(c_eptr, c_fptr)
+ !$omp target update from(ff)
+ if (abs(ee - 555.0_c_double) > 10.0_c_double * epsilon(ee)) stop 1
+ if (abs(3.0_c_double * ee - ff) > 10.0_c_double * epsilon(ee)) stop 1
+
+ ! check c_loc ptr again after target-value modification
+ ee = 5555.0_c_double
+ !$omp target update to(ee)
+ call copy3_scalar(c_eptr, c_fptr)
+ !$omp target update from(ff)
+ if (abs(ee - 5555.0_c_double) > 10.0_c_double * epsilon(ee)) stop 1
+ if (abs(3.0_c_double * ee - ff) > 10.0_c_double * epsilon(ee)) stop 1
+
+ ! check Fortran pointer after target-value modification
+ ee = 55555.0_c_double
+ !$omp target update to(ee)
+ call copy3_scalar(c_loc(eptr), c_loc(fptr))
+ !$omp target update from(ff)
+ if (abs(ee - 55555.0_c_double) > 10.0_c_double * epsilon(ee)) stop 1
+ if (abs(3.0_c_double * ee - ff) > 10.0_c_double * epsilon(ff)) stop 1
+ !$omp end target data
+
+ if (abs(ee - 55555.0_c_double) > 10.0_c_double * epsilon(ee)) stop 1
+ if (abs(3.0_c_double * ee - ff) > 10.0_c_double * epsilon(ee)) stop 1
+
+
+ !$omp target data map(to:gg) map(from:hh)
+ !$omp target data map(alloc:dummy) use_device_addr(gg,hh)
+ c_gptr = c_loc(gg)
+ c_hptr = c_loc(hh)
+ gptr => gg
+ hptr => hh
+ !$omp end target data
+
+ ! check c_loc ptr once
+ call copy3_array(c_gptr, c_hptr, N)
+ !$omp target update from(hh)
+ if (any(abs(gg - 777.0_c_double) > 10.0_c_double * epsilon(gg))) stop 1
+ if (any(abs(3.0_c_double * gg - hh) > 10.0_c_double * epsilon(hh))) stop 1
+
+ ! check c_loc ptr again after target-value modification
+ gg = 7777.0_c_double
+ !$omp target update to(gg)
+ call copy3_array(c_gptr, c_hptr, N)
+ !$omp target update from(hh)
+ if (any(abs(gg - 7777.0_c_double) > 10.0_c_double * epsilon(gg))) stop 1
+ if (any(abs(3.0_c_double * gg - hh) > 10.0_c_double * epsilon(gg))) stop 1
+
+ ! check Fortran pointer after target-value modification
+ gg = 77777.0_c_double
+ !$omp target update to(gg)
+ call copy3_array(c_loc(gptr), c_loc(hptr), N)
+ !$omp target update from(hh)
+ if (any(abs(gg - 77777.0_c_double) > 10.0_c_double * epsilon(gg))) stop 1
+ if (any(abs(3.0_c_double * gg - hh) > 10.0_c_double * epsilon(gg))) stop 1
+ !$omp end target data
+
+ if (any(abs(gg - 77777.0_c_double) > 10.0_c_double * epsilon(gg))) stop 1
+ if (any(abs(3.0_c_double * gg - hh) > 10.0_c_double * epsilon(gg))) stop 1
+
+ deallocate(ee, ff)
+ end subroutine test_main_2
+end module tests
+
+
+program omp_device_addr
+ use tests
+ use test_dummies
+ use test_dummies_value
+ use test_dummies_opt
+ use test_dummies_opt_value
+ use test_nullptr
+ implicit none (type, external)
+
+ call test_main_1()
+ call test_main_2()
+
+ call test_dummy_call_1()
+ call test_dummy_call_2()
+
+ call test_dummy_val_call_1()
+ call test_dummy_val_call_2()
+
+ call test_dummy_opt_call_1()
+ call test_dummy_opt_call_2()
+
+ call test_dummy_opt_val_call_1()
+ call test_dummy_opt_val_call_2()
+
+ call test_nullptr_1()
+end program omp_device_addr
diff --git a/libgomp/testsuite/libgomp.fortran/use_device_addr-2.f90 b/libgomp/testsuite/libgomp.fortran/use_device_addr-2.f90
new file mode 100644
index 00000000000..bddb4491414
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/use_device_addr-2.f90
@@ -0,0 +1,1196 @@
+! Comprehensive run-time test for use_device_addr
+!
+! Differs from use_device_addr-1.f90 by using a 4-byte variable (c_float)
+!
+! This test case assumes that a 'var' appearing in 'use_device_addr' is
+! only used as 'c_loc(var)' - such that only the actual data is used/usable
+! on the device - and not meta data ((dynamic) type information, 'present()'
+! status, array shape).
+!
+! Untested in this test case are:
+! - arrays with array descriptor
+! - polymorphic variables
+! - absent optional arguments
+!
+module target_procs
+ use iso_c_binding
+ implicit none (type, external)
+ private
+ public :: copy3_array, copy3_scalar
+contains
+ subroutine copy3_array_int(from_ptr, to_ptr, N)
+ !$omp declare target
+ real(c_float) :: from_ptr(:)
+ real(c_float) :: to_ptr(:)
+ integer, value :: N
+ integer :: i
+
+ !$omp parallel do
+ do i = 1, N
+ to_ptr(i) = 3 * from_ptr(i)
+ end do
+ !$omp end parallel do
+ end subroutine copy3_array_int
+
+ subroutine copy3_scalar_int(from, to)
+ !$omp declare target
+ real(c_float) :: from, to
+
+ to = 3 * from
+ end subroutine copy3_scalar_int
+
+
+ subroutine copy3_array(from, to, N)
+ type(c_ptr), value :: from, to
+ integer, value :: N
+ real(c_float), pointer :: from_ptr(:), to_ptr(:)
+
+ call c_f_pointer(from, from_ptr, shape=[N])
+ call c_f_pointer(to, to_ptr, shape=[N])
+
+ call do_offload_scalar(from_ptr,to_ptr)
+ contains
+ subroutine do_offload_scalar(from_r, to_r)
+ real(c_float), target :: from_r(:), to_r(:)
+ ! The extra function is needed as is_device_ptr
+ ! requires non-value, non-pointer dummy arguments
+
+ !$omp target is_device_ptr(from_r, to_r)
+ call copy3_array_int(from_r, to_r, N)
+ !$omp end target
+ end subroutine do_offload_scalar
+ end subroutine copy3_array
+
+ subroutine copy3_scalar(from, to)
+ type(c_ptr), value, target :: from, to
+ real(c_float), pointer :: from_ptr(:), to_ptr(:)
+
+ ! Standard-conform detour of using an array as at time of writing
+ ! is_device_ptr below does not handle scalars
+ call c_f_pointer(from, from_ptr, shape=[1])
+ call c_f_pointer(to, to_ptr, shape=[1])
+
+ call do_offload_scalar(from_ptr,to_ptr)
+ contains
+ subroutine do_offload_scalar(from_r, to_r)
+ real(c_float), target :: from_r(:), to_r(:)
+ ! The extra function is needed as is_device_ptr
+ ! requires non-value, non-pointer dummy arguments
+
+ !$omp target is_device_ptr(from_r, to_r)
+ call copy3_scalar_int(from_r(1), to_r(1))
+ !$omp end target
+ end subroutine do_offload_scalar
+ end subroutine copy3_scalar
+end module target_procs
+
+
+
+! Test local dummy arguments (w/o optional)
+module test_dummies
+ use iso_c_binding
+ use target_procs
+ implicit none (type, external)
+ private
+ public :: test_dummy_call_1, test_dummy_call_2
+contains
+ subroutine test_dummy_call_1()
+ integer, parameter :: N = 1000
+
+ ! scalars
+ real(c_float), target :: aa, bb
+ real(c_float), target, allocatable :: cc, dd
+ real(c_float), pointer :: ee, ff
+
+ ! non-descriptor arrays
+ real(c_float), target :: gg(N), hh(N)
+
+ allocate(cc, dd, ee, ff)
+
+ aa = 11.0_c_float
+ bb = 22.0_c_float
+ cc = 33.0_c_float
+ dd = 44.0_c_float
+ ee = 55.0_c_float
+ ff = 66.0_c_float
+ gg = 77.0_c_float
+ hh = 88.0_c_float
+
+ call test_dummy_callee_1(aa, bb, cc, dd, ee, ff, gg, hh, N)
+ deallocate(ee, ff) ! pointers, only
+ end subroutine test_dummy_call_1
+
+ subroutine test_dummy_callee_1(aa, bb, cc, dd, ee, ff, gg, hh, N)
+ ! scalars
+ real(c_float), target :: aa, bb
+ real(c_float), target, allocatable :: cc, dd
+ real(c_float), pointer :: ee, ff
+
+ ! non-descriptor arrays
+ real(c_float), target :: gg(N), hh(N)
+ integer, value :: N
+
+ !$omp target data map(to:aa) map(from:bb) use_device_addr(aa,bb)
+ call copy3_scalar(c_loc(aa), c_loc(bb))
+ !$omp end target data
+ if (abs(aa - 11.0_c_float) > 10.0_c_float * epsilon(aa)) stop 1
+ if (abs(3.0_c_float * aa - bb) > 10.0_c_float * epsilon(aa)) stop 1
+
+ !$omp target data map(to:cc) map(from:dd) use_device_addr(cc,dd)
+ call copy3_scalar(c_loc(cc), c_loc(dd))
+ !$omp end target data
+ if (abs(cc - 33.0_c_float) > 10.0_c_float * epsilon(cc)) stop 1
+ if (abs(3.0_c_float * cc - dd) > 10.0_c_float * epsilon(cc)) stop 1
+
+ !$omp target data map(to:ee) map(from:ff) use_device_addr(ee,ff)
+ call copy3_scalar(c_loc(ee), c_loc(ff))
+ !$omp end target data
+ if (abs(ee - 55.0_c_float) > 10.0_c_float * epsilon(ee)) stop 1
+ if (abs(3.0_c_float * ee - ff) > 10.0_c_float * epsilon(ee)) stop 1
+
+
+ !$omp target data map(to:gg) map(from:hh) use_device_addr(gg,hh)
+ call copy3_array(c_loc(gg), c_loc(hh), N)
+ !$omp end target data
+ if (any(abs(gg - 77.0_c_float) > 10.0_c_float * epsilon(gg))) stop 1
+ if (any(abs(3.0_c_float * gg - hh) > 10.0_c_float * epsilon(gg))) stop 1
+ end subroutine test_dummy_callee_1
+
+ ! Save device ptr - and recall pointer
+ subroutine test_dummy_call_2()
+ integer, parameter :: N = 1000
+
+ ! scalars
+ real(c_float), target :: aa, bb
+ real(c_float), target, allocatable :: cc, dd
+ real(c_float), pointer :: ee, ff
+
+ ! non-descriptor arrays
+ real(c_float), target :: gg(N), hh(N)
+
+ type(c_ptr) :: c_aptr, c_bptr, c_cptr, c_dptr, c_eptr, c_fptr, c_gptr, c_hptr
+ real(c_float), pointer :: aptr, bptr, cptr, dptr, eptr, fptr
+ real(c_float), pointer :: gptr(:), hptr(:)
+
+ allocate(cc, dd, ee, ff)
+ call test_dummy_callee_2(aa, bb, cc, dd, ee, ff, gg, hh, &
+ c_aptr, c_bptr, c_cptr, c_dptr, c_eptr, c_fptr, c_gptr, c_hptr, &
+ aptr, bptr, cptr, dptr, eptr, fptr, gptr, hptr, &
+ N)
+ deallocate(ee, ff)
+ end subroutine test_dummy_call_2
+
+ subroutine test_dummy_callee_2(aa, bb, cc, dd, ee, ff, gg, hh, &
+ c_aptr, c_bptr, c_cptr, c_dptr, c_eptr, c_fptr, c_gptr, c_hptr, &
+ aptr, bptr, cptr, dptr, eptr, fptr, gptr, hptr, &
+ N)
+ ! scalars
+ real(c_float), target :: aa, bb
+ real(c_float), target, allocatable :: cc, dd
+ real(c_float), pointer :: ee, ff
+
+ ! non-descriptor arrays
+ real(c_float), target :: gg(N), hh(N)
+
+ type(c_ptr) :: c_aptr, c_bptr, c_cptr, c_dptr, c_eptr, c_fptr, c_gptr, c_hptr
+ real(c_float), pointer :: aptr, bptr, cptr, dptr, eptr, fptr
+ real(c_float), pointer :: gptr(:), hptr(:)
+
+ integer, value :: N
+
+ real(c_float) :: dummy
+
+ aa = 111.0_c_float
+ bb = 222.0_c_float
+ cc = 333.0_c_float
+ dd = 444.0_c_float
+ ee = 555.0_c_float
+ ff = 666.0_c_float
+ gg = 777.0_c_float
+ hh = 888.0_c_float
+
+ !$omp target data map(to:aa) map(from:bb)
+ !$omp target data map(alloc:dummy) use_device_addr(aa,bb)
+ c_aptr = c_loc(aa)
+ c_bptr = c_loc(bb)
+ aptr => aa
+ bptr => bb
+ !$omp end target data
+
+ ! check c_loc ptr once
+ call copy3_scalar(c_aptr, c_bptr)
+ !$omp target update from(bb)
+ if (abs(aa - 111.0_c_float) > 10.0_c_float * epsilon(aa)) stop 1
+ if (abs(3.0_c_float * aa - bb) > 10.0_c_float * epsilon(aa)) stop 1
+
+ ! check c_loc ptr again after target-value modification
+ aa = 1111.0_c_float
+ !$omp target update to(aa)
+ call copy3_scalar(c_aptr, c_bptr)
+ !$omp target update from(bb)
+ if (abs(aa - 1111.0_c_float) > 10.0_c_float * epsilon(aa)) stop 1
+ if (abs(3.0_c_float * aa - bb) > 10.0_c_float * epsilon(aa)) stop 1
+
+ ! check Fortran pointer after target-value modification
+ aa = 11111.0_c_float
+ !$omp target update to(aa)
+ call copy3_scalar(c_loc(aptr), c_loc(bptr))
+ !$omp target update from(bb)
+ if (abs(aa - 11111.0_c_float) > 10.0_c_float * epsilon(aa)) stop 1
+ if (abs(3.0_c_float * aa - bb) > 10.0_c_float * epsilon(aa)) stop 1
+ !$omp end target data
+
+ if (abs(aa - 11111.0_c_float) > 10.0_c_float * epsilon(aa)) stop 1
+ if (abs(3.0_c_float * aa - bb) > 10.0_c_float * epsilon(aa)) stop 1
+
+
+ !$omp target data map(to:cc) map(from:dd)
+ !$omp target data map(alloc:dummy) use_device_addr(cc,dd)
+ c_cptr = c_loc(cc)
+ c_dptr = c_loc(dd)
+ cptr => cc
+ dptr => dd
+ !$omp end target data
+
+ ! check c_loc ptr once
+ call copy3_scalar(c_cptr, c_dptr)
+ !$omp target update from(dd)
+ if (abs(cc - 333.0_c_float) > 10.0_c_float * epsilon(cc)) stop 1
+ if (abs(3.0_c_float * cc - dd) > 10.0_c_float * epsilon(cc)) stop 1
+
+ ! check c_loc ptr again after target-value modification
+ cc = 3333.0_c_float
+ !$omp target update to(cc)
+ call copy3_scalar(c_cptr, c_dptr)
+ !$omp target update from(dd)
+ if (abs(cc - 3333.0_c_float) > 10.0_c_float * epsilon(cc)) stop 1
+ if (abs(3.0_c_float * cc - dd) > 10.0_c_float * epsilon(cc)) stop 1
+
+ ! check Fortran pointer after target-value modification
+ cc = 33333.0_c_float
+ !$omp target update to(cc)
+ call copy3_scalar(c_loc(cptr), c_loc(dptr))
+ !$omp target update from(dd)
+ if (abs(cc - 33333.0_c_float) > 10.0_c_float * epsilon(cc)) stop 1
+ if (abs(3.0_c_float * cc - dd) > 10.0_c_float * epsilon(cc)) stop 1
+ !$omp end target data
+
+ if (abs(cc - 33333.0_c_float) > 10.0_c_float * epsilon(dd)) stop 1
+ if (abs(3.0_c_float * cc - dd) > 10.0_c_float * epsilon(dd)) stop 1
+
+
+ !$omp target data map(to:ee) map(from:ff)
+ !$omp target data map(alloc:dummy) use_device_addr(ee,ff)
+ c_eptr = c_loc(ee)
+ c_fptr = c_loc(ff)
+ eptr => ee
+ fptr => ff
+ !$omp end target data
+
+ ! check c_loc ptr once
+ call copy3_scalar(c_eptr, c_fptr)
+ !$omp target update from(ff)
+ if (abs(ee - 555.0_c_float) > 10.0_c_float * epsilon(ee)) stop 1
+ if (abs(3.0_c_float * ee - ff) > 10.0_c_float * epsilon(ee)) stop 1
+
+ ! check c_loc ptr again after target-value modification
+ ee = 5555.0_c_float
+ !$omp target update to(ee)
+ call copy3_scalar(c_eptr, c_fptr)
+ !$omp target update from(ff)
+ if (abs(ee - 5555.0_c_float) > 10.0_c_float * epsilon(ee)) stop 1
+ if (abs(3.0_c_float * ee - ff) > 10.0_c_float * epsilon(ee)) stop 1
+
+ ! check Fortran pointer after target-value modification
+ ee = 55555.0_c_float
+ !$omp target update to(ee)
+ call copy3_scalar(c_loc(eptr), c_loc(fptr))
+ !$omp target update from(ff)
+ if (abs(ee - 55555.0_c_float) > 10.0_c_float * epsilon(ee)) stop 1
+ if (abs(3.0_c_float * ee - ff) > 10.0_c_float * epsilon(ff)) stop 1
+ !$omp end target data
+
+ if (abs(ee - 55555.0_c_float) > 10.0_c_float * epsilon(ee)) stop 1
+ if (abs(3.0_c_float * ee - ff) > 10.0_c_float * epsilon(ee)) stop 1
+
+
+ !$omp target data map(to:gg) map(from:hh)
+ !$omp target data map(alloc:dummy) use_device_addr(gg,hh)
+ c_gptr = c_loc(gg)
+ c_hptr = c_loc(hh)
+ gptr => gg
+ hptr => hh
+ !$omp end target data
+
+ ! check c_loc ptr once
+ call copy3_array(c_gptr, c_hptr, N)
+ !$omp target update from(hh)
+ if (any(abs(gg - 777.0_c_float) > 10.0_c_float * epsilon(gg))) stop 1
+ if (any(abs(3.0_c_float * gg - hh) > 10.0_c_float * epsilon(hh))) stop 1
+
+ ! check c_loc ptr again after target-value modification
+ gg = 7777.0_c_float
+ !$omp target update to(gg)
+ call copy3_array(c_gptr, c_hptr, N)
+ !$omp target update from(hh)
+ if (any(abs(gg - 7777.0_c_float) > 10.0_c_float * epsilon(gg))) stop 1
+ if (any(abs(3.0_c_float * gg - hh) > 10.0_c_float * epsilon(gg))) stop 1
+
+ ! check Fortran pointer after target-value modification
+ gg = 77777.0_c_float
+ !$omp target update to(gg)
+ call copy3_array(c_loc(gptr), c_loc(hptr), N)
+ !$omp target update from(hh)
+ if (any(abs(gg - 77777.0_c_float) > 10.0_c_float * epsilon(gg))) stop 1
+ if (any(abs(3.0_c_float * gg - hh) > 10.0_c_float * epsilon(gg))) stop 1
+ !$omp end target data
+
+ if (any(abs(gg - 77777.0_c_float) > 10.0_c_float * epsilon(gg))) stop 1
+ if (any(abs(3.0_c_float * gg - hh) > 10.0_c_float * epsilon(gg))) stop 1
+ end subroutine test_dummy_callee_2
+end module test_dummies
+
+
+
+! Test local dummy arguments + VALUE (w/o optional)
+module test_dummies_value
+ use iso_c_binding
+ use target_procs
+ implicit none (type, external)
+ private
+ public :: test_dummy_val_call_1, test_dummy_val_call_2
+contains
+ subroutine test_dummy_val_call_1()
+ ! scalars - with value, neither allocatable nor pointer no dimension permitted
+ real(c_float), target :: aa, bb
+
+ aa = 11.0_c_float
+ bb = 22.0_c_float
+
+ call test_dummy_val_callee_1(aa, bb)
+ end subroutine test_dummy_val_call_1
+
+ subroutine test_dummy_val_callee_1(aa, bb)
+ ! scalars
+ real(c_float), value, target :: aa, bb
+
+ !$omp target data map(to:aa) map(from:bb) use_device_addr(aa,bb)
+ call copy3_scalar(c_loc(aa), c_loc(bb))
+ !$omp end target data
+ if (abs(aa - 11.0_c_float) > 10.0_c_float * epsilon(aa)) stop 1
+ if (abs(3.0_c_float * aa - bb) > 10.0_c_float * epsilon(aa)) stop 1
+ end subroutine test_dummy_val_callee_1
+
+ ! Save device ptr - and recall pointer
+ subroutine test_dummy_val_call_2()
+ ! scalars - with value, neither allocatable nor pointer no dimension permitted
+ real(c_float), target :: aa, bb
+ type(c_ptr) :: c_aptr, c_bptr
+ real(c_float), pointer :: aptr, bptr
+
+ call test_dummy_val_callee_2(aa, bb, c_aptr, c_bptr, aptr, bptr)
+ end subroutine test_dummy_val_call_2
+
+ subroutine test_dummy_val_callee_2(aa, bb, c_aptr, c_bptr, aptr, bptr)
+ real(c_float), value, target :: aa, bb
+ type(c_ptr), value :: c_aptr, c_bptr
+ real(c_float), pointer :: aptr, bptr
+
+ real(c_float) :: dummy
+
+ aa = 111.0_c_float
+ bb = 222.0_c_float
+
+ !$omp target data map(to:aa) map(from:bb)
+ !$omp target data map(alloc:dummy) use_device_addr(aa,bb)
+ c_aptr = c_loc(aa)
+ c_bptr = c_loc(bb)
+ aptr => aa
+ bptr => bb
+ !$omp end target data
+
+ ! check c_loc ptr once
+ call copy3_scalar(c_aptr, c_bptr)
+ !$omp target update from(bb)
+ if (abs(aa - 111.0_c_float) > 10.0_c_float * epsilon(aa)) stop 1
+ if (abs(3.0_c_float * aa - bb) > 10.0_c_float * epsilon(aa)) stop 1
+
+ ! check c_loc ptr again after target-value modification
+ aa = 1111.0_c_float
+ !$omp target update to(aa)
+ call copy3_scalar(c_aptr, c_bptr)
+ !$omp target update from(bb)
+ if (abs(aa - 1111.0_c_float) > 10.0_c_float * epsilon(aa)) stop 1
+ if (abs(3.0_c_float * aa - bb) > 10.0_c_float * epsilon(aa)) stop 1
+
+ ! check Fortran pointer after target-value modification
+ aa = 11111.0_c_float
+ !$omp target update to(aa)
+ call copy3_scalar(c_loc(aptr), c_loc(bptr))
+ !$omp target update from(bb)
+ if (abs(aa - 11111.0_c_float) > 10.0_c_float * epsilon(aa)) stop 1
+ if (abs(3.0_c_float * aa - bb) > 10.0_c_float * epsilon(aa)) stop 1
+ !$omp end target data
+
+ if (abs(aa - 11111.0_c_float) > 10.0_c_float * epsilon(aa)) stop 1
+ if (abs(3.0_c_float * aa - bb) > 10.0_c_float * epsilon(aa)) stop 1
+ end subroutine test_dummy_val_callee_2
+end module test_dummies_value
+
+
+
+! Test local dummy arguments + OPTIONAL
+! Values present and ptr associated to nonzero
+module test_dummies_opt
+ use iso_c_binding
+ use target_procs
+ implicit none (type, external)
+ private
+ public :: test_dummy_opt_call_1, test_dummy_opt_call_2
+contains
+ subroutine test_dummy_opt_call_1()
+ integer, parameter :: N = 1000
+
+ ! scalars
+ real(c_float), target :: aa, bb
+ real(c_float), target, allocatable :: cc, dd
+ real(c_float), pointer :: ee, ff
+
+ ! non-descriptor arrays
+ real(c_float), target :: gg(N), hh(N)
+
+ allocate(cc, dd, ee, ff)
+
+ aa = 11.0_c_float
+ bb = 22.0_c_float
+ cc = 33.0_c_float
+ dd = 44.0_c_float
+ ee = 55.0_c_float
+ ff = 66.0_c_float
+ gg = 77.0_c_float
+ hh = 88.0_c_float
+
+ call test_dummy_opt_callee_1(aa, bb, cc, dd, ee, ff, gg, hh, N)
+ deallocate(ee, ff) ! pointers, only
+ end subroutine test_dummy_opt_call_1
+
+ subroutine test_dummy_opt_callee_1(aa, bb, cc, dd, ee, ff, gg, hh, N)
+ ! scalars
+ real(c_float), optional, target :: aa, bb
+ real(c_float), optional, target, allocatable :: cc, dd
+ real(c_float), optional, pointer :: ee, ff
+
+ ! non-descriptor arrays
+ real(c_float), optional, target :: gg(N), hh(N)
+ integer, value :: N
+
+ ! All shall be present - and pointing to non-NULL
+ if (.not.present(aa) .or. .not.present(bb)) stop 1
+ if (.not.present(cc) .or. .not.present(dd)) stop 1
+ if (.not.present(ee) .or. .not.present(ff)) stop 1
+ if (.not.present(gg) .or. .not.present(hh)) stop 1
+
+ if (.not.associated(ee) .or. .not.associated(ff)) stop 1
+
+ !$omp target data map(to:aa) map(from:bb) use_device_addr(aa,bb)
+ if (.not.present(aa) .or. .not.present(bb)) stop 1
+ if (.not.c_associated(c_loc(aa)) .or. .not.c_associated(c_loc(bb))) stop 1
+ call copy3_scalar(c_loc(aa), c_loc(bb))
+ !$omp end target data
+ if (abs(aa - 11.0_c_float) > 10.0_c_float * epsilon(aa)) stop 1
+ if (abs(3.0_c_float * aa - bb) > 10.0_c_float * epsilon(aa)) stop 1
+
+ !$omp target data map(to:cc) map(from:dd) use_device_addr(cc,dd)
+ if (.not.present(cc) .or. .not.present(dd)) stop 1
+ if (.not.c_associated(c_loc(cc)) .or. .not.c_associated(c_loc(dd))) stop 1
+ call copy3_scalar(c_loc(cc), c_loc(dd))
+ !$omp end target data
+ if (abs(cc - 33.0_c_float) > 10.0_c_float * epsilon(cc)) stop 1
+ if (abs(3.0_c_float * cc - dd) > 10.0_c_float * epsilon(cc)) stop 1
+
+ !$omp target data map(to:ee) map(from:ff) use_device_addr(ee,ff)
+ if (.not.present(ee) .or. .not.present(ff)) stop 1
+ if (.not.associated(ee) .or. .not.associated(ff)) stop 1
+ if (.not.c_associated(c_loc(ee)) .or. .not.c_associated(c_loc(ff))) stop 1
+ call copy3_scalar(c_loc(ee), c_loc(ff))
+ !$omp end target data
+ if (abs(ee - 55.0_c_float) > 10.0_c_float * epsilon(ee)) stop 1
+ if (abs(3.0_c_float * ee - ff) > 10.0_c_float * epsilon(ee)) stop 1
+
+ !$omp target data map(to:gg) map(from:hh) use_device_addr(gg,hh)
+ if (.not.present(gg) .or. .not.present(hh)) stop 1
+ if (.not.c_associated(c_loc(gg)) .or. .not.c_associated(c_loc(hh))) stop 1
+ call copy3_array(c_loc(gg), c_loc(hh), N)
+ !$omp end target data
+ if (any(abs(gg - 77.0_c_float) > 10.0_c_float * epsilon(gg))) stop 1
+ if (any(abs(3.0_c_float * gg - hh) > 10.0_c_float * epsilon(gg))) stop 1
+ end subroutine test_dummy_opt_callee_1
+
+ ! Save device ptr - and recall pointer
+ subroutine test_dummy_opt_call_2()
+ integer, parameter :: N = 1000
+
+ ! scalars
+ real(c_float), target :: aa, bb
+ real(c_float), target, allocatable :: cc, dd
+ real(c_float), pointer :: ee, ff
+
+ ! non-descriptor arrays
+ real(c_float), target :: gg(N), hh(N)
+
+ type(c_ptr) :: c_aptr, c_bptr, c_cptr, c_dptr, c_eptr, c_fptr, c_gptr, c_hptr
+ real(c_float), pointer :: aptr, bptr, cptr, dptr, eptr, fptr
+ real(c_float), pointer :: gptr(:), hptr(:)
+
+ allocate(cc, dd, ee, ff)
+ call test_dummy_opt_callee_2(aa, bb, cc, dd, ee, ff, gg, hh, &
+ c_aptr, c_bptr, c_cptr, c_dptr, c_eptr, c_fptr, c_gptr, c_hptr, &
+ aptr, bptr, cptr, dptr, eptr, fptr, gptr, hptr, &
+ N)
+ deallocate(ee, ff)
+ end subroutine test_dummy_opt_call_2
+
+ subroutine test_dummy_opt_callee_2(aa, bb, cc, dd, ee, ff, gg, hh, &
+ c_aptr, c_bptr, c_cptr, c_dptr, c_eptr, c_fptr, c_gptr, c_hptr, &
+ aptr, bptr, cptr, dptr, eptr, fptr, gptr, hptr, &
+ N)
+ ! scalars
+ real(c_float), optional, target :: aa, bb
+ real(c_float), optional, target, allocatable :: cc, dd
+ real(c_float), optional, pointer :: ee, ff
+
+ ! non-descriptor arrays
+ real(c_float), optional, target :: gg(N), hh(N)
+
+ type(c_ptr) :: c_aptr, c_bptr, c_cptr, c_dptr, c_eptr, c_fptr, c_gptr, c_hptr
+ real(c_float), optional, pointer :: aptr, bptr, cptr, dptr, eptr, fptr
+ real(c_float), optional, pointer :: gptr(:), hptr(:)
+
+ integer, value :: N
+
+ real(c_float) :: dummy
+
+ ! All shall be present - and pointing to non-NULL
+ if (.not.present(aa) .or. .not.present(bb)) stop 1
+ if (.not.present(cc) .or. .not.present(dd)) stop 1
+ if (.not.present(ee) .or. .not.present(ff)) stop 1
+ if (.not.present(gg) .or. .not.present(hh)) stop 1
+
+ if (.not.associated(ee) .or. .not.associated(ff)) stop 1
+
+ aa = 111.0_c_float
+ bb = 222.0_c_float
+ cc = 333.0_c_float
+ dd = 444.0_c_float
+ ee = 555.0_c_float
+ ff = 666.0_c_float
+ gg = 777.0_c_float
+ hh = 888.0_c_float
+
+ !$omp target data map(to:aa) map(from:bb)
+ !$omp target data map(alloc:dummy) use_device_addr(aa,bb)
+ if (.not.present(aa) .or. .not.present(bb)) stop 1
+ if (.not.c_associated(c_loc(aa)) .or. .not.c_associated(c_loc(bb))) stop 1
+ c_aptr = c_loc(aa)
+ c_bptr = c_loc(bb)
+ aptr => aa
+ bptr => bb
+ if (.not.c_associated(c_aptr) .or. .not.c_associated(c_bptr)) stop 1
+ if (.not.associated(aptr) .or. .not.associated(bptr)) stop 1
+ !$omp end target data
+
+ if (.not.present(aa) .or. .not.present(bb)) stop 1
+ if (.not.c_associated(c_loc(aa)) .or. .not.c_associated(c_loc(bb))) stop 1
+ if (.not.c_associated(c_aptr) .or. .not.c_associated(c_bptr)) stop 1
+ if (.not.associated(aptr) .or. .not.associated(bptr)) stop 1
+
+ ! check c_loc ptr once
+ call copy3_scalar(c_aptr, c_bptr)
+ !$omp target update from(bb)
+ if (abs(aa - 111.0_c_float) > 10.0_c_float * epsilon(aa)) stop 1
+ if (abs(3.0_c_float * aa - bb) > 10.0_c_float * epsilon(aa)) stop 1
+
+ ! check c_loc ptr again after target-value modification
+ aa = 1111.0_c_float
+ !$omp target update to(aa)
+ call copy3_scalar(c_aptr, c_bptr)
+ !$omp target update from(bb)
+ if (abs(aa - 1111.0_c_float) > 10.0_c_float * epsilon(aa)) stop 1
+ if (abs(3.0_c_float * aa - bb) > 10.0_c_float * epsilon(aa)) stop 1
+
+ ! check Fortran pointer after target-value modification
+ aa = 11111.0_c_float
+ !$omp target update to(aa)
+ call copy3_scalar(c_loc(aptr), c_loc(bptr))
+ !$omp target update from(bb)
+ if (abs(aa - 11111.0_c_float) > 10.0_c_float * epsilon(aa)) stop 1
+ if (abs(3.0_c_float * aa - bb) > 10.0_c_float * epsilon(aa)) stop 1
+ !$omp end target data
+
+ if (abs(aa - 11111.0_c_float) > 10.0_c_float * epsilon(aa)) stop 1
+ if (abs(3.0_c_float * aa - bb) > 10.0_c_float * epsilon(aa)) stop 1
+
+
+ !$omp target data map(to:cc) map(from:dd)
+ !$omp target data map(alloc:dummy) use_device_addr(cc,dd)
+ if (.not.present(cc) .or. .not.present(dd)) stop 1
+ if (.not.c_associated(c_loc(cc)) .or. .not.c_associated(c_loc(dd))) stop 1
+ c_cptr = c_loc(cc)
+ c_dptr = c_loc(dd)
+ cptr => cc
+ dptr => dd
+ if (.not.c_associated(c_cptr) .or. .not.c_associated(c_dptr)) stop 1
+ if (.not.associated(cptr) .or. .not.associated(dptr)) stop 1
+ !$omp end target data
+ if (.not.present(cc) .or. .not.present(dd)) stop 1
+ if (.not.c_associated(c_loc(cc)) .or. .not.c_associated(c_loc(dd))) stop 1
+ if (.not.c_associated(c_cptr) .or. .not.c_associated(c_dptr)) stop 1
+ if (.not.associated(cptr) .or. .not.associated(dptr)) stop 1
+
+ ! check c_loc ptr once
+ call copy3_scalar(c_cptr, c_dptr)
+ !$omp target update from(dd)
+ if (abs(cc - 333.0_c_float) > 10.0_c_float * epsilon(cc)) stop 1
+ if (abs(3.0_c_float * cc - dd) > 10.0_c_float * epsilon(cc)) stop 1
+
+ ! check c_loc ptr again after target-value modification
+ cc = 3333.0_c_float
+ !$omp target update to(cc)
+ call copy3_scalar(c_cptr, c_dptr)
+ !$omp target update from(dd)
+ if (abs(cc - 3333.0_c_float) > 10.0_c_float * epsilon(cc)) stop 1
+ if (abs(3.0_c_float * cc - dd) > 10.0_c_float * epsilon(cc)) stop 1
+
+ ! check Fortran pointer after target-value modification
+ cc = 33333.0_c_float
+ !$omp target update to(cc)
+ call copy3_scalar(c_loc(cptr), c_loc(dptr))
+ !$omp target update from(dd)
+ if (abs(cc - 33333.0_c_float) > 10.0_c_float * epsilon(cc)) stop 1
+ if (abs(3.0_c_float * cc - dd) > 10.0_c_float * epsilon(cc)) stop 1
+ !$omp end target data
+
+ if (abs(cc - 33333.0_c_float) > 10.0_c_float * epsilon(dd)) stop 1
+ if (abs(3.0_c_float * cc - dd) > 10.0_c_float * epsilon(dd)) stop 1
+
+
+ !$omp target data map(to:ee) map(from:ff)
+ !$omp target data map(alloc:dummy) use_device_addr(ee,ff)
+ if (.not.present(ee) .or. .not.present(ff)) stop 1
+ if (.not.associated(ee) .or. .not.associated(ff)) stop 1
+ if (.not.c_associated(c_loc(ee)) .or. .not.c_associated(c_loc(ff))) stop 1
+ c_eptr = c_loc(ee)
+ c_fptr = c_loc(ff)
+ eptr => ee
+ fptr => ff
+ if (.not.c_associated(c_eptr) .or. .not.c_associated(c_fptr)) stop 1
+ if (.not.associated(eptr) .or. .not.associated(fptr)) stop 1
+ !$omp end target data
+ if (.not.present(ee) .or. .not.present(ff)) stop 1
+ if (.not.associated(ee) .or. .not.associated(ff)) stop 1
+ if (.not.c_associated(c_loc(ee)) .or. .not.c_associated(c_loc(ff))) stop 1
+ if (.not.c_associated(c_eptr) .or. .not.c_associated(c_fptr)) stop 1
+ if (.not.associated(eptr) .or. .not.associated(fptr)) stop 1
+
+ ! check c_loc ptr once
+ call copy3_scalar(c_eptr, c_fptr)
+ !$omp target update from(ff)
+ if (abs(ee - 555.0_c_float) > 10.0_c_float * epsilon(ee)) stop 1
+ if (abs(3.0_c_float * ee - ff) > 10.0_c_float * epsilon(ee)) stop 1
+
+ ! check c_loc ptr again after target-value modification
+ ee = 5555.0_c_float
+ !$omp target update to(ee)
+ call copy3_scalar(c_eptr, c_fptr)
+ !$omp target update from(ff)
+ if (abs(ee - 5555.0_c_float) > 10.0_c_float * epsilon(ee)) stop 1
+ if (abs(3.0_c_float * ee - ff) > 10.0_c_float * epsilon(ee)) stop 1
+
+ ! check Fortran pointer after target-value modification
+ ee = 55555.0_c_float
+ !$omp target update to(ee)
+ call copy3_scalar(c_loc(eptr), c_loc(fptr))
+ !$omp target update from(ff)
+ if (abs(ee - 55555.0_c_float) > 10.0_c_float * epsilon(ee)) stop 1
+ if (abs(3.0_c_float * ee - ff) > 10.0_c_float * epsilon(ff)) stop 1
+ !$omp end target data
+
+ if (abs(ee - 55555.0_c_float) > 10.0_c_float * epsilon(ee)) stop 1
+ if (abs(3.0_c_float * ee - ff) > 10.0_c_float * epsilon(ee)) stop 1
+
+
+ !$omp target data map(to:gg) map(from:hh)
+ !$omp target data map(alloc:dummy) use_device_addr(gg,hh)
+ if (.not.present(gg) .or. .not.present(hh)) stop 1
+ if (.not.c_associated(c_loc(gg)) .or. .not.c_associated(c_loc(hh))) stop 1
+ c_gptr = c_loc(gg)
+ c_hptr = c_loc(hh)
+ gptr => gg
+ hptr => hh
+ if (.not.c_associated(c_gptr) .or. .not.c_associated(c_hptr)) stop 1
+ if (.not.associated(gptr) .or. .not.associated(hptr)) stop 1
+ !$omp end target data
+ if (.not.present(gg) .or. .not.present(hh)) stop 1
+ if (.not.c_associated(c_loc(gg)) .or. .not.c_associated(c_loc(hh))) stop 1
+ if (.not.c_associated(c_gptr) .or. .not.c_associated(c_hptr)) stop 1
+ if (.not.associated(gptr) .or. .not.associated(hptr)) stop 1
+
+ ! check c_loc ptr once
+ call copy3_array(c_gptr, c_hptr, N)
+ !$omp target update from(hh)
+ if (any(abs(gg - 777.0_c_float) > 10.0_c_float * epsilon(gg))) stop 1
+ if (any(abs(3.0_c_float * gg - hh) > 10.0_c_float * epsilon(hh))) stop 1
+
+ ! check c_loc ptr again after target-value modification
+ gg = 7777.0_c_float
+ !$omp target update to(gg)
+ call copy3_array(c_gptr, c_hptr, N)
+ !$omp target update from(hh)
+ if (any(abs(gg - 7777.0_c_float) > 10.0_c_float * epsilon(gg))) stop 1
+ if (any(abs(3.0_c_float * gg - hh) > 10.0_c_float * epsilon(gg))) stop 1
+
+ ! check Fortran pointer after target-value modification
+ gg = 77777.0_c_float
+ !$omp target update to(gg)
+ call copy3_array(c_loc(gptr), c_loc(hptr), N)
+ !$omp target update from(hh)
+ if (any(abs(gg - 77777.0_c_float) > 10.0_c_float * epsilon(gg))) stop 1
+ if (any(abs(3.0_c_float * gg - hh) > 10.0_c_float * epsilon(gg))) stop 1
+ !$omp end target data
+
+ if (any(abs(gg - 77777.0_c_float) > 10.0_c_float * epsilon(gg))) stop 1
+ if (any(abs(3.0_c_float * gg - hh) > 10.0_c_float * epsilon(gg))) stop 1
+ end subroutine test_dummy_opt_callee_2
+end module test_dummies_opt
+
+
+
+! Test local dummy arguments + OPTIONAL + VALUE
+! Values present
+module test_dummies_opt_value
+ use iso_c_binding
+ use target_procs
+ implicit none (type, external)
+ private
+ public :: test_dummy_opt_val_call_1, test_dummy_opt_val_call_2
+contains
+ subroutine test_dummy_opt_val_call_1()
+ ! scalars - with value, neither allocatable nor pointer no dimension permitted
+ real(c_float), target :: aa, bb
+
+ aa = 11.0_c_float
+ bb = 22.0_c_float
+
+ call test_dummy_opt_val_callee_1(aa, bb)
+ end subroutine test_dummy_opt_val_call_1
+
+ subroutine test_dummy_opt_val_callee_1(aa, bb)
+ ! scalars
+ real(c_float), optional, value, target :: aa, bb
+
+ if (.not.present(aa) .or. .not.present(bb)) stop 1
+
+ !$omp target data map(to:aa) map(from:bb) use_device_addr(aa,bb)
+ if (.not.present(aa) .or. .not.present(bb)) stop 1
+ if (.not.c_associated(c_loc(aa)) .or. .not.c_associated(c_loc(bb))) stop 1
+ call copy3_scalar(c_loc(aa), c_loc(bb))
+ !$omp end target data
+ if (abs(aa - 11.0_c_float) > 10.0_c_float * epsilon(aa)) stop 1
+ if (abs(3.0_c_float * aa - bb) > 10.0_c_float * epsilon(aa)) stop 1
+ end subroutine test_dummy_opt_val_callee_1
+
+ ! Save device ptr - and recall pointer
+ subroutine test_dummy_opt_val_call_2()
+ ! scalars - with value, neither allocatable nor pointer no dimension permitted
+ real(c_float), target :: aa, bb
+ type(c_ptr) :: c_aptr, c_bptr
+ real(c_float), pointer :: aptr, bptr
+
+ call test_dummy_opt_val_callee_2(aa, bb, c_aptr, c_bptr, aptr, bptr)
+ end subroutine test_dummy_opt_val_call_2
+
+ subroutine test_dummy_opt_val_callee_2(aa, bb, c_aptr, c_bptr, aptr, bptr)
+ real(c_float), optional, value, target :: aa, bb
+ type(c_ptr), optional, value :: c_aptr, c_bptr
+ real(c_float), optional, pointer :: aptr, bptr
+
+ real(c_float) :: dummy
+
+ if (.not.present(aa) .or. .not.present(bb)) stop 1
+ if (.not.present(c_aptr) .or. .not.present(c_bptr)) stop 1
+ if (.not.present(aptr) .or. .not.present(bptr)) stop 1
+
+ aa = 111.0_c_float
+ bb = 222.0_c_float
+
+ !$omp target data map(to:aa) map(from:bb)
+ if (.not.present(aa) .or. .not.present(bb)) stop 1
+ if (.not.present(c_aptr) .or. .not.present(c_bptr)) stop 1
+ if (.not.present(aptr) .or. .not.present(bptr)) stop 1
+
+ !$omp target data map(alloc:dummy) use_device_addr(aa,bb)
+ if (.not.present(aa) .or. .not.present(bb)) stop 1
+ if (.not.present(c_aptr) .or. .not.present(c_bptr)) stop 1
+ if (.not.present(aptr) .or. .not.present(bptr)) stop 1
+
+ c_aptr = c_loc(aa)
+ c_bptr = c_loc(bb)
+ aptr => aa
+ bptr => bb
+ if (.not.c_associated(c_aptr) .or. .not.c_associated(c_bptr)) stop 1
+ if (.not.associated(aptr) .or. .not.associated(bptr)) stop 1
+ !$omp end target data
+
+ ! check c_loc ptr once
+ call copy3_scalar(c_aptr, c_bptr)
+ !$omp target update from(bb)
+ if (abs(aa - 111.0_c_float) > 10.0_c_float * epsilon(aa)) stop 1
+ if (abs(3.0_c_float * aa - bb) > 10.0_c_float * epsilon(aa)) stop 1
+
+ ! check c_loc ptr again after target-value modification
+ aa = 1111.0_c_float
+ !$omp target update to(aa)
+ call copy3_scalar(c_aptr, c_bptr)
+ !$omp target update from(bb)
+ if (abs(aa - 1111.0_c_float) > 10.0_c_float * epsilon(aa)) stop 1
+ if (abs(3.0_c_float * aa - bb) > 10.0_c_float * epsilon(aa)) stop 1
+
+ ! check Fortran pointer after target-value modification
+ aa = 11111.0_c_float
+ !$omp target update to(aa)
+ call copy3_scalar(c_loc(aptr), c_loc(bptr))
+ !$omp target update from(bb)
+ if (abs(aa - 11111.0_c_float) > 10.0_c_float * epsilon(aa)) stop 1
+ if (abs(3.0_c_float * aa - bb) > 10.0_c_float * epsilon(aa)) stop 1
+ !$omp end target data
+
+ if (abs(aa - 11111.0_c_float) > 10.0_c_float * epsilon(aa)) stop 1
+ if (abs(3.0_c_float * aa - bb) > 10.0_c_float * epsilon(aa)) stop 1
+ end subroutine test_dummy_opt_val_callee_2
+end module test_dummies_opt_value
+
+
+
+! Test nullptr
+module test_nullptr
+ use iso_c_binding
+ implicit none (type, external)
+ private
+ public :: test_nullptr_1
+contains
+ subroutine test_nullptr_1()
+ ! scalars
+ real(c_float), pointer :: aa, bb
+ real(c_float), pointer :: ee, ff
+
+ type(c_ptr) :: c_aptr, c_bptr, c_eptr, c_fptr
+ real(c_float), pointer :: aptr, bptr, eptr, fptr
+
+ aa => null()
+ bb => null()
+ ee => null()
+ ff => null()
+
+ if (associated(aa) .or. associated(bb)) stop 1
+ !$omp target data map(to:aa) map(from:bb) use_device_addr(aa,bb)
+ if (c_associated(c_loc(aa)) .or. c_associated(c_loc(bb))) stop 1
+ c_aptr = c_loc(aa)
+ c_bptr = c_loc(bb)
+ aptr => aa
+ bptr => bb
+ if (c_associated(c_aptr) .or. c_associated(c_bptr)) stop 1
+ if (associated(aptr) .or. associated(bptr, bb)) stop 1
+ !$omp end target data
+ if (c_associated(c_aptr) .or. c_associated(c_bptr)) stop 1
+ if (associated(aptr) .or. associated(bptr, bb)) stop 1
+
+ call test_dummy_opt_nullptr_callee_1(ee, ff, c_eptr, c_fptr, eptr, fptr)
+ end subroutine test_nullptr_1
+
+ subroutine test_dummy_opt_nullptr_callee_1(ee, ff, c_eptr, c_fptr, eptr, fptr)
+ ! scalars
+ real(c_float), optional, pointer :: ee, ff
+
+ type(c_ptr), optional :: c_eptr, c_fptr
+ real(c_float), optional, pointer :: eptr, fptr
+
+ if (.not.present(ee) .or. .not.present(ff)) stop 1
+ if (associated(ee) .or. associated(ff)) stop 1
+
+ !$omp target data map(to:ee) map(from:ff) use_device_addr(ee,ff)
+ if (.not.present(ee) .or. .not.present(ff)) stop 1
+ if (associated(ee) .or. associated(ff)) stop 1
+ if (c_associated(c_loc(ee)) .or. c_associated(c_loc(ff))) stop 1
+ c_eptr = c_loc(ee)
+ c_fptr = c_loc(ff)
+ eptr => ee
+ fptr => ff
+ if (c_associated(c_eptr) .or. c_associated(c_fptr)) stop 1
+ if (associated(eptr) .or. associated(fptr)) stop 1
+ !$omp end target data
+
+ if (c_associated(c_eptr) .or. c_associated(c_fptr)) stop 1
+ if (associated(eptr) .or. associated(fptr)) stop 1
+ end subroutine test_dummy_opt_nullptr_callee_1
+end module test_nullptr
+
+
+
+! Test local variables
+module tests
+ use iso_c_binding
+ use target_procs
+ implicit none (type, external)
+ private
+ public :: test_main_1, test_main_2
+contains
+ ! map + use_device_addr + c_loc
+ subroutine test_main_1()
+ integer, parameter :: N = 1000
+
+ ! scalars
+ real(c_float), target :: aa, bb
+ real(c_float), target, allocatable :: cc, dd
+ real(c_float), pointer :: ee, ff
+
+ ! non-descriptor arrays
+ real(c_float), target :: gg(N), hh(N)
+
+ allocate(cc, dd, ee, ff)
+
+
+ aa = 11.0_c_float
+ bb = 22.0_c_float
+ cc = 33.0_c_float
+ dd = 44.0_c_float
+ ee = 55.0_c_float
+ ff = 66.0_c_float
+ gg = 77.0_c_float
+ hh = 88.0_c_float
+
+ !$omp target data map(to:aa) map(from:bb) use_device_addr(aa,bb)
+ call copy3_scalar(c_loc(aa), c_loc(bb))
+ !$omp end target data
+ if (abs(aa - 11.0_c_float) > 10.0_c_float * epsilon(aa)) stop 1
+ if (abs(3.0_c_float * aa - bb) > 10.0_c_float * epsilon(aa)) stop 1
+
+ !$omp target data map(to:cc) map(from:dd) use_device_addr(cc,dd)
+ call copy3_scalar(c_loc(cc), c_loc(dd))
+ !$omp end target data
+ if (abs(cc - 33.0_c_float) > 10.0_c_float * epsilon(cc)) stop 1
+ if (abs(3.0_c_float * cc - dd) > 10.0_c_float * epsilon(cc)) stop 1
+
+ !$omp target data map(to:ee) map(from:ff) use_device_addr(ee,ff)
+ call copy3_scalar(c_loc(ee), c_loc(ff))
+ !$omp end target data
+ if (abs(ee - 55.0_c_float) > 10.0_c_float * epsilon(ee)) stop 1
+ if (abs(3.0_c_float * ee - ff) > 10.0_c_float * epsilon(ee)) stop 1
+
+
+ !$omp target data map(to:gg) map(from:hh) use_device_addr(gg,hh)
+ call copy3_array(c_loc(gg), c_loc(hh), N)
+ !$omp end target data
+ if (any(abs(gg - 77.0_c_float) > 10.0_c_float * epsilon(gg))) stop 1
+ if (any(abs(3.0_c_float * gg - hh) > 10.0_c_float * epsilon(gg))) stop 1
+
+ deallocate(ee, ff) ! pointers, only
+ end subroutine test_main_1
+
+ ! Save device ptr - and recall pointer
+ subroutine test_main_2
+ integer, parameter :: N = 1000
+
+ ! scalars
+ real(c_float), target :: aa, bb
+ real(c_float), target, allocatable :: cc, dd
+ real(c_float), pointer :: ee, ff
+
+ ! non-descriptor arrays
+ real(c_float), target :: gg(N), hh(N)
+
+ real(c_float) :: dummy
+ type(c_ptr) :: c_aptr, c_bptr, c_cptr, c_dptr, c_eptr, c_fptr, c_gptr, c_hptr
+ real(c_float), pointer :: aptr, bptr, cptr, dptr, eptr, fptr
+ real(c_float), pointer :: gptr(:), hptr(:)
+
+ allocate(cc, dd, ee, ff)
+
+ aa = 111.0_c_float
+ bb = 222.0_c_float
+ cc = 333.0_c_float
+ dd = 444.0_c_float
+ ee = 555.0_c_float
+ ff = 666.0_c_float
+ gg = 777.0_c_float
+ hh = 888.0_c_float
+
+ !$omp target data map(to:aa) map(from:bb)
+ !$omp target data map(alloc:dummy) use_device_addr(aa,bb)
+ c_aptr = c_loc(aa)
+ c_bptr = c_loc(bb)
+ aptr => aa
+ bptr => bb
+ !$omp end target data
+
+ ! check c_loc ptr once
+ call copy3_scalar(c_aptr, c_bptr)
+ !$omp target update from(bb)
+ if (abs(aa - 111.0_c_float) > 10.0_c_float * epsilon(aa)) stop 1
+ if (abs(3.0_c_float * aa - bb) > 10.0_c_float * epsilon(aa)) stop 1
+
+ ! check c_loc ptr again after target-value modification
+ aa = 1111.0_c_float
+ !$omp target update to(aa)
+ call copy3_scalar(c_aptr, c_bptr)
+ !$omp target update from(bb)
+ if (abs(aa - 1111.0_c_float) > 10.0_c_float * epsilon(aa)) stop 1
+ if (abs(3.0_c_float * aa - bb) > 10.0_c_float * epsilon(aa)) stop 1
+
+ ! check Fortran pointer after target-value modification
+ aa = 11111.0_c_float
+ !$omp target update to(aa)
+ call copy3_scalar(c_loc(aptr), c_loc(bptr))
+ !$omp target update from(bb)
+ if (abs(aa - 11111.0_c_float) > 10.0_c_float * epsilon(aa)) stop 1
+ if (abs(3.0_c_float * aa - bb) > 10.0_c_float * epsilon(aa)) stop 1
+ !$omp end target data
+
+ if (abs(aa - 11111.0_c_float) > 10.0_c_float * epsilon(aa)) stop 1
+ if (abs(3.0_c_float * aa - bb) > 10.0_c_float * epsilon(aa)) stop 1
+
+
+ !$omp target data map(to:cc) map(from:dd)
+ !$omp target data map(alloc:dummy) use_device_addr(cc,dd)
+ c_cptr = c_loc(cc)
+ c_dptr = c_loc(dd)
+ cptr => cc
+ dptr => dd
+ !$omp end target data
+
+ ! check c_loc ptr once
+ call copy3_scalar(c_cptr, c_dptr)
+ !$omp target update from(dd)
+ if (abs(cc - 333.0_c_float) > 10.0_c_float * epsilon(cc)) stop 1
+ if (abs(3.0_c_float * cc - dd) > 10.0_c_float * epsilon(cc)) stop 1
+
+ ! check c_loc ptr again after target-value modification
+ cc = 3333.0_c_float
+ !$omp target update to(cc)
+ call copy3_scalar(c_cptr, c_dptr)
+ !$omp target update from(dd)
+ if (abs(cc - 3333.0_c_float) > 10.0_c_float * epsilon(cc)) stop 1
+ if (abs(3.0_c_float * cc - dd) > 10.0_c_float * epsilon(cc)) stop 1
+
+ ! check Fortran pointer after target-value modification
+ cc = 33333.0_c_float
+ !$omp target update to(cc)
+ call copy3_scalar(c_loc(cptr), c_loc(dptr))
+ !$omp target update from(dd)
+ if (abs(cc - 33333.0_c_float) > 10.0_c_float * epsilon(cc)) stop 1
+ if (abs(3.0_c_float * cc - dd) > 10.0_c_float * epsilon(cc)) stop 1
+ !$omp end target data
+
+ if (abs(cc - 33333.0_c_float) > 10.0_c_float * epsilon(dd)) stop 1
+ if (abs(3.0_c_float * cc - dd) > 10.0_c_float * epsilon(dd)) stop 1
+
+
+ !$omp target data map(to:ee) map(from:ff)
+ !$omp target data map(alloc:dummy) use_device_addr(ee,ff)
+ c_eptr = c_loc(ee)
+ c_fptr = c_loc(ff)
+ eptr => ee
+ fptr => ff
+ !$omp end target data
+
+ ! check c_loc ptr once
+ call copy3_scalar(c_eptr, c_fptr)
+ !$omp target update from(ff)
+ if (abs(ee - 555.0_c_float) > 10.0_c_float * epsilon(ee)) stop 1
+ if (abs(3.0_c_float * ee - ff) > 10.0_c_float * epsilon(ee)) stop 1
+
+ ! check c_loc ptr again after target-value modification
+ ee = 5555.0_c_float
+ !$omp target update to(ee)
+ call copy3_scalar(c_eptr, c_fptr)
+ !$omp target update from(ff)
+ if (abs(ee - 5555.0_c_float) > 10.0_c_float * epsilon(ee)) stop 1
+ if (abs(3.0_c_float * ee - ff) > 10.0_c_float * epsilon(ee)) stop 1
+
+ ! check Fortran pointer after target-value modification
+ ee = 55555.0_c_float
+ !$omp target update to(ee)
+ call copy3_scalar(c_loc(eptr), c_loc(fptr))
+ !$omp target update from(ff)
+ if (abs(ee - 55555.0_c_float) > 10.0_c_float * epsilon(ee)) stop 1
+ if (abs(3.0_c_float * ee - ff) > 10.0_c_float * epsilon(ff)) stop 1
+ !$omp end target data
+
+ if (abs(ee - 55555.0_c_float) > 10.0_c_float * epsilon(ee)) stop 1
+ if (abs(3.0_c_float * ee - ff) > 10.0_c_float * epsilon(ee)) stop 1
+
+
+ !$omp target data map(to:gg) map(from:hh)
+ !$omp target data map(alloc:dummy) use_device_addr(gg,hh)
+ c_gptr = c_loc(gg)
+ c_hptr = c_loc(hh)
+ gptr => gg
+ hptr => hh
+ !$omp end target data
+
+ ! check c_loc ptr once
+ call copy3_array(c_gptr, c_hptr, N)
+ !$omp target update from(hh)
+ if (any(abs(gg - 777.0_c_float) > 10.0_c_float * epsilon(gg))) stop 1
+ if (any(abs(3.0_c_float * gg - hh) > 10.0_c_float * epsilon(hh))) stop 1
+
+ ! check c_loc ptr again after target-value modification
+ gg = 7777.0_c_float
+ !$omp target update to(gg)
+ call copy3_array(c_gptr, c_hptr, N)
+ !$omp target update from(hh)
+ if (any(abs(gg - 7777.0_c_float) > 10.0_c_float * epsilon(gg))) stop 1
+ if (any(abs(3.0_c_float * gg - hh) > 10.0_c_float * epsilon(gg))) stop 1
+
+ ! check Fortran pointer after target-value modification
+ gg = 77777.0_c_float
+ !$omp target update to(gg)
+ call copy3_array(c_loc(gptr), c_loc(hptr), N)
+ !$omp target update from(hh)
+ if (any(abs(gg - 77777.0_c_float) > 10.0_c_float * epsilon(gg))) stop 1
+ if (any(abs(3.0_c_float * gg - hh) > 10.0_c_float * epsilon(gg))) stop 1
+ !$omp end target data
+
+ if (any(abs(gg - 77777.0_c_float) > 10.0_c_float * epsilon(gg))) stop 1
+ if (any(abs(3.0_c_float * gg - hh) > 10.0_c_float * epsilon(gg))) stop 1
+
+ deallocate(ee, ff)
+ end subroutine test_main_2
+end module tests
+
+
+program omp_device_addr
+ use tests
+ use test_dummies
+ use test_dummies_value
+ use test_dummies_opt
+ use test_dummies_opt_value
+ use test_nullptr
+ implicit none (type, external)
+
+ call test_main_1()
+ call test_main_2()
+
+ call test_dummy_call_1()
+ call test_dummy_call_2()
+
+ call test_dummy_val_call_1()
+ call test_dummy_val_call_2()
+
+ call test_dummy_opt_call_1()
+ call test_dummy_opt_call_2()
+
+ call test_dummy_opt_val_call_1()
+ call test_dummy_opt_val_call_2()
+
+ call test_nullptr_1()
+end program omp_device_addr
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/data-firstprivate-1.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/data-firstprivate-1.c
new file mode 100644
index 00000000000..8900a4e070d
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/data-firstprivate-1.c
@@ -0,0 +1,165 @@
+/* Test behavior of 'firstprivate' lexically vs. dynamically nested inside a
+ 'data' region. */
+
+#include <stdlib.h>
+
+
+#define VERIFY(x) \
+ do { \
+ if (!(x)) \
+ abort (); \
+ } while (0);
+
+
+/* This is basically and extended version of 't2' from 'firstprivate-1.c'. */
+
+int lexically_nested_val = 2;
+
+static void
+lexically_nested ()
+{
+#pragma acc data \
+ copy (lexically_nested_val)
+ {
+ VERIFY (lexically_nested_val == 2);
+
+#pragma acc parallel \
+ present (lexically_nested_val)
+ {
+ VERIFY (lexically_nested_val == 2);
+
+ /* This updates the device copy, or shared variable. */
+ lexically_nested_val = 7;
+ }
+
+#if ACC_MEM_SHARED
+ VERIFY (lexically_nested_val == 7);
+#else
+ VERIFY (lexically_nested_val == 2);
+#endif
+
+ /* This only updates the local/shared variable, but not the device
+ copy. */
+ lexically_nested_val = 5;
+
+#pragma acc parallel \
+ firstprivate (lexically_nested_val)
+ {
+#if 1 /* Current behavior. */
+ /* The 'firstprivate' copy is initialized from the device copy, or
+ shared variable. */
+# if ACC_MEM_SHARED
+ VERIFY (lexically_nested_val == 5);
+# else
+ VERIFY (lexically_nested_val == 7);
+# endif
+#else /* Expected behavior per PR92036. */
+ /* The 'firstprivate' copy is initialized from the local thread. */
+ VERIFY (lexically_nested_val == 5);
+#endif
+
+ /* This updates the 'firstprivate' copy only, but not the shared
+ variable. */
+ lexically_nested_val = 9;
+ }
+
+ VERIFY (lexically_nested_val == 5);
+ }
+ /* If not shared, the device copy has now been copied back. */
+
+#if ACC_MEM_SHARED
+ VERIFY (lexically_nested_val == 5);
+#else
+ VERIFY (lexically_nested_val == 7);
+#endif
+}
+
+
+int dynamically_nested_val = 2;
+
+/* Same as above, but compute construct 1 broken out, so no longer lexically
+ nested inside 'data' region. */
+
+static void
+dynamically_nested_compute_1 ()
+{
+#pragma acc parallel \
+ present (dynamically_nested_val)
+ {
+ VERIFY (dynamically_nested_val == 2);
+
+ /* This updates the device copy, or shared variable. */
+ dynamically_nested_val = 7;
+ }
+}
+
+/* Same as above, but compute construct 2 broken out, so no longer lexically
+ nested inside 'data' region. */
+
+static void
+dynamically_nested_compute_2 ()
+{
+#pragma acc parallel \
+ firstprivate (dynamically_nested_val)
+ {
+#if 1 /* Current behavior. */
+ /* The 'firstprivate' copy is initialized from the device copy, or shared
+ variable. */
+# if ACC_MEM_SHARED
+ VERIFY (dynamically_nested_val == 5);
+# else
+ VERIFY (dynamically_nested_val == 7);
+# endif
+#else /* Expected behavior per PR92036. */
+ /* The 'firstprivate' copy is initialized from the local thread. */
+ VERIFY (dynamically_nested_val == 5);
+#endif
+
+ /* This updates the 'firstprivate' copy only, but not the shared
+ variable. */
+ dynamically_nested_val = 9;
+ }
+}
+
+static void
+dynamically_nested ()
+{
+#pragma acc data \
+ copy (dynamically_nested_val)
+ {
+ VERIFY (dynamically_nested_val == 2);
+
+ dynamically_nested_compute_1 ();
+
+#if ACC_MEM_SHARED
+ VERIFY (dynamically_nested_val == 7);
+#else
+ VERIFY (dynamically_nested_val == 2);
+#endif
+
+ /* This only updates the local/shared variable, but not the device
+ copy. */
+ dynamically_nested_val = 5;
+
+ dynamically_nested_compute_2 ();
+
+ VERIFY (dynamically_nested_val == 5);
+ }
+ /* If not shared, the device copy has now been copied back. */
+
+#if ACC_MEM_SHARED
+ VERIFY (dynamically_nested_val == 5);
+#else
+ VERIFY (dynamically_nested_val == 7);
+#endif
+}
+
+
+int
+main()
+{
+ lexically_nested ();
+ dynamically_nested ();
+
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/fortran.exp b/libgomp/testsuite/libgomp.oacc-fortran/fortran.exp
index af25a22a522..852f372b319 100644
--- a/libgomp/testsuite/libgomp.oacc-fortran/fortran.exp
+++ b/libgomp/testsuite/libgomp.oacc-fortran/fortran.exp
@@ -56,11 +56,17 @@ if { $lang_test_file_found } {
# Allow for spec subsitution.
lappend ALWAYS_CFLAGS "additional_flags=-B${blddir}/${quadmath_library_path}/"
set ld_library_path "$always_ld_library_path:${blddir}/${lang_library_path}:${blddir}/${quadmath_library_path}"
+ append lang_link_flags " -lquadmath"
} else {
set ld_library_path "$always_ld_library_path:${blddir}/${lang_library_path}"
}
} else {
set ld_library_path "$always_ld_library_path"
+ if { [check_no_compiler_messages has_libquadmath executable {
+ int main() {return 0;}
+ } "-lgfortran -lquadmath"] } then {
+ append lang_link_flags " -lquadmath"
+ }
}
append ld_library_path [gcc-set-multilib-library-path $GCC_UNDER_TEST]
set_ld_library_path_env_vars
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index e0d3fd5f3a9..8119455e1ad 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,143 @@
+2019-10-11 Jonathan Wakely <jwakely@redhat.com>
+
+ * include/Makefile.am: Add new header.
+ * include/Makefile.in: Regenerate.
+ * include/precompiled/stdc++.h: Include <concepts>.
+ * include/std/concepts: New header for C++20.
+ * include/std/version (__cpp_lib_concepts): Define.
+ * scripts/create_testsuite_files: Look for test files in new std
+ directory.
+ * testsuite/libstdc++-dg/conformance.exp: Likewise.
+ * testsuite/std/concepts/concepts.callable/invocable.cc: New test.
+ * testsuite/std/concepts/concepts.callable/regular_invocable.cc: New
+ test.
+ * testsuite/std/concepts/concepts.callable/relation.cc: New test.
+ * testsuite/std/concepts/concepts.callable/strictweakorder.cc: New
+ test.
+ * testsuite/std/concepts/concepts.lang/concept.arithmetic/
+ floating_point.cc: New test.
+ * testsuite/std/concepts/concepts.lang/concept.arithmetic/integral.cc:
+ New test.
+ * testsuite/std/concepts/concepts.lang/concept.arithmetic/
+ signed_integral.cc: New test.
+ * testsuite/std/concepts/concepts.lang/concept.arithmetic/
+ unsigned_integral.cc: New test.
+ * testsuite/std/concepts/concepts.lang/concept.assignable/1.cc: New
+ test.
+ * testsuite/std/concepts/concepts.lang/concept.common/1.cc: New test.
+ * testsuite/std/concepts/concepts.lang/concept.commonref/1.cc: New
+ test.
+ * testsuite/std/concepts/concepts.lang/concept.constructible/1.cc:
+ New test.
+ * testsuite/std/concepts/concepts.lang/concept.convertible/1.cc:
+ New test.
+ * testsuite/std/concepts/concepts.lang/concept.copyconstructible/1.cc:
+ New test.
+ * testsuite/std/concepts/concepts.lang/concept.defaultconstructible/
+ 1.cc: New test.
+ * testsuite/std/concepts/concepts.lang/concept.derived/1.cc:
+ New test.
+ * testsuite/std/concepts/concepts.lang/concept.destructible/1.cc:
+ New test.
+ * testsuite/std/concepts/concepts.lang/concept.moveconstructible/1.cc:
+ New test.
+ * testsuite/std/concepts/concepts.lang/concept.same/1.cc:
+ New test.
+ * testsuite/std/concepts/concepts.lang/concept.swappable/swap.cc:
+ New test.
+ * testsuite/std/concepts/concepts.lang/concept.swappable/swappable.cc:
+ New test.
+ * testsuite/std/concepts/concepts.lang/concept.swappable/
+ swappable_with.cc: New test.
+ * testsuite/std/concepts/concepts.object/copyable.cc: New test.
+ * testsuite/std/concepts/concepts.object/movable.cc: New test.
+ * testsuite/std/concepts/concepts.object/regular.cc: New test.
+ * testsuite/std/concepts/concepts.object/semiregular.cc: New test.
+
+ * include/std/type_traits (is_same): Replace partial specialization
+ by using __is_same_as built-in in primary template.
+ (is_same_v): Use __is_same_as built-in instead of instantiating the
+ is_same trait.
+
+ PR libstdc++/92059
+ * include/tr2/dynamic_bitset (__dynamic_bitset_base): Define all
+ special member functions as defaulted. Add noexcept to most members.
+ (__dynamic_bitset_base(size_t, unsigned long long, const _Alloc&)):
+ Mask off unwanted bits in the __val parameter. Avoid undefined left
+ shifts.
+ (__dynamic_bitset_base::_M_assign): Remove.
+ (__dynamic_bitset_base::_M_do_reset): Use std::fill.
+ (__dynamic_bitset_base::_M_are_all_aux): Avoid integer promotion when
+ block_type has lower rank than int.
+ (dynamic_bitset): Add noexcept to most members. Use injected-class-name
+ in return types and parameter types.
+ (dynamic_bitset::_M_Nb): Add default member initializer.
+ (dynamic_bitset(), dynamic_bitset(const dynamic_bitset&)): Define as
+ defaulted.
+ (dynamic_bitset(dynamic_bitset&&)): Clear source object after move.
+ (dynamic_bitset::operator=(const dynamic_bitset&)): Define as
+ defaulted.
+ (dynamic_bitset::operator=(dynamic_bitset&&)): Add noexcept-specifier.
+ Define without using swap, to propagate allocator correctly.
+ (dynamic_bitset(const char*, const _Alloc&)): Use strlen.
+ (dynamic_bitset::_M_do_sanitize, dynamic_bitset::_M_do_fill): Use
+ casts to avoid unwanted integer promotions.
+ (dynamic_bitset::_M_copy_from_ptr): Rearrange template parameters and
+ add default template arguments and default argument to simplify usage.
+ (dynamic_bitset::_M_copy_from_string): Adjust call to _M_copy_from_ptr.
+ (operator==(const dynamic_bitset&, const dynamic_bitset&))
+ (operator<(const dynamic_bitset&, const dynamic_bitset&)): Use _M_Nb.
+ * include/tr2/dynamic_bitset.tcc (dynamic_bitset::_M_copy_from_ptr):
+ Adjust template parameters to match declaration.
+ * testsuite/tr2/dynamic_bitset/cmp.cc: New test.
+ * testsuite/tr2/dynamic_bitset/cons.cc: New test.
+ * testsuite/tr2/dynamic_bitset/copy.cc: New test.
+ * testsuite/tr2/dynamic_bitset/move.cc: New test.
+ * testsuite/tr2/dynamic_bitset/pr92059.cc: New test.
+
+ * include/bits/charconv.h (__to_chars_len): Avoid -Wsign-compare
+ warnings.
+
+2019-10-10 Jonathan Wakely <jwakely@redhat.com>
+
+ PR libstdc++/91057
+ * src/c++98/locale.cc [_GLIBCXX_LONG_DOUBLE_COMPAT]
+ (find_ldbl_sync_facet): Fix parameter type and missing return.
+
+2019-10-09 Marek Polacek <polacek@redhat.com>
+
+ PR c++/91364 - P0388R4: Permit conversions to arrays of unknown bound.
+ PR c++/69531 - DR 1307: Differently bounded array parameters.
+ PR c++/88128 - DR 330: Qual convs and pointers to arrays of pointers.
+ * testsuite/23_containers/span/lwg3255.cc: Adjust test to match the
+ post-P0388R4 behavior.
+
+2019-10-09 Jonathan Wakely <jwakely@redhat.com>
+
+ PR libstdc++/91057
+ * src/c++98/locale.cc (locale::id::_M_id()) [__GTHREADS]: Use atomic
+ compare-exchange or double-checked lock to ensure only one thread sets
+ the _M_index variable.
+ [_GLIBCXX_LONG_DOUBLE_COMPAT]: Call find_ldbl_sync_facet to detect
+ facets that share another facet's ID.
+ [_GLIBCXX_LONG_DOUBLE_COMPAT] (find_ldbl_sync_facet): New function.
+
+ PR libstdc++/78552
+ * src/c++98/locale_init.cc (locale::classic()): Do not construct a new
+ locale object for every call.
+ (locale::_S_initialize_once()): Construct C locale here.
+
+2019-10-08 Jonathan Wakely <jwakely@redhat.com>
+
+ * doc/Makefile.am (doc-html-docbook-regenerate): New target.
+ (${docbook_outdir}/html): Do not create unused 'html/ext' directory.
+ * doc/Makefile.in: Regenerate.
+ * doc/xml/manual/documentation_hacking.xml: Document new target.
+ * doc/html/*: Regenerate.
+
+ * doc/xml/manual/allocator.xml: Use archived copy of CUJ article.
+ * doc/html/*: Regenerate.
+
2019-10-06 François Dumont <fdumont@gcc.gnu.org>
* include/bits/stl_algo.h
diff --git a/libstdc++-v3/doc/Makefile.am b/libstdc++-v3/doc/Makefile.am
index b9aca381b74..9b385edecff 100644
--- a/libstdc++-v3/doc/Makefile.am
+++ b/libstdc++-v3/doc/Makefile.am
@@ -476,7 +476,6 @@ ${docbook_outdir}/fo:
${docbook_outdir}/html:
mkdir -p ${docbook_outdir}/html
- mkdir -p ${docbook_outdir}/html/ext
mkdir -p ${docbook_outdir}/html/images
mkdir -p ${docbook_outdir}/html/manual
@@ -545,6 +544,12 @@ stamp-html-docbook: $(xml_sources) ${docbook_outdir}/html
doc-html-docbook: stamp-html-docbook-data
+# Generate the HTML pages and copy them back to the source tree.
+doc-html-docbook-regenerate: doc-html-docbook
+ $(INSTALL_DATA) ${docbook_outdir}/html/*.html ${top_srcdir}/doc/html
+ $(INSTALL_DATA) ${docbook_outdir}/html/images/* ${top_srcdir}/doc/html/images
+ $(INSTALL_DATA) ${docbook_outdir}/html/manual/*.html ${top_srcdir}/doc/html/manual
+
# HTML, all one page
# NB: Have to generate customization XSL for UTF-8 output.
manual_html = ${docbook_outdir}/html/libstdc++-manual-single.html
diff --git a/libstdc++-v3/doc/Makefile.in b/libstdc++-v3/doc/Makefile.in
index 5fee1b2d310..6114bff62f6 100644
--- a/libstdc++-v3/doc/Makefile.in
+++ b/libstdc++-v3/doc/Makefile.in
@@ -977,7 +977,6 @@ ${docbook_outdir}/fo:
${docbook_outdir}/html:
mkdir -p ${docbook_outdir}/html
- mkdir -p ${docbook_outdir}/html/ext
mkdir -p ${docbook_outdir}/html/images
mkdir -p ${docbook_outdir}/html/manual
@@ -1029,6 +1028,12 @@ stamp-html-docbook: $(xml_sources) ${docbook_outdir}/html
$(STAMP) stamp-html-docbook
doc-html-docbook: stamp-html-docbook-data
+
+# Generate the HTML pages and copy them back to the source tree.
+doc-html-docbook-regenerate: doc-html-docbook
+ $(INSTALL_DATA) ${docbook_outdir}/html/*.html ${top_srcdir}/doc/html
+ $(INSTALL_DATA) ${docbook_outdir}/html/images/* ${top_srcdir}/doc/html/images
+ $(INSTALL_DATA) ${docbook_outdir}/html/manual/*.html ${top_srcdir}/doc/html/manual
stamp-html-single-docbook: $(xml_sources) ${docbook_outdir}/html
@echo "Generating html single file..."
$(XSLTPROC) $(XSLT_PARAM) $(XSLT_FLAGS) -o ${manual_html} \
diff --git a/libstdc++-v3/doc/html/manual/documentation_hacking.html b/libstdc++-v3/doc/html/manual/documentation_hacking.html
index 6b4592c24a2..0de98a5ff94 100644
--- a/libstdc++-v3/doc/html/manual/documentation_hacking.html
+++ b/libstdc++-v3/doc/html/manual/documentation_hacking.html
@@ -381,11 +381,16 @@
</p><p>
</p><pre class="screen"><strong class="userinput"><code>make doc-xml-single-docbook</code></strong></pre><p>
</p><p>
- Generated files are output into separate sub directores of
+ Generated files are output into separate sub-directores of
<code class="filename">doc/docbook/</code> in the
build directory, based on the output format. For instance, the
HTML docs will be in <code class="filename">doc/docbook/html</code>.
</p><p>
+ The </p><pre class="screen">doc-html-docbook-regenerate</pre><p> target will generate
+ the HTML files and copy them back to the libstdc++ source tree.
+ This can be used to update the HTML files that are checked in to
+ version control.
+ </p><p>
If the Docbook stylesheets are installed in a custom location,
one can use the variable <code class="literal">XSL_STYLE_DIR</code> to
override the Makefile defaults. For example:
diff --git a/libstdc++-v3/doc/html/manual/memory.html b/libstdc++-v3/doc/html/manual/memory.html
index 54d95c805cc..5b28a5a9763 100644
--- a/libstdc++-v3/doc/html/manual/memory.html
+++ b/libstdc++-v3/doc/html/manual/memory.html
@@ -301,7 +301,9 @@
</em>. </span>
isoc++_1998
<span class="pagenums">20.4 Memory. </span></p></div><div class="biblioentry"><a id="id-1.3.4.4.4.3.9.3"></a><p><span class="title"><em>
+ <a class="link" href="https://web.archive.org/web/20190622154249/http://www.drdobbs.com/the-standard-librarian-what-are-allocato/184403759" target="_top">
The Standard Librarian: What Are Allocators Good For?
+ </a>
</em>. </span><span class="author"><span class="firstname">Matt</span> <span class="surname">Austern</span>. </span><span class="publisher"><span class="publishername">
C/C++ Users Journal
. </span></span><span class="pubdate">2000-12. </span></p></div><div class="biblioentry"><a id="id-1.3.4.4.4.3.9.4"></a><p><span class="title"><em>
diff --git a/libstdc++-v3/doc/xml/manual/allocator.xml b/libstdc++-v3/doc/xml/manual/allocator.xml
index 922bc49091c..d8a255ca213 100644
--- a/libstdc++-v3/doc/xml/manual/allocator.xml
+++ b/libstdc++-v3/doc/xml/manual/allocator.xml
@@ -483,7 +483,10 @@
<biblioentry>
<title>
+ <link xmlns:xlink="http://www.w3.org/1999/xlink"
+ xlink:href="https://web.archive.org/web/20190622154249/http://www.drdobbs.com/the-standard-librarian-what-are-allocato/184403759">
The Standard Librarian: What Are Allocators Good For?
+ </link>
</title>
<author><personname><firstname>Matt</firstname><surname>Austern</surname></personname></author>
diff --git a/libstdc++-v3/doc/xml/manual/documentation_hacking.xml b/libstdc++-v3/doc/xml/manual/documentation_hacking.xml
index e0990a28516..7db776794c2 100644
--- a/libstdc++-v3/doc/xml/manual/documentation_hacking.xml
+++ b/libstdc++-v3/doc/xml/manual/documentation_hacking.xml
@@ -807,7 +807,7 @@
</para>
<para>
- Generated files are output into separate sub directores of
+ Generated files are output into separate sub-directores of
<filename class="directory">doc/docbook/</filename> in the
build directory, based on the output format. For instance, the
HTML docs will be in <filename
@@ -815,6 +815,13 @@
</para>
<para>
+ The <screen>doc-html-docbook-regenerate</screen> target will generate
+ the HTML files and copy them back to the libstdc++ source tree.
+ This can be used to update the HTML files that are checked in to
+ version control.
+ </para>
+
+ <para>
If the Docbook stylesheets are installed in a custom location,
one can use the variable <literal>XSL_STYLE_DIR</literal> to
override the Makefile defaults. For example:
diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index 060a4679eeb..2d497af1d52 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -36,6 +36,7 @@ std_headers = \
${std_srcdir}/chrono \
${std_srcdir}/codecvt \
${std_srcdir}/complex \
+ ${std_srcdir}/concepts \
${std_srcdir}/condition_variable \
${std_srcdir}/deque \
${std_srcdir}/execution \
@@ -1380,8 +1381,8 @@ endif
# This is a subset of the full install-headers rule. We only need <ciso646>,
# <cstddef>, <cfloat>, <limits>, <climits>, <version>, <cstdint>, <cstdlib>,
# <new>, <typeinfo>, <exception>, <initializer_list>, <cstdalign>, <cstdarg>,
-# <cstdbool>, <type_traits>, <bit>, <atomic>, and any files which they include
-# (and which we provide).
+# <concepts>, <cstdbool>, <type_traits>, <bit>, <atomic>,
+# and any files which they include (and which we provide).
# <new>, <typeinfo>, <exception>, and <initializer_list> are installed by
# libsupc++, so only the others and the sub-includes are copied here.
install-freestanding-headers:
@@ -1394,7 +1395,7 @@ install-freestanding-headers:
${glibcxx_srcdir}/$(CPU_DEFINES_SRCDIR)/cpu_defines.h; do \
$(INSTALL_DATA) $${file} $(DESTDIR)${host_installdir}; done
$(mkinstalldirs) $(DESTDIR)${gxx_include_dir}/${std_builddir}
- for file in limits type_traits atomic bit version; do \
+ for file in limits type_traits atomic bit concepts version; do \
$(INSTALL_DATA) ${std_builddir}/$${file} $(DESTDIR)${gxx_include_dir}/${std_builddir}; done
$(mkinstalldirs) $(DESTDIR)${gxx_include_dir}/${c_base_builddir}
for file in ciso646 cstddef cfloat climits cstdint cstdlib \
diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
index 9071a0a8bbb..11d49973dd6 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -380,6 +380,7 @@ std_headers = \
${std_srcdir}/chrono \
${std_srcdir}/codecvt \
${std_srcdir}/complex \
+ ${std_srcdir}/concepts \
${std_srcdir}/condition_variable \
${std_srcdir}/deque \
${std_srcdir}/execution \
@@ -1854,8 +1855,8 @@ ${pch3_output}: ${pch3_source} ${pch2_output}
# This is a subset of the full install-headers rule. We only need <ciso646>,
# <cstddef>, <cfloat>, <limits>, <climits>, <version>, <cstdint>, <cstdlib>,
# <new>, <typeinfo>, <exception>, <initializer_list>, <cstdalign>, <cstdarg>,
-# <cstdbool>, <type_traits>, <bit>, <atomic>, and any files which they include
-# (and which we provide).
+# <concepts>, <cstdbool>, <type_traits>, <bit>, <atomic>,
+# and any files which they include (and which we provide).
# <new>, <typeinfo>, <exception>, and <initializer_list> are installed by
# libsupc++, so only the others and the sub-includes are copied here.
install-freestanding-headers:
@@ -1868,7 +1869,7 @@ install-freestanding-headers:
${glibcxx_srcdir}/$(CPU_DEFINES_SRCDIR)/cpu_defines.h; do \
$(INSTALL_DATA) $${file} $(DESTDIR)${host_installdir}; done
$(mkinstalldirs) $(DESTDIR)${gxx_include_dir}/${std_builddir}
- for file in limits type_traits atomic bit version; do \
+ for file in limits type_traits atomic bit concepts version; do \
$(INSTALL_DATA) ${std_builddir}/$${file} $(DESTDIR)${gxx_include_dir}/${std_builddir}; done
$(mkinstalldirs) $(DESTDIR)${gxx_include_dir}/${c_base_builddir}
for file in ciso646 cstddef cfloat climits cstdint cstdlib \
diff --git a/libstdc++-v3/include/bits/charconv.h b/libstdc++-v3/include/bits/charconv.h
index a5b6be567bc..7c0922fec21 100644
--- a/libstdc++-v3/include/bits/charconv.h
+++ b/libstdc++-v3/include/bits/charconv.h
@@ -50,16 +50,16 @@ namespace __detail
static_assert(is_unsigned<_Tp>::value, "implementation bug");
unsigned __n = 1;
- const int __b2 = __base * __base;
- const int __b3 = __b2 * __base;
- const int __b4 = __b3 * __base;
+ const unsigned __b2 = __base * __base;
+ const unsigned __b3 = __b2 * __base;
+ const unsigned long __b4 = __b3 * __base;
for (;;)
{
- if (__value < __base) return __n;
+ if (__value < (unsigned)__base) return __n;
if (__value < __b2) return __n + 1;
if (__value < __b3) return __n + 2;
if (__value < __b4) return __n + 3;
- __value /= (unsigned)__b4;
+ __value /= __b4;
__n += 4;
}
}
diff --git a/libstdc++-v3/include/precompiled/stdc++.h b/libstdc++-v3/include/precompiled/stdc++.h
index 4b668fddc03..fefd6e76845 100644
--- a/libstdc++-v3/include/precompiled/stdc++.h
+++ b/libstdc++-v3/include/precompiled/stdc++.h
@@ -136,7 +136,7 @@
#if __cplusplus > 201703L
#include <bit>
// #include <compare>
-// #include <concepts>
+#include <concepts>
#include <numbers>
// #include <ranges>
#include <span>
diff --git a/libstdc++-v3/include/std/concepts b/libstdc++-v3/include/std/concepts
new file mode 100644
index 00000000000..6b1150a32d2
--- /dev/null
+++ b/libstdc++-v3/include/std/concepts
@@ -0,0 +1,351 @@
+// <concepts> -*- C++ -*-
+
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received __a copy of the GNU General Public License and
+// __a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/concepts
+ * This is __a Standard C++ Library header.
+ * @ingroup concepts
+ */
+
+#ifndef _GLIBCXX_CONCEPTS
+#define _GLIBCXX_CONCEPTS 1
+
+#if __cplusplus > 201703L && __cpp_concepts
+
+#pragma GCC system_header
+
+/**
+ * @defgroup concepts Concepts
+ * @ingroup utilities
+ *
+ * Concepts for checking type requirements.
+ */
+
+#include <type_traits>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+#define __cpp_lib_concepts 201806L
+
+ // [concepts.lang], language-related concepts
+
+ namespace __detail
+ {
+ template<typename _Tp, typename _Up>
+ concept __same_as = __is_same_as(_Tp, _Up);
+ } // namespace __detail
+
+ /// [concept.same], concept same_as
+ template<typename _Tp, typename _Up>
+ concept same_as
+ = __detail::__same_as<_Tp, _Up> && __detail::__same_as<_Up, _Tp>;
+
+ /// [concept.derived], concept derived_from
+ template<typename _Derived, typename _Base>
+ concept derived_from = __is_base_of(_Base, _Derived)
+ && is_convertible_v<const volatile _Derived*, const volatile _Base*>;
+
+ /// [concept.convertible], concept convertible_to
+ template<typename _From, typename _To>
+ concept convertible_to = is_convertible_v<_From, _To>
+ && requires(add_rvalue_reference_t<_From> (&__f)()) {
+ static_cast<_To>(__f());
+ };
+
+ /// [concept.commonref], concept common_reference_with
+ template<typename _Tp, typename _Up>
+ concept common_reference_with
+ = same_as<common_reference_t<_Tp, _Up>, common_reference_t<_Up, _Tp>>
+ && convertible_to<_Tp, common_reference_t<_Tp, _Up>>
+ && convertible_to<_Up, common_reference_t<_Tp, _Up>>;
+
+ /// [concept.common], concept common_with
+ template<typename _Tp, typename _Up>
+ concept common_with
+ = same_as<common_type_t<_Tp, _Up>, common_type_t<_Up, _Tp>>
+ && requires {
+ static_cast<common_type_t<_Tp, _Up>>(std::declval<_Tp>());
+ static_cast<common_type_t<_Tp, _Up>>(std::declval<_Up>());
+ }
+ && common_reference_with<add_lvalue_reference_t<const _Tp>,
+ add_lvalue_reference_t<const _Up>>
+ && common_reference_with<add_lvalue_reference_t<common_type_t<_Tp, _Up>>,
+ common_reference_t<
+ add_lvalue_reference_t<const _Tp>,
+ add_lvalue_reference_t<const _Up>>>;
+
+ // [concepts.arithmetic], arithmetic concepts
+
+ template<typename _Tp>
+ concept integral = is_integral_v<_Tp>;
+
+ template<typename _Tp>
+ concept signed_integral = integral<_Tp> && is_signed_v<_Tp>;
+
+ template<typename _Tp>
+ concept unsigned_integral = integral<_Tp> && !signed_integral<_Tp>;
+
+ template<typename _Tp>
+ concept floating_point = is_floating_point_v<_Tp>;
+
+ namespace __detail
+ {
+ template<typename _Tp>
+ using __cref = const remove_reference_t<_Tp>&;
+ } // namespace __detail
+
+ /// [concept.assignable], concept assignable_from
+ template<typename _Lhs, typename _Rhs>
+ concept assignable_from
+ = is_lvalue_reference_v<_Lhs>
+ && common_reference_with<__detail::__cref<_Lhs>, __detail::__cref<_Rhs>>
+ && requires(_Lhs __lhs, _Rhs&& __rhs) {
+ { __lhs = static_cast<_Rhs&&>(__rhs) } -> same_as<_Lhs>;
+ };
+
+ /// [concept.destructible], concept destructible
+ template<typename _Tp>
+ concept destructible = is_nothrow_destructible_v<_Tp>;
+
+ /// [concept.constructible], concept constructible_from
+ template<typename _Tp, typename... _Args>
+ concept constructible_from
+ = destructible<_Tp> && is_constructible_v<_Tp, _Args...>;
+
+ /// [concept.defaultconstructible], concept default_constructible
+ template<typename _Tp>
+ concept default_constructible = constructible_from<_Tp>;
+
+ /// [concept.moveconstructible], concept move_constructible
+ template<typename _Tp>
+ concept move_constructible
+ = constructible_from<_Tp, _Tp> && convertible_to<_Tp, _Tp>;
+
+ /// [concept.copyconstructible], concept copy_constructible
+ template<typename _Tp>
+ concept copy_constructible
+ = move_constructible<_Tp>
+ && constructible_from<_Tp, _Tp&> && convertible_to<_Tp&, _Tp>
+ && constructible_from<_Tp, const _Tp&> && convertible_to<const _Tp&, _Tp>
+ && constructible_from<_Tp, const _Tp> && convertible_to<const _Tp, _Tp>;
+
+ // [concept.swappable], concept swappable
+
+ namespace ranges
+ {
+ namespace __cust_swap
+ {
+ template<typename _Tp> void swap(_Tp&, _Tp&) = delete;
+
+ template<typename _Tp>
+ concept __class_or_enum
+ = is_class_v<_Tp> || is_union_v<_Tp> || is_enum_v<_Tp>;
+
+ template<typename _Tp, typename _Up>
+ concept __adl_swap
+ = (__class_or_enum<remove_cvref_t<_Tp>>
+ || __class_or_enum<remove_cvref_t<_Up>>)
+ && requires(_Tp&& __t, _Up&& __u) {
+ swap(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u));
+ };
+
+ struct _Swap
+ {
+ template<typename _Tp, typename _Up>
+ requires __adl_swap<_Tp, _Up>
+ constexpr void operator()(_Tp&& __t, _Up&& __u) const
+ noexcept(noexcept(swap(std::declval<_Tp>(), std::declval<_Up>())))
+ { swap(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u)); }
+
+ template<typename _Tp, typename _Up, size_t _Num>
+ requires requires(const _Swap& __swap, _Tp& __e1, _Up& __e2) {
+ __swap(__e1, __e2);
+ }
+ constexpr void
+ operator()(_Tp (&__e1)[_Num], _Up (&__e2)[_Num]) const
+ noexcept(noexcept(std::declval<const _Swap&>()(*__e1, *__e2)))
+ {
+ for (size_t __n = 0; __n < _Num; ++__n)
+ (*this)(__e1[__n], __e2[__n]);
+ }
+
+ template<typename _Tp>
+ requires (!__adl_swap<_Tp&, _Tp&>
+ && move_constructible<_Tp> && assignable_from<_Tp&, _Tp>)
+ constexpr void
+ operator()(_Tp& __e1, _Tp& __e2) const
+ noexcept(is_nothrow_move_constructible_v<_Tp>
+ && is_nothrow_move_assignable_v<_Tp>)
+ {
+ _Tp __tmp = static_cast<_Tp&&>(__e1);
+ __e1 = static_cast<_Tp&&>(__e2);
+ __e2 = static_cast<_Tp&&>(__tmp);
+ }
+ };
+ } // namespace __cust_swap
+
+ inline namespace __cust
+ {
+ inline constexpr __cust_swap::_Swap swap{};
+ } // inline namespace __cust
+ } // namespace ranges
+
+ template<typename _Tp>
+ concept swappable
+ = requires(_Tp& __a, _Tp& __b) { ranges::swap(__a, __b); };
+
+ template<typename _Tp, typename _Up>
+ concept swappable_with = common_reference_with<_Tp, _Up>
+ && requires(_Tp&& __t, _Up&& __u) {
+ ranges::swap(static_cast<_Tp&&>(__t), static_cast<_Tp&&>(__t));
+ ranges::swap(static_cast<_Up&&>(__u), static_cast<_Up&&>(__u));
+ ranges::swap(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u));
+ ranges::swap(static_cast<_Up&&>(__u), static_cast<_Tp&&>(__t));
+ };
+
+ // [concepts.object], Object concepts
+
+ template<typename _Tp>
+ concept movable = is_object_v<_Tp> && move_constructible<_Tp>
+ && assignable_from<_Tp&, _Tp> && swappable<_Tp>;
+
+ template<typename _Tp>
+ concept copyable = copy_constructible<_Tp> && movable<_Tp>
+ && assignable_from<_Tp&, const _Tp&>;
+
+ template<typename _Tp>
+ concept semiregular = copyable<_Tp> && default_constructible<_Tp>;
+
+ // [concepts.compare], comparison concepts
+
+ /// [concept.boolean], concept boolean
+ template<typename _Bp>
+ concept boolean
+ = movable<remove_cvref_t<_Bp>>
+ && requires(__detail::__cref<_Bp> __b1, __detail::__cref<_Bp> __b2,
+ const bool __a) {
+ { __b1 } -> convertible_to<bool>;
+ { !__b1 } -> convertible_to<bool>;
+ { __b1 && __b2 } -> same_as<bool>;
+ { __b1 && __a } -> same_as<bool>;
+ { __a && __b2 } -> same_as<bool>;
+ { __b1 || __b2 } -> same_as<bool>;
+ { __b1 || __a } -> same_as<bool>;
+ { __a || __b2 } -> same_as<bool>;
+ { __b1 == __b2 } -> convertible_to<bool>;
+ { __b1 == __a } -> convertible_to<bool>;
+ { __a == __b2 } -> convertible_to<bool>;
+ { __b1 != __b2 } -> convertible_to<bool>;
+ { __b1 != __a } -> convertible_to<bool>;
+ { __a != __b2 } -> convertible_to<bool>;
+ };
+
+ // [concept.equalitycomparable], concept equality_comparable
+
+ namespace __detail
+ {
+ template<typename _Tp, typename _Up>
+ concept __weakly_eq_cmp_with
+ = requires(__detail::__cref<_Tp> __t, __detail::__cref<_Up> __u) {
+ { __t == __u } -> boolean;
+ { __t != __u } -> boolean;
+ { __u == __t } -> boolean;
+ { __u != __t } -> boolean;
+ };
+ } // namespace __detail
+
+ template<typename _Tp>
+ concept equality_comparable = __detail::__weakly_eq_cmp_with<_Tp, _Tp>;
+
+ template<typename _Tp, typename _Up>
+ concept equality_comparable_with
+ = equality_comparable<_Tp> && equality_comparable<_Up>
+ && common_reference_with<__detail::__cref<_Tp>, __detail::__cref<_Up>>
+ && equality_comparable<common_reference_t<__detail::__cref<_Tp>,
+ __detail::__cref<_Up>>>
+ && __detail::__weakly_eq_cmp_with<_Tp, _Up>;
+
+ // [concept.totallyordered], concept totally_ordered
+ template<typename _Tp>
+ concept totally_ordered
+ = equality_comparable<_Tp>
+ && requires(__detail::__cref<_Tp> __a, __detail::__cref<_Tp> __b) {
+ { __a < __b } -> boolean;
+ { __a > __b } -> boolean;
+ { __a <= __b } -> boolean;
+ { __a >= __b } -> boolean;
+ };
+
+ template<typename _Tp, typename _Up>
+ concept totally_ordered_with
+ = totally_ordered<_Tp> && totally_ordered<_Up>
+ && common_reference_with<__detail::__cref<_Tp>, __detail::__cref<_Up>>
+ && totally_ordered<common_reference_t<__detail::__cref<_Tp>,
+ __detail::__cref<_Up>>>
+ && equality_comparable_with<_Tp, _Up>
+ && requires(__detail::__cref<_Tp> __t, __detail::__cref<_Up> __u) {
+ { __t < __u } -> boolean;
+ { __t > __u } -> boolean;
+ { __t <= __u } -> boolean;
+ { __t >= __u } -> boolean;
+ { __u < __t } -> boolean;
+ { __u > __t } -> boolean;
+ { __u <= __t } -> boolean;
+ { __u >= __t } -> boolean;
+ };
+
+ template<typename _Tp>
+ concept regular = semiregular<_Tp> && equality_comparable<_Tp>;
+
+ // [concepts.callable], callable concepts
+
+ // [concept.invocable], concept invocable
+ template<typename _Fn, typename... _Args>
+ concept invocable = is_invocable_v<_Fn, _Args...>;
+
+ // [concept.regularinvocable], concept regular_invocable
+ template<typename _Fn, typename... _Args>
+ concept regular_invocable = invocable<_Fn, _Args...>;
+
+ // [concept.predicate], concept predicate
+ template<typename _Fn, typename... _Args>
+ concept predicate = regular_invocable<_Fn, _Args...>
+ && boolean<invoke_result_t<_Fn, _Args...>>;
+
+ // [concept.relation], concept relation
+ template<typename _Rel, typename _Tp, typename _Up>
+ concept relation
+ = predicate<_Rel, _Tp, _Tp> && predicate<_Rel, _Up, _Up>
+ && predicate<_Rel, _Tp, _Up> && predicate<_Rel, _Up, _Tp>;
+
+ // [concept.strictweakorder], concept strict_weak_order
+ template<typename _Rel, typename _Tp, typename _Up>
+ concept strict_weak_order = relation<_Rel, _Tp, _Up>;
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace
+#endif // C++2a
+
+#endif /* _GLIBCXX_CONCEPTS */
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index dc8a019324d..4de5daa9f06 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -1388,13 +1388,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Type relations.
/// is_same
- template<typename, typename>
+ template<typename _Tp, typename _Up>
struct is_same
- : public false_type { };
-
- template<typename _Tp>
- struct is_same<_Tp, _Tp>
- : public true_type { };
+ : public integral_constant<bool, __is_same_as(_Tp, _Up)>
+ { };
/// is_base_of
template<typename _Base, typename _Derived>
@@ -3158,7 +3155,7 @@ template <typename _Tp>
template <typename _Tp, unsigned _Idx = 0>
inline constexpr size_t extent_v = extent<_Tp, _Idx>::value;
template <typename _Tp, typename _Up>
- inline constexpr bool is_same_v = is_same<_Tp, _Up>::value;
+ inline constexpr bool is_same_v = __is_same_as(_Tp, _Up);
template <typename _Base, typename _Derived>
inline constexpr bool is_base_of_v = is_base_of<_Base, _Derived>::value;
template <typename _From, typename _To>
diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version
index f758bcd4301..21cc28b3450 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -153,6 +153,9 @@
#define __cpp_lib_atomic_ref 201806L
#define __cpp_lib_bind_front 201907L
#define __cpp_lib_bounded_array_traits 201902L
+#if __cpp_concepts
+# define __cpp_lib_concepts 201806L
+#endif
#define __cpp_lib_constexpr 201711L
#define __cpp_lib_constexpr_algorithms 201806L
#if __cpp_impl_destroying_delete
diff --git a/libstdc++-v3/include/tr2/dynamic_bitset b/libstdc++-v3/include/tr2/dynamic_bitset
index 434a4cc87ec..28c877c0484 100644
--- a/libstdc++-v3/include/tr2/dynamic_bitset
+++ b/libstdc++-v3/include/tr2/dynamic_bitset
@@ -34,10 +34,9 @@
#include <limits>
#include <vector>
#include <string>
-#include <memory> // For std::allocator
-#include <bits/functexcept.h> // For invalid_argument, out_of_range,
- // overflow_error
-#include <iosfwd>
+#include <istream>
+#include <bits/functexcept.h>
+#include <bits/stl_algo.h> // For fill
#include <bits/cxxabi_forced.h>
namespace std _GLIBCXX_VISIBILITY(default)
@@ -76,41 +75,48 @@ namespace tr2
std::vector<block_type, allocator_type> _M_w;
explicit
- __dynamic_bitset_base(const allocator_type& __alloc = allocator_type())
+ __dynamic_bitset_base(const allocator_type& __alloc)
: _M_w(__alloc)
{ }
- explicit
- __dynamic_bitset_base(__dynamic_bitset_base&& __b)
- { this->_M_w.swap(__b._M_w); }
+ __dynamic_bitset_base() = default;
+ __dynamic_bitset_base(const __dynamic_bitset_base&) = default;
+ __dynamic_bitset_base(__dynamic_bitset_base&& __b) = default;
+ __dynamic_bitset_base& operator=(const __dynamic_bitset_base&) = default;
+ __dynamic_bitset_base& operator=(__dynamic_bitset_base&&) = default;
+ ~__dynamic_bitset_base() = default;
explicit
__dynamic_bitset_base(size_type __nbits, unsigned long long __val = 0ULL,
const allocator_type& __alloc = allocator_type())
- : _M_w(__nbits / _S_bits_per_block
- + (__nbits % _S_bits_per_block > 0),
- __val, __alloc)
+ : _M_w(__nbits / _S_bits_per_block + (__nbits % _S_bits_per_block > 0),
+ block_type(0), __alloc)
{
- unsigned long long __mask = ~static_cast<block_type>(0);
- size_t __n = std::min(this->_M_w.size(),
- sizeof(unsigned long long) / sizeof(block_type));
- for (size_t __i = 0; __i < __n; ++__i)
+ if (__nbits < std::numeric_limits<decltype(__val)>::digits)
+ __val &= ~(-1ULL << __nbits);
+ if (__val == 0)
+ return;
+
+ if _GLIBCXX17_CONSTEXPR (sizeof(__val) == sizeof(block_type))
+ _M_w[0] = __val;
+ else
{
- this->_M_w[__i] = (__val & __mask) >> (__i * _S_bits_per_block);
- __mask <<= _S_bits_per_block;
+ const size_t __n
+ = std::min(_M_w.size(), sizeof(__val) / sizeof(block_type));
+ for (size_t __i = 0; __val && __i < __n; ++__i)
+ {
+ _M_w[__i] = static_cast<block_type>(__val);
+ __val >>= _S_bits_per_block;
+ }
}
}
void
- _M_assign(const __dynamic_bitset_base& __b)
- { this->_M_w = __b._M_w; }
-
- void
- _M_swap(__dynamic_bitset_base& __b)
+ _M_swap(__dynamic_bitset_base& __b) noexcept
{ this->_M_w.swap(__b._M_w); }
void
- _M_clear()
+ _M_clear() noexcept
{ this->_M_w.clear(); }
void
@@ -129,7 +135,7 @@ namespace tr2
}
allocator_type
- _M_get_allocator() const
+ _M_get_allocator() const noexcept
{ return this->_M_w.get_allocator(); }
static size_type
@@ -149,23 +155,23 @@ namespace tr2
{ return (static_cast<block_type>(1)) << _S_whichbit(__pos); }
block_type&
- _M_getword(size_type __pos)
+ _M_getword(size_type __pos) noexcept
{ return this->_M_w[_S_whichword(__pos)]; }
block_type
- _M_getword(size_type __pos) const
+ _M_getword(size_type __pos) const noexcept
{ return this->_M_w[_S_whichword(__pos)]; }
block_type&
- _M_hiword()
+ _M_hiword() noexcept
{ return this->_M_w[_M_w.size() - 1]; }
block_type
- _M_hiword() const
+ _M_hiword() const noexcept
{ return this->_M_w[_M_w.size() - 1]; }
void
- _M_do_and(const __dynamic_bitset_base& __x)
+ _M_do_and(const __dynamic_bitset_base& __x) noexcept
{
if (__x._M_w.size() == this->_M_w.size())
for (size_t __i = 0; __i < this->_M_w.size(); ++__i)
@@ -175,7 +181,7 @@ namespace tr2
}
void
- _M_do_or(const __dynamic_bitset_base& __x)
+ _M_do_or(const __dynamic_bitset_base& __x) noexcept
{
if (__x._M_w.size() == this->_M_w.size())
for (size_t __i = 0; __i < this->_M_w.size(); ++__i)
@@ -185,7 +191,7 @@ namespace tr2
}
void
- _M_do_xor(const __dynamic_bitset_base& __x)
+ _M_do_xor(const __dynamic_bitset_base& __x) noexcept
{
if (__x._M_w.size() == this->_M_w.size())
for (size_t __i = 0; __i < this->_M_w.size(); ++__i)
@@ -195,7 +201,7 @@ namespace tr2
}
void
- _M_do_dif(const __dynamic_bitset_base& __x)
+ _M_do_dif(const __dynamic_bitset_base& __x) noexcept
{
if (__x._M_w.size() == this->_M_w.size())
for (size_t __i = 0; __i < this->_M_w.size(); ++__i)
@@ -211,28 +217,27 @@ namespace tr2
_M_do_right_shift(size_t __shift);
void
- _M_do_flip()
+ _M_do_flip() noexcept
{
for (size_t __i = 0; __i < this->_M_w.size(); ++__i)
this->_M_w[__i] = ~this->_M_w[__i];
}
void
- _M_do_set()
+ _M_do_set() noexcept
{
for (size_t __i = 0; __i < this->_M_w.size(); ++__i)
- this->_M_w[__i] = ~static_cast<block_type>(0);
+ this->_M_w[__i] = static_cast<block_type>(-1);
}
void
- _M_do_reset()
+ _M_do_reset() noexcept
{
- for (size_t __i = 0; __i < this->_M_w.size(); ++__i)
- this->_M_w[__i] = static_cast<block_type>(0);
+ std::fill(_M_w.begin(), _M_w.end(), static_cast<block_type>(0));
}
bool
- _M_is_equal(const __dynamic_bitset_base& __x) const
+ _M_is_equal(const __dynamic_bitset_base& __x) const noexcept
{
if (__x._M_w.size() == this->_M_w.size())
{
@@ -246,7 +251,7 @@ namespace tr2
}
bool
- _M_is_less(const __dynamic_bitset_base& __x) const
+ _M_is_less(const __dynamic_bitset_base& __x) const noexcept
{
if (__x._M_w.size() == this->_M_w.size())
{
@@ -264,17 +269,17 @@ namespace tr2
}
size_t
- _M_are_all_aux() const
+ _M_are_all_aux() const noexcept
{
for (size_t __i = 0; __i < this->_M_w.size() - 1; ++__i)
- if (_M_w[__i] != ~static_cast<block_type>(0))
+ if (_M_w[__i] != static_cast<block_type>(-1))
return 0;
return ((this->_M_w.size() - 1) * _S_bits_per_block
+ __builtin_popcountll(this->_M_hiword()));
}
bool
- _M_is_any() const
+ _M_is_any() const noexcept
{
for (size_t __i = 0; __i < this->_M_w.size(); ++__i)
if (this->_M_w[__i] != static_cast<block_type>(0))
@@ -283,7 +288,7 @@ namespace tr2
}
bool
- _M_is_subset_of(const __dynamic_bitset_base& __b)
+ _M_is_subset_of(const __dynamic_bitset_base& __b) noexcept
{
if (__b._M_w.size() == this->_M_w.size())
{
@@ -297,7 +302,7 @@ namespace tr2
}
bool
- _M_is_proper_subset_of(const __dynamic_bitset_base& __b) const
+ _M_is_proper_subset_of(const __dynamic_bitset_base& __b) const noexcept
{
if (this->is_subset_of(__b))
{
@@ -311,7 +316,7 @@ namespace tr2
}
size_t
- _M_do_count() const
+ _M_do_count() const noexcept
{
size_t __result = 0;
for (size_t __i = 0; __i < this->_M_w.size(); ++__i)
@@ -357,6 +362,7 @@ namespace tr2
*
* See N2050,
* Proposal to Add a Dynamically Sizeable Bitset to the Standard Library.
+ * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2050.pdf
*
* In the general unoptimized case, storage is allocated in
* word-sized blocks. Let B be the number of bits in a word, then
@@ -435,7 +441,7 @@ namespace tr2
{
size_type __shift = this->_M_Nb % bits_per_block;
if (__shift > 0)
- this->_M_hiword() &= ~((~static_cast<block_type>(0)) << __shift);
+ this->_M_hiword() &= block_type(~(block_type(-1) << __shift));
}
// Set the unused bits in the uppermost word.
@@ -444,22 +450,22 @@ namespace tr2
{
size_type __shift = this->_M_Nb % bits_per_block;
if (__shift > 0)
- this->_M_hiword() |= ((~static_cast<block_type>(0)) << __shift);
+ this->_M_hiword() |= block_type(block_type(-1) << __shift);
}
/**
* These versions of single-bit set, reset, flip, and test
* do no range checking.
*/
- dynamic_bitset<_WordT, _Alloc>&
- _M_unchecked_set(size_type __pos)
+ dynamic_bitset&
+ _M_unchecked_set(size_type __pos) noexcept
{
this->_M_getword(__pos) |= _Base::_S_maskbit(__pos);
return *this;
}
- dynamic_bitset<_WordT, _Alloc>&
- _M_unchecked_set(size_type __pos, int __val)
+ dynamic_bitset&
+ _M_unchecked_set(size_type __pos, int __val) noexcept
{
if (__val)
this->_M_getword(__pos) |= _Base::_S_maskbit(__pos);
@@ -468,26 +474,26 @@ namespace tr2
return *this;
}
- dynamic_bitset<_WordT, _Alloc>&
- _M_unchecked_reset(size_type __pos)
+ dynamic_bitset&
+ _M_unchecked_reset(size_type __pos) noexcept
{
this->_M_getword(__pos) &= ~_Base::_S_maskbit(__pos);
return *this;
}
- dynamic_bitset<_WordT, _Alloc>&
- _M_unchecked_flip(size_type __pos)
+ dynamic_bitset&
+ _M_unchecked_flip(size_type __pos) noexcept
{
this->_M_getword(__pos) ^= _Base::_S_maskbit(__pos);
return *this;
}
bool
- _M_unchecked_test(size_type __pos) const
+ _M_unchecked_test(size_type __pos) const noexcept
{ return ((this->_M_getword(__pos) & _Base::_S_maskbit(__pos))
!= static_cast<_WordT>(0)); }
- size_type _M_Nb;
+ size_type _M_Nb = 0;
public:
/**
@@ -511,22 +517,16 @@ namespace tr2
block_type *_M_wp;
size_type _M_bpos;
- // left undefined
- reference();
-
public:
- reference(dynamic_bitset& __b, size_type __pos)
+ reference(dynamic_bitset& __b, size_type __pos) noexcept
{
this->_M_wp = &__b._M_getword(__pos);
this->_M_bpos = _Base::_S_whichbit(__pos);
}
- ~reference()
- { }
-
// For b[i] = __x;
reference&
- operator=(bool __x)
+ operator=(bool __x) noexcept
{
if (__x)
*this->_M_wp |= _Base::_S_maskbit(this->_M_bpos);
@@ -537,7 +537,7 @@ namespace tr2
// For b[i] = b[__j];
reference&
- operator=(const reference& __j)
+ operator=(const reference& __j) noexcept
{
if ((*(__j._M_wp) & _Base::_S_maskbit(__j._M_bpos)))
*this->_M_wp |= _Base::_S_maskbit(this->_M_bpos);
@@ -548,16 +548,16 @@ namespace tr2
// Flips the bit
bool
- operator~() const
+ operator~() const noexcept
{ return (*(_M_wp) & _Base::_S_maskbit(this->_M_bpos)) == 0; }
// For __x = b[i];
- operator bool() const
+ operator bool() const noexcept
{ return (*(this->_M_wp) & _Base::_S_maskbit(this->_M_bpos)) != 0; }
// For b[i].flip();
reference&
- flip()
+ flip() noexcept
{
*this->_M_wp ^= _Base::_S_maskbit(this->_M_bpos);
return *this;
@@ -569,10 +569,14 @@ namespace tr2
typedef bool const_reference;
// 23.3.5.1 constructors:
+
+ /// All bits set to zero.
+ dynamic_bitset() = default;
+
/// All bits set to zero.
explicit
- dynamic_bitset(const allocator_type& __alloc = allocator_type())
- : _Base(__alloc), _M_Nb(0)
+ dynamic_bitset(const allocator_type& __alloc)
+ : _Base(__alloc)
{ }
/// Initial bits bitwise-copied from a single word (others set to zero).
@@ -585,7 +589,7 @@ namespace tr2
dynamic_bitset(initializer_list<block_type> __il,
const allocator_type& __alloc = allocator_type())
- : _Base(__alloc), _M_Nb(0)
+ : _Base(__alloc)
{ this->append(__il); }
/**
@@ -609,8 +613,7 @@ namespace tr2
__n = std::basic_string<_CharT, _Traits, _Alloc1>::npos,
_CharT __zero = _CharT('0'), _CharT __one = _CharT('1'),
const allocator_type& __alloc = allocator_type())
- : _Base(__alloc),
- _M_Nb(0) // Watch for npos.
+ : _Base(__alloc)
{
if (__pos > __str.size())
__throw_out_of_range(__N("dynamic_bitset::bitset initial position "
@@ -619,8 +622,7 @@ namespace tr2
// Watch for npos.
this->_M_Nb = (__n > __str.size() ? __str.size() - __pos : __n);
this->resize(this->_M_Nb);
- this->_M_copy_from_string(__str, __pos, __n,
- _CharT('0'), _CharT('1'));
+ this->_M_copy_from_string(__str, __pos, __n);
}
/**
@@ -633,61 +635,42 @@ namespace tr2
explicit
dynamic_bitset(const char* __str,
const allocator_type& __alloc = allocator_type())
- : _Base(__alloc)
+ : _Base(__builtin_strlen(__str), 0ULL, __alloc),
+ _M_Nb(__builtin_strlen(__str))
{
- size_t __len = 0;
- if (__str)
- while (__str[__len] != '\0')
- ++__len;
- this->resize(__len);
- this->_M_copy_from_ptr<char,std::char_traits<char>>
- (__str, __len, 0, __len, '0', '1');
+ this->_M_copy_from_ptr(__str, _M_Nb, 0, _M_Nb);
}
- /**
- * @brief Copy constructor.
- */
- dynamic_bitset(const dynamic_bitset& __b)
- : _Base(__b), _M_Nb(__b.size())
- { }
+ /// Copy constructor.
+ dynamic_bitset(const dynamic_bitset&) = default;
- /**
- * @brief Move constructor.
- */
- dynamic_bitset(dynamic_bitset&& __b)
- : _Base(std::forward<_Base>(__b)), _M_Nb(__b.size())
- { }
+ /// Move constructor.
+ dynamic_bitset(dynamic_bitset&& __b) noexcept
+ : _Base(std::move(__b)), _M_Nb(__b._M_Nb)
+ { __b.clear(); }
- /**
- * @brief Swap with another bitset.
- */
+ /// Swap with another bitset.
void
- swap(dynamic_bitset& __b)
+ swap(dynamic_bitset& __b) noexcept
{
this->_M_swap(__b);
std::swap(this->_M_Nb, __b._M_Nb);
}
- /**
- * @brief Assignment.
- */
- dynamic_bitset&
- operator=(const dynamic_bitset& __b)
- {
- if (&__b != this)
- {
- this->_M_assign(__b);
- this->_M_Nb = __b._M_Nb;
- }
- }
+ /// Copy assignment operator.
+ dynamic_bitset& operator=(const dynamic_bitset&) = default;
- /**
- * @brief Move assignment.
- */
+ /// Move assignment operator.
dynamic_bitset&
operator=(dynamic_bitset&& __b)
+ noexcept(std::is_nothrow_move_assignable<_Base>::value)
{
- this->swap(__b);
+ static_cast<_Base&>(*this) = static_cast<_Base&&>(__b);
+ _M_Nb = __b._M_Nb;
+ if _GLIBCXX17_CONSTEXPR (std::is_nothrow_move_assignable<_Base>::value)
+ __b._M_Nb = 0;
+ else if (get_allocator() == __b.get_allocator())
+ __b._M_Nb = 0;
return *this;
}
@@ -695,7 +678,7 @@ namespace tr2
* @brief Return the allocator for the bitset.
*/
allocator_type
- get_allocator() const
+ get_allocator() const noexcept
{ return this->_M_get_allocator(); }
/**
@@ -734,6 +717,8 @@ namespace tr2
++this->_M_Nb;
}
+ // XXX why is there no pop_back() member in the proposal?
+
/**
* @brief Append a block.
*/
@@ -770,36 +755,36 @@ namespace tr2
*
* These should be self-explanatory.
*/
- dynamic_bitset<_WordT, _Alloc>&
- operator&=(const dynamic_bitset<_WordT, _Alloc>& __rhs)
+ dynamic_bitset&
+ operator&=(const dynamic_bitset& __rhs)
{
this->_M_do_and(__rhs);
return *this;
}
- dynamic_bitset<_WordT, _Alloc>&
- operator&=(dynamic_bitset<_WordT, _Alloc>&& __rhs)
+ dynamic_bitset&
+ operator&=(dynamic_bitset&& __rhs)
{
this->_M_do_and(std::move(__rhs));
return *this;
}
- dynamic_bitset<_WordT, _Alloc>&
- operator|=(const dynamic_bitset<_WordT, _Alloc>& __rhs)
+ dynamic_bitset&
+ operator|=(const dynamic_bitset& __rhs)
{
this->_M_do_or(__rhs);
return *this;
}
- dynamic_bitset<_WordT, _Alloc>&
- operator^=(const dynamic_bitset<_WordT, _Alloc>& __rhs)
+ dynamic_bitset&
+ operator^=(const dynamic_bitset& __rhs)
{
this->_M_do_xor(__rhs);
return *this;
}
- dynamic_bitset<_WordT, _Alloc>&
- operator-=(const dynamic_bitset<_WordT, _Alloc>& __rhs)
+ dynamic_bitset&
+ operator-=(const dynamic_bitset& __rhs)
{
this->_M_do_dif(__rhs);
return *this;
@@ -813,7 +798,7 @@ namespace tr2
*
* These should be self-explanatory.
*/
- dynamic_bitset<_WordT, _Alloc>&
+ dynamic_bitset&
operator<<=(size_type __pos)
{
if (__builtin_expect(__pos < this->_M_Nb, 1))
@@ -826,7 +811,7 @@ namespace tr2
return *this;
}
- dynamic_bitset<_WordT, _Alloc>&
+ dynamic_bitset&
operator>>=(size_type __pos)
{
if (__builtin_expect(__pos < this->_M_Nb, 1))
@@ -844,7 +829,7 @@ namespace tr2
/**
* @brief Sets every bit to true.
*/
- dynamic_bitset<_WordT, _Alloc>&
+ dynamic_bitset&
set()
{
this->_M_do_set();
@@ -858,7 +843,7 @@ namespace tr2
* @param __val Either true or false, defaults to true.
* @throw std::out_of_range If @a __pos is bigger the size of the %set.
*/
- dynamic_bitset<_WordT, _Alloc>&
+ dynamic_bitset&
set(size_type __pos, bool __val = true)
{
if (__pos >= _M_Nb)
@@ -869,7 +854,7 @@ namespace tr2
/**
* @brief Sets every bit to false.
*/
- dynamic_bitset<_WordT, _Alloc>&
+ dynamic_bitset&
reset()
{
this->_M_do_reset();
@@ -883,7 +868,7 @@ namespace tr2
*
* Same as writing @c set(__pos, false).
*/
- dynamic_bitset<_WordT, _Alloc>&
+ dynamic_bitset&
reset(size_type __pos)
{
if (__pos >= _M_Nb)
@@ -894,7 +879,7 @@ namespace tr2
/**
* @brief Toggles every bit to its opposite value.
*/
- dynamic_bitset<_WordT, _Alloc>&
+ dynamic_bitset&
flip()
{
this->_M_do_flip();
@@ -907,7 +892,7 @@ namespace tr2
* @param __pos The index of the bit.
* @throw std::out_of_range If @a __pos is bigger the size of the %set.
*/
- dynamic_bitset<_WordT, _Alloc>&
+ dynamic_bitset&
flip(size_type __pos)
{
if (__pos >= _M_Nb)
@@ -916,7 +901,7 @@ namespace tr2
}
/// See the no-argument flip().
- dynamic_bitset<_WordT, _Alloc>
+ dynamic_bitset
operator~() const
{ return dynamic_bitset<_WordT, _Alloc>(*this).flip(); }
@@ -978,19 +963,23 @@ namespace tr2
}
// Helper functions for string operations.
- template<typename _CharT, typename _Traits>
+ template<typename _Traits = std::char_traits<char>,
+ typename _CharT = typename _Traits::char_type>
void
_M_copy_from_ptr(const _CharT*, size_t, size_t, size_t,
- _CharT, _CharT);
+ _CharT __zero = _CharT('0'),
+ _CharT __one = _CharT('1'));
template<typename _CharT, typename _Traits, typename _Alloc1>
void
- _M_copy_from_string(const std::basic_string<_CharT,
- _Traits, _Alloc1>& __str, size_t __pos, size_t __n,
+ _M_copy_from_string(const basic_string<_CharT, _Traits, _Alloc1>& __str,
+ size_t __pos, size_t __n,
_CharT __zero = _CharT('0'),
_CharT __one = _CharT('1'))
- { _M_copy_from_ptr<_CharT, _Traits>(__str.data(), __str.size(),
- __pos, __n, __zero, __one); }
+ {
+ _M_copy_from_ptr<_Traits>(__str.data(), __str.size(), __pos, __n,
+ __zero, __one);
+ }
template<typename _CharT, typename _Traits, typename _Alloc1>
void
@@ -1065,13 +1054,13 @@ namespace tr2
//@{
/// Self-explanatory.
- dynamic_bitset<_WordT, _Alloc>
+ dynamic_bitset
operator<<(size_type __pos) const
- { return dynamic_bitset<_WordT, _Alloc>(*this) <<= __pos; }
+ { return dynamic_bitset(*this) <<= __pos; }
- dynamic_bitset<_WordT, _Alloc>
+ dynamic_bitset
operator>>(size_type __pos) const
- { return dynamic_bitset<_WordT, _Alloc>(*this) >>= __pos; }
+ { return dynamic_bitset(*this) >>= __pos; }
//@}
/**
@@ -1102,14 +1091,14 @@ namespace tr2
{ return this->_M_is_proper_subset_of(__b); }
friend bool
- operator==(const dynamic_bitset<_WordT, _Alloc>& __lhs,
- const dynamic_bitset<_WordT, _Alloc>& __rhs)
- { return __lhs._M_is_equal(__rhs); }
+ operator==(const dynamic_bitset& __lhs,
+ const dynamic_bitset& __rhs) noexcept
+ { return __lhs._M_Nb == __rhs._M_Nb && __lhs._M_is_equal(__rhs); }
friend bool
- operator<(const dynamic_bitset<_WordT, _Alloc>& __lhs,
- const dynamic_bitset<_WordT, _Alloc>& __rhs)
- { return __lhs._M_is_less(__rhs); }
+ operator<(const dynamic_bitset& __lhs,
+ const dynamic_bitset& __rhs) noexcept
+ { return __lhs._M_is_less(__rhs) || __lhs._M_Nb < __rhs._M_Nb; }
};
template<typename _WordT, typename _Alloc>
diff --git a/libstdc++-v3/include/tr2/dynamic_bitset.tcc b/libstdc++-v3/include/tr2/dynamic_bitset.tcc
index 8228d7bc472..bbd2cb3bb04 100644
--- a/libstdc++-v3/include/tr2/dynamic_bitset.tcc
+++ b/libstdc++-v3/include/tr2/dynamic_bitset.tcc
@@ -174,7 +174,7 @@ namespace tr2
// Definitions of non-inline member functions.
template<typename _WordT, typename _Alloc>
- template<typename _CharT, typename _Traits>
+ template<typename _Traits, typename _CharT>
void
dynamic_bitset<_WordT, _Alloc>::
_M_copy_from_ptr(const _CharT* __str, size_t __len,
diff --git a/libstdc++-v3/scripts/create_testsuite_files b/libstdc++-v3/scripts/create_testsuite_files
index 40e81cea8a9..52bbb5cda5a 100755
--- a/libstdc++-v3/scripts/create_testsuite_files
+++ b/libstdc++-v3/scripts/create_testsuite_files
@@ -33,7 +33,7 @@ cd $srcdir
# what has to happen when find(1) doesn't support -mindepth, or -xtype.
# The directories here should be consistent with libstdc++-dg/conformance.exp
dlist=`echo [0-9][0-9]*`
-dlist="$dlist abi backward ext performance tr1 tr2 decimal experimental"
+dlist="$dlist std abi backward ext performance tr1 tr2 decimal experimental"
dlist="$dlist special_functions"
find $dlist "(" -type f -o -type l ")" -name "*.cc" -print > $tmp.01
find $dlist "(" -type f -o -type l ")" -name "*.c" -print > $tmp.02
diff --git a/libstdc++-v3/src/c++98/locale.cc b/libstdc++-v3/src/c++98/locale.cc
index 8652f8559c2..74a800c9c15 100644
--- a/libstdc++-v3/src/c++98/locale.cc
+++ b/libstdc++-v3/src/c++98/locale.cc
@@ -474,6 +474,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Definitions for static const data members of locale::id
_Atomic_word locale::id::_S_refcount; // init'd to 0 by linker
+ // XXX GLIBCXX_ABI Deprecated
+#ifdef _GLIBCXX_LONG_DOUBLE_COMPAT
+namespace {
+ inline locale::id*
+ find_ldbl_sync_facet(const locale::id* __idp)
+ {
+# define _GLIBCXX_SYNC_ID(facet, mangled) \
+ if (__idp == &::mangled) \
+ return &facet::id
+
+ _GLIBCXX_SYNC_ID (num_get<char>, _ZNSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE2idE);
+ _GLIBCXX_SYNC_ID (num_put<char>, _ZNSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE2idE);
+ _GLIBCXX_SYNC_ID (money_get<char>, _ZNSt9money_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE2idE);
+ _GLIBCXX_SYNC_ID (money_put<char>, _ZNSt9money_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE2idE);
+# ifdef _GLIBCXX_USE_WCHAR_T
+ _GLIBCXX_SYNC_ID (num_get<wchar_t>, _ZNSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE2idE);
+ _GLIBCXX_SYNC_ID (num_put<wchar_t>, _ZNSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE2idE);
+ _GLIBCXX_SYNC_ID (money_get<wchar_t>, _ZNSt9money_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE2idE);
+ _GLIBCXX_SYNC_ID (money_put<wchar_t>, _ZNSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE2idE);
+# endif
+ return 0;
+ }
+} // namespace
+#endif
+
size_t
locale::id::_M_id() const throw()
{
@@ -481,26 +506,38 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
// XXX GLIBCXX_ABI Deprecated
#ifdef _GLIBCXX_LONG_DOUBLE_COMPAT
- locale::id *f = 0;
-# define _GLIBCXX_SYNC_ID(facet, mangled) \
- if (this == &::mangled) \
- f = &facet::id
- _GLIBCXX_SYNC_ID (num_get<char>, _ZNSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE2idE);
- _GLIBCXX_SYNC_ID (num_put<char>, _ZNSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE2idE);
- _GLIBCXX_SYNC_ID (money_get<char>, _ZNSt9money_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE2idE);
- _GLIBCXX_SYNC_ID (money_put<char>, _ZNSt9money_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE2idE);
-# ifdef _GLIBCXX_USE_WCHAR_T
- _GLIBCXX_SYNC_ID (num_get<wchar_t>, _ZNSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE2idE);
- _GLIBCXX_SYNC_ID (num_put<wchar_t>, _ZNSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE2idE);
- _GLIBCXX_SYNC_ID (money_get<wchar_t>, _ZNSt9money_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE2idE);
- _GLIBCXX_SYNC_ID (money_put<wchar_t>, _ZNSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE2idE);
-# endif
- if (f)
- _M_index = 1 + f->_M_id();
+ if (locale::id* f = find_ldbl_sync_facet(this))
+ {
+ const size_t sync_id = f->_M_id();
+ _M_index = 1 + sync_id;
+ return sync_id;
+ }
+#endif
+
+#ifdef __GTHREADS
+ if (__gthread_active_p())
+ {
+ if (__atomic_always_lock_free(sizeof(_M_index), &_M_index))
+ {
+ const _Atomic_word next
+ = 1 + __gnu_cxx::__exchange_and_add(&_S_refcount, 1);
+ size_t expected = 0;
+ __atomic_compare_exchange_n(&_M_index, &expected, next,
+ /* weak = */ false,
+ /* success = */ __ATOMIC_ACQ_REL,
+ /* failure = */ __ATOMIC_ACQUIRE);
+ }
+ else
+ {
+ static __gnu_cxx::__mutex m;
+ __gnu_cxx::__scoped_lock l(m);
+ if (!_M_index)
+ _M_index = ++_S_refcount;
+ }
+ }
else
#endif
- _M_index = 1 + __gnu_cxx::__exchange_and_add_dispatch(&_S_refcount,
- 1);
+ _M_index = ++_S_refcount; // single-threaded case
}
return _M_index - 1;
}
diff --git a/libstdc++-v3/src/c++98/locale_init.cc b/libstdc++-v3/src/c++98/locale_init.cc
index e5e9d74379f..07d95dc09fd 100644
--- a/libstdc++-v3/src/c++98/locale_init.cc
+++ b/libstdc++-v3/src/c++98/locale_init.cc
@@ -303,7 +303,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
locale::classic()
{
_S_initialize();
- return *(new (&c_locale) locale(_S_classic));
+ return *(const locale*)c_locale;
}
void
@@ -313,6 +313,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// One reference for _S_classic, one for _S_global
_S_classic = new (&c_locale_impl) _Impl(2);
_S_global = _S_classic;
+ new (&c_locale) locale(_S_classic);
}
void
diff --git a/libstdc++-v3/testsuite/23_containers/span/lwg3255.cc b/libstdc++-v3/testsuite/23_containers/span/lwg3255.cc
index 638c88101f9..bab7da3bf19 100644
--- a/libstdc++-v3/testsuite/23_containers/span/lwg3255.cc
+++ b/libstdc++-v3/testsuite/23_containers/span/lwg3255.cc
@@ -28,8 +28,7 @@ using std::is_constructible_v;
// LWG 3255 span's array constructor is too strict
-// FIXME: remove '!' from next line when P0388R4 is implemented:
-static_assert( ! is_constructible_v<span<const int* const>, array<int*, 2>> );
+static_assert( is_constructible_v<span<const int* const>, array<int*, 2>> );
static_assert( is_constructible_v<span<const int>, array<const int, 4>> );
static_assert( is_constructible_v<span<int, 1>, int(&)[1]> );
diff --git a/libstdc++-v3/testsuite/libstdc++-dg/conformance.exp b/libstdc++-v3/testsuite/libstdc++-dg/conformance.exp
index 6564b046ca8..f334f76a8d9 100644
--- a/libstdc++-v3/testsuite/libstdc++-dg/conformance.exp
+++ b/libstdc++-v3/testsuite/libstdc++-dg/conformance.exp
@@ -54,6 +54,7 @@ if {[info exists tests_file] && [file exists $tests_file]} {
# Find directories that might have tests.
# This list should be consistent with scripts/create_testsuite_files
set subdirs [glob "$srcdir/\[0-9\]\[0-9\]*"]
+ lappend subdirs "$srcdir/std"
lappend subdirs "$srcdir/abi"
lappend subdirs "$srcdir/backward"
lappend subdirs "$srcdir/ext"
diff --git a/libstdc++-v3/testsuite/std/concepts/concepts.callable/invocable.cc b/libstdc++-v3/testsuite/std/concepts/concepts.callable/invocable.cc
new file mode 100644
index 00000000000..d6a8549eaba
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/concepts/concepts.callable/invocable.cc
@@ -0,0 +1,45 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <concepts>
+
+static_assert( ! std::invocable<int> );
+static_assert( std::invocable<int()> );
+static_assert( std::invocable<int(*)()> );
+static_assert( std::invocable<int(&)()> );
+static_assert( ! std::invocable<int(), int> );
+static_assert( ! std::invocable<int() const> );
+
+static_assert( std::invocable<int(const long*, short), long*, char> );
+
+struct A;
+static_assert( std::invocable<int A::*, const A&> );
+static_assert( ! std::invocable<void (A::*)(long&), const A*, long&> );
+static_assert( std::invocable<void (A::*)(long&) const, A*, long&> );
+
+struct F
+{
+ void operator()() const;
+ void operator()(int);
+};
+static_assert( std::invocable<F> );
+static_assert( std::invocable<F, int> );
+static_assert( std::invocable<const F&> );
+static_assert( ! std::invocable<const F&, int> );
diff --git a/libstdc++-v3/testsuite/std/concepts/concepts.callable/regular_invocable.cc b/libstdc++-v3/testsuite/std/concepts/concepts.callable/regular_invocable.cc
new file mode 100644
index 00000000000..f7ca447ab85
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/concepts/concepts.callable/regular_invocable.cc
@@ -0,0 +1,45 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <concepts>
+
+static_assert( ! std::regular_invocable<int> );
+static_assert( std::regular_invocable<int()> );
+static_assert( std::regular_invocable<int(*)()> );
+static_assert( std::regular_invocable<int(&)()> );
+static_assert( ! std::regular_invocable<int(), int> );
+static_assert( ! std::regular_invocable<int() const> );
+
+static_assert( std::regular_invocable<int(const long*, short), long*, char> );
+
+struct A;
+static_assert( std::regular_invocable<int A::*, const A&> );
+static_assert( ! std::regular_invocable<void (A::*)(long&), const A*, long&> );
+static_assert( std::regular_invocable<void (A::*)(long&) const, A*, long&> );
+
+struct F
+{
+ void operator()() const;
+ void operator()(int);
+};
+static_assert( std::regular_invocable<F> );
+static_assert( std::regular_invocable<F, int> );
+static_assert( std::regular_invocable<const F&> );
+static_assert( ! std::regular_invocable<const F&, int> );
diff --git a/libstdc++-v3/testsuite/std/concepts/concepts.callable/relation.cc b/libstdc++-v3/testsuite/std/concepts/concepts.callable/relation.cc
new file mode 100644
index 00000000000..783c3ab9c4a
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/concepts/concepts.callable/relation.cc
@@ -0,0 +1,48 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <concepts>
+
+static_assert( ! std::relation<bool, void, void> );
+static_assert( ! std::relation<bool(), void, void> );
+static_assert( ! std::relation<bool(*)(), void, void> );
+static_assert( ! std::relation<bool(&)(int, int), void, void> );
+static_assert( ! std::relation<bool(), int, int> );
+static_assert( ! std::relation<bool() const, int, int> );
+
+static_assert( std::relation<bool(*)(int, int), short, long> );
+static_assert( std::relation<bool(&)(const void*, const void*), char[2], int*> );
+
+static_assert( ! std::relation<bool& (const long*, short), long*, char> );
+
+struct A;
+static_assert( ! std::relation<int A::*, const A&, const A&> );
+static_assert( ! std::relation<void (A::*)(long&), const A*, long&> );
+static_assert( ! std::relation<void (A::*)(long&) const, A*, long&> );
+static_assert( std::relation<long (A::*)(A*) const, A*, A*> );
+
+struct F
+{
+ void operator()(long, long) const;
+ bool& operator()(int, const int&) const;
+};
+static_assert( ! std::relation<F, long, long> );
+static_assert( std::relation<F&, int, int> );
+static_assert( std::relation<const F&, const int, const int> );
diff --git a/libstdc++-v3/testsuite/std/concepts/concepts.callable/strictweakorder.cc b/libstdc++-v3/testsuite/std/concepts/concepts.callable/strictweakorder.cc
new file mode 100644
index 00000000000..9a01eb259cb
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/concepts/concepts.callable/strictweakorder.cc
@@ -0,0 +1,48 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <concepts>
+
+static_assert( ! std::strict_weak_order<bool, void, void> );
+static_assert( ! std::strict_weak_order<bool(), void, void> );
+static_assert( ! std::strict_weak_order<bool(*)(), void, void> );
+static_assert( ! std::strict_weak_order<bool(&)(int, int), void, void> );
+static_assert( ! std::strict_weak_order<bool(), int, int> );
+static_assert( ! std::strict_weak_order<bool() const, int, int> );
+
+static_assert( std::strict_weak_order<bool(*)(int, int), short, long> );
+static_assert( std::strict_weak_order<bool(&)(const void*, const void*), char[2], int*> );
+
+static_assert( ! std::strict_weak_order<bool& (const long*, short), long*, char> );
+
+struct A;
+static_assert( ! std::strict_weak_order<int A::*, const A&, const A&> );
+static_assert( ! std::strict_weak_order<void (A::*)(long&), const A*, long&> );
+static_assert( ! std::strict_weak_order<void (A::*)(long&) const, A*, long&> );
+static_assert( std::strict_weak_order<long (A::*)(A*) const, A*, A*> );
+
+struct F
+{
+ void operator()(long, long) const;
+ bool& operator()(int, const int&) const;
+};
+static_assert( ! std::strict_weak_order<F, long, long> );
+static_assert( std::strict_weak_order<F&, int, int> );
+static_assert( std::strict_weak_order<const F&, const int, const int> );
diff --git a/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.arithmetic/floating_point.cc b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.arithmetic/floating_point.cc
new file mode 100644
index 00000000000..802f2374805
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.arithmetic/floating_point.cc
@@ -0,0 +1,58 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <concepts>
+
+static_assert( std::floating_point<float> );
+static_assert( std::floating_point<double> );
+static_assert( std::floating_point<long double> );
+#ifdef _GLIBCXX_USE_FLOAT128
+static_assert( std::floating_point<__float128> );
+#endif
+
+static_assert( !std::floating_point<char> );
+static_assert( !std::floating_point<signed char> );
+static_assert( !std::floating_point<bool> );
+static_assert( !std::floating_point<int> );
+static_assert( !std::floating_point<char32_t> );
+
+#ifdef __GLIBCXX_TYPE_INT_N_0
+static_assert( !std::floating_point<signed __GLIBCXX_TYPE_INT_N_0> );
+#endif
+
+static_assert( !std::floating_point<void> );
+static_assert( !std::floating_point<float*> );
+static_assert( !std::floating_point<float&> );
+static_assert( !std::floating_point<float&&> );
+static_assert( !std::floating_point<const float&> );
+static_assert( !std::floating_point<float[]> );
+static_assert( !std::floating_point<float[2]> );
+static_assert( !std::floating_point<float()> );
+static_assert( !std::floating_point<float(*)()> );
+static_assert( !std::floating_point<float(&)()> );
+
+enum E { };
+static_assert( !std::floating_point<E> );
+enum class CE { };
+static_assert( !std::floating_point<CE> );
+struct A { };
+static_assert( !std::floating_point<A> );
+union B { };
+static_assert( !std::floating_point<B> );
diff --git a/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.arithmetic/integral.cc b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.arithmetic/integral.cc
new file mode 100644
index 00000000000..4716dde03b1
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.arithmetic/integral.cc
@@ -0,0 +1,73 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <concepts>
+
+// signed integer types
+static_assert( std::integral<signed char> );
+static_assert( std::integral<signed short> );
+static_assert( std::integral<signed int> );
+static_assert( std::integral<signed long> );
+static_assert( std::integral<signed long long> );
+
+// unsigned integer types
+static_assert( std::integral<unsigned char> );
+static_assert( std::integral<unsigned short> );
+static_assert( std::integral<unsigned int> );
+static_assert( std::integral<unsigned long> );
+static_assert( std::integral<unsigned long long> );
+
+// other integral types
+static_assert( std::integral<bool> );
+static_assert( std::integral<char> );
+static_assert( std::integral<char16_t> );
+static_assert( std::integral<char32_t> );
+#ifdef _GLIBCXX_USE_WCHAR_T
+static_assert( std::integral<wchar_t> );
+#endif
+#ifdef _GLIBCXX_USE_CHAR8_T
+static_assert( std::integral<char8_t> );
+#endif
+
+#ifdef __GLIBCXX_TYPE_INT_N_0
+static_assert( std::integral<signed __GLIBCXX_TYPE_INT_N_0> );
+static_assert( std::integral<unsigned __GLIBCXX_TYPE_INT_N_0> );
+#endif
+
+static_assert( !std::integral<void> );
+static_assert( !std::integral<float> );
+static_assert( !std::integral<int*> );
+static_assert( !std::integral<int&> );
+static_assert( !std::integral<int&&> );
+static_assert( !std::integral<const int&> );
+static_assert( !std::integral<int[]> );
+static_assert( !std::integral<int[2]> );
+static_assert( !std::integral<int()> );
+static_assert( !std::integral<int(*)()> );
+static_assert( !std::integral<int(&)()> );
+
+enum E { };
+static_assert( !std::integral<E> );
+enum class CE { };
+static_assert( !std::integral<CE> );
+struct A { };
+static_assert( !std::integral<A> );
+union B { };
+static_assert( !std::integral<B> );
diff --git a/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.arithmetic/signed_integral.cc b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.arithmetic/signed_integral.cc
new file mode 100644
index 00000000000..8dd33e51ae7
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.arithmetic/signed_integral.cc
@@ -0,0 +1,73 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <concepts>
+
+// signed integer types
+static_assert( std::signed_integral<signed char> );
+static_assert( std::signed_integral<signed short> );
+static_assert( std::signed_integral<signed int> );
+static_assert( std::signed_integral<signed long> );
+static_assert( std::signed_integral<signed long long> );
+
+// unsigned integer types
+static_assert( !std::signed_integral<unsigned char> );
+static_assert( !std::signed_integral<unsigned short> );
+static_assert( !std::signed_integral<unsigned int> );
+static_assert( !std::signed_integral<unsigned long> );
+static_assert( !std::signed_integral<unsigned long long> );
+
+// other integral types
+static_assert( !std::signed_integral<bool> );
+static_assert( std::is_signed_v<char> ? std::signed_integral<char> : true );
+static_assert( !std::signed_integral<char16_t> );
+static_assert( !std::signed_integral<char32_t> );
+#ifdef _GLIBCXX_USE_WCHAR_T
+static_assert( std::is_signed_v<wchar_t> ? std::signed_integral<wchar_t> : true );
+#endif
+#ifdef _GLIBCXX_USE_CHAR8_T
+static_assert( !std::signed_integral<char8_t> );
+#endif
+
+#ifdef __GLIBCXX_TYPE_INT_N_0
+static_assert( std::signed_integral<signed __GLIBCXX_TYPE_INT_N_0> );
+static_assert( !std::signed_integral<unsigned __GLIBCXX_TYPE_INT_N_0> );
+#endif
+
+static_assert( !std::signed_integral<void> );
+static_assert( !std::signed_integral<float> );
+static_assert( !std::signed_integral<int&> );
+static_assert( !std::signed_integral<int&> );
+static_assert( !std::signed_integral<int&&> );
+static_assert( !std::signed_integral<const int&> );
+static_assert( !std::signed_integral<int[]> );
+static_assert( !std::signed_integral<int[2]> );
+static_assert( !std::signed_integral<int()> );
+static_assert( !std::signed_integral<int(*)()> );
+static_assert( !std::signed_integral<int(&)()> );
+
+enum E { };
+static_assert( !std::signed_integral<E> );
+enum class CE { };
+static_assert( !std::signed_integral<CE> );
+struct A { };
+static_assert( !std::signed_integral<A> );
+union B { };
+static_assert( !std::signed_integral<B> );
diff --git a/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.arithmetic/unsigned_integral.cc b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.arithmetic/unsigned_integral.cc
new file mode 100644
index 00000000000..33affffc895
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.arithmetic/unsigned_integral.cc
@@ -0,0 +1,73 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <concepts>
+
+// unsigned integer types
+static_assert( std::unsigned_integral<unsigned char> );
+static_assert( std::unsigned_integral<unsigned short> );
+static_assert( std::unsigned_integral<unsigned int> );
+static_assert( std::unsigned_integral<unsigned long> );
+static_assert( std::unsigned_integral<unsigned long long> );
+
+// signed integer types
+static_assert( !std::unsigned_integral<signed char> );
+static_assert( !std::unsigned_integral<signed short> );
+static_assert( !std::unsigned_integral<signed int> );
+static_assert( !std::unsigned_integral<signed long> );
+static_assert( !std::unsigned_integral<signed long long> );
+
+// other integral types
+static_assert( std::unsigned_integral<bool> );
+static_assert( std::is_signed_v<char> ? true : std::unsigned_integral<char> );
+static_assert( std::unsigned_integral<char16_t> );
+static_assert( std::unsigned_integral<char32_t> );
+#ifdef _GLIBCXX_USE_WCHAR_T
+static_assert( std::is_signed_v<wchar_t> ? true : std::unsigned_integral<wchar_t> );
+#endif
+#ifdef _GLIBCXX_USE_CHAR8_T
+static_assert( std::unsigned_integral<char8_t> );
+#endif
+
+#ifdef __GLIBCXX_TYPE_INT_N_0
+static_assert( !std::unsigned_integral<signed __GLIBCXX_TYPE_INT_N_0> );
+static_assert( std::unsigned_integral<unsigned __GLIBCXX_TYPE_INT_N_0> );
+#endif
+
+static_assert( !std::unsigned_integral<void> );
+static_assert( !std::unsigned_integral<float> );
+static_assert( !std::unsigned_integral<unsigned&> );
+static_assert( !std::unsigned_integral<unsigned&> );
+static_assert( !std::unsigned_integral<unsigned&&> );
+static_assert( !std::unsigned_integral<const unsigned&> );
+static_assert( !std::unsigned_integral<unsigned[]> );
+static_assert( !std::unsigned_integral<unsigned[2]> );
+static_assert( !std::unsigned_integral<unsigned()> );
+static_assert( !std::unsigned_integral<unsigned(*)()> );
+static_assert( !std::unsigned_integral<unsigned(&)()> );
+
+enum E { };
+static_assert( !std::unsigned_integral<E> );
+enum class CE { };
+static_assert( !std::unsigned_integral<CE> );
+struct A { };
+static_assert( !std::unsigned_integral<A> );
+union B { };
+static_assert( !std::unsigned_integral<B> );
diff --git a/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.assignable/1.cc b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.assignable/1.cc
new file mode 100644
index 00000000000..64773924682
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.assignable/1.cc
@@ -0,0 +1,85 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <concepts>
+
+static_assert( !std::assignable_from<void, void> );
+static_assert( !std::assignable_from<void*, int*> );
+static_assert( std::assignable_from<void*&, int*> );
+static_assert( !std::assignable_from<void*&, const int*> );
+static_assert( std::assignable_from<const void*&, const int*> );
+static_assert( !std::assignable_from<char, char> );
+static_assert( std::assignable_from<char&, char> );
+static_assert( !std::assignable_from<float, float> );
+static_assert( std::assignable_from<float&, double> );
+static_assert( std::assignable_from<int*&, int*> );
+static_assert( std::assignable_from<int&, int&> );
+static_assert( std::assignable_from<int&, int&&> );
+static_assert( !std::assignable_from<int&&, int> );
+static_assert( !std::assignable_from<const int&, int> );
+static_assert( !std::assignable_from<const int&, int&> );
+static_assert( !std::assignable_from<const int&, const int> );
+static_assert( !std::assignable_from<const int&, const int&> );
+static_assert( !std::assignable_from<int(&)[], int(&)[]> );
+static_assert( !std::assignable_from<int(&)[], int> );
+static_assert( !std::assignable_from<int(&)[2], int(&)[2]> );
+static_assert( !std::assignable_from<int(), int()> );
+static_assert( !std::assignable_from<int(*)(), int(*)()> );
+static_assert( std::assignable_from<int(*&)(), int(*)()> );
+static_assert( std::assignable_from<int(*&)(), std::nullptr_t> );
+static_assert( std::assignable_from<int(*&)(), int(*)() noexcept> );
+static_assert( std::assignable_from<int(*&)(), int(&)() noexcept> );
+static_assert( !std::assignable_from<int(&)(), std::nullptr_t> );
+static_assert( !std::assignable_from<int(&)(), int(&)() noexcept> );
+
+enum E { };
+static_assert( !std::assignable_from<E, E> );
+static_assert( std::assignable_from<E&, E> );
+static_assert( std::assignable_from<E&, E&> );
+static_assert( std::assignable_from<E&, const E&> );
+static_assert( !std::assignable_from<const E&, const E&> );
+enum class CE { };
+static_assert( !std::assignable_from<CE, CE> );
+static_assert( std::assignable_from<CE&, CE&> );
+static_assert( std::assignable_from<CE&, const CE&> );
+static_assert( !std::assignable_from<const CE&, const CE&> );
+struct A { };
+static_assert( !std::assignable_from<A, A> );
+static_assert( std::assignable_from<A&, A> );
+static_assert( !std::assignable_from<A, A&> );
+static_assert( std::assignable_from<A&, const A&> );
+union B { };
+static_assert( !std::assignable_from<B, B> );
+static_assert( std::assignable_from<B&, B> );
+static_assert( !std::assignable_from<B, B&> );
+static_assert( std::assignable_from<B&, const B&> );
+
+struct C
+{
+ C(int) { }
+ C& operator=(const C&) { return *this; }
+ C& operator=(int) { return *this; }
+ void operator=(void*) { }
+};
+static_assert( std::assignable_from<C&, C> );
+static_assert( std::assignable_from<C&, const C&> );
+static_assert( std::assignable_from<C&, int> );
+static_assert( !std::assignable_from<C&, void*> );
+static_assert( !std::assignable_from<C&, std::nullptr_t> );
diff --git a/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.common/1.cc b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.common/1.cc
new file mode 100644
index 00000000000..2432ab8e561
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.common/1.cc
@@ -0,0 +1,73 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <concepts>
+
+static_assert( std::common_with<int, int> );
+static_assert( std::common_with<int, const int> );
+static_assert( std::common_with<int&&, const int&> );
+static_assert( std::common_with<int&, const int&&> );
+static_assert( std::common_with<void, void> );
+static_assert( ! std::common_with<int, void> );
+static_assert( ! std::common_with<int, int*> );
+static_assert( ! std::common_with<int, int()> );
+
+static_assert( std::common_with<int, short> );
+static_assert( std::common_with<short, int> );
+static_assert( std::common_with<void*, const int*> );
+
+struct A { A(int) { } };
+static_assert( std::common_with<A, int> );
+
+struct B { };
+static_assert( ! std::common_with<A, B> );
+
+struct C { C(const A&) { } };
+static_assert( std::common_with<A, C> );
+static_assert( std::common_with<A, const C> );
+static_assert( std::common_with<const A, C> );
+static_assert( std::common_with<const A, const C> );
+
+struct D;
+struct E { E(const D&) { } };
+struct D { D(const E&) { } };
+static_assert( ! std::common_with<D, E> ); // ambiguous conversion
+
+struct F { };
+struct G { };
+struct H {
+ H(const F&) { }
+ H(const G&) { }
+};
+namespace std
+{
+ template<> struct common_type<F, G> { using type = H; };
+ template<> struct common_type<G, F> { using type = H; };
+}
+
+static_assert( std::common_with<F, G> );
+static_assert( std::common_with<F, const G> );
+static_assert( std::common_with<const F, G> );
+static_assert( std::common_with<const F, const G> );
+
+struct Base { };
+struct Derived : Base { };
+static_assert( std::common_with<Derived, Base> );
+static_assert( std::common_with<Derived*, Base*> );
diff --git a/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.commonref/1.cc b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.commonref/1.cc
new file mode 100644
index 00000000000..4b56dd71679
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.commonref/1.cc
@@ -0,0 +1,71 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <concepts>
+
+static_assert( std::common_reference_with<int, int> );
+static_assert( std::common_reference_with<int, const int> );
+static_assert( std::common_reference_with<int&&, const int&> );
+static_assert( std::common_reference_with<int&, const int&&> );
+static_assert( ! std::common_reference_with<int, void> );
+static_assert( ! std::common_reference_with<int, int*> );
+static_assert( ! std::common_reference_with<int, int()> );
+
+struct A { A(int) { } };
+static_assert( std::common_reference_with<A, int> );
+
+struct B { };
+static_assert( ! std::common_reference_with<A, B> );
+
+struct C { C(A&) { } };
+static_assert( std::common_reference_with<A&, C> );
+static_assert( std::common_reference_with<A&, C&&> );
+static_assert( std::common_reference_with<A&, const C&> );
+static_assert( std::common_reference_with<A&, C&> );
+static_assert( ! std::common_reference_with<const A&, C> );
+static_assert( ! std::common_reference_with<const A&, const C&> );
+
+struct D;
+struct E { E(D&) { } };
+struct D { D(E&) { } };
+static_assert( ! std::common_reference_with<D&, E&> ); // ambiguous conversion
+
+struct F;
+struct G { G(const F&) { } };
+struct F { F(const G&) { } };
+namespace std
+{
+ template<template<typename> class Qual1, template<typename> class Qual2>
+ struct basic_common_reference<F, G, Qual1, Qual2>
+ { using type = Qual1<Qual2<F>>; };
+ template<template<typename> class Qual1, template<typename> class Qual2>
+ struct basic_common_reference<G, F, Qual1, Qual2>
+ { using type = Qual1<Qual2<F>>; };
+}
+
+static_assert( ! std::common_reference_with<F&, G&> );
+static_assert( std::common_reference_with<F, G> );
+static_assert( std::common_reference_with<F, const G> );
+static_assert( std::common_reference_with<const F, const G> );
+
+struct Base { };
+struct Derived : Base { };
+static_assert( std::common_reference_with<Derived&, Base&> );
+static_assert( std::common_with<Derived*, Base*> );
diff --git a/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.constructible/1.cc b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.constructible/1.cc
new file mode 100644
index 00000000000..22a52d02360
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.constructible/1.cc
@@ -0,0 +1,89 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <concepts>
+
+static_assert( !std::constructible_from<void> );
+static_assert( !std::constructible_from<void, void> );
+static_assert( std::constructible_from<void*, int*> );
+static_assert( !std::constructible_from<void*, const int*> );
+static_assert( std::constructible_from<const void*, const int*> );
+static_assert( std::constructible_from<char> );
+static_assert( std::constructible_from<float> );
+static_assert( std::constructible_from<float, float> );
+static_assert( std::constructible_from<float, double> );
+static_assert( std::constructible_from<int*> );
+static_assert( std::constructible_from<int*, int*> );
+static_assert( !std::constructible_from<int&> );
+static_assert( std::constructible_from<int&, int&> );
+static_assert( !std::constructible_from<int&&> );
+static_assert( std::constructible_from<int&&, int> );
+static_assert( !std::constructible_from<const int&> );
+static_assert( std::constructible_from<const int&, int> );
+static_assert( std::constructible_from<const int&, int&> );
+static_assert( std::constructible_from<const int&, const int> );
+static_assert( std::constructible_from<const int&, const int&> );
+static_assert( !std::constructible_from<const int&, int, int> );
+static_assert( !std::constructible_from<int[]> );
+static_assert( std::constructible_from<int[2]> );
+static_assert( !std::constructible_from<int()> );
+static_assert( std::constructible_from<int(*)()> );
+static_assert( std::constructible_from<int(*)(), std::nullptr_t> );
+static_assert( std::constructible_from<int(*)(), int(*)() noexcept> );
+static_assert( std::constructible_from<int(*)(), int(&)() noexcept> );
+static_assert( !std::constructible_from<int(&)()> );
+static_assert( std::constructible_from<int(&)(), int(&)() noexcept> );
+
+enum E { };
+static_assert( std::constructible_from<E> );
+static_assert( std::constructible_from<E, E&> );
+enum class CE { };
+static_assert( std::constructible_from<CE> );
+static_assert( std::constructible_from<CE, CE&> );
+struct A { };
+static_assert( std::constructible_from<A> );
+static_assert( std::constructible_from<A, A> );
+static_assert( std::constructible_from<A, A&> );
+static_assert( std::constructible_from<A, const A&> );
+union B { };
+static_assert( std::constructible_from<B> );
+static_assert( std::constructible_from<B, B> );
+static_assert( std::constructible_from<B, B&> );
+static_assert( std::constructible_from<B, const B&> );
+
+struct C
+{
+ C(void* = nullptr) { }
+ ~C() noexcept(false) { }
+};
+static_assert( !std::constructible_from<C> );
+static_assert( !std::constructible_from<C, void*> );
+static_assert( !std::constructible_from<C, std::nullptr_t> );
+
+class D
+{
+public:
+ D() { }
+ D(int) { }
+private:
+ ~D() { }
+};
+static_assert( !std::constructible_from<D> );
+static_assert( !std::constructible_from<D, int> );
diff --git a/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.convertible/1.cc b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.convertible/1.cc
new file mode 100644
index 00000000000..295706c0440
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.convertible/1.cc
@@ -0,0 +1,77 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <concepts>
+
+static_assert( std::convertible_to<int, int> );
+static_assert( std::convertible_to<int&, int> );
+static_assert( !std::convertible_to<int, int&> );
+static_assert( std::convertible_to<int, const int&> );
+static_assert( !std::convertible_to<int&&, int&> );
+static_assert( std::convertible_to<int&&, const int&> );
+static_assert( std::convertible_to<const int, int> );
+static_assert( !std::convertible_to<const int, int&> );
+static_assert( std::convertible_to<const int, const int> );
+static_assert( std::convertible_to<const int, const int&> );
+
+static_assert( std::convertible_to<int, float> );
+static_assert( !std::convertible_to<int, float&> );
+static_assert( !std::convertible_to<int, int*> );
+static_assert( std::convertible_to<int*, void*> );
+static_assert( std::convertible_to<int*, const void*> );
+static_assert( !std::convertible_to<const int*, void*> );
+static_assert( !std::convertible_to<int, void> );
+
+struct A { };
+static_assert( std::convertible_to<A, A> );
+static_assert( std::convertible_to<A, const A> );
+static_assert( std::convertible_to<A const, const A> );
+static_assert( !std::convertible_to<volatile A, const A> );
+static_assert( !std::convertible_to<volatile A, const volatile A&> );
+static_assert( std::convertible_to<volatile A&, const volatile A&> );
+
+struct B : A { };
+static_assert( !std::convertible_to<A, B> );
+static_assert( std::convertible_to<B, A> );
+static_assert( std::convertible_to<const B, A> );
+static_assert( std::convertible_to<B, const A> );
+static_assert( std::convertible_to<B, const A&> );
+static_assert( !std::convertible_to<volatile B, const A> );
+static_assert( !std::convertible_to<volatile B, const A&> );
+
+struct C : private A { };
+static_assert( !std::convertible_to<A, C> );
+static_assert( !std::convertible_to<C, A> );
+
+struct D : A { };
+struct E : B, D { };
+static_assert( !std::convertible_to<A, E> );
+static_assert( !std::convertible_to<E, A> );
+
+struct F
+{
+ F(A) { }
+ F(C&&) { }
+};
+static_assert( std::convertible_to<A, F> );
+static_assert( std::convertible_to<const A, F> );
+static_assert( std::convertible_to<C, F> );
+static_assert( !std::convertible_to<C&, F> );
+static_assert( !std::convertible_to<const C, F> );
diff --git a/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.copyconstructible/1.cc b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.copyconstructible/1.cc
new file mode 100644
index 00000000000..0e7843ebb9d
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.copyconstructible/1.cc
@@ -0,0 +1,63 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <concepts>
+
+static_assert( !std::copy_constructible<void> );
+static_assert( std::copy_constructible<void*> );
+static_assert( std::copy_constructible<const void*> );
+static_assert( std::copy_constructible<char> );
+static_assert( std::copy_constructible<const float> );
+static_assert( std::copy_constructible<int*> );
+static_assert( std::copy_constructible<int&> );
+static_assert( !std::copy_constructible<int&&> );
+static_assert( std::copy_constructible<const int&> );
+static_assert( !std::copy_constructible<int[]> );
+static_assert( !std::copy_constructible<int[2]> );
+static_assert( !std::copy_constructible<int()> );
+static_assert( std::copy_constructible<int(*)()> );
+static_assert( std::copy_constructible<int(&)()> );
+static_assert( std::copy_constructible<int(&)() noexcept> );
+
+enum E { };
+static_assert( std::copy_constructible<E> );
+enum class CE { };
+static_assert( std::copy_constructible<CE> );
+struct A { };
+static_assert( std::copy_constructible<A> );
+union B { };
+static_assert( std::copy_constructible<B> );
+
+struct C
+{
+ C(void* = nullptr) { }
+ ~C() noexcept(false) { }
+};
+static_assert( !std::copy_constructible<C> );
+
+class D
+{
+public:
+ D() { }
+ D(int) { }
+private:
+ ~D() { }
+};
+static_assert( !std::copy_constructible<D> );
diff --git a/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.defaultconstructible/1.cc b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.defaultconstructible/1.cc
new file mode 100644
index 00000000000..56a4844a957
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.defaultconstructible/1.cc
@@ -0,0 +1,63 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <concepts>
+
+static_assert( !std::default_constructible<void> );
+static_assert( std::default_constructible<void*> );
+static_assert( std::default_constructible<const void*> );
+static_assert( std::default_constructible<char> );
+static_assert( std::default_constructible<float> );
+static_assert( std::default_constructible<const int> );
+static_assert( std::default_constructible<int*> );
+static_assert( !std::default_constructible<int&> );
+static_assert( !std::default_constructible<int&&> );
+static_assert( !std::default_constructible<const int&> );
+static_assert( !std::default_constructible<int[]> );
+static_assert( std::default_constructible<int[2]> );
+static_assert( !std::default_constructible<int()> );
+static_assert( std::default_constructible<int(*)()> );
+static_assert( !std::default_constructible<int(&)()> );
+
+enum E { };
+static_assert( std::default_constructible<E> );
+enum class CE { };
+static_assert( std::default_constructible<CE> );
+struct A { };
+static_assert( std::default_constructible<A> );
+union B { };
+static_assert( std::constructible_from<B> );
+
+struct C
+{
+ C(void* = nullptr) { }
+ ~C() noexcept(false) { }
+};
+static_assert( !std::default_constructible<C> );
+
+class D
+{
+public:
+ D() { }
+ D(int) { }
+private:
+ ~D() { }
+};
+static_assert( !std::default_constructible<D> );
diff --git a/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.derived/1.cc b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.derived/1.cc
new file mode 100644
index 00000000000..f376aee7ee4
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.derived/1.cc
@@ -0,0 +1,50 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <concepts>
+
+static_assert( !std::derived_from<int, int> );
+static_assert( !std::derived_from<int&, int> );
+static_assert( !std::derived_from<int, int&> );
+static_assert( !std::derived_from<int&&, int&> );
+static_assert( !std::derived_from<const int, int> );
+static_assert( !std::derived_from<const int, const int> );
+
+struct A { };
+static_assert( std::derived_from<A, A> );
+static_assert( std::derived_from<A, const A> );
+static_assert( std::derived_from<A const, const A> );
+static_assert( std::derived_from<volatile A, const A> );
+
+struct B : A { };
+static_assert( !std::derived_from<A, B> );
+static_assert( std::derived_from<B, A> );
+static_assert( std::derived_from<const B, A> );
+static_assert( std::derived_from<B, const A> );
+static_assert( std::derived_from<volatile B, const A> );
+
+struct C : private A { };
+static_assert( !std::derived_from<A, C> );
+static_assert( !std::derived_from<C, A> );
+
+struct D : A { };
+struct E : B, D { };
+static_assert( !std::derived_from<A, E> );
+static_assert( !std::derived_from<E, A> );
diff --git a/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.destructible/1.cc b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.destructible/1.cc
new file mode 100644
index 00000000000..279072aa4c8
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.destructible/1.cc
@@ -0,0 +1,57 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <concepts>
+
+static_assert( !std::destructible<void> );
+static_assert( std::destructible<char> );
+static_assert( std::destructible<float> );
+static_assert( std::destructible<int*> );
+static_assert( std::destructible<int&> );
+static_assert( std::destructible<int&&> );
+static_assert( std::destructible<const int&> );
+static_assert( !std::destructible<int[]> );
+static_assert( std::destructible<int[2]> );
+static_assert( !std::destructible<int()> );
+static_assert( std::destructible<int(*)()> );
+static_assert( std::destructible<int(&)()> );
+
+enum E { };
+static_assert( std::destructible<E> );
+enum class CE { };
+static_assert( std::destructible<CE> );
+struct A { };
+static_assert( std::destructible<A> );
+union B { };
+static_assert( std::destructible<B> );
+
+struct C
+{
+ ~C() noexcept(false) { }
+};
+static_assert( !std::destructible<C> );
+class D
+{
+public:
+ D() { }
+private:
+ ~D() { }
+};
+static_assert( !std::destructible<D> );
diff --git a/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.moveconstructible/1.cc b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.moveconstructible/1.cc
new file mode 100644
index 00000000000..9bdf87bcaa2
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.moveconstructible/1.cc
@@ -0,0 +1,63 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <concepts>
+
+static_assert( !std::move_constructible<void> );
+static_assert( std::move_constructible<void*> );
+static_assert( std::move_constructible<const void*> );
+static_assert( std::move_constructible<char> );
+static_assert( std::move_constructible<const float> );
+static_assert( std::move_constructible<int*> );
+static_assert( std::move_constructible<int&> );
+static_assert( std::move_constructible<int&&> );
+static_assert( std::move_constructible<const int&> );
+static_assert( !std::move_constructible<int[]> );
+static_assert( !std::move_constructible<int[2]> );
+static_assert( !std::move_constructible<int()> );
+static_assert( std::move_constructible<int(*)()> );
+static_assert( std::move_constructible<int(&)()> );
+static_assert( std::move_constructible<int(&)() noexcept> );
+
+enum E { };
+static_assert( std::move_constructible<E> );
+enum class CE { };
+static_assert( std::move_constructible<CE> );
+struct A { };
+static_assert( std::move_constructible<A> );
+union B { };
+static_assert( std::move_constructible<B> );
+
+struct C
+{
+ C(void* = nullptr) { }
+ ~C() noexcept(false) { }
+};
+static_assert( !std::move_constructible<C> );
+
+class D
+{
+public:
+ D() { }
+ D(int) { }
+private:
+ ~D() { }
+};
+static_assert( !std::move_constructible<D> );
diff --git a/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.same/1.cc b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.same/1.cc
new file mode 100644
index 00000000000..dfb66f4df9a
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.same/1.cc
@@ -0,0 +1,66 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <concepts>
+
+static_assert( std::same_as<int, int> );
+static_assert( !std::same_as<int&, int> );
+static_assert( !std::same_as<int, int&> );
+static_assert( !std::same_as<int&&, int&> );
+static_assert( !std::same_as<const int, int> );
+static_assert( std::same_as<const int, const int> );
+
+struct A { };
+static_assert( std::same_as<A, A> );
+static_assert( !std::same_as<A, const A> );
+static_assert( std::same_as<A const, const A> );
+static_assert( !std::same_as<volatile A, const A> );
+
+struct B : A { };
+static_assert( !std::same_as<A, B> );
+
+template<typename T, typename U>
+ constexpr int
+ check_subsumption()
+ { return 0; }
+
+template<typename T, typename U>
+ requires std::same_as<T, U>
+ constexpr int
+ check_subsumption()
+ { return 1; }
+
+template<typename T, typename U>
+ requires std::same_as<U, T> && std::is_const_v<T>
+ constexpr int
+ check_subsumption()
+ { return 2; }
+
+template<typename T, typename U>
+ requires std::same_as<U, T> && std::is_volatile_v<T>
+ constexpr int
+ check_subsumption()
+ { return 3; }
+
+static_assert( check_subsumption<short, long>() == 0 );
+static_assert( check_subsumption<unsigned, unsigned>() == 1 );
+// These will be ambiguous if same_as<T,U> doesn't subsume same_as<U,T>:
+static_assert( check_subsumption<const char, const char>() == 2 );
+static_assert( check_subsumption<volatile int, volatile int>() == 3 );
diff --git a/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.swappable/swap.cc b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.swappable/swap.cc
new file mode 100644
index 00000000000..0b7f28cc6fb
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.swappable/swap.cc
@@ -0,0 +1,78 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <concepts>
+
+namespace nu
+{
+ struct S { bool swapped = false; };
+ constexpr void swap(S& l, S& r) { l.swapped = r.swapped = true; }
+ struct T { int i; };
+
+ union U { char c; int i; };
+ constexpr void swap(U& l, U& r) { l.i = r.i = 99; }
+}
+
+constexpr bool check_struct_with_adl_swap(int i)
+{
+ nu::S s1, s2;
+ std::ranges::swap(s1, s2);
+ return s1.swapped && s2.swapped;
+}
+
+static_assert(check_struct_with_adl_swap(1));
+
+constexpr bool check_array_with_adl_swap(int i)
+{
+ nu::S s1[2], s2[2];
+ std::ranges::swap(s1, s2);
+ return s1[0].swapped && s2[0].swapped && s1[1].swapped && s2[1].swapped;
+}
+
+static_assert(check_array_with_adl_swap(1));
+
+constexpr bool check_struct_without_adl_swap(int i)
+{
+ nu::T t1{i}, t2{2*i};
+ std::ranges::swap(t1, t2);
+ return t1.i == 2*i && t2.i == i;
+}
+
+static_assert(check_struct_without_adl_swap(1));
+
+constexpr bool check_array_without_adl_swap(int i)
+{
+ nu::T t1[2]{i, 2*i}, t2[2]{3*i, 4*i};
+ std::ranges::swap(t1, t2);
+ return t1[0].i == 3*i && t2[0].i == i && t1[1].i == 4*i && t2[1].i == 2*i;
+}
+
+static_assert(check_array_without_adl_swap(1));
+
+
+constexpr bool check_union_with_adl_swap(int i)
+{
+ nu::U u1{}, u2{};
+ u1.i = u2.i = i;
+ std::ranges::swap(u1, u2);
+ return u1.i == 99 && u2.i == 99;
+}
+
+static_assert(check_union_with_adl_swap(1));
diff --git a/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.swappable/swappable.cc b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.swappable/swappable.cc
new file mode 100644
index 00000000000..b5a302468db
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.swappable/swappable.cc
@@ -0,0 +1,38 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <concepts>
+
+namespace nu
+{
+ struct S { bool swapped = false; };
+ constexpr void swap(S& l, S& r) { }
+ struct T { int i; };
+
+ union U { char c; int i; };
+ constexpr void swap(U& l, U& r) { }
+}
+
+static_assert( std::swappable<nu::S> );
+static_assert( !std::swappable<const nu::S> );
+static_assert( std::swappable<nu::T> );
+static_assert( !std::swappable<const nu::T> );
+static_assert( std::swappable<nu::U> );
+static_assert( !std::swappable<const nu::U> );
diff --git a/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.swappable/swappable_with.cc b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.swappable/swappable_with.cc
new file mode 100644
index 00000000000..7d1147fdf7b
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.swappable/swappable_with.cc
@@ -0,0 +1,80 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <concepts>
+
+static_assert( std::swappable_with<int&, int&> );
+static_assert( ! std::swappable_with<int, int> );
+static_assert( ! std::swappable_with<int*, int*> );
+static_assert( ! std::swappable_with<int&, const int&> );
+static_assert( ! std::swappable_with<const int&, const int&> );
+static_assert( ! std::swappable_with<int&, long&> );
+
+namespace N1
+{
+ struct Immovable
+ {
+ Immovable() = default;
+ Immovable(Immovable&&) = delete;
+ };
+}
+static_assert( ! std::swappable_with<N1::Immovable&, N1::Immovable&> );
+
+namespace N2
+{
+ struct Swappable
+ {
+ Swappable() = default;
+ Swappable(Swappable&&) = delete;
+ friend void swap(Swappable&, Swappable&) { }
+ };
+}
+static_assert( std::swappable_with<N2::Swappable&, N2::Swappable&> );
+
+namespace N3
+{
+ struct A { };
+ struct Proxy {
+ Proxy(A&) { }
+ friend void swap(Proxy, Proxy) { }
+ };
+}
+
+static_assert( std::swappable_with<N3::A&, N3::A&> );
+static_assert( std::swappable_with<N3::A&, N3::Proxy> );
+static_assert( std::swappable_with<N3::Proxy, N3::A&> );
+static_assert( std::swappable_with<N3::Proxy, N3::Proxy> );
+
+struct C { C(int&) { } };
+void swap(int&, C&) { } // not symmetrical
+static_assert( ! std::swappable_with<int, C> );
+static_assert( ! std::swappable_with<C, int> );
+
+struct D { D(int&) { } };
+void swap(int&, D&) { }
+void swap(D&&, int&) { } // only accepts rvalues
+static_assert( ! std::swappable_with<int&, D> );
+static_assert( ! std::swappable_with<D, int> );
+
+struct E { E(int&) { } };
+void swap(int, E&&) { } // only accepts rvalues
+void swap(E&, int) { }
+static_assert( ! std::swappable_with<int, E> );
+static_assert( ! std::swappable_with<E, int> );
diff --git a/libstdc++-v3/testsuite/std/concepts/concepts.object/copyable.cc b/libstdc++-v3/testsuite/std/concepts/concepts.object/copyable.cc
new file mode 100644
index 00000000000..abb16895eb6
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/concepts/concepts.object/copyable.cc
@@ -0,0 +1,108 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <concepts>
+
+static_assert( std::copyable<int> );
+static_assert( std::copyable<int*> );
+static_assert( ! std::copyable<int&> );
+static_assert( ! std::copyable<void> );
+static_assert( ! std::copyable<void()> );
+static_assert( ! std::copyable<void() noexcept> );
+static_assert( ! std::copyable<void() const> );
+
+struct Trivial { };
+static_assert( std::copyable<Trivial> );
+
+struct NotTrivial
+{
+ NotTrivial(int) { }
+ NotTrivial(const NotTrivial&) { }
+ NotTrivial& operator=(const NotTrivial&) { return *this; }
+ ~NotTrivial() { }
+};
+static_assert( std::copyable<NotTrivial> );
+
+namespace N1
+{
+ struct Immovable
+ {
+ Immovable() = default;
+ Immovable(Immovable&&) = delete;
+ };
+}
+static_assert( ! std::copyable<N1::Immovable> );
+
+struct Movable
+{
+ Movable() = default;
+ Movable(Movable&&) = default;
+ Movable& operator=(Movable&&) = default;
+};
+static_assert( ! std::copyable<Movable> );
+
+struct MovableAndCopyAssignable
+{
+ MovableAndCopyAssignable() = default;
+ MovableAndCopyAssignable(MovableAndCopyAssignable&&) = default;
+ MovableAndCopyAssignable& operator=(MovableAndCopyAssignable&&) = default;
+ MovableAndCopyAssignable& operator=(const MovableAndCopyAssignable&) = default;
+};
+static_assert( ! std::copyable<MovableAndCopyAssignable> );
+
+struct MovableAndCopyConstructible
+{
+ MovableAndCopyConstructible() = default;
+ MovableAndCopyConstructible(MovableAndCopyConstructible&&) = default;
+ MovableAndCopyConstructible(const MovableAndCopyConstructible&) = default;
+ MovableAndCopyConstructible& operator=(MovableAndCopyConstructible&&) = default;
+};
+static_assert( ! std::copyable<MovableAndCopyConstructible> );
+
+namespace N2
+{
+ struct Swappable
+ {
+ Swappable() = default;
+ Swappable(Swappable&&) = default;
+ friend void swap(Swappable&, Swappable&) { }
+ };
+}
+static_assert( ! std::copyable<N2::Swappable> );
+
+struct NotAssignable
+{
+ NotAssignable() = default;
+ NotAssignable(NotAssignable&&) = default;
+ NotAssignable& operator=(NotAssignable&&) = default;
+ NotAssignable(const NotAssignable&) = default;
+ NotAssignable& operator=(const NotAssignable&) = delete;
+ friend void swap(NotAssignable&, NotAssignable&) { }
+};
+static_assert( ! std::copyable<NotAssignable> );
+
+struct NotSwappable
+{
+ NotSwappable() = default;
+ NotSwappable(const NotSwappable&) = default;
+ NotSwappable& operator=(const NotSwappable&) = default;
+};
+void swap(NotSwappable&, NotSwappable&) = delete;
+static_assert( std::copyable<NotSwappable> ); // ranges::swap still works!
diff --git a/libstdc++-v3/testsuite/std/concepts/concepts.object/movable.cc b/libstdc++-v3/testsuite/std/concepts/concepts.object/movable.cc
new file mode 100644
index 00000000000..48fddc1e113
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/concepts/concepts.object/movable.cc
@@ -0,0 +1,81 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <concepts>
+
+static_assert( std::movable<int> );
+static_assert( std::movable<int*> );
+static_assert( ! std::movable<int&> );
+static_assert( ! std::movable<void> );
+static_assert( ! std::movable<void()> );
+static_assert( ! std::movable<void() noexcept> );
+static_assert( ! std::movable<void() const> );
+
+struct Trivial { };
+static_assert( std::movable<Trivial> );
+
+struct NotTrivial
+{
+ NotTrivial(int) { }
+ NotTrivial(NotTrivial&&) { }
+ NotTrivial& operator=(NotTrivial&&) { return *this; }
+ ~NotTrivial() { }
+};
+static_assert( std::movable<NotTrivial> );
+
+namespace N1
+{
+ struct Immovable
+ {
+ Immovable() = default;
+ Immovable(Immovable&&) = delete;
+ };
+}
+static_assert( ! std::movable<N1::Immovable> );
+
+namespace N2
+{
+ struct Swappable
+ {
+ Swappable() = default;
+ Swappable(Swappable&&) = delete;
+ Swappable& operator=(Swappable&&) = default;
+ friend void swap(Swappable&, Swappable&) { }
+ };
+}
+static_assert( ! std::movable<N2::Swappable> );
+
+struct NotAssignable
+{
+ NotAssignable() = default;
+ NotAssignable(NotAssignable&&) = default;
+ NotAssignable& operator=(NotAssignable&&) = delete;
+ friend void swap(NotAssignable&, NotAssignable&) { }
+};
+static_assert( ! std::movable<NotAssignable> );
+
+struct NotSwappable
+{
+ NotSwappable() = default;
+ NotSwappable(NotSwappable&&) = default;
+ NotSwappable& operator=(NotSwappable&&) = default;
+};
+void swap(NotSwappable&, NotSwappable&) = delete;
+static_assert( std::movable<NotSwappable> ); // ranges::swap still works!
diff --git a/libstdc++-v3/testsuite/std/concepts/concepts.object/regular.cc b/libstdc++-v3/testsuite/std/concepts/concepts.object/regular.cc
new file mode 100644
index 00000000000..338cf1ba32c
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/concepts/concepts.object/regular.cc
@@ -0,0 +1,64 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <concepts>
+
+static_assert( std::regular<int> );
+static_assert( std::regular<int*> );
+static_assert( ! std::regular<int&> );
+static_assert( ! std::regular<void> );
+static_assert( ! std::regular<void()> );
+static_assert( ! std::regular<void() noexcept> );
+static_assert( ! std::regular<void() const> );
+
+struct Trivial { };
+static_assert( ! std::regular<Trivial> );
+
+struct NotTrivial
+{
+ NotTrivial() { }
+ ~NotTrivial() { }
+};
+static_assert( ! std::regular<NotTrivial> );
+
+struct NotDefaultConstructible
+{
+ NotDefaultConstructible(int) { }
+};
+static_assert( ! std::regular<NotDefaultConstructible> );
+
+struct HasReference
+{
+ int& ref;
+};
+static_assert( ! std::regular<HasReference> );
+
+struct HasEq { };
+bool operator==(HasEq, HasEq) { return true; }
+#ifdef __cpp_lib_three_way_comparison
+static_assert( std::regular<HasEq> );
+#else
+static_assert( ! std::regular<HasEq> );
+#endif
+
+struct HasEqNeq { };
+bool operator==(HasEqNeq, HasEqNeq) { return true; }
+bool operator!=(HasEqNeq, HasEqNeq) { return false; }
+static_assert( std::regular<HasEqNeq> );
diff --git a/libstdc++-v3/testsuite/std/concepts/concepts.object/semiregular.cc b/libstdc++-v3/testsuite/std/concepts/concepts.object/semiregular.cc
new file mode 100644
index 00000000000..1e095d60194
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/concepts/concepts.object/semiregular.cc
@@ -0,0 +1,51 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <concepts>
+
+static_assert( std::semiregular<int> );
+static_assert( std::semiregular<int*> );
+static_assert( ! std::semiregular<int&> );
+static_assert( ! std::semiregular<void> );
+static_assert( ! std::semiregular<void()> );
+static_assert( ! std::semiregular<void() noexcept> );
+static_assert( ! std::semiregular<void() const> );
+
+struct Trivial { };
+static_assert( std::semiregular<Trivial> );
+
+struct NotTrivial
+{
+ NotTrivial() { }
+ ~NotTrivial() { }
+};
+static_assert( std::semiregular<NotTrivial> );
+
+struct NotDefaultConstructible
+{
+ NotDefaultConstructible(int) { }
+};
+static_assert( ! std::semiregular<NotDefaultConstructible> );
+
+struct HasReference
+{
+ int& ref;
+};
+static_assert( ! std::semiregular<HasReference> );
diff --git a/libstdc++-v3/testsuite/tr2/dynamic_bitset/cmp.cc b/libstdc++-v3/testsuite/tr2/dynamic_bitset/cmp.cc
new file mode 100644
index 00000000000..a811307c73a
--- /dev/null
+++ b/libstdc++-v3/testsuite/tr2/dynamic_bitset/cmp.cc
@@ -0,0 +1,50 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run { target c++11 } }
+
+#include <tr2/dynamic_bitset>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+ std::tr2::dynamic_bitset<> a(100);
+ std::tr2::dynamic_bitset<> b = a;
+ VERIFY( a == b );
+ b.resize(99);
+ VERIFY( a != b );
+}
+
+void
+test02()
+{
+ std::tr2::dynamic_bitset<> a(100);
+ std::tr2::dynamic_bitset<> b = a;
+ VERIFY( !(a < b) );
+ VERIFY( !(b < a) );
+ b.resize(99);
+ VERIFY( !(a < b) );
+ VERIFY( b < a );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/tr2/dynamic_bitset/cons.cc b/libstdc++-v3/testsuite/tr2/dynamic_bitset/cons.cc
new file mode 100644
index 00000000000..9e21a91ff52
--- /dev/null
+++ b/libstdc++-v3/testsuite/tr2/dynamic_bitset/cons.cc
@@ -0,0 +1,105 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run { target c++11 } }
+
+#include <tr2/dynamic_bitset>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+ std::tr2::dynamic_bitset<> a;
+ VERIFY( a.size() == 0 );
+ VERIFY( a.empty() );
+ std::tr2::dynamic_bitset<> b(1);
+ VERIFY( b.size() == 1 );
+ VERIFY( !b.empty() );
+ VERIFY( a != b );
+}
+
+void
+test02()
+{
+ std::tr2::dynamic_bitset<> a(1, 0); // { 0 }
+ std::tr2::dynamic_bitset<> b(2, 2); // { 0, 1 }
+ VERIFY( a != b );
+}
+
+void
+test03()
+{
+ std::tr2::dynamic_bitset<> a;
+ a.resize(1); // { 0 }
+ std::tr2::dynamic_bitset<> b(2, 2); // { 0, 1 }
+ VERIFY( a != b );
+}
+
+void
+test04()
+{
+ std::tr2::dynamic_bitset<> a(3, 2); // { 0, 1, 0 }
+ std::tr2::dynamic_bitset<> b(2, 2); // { 0, 1 }
+ VERIFY( a != b );
+}
+
+void
+test05()
+{
+ std::tr2::dynamic_bitset<unsigned short> a(1, 0); // { 0 }
+ std::tr2::dynamic_bitset<unsigned short> b(2, 2); // { 0, 1 }
+ VERIFY( a != b );
+}
+
+void
+test06()
+{
+ std::tr2::dynamic_bitset<unsigned short> a;
+ a.resize(1); // { 0 }
+ std::tr2::dynamic_bitset<unsigned short> b(2, 2); // { 0, 1 }
+ VERIFY( a != b );
+}
+
+void
+test07()
+{
+ std::tr2::dynamic_bitset<unsigned short> a(3, 2); // { 0, 1, 0 }
+ std::tr2::dynamic_bitset<unsigned short> b(2, 2); // { 0, 1 }
+ VERIFY( a != b );
+}
+
+void
+test08()
+{
+ std::tr2::dynamic_bitset<> a(65, -1ULL);
+ std::tr2::dynamic_bitset<> b(64, -1ULL);
+ b.push_back(0);
+ VERIFY( a == b );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+ test05();
+ test06();
+ test07();
+ test08();
+}
diff --git a/libstdc++-v3/testsuite/tr2/dynamic_bitset/copy.cc b/libstdc++-v3/testsuite/tr2/dynamic_bitset/copy.cc
new file mode 100644
index 00000000000..06bc1158a82
--- /dev/null
+++ b/libstdc++-v3/testsuite/tr2/dynamic_bitset/copy.cc
@@ -0,0 +1,55 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run { target c++11 } }
+
+#include <tr2/dynamic_bitset>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+ std::tr2::dynamic_bitset<> a(100);
+ const auto n = a.num_blocks();
+ std::tr2::dynamic_bitset<> b = a;
+ VERIFY(b.num_blocks() == n);
+ VERIFY(b.size() == 100);
+ VERIFY(a.num_blocks() == n);
+ VERIFY(a.size() == 100);
+ VERIFY(b == a);
+}
+
+void
+test02()
+{
+ std::tr2::dynamic_bitset<> a(100);
+ const auto n = a.num_blocks();
+ std::tr2::dynamic_bitset<> b;
+ b = a;
+ VERIFY(b.num_blocks() == n);
+ VERIFY(b.size() == 100);
+ VERIFY(a.num_blocks() == n);
+ VERIFY(a.size() == 100);
+ VERIFY(b == a);
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/tr2/dynamic_bitset/move.cc b/libstdc++-v3/testsuite/tr2/dynamic_bitset/move.cc
new file mode 100644
index 00000000000..ed320db300d
--- /dev/null
+++ b/libstdc++-v3/testsuite/tr2/dynamic_bitset/move.cc
@@ -0,0 +1,53 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run { target c++11 } }
+
+#include <tr2/dynamic_bitset>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+ std::tr2::dynamic_bitset<> a(100);
+ const auto n = a.num_blocks();
+ std::tr2::dynamic_bitset<> b = std::move(a);
+ VERIFY(b.num_blocks() == n);
+ VERIFY(b.size() == 100);
+ VERIFY(a.num_blocks() == 0);
+ VERIFY(a.size() == 0);
+}
+
+void
+test02()
+{
+ std::tr2::dynamic_bitset<> a(100);
+ const auto n = a.num_blocks();
+ std::tr2::dynamic_bitset<> b;
+ b = std::move(a);
+ VERIFY(b.num_blocks() == n);
+ VERIFY(b.size() == 100);
+ VERIFY(a.num_blocks() == 0);
+ VERIFY(a.size() == 0);
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/tr2/dynamic_bitset/pr92059.cc b/libstdc++-v3/testsuite/tr2/dynamic_bitset/pr92059.cc
new file mode 100644
index 00000000000..0aec1adf65b
--- /dev/null
+++ b/libstdc++-v3/testsuite/tr2/dynamic_bitset/pr92059.cc
@@ -0,0 +1,36 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run { target c++11 } }
+
+#include <tr2/dynamic_bitset>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+ // PR libstdc++/92059
+ std::tr2::dynamic_bitset<> b1(10000), b2(10000);
+ b2 = b1; // crashed on missing return
+ VERIFY( b2 == b1);
+}
+
+int
+main()
+{
+ test01();
+}