diff -Nrcpad gcc-16-20251214/ChangeLog gcc-16-20251221/ChangeLog
*** gcc-16-20251214/ChangeLog	Sun Dec 14 22:32:05 2025
--- gcc-16-20251221/ChangeLog	Sun Dec 21 22:32:05 2025
***************
*** 1,3 ****
--- 1,18 ----
+ 2025-12-19  Lewis Hyatt  <lhyatt@gmail.com>
+ 
+ 	PR bootstrap/12407
+ 	* configure.ac: Add feature to parsing of --enable-languages so that
+ 	a language can be disabled by prefixing it with a caret.
+ 	* configure: Regenerate.
+ 
+ 2025-12-17  Jeff Law  <jlaw@ventanamicro.com>
+ 
+ 	* MAINTAINERS: Use my oss.qualcomm.com address.
+ 
+ 2025-12-15  Jose E. Marchesi  <jose.marchesi@oracle.com>
+ 
+ 	* MAINTAINERS: Add myself to DCO section.
+ 
  2025-12-12  Pietro Monteiro  <pietro@sociotechnical.xyz>
  
  	* MAINTAINERS: add myself to write after approval
diff -Nrcpad gcc-16-20251214/LAST_UPDATED gcc-16-20251221/LAST_UPDATED
*** gcc-16-20251214/LAST_UPDATED	Sun Dec 14 22:32:21 2025
--- gcc-16-20251221/LAST_UPDATED	Sun Dec 21 22:32:19 2025
***************
*** 1 ****
! Obtained from git: master revision 8e23a9982fa4b885a27608825cbe326d61f20498
--- 1 ----
! Obtained from git: master revision abf3f0b24c4d07649266371c0f8f9625dff58cd3
diff -Nrcpad gcc-16-20251214/MAINTAINERS gcc-16-20251221/MAINTAINERS
*** gcc-16-20251214/MAINTAINERS	Sun Dec 14 22:32:05 2025
--- gcc-16-20251221/MAINTAINERS	Sun Dec 21 22:32:05 2025
*************** Richard Biener
*** 35,41 ****
  Richard Earnshaw                                <richard.earnshaw@arm.com>
  Jakub Jelinek                                   <jakub@redhat.com>
  Richard Kenner                                  <kenner@nyu.edu>
! Jeff Law                                        <jefflaw@qti.qualcomm.com>
  Michael Meissner                                <gnu@the-meissners.org>
  Jason Merrill                                   <jason@redhat.com>
  David S. Miller                                 <davem@redhat.com>
--- 35,41 ----
  Richard Earnshaw                                <richard.earnshaw@arm.com>
  Jakub Jelinek                                   <jakub@redhat.com>
  Richard Kenner                                  <kenner@nyu.edu>
! Jeff Law                                        <jeffrey.law@oss.qualcomm.com>
  Michael Meissner                                <gnu@the-meissners.org>
  Jason Merrill                                   <jason@redhat.com>
  David S. Miller                                 <davem@redhat.com>
*************** Prathamesh Kulkarni
*** 969,980 ****
--- 969,982 ----
  Tim Lange                                       <mail@tim-lange.me>
  Jeff Law                                        <jefflaw@qti.qualcomm.com>
  Jeff Law                                        <jeffreyalaw@gmail.com>
+ Jeff Law                                        <jeffrey.law@oss.qualcomm.com>
  Jeff Law                                        <jlaw@tachyum.com>
  Jeff Law                                        <jlaw@ventanamicro.com>
  Martin Liška                                    <martin.liska@hey.com>
  H.J. Lu                                         <hjl.tools@gmail.com>
  Yuao Ma                                         <yuao@gcc.gnu.org>
  Matthew Malcomson                               <mmalcomson@nvidia.com>
+ Jose E. Marchesi                                <jemarch@gnu.org>
  Immad Mir                                       <mir@sourceware.org>
  Gaius Mulley                                    <gaiusmod2@gmail.com>
  Shreya Munnangi                                 <smunnang@qti.qualcomm.com>
diff -Nrcpad gcc-16-20251214/MD5SUMS gcc-16-20251221/MD5SUMS
*** gcc-16-20251214/MD5SUMS	Sun Dec 14 22:32:26 2025
--- gcc-16-20251221/MD5SUMS	Sun Dec 21 22:32:24 2025
***************
*** 1,5 ****
  # This file contains the MD5 checksums of the files in the
! # gcc-16-20251214.tar.xz tarball.
  #
  # Besides verifying that all files in the tarball were correctly expanded,
  # it also can be used to determine if any files have changed since the
--- 1,5 ----
  # This file contains the MD5 checksums of the files in the
! # gcc-16-20251221.tar.xz tarball.
  #
  # Besides verifying that all files in the tarball were correctly expanded,
  # it also can be used to determine if any files have changed since the
*************** ac5a8807f431d3dab46a7425b96379e4  .gitig
*** 23,34 ****
  fe60d87048567d4fe8c8a0ed2448bcc8  COPYING.RUNTIME
  d32239bcb673463ab874e80d47fae504  COPYING3
  6a6a8e020838b23406c81b19c1d46df6  COPYING3.LIB
! 86ba1548e4b906bd760fa562c6be7635  ChangeLog
  fd4ecdf5d672efe2b0e409aca9cf9446  ChangeLog.jit
  09538b708302f1735f6fa05b622ecf5e  ChangeLog.tree-ssa
  24ab760126489e69436a43185dc3d202  INSTALL/README
! 70efcf126ce8f6472ef6b1627c5e77ca  LAST_UPDATED
! b700a43d3f580039c0f891f2a148baae  MAINTAINERS
  303dcd6947e003fbebd9a1ba06190d09  Makefile.def
  97cb7e7715d72f600061eb2b788d9978  Makefile.in
  06bb9185fc38eb1a37d9b86363018cb3  Makefile.tpl
--- 23,34 ----
  fe60d87048567d4fe8c8a0ed2448bcc8  COPYING.RUNTIME
  d32239bcb673463ab874e80d47fae504  COPYING3
  6a6a8e020838b23406c81b19c1d46df6  COPYING3.LIB
! 5381215043e80eb2bdd889902242ebe1  ChangeLog
  fd4ecdf5d672efe2b0e409aca9cf9446  ChangeLog.jit
  09538b708302f1735f6fa05b622ecf5e  ChangeLog.tree-ssa
  24ab760126489e69436a43185dc3d202  INSTALL/README
! 1aa1d3c30e25699578c67fd68e59bf6c  LAST_UPDATED
! 6ee7d877589ec941194b43f62471d36e  MAINTAINERS
  303dcd6947e003fbebd9a1ba06190d09  Makefile.def
  97cb7e7715d72f600061eb2b788d9978  Makefile.in
  06bb9185fc38eb1a37d9b86363018cb3  Makefile.tpl
*************** e2dc6b4fd62b77bff96b7951ef74f78f  config
*** 155,163 ****
  7ef51b0adb98e5c5f7aba46d2c7293f1  config/weakref.m4
  0163b672c888aaf1c8ad3e867a0ec9f1  config/zlib.m4
  db74a73c3c9c3cc71edec37c2436e082  config/zstd.m4
! f9b6d608238df07c76634c78009afa33  configure
! 03778937a9f2ba52fd4dc7a290281c17  configure.ac
! 97c5a20fb7666f4819c268ad137f6f56  contrib/ChangeLog
  5fc435c7928f858246df931ea3f3ece7  contrib/ChangeLog.jit
  7af8d2979bf1a7cfa88e30d05fa22be2  contrib/ChangeLog.tree-ssa
  13605e5ba7b533ecbe3a902b8ebe4079  contrib/analyze_brprob.py
--- 155,163 ----
  7ef51b0adb98e5c5f7aba46d2c7293f1  config/weakref.m4
  0163b672c888aaf1c8ad3e867a0ec9f1  config/zlib.m4
  db74a73c3c9c3cc71edec37c2436e082  config/zstd.m4
! 0b6010fb983df11ebb5c12f5c5dc8eb2  configure
! 009d477c9585e404e95af2bca3f1078f  configure.ac
! 65bd146a1c83dec54eb92a4358fba1b4  contrib/ChangeLog
  5fc435c7928f858246df931ea3f3ece7  contrib/ChangeLog.jit
  7af8d2979bf1a7cfa88e30d05fa22be2  contrib/ChangeLog.tree-ssa
  13605e5ba7b533ecbe3a902b8ebe4079  contrib/analyze_brprob.py
*************** dc562ddb86567c65e82953825713dc4b  contri
*** 334,340 ****
  0ef1f0f3b8112a12de68f806daf96994  contrib/relpath.sh
  5e4ee087708d8039fdd3e37392496a3f  contrib/repro_fail
  7a4452f82f140141ca92ef50ae08afe8  contrib/sarif-listener.py
! 23c8b71db40d950898670626c11e563b  contrib/test_installed
  b60f03a88bd6e5db8ea8361daec256ea  contrib/test_mklog.py
  2c2a06a23394c548bb4afba3c25aacce  contrib/test_recheck
  c650e776de65a2de80bbfb0033641805  contrib/test_summary
--- 334,340 ----
  0ef1f0f3b8112a12de68f806daf96994  contrib/relpath.sh
  5e4ee087708d8039fdd3e37392496a3f  contrib/repro_fail
  7a4452f82f140141ca92ef50ae08afe8  contrib/sarif-listener.py
! 54653f415e3cc68669f9053dd8b05a8b  contrib/test_installed
  b60f03a88bd6e5db8ea8361daec256ea  contrib/test_mklog.py
  2c2a06a23394c548bb4afba3c25aacce  contrib/test_recheck
  c650e776de65a2de80bbfb0033641805  contrib/test_summary
*************** a22e70b3f29292d0e628450f4bb11e62  fixinc
*** 521,527 ****
  a916467b91076e631dd8edb7424769c7  gcc/COPYING.LIB
  d32239bcb673463ab874e80d47fae504  gcc/COPYING3
  6a6a8e020838b23406c81b19c1d46df6  gcc/COPYING3.LIB
! 1804c6d0ee0503acd051f359103bebe0  gcc/ChangeLog
  51281e73aa07fb62394bd72f3c9299ba  gcc/ChangeLog-1997
  f77af8c9ac412064886b00c5506123b5  gcc/ChangeLog-1998
  00a2e4ead1b289bf69bca0196fed6f9f  gcc/ChangeLog-1999
--- 521,527 ----
  a916467b91076e631dd8edb7424769c7  gcc/COPYING.LIB
  d32239bcb673463ab874e80d47fae504  gcc/COPYING3
  6a6a8e020838b23406c81b19c1d46df6  gcc/COPYING3.LIB
! 77cc69c48d39d8968e3c7dbc2e2d1da3  gcc/ChangeLog
  51281e73aa07fb62394bd72f3c9299ba  gcc/ChangeLog-1997
  f77af8c9ac412064886b00c5506123b5  gcc/ChangeLog-1998
  00a2e4ead1b289bf69bca0196fed6f9f  gcc/ChangeLog-1999
*************** fb3fadb88e1d2b3b640cfaaa5ff11780  gcc/Ch
*** 558,576 ****
  3eb07e0b2e542409bf73d359f7f65609  gcc/ChangeLog.ptr
  e13638e26743ba41e6011b76cc00d9a9  gcc/ChangeLog.tree-ssa
  739ab47f6425bcea1d05e4fc0542de54  gcc/ChangeLog.tuples
! 41f179a3a82f2f3c35e096d9672908a0  gcc/DATESTAMP
  deb513e591f23901188e22323bd3b1d4  gcc/DEV-PHASE
  eb92e1ff5e982ca07e173e0eb286d243  gcc/FSFChangeLog
  30e1e33411566388b3164558482dc5e6  gcc/FSFChangeLog.10
  36698274bb69e2ada20f5cc434f3caa5  gcc/FSFChangeLog.11
  4dc2573d948287a3722ce977490b026c  gcc/LANGUAGES
! 0cc3e079f827fef99401f57370d28934  gcc/Makefile.in
  ec6799501b2eb2923d5de6a66169dbd2  gcc/ONEWS
  15d6908b4409b0925d9f1c72b56b5cb7  gcc/README.Portability
  ee95df275c932cada412ed8168975af9  gcc/acinclude.m4
  e74733ebf762151e601c9e0aa1461a20  gcc/aclocal.m4
  16a499934b71eb6cf7c0d6899cd6006a  gcc/ada/.gitignore
! 4323751f7958a05664920218021954b8  gcc/ada/ChangeLog
  c2094c0d3135f9ac89917f162046ee04  gcc/ada/ChangeLog-2001
  fa410b57f5d814d5d3ac3b45f486cdcf  gcc/ada/ChangeLog-2002
  2dbefa7bdc8dc28ec746002028861278  gcc/ada/ChangeLog-2003
--- 558,576 ----
  3eb07e0b2e542409bf73d359f7f65609  gcc/ChangeLog.ptr
  e13638e26743ba41e6011b76cc00d9a9  gcc/ChangeLog.tree-ssa
  739ab47f6425bcea1d05e4fc0542de54  gcc/ChangeLog.tuples
! 80eaeb503dc99d61b09368710ba0023d  gcc/DATESTAMP
  deb513e591f23901188e22323bd3b1d4  gcc/DEV-PHASE
  eb92e1ff5e982ca07e173e0eb286d243  gcc/FSFChangeLog
  30e1e33411566388b3164558482dc5e6  gcc/FSFChangeLog.10
  36698274bb69e2ada20f5cc434f3caa5  gcc/FSFChangeLog.11
  4dc2573d948287a3722ce977490b026c  gcc/LANGUAGES
! 824ac5230295c8611e2f1a432bb01789  gcc/Makefile.in
  ec6799501b2eb2923d5de6a66169dbd2  gcc/ONEWS
  15d6908b4409b0925d9f1c72b56b5cb7  gcc/README.Portability
  ee95df275c932cada412ed8168975af9  gcc/acinclude.m4
  e74733ebf762151e601c9e0aa1461a20  gcc/aclocal.m4
  16a499934b71eb6cf7c0d6899cd6006a  gcc/ada/.gitignore
! 43a94527a053439df886bcf0b5bdd2cd  gcc/ada/ChangeLog
  c2094c0d3135f9ac89917f162046ee04  gcc/ada/ChangeLog-2001
  fa410b57f5d814d5d3ac3b45f486cdcf  gcc/ada/ChangeLog-2002
  2dbefa7bdc8dc28ec746002028861278  gcc/ada/ChangeLog-2003
*************** ff29a10285881817c71f15a28a61496e  gcc/ad
*** 850,856 ****
  a74b4504c5ad4ed4e963f0691c289b40  gcc/ada/gcc-interface/system.ads
  b350a6fd65cafe8bd47dc42192437310  gcc/ada/gcc-interface/targtyps.cc
  d7f5374a67a40e0ebecaf6ba95369af1  gcc/ada/gcc-interface/trans.cc
! b78b106323d7d5be0f58c681fc4db76d  gcc/ada/gcc-interface/utils.cc
  0b638ee76fd250092e4f0077d2deb899  gcc/ada/gcc-interface/utils2.cc
  c890d810259c6c7abec61c9108498443  gcc/ada/gen_il-fields.ads
  cb6e91720726277e3f4542d2859a43b0  gcc/ada/gen_il-gen-gen_entities.adb
--- 850,856 ----
  a74b4504c5ad4ed4e963f0691c289b40  gcc/ada/gcc-interface/system.ads
  b350a6fd65cafe8bd47dc42192437310  gcc/ada/gcc-interface/targtyps.cc
  d7f5374a67a40e0ebecaf6ba95369af1  gcc/ada/gcc-interface/trans.cc
! 8a5eb8d9b0562b4cd7b4b3a7f76673ff  gcc/ada/gcc-interface/utils.cc
  0b638ee76fd250092e4f0077d2deb899  gcc/ada/gcc-interface/utils2.cc
  c890d810259c6c7abec61c9108498443  gcc/ada/gen_il-fields.ads
  cb6e91720726277e3f4542d2859a43b0  gcc/ada/gen_il-gen-gen_entities.adb
*************** a424011f3e6f5e5a1163e2a9e1324779  gcc/ad
*** 2893,2899 ****
  b1230ac9f3cae75bd98a0fc5e0fabdcf  gcc/ada/sem.ads
  35bea96899d106c6584dbdbff3268c97  gcc/ada/sem_aggr.adb
  d9e9e67a1e6554ab3bc7e11269dd3763  gcc/ada/sem_aggr.ads
! 749f57dc58f0f56e802c7b65792c7d8d  gcc/ada/sem_attr.adb
  2a239613f39312b54ea82d1e690a3ea2  gcc/ada/sem_attr.ads
  9933f6b1c6d6ebb417929ba3ed154bff  gcc/ada/sem_aux.adb
  e15b069fa2ff472febda85c8b9cacb81  gcc/ada/sem_aux.ads
--- 2893,2899 ----
  b1230ac9f3cae75bd98a0fc5e0fabdcf  gcc/ada/sem.ads
  35bea96899d106c6584dbdbff3268c97  gcc/ada/sem_aggr.adb
  d9e9e67a1e6554ab3bc7e11269dd3763  gcc/ada/sem_aggr.ads
! 48c6d5f87fb01a1edbebfe650a4c50e6  gcc/ada/sem_attr.adb
  2a239613f39312b54ea82d1e690a3ea2  gcc/ada/sem_attr.ads
  9933f6b1c6d6ebb417929ba3ed154bff  gcc/ada/sem_aux.adb
  e15b069fa2ff472febda85c8b9cacb81  gcc/ada/sem_aux.ads
*************** e096bc417315d565cb772d1957d16c3f  gcc/ad
*** 2917,2923 ****
  adba03aae1f439b9e9db8cea05d8e03f  gcc/ada/sem_ch4.ads
  67f40a13b7faf3883c09b190670b8ce2  gcc/ada/sem_ch5.adb
  ec8d5a42c27c46e4969c16d6e18ed276  gcc/ada/sem_ch5.ads
! d72f968a0de159b80d3b6a39a7827008  gcc/ada/sem_ch6.adb
  165c2ff9990d74ba204881b7983566c7  gcc/ada/sem_ch6.ads
  3883f8e98e883801346bbdd9e4ecf027  gcc/ada/sem_ch7.adb
  24a1265e6a25756265643858abcf7ded  gcc/ada/sem_ch7.ads
--- 2917,2923 ----
  adba03aae1f439b9e9db8cea05d8e03f  gcc/ada/sem_ch4.ads
  67f40a13b7faf3883c09b190670b8ce2  gcc/ada/sem_ch5.adb
  ec8d5a42c27c46e4969c16d6e18ed276  gcc/ada/sem_ch5.ads
! c6e3dfd1885f09eaa7d00801a060cf20  gcc/ada/sem_ch6.adb
  165c2ff9990d74ba204881b7983566c7  gcc/ada/sem_ch6.ads
  3883f8e98e883801346bbdd9e4ecf027  gcc/ada/sem_ch7.adb
  24a1265e6a25756265643858abcf7ded  gcc/ada/sem_ch7.ads
*************** ceaa52edf6355622601cd30f7c096b06  gcc/ad
*** 3010,3016 ****
  2ee5998b92d56bf9c5cc341e1f1ad78e  gcc/ada/switch-m.ads
  7e7afcf1b2687d2270ec21617a7bb854  gcc/ada/switch.adb
  3ce7cd08e301dd2487e065308c9e9fe9  gcc/ada/switch.ads
! 1c5f4065ed9bfb55ca7167c50baf2159  gcc/ada/sysdep.c
  69800f63276ca2e455c6b79cbfae2d07  gcc/ada/table.adb
  6749edbf6142a410672c491892a48283  gcc/ada/table.ads
  9f45bf3ee4cf0a6b06c0b5cc6a4830a7  gcc/ada/targext.c
--- 3010,3016 ----
  2ee5998b92d56bf9c5cc341e1f1ad78e  gcc/ada/switch-m.ads
  7e7afcf1b2687d2270ec21617a7bb854  gcc/ada/switch.adb
  3ce7cd08e301dd2487e065308c9e9fe9  gcc/ada/switch.ads
! 4d92ee38d0b4675a02afe03ab1416575  gcc/ada/sysdep.c
  69800f63276ca2e455c6b79cbfae2d07  gcc/ada/table.adb
  6749edbf6142a410672c491892a48283  gcc/ada/table.ads
  9f45bf3ee4cf0a6b06c0b5cc6a4830a7  gcc/ada/targext.c
*************** cc77d76c407f099273c5d6691a91f67a  gcc/ad
*** 3057,3069 ****
  a8f3f69de7abdd693a971d4655971bf7  gcc/ada/xutil.ads
  60f1f34895b64cc9a3b2d590e6cf576f  gcc/addresses.h
  df3f6c6882fc8f715d4cc537af0f6442  gcc/adjust-alignment.cc
! e5d25a7b64f4f7663769ead9921716a4  gcc/algol68/ChangeLog
  2a93a1799a2add5d7ad920f0001f7aa5  gcc/algol68/Make-lang.in
  7479907efeefafc7c6d3bc2aaa5c6a83  gcc/algol68/README
  fb43be530798e23528ffc144413b80a9  gcc/algol68/a68-diagnostics.cc
  95aea877c594908679a2057305b999c8  gcc/algol68/a68-exports.cc
! e26818bcc3bc1f737dac9cb588b14ad6  gcc/algol68/a68-imports.cc
! 6691c0e619bbdb98556bd44b6eb8bd41  gcc/algol68/a68-lang.cc
  c7f3e4b6ca328ed109839fb6af254e6b  gcc/algol68/a68-low-bits.cc
  284cf6c8827f78791575949cc1f634ef  gcc/algol68/a68-low-bools.cc
  421c70a781dc2c00722aa019bc39f683  gcc/algol68/a68-low-builtins.cc
--- 3057,3069 ----
  a8f3f69de7abdd693a971d4655971bf7  gcc/ada/xutil.ads
  60f1f34895b64cc9a3b2d590e6cf576f  gcc/addresses.h
  df3f6c6882fc8f715d4cc537af0f6442  gcc/adjust-alignment.cc
! 410c4f42d491d2f96b450be6f3ef8959  gcc/algol68/ChangeLog
  2a93a1799a2add5d7ad920f0001f7aa5  gcc/algol68/Make-lang.in
  7479907efeefafc7c6d3bc2aaa5c6a83  gcc/algol68/README
  fb43be530798e23528ffc144413b80a9  gcc/algol68/a68-diagnostics.cc
  95aea877c594908679a2057305b999c8  gcc/algol68/a68-exports.cc
! a7af5f499be1e12dd2f87e36f320b220  gcc/algol68/a68-imports.cc
! fb6568756cb89923a57a423225c4550c  gcc/algol68/a68-lang.cc
  c7f3e4b6ca328ed109839fb6af254e6b  gcc/algol68/a68-low-bits.cc
  284cf6c8827f78791575949cc1f634ef  gcc/algol68/a68-low-bools.cc
  421c70a781dc2c00722aa019bc39f683  gcc/algol68/a68-low-builtins.cc
*************** ade291f272227055db98bddb78ff715f  gcc/al
*** 3071,3081 ****
  627c624b3c087448b1669f1805501cff  gcc/algol68/a68-low-clauses.cc
  e475601178306ca722c941848f7b25d7  gcc/algol68/a68-low-coercions.cc
  5aa76e1c20ed5b89f9d01211f6bb6cc6  gcc/algol68/a68-low-complex.cc
! f7c4063a70cd0a3f31880770cd974ec2  gcc/algol68/a68-low-decls.cc
  ef61d04fdb839242c97e53b105268e52  gcc/algol68/a68-low-generator.cc
  49e9c1592266268c752da49a2ef0bbc9  gcc/algol68/a68-low-ints.cc
  949d0f0a5f79da34ba44f79c6ebfe282  gcc/algol68/a68-low-misc.cc
! c81c9137e6f6284c6a1ba0be68609895  gcc/algol68/a68-low-moids.cc
  7cff8c4f9adad0de3b4db98dc5e2039f  gcc/algol68/a68-low-multiples.cc
  1a382214dc720355d1f18b5402c6aa93  gcc/algol68/a68-low-posix.cc
  a0a1cfa2c51f6a415389792643b1d1e6  gcc/algol68/a68-low-prelude.cc
--- 3071,3081 ----
  627c624b3c087448b1669f1805501cff  gcc/algol68/a68-low-clauses.cc
  e475601178306ca722c941848f7b25d7  gcc/algol68/a68-low-coercions.cc
  5aa76e1c20ed5b89f9d01211f6bb6cc6  gcc/algol68/a68-low-complex.cc
! 8cbe6bbe58fe206a93946f3a1a42b457  gcc/algol68/a68-low-decls.cc
  ef61d04fdb839242c97e53b105268e52  gcc/algol68/a68-low-generator.cc
  49e9c1592266268c752da49a2ef0bbc9  gcc/algol68/a68-low-ints.cc
  949d0f0a5f79da34ba44f79c6ebfe282  gcc/algol68/a68-low-misc.cc
! 8e958b50675b076eba75cf460e2332bb  gcc/algol68/a68-low-moids.cc
  7cff8c4f9adad0de3b4db98dc5e2039f  gcc/algol68/a68-low-multiples.cc
  1a382214dc720355d1f18b5402c6aa93  gcc/algol68/a68-low-posix.cc
  a0a1cfa2c51f6a415389792643b1d1e6  gcc/algol68/a68-low-prelude.cc
*************** bf2e9b5dd21e1dfe9dc046812e7dd756  gcc/al
*** 3094,3100 ****
  86ee3e220ec49b15faa51baf250cf66f  gcc/algol68/a68-moids-misc.cc
  93ab5a30cda3f697bee77eba313c66d6  gcc/algol68/a68-moids-to-string.cc
  c324f111303d399ec78ee3371488176f  gcc/algol68/a68-parser-attrs.def
! e5ff07e371674982739a2c89b6f737dc  gcc/algol68/a68-parser-bottom-up.cc
  11c6e7547ee9292410a3b91692ea6ad1  gcc/algol68/a68-parser-brackets.cc
  06167f432b9437d0cc135868d1067782  gcc/algol68/a68-parser-debug.cc
  f0ccd998d854bd7f1c8c0a97fe8dfd8d  gcc/algol68/a68-parser-extract.cc
--- 3094,3100 ----
  86ee3e220ec49b15faa51baf250cf66f  gcc/algol68/a68-moids-misc.cc
  93ab5a30cda3f697bee77eba313c66d6  gcc/algol68/a68-moids-to-string.cc
  c324f111303d399ec78ee3371488176f  gcc/algol68/a68-parser-attrs.def
! 9444ab5060852dcb1ca6f21c2ef2d3d6  gcc/algol68/a68-parser-bottom-up.cc
  11c6e7547ee9292410a3b91692ea6ad1  gcc/algol68/a68-parser-brackets.cc
  06167f432b9437d0cc135868d1067782  gcc/algol68/a68-parser-debug.cc
  f0ccd998d854bd7f1c8c0a97fe8dfd8d  gcc/algol68/a68-parser-extract.cc
*************** cef52688a96e5c6b6309f823287d7460  gcc/al
*** 3103,3111 ****
  451910827918a165063a77e10deebc2a  gcc/algol68/a68-parser-moids-check.cc
  eb200628692c30c1ade0eaeabcddf008  gcc/algol68/a68-parser-moids-coerce.cc
  21df1102d7944e20f83a720318e21de8  gcc/algol68/a68-parser-moids-equivalence.cc
! 5ff1fcb1ff4985b94774b904b71582b7  gcc/algol68/a68-parser-pragmat.cc
  05804e13f2603c536bbb12fb8a5a14ff  gcc/algol68/a68-parser-prelude.cc
! 97210ee3eff2eb58ddd5146cd9bb346b  gcc/algol68/a68-parser-scanner.cc
  642248594944766b6cf1d2ee348ae403  gcc/algol68/a68-parser-scope.cc
  d259fcdbab02c9c536b330f7111ae7cf  gcc/algol68/a68-parser-serial-dsa.cc
  82335b969057c5977552639844d93cf0  gcc/algol68/a68-parser-taxes.cc
--- 3103,3111 ----
  451910827918a165063a77e10deebc2a  gcc/algol68/a68-parser-moids-check.cc
  eb200628692c30c1ade0eaeabcddf008  gcc/algol68/a68-parser-moids-coerce.cc
  21df1102d7944e20f83a720318e21de8  gcc/algol68/a68-parser-moids-equivalence.cc
! 6f1acfebba6072c81c25a2597686d0e4  gcc/algol68/a68-parser-pragmat.cc
  05804e13f2603c536bbb12fb8a5a14ff  gcc/algol68/a68-parser-prelude.cc
! df6822d94674605842ad59a947523030  gcc/algol68/a68-parser-scanner.cc
  642248594944766b6cf1d2ee348ae403  gcc/algol68/a68-parser-scope.cc
  d259fcdbab02c9c536b330f7111ae7cf  gcc/algol68/a68-parser-serial-dsa.cc
  82335b969057c5977552639844d93cf0  gcc/algol68/a68-parser-taxes.cc
*************** bb6a9492686645cd8ede63a3aa41bb2e  gcc/al
*** 3116,3137 ****
  614ee2f3c97cf1910484b4ba1b697352  gcc/algol68/a68-tree.def
  64a4d7c961501b931b15a7093ed28291  gcc/algol68/a68-types.h
  cddb33683b15b95275fe506ebd8903ca  gcc/algol68/a68-unistr.c
! f66a4bc78885fc31363bbcb594c1804f  gcc/algol68/a68.h
  cbc2ddca0589edc81c7df109b1a1927b  gcc/algol68/a68spec.cc
  661865b5bba0ac76e041c54bd958a1ef  gcc/algol68/config-lang.in
! 6877d7243fce731d111226227b06d1fe  gcc/algol68/ga68-exports.pk
  f150e2c760036b980e94ec7bb14e1172  gcc/algol68/ga68-internals.texi
! 6f8f9154450672d1634858a815ea819e  gcc/algol68/ga68.texi
  4810fa1d976ad329fa7a115292ce8fe8  gcc/algol68/ga68.vw
  0a91d85c360d5ee3eb6258aecdab4636  gcc/algol68/lang-specs.h
! 325fb18926c663a69528644401707a7e  gcc/algol68/lang.opt
! 70bc70fd00e76244f79d55d14e1eea1d  gcc/algol68/lang.opt.urls
! 22e67419538a3230a4cff638bb5a068b  gcc/alias.cc
  0d0b7a8d67ab4391dba470baf07f7ad4  gcc/alias.h
  a13250e9011949e791f210139f4c4323  gcc/align.h
  192d075c6984da6ef1e282fd63829079  gcc/alloc-pool.cc
  b2194a7136db5f26272ca6162d858997  gcc/alloc-pool.h
! 1c79bd86f666031ae8f5653ac344f15f  gcc/analyzer/ChangeLog
  99ca8e9358149d619a543e45725f689f  gcc/analyzer/access-diagram.cc
  58f352acafda673d24da4113c4f80b8d  gcc/analyzer/access-diagram.h
  d3f3112562b7552a583d7d995ed2f2d1  gcc/analyzer/ana-state-to-diagnostic-state.cc
--- 3116,3137 ----
  614ee2f3c97cf1910484b4ba1b697352  gcc/algol68/a68-tree.def
  64a4d7c961501b931b15a7093ed28291  gcc/algol68/a68-types.h
  cddb33683b15b95275fe506ebd8903ca  gcc/algol68/a68-unistr.c
! 77b43dcdee1cd2188eef4f682069b824  gcc/algol68/a68.h
  cbc2ddca0589edc81c7df109b1a1927b  gcc/algol68/a68spec.cc
  661865b5bba0ac76e041c54bd958a1ef  gcc/algol68/config-lang.in
! 3944dc558e8139d69cdc73ffdbe90cc7  gcc/algol68/ga68-exports.pk
  f150e2c760036b980e94ec7bb14e1172  gcc/algol68/ga68-internals.texi
! f06c8907496307c081014f5c878b6583  gcc/algol68/ga68.texi
  4810fa1d976ad329fa7a115292ce8fe8  gcc/algol68/ga68.vw
  0a91d85c360d5ee3eb6258aecdab4636  gcc/algol68/lang-specs.h
! e8f055cedd169c6d7c4de52b26b93634  gcc/algol68/lang.opt
! 411f26970a0d93b07c697a1bcfeda50c  gcc/algol68/lang.opt.urls
! 7b31a8c9a91aaaa010fd9faebc6682a5  gcc/alias.cc
  0d0b7a8d67ab4391dba470baf07f7ad4  gcc/alias.h
  a13250e9011949e791f210139f4c4323  gcc/align.h
  192d075c6984da6ef1e282fd63829079  gcc/alloc-pool.cc
  b2194a7136db5f26272ca6162d858997  gcc/alloc-pool.h
! cc550247f662e02127eb31863fae0723  gcc/analyzer/ChangeLog
  99ca8e9358149d619a543e45725f689f  gcc/analyzer/access-diagram.cc
  58f352acafda673d24da4113c4f80b8d  gcc/analyzer/access-diagram.h
  d3f3112562b7552a583d7d995ed2f2d1  gcc/analyzer/ana-state-to-diagnostic-state.cc
*************** a82a71ab7f96ca02b70fd75fd951ea5f  gcc/an
*** 3159,3166 ****
  a131be41d45ef61144679e37411d8b5e  gcc/analyzer/call-string.h
  498b92c06e997fb220e232350ec7ff41  gcc/analyzer/call-summary.cc
  bc77cd1e5aec40e5623c49cb8974b3d4  gcc/analyzer/call-summary.h
! 5efec15bdf190aa8b75b249fc7ca4b24  gcc/analyzer/checker-event.cc
! 4e8eb0f192c1be7b8e6476a0fe50d2d2  gcc/analyzer/checker-event.h
  3ab3510c119841ad20bbfcab82653f7c  gcc/analyzer/checker-path.cc
  717c8ea5a0fcd626c448dd37a593cfda  gcc/analyzer/checker-path.h
  e685d4762247bcb6c8ce6983c7332b3a  gcc/analyzer/common.h
--- 3159,3166 ----
  a131be41d45ef61144679e37411d8b5e  gcc/analyzer/call-string.h
  498b92c06e997fb220e232350ec7ff41  gcc/analyzer/call-summary.cc
  bc77cd1e5aec40e5623c49cb8974b3d4  gcc/analyzer/call-summary.h
! db7ae1e99659ad01eb6c7bc92b1ffdb6  gcc/analyzer/checker-event.cc
! 8796e3df3d213b3891c8de4b9e10303e  gcc/analyzer/checker-event.h
  3ab3510c119841ad20bbfcab82653f7c  gcc/analyzer/checker-path.cc
  717c8ea5a0fcd626c448dd37a593cfda  gcc/analyzer/checker-path.h
  e685d4762247bcb6c8ce6983c7332b3a  gcc/analyzer/common.h
*************** e685d4762247bcb6c8ce6983c7332b3a  gcc/an
*** 3170,3176 ****
  de3e24210b7d7d058b9fa4197b5e3a52  gcc/analyzer/constraint-manager.h
  d0e6383909772d9e78df0a42ddc85589  gcc/analyzer/diagnostic-manager.cc
  4e59d9dab4492a2c6d76c1ba5b3d087d  gcc/analyzer/diagnostic-manager.h
! 29bfe45fac20fa31da0e1d11c3c6d461  gcc/analyzer/engine.cc
  acc1f4f20384df654fa365f64ad6a6f9  gcc/analyzer/engine.h
  dccc2d81d8b2122311176d2a595de8b5  gcc/analyzer/event-loc-info.h
  6e0c1059e9207dc0659b0564f1817b06  gcc/analyzer/exploded-graph.h
--- 3170,3176 ----
  de3e24210b7d7d058b9fa4197b5e3a52  gcc/analyzer/constraint-manager.h
  d0e6383909772d9e78df0a42ddc85589  gcc/analyzer/diagnostic-manager.cc
  4e59d9dab4492a2c6d76c1ba5b3d087d  gcc/analyzer/diagnostic-manager.h
! c99ca30b2fb6d07403c04f48756dc89b  gcc/analyzer/engine.cc
  acc1f4f20384df654fa365f64ad6a6f9  gcc/analyzer/engine.h
  dccc2d81d8b2122311176d2a595de8b5  gcc/analyzer/event-loc-info.h
  6e0c1059e9207dc0659b0564f1817b06  gcc/analyzer/exploded-graph.h
*************** bba160592a366830aa43a07e0e86118d  gcc/an
*** 3187,3194 ****
  6ff38999d2e80d0b4777aa487dbf4649  gcc/analyzer/kf.cc
  b1767c404b2a466ceeb581380c8a81fe  gcc/analyzer/known-function-manager.cc
  03a32d089b911aa5389a2b9006795f83  gcc/analyzer/known-function-manager.h
! cb424e016e5823aa62505cae534209ff  gcc/analyzer/ops.cc
! 81e3dc98cc103c9dc391fa286f20b362  gcc/analyzer/ops.h
  bfcb1ad4fb40d42049006f2257dd78f2  gcc/analyzer/pending-diagnostic.cc
  ecdcea18317dc8e6d682f70a597795c8  gcc/analyzer/pending-diagnostic.h
  cf7a2630a3efe6938fcb2c3481ed5632  gcc/analyzer/program-point.cc
--- 3187,3194 ----
  6ff38999d2e80d0b4777aa487dbf4649  gcc/analyzer/kf.cc
  b1767c404b2a466ceeb581380c8a81fe  gcc/analyzer/known-function-manager.cc
  03a32d089b911aa5389a2b9006795f83  gcc/analyzer/known-function-manager.h
! 5c413467e156a93b778b9bd38dafc58d  gcc/analyzer/ops.cc
! 9b84efd707865ea0abaa3dc5d033405e  gcc/analyzer/ops.h
  bfcb1ad4fb40d42049006f2257dd78f2  gcc/analyzer/pending-diagnostic.cc
  ecdcea18317dc8e6d682f70a597795c8  gcc/analyzer/pending-diagnostic.h
  cf7a2630a3efe6938fcb2c3481ed5632  gcc/analyzer/program-point.cc
*************** f0acfecca8767075f2b2e9bc04089741  gcc/an
*** 3201,3212 ****
  59f0552f76cf621495df906f2db01f93  gcc/analyzer/record-layout.cc
  57354826ca1c448180149706333f891f  gcc/analyzer/record-layout.h
  e1490c2bf5b3d5b5a3fec56291595d0b  gcc/analyzer/region-model-asm.cc
! f7c2233b01a49c3ce8e881a91c1137d5  gcc/analyzer/region-model-manager.cc
  1594543b67f312531d1d40036536b341  gcc/analyzer/region-model-manager.h
  41f9d87a517295eec94a690a02e74027  gcc/analyzer/region-model-reachability.cc
  34ab719ce08057bb88f8bf20e7c3c959  gcc/analyzer/region-model-reachability.h
! b933ffcd35983b36d0c410c410f8e72c  gcc/analyzer/region-model.cc
! f4c774583fb0ce97114659e550904681  gcc/analyzer/region-model.h
  5ad0cc8e3f7fed3aed96be1f7f85fe35  gcc/analyzer/region.cc
  1ea9c46e24a4c830bab76a9ddf0ffa3f  gcc/analyzer/region.h
  99fb5faee40376b23c3240ca70ea1e47  gcc/analyzer/sm-fd.cc
--- 3201,3212 ----
  59f0552f76cf621495df906f2db01f93  gcc/analyzer/record-layout.cc
  57354826ca1c448180149706333f891f  gcc/analyzer/record-layout.h
  e1490c2bf5b3d5b5a3fec56291595d0b  gcc/analyzer/region-model-asm.cc
! 00d26a96bdc5cdf413cbfa06e0802f25  gcc/analyzer/region-model-manager.cc
  1594543b67f312531d1d40036536b341  gcc/analyzer/region-model-manager.h
  41f9d87a517295eec94a690a02e74027  gcc/analyzer/region-model-reachability.cc
  34ab719ce08057bb88f8bf20e7c3c959  gcc/analyzer/region-model-reachability.h
! 68c47ab0ed863da26483bde75c03bd8d  gcc/analyzer/region-model.cc
! daca854b246726996da872a7288990b2  gcc/analyzer/region-model.h
  5ad0cc8e3f7fed3aed96be1f7f85fe35  gcc/analyzer/region.cc
  1ea9c46e24a4c830bab76a9ddf0ffa3f  gcc/analyzer/region.h
  99fb5faee40376b23c3240ca70ea1e47  gcc/analyzer/sm-fd.cc
*************** bf7ec9c334de642875bc0af7d64fd755  gcc/an
*** 3225,3235 ****
  c0ba7967d47112ed257f449227aa6b76  gcc/analyzer/state-purge.h
  dd9996afff455863987249435c4c2812  gcc/analyzer/store.cc
  443f4aa63dd0b4df7041a7f547343650  gcc/analyzer/store.h
! 09fd7f23eba0ea31da5b5093f4a4db95  gcc/analyzer/supergraph-fixup-locations.cc
  4f8ed66df3958837a577f47c80ac79cd  gcc/analyzer/supergraph-manipulation.h
  c5d61f8a7ee5ddd8a09e70002b6beb5d  gcc/analyzer/supergraph-simplify.cc
! 6e23546be75f9f07a966259c12f9257c  gcc/analyzer/supergraph-sorting.cc
! d8cfe76fc1d575e7e01aaa415df050a8  gcc/analyzer/supergraph.cc
  ef11c2ace82389357ac6a8055a7319e7  gcc/analyzer/supergraph.h
  1d41c9be8b0944f10ffd41e881e94fea  gcc/analyzer/svalue.cc
  2d02f3c1fd4a2ffd8217d6a22472a961  gcc/analyzer/svalue.h
--- 3225,3235 ----
  c0ba7967d47112ed257f449227aa6b76  gcc/analyzer/state-purge.h
  dd9996afff455863987249435c4c2812  gcc/analyzer/store.cc
  443f4aa63dd0b4df7041a7f547343650  gcc/analyzer/store.h
! 5c7fa5859cc9f1c2e2c2548ef9b7a68a  gcc/analyzer/supergraph-fixup-locations.cc
  4f8ed66df3958837a577f47c80ac79cd  gcc/analyzer/supergraph-manipulation.h
  c5d61f8a7ee5ddd8a09e70002b6beb5d  gcc/analyzer/supergraph-simplify.cc
! d26a8c1823063a26a7ee67ec16294817  gcc/analyzer/supergraph-sorting.cc
! bf91b6ce4291c9e6ea2ac33f76ce7e80  gcc/analyzer/supergraph.cc
  ef11c2ace82389357ac6a8055a7319e7  gcc/analyzer/supergraph.h
  1d41c9be8b0944f10ffd41e881e94fea  gcc/analyzer/svalue.cc
  2d02f3c1fd4a2ffd8217d6a22472a961  gcc/analyzer/svalue.h
*************** c60f1ef3d02e040c88d9e217de84ee81  gcc/an
*** 3240,3247 ****
  fdc820ba8335a1c10f8e08c581379570  gcc/analyzer/varargs.cc
  cc81acb908eb9d6b13038a95c3a10a9c  gcc/analyzer/varargs.dot
  eeb42b412edc2884a4c60d6f38f7473b  gcc/array-traits.h
! 6abcb9777280c69da14835a391a5c347  gcc/asan.cc
! 135df8f25422fc20afd9efad9dffdd54  gcc/asan.h
  a350e0e702ef2468ff3c700dff5b7433  gcc/attr-callback.cc
  0ec27d414707ba546fed401eaaf2af22  gcc/attr-callback.h
  8eabb720cd45c245a7d1be51c0f744ca  gcc/attr-fnspec.h
--- 3240,3247 ----
  fdc820ba8335a1c10f8e08c581379570  gcc/analyzer/varargs.cc
  cc81acb908eb9d6b13038a95c3a10a9c  gcc/analyzer/varargs.dot
  eeb42b412edc2884a4c60d6f38f7473b  gcc/array-traits.h
! ce1551377582b7cc6d3c1cc0f538b265  gcc/asan.cc
! 22fd8eff178cc62d0d38abc54459a7e2  gcc/asan.h
  a350e0e702ef2468ff3c700dff5b7433  gcc/attr-callback.cc
  0ec27d414707ba546fed401eaaf2af22  gcc/attr-callback.h
  8eabb720cd45c245a7d1be51c0f744ca  gcc/attr-fnspec.h
*************** fe292df4b7f3e3ef7c0b8305084b6844  gcc/bi
*** 3264,3280 ****
  ab9fdb6ff2584fb7c564bdd3d5546c02  gcc/btfout.cc
  5423cf9cfc9de5ca30bc45842efead77  gcc/builtin-attrs.def
  9b2538f67781c7ccab3891a929caaaf0  gcc/builtin-types.def
! 67b762b0b5e04e028c2e2436f9a6cfbe  gcc/builtins.cc
! 52ff6fb92e162a8ad41a1af1dfb0171a  gcc/builtins.def
  08bacecaf5d3527bf3df15480fb78537  gcc/builtins.h
! f92f1791c389a192409691371269d881  gcc/c-family/ChangeLog
  ea3fa1f4d7390a105fa3caab4f79aaf7  gcc/c-family/ChangeLog.gimple-classes
  9c7ff39ab2ffc5f0938f59efc3657201  gcc/c-family/c-ada-spec.cc
  4e83011bee68d9607834ed5335191d65  gcc/c-family/c-ada-spec.h
  d44a12a363aa3f6d21f2be5e2ff91306  gcc/c-family/c-attribs.cc
! 596dbd2931504d95df7e9f80209f701e  gcc/c-family/c-common.cc
  461f8fd980064d18d90eacf82418efa0  gcc/c-family/c-common.def
! a9f5b0cff328f824fd403136d48f4bca  gcc/c-family/c-common.h
  14ba009130187cc3d40c52c4e77f6b5f  gcc/c-family/c-cppbuiltin.cc
  01db2d5cca29943c49bb372f2137d874  gcc/c-family/c-dump.cc
  19059a85545bb95b391e68da0cbc670c  gcc/c-family/c-format.cc
--- 3264,3280 ----
  ab9fdb6ff2584fb7c564bdd3d5546c02  gcc/btfout.cc
  5423cf9cfc9de5ca30bc45842efead77  gcc/builtin-attrs.def
  9b2538f67781c7ccab3891a929caaaf0  gcc/builtin-types.def
! c34ad434048eaf621308958d1e2665a4  gcc/builtins.cc
! 8529f75c9821af4a1db265277a0ef04a  gcc/builtins.def
  08bacecaf5d3527bf3df15480fb78537  gcc/builtins.h
! 870e389cab9b1244d52936e5f2aa0f75  gcc/c-family/ChangeLog
  ea3fa1f4d7390a105fa3caab4f79aaf7  gcc/c-family/ChangeLog.gimple-classes
  9c7ff39ab2ffc5f0938f59efc3657201  gcc/c-family/c-ada-spec.cc
  4e83011bee68d9607834ed5335191d65  gcc/c-family/c-ada-spec.h
  d44a12a363aa3f6d21f2be5e2ff91306  gcc/c-family/c-attribs.cc
! 378e7c2524f6ea3c3f90790e22b8e210  gcc/c-family/c-common.cc
  461f8fd980064d18d90eacf82418efa0  gcc/c-family/c-common.def
! ca922c73fc6bf20139197b4052b563c9  gcc/c-family/c-common.h
  14ba009130187cc3d40c52c4e77f6b5f  gcc/c-family/c-cppbuiltin.cc
  01db2d5cca29943c49bb372f2137d874  gcc/c-family/c-dump.cc
  19059a85545bb95b391e68da0cbc670c  gcc/c-family/c-format.cc
*************** c8d86c12bc259d3a335f338ce3a10304  gcc/c-
*** 3284,3290 ****
  a4b7179d2e948bb7586a9143fbe05593  gcc/c-family/c-indentation.h
  c80c4d6e16ab46358143d22a8a146725  gcc/c-family/c-lex.cc
  c880dc584a0fd4908e5df33dd81137b8  gcc/c-family/c-objc.h
! 01d687bce8334969b5e10c6c1607f672  gcc/c-family/c-omp.cc
  d6f330016fc2e053464709bdc03c1101  gcc/c-family/c-opts.cc
  5be37a0daa62d32d800f4818f979e598  gcc/c-family/c-pch.cc
  6e53d008a0c4738339154c353a50ff0a  gcc/c-family/c-ppoutput.cc
--- 3284,3290 ----
  a4b7179d2e948bb7586a9143fbe05593  gcc/c-family/c-indentation.h
  c80c4d6e16ab46358143d22a8a146725  gcc/c-family/c-lex.cc
  c880dc584a0fd4908e5df33dd81137b8  gcc/c-family/c-objc.h
! 40f1001bcd780f8409b3a7179d0591fe  gcc/c-family/c-omp.cc
  d6f330016fc2e053464709bdc03c1101  gcc/c-family/c-opts.cc
  5be37a0daa62d32d800f4818f979e598  gcc/c-family/c-pch.cc
  6e53d008a0c4738339154c353a50ff0a  gcc/c-family/c-ppoutput.cc
*************** f33c757b5c412f1062f4d8d3d39ea3c5  gcc/c-
*** 3310,3316 ****
  ac5daa4f7d7788a3f68dde7fe7a25316  gcc/c-family/known-headers.h
  f09c431056b5138e7cfe8376e05de9a6  gcc/c-family/name-hint.h
  d71f74b5b48d9ec5e4e6463e7330121d  gcc/c-family/stub-objc.cc
! 04f50d5167d27bb4ea64f4c1d46b1028  gcc/c/ChangeLog
  a1ab86dd79d40d45839823afe798673a  gcc/c/Make-lang.in
  f1e5593aebd5cffb4b3cbffe6bd0860a  gcc/c/c-aux-info.cc
  178d24653bb20936d73bad078e70763c  gcc/c/c-convert.cc
--- 3310,3316 ----
  ac5daa4f7d7788a3f68dde7fe7a25316  gcc/c-family/known-headers.h
  f09c431056b5138e7cfe8376e05de9a6  gcc/c-family/name-hint.h
  d71f74b5b48d9ec5e4e6463e7330121d  gcc/c-family/stub-objc.cc
! 04c825cba4ddca19f28cfc74976887c4  gcc/c/ChangeLog
  a1ab86dd79d40d45839823afe798673a  gcc/c/Make-lang.in
  f1e5593aebd5cffb4b3cbffe6bd0860a  gcc/c/c-aux-info.cc
  178d24653bb20936d73bad078e70763c  gcc/c/c-convert.cc
*************** d9c0725d061adffdf400457d91be3aed  gcc/c/
*** 3321,3334 ****
  66f4b0672865216b2d3040eee16759b5  gcc/c/c-lang.h
  c2644975781d9f78ae4c387d01a3270e  gcc/c/c-objc-common.cc
  757f583d06a3ec98336adbfc92b4e6a8  gcc/c/c-objc-common.h
! 68e771e071730f4d539eb159a7c2c67b  gcc/c/c-parser.cc
  4cd2bf432e96f0de530e0ea4e8b44aa2  gcc/c/c-parser.h
  9179f46b6a06c7d734278f5ce2c55883  gcc/c/c-tree.def
  37ad86287839e5f9849ab677266e1909  gcc/c/c-tree.h
  a77ee56eb91026257ae7bdff107c8492  gcc/c/c-typeck.cc
  cd371895d730dd64e947066b2e4378f8  gcc/c/config-lang.in
  1bd76a24d1322659f048abe2272a6f34  gcc/c/gccspec.cc
! a1cb75cf27d4ffb2f87f4f7dbf93ea45  gcc/c/gimple-parser.cc
  84e0373f5db72260d34cf125d8587f06  gcc/c/gimple-parser.h
  137bed6e3e62068dc6a3292ae42a0a4e  gcc/caller-save.cc
  11d34bcacb1039b02654b25c000d62f5  gcc/calls.cc
--- 3321,3334 ----
  66f4b0672865216b2d3040eee16759b5  gcc/c/c-lang.h
  c2644975781d9f78ae4c387d01a3270e  gcc/c/c-objc-common.cc
  757f583d06a3ec98336adbfc92b4e6a8  gcc/c/c-objc-common.h
! be6bc9ed4354189b8055e3630254fbed  gcc/c/c-parser.cc
  4cd2bf432e96f0de530e0ea4e8b44aa2  gcc/c/c-parser.h
  9179f46b6a06c7d734278f5ce2c55883  gcc/c/c-tree.def
  37ad86287839e5f9849ab677266e1909  gcc/c/c-tree.h
  a77ee56eb91026257ae7bdff107c8492  gcc/c/c-typeck.cc
  cd371895d730dd64e947066b2e4378f8  gcc/c/config-lang.in
  1bd76a24d1322659f048abe2272a6f34  gcc/c/gccspec.cc
! 0b9a6bcbfcf1f0f74c836ed0436e0372  gcc/c/gimple-parser.cc
  84e0373f5db72260d34cf125d8587f06  gcc/c/gimple-parser.h
  137bed6e3e62068dc6a3292ae42a0a4e  gcc/caller-save.cc
  11d34bcacb1039b02654b25c000d62f5  gcc/calls.cc
*************** c08ead9db4f4b74ebcdec4329f22b297  gcc/cf
*** 3344,3350 ****
  0d52ee7360736bb3d0306e66c1f3a9ce  gcc/cfgbuild.h
  39bbd18fab17b2880094aa317111df50  gcc/cfgcleanup.cc
  0761d2fe0a8e51aa7ed662e27b66747a  gcc/cfgcleanup.h
! b16722a083547061a927ed6271ce6028  gcc/cfgexpand.cc
  1ec4e9a88b7aff0e8dc3577ab103b559  gcc/cfgexpand.h
  5d460f011f4a8ff85a40de115ad0752d  gcc/cfghooks.cc
  bbad65845fcf9cdbc5137d96f92eacab  gcc/cfghooks.h
--- 3344,3350 ----
  0d52ee7360736bb3d0306e66c1f3a9ce  gcc/cfgbuild.h
  39bbd18fab17b2880094aa317111df50  gcc/cfgcleanup.cc
  0761d2fe0a8e51aa7ed662e27b66747a  gcc/cfgcleanup.h
! 0d8e98abad059da0d80a563e180e7be8  gcc/cfgexpand.cc
  1ec4e9a88b7aff0e8dc3577ab103b559  gcc/cfgexpand.h
  5d460f011f4a8ff85a40de115ad0752d  gcc/cfghooks.cc
  bbad65845fcf9cdbc5137d96f92eacab  gcc/cfghooks.h
*************** bbad65845fcf9cdbc5137d96f92eacab  gcc/cf
*** 3355,3367 ****
  7c2358ab451ca13a153f64b7682d772a  gcc/cfgloopmanip.h
  86fd277253913430380bc5d51e4b395b  gcc/cfgrtl.cc
  132f0eb682ec622dc563cfc697da1fb8  gcc/cfgrtl.h
! 4da7db85ba94a8e34a74cf7ecfe3a9dd  gcc/cgraph.cc
! 7e4a03cab55e3131e6de1de90ecb7af4  gcc/cgraph.h
  5fa2e94f261a8a6fc0d80b1c4b227d25  gcc/cgraphbuild.cc
! 6e6912b7178d1b640a657bcd1368d3d9  gcc/cgraphclones.cc
! 0aa3ff692dc9fbc1428609accd2b1c77  gcc/cgraphunit.cc
  bd38ef84be4e8351bde3ee96f062c357  gcc/cif-code.def
! 7f9335fcdc47fc3584a55874e8479428  gcc/cobol/ChangeLog
  ee705da1a8f69fdc22716ef43112bfcc  gcc/cobol/Make-lang.in
  0a84e784d2bc4066654d2377fc6a2930  gcc/cobol/TODO
  d2b0dd7d8414ce5776a1038d19ac8153  gcc/cobol/cbldiag.h
--- 3355,3367 ----
  7c2358ab451ca13a153f64b7682d772a  gcc/cfgloopmanip.h
  86fd277253913430380bc5d51e4b395b  gcc/cfgrtl.cc
  132f0eb682ec622dc563cfc697da1fb8  gcc/cfgrtl.h
! 31702ba537de0dd618704b1a2dc6013e  gcc/cgraph.cc
! c9582e070a96b548d3194f5c63507c2c  gcc/cgraph.h
  5fa2e94f261a8a6fc0d80b1c4b227d25  gcc/cgraphbuild.cc
! 24f28e8ed4265cee1f116587e9fda3f0  gcc/cgraphclones.cc
! b98852072012806aa50fec7c5577855b  gcc/cgraphunit.cc
  bd38ef84be4e8351bde3ee96f062c357  gcc/cif-code.def
! 38ca5d0498842cbd6ebad4c767071939  gcc/cobol/ChangeLog
  ee705da1a8f69fdc22716ef43112bfcc  gcc/cobol/Make-lang.in
  0a84e784d2bc4066654d2377fc6a2930  gcc/cobol/TODO
  d2b0dd7d8414ce5776a1038d19ac8153  gcc/cobol/cbldiag.h
*************** fc78b78c0e88e56d8a5bc08ac67ee843  gcc/co
*** 3393,3399 ****
  fd52a00ee627385048b4901c68152fd3  gcc/cobol/lang-specs.h
  326453d4d833b38774f1e514a5d906ae  gcc/cobol/lang.opt
  27fcbbb7a8eb5ed2cb9e2afff4e05f7e  gcc/cobol/lang.opt.urls
! 8dc044a3f18b53471a35b59faa9c6499  gcc/cobol/lexio.cc
  5953c820cdc03feb815bfbf28c10730c  gcc/cobol/lexio.h
  112b5088144c95f653839c42f9763cb8  gcc/cobol/messages.cc
  a1dc6074f38f10cc7f2f266756cb68af  gcc/cobol/parse.y
--- 3393,3399 ----
  fd52a00ee627385048b4901c68152fd3  gcc/cobol/lang-specs.h
  326453d4d833b38774f1e514a5d906ae  gcc/cobol/lang.opt
  27fcbbb7a8eb5ed2cb9e2afff4e05f7e  gcc/cobol/lang.opt.urls
! 7639e435c94d2da10156ddd3db927e9e  gcc/cobol/lexio.cc
  5953c820cdc03feb815bfbf28c10730c  gcc/cobol/lexio.h
  112b5088144c95f653839c42f9763cb8  gcc/cobol/messages.cc
  a1dc6074f38f10cc7f2f266756cb68af  gcc/cobol/parse.y
*************** ccb41d4e6733c464561a8425ed5e090e  gcc/co
*** 3420,3435 ****
  f55010fab8b9aabea82c3ac50d031028  gcc/collect2.h
  47b3611844b583f418ce3aaf051c492a  gcc/color-macros.h
  7041e62f0f582b09331732fef4bb9545  gcc/combine-stack-adj.cc
! 8db32a2301bfbb3281c1cc38024ad792  gcc/combine.cc
  2b9ccf7fc2473ef7e36aee9bcf170843  gcc/common.md
! 1b99b9adbc8aca6636b14206165a9321  gcc/common.opt
! 90ce4da214d6c817fab1430f539f24b5  gcc/common.opt.urls
  26050db921f73fd87b026dc950bde97b  gcc/common/common-target-def.h
  dae02ebe59cdaaf21611ad354e939ca5  gcc/common/common-target.def
  4a00b1cedd9d15d93e32920b16b3c292  gcc/common/common-target.h
  6a072ad74a92c43b4c4ddaf601c5dba5  gcc/common/common-targhooks.cc
  053301c186b4ed1dbacedc670026f9cf  gcc/common/common-targhooks.h
! 23a82fb833f55a245e4aefdecf963119  gcc/common/config/aarch64/aarch64-common.cc
  dff0f13281ab4dbd1ca026f971ee7553  gcc/common/config/aarch64/cpuinfo.h
  583d89cf5b4ff63572bfcd107bd598e1  gcc/common/config/alpha/alpha-common.cc
  c54d5f1066ada6f197004c84bc9e6a63  gcc/common/config/arc/arc-common.cc
--- 3420,3435 ----
  f55010fab8b9aabea82c3ac50d031028  gcc/collect2.h
  47b3611844b583f418ce3aaf051c492a  gcc/color-macros.h
  7041e62f0f582b09331732fef4bb9545  gcc/combine-stack-adj.cc
! dbe869491a5b634a06f5a7488563e015  gcc/combine.cc
  2b9ccf7fc2473ef7e36aee9bcf170843  gcc/common.md
! bbd3bfe8d8ae38defef14d0a6d9e4ceb  gcc/common.opt
! 40215d7288fffc3b0c3524fd9bb23dbd  gcc/common.opt.urls
  26050db921f73fd87b026dc950bde97b  gcc/common/common-target-def.h
  dae02ebe59cdaaf21611ad354e939ca5  gcc/common/common-target.def
  4a00b1cedd9d15d93e32920b16b3c292  gcc/common/common-target.h
  6a072ad74a92c43b4c4ddaf601c5dba5  gcc/common/common-targhooks.cc
  053301c186b4ed1dbacedc670026f9cf  gcc/common/common-targhooks.h
! 482d444323d061c69d73e9d23adc4e7a  gcc/common/config/aarch64/aarch64-common.cc
  dff0f13281ab4dbd1ca026f971ee7553  gcc/common/config/aarch64/cpuinfo.h
  583d89cf5b4ff63572bfcd107bd598e1  gcc/common/config/alpha/alpha-common.cc
  c54d5f1066ada6f197004c84bc9e6a63  gcc/common/config/arc/arc-common.cc
*************** e6e86df919407a02a2bcc6baffb28dd6  gcc/co
*** 3446,3455 ****
  e52e97d4d4876d6657fdd48e9f622383  gcc/common/config/frv/frv-common.cc
  2da12f05a7597886b6b659f44fb2d0b0  gcc/common/config/gcn/gcn-common.cc
  cba8bad9b28e5a0f8934b00becb13d4a  gcc/common/config/h8300/h8300-common.cc
! e577851e3fec618f8d95579ba1117872  gcc/common/config/i386/cpuinfo.h
! 3999256476740a6f5fce61640b1b6013  gcc/common/config/i386/i386-common.cc
! 0b05ae5a9ac775fa157d017b8cdfc6ab  gcc/common/config/i386/i386-cpuinfo.h
! 1fde110881f428f0dd213fa45b6ca1ad  gcc/common/config/i386/i386-isas.h
  2a64c5f639b347964e652ebb1add9831  gcc/common/config/ia64/ia64-common.cc
  94b8ff9b1f75e2aaff5033327ccfb449  gcc/common/config/iq2000/iq2000-common.cc
  fd1d75b5f0b2cfac12e5ed2e83377f77  gcc/common/config/lm32/lm32-common.cc
--- 3446,3455 ----
  e52e97d4d4876d6657fdd48e9f622383  gcc/common/config/frv/frv-common.cc
  2da12f05a7597886b6b659f44fb2d0b0  gcc/common/config/gcn/gcn-common.cc
  cba8bad9b28e5a0f8934b00becb13d4a  gcc/common/config/h8300/h8300-common.cc
! cead841f744efa8ef70f58e360da229f  gcc/common/config/i386/cpuinfo.h
! 8a6bcb4626b97f3ce1e3aeb8f844a3d5  gcc/common/config/i386/i386-common.cc
! 3351c0b359d7cf33cf78501d0b209b77  gcc/common/config/i386/i386-cpuinfo.h
! 44a3b5cdcb9270292860a3e36eb01d23  gcc/common/config/i386/i386-isas.h
  2a64c5f639b347964e652ebb1add9831  gcc/common/config/ia64/ia64-common.cc
  94b8ff9b1f75e2aaff5033327ccfb449  gcc/common/config/iq2000/iq2000-common.cc
  fd1d75b5f0b2cfac12e5ed2e83377f77  gcc/common/config/lm32/lm32-common.cc
*************** b5a916bb9dd788754ac9e4ad7174ee74  gcc/co
*** 3484,3503 ****
  b209201703dd766f76ff5e16b99191e5  gcc/compare-elim.cc
  618780fbce0ce0cb6f9b86e079ce4e54  gcc/conditions.h
  1b4bc58c657bf910929d06d51bc8fa6c  gcc/config.build
! 2167173c3ec2b6f01d43b11455236d3c  gcc/config.gcc
  053bb14b428d0f073932e88b9a29a8bd  gcc/config.host
! 756f3bb3af308945746fb7b5683487ea  gcc/config.in
  8e697813dc96ca90f5d0f4c196efe2cc  gcc/config/README
  a66e3cd55f15eb5f17a8d848161371a7  gcc/config/aarch64/aarch64-abi-ms-protos.h
  fc247aa8c40db38e448846ba37245cc0  gcc/config/aarch64/aarch64-abi-ms.cc
  1e461c3cff9ad213b0c430fa2505e7e3  gcc/config/aarch64/aarch64-abi-ms.h
! 9ff4e02500f5622983fef95cce7f38fd  gcc/config/aarch64/aarch64-arches.def
  25015a0315f13c9da9f02b76796af35c  gcc/config/aarch64/aarch64-builtin-pairs.def
! 484479d548374fdcb26338db469a20d4  gcc/config/aarch64/aarch64-builtins.cc
  482530e7572b40bc2ad01bdec0c1b97e  gcc/config/aarch64/aarch64-builtins.h
! a23e0fac46a5ec3786d2e8cc7ad18058  gcc/config/aarch64/aarch64-c.cc
  7e379e769908e6e6cce538dbc8872dad  gcc/config/aarch64/aarch64-coff.h
! 8585ecd2387bb9252d2ac47716ac114a  gcc/config/aarch64/aarch64-cores.def
  85b8b0267c641b7fb638fffcb3016739  gcc/config/aarch64/aarch64-cost-tables.h
  bef2a61270424fd606c71d78d20ad675  gcc/config/aarch64/aarch64-d.cc
  36405b6300d5ec6ca8faf17212ad1bc9  gcc/config/aarch64/aarch64-d.h
--- 3484,3503 ----
  b209201703dd766f76ff5e16b99191e5  gcc/compare-elim.cc
  618780fbce0ce0cb6f9b86e079ce4e54  gcc/conditions.h
  1b4bc58c657bf910929d06d51bc8fa6c  gcc/config.build
! 368fefe24a5ecefbdefc6690ad928720  gcc/config.gcc
  053bb14b428d0f073932e88b9a29a8bd  gcc/config.host
! 81e7a5d0e9803bfab08b2b4e88fbc77f  gcc/config.in
  8e697813dc96ca90f5d0f4c196efe2cc  gcc/config/README
  a66e3cd55f15eb5f17a8d848161371a7  gcc/config/aarch64/aarch64-abi-ms-protos.h
  fc247aa8c40db38e448846ba37245cc0  gcc/config/aarch64/aarch64-abi-ms.cc
  1e461c3cff9ad213b0c430fa2505e7e3  gcc/config/aarch64/aarch64-abi-ms.h
! 7bbbafcdc44148104603f9d99f82f14c  gcc/config/aarch64/aarch64-arches.def
  25015a0315f13c9da9f02b76796af35c  gcc/config/aarch64/aarch64-builtin-pairs.def
! 31cce7a398632723b6a777bda5fff7d2  gcc/config/aarch64/aarch64-builtins.cc
  482530e7572b40bc2ad01bdec0c1b97e  gcc/config/aarch64/aarch64-builtins.h
! 7e0d659d19fdff97c9d26f75609fd883  gcc/config/aarch64/aarch64-c.cc
  7e379e769908e6e6cce538dbc8872dad  gcc/config/aarch64/aarch64-coff.h
! e7499fc26ae2e35538ced2586da8b45c  gcc/config/aarch64/aarch64-cores.def
  85b8b0267c641b7fb638fffcb3016739  gcc/config/aarch64/aarch64-cost-tables.h
  bef2a61270424fd606c71d78d20ad675  gcc/config/aarch64/aarch64-d.cc
  36405b6300d5ec6ca8faf17212ad1bc9  gcc/config/aarch64/aarch64-d.h
*************** d75100bc2f054afcf41a992cdaa5f793  gcc/co
*** 3507,3513 ****
  a626b42ff6790e8447d6f7bf1b19e5fb  gcc/config/aarch64/aarch64-elf-raw.h
  c0d880a26a41c2eddec7a4e7617612cb  gcc/config/aarch64/aarch64-elf.h
  6e8efccd687b154a1a7fcc3e9672274f  gcc/config/aarch64/aarch64-errata.h
! 6df4d6606c5577f4c539576fb9118290  gcc/config/aarch64/aarch64-feature-deps.h
  81054413a10f449c26d39daf0861c255  gcc/config/aarch64/aarch64-freebsd.h
  28a1c2270ecf37dbbc890a00afce3f18  gcc/config/aarch64/aarch64-fusion-pairs.def
  af558ba2beea39cc3b20c9f198e27d8a  gcc/config/aarch64/aarch64-generate-json-tuning-routines.py
--- 3507,3513 ----
  a626b42ff6790e8447d6f7bf1b19e5fb  gcc/config/aarch64/aarch64-elf-raw.h
  c0d880a26a41c2eddec7a4e7617612cb  gcc/config/aarch64/aarch64-elf.h
  6e8efccd687b154a1a7fcc3e9672274f  gcc/config/aarch64/aarch64-errata.h
! bf42ff88af2bc5a1b18b52e6c902944c  gcc/config/aarch64/aarch64-feature-deps.h
  81054413a10f449c26d39daf0861c255  gcc/config/aarch64/aarch64-freebsd.h
  28a1c2270ecf37dbbc890a00afce3f18  gcc/config/aarch64/aarch64-fusion-pairs.def
  af558ba2beea39cc3b20c9f198e27d8a  gcc/config/aarch64/aarch64-generate-json-tuning-routines.py
*************** fdf8868f9bbd9b6e88b6021e1ed56216  gcc/co
*** 3522,3535 ****
  50481181ce92fb4dac1644f120ba36a0  gcc/config/aarch64/aarch64-json-tunings-printer.h
  eb027b43f3e6788c44aa2d2b7e11943f  gcc/config/aarch64/aarch64-ldp-fusion.cc
  7387cc42927b91bf90a7aa8d49a9eff7  gcc/config/aarch64/aarch64-ldpstp.md
! 13f036b6a160cb85ad864e7e475dc552  gcc/config/aarch64/aarch64-linux.h
  3c95e830c849ee5787b2e1d5128a4bc6  gcc/config/aarch64/aarch64-modes.def
  64c80b1b7cd981b4fb4b76f7c36c9428  gcc/config/aarch64/aarch64-neon-sve-bridge-builtins.def
  f931bc8e97c2f1358ad3ad91e902d553  gcc/config/aarch64/aarch64-netbsd.h
! a1976079127ae261204af8cdddd28c03  gcc/config/aarch64/aarch64-option-extensions.def
  03abf94646a4b525b350e9ecdb8e45a5  gcc/config/aarch64/aarch64-opts.h
  a349e9ba39f96f10f6c9f5e13bb8b661  gcc/config/aarch64/aarch64-passes.def
! 43137fc19bb3285435ff7b357109ef86  gcc/config/aarch64/aarch64-protos.h
  7beff4ec013b184132d7c933faa51208  gcc/config/aarch64/aarch64-sched-dispatch.cc
  b824341b8f6fdb8eb1667425adf63db8  gcc/config/aarch64/aarch64-sched-dispatch.h
  7cfa3d0cdd28cdcd73a29c2c8a925548  gcc/config/aarch64/aarch64-simd-builtin-types.def
--- 3522,3535 ----
  50481181ce92fb4dac1644f120ba36a0  gcc/config/aarch64/aarch64-json-tunings-printer.h
  eb027b43f3e6788c44aa2d2b7e11943f  gcc/config/aarch64/aarch64-ldp-fusion.cc
  7387cc42927b91bf90a7aa8d49a9eff7  gcc/config/aarch64/aarch64-ldpstp.md
! cae1b2e3499c0eaecd54f578a51ffb1f  gcc/config/aarch64/aarch64-linux.h
  3c95e830c849ee5787b2e1d5128a4bc6  gcc/config/aarch64/aarch64-modes.def
  64c80b1b7cd981b4fb4b76f7c36c9428  gcc/config/aarch64/aarch64-neon-sve-bridge-builtins.def
  f931bc8e97c2f1358ad3ad91e902d553  gcc/config/aarch64/aarch64-netbsd.h
! 984ae80e4bd29649a520a667c1e4495d  gcc/config/aarch64/aarch64-option-extensions.def
  03abf94646a4b525b350e9ecdb8e45a5  gcc/config/aarch64/aarch64-opts.h
  a349e9ba39f96f10f6c9f5e13bb8b661  gcc/config/aarch64/aarch64-passes.def
! 795e3f2cbfd5544c02f823a1c1e1d618  gcc/config/aarch64/aarch64-protos.h
  7beff4ec013b184132d7c933faa51208  gcc/config/aarch64/aarch64-sched-dispatch.cc
  b824341b8f6fdb8eb1667425adf63db8  gcc/config/aarch64/aarch64-sched-dispatch.h
  7cfa3d0cdd28cdcd73a29c2c8a925548  gcc/config/aarch64/aarch64-simd-builtin-types.def
*************** f3e52f115b01c46c9eb8009d950b8d7f  gcc/co
*** 3548,3554 ****
  2c404dcd9f8edf147364f4503199c585  gcc/config/aarch64/aarch64-sve-builtins-sme.def
  4929a2908dc0a3aaa4b8e51c84cee8c8  gcc/config/aarch64/aarch64-sve-builtins-sme.h
  590c9c2e2c6855697cef84761c420b80  gcc/config/aarch64/aarch64-sve-builtins-sve2.cc
! 5249e3dd61e8bd70c85a23c5711f3ca2  gcc/config/aarch64/aarch64-sve-builtins-sve2.def
  e2d80b89552da0c6b4cb6bede3b2e573  gcc/config/aarch64/aarch64-sve-builtins-sve2.h
  6898353f8b81b1bd82f117ddced5b0d5  gcc/config/aarch64/aarch64-sve-builtins.cc
  30d08305d5bc784af521254aea449949  gcc/config/aarch64/aarch64-sve-builtins.def
--- 3548,3554 ----
  2c404dcd9f8edf147364f4503199c585  gcc/config/aarch64/aarch64-sve-builtins-sme.def
  4929a2908dc0a3aaa4b8e51c84cee8c8  gcc/config/aarch64/aarch64-sve-builtins-sme.h
  590c9c2e2c6855697cef84761c420b80  gcc/config/aarch64/aarch64-sve-builtins-sve2.cc
! 5abe907050ad53adc25993be474c39c0  gcc/config/aarch64/aarch64-sve-builtins-sve2.def
  e2d80b89552da0c6b4cb6bede3b2e573  gcc/config/aarch64/aarch64-sve-builtins-sve2.h
  6898353f8b81b1bd82f117ddced5b0d5  gcc/config/aarch64/aarch64-sve-builtins.cc
  30d08305d5bc784af521254aea449949  gcc/config/aarch64/aarch64-sve-builtins.def
*************** ae7ea468046099ae99d717e107a85497  gcc/co
*** 3556,3569 ****
  8a1b76053840bf68b3da053c081081e8  gcc/config/aarch64/aarch64-sve.md
  0e48ec989797cfed5b216617692403e9  gcc/config/aarch64/aarch64-sve2.md
  28e8e7965d9ed466a7d53a53e2ec7397  gcc/config/aarch64/aarch64-sys-regs.def
! 5b8c2fbcb70280c8d3a7290fd01efb5b  gcc/config/aarch64/aarch64-tune.md
  dec4c8fd03ac5636ba08d9523bee06be  gcc/config/aarch64/aarch64-tuning-enums.def
  586e3b2fd446baa0a6fb8da7c8cdd660  gcc/config/aarch64/aarch64-tuning-flags.def
  a5cfcce7c9dd86a597161f8bde3497bc  gcc/config/aarch64/aarch64-vxworks.h
! ca688089bbbcac7fa0fa85b441117158  gcc/config/aarch64/aarch64.cc
! 9a8f7c54af5be142140e2dc31f99fdab  gcc/config/aarch64/aarch64.h
! 87bb81f80d1f24768f04e99072c2f669  gcc/config/aarch64/aarch64.md
! 0ce505ced96a535a383adbbdb7c31de8  gcc/config/aarch64/aarch64.opt
  f8862c1a17df0d9164d1f07fc8288527  gcc/config/aarch64/aarch64.opt.urls
  7b468a20f0362cbe02c7699720a962fa  gcc/config/aarch64/arm_acle.h
  d8c2d46b77748c711b5354380ee49819  gcc/config/aarch64/arm_bf16.h
--- 3556,3569 ----
  8a1b76053840bf68b3da053c081081e8  gcc/config/aarch64/aarch64-sve.md
  0e48ec989797cfed5b216617692403e9  gcc/config/aarch64/aarch64-sve2.md
  28e8e7965d9ed466a7d53a53e2ec7397  gcc/config/aarch64/aarch64-sys-regs.def
! 33a2011b9d1511f6f2a48135ef9c91dc  gcc/config/aarch64/aarch64-tune.md
  dec4c8fd03ac5636ba08d9523bee06be  gcc/config/aarch64/aarch64-tuning-enums.def
  586e3b2fd446baa0a6fb8da7c8cdd660  gcc/config/aarch64/aarch64-tuning-flags.def
  a5cfcce7c9dd86a597161f8bde3497bc  gcc/config/aarch64/aarch64-vxworks.h
! 3f7c6df51b76ab25035de3053a673245  gcc/config/aarch64/aarch64.cc
! f12af72da57c184e7695a3c2f0fe3556  gcc/config/aarch64/aarch64.h
! 780d9d855b48ffb7caa40ded2d64fc99  gcc/config/aarch64/aarch64.md
! 09d9d492d98449c69cd0c4ae255cc135  gcc/config/aarch64/aarch64.opt
  f8862c1a17df0d9164d1f07fc8288527  gcc/config/aarch64/aarch64.opt.urls
  7b468a20f0362cbe02c7699720a962fa  gcc/config/aarch64/arm_acle.h
  d8c2d46b77748c711b5354380ee49819  gcc/config/aarch64/arm_bf16.h
*************** c61b39c4504a36e5c45cd1e3b64723d7  gcc/co
*** 3578,3595 ****
  35fa48ff42e4796d58857c4d001d9920  gcc/config/aarch64/biarchilp32.h
  ae88170d2d567105865813bb4b77d91f  gcc/config/aarch64/biarchlp64.h
  124d7f2adedfdccecd86bb0274dfc7aa  gcc/config/aarch64/check-sve-md.awk
! e6affb6245a300a09ed57ed4fc0b212b  gcc/config/aarch64/constraints.md
  dd76583202434d2161c8668396b95079  gcc/config/aarch64/cortex-a57-fma-steering.cc
! 6fb19490d45ca30e5e457cc8711266ac  gcc/config/aarch64/cygming.h
  292d2b0e05a5d9d17f1d5ab6e78f23b3  gcc/config/aarch64/driver-aarch64.cc
  f713d33fdaee532813b56547dd070c8c  gcc/config/aarch64/fractional-cost.h
  f7165d62ef852e1929a8fc9a85c01ab2  gcc/config/aarch64/gcc-auto-profile
  dfcdbda4a3bb64a86fdf64ce6fce0ae3  gcc/config/aarch64/geniterators.sh
  bc3b4ebfac8bfd42d3e9098f33585afd  gcc/config/aarch64/gentune.sh
  86eaf33edeb885c2c9ae2a9825879e59  gcc/config/aarch64/host-aarch64-darwin.cc
! b28994e8791a9190a2be1df6d81bad02  gcc/config/aarch64/iterators.md
  811f43b19ba5f415244c59b4ab377445  gcc/config/aarch64/neoversev2.md
! d7be23445faf070c6e51cc3d3403dd81  gcc/config/aarch64/predicates.md
  a4e902ee1494ba5eee811ea46ecdf995  gcc/config/aarch64/rtems.h
  baaec1b607c99920513eb3d3d47af504  gcc/config/aarch64/t-aarch64
  5a6fa47ba2bb65a12cd953f8edee028d  gcc/config/aarch64/t-aarch64-freebsd
--- 3578,3596 ----
  35fa48ff42e4796d58857c4d001d9920  gcc/config/aarch64/biarchilp32.h
  ae88170d2d567105865813bb4b77d91f  gcc/config/aarch64/biarchlp64.h
  124d7f2adedfdccecd86bb0274dfc7aa  gcc/config/aarch64/check-sve-md.awk
! 2cb4775109adab44133b608663f49d65  gcc/config/aarch64/constraints.md
  dd76583202434d2161c8668396b95079  gcc/config/aarch64/cortex-a57-fma-steering.cc
! 330770f3cae8713bf4cd6a8ec83f191f  gcc/config/aarch64/cygming.h
  292d2b0e05a5d9d17f1d5ab6e78f23b3  gcc/config/aarch64/driver-aarch64.cc
  f713d33fdaee532813b56547dd070c8c  gcc/config/aarch64/fractional-cost.h
  f7165d62ef852e1929a8fc9a85c01ab2  gcc/config/aarch64/gcc-auto-profile
  dfcdbda4a3bb64a86fdf64ce6fce0ae3  gcc/config/aarch64/geniterators.sh
  bc3b4ebfac8bfd42d3e9098f33585afd  gcc/config/aarch64/gentune.sh
  86eaf33edeb885c2c9ae2a9825879e59  gcc/config/aarch64/host-aarch64-darwin.cc
! 2ea2b0b7b7b048a2752ccbbfa70b263b  gcc/config/aarch64/iterators.md
  811f43b19ba5f415244c59b4ab377445  gcc/config/aarch64/neoversev2.md
! b382a70dce13e2b3d554e31443c0dbf0  gcc/config/aarch64/olympus.md
! 253b9fee72bea13aedb53832fd8fad3f  gcc/config/aarch64/predicates.md
  a4e902ee1494ba5eee811ea46ecdf995  gcc/config/aarch64/rtems.h
  baaec1b607c99920513eb3d3d47af504  gcc/config/aarch64/t-aarch64
  5a6fa47ba2bb65a12cd953f8edee028d  gcc/config/aarch64/t-aarch64-freebsd
*************** af5cf08b218a58580f721de0803b2c46  gcc/co
*** 3626,3632 ****
  580c319ed787494654a89603535b16eb  gcc/config/aarch64/tuning_models/neoversev2.h
  4c0c4f0872cebbc1f03c7458d9ee68a1  gcc/config/aarch64/tuning_models/neoversev3.h
  a773c098793d3faf0c196e93fb0e1bdf  gcc/config/aarch64/tuning_models/neoversev3ae.h
! 031ac7d2898eac53b05d7540506fcbd6  gcc/config/aarch64/tuning_models/olympus.h
  cff8765d9b9b855a1d90b5496e8f559c  gcc/config/aarch64/tuning_models/qdf24xx.h
  d55f39c6f0f17b514eb02e3d34d21d13  gcc/config/aarch64/tuning_models/saphira.h
  a1d2ac92f9a8fb9d62a422b63db82278  gcc/config/aarch64/tuning_models/thunderx.h
--- 3627,3633 ----
  580c319ed787494654a89603535b16eb  gcc/config/aarch64/tuning_models/neoversev2.h
  4c0c4f0872cebbc1f03c7458d9ee68a1  gcc/config/aarch64/tuning_models/neoversev3.h
  a773c098793d3faf0c196e93fb0e1bdf  gcc/config/aarch64/tuning_models/neoversev3ae.h
! 76bf5799a4058680896ad8b605b8b9e8  gcc/config/aarch64/tuning_models/olympus.h
  cff8765d9b9b855a1d90b5496e8f559c  gcc/config/aarch64/tuning_models/qdf24xx.h
  d55f39c6f0f17b514eb02e3d34d21d13  gcc/config/aarch64/tuning_models/saphira.h
  a1d2ac92f9a8fb9d62a422b63db82278  gcc/config/aarch64/tuning_models/thunderx.h
*************** a05a37166e94a56a2d7d2be632dbab55  gcc/co
*** 3850,3860 ****
  d37f092206fc4c0379cee5e5fc01b654  gcc/config/avr/avr-passes-fuse-move.h
  627df811141f10a317b8ff56208c13b8  gcc/config/avr/avr-passes.cc
  6b425f8df921557284017d42be8efc3c  gcc/config/avr/avr-passes.def
! 65447cdb57d64c621846dbfaece9c7f6  gcc/config/avr/avr-protos.h
  eb753641e5bf09dbcc2be97e61be8767  gcc/config/avr/avr-stdint.h
! 49d1ad299e55ad19de3b2cbd6db25664  gcc/config/avr/avr.cc
  bee0e6e1aecf816b3bc39ba11e67566f  gcc/config/avr/avr.h
! b945bd3677c52afb1d50d329250126cb  gcc/config/avr/avr.md
  9b16afc684b8a6d301aa731ed7683f93  gcc/config/avr/avr.opt
  489f7578c0afc389ad7e6a8168b3613b  gcc/config/avr/avr.opt.urls
  e29c33fe5d0d32a0d578ef5a092a9836  gcc/config/avr/avrlibc.h
--- 3851,3861 ----
  d37f092206fc4c0379cee5e5fc01b654  gcc/config/avr/avr-passes-fuse-move.h
  627df811141f10a317b8ff56208c13b8  gcc/config/avr/avr-passes.cc
  6b425f8df921557284017d42be8efc3c  gcc/config/avr/avr-passes.def
! 50098ae685bc2b4906c7039ac95aabb8  gcc/config/avr/avr-protos.h
  eb753641e5bf09dbcc2be97e61be8767  gcc/config/avr/avr-stdint.h
! 44f9560b515ebc62c8615f795a64a375  gcc/config/avr/avr.cc
  bee0e6e1aecf816b3bc39ba11e67566f  gcc/config/avr/avr.h
! 29026b61e6e0a76a5ead6e7995683cb4  gcc/config/avr/avr.md
  9b16afc684b8a6d301aa731ed7683f93  gcc/config/avr/avr.opt
  489f7578c0afc389ad7e6a8168b3613b  gcc/config/avr/avr.opt.urls
  e29c33fe5d0d32a0d578ef5a092a9836  gcc/config/avr/avrlibc.h
*************** b010bad757aa01bd9f92af3564cb6384  gcc/co
*** 4103,4117 ****
  4664439672c5dddfd6148672f30ab54b  gcc/config/h8300/extensions.md
  ddfe3148d7a5affa40d0bdd16b650c5d  gcc/config/h8300/genmova.sh
  3a51a2d8d990cd6a1ff86d27c2ce6e4a  gcc/config/h8300/h8300-modes.def
! e1a1dc5e56d3c33f2c8b2ae080bf06c1  gcc/config/h8300/h8300-protos.h
! 19f1eed89faecae047ebe6cbfa6526a5  gcc/config/h8300/h8300.cc
  63e759894d1e6e471aa2654b3c93efe8  gcc/config/h8300/h8300.h
  c98efa4d243ed51c1105702ae383adea  gcc/config/h8300/h8300.md
  7f83af528763ab2c391dd6ec8ad01785  gcc/config/h8300/h8300.opt
  a5103b89aad288d854b885f74c3fea87  gcc/config/h8300/h8300.opt.urls
  9c526eb23649968b6b084788c80cb23f  gcc/config/h8300/jumpcall.md
  a6811f2f47d8c10c82edbfe6b0e5d6c1  gcc/config/h8300/linux.h
! 58f7f56ceec868a6a25ba54adaf00b61  gcc/config/h8300/logical.md
  51d196eafc160208ae48bcb8f79227ab  gcc/config/h8300/mova.md
  d329c98204120e78e720acd16234ad63  gcc/config/h8300/movepush.md
  6497e83ede4f1f9ec82eb6a07ba6f856  gcc/config/h8300/multiply.md
--- 4104,4118 ----
  4664439672c5dddfd6148672f30ab54b  gcc/config/h8300/extensions.md
  ddfe3148d7a5affa40d0bdd16b650c5d  gcc/config/h8300/genmova.sh
  3a51a2d8d990cd6a1ff86d27c2ce6e4a  gcc/config/h8300/h8300-modes.def
! 83bbdafed0af067194ca451638c80171  gcc/config/h8300/h8300-protos.h
! dbfb72b556dc691cbad48990a431e11d  gcc/config/h8300/h8300.cc
  63e759894d1e6e471aa2654b3c93efe8  gcc/config/h8300/h8300.h
  c98efa4d243ed51c1105702ae383adea  gcc/config/h8300/h8300.md
  7f83af528763ab2c391dd6ec8ad01785  gcc/config/h8300/h8300.opt
  a5103b89aad288d854b885f74c3fea87  gcc/config/h8300/h8300.opt.urls
  9c526eb23649968b6b084788c80cb23f  gcc/config/h8300/jumpcall.md
  a6811f2f47d8c10c82edbfe6b0e5d6c1  gcc/config/h8300/linux.h
! c95c16ca27ef1c638037907971e593a0  gcc/config/h8300/logical.md
  51d196eafc160208ae48bcb8f79227ab  gcc/config/h8300/mova.md
  d329c98204120e78e720acd16234ad63  gcc/config/h8300/movepush.md
  6497e83ede4f1f9ec82eb6a07ba6f856  gcc/config/h8300/multiply.md
*************** c0d3ca3f62caf30238675b1b8479aadc  gcc/co
*** 4148,4154 ****
  d5344f5586a4fdddcf32cfad79672651  gcc/config/i386/athlon.md
  c7639653fc509c53955783e5c3d3ed63  gcc/config/i386/atom.md
  e4ad129bfdb387d691c45180574d648e  gcc/config/i386/att.h
! 4d7e33724e59f6e1b2ece3d783b6f148  gcc/config/i386/avx10_2bf16intrin.h
  90f2d1436ca0d98dd30c10d69045883e  gcc/config/i386/avx10_2convertintrin.h
  284b65d9f14985fcf610d8d1a59a3b88  gcc/config/i386/avx10_2copyintrin.h
  478199ec3a1ffbcce3526921dd56ba5e  gcc/config/i386/avx10_2mediaintrin.h
--- 4149,4155 ----
  d5344f5586a4fdddcf32cfad79672651  gcc/config/i386/athlon.md
  c7639653fc509c53955783e5c3d3ed63  gcc/config/i386/atom.md
  e4ad129bfdb387d691c45180574d648e  gcc/config/i386/att.h
! 545544374b54a1c56bed173ceeaa8c0c  gcc/config/i386/avx10_2bf16intrin.h
  90f2d1436ca0d98dd30c10d69045883e  gcc/config/i386/avx10_2convertintrin.h
  284b65d9f14985fcf610d8d1a59a3b88  gcc/config/i386/avx10_2copyintrin.h
  478199ec3a1ffbcce3526921dd56ba5e  gcc/config/i386/avx10_2mediaintrin.h
*************** fe68438cc28695e7cdc08fb1954473a6  gcc/co
*** 4161,4166 ****
--- 4162,4169 ----
  bc9196fc44f5c18cc9c742b908853b01  gcc/config/i386/avx512bf16vlintrin.h
  1c696fd17531ec6e57128c367d20a59e  gcc/config/i386/avx512bitalgintrin.h
  5bdbd6274d160a8302d228f7291c70b4  gcc/config/i386/avx512bitalgvlintrin.h
+ b589e57e18611557ce2dea19ad5e6f70  gcc/config/i386/avx512bmmintrin.h
+ 4196b16dad3986021453848cdb356168  gcc/config/i386/avx512bmmvlintrin.h
  a8ab654c725276de489d77af27ca6be2  gcc/config/i386/avx512bwintrin.h
  8e8fb51bdc761dc7d57ebd1ec6d7e1cf  gcc/config/i386/avx512cdintrin.h
  b1110d9f8f990239ca4006510e7e12a2  gcc/config/i386/avx512dqintrin.h
*************** ed2254bdda3903cf7bffcad423af98ae  gcc/co
*** 4209,4218 ****
  5ad53873fee13ffe31a50e133663fd9e  gcc/config/i386/cmpccxaddintrin.h
  62c57c7c63efd8b0c33fbe1e6fcb5a60  gcc/config/i386/constraints.md
  4dd937d3024e34071e1f77d6d1cec027  gcc/config/i386/core2.md
! 08d1e06b716f6a61f08d0dc23759a3b4  gcc/config/i386/cpuid.h
  f700a1d35423658eaa2b4908da695bda  gcc/config/i386/cross-stdarg.h
  82964c7428d66bf1874c63a65b858957  gcc/config/i386/crtdll.h
! f8f2f3d70464037d7bd8bae81910ae7f  gcc/config/i386/cygming.h
  f2a2f556815a6dc38e47cca165d51ea3  gcc/config/i386/cygwin-stdint.h
  1868c3b9e51f09941105430ebd8c2286  gcc/config/i386/cygwin-w64.h
  47570db058e06dc2ab076ed2f9cf4242  gcc/config/i386/cygwin.h
--- 4212,4221 ----
  5ad53873fee13ffe31a50e133663fd9e  gcc/config/i386/cmpccxaddintrin.h
  62c57c7c63efd8b0c33fbe1e6fcb5a60  gcc/config/i386/constraints.md
  4dd937d3024e34071e1f77d6d1cec027  gcc/config/i386/core2.md
! 4a97256ac1adfc85403dcdb06d13d734  gcc/config/i386/cpuid.h
  f700a1d35423658eaa2b4908da695bda  gcc/config/i386/cross-stdarg.h
  82964c7428d66bf1874c63a65b858957  gcc/config/i386/crtdll.h
! 6ef36b544c651b07c6532b62a3a4d75c  gcc/config/i386/cygming.h
  f2a2f556815a6dc38e47cca165d51ea3  gcc/config/i386/cygwin-stdint.h
  1868c3b9e51f09941105430ebd8c2286  gcc/config/i386/cygwin-w64.h
  47570db058e06dc2ab076ed2f9cf4242  gcc/config/i386/cygwin.h
*************** a2bf0873375fc2ab681bcd55a2b23e26  gcc/co
*** 4227,4233 ****
  a5346c37d189bcadf27fd946fe2c2566  gcc/config/i386/djgpp.opt
  1b346c8cab1daa697ecd6c31e8e0e1d5  gcc/config/i386/djgpp.opt.urls
  0ada511dcea9cb884e7aed714cecb141  gcc/config/i386/dragonfly.h
! 38d33571f430d3221ccef0104b24cfbf  gcc/config/i386/driver-i386.cc
  8db059b2a4621231dcdc591159eace91  gcc/config/i386/driver-mingw32.cc
  436804c1d1ef71b2a318f01e7e91c190  gcc/config/i386/emmintrin.h
  def0edea16aac07cf3e0e7d2daf27455  gcc/config/i386/enqcmdintrin.h
--- 4230,4236 ----
  a5346c37d189bcadf27fd946fe2c2566  gcc/config/i386/djgpp.opt
  1b346c8cab1daa697ecd6c31e8e0e1d5  gcc/config/i386/djgpp.opt.urls
  0ada511dcea9cb884e7aed714cecb141  gcc/config/i386/dragonfly.h
! 043a1e06186a2ba879e0c763bf75b866  gcc/config/i386/driver-i386.cc
  8db059b2a4621231dcdc591159eace91  gcc/config/i386/driver-mingw32.cc
  436804c1d1ef71b2a318f01e7e91c190  gcc/config/i386/emmintrin.h
  def0edea16aac07cf3e0e7d2daf27455  gcc/config/i386/enqcmdintrin.h
*************** ebf8fdac06861901e2744eb4d97b15c5  gcc/co
*** 4256,4276 ****
  c527fd639b424e1e0a95494e13e8cad2  gcc/config/i386/hresetintrin.h
  597ec35a360b8b37f5d1e4483b508834  gcc/config/i386/i386-builtin-types.awk
  5090ae3207d0bedc79ecdcec7c2cb71b  gcc/config/i386/i386-builtin-types.def
! 81059d1444982c18f0d455534dec5fa5  gcc/config/i386/i386-builtin.def
  652c102e7218f6248806f6cfbae988ed  gcc/config/i386/i386-builtins.cc
  d3fb594d11281112ff8d8f304a000c4e  gcc/config/i386/i386-builtins.h
! 10a38f2a86740708977ea6a86051e67e  gcc/config/i386/i386-c.cc
  54909bb70e074c14dcf4499a5baedc54  gcc/config/i386/i386-d.cc
  172dcd61afc5800b61ebb688838d9adc  gcc/config/i386/i386-d.h
! 67e69fe15b762ace63b044cbbb29326f  gcc/config/i386/i386-expand.cc
  c9c3969c00808c9b6809fbeab3e4a1d2  gcc/config/i386/i386-expand.h
  bc18f421fa068cbf9bd4a5c001fe0818  gcc/config/i386/i386-features.cc
  1ee34fa5f2ae92fd7d48419d8fc529f8  gcc/config/i386/i386-features.h
! 3d9edfe94007cdc032797a67ebe9733e  gcc/config/i386/i386-isa.def
  03ca94d6fcaa109c0837ebc3f067eb3f  gcc/config/i386/i386-jit.cc
  1e61c026f5b7b51c6c07bec125bf4fbe  gcc/config/i386/i386-jit.h
  09f791543c9ad5918bde13160f0de1df  gcc/config/i386/i386-modes.def
! 83885f3d46cc74c687dc87ae9193ecb4  gcc/config/i386/i386-options.cc
  636d7cce4cd0b632fee9d490d15da86b  gcc/config/i386/i386-options.h
  02c486451c524cfc143358e07b88cd70  gcc/config/i386/i386-opts.h
  3c7d0006f2f31d8607f2c9e74557fbee  gcc/config/i386/i386-passes.def
--- 4259,4279 ----
  c527fd639b424e1e0a95494e13e8cad2  gcc/config/i386/hresetintrin.h
  597ec35a360b8b37f5d1e4483b508834  gcc/config/i386/i386-builtin-types.awk
  5090ae3207d0bedc79ecdcec7c2cb71b  gcc/config/i386/i386-builtin-types.def
! 742b488bea1da45aa2ac71d587b55dc9  gcc/config/i386/i386-builtin.def
  652c102e7218f6248806f6cfbae988ed  gcc/config/i386/i386-builtins.cc
  d3fb594d11281112ff8d8f304a000c4e  gcc/config/i386/i386-builtins.h
! 6e6be529907497c0e49ccae4f6fefdfb  gcc/config/i386/i386-c.cc
  54909bb70e074c14dcf4499a5baedc54  gcc/config/i386/i386-d.cc
  172dcd61afc5800b61ebb688838d9adc  gcc/config/i386/i386-d.h
! a7d827c49b22cfc230bec829b1dabc14  gcc/config/i386/i386-expand.cc
  c9c3969c00808c9b6809fbeab3e4a1d2  gcc/config/i386/i386-expand.h
  bc18f421fa068cbf9bd4a5c001fe0818  gcc/config/i386/i386-features.cc
  1ee34fa5f2ae92fd7d48419d8fc529f8  gcc/config/i386/i386-features.h
! ce54c4b8578ee28d3b1b11dcccc2849a  gcc/config/i386/i386-isa.def
  03ca94d6fcaa109c0837ebc3f067eb3f  gcc/config/i386/i386-jit.cc
  1e61c026f5b7b51c6c07bec125bf4fbe  gcc/config/i386/i386-jit.h
  09f791543c9ad5918bde13160f0de1df  gcc/config/i386/i386-modes.def
! baddda59b57ec2cf9d6325a672b13cb6  gcc/config/i386/i386-options.cc
  636d7cce4cd0b632fee9d490d15da86b  gcc/config/i386/i386-options.h
  02c486451c524cfc143358e07b88cd70  gcc/config/i386/i386-opts.h
  3c7d0006f2f31d8607f2c9e74557fbee  gcc/config/i386/i386-passes.def
*************** fb6d632066a5383c0ec89e867a9cc9c6  gcc/co
*** 4278,4292 ****
  5b778b3296ea91dab0ca82338ca6828d  gcc/config/i386/i386-rust-and-jit.inc
  b19c27e8a900f9eeb7d73e2bb4b8d313  gcc/config/i386/i386-rust.cc
  24065393854cd1e08e3285bd707210fe  gcc/config/i386/i386-rust.h
! 65aeafb970568f7d8b006b3bd3131410  gcc/config/i386/i386.cc
! 8074be081d221085c70445d5cac8920f  gcc/config/i386/i386.h
! 61a944c2764dd8002b6cbaf89ebca8ea  gcc/config/i386/i386.md
! 4d6e66705102c7128048fa8c5bbed2a8  gcc/config/i386/i386.opt
! a7ee58e110164c031bb7e72e772d66cc  gcc/config/i386/i386.opt.urls
  f22876926ff4a2cb67b105ac266c72ea  gcc/config/i386/i386elf.h
  12088706f0584b21b2bf165c3cde88e8  gcc/config/i386/ia32intrin.h
  116503ecbb821bb13293049d85a641f9  gcc/config/i386/iamcu.h
! 69a0b6d9649248da0bf49a6c50239bb0  gcc/config/i386/immintrin.h
  619372cf439740085d314ec3bd4aaef7  gcc/config/i386/k6.md
  f25ac919a919b558d8b3364eb84ea8d0  gcc/config/i386/keylockerintrin.h
  dea7969b20f10da9e23e939ae4566e50  gcc/config/i386/kfreebsd-gnu.h
--- 4281,4295 ----
  5b778b3296ea91dab0ca82338ca6828d  gcc/config/i386/i386-rust-and-jit.inc
  b19c27e8a900f9eeb7d73e2bb4b8d313  gcc/config/i386/i386-rust.cc
  24065393854cd1e08e3285bd707210fe  gcc/config/i386/i386-rust.h
! d578483d595eda053ea3a6aec6d76791  gcc/config/i386/i386.cc
! 447fc32a81e923c898e71507fa56d7b8  gcc/config/i386/i386.h
! 1b4da652934a883d353f3589b37ff2d8  gcc/config/i386/i386.md
! e792289f6c7c1f8981a08c25388c504e  gcc/config/i386/i386.opt
! da9fed301f222c1a1a945281ebde6199  gcc/config/i386/i386.opt.urls
  f22876926ff4a2cb67b105ac266c72ea  gcc/config/i386/i386elf.h
  12088706f0584b21b2bf165c3cde88e8  gcc/config/i386/ia32intrin.h
  116503ecbb821bb13293049d85a641f9  gcc/config/i386/iamcu.h
! 92d01747289026c935c2fedd9e1be03e  gcc/config/i386/immintrin.h
  619372cf439740085d314ec3bd4aaef7  gcc/config/i386/k6.md
  f25ac919a919b558d8b3364eb84ea8d0  gcc/config/i386/keylockerintrin.h
  dea7969b20f10da9e23e939ae4566e50  gcc/config/i386/kfreebsd-gnu.h
*************** de4e89bc042c6bc7eb093bda5d33a266  gcc/co
*** 4343,4349 ****
  380f2e50c7d803059b0e7617da00460f  gcc/config/i386/sm4intrin.h
  a24296639492577352dd1309b136bc9a  gcc/config/i386/smmintrin.h
  ffbc43ec2b7f2d37d4a6f69f70d5a345  gcc/config/i386/sol2.h
! e91c3a948778490fe94251fc2bac0c80  gcc/config/i386/sse.md
  7c6ff828c11c2892168a2e450559dcb6  gcc/config/i386/ssemath.h
  7ada9f54207701e1d29fd03ea990e163  gcc/config/i386/stringop.def
  9f75a2e9a9bf20db0bef264cabe77a29  gcc/config/i386/subst.md
--- 4346,4352 ----
  380f2e50c7d803059b0e7617da00460f  gcc/config/i386/sm4intrin.h
  a24296639492577352dd1309b136bc9a  gcc/config/i386/smmintrin.h
  ffbc43ec2b7f2d37d4a6f69f70d5a345  gcc/config/i386/sol2.h
! 50cad2e6257deb95c6bf2279043a27e9  gcc/config/i386/sse.md
  7c6ff828c11c2892168a2e450559dcb6  gcc/config/i386/ssemath.h
  7ada9f54207701e1d29fd03ea990e163  gcc/config/i386/stringop.def
  9f75a2e9a9bf20db0bef264cabe77a29  gcc/config/i386/subst.md
*************** b4cde95b709fc93c90bf4d6b3edc7fd0  gcc/co
*** 4395,4408 ****
  17e3f95274600e3d41c671903847d8ec  gcc/config/i386/x86-tune-sched-atom.cc
  acfa3e6ce1f37bbad35e49e06b663ea9  gcc/config/i386/x86-tune-sched-bd.cc
  13fcb5234b2d8208c12932d96efef72b  gcc/config/i386/x86-tune-sched-core.cc
! 5a7755d4ab94bc8e76dedd1afec3badb  gcc/config/i386/x86-tune-sched.cc
! a22209774c5d6e4cfef16d7c13aeb709  gcc/config/i386/x86-tune.def
  95b91fd21504348ecd2f8510ebab204c  gcc/config/i386/x86gprintrin.h
  1ef1746c703bfdb9c245f7b7276b7d56  gcc/config/i386/x86intrin.h
  709155b5a0371d397baf22295493b77b  gcc/config/i386/xm-cygwin.h
  defa9e0464eba862bed3764716650f29  gcc/config/i386/xm-djgpp.h
  bae94af26195c7e64a5f59018ab9df85  gcc/config/i386/xm-mingw32.h
! 9463d0d50e39a1dff707b4a422f44f1d  gcc/config/i386/xmmintrin.h
  368186e4aee42c25c7031e2fcaa4c3fd  gcc/config/i386/xopintrin.h
  c59d69078b2dfb5edefbca0d79268e54  gcc/config/i386/xsavecintrin.h
  97f252ad13e5079471073dcf6ad3030c  gcc/config/i386/xsaveintrin.h
--- 4398,4411 ----
  17e3f95274600e3d41c671903847d8ec  gcc/config/i386/x86-tune-sched-atom.cc
  acfa3e6ce1f37bbad35e49e06b663ea9  gcc/config/i386/x86-tune-sched-bd.cc
  13fcb5234b2d8208c12932d96efef72b  gcc/config/i386/x86-tune-sched-core.cc
! 2b4b6726487759b3114fd9806d3c32a4  gcc/config/i386/x86-tune-sched.cc
! 2b7c603eab93a346614d02b2fe819738  gcc/config/i386/x86-tune.def
  95b91fd21504348ecd2f8510ebab204c  gcc/config/i386/x86gprintrin.h
  1ef1746c703bfdb9c245f7b7276b7d56  gcc/config/i386/x86intrin.h
  709155b5a0371d397baf22295493b77b  gcc/config/i386/xm-cygwin.h
  defa9e0464eba862bed3764716650f29  gcc/config/i386/xm-djgpp.h
  bae94af26195c7e64a5f59018ab9df85  gcc/config/i386/xm-mingw32.h
! f0e2f038176680312a6cf7d3c8359dd2  gcc/config/i386/xmmintrin.h
  368186e4aee42c25c7031e2fcaa4c3fd  gcc/config/i386/xopintrin.h
  c59d69078b2dfb5edefbca0d79268e54  gcc/config/i386/xsavecintrin.h
  97f252ad13e5079471073dcf6ad3030c  gcc/config/i386/xsaveintrin.h
*************** b4a163b80e648410a29c10e7ef4e213c  gcc/co
*** 4515,4521 ****
  0edad035f69c87e6ed2437d79eef49e1  gcc/config/loongarch/loongarch-str.h
  6ffb969d44f9d52731fdbc6bca845054  gcc/config/loongarch/loongarch-target-attr.cc
  f539c2da7e8d7a3ef7c741bceee19eed  gcc/config/loongarch/loongarch-tune.h
! 4ed3544507f2e1fcb793a631f22592c1  gcc/config/loongarch/loongarch.cc
  9bff1f004518dc1a193488cec1e35e1a  gcc/config/loongarch/loongarch.h
  836cec7217591e9b915216755b1957bc  gcc/config/loongarch/loongarch.md
  984ead0ce7e850d1d8ebc6582a3024fd  gcc/config/loongarch/loongarch.opt
--- 4518,4524 ----
  0edad035f69c87e6ed2437d79eef49e1  gcc/config/loongarch/loongarch-str.h
  6ffb969d44f9d52731fdbc6bca845054  gcc/config/loongarch/loongarch-target-attr.cc
  f539c2da7e8d7a3ef7c741bceee19eed  gcc/config/loongarch/loongarch-tune.h
! 68551268dd9425134f51a5e7a48e95ff  gcc/config/loongarch/loongarch.cc
  9bff1f004518dc1a193488cec1e35e1a  gcc/config/loongarch/loongarch.h
  836cec7217591e9b915216755b1957bc  gcc/config/loongarch/loongarch.md
  984ead0ce7e850d1d8ebc6582a3024fd  gcc/config/loongarch/loongarch.opt
*************** ccf120397e978f8cd4ed98cbe2c0d4f5  gcc/co
*** 4988,4995 ****
  96a9b8701199ede652cadbcdeec423d7  gcc/config/riscv/andes.md
  7444da2915b734a807ab2b707fe0fe35  gcc/config/riscv/andes_vector.h
  3d4ef2c5571dbf0e4bb86d09917f7c07  gcc/config/riscv/arch-canonicalize
! 14a2555a6dd29f700e6b7024febcbe3f  gcc/config/riscv/autovec-opt.md
! 6f1495bb44d6d9bb4878dc8a3250fa82  gcc/config/riscv/autovec.md
  d4306030a8879ce9aa1e6cc18aff56eb  gcc/config/riscv/bitmanip.md
  3d4917c0a2efee97aaca242060652e02  gcc/config/riscv/constraints.md
  4e0968dc35562b151fd162778542718f  gcc/config/riscv/corev.def
--- 4991,4998 ----
  96a9b8701199ede652cadbcdeec423d7  gcc/config/riscv/andes.md
  7444da2915b734a807ab2b707fe0fe35  gcc/config/riscv/andes_vector.h
  3d4ef2c5571dbf0e4bb86d09917f7c07  gcc/config/riscv/arch-canonicalize
! b0b2da9276dd4c805654f99da6fcc076  gcc/config/riscv/autovec-opt.md
! 0780b27d9a2603fd8e71959ad0419817  gcc/config/riscv/autovec.md
  d4306030a8879ce9aa1e6cc18aff56eb  gcc/config/riscv/bitmanip.md
  3d4917c0a2efee97aaca242060652e02  gcc/config/riscv/constraints.md
  4e0968dc35562b151fd162778542718f  gcc/config/riscv/corev.def
*************** d404c19d5b1a2aca0a73917bb692bd96  gcc/co
*** 4997,5004 ****
  c530e27e7ff7458093cb72dcea6d26a8  gcc/config/riscv/crypto.md
  70cc6640001ff23ac9b647ea784ffb2b  gcc/config/riscv/elf.h
  9a5e3c714ef42f079425c3c0af8184dc  gcc/config/riscv/freebsd.h
! 1bc5c74b1340281b5b6ce05eed2d74fd  gcc/config/riscv/gen-riscv-ext-opt.cc
! d88ea862a5be7784a17a698cc6a7c5e5  gcc/config/riscv/gen-riscv-ext-texi.cc
  cf7e3b74a177d82efae8944960b963a5  gcc/config/riscv/gen-riscv-mcpu-texi.cc
  07b6093b3b5eac46d2fd1184d333101a  gcc/config/riscv/gen-riscv-mtune-texi.cc
  fdf40414be0404faa2f689ccff02d68d  gcc/config/riscv/generic-ooo.md
--- 5000,5007 ----
  c530e27e7ff7458093cb72dcea6d26a8  gcc/config/riscv/crypto.md
  70cc6640001ff23ac9b647ea784ffb2b  gcc/config/riscv/elf.h
  9a5e3c714ef42f079425c3c0af8184dc  gcc/config/riscv/freebsd.h
! 9a73086e37ae8c9672fbdd8288a09c68  gcc/config/riscv/gen-riscv-ext-opt.cc
! 9b5dffc44b8bc0f4d12e2f52148750c1  gcc/config/riscv/gen-riscv-ext-texi.cc
  cf7e3b74a177d82efae8944960b963a5  gcc/config/riscv/gen-riscv-mcpu-texi.cc
  07b6093b3b5eac46d2fd1184d333101a  gcc/config/riscv/gen-riscv-mtune-texi.cc
  fdf40414be0404faa2f689ccff02d68d  gcc/config/riscv/generic-ooo.md
*************** bffa0caedd7144aff55c80a16431d1a1  gcc/co
*** 5014,5021 ****
  80e8994ee9e6abf380e68aca6443d157  gcc/config/riscv/peephole.md
  a3d3fa9142d4e2ed34ead146941c574a  gcc/config/riscv/pic.md
  674baa66306b2b08e1b80995759f5381  gcc/config/riscv/pipeline-checker
! 5a2de8a3ef45be990e2a676b93069985  gcc/config/riscv/predicates.md
! 47128c226cbf453b9816615bc43b879b  gcc/config/riscv/riscv-avlprop.cc
  179d92544e7a65f0ccf206e876026744  gcc/config/riscv/riscv-bclr-lowest-set-bit.cc
  e54a2d33c6fb9bb0381889dad6fa71d8  gcc/config/riscv/riscv-builtins.cc
  44c502ebc66c1ee0f150a119b170a63c  gcc/config/riscv/riscv-c.cc
--- 5017,5024 ----
  80e8994ee9e6abf380e68aca6443d157  gcc/config/riscv/peephole.md
  a3d3fa9142d4e2ed34ead146941c574a  gcc/config/riscv/pic.md
  674baa66306b2b08e1b80995759f5381  gcc/config/riscv/pipeline-checker
! a077a05a5835fab7137a1d41d03441b5  gcc/config/riscv/predicates.md
! cf45a8ed95fa845d6f648e14b0bc2caf  gcc/config/riscv/riscv-avlprop.cc
  179d92544e7a65f0ccf206e876026744  gcc/config/riscv/riscv-bclr-lowest-set-bit.cc
  e54a2d33c6fb9bb0381889dad6fa71d8  gcc/config/riscv/riscv-builtins.cc
  44c502ebc66c1ee0f150a119b170a63c  gcc/config/riscv/riscv-c.cc
*************** b13609eaffc2081ddd2cda1290a2b2c4  gcc/co
*** 5024,5035 ****
  173996678a5bf2b1b40e30fe260109b4  gcc/config/riscv/riscv-d.cc
  790bd2a5355776ab5ebf4c7814489760  gcc/config/riscv/riscv-d.h
  5d018c4d2b91ca8e5745a3eb3b3b17cd  gcc/config/riscv/riscv-ext-andes.def
! 9848282285cd3a3e21f6181f220f6ba9  gcc/config/riscv/riscv-ext-corev.def
  e5ee9a298220a6317f6fd463f229fc22  gcc/config/riscv/riscv-ext-mips.def
! a8a293d3f8f01367abc68e7556a51898  gcc/config/riscv/riscv-ext-sifive.def
  627262a9fe6f0261a9e6d59a28544d83  gcc/config/riscv/riscv-ext-spacemit.def
! 85fb34f0d0de09dc83b4df6f525d78f9  gcc/config/riscv/riscv-ext-thead.def
! 5551f756c3aae6dce60511f7f52efa5c  gcc/config/riscv/riscv-ext-ventana.def
  4f885a9060908c8f84ff25ad1518c05c  gcc/config/riscv/riscv-ext.def
  d72211affddf6f00b90cc9c258efe14d  gcc/config/riscv/riscv-ext.opt
  8463b74f5d66e1a7f0d58a7ae087d8ad  gcc/config/riscv/riscv-ext.opt.urls
--- 5027,5038 ----
  173996678a5bf2b1b40e30fe260109b4  gcc/config/riscv/riscv-d.cc
  790bd2a5355776ab5ebf4c7814489760  gcc/config/riscv/riscv-d.h
  5d018c4d2b91ca8e5745a3eb3b3b17cd  gcc/config/riscv/riscv-ext-andes.def
! 29843ffab8170b07cffd6a91d300e241  gcc/config/riscv/riscv-ext-corev.def
  e5ee9a298220a6317f6fd463f229fc22  gcc/config/riscv/riscv-ext-mips.def
! b6257cb327a2e9bc1b4f303235b43436  gcc/config/riscv/riscv-ext-sifive.def
  627262a9fe6f0261a9e6d59a28544d83  gcc/config/riscv/riscv-ext-spacemit.def
! ded4bbf01f624d02f029b02c9c7ac765  gcc/config/riscv/riscv-ext-thead.def
! 59e2535037359d1237d4953bc6bbf7f9  gcc/config/riscv/riscv-ext-ventana.def
  4f885a9060908c8f84ff25ad1518c05c  gcc/config/riscv/riscv-ext.def
  d72211affddf6f00b90cc9c258efe14d  gcc/config/riscv/riscv-ext.opt
  8463b74f5d66e1a7f0d58a7ae087d8ad  gcc/config/riscv/riscv-ext.opt.urls
*************** fb8278eead727b22c3863e30a89fbc0c  gcc/co
*** 5040,5072 ****
  e1bb69cfc54bb16775e01e36a6718b15  gcc/config/riscv/riscv-opts.h
  4b5f5f162a40b5ae9dc3359a58f10c33  gcc/config/riscv/riscv-passes.def
  6a4ba8b1df2cb6b09b291d1fdeded67c  gcc/config/riscv/riscv-profiles.def
! 0e489a6ff0b54dcfdf781f1343fdc50e  gcc/config/riscv/riscv-protos.h
  446f0f39c6f980e246ea56f1233e9271  gcc/config/riscv/riscv-scalar-crypto.def
! 003d5626ce3adcac7ca55401c7dec2bc  gcc/config/riscv/riscv-selftests.cc
  da4e034d23a8f2754b1dfce0122f286e  gcc/config/riscv/riscv-shorten-memrefs.cc
  62b31689063eeeca8f0e7ae25da92d0a  gcc/config/riscv/riscv-sr.cc
  38e9863d2a2af1a5773ed060b713ccc1  gcc/config/riscv/riscv-string.cc
  3b52301e3425e6de33a2436af4de6bd8  gcc/config/riscv/riscv-subset.h
  cf55107f936e04e71b010f2f0948d4c8  gcc/config/riscv/riscv-target-attr.cc
! 38e8f0fc6acfe20295d7783aec360f3b  gcc/config/riscv/riscv-v.cc
  0d419e9df116fed7ce6e0ae15131417e  gcc/config/riscv/riscv-v.h
  c5f3161dedd668dfb126ffb191cfb236  gcc/config/riscv/riscv-vect-permconst.cc
! 472dc58a1c70b0345dcced1152fb8244  gcc/config/riscv/riscv-vector-builtins-bases.cc
  689f453a4cdf7fa3e64a7f4bfba8f7dd  gcc/config/riscv/riscv-vector-builtins-bases.h
  bdc5f6caf56fd0411faf705e9c32ccd4  gcc/config/riscv/riscv-vector-builtins-functions.def
  278d45dd3b6250781b7481f0bb02266b  gcc/config/riscv/riscv-vector-builtins-shapes.cc
  7e178dc137007d4ca1aaaaf29940c12f  gcc/config/riscv/riscv-vector-builtins-shapes.h
  dba94786c1a18e3f5fbcca2b5c0af496  gcc/config/riscv/riscv-vector-builtins-types.def
! 2d8f2fe245bee4b96da8cc6a5db36214  gcc/config/riscv/riscv-vector-builtins.cc
  9cbc8a65b5045746afeedeb7b0404c5c  gcc/config/riscv/riscv-vector-builtins.def
  222117629707cd3603c59cd1d3ebfb83  gcc/config/riscv/riscv-vector-builtins.h
! a8fdfe0455fce7cebbb65a7e70831d8a  gcc/config/riscv/riscv-vector-costs.cc
  2a441fb15ed4d774924fe163f29ccf7a  gcc/config/riscv/riscv-vector-costs.h
  4f6ae86b313b2a103caaaca3ec27eb47  gcc/config/riscv/riscv-vector-switch.def
  724b5012debbc56e08795eb0d757a8ed  gcc/config/riscv/riscv-vsetvl.cc
  d120ed6eb2847b636271b3a1ef82ecbf  gcc/config/riscv/riscv-vsetvl.def
  7082a18dbfc574d47bf71f4d50dd30f9  gcc/config/riscv/riscv-zicfilp.cc
! b7792b16226d9d8a187df3952748a40b  gcc/config/riscv/riscv.cc
  7a65f8b385600c8a895a04444c2334d3  gcc/config/riscv/riscv.h
  df70b8958bb33644092fa7f52e8dcb7a  gcc/config/riscv/riscv.md
  8f19f0367d8843752ea81feb762a76b3  gcc/config/riscv/riscv.opt
--- 5043,5075 ----
  e1bb69cfc54bb16775e01e36a6718b15  gcc/config/riscv/riscv-opts.h
  4b5f5f162a40b5ae9dc3359a58f10c33  gcc/config/riscv/riscv-passes.def
  6a4ba8b1df2cb6b09b291d1fdeded67c  gcc/config/riscv/riscv-profiles.def
! 7db6bacc2a6b412f9f7bfa842aadea57  gcc/config/riscv/riscv-protos.h
  446f0f39c6f980e246ea56f1233e9271  gcc/config/riscv/riscv-scalar-crypto.def
! c171108cfab16c74097a841489b04298  gcc/config/riscv/riscv-selftests.cc
  da4e034d23a8f2754b1dfce0122f286e  gcc/config/riscv/riscv-shorten-memrefs.cc
  62b31689063eeeca8f0e7ae25da92d0a  gcc/config/riscv/riscv-sr.cc
  38e9863d2a2af1a5773ed060b713ccc1  gcc/config/riscv/riscv-string.cc
  3b52301e3425e6de33a2436af4de6bd8  gcc/config/riscv/riscv-subset.h
  cf55107f936e04e71b010f2f0948d4c8  gcc/config/riscv/riscv-target-attr.cc
! 6c1b54e33125042fe285e1166963f558  gcc/config/riscv/riscv-v.cc
  0d419e9df116fed7ce6e0ae15131417e  gcc/config/riscv/riscv-v.h
  c5f3161dedd668dfb126ffb191cfb236  gcc/config/riscv/riscv-vect-permconst.cc
! f7155afde45201d3356ca654c816d3a5  gcc/config/riscv/riscv-vector-builtins-bases.cc
  689f453a4cdf7fa3e64a7f4bfba8f7dd  gcc/config/riscv/riscv-vector-builtins-bases.h
  bdc5f6caf56fd0411faf705e9c32ccd4  gcc/config/riscv/riscv-vector-builtins-functions.def
  278d45dd3b6250781b7481f0bb02266b  gcc/config/riscv/riscv-vector-builtins-shapes.cc
  7e178dc137007d4ca1aaaaf29940c12f  gcc/config/riscv/riscv-vector-builtins-shapes.h
  dba94786c1a18e3f5fbcca2b5c0af496  gcc/config/riscv/riscv-vector-builtins-types.def
! 1c4a04c26672cb0d483765c3ee8a638d  gcc/config/riscv/riscv-vector-builtins.cc
  9cbc8a65b5045746afeedeb7b0404c5c  gcc/config/riscv/riscv-vector-builtins.def
  222117629707cd3603c59cd1d3ebfb83  gcc/config/riscv/riscv-vector-builtins.h
! 75d4d869655d4a7b1fe2f93fabf24c81  gcc/config/riscv/riscv-vector-costs.cc
  2a441fb15ed4d774924fe163f29ccf7a  gcc/config/riscv/riscv-vector-costs.h
  4f6ae86b313b2a103caaaca3ec27eb47  gcc/config/riscv/riscv-vector-switch.def
  724b5012debbc56e08795eb0d757a8ed  gcc/config/riscv/riscv-vsetvl.cc
  d120ed6eb2847b636271b3a1ef82ecbf  gcc/config/riscv/riscv-vsetvl.def
  7082a18dbfc574d47bf71f4d50dd30f9  gcc/config/riscv/riscv-zicfilp.cc
! b9dee007ac6fd1c526a645e2de3f834c  gcc/config/riscv/riscv.cc
  7a65f8b385600c8a895a04444c2334d3  gcc/config/riscv/riscv.h
  df70b8958bb33644092fa7f52e8dcb7a  gcc/config/riscv/riscv.md
  8f19f0367d8843752ea81feb762a76b3  gcc/config/riscv/riscv.opt
*************** b5fb046770f7e60fc485d6092c296c38  gcc/co
*** 5088,5094 ****
  afc3d8034fa9acd880634ca7807d70a8  gcc/config/riscv/spacemit-x60.md
  faca69fa18f3f779cd3ee4d6a53e6193  gcc/config/riscv/sync-rvwmo.md
  4dff560d8961c6dd9b4dd18c668c629e  gcc/config/riscv/sync-ztso.md
! e99034efee42fab0266bbd7690bd92db  gcc/config/riscv/sync.md
  1c27821991689abdaa7a908a0cc8dfa4  gcc/config/riscv/t-elf-multilib
  381cb38e167feed84dad697fce89cabd  gcc/config/riscv/t-linux
  1ed181a166b1d0e206c4a4e0024cce2a  gcc/config/riscv/t-linux-multilib
--- 5091,5097 ----
  afc3d8034fa9acd880634ca7807d70a8  gcc/config/riscv/spacemit-x60.md
  faca69fa18f3f779cd3ee4d6a53e6193  gcc/config/riscv/sync-rvwmo.md
  4dff560d8961c6dd9b4dd18c668c629e  gcc/config/riscv/sync-ztso.md
! 1cffac0de41c5b63259bfec4e3c07bb0  gcc/config/riscv/sync.md
  1c27821991689abdaa7a908a0cc8dfa4  gcc/config/riscv/t-elf-multilib
  381cb38e167feed84dad697fce89cabd  gcc/config/riscv/t-linux
  1ed181a166b1d0e206c4a4e0024cce2a  gcc/config/riscv/t-linux-multilib
*************** bcf728ad2379630774fd5bb529d4ee86  gcc/co
*** 5103,5111 ****
  6db368570eae8b4003cba3d4eab94aa9  gcc/config/riscv/thead.md
  27cf4e9b6199721b239c10c84ecdc2e4  gcc/config/riscv/tt-ascalon-d8.md
  b5e46305db1116cc1758b504ea37fe74  gcc/config/riscv/vector-bfloat16.md
! 88f7597398d0c8b8b87baba5fd207996  gcc/config/riscv/vector-crypto.md
! cf9f38e85752fd2a3ceafd8b1521322a  gcc/config/riscv/vector-iterators.md
! 3a2e592c6ae4996adc76f7618a28e079  gcc/config/riscv/vector.md
  18d213c106fe52eebc74017d5ff892ce  gcc/config/riscv/xiangshan.md
  0f64aaa114ab62a1a46f7ac422d6a129  gcc/config/riscv/zc.md
  36cba2444ae9c8f107fee34492bd0ed6  gcc/config/riscv/zicond.md
--- 5106,5114 ----
  6db368570eae8b4003cba3d4eab94aa9  gcc/config/riscv/thead.md
  27cf4e9b6199721b239c10c84ecdc2e4  gcc/config/riscv/tt-ascalon-d8.md
  b5e46305db1116cc1758b504ea37fe74  gcc/config/riscv/vector-bfloat16.md
! 68ec1dbeaaa81bae31a89d9fc934b32e  gcc/config/riscv/vector-crypto.md
! 5ab6c683eb7a163d697f865dcc4c9e62  gcc/config/riscv/vector-iterators.md
! 61d018f1047546638bdb476c3ddd69a7  gcc/config/riscv/vector.md
  18d213c106fe52eebc74017d5ff892ce  gcc/config/riscv/xiangshan.md
  0f64aaa114ab62a1a46f7ac422d6a129  gcc/config/riscv/zc.md
  36cba2444ae9c8f107fee34492bd0ed6  gcc/config/riscv/zicond.md
*************** dce39de8bb20b88ffeb8b2073101dcfe  gcc/co
*** 5235,5241 ****
  062e9e612338d86d0d47a3e1131384fa  gcc/config/rs6000/rs6000-tables.opt
  ce8de9a27f36b759a69194616c02eb38  gcc/config/rs6000/rs6000-tables.opt.urls
  3db6a717f9dcac1e92b1b7809a4f97cd  gcc/config/rs6000/rs6000.cc
! 1d91827dae3ab7a332473805ac3cf40c  gcc/config/rs6000/rs6000.h
  436f411ef141a9e9faf742a0e0e4d4c6  gcc/config/rs6000/rs6000.md
  77c1c38e6705e421b8838bf19f938cef  gcc/config/rs6000/rs6000.opt
  d46cc498f0b6a0445ba8e61e7054ed20  gcc/config/rs6000/rs6000.opt.urls
--- 5238,5244 ----
  062e9e612338d86d0d47a3e1131384fa  gcc/config/rs6000/rs6000-tables.opt
  ce8de9a27f36b759a69194616c02eb38  gcc/config/rs6000/rs6000-tables.opt.urls
  3db6a717f9dcac1e92b1b7809a4f97cd  gcc/config/rs6000/rs6000.cc
! 0d7d6a61b11d57d7180bb95f6ac803ed  gcc/config/rs6000/rs6000.h
  436f411ef141a9e9faf742a0e0e4d4c6  gcc/config/rs6000/rs6000.md
  77c1c38e6705e421b8838bf19f938cef  gcc/config/rs6000/rs6000.opt
  d46cc498f0b6a0445ba8e61e7054ed20  gcc/config/rs6000/rs6000.opt.urls
*************** d7112093049d4abbc421609d032b7358  gcc/co
*** 5333,5339 ****
  724b9c8075459b5c23142704c2ba1865  gcc/config/s390/s390-opts.h
  87bca0c72260bdf7b32cbe797e607999  gcc/config/s390/s390-passes.def
  b6426b7457d4617875547be76bb5112d  gcc/config/s390/s390-protos.h
! 0c8add06b9fdcfba48121044bb98b19a  gcc/config/s390/s390.cc
  fedf0be07777b765b244a82ecf4fe421  gcc/config/s390/s390.h
  def1eabaa50c31445465c2f80ad807fe  gcc/config/s390/s390.md
  2b0ec6eba7d16cee640146cd31989c99  gcc/config/s390/s390.opt
--- 5336,5342 ----
  724b9c8075459b5c23142704c2ba1865  gcc/config/s390/s390-opts.h
  87bca0c72260bdf7b32cbe797e607999  gcc/config/s390/s390-passes.def
  b6426b7457d4617875547be76bb5112d  gcc/config/s390/s390-protos.h
! a738e87bf0ff048d217e5f9acc5810b4  gcc/config/s390/s390.cc
  fedf0be07777b765b244a82ecf4fe421  gcc/config/s390/s390.h
  def1eabaa50c31445465c2f80ad807fe  gcc/config/s390/s390.md
  2b0ec6eba7d16cee640146cd31989c99  gcc/config/s390/s390.opt
*************** ef292bd063751273e93912005054621c  gcc/co
*** 5588,5594 ****
  784e78d129e667eb51b57cd3bb4cf498  gcc/config/xtensa/elf.opt
  f140d72c4f00aa6f39295fedb6f6fc92  gcc/config/xtensa/elf.opt.urls
  7d826e1325729fc54de80be38daf7484  gcc/config/xtensa/linux.h
! 6b7e8cc7697bfb7418bcb3add76abbda  gcc/config/xtensa/predicates.md
  9909237e265cc03c48173ae6280a7b66  gcc/config/xtensa/t-xtensa
  4cf53f30f4e09026e45f314036f2449e  gcc/config/xtensa/uclinux.h
  4d05c7a063b0b89e0e6f4cf516e0da92  gcc/config/xtensa/uclinux.opt
--- 5591,5597 ----
  784e78d129e667eb51b57cd3bb4cf498  gcc/config/xtensa/elf.opt
  f140d72c4f00aa6f39295fedb6f6fc92  gcc/config/xtensa/elf.opt.urls
  7d826e1325729fc54de80be38daf7484  gcc/config/xtensa/linux.h
! e47765fd829fb28300166f381db02162  gcc/config/xtensa/predicates.md
  9909237e265cc03c48173ae6280a7b66  gcc/config/xtensa/t-xtensa
  4cf53f30f4e09026e45f314036f2449e  gcc/config/xtensa/uclinux.h
  4d05c7a063b0b89e0e6f4cf516e0da92  gcc/config/xtensa/uclinux.opt
*************** f140d72c4f00aa6f39295fedb6f6fc92  gcc/co
*** 5597,5609 ****
  c7be35a23fd70ac184dd9072319304c7  gcc/config/xtensa/xtensa-opts.h
  f154c7dc9175c4e8204205bb4fbd2cbc  gcc/config/xtensa/xtensa-passes.def
  23de1a423f72982c1a7ec04a2cf54364  gcc/config/xtensa/xtensa-protos.h
! 49d78213dc9f09252fa92ac80408f9b0  gcc/config/xtensa/xtensa.cc
  1c1ce8236bb94fc6c2784ab209bff598  gcc/config/xtensa/xtensa.h
  0e227e351d2efea226ca8c249e52aff3  gcc/config/xtensa/xtensa.md
  f0452ea712955ce21c9c149136850780  gcc/config/xtensa/xtensa.opt
  db57d7603312357e8c0cfb21c32353d1  gcc/config/xtensa/xtensa.opt.urls
! 919b3547a9b052a91dfdb02a6e02ab68  gcc/configure
! 62342358812d6993144b5b103cf00497  gcc/configure.ac
  ec3aa966ca3fe9c6f84d4378160541b6  gcc/context.cc
  d1bde52b8dee0c0c5506d7e320b1bb61  gcc/context.h
  a9c3cddee4e237141062720b72fe38cd  gcc/convert.cc
--- 5600,5612 ----
  c7be35a23fd70ac184dd9072319304c7  gcc/config/xtensa/xtensa-opts.h
  f154c7dc9175c4e8204205bb4fbd2cbc  gcc/config/xtensa/xtensa-passes.def
  23de1a423f72982c1a7ec04a2cf54364  gcc/config/xtensa/xtensa-protos.h
! 578543f44ba812e1ea040be6a9e0b6a7  gcc/config/xtensa/xtensa.cc
  1c1ce8236bb94fc6c2784ab209bff598  gcc/config/xtensa/xtensa.h
  0e227e351d2efea226ca8c249e52aff3  gcc/config/xtensa/xtensa.md
  f0452ea712955ce21c9c149136850780  gcc/config/xtensa/xtensa.opt
  db57d7603312357e8c0cfb21c32353d1  gcc/config/xtensa/xtensa.opt.urls
! b57d777328ee2a9661db341e01f731a9  gcc/configure
! 6a02a8634fc2d88b839f9ecba76d4395  gcc/configure.ac
  ec3aa966ca3fe9c6f84d4378160541b6  gcc/context.cc
  d1bde52b8dee0c0c5506d7e320b1bb61  gcc/context.h
  a9c3cddee4e237141062720b72fe38cd  gcc/convert.cc
*************** a9c3cddee4e237141062720b72fe38cd  gcc/co
*** 5613,5619 ****
  5d31df44fc0a5b17beb74ce0ff38e214  gcc/coroutine-passes.cc
  02796caeaa2f14f72dc3c9c23cc97dfc  gcc/coverage.cc
  722fb5fda78e55c5af5da72cad78751f  gcc/coverage.h
! 67342768b3b00e0bde531640f0227129  gcc/cp/ChangeLog
  70c059f2b75a2fc1bb95a526b21b8cd7  gcc/cp/ChangeLog-1993
  7cbd106e10a0ba7c052bee3fe20671c2  gcc/cp/ChangeLog-1994
  3b1e3ed23ad4363f75e6fd2fbb583dee  gcc/cp/ChangeLog-1995
--- 5616,5622 ----
  5d31df44fc0a5b17beb74ce0ff38e214  gcc/coroutine-passes.cc
  02796caeaa2f14f72dc3c9c23cc97dfc  gcc/coverage.cc
  722fb5fda78e55c5af5da72cad78751f  gcc/coverage.h
! 55ee3ba48026d0355e06476163f12460  gcc/cp/ChangeLog
  70c059f2b75a2fc1bb95a526b21b8cd7  gcc/cp/ChangeLog-1993
  7cbd106e10a0ba7c052bee3fe20671c2  gcc/cp/ChangeLog-1994
  3b1e3ed23ad4363f75e6fd2fbb583dee  gcc/cp/ChangeLog-1995
*************** fce8de27014c109814b3f69be6a5d4f6  gcc/cp
*** 5655,5661 ****
  a096f968454d0245d006f9f559a56a08  gcc/cp/class.cc
  ee3fb2cc9b9557d3895f527353160bd4  gcc/cp/config-lang.in
  0b92202b0cb62d8185cdfa9677e5b713  gcc/cp/constexpr.cc
! 6989db9e0165df0eb4e437ac3596cd48  gcc/cp/constraint.cc
  b4452de3b42a36f42cdd92b905d201b6  gcc/cp/contracts.cc
  e995f4adf7a857b715c0534a24556d3b  gcc/cp/contracts.h
  de31e99c416f73448d9f45f50a7d4823  gcc/cp/coroutines.cc
--- 5658,5664 ----
  a096f968454d0245d006f9f559a56a08  gcc/cp/class.cc
  ee3fb2cc9b9557d3895f527353160bd4  gcc/cp/config-lang.in
  0b92202b0cb62d8185cdfa9677e5b713  gcc/cp/constexpr.cc
! edf99013149e80a5e321bf8c831b0dd8  gcc/cp/constraint.cc
  b4452de3b42a36f42cdd92b905d201b6  gcc/cp/contracts.cc
  e995f4adf7a857b715c0534a24556d3b  gcc/cp/contracts.h
  de31e99c416f73448d9f45f50a7d4823  gcc/cp/coroutines.cc
*************** de31e99c416f73448d9f45f50a7d4823  gcc/cp
*** 5667,5689 ****
  acb30767d403ad5a0d7ae97437159ebe  gcc/cp/cp-objcp-common.h
  99f4b67f8ef26f58f35166be5ae39170  gcc/cp/cp-trait.def
  d219c7261c4e8b7d170b10d9b450f256  gcc/cp/cp-tree.def
! 724000d77e08c79426c069f3b8884456  gcc/cp/cp-tree.h
  e5ccdda9d62d96ac397910d0fa391b0a  gcc/cp/cp-ubsan.cc
  dce6e74658eab6bdf17f4f3b74e84891  gcc/cp/cvt.cc
  8e454e3f7746836df899a46698f5af3e  gcc/cp/cxx-pretty-print.cc
  2d4d94b8a1d1c1d26764ae93a8039dda  gcc/cp/cxx-pretty-print.h
  c5f1614ded8bb57480eb7d1afecb7c7c  gcc/cp/cxxapi-data.csv
! f07186296ecdd492ac437a19c9c8c96c  gcc/cp/decl.cc
  7f116fdc50b24dcb13cdcf096636aef9  gcc/cp/decl.h
! a1fb87c99967896feccfe593636a2368  gcc/cp/decl2.cc
  691a10b3246d19925433648ba9a4ea9a  gcc/cp/dump.cc
! 839ddc69347ac968987974eedc0ea5a7  gcc/cp/error.cc
  856ffef082c6d62b43386d99e03e94b0  gcc/cp/except.cc
  6e7ef55a429d1521e6ceb90830dc8a9a  gcc/cp/expr.cc
  8e304891ca80b19f9426e06f41201de6  gcc/cp/friend.cc
  f17d1a51b511b5ce45839d373e36be71  gcc/cp/g++spec.cc
  30b9ed40d39cf78b95792ef5dca2aebb  gcc/cp/gen-cxxapi-file.py
! 377bfb8826c6d37a017bce2538c7069d  gcc/cp/init.cc
  5ccbfdb682bc156eb436b763ee892050  gcc/cp/lambda.cc
  8274216dc9f1baac0c5d34774aba7558  gcc/cp/lang-specs.h
  f43fedd5fd24018bc0a3c348196ec826  gcc/cp/lex.cc
--- 5670,5692 ----
  acb30767d403ad5a0d7ae97437159ebe  gcc/cp/cp-objcp-common.h
  99f4b67f8ef26f58f35166be5ae39170  gcc/cp/cp-trait.def
  d219c7261c4e8b7d170b10d9b450f256  gcc/cp/cp-tree.def
! 5c8bb313d5accd50b7452bf3a0cfb767  gcc/cp/cp-tree.h
  e5ccdda9d62d96ac397910d0fa391b0a  gcc/cp/cp-ubsan.cc
  dce6e74658eab6bdf17f4f3b74e84891  gcc/cp/cvt.cc
  8e454e3f7746836df899a46698f5af3e  gcc/cp/cxx-pretty-print.cc
  2d4d94b8a1d1c1d26764ae93a8039dda  gcc/cp/cxx-pretty-print.h
  c5f1614ded8bb57480eb7d1afecb7c7c  gcc/cp/cxxapi-data.csv
! aa7c55b3bc5dd7de044ac8709a5d8e2f  gcc/cp/decl.cc
  7f116fdc50b24dcb13cdcf096636aef9  gcc/cp/decl.h
! 9624c5a3f54ecd737591ce9cb13c32ba  gcc/cp/decl2.cc
  691a10b3246d19925433648ba9a4ea9a  gcc/cp/dump.cc
! 7470ea0cf3543a1a98de1bb0a976e290  gcc/cp/error.cc
  856ffef082c6d62b43386d99e03e94b0  gcc/cp/except.cc
  6e7ef55a429d1521e6ceb90830dc8a9a  gcc/cp/expr.cc
  8e304891ca80b19f9426e06f41201de6  gcc/cp/friend.cc
  f17d1a51b511b5ce45839d373e36be71  gcc/cp/g++spec.cc
  30b9ed40d39cf78b95792ef5dca2aebb  gcc/cp/gen-cxxapi-file.py
! 60a059003917a4cd9bddb46e01fb1727  gcc/cp/init.cc
  5ccbfdb682bc156eb436b763ee892050  gcc/cp/lambda.cc
  8274216dc9f1baac0c5d34774aba7558  gcc/cp/lang-specs.h
  f43fedd5fd24018bc0a3c348196ec826  gcc/cp/lex.cc
*************** aaf76a9b03fd0532d2904aef004fd66a  gcc/cp
*** 5693,5716 ****
  6c77b1fab5f6d146677090285a202a50  gcc/cp/mapper-client.h
  44e22b51797f89c9da996523a6d97f1c  gcc/cp/mapper-resolver.cc
  a87a2754a8a50d73ad227fee0e31caec  gcc/cp/method.cc
! 6a7b266a896fa9c6565a2998af394f6d  gcc/cp/module.cc
! f1f183b4320198a66dd316934a528e05  gcc/cp/name-lookup.cc
! 496f323514612f2e06231cb67428b04e  gcc/cp/name-lookup.h
  e7fe06956aada61bcaae5168ad47a9c1  gcc/cp/operators.def
  813c253a000ee20d8d6598f56edc400e  gcc/cp/optimize.cc
! d6a3485f2ca3e16725710fb1bef68903  gcc/cp/parser.cc
! f6ddd589a7423f07d554dad74c5e43a7  gcc/cp/parser.h
! 3ce1e0ad5cddef00d6d7b8a3f2b9674b  gcc/cp/pt.cc
  b606903e35fe6806362fe4eee7a89fef  gcc/cp/ptree.cc
! ee1ddf1e1b9554bb1a10109ce8c6dee5  gcc/cp/rtti.cc
  9c5477f737d2c390510c3fe72454f657  gcc/cp/search.cc
! 15eb28598ab5e2f6c67492e7244d3569  gcc/cp/semantics.cc
  8ccc82546d801360d2ccd8fd2a48b5d6  gcc/cp/std-name-hint.gperf
  bb87dbae9e49b63a73c4afa927a9018e  gcc/cp/std-name-hint.h
! 1fe34e428beb7b18d5180400e36d9f86  gcc/cp/tree.cc
  bb1304379ac1bf9a568942bc7e976e8a  gcc/cp/type-utils.h
! dd07aba39873c93f6859b787c8ab428c  gcc/cp/typeck.cc
! 2b27861b0d392281a32cc8cdb1d8eae5  gcc/cp/typeck2.cc
  aa6906e22dc44502ca268580e5b8dfdd  gcc/cp/vtable-class-hierarchy.cc
  c74d2f6cc5dcb1bf1953c093eb903b37  gcc/cppbuiltin.cc
  05a136afb0839d5238cd1390602e748e  gcc/cppbuiltin.h
--- 5696,5719 ----
  6c77b1fab5f6d146677090285a202a50  gcc/cp/mapper-client.h
  44e22b51797f89c9da996523a6d97f1c  gcc/cp/mapper-resolver.cc
  a87a2754a8a50d73ad227fee0e31caec  gcc/cp/method.cc
! d127347a18b541897b589ac8983500c1  gcc/cp/module.cc
! 09ce3d1773fa040d7156df184f93a3ef  gcc/cp/name-lookup.cc
! 31b07642e37cb14980ac9d71307ffb09  gcc/cp/name-lookup.h
  e7fe06956aada61bcaae5168ad47a9c1  gcc/cp/operators.def
  813c253a000ee20d8d6598f56edc400e  gcc/cp/optimize.cc
! 3df32cdf6de14ffb260c20baa2298171  gcc/cp/parser.cc
! dd486113810dfaf82462dc26b748a48f  gcc/cp/parser.h
! 6a8f13efd01c05fd31a21d46d8505e1b  gcc/cp/pt.cc
  b606903e35fe6806362fe4eee7a89fef  gcc/cp/ptree.cc
! 3ffd52177d902f09ccffd5f1cc9dfe30  gcc/cp/rtti.cc
  9c5477f737d2c390510c3fe72454f657  gcc/cp/search.cc
! a9f602071c974a24aff7524b97028373  gcc/cp/semantics.cc
  8ccc82546d801360d2ccd8fd2a48b5d6  gcc/cp/std-name-hint.gperf
  bb87dbae9e49b63a73c4afa927a9018e  gcc/cp/std-name-hint.h
! 7ba2906539e812a38fddb3fa26a4b7c3  gcc/cp/tree.cc
  bb1304379ac1bf9a568942bc7e976e8a  gcc/cp/type-utils.h
! fe7d18769a554d68af8f77182841f715  gcc/cp/typeck.cc
! fa7f9cad7e86f25adafb968afd4852b1  gcc/cp/typeck2.cc
  aa6906e22dc44502ca268580e5b8dfdd  gcc/cp/vtable-class-hierarchy.cc
  c74d2f6cc5dcb1bf1953c093eb903b37  gcc/cppbuiltin.cc
  05a136afb0839d5238cd1390602e748e  gcc/cppbuiltin.h
*************** eea2c218106edc18c40919ad04f90bf8  gcc/cp
*** 5720,5726 ****
  9b5eac8e75a52c0f6080cee20a27587a  gcc/crc-verification.cc
  ec1e9c9456a8530e241079823e2fc126  gcc/crc-verification.h
  9d3c9741dc7aa7fb63e5b4b472a4feb1  gcc/cse.cc
! 9a6f70c45240207f951e8742aa47ea9c  gcc/cselib.cc
  44a1aa31be5edacb5f5644352fbb669c  gcc/cselib.h
  1ded054093de910d9786c62bc4fe8cc6  gcc/cstamp-h.in
  d980e3c4abd7ebfe505123a9fe01e4db  gcc/ctfc.cc
--- 5723,5729 ----
  9b5eac8e75a52c0f6080cee20a27587a  gcc/crc-verification.cc
  ec1e9c9456a8530e241079823e2fc126  gcc/crc-verification.h
  9d3c9741dc7aa7fb63e5b4b472a4feb1  gcc/cse.cc
! 45eae5527892c4d4a0bbc5c19a508db2  gcc/cselib.cc
  44a1aa31be5edacb5f5644352fbb669c  gcc/cselib.h
  1ded054093de910d9786c62bc4fe8cc6  gcc/cstamp-h.in
  d980e3c4abd7ebfe505123a9fe01e4db  gcc/ctfc.cc
*************** acdfc663791e4321372e79932070d05d  gcc/do
*** 6086,6092 ****
  81ae745aed5479afae430c578fa29055  gcc/doc/cppinternals.texi
  916609b97298dbc7d4d607a08543d64f  gcc/doc/cppopts.texi
  14b0532614eb25d7d84e7efd6664ecf3  gcc/doc/cppwarnopts.texi
! 852b9a351d719f86b9eaaab3dab4d227  gcc/doc/extend.texi
  ddcdbcb699f5252a1c1219d92d87ed8b  gcc/doc/fragments.texi
  cd346f0c279f68138ef08c7addc796de  gcc/doc/frontends.texi
  a28615d9873d98f0d5f4ef8dd3e4c39d  gcc/doc/gcc.texi
--- 6089,6095 ----
  81ae745aed5479afae430c578fa29055  gcc/doc/cppinternals.texi
  916609b97298dbc7d4d607a08543d64f  gcc/doc/cppopts.texi
  14b0532614eb25d7d84e7efd6664ecf3  gcc/doc/cppwarnopts.texi
! 0d1c5e6aef5f5cdee76ae5461b771895  gcc/doc/extend.texi
  ddcdbcb699f5252a1c1219d92d87ed8b  gcc/doc/fragments.texi
  cd346f0c279f68138ef08c7addc796de  gcc/doc/frontends.texi
  a28615d9873d98f0d5f4ef8dd3e4c39d  gcc/doc/gcc.texi
*************** ee4c7654f733cefcb73d4fd24f3e1b82  gcc/do
*** 6108,6116 ****
  9512a9fe27682edff7dd2ed171bbb853  gcc/doc/include/gcc-common.texi
  95c90bf85d3eab67f348ee3ce0bf4050  gcc/doc/include/gpl_v3.texi
  e9b8122841fbfbbc30fee8ed6613c399  gcc/doc/include/texinfo.tex
! 92e92962c982d3290684f9657660ad88  gcc/doc/install.texi
  0f98706361e63fac2c35c2c4491eaac4  gcc/doc/install.texi2html
! 101fa5b74e74a846d185daab0bf0fc13  gcc/doc/invoke.texi
  47f1f55b3595acf670eb6193a0cbd933  gcc/doc/languages.texi
  8783f1b0b6c204d4417b00f3b772beea  gcc/doc/libgcc.texi
  ef4f00c423089323edef1d3cff31a4a2  gcc/doc/libgdiagnostics/Makefile
--- 6111,6119 ----
  9512a9fe27682edff7dd2ed171bbb853  gcc/doc/include/gcc-common.texi
  95c90bf85d3eab67f348ee3ce0bf4050  gcc/doc/include/gpl_v3.texi
  e9b8122841fbfbbc30fee8ed6613c399  gcc/doc/include/texinfo.tex
! b7d273b89c588dc7a8d620e6a9c90f90  gcc/doc/install.texi
  0f98706361e63fac2c35c2c4491eaac4  gcc/doc/install.texi2html
! 9b3004695965bdc199f2bd8e85f55be9  gcc/doc/invoke.texi
  47f1f55b3595acf670eb6193a0cbd933  gcc/doc/languages.texi
  8783f1b0b6c204d4417b00f3b772beea  gcc/doc/libgcc.texi
  ef4f00c423089323edef1d3cff31a4a2  gcc/doc/libgdiagnostics/Makefile
*************** a1f65f3aec3cc5d5b6505fb976d4c216  gcc/do
*** 6148,6154 ****
  c98feb0a43876ed3ef2fca3c8448e8f8  gcc/doc/lto.texi
  26f08ad01720c082109915a4ec33c80f  gcc/doc/makefile.texi
  2f8484fc473d3a7141e34a260b920ea3  gcc/doc/match-and-simplify.texi
! 54eb9404280abee0d0a04e14630dd457  gcc/doc/md.texi
  8836b7001f069e8dead6a4643108258b  gcc/doc/objc.texi
  9673b2a6dd62d5ac08afb00421e98cdb  gcc/doc/optinfo.texi
  a7117c4fee8c54e338b967886f3b2dcb  gcc/doc/options.texi
--- 6151,6157 ----
  c98feb0a43876ed3ef2fca3c8448e8f8  gcc/doc/lto.texi
  26f08ad01720c082109915a4ec33c80f  gcc/doc/makefile.texi
  2f8484fc473d3a7141e34a260b920ea3  gcc/doc/match-and-simplify.texi
! 7d5bea817ab5029dd6882185e015bfe4  gcc/doc/md.texi
  8836b7001f069e8dead6a4643108258b  gcc/doc/objc.texi
  9673b2a6dd62d5ac08afb00421e98cdb  gcc/doc/optinfo.texi
  a7117c4fee8c54e338b967886f3b2dcb  gcc/doc/options.texi
*************** e0434ec541556c6ba008fe012784ad16  gcc/do
*** 6163,6169 ****
  bd20fd07c5ee8f444bf1d3f5e64e066a  gcc/doc/service.texi
  662dca51632c008a252102b76f63a95a  gcc/doc/sourcebuild.texi
  256b54301263a6c10e6e88798debd9e3  gcc/doc/standards.texi
! 0c0a61051d1104610d7593a2eec374c3  gcc/doc/tm.texi
  ca93e26f45f99e628a14a760a3b02746  gcc/doc/tm.texi.in
  173ab0ec22dd651701e36e43ed21375f  gcc/doc/tree-ssa.texi
  5f62752970e47d350c8cbce47123d1cf  gcc/doc/trouble.texi
--- 6166,6172 ----
  bd20fd07c5ee8f444bf1d3f5e64e066a  gcc/doc/service.texi
  662dca51632c008a252102b76f63a95a  gcc/doc/sourcebuild.texi
  256b54301263a6c10e6e88798debd9e3  gcc/doc/standards.texi
! e6fedbd33be444d2a534437a506a525c  gcc/doc/tm.texi
  ca93e26f45f99e628a14a760a3b02746  gcc/doc/tm.texi.in
  173ab0ec22dd651701e36e43ed21375f  gcc/doc/tree-ssa.texi
  5f62752970e47d350c8cbce47123d1cf  gcc/doc/trouble.texi
*************** b21182651156de7779948fe8ca2c4160  gcc/dw
*** 6187,6193 ****
  186b01005d892edba3b03fc17bd0dc8f  gcc/dwarf2codeview.h
  990f627cfa0aa26758dc2ffa0422da1b  gcc/dwarf2ctf.cc
  1d0191caafac1774f50a47175d915ea0  gcc/dwarf2ctf.h
! 6d293f92c36f5f40ea6a17021b660bd4  gcc/dwarf2out.cc
  7ff70632352b65c214e02360ed6d6aae  gcc/dwarf2out.h
  fdd976759ee89958c91a4010e53c0f02  gcc/early-remat.cc
  0fa3f12b9f441f701d99e167274a0961  gcc/emit-rtl.cc
--- 6190,6196 ----
  186b01005d892edba3b03fc17bd0dc8f  gcc/dwarf2codeview.h
  990f627cfa0aa26758dc2ffa0422da1b  gcc/dwarf2ctf.cc
  1d0191caafac1774f50a47175d915ea0  gcc/dwarf2ctf.h
! a50f22a9b00f6712879671800e855212  gcc/dwarf2out.cc
  7ff70632352b65c214e02360ed6d6aae  gcc/dwarf2out.h
  fdd976759ee89958c91a4010e53c0f02  gcc/early-remat.cc
  0fa3f12b9f441f701d99e167274a0961  gcc/emit-rtl.cc
*************** b0756a8dbbe0b39051dfda2c5e26663f  gcc/fi
*** 6216,6229 ****
  77b50b9533828ae8b124e191cc55b74f  gcc/final.cc
  28cc3b30502fab34fffa55fd82454e16  gcc/fixed-value.cc
  7852b04b41add4ad6cc7c7c86cb82658  gcc/fixed-value.h
! d752cd9a8d46470c7f60cd7fc3ff2cf4  gcc/flag-types.h
  e8c5838138a5e07e5716964a8284e9a1  gcc/flags.h
  b7bf1ecba30babcca6fcc9e9a66bebfb  gcc/fold-const-call.cc
  182559f127e8416b9e9abcffb267d5fc  gcc/fold-const-call.h
  17f1e7f727e08a6e42a5ecbeedca48b5  gcc/fold-const.cc
  09573b86bdb27d2d064ccdd670710fde  gcc/fold-const.h
  cd4e6baf5d162fbd41160606055f8297  gcc/fold-mem-offsets.cc
! f47d5c6ec831196d53b940fba2ffc5ca  gcc/fortran/ChangeLog
  083c53fadafdcf3be46713838a51e36c  gcc/fortran/ChangeLog-2002
  2a4ca18d211fb2603139354fd16398ed  gcc/fortran/ChangeLog-2003
  e7462609ebd0dd7c874e0fc00e2833aa  gcc/fortran/ChangeLog-2004
--- 6219,6232 ----
  77b50b9533828ae8b124e191cc55b74f  gcc/final.cc
  28cc3b30502fab34fffa55fd82454e16  gcc/fixed-value.cc
  7852b04b41add4ad6cc7c7c86cb82658  gcc/fixed-value.h
! a7760ce11f8802f8cd4f1e203b582592  gcc/flag-types.h
  e8c5838138a5e07e5716964a8284e9a1  gcc/flags.h
  b7bf1ecba30babcca6fcc9e9a66bebfb  gcc/fold-const-call.cc
  182559f127e8416b9e9abcffb267d5fc  gcc/fold-const-call.h
  17f1e7f727e08a6e42a5ecbeedca48b5  gcc/fold-const.cc
  09573b86bdb27d2d064ccdd670710fde  gcc/fold-const.h
  cd4e6baf5d162fbd41160606055f8297  gcc/fold-mem-offsets.cc
! f0d000e781d30e20bc688ae2b81cd663  gcc/fortran/ChangeLog
  083c53fadafdcf3be46713838a51e36c  gcc/fortran/ChangeLog-2002
  2a4ca18d211fb2603139354fd16398ed  gcc/fortran/ChangeLog-2003
  e7462609ebd0dd7c874e0fc00e2833aa  gcc/fortran/ChangeLog-2004
*************** aed3aedb6378a970055dff9e11eedc2d  gcc/fo
*** 6260,6287 ****
  16ea0e15947038265fbb5983b455b7bf  gcc/fortran/constructor.cc
  85285f438769e841d8dc39fedcd731d5  gcc/fortran/constructor.h
  8a26ac4e9bbfcee3a5911bf1864ee2e6  gcc/fortran/convert.cc
! 684bee52c4789faf429f7df554f0891c  gcc/fortran/cpp.cc
  b7e224f665bb5044ce35ed09435bd4fb  gcc/fortran/cpp.h
  a232f4d280ad08511e2718281b3d1ab6  gcc/fortran/data.cc
  d85e2f2fc3ee4721563bd47719063fb6  gcc/fortran/data.h
  6fa8c2d2d6646feaae51271e24ce9d43  gcc/fortran/decl.cc
  917fd2716f1eef2f47d4f032e14958ad  gcc/fortran/dependency.cc
  70111b1c7592e650c281b513c3cf2f47  gcc/fortran/dependency.h
! 029735552d67a599918afceb5c9067aa  gcc/fortran/dump-parse-tree.cc
  fcdf26536d578abd3a720a2579b4def5  gcc/fortran/error.cc
! 7617494d6a00986d20b6e62ab8e26a70  gcc/fortran/expr.cc
! 64cd8af37cf94e944e54f1c1fe1eaef5  gcc/fortran/f95-lang.cc
  5fad9972996846ea1af084cc613ae8b5  gcc/fortran/frontend-passes.cc
  a39f360f255f1ef6dfd91ccefef63e05  gcc/fortran/gfc-diagnostic.def
  bd08c55098f00394b9922e6163c27b92  gcc/fortran/gfc-internals.texi
! 94aacc49d064750afb608e1a14969f5a  gcc/fortran/gfortran.h
! 51080f85cdf0c15f058a19f00f38bce7  gcc/fortran/gfortran.texi
  af66ab40a5434219772b76ad10035e45  gcc/fortran/gfortranspec.cc
  e4fe6ce0303cd182ebd328bdb0ae5743  gcc/fortran/interface.cc
  74d5cc035a8e6ee1fb5826c965c90532  gcc/fortran/intrinsic.cc
  47e0e62e0a6eaad27941f8e734cda2a2  gcc/fortran/intrinsic.h
  e4b048e3c76dd062984cec31ab97a29d  gcc/fortran/intrinsic.texi
! 5473a119790d46d5095d68484263a5f9  gcc/fortran/invoke.texi
  4a91f323761835f16a1a9b3995485379  gcc/fortran/io.cc
  d2a28ef98f6f78d1608fb52204e013a5  gcc/fortran/ioparm.def
  4d2d654877c2408059ea42ec970d9e6b  gcc/fortran/iresolve.cc
--- 6263,6290 ----
  16ea0e15947038265fbb5983b455b7bf  gcc/fortran/constructor.cc
  85285f438769e841d8dc39fedcd731d5  gcc/fortran/constructor.h
  8a26ac4e9bbfcee3a5911bf1864ee2e6  gcc/fortran/convert.cc
! 08a50dfb0a8f7fbd14421c680f0b0390  gcc/fortran/cpp.cc
  b7e224f665bb5044ce35ed09435bd4fb  gcc/fortran/cpp.h
  a232f4d280ad08511e2718281b3d1ab6  gcc/fortran/data.cc
  d85e2f2fc3ee4721563bd47719063fb6  gcc/fortran/data.h
  6fa8c2d2d6646feaae51271e24ce9d43  gcc/fortran/decl.cc
  917fd2716f1eef2f47d4f032e14958ad  gcc/fortran/dependency.cc
  70111b1c7592e650c281b513c3cf2f47  gcc/fortran/dependency.h
! b9ec8a53356a221f303b3ec8bf1cad67  gcc/fortran/dump-parse-tree.cc
  fcdf26536d578abd3a720a2579b4def5  gcc/fortran/error.cc
! 4a8ae1882e9261f7beaa354b3ecaca12  gcc/fortran/expr.cc
! 723c358b58284256c9b46a5358ba7050  gcc/fortran/f95-lang.cc
  5fad9972996846ea1af084cc613ae8b5  gcc/fortran/frontend-passes.cc
  a39f360f255f1ef6dfd91ccefef63e05  gcc/fortran/gfc-diagnostic.def
  bd08c55098f00394b9922e6163c27b92  gcc/fortran/gfc-internals.texi
! 6ab4d2bd69fb7c9806d03a83de0f7a9f  gcc/fortran/gfortran.h
! fc1726c6b4827e602f3cde01eea0478e  gcc/fortran/gfortran.texi
  af66ab40a5434219772b76ad10035e45  gcc/fortran/gfortranspec.cc
  e4fe6ce0303cd182ebd328bdb0ae5743  gcc/fortran/interface.cc
  74d5cc035a8e6ee1fb5826c965c90532  gcc/fortran/intrinsic.cc
  47e0e62e0a6eaad27941f8e734cda2a2  gcc/fortran/intrinsic.h
  e4b048e3c76dd062984cec31ab97a29d  gcc/fortran/intrinsic.texi
! 3ada13146de7aceedea825a104103adf  gcc/fortran/invoke.texi
  4a91f323761835f16a1a9b3995485379  gcc/fortran/io.cc
  d2a28ef98f6f78d1608fb52204e013a5  gcc/fortran/ioparm.def
  4d2d654877c2408059ea42ec970d9e6b  gcc/fortran/iresolve.cc
*************** cc75a1ff850c3546d6c8156895b54c5a  gcc/fo
*** 6297,6309 ****
  763c37f838e32f5ed8ad600157a0d951  gcc/fortran/mathbuiltins.def
  6e89e2e347d7f6e1576cbda0e958b5bd  gcc/fortran/misc.cc
  c2ff9c82debbc68da75c5a307ef1b138  gcc/fortran/module.cc
! 845de4d821f6b5e1ed814be1c3022223  gcc/fortran/openmp.cc
  97facac1dd9ae327c6c4547b527e4527  gcc/fortran/options.cc
  803727385bdded6044f6397cbfcb705d  gcc/fortran/parse.cc
  718f4db6bea1b398551c501068f61597  gcc/fortran/parse.h
  c381d2f08a8a8b647089c5236ed5364a  gcc/fortran/primary.cc
! a9bd6084141151240ceb92c53632a84f  gcc/fortran/resolve.cc
! 8dc2391850ee95634781b6e296a096f6  gcc/fortran/scanner.cc
  3c39e0eef946c7f557ac375f23b9f3db  gcc/fortran/scanner.h
  d78cc6d6b48b8228757fb8b674f6ad9b  gcc/fortran/simplify.cc
  ebfc538fb0470443c527273e8a50c2a1  gcc/fortran/st.cc
--- 6300,6312 ----
  763c37f838e32f5ed8ad600157a0d951  gcc/fortran/mathbuiltins.def
  6e89e2e347d7f6e1576cbda0e958b5bd  gcc/fortran/misc.cc
  c2ff9c82debbc68da75c5a307ef1b138  gcc/fortran/module.cc
! cfea3267ba62c5b6980ae0ce30ae886a  gcc/fortran/openmp.cc
  97facac1dd9ae327c6c4547b527e4527  gcc/fortran/options.cc
  803727385bdded6044f6397cbfcb705d  gcc/fortran/parse.cc
  718f4db6bea1b398551c501068f61597  gcc/fortran/parse.h
  c381d2f08a8a8b647089c5236ed5364a  gcc/fortran/primary.cc
! e443d38fa4473ebcd01aa57732c0c850  gcc/fortran/resolve.cc
! 44b9f31e2e4f86676ee5d39f92f397bd  gcc/fortran/scanner.cc
  3c39e0eef946c7f557ac375f23b9f3db  gcc/fortran/scanner.h
  d78cc6d6b48b8228757fb8b674f6ad9b  gcc/fortran/simplify.cc
  ebfc538fb0470443c527273e8a50c2a1  gcc/fortran/st.cc
*************** f13dfeafc421dcdcc35ec7a854ae1a77  gcc/fo
*** 6316,6330 ****
  fa8521f4c98868ee5fa7e9dea5a35e37  gcc/fortran/trans-const.cc
  857805820c2a6ac77d2652c610d23de8  gcc/fortran/trans-const.h
  1bf381029ae74da9d767c99d6e64940d  gcc/fortran/trans-decl.cc
! d56ea64da5cc1b4646832b288055ffc4  gcc/fortran/trans-expr.cc
  2889ceeab429a8d9e062daa88b51dd03  gcc/fortran/trans-intrinsic.cc
  2d29342f65aeef2af368527483b2d4f1  gcc/fortran/trans-io.cc
! c034cfe7281ba9e816c14777f6504b0e  gcc/fortran/trans-openmp.cc
  cd091509b69239b87561c8695ce522ca  gcc/fortran/trans-stmt.cc
  9caf8a2f93e6cf5e2a567a3aa18f957c  gcc/fortran/trans-stmt.h
  24751fdbf5162757525888384f73dfd7  gcc/fortran/trans-types.cc
  422959ab20fd75df3766a03597227fd2  gcc/fortran/trans-types.h
! 47d7a4f95fe5f62d3f8d58763509ad3d  gcc/fortran/trans.cc
  cc062433370f6b8d6b7731c3ced71024  gcc/fortran/trans.h
  6f893e67fc7e5f247079bd418e61d1e2  gcc/fortran/trigd_fe.inc
  2ddfa7f2ac232123d67959795d85aaa6  gcc/fortran/types.def
--- 6319,6333 ----
  fa8521f4c98868ee5fa7e9dea5a35e37  gcc/fortran/trans-const.cc
  857805820c2a6ac77d2652c610d23de8  gcc/fortran/trans-const.h
  1bf381029ae74da9d767c99d6e64940d  gcc/fortran/trans-decl.cc
! 1ed8325c9cd56739bff4fc842cf9e21a  gcc/fortran/trans-expr.cc
  2889ceeab429a8d9e062daa88b51dd03  gcc/fortran/trans-intrinsic.cc
  2d29342f65aeef2af368527483b2d4f1  gcc/fortran/trans-io.cc
! 277cdabea225994706c39ebe0e0fad51  gcc/fortran/trans-openmp.cc
  cd091509b69239b87561c8695ce522ca  gcc/fortran/trans-stmt.cc
  9caf8a2f93e6cf5e2a567a3aa18f957c  gcc/fortran/trans-stmt.h
  24751fdbf5162757525888384f73dfd7  gcc/fortran/trans-types.cc
  422959ab20fd75df3766a03597227fd2  gcc/fortran/trans-types.h
! 1f9774b2d205dd21ecb0e98366996c05  gcc/fortran/trans.cc
  cc062433370f6b8d6b7731c3ced71024  gcc/fortran/trans.h
  6f893e67fc7e5f247079bd418e61d1e2  gcc/fortran/trigd_fe.inc
  2ddfa7f2ac232123d67959795d85aaa6  gcc/fortran/types.def
*************** cac72ec7acd3c0b9265d75c09766a847  gcc/gc
*** 6347,6353 ****
  74b8852724cd126309c2e814288bcaa4  gcc/gcc-urlifier.cc
  3ba51d67080efcd8791ea2eaf4103d72  gcc/gcc-urlifier.def
  7e2f3c81fe7c2381b433886ab2914fa7  gcc/gcc-urlifier.h
! 5959f8cd12e6eadc0424ecf79f74ad4a  gcc/gcc.cc
  265ae8f124014a92ca7dee798d9c2b46  gcc/gcc.h
  d66e80f2ea9c1b6754479c999040b857  gcc/gcov-counter.def
  c4e07547b91be991d1bed6c22015cec2  gcc/gcov-dump.cc
--- 6350,6356 ----
  74b8852724cd126309c2e814288bcaa4  gcc/gcc-urlifier.cc
  3ba51d67080efcd8791ea2eaf4103d72  gcc/gcc-urlifier.def
  7e2f3c81fe7c2381b433886ab2914fa7  gcc/gcc-urlifier.h
! 1bd4f4b586810d171ea39db498eaccc8  gcc/gcc.cc
  265ae8f124014a92ca7dee798d9c2b46  gcc/gcc.h
  d66e80f2ea9c1b6754479c999040b857  gcc/gcov-counter.def
  c4e07547b91be991d1bed6c22015cec2  gcc/gcov-dump.cc
*************** a5a23bee543191529294d325e1de0424  gcc/ge
*** 6384,6393 ****
  505f802b42b5e0fab91876db24fed173  gcc/gengtype-lex.l
  8b99c04e54d5d4377c4fbf3dcab54659  gcc/gengtype-parse.cc
  fc2add74b25837de88ed3c40f4f1193d  gcc/gengtype-state.cc
! 1e163a15894754209927f6da377f7eb3  gcc/gengtype.cc
  f8db11f7873a70ad5009e0d6d239f1c8  gcc/gengtype.h
  674c5935f7327cc27a11efeb1a30d0a0  gcc/genhooks.cc
! f462d5a18a683a40d6f1e731674d483f  gcc/genmatch.cc
  a97b3578ac581dcde94c740fbde65486  gcc/genmddeps.cc
  8c578841175ffc99a0d2e35d5844de5f  gcc/genmddump.cc
  2d5f79e0543565e8a2c55a08a6ba8393  gcc/genmodes.cc
--- 6387,6396 ----
  505f802b42b5e0fab91876db24fed173  gcc/gengtype-lex.l
  8b99c04e54d5d4377c4fbf3dcab54659  gcc/gengtype-parse.cc
  fc2add74b25837de88ed3c40f4f1193d  gcc/gengtype-state.cc
! f5985d42e0a0fe673af41f033b73aa1d  gcc/gengtype.cc
  f8db11f7873a70ad5009e0d6d239f1c8  gcc/gengtype.h
  674c5935f7327cc27a11efeb1a30d0a0  gcc/genhooks.cc
! aaebdaaecf7af1a5c5c76cb4f27d423a  gcc/genmatch.cc
  a97b3578ac581dcde94c740fbde65486  gcc/genmddeps.cc
  8c578841175ffc99a0d2e35d5844de5f  gcc/genmddump.cc
  2d5f79e0543565e8a2c55a08a6ba8393  gcc/genmodes.cc
*************** cf3104344cd1bd624fd31423353ea269  gcc/gi
*** 6444,6458 ****
  c8dd21ff63045c1a13e516534e9f26c8  gcc/gimple-range-edge.h
  92fd16a2650fbd57ba2c72841e98771d  gcc/gimple-range-fold.cc
  e7ca0edf79f7bcfe8856f81863f47d7d  gcc/gimple-range-fold.h
! 2ab6e680fbd55d50bfc4690e2ecf8a4f  gcc/gimple-range-gori.cc
  db61cb44af184c491426f70b14b72f64  gcc/gimple-range-gori.h
  60c1306ed88dab1ceb0f87187653585f  gcc/gimple-range-infer.cc
  d1b8fdd0fd8c738683e5995bf45cda94  gcc/gimple-range-infer.h
! afe93bca845d66d8f5c8bb4e79507028  gcc/gimple-range-op.cc
! c33a426eeaa6da07a474caf81b43a278  gcc/gimple-range-op.h
  9b17c9e2e81ab747e378d3e9a891675b  gcc/gimple-range-path.cc
  55a80a9f04099be643d37e29c9ac7d10  gcc/gimple-range-path.h
! f5f2a2bd714b9aba3bf45fbcd137ee4a  gcc/gimple-range-phi.cc
  079db3f6a23a106d51d55dfa751664d3  gcc/gimple-range-phi.h
  8a80a7176e272213da512b76afcab3d7  gcc/gimple-range-tests.cc
  74bf54ac2be468226c893a76f7919cbf  gcc/gimple-range-trace.cc
--- 6447,6461 ----
  c8dd21ff63045c1a13e516534e9f26c8  gcc/gimple-range-edge.h
  92fd16a2650fbd57ba2c72841e98771d  gcc/gimple-range-fold.cc
  e7ca0edf79f7bcfe8856f81863f47d7d  gcc/gimple-range-fold.h
! 77fe03fd98cf05a1c12a80fdad6237c2  gcc/gimple-range-gori.cc
  db61cb44af184c491426f70b14b72f64  gcc/gimple-range-gori.h
  60c1306ed88dab1ceb0f87187653585f  gcc/gimple-range-infer.cc
  d1b8fdd0fd8c738683e5995bf45cda94  gcc/gimple-range-infer.h
! a9b54049deea914c035bbb0d03ad7449  gcc/gimple-range-op.cc
! 446746a57d5d1a23699d36f2252a61ba  gcc/gimple-range-op.h
  9b17c9e2e81ab747e378d3e9a891675b  gcc/gimple-range-path.cc
  55a80a9f04099be643d37e29c9ac7d10  gcc/gimple-range-path.h
! 1489e3b09e3726f2c955d57351d0d75c  gcc/gimple-range-phi.cc
  079db3f6a23a106d51d55dfa751664d3  gcc/gimple-range-phi.h
  8a80a7176e272213da512b76afcab3d7  gcc/gimple-range-tests.cc
  74bf54ac2be468226c893a76f7919cbf  gcc/gimple-range-trace.cc
*************** b417ca4d3d865879d0e642790dafa8cf  gcc/gi
*** 6467,6473 ****
  7cc5761502132b3ca93063369ba8f5c0  gcc/gimple-ssa-sccopy.cc
  b551cb1f1566bf3aa2bca3816f2b1c98  gcc/gimple-ssa-split-paths.cc
  fcc4ed911cdab9bdd135501c8faeb812  gcc/gimple-ssa-sprintf.cc
! 87d47a47b50b82ce1660751e9d73d3b3  gcc/gimple-ssa-store-merging.cc
  5081e3b07e7210c50573a328ecd9e1b9  gcc/gimple-ssa-strength-reduction.cc
  caf2aebd4f089b468d37972535cbf647  gcc/gimple-ssa-warn-access.cc
  3ae7b597d9d5e0c5ba61dc7ee8a7f2c2  gcc/gimple-ssa-warn-access.h
--- 6470,6476 ----
  7cc5761502132b3ca93063369ba8f5c0  gcc/gimple-ssa-sccopy.cc
  b551cb1f1566bf3aa2bca3816f2b1c98  gcc/gimple-ssa-split-paths.cc
  fcc4ed911cdab9bdd135501c8faeb812  gcc/gimple-ssa-sprintf.cc
! b052b8dd14259957553a95ae1333a608  gcc/gimple-ssa-store-merging.cc
  5081e3b07e7210c50573a328ecd9e1b9  gcc/gimple-ssa-strength-reduction.cc
  caf2aebd4f089b468d37972535cbf647  gcc/gimple-ssa-warn-access.cc
  3ae7b597d9d5e0c5ba61dc7ee8a7f2c2  gcc/gimple-ssa-warn-access.h
*************** c33f19efabf2e1331a65e467f6a2e7fc  gcc/gi
*** 6478,6484 ****
  7f8c492dbd88d8d371f858c251bb8d5c  gcc/gimple-streamer-in.cc
  c46e71acb17764a720ac6a68007b7298  gcc/gimple-streamer-out.cc
  469e775c51a02638e22300d5645b22ce  gcc/gimple-streamer.h
! b5b13ba4f92b3ef5294cee911b571925  gcc/gimple-walk.cc
  898d5f9cd9c732cb06cb7e84ca28c99b  gcc/gimple-walk.h
  b5ed1ca4ba5f0f56cd7e3ec1d2a1d01f  gcc/gimple-warn-recursion.cc
  0809761e93e784b8b311ec9cfaab0e63  gcc/gimple.cc
--- 6481,6487 ----
  7f8c492dbd88d8d371f858c251bb8d5c  gcc/gimple-streamer-in.cc
  c46e71acb17764a720ac6a68007b7298  gcc/gimple-streamer-out.cc
  469e775c51a02638e22300d5645b22ce  gcc/gimple-streamer.h
! d53058e1232157a29fe4f71179a2458f  gcc/gimple-walk.cc
  898d5f9cd9c732cb06cb7e84ca28c99b  gcc/gimple-walk.h
  b5ed1ca4ba5f0f56cd7e3ec1d2a1d01f  gcc/gimple-warn-recursion.cc
  0809761e93e784b8b311ec9cfaab0e63  gcc/gimple.cc
*************** ed9c9a9b8efbcca1621cb38f6a7f739b  gcc/gi
*** 6486,6492 ****
  1835ccd82890f84e5a82ca342d0c5455  gcc/gimple.h
  78067ab7e777ee9d0a105da78655ee19  gcc/gimplify-me.cc
  84814cb09300f3db388dd0d22133ccb4  gcc/gimplify-me.h
! ce218e5b4c329178858e9fead738e927  gcc/gimplify.cc
  08a911f7f8b65840f9b57e0e76a2061c  gcc/gimplify.h
  ba3039c0ed9645080c52c0d4bc46096f  gcc/gimplify_reg_info.h
  7df17d7c2bcdff0a474d633a02195544  gcc/ginclude/float.h
--- 6489,6495 ----
  1835ccd82890f84e5a82ca342d0c5455  gcc/gimple.h
  78067ab7e777ee9d0a105da78655ee19  gcc/gimplify-me.cc
  84814cb09300f3db388dd0d22133ccb4  gcc/gimplify-me.h
! a35647328713597f39a2d820251c4804  gcc/gimplify.cc
  08a911f7f8b65840f9b57e0e76a2061c  gcc/gimplify.h
  ba3039c0ed9645080c52c0d4bc46096f  gcc/gimplify_reg_info.h
  7df17d7c2bcdff0a474d633a02195544  gcc/ginclude/float.h
*************** c5d6aaa7e913ef205113a2bba2e5206f  gcc/go
*** 6522,6528 ****
  ec49aa04ab6e271ed2c9c16d80ede5fd  gcc/go/go-sha1.cc
  9e1f364c7cce987a1ae4edab7aeb4ba7  gcc/go/go-system.h
  5d4950ecb7b26d2c5e4e7b4e0dd74707  gcc/go/gofrontend/LICENSE
! cb2238c988069dc62f07ba508fb23593  gcc/go/gofrontend/MERGE
  3a55d95595a6f9e37dee53826b4daff2  gcc/go/gofrontend/PATENTS
  31c16a91d82f8ad3319819ebbba2d17f  gcc/go/gofrontend/README
  f121b2384cf688c9a215cd09a62e60b8  gcc/go/gofrontend/ast-dump.cc
--- 6525,6531 ----
  ec49aa04ab6e271ed2c9c16d80ede5fd  gcc/go/go-sha1.cc
  9e1f364c7cce987a1ae4edab7aeb4ba7  gcc/go/go-system.h
  5d4950ecb7b26d2c5e4e7b4e0dd74707  gcc/go/gofrontend/LICENSE
! d02ba16ff340b2a48cd18f2fc168daba  gcc/go/gofrontend/MERGE
  3a55d95595a6f9e37dee53826b4daff2  gcc/go/gofrontend/PATENTS
  31c16a91d82f8ad3319819ebbba2d17f  gcc/go/gofrontend/README
  f121b2384cf688c9a215cd09a62e60b8  gcc/go/gofrontend/ast-dump.cc
*************** b2382217b0cdd6780d4a73074019478e  gcc/gr
*** 6577,6583 ****
  0a17f8d61bae01b9b643880f7f2c17b2  gcc/graphds.cc
  902cd397382b2fcd5c82b58058da5229  gcc/graphds.h
  002cf4c101220f2b7dbe660b57c4f5d9  gcc/graphite-dependences.cc
! e60b7a14c34b20b6a3f132101d648d09  gcc/graphite-isl-ast-to-gimple.cc
  376b25a89363d7b098a4c967db2b7b29  gcc/graphite-optimize-isl.cc
  a39be7421a418fc441f0372c3cde3777  gcc/graphite-poly.cc
  b31732d7a4fe3de8e26b483ab3a44651  gcc/graphite-scop-detection.cc
--- 6580,6586 ----
  0a17f8d61bae01b9b643880f7f2c17b2  gcc/graphds.cc
  902cd397382b2fcd5c82b58058da5229  gcc/graphds.h
  002cf4c101220f2b7dbe660b57c4f5d9  gcc/graphite-dependences.cc
! 1d9c43638585eb8e2775a173ff26b60b  gcc/graphite-isl-ast-to-gimple.cc
  376b25a89363d7b098a4c967db2b7b29  gcc/graphite-optimize-isl.cc
  a39be7421a418fc441f0372c3cde3777  gcc/graphite-poly.cc
  b31732d7a4fe3de8e26b483ab3a44651  gcc/graphite-scop-detection.cc
*************** b31732d7a4fe3de8e26b483ab3a44651  gcc/gr
*** 6590,6596 ****
  4f9ffef63d4b3ae5c0c7cafc11816ac2  gcc/gsyms.h
  8585d36b3917e41144ca7ee8a6b5e065  gcc/gsyslimits.h
  053ee4a84e4593c88c088f25e153d1a5  gcc/gtm-builtins.def
! 87cc9d25731e0eb84e214143403050c2  gcc/haifa-sched.cc
  d4abb22ea25bb75f623a81023294a28b  gcc/hard-reg-set.h
  d6e4aa327744bebf23d0737d5c4122bc  gcc/hash-map-tests.cc
  a7fb406037fcb6153b3c205f2980edde  gcc/hash-map-traits.h
--- 6593,6599 ----
  4f9ffef63d4b3ae5c0c7cafc11816ac2  gcc/gsyms.h
  8585d36b3917e41144ca7ee8a6b5e065  gcc/gsyslimits.h
  053ee4a84e4593c88c088f25e153d1a5  gcc/gtm-builtins.def
! 348b7668f2a231a1e6cb7c336ac00c0b  gcc/haifa-sched.cc
  d4abb22ea25bb75f623a81023294a28b  gcc/hard-reg-set.h
  d6e4aa327744bebf23d0737d5c4122bc  gcc/hash-map-tests.cc
  a7fb406037fcb6153b3c205f2980edde  gcc/hash-map-traits.h
*************** f875de05790ff6f9d4a538f3165a775b  gcc/in
*** 6622,6636 ****
  0dc4e5a1c70a5b34153b06594dd3ae85  gcc/insn-addr.h
  eec072fb4c8277a3634cf4cdc0846598  gcc/insn-notes.def
  769443add1b7187045688cd8b1129647  gcc/int-vector-builder.h
! d195ce274224167808b09a54f67439b5  gcc/internal-fn.cc
! 1bbd00353a8c4336aed70e25ab408944  gcc/internal-fn.def
  290489b0e36c5962b1f15bf3135f8eff  gcc/internal-fn.h
  bcb802c64e78f80e8e46c799c7e449ad  gcc/intl.cc
  deb111e00b2b07aa631595045bce5003  gcc/intl.h
  47a65e558aff89879902e88b055c7b12  gcc/ipa-comdats.cc
! 1c543568db2d014ab1eb4a2ea7fc1a5f  gcc/ipa-cp.cc
  b65413c6163d502dbe95a08ac40cb575  gcc/ipa-cp.h
! ce2190c4f151ec8c25f970da83a9a696  gcc/ipa-devirt.cc
  de9f38bd093cebcda124f00fefc75b7c  gcc/ipa-fnsummary.cc
  fef6f27045737cc29ebf2dbbd22dda02  gcc/ipa-fnsummary.h
  a3882f8a9c03be47eb0deee0bd27e04d  gcc/ipa-free-lang-data.cc
--- 6625,6639 ----
  0dc4e5a1c70a5b34153b06594dd3ae85  gcc/insn-addr.h
  eec072fb4c8277a3634cf4cdc0846598  gcc/insn-notes.def
  769443add1b7187045688cd8b1129647  gcc/int-vector-builder.h
! 9a7c11c64bd0c5e2c663b050fa384785  gcc/internal-fn.cc
! 3180756e1144cef471c07afb774b4167  gcc/internal-fn.def
  290489b0e36c5962b1f15bf3135f8eff  gcc/internal-fn.h
  bcb802c64e78f80e8e46c799c7e449ad  gcc/intl.cc
  deb111e00b2b07aa631595045bce5003  gcc/intl.h
  47a65e558aff89879902e88b055c7b12  gcc/ipa-comdats.cc
! ff153aae96a15a002ea2802763b5cbff  gcc/ipa-cp.cc
  b65413c6163d502dbe95a08ac40cb575  gcc/ipa-cp.h
! 3aa7fb336e70a973a21beb86affc713d  gcc/ipa-devirt.cc
  de9f38bd093cebcda124f00fefc75b7c  gcc/ipa-fnsummary.cc
  fef6f27045737cc29ebf2dbbd22dda02  gcc/ipa-fnsummary.h
  a3882f8a9c03be47eb0deee0bd27e04d  gcc/ipa-free-lang-data.cc
*************** a3882f8a9c03be47eb0deee0bd27e04d  gcc/ip
*** 6640,6646 ****
  b2ecb607534e24bdc2bc2e02ba2199ca  gcc/ipa-icf.h
  da5a8b46913e455ff432d2110722af82  gcc/ipa-inline-analysis.cc
  3a7b210d2f26cf868f3eec1036b8a20f  gcc/ipa-inline-transform.cc
! 6d80b6419f5608e8903a0182e250fc89  gcc/ipa-inline.cc
  a8bc23feef2d2f8a3d25702ece427f87  gcc/ipa-inline.h
  19c0cbbd70e071bd63dbb0527d02423e  gcc/ipa-locality-cloning.cc
  e1e331896b86db8a2281657bbb21ac72  gcc/ipa-locality-cloning.h
--- 6643,6649 ----
  b2ecb607534e24bdc2bc2e02ba2199ca  gcc/ipa-icf.h
  da5a8b46913e455ff432d2110722af82  gcc/ipa-inline-analysis.cc
  3a7b210d2f26cf868f3eec1036b8a20f  gcc/ipa-inline-transform.cc
! 5235a078a3c386eed64d02824292cedd  gcc/ipa-inline.cc
  a8bc23feef2d2f8a3d25702ece427f87  gcc/ipa-inline.h
  19c0cbbd70e071bd63dbb0527d02423e  gcc/ipa-locality-cloning.cc
  e1e331896b86db8a2281657bbb21ac72  gcc/ipa-locality-cloning.h
*************** d077e947a9fce9c40d0f0c11d3364802  gcc/ip
*** 6648,6661 ****
  7f6c600cb6695244b71263edd1186df3  gcc/ipa-modref-tree.h
  d4b6029d550d1c8bf41bfb44083a9843  gcc/ipa-modref.cc
  8fe1972490c1cce5a10c7cdcd57b2361  gcc/ipa-modref.h
! 4ef53e0bff9d618eacffb76e9fb73013  gcc/ipa-param-manipulation.cc
  6402305bfd352583fddaf5ceee9f6a46  gcc/ipa-param-manipulation.h
  9c809f4fa05d60a2694cc5b392ba2ce1  gcc/ipa-polymorphic-call.cc
  83c011375208cf1307980bcb1b18b67a  gcc/ipa-predicate.cc
  3290558dca39b32c0ca581e6c3427551  gcc/ipa-predicate.h
! cb4c87b016a31121941a3b4b6060d470  gcc/ipa-profile.cc
! 38a03016010637f74c58b1d0edfb43e4  gcc/ipa-prop.cc
! 00d42ec7c12a0fe53f1cce1d2ac27096  gcc/ipa-prop.h
  1c585ae593227742840d2cccb610d475  gcc/ipa-pure-const.cc
  ce0496bede6d40e2fcfbc8277856fc23  gcc/ipa-ref.cc
  ee6c4ff9a86c5d0a68fa41c8da2b5c6f  gcc/ipa-ref.h
--- 6651,6664 ----
  7f6c600cb6695244b71263edd1186df3  gcc/ipa-modref-tree.h
  d4b6029d550d1c8bf41bfb44083a9843  gcc/ipa-modref.cc
  8fe1972490c1cce5a10c7cdcd57b2361  gcc/ipa-modref.h
! 64c72e78689f3734130a82362219998e  gcc/ipa-param-manipulation.cc
  6402305bfd352583fddaf5ceee9f6a46  gcc/ipa-param-manipulation.h
  9c809f4fa05d60a2694cc5b392ba2ce1  gcc/ipa-polymorphic-call.cc
  83c011375208cf1307980bcb1b18b67a  gcc/ipa-predicate.cc
  3290558dca39b32c0ca581e6c3427551  gcc/ipa-predicate.h
! a0bae69f0e501a74a5f68dec3d240b25  gcc/ipa-profile.cc
! db4df2310c1b12682dd24e1ed16e9cc4  gcc/ipa-prop.cc
! cc522dd6ca6f6df9ec0cc1c9d0e99f7f  gcc/ipa-prop.h
  1c585ae593227742840d2cccb610d475  gcc/ipa-pure-const.cc
  ce0496bede6d40e2fcfbc8277856fc23  gcc/ipa-ref.cc
  ee6c4ff9a86c5d0a68fa41c8da2b5c6f  gcc/ipa-ref.h
*************** d4930f12a999a28238b013539b631f2f  gcc/ip
*** 6666,6674 ****
  1277e7fb1c75f935550a926b823894bf  gcc/ipa-strub.cc
  7441ae66ef417a1eed323b8c98c8e589  gcc/ipa-strub.h
  15fb2e7205c9068dc163478055d814aa  gcc/ipa-utils.cc
! 3123c1da10da09196605cf2b230afdcd  gcc/ipa-utils.h
  ee440e6aefa2af85a2a7e53c77974413  gcc/ipa-visibility.cc
! 32824db5845e283ff117eeb88f4acdf2  gcc/ipa.cc
  c293da53973fb7a7f436f875b73a9753  gcc/ira-build.cc
  beee9dcc951c396654d44195869c5840  gcc/ira-color.cc
  d57cb77872c8989b131d3c2c14a685db  gcc/ira-conflicts.cc
--- 6669,6677 ----
  1277e7fb1c75f935550a926b823894bf  gcc/ipa-strub.cc
  7441ae66ef417a1eed323b8c98c8e589  gcc/ipa-strub.h
  15fb2e7205c9068dc163478055d814aa  gcc/ipa-utils.cc
! fafa5dcba78e81ac88047aa0ef534184  gcc/ipa-utils.h
  ee440e6aefa2af85a2a7e53c77974413  gcc/ipa-visibility.cc
! 19a5ea1e7400577c919f86d61f0f5f72  gcc/ipa.cc
  c293da53973fb7a7f436f875b73a9753  gcc/ira-build.cc
  beee9dcc951c396654d44195869c5840  gcc/ira-color.cc
  d57cb77872c8989b131d3c2c14a685db  gcc/ira-conflicts.cc
*************** c9172b932523f381ffa415f3e81f4517  gcc/li
*** 6799,6805 ****
  7bf480c85a74d6690a5657de1434aef1  gcc/lockfile.cc
  03fdf33413400a8644c324d657debba0  gcc/lockfile.h
  0816d05453d7e9ce04f5d1bd97b7872b  gcc/loop-doloop.cc
! 154eba32ec80f6804e8861149e26652c  gcc/loop-init.cc
  6e39bd9aab94c794b8cc992d0cadd9ae  gcc/loop-invariant.cc
  d09474ac29ae534bc531b2fc2c2bd909  gcc/loop-iv.cc
  f6b72b7aa70bf2902317fd52a231d14e  gcc/loop-unroll.cc
--- 6802,6808 ----
  7bf480c85a74d6690a5657de1434aef1  gcc/lockfile.cc
  03fdf33413400a8644c324d657debba0  gcc/lockfile.h
  0816d05453d7e9ce04f5d1bd97b7872b  gcc/loop-doloop.cc
! 6df265538d73c66790347bc7da05e49b  gcc/loop-init.cc
  6e39bd9aab94c794b8cc992d0cadd9ae  gcc/loop-invariant.cc
  d09474ac29ae534bc531b2fc2c2bd909  gcc/loop-iv.cc
  f6b72b7aa70bf2902317fd52a231d14e  gcc/loop-unroll.cc
*************** b54054c495232a416b1cdea9032d1d9f  gcc/lo
*** 6808,6814 ****
  05bf78e6d3e36587723b1177ffcd9c6e  gcc/lower-subreg.h
  211eca25f95cc4597f926c35778c41ca  gcc/lra-assigns.cc
  0232e051e662ebb7fd2fa507d9c581b8  gcc/lra-coalesce.cc
! 122b4d014199d491a4cf50d3be0ee24a  gcc/lra-constraints.cc
  ebe278d864d3a7e33fbcc46f02926248  gcc/lra-eliminations.cc
  c9f048755e3742fbe86e02e2b4b1eb6d  gcc/lra-int.h
  52ba28cd117bff034bd9a26fe150f692  gcc/lra-lives.cc
--- 6811,6817 ----
  05bf78e6d3e36587723b1177ffcd9c6e  gcc/lower-subreg.h
  211eca25f95cc4597f926c35778c41ca  gcc/lra-assigns.cc
  0232e051e662ebb7fd2fa507d9c581b8  gcc/lra-coalesce.cc
! 48f7f866f92aac8553dee32799da627d  gcc/lra-constraints.cc
  ebe278d864d3a7e33fbcc46f02926248  gcc/lra-eliminations.cc
  c9f048755e3742fbe86e02e2b4b1eb6d  gcc/lra-int.h
  52ba28cd117bff034bd9a26fe150f692  gcc/lra-lives.cc
*************** f98dc87a80f661782eacaf50d123997d  gcc/lr
*** 6816,6822 ****
  7d88a319b2eed09205d9a01cca221eb6  gcc/lra-spills.cc
  e5fef2ffe59f5bb8bf855af92be9ce6a  gcc/lra.cc
  f34f18b0bf45561aad0763e10bc1ecb1  gcc/lra.h
! a184b047851ed058660ead45e7acc3e3  gcc/lto-cgraph.cc
  3c0edd5f81587bb2a1bebb7979c19aa8  gcc/lto-compress.cc
  6081736069853cccad4e30dab7992217  gcc/lto-compress.h
  e30abe8a6f83280333eda23e196378ad  gcc/lto-ltrans-cache.cc
--- 6819,6825 ----
  7d88a319b2eed09205d9a01cca221eb6  gcc/lra-spills.cc
  e5fef2ffe59f5bb8bf855af92be9ce6a  gcc/lra.cc
  f34f18b0bf45561aad0763e10bc1ecb1  gcc/lra.h
! ff2a307951a38c49fda40cdf036b2820  gcc/lto-cgraph.cc
  3c0edd5f81587bb2a1bebb7979c19aa8  gcc/lto-compress.cc
  6081736069853cccad4e30dab7992217  gcc/lto-compress.h
  e30abe8a6f83280333eda23e196378ad  gcc/lto-ltrans-cache.cc
*************** f2a9985147f87fd566d4ae2dd8fceabc  gcc/lt
*** 6830,6836 ****
  8caf9a68892d64dc294b20c27291b749  gcc/lto-streamer.cc
  c1f5544bbcb0c97f44efaa8e7ab62c22  gcc/lto-streamer.h
  83090028348934d032ead727241d7ad7  gcc/lto-wrapper.cc
! 06d80728fd17b6fa0f5c719e892a55cc  gcc/lto/ChangeLog
  3e7816807401da2506930719e6dc8b3d  gcc/lto/Make-lang.in
  705d8eaa74b456d79367c2c42b7a2fef  gcc/lto/common.cc
  3d201b30f0538a8cfddc450739b1c8c5  gcc/lto/common.h
--- 6833,6839 ----
  8caf9a68892d64dc294b20c27291b749  gcc/lto-streamer.cc
  c1f5544bbcb0c97f44efaa8e7ab62c22  gcc/lto-streamer.h
  83090028348934d032ead727241d7ad7  gcc/lto-wrapper.cc
! f79a84ebfb7c8bb731bf4a8203f82046  gcc/lto/ChangeLog
  3e7816807401da2506930719e6dc8b3d  gcc/lto/Make-lang.in
  705d8eaa74b456d79367c2c42b7a2fef  gcc/lto/common.cc
  3d201b30f0538a8cfddc450739b1c8c5  gcc/lto/common.h
*************** c1f5544bbcb0c97f44efaa8e7ab62c22  gcc/lt
*** 6838,6844 ****
  a1977e121a895c3241becf0d3e41bd3a  gcc/lto/lang-specs.h
  d93ec20c141afe4ec8419083e7e5427d  gcc/lto/lang.opt
  e09c982f34fcc53d88fb9b974a77d569  gcc/lto/lang.opt.urls
! 92442a2a292dfcc782c70585852097b7  gcc/lto/lto-common.cc
  1bbd724bce4771513f0a356074d52d51  gcc/lto/lto-common.h
  24353553f316f6efb9d7f42253a3ec7c  gcc/lto/lto-dump.cc
  6f7bac8568b01539cfeadad94e94aa6e  gcc/lto/lto-lang.cc
--- 6841,6847 ----
  a1977e121a895c3241becf0d3e41bd3a  gcc/lto/lang-specs.h
  d93ec20c141afe4ec8419083e7e5427d  gcc/lto/lang.opt
  e09c982f34fcc53d88fb9b974a77d569  gcc/lto/lang.opt.urls
! ede0abd894fc01d0f9cc50e58fb2defd  gcc/lto/lto-common.cc
  1bbd724bce4771513f0a356074d52d51  gcc/lto/lto-common.h
  24353553f316f6efb9d7f42253a3ec7c  gcc/lto/lto-dump.cc
  6f7bac8568b01539cfeadad94e94aa6e  gcc/lto/lto-lang.cc
*************** ff9a9ca6ac5fa2e371f831911c148f9b  gcc/lt
*** 6854,6860 ****
  b417a4bd52371186803e70c49d24764d  gcc/m2/COPYING.RUNTIME
  8f0e2cd40e05189ec81232da84bd6e1a  gcc/m2/COPYING3
  6a6a8e020838b23406c81b19c1d46df6  gcc/m2/COPYING3.LIB
! 6c0f9a32e54236d38df2bb89d0f7686e  gcc/m2/ChangeLog
  1b9fd55a4978f2f62717ca706fc999f4  gcc/m2/Make-lang.in
  e212443a3231afc28440b22d94debe50  gcc/m2/Make-maintainer.in
  6a74129fda00ca52ba9f953538250c45  gcc/m2/NEWS
--- 6857,6863 ----
  b417a4bd52371186803e70c49d24764d  gcc/m2/COPYING.RUNTIME
  8f0e2cd40e05189ec81232da84bd6e1a  gcc/m2/COPYING3
  6a6a8e020838b23406c81b19c1d46df6  gcc/m2/COPYING3.LIB
! 7308013b9b43d9126cd1ec5b33edb1c8  gcc/m2/ChangeLog
  1b9fd55a4978f2f62717ca706fc999f4  gcc/m2/Make-lang.in
  e212443a3231afc28440b22d94debe50  gcc/m2/Make-maintainer.in
  6a74129fda00ca52ba9f953538250c45  gcc/m2/NEWS
*************** a020b7778724f9773472fbcdc64655c8  gcc/m2
*** 6870,6876 ****
  b4e73ff163e583eb283a480fcbc759fc  gcc/m2/gm2-compiler/FifoQueue.def
  0fdde2d8181765119b6dbb6521dc2b06  gcc/m2/gm2-compiler/FifoQueue.mod
  6438215678d8060aadd279593ab68160  gcc/m2/gm2-compiler/FilterError.def
! 4381cca7088506da6f83e4c241e26dd7  gcc/m2/gm2-compiler/FilterError.mod
  64ee122c86e7cb39e1153284889e897f  gcc/m2/gm2-compiler/Lists.def
  b7e8471a0cbebdd6e14d9f090a2f681b  gcc/m2/gm2-compiler/Lists.mod
  01d6bbc3d6e795097ffb673b5fa56f9c  gcc/m2/gm2-compiler/M2ALU.def
--- 6873,6879 ----
  b4e73ff163e583eb283a480fcbc759fc  gcc/m2/gm2-compiler/FifoQueue.def
  0fdde2d8181765119b6dbb6521dc2b06  gcc/m2/gm2-compiler/FifoQueue.mod
  6438215678d8060aadd279593ab68160  gcc/m2/gm2-compiler/FilterError.def
! 80c53eed339acb137a2e640b00bc60f9  gcc/m2/gm2-compiler/FilterError.mod
  64ee122c86e7cb39e1153284889e897f  gcc/m2/gm2-compiler/Lists.def
  b7e8471a0cbebdd6e14d9f090a2f681b  gcc/m2/gm2-compiler/Lists.mod
  01d6bbc3d6e795097ffb673b5fa56f9c  gcc/m2/gm2-compiler/M2ALU.def
*************** b7e8471a0cbebdd6e14d9f090a2f681b  gcc/m2
*** 6882,6888 ****
  9bbe74980b3d3b1426ae58bcef5e737e  gcc/m2/gm2-compiler/M2BasicBlock.def
  17bc7901a3742e1d4b5106653c300103  gcc/m2/gm2-compiler/M2BasicBlock.mod
  39400c03b888a32af5ecb92265fbd08c  gcc/m2/gm2-compiler/M2Batch.def
! 7d7e7eb2fca83fae1a54d54a0f5795aa  gcc/m2/gm2-compiler/M2Batch.mod
  dec6f2aff29cb5fe1427242c7c5e9bd7  gcc/m2/gm2-compiler/M2Bitset.def
  4fd8de25a94ebe3d7dc535d77d35bcf1  gcc/m2/gm2-compiler/M2Bitset.mod
  d4b939b5e1e8ebd5bbfd57a171da0768  gcc/m2/gm2-compiler/M2CaseList.def
--- 6885,6891 ----
  9bbe74980b3d3b1426ae58bcef5e737e  gcc/m2/gm2-compiler/M2BasicBlock.def
  17bc7901a3742e1d4b5106653c300103  gcc/m2/gm2-compiler/M2BasicBlock.mod
  39400c03b888a32af5ecb92265fbd08c  gcc/m2/gm2-compiler/M2Batch.def
! 11667e0c55689a5f21c02b4d5cd975e6  gcc/m2/gm2-compiler/M2Batch.mod
  dec6f2aff29cb5fe1427242c7c5e9bd7  gcc/m2/gm2-compiler/M2Bitset.def
  4fd8de25a94ebe3d7dc535d77d35bcf1  gcc/m2/gm2-compiler/M2Bitset.mod
  d4b939b5e1e8ebd5bbfd57a171da0768  gcc/m2/gm2-compiler/M2CaseList.def
*************** f64ab23b49282386ad67b3551c995c79  gcc/m2
*** 6992,6998 ****
  bacc5489cee9efd5ca0c430d44edaac0  gcc/m2/gm2-compiler/P3Build.bnf
  41f585d1e8e6fd1786dd36cb69cf3e82  gcc/m2/gm2-compiler/P3Build.def
  97492b4aea16b395bb56343086810be4  gcc/m2/gm2-compiler/P3SymBuild.def
! 3820bdfcda75541819ccbc3ed3bb28d9  gcc/m2/gm2-compiler/P3SymBuild.mod
  f40ce8692c5a5a9de8e072619d14e82a  gcc/m2/gm2-compiler/PCBuild.bnf
  428e2092f5708fd9cf986ae14771fff1  gcc/m2/gm2-compiler/PCBuild.def
  17848423d631516c5135c755b6531842  gcc/m2/gm2-compiler/PCSymBuild.def
--- 6995,7001 ----
  bacc5489cee9efd5ca0c430d44edaac0  gcc/m2/gm2-compiler/P3Build.bnf
  41f585d1e8e6fd1786dd36cb69cf3e82  gcc/m2/gm2-compiler/P3Build.def
  97492b4aea16b395bb56343086810be4  gcc/m2/gm2-compiler/P3SymBuild.def
! f94e36286741636490173ee99eb90e32  gcc/m2/gm2-compiler/P3SymBuild.mod
  f40ce8692c5a5a9de8e072619d14e82a  gcc/m2/gm2-compiler/PCBuild.bnf
  428e2092f5708fd9cf986ae14771fff1  gcc/m2/gm2-compiler/PCBuild.def
  17848423d631516c5135c755b6531842  gcc/m2/gm2-compiler/PCSymBuild.def
*************** d175b1db289f761bef82985010501b08  gcc/m2
*** 7364,7371 ****
  be1fdd1dea1af314b32e95e9fb1e613f  gcc/m2/gm2-libs/DynamicStrings.mod
  336f00218f5e3fff779dccd2a615fa63  gcc/m2/gm2-libs/Environment.def
  0dde314513020c8101bae6227dc7d4d4  gcc/m2/gm2-libs/Environment.mod
! 34fadb2b6843988e6914d1436e56f4fc  gcc/m2/gm2-libs/FIO.def
! 861b03d675f63653f159204dafbc300f  gcc/m2/gm2-libs/FIO.mod
  778d1ff012b61101cb234ca5b9ef9146  gcc/m2/gm2-libs/FileSysOp.def
  3a3c2b8ed0b5f9b1297332990036351a  gcc/m2/gm2-libs/FileSysOp.mod
  972105c4bd1196ec3fe7f29c84965fb1  gcc/m2/gm2-libs/FormatStrings.def
--- 7367,7374 ----
  be1fdd1dea1af314b32e95e9fb1e613f  gcc/m2/gm2-libs/DynamicStrings.mod
  336f00218f5e3fff779dccd2a615fa63  gcc/m2/gm2-libs/Environment.def
  0dde314513020c8101bae6227dc7d4d4  gcc/m2/gm2-libs/Environment.mod
! 5c48ecf7bd565c38e6d220f60de07198  gcc/m2/gm2-libs/FIO.def
! e6be75d76d0d4da5c5d556f42c3a0561  gcc/m2/gm2-libs/FIO.mod
  778d1ff012b61101cb234ca5b9ef9146  gcc/m2/gm2-libs/FileSysOp.def
  3a3c2b8ed0b5f9b1297332990036351a  gcc/m2/gm2-libs/FileSysOp.mod
  972105c4bd1196ec3fe7f29c84965fb1  gcc/m2/gm2-libs/FormatStrings.def
*************** f9608e9005487c369e6c38949ab36fa1  gcc/m2
*** 7829,7835 ****
  9c73ce7b15dda9ddf7130eb220aee884  gcc/machmode.def
  550bdb35d0e034ca0050c574ba896d61  gcc/machmode.h
  486412acbbb6de10b080e31410a14f33  gcc/main.cc
! 98563a786ae65828f21df32c7d5e63b2  gcc/match.pd
  63bf182c7c3a100e101b2129976be89b  gcc/mcf.cc
  795fbbc034a60f5af7e79dbe3bac65a0  gcc/mem-stats-traits.h
  295dcd7618653c13dcf063266752d06f  gcc/mem-stats.h
--- 7832,7838 ----
  9c73ce7b15dda9ddf7130eb220aee884  gcc/machmode.def
  550bdb35d0e034ca0050c574ba896d61  gcc/machmode.h
  486412acbbb6de10b080e31410a14f33  gcc/main.cc
! f6c44199beedde36ae3e2422ddaa0c33  gcc/match.pd
  63bf182c7c3a100e101b2129976be89b  gcc/mcf.cc
  795fbbc034a60f5af7e79dbe3bac65a0  gcc/mem-stats-traits.h
  295dcd7618653c13dcf063266752d06f  gcc/mem-stats.h
*************** db351af3c135e85d5daecadfdff02e4a  gcc/om
*** 7875,7881 ****
  286190bcce78c62804516df6cd0d1684  gcc/omp-expand.h
  9c0c5720928afb3e264aa62d4e9b9cb3  gcc/omp-general.cc
  9ba5023e72c73609347d8584119f8372  gcc/omp-general.h
! bc799bc6ae7feb93c4eb28fcb6a3c272  gcc/omp-low.cc
  73fb62acbdd74e28aff8cc147ee7fa11  gcc/omp-low.h
  bf774332919d8fc6ad76372ccefd0aa2  gcc/omp-oacc-kernels-decompose.cc
  51e7c46004876244d3f23ab786112c1a  gcc/omp-oacc-neuter-broadcast.cc
--- 7878,7884 ----
  286190bcce78c62804516df6cd0d1684  gcc/omp-expand.h
  9c0c5720928afb3e264aa62d4e9b9cb3  gcc/omp-general.cc
  9ba5023e72c73609347d8584119f8372  gcc/omp-general.h
! 9c8fb495c2b27b759fd332a4dd788e89  gcc/omp-low.cc
  73fb62acbdd74e28aff8cc147ee7fa11  gcc/omp-low.h
  bf774332919d8fc6ad76372ccefd0aa2  gcc/omp-oacc-kernels-decompose.cc
  51e7c46004876244d3f23ab786112c1a  gcc/omp-oacc-neuter-broadcast.cc
*************** e3dcab493cb237abbc70ee839e1fc3c0  gcc/op
*** 7898,7904 ****
  28bb97827aab6913c7fa55727bd8cea0  gcc/optabs-query.h
  956c25750704a6c5f42092d7400badf3  gcc/optabs-tree.cc
  295bbec8fcdeeac30d6f914e52d4adc4  gcc/optabs-tree.h
! 79fd5b7dc301451eb44cafc5af373938  gcc/optabs.cc
  503193d9bcdf4017d90d212acc0a34f7  gcc/optabs.def
  fe27687b66727b0800e152caad7a6829  gcc/optabs.h
  4b8341a8e70bcb44afdbe2e4be1dcc46  gcc/optc-gen.awk
--- 7901,7907 ----
  28bb97827aab6913c7fa55727bd8cea0  gcc/optabs-query.h
  956c25750704a6c5f42092d7400badf3  gcc/optabs-tree.cc
  295bbec8fcdeeac30d6f914e52d4adc4  gcc/optabs-tree.h
! ab77c1b9be8e82dd107a0c6ea7ea7b17  gcc/optabs.cc
  503193d9bcdf4017d90d212acc0a34f7  gcc/optabs.def
  fe27687b66727b0800e152caad7a6829  gcc/optabs.h
  4b8341a8e70bcb44afdbe2e4be1dcc46  gcc/optc-gen.awk
*************** fcb5b7227342c442bcddbcc06eaddcdc  gcc/op
*** 7909,7927 ****
  79cdb91fae5008327a4a19e7f49fb42e  gcc/optinfo.cc
  bdacbcb932eb0c2db8707e3727f574dd  gcc/optinfo.h
  1c30e8950551cbe97bda991d288b7bb7  gcc/options-urls-cc-gen.awk
! 09395c50b5992609f34cd388cc3257c0  gcc/opts-common.cc
  b4c35ee2dcd91ade3c9baf0bb43c18ca  gcc/opts-diagnostic.cc
  6d624f6fea144bbb8e71378935b84abd  gcc/opts-diagnostic.h
  dd6379e65503d93b6eb08844e8bf2d09  gcc/opts-global.cc
  079a115ae417106f3e7f42b0272b866d  gcc/opts-jobserver.h
! 5f6f1ceba66df56398e1ea64bd3f24c7  gcc/opts.cc
  7297ae8caf0c34afb0609151e7e3f987  gcc/opts.h
  b7a4b3edfca283f972cdeb23102a28a4  gcc/ordered-hash-map-tests.cc
  fccd951e3de91d49d3824e482c12e070  gcc/ordered-hash-map.h
  673ce61076fa80e959fe72ae50291616  gcc/output.h
  c9e6163e1eaa8f82c57f03f76e86da75  gcc/pair-fusion.cc
  b2f692287d25760afcef126c010f7078  gcc/pair-fusion.h
! bb4d30d4d84d592dc0f626301158e034  gcc/params.opt
  2cc794e23d80a8c9f057a7e402c65fb8  gcc/params.opt.urls
  818628b1b793b8f87f62d0c18fd1219a  gcc/pass_manager.h
  38b9f60b5fd192ab2d5c201b4aff3f29  gcc/passes.cc
--- 7912,7930 ----
  79cdb91fae5008327a4a19e7f49fb42e  gcc/optinfo.cc
  bdacbcb932eb0c2db8707e3727f574dd  gcc/optinfo.h
  1c30e8950551cbe97bda991d288b7bb7  gcc/options-urls-cc-gen.awk
! 8095ceff59a2dd0746ae60ef958ebf76  gcc/opts-common.cc
  b4c35ee2dcd91ade3c9baf0bb43c18ca  gcc/opts-diagnostic.cc
  6d624f6fea144bbb8e71378935b84abd  gcc/opts-diagnostic.h
  dd6379e65503d93b6eb08844e8bf2d09  gcc/opts-global.cc
  079a115ae417106f3e7f42b0272b866d  gcc/opts-jobserver.h
! 9dbe8352407c0b860d0dd74fc8ab3da1  gcc/opts.cc
  7297ae8caf0c34afb0609151e7e3f987  gcc/opts.h
  b7a4b3edfca283f972cdeb23102a28a4  gcc/ordered-hash-map-tests.cc
  fccd951e3de91d49d3824e482c12e070  gcc/ordered-hash-map.h
  673ce61076fa80e959fe72ae50291616  gcc/output.h
  c9e6163e1eaa8f82c57f03f76e86da75  gcc/pair-fusion.cc
  b2f692287d25760afcef126c010f7078  gcc/pair-fusion.h
! c08d70951f9fdf4f57eea68c2c8b46f4  gcc/params.opt
  2cc794e23d80a8c9f057a7e402c65fb8  gcc/params.opt.urls
  818628b1b793b8f87f62d0c18fd1219a  gcc/pass_manager.h
  38b9f60b5fd192ab2d5c201b4aff3f29  gcc/passes.cc
*************** d869add118f3b4328fb1691092405516  gcc/po
*** 7962,7968 ****
  e4cbc3dec8ff394525eecb5ab8dda3e0  gcc/poly-int.h
  475f722ae164d853cf948309392e72fa  gcc/postreload-gcse.cc
  1696ccf7c912de56dfdeaaa05e52380e  gcc/postreload.cc
! 844b3e8351cc891efc3de2ba8b6dc7f2  gcc/predict.cc
  a4c4b609df2262702bd9691ce3ef1b39  gcc/predict.def
  5494603f698198c1a7d327aa6bbdb09a  gcc/predict.h
  00fb3c12fcc945bd00d0da1986741e41  gcc/prefix.cc
--- 7965,7971 ----
  e4cbc3dec8ff394525eecb5ab8dda3e0  gcc/poly-int.h
  475f722ae164d853cf948309392e72fa  gcc/postreload-gcse.cc
  1696ccf7c912de56dfdeaaa05e52380e  gcc/postreload.cc
! 6fc7b8def2131e36fee12e086508b88f  gcc/predict.cc
  a4c4b609df2262702bd9691ce3ef1b39  gcc/predict.def
  5494603f698198c1a7d327aa6bbdb09a  gcc/predict.h
  00fb3c12fcc945bd00d0da1986741e41  gcc/prefix.cc
*************** c08edc659010d9072c249418c1be7fe6  gcc/rt
*** 8060,8074 ****
  ecb31a48caf7998f695601ec7350bdc0  gcc/run-rtl-passes.cc
  c4bc204b62fdb61848c09abf05a60a9d  gcc/run-rtl-passes.h
  add9bd82fcec23469a4d0f7df03d9589  gcc/rust/CONTRIBUTING.md
! 4a937995549253194fb99b79e37a81a7  gcc/rust/ChangeLog
  71972a823341f4ee0b2af7347ef7a633  gcc/rust/Make-lang.in
  f3527e161e6e2827d299c1a928ebe1c6  gcc/rust/README.md
  27f492ab17f50d840e1e0fd32a89c84a  gcc/rust/ast/rust-ast-builder.cc
  3714514495ced2204392eef66c900c13  gcc/rust/ast/rust-ast-builder.h
! 21d814f35d0144aa47c15e8301b13890  gcc/rust/ast/rust-ast-collector.cc
! 2218748445677411bd6873a3c03ccd5d  gcc/rust/ast/rust-ast-collector.h
! 494672e10e3cd2a3c29f72147b6e42e8  gcc/rust/ast/rust-ast-dump.cc
! e21cd4002e965dd8e32f6afb373d6ead  gcc/rust/ast/rust-ast-dump.h
  4b956fa2250010f85282d2ea3339d66f  gcc/rust/ast/rust-ast-formatting.cc
  fa22a966da9420728a72f8164b29aeef  gcc/rust/ast/rust-ast-formatting.h
  9a53c932a6dd665e6f534655a2c1096c  gcc/rust/ast/rust-ast-fragment.cc
--- 8063,8077 ----
  ecb31a48caf7998f695601ec7350bdc0  gcc/run-rtl-passes.cc
  c4bc204b62fdb61848c09abf05a60a9d  gcc/run-rtl-passes.h
  add9bd82fcec23469a4d0f7df03d9589  gcc/rust/CONTRIBUTING.md
! 60660701dabaa0ce9a5c96b4560493e1  gcc/rust/ChangeLog
  71972a823341f4ee0b2af7347ef7a633  gcc/rust/Make-lang.in
  f3527e161e6e2827d299c1a928ebe1c6  gcc/rust/README.md
  27f492ab17f50d840e1e0fd32a89c84a  gcc/rust/ast/rust-ast-builder.cc
  3714514495ced2204392eef66c900c13  gcc/rust/ast/rust-ast-builder.h
! e227fd53f48390bd8eceeac8abd876fe  gcc/rust/ast/rust-ast-collector.cc
! 33b8ac2740e83341948b8947bcb411a0  gcc/rust/ast/rust-ast-collector.h
! cc234f8fcb2d047bbf2765a60cbe179c  gcc/rust/ast/rust-ast-dump.cc
! d6961e8394ecb5a2720caea10c0a0521  gcc/rust/ast/rust-ast-dump.h
  4b956fa2250010f85282d2ea3339d66f  gcc/rust/ast/rust-ast-formatting.cc
  fa22a966da9420728a72f8164b29aeef  gcc/rust/ast/rust-ast-formatting.h
  9a53c932a6dd665e6f534655a2c1096c  gcc/rust/ast/rust-ast-fragment.cc
*************** fa22a966da9420728a72f8164b29aeef  gcc/ru
*** 8079,8086 ****
  ab4843ea68c29da6b2a1c9981b059e06  gcc/rust/ast/rust-ast-pointer-visitor.h
  9ab1d23308048adc03212cb5ea086d07  gcc/rust/ast/rust-ast-visitor.cc
  0adfcf6a63038808c3009e74ef1c6a39  gcc/rust/ast/rust-ast-visitor.h
! 632a6fc7172714b617f69b29bc441746  gcc/rust/ast/rust-ast.cc
! 4a1b73a90a3a390cceeda49d80d98b6c  gcc/rust/ast/rust-ast.h
  47cbbb053e5e83cfcb63e85fe1777921  gcc/rust/ast/rust-builtin-ast-nodes.h
  6c128fd9e73db1e26ff7ddbc86f69722  gcc/rust/ast/rust-collect-lang-items.cc
  d526cc472464ac531167ac67e9139d7e  gcc/rust/ast/rust-collect-lang-items.h
--- 8082,8089 ----
  ab4843ea68c29da6b2a1c9981b059e06  gcc/rust/ast/rust-ast-pointer-visitor.h
  9ab1d23308048adc03212cb5ea086d07  gcc/rust/ast/rust-ast-visitor.cc
  0adfcf6a63038808c3009e74ef1c6a39  gcc/rust/ast/rust-ast-visitor.h
! e3034f54429d242a5f958bb08b827597  gcc/rust/ast/rust-ast.cc
! e13ded45e7ffbeae91c700ffc79a4d6f  gcc/rust/ast/rust-ast.h
  47cbbb053e5e83cfcb63e85fe1777921  gcc/rust/ast/rust-builtin-ast-nodes.h
  6c128fd9e73db1e26ff7ddbc86f69722  gcc/rust/ast/rust-collect-lang-items.cc
  d526cc472464ac531167ac67e9139d7e  gcc/rust/ast/rust-collect-lang-items.h
*************** ce782a41f25cb7bab408fb56d3691217  gcc/ru
*** 8095,8107 ****
  7f083f8b90958b45346c1ede8236b34b  gcc/rust/ast/rust-desugar-try-block.h
  e6d36246282c627ce4935b5006882cde  gcc/rust/ast/rust-desugar-while-let.cc
  8962928afafa7cdb402e49863510fee6  gcc/rust/ast/rust-desugar-while-let.h
! 3403f6d26cdb07e406b3a7231b5ae964  gcc/rust/ast/rust-expr.h
  56b2d9b9ff0f8e730b276195a3614e07  gcc/rust/ast/rust-expression-yeast.cc
  5738296d90ef786d16f052f0c0ed613f  gcc/rust/ast/rust-expression-yeast.h
  b0a8d5728f73b0493b0b4aae04568187  gcc/rust/ast/rust-fmt.cc
  47fa77e4a5e65d5dde6e13fb22489869  gcc/rust/ast/rust-fmt.h
! 849c4f62857b225f5709be85f3992b50  gcc/rust/ast/rust-item.h
! 443acf32f91c4929d384f42d0360e19f  gcc/rust/ast/rust-macro.h
  277825a1ab6df255dbe079bb8560e311  gcc/rust/ast/rust-path.cc
  1a331eb0cd7eedec74fbb2ce3677449b  gcc/rust/ast/rust-path.h
  aa85db7e311dbe19dc2be9abadd44aef  gcc/rust/ast/rust-pattern.cc
--- 8098,8110 ----
  7f083f8b90958b45346c1ede8236b34b  gcc/rust/ast/rust-desugar-try-block.h
  e6d36246282c627ce4935b5006882cde  gcc/rust/ast/rust-desugar-while-let.cc
  8962928afafa7cdb402e49863510fee6  gcc/rust/ast/rust-desugar-while-let.h
! 7f6eff12162e1cc482a362739c4c6199  gcc/rust/ast/rust-expr.h
  56b2d9b9ff0f8e730b276195a3614e07  gcc/rust/ast/rust-expression-yeast.cc
  5738296d90ef786d16f052f0c0ed613f  gcc/rust/ast/rust-expression-yeast.h
  b0a8d5728f73b0493b0b4aae04568187  gcc/rust/ast/rust-fmt.cc
  47fa77e4a5e65d5dde6e13fb22489869  gcc/rust/ast/rust-fmt.h
! bc42fe789e0852a0218a7921a004a4fa  gcc/rust/ast/rust-item.h
! ae461cb141678a5ac2400974deba2aa5  gcc/rust/ast/rust-macro.h
  277825a1ab6df255dbe079bb8560e311  gcc/rust/ast/rust-path.cc
  1a331eb0cd7eedec74fbb2ce3677449b  gcc/rust/ast/rust-path.h
  aa85db7e311dbe19dc2be9abadd44aef  gcc/rust/ast/rust-pattern.cc
*************** a24c9465702c5bb64a467cc4f251ec38  gcc/ru
*** 8304,8319 ****
  b09e41a88ef4016a6294d77183668bf7  gcc/rust/expand/rust-macro-builtins-format-args.cc
  470ca31c9edf1792290a63da0ae3bdd7  gcc/rust/expand/rust-macro-builtins-helpers.cc
  dff0ef1b84e3096bd94fe2815b90981d  gcc/rust/expand/rust-macro-builtins-helpers.h
! f813ef580dce9d9b6c9a75e9577bdbe0  gcc/rust/expand/rust-macro-builtins-include.cc
  cfe6beb6d729f4b555ffc6493de34a20  gcc/rust/expand/rust-macro-builtins-location.cc
  7d4293c5bb91064c3bb11e2ec9bd1893  gcc/rust/expand/rust-macro-builtins-log-debug.cc
! 7a98e5195382adae583a972114402078  gcc/rust/expand/rust-macro-builtins-offset-of.cc
  277542c684eada894583030cf02b7424  gcc/rust/expand/rust-macro-builtins-test-bench.cc
  277542c684eada894583030cf02b7424  gcc/rust/expand/rust-macro-builtins-trait.cc
  e253e39de6ea2a67018f97fc8e838ef5  gcc/rust/expand/rust-macro-builtins-utility.cc
  26a6c99fd51145137f378321795b869d  gcc/rust/expand/rust-macro-builtins.cc
  b0344bc54018de3abfa44322f6262176  gcc/rust/expand/rust-macro-builtins.h
! 4fa665fac04b4ae19d1c2dabf6ca0821  gcc/rust/expand/rust-macro-expand.cc
  a015fbe3c7e78312ee1a662ac22b8025  gcc/rust/expand/rust-macro-expand.h
  b4b31e238293e868394fdf9247353b30  gcc/rust/expand/rust-macro-invoc-lexer.cc
  df22bd0c18e9d6037a1dbfbd733f009a  gcc/rust/expand/rust-macro-invoc-lexer.h
--- 8307,8322 ----
  b09e41a88ef4016a6294d77183668bf7  gcc/rust/expand/rust-macro-builtins-format-args.cc
  470ca31c9edf1792290a63da0ae3bdd7  gcc/rust/expand/rust-macro-builtins-helpers.cc
  dff0ef1b84e3096bd94fe2815b90981d  gcc/rust/expand/rust-macro-builtins-helpers.h
! bc72f6859ad441577d17331c45f8843a  gcc/rust/expand/rust-macro-builtins-include.cc
  cfe6beb6d729f4b555ffc6493de34a20  gcc/rust/expand/rust-macro-builtins-location.cc
  7d4293c5bb91064c3bb11e2ec9bd1893  gcc/rust/expand/rust-macro-builtins-log-debug.cc
! f9b5208fa1db6ac9cf3db449c2025bad  gcc/rust/expand/rust-macro-builtins-offset-of.cc
  277542c684eada894583030cf02b7424  gcc/rust/expand/rust-macro-builtins-test-bench.cc
  277542c684eada894583030cf02b7424  gcc/rust/expand/rust-macro-builtins-trait.cc
  e253e39de6ea2a67018f97fc8e838ef5  gcc/rust/expand/rust-macro-builtins-utility.cc
  26a6c99fd51145137f378321795b869d  gcc/rust/expand/rust-macro-builtins.cc
  b0344bc54018de3abfa44322f6262176  gcc/rust/expand/rust-macro-builtins.h
! 0aa1447f0354158bc18157d2402c31ea  gcc/rust/expand/rust-macro-expand.cc
  a015fbe3c7e78312ee1a662ac22b8025  gcc/rust/expand/rust-macro-expand.h
  b4b31e238293e868394fdf9247353b30  gcc/rust/expand/rust-macro-invoc-lexer.cc
  df22bd0c18e9d6037a1dbfbd733f009a  gcc/rust/expand/rust-macro-invoc-lexer.h
*************** af09b97c0baeff87520d8face05b8f05  gcc/ru
*** 8345,8351 ****
  b86ab6b1f3ddb71091146e2d7265bd7f  gcc/rust/hir/rust-ast-lower-struct-field-expr.h
  a3f9b9d71a7b0a056ea2218035dd8dad  gcc/rust/hir/rust-ast-lower-type.cc
  2144c5ed50fecb7465bad4f0676110be  gcc/rust/hir/rust-ast-lower-type.h
! f804813c101f8b007f8025dcd50455ba  gcc/rust/hir/rust-ast-lower.cc
  dfd71f28a4e33f88e4f9f845a85eff57  gcc/rust/hir/rust-ast-lower.h
  f38e6ed9d1426eaac2c1bed8f56a0bd0  gcc/rust/hir/rust-hir-dump.cc
  9f61ffcd5016bb874c6a0829e3feb9ae  gcc/rust/hir/rust-hir-dump.h
--- 8348,8354 ----
  b86ab6b1f3ddb71091146e2d7265bd7f  gcc/rust/hir/rust-ast-lower-struct-field-expr.h
  a3f9b9d71a7b0a056ea2218035dd8dad  gcc/rust/hir/rust-ast-lower-type.cc
  2144c5ed50fecb7465bad4f0676110be  gcc/rust/hir/rust-ast-lower-type.h
! 24cb5c06629dd6c9f1572b26bc5dc2b9  gcc/rust/hir/rust-ast-lower.cc
  dfd71f28a4e33f88e4f9f845a85eff57  gcc/rust/hir/rust-ast-lower.h
  f38e6ed9d1426eaac2c1bed8f56a0bd0  gcc/rust/hir/rust-hir-dump.cc
  9f61ffcd5016bb874c6a0829e3feb9ae  gcc/rust/hir/rust-hir-dump.h
*************** fe40f8618a9f5a5f007bc1a81fe45d3a  gcc/ru
*** 8400,8411 ****
  659356fda258855d3d26c1eff1e24215  gcc/rust/metadata/rust-imports.h
  6157b499aceab0b9b632eea936bc0f0d  gcc/rust/parse/rust-cfg-parser.cc
  dcbc600defe89f418c72fb56de980c97  gcc/rust/parse/rust-cfg-parser.h
! d32fa6f6e6b4f85681679a48b9143b49  gcc/rust/parse/rust-parse-impl-lexer.cc
! 512507c7858c53e9bcb25b431891ced3  gcc/rust/parse/rust-parse-impl-macro.cc
! eadcb6e38b643a9b344ba845b7eaa4b0  gcc/rust/parse/rust-parse-impl-proc-macro.cc
! ddf1dd50e1e8a44073768831518757a0  gcc/rust/parse/rust-parse-impl.h
  d60ac257492f0b2d13c8c305707dd04a  gcc/rust/parse/rust-parse.cc
! efd8c95f4749b7137731fe544b287e0f  gcc/rust/parse/rust-parse.h
  d5113906116ffd33fb4c45243a97fb67  gcc/rust/resolve/rust-ast-resolve.h
  b6b01419e9dcc7774b5791b9a708466a  gcc/rust/resolve/rust-default-resolver.cc
  4320f2346a3c6f9c6e6bdec7e1901019  gcc/rust/resolve/rust-default-resolver.h
--- 8403,8423 ----
  659356fda258855d3d26c1eff1e24215  gcc/rust/metadata/rust-imports.h
  6157b499aceab0b9b632eea936bc0f0d  gcc/rust/parse/rust-cfg-parser.cc
  dcbc600defe89f418c72fb56de980c97  gcc/rust/parse/rust-cfg-parser.h
! 07d2d37e63ca53a20b688c313702c5f9  gcc/rust/parse/rust-parse-error.h
! 13a7f16ae49c6456ae7694bdd5d0e724  gcc/rust/parse/rust-parse-impl-attribute.hxx
! 2efffbe190bd7c28465925224b5f9aba  gcc/rust/parse/rust-parse-impl-expr.hxx
! a36a94b115280a61b1354f1725ea76cd  gcc/rust/parse/rust-parse-impl-lexer.cc
! da3ae35ba2d8682a2d7cb75bedb3b58a  gcc/rust/parse/rust-parse-impl-macro.cc
! 9fa18b4651a448f510fd0115e76d2429  gcc/rust/parse/rust-parse-impl-macro.hxx
! 5d50787b9860f8daa524b322dfc2007c  gcc/rust/parse/rust-parse-impl-path.hxx
! b110f1b0070568fe5b84619bcf9c9d89  gcc/rust/parse/rust-parse-impl-pattern.hxx
! b1ff3c1e7c6c141048d92ffc148856dd  gcc/rust/parse/rust-parse-impl-proc-macro.cc
! 1d5f77b64c20c8cab13f1cb1466ac4fc  gcc/rust/parse/rust-parse-impl-ttree.hxx
! a3d4471aa17be4199bb98e7a4a7974c6  gcc/rust/parse/rust-parse-impl-utils.hxx
! 7fab0fcdaf81dd46c012ce59767f1d14  gcc/rust/parse/rust-parse-impl.hxx
! ddf19fac2d6da02026f6c8e5fed70358  gcc/rust/parse/rust-parse-utils.h
  d60ac257492f0b2d13c8c305707dd04a  gcc/rust/parse/rust-parse.cc
! 47d6f72222477ca5e39c824ea88e1dc1  gcc/rust/parse/rust-parse.h
  d5113906116ffd33fb4c45243a97fb67  gcc/rust/resolve/rust-ast-resolve.h
  b6b01419e9dcc7774b5791b9a708466a  gcc/rust/resolve/rust-default-resolver.cc
  4320f2346a3c6f9c6e6bdec7e1901019  gcc/rust/resolve/rust-default-resolver.h
*************** a591947189b9249649cd9d0d05bb6f3b  gcc/ru
*** 8445,8452 ****
  44c864a134b8524b6fd7e36dc13b1d12  gcc/rust/rust-location.h
  b45417b3f3262f4edcbe101bd348c5a0  gcc/rust/rust-object-export.cc
  c4892cc98a9ac5c00fb35b20592c0a82  gcc/rust/rust-object-export.h
! 22898d619df452bc13d3e295bdc23c70  gcc/rust/rust-session-manager.cc
! 036d9a7a214c0a73976981f212ca0866  gcc/rust/rust-session-manager.h
  567d0d8fd5f4f8ae4496a4212922201d  gcc/rust/rust-system.h
  ac420eeb07d0fa93baebb7cfaafe3a69  gcc/rust/rust-target-def.h
  079faeff0bcbd134ce19509fd4a7c49c  gcc/rust/rust-target.def
--- 8457,8464 ----
  44c864a134b8524b6fd7e36dc13b1d12  gcc/rust/rust-location.h
  b45417b3f3262f4edcbe101bd348c5a0  gcc/rust/rust-object-export.cc
  c4892cc98a9ac5c00fb35b20592c0a82  gcc/rust/rust-object-export.h
! 8dc7cbfce0b4ec16004dae4c55ff16d6  gcc/rust/rust-session-manager.cc
! 7c733b02bd9c62e92a8826079672021a  gcc/rust/rust-session-manager.h
  567d0d8fd5f4f8ae4496a4212922201d  gcc/rust/rust-system.h
  ac420eeb07d0fa93baebb7cfaafe3a69  gcc/rust/rust-target-def.h
  079faeff0bcbd134ce19509fd4a7c49c  gcc/rust/rust-target.def
*************** b4f0c77852dde185d8745c16c0f82ac0  gcc/ru
*** 8555,8561 ****
  8d112f972dcbf2531c2a2b6c24bc14f6  gcc/rust/util/rust-unwrap-segment.h
  1157834f858df87f4cff12c780fe7030  gcc/sancov.cc
  f47b1babbf39168c2829bbc0997f6b9b  gcc/sanitizer.def
! 1c4a31054492029cadf12999aee53d81  gcc/sanopt.cc
  78d2106a665ed01c45dd890d56e34254  gcc/sarif-replay.cc
  a92419791c8e8d842c6ef029d4537463  gcc/sarif-spec-urls.def
  31050442ff986af301d1822bb48a2dc0  gcc/sbitmap.cc
--- 8567,8573 ----
  8d112f972dcbf2531c2a2b6c24bc14f6  gcc/rust/util/rust-unwrap-segment.h
  1157834f858df87f4cff12c780fe7030  gcc/sancov.cc
  f47b1babbf39168c2829bbc0997f6b9b  gcc/sanitizer.def
! d8fce70fef154f25279a11aa5cb0a60c  gcc/sanopt.cc
  78d2106a665ed01c45dd890d56e34254  gcc/sarif-replay.cc
  a92419791c8e8d842c6ef029d4537463  gcc/sarif-spec-urls.def
  31050442ff986af301d1822bb48a2dc0  gcc/sbitmap.cc
*************** b3a965e425e6cf7888319667faf58da9  gcc/sy
*** 8635,8647 ****
  7e57ef65e3a1144e28765b6e8d7f6cff  gcc/target-globals.cc
  32c99c974fd34089d47160168688da1d  gcc/target-globals.h
  84051f22ca8c9ee213931106395ac151  gcc/target-hooks-macros.h
! 354306a484432bca2f94887455f25599  gcc/target-insns.def
! 76894c1776b009491353fcca183f34cf  gcc/target.def
  5e326cfe9b9871c8077b30f9a44e6663  gcc/target.h
  b3ba747676feafec77aa6befa2dec6f0  gcc/targhooks.cc
  94a98d77cef80b0f949fc6d206067e2e  gcc/targhooks.h
  f39fcaa8197187283ccfed40107b426d  gcc/testsuite/.gitattributes
! ae0a9c8f11f6efe1568cf469eb1d3b17  gcc/testsuite/ChangeLog
  47e8e29b649ead73b8a1e4797da470ed  gcc/testsuite/ChangeLog-1993-2007
  35198a9e4fd31b935de8789faabf3351  gcc/testsuite/ChangeLog-2008
  0f19934540750356d1b91595cebfd9a8  gcc/testsuite/ChangeLog-2009
--- 8647,8659 ----
  7e57ef65e3a1144e28765b6e8d7f6cff  gcc/target-globals.cc
  32c99c974fd34089d47160168688da1d  gcc/target-globals.h
  84051f22ca8c9ee213931106395ac151  gcc/target-hooks-macros.h
! d6258f1a0aa10c5dda51e11da016a5f0  gcc/target-insns.def
! 183fed1f00e58b5de00b6040888fb83e  gcc/target.def
  5e326cfe9b9871c8077b30f9a44e6663  gcc/target.h
  b3ba747676feafec77aa6befa2dec6f0  gcc/targhooks.cc
  94a98d77cef80b0f949fc6d206067e2e  gcc/targhooks.h
  f39fcaa8197187283ccfed40107b426d  gcc/testsuite/.gitattributes
! cee4c20f737b36b7071f67c9ae8b44c6  gcc/testsuite/ChangeLog
  47e8e29b649ead73b8a1e4797da470ed  gcc/testsuite/ChangeLog-1993-2007
  35198a9e4fd31b935de8789faabf3351  gcc/testsuite/ChangeLog-2008
  0f19934540750356d1b91595cebfd9a8  gcc/testsuite/ChangeLog-2009
*************** bc971283f5728545e6e3cd2df580d7f6  gcc/te
*** 16938,16944 ****
  712e2ae6e2d14b147adaaf3a2d4951a2  gcc/testsuite/algol68/compile/error-coercion-1.a68
  7387813dd068726b8857614ece1a4efb  gcc/testsuite/algol68/compile/error-coercion-2.a68
  0cb5c38709490b0cb4abdcbad85e72d7  gcc/testsuite/algol68/compile/error-coercion-flex-1.a68
! 9c935fb17c25d4daa254f9572f167c8c  gcc/testsuite/algol68/compile/error-compile-unknown-tag-1.a68
  772b50965a7c1f70a579488e1cefb701  gcc/testsuite/algol68/compile/error-conformance-clause-1.a68
  91f04623f952b388804ef290a229f30d  gcc/testsuite/algol68/compile/error-contraction-1.a68
  423a86246648987337fb3246786d0e72  gcc/testsuite/algol68/compile/error-contraction-2.a68
--- 16950,16956 ----
  712e2ae6e2d14b147adaaf3a2d4951a2  gcc/testsuite/algol68/compile/error-coercion-1.a68
  7387813dd068726b8857614ece1a4efb  gcc/testsuite/algol68/compile/error-coercion-2.a68
  0cb5c38709490b0cb4abdcbad85e72d7  gcc/testsuite/algol68/compile/error-coercion-flex-1.a68
! 6f10136e865caf9cc474a2a5e7d1c7c1  gcc/testsuite/algol68/compile/error-compile-unknown-tag-1.a68
  772b50965a7c1f70a579488e1cefb701  gcc/testsuite/algol68/compile/error-conformance-clause-1.a68
  91f04623f952b388804ef290a229f30d  gcc/testsuite/algol68/compile/error-contraction-1.a68
  423a86246648987337fb3246786d0e72  gcc/testsuite/algol68/compile/error-contraction-2.a68
*************** ea8363590d8ae913ced70be6d0da442d  gcc/te
*** 16961,16969 ****
  d8d90e3ccd49a8c350bb7fa06c23b69e  gcc/testsuite/algol68/compile/error-mode-stropping-6.a68
  d9255b384fd183b33a0f3f1705652aef  gcc/testsuite/algol68/compile/error-mode-stropping-8.a68
  948785683824fa830a45a02ee6ebd9f4  gcc/testsuite/algol68/compile/error-mode-stropping-9.a68
! b80ebda24ada6a3b555c4762bd7af213  gcc/testsuite/algol68/compile/error-module-coercions-1.a68
  c2b0d2946cbab417eebb4d24da1ab5a8  gcc/testsuite/algol68/compile/error-module-not-found-1.a68
! edf4ae3f64f1086a659495c480cc1fc6  gcc/testsuite/algol68/compile/error-module-ranges-1.a68
  e74cfe8a318c62621bf56edc50d99212  gcc/testsuite/algol68/compile/error-nestable-comments-1.a68
  819697f82afa8855ae899bae58e61181  gcc/testsuite/algol68/compile/error-nested-comment-1.a68
  cc2e80ef77087324e853715ffa5b0fe9  gcc/testsuite/algol68/compile/error-no-bounds-allowed-1.a68
--- 16973,16981 ----
  d8d90e3ccd49a8c350bb7fa06c23b69e  gcc/testsuite/algol68/compile/error-mode-stropping-6.a68
  d9255b384fd183b33a0f3f1705652aef  gcc/testsuite/algol68/compile/error-mode-stropping-8.a68
  948785683824fa830a45a02ee6ebd9f4  gcc/testsuite/algol68/compile/error-mode-stropping-9.a68
! ed8937b8a485d89ad1b8dc4c0b235b82  gcc/testsuite/algol68/compile/error-module-coercions-1.a68
  c2b0d2946cbab417eebb4d24da1ab5a8  gcc/testsuite/algol68/compile/error-module-not-found-1.a68
! 8b0c028ef528ab0ddc26892632812b6e  gcc/testsuite/algol68/compile/error-module-ranges-1.a68
  e74cfe8a318c62621bf56edc50d99212  gcc/testsuite/algol68/compile/error-nestable-comments-1.a68
  819697f82afa8855ae899bae58e61181  gcc/testsuite/algol68/compile/error-nested-comment-1.a68
  cc2e80ef77087324e853715ffa5b0fe9  gcc/testsuite/algol68/compile/error-no-bounds-allowed-1.a68
*************** cb076d039affa49f256d588c4171e17e  gcc/te
*** 17017,17023 ****
  b602de4d7ac9a6d1023dcc45983c25fa  gcc/testsuite/algol68/compile/mcgt-7.1.3a-bis.a68
  9beecedeeea6e22797a615259ef9da5b  gcc/testsuite/algol68/compile/mcgt-7.1.3a.a68
  866415cb9d8563f6b5063c4f3b64551c  gcc/testsuite/algol68/compile/module-1.a68
! fc4af2002a1409a130bbeb4f5c0b55e8  gcc/testsuite/algol68/compile/module-2.a68
  36368510f5b54908ecf16098c9adf923  gcc/testsuite/algol68/compile/module-extracts-1.a68
  58f8a8146e64b14f207b30ac931202c1  gcc/testsuite/algol68/compile/module-mode-exports-1.a68
  3108816a0d7320ec6290ade299708451  gcc/testsuite/algol68/compile/module-mode-exports-2.a68
--- 17029,17035 ----
  b602de4d7ac9a6d1023dcc45983c25fa  gcc/testsuite/algol68/compile/mcgt-7.1.3a-bis.a68
  9beecedeeea6e22797a615259ef9da5b  gcc/testsuite/algol68/compile/mcgt-7.1.3a.a68
  866415cb9d8563f6b5063c4f3b64551c  gcc/testsuite/algol68/compile/module-1.a68
! 3baba36aae381c8fba34a6518ec4c36b  gcc/testsuite/algol68/compile/module-2.a68
  36368510f5b54908ecf16098c9adf923  gcc/testsuite/algol68/compile/module-extracts-1.a68
  58f8a8146e64b14f207b30ac931202c1  gcc/testsuite/algol68/compile/module-mode-exports-1.a68
  3108816a0d7320ec6290ade299708451  gcc/testsuite/algol68/compile/module-mode-exports-2.a68
*************** d2479b622fe7e2b36db5719bd2e94ffd  gcc/te
*** 17029,17035 ****
  3bd11a181372de6d7f9991e91a5ebe72  gcc/testsuite/algol68/compile/module-mode-exports-8.a68
  96dd99f70b78c81fb57c5d0e5774461d  gcc/testsuite/algol68/compile/module-mode-exports-9.a68
  c2b468c74e5471b3f54ca28cbaea6686  gcc/testsuite/algol68/compile/module-pub-1.a68
! a29e7248a591037e6669b73734a430ec  gcc/testsuite/algol68/compile/module-pub-mangling-1.a68
  bdcbc238c76116ee32c7b009c9fa639e  gcc/testsuite/algol68/compile/module-pub-mangling-10.a68
  6fdee0bc204ebc1f76be037d4a87fc70  gcc/testsuite/algol68/compile/module-pub-mangling-11.a68
  cfe6a6dc351a8b5c2dbd290d3c71811a  gcc/testsuite/algol68/compile/module-pub-mangling-12.a68
--- 17041,17047 ----
  3bd11a181372de6d7f9991e91a5ebe72  gcc/testsuite/algol68/compile/module-mode-exports-8.a68
  96dd99f70b78c81fb57c5d0e5774461d  gcc/testsuite/algol68/compile/module-mode-exports-9.a68
  c2b468c74e5471b3f54ca28cbaea6686  gcc/testsuite/algol68/compile/module-pub-1.a68
! 22b07a9083a60c5884613f7e6d659d62  gcc/testsuite/algol68/compile/module-pub-mangling-1.a68
  bdcbc238c76116ee32c7b009c9fa639e  gcc/testsuite/algol68/compile/module-pub-mangling-10.a68
  6fdee0bc204ebc1f76be037d4a87fc70  gcc/testsuite/algol68/compile/module-pub-mangling-11.a68
  cfe6a6dc351a8b5c2dbd290d3c71811a  gcc/testsuite/algol68/compile/module-pub-mangling-12.a68
*************** bf038513538261cf469cd9ab2144d04a  gcc/te
*** 17040,17058 ****
  263383f62ad84153059b202bbaf5d077  gcc/testsuite/algol68/compile/module-pub-mangling-17.a68
  368417893936084e3b3152f5f7622aed  gcc/testsuite/algol68/compile/module-pub-mangling-18.a68
  759b966822f4397503f11ec6228a70d2  gcc/testsuite/algol68/compile/module-pub-mangling-19.a68
! 8bc8c1c04b3c7af78578800881df11d8  gcc/testsuite/algol68/compile/module-pub-mangling-2.a68
  55c6faaeee3e6cdda3597d466deb1833  gcc/testsuite/algol68/compile/module-pub-mangling-20.a68
  a30ee6cd63bedaff93b8e6fe5e3104c8  gcc/testsuite/algol68/compile/module-pub-mangling-21.a68
  09feb0cae5d29f5002b08eae929c069f  gcc/testsuite/algol68/compile/module-pub-mangling-22.a68
! bef5cef400f893076fbcda6fb1d30b4a  gcc/testsuite/algol68/compile/module-pub-mangling-3.a68
! 2d27bc56a02d51318b417a59eba307f2  gcc/testsuite/algol68/compile/module-pub-mangling-4.a68
! da47adc569a28fe9db3e596511b34bc7  gcc/testsuite/algol68/compile/module-pub-mangling-5.a68
! 7e8cf90e2c1ae01a4363bf17e3c67b1e  gcc/testsuite/algol68/compile/module-pub-mangling-6.a68
  0b4169969cf1067eb9799385c8b1c10f  gcc/testsuite/algol68/compile/module-pub-mangling-7.a68
  60794c0d1c26ba1f2f284fa16dce9367  gcc/testsuite/algol68/compile/module-pub-mangling-8.a68
  8df94e66c0218a933ffbabde87c98f0f  gcc/testsuite/algol68/compile/module-pub-mangling-9.a68
  57e64fa4245da0f8ca4b5b370648c45c  gcc/testsuite/algol68/compile/module-top-down-1.a68
! 356d8df23bf52a9d6706f5fa5e750b6c  gcc/testsuite/algol68/compile/modules/compile.exp
  1dcb757cdfc80354940aadcc2c058999  gcc/testsuite/algol68/compile/modules/module1.a68
  0ead388a4ef7afb2ca500c71f6b4cc5e  gcc/testsuite/algol68/compile/modules/module2.a68
  88030bf9e8eba22018c0bf58fc16fb57  gcc/testsuite/algol68/compile/modules/module3.a68
--- 17052,17070 ----
  263383f62ad84153059b202bbaf5d077  gcc/testsuite/algol68/compile/module-pub-mangling-17.a68
  368417893936084e3b3152f5f7622aed  gcc/testsuite/algol68/compile/module-pub-mangling-18.a68
  759b966822f4397503f11ec6228a70d2  gcc/testsuite/algol68/compile/module-pub-mangling-19.a68
! fc4ec9c4918c35aeb1b346a0eaf18fa9  gcc/testsuite/algol68/compile/module-pub-mangling-2.a68
  55c6faaeee3e6cdda3597d466deb1833  gcc/testsuite/algol68/compile/module-pub-mangling-20.a68
  a30ee6cd63bedaff93b8e6fe5e3104c8  gcc/testsuite/algol68/compile/module-pub-mangling-21.a68
  09feb0cae5d29f5002b08eae929c069f  gcc/testsuite/algol68/compile/module-pub-mangling-22.a68
! 9c8122be7fb2969d5f0bb16f99f1a819  gcc/testsuite/algol68/compile/module-pub-mangling-3.a68
! 09d1821ad1bac0c00d8936de3dd768a5  gcc/testsuite/algol68/compile/module-pub-mangling-4.a68
! 802c03a836c31b45b3d87282ed957fbc  gcc/testsuite/algol68/compile/module-pub-mangling-5.a68
! 76259e31cd83395a7b4e085144a96755  gcc/testsuite/algol68/compile/module-pub-mangling-6.a68
  0b4169969cf1067eb9799385c8b1c10f  gcc/testsuite/algol68/compile/module-pub-mangling-7.a68
  60794c0d1c26ba1f2f284fa16dce9367  gcc/testsuite/algol68/compile/module-pub-mangling-8.a68
  8df94e66c0218a933ffbabde87c98f0f  gcc/testsuite/algol68/compile/module-pub-mangling-9.a68
  57e64fa4245da0f8ca4b5b370648c45c  gcc/testsuite/algol68/compile/module-top-down-1.a68
! 26b62815fc288b379cddbabe18f65a6d  gcc/testsuite/algol68/compile/modules/compile.exp
  1dcb757cdfc80354940aadcc2c058999  gcc/testsuite/algol68/compile/modules/module1.a68
  0ead388a4ef7afb2ca500c71f6b4cc5e  gcc/testsuite/algol68/compile/modules/module2.a68
  88030bf9e8eba22018c0bf58fc16fb57  gcc/testsuite/algol68/compile/modules/module3.a68
*************** f8bdf597e223f7a19312f469e7bebb2c  gcc/te
*** 17098,17104 ****
  9f86c9afe58719a2b293131967222a4a  gcc/testsuite/algol68/compile/warning-hidding-5.a68
  13f7654ced30a31d28d56c3239b89f5e  gcc/testsuite/algol68/compile/warning-hidding-6.a68
  e14ebfc17f0d5a0614337bead1e007ba  gcc/testsuite/algol68/compile/warning-hidding-7.a68
! 1757b8746272ad8daa8a13c84a22e509  gcc/testsuite/algol68/compile/warning-module-hidding-1.a68
  41df534ea49cfcb09d174d33fd30ee3f  gcc/testsuite/algol68/compile/warning-pub-loc-1.a68
  1d064e1d3ce2a25c6d87a174853839b8  gcc/testsuite/algol68/compile/warning-scope-1.a68
  c1bb63db8778574141ba8b0ba3efdffb  gcc/testsuite/algol68/compile/warning-scope-2.a68
--- 17110,17116 ----
  9f86c9afe58719a2b293131967222a4a  gcc/testsuite/algol68/compile/warning-hidding-5.a68
  13f7654ced30a31d28d56c3239b89f5e  gcc/testsuite/algol68/compile/warning-hidding-6.a68
  e14ebfc17f0d5a0614337bead1e007ba  gcc/testsuite/algol68/compile/warning-hidding-7.a68
! 4d1973c48986daa9670ee83d7c85ff4e  gcc/testsuite/algol68/compile/warning-module-hidding-1.a68
  41df534ea49cfcb09d174d33fd30ee3f  gcc/testsuite/algol68/compile/warning-pub-loc-1.a68
  1d064e1d3ce2a25c6d87a174853839b8  gcc/testsuite/algol68/compile/warning-scope-1.a68
  c1bb63db8778574141ba8b0ba3efdffb  gcc/testsuite/algol68/compile/warning-scope-2.a68
*************** f2beb07edffabebdccad8faf2bc3b584  gcc/te
*** 17362,17372 ****
  ed509318512a89382e1649c84de44521  gcc/testsuite/algol68/execute/modab-1.a68
  2c85457bdee9291c8a0c753cefa40d62  gcc/testsuite/algol68/execute/modab-2.a68
  8003cac24f1aa6e0dc244b3788038cb6  gcc/testsuite/algol68/execute/mode-indication-1.a68
  bcfdb63511805c2e3f5b07f72f0171f0  gcc/testsuite/algol68/execute/modules/README
! b2a7a3e5db21bd4321546158c19963ba  gcc/testsuite/algol68/execute/modules/execute.exp
  39fcf22b33adb94c6b5bd5617b63e86d  gcc/testsuite/algol68/execute/modules/module1.a68
  855a8f2560fc05a0a81d49c7cb67ff67  gcc/testsuite/algol68/execute/modules/module10.a68
! 3950a78a44cbdfecabd0173325cc5806  gcc/testsuite/algol68/execute/modules/module11.a68
  d96afe1f473d2f45009f219219c15469  gcc/testsuite/algol68/execute/modules/module12.a68
  9fd12220c9065df94120aef748cbda95  gcc/testsuite/algol68/execute/modules/module13.a68
  a587cd3c9bf8eaf397493ee12823942c  gcc/testsuite/algol68/execute/modules/module14.a68
--- 17374,17387 ----
  ed509318512a89382e1649c84de44521  gcc/testsuite/algol68/execute/modab-1.a68
  2c85457bdee9291c8a0c753cefa40d62  gcc/testsuite/algol68/execute/modab-2.a68
  8003cac24f1aa6e0dc244b3788038cb6  gcc/testsuite/algol68/execute/mode-indication-1.a68
+ ddb9ed171e55fb428066288927a9bd82  gcc/testsuite/algol68/execute/modules/Modules20.map
  bcfdb63511805c2e3f5b07f72f0171f0  gcc/testsuite/algol68/execute/modules/README
! e5b476c1b300f469c5d1e91806486a63  gcc/testsuite/algol68/execute/modules/execute.exp
! 6886f82d84222ca0459b86fbdec52673  gcc/testsuite/algol68/execute/modules/module-bar.a68
! abe7f005a9e088b8203de09a769768e0  gcc/testsuite/algol68/execute/modules/module-foo.a68
  39fcf22b33adb94c6b5bd5617b63e86d  gcc/testsuite/algol68/execute/modules/module1.a68
  855a8f2560fc05a0a81d49c7cb67ff67  gcc/testsuite/algol68/execute/modules/module10.a68
! fccef707a976cbc27c1dcdeb9bcceef6  gcc/testsuite/algol68/execute/modules/module11.a68
  d96afe1f473d2f45009f219219c15469  gcc/testsuite/algol68/execute/modules/module12.a68
  9fd12220c9065df94120aef748cbda95  gcc/testsuite/algol68/execute/modules/module13.a68
  a587cd3c9bf8eaf397493ee12823942c  gcc/testsuite/algol68/execute/modules/module14.a68
*************** f426864755e710beb231da3ea058d671  gcc/te
*** 17387,17393 ****
--- 17402,17410 ----
  a99af1096f319575a7f72a39e2cf179e  gcc/testsuite/algol68/execute/modules/program-15.a68
  8d0c43b9fdccd78d75beefb6013496b2  gcc/testsuite/algol68/execute/modules/program-16.a68
  54a19c7d8623132b8094c6c4aa2692e4  gcc/testsuite/algol68/execute/modules/program-17.a68
+ aeabee135ed523b7f2a8f8d1f77b06eb  gcc/testsuite/algol68/execute/modules/program-19.a68
  57f36f8064ebb76768548805faaf91d5  gcc/testsuite/algol68/execute/modules/program-2.a68
+ 924948ff93175f2dd41713aed063e240  gcc/testsuite/algol68/execute/modules/program-20.a68
  b8f47f3c2df580248368a5c298a1b812  gcc/testsuite/algol68/execute/modules/program-3.a68
  7d433464d7d562ce9bd71eea28f40c03  gcc/testsuite/algol68/execute/modules/program-4.a68
  a00ad027485af688f31ddcf5b822ad9e  gcc/testsuite/algol68/execute/modules/program-5.a68
*************** a2a78072e3d8b53573e8f00012aa5e02  gcc/te
*** 17949,17954 ****
--- 17966,17972 ----
  c7b299e5fe505151c6cb908712174601  gcc/testsuite/c-c++-common/analyzer/analyzer-verbosity-2a.c
  6d64ae2854f0c1c2c817a3832375555f  gcc/testsuite/c-c++-common/analyzer/analyzer-verbosity-3.c
  ed77fd41a183e028937b9a3322bb7a70  gcc/testsuite/c-c++-common/analyzer/analyzer-verbosity-3a.c
+ cca57e9fb9342c8e79642164deb2fa66  gcc/testsuite/c-c++-common/analyzer/arith-1.c
  fc965261104eb781f63faa0fe5a3d7b1  gcc/testsuite/c-c++-common/analyzer/asm-x86-1.c
  4f3de36e277422446a2a0c8cd3afe090  gcc/testsuite/c-c++-common/analyzer/asm-x86-dyndbg-2.c
  cfc15687f29058760db8cdfd6af9f0d8  gcc/testsuite/c-c++-common/analyzer/asm-x86-lp64-2.c
*************** a105342d3292d355507ab715b3a2ca98  gcc/te
*** 18123,18128 ****
--- 18141,18147 ----
  a66185ed3bef2742621b423d3bec08ab  gcc/testsuite/c-c++-common/analyzer/infinite-recursion-pr108935-1.c
  7d75523d81879148276b42e991a4c362  gcc/testsuite/c-c++-common/analyzer/infinite-recursion-pr108935-1a.c
  66723f902622a5e196b22ca3d8fceff6  gcc/testsuite/c-c++-common/analyzer/infinite-recursion-pr108935-2.c
+ 06baba8fb190338b8a7cb3d26bb98679  gcc/testsuite/c-c++-common/analyzer/infinite-recursion-pr122975.c
  43c57be318716a133d18499c08ddc7aa  gcc/testsuite/c-c++-common/analyzer/infinite-recursion-variadic.c
  b5d43db912cf8450f4d29c2782ff99f0  gcc/testsuite/c-c++-common/analyzer/infinite-recursion.c
  e7a346d9228f0a095843adfb8d30f916  gcc/testsuite/c-c++-common/analyzer/init.c
*************** a20f56474f9327e4df5f75e759a08cfc  gcc/te
*** 18423,18428 ****
--- 18442,18448 ----
  8f913e3de654aeeed3a380e266f73c9d  gcc/testsuite/c-c++-common/analyzer/strlen-pr111361.c
  c02d2254f7ec2e1d0a71dadd15088d94  gcc/testsuite/c-c++-common/analyzer/strlen-pr112811.c
  3d94f951f5b6fbc3d0844975b793c18e  gcc/testsuite/c-c++-common/analyzer/strlen-pr113999.c
+ af84b442d8f68452823319bf94649695  gcc/testsuite/c-c++-common/analyzer/strlen-pr123085.c
  188f94d7648b519e3d2cce6399a73f5f  gcc/testsuite/c-c++-common/analyzer/strncpy-1.c
  95822937a3320cebcdcd88c927eb703e  gcc/testsuite/c-c++-common/analyzer/strncpy-pr111361.c
  5f63b79c771eee4d268d6bba34c9182c  gcc/testsuite/c-c++-common/analyzer/strndup-1.c
*************** fe6ba0d7acbbc77e0b1c41bbf1c0f42b  gcc/te
*** 19379,19384 ****
--- 19399,19405 ----
  8b2645274383ff712f17cf9c9ea41def  gcc/testsuite/c-c++-common/gomp/assume-2.c
  9adbf63d6cc6673274053baa4a7406f3  gcc/testsuite/c-c++-common/gomp/assume-3.c
  32f71a409194e932942c40570b74b4c1  gcc/testsuite/c-c++-common/gomp/assume-4.c
+ 64b4ac9b97648cf8c29bd561ccba1359  gcc/testsuite/c-c++-common/gomp/assume-5.c
  fe9e9de178a149d4be1130f4bb6a725d  gcc/testsuite/c-c++-common/gomp/assumes-1.c
  a04d7de81be62c6f374ee7d4802190c1  gcc/testsuite/c-c++-common/gomp/assumes-2.c
  1e08736ed2274dbfec7f233a154f1bff  gcc/testsuite/c-c++-common/gomp/assumes-3.c
*************** a89d3bc336c39386e5c41b412c5cadf6  gcc/te
*** 19843,19848 ****
--- 19864,19870 ----
  415ffbd983ab85f8ae866ca8d4790b1d  gcc/testsuite/c-c++-common/gomp/target-device-ancestor-3.c
  ca7ba586dac58a7cd9e9b58a6d8e470e  gcc/testsuite/c-c++-common/gomp/target-device-ancestor-4.c
  4561a8adae0edb1000cfcf5746ff89dd  gcc/testsuite/c-c++-common/gomp/target-device-ancestor-5.c
+ f293c0a7e739752d474b940558985611  gcc/testsuite/c-c++-common/gomp/target-device-type-1.c
  66e2be8c890c4523436f834850ae75a5  gcc/testsuite/c-c++-common/gomp/target-enter-data-1.c
  8c2b82227fc84e1d964bb4a1b2f14f03  gcc/testsuite/c-c++-common/gomp/target-has-device-addr-1.c
  e5def8b0431262a97550aa7141a818a1  gcc/testsuite/c-c++-common/gomp/target-has-device-addr-2.c
*************** c67d4ce1ba8835a7d5bba95cfee6a999  gcc/te
*** 19905,19910 ****
--- 19927,19933 ----
  c990dbb84715f7cae212333d6c10df66  gcc/testsuite/c-c++-common/gomp/uses_allocators-2.c
  f467d80ae7a5dcb6ae64d06010a6bccd  gcc/testsuite/c-c++-common/gomp/uses_allocators-4.c
  068da7e739dbe5d90ada7169c0588ca2  gcc/testsuite/c-c++-common/gomp/uses_allocators-7.c
+ a397f398c9637b673aa01aa66ce48a72  gcc/testsuite/c-c++-common/gomp/uses_allocators-8.c
  ae581c139df3ad068476c3c0011b10df  gcc/testsuite/c-c++-common/guality/Og-dce-1.c
  77dfce37c98a7f3ba9475b987b487300  gcc/testsuite/c-c++-common/guality/Og-dce-2.c
  d8649d74f0435be9dfbda3d78613de4d  gcc/testsuite/c-c++-common/guality/Og-dce-3.c
*************** c2020757348be38768a84038f994ef30  gcc/te
*** 21653,21659 ****
  098b67367f9be2c124f0064e61162fa9  gcc/testsuite/g++.dg/DRs/dr2874.C
  a0e21528a4a4b6c55e3ddacf0a8cf5f7  gcc/testsuite/g++.dg/DRs/dr2918.C
  35a1ad73c2dad3082e687ad6cb6e4a83  gcc/testsuite/g++.dg/DRs/dr3045.C
! 2ca94605cdd826e6318b37f454c91235  gcc/testsuite/g++.dg/DRs/dr3061.C
  0db4e83f65185c2945cb11bd0815a87e  gcc/testsuite/g++.dg/DRs/dr3079.C
  7a4b27e45b2c85a34faf94f75f8945d1  gcc/testsuite/g++.dg/DRs/dr625.C
  cdd5e29f9e112d6201410809ca83e0d2  gcc/testsuite/g++.dg/DRs/dr882.C
--- 21676,21682 ----
  098b67367f9be2c124f0064e61162fa9  gcc/testsuite/g++.dg/DRs/dr2874.C
  a0e21528a4a4b6c55e3ddacf0a8cf5f7  gcc/testsuite/g++.dg/DRs/dr2918.C
  35a1ad73c2dad3082e687ad6cb6e4a83  gcc/testsuite/g++.dg/DRs/dr3045.C
! 3f297cb3f2f7472c7c0e23d3d9a4e49c  gcc/testsuite/g++.dg/DRs/dr3061.C
  0db4e83f65185c2945cb11bd0815a87e  gcc/testsuite/g++.dg/DRs/dr3079.C
  7a4b27e45b2c85a34faf94f75f8945d1  gcc/testsuite/g++.dg/DRs/dr625.C
  cdd5e29f9e112d6201410809ca83e0d2  gcc/testsuite/g++.dg/DRs/dr882.C
*************** f0e116d82b5a6de3a9e5af9a0a9f86f6  gcc/te
*** 24136,24141 ****
--- 24159,24165 ----
  60b64cb629f4a02ed81a12fb0b2cc041  gcc/testsuite/g++.dg/cpp0x/deleted16.C
  e0ec3b8dde104f6e13caaaf049aa05c6  gcc/testsuite/g++.dg/cpp0x/deleted16a.C
  739d0ece28a2f02a16bc7821fc37839c  gcc/testsuite/g++.dg/cpp0x/deleted17.C
+ 5b4f225619f296097880cecd253cfafa  gcc/testsuite/g++.dg/cpp0x/deleted18.C
  80874d553919bf312b4841380187e0f9  gcc/testsuite/g++.dg/cpp0x/deleted2.C
  a9129f4cd34b93dbe745e3849ea1c38a  gcc/testsuite/g++.dg/cpp0x/deleted3.C
  d6f65d86ea217a2efd4c31ebedc9c9db  gcc/testsuite/g++.dg/cpp0x/deleted4.C
*************** a91da33ee84c2ea78d5b6401d75d528e  gcc/te
*** 24603,24609 ****
  e740069b6b9e1423ef8e1b3610d6d39f  gcc/testsuite/g++.dg/cpp0x/initlist29.C
  ee2417eea379565b56e2d87788fa6673  gcc/testsuite/g++.dg/cpp0x/initlist3.C
  a558a49726098b2e30f9484a7f3b4bb8  gcc/testsuite/g++.dg/cpp0x/initlist30.C
! d778aca18992e788189451060e227a20  gcc/testsuite/g++.dg/cpp0x/initlist31.C
  348452a0372d790b7162b71f61d7cbcf  gcc/testsuite/g++.dg/cpp0x/initlist32.C
  a2834629b04af762946ceecad082bf0e  gcc/testsuite/g++.dg/cpp0x/initlist33.C
  53ef55753c091278fa63b21ed620c269  gcc/testsuite/g++.dg/cpp0x/initlist34.C
--- 24627,24633 ----
  e740069b6b9e1423ef8e1b3610d6d39f  gcc/testsuite/g++.dg/cpp0x/initlist29.C
  ee2417eea379565b56e2d87788fa6673  gcc/testsuite/g++.dg/cpp0x/initlist3.C
  a558a49726098b2e30f9484a7f3b4bb8  gcc/testsuite/g++.dg/cpp0x/initlist30.C
! 7932e86e8f9511d8943a4ea17d40ffc8  gcc/testsuite/g++.dg/cpp0x/initlist31.C
  348452a0372d790b7162b71f61d7cbcf  gcc/testsuite/g++.dg/cpp0x/initlist32.C
  a2834629b04af762946ceecad082bf0e  gcc/testsuite/g++.dg/cpp0x/initlist33.C
  53ef55753c091278fa63b21ed620c269  gcc/testsuite/g++.dg/cpp0x/initlist34.C
*************** fe526337c46e51da61277e503a425d3c  gcc/te
*** 25003,25009 ****
  4c9fa986dc7f6deef6a257359aa5e2ca  gcc/testsuite/g++.dg/cpp0x/new1.C
  5103d8a889c20932b4c0d1f36f771d88  gcc/testsuite/g++.dg/cpp0x/new2.C
  619ac7b9f67c073afd9a0d09b9e71a25  gcc/testsuite/g++.dg/cpp0x/new3.C
! fd416d8d36f2dd6e9ba7d2cef681fdbb  gcc/testsuite/g++.dg/cpp0x/new4.C
  49906341e996621b46c7c41ec0499a34  gcc/testsuite/g++.dg/cpp0x/new5.C
  f9622d878dfdbb80673c052485d80c80  gcc/testsuite/g++.dg/cpp0x/new6.C
  981a1b52d13a4061d8e2bfcbe9c0fba0  gcc/testsuite/g++.dg/cpp0x/no-weak1.C
--- 25027,25033 ----
  4c9fa986dc7f6deef6a257359aa5e2ca  gcc/testsuite/g++.dg/cpp0x/new1.C
  5103d8a889c20932b4c0d1f36f771d88  gcc/testsuite/g++.dg/cpp0x/new2.C
  619ac7b9f67c073afd9a0d09b9e71a25  gcc/testsuite/g++.dg/cpp0x/new3.C
! 7788dda0bd6950464fd65c6ec56eefd6  gcc/testsuite/g++.dg/cpp0x/new4.C
  49906341e996621b46c7c41ec0499a34  gcc/testsuite/g++.dg/cpp0x/new5.C
  f9622d878dfdbb80673c052485d80c80  gcc/testsuite/g++.dg/cpp0x/new6.C
  981a1b52d13a4061d8e2bfcbe9c0fba0  gcc/testsuite/g++.dg/cpp0x/no-weak1.C
*************** e944a760f2bcd206b36820c53e03b241  gcc/te
*** 25099,25104 ****
--- 25123,25129 ----
  6920aaae5ff91adaae9f973d58b99fd0  gcc/testsuite/g++.dg/cpp0x/noexcept89.C
  01fdf9b25aed01336395f7314f3b5857  gcc/testsuite/g++.dg/cpp0x/noexcept90.C
  a1c17fbec179b1075e3839acd36429dc  gcc/testsuite/g++.dg/cpp0x/noexcept91.C
+ 0b7482d65d1817e0099f68c74ce2cd47  gcc/testsuite/g++.dg/cpp0x/noexcept91a.C
  3bf83ccb654cedbb57a45851fb14aa9d  gcc/testsuite/g++.dg/cpp0x/nolinkage1.C
  6b7c91b931bbdacbbffbf9b90a79bc6a  gcc/testsuite/g++.dg/cpp0x/nolinkage1.h
  c92e0eda44dd6b3d74960b249fa5204f  gcc/testsuite/g++.dg/cpp0x/nolinkage1a.cc
*************** e3a88ae9ca562b3c9a47ee98c06e6ded  gcc/te
*** 27280,27285 ****
--- 27305,27311 ----
  63be3b6d75aa3c2c8088552683d5245e  gcc/testsuite/g++.dg/cpp1z/eval-order10.C
  3abc6084e572264410718d38beb290bb  gcc/testsuite/g++.dg/cpp1z/eval-order11.C
  2a2d4866a044c20823b5f37f629ac147  gcc/testsuite/g++.dg/cpp1z/eval-order13.C
+ 612e7cfe92accd2bee31cd13a0976f33  gcc/testsuite/g++.dg/cpp1z/eval-order14.C
  ebf7b90ef919b5a31b45b49ad9bd61c9  gcc/testsuite/g++.dg/cpp1z/eval-order2.C
  8b89dee7164b6f4d992706e5b85433f4  gcc/testsuite/g++.dg/cpp1z/eval-order3.C
  6d8d378fedaf65b4cb89952060799280  gcc/testsuite/g++.dg/cpp1z/eval-order4.C
*************** f35c40f9359deda380357490b21bcf4f  gcc/te
*** 27493,27498 ****
--- 27519,27525 ----
  1cec7e8e1ac5999209a00a7fd3e2dbab  gcc/testsuite/g++.dg/cpp1z/static1.C
  41cdf88b4e2dc9ba29ab954fd0f3d05c  gcc/testsuite/g++.dg/cpp1z/static2.C
  491588e8dd93d83d5049e3c332e8755f  gcc/testsuite/g++.dg/cpp1z/static_assert-nomsg.C
+ d123582c5d5cdc2e4fdc925fa563f023  gcc/testsuite/g++.dg/cpp1z/static_assert1.C
  7dd3448d4722a9ee0446db6aa3c7a0b0  gcc/testsuite/g++.dg/cpp1z/ttp1.C
  0cd62ffa5ae2d02bd665e02895b12f01  gcc/testsuite/g++.dg/cpp1z/ttp2.C
  64b3f9e4e9d3f04ac339e1f86e353e9b  gcc/testsuite/g++.dg/cpp1z/typename-tmpl-tmpl-parm-neg.C
*************** ee32c4ffc3127b060ad7d2d7978d4c00  gcc/te
*** 27572,27577 ****
--- 27599,27605 ----
  436f3521c73eff29eb95a9935488f619  gcc/testsuite/g++.dg/cpp23/charlit-encoding1.C
  bbd34d70bffdb5659d43e105cc5654f0  gcc/testsuite/g++.dg/cpp23/charset1.C
  fc95968ef690ef967f99e7fc9cf9bb22  gcc/testsuite/g++.dg/cpp23/class-deduction-inherited1.C
+ 289c2847fb294b33f74d735aba8d2b44  gcc/testsuite/g++.dg/cpp23/class-deduction-inherited10.C
  0bfba7997142477c825e6eac0de01c78  gcc/testsuite/g++.dg/cpp23/class-deduction-inherited2.C
  4d439f6f5585d12bf5b651068b33af79  gcc/testsuite/g++.dg/cpp23/class-deduction-inherited3.C
  726edadc3f3d862f8f9d5cdbffdc3430  gcc/testsuite/g++.dg/cpp23/class-deduction-inherited4.C
*************** d1816c76dd387be6d07b1763c88d7e12  gcc/te
*** 27579,27584 ****
--- 27607,27613 ----
  7102bd9f78d9dd5baf868b5867fd00fb  gcc/testsuite/g++.dg/cpp23/class-deduction-inherited6.C
  1eb71fc21e8ad1d9fc8b9177ae3ff8bd  gcc/testsuite/g++.dg/cpp23/class-deduction-inherited7.C
  b70c43fcf5e919517d07b52eba057f7e  gcc/testsuite/g++.dg/cpp23/class-deduction-inherited8.C
+ c281d9c48ed1e62c15bb0a8e9a361e9a  gcc/testsuite/g++.dg/cpp23/class-deduction-inherited9.C
  a5e6981af3e3d461e280ff24cd289402  gcc/testsuite/g++.dg/cpp23/concepts-err1.C
  636155e5662c48788ae52677e22b5249  gcc/testsuite/g++.dg/cpp23/consteval-if1.C
  821ea836b45f7af0a628e6eb278e28f9  gcc/testsuite/g++.dg/cpp23/consteval-if10.C
*************** aa7084460b314da9c28cdf37e67100c4  gcc/te
*** 27866,27872 ****
  0c6cc7bc14adc7d7cff2e19ed2f21ba9  gcc/testsuite/g++.dg/cpp26/erroneous4.C
  297da1726d3e7afdc47f8d5d6953759b  gcc/testsuite/g++.dg/cpp26/erroneous5.C
  a37be6fa19087a24f020178e94b5020d  gcc/testsuite/g++.dg/cpp26/erroneous6.C
! d4331d8da306930f1d44ca3a2535e838  gcc/testsuite/g++.dg/cpp26/expansion-stmt1.C
  550ad6705c2ee18c462420135db42434  gcc/testsuite/g++.dg/cpp26/expansion-stmt10.C
  27464fb36f9adff660032384a5f744d1  gcc/testsuite/g++.dg/cpp26/expansion-stmt11.C
  d2f3d1d0903cd9aafbe5cfc699f5e974  gcc/testsuite/g++.dg/cpp26/expansion-stmt12.C
--- 27895,27901 ----
  0c6cc7bc14adc7d7cff2e19ed2f21ba9  gcc/testsuite/g++.dg/cpp26/erroneous4.C
  297da1726d3e7afdc47f8d5d6953759b  gcc/testsuite/g++.dg/cpp26/erroneous5.C
  a37be6fa19087a24f020178e94b5020d  gcc/testsuite/g++.dg/cpp26/erroneous6.C
! 954c74496d3a7aab6f8eedc25fa7fae1  gcc/testsuite/g++.dg/cpp26/expansion-stmt1.C
  550ad6705c2ee18c462420135db42434  gcc/testsuite/g++.dg/cpp26/expansion-stmt10.C
  27464fb36f9adff660032384a5f744d1  gcc/testsuite/g++.dg/cpp26/expansion-stmt11.C
  d2f3d1d0903cd9aafbe5cfc699f5e974  gcc/testsuite/g++.dg/cpp26/expansion-stmt12.C
*************** d2f3d1d0903cd9aafbe5cfc699f5e974  gcc/te
*** 27875,27890 ****
  8b57ea067d4cae17a4720a89345931b4  gcc/testsuite/g++.dg/cpp26/expansion-stmt15.C
  14352b0cb38dc6eeb6188f47cd518b4a  gcc/testsuite/g++.dg/cpp26/expansion-stmt16.C
  40a9f0169438dcc0077a4b3f3a07e396  gcc/testsuite/g++.dg/cpp26/expansion-stmt17.C
! 86eecfab49da65a501129dfaf2007e5c  gcc/testsuite/g++.dg/cpp26/expansion-stmt18.C
  a9c707a9b9460b695998400fa35fced5  gcc/testsuite/g++.dg/cpp26/expansion-stmt19.C
! 2e358fbc45ce2ab793c6396aabaf7c00  gcc/testsuite/g++.dg/cpp26/expansion-stmt2.C
  a430b39e1be5d1fb74398b6e2ed2bc77  gcc/testsuite/g++.dg/cpp26/expansion-stmt20.C
  6d0dfe9eb3ad7d8109fbb3b138464ecc  gcc/testsuite/g++.dg/cpp26/expansion-stmt21.C
  f8d8f977a2ce10a22535ceb90309b531  gcc/testsuite/g++.dg/cpp26/expansion-stmt22.C
  acbce95791211ede09f67fcd376b48cb  gcc/testsuite/g++.dg/cpp26/expansion-stmt23.C
  4f56781af7d20030274d9a133126e14b  gcc/testsuite/g++.dg/cpp26/expansion-stmt24.C
  6e0ba6570c6704c45f502e328e1b9c51  gcc/testsuite/g++.dg/cpp26/expansion-stmt27.C
! c66852484325a654361305c49419f459  gcc/testsuite/g++.dg/cpp26/expansion-stmt3.C
  05972a123b20a66b9c7899c2bb0b5042  gcc/testsuite/g++.dg/cpp26/expansion-stmt4.C
  7cfc2afc603d55bfd66b320b3d190acd  gcc/testsuite/g++.dg/cpp26/expansion-stmt5.C
  8419176a2bf5898de53901daf6efe2a9  gcc/testsuite/g++.dg/cpp26/expansion-stmt6.C
--- 27904,27919 ----
  8b57ea067d4cae17a4720a89345931b4  gcc/testsuite/g++.dg/cpp26/expansion-stmt15.C
  14352b0cb38dc6eeb6188f47cd518b4a  gcc/testsuite/g++.dg/cpp26/expansion-stmt16.C
  40a9f0169438dcc0077a4b3f3a07e396  gcc/testsuite/g++.dg/cpp26/expansion-stmt17.C
! e3a8dec9a6c102a45b488c0902a817d7  gcc/testsuite/g++.dg/cpp26/expansion-stmt18.C
  a9c707a9b9460b695998400fa35fced5  gcc/testsuite/g++.dg/cpp26/expansion-stmt19.C
! b9aba1d42afeda7f7d3906234c8c2fd9  gcc/testsuite/g++.dg/cpp26/expansion-stmt2.C
  a430b39e1be5d1fb74398b6e2ed2bc77  gcc/testsuite/g++.dg/cpp26/expansion-stmt20.C
  6d0dfe9eb3ad7d8109fbb3b138464ecc  gcc/testsuite/g++.dg/cpp26/expansion-stmt21.C
  f8d8f977a2ce10a22535ceb90309b531  gcc/testsuite/g++.dg/cpp26/expansion-stmt22.C
  acbce95791211ede09f67fcd376b48cb  gcc/testsuite/g++.dg/cpp26/expansion-stmt23.C
  4f56781af7d20030274d9a133126e14b  gcc/testsuite/g++.dg/cpp26/expansion-stmt24.C
  6e0ba6570c6704c45f502e328e1b9c51  gcc/testsuite/g++.dg/cpp26/expansion-stmt27.C
! b2b33bdc39d1d27a4c8029e91514b3c1  gcc/testsuite/g++.dg/cpp26/expansion-stmt3.C
  05972a123b20a66b9c7899c2bb0b5042  gcc/testsuite/g++.dg/cpp26/expansion-stmt4.C
  7cfc2afc603d55bfd66b320b3d190acd  gcc/testsuite/g++.dg/cpp26/expansion-stmt5.C
  8419176a2bf5898de53901daf6efe2a9  gcc/testsuite/g++.dg/cpp26/expansion-stmt6.C
*************** f3b34592f993c84838b0ef36dad5ed5e  gcc/te
*** 27893,27899 ****
  fab75ccc959cbef8fb3183a88990faa8  gcc/testsuite/g++.dg/cpp26/expansion-stmt9.C
  ecc4e011dced560dab638b382ac4b9e1  gcc/testsuite/g++.dg/cpp26/feat-cxx26.C
  e439504634b8fdea668e10d9fc930c63  gcc/testsuite/g++.dg/cpp26/literals1.C
! 24ebebb3be412c0e507595cb8c7458f5  gcc/testsuite/g++.dg/cpp26/literals2.C
  8f5e59e0f7c8cbf6a6ab946370b7128b  gcc/testsuite/g++.dg/cpp26/name-independent-decl1.C
  cd432aa62bbbf4b16b93cb38b110d2a5  gcc/testsuite/g++.dg/cpp26/name-independent-decl10.C
  716a88642b5e961fcc1c493ea3af08bd  gcc/testsuite/g++.dg/cpp26/name-independent-decl11.C
--- 27922,27928 ----
  fab75ccc959cbef8fb3183a88990faa8  gcc/testsuite/g++.dg/cpp26/expansion-stmt9.C
  ecc4e011dced560dab638b382ac4b9e1  gcc/testsuite/g++.dg/cpp26/feat-cxx26.C
  e439504634b8fdea668e10d9fc930c63  gcc/testsuite/g++.dg/cpp26/literals1.C
! 3572f5ef732defbaed672decde98fc83  gcc/testsuite/g++.dg/cpp26/literals2.C
  8f5e59e0f7c8cbf6a6ab946370b7128b  gcc/testsuite/g++.dg/cpp26/name-independent-decl1.C
  cd432aa62bbbf4b16b93cb38b110d2a5  gcc/testsuite/g++.dg/cpp26/name-independent-decl10.C
  716a88642b5e961fcc1c493ea3af08bd  gcc/testsuite/g++.dg/cpp26/name-independent-decl11.C
*************** c61f89754bf19eb066c90223050eb1d6  gcc/te
*** 28173,28178 ****
--- 28202,28208 ----
  f553dcaedc09d2c9050b889d62bcff97  gcc/testsuite/g++.dg/cpp2a/concepts-lambda22.C
  a33c273c880831d4ae8354f3eae13e25  gcc/testsuite/g++.dg/cpp2a/concepts-lambda23.C
  c5f62ec8bee71a828d47886f4bfb04dc  gcc/testsuite/g++.dg/cpp2a/concepts-lambda24.C
+ 4f2175a0b18d9ac1791f0a131a07292a  gcc/testsuite/g++.dg/cpp2a/concepts-lambda25.C
  c1dc95530d3c5579fce346628c40061a  gcc/testsuite/g++.dg/cpp2a/concepts-lambda3.C
  6f185f0a7016ab67c7f0d4ffa7012182  gcc/testsuite/g++.dg/cpp2a/concepts-lambda4.C
  86976d8466300862e381a2182c187b35  gcc/testsuite/g++.dg/cpp2a/concepts-lambda5.C
*************** d948ecca981f7c5de5ca48afc987ea36  gcc/te
*** 28893,28898 ****
--- 28923,28929 ----
  cdfd5d4f5405d532a58794854f989b98  gcc/testsuite/g++.dg/cpp2a/lambda-targ7.C
  fa760f5c26c36d0c67ddc827d3f5e208  gcc/testsuite/g++.dg/cpp2a/lambda-targ8.C
  15b80269879f037a123b86aca4c9b576  gcc/testsuite/g++.dg/cpp2a/lambda-targ9.C
+ 45e29b436b481b2e96108549f778979f  gcc/testsuite/g++.dg/cpp2a/lambda-template-pr117034.C
  22ec10632b049637a7cbf82f46eda177  gcc/testsuite/g++.dg/cpp2a/lambda-this1.C
  c09b3406a6984eced941c654f03df8b6  gcc/testsuite/g++.dg/cpp2a/lambda-this2.C
  58b6c8506ae6f77f9498fd7dbed8bdeb  gcc/testsuite/g++.dg/cpp2a/lambda-this3.C
*************** becc0e6f064af285a504ff10eaffc525  gcc/te
*** 29534,29539 ****
--- 29565,29572 ----
  204f6d67816240aa15bfa5d9320862f5  gcc/testsuite/g++.dg/dfp/mangle-6.C
  8b4d16a77a1edab85ee4c99fda03eb79  gcc/testsuite/g++.dg/dfp/mangle-mode.C
  3a865b01c504023d0b90b1f055163c6a  gcc/testsuite/g++.dg/dfp/nofields.C
+ fd0549fb3825f83ce2ac884838fe2187  gcc/testsuite/g++.dg/dfp/pr122834-1.C
+ 87b1932d8497bd7b8b41f36fb0c23208  gcc/testsuite/g++.dg/dfp/pr122834-2.C
  919ff80bde2b401e1cf10423071bab16  gcc/testsuite/g++.dg/dfp/pr92744.C
  cd0133a632a541db051ef84d53754ac6  gcc/testsuite/g++.dg/dfp/typeid1.C
  d7b10c41bed5782388e3e624407cba5c  gcc/testsuite/g++.dg/dg.exp
*************** aa081a16610eaae6eaa83ad85ce8aa33  gcc/te
*** 30619,30624 ****
--- 30652,30658 ----
  37398fff65ce2d16df6f0cb340b97987  gcc/testsuite/g++.dg/ext/is_final.C
  3702c5ca025df0d43d103161203f0ddf  gcc/testsuite/g++.dg/ext/is_function.C
  421f56d6828967eabadae2f63452e22d  gcc/testsuite/g++.dg/ext/is_implicit_lifetime.C
+ 17ec903e307ff61c01e84ba3f010b82c  gcc/testsuite/g++.dg/ext/is_implicit_lifetime2.C
  04356e7583c2b33f9d0c90103c46653f  gcc/testsuite/g++.dg/ext/is_invocable1.C
  0da83314cec6d313a123af04a33e386b  gcc/testsuite/g++.dg/ext/is_invocable2.C
  a880bbf4a2491686f32ef99587f1d5d7  gcc/testsuite/g++.dg/ext/is_invocable3.C
*************** b37a08c48590ee57a45669e3a61fc899  gcc/te
*** 31621,31626 ****
--- 31655,31661 ----
  012194f3f4441fc0dc8fb4ba94a8882b  gcc/testsuite/g++.dg/graphite/pr42681.C
  dfe63b7d52f6d97e04da25f267ac330c  gcc/testsuite/g++.dg/graphite/pr42930.C
  4cf735ba9e5b65e201dbbd4ec916b359  gcc/testsuite/g++.dg/graphite/pr43026.C
+ 972ae62627d5778f45f285feb6661317  gcc/testsuite/g++.dg/guality/decomp1.C
  08dc2a58649d3fc498035d86e6f73fde  gcc/testsuite/g++.dg/guality/guality.exp
  2e0a2ac35d8a11426ad1e59f818a5d03  gcc/testsuite/g++.dg/guality/guality.h
  9f6bd16255ea79978f41ff1fd8300ddc  gcc/testsuite/g++.dg/guality/pr46815.C
*************** d27e4ee4f5f5e0db3eac539e5050b624  gcc/te
*** 33070,33075 ****
--- 33105,33112 ----
  d975bcfcc66f10d16ed8c046fec4ba04  gcc/testsuite/g++.dg/modules/adl-10_b.C
  314ee1208d31d73f6b8581612ceea903  gcc/testsuite/g++.dg/modules/adl-11_a.C
  d5e6364be38f2a4bd3ffc35aed9b8edd  gcc/testsuite/g++.dg/modules/adl-11_b.C
+ 098dcbc5ef632f9258da5c6fdbafb2ff  gcc/testsuite/g++.dg/modules/adl-12_a.C
+ 8872836fee2731305f41b19ed42637c2  gcc/testsuite/g++.dg/modules/adl-12_b.C
  9c824c1a28f6bcf79fd72186d79fe93c  gcc/testsuite/g++.dg/modules/adl-1_a.C
  3bb31e23ac383185d41cda2c5fcbdaf3  gcc/testsuite/g++.dg/modules/adl-1_b.C
  46103f57f3287176308fc33634d7da8e  gcc/testsuite/g++.dg/modules/adl-1_c.C
*************** d78c1de0f7d9cac90e50c0208adc2926  gcc/te
*** 33703,33708 ****
--- 33740,33748 ----
  804382f5b6a9cda1fca29fc8024f66a4  gcc/testsuite/g++.dg/modules/lambda-12.h
  f42f3f252e14bfc0ef3c1e93ea73a06d  gcc/testsuite/g++.dg/modules/lambda-12_a.H
  92f393f2dacc1d0ca3a6c8c35172d4a5  gcc/testsuite/g++.dg/modules/lambda-12_b.C
+ b71a8d6fad6407cf6bc8a5ce5b671942  gcc/testsuite/g++.dg/modules/lambda-13.h
+ b74a2e1e96f41ccb9dd0b18848d3fcae  gcc/testsuite/g++.dg/modules/lambda-13_a.H
+ 4ff9a9a90c54534503be44216ba03c64  gcc/testsuite/g++.dg/modules/lambda-13_b.C
  d40eb3b191ce03c71ec885f4126c9c01  gcc/testsuite/g++.dg/modules/lambda-1_a.C
  0c208993fd82c4dab83fb16f53f43099  gcc/testsuite/g++.dg/modules/lambda-1_b.C
  0b364ead1b387b5505e2f7bf2e5dc3b5  gcc/testsuite/g++.dg/modules/lambda-2.h
*************** b02e012e3fe6df1deadb2b6c08aee478  gcc/te
*** 34024,34029 ****
--- 34064,34071 ----
  a9638b26b6321d94457e9e43bed55221  gcc/testsuite/g++.dg/modules/namespace-16_b.C
  373b62f20b7106a4cb635969e59b28c7  gcc/testsuite/g++.dg/modules/namespace-16_c.C
  e28683c6caacdc8a9428c0c5663e47f1  gcc/testsuite/g++.dg/modules/namespace-16_d.C
+ bc491f67c578360461f5270610e8475d  gcc/testsuite/g++.dg/modules/namespace-17_a.C
+ 8c70e4b3a6a0c5b83eaaaed0207b4dbe  gcc/testsuite/g++.dg/modules/namespace-17_b.C
  ebce3d8effe71472ad6b1910c0b435f6  gcc/testsuite/g++.dg/modules/namespace-1_a.C
  c34c17e18223f5c84607e68a5f2dd81a  gcc/testsuite/g++.dg/modules/namespace-1_b.C
  d35b80efe49eb34a9b0c6be1e97ef76a  gcc/testsuite/g++.dg/modules/namespace-1_c.C
*************** c612aa7562a08eee08fd881b3b27fee6  gcc/te
*** 34276,34281 ****
--- 34318,34325 ----
  680ac168b034a19e8070cf8c66cd3edc  gcc/testsuite/g++.dg/modules/pr120040_b.C
  625496a3dbc3dab3e9ee3fd5aa044187  gcc/testsuite/g++.dg/modules/pr122053_a.C
  1b9a9e771ff94ed09a2f483d4eb9b884  gcc/testsuite/g++.dg/modules/pr122053_b.C
+ 2b317cc9d17067098caad41a9ab4b86e  gcc/testsuite/g++.dg/modules/pr122922_a.C
+ acc8849da8a5b2d5ba59c3913e5a6714  gcc/testsuite/g++.dg/modules/pr122922_b.C
  56ba9e2a41b995724a511df79d8df541  gcc/testsuite/g++.dg/modules/pr98531-1.h
  7155fba8679861dc6ac8879b5f49a6eb  gcc/testsuite/g++.dg/modules/pr98531-1_a.H
  db36409e89afb58e627178caf0f3d7d5  gcc/testsuite/g++.dg/modules/pr98531-1_b.C
*************** a0fee4f3ee4678b54afd993b619baa05  gcc/te
*** 36323,36328 ****
--- 36367,36373 ----
  dfa745316c10162491bb418266c2b932  gcc/testsuite/g++.dg/parse/pr116071.C
  732ccde523003692267913067f6a0ccd  gcc/testsuite/g++.dg/parse/pr120471.C
  225e1d7f8cf80186eac35ff37acc9379  gcc/testsuite/g++.dg/parse/pr120940.C
+ 2c83db83aed27c707a2c8d18e73ebfa5  gcc/testsuite/g++.dg/parse/pr121443.C
  2dde7d845edb3fc1b6b06c1f7c1d71f6  gcc/testsuite/g++.dg/parse/pr16696-permissive.C
  f8326578679fecd658e1bec2d3ed7654  gcc/testsuite/g++.dg/parse/pr16696.C
  29f6ba15da1283765b5179abe6707d09  gcc/testsuite/g++.dg/parse/pr18770.C
*************** b393922db8d338bed7f3bcf037edd19c  gcc/te
*** 36568,36574 ****
  3a80079be7a0bfd6f8efce4de8795fcb  gcc/testsuite/g++.dg/plugin/header_plugin.cc
  1c30a8080468929a3cbbc7a4ef384c4c  gcc/testsuite/g++.dg/plugin/location-overflow-test-pr100796.c
  0422777feb5bb202ec0e53d6551fe397  gcc/testsuite/g++.dg/plugin/location-overflow-test-pr96391.c
! 80b793bd64952e9185817f992d47a6dd  gcc/testsuite/g++.dg/plugin/plugin.exp
  0555e81b1b7c9c8e06b4e9d9ffccb7ff  gcc/testsuite/g++.dg/plugin/pragma_plugin-test-1.C
  bb9719af4ef365b9625ed93e9794b8b2  gcc/testsuite/g++.dg/plugin/pragma_plugin.cc
  503f96544096dfaa1ea93338e21923ff  gcc/testsuite/g++.dg/plugin/self-assign-test-1.C
--- 36613,36619 ----
  3a80079be7a0bfd6f8efce4de8795fcb  gcc/testsuite/g++.dg/plugin/header_plugin.cc
  1c30a8080468929a3cbbc7a4ef384c4c  gcc/testsuite/g++.dg/plugin/location-overflow-test-pr100796.c
  0422777feb5bb202ec0e53d6551fe397  gcc/testsuite/g++.dg/plugin/location-overflow-test-pr96391.c
! ea9af60f4e4ad4b64dcc87e40c147ddd  gcc/testsuite/g++.dg/plugin/plugin.exp
  0555e81b1b7c9c8e06b4e9d9ffccb7ff  gcc/testsuite/g++.dg/plugin/pragma_plugin-test-1.C
  bb9719af4ef365b9625ed93e9794b8b2  gcc/testsuite/g++.dg/plugin/pragma_plugin.cc
  503f96544096dfaa1ea93338e21923ff  gcc/testsuite/g++.dg/plugin/self-assign-test-1.C
*************** db994e5b10fcb3e8ba3d62cd17b3ae65  gcc/te
*** 36969,36974 ****
--- 37014,37020 ----
  62aa8921c6705fdab59b10a7be7f39b9  gcc/testsuite/g++.dg/tc1/dr161.C
  3e61e5bdc2b1492780331f39f942586f  gcc/testsuite/g++.dg/tc1/dr164.C
  5825ece278cc051f3204f72abb191317  gcc/testsuite/g++.dg/tc1/dr166.C
+ 18c42ebaf610df10d811e4b47e7ff0d1  gcc/testsuite/g++.dg/tc1/dr176-2.C
  41924759177f1face88bf750afa5a403  gcc/testsuite/g++.dg/tc1/dr176.C
  54a7e43eb51f59e7eae694e23b7ef1f6  gcc/testsuite/g++.dg/tc1/dr179.C
  9704d0caf0975b804de4cf5a0218a1db  gcc/testsuite/g++.dg/tc1/dr185.C
*************** df27fa537f93cbc7c2d2e1f1d60aee3e  gcc/te
*** 37245,37250 ****
--- 37291,37297 ----
  9c6b765ef2765893236204902d1a1e19  gcc/testsuite/g++.dg/template/crash130.C
  89f747766be706a5f5c19c7e4868993b  gcc/testsuite/g++.dg/template/crash131.C
  8295637f711a0ce2e777cc798e8a6d00  gcc/testsuite/g++.dg/template/crash132.C
+ 1a52449e00b05d795dcabb33ba6911e5  gcc/testsuite/g++.dg/template/crash133.C
  7c732ef3b17279bd746eb1196b0d76fe  gcc/testsuite/g++.dg/template/crash14.C
  e50e217f7da35dc497156675b2547e44  gcc/testsuite/g++.dg/template/crash15.C
  0b7b35a94bb1a8a5457b2c3bd299d5e2  gcc/testsuite/g++.dg/template/crash16.C
*************** ecf4a5a96a9a66275db51c43656e4549  gcc/te
*** 37416,37421 ****
--- 37463,37469 ----
  5a8510fe4f107344e120dad60a01d61e  gcc/testsuite/g++.dg/template/dependent-name16.C
  821354ce1318166659eba50d9ae2f7bc  gcc/testsuite/g++.dg/template/dependent-name17.C
  e8a32b9dc0ab464b7f14ed88342967c0  gcc/testsuite/g++.dg/template/dependent-name18.C
+ 95cef29e581db16b7553a10027c170e2  gcc/testsuite/g++.dg/template/dependent-name19.C
  18d61b100652dfe4816b8b9c6cefa923  gcc/testsuite/g++.dg/template/dependent-name2.C
  03c5fb73327b7854a036dd70874ee185  gcc/testsuite/g++.dg/template/dependent-name3.C
  147338e18276d105fca28005404df2a8  gcc/testsuite/g++.dg/template/dependent-name4.C
*************** ae55d6e48a2ac8b72c938dc82c696408  gcc/te
*** 37666,37671 ****
--- 37714,37720 ----
  d5d24fc94d133229a10c5b13f44c253b  gcc/testsuite/g++.dg/template/func1.C
  363cfac4cb9c49757acf9e6f0861b62e  gcc/testsuite/g++.dg/template/func2.C
  bead5f49843ac4a923c8b06419fc1688  gcc/testsuite/g++.dg/template/function1.C
+ afca637314dc606fbc716b5e0d5ae345  gcc/testsuite/g++.dg/template/implicit-func-cast.C
  4b00efc6df70febef975b0e3b186b589  gcc/testsuite/g++.dg/template/incomplete1.C
  6eb242700c6d66d2e369769157f668e1  gcc/testsuite/g++.dg/template/incomplete10.C
  013b3193d7f45f44f8c7e8a4b8e35e24  gcc/testsuite/g++.dg/template/incomplete11.C
*************** c8bd1a4a60ae7b3886c575e82da06256  gcc/te
*** 39556,39562 ****
  b3721c1012726f86c682c19ffbad76a6  gcc/testsuite/g++.dg/tree-ssa/pr41961.C
  f56be237c5b4f819e8b8a838af2ff0dc  gcc/testsuite/g++.dg/tree-ssa/pr42337.C
  e2c24d55a6b2e21cfe1781dded2f3465  gcc/testsuite/g++.dg/tree-ssa/pr43411.C
! 4ae64fe9713a771de3eec6d2ef7baf39  gcc/testsuite/g++.dg/tree-ssa/pr44706.C
  bf024d05ee739cc11776ea4df13e3e55  gcc/testsuite/g++.dg/tree-ssa/pr44914.C
  96a471b3606608b932016a19f1c0ba4f  gcc/testsuite/g++.dg/tree-ssa/pr45453.C
  4cba7d5b509352db7bc78ba73db61313  gcc/testsuite/g++.dg/tree-ssa/pr45605.C
--- 39605,39611 ----
  b3721c1012726f86c682c19ffbad76a6  gcc/testsuite/g++.dg/tree-ssa/pr41961.C
  f56be237c5b4f819e8b8a838af2ff0dc  gcc/testsuite/g++.dg/tree-ssa/pr42337.C
  e2c24d55a6b2e21cfe1781dded2f3465  gcc/testsuite/g++.dg/tree-ssa/pr43411.C
! d662adaafef27c4bdf3fb51359f45842  gcc/testsuite/g++.dg/tree-ssa/pr44706.C
  bf024d05ee739cc11776ea4df13e3e55  gcc/testsuite/g++.dg/tree-ssa/pr44914.C
  96a471b3606608b932016a19f1c0ba4f  gcc/testsuite/g++.dg/tree-ssa/pr45453.C
  4cba7d5b509352db7bc78ba73db61313  gcc/testsuite/g++.dg/tree-ssa/pr45605.C
*************** c0b65a34728bd0641ed11250d156dd96  gcc/te
*** 39598,39604 ****
  33c3ca116bd47b630a440a6f2c7764db  gcc/testsuite/g++.dg/tree-ssa/pr86544.C
  b275e1ed3abd90cc7e8e421e8c6062b9  gcc/testsuite/g++.dg/tree-ssa/pr87008.C
  cfcb017784f2c8d78d4dc8299526d486  gcc/testsuite/g++.dg/tree-ssa/pr87436.C
! cf6d7cf613841934a0f174773729fec8  gcc/testsuite/g++.dg/tree-ssa/pr87502.C
  ea4e143932bfcde8a35c6a9f47ca6cde  gcc/testsuite/g++.dg/tree-ssa/pr87686.C
  3994473d87cf2cf8e4060f87f4631734  gcc/testsuite/g++.dg/tree-ssa/pr8781.C
  34be04a2a8ccec91647967353a92f38e  gcc/testsuite/g++.dg/tree-ssa/pr88152-1.C
--- 39647,39653 ----
  33c3ca116bd47b630a440a6f2c7764db  gcc/testsuite/g++.dg/tree-ssa/pr86544.C
  b275e1ed3abd90cc7e8e421e8c6062b9  gcc/testsuite/g++.dg/tree-ssa/pr87008.C
  cfcb017784f2c8d78d4dc8299526d486  gcc/testsuite/g++.dg/tree-ssa/pr87436.C
! f27d259523b74873b4f896b76c2504a2  gcc/testsuite/g++.dg/tree-ssa/pr87502.C
  ea4e143932bfcde8a35c6a9f47ca6cde  gcc/testsuite/g++.dg/tree-ssa/pr87686.C
  3994473d87cf2cf8e4060f87f4631734  gcc/testsuite/g++.dg/tree-ssa/pr8781.C
  34be04a2a8ccec91647967353a92f38e  gcc/testsuite/g++.dg/tree-ssa/pr88152-1.C
*************** f9ec9f29d29198d0fd2269ad44e55b21  gcc/te
*** 39873,39879 ****
  4665de842fe7961eed5fad345695a420  gcc/testsuite/g++.dg/vect/pr60836.cc
  b7b79e1c6424f4373d8f860593191fd9  gcc/testsuite/g++.dg/vect/pr60896.cc
  2de94c5a0cf4dc2ff2b7fb5f335afddf  gcc/testsuite/g++.dg/vect/pr61171.cc
! f337bf9b50a3e9afde5e4eb20ff26984  gcc/testsuite/g++.dg/vect/pr64410.cc
  13783ab06d92e72061bad5e947c2f942  gcc/testsuite/g++.dg/vect/pr68145.cc
  6600a6f2c35c0e029bfea60c0a597d46  gcc/testsuite/g++.dg/vect/pr68762-1.cc
  5c7fd9083bc5eecf88828a3e8041163f  gcc/testsuite/g++.dg/vect/pr68762-2.cc
--- 39922,39928 ----
  4665de842fe7961eed5fad345695a420  gcc/testsuite/g++.dg/vect/pr60836.cc
  b7b79e1c6424f4373d8f860593191fd9  gcc/testsuite/g++.dg/vect/pr60896.cc
  2de94c5a0cf4dc2ff2b7fb5f335afddf  gcc/testsuite/g++.dg/vect/pr61171.cc
! f63b1efc785b49e934e34e56b6127db9  gcc/testsuite/g++.dg/vect/pr64410.cc
  13783ab06d92e72061bad5e947c2f942  gcc/testsuite/g++.dg/vect/pr68145.cc
  6600a6f2c35c0e029bfea60c0a597d46  gcc/testsuite/g++.dg/vect/pr68762-1.cc
  5c7fd9083bc5eecf88828a3e8041163f  gcc/testsuite/g++.dg/vect/pr68762-2.cc
*************** bb04402a5286da0c2b2bd970e15a7c0a  gcc/te
*** 39944,39949 ****
--- 39993,39999 ----
  7509f0d1c7df2744d657804a467cd882  gcc/testsuite/g++.dg/vect/vect-early-break_6.cc
  750c3d825061bd1ca9b4587c0081a7aa  gcc/testsuite/g++.dg/vect/vect-novector-pragma.cc
  c9f2a8124f076b5bb673e6fab2b06069  gcc/testsuite/g++.dg/vect/vect-novector-pragma_2.cc
+ 0a23130ea4ce46e0a0236cd4d6c8e7fa  gcc/testsuite/g++.dg/vect/vect-uncounted-prolog-peel_1.cc
  f8c767a314721a1883abbb6a43baf1b2  gcc/testsuite/g++.dg/vect/vect.exp
  71d10a285587bb46cc1bf1ab339fa743  gcc/testsuite/g++.dg/warn/83895.C
  daeef1989c46da48d17102900d28c0c7  gcc/testsuite/g++.dg/warn/Waddress-1.C
*************** bc255ba4628b94d5377f0ba915ad26da  gcc/te
*** 44559,44565 ****
  c3abd0fb44ca490064aaa6988814d40c  gcc/testsuite/g++.target/i386/mv26.C
  203c2fb05767e713a362682a2dcedfc7  gcc/testsuite/g++.target/i386/mv27.C
  40932b515fb9f24850535ab3021f3da7  gcc/testsuite/g++.target/i386/mv28.C
! f1dcd0f047238a664c71844662594d0b  gcc/testsuite/g++.target/i386/mv29.C
  bad9a677892adffe2c45653797aad55c  gcc/testsuite/g++.target/i386/mv3.C
  8e16cb4ef8b3ee3b728e21112c7331d1  gcc/testsuite/g++.target/i386/mv30.C
  6c2437562ef96defbdcf21aa49f5676f  gcc/testsuite/g++.target/i386/mv31.C
--- 44609,44615 ----
  c3abd0fb44ca490064aaa6988814d40c  gcc/testsuite/g++.target/i386/mv26.C
  203c2fb05767e713a362682a2dcedfc7  gcc/testsuite/g++.target/i386/mv27.C
  40932b515fb9f24850535ab3021f3da7  gcc/testsuite/g++.target/i386/mv28.C
! 564e257b536db045b9bce6baaf544c40  gcc/testsuite/g++.target/i386/mv29.C
  bad9a677892adffe2c45653797aad55c  gcc/testsuite/g++.target/i386/mv3.C
  8e16cb4ef8b3ee3b728e21112c7331d1  gcc/testsuite/g++.target/i386/mv30.C
  6c2437562ef96defbdcf21aa49f5676f  gcc/testsuite/g++.target/i386/mv31.C
*************** bbffb78a05c981886c82c4d7bb1ab46a  gcc/te
*** 44923,44928 ****
--- 44973,44979 ----
  65e822c3566d2be95d4e4a1852d2d11e  gcc/testsuite/g++.target/riscv/rvv/autovec/pr119547-2.C
  e0fcda19753adb81a996dcb37c1e40f0  gcc/testsuite/g++.target/riscv/rvv/autovec/pr119547.C
  5cf8aba8614b6e7a77dd44f21cedac0c  gcc/testsuite/g++.target/riscv/rvv/autovec/pr123074.C
+ 81a8396006a903276bfc03dd5c96149c  gcc/testsuite/g++.target/riscv/rvv/autovec/pr123118.C
  b073f099736b28c243e723ac86cb8fd5  gcc/testsuite/g++.target/riscv/rvv/base/attribute-riscv_vector_cc-error.C
  1b1bc5039f56e1bab95c9773c435167c  gcc/testsuite/g++.target/riscv/rvv/base/bug-1.C
  23e072f75d6f4f14b994051bd34559a4  gcc/testsuite/g++.target/riscv/rvv/base/bug-10.C
*************** dde91892495d17ce2df23f544a2d14fa  gcc/te
*** 44978,44983 ****
--- 45029,45041 ----
  c0aa169f53b6c831c9c42b449fec63b6  gcc/testsuite/g++.target/s390/pr98722.C
  c203475d88ea00f74316e4db91a6246f  gcc/testsuite/g++.target/s390/s390.exp
  9ff1a8d8d1c6f294a317244992dec97a  gcc/testsuite/g++.target/s390/zvec-templ-1.C
+ 7d3dd8d322ab121279faa522704e7392  gcc/testsuite/g++.target/sh/sh.exp
+ 09b8b53ce09543cb0dc494095977eb30  gcc/testsuite/g++.target/sh/torture/pr55212-c311.C
+ c459a9b755a4a6fec4beda7e103a9a34  gcc/testsuite/g++.target/sh/torture/pr55212-c333.C
+ 4c6c9e7f4529efcc8e887f067527d612  gcc/testsuite/g++.target/sh/torture/pr55212-c373.C
+ 74ee7729e1f98918660311f23db5e309  gcc/testsuite/g++.target/sh/torture/pr55212-c384.C
+ 810cbbd931332a2875c95ba17d0d4166  gcc/testsuite/g++.target/sh/torture/pr55212-c413.C
+ 67850126fe778b1c30113ae26cf68c45  gcc/testsuite/g++.target/sh/torture/sh-torture.exp
  9ec75dfed03d43e4480e98ac02f604a7  gcc/testsuite/g++.target/xtensa/pr95571.C
  eb2628e873513195d3a2fe71344ac7d4  gcc/testsuite/g++.target/xtensa/xtensa.exp
  ab411a7e60cfec57473a2cab3ecc3197  gcc/testsuite/gcc.c-torture/ChangeLog.0
*************** d95d3791be79edb41b4192d2696815fb  gcc/te
*** 45185,45191 ****
  f6669c2a749498d487e22ebfc2435eba  gcc/testsuite/gcc.c-torture/compile/20030314-1.c
  04a8a9f37c8348589a3110b86c07ae26  gcc/testsuite/gcc.c-torture/compile/20030319-1.c
  636afeca97e7bba8823cca3efc1e7df1  gcc/testsuite/gcc.c-torture/compile/20030320-1.c
! 94d7088d3f5f8a2ae799c04f964efbfe  gcc/testsuite/gcc.c-torture/compile/20030323-1.c
  73bf3aed397c6b3c6218590a3f60d762  gcc/testsuite/gcc.c-torture/compile/20030330-1.c
  6948cd26b8e708cff8d37323f927fb52  gcc/testsuite/gcc.c-torture/compile/20030331-1.c
  57016aeddadea6003ad54539984737c9  gcc/testsuite/gcc.c-torture/compile/20030405-1.c
--- 45243,45249 ----
  f6669c2a749498d487e22ebfc2435eba  gcc/testsuite/gcc.c-torture/compile/20030314-1.c
  04a8a9f37c8348589a3110b86c07ae26  gcc/testsuite/gcc.c-torture/compile/20030319-1.c
  636afeca97e7bba8823cca3efc1e7df1  gcc/testsuite/gcc.c-torture/compile/20030320-1.c
! e75539741e2053ff92f3de72c1e88753  gcc/testsuite/gcc.c-torture/compile/20030323-1.c
  73bf3aed397c6b3c6218590a3f60d762  gcc/testsuite/gcc.c-torture/compile/20030330-1.c
  6948cd26b8e708cff8d37323f927fb52  gcc/testsuite/gcc.c-torture/compile/20030331-1.c
  57016aeddadea6003ad54539984737c9  gcc/testsuite/gcc.c-torture/compile/20030405-1.c
*************** c14634a323696079f49ec83c65002f01  gcc/te
*** 54647,54653 ****
  98dbbd197e8c7c832cd21e157df3bf0e  gcc/testsuite/gcc.dg/gomp/sink-fold-1.c
  30b3501cdbf4af67a36f7003998e9d4b  gcc/testsuite/gcc.dg/gomp/sink-fold-2.c
  606fbcb4bc3e953e4f15ee070118b30f  gcc/testsuite/gcc.dg/gomp/sink-fold-3.c
! 2c7c35d918725944cf4998bb474f579d  gcc/testsuite/gcc.dg/gomp/static-chunk-size-one.c
  871d2afbf0f76e5d008f733eaf14a059  gcc/testsuite/gcc.dg/gomp/static.c
  0e4b88bcdaea3e0ec538494446e27cde  gcc/testsuite/gcc.dg/gomp/target-1.c
  3dbda1e12ff1651f658704d415f7e84f  gcc/testsuite/gcc.dg/gomp/target-2.c
--- 54705,54711 ----
  98dbbd197e8c7c832cd21e157df3bf0e  gcc/testsuite/gcc.dg/gomp/sink-fold-1.c
  30b3501cdbf4af67a36f7003998e9d4b  gcc/testsuite/gcc.dg/gomp/sink-fold-2.c
  606fbcb4bc3e953e4f15ee070118b30f  gcc/testsuite/gcc.dg/gomp/sink-fold-3.c
! 70a7ec49c02ac39036b5861d1f2c0e08  gcc/testsuite/gcc.dg/gomp/static-chunk-size-one.c
  871d2afbf0f76e5d008f733eaf14a059  gcc/testsuite/gcc.dg/gomp/static.c
  0e4b88bcdaea3e0ec538494446e27cde  gcc/testsuite/gcc.dg/gomp/target-1.c
  3dbda1e12ff1651f658704d415f7e84f  gcc/testsuite/gcc.dg/gomp/target-2.c
*************** e22501e605edeaceeca043b437e49ba9  gcc/te
*** 55826,55831 ****
--- 55884,55895 ----
  1ed435f0f8bee4556b01e24c97ab41e3  gcc/testsuite/gcc.dg/lto/const-uniq_1.c
  b915a8da2759e8acfd7b4a5ed6628ee2  gcc/testsuite/gcc.dg/lto/embed-1_0.c
  099276feaa888c7fa8e834f941a656eb  gcc/testsuite/gcc.dg/lto/embed-1_1.c
+ 0ab1d9c12b11fc29d938c6ffbab9e60e  gcc/testsuite/gcc.dg/lto/fnptr-from-rec-1_0.c
+ 1489831d6f8e66aea79da990281b193c  gcc/testsuite/gcc.dg/lto/fnptr-from-rec-1_1.c
+ 312850ddd7ea136e88525e0962088c11  gcc/testsuite/gcc.dg/lto/fnptr-from-rec-2_0.c
+ 1cf11d42f9ca42a298e97a28c243bf75  gcc/testsuite/gcc.dg/lto/fnptr-from-rec-2_1.c
+ 312850ddd7ea136e88525e0962088c11  gcc/testsuite/gcc.dg/lto/fnptr-from-rec-3_0.c
+ 1489831d6f8e66aea79da990281b193c  gcc/testsuite/gcc.dg/lto/fnptr-from-rec-3_1.c
  9832f2325d13caa677963d6a73562014  gcc/testsuite/gcc.dg/lto/ipacp_0.c
  978da60d3a01b7ce53a5f8b06a2813e9  gcc/testsuite/gcc.dg/lto/ipacp_1.c
  2250fbcaea4453970ef7ce141192bd68  gcc/testsuite/gcc.dg/lto/ipareference2_0.c
*************** c8b296cff91e0dc2cbddba1d03bda22e  gcc/te
*** 56512,56522 ****
  40152da94873a453612f018f2bedc6b9  gcc/testsuite/gcc.dg/plugin/crash-test-nested-ice-html.py
  8ce7b57d4e70274d3fc06b4026c725ce  gcc/testsuite/gcc.dg/plugin/crash-test-nested-ice-sarif.py
  33fa37cd40332b2344cccbffd9acb4dd  gcc/testsuite/gcc.dg/plugin/crash-test-nested-ice.c
! 0ee119ef6c937ffd206dc1516e9ecc13  gcc/testsuite/gcc.dg/plugin/crash-test-nested-write-through-null-html.py
! ea222b1a587131420a80aa2065e9b799  gcc/testsuite/gcc.dg/plugin/crash-test-nested-write-through-null-sarif.py
  291db98b71fd518cee0fe121d4d9bb47  gcc/testsuite/gcc.dg/plugin/crash-test-nested-write-through-null.c
  3333d94ad6aeaef96f8f360fbb86bc40  gcc/testsuite/gcc.dg/plugin/crash-test-write-through-null-sarif.c
! 6a8964ce93ffc0bd30309c60194183b2  gcc/testsuite/gcc.dg/plugin/crash-test-write-through-null-stderr.c
  fe8b11287b636cbc97d256fbd9ee7e9f  gcc/testsuite/gcc.dg/plugin/crash_test_plugin.cc
  146ffa25d8a6444346ca2a51bfa748ec  gcc/testsuite/gcc.dg/plugin/diagnostic-group-test-1.c
  901114feb3fc4bc44a06034fc6abcbff  gcc/testsuite/gcc.dg/plugin/diagnostic-path-format-inline-events-1.c
--- 56576,56586 ----
  40152da94873a453612f018f2bedc6b9  gcc/testsuite/gcc.dg/plugin/crash-test-nested-ice-html.py
  8ce7b57d4e70274d3fc06b4026c725ce  gcc/testsuite/gcc.dg/plugin/crash-test-nested-ice-sarif.py
  33fa37cd40332b2344cccbffd9acb4dd  gcc/testsuite/gcc.dg/plugin/crash-test-nested-ice.c
! b7781bc13218fe0a7931b8b94cbf228c  gcc/testsuite/gcc.dg/plugin/crash-test-nested-write-through-null-html.py
! 2c8b4656128d7c3ae223e746068e8df9  gcc/testsuite/gcc.dg/plugin/crash-test-nested-write-through-null-sarif.py
  291db98b71fd518cee0fe121d4d9bb47  gcc/testsuite/gcc.dg/plugin/crash-test-nested-write-through-null.c
  3333d94ad6aeaef96f8f360fbb86bc40  gcc/testsuite/gcc.dg/plugin/crash-test-write-through-null-sarif.c
! 378954d104a4557a5b27e3e39c3de042  gcc/testsuite/gcc.dg/plugin/crash-test-write-through-null-stderr.c
  fe8b11287b636cbc97d256fbd9ee7e9f  gcc/testsuite/gcc.dg/plugin/crash_test_plugin.cc
  146ffa25d8a6444346ca2a51bfa748ec  gcc/testsuite/gcc.dg/plugin/diagnostic-group-test-1.c
  901114feb3fc4bc44a06034fc6abcbff  gcc/testsuite/gcc.dg/plugin/diagnostic-path-format-inline-events-1.c
*************** ab9b438d79da41ae2faa25073b1f68ff  gcc/te
*** 56526,56532 ****
  2fe90d668bb3a5c6c5bf999732d4ba2f  gcc/testsuite/gcc.dg/plugin/diagnostic-path-format-plain.c
  703aa583a7e531e21f36720dc5060a1a  gcc/testsuite/gcc.dg/plugin/diagnostic-path-format-separate-events.c
  82d440b1e4dce5930ce8d0eb753b41e8  gcc/testsuite/gcc.dg/plugin/diagnostic-test-expressions-1.c
! f26f1bf96796d8b24031806c06a0f052  gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-html.c
  8e3f36ccd34f3a01727845d526a29ee6  gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-html.py
  9fd38029a33519cf7e44d1f8653aa738  gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-sarif.c
  c9a71bb22094924ec0c655c680eae543  gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-sarif.py
--- 56590,56596 ----
  2fe90d668bb3a5c6c5bf999732d4ba2f  gcc/testsuite/gcc.dg/plugin/diagnostic-path-format-plain.c
  703aa583a7e531e21f36720dc5060a1a  gcc/testsuite/gcc.dg/plugin/diagnostic-path-format-separate-events.c
  82d440b1e4dce5930ce8d0eb753b41e8  gcc/testsuite/gcc.dg/plugin/diagnostic-test-expressions-1.c
! 732465885728f1f8db010bcdc04dd064  gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-html.c
  8e3f36ccd34f3a01727845d526a29ee6  gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-html.py
  9fd38029a33519cf7e44d1f8653aa738  gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-sarif.c
  c9a71bb22094924ec0c655c680eae543  gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-sarif.py
*************** c323b7b4ac0cf2caa641c6bb31350375  gcc/te
*** 56638,56644 ****
  4905199fc259967af414db22821f7f74  gcc/testsuite/gcc.dg/plugin/must_tail_call_plugin.cc
  adbc6d60d6e1474ca93af3b50208e741  gcc/testsuite/gcc.dg/plugin/one_time-test-1.c
  91500c30c78de7048ecb72b86a431e80  gcc/testsuite/gcc.dg/plugin/one_time_plugin.cc
! f43efd994d1489bf776959c6d00930fd  gcc/testsuite/gcc.dg/plugin/plugin.exp
  10b87cc378ff8b6e30ae77af8c669e4b  gcc/testsuite/gcc.dg/plugin/plugindir1.c
  770fbe5bf2a65884c6120dab4b13a1d4  gcc/testsuite/gcc.dg/plugin/plugindir2.c
  5be673fb13573d3689c3cc3dff9f5a2e  gcc/testsuite/gcc.dg/plugin/plugindir3.c
--- 56702,56708 ----
  4905199fc259967af414db22821f7f74  gcc/testsuite/gcc.dg/plugin/must_tail_call_plugin.cc
  adbc6d60d6e1474ca93af3b50208e741  gcc/testsuite/gcc.dg/plugin/one_time-test-1.c
  91500c30c78de7048ecb72b86a431e80  gcc/testsuite/gcc.dg/plugin/one_time_plugin.cc
! ae6c6cb77186900e60cc779b737b947f  gcc/testsuite/gcc.dg/plugin/plugin.exp
  10b87cc378ff8b6e30ae77af8c669e4b  gcc/testsuite/gcc.dg/plugin/plugindir1.c
  770fbe5bf2a65884c6120dab4b13a1d4  gcc/testsuite/gcc.dg/plugin/plugindir2.c
  5be673fb13573d3689c3cc3dff9f5a2e  gcc/testsuite/gcc.dg/plugin/plugindir3.c
*************** bf675da3de2d4a46664269703dd05797  gcc/te
*** 57359,57370 ****
--- 57423,57437 ----
  3675df2622072bf0e5cccbf94e93a50f  gcc/testsuite/gcc.dg/pr122126_vextr.c
  b975ebfa27ac446e553bacbb75421590  gcc/testsuite/gcc.dg/pr122126_vset.c
  ea90b28181a941740c845e0095310a27  gcc/testsuite/gcc.dg/pr122200.c
+ 47e5eee5a7b9e8a561523488f8af584f  gcc/testsuite/gcc.dg/pr122343-1.c
  afbbdc9160c7bbb463b8a9a0ccecc1ec  gcc/testsuite/gcc.dg/pr122756.c
  6f902818ec608b0949c72df134c134a3  gcc/testsuite/gcc.dg/pr122773.c
  7344e7d40edaaaf0a7feba4fc50f3e85  gcc/testsuite/gcc.dg/pr122898.c
  acdecc3711a0a56635d3de4e2064206c  gcc/testsuite/gcc.dg/pr122947.c
  9f4094b7196b5eab8c79608995a96efc  gcc/testsuite/gcc.dg/pr122991.c
  9fcb8913b9a18055b2a811284d59780e  gcc/testsuite/gcc.dg/pr123018.c
+ 4bb95b7b27d5cf33c1f6f21056e27c11  gcc/testsuite/gcc.dg/pr123110-1.c
+ a7854fc3636527bc932319df4a19bc42  gcc/testsuite/gcc.dg/pr123205.c
  bc5ddfbbc46f4e0cce1629d1b58d3090  gcc/testsuite/gcc.dg/pr12603.c
  72a2fca76cb69617ae36bab93c7ec0d7  gcc/testsuite/gcc.dg/pr12625-1.c
  6f0ef61e5a12db5f11da839b2988c5e1  gcc/testsuite/gcc.dg/pr13519-1.c
*************** b465b03e50a5f0e6eb3f4fc778cae87c  gcc/te
*** 60478,60483 ****
--- 60545,60551 ----
  c1b87db2a9e9bd9b79aeb89e694fd159  gcc/testsuite/gcc.dg/torture/builtin-round-roundevenf128.c
  9e1b5d427790f2b01d5620a8b551a56a  gcc/testsuite/gcc.dg/torture/builtin-rounding-1.c
  e09f1e946db0ab1dc4d3acd77ea2b116  gcc/testsuite/gcc.dg/torture/builtin-self.c
+ ca574b7eaab84272d7e1576d29f284bc  gcc/testsuite/gcc.dg/torture/builtin-shufflevector-pr123156.c
  fe01d458fb1e7b307aca4d27de62eff0  gcc/testsuite/gcc.dg/torture/builtin-sin-mpfr-1.c
  8d42dae4813a5c391a3481a72ac9c577  gcc/testsuite/gcc.dg/torture/builtin-sprintf.c
  23e1ea0bdd97005c1b4f8564d23f2b6a  gcc/testsuite/gcc.dg/torture/builtin-sqrt-cmp-1.c
*************** f337209daba5d33fb4d0b55313bfde9e  gcc/te
*** 62807,62812 ****
--- 62875,62881 ----
  bc009876b7c6d6631a4147b81b3e22f8  gcc/testsuite/gcc.dg/tree-ssa/copy-headers-10.c
  8fd4daab6dbf8eb1cfcd8fd48f789cbb  gcc/testsuite/gcc.dg/tree-ssa/copy-headers-11.c
  278320fc185c5d86fc66245701a90aa2  gcc/testsuite/gcc.dg/tree-ssa/copy-headers-12.c
+ e0f2db853fca999c02cdf79ba1194a7a  gcc/testsuite/gcc.dg/tree-ssa/copy-headers-13.c
  0cf82fedd0523d48a3c11ee74277d669  gcc/testsuite/gcc.dg/tree-ssa/copy-headers-2.c
  363d3e4ac12b479eddce56ba34c2afd4  gcc/testsuite/gcc.dg/tree-ssa/copy-headers-3.c
  a0f533cf1734bcf6ffb5fc5a84378862  gcc/testsuite/gcc.dg/tree-ssa/copy-headers-4.c
*************** b51831242139a92b34dbcd60cebb1cd5  gcc/te
*** 62841,62847 ****
  67d0a347d377cdd5876ed6d3ffc4103b  gcc/testsuite/gcc.dg/tree-ssa/cswtch-6.c
  a7ee922e30693d72b161287620162cc4  gcc/testsuite/gcc.dg/tree-ssa/cswtch-7.c
  59e69728c798843be3e7e01a41019422  gcc/testsuite/gcc.dg/tree-ssa/cswtch.c
! d828b3c3b47559f668395b6499bae8f7  gcc/testsuite/gcc.dg/tree-ssa/ctz-ch.c
  0c2e8b89d38d92078d06d1cdf2afb596  gcc/testsuite/gcc.dg/tree-ssa/ctz-char.c
  dcd8e98ed7d206d39eae19ea623d2985  gcc/testsuite/gcc.dg/tree-ssa/ctz-complement-char.c
  8040629cefe8139efef7e9b6c12bd92c  gcc/testsuite/gcc.dg/tree-ssa/ctz-complement-int.c
--- 62910,62916 ----
  67d0a347d377cdd5876ed6d3ffc4103b  gcc/testsuite/gcc.dg/tree-ssa/cswtch-6.c
  a7ee922e30693d72b161287620162cc4  gcc/testsuite/gcc.dg/tree-ssa/cswtch-7.c
  59e69728c798843be3e7e01a41019422  gcc/testsuite/gcc.dg/tree-ssa/cswtch.c
! 5240ca6fda47d5773cd7adbd74043508  gcc/testsuite/gcc.dg/tree-ssa/ctz-ch.c
  0c2e8b89d38d92078d06d1cdf2afb596  gcc/testsuite/gcc.dg/tree-ssa/ctz-char.c
  dcd8e98ed7d206d39eae19ea623d2985  gcc/testsuite/gcc.dg/tree-ssa/ctz-complement-char.c
  8040629cefe8139efef7e9b6c12bd92c  gcc/testsuite/gcc.dg/tree-ssa/ctz-complement-int.c
*************** a0647084804b90be3e8bdad82c7777a9  gcc/te
*** 64093,64100 ****
  a73a95372785101c5f4de5e36a62d6a1  gcc/testsuite/gcc.dg/tree-ssa/pr96688.c
  70188bafba9d185995a25fd8835ab428  gcc/testsuite/gcc.dg/tree-ssa/pr96691.c
  7b531ae0c6a470cf7a1f01a121524cb9  gcc/testsuite/gcc.dg/tree-ssa/pr96730.c
! daeb1c528ad4784407e7da4fe6db99d8  gcc/testsuite/gcc.dg/tree-ssa/pr96779-disabled.c
! 9522287958089c6c057c70702b091d11  gcc/testsuite/gcc.dg/tree-ssa/pr96779.c
  83c579881e1867fc68ce84f7d2d6c782  gcc/testsuite/gcc.dg/tree-ssa/pr96782.c
  f1814d9f48268164f5abca2ef9ff90f6  gcc/testsuite/gcc.dg/tree-ssa/pr96789.c
  7ce01d5539f42257afefbfc03dd79f4c  gcc/testsuite/gcc.dg/tree-ssa/pr96820.c
--- 64162,64169 ----
  a73a95372785101c5f4de5e36a62d6a1  gcc/testsuite/gcc.dg/tree-ssa/pr96688.c
  70188bafba9d185995a25fd8835ab428  gcc/testsuite/gcc.dg/tree-ssa/pr96691.c
  7b531ae0c6a470cf7a1f01a121524cb9  gcc/testsuite/gcc.dg/tree-ssa/pr96730.c
! d84bc61aefb899c22f593c599c43b132  gcc/testsuite/gcc.dg/tree-ssa/pr96779-disabled.c
! 254df303cd938801df3b3fc71576613b  gcc/testsuite/gcc.dg/tree-ssa/pr96779.c
  83c579881e1867fc68ce84f7d2d6c782  gcc/testsuite/gcc.dg/tree-ssa/pr96782.c
  f1814d9f48268164f5abca2ef9ff90f6  gcc/testsuite/gcc.dg/tree-ssa/pr96789.c
  7ce01d5539f42257afefbfc03dd79f4c  gcc/testsuite/gcc.dg/tree-ssa/pr96820.c
*************** f8d79acf16a7b0f25c65f787eb80a4f0  gcc/te
*** 64706,64712 ****
  639917ac728fb50216b5d641326a2d4e  gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-13.c
  2d2a4c5d9176f15e6d84e8b7ebd76656  gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-14.c
  d27e19cbc74977f6d1e4eb7b508acbd2  gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-15.c
! 97654a0ac48e6a645068fcebe3d8d8ed  gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-16.c
  7b67e9ddb035d2cd169ccd1452a8d47a  gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-17.c
  054da81e5ac60be0a91010d71ddf9ee8  gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-18.c
  4b0f41e665ea108724b1c5c7fc582cd4  gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-19.c
--- 64775,64781 ----
  639917ac728fb50216b5d641326a2d4e  gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-13.c
  2d2a4c5d9176f15e6d84e8b7ebd76656  gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-14.c
  d27e19cbc74977f6d1e4eb7b508acbd2  gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-15.c
! eba056f8fdfc01dd50d19a42ad34bd50  gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-16.c
  7b67e9ddb035d2cd169ccd1452a8d47a  gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-17.c
  054da81e5ac60be0a91010d71ddf9ee8  gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-18.c
  4b0f41e665ea108724b1c5c7fc582cd4  gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-19.c
*************** d2b36be7e59029cef1dd2fecf866de62  gcc/te
*** 66039,66045 ****
--- 66108,66116 ----
  72763d9273f88d0ae6d2adb1c7239efb  gcc/testsuite/gcc.dg/vect/pr122850.c
  ae7dd7b535828dd877ea453ce08b1b4b  gcc/testsuite/gcc.dg/vect/pr122855.c
  13a0e19b576c184d6a3d2a5e046b1d77  gcc/testsuite/gcc.dg/vect/pr122969.c
+ 1e57bd875cece14e0d06e2d617c8ef1c  gcc/testsuite/gcc.dg/vect/pr123032.c
  1a89666cdf0f2352dc6a3b60a35d5526  gcc/testsuite/gcc.dg/vect/pr123038.c
+ 2838d9516eba265f0e0975f689ddd518  gcc/testsuite/gcc.dg/vect/pr123043.c
  42d48d2ecd5682545b12ac42f879a831  gcc/testsuite/gcc.dg/vect/pr16105.c
  231c99dba9475fe09525bbf6f4374124  gcc/testsuite/gcc.dg/vect/pr18308.c
  915cf38408eaa7fee5013d90ec1c3251  gcc/testsuite/gcc.dg/vect/pr18400.c
*************** b14a7c563931d32378d5a7c177b4a9c9  gcc/te
*** 67066,67071 ****
--- 67137,67143 ----
  fca55cf03db9d8a5e743486b3427a96a  gcc/testsuite/gcc.dg/vect/vect-early-break_140-pr122868_2.c
  8cbd75311a4ecc168ec09085f538c7d0  gcc/testsuite/gcc.dg/vect/vect-early-break_140-pr122868_3.c
  25d4d94bafb1405becf55cc15f94275e  gcc/testsuite/gcc.dg/vect/vect-early-break_140-pr122868_4.c
+ e3f3a36d35d6f9ef525a93d5cb0eb94b  gcc/testsuite/gcc.dg/vect/vect-early-break_141-pr123089.c
  e90473e2ecf7c08db9278bdca5060773  gcc/testsuite/gcc.dg/vect/vect-early-break_15.c
  2232d395ceff11af9b28f269e86162c9  gcc/testsuite/gcc.dg/vect/vect-early-break_16.c
  74848a5e9be64a5356628885f52c286b  gcc/testsuite/gcc.dg/vect/vect-early-break_17.c
*************** c6478ec076451d018cdfd7229ea3d987  gcc/te
*** 67094,67100 ****
  b1864d1f0bb0845c92996f95385d7864  gcc/testsuite/gcc.dg/vect/vect-early-break_38.c
  424b5dbc3b606e03269242101abc0ee2  gcc/testsuite/gcc.dg/vect/vect-early-break_39.c
  b79992b539b9fdd81c73ef95ccc8a698  gcc/testsuite/gcc.dg/vect/vect-early-break_4.c
! 7761ce13a32a18b3ec7db110a8b90cbd  gcc/testsuite/gcc.dg/vect/vect-early-break_40.c
  558c156f60ccffa54575ac120eab374f  gcc/testsuite/gcc.dg/vect/vect-early-break_41.c
  c66141b356f45606226340093d65e0d4  gcc/testsuite/gcc.dg/vect/vect-early-break_42.c
  1ea872bfccc024b55547efc2ab3829b2  gcc/testsuite/gcc.dg/vect/vect-early-break_43.c
--- 67166,67172 ----
  b1864d1f0bb0845c92996f95385d7864  gcc/testsuite/gcc.dg/vect/vect-early-break_38.c
  424b5dbc3b606e03269242101abc0ee2  gcc/testsuite/gcc.dg/vect/vect-early-break_39.c
  b79992b539b9fdd81c73ef95ccc8a698  gcc/testsuite/gcc.dg/vect/vect-early-break_4.c
! 771e96a4b1ae42e4ef83ce5c66faeb50  gcc/testsuite/gcc.dg/vect/vect-early-break_40.c
  558c156f60ccffa54575ac120eab374f  gcc/testsuite/gcc.dg/vect/vect-early-break_41.c
  c66141b356f45606226340093d65e0d4  gcc/testsuite/gcc.dg/vect/vect-early-break_42.c
  1ea872bfccc024b55547efc2ab3829b2  gcc/testsuite/gcc.dg/vect/vect-early-break_43.c
*************** dacaab2848ce0cac26021e40c45f6986  gcc/te
*** 67623,67628 ****
--- 67695,67713 ----
  aedea3f0c7c434dce657bf63c5b4c1cf  gcc/testsuite/gcc.dg/vect/vect-switch-ifcvt-3.c
  591202848a360199c23468d3d402f59b  gcc/testsuite/gcc.dg/vect/vect-switch-search-line-fast.c
  f353f9ae20bcced6cafb958f09ad8305  gcc/testsuite/gcc.dg/vect/vect-tail-nomask-1.c
+ db073e8e46c5bf7927a443b0eee7bbbf  gcc/testsuite/gcc.dg/vect/vect-uncounted-prolog-peel_1.c
+ 952c8d08bf0fae0e83edc26c4d666f20  gcc/testsuite/gcc.dg/vect/vect-uncounted-prolog-peel_2.c
+ 7091041c74f71a2afd6b43e0c0571928  gcc/testsuite/gcc.dg/vect/vect-uncounted-prolog-peel_3.c
+ b0e70e0f2ffd2196553b00c59f02bed8  gcc/testsuite/gcc.dg/vect/vect-uncounted-run_1.c
+ 21d2a8bb2b8e06944ff1ead18bb38991  gcc/testsuite/gcc.dg/vect/vect-uncounted-run_2.c
+ 75296732077eb3f522d929ebfeab87f1  gcc/testsuite/gcc.dg/vect/vect-uncounted-run_3.c
+ e272c1df119c914b1c664282d40591b6  gcc/testsuite/gcc.dg/vect/vect-uncounted_1.c
+ 99b9cb6bbf68684a1596f785900aafae  gcc/testsuite/gcc.dg/vect/vect-uncounted_2.c
+ 23ed0940ec35af12b6c3324bf81398ff  gcc/testsuite/gcc.dg/vect/vect-uncounted_3.c
+ c5dc885a4fd607cf61e6a4a5532975c8  gcc/testsuite/gcc.dg/vect/vect-uncounted_4.c
+ e055b43566f39136325b4d4c24a4d8e7  gcc/testsuite/gcc.dg/vect/vect-uncounted_5.c
+ 3c8aa56df5d4e35482f5b5128e67bad1  gcc/testsuite/gcc.dg/vect/vect-uncounted_6.c
+ 88d43b547e698a4c9a0d5f961e56dfdc  gcc/testsuite/gcc.dg/vect/vect-uncounted_7.c
  77c1344d6e99c9bf6c4f1170c256d122  gcc/testsuite/gcc.dg/vect/vect-version-1.c
  b4f31e51d7444b0dbc43aff2dc3d5426  gcc/testsuite/gcc.dg/vect/vect-version-2.c
  6bf67c113cd4d93ff129dbdce29b1131  gcc/testsuite/gcc.dg/vect/vect-vfa-01.c
*************** b78a4169933a9354d9c9f02a41a28212  gcc/te
*** 68292,68298 ****
  c2eae4877980c06eaa23ea8db426a5c1  gcc/testsuite/gcc.target/aarch64/acle/ls64_st64bv0-3.c
  a9efd5e0ebc228f128308006c2db9c2b  gcc/testsuite/gcc.target/aarch64/acle/ls64_st64bv0.c
  bbcc298547eb556312f83b765ff6baef  gcc/testsuite/gcc.target/aarch64/acle/ls64_strict_align.c
! ff3a09d9afde293ac1598cb7530ead9d  gcc/testsuite/gcc.target/aarch64/acle/memtag_1.c
  42f386dac12d330a687e58d7027f0c47  gcc/testsuite/gcc.target/aarch64/acle/memtag_2.c
  dad27dd9a8b076099818ec56a74ef781  gcc/testsuite/gcc.target/aarch64/acle/memtag_2a.c
  e2be4748443bb6caa176b86d28972388  gcc/testsuite/gcc.target/aarch64/acle/memtag_3.c
--- 68377,68383 ----
  c2eae4877980c06eaa23ea8db426a5c1  gcc/testsuite/gcc.target/aarch64/acle/ls64_st64bv0-3.c
  a9efd5e0ebc228f128308006c2db9c2b  gcc/testsuite/gcc.target/aarch64/acle/ls64_st64bv0.c
  bbcc298547eb556312f83b765ff6baef  gcc/testsuite/gcc.target/aarch64/acle/ls64_strict_align.c
! a6b97d3c920a4b589738d78cf9cdbbc2  gcc/testsuite/gcc.target/aarch64/acle/memtag_1.c
  42f386dac12d330a687e58d7027f0c47  gcc/testsuite/gcc.target/aarch64/acle/memtag_2.c
  dad27dd9a8b076099818ec56a74ef781  gcc/testsuite/gcc.target/aarch64/acle/memtag_2a.c
  e2be4748443bb6caa176b86d28972388  gcc/testsuite/gcc.target/aarch64/acle/memtag_3.c
*************** b50e1f81d7305cfe5249cb4bd2be5e6f  gcc/te
*** 69530,69535 ****
--- 69615,69646 ----
  f36275b28313084fe8b53fd06787e739  gcc/testsuite/gcc.target/aarch64/memset-corner-cases.c
  ef180504b13044e94b604990b6c3ef43  gcc/testsuite/gcc.target/aarch64/memset-q-reg.c
  99f047cbf8399ea75f540f743fbcd4cb  gcc/testsuite/gcc.target/aarch64/memset-strict-align-1.c
+ 8540bb84a700a548a308ce55edcbe16e  gcc/testsuite/gcc.target/aarch64/memtag/alloca-1.c
+ 2de13ace21585ee3fc28086addef5613  gcc/testsuite/gcc.target/aarch64/memtag/alloca-2.c
+ 08559db553386a4e5abd9156d6cf18fe  gcc/testsuite/gcc.target/aarch64/memtag/alloca-3.c
+ b7ef11add7fe67aa82583bd030e7e4d0  gcc/testsuite/gcc.target/aarch64/memtag/arguments-1.c
+ 2f289d1c73f55d3ca6ab4d026dbd5639  gcc/testsuite/gcc.target/aarch64/memtag/arguments-2.c
+ 648dd0befca4c514d5ed932a4f538158  gcc/testsuite/gcc.target/aarch64/memtag/arguments-3.c
+ 24281e882e236cc48318591f07780bf9  gcc/testsuite/gcc.target/aarch64/memtag/arguments-4.c
+ e60f98256d2c3174ee010df8ba0b99d4  gcc/testsuite/gcc.target/aarch64/memtag/arguments.c
+ ca65a1819840555f5018fc3778a8d415  gcc/testsuite/gcc.target/aarch64/memtag/basic-1.c
+ a258103afbe24fca467d43ec89acb4b3  gcc/testsuite/gcc.target/aarch64/memtag/basic-3.c
+ 2dd8ed38c1c49513bc471cca98a64eaf  gcc/testsuite/gcc.target/aarch64/memtag/basic-struct.c
+ 0010c727ea158eafe6796f2c69f4a804  gcc/testsuite/gcc.target/aarch64/memtag/cfi-mte-memtag-frame-1.c
+ 986b9b5a67efd4ea4233b8940ea32760  gcc/testsuite/gcc.target/aarch64/memtag/large-array.c
+ e3454b8aba00fb02bddbd459b5e54489  gcc/testsuite/gcc.target/aarch64/memtag/local-no-escape.c
+ bf58eecb4368a54162f11c642aae87c4  gcc/testsuite/gcc.target/aarch64/memtag/memtag.exp
+ 7113c937818c3dc1312446bbe88d3c2f  gcc/testsuite/gcc.target/aarch64/memtag/mte-sig.h
+ 831f287dd9fa0aaae4de4f92f296f1e1  gcc/testsuite/gcc.target/aarch64/memtag/no-sanitize-attribute.c
+ 26bf3e3e962b2c712ec7fcfa795e5666  gcc/testsuite/gcc.target/aarch64/memtag/texec-1.c
+ 1dc4ec3d04dd74b958bc9846dcf186ba  gcc/testsuite/gcc.target/aarch64/memtag/texec-2.c
+ 7e86151c1b6efd3b3824d31097f4af85  gcc/testsuite/gcc.target/aarch64/memtag/texec-3.c
+ ecbb11b978700a54c48bac46cb92d757  gcc/testsuite/gcc.target/aarch64/memtag/value-init.c
+ 11097c8d1c5fcf869e68abac1250b33b  gcc/testsuite/gcc.target/aarch64/memtag/vararray-gimple.c
+ c42951cba4b532f35f74ae2978d26f1c  gcc/testsuite/gcc.target/aarch64/memtag/vararray.c
+ 5cc15223a1de62d8acb2eea746d6efa2  gcc/testsuite/gcc.target/aarch64/memtag/vla-1.c
+ f8513bf8b3440dcb55c3304490cabb8b  gcc/testsuite/gcc.target/aarch64/memtag/vla-2.c
+ dd25cb10e93fc2aa1601b491a4e85c25  gcc/testsuite/gcc.target/aarch64/memtag/zero-init.c
  424a2b5eafd789db7d0b5caa9628ff62  gcc/testsuite/gcc.target/aarch64/merge_trunc1.c
  abc6ce7914d6d644d308d83fc8bd777f  gcc/testsuite/gcc.target/aarch64/mfloat-init-1.c
  4eed4dd5aa94cdbafdb452fb4f2fa939  gcc/testsuite/gcc.target/aarch64/mgeneral-regs_1.c
*************** f3b5922b8b4354df5f810cfdcfd0f7e6  gcc/te
*** 69723,69728 ****
--- 69834,69840 ----
  45fde6d2b5e6119a4720e8c2aaa5396c  gcc/testsuite/gcc.target/aarch64/options_set_28.c
  7dbad8c7e1b6f04a8adab6aac3c9f332  gcc/testsuite/gcc.target/aarch64/options_set_29.c
  936ce13e85d31d5545886eb94526915b  gcc/testsuite/gcc.target/aarch64/options_set_3.c
+ 8daf2d27f08d7ccca85ae92c69c9127e  gcc/testsuite/gcc.target/aarch64/options_set_30.c
  e721f980e1e7a9648d77300c2f6ea0e5  gcc/testsuite/gcc.target/aarch64/options_set_4.c
  9c2ebf89a44fab00a57afc61e1a1fe86  gcc/testsuite/gcc.target/aarch64/options_set_5.c
  3da7d2bb75f9e314375a2e3a933c689d  gcc/testsuite/gcc.target/aarch64/options_set_6.c
*************** cc4f69997a3864b3299f1b4809507883  gcc/te
*** 69976,69981 ****
--- 70088,70094 ----
  be30d927e2df67d4fe2786d0d026bbaa  gcc/testsuite/gcc.target/aarch64/pragma_cpp_predefs_2.c
  38af83405c4b19363e539e8f2589d817  gcc/testsuite/gcc.target/aarch64/pragma_cpp_predefs_3.c
  5665583c5162a1f3f37fd70cbe7f9809  gcc/testsuite/gcc.target/aarch64/pragma_cpp_predefs_4.c
+ b5ff836b5a987f9feaf35c5f8ec9f4db  gcc/testsuite/gcc.target/aarch64/pragma_cpp_predefs_5.c
  1f95766b4ed5bfb5f2cf1f168a607a8d  gcc/testsuite/gcc.target/aarch64/predefine_large.c
  d38e476730748c653068e7cb2d8d6ca6  gcc/testsuite/gcc.target/aarch64/predefine_small.c
  29e7dbfba15c0f945488b33400b908b4  gcc/testsuite/gcc.target/aarch64/predefine_tiny.c
*************** f1244fcb32ddc0f3d61678f9cd118ff3  gcc/te
*** 73693,73699 ****
  aa357d405e2f83cc3b5b21d3513c1281  gcc/testsuite/gcc.target/aarch64/sve/acle/general/add_1.c
  e40e4d129ea43829ee4a75365eb50265  gcc/testsuite/gcc.target/aarch64/sve/acle/general/amin_1.c
  171242c36c5137cac47934923813a672  gcc/testsuite/gcc.target/aarch64/sve/acle/general/and_1.c
! 68b3b762499b486689be862b5b06513c  gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_1.c
  c837aa90d4f65fe43a41a1df66ecddaa  gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_2.c
  065185852393d4ba6508c94833c67eb2  gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_3.c
  dbd822adb848a971885a06967432c628  gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_4.c
--- 73806,73812 ----
  aa357d405e2f83cc3b5b21d3513c1281  gcc/testsuite/gcc.target/aarch64/sve/acle/general/add_1.c
  e40e4d129ea43829ee4a75365eb50265  gcc/testsuite/gcc.target/aarch64/sve/acle/general/amin_1.c
  171242c36c5137cac47934923813a672  gcc/testsuite/gcc.target/aarch64/sve/acle/general/and_1.c
! 68d17e82076281840af8bbba6076c5b0  gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_1.c
  c837aa90d4f65fe43a41a1df66ecddaa  gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_2.c
  065185852393d4ba6508c94833c67eb2  gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_3.c
  dbd822adb848a971885a06967432c628  gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_4.c
*************** cffa63a742186323feab22505915a6e9  gcc/te
*** 73701,73706 ****
--- 73814,73820 ----
  e1e1569e7833d66a82f4148d1aae172a  gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_6.c
  e681aa76b7413f54146a5660729b0f7c  gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_7.c
  92c276aa826427c641795daf9568c67a  gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_8.c
+ 6257abaca6dbe01c7e69c5f185dfaee8  gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_9.c
  05382618b8c4ba6e308d6b5ff864fab5  gcc/testsuite/gcc.target/aarch64/sve/acle/general/bic_1.c
  af77aba325d1fbc52d95aa9fcc602577  gcc/testsuite/gcc.target/aarch64/sve/acle/general/brka_1.c
  4eea3d7baf0e2958356c0c33600e72e4  gcc/testsuite/gcc.target/aarch64/sve/acle/general/brka_2.c
*************** c7be3d386d00158fa4fd485f85997a4a  gcc/te
*** 74638,74643 ****
--- 74752,74765 ----
  cf5911e80d16a3e85670a00b9b169a70  gcc/testsuite/gcc.target/aarch64/sve/peel_ind_12_run.c
  d3421111b9d0c71bb816a189ca9c6c62  gcc/testsuite/gcc.target/aarch64/sve/peel_ind_13.c
  218cc357e6fab35253ba0c9af84d11b1  gcc/testsuite/gcc.target/aarch64/sve/peel_ind_13_run.c
+ c3358aa7b955c665c757a81bdcdcb97d  gcc/testsuite/gcc.target/aarch64/sve/peel_ind_14.c
+ 19c5097d7e7f2a6df3239d55402b6c14  gcc/testsuite/gcc.target/aarch64/sve/peel_ind_14_run.c
+ c3358aa7b955c665c757a81bdcdcb97d  gcc/testsuite/gcc.target/aarch64/sve/peel_ind_15.c
+ fb6baf73912dea8e3fa8332b961542f3  gcc/testsuite/gcc.target/aarch64/sve/peel_ind_15_run.c
+ c3358aa7b955c665c757a81bdcdcb97d  gcc/testsuite/gcc.target/aarch64/sve/peel_ind_16.c
+ d539b9b1cb1d3660f07351b16bfe12ba  gcc/testsuite/gcc.target/aarch64/sve/peel_ind_16_run.c
+ 1f9ed3d52287b537bc5db440e591252a  gcc/testsuite/gcc.target/aarch64/sve/peel_ind_17.c
+ 5d3087fe0f6aef08674b523b2be56be7  gcc/testsuite/gcc.target/aarch64/sve/peel_ind_17_run.c
  554f0eec3d39895e8e465acc9954378d  gcc/testsuite/gcc.target/aarch64/sve/peel_ind_1_run.c
  11928fb92734ba578ca3c71362426cd8  gcc/testsuite/gcc.target/aarch64/sve/peel_ind_2.c
  40ef61fe1aa9144c65314b0f7a98fa78  gcc/testsuite/gcc.target/aarch64/sve/peel_ind_2_run.c
*************** b39fe9dc3f7b0c435de242709abf276a  gcc/te
*** 83823,83828 ****
--- 83945,83952 ----
  ae6b05eb60ec60c92e6f0b3a7d4e3adf  gcc/testsuite/gcc.target/i386/avx512bitalgvl-vpopcntb-1.c
  1bc03df9d4275e9b41e7f0e356b06088  gcc/testsuite/gcc.target/i386/avx512bitalgvl-vpopcntw-1.c
  687030be4c7de0df65d352c6e5e2741b  gcc/testsuite/gcc.target/i386/avx512bitalgvl-vpshufbitqmb-1.c
+ 6581ef9df6c5a4405444da740b69c52b  gcc/testsuite/gcc.target/i386/avx512bmm-1.c
+ cd81465cf03fcdafd419bd70419a61a9  gcc/testsuite/gcc.target/i386/avx512bmmvl-1.c
  34f70835661397c9f3bdb5572f6d8ce1  gcc/testsuite/gcc.target/i386/avx512bw-check.h
  2e4baf9c42678da5e49f8dcae5df06ec  gcc/testsuite/gcc.target/i386/avx512bw-extendbf2sf.c
  edb4e52333b73c860f134c92abb703cc  gcc/testsuite/gcc.target/i386/avx512bw-kaddd-1.c
*************** c1320fd604803bc04257c984f1e3ba77  gcc/te
*** 87091,87097 ****
  3dd864a351a6115db6a5b2ea1ee16ece  gcc/testsuite/gcc.target/i386/funcspec-3.c
  5af0527c599bf95f77628d48b1beb0ec  gcc/testsuite/gcc.target/i386/funcspec-4.c
  7568c1249431aafb7f8e2610a1e4a35e  gcc/testsuite/gcc.target/i386/funcspec-5.c
! 91613dd5847aa6776004b163c9757110  gcc/testsuite/gcc.target/i386/funcspec-56.inc
  b954a6c88c30f112db6bd140acb0162c  gcc/testsuite/gcc.target/i386/funcspec-6.c
  35655de5c9348f2a36254312a8d17908  gcc/testsuite/gcc.target/i386/funcspec-7.c
  0ba9f1b7368ea580cabab541b451aea8  gcc/testsuite/gcc.target/i386/funcspec-8.c
--- 87215,87221 ----
  3dd864a351a6115db6a5b2ea1ee16ece  gcc/testsuite/gcc.target/i386/funcspec-3.c
  5af0527c599bf95f77628d48b1beb0ec  gcc/testsuite/gcc.target/i386/funcspec-4.c
  7568c1249431aafb7f8e2610a1e4a35e  gcc/testsuite/gcc.target/i386/funcspec-5.c
! 31a53e1ba0b01416e951e4f68667e2c8  gcc/testsuite/gcc.target/i386/funcspec-56.inc
  b954a6c88c30f112db6bd140acb0162c  gcc/testsuite/gcc.target/i386/funcspec-6.c
  35655de5c9348f2a36254312a8d17908  gcc/testsuite/gcc.target/i386/funcspec-7.c
  0ba9f1b7368ea580cabab541b451aea8  gcc/testsuite/gcc.target/i386/funcspec-8.c
*************** eea09433ae07509586cf81bfe0eba660  gcc/te
*** 87320,87325 ****
--- 87444,87450 ----
  c6f6aaff47d064fbceed4cfbcb5b9279  gcc/testsuite/gcc.target/i386/keylocker-encodekey128.c
  a468c392fd8838d0198cfb8b367d4b6d  gcc/testsuite/gcc.target/i386/keylocker-encodekey256.c
  78393ec91600382e98db57e560deaea9  gcc/testsuite/gcc.target/i386/keylocker-loadiwkey.c
+ 75eec9ddfedd16dad1c34342d4bb3a1a  gcc/testsuite/gcc.target/i386/keylocker-pr123217.c
  756d96c509b9d211464cf07af4df2b2c  gcc/testsuite/gcc.target/i386/kortest_ccz-1.c
  6a61f297f5746de86187140f048ab655  gcc/testsuite/gcc.target/i386/l_fma_1.h
  c598c1d2a127be1189b3dfe020919429  gcc/testsuite/gcc.target/i386/l_fma_2.h
*************** c1a42e6abf341c78082c17c60365086c  gcc/te
*** 88576,88583 ****
  b69eb677daef92be04da1f0e0218c44e  gcc/testsuite/gcc.target/i386/pr120840-1b.c
  90c426e3f9f68074b3688e77c0a85c20  gcc/testsuite/gcc.target/i386/pr120840-1c.c
  b157fbe2632de5156079590d5faadfd7  gcc/testsuite/gcc.target/i386/pr120840-1d.c
! 906e507034982c533b2ad0a2614d8730  gcc/testsuite/gcc.target/i386/pr120881-1a.c
! 99479cd9600e1e2a8ae9b7781b9895ea  gcc/testsuite/gcc.target/i386/pr120881-1b.c
  dc5699b1ed908f2743344eb7eccdf1b4  gcc/testsuite/gcc.target/i386/pr120881-1c.c
  ee181f50a327c5ee8df5da7cab955ca5  gcc/testsuite/gcc.target/i386/pr120881-1d.c
  9e01dd8a47d1204b9266fddba59ae6da  gcc/testsuite/gcc.target/i386/pr120881-2a.c
--- 88701,88708 ----
  b69eb677daef92be04da1f0e0218c44e  gcc/testsuite/gcc.target/i386/pr120840-1b.c
  90c426e3f9f68074b3688e77c0a85c20  gcc/testsuite/gcc.target/i386/pr120840-1c.c
  b157fbe2632de5156079590d5faadfd7  gcc/testsuite/gcc.target/i386/pr120840-1d.c
! 4b9fcb69739d672e799c27a972aaf97d  gcc/testsuite/gcc.target/i386/pr120881-1a.c
! be5b82c04ee4bc5470f2a54c12758197  gcc/testsuite/gcc.target/i386/pr120881-1b.c
  dc5699b1ed908f2743344eb7eccdf1b4  gcc/testsuite/gcc.target/i386/pr120881-1c.c
  ee181f50a327c5ee8df5da7cab955ca5  gcc/testsuite/gcc.target/i386/pr120881-1d.c
  9e01dd8a47d1204b9266fddba59ae6da  gcc/testsuite/gcc.target/i386/pr120881-2a.c
*************** e6b30d1b12ce6371b1496537f813409b  gcc/te
*** 88627,88633 ****
  2dc3b7effccafde04f6a1a6979dfda02  gcc/testsuite/gcc.target/i386/pr121541-4.c
  49453a7f94bae8710b481412068b8c3a  gcc/testsuite/gcc.target/i386/pr121541-5a.c
  49647fa6eb097d991a160b581c3ad123  gcc/testsuite/gcc.target/i386/pr121541-5b.c
! 8655d79855cf007c763e79cc65d1112a  gcc/testsuite/gcc.target/i386/pr121572-1a.c
  68b576a781e6a2dc5f79397f2956beaf  gcc/testsuite/gcc.target/i386/pr121572-1b.c
  7fe4d8dc41303448e9d4b3659eb12e8e  gcc/testsuite/gcc.target/i386/pr121572-2a.c
  04e55eb00b90402ca90af7e818eb8d3c  gcc/testsuite/gcc.target/i386/pr121572-2b.c
--- 88752,88758 ----
  2dc3b7effccafde04f6a1a6979dfda02  gcc/testsuite/gcc.target/i386/pr121541-4.c
  49453a7f94bae8710b481412068b8c3a  gcc/testsuite/gcc.target/i386/pr121541-5a.c
  49647fa6eb097d991a160b581c3ad123  gcc/testsuite/gcc.target/i386/pr121541-5b.c
! 01537400901755ab7517f93176f78533  gcc/testsuite/gcc.target/i386/pr121572-1a.c
  68b576a781e6a2dc5f79397f2956beaf  gcc/testsuite/gcc.target/i386/pr121572-1b.c
  7fe4d8dc41303448e9d4b3659eb12e8e  gcc/testsuite/gcc.target/i386/pr121572-2a.c
  04e55eb00b90402ca90af7e818eb8d3c  gcc/testsuite/gcc.target/i386/pr121572-2b.c
*************** c05d22a930ef3f74451ec3e9d4db1b74  gcc/te
*** 90781,90787 ****
  1d13c923e2137e0e9947a181060c5ef9  gcc/testsuite/gcc.target/i386/sha512msg2-2.c
  e0ace5d39e9cc7930c86ec3fac2a2562  gcc/testsuite/gcc.target/i386/sha512rnds2-2.c
  ee83ab3d7af07a61b43a69ecb4581e78  gcc/testsuite/gcc.target/i386/shift-gf2p8affine-1.c
! 1f46d5eb18241da3a71a73289e00fc9b  gcc/testsuite/gcc.target/i386/shift-gf2p8affine-2.c
  59b3726b3fa2a69c347fc834960c4bb7  gcc/testsuite/gcc.target/i386/shift-gf2p8affine-3.c
  c62277376d2a18d4875b451e08be9e76  gcc/testsuite/gcc.target/i386/shift-gf2p8affine-5.c
  877f13bdda2b37a38cecc3c3ba5c3fe6  gcc/testsuite/gcc.target/i386/shift-gf2p8affine-6.c
--- 90906,90912 ----
  1d13c923e2137e0e9947a181060c5ef9  gcc/testsuite/gcc.target/i386/sha512msg2-2.c
  e0ace5d39e9cc7930c86ec3fac2a2562  gcc/testsuite/gcc.target/i386/sha512rnds2-2.c
  ee83ab3d7af07a61b43a69ecb4581e78  gcc/testsuite/gcc.target/i386/shift-gf2p8affine-1.c
! 134abe762bb465da1b9aed9f8569ce8d  gcc/testsuite/gcc.target/i386/shift-gf2p8affine-2.c
  59b3726b3fa2a69c347fc834960c4bb7  gcc/testsuite/gcc.target/i386/shift-gf2p8affine-3.c
  c62277376d2a18d4875b451e08be9e76  gcc/testsuite/gcc.target/i386/shift-gf2p8affine-5.c
  877f13bdda2b37a38cecc3c3ba5c3fe6  gcc/testsuite/gcc.target/i386/shift-gf2p8affine-6.c
*************** b3482aa074e044edfb2a4c72e5c1d085  gcc/te
*** 91573,91578 ****
--- 91698,91704 ----
  133d7eb15ead287c2ef11a8162780801  gcc/testsuite/gcc.target/i386/unroll-1.c
  c30812b4c7eb367ec8e5f4aba349d66b  gcc/testsuite/gcc.target/i386/user_msr-1.c
  d817f6a5d58eae58bff8e4083f7945db  gcc/testsuite/gcc.target/i386/user_msr-2.c
+ aa50202a413f80a35396415eec316d08  gcc/testsuite/gcc.target/i386/user_msr-pr123217.c
  aafb0010ebceff249236af3aa1f22e2b  gcc/testsuite/gcc.target/i386/vararg-1.c
  3b8acabb2f18b3fd13f3871729bac23f  gcc/testsuite/gcc.target/i386/vararg-10.c
  2869209769b52916ee551938b0c572f1  gcc/testsuite/gcc.target/i386/vararg-2.c
*************** dde2cba27bc4292492e4c0dd492a70e0  gcc/te
*** 92135,92140 ****
--- 92261,92267 ----
  1dd25b33f6fd8d4c4dc750865d86f404  gcc/testsuite/gcc.target/loongarch/pr121906.c
  0626ac54385b7d00394be7a0b09850a1  gcc/testsuite/gcc.target/loongarch/pr122695-1.c
  fb640df1e5eb969859e5c360f608dec4  gcc/testsuite/gcc.target/loongarch/pr122695-2.c
+ a7b8424d31ff38e61388847501535b2d  gcc/testsuite/gcc.target/loongarch/pr123171.c
  d8ba98681e844aa3cab41dadb293ad62  gcc/testsuite/gcc.target/loongarch/pragma-la64V1_1-2.c
  94f43e2ce509bac58eba454a85dd7a33  gcc/testsuite/gcc.target/loongarch/pragma-la64V1_1.c
  596c5238ab0cc321a3b51db7071941d8  gcc/testsuite/gcc.target/loongarch/regname-float-abi.c
*************** c3b9c79f87c4206d38cd6acc05f5be9f  gcc/te
*** 92167,92172 ****
--- 92294,92300 ----
  75db51c40cf15cf674f98cd2664252bd  gcc/testsuite/gcc.target/loongarch/trap-default.c
  bb57d24452eb2fea309f990edfa5de1c  gcc/testsuite/gcc.target/loongarch/umulsi3_highpart.c
  20592e6b1e8a0f3b8742b7beb0f51ae2  gcc/testsuite/gcc.target/loongarch/va_arg.c
+ c32afe294b6ac61449492b3292f7530d  gcc/testsuite/gcc.target/loongarch/vect-mode-tieable.c
  fdc09cb25851254e708f2d7b35b30157  gcc/testsuite/gcc.target/loongarch/vector/lasx/abd-lasx.c
  10a58b0c68aafdaa8704cc0ab8a37e3c  gcc/testsuite/gcc.target/loongarch/vector/lasx/avg-ceil-lasx.c
  38e4e62393ad811f1092ea45b0c52b77  gcc/testsuite/gcc.target/loongarch/vector/lasx/avg-floor-lasx.c
*************** cecd9f8159d8c4d5b14c7d7037f45906  gcc/te
*** 92413,92419 ****
  590522d9e3f47096ccc8e0a658c2812f  gcc/testsuite/gcc.target/loongarch/vector/lasx/vect-concat-128-256-result.c
  be2f81347a1bc18228cbe68f8a6676df  gcc/testsuite/gcc.target/loongarch/vector/lasx/vect-concat-128-256.c
  4978a46fd91b35d00996d6af20419bc4  gcc/testsuite/gcc.target/loongarch/vector/lasx/vect-extract-256-128-result.c
! afb34e017ce38a8c38b1f7c758f72da6  gcc/testsuite/gcc.target/loongarch/vector/lasx/vect-extract-256-128.c
  13cec58c7391a5cef41368197f850947  gcc/testsuite/gcc.target/loongarch/vector/lasx/vect-extract.c
  e938ebb81df2ed0b44e7fabc3afc2107  gcc/testsuite/gcc.target/loongarch/vector/lasx/vect-frint-no-inexact.c
  179412aced110fd38bdd89629658990a  gcc/testsuite/gcc.target/loongarch/vector/lasx/vect-frint.c
--- 92541,92547 ----
  590522d9e3f47096ccc8e0a658c2812f  gcc/testsuite/gcc.target/loongarch/vector/lasx/vect-concat-128-256-result.c
  be2f81347a1bc18228cbe68f8a6676df  gcc/testsuite/gcc.target/loongarch/vector/lasx/vect-concat-128-256.c
  4978a46fd91b35d00996d6af20419bc4  gcc/testsuite/gcc.target/loongarch/vector/lasx/vect-extract-256-128-result.c
! 820ed6aaf6680052a63ae40334b2617a  gcc/testsuite/gcc.target/loongarch/vector/lasx/vect-extract-256-128.c
  13cec58c7391a5cef41368197f850947  gcc/testsuite/gcc.target/loongarch/vector/lasx/vect-extract.c
  e938ebb81df2ed0b44e7fabc3afc2107  gcc/testsuite/gcc.target/loongarch/vector/lasx/vect-frint-no-inexact.c
  179412aced110fd38bdd89629658990a  gcc/testsuite/gcc.target/loongarch/vector/lasx/vect-frint.c
*************** ec09b6aa0ae7b7a9eac9fb924e19c04c  gcc/te
*** 92661,92666 ****
--- 92789,92795 ----
  dbfbd76701c5c3e6c8ed37ced1ba9cc7  gcc/testsuite/gcc.target/loongarch/vector/lsx/pr119084.c
  359760e5160f4b52d2fa349806589a0d  gcc/testsuite/gcc.target/loongarch/vector/lsx/pr121064.c
  4fb67de6ceaa4d3d0dfff318541b470b  gcc/testsuite/gcc.target/loongarch/vector/lsx/pr122097.c
+ 76be8fbd02020c0b574be8ba3ce9b597  gcc/testsuite/gcc.target/loongarch/vector/lsx/pr123117.c
  2ddebd413eaa67833fbe9045727d296a  gcc/testsuite/gcc.target/loongarch/vector/lsx/rotl-with-vrotr-b.c
  b4792704ae2560835ce2844ab052bd96  gcc/testsuite/gcc.target/loongarch/vector/lsx/rotl-with-vrotr-d.c
  0f0929ffb430681fa30b2b435c3a1aea  gcc/testsuite/gcc.target/loongarch/vector/lsx/rotl-with-vrotr-h.c
*************** ade16f059b010bf66d77fcf2968ef4e1  gcc/te
*** 98202,98207 ****
--- 98331,98339 ----
  79de851b19bf562fd7b650f742485afa  gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-template.h
  20b13d398df88501296ba6a72e6c9c15  gcc/testsuite/gcc.target/riscv/rvv/autovec/early-break-1.c
  ff340d9c6dee8784837f8941d76ecb52  gcc/testsuite/gcc.target/riscv/rvv/autovec/early-break-2.c
+ 5522a5c36ca95ef215635928ff0690c4  gcc/testsuite/gcc.target/riscv/rvv/autovec/early-break-3.c
+ 98c9ad8647e73c3d00ffb9b02387030e  gcc/testsuite/gcc.target/riscv/rvv/autovec/early-break-4.c
+ 4eec1c208618208817133e20728e6cb7  gcc/testsuite/gcc.target/riscv/rvv/autovec/early-break-5.c
  5a12daa267ef1b36fd2b14c30b0c65fc  gcc/testsuite/gcc.target/riscv/rvv/autovec/fixed-vlmax-1.c
  dd2861db83bd4db623b682d60209ffd7  gcc/testsuite/gcc.target/riscv/rvv/autovec/fold-min-poly.c
  b60c9f046ba24d1346603ea33fa46de1  gcc/testsuite/gcc.target/riscv/rvv/autovec/gather-scatter/gather_load_32-1.c
*************** d90ca4ab32f893e58362b7afbe85e6fd  gcc/te
*** 98339,98352 ****
  71f36e6090396f7da8cd0a7e211aa985  gcc/testsuite/gcc.target/riscv/rvv/autovec/gather-scatter/strided_load_run-1.c
  123e1e676e90cec58a1e110a14431406  gcc/testsuite/gcc.target/riscv/rvv/autovec/gather-scatter/strided_load_run-2.c
  1ce08b15fd645f580810df743eb6d8d4  gcc/testsuite/gcc.target/riscv/rvv/autovec/gather-scatter/strided_store-1.c
! 06162d55a09aeffab07f54e7cf9d3de6  gcc/testsuite/gcc.target/riscv/rvv/autovec/gather-scatter/strided_store-2.c
  107743a69f58f28cf14e8a598bd333e7  gcc/testsuite/gcc.target/riscv/rvv/autovec/gather-scatter/strided_store_run-1.c
  c1274e3ee15699a124ca1ff4e24fd55b  gcc/testsuite/gcc.target/riscv/rvv/autovec/gather-scatter/strided_store_run-2.c
  c1779350d6b08b51c352226f6a13ffb2  gcc/testsuite/gcc.target/riscv/rvv/autovec/madd-split2-1.c
  f7a8ba49de6d1e5b275e35f45edbf009  gcc/testsuite/gcc.target/riscv/rvv/autovec/max-vect-1.c
  2b66681c6de1c53f888f788a0ccfb6da  gcc/testsuite/gcc.target/riscv/rvv/autovec/max-vect-2.c
  03b6c6282f299ea1ba67e487d39d0d18  gcc/testsuite/gcc.target/riscv/rvv/autovec/no-segment.c
! 968af9929dcdb9ff769f561707bd3e36  gcc/testsuite/gcc.target/riscv/rvv/autovec/param-autovec-mode.c
  7da5b354874f99fde1d14c20b0fa76e7  gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/gimple_fold-1.c
  78f17ccf2c8434fe0739b9fd95e2aa43  gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/live-1.c
  cc143b9c26bd55a3825fe0f7577a91fa  gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/live-2.c
--- 98471,98484 ----
  71f36e6090396f7da8cd0a7e211aa985  gcc/testsuite/gcc.target/riscv/rvv/autovec/gather-scatter/strided_load_run-1.c
  123e1e676e90cec58a1e110a14431406  gcc/testsuite/gcc.target/riscv/rvv/autovec/gather-scatter/strided_load_run-2.c
  1ce08b15fd645f580810df743eb6d8d4  gcc/testsuite/gcc.target/riscv/rvv/autovec/gather-scatter/strided_store-1.c
! edd0a4ba6a9489214ca39d04c6a65fdc  gcc/testsuite/gcc.target/riscv/rvv/autovec/gather-scatter/strided_store-2.c
  107743a69f58f28cf14e8a598bd333e7  gcc/testsuite/gcc.target/riscv/rvv/autovec/gather-scatter/strided_store_run-1.c
  c1274e3ee15699a124ca1ff4e24fd55b  gcc/testsuite/gcc.target/riscv/rvv/autovec/gather-scatter/strided_store_run-2.c
  c1779350d6b08b51c352226f6a13ffb2  gcc/testsuite/gcc.target/riscv/rvv/autovec/madd-split2-1.c
  f7a8ba49de6d1e5b275e35f45edbf009  gcc/testsuite/gcc.target/riscv/rvv/autovec/max-vect-1.c
  2b66681c6de1c53f888f788a0ccfb6da  gcc/testsuite/gcc.target/riscv/rvv/autovec/max-vect-2.c
  03b6c6282f299ea1ba67e487d39d0d18  gcc/testsuite/gcc.target/riscv/rvv/autovec/no-segment.c
! ab21455fe24976076ab6c6ae759350ef  gcc/testsuite/gcc.target/riscv/rvv/autovec/param-autovec-mode.c
  7da5b354874f99fde1d14c20b0fa76e7  gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/gimple_fold-1.c
  78f17ccf2c8434fe0739b9fd95e2aa43  gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/live-1.c
  cc143b9c26bd55a3825fe0f7577a91fa  gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/live-2.c
*************** cdcb3f79dcdc39964352b1cfd0a498a9  gcc/te
*** 98365,98371 ****
  2b294ee4b231e73fa76c00bc1f925e14  gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/multiple_rgroup_zbb.c
  14ee564a315509685f622f7c538f6323  gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/pr112773.c
  7d8e539f2d8f971aa17162bf1af6be22  gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/select_vl-1.c
! 93d71f92f52cb23033f828501713f071  gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/select_vl-2.c
  8296af47d5dbbf6472d921747ddab15d  gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/single_rgroup-1.c
  ad63bb25169ac08133a112caeb9cd138  gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/single_rgroup-1.h
  7d205209316fb0bf3e4ccf0b60b1fdf4  gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/single_rgroup-2.c
--- 98497,98503 ----
  2b294ee4b231e73fa76c00bc1f925e14  gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/multiple_rgroup_zbb.c
  14ee564a315509685f622f7c538f6323  gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/pr112773.c
  7d8e539f2d8f971aa17162bf1af6be22  gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/select_vl-1.c
! 5ed68f728ccf46bedcde0b8db6a7ae7f  gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/select_vl-2.c
  8296af47d5dbbf6472d921747ddab15d  gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/single_rgroup-1.c
  ad63bb25169ac08133a112caeb9cd138  gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/single_rgroup-1.h
  7d205209316fb0bf3e4ccf0b60b1fdf4  gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/single_rgroup-2.c
*************** e5794d88a1109065814ce4f8f2246087  gcc/te
*** 98507,98513 ****
  e7ca8fe6239410f9affbff1106fd2d15  gcc/testsuite/gcc.target/riscv/rvv/autovec/pr119114.c
  446b0327be112ddedf3f8db6bc96d603  gcc/testsuite/gcc.target/riscv/rvv/autovec/pr119224.c
  97a2ebde6fd6564be1fe7abc131eb066  gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120356.c
! 292706864e99c451e560a352aa01e688  gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-1.c
  f3a9ddca4f092e66d160c682c897eab0  gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-2.c
  17dd3c0282d1ec39655b88b23d9407a0  gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-3.c
  1eddb2cc7c5ba2d1d837f5842181cd73  gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-4.c
--- 98639,98645 ----
  e7ca8fe6239410f9affbff1106fd2d15  gcc/testsuite/gcc.target/riscv/rvv/autovec/pr119114.c
  446b0327be112ddedf3f8db6bc96d603  gcc/testsuite/gcc.target/riscv/rvv/autovec/pr119224.c
  97a2ebde6fd6564be1fe7abc131eb066  gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120356.c
! d089ebc71ed2d229654df324ccecea76  gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-1.c
  f3a9ddca4f092e66d160c682c897eab0  gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-2.c
  17dd3c0282d1ec39655b88b23d9407a0  gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-3.c
  1eddb2cc7c5ba2d1d837f5842181cd73  gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-4.c
*************** f3a9ddca4f092e66d160c682c897eab0  gcc/te
*** 98516,98522 ****
  b81941261eb74f03f85b72b205359f75  gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120652-3.c
  7fc7aa17b0d67ed9ebe9082530c252eb  gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120652.h
  e551adccc3ae041941558e7ebb4dd965  gcc/testsuite/gcc.target/riscv/rvv/autovec/pr121334.c
! cf801f2e1c669d164d4ceb3cd657f647  gcc/testsuite/gcc.target/riscv/rvv/autovec/pr121510.c
  34869ae69595f572c19e98413f9d760b  gcc/testsuite/gcc.target/riscv/rvv/autovec/pr121582.c
  ed132fcfade8212b992e822b341be9eb  gcc/testsuite/gcc.target/riscv/rvv/autovec/pr121742.c
  eda1f0d5c82c50988ede53858da3cabd  gcc/testsuite/gcc.target/riscv/rvv/autovec/pr121780.c
--- 98648,98654 ----
  b81941261eb74f03f85b72b205359f75  gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120652-3.c
  7fc7aa17b0d67ed9ebe9082530c252eb  gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120652.h
  e551adccc3ae041941558e7ebb4dd965  gcc/testsuite/gcc.target/riscv/rvv/autovec/pr121334.c
! 1159bf825f9c6c94effd66005702c75f  gcc/testsuite/gcc.target/riscv/rvv/autovec/pr121510.c
  34869ae69595f572c19e98413f9d760b  gcc/testsuite/gcc.target/riscv/rvv/autovec/pr121582.c
  ed132fcfade8212b992e822b341be9eb  gcc/testsuite/gcc.target/riscv/rvv/autovec/pr121742.c
  eda1f0d5c82c50988ede53858da3cabd  gcc/testsuite/gcc.target/riscv/rvv/autovec/pr121780.c
*************** a46c21828339f41cac3054a662eefb70  gcc/te
*** 98537,98544 ****
--- 98669,98679 ----
  9e392034c9515123dd44a7ee88bd8905  gcc/testsuite/gcc.target/riscv/rvv/autovec/pr122627.c
  f282bbefbf97b6d53a628679bbaa73c0  gcc/testsuite/gcc.target/riscv/rvv/autovec/pr122635-1.c
  b2dd0767e7d7daf54047f6721f5c4fc5  gcc/testsuite/gcc.target/riscv/rvv/autovec/pr122635-2.c
+ cf72fc61666d019de029c8143c4c42a2  gcc/testsuite/gcc.target/riscv/rvv/autovec/pr122970.c
  4c249548c54ca3fd544c8943a9d28b77  gcc/testsuite/gcc.target/riscv/rvv/autovec/pr123022-2.c
  159ba529f2ab9b94d86dd9c7121d5aec  gcc/testsuite/gcc.target/riscv/rvv/autovec/pr123022.c
+ c447bf3b1ca59703351696005c25a811  gcc/testsuite/gcc.target/riscv/rvv/autovec/pr123097-run.c
+ f7f343c3de4454209ad958bd70574bf9  gcc/testsuite/gcc.target/riscv/rvv/autovec/pr123097.c
  ee8bcba5f6876f2027f0f263f81465aa  gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-1.c
  7ff884bfa2e6cf9bc4c6172466538515  gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-10.c
  b2792e9264dcd6fa2e88f495d51677e6  gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-11.c
*************** a9e43e12d05f5060efb91812c5538d27  gcc/te
*** 99271,99276 ****
--- 99406,99412 ----
  9ad0b4eb2ccb28e0fd1adef5c8454588  gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-7.c
  324b3f01b2d22096ed23e1c7b389fd80  gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-8.c
  5690b06a34bd472837c2573a580ce080  gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-9.c
+ b9148e8a25b68a52c556bbef58f30e37  gcc/testsuite/gcc.target/riscv/rvv/autovec/subreg-extract.c
  3ec4558b8a9b8151a6ec061952ce0d1e  gcc/testsuite/gcc.target/riscv/rvv/autovec/template-1.h
  68af9e429e1d21a9b0a022aaea868104  gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop-1.c
  462e8176f898c1c5eb2f95c5289e157e  gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop-10.c
*************** d5db82e84e090e7af1a8e302f7933759  gcc/te
*** 100507,100513 ****
  c41b9a25857076a8b6c28a92df10b77d  gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32x_zvl256b-1.c
  abd8a3184e218e70a4a64ddd64e8be65  gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32x_zvl4096b-1.c
  7591e6439b1ce8bf6516a32d504618a5  gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32x_zvl512b-1.c
! 5e6f7d6b6f640248df93a502d81ed96f  gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d-1.c
  b127736d78362b7857b7b2c0aa215df9  gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d-2.c
  06a773055bb47a1a9d0026cb5a239ae1  gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d-3.c
  82c5727175f76a8933af14d4f269bdc4  gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d_zvl1024b-1.c
--- 100643,100649 ----
  c41b9a25857076a8b6c28a92df10b77d  gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32x_zvl256b-1.c
  abd8a3184e218e70a4a64ddd64e8be65  gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32x_zvl4096b-1.c
  7591e6439b1ce8bf6516a32d504618a5  gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32x_zvl512b-1.c
! e68d4be09ffa85175f231425fb911e14  gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d-1.c
  b127736d78362b7857b7b2c0aa215df9  gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d-2.c
  06a773055bb47a1a9d0026cb5a239ae1  gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d-3.c
  82c5727175f76a8933af14d4f269bdc4  gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d_zvl1024b-1.c
*************** f4b66618991adc6ed1836af6b7ab1696  gcc/te
*** 100517,100523 ****
  36da0e50a1f4295e4a69e2d8dacbffba  gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d_zvl256b-1.c
  6c64ac6da33d722229c95d58e2aa6a3e  gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d_zvl4096b-1.c
  f674e95fd20c15bbb4b89561a30bce95  gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d_zvl512b-1.c
! 96d7bd659933c8f23a8d6059fc78274d  gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64f-1.c
  ab3b34c3c66af1b657d522e1caceae51  gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64f-2.c
  e775fc2017ad37c7d2c4cfe4ae5b0515  gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64f-3.c
  5914484ae94b4c3fa439068a6ee9593c  gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64f_zvl1024b-1.c
--- 100653,100659 ----
  36da0e50a1f4295e4a69e2d8dacbffba  gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d_zvl256b-1.c
  6c64ac6da33d722229c95d58e2aa6a3e  gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d_zvl4096b-1.c
  f674e95fd20c15bbb4b89561a30bce95  gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d_zvl512b-1.c
! 5cda479569d800d05eef9efe149f1bf4  gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64f-1.c
  ab3b34c3c66af1b657d522e1caceae51  gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64f-2.c
  e775fc2017ad37c7d2c4cfe4ae5b0515  gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64f-3.c
  5914484ae94b4c3fa439068a6ee9593c  gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64f_zvl1024b-1.c
*************** cfeb2916d3c635fdc870fa4dd68db703  gcc/te
*** 101082,101088 ****
  7e4acf8a36d5832d7d5e91c74df1e724  gcc/testsuite/gcc.target/riscv/rvv/base/pr112431-19.c
  3e2ec7778c99a6a0261ab2f4a6450f3e  gcc/testsuite/gcc.target/riscv/rvv/base/pr112431-2.c
  1a7558800b040b8dda24bcc3d94f5729  gcc/testsuite/gcc.target/riscv/rvv/base/pr112431-20.c
! aa98c41a6ee8d307994d4aa833a1ff75  gcc/testsuite/gcc.target/riscv/rvv/base/pr112431-21.c
  ddfc52ce3e11b16f5826a17400d5173d  gcc/testsuite/gcc.target/riscv/rvv/base/pr112431-22.c
  01113869871bb1fbcb103fb4d9b60577  gcc/testsuite/gcc.target/riscv/rvv/base/pr112431-23.c
  dfb14b9db17d26fe2fff40418d1cf459  gcc/testsuite/gcc.target/riscv/rvv/base/pr112431-24.c
--- 101218,101224 ----
  7e4acf8a36d5832d7d5e91c74df1e724  gcc/testsuite/gcc.target/riscv/rvv/base/pr112431-19.c
  3e2ec7778c99a6a0261ab2f4a6450f3e  gcc/testsuite/gcc.target/riscv/rvv/base/pr112431-2.c
  1a7558800b040b8dda24bcc3d94f5729  gcc/testsuite/gcc.target/riscv/rvv/base/pr112431-20.c
! 096b804168636ee17c9d4636018e26fb  gcc/testsuite/gcc.target/riscv/rvv/base/pr112431-21.c
  ddfc52ce3e11b16f5826a17400d5173d  gcc/testsuite/gcc.target/riscv/rvv/base/pr112431-22.c
  01113869871bb1fbcb103fb4d9b60577  gcc/testsuite/gcc.target/riscv/rvv/base/pr112431-23.c
  dfb14b9db17d26fe2fff40418d1cf459  gcc/testsuite/gcc.target/riscv/rvv/base/pr112431-24.c
*************** a9bc35f3b8e2135b6e2d575d37dd20e7  gcc/te
*** 103659,103665 ****
  ef2c5743cfecad7fa099e99612f0f0e1  gcc/testsuite/gcc.target/s390/isfinite-isinf-isnormal-signbit-3.c
  2fac1f3d555a888fa224b855ee080ef3  gcc/testsuite/gcc.target/s390/isfinite-isinf-isnormal-signbit.h
  5ec66e2212ebc6c860d123f507d0b6bc  gcc/testsuite/gcc.target/s390/jump-label.c
! e24d2c019a37c569a797e81173782052  gcc/testsuite/gcc.target/s390/larl-1.c
  86858e91f5b4dabc479f75228a16d550  gcc/testsuite/gcc.target/s390/leaf-profile.c
  f13fa958f52666320ebd966fc9530e05  gcc/testsuite/gcc.target/s390/litpool-int.c
  25399ee14c48d99597fc401591d68286  gcc/testsuite/gcc.target/s390/litpool-r3-1.c
--- 103795,103801 ----
  ef2c5743cfecad7fa099e99612f0f0e1  gcc/testsuite/gcc.target/s390/isfinite-isinf-isnormal-signbit-3.c
  2fac1f3d555a888fa224b855ee080ef3  gcc/testsuite/gcc.target/s390/isfinite-isinf-isnormal-signbit.h
  5ec66e2212ebc6c860d123f507d0b6bc  gcc/testsuite/gcc.target/s390/jump-label.c
! 91bc2877aa0bfe7d8d59f1e2b0d68dbf  gcc/testsuite/gcc.target/s390/larl-1.c
  86858e91f5b4dabc479f75228a16d550  gcc/testsuite/gcc.target/s390/leaf-profile.c
  f13fa958f52666320ebd966fc9530e05  gcc/testsuite/gcc.target/s390/litpool-int.c
  25399ee14c48d99597fc401591d68286  gcc/testsuite/gcc.target/s390/litpool-r3-1.c
*************** f01a6228581302d6d97b59085e8b8b1a  gcc/te
*** 104440,104445 ****
--- 104576,104582 ----
  6eb5add3ca1c643966e1cb503a52ead4  gcc/testsuite/gcc.target/sh/pr54760-6.c
  591dd31cc0ab14f1cf2e4efd0c73a6c2  gcc/testsuite/gcc.target/sh/pr55146.c
  f347bb22f41ec16d4bc6301927325f40  gcc/testsuite/gcc.target/sh/pr55160.c
+ b7884938bd707424792dbcdd54c246cb  gcc/testsuite/gcc.target/sh/pr55212-c248.c
  8f717e44414a43985e9764ae6fd48b44  gcc/testsuite/gcc.target/sh/pr55303-1.c
  e1ee5790a1ff9502dcff1b9d308673c5  gcc/testsuite/gcc.target/sh/pr55303-2.c
  2e2164e7dcbf7f288bb8b6c95f7c502d  gcc/testsuite/gcc.target/sh/pr55303-3.c
*************** d3d333698144b6bad92425ebed117768  gcc/te
*** 110362,110367 ****
--- 110499,110505 ----
  e0fe6119bfcf724ee51375d3156cacc5  gcc/testsuite/gfortran.dg/associate_73.f90
  151edd623643e466e74fa24488fd3142  gcc/testsuite/gfortran.dg/associate_74.f90
  9324e6abeab7018b1551e0a075cd2085  gcc/testsuite/gfortran.dg/associate_75.f90
+ aa468db4416b89ec8f44889e6cc47748  gcc/testsuite/gfortran.dg/associate_76.f90
  3c2206420bb8717914aa447789b5f079  gcc/testsuite/gfortran.dg/associate_8.f03
  0406413659a92c10d44ed1f1576987b9  gcc/testsuite/gfortran.dg/associate_9.f03
  51f82584276ab8f411b8d9d7e84fadc8  gcc/testsuite/gfortran.dg/associated_1.f90
*************** d863afb920048efbca3bf6b678a61dec  gcc/te
*** 110522,110528 ****
  f98c4c5663f30de86f0afb3d79ad29d9  gcc/testsuite/gfortran.dg/bessel_4.f90
  7c6a0363c8e5760a8743dd93665ea8ac  gcc/testsuite/gfortran.dg/bessel_5.f90
  feb49f28f0ec043a30b1c7ae6bbf396b  gcc/testsuite/gfortran.dg/bessel_5_redux.f90
! cd4aa7232c928332e81cd4789dde35b5  gcc/testsuite/gfortran.dg/bessel_6.f90
  71cc71770bb1326fb30cecdef3599e69  gcc/testsuite/gfortran.dg/bessel_7.f90
  9969185b5b657469b14a9f67f9a454ce  gcc/testsuite/gfortran.dg/besxy.f90
  93acf2e57d0045b0633aab0d87f61c61  gcc/testsuite/gfortran.dg/bind-c-char-descr.f90
--- 110660,110666 ----
  f98c4c5663f30de86f0afb3d79ad29d9  gcc/testsuite/gfortran.dg/bessel_4.f90
  7c6a0363c8e5760a8743dd93665ea8ac  gcc/testsuite/gfortran.dg/bessel_5.f90
  feb49f28f0ec043a30b1c7ae6bbf396b  gcc/testsuite/gfortran.dg/bessel_5_redux.f90
! 1ca68baec1ccf4598573d4e7df804d39  gcc/testsuite/gfortran.dg/bessel_6.f90
  71cc71770bb1326fb30cecdef3599e69  gcc/testsuite/gfortran.dg/bessel_7.f90
  9969185b5b657469b14a9f67f9a454ce  gcc/testsuite/gfortran.dg/besxy.f90
  93acf2e57d0045b0633aab0d87f61c61  gcc/testsuite/gfortran.dg/bind-c-char-descr.f90
*************** a55e030873dd3ed21b29b10669bfe719  gcc/te
*** 110701,110707 ****
  a2f76eca5ccc5ab54f50921f58e74199  gcc/testsuite/gfortran.dg/bound_5.f90
  a10bdff349043061c24ed4617b114c28  gcc/testsuite/gfortran.dg/bound_6.f90
  f36c2ee69da3a20951ff618d8c153000  gcc/testsuite/gfortran.dg/bound_7.f90
! 79ae6408deb6de8873553a468eefd03c  gcc/testsuite/gfortran.dg/bound_8.f90
  20b4378ec5d7f67596986f854f336780  gcc/testsuite/gfortran.dg/bound_9.f90
  a5e7c88c753868b606e43c1faa6f8b5f  gcc/testsuite/gfortran.dg/bound_resolve_after_error_1.f90
  c790ba1b682d5921194128ba48f39633  gcc/testsuite/gfortran.dg/bound_simplification_1.f90
--- 110839,110845 ----
  a2f76eca5ccc5ab54f50921f58e74199  gcc/testsuite/gfortran.dg/bound_5.f90
  a10bdff349043061c24ed4617b114c28  gcc/testsuite/gfortran.dg/bound_6.f90
  f36c2ee69da3a20951ff618d8c153000  gcc/testsuite/gfortran.dg/bound_7.f90
! a4a459acf190f70dd621725e76845ffe  gcc/testsuite/gfortran.dg/bound_8.f90
  20b4378ec5d7f67596986f854f336780  gcc/testsuite/gfortran.dg/bound_9.f90
  a5e7c88c753868b606e43c1faa6f8b5f  gcc/testsuite/gfortran.dg/bound_resolve_after_error_1.f90
  c790ba1b682d5921194128ba48f39633  gcc/testsuite/gfortran.dg/bound_simplification_1.f90
*************** ac59a53542ba1c45e3d363202502b8d7  gcc/te
*** 111522,111528 ****
  67aaadc572d2c00aa2d3389f87f0bd5d  gcc/testsuite/gfortran.dg/coarray_11.f90
  7e3b8c86ae974b8e72515cbd7d6243d8  gcc/testsuite/gfortran.dg/coarray_12.f90
  153a17a1d1205d1ac64bf6bbb965d841  gcc/testsuite/gfortran.dg/coarray_13.f90
! e08486b636a2e274b143c8af55f6777e  gcc/testsuite/gfortran.dg/coarray_14.f90
  3f13567f9ad391e0016c04e83d62970f  gcc/testsuite/gfortran.dg/coarray_15.f90
  c6a0c1d2cb2a007db6f999e0e1fccf1f  gcc/testsuite/gfortran.dg/coarray_16.f90
  f3811361487b4309fbf46c6f31aefaa2  gcc/testsuite/gfortran.dg/coarray_17.f90
--- 111660,111666 ----
  67aaadc572d2c00aa2d3389f87f0bd5d  gcc/testsuite/gfortran.dg/coarray_11.f90
  7e3b8c86ae974b8e72515cbd7d6243d8  gcc/testsuite/gfortran.dg/coarray_12.f90
  153a17a1d1205d1ac64bf6bbb965d841  gcc/testsuite/gfortran.dg/coarray_13.f90
! 863fbb85aa43fe72968b90a6746cc6e8  gcc/testsuite/gfortran.dg/coarray_14.f90
  3f13567f9ad391e0016c04e83d62970f  gcc/testsuite/gfortran.dg/coarray_15.f90
  c6a0c1d2cb2a007db6f999e0e1fccf1f  gcc/testsuite/gfortran.dg/coarray_16.f90
  f3811361487b4309fbf46c6f31aefaa2  gcc/testsuite/gfortran.dg/coarray_17.f90
*************** d9dcad9e03bd8c27d5f76eaa4cf71a0e  gcc/te
*** 112545,112551 ****
  debb6284910bc9893ee8d64655d67794  gcc/testsuite/gfortran.dg/equiv_pure.f90
  7068ea1b9ef6f4e1c0602de0112c99c8  gcc/testsuite/gfortran.dg/equiv_substr.f90
  1a93c19b7b17152e8d50abaa1075e512  gcc/testsuite/gfortran.dg/erf.f90
! eb8b6bf7208f1b2c958420a7c10478b2  gcc/testsuite/gfortran.dg/erf_2.F90
  a8fc794bdc228830fdce4b036804b410  gcc/testsuite/gfortran.dg/erf_3.F90
  4896a13f6fa4af7bce5540bb1d7edf28  gcc/testsuite/gfortran.dg/erfc_scaled_1.f90
  6ff6465694368d012e66b39c130fe7ae  gcc/testsuite/gfortran.dg/erfc_scaled_2.f90
--- 112683,112689 ----
  debb6284910bc9893ee8d64655d67794  gcc/testsuite/gfortran.dg/equiv_pure.f90
  7068ea1b9ef6f4e1c0602de0112c99c8  gcc/testsuite/gfortran.dg/equiv_substr.f90
  1a93c19b7b17152e8d50abaa1075e512  gcc/testsuite/gfortran.dg/erf.f90
! 13db7911403b37123bca161c1962ab25  gcc/testsuite/gfortran.dg/erf_2.F90
  a8fc794bdc228830fdce4b036804b410  gcc/testsuite/gfortran.dg/erf_3.F90
  4896a13f6fa4af7bce5540bb1d7edf28  gcc/testsuite/gfortran.dg/erfc_scaled_1.f90
  6ff6465694368d012e66b39c130fe7ae  gcc/testsuite/gfortran.dg/erfc_scaled_2.f90
*************** f8465776106b63fb5b5ceb95fe4f98f6  gcc/te
*** 113313,113319 ****
  13c4667263e4bb4a1bccbfc14139aa60  gcc/testsuite/gfortran.dg/goacc/uninit-if-clause.f95
  cc049d7a09437572cf0153480f72863e  gcc/testsuite/gfortran.dg/goacc/uninit-use-device-clause.f95
  e5de83f3c72df9c91e2516026a10fd5c  gcc/testsuite/gfortran.dg/goacc/update-if_present-1.f90
! 53b0b25c4ac601eb1c5d6d7b1c2e6fd3  gcc/testsuite/gfortran.dg/goacc/update-if_present-2.f90
  5c6b557fbcefd15ad6ec6ef08ade9d19  gcc/testsuite/gfortran.dg/goacc/update.f95
  e9972505e1a87fdeda00b94d99cf711b  gcc/testsuite/gfortran.dg/goacc/vector_length.f90
  d09b6d0bd3c55d3b99ebe64fe2ee3d04  gcc/testsuite/gfortran.dg/goacc/wait.f90
--- 113451,113457 ----
  13c4667263e4bb4a1bccbfc14139aa60  gcc/testsuite/gfortran.dg/goacc/uninit-if-clause.f95
  cc049d7a09437572cf0153480f72863e  gcc/testsuite/gfortran.dg/goacc/uninit-use-device-clause.f95
  e5de83f3c72df9c91e2516026a10fd5c  gcc/testsuite/gfortran.dg/goacc/update-if_present-1.f90
! ec6f1af4201fcc3c0c1471347159a131  gcc/testsuite/gfortran.dg/goacc/update-if_present-2.f90
  5c6b557fbcefd15ad6ec6ef08ade9d19  gcc/testsuite/gfortran.dg/goacc/update.f95
  e9972505e1a87fdeda00b94d99cf711b  gcc/testsuite/gfortran.dg/goacc/vector_length.f90
  d09b6d0bd3c55d3b99ebe64fe2ee3d04  gcc/testsuite/gfortran.dg/goacc/wait.f90
*************** f1a766f8696c6d4c654b209e78e352ce  gcc/te
*** 113438,113443 ****
--- 113576,113582 ----
  5e6389d0abcd7c2f90b6a1cd61ef9bc3  gcc/testsuite/gfortran.dg/gomp/assume-3.f90
  4bee16d209be417ce87c236f99f90dfb  gcc/testsuite/gfortran.dg/gomp/assume-4.f90
  0812a6a2cc0b6a44ec3668a36bd6b33b  gcc/testsuite/gfortran.dg/gomp/assume-5.f90
+ 30dac29cc0761f5fc713cce3937c6a81  gcc/testsuite/gfortran.dg/gomp/assume-6.f90
  3b3dfd23626e235883bd65611239768d  gcc/testsuite/gfortran.dg/gomp/assumes-1.f90
  20f82388ecca25bd046552320ab24d99  gcc/testsuite/gfortran.dg/gomp/assumes-2.f90
  35cd43e5e50dfb825738cd8d77ba5b24  gcc/testsuite/gfortran.dg/gomp/atomic-10.f90
*************** f8e40f23828c760759b3893792acb659  gcc/te
*** 113705,113712 ****
  35c099331d2ac9c6383bb03bcf2fab33  gcc/testsuite/gfortran.dg/gomp/order-5.f90
  901de0f48b4103e45783c545e17e9697  gcc/testsuite/gfortran.dg/gomp/order-6.f90
  5aee86e6d3f0327d9fcb22e4e1a7d079  gcc/testsuite/gfortran.dg/gomp/order-7.f90
! 1df5307e687b9a678831469ec20695e5  gcc/testsuite/gfortran.dg/gomp/order-8.f90
! 054c5c2350f2722c8a722ca2a63bed3f  gcc/testsuite/gfortran.dg/gomp/order-9.f90
  9f9f67726dedce0b7ada760b7075ff24  gcc/testsuite/gfortran.dg/gomp/parallel-master-1.f90
  52a2936d315828f32d6e92776c565212  gcc/testsuite/gfortran.dg/gomp/parallel-master-2.f90
  583f15b294093b280f67c26128dd1e2e  gcc/testsuite/gfortran.dg/gomp/polymorphic-mapping-1.f90
--- 113844,113851 ----
  35c099331d2ac9c6383bb03bcf2fab33  gcc/testsuite/gfortran.dg/gomp/order-5.f90
  901de0f48b4103e45783c545e17e9697  gcc/testsuite/gfortran.dg/gomp/order-6.f90
  5aee86e6d3f0327d9fcb22e4e1a7d079  gcc/testsuite/gfortran.dg/gomp/order-7.f90
! 90ec41dc331ac7669999c960eda7265b  gcc/testsuite/gfortran.dg/gomp/order-8.f90
! 41cb4c2035ba0db4f124531a1646d6ab  gcc/testsuite/gfortran.dg/gomp/order-9.f90
  9f9f67726dedce0b7ada760b7075ff24  gcc/testsuite/gfortran.dg/gomp/parallel-master-1.f90
  52a2936d315828f32d6e92776c565212  gcc/testsuite/gfortran.dg/gomp/parallel-master-2.f90
  583f15b294093b280f67c26128dd1e2e  gcc/testsuite/gfortran.dg/gomp/polymorphic-mapping-1.f90
*************** b3d1280c39c6cae9dddab498b1e1eeb4  gcc/te
*** 113914,113919 ****
--- 114053,114059 ----
  500a5f460107c8722e23208574b65d09  gcc/testsuite/gfortran.dg/gomp/target-device-ancestor-4.f90
  7ec834f632faabec913cbd38f2862fb3  gcc/testsuite/gfortran.dg/gomp/target-device-ancestor-5.f90
  1577072db3f937bbd080bc7c33395c3b  gcc/testsuite/gfortran.dg/gomp/target-device-ancestor-6.f90
+ d2ca8da69a3b478409a3711ceaa62604  gcc/testsuite/gfortran.dg/gomp/target-device-type-1.f90
  a81fcf292a341e29920f0576722dfd3e  gcc/testsuite/gfortran.dg/gomp/target-enter-exit-data.f90
  874160eb3e56004e967fed8574857c36  gcc/testsuite/gfortran.dg/gomp/target-exit-data.f90
  255df1293a7e993064b5f2531dd1a039  gcc/testsuite/gfortran.dg/gomp/target-has-device-addr-1.f90
*************** f9b5b9b94495a638b782238b568ce680  gcc/te
*** 114504,114512 ****
  666e3cc15f36ed1a1563118d5ffb6869  gcc/testsuite/gfortran.dg/int_range_io_1.f90
  8ad0e5ed51c054fefd4a1619ce84a9e3  gcc/testsuite/gfortran.dg/integer_exponentiation_1.f90
  a784a7cc799cc5fc849a973a4ebff429  gcc/testsuite/gfortran.dg/integer_exponentiation_2.f90
! c7199a7f7c51b93670e965da1d668e97  gcc/testsuite/gfortran.dg/integer_exponentiation_3.F90
  ae15efd6a7c1892fccaf99f1b6fa020b  gcc/testsuite/gfortran.dg/integer_exponentiation_4.f90
! ce503c26e91680933d6b2da36dae11d3  gcc/testsuite/gfortran.dg/integer_exponentiation_5.F90
  5436c9710c4dbacc08026642a5d88b2d  gcc/testsuite/gfortran.dg/integer_exponentiation_6.F90
  0015da9ffa828cd555fcffad1c400715  gcc/testsuite/gfortran.dg/integer_exponentiation_7.f90
  05d602dc265060112a645567473b9a65  gcc/testsuite/gfortran.dg/integer_plus.f90
--- 114644,114652 ----
  666e3cc15f36ed1a1563118d5ffb6869  gcc/testsuite/gfortran.dg/int_range_io_1.f90
  8ad0e5ed51c054fefd4a1619ce84a9e3  gcc/testsuite/gfortran.dg/integer_exponentiation_1.f90
  a784a7cc799cc5fc849a973a4ebff429  gcc/testsuite/gfortran.dg/integer_exponentiation_2.f90
! 01de1bbadea2c30ff3054eaa5deb9494  gcc/testsuite/gfortran.dg/integer_exponentiation_3.F90
  ae15efd6a7c1892fccaf99f1b6fa020b  gcc/testsuite/gfortran.dg/integer_exponentiation_4.f90
! b9c90ea6ebc627389cab2b42a9fc8dea  gcc/testsuite/gfortran.dg/integer_exponentiation_5.F90
  5436c9710c4dbacc08026642a5d88b2d  gcc/testsuite/gfortran.dg/integer_exponentiation_6.F90
  0015da9ffa828cd555fcffad1c400715  gcc/testsuite/gfortran.dg/integer_exponentiation_7.f90
  05d602dc265060112a645567473b9a65  gcc/testsuite/gfortran.dg/integer_plus.f90
*************** e79a5fff5c4841ba8e2da41f54be1c1c  gcc/te
*** 115940,115948 ****
--- 116080,116091 ----
  b1cb2c9a52574c2df5df49bd13ee7e5d  gcc/testsuite/gfortran.dg/pr120196.f90
  94f286710243a0388de6f82a32d72ca5  gcc/testsuite/gfortran.dg/pr120743.f90
  9a63937be6d5e03574fd9c46968454c5  gcc/testsuite/gfortran.dg/pr121234.f90
+ a01a62a01e9e7263ce5c3eb6b06e96a7  gcc/testsuite/gfortran.dg/pr121472.f90
+ 2c5769bb5fd02bd8b8791d960937aa78  gcc/testsuite/gfortran.dg/pr121475.f90
  6be9000a862f8c64a384c1727d879f04  gcc/testsuite/gfortran.dg/pr121627.f90
  6df685f9b4cb8f7874082b4e9d9e61f5  gcc/testsuite/gfortran.dg/pr122513-2.f90
  b6e7e7e8bea9878d7980ddcd5a97c5f5  gcc/testsuite/gfortran.dg/pr122513.f90
+ b9c77c8cd78fcd9e57fbfafe732a8c95  gcc/testsuite/gfortran.dg/pr122936.f90
  984f8307f36d56a0b48b5acce2dd5eb5  gcc/testsuite/gfortran.dg/pr12884.f
  64075248b9d1bffd6f380bb4e2a6eae0  gcc/testsuite/gfortran.dg/pr15129.f90
  2b5f18b773a5db29b0a2ee2d8cce767c  gcc/testsuite/gfortran.dg/pr15140.f90
*************** cd47c5f771e296971301643af5583dfa  gcc/te
*** 116580,116585 ****
--- 116723,116730 ----
  8623fdd6c6daabe9a4f011dbfe739aa7  gcc/testsuite/gfortran.dg/pr92277.f90
  f9f3f23d1f0e555393704aacc1883399  gcc/testsuite/gfortran.dg/pr92537.f90
  046e4aaa6db5ee0c20856d4a366b6343  gcc/testsuite/gfortran.dg/pr92586.f90
+ 32cf1aafbe9511dbafe4de8d2ac60d97  gcc/testsuite/gfortran.dg/pr92613.f90
+ 16ef421144d4e1c92ef3108573f95612  gcc/testsuite/gfortran.dg/pr92613_2.f90
  7383008a151433faa521410955d94a9f  gcc/testsuite/gfortran.dg/pr92629.f90
  4f42dad4b149f18ca843630273713f7d  gcc/testsuite/gfortran.dg/pr92781.f90
  4dd22e19ac67028e19b5789647a9a64b  gcc/testsuite/gfortran.dg/pr92874.f90
*************** d1fb25c2d89c26a98edcfffc14882c3e  gcc/te
*** 116955,116961 ****
  5d7bbbfcefc1b5f07177f63161d102c1  gcc/testsuite/gfortran.dg/protected_5.f90
  ddf6a96210acd9846d96c96f4d91e038  gcc/testsuite/gfortran.dg/protected_6.f90
  52dff839978be3dcf2e894769b9a6a7c  gcc/testsuite/gfortran.dg/protected_7.f90
! 8823218c8e39e313a365821aff2faabe  gcc/testsuite/gfortran.dg/protected_8.f90
  73ab7ba9b0a193e7d3835ba4228e5045  gcc/testsuite/gfortran.dg/protected_9.f90
  9bd44f03cb1f3b37599ac931fdefe6cc  gcc/testsuite/gfortran.dg/ptr-func-1.f90
  b6c22a1a69dfaeda3ed576a61060580d  gcc/testsuite/gfortran.dg/ptr-func-2.f90
--- 117100,117106 ----
  5d7bbbfcefc1b5f07177f63161d102c1  gcc/testsuite/gfortran.dg/protected_5.f90
  ddf6a96210acd9846d96c96f4d91e038  gcc/testsuite/gfortran.dg/protected_6.f90
  52dff839978be3dcf2e894769b9a6a7c  gcc/testsuite/gfortran.dg/protected_7.f90
! cb43adc087dd83db2ebabfeed3100cf7  gcc/testsuite/gfortran.dg/protected_8.f90
  73ab7ba9b0a193e7d3835ba4228e5045  gcc/testsuite/gfortran.dg/protected_9.f90
  9bd44f03cb1f3b37599ac931fdefe6cc  gcc/testsuite/gfortran.dg/ptr-func-1.f90
  b6c22a1a69dfaeda3ed576a61060580d  gcc/testsuite/gfortran.dg/ptr-func-2.f90
*************** db7436cc6948424e65700d7b6597862f  gcc/te
*** 119656,119661 ****
--- 119801,119807 ----
  ecdbb910ccdbf4a9ff9978bb73c88f41  gcc/testsuite/gm2/pim/fail/badpointer4.mod
  3b70d947b4ea67fb7afcaddfd1ba2418  gcc/testsuite/gm2/pim/fail/badprocbool.mod
  1a8f950ee43a0dfff7a19a75a075d9c8  gcc/testsuite/gm2/pim/fail/badproccard.mod
+ b435128d6ff9a0301472d7f603852478  gcc/testsuite/gm2/pim/fail/badprocedure.mod
  07d625c5434862792bce301cb2616c92  gcc/testsuite/gm2/pim/fail/badprocint.mod
  dbe65c434f0a6b28ab79a771b3662b3f  gcc/testsuite/gm2/pim/fail/badprocint2.mod
  212d8402f510392bda8bdfb7796944e8  gcc/testsuite/gm2/pim/fail/badproctype.mod
*************** f4f8d23df0f1a9b99b0109a940ba8a4e  gcc/te
*** 120420,120426 ****
  4dac8aa23106e9b75cfc21b28380dc08  gcc/testsuite/gm2/pimcoroutines/pass/pimcoroutines-pass.exp
  81314ef63e8b11463cd34b34274c1b57  gcc/testsuite/gm2/pimcoroutines/run/pass/pimcoroutines-run-pass.exp
  c953eb0b38fdc8c2f9526508f1594b00  gcc/testsuite/gm2/pimcoroutines/run/pass/testtime.mod
! 941a3483c8a10137ae148130da144c48  gcc/testsuite/gm2/pimlib/base/run/pass/FIO.mod
  0de2a4029cfe9e1ca579c68f9596e248  gcc/testsuite/gm2/pimlib/base/run/pass/StrLib.mod
  d33f75933ba54ebf6d93f43daa52e551  gcc/testsuite/gm2/pimlib/base/run/pass/pimlib-base-run-pass.exp
  0dcaef09d969b7670f7ae3450706ad2a  gcc/testsuite/gm2/pimlib/base/run/pass/testconvert.mod
--- 120566,120572 ----
  4dac8aa23106e9b75cfc21b28380dc08  gcc/testsuite/gm2/pimcoroutines/pass/pimcoroutines-pass.exp
  81314ef63e8b11463cd34b34274c1b57  gcc/testsuite/gm2/pimcoroutines/run/pass/pimcoroutines-run-pass.exp
  c953eb0b38fdc8c2f9526508f1594b00  gcc/testsuite/gm2/pimcoroutines/run/pass/testtime.mod
! e6be75d76d0d4da5c5d556f42c3a0561  gcc/testsuite/gm2/pimlib/base/run/pass/FIO.mod
  0de2a4029cfe9e1ca579c68f9596e248  gcc/testsuite/gm2/pimlib/base/run/pass/StrLib.mod
  d33f75933ba54ebf6d93f43daa52e551  gcc/testsuite/gm2/pimlib/base/run/pass/pimlib-base-run-pass.exp
  0dcaef09d969b7670f7ae3450706ad2a  gcc/testsuite/gm2/pimlib/base/run/pass/testconvert.mod
*************** b434571f14dc637407f321e185093bce  gcc/te
*** 120455,120460 ****
--- 120601,120607 ----
  12b74f13ad655f02d6d03cd3afd8386b  gcc/testsuite/gm2/pimlib/run/pass/pimlib-run-pass.exp
  19fbabb90573435e066566857d602ff9  gcc/testsuite/gm2/pimlib/run/pass/test.c
  eb658a5ad91f33a16115753df34c87d4  gcc/testsuite/gm2/pimlib/run/pass/testchar.mod
+ 0df86f87c43328c4bf5d097adbd8d3ca  gcc/testsuite/gm2/pimlib/run/pass/testclose.mod
  e1370374caa4a3a31fefd6609cc7df7f  gcc/testsuite/gm2/pimlib/run/pass/testdelete.mod
  248b32cb4654932e670ca1f4528b0e6d  gcc/testsuite/gm2/pimlib/run/pass/testfiobinary.mod
  e5d5befc7aececd211929f46bd11fdda  gcc/testsuite/gm2/pimlib/run/pass/testgetopt.mod
*************** c0f02b651aa311a5b5cddd400f9701ed  gcc/te
*** 122076,122081 ****
--- 122223,122230 ----
  fb19807d91f445350623ae19eb1b5aee  gcc/testsuite/gnat.dg/lto28_pkg3.ads
  d38a63c50972ebf0d60bc6959e5d130f  gcc/testsuite/gnat.dg/lto29.adb
  92924880135ec84fd65e4fecf6055807  gcc/testsuite/gnat.dg/lto29_pkg.ads
+ 0bb4f053befcf73a4d457f035ee97b6a  gcc/testsuite/gnat.dg/lto30.adb
+ 5889bf52461acb4efaa37c6ba94a8f31  gcc/testsuite/gnat.dg/lto30.ads
  2acb4cc31994f1569a3db6ac6613928d  gcc/testsuite/gnat.dg/lto4.adb
  9b38247c8e825c514f87e2965d931dad  gcc/testsuite/gnat.dg/lto4.ads
  959fb8bdf4cd1c34347ecfbab19ea60b  gcc/testsuite/gnat.dg/lto5.adb
*************** fde5d5ed0c271572ac7da0e31e22bc5c  gcc/te
*** 122623,122628 ****
--- 122772,122779 ----
  85a55db824671af62dedb2987941d2fe  gcc/testsuite/gnat.dg/reduce1.adb
  0b27bcc5788ce003bc049b34d20d5c88  gcc/testsuite/gnat.dg/reduce2.adb
  cc69f06d5cf4cbc8c70e417d3db3148b  gcc/testsuite/gnat.dg/reduce3.adb
+ 5870b8cebdd6ce91693a485c5a6854d5  gcc/testsuite/gnat.dg/reduce4.adb
+ 001425eca43e1ece9e65dd7929459079  gcc/testsuite/gnat.dg/reduce5.adb
  50be8d98f4f9ac99d64926a10596a2df  gcc/testsuite/gnat.dg/ref_type.adb
  5457827e708b7bfc92ffe5610655a443  gcc/testsuite/gnat.dg/ref_type.ads
  222b5d10f23a2e8e8a5e4d41e86e66ed  gcc/testsuite/gnat.dg/regpat1.adb
*************** d19a0449bac1fb497429a88904f3d658  gcc/te
*** 125508,125514 ****
  50c0f03762d429c13fd0302c79d90157  gcc/testsuite/go.test/test/varinit.go
  6447a99ae1e2eec266af1ceab6a7343c  gcc/testsuite/go.test/test/zerodivide.go
  340e08c9aef97a2da8f4cd4568d52675  gcc/testsuite/jit.dg/add-driver-options-testlib.c
! cc837bfe74ef7da8c6b5737b231a2994  gcc/testsuite/jit.dg/all-non-failing-tests.h
  7bc42e89ae77872c8fc581b4babf1832  gcc/testsuite/jit.dg/create-code-for-hello-world-executable.h
  6599d673695ac45c69f897e7b9643cdb  gcc/testsuite/jit.dg/harness.h
  c2ab8a50f6099a876788d5e2b281249b  gcc/testsuite/jit.dg/jit.exp
--- 125659,125665 ----
  50c0f03762d429c13fd0302c79d90157  gcc/testsuite/go.test/test/varinit.go
  6447a99ae1e2eec266af1ceab6a7343c  gcc/testsuite/go.test/test/zerodivide.go
  340e08c9aef97a2da8f4cd4568d52675  gcc/testsuite/jit.dg/add-driver-options-testlib.c
! fef92b23b20b3d99fdd95fa493cfd0bb  gcc/testsuite/jit.dg/all-non-failing-tests.h
  7bc42e89ae77872c8fc581b4babf1832  gcc/testsuite/jit.dg/create-code-for-hello-world-executable.h
  6599d673695ac45c69f897e7b9643cdb  gcc/testsuite/jit.dg/harness.h
  c2ab8a50f6099a876788d5e2b281249b  gcc/testsuite/jit.dg/jit.exp
*************** c1c4ffe41bbf76d4a61fec8d9b42486c  gcc/te
*** 125538,125544 ****
  af0a18ef8912906bb36ca88219c06667  gcc/testsuite/jit.dg/test-calling-external-function.c
  fcf20b943f3e9affe23adec9277064a7  gcc/testsuite/jit.dg/test-calling-function-ptr.c
  e3bf5c17797aeaea60953345b0ec836b  gcc/testsuite/jit.dg/test-cast.c
! 1abc657df5f9cfb2b57bf23048e54d17  gcc/testsuite/jit.dg/test-cold-attribute.c
  dc3f5924516f317d0e822022186a89d9  gcc/testsuite/jit.dg/test-combination.c
  2e035396a65d6176ba9798f667c5621a  gcc/testsuite/jit.dg/test-compile-to-assembler.c
  897c5ab27b1fd560e0e9f30525797a81  gcc/testsuite/jit.dg/test-compile-to-dynamic-library.c
--- 125689,125695 ----
  af0a18ef8912906bb36ca88219c06667  gcc/testsuite/jit.dg/test-calling-external-function.c
  fcf20b943f3e9affe23adec9277064a7  gcc/testsuite/jit.dg/test-calling-function-ptr.c
  e3bf5c17797aeaea60953345b0ec836b  gcc/testsuite/jit.dg/test-cast.c
! 6bfe3202df4a59189a757d8df0af0d9d  gcc/testsuite/jit.dg/test-cold-attribute.c
  dc3f5924516f317d0e822022186a89d9  gcc/testsuite/jit.dg/test-combination.c
  2e035396a65d6176ba9798f667c5621a  gcc/testsuite/jit.dg/test-compile-to-assembler.c
  897c5ab27b1fd560e0e9f30525797a81  gcc/testsuite/jit.dg/test-compile-to-dynamic-library.c
*************** e309c53b14c724939a1564046c6a5df2  gcc/te
*** 125704,125711 ****
  96ac85af1dde837e4f4e2444d083cf22  gcc/testsuite/jit.dg/test-volatile.c
  9da1409ac5b1dea56852239c56e8fa5f  gcc/testsuite/jit.dg/test-weak-attribute.c
  6477c66fcebff4d502d26e2d247251ce  gcc/testsuite/jit.dg/verify-dynamic-library.c
! d59035ff29befc98b162474612dc7eb7  gcc/testsuite/lib/algol68-dg.exp
! e9763edbe4ef9fce0301a298dd9e624a  gcc/testsuite/lib/algol68-torture.exp
  d9262cbfe00f97eb82467b3a71cbd0d8  gcc/testsuite/lib/algol68.exp
  d97cb720c01f1bc719687ebc9f26e19b  gcc/testsuite/lib/asan-dg.exp
  007a28907562dba3b6d50680bee1d7a5  gcc/testsuite/lib/atomic-dg.exp
--- 125855,125862 ----
  96ac85af1dde837e4f4e2444d083cf22  gcc/testsuite/jit.dg/test-volatile.c
  9da1409ac5b1dea56852239c56e8fa5f  gcc/testsuite/jit.dg/test-weak-attribute.c
  6477c66fcebff4d502d26e2d247251ce  gcc/testsuite/jit.dg/verify-dynamic-library.c
! f68219781327b313f412eff49877ee80  gcc/testsuite/lib/algol68-dg.exp
! 3bb78ffc63d33419293bae22be8e9d0c  gcc/testsuite/lib/algol68-torture.exp
  d9262cbfe00f97eb82467b3a71cbd0d8  gcc/testsuite/lib/algol68.exp
  d97cb720c01f1bc719687ebc9f26e19b  gcc/testsuite/lib/asan-dg.exp
  007a28907562dba3b6d50680bee1d7a5  gcc/testsuite/lib/atomic-dg.exp
*************** e7c501da98d4a79a382f65d5a172d7b5  gcc/te
*** 125757,125763 ****
  368db59d1d824d7b0746d902abd46598  gcc/testsuite/lib/objc-torture.exp
  0cb9e8b4aaa52806bd9e000fbb88335e  gcc/testsuite/lib/objc.exp
  73f8e7fcba76f3bb5458e5c95e1a21d5  gcc/testsuite/lib/options.exp
! 22774fd5371b440075969ba8c2ea47a4  gcc/testsuite/lib/plugin-support.exp
  314adb1e13c4c51727a909aceee45a3a  gcc/testsuite/lib/print-stack.exp
  4e295ef8c79574b6d01edf397fa2ba08  gcc/testsuite/lib/profopt.exp
  d7307d6eecb64fbf8475c3fba44ea3ee  gcc/testsuite/lib/prune.exp
--- 125908,125914 ----
  368db59d1d824d7b0746d902abd46598  gcc/testsuite/lib/objc-torture.exp
  0cb9e8b4aaa52806bd9e000fbb88335e  gcc/testsuite/lib/objc.exp
  73f8e7fcba76f3bb5458e5c95e1a21d5  gcc/testsuite/lib/options.exp
! 5c530c179d98a9ccee9423414a791569  gcc/testsuite/lib/plugin-support.exp
  314adb1e13c4c51727a909aceee45a3a  gcc/testsuite/lib/print-stack.exp
  4e295ef8c79574b6d01edf397fa2ba08  gcc/testsuite/lib/profopt.exp
  d7307d6eecb64fbf8475c3fba44ea3ee  gcc/testsuite/lib/prune.exp
*************** eb1595e729e2eaac81c7ffe330d8f24e  gcc/te
*** 125784,125790 ****
  f7940f4f8c24d9f0bf4d062473f55777  gcc/testsuite/lib/scanwpaipa.exp
  23e89ca46b182663a4139064b179545f  gcc/testsuite/lib/target-libpath.exp
  d9a6726c38c578e1cd46631ee7f92d0a  gcc/testsuite/lib/target-supports-dg.exp
! 33fd07e7e0080132e5442fc824aeeea6  gcc/testsuite/lib/target-supports.exp
  cfe4a2f0a83382048de060dc6669cbb9  gcc/testsuite/lib/target-utils.exp
  e45ee1a35539730bd823a310ad306ded  gcc/testsuite/lib/timeout-dg.exp
  b755c82fb5ee43ef6c852f23fbdc8704  gcc/testsuite/lib/timeout.exp
--- 125935,125941 ----
  f7940f4f8c24d9f0bf4d062473f55777  gcc/testsuite/lib/scanwpaipa.exp
  23e89ca46b182663a4139064b179545f  gcc/testsuite/lib/target-libpath.exp
  d9a6726c38c578e1cd46631ee7f92d0a  gcc/testsuite/lib/target-supports-dg.exp
! 55720f9818a46917be7dcef4eee85d58  gcc/testsuite/lib/target-supports.exp
  cfe4a2f0a83382048de060dc6669cbb9  gcc/testsuite/lib/target-utils.exp
  e45ee1a35539730bd823a310ad306ded  gcc/testsuite/lib/timeout-dg.exp
  b755c82fb5ee43ef6c852f23fbdc8704  gcc/testsuite/lib/timeout.exp
*************** bb8ccf448c201adbf05356ac551899fb  gcc/te
*** 126010,126016 ****
  1c39d0d9e54d7c124e4e36d7ac5c8033  gcc/testsuite/obj-c++.dg/objc-gc-3.mm
  bd3b42583db47ebcc7fac037f85f00ed  gcc/testsuite/obj-c++.dg/overload-1.mm
  e84cd2640f9e4f66e445c60cecc3bfd2  gcc/testsuite/obj-c++.dg/plugin/diagnostic-test-expressions-1.mm
! e675024c80eaa9ab18ae35d94d13fe95  gcc/testsuite/obj-c++.dg/plugin/plugin.exp
  a1ff757de40d44fb3868d406ed01c4eb  gcc/testsuite/obj-c++.dg/pr101666-0.mm
  339a76362d0703671d6ddc07066f2d95  gcc/testsuite/obj-c++.dg/pr101666-1.mm
  7b3270d7548d00c42ba59f5769932087  gcc/testsuite/obj-c++.dg/pr101666.inc
--- 126161,126167 ----
  1c39d0d9e54d7c124e4e36d7ac5c8033  gcc/testsuite/obj-c++.dg/objc-gc-3.mm
  bd3b42583db47ebcc7fac037f85f00ed  gcc/testsuite/obj-c++.dg/overload-1.mm
  e84cd2640f9e4f66e445c60cecc3bfd2  gcc/testsuite/obj-c++.dg/plugin/diagnostic-test-expressions-1.mm
! b1bd6dd5e55d5506e09743a335abd943  gcc/testsuite/obj-c++.dg/plugin/plugin.exp
  a1ff757de40d44fb3868d406ed01c4eb  gcc/testsuite/obj-c++.dg/pr101666-0.mm
  339a76362d0703671d6ddc07066f2d95  gcc/testsuite/obj-c++.dg/pr101666-1.mm
  7b3270d7548d00c42ba59f5769932087  gcc/testsuite/obj-c++.dg/pr101666.inc
*************** d6bb76e151385d5dcc0bccac5e79fa6e  gcc/te
*** 126511,126517 ****
  71da4e106e38b3671b4f4ae8a237e55f  gcc/testsuite/objc.dg/pch/interface-1.m
  f3149d9c99bcd6859904911024284a3e  gcc/testsuite/objc.dg/pch/pch.exp
  9d6541dc0a9955231b38937f98c5b78a  gcc/testsuite/objc.dg/plugin/diagnostic-test-expressions-1.m
! 468e24ee1e0ade66878ea59796b10494  gcc/testsuite/objc.dg/plugin/plugin.exp
  a1ff757de40d44fb3868d406ed01c4eb  gcc/testsuite/objc.dg/pr101666-0.m
  339a76362d0703671d6ddc07066f2d95  gcc/testsuite/objc.dg/pr101666-1.m
  c963db6673c4b0358e639bc17180a2a0  gcc/testsuite/objc.dg/pr101666.inc
--- 126662,126668 ----
  71da4e106e38b3671b4f4ae8a237e55f  gcc/testsuite/objc.dg/pch/interface-1.m
  f3149d9c99bcd6859904911024284a3e  gcc/testsuite/objc.dg/pch/pch.exp
  9d6541dc0a9955231b38937f98c5b78a  gcc/testsuite/objc.dg/plugin/diagnostic-test-expressions-1.m
! 98a4ef6a502e0d1c56af11d821df0956  gcc/testsuite/objc.dg/plugin/plugin.exp
  a1ff757de40d44fb3868d406ed01c4eb  gcc/testsuite/objc.dg/pr101666-0.m
  339a76362d0703671d6ddc07066f2d95  gcc/testsuite/objc.dg/pr101666-1.m
  c963db6673c4b0358e639bc17180a2a0  gcc/testsuite/objc.dg/pr101666.inc
*************** b889a37174c1fb578620fbb747c66988  gcc/te
*** 127390,127395 ****
--- 127541,127547 ----
  2133db7e84c5e92ff47b3f6ec5232983  gcc/testsuite/rust/compile/issue-4261.rs
  c6047d6f2d7da439614b6d3e2824f2f0  gcc/testsuite/rust/compile/issue-4262.rs
  982dd5cc22276d1f70ba9c3606bf42ff  gcc/testsuite/rust/compile/issue-4267.rs
+ d1b9be613a5d378f76be21f5ccefda20  gcc/testsuite/rust/compile/issue-4301.rs
  229b98c45f842adf4958f0a3abd8e500  gcc/testsuite/rust/compile/issue-557.rs
  f8f243df4bb6d8ad64bad3b19771c416  gcc/testsuite/rust/compile/issue-635-1.rs
  4ebac20282b976fe52f1017d59feaccb  gcc/testsuite/rust/compile/issue-635-2.rs
*************** df1b8a97ae68cf8e9eac8408a743fa64  gcc/te
*** 127447,127453 ****
  28d4ec252bf0945ced2a862377c87487  gcc/testsuite/rust/compile/macros/mbe/macro-issue2273.rs
  0fb684b40daad17a61596f80938a52bc  gcc/testsuite/rust/compile/macros/mbe/macro-issue2653.rs
  92aabd663e1074ae6360f66e208ee5f4  gcc/testsuite/rust/compile/macros/mbe/macro-issue2983_2984.rs
! b77d548768f199c01ca8e079258b5481  gcc/testsuite/rust/compile/macros/mbe/macro-issue3608.rs
  5f52281927c41a8a2db3f5f874ff92f3  gcc/testsuite/rust/compile/macros/mbe/macro-issue3693.rs
  7e84408a82baddd6ba15e8bd51a0be2d  gcc/testsuite/rust/compile/macros/mbe/macro-issue3708.rs
  135abba02ca556e90f3518bbc2322024  gcc/testsuite/rust/compile/macros/mbe/macro-issue3709-1.rs
--- 127599,127605 ----
  28d4ec252bf0945ced2a862377c87487  gcc/testsuite/rust/compile/macros/mbe/macro-issue2273.rs
  0fb684b40daad17a61596f80938a52bc  gcc/testsuite/rust/compile/macros/mbe/macro-issue2653.rs
  92aabd663e1074ae6360f66e208ee5f4  gcc/testsuite/rust/compile/macros/mbe/macro-issue2983_2984.rs
! 0be0e07f10f3cdba3045b01714c24912  gcc/testsuite/rust/compile/macros/mbe/macro-issue3608.rs
  5f52281927c41a8a2db3f5f874ff92f3  gcc/testsuite/rust/compile/macros/mbe/macro-issue3693.rs
  7e84408a82baddd6ba15e8bd51a0be2d  gcc/testsuite/rust/compile/macros/mbe/macro-issue3708.rs
  135abba02ca556e90f3518bbc2322024  gcc/testsuite/rust/compile/macros/mbe/macro-issue3709-1.rs
*************** d1eee141f10cb25a673cf78888396745  gcc/ti
*** 128440,128454 ****
  1720dc69e58e480830de71ecb3eb364d  gcc/toplev.h
  cbb8fb6fcd7138a90fc489b10fe3c862  gcc/tracer.cc
  a58a166bda01c9a970218d3f6c5e330f  gcc/tracer.h
! faec002bae61e7eba3ea45251fbcbc30  gcc/trans-mem.cc
  ffb9a5436754a7e1571b88f970f08891  gcc/trans-mem.h
  b4a6da1471f279353aaca4956c18cdea  gcc/tree-affine.cc
  bcff760f6710b9047412aba72a381983  gcc/tree-affine.h
  527c9fa3845b2653cafc14c109129179  gcc/tree-assume.cc
  23590c969997d33ec2e1fa1da2a89526  gcc/tree-call-cdce.cc
! f95abeeb84fab10990790adba3fdf2f3  gcc/tree-cfg.cc
! a2ce5683f24c556f6dbc78e7c6d27dd6  gcc/tree-cfg.h
! 7f12d8875f61aad8508fa38cefd5dc57  gcc/tree-cfgcleanup.cc
  b528a0932f50504df146d112f7d01a5c  gcc/tree-cfgcleanup.h
  1718a36253ebbb17fe4570fc768216c9  gcc/tree-chrec.cc
  0e4a484c6387f9be0a506783637432f9  gcc/tree-chrec.h
--- 128592,128606 ----
  1720dc69e58e480830de71ecb3eb364d  gcc/toplev.h
  cbb8fb6fcd7138a90fc489b10fe3c862  gcc/tracer.cc
  a58a166bda01c9a970218d3f6c5e330f  gcc/tracer.h
! d1eb203157861f144b71e90b7bc19560  gcc/trans-mem.cc
  ffb9a5436754a7e1571b88f970f08891  gcc/trans-mem.h
  b4a6da1471f279353aaca4956c18cdea  gcc/tree-affine.cc
  bcff760f6710b9047412aba72a381983  gcc/tree-affine.h
  527c9fa3845b2653cafc14c109129179  gcc/tree-assume.cc
  23590c969997d33ec2e1fa1da2a89526  gcc/tree-call-cdce.cc
! 611eba9410da3f563f6de640fb0c456d  gcc/tree-cfg.cc
! 83a5d14539dc2f6a8574c053c1a5814b  gcc/tree-cfg.h
! 623eb6cdf2f5a632fd0939153caf1ce3  gcc/tree-cfgcleanup.cc
  b528a0932f50504df146d112f7d01a5c  gcc/tree-cfgcleanup.h
  1718a36253ebbb17fe4570fc768216c9  gcc/tree-chrec.cc
  0e4a484c6387f9be0a506783637432f9  gcc/tree-chrec.h
*************** e046a9c4874579f81515c4b3d9106b63  gcc/tr
*** 128470,128476 ****
  7e063b1edd28723f3f432596c39cfbee  gcc/tree-hasher.h
  ab245837876f2da0af044a74ebcfac2d  gcc/tree-if-conv.cc
  002c9568898504ca2025dcacf5151fd6  gcc/tree-if-conv.h
! 9650c4ca2c6433fcd2096065741fda15  gcc/tree-inline.cc
  326f91431bfd3c15d8ddd74699d666e6  gcc/tree-inline.h
  90ca59c0844cd326f35f9cae17ec174b  gcc/tree-into-ssa.cc
  ef1cb0fba517532ecda9f4e0dd5218f7  gcc/tree-into-ssa.h
--- 128622,128628 ----
  7e063b1edd28723f3f432596c39cfbee  gcc/tree-hasher.h
  ab245837876f2da0af044a74ebcfac2d  gcc/tree-if-conv.cc
  002c9568898504ca2025dcacf5151fd6  gcc/tree-if-conv.h
! 36f8a50f3f9f778fd5297a59dbd8f365  gcc/tree-inline.cc
  326f91431bfd3c15d8ddd74699d666e6  gcc/tree-inline.h
  90ca59c0844cd326f35f9cae17ec174b  gcc/tree-into-ssa.cc
  ef1cb0fba517532ecda9f4e0dd5218f7  gcc/tree-into-ssa.h
*************** ef1cb0fba517532ecda9f4e0dd5218f7  gcc/tr
*** 128478,128484 ****
  1a3fc26573e4e592efe69f41168a65fa  gcc/tree-iterator.h
  708a19806855f78da0268f0c25a1c1c0  gcc/tree-logical-location.cc
  fba074361c117a968daf282ef88a2b6e  gcc/tree-logical-location.h
! f9aaa5558fcc5a324ef572971dc9f564  gcc/tree-loop-distribution.cc
  dfd20c8b11a281f68c975c63033ed5e0  gcc/tree-nested.cc
  b9bad013f5186a6cf78fe8adbe457945  gcc/tree-nested.h
  b2cc2bfd702552bff382308428fec556  gcc/tree-nrv.cc
--- 128630,128636 ----
  1a3fc26573e4e592efe69f41168a65fa  gcc/tree-iterator.h
  708a19806855f78da0268f0c25a1c1c0  gcc/tree-logical-location.cc
  fba074361c117a968daf282ef88a2b6e  gcc/tree-logical-location.h
! e94b5e37af07c5120dba44870806eef8  gcc/tree-loop-distribution.cc
  dfd20c8b11a281f68c975c63033ed5e0  gcc/tree-nested.cc
  b9bad013f5186a6cf78fe8adbe457945  gcc/tree-nested.h
  b2cc2bfd702552bff382308428fec556  gcc/tree-nrv.cc
*************** beaa17685ead93eee17f6373d004c4c4  gcc/tr
*** 128493,128509 ****
  460fc341cb2d78f53e0a27c81de36a7d  gcc/tree-phinodes.h
  10ba4bea4c7470735678acc6088c06d5  gcc/tree-predcom.cc
  529cb4117fb3ff7fd899c570bd97e944  gcc/tree-pretty-print-markup.h
! 9549fe142712a6a3002b12302fc770a7  gcc/tree-pretty-print.cc
  fd4dd1219acc650a4f7855faa0097964  gcc/tree-pretty-print.h
  7c11aa147a6d02acce5170cb35aed445  gcc/tree-profile.cc
  30eadcd3625eaa7cbebc8de55729efbc  gcc/tree-scalar-evolution.cc
  dddd950fe463803c41bc0c7cddf0fe44  gcc/tree-scalar-evolution.h
! b72513bb0f4b53e7bfa5353836a30feb  gcc/tree-sra.cc
  c022e816e38c8f399e6a16163c56d6db  gcc/tree-sra.h
  3e42023ef3fe5187ffffddbbb5740208  gcc/tree-ssa-address.cc
  c724c8becbea9eec0f806e3335942c32  gcc/tree-ssa-address.h
  b8450f3f71eba56c45cfa47b8a520ef2  gcc/tree-ssa-alias-compare.h
! 185e75eff0ace3e984dbb5c3aa1478cd  gcc/tree-ssa-alias.cc
  9d359861d05b5dfbc59cbf45c70feb0f  gcc/tree-ssa-alias.h
  bc6f720750badcd2ff68dddf544e75eb  gcc/tree-ssa-ccp.cc
  0facf771754439bdf307ff1c5ae92cb5  gcc/tree-ssa-ccp.h
--- 128645,128661 ----
  460fc341cb2d78f53e0a27c81de36a7d  gcc/tree-phinodes.h
  10ba4bea4c7470735678acc6088c06d5  gcc/tree-predcom.cc
  529cb4117fb3ff7fd899c570bd97e944  gcc/tree-pretty-print-markup.h
! c5d6e297c079987fa6c5d46ed5d525fc  gcc/tree-pretty-print.cc
  fd4dd1219acc650a4f7855faa0097964  gcc/tree-pretty-print.h
  7c11aa147a6d02acce5170cb35aed445  gcc/tree-profile.cc
  30eadcd3625eaa7cbebc8de55729efbc  gcc/tree-scalar-evolution.cc
  dddd950fe463803c41bc0c7cddf0fe44  gcc/tree-scalar-evolution.h
! 6b99b33abdbb4e8324c72e5bc0cd82d2  gcc/tree-sra.cc
  c022e816e38c8f399e6a16163c56d6db  gcc/tree-sra.h
  3e42023ef3fe5187ffffddbbb5740208  gcc/tree-ssa-address.cc
  c724c8becbea9eec0f806e3335942c32  gcc/tree-ssa-address.h
  b8450f3f71eba56c45cfa47b8a520ef2  gcc/tree-ssa-alias-compare.h
! ec78b7d05ee874b736c53ecd1aa0ed36  gcc/tree-ssa-alias.cc
  9d359861d05b5dfbc59cbf45c70feb0f  gcc/tree-ssa-alias.h
  bc6f720750badcd2ff68dddf544e75eb  gcc/tree-ssa-ccp.cc
  0facf771754439bdf307ff1c5ae92cb5  gcc/tree-ssa-ccp.h
*************** b9ccca93dfe789389d268eca6dbec62f  gcc/tr
*** 128516,128526 ****
  0046e212ff1b9f3f4d27d055aa299c47  gcc/tree-ssa-dom.h
  6ddd79e7a349847a539144d422bf5a49  gcc/tree-ssa-dse.cc
  a6d83be241a72da1740cf6c5b2ce7d52  gcc/tree-ssa-dse.h
! 1a9e5176c9e3f709d297d9b3bf48c422  gcc/tree-ssa-forwprop.cc
! 0915c4bbeb42abdda8799c2b27e5db12  gcc/tree-ssa-ifcombine.cc
  9bff033c448d54835a74eae5797b80e7  gcc/tree-ssa-live.cc
  cf4bde43ab3b843eff45bac243d4116d  gcc/tree-ssa-live.h
! 43cee7e03d2dcf9be9a012c3b6f663e0  gcc/tree-ssa-loop-ch.cc
  56c17094ff91d36af5c68291820c1d2f  gcc/tree-ssa-loop-im.cc
  59817c52e943058ad942cd5b8c8427d0  gcc/tree-ssa-loop-ivcanon.cc
  ec0ea4b2fca8f29ceacc9fa4130673d0  gcc/tree-ssa-loop-ivopts.cc
--- 128668,128678 ----
  0046e212ff1b9f3f4d27d055aa299c47  gcc/tree-ssa-dom.h
  6ddd79e7a349847a539144d422bf5a49  gcc/tree-ssa-dse.cc
  a6d83be241a72da1740cf6c5b2ce7d52  gcc/tree-ssa-dse.h
! af75d9c8c889bf48bed7f36350e6708f  gcc/tree-ssa-forwprop.cc
! 8107ac9eed21ae6e3d593fd93b3769e1  gcc/tree-ssa-ifcombine.cc
  9bff033c448d54835a74eae5797b80e7  gcc/tree-ssa-live.cc
  cf4bde43ab3b843eff45bac243d4116d  gcc/tree-ssa-live.h
! 8fb545bd550f08c8e88222c745f881a0  gcc/tree-ssa-loop-ch.cc
  56c17094ff91d36af5c68291820c1d2f  gcc/tree-ssa-loop-im.cc
  59817c52e943058ad942cd5b8c8427d0  gcc/tree-ssa-loop-ivcanon.cc
  ec0ea4b2fca8f29ceacc9fa4130673d0  gcc/tree-ssa-loop-ivopts.cc
*************** e6684bfab00087c19d73f3a45f523786  gcc/tr
*** 128540,128546 ****
  da72a60de8a6f51a635ead26120d3cc7  gcc/tree-ssa-operands.h
  fbb4dbd95b07fb6744745c6d010a7341  gcc/tree-ssa-phiopt.cc
  cc64c91d8734e7d0da1a88587224af44  gcc/tree-ssa-phiprop.cc
! 45bbadfd0296a849ac6eebf1a85d74ec  gcc/tree-ssa-pre.cc
  090c54ea646b8886730039b6cc16adb6  gcc/tree-ssa-propagate.cc
  ec25a5b6fd6b05135faa83b07eca7e91  gcc/tree-ssa-propagate.h
  2e77cb6dbff1d8175a2c6adc5299e1cf  gcc/tree-ssa-reassoc.cc
--- 128692,128698 ----
  da72a60de8a6f51a635ead26120d3cc7  gcc/tree-ssa-operands.h
  fbb4dbd95b07fb6744745c6d010a7341  gcc/tree-ssa-phiopt.cc
  cc64c91d8734e7d0da1a88587224af44  gcc/tree-ssa-phiprop.cc
! 8015bc735903abc22b74765ef4fbb4a6  gcc/tree-ssa-pre.cc
  090c54ea646b8886730039b6cc16adb6  gcc/tree-ssa-propagate.cc
  ec25a5b6fd6b05135faa83b07eca7e91  gcc/tree-ssa-propagate.h
  2e77cb6dbff1d8175a2c6adc5299e1cf  gcc/tree-ssa-reassoc.cc
*************** af4c63760c432f66b1c6c8e7e7666699  gcc/tr
*** 128577,128597 ****
  9eb012617e4989c6e0f013631b853d98  gcc/tree-switch-conversion.cc
  ebb8ac3717c1bf5db4371da2f3cf6af7  gcc/tree-switch-conversion.h
  c98debbdc978c10e8934f3b4fb7e2504  gcc/tree-tailcall.cc
! afc64fe5f2d0be7edd7fd887eb73b974  gcc/tree-vect-data-refs.cc
  643ae42915f153c0014934d90e00c875  gcc/tree-vect-generic.cc
! 9b4b4c9a9ecbdf482cab09c556fa92fd  gcc/tree-vect-loop-manip.cc
! 7afd755aead556a7b9c54083248dc70c  gcc/tree-vect-loop.cc
! 92facee65a97dd1619b579cad2d611d1  gcc/tree-vect-patterns.cc
  588899232babed9c67e61795ff405608  gcc/tree-vect-slp-patterns.cc
! 241056c37ca5ddefdad7c9c3132f788e  gcc/tree-vect-slp.cc
! 717e5918b264584711060b325baa3779  gcc/tree-vect-stmts.cc
  c8efeee600d612c4bae8dda4bd45ee54  gcc/tree-vector-builder.cc
  258611ff1e83cc7680e8c9f033499665  gcc/tree-vector-builder.h
! c516450d07587e25c338c4223664b2ad  gcc/tree-vectorizer.cc
! 69c93a44a2b800f839150157cfd558e1  gcc/tree-vectorizer.h
  6af612260e9aa57da3abab8955305844  gcc/tree-vrp.cc
  a19edad681d27130bd2a0d83768ac946  gcc/tree-vrp.h
! a28c66d5fa146a42930296a1f6dfc91f  gcc/tree.cc
  2b3067f4ee14760d08fdfee4eb6b8a00  gcc/tree.def
  d4ada940c189672b6a0a2a9874d2b11d  gcc/tree.h
  b642c83968cda285afc700da2fb276d5  gcc/treestruct.def
--- 128729,128749 ----
  9eb012617e4989c6e0f013631b853d98  gcc/tree-switch-conversion.cc
  ebb8ac3717c1bf5db4371da2f3cf6af7  gcc/tree-switch-conversion.h
  c98debbdc978c10e8934f3b4fb7e2504  gcc/tree-tailcall.cc
! 3e60b11b9b0d8bdb2a8af6f8d292ca9c  gcc/tree-vect-data-refs.cc
  643ae42915f153c0014934d90e00c875  gcc/tree-vect-generic.cc
! 60a5b5d7ceca192eea76f24c8e29da16  gcc/tree-vect-loop-manip.cc
! 89a46cee071aa219e0b38cd44d8a21b4  gcc/tree-vect-loop.cc
! 6bf9b00ee28f749d7b1fbf76c7e2f098  gcc/tree-vect-patterns.cc
  588899232babed9c67e61795ff405608  gcc/tree-vect-slp-patterns.cc
! 11ec3562bf7dc26bc5349f28ce7a6fe5  gcc/tree-vect-slp.cc
! a714fc5566aed2842d03c78628951854  gcc/tree-vect-stmts.cc
  c8efeee600d612c4bae8dda4bd45ee54  gcc/tree-vector-builder.cc
  258611ff1e83cc7680e8c9f033499665  gcc/tree-vector-builder.h
! c8b7b8b7c09184f0bf7eb7f001bcd27b  gcc/tree-vectorizer.cc
! adffa8995a83e88761f425d183f46f6f  gcc/tree-vectorizer.h
  6af612260e9aa57da3abab8955305844  gcc/tree-vrp.cc
  a19edad681d27130bd2a0d83768ac946  gcc/tree-vrp.h
! c246e9fe248d72d7134045768d0c01bd  gcc/tree.cc
  2b3067f4ee14760d08fdfee4eb6b8a00  gcc/tree.def
  d4ada940c189672b6a0a2a9874d2b11d  gcc/tree.h
  b642c83968cda285afc700da2fb276d5  gcc/treestruct.def
*************** e1189a7a57364aa6379d885c8c3034c4  gcc/va
*** 128622,128635 ****
  8456af13cd791169eff90d7d6cf3d657  gcc/value-range.h
  79218f1b1541107edcd2c970e947e835  gcc/value-relation.cc
  be431fb5e48823f5b9bce654ae3e7645  gcc/value-relation.h
! db99ee82ab71b58820d60f9863e62aac  gcc/var-tracking.cc
  63e6a64533514c36d9e6e1bd510a2c21  gcc/varasm.cc
  69f8e035a8548037bc8c8f7f854253c4  gcc/varasm.h
  2f869cb153fe0c8c605d1271668c9d45  gcc/varpool.cc
  5958f38d462c8e23023f7b272b8b969c  gcc/vec-perm-indices.cc
  d9c4840a497d0e1f2063865edafe6e97  gcc/vec-perm-indices.h
  49e92de0554d55d6fb8db9734d0f76d1  gcc/vec.cc
! a4370fef630f3c010a5988b36caeb61d  gcc/vec.h
  54a3885ae2d326266cc13ab447394d8f  gcc/vector-builder.h
  40fec2b7bbea0b654d0704244caa4e9c  gcc/vmsdbg.h
  c2784afc7476e44bc70100f7c350e07b  gcc/vmsdbgout.cc
--- 128774,128787 ----
  8456af13cd791169eff90d7d6cf3d657  gcc/value-range.h
  79218f1b1541107edcd2c970e947e835  gcc/value-relation.cc
  be431fb5e48823f5b9bce654ae3e7645  gcc/value-relation.h
! 44344867bb9f8ed8ba4e88a2acd0ed50  gcc/var-tracking.cc
  63e6a64533514c36d9e6e1bd510a2c21  gcc/varasm.cc
  69f8e035a8548037bc8c8f7f854253c4  gcc/varasm.h
  2f869cb153fe0c8c605d1271668c9d45  gcc/varpool.cc
  5958f38d462c8e23023f7b272b8b969c  gcc/vec-perm-indices.cc
  d9c4840a497d0e1f2063865edafe6e97  gcc/vec-perm-indices.h
  49e92de0554d55d6fb8db9734d0f76d1  gcc/vec.cc
! 8d38897f7f14329ca58551e71aa93811  gcc/vec.h
  54a3885ae2d326266cc13ab447394d8f  gcc/vector-builder.h
  40fec2b7bbea0b654d0704244caa4e9c  gcc/vmsdbg.h
  c2784afc7476e44bc70100f7c350e07b  gcc/vmsdbgout.cc
*************** a3eb5dee2788fe0a6c42502ba658eddd  libffi
*** 129450,129456 ****
  0f3c94e520870e194cf525de7ec404dc  libffi/testsuite/libffi.go/ffitest.h
  6cfb66c1c00023abb2c2276d85f16e77  libffi/testsuite/libffi.go/go.exp
  189dc193fd0e627a2d55b2e84871edc5  libffi/testsuite/libffi.go/static-chain.h
! 022e54e5f5f1030f43df9ee002c148ef  libga68/ChangeLog
  32a6cfe3b283d9e93de3717f07be75a9  libga68/Makefile.am
  3a23c15e53f814e130a87c72920a7b13  libga68/Makefile.in
  e582170826a5049ebe5f76ccb66fe5f2  libga68/README
--- 129602,129608 ----
  0f3c94e520870e194cf525de7ec404dc  libffi/testsuite/libffi.go/ffitest.h
  6cfb66c1c00023abb2c2276d85f16e77  libffi/testsuite/libffi.go/go.exp
  189dc193fd0e627a2d55b2e84871edc5  libffi/testsuite/libffi.go/static-chain.h
! c687e0d03aef2bfa3876c26a7784ad0c  libga68/ChangeLog
  32a6cfe3b283d9e93de3717f07be75a9  libga68/Makefile.am
  3a23c15e53f814e130a87c72920a7b13  libga68/Makefile.in
  e582170826a5049ebe5f76ccb66fe5f2  libga68/README
*************** fee976d3e4dd69fd4ce510cd3f657490  libga6
*** 129462,129472 ****
  adf1f645e63900a1f48a7b62b3244e82  libga68/ga68-error.c
  03e76f4209cfbe93f665f3a9b6669d54  libga68/ga68-posix.c
  0cb9061543a123a912e4657db7b527f9  libga68/ga68-standenv.c
! f7003e261c3571b88fe403d28fb3157f  libga68/ga68-unistr.c
! d85b910fef5199d4921a6353feb96b71  libga68/ga68.h
  df913cb29914c3ebdb600c9c3be7f788  libga68/libga68.c
  5a99bd84e0794e311b25ab281d6c294a  libga68/libga68.spec.in
! b8b1e67d09cef1e57e713c78dbb5e916  libgcc/ChangeLog
  cada2741a04d59811a0d9b12b601d3cf  libgcc/Makefile.in
  3909078d285165298c78eb97ea152e90  libgcc/config.host
  46412830a2ee8a02503ccc921912c3cf  libgcc/config.in
--- 129614,129624 ----
  adf1f645e63900a1f48a7b62b3244e82  libga68/ga68-error.c
  03e76f4209cfbe93f665f3a9b6669d54  libga68/ga68-posix.c
  0cb9061543a123a912e4657db7b527f9  libga68/ga68-standenv.c
! 42897103d2dd7bb1ffbe9bd8d3101f9f  libga68/ga68-unistr.c
! 44efc2d0ac0918a2b135870b40bf5341  libga68/ga68.h
  df913cb29914c3ebdb600c9c3be7f788  libga68/libga68.c
  5a99bd84e0794e311b25ab281d6c294a  libga68/libga68.spec.in
! 75e87c6612aecbf7ac3145adfaba51fd  libgcc/ChangeLog
  cada2741a04d59811a0d9b12b601d3cf  libgcc/Makefile.in
  3909078d285165298c78eb97ea152e90  libgcc/config.host
  46412830a2ee8a02503ccc921912c3cf  libgcc/config.in
*************** c150e28c734710584eba8e77d2ff5105  libgcc
*** 130668,130676 ****
  26d353eea9229af01124cc46b2e0cebd  libgcc/config/s390/t-stack-s390
  a5218871642ae69c55b0e826c41f3798  libgcc/config/s390/t-tpf
  c06c11db33a4129e60e075061e8c9326  libgcc/config/s390/tpf-unwind.h
- 3281bea2cf85d3a4af3b83fd314f959b  libgcc/config/score/crti.S
- 0cc50361d6b8db5fc11415b212e4a36e  libgcc/config/score/crtn.S
- 5d570ff5cd40fc6fba8876bdebd59a6b  libgcc/config/score/sfp-machine.h
  50cd82b198ecfd4c1c35ac74bc5383f8  libgcc/config/sh/crt.h
  5c0c8ca18e7c6168ec09c55c392265ed  libgcc/config/sh/crt1.S
  6010d0873c904253466e110a51372c22  libgcc/config/sh/crti.S
--- 130820,130825 ----
*************** b596ffc38045755f7ef0c54f1d5555a1  libgco
*** 131111,131117 ****
  2b31946dfaa7df328dd0749c37f1ae36  libgcobol/valconv.cc
  bf52fdaed06effba57a10e8157bc6930  libgcobol/valconv.h
  c87d0834249e4949627ac190796295e9  libgcobol/xmlparse.cc
! 2104c8a11398902021f9bd89abce66de  libgfortran/ChangeLog
  d99469a76bfe825683f8d94fe07b508c  libgfortran/ChangeLog-2002
  522fdb2df6cefe6bcaed3c7c7311eae1  libgfortran/ChangeLog-2003
  5a3a93e76d878d063aba66079340cfe0  libgfortran/ChangeLog-2004
--- 131260,131266 ----
  2b31946dfaa7df328dd0749c37f1ae36  libgcobol/valconv.cc
  bf52fdaed06effba57a10e8157bc6930  libgcobol/valconv.h
  c87d0834249e4949627ac190796295e9  libgcobol/xmlparse.cc
! 0791c93c35c6d4fc32ddd6975fe12f0e  libgfortran/ChangeLog
  d99469a76bfe825683f8d94fe07b508c  libgfortran/ChangeLog-2002
  522fdb2df6cefe6bcaed3c7c7311eae1  libgfortran/ChangeLog-2003
  5a3a93e76d878d063aba66079340cfe0  libgfortran/ChangeLog-2004
*************** aa985952e87571b015b2b85e508c6a0b  libgfo
*** 132029,132035 ****
  2c879686a9c5431b13c4d3a9323e5fed  libgfortran/io/inquire.c
  9a1581b774b6fa5ddc5861750824984f  libgfortran/io/intrinsics.c
  68b0f7c5c62320c0b053455824877d6e  libgfortran/io/io.h
! b95dff39f8b38e33ccf895ccf509a3a6  libgfortran/io/list_read.c
  bc0fa60eac17837b1c762e97a8c08673  libgfortran/io/lock.c
  d043bdbc42f0d079e46ba78d36d7d784  libgfortran/io/open.c
  d48a4345efa3ebd21fbcc13f864cb82c  libgfortran/io/read.c
--- 132178,132184 ----
  2c879686a9c5431b13c4d3a9323e5fed  libgfortran/io/inquire.c
  9a1581b774b6fa5ddc5861750824984f  libgfortran/io/intrinsics.c
  68b0f7c5c62320c0b053455824877d6e  libgfortran/io/io.h
! 2885ac6fa470ae0851603e724c6b347e  libgfortran/io/list_read.c
  bc0fa60eac17837b1c762e97a8c08673  libgfortran/io/lock.c
  d043bdbc42f0d079e46ba78d36d7d784  libgfortran/io/open.c
  d48a4345efa3ebd21fbcc13f864cb82c  libgfortran/io/read.c
*************** fabf825638554348a64e8dee21986b0a  libgm2
*** 132181,132188 ****
  99ede8f0e7ba72a5449d5e9380ec5475  libgm2/libm2pim/wrapc.cc
  5d4950ecb7b26d2c5e4e7b4e0dd74707  libgo/LICENSE
  160ac38979ae9334894994a1e7b4bf3b  libgo/MERGE
! 9c4a11ea93d0f8b552f2485c9664bd80  libgo/Makefile.am
! 19e4b59405ea0e8421687f8d6ee68615  libgo/Makefile.in
  3a55d95595a6f9e37dee53826b4daff2  libgo/PATENTS
  d0952f0b499c9ebb887222764488a2fc  libgo/README
  492dd43b98c6602a8754328947942c40  libgo/README.gcc
--- 132330,132337 ----
  99ede8f0e7ba72a5449d5e9380ec5475  libgm2/libm2pim/wrapc.cc
  5d4950ecb7b26d2c5e4e7b4e0dd74707  libgo/LICENSE
  160ac38979ae9334894994a1e7b4bf3b  libgo/MERGE
! a3d9d822336d9af3b61708f1968d94d8  libgo/Makefile.am
! acf619efe50af250f7a3fd5a3aee2d12  libgo/Makefile.in
  3a55d95595a6f9e37dee53826b4daff2  libgo/PATENTS
  d0952f0b499c9ebb887222764488a2fc  libgo/README
  492dd43b98c6602a8754328947942c40  libgo/README.gcc
*************** dee72a6a60e99528b0d17bf3ff9a1e15  libgo/
*** 132197,132204 ****
  bc2f6032c98896249eadb56177c7d357  libgo/config/ltsugar.m4
  c30cd33c496505f13d9fbdb6970c7c33  libgo/config/ltversion.m4
  293853a13b7e218e3a4342cf85fbbf25  libgo/config/lt~obsolete.m4
! 9843ea65de679bfac9ff7e6789194aa9  libgo/configure
! 941568ff2f4ed13be3b442eae32335f0  libgo/configure.ac
  aac32f286f60f443762f017a205c38dc  libgo/go/archive/tar/common.go
  f7d12cedad0468bfe618b4d2f78e2389  libgo/go/archive/tar/format.go
  2bbe8478660c394e2178904d3b0fd954  libgo/go/archive/tar/fuzz_test.go
--- 132346,132353 ----
  bc2f6032c98896249eadb56177c7d357  libgo/config/ltsugar.m4
  c30cd33c496505f13d9fbdb6970c7c33  libgo/config/ltversion.m4
  293853a13b7e218e3a4342cf85fbbf25  libgo/config/lt~obsolete.m4
! f9b81f1e857ea0de4282cc158ab6b836  libgo/configure
! 68936202ddf48cf4c094999342105aef  libgo/configure.ac
  aac32f286f60f443762f017a205c38dc  libgo/go/archive/tar/common.go
  f7d12cedad0468bfe618b4d2f78e2389  libgo/go/archive/tar/format.go
  2bbe8478660c394e2178904d3b0fd954  libgo/go/archive/tar/fuzz_test.go
*************** c3d76c2792e5791b282011e1c74eb6e7  libgo/
*** 134375,134381 ****
  8d84dada6b800609d48b0c7e0a775cb6  libgo/go/fmt/scan_test.go
  6fcb09cb0cd589441f3d63eda967b071  libgo/go/fmt/stringer_example_test.go
  2369824f08c60e32daa40b736d182964  libgo/go/fmt/stringer_test.go
! d55c9bd287b7a7941e145354f5974d0a  libgo/go/go.mod
  ce5ef3c8bfb0242e90cfb06de2c15b3b  libgo/go/go/ast/ast.go
  d4d45d52a65eb9a90a577b7642507749  libgo/go/go/ast/ast_test.go
  e614191e6d9697c1dac5128c815b62e4  libgo/go/go/ast/commentmap.go
--- 134524,134530 ----
  8d84dada6b800609d48b0c7e0a775cb6  libgo/go/fmt/scan_test.go
  6fcb09cb0cd589441f3d63eda967b071  libgo/go/fmt/stringer_example_test.go
  2369824f08c60e32daa40b736d182964  libgo/go/fmt/stringer_test.go
! e831b12c85471a0fa0fbcc7dec7db934  libgo/go/go.mod
  ce5ef3c8bfb0242e90cfb06de2c15b3b  libgo/go/go/ast/ast.go
  d4d45d52a65eb9a90a577b7642507749  libgo/go/go/ast/ast_test.go
  e614191e6d9697c1dac5128c815b62e4  libgo/go/go/ast/commentmap.go
*************** c4d2846cb08f6c5bab32f58c0fa76517  libgo/
*** 137257,137263 ****
  45392f48d7d1aaa462bcc95b51bc70b1  libgo/go/unicode/utf8/example_test.go
  2c4d3713a77c44ac98c5666b839f529e  libgo/go/unicode/utf8/utf8.go
  db676c1f1d2849067afce04315a08b09  libgo/go/unicode/utf8/utf8_test.go
! 68b0af602cca7611c675a533d1ca1ab4  libgo/go/vendor/modules.txt
  b34a692bd542de151dc73de26d16dd2e  libgo/goarch.sh
  342e21bbfbb708562a0417b169575759  libgo/godeps.sh
  59c854f27a495007f0fce591f2e9c5b3  libgo/gotool-packages.txt
--- 137406,137412 ----
  45392f48d7d1aaa462bcc95b51bc70b1  libgo/go/unicode/utf8/example_test.go
  2c4d3713a77c44ac98c5666b839f529e  libgo/go/unicode/utf8/utf8.go
  db676c1f1d2849067afce04315a08b09  libgo/go/unicode/utf8/utf8_test.go
! f93d661f668346a0fa9592dc5dd7cd81  libgo/go/vendor/modules.txt
  b34a692bd542de151dc73de26d16dd2e  libgo/goarch.sh
  342e21bbfbb708562a0417b169575759  libgo/godeps.sh
  59c854f27a495007f0fce591f2e9c5b3  libgo/gotool-packages.txt
*************** b0bef0d844dadebbe84ad9cf32c002bf  libgo/
*** 137668,137681 ****
  f1f0917f45d626d15a5f129fef3d81e2  libgo/runtime/yield.c
  00019600f80b0ce3d73e8655fc80d153  libgo/sysinfo.c
  64195708a46fb2d5225149f15a8e3991  libgo/testsuite/Makefile.am
! 3afd5e92aeacb17936026fd2d1b8ba43  libgo/testsuite/Makefile.in
  180c96a619276205ec9fc8e8217b67bd  libgo/testsuite/config/default.exp
  119ed5d3e1f74e576b1f430ed406a3ff  libgo/testsuite/gotest
  a3a7e9ca6057da9ca42e03e41e1c73f7  libgo/testsuite/lib/libgo.exp
  dcdf1b680b15b372bdb64cc5107d51b6  libgo/testsuite/libgo-test-support.exp.in
  bf162aa572f7b96b25dbd2b027845d32  libgo/testsuite/libgo.testmain/testmain.exp
  cc9d2a0e34e31ba866a8caf9f46f48f3  libgomp/.gitattributes
! c7df59be93f3a5bd9e7c9cba5378760f  libgomp/ChangeLog
  0d55aa862aee66efdc5f8d62c94ff8fb  libgomp/ChangeLog.graphite
  714e3b9c0810a61df01246c2a97e825a  libgomp/Makefile.am
  a0a1ac8cf0159995930a1c6c60042f2d  libgomp/Makefile.in
--- 137817,137830 ----
  f1f0917f45d626d15a5f129fef3d81e2  libgo/runtime/yield.c
  00019600f80b0ce3d73e8655fc80d153  libgo/sysinfo.c
  64195708a46fb2d5225149f15a8e3991  libgo/testsuite/Makefile.am
! 2d16de6a5067759fbfa0df635e479eae  libgo/testsuite/Makefile.in
  180c96a619276205ec9fc8e8217b67bd  libgo/testsuite/config/default.exp
  119ed5d3e1f74e576b1f430ed406a3ff  libgo/testsuite/gotest
  a3a7e9ca6057da9ca42e03e41e1c73f7  libgo/testsuite/lib/libgo.exp
  dcdf1b680b15b372bdb64cc5107d51b6  libgo/testsuite/libgo-test-support.exp.in
  bf162aa572f7b96b25dbd2b027845d32  libgo/testsuite/libgo.testmain/testmain.exp
  cc9d2a0e34e31ba866a8caf9f46f48f3  libgomp/.gitattributes
! 47a360885282f48697c3a412239ec750  libgomp/ChangeLog
  0d55aa862aee66efdc5f8d62c94ff8fb  libgomp/ChangeLog.graphite
  714e3b9c0810a61df01246c2a97e825a  libgomp/Makefile.am
  a0a1ac8cf0159995930a1c6c60042f2d  libgomp/Makefile.in
*************** c3d837ee5481f078c8b7875c1c8306be  libgom
*** 137818,137824 ****
  21a838f501beb823e9b3a82f26344b31  libgomp/libgomp.h
  cd6a22eaa3c99a58084ad32602f087b4  libgomp/libgomp.map
  8b2aa50aecad82171348a6918309afd6  libgomp/libgomp.spec.in
! e646d859aeb8498a75a56abd4abe6af6  libgomp/libgomp.texi
  519d28879206bae759d85cd3bb7b493b  libgomp/libgomp_f.h.in
  fdadcc861565b686070908326f5e5914  libgomp/libgomp_g.h
  a5060d745455b036a62cc46de1fe0576  libgomp/lock.c
--- 137967,137973 ----
  21a838f501beb823e9b3a82f26344b31  libgomp/libgomp.h
  cd6a22eaa3c99a58084ad32602f087b4  libgomp/libgomp.map
  8b2aa50aecad82171348a6918309afd6  libgomp/libgomp.spec.in
! 3ac277022c793b115844a1db93b90504  libgomp/libgomp.texi
  519d28879206bae759d85cd3bb7b493b  libgomp/libgomp_f.h.in
  fdadcc861565b686070908326f5e5914  libgomp/libgomp_g.h
  a5060d745455b036a62cc46de1fe0576  libgomp/lock.c
*************** f24734d0f876e60f6edf6283233372be  libgom
*** 137844,137850 ****
  70196de117934b7f120ff364699b0142  libgomp/ordered.c
  5d03c6596f36bc8b6127cd047fb71b81  libgomp/parallel.c
  a5ada313613c1edc8912eba3982794b2  libgomp/plugin/Makefrag.am
! 00915d9ce3e412613822d106e8c71deb  libgomp/plugin/build-target-indirect-htab.h
  5a5c5a37c066333fa237c308a243cda1  libgomp/plugin/configfrag.ac
  92f97e6738a0b5c4baa390cce2f52809  libgomp/plugin/cuda-lib.def
  b21ea8a17acdb2346d0b7ef2ab49b81b  libgomp/plugin/mutex.c
--- 137993,137999 ----
  70196de117934b7f120ff364699b0142  libgomp/ordered.c
  5d03c6596f36bc8b6127cd047fb71b81  libgomp/parallel.c
  a5ada313613c1edc8912eba3982794b2  libgomp/plugin/Makefrag.am
! 1bb5ed9c27079d83f4beaa81ca7105f3  libgomp/plugin/build-target-indirect-htab.h
  5a5c5a37c066333fa237c308a243cda1  libgomp/plugin/configfrag.ac
  92f97e6738a0b5c4baa390cce2f52809  libgomp/plugin/cuda-lib.def
  b21ea8a17acdb2346d0b7ef2ab49b81b  libgomp/plugin/mutex.c
*************** caca1aa745e9df985dc965e87fc08c02  libgom
*** 138675,138681 ****
  22339699e5ead02323ff39f1b6fe0db9  libgomp/testsuite/libgomp.c-target/aarch64/threadprivate.c
  3e38202a9a5de0a29a80148a97ba15d8  libgomp/testsuite/libgomp.c-target/aarch64/udr-sve.c
  9827d700d634869b090c7636cc855819  libgomp/testsuite/libgomp.c/address-space-1.c
! ee0aef7568eaf6032ce83a846610f437  libgomp/testsuite/libgomp.c/affinity-1.c
  fe6e22f8c0d2e289ecbd5ea26c9ed1bc  libgomp/testsuite/libgomp.c/affinity-2.c
  a52fb92b19587144b8e2695db415d94e  libgomp/testsuite/libgomp.c/alloc-managed-1.c
  6c8686bb019986a5da3b70a8e4ec67e6  libgomp/testsuite/libgomp.c/alloc-managed-2.c
--- 138824,138830 ----
  22339699e5ead02323ff39f1b6fe0db9  libgomp/testsuite/libgomp.c-target/aarch64/threadprivate.c
  3e38202a9a5de0a29a80148a97ba15d8  libgomp/testsuite/libgomp.c-target/aarch64/udr-sve.c
  9827d700d634869b090c7636cc855819  libgomp/testsuite/libgomp.c/address-space-1.c
! ce1cb8cd64d75262790a2e375e2e81b2  libgomp/testsuite/libgomp.c/affinity-1.c
  fe6e22f8c0d2e289ecbd5ea26c9ed1bc  libgomp/testsuite/libgomp.c/affinity-2.c
  a52fb92b19587144b8e2695db415d94e  libgomp/testsuite/libgomp.c/alloc-managed-1.c
  6c8686bb019986a5da3b70a8e4ec67e6  libgomp/testsuite/libgomp.c/alloc-managed-2.c
*************** ba23071854d45364a52aa56e0e3316ac  libgom
*** 139776,139782 ****
  145271a42e3885d82155f89fbb8a1d67  libgomp/testsuite/libgomp.fortran/use_device_ptr-optional-3.f90
  dc1df4b97d0fa5209eb509523fa08bfc  libgomp/testsuite/libgomp.fortran/use_device_ptr-optional-4.f90
  fd6becb20369d6ac5a1bacfc014b31a3  libgomp/testsuite/libgomp.fortran/use_intrinsic_1.f90
! 4b4761c07dd081ab36a01dfa8f710bf0  libgomp/testsuite/libgomp.fortran/uses_allocators-7.f90
  9a2ba6cff64ca5bc6375ce44cf49a165  libgomp/testsuite/libgomp.fortran/uses_allocators_1.f90
  112d434e4f93bd46b5f504a2376b9129  libgomp/testsuite/libgomp.fortran/uses_allocators_2.f90
  fecda9fc3e70ac57c13ecf7a85196138  libgomp/testsuite/libgomp.fortran/vla1.f90
--- 139925,139931 ----
  145271a42e3885d82155f89fbb8a1d67  libgomp/testsuite/libgomp.fortran/use_device_ptr-optional-3.f90
  dc1df4b97d0fa5209eb509523fa08bfc  libgomp/testsuite/libgomp.fortran/use_device_ptr-optional-4.f90
  fd6becb20369d6ac5a1bacfc014b31a3  libgomp/testsuite/libgomp.fortran/use_intrinsic_1.f90
! 0047760a13ce6b018e8db47739f97caf  libgomp/testsuite/libgomp.fortran/uses_allocators-7.f90
  9a2ba6cff64ca5bc6375ce44cf49a165  libgomp/testsuite/libgomp.fortran/uses_allocators_1.f90
  112d434e4f93bd46b5f504a2376b9129  libgomp/testsuite/libgomp.fortran/uses_allocators_2.f90
  fecda9fc3e70ac57c13ecf7a85196138  libgomp/testsuite/libgomp.fortran/vla1.f90
*************** d680e7307fb59fe24f8431e179191f16  libssp
*** 143246,143252 ****
  534c3fb4a88e5c1f70db35c12b7742c3  libssp/vsnprintf-chk.c
  34daeb04a522ee796098df4446d6ce61  libssp/vsprintf-chk.c
  9e2de2e1f20ab0ffa2201164de02824f  libstdc++-v3/.editorconfig
! 30c65053f82c46a2d45fc72d62f8a24f  libstdc++-v3/ChangeLog
  7aa6c40440a44fcf5ec94c066160c2f8  libstdc++-v3/ChangeLog-1998
  7aff86600b6a1ed3fa87305075a92db0  libstdc++-v3/ChangeLog-1999
  a6f28e8fc9bb07696a9e068b439a3a87  libstdc++-v3/ChangeLog-2000
--- 143395,143401 ----
  534c3fb4a88e5c1f70db35c12b7742c3  libssp/vsnprintf-chk.c
  34daeb04a522ee796098df4446d6ce61  libssp/vsprintf-chk.c
  9e2de2e1f20ab0ffa2201164de02824f  libstdc++-v3/.editorconfig
! f66b0f51148d0263c1e6f381a8a467da  libstdc++-v3/ChangeLog
  7aa6c40440a44fcf5ec94c066160c2f8  libstdc++-v3/ChangeLog-1998
  7aff86600b6a1ed3fa87305075a92db0  libstdc++-v3/ChangeLog-1999
  a6f28e8fc9bb07696a9e068b439a3a87  libstdc++-v3/ChangeLog-2000
*************** bde027a723c2d8c3d63a6878dce6d0e4  libstd
*** 143439,143445 ****
  b4e7e61f1004abb042359425cc117dd9  libstdc++-v3/config/os/mingw32-w64/ctype_configure_char.cc
  0e67e3c4ad62bc9d22bebe77f89dd73a  libstdc++-v3/config/os/mingw32-w64/ctype_inline.h
  9f956dbe9cf2891c557bf3926f63f7e9  libstdc++-v3/config/os/mingw32-w64/error_constants.h
! 4bc2c3119600ecace2229a1da6875de3  libstdc++-v3/config/os/mingw32-w64/os_defines.h
  bde027a723c2d8c3d63a6878dce6d0e4  libstdc++-v3/config/os/mingw32/ctype_base.h
  b4e7e61f1004abb042359425cc117dd9  libstdc++-v3/config/os/mingw32/ctype_configure_char.cc
  0e67e3c4ad62bc9d22bebe77f89dd73a  libstdc++-v3/config/os/mingw32/ctype_inline.h
--- 143588,143594 ----
  b4e7e61f1004abb042359425cc117dd9  libstdc++-v3/config/os/mingw32-w64/ctype_configure_char.cc
  0e67e3c4ad62bc9d22bebe77f89dd73a  libstdc++-v3/config/os/mingw32-w64/ctype_inline.h
  9f956dbe9cf2891c557bf3926f63f7e9  libstdc++-v3/config/os/mingw32-w64/error_constants.h
! 707d81312fa59e7206b2c68010c23e45  libstdc++-v3/config/os/mingw32-w64/os_defines.h
  bde027a723c2d8c3d63a6878dce6d0e4  libstdc++-v3/config/os/mingw32/ctype_base.h
  b4e7e61f1004abb042359425cc117dd9  libstdc++-v3/config/os/mingw32/ctype_configure_char.cc
  0e67e3c4ad62bc9d22bebe77f89dd73a  libstdc++-v3/config/os/mingw32/ctype_inline.h
*************** a04390416b071401200d585473d823f2  libstd
*** 143920,143926 ****
  c2f5862787920c2fc07b4f499e362a00  libstdc++-v3/include/bits/alloc_traits.h
  752923e212a8a01f4d659889177a76eb  libstdc++-v3/include/bits/allocated_ptr.h
  d18c16b3c9c3ab2e7d487de90ec27d17  libstdc++-v3/include/bits/allocator.h
! 2b1a23c26b949972792d8aaa9bfecb81  libstdc++-v3/include/bits/atomic_base.h
  7c88fbee1dffec663e740720882b5344  libstdc++-v3/include/bits/atomic_futex.h
  bbb2e6df693b76b595fa2fb59b423b42  libstdc++-v3/include/bits/atomic_timed_wait.h
  40e1eb93e4f9a6472b74fe13470d2ef5  libstdc++-v3/include/bits/atomic_wait.h
--- 144069,144075 ----
  c2f5862787920c2fc07b4f499e362a00  libstdc++-v3/include/bits/alloc_traits.h
  752923e212a8a01f4d659889177a76eb  libstdc++-v3/include/bits/allocated_ptr.h
  d18c16b3c9c3ab2e7d487de90ec27d17  libstdc++-v3/include/bits/allocator.h
! cc55a60b5d4be55ea930ce9404fbf0ea  libstdc++-v3/include/bits/atomic_base.h
  7c88fbee1dffec663e740720882b5344  libstdc++-v3/include/bits/atomic_futex.h
  bbb2e6df693b76b595fa2fb59b423b42  libstdc++-v3/include/bits/atomic_timed_wait.h
  40e1eb93e4f9a6472b74fe13470d2ef5  libstdc++-v3/include/bits/atomic_wait.h
*************** a155d2afa910d24be0955f42c4585228  libstd
*** 143935,143947 ****
  5384dfbb9eb9731df3aca40e40d55350  libstdc++-v3/include/bits/char_traits.h
  195dabcb74f9b313c574745539925b0e  libstdc++-v3/include/bits/charconv.h
  0cb9a3c5bdddb11656d4542f26a916dc  libstdc++-v3/include/bits/chrono.h
! 0021dee9f87c2d7b4963da843d73afb1  libstdc++-v3/include/bits/chrono_io.h
  2ff73cb405cb01626a751e0fa0f339f3  libstdc++-v3/include/bits/codecvt.h
  23fc42ee8644308c793f44d20f00420e  libstdc++-v3/include/bits/concept_check.h
  4754401e820e3e65a300a2d3498a37db  libstdc++-v3/include/bits/cow_string.h
! ab10cb2f08652ed880121613c166fb90  libstdc++-v3/include/bits/cpp_type_traits.h
  1a6ab365d16951ef25f6a0b562b27ede  libstdc++-v3/include/bits/cpyfunc_impl.h
! 57a11de44210dce26e42e6cb05249448  libstdc++-v3/include/bits/deque.tcc
  be08582d1795753f6e8fb613a7ec9fe0  libstdc++-v3/include/bits/elements_of.h
  397af990234a7f718cce0f629f7d8b13  libstdc++-v3/include/bits/enable_special_members.h
  b194eb42ed4e3bc3a3f65805561d45c8  libstdc++-v3/include/bits/erase_if.h
--- 144084,144096 ----
  5384dfbb9eb9731df3aca40e40d55350  libstdc++-v3/include/bits/char_traits.h
  195dabcb74f9b313c574745539925b0e  libstdc++-v3/include/bits/charconv.h
  0cb9a3c5bdddb11656d4542f26a916dc  libstdc++-v3/include/bits/chrono.h
! 76f76ab755d9be22c3744eeb8bf22bbd  libstdc++-v3/include/bits/chrono_io.h
  2ff73cb405cb01626a751e0fa0f339f3  libstdc++-v3/include/bits/codecvt.h
  23fc42ee8644308c793f44d20f00420e  libstdc++-v3/include/bits/concept_check.h
  4754401e820e3e65a300a2d3498a37db  libstdc++-v3/include/bits/cow_string.h
! 99e27d0e9f901a89456fd825af83fed7  libstdc++-v3/include/bits/cpp_type_traits.h
  1a6ab365d16951ef25f6a0b562b27ede  libstdc++-v3/include/bits/cpyfunc_impl.h
! 184cb69fd9197ed68b58064385e7aa8f  libstdc++-v3/include/bits/deque.tcc
  be08582d1795753f6e8fb613a7ec9fe0  libstdc++-v3/include/bits/elements_of.h
  397af990234a7f718cce0f629f7d8b13  libstdc++-v3/include/bits/enable_special_members.h
  b194eb42ed4e3bc3a3f65805561d45c8  libstdc++-v3/include/bits/erase_if.h
*************** a0ff2aff5e6b290f02129d8fd5066f94  libstd
*** 143997,144006 ****
  e2b07d6bac5a54e44812c2b83a5ccb42  libstdc++-v3/include/bits/predefined_ops.h
  26211880ae17ac4d714473ad1bc786e4  libstdc++-v3/include/bits/ptr_traits.h
  0ee20b758bc3a6d8ca12b81847727538  libstdc++-v3/include/bits/quoted_string.h
! 5d0c406a949446a5a88fc858e3f5724f  libstdc++-v3/include/bits/random.h
! 4593452a515fffc6707a958d6847c516  libstdc++-v3/include/bits/random.tcc
  b0c29f09a819ac9aa11c3507409c11ef  libstdc++-v3/include/bits/range_access.h
! 035d554aee03ff3b4aaec00ee2b7c36a  libstdc++-v3/include/bits/ranges_algo.h
  603de5fc22f9ccbe5726390148fc3a09  libstdc++-v3/include/bits/ranges_algobase.h
  74b46462d5eb1196370b00da56c5378f  libstdc++-v3/include/bits/ranges_base.h
  b6eed13c8fe4256b2bc0de7419a05bb5  libstdc++-v3/include/bits/ranges_cmp.h
--- 144146,144155 ----
  e2b07d6bac5a54e44812c2b83a5ccb42  libstdc++-v3/include/bits/predefined_ops.h
  26211880ae17ac4d714473ad1bc786e4  libstdc++-v3/include/bits/ptr_traits.h
  0ee20b758bc3a6d8ca12b81847727538  libstdc++-v3/include/bits/quoted_string.h
! f05623507e3ff718982faa1d1f0d5804  libstdc++-v3/include/bits/random.h
! 0286e9e9f74de40a765219fc2872c153  libstdc++-v3/include/bits/random.tcc
  b0c29f09a819ac9aa11c3507409c11ef  libstdc++-v3/include/bits/range_access.h
! 5d339979abd71425e50f64ada9c6b608  libstdc++-v3/include/bits/ranges_algo.h
  603de5fc22f9ccbe5726390148fc3a09  libstdc++-v3/include/bits/ranges_algobase.h
  74b46462d5eb1196370b00da56c5378f  libstdc++-v3/include/bits/ranges_base.h
  b6eed13c8fe4256b2bc0de7419a05bb5  libstdc++-v3/include/bits/ranges_cmp.h
*************** cffd73f057e9c37be8d8f13e0e97c5c0  libstd
*** 144023,144029 ****
  37bc69a700bfdf4f91c9ebd678231ea8  libstdc++-v3/include/bits/sat_arith.h
  0323932b17809619626eeceaf3ad375f  libstdc++-v3/include/bits/semaphore_base.h
  ec9967579f5a56f1f687a745536eafea  libstdc++-v3/include/bits/shared_ptr.h
! 1d175c4fafbb8ff4655e2de7f60b5ae7  libstdc++-v3/include/bits/shared_ptr_atomic.h
  e7a0f2e6e40ce70d795ab8cb06878277  libstdc++-v3/include/bits/shared_ptr_base.h
  d050e025f60dc3eef08990d737b75085  libstdc++-v3/include/bits/slice_array.h
  1aed7661ceda20bd5c9830dbe12ceef8  libstdc++-v3/include/bits/specfun.h
--- 144172,144178 ----
  37bc69a700bfdf4f91c9ebd678231ea8  libstdc++-v3/include/bits/sat_arith.h
  0323932b17809619626eeceaf3ad375f  libstdc++-v3/include/bits/semaphore_base.h
  ec9967579f5a56f1f687a745536eafea  libstdc++-v3/include/bits/shared_ptr.h
! 17648ee5e3e9fa8c41227179cc887cfc  libstdc++-v3/include/bits/shared_ptr_atomic.h
  e7a0f2e6e40ce70d795ab8cb06878277  libstdc++-v3/include/bits/shared_ptr_base.h
  d050e025f60dc3eef08990d737b75085  libstdc++-v3/include/bits/slice_array.h
  1aed7661ceda20bd5c9830dbe12ceef8  libstdc++-v3/include/bits/specfun.h
*************** bb19c550085b43f6251959e05791f4c6  libstd
*** 144036,144050 ****
  76d7a6303d5a8566aefdb4f4de3d3935  libstdc++-v3/include/bits/stdexcept_throw.h
  366b7eaf3d477f3a3b8bad91c143ab2c  libstdc++-v3/include/bits/stdexcept_throwdef.h
  f33e4980fe75fd40c1f3d234474f6fab  libstdc++-v3/include/bits/stdexcept_throwfwd.h
! de56251aaccb7f2a48169f9f6b369cf6  libstdc++-v3/include/bits/stl_algo.h
! 64c183f3d93df5d0d4a6b887dc9205b1  libstdc++-v3/include/bits/stl_algobase.h
  50378fb402a4f63ad663a2763f5cd08a  libstdc++-v3/include/bits/stl_bvector.h
  8abaf8c2264c2af42f3e3ac2a8bb1941  libstdc++-v3/include/bits/stl_construct.h
  ca1849d33a84098658d3310146abebf0  libstdc++-v3/include/bits/stl_deque.h
  ce452f748be2c455c1ac0f358be411e7  libstdc++-v3/include/bits/stl_function.h
  741f55b507d0ff8007014ce8927ac8d8  libstdc++-v3/include/bits/stl_heap.h
  7f15896f0e815aaa22a610841ad076bd  libstdc++-v3/include/bits/stl_iterator.h
! 8985b7e75e42ac4e5951cc4e88df3455  libstdc++-v3/include/bits/stl_iterator_base_funcs.h
  54bf96df9d7600b71ab8d00f28c7e6de  libstdc++-v3/include/bits/stl_iterator_base_types.h
  4f93444bfce714698d1c4bd36a134164  libstdc++-v3/include/bits/stl_list.h
  f0b5fa38097d4f2d3e8f4137582b16a3  libstdc++-v3/include/bits/stl_map.h
--- 144185,144199 ----
  76d7a6303d5a8566aefdb4f4de3d3935  libstdc++-v3/include/bits/stdexcept_throw.h
  366b7eaf3d477f3a3b8bad91c143ab2c  libstdc++-v3/include/bits/stdexcept_throwdef.h
  f33e4980fe75fd40c1f3d234474f6fab  libstdc++-v3/include/bits/stdexcept_throwfwd.h
! 6727229ce17ddadf1c9ac49643cefa8b  libstdc++-v3/include/bits/stl_algo.h
! be033dedbc940fb4511c3a69117deed3  libstdc++-v3/include/bits/stl_algobase.h
  50378fb402a4f63ad663a2763f5cd08a  libstdc++-v3/include/bits/stl_bvector.h
  8abaf8c2264c2af42f3e3ac2a8bb1941  libstdc++-v3/include/bits/stl_construct.h
  ca1849d33a84098658d3310146abebf0  libstdc++-v3/include/bits/stl_deque.h
  ce452f748be2c455c1ac0f358be411e7  libstdc++-v3/include/bits/stl_function.h
  741f55b507d0ff8007014ce8927ac8d8  libstdc++-v3/include/bits/stl_heap.h
  7f15896f0e815aaa22a610841ad076bd  libstdc++-v3/include/bits/stl_iterator.h
! d6fa970dba28c6ed3d064f3f0db15596  libstdc++-v3/include/bits/stl_iterator_base_funcs.h
  54bf96df9d7600b71ab8d00f28c7e6de  libstdc++-v3/include/bits/stl_iterator_base_types.h
  4f93444bfce714698d1c4bd36a134164  libstdc++-v3/include/bits/stl_list.h
  f0b5fa38097d4f2d3e8f4137582b16a3  libstdc++-v3/include/bits/stl_map.h
*************** ef960a69cca203133e14f230f029c45f  libstd
*** 144059,144065 ****
  c48928d63732da42056105c33cf860ff  libstdc++-v3/include/bits/stl_stack.h
  e77200e337d1f4695ed04b8f6fd9991d  libstdc++-v3/include/bits/stl_tempbuf.h
  ac768cd1868664a11e86594d35aa3270  libstdc++-v3/include/bits/stl_tree.h
! acafb6ad2e0035c5b84058721e364dca  libstdc++-v3/include/bits/stl_uninitialized.h
  3d69e173970f30161e10fefe302d77b3  libstdc++-v3/include/bits/stl_vector.h
  c021eea8ffb782c5cae76e39deaa7369  libstdc++-v3/include/bits/stream_iterator.h
  69fecd7181ec71c850dba6e19cf9a58c  libstdc++-v3/include/bits/streambuf.tcc
--- 144208,144214 ----
  c48928d63732da42056105c33cf860ff  libstdc++-v3/include/bits/stl_stack.h
  e77200e337d1f4695ed04b8f6fd9991d  libstdc++-v3/include/bits/stl_tempbuf.h
  ac768cd1868664a11e86594d35aa3270  libstdc++-v3/include/bits/stl_tree.h
! 174b312f57db49e6834eea5f1d01f843  libstdc++-v3/include/bits/stl_uninitialized.h
  3d69e173970f30161e10fefe302d77b3  libstdc++-v3/include/bits/stl_vector.h
  c021eea8ffb782c5cae76e39deaa7369  libstdc++-v3/include/bits/stream_iterator.h
  69fecd7181ec71c850dba6e19cf9a58c  libstdc++-v3/include/bits/streambuf.tcc
*************** f82756dba1eb6b3ea0ca4d3ed0da3773  libstd
*** 144083,144090 ****
  3ddbcccf58411251c2825ae41b697844  libstdc++-v3/include/bits/valarray_array.tcc
  a4c99020fc6d28e94d24a3f60a71b6ec  libstdc++-v3/include/bits/valarray_before.h
  6adf2ccea897e9d5fc8e7650eceac96f  libstdc++-v3/include/bits/vector.tcc
! b6c5eab1d9a91685768704b109339aaf  libstdc++-v3/include/bits/version.def
! 5c4dd8cef7b06a6966612af388c91e64  libstdc++-v3/include/bits/version.h
  602b081d70553843ef4511ca8ec803c9  libstdc++-v3/include/bits/version.tpl
  6ccd70c0c36dd38ba559c1fc5a05fbd0  libstdc++-v3/include/c/cassert
  c31b54f25b2f8c7ca3ca3eec930d4e1d  libstdc++-v3/include/c/cctype
--- 144232,144239 ----
  3ddbcccf58411251c2825ae41b697844  libstdc++-v3/include/bits/valarray_array.tcc
  a4c99020fc6d28e94d24a3f60a71b6ec  libstdc++-v3/include/bits/valarray_before.h
  6adf2ccea897e9d5fc8e7650eceac96f  libstdc++-v3/include/bits/vector.tcc
! 9dd3a6f5395d465aa43b72201bac96ca  libstdc++-v3/include/bits/version.def
! d93fa84a7a0456c1175a93baefd68dae  libstdc++-v3/include/bits/version.h
  602b081d70553843ef4511ca8ec803c9  libstdc++-v3/include/bits/version.tpl
  6ccd70c0c36dd38ba559c1fc5a05fbd0  libstdc++-v3/include/c/cassert
  c31b54f25b2f8c7ca3ca3eec930d4e1d  libstdc++-v3/include/c/cctype
*************** d04ab77d57ea4da4e9368ea91a58b0b9  libstd
*** 144186,144192 ****
  4bfcb8801504f4255afc7240ed87193f  libstdc++-v3/include/debug/formatter.h
  2449beab5eab6049ace03f3e4be6acb0  libstdc++-v3/include/debug/forward_list
  ffc8e7ea0022fb867df992083c41f744  libstdc++-v3/include/debug/functions.h
! 33af44b79ac30bbacc1cfd1f4f3e116c  libstdc++-v3/include/debug/helper_functions.h
  95593578171eceb0a645a3345a408d09  libstdc++-v3/include/debug/inplace_vector
  c56cf423167e7d092ffc37f84df8f959  libstdc++-v3/include/debug/list
  48ad2bbf8cb94bbfb81869406475eaa3  libstdc++-v3/include/debug/macros.h
--- 144335,144341 ----
  4bfcb8801504f4255afc7240ed87193f  libstdc++-v3/include/debug/formatter.h
  2449beab5eab6049ace03f3e4be6acb0  libstdc++-v3/include/debug/forward_list
  ffc8e7ea0022fb867df992083c41f744  libstdc++-v3/include/debug/functions.h
! 91b41c8031068fe38be9d573cf78610e  libstdc++-v3/include/debug/helper_functions.h
  95593578171eceb0a645a3345a408d09  libstdc++-v3/include/debug/inplace_vector
  c56cf423167e7d092ffc37f84df8f959  libstdc++-v3/include/debug/list
  48ad2bbf8cb94bbfb81869406475eaa3  libstdc++-v3/include/debug/macros.h
*************** c5d850b63f4a5052d58fbaa66c5a6b9e  libstd
*** 144196,144202 ****
  1d41253547d7e8329dd21632fb7c523a  libstdc++-v3/include/debug/multiset.h
  d91aa8714bf3440140ff3ce06fcf6a8a  libstdc++-v3/include/debug/safe_base.h
  0f2fbdc2123d808c40d7944c7a4b111d  libstdc++-v3/include/debug/safe_container.h
! 33c36c3ee85f1599105b92bf2fbef34d  libstdc++-v3/include/debug/safe_iterator.h
  d6bcf138ca31811eb1e7b8c10ea1b3b8  libstdc++-v3/include/debug/safe_iterator.tcc
  59e65cdeb71c21b01a6f79721c97b8dc  libstdc++-v3/include/debug/safe_local_iterator.h
  0b8246199e84b21d0c9acb326649404f  libstdc++-v3/include/debug/safe_local_iterator.tcc
--- 144345,144351 ----
  1d41253547d7e8329dd21632fb7c523a  libstdc++-v3/include/debug/multiset.h
  d91aa8714bf3440140ff3ce06fcf6a8a  libstdc++-v3/include/debug/safe_base.h
  0f2fbdc2123d808c40d7944c7a4b111d  libstdc++-v3/include/debug/safe_container.h
! e3e668b770c8abc882d376570ea46fe4  libstdc++-v3/include/debug/safe_iterator.h
  d6bcf138ca31811eb1e7b8c10ea1b3b8  libstdc++-v3/include/debug/safe_iterator.tcc
  59e65cdeb71c21b01a6f79721c97b8dc  libstdc++-v3/include/debug/safe_local_iterator.h
  0b8246199e84b21d0c9acb326649404f  libstdc++-v3/include/debug/safe_local_iterator.tcc
*************** f1cc3238df41adc204bc4f90accc63f3  libstd
*** 144631,144645 ****
  9641fe465599079a5bc733f08bd242eb  libstdc++-v3/include/pstl/unseq_backend_simd.h
  6e7da3aed3b413aec47ea7457e6ea726  libstdc++-v3/include/pstl/utils.h
  2bd04b33c3c9ee14ba8890fcbceb4328  libstdc++-v3/include/std/.editorconfig
! d26c17df4d8dbf3f28df91e901fb1ae2  libstdc++-v3/include/std/algorithm
  d891b88417c6426b21aee63c74ec4e98  libstdc++-v3/include/std/any
  15534634b73cbb2a8e3a5841166aeef3  libstdc++-v3/include/std/array
! 3e7b188185af6d862ad47487fc129213  libstdc++-v3/include/std/atomic
! d1730a41b18e21cbac0f5328aad2d223  libstdc++-v3/include/std/barrier
  66a9c513e3e5b0698ace3297c819bdcf  libstdc++-v3/include/std/bit
  95561699be9789488c473023d620b45c  libstdc++-v3/include/std/bitset
  a005537f5caa45d5b19156fada65b9b8  libstdc++-v3/include/std/charconv
! d6def2fbc6c487eccc892bf726821e1a  libstdc++-v3/include/std/chrono
  a90e2b9ed2c236c92f3f2387a39a0ac8  libstdc++-v3/include/std/codecvt
  489f1fa388f56f93420713f979711c6b  libstdc++-v3/include/std/complex
  f97745aad50f0c7e3a7c84deb2b3b179  libstdc++-v3/include/std/concepts
--- 144780,144794 ----
  9641fe465599079a5bc733f08bd242eb  libstdc++-v3/include/pstl/unseq_backend_simd.h
  6e7da3aed3b413aec47ea7457e6ea726  libstdc++-v3/include/pstl/utils.h
  2bd04b33c3c9ee14ba8890fcbceb4328  libstdc++-v3/include/std/.editorconfig
! bba760acdd69d0d05d36caa5e98f9441  libstdc++-v3/include/std/algorithm
  d891b88417c6426b21aee63c74ec4e98  libstdc++-v3/include/std/any
  15534634b73cbb2a8e3a5841166aeef3  libstdc++-v3/include/std/array
! 7f8e368da06d1c957bcd27471902f05f  libstdc++-v3/include/std/atomic
! 42cb5af5fdc1d15b7c1fec4d253df378  libstdc++-v3/include/std/barrier
  66a9c513e3e5b0698ace3297c819bdcf  libstdc++-v3/include/std/bit
  95561699be9789488c473023d620b45c  libstdc++-v3/include/std/bitset
  a005537f5caa45d5b19156fada65b9b8  libstdc++-v3/include/std/charconv
! 2bee5d03fd48437004d51afb54d3704b  libstdc++-v3/include/std/chrono
  a90e2b9ed2c236c92f3f2387a39a0ac8  libstdc++-v3/include/std/codecvt
  489f1fa388f56f93420713f979711c6b  libstdc++-v3/include/std/complex
  f97745aad50f0c7e3a7c84deb2b3b179  libstdc++-v3/include/std/concepts
*************** c9ef2791c2dc0d6c98a1a85c8f6aa473  libstd
*** 144671,144681 ****
  f4af31191dea172207576960ad71d42d  libstdc++-v3/include/std/locale
  8b76fc7da76f0579c2fd1f22821d03be  libstdc++-v3/include/std/map
  0ad5b6c8098cd5eba2a4160a431f554d  libstdc++-v3/include/std/mdspan
! 563ae67a140bca148dc565c4a845d161  libstdc++-v3/include/std/memory
  9e86c11ff29d60fddf403674e9182b36  libstdc++-v3/include/std/memory_resource
! 154adad15522042ed2886d969f645c0b  libstdc++-v3/include/std/mutex
  ef0d0725f5b70a4c1b5b62b84b2b63f7  libstdc++-v3/include/std/numbers
! b944796362aa39fc1cba3747d2247464  libstdc++-v3/include/std/numeric
  20a657a251637e353b23e9f9177ee1ee  libstdc++-v3/include/std/optional
  050dc2c12dd36f95d5fbe750ff182a38  libstdc++-v3/include/std/ostream
  fd773662a4b346f11b66520f34a8898e  libstdc++-v3/include/std/print
--- 144820,144830 ----
  f4af31191dea172207576960ad71d42d  libstdc++-v3/include/std/locale
  8b76fc7da76f0579c2fd1f22821d03be  libstdc++-v3/include/std/map
  0ad5b6c8098cd5eba2a4160a431f554d  libstdc++-v3/include/std/mdspan
! 367e72fbd22bc79f4cde7cd2ace0e295  libstdc++-v3/include/std/memory
  9e86c11ff29d60fddf403674e9182b36  libstdc++-v3/include/std/memory_resource
! 5f32db0a8a61c079237624e0e41a858e  libstdc++-v3/include/std/mutex
  ef0d0725f5b70a4c1b5b62b84b2b63f7  libstdc++-v3/include/std/numbers
! 0764ff81f2cf3719884e913423c1f33a  libstdc++-v3/include/std/numeric
  20a657a251637e353b23e9f9177ee1ee  libstdc++-v3/include/std/optional
  050dc2c12dd36f95d5fbe750ff182a38  libstdc++-v3/include/std/ostream
  fd773662a4b346f11b66520f34a8898e  libstdc++-v3/include/std/print
*************** af06c1788519332260aca1c43501b543  libstd
*** 144705,144717 ****
  608edef7344e2e25c7b00170df6fa9e6  libstdc++-v3/include/std/text_encoding
  0ed8103f880c65d72326076bb36a84d2  libstdc++-v3/include/std/thread
  8456c84295d4d092b0b55a359845078d  libstdc++-v3/include/std/tuple
! 58e23728dc03d07437abac18ce1cf55e  libstdc++-v3/include/std/type_traits
  237682577d22ec3f9f5046abf0acd8e7  libstdc++-v3/include/std/typeindex
  520c52362f53e18f20838693cfd131bf  libstdc++-v3/include/std/unordered_map
  c82be32edefaa23cc1228b092d319315  libstdc++-v3/include/std/unordered_set
  cce1369fb552a9bb18d80b605d122c45  libstdc++-v3/include/std/utility
  14c64f3107d654e98e9cad7d2b1a2bac  libstdc++-v3/include/std/valarray
! c83eab68f3ca52f93f964f3068c4146f  libstdc++-v3/include/std/variant
  54cb5753db7ef9673ab74fcd2fbd75d6  libstdc++-v3/include/std/vector
  1c10633087657ad7a31f6c3569a3ebe0  libstdc++-v3/include/std/version
  4277499f8a01c2dff2f84e3c3f5cba43  libstdc++-v3/include/tr1/array
--- 144854,144866 ----
  608edef7344e2e25c7b00170df6fa9e6  libstdc++-v3/include/std/text_encoding
  0ed8103f880c65d72326076bb36a84d2  libstdc++-v3/include/std/thread
  8456c84295d4d092b0b55a359845078d  libstdc++-v3/include/std/tuple
! fc8d7971cdf178d8d1f646ccbd5cf145  libstdc++-v3/include/std/type_traits
  237682577d22ec3f9f5046abf0acd8e7  libstdc++-v3/include/std/typeindex
  520c52362f53e18f20838693cfd131bf  libstdc++-v3/include/std/unordered_map
  c82be32edefaa23cc1228b092d319315  libstdc++-v3/include/std/unordered_set
  cce1369fb552a9bb18d80b605d122c45  libstdc++-v3/include/std/utility
  14c64f3107d654e98e9cad7d2b1a2bac  libstdc++-v3/include/std/valarray
! b07b51cc2bf35338c67ac820a58edf93  libstdc++-v3/include/std/variant
  54cb5753db7ef9673ab74fcd2fbd75d6  libstdc++-v3/include/std/vector
  1c10633087657ad7a31f6c3569a3ebe0  libstdc++-v3/include/std/version
  4277499f8a01c2dff2f84e3c3f5cba43  libstdc++-v3/include/tr1/array
*************** eb18701dec73b580133ac3818cf6617f  libstd
*** 144951,144957 ****
  8b2762ff1cf52ac591b65ff11d0285d5  libstdc++-v3/src/c++11/locale-inst.cc
  039814637549f9711143c6b2687f4e03  libstdc++-v3/src/c++11/locale_init.cc
  05e7c5185b6edd017225c0514d9d5c2c  libstdc++-v3/src/c++11/localename.cc
! fe798e7b6ed341445d180675eb4fb53d  libstdc++-v3/src/c++11/mutex.cc
  08e22c5ba954ee9431bb4c897303ac16  libstdc++-v3/src/c++11/mutex_pool.h
  dbbbe37a5a3b86855b51fa69cb4fab23  libstdc++-v3/src/c++11/ostream-inst.cc
  75a70286896b5e9d774527af220c188a  libstdc++-v3/src/c++11/placeholders.cc
--- 145100,145106 ----
  8b2762ff1cf52ac591b65ff11d0285d5  libstdc++-v3/src/c++11/locale-inst.cc
  039814637549f9711143c6b2687f4e03  libstdc++-v3/src/c++11/locale_init.cc
  05e7c5185b6edd017225c0514d9d5c2c  libstdc++-v3/src/c++11/localename.cc
! b3094deb5d6fe15a7b152509c89d16c2  libstdc++-v3/src/c++11/mutex.cc
  08e22c5ba954ee9431bb4c897303ac16  libstdc++-v3/src/c++11/mutex_pool.h
  dbbbe37a5a3b86855b51fa69cb4fab23  libstdc++-v3/src/c++11/ostream-inst.cc
  75a70286896b5e9d774527af220c188a  libstdc++-v3/src/c++11/placeholders.cc
*************** ac664105ccfd50a2a092e98df11864a3  libstd
*** 145009,145016 ****
  94b3ab191e8fe566a951ac2b4f081c40  libstdc++-v3/src/c++20/format.cc
  939eb3ac7ce3c32a8b2aac493f053893  libstdc++-v3/src/c++20/sstream-inst.cc
  6b7e270cd96c865db9baa1ad0df93823  libstdc++-v3/src/c++20/syncbuf.cc
! e9e89f4578e59d252e4caaf0b63d6dfb  libstdc++-v3/src/c++20/tzdata.zi
! e7b5fbbd5ee61bf8fbf8702b095de326  libstdc++-v3/src/c++20/tzdb.cc
  ac7b7a080d5f7aa8fe6a26188631fc18  libstdc++-v3/src/c++20/windows_zones-map.h
  3665d657cc35c7afb8b5cc7bae0ef058  libstdc++-v3/src/c++23/Makefile.am
  ba1de75ac9c1bb7d2506c503fe17708a  libstdc++-v3/src/c++23/Makefile.in
--- 145158,145165 ----
  94b3ab191e8fe566a951ac2b4f081c40  libstdc++-v3/src/c++20/format.cc
  939eb3ac7ce3c32a8b2aac493f053893  libstdc++-v3/src/c++20/sstream-inst.cc
  6b7e270cd96c865db9baa1ad0df93823  libstdc++-v3/src/c++20/syncbuf.cc
! 5f51e6efda14986b9b4932b46f8e73c3  libstdc++-v3/src/c++20/tzdata.zi
! 0bc6217c7afbcd055496ad3d341a5de0  libstdc++-v3/src/c++20/tzdb.cc
  ac7b7a080d5f7aa8fe6a26188631fc18  libstdc++-v3/src/c++20/windows_zones-map.h
  3665d657cc35c7afb8b5cc7bae0ef058  libstdc++-v3/src/c++23/Makefile.am
  ba1de75ac9c1bb7d2506c503fe17708a  libstdc++-v3/src/c++23/Makefile.in
*************** bb688b1bf0bbfcf18f17ecc4aceccfa1  libstd
*** 145160,145166 ****
  078cee4676bbf4e43b6d9434dcbaa62f  libstdc++-v3/testsuite/18_support/cxa_vec.cc
  37fe08e5125d8624f4aa4900e2c144a8  libstdc++-v3/testsuite/18_support/destroying_delete.cc
  198455a37447986dc59d680adafc35c8  libstdc++-v3/testsuite/18_support/exception/38732.cc
! 808d3bf1ddffb9a68649208dcb425467  libstdc++-v3/testsuite/18_support/exception/version.cc
  a50173907daec62db9e77f26b56a12b8  libstdc++-v3/testsuite/18_support/exception/what.cc
  8a3e4fc86620d59634749ffecd317237  libstdc++-v3/testsuite/18_support/exception_ptr/103630.cc
  b68d3b924d0ec6839ff81111c3d60e3e  libstdc++-v3/testsuite/18_support/exception_ptr/40296.cc
--- 145309,145315 ----
  078cee4676bbf4e43b6d9434dcbaa62f  libstdc++-v3/testsuite/18_support/cxa_vec.cc
  37fe08e5125d8624f4aa4900e2c144a8  libstdc++-v3/testsuite/18_support/destroying_delete.cc
  198455a37447986dc59d680adafc35c8  libstdc++-v3/testsuite/18_support/exception/38732.cc
! 066590a9a6a13ab156d192461ff5528e  libstdc++-v3/testsuite/18_support/exception/version.cc
  a50173907daec62db9e77f26b56a12b8  libstdc++-v3/testsuite/18_support/exception/what.cc
  8a3e4fc86620d59634749ffecd317237  libstdc++-v3/testsuite/18_support/exception_ptr/103630.cc
  b68d3b924d0ec6839ff81111c3d60e3e  libstdc++-v3/testsuite/18_support/exception_ptr/40296.cc
*************** cb3fad10e5e26fe4364e24cc72871384  libstd
*** 145171,145177 ****
  cc5dd043c9d14c6d41ee5c1ca240e563  libstdc++-v3/testsuite/18_support/exception_ptr/90295.cc
  8907da30a344e71f1227eec1fae72f2b  libstdc++-v3/testsuite/18_support/exception_ptr/96657.cc
  5ad138fdb1a7eba577340cd01d0f6c41  libstdc++-v3/testsuite/18_support/exception_ptr/current_exception.cc
! 8e42da8ec418cc6ca5a05bcb44d45f06  libstdc++-v3/testsuite/18_support/exception_ptr/exception_ptr_cast.cc
  ee8560e001acdf60c93f0b858cf08201  libstdc++-v3/testsuite/18_support/exception_ptr/lifespan.cc
  6fe7c52ba7ec7ed537581a961d292a99  libstdc++-v3/testsuite/18_support/exception_ptr/make_exception_ptr.cc
  7a48c334b8f976d3830aa87522a6ebe0  libstdc++-v3/testsuite/18_support/exception_ptr/make_exception_ptr_2.cc
--- 145320,145326 ----
  cc5dd043c9d14c6d41ee5c1ca240e563  libstdc++-v3/testsuite/18_support/exception_ptr/90295.cc
  8907da30a344e71f1227eec1fae72f2b  libstdc++-v3/testsuite/18_support/exception_ptr/96657.cc
  5ad138fdb1a7eba577340cd01d0f6c41  libstdc++-v3/testsuite/18_support/exception_ptr/current_exception.cc
! e75dbc9f8ff91043f3e664ca265afe14  libstdc++-v3/testsuite/18_support/exception_ptr/exception_ptr_cast.cc
  ee8560e001acdf60c93f0b858cf08201  libstdc++-v3/testsuite/18_support/exception_ptr/lifespan.cc
  6fe7c52ba7ec7ed537581a961d292a99  libstdc++-v3/testsuite/18_support/exception_ptr/make_exception_ptr.cc
  7a48c334b8f976d3830aa87522a6ebe0  libstdc++-v3/testsuite/18_support/exception_ptr/make_exception_ptr_2.cc
*************** b993c63aa44508888d71e9c3e0d14c6a  libstd
*** 145327,145346 ****
  2c66677d3de8621d918e5cca45feeb18  libstdc++-v3/testsuite/19_diagnostics/headers/cerrno/macros.cc
  fc983a5832136c395f79367b9ae13390  libstdc++-v3/testsuite/19_diagnostics/headers/stdexcept/synopsis.cc
  ca810f42fe48b7c84e0bf80516ec67a4  libstdc++-v3/testsuite/19_diagnostics/headers/stdexcept/types_std.cc
! 229a48db08ce89214fae9059129a0a84  libstdc++-v3/testsuite/19_diagnostics/headers/stdexcept/version.cc
  231951e58fc01e7c15613cf4fbc0bee9  libstdc++-v3/testsuite/19_diagnostics/headers/system_error/34538.cc
  7854cf45dae7fbe0afe099ba62d89005  libstdc++-v3/testsuite/19_diagnostics/headers/system_error/93151.cc
  3d872899fb228bc488fc29036bc906f7  libstdc++-v3/testsuite/19_diagnostics/headers/system_error/errc_std_c++0x.cc
  163d9618cf6ef0d9d2f17cfc172f862f  libstdc++-v3/testsuite/19_diagnostics/headers/system_error/std_c++0x_neg.cc
  b536c9afb85a1022cb103035fcd93a04  libstdc++-v3/testsuite/19_diagnostics/headers/system_error/types_std_c++0x.cc
  9638e9cfb67573686ee977f4a75c7e7d  libstdc++-v3/testsuite/19_diagnostics/logic_error/cons_virtual_derivation.cc
! 463a84605e820c8cc0a48cb7caf23f87  libstdc++-v3/testsuite/19_diagnostics/logic_error/constexpr.cc
  ad0984eec50061c4936ee8f0e6774351  libstdc++-v3/testsuite/19_diagnostics/logic_error/what-1.cc
  fe10001337efb3317a203f5de7cb4836  libstdc++-v3/testsuite/19_diagnostics/logic_error/what-2.cc
  072c061e7c6da4e7fcf5f4cfd735e668  libstdc++-v3/testsuite/19_diagnostics/logic_error/what-3.cc
  844a0a7fb162c9de1b371138cddaacee  libstdc++-v3/testsuite/19_diagnostics/logic_error/what-big.cc
  caf636b4ba58f8cf8b65ce85f998759e  libstdc++-v3/testsuite/19_diagnostics/runtime_error/cons_virtual_derivation.cc
! 4abe2ee94a4e0ae142c41828d51ab50a  libstdc++-v3/testsuite/19_diagnostics/runtime_error/constexpr.cc
  630ffbd2b7a17fe20de854167d931dcd  libstdc++-v3/testsuite/19_diagnostics/runtime_error/what-1.cc
  831fb3ef7996018195e89821e90326e4  libstdc++-v3/testsuite/19_diagnostics/runtime_error/what-2.cc
  4532c3db90095a70c3a0981e4c42da01  libstdc++-v3/testsuite/19_diagnostics/runtime_error/what-3.cc
--- 145476,145495 ----
  2c66677d3de8621d918e5cca45feeb18  libstdc++-v3/testsuite/19_diagnostics/headers/cerrno/macros.cc
  fc983a5832136c395f79367b9ae13390  libstdc++-v3/testsuite/19_diagnostics/headers/stdexcept/synopsis.cc
  ca810f42fe48b7c84e0bf80516ec67a4  libstdc++-v3/testsuite/19_diagnostics/headers/stdexcept/types_std.cc
! 753e93d0fa77f952239b67d8da30e240  libstdc++-v3/testsuite/19_diagnostics/headers/stdexcept/version.cc
  231951e58fc01e7c15613cf4fbc0bee9  libstdc++-v3/testsuite/19_diagnostics/headers/system_error/34538.cc
  7854cf45dae7fbe0afe099ba62d89005  libstdc++-v3/testsuite/19_diagnostics/headers/system_error/93151.cc
  3d872899fb228bc488fc29036bc906f7  libstdc++-v3/testsuite/19_diagnostics/headers/system_error/errc_std_c++0x.cc
  163d9618cf6ef0d9d2f17cfc172f862f  libstdc++-v3/testsuite/19_diagnostics/headers/system_error/std_c++0x_neg.cc
  b536c9afb85a1022cb103035fcd93a04  libstdc++-v3/testsuite/19_diagnostics/headers/system_error/types_std_c++0x.cc
  9638e9cfb67573686ee977f4a75c7e7d  libstdc++-v3/testsuite/19_diagnostics/logic_error/cons_virtual_derivation.cc
! 4fc2e46cacb15efed5bc3b9613445f80  libstdc++-v3/testsuite/19_diagnostics/logic_error/constexpr.cc
  ad0984eec50061c4936ee8f0e6774351  libstdc++-v3/testsuite/19_diagnostics/logic_error/what-1.cc
  fe10001337efb3317a203f5de7cb4836  libstdc++-v3/testsuite/19_diagnostics/logic_error/what-2.cc
  072c061e7c6da4e7fcf5f4cfd735e668  libstdc++-v3/testsuite/19_diagnostics/logic_error/what-3.cc
  844a0a7fb162c9de1b371138cddaacee  libstdc++-v3/testsuite/19_diagnostics/logic_error/what-big.cc
  caf636b4ba58f8cf8b65ce85f998759e  libstdc++-v3/testsuite/19_diagnostics/runtime_error/cons_virtual_derivation.cc
! 8e7f06249f63c55201a37c5438974407  libstdc++-v3/testsuite/19_diagnostics/runtime_error/constexpr.cc
  630ffbd2b7a17fe20de854167d931dcd  libstdc++-v3/testsuite/19_diagnostics/runtime_error/what-1.cc
  831fb3ef7996018195e89821e90326e4  libstdc++-v3/testsuite/19_diagnostics/runtime_error/what-2.cc
  4532c3db90095a70c3a0981e4c42da01  libstdc++-v3/testsuite/19_diagnostics/runtime_error/what-3.cc
*************** b6846002a3a56bb10b1621e1792c246a  libstd
*** 145667,145673 ****
  8c41a21e12dcb978b196eabf48e15513  libstdc++-v3/testsuite/20_util/expected/swap.cc
  44dfca2fb3ccdb8f3ea97514568bab14  libstdc++-v3/testsuite/20_util/expected/synopsis.cc
  4b84f057fc22805edcab3b394acb5a2f  libstdc++-v3/testsuite/20_util/expected/unexpected.cc
! 9871e3d836705c317e0489642b6a82fd  libstdc++-v3/testsuite/20_util/expected/version.cc
  a575f97946121367a0e597dae96cb9dd  libstdc++-v3/testsuite/20_util/extent/requirements/explicit_instantiation.cc
  4b8ed997a5c31981f1fc4aae96c15b38  libstdc++-v3/testsuite/20_util/extent/requirements/typedefs.cc
  87c36e56af23d836f365244a25996af2  libstdc++-v3/testsuite/20_util/extent/value.cc
--- 145816,145822 ----
  8c41a21e12dcb978b196eabf48e15513  libstdc++-v3/testsuite/20_util/expected/swap.cc
  44dfca2fb3ccdb8f3ea97514568bab14  libstdc++-v3/testsuite/20_util/expected/synopsis.cc
  4b84f057fc22805edcab3b394acb5a2f  libstdc++-v3/testsuite/20_util/expected/unexpected.cc
! e6d4278a2513c0fdaeaafe62299be0e9  libstdc++-v3/testsuite/20_util/expected/version.cc
  a575f97946121367a0e597dae96cb9dd  libstdc++-v3/testsuite/20_util/extent/requirements/explicit_instantiation.cc
  4b8ed997a5c31981f1fc4aae96c15b38  libstdc++-v3/testsuite/20_util/extent/requirements/typedefs.cc
  87c36e56af23d836f365244a25996af2  libstdc++-v3/testsuite/20_util/extent/value.cc
*************** a6e4231f1606e2be084d98550f7242cd  libstd
*** 146306,146312 ****
  0f3d45388c61f51b7f6df124ff507aaa  libstdc++-v3/testsuite/20_util/optional/swap/1.cc
  001a4c1e1cdc738cbb337a561fdf8f1b  libstdc++-v3/testsuite/20_util/optional/swap/2.cc
  87b708c4b560c5395ed1befec2f78c20  libstdc++-v3/testsuite/20_util/optional/typedefs.cc
! f5ef77c565e21bdf9e860ca5c4bfec07  libstdc++-v3/testsuite/20_util/optional/version.cc
  822529fe3664026abe193e232af92eb1  libstdc++-v3/testsuite/20_util/owner_equal/cmp.cc
  d301a9d092bb6e8452ae1ebce956a4e2  libstdc++-v3/testsuite/20_util/owner_equal/noexcept.cc
  8d07ce272199306a82af04d41bd63384  libstdc++-v3/testsuite/20_util/owner_equal/version.cc
--- 146455,146461 ----
  0f3d45388c61f51b7f6df124ff507aaa  libstdc++-v3/testsuite/20_util/optional/swap/1.cc
  001a4c1e1cdc738cbb337a561fdf8f1b  libstdc++-v3/testsuite/20_util/optional/swap/2.cc
  87b708c4b560c5395ed1befec2f78c20  libstdc++-v3/testsuite/20_util/optional/typedefs.cc
! 29609cbb181463c2f90cf3dec1096fc9  libstdc++-v3/testsuite/20_util/optional/version.cc
  822529fe3664026abe193e232af92eb1  libstdc++-v3/testsuite/20_util/owner_equal/cmp.cc
  d301a9d092bb6e8452ae1ebce956a4e2  libstdc++-v3/testsuite/20_util/owner_equal/noexcept.cc
  8d07ce272199306a82af04d41bd63384  libstdc++-v3/testsuite/20_util/owner_equal/version.cc
*************** c2e30b2ec16642f486b80b9842fc91fd  libstd
*** 146912,146918 ****
  79e926626c7dc3719ed0dffd8aaed843  libstdc++-v3/testsuite/20_util/variable_templates_for_traits.cc
  b9698b5e78dcefad507d6737875a6a1d  libstdc++-v3/testsuite/20_util/variant/100384.cc
  5ef3d7df10dd90d995e4c63bc62c39de  libstdc++-v3/testsuite/20_util/variant/102912.cc
! 154fba5a48d201d17438edfa7feb44be  libstdc++-v3/testsuite/20_util/variant/112591.cc
  909e769606f79e2311fe65f425279584  libstdc++-v3/testsuite/20_util/variant/80165.cc
  7e5da65bff44ca0a6b8805cd0e06fd94  libstdc++-v3/testsuite/20_util/variant/85183.cc
  becaf5bd5913b3b0b3dcd36c9153e633  libstdc++-v3/testsuite/20_util/variant/86874.cc
--- 147061,147068 ----
  79e926626c7dc3719ed0dffd8aaed843  libstdc++-v3/testsuite/20_util/variable_templates_for_traits.cc
  b9698b5e78dcefad507d6737875a6a1d  libstdc++-v3/testsuite/20_util/variant/100384.cc
  5ef3d7df10dd90d995e4c63bc62c39de  libstdc++-v3/testsuite/20_util/variant/102912.cc
! 8a98faef69d02af6ad48bf92f83aa16d  libstdc++-v3/testsuite/20_util/variant/112591.cc
! aec986d5aa236946fd656f5179088540  libstdc++-v3/testsuite/20_util/variant/112591_compat.cc
  909e769606f79e2311fe65f425279584  libstdc++-v3/testsuite/20_util/variant/80165.cc
  7e5da65bff44ca0a6b8805cd0e06fd94  libstdc++-v3/testsuite/20_util/variant/85183.cc
  becaf5bd5913b3b0b3dcd36c9153e633  libstdc++-v3/testsuite/20_util/variant/86874.cc
*************** a084c83ce7846b185f9f540c49cb60f6  libstd
*** 146924,146929 ****
--- 147074,147081 ----
  2f9a0e0955b9a4162468e53d1072e9d6  libstdc++-v3/testsuite/20_util/variant/any.cc
  d26bd75bbd8dc15059edfed867c29f06  libstdc++-v3/testsuite/20_util/variant/compile.cc
  bf2a98b9d9e5e4d51eeea3285ea8a137  libstdc++-v3/testsuite/20_util/variant/constexpr.cc
+ e2f43242aba2c0b6806b54964c459894  libstdc++-v3/testsuite/20_util/variant/constinit.cc
+ 6dd4f7de3ec923e93a0e57089968e78b  libstdc++-v3/testsuite/20_util/variant/constinit_compat.cc
  aca7fd5a5c0afed062d12c96f859019b  libstdc++-v3/testsuite/20_util/variant/deduction.cc
  1fc2162ff0864215d7d9683e80eb2be2  libstdc++-v3/testsuite/20_util/variant/default_ctor.cc
  8f533dbbd716d58c270e44701e17905c  libstdc++-v3/testsuite/20_util/variant/exception_safety.cc
*************** e56cd950ff384e81521ce2616669bfa4  libstd
*** 146938,146944 ****
  42dd952bd177e86fe26e8cf83e7a8513  libstdc++-v3/testsuite/20_util/variant/relops/three_way.cc
  569408f6d5bf9ab3ed633fdd7024c149  libstdc++-v3/testsuite/20_util/variant/run.cc
  064e84504a9fc3d50cfd8e95617bd6e1  libstdc++-v3/testsuite/20_util/variant/types_neg.cc
! 98288a62dfd35e8c4e7ae292a7be72b4  libstdc++-v3/testsuite/20_util/variant/version.cc
  e412b98c1d840f8bb2292ef008408afe  libstdc++-v3/testsuite/20_util/variant/visit.cc
  17098b13758ee1e3f169c2ee138604aa  libstdc++-v3/testsuite/20_util/variant/visit_inherited.cc
  26d4f9b70627db347289a0f52da37eb4  libstdc++-v3/testsuite/20_util/variant/visit_member.cc
--- 147090,147096 ----
  42dd952bd177e86fe26e8cf83e7a8513  libstdc++-v3/testsuite/20_util/variant/relops/three_way.cc
  569408f6d5bf9ab3ed633fdd7024c149  libstdc++-v3/testsuite/20_util/variant/run.cc
  064e84504a9fc3d50cfd8e95617bd6e1  libstdc++-v3/testsuite/20_util/variant/types_neg.cc
! 1dcdf25d4cb71a0517cb44ae4e3c8fae  libstdc++-v3/testsuite/20_util/variant/version.cc
  e412b98c1d840f8bb2292ef008408afe  libstdc++-v3/testsuite/20_util/variant/visit.cc
  17098b13758ee1e3f169c2ee138604aa  libstdc++-v3/testsuite/20_util/variant/visit_inherited.cc
  26d4f9b70627db347289a0f52da37eb4  libstdc++-v3/testsuite/20_util/variant/visit_member.cc
*************** dc51bf8ec0600eaf13a5e97b344b0c79  libstd
*** 150002,150007 ****
--- 150154,150160 ----
  ae049046b45a395504fd1e8a19c4f18b  libstdc++-v3/testsuite/25_algorithms/copy/108846.cc
  6f8c3f9d5e1238778b6e1ba3a9bb80ef  libstdc++-v3/testsuite/25_algorithms/copy/114817.cc
  23b0d913d66888b7f56b9fe9040957c3  libstdc++-v3/testsuite/25_algorithms/copy/115444.cc
+ 125e1ba85822cfd51c8df1b6a842bc84  libstdc++-v3/testsuite/25_algorithms/copy/122907.cc
  5003c29765774a7418c3443878d83332  libstdc++-v3/testsuite/25_algorithms/copy/2.cc
  273dff5a2d0cc6cda1596a2c8a114fec  libstdc++-v3/testsuite/25_algorithms/copy/3.cc
  809bbcd5453cb854bf0b20b8491fb7da  libstdc++-v3/testsuite/25_algorithms/copy/34595.cc
*************** ade513e8a2631e60e9567596c05ded98  libstd
*** 150173,150178 ****
--- 150326,150332 ----
  34713408c7f0886835ce8dd3cf18f41d  libstdc++-v3/testsuite/25_algorithms/find/requirements/explicit_instantiation/pod.cc
  3ec7f0cb7f5f29b18bb2756be9611163  libstdc++-v3/testsuite/25_algorithms/find/vectorbool.cc
  5d6621b2a92af06f338e0cc4fdcc0f8d  libstdc++-v3/testsuite/25_algorithms/find_end/1.cc
+ 89574b1dd36c06082bf8afe4e1e9de9d  libstdc++-v3/testsuite/25_algorithms/find_end/c++20_iter.cc
  7ced33941da7067dd9f9d4c7c547cd53  libstdc++-v3/testsuite/25_algorithms/find_end/check_type.cc
  6e280f2da18a0a2f3697874279b91b29  libstdc++-v3/testsuite/25_algorithms/find_end/constexpr.cc
  5748d0b0273ef0ac444f3b563aeb6c53  libstdc++-v3/testsuite/25_algorithms/find_end/constrained.cc
*************** f85527739c22f6990850af90763be435  libstd
*** 150636,150641 ****
--- 150790,150796 ----
  37265ad69c9265f70fcea53333e1710f  libstdc++-v3/testsuite/25_algorithms/sample/2.cc
  2f39e5fff2bde6d594bfef4d07df43b6  libstdc++-v3/testsuite/25_algorithms/sample/3.cc
  ece9a25a8b175fc144eaa3d670f457c2  libstdc++-v3/testsuite/25_algorithms/sample/81221.cc
+ 1cd3a73f6e27e313a8e5a6895f96ba0f  libstdc++-v3/testsuite/25_algorithms/sample/c++20_iter.cc
  17fa03de2529c39f708ff37141599605  libstdc++-v3/testsuite/25_algorithms/sample/constrained.cc
  4b86b57fa032c39d07624855123a8805  libstdc++-v3/testsuite/25_algorithms/search/1.cc
  59c71531359e5eec4244bffd6153ac2c  libstdc++-v3/testsuite/25_algorithms/search/78346.cc
*************** a928cb4237d66d3f29e70bd0efc36daf  libstd
*** 150648,150653 ****
--- 150803,150809 ----
  871e52b49c4ea87127a625d78bb44339  libstdc++-v3/testsuite/25_algorithms/search_n/11400.cc
  9463cf2ddc8430ef51456da84915d185  libstdc++-v3/testsuite/25_algorithms/search_n/58358.cc
  98c8fdffd0f3dc67acb72be83c6ecbe3  libstdc++-v3/testsuite/25_algorithms/search_n/97828.cc
+ 2766ae632c8e01a44f7ee469d5055249  libstdc++-v3/testsuite/25_algorithms/search_n/c++20_iter.cc
  108a009373103e3f7c019c20648d0214  libstdc++-v3/testsuite/25_algorithms/search_n/check_type.cc
  bd27c4ffa098323cf8a705ee92ed955f  libstdc++-v3/testsuite/25_algorithms/search_n/constexpr.cc
  0f0e121d31d0d3cf51072530ab344dab  libstdc++-v3/testsuite/25_algorithms/search_n/constrained.cc
*************** c2a6e4f5167c14f8a67e8cb05be28dc5  libstd
*** 150716,150721 ****
--- 150872,150878 ----
  8ee79280c6de5cb635aa18e0b3b6d847  libstdc++-v3/testsuite/25_algorithms/stable_partition/requirements/explicit_instantiation/2.cc
  c37229ac5f227adfb20d4c9fa73ca7b1  libstdc++-v3/testsuite/25_algorithms/stable_partition/requirements/explicit_instantiation/pod.cc
  7af8b4edc6d0a0725b4940df3fa97949  libstdc++-v3/testsuite/25_algorithms/stable_sort/1.cc
+ e1fd5af67bdd8ea34782038792789f84  libstdc++-v3/testsuite/25_algorithms/stable_sort/123180.cc
  8f083109c13605d840c022d54a71a078  libstdc++-v3/testsuite/25_algorithms/stable_sort/2.cc
  d14b7dc2735ee0cc55652801b7160261  libstdc++-v3/testsuite/25_algorithms/stable_sort/3.cc
  b3f58b622470c2e75b734eba5c7ee60a  libstdc++-v3/testsuite/25_algorithms/stable_sort/4.cc
*************** e926410ecd98200362050b556c737fe6  libstd
*** 150762,150767 ****
--- 150919,150925 ----
  af21e5ed22ae1277398751ff84914c01  libstdc++-v3/testsuite/25_algorithms/unique_copy/120384.cc
  566c21bbd932c2ff2ea7ab5d0d026853  libstdc++-v3/testsuite/25_algorithms/unique_copy/2.cc
  bccc2620741d0bb50ee990ac03515498  libstdc++-v3/testsuite/25_algorithms/unique_copy/26133.cc
+ 2d6687e01be5154ecae5563667e339d6  libstdc++-v3/testsuite/25_algorithms/unique_copy/c++20_iter.cc
  9017b16aa2b3514d77f2217dfa840239  libstdc++-v3/testsuite/25_algorithms/unique_copy/check_type.cc
  025c3b6404eb8b477ce9e6cfe7cc6c9f  libstdc++-v3/testsuite/25_algorithms/unique_copy/constexpr.cc
  8aa85ba6eb17f92a2514e964dece3932  libstdc++-v3/testsuite/25_algorithms/unique_copy/constrained.cc
*************** c66820805cf06634dd752a3287e88639  libstd
*** 150932,150937 ****
--- 151090,151096 ----
  185eaf91d6c6b75715f833d6781171d6  libstdc++-v3/testsuite/26_numerics/headers/valarray/synopsis.cc
  6159ad8e029a620d4ad0add12527f8df  libstdc++-v3/testsuite/26_numerics/headers/valarray/types_std.cc
  345b5a89d85a2a9f42356504b5481fb4  libstdc++-v3/testsuite/26_numerics/inclusive_scan/1.cc
+ 3a9d6079bde3a49fdde7c896da374bdc  libstdc++-v3/testsuite/26_numerics/inclusive_scan/c++20_iter.cc
  765b700e23d52c20fc3c98ebe065fc89  libstdc++-v3/testsuite/26_numerics/inclusive_scan/constexpr.cc
  64249bae5ee7a02a2f195280988e62b2  libstdc++-v3/testsuite/26_numerics/inner_product/1.cc
  6e5df95abe24085fac9d4e6d90d2aba7  libstdc++-v3/testsuite/26_numerics/inner_product/constexpr.cc
*************** cda00f041bc7c766be518fce9f533d54  libstd
*** 151146,151160 ****
  23f65a251c55843e9da2ee98b63a9e1e  libstdc++-v3/testsuite/26_numerics/random/normal_distribution/operators/serialize.cc
  a1110c1451e4a44827a2e6970c8b7233  libstdc++-v3/testsuite/26_numerics/random/normal_distribution/requirements/explicit_instantiation/1.cc
  d651f18a094c3dfc0e8c45c131f3cb7f  libstdc++-v3/testsuite/26_numerics/random/normal_distribution/requirements/typedefs.cc
! 4455732d2736b7709b1c8639bd241c58  libstdc++-v3/testsuite/26_numerics/random/philox4x32.cc
! 593d9afb7990d09a1447e933e3ff2338  libstdc++-v3/testsuite/26_numerics/random/philox4x64.cc
! cc19166fbb0ace21df9b897388d7dbfd  libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/copy.cc
! ac57eb09cc97a06ca1819d5c54fb7450  libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/default.cc
! c83ca039cc9c67f1f5071d11619c8791  libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed.cc
! a2123a99800980e0a83c036b268d2b88  libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/equal.cc
! f4220b9dfaed5314c9d6ba8c29a0c096  libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/serialize.cc
! cfe7effda6056656c48d4c02f33d25d7  libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constants.cc
! 29798ea2f2291e1e79f65e51f04a00ae  libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/typedefs.cc
  8af781af7df41c657a94ff0828bdaafe  libstdc++-v3/testsuite/26_numerics/random/piecewise_constant_distribution/cons/default.cc
  14729ec22164b6cdcf385a2d1b90b755  libstdc++-v3/testsuite/26_numerics/random/piecewise_constant_distribution/cons/initlist_fun.cc
  9b0f96efc6c0d7e3986d215840097ef2  libstdc++-v3/testsuite/26_numerics/random/piecewise_constant_distribution/cons/num_xbound_fun.cc
--- 151305,151319 ----
  23f65a251c55843e9da2ee98b63a9e1e  libstdc++-v3/testsuite/26_numerics/random/normal_distribution/operators/serialize.cc
  a1110c1451e4a44827a2e6970c8b7233  libstdc++-v3/testsuite/26_numerics/random/normal_distribution/requirements/explicit_instantiation/1.cc
  d651f18a094c3dfc0e8c45c131f3cb7f  libstdc++-v3/testsuite/26_numerics/random/normal_distribution/requirements/typedefs.cc
! 77afeda865ca994856a85f8fd0744e04  libstdc++-v3/testsuite/26_numerics/random/philox4x32.cc
! 92f89089efad8b3f23591fe1ae7a7995  libstdc++-v3/testsuite/26_numerics/random/philox4x64.cc
! 39e746c95583b73ae0083ac8e10a847b  libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/copy.cc
! c9f93ce5f5c9e82470077e6577ea1ff0  libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/default.cc
! bbc0ac3db492f2094eb97d21360e9970  libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed.cc
! 6fed4d0d5264e18ca91096cef0cb2c50  libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/equal.cc
! aa00adf50c193a2b13b2ebf5aa1f5858  libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/serialize.cc
! a8b98cfabb68398f2afafff0416479c1  libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constants.cc
! cbc4cea209f5ae35db8b0c6b8629a43e  libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/typedefs.cc
  8af781af7df41c657a94ff0828bdaafe  libstdc++-v3/testsuite/26_numerics/random/piecewise_constant_distribution/cons/default.cc
  14729ec22164b6cdcf385a2d1b90b755  libstdc++-v3/testsuite/26_numerics/random/piecewise_constant_distribution/cons/initlist_fun.cc
  9b0f96efc6c0d7e3986d215840097ef2  libstdc++-v3/testsuite/26_numerics/random/piecewise_constant_distribution/cons/num_xbound_fun.cc
*************** f50f08ea0f3c56fb4f3f904226197961  libstd
*** 151184,151190 ****
  d83d81a4149ce8c9ff230914f3cf74c1  libstdc++-v3/testsuite/26_numerics/random/poisson_distribution/operators/values.cc
  737dbd8856530e44be7a70115fa0ce96  libstdc++-v3/testsuite/26_numerics/random/poisson_distribution/requirements/explicit_instantiation/1.cc
  64087aa200aa0ddee5d103b4cb4b77b5  libstdc++-v3/testsuite/26_numerics/random/poisson_distribution/requirements/typedefs.cc
! f5de27e758179ab56b8b4f1bf9f56890  libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc
  1c30a2a995b0786c632ceb76a66a91b0  libstdc++-v3/testsuite/26_numerics/random/random_device/85494.cc
  dd58fca2d95b558ae402a2cbee1158fd  libstdc++-v3/testsuite/26_numerics/random/random_device/94087.cc
  26c74a52d1fac9cc4f712bf483f369d6  libstdc++-v3/testsuite/26_numerics/random/random_device/cons/default-cow.cc
--- 151343,151349 ----
  d83d81a4149ce8c9ff230914f3cf74c1  libstdc++-v3/testsuite/26_numerics/random/poisson_distribution/operators/values.cc
  737dbd8856530e44be7a70115fa0ce96  libstdc++-v3/testsuite/26_numerics/random/poisson_distribution/requirements/explicit_instantiation/1.cc
  64087aa200aa0ddee5d103b4cb4b77b5  libstdc++-v3/testsuite/26_numerics/random/poisson_distribution/requirements/typedefs.cc
! 47f96d5bdb7b4e74b2a11497ee349836  libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc
  1c30a2a995b0786c632ceb76a66a91b0  libstdc++-v3/testsuite/26_numerics/random/random_device/85494.cc
  dd58fca2d95b558ae402a2cbee1158fd  libstdc++-v3/testsuite/26_numerics/random/random_device/94087.cc
  26c74a52d1fac9cc4f712bf483f369d6  libstdc++-v3/testsuite/26_numerics/random/random_device/cons/default-cow.cc
*************** cf67202311bf128140eaf3e3b6bf217b  libstd
*** 151250,151257 ****
  f294d11fe950a7b40373322a491aa1a2  libstdc++-v3/testsuite/26_numerics/random/uniform_int_distribution/requirements/typedefs.cc
  8f4a87663000cf7de408ce4d2cf38b0a  libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/cons/default.cc
  fda6b0912853b2162da8354eccb88ba6  libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/cons/parms.cc
! ad318d48b67e4e1b4b8c49b48fcf87a6  libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/64351.cc
  965db3accbc424e178ff18873d5f5426  libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/equal.cc
  6cb8e3dc1e8ec83b32f8800b5d974425  libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/inequal.cc
  bf6f79fa40e9c446a409a565fa8a5785  libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/serialize.cc
  829ba8e03756696f0180568217ae164f  libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/requirements/explicit_instantiation/1.cc
--- 151409,151418 ----
  f294d11fe950a7b40373322a491aa1a2  libstdc++-v3/testsuite/26_numerics/random/uniform_int_distribution/requirements/typedefs.cc
  8f4a87663000cf7de408ce4d2cf38b0a  libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/cons/default.cc
  fda6b0912853b2162da8354eccb88ba6  libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/cons/parms.cc
! 15d066928877ed24c20dbf5e1bff0126  libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/64351.cc
  965db3accbc424e178ff18873d5f5426  libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/equal.cc
+ 5ba91e2cb224c5b66e31b924c722fd79  libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/gencanon.cc
+ 316869129064e3da75b4d3639c05a9ff  libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/gencanon_eng.cc
  6cb8e3dc1e8ec83b32f8800b5d974425  libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/inequal.cc
  bf6f79fa40e9c446a409a565fa8a5785  libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/serialize.cc
  829ba8e03756696f0180568217ae164f  libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/requirements/explicit_instantiation/1.cc
*************** ae6700b4bf5b034e318443bed6ddfe00  libstd
*** 152764,152769 ****
--- 152925,152931 ----
  19b29f234ce63590ebcc167b26723a58  libstdc++-v3/testsuite/29_atomics/atomic_ref/address.cc
  fd7d907573ccec469e8ce190a6409dce  libstdc++-v3/testsuite/29_atomics/atomic_ref/bool.cc
  32c306fa56643321c7e2c4c7920c2990  libstdc++-v3/testsuite/29_atomics/atomic_ref/compare_exchange_padding.cc
+ 8c8c1dbc7c6d7c022d5e2b7b3c0dca88  libstdc++-v3/testsuite/29_atomics/atomic_ref/ctor.cc
  21da5010562f5cc292d3aee5a3420a1b  libstdc++-v3/testsuite/29_atomics/atomic_ref/cv_qual.cc
  feaeb9209013d212c6ef3d1ee935550c  libstdc++-v3/testsuite/29_atomics/atomic_ref/deduction.cc
  05e9e7877bb6e98c3774e3439911cfd2  libstdc++-v3/testsuite/29_atomics/atomic_ref/float.cc
*************** a6b263685ef489371877099687c56a81  libstd
*** 154120,154126 ****
  0994b0bdd099a3dda63f7e4a254f28e5  libstdc++-v3/testsuite/ext/vstring/types/23767.cc
  d9fe5004af958ef6371080258e741d7a  libstdc++-v3/testsuite/lib/dg-options.exp
  a974a2ccf1152b37304e5b3202056ace  libstdc++-v3/testsuite/lib/gdb-test.exp
! 70e8d46894f3a980e6e36c986d2cf6e0  libstdc++-v3/testsuite/lib/libstdc++.exp
  e5e6573751fab3a5e9e9bad9586da65e  libstdc++-v3/testsuite/lib/prune.exp
  33e43b63e93544d8165fe54e55d40041  libstdc++-v3/testsuite/libstdc++-abi/abi.exp
  c7b1096d1cba1418bd68c171b66a64eb  libstdc++-v3/testsuite/libstdc++-dg/conformance.exp
--- 154282,154288 ----
  0994b0bdd099a3dda63f7e4a254f28e5  libstdc++-v3/testsuite/ext/vstring/types/23767.cc
  d9fe5004af958ef6371080258e741d7a  libstdc++-v3/testsuite/lib/dg-options.exp
  a974a2ccf1152b37304e5b3202056ace  libstdc++-v3/testsuite/lib/gdb-test.exp
! 53bafecff029b9df00b7ad4a8839f1f9  libstdc++-v3/testsuite/lib/libstdc++.exp
  e5e6573751fab3a5e9e9bad9586da65e  libstdc++-v3/testsuite/lib/prune.exp
  33e43b63e93544d8165fe54e55d40041  libstdc++-v3/testsuite/libstdc++-abi/abi.exp
  c7b1096d1cba1418bd68c171b66a64eb  libstdc++-v3/testsuite/libstdc++-dg/conformance.exp
*************** c8926de8f6ede51b5698239a063bcac4  libstd
*** 154602,154608 ****
  075601020e49a49a2f5131b011ff3b25  libstdc++-v3/testsuite/std/time/month_weekday_last/io.cc
  60231b6bb71cc9175500ebf6d9f92ceb  libstdc++-v3/testsuite/std/time/parse/114240.cc
  a0be85b8053be995a48a4cfec6a5b675  libstdc++-v3/testsuite/std/time/parse/114279.cc
! 61fe64fc0ce6aae0635b3572b41566e5  libstdc++-v3/testsuite/std/time/parse/parse.cc
  8e3bf07939ba94874a6652e2a596d549  libstdc++-v3/testsuite/std/time/syn_c++20.cc
  f9d9d1cb483f1731762a8e5787c8020b  libstdc++-v3/testsuite/std/time/time_zone/get_info_local.cc
  d041367e20c424ad627fce102335edd0  libstdc++-v3/testsuite/std/time/time_zone/get_info_sys.cc
--- 154764,154770 ----
  075601020e49a49a2f5131b011ff3b25  libstdc++-v3/testsuite/std/time/month_weekday_last/io.cc
  60231b6bb71cc9175500ebf6d9f92ceb  libstdc++-v3/testsuite/std/time/parse/114240.cc
  a0be85b8053be995a48a4cfec6a5b675  libstdc++-v3/testsuite/std/time/parse/114279.cc
! 5762399d57d6d0d2d2d8cd51ff3f423d  libstdc++-v3/testsuite/std/time/parse/parse.cc
  8e3bf07939ba94874a6652e2a596d549  libstdc++-v3/testsuite/std/time/syn_c++20.cc
  f9d9d1cb483f1731762a8e5787c8020b  libstdc++-v3/testsuite/std/time/time_zone/get_info_local.cc
  d041367e20c424ad627fce102335edd0  libstdc++-v3/testsuite/std/time/time_zone/get_info_sys.cc
*************** dee72a6a60e99528b0d17bf3ff9a1e15  ltopti
*** 155470,155476 ****
  bc2f6032c98896249eadb56177c7d357  ltsugar.m4
  c30cd33c496505f13d9fbdb6970c7c33  ltversion.m4
  293853a13b7e218e3a4342cf85fbbf25  lt~obsolete.m4
! 1a15123b41df67846d98a83aeb63f7e0  maintainer-scripts/ChangeLog
  33c7bc2d2c55956dfac85a05d8a80eff  maintainer-scripts/README
  507e832af5f2d63b8a78eef217c807a7  maintainer-scripts/branch_changer.py
  c819510f0d438149c1518bda7b165ac4  maintainer-scripts/bugzilla-close-candidate.py
--- 155632,155638 ----
  bc2f6032c98896249eadb56177c7d357  ltsugar.m4
  c30cd33c496505f13d9fbdb6970c7c33  ltversion.m4
  293853a13b7e218e3a4342cf85fbbf25  lt~obsolete.m4
! 3df898f35a88409b05244af8bb325230  maintainer-scripts/ChangeLog
  33c7bc2d2c55956dfac85a05d8a80eff  maintainer-scripts/README
  507e832af5f2d63b8a78eef217c807a7  maintainer-scripts/branch_changer.py
  c819510f0d438149c1518bda7b165ac4  maintainer-scripts/bugzilla-close-candidate.py
*************** c67f943b672b0dc1c628ebb0e2df97a3  mainta
*** 155480,155486 ****
  33d97164a8610c7abf67eff7d28f47ff  maintainer-scripts/maintainer-addresses
  1fcc4f18e9f9043eaea6c3c990d96d9b  maintainer-scripts/setup.cfg
  1012437849cecda6e54b3948f279ae93  maintainer-scripts/update_version_git
! fe5245ec8ea53aaa51ffafbaef989713  maintainer-scripts/update_web_docs_git
  f96ea8872725419d57ba3089658c607e  maintainer-scripts/update_web_docs_libstdcxx_git
  5f2a276ee7b8decec541391229d03591  missing
  fbe2467afef81c41c166173adeb0ee20  mkdep
--- 155642,155648 ----
  33d97164a8610c7abf67eff7d28f47ff  maintainer-scripts/maintainer-addresses
  1fcc4f18e9f9043eaea6c3c990d96d9b  maintainer-scripts/setup.cfg
  1012437849cecda6e54b3948f279ae93  maintainer-scripts/update_version_git
! fc6ca4aa2bd66d8a1ca62ac146f634bf  maintainer-scripts/update_web_docs_git
  f96ea8872725419d57ba3089658c607e  maintainer-scripts/update_web_docs_libstdcxx_git
  5f2a276ee7b8decec541391229d03591  missing
  fbe2467afef81c41c166173adeb0ee20  mkdep
diff -Nrcpad gcc-16-20251214/configure gcc-16-20251221/configure
*** gcc-16-20251214/configure	Sun Dec 14 22:32:20 2025
--- gcc-16-20251221/configure	Sun Dec 21 22:32:18 2025
*************** if test -d ${srcdir}/gcc; then
*** 10093,10108 ****
    # 'f95' is the old name for the 'fortran' language. We issue a warning
    # and make the substitution.
    case ,${enable_languages}, in
!     *,f95,*)
        echo configure.ac: warning: 'f95' as language name is deprecated, use 'fortran' instead 1>&2
        enable_languages=`echo "${enable_languages}" | sed -e 's/f95/fortran/g'`
        ;;
    esac
  
    # If bootstrapping, C++ must be enabled.
!   case ",$enable_languages,:$enable_bootstrap" in
!     *,c++,*:*) ;;
!     *:yes)
        if test -f ${srcdir}/gcc/cp/config-lang.in; then
          enable_languages="${enable_languages},c++"
        else
--- 10093,10132 ----
    # 'f95' is the old name for the 'fortran' language. We issue a warning
    # and make the substitution.
    case ,${enable_languages}, in
!     *,f95,* | *,^f95,*)
        echo configure.ac: warning: 'f95' as language name is deprecated, use 'fortran' instead 1>&2
        enable_languages=`echo "${enable_languages}" | sed -e 's/f95/fortran/g'`
        ;;
    esac
  
+   # Extract the language disable requests.  N.B. some non-GNU sed, e.g. on SunOS,
+   # will ignore a line without a trailing newline.
+   disable_languages=`echo "$enable_languages" | tr , "$as_nl" | grep '^\^' | (tr "$as_nl" , ; echo) | sed -e 's/\^//g' -e 's/,$//'`
+   new_enable_languages=
+   for lang in `echo "$enable_languages" | tr , ' '`; do
+     case "${lang}:,${disable_languages}," in
+       ^default:* | ^all:*)
+         as_fn_error $? "only specific individual languages may be disabled, not \"$lang\"" "$LINENO" 5
+         ;;
+       ^lto:*)
+ 	as_fn_error $? "LTO should be disabled with the \"--disable-lto\" argument, not via \"--enable-languages=^lto\"" "$LINENO" 5
+ 	;;
+       ^c:*)
+ 	as_fn_error $? "language \"c\" cannot be disabled" "$LINENO" 5
+ 	;;
+       ^* | ${lang}:*,${lang},*) ;;
+       *) new_enable_languages="${new_enable_languages}${lang}," ;;
+     esac
+   done
+   enable_languages=`echo "$new_enable_languages" | sed -e 's/,$//'`
+ 
    # If bootstrapping, C++ must be enabled.
!   case ",${enable_languages},:${enable_bootstrap}:,${disable_languages}," in
!     *:yes:*,c++,*)
!       as_fn_error $? "c++ cannot be disabled for a bootstrap build" "$LINENO" 5
!       ;;
!     *,c++,*:*:*) ;;
!     *:yes:*)
        if test -f ${srcdir}/gcc/cp/config-lang.in; then
          enable_languages="${enable_languages},c++"
        else
*************** if test -d ${srcdir}/gcc; then
*** 10111,10119 ****
        ;;
    esac
  
!   # First scan to see if an enabled language requires some other language.
!   # We assume that a given config-lang.in will list all the language
!   # front ends it requires, even if some are required indirectly.
    for lang_frag in ${srcdir}/gcc/*/config-lang.in .. ; do
      case ${lang_frag} in
        ..) ;;
--- 10135,10143 ----
        ;;
    esac
  
!   # Collect the list of default languages; keep it prefixed and suffixed with
!   # commas for later convenience.
!   default_languages=,
    for lang_frag in ${srcdir}/gcc/*/config-lang.in .. ; do
      case ${lang_frag} in
        ..) ;;
*************** if test -d ${srcdir}/gcc; then
*** 10121,10148 ****
        # an apparent bug in bash 1.12 on linux.
        ${srcdir}/gcc/[*]/config-lang.in) ;;
        *)
!         # From the config-lang.in, get $language, $lang_requires, and
!         # $lang_requires_boot_languages.
          language=
!         lang_requires=
!         lang_requires_boot_languages=
!         # set srcdir during sourcing lang_frag to the gcc dir.
!         # Sadly overriding srcdir on the . line doesn't work in plain sh as it
!         # pollutes this shell
          saved_srcdir=${srcdir}
          srcdir=${srcdir}/gcc . ${lang_frag}
          srcdir=${saved_srcdir}
!         for other in ${lang_requires} ${lang_requires_boot_languages}; do
!           case ,${enable_languages}, in
! 	    *,$other,*) ;;
! 	    *,default,*) ;;
! 	    *,all,*) ;;
! 	    *,$language,*)
! 	      echo " \`$other' language required by \`$language'; enabling" 1>&2
! 	      enable_languages="${enable_languages},${other}"
  	      ;;
  	  esac
!         done
  	for other in ${lang_requires_boot_languages} ; do
  	  if test "$other" != "c"; then
  	    case ,${enable_stage1_languages}, in
--- 10145,10229 ----
        # an apparent bug in bash 1.12 on linux.
        ${srcdir}/gcc/[*]/config-lang.in) ;;
        *)
!         # From the config-lang.in, get $language and $build_by_default.
          language=
!         build_by_default=yes
!         # See note below about saving srcdir.
          saved_srcdir=${srcdir}
          srcdir=${srcdir}/gcc . ${lang_frag}
          srcdir=${saved_srcdir}
!         if test x"$build_by_default" = xyes; then
!           default_languages="${default_languages}${language},"
!         fi
!         ;;
!     esac
!   done
! 
!   # First scan to see if an enabled language requires some other language.
!   # We assume that a given config-lang.in will list all the language
!   # front ends it requires, even if some are required indirectly.
!   delayed_error_languages=,
!   for lang_frag in ${srcdir}/gcc/*/config-lang.in .. ; do
!     case ${lang_frag} in
!       ..) ;;
!       # The odd quoting in the next line works around
!       # an apparent bug in bash 1.12 on linux.
!       ${srcdir}/gcc/[*]/config-lang.in) ;;
!       *)
! 	# From the config-lang.in, get $language, $lang_requires, and
! 	# $lang_requires_boot_languages.
! 	language=
! 	lang_requires=
! 	lang_requires_boot_languages=
! 	# set srcdir during sourcing lang_frag to the gcc dir.
! 	# Sadly overriding srcdir on the . line doesn't work in plain sh as it
! 	# pollutes this shell
! 	saved_srcdir=${srcdir}
! 	srcdir=${srcdir}/gcc . ${lang_frag}
! 	srcdir=${saved_srcdir}
! 
! 	# Determine if this language was requested; if not, don't bring in its
! 	# dependencies.  To match historical behavior, do bring in the dependencies
! 	# for unsupported languages that were not explicitly disabled.
! 	case ,${disable_languages}, in
! 	  *,${language},*) continue ;;
! 	esac
! 	case ,${enable_languages}, in
! 	  *,${language},* | *,all,*) ;;
! 	  *,default,*)
!             case ${default_languages} in
!               *,${language},*) ;;
!               *) continue ;;
!             esac
!             ;;
! 	  *) continue ;;
! 	esac
! 
! 	# This language was indeed requested; make sure all dependencies are
! 	# also enabled.
! 	for other in ${lang_requires} ${lang_requires_boot_languages}; do
! 	  need_to_add=0
! 	  case ,${enable_languages},:,${disable_languages}, in
!             *:*,${other},*)
! 	      # This language cannot be built because one of its dependencies
! 	      # was explicitly disabled.  Don't complain just yet, though; other
! 	      # checks later may decide the language won't be built anyway.
! 	      delayed_error_languages="${delayed_error_languages}${language}:${other},"
!               ;;
!             *,${other},*:* | *,all,*:*) ;;
!             *,default,*:*)
! 	      case ${default_languages} in
! 		*,${other},*) ;;
! 		*) need_to_add=1 ;;
! 	      esac
  	      ;;
+ 	    *) need_to_add=1 ;;
  	  esac
! 	  if test $need_to_add = 1; then
! 	    echo " \`$other' language required by \`$language'; enabling" 1>&2
! 	    enable_languages="${enable_languages},${other}"
! 	  fi
! 	done
  	for other in ${lang_requires_boot_languages} ; do
  	  if test "$other" != "c"; then
  	    case ,${enable_stage1_languages}, in
*************** if test -d ${srcdir}/gcc; then
*** 10150,10166 ****
  	      *,default,*) ;;
  	      *,all,*) ;;
  	      *)
! 		case ,${enable_languages}, in
! 		  *,$language,*)
! 		    echo " '$other' language required by '$language' in stage 1; enabling" 1>&2
! 		    enable_stage1_languages="$enable_stage1_languages,${other}"
! 		    ;;
! 		esac
  		;;
  	    esac
!           fi
!         done
!         ;;
      esac
    done
  
--- 10231,10243 ----
  	      *,default,*) ;;
  	      *,all,*) ;;
  	      *)
! 		echo " '$other' language required by '$language' in stage 1; enabling" 1>&2
! 		enable_stage1_languages="$enable_stage1_languages,${other}"
  		;;
  	    esac
! 	  fi
! 	done
! 	;;
      esac
    done
  
*************** if test -d ${srcdir}/gcc; then
*** 10199,10211 ****
        ${srcdir}/gcc/[*]/config-lang.in) ;;
        *)
          # From the config-lang.in, get $language, $target_libs,
!         # $lang_dirs, $boot_language, and $build_by_default
          language=
          target_libs=
          lang_dirs=
          subdir_requires=
          boot_language=no
-         build_by_default=yes
          # set srcdir during sourcing.  See above about save & restore
          saved_srcdir=${srcdir}
          srcdir=${srcdir}/gcc . ${lang_frag}
--- 10276,10287 ----
        ${srcdir}/gcc/[*]/config-lang.in) ;;
        *)
          # From the config-lang.in, get $language, $target_libs,
!         # $lang_dirs, and $boot_language.
          language=
          target_libs=
          lang_dirs=
          subdir_requires=
          boot_language=no
          # set srcdir during sourcing.  See above about save & restore
          saved_srcdir=${srcdir}
          srcdir=${srcdir}/gcc . ${lang_frag}
*************** if test -d ${srcdir}/gcc; then
*** 10221,10241 ****
  
          add_this_lang=no
          # C is always enabled, so no need to add it again
!         if test "$language" != "c"; then
!           case ,${enable_languages}, in
!             *,${language},*)
!               # Language was explicitly selected; include it
! 	      add_this_lang=yes
!               ;;
! 	    *,all,*)
! 	      # All languages are enabled
! 	      add_this_lang=all
!               ;;
!             *,default,*)
!               # 'default' was selected, select it if it is a default language
! 	      add_this_lang=${build_by_default}
!               ;;
!           esac
          fi
  
          # Disable languages that need other directories if these aren't available.
--- 10297,10325 ----
  
          add_this_lang=no
          # C is always enabled, so no need to add it again
! 	if test "$language" != "c"; then
! 	    # Determine if this language was requested.
! 	    case ,${disable_languages}, in
! 	      *,${language},* ) ;;
! 	      *)
! 		case ,${enable_languages}, in
! 		  *,${language},*)
! 		    # Language was explicitly selected; include it
! 		    add_this_lang=yes
! 		    ;;
! 		  *,all,*)
! 		    # All languages are enabled, and this one not excluded.
! 		    add_this_lang=all
! 		    ;;
! 		  *,default,*)
! 		    # 'default' was selected, select it if it is a default language
! 		    case ${default_languages} in
! 		      *,${language},*) add_this_lang=yes ;;
! 		    esac
! 		    ;;
! 		esac
! 		;;
! 	    esac
          fi
  
          # Disable languages that need other directories if these aren't available.
*************** $as_echo "$as_me: WARNING: --enable-host
*** 10341,10347 ****
                # Silently disable.
                add_this_lang=unsupported
                ;;
! 	        esac
            ;;
          esac
  
--- 10425,10431 ----
                # Silently disable.
                add_this_lang=unsupported
                ;;
! 	  esac
            ;;
          esac
  
*************** $as_echo "$as_me: WARNING: ${language} n
*** 10400,10405 ****
--- 10484,10494 ----
              potential_languages="${potential_languages}${language},"
  	    ;;
            all|yes)
+ 	    case "$delayed_error_languages" in
+ 	      *,${language}:*,*)
+ 		as_fn_error $? "invalid configuration for language \"${language}\"; at least one of the dependencies \"$delayed_error_languages\" was explicitly disabled" "$LINENO" 5
+ 		;;
+ 	    esac
  	    new_enable_languages="${new_enable_languages}${language},"
              potential_languages="${potential_languages}${language},"
  	    missing_languages=`echo "$missing_languages" | sed "s/,$language,/,/"`
diff -Nrcpad gcc-16-20251214/configure.ac gcc-16-20251221/configure.ac
*** gcc-16-20251214/configure.ac	Sun Dec 14 22:32:05 2025
--- gcc-16-20251221/configure.ac	Sun Dec 21 22:32:05 2025
*************** if test -d ${srcdir}/gcc; then
*** 2255,2270 ****
    # 'f95' is the old name for the 'fortran' language. We issue a warning
    # and make the substitution.
    case ,${enable_languages}, in
!     *,f95,*)
        echo configure.ac: warning: 'f95' as language name is deprecated, use 'fortran' instead 1>&2
        enable_languages=`echo "${enable_languages}" | sed -e 's/f95/fortran/g'`
        ;;
    esac
  
    # If bootstrapping, C++ must be enabled.
!   case ",$enable_languages,:$enable_bootstrap" in
!     *,c++,*:*) ;;
!     *:yes)
        if test -f ${srcdir}/gcc/cp/config-lang.in; then
          enable_languages="${enable_languages},c++"
        else
--- 2255,2294 ----
    # 'f95' is the old name for the 'fortran' language. We issue a warning
    # and make the substitution.
    case ,${enable_languages}, in
!     *,f95,* | *,^f95,*)
        echo configure.ac: warning: 'f95' as language name is deprecated, use 'fortran' instead 1>&2
        enable_languages=`echo "${enable_languages}" | sed -e 's/f95/fortran/g'`
        ;;
    esac
  
+   # Extract the language disable requests.  N.B. some non-GNU sed, e.g. on SunOS,
+   # will ignore a line without a trailing newline.
+   disable_languages=`echo "$enable_languages" | tr , "$as_nl" | grep '^\^' | (tr "$as_nl" , ; echo) | sed -e 's/\^//g' -e 's/,$//'`
+   new_enable_languages=
+   for lang in `echo "$enable_languages" | tr , ' '`; do
+     case "${lang}:,${disable_languages}," in
+       ^default:* | ^all:*)
+         AC_MSG_ERROR([only specific individual languages may be disabled, not "$lang"])
+         ;;
+       ^lto:*)
+ 	AC_MSG_ERROR([LTO should be disabled with the "--disable-lto" argument, not via "--enable-languages=^lto"])
+ 	;;
+       ^c:*)
+ 	AC_MSG_ERROR([language "c" cannot be disabled])
+ 	;;
+       ^* | ${lang}:*,${lang},*) ;;
+       *) new_enable_languages="${new_enable_languages}${lang}," ;;
+     esac
+   done
+   enable_languages=`echo "$new_enable_languages" | sed -e 's/,$//'`
+ 
    # If bootstrapping, C++ must be enabled.
!   case ",${enable_languages},:${enable_bootstrap}:,${disable_languages}," in
!     *:yes:*,c++,*)
!       AC_MSG_ERROR([c++ cannot be disabled for a bootstrap build])
!       ;;
!     *,c++,*:*:*) ;;
!     *:yes:*)
        if test -f ${srcdir}/gcc/cp/config-lang.in; then
          enable_languages="${enable_languages},c++"
        else
*************** if test -d ${srcdir}/gcc; then
*** 2273,2281 ****
        ;;
    esac
  
!   # First scan to see if an enabled language requires some other language.
!   # We assume that a given config-lang.in will list all the language
!   # front ends it requires, even if some are required indirectly.
    for lang_frag in ${srcdir}/gcc/*/config-lang.in .. ; do
      case ${lang_frag} in
        ..) ;;
--- 2297,2305 ----
        ;;
    esac
  
!   # Collect the list of default languages; keep it prefixed and suffixed with
!   # commas for later convenience.
!   default_languages=,
    for lang_frag in ${srcdir}/gcc/*/config-lang.in .. ; do
      case ${lang_frag} in
        ..) ;;
*************** if test -d ${srcdir}/gcc; then
*** 2283,2310 ****
        # an apparent bug in bash 1.12 on linux.
        ${srcdir}/gcc/[[*]]/config-lang.in) ;;
        *)
!         # From the config-lang.in, get $language, $lang_requires, and
!         # $lang_requires_boot_languages.
          language=
!         lang_requires=
!         lang_requires_boot_languages=
!         # set srcdir during sourcing lang_frag to the gcc dir.
!         # Sadly overriding srcdir on the . line doesn't work in plain sh as it
!         # pollutes this shell
          saved_srcdir=${srcdir}
          srcdir=${srcdir}/gcc . ${lang_frag}
          srcdir=${saved_srcdir}
!         for other in ${lang_requires} ${lang_requires_boot_languages}; do
!           case ,${enable_languages}, in
! 	    *,$other,*) ;;
! 	    *,default,*) ;;
! 	    *,all,*) ;;
! 	    *,$language,*)
! 	      echo " \`$other' language required by \`$language'; enabling" 1>&2
! 	      enable_languages="${enable_languages},${other}"
  	      ;;
  	  esac
!         done
  	for other in ${lang_requires_boot_languages} ; do
  	  if test "$other" != "c"; then
  	    case ,${enable_stage1_languages}, in
--- 2307,2391 ----
        # an apparent bug in bash 1.12 on linux.
        ${srcdir}/gcc/[[*]]/config-lang.in) ;;
        *)
!         # From the config-lang.in, get $language and $build_by_default.
          language=
!         build_by_default=yes
!         # See note below about saving srcdir.
          saved_srcdir=${srcdir}
          srcdir=${srcdir}/gcc . ${lang_frag}
          srcdir=${saved_srcdir}
!         if test x"$build_by_default" = xyes; then
!           default_languages="${default_languages}${language},"
!         fi
!         ;;
!     esac
!   done
! 
!   # First scan to see if an enabled language requires some other language.
!   # We assume that a given config-lang.in will list all the language
!   # front ends it requires, even if some are required indirectly.
!   delayed_error_languages=,
!   for lang_frag in ${srcdir}/gcc/*/config-lang.in .. ; do
!     case ${lang_frag} in
!       ..) ;;
!       # The odd quoting in the next line works around
!       # an apparent bug in bash 1.12 on linux.
!       ${srcdir}/gcc/[[*]]/config-lang.in) ;;
!       *)
! 	# From the config-lang.in, get $language, $lang_requires, and
! 	# $lang_requires_boot_languages.
! 	language=
! 	lang_requires=
! 	lang_requires_boot_languages=
! 	# set srcdir during sourcing lang_frag to the gcc dir.
! 	# Sadly overriding srcdir on the . line doesn't work in plain sh as it
! 	# pollutes this shell
! 	saved_srcdir=${srcdir}
! 	srcdir=${srcdir}/gcc . ${lang_frag}
! 	srcdir=${saved_srcdir}
! 
! 	# Determine if this language was requested; if not, don't bring in its
! 	# dependencies.  To match historical behavior, do bring in the dependencies
! 	# for unsupported languages that were not explicitly disabled.
! 	case ,${disable_languages}, in
! 	  *,${language},*) continue ;;
! 	esac
! 	case ,${enable_languages}, in
! 	  *,${language},* | *,all,*) ;;
! 	  *,default,*)
!             case ${default_languages} in
!               *,${language},*) ;;
!               *) continue ;;
!             esac
!             ;;
! 	  *) continue ;;
! 	esac
! 
! 	# This language was indeed requested; make sure all dependencies are
! 	# also enabled.
! 	for other in ${lang_requires} ${lang_requires_boot_languages}; do
! 	  need_to_add=0
! 	  case ,${enable_languages},:,${disable_languages}, in
!             *:*,${other},*)
! 	      # This language cannot be built because one of its dependencies
! 	      # was explicitly disabled.  Don't complain just yet, though; other
! 	      # checks later may decide the language won't be built anyway.
! 	      delayed_error_languages="${delayed_error_languages}${language}:${other},"
!               ;;
!             *,${other},*:* | *,all,*:*) ;;
!             *,default,*:*)
! 	      case ${default_languages} in
! 		*,${other},*) ;;
! 		*) need_to_add=1 ;;
! 	      esac
  	      ;;
+ 	    *) need_to_add=1 ;;
  	  esac
! 	  if test $need_to_add = 1; then
! 	    echo " \`$other' language required by \`$language'; enabling" 1>&2
! 	    enable_languages="${enable_languages},${other}"
! 	  fi
! 	done
  	for other in ${lang_requires_boot_languages} ; do
  	  if test "$other" != "c"; then
  	    case ,${enable_stage1_languages}, in
*************** if test -d ${srcdir}/gcc; then
*** 2312,2328 ****
  	      *,default,*) ;;
  	      *,all,*) ;;
  	      *)
! 		case ,${enable_languages}, in
! 		  *,$language,*)
! 		    echo " '$other' language required by '$language' in stage 1; enabling" 1>&2
! 		    enable_stage1_languages="$enable_stage1_languages,${other}"
! 		    ;;
! 		esac
  		;;
  	    esac
!           fi
!         done
!         ;;
      esac
    done
  
--- 2393,2405 ----
  	      *,default,*) ;;
  	      *,all,*) ;;
  	      *)
! 		echo " '$other' language required by '$language' in stage 1; enabling" 1>&2
! 		enable_stage1_languages="$enable_stage1_languages,${other}"
  		;;
  	    esac
! 	  fi
! 	done
! 	;;
      esac
    done
  
*************** if test -d ${srcdir}/gcc; then
*** 2361,2373 ****
        ${srcdir}/gcc/[[*]]/config-lang.in) ;;
        *)
          # From the config-lang.in, get $language, $target_libs, 
!         # $lang_dirs, $boot_language, and $build_by_default
          language=
          target_libs=
          lang_dirs=
          subdir_requires=
          boot_language=no
-         build_by_default=yes
          # set srcdir during sourcing.  See above about save & restore
          saved_srcdir=${srcdir}
          srcdir=${srcdir}/gcc . ${lang_frag}
--- 2438,2449 ----
        ${srcdir}/gcc/[[*]]/config-lang.in) ;;
        *)
          # From the config-lang.in, get $language, $target_libs, 
!         # $lang_dirs, and $boot_language.
          language=
          target_libs=
          lang_dirs=
          subdir_requires=
          boot_language=no
          # set srcdir during sourcing.  See above about save & restore
          saved_srcdir=${srcdir}
          srcdir=${srcdir}/gcc . ${lang_frag}
*************** if test -d ${srcdir}/gcc; then
*** 2383,2403 ****
  
          add_this_lang=no
          # C is always enabled, so no need to add it again
!         if test "$language" != "c"; then
!           case ,${enable_languages}, in
!             *,${language},*)
!               # Language was explicitly selected; include it
! 	      add_this_lang=yes
!               ;;
! 	    *,all,*)
! 	      # All languages are enabled
! 	      add_this_lang=all
!               ;;
!             *,default,*)
!               # 'default' was selected, select it if it is a default language
! 	      add_this_lang=${build_by_default}
!               ;;
!           esac
          fi
  
          # Disable languages that need other directories if these aren't available.
--- 2459,2487 ----
  
          add_this_lang=no
          # C is always enabled, so no need to add it again
! 	if test "$language" != "c"; then
! 	    # Determine if this language was requested.
! 	    case ,${disable_languages}, in
! 	      *,${language},* ) ;;
! 	      *)
! 		case ,${enable_languages}, in
! 		  *,${language},*)
! 		    # Language was explicitly selected; include it
! 		    add_this_lang=yes
! 		    ;;
! 		  *,all,*)
! 		    # All languages are enabled, and this one not excluded.
! 		    add_this_lang=all
! 		    ;;
! 		  *,default,*)
! 		    # 'default' was selected, select it if it is a default language
! 		    case ${default_languages} in
! 		      *,${language},*) add_this_lang=yes ;;
! 		    esac
! 		    ;;
! 		esac
! 		;;
! 	    esac
          fi
  
          # Disable languages that need other directories if these aren't available.
*************** directories, to avoid imposing the perfo
*** 2498,2504 ****
                # Silently disable.
                add_this_lang=unsupported
                ;;
! 	        esac
            ;;
          esac
  
--- 2582,2588 ----
                # Silently disable.
                add_this_lang=unsupported
                ;;
! 	  esac
            ;;
          esac
  
*************** directories, to avoid imposing the perfo
*** 2554,2559 ****
--- 2638,2648 ----
              potential_languages="${potential_languages}${language},"
  	    ;;
            all|yes)
+ 	    case "$delayed_error_languages" in
+ 	      *,${language}:*,*)
+ 		AC_MSG_ERROR([invalid configuration for language "${language}"; at least one of the dependencies "$delayed_error_languages" was explicitly disabled])
+ 		;;
+ 	    esac
  	    new_enable_languages="${new_enable_languages}${language},"
              potential_languages="${potential_languages}${language},"
  	    missing_languages=`echo "$missing_languages" | sed "s/,$language,/,/"`
diff -Nrcpad gcc-16-20251214/contrib/ChangeLog gcc-16-20251221/contrib/ChangeLog
*** gcc-16-20251214/contrib/ChangeLog	Sun Dec 14 22:32:05 2025
--- gcc-16-20251221/contrib/ChangeLog	Sun Dec 21 22:32:05 2025
***************
*** 1,3 ****
--- 1,8 ----
+ 2025-12-15  Joseph Myers  <josmyers@redhat.com>
+ 
+ 	* test_installed (--enable-plugin, --with-plugincc=)
+ 	(--with-plugincflags=, --with-gmpinc=): New options.
+ 
  2025-12-12  mengqinggang  <mengqinggang@loongson.cn>
  	    Jiajie Chen  <c@jia.je>
  
diff -Nrcpad gcc-16-20251214/contrib/test_installed gcc-16-20251221/contrib/test_installed
*** gcc-16-20251214/contrib/test_installed	Sun Dec 14 22:32:05 2025
--- gcc-16-20251221/contrib/test_installed	Sun Dec 21 22:32:05 2025
*************** while true; do
*** 49,54 ****
--- 49,55 ----
    --srcdir=*) srcdir=`echo "$1" | sed 's/[^=]*=//'`; shift;;
    --target=*) target=`echo "$1" | sed 's/[^=]*=//'`; shift;;
    --prefix=*) prefix=`echo "$1" | sed 's/[^=]*=//'`; shift;;
+   --enable-plugin) ENABLE_PLUGIN=1; shift;;
    --with-gcc=*) GCC_UNDER_TEST=`echo "$1" | sed 's/[^=]*=//'`; shift;;
    --with-g++=*) GXX_UNDER_TEST=`echo "$1" | sed 's/[^=]*=//'`; shift;;
    --with-gfortran=*) GFORTRAN_UNDER_TEST=`echo "$1" | sed 's/[^=]*=//'`; shift;;
*************** while true; do
*** 56,61 ****
--- 57,65 ----
    --with-alt-cxx=*) ALT_CXX_UNDER_TEST=`echo "$1" | sed 's/[^=]*=//'`; shift;;
    --with-compat-options=*) COMPAT_OPTIONS=`echo "$1" | sed 's/[^=]*=//'`; shift;;
    --with-libiconv=*) libiconv=`echo "$1" | sed 's/[^=]*=//'`; shift;;
+   --with-plugincc=*) PLUGINCC=`echo "$1" | sed 's/[^=]*=//'`; shift;;
+   --with-plugincflags=*) PLUGINCFLAGS=`echo "$1" | sed 's/[^=]*=//'`; shift;;
+   --with-gmpinc=*) GMPINC=`echo "$1" | sed 's/[^=]*=//'`; shift;;
    --without-gcc) GCC_UNDER_TEST=no; shift;;
    --without-g++) GXX_UNDER_TEST=no; shift;;
    --without-gfortran) GFORTRAN_UNDER_TEST=no; shift;;
*************** Supported arguments:
*** 80,85 ****
--- 84,90 ----
                                tested if different than the host.
  
  --prefix=/some/dir            use gcc, g++ and gfortran from /some/dir/bin [PATH]
+ --enable-plugin               run GCC plugin tests
  --with-gcc=/some/dir/bin/gcc  use specified gcc program [gcc]
  --with-g++=/some/dir/bin/g++  use specified g++ program [g++]
  --with-gfortran=/some/dir/bin/gfortran  use specified gfortran program [gfortran]
*************** Supported arguments:
*** 87,92 ****
--- 92,100 ----
  --with-alt-cxx=/some/compiler use specified alternative compiler in compat tests
  --with-compat-options=opts    use specified COMPAT_OPTIONS in compat tests
  --with-libiconv=linker-args   use given arguments to link with iconv [-liconv]
+ --with-plugincc=/some/c++     use given host compiler to build plugins [g++]
+ --with-plugincflags=args      use given options to build plugins [-g -O2]
+ --with-gmpinc=args            use given options to find GMP for host []
  --without-gcc                 do not run gcc testsuite
  --without-g++                 do not run g++ testsuite
  --without-gfortran            do not run gfortran testsuite
*************** fi
*** 146,151 ****
--- 154,165 ----
  if test x"$COMPAT_OPTIONS" != x; then
    echo "set COMPAT_OPTIONS \"${COMPAT_OPTIONS}\"" >> site.exp
  fi
+ if test x"$ENABLE_PLUGIN" != x; then
+     echo "set ENABLE_PLUGIN \"${ENABLE_PLUGIN}\"" >> site.exp
+     echo "set PLUGINCC \"${PLUGINCC-g++}\"" >> site.exp
+     echo "set PLUGINCFLAGS \"${PLUGINCFLAGS--g -O2}\"" >> site.exp
+     echo "set GMPINC \"${GMPINC}\"" >> site.exp
+ fi
  
  test x"${GCC_UNDER_TEST}" = x"no" || runtest --tool gcc ${1+"$@"}
  test x"${GXX_UNDER_TEST}" = x"no" || runtest --tool g++ ${1+"$@"}
diff -Nrcpad gcc-16-20251214/gcc/ChangeLog gcc-16-20251221/gcc/ChangeLog
*** gcc-16-20251214/gcc/ChangeLog	Sun Dec 14 22:32:05 2025
--- gcc-16-20251221/gcc/ChangeLog	Sun Dec 21 22:32:05 2025
***************
*** 1,3 ****
--- 1,1117 ----
+ 2025-12-20  Andrew Pinski  <andrew.pinski@oss.qualcomm.com>
+ 
+ 	PR middle-end/123222
+ 	* doc/extend.texi: Fix copy-and-pasto for __builtin_*_overflow_p.
+ 
+ 2025-12-20  Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	PR target/123216
+ 	* common/config/i386/i386-common.cc (OPTION_MASK_ISA_AVX512FP16_UNSET):
+ 	Remove unused macro.
+ 	(OPTION_MASK_ISA2_AVX512FP16_UNSET, OPTION_MASK_ISA2_AVX512BF16_UNSET,
+ 	OPTION_MASK_ISA2_AVX512BW_UNSET): Or in OPTION_MASK_ISA2_AVX10_1_UNSET.
+ 	(OPTION_MASK_ISA2_AVX512CD_UNSET, OPTION_MASK_ISA2_AVX512DQ_UNSET,
+ 	OPTION_MASK_ISA2_AVX512VL_UNSET, OPTION_MASK_ISA2_AVX512IFMA_UNSET,
+ 	OPTION_MASK_ISA2_AVX512VNNI_UNSET,
+ 	OPTION_MASK_ISA2_AVX512VPOPCNTDQ_UNSET,
+ 	OPTION_MASK_ISA2_AVX512VBMI_UNSET, OPTION_MASK_ISA2_AVX512VBMI2_UNSET,
+ 	OPTION_MASK_ISA2_AVX512BITALG_UNSET): Define.
+ 	(ix86_handle_option): For
+ 	-mno-avx512{cd,dq,vl,ifma,vnni,vpopcntdq,vbmi,vbmi2,bitalg} also remove
+ 	corresponding OPTION_MASK_ISA2_AVX512*_UNSET from ix86_isa_flags2
+ 	and add it to ix86_isa_flags2_explicit.
+ 
+ 2025-12-20  Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	PR target/123217
+ 	* config/i386/i386-expand.cc (ix86_expand_builtin)
+ 	<case IX86_BUILTIN_ENCODEKEY128U32, case IX86_BUILTIN_ENCODEKEY256U32,
+ 	case IX86_BUILTIN_URDMSR>: Set target to a new pseudo even if it is
+ 	non-NULL but doesn't satisfy register_operand predicate.
+ 
+ 2025-12-19  Victor Do Nascimento  <victor.donascimento@arm.com>
+ 
+ 	PR tree-optimization/123152
+ 	* tree-vect-loop-manip.cc
+ 	(slpeel_tree_duplicate_loop_to_edge_cfg): Correct order of
+ 	dominator update.
+ 
+ 2025-12-19  Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	* alias.cc (alias_set_subset_of): Fix comment typo, explicitely
+ 	-> explicitly.
+ 	* builtins.cc (get_object_alignment_2): Likewise.
+ 	* combine.cc (make_extraction): Fix comment typos, potentionally
+ 	-> potentially and implicitely -> implicitly.
+ 	(simplify_comparison): Fix comment typo, outmost -> outermost.
+ 	(record_truncated_values): Fix comment typo, truning -> turning.
+ 	(distribute_notes): Fix comment typo, recourse -> recurse.
+ 	* config/avr/avr.md (*<extend_u>maddqihi4_split): Fix comment
+ 	typo, explicitely -> explicitly.
+ 	(*mulu<mode>si3): Likewise.  Fix comment typo, implicitely
+ 	-> implicitly.
+ 	* config/i386/i386.cc (ix86_get_drap_rtx): Fix comment typo,
+ 	statment -> statement.
+ 	* config/rs6000/rs6000.h (TARGET_DIRECT_MOVE_64BIT): Fix comment typo,
+ 	transfered -> transferred.
+ 	* config/s390/s390.cc (s390_encode_section_info): Fix comment typo,
+ 	catched -> caught.
+ 	* dwarf2out.cc (dwarf_proc_stack_usage_map): Fix comment typo,
+ 	invokation -> invocation.
+ 	(dwarf2out_die_ref_for_decl): Fix comment typo, refering -> referring.
+ 	(loc_list_from_tree_1): Fix message typo, INDCREMENT -> INCREMENT.
+ 	(field_byte_offset): Fix comment typo, simplier -> simpler.
+ 	(add_data_member_location_attribute): Fix comment typo, catched
+ 	-> caught.
+ 	(gen_lexical_block_die): Fix comment typo, conrecte -> concrete.
+ 	(analyze_variants_discr): Fix comment typo, consistant -> consistent.
+ 	(gen_decl_die): Fix comment typo, prunning -> pruning.
+ 	(resolve_variable_values): Fix comment typo, refering -> referring.
+ 	* genmatch.cc (expr::expr_type): Fix comment typo, explicitely
+ 	-> explicitly.
+ 	* gimple-range-phi.cc (phi_group::is_modifier_p): Fix comment typo,
+ 	statment -> statement.
+ 	* gimple-ssa-store-merging.cc (pass_optimize_bswap::execute): Fix
+ 	comment typo, invokation -> invocation.  Add second space after dot.
+ 	* gimple-walk.cc (walk_gimple_op): Fix comment typo, explicitely
+ 	-> explicitly.
+ 	* gimplify.cc (mostly_copy_tree_r): Fix comment typo, gimplication
+ 	-> gimplification.
+ 	(var_needs_auto_init_p): Fix comment typo, automaticly
+ 	-> automatically.
+ 	(gimplify_decl_expr): Fix comment typos, varaible -> variable
+ 	and compatiple -> compatible.
+ 	(emit_warn_switch_unreachable): Fix comment typo, statment
+ 	-> statement.
+ 	(should_warn_for_implicit_fallthrough): Fix comment typo, fallthough
+ 	-> fallthrough.
+ 	(modify_call_for_omp_dispatch): Fix comment typo, interobject
+ 	-> interop.
+ 	(oacc_default_clause): Fix comment typo, tranfered -> transferred.
+ 	(omp_notice_variable): Likewise.
+ 	* graphite-isl-ast-to-gimple.cc (binary_op_to_tree): Fix comment
+ 	typo, explicitely -> explicitly.
+ 	* ipa-param-manipulation.cc (push_function_arg_decls): Likewise.
+ 	* ipa-prop.cc (ipa_make_edge_direct_to_target): Likewise.
+ 	* ipa-prop.h (ipa_node_params::node_within_scc): Fix comment typo,
+ 	potentionally -> potentially.
+ 	* loop-init.cc (fix_loop_structure): Fix comment typo, refering
+ 	-> referring.
+ 	* match.pd (1 / X -> X == 1): Fix comment typo, simplier -> simpler.
+ 	* opts.cc (global_options): Fix comment typo, explicitely
+ 	-> explicitly.
+ 	* sanopt.cc (sanopt_optimize_walker): Fix comment typo, potentionally
+ 	-> potentially.
+ 	* tree.cc (variably_modified_type_p): Fix comment typo, refering
+ 	-> referring.
+ 	* tree-cfg.cc (group_case_labels_stmt): Likewise.
+ 	(dump_function_to_file): Fix comment typo, explicitely -> explicitly.
+ 	(make_forwarders_with_degenerate_phis): Likewise.
+ 	* tree-inline.cc (replace_locals_op): Likewise.
+ 	* tree-loop-distribution.cc (loop_distribution::execute): Fix comment
+ 	typo, refering -> referring.
+ 	* tree-sra.cc (generate_subtree_deferred_init): Fix comment typo,
+ 	statment -> statement.
+ 	* tree-ssa-alias.cc (ptrs_compare_unequal): Fix comment typo,
+ 	explicitely -> explicitly.
+ 	* tree-ssa-forwprop.cc (_vec_perm_simplify_seq::stmt): Fix comment
+ 	typo, statment -> statement.
+ 	(narrow_vec_perm_simplify_seq): Fix message typo, statment
+ 	-> statement.
+ 	(blend_vec_perm_simplify_seqs): Likewise.
+ 	* tree-ssa-pre.cc (compute_antic_aux): Fix comment typo, explicitely
+ 	-> explicitly.
+ 	* tree-vect-loop-manip.cc (vect_do_peeling): Fix comment typo,
+ 	refering -> referring.
+ 	* tree-vect-patterns.cc: Fix comment typo, transfered -> transferred.
+ 	* tree-vect-slp.cc (vect_build_slp_tree_2): Fix comment typo,
+ 	explicitely -> explicitly.
+ 	(vect_build_slp_instance): Fix comment typo, transfered
+ 	-> transferred.
+ 	(vect_optimize_slp_pass::build_vertices): Fix comment typo,
+ 	explicitely -> explicitly.
+ 	(vect_slp_analyze_node_operations): Likewise.  Fix comment typo,
+ 	refering -> referring.
+ 	* tree-vect-stmts.cc (vectorizable_store): Fix comment typo, catched
+ 	-> caught.
+ 	* vec.h (auto_vec::auto_vec): Fix comment typo, refering -> referring.
+ 
+ 2025-12-19  Robin Dapp  <rdapp@qti.qualcomm.com>
+ 
+ 	PR target/122970
+ 	* config/riscv/riscv-v.cc (expand_const_vector_interleaved_stepped_npatterns):
+ 	Reinterpret base as smaller type.
+ 
+ 2025-12-19  Robin Dapp  <rdapp@ventanamicro.com>
+ 
+ 	* config/riscv/riscv-v.cc (expand_vector_subreg_extract): New
+ 	function that checks for and performs "vector extracts".
+ 	(legitimize_move): Call new function.
+ 
+ 2025-12-19  Robin Dapp  <rdapp@ventanamicro.com>
+ 
+ 	* config/riscv/autovec.md: Ditto.
+ 	* config/riscv/autovec-opt.md: Add VLS modes.
+ 	* config/riscv/vector-crypto.md: Ditto.
+ 	* config/riscv/vector-iterators.md: Ditto.
+ 	* config/riscv/vector.md (@pred_ffs<VB:mode><P:mode>): Ditto.
+ 	(@pred_ffs<VB_VLS:mode><P:mode>): Ditto.
+ 
+ 2025-12-19  Robin Dapp  <rdapp@ventanamicro.com>
+ 
+ 	* config/riscv/riscv-avlprop.cc (pass_avlprop::execute): Rename.
+ 	* config/riscv/riscv-protos.h (riscv_v_ext_vector_mode_p):
+ 	Rename.
+ 	(riscv_v_ext_tuple_mode_p): Ditto.
+ 	(riscv_v_ext_vls_mode_p): Ditto.
+ 	(riscv_vla_mode_p): To new name.
+ 	(riscv_tuple_mode_p): Ditto.
+ 	(riscv_vls_mode_p): Ditto.
+ 	* config/riscv/riscv-selftests.cc (run_const_vector_selftests):
+ 	Use new name.
+ 	(BROADCAST_TEST): Ditto.
+ 	* config/riscv/riscv-v.cc (imm_avl_p): Ditto.
+ 	(legitimize_move): Ditto.
+ 	(get_vlmul): Ditto.
+ 	(get_vlmax_rtx): Ditto.
+ 	(get_nf): Ditto.
+ 	(get_subpart_mode): Ditto.
+ 	(get_ratio): Ditto.
+ 	(get_mask_mode): Ditto.
+ 	(get_vector_mode): Ditto.
+ 	(get_tuple_mode): Ditto.
+ 	(can_find_related_mode_p): Ditto.
+ 	(cmp_lmul_le_one): Ditto.
+ 	(cmp_lmul_gt_one): Ditto.
+ 	(vls_mode_valid_p): Ditto.
+ 	* config/riscv/riscv-vector-builtins-bases.cc: Ditto.
+ 	* config/riscv/riscv-vector-builtins.cc (rvv_switcher::rvv_switcher): Ditto.
+ 	(register_builtin_type): Ditto.
+ 	* config/riscv/riscv-vector-costs.cc (max_number_of_live_regs):
+ 	Ditto.
+ 	(compute_estimated_lmul): Ditto.
+ 	(costs::costs): Ditto.
+ 	(costs::better_main_loop_than_p): Ditto.
+ 	(costs::adjust_stmt_cost): Ditto.
+ 	* config/riscv/riscv.cc (riscv_v_ext_vector_mode_p): Ditto.
+ 	(riscv_vla_mode_p): Ditto.
+ 	(riscv_v_ext_tuple_mode_p): Ditto.
+ 	(riscv_tuple_mode_p): Ditto.
+ 	(riscv_v_ext_vls_mode_p): Ditto.
+ 	(riscv_vls_mode_p): Ditto.
+ 	(riscv_v_ext_mode_p): Ditto.
+ 	(riscv_vector_mode_p): Ditto.
+ 	(riscv_v_adjust_nunits): Ditto.
+ 	(riscv_v_adjust_bytesize): Ditto.
+ 	(riscv_classify_address): Ditto.
+ 	(riscv_legitimate_address_p): Ditto.
+ 	(riscv_address_insns): Ditto.
+ 	(riscv_const_insns): Ditto.
+ 	(riscv_legitimize_move): Ditto.
+ 	(riscv_binary_cost): Ditto.
+ 	(riscv_rtx_costs): Ditto.
+ 	(riscv_pass_vls_aggregate_in_gpr): Ditto.
+ 	(riscv_get_vector_arg): Ditto.
+ 	(riscv_pass_vls_in_vr): Ditto.
+ 	(riscv_get_arg_info): Ditto.
+ 	(riscv_pass_by_reference): Ditto.
+ 	(riscv_vector_required_min_vlen): Ditto.
+ 	(riscv_get_v_regno_alignment): Ditto.
+ 	(riscv_print_operand): Ditto.
+ 	(riscv_secondary_memory_needed): Ditto.
+ 	(riscv_hard_regno_nregs): Ditto.
+ 	(riscv_hard_regno_mode_ok): Ditto.
+ 	(riscv_modes_tieable_p): Ditto.
+ 	(riscv_can_change_mode_class): Ditto.
+ 	(riscv_vector_mode_supported_p): Ditto.
+ 	(riscv_regmode_natural_size): Ditto.
+ 	(riscv_get_mask_mode): Ditto.
+ 	(riscv_vectorize_preferred_vector_alignment): Ditto.
+ 	(riscv_vectorize_vec_perm_const): Ditto.
+ 	(get_common_costs): Ditto.
+ 	(riscv_preferred_else_value): Ditto.
+ 
+ 2025-12-19  Robin Dapp  <rdapp@ventanamicro.com>
+ 
+ 	* config/riscv/autovec.md (mask_len_gather_load<RATIO64:mode><RATIO64I:mode>):
+ 	Change from this...
+ 	(mask_len_gather_load<mode><vindex>): ...to this.
+ 	(mask_len_gather_load<RATIO32:mode><RATIO32I:mode>): Ditto.
+ 	(mask_len_gather_load<mode><vindex_double_trunc>): Ditto.
+ 	(mask_len_gather_load<RATIO16:mode><RATIO16I:mode>): Ditto.
+ 	(mask_len_gather_load<mode><vindex_quad_trunc>): Ditto.
+ 	(mask_len_gather_load<RATIO8:mode><RATIO8I:mode>): Ditto.
+ 	(mask_len_gather_load<mode><vindex_oct_trunc>): Ditto.
+ 	(mask_len_gather_load<RATIO4:mode><RATIO4I:mode>): Ditto.
+ 	(mask_len_gather_load<mode><vindex_double_ext>): Ditto.
+ 	(mask_len_gather_load<RATIO2:mode><RATIO2I:mode>): Ditto.
+ 	(mask_len_gather_load<mode><vindex_quad_ext>): Ditto.
+ 	(mask_len_gather_load<mode><mode>): Ditto.
+ 	(mask_len_gather_load<mode><vindex_oct_ext>): Ditto.
+ 	(mask_len_scatter_store<RATIO64:mode><RATIO64I:mode>): Ditto.
+ 	(mask_len_scatter_store<mode><vindex>): Ditto.
+ 	(mask_len_scatter_store<RATIO32:mode><RATIO32I:mode>): Ditto.
+ 	(mask_len_scatter_store<mode><vindex_double_trunc>): Ditto.
+ 	(mask_len_scatter_store<RATIO16:mode><RATIO16I:mode>): Ditto.
+ 	(mask_len_scatter_store<mode><vindex_quad_trunc>): Ditto.
+ 	(mask_len_scatter_store<RATIO8:mode><RATIO8I:mode>): Ditto.
+ 	(mask_len_scatter_store<mode><vindex_oct_trunc>): Ditto.
+ 	(mask_len_scatter_store<RATIO4:mode><RATIO4I:mode>): Ditto.
+ 	(mask_len_scatter_store<mode><vindex_double_ext>): Ditto.
+ 	(mask_len_scatter_store<RATIO2:mode><RATIO2I:mode>): Ditto.
+ 	(mask_len_scatter_store<mode><vindex_quad_ext>): Ditto.
+ 	(mask_len_scatter_store<mode><mode>): Ditto.
+ 	(mask_len_scatter_store<mode><vindex_oct_ext>): Ditto.
+ 	* config/riscv/riscv-v.cc (prepare_gather_scatter): Use new
+ 	scheme
+ 	(get_gather_scatter_code): Ditto.
+ 	(expand_gather_scatter): Ditto.
+ 	* config/riscv/riscv-vector-builtins-bases.cc: Ditto.
+ 	* config/riscv/vector-iterators.md: Ditto.
+ 	* config/riscv/vector.md (@pred_indexed_<order>store<RATIO64:mode><RATIO64I:mode>):
+ 	Go from this...
+ 	(@pred_indexed_<order>store<mode>_same_eew): ...to this.
+ 	(@pred_indexed_<order>store<RATIO32:mode><RATIO32I:mode>):
+ 	Ditto.
+ 	(@pred_indexed_<order>store<mode>_x2_greater_eew): Ditto.
+ 	(@pred_indexed_<order>store<RATIO16:mode><RATIO16I:mode>):
+ 	Ditto.
+ 	(@pred_indexed_<order>store<mode>_x4_greater_eew): Ditto.
+ 	(@pred_indexed_<order>store<RATIO8:mode><RATIO8I:mode>): Ditto.
+ 	(@pred_indexed_<order>store<mode>_x8_greater_eew): Ditto.
+ 	(@pred_indexed_<order>store<RATIO4:mode><RATIO4I:mode>): Ditto.
+ 	(@pred_indexed_<order>store<mode>_x2_smaller_eew): Ditto.
+ 	(@pred_indexed_<order>store<RATIO2:mode><RATIO2I:mode>): Ditto.
+ 	(@pred_indexed_<order>store<mode>_x4_smaller_eew): Ditto.
+ 	(@pred_indexed_<order>store<RATIO1:mode><RATIO1:mode>): Ditto.
+ 	(@pred_indexed_<order>store<mode>_x8_smaller_eew): Ditto.
+ 
+ 2025-12-19  Robin Dapp  <rdapp@qti.qualcomm.com>
+ 
+ 	PR tree-optimization/123118
+ 	* tree-vect-data-refs.cc (vect_gather_scatter_fn_p): Check that
+ 	the type sign is equal.
+ 
+ 2025-12-19  Robin Dapp  <rdapp@qti.qualcomm.com>
+ 
+ 	PR tree-optimization/123117
+ 	* tree-ssa-forwprop.cc (simplify_vector_constructor):
+ 	Check if we had a nop conversion and don't use pack/unpack in
+ 	that case.
+ 
+ 2025-12-19  Robin Dapp  <rdapp@qti.qualcomm.com>
+ 
+ 	* doc/md.texi: Use unicode quotation marks.
+ 
+ 2025-12-19  Robin Dapp  <rdapp@ventanamicro.com>
+ 
+ 	* config/riscv/autovec.md (<cbranch_optab><mode>): Implement.
+ 	* config/riscv/predicates.md (riscv_cbranch_comparison_operator):
+ 	Define.
+ 	* config/riscv/vector-iterators.md: New iterators.
+ 
+ 2025-12-19  Robin Dapp  <rdapp@ventanamicro.com>
+ 
+ 	* optabs.cc (emit_cmp_and_jump_insns): Fix len/bias operands.
+ 
+ 2025-12-19  Robin Dapp  <rdapp@ventanamicro.com>
+ 
+ 	PR tree-optimization/123097
+ 	* tree-vect-loop.cc (vect_create_epilog_for_reduction):
+ 	Calculate vector size by number of elements * bit size per
+ 	element.
+ 
+ 2025-12-19  Vladimir N. Makarov  <vmakarov@redhat.com>
+ 
+ 	PR rtl-optimization/123223
+ 	* lra-constraints.cc (match_reload, curr_insn_transform): Check
+ 	rtx on REG when testing scratch pseudos.
+ 
+ 2025-12-19  Jeff Law  <jlaw@ventanamicro.com>
+ 
+ 	* config/h8300/h8300.cc (output_logical_op): Adjust last argument to
+ 	be a pattern, not an insn.  Corresponding implementation changes.
+ 	(output_shift_loop): Extracted from output_a_shift and improved
+ 	to use a sentinel to indicate when to stop the loop.
+ 	(output_a_shift): Use output_shift_loop.
+ 	(compute_a_shift_length): Handle adjusted shift loop code.
+ 	* config/h8300/logical.md (logicals): Pass pattern to output_logical_op
+ 	rather then the full insn.
+ 	* config/h8300/h8300-protos.h (output_logical_op): Update prototype.
+ 
+ 2025-12-19  Andrew MacLeod  <amacleod@redhat.com>
+ 
+ 	PR tree-optimization/123205
+ 	* gimple-range-gori.cc (gori_compute::may_recompute_p): Only
+ 	recompute range-op statements.
+ 	* gimple-range-op.cc (gimple_range_op_handler): Default
+ 	recomputation to true.
+ 	(maybe_builtin_call): CFN_BUILT_IN_CONSTANT_P should not be
+ 	recomputable.
+ 	* gimple-range-op.h (recomputable_p): New.
+ 	(recomputable_p): New.
+ 
+ 2025-12-19  Tobias Burnus  <tburnus@baylibre.com>
+ 
+ 	* tree-pretty-print.cc (dump_omp_clause): For uses_allocators,
+ 	print modifier before allocator variable.
+ 
+ 2025-12-19  Takayuki 'January June' Suwa  <jjsuwa_sys3175@yahoo.co.jp>
+ 
+ 	* config/xtensa/predicates.md (xtensa_cstoresi_operator):
+ 	Change it to include unsigned comparisons only when TARGET_SALT is
+ 	enabled.
+ 
+ 2025-12-19  Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	PR debug/122968
+ 	* dwarf2out.cc (premark_used_variables): Handle "structured bindings"
+ 	attribute.
+ 	(dwarf2out_late_global_decl): Likewise.
+ 
+ 2025-12-19  Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	* doc/install.texi (--with-tls=): Fix a typo, were -> where.
+ 
+ 2025-12-19  Alexandre Oliva  <oliva@gnu.org>
+ 
+ 	PR target/55212
+ 	* lra-constraints.cc (match_reload): Treat former scratch
+ 	regs as implicit unused output reloads.
+ 	(process_alt_operands): Likewise.
+ 	(curr_insn_transform): Likewise.
+ 
+ 2025-12-19  Lewis Hyatt  <lhyatt@gmail.com>
+ 
+ 	PR bootstrap/12407
+ 	* doc/install.texi (--enable-languages): Document the new language
+ 	exclusion feature.
+ 
+ 2025-12-18  Tobias Burnus  <tburnus@baylibre.com>
+ 
+ 	* gimplify.cc (gimplify_scan_omp_clauses): Handle
+ 	OpenMP device_type clause.
+ 	* omp-low.cc (scan_sharing_clauses): Likewise.
+ 	(lower_omp_target): Print 'sorry, unimplemented' for
+ 	device_type clause value other than 'any'.
+ 
+ 2025-12-18  Tejas Belagod  <tejas.belagod@arm.com>
+ 
+ 	* config/aarch64/aarch64-c.cc (aarch64_update_cpp_builtins): Define
+ 	__ARM_FEATURE_SVE_PREDICATE_OPERATORS.
+ 
+ 2025-12-18  Victor Do Nascimento  <victor.donascimento@arm.com>
+ 
+ 	PR tree-optimization/123153
+ 	* tree-vect-loop-manip.cc
+ 	(slpeel_tree_duplicate_loop_to_edge_cfg): use
+ 	profile_probability::even () for even likelihood.
+ 
+ 2025-12-18  Alfie Richards  <alfie.richards@arm.com>
+ 
+ 	* config/aarch64/aarch64-option-extensions.def (sme-lutv2): Fix
+ 	feature string.
+ 
+ 2025-12-18  Alfie Richards  <alfie.richards@arm.com>
+ 
+ 	* config/aarch64/aarch64-arches.def: Add armv9.6-a.
+ 	* config/aarch64/aarch64-option-extensions.def:
+ 	(sve-aes): Update to be enables by smeaes.
+ 	(sve-bitperm): Update to be enables by smesbitperm.
+ 	(fprcvt): New cli extension option.
+ 	(lsfe): Likewise.
+ 	(f8f32mm): Likewise.
+ 	(f8f16mm): Likewise.
+ 	(sme2p2): Likewise.
+ 	(sve2p2): Likewise.
+ 	(sve-aes2): Likewise.
+ 	(sve-f16f32mm): Likewise.
+ 	(sve-bfscale): Likewise.
+ 	(ssve-aes): Likewise.
+ 	(lsui): Likewise.
+ 	(occmo): Likewise.
+ 	(pcdphint): Likewise.
+ 	(pops): Likewise.
+ 	(ssve-bitperm): Likewise.
+ 	(ssve-fexpa): Likewise.
+ 	(sme-mop4): Likewise.
+ 	(sme-tmop): Likewise.
+ 
+ 2025-12-18  Alfie Richards  <alfie.richards@arm.com>
+ 
+ 	* config/aarch64/aarch64-option-extensions.def
+ 	(sve-aes): New cli extension option.
+ 	(sve2-aes): Changed to be alias of sve2+sve-aes2.
+ 	(sve-bitperm): New cli extension option.
+ 	(sve2-bitperm): Changed to be alias of sve2+sve-bitperm.
+ 	(sve-sm4): New cli extension option.
+ 	(sve2-sm4): Changed to be alias of sve2+sve-sm4.
+ 	(sve-sm4): New cli extension option.
+ 	(sve2-sm4): Changed to be alias of sve2+sve-sm4.
+ 	* config/aarch64/aarch64.h (TARGET_SVE2_AES): Updated to require
+ 	sve2+sve-aes.
+ 	(TARGET_SVE2_BITPERM): Updated to require sve2+sve-bitperm.
+ 	(TARGET_SVE2_SHA3): Updated to require sve2+sve-sha3.
+ 	(TARGET_SVE2_SM4): Updated to require sve2+sve-sm4
+ 	* config/aarch64/aarch64-sve-builtins-sve2.def: Update gating for sve2-X
+ 	intrinsics.
+ 
+ 2025-12-18  Alfie Richards  <alfie.richards@arm.com>
+ 
+ 	* common/config/aarch64/aarch64-common.cc
+ 	(struct aarch64_extension_info): Add flags_alias_preferred_over.
+ 	(AARCH64_OPT_EXTENSION): Add setting flags preferred over to 0.
+ 	(AARCH64_OPT_EXTENSION_ALIAS): New macro def.
+ 	(aarch64_get_extension_string_for_isa_flags): Update to use alias
+ 	extensions over constituent extensions.
+ 	* config/aarch64/aarch64-feature-deps.h (alias_flags): New variable
+ 	(AARCH64_OPT_EXTENSION): New macro def.
+ 	(AARCH64_OPT_EXTENSION_ALIAS): New macro def.
+ 	(HANDLE): Update to use alias_flags.
+ 	(AARCH64_CORE): Update to use alias_flags.
+ 	* config/aarch64/aarch64-option-extensions.def
+ 	(AARCH64_OPT_EXTENSION_ALIAS): New macro def to
+ 	define alias_prefer_over_flags_X.
+ 	(crypto): Update to us AARCH64_OPT_EXTENSION_ALIAS.
+ 
+ 2025-12-18  WANG Xuerui  <git@xen0n.name>
+ 
+ 	PR target/123171
+ 	* config/loongarch/loongarch.cc (loongarch_option_restore): Add
+ 	missing update to la_target.isa.base.
+ 
+ 2025-12-18  chenxiaolong  <chenxiaolong@loongson.cn>
+ 
+ 	* config/loongarch/loongarch.cc (loongarch_modes_tieable_p):
+ 	Add support for vector conversion.
+ 
+ 2025-12-18  Senthil Kumar Selvaraj  <saaadhu@gcc.gnu.org>
+ 
+ 	* opts-common.cc (jobserver_info::jobserver_info): Do not skip
+ 	negative file descriptors in simple UNIX pipe mode.
+ 
+ 2025-12-18  Andrew Pinski  <andrew.pinski@oss.qualcomm.com>
+ 
+ 	PR tree-optimization/122734
+ 	* tree-ssa-loop-ch.cc (should_duplicate_loop_header_p): Remove
+ 	check on very_unlikely probability.
+ 
+ 2025-12-18  Andrew Pinski  <andrew.pinski@oss.qualcomm.com>
+ 
+ 	* predict.cc (unlikely_executed_stmt_p): Fix up return for
+ 	__builtin_unreachable/__builtin_trap.
+ 
+ 2025-12-18  Alexandre Oliva  <oliva@adacore.com>
+ 
+ 	* var-tracking.cc (vt_expand_var_loc_chain): Prepare to exit
+ 	the loop after unsuitable_loc.
+ 
+ 2025-12-17  H.J. Lu  <hjl.tools@gmail.com>
+ 
+ 	PR target/122343
+ 	* cselib.cc (cselib_redundant_set_p): Return false for volatile
+ 	memory source or destination.
+ 
+ 2025-12-17  Georg-Johann Lay  <avr@gjlay.de>
+ 
+ 	* config/avr/avr.cc (avr_out_shift_with_cnt): Tweak
+ 	execution time by count-1 cycles in some cases.
+ 
+ 2025-12-17  Georg-Johann Lay  <avr@gjlay.de>
+ 
+ 	* config/avr/avr-protos.h (out_shift_with_cnt): Remove.
+ 	* config/avr/avr.cc (avr_out_shift_with_cnt): New static
+ 	function from out_shift_with_cnt: Pass shift rtx_code instead
+ 	of asm template.
+ 	(avr_out_shift_1): New static helper function.
+ 	(ashlqi3_out, ashlhi3_out, avr_out_ashlpsi3, ashlsi3_out)
+ 	(ashrqi3_out, ashrhi3_out, avr_out_ashrpsi3, ashrsi3_out)
+ 	(lshrqi3_out, lshrhi3_out, avr_out_lshrpsi3, lshrsi3_out):
+ 	Adjust avr_out_shift_with_cnt to new interface.
+ 
+ 2025-12-17  Jeff Law  <jeffrey.law@oss.qualcomm.com>
+ 
+ 	* config/riscv/sync.md (atomic compare and set): Reorder patterns
+ 	so the stricter pattern comes first.
+ 
+ 2025-12-17  Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	PR target/123155
+ 	* config/i386/xmmintrin.h (_mm_maskmove_si64): Rename offset automatic
+ 	variable to __offset.
+ 
+ 2025-12-17  Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	PR target/123155
+ 	* config/i386/avx10_2bf16intrin.h (_mm512_roundscale_pbh,
+ 	_mm512_mask_roundscale_pbh, _mm512_maskz_roundscale_pbh,
+ 	_mm256_roundscale_pbh, _mm256_mask_roundscale_pbh,
+ 	_mm256_maskz_roundscale_pbh, _mm_roundscale_pbh,
+ 	_mm_mask_roundscale_pbh, _mm_maskz_roundscale_pbh,
+ 	_mm512_reduce_pbh, _mm512_mask_reduce_pbh, _mm512_maskz_reduce_pbh,
+ 	_mm256_reduce_pbh, _mm256_mask_reduce_pbh, _mm256_maskz_reduce_pbh,
+ 	_mm_reduce_pbh, _mm_mask_reduce_pbh, _mm_maskz_reduce_pbh): Rename
+ 	B argument to __B.
+ 
+ 2025-12-17  Umesh Kalvakuntla  <umesh.kalvakuntla@amd.com>
+ 
+ 	* common/config/i386/cpuinfo.h (get_amd_cpu): Add znver6 1Ah
+ 	family model numbers.
+ 	(get_available_features): Set feature AVX512BMM.
+ 	* common/config/i386/i386-common.cc (OPTION_MASK_ISA2_AVX512BMM_SET):
+ 	New macro.
+ 	(OPTION_MASK_ISA2_AVX512BMM_UNSET): New macro.
+ 	(OPTION_MASK_ISA2_AVX512BW_UNSET): Unset AVX512BMM.
+ 	(ix86_handle_option): Likewise.
+ 	* common/config/i386/i386-cpuinfo.h (enum processor_subtypes):
+ 	Add AMDFAM1AH_ZNVER6.
+ 	(enum processor_features): Add FEATURE_AVX512BMM.
+ 	* common/config/i386/i386-isas.h: Likewise.
+ 	* config.gcc: Add avx512bmmintrin.h, avx512bmmvlintrin.h,
+ 	znver6.
+ 	* config/i386/cpuid.h (bit_AVX512BMM): New macro.
+ 	* config/i386/driver-i386.cc (host_detect_local_cpu): Likewise.
+ 	* config/i386/i386-builtin.def (BDESC): Add AVX512BMM builtins.
+ 	* config/i386/i386-c.cc (ix86_target_macros_internal): Likewise.
+ 	* config/i386/i386-isa.def (AVX512BMM): Likewise.
+ 	* config/i386/i386-options.cc (m_ZNVER6): New macro.
+ 	(m_ZNVER): Add m_ZNVER6.
+ 	(processor_cost_table): Uses znver5_cost table for
+ 	PROCESSOR_ZNVER6 for now.
+ 	(ix86_valid_target_attribute_inner_p): Likewise.
+ 	* config/i386/i386.cc (ix86_reassociation_width): Likewise.
+ 	* config/i386/i386.h (enum processor_type): Likewise.
+ 	* config/i386/i386.md: Likewise.
+ 	* config/i386/i386.opt: Likewise.
+ 	* config/i386/i386.opt.urls: Likewise.
+ 	* config/i386/immintrin.h: Likewise.
+ 	* config/i386/sse.md (avx512bmm_vbmacor16x16x16_<mode>): New
+ 	define_insn.
+ 	(avx512bmm_vbmacxor16x16x16_<mode>): Likewise.
+ 	(avx512bmm_vbitrevb_<mode>_mask): Likewise.
+ 	(avx512bmm_vbitrevb_<mode>): Likewise.
+ 	* config/i386/x86-tune-sched.cc (ix86_issue_rate): Likewise.
+ 	(ix86_adjust_cost): Likewise.
+ 	* config/i386/x86-tune.def (X86_TUNE_FUSE_ALU_AND_BRANCH): Add
+ 	m_ZNVER6.
+ 	(X86_TUNE_FUSE_MOV_AND_ALU): Likewise.
+ 	(X86_TUNE_USE_SCATTER_2PARTS): Likewise.
+ 	(X86_TUNE_USE_SCATTER_4PARTS): Likewise.
+ 	(X86_TUNE_USE_SCATTER_8PARTS): Likewise.
+ 	(X86_TUNE_AVOID_256FMA_CHAINS): Likewise.
+ 	(X86_TUNE_AVOID_512FMA_CHAINS): Likewise.
+ 	(X86_TUNE_AVX512_MOVE_BY_PIECES): Likewise.
+ 	* doc/extend.texi: Likewise.
+ 	* doc/invoke.texi: Likewise.
+ 	* config/i386/avx512bmmintrin.h: New file.
+ 	* config/i386/avx512bmmvlintrin.h: New file.
+ 
+ 2025-12-16  Iain Sandoe  <iain@sandoe.co.uk>
+ 
+ 	* config/aarch64/aarch64.cc
+ 	(aarch64_function_abi): Use checking assert.
+ 	(aarch64_fndecl_abi): Test for the availability of the
+ 	machine content before trying to look up the cached PCS.
+ 	Use a checking assert.
+ 
+ 2025-12-16  Jose E. Marchesi  <jose.marchesi@oracle.com>
+ 
+ 	* common.opt.urls: Regenerate.
+ 
+ 2025-12-16  Takayuki 'January June' Suwa  <jjsuwa_sys3175@yahoo.co.jp>
+ 
+ 	* config/xtensa/xtensa.cc (xtensa_expand_scc_SALT):
+ 	New sub-function that emits the SALT/SALTU instructions.
+ 	(xtensa_expand_scc): Change the part related to the SALT/SALTU
+ 	instructions to a call to the above sub-function.
+ 
+ 2025-12-16  Takayuki 'January June' Suwa  <jjsuwa_sys3175@yahoo.co.jp>
+ 
+ 	* config/xtensa/xtensa.cc
+ 	(xtensa_expand_block_set_libcall,
+ 	xtensa_expand_block_set_unrolled_loop,
+ 	xtensa_expand_block_set_small_loop, xtensa_call_tls_desc):
+ 	Change the return statement to pass the return value of
+ 	end_sequence() directly without going through a variable, and
+ 	remove the definition of that variable.
+ 
+ 2025-12-16  Claudiu Zissulescu  <claudiu.zissulescu-ianculescu@oracle.com>
+ 	    Indu Bhagat  <indu.bhagat@oracle.com>
+ 
+ 	* config/aarch64/aarch64.md (addg): Update pattern to use
+ 	addg/subg instructions.
+ 	(stg): Update pattern.
+ 	(st2g): New pattern.
+ 	(tag_memory): Likewise.
+ 	(compose_tag): Likewise.
+ 	(irq): Update pattern to accept xzr register.
+ 	(gmi): Likewise.
+ 	(UNSPECV_TAG_SPACE): Define.
+ 	* config/aarch64/aarch64.cc (AARCH64_MEMTAG_GRANULE_SIZE):
+ 	Define.
+ 	(AARCH64_MEMTAG_TAG_BITSIZE): Likewise.
+ 	(aarch64_override_options_internal): Error out if MTE instructions
+ 	are not available.
+ 	(aarch64_post_cfi_startproc): Emit .cfi_mte_tagged_frame.
+ 	(aarch64_can_tag_addresses): Add MEMTAG specific handling.
+ 	(aarch64_memtag_tag_bitsize): New function
+ 	(aarch64_memtag_granule_size): Likewise.
+ 	(aarch64_memtag_insert_random_tag): Likwise.
+ 	(aarch64_memtag_add_tag): Likewise.
+ 	(aarch64_memtag_extract_tag): Likewise.
+ 	(aarch64_granule16_memory_address_p): Likewise.
+ 	(aarch64_emit_stxg_insn): Likewise.
+ 	(aarch64_memtag_tag_memory_via_loop): New definition.
+ 	(aarch64_expand_tag_memory): Likewise.
+ 	(aarch64_check_memtag_ops): Likewise.
+ 	(TARGET_MEMTAG_TAG_BITSIZE): Likewise.
+ 	(TARGET_MEMTAG_GRANULE_SIZE): Likewise.
+ 	(TARGET_MEMTAG_INSERT_RANDOM_TAG): Likewise.
+ 	(TARGET_MEMTAG_ADD_TAG): Likewise.
+ 	(TARGET_MEMTAG_EXTRACT_TAG): Likewise.
+ 	* config/aarch64/aarch64-builtins.cc
+ 	(aarch64_expand_builtin_memtag): Update set tag builtin logic.
+ 	* config/aarch64/aarch64-linux.h: Pass memtag-stack sanitizer
+ 	specific options to the linker.
+ 	* config/aarch64/aarch64-protos.h
+ 	(aarch64_granule16_memory_address_p): New prototype.
+ 	(aarch64_check_memtag_ops): Likewise.
+ 	(aarch64_expand_tag_memory): Likewise.
+ 	* config/aarch64/constraints.md (Umg): New memory constraint.
+ 	(Uag): New constraint.
+ 	(Ung): Likewise.
+ 	* config/aarch64/predicates.md (aarch64_memtag_tag_offset):
+ 	Refactor it.
+ 	(aarch64_granule16_imm6): Rename from aarch64_granule16_uimm6 and
+ 	refactor it.
+ 	(aarch64_granule16_memory_operand): New constraint.
+ 	* config/aarch64/iterators.md (MTE_PP): New code iterator to be
+ 	used for mte instructions.
+ 	(stg_ops): New code attributes.
+ 	(st2g_ops): Likewise.
+ 	(mte_name): Likewise.
+ 	* config/aarch64/aarch64.opt (aarch64-tag-memory-loop-threshold):
+ 	New parameter.
+ 	* doc/invoke.texi: Update documentation.
+ 
+ 2025-12-16  Claudiu Zissulescu  <claudiu.zissulescu-ianculescu@oracle.com>
+ 	    Indu Bhagat  <indu.bhagat@oracle.com>
+ 
+ 	* asan.cc (handle_builtin_stack_restore): Accommodate MEMTAG
+ 	sanitizer.
+ 	(handle_builtin_alloca): Expand differently if MEMTAG sanitizer.
+ 	(get_mem_refs_of_builtin_call): Include MEMTAG along with
+ 	HWASAN.
+ 	(memtag_sanitize_stack_p): New definition.
+ 	(memtag_sanitize_allocas_p): Likewise.
+ 	(memtag_memintrin): Likewise.
+ 	(hwassist_sanitize_p): Likewise.
+ 	(hwassist_sanitize_stack_p): Likewise.
+ 	(report_error_func): Include MEMTAG along with HWASAN.
+ 	(build_check_stmt): Likewise.
+ 	(instrument_derefs): MEMTAG too does not deal with globals yet.
+ 	(instrument_builtin_call): Include MEMTAG along with HWASAN.
+ 	(maybe_instrument_call): Likewise.
+ 	(asan_expand_mark_ifn): Likewise.
+ 	(asan_expand_check_ifn): Likewise.
+ 	(asan_expand_poison_ifn): Expand differently if MEMTAG sanitizer.
+ 	(asan_instrument): Include MEMTAG along with HWASAN.
+ 	(hwasan_emit_prologue): Expand differently if MEMTAG sanitizer.
+ 	(hwasan_emit_untag_frame): Likewise.
+ 	* asan.h (memtag_sanitize_stack_p): New declaration.
+ 	(memtag_sanitize_allocas_p): Likewise.
+ 	(hwassist_sanitize_p): Likewise.
+ 	(hwassist_sanitize_stack_p): Likewise.
+ 	(asan_sanitize_use_after_scope): Include MEMTAG along with
+ 	HWASAN.
+ 	* cfgexpand.cc (align_local_variable): Likewise.
+ 	(expand_one_stack_var_at): Likewise.
+ 	(expand_stack_vars): Likewise.
+ 	(expand_one_stack_var_1): Likewise.
+ 	(init_vars_expansion): Likewise.
+ 	(expand_used_vars): Likewise.
+ 	(pass_expand::execute): Likewise.
+ 	* gimplify.cc (asan_poison_variable): Likewise.
+ 	* internal-fn.cc (expand_HWASAN_ALLOCA_POISON): New definition.
+ 	(expand_HWASAN_ALLOCA_UNPOISON): Expand differently if MEMTAG
+ 	sanitizer.
+ 	(expand_HWASAN_MARK): Likewise.
+ 	* internal-fn.def (HWASAN_ALLOCA_POISON): Define new.
+ 	* params.opt: Document new param.
+ 	* sanopt.cc (pass_sanopt::execute): Include MEMTAG along with
+ 	HWASAN.
+ 	* gcc.cc (sanitize_spec_function): Add check for memtag-stack.
+ 	* doc/tm.texi: Regenerate.
+ 	* target.def (extract_tag): Update documentation.
+ 	(add_tag): Likewise.
+ 	(insert_random_tag): Likewise.
+ 
+ 2025-12-16  Indu Bhagat  <indu.bhagat@oracle.com>
+ 	    Claudiu Zissulescu  <claudiu.zissulescu-ianculescu@oracle.com>
+ 
+ 	* builtins.def: Adjust the macro to include the new
+ 	SANTIZIE_MEMTAG_STACK.
+ 	* flag-types.h (enum sanitize_code): Add new enumerator for
+ 	SANITIZE_MEMTAG and SANITIZE_MEMTAG_STACK.
+ 	* opts.cc (finish_options): memtag-stack sanitizer conflicts with
+ 	hwaddress and address sanitizers.
+ 	(sanitizer_opts): Add new memtag-stack sanitizer.
+ 	(parse_sanitizer_options): memtag-stack sanitizer cannot recover.
+ 	* params.opt: Add new params for memtag-stack sanitizer.
+ 	* doc/invoke.texi: Update documentation.
+ 
+ 2025-12-16  Claudiu Zissulescu  <claudiu.zissulescu-ianculescu@oracle.com>
+ 
+ 	* target-insns.def (compose_tag): New target instruction.
+ 	* doc/md.texi (compose_tag): Add documentation.
+ 
+ 2025-12-16  Claudiu Zissulescu  <claudiu.zissulescu-ianculescu@oracle.com>
+ 
+ 	* target-insns.def (tag_memory): New target instruction.
+ 	* doc/md.texi (tag_memory): Add documentation.
+ 
+ 2025-12-16  Jennifer Schmitz  <jschmitz@nvidia.com>
+ 
+ 	* config/aarch64/aarch64.md: Include olympus.md.
+ 	* config/aarch64/olympus.md: New file.
+ 	* config/aarch64/tuning_models/olympus.h: Add dispatch
+ 	constraints and enable dispatch scheduling.
+ 
+ 2025-12-16  Maxim Kuvyrkov  <maxim.kuvyrkov@linaro.org>
+ 
+ 	* haifa-sched.cc (choose_ready): Don't require dfa_lookahead <= 0
+ 	to schedule SCHED_GROUP_P insns first.
+ 
+ 2025-12-16  Richard Biener  <rguenther@suse.de>
+ 
+ 	PR ipa/122456
+ 	* cgraph.cc (cgraph_edge::resolve_speculation): Handle
+ 	a NULL symtab_node::get (callee_decl).
+ 
+ 2025-12-16  Andrew Pinski  <andrew.pinski@oss.qualcomm.com>
+ 
+ 	PR tree-optimization/123110
+ 	* tree-cfgcleanup.cc (maybe_remove_forwarder_block): Add back
+ 	check for eh landing pad or non-local dest on the dest.
+ 
+ 2025-12-16  Andrew Pinski  <andrew.pinski@oss.qualcomm.com>
+ 
+ 	PR tree-optimization/123111
+ 	* tree-cfg.cc (ifconvertable_edge): New function.
+ 	(make_forwarders_with_degenerate_phis):	Add skip_ifcvtable argument,
+ 	check ifconvertable_edge if skip_ifcvtable is true.
+ 	* tree-cfg.h (make_forwarders_with_degenerate_phis): New argument
+ 	with default of false.
+ 	* tree-cfgcleanup.cc (execute_cleanup_cfg_post_optimizing): Update
+ 	argument to make_forwarders_with_degenerate_phis.
+ 
+ 2025-12-15  Martin Jambor  <mjambor@suse.cz>
+ 
+ 	PR ipa/107666
+ 	* common.opt (fspeculatively-call-stored-functions): New.
+ 	* cgraph.h (cgraph_simple_indirect_info): New fields rec_type and
+ 	fld_offset.
+ 	* ipa-prop.h (ipa_analyze_var_static_initializer): Declare.
+ 	(ipa_dump_noted_record_fnptrs): Likewise.
+ 	(ipa_debug_noted_record_fnptrs): Likewise.
+ 	(ipa_single_noted_fnptr_in_record): Likewise.
+ 	(ipa_free_noted_fnptr_calls): Likewise.
+ 	* ipa-cp.cc (ipcp_generate_summary): Call
+ 	ipa_analyze_var_static_initializer on each varbool node with a static
+ 	initializer.
+ 	* ipa-devirt.cc (struct devirt_stats): New type.
+ 	(devirt_target_ok_p): New function.
+ 	(ipa_devirt): Move statistics counters to the new structure.  dump
+ 	noted function pointers stored in records.  Check for edge hotness
+ 	first and for odr_types only for polymorphic edges.  Moved a number of
+ 	checks to devirt_target_ok_p.  Also add speculative direct calls for
+ 	non-polymorphic indirect ones when ipa_single_noted_fnptr_in_record
+ 	finds a likely target.  Call ipa_free_noted_fnptr_calls.
+ 	(pass_ipa_devirt::gate): Also check the new flag.
+ 	* ipa-prop.cc (noted_fnptr_store): New type.
+ 	(struct noted_fnptr_hasher): Likewise.
+ 	(noted_fnptr_hasher::hash): New function.
+ 	(noted_fnptr_hasher::equal): Likewise.
+ 	(noted_fnptrs_in_records): New.
+ 	(is_func_ptr_from_record): New function.
+ 	(ipa_analyze_indirect_call_uses): Also simple create indirect info
+ 	structures with fnptr_loaded_from_record set.
+ 	(note_fnptr_in_record): New function.
+ 	(ipa_dump_noted_record_fnptrs): Likewise.
+ 	(ipa_debug_noted_record_fnptrs): Likewise.
+ 	(ipa_single_noted_fnptr_in_record): Likewise.
+ 	(ipa_free_noted_fnptr_calls): Likewise.
+ 	(ipa_analyze_stmt_uses): Also look for stroes of function pointers to
+ 	record structures.
+ 	(ipa_analyze_var_static_initializer): New function.
+ 	(ipa_write_indirect_edge_info): Also stream fnptr_loaded_from_record
+ 	indirec infos.
+ 	(ipa_read_indirect_edge_info): Likewise.
+ 	(ipa_prop_write_jump_functions): Also stream the contents of
+ 	noted_fnptrs_in_records.
+ 	(ipa_prop_read_section): Likewise.
+ 	* opts.cc (default_options_table): Also turn on
+ 	OPT_fspeculatively_call_stored_functions at -O2.
+ 	(common_handle_option): Turn flag_speculatively_call_stored_functions
+ 	when using profile feedback.
+ 	* doc/invoke.texi (-fspeculatively-call-stored-functions): New.
+ 
+ 2025-12-15  Martin Jambor  <mjambor@suse.cz>
+ 
+ 	* cgraph.h (cgraph_node): Adjust the comment of member function
+ 	create_indirect_edge.
+ 	(enum cgraph_indirect_info_kind): New.
+ 	(cgraph_indirect_call_info): Convert into a base class.
+ 	(cgraph_simple_indirect_info): New.
+ 	(cgraph_polymorphic_indirect_info): Likewise.
+ 	(usable_polymorphic_info_p): Likewise.
+ 	(is_a_helper <cgraph_simple_indirect_info *>::test): Likewise.
+ 	(is_a_helper <cgraph_polymorphic_indirect_info *>::test): Likewise.
+ 	(cgraph_allocate_init_indirect_info): Remove declaration.
+ 	(ipa_polymorphic_call_context::ipa_polymorphic_call_context): Use the
+ 	appropriate derived type of indirect info.
+ 	* cgraph.cc (cgraph_allocate_init_indirect_info): Removed.
+ 	(cgraph_node::create_indirect_edge): Create an appropriate type of
+ 	indirect_info.
+ 	(cgraph_node::dump): Dump indirect info using its dump function.
+ 	(cgraph_indirect_call_info::dump): New function.
+ 	(cgraph_indirect_call_info::debug): Likewise.
+ 	* cgraphclones.cc (cgraph_edge::clone): Create an appropriate type of
+ 	indirect_info.
+ 	* cgraphunit.cc (analyze_functions): Use the appropriate derived type
+ 	of indirect info.
+ 	* ipa-cp.cc (initialize_node_lattices): Adjust the check for
+ 	polymorphic indirect info.
+ 	(ipa_get_indirect_edge_target_1): Use the appropriate derived types of
+ 	indirect info.
+ 	(ipcp_discover_new_direct_edges): Likewise.
+ 	* ipa-devirt.cc (ipa_devirt): Use the polymorphis derived type of
+ 	indirect info and check that it is usable.
+ 	* ipa-inline.cc (dump_inline_stats): Adjust the check for polymorphic
+ 	indirect info.
+ 	* ipa-profile.cc (ipa_profile): Likewise and check usability.
+ 	* ipa-prop.cc (ipa_print_node_jump_functions): Dump indirect info
+ 	using its dumping member function.
+ 	(ipa_note_param_call): Removed.
+ 	(ipa_analyze_indirect_call_uses): Use the appropriate derived type of
+ 	indirect info, set all fields of indirect info separately rather than
+ 	relying on ipa_note_param_call.
+ 	(ipa_analyze_virtual_call_uses): Use the polymorphis derived type of
+ 	indirect info and check that it is usable, set all fields of indirect
+ 	info separately rather than relying on ipa_note_param_call.
+ 	(ipa_analyze_call_uses): Use the appropriate derived type of indirect
+ 	info.
+ 	(ipa_make_edge_direct_to_target): Use the appropriate derived type of
+ 	indirect info.  Remove wrong note that member_ptr check was not
+ 	needed.  Adjust check for polymorphic call when dumping.
+ 	(try_make_edge_direct_simple_call): Use the appropriate derived type
+ 	of indirect info.
+ 	(try_make_edge_direct_virtual_call): Use the polymorphis derived type
+ 	of indirect info and check that it is usable.
+ 	(update_indirect_edges_after_inlining): Use the appropriate derived
+ 	type of indirect info.  Define local variables only before their first
+ 	use.
+ 	(ipa_write_indirect_edge_info): Also stream indirect info kind.  Use
+ 	the appropriate derived type of indirect info.
+ 	(ipa_read_indirect_edge_info): Check that the streamed in indirect
+ 	info kind matches rthe structure at hand.  Use the appropriate derived
+ 	type of indirect info.
+ 	* ipa-utils.h (possible_polymorphic_call_targets): Use the
+ 	polymorphis derived type of indirect info.  Assert it is usable.
+ 	(dump_possible_polymorphic_call_targets): Use the polymorphis
+ 	derived type of indirect info and check it is usable.
+ 	(possible_polymorphic_call_target_p): Likewise.
+ 	* ipa.cc (symbol_table::remove_unreachable_nodes): Use
+ 	usable_polymorphic_info_p.
+ 	* lto-cgraph.cc (lto_output_edge): Stream indirect info kind.
+ 	(compute_ltrans_boundary): Use usable_polymorphic_info_p.
+ 	(input_edge): Move definition of ecf_flags before its first use.
+ 	Pass true as the last parameter to create_indirect_edge.  Stream
+ 	indirect info kind and create a corresponding type to hold the
+ 	information.
+ 	* trans-mem.cc (ipa_tm_insert_gettmclone_call): Use the
+ 	polymorphis derived type of indirect info.
+ 
+ 2025-12-15  Martin Jambor  <mjambor@suse.cz>
+ 
+ 	* gengtype.cc (walk_subclasses): Avoid generating code with unused
+ 	variables.
+ 
+ 2025-12-15  Pengxuan Zheng  <pengxuan.zheng@oss.qualcomm.com>
+ 
+ 	PR tree-optimization/122987
+ 	* tree-ssa-ifcombine.cc (ifcombine_ifandif): Replace
+ 	force_gimple_operand_gsi with gimple_build.
+ 
+ 2025-12-15  Joseph Myers  <josmyers@redhat.com>
+ 
+ 	* Makefile.in (PLUGIN_HEADERS): Add $(srcdir)/text-art/*.h.
+ 	(install-plugin): Preserve directory structure for text-art
+ 	headers.
+ 
+ 2025-12-15  Alfie Richards  <alfie.richards@arm.com>
+ 
+ 	* config/aarch64/aarch64-cores.def (cortex-a320): New core.
+ 	* config/aarch64/aarch64-tune.md: Regenerate.
+ 
+ 2025-12-15  Victor Do Nascimento  <victor.donascimento@arm.com>
+ 
+ 	* tree-vect-loop.cc (vect_analyze_loop_form): Relax niters
+ 	condition.
+ 
+ 2025-12-15  Victor Do Nascimento  <victor.donascimento@arm.com>
+ 
+ 	* tree-vect-data-refs.cc (vect_enhance_data_refs_alignment):
+ 	Enable peeling for uncounted loops.
+ 	* tree-vect-loop-manip.cc
+ 	(slpeel_tree_duplicate_loop_to_edge_cfg): Add exit condition
+ 	duplication functionality.
+ 	* tree-vectorizer.h (slpeel_tree_duplicate_loop_to_edge_cfg):
+ 	Modify function signature.
+ 	(vect_do_peeling): Enable uncounted loop peeling.
+ 
+ 2025-12-15  Victor Do Nascimento  <victor.donascimento@arm.com>
+ 
+ 	* tree-vect-data-refs.cc (vect_prune_runtime_alias_test_list):
+ 	Reject when !operand_equal_p for any data ref pair.
+ 
+ 2025-12-15  Victor Do Nascimento  <victor.donascimento@arm.com>
+ 
+ 	* tree-vect-loop.cc (vect_analyze_loop_2): Disable partial
+ 	vector use for uncounted loops.
+ 
+ 2025-12-15  Victor Do Nascimento  <victor.donascimento@arm.com>
+ 
+ 	* tree-vect-loop-manip.cc (slpeel_tree_duplicate_loop_to_edge_cfg):
+ 	reset IVs and accumulators for all exits for uncounted loops.
+ 	* tree-vectorizer.h (slpeel_tree_duplicate_loop_to_edge_cfg):
+ 	add boolean `uncounted_p' argument.
+ 
+ 2025-12-15  Victor Do Nascimento  <victor.donascimento@arm.com>
+ 
+ 	* tree-vect-loop-manip.cc (vect_do_peeling): Disable vector
+ 	loop skip checking.
+ 	(vect_loop_versioning): skip profitability check for uncounted loops.
+ 
+ 2025-12-15  Victor Do Nascimento  <victor.donascimento@arm.com>
+ 
+ 	* tree-vect-loop-manip.cc (vect_do_peeling): Disable niters
+ 	update.
+ 	* tree-vect-loop.cc (vect_transform_loop): Likewise.
+ 
+ 2025-12-15  Victor Do Nascimento  <victor.donascimento@arm.com>
+ 
+ 	* tree-vectorizer.h (LOOP_VINFO_IV_EXIT): Replace this...
+ 	(LOOP_VINFO_MAIN_EXIT): ...with this.
+ 	(LOOP_VINFO_EPILOGUE_IV_EXIT): Replace this...
+ 	(LOOP_VINFO_EPILOGUE_MAIN_EXIT): ...with this.
+ 	(LOOP_VINFO_SCALAR_IV_EXIT): Replace this...
+ 	(LOOP_VINFO_SCALAR_MAIN_EXIT): ...with this.
+ 	(class _loop_vec_info): s/iv/main for `vec_loop_iv_exit',
+ 	`vec_epilogue_loop_main_exit' and `scalar_loop_main_exit'
+ 	class members.
+ 	* tree-vect-data-refs.cc
+ 	(vect_enhance_data_refs_alignment):
+ 	s/LOOP_VINFO_IV_EXIT/LOOP_VINFO_MAIN_EXIT/.
+ 	* tree-vect-loop-manip.cc
+ 	(vect_set_loop_controls_directly): Likewise.
+ 	(vect_gen_vector_loop_niters_mult_vf): Likewise.
+ 	(vect_loop_versioning): Likewise.
+ 	(vect_do_peeling):
+ 	s/LOOP_VINFO_IV_EXIT/LOOP_VINFO_MAIN_EXIT/,
+ 	s/LOOP_VINFO_SCALAR_IV_EXIT/LOOP_VINFO_SCALAR_MAIN_EXIT,
+ 	s/LOOP_VINFO_EPILOGUE_IV_EXIT/LOOP_VINFO_EPILOGUE_MAIN_EXIT.
+ 	* tree-vect-loop.cc (_loop_vec_info::_loop_vec_info):
+ 	s/iv_exit/main_exit/ in initializer list.
+ 	(vec_init_loop_exit_info): Handle multiple-exit uncounted loops.
+ 	(vect_analyze_loop_form): Fix `failure_at' message.
+ 	(vect_create_loop_vinfo):
+ 	s/LOOP_VINFO_IV_EXIT/LOOP_VINFO_MAIN_EXIT/.
+ 	(vect_create_epilog_for_reduction): Likewise.
+ 	(vectorizable_live_operation): Likewise.
+ 	(vect_update_ivs_after_vectorizer_for_early_breaks): Likewise.
+ 	(vect_transform_loop):
+ 	s/LOOP_VINFO_IV_EXIT/LOOP_VINFO_MAIN_EXIT/,
+ 	s/LOOP_VINFO_SCALAR_IV_EXIT/LOOP_VINFO_SCALAR_MAIN_EXIT.
+ 	* tree-vectorizer.cc (set_uid_loop_bbs):
+ 	s/LOOP_VINFO_SCALAR_IV_EXIT/LOOP_VINFO_SCALAR_MAIN_EXIT.
+ 
+ 2025-12-15  Victor Do Nascimento  <victor.donascimento@arm.com>
+ 
+ 	* tree-vectorizer.h (LOOP_VINFO_EARLY_BREAKS_VECT_PEELED): OR
+ 	its current definition with `LOOP_VINFO_NITERS_UNCOUNTED_P(L)'
+ 	* tree-vect-loop.cc (vect_create_loop_vinfo): Don't populate
+ 	`LOOP_VINFO_LOOP_IV_COND' for uncounted loops.
+ 
+ 2025-12-15  Victor Do Nascimento  <victor.donascimento@arm.com>
+ 
+ 	* tree-vect-loop-manip.cc (vect_build_loop_niters): Gracefully
+ 	handle uncounted loops.
+ 	(vect_gen_prolog_loop_niters): Add type default of `sizetype'.
+ 	(vect_gen_vector_loop_niters): Likewise.
+ 	(vect_do_peeling): Likewise.
+ 	* tree-vect-loop.cc (vect_min_prec_for_max_niters): Likewise.
+ 	(loop_niters_no_overflow): Likewise.
+ 	* tree-vectorizer.h (LOOP_VINFO_NITERS_UNCOUNTED_P): New.
+ 
+ 2025-12-15  Peter Damianov  <peter0x44@disroot.org>
+ 
+ 	PR target/108866
+ 	* doc/install.texi: Document --with-windres configure option.
+ 
+ 2025-12-15  Peter Damianov  <peter0x44@disroot.org>
+ 
+ 	PR target/108866
+ 	* gcc.cc (find_a_program): Add check for DEFAULT_WINDRES.
+ 	* configure.ac: Add --with-windres= option.
+ 	* config.in: Regenerate.
+ 	* configure: Regenerate.
+ 
+ 2025-12-15  Peter Damianov  <peter0x44@disroot.org>
+ 
+ 	PR driver/108866
+ 	* gcc.cc (default_compilers): Add EXTRA_DEFAULT_COMPILERS so the config
+ 	of a target can add an extra compiler spec to default_compilers.
+ 	* config/i386/cygming.h (WINDRES_FORMAT_SPEC): New macro to handle
+ 	PE format selection based on TARGET_64BIT_DEFAULT and -m32/-m64 flags.
+ 	(EXTRA_DEFAULT_COMPILERS): Add spec for windres.
+ 	* config/aarch64/cygming.h (EXTRA_DEFAULT_COMPILERS): Likewise.
+ 
+ 2025-12-15  Jerry Zhang Jian  <jerry.zhangjian@sifive.com>
+ 
+ 	* config/riscv/gen-riscv-ext-opt.cc: Rename UPPERCAE_NAME to
+ 	UPPERCASE_NAME.
+ 	* config/riscv/gen-riscv-ext-texi.cc: Likewise.
+ 	* config/riscv/riscv-ext-corev.def: Likewise.
+ 	* config/riscv/riscv-ext-sifive.def: Likewise.
+ 	* config/riscv/riscv-ext-thead.def: Likewise.
+ 	* config/riscv/riscv-ext-ventana.def: Likewise.
+ 
+ 2025-12-14  Lewis Hyatt  <lhyatt@gmail.com>
+ 
+ 	PR tree-optimization/106409
+ 	* gimple-ssa-warn-access.cc (maybe_warn_alloc_args_overflow): Adjust
+ 	comment for clarity, and augment check to work in LTO as well.
+ 
+ 2025-12-14  Surya Kumari Jangala  <jskumari@linux.ibm.com>
+ 
+ 	PR rtl-optimization/122274
+ 	* regcprop.cc (value_data_entry): New field.
+ 	(kill_value_one_regno): Update field.
+ 	(init_value_data): Initialize field.
+ 	(kill_set_value_data): New field.
+ 	(kill_set_value): Update field.
+ 	(kill_autoinc_value): Likewise.
+ 	(copy_value): New parameter. Update field.
+ 	(incompatible_frame_status): New function.
+ 	(find_oldest_value_reg): New parameter. Compare frame relatedness of
+ 	insn and propagated value.
+ 	(replace_oldest_value_reg): Pass additional parameter to
+ 	find_oldest_value_reg().
+ 	(copyprop_hardreg_forward_1): Pass additional parameter to
+ 	find_oldest_value_reg(). Compare frame relatedness of insn and
+ 	propagated value. Call copy_value() with additional parameter.
+ 
  2025-12-13  Andrew Pinski  <andrew.pinski@oss.qualcomm.com>
  
  	PR tree-optimization/46555
diff -Nrcpad gcc-16-20251214/gcc/DATESTAMP gcc-16-20251221/gcc/DATESTAMP
*** gcc-16-20251214/gcc/DATESTAMP	Sun Dec 14 22:32:05 2025
--- gcc-16-20251221/gcc/DATESTAMP	Sun Dec 21 22:32:05 2025
***************
*** 1 ****
! 20251214
--- 1 ----
! 20251221
diff -Nrcpad gcc-16-20251214/gcc/Makefile.in gcc-16-20251221/gcc/Makefile.in
*** gcc-16-20251214/gcc/Makefile.in	Sun Dec 14 22:32:05 2025
--- gcc-16-20251221/gcc/Makefile.in	Sun Dec 21 22:32:05 2025
*************** PLUGIN_HEADERS = $(TREE_H) $(CONFIG_H) $
*** 4140,4146 ****
    hash-set.h dominance.h cfg.h cfgrtl.h cfganal.h cfgbuild.h cfgcleanup.h \
    lcm.h cfgloopmanip.h file-prefix-map.h builtins.def $(INSN_ATTR_H) \
    pass-instances.def params.list $(srcdir)/../include/gomp-constants.h \
!   $(EXPR_H) $(srcdir)/analyzer/*.h $(srcdir)/diagnostics/*.h
  
  # generate the 'build fragment' b-header-vars
  s-header-vars: Makefile
--- 4140,4147 ----
    hash-set.h dominance.h cfg.h cfgrtl.h cfganal.h cfgbuild.h cfgcleanup.h \
    lcm.h cfgloopmanip.h file-prefix-map.h builtins.def $(INSN_ATTR_H) \
    pass-instances.def params.list $(srcdir)/../include/gomp-constants.h \
!   $(EXPR_H) $(srcdir)/analyzer/*.h $(srcdir)/diagnostics/*.h \
!   $(srcdir)/text-art/*.h
  
  # generate the 'build fragment' b-header-vars
  s-header-vars: Makefile
*************** install-plugin: installdirs lang.install
*** 4179,4184 ****
--- 4180,4186 ----
  	  case $$path in \
  	  "$(srcdir)"/analyzer/* \
  	  | "$(srcdir)"/diagnostics/* \
+ 	  | "$(srcdir)"/text-art/* \
  	  | "$(srcdir)"/config/* | "$(srcdir)"/common/config/* \
  	  | "$(srcdir)"/c-family/* | "$(srcdir)"/*.def ) \
  	    base=`echo "$$path" | sed -e "s|$$srcdirstrip/||"`;; \
diff -Nrcpad gcc-16-20251214/gcc/ada/ChangeLog gcc-16-20251221/gcc/ada/ChangeLog
*** gcc-16-20251214/gcc/ada/ChangeLog	Sun Dec 14 22:32:05 2025
--- gcc-16-20251221/gcc/ada/ChangeLog	Sun Dec 21 22:32:05 2025
***************
*** 1,3 ****
--- 1,24 ----
+ 2025-12-19  Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	* sem_attr.adb (Set_Bounds): Fix comment typo, transfered
+ 	-> transferred.
+ 	* sem_ch6.adb (Analyze_Expression_Function): Likewise.
+ 	* sysdep.c (__gnat_get_task_options): Fix comment typo, explicitely
+ 	-> explicitly.
+ 
+ 2025-12-15  Eric Botcazou  <ebotcazou@adacore.com>
+ 
+ 	PR ada/123138
+ 	* sem_attr.adb (Resolve_Attribute) <Attribute_Reduce>: Override a
+ 	universal numeric type only if the prefix is not an aggregate.
+ 
+ 2025-12-15  Eric Botcazou  <ebotcazou@adacore.com>
+ 
+ 	PR ada/123060
+ 	* gcc-interface/utils.cc (update_pointer_to): Synthesize a new
+ 	TYPE_CANONICAL for the old pointer type in the case where there
+ 	is no new pointer type.  Likewise for references.
+ 
  2025-12-11  Eric Botcazou  <ebotcazou@adacore.com>
  
  	PR ada/123096
diff -Nrcpad gcc-16-20251214/gcc/ada/gcc-interface/utils.cc gcc-16-20251221/gcc/ada/gcc-interface/utils.cc
*** gcc-16-20251214/gcc/ada/gcc-interface/utils.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/ada/gcc-interface/utils.cc	Sun Dec 21 22:32:05 2025
*************** update_pointer_to (tree old_type, tree n
*** 4673,4680 ****
  	    new_ptr = TYPE_NEXT_PTR_TO (new_ptr);
  	  TYPE_NEXT_PTR_TO (new_ptr) = old_ptr;
  	}
!       else
! 	TYPE_POINTER_TO (new_type) = old_ptr;
  
        /* Now adjust them.  */
        for (ptr = old_ptr; ptr; ptr = TYPE_NEXT_PTR_TO (ptr))
--- 4673,4695 ----
  	    new_ptr = TYPE_NEXT_PTR_TO (new_ptr);
  	  TYPE_NEXT_PTR_TO (new_ptr) = old_ptr;
  	}
!       else if (old_ptr)
! 	{
! 	  TYPE_POINTER_TO (new_type) = old_ptr;
! 
! 	  /* If there is no pointer pointing to NEW_TYPE yet, re-compute the
! 	     TYPE_CANONICAL of the old pointer but pointing to NEW_TYPE, like
! 	     build_pointer_type would have done for such a pointer, because we
! 	     will propagate it in the adjustment loop below.  */
! 	  if (TYPE_STRUCTURAL_EQUALITY_P (new_type))
! 	    SET_TYPE_STRUCTURAL_EQUALITY (old_ptr);
! 	  else if (TYPE_CANONICAL (new_type) != new_type
! 		   || (TYPE_REF_CAN_ALIAS_ALL (old_ptr)
! 		       && !lookup_attribute ("may_alias",
! 					     TYPE_ATTRIBUTES (new_type))))
! 	    TYPE_CANONICAL (old_ptr)
! 	      = build_pointer_type (TYPE_CANONICAL (new_type));
! 	}
  
        /* Now adjust them.  */
        for (ptr = old_ptr; ptr; ptr = TYPE_NEXT_PTR_TO (ptr))
*************** update_pointer_to (tree old_type, tree n
*** 4694,4701 ****
  	    new_ref = TYPE_NEXT_REF_TO (new_ref);
  	  TYPE_NEXT_REF_TO (new_ref) = old_ref;
  	}
!       else
! 	TYPE_REFERENCE_TO (new_type) = old_ref;
  
        /* Now adjust them.  */
        for (ref = old_ref; ref; ref = TYPE_NEXT_REF_TO (ref))
--- 4709,4731 ----
  	    new_ref = TYPE_NEXT_REF_TO (new_ref);
  	  TYPE_NEXT_REF_TO (new_ref) = old_ref;
  	}
!       else if (old_ref)
! 	{
! 	  TYPE_REFERENCE_TO (new_type) = old_ref;
! 
! 	  /* If there is no reference pointing to NEW_TYPE yet, re-compute the
! 	     TYPE_CANONICAL of the old reference but pointing to NEW_TYPE, like
! 	     build_reference_type would have done for such a reference, because
! 	     we will propagate it in the adjustment loop below.  */
! 	  if (TYPE_STRUCTURAL_EQUALITY_P (new_type))
! 	    SET_TYPE_STRUCTURAL_EQUALITY (old_ref);
! 	  else if (TYPE_CANONICAL (new_type) != new_type
! 		   || (TYPE_REF_CAN_ALIAS_ALL (old_ref)
! 		       && !lookup_attribute ("may_alias",
! 					     TYPE_ATTRIBUTES (new_type))))
! 	    TYPE_CANONICAL (old_ref)
! 	      = build_reference_type (TYPE_CANONICAL (new_type));
! 	}
  
        /* Now adjust them.  */
        for (ref = old_ref; ref; ref = TYPE_NEXT_REF_TO (ref))
diff -Nrcpad gcc-16-20251214/gcc/ada/sem_attr.adb gcc-16-20251221/gcc/ada/sem_attr.adb
*** gcc-16-20251214/gcc/ada/sem_attr.adb	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/ada/sem_attr.adb	Sun Dec 21 22:32:06 2025
*************** package body Sem_Attr is
*** 8199,8205 ****
           --  subtype indication. This is syntactically a pain, but should
           --  not propagate to the entity for the corresponding index subtype.
           --  After checking that the subtype indication is legal, the range
!          --  of the subtype indication should be transfered to the entity.
           --  The attributes for the bounds should remain the simple retrievals
           --  that they are now.
  
--- 8199,8205 ----
           --  subtype indication. This is syntactically a pain, but should
           --  not propagate to the entity for the corresponding index subtype.
           --  After checking that the subtype indication is legal, the range
!          --  of the subtype indication should be transferred to the entity.
           --  The attributes for the bounds should remain the simple retrievals
           --  that they are now.
  
*************** package body Sem_Attr is
*** 13260,13275 ****
                    Accum_Typ := Entity (Prefix (Reducer_E));
  
                 --  If the reducer is an operator from Standard, then the type
!                --  of its first operand would be Any_Type. In this case, make
!                --  sure we do not have an universal type to avoid resolution
!                --  problems later on, and use the base type of numeric types
!                --  to avoid spurious subtype mismatches for the initial value.
  
                 elsif Scope (Reducer_E) = Standard_Standard then
!                   if Accum_Typ = Universal_Integer then
!                      Accum_Typ := Standard_Integer;
!                   elsif Accum_Typ = Universal_Real then
!                      Accum_Typ := Standard_Float;
                    elsif Is_Numeric_Type (Accum_Typ) then
                       Accum_Typ := Base_Type (Accum_Typ);
                    end if;
--- 13260,13280 ----
                    Accum_Typ := Entity (Prefix (Reducer_E));
  
                 --  If the reducer is an operator from Standard, then the type
!                --  of its first operand would be Any_Type.
  
                 elsif Scope (Reducer_E) = Standard_Standard then
!                   --  If Accum_Typ is a universal numeric type and the prefix
!                   --  is not an aggregate, use its component type in order to
!                   --  avoid resolution problems later on.
! 
!                   if Is_Universal_Numeric_Type (Accum_Typ) then
!                      if Nkind (P) /= N_Aggregate then
!                         Accum_Typ := Component_Type (Etype (P));
!                      end if;
! 
!                   --  If Accum_Typ is a specific numeric type, use its base
!                   --  type to avoid subtype mismatches for the initial value.
! 
                    elsif Is_Numeric_Type (Accum_Typ) then
                       Accum_Typ := Base_Type (Accum_Typ);
                    end if;
diff -Nrcpad gcc-16-20251214/gcc/ada/sem_ch6.adb gcc-16-20251221/gcc/ada/sem_ch6.adb
*** gcc-16-20251214/gcc/ada/sem_ch6.adb	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/ada/sem_ch6.adb	Sun Dec 21 22:32:06 2025
*************** package body Sem_Ch6 is
*** 464,470 ****
  
           --  Propagate any pragmas that apply to expression function to the
           --  proper body when the expression function acts as a completion.
!          --  Aspects are automatically transfered because of node rewriting.
  
           Relocate_Pragmas_To_Body (N);
           Analyze (N);
--- 464,470 ----
  
           --  Propagate any pragmas that apply to expression function to the
           --  proper body when the expression function acts as a completion.
!          --  Aspects are automatically transferred because of node rewriting.
  
           Relocate_Pragmas_To_Body (N);
           Analyze (N);
diff -Nrcpad gcc-16-20251214/gcc/ada/sysdep.c gcc-16-20251221/gcc/ada/sysdep.c
*** gcc-16-20251214/gcc/ada/sysdep.c	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/ada/sysdep.c	Sun Dec 21 22:32:06 2025
*************** __gnat_get_task_options (void)
*** 907,913 ****
  
       Note that the same error occurs in both RTP and Kernel mode, but
       VX_DEALLOC_TCB is not defined in the RTP headers, so we need to
!      explicitely check if VX_PRIVATE_UMASK has value 0x8000
    */
  # if defined (VX_PRIVATE_UMASK) && (0x8000 == VX_PRIVATE_UMASK)
    options &= ~VX_PRIVATE_UMASK;
--- 907,913 ----
  
       Note that the same error occurs in both RTP and Kernel mode, but
       VX_DEALLOC_TCB is not defined in the RTP headers, so we need to
!      explicitly check if VX_PRIVATE_UMASK has value 0x8000
    */
  # if defined (VX_PRIVATE_UMASK) && (0x8000 == VX_PRIVATE_UMASK)
    options &= ~VX_PRIVATE_UMASK;
diff -Nrcpad gcc-16-20251214/gcc/algol68/ChangeLog gcc-16-20251221/gcc/algol68/ChangeLog
*** gcc-16-20251214/gcc/algol68/ChangeLog	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/algol68/ChangeLog	Sun Dec 21 22:32:06 2025
***************
*** 1,3 ****
--- 1,82 ----
+ 2025-12-20  Jose E. Marchesi  <jose.marchesi@oracle.com>
+ 
+ 	* a68-low-moids.cc (a68_lower_moids): Fix for layout of
+ 	incomplete types.
+ 
+ 2025-12-19  Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	* a68-low-decls.cc (a68_lower_variable_declaration): Fix comment typo,
+ 	varaible -> variable.
+ 
+ 2025-12-17  Jose E. Marchesi  <jose.marchesi@oracle.com>
+ 
+ 	PR algol68/123006
+ 	* a68-imports.cc (complete_encoded_mode): Fix handling of flex
+ 	modes.
+ 
+ 2025-12-17  Jose E. Marchesi  <jose.marchesi@oracle.com>
+ 
+ 	PR algol68/123132
+ 	* a68-imports.cc (DOFFSET): Fix big-endian path.
+ 
+ 2025-12-16  Jose E. Marchesi  <jose.marchesi@oracle.com>
+ 
+ 	* a68-parser-bottom-up.cc (reduce_prelude_packet): Do not support
+ 	multiple module definitions per packet.
+ 
+ 2025-12-16  Jose E. Marchesi  <jose.marchesi@oracle.com>
+ 
+ 	* lang.opt.urls: Regenerate.
+ 
+ 2025-12-16  Jose E. Marchesi  <jose.marchesi@oracle.com>
+ 
+ 	* lang.opt (-fmodules-map): New option.
+ 	(-fmodules-map-file): Likewise.
+ 	* a68.h: Add prototype for a68_process_module_map.
+ 	* a68-imports.cc (SKIP_WHITESPACES): Define.
+ 	(PARSE_BASENAME): Likewise.
+ 	(PARSE_INDICANT): Likewise.
+ 	(a68_process_module_map): New function.
+ 	* a68-lang.cc: (a68_init): Move initialization of
+ 	A68_MODULE_FILES from there...
+ 	(a68_init_options): to here.
+ 	(a68_handle_option): Handle OPT_fmodules_map and
+ 	OPT_fmodules_map_.
+ 	* a68-parser-pragmat.cc (handle_access_in_pragmat): Normalize
+ 	module indicants to upper case.
+ 	* ga68.texi (Module search options): New section.
+ 
+ 2025-12-16  Jose E. Marchesi  <jose.marchesi@oracle.com>
+ 
+ 	* a68.h: Prototypes for a68_get_file_size and a68_file_read.
+ 	* a68-parser-scanner.cc (a68_file_size): New function.
+ 	(a68_file_read): Renamed from io_read.
+ 	(get_source_size): Deleted function.
+ 	(include_files): Use a68_file_size and a68_file_read.
+ 
+ 2025-12-16  Mohammad-Reza Nabipoor  <mnabipoor@gnu.org>
+ 
+ 	* a68-imports.cc (dump_encoded_mode): Replace "basic" with
+ 	"string".
+ 
+ 2025-12-15  Mohammad-Reza Nabipoor  <mnabipoor@gnu.org>
+ 
+ 	* ga68-exports.pk (ga68_text_reloc_64): Renamed and
+ 	adapted from ga68_text_reloc.
+ 	(ga68_data_reloc_64): Renamed and adapted from ga68_data_reloc.
+ 	(ga68_mode_64): Renamed and adapted from ga68_mode.
+ 	(ga68_extract_64): Renamed and adapted from ga68_extract.
+ 	(ga68_module_64): Renamed and adapted from ga68_module.
+ 	(ga68_text_reloc_32): New type.
+ 	(ga68_data_reloc_32): Likewise.
+ 	(ga68_mode_32): Likewise.
+ 	(ga68_extract_32): Likewise.
+ 	(ga68_module_32): Likewise.
+ 
+ 2025-12-15  Mohammad-Reza Nabipoor  <mnabipoor@gnu.org>
+ 
+ 	* ga68-exports.pk: Fix comment and value for magic number.
+ 
  2025-12-13  Jose E. Marchesi  <jose.marchesi@oracle.com>
  
  	* a68-parser-bottom-up.cc (a68_bottom_up_coalesce_pub): Do not
diff -Nrcpad gcc-16-20251214/gcc/algol68/a68-imports.cc gcc-16-20251221/gcc/algol68/a68-imports.cc
*** gcc-16-20251214/gcc/algol68/a68-imports.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/algol68/a68-imports.cc	Sun Dec 21 22:32:06 2025
***************
*** 45,50 ****
--- 45,150 ----
  
  #include "a68.h"
  
+ /* A few macros to aid parsing of module map strings below.  */
+ 
+ #define SKIP_WHITESPACES(P) while (ISSPACE (*(P))) (P)++
+ 
+ #define PARSE_BASENAME(P,W)						\
+   do									\
+     {									\
+       (W) = (char *) alloca (strlen ((P)));				\
+       size_t i = 0;							\
+       while ((*(P)) != '=' && !ISSPACE (*(P)) && ((*(P)) != '\0'))	\
+ 	(W)[i++] = *((P)++);						\
+       (W)[i] = '\0';							\
+     } while (0)
+ 
+ #define PARSE_INDICANT(P,W)						\
+   do									\
+     {									\
+       (W) = (char *) alloca (strlen ((P)));				\
+       size_t i = 0;							\
+       if (ISALPHA (*(P)))						\
+ 	{								\
+ 	  (W)[i++] = *((P)++);						\
+ 	  while (ISALPHA (*(P)) || ISDIGIT(*(P)) || (*(P)) == '_')	\
+ 	    {								\
+ 	      if ((*(P)) != '_')					\
+ 		(W)[i++] = *((P)++);					\
+ 	    }								\
+ 	}								\
+       (W)[i] = '\0';							\
+     } while (0)
+ 
+ /* Parse module map information in MAP and add entries to A68_MODULE_FILES
+    accordingly.  Existing entries in the map are overriden without warning.
+ 
+    If MAP is not a valid module map specification then this function returns
+    `false' and sets *ERRMSG to some explanatory message.  Otherwise it returns
+    `true' and sets *ERRMSG to NULL.  */
+ 
+ bool
+ a68_process_module_map (const char *map, const char **errmsg)
+ {
+   const char *p = map;
+ 
+   while (*p != '\0')
+     {
+       char *filename;
+       SKIP_WHITESPACES (p);
+       PARSE_BASENAME (p, filename);
+ 
+       if (p[0] != '=')
+ 	{
+ 	  *errmsg = "expected = after filename";
+ 	  goto error;
+ 	}
+       p++;
+ 
+       /* Parse one or more joined module indicants.  */
+       while (p[0] != ':' && p[0] != '\0')
+ 	{
+ 	  char *module;
+ 	  SKIP_WHITESPACES (p);
+ 	  PARSE_INDICANT (p, module);
+ 	  if (module[0] == '\0')
+ 	    {
+ 	      *errmsg = "expected module indicant";
+ 	      goto error;
+ 	    }
+ 
+ 	  SKIP_WHITESPACES (p);
+ 	  if (p[0] != ',' && p[0] != ':' && p[0] != '\0')
+ 	    {
+ 	      *errmsg = "expected comma or end of string after module indicant";
+ 	      goto error;
+ 	    }
+ 
+ 	  for (char *q = module; *q; ++q)
+ 	    *q = TOUPPER (*q);
+ 	  A68_MODULE_FILES->put (ggc_strdup (module), ggc_strdup (filename));
+ 
+ 	  if (p[0] == ',')
+ 	    p++;
+ 	}
+ 
+       SKIP_WHITESPACES (p);
+       if (p[0] != ':' && p[0] != '\0')
+ 	{
+ 	  *errmsg = "expected semicolon or end of string";
+ 	  goto error;
+ 	}
+ 
+       if (p[0] == ':')
+ 	p++;
+     }
+ 
+   *errmsg = NULL;
+   return true;
+  error:
+   return false;
+ }
+ 
  /* Read exports from an object file.
  
     FD is a file descriptor open for reading.
*************** a68_get_packet_exports (const std::strin
*** 395,405 ****
        if (pos + PTR_SIZE > size)					\
  	goto decode_error;						\
        (V) = 0;								\
-       uint64_t ptr_bit_size = 8 * PTR_SIZE;				\
        if (BYTES_BIG_ENDIAN)						\
  	{								\
  	  for (int i = 0; i < PTR_SIZE;	i++)				\
! 	    (V) = ((V) | ((uint8_t) data[pos + i] << (ptr_bit_size - (i * 8)))); \
  	}								\
        else								\
  	{								\
--- 495,504 ----
        if (pos + PTR_SIZE > size)					\
  	goto decode_error;						\
        (V) = 0;								\
        if (BYTES_BIG_ENDIAN)						\
  	{								\
  	  for (int i = 0; i < PTR_SIZE;	i++)				\
! 	    (V) = ((V) | ((uint8_t) data[pos + i] << ((PTR_SIZE - i - 1) * 8))); \
  	}								\
        else								\
  	{								\
*************** complete_encoded_mode (encoded_modes_map
*** 607,613 ****
        /* For recursive declarations.  */
        em->moid = a68_create_mode (em->kind == GA68_MODE_NAME ? REF_SYMBOL : FLEX_SYMBOL,
  				  0, NO_NODE, M_ERROR, NO_PACK);
!       sub = complete_encoded_mode (encoded_modes, em->data.name.sub_offset);
        if (sub == NO_MOID)
  	{
  	  /* Free em->moid */
--- 706,714 ----
        /* For recursive declarations.  */
        em->moid = a68_create_mode (em->kind == GA68_MODE_NAME ? REF_SYMBOL : FLEX_SYMBOL,
  				  0, NO_NODE, M_ERROR, NO_PACK);
!       sub = complete_encoded_mode (encoded_modes,
! 				   em->kind == GA68_MODE_NAME
! 				   ? em->data.name.sub_offset : em->data.flex.sub_offset);
        if (sub == NO_MOID)
  	{
  	  /* Free em->moid */
*************** dump_encoded_mode (struct encoded_mode *
*** 729,735 ****
        printf (" bool\n");
        break;
      case GA68_MODE_STRING:
!       printf (" basic\n");
        break;
      case GA68_MODE_NAME:
        printf (" name\n");
--- 830,836 ----
        printf (" bool\n");
        break;
      case GA68_MODE_STRING:
!       printf (" string\n");
        break;
      case GA68_MODE_NAME:
        printf (" name\n");
diff -Nrcpad gcc-16-20251214/gcc/algol68/a68-lang.cc gcc-16-20251221/gcc/algol68/a68-lang.cc
*** gcc-16-20251214/gcc/algol68/a68-lang.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/algol68/a68-lang.cc	Sun Dec 21 22:32:06 2025
*************** a68_init (void)
*** 239,248 ****
    else
      size_type_node = long_unsigned_type_node;
  
-   /* Create an empty module files map.  */
-   A68_MODULE_FILES = hash_map<nofree_string_hash,const char*>::create_ggc (16);
-   A68_MODULE_FILES->empty ();
- 
    return true;
  }
  
--- 239,244 ----
*************** static void
*** 445,451 ****
  a68_init_options (unsigned int argc ATTRIBUTE_UNUSED,
  		  cl_decoded_option *decoded_options ATTRIBUTE_UNUSED)
  {
!   /* Nothing to do here for now.  */
  }
  
  #undef LANG_HOOKS_INIT_OPTIONS
--- 441,449 ----
  a68_init_options (unsigned int argc ATTRIBUTE_UNUSED,
  		  cl_decoded_option *decoded_options ATTRIBUTE_UNUSED)
  {
!   /* Create an empty module files map.  */
!   A68_MODULE_FILES = hash_map<nofree_string_hash,const char*>::create_ggc (16);
!   A68_MODULE_FILES->empty ();
  }
  
  #undef LANG_HOOKS_INIT_OPTIONS
*************** a68_handle_option (size_t scode,
*** 519,524 ****
--- 517,557 ----
  
    switch (code)
      {
+     case OPT_fmodules_map:
+     case OPT_fmodules_map_:
+       {
+ 	const char *errmsg;
+ 	if (!a68_process_module_map (arg, &errmsg))
+ 	  error ("invalid argument for %<-fmodules-map%>: %s", errmsg);
+ 	break;
+       }
+     case OPT_fmodules_map_file:
+     case OPT_fmodules_map_file_:
+       {
+ 	FILE *file = fopen (arg, "r");
+ 	if (file == NULL)
+ 	  fatal_error (UNKNOWN_LOCATION,
+ 		       "cannot open modules map file %<%s%>", arg);
+ 	
+ 	ssize_t ssize = a68_file_size (file);
+ 	if (ssize < 0)
+ 	  fatal_error (UNKNOWN_LOCATION,
+ 		       "cannot determine size of modules map file %<%s%>", arg);
+ 	size_t fsize = ssize;
+ 
+ 	char *buffer = (char *) xmalloc (fsize + 1);
+ 	size_t bytes_read = a68_file_read (file, buffer, fsize);
+ 	if (bytes_read != fsize)
+ 	  fatal_error (UNKNOWN_LOCATION,
+ 		       "cannot read contents of modules map file %<%s%>", arg);
+ 	buffer[fsize] = '\0';
+ 
+ 	const char *errmsg;
+ 	if (!a68_process_module_map (buffer, &errmsg))
+ 	  fatal_error (UNKNOWN_LOCATION, "%s: %s", arg, errmsg);
+ 	free (buffer);
+ 	break;
+       }
      case OPT_std_algol68:
        OPTION_STRICT (&A68_JOB) = 1;
        break;
diff -Nrcpad gcc-16-20251214/gcc/algol68/a68-low-decls.cc gcc-16-20251221/gcc/algol68/a68-low-decls.cc
*** gcc-16-20251214/gcc/algol68/a68-low-decls.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/algol68/a68-low-decls.cc	Sun Dec 21 22:32:06 2025
*************** a68_lower_variable_declaration (NODE_T *
*** 209,215 ****
       pointer as the initial of the var_decl because the bouns in the actual
       declarer shall be elaborated at the point of the code where the
       declaration appears, not at the beginning of its reach.  Note that the
!      mode of the declarer will be always a REF, since this is a varaible
       declaration: the referred mode is what we pass to the a68_low_generator.
  
       If the STATIC generator is used, the var_decl created above is not a
--- 209,215 ----
       pointer as the initial of the var_decl because the bouns in the actual
       declarer shall be elaborated at the point of the code where the
       declaration appears, not at the beginning of its reach.  Note that the
!      mode of the declarer will be always a REF, since this is a variable
       declaration: the referred mode is what we pass to the a68_low_generator.
  
       If the STATIC generator is used, the var_decl created above is not a
diff -Nrcpad gcc-16-20251214/gcc/algol68/a68-low-moids.cc gcc-16-20251221/gcc/algol68/a68-low-moids.cc
*** gcc-16-20251214/gcc/algol68/a68-low-moids.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/algol68/a68-low-moids.cc	Sun Dec 21 22:32:06 2025
*************** a68_lower_moids (MOID_T *mode)
*** 688,714 ****
  
    for (MOID_T *m = mode; m != NO_MOID; FORWARD (m))
      {
!       if (!COMPLETE_TYPE_P (CTYPE (m)))
  	{
! 	  if (IS_STRUCT (m))
  	    {
! 	      tree struct_type = CTYPE (m);
! 	      layout_type (struct_type);
! 	      compute_record_mode (struct_type);
  	    }
- 	  else if (IS_UNION (m))
- 	    {
- 	      tree union_type = CTYPE (m);
- 	      tree c_union_type = TREE_TYPE (TREE_CHAIN (TYPE_FIELDS (union_type)));
- 
- 	      if (!COMPLETE_TYPE_P (c_union_type))
- 		{
- 		  layout_type (c_union_type);
- 		  compute_record_mode (c_union_type);
- 		}
  
  	      layout_type (union_type);
  	      compute_record_mode (union_type);
  	    }
  	  else
  	    layout_type (CTYPE (m));
--- 688,719 ----
  
    for (MOID_T *m = mode; m != NO_MOID; FORWARD (m))
      {
!       if (IS_UNION (m))
  	{
! 	  tree union_type = CTYPE (m);
! 	  tree c_union_type = TREE_TYPE (TREE_CHAIN (TYPE_FIELDS (union_type)));
! 
! 	  if (!COMPLETE_TYPE_P (c_union_type))
  	    {
! 	      layout_type (c_union_type);
! 	      compute_record_mode (c_union_type);
! 	      gcc_assert (COMPLETE_TYPE_P (c_union_type));
  	    }
  
+ 	  if (!COMPLETE_TYPE_P (union_type))
+ 	    {
  	      layout_type (union_type);
  	      compute_record_mode (union_type);
+ 	      gcc_assert (COMPLETE_TYPE_P (union_type));
+ 	    }
+ 	}
+       else if (!COMPLETE_TYPE_P (CTYPE (m)))
+ 	{
+ 	  if (IS_STRUCT (m))
+ 	    {
+ 	      tree struct_type = CTYPE (m);
+ 	      layout_type (struct_type);
+ 	      compute_record_mode (struct_type);
  	    }
  	  else
  	    layout_type (CTYPE (m));
diff -Nrcpad gcc-16-20251214/gcc/algol68/a68-parser-bottom-up.cc gcc-16-20251221/gcc/algol68/a68-parser-bottom-up.cc
*** gcc-16-20251214/gcc/algol68/a68-parser-bottom-up.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/algol68/a68-parser-bottom-up.cc	Sun Dec 21 22:32:06 2025
*************** reduce_prelude_packet (NODE_T *p)
*** 456,461 ****
--- 456,462 ----
    reduce (p, strange_tokens, NO_TICK,
  	  MODULE_DECLARATION, MODULE_SYMBOL, DEFINING_MODULE_INDICANT, EQUALS_SYMBOL, -MODULE_TEXT, STOP);
  
+ #if 0
    /* Joined module declarations.  */
    for (NODE_T *q = p; q != NO_NODE; FORWARD (q))
      {
*************** reduce_prelude_packet (NODE_T *p)
*** 469,474 ****
--- 470,476 ----
  	}
        while (siga);
      }
+ #endif
  
    /* Try reducing a prelude packet.  */
    reduce (p, NO_NOTE, NO_TICK, PRELUDE_PACKET, MODULE_DECLARATION, STOP);
diff -Nrcpad gcc-16-20251214/gcc/algol68/a68-parser-pragmat.cc gcc-16-20251221/gcc/algol68/a68-parser-pragmat.cc
*** gcc-16-20251214/gcc/algol68/a68-parser-pragmat.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/algol68/a68-parser-pragmat.cc	Sun Dec 21 22:32:06 2025
*************** handle_access_in_pragmat (NODE_T *p, con
*** 118,123 ****
--- 118,128 ----
  			    found);
        return NULL;
      }
+ 
+   /* Normalize module indicant to upper-case.  */
+   for (char *q = module; *q; ++q)
+     *q = TOUPPER (*q);
+ 
    /* Add entry in the module files map.  */
    const char **pmodule = A68_MODULE_FILES->get (module);
    if (pmodule != NULL)
diff -Nrcpad gcc-16-20251214/gcc/algol68/a68-parser-scanner.cc gcc-16-20251221/gcc/algol68/a68-parser-scanner.cc
*** gcc-16-20251214/gcc/algol68/a68-parser-scanner.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/algol68/a68-parser-scanner.cc	Sun Dec 21 22:32:06 2025
*************** supper_postlude[] = {
*** 119,128 ****
      }									\
    while (0)
  
  /* Read bytes from file into buffer.  */
  
! static ssize_t
! io_read (FILE *file, void *buf, size_t n)
  {
    int fd = fileno (file);
    size_t to_do = n;
--- 119,153 ----
      }									\
    while (0)
  
+ /* Get the size of a file given a file descriptor FILE.  In case the size of
+    the file cannot be determined then this function returns -1.  */
+ 
+ ssize_t
+ a68_file_size (FILE *file)
+ {
+   ssize_t fsize;
+   off_t off, save;
+ 
+   save = ftell (file);
+   if (save == -1)
+     return -1;
+ 
+   off = lseek (fileno (file), 0, SEEK_END);
+   if (off == (off_t) -1)
+     return -1;
+   fsize = (ssize_t) off;
+ 
+   off = lseek (fileno (file), 0, save);
+   if (off == (off_t) -1)
+     return -1;
+ 
+   return fsize;
+ }
+ 
  /* Read bytes from file into buffer.  */
  
! ssize_t
! a68_file_read (FILE *file, void *buf, size_t n)
  {
    int fd = fileno (file);
    size_t to_do = n;
*************** concatenate_lines (LINE_T * top)
*** 291,305 ****
      }
  }
  
- /* Size of source file.  */
- 
- static int
- get_source_size (void)
- {
-   FILE *f = FILE_SOURCE_FD (&A68_JOB);
-   return (int) lseek (fileno (f), 0, SEEK_END);
- }
- 
  /* Read source file FILENAME and make internal copy.  */
  
  static bool
--- 316,321 ----
*************** read_source_file (const char *filename)
*** 328,334 ****
      fatal_error (UNKNOWN_LOCATION, "specified file %s is a directory",
  		 filename);
  
!   source_file_size = get_source_size ();
  
    /* Allocate A68_PARSER (scan_buf), which is an auxiliary buffer used by the
       scanner known to be big enough to hold any string contained in the source
--- 344,353 ----
      fatal_error (UNKNOWN_LOCATION, "specified file %s is a directory",
  		 filename);
  
!   l = a68_file_size (f);
!   if (l < 0)
!     error ("could not get size of source file");
!   source_file_size = l;
  
    /* Allocate A68_PARSER (scan_buf), which is an auxiliary buffer used by the
       scanner known to be big enough to hold any string contained in the source
*************** read_source_file (const char *filename)
*** 344,356 ****
  
    /* Read the file into a single buffer, so we save on system calls.  */
    line_num = 1;
-   errno = 0;
    buffer = (char *) xmalloc (8 + source_file_size);
!   if (lseek (fileno (f), 0, SEEK_SET) < 0)
!     gcc_unreachable ();
!   errno = 0;
!   bytes_read = io_read (f, buffer, source_file_size);
!   gcc_assert (errno == 0 && bytes_read == source_file_size);
  
    /* Link all lines into the list.  */
    k = 0;
--- 363,371 ----
  
    /* Read the file into a single buffer, so we save on system calls.  */
    line_num = 1;
    buffer = (char *) xmalloc (8 + source_file_size);
!   bytes_read = a68_file_read (f, buffer, source_file_size);
!   gcc_assert (bytes_read == source_file_size);
  
    /* Link all lines into the list.  */
    k = 0;
*************** include_files (LINE_T *top)
*** 969,976 ****
  	  if (item != NO_TEXT && streq (item, "INCLUDE") == 0)
  	    {
  	      FILE *fp;
- 	      int fd;
  	      size_t fsize, k;
  	      int n, linum, bytes_read;
  	      char *fbuf, delim;
  	      BUFFER fnb;
--- 984,991 ----
  	  if (item != NO_TEXT && streq (item, "INCLUDE") == 0)
  	    {
  	      FILE *fp;
  	      size_t fsize, k;
+ 	      ssize_t ssize;
  	      int n, linum, bytes_read;
  	      char *fbuf, delim;
  	      BUFFER fnb;
*************** include_files (LINE_T *top)
*** 1060,1085 ****
  	      t = NO_LINE;
  
  	      /* Access the file.  */
- 	      errno = 0;
  	      fp = fopen (fn, "r");
  	      SCAN_ERROR (fp == NULL, start_l, start_c,
  			  "error opening included file");
! 	      fd = fileno (fp);
! 	      errno = 0;
! 	      off_t off = lseek (fd, 0, SEEK_END);
! 	      gcc_assert (off >= 0);
! 	      fsize = (size_t) off;
! 	      SCAN_ERROR (errno != 0, start_l, start_c,
! 			  "error while reading file");
  	      fbuf = (char *) xmalloc (8 + fsize);
! 	      errno = 0;
! 	      if (lseek (fd, 0, SEEK_SET) < 0)
! 		gcc_unreachable ();
! 	      SCAN_ERROR (errno != 0, start_l, start_c,
! 			  "error while reading file");
! 	      errno = 0;
! 	      bytes_read = (int) io_read (fp, fbuf, (size_t) fsize);
! 	      SCAN_ERROR (errno != 0 || (size_t) bytes_read != fsize, start_l, start_c,
  			  "error while reading file");
  
  	      /* Buffer still usable?.  */
--- 1075,1090 ----
  	      t = NO_LINE;
  
  	      /* Access the file.  */
  	      fp = fopen (fn, "r");
  	      SCAN_ERROR (fp == NULL, start_l, start_c,
  			  "error opening included file");
! 	      ssize = a68_file_size (fp);
! 	      SCAN_ERROR (ssize < 0, start_l, start_c,
! 			  "error getting included file size");
! 	      fsize = ssize;
  	      fbuf = (char *) xmalloc (8 + fsize);
! 	      bytes_read = (int) a68_file_read (fp, fbuf, (size_t) fsize);
! 	      SCAN_ERROR ((size_t) bytes_read != fsize, start_l, start_c,
  			  "error while reading file");
  
  	      /* Buffer still usable?.  */
diff -Nrcpad gcc-16-20251214/gcc/algol68/a68.h gcc-16-20251221/gcc/algol68/a68.h
*** gcc-16-20251214/gcc/algol68/a68.h	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/algol68/a68.h	Sun Dec 21 22:32:06 2025
*************** void a68_scan_error (LINE_T *u, char *v,
*** 281,286 ****
--- 281,288 ----
  /* a68-parser-scanner.cc  */
  
  bool a68_lexical_analyser (const char *filename, bool *empty_file);
+ ssize_t a68_file_size (FILE *file);
+ ssize_t a68_file_read (FILE *file, void *buf, size_t n);
  
  /* a68-parser.cc  */
  
*************** void a68_do_exports (NODE_T *p);
*** 1107,1112 ****
--- 1109,1115 ----
  /* a68-imports.cc  */
  
  MOIF_T *a68_open_packet (const char *module);
+ bool a68_process_module_map (const char *map, const char **errmsg);
  
  /* a68-parser-debug.cc  */
  
diff -Nrcpad gcc-16-20251214/gcc/algol68/ga68-exports.pk gcc-16-20251221/gcc/algol68/ga68-exports.pk
*** gcc-16-20251214/gcc/algol68/ga68-exports.pk	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/algol68/ga68-exports.pk	Sun Dec 21 22:32:06 2025
*************** var ga68_exports_ver = 1;
*** 95,102 ****
  
  load elf;
  
! type ga68_text_reloc = Elf64_Addr;
! type ga68_data_reloc = Elf64_Addr;
  
  /* Strings are encoded in-place and are both pre-sized and
     NULL-terminated.  This is to ease reading them quickly and
--- 95,104 ----
  
  load elf;
  
! type ga68_text_reloc_64 = Elf64_Addr;
! type ga68_data_reloc_64 = Elf64_Addr;
! type ga68_text_reloc_32 = Elf32_Addr;
! type ga68_data_reloc_32 = Elf32_Addr;
  
  /* Strings are encoded in-place and are both pre-sized and
     NULL-terminated.  This is to ease reading them quickly and
*************** var GA68_MODE_UNKNOWN   = 0UB,
*** 135,141 ****
      GA68_MODE_STRING    = 14UB,
      GA68_MODE_FLEX      = 15UB;
  
! type ga68_mode =
    struct
    {
      uint<8> kind : kind in [GA68_MODE_VOID, GA68_MODE_INT,
--- 137,143 ----
      GA68_MODE_STRING    = 14UB,
      GA68_MODE_FLEX      = 15UB;
  
! type ga68_mode_64 =
    struct
    {
      uint<8> kind : kind in [GA68_MODE_VOID, GA68_MODE_INT,
*************** type ga68_mode =
*** 153,173 ****
                                 GA68_MODE_BYTES];
        struct
        {
!         ga68_data_reloc mode;
        } name : kind == GA68_MODE_NAME || kind == GA68_MODE_FLEX;
  
        struct
        {
!         type triplet = struct { ga68_text_reloc lb; ga68_text_reloc ub; };
  
          uint<8> ndims;
          triplet[ndims] dims;
!         ga68_data_reloc row_of;
        } row : kind == GA68_MODE_ROW;
  
        struct
        {
!         type field = struct { ga68_data_reloc mode; ga68_str name; };
  
          uint<16> nfields;
          field[nfields] fields;
--- 155,175 ----
                                 GA68_MODE_BYTES];
        struct
        {
!         ga68_data_reloc_64 mode;
        } name : kind == GA68_MODE_NAME || kind == GA68_MODE_FLEX;
  
        struct
        {
!         type triplet = struct { ga68_text_reloc_64 lb; ga68_text_reloc_64 ub; };
  
          uint<8> ndims;
          triplet[ndims] dims;
!         ga68_data_reloc_64 row_of;
        } row : kind == GA68_MODE_ROW;
  
        struct
        {
!         type field = struct { ga68_data_reloc_64 mode; ga68_str name; };
  
          uint<16> nfields;
          field[nfields] fields;
*************** type ga68_mode =
*** 176,189 ****
        struct
        {
          uint<8> nmodes;
!         ga68_data_reloc[nmodes] modes;
        } uni : kind == GA68_MODE_UNION;
  
        struct
        {
!         type arg = struct { ga68_data_reloc mode; ga68_str name; };
  
!         ga68_data_reloc ret_mode;
          uint<8> nargs;
          arg[nargs] args;
        } routine : kind == GA68_MODE_PROC;
--- 178,251 ----
        struct
        {
          uint<8> nmodes;
!         ga68_data_reloc_64[nmodes] modes;
        } uni : kind == GA68_MODE_UNION;
  
        struct
        {
!         type arg = struct { ga68_data_reloc_64 mode; ga68_str name; };
  
!         ga68_data_reloc_64 ret_mode;
!         uint<8> nargs;
!         arg[nargs] args;
!       } routine : kind == GA68_MODE_PROC;
! 
!       struct { } _ : kind in [GA68_MODE_UNKNOWN, GA68_MODE_VOID,
!                               GA68_MODE_CHAR, GA68_MODE_BOOL,
!                               GA68_MODE_STRING];
! 
!     } data;
!   };
! 
! type ga68_mode_32 =
!   struct
!   {
!     uint<8> kind : kind in [GA68_MODE_VOID, GA68_MODE_INT,
!                             GA68_MODE_REAL, GA68_MODE_BITS,
!                             GA68_MODE_BYTES, GA68_MODE_CHAR,
!                             GA68_MODE_CMPL, GA68_MODE_ROW,
!                             GA68_MODE_STRUCT, GA68_MODE_UNION,
!                             GA68_MODE_NAME, GA68_MODE_PROC,
!                             GA68_MODE_FLEX];
! 
!     union
!     {
!       int<8> sizety : kind in [GA68_MODE_INT, GA68_MODE_REAL,
!                                GA68_MODE_CMPL, GA68_MODE_BITS,
!                                GA68_MODE_BYTES];
!       struct
!       {
!         ga68_data_reloc_32 mode;
!       } name : kind == GA68_MODE_NAME || kind == GA68_MODE_FLEX;
! 
!       struct
!       {
!         type triplet = struct { ga68_text_reloc_32 lb; ga68_text_reloc_32 ub; };
! 
!         uint<8> ndims;
!         triplet[ndims] dims;
!         ga68_data_reloc_32 row_of;
!       } row : kind == GA68_MODE_ROW;
! 
!       struct
!       {
!         type field = struct { ga68_data_reloc_32 mode; ga68_str name; };
! 
!         uint<16> nfields;
!         field[nfields] fields;
!       } sct : kind == GA68_MODE_STRUCT;
! 
!       struct
!       {
!         uint<8> nmodes;
!         ga68_data_reloc_32[nmodes] modes;
!       } uni : kind == GA68_MODE_UNION;
! 
!       struct
!       {
!         type arg = struct { ga68_data_reloc_32 mode; ga68_str name; };
! 
!         ga68_data_reloc_32 ret_mode;
          uint<8> nargs;
          arg[nargs] args;
        } routine : kind == GA68_MODE_PROC;
*************** type ga68_mode =
*** 201,207 ****
     Mode extracts represent declarations of mode indications, like for
     example `mode Foo = struct (int i, real r)'.
  
!    Identifier extracts represent declarations of constans, variables,
     procedures and operators.  Examples are `real pi = 3.14', `int
     counter', `proc double = (int a) int : a * 2' and `op // = (int a,
     b) int: a % b'.
--- 263,269 ----
     Mode extracts represent declarations of mode indications, like for
     example `mode Foo = struct (int i, real r)'.
  
!    Identifier extracts represent declarations of constants, variables,
     procedures and operators.  Examples are `real pi = 3.14', `int
     counter', `proc double = (int a) int : a * 2' and `op // = (int a,
     b) int: a % b'.
*************** var GA68_EXTRACT_MODU  = 0UB,
*** 224,230 ****
      GA68_EXTRACT_PRIO = 3UB,
      GA68_EXTRACT_OPER = 4UB;
  
! type ga68_extract =
    struct
    {
      Elf64_Off extract_size;
--- 286,292 ----
      GA68_EXTRACT_PRIO = 3UB,
      GA68_EXTRACT_OPER = 4UB;
  
! type ga68_extract_64 =
    struct
    {
      Elf64_Off extract_size;
*************** type ga68_extract =
*** 240,253 ****
        {
          uint<8> mark : mark == GA68_EXTRACT_IDEN;
          ga68_str name;
!         ga68_data_reloc mode;
        } identifier;
  
        struct
        {
          uint<8> mark : mark == GA68_EXTRACT_MODE;
          ga68_str mode_indication;
!         ga68_data_reloc mode;
        } mode;
  
        struct
--- 302,315 ----
        {
          uint<8> mark : mark == GA68_EXTRACT_IDEN;
          ga68_str name;
!         ga68_data_reloc_64 mode;
        } identifier;
  
        struct
        {
          uint<8> mark : mark == GA68_EXTRACT_MODE;
          ga68_str mode_indication;
!         ga68_data_reloc_64 mode;
        } mode;
  
        struct
*************** type ga68_extract =
*** 261,267 ****
        {
          uint<8> mark : mark == GA68_EXTRACT_OPER;
          ga68_str opname;
!         ga68_mode mode;
        } oper;
  
      } extract : extract'size == extract_size;
--- 323,329 ----
        {
          uint<8> mark : mark == GA68_EXTRACT_OPER;
          ga68_str opname;
!         ga68_mode_64 mode;
        } oper;
  
      } extract : extract'size == extract_size;
*************** type ga68_extract =
*** 270,282 ****
      uint<8>[mdextra_size] data;
    };
  
  /* The contents of the .ga68_exports section can be mapped as a
     ga68_module[sec.sh_size] */
  
! type ga68_module =
    struct
    {
!     uint<8>[2] magic : magic == [0x0aUB, 0xadUB];
      uint<16> version : version == ga68_exports_ver;
  
      /* Module identification.
--- 332,396 ----
      uint<8>[mdextra_size] data;
    };
  
+ type ga68_extract_32 =
+   struct
+   {
+     type ga68_mdextra =
+       struct
+         {
+           Elf32_Off mdextra_size;
+           uint<8>[mdextra_size] data;
+         };
+ 
+     Elf32_Off extract_size;
+     union
+     {
+       struct
+       {
+         uint<8> mark : mark == GA68_EXTRACT_MODU;
+         ga68_str module_indication;
+       } module;
+ 
+       struct
+       {
+         uint<8> mark : mark == GA68_EXTRACT_IDEN;
+         ga68_str name;
+         ga68_data_reloc_32 mode;
+         ga68_mdextra mdextra;
+       } identifier;
+ 
+       struct
+       {
+         uint<8> mark : mark == GA68_EXTRACT_MODE;
+         ga68_str mode_indication;
+         ga68_data_reloc_32 mode;
+       } mode;
+ 
+       struct
+       {
+         uint<8> mark : mark == GA68_EXTRACT_PRIO;
+         ga68_str opname;
+         uint<8> prio;
+       } prio;
+ 
+       struct
+       {
+         uint<8> mark : mark == GA68_EXTRACT_OPER;
+         ga68_str opname;
+         ga68_mode_32 mode;
+         ga68_mdextra mdextra;
+       } oper;
+ 
+     } extract : extract'size == extract_size;
+   };
+ 
  /* The contents of the .ga68_exports section can be mapped as a
     ga68_module[sec.sh_size] */
  
! type ga68_module_64 =
    struct
    {
!     uint<8>[2] magic : magic == [0x0aUB, 0x68UB];
      uint<16> version : version == ga68_exports_ver;
  
      /* Module identification.
*************** type ga68_module =
*** 289,297 ****
  
      /* Table of modes.  */
      Elf64_Off modes_size;
!     ga68_mode[modes_size] modes;
  
      /* Table of extracts.  */
      Elf64_Off extracts_size;
!     ga68_extract[extracts_size] extracts;
    };
--- 403,434 ----
  
      /* Table of modes.  */
      Elf64_Off modes_size;
!     ga68_mode_64[modes_size] modes;
  
      /* Table of extracts.  */
      Elf64_Off extracts_size;
!     ga68_extract_64[extracts_size] extracts;
!   };
! 
! type ga68_module_32 =
!   struct
!   {
!     uint<8>[2] magic : magic == [0x0aUB, 0x68UB];
!     uint<16> version : version == ga68_exports_ver;
! 
!     /* Module identification.
!        Add a hash or UUID?  */
!     ga68_str name;
! 
!     /* Entry points.  */
!     ga68_str prelude;
!     ga68_str poslude;
! 
!     /* Table of modes.  */
!     Elf32_Off modes_size;
!     ga68_mode_32[modes_size] modes;
! 
!     /* Table of extracts.  */
!     Elf32_Off extracts_size;
!     ga68_extract_32[extracts_size] extracts;
    };
diff -Nrcpad gcc-16-20251214/gcc/algol68/ga68.texi gcc-16-20251221/gcc/algol68/ga68.texi
*** gcc-16-20251214/gcc/algol68/ga68.texi	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/algol68/ga68.texi	Sun Dec 21 22:32:06 2025
*************** This manual only documents the options s
*** 155,160 ****
--- 155,161 ----
  @menu
  * Dialect options::         Options controlling the accepted language.
  * Directory options::       Options influencing where to find source files.
+ * Module search options::   Options influencing where to look for modules.
  * Warnings options::        Options controlling warnings specific to ga68
  * Runtime options::         Options controlling runtime behavior
  * Linking options::         Options influencing the linking step
*************** will also be added to the list of librar
*** 224,229 ****
--- 225,264 ----
  
  @end table
  
+ @node Module search options
+ @section Module search options
+ @cindex options, modules
+ @cindex modules
+ 
+ The following options can be used to tell the compiler where to look
+ for certain modules.
+ 
+ @table @gcctabopt
+ @opindex fmodules-map
+ @item -fmodules-map=@var{string}
+ Use the mapping between module indicants and module base filenames
+ specified in @var{string}, which must contain a sequence of entries
+ with form
+ @code{@var{basename}=@var{moduleindicant}[,@var{moduleindicant}]...}
+ separated by colon (@code{:}) characters.
+ 
+ When a module @var{moduleindicant} is accessed, the compiler will look
+ for exports information for it in files @file{@var{basename}.m68},
+ @file{lib@var{basename}.so}, @file{lib@var{basename}.a},
+ @file{@var{basename}.o}, in that order.
+ 
+ This option is used to avoid the default behavior, in which the
+ basename used to search for an accessed module is implicitly derived
+ from its indicant, by transforming it to lower case.
+ 
+ The effect of this option is accumulative.
+ 
+ @opindex fmodules-map-file
+ @item -fmodules-map-file=@var{<filename>}
+ Like @option{-fmodules-map}, but read the mapping information from the
+ file @var{<filename>}.
+ @end table
+ 
  @node Warnings options
  @section Warnings options
  @cindex options, warnings
*************** XXX
*** 850,855 ****
--- 885,895 ----
  
  XXX
  
+ As we have seen modules are accessed by referring to them in
+ access-clauses, using the same sort of bold-word indicants that
+ identify user-defined modes and operators, such as @code{JSON},
+ @code{Transput} or @code{LEB128_Arithmetic}.
+ 
  @node Modules and protection
  @subsection Modules and protection
  @cindex protection
diff -Nrcpad gcc-16-20251214/gcc/algol68/lang.opt gcc-16-20251221/gcc/algol68/lang.opt
*** gcc-16-20251214/gcc/algol68/lang.opt	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/algol68/lang.opt	Sun Dec 21 22:32:06 2025
*************** Enum(stropping_regime) String(upper) Val
*** 123,126 ****
--- 123,144 ----
  EnumValue
  Enum(stropping_regime) String(supper) Value(1)
  
+ ; Module maps
+ 
+ fmodules-map
+ Algol68 Separate RejectNegative
+ -fmodules-map=<mapstring>                 Association between module indicants and files.
+ 
+ fmodules-map=
+ Algol68 Joined RejectNegative
+ -fmodules-map=<mapstring>                 Association between module indicants and files.
+ 
+ fmodules-map-file
+ Algol68 Separate RejectNegative
+ -fmodules-map-file=<filename>              File containing modules map.
+ 
+ fmodules-map-file=
+ Algol68 Joined RejectNegative
+ -fmodules-map-file=<filename>              File containing modules map.
+ 
  ; This comment is to ensure we retain the blank line above.
diff -Nrcpad gcc-16-20251214/gcc/algol68/lang.opt.urls gcc-16-20251221/gcc/algol68/lang.opt.urls
*** gcc-16-20251214/gcc/algol68/lang.opt.urls	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/algol68/lang.opt.urls	Sun Dec 21 22:32:06 2025
*************** LangUrlSuffix_Algol68(ga68/Linking-optio
*** 48,50 ****
--- 48,62 ----
  shared-libga68
  LangUrlSuffix_Algol68(ga68/Linking-options.html#index-shared-libga68)
  
+ fmodules-map
+ LangUrlSuffix_Algol68(ga68/Module-search-options.html#index-fmodules-map)
+ 
+ fmodules-map=
+ LangUrlSuffix_Algol68(ga68/Module-search-options.html#index-fmodules-map)
+ 
+ fmodules-map-file
+ LangUrlSuffix_Algol68(ga68/Module-search-options.html#index-fmodules-map-file)
+ 
+ fmodules-map-file=
+ LangUrlSuffix_Algol68(ga68/Module-search-options.html#index-fmodules-map-file)
+ 
diff -Nrcpad gcc-16-20251214/gcc/alias.cc gcc-16-20251221/gcc/alias.cc
*** gcc-16-20251214/gcc/alias.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/alias.cc	Sun Dec 21 22:32:06 2025
*************** alias_set_subset_of (alias_set_type set1
*** 442,448 ****
       *ptr2 = ...
  
       Additionally if a set contains universal pointer, we consider every pointer
!      to be a subset of it, but we do not represent this explicitely - doing so
       would require us to update transitive closure each time we introduce new
       pointer type.  This makes aliasing_component_refs_p to return true
       on the following testcase:
--- 442,448 ----
       *ptr2 = ...
  
       Additionally if a set contains universal pointer, we consider every pointer
!      to be a subset of it, but we do not represent this explicitly - doing so
       would require us to update transitive closure each time we introduce new
       pointer type.  This makes aliasing_component_refs_p to return true
       on the following testcase:
diff -Nrcpad gcc-16-20251214/gcc/analyzer/ChangeLog gcc-16-20251221/gcc/analyzer/ChangeLog
*** gcc-16-20251214/gcc/analyzer/ChangeLog	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/analyzer/ChangeLog	Sun Dec 21 22:32:06 2025
***************
*** 1,3 ****
--- 1,54 ----
+ 2025-12-16  David Malcolm  <dmalcolm@redhat.com>
+ 
+ 	PR analyzer/123136
+ 	* engine.cc
+ 	(strongly_connected_components::strongly_connected_components):
+ 	Consistently use size_t.
+ 	(strongly_connected_components::dump): Likewise.
+ 	(strongly_connected_components::to_json): Likewise.
+ 	(exploded_graph::print_bar_charts): Likewise.
+ 	(exploded_path::feasible_p): Remove unused locals.
+ 	(exploded_graph_annotator::exploded_graph_annotator): Use size_t
+ 	for iterator var.
+ 	(impl_run_checkers): Drop logger param of engine ctor.
+ 	* ops.cc (phis_for_edge_op::maybe_make): Drop unused param of
+ 	phis_for_edge_op ctor.
+ 	(phis_for_edge_op::phis_for_edge_op): Likewise.
+ 	* ops.h (operation::~operation): Make virtual.
+ 	(control_flow_op::dyn_cast_control_flow_op): Add "final override".
+ 	(phis_for_edge_op::phis_for_edge_op): Drop unused param.
+ 	(phis_for_edge_op::m_cfg_in_edge): Drop unused field.
+ 	* region-model.cc (engine::engine): Drop unused "logger" param.
+ 	* region-model.h (engine::engine): Likewise.
+ 	* supergraph-fixup-locations.cc (location_fixer::location_fixer):
+ 	Drop m_sg field.
+ 	(location_fixer::m_sg): Drop unused field.
+ 	(location_fixer::m_purge_map): Drop unused field.
+ 	* supergraph-sorting.cc (class sorting_worklist): Drop unused
+ 	m_worklist field.
+ 
+ 2025-12-16  David Malcolm  <dmalcolm@redhat.com>
+ 
+ 	* supergraph.cc (supernode::dump_dot): Escape filename.
+ 
+ 2025-12-16  David Malcolm  <dmalcolm@redhat.com>
+ 
+ 	PR analyzer/122003
+ 	* checker-event.cc (return_event::get_program_state): New.
+ 	* checker-event.h (return_event::get_program_state): New decl.
+ 
+ 2025-12-15  David Malcolm  <dmalcolm@redhat.com>
+ 
+ 	PR analyzer/123085
+ 	* region-model.cc (region_model::scan_for_null_terminator_1): Use
+ 	byte offset when accessing string constant.
+ 
+ 2025-12-15  David Malcolm  <dmalcolm@redhat.com>
+ 
+ 	PR analyzer/122975
+ 	* region-model-manager.cc (region_model_manager::maybe_fold_binop): Fold
+ 	X + (-X) to zero.
+ 
  2025-12-12  David Malcolm  <dmalcolm@redhat.com>
  
  	* analyzer.opt.urls: Regenerate.
diff -Nrcpad gcc-16-20251214/gcc/analyzer/checker-event.cc gcc-16-20251221/gcc/analyzer/checker-event.cc
*** gcc-16-20251214/gcc/analyzer/checker-event.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/analyzer/checker-event.cc	Sun Dec 21 22:32:06 2025
*************** return_event::is_return_p () const
*** 847,852 ****
--- 847,858 ----
    return true;
  }
  
+ const program_state *
+ return_event::get_program_state () const
+ {
+   return &m_eedge.m_dest->get_state ();
+ }
+ 
  /* class start_consolidated_cfg_edges_event : public checker_event.  */
  
  void
diff -Nrcpad gcc-16-20251214/gcc/analyzer/checker-event.h gcc-16-20251221/gcc/analyzer/checker-event.h
*** gcc-16-20251214/gcc/analyzer/checker-event.h	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/analyzer/checker-event.h	Sun Dec 21 22:32:06 2025
*************** public:
*** 603,608 ****
--- 603,611 ----
      return m_call_and_return_op;
    }
  
+   const program_state *
+   get_program_state () const override;
+ 
    /* Mark this edge event as being either an interprocedural call or
       return in which VAR is in STATE, and that this is critical to the
       diagnostic (so that print_desc can attempt to get a better description
diff -Nrcpad gcc-16-20251214/gcc/analyzer/engine.cc gcc-16-20251221/gcc/analyzer/engine.cc
*** gcc-16-20251214/gcc/analyzer/engine.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/analyzer/engine.cc	Sun Dec 21 22:32:06 2025
*************** strongly_connected_components (const sup
*** 2228,2234 ****
    LOG_SCOPE (logger);
    auto_timevar tv (TV_ANALYZER_SCC);
  
!   for (int i = 0; i < m_sg.m_nodes.length (); i++)
      m_per_node.quick_push (per_node_data ());
  
    for (auto snode : m_sg.m_nodes)
--- 2228,2234 ----
    LOG_SCOPE (logger);
    auto_timevar tv (TV_ANALYZER_SCC);
  
!   for (size_t i = 0; i < m_sg.m_nodes.length (); i++)
      m_per_node.quick_push (per_node_data ());
  
    for (auto snode : m_sg.m_nodes)
*************** strongly_connected_components::dump () c
*** 2255,2264 ****
        fprintf (stderr, "%i", i);
      }
    fprintf (stderr, "]\n");
!   for (int i = 0; i < m_sg.m_nodes.length (); i++)
      {
        const per_node_data &v = m_per_node[i];
!       fprintf (stderr, "SN %i: index: %i lowlink: %i on_stack: %i\n",
  	       i, v.m_id, v.m_lowlink, v.m_on_stack);
      }
  }
--- 2255,2264 ----
        fprintf (stderr, "%i", i);
      }
    fprintf (stderr, "]\n");
!   for (size_t i = 0; i < m_sg.m_nodes.length (); i++)
      {
        const per_node_data &v = m_per_node[i];
!       fprintf (stderr, "SN %lu: index: %i lowlink: %i on_stack: %i\n",
  	       i, v.m_id, v.m_lowlink, v.m_on_stack);
      }
  }
*************** std::unique_ptr<json::array>
*** 2269,2275 ****
  strongly_connected_components::to_json () const
  {
    auto scc_arr = std::make_unique<json::array> ();
!   for (int i = 0; i < m_sg.m_nodes.length (); i++)
      scc_arr->append (std::make_unique<json::integer_number> (get_scc_id (i)));
    return scc_arr;
  }
--- 2269,2275 ----
  strongly_connected_components::to_json () const
  {
    auto scc_arr = std::make_unique<json::array> ();
!   for (size_t i = 0; i < m_sg.m_nodes.length (); i++)
      scc_arr->append (std::make_unique<json::integer_number> (get_scc_id (i)));
    return scc_arr;
  }
*************** exploded_graph::print_bar_charts (pretty
*** 3831,3837 ****
  
    /* Accumulate number of enodes per supernode.  */
    auto_vec<unsigned> enodes_per_supernode (m_sg.m_nodes.length ());
!   for (int i = 0; i < m_sg.m_nodes.length (); i++)
      enodes_per_supernode.quick_push (0);
    int i;
    exploded_node *enode;
--- 3831,3837 ----
  
    /* Accumulate number of enodes per supernode.  */
    auto_vec<unsigned> enodes_per_supernode (m_sg.m_nodes.length ());
!   for (size_t i = 0; i < m_sg.m_nodes.length (); i++)
      enodes_per_supernode.quick_push (0);
    int i;
    exploded_node *enode;
*************** exploded_graph::print_bar_charts (pretty
*** 3845,3851 ****
  
    /* Accumulate excess enodes per supernode.  */
    auto_vec<unsigned> excess_enodes_per_supernode (m_sg.m_nodes.length ());
!   for (int i = 0; i < m_sg.m_nodes.length (); i++)
      excess_enodes_per_supernode.quick_push (0);
    for (point_map_t::iterator iter = m_per_point_data.begin ();
         iter != m_per_point_data.end (); ++iter)
--- 3845,3851 ----
  
    /* Accumulate excess enodes per supernode.  */
    auto_vec<unsigned> excess_enodes_per_supernode (m_sg.m_nodes.length ());
!   for (size_t i = 0; i < m_sg.m_nodes.length (); i++)
      excess_enodes_per_supernode.quick_push (0);
    for (point_map_t::iterator iter = m_per_point_data.begin ();
         iter != m_per_point_data.end (); ++iter)
*************** exploded_graph::print_bar_charts (pretty
*** 3871,3877 ****
        bar_chart enodes_per_snode;
        bar_chart excess_enodes_per_snode;
        bool have_excess_enodes = false;
!       for (int i = 0; i < m_sg.m_nodes.length (); i++)
  	{
  	  const supernode *iter_snode = m_sg.m_nodes[i];
  	  if (iter_snode->get_function () != fn)
--- 3871,3877 ----
        bar_chart enodes_per_snode;
        bar_chart excess_enodes_per_snode;
        bool have_excess_enodes = false;
!       for (size_t i = 0; i < m_sg.m_nodes.length (); i++)
  	{
  	  const supernode *iter_snode = m_sg.m_nodes[i];
  	  if (iter_snode->get_function () != fn)
*************** exploded_path::feasible_p (logger *logge
*** 4089,4100 ****
  	{
  	  gcc_assert (rc);
  	  if (out)
! 	    {
! 	      const exploded_node &src_enode = *eedge->m_src;
! 	      const program_point &src_point = src_enode.get_point ();
! 	      *out = std::make_unique<feasibility_problem> (edge_idx, *eedge,
! 							    std::move (rc));
! 	    }
  	  return false;
  	}
  
--- 4089,4096 ----
  	{
  	  gcc_assert (rc);
  	  if (out)
! 	    *out = std::make_unique<feasibility_problem> (edge_idx, *eedge,
! 							  std::move (rc));
  	  return false;
  	}
  
*************** public:
*** 4897,4903 ****
    : m_eg (eg)
    {
      /* Avoid O(N^2) by prepopulating m_enodes_per_snode_id.  */
!     for (int i = 0; i < eg.get_supergraph ().m_nodes.length (); ++i)
        m_enodes_per_snode_id.push_back (std::vector<exploded_node *> ());
      exploded_node *enode;
      unsigned i;
--- 4893,4899 ----
    : m_eg (eg)
    {
      /* Avoid O(N^2) by prepopulating m_enodes_per_snode_id.  */
!     for (size_t i = 0; i < eg.get_supergraph ().m_nodes.length (); ++i)
        m_enodes_per_snode_id.push_back (std::vector<exploded_node *> ());
      exploded_node *enode;
      unsigned i;
*************** impl_run_checkers (logger *logger)
*** 5192,5198 ****
  
    maybe_dump_supergraph (sg, "fixup-locations");
  
!   engine eng (mgr, &sg, logger);
  
    state_purge_map *purge_map = nullptr;
    if (flag_analyzer_state_purge)
--- 5188,5194 ----
  
    maybe_dump_supergraph (sg, "fixup-locations");
  
!   engine eng (mgr, &sg);
  
    state_purge_map *purge_map = nullptr;
    if (flag_analyzer_state_purge)
diff -Nrcpad gcc-16-20251214/gcc/analyzer/ops.cc gcc-16-20251221/gcc/analyzer/ops.cc
*** gcc-16-20251214/gcc/analyzer/ops.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/analyzer/ops.cc	Sun Dec 21 22:32:06 2025
*************** phis_for_edge_op::maybe_make (::edge cfg
*** 2158,2172 ****
    if (pairs.empty ())
      return nullptr;
  
!   return std::make_unique <phis_for_edge_op> (std::move (pairs),
! 					      cfg_in_edge);
  }
  
! phis_for_edge_op::phis_for_edge_op (std::vector<pair> &&pairs,
! 				    ::edge cfg_in_edge)
  : operation (kind::phis),
!   m_pairs (std::move (pairs)),
!   m_cfg_in_edge (cfg_in_edge)
  {
  }
  
--- 2158,2169 ----
    if (pairs.empty ())
      return nullptr;
  
!   return std::make_unique <phis_for_edge_op> (std::move (pairs));
  }
  
! phis_for_edge_op::phis_for_edge_op (std::vector<pair> &&pairs)
  : operation (kind::phis),
!   m_pairs (std::move (pairs))
  {
  }
  
diff -Nrcpad gcc-16-20251214/gcc/analyzer/ops.h gcc-16-20251221/gcc/analyzer/ops.h
*** gcc-16-20251214/gcc/analyzer/ops.h	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/analyzer/ops.h	Sun Dec 21 22:32:06 2025
*************** class operation
*** 96,102 ****
      call_and_return
    };
  
!   ~operation () {}
  
    void
    dump () const;
--- 96,102 ----
      call_and_return
    };
  
!   virtual ~operation () {}
  
    void
    dump () const;
*************** public:
*** 630,636 ****
  			   std::unique_ptr<rejected_constraint> *out_rc) const override;
  
    const control_flow_op *
!   dyn_cast_control_flow_op () const { return this; }
  
    ::edge get_cfg_edge () const { return m_cfg_edge; }
    int get_flags () const { return m_cfg_edge->flags; }
--- 630,636 ----
  			   std::unique_ptr<rejected_constraint> *out_rc) const override;
  
    const control_flow_op *
!   dyn_cast_control_flow_op () const final override { return this; }
  
    ::edge get_cfg_edge () const { return m_cfg_edge; }
    int get_flags () const { return m_cfg_edge->flags; }
*************** public:
*** 947,954 ****
      return std::make_unique<phis_for_edge_op> (*this);
    }
  
!   phis_for_edge_op (std::vector<pair> &&pairs,
! 		    ::edge cfg_in_edge);
  
    const phis_for_edge_op *
    dyn_cast_phis_for_edge_op () const final override { return this; }
--- 947,953 ----
      return std::make_unique<phis_for_edge_op> (*this);
    }
  
!   phis_for_edge_op (std::vector<pair> &&pairs);
  
    const phis_for_edge_op *
    dyn_cast_phis_for_edge_op () const final override { return this; }
*************** private:
*** 999,1005 ****
  		region_model_context *ctxt) const;
  
    std::vector<pair> m_pairs;
-   ::edge m_cfg_in_edge;
  };
  
  } // namespace ana
--- 998,1003 ----
diff -Nrcpad gcc-16-20251214/gcc/analyzer/region-model-manager.cc gcc-16-20251221/gcc/analyzer/region-model-manager.cc
*** gcc-16-20251214/gcc/analyzer/region-model-manager.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/analyzer/region-model-manager.cc	Sun Dec 21 22:32:06 2025
*************** region_model_manager::maybe_fold_binop (
*** 680,685 ****
--- 680,690 ----
        /* (VAL + 0) -> VAL.  */
        if (cst1 && zerop (cst1))
  	return get_or_create_cast (type, arg0);
+       /* X + (-X) -> 0.  */
+       if (const unaryop_svalue *unary_op = arg1->dyn_cast_unaryop_svalue ())
+ 	if (unary_op->get_op () == NEGATE_EXPR
+ 	    && unary_op->get_arg () == arg0)
+ 	  return get_or_create_int_cst (type, 0);
        break;
      case MINUS_EXPR:
        /* (VAL - 0) -> VAL.  */
diff -Nrcpad gcc-16-20251214/gcc/analyzer/region-model.cc gcc-16-20251221/gcc/analyzer/region-model.cc
*** gcc-16-20251214/gcc/analyzer/region-model.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/analyzer/region-model.cc	Sun Dec 21 22:32:06 2025
*************** region_model::scan_for_null_terminator_1
*** 4684,4707 ****
    if (const string_region *str_reg = base_reg->dyn_cast_string_region ())
      {
        tree string_cst = str_reg->get_string_cst ();
!       if (const void *p = memchr (TREE_STRING_POINTER (string_cst),
! 				  0,
! 				  TREE_STRING_LENGTH (string_cst)))
  	{
! 	  size_t num_bytes_read
! 	    = (const char *)p - TREE_STRING_POINTER (string_cst) + 1;
! 	  /* Simulate the read.  */
! 	  byte_range bytes_to_read (0, num_bytes_read);
! 	  const svalue *sval = get_store_bytes (reg, bytes_to_read, ctxt);
! 	  if (out_sval)
! 	    *out_sval = sval;
! 	  if (logger)
! 	    logger->log ("using string_cst");
! 	  return m_mgr->get_or_create_int_cst (size_type_node,
! 					       num_bytes_read);
  	}
      }
- 
    const binding_cluster *cluster = m_store.get_cluster (base_reg);
    iterable_cluster c (cluster);
    if (logger)
--- 4684,4714 ----
    if (const string_region *str_reg = base_reg->dyn_cast_string_region ())
      {
        tree string_cst = str_reg->get_string_cst ();
!       if (src_byte_offset >= 0
! 	  && src_byte_offset < TREE_STRING_LENGTH (string_cst)
! 	  && wi::fits_shwi_p (src_byte_offset))
  	{
! 	  HOST_WIDE_INT str_byte_offset = src_byte_offset.to_shwi ();
! 	  const char *effective_start
! 	    = TREE_STRING_POINTER (string_cst) + str_byte_offset;
! 	  size_t effective_len
! 	    = TREE_STRING_LENGTH (string_cst) - str_byte_offset;
! 	  if (const void *p = memchr (effective_start, 0, effective_len))
! 	    {
! 	      size_t num_bytes_read
! 		= (const char *)p - effective_start + 1;
! 	      /* Simulate the read.  */
! 	      byte_range bytes_to_read (0, num_bytes_read);
! 	      const svalue *sval = get_store_bytes (reg, bytes_to_read, ctxt);
! 	      if (out_sval)
! 		*out_sval = sval;
! 	      if (logger)
! 		logger->log ("using string_cst");
! 	      return m_mgr->get_or_create_int_cst (size_type_node,
! 						   num_bytes_read);
! 	    }
  	}
      }
    const binding_cluster *cluster = m_store.get_cluster (base_reg);
    iterable_cluster c (cluster);
    if (logger)
*************** rejected_ranges_constraint::dump_to_pp (
*** 7594,7601 ****
  /* engine's ctor.  */
  
  engine::engine (region_model_manager &mgr,
! 		const supergraph *sg,
! 		logger *logger)
  : m_mgr (mgr),
    m_sg (sg)
  {
--- 7601,7607 ----
  /* engine's ctor.  */
  
  engine::engine (region_model_manager &mgr,
! 		const supergraph *sg)
  : m_mgr (mgr),
    m_sg (sg)
  {
diff -Nrcpad gcc-16-20251214/gcc/analyzer/region-model.h gcc-16-20251221/gcc/analyzer/region-model.h
*** gcc-16-20251214/gcc/analyzer/region-model.h	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/analyzer/region-model.h	Sun Dec 21 22:32:06 2025
*************** class engine
*** 1334,1341 ****
  {
  public:
    engine (region_model_manager &mgr,
! 	  const supergraph *sg = nullptr,
! 	  logger *logger = nullptr);
    const supergraph *get_supergraph () { return m_sg; }
    region_model_manager *get_model_manager () { return &m_mgr; }
    known_function_manager *get_known_function_manager ()
--- 1334,1340 ----
  {
  public:
    engine (region_model_manager &mgr,
! 	  const supergraph *sg = nullptr);
    const supergraph *get_supergraph () { return m_sg; }
    region_model_manager *get_model_manager () { return &m_mgr; }
    known_function_manager *get_known_function_manager ()
diff -Nrcpad gcc-16-20251214/gcc/analyzer/supergraph-fixup-locations.cc gcc-16-20251221/gcc/analyzer/supergraph-fixup-locations.cc
*** gcc-16-20251214/gcc/analyzer/supergraph-fixup-locations.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/analyzer/supergraph-fixup-locations.cc	Sun Dec 21 22:32:06 2025
*************** class location_fixer
*** 36,43 ****
  public:
    location_fixer (supergraph &sg,
  		  ana::logger *logger)
!   : m_sg (sg),
!     m_logger (logger),
      m_stats ()
    {
      for (auto node : sg.m_nodes)
--- 36,42 ----
  public:
    location_fixer (supergraph &sg,
  		  ana::logger *logger)
!   : m_logger (logger),
      m_stats ()
    {
      for (auto node : sg.m_nodes)
*************** public:
*** 84,91 ****
    }
  
  private:
-   supergraph &m_sg;
-   state_purge_map *m_purge_map;
    supergraph_manipulation::worklist m_worklist;
    ana::logger *m_logger;
    struct stats
--- 83,88 ----
diff -Nrcpad gcc-16-20251214/gcc/analyzer/supergraph-sorting.cc gcc-16-20251221/gcc/analyzer/supergraph-sorting.cc
*** gcc-16-20251214/gcc/analyzer/supergraph-sorting.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/analyzer/supergraph-sorting.cc	Sun Dec 21 22:32:06 2025
*************** class sorting_worklist
*** 76,82 ****
  {
  public:
    sorting_worklist ()
!   : m_queue (key_t (*this, nullptr))
    {
    }
  
--- 76,82 ----
  {
  public:
    sorting_worklist ()
!   : m_queue (key_t (nullptr))
    {
    }
  
*************** private:
*** 88,95 ****
    class key_t
    {
    public:
!     key_t (const sorting_worklist &w, supernode *snode)
!     : m_worklist (w), m_snode (snode)
      {}
  
      bool operator< (const key_t &other) const
--- 88,95 ----
    class key_t
    {
    public:
!     key_t (supernode *snode)
!     : m_snode (snode)
      {}
  
      bool operator< (const key_t &other) const
*************** private:
*** 109,115 ****
  
    private:
      static int cmp (const key_t &ka, const key_t &kb);
-     const sorting_worklist &m_worklist;
      supernode *m_snode;
    };
  
--- 109,114 ----
*************** private:
*** 126,132 ****
  void
  sorting_worklist::add_node (supernode *n)
  {
!   m_queue.insert ({*this, n}, n);
    m_set_of_queued_nodes.insert (n);
  }
  
--- 125,131 ----
  void
  sorting_worklist::add_node (supernode *n)
  {
!   m_queue.insert ({n}, n);
    m_set_of_queued_nodes.insert (n);
  }
  
diff -Nrcpad gcc-16-20251214/gcc/analyzer/supergraph.cc gcc-16-20251221/gcc/analyzer/supergraph.cc
*** gcc-16-20251214/gcc/analyzer/supergraph.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/analyzer/supergraph.cc	Sun Dec 21 22:32:06 2025
*************** supernode::dump_dot (graphviz_out *gv, c
*** 847,854 ****
  
  	  if ((exploc.file != prev_exploc.file)
  	      && exploc.file)
! 	    pp_printf (pp, "<TR><TD>%s:%i:</TD></TR>",
! 		       exploc.file, exploc.line);
  	  if (exploc.line != prev_exploc.line)
  	    if (const diagnostics::char_span line
  		= global_dc->get_file_cache ().get_source_line (exploc.file,
--- 847,860 ----
  
  	  if ((exploc.file != prev_exploc.file)
  	      && exploc.file)
! 	    {
! 	      pp_string (pp, "<TR><TD>");
! 	      pp_flush (pp);
! 	      pp_printf (pp, "%s", exploc.file);
! 	      /* Escape, to handle cases like "<built-in>".  */
! 	      pp_write_text_as_html_like_dot_to_stream (pp);
! 	      pp_printf (pp, ":%i:</TD></TR>", exploc.line);
! 	    }
  	  if (exploc.line != prev_exploc.line)
  	    if (const diagnostics::char_span line
  		= global_dc->get_file_cache ().get_source_line (exploc.file,
diff -Nrcpad gcc-16-20251214/gcc/asan.cc gcc-16-20251221/gcc/asan.cc
*** gcc-16-20251214/gcc/asan.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/asan.cc	Sun Dec 21 22:32:06 2025
*************** static void
*** 762,775 ****
  handle_builtin_stack_restore (gcall *call, gimple_stmt_iterator *iter)
  {
    if (!iter
!       || !(asan_sanitize_allocas_p () || hwasan_sanitize_allocas_p ()))
      return;
  
    tree restored_stack = gimple_call_arg (call, 0);
  
    gimple *g;
  
!   if (hwasan_sanitize_allocas_p ())
      {
        enum internal_fn fn = IFN_HWASAN_ALLOCA_UNPOISON;
        /* There is only one piece of information `expand_HWASAN_ALLOCA_UNPOISON`
--- 762,776 ----
  handle_builtin_stack_restore (gcall *call, gimple_stmt_iterator *iter)
  {
    if (!iter
!       || !(asan_sanitize_allocas_p () || hwasan_sanitize_allocas_p ()
! 	   || memtag_sanitize_allocas_p ()))
      return;
  
    tree restored_stack = gimple_call_arg (call, 0);
  
    gimple *g;
  
!   if (hwasan_sanitize_allocas_p () || memtag_sanitize_allocas_p ())
      {
        enum internal_fn fn = IFN_HWASAN_ALLOCA_UNPOISON;
        /* There is only one piece of information `expand_HWASAN_ALLOCA_UNPOISON`
*************** static void
*** 818,824 ****
  handle_builtin_alloca (gcall *call, gimple_stmt_iterator *iter)
  {
    if (!iter
!       || !(asan_sanitize_allocas_p () || hwasan_sanitize_allocas_p ()))
      return;
  
    gassign *g;
--- 819,826 ----
  handle_builtin_alloca (gcall *call, gimple_stmt_iterator *iter)
  {
    if (!iter
!       || !(asan_sanitize_allocas_p () || hwasan_sanitize_allocas_p ()
! 	   || memtag_sanitize_allocas_p ()))
      return;
  
    gassign *g;
*************** handle_builtin_alloca (gcall *call, gimp
*** 842,864 ****
        e = find_fallthru_edge (gsi_bb (*iter)->succs);
      }
  
!   if (hwasan_sanitize_allocas_p ())
      {
        gimple_seq stmts = NULL;
        location_t loc = gimple_location (gsi_stmt (*iter));
!       /*
! 	 HWASAN needs a different expansion.
  
  	 addr = __builtin_alloca (size, align);
  
! 	 should be replaced by
  
  	 new_size = size rounded up to HWASAN_TAG_GRANULE_SIZE byte alignment;
  	 untagged_addr = __builtin_alloca (new_size, align);
  	 tag = __hwasan_choose_alloca_tag ();
  	 addr = ifn_HWASAN_SET_TAG (untagged_addr, tag);
  	 __hwasan_tag_memory (untagged_addr, tag, new_size);
! 	*/
        /* Ensure alignment at least HWASAN_TAG_GRANULE_SIZE bytes so we start on
  	 a tag granule.  */
        align = align > HWASAN_TAG_GRANULE_SIZE ? align : HWASAN_TAG_GRANULE_SIZE;
--- 844,874 ----
        e = find_fallthru_edge (gsi_bb (*iter)->succs);
      }
  
!   if (hwasan_sanitize_allocas_p () || memtag_sanitize_allocas_p ())
      {
        gimple_seq stmts = NULL;
        location_t loc = gimple_location (gsi_stmt (*iter));
!       /* HWASAN and MEMTAG need a different expansion.
  
  	 addr = __builtin_alloca (size, align);
  
! 	 in case of HWASAN, should be replaced by
  
  	 new_size = size rounded up to HWASAN_TAG_GRANULE_SIZE byte alignment;
  	 untagged_addr = __builtin_alloca (new_size, align);
  	 tag = __hwasan_choose_alloca_tag ();
  	 addr = ifn_HWASAN_SET_TAG (untagged_addr, tag);
  	 __hwasan_tag_memory (untagged_addr, tag, new_size);
! 
! 	 in case of MEMTAG, should be replaced by
! 
! 	 new_size = size rounded up to HWASAN_TAG_GRANULE_SIZE byte alignment;
! 	 untagged_addr = __builtin_alloca (new_size, align);
! 	 addr = ifn_HWASAN_ALLOCA_POISON (untagged_addr, new_size);
! 
! 	 where a new tag is chosen and set on untagged_addr when
! 	 HWASAN_ALLOCA_POISON is expanded.  */
! 
        /* Ensure alignment at least HWASAN_TAG_GRANULE_SIZE bytes so we start on
  	 a tag granule.  */
        align = align > HWASAN_TAG_GRANULE_SIZE ? align : HWASAN_TAG_GRANULE_SIZE;
*************** handle_builtin_alloca (gcall *call, gimp
*** 874,896 ****
  			as_combined_fn (BUILT_IN_ALLOCA_WITH_ALIGN), ptr_type,
  			new_size, build_int_cst (size_type_node, align));
  
!       /* Choose the tag.
! 	 Here we use an internal function so we can choose the tag at expand
! 	 time.  We need the decision to be made after stack variables have been
! 	 assigned their tag (i.e. once the hwasan_frame_tag_offset variable has
! 	 been set to one after the last stack variables tag).  */
!       tree tag = gimple_build (&stmts, loc, CFN_HWASAN_CHOOSE_TAG,
! 			       unsigned_char_type_node);
  
!       /* Add tag to pointer.  */
!       tree addr
! 	= gimple_build (&stmts, loc, CFN_HWASAN_SET_TAG, ptr_type,
! 			untagged_addr, tag);
  
!       /* Tag shadow memory.
! 	 NOTE: require using `untagged_addr` here for libhwasan API.  */
!       gimple_build (&stmts, loc, as_combined_fn (BUILT_IN_HWASAN_TAG_MEM),
! 		    void_type_node, untagged_addr, tag, new_size);
  
        /* Insert the built up code sequence into the original instruction stream
  	 the iterator points to.  */
--- 884,913 ----
  			as_combined_fn (BUILT_IN_ALLOCA_WITH_ALIGN), ptr_type,
  			new_size, build_int_cst (size_type_node, align));
  
!       tree addr;
  
!       if (memtag_sanitize_p ())
! 	addr = gimple_build (&stmts, loc, CFN_HWASAN_ALLOCA_POISON, ptr_type,
! 			     untagged_addr, new_size);
!       else
! 	{
! 	  /* Choose the tag.
! 	     Here we use an internal function so we can choose the tag at expand
! 	     time.  We need the decision to be made after stack variables have been
! 	     assigned their tag (i.e. once the hwasan_frame_tag_offset variable has
! 	     been set to one after the last stack variables tag).  */
! 	  tree tag = gimple_build (&stmts, loc, CFN_HWASAN_CHOOSE_TAG,
! 				   unsigned_char_type_node);
  
! 	  /* Add tag to pointer.  */
! 	  addr = gimple_build (&stmts, loc, CFN_HWASAN_SET_TAG, ptr_type,
! 			       untagged_addr, tag);
! 
! 	  /* Tag shadow memory.
! 	     NOTE: require using `untagged_addr` here for libhwasan API.  */
! 	  gimple_build (&stmts, loc, as_combined_fn (BUILT_IN_HWASAN_TAG_MEM),
! 			void_type_node, untagged_addr, tag, new_size);
! 	}
  
        /* Insert the built up code sequence into the original instruction stream
  	 the iterator points to.  */
*************** get_mem_refs_of_builtin_call (gcall *cal
*** 1104,1110 ****
  	 for now we choose to just ignore `strlen` calls.
  	 This decision was simply made because that means the special case is
  	 limited to this one case of this one function.  */
!       if (hwasan_sanitize_p ())
  	return false;
        source0 = gimple_call_arg (call, 0);
        len = gimple_call_lhs (call);
--- 1121,1127 ----
  	 for now we choose to just ignore `strlen` calls.
  	 This decision was simply made because that means the special case is
  	 limited to this one case of this one function.  */
!       if (hwassist_sanitize_p ())
  	return false;
        source0 = gimple_call_arg (call, 0);
        len = gimple_call_lhs (call);
*************** hwasan_memintrin (void)
*** 1886,1891 ****
--- 1903,1985 ----
    return (hwasan_sanitize_p () && param_hwasan_instrument_mem_intrinsics);
  }
  
+ /* MEMoryTAGging sanitizer (MEMTAG) uses a hardware based capability known as
+    memory tagging to detect memory safety vulnerabilities.  Similar to HWASAN,
+    it is also a probabilistic method.
+ 
+    MEMTAG relies on the optional extension in armv8.5a known as MTE (Memory
+    Tagging Extension).  The extension is available in AArch64 only and
+    introduces two types of tags:
+      - Logical Address Tag - bits 56-59 (TARGET_MEMTAG_TAG_BITSIZE) of the
+        virtual address.
+      - Allocation Tag - 4 bits for each tag granule (TARGET_MEMTAG_GRANULE_SIZE
+        set to 16 bytes), stored separately.
+    Load / store instructions raise an exception if tags differ, thereby
+    providing a faster way (than HWASAN) to detect memory safety issues.
+    Further, new instructions are available in MTE to manipulate (generate,
+    update address with) tags.  Load / store instructions with SP base register
+    and immediate offset do not check tags.
+ 
+    PS: Currently, MEMTAG sanitizer is capable of stack (variable / memory)
+    tagging only.
+ 
+    In general, detecting stack-related memory bugs requires the compiler to:
+      - ensure that each tag granule is only used by one variable at a time.
+        This includes alloca.
+      - Tag/Color: put tags into each stack variable pointer.
+      - Untag: the function epilogue will retag the memory.
+ 
+    MEMTAG sanitizer is based off the HWASAN sanitizer implementation
+    internally.  Similar to HWASAN:
+      - Assigning an independently random tag to each variable is carried out by
+        keeping a tagged base pointer.  A tagged base pointer allows addressing
+        variables with (addr offset, tag offset).
+    */
+ 
+ /* Returns whether we are tagging pointers and checking those tags on memory
+    access.  */
+ bool
+ memtag_sanitize_p ()
+ {
+   return sanitize_flags_p (SANITIZE_MEMTAG);
+ }
+ 
+ /* Are we tagging the stack?  */
+ bool
+ memtag_sanitize_stack_p ()
+ {
+   return (sanitize_flags_p (SANITIZE_MEMTAG_STACK));
+ }
+ 
+ /* Are we tagging alloca objects?  */
+ bool
+ memtag_sanitize_allocas_p (void)
+ {
+   return (memtag_sanitize_stack_p () && param_memtag_instrument_allocas);
+ }
+ 
+ /* Are we taggin mem intrinsics?  */
+ bool
+ memtag_memintrin (void)
+ {
+   return (memtag_sanitize_p () && param_memtag_instrument_mem_intrinsics);
+ }
+ 
+ /* Returns whether we are tagging pointers and checking those tags on memory
+    access.  */
+ bool
+ hwassist_sanitize_p ()
+ {
+   return (hwasan_sanitize_p () || memtag_sanitize_p ());
+ }
+ 
+ /* Are we tagging stack objects for hwasan or memtag?  */
+ bool
+ hwassist_sanitize_stack_p ()
+ {
+   return (hwasan_sanitize_stack_p () || memtag_sanitize_stack_p ());
+ }
+ 
  /* Insert code to protect stack vars.  The prologue sequence should be emitted
     directly, epilogue sequence returned.  BASE is the register holding the
     stack base, against which OFFSETS array offsets are relative to, OFFSETS
*************** static tree
*** 2416,2422 ****
  report_error_func (bool is_store, bool recover_p, HOST_WIDE_INT size_in_bytes,
  		   int *nargs)
  {
!   gcc_assert (!hwasan_sanitize_p ());
  
    static enum built_in_function report[2][2][6]
      = { { { BUILT_IN_ASAN_REPORT_LOAD1, BUILT_IN_ASAN_REPORT_LOAD2,
--- 2510,2516 ----
  report_error_func (bool is_store, bool recover_p, HOST_WIDE_INT size_in_bytes,
  		   int *nargs)
  {
!   gcc_assert (!hwassist_sanitize_p ());
  
    static enum built_in_function report[2][2][6]
      = { { { BUILT_IN_ASAN_REPORT_LOAD1, BUILT_IN_ASAN_REPORT_LOAD2,
*************** build_check_stmt (location_t loc, tree b
*** 2755,2761 ****
    if (is_scalar_access)
      flags |= ASAN_CHECK_SCALAR_ACCESS;
  
!   enum internal_fn fn = hwasan_sanitize_p ()
      ? IFN_HWASAN_CHECK
      : IFN_ASAN_CHECK;
  
--- 2849,2855 ----
    if (is_scalar_access)
      flags |= ASAN_CHECK_SCALAR_ACCESS;
  
!   enum internal_fn fn = hwassist_sanitize_p ()
      ? IFN_HWASAN_CHECK
      : IFN_ASAN_CHECK;
  
*************** instrument_derefs (gimple_stmt_iterator
*** 2855,2861 ****
  	 access is inside a global variable, then there's no point adding
  	 instrumentation to check the access.  N.b. hwasan currently never
  	 sanitizes globals.  */
!       if ((hwasan_sanitize_p () || !param_asan_globals)
  	  && is_global_var (inner))
          return;
        if (!TREE_STATIC (inner))
--- 2949,2955 ----
  	 access is inside a global variable, then there's no point adding
  	 instrumentation to check the access.  N.b. hwasan currently never
  	 sanitizes globals.  */
!       if ((hwassist_sanitize_p () || !param_asan_globals)
  	  && is_global_var (inner))
          return;
        if (!TREE_STATIC (inner))
*************** instrument_mem_region_access (tree base,
*** 2954,2960 ****
  static bool
  instrument_builtin_call (gimple_stmt_iterator *iter)
  {
!   if (!(asan_memintrin () || hwasan_memintrin ()))
      return false;
  
    bool iter_advanced_p = false;
--- 3048,3055 ----
  static bool
  instrument_builtin_call (gimple_stmt_iterator *iter)
  {
!   if (!(asan_memintrin () || hwasan_memintrin ()
! 	|| memtag_memintrin ()))
      return false;
  
    bool iter_advanced_p = false;
*************** maybe_instrument_call (gimple_stmt_itera
*** 3108,3114 ****
  	 `longjmp`, thread exit, and exceptions in a different way.  These
  	 problems must be handled externally to the compiler, e.g. in the
  	 language runtime.  */
!       if (! hwasan_sanitize_p ())
  	{
  	  tree decl = builtin_decl_implicit (BUILT_IN_ASAN_HANDLE_NO_RETURN);
  	  gimple *g = gimple_build_call (decl, 0);
--- 3203,3209 ----
  	 `longjmp`, thread exit, and exceptions in a different way.  These
  	 problems must be handled externally to the compiler, e.g. in the
  	 language runtime.  */
!       if (! hwassist_sanitize_p ())
  	{
  	  tree decl = builtin_decl_implicit (BUILT_IN_ASAN_HANDLE_NO_RETURN);
  	  gimple *g = gimple_build_call (decl, 0);
*************** asan_expand_mark_ifn (gimple_stmt_iterat
*** 3861,3867 ****
  
    gcc_checking_assert (TREE_CODE (decl) == VAR_DECL);
  
!   if (hwasan_sanitize_p ())
      {
        gcc_assert (param_hwasan_instrument_stack);
        gimple_seq stmts = NULL;
--- 3956,3962 ----
  
    gcc_checking_assert (TREE_CODE (decl) == VAR_DECL);
  
!   if (hwassist_sanitize_p ())
      {
        gcc_assert (param_hwasan_instrument_stack);
        gimple_seq stmts = NULL;
*************** asan_expand_mark_ifn (gimple_stmt_iterat
*** 3959,3965 ****
  bool
  asan_expand_check_ifn (gimple_stmt_iterator *iter, bool use_calls)
  {
!   gcc_assert (!hwasan_sanitize_p ());
    gimple *g = gsi_stmt (*iter);
    location_t loc = gimple_location (g);
    bool recover_p;
--- 4054,4060 ----
  bool
  asan_expand_check_ifn (gimple_stmt_iterator *iter, bool use_calls)
  {
!   gcc_assert (!hwassist_sanitize_p ());
    gimple *g = gsi_stmt (*iter);
    location_t loc = gimple_location (g);
    bool recover_p;
*************** asan_expand_poison_ifn (gimple_stmt_iter
*** 4234,4240 ****
        int nargs;
        bool store_p = gimple_call_internal_p (use, IFN_ASAN_POISON_USE);
        gcall *call;
!       if (hwasan_sanitize_p ())
  	{
  	  tree fun = builtin_decl_implicit (BUILT_IN_HWASAN_TAG_MISMATCH4);
  	  /* NOTE: hwasan has no __hwasan_report_* functions like asan does.
--- 4329,4335 ----
        int nargs;
        bool store_p = gimple_call_internal_p (use, IFN_ASAN_POISON_USE);
        gcall *call;
!       if (hwassist_sanitize_p ())
  	{
  	  tree fun = builtin_decl_implicit (BUILT_IN_HWASAN_TAG_MISMATCH4);
  	  /* NOTE: hwasan has no __hwasan_report_* functions like asan does.
*************** asan_expand_poison_ifn (gimple_stmt_iter
*** 4335,4341 ****
  static unsigned int
  asan_instrument (void)
  {
!   if (hwasan_sanitize_p ())
      {
        initialize_sanitizer_builtins ();
        transform_statements ();
--- 4430,4436 ----
  static unsigned int
  asan_instrument (void)
  {
!   if (hwassist_sanitize_p ())
      {
        initialize_sanitizer_builtins ();
        transform_statements ();
*************** public:
*** 4381,4387 ****
    opt_pass * clone () final override { return new pass_asan (m_ctxt); }
    bool gate (function *) final override
    {
!     return gate_asan () || gate_hwasan ();
    }
    unsigned int execute (function *) final override
    {
--- 4476,4482 ----
    opt_pass * clone () final override { return new pass_asan (m_ctxt); }
    bool gate (function *) final override
    {
!     return gate_asan () || gate_hwasan () || gate_memtag ();
    }
    unsigned int execute (function *) final override
    {
*************** public:
*** 4423,4429 ****
    /* opt_pass methods: */
    bool gate (function *) final override
      {
!       return !optimize && (gate_asan () || gate_hwasan ());
      }
    unsigned int execute (function *) final override
    {
--- 4518,4524 ----
    /* opt_pass methods: */
    bool gate (function *) final override
      {
!       return !optimize && (gate_asan () || gate_hwasan () || gate_memtag ());
      }
    unsigned int execute (function *) final override
    {
*************** hwasan_emit_prologue ()
*** 4676,4694 ****
        gcc_assert (multiple_p (bot, HWASAN_TAG_GRANULE_SIZE));
        gcc_assert (multiple_p (size, HWASAN_TAG_GRANULE_SIZE));
  
-       rtx fn = init_one_libfunc ("__hwasan_tag_memory");
        rtx base_tag = targetm.memtag.extract_tag (cur.tagged_base, NULL_RTX);
-       rtx tag = plus_constant (QImode, base_tag, cur.tag_offset);
-       tag = hwasan_truncate_to_tag_size (tag, NULL_RTX);
  
        rtx bottom = convert_memory_address (ptr_mode,
  					   plus_constant (Pmode,
  							  cur.untagged_base,
  							  bot));
!       emit_library_call (fn, LCT_NORMAL, VOIDmode,
! 			 bottom, ptr_mode,
! 			 tag, QImode,
! 			 gen_int_mode (size, ptr_mode), ptr_mode);
      }
    /* Clear the stack vars, we've emitted the prologue for them all now.  */
    hwasan_tagged_stack_vars.truncate (0);
--- 4771,4811 ----
        gcc_assert (multiple_p (bot, HWASAN_TAG_GRANULE_SIZE));
        gcc_assert (multiple_p (size, HWASAN_TAG_GRANULE_SIZE));
  
        rtx base_tag = targetm.memtag.extract_tag (cur.tagged_base, NULL_RTX);
  
        rtx bottom = convert_memory_address (ptr_mode,
  					   plus_constant (Pmode,
  							  cur.untagged_base,
  							  bot));
!       if (memtag_sanitize_p ())
! 	{
! 	  expand_operand ops[3];
! 	  rtx tagged_addr = gen_reg_rtx (ptr_mode);
! 
! 	  /* Check if the required target instructions are present.  */
! 	  gcc_assert (targetm.have_compose_tag ());
! 	  gcc_assert (targetm.have_tag_memory ());
! 
! 	  /* The AArch64 has addg/subg instructions which are working directly
! 	     on a tagged pointer.  */
! 	  create_output_operand (&ops[0], tagged_addr, ptr_mode);
! 	  create_input_operand (&ops[1], base_tag, ptr_mode);
! 	  create_integer_operand (&ops[2], cur.tag_offset);
! 	  expand_insn (targetm.code_for_compose_tag, 3, ops);
! 
! 	  emit_insn (targetm.gen_tag_memory (bottom, tagged_addr,
! 					     gen_int_mode (size, ptr_mode)));
! 	}
!       else
! 	{
! 	  rtx fn = init_one_libfunc ("__hwasan_tag_memory");
! 	  rtx tag = plus_constant (QImode, base_tag, cur.tag_offset);
! 	  tag = hwasan_truncate_to_tag_size (tag, NULL_RTX);
! 	  emit_library_call (fn, LCT_NORMAL, VOIDmode,
! 			     bottom, ptr_mode,
! 			     tag, QImode,
! 			     gen_int_mode (size, ptr_mode), ptr_mode);
! 	}
      }
    /* Clear the stack vars, we've emitted the prologue for them all now.  */
    hwasan_tagged_stack_vars.truncate (0);
*************** hwasan_emit_untag_frame (rtx dynamic, rt
*** 4725,4739 ****
        bot_rtx = vars;
      }
  
!   rtx size_rtx = expand_simple_binop (ptr_mode, MINUS, top_rtx, bot_rtx,
! 				      NULL_RTX, /* unsignedp = */0,
! 				      OPTAB_DIRECT);
  
!   rtx fn = init_one_libfunc ("__hwasan_tag_memory");
!   emit_library_call (fn, LCT_NORMAL, VOIDmode,
! 		     bot_rtx, ptr_mode,
! 		     HWASAN_STACK_BACKGROUND, QImode,
! 		     size_rtx, ptr_mode);
  
    do_pending_stack_adjust ();
    return end_sequence ();
--- 4842,4862 ----
        bot_rtx = vars;
      }
  
!   rtx size_rtx = simplify_gen_binary (MINUS, ptr_mode, top_rtx, bot_rtx);
!   if (!CONST_INT_P (size_rtx))
!     size_rtx = force_reg (ptr_mode, size_rtx);
  
!   if (memtag_sanitize_p ())
!     emit_insn (targetm.gen_tag_memory (bot_rtx, HWASAN_STACK_BACKGROUND,
! 				       size_rtx));
!   else
!     {
!       rtx fn = init_one_libfunc ("__hwasan_tag_memory");
!       emit_library_call (fn, LCT_NORMAL, VOIDmode,
! 			 bot_rtx, ptr_mode,
! 			 HWASAN_STACK_BACKGROUND, QImode,
! 			 size_rtx, ptr_mode);
!     }
  
    do_pending_stack_adjust ();
    return end_sequence ();
*************** gate_hwasan ()
*** 4919,4922 ****
--- 5042,5051 ----
    return hwasan_sanitize_p ();
  }
  
+ bool
+ gate_memtag ()
+ {
+   return memtag_sanitize_p ();
+ }
+ 
  #include "gt-asan.h"
diff -Nrcpad gcc-16-20251214/gcc/asan.h gcc-16-20251221/gcc/asan.h
*** gcc-16-20251214/gcc/asan.h	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/asan.h	Sun Dec 21 22:32:06 2025
*************** extern bool hwasan_expand_check_ifn (gim
*** 57,62 ****
--- 57,70 ----
  extern bool hwasan_expand_mark_ifn (gimple_stmt_iterator *);
  extern bool gate_hwasan (void);
  
+ extern bool memtag_sanitize_p (void);
+ extern bool memtag_sanitize_stack_p (void);
+ extern bool memtag_sanitize_allocas_p (void);
+ extern bool gate_memtag (void);
+ 
+ bool hwassist_sanitize_p (void);
+ bool hwassist_sanitize_stack_p (void);
+ 
  extern gimple_stmt_iterator create_cond_insert_point
       (gimple_stmt_iterator *, bool, bool, bool, basic_block *, basic_block *);
  
*************** inline bool
*** 225,231 ****
  asan_sanitize_use_after_scope (void)
  {
    return (flag_sanitize_address_use_after_scope
! 	  && (asan_sanitize_stack_p () || hwasan_sanitize_stack_p ()));
  }
  
  /* Return true if DECL should be guarded on the stack.  */
--- 233,239 ----
  asan_sanitize_use_after_scope (void)
  {
    return (flag_sanitize_address_use_after_scope
! 	  && (asan_sanitize_stack_p () || hwassist_sanitize_stack_p ()));
  }
  
  /* Return true if DECL should be guarded on the stack.  */
diff -Nrcpad gcc-16-20251214/gcc/builtins.cc gcc-16-20251221/gcc/builtins.cc
*** gcc-16-20251214/gcc/builtins.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/builtins.cc	Sun Dec 21 22:32:06 2025
*************** get_object_alignment_2 (tree exp, unsign
*** 288,294 ****
        unsigned HOST_WIDE_INT ptr_bitpos;
        unsigned HOST_WIDE_INT ptr_bitmask = ~0;
  
!       /* If the address is explicitely aligned, handle that.  */
        if (TREE_CODE (addr) == BIT_AND_EXPR
  	  && TREE_CODE (TREE_OPERAND (addr, 1)) == INTEGER_CST)
  	{
--- 288,294 ----
        unsigned HOST_WIDE_INT ptr_bitpos;
        unsigned HOST_WIDE_INT ptr_bitmask = ~0;
  
!       /* If the address is explicitly aligned, handle that.  */
        if (TREE_CODE (addr) == BIT_AND_EXPR
  	  && TREE_CODE (TREE_OPERAND (addr, 1)) == INTEGER_CST)
  	{
diff -Nrcpad gcc-16-20251214/gcc/builtins.def gcc-16-20251221/gcc/builtins.def
*** gcc-16-20251214/gcc/builtins.def	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/builtins.def	Sun Dec 21 22:32:06 2025
*************** along with GCC; see the file COPYING3.
*** 257,262 ****
--- 257,263 ----
  	       true, true, true, ATTRS, true, \
  	      (flag_sanitize & (SANITIZE_ADDRESS | SANITIZE_THREAD \
  				| SANITIZE_HWADDRESS \
+ 				| SANITIZE_MEMTAG_STACK \
  				| SANITIZE_UNDEFINED \
  				| SANITIZE_UNDEFINED_NONDEFAULT) \
  	       || flag_sanitize_coverage))
diff -Nrcpad gcc-16-20251214/gcc/c/ChangeLog gcc-16-20251221/gcc/c/ChangeLog
*** gcc-16-20251214/gcc/c/ChangeLog	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/c/ChangeLog	Sun Dec 21 22:32:06 2025
***************
*** 1,3 ****
--- 1,23 ----
+ 2025-12-19  Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	* gimple-parser.cc (c_parser_gimple_switch_stmt): Fix comment typo,
+ 	statment -> statement.
+ 
+ 2025-12-19  Tobias Burnus  <tburnus@baylibre.com>
+ 
+ 	* c-parser.cc (c_parser_omp_clause_uses_allocators): Accept
+ 	multiple clause-argument-specifications separated by ';'.
+ 
+ 2025-12-18  Tobias Burnus  <tburnus@baylibre.com>
+ 
+ 	* c-parser.cc (c_parser_omp_assumption_clauses): Add
+ 	no_openmp_constructs clause.
+ 
+ 2025-12-18  Tobias Burnus  <tburnus@baylibre.com>
+ 
+ 	* c-parser.cc (OMP_TARGET_CLAUSE_MASK): Add
+ 	device_type clause.
+ 
  2025-12-13  Jakub Jelinek  <jakub@redhat.com>
  
  	* c-parser.cc (c_parser_omp_clause_reduction): Provide fixit hints
diff -Nrcpad gcc-16-20251214/gcc/c/c-parser.cc gcc-16-20251221/gcc/c/c-parser.cc
*** gcc-16-20251214/gcc/c/c-parser.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/c/c-parser.cc	Sun Dec 21 22:32:06 2025
*************** c_parser_omp_clause_allocate (c_parser *
*** 19577,19587 ****
--- 19577,19592 ----
     allocator ( traits-array )
     allocator ( traits-array ) , allocator-list
  
+    Deprecated in 5.2, removed in 6.0: 'allocator(trait-array)' syntax.
+ 
     OpenMP 5.2:
  
     uses_allocators ( modifier : allocator-list )
     uses_allocators ( modifier , modifier : allocator-list )
  
+    OpenMP 6.0:
+    uses_allocators ( [modifier-list :] allocator-list [; ...] )
+ 
     modifier:
     traits ( traits-array )
     memspace ( mem-space-handle )  */
*************** c_parser_omp_clause_uses_allocators (c_p
*** 19595,19600 ****
--- 19600,19607 ----
    if (!parens.require_open (parser))
      return list;
  
+ parse_next:
+ 
    bool has_modifiers = false;
    bool seen_allocators = false;
    tree memspace_expr = NULL_TREE;
*************** c_parser_omp_clause_uses_allocators (c_p
*** 19790,19795 ****
--- 19797,19808 ----
  	break;
      }
  
+   if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+     {
+       c_parser_consume_token (parser);
+       goto parse_next;
+     }
+ 
   end:
    parens.skip_until_found_close (parser);
    return nl;
*************** c_parser_omp_target_exit_data (location_
*** 27217,27222 ****
--- 27230,27236 ----
  	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULTMAP)	\
  	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND)	\
  	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE)	\
+ 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE_TYPE)	\
  	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DYN_GROUPPRIVATE) \
  	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE)	\
  	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_HAS_DEVICE_ADDR) \
*************** c_parser_omp_error (c_parser *parser, en
*** 30171,30189 ****
    return false;
  }
  
! /* Assumption clauses:
!    OpenMP 5.1
     absent (directive-name-list)
     contains (directive-name-list)
     holds (expression)
     no_openmp
     no_openmp_routines
!    no_parallelism  */
  
  static void
  c_parser_omp_assumption_clauses (c_parser *parser, bool is_assume)
  {
    bool no_openmp = false;
    bool no_openmp_routines = false;
    bool no_parallelism = false;
    bitmap_head absent_head, contains_head;
--- 30185,30207 ----
    return false;
  }
  
! /* Assumption clauses
!    OpenMP 5.1:
     absent (directive-name-list)
     contains (directive-name-list)
     holds (expression)
     no_openmp
     no_openmp_routines
!    no_parallelism
! 
!    OpenMP 6.0:
!    no_openmp_constructs  */
  
  static void
  c_parser_omp_assumption_clauses (c_parser *parser, bool is_assume)
  {
    bool no_openmp = false;
+   bool no_openmp_constructs = false;
    bool no_openmp_routines = false;
    bool no_parallelism = false;
    bitmap_head absent_head, contains_head;
*************** c_parser_omp_assumption_clauses (c_parse
*** 30216,30221 ****
--- 30234,30246 ----
  	    error_at (cloc, "too many %qs clauses", "no_openmp");
  	  no_openmp = true;
  	}
+       else if (!strcmp (p, "no_openmp_constructs"))
+ 	{
+ 	  c_parser_consume_token (parser);
+ 	  if (no_openmp_constructs)
+ 	    error_at (cloc, "too many %qs clauses", "no_openmp_constructs");
+ 	  no_openmp_constructs = true;
+ 	}
        else if (!strcmp (p, "no_openmp_routines"))
  	{
  	  c_parser_consume_token (parser);
diff -Nrcpad gcc-16-20251214/gcc/c/gimple-parser.cc gcc-16-20251221/gcc/c/gimple-parser.cc
*** gcc-16-20251214/gcc/c/gimple-parser.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/c/gimple-parser.cc	Sun Dec 21 22:32:06 2025
*************** c_parser_gimple_if_stmt (gimple_parser &
*** 2482,2488 ****
  
     gimple-case-statement:
       gimple-case-statement
!      gimple-label-statement : gimple-goto-statment
  */
  
  static void
--- 2482,2488 ----
  
     gimple-case-statement:
       gimple-case-statement
!      gimple-label-statement : gimple-goto-statement
  */
  
  static void
diff -Nrcpad gcc-16-20251214/gcc/c-family/ChangeLog gcc-16-20251221/gcc/c-family/ChangeLog
*** gcc-16-20251214/gcc/c-family/ChangeLog	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/c-family/ChangeLog	Sun Dec 21 22:32:06 2025
***************
*** 1,3 ****
--- 1,14 ----
+ 2025-12-18  Tobias Burnus  <tburnus@baylibre.com>
+ 
+ 	* c-omp.cc (c_omp_split_clauses): Handle target's
+ 	device_type clause.
+ 
+ 2025-12-18  Richard Biener  <rguenther@suse.de>
+ 
+ 	PR c/123156
+ 	* c-common.cc (c_build_shufflevector): Use ssizetype for the
+ 	permute vector element type.
+ 
  2025-12-12  Chung-Lin Tang  <cltang@baylibre.com>
  	    Tobias Burnus  <tburnus@baylibre.com>
  	    Andrew Stubbs  <ams@baylibre.com>
diff -Nrcpad gcc-16-20251214/gcc/c-family/c-common.cc gcc-16-20251221/gcc/c-family/c-common.cc
*** gcc-16-20251214/gcc/c-family/c-common.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/c-family/c-common.cc	Sun Dec 21 22:32:06 2025
*************** c_build_shufflevector (location_t loc, t
*** 1260,1268 ****
    vec_perm_indices indices (sel, 2, maskl);
  
    tree ret_type = build_vector_type (TREE_TYPE (TREE_TYPE (v0)), maskl);
!   tree mask_type = build_vector_type (build_nonstandard_integer_type
! 		(TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (ret_type))), 1),
! 		maskl);
    /* Pad out arguments to the common vector size.  */
    if (v0n < maskl)
      {
--- 1260,1266 ----
    vec_perm_indices indices (sel, 2, maskl);
  
    tree ret_type = build_vector_type (TREE_TYPE (TREE_TYPE (v0)), maskl);
!   tree mask_type = build_vector_type (ssizetype, maskl);
    /* Pad out arguments to the common vector size.  */
    if (v0n < maskl)
      {
diff -Nrcpad gcc-16-20251214/gcc/c-family/c-common.h gcc-16-20251221/gcc/c-family/c-common.h
*** gcc-16-20251214/gcc/c-family/c-common.h	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/c-family/c-common.h	Sun Dec 21 22:32:06 2025
*************** enum cxx_dialect {
*** 748,754 ****
    cxx26
  };
  
! /* The C++ dialect being used.  C++17 is the default.  */
  extern enum cxx_dialect cxx_dialect;
  
  /* Maximum template instantiation depth.  This limit is rather
--- 748,754 ----
    cxx26
  };
  
! /* The C++ dialect being used.  C++20 is the default.  */
  extern enum cxx_dialect cxx_dialect;
  
  /* Maximum template instantiation depth.  This limit is rather
diff -Nrcpad gcc-16-20251214/gcc/c-family/c-omp.cc gcc-16-20251221/gcc/c-family/c-omp.cc
*** gcc-16-20251214/gcc/c-family/c-omp.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/c-family/c-omp.cc	Sun Dec 21 22:32:06 2025
*************** c_omp_split_clauses (location_t loc, enu
*** 2176,2181 ****
--- 2176,2182 ----
  	{
  	/* First the clauses that are unique to some constructs.  */
  	case OMP_CLAUSE_DEVICE:
+ 	case OMP_CLAUSE_DEVICE_TYPE:
  	case OMP_CLAUSE_DEFAULTMAP:
  	case OMP_CLAUSE_DEPEND:
  	case OMP_CLAUSE_DYN_GROUPPRIVATE:
diff -Nrcpad gcc-16-20251214/gcc/cfgexpand.cc gcc-16-20251221/gcc/cfgexpand.cc
*** gcc-16-20251214/gcc/cfgexpand.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/cfgexpand.cc	Sun Dec 21 22:32:06 2025
*************** align_local_variable (tree decl, bool re
*** 383,389 ****
    else
      align = LOCAL_DECL_ALIGNMENT (decl);
  
!   if (hwasan_sanitize_stack_p ())
      align = MAX (align, (unsigned) HWASAN_TAG_GRANULE_SIZE * BITS_PER_UNIT);
  
    if (TREE_CODE (decl) != SSA_NAME && really_expand)
--- 383,389 ----
    else
      align = LOCAL_DECL_ALIGNMENT (decl);
  
!   if (hwassist_sanitize_stack_p ())
      align = MAX (align, (unsigned) HWASAN_TAG_GRANULE_SIZE * BITS_PER_UNIT);
  
    if (TREE_CODE (decl) != SSA_NAME && really_expand)
*************** expand_one_stack_var_at (tree decl, rtx
*** 1337,1343 ****
    /* If this fails, we've overflowed the stack frame.  Error nicely?  */
    gcc_assert (known_eq (offset, trunc_int_for_mode (offset, Pmode)));
  
!   if (hwasan_sanitize_stack_p ())
      x = targetm.memtag.add_tag (base, offset,
  				hwasan_current_frame_tag ());
    else
--- 1337,1343 ----
    /* If this fails, we've overflowed the stack frame.  Error nicely?  */
    gcc_assert (known_eq (offset, trunc_int_for_mode (offset, Pmode)));
  
!   if (hwassist_sanitize_stack_p ())
      x = targetm.memtag.add_tag (base, offset,
  				hwasan_current_frame_tag ());
    else
*************** expand_stack_vars (bool (*pred) (unsigne
*** 1472,1485 ****
        if (pred && !pred (i))
  	continue;
  
!       base = (hwasan_sanitize_stack_p ()
  	      ? hwasan_frame_base ()
  	      : virtual_stack_vars_rtx);
        alignb = stack_vars[i].alignb;
        if (alignb * BITS_PER_UNIT <= MAX_SUPPORTED_STACK_ALIGNMENT)
  	{
  	  poly_int64 hwasan_orig_offset;
! 	  if (hwasan_sanitize_stack_p ())
  	    {
  	      /* There must be no tag granule "shared" between different
  		 objects.  This means that no HWASAN_TAG_GRANULE_SIZE byte
--- 1472,1485 ----
        if (pred && !pred (i))
  	continue;
  
!       base = (hwassist_sanitize_stack_p ()
  	      ? hwasan_frame_base ()
  	      : virtual_stack_vars_rtx);
        alignb = stack_vars[i].alignb;
        if (alignb * BITS_PER_UNIT <= MAX_SUPPORTED_STACK_ALIGNMENT)
  	{
  	  poly_int64 hwasan_orig_offset;
! 	  if (hwassist_sanitize_stack_p ())
  	    {
  	      /* There must be no tag granule "shared" between different
  		 objects.  This means that no HWASAN_TAG_GRANULE_SIZE byte
*************** expand_stack_vars (bool (*pred) (unsigne
*** 1578,1584 ****
  	      offset = alloc_stack_frame_space (stack_vars[i].size, alignb);
  	      base_align = crtl->max_used_stack_slot_alignment;
  
! 	      if (hwasan_sanitize_stack_p ())
  		{
  		  /* Align again since the point of this alignment is to handle
  		     the "end" of the object (i.e. smallest address after the
--- 1578,1584 ----
  	      offset = alloc_stack_frame_space (stack_vars[i].size, alignb);
  	      base_align = crtl->max_used_stack_slot_alignment;
  
! 	      if (hwassist_sanitize_stack_p ())
  		{
  		  /* Align again since the point of this alignment is to handle
  		     the "end" of the object (i.e. smallest address after the
*************** expand_stack_vars (bool (*pred) (unsigne
*** 1623,1629 ****
  	  large_alloc = aligned_upper_bound (large_alloc, alignb);
  	  offset = large_alloc;
  	  large_alloc += stack_vars[i].size;
! 	  if (hwasan_sanitize_stack_p ())
  	    {
  	      /* An object with a large alignment requirement means that the
  		 alignment requirement is greater than the required alignment
--- 1623,1629 ----
  	  large_alloc = aligned_upper_bound (large_alloc, alignb);
  	  offset = large_alloc;
  	  large_alloc += stack_vars[i].size;
! 	  if (hwassist_sanitize_stack_p ())
  	    {
  	      /* An object with a large alignment requirement means that the
  		 alignment requirement is greater than the required alignment
*************** expand_stack_vars (bool (*pred) (unsigne
*** 1654,1660 ****
  	  expand_one_stack_var_at (stack_vars[j].decl,
  				   base, base_align, offset);
  	}
!       if (hwasan_sanitize_stack_p ())
  	hwasan_increment_frame_tag ();
      }
  
--- 1654,1660 ----
  	  expand_one_stack_var_at (stack_vars[j].decl,
  				   base, base_align, offset);
  	}
!       if (hwassist_sanitize_stack_p ())
  	hwasan_increment_frame_tag ();
      }
  
*************** expand_one_stack_var_1 (tree var)
*** 1747,1753 ****
    gcc_assert (byte_align * BITS_PER_UNIT <= MAX_SUPPORTED_STACK_ALIGNMENT);
  
    rtx base;
!   if (hwasan_sanitize_stack_p ())
      {
        /* Allocate zero bytes to align the stack.  */
        poly_int64 hwasan_orig_offset
--- 1747,1753 ----
    gcc_assert (byte_align * BITS_PER_UNIT <= MAX_SUPPORTED_STACK_ALIGNMENT);
  
    rtx base;
!   if (hwassist_sanitize_stack_p ())
      {
        /* Allocate zero bytes to align the stack.  */
        poly_int64 hwasan_orig_offset
*************** expand_one_stack_var_1 (tree var)
*** 1775,1781 ****
    expand_one_stack_var_at (var, base,
  			   crtl->max_used_stack_slot_alignment, offset);
  
!   if (hwasan_sanitize_stack_p ())
      hwasan_increment_frame_tag ();
  }
  
--- 1775,1781 ----
    expand_one_stack_var_at (var, base,
  			   crtl->max_used_stack_slot_alignment, offset);
  
!   if (hwassist_sanitize_stack_p ())
      hwasan_increment_frame_tag ();
  }
  
*************** init_vars_expansion (void)
*** 2379,2385 ****
    /* Initialize local stack smashing state.  */
    has_protected_decls = false;
    has_short_buffer = false;
!   if (hwasan_sanitize_stack_p ())
      hwasan_record_frame_init ();
  }
  
--- 2379,2385 ----
    /* Initialize local stack smashing state.  */
    has_protected_decls = false;
    has_short_buffer = false;
!   if (hwassist_sanitize_stack_p ())
      hwasan_record_frame_init ();
  }
  
*************** expand_used_vars (bitmap forced_stack_va
*** 2705,2717 ****
        expand_stack_vars (NULL, &data);
      }
  
!   if (hwasan_sanitize_stack_p ())
      hwasan_emit_prologue ();
    if (asan_sanitize_allocas_p () && cfun->calls_alloca)
      var_end_seq = asan_emit_allocas_unpoison (virtual_stack_dynamic_rtx,
  					      virtual_stack_vars_rtx,
  					      var_end_seq);
!   else if (hwasan_sanitize_allocas_p () && cfun->calls_alloca)
      /* When using out-of-line instrumentation we only want to emit one function
         call for clearing the tags in a region of shadow stack.  When there are
         alloca calls in this frame we want to emit a call using the
--- 2705,2718 ----
        expand_stack_vars (NULL, &data);
      }
  
!   if (hwassist_sanitize_stack_p ())
      hwasan_emit_prologue ();
    if (asan_sanitize_allocas_p () && cfun->calls_alloca)
      var_end_seq = asan_emit_allocas_unpoison (virtual_stack_dynamic_rtx,
  					      virtual_stack_vars_rtx,
  					      var_end_seq);
!   else if ((hwasan_sanitize_allocas_p () || memtag_sanitize_p ())
! 	   && cfun->calls_alloca)
      /* When using out-of-line instrumentation we only want to emit one function
         call for clearing the tags in a region of shadow stack.  When there are
         alloca calls in this frame we want to emit a call using the
*************** expand_used_vars (bitmap forced_stack_va
*** 2719,2725 ****
         rtx we created in expand_stack_vars.  */
      var_end_seq = hwasan_emit_untag_frame (virtual_stack_dynamic_rtx,
  					   virtual_stack_vars_rtx);
!   else if (hwasan_sanitize_stack_p ())
      /* If no variables were stored on the stack, `hwasan_get_frame_extent`
         will return NULL_RTX and hence `hwasan_emit_untag_frame` will return
         NULL (i.e. an empty sequence).  */
--- 2720,2726 ----
         rtx we created in expand_stack_vars.  */
      var_end_seq = hwasan_emit_untag_frame (virtual_stack_dynamic_rtx,
  					   virtual_stack_vars_rtx);
!   else if (hwassist_sanitize_stack_p ())
      /* If no variables were stored on the stack, `hwasan_get_frame_extent`
         will return NULL_RTX and hence `hwasan_emit_untag_frame` will return
         NULL (i.e. an empty sequence).  */
*************** pass_expand::execute (function *fun)
*** 7310,7316 ****
        emit_insn_after (var_ret_seq, after);
      }
  
!   if (hwasan_sanitize_stack_p ())
      hwasan_maybe_emit_frame_base_init ();
  
    /* Zap the tree EH table.  */
--- 7311,7317 ----
        emit_insn_after (var_ret_seq, after);
      }
  
!   if (hwassist_sanitize_stack_p ())
      hwasan_maybe_emit_frame_base_init ();
  
    /* Zap the tree EH table.  */
diff -Nrcpad gcc-16-20251214/gcc/cgraph.cc gcc-16-20251221/gcc/cgraph.cc
*** gcc-16-20251214/gcc/cgraph.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/cgraph.cc	Sun Dec 21 22:32:06 2025
*************** cgraph_node::create_edge (cgraph_node *c
*** 1162,1217 ****
    return edge;
  }
  
! /* Allocate cgraph_indirect_call_info and set its fields to default values. */
! 
! cgraph_indirect_call_info *
! cgraph_allocate_init_indirect_info (void)
! {
!   cgraph_indirect_call_info *ii;
! 
!   ii = ggc_cleared_alloc<cgraph_indirect_call_info> ();
!   ii->param_index = -1;
!   return ii;
! }
! 
! /* Create an indirect edge with a yet-undetermined callee where the call
!    statement destination is a formal parameter of the caller with index
!    PARAM_INDEX. CLONING_P should be set if properties that are copied from an
!    original edge should not be calculated and indirect_info structure should
!    not be calculated.  */
  
  cgraph_edge *
  cgraph_node::create_indirect_edge (gcall *call_stmt, int ecf_flags,
! 				   profile_count count,
! 				   bool cloning_p)
  {
    cgraph_edge *edge = symtab->create_edge (this, NULL, call_stmt, count, true,
  					   cloning_p);
-   tree target;
  
    if (!cloning_p)
-     initialize_inline_failed (edge);
- 
-   edge->indirect_info = cgraph_allocate_init_indirect_info ();
-   edge->indirect_info->ecf_flags = ecf_flags;
-   edge->indirect_info->vptr_changed = true;
- 
-   /* Record polymorphic call info.  */
-   if (!cloning_p
-       && call_stmt
-       && (target = gimple_call_fn (call_stmt))
-       && virtual_method_call_p (target))
      {
!       ipa_polymorphic_call_context context (decl, target, call_stmt);
  
!       /* Only record types can have virtual calls.  */
!       edge->indirect_info->polymorphic = true;
!       edge->indirect_info->param_index = -1;
!       edge->indirect_info->otr_token
! 	 = tree_to_uhwi (OBJ_TYPE_REF_TOKEN (target));
!       edge->indirect_info->otr_type = obj_type_ref_class (target);
!       gcc_assert (TREE_CODE (edge->indirect_info->otr_type) == RECORD_TYPE);
!       edge->indirect_info->context = context;
      }
  
    edge->next_callee = indirect_calls;
--- 1162,1205 ----
    return edge;
  }
  
! /* Create an indirect edge to a (yet-)undetermined callee.  CALL_STMT is the
!    corresponding statement, if available, ECF_FLAGS and COUNT are corresponding
!    gimple call flags and profiling count respectively.  CLONING_P should be set
!    if properties that are copied from an original edge should not be
!    calculated.  */
  
  cgraph_edge *
  cgraph_node::create_indirect_edge (gcall *call_stmt, int ecf_flags,
! 				   profile_count count, bool cloning_p)
  {
    cgraph_edge *edge = symtab->create_edge (this, NULL, call_stmt, count, true,
  					   cloning_p);
  
    if (!cloning_p)
      {
!       initialize_inline_failed (edge);
  
!       tree target = NULL_TREE;
!       if (call_stmt)
! 	target = gimple_call_fn (call_stmt);
!       if (target && virtual_method_call_p (target))
! 	{
! 	  ipa_polymorphic_call_context context (decl, target, call_stmt);
! 	  HOST_WIDE_INT token = tree_to_shwi (OBJ_TYPE_REF_TOKEN (target));
! 	  tree type = obj_type_ref_class (target);
! 	  edge->indirect_info
! 	    = (new (ggc_alloc<cgraph_polymorphic_indirect_info> ())
! 	       cgraph_polymorphic_indirect_info (ecf_flags, context, token,
! 						 type));
! 	}
!       else if (target && TREE_CODE (target) == SSA_NAME)
! 	edge->indirect_info
! 	  = (new (ggc_alloc<cgraph_simple_indirect_info> ())
! 	     cgraph_simple_indirect_info (ecf_flags));
!       else
! 	edge->indirect_info
! 	  = (new (ggc_alloc<cgraph_indirect_call_info> ())
! 	     cgraph_indirect_call_info(CIIK_UNSPECIFIED, ecf_flags));
      }
  
    edge->next_callee = indirect_calls;
*************** cgraph_edge::resolve_speculation (cgraph
*** 1527,1535 ****
      e2 = edge;
    ref = e2->speculative_call_target_ref ();
    edge = edge->speculative_call_indirect_edge ();
    if (!callee_decl
!       || !ref->referred->semantically_equivalent_p
! 	   (symtab_node::get (callee_decl)))
      {
        if (dump_file)
  	{
--- 1515,1524 ----
      e2 = edge;
    ref = e2->speculative_call_target_ref ();
    edge = edge->speculative_call_indirect_edge ();
+   symtab_node *callee;
    if (!callee_decl
!       || !(callee = symtab_node::get (callee_decl))
!       || !ref->referred->semantically_equivalent_p (callee))
      {
        if (dump_file)
  	{
*************** cgraph_node::dump (FILE *f)
*** 2666,2695 ****
  
    for (edge = indirect_calls; edge; edge = edge->next_callee)
      {
!       if (edge->indirect_info->polymorphic)
! 	{
! 	  fprintf (f, "   Polymorphic indirect call of type ");
! 	  print_generic_expr (f, edge->indirect_info->otr_type, TDF_SLIM);
! 	  fprintf (f, " token:%i", (int) edge->indirect_info->otr_token);
! 	}
!       else
! 	fprintf (f, "   Indirect call");
!       edge->dump_edge_flags (f);
!       if (edge->indirect_info->param_index != -1)
! 	{
! 	  fprintf (f, "of param:%i ", edge->indirect_info->param_index);
! 	  if (edge->indirect_info->agg_contents)
! 	   fprintf (f, "loaded from %s %s at offset %i ",
! 		    edge->indirect_info->member_ptr ? "member ptr" : "aggregate",
! 		    edge->indirect_info->by_ref ? "passed by reference" : "",
! 		    (int)edge->indirect_info->offset);
! 	  if (edge->indirect_info->vptr_changed)
! 	    fprintf (f, "(vptr maybe changed) ");
! 	}
!       fprintf (f, "num speculative call targets: %i\n",
! 	       edge->indirect_info->num_speculative_call_targets);
!       if (edge->indirect_info->polymorphic)
! 	edge->indirect_info->context.dump (f);
      }
  }
  
--- 2655,2662 ----
  
    for (edge = indirect_calls; edge; edge = edge->next_callee)
      {
!       fprintf (f, "   ");
!       edge->indirect_info->dump (f);
      }
  }
  
*************** cgraph_node::dump_cgraph (FILE *f)
*** 2729,2734 ****
--- 2696,2752 ----
      node->dump (f);
  }
  
+ /* Dump human readable information about the indirect call to F.  If NEWLINE
+    is true, it will be terminated by a newline.  */
+ 
+ void
+ cgraph_indirect_call_info::dump (FILE *f, bool newline) const
+ {
+   if (const cgraph_polymorphic_indirect_info *pii
+       = dyn_cast <const cgraph_polymorphic_indirect_info *> (this))
+     {
+       fprintf (f, "    indirect polymorphic callsite, %s, "
+ 	       "calling param %i, offset " HOST_WIDE_INT_PRINT_DEC
+ 	       "otr_token " HOST_WIDE_INT_PRINT_DEC ", otr_type ",
+ 	       pii->vptr_changed ? "vptr_changed" : "vptr not changed",
+ 	       pii->param_index, pii->offset, pii->otr_token);
+       print_generic_expr (f, pii->otr_type);
+       fprintf (f, ", context ");
+       pii->context.dump (f, false);
+     }
+   else if (const cgraph_simple_indirect_info *sii
+ 	   = dyn_cast <const cgraph_simple_indirect_info *> (this))
+     {
+       if (sii->agg_contents)
+ 	fprintf (f, "    indirect %s callsite, calling param %i, "
+ 		 "offset " HOST_WIDE_INT_PRINT_DEC ", %s",
+ 		 sii->member_ptr ? "member ptr" : "aggregate",
+ 		 sii->param_index, sii->offset,
+ 		 sii->by_ref ? "by reference" : "by_value");
+       else if (sii->param_index >= 0)
+ 	fprintf (f, "    indirect simple callsite, calling param %i",
+ 		 sii->param_index);
+       else
+ 	fprintf (f, "    indirect simple callsite, not calling a known "
+ 		 "parameter");
+     }
+   else
+     fprintf (f, "    indirect callsite");
+ 
+   fprintf (f, ", flags %i, num speculative call targets: %i", ecf_flags,
+ 	   num_speculative_call_targets);
+   if (newline)
+     fprintf (f, "\n");
+ }
+ 
+ /* Dump human readable information about the indirect call to stderr.  */
+ 
+ void
+ cgraph_indirect_call_info::debug () const
+ {
+   dump (stderr);
+ }
+ 
  /* Return true when the DECL can possibly be inlined.  */
  
  bool
diff -Nrcpad gcc-16-20251214/gcc/cgraph.h gcc-16-20251221/gcc/cgraph.h
*** gcc-16-20251214/gcc/cgraph.h	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/cgraph.h	Sun Dec 21 22:32:06 2025
*************** struct GTY((tag ("SYMTAB_FUNCTION"))) cg
*** 1170,1178 ****
  			    gcall *call_stmt, profile_count count,
  			    bool cloning_p = false);
  
!   /* Create an indirect edge with a yet-undetermined callee where the call
!      statement destination is a formal parameter of the caller with index
!      PARAM_INDEX. */
    cgraph_edge *create_indirect_edge (gcall *call_stmt, int ecf_flags,
  				     profile_count count,
  				     bool cloning_p = false);
--- 1170,1181 ----
  			    gcall *call_stmt, profile_count count,
  			    bool cloning_p = false);
  
!   /* Create an indirect edge to a (yet-)undetermined callee.  CALL_STMT is the
!      corresponding statement, if available, ECF_FLAGS and COUNT are
!      corresponding gimple call flags and profiling count respectively.
!      CLONING_P should be set if properties that are copied from an original
!      edge should not be calculated.  */
! 
    cgraph_edge *create_indirect_edge (gcall *call_stmt, int ecf_flags,
  				     profile_count count,
  				     bool cloning_p = false);
*************** private:
*** 1703,1738 ****
    void make_speculative (tree otr_type = NULL);
  };
  
! /* Structure containing additional information about an indirect call.  */
  
! class GTY(()) cgraph_indirect_call_info
  {
  public:
!   /* When agg_content is set, an offset where the call pointer is located
!      within the aggregate.  */
!   HOST_WIDE_INT offset;
!   /* Context of the polymorphic call; use only when POLYMORPHIC flag is set.  */
!   ipa_polymorphic_call_context context;
!   /* OBJ_TYPE_REF_TOKEN of a polymorphic call (if polymorphic is set).  */
!   HOST_WIDE_INT otr_token;
!   /* Type of the object from OBJ_TYPE_REF_OBJECT. */
!   tree otr_type;
!   /* Index of the parameter that is called.  */
!   int param_index;
    /* ECF flags determined from the caller.  */
    int ecf_flags;
  
!   /* Number of speculative call targets, it's less than GCOV_TOPN_VALUES.  */
    unsigned num_speculative_call_targets : 16;
  
-   /* Set when the call is a virtual call with the parameter being the
-      associated object pointer rather than a simple direct call.  */
-   unsigned polymorphic : 1;
    /* Set when the call is a call of a pointer loaded from contents of an
       aggregate at offset.  */
    unsigned agg_contents : 1;
    /* Set when this is a call through a member pointer.  */
    unsigned member_ptr : 1;
    /* When the agg_contents bit is set, this one determines whether the
       destination is loaded from a parameter passed by reference. */
    unsigned by_ref : 1;
--- 1706,1793 ----
    void make_speculative (tree otr_type = NULL);
  };
  
! /* Denotes the kind of call that a particular cgraph_indirect_call_info
!    instance describes.  */
  
! enum cgraph_indirect_info_kind {
!   /* Unspecified kind.  Only to be used when no information about the call
!      statement is available or it does not fall into any of the other
!      categories.  */
!   CIIK_UNSPECIFIED,
!   /* A normal indirect call when the target is an SSA_NAME.  */
!   CIIK_SIMPLE,
!   /* Call of a virtual method when the target is an OBJ_TYPE_REF which conforms
!      to virtual_method_call_p.  */
!   CIIK_POLYMORPHIC,
!   /* Must be last */
!   CIIK_N_KINDS
! };
! 
! /* The base class containing additional information about all kinds of indirect
!    calls.  It can also be used when no information about the call statement is
!    available or it does not fall into any of the other categories.  */
! 
! class GTY((desc ("%h.kind"), tag ("CIIK_UNSPECIFIED")))
! 	  cgraph_indirect_call_info
  {
  public:
!   cgraph_indirect_call_info (int flags)
!     : ecf_flags (flags), param_index (-1), kind (CIIK_UNSPECIFIED),
!     num_speculative_call_targets (0) {}
!   cgraph_indirect_call_info (enum cgraph_indirect_info_kind k, int flags)
!     : ecf_flags (flags), param_index (-1), kind (k),
!     num_speculative_call_targets (0) {}
! 
!   /* Dump human readable information about the indirect call to F.  If NEWLINE
!      is true, it will be terminated by a newline.  */
!   void dump (FILE *f, bool newline = true) const;
!   void DEBUG_FUNCTION debug () const;
! 
    /* ECF flags determined from the caller.  */
    int ecf_flags;
+   /* If we can relate this call target to a specific formal parameter of the
+      caller, then this is its index.  Otherwise set to -1.  */
+   int param_index;
  
!   /* Identifier of the specific type of indirect info this actually is.  */
!   enum cgraph_indirect_info_kind kind : 2;
!   /* Number of speculative call targets.  */
    unsigned num_speculative_call_targets : 16;
+ };
+ 
+ /* Structure containing additional information about non-virtual indirect calls
+    where the target is an SSA_NAME.  */
+ 
+ class GTY((tag ("CIIK_SIMPLE")))
+ 	  cgraph_simple_indirect_info : public cgraph_indirect_call_info
+ {
+ public:
+   cgraph_simple_indirect_info (int flags)
+     : cgraph_indirect_call_info (CIIK_SIMPLE, flags), offset (0),
+     rec_type (NULL_TREE), fld_offset (0), agg_contents (false),
+     member_ptr (false), fnptr_loaded_from_record (false), by_ref (false),
+     guaranteed_unmodified (false)
+     {}
+ 
+   /* When agg_content is set, an offset where the call pointer is located
+      within the aggregate.  */
+   HOST_WIDE_INT offset;
+   /* Only meaningful if fnptr_loaded_from_record is set.  Then it contains the
+      type of the record from which the target of the call was loaded. */
+   tree rec_type;
+   /* Only meaningful if fnptr_loaded_from_record is set.  Then it contains the
+      offset in bytes within the type above from which the target of the call
+      was loaded.  */
+   unsigned fld_offset;
  
    /* Set when the call is a call of a pointer loaded from contents of an
       aggregate at offset.  */
    unsigned agg_contents : 1;
    /* Set when this is a call through a member pointer.  */
    unsigned member_ptr : 1;
+   /* Set if the function is a call of a pointer loaded from a record type
+      stored in otr_type at offset offset. */
+   unsigned fnptr_loaded_from_record : 1;
    /* When the agg_contents bit is set, this one determines whether the
       destination is loaded from a parameter passed by reference. */
    unsigned by_ref : 1;
*************** public:
*** 1741,1751 ****
--- 1796,1864 ----
       never modified between the invocation of the function and the load
       point.  */
    unsigned guaranteed_unmodified : 1;
+ };
+ 
+ /* Structure containing additional information about non-virtual indirect calls
+    when the target is an OBJ_TYPE_REF which conforms to
+    virtual_method_call_p.  */
+ 
+ class GTY((tag ("CIIK_POLYMORPHIC")))
+ 	  cgraph_polymorphic_indirect_info : public cgraph_indirect_call_info
+ {
+ public:
+   cgraph_polymorphic_indirect_info (int flags)
+     : cgraph_indirect_call_info (CIIK_POLYMORPHIC, flags), context (),
+     otr_token (0), otr_type (nullptr), offset (0), vptr_changed (true)
+     {}
+   cgraph_polymorphic_indirect_info (int flags,
+ 				    const ipa_polymorphic_call_context &ctx,
+ 				    HOST_WIDE_INT token, tree type)
+     : cgraph_indirect_call_info (CIIK_POLYMORPHIC, flags), context (ctx),
+     otr_token (token), otr_type (type), offset (0), vptr_changed (true)
+     {}
+ 
+   /* Return true if the information is usable for devirtualization.  This can
+      happen if part of the required information is not streamed in yet and for
+      some cases we determine it is no longer useful to attempt to use the
+      information too.  */
+   bool usable_p () const
+   {
+     return !!otr_type;
+   }
+   /* Mark this information as not useful for devirtualization.  Return true if
+      it was considered useful until now.  */
+   bool mark_unusable ()
+   {
+     bool r = !!otr_type;
+     otr_type = NULL_TREE;
+     return r;
+   }
+ 
+   /* Context of the polymorphic call; use only when POLYMORPHIC flag is set.  */
+   ipa_polymorphic_call_context context;
+   /* OBJ_TYPE_REF_TOKEN of a polymorphic call (if polymorphic is set).  */
+   HOST_WIDE_INT otr_token;
+   /* Type of the object from OBJ_TYPE_REF_OBJECT. */
+   tree otr_type;
+   /* The offset from the point where the parameter identified by param_index to
+      the point where the corresponding object appears.  */
+   HOST_WIDE_INT offset;
+ 
    /* For polymorphic calls this specify whether the virtual table pointer
       may have changed in between function entry and the call.  */
    unsigned vptr_changed : 1;
  };
  
+ /* Return true if ii is a cgraph_polymorphic_indirect_info that is usable_p.  */
+ 
+ inline bool
+ usable_polymorphic_info_p (cgraph_indirect_call_info *ii)
+ {
+   cgraph_polymorphic_indirect_info *pii
+     = dyn_cast <cgraph_polymorphic_indirect_info *> (ii);
+   return pii && pii->usable_p ();
+ }
+ 
  class GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_caller"),
  	   for_user)) cgraph_edge
  {
*************** is_a_helper <asm_node *>::test (toplevel
*** 2311,2316 ****
--- 2424,2472 ----
    return p && p->type == TOPLEVEL_ASM;
  }
  
+ /* Report whether or not THIS indirect info is a known simple one.  */
+ 
+ template <>
+ template <>
+ inline bool
+ is_a_helper <cgraph_simple_indirect_info *>::test (cgraph_indirect_call_info *p)
+ {
+   return p && p->kind == CIIK_SIMPLE;
+ }
+ 
+ /* Likewise, but const qualified.  */
+ 
+ template <>
+ template <>
+ inline bool
+ is_a_helper <const cgraph_simple_indirect_info *>
+ ::test (const cgraph_indirect_call_info *p)
+ {
+   return p && p->kind == CIIK_SIMPLE;
+ }
+ 
+ /* Report whether or not THIS indirect info is a known polymorphic one.  */
+ 
+ template <>
+ template <>
+ inline bool
+ is_a_helper <cgraph_polymorphic_indirect_info *>
+ ::test (cgraph_indirect_call_info *p)
+ {
+   return p && p->kind == CIIK_POLYMORPHIC;
+ }
+ 
+ /* Likewise, but const qualified.  */
+ 
+ template <>
+ template <>
+ inline bool
+ is_a_helper <const cgraph_polymorphic_indirect_info *>
+ ::test (const cgraph_indirect_call_info *p)
+ {
+   return p && p->kind == CIIK_POLYMORPHIC;
+ }
+ 
  typedef void (*cgraph_edge_hook)(cgraph_edge *, void *);
  typedef void (*cgraph_node_hook)(cgraph_node *, void *);
  typedef void (*varpool_node_hook)(varpool_node *, void *);
*************** asmname_hasher::equal (symtab_node *n, c
*** 2734,2740 ****
  /* In cgraph.cc  */
  void cgraph_cc_finalize (void);
  void release_function_body (tree);
- cgraph_indirect_call_info *cgraph_allocate_init_indirect_info (void);
  
  void cgraph_update_edges_for_call_stmt (gimple *, tree, gimple *);
  bool cgraph_function_possibly_inlined_p (tree);
--- 2890,2895 ----
*************** ipa_ref::address_matters_p ()
*** 3633,3640 ****
  inline
  ipa_polymorphic_call_context::ipa_polymorphic_call_context (cgraph_edge *e)
  {
!   gcc_checking_assert (e->indirect_info->polymorphic);
!   *this = e->indirect_info->context;
  }
  
  /* Build empty "I know nothing" context.  */
--- 3788,3796 ----
  inline
  ipa_polymorphic_call_context::ipa_polymorphic_call_context (cgraph_edge *e)
  {
!   cgraph_polymorphic_indirect_info *pii
!     = as_a <cgraph_polymorphic_indirect_info *> (e->indirect_info);
!   *this = pii->context;
  }
  
  /* Build empty "I know nothing" context.  */
diff -Nrcpad gcc-16-20251214/gcc/cgraphclones.cc gcc-16-20251221/gcc/cgraphclones.cc
*** gcc-16-20251214/gcc/cgraphclones.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/cgraphclones.cc	Sun Dec 21 22:32:06 2025
*************** cgraph_edge::clone (cgraph_node *n, gcal
*** 121,127 ****
  	  new_edge = n->create_indirect_edge (call_stmt,
  					      indirect_info->ecf_flags,
  					      prof_count, true);
! 	  *new_edge->indirect_info = *indirect_info;
  	}
      }
    else
--- 121,142 ----
  	  new_edge = n->create_indirect_edge (call_stmt,
  					      indirect_info->ecf_flags,
  					      prof_count, true);
! 
! 	  if (indirect_info->kind == CIIK_POLYMORPHIC)
! 	    new_edge->indirect_info
! 	      = (new (ggc_alloc<cgraph_polymorphic_indirect_info> ())
! 		 cgraph_polymorphic_indirect_info (
! 		     *(const cgraph_polymorphic_indirect_info *) indirect_info));
! 	  else if (indirect_info->kind == CIIK_SIMPLE)
! 	    new_edge->indirect_info
! 	      = (new (ggc_alloc<cgraph_simple_indirect_info> ())
! 		 cgraph_simple_indirect_info (
! 		     *(const cgraph_simple_indirect_info *) indirect_info));
! 	  else
! 	    new_edge->indirect_info
! 	      = (new (ggc_alloc<cgraph_indirect_call_info> ())
! 		 cgraph_indirect_call_info(
! 		     *(const cgraph_indirect_call_info *) indirect_info));
  	}
      }
    else
diff -Nrcpad gcc-16-20251214/gcc/cgraphunit.cc gcc-16-20251221/gcc/cgraphunit.cc
*** gcc-16-20251214/gcc/cgraphunit.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/cgraphunit.cc	Sun Dec 21 22:32:06 2025
*************** analyze_functions (bool first_time)
*** 1297,1303 ****
  		  for (edge = cnode->indirect_calls; edge; edge = next)
  		    {
  		      next = edge->next_callee;
! 		      if (edge->indirect_info->polymorphic)
  			walk_polymorphic_call_targets (&reachable_call_targets,
  						       edge);
  		    }
--- 1297,1304 ----
  		  for (edge = cnode->indirect_calls; edge; edge = next)
  		    {
  		      next = edge->next_callee;
! 		      if (is_a <cgraph_polymorphic_indirect_info *>
! 			  (edge->indirect_info))
  			walk_polymorphic_call_targets (&reachable_call_targets,
  						       edge);
  		    }
diff -Nrcpad gcc-16-20251214/gcc/cobol/ChangeLog gcc-16-20251221/gcc/cobol/ChangeLog
*** gcc-16-20251214/gcc/cobol/ChangeLog	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/cobol/ChangeLog	Sun Dec 21 22:32:06 2025
***************
*** 1,3 ****
--- 1,9 ----
+ 2025-12-19  Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	* lexio.cc (parse_replace_pairs): Fix comment typo, statment
+ 	-> statement.
+ 	(cdftext::free_form_reference_format): Likewise.
+ 
  2025-12-11  Jakub Jelinek  <jakub@redhat.com>
  
  	* util.cc (class temp_loc_t): Fix comment typo, paramters
diff -Nrcpad gcc-16-20251214/gcc/cobol/lexio.cc gcc-16-20251221/gcc/cobol/lexio.cc
*** gcc-16-20251214/gcc/cobol/lexio.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/cobol/lexio.cc	Sun Dec 21 22:32:06 2025
*************** parse_replace_pairs( const char *stmt, c
*** 899,905 ****
      gcc_assert(!before.has_nul());
      pairs.push_back( replace_t( output.before, output.after ) );
  
!     // COPY REPLACING matches end-of-statment here
      // REPLACE matched end-of-statement in caller, and estmt[-1] == '.'
      if( is_copy_stmt && parsed.stmt.pend[-1] == '.' ) break;
    }
--- 899,905 ----
      gcc_assert(!before.has_nul());
      pairs.push_back( replace_t( output.before, output.after ) );
  
!     // COPY REPLACING matches end-of-statement here
      // REPLACE matched end-of-statement in caller, and estmt[-1] == '.'
      if( is_copy_stmt && parsed.stmt.pend[-1] == '.' ) break;
    }
*************** cdftext::free_form_reference_format( int
*** 1864,1870 ****
   * denoting the source filename.  As far as the lexer is concerned,
   * there's only ever one file: the name passed to lex_open() when we
   * kicked things off.  But messages and the debugger need to know
!  * which file and line each statment appeared in.
   *
   * The lexer uses the input stack to keep track of names and
   * numbers. The top of the input file stack is the current file
--- 1864,1870 ----
   * denoting the source filename.  As far as the lexer is concerned,
   * there's only ever one file: the name passed to lex_open() when we
   * kicked things off.  But messages and the debugger need to know
!  * which file and line each statement appeared in.
   *
   * The lexer uses the input stack to keep track of names and
   * numbers. The top of the input file stack is the current file
diff -Nrcpad gcc-16-20251214/gcc/combine.cc gcc-16-20251221/gcc/combine.cc
*** gcc-16-20251214/gcc/combine.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/combine.cc	Sun Dec 21 22:32:06 2025
*************** make_extraction (machine_mode mode, rtx
*** 7615,7621 ****
    if (GET_CODE (inner) == SUBREG
        && subreg_lowpart_p (inner)
        && (paradoxical_subreg_p (inner)
! 	  /* If trying or potentionally trying to extract
  	     bits outside of is_mode, don't look through
  	     non-paradoxical SUBREGs.  See PR82192.  */
  	  || (pos_rtx == NULL_RTX
--- 7615,7621 ----
    if (GET_CODE (inner) == SUBREG
        && subreg_lowpart_p (inner)
        && (paradoxical_subreg_p (inner)
! 	  /* If trying or potentially trying to extract
  	     bits outside of is_mode, don't look through
  	     non-paradoxical SUBREGs.  See PR82192.  */
  	  || (pos_rtx == NULL_RTX
*************** make_extraction (machine_mode mode, rtx
*** 7664,7670 ****
  	}
      }
    else if (GET_CODE (inner) == TRUNCATE
! 	   /* If trying or potentionally trying to extract
  	      bits outside of is_mode, don't look through
  	      TRUNCATE.  See PR82192.  */
  	   && pos_rtx == NULL_RTX
--- 7664,7670 ----
  	}
      }
    else if (GET_CODE (inner) == TRUNCATE
! 	   /* If trying or potentially trying to extract
  	      bits outside of is_mode, don't look through
  	      TRUNCATE.  See PR82192.  */
  	   && pos_rtx == NULL_RTX
*************** make_extraction (machine_mode mode, rtx
*** 7929,7935 ****
       mode.  */
    else if (!MEM_P (inner))
      {
!       /* On the LHS, don't create paradoxical subregs implicitely truncating
  	 the register unless TARGET_TRULY_NOOP_TRUNCATION.  */
        if (in_dest
  	  && !TRULY_NOOP_TRUNCATION_MODES_P (GET_MODE (inner),
--- 7929,7935 ----
       mode.  */
    else if (!MEM_P (inner))
      {
!       /* On the LHS, don't create paradoxical subregs implicitly truncating
  	 the register unless TARGET_TRULY_NOOP_TRUNCATION.  */
        if (in_dest
  	  && !TRULY_NOOP_TRUNCATION_MODES_P (GET_MODE (inner),
*************** simplify_comparison (enum rtx_code code,
*** 13131,13137 ****
      }
  
    /* Now make any compound operations involved in this comparison.  Then,
!      check for an outmost SUBREG on OP0 that is not doing anything or is
       paradoxical.  The latter transformation must only be performed when
       it is known that the "extra" bits will be the same in op0 and op1 or
       that they don't matter.  There are three cases to consider:
--- 13131,13137 ----
      }
  
    /* Now make any compound operations involved in this comparison.  Then,
!      check for an outermost SUBREG on OP0 that is not doing anything or is
       paradoxical.  The latter transformation must only be performed when
       it is known that the "extra" bits will be the same in op0 and op1 or
       that they don't matter.  There are three cases to consider:
*************** record_truncated_value (rtx x)
*** 13779,13785 ****
  }
  
  /* Callback for note_uses.  Find hardregs and subregs of pseudos and
!    the modes they are used in.  This can help truning TRUNCATEs into
     SUBREGs.  */
  
  static void
--- 13779,13785 ----
  }
  
  /* Callback for note_uses.  Find hardregs and subregs of pseudos and
!    the modes they are used in.  This can help turning TRUNCATEs into
     SUBREGs.  */
  
  static void
*************** distribute_notes (rtx notes, rtx_insn *f
*** 14919,14925 ****
  		 that is unused, we must arrange for an appropriate REG_DEAD
  		 note to be added for it.  However, we can't just emit a USE
  		 and tag the note to it, since the register might actually
! 		 be dead; so we recourse, and the recursive call then finds
  		 the previous insn that used this register.  */
  
  	      if (place && REG_NREGS (XEXP (note, 0)) > 1)
--- 14919,14925 ----
  		 that is unused, we must arrange for an appropriate REG_DEAD
  		 note to be added for it.  However, we can't just emit a USE
  		 and tag the note to it, since the register might actually
! 		 be dead; so we recurse, and the recursive call then finds
  		 the previous insn that used this register.  */
  
  	      if (place && REG_NREGS (XEXP (note, 0)) > 1)
diff -Nrcpad gcc-16-20251214/gcc/common/config/aarch64/aarch64-common.cc gcc-16-20251221/gcc/common/config/aarch64/aarch64-common.cc
*** gcc-16-20251214/gcc/common/config/aarch64/aarch64-common.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/common/config/aarch64/aarch64-common.cc	Sun Dec 21 22:32:06 2025
*************** struct aarch64_extension_info
*** 165,170 ****
--- 165,174 ----
    aarch64_feature_flags flags_off;
    /* If this feature remains enabled, these bits must also remain enabled.  */
    aarch64_feature_flags flags_required;
+   /* If this is not an alias extension, then this is zero.
+      Otherwise, this is the set of feature bits this alias is preferred
+      over.  */
+   aarch64_feature_flags flags_alias_preferred_over;
  };
  
  /* ISA extensions in AArch64.  */
*************** static constexpr aarch64_extension_info
*** 173,181 ****
  #define AARCH64_OPT_EXTENSION(NAME, IDENT, C, D, E, FEATURE_STRING) \
    {NAME, AARCH64_FL_##IDENT, feature_deps::IDENT ().explicit_on, \
     feature_deps::get_flags_off (feature_deps::root_off_##IDENT), \
!    feature_deps::IDENT ().enable},
  #include "config/aarch64/aarch64-option-extensions.def"
!   {NULL, 0, 0, 0, 0}
  };
  
  struct aarch64_arch_info
--- 177,186 ----
  #define AARCH64_OPT_EXTENSION(NAME, IDENT, C, D, E, FEATURE_STRING) \
    {NAME, AARCH64_FL_##IDENT, feature_deps::IDENT ().explicit_on, \
     feature_deps::get_flags_off (feature_deps::root_off_##IDENT), \
!    feature_deps::IDENT ().enable, \
!    feature_deps::alias_prefer_over_flags_##IDENT},
  #include "config/aarch64/aarch64-option-extensions.def"
!   {NULL, 0, 0, 0, 0, 0}
  };
  
  struct aarch64_arch_info
*************** aarch64_get_extension_string_for_isa_fla
*** 634,643 ****
  {
    std::string outstr = "";
  
!   /* The CRYPTO bit should only be used to support the +crypto alias
       during option processing, and should be cleared at all other times.
       Verify this property for the supplied flags bitmask.  */
!   gcc_assert (!(AARCH64_FL_CRYPTO & aarch64_isa_flags));
    aarch64_feature_flags current_flags = default_arch_flags;
  
    /* As a special case, do not assume that the assembler will enable CRC
--- 639,648 ----
  {
    std::string outstr = "";
  
!   /* The alias bits should only be used to support the aliases
       during option processing, and should be cleared at all other times.
       Verify this property for the supplied flags bitmask.  */
!   gcc_assert (!(feature_deps::alias_flags & aarch64_isa_flags));
    aarch64_feature_flags current_flags = default_arch_flags;
  
    /* As a special case, do not assume that the assembler will enable CRC
*************** aarch64_get_extension_string_for_isa_fla
*** 657,680 ****
       But in order to make the output more readable, it seems better
       to add the strings in definition order.  */
    aarch64_feature_flags added = 0;
-   auto flags_crypto = AARCH64_FL_AES | AARCH64_FL_SHA2;
    for (unsigned int i = ARRAY_SIZE (all_extensions); i-- > 0; )
      {
        auto &opt = all_extensions[i];
  
!       /* As a special case, emit +crypto rather than +aes+sha2,
! 	 in order to support assemblers that predate the separate
! 	 per-feature crypto flags.  */
!       auto flags = opt.flag_canonical;
!       if (flags == AARCH64_FL_CRYPTO)
! 	flags = flags_crypto;
! 
!       if ((flags & isa_flags & (explicit_flags | ~current_flags)) == flags)
  	{
  	  current_flags |= opt.flags_on;
  	  added |= opt.flag_canonical;
  	}
      }
    for (auto &opt : all_extensions)
      if (added & opt.flag_canonical)
        {
--- 662,691 ----
       But in order to make the output more readable, it seems better
       to add the strings in definition order.  */
    aarch64_feature_flags added = 0;
    for (unsigned int i = ARRAY_SIZE (all_extensions); i-- > 0; )
      {
        auto &opt = all_extensions[i];
  
!       if (!opt.flags_alias_preferred_over
! 	  && (opt.flag_canonical & isa_flags
! 	      & (explicit_flags | ~current_flags)))
  	{
  	  current_flags |= opt.flags_on;
  	  added |= opt.flag_canonical;
  	}
      }
+ 
+   /* Replace any aliased extensions.  */
+   for (auto alias: all_extensions)
+     if (alias.flags_alias_preferred_over
+ 	&& (added & alias.flags_alias_preferred_over)
+ 	     == alias.flags_alias_preferred_over
+ 	&& (alias.flags_on | isa_flags) == isa_flags)
+       {
+ 	added &= ~alias.flags_on;
+ 	added |= alias.flag_canonical;
+       }
+ 
    for (auto &opt : all_extensions)
      if (added & opt.flag_canonical)
        {
*************** aarch64_get_extension_string_for_isa_fla
*** 687,717 ****
       detection because one way or another we can't tell if it's available
       or not.  */
  
    for (auto &opt : all_extensions)
!     {
!       auto flags = opt.flag_canonical;
!       /* As a special case, don't emit "+noaes" or "+nosha2" when we could emit
! 	 "+nocrypto" instead, in order to support assemblers that predate the
! 	 separate per-feature crypto flags.  Only allow "+nocrypto" when "sm4"
! 	 is not already enabled (to avoid dependending on whether "+nocrypto"
! 	 also disables "sm4").  */
!       if (flags & flags_crypto
! 	  && (flags_crypto & current_flags & ~isa_flags) == flags_crypto
! 	  && !(current_flags & AARCH64_FL_SM4))
! 	  continue;
  
!       if (flags == AARCH64_FL_CRYPTO)
! 	/* If either crypto flag needs removing here, then both do.  */
! 	flags = flags_crypto;
  
!       if (flags & current_flags & ~isa_flags)
  	{
! 	  current_flags &= ~opt.flags_off;
! 	  outstr += "+no";
! 	  outstr += opt.name;
  	}
      }
  
    return outstr;
  }
  
--- 698,740 ----
       detection because one way or another we can't tell if it's available
       or not.  */
  
+   aarch64_feature_flags removed = 0;
    for (auto &opt : all_extensions)
!     if (!opt.flags_alias_preferred_over
! 	&& (opt.flag_canonical & current_flags & ~isa_flags))
!       {
! 	current_flags &= ~opt.flags_off;
! 	removed |= opt.flag_canonical;
!       }
  
!   /* Replace any aliased extensions.  */
!   for (auto alias: all_extensions)
!     {
!       /* Only allow "+nocrypto" when "sm4" is not already enabled
! 	 (to avoid dependending on whether "+nocrypto" also disables "sm4").  */
!       if (alias.flag_canonical == AARCH64_FL_CRYPTO
! 	  && (current_flags & AARCH64_FL_SM4))
! 	continue;
  
!       if (alias.flags_alias_preferred_over /* Check this is an alias.  */
! 	  /* Check we turn off any of the extensions for which we would prefer
! 	     to use the alias.  */
! 	  && (removed & alias.flags_alias_preferred_over)
! 	  /* Check this doesn't turn off more flags than we need.  */
! 	  && (alias.flags_off & isa_flags) == 0)
  	{
! 	  removed &= ~alias.flags_off;
! 	  removed |= alias.flag_canonical;
  	}
      }
  
+   for (auto &opt : all_extensions)
+     if (removed & opt.flag_canonical)
+       {
+ 	outstr += "+no";
+ 	outstr += opt.name;
+       }
+ 
    return outstr;
  }
  
diff -Nrcpad gcc-16-20251214/gcc/common/config/i386/cpuinfo.h gcc-16-20251221/gcc/common/config/i386/cpuinfo.h
*** gcc-16-20251214/gcc/common/config/i386/cpuinfo.h	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/common/config/i386/cpuinfo.h	Sun Dec 21 22:32:06 2025
*************** get_amd_cpu (struct __processor_model *c
*** 319,324 ****
--- 319,332 ----
  	  CHECK___builtin_cpu_is ("znver5");
  	  cpu_model->__cpu_subtype = AMDFAM1AH_ZNVER5;
  	}
+       else if ((model >= 0x50 && model <= 0x5f) ||
+ 	       (model >= 0x80 && model <= 0xcf) ||
+ 	       (model >= 0xd8 && model <= 0xe7))
+ 	{
+ 	  cpu = "znver6";
+ 	  CHECK___builtin_cpu_is ("znver6");
+ 	  cpu_model->__cpu_subtype = AMDFAM1AH_ZNVER6;
+ 	}
        else if (has_cpu_feature (cpu_model, cpu_features2,
  				FEATURE_AVX512VP2INTERSECT))
  	{
*************** get_amd_cpu (struct __processor_model *c
*** 326,331 ****
--- 334,346 ----
  	  CHECK___builtin_cpu_is ("znver5");
  	  cpu_model->__cpu_subtype = AMDFAM1AH_ZNVER5;
  	}
+       else if (has_cpu_feature (cpu_model, cpu_features2,
+ 				FEATURE_AVX512BMM))
+ 	{
+ 	  cpu = "znver6";
+ 	  CHECK___builtin_cpu_is ("znver6");
+ 	  cpu_model->__cpu_subtype = AMDFAM1AH_ZNVER6;
+ 	}
        break;
      default:
        break;
*************** get_available_features (struct __process
*** 1049,1054 ****
--- 1064,1079 ----
  	}
      }
  
+   /* Get Advanced Features at level 0x21 (eax = 0x21).  */
+   if (max_cpuid_level >= 0x21)
+     {
+       __cpuid (0x21, eax, ebx, ecx, edx);
+       if (eax & bit_AVX512BMM)
+ 	{
+ 	  set_feature (FEATURE_AVX512BMM);
+ 	}
+     }
+ 
    /* Get Advanced Features at level 0x24 (eax = 0x24, ecx = 0).  */
    if (avx10_set && max_cpuid_level >= 0x24)
      {
diff -Nrcpad gcc-16-20251214/gcc/common/config/i386/i386-common.cc gcc-16-20251221/gcc/common/config/i386/i386-common.cc
*** gcc-16-20251214/gcc/common/config/i386/i386-common.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/common/config/i386/i386-common.cc	Sun Dec 21 22:32:06 2025
*************** along with GCC; see the file COPYING3.
*** 139,144 ****
--- 139,145 ----
  #define OPTION_MASK_ISA2_MOVRS_SET OPTION_MASK_ISA2_MOVRS
  #define OPTION_MASK_ISA2_AMX_MOVRS_SET \
    (OPTION_MASK_ISA2_AMX_TILE_SET | OPTION_MASK_ISA2_AMX_MOVRS)
+ #define OPTION_MASK_ISA2_AVX512BMM_SET OPTION_MASK_ISA2_AVX512BMM
  
  /* SSE4 includes both SSE4.1 and SSE4.2. -msse4 should be the same
     as -msse4.2.  */
*************** along with GCC; see the file COPYING3.
*** 265,277 ****
  #define OPTION_MASK_ISA2_AVXIFMA_UNSET OPTION_MASK_ISA2_AVXIFMA
  #define OPTION_MASK_ISA_AVX512VBMI_UNSET OPTION_MASK_ISA_AVX512VBMI
  #define OPTION_MASK_ISA_AVX512VBMI2_UNSET OPTION_MASK_ISA_AVX512VBMI2
! #define OPTION_MASK_ISA_AVX512FP16_UNSET OPTION_MASK_ISA_AVX512BW_UNSET
! #define OPTION_MASK_ISA2_AVX512FP16_UNSET OPTION_MASK_ISA2_AVX512FP16
  #define OPTION_MASK_ISA_AVX512VNNI_UNSET OPTION_MASK_ISA_AVX512VNNI
  #define OPTION_MASK_ISA2_AVXVNNI_UNSET OPTION_MASK_ISA2_AVXVNNI
  #define OPTION_MASK_ISA_AVX512VPOPCNTDQ_UNSET OPTION_MASK_ISA_AVX512VPOPCNTDQ
  #define OPTION_MASK_ISA_AVX512BITALG_UNSET OPTION_MASK_ISA_AVX512BITALG
! #define OPTION_MASK_ISA2_AVX512BF16_UNSET OPTION_MASK_ISA2_AVX512BF16
  #define OPTION_MASK_ISA_RTM_UNSET OPTION_MASK_ISA_RTM
  #define OPTION_MASK_ISA_PRFCHW_UNSET OPTION_MASK_ISA_PRFCHW
  #define OPTION_MASK_ISA_RDSEED_UNSET OPTION_MASK_ISA_RDSEED
--- 266,279 ----
  #define OPTION_MASK_ISA2_AVXIFMA_UNSET OPTION_MASK_ISA2_AVXIFMA
  #define OPTION_MASK_ISA_AVX512VBMI_UNSET OPTION_MASK_ISA_AVX512VBMI
  #define OPTION_MASK_ISA_AVX512VBMI2_UNSET OPTION_MASK_ISA_AVX512VBMI2
! #define OPTION_MASK_ISA2_AVX512FP16_UNSET \
!   (OPTION_MASK_ISA2_AVX512FP16 | OPTION_MASK_ISA2_AVX10_1_UNSET)
  #define OPTION_MASK_ISA_AVX512VNNI_UNSET OPTION_MASK_ISA_AVX512VNNI
  #define OPTION_MASK_ISA2_AVXVNNI_UNSET OPTION_MASK_ISA2_AVXVNNI
  #define OPTION_MASK_ISA_AVX512VPOPCNTDQ_UNSET OPTION_MASK_ISA_AVX512VPOPCNTDQ
  #define OPTION_MASK_ISA_AVX512BITALG_UNSET OPTION_MASK_ISA_AVX512BITALG
! #define OPTION_MASK_ISA2_AVX512BF16_UNSET \
!   (OPTION_MASK_ISA2_AVX512BF16 | OPTION_MASK_ISA2_AVX10_1_UNSET)
  #define OPTION_MASK_ISA_RTM_UNSET OPTION_MASK_ISA_RTM
  #define OPTION_MASK_ISA_PRFCHW_UNSET OPTION_MASK_ISA_PRFCHW
  #define OPTION_MASK_ISA_RDSEED_UNSET OPTION_MASK_ISA_RDSEED
*************** along with GCC; see the file COPYING3.
*** 331,336 ****
--- 333,339 ----
  #define OPTION_MASK_ISA2_AMX_FP8_UNSET OPTION_MASK_ISA2_AMX_FP8
  #define OPTION_MASK_ISA2_MOVRS_UNSET OPTION_MASK_ISA2_MOVRS
  #define OPTION_MASK_ISA2_AMX_MOVRS_UNSET OPTION_MASK_ISA2_AMX_MOVRS
+ #define OPTION_MASK_ISA2_AVX512BMM_UNSET OPTION_MASK_ISA2_AVX512BMM
  
  /* SSE4 includes both SSE4.1 and SSE4.2.  -mno-sse4 should the same
     as -mno-sse4.1. */
*************** along with GCC; see the file COPYING3.
*** 393,399 ****
  
  #define OPTION_MASK_ISA2_AVX512BW_UNSET \
    (OPTION_MASK_ISA2_AVX512BF16_UNSET \
!     | OPTION_MASK_ISA2_AVX512FP16_UNSET)
  
  /* Set 1 << value as value of -malign-FLAG option.  */
  
--- 396,413 ----
  
  #define OPTION_MASK_ISA2_AVX512BW_UNSET \
    (OPTION_MASK_ISA2_AVX512BF16_UNSET \
!     | OPTION_MASK_ISA2_AVX512FP16_UNSET \
!     | OPTION_MASK_ISA2_AVX10_1_UNSET \
!     | OPTION_MASK_ISA2_AVX512BMM_UNSET)
! #define OPTION_MASK_ISA2_AVX512CD_UNSET OPTION_MASK_ISA2_AVX10_1_UNSET
! #define OPTION_MASK_ISA2_AVX512DQ_UNSET OPTION_MASK_ISA2_AVX10_1_UNSET
! #define OPTION_MASK_ISA2_AVX512VL_UNSET OPTION_MASK_ISA2_AVX10_1_UNSET
! #define OPTION_MASK_ISA2_AVX512IFMA_UNSET OPTION_MASK_ISA2_AVX10_1_UNSET
! #define OPTION_MASK_ISA2_AVX512VNNI_UNSET OPTION_MASK_ISA2_AVX10_1_UNSET
! #define OPTION_MASK_ISA2_AVX512VPOPCNTDQ_UNSET OPTION_MASK_ISA2_AVX10_1_UNSET
! #define OPTION_MASK_ISA2_AVX512VBMI_UNSET OPTION_MASK_ISA2_AVX10_1_UNSET
! #define OPTION_MASK_ISA2_AVX512VBMI2_UNSET OPTION_MASK_ISA2_AVX10_1_UNSET
! #define OPTION_MASK_ISA2_AVX512BITALG_UNSET OPTION_MASK_ISA2_AVX10_1_UNSET
  
  /* Set 1 << value as value of -malign-FLAG option.  */
  
*************** ix86_handle_option (struct gcc_options *
*** 645,650 ****
--- 659,666 ----
  	{
  	  opts->x_ix86_isa_flags &= ~OPTION_MASK_ISA_AVX512CD_UNSET;
  	  opts->x_ix86_isa_flags_explicit |= OPTION_MASK_ISA_AVX512CD_UNSET;
+ 	  opts->x_ix86_isa_flags2 &= ~OPTION_MASK_ISA2_AVX512CD_UNSET;
+ 	  opts->x_ix86_isa_flags2_explicit |= OPTION_MASK_ISA2_AVX512CD_UNSET;
  	}
        return true;
  
*************** ix86_handle_option (struct gcc_options *
*** 863,868 ****
--- 879,887 ----
  	{
  	  opts->x_ix86_isa_flags &= ~OPTION_MASK_ISA_AVX512VBMI2_UNSET;
  	  opts->x_ix86_isa_flags_explicit |= OPTION_MASK_ISA_AVX512VBMI2_UNSET;
+ 	  opts->x_ix86_isa_flags2 &= ~OPTION_MASK_ISA2_AVX512VBMI2_UNSET;
+ 	  opts->x_ix86_isa_flags2_explicit
+ 	    |= OPTION_MASK_ISA2_AVX512VBMI2_UNSET;
  	}
        return true;
  
*************** ix86_handle_option (struct gcc_options *
*** 891,896 ****
--- 910,918 ----
  	{
  	  opts->x_ix86_isa_flags &= ~OPTION_MASK_ISA_AVX512VNNI_UNSET;
  	  opts->x_ix86_isa_flags_explicit |= OPTION_MASK_ISA_AVX512VNNI_UNSET;
+ 	  opts->x_ix86_isa_flags2 &= ~OPTION_MASK_ISA2_AVX512VNNI_UNSET;
+ 	  opts->x_ix86_isa_flags2_explicit
+ 	    |= OPTION_MASK_ISA2_AVX512VNNI_UNSET;
  	}
        return true;
  
*************** ix86_handle_option (struct gcc_options *
*** 906,911 ****
--- 928,936 ----
  	  opts->x_ix86_isa_flags &= ~OPTION_MASK_ISA_AVX512VPOPCNTDQ_UNSET;
  	  opts->x_ix86_isa_flags_explicit
  	    |= OPTION_MASK_ISA_AVX512VPOPCNTDQ_UNSET;
+ 	  opts->x_ix86_isa_flags2 &= ~OPTION_MASK_ISA2_AVX512VPOPCNTDQ_UNSET;
+ 	  opts->x_ix86_isa_flags2_explicit
+ 	    |= OPTION_MASK_ISA2_AVX512VPOPCNTDQ_UNSET;
  	}
        return true;
  
*************** ix86_handle_option (struct gcc_options *
*** 920,925 ****
--- 945,953 ----
  	  opts->x_ix86_isa_flags &= ~OPTION_MASK_ISA_AVX512BITALG_UNSET;
  	  opts->x_ix86_isa_flags_explicit
  		|= OPTION_MASK_ISA_AVX512BITALG_UNSET;
+ 	  opts->x_ix86_isa_flags2 &= ~OPTION_MASK_ISA2_AVX512BITALG_UNSET;
+ 	  opts->x_ix86_isa_flags2_explicit
+ 	    |= OPTION_MASK_ISA2_AVX512BITALG_UNSET;
  	}
        return true;
  
*************** ix86_handle_option (struct gcc_options *
*** 938,943 ****
--- 966,986 ----
  	}
        return true;
  
+     case OPT_mavx512bmm:
+       if (value)
+ 	{
+ 	  opts->x_ix86_isa_flags2 |= OPTION_MASK_ISA2_AVX512BMM_SET;
+ 	  opts->x_ix86_isa_flags2_explicit |= OPTION_MASK_ISA2_AVX512BMM_SET;
+ 	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_AVX512BW_SET;
+ 	  opts->x_ix86_isa_flags_explicit |= OPTION_MASK_ISA_AVX512BW_SET;
+ 	}
+       else
+ 	{
+ 	  opts->x_ix86_isa_flags2 &= ~OPTION_MASK_ISA2_AVX512BMM_UNSET;
+ 	  opts->x_ix86_isa_flags2_explicit |= OPTION_MASK_ISA2_AVX512BMM_UNSET;
+ 	}
+       return true;
+ 
      case OPT_mavxvnni:
        if (value)
  	{
*************** ix86_handle_option (struct gcc_options *
*** 1002,1007 ****
--- 1045,1052 ----
  	{
  	  opts->x_ix86_isa_flags &= ~OPTION_MASK_ISA_AVX512DQ_UNSET;
  	  opts->x_ix86_isa_flags_explicit |= OPTION_MASK_ISA_AVX512DQ_UNSET;
+ 	  opts->x_ix86_isa_flags2 &= ~OPTION_MASK_ISA2_AVX512DQ_UNSET;
+ 	  opts->x_ix86_isa_flags2_explicit |= OPTION_MASK_ISA2_AVX512DQ_UNSET;
  	}
        return true;
  
*************** ix86_handle_option (struct gcc_options *
*** 1030,1035 ****
--- 1075,1082 ----
  	{
  	  opts->x_ix86_isa_flags &= ~OPTION_MASK_ISA_AVX512VL_UNSET;
  	  opts->x_ix86_isa_flags_explicit |= OPTION_MASK_ISA_AVX512VL_UNSET;
+ 	  opts->x_ix86_isa_flags2 &= ~OPTION_MASK_ISA2_AVX512VL_UNSET;
+ 	  opts->x_ix86_isa_flags2_explicit |= OPTION_MASK_ISA2_AVX512VL_UNSET;
  	}
        return true;
  
*************** ix86_handle_option (struct gcc_options *
*** 1043,1048 ****
--- 1090,1098 ----
  	{
  	  opts->x_ix86_isa_flags &= ~OPTION_MASK_ISA_AVX512IFMA_UNSET;
  	  opts->x_ix86_isa_flags_explicit |= OPTION_MASK_ISA_AVX512IFMA_UNSET;
+ 	  opts->x_ix86_isa_flags2 &= ~OPTION_MASK_ISA2_AVX512IFMA_UNSET;
+ 	  opts->x_ix86_isa_flags2_explicit
+ 	    |= OPTION_MASK_ISA2_AVX512IFMA_UNSET;
  	}
        return true;
  
*************** ix86_handle_option (struct gcc_options *
*** 1056,1061 ****
--- 1106,1114 ----
  	{
  	  opts->x_ix86_isa_flags &= ~OPTION_MASK_ISA_AVX512VBMI_UNSET;
  	  opts->x_ix86_isa_flags_explicit |= OPTION_MASK_ISA_AVX512VBMI_UNSET;
+ 	  opts->x_ix86_isa_flags2 &= ~OPTION_MASK_ISA2_AVX512VBMI_UNSET;
+ 	  opts->x_ix86_isa_flags2_explicit
+ 	    |= OPTION_MASK_ISA2_AVX512VBMI_UNSET;
  	}
        return true;
  
*************** const char *const processor_names[] =
*** 2151,2157 ****
    "znver2",
    "znver3",
    "znver4",
!   "znver5"
  };
  
  /* Guarantee that the array is aligned with enum processor_type.  */
--- 2204,2211 ----
    "znver2",
    "znver3",
    "znver4",
!   "znver5",
!   "znver6"
  };
  
  /* Guarantee that the array is aligned with enum processor_type.  */
*************** const pta processor_alias_table[] =
*** 2410,2415 ****
--- 2464,2472 ----
    {"znver5", PROCESSOR_ZNVER5, CPU_ZNVER5,
      PTA_ZNVER5,
      M_CPU_SUBTYPE (AMDFAM1AH_ZNVER5), P_PROC_AVX512F},
+   {"znver6", PROCESSOR_ZNVER6, CPU_ZNVER5,
+     PTA_ZNVER6,
+     M_CPU_SUBTYPE (AMDFAM1AH_ZNVER6), P_PROC_AVX512F},
    {"btver1", PROCESSOR_BTVER1, CPU_GENERIC,
      PTA_BTVER1,
      M_CPU_TYPE (AMD_BTVER1), P_PROC_SSE4_A},
diff -Nrcpad gcc-16-20251214/gcc/common/config/i386/i386-cpuinfo.h gcc-16-20251221/gcc/common/config/i386/i386-cpuinfo.h
*** gcc-16-20251214/gcc/common/config/i386/i386-cpuinfo.h	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/common/config/i386/i386-cpuinfo.h	Sun Dec 21 22:32:06 2025
*************** enum processor_subtypes
*** 107,112 ****
--- 107,113 ----
    ZHAOXIN_FAM7H_SHIJIDADAO,
    INTEL_COREI7_DIAMONDRAPIDS,
    INTEL_COREI7_NOVALAKE,
+   AMDFAM1AH_ZNVER6,
    CPU_SUBTYPE_MAX
  };
  
*************** enum processor_features
*** 273,278 ****
--- 274,280 ----
    FEATURE_AMX_FP8 = 120,
    FEATURE_MOVRS,
    FEATURE_AMX_MOVRS,
+   FEATURE_AVX512BMM,
    CPU_FEATURE_MAX
  };
  
diff -Nrcpad gcc-16-20251214/gcc/common/config/i386/i386-isas.h gcc-16-20251221/gcc/common/config/i386/i386-isas.h
*** gcc-16-20251214/gcc/common/config/i386/i386-isas.h	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/common/config/i386/i386-isas.h	Sun Dec 21 22:32:06 2025
*************** ISA_NAMES_TABLE_START
*** 191,194 ****
--- 191,195 ----
    ISA_NAMES_TABLE_ENTRY("amx-fp8", FEATURE_AMX_FP8, P_NONE, "-mamx-fp8")
    ISA_NAMES_TABLE_ENTRY("movrs", FEATURE_MOVRS, P_NONE, "-mmovrs")
    ISA_NAMES_TABLE_ENTRY("amx-movrs", FEATURE_AMX_MOVRS, P_NONE, "-mamx-movrs")
+   ISA_NAMES_TABLE_ENTRY("avx512bmm", FEATURE_AVX512BMM, P_NONE, "-mavx512bmm")
  ISA_NAMES_TABLE_END
diff -Nrcpad gcc-16-20251214/gcc/common.opt gcc-16-20251221/gcc/common.opt
*** gcc-16-20251214/gcc/common.opt	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/common.opt	Sun Dec 21 22:32:06 2025
*************** floop-nest-optimize
*** 1937,1942 ****
--- 1937,1946 ----
  Common Var(flag_loop_nest_optimize) Optimization
  Enable the loop nest optimizer.
  
+ fspeculatively-call-stored-functions
+ Common Var(flag_speculatively_call_stored_functions) Optimization
+ Turn indirect calls of pointers loaded from structures to speculative calls if there is one known candidate.
+ 
  fstrict-volatile-bitfields
  Common Var(flag_strict_volatile_bitfields) Init(-1) Optimization
  Force bitfield accesses to match their type width.
diff -Nrcpad gcc-16-20251214/gcc/common.opt.urls gcc-16-20251221/gcc/common.opt.urls
*** gcc-16-20251214/gcc/common.opt.urls	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/common.opt.urls	Sun Dec 21 22:32:06 2025
*************** UrlSuffix(gcc/Code-Gen-Options.html#inde
*** 836,841 ****
--- 836,844 ----
  floop-nest-optimize
  UrlSuffix(gcc/Optimize-Options.html#index-floop-nest-optimize)
  
+ fspeculatively-call-stored-functions
+ UrlSuffix(gcc/Optimize-Options.html#index-fspeculatively-call-stored-functions)
+ 
  fstrict-volatile-bitfields
  UrlSuffix(gcc/Code-Gen-Options.html#index-fstrict-volatile-bitfields)
  
diff -Nrcpad gcc-16-20251214/gcc/config/aarch64/aarch64-arches.def gcc-16-20251221/gcc/config/aarch64/aarch64-arches.def
*** gcc-16-20251214/gcc/config/aarch64/aarch64-arches.def	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/aarch64/aarch64-arches.def	Sun Dec 21 22:32:06 2025
*************** AARCH64_ARCH("armv9.2-a",     generic_ar
*** 47,51 ****
--- 47,52 ----
  AARCH64_ARCH("armv9.3-a",     generic_armv9_a,   V9_3A,     9,  (V8_8A, V9_2A))
  AARCH64_ARCH("armv9.4-a",     generic_armv9_a,   V9_4A,     9,  (V8_9A, V9_3A, SVE2p1))
  AARCH64_ARCH("armv9.5-a",     generic_armv9_a,   V9_5A,     9,  (V9_4A, CPA, FAMINMAX, LUT))
+ AARCH64_ARCH("armv9.6-a",     generic_armv9_a,   V9_6A,     9,  (V9_5A, CMPBR, LSUI, OCCMO))
  
  #undef AARCH64_ARCH
diff -Nrcpad gcc-16-20251214/gcc/config/aarch64/aarch64-builtins.cc gcc-16-20251221/gcc/config/aarch64/aarch64-builtins.cc
*** gcc-16-20251214/gcc/config/aarch64/aarch64-builtins.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/aarch64/aarch64-builtins.cc	Sun Dec 21 22:32:06 2025
*************** aarch64_expand_builtin_memtag (int fcode
*** 3713,3720 ****
  	pat = GEN_FCN (icode) (target, op0, const0_rtx);
  	break;
        case AARCH64_MEMTAG_BUILTIN_SET_TAG:
! 	pat = GEN_FCN (icode) (op0, op0, const0_rtx);
! 	break;
        default:
  	gcc_unreachable();
      }
--- 3713,3723 ----
  	pat = GEN_FCN (icode) (target, op0, const0_rtx);
  	break;
        case AARCH64_MEMTAG_BUILTIN_SET_TAG:
! 	{
! 	  rtx mem = gen_rtx_MEM (TImode, op0);
! 	  pat = GEN_FCN (icode) (mem, op0);
! 	  break;
! 	}
        default:
  	gcc_unreachable();
      }
diff -Nrcpad gcc-16-20251214/gcc/config/aarch64/aarch64-c.cc gcc-16-20251221/gcc/config/aarch64/aarch64-c.cc
*** gcc-16-20251214/gcc/config/aarch64/aarch64-c.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/aarch64/aarch64-c.cc	Sun Dec 21 22:32:06 2025
*************** aarch64_update_cpp_builtins (cpp_reader
*** 199,204 ****
--- 199,205 ----
    aarch64_def_or_undef (TARGET_SVE, "__ARM_FEATURE_SVE", pfile);
    cpp_undef (pfile, "__ARM_FEATURE_SVE_BITS");
    cpp_undef (pfile, "__ARM_FEATURE_SVE_VECTOR_OPERATORS");
+   cpp_undef (pfile, "__ARM_FEATURE_SVE_PREDICATE_OPERATORS");
    if (TARGET_SVE)
      {
        int bits;
*************** aarch64_update_cpp_builtins (cpp_reader
*** 210,215 ****
--- 211,218 ----
  	}
        builtin_define_with_int_value ("__ARM_FEATURE_SVE_BITS", bits);
        builtin_define_with_int_value ("__ARM_FEATURE_SVE_VECTOR_OPERATORS", ops);
+       builtin_define_with_int_value ("__ARM_FEATURE_SVE_PREDICATE_OPERATORS",
+ 				     ops);
      }
    aarch64_def_or_undef (TARGET_SVE_I8MM,
  			"__ARM_FEATURE_SVE_MATMUL_INT8", pfile);
diff -Nrcpad gcc-16-20251214/gcc/config/aarch64/aarch64-cores.def gcc-16-20251221/gcc/config/aarch64/aarch64-cores.def
*** gcc-16-20251214/gcc/config/aarch64/aarch64-cores.def	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/aarch64/aarch64-cores.def	Sun Dec 21 22:32:06 2025
*************** AARCH64_CORE("cortex-a720",  cortexa720,
*** 213,218 ****
--- 213,220 ----
  AARCH64_CORE("cortex-a720ae",  cortexa720ae, cortexa57, V9_2A,  (SVE2_BITPERM, MEMTAG, PROFILE), neoversen2, 0x41, 0xd89, -1)
  AARCH64_CORE("cortex-a725",  cortexa725, cortexa57, V9_2A, (SVE2_BITPERM, MEMTAG, PROFILE), neoversen3, 0x41, 0xd87, -1)
  
+ AARCH64_CORE("cortex-a320", cortexa320, cortexa53, V9_2A, (SVE2_BITPERM, MEMTAG), cortexa53, 0x41, 0xd8f, -1)
+ 
  AARCH64_CORE("cortex-x2",  cortexx2, cortexa57, V9A,  (SVE2_BITPERM, MEMTAG, I8MM, BF16), neoversen2, 0x41, 0xd48, -1)
  
  AARCH64_CORE("cortex-x3",  cortexx3, cortexa57, V9A,  (SVE2_BITPERM, MEMTAG, I8MM, BF16), neoversev2, 0x41, 0xd4e, -1)
diff -Nrcpad gcc-16-20251214/gcc/config/aarch64/aarch64-feature-deps.h gcc-16-20251221/gcc/config/aarch64/aarch64-feature-deps.h
*** gcc-16-20251214/gcc/config/aarch64/aarch64-feature-deps.h	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/aarch64/aarch64-feature-deps.h	Sun Dec 21 22:32:06 2025
*************** get_enable (T1 i, Ts... args)
*** 66,77 ****
     files are in topological order.  */
  template<aarch64_feature> struct info;
  
  #define HANDLE(IDENT, REQUIRES, EXPLICIT_ON)				\
    template<> struct info<aarch64_feature::IDENT> {			\
      static constexpr auto flag = AARCH64_FL_##IDENT;			\
      static constexpr auto enable = flag | get_enable REQUIRES;		\
!     static constexpr auto explicit_on                                   \
!       = (enable | get_enable EXPLICIT_ON) & ~AARCH64_FL_CRYPTO;         \
    };									\
    constexpr aarch64_feature_flags info<aarch64_feature::IDENT>::flag;	\
    constexpr aarch64_feature_flags info<aarch64_feature::IDENT>::enable;	\
--- 66,83 ----
     files are in topological order.  */
  template<aarch64_feature> struct info;
  
+   constexpr auto alias_flags = aarch64_feature_flags (0)
+ #define AARCH64_OPT_EXTENSION_ALIAS(A, IDENT, C, D, E, F, G) | AARCH64_FL_##IDENT
+ #define AARCH64_OPT_EXTENSION(A, IDENT, C, D, E, F)
+ #include "config/aarch64/aarch64-option-extensions.def"
+ ;
+ 
  #define HANDLE(IDENT, REQUIRES, EXPLICIT_ON)				\
    template<> struct info<aarch64_feature::IDENT> {			\
      static constexpr auto flag = AARCH64_FL_##IDENT;			\
      static constexpr auto enable = flag | get_enable REQUIRES;		\
!     static constexpr auto explicit_on					\
!       = (enable | get_enable EXPLICIT_ON) & ~alias_flags;		\
    };									\
    constexpr aarch64_feature_flags info<aarch64_feature::IDENT>::flag;	\
    constexpr aarch64_feature_flags info<aarch64_feature::IDENT>::enable;	\
*************** get_flags_off (aarch64_feature_flags mas
*** 116,126 ****
  #include "config/aarch64/aarch64-option-extensions.def"
  
  /* Define cpu_<NAME> variables for each CPU, giving the transitive
!    closure of all the features that the CPU supports.  The CRYPTO bit is just
!    an alias, so explicitly unset it for consistency.  */
  #define AARCH64_CORE(A, CORE_IDENT, C, ARCH_IDENT, FEATURES, F, G, H, I) \
    constexpr auto cpu_##CORE_IDENT \
!     = (ARCH_IDENT ().enable | get_enable FEATURES) & ~AARCH64_FL_CRYPTO;
  #include "config/aarch64/aarch64-cores.def"
  
  /* Define fmv_deps_<NAME> variables for each FMV feature, giving the transitive
--- 122,132 ----
  #include "config/aarch64/aarch64-option-extensions.def"
  
  /* Define cpu_<NAME> variables for each CPU, giving the transitive
!    closure of all the features that the CPU supports.  The alias flags are
!    explicitly unset for consistency.  */
  #define AARCH64_CORE(A, CORE_IDENT, C, ARCH_IDENT, FEATURES, F, G, H, I) \
    constexpr auto cpu_##CORE_IDENT \
!     = (ARCH_IDENT ().enable | get_enable FEATURES) & ~alias_flags;
  #include "config/aarch64/aarch64-cores.def"
  
  /* Define fmv_deps_<NAME> variables for each FMV feature, giving the transitive
*************** get_flags_off (aarch64_feature_flags mas
*** 129,135 ****
    constexpr auto fmv_deps_##FEAT_NAME = get_enable OPT_FLAGS;
  #include "config/aarch64/aarch64-option-extensions.def"
  
! 
  }
  }
  
--- 135,146 ----
    constexpr auto fmv_deps_##FEAT_NAME = get_enable OPT_FLAGS;
  #include "config/aarch64/aarch64-option-extensions.def"
  
! #define AARCH64_OPT_EXTENSION_ALIAS(A, IDENT, OPT_FLAGS, D, E, \
! 				    PREFER_FLAGS, G) \
!   constexpr auto alias_prefer_over_flags_##IDENT = get_flags PREFER_FLAGS;
! #define AARCH64_OPT_EXTENSION(A, IDENT, C, D, E, F) \
!   constexpr aarch64_feature_flags alias_prefer_over_flags_##IDENT = 0;
! #include "config/aarch64/aarch64-option-extensions.def"
  }
  }
  
diff -Nrcpad gcc-16-20251214/gcc/config/aarch64/aarch64-linux.h gcc-16-20251221/gcc/config/aarch64/aarch64-linux.h
*** gcc-16-20251214/gcc/config/aarch64/aarch64-linux.h	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/aarch64/aarch64-linux.h	Sun Dec 21 22:32:06 2025
***************
*** 48,54 ****
     %{static-pie:-Bstatic -pie --no-dynamic-linker -z text} \
     -X						\
     %{mbig-endian:-EB} %{mlittle-endian:-EL}     \
!    -maarch64linux%{mabi=ilp32:32}%{mbig-endian:b}"
  
  
  #define LINK_SPEC LINUX_TARGET_LINK_SPEC AARCH64_ERRATA_LINK_SPEC
--- 48,56 ----
     %{static-pie:-Bstatic -pie --no-dynamic-linker -z text} \
     -X						\
     %{mbig-endian:-EB} %{mlittle-endian:-EL}     \
!    -maarch64linux%{mabi=ilp32:32}%{mbig-endian:b} \
!    %{%:sanitize(memtag-stack):%{!fsanitize-memtag-mode:-z memtag-stack -z memtag-mode=sync}} \
!    %{%:sanitize(memtag-stack):%{fsanitize-memtag-mode=*:-z memtag-stack -z memtag-mode=%}}"
  
  
  #define LINK_SPEC LINUX_TARGET_LINK_SPEC AARCH64_ERRATA_LINK_SPEC
diff -Nrcpad gcc-16-20251214/gcc/config/aarch64/aarch64-option-extensions.def gcc-16-20251221/gcc/config/aarch64/aarch64-option-extensions.def
*** gcc-16-20251214/gcc/config/aarch64/aarch64-option-extensions.def	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/aarch64/aarch64-option-extensions.def	Sun Dec 21 22:32:06 2025
***************
*** 25,30 ****
--- 25,33 ----
        AARCH64_OPT_EXTENSION(NAME, IDENT, REQUIRES, EXPLICIT_ON,
  			    EXPLICIT_OFF, FEATURE_STRING)
  
+       AARCH64_OPT_EXTENSION_ALIAS(NAME, IDENT, REQUIRES, EXPLICIT_ON,
+ 				  EXPLICIT_OFF, PREFER_OVER, FEATURE_STRING)
+ 
        AARCH64_FMV_FEATURE(NAME, FEAT_NAME, IDENT)
  
     - NAME is the name of the extension, represented as a string constant.
***************
*** 66,71 ****
--- 69,78 ----
     - OPT_FLAGS is a list of feature IDENTS that should be enabled (along with
       their transitive dependencies) when the specified FMV feature is present.
  
+    - PREFER_OVER is a list of features that need to be present when emitting
+      the list of architecture feature options for the alias option to be
+      preferred instead.
+ 
     Where a feature is present as both an extension and a function
     multiversioning feature, and IDENT matches the FEAT_NAME suffix, then these
     can be listed here simultaneously using the macro:
***************
*** 88,93 ****
--- 95,108 ----
  			      EXPLICIT_OFF, FEATURE_STRING)
  #endif
  
+ #ifndef AARCH64_OPT_EXTENSION_ALIAS
+ #define AARCH64_OPT_EXTENSION_ALIAS(NAME, IDENT, REQUIRES, EXPLICIT_ON, \
+ 				    EXPLICIT_OFF, PREFERRED_OVER, \
+ 				    FEATURE_STRING) \
+ AARCH64_OPT_EXTENSION(NAME, IDENT, REQUIRES, EXPLICIT_ON, EXPLICIT_OFF, \
+ 		      FEATURE_STRING)
+ #endif
+ 
  #ifndef AARCH64_FMV_FEATURE
  #define AARCH64_FMV_FEATURE(NAME, FEAT_NAME, OPT_FLAGS)
  #endif
*************** AARCH64_FMV_FEATURE("aes", PMULL, (AES))
*** 134,144 ****
  
  /* +nocrypto disables AES, SHA2 and SM4, and anything that depends on them
     (such as SHA3 and the SVE2 crypto extensions).  */
! AARCH64_OPT_EXTENSION("crypto", CRYPTO, (AES, SHA2), (), (AES, SHA2, SM4),
! 		      "aes pmull sha1 sha2")
  
- /* Listing sha3 after crypto means we pass "+aes+sha3" to the assembler
-    instead of "+sha3+crypto".  */
  AARCH64_OPT_EXTENSION("sha3", SHA3, (SHA2), (), (), "sha3 sha512")
  
  /* +nofp16 disables an implicit F16FML, even though an implicit F16FML
--- 149,157 ----
  
  /* +nocrypto disables AES, SHA2 and SM4, and anything that depends on them
     (such as SHA3 and the SVE2 crypto extensions).  */
! AARCH64_OPT_EXTENSION_ALIAS("crypto", CRYPTO, (AES, SHA2), (), (AES, SHA2, SM4),
! 			    (AES, SHA2), "aes pmull sha1 sha2")
  
  AARCH64_OPT_EXTENSION("sha3", SHA3, (SHA2), (), (), "sha3 sha512")
  
  /* +nofp16 disables an implicit F16FML, even though an implicit F16FML
*************** AARCH64_FMV_FEATURE("f64mm", SVE_F64MM,
*** 194,215 ****
  
  AARCH64_OPT_FMV_EXTENSION("sve2", SVE2, (SVE), (), (), "sve2")
  
! AARCH64_OPT_EXTENSION("sve2-aes", SVE2_AES, (SVE2, AES), (), (), "sveaes")
  
! AARCH64_FMV_FEATURE("sve2-aes", SVE_PMULL128, (SVE2_AES))
  
! AARCH64_OPT_EXTENSION("sve2-bitperm", SVE2_BITPERM, (SVE2), (), (),
! 		      "svebitperm")
  
! AARCH64_FMV_FEATURE("sve2-bitperm", SVE_BITPERM, (SVE2_BITPERM))
  
! AARCH64_OPT_EXTENSION("sve2-sha3", SVE2_SHA3, (SVE2, SHA3), (), (), "svesha3")
  
! AARCH64_FMV_FEATURE("sve2-sha3", SVE_SHA3, (SVE2_SHA3))
  
! AARCH64_OPT_EXTENSION("sve2-sm4", SVE2_SM4, (SVE2, SM4), (), (), "svesm4")
  
! AARCH64_FMV_FEATURE("sve2-sm4", SVE_SM4, (SVE2_SM4))
  
  AARCH64_OPT_EXTENSION("sve2p1", SVE2p1, (SVE2), (), (), "sve2p1")
  
--- 207,236 ----
  
  AARCH64_OPT_FMV_EXTENSION("sve2", SVE2, (SVE), (), (), "sve2")
  
! AARCH64_OPT_EXTENSION("sve-aes", SVE_AES, (AES), (), (), "sveaes | smeaes")
  
! AARCH64_OPT_EXTENSION_ALIAS("sve2-aes", SVE2_AES, (SVE2, SVE_AES), (), (SVE_AES), (SVE_AES), "sveaes")
  
! AARCH64_FMV_FEATURE("sve2-aes", SVE_PMULL128, (SVE2, SVE_AES))
  
! AARCH64_OPT_EXTENSION("sve-bitperm", SVE_BITPERM, (), (), (), "svebitperm | smesbitperm")
  
! AARCH64_OPT_EXTENSION_ALIAS("sve2-bitperm", SVE2_BITPERM, (SVE2, SVE_BITPERM), (), (SVE_BITPERM),
! 			    (SVE_BITPERM), "svebitperm")
  
! AARCH64_FMV_FEATURE("sve2-bitperm", SVE_BITPERM, (SVE2, SVE_BITPERM))
  
! AARCH64_OPT_EXTENSION("sve-sha3", SVE_SHA3, (SHA3), (), (), "svesha3")
  
! AARCH64_OPT_EXTENSION_ALIAS("sve2-sha3", SVE2_SHA3, (SVE2, SVE_SHA3), (), (SVE_SHA3), (SVE_SHA3), "svesha3")
! 
! AARCH64_FMV_FEATURE("sve2-sha3", SVE_SHA3, (SVE2, SVE_SHA3))
! 
! AARCH64_OPT_EXTENSION("sve-sm4", SVE_SM4, (SM4), (), (), "svesm4")
! 
! AARCH64_OPT_EXTENSION_ALIAS("sve2-sm4", SVE2_SM4, (SVE2, SVE_SM4), (), (SVE_SM4), (SVE_SM4), "svesm4")
! 
! AARCH64_FMV_FEATURE("sve2-sm4", SVE_SM4, (SVE2, SVE_SM4))
  
  AARCH64_OPT_EXTENSION("sve2p1", SVE2p1, (SVE2), (), (), "sve2p1")
  
*************** AARCH64_OPT_EXTENSION("ssve-fp8dot2", SS
*** 285,294 ****
  
  AARCH64_OPT_EXTENSION("lut", LUT, (SIMD), (), (), "lut")
  
! AARCH64_OPT_EXTENSION ("sme-lutv2", SME_LUTv2, (SME2), (), (), "sme-lutv2")
  
  AARCH64_OPT_EXTENSION("cpa", CPA, (), (), (), "")
  
  #undef AARCH64_OPT_FMV_EXTENSION
  #undef AARCH64_OPT_EXTENSION
  #undef AARCH64_FMV_FEATURE
--- 306,353 ----
  
  AARCH64_OPT_EXTENSION("lut", LUT, (SIMD), (), (), "lut")
  
! AARCH64_OPT_EXTENSION ("sme-lutv2", SME_LUTv2, (SME2), (), (), "smelutv2")
  
  AARCH64_OPT_EXTENSION("cpa", CPA, (), (), (), "")
  
+ AARCH64_OPT_EXTENSION("fprcvt", FPRCVT, (FP), (), (), "fprcvt")
+ 
+ AARCH64_OPT_EXTENSION("lsfe", LSFE, (FP), (), (), "lsfe")
+ 
+ AARCH64_OPT_EXTENSION("f8f32mm", F8F32MM, (SIMD, FP8), (), (), "f8mm8")
+ 
+ AARCH64_OPT_EXTENSION("f8f16mm", F8F16MM, (SIMD, FP8), (), (), "f8mm4")
+ 
+ AARCH64_OPT_EXTENSION("sme2p2", SME2p2, (SME2p1), (), (), "sme2p2")
+ 
+ AARCH64_OPT_EXTENSION("sve2p2", SVE2p2, (SVE2p1), (), (), "sve2p2")
+ 
+ AARCH64_OPT_EXTENSION("sve-aes2", SVE_AES2, (), (), (), "sveaes2")
+ 
+ AARCH64_OPT_EXTENSION("sve-f16f32mm", SVE_F16F32MM, (SVE), (), (), "svef16mm")
+ 
+ AARCH64_OPT_EXTENSION("sve-bfscale", SVE_BFSCALE, (), (), (), "svebfscale")
+ 
+ AARCH64_OPT_EXTENSION("ssve-aes", SSVE_AES, (SME2, SVE_AES), (), (), "smeaes")
+ 
+ AARCH64_OPT_EXTENSION("ssve-bitperm", SSVE_BITPERM, (SME2, SVE_BITPERM), (), (), "smesbitperm")
+ 
+ AARCH64_OPT_EXTENSION("ssve-fexpa", SSVE_FEXPA, (SME2), (), (), "smesfexpa")
+ 
+ AARCH64_OPT_EXTENSION("sme-mop4", SME_MOP4, (SME2), (), (), "smesmop4")
+ 
+ AARCH64_OPT_EXTENSION("sme-tmop", SME_TMOP, (SME2), (), (), "smestmop")
+ 
+ /* FEATURE_STRING not yet defined.  TODO: Update this when that value is decided.  */
+ AARCH64_OPT_EXTENSION("lsui", LSUI, (), (), (), "")
+ 
+ AARCH64_OPT_EXTENSION("occmo", OCCMO, (), (), (), "")
+ 
+ AARCH64_OPT_EXTENSION("pcdphint", PCDPHINT, (), (), (), "")
+ 
+ AARCH64_OPT_EXTENSION("pops", PoPS, (), (), (), "")
+ 
  #undef AARCH64_OPT_FMV_EXTENSION
  #undef AARCH64_OPT_EXTENSION
+ #undef AARCH64_OPT_EXTENSION_ALIAS
  #undef AARCH64_FMV_FEATURE
diff -Nrcpad gcc-16-20251214/gcc/config/aarch64/aarch64-protos.h gcc-16-20251221/gcc/config/aarch64/aarch64-protos.h
*** gcc-16-20251214/gcc/config/aarch64/aarch64-protos.h	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/aarch64/aarch64-protos.h	Sun Dec 21 22:32:06 2025
*************** void aarch64_expand_sve_vec_cmp_float (r
*** 1126,1131 ****
--- 1126,1134 ----
  
  bool aarch64_prepare_sve_int_fma (rtx *, rtx_code);
  bool aarch64_prepare_sve_cond_int_fma (rtx *, rtx_code);
+ 
+ bool aarch64_granule16_memory_address_p (rtx mem);
+ void aarch64_expand_tag_memory (rtx, rtx, rtx);
  #endif /* RTX_CODE */
  
  bool aarch64_process_target_attr (tree);
diff -Nrcpad gcc-16-20251214/gcc/config/aarch64/aarch64-sve-builtins-sve2.def gcc-16-20251221/gcc/config/aarch64/aarch64-sve-builtins-sve2.def
*** gcc-16-20251214/gcc/config/aarch64/aarch64-sve-builtins-sve2.def	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/aarch64/aarch64-sve-builtins-sve2.def	Sun Dec 21 22:32:06 2025
*************** DEF_SVE_FUNCTION (svstnt1w_scatter, stor
*** 193,199 ****
  #undef REQUIRED_EXTENSIONS
  
  #define REQUIRED_EXTENSIONS nonstreaming_sve (AARCH64_FL_SVE2 \
! 					      | AARCH64_FL_SVE2_AES)
  DEF_SVE_FUNCTION (svaesd, binary, b_unsigned, none)
  DEF_SVE_FUNCTION (svaese, binary, b_unsigned, none)
  DEF_SVE_FUNCTION (svaesimc, unary, b_unsigned, none)
--- 193,199 ----
  #undef REQUIRED_EXTENSIONS
  
  #define REQUIRED_EXTENSIONS nonstreaming_sve (AARCH64_FL_SVE2 \
! 					      | AARCH64_FL_SVE_AES)
  DEF_SVE_FUNCTION (svaesd, binary, b_unsigned, none)
  DEF_SVE_FUNCTION (svaese, binary, b_unsigned, none)
  DEF_SVE_FUNCTION (svaesimc, unary, b_unsigned, none)
*************** DEF_SVE_FUNCTION (svpmullt_pair, binary_
*** 203,221 ****
  #undef REQUIRED_EXTENSIONS
  
  #define REQUIRED_EXTENSIONS nonstreaming_sve (AARCH64_FL_SVE2 \
! 					      | AARCH64_FL_SVE2_BITPERM)
  DEF_SVE_FUNCTION (svbdep, binary_opt_n, all_unsigned, none)
  DEF_SVE_FUNCTION (svbext, binary_opt_n, all_unsigned, none)
  DEF_SVE_FUNCTION (svbgrp, binary_opt_n, all_unsigned, none)
  #undef REQUIRED_EXTENSIONS
  
  #define REQUIRED_EXTENSIONS nonstreaming_sve (AARCH64_FL_SVE2 \
! 					      | AARCH64_FL_SVE2_SHA3)
  DEF_SVE_FUNCTION (svrax1, binary, d_integer, none)
  #undef REQUIRED_EXTENSIONS
  
  #define REQUIRED_EXTENSIONS nonstreaming_sve (AARCH64_FL_SVE2 \
! 					      | AARCH64_FL_SVE2_SM4)
  DEF_SVE_FUNCTION (svsm4e, binary, s_unsigned, none)
  DEF_SVE_FUNCTION (svsm4ekey, binary, s_unsigned, none)
  #undef REQUIRED_EXTENSIONS
--- 203,221 ----
  #undef REQUIRED_EXTENSIONS
  
  #define REQUIRED_EXTENSIONS nonstreaming_sve (AARCH64_FL_SVE2 \
! 					      | AARCH64_FL_SVE_BITPERM)
  DEF_SVE_FUNCTION (svbdep, binary_opt_n, all_unsigned, none)
  DEF_SVE_FUNCTION (svbext, binary_opt_n, all_unsigned, none)
  DEF_SVE_FUNCTION (svbgrp, binary_opt_n, all_unsigned, none)
  #undef REQUIRED_EXTENSIONS
  
  #define REQUIRED_EXTENSIONS nonstreaming_sve (AARCH64_FL_SVE2 \
! 					      | AARCH64_FL_SVE_SHA3)
  DEF_SVE_FUNCTION (svrax1, binary, d_integer, none)
  #undef REQUIRED_EXTENSIONS
  
  #define REQUIRED_EXTENSIONS nonstreaming_sve (AARCH64_FL_SVE2 \
! 					      | AARCH64_FL_SVE_SM4)
  DEF_SVE_FUNCTION (svsm4e, binary, s_unsigned, none)
  DEF_SVE_FUNCTION (svsm4ekey, binary, s_unsigned, none)
  #undef REQUIRED_EXTENSIONS
diff -Nrcpad gcc-16-20251214/gcc/config/aarch64/aarch64-tune.md gcc-16-20251221/gcc/config/aarch64/aarch64-tune.md
*** gcc-16-20251214/gcc/config/aarch64/aarch64-tune.md	Sun Dec 14 22:32:20 2025
--- gcc-16-20251221/gcc/config/aarch64/aarch64-tune.md	Sun Dec 21 22:32:18 2025
***************
*** 1,5 ****
  ;; -*- buffer-read-only: t -*-
  ;; Generated automatically by gentune.sh from aarch64-cores.def
  (define_attr "tune"
! 	"cortexa34,cortexa35,cortexa53,cortexa57,cortexa72,cortexa73,thunderx,thunderxt88,thunderxt88p1,octeontx,octeontxt81,octeontxt83,thunderxt81,thunderxt83,ampere1,ampere1a,ampere1b,ampere1c,emag,xgene1,falkor,qdf24xx,exynosm1,phecda,thunderx2t99p1,vulcan,thunderx2t99,cortexa55,cortexa75,cortexa76,cortexa76ae,cortexa77,cortexa78,cortexa78ae,cortexa78c,cortexa65,cortexa65ae,cortexx1,cortexx1c,neoversen1,ares,neoversee1,octeontx2,octeontx2t98,octeontx2t96,octeontx2t93,octeontx2f95,octeontx2f95n,octeontx2f95mm,a64fx,fujitsu_monaka,tsv110,thunderx3t110,neoversev1,zeus,neoverse512tvb,saphira,oryon1,cortexa57cortexa53,cortexa72cortexa53,cortexa73cortexa35,cortexa73cortexa53,cortexa75cortexa55,cortexa76cortexa55,cortexr82,cortexr82ae,applea12,applem1_0,applem1_1,applem1_2,applem1_3,applem2_0,applem2_1,applem2_2,applem2_3,applem3_0,applem3_1,applem3_2,applem4_0,applem4_1,applem4_2,cortexa510,cortexa520,cortexa520ae,cortexa710,cortexa715,cortexa720,cortexa720ae,cortexa725,cortexx2,cortexx3,cortexx4,cortexx925,neoversen2,cobalt100,neoversen3,neoversev2,grace,neoversev3,neoversev3ae,c1nano,c1pro,c1premium,c1ultra,demeter,olympus,gb10,generic,generic_armv8_a,generic_armv9_a"
  	(const (symbol_ref "((enum attr_tune) aarch64_tune)")))
--- 1,5 ----
  ;; -*- buffer-read-only: t -*-
  ;; Generated automatically by gentune.sh from aarch64-cores.def
  (define_attr "tune"
! 	"cortexa34,cortexa35,cortexa53,cortexa57,cortexa72,cortexa73,thunderx,thunderxt88,thunderxt88p1,octeontx,octeontxt81,octeontxt83,thunderxt81,thunderxt83,ampere1,ampere1a,ampere1b,ampere1c,emag,xgene1,falkor,qdf24xx,exynosm1,phecda,thunderx2t99p1,vulcan,thunderx2t99,cortexa55,cortexa75,cortexa76,cortexa76ae,cortexa77,cortexa78,cortexa78ae,cortexa78c,cortexa65,cortexa65ae,cortexx1,cortexx1c,neoversen1,ares,neoversee1,octeontx2,octeontx2t98,octeontx2t96,octeontx2t93,octeontx2f95,octeontx2f95n,octeontx2f95mm,a64fx,fujitsu_monaka,tsv110,thunderx3t110,neoversev1,zeus,neoverse512tvb,saphira,oryon1,cortexa57cortexa53,cortexa72cortexa53,cortexa73cortexa35,cortexa73cortexa53,cortexa75cortexa55,cortexa76cortexa55,cortexr82,cortexr82ae,applea12,applem1_0,applem1_1,applem1_2,applem1_3,applem2_0,applem2_1,applem2_2,applem2_3,applem3_0,applem3_1,applem3_2,applem4_0,applem4_1,applem4_2,cortexa510,cortexa520,cortexa520ae,cortexa710,cortexa715,cortexa720,cortexa720ae,cortexa725,cortexa320,cortexx2,cortexx3,cortexx4,cortexx925,neoversen2,cobalt100,neoversen3,neoversev2,grace,neoversev3,neoversev3ae,c1nano,c1pro,c1premium,c1ultra,demeter,olympus,gb10,generic,generic_armv8_a,generic_armv9_a"
  	(const (symbol_ref "((enum attr_tune) aarch64_tune)")))
diff -Nrcpad gcc-16-20251214/gcc/config/aarch64/aarch64.cc gcc-16-20251221/gcc/config/aarch64/aarch64.cc
*** gcc-16-20251214/gcc/config/aarch64/aarch64.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/aarch64/aarch64.cc	Sun Dec 21 22:32:06 2025
*************** aarch64_merge_string_arguments (tree arg
*** 742,748 ****
  static arm_pcs
  aarch64_function_abi (struct function *fun)
  {
!   gcc_assert (fun);
    if (fun->machine->pcs == ARM_PCS_UNKNOWN)
      fun->machine->pcs = arm_pcs (fndecl_abi (fun->decl).id ());
  
--- 742,748 ----
  static arm_pcs
  aarch64_function_abi (struct function *fun)
  {
!   gcc_checking_assert (fun);
    if (fun->machine->pcs == ARM_PCS_UNKNOWN)
      fun->machine->pcs = arm_pcs (fndecl_abi (fun->decl).id ());
  
*************** aarch64_function_abi (struct function *f
*** 755,763 ****
  static arm_pcs
  aarch64_fndecl_abi (tree fn)
  {
!   gcc_assert (TREE_CODE (fn) == FUNCTION_DECL);
    struct function *fun = DECL_STRUCT_FUNCTION (fn);
!   if (!fun)
      return arm_pcs (fndecl_abi (fn).id ());
  
    return aarch64_function_abi (fun);
--- 755,763 ----
  static arm_pcs
  aarch64_fndecl_abi (tree fn)
  {
!   gcc_checking_assert (TREE_CODE (fn) == FUNCTION_DECL);
    struct function *fun = DECL_STRUCT_FUNCTION (fn);
!   if (!fun || !fun->machine)
      return arm_pcs (fndecl_abi (fn).id ());
  
    return aarch64_function_abi (fun);
*************** aarch64_override_options_internal (struc
*** 19439,19444 ****
--- 19439,19448 ----
  #endif
      }
  
+   if (flag_sanitize & SANITIZE_MEMTAG_STACK && !TARGET_MEMTAG)
+     error ("%<-fsanitize=memtag-stack%> requires the ISA extension %qs",
+ 	   "memtag");
+ 
    aarch64_feature_flags isa_flags = aarch64_get_isa_flags (opts);
    if ((isa_flags & (AARCH64_FL_SM_ON | AARCH64_FL_ZA_ON))
        && !(isa_flags & AARCH64_FL_SME))
*************** aarch64_asm_output_external (FILE *strea
*** 26073,26078 ****
--- 26077,26095 ----
    aarch64_asm_output_variant_pcs (stream, decl, name);
  }
  
+ /* Implement TARGET_MEMTAG_CAN_TAG_ADDRESSES.  Here we tell the rest of the
+    compiler that we automatically ignore the top byte of our pointers, which
+    allows using -fsanitize=hwaddress.  In case of -fsanitize=memtag, we
+    additionally ensure that target supports MEMTAG insns.  */
+ 
+ bool
+ aarch64_can_tag_addresses ()
+ {
+   if (memtag_sanitize_p ())
+     return !TARGET_ILP32 && TARGET_MEMTAG;
+   return !TARGET_ILP32;
+ }
+ 
  /* Triggered after a .cfi_startproc directive is emitted into the assembly file.
     Used to output the .cfi_b_key_frame directive when signing the current
     function with the B key.  */
*************** aarch64_post_cfi_startproc (FILE *f, tre
*** 26083,26088 ****
--- 26100,26110 ----
    if (cfun->machine->frame.laid_out && aarch64_return_address_signing_enabled ()
        && aarch64_ra_sign_key == AARCH64_KEY_B)
  	asm_fprintf (f, "\t.cfi_b_key_frame\n");
+   if (cfun->machine->frame.laid_out
+       && aarch64_can_tag_addresses ()
+       && memtag_sanitize_p ()
+       && !known_eq (cfun->machine->frame.frame_size, 0))
+     asm_fprintf (f, "\t.cfi_mte_tagged_frame\n");
  }
  
  /* Implement TARGET_STRICT_ARGUMENT_NAMING.
*************** aarch64_invalid_binary_op (int op, const
*** 30849,30861 ****
    return NULL;
  }
  
! /* Implement TARGET_MEMTAG_CAN_TAG_ADDRESSES.  Here we tell the rest of the
!    compiler that we automatically ignore the top byte of our pointers, which
!    allows using -fsanitize=hwaddress.  */
  bool
! aarch64_can_tag_addresses ()
  {
!   return !TARGET_ILP32;
  }
  
  /* Implement TARGET_ASM_FILE_END for AArch64.  This adds the AArch64 GNU NOTE
--- 30871,31156 ----
    return NULL;
  }
  
! #define AARCH64_MEMTAG_GRANULE_SIZE  16
! #define AARCH64_MEMTAG_TAG_BITSIZE    4
! 
! /* Implement TARGET_MEMTAG_TAG_BITSIZE.  */
! unsigned char
! aarch64_memtag_tag_bitsize ()
! {
!   if (memtag_sanitize_p ())
!     return AARCH64_MEMTAG_TAG_BITSIZE;
!   return default_memtag_tag_bitsize ();
! }
! 
! /* Implement TARGET_MEMTAG_GRANULE_SIZE.  */
! unsigned char
! aarch64_memtag_granule_size ()
! {
!   if (memtag_sanitize_p ())
!     return AARCH64_MEMTAG_GRANULE_SIZE;
!   return default_memtag_granule_size ();
! }
! 
! /* Implement TARGET_MEMTAG_INSERT_RANDOM_TAG.  In the case of MTE instructions,
!    make sure the gmi and irg instructions are generated when
!    -fsanitize=memtag-stack is used.  The first argument UNTAGGED can be a
!    tagged pointer, and its tag is used in the exclusion set.  Thus, the TARGET
!    doesn't use the same tag.  */
! rtx
! aarch64_memtag_insert_random_tag (rtx untagged, rtx target)
! {
!   if (memtag_sanitize_p ())
!     {
!       insn_code icode = CODE_FOR_gmi;
!       expand_operand ops_gmi[3];
!       rtx tmp = gen_reg_rtx (Pmode);
!       create_output_operand (&ops_gmi[0], tmp, Pmode);
!       create_input_operand  (&ops_gmi[1], untagged, Pmode);
!       create_integer_operand  (&ops_gmi[2], 0);
!       expand_insn (icode, 3, ops_gmi);
! 
!       icode = CODE_FOR_irg;
!       expand_operand ops_irg[3];
!       create_output_operand (&ops_irg[0], target, Pmode);
!       create_input_operand  (&ops_irg[1], untagged, Pmode);
!       create_input_operand  (&ops_irg[2], ops_gmi[0].value, Pmode);
!       expand_insn (icode, 3, ops_irg);
!       return ops_irg[0].value;
!     }
!   else
!     return default_memtag_insert_random_tag (untagged, target);
! }
! 
! /* Implement TARGET_MEMTAG_ADD_TAG.  For memtag sanitizer, emit addg/subg
!    instructions, otherwise fall back on the default implementation.  */
! rtx
! aarch64_memtag_add_tag (rtx base, poly_int64 offset, uint8_t tag_offset)
! {
!   if (memtag_sanitize_p ())
!     {
!       rtx target = NULL;
!       poly_int64 addr_offset = offset;
!       rtx offset_rtx = gen_int_mode (addr_offset, DImode);
! 
!       if (!aarch64_granule16_imm6 (offset_rtx, DImode))
! 	{
! 	  /* Emit addr arithmetic prior to addg/subg.  */
! 	  base = expand_simple_binop (Pmode, PLUS, base, offset_rtx,
! 				      NULL, true, OPTAB_LIB_WIDEN);
! 	  addr_offset = 0;
! 	}
! 
!       insn_code icode = CODE_FOR_addg;
!       expand_operand ops[4];
!       create_output_operand (&ops[0], target, DImode);
!       create_input_operand (&ops[1], base, DImode);
!       create_integer_operand (&ops[2], addr_offset);
!       create_integer_operand (&ops[3], tag_offset);
!       /* Addr offset and tag offset must be within bounds at this time.  */
!       gcc_assert (aarch64_memtag_tag_offset (ops[3].value, DImode));
! 
!       expand_insn (icode, 4, ops);
!       return ops[0].value;
!     }
!   else
!     return default_memtag_add_tag (base, offset, tag_offset);
! }
! 
! /* Implement TARGET_MEMTAG_EXTRACT_TAG.  In the case of memtag sanitizer, MTE
!    instructions allows us to work with tag-address tuple, thus no need to
!    extract the tag, emit a simple move.  */
! rtx
! aarch64_memtag_extract_tag (rtx tagged_pointer, rtx target)
! {
! 
!   if (memtag_sanitize_p ())
!     {
!       rtx ret = gen_reg_rtx (DImode);
!       emit_move_insn (ret, gen_lowpart (DImode, tagged_pointer));
!       return ret;
!     }
!   else
!     return default_memtag_extract_tag (tagged_pointer, target);
! }
! 
! /* Return TRUE if x is a valid memory address form for memtag loads and
!    stores.  */
  bool
! aarch64_granule16_memory_address_p (rtx x)
  {
!   struct aarch64_address_info addr;
! 
!   if (!MEM_P (x)
!       || !aarch64_classify_address (&addr, XEXP (x, 0), GET_MODE (x), false))
!     return false;
! 
!   /* Check that the offset, if any, is encodable as 9-bit immediate.  */
!   switch (addr.type)
!     {
!     case ADDRESS_REG_IMM:
!       return aarch64_granule16_simm9 (gen_int_mode (addr.const_offset, DImode),
! 				      DImode);
! 
!     case ADDRESS_REG_REG:
!       return addr.shift == 0;
! 
!     default:
!       break;
!     }
!   return false;
! }
! 
! /* Helper to emit either stg or st2g instruction.  */
! static void
! aarch64_emit_stxg_insn (machine_mode mode, rtx nxt, rtx addr, rtx tagp)
! {
!   rtx pat;
!   rtx mem_addr = gen_rtx_MEM (mode, nxt);
!   rtvec vec = gen_rtvec (2, gen_rtx_MEM (mode, addr), tagp);
!   rtx unspec = gen_rtx_UNSPEC_VOLATILE (mode, vec, UNSPECV_TAG_SPACE);
! 
!   if (!rtx_equal_p (nxt, addr))
!     {
!       rtx tmp = gen_rtx_CLOBBER (VOIDmode, addr);
!       rtvec parv = gen_rtvec (2, gen_rtx_SET (mem_addr, unspec), tmp);
!       pat = gen_rtx_PARALLEL (VOIDmode, parv);
!     }
!   else
!     {
!       pat = gen_rtx_SET (mem_addr, unspec);
!     }
!   emit_insn (pat);
! }
! 
! /* Tag the memory via an explicit loop.  This is used when tag_memory expand
!    is invoked for:
!      - non-constant size, or
!      - constant but not encodable size (!aarch64_granule16_simm9 ()), or
!      - constant and encodable size (aarch64_granule16_simm9 ()), but over the
!        unroll threshold (aarch64_tag_memory_loop_threshold).  */
! 
! static void
! aarch64_tag_memory_via_loop (rtx base, rtx size, rtx tagged_pointer)
! {
!   rtx_code_label *top_label, *bottom_label;
!   machine_mode iter_mode;
!   rtx next;
! 
!   iter_mode = GET_MODE (size);
!   if (iter_mode == VOIDmode)
!     iter_mode = word_mode;
! 
!   /* Prepare the addr operand for tagging memory.  */
!   rtx addr_reg = gen_reg_rtx (Pmode);
!   emit_move_insn (addr_reg, base);
! 
!   rtx size_reg = gen_reg_rtx (iter_mode);
!   emit_move_insn (size_reg, size);
! 
!   /* tbz  size, 4, label1
!      stg  tag,[addr], #16
!      label1:
!    */
!   auto *label1 = gen_label_rtx ();
!   auto branch = aarch64_gen_test_and_branch (EQ, size_reg, 4, label1);
!   auto jump = emit_jump_insn (branch);
!   JUMP_LABEL (jump) = label1;
! 
!   next = gen_rtx_POST_INC (Pmode, addr_reg);
!   aarch64_emit_stxg_insn (TImode, next, addr_reg, tagged_pointer);
! 
!   emit_label (label1);
! 
!   /* asr  iter, size, 5
!      cbz  iter, label2
!    */
!   rtx iter = gen_reg_rtx (iter_mode);
!   emit_insn (gen_rtx_SET (iter,
! 			  gen_rtx_ASHIFTRT (iter_mode, size_reg, GEN_INT (5))));
!   bottom_label = gen_label_rtx ();
!   branch = aarch64_gen_compare_zero_and_branch (EQ, iter, bottom_label);
!   aarch64_emit_unlikely_jump (branch);
! 
!   /* top_label:
!      st2g  tag, [addr], #32
!      subs  iter, iter, #1
!      bne   top_label
!    */
!   top_label = gen_label_rtx ();
!   emit_label (top_label);
! 
!   /* Tag Memory using post-index st2g.  */
!   next = gen_rtx_POST_INC (Pmode, addr_reg);
!   aarch64_emit_stxg_insn (OImode, next, addr_reg, tagged_pointer);
! 
!   /* Decrement ITER.  */
!   emit_insn (gen_subdi3_compare1_imm (iter, iter, CONST1_RTX (iter_mode),
! 				      CONSTM1_RTX (iter_mode)));
! 
!   rtx cc_reg = gen_rtx_REG (CCmode, CC_REGNUM);
!   rtx x = gen_rtx_fmt_ee (NE, CCmode, cc_reg, const0_rtx);
!   jump = emit_jump_insn (gen_aarch64_bcond (x, cc_reg, top_label));
!   JUMP_LABEL (jump) = top_label;
! 
!   emit_label (bottom_label);
! }
! 
! /* Implement expand for tag_memory.  */
! void
! aarch64_expand_tag_memory (rtx base, rtx tagged_pointer, rtx size)
! {
!   rtx addr;
!   HOST_WIDE_INT len, offset;
!   unsigned HOST_WIDE_INT granule_size;
!   unsigned HOST_WIDE_INT iters = 0;
! 
!   granule_size = (HOST_WIDE_INT) AARCH64_MEMTAG_GRANULE_SIZE;
! 
!   if (!REG_P (tagged_pointer))
!     tagged_pointer = force_reg (Pmode, tagged_pointer);
! 
!   if (!REG_P (base))
!     base = force_reg (Pmode, base);
! 
!   /* If size is small enough, I can can unroll the loop using stg/st2g
!      instructions.  */
!   if (CONST_INT_P (size))
!     {
!       len = INTVAL (size);
!       if (len == 0)
! 	return; /* Nothing to do.  */
! 
!       /* The amount of memory to tag must be aligned to granule size by now.  */
!       gcc_assert (len % granule_size == 0);
! 
!       iters = len / granule_size;
!     }
! 
!   /* Check predicate on max offset possible: offset (in base rtx) + size.  */
!   rtx end_addr = simplify_gen_binary (PLUS, Pmode, base, size);
!   end_addr = gen_rtx_MEM (TImode, end_addr);
!   if (iters > 0
!       && iters <= (unsigned HOST_WIDE_INT) aarch64_tag_memory_loop_threshold
!       && aarch64_granule16_memory_address_p (end_addr))
!     {
!       offset = 0;
!       while (iters)
! 	{
! 	  machine_mode mode = TImode;
! 	  if (iters / 2)
! 	    {
! 	      mode = OImode;
! 	      iters--;
! 	    }
! 	  iters--;
! 	  addr = plus_constant (Pmode, base, offset);
! 	  offset +=  GET_MODE_SIZE (mode).to_constant ();
! 	  aarch64_emit_stxg_insn (mode, addr, addr, tagged_pointer);
! 	}
!     }
!   else
!     aarch64_tag_memory_via_loop (base, size, tagged_pointer);
  }
  
  /* Implement TARGET_ASM_FILE_END for AArch64.  This adds the AArch64 GNU NOTE
*************** aarch64_libgcc_floating_mode_supported_p
*** 33336,33341 ****
--- 33631,33651 ----
  #undef TARGET_MEMTAG_CAN_TAG_ADDRESSES
  #define TARGET_MEMTAG_CAN_TAG_ADDRESSES aarch64_can_tag_addresses
  
+ #undef TARGET_MEMTAG_TAG_BITSIZE
+ #define TARGET_MEMTAG_TAG_BITSIZE aarch64_memtag_tag_bitsize
+ 
+ #undef TARGET_MEMTAG_GRANULE_SIZE
+ #define TARGET_MEMTAG_GRANULE_SIZE aarch64_memtag_granule_size
+ 
+ #undef TARGET_MEMTAG_INSERT_RANDOM_TAG
+ #define TARGET_MEMTAG_INSERT_RANDOM_TAG aarch64_memtag_insert_random_tag
+ 
+ #undef TARGET_MEMTAG_ADD_TAG
+ #define TARGET_MEMTAG_ADD_TAG aarch64_memtag_add_tag
+ 
+ #undef TARGET_MEMTAG_EXTRACT_TAG
+ #define TARGET_MEMTAG_EXTRACT_TAG aarch64_memtag_extract_tag
+ 
  #if CHECKING_P
  #undef TARGET_RUN_TARGET_SELFTESTS
  #define TARGET_RUN_TARGET_SELFTESTS selftest::aarch64_run_selftests
diff -Nrcpad gcc-16-20251214/gcc/config/aarch64/aarch64.h gcc-16-20251221/gcc/config/aarch64/aarch64.h
*** gcc-16-20251214/gcc/config/aarch64/aarch64.h	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/aarch64/aarch64.h	Sun Dec 21 22:32:06 2025
*************** constexpr auto AARCH64_FL_DEFAULT_ISA_MO
*** 291,307 ****
  #define TARGET_SVE2 AARCH64_HAVE_ISA (SVE2)
  
  /* SVE2 AES instructions, enabled through +sve2-aes.  */
! #define TARGET_SVE2_AES (AARCH64_HAVE_ISA (SVE2_AES) && TARGET_NON_STREAMING)
  
  /* SVE2 BITPERM instructions, enabled through +sve2-bitperm.  */
! #define TARGET_SVE2_BITPERM (AARCH64_HAVE_ISA (SVE2_BITPERM) \
  			     && TARGET_NON_STREAMING)
  
  /* SVE2 SHA3 instructions, enabled through +sve2-sha3.  */
! #define TARGET_SVE2_SHA3 (AARCH64_HAVE_ISA (SVE2_SHA3) && TARGET_NON_STREAMING)
  
  /* SVE2 SM4 instructions, enabled through +sve2-sm4.  */
! #define TARGET_SVE2_SM4 (AARCH64_HAVE_ISA (SVE2_SM4) && TARGET_NON_STREAMING)
  
  /* SVE2p1 instructions, enabled through +sve2p1.  */
  #define TARGET_SVE2p1 AARCH64_HAVE_ISA (SVE2p1)
--- 291,314 ----
  #define TARGET_SVE2 AARCH64_HAVE_ISA (SVE2)
  
  /* SVE2 AES instructions, enabled through +sve2-aes.  */
! #define TARGET_SVE2_AES (AARCH64_HAVE_ISA (SVE2) \
! 			 && AARCH64_HAVE_ISA (SVE_AES) \
! 			 && TARGET_NON_STREAMING)
  
  /* SVE2 BITPERM instructions, enabled through +sve2-bitperm.  */
! #define TARGET_SVE2_BITPERM (AARCH64_HAVE_ISA (SVE2) \
! 			     && AARCH64_HAVE_ISA (SVE_BITPERM) \
  			     && TARGET_NON_STREAMING)
  
  /* SVE2 SHA3 instructions, enabled through +sve2-sha3.  */
! #define TARGET_SVE2_SHA3 (AARCH64_HAVE_ISA (SVE2) \
! 			  && AARCH64_HAVE_ISA (SVE_SHA3) \
! 			  && TARGET_NON_STREAMING)
  
  /* SVE2 SM4 instructions, enabled through +sve2-sm4.  */
! #define TARGET_SVE2_SM4 (AARCH64_HAVE_ISA (SVE2) \
! 			 && AARCH64_HAVE_ISA (SVE_SM4) \
! 			 && TARGET_NON_STREAMING)
  
  /* SVE2p1 instructions, enabled through +sve2p1.  */
  #define TARGET_SVE2p1 AARCH64_HAVE_ISA (SVE2p1)
diff -Nrcpad gcc-16-20251214/gcc/config/aarch64/aarch64.md gcc-16-20251221/gcc/config/aarch64/aarch64.md
*** gcc-16-20251214/gcc/config/aarch64/aarch64.md	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/aarch64/aarch64.md	Sun Dec 21 22:32:06 2025
***************
*** 412,417 ****
--- 412,418 ----
      UNSPECV_GCSPOPM		; Represent GCSPOPM.
      UNSPECV_GCSSS1		; Represent GCSSS1 Xt.
      UNSPECV_GCSSS2		; Represent GCSSS2 Xt.
+     UNSPECV_TAG_SPACE		; Represent MTE tag memory space.
      UNSPECV_TSTART		; Represent transaction start.
      UNSPECV_TCOMMIT		; Represent transaction commit.
      UNSPECV_TCANCEL		; Represent transaction cancel.
***************
*** 689,694 ****
--- 690,696 ----
  
  ;; Dispatch scheduling
  (include "neoversev2.md")
+ (include "olympus.md")
  
  ;; -------------------------------------------------------------------
  ;; Jumps and other miscellaneous insns
***************
*** 8616,8661 ****
  ;; Memory Tagging Extension (MTE) instructions.
  
  (define_insn "irg"
!   [(set (match_operand:DI 0 "register_operand" "=rk")
  	(ior:DI
! 	 (and:DI (match_operand:DI 1 "register_operand" "rk")
  		 (const_int MEMTAG_TAG_MASK))
! 	 (ashift:DI (unspec:QI [(match_operand:DI 2 "register_operand" "r")]
  		     UNSPEC_GEN_TAG_RND)
  		    (const_int 56))))]
    "TARGET_MEMTAG"
!   "irg\\t%0, %1, %2"
!   [(set_attr "type" "memtag")]
  )
  
  (define_insn "gmi"
    [(set (match_operand:DI 0 "register_operand" "=r")
! 	(ior:DI (ashift:DI
! 		 (const_int 1)
! 		 (and:QI (lshiftrt:DI
! 			  (match_operand:DI 1 "register_operand" "rk")
! 			  (const_int 56)) (const_int 15)))
! 		(match_operand:DI 2 "register_operand" "r")))]
    "TARGET_MEMTAG"
!   "gmi\\t%0, %1, %2"
    [(set_attr "type" "memtag")]
  )
  
  (define_insn "addg"
!   [(set (match_operand:DI 0 "register_operand" "=rk")
  	(ior:DI
! 	 (and:DI (plus:DI (match_operand:DI 1 "register_operand" "rk")
! 			  (match_operand:DI 2 "aarch64_granule16_uimm6" "i"))
! 		 (const_int -1080863910568919041)) ;; 0xf0ff...
  	 (ashift:DI
! 	  (unspec:QI
! 	   [(and:QI (lshiftrt:DI (match_dup 1) (const_int 56)) (const_int 15))
! 	    (match_operand:QI 3 "aarch64_memtag_tag_offset" "i")]
! 	   UNSPEC_GEN_TAG)
  	  (const_int 56))))]
    "TARGET_MEMTAG"
!   "addg\\t%0, %1, #%2, #%3"
!   [(set_attr "type" "memtag")]
  )
  
  (define_insn "subp"
--- 8618,8665 ----
  ;; Memory Tagging Extension (MTE) instructions.
  
  (define_insn "irg"
!   [(set (match_operand:DI 0 "register_operand")
  	(ior:DI
! 	 (and:DI (match_operand:DI 1 "register_operand")
  		 (const_int MEMTAG_TAG_MASK))
! 	 (ashift:DI (unspec:QI [(match_operand:DI 2 "aarch64_reg_or_zero")]
  		     UNSPEC_GEN_TAG_RND)
  		    (const_int 56))))]
    "TARGET_MEMTAG"
!   {@ [ cons: =0, 1, 2 ; attrs: type ]
!      [ rk      , rk, r  ; memtag ] irg\\t%0, %1, %2
!      [ rk      , rk, Z  ; memtag ] irg\\t%0, %1
!   }
  )
  
  (define_insn "gmi"
    [(set (match_operand:DI 0 "register_operand" "=r")
! 	(ior:DI
! 	 (unspec:DI [(match_operand:DI 1 "register_operand" "rk")
! 		     (const_int 0)]
! 		    UNSPEC_GEN_TAG)
! 	 (match_operand:DI 2 "aarch64_reg_or_zero" "rZ")))]
    "TARGET_MEMTAG"
!   "gmi\\t%0, %1, %x2"
    [(set_attr "type" "memtag")]
  )
  
  (define_insn "addg"
!   [(set (match_operand:DI 0 "register_operand")
  	(ior:DI
! 	 (and:DI (plus:DI (match_operand:DI 1 "register_operand")
! 			  (match_operand:DI 2 "aarch64_granule16_imm6"))
! 		 (const_int MEMTAG_TAG_MASK))
  	 (ashift:DI
! 	   (unspec:DI [(match_dup 1)
! 		       (match_operand:QI 3 "aarch64_memtag_tag_offset")]
! 		       UNSPEC_GEN_TAG)
  	  (const_int 56))))]
    "TARGET_MEMTAG"
!   {@ [ cons: =0 , 1  , 2 , 3 ; attrs: type ]
!      [ rk       , rk , Uag ,  ; memtag   ] addg\t%0, %1, #%2, #%3
!      [ rk       , rk , Ung ,  ; memtag   ] subg\t%0, %1, #%n2, #%3
!   }
  )
  
  (define_insn "subp"
***************
*** 8689,8705 ****
  ;; STG doesn't align the address but aborts with alignment fault
  ;; when the address is not 16-byte aligned.
  (define_insn "stg"
!   [(set (mem:QI (unspec:DI
! 	 [(plus:DI (match_operand:DI 1 "register_operand" "rk")
! 		   (match_operand:DI 2 "aarch64_granule16_simm9" "i"))]
! 	 UNSPEC_TAG_SPACE))
! 	(and:QI (lshiftrt:DI (match_operand:DI 0 "register_operand" "rk")
! 			     (const_int 56)) (const_int 15)))]
    "TARGET_MEMTAG"
!   "stg\\t%0, [%1, #%2]"
    [(set_attr "type" "memtag")]
  )
  
  ;; Load/Store 64-bit (LS64) instructions.
  (define_insn "ld64b"
    [(set (match_operand:V8DI 0 "register_operand" "=r")
--- 8693,8775 ----
  ;; STG doesn't align the address but aborts with alignment fault
  ;; when the address is not 16-byte aligned.
  (define_insn "stg"
!   [(set (match_operand:TI 0 "aarch64_granule16_memory_operand" "+Umg")
!       (unspec_volatile:TI
! 	[(match_dup 0)
! 	 (match_operand:DI 1 "register_operand" "rk")]
! 	UNSPECV_TAG_SPACE))]
    "TARGET_MEMTAG"
!   "stg\\t%1, %0"
!   [(set_attr "type" "memtag")]
! )
! 
! (define_insn "stg_<mte_name>"
!   [(set (mem:TI (MTE_PP:DI (match_operand:DI 0 "register_operand" "+rk")))
! 	(unspec_volatile:TI
! 	 [(mem:TI (match_dup 0))
! 	  (match_operand:DI 1 "register_operand" "rk")]
! 	 UNSPECV_TAG_SPACE))
!    (clobber (match_dup 0))]
!   "TARGET_MEMTAG"
!   "stg\\t%1, <stg_ops>"
!   [(set_attr "type" "memtag")]
! )
! 
! ;; ST2G updates allocation tags for two memory granules (i.e. 32 bytes) at
! ;; once, without zero initialization.
! (define_insn "st2g"
!   [(set (match_operand:OI 0 "aarch64_granule16_memory_operand" "+Umg")
!       (unspec_volatile:OI
! 	[(match_dup 0)
! 	 (match_operand:DI 1 "register_operand" "rk")]
! 	UNSPECV_TAG_SPACE))]
!   "TARGET_MEMTAG"
!   "st2g\\t%1, %0"
!   [(set_attr "type" "memtag")]
! )
! 
! (define_insn "st2g_<mte_name>"
!   [(set (mem:OI (MTE_PP:DI (match_operand:DI 0 "register_operand" "+rk")))
! 	(unspec_volatile:OI
! 	 [(mem:OI (match_dup 0))
! 	  (match_operand:DI 1 "register_operand" "rk")]
! 	 UNSPECV_TAG_SPACE))
!    (clobber (match_dup 0))]
!   "TARGET_MEMTAG"
!   "st2g\\t%1, <st2g_ops>"
    [(set_attr "type" "memtag")]
  )
  
+ (define_expand "tag_memory"
+   [(match_operand:DI 0 "register_operand" "")
+    (match_operand:DI 1 "nonmemory_operand" "")
+    (match_operand:DI 2 "nonmemory_operand" "")]
+   ""
+ {
+   aarch64_expand_tag_memory (operands[0], operands[1], operands[2]);
+   DONE;
+ })
+ 
+ (define_expand "compose_tag"
+   [(set (match_operand:DI 0 "register_operand")
+ 	(ior:DI
+ 	 (and:DI (plus:DI (match_operand:DI 1 "register_operand")
+ 			  (const_int 0))
+ 		 (const_int MEMTAG_TAG_MASK))
+ 	 (ashift:DI
+ 	  (unspec:DI [(match_dup 1)
+ 		     (match_operand 2 "immediate_operand")]
+ 		     UNSPEC_GEN_TAG)
+ 	  (const_int 56))))]
+   ""
+ {
+   if (INTVAL (operands[2]) == 0)
+     {
+      emit_move_insn (operands[0], operands[1]);
+      DONE;
+     }
+ })
+ 
  ;; Load/Store 64-bit (LS64) instructions.
  (define_insn "ld64b"
    [(set (match_operand:V8DI 0 "register_operand" "=r")
diff -Nrcpad gcc-16-20251214/gcc/config/aarch64/aarch64.opt gcc-16-20251221/gcc/config/aarch64/aarch64.opt
*** gcc-16-20251214/gcc/config/aarch64/aarch64.opt	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/aarch64/aarch64.opt	Sun Dec 21 22:32:06 2025
*************** individual writeback accesses where poss
*** 456,461 ****
--- 456,466 ----
  also try to opportunistically form writeback opportunities by folding in
  trailing destructive updates of the base register used by a pair.
  
+ -param=aarch64-tag-memory-loop-threshold=
+ Target Joined UInteger Var(aarch64_tag_memory_loop_threshold) Init(10) IntegerRange(0, 65536) Param
+ Param to control the treshold in number of granules beyond which an
+ explicit loop for tagging a memory block is emitted.
+ 
  Wexperimental-fmv-target
  Target Var(warn_experimental_fmv) Warning Init(1) Undocumented
  This option is deprecated.
diff -Nrcpad gcc-16-20251214/gcc/config/aarch64/constraints.md gcc-16-20251221/gcc/config/aarch64/constraints.md
*** gcc-16-20251214/gcc/config/aarch64/constraints.md	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/aarch64/constraints.md	Sun Dec 21 22:32:06 2025
***************
*** 346,351 ****
--- 346,357 ----
         (match_test "aarch64_legitimate_address_p (GET_MODE (op), XEXP (op, 0),
  						  true, ADDR_QUERY_LDP_STP)")))
  
+ (define_memory_constraint "Umg"
+   "@internal
+   A memory address for MTE load/store tag operation."
+   (and (match_code "mem")
+        (match_test "aarch64_granule16_memory_address_p (op)")))
+ 
  ;; Used for storing or loading pairs in an AdvSIMD register using an STP/LDP
  ;; as a vector-concat.  The address mode uses the same constraints as if it
  ;; were for a single value.
***************
*** 600,605 ****
--- 606,626 ----
   An address valid for a prefetch instruction."
   (match_test "aarch64_address_valid_for_prefetch_p (op, true)"))
  
+ (define_constraint "Uag"
+   "@internal
+   A constant that can be used as address offset for an ADDG operation."
+   (and (match_code "const_int")
+        (match_test "IN_RANGE (ival, 0, 1008)
+ 		    && !(ival & 0xf)")))
+ 
+ (define_constraint "Ung"
+   "@internal
+   A constant that can be used as address offset for an SUBG operation (once
+   negated)."
+   (and (match_code "const_int")
+        (match_test "IN_RANGE (ival, -1008, -1)
+ 		    && !(ival & 0xf)")))
+ 
  (define_constraint "vgb"
    "@internal
     A constraint that matches an immediate offset valid for SVE LD1B
diff -Nrcpad gcc-16-20251214/gcc/config/aarch64/cygming.h gcc-16-20251221/gcc/config/aarch64/cygming.h
*** gcc-16-20251214/gcc/config/aarch64/cygming.h	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/aarch64/cygming.h	Sun Dec 21 22:32:06 2025
*************** still needed for compilation.  */
*** 254,257 ****
--- 254,271 ----
  #undef  TARGET_ASM_LTO_END
  #define TARGET_ASM_LTO_END mingw_pe_asm_lto_end
  
+ /* Support for Windows resource files.  */
+ #define EXTRA_DEFAULT_COMPILERS \
+   {".rc", "@windres-rc", 0, 0, 0}, \
+   {"@windres-rc", \
+    "%{!E:%{!M:%{!MM:windres -J rc -O coff -F pe-aarch64 \
+       %{I*:-I%*} %{D*:-D%*} %{U*:-U%*} \
+       %{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O} %i}}}", \
+    0, 0, 0}, \
+   {".res", "@windres-res", 0, 0, 0}, \
+   {"@windres-res", \
+    "%{!E:%{!M:%{!MM:windres -J res -O coff -F pe-aarch64 \
+       %{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O} %i}}}", \
+    0, 0, 0},
+ 
  #endif
diff -Nrcpad gcc-16-20251214/gcc/config/aarch64/iterators.md gcc-16-20251221/gcc/config/aarch64/iterators.md
*** gcc-16-20251214/gcc/config/aarch64/iterators.md	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/aarch64/iterators.md	Sun Dec 21 22:32:06 2025
***************
*** 2930,2935 ****
--- 2930,2938 ----
  ;; SVE integer comparisons.
  (define_code_iterator SVE_INT_CMP [lt le eq ne ge gt ltu leu geu gtu])
  
+ ;; pre/post-{inc,dec} for mte instructions.
+ (define_code_iterator MTE_PP [post_inc post_dec pre_inc pre_dec])
+ 
  ;; -------------------------------------------------------------------
  ;; Code Attributes
  ;; -------------------------------------------------------------------
***************
*** 3279,3284 ****
--- 3282,3304 ----
  			       (minus "UNSPEC_COND_FSUB")
  			       (mult "UNSPEC_COND_FMUL")])
  
+ ;; Map MTE pre/post to the right asm format
+ (define_code_attr stg_ops [(post_inc "[%0], 16")
+ 			   (post_dec "[%0], -16")
+ 			   (pre_inc  "[%0, 16]!")
+ 			   (pre_dec  "[%0, -16]!")])
+ 
+ (define_code_attr st2g_ops [(post_inc "[%0], 32")
+ 			    (post_dec "[%0], -32")
+ 			    (pre_inc  "[%0, 32]!")
+ 			    (pre_dec  "[%0, -32]!")])
+ 
+ ;; Map MTE pre/post to names
+ (define_code_attr mte_name [(post_inc "postinc")
+ 			    (post_dec "postdec")
+ 			    (pre_inc "preinc")
+ 			    (pre_dec "predec")])
+ 
  ;; -------------------------------------------------------------------
  ;; Int Iterators.
  ;; -------------------------------------------------------------------
diff -Nrcpad gcc-16-20251214/gcc/config/aarch64/olympus.md gcc-16-20251221/gcc/config/aarch64/olympus.md
*** gcc-16-20251214/gcc/config/aarch64/olympus.md	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/config/aarch64/olympus.md	Sun Dec 21 22:32:06 2025
***************
*** 0 ****
--- 1,199 ----
+ ;; Instruction attribute for dispatch scheduling for NVIDIA Olympus.
+ ;; Copyright The GNU Toolchain Authors.
+ ;;
+ ;; 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/>.
+ 
+ ;; Attribute that groups other instruction attributes into dispatch groups
+ ;; for the Olympus core. Dispatch groups are groups of pipelines for which
+ ;; the SWOG specifies a dispatch constraint. For example: Because the SWOG
+ ;; contains a dispatch constraint for the V12 pipelines, there is an attribute
+ ;; value "v12" that groups instructions that are processed by the V1 and V2
+ ;; pipelines.
+ ;; Values that contain a "_" represent combinations of dispatch groups.
+ ;; For example, there are dispatch constraints for the M and V pipelines. The
+ ;; value "m_v" groups instructions that utilize the M as well as the
+ ;; V pipelines, such that both dispatch constraints apply.
+ 
+ (define_attr "olympus_dispatch"
+   "none,b,i,m,m0,l,v,v0,v03,v12,v45,v0123,m_v,l_v,m_l,m_v0123,v_v0123,\
+    l_v03,sa_d,sa_v0123,sa_v_v0123"
+   (cond [(eq_attr "type" "branch,call")
+ 	 (const_string "b")
+ 	 (eq_attr "type" "adr,adc_reg,alu_ext,alu_imm,alu_sreg,alus_ext,\
+ 	  alus_imm,alus_shift_imm,alus_sreg,clz,csel,extend,logic_imm,\
+ 	  logic_reg,logics_imm,logics_reg,mov_imm,mov_reg,rbit,rev")
+ 	 (const_string "i")
+ 	 (ior
+ 	   (eq_attr "type" "bfm,bfx,crc,f_mrc,logic_shift_imm,\
+ 	    logics_shift_imm,memtag,mul,neon_from_gp,neon_from_gp_q,\
+ 	    rotate_imm,shift_reg,smull,sdiv,udiv,umull")
+ 	   (eq_attr "autodetect_type" "alu_shift_asr_op2,alu_shift_lsl_op2,\
+ 	    alu_shift_lsr_op2")
+ 	   (eq_attr "sve_type" "sve_pred_cnt_ctrl,sve_pred_cnt_scalar,\
+ 	    sve_pred_logical,sve_pred_misc"))
+ 	 (const_string "m")
+ 	 (eq_attr "sve_type" "sve_ffr")
+ 	 (const_string "m0")
+ 	 (ior
+ 	   (eq_attr "type" "f_loadd,f_loads,load_4,load_8,load_16,\
+ 	    neon_ldp,neon_ldp_q,neon_load1_1reg,neon_load1_1reg_q,\
+ 	    neon_load1_2reg,neon_load1_2reg_q,neon_load1_3reg,\
+ 	    neon_load1_3reg_q,neon_load1_4reg,neon_load1_4reg_q,\
+ 	    neon_load1_all_lanes")
+ 	   (eq_attr "sve_type" "sve_load_1reg"))
+ 	 (const_string "l")
+ 	 (ior
+ 	   (eq_attr "type" "crypto_aese,crypto_aesmc,crypto_pmull,faddd,fadds,\
+ 	    fccmpd,fccmps,fcmpd,fcmps,fcsel,fconstd,fconsts,fmuld,fmuls,\
+ 	    ffarithd,ffariths,fmacd,fmacs,f_mcr,f_minmaxd,f_minmaxs,fmov,\
+ 	    f_rintd,f_rints,neon_abs,neon_abs_q,\
+ 	    neon_add,neon_add_halve,neon_add_halve_narrow_q,neon_add_halve_q,\
+ 	    neon_add_long,neon_add_q,neon_add_widen,neon_abd,neon_abd_long,\
+ 	    neon_abd_q,neon_arith_acc,neon_arith_acc_q,neon_bsl,neon_bsl_q,\
+ 	    neon_cls,neon_cls_q,neon_compare,neon_compare_q,\
+ 	    neon_compare_zero,neon_compare_zero_q,neon_cnt,neon_cnt_q,\
+ 	    neon_dup,neon_dup_q,neon_ext,neon_ext_q,neon_fcadd,neon_fcmla,\
+ 	    neon_fp_abs_d,neon_fp_abs_d_q,neon_fp_abs_s,neon_fp_abs_s_q,\
+ 	    neon_fp_abd_d,neon_fp_abd_d_q,neon_fp_abd_s,neon_fp_abd_s_q,\
+ 	    neon_fp_addsub_d,neon_fp_addsub_d_q,neon_fp_addsub_s,\
+ 	    neon_fp_addsub_s_q,neon_fp_compare_d,neon_fp_compare_d_q,\
+ 	    neon_fp_compare_s,neon_fp_compare_s_q,neon_fp_mla_d,\
+ 	    neon_fp_mla_d_q,neon_fp_mla_d_scalar_q,neon_fp_mla_s,\
+ 	    neon_fp_mla_s_q,neon_fp_mla_s_scalar,neon_fp_mla_s_scalar_q,\
+ 	    neon_fp_minmax_d,neon_fp_minmax_d_q,neon_fp_minmax_s,\
+ 	    neon_fp_minmax_s_q,neon_fp_mul_d,neon_fp_mul_d_q,neon_fp_mul_s,\
+ 	    neon_fp_mul_s_q,neon_fp_mul_s_scalar,neon_fp_mul_s_scalar_q,\
+ 	    neon_fp_mul_d_scalar_q,neon_fp_neg_s,neon_fp_neg_s_q,\
+ 	    neon_fp_neg_d,neon_fp_neg_d_q,neon_fp_recps_d,\
+ 	    neon_fp_recps_d_q,neon_fp_recps_s,neon_fp_recps_s_q,\
+ 	    neon_fp_reduc_add_d,neon_fp_reduc_add_d_q,neon_fp_reduc_add_s,\
+ 	    neon_fp_reduc_add_s_q,neon_fp_reduc_minmax_d,\
+ 	    neon_fp_reduc_minmax_d_q,neon_fp_reduc_minmax_s,\
+ 	    neon_fp_reduc_minmax_s_q,neon_fp_rsqrts_d,neon_fp_rsqrts_d_q,\
+ 	    neon_fp_rsqrts_s,neon_fp_rsqrts_s_q,neon_logic,neon_logic_q,\
+ 	    neon_minmax,neon_minmax_q,neon_move,neon_move_narrow_q,\
+ 	    neon_move_q,neon_neg,neon_neg_q,neon_permute,neon_permute_q,\
+ 	    neon_qabs,neon_qabs_q,neon_qadd,neon_qadd_q,neon_qneg,neon_qneg_q,\
+ 	    neon_qsub,neon_qsub_q,neon_rev,neon_rev_q,neon_rbit,neon_rbit_q,\
+ 	    neon_sat_shift_imm,neon_sat_shift_imm_narrow_q,\
+ 	    neon_sat_shift_imm_q,neon_sat_shift_reg,neon_sat_shift_reg_q,\
+ 	    neon_shift_acc,neon_shift_acc_q,neon_shift_imm,\
+ 	    neon_shift_imm_long,neon_shift_imm_narrow_q,neon_shift_imm_q,\
+ 	    neon_shift_reg,neon_shift_reg_q,neon_sub,neon_sub_halve,\
+ 	    neon_sub_halve_narrow_q,neon_sub_halve_q,neon_sub_long,\
+ 	    neon_sub_q,neon_sub_widen,neon_tbl1,neon_tbl1_q,neon_tbl2,\
+ 	    neon_tbl2_q,neon_tbl3,neon_tbl3_q,neon_tbl4,neon_tbl4_q,\
+ 	    neon_tst,neon_tst_q,neon_zip,neon_zip_q")
+ 	   (eq_attr "sve_type" "sve_fp_arith,sve_fp_misc,\
+ 	    sve_fp_mul,sve_fp_reduc,sve_int_accum,sve_int_dot,sve_int_extend,\
+ 	    sve_int_general,sve_int_pmul,sve_int_shift"))
+ 	 (const_string "v")
+ 	 (ior
+ 	   (eq_attr "type" "crypto_sha1_fast,crypto_sha1_slow,crypto_sha1_xor,\
+ 	    crypto_sha256_fast,crypto_sha256_slow,crypto_sha3,crypto_sha512,\
+ 	    crypto_sm4")
+ 	   (eq_attr "sve_type" "sve_crypto_sha3"))
+ 	 (const_string "v0")
+ 	 (ior
+ 	   (eq_attr "type" "fccmpd,fccmps,fcmpd,fcmps,neon_fp_to_int_d,\
+ 	    neon_fp_to_int_d_q,neon_fp_to_int_s,neon_fp_to_int_s_q,\
+ 	    neon_to_gp,neon_to_gp_q")
+ 	   (eq_attr "sve_type" "sve_fp_assoc_add,sve_fp_cmp"))
+ 	 (const_string "v03")
+ 	 (ior
+ 	   (eq_attr "type" "fdivd,fdivs,fsqrtd,fsqrts,neon_fp_div_d,\
+ 	    neon_fp_div_d_q,neon_fp_div_s,neon_fp_div_s_q,neon_fp_sqrt_d,\
+ 	    neon_fp_sqrt_d_q,neon_fp_sqrt_s,neon_fp_sqrt_s_q")
+ 	   (eq_attr "sve_type" "sve_fp_div,sve_fp_exp,sve_fp_sqrt,\
+ 	    sve_int_extract,sve_int_bit_perm"))
+ 	 (const_string "v12")
+ 	 (eq_attr "sve_type" "sve_int_div")
+ 	 (const_string "v45")
+ 	 (ior
+ 	   (eq_attr "type" "crypto_sm3,f_cvt,f_cvtf2i,f_cvti2f,f_rintd,\
+ 	    f_rints,mla,neon_fp_cvt_narrow_d_q,neon_fp_cvt_narrow_s_q,\
+ 	    neon_fp_cvt_widen_h,neon_fp_cvt_widen_s,\
+ 	    neon_fp_recpe_d,neon_fp_recpe_d_q,neon_fp_recpe_s,\
+ 	    neon_fp_recpe_s_q,neon_fp_recpx_d,neon_fp_recpx_d_q,\
+ 	    neon_fp_recpx_s,neon_fp_recpx_s_q,neon_fp_round_d,\
+ 	    neon_fp_round_d_q,neon_fp_round_s,neon_fp_round_s_q,\
+ 	    neon_fp_rsqrte_d,neon_fp_rsqrte_d_q,neon_fp_rsqrte_s,\
+ 	    neon_fp_rsqrte_s_q,neon_int_to_fp_s,\
+ 	    neon_int_to_fp_s_q,neon_int_to_fp_d,neon_int_to_fp_d_q,\
+ 	    neon_mla_b,neon_mla_b_long,neon_mla_b_q,neon_mla_h,\
+ 	    neon_mla_h_long,neon_mla_h_q,neon_mla_h_scalar,\
+ 	    neon_mla_h_scalar_q,neon_mla_h_scalar_long,neon_mla_s,\
+ 	    neon_mla_s_long,neon_mla_s_q,neon_mla_s_scalar,\
+ 	    neon_mla_s_scalar_q,neon_mla_s_scalar_long,neon_mul_b,\
+ 	    neon_mul_b_long,neon_mul_b_q,neon_mul_d_long,neon_mul_h,\
+ 	    neon_mul_h_q,neon_mul_h_long,neon_mul_h_scalar,\
+ 	    neon_mul_h_scalar_long,neon_mul_h_scalar_q,neon_mul_s,\
+ 	    neon_mul_s_scalar_q,neon_mul_s_q,neon_mul_s_long,\
+ 	    neon_mul_s_scalar,neon_mul_s_scalar_long,neon_reduc_add,\
+ 	    neon_reduc_add_long,neon_reduc_add_q,neon_reduc_minmax,\
+ 	    neon_reduc_minmax_q,neon_sat_mla_b_long,neon_sat_mla_h_long,\
+ 	    neon_sat_mla_h_scalar_long,neon_sat_mla_s_long,\
+ 	    neon_sat_mla_s_scalar_long,neon_sat_mul_b,neon_sat_mul_b_q,\
+ 	    neon_sat_mul_b_long,neon_sat_mul_h,neon_sat_mul_h_q,\
+ 	    neon_sat_mul_h_long,neon_sat_mul_h_scalar,\
+ 	    neon_sat_mul_h_scalar_q,neon_sat_mul_h_scalar_long,\
+ 	    neon_sat_mul_s,neon_sat_mul_s_q,neon_sat_mul_s_long,\
+ 	    neon_sat_mul_s_scalar,neon_sat_mul_s_scalar_q,\
+ 	    neon_sat_mul_s_scalar_long,smlal,umlal")
+ 	   (eq_attr "sve_type" "sve_fp_cvt,sve_fp_log,sve_int_cvt,\
+ 	    sve_int_mul,sve_int_recip_est"))
+ 	 (const_string "v0123")
+ 	 (eq_attr "type" "neon_ins,neon_ins_q")
+ 	 (const_string "m_v")
+ 	 (ior
+ 	   (eq_attr "type" "neon_load1_one_lane,neon_load1_one_lane_q,\
+ 	    neon_load2_2reg,neon_load2_2reg_q,neon_load2_all_lanes,\
+ 	    neon_load2_all_lanes_q,neon_load2_one_lane,neon_load3_3reg,\
+ 	    neon_load3_3reg_q,neon_load3_all_lanes,neon_load3_all_lanes_q,\
+ 	    neon_load3_one_lane,neon_load4_4reg,neon_load4_4reg_q,\
+ 	    neon_load4_all_lanes,neon_load4_all_lanes_q,neon_load4_one_lane")
+ 	   (eq_attr "sve_type" "sve_load_2reg,sve_load_3reg,sve_load_4reg"))
+ 	 (const_string "l_v")
+ 	 (eq_attr "sve_type" "sve_load_pred,sve_pred_vec")
+ 	 (const_string "m_l")
+ 	 (eq_attr "sve_type" "sve_int_cmp_set,sve_int_index,sve_int_match")
+ 	 (const_string "m_v0123")
+ 	 (eq_attr "sve_type" "sve_int_reduc")
+ 	 (const_string "v_v0123")
+ 	 (eq_attr "sve_type" "sve_gatherload_32,sve_gatherload_64")
+ 	 (const_string "l_v03")
+ 	 (ior
+ 	   (eq_attr "type" "store_4,store_8,store_16")
+ 	   (eq_attr "sve_type" "sve_store_pred"))
+ 	 (const_string "sa_d")
+ 	 (ior
+ 	   (eq_attr "type" "f_stored,f_stores,neon_stp,neon_stp_q,\
+ 	    neon_store1_1reg,neon_store1_1reg_q,neon_store1_2reg,\
+ 	    neon_store1_2reg_q,neon_store1_3reg,neon_store1_3reg_q,\
+ 	    neon_store1_4reg,neon_store1_4reg_q")
+ 	   (eq_attr "sve_type" "sve_store_1reg"))
+ 	 (const_string "sa_v0123")
+ 	 (ior
+ 	   (eq_attr "type" "neon_store1_one_lane,neon_store1_one_lane_q,\
+ 	    neon_store2_2reg,neon_store2_2reg_q,neon_store2_one_lane,\
+ 	    neon_store2_one_lane_q,neon_store3_3reg,neon_store3_3reg_q,\
+ 	    neon_store3_one_lane,neon_store3_one_lane_q,neon_store4_4reg,\
+ 	    neon_store4_4reg_q,neon_store4_one_lane,neon_store4_one_lane_q")
+ 	   (eq_attr "sve_type" "sve_store_2reg,sve_store_3reg,sve_store_4reg,\
+ 	    sve_scatterstore_32,sve_scatterstore_64"))
+ 	 (const_string "sa_v_v0123")]
+ 	 (const_string "none")))
\ No newline at end of file
diff -Nrcpad gcc-16-20251214/gcc/config/aarch64/predicates.md gcc-16-20251221/gcc/config/aarch64/predicates.md
*** gcc-16-20251214/gcc/config/aarch64/predicates.md	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/aarch64/predicates.md	Sun Dec 21 22:32:06 2025
***************
*** 1092,1104 ****
         (match_test "known_eq (wi::to_poly_wide (op, mode),
  			      BYTES_PER_SVE_VECTOR)")))
  
  (define_predicate "aarch64_memtag_tag_offset"
    (and (match_code "const_int")
!        (match_test "IN_RANGE (INTVAL (op), 0, 15)")))
  
! (define_predicate "aarch64_granule16_uimm6"
    (and (match_code "const_int")
!        (match_test "IN_RANGE (INTVAL (op), 0, 1008)
  		    && !(INTVAL (op) & 0xf)")))
  
  (define_predicate "aarch64_granule16_simm9"
--- 1092,1111 ----
         (match_test "known_eq (wi::to_poly_wide (op, mode),
  			      BYTES_PER_SVE_VECTOR)")))
  
+ ;; The uimm4 field is a 4-bit field that only accepts immediates in the
+ ;; range 0..15.
  (define_predicate "aarch64_memtag_tag_offset"
    (and (match_code "const_int")
!        (match_test "UINTVAL (op) <= 15")))
  
! (define_predicate "aarch64_granule16_memory_operand"
!   (and (match_test "TARGET_MEMTAG")
!        (match_code "mem")
!        (match_test "aarch64_granule16_memory_address_p (op)")))
! 
! (define_predicate "aarch64_granule16_imm6"
    (and (match_code "const_int")
!        (match_test "IN_RANGE (INTVAL (op), -1008, 1008)
  		    && !(INTVAL (op) & 0xf)")))
  
  (define_predicate "aarch64_granule16_simm9"
diff -Nrcpad gcc-16-20251214/gcc/config/aarch64/tuning_models/olympus.h gcc-16-20251221/gcc/config/aarch64/tuning_models/olympus.h
*** gcc-16-20251214/gcc/config/aarch64/tuning_models/olympus.h	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/aarch64/tuning_models/olympus.h	Sun Dec 21 22:32:06 2025
***************
*** 21,26 ****
--- 21,28 ----
  #define GCC_AARCH64_H_OLYMPUS
  
  #include "generic.h"
+ #include "../aarch64-sched-dispatch.h"
+ #include "vec.h"
  
  static struct cpu_regmove_cost olympus_regmove_cost =
  {
*************** static cpu_prefetch_tune olympus_prefetc
*** 169,174 ****
--- 171,532 ----
    -1			/* default_opt_level  */
  };
  
+ /* Olympus dispatch constraint types.  */
+ enum olympus_dispatch_constraint_type
+ {
+   OLYMPUS_TOTAL_SLOTS, /* total slots  */
+   OLYMPUS_M_PIPE,      /* m pipelines  */
+   OLYMPUS_M0_PIPE,     /* m0 pipeline  */
+   OLYMPUS_BRANCH_PIPE, /* branch pipelines  */
+   OLYMPUS_L_SA_PIPE,   /* l, sa pipelines  */
+   OLYMPUS_SA_PIPE,     /* sa pipelines  */
+   OLYMPUS_V_PIPE,      /* v pipelines  */
+   OLYMPUS_V0123_PIPE,  /* v0, v1, v2, v3 pipelines  */
+   OLYMPUS_V03_PIPE,    /* v0, v3 pipelines  */
+   OLYMPUS_V12_PIPE,    /* v1, v2 pipelines  */
+   OLYMPUS_V45_PIPE,    /* v4, v5 pipelines  */
+   OLYMPUS_V0_PIPE      /* v0 pipeline  */
+ };
+ 
+ /* Olympus dispatch constraints for instruction scheduling.
+    The numbers are based on the Olympus CPU Core SWOG, section 4.1.  */
+ static const int olympus_dispatch_max_slots[] = {
+   10, /* total slots  */
+   6,  /* m pipelines  */
+   3,  /* m0 pipeline  */
+   3,  /* branch pipelines  */
+   8,  /* l, sa pipelines  */
+   4,  /* sa pipelines  */
+   6,  /* v pipelines  */
+   4,  /* v0, v1, v2, v3 pipelines  */
+   4,  /* v0, v3 pipelines  */
+   4,  /* v1, v2 pipelines  */
+   2,  /* v4, v5 pipelines  */
+   2   /* v0 pipeline  */
+ };
+ 
+ /* Olympus dispatch constraint callback function.
+    Determines which constraints apply to an instruction and how many slots
+    it requires.  Returns a vec of (constraint_index, slots_required) pairs.  */
+ static vec<std::pair<int, int>>
+ olympus_dispatch_constraint_callback (rtx_insn *insn)
+ {
+   auto dispatch_group = get_attr_olympus_dispatch (insn);
+   vec<std::pair<int, int>> constraints = vNULL;
+ 
+   /* In addition to deducting slots from the specific pipeline types required
+      by an instruction, we keep track of the total number of slots required.
+      There are different cases how total_slots is derived from the specific
+      pipeline slots:
+      Case 1: Single top-level pipeline type used
+        Example groups: OLYMPUS_DISPATCH_B, OLYMPUS_DISPATCH_V_V0123
+        Total_slots is equal to the number of slots for the top-level
+        pipeline type.
+        Example: Assume an instruction in the OLYMPUS_DISPATCH_V_V0123
+        dispatch group is executed as 2 MOps: 1 utilizing any V pipeline and
+        1 utilizing a V0123 pipeline.  It requires 1 slot in the
+        OLYMPUS_V0123_PIPE constraint and a total of 2 slots in the
+        OLYMPUS_V_PIPE constraint, because the V0123 pipelines are a subset of
+        the V pipelines. Total_slots is 2.
+      Case 2: Multiple top-level pipeline types used
+        Example groups: OLYMPUS_DISPATCH_M_V, OLYMPUS_DISPATCH_SA_V_V0123
+        Total_slots is equal to the sum of the slots for the top-level
+        pipeline types.  */
+   int total_slots = 1;
+ 
+   switch (dispatch_group)
+     {
+     case OLYMPUS_DISPATCH_NONE:
+     case OLYMPUS_DISPATCH_I:
+       break;
+ 
+     case OLYMPUS_DISPATCH_B:
+       constraints.safe_push ({OLYMPUS_BRANCH_PIPE, 1});
+       break;
+ 
+     case OLYMPUS_DISPATCH_M:
+       constraints.safe_push ({OLYMPUS_M_PIPE, 1});
+       break;
+ 
+     case OLYMPUS_DISPATCH_M0:
+       constraints.safe_push ({OLYMPUS_M_PIPE, 1});
+       constraints.safe_push ({OLYMPUS_M0_PIPE, 1});
+       break;
+ 
+     case OLYMPUS_DISPATCH_L:
+       {
+ 	auto type_attr = get_attr_type (insn);
+ 	int l_slots = 1;
+ 	if (type_attr == TYPE_NEON_LDP_Q
+ 	    || type_attr == TYPE_NEON_LOAD1_2REG_Q
+ 	    || type_attr == TYPE_NEON_LOAD1_3REG
+ 	    || type_attr == TYPE_NEON_LOAD1_4REG)
+ 	  l_slots = 2;
+ 	else if (type_attr == TYPE_NEON_LOAD1_3REG_Q)
+ 	  l_slots = 3;
+ 	else if (type_attr == TYPE_NEON_LOAD1_4REG_Q)
+ 	  l_slots = 4;
+ 	constraints.safe_push ({OLYMPUS_L_SA_PIPE, l_slots});
+ 	total_slots = l_slots;
+       }
+       break;
+ 
+     case OLYMPUS_DISPATCH_V:
+       {
+ 	auto type_attr = get_attr_type (insn);
+ 	int v_slots = 1;
+ 	if (type_attr == TYPE_NEON_TBL3
+ 	    || type_attr == TYPE_NEON_FP_REDUC_MINMAX_D
+ 	    || type_attr == TYPE_NEON_FP_REDUC_MINMAX_S
+ 	    || get_attr_sve_type (insn) == SVE_TYPE_SVE_FP_REDUC)
+ 	  v_slots = 2;
+ 	else if (type_attr == TYPE_NEON_TBL4
+ 		 || type_attr == TYPE_NEON_FP_REDUC_MINMAX_D_Q
+ 		 || type_attr == TYPE_NEON_FP_REDUC_MINMAX_S_Q)
+ 	  v_slots = 3;
+ 	constraints.safe_push ({OLYMPUS_V_PIPE, v_slots});
+ 	total_slots = v_slots;
+       }
+       break;
+ 
+     case OLYMPUS_DISPATCH_V0:
+       constraints.safe_push ({OLYMPUS_V_PIPE, 1});
+       constraints.safe_push ({OLYMPUS_V0123_PIPE, 1});
+       constraints.safe_push ({OLYMPUS_V03_PIPE, 1});
+       constraints.safe_push ({OLYMPUS_V0_PIPE, 1});
+       break;
+ 
+     case OLYMPUS_DISPATCH_V03:
+       constraints.safe_push ({OLYMPUS_V_PIPE, 1});
+       constraints.safe_push ({OLYMPUS_V0123_PIPE, 1});
+       constraints.safe_push ({OLYMPUS_V03_PIPE, 1});
+       break;
+ 
+     case OLYMPUS_DISPATCH_V12:
+       {
+ 	auto sve_type_attr = get_attr_sve_type (insn);
+ 	int slots = (sve_type_attr == SVE_TYPE_SVE_INT_BIT_PERM) ? 2 : 1;
+ 	constraints.safe_push ({OLYMPUS_V_PIPE, slots});
+ 	constraints.safe_push ({OLYMPUS_V0123_PIPE, slots});
+ 	constraints.safe_push ({OLYMPUS_V12_PIPE, slots});
+ 	total_slots = slots;
+       }
+       break;
+ 
+     case OLYMPUS_DISPATCH_V45:
+       constraints.safe_push ({OLYMPUS_V_PIPE, 1});
+       constraints.safe_push ({OLYMPUS_V45_PIPE, 1});
+       break;
+ 
+     case OLYMPUS_DISPATCH_V0123:
+       constraints.safe_push ({OLYMPUS_V_PIPE, 1});
+       constraints.safe_push ({OLYMPUS_V0123_PIPE, 1});
+       break;
+ 
+     case OLYMPUS_DISPATCH_M_V:
+       constraints.safe_push ({OLYMPUS_M_PIPE, 1});
+       constraints.safe_push ({OLYMPUS_V_PIPE, 1});
+       total_slots = 2;
+       break;
+ 
+     case OLYMPUS_DISPATCH_L_V:
+       {
+ 	auto type_attr = get_attr_type (insn);
+ 	auto sve_type_attr = get_attr_sve_type (insn);
+ 	int l_sa_slots = 1;
+ 	int v_slots = 1;
+ 	if (type_attr == TYPE_NEON_LOAD2_2REG
+ 	    || type_attr == TYPE_NEON_LOAD2_ALL_LANES
+ 	    || type_attr == TYPE_NEON_LOAD2_ALL_LANES_Q
+ 	    || type_attr == TYPE_NEON_LOAD2_ONE_LANE)
+ 	  v_slots = 2;
+ 	else if (type_attr == TYPE_NEON_LOAD2_2REG_Q
+ 		 || sve_type_attr == SVE_TYPE_SVE_LOAD_2REG)
+ 	  {
+ 	    l_sa_slots = 2;
+ 	    v_slots = 2;
+ 	  }
+ 	else if (type_attr == TYPE_NEON_LOAD3_3REG
+ 		 || type_attr == TYPE_NEON_LOAD3_ALL_LANES
+ 		 || type_attr == TYPE_NEON_LOAD3_ONE_LANE
+ 		 || sve_type_attr == SVE_TYPE_SVE_LOAD_3REG)
+ 	  {
+ 	    l_sa_slots = 2;
+ 	    v_slots = 3;
+ 	  }
+ 	else if (type_attr == TYPE_NEON_LOAD3_3REG_Q)
+ 	  {
+ 	    l_sa_slots = 3;
+ 	    v_slots = 3;
+ 	  }
+ 	else if (type_attr == TYPE_NEON_LOAD4_4REG
+ 		 || type_attr == TYPE_NEON_LOAD4_ALL_LANES
+ 		 || type_attr == TYPE_NEON_LOAD4_ONE_LANE)
+ 	  {
+ 	    l_sa_slots = 2;
+ 	    v_slots = 4;
+ 	  }
+ 	else if (type_attr == TYPE_NEON_LOAD4_4REG_Q
+ 		 || sve_type_attr == SVE_TYPE_SVE_LOAD_4REG)
+ 	  {
+ 	    l_sa_slots = 4;
+ 	    v_slots = 6;
+ 	  }
+ 	constraints.safe_push ({OLYMPUS_L_SA_PIPE, l_sa_slots});
+ 	constraints.safe_push ({OLYMPUS_V_PIPE, v_slots});
+ 	total_slots = l_sa_slots + v_slots;
+       }
+       break;
+ 
+     case OLYMPUS_DISPATCH_M_L:
+       constraints.safe_push ({OLYMPUS_M_PIPE, 1});
+       constraints.safe_push ({OLYMPUS_L_SA_PIPE, 1});
+       total_slots = 2;
+       break;
+ 
+     case OLYMPUS_DISPATCH_M_V0123:
+       constraints.safe_push ({OLYMPUS_M_PIPE, 1});
+       constraints.safe_push ({OLYMPUS_V_PIPE, 1});
+       constraints.safe_push ({OLYMPUS_V0123_PIPE, 1});
+       total_slots = 2;
+       break;
+ 
+     case OLYMPUS_DISPATCH_V_V0123:
+       constraints.safe_push ({OLYMPUS_V_PIPE, 2});
+       constraints.safe_push ({OLYMPUS_V0123_PIPE, 1});
+       total_slots = 2;
+       break;
+ 
+     case OLYMPUS_DISPATCH_L_V03:
+       {
+ 	auto sve_type_attr = get_attr_sve_type (insn);
+ 	int l_slots = 1;
+ 	if (sve_type_attr == SVE_TYPE_SVE_GATHERLOAD_32)
+ 	  l_slots = 4;
+ 	else if (sve_type_attr == SVE_TYPE_SVE_GATHERLOAD_64)
+ 	  l_slots = 2;
+ 	constraints.safe_push ({OLYMPUS_L_SA_PIPE, l_slots});
+ 	constraints.safe_push ({OLYMPUS_V_PIPE, 1});
+ 	constraints.safe_push ({OLYMPUS_V0123_PIPE, 1});
+ 	constraints.safe_push ({OLYMPUS_V03_PIPE, 1});
+ 	total_slots = l_slots + 1;
+       }
+       break;
+ 
+     case OLYMPUS_DISPATCH_SA_D:
+       constraints.safe_push ({OLYMPUS_SA_PIPE, 1});
+       break;
+ 
+     case OLYMPUS_DISPATCH_SA_V0123:
+       {
+ 	/* According to the note in section 4.1 of the SWOG, MOps using the
+ 	   V0123 pipeline do not count towards the limits, when those MOps
+ 	   are in the same instruction as a MOp in the SA pipeline.  That is
+ 	   why total_slots is set to the number of slots for the SA pipelines,
+ 	   disregarding the slots for the V0123 pipelines.  */
+ 	auto type_attr = get_attr_type (insn);
+ 	if (type_attr == TYPE_NEON_STORE1_3REG
+ 	    || type_attr == TYPE_NEON_STORE1_3REG_Q
+ 	    || type_attr == TYPE_NEON_STORE1_4REG
+ 	    || type_attr == TYPE_NEON_STORE1_4REG_Q)
+ 	  {
+ 	    constraints.safe_push ({OLYMPUS_SA_PIPE, 2});
+ 	    constraints.safe_push ({OLYMPUS_V_PIPE, 2});
+ 	    constraints.safe_push ({OLYMPUS_V0123_PIPE, 2});
+ 	    total_slots = 2;
+ 	  }
+ 	else
+ 	  {
+ 	    constraints.safe_push ({OLYMPUS_SA_PIPE, 1});
+ 	    constraints.safe_push ({OLYMPUS_V_PIPE, 1});
+ 	    constraints.safe_push ({OLYMPUS_V0123_PIPE, 1});
+ 	    total_slots = 1;
+ 	  }
+       }
+       break;
+ 
+     case OLYMPUS_DISPATCH_SA_V_V0123:
+       {
+ 	auto type_attr = get_attr_type (insn);
+ 	auto sve_type_attr = get_attr_sve_type (insn);
+ 	int sa_slots = 1;
+ 	int v_slots = 2;
+ 	int v0123_slots = 1;
+ 	if (type_attr == TYPE_NEON_STORE2_2REG_Q
+ 	    || type_attr == TYPE_NEON_STORE4_ONE_LANE
+ 	    || type_attr == TYPE_NEON_STORE4_ONE_LANE_Q)
+ 	  v_slots = 3;
+ 	else if (type_attr == TYPE_NEON_STORE3_3REG
+ 		 || type_attr == TYPE_NEON_STORE3_ONE_LANE
+ 		 || type_attr == TYPE_NEON_STORE3_ONE_LANE_Q
+ 		 || sve_type_attr == SVE_TYPE_SVE_STORE_2REG)
+ 	  {
+ 	    sa_slots = 2;
+ 	    v_slots = 4;
+ 	    v0123_slots = 2;
+ 	  }
+ 	else if (type_attr == TYPE_NEON_STORE3_3REG_Q)
+ 	  {
+ 	    sa_slots = 2;
+ 	    v_slots = 5;
+ 	    v0123_slots = 2;
+ 	  }
+ 	else if (type_attr == TYPE_NEON_STORE4_4REG)
+ 	  v_slots = 5;
+ 	else if (type_attr == TYPE_NEON_STORE4_4REG_Q)
+ 	  {
+ 	    sa_slots = 2;
+ 	    v_slots = 6;
+ 	    v0123_slots = 2;
+ 	  }
+ 	else if (sve_type_attr == SVE_TYPE_SVE_STORE_3REG)
+ 	  {
+ 	    sa_slots = 3;
+ 	    v_slots = 6;
+ 	    v0123_slots = 3;
+ 	  }
+ 	else if (sve_type_attr == SVE_TYPE_SVE_STORE_4REG)
+ 	  {
+ 	    sa_slots = 4;
+ 	    v_slots = 6;
+ 	    v0123_slots = 4;
+ 	  }
+ 	else if (sve_type_attr == SVE_TYPE_SVE_SCATTERSTORE_32)
+ 	  {
+ 	    sa_slots = 4;
+ 	    v_slots = 5;
+ 	    v0123_slots = 4;
+ 	  }
+ 	else if (sve_type_attr == SVE_TYPE_SVE_SCATTERSTORE_64)
+ 	  {
+ 	    sa_slots = 2;
+ 	    v_slots = 4;
+ 	    v0123_slots = 3;
+ 	  }
+ 	constraints.safe_push ({OLYMPUS_SA_PIPE, sa_slots});
+ 	constraints.safe_push ({OLYMPUS_V_PIPE, v_slots});
+ 	constraints.safe_push ({OLYMPUS_V0123_PIPE, v0123_slots});
+ 	/* We disregard slots from the V0123 pipelines in total_slots when
+ 	   the instruction also uses the SA pipelines, see comment in
+ 	   OLYMPUS_DISPATCH_SA_V0123.  */
+ 	total_slots = sa_slots + (v_slots - v0123_slots);
+       }
+       break;
+     }
+ 
+   /* Add total slots constraint  */
+   constraints.safe_push ({OLYMPUS_TOTAL_SLOTS, total_slots});
+ 
+   return constraints;
+ }
+ 
+ /* Olympus dispatch constraints configuration. */
+ static const struct dispatch_constraint_info olympus_dispatch_constraint_info = {
+   olympus_dispatch_max_slots,  /* max_slots */
+   ARRAY_SIZE (olympus_dispatch_max_slots),  /* num_constraints */
+   olympus_dispatch_constraint_callback  /* callback */
+ };
+ 
  static struct tune_params olympus_tunings =
  {
    &cortexa76_extra_costs,
*************** static struct tune_params olympus_tuning
*** 201,211 ****
    (AARCH64_EXTRA_TUNE_BASE
     | AARCH64_EXTRA_TUNE_CSE_SVE_VL_CONSTANTS
     | AARCH64_EXTRA_TUNE_MATCHED_VECTOR_THROUGHPUT
!    | AARCH64_EXTRA_TUNE_AVOID_PRED_RMW),	/* tune_flags.  */
    &olympus_prefetch_tune,
    AARCH64_LDP_STP_POLICY_ALWAYS,   /* ldp_policy_model.  */
    AARCH64_LDP_STP_POLICY_ALWAYS,   /* stp_policy_model.  */
!   nullptr	/* dispatch_constraints.  */
  };
  
  #endif /* GCC_AARCH64_H_OLYMPUS.  */
--- 559,570 ----
    (AARCH64_EXTRA_TUNE_BASE
     | AARCH64_EXTRA_TUNE_CSE_SVE_VL_CONSTANTS
     | AARCH64_EXTRA_TUNE_MATCHED_VECTOR_THROUGHPUT
!    | AARCH64_EXTRA_TUNE_AVOID_PRED_RMW
!    | AARCH64_EXTRA_TUNE_DISPATCH_SCHED),	/* tune_flags.  */
    &olympus_prefetch_tune,
    AARCH64_LDP_STP_POLICY_ALWAYS,   /* ldp_policy_model.  */
    AARCH64_LDP_STP_POLICY_ALWAYS,   /* stp_policy_model.  */
!   &olympus_dispatch_constraint_info	/* dispatch_constraints.  */
  };
  
  #endif /* GCC_AARCH64_H_OLYMPUS.  */
diff -Nrcpad gcc-16-20251214/gcc/config/avr/avr-protos.h gcc-16-20251221/gcc/config/avr/avr-protos.h
*** gcc-16-20251214/gcc/config/avr/avr-protos.h	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/avr/avr-protos.h	Sun Dec 21 22:32:06 2025
*************** extern bool avr_nonzero_bits_lsr_operand
*** 141,148 ****
  extern void avr_final_prescan_insn (rtx_insn *insn, rtx *operand,
  				    int num_operands);
  extern rtx_code avr_normalize_condition (rtx_code condition);
- extern void out_shift_with_cnt (const char *templ, rtx_insn *insn,
- 				rtx operands[], int *len, int t_len);
  extern enum reg_class avr_mode_code_base_reg_class (machine_mode, addr_space_t, rtx_code, rtx_code);
  extern bool avr_regno_mode_code_ok_for_base_p (int, machine_mode, addr_space_t, rtx_code, rtx_code);
  extern rtx avr_incoming_return_addr_rtx (void);
--- 141,146 ----
diff -Nrcpad gcc-16-20251214/gcc/config/avr/avr.cc gcc-16-20251221/gcc/config/avr/avr.cc
*** gcc-16-20251214/gcc/config/avr/avr.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/avr/avr.cc	Sun Dec 21 22:32:06 2025
*************** avr_out_cmp_ext (rtx xop[], rtx_code cod
*** 6917,6943 ****
  }
  
  
! /* Generate asm equivalent for various shifts.  This only handles cases
!    that are not already carefully hand-optimized in ?sh<mode>3_out.
  
-    OPERANDS[0] resp. %0 in TEMPL is the operand to be shifted.
     OPERANDS[2] is the shift count as CONST_INT, MEM or REG.
     OPERANDS[3] is a QImode scratch register from LD regs if
!                available and SCRATCH, otherwise (no scratch available)
! 
!    TEMPL is an assembler template that shifts by one position.
!    T_LEN is the length of this template.
     PLEN != 0: Set *PLEN to the length of the sequence in words.
     PLEN == 0: Output instructions.  */
  
! void
! out_shift_with_cnt (const char *templ, rtx_insn *insn, rtx operands[],
! 		    int *plen, int t_len)
  {
    bool second_label = true;
    bool saved_in_tmp = false;
    bool use_zero_reg = false;
!   rtx op[5];
  
    op[0] = operands[0];
    op[1] = operands[1];
--- 6917,6971 ----
  }
  
  
! /* Helper for the next function:  Shift register REG by 1 bit position
!    according to the shift CODE of ASHIFT, LSHIFTRT or ASHIFTRT.
!    PLEN == 0: Asm output respective shift instruction(s).
!    PLEN != 0: Add the length of the sequence in words to *PLEN.  */
! 
! static void
! avr_out_shift_1 (rtx_code code, rtx reg, int *plen)
! {
!   const int n_bytes = GET_MODE_SIZE (GET_MODE (reg));
!   const int dir = code == ASHIFT ? 1 : -1;
!   const int regno = REGNO (reg);
!   const int first = code == ASHIFT ? 0 : n_bytes - 1;
!   for (int i = 0; i < n_bytes; ++i)
!     {
!       rtx reg8 = all_regs_rtx[regno + first + i * dir];
!       if (code == ASHIFT)
! 	avr_asm_len (i == 0 ? "lsl %0" : "rol %0", &reg8, plen, 1);
!       else if (code == LSHIFTRT)
! 	avr_asm_len (i == 0 ? "lsr %0" : "ror %0", &reg8, plen, 1);
!       else if (code == ASHIFTRT)
! 	avr_asm_len (i == 0 ? "asr %0" : "ror %0", &reg8, plen, 1);
!       else
! 	gcc_unreachable ();
!     }
! }
! 
! 
! /* Generate asm code to perform a shift of code CODE on register OPERANDS[0].
!    This only handles cases that are not already carefully hand-optimized
!    in ?sh<mode>3_out.  Always returns "".
  
     OPERANDS[2] is the shift count as CONST_INT, MEM or REG.
     OPERANDS[3] is a QImode scratch register from LD regs if
! 	       available and SCRATCH, otherwise (no scratch available).
     PLEN != 0: Set *PLEN to the length of the sequence in words.
     PLEN == 0: Output instructions.  */
  
! static const char*
! avr_out_shift_with_cnt (rtx_code code, rtx_insn *insn, rtx operands[],
! 			int *plen)
  {
    bool second_label = true;
    bool saved_in_tmp = false;
    bool use_zero_reg = false;
!   bool tail_bits = false;
!   const int t_len = GET_MODE_SIZE (GET_MODE (operands[0]));
!   const int regno = REGNO (operands[0]);
!   const int tail_regno = regno + (code == ASHIFT ? t_len - 1 : 0);
!   rtx op[6];
  
    op[0] = operands[0];
    op[1] = operands[1];
*************** out_shift_with_cnt (const char *templ, r
*** 6961,6985 ****
        int max_len = 10;  /* If larger than this, always use a loop.  */
  
        if (count <= 0)
! 	return;
  
!       if (count < 8 && !scratch)
  	use_zero_reg = true;
  
        if (optimize_size)
! 	max_len = t_len + (scratch ? 3 : (use_zero_reg ? 4 : 5));
  
        if (t_len * count <= max_len)
  	{
  	  /* Output shifts inline with no loop - faster.  */
  
  	  while (count-- > 0)
! 	    avr_asm_len (templ, op, plen, t_len);
  
! 	  return;
  	}
  
!       if (scratch)
  	{
  	  avr_asm_len ("ldi %3,%2", op, plen, 1);
  	}
--- 6989,7035 ----
        int max_len = 10;  /* If larger than this, always use a loop.  */
  
        if (count <= 0)
! 	return "";
  
!       if (count < 8 && tail_regno >= REG_16)
! 	tail_bits = true;
!       else if (count < 8 && !scratch)
  	use_zero_reg = true;
  
        if (optimize_size)
! 	max_len = t_len + (scratch || tail_bits ? 3 : (use_zero_reg ? 4 : 5));
  
        if (t_len * count <= max_len)
  	{
  	  /* Output shifts inline with no loop - faster.  */
  
  	  while (count-- > 0)
! 	    avr_out_shift_1 (code, op[0], plen);
  
! 	  return "";
  	}
  
!       if (tail_bits)
! 	{
! 	  /* The tail register (the last one in a multi-byte shift) is
! 	     an upper register, so we can insert a stop mask into it.
! 	     This will cost 2 instructions, but the loop body is one
! 	     instruction shorter.  That yields the same code size like
! 	     the "scratch" case but saves count-1 cycles.
! 	     The loop branch is a BRCC that sees count-1 zeros and then
! 	     a one to drop out of the loop.  */
! 
! 	  op[3] = all_regs_rtx[tail_regno];
! 	  op[4] = gen_int_mode (code == ASHIFT
! 				? 0xff >> count
! 				: 0xff << count, QImode);
! 	  op[5] = gen_int_mode (code == ASHIFT
! 				? 0x80 >> (count - 1)
! 				: 0x01 << (count - 1), QImode);
! 	  avr_asm_len ("andi %3,%4" CR_TAB
! 		       "ori %3,%5", op, plen, 2);
! 	}
!       else if (scratch)
  	{
  	  avr_asm_len ("ldi %3,%2", op, plen, 1);
  	}
*************** out_shift_with_cnt (const char *templ, r
*** 7035,7050 ****
      avr_asm_len ("rjmp 2f", op, plen, 1);
  
    avr_asm_len ("1:", op, plen, 0);
!   avr_asm_len (templ, op, plen, t_len);
  
    if (second_label)
      avr_asm_len ("2:", op, plen, 0);
  
!   avr_asm_len (use_zero_reg ? "lsr %3" : "dec %3", op, plen, 1);
!   avr_asm_len (second_label ? "brpl 1b" : "brne 1b", op, plen, 1);
  
    if (saved_in_tmp)
      avr_asm_len ("mov %3,%4", op, plen, 1);
  }
  
  
--- 7085,7109 ----
      avr_asm_len ("rjmp 2f", op, plen, 1);
  
    avr_asm_len ("1:", op, plen, 0);
!   avr_out_shift_1 (code, op[0], plen);
  
    if (second_label)
      avr_asm_len ("2:", op, plen, 0);
  
!   if (tail_bits)
!     {
!       avr_asm_len ("brcc 1b", op, plen, 1);
!     }
!   else
!     {
!       avr_asm_len (use_zero_reg ? "lsr %3" : "dec %3", op, plen, 1);
!       avr_asm_len (second_label ? "brpl 1b" : "brne 1b", op, plen, 1);
!     }
  
    if (saved_in_tmp)
      avr_asm_len ("mov %3,%4", op, plen, 1);
+ 
+   return "";
  }
  
  
*************** ashlqi3_out (rtx_insn *insn, rtx operand
*** 7122,7130 ****
    else if (CONSTANT_P (operands[2]))
      fatal_insn ("internal compiler error.  Incorrect shift:", insn);
  
!   out_shift_with_cnt ("lsl %0",
! 		      insn, operands, plen, 1);
!   return "";
  }
  
  
--- 7181,7187 ----
    else if (CONSTANT_P (operands[2]))
      fatal_insn ("internal compiler error.  Incorrect shift:", insn);
  
!   return avr_out_shift_with_cnt (ASHIFT, insn, operands, plen);
  }
  
  
*************** ashlhi3_out (rtx_insn *insn, rtx operand
*** 7389,7397 ****
  	} // switch
      }
  
!   out_shift_with_cnt ("lsl %A0" CR_TAB
! 		      "rol %B0", insn, operands, plen, 2);
!   return "";
  }
  
  
--- 7446,7452 ----
  	} // switch
      }
  
!   return avr_out_shift_with_cnt (ASHIFT, insn, operands, plen);
  }
  
  
*************** avr_out_ashlpsi3 (rtx_insn *insn, rtx *o
*** 7455,7464 ****
  	}
      }
  
!   out_shift_with_cnt ("lsl %A0" CR_TAB
! 		      "rol %B0" CR_TAB
! 		      "rol %C0", insn, op, plen, 3);
!   return "";
  }
  
  
--- 7510,7516 ----
  	}
      }
  
!   return avr_out_shift_with_cnt (ASHIFT, insn, op, plen);
  }
  
  
*************** ashlsi3_out (rtx_insn *insn, rtx operand
*** 7604,7614 ****
  	}
      }
  
!   out_shift_with_cnt ("lsl %A0" CR_TAB
! 		      "rol %B0" CR_TAB
! 		      "rol %C0" CR_TAB
! 		      "rol %D0", insn, operands, plen, 4);
!   return "";
  }
  
  
--- 7656,7662 ----
  	}
      }
  
!   return avr_out_shift_with_cnt (ASHIFT, insn, operands, plen);
  }
  
  
*************** ashrqi3_out (rtx_insn *insn, rtx operand
*** 7659,7667 ****
    else if (CONSTANT_P (operands[2]))
      fatal_insn ("internal compiler error.  Incorrect shift:", insn);
  
!   out_shift_with_cnt ("asr %0",
! 		      insn, operands, plen, 1);
!   return "";
  }
  
  
--- 7707,7713 ----
    else if (CONSTANT_P (operands[2]))
      fatal_insn ("internal compiler error.  Incorrect shift:", insn);
  
!   return avr_out_shift_with_cnt (ASHIFTRT, insn, operands, plen);
  }
  
  
*************** ashrhi3_out (rtx_insn *insn, rtx operand
*** 7818,7826 ****
  	} // switch
      }
  
!   out_shift_with_cnt ("asr %B0" CR_TAB
! 		      "ror %A0", insn, operands, plen, 2);
!   return "";
  }
  
  
--- 7864,7870 ----
  	} // switch
      }
  
!   return avr_out_shift_with_cnt (ASHIFTRT, insn, operands, plen);
  }
  
  
*************** avr_out_ashrpsi3 (rtx_insn *insn, rtx *o
*** 7915,7924 ****
  	} /* switch */
      }
  
!   out_shift_with_cnt ("asr %C0" CR_TAB
! 		      "ror %B0" CR_TAB
! 		      "ror %A0", insn, op, plen, 3);
!   return "";
  }
  
  
--- 7959,7965 ----
  	} /* switch */
      }
  
!   return avr_out_shift_with_cnt (ASHIFTRT, insn, op, plen);
  }
  
  
*************** ashrsi3_out (rtx_insn *insn, rtx operand
*** 8052,8062 ****
  	} // switch
      }
  
!   out_shift_with_cnt ("asr %D0" CR_TAB
! 		      "ror %C0" CR_TAB
! 		      "ror %B0" CR_TAB
! 		      "ror %A0", insn, operands, plen, 4);
!   return "";
  }
  
  /* 8-bit logic shift right ((unsigned char)x >> i) */
--- 8093,8099 ----
  	} // switch
      }
  
!   return avr_out_shift_with_cnt (ASHIFTRT, insn, operands, plen);
  }
  
  /* 8-bit logic shift right ((unsigned char)x >> i) */
*************** lshrqi3_out (rtx_insn *insn, rtx operand
*** 8133,8141 ****
    else if (CONSTANT_P (operands[2]))
      fatal_insn ("internal compiler error.  Incorrect shift:", insn);
  
!   out_shift_with_cnt ("lsr %0",
! 		      insn, operands, plen, 1);
!   return "";
  }
  
  
--- 8170,8176 ----
    else if (CONSTANT_P (operands[2]))
      fatal_insn ("internal compiler error.  Incorrect shift:", insn);
  
!   return avr_out_shift_with_cnt (LSHIFTRT, insn, operands, plen);
  }
  
  
*************** lshrhi3_out (rtx_insn *insn, rtx operand
*** 8339,8347 ****
  	}
      }
  
!   out_shift_with_cnt ("lsr %B0" CR_TAB
! 		      "ror %A0", insn, operands, plen, 2);
!   return "";
  }
  
  
--- 8374,8380 ----
  	}
      }
  
!   return avr_out_shift_with_cnt (LSHIFTRT, insn, operands, plen);
  }
  
  
*************** avr_out_lshrpsi3 (rtx_insn *insn, rtx *o
*** 8406,8415 ****
  	} /* switch */
      }
  
!   out_shift_with_cnt ("lsr %C0" CR_TAB
! 		      "ror %B0" CR_TAB
! 		      "ror %A0", insn, op, plen, 3);
!   return "";
  }
  
  
--- 8439,8445 ----
  	} /* switch */
      }
  
!   return avr_out_shift_with_cnt (LSHIFTRT, insn, op, plen);
  }
  
  
*************** lshrsi3_out (rtx_insn *insn, rtx operand
*** 8555,8565 ****
  	} // switch
      }
  
!   out_shift_with_cnt ("lsr %D0" CR_TAB
! 		      "ror %C0" CR_TAB
! 		      "ror %B0" CR_TAB
! 		      "ror %A0", insn, operands, plen, 4);
!   return "";
  }
  
  
--- 8585,8591 ----
  	} // switch
      }
  
!   return avr_out_shift_with_cnt (LSHIFTRT, insn, operands, plen);
  }
  
  
diff -Nrcpad gcc-16-20251214/gcc/config/avr/avr.md gcc-16-20251221/gcc/config/avr/avr.md
*** gcc-16-20251214/gcc/config/avr/avr.md	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/avr/avr.md	Sun Dec 21 22:32:06 2025
***************
*** 2565,2571 ****
  ;;       return aInt[3*z+2];
  ;;     }
  ;;
! ;; because the constant +4 then is added explicitely instead of consuming it
  ;; with the aInt symbol.  Therefore, we rely on insn combine which takes costs
  ;; into account more accurately and doesn't do burte-force multiply-add/sub.
  ;; The implementational effort is the same so we are fine with that approach.
--- 2565,2571 ----
  ;;       return aInt[3*z+2];
  ;;     }
  ;;
! ;; because the constant +4 then is added explicitly instead of consuming it
  ;; with the aInt symbol.  Therefore, we rely on insn combine which takes costs
  ;; into account more accurately and doesn't do burte-force multiply-add/sub.
  ;; The implementational effort is the same so we are fine with that approach.
***************
*** 3384,3391 ****
     (set (match_dup 0)
          (reg:SI 22))]
    {
!     // Do the QI -> HI extension explicitely before the multiplication.
!     // Do the HI -> SI extension implicitely and after the multiplication.
  
      if (QImode == <MODE>mode)
        operands[1] = gen_rtx_ZERO_EXTEND (HImode, operands[1]);
--- 3384,3391 ----
     (set (match_dup 0)
          (reg:SI 22))]
    {
!     // Do the QI -> HI extension explicitly before the multiplication.
!     // Do the HI -> SI extension implicitly and after the multiplication.
  
      if (QImode == <MODE>mode)
        operands[1] = gen_rtx_ZERO_EXTEND (HImode, operands[1]);
diff -Nrcpad gcc-16-20251214/gcc/config/h8300/h8300-protos.h gcc-16-20251221/gcc/config/h8300/h8300-protos.h
*** gcc-16-20251214/gcc/config/h8300/h8300-protos.h	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/h8300/h8300-protos.h	Sun Dec 21 22:32:06 2025
*************** extern const char *output_simode_bld (in
*** 36,43 ****
  extern void final_prescan_insn (rtx_insn *, rtx *, int);
  extern int h8300_expand_movsi (rtx[]);
  extern machine_mode  h8300_select_cc_mode (RTX_CODE, rtx, rtx);
! extern const char *output_logical_op (machine_mode, rtx_code code,
! 				      rtx *, rtx_insn *);
  extern unsigned int compute_logical_op_length (machine_mode, rtx_code,
  					      rtx *, rtx_insn *);
  
--- 36,42 ----
  extern void final_prescan_insn (rtx_insn *, rtx *, int);
  extern int h8300_expand_movsi (rtx[]);
  extern machine_mode  h8300_select_cc_mode (RTX_CODE, rtx, rtx);
! extern const char *output_logical_op (machine_mode, rtx_code, rtx *, rtx);
  extern unsigned int compute_logical_op_length (machine_mode, rtx_code,
  					      rtx *, rtx_insn *);
  
diff -Nrcpad gcc-16-20251214/gcc/config/h8300/h8300.cc gcc-16-20251221/gcc/config/h8300/h8300.cc
*** gcc-16-20251214/gcc/config/h8300/h8300.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/h8300/h8300.cc	Sun Dec 21 22:32:06 2025
*************** compute_plussi_cc (rtx *operands)
*** 2945,2951 ****
  /* Output a logical insn.  */
  
  const char *
! output_logical_op (machine_mode mode, rtx_code code, rtx *operands, rtx_insn *insn)
  {
    /* Pretend that every byte is affected if both operands are registers.  */
    const unsigned HOST_WIDE_INT intval =
--- 2945,2952 ----
  /* Output a logical insn.  */
  
  const char *
! output_logical_op (machine_mode mode, rtx_code code,
! 		   rtx *operands, rtx pattern)
  {
    /* Pretend that every byte is affected if both operands are registers.  */
    const unsigned HOST_WIDE_INT intval =
*************** output_logical_op (machine_mode mode, rt
*** 2978,2984 ****
  
       The key is to look at the second object in the PARALLEL. If it is not
       a CLOBBER, then we care about the condition codes.  */
-   rtx pattern = PATTERN (insn);
    gcc_assert (GET_CODE (pattern) == PARALLEL);
    rtx second_op = XVECEXP (pattern, 0, 1);
    bool cc_meaningful = (GET_CODE (second_op) != CLOBBER);
--- 2979,2984 ----
*************** h8300_shift_needs_scratch_p (int count,
*** 4053,4072 ****
    gcc_unreachable ();
  }
  
  /* Output the assembler code for doing shifts.  */
  
  const char *
  output_a_shift (rtx operands[4], rtx_code code)
  {
-   static int loopend_lab;
    machine_mode mode = GET_MODE (operands[0]);
    enum shift_type shift_type;
    enum shift_mode shift_mode;
    struct shift_info info;
    int n;
  
-   loopend_lab++;
- 
    switch (mode)
      {
      case E_QImode:
--- 4053,4117 ----
    gcc_unreachable ();
  }
  
+ /* Output a shift loop where the shift count is known.  We use a
+    sentinel bit to know when to stop the loop so that we don't
+    have to decrement a loop counter.  MASK is the bits to leave
+    alone while SET is the bit to set when setting up the sentinel.
+ 
+    OPERANDS are the original operands of the shift.
+ 
+    SHIFT1 is a string for the shift instruction.  This routine does
+    not care about what kind of shift is needed.  */
+ void
+ output_shift_loop (rtx operands[3], rtx mask, rtx set, const char *shift1, const char *shift2)
+ {
+   static int loopend_lab;
+   loopend_lab++;
+   machine_mode mode = GET_MODE (operands[0]);
+ 
+   rtx xoperands[3];
+   xoperands[0] = operands[0];
+   xoperands[1] = operands[0];
+   xoperands[2] = mask;
+   rtx x = gen_rtx_AND (mode, xoperands[1], xoperands[2]);
+   x = gen_rtx_SET (xoperands[0], x);
+   rtvec vec = rtvec_alloc (2);
+   RTVEC_ELT (vec, 0) = x;
+   RTVEC_ELT (vec, 1) = gen_rtx_CLOBBER (VOIDmode,
+ 					gen_rtx_SCRATCH (QImode));
+ 
+   output_logical_op (mode, AND, xoperands,
+ 		     gen_rtx_PARALLEL (VOIDmode, vec));
+ 
+   /* Now set the sentinel bit.  When this bit shifts into C,
+      we are done.  That avoids the need for the decrement in the
+      loop.  We reuse RTL here in a way that would normally be
+      unsafe, but these never actually appear in the IL.  */
+   xoperands[2] = set;
+   x = gen_rtx_IOR (mode, xoperands[1], xoperands[2]);
+   x = gen_rtx_SET (xoperands[0], x);
+   RTVEC_ELT (vec, 0) = x;
+   output_logical_op (mode, IOR, xoperands,
+ 		     gen_rtx_PARALLEL (VOIDmode, vec));
+ 
+   fprintf (asm_out_file, ".Llt%d:\n", loopend_lab);
+   output_asm_insn (shift2 ? shift2 : shift1, operands);
+   fprintf (asm_out_file, "\tbcc	.Llt%d\n", loopend_lab);
+   if (shift2 && INTVAL (operands[2]) % 2)
+     output_asm_insn (shift1, operands);
+ }
+ 
  /* Output the assembler code for doing shifts.  */
  
  const char *
  output_a_shift (rtx operands[4], rtx_code code)
  {
    machine_mode mode = GET_MODE (operands[0]);
    enum shift_type shift_type;
    enum shift_mode shift_mode;
    struct shift_info info;
    int n;
  
    switch (mode)
      {
      case E_QImode:
*************** output_a_shift (rtx operands[4], rtx_cod
*** 4177,4204 ****
  	return "";
        }
  
      case SHIFT_LOOP:
!       /* A loop to shift by a "large" constant value.
! 	 If we have shift-by-2 insns, use them.  */
!       if (info.shift2 != NULL)
  	{
! 	  fprintf (asm_out_file, "\tmov.b	#%d,%sl\n", n / 2,
! 		   names_big[REGNO (operands[3])]);
! 	  fprintf (asm_out_file, ".Llt%d:\n", loopend_lab);
! 	  output_asm_insn (info.shift2, operands);
! 	  output_asm_insn ("add	#0xff,%X3", operands);
! 	  fprintf (asm_out_file, "\tbne	.Llt%d\n", loopend_lab);
! 	  if (n % 2)
! 	    output_asm_insn (info.shift1, operands);
! 	}
        else
  	{
! 	  fprintf (asm_out_file, "\tmov.b	#%d,%sl\n", n,
! 		   names_big[REGNO (operands[3])]);
! 	  fprintf (asm_out_file, ".Llt%d:\n", loopend_lab);
! 	  output_asm_insn (info.shift1, operands);
! 	  output_asm_insn ("add	#0xff,%X3", operands);
! 	  fprintf (asm_out_file, "\tbne	.Llt%d\n", loopend_lab);
  	}
        return "";
  
--- 4222,4245 ----
  	return "";
        }
  
+     /* SHIFT_LOOP is not used for H8/S or newer which have stronger
+        shifters.  */
      case SHIFT_LOOP:
!       if (code == ASHIFT)
  	{
! 	  unsigned HOST_WIDE_INT mask = (1 << (GET_MODE_BITSIZE (mode) - n)) - 1;
! 	  if (info.shift2 && (n & 1))
! 	    n -= 1;
! 	  unsigned HOST_WIDE_INT set = (1 << (GET_MODE_BITSIZE (mode) - n));
! 	  output_shift_loop (operands, GEN_INT (mask), GEN_INT (set), info.shift1, info.shift2);
! 	} 
        else
  	{
! 	  unsigned HOST_WIDE_INT mask =~((HOST_WIDE_INT_1U << n) - 1);
! 	  if (info.shift2 && (n & 1))
! 	    n -= 1;
! 	  unsigned HOST_WIDE_INT set = HOST_WIDE_INT_1U << (n - 1);
! 	  output_shift_loop (operands, GEN_INT (mask), GEN_INT (set), info.shift1, info.shift2);
  	}
        return "";
  
*************** compute_a_shift_length (rtx operands[3],
*** 4358,4367 ****
--- 4399,4420 ----
  	      wlength += 3 + h8300_asm_insn_count (info.shift2);
  	      if (n % 2)
  		wlength += h8300_asm_insn_count (info.shift1);
+ 	      if (mode == E_HImode)
+ 		wlength += 2;
+ 	      else if (mode == E_SImode)
+ 		wlength += 4;
  	    }
  	  else
  	    {
+ 	      /* The loop uses a sentinel as a stop point.  That requires
+ 		 two setup instructions before the loop, but they can be
+ 		 longer based on the mode.  The loop itself is just two
+ 		 two byte instructions.  */
  	      wlength += 3 + h8300_asm_insn_count (info.shift1);
+ 	      if (mode == E_HImode)
+ 		wlength += 2;
+ 	      else if (mode == E_SImode)
+ 		wlength += 4;
  	    }
  	  return 2 * wlength;
  
diff -Nrcpad gcc-16-20251214/gcc/config/h8300/logical.md gcc-16-20251221/gcc/config/h8300/logical.md
*** gcc-16-20251214/gcc/config/h8300/logical.md	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/h8300/logical.md	Sun Dec 21 22:32:06 2025
***************
*** 228,234 ****
  	  (match_operand:QHSI 2 "h8300_src_operand" "rQi")))
     (clobber (reg:CC CC_REG))]
    "h8300_operands_match_p (operands)"
!   { return output_logical_op (<MODE>mode, <CODE>, operands, insn); }
    [(set (attr "length")
  	(symbol_ref "compute_logical_op_length (<MODE>mode, <CODE>, operands, insn)"))])
  
--- 228,234 ----
  	  (match_operand:QHSI 2 "h8300_src_operand" "rQi")))
     (clobber (reg:CC CC_REG))]
    "h8300_operands_match_p (operands)"
!   { return output_logical_op (<MODE>mode, <CODE>, operands, PATTERN (insn)); }
    [(set (attr "length")
  	(symbol_ref "compute_logical_op_length (<MODE>mode, <CODE>, operands, insn)"))])
  
diff -Nrcpad gcc-16-20251214/gcc/config/i386/avx10_2bf16intrin.h gcc-16-20251221/gcc/config/i386/avx10_2bf16intrin.h
*** gcc-16-20251214/gcc/config/i386/avx10_2bf16intrin.h	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/i386/avx10_2bf16intrin.h	Sun Dec 21 22:32:06 2025
*************** _mm_maskz_getexp_pbh (__mmask8 __U, __m1
*** 1339,1376 ****
  #ifdef __OPTIMIZE__
  extern __inline__ __m512bh
  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
! _mm512_roundscale_pbh (__m512bh __A, int B)
  {
    return (__m512bh)
!     __builtin_ia32_rndscalebf16512_mask (__A, B,
  					 (__v32bf) _mm512_setzero_si512 (),
  					 (__mmask32) -1);
  }
  
  extern __inline__ __m512bh
  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
! _mm512_mask_roundscale_pbh (__m512bh __W, __mmask32 __U, __m512bh __A, int B)
  {
    return (__m512bh)
!     __builtin_ia32_rndscalebf16512_mask (__A, B, __W,  __U);
  }
  
  extern __inline__ __m512bh
  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
! _mm512_maskz_roundscale_pbh (__mmask32 __U, __m512bh __A, int B)
  {
    return (__m512bh)
!     __builtin_ia32_rndscalebf16512_mask (__A, B,
  					 (__v32bf) _mm512_setzero_si512 (),
  					 __U);
  }
  
  extern __inline__ __m256bh
  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
! _mm256_roundscale_pbh (__m256bh __A, int B)
  {
    return (__m256bh)
!     __builtin_ia32_rndscalebf16256_mask (__A, B,
  					 (__v16bf) _mm256_setzero_si256 (),
  					 (__mmask16) -1);
  }
--- 1339,1376 ----
  #ifdef __OPTIMIZE__
  extern __inline__ __m512bh
  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
! _mm512_roundscale_pbh (__m512bh __A, int __B)
  {
    return (__m512bh)
!     __builtin_ia32_rndscalebf16512_mask (__A, __B,
  					 (__v32bf) _mm512_setzero_si512 (),
  					 (__mmask32) -1);
  }
  
  extern __inline__ __m512bh
  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
! _mm512_mask_roundscale_pbh (__m512bh __W, __mmask32 __U, __m512bh __A, int __B)
  {
    return (__m512bh)
!     __builtin_ia32_rndscalebf16512_mask (__A, __B, __W, __U);
  }
  
  extern __inline__ __m512bh
  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
! _mm512_maskz_roundscale_pbh (__mmask32 __U, __m512bh __A, int __B)
  {
    return (__m512bh)
!     __builtin_ia32_rndscalebf16512_mask (__A, __B,
  					 (__v32bf) _mm512_setzero_si512 (),
  					 __U);
  }
  
  extern __inline__ __m256bh
  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
! _mm256_roundscale_pbh (__m256bh __A, int __B)
  {
    return (__m256bh)
!     __builtin_ia32_rndscalebf16256_mask (__A, __B,
  					 (__v16bf) _mm256_setzero_si256 (),
  					 (__mmask16) -1);
  }
*************** _mm256_roundscale_pbh (__m256bh __A, int
*** 1378,1405 ****
  extern __inline__ __m256bh
  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
  _mm256_mask_roundscale_pbh (__m256bh __W, __mmask16 __U,
! 			    __m256bh __A, int B)
  {
    return (__m256bh)
!     __builtin_ia32_rndscalebf16256_mask (__A, B, __W, __U);
  }
  
  extern __inline__ __m256bh
  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
! _mm256_maskz_roundscale_pbh (__mmask16 __U, __m256bh __A, int B)
  {
    return (__m256bh)
!     __builtin_ia32_rndscalebf16256_mask (__A, B,
  					 (__v16bf) _mm256_setzero_si256 (),
  					 __U);
  }
  
  extern __inline__ __m128bh
  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
! _mm_roundscale_pbh (__m128bh __A, int B)
  {
    return (__m128bh)
!     __builtin_ia32_rndscalebf16128_mask (__A, B,
  					 (__v8bf) _mm_setzero_si128 (),
  					 (__mmask8) -1);
  }
--- 1378,1405 ----
  extern __inline__ __m256bh
  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
  _mm256_mask_roundscale_pbh (__m256bh __W, __mmask16 __U,
! 			    __m256bh __A, int __B)
  {
    return (__m256bh)
!     __builtin_ia32_rndscalebf16256_mask (__A, __B, __W, __U);
  }
  
  extern __inline__ __m256bh
  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
! _mm256_maskz_roundscale_pbh (__mmask16 __U, __m256bh __A, int __B)
  {
    return (__m256bh)
!     __builtin_ia32_rndscalebf16256_mask (__A, __B,
  					 (__v16bf) _mm256_setzero_si256 (),
  					 __U);
  }
  
  extern __inline__ __m128bh
  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
! _mm_roundscale_pbh (__m128bh __A, int __B)
  {
    return (__m128bh)
!     __builtin_ia32_rndscalebf16128_mask (__A, __B,
  					 (__v8bf) _mm_setzero_si128 (),
  					 (__mmask8) -1);
  }
*************** _mm_roundscale_pbh (__m128bh __A, int B)
*** 1407,1424 ****
  extern __inline__ __m128bh
  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
  _mm_mask_roundscale_pbh (__m128bh __W, __mmask8 __U,
! 			 __m128bh __A, int B)
  {
    return (__m128bh)
!     __builtin_ia32_rndscalebf16128_mask (__A, B, __W, __U);
  }
  
  extern __inline__ __m128bh
  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
! _mm_maskz_roundscale_pbh (__mmask8 __U, __m128bh __A, int B)
  {
    return (__m128bh)
!     __builtin_ia32_rndscalebf16128_mask (__A, B,
  					 (__v8bf) _mm_setzero_si128 (),
  					 __U);
  }
--- 1407,1424 ----
  extern __inline__ __m128bh
  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
  _mm_mask_roundscale_pbh (__m128bh __W, __mmask8 __U,
! 			 __m128bh __A, int __B)
  {
    return (__m128bh)
!     __builtin_ia32_rndscalebf16128_mask (__A, __B, __W, __U);
  }
  
  extern __inline__ __m128bh
  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
! _mm_maskz_roundscale_pbh (__mmask8 __U, __m128bh __A, int __B)
  {
    return (__m128bh)
!     __builtin_ia32_rndscalebf16128_mask (__A, __B,
  					 (__v8bf) _mm_setzero_si128 (),
  					 __U);
  }
*************** _mm_maskz_roundscale_pbh (__mmask8 __U,
*** 1469,1478 ****
  #ifdef __OPTIMIZE__
  extern __inline__ __m512bh
  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
! _mm512_reduce_pbh (__m512bh __A, int B)
  {
    return (__m512bh)
!     __builtin_ia32_reducebf16512_mask (__A, B,
  				       (__v32bf) _mm512_setzero_si512 (),
  				       (__mmask32) -1);
  }
--- 1469,1478 ----
  #ifdef __OPTIMIZE__
  extern __inline__ __m512bh
  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
! _mm512_reduce_pbh (__m512bh __A, int __B)
  {
    return (__m512bh)
!     __builtin_ia32_reducebf16512_mask (__A, __B,
  				       (__v32bf) _mm512_setzero_si512 (),
  				       (__mmask32) -1);
  }
*************** _mm512_reduce_pbh (__m512bh __A, int B)
*** 1480,1507 ****
  extern __inline__ __m512bh
  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
  _mm512_mask_reduce_pbh (__m512bh __W, __mmask32 __U,
! 			__m512bh __A, int B)
  {
    return (__m512bh)
!     __builtin_ia32_reducebf16512_mask (__A, B, __W,  __U);
  }
  
  extern __inline__ __m512bh
  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
! _mm512_maskz_reduce_pbh (__mmask32 __U, __m512bh __A, int B)
  {
    return (__m512bh)
!     __builtin_ia32_reducebf16512_mask (__A, B,
  					  (__v32bf) _mm512_setzero_si512 (),
  					  __U);
  }
  
  extern __inline__ __m256bh
  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
! _mm256_reduce_pbh (__m256bh __A, int B)
  {
    return (__m256bh)
!     __builtin_ia32_reducebf16256_mask (__A, B,
  				       (__v16bf) _mm256_setzero_si256 (),
  				       (__mmask16) -1);
  }
--- 1480,1507 ----
  extern __inline__ __m512bh
  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
  _mm512_mask_reduce_pbh (__m512bh __W, __mmask32 __U,
! 			__m512bh __A, int __B)
  {
    return (__m512bh)
!     __builtin_ia32_reducebf16512_mask (__A, __B, __W,  __U);
  }
  
  extern __inline__ __m512bh
  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
! _mm512_maskz_reduce_pbh (__mmask32 __U, __m512bh __A, int __B)
  {
    return (__m512bh)
!     __builtin_ia32_reducebf16512_mask (__A, __B,
  					  (__v32bf) _mm512_setzero_si512 (),
  					  __U);
  }
  
  extern __inline__ __m256bh
  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
! _mm256_reduce_pbh (__m256bh __A, int __B)
  {
    return (__m256bh)
!     __builtin_ia32_reducebf16256_mask (__A, __B,
  				       (__v16bf) _mm256_setzero_si256 (),
  				       (__mmask16) -1);
  }
*************** _mm256_reduce_pbh (__m256bh __A, int B)
*** 1509,1536 ****
  extern __inline__ __m256bh
  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
  _mm256_mask_reduce_pbh (__m256bh __W, __mmask16 __U,
! 			__m256bh __A, int B)
  {
    return (__m256bh)
!     __builtin_ia32_reducebf16256_mask (__A, B, __W, __U);
  }
  
  extern __inline__ __m256bh
  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
! _mm256_maskz_reduce_pbh (__mmask16 __U, __m256bh __A, int B)
  {
    return (__m256bh)
!     __builtin_ia32_reducebf16256_mask (__A, B,
  				       (__v16bf) _mm256_setzero_si256 (),
  				       __U);
  }
  
  extern __inline__ __m128bh
  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
! _mm_reduce_pbh (__m128bh __A, int B)
  {
    return (__m128bh)
!     __builtin_ia32_reducebf16128_mask (__A, B,
  				       (__v8bf) _mm_setzero_si128 (),
  				       (__mmask8) -1);
  }
--- 1509,1536 ----
  extern __inline__ __m256bh
  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
  _mm256_mask_reduce_pbh (__m256bh __W, __mmask16 __U,
! 			__m256bh __A, int __B)
  {
    return (__m256bh)
!     __builtin_ia32_reducebf16256_mask (__A, __B, __W, __U);
  }
  
  extern __inline__ __m256bh
  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
! _mm256_maskz_reduce_pbh (__mmask16 __U, __m256bh __A, int __B)
  {
    return (__m256bh)
!     __builtin_ia32_reducebf16256_mask (__A, __B,
  				       (__v16bf) _mm256_setzero_si256 (),
  				       __U);
  }
  
  extern __inline__ __m128bh
  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
! _mm_reduce_pbh (__m128bh __A, int __B)
  {
    return (__m128bh)
!     __builtin_ia32_reducebf16128_mask (__A, __B,
  				       (__v8bf) _mm_setzero_si128 (),
  				       (__mmask8) -1);
  }
*************** _mm_reduce_pbh (__m128bh __A, int B)
*** 1538,1555 ****
  extern __inline__ __m128bh
  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
  _mm_mask_reduce_pbh (__m128bh __W, __mmask8 __U,
! 		     __m128bh __A, int B)
  {
    return (__m128bh)
!     __builtin_ia32_reducebf16128_mask (__A, B, __W, __U);
  }
  
  extern __inline__ __m128bh
  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
! _mm_maskz_reduce_pbh (__mmask8 __U, __m128bh __A, int B)
  {
    return (__m128bh)
!     __builtin_ia32_reducebf16128_mask (__A, B,
  				       (__v8bf) _mm_setzero_si128 (),
  				       __U);
  }
--- 1538,1555 ----
  extern __inline__ __m128bh
  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
  _mm_mask_reduce_pbh (__m128bh __W, __mmask8 __U,
! 		     __m128bh __A, int __B)
  {
    return (__m128bh)
!     __builtin_ia32_reducebf16128_mask (__A, __B, __W, __U);
  }
  
  extern __inline__ __m128bh
  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
! _mm_maskz_reduce_pbh (__mmask8 __U, __m128bh __A, int __B)
  {
    return (__m128bh)
!     __builtin_ia32_reducebf16128_mask (__A, __B,
  				       (__v8bf) _mm_setzero_si128 (),
  				       __U);
  }
diff -Nrcpad gcc-16-20251214/gcc/config/i386/avx512bmmintrin.h gcc-16-20251221/gcc/config/i386/avx512bmmintrin.h
*** gcc-16-20251214/gcc/config/i386/avx512bmmintrin.h	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/config/i386/avx512bmmintrin.h	Sun Dec 21 22:32:06 2025
***************
*** 0 ****
--- 1,89 ----
+ /* Copyright (C) 2025 Free Software Foundation, Inc.
+ 
+    This file is part of GCC.
+ 
+    GCC is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3, or (at your option)
+    any later version.
+ 
+    GCC is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+ 
+    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/>.  */
+ 
+ #if !defined _IMMINTRIN_H_INCLUDED
+ # error "Never use <avx512bmmintrin.h> directly; include <immintrin.h> instead."
+ #endif
+ 
+ #ifndef _AVX512BMMINTRIN_H_INCLUDED
+ #define _AVX512BMMINTRIN_H_INCLUDED
+ 
+ #ifndef __AVX512BMM__
+ #pragma GCC push_options
+ #pragma GCC target("avx512bmm")
+ #define __DISABLE_AVX512BMM__
+ #endif /* __AVX512BMM__ */
+ 
+ extern __inline __m512i
+ __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ _mm512_bmacor16x16x16 (__m512i __A, __m512i __B, __m512i __C)
+ {
+   return (__m512i) __builtin_ia32_vbmacor16x16x16_v32hi ((__v32hi) __A,
+ 							 (__v32hi) __B,
+ 							 (__v32hi) __C);
+ }
+ 
+ extern __inline __m512i
+ __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ _mm512_bmacxor16x16x16 (__m512i __A, __m512i __B, __m512i __C)
+ {
+   return (__m512i) __builtin_ia32_vbmacxor16x16x16_v32hi ((__v32hi) __A,
+ 							  (__v32hi) __B,
+ 							  (__v32hi) __C);
+ }
+ 
+ extern __inline __m512i
+ __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+ _mm512_mask_bitrev_epi8 (__mmask64 __U, __m512i __A, __m512i __B)
+ {
+   return (__m512i) __builtin_ia32_vbitrevb512_mask ((__v64qi) __A,
+ 						    (__v64qi) __B,
+ 						    (__mmask64) __U);
+ }
+ 
+ extern __inline __m512i
+ __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+ _mm512_maskz_bitrev_epi8 (__mmask64 __U, __m512i __A)
+ {
+   return (__m512i) __builtin_ia32_vbitrevb512_mask ((__v64qi) __A,
+ 						    (__v64qi)(__m512i)
+ 						    _mm512_setzero_epi32 (),
+ 						    (__mmask64) __U);
+ }
+ 
+ extern __inline __m512i
+ __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+ _mm512_bitrev_epi8 (__m512i __A)
+ {
+   return (__m512i) __builtin_ia32_vbitrevb512_mask ((__v64qi) __A,
+ 						    (__v64qi)(__m512i)
+ 						    _mm512_undefined_epi32 (),
+ 						    (__mmask64) -1);
+ }
+ 
+ #ifdef __DISABLE_AVX512BMM__
+ #undef __DISABLE_AVX512BMM__
+ #pragma GCC pop_options
+ #endif /* __DISABLE_AVX512BMM__ */
+ 
+ #endif /* _AVX512BMMINTRIN_H_INCLUDED */
diff -Nrcpad gcc-16-20251214/gcc/config/i386/avx512bmmvlintrin.h gcc-16-20251221/gcc/config/i386/avx512bmmvlintrin.h
*** gcc-16-20251214/gcc/config/i386/avx512bmmvlintrin.h	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/config/i386/avx512bmmvlintrin.h	Sun Dec 21 22:32:06 2025
***************
*** 0 ****
--- 1,118 ----
+ /* Copyright (C) 2025 Free Software Foundation, Inc.
+ 
+    This file is part of GCC.
+ 
+    GCC is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3, or (at your option)
+    any later version.
+ 
+    GCC is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+ 
+    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/>.  */
+ 
+ #if !defined _IMMINTRIN_H_INCLUDED
+ # error "Never use <avx512bmmvlintrin.h> directly; include <immintrin.h> instead."
+ #endif
+ 
+ #ifndef _AVX512BMMVLINTRIN_H_INCLUDED
+ #define _AVX512BMMVLINTRIN_H_INCLUDED
+ 
+ #if !defined(__AVX512VL__) || !defined(__AVX512BMM__)
+ #pragma GCC push_options
+ #pragma GCC target("avx512bmm,avx512vl")
+ #define __DISABLE_AVX512BMMVL__
+ #endif /* __AVX512BMM__ */
+ 
+ extern __inline __m256i
+ __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ _mm256_bmacor16x16x16 (__m256i __A, __m256i __B, __m256i __C)
+ {
+    return (__m256i) __builtin_ia32_vbmacor16x16x16_v16hi ((__v16hi) __A,
+ 							  (__v16hi) __B,
+ 							  (__v16hi) __C);
+ }
+ 
+ extern __inline __m256i
+ __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ _mm256_bmacxor16x16x16 (__m256i __A, __m256i __B, __m256i __C)
+ {
+   return (__m256i) __builtin_ia32_vbmacxor16x16x16_v16hi ((__v16hi) __A,
+ 							  (__v16hi) __B,
+ 							  (__v16hi) __C);
+ }
+ 
+ extern __inline __m128i
+ __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+ _mm128_mask_bitrev_epi8 (__mmask16 __U, __m128i __A, __m128i __B)
+ {
+   return (__m128i) __builtin_ia32_vbitrevb128_mask ((__v16qi) __A,
+ 						    (__v16qi) __B,
+ 						    (__mmask16) __U);
+ }
+ 
+ extern __inline __m128i
+ __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+ _mm128_maskz_bitrev_epi8 (__mmask16 __U, __m128i __A)
+ {
+   return (__m128i) __builtin_ia32_vbitrevb128_mask ((__v16qi) __A,
+ 						    (__v16qi)(__m128i)
+ 						    _mm_setzero_si128 (),
+ 						    (__mmask16) __U);
+ }
+ 
+ extern __inline __m128i
+ __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+ _mm128_bitrev_epi8 (__m128i __A)
+ {
+   return (__m128i) __builtin_ia32_vbitrevb128_mask ((__v16qi) __A,
+ 						    (__v16qi)(__m128i)
+ 						    _mm_undefined_si128 (),
+ 						    (__mmask16) -1);
+ }
+ 
+ extern __inline __m256i
+ __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+ _mm256_mask_bitrev_epi8 (__mmask32 __U, __m256i __A, __m256i __B)
+ {
+   return (__m256i) __builtin_ia32_vbitrevb256_mask ((__v32qi) __A,
+ 						    (__v32qi) __B,
+ 						    (__mmask32) __U);
+ }
+ 
+ extern __inline __m256i
+ __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+ _mm256_maskz_bitrev_epi8 (__mmask32 __U, __m256i __A)
+ {
+   return (__m256i) __builtin_ia32_vbitrevb256_mask ((__v32qi) __A,
+ 						    (__v32qi)(__m256i)
+ 						    _mm256_setzero_si256 (),
+ 						    (__mmask32) __U);
+ }
+ 
+ extern __inline __m256i
+ __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+ _mm256_bitrev_epi8 (__m256i __A)
+ {
+   return (__m256i) __builtin_ia32_vbitrevb256_mask ((__v32qi) __A,
+ 						    (__v32qi)(__m256i)
+ 						    _mm256_undefined_si256 (),
+ 						    (__mmask32) -1);
+ }
+ 
+ #ifdef __DISABLE_AVX512BMMVL__
+ #undef __DISABLE_AVX512BMMVL__
+ #pragma GCC pop_options
+ #endif /* __DISABLE_AVX512BMMVL__ */
+ 
+ #endif /* _AVX512BMMVLINTRIN_H_INCLUDED */
diff -Nrcpad gcc-16-20251214/gcc/config/i386/cpuid.h gcc-16-20251221/gcc/config/i386/cpuid.h
*** gcc-16-20251214/gcc/config/i386/cpuid.h	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/i386/cpuid.h	Sun Dec 21 22:32:06 2025
***************
*** 167,172 ****
--- 167,175 ----
  #define bit_AESKLE	( 1<<0 )
  #define bit_WIDEKL	( 1<<2 )
  
+ /* Sub leaf (%eax == 0x21) */
+ #define bit_AVX512BMM	( 1<<23 )
+ 
  /* AMX sub leaf (%eax == 0x1e, %ecx == 1) */
  /* %eax */
  #define bit_AMX_FP8	(1 << 4)
diff -Nrcpad gcc-16-20251214/gcc/config/i386/cygming.h gcc-16-20251221/gcc/config/i386/cygming.h
*** gcc-16-20251214/gcc/config/i386/cygming.h	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/i386/cygming.h	Sun Dec 21 22:32:06 2025
*************** do {						\
*** 474,476 ****
--- 474,500 ----
    (ix86_cmodel == CM_LARGE_PIC || ix86_cmodel == CM_MEDIUM_PIC)
  
  #define HAVE_64BIT_POINTERS TARGET_64BIT_DEFAULT
+ 
+ /* Support for Windows resource files.  */
+ #if TARGET_64BIT_DEFAULT
+ #define WINDRES_FORMAT_SPEC \
+       "%{m32:-F pe-i386;m64|!m32:-F pe-x86-64} "
+ #else
+ #define WINDRES_FORMAT_SPEC \
+       "%{m64:-F pe-x86-64;m32|!m64:-F pe-i386} "
+ #endif
+ 
+ #define EXTRA_DEFAULT_COMPILERS \
+   {".rc", "@windres-rc", 0, 0, 0}, \
+   {"@windres-rc", \
+    "%{!E:%{!M:%{!MM:windres -J rc -O coff " \
+       WINDRES_FORMAT_SPEC \
+       "%{I*:-I%*} %{D*:-D%*} %{U*:-U%*} \
+       %{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O} %i}}}", \
+    0, 0, 0}, \
+   {".res", "@windres-res", 0, 0, 0}, \
+   {"@windres-res", \
+    "%{!E:%{!M:%{!MM:windres -J res -O coff " \
+       WINDRES_FORMAT_SPEC \
+       "%{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O} %i}}}", \
+    0, 0, 0},
diff -Nrcpad gcc-16-20251214/gcc/config/i386/driver-i386.cc gcc-16-20251221/gcc/config/i386/driver-i386.cc
*** gcc-16-20251214/gcc/config/i386/driver-i386.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/i386/driver-i386.cc	Sun Dec 21 22:32:06 2025
*************** const char *host_detect_local_cpu (int a
*** 466,471 ****
--- 466,473 ----
  	processor = PROCESSOR_GEODE;
        else if (has_feature (FEATURE_MOVBE) && family == 22)
  	processor = PROCESSOR_BTVER2;
+       else if (has_feature (FEATURE_AVX512BMM))
+ 	processor = PROCESSOR_ZNVER6;
        else if (has_feature (FEATURE_AVX512VP2INTERSECT))
  	processor = PROCESSOR_ZNVER5;
        else if (has_feature (FEATURE_AVX512F))
*************** const char *host_detect_local_cpu (int a
*** 830,835 ****
--- 832,840 ----
      case PROCESSOR_ZNVER5:
        cpu = "znver5";
        break;
+     case PROCESSOR_ZNVER6:
+       cpu = "znver6";
+       break;
      case PROCESSOR_BTVER1:
        cpu = "btver1";
        break;
diff -Nrcpad gcc-16-20251214/gcc/config/i386/i386-builtin.def gcc-16-20251221/gcc/config/i386/i386-builtin.def
*** gcc-16-20251214/gcc/config/i386/i386-builtin.def	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/i386/i386-builtin.def	Sun Dec 21 22:32:06 2025
*************** BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_
*** 2881,2886 ****
--- 2881,2894 ----
  BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512BF16, CODE_FOR_avx512f_dpbf16ps_v4sf_maskz, "__builtin_ia32_dpbf16ps_v4sf_maskz", IX86_BUILTIN_DPBF16PS_V4SF_MASKZ, UNKNOWN, (int) V4SF_FTYPE_V4SF_V8BF_V8BF_UQI)
  BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_extendbfsf2_1, "__builtin_ia32_cvtbf2sf", IX86_BUILTIN_CVTBF2SF, UNKNOWN, (int) FLOAT_FTYPE_BFLOAT16)
  
+ /* AVX512BMM.  */
+ BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512BMM, CODE_FOR_avx512bmm_vbmacor16x16x16_v16hi, "__builtin_ia32_vbmacor16x16x16_v16hi", IX86_BUILTIN_VBMACORV16HI, UNKNOWN, (int) V16HI_FTYPE_V16HI_V16HI_V16HI)
+ BDESC (0, OPTION_MASK_ISA2_AVX512BMM, CODE_FOR_avx512bmm_vbmacor16x16x16_v32hi, "__builtin_ia32_vbmacor16x16x16_v32hi", IX86_BUILTIN_VBMACORV32HI, UNKNOWN, (int) V32HI_FTYPE_V32HI_V32HI_V32HI)
+ BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512BMM, CODE_FOR_avx512bmm_vbmacxor16x16x16_v16hi, "__builtin_ia32_vbmacxor16x16x16_v16hi", IX86_BUILTIN_VBMACXORV16HI, UNKNOWN, (int) V16HI_FTYPE_V16HI_V16HI_V16HI)
+ BDESC (0, OPTION_MASK_ISA2_AVX512BMM, CODE_FOR_avx512bmm_vbmacxor16x16x16_v32hi, "__builtin_ia32_vbmacxor16x16x16_v32hi", IX86_BUILTIN_VBMACXORV32HI, UNKNOWN, (int) V32HI_FTYPE_V32HI_V32HI_V32HI)
+ BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512BMM, CODE_FOR_avx512bmm_vbitrevb_v16qi_mask, "__builtin_ia32_vbitrevb128_mask", IX86_BUILTIN_VBITREV16_MASK, UNKNOWN, (int) V16QI_FTYPE_V16QI_V16QI_UHI)
+ BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512BMM, CODE_FOR_avx512bmm_vbitrevb_v32qi_mask, "__builtin_ia32_vbitrevb256_mask", IX86_BUILTIN_VBITREV32_MASK, UNKNOWN, (int) V32QI_FTYPE_V32QI_V32QI_USI)
+ BDESC (0, OPTION_MASK_ISA2_AVX512BMM, CODE_FOR_avx512bmm_vbitrevb_v64qi_mask, "__builtin_ia32_vbitrevb512_mask", IX86_BUILTIN_VBITREV64_MASK, UNKNOWN, (int) V64QI_FTYPE_V64QI_V64QI_UDI)
  
  /* AVX512FP16.  */
  BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_addv8hf3_mask, "__builtin_ia32_addph128_mask", IX86_BUILTIN_ADDPH128_MASK, UNKNOWN, (int) V8HF_FTYPE_V8HF_V8HF_V8HF_UQI)
diff -Nrcpad gcc-16-20251214/gcc/config/i386/i386-c.cc gcc-16-20251221/gcc/config/i386/i386-c.cc
*** gcc-16-20251214/gcc/config/i386/i386-c.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/i386/i386-c.cc	Sun Dec 21 22:32:06 2025
*************** ix86_target_macros_internal (HOST_WIDE_I
*** 140,145 ****
--- 140,149 ----
        def_or_undef (parse_in, "__znver5");
        def_or_undef (parse_in, "__znver5__");
        break;
+     case PROCESSOR_ZNVER6:
+       def_or_undef (parse_in, "__znver6");
+       def_or_undef (parse_in, "__znver6__");
+       break;
      case PROCESSOR_BTVER1:
        def_or_undef (parse_in, "__btver1");
        def_or_undef (parse_in, "__btver1__");
*************** ix86_target_macros_internal (HOST_WIDE_I
*** 386,391 ****
--- 390,398 ----
      case PROCESSOR_ZNVER5:
        def_or_undef (parse_in, "__tune_znver5__");
        break;
+     case PROCESSOR_ZNVER6:
+       def_or_undef (parse_in, "__tune_znver6__");
+       break;
      case PROCESSOR_BTVER1:
        def_or_undef (parse_in, "__tune_btver1__");
        break;
*************** ix86_target_macros_internal (HOST_WIDE_I
*** 756,761 ****
--- 763,770 ----
      def_or_undef (parse_in, "__MOVRS__");
    if (isa_flag2 & OPTION_MASK_ISA2_AMX_MOVRS)
      def_or_undef (parse_in, "__AMX_MOVRS__");
+   if (isa_flag2 & OPTION_MASK_ISA2_AVX512BMM)
+     def_or_undef (parse_in, "__AVX512BMM__");
    if (TARGET_IAMCU)
      {
        def_or_undef (parse_in, "__iamcu");
diff -Nrcpad gcc-16-20251214/gcc/config/i386/i386-expand.cc gcc-16-20251221/gcc/config/i386/i386-expand.cc
*** gcc-16-20251214/gcc/config/i386/i386-expand.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/i386/i386-expand.cc	Sun Dec 21 22:32:06 2025
*************** ix86_expand_builtin (tree exp, rtx targe
*** 15131,15137 ****
  	for (i = 0; i < 3; i++)
  	  xmm_regs[i] = gen_rtx_REG (V2DImode, GET_SSE_REGNO (i));
  
! 	if (target == 0)
  	  target = gen_reg_rtx (SImode);
  
  	emit_insn (gen_encodekey128u32 (target, op0));
--- 15131,15137 ----
  	for (i = 0; i < 3; i++)
  	  xmm_regs[i] = gen_rtx_REG (V2DImode, GET_SSE_REGNO (i));
  
! 	if (target == 0 || !register_operand (target, SImode))
  	  target = gen_reg_rtx (SImode);
  
  	emit_insn (gen_encodekey128u32 (target, op0));
*************** ix86_expand_builtin (tree exp, rtx targe
*** 15174,15180 ****
  	for (i = 0; i < 4; i++)
  	  xmm_regs[i] = gen_rtx_REG (V2DImode, GET_SSE_REGNO (i));
  
! 	if (target == 0)
  	  target = gen_reg_rtx (SImode);
  
  	emit_insn (gen_encodekey256u32 (target, op0));
--- 15174,15180 ----
  	for (i = 0; i < 4; i++)
  	  xmm_regs[i] = gen_rtx_REG (V2DImode, GET_SSE_REGNO (i));
  
! 	if (target == 0 || !register_operand (target, SImode))
  	  target = gen_reg_rtx (SImode);
  
  	emit_insn (gen_encodekey256u32 (target, op0));
*************** ix86_expand_builtin (tree exp, rtx targe
*** 15323,15329 ****
  	  }
  	else
  	  {
! 	    if (target == 0)
  	      target = gen_reg_rtx (DImode);
  	    icode = CODE_FOR_urdmsr;
  	    op1 = op0;
--- 15323,15329 ----
  	  }
  	else
  	  {
! 	    if (target == 0 || !register_operand (target, DImode))
  	      target = gen_reg_rtx (DImode);
  	    icode = CODE_FOR_urdmsr;
  	    op1 = op0;
diff -Nrcpad gcc-16-20251214/gcc/config/i386/i386-isa.def gcc-16-20251221/gcc/config/i386/i386-isa.def
*** gcc-16-20251214/gcc/config/i386/i386-isa.def	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/i386/i386-isa.def	Sun Dec 21 22:32:06 2025
*************** DEF_PTA(AMX_TF32)
*** 125,127 ****
--- 125,128 ----
  DEF_PTA(AMX_FP8)
  DEF_PTA(MOVRS)
  DEF_PTA(AMX_MOVRS)
+ DEF_PTA(AVX512BMM)
diff -Nrcpad gcc-16-20251214/gcc/config/i386/i386-options.cc gcc-16-20251221/gcc/config/i386/i386-options.cc
*** gcc-16-20251214/gcc/config/i386/i386-options.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/i386/i386-options.cc	Sun Dec 21 22:32:06 2025
*************** along with GCC; see the file COPYING3.
*** 177,187 ****
  #define m_ZNVER3 (HOST_WIDE_INT_1U<<PROCESSOR_ZNVER3)
  #define m_ZNVER4 (HOST_WIDE_INT_1U<<PROCESSOR_ZNVER4)
  #define m_ZNVER5 (HOST_WIDE_INT_1U<<PROCESSOR_ZNVER5)
  #define m_BTVER1 (HOST_WIDE_INT_1U<<PROCESSOR_BTVER1)
  #define m_BTVER2 (HOST_WIDE_INT_1U<<PROCESSOR_BTVER2)
  #define m_BDVER	(m_BDVER1 | m_BDVER2 | m_BDVER3 | m_BDVER4)
  #define m_BTVER (m_BTVER1 | m_BTVER2)
! #define m_ZNVER (m_ZNVER1 | m_ZNVER2 | m_ZNVER3 | m_ZNVER4 | m_ZNVER5)
  #define m_AMD_MULTIPLE (m_ATHLON_K8 | m_AMDFAM10 | m_BDVER | m_BTVER \
  			| m_ZNVER)
  
--- 177,188 ----
  #define m_ZNVER3 (HOST_WIDE_INT_1U<<PROCESSOR_ZNVER3)
  #define m_ZNVER4 (HOST_WIDE_INT_1U<<PROCESSOR_ZNVER4)
  #define m_ZNVER5 (HOST_WIDE_INT_1U<<PROCESSOR_ZNVER5)
+ #define m_ZNVER6 (HOST_WIDE_INT_1U<<PROCESSOR_ZNVER6)
  #define m_BTVER1 (HOST_WIDE_INT_1U<<PROCESSOR_BTVER1)
  #define m_BTVER2 (HOST_WIDE_INT_1U<<PROCESSOR_BTVER2)
  #define m_BDVER	(m_BDVER1 | m_BDVER2 | m_BDVER3 | m_BDVER4)
  #define m_BTVER (m_BTVER1 | m_BTVER2)
! #define m_ZNVER (m_ZNVER1 | m_ZNVER2 | m_ZNVER3 | m_ZNVER4 | m_ZNVER5 | m_ZNVER6)
  #define m_AMD_MULTIPLE (m_ATHLON_K8 | m_AMDFAM10 | m_BDVER | m_BTVER \
  			| m_ZNVER)
  
*************** static struct ix86_target_opts isa2_opts
*** 267,273 ****
    { "-mamx-tf32",	OPTION_MASK_ISA2_AMX_TF32 },
    { "-mamx-fp8", 	OPTION_MASK_ISA2_AMX_FP8 },
    { "-mmovrs",		OPTION_MASK_ISA2_MOVRS },
!   { "-mamx-movrs",	OPTION_MASK_ISA2_AMX_MOVRS }
  };
  static struct ix86_target_opts isa_opts[] =
  {
--- 268,275 ----
    { "-mamx-tf32",	OPTION_MASK_ISA2_AMX_TF32 },
    { "-mamx-fp8", 	OPTION_MASK_ISA2_AMX_FP8 },
    { "-mmovrs",		OPTION_MASK_ISA2_MOVRS },
!   { "-mamx-movrs",	OPTION_MASK_ISA2_AMX_MOVRS },
!   { "-mavx512bmm",	OPTION_MASK_ISA2_AVX512BMM }
  };
  static struct ix86_target_opts isa_opts[] =
  {
*************** static const struct processor_costs *pro
*** 811,817 ****
    &znver2_cost,		/* PROCESSOR_ZNVER2.		*/
    &znver3_cost,		/* PROCESSOR_ZNVER3.		*/
    &znver4_cost,		/* PROCESSOR_ZNVER4.		*/
!   &znver5_cost		/* PROCESSOR_ZNVER5.		*/
  };
  
  /* Guarantee that the array is aligned with enum processor_type.  */
--- 813,820 ----
    &znver2_cost,		/* PROCESSOR_ZNVER2.		*/
    &znver3_cost,		/* PROCESSOR_ZNVER3.		*/
    &znver4_cost,		/* PROCESSOR_ZNVER4.		*/
!   &znver5_cost,		/* PROCESSOR_ZNVER5.		*/
!   &znver5_cost		/* PROCESSOR_ZNVER6.		*/
  };
  
  /* Guarantee that the array is aligned with enum processor_type.  */
*************** ix86_valid_target_attribute_inner_p (tre
*** 1127,1132 ****
--- 1130,1136 ----
      IX86_ATTR_ISA ("amx-fp8", OPT_mamx_fp8),
      IX86_ATTR_ISA ("movrs", OPT_mmovrs),
      IX86_ATTR_ISA ("amx-movrs", OPT_mamx_movrs),
+     IX86_ATTR_ISA ("avx512bmm", OPT_mavx512bmm),
  
      /* enum options */
      IX86_ATTR_ENUM ("fpmath=",	OPT_mfpmath_),
diff -Nrcpad gcc-16-20251214/gcc/config/i386/i386.cc gcc-16-20251221/gcc/config/i386/i386.cc
*** gcc-16-20251214/gcc/config/i386/i386.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/i386/i386.cc	Sun Dec 21 22:32:06 2025
*************** static rtx
*** 8047,8053 ****
  ix86_get_drap_rtx (void)
  {
    /* We must use DRAP if there are outgoing arguments on stack or
!      the stack pointer register is clobbered by asm statment and
       ACCUMULATE_OUTGOING_ARGS is false.  */
    if (ix86_force_drap
        || ((cfun->machine->outgoing_args_on_stack
--- 8047,8053 ----
  ix86_get_drap_rtx (void)
  {
    /* We must use DRAP if there are outgoing arguments on stack or
!      the stack pointer register is clobbered by asm statement and
       ACCUMULATE_OUTGOING_ARGS is false.  */
    if (ix86_force_drap
        || ((cfun->machine->outgoing_args_on_stack
*************** ix86_reassociation_width (unsigned int o
*** 25550,25556 ****
  	return 1;
        /* Znver5 can do 2 integer multiplications per cycle with latency
  	 of 3.  */
!       if (ix86_tune == PROCESSOR_ZNVER5
  	  && INTEGRAL_MODE_P (mode) && op != PLUS && op != MINUS)
  	width = 6;
  
--- 25550,25556 ----
  	return 1;
        /* Znver5 can do 2 integer multiplications per cycle with latency
  	 of 3.  */
!       if ((ix86_tune == PROCESSOR_ZNVER5 || ix86_tune == PROCESSOR_ZNVER6)
  	  && INTEGRAL_MODE_P (mode) && op != PLUS && op != MINUS)
  	width = 6;
  
diff -Nrcpad gcc-16-20251214/gcc/config/i386/i386.h gcc-16-20251221/gcc/config/i386/i386.h
*** gcc-16-20251214/gcc/config/i386/i386.h	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/i386/i386.h	Sun Dec 21 22:32:06 2025
*************** enum processor_type
*** 2380,2385 ****
--- 2380,2386 ----
    PROCESSOR_ZNVER3,
    PROCESSOR_ZNVER4,
    PROCESSOR_ZNVER5,
+   PROCESSOR_ZNVER6,
    PROCESSOR_max
  };
  
*************** constexpr wide_int_bitmask PTA_ZNVER4 =
*** 2525,2530 ****
--- 2526,2533 ----
    | PTA_AVX512VNNI | PTA_AVX512BITALG | PTA_AVX512VPOPCNTDQ;
  constexpr wide_int_bitmask PTA_ZNVER5 = PTA_ZNVER4 | PTA_AVXVNNI
    | PTA_MOVDIRI | PTA_MOVDIR64B | PTA_AVX512VP2INTERSECT | PTA_PREFETCHI;
+ constexpr wide_int_bitmask PTA_ZNVER6 = PTA_ZNVER5 | PTA_AVXVNNIINT8
+   | PTA_AVXNECONVERT | PTA_AVX512BMM | PTA_AVXIFMA | PTA_AVX512FP16;
  
  constexpr wide_int_bitmask PTA_BTVER1 = PTA_64BIT | PTA_MMX | PTA_SSE
    | PTA_SSE2 | PTA_SSE3 | PTA_SSSE3 | PTA_SSE4A | PTA_LZCNT | PTA_POPCNT
diff -Nrcpad gcc-16-20251214/gcc/config/i386/i386.md gcc-16-20251221/gcc/config/i386/i386.md
*** gcc-16-20251214/gcc/config/i386/i386.md	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/i386/i386.md	Sun Dec 21 22:32:06 2025
***************
*** 530,536 ****
  (define_attr "cpu" "none,pentium,pentiumpro,geode,k6,athlon,k8,core2,nehalem,
  		    atom,slm,glm,haswell,generic,lujiazui,yongfeng,amdfam10,bdver1,
  		    bdver2,bdver3,bdver4,btver2,znver1,znver2,znver3,znver4,
! 		    znver5"
    (const (symbol_ref "ix86_schedule")))
  
  ;; A basic instruction type.  Refinements due to arguments to be
--- 530,536 ----
  (define_attr "cpu" "none,pentium,pentiumpro,geode,k6,athlon,k8,core2,nehalem,
  		    atom,slm,glm,haswell,generic,lujiazui,yongfeng,amdfam10,bdver1,
  		    bdver2,bdver3,bdver4,btver2,znver1,znver2,znver3,znver4,
! 		    znver5,znver6"
    (const (symbol_ref "ix86_schedule")))
  
  ;; A basic instruction type.  Refinements due to arguments to be
diff -Nrcpad gcc-16-20251214/gcc/config/i386/i386.opt gcc-16-20251221/gcc/config/i386/i386.opt
*** gcc-16-20251214/gcc/config/i386/i386.opt	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/i386/i386.opt	Sun Dec 21 22:32:06 2025
*************** Support MOVRS built-in functions and cod
*** 1373,1375 ****
--- 1373,1379 ----
  mamx-movrs
  Target Mask(ISA2_AMX_MOVRS) Var(ix86_isa_flags2) Save
  Support AMX-MOVRS built-in functions and code generation.
+ 
+ mavx512bmm
+ Target Mask(ISA2_AVX512BMM) Var(ix86_isa_flags2) Save
+ Support AVX512BMM built-in functions and code generation.
diff -Nrcpad gcc-16-20251214/gcc/config/i386/i386.opt.urls gcc-16-20251221/gcc/config/i386/i386.opt.urls
*** gcc-16-20251214/gcc/config/i386/i386.opt.urls	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/i386/i386.opt.urls	Sun Dec 21 22:32:06 2025
*************** UrlSuffix(gcc/x86-Options.html#index-mmo
*** 614,616 ****
--- 614,619 ----
  mamx-movrs
  UrlSuffix(gcc/x86-Options.html#index-mamx-movrs)
  
+ mavx512bmm
+ UrlSuffix(gcc/x86-Options.html#index-mavx512bmm)
+ 
diff -Nrcpad gcc-16-20251214/gcc/config/i386/immintrin.h gcc-16-20251221/gcc/config/i386/immintrin.h
*** gcc-16-20251214/gcc/config/i386/immintrin.h	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/i386/immintrin.h	Sun Dec 21 22:32:06 2025
***************
*** 159,162 ****
--- 159,166 ----
  #include <movrsintrin.h>
  
  #include <amxmovrsintrin.h>
+ 
+ #include <avx512bmmintrin.h>
+ 
+ #include <avx512bmmvlintrin.h>
  #endif /* _IMMINTRIN_H_INCLUDED */
diff -Nrcpad gcc-16-20251214/gcc/config/i386/sse.md gcc-16-20251221/gcc/config/i386/sse.md
*** gcc-16-20251214/gcc/config/i386/sse.md	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/i386/sse.md	Sun Dec 21 22:32:06 2025
***************
*** 251,256 ****
--- 251,261 ----
    UNSPEC_MINMAXBF16
    UNSPEC_MINMAX
  
+   ;; For AVX512BMM support
+   UNSPEC_VBMACOR
+   UNSPEC_VBMACXOR
+   UNSPEC_VBITREV
+ 
    ;; For MOVRS suppport
    UNSPEC_VMOVRS
  ])
***************
*** 33137,33139 ****
--- 33142,33196 ----
     (set_attr "prefix" "evex")
     (set_attr "memory" "load")
     (set_attr "mode" "<sseinsnmode>")])
+ 
+ (define_mode_iterator VI2_256_512_AVX512VL
+   [V32HI (V16HI "TARGET_AVX512VL")])
+ 
+ (define_insn "avx512bmm_vbmacor16x16x16_<mode>"
+   [(set (match_operand:VI2_256_512_AVX512VL 0 "register_operand" "=v")
+ 	(unspec:VI2_256_512_AVX512VL
+ 	  [(match_operand:VI2_256_512_AVX512VL 1 "register_operand" "0")
+ 	   (match_operand:VI2_256_512_AVX512VL 2 "register_operand" "v")
+ 	   (match_operand:VI2_256_512_AVX512VL 3 "nonimmediate_operand" "vm")]
+ 	  UNSPEC_VBMACOR))]
+   "TARGET_AVX512BMM"
+   "vbmacor16x16x16\t{%3, %2, %0|%0, %2, %3}"
+    [(set_attr ("prefix") ("evex"))
+    (set_attr "mode" "<sseinsnmode>")])
+ 
+ 
+ (define_insn "avx512bmm_vbmacxor16x16x16_<mode>"
+   [(set (match_operand:VI2_256_512_AVX512VL 0 "register_operand" "=v")
+ 	(unspec:VI2_256_512_AVX512VL
+ 	  [(match_operand:VI2_256_512_AVX512VL 1 "register_operand" "0")
+ 	   (match_operand:VI2_256_512_AVX512VL 2 "register_operand" "v")
+ 	   (match_operand:VI2_256_512_AVX512VL 3 "nonimmediate_operand" "vm")]
+ 	  UNSPEC_VBMACXOR))]
+   "TARGET_AVX512BMM"
+   "vbmacxor16x16x16\t{%3, %2, %0|%0, %2, %3}"
+    [(set_attr ("prefix") ("evex"))
+    (set_attr "mode" "<sseinsnmode>")])
+ 
+ (define_insn "avx512bmm_vbitrevb_<mode>_mask"
+   [(set (match_operand:VI1_AVX512VL 0 "register_operand" "=v")
+ 	(vec_merge:VI1_AVX512VL
+ 	  (unspec:VI1_AVX512VL
+ 	     [(match_operand:VI1_AVX512VL 1 "nonimmediate_operand" "vm")]
+ 	    UNSPEC_VBITREV)
+ 	  (match_operand:VI1_AVX512VL 2 "reg_or_0_operand" "0C")
+ 	  (match_operand:<avx512fmaskmode> 3 "register_operand" "Yk")))]
+   "TARGET_AVX512BMM"
+   "vbitrevb\t{%1, %0%{%3%}%N2|%0%{%3%}%N2, %1}"
+   [(set_attr "prefix" "evex")
+    (set_attr "mode" "<sseinsnmode>")])
+ 
+ (define_insn "avx512bmm_vbitrevb_<mode>"
+   [(set (match_operand:VI1_AVX512VL 0 "register_operand" "=v")
+ 	(unspec:VI1_AVX512VL
+ 	  [(match_operand:VI1_AVX512VL 1 "nonimmediate_operand" "vm")]
+           UNSPEC_VBITREV)
+ 	)]
+   "TARGET_AVX512BMM"
+   "vbitrevb\t{%1, %0|%0, %1}"
+   [(set_attr "prefix" "evex")
+    (set_attr "mode" "<sseinsnmode>")])
diff -Nrcpad gcc-16-20251214/gcc/config/i386/x86-tune-sched.cc gcc-16-20251221/gcc/config/i386/x86-tune-sched.cc
*** gcc-16-20251214/gcc/config/i386/x86-tune-sched.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/i386/x86-tune-sched.cc	Sun Dec 21 22:32:06 2025
*************** ix86_issue_rate (void)
*** 90,95 ****
--- 90,96 ----
         is not going to be able to use more than 4 instructions since that
         is limits of the decoders.  */
      case PROCESSOR_ZNVER5:
+     case PROCESSOR_ZNVER6:
        return 4;
  
      case PROCESSOR_ICELAKE_CLIENT:
*************** ix86_adjust_cost (rtx_insn *insn, int de
*** 438,443 ****
--- 439,445 ----
      case PROCESSOR_ZNVER3:
      case PROCESSOR_ZNVER4:
      case PROCESSOR_ZNVER5:
+     case PROCESSOR_ZNVER6:
        /* Stack engine allows to execute push&pop instructions in parall.  */
        if ((insn_type == TYPE_PUSH || insn_type == TYPE_POP)
  	  && (dep_insn_type == TYPE_PUSH || dep_insn_type == TYPE_POP))
diff -Nrcpad gcc-16-20251214/gcc/config/i386/x86-tune.def gcc-16-20251221/gcc/config/i386/x86-tune.def
*** gcc-16-20251214/gcc/config/i386/x86-tune.def	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/i386/x86-tune.def	Sun Dec 21 22:32:06 2025
*************** DEF_TUNE (X86_TUNE_FUSE_CMP_AND_BRANCH_S
*** 147,159 ****
     TODO: znver5 supports fusing with SUB, ADD, INC, DEC, OR, AND,
     There is also limitation for immediate and displacement supported.  */
  DEF_TUNE (X86_TUNE_FUSE_ALU_AND_BRANCH, "fuse_alu_and_branch",
! 	  m_SANDYBRIDGE | m_CORE_AVX2 | m_ZHAOXIN | m_GENERIC | m_ZNVER3 | m_ZNVER4 | m_ZNVER5)
  
  /* X86_TUNE_FUSE_MOV_AND_ALU: mov and alu in case mov is reg-reg mov
     and the destination is used by alu.  alu must be one of
     ADD, ADC, AND, XOR, OR, SUB, SBB, INC, DEC, NOT, SAL, SHL, SHR, SAR.  */
  DEF_TUNE (X86_TUNE_FUSE_MOV_AND_ALU, "fuse_mov_and_alu",
! 	 m_ZNVER5 | m_GRANITERAPIDS | m_GRANITERAPIDS_D)
  
  /* X86_TUNE_FUSE_AND_BRANCH_MEM: Fuse alu with a subsequent conditional
     jump instruction when alu contains memory operand.
--- 147,160 ----
     TODO: znver5 supports fusing with SUB, ADD, INC, DEC, OR, AND,
     There is also limitation for immediate and displacement supported.  */
  DEF_TUNE (X86_TUNE_FUSE_ALU_AND_BRANCH, "fuse_alu_and_branch",
! 	  m_SANDYBRIDGE | m_CORE_AVX2 | m_ZHAOXIN | m_GENERIC | m_ZNVER3 | m_ZNVER4 | m_ZNVER5
! 	  | m_ZNVER6)
  
  /* X86_TUNE_FUSE_MOV_AND_ALU: mov and alu in case mov is reg-reg mov
     and the destination is used by alu.  alu must be one of
     ADD, ADC, AND, XOR, OR, SUB, SBB, INC, DEC, NOT, SAL, SHL, SHR, SAR.  */
  DEF_TUNE (X86_TUNE_FUSE_MOV_AND_ALU, "fuse_mov_and_alu",
! 	 m_ZNVER5 | m_ZNVER6 | m_GRANITERAPIDS | m_GRANITERAPIDS_D)
  
  /* X86_TUNE_FUSE_AND_BRANCH_MEM: Fuse alu with a subsequent conditional
     jump instruction when alu contains memory operand.
*************** DEF_TUNE (X86_TUNE_USE_GATHER_2PARTS, "u
*** 519,525 ****
  /* X86_TUNE_USE_SCATTER_2PARTS: Use scater instructions for vectors with 2
     elements.  */
  DEF_TUNE (X86_TUNE_USE_SCATTER_2PARTS, "use_scatter_2parts",
! 	  ~(m_ZNVER4 | m_ZNVER5))
  
  /* X86_TUNE_USE_GATHER_4PARTS: Use gather instructions for vectors with 4
     elements.  */
--- 520,526 ----
  /* X86_TUNE_USE_SCATTER_2PARTS: Use scater instructions for vectors with 2
     elements.  */
  DEF_TUNE (X86_TUNE_USE_SCATTER_2PARTS, "use_scatter_2parts",
! 	  ~(m_ZNVER4 | m_ZNVER5 | m_ZNVER6))
  
  /* X86_TUNE_USE_GATHER_4PARTS: Use gather instructions for vectors with 4
     elements.  */
*************** DEF_TUNE (X86_TUNE_USE_GATHER_4PARTS, "u
*** 530,536 ****
  /* X86_TUNE_USE_SCATTER_4PARTS: Use scater instructions for vectors with 4
     elements.  */
  DEF_TUNE (X86_TUNE_USE_SCATTER_4PARTS, "use_scatter_4parts",
! 	  ~(m_ZNVER4 | m_ZNVER5))
  
  /* X86_TUNE_USE_GATHER: Use gather instructions for vectors with 8 or more
     elements.  */
--- 531,537 ----
  /* X86_TUNE_USE_SCATTER_4PARTS: Use scater instructions for vectors with 4
     elements.  */
  DEF_TUNE (X86_TUNE_USE_SCATTER_4PARTS, "use_scatter_4parts",
! 	  ~(m_ZNVER4 | m_ZNVER5 | m_ZNVER6))
  
  /* X86_TUNE_USE_GATHER: Use gather instructions for vectors with 8 or more
     elements.  */
*************** DEF_TUNE (X86_TUNE_USE_GATHER_8PARTS, "u
*** 541,547 ****
  /* X86_TUNE_USE_SCATTER: Use scater instructions for vectors with 8 or more
     elements.  */
  DEF_TUNE (X86_TUNE_USE_SCATTER_8PARTS, "use_scatter_8parts",
! 	  ~(m_ZNVER4 | m_ZNVER5))
  
  /* X86_TUNE_AVOID_128FMA_CHAINS: Avoid creating loops with tight 128bit or
     smaller FMA chain.  */
--- 542,548 ----
  /* X86_TUNE_USE_SCATTER: Use scater instructions for vectors with 8 or more
     elements.  */
  DEF_TUNE (X86_TUNE_USE_SCATTER_8PARTS, "use_scatter_8parts",
! 	  ~(m_ZNVER4 | m_ZNVER5 | m_ZNVER6))
  
  /* X86_TUNE_AVOID_128FMA_CHAINS: Avoid creating loops with tight 128bit or
     smaller FMA chain.  */
*************** DEF_TUNE (X86_TUNE_AVOID_128FMA_CHAINS,
*** 551,563 ****
  /* X86_TUNE_AVOID_256FMA_CHAINS: Avoid creating loops with tight 256bit or
     smaller FMA chain.  */
  DEF_TUNE (X86_TUNE_AVOID_256FMA_CHAINS, "avoid_fma256_chains",
! 	  m_ZNVER2 | m_ZNVER3 | m_ZNVER4 | m_ZNVER5 | m_CORE_HYBRID
  	  | m_SAPPHIRERAPIDS | m_GRANITERAPIDS | m_GRANITERAPIDS_D
  	  | m_DIAMONDRAPIDS | m_CORE_ATOM | m_GENERIC)
  
  /* X86_TUNE_AVOID_512FMA_CHAINS: Avoid creating loops with tight 512bit or
     smaller FMA chain.  */
! DEF_TUNE (X86_TUNE_AVOID_512FMA_CHAINS, "avoid_fma512_chains", m_ZNVER5)
  
  /* X86_TUNE_V2DF_REDUCTION_PREFER_PHADDPD: Prefer haddpd
     for v2df vector reduction.  */
--- 552,565 ----
  /* X86_TUNE_AVOID_256FMA_CHAINS: Avoid creating loops with tight 256bit or
     smaller FMA chain.  */
  DEF_TUNE (X86_TUNE_AVOID_256FMA_CHAINS, "avoid_fma256_chains",
! 	  m_ZNVER2 | m_ZNVER3 | m_ZNVER4 | m_ZNVER5  | m_ZNVER6 | m_CORE_HYBRID
  	  | m_SAPPHIRERAPIDS | m_GRANITERAPIDS | m_GRANITERAPIDS_D
  	  | m_DIAMONDRAPIDS | m_CORE_ATOM | m_GENERIC)
  
  /* X86_TUNE_AVOID_512FMA_CHAINS: Avoid creating loops with tight 512bit or
     smaller FMA chain.  */
! DEF_TUNE (X86_TUNE_AVOID_512FMA_CHAINS, "avoid_fma512_chains", m_ZNVER5
! 	  | m_ZNVER6)
  
  /* X86_TUNE_V2DF_REDUCTION_PREFER_PHADDPD: Prefer haddpd
     for v2df vector reduction.  */
*************** DEF_TUNE (X86_TUNE_AVX256_MOVE_BY_PIECES
*** 622,628 ****
  /* X86_TUNE_AVX512_MOVE_BY_PIECES: Optimize move_by_pieces with 512-bit
     AVX instructions.  */
  DEF_TUNE (X86_TUNE_AVX512_MOVE_BY_PIECES, "avx512_move_by_pieces",
! 	   m_ZNVER4 | m_ZNVER5)
  
  /* X86_TUNE_AVX512_TWO_EPILOGUES: Use two vector epilogues for 512-bit
     vectorized loops.  */
--- 624,630 ----
  /* X86_TUNE_AVX512_MOVE_BY_PIECES: Optimize move_by_pieces with 512-bit
     AVX instructions.  */
  DEF_TUNE (X86_TUNE_AVX512_MOVE_BY_PIECES, "avx512_move_by_pieces",
! 	   m_ZNVER4 | m_ZNVER5 | m_ZNVER6)
  
  /* X86_TUNE_AVX512_TWO_EPILOGUES: Use two vector epilogues for 512-bit
     vectorized loops.  */
diff -Nrcpad gcc-16-20251214/gcc/config/i386/xmmintrin.h gcc-16-20251221/gcc/config/i386/xmmintrin.h
*** gcc-16-20251214/gcc/config/i386/xmmintrin.h	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/i386/xmmintrin.h	Sun Dec 21 22:32:06 2025
*************** _mm_maskmove_si64 (__m64 __A, __m64 __N,
*** 1223,1239 ****
    __v2di __N128 = __extension__ (__v2di) { ((__v1di) __N)[0], 0 };
  
    /* Check the alignment of __P.  */
!   __SIZE_TYPE__ offset = ((__SIZE_TYPE__) __P) & 0xf;
!   if (offset)
      {
        /* If the misalignment of __P > 8, subtract __P by 8 bytes.
  	 Otherwise, subtract __P by the misalignment.  */
!       if (offset > 8)
! 	offset = 8;
!       __P = (char *) (((__SIZE_TYPE__) __P) - offset);
  
        /* Shift __A128 and __N128 to the left by the adjustment.  */
!       switch (offset)
  	{
  	case 1:
  	  __A128 = __builtin_ia32_pslldqi128 (__A128, 8);
--- 1223,1239 ----
    __v2di __N128 = __extension__ (__v2di) { ((__v1di) __N)[0], 0 };
  
    /* Check the alignment of __P.  */
!   __SIZE_TYPE__ __offset = ((__SIZE_TYPE__) __P) & 0xf;
!   if (__offset)
      {
        /* If the misalignment of __P > 8, subtract __P by 8 bytes.
  	 Otherwise, subtract __P by the misalignment.  */
!       if (__offset > 8)
! 	__offset = 8;
!       __P = (char *) (((__SIZE_TYPE__) __P) - __offset);
  
        /* Shift __A128 and __N128 to the left by the adjustment.  */
!       switch (__offset)
  	{
  	case 1:
  	  __A128 = __builtin_ia32_pslldqi128 (__A128, 8);
diff -Nrcpad gcc-16-20251214/gcc/config/loongarch/loongarch.cc gcc-16-20251221/gcc/config/loongarch/loongarch.cc
*** gcc-16-20251214/gcc/config/loongarch/loongarch.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/loongarch/loongarch.cc	Sun Dec 21 22:32:06 2025
*************** loongarch_modes_tieable_p (machine_mode
*** 7514,7520 ****
  	  || (GET_MODE_CLASS(mode1) == MODE_FLOAT
  	      && GET_MODE_CLASS(mode2) == MODE_INT)
  	  || (GET_MODE_CLASS(mode2) == MODE_FLOAT
! 	      && GET_MODE_CLASS(mode1) == MODE_INT));
  }
  
  /* Implement TARGET_PREFERRED_RELOAD_CLASS.  */
--- 7514,7524 ----
  	  || (GET_MODE_CLASS(mode1) == MODE_FLOAT
  	      && GET_MODE_CLASS(mode2) == MODE_INT)
  	  || (GET_MODE_CLASS(mode2) == MODE_FLOAT
! 	      && GET_MODE_CLASS(mode1) == MODE_INT)
! 	  || (GET_MODE_CLASS (mode1) == MODE_VECTOR_INT
! 	      && GET_MODE_CLASS (mode2) == MODE_VECTOR_INT)
! 	  || (GET_MODE_CLASS (mode1) == MODE_VECTOR_FLOAT
! 	      &&  GET_MODE_CLASS (mode2) == MODE_VECTOR_FLOAT));
  }
  
  /* Implement TARGET_PREFERRED_RELOAD_CLASS.  */
*************** loongarch_option_restore (struct gcc_opt
*** 8440,8445 ****
--- 8444,8450 ----
    la_target.cpu_arch = ptr->x_la_opt_cpu_arch;
    la_target.cpu_tune = ptr->x_la_opt_cpu_tune;
  
+   la_target.isa.base = loongarch_cpu_default_isa[la_target.cpu_arch].base;
    la_target.isa.fpu = ptr->x_la_opt_fpu;
    la_target.isa.simd = ptr->x_la_opt_simd;
    la_target.isa.evolution = ptr->x_la_isa_evolution;
diff -Nrcpad gcc-16-20251214/gcc/config/riscv/autovec-opt.md gcc-16-20251221/gcc/config/riscv/autovec-opt.md
*** gcc-16-20251214/gcc/config/riscv/autovec-opt.md	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/riscv/autovec-opt.md	Sun Dec 21 22:32:06 2025
***************
*** 37,53 ****
  ;; -----------------------------------------------------------------------------
  
  (define_split
!   [(set (match_operand:VB      0 "register_operand")
! 	(if_then_else:VB
! 	  (unspec:VB
! 	    [(match_operand:VB 1 "vector_all_trues_mask_operand")
  	     (match_operand    4 "vector_length_operand")
  	     (match_operand    5 "const_int_operand")
  	     (match_operand    6 "const_int_operand")
  	     (reg:SI VL_REGNUM)
  	     (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
! 	  (match_operand:VB    3 "vector_move_operand")
! 	  (match_operand:VB    2 "vector_undef_operand")))]
    "TARGET_VECTOR"
    [(const_int 0)]
    {
--- 37,53 ----
  ;; -----------------------------------------------------------------------------
  
  (define_split
!   [(set (match_operand:VB_VLS      0 "register_operand")
! 	(if_then_else:VB_VLS
! 	  (unspec:VB_VLS
! 	    [(match_operand:VB_VLS 1 "vector_all_trues_mask_operand")
  	     (match_operand    4 "vector_length_operand")
  	     (match_operand    5 "const_int_operand")
  	     (match_operand    6 "const_int_operand")
  	     (reg:SI VL_REGNUM)
  	     (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
! 	  (match_operand:VB_VLS    3 "vector_move_operand")
! 	  (match_operand:VB_VLS    2 "vector_undef_operand")))]
    "TARGET_VECTOR"
    [(const_int 0)]
    {
***************
*** 1447,1457 ****
  
  ;; Combine neg + vfsgnj to vfsgnjn
  (define_insn_and_split "*copysign<mode>_neg"
!   [(set (match_operand:VF 0 "register_operand")
!         (neg:VF
!           (unspec:VF [
!             (match_operand:VF 1 "register_operand")
!             (match_operand:VF 2 "register_operand")
            ] UNSPEC_VCOPYSIGN)))]
    "TARGET_VECTOR && can_create_pseudo_p ()"
    "#"
--- 1447,1457 ----
  
  ;; Combine neg + vfsgnj to vfsgnjn
  (define_insn_and_split "*copysign<mode>_neg"
!   [(set (match_operand:V_VLSF 0 "register_operand")
!         (neg:V_VLSF
!           (unspec:V_VLSF [
!             (match_operand:V_VLSF 1 "register_operand")
!             (match_operand:V_VLSF 2 "register_operand")
            ] UNSPEC_VCOPYSIGN)))]
    "TARGET_VECTOR && can_create_pseudo_p ()"
    "#"
diff -Nrcpad gcc-16-20251214/gcc/config/riscv/autovec.md gcc-16-20251221/gcc/config/riscv/autovec.md
*** gcc-16-20251214/gcc/config/riscv/autovec.md	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/riscv/autovec.md	Sun Dec 21 22:32:06 2025
***************
*** 23,32 ****
  ;; =========================================================================
  
  (define_expand "mask_len_load<mode><vm>"
!   [(match_operand:V 0 "register_operand")
!    (match_operand:V 1 "memory_operand")
     (match_operand:<VM> 2 "vector_mask_operand")
!    (match_operand:V 3 "maskload_else_operand")
     (match_operand 4 "autovec_length_operand")
     (match_operand 5 "const_0_operand")]
    "TARGET_VECTOR"
--- 23,32 ----
  ;; =========================================================================
  
  (define_expand "mask_len_load<mode><vm>"
!   [(match_operand:V_VLS 0 "register_operand")
!    (match_operand:V_VLS 1 "memory_operand")
     (match_operand:<VM> 2 "vector_mask_operand")
!    (match_operand:V_VLS 3 "maskload_else_operand")
     (match_operand 4 "autovec_length_operand")
     (match_operand 5 "const_0_operand")]
    "TARGET_VECTOR"
***************
*** 36,43 ****
  })
  
  (define_expand "mask_len_store<mode><vm>"
!   [(match_operand:V 0 "memory_operand")
!    (match_operand:V 1 "register_operand")
     (match_operand:<VM> 2 "vector_mask_operand")
     (match_operand 3 "autovec_length_operand")
     (match_operand 4 "const_0_operand")]
--- 36,43 ----
  })
  
  (define_expand "mask_len_store<mode><vm>"
!   [(match_operand:V_VLS 0 "memory_operand")
!    (match_operand:V_VLS 1 "register_operand")
     (match_operand:<VM> 2 "vector_mask_operand")
     (match_operand 3 "autovec_length_operand")
     (match_operand 4 "const_0_operand")]
***************
*** 51,160 ****
  ;; == Gather Load
  ;; =========================================================================
  
! (define_expand "mask_len_gather_load<RATIO64:mode><RATIO64I:mode>"
!   [(match_operand:RATIO64 0 "register_operand")
     (match_operand 1 "pmode_reg_or_0_operand")
!    (match_operand:RATIO64I 2 "register_operand")
     (match_operand 3 "const_1_operand")
     (match_operand 4 "const_1_operand")
!    (match_operand:<RATIO64:VM> 5 "vector_mask_operand")
     (match_operand 6 "maskload_else_operand")
     (match_operand 7 "autovec_length_operand")
     (match_operand 8 "const_0_operand")]
!   "TARGET_VECTOR && riscv_vector::gather_scatter_valid_offset_p (<RATIO64I:MODE>mode)"
  {
    riscv_vector::expand_gather_scatter (operands, true);
    DONE;
  })
  
! (define_expand "mask_len_gather_load<RATIO32:mode><RATIO32I:mode>"
!   [(match_operand:RATIO32 0 "register_operand")
     (match_operand 1 "pmode_reg_or_0_operand")
!    (match_operand:RATIO32I 2 "register_operand")
     (match_operand 3 "const_1_operand")
     (match_operand 4 "const_1_operand")
!    (match_operand:<RATIO32:VM> 5 "vector_mask_operand")
     (match_operand 6 "maskload_else_operand")
     (match_operand 7 "autovec_length_operand")
     (match_operand 8 "const_0_operand")]
!   "TARGET_VECTOR && riscv_vector::gather_scatter_valid_offset_p (<RATIO32I:MODE>mode)"
  {
    riscv_vector::expand_gather_scatter (operands, true);
    DONE;
  })
  
! (define_expand "mask_len_gather_load<RATIO16:mode><RATIO16I:mode>"
!   [(match_operand:RATIO16 0 "register_operand")
     (match_operand 1 "pmode_reg_or_0_operand")
!    (match_operand:RATIO16I 2 "register_operand")
     (match_operand 3 "const_1_operand")
     (match_operand 4 "const_1_operand")
!    (match_operand:<RATIO16:VM> 5 "vector_mask_operand")
     (match_operand 6 "maskload_else_operand")
     (match_operand 7 "autovec_length_operand")
     (match_operand 8 "const_0_operand")]
!   "TARGET_VECTOR && riscv_vector::gather_scatter_valid_offset_p (<RATIO16I:MODE>mode)"
  {
    riscv_vector::expand_gather_scatter (operands, true);
    DONE;
  })
  
! (define_expand "mask_len_gather_load<RATIO8:mode><RATIO8I:mode>"
!   [(match_operand:RATIO8 0 "register_operand")
     (match_operand 1 "pmode_reg_or_0_operand")
!    (match_operand:RATIO8I 2 "register_operand")
     (match_operand 3 "const_1_operand")
     (match_operand 4 "const_1_operand")
!    (match_operand:<RATIO8:VM> 5 "vector_mask_operand")
     (match_operand 6 "maskload_else_operand")
     (match_operand 7 "autovec_length_operand")
     (match_operand 8 "const_0_operand")]
!   "TARGET_VECTOR && riscv_vector::gather_scatter_valid_offset_p (<RATIO8I:MODE>mode)"
  {
    riscv_vector::expand_gather_scatter (operands, true);
    DONE;
  })
  
! (define_expand "mask_len_gather_load<RATIO4:mode><RATIO4I:mode>"
!   [(match_operand:RATIO4 0 "register_operand")
     (match_operand 1 "pmode_reg_or_0_operand")
!    (match_operand:RATIO4I 2 "register_operand")
     (match_operand 3 "const_1_operand")
     (match_operand 4 "const_1_operand")
!    (match_operand:<RATIO4:VM> 5 "vector_mask_operand")
     (match_operand 6 "maskload_else_operand")
     (match_operand 7 "autovec_length_operand")
     (match_operand 8 "const_0_operand")]
!   "TARGET_VECTOR && riscv_vector::gather_scatter_valid_offset_p (<RATIO4I:MODE>mode)"
  {
    riscv_vector::expand_gather_scatter (operands, true);
    DONE;
  })
  
! (define_expand "mask_len_gather_load<RATIO2:mode><RATIO2I:mode>"
!   [(match_operand:RATIO2 0 "register_operand")
     (match_operand 1 "pmode_reg_or_0_operand")
!    (match_operand:RATIO2I 2 "register_operand")
     (match_operand 3 "const_1_operand")
     (match_operand 4 "const_1_operand")
!    (match_operand:<RATIO2:VM> 5 "vector_mask_operand")
     (match_operand 6 "maskload_else_operand")
     (match_operand 7 "autovec_length_operand")
     (match_operand 8 "const_0_operand")]
!   "TARGET_VECTOR && riscv_vector::gather_scatter_valid_offset_p (<RATIO2I:MODE>mode)"
  {
    riscv_vector::expand_gather_scatter (operands, true);
    DONE;
  })
  
! ;; When SEW = 8 and LMUL = 8, we can't find any index mode with
! ;; larger SEW. Since RVV indexed load/store support zero extend
! ;; implicitly and not support scaling, we should only allow
! ;; operands[3] and operands[4] to be const_1_operand.
! (define_expand "mask_len_gather_load<mode><mode>"
!   [(match_operand:RATIO1 0 "register_operand")
     (match_operand 1 "pmode_reg_or_0_operand")
!    (match_operand:RATIO1 2 "register_operand")
     (match_operand 3 "const_1_operand")
     (match_operand 4 "const_1_operand")
     (match_operand:<VM> 5 "vector_mask_operand")
--- 51,163 ----
  ;; == Gather Load
  ;; =========================================================================
  
! ;; Same element size for index, extension operand is irrelevant.
! (define_expand "mask_len_gather_load<mode><vindex>"
!   [(match_operand:VINDEXED 0 "register_operand")
     (match_operand 1 "pmode_reg_or_0_operand")
!    (match_operand:<VINDEX> 2 "register_operand")
     (match_operand 3 "const_1_operand")
     (match_operand 4 "const_1_operand")
!    (match_operand:<VM> 5 "vector_mask_operand")
     (match_operand 6 "maskload_else_operand")
     (match_operand 7 "autovec_length_operand")
     (match_operand 8 "const_0_operand")]
!   "TARGET_VECTOR"
  {
    riscv_vector::expand_gather_scatter (operands, true);
    DONE;
  })
  
! ;; e.g. DImode, index SImode
! (define_expand "mask_len_gather_load<mode><vindex_double_trunc>"
!   [(match_operand:VEEWEXT2 0 "register_operand")
     (match_operand 1 "pmode_reg_or_0_operand")
!    (match_operand:<VINDEX_DOUBLE_TRUNC> 2 "register_operand")
     (match_operand 3 "const_1_operand")
     (match_operand 4 "const_1_operand")
!    (match_operand:<VM> 5 "vector_mask_operand")
     (match_operand 6 "maskload_else_operand")
     (match_operand 7 "autovec_length_operand")
     (match_operand 8 "const_0_operand")]
!   "TARGET_VECTOR"
  {
    riscv_vector::expand_gather_scatter (operands, true);
    DONE;
  })
  
! ;; e.g. DImode, index HImode
! (define_expand "mask_len_gather_load<mode><vindex_quad_trunc>"
!   [(match_operand:VEEWEXT4 0 "register_operand")
     (match_operand 1 "pmode_reg_or_0_operand")
!    (match_operand:<VINDEX_QUAD_TRUNC> 2 "register_operand")
     (match_operand 3 "const_1_operand")
     (match_operand 4 "const_1_operand")
!    (match_operand:<VM> 5 "vector_mask_operand")
     (match_operand 6 "maskload_else_operand")
     (match_operand 7 "autovec_length_operand")
     (match_operand 8 "const_0_operand")]
!   "TARGET_VECTOR"
  {
    riscv_vector::expand_gather_scatter (operands, true);
    DONE;
  })
  
! ;; e.g. DImode, index QImode
! (define_expand "mask_len_gather_load<mode><vindex_oct_trunc>"
!   [(match_operand:VEEWEXT8 0 "register_operand")
     (match_operand 1 "pmode_reg_or_0_operand")
!    (match_operand:<VINDEX_OCT_TRUNC> 2 "register_operand")
     (match_operand 3 "const_1_operand")
     (match_operand 4 "const_1_operand")
!    (match_operand:<VM> 5 "vector_mask_operand")
     (match_operand 6 "maskload_else_operand")
     (match_operand 7 "autovec_length_operand")
     (match_operand 8 "const_0_operand")]
!   "TARGET_VECTOR"
  {
    riscv_vector::expand_gather_scatter (operands, true);
    DONE;
  })
  
! ;; e.g. SImode, index DImode
! (define_expand "mask_len_gather_load<mode><vindex_double_ext>"
!   [(match_operand:VEEWTRUNC2 0 "register_operand")
     (match_operand 1 "pmode_reg_or_0_operand")
!    (match_operand:<VINDEX_DOUBLE_EXT> 2 "register_operand")
     (match_operand 3 "const_1_operand")
     (match_operand 4 "const_1_operand")
!    (match_operand:<VM> 5 "vector_mask_operand")
     (match_operand 6 "maskload_else_operand")
     (match_operand 7 "autovec_length_operand")
     (match_operand 8 "const_0_operand")]
!   "TARGET_VECTOR"
  {
    riscv_vector::expand_gather_scatter (operands, true);
    DONE;
  })
  
! ;; e.g. HImode, index DImode
! (define_expand "mask_len_gather_load<mode><vindex_quad_ext>"
!   [(match_operand:VEEWTRUNC4 0 "register_operand")
     (match_operand 1 "pmode_reg_or_0_operand")
!    (match_operand:<VINDEX_QUAD_EXT> 2 "register_operand")
     (match_operand 3 "const_1_operand")
     (match_operand 4 "const_1_operand")
!    (match_operand:<VM> 5 "vector_mask_operand")
     (match_operand 6 "maskload_else_operand")
     (match_operand 7 "autovec_length_operand")
     (match_operand 8 "const_0_operand")]
!   "TARGET_VECTOR"
  {
    riscv_vector::expand_gather_scatter (operands, true);
    DONE;
  })
  
! ;; e.g. QImode, index DImode
! (define_expand "mask_len_gather_load<mode><vindex_oct_ext>"
!   [(match_operand:VEEWTRUNC8 0 "register_operand")
     (match_operand 1 "pmode_reg_or_0_operand")
!    (match_operand:<VINDEX_OCT_EXT> 2 "register_operand")
     (match_operand 3 "const_1_operand")
     (match_operand 4 "const_1_operand")
     (match_operand:<VM> 5 "vector_mask_operand")
***************
*** 171,276 ****
  ;; == Scatter Store
  ;; =========================================================================
  
! (define_expand "mask_len_scatter_store<RATIO64:mode><RATIO64I:mode>"
    [(match_operand 0 "pmode_reg_or_0_operand")
!    (match_operand:RATIO64I 1 "register_operand")
     (match_operand 2 "const_1_operand")
     (match_operand 3 "const_1_operand")
!    (match_operand:RATIO64 4 "register_operand")
!    (match_operand:<RATIO64:VM> 5 "vector_mask_operand")
     (match_operand 6 "autovec_length_operand")
     (match_operand 7 "const_0_operand")]
!   "TARGET_VECTOR && riscv_vector::gather_scatter_valid_offset_p (<RATIO64I:MODE>mode)"
  {
    riscv_vector::expand_gather_scatter (operands, false);
    DONE;
  })
  
! (define_expand "mask_len_scatter_store<RATIO32:mode><RATIO32I:mode>"
    [(match_operand 0 "pmode_reg_or_0_operand")
!    (match_operand:RATIO32I 1 "register_operand")
     (match_operand 2 "const_1_operand")
     (match_operand 3 "const_1_operand")
!    (match_operand:RATIO32 4 "register_operand")
!    (match_operand:<RATIO32:VM> 5 "vector_mask_operand")
     (match_operand 6 "autovec_length_operand")
     (match_operand 7 "const_0_operand")]
!   "TARGET_VECTOR && riscv_vector::gather_scatter_valid_offset_p (<RATIO32I:MODE>mode)"
  {
    riscv_vector::expand_gather_scatter (operands, false);
    DONE;
  })
  
! (define_expand "mask_len_scatter_store<RATIO16:mode><RATIO16I:mode>"
    [(match_operand 0 "pmode_reg_or_0_operand")
!    (match_operand:RATIO16I 1 "register_operand")
     (match_operand 2 "const_1_operand")
     (match_operand 3 "const_1_operand")
!    (match_operand:RATIO16 4 "register_operand")
!    (match_operand:<RATIO16:VM> 5 "vector_mask_operand")
     (match_operand 6 "autovec_length_operand")
     (match_operand 7 "const_0_operand")]
!   "TARGET_VECTOR && riscv_vector::gather_scatter_valid_offset_p (<RATIO16I:MODE>mode)"
  {
    riscv_vector::expand_gather_scatter (operands, false);
    DONE;
  })
  
! (define_expand "mask_len_scatter_store<RATIO8:mode><RATIO8I:mode>"
    [(match_operand 0 "pmode_reg_or_0_operand")
!    (match_operand:RATIO8I 1 "register_operand")
     (match_operand 2 "const_1_operand")
     (match_operand 3 "const_1_operand")
!    (match_operand:RATIO8 4 "register_operand")
!    (match_operand:<RATIO8:VM> 5 "vector_mask_operand")
     (match_operand 6 "autovec_length_operand")
     (match_operand 7 "const_0_operand")]
!   "TARGET_VECTOR && riscv_vector::gather_scatter_valid_offset_p (<RATIO8I:MODE>mode)"
  {
    riscv_vector::expand_gather_scatter (operands, false);
    DONE;
  })
  
! (define_expand "mask_len_scatter_store<RATIO4:mode><RATIO4I:mode>"
    [(match_operand 0 "pmode_reg_or_0_operand")
!    (match_operand:RATIO4I 1 "register_operand")
     (match_operand 2 "const_1_operand")
     (match_operand 3 "const_1_operand")
!    (match_operand:RATIO4 4 "register_operand")
!    (match_operand:<RATIO4:VM> 5 "vector_mask_operand")
     (match_operand 6 "autovec_length_operand")
     (match_operand 7 "const_0_operand")]
!   "TARGET_VECTOR && riscv_vector::gather_scatter_valid_offset_p (<RATIO4I:MODE>mode)"
  {
    riscv_vector::expand_gather_scatter (operands, false);
    DONE;
  })
  
! (define_expand "mask_len_scatter_store<RATIO2:mode><RATIO2I:mode>"
    [(match_operand 0 "pmode_reg_or_0_operand")
!    (match_operand:RATIO2I 1 "register_operand")
     (match_operand 2 "const_1_operand")
     (match_operand 3 "const_1_operand")
!    (match_operand:RATIO2 4 "register_operand")
!    (match_operand:<RATIO2:VM> 5 "vector_mask_operand")
     (match_operand 6 "autovec_length_operand")
     (match_operand 7 "const_0_operand")]
!   "TARGET_VECTOR && riscv_vector::gather_scatter_valid_offset_p (<RATIO2I:MODE>mode)"
  {
    riscv_vector::expand_gather_scatter (operands, false);
    DONE;
  })
  
! ;; When SEW = 8 and LMUL = 8, we can't find any index mode with
! ;; larger SEW. Since RVV indexed load/store support zero extend
! ;; implicitly and not support scaling, we should only allow
! ;; operands[3] and operands[4] to be const_1_operand.
! (define_expand "mask_len_scatter_store<mode><mode>"
    [(match_operand 0 "pmode_reg_or_0_operand")
!    (match_operand:RATIO1 1 "register_operand")
     (match_operand 2 "const_1_operand")
     (match_operand 3 "const_1_operand")
!    (match_operand:RATIO1 4 "register_operand")
     (match_operand:<VM> 5 "vector_mask_operand")
     (match_operand 6 "autovec_length_operand")
     (match_operand 7 "const_0_operand")]
--- 174,275 ----
  ;; == Scatter Store
  ;; =========================================================================
  
! (define_expand "mask_len_scatter_store<mode><vindex>"
    [(match_operand 0 "pmode_reg_or_0_operand")
!    (match_operand:<VINDEX> 1 "register_operand")
     (match_operand 2 "const_1_operand")
     (match_operand 3 "const_1_operand")
!    (match_operand:VINDEXED 4 "register_operand")
!    (match_operand:<VM> 5 "vector_mask_operand")
     (match_operand 6 "autovec_length_operand")
     (match_operand 7 "const_0_operand")]
!   "TARGET_VECTOR"
  {
    riscv_vector::expand_gather_scatter (operands, false);
    DONE;
  })
  
! (define_expand "mask_len_scatter_store<mode><vindex_double_trunc>"
    [(match_operand 0 "pmode_reg_or_0_operand")
!    (match_operand:<VINDEX_DOUBLE_TRUNC> 1 "register_operand")
     (match_operand 2 "const_1_operand")
     (match_operand 3 "const_1_operand")
!    (match_operand:VEEWEXT2 4 "register_operand")
!    (match_operand:<VM> 5 "vector_mask_operand")
     (match_operand 6 "autovec_length_operand")
     (match_operand 7 "const_0_operand")]
!   "TARGET_VECTOR"
  {
    riscv_vector::expand_gather_scatter (operands, false);
    DONE;
  })
  
! (define_expand "mask_len_scatter_store<mode><vindex_quad_trunc>"
    [(match_operand 0 "pmode_reg_or_0_operand")
!    (match_operand:<VINDEX_QUAD_TRUNC> 1 "register_operand")
     (match_operand 2 "const_1_operand")
     (match_operand 3 "const_1_operand")
!    (match_operand:VEEWEXT4 4 "register_operand")
!    (match_operand:<VM> 5 "vector_mask_operand")
     (match_operand 6 "autovec_length_operand")
     (match_operand 7 "const_0_operand")]
!   "TARGET_VECTOR"
  {
    riscv_vector::expand_gather_scatter (operands, false);
    DONE;
  })
  
! (define_expand "mask_len_scatter_store<mode><vindex_oct_trunc>"
    [(match_operand 0 "pmode_reg_or_0_operand")
!    (match_operand:<VINDEX_OCT_TRUNC> 1 "register_operand")
     (match_operand 2 "const_1_operand")
     (match_operand 3 "const_1_operand")
!    (match_operand:VEEWEXT8 4 "register_operand")
!    (match_operand:<VM> 5 "vector_mask_operand")
     (match_operand 6 "autovec_length_operand")
     (match_operand 7 "const_0_operand")]
!   "TARGET_VECTOR"
  {
    riscv_vector::expand_gather_scatter (operands, false);
    DONE;
  })
  
! (define_expand "mask_len_scatter_store<mode><vindex_double_ext>"
    [(match_operand 0 "pmode_reg_or_0_operand")
!    (match_operand:<VINDEX_DOUBLE_EXT> 1 "register_operand")
     (match_operand 2 "const_1_operand")
     (match_operand 3 "const_1_operand")
!    (match_operand:VEEWTRUNC2 4 "register_operand")
!    (match_operand:<VM> 5 "vector_mask_operand")
     (match_operand 6 "autovec_length_operand")
     (match_operand 7 "const_0_operand")]
!   "TARGET_VECTOR"
  {
    riscv_vector::expand_gather_scatter (operands, false);
    DONE;
  })
  
! (define_expand "mask_len_scatter_store<mode><vindex_quad_ext>"
    [(match_operand 0 "pmode_reg_or_0_operand")
!    (match_operand:<VINDEX_QUAD_EXT> 1 "register_operand")
     (match_operand 2 "const_1_operand")
     (match_operand 3 "const_1_operand")
!    (match_operand:VEEWTRUNC4 4 "register_operand")
!    (match_operand:<VM> 5 "vector_mask_operand")
     (match_operand 6 "autovec_length_operand")
     (match_operand 7 "const_0_operand")]
!   "TARGET_VECTOR"
  {
    riscv_vector::expand_gather_scatter (operands, false);
    DONE;
  })
  
! (define_expand "mask_len_scatter_store<mode><vindex_oct_ext>"
    [(match_operand 0 "pmode_reg_or_0_operand")
!    (match_operand:<VINDEX_OCT_EXT> 1 "register_operand")
     (match_operand 2 "const_1_operand")
     (match_operand 3 "const_1_operand")
!    (match_operand:VEEWTRUNC8 4 "register_operand")
     (match_operand:<VM> 5 "vector_mask_operand")
     (match_operand 6 "autovec_length_operand")
     (match_operand 7 "const_0_operand")]
***************
*** 441,448 ****
  
  ;; Slide an RVV vector left and insert a scalar into element 0.
  (define_expand "vec_shl_insert_<mode>"
!   [(match_operand:VI 0 "register_operand")
!    (match_operand:VI 1 "register_operand")
     (match_operand:<VEL> 2 "reg_or_0_operand")]
    "TARGET_VECTOR"
  {
--- 440,447 ----
  
  ;; Slide an RVV vector left and insert a scalar into element 0.
  (define_expand "vec_shl_insert_<mode>"
!   [(match_operand:V_VLSI 0 "register_operand")
!    (match_operand:V_VLSI 1 "register_operand")
     (match_operand:<VEL> 2 "reg_or_0_operand")]
    "TARGET_VECTOR"
  {
***************
*** 453,460 ****
  })
  
  (define_expand "vec_shl_insert_<mode>"
!   [(match_operand:VF 0 "register_operand")
!    (match_operand:VF 1 "register_operand")
     (match_operand:<VEL> 2 "register_operand")]
    "TARGET_VECTOR"
  {
--- 452,459 ----
  })
  
  (define_expand "vec_shl_insert_<mode>"
!   [(match_operand:V_VLSF 0 "register_operand")
!    (match_operand:V_VLSF 1 "register_operand")
     (match_operand:<VEL> 2 "register_operand")]
    "TARGET_VECTOR"
  {
***************
*** 623,632 ****
  )
  
  (define_expand "vcond_mask_len_<mode>"
!   [(match_operand:V 0 "register_operand")
      (match_operand:<VM> 1 "nonmemory_operand")
!     (match_operand:V 2 "nonmemory_operand")
!     (match_operand:V 3 "autovec_else_operand")
      (match_operand 4 "autovec_length_operand")
      (match_operand 5 "const_0_operand")]
    "TARGET_VECTOR"
--- 622,631 ----
  )
  
  (define_expand "vcond_mask_len_<mode>"
!   [(match_operand:V_VLS 0 "register_operand")
      (match_operand:<VM> 1 "nonmemory_operand")
!     (match_operand:V_VLS 2 "nonmemory_operand")
!     (match_operand:V_VLS 3 "autovec_else_operand")
      (match_operand 4 "autovec_length_operand")
      (match_operand 5 "const_0_operand")]
    "TARGET_VECTOR"
***************
*** 1731,1741 ****
  })
  
  (define_expand "cond_len_<optab><mode>"
!   [(match_operand:VI 0 "register_operand")
     (match_operand:<VM> 1 "vector_mask_operand")
!    (any_int_unop:VI
!      (match_operand:VI 2 "register_operand"))
!    (match_operand:VI 3 "autovec_else_operand")
     (match_operand 4 "autovec_length_operand")
     (match_operand 5 "const_0_operand")]
    "TARGET_VECTOR"
--- 1730,1740 ----
  })
  
  (define_expand "cond_len_<optab><mode>"
!   [(match_operand:V_VLSI 0 "register_operand")
     (match_operand:<VM> 1 "vector_mask_operand")
!    (any_int_unop:V_VLSI
!      (match_operand:V_VLSI 2 "register_operand"))
!    (match_operand:V_VLSI 3 "autovec_else_operand")
     (match_operand 4 "autovec_length_operand")
     (match_operand 5 "const_0_operand")]
    "TARGET_VECTOR"
***************
*** 1766,1776 ****
  })
  
  (define_expand "cond_len_<optab><mode>"
!   [(match_operand:VF 0 "register_operand")
     (match_operand:<VM> 1 "vector_mask_operand")
!    (any_float_unop_nofrm:VF
!      (match_operand:VF 2 "register_operand"))
!    (match_operand:VF 3 "autovec_else_operand")
     (match_operand 4 "autovec_length_operand")
     (match_operand 5 "const_0_operand")]
    "TARGET_VECTOR"
--- 1765,1775 ----
  })
  
  (define_expand "cond_len_<optab><mode>"
!   [(match_operand:V_VLSF 0 "register_operand")
     (match_operand:<VM> 1 "vector_mask_operand")
!    (any_float_unop_nofrm:V_VLSF
!      (match_operand:V_VLSF 2 "register_operand"))
!    (match_operand:V_VLSF 3 "autovec_else_operand")
     (match_operand 4 "autovec_length_operand")
     (match_operand 5 "const_0_operand")]
    "TARGET_VECTOR"
***************
*** 1802,1813 ****
  })
  
  (define_expand "cond_len_<optab><mode>"
!   [(match_operand:VI 0 "register_operand")
     (match_operand:<VM> 1 "vector_mask_operand")
!    (any_shift:VI
!      (match_operand:VI 2 "register_operand")
!      (match_operand:VI 3 "vector_shift_operand"))
!    (match_operand:VI 4 "autovec_else_operand")
     (match_operand 5 "autovec_length_operand")
     (match_operand 6 "const_0_operand")]
    "TARGET_VECTOR"
--- 1801,1812 ----
  })
  
  (define_expand "cond_len_<optab><mode>"
!   [(match_operand:V_VLSI 0 "register_operand")
     (match_operand:<VM> 1 "vector_mask_operand")
!    (any_shift:V_VLSI
!      (match_operand:V_VLSI 2 "register_operand")
!      (match_operand:V_VLSI 3 "vector_shift_operand"))
!    (match_operand:V_VLSI 4 "autovec_else_operand")
     (match_operand 5 "autovec_length_operand")
     (match_operand 6 "const_0_operand")]
    "TARGET_VECTOR"
***************
*** 1840,1851 ****
  })
  
  (define_expand "cond_len_<optab><mode>"
!   [(match_operand:VI 0 "register_operand")
     (match_operand:<VM> 1 "vector_mask_operand")
!    (any_int_binop_no_shift:VI
!      (match_operand:VI 2 "<binop_rhs1_predicate>")
!      (match_operand:VI 3 "<binop_rhs2_predicate>"))
!    (match_operand:VI 4 "autovec_else_operand")
     (match_operand 5 "autovec_length_operand")
     (match_operand 6 "const_0_operand")]
    "TARGET_VECTOR"
--- 1839,1850 ----
  })
  
  (define_expand "cond_len_<optab><mode>"
!   [(match_operand:V_VLSI 0 "register_operand")
     (match_operand:<VM> 1 "vector_mask_operand")
!    (any_int_binop_no_shift:V_VLSI
!      (match_operand:V_VLSI 2 "<binop_rhs1_predicate>")
!      (match_operand:V_VLSI 3 "<binop_rhs2_predicate>"))
!    (match_operand:V_VLSI 4 "autovec_else_operand")
     (match_operand 5 "autovec_length_operand")
     (match_operand 6 "const_0_operand")]
    "TARGET_VECTOR"
***************
*** 1878,1889 ****
  })
  
  (define_expand "cond_len_<optab><mode>"
!   [(match_operand:VF 0 "register_operand")
     (match_operand:<VM> 1 "vector_mask_operand")
!    (any_float_binop:VF
!      (match_operand:VF 2 "register_operand")
!      (match_operand:VF 3 "register_operand"))
!    (match_operand:VF 4 "autovec_else_operand")
     (match_operand 5 "autovec_length_operand")
     (match_operand 6 "const_0_operand")]
    "TARGET_VECTOR"
--- 1877,1888 ----
  })
  
  (define_expand "cond_len_<optab><mode>"
!   [(match_operand:V_VLSF 0 "register_operand")
     (match_operand:<VM> 1 "vector_mask_operand")
!    (any_float_binop:V_VLSF
!      (match_operand:V_VLSF 2 "register_operand")
!      (match_operand:V_VLSF 3 "register_operand"))
!    (match_operand:V_VLSF 4 "autovec_else_operand")
     (match_operand 5 "autovec_length_operand")
     (match_operand 6 "const_0_operand")]
    "TARGET_VECTOR"
***************
*** 1914,1925 ****
  })
  
  (define_expand "cond_len_<optab><mode>"
!   [(match_operand:VF 0 "register_operand")
     (match_operand:<VM> 1 "vector_mask_operand")
!    (any_float_binop_nofrm:VF
!      (match_operand:VF 2 "register_operand")
!      (match_operand:VF 3 "register_operand"))
!    (match_operand:VF 4 "autovec_else_operand")
     (match_operand 5 "autovec_length_operand")
     (match_operand 6 "const_0_operand")]
    "TARGET_VECTOR"
--- 1913,1924 ----
  })
  
  (define_expand "cond_len_<optab><mode>"
!   [(match_operand:V_VLSF 0 "register_operand")
     (match_operand:<VM> 1 "vector_mask_operand")
!    (any_float_binop_nofrm:V_VLSF
!      (match_operand:V_VLSF 2 "register_operand")
!      (match_operand:V_VLSF 3 "register_operand"))
!    (match_operand:V_VLSF 4 "autovec_else_operand")
     (match_operand 5 "autovec_length_operand")
     (match_operand 6 "const_0_operand")]
    "TARGET_VECTOR"
***************
*** 1944,1955 ****
  })
  
  (define_expand "cond_len_<ieee_fmaxmin_op><mode>"
!   [(match_operand:VF 0 "register_operand")
     (match_operand:<VM> 1 "vector_mask_operand")
!    (unspec:VF
!      [(match_operand:VF 2 "register_operand")
!       (match_operand:VF 3 "register_operand")] UNSPEC_VFMAXMIN)
!    (match_operand:VF 4 "autovec_else_operand")
     (match_operand 5 "autovec_length_operand")
     (match_operand 6 "const_0_operand")]
    "TARGET_VECTOR && !HONOR_SNANS (<MODE>mode)"
--- 1943,1954 ----
  })
  
  (define_expand "cond_len_<ieee_fmaxmin_op><mode>"
!   [(match_operand:V_VLSF 0 "register_operand")
     (match_operand:<VM> 1 "vector_mask_operand")
!    (unspec:V_VLSF
!      [(match_operand:V_VLSF 2 "register_operand")
!       (match_operand:V_VLSF 3 "register_operand")] UNSPEC_VFMAXMIN)
!    (match_operand:V_VLSF 4 "autovec_else_operand")
     (match_operand 5 "autovec_length_operand")
     (match_operand 6 "const_0_operand")]
    "TARGET_VECTOR && !HONOR_SNANS (<MODE>mode)"
***************
*** 2003,2014 ****
  })
  
  (define_expand "cond_len_fma<mode>"
!   [(match_operand:VI 0 "register_operand")
     (match_operand:<VM> 1 "vector_mask_operand")
!    (match_operand:VI 2 "register_operand")
!    (match_operand:VI 3 "register_operand")
!    (match_operand:VI 4 "register_operand")
!    (match_operand:VI 5 "autovec_else_operand")
     (match_operand 6 "autovec_length_operand")
     (match_operand 7 "const_0_operand")]
    "TARGET_VECTOR"
--- 2002,2013 ----
  })
  
  (define_expand "cond_len_fma<mode>"
!   [(match_operand:V_VLSI 0 "register_operand")
     (match_operand:<VM> 1 "vector_mask_operand")
!    (match_operand:V_VLSI 2 "register_operand")
!    (match_operand:V_VLSI 3 "register_operand")
!    (match_operand:V_VLSI 4 "register_operand")
!    (match_operand:V_VLSI 5 "autovec_else_operand")
     (match_operand 6 "autovec_length_operand")
     (match_operand 7 "const_0_operand")]
    "TARGET_VECTOR"
***************
*** 2033,2044 ****
  })
  
  (define_expand "cond_len_fnma<mode>"
!   [(match_operand:VI 0 "register_operand")
     (match_operand:<VM> 1 "vector_mask_operand")
!    (match_operand:VI 2 "register_operand")
!    (match_operand:VI 3 "register_operand")
!    (match_operand:VI 4 "register_operand")
!    (match_operand:VI 5 "autovec_else_operand")
     (match_operand 6 "autovec_length_operand")
     (match_operand 7 "const_0_operand")]
    "TARGET_VECTOR"
--- 2032,2043 ----
  })
  
  (define_expand "cond_len_fnma<mode>"
!   [(match_operand:V_VLSI 0 "register_operand")
     (match_operand:<VM> 1 "vector_mask_operand")
!    (match_operand:V_VLSI 2 "register_operand")
!    (match_operand:V_VLSI 3 "register_operand")
!    (match_operand:V_VLSI 4 "register_operand")
!    (match_operand:V_VLSI 5 "autovec_else_operand")
     (match_operand 6 "autovec_length_operand")
     (match_operand 7 "const_0_operand")]
    "TARGET_VECTOR"
***************
*** 2070,2081 ****
  })
  
  (define_expand "cond_len_fma<mode>"
!   [(match_operand:VF 0 "register_operand")
     (match_operand:<VM> 1 "vector_mask_operand")
!    (match_operand:VF 2 "register_operand")
!    (match_operand:VF 3 "register_operand")
!    (match_operand:VF 4 "register_operand")
!    (match_operand:VF 5 "autovec_else_operand")
     (match_operand 6 "autovec_length_operand")
     (match_operand 7 "const_0_operand")]
    "TARGET_VECTOR"
--- 2069,2080 ----
  })
  
  (define_expand "cond_len_fma<mode>"
!   [(match_operand:V_VLSF 0 "register_operand")
     (match_operand:<VM> 1 "vector_mask_operand")
!    (match_operand:V_VLSF 2 "register_operand")
!    (match_operand:V_VLSF 3 "register_operand")
!    (match_operand:V_VLSF 4 "register_operand")
!    (match_operand:V_VLSF 5 "autovec_else_operand")
     (match_operand 6 "autovec_length_operand")
     (match_operand 7 "const_0_operand")]
    "TARGET_VECTOR"
***************
*** 2100,2111 ****
  })
  
  (define_expand "cond_len_fnma<mode>"
!   [(match_operand:VF 0 "register_operand")
     (match_operand:<VM> 1 "vector_mask_operand")
!    (match_operand:VF 2 "register_operand")
!    (match_operand:VF 3 "register_operand")
!    (match_operand:VF 4 "register_operand")
!    (match_operand:VF 5 "autovec_else_operand")
     (match_operand 6 "autovec_length_operand")
     (match_operand 7 "const_0_operand")]
    "TARGET_VECTOR"
--- 2099,2110 ----
  })
  
  (define_expand "cond_len_fnma<mode>"
!   [(match_operand:V_VLSF 0 "register_operand")
     (match_operand:<VM> 1 "vector_mask_operand")
!    (match_operand:V_VLSF 2 "register_operand")
!    (match_operand:V_VLSF 3 "register_operand")
!    (match_operand:V_VLSF 4 "register_operand")
!    (match_operand:V_VLSF 5 "autovec_else_operand")
     (match_operand 6 "autovec_length_operand")
     (match_operand 7 "const_0_operand")]
    "TARGET_VECTOR"
***************
*** 2130,2141 ****
  })
  
  (define_expand "cond_len_fms<mode>"
!   [(match_operand:VF 0 "register_operand")
     (match_operand:<VM> 1 "vector_mask_operand")
!    (match_operand:VF 2 "register_operand")
!    (match_operand:VF 3 "register_operand")
!    (match_operand:VF 4 "register_operand")
!    (match_operand:VF 5 "autovec_else_operand")
     (match_operand 6 "autovec_length_operand")
     (match_operand 7 "const_0_operand")]
    "TARGET_VECTOR"
--- 2129,2140 ----
  })
  
  (define_expand "cond_len_fms<mode>"
!   [(match_operand:V_VLSF 0 "register_operand")
     (match_operand:<VM> 1 "vector_mask_operand")
!    (match_operand:V_VLSF 2 "register_operand")
!    (match_operand:V_VLSF 3 "register_operand")
!    (match_operand:V_VLSF 4 "register_operand")
!    (match_operand:V_VLSF 5 "autovec_else_operand")
     (match_operand 6 "autovec_length_operand")
     (match_operand 7 "const_0_operand")]
    "TARGET_VECTOR"
***************
*** 2160,2171 ****
  })
  
  (define_expand "cond_len_fnms<mode>"
!   [(match_operand:VF 0 "register_operand")
     (match_operand:<VM> 1 "vector_mask_operand")
!    (match_operand:VF 2 "register_operand")
!    (match_operand:VF 3 "register_operand")
!    (match_operand:VF 4 "register_operand")
!    (match_operand:VF 5 "autovec_else_operand")
     (match_operand 6 "autovec_length_operand")
     (match_operand 7 "const_0_operand")]
    "TARGET_VECTOR"
--- 2159,2170 ----
  })
  
  (define_expand "cond_len_fnms<mode>"
!   [(match_operand:V_VLSF 0 "register_operand")
     (match_operand:<VM> 1 "vector_mask_operand")
!    (match_operand:V_VLSF 2 "register_operand")
!    (match_operand:V_VLSF 3 "register_operand")
!    (match_operand:V_VLSF 4 "register_operand")
!    (match_operand:V_VLSF 5 "autovec_else_operand")
     (match_operand 6 "autovec_length_operand")
     (match_operand 7 "const_0_operand")]
    "TARGET_VECTOR"
***************
*** 2451,2457 ****
  (define_insn_and_split "mask_len_fold_left_plus_<mode>"
    [(set (match_operand:<VEL> 0 "register_operand")
          (unspec:<VEL> [
!           (match_operand:VF 2 "register_operand")
            (match_operand:<VEL> 1 "register_operand")
            (match_operand:<VM> 3 "vector_mask_operand")
            (match_operand 4 "autovec_length_operand")
--- 2450,2456 ----
  (define_insn_and_split "mask_len_fold_left_plus_<mode>"
    [(set (match_operand:<VEL> 0 "register_operand")
          (unspec:<VEL> [
!           (match_operand:V_VLSF 2 "register_operand")
            (match_operand:<VEL> 1 "register_operand")
            (match_operand:<VM> 3 "vector_mask_operand")
            (match_operand 4 "autovec_length_operand")
***************
*** 2487,2492 ****
--- 2486,2494 ----
  ;; - vfmv.f.s
  ;; -------------------------------------------------------------------------
  
+ ;; If this is available for VLS modes we sometimes don't fall back to
+ ;; non-partial accesses, thus missing a vectorization opportunity.
+ ;; See PR122938.
  (define_expand "len_fold_extract_last_<mode>"
    [(match_operand:<VEL> 0 "register_operand")
     (match_operand:<VEL> 1 "register_operand")
***************
*** 2986,2999 ****
    }
  )
  
  ;; -------------------------------------------------------------------------
  ;; - vrol.vv vror.vv
  ;; -------------------------------------------------------------------------
  (define_expand "v<bitmanip_optab><mode>3"
!   [(set (match_operand:VI 0 "register_operand")
! 	(bitmanip_rotate:VI
! 	  (match_operand:VI 1 "register_operand")
! 	  (match_operand:VI 2 "register_operand")))]
    "TARGET_ZVBB || TARGET_ZVKB"
    {
      riscv_vector::emit_vlmax_insn (code_for_pred_v (<CODE>, <MODE>mode),
--- 2988,3078 ----
    }
  )
  
+ ;; Implement cond_len_vec_cbranch_any and cond_len_vec_cbranch_all
+ ;; Vector comparison with length and mask, then branch for integer types.
+ (define_expand "<cbranch_optab><mode>"
+   [(set (pc)
+ 	(unspec:V_VLSI
+ 	  [(if_then_else
+ 	    (match_operator 0 "riscv_cbranch_comparison_operator"
+ 	      [(match_operand:<VM> 1 "register_operand")
+ 	       (match_operand:V_VLSI 2 "register_operand")
+ 	       (match_operand:V_VLSI 3 "nonmemory_operand")
+ 	       (match_operand 4 "autovec_length_operand")
+ 	       (match_operand 5 "const_0_operand")])
+ 	    (label_ref (match_operand 6 ""))
+ 	    (pc))]
+ 	 COND_LEN_CBRANCH_CMP))]
+   "TARGET_VECTOR"
+ {
+   rtx_code code = GET_CODE (operands[0]);
+   rtx mask = gen_reg_rtx (<VM>mode);
+ 
+   /* Generate the masked comparison.  */
+   rtx maskoff = CONST0_RTX (<VM>mode);
+   riscv_vector::expand_vec_cmp (mask, code, operands[2], operands[3],
+ 				operands[1], maskoff);
+ 
+   /* Use vcpop to count the number of active elements.  */
+   rtx count = gen_reg_rtx (Pmode);
+   rtx cpop_ops[] = {count, mask};
+   riscv_vector::emit_vlmax_insn (code_for_pred_popcount (<VM>mode, Pmode),
+ 				 riscv_vector::CPOP_OP, cpop_ops);
+ 
+   /* Branch based on whether count is zero or non-zero.  */
+   riscv_expand_conditional_branch (operands[6], <cbranch_op>, count,
+ 				   const0_rtx);
+   DONE;
+ })
+ 
+ ;; Floating-point version with length and mask
+ (define_expand "<cbranch_optab><mode>"
+   [(set (pc)
+ 	(unspec:V_VLSF
+ 	  [(if_then_else
+ 	    (match_operator 0 "riscv_cbranch_comparison_operator"
+ 	      [(match_operand:<VM> 1 "register_operand")
+ 	       (match_operand:V_VLSF 2 "register_operand")
+ 	       (match_operand:V_VLSF 3 "register_operand")
+ 	       (match_operand 4 "autovec_length_operand")
+ 	       (match_operand 5 "const_0_operand")])
+ 	    (label_ref (match_operand 6 ""))
+ 	    (pc))]
+ 	 COND_LEN_CBRANCH_CMP))]
+   "TARGET_VECTOR"
+ {
+   rtx_code code = GET_CODE (operands[0]);
+   rtx mask = gen_reg_rtx (<VM>mode);
+ 
+   rtx tmp = gen_reg_rtx (<VM>mode);
+   riscv_vector::expand_vec_cmp_float (tmp, code, operands[2], operands[3],
+ 				      false);
+ 
+   /* Combine with the incoming mask using AND.  */
+   rtx ops[] = {mask, operands[1], tmp};
+   riscv_vector::emit_vlmax_insn (code_for_pred (AND, <VM>mode),
+ 				 riscv_vector::BINARY_MASK_OP, ops);
+ 
+   /* Use vcpop to count the number of active elements.  */
+   rtx count = gen_reg_rtx (Pmode);
+   rtx cpop_ops[] = {count, mask};
+   riscv_vector::emit_vlmax_insn (code_for_pred_popcount (<VM>mode, Pmode),
+ 				 riscv_vector::CPOP_OP, cpop_ops);
+ 
+   /* Branch based on whether count is zero or non-zero.  */
+   riscv_expand_conditional_branch (operands[6], <cbranch_op>, count,
+ 				   const0_rtx);
+   DONE;
+ })
+ 
  ;; -------------------------------------------------------------------------
  ;; - vrol.vv vror.vv
  ;; -------------------------------------------------------------------------
  (define_expand "v<bitmanip_optab><mode>3"
!   [(set (match_operand:V_VLSI 0 "register_operand")
! 	(bitmanip_rotate:V_VLSI
! 	  (match_operand:V_VLSI 1 "register_operand")
! 	  (match_operand:V_VLSI 2 "register_operand")))]
    "TARGET_ZVBB || TARGET_ZVKB"
    {
      riscv_vector::emit_vlmax_insn (code_for_pred_v (<CODE>, <MODE>mode),
diff -Nrcpad gcc-16-20251214/gcc/config/riscv/gen-riscv-ext-opt.cc gcc-16-20251221/gcc/config/riscv/gen-riscv-ext-opt.cc
*** gcc-16-20251214/gcc/config/riscv/gen-riscv-ext-opt.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/riscv/gen-riscv-ext-opt.cc	Sun Dec 21 22:32:06 2025
*************** main ()
*** 37,43 ****
    puts ("; Please *DO NOT* edit manually.");
  
    std::set<std::string> all_vars;
! #define DEFINE_RISCV_EXT(NAME, UPPERCAE_NAME, FULL_NAME, DESC, URL, DEP_EXTS,  \
  			 SUPPORTED_VERSIONS, FLAG_GROUP, BITMASK_GROUP_ID,     \
  			 BITMASK_BIT_POSITION, EXTRA_EXTENSION_FLAGS)          \
    all_vars.insert ("riscv_" #FLAG_GROUP "_subext");
--- 37,43 ----
    puts ("; Please *DO NOT* edit manually.");
  
    std::set<std::string> all_vars;
! #define DEFINE_RISCV_EXT(NAME, UPPERCASE_NAME, FULL_NAME, DESC, URL, DEP_EXTS,  \
  			 SUPPORTED_VERSIONS, FLAG_GROUP, BITMASK_GROUP_ID,     \
  			 BITMASK_BIT_POSITION, EXTRA_EXTENSION_FLAGS)          \
    all_vars.insert ("riscv_" #FLAG_GROUP "_subext");
*************** main ()
*** 50,59 ****
        printf ("int %s\n\n", var.c_str ());
      }
  
! #define DEFINE_RISCV_EXT(NAME, UPPERCAE_NAME, FULL_NAME, DESC, URL, DEP_EXTS,  \
  			 SUPPORTED_VERSIONS, FLAG_GROUP, BITMASK_GROUP_ID,     \
  			 BITMASK_BIT_POSITION, EXTRA_EXTENSION_FLAGS)          \
!   puts ("Mask(" #UPPERCAE_NAME ") Var(riscv_" #FLAG_GROUP "_subext)\n");
  #include "riscv-ext.def"
  #undef DEFINE_RISCV_EXT
  
--- 50,59 ----
        printf ("int %s\n\n", var.c_str ());
      }
  
! #define DEFINE_RISCV_EXT(NAME, UPPERCASE_NAME, FULL_NAME, DESC, URL, DEP_EXTS,  \
  			 SUPPORTED_VERSIONS, FLAG_GROUP, BITMASK_GROUP_ID,     \
  			 BITMASK_BIT_POSITION, EXTRA_EXTENSION_FLAGS)          \
!   puts ("Mask(" #UPPERCASE_NAME ") Var(riscv_" #FLAG_GROUP "_subext)\n");
  #include "riscv-ext.def"
  #undef DEFINE_RISCV_EXT
  
diff -Nrcpad gcc-16-20251214/gcc/config/riscv/gen-riscv-ext-texi.cc gcc-16-20251221/gcc/config/riscv/gen-riscv-ext-texi.cc
*** gcc-16-20251214/gcc/config/riscv/gen-riscv-ext-texi.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/riscv/gen-riscv-ext-texi.cc	Sun Dec 21 22:32:06 2025
*************** main ()
*** 75,81 ****
    puts ("@samp{zifencei}.");
    puts ("");
  
! #define DEFINE_RISCV_EXT(NAME, UPPERCAE_NAME, FULL_NAME, DESC, URL, DEP_EXTS,  \
  			 SUPPORTED_VERSIONS, FLAG_GROUP, BITMASK_GROUP_ID,     \
  			 BITMASK_BIT_POSITION, EXTRA_EXTENSION_FLAGS)          \
    print_ext_doc_entry (#NAME, FULL_NAME, DESC,                                 \
--- 75,81 ----
    puts ("@samp{zifencei}.");
    puts ("");
  
! #define DEFINE_RISCV_EXT(NAME, UPPERCASE_NAME, FULL_NAME, DESC, URL, DEP_EXTS,  \
  			 SUPPORTED_VERSIONS, FLAG_GROUP, BITMASK_GROUP_ID,     \
  			 BITMASK_BIT_POSITION, EXTRA_EXTENSION_FLAGS)          \
    print_ext_doc_entry (#NAME, FULL_NAME, DESC,                                 \
diff -Nrcpad gcc-16-20251214/gcc/config/riscv/predicates.md gcc-16-20251221/gcc/config/riscv/predicates.md
*** gcc-16-20251214/gcc/config/riscv/predicates.md	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/riscv/predicates.md	Sun Dec 21 22:32:06 2025
***************
*** 617,622 ****
--- 617,629 ----
  (define_predicate "ge_operator"
    (match_code "ge,geu"))
  
+ (define_special_predicate "riscv_cbranch_comparison_operator"
+   (match_code "eq,ne,le,lt,ge,gt,geu,gtu,leu,ltu,unordered,
+ 	       ordered,unlt,unle,unge,ungt")
+ {
+   return TARGET_VECTOR;
+ })
+ 
  ;; pmode_reg_or_uimm5_operand can be used by vsll.vx/vsrl.vx/vsra.vx instructions
  ;; It is *not* equivalent to vector_length_operand due to the vector_length_operand
  ;; needing to conditionalize some behavior on XTHEADVECTOR.
diff -Nrcpad gcc-16-20251214/gcc/config/riscv/riscv-avlprop.cc gcc-16-20251221/gcc/config/riscv/riscv-avlprop.cc
*** gcc-16-20251214/gcc/config/riscv/riscv-avlprop.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/riscv/riscv-avlprop.cc	Sun Dec 21 22:32:06 2025
*************** pass_avlprop::execute (function *fn)
*** 580,586 ****
  		 not all NF registers.  Therefore divide the mode size by NF
  		 to obtain the proper AVL.  */
  	      int nf = 1;
! 	      if (riscv_v_ext_tuple_mode_p (vtype_mode))
  		nf = get_nf (vtype_mode);
  	      rtx new_avl = gen_int_mode
  	      (GET_MODE_NUNITS (vtype_mode).to_constant () / nf, Pmode);
--- 580,586 ----
  		 not all NF registers.  Therefore divide the mode size by NF
  		 to obtain the proper AVL.  */
  	      int nf = 1;
! 	      if (riscv_tuple_mode_p (vtype_mode))
  		nf = get_nf (vtype_mode);
  	      rtx new_avl = gen_int_mode
  	      (GET_MODE_NUNITS (vtype_mode).to_constant () / nf, Pmode);
diff -Nrcpad gcc-16-20251214/gcc/config/riscv/riscv-ext-corev.def gcc-16-20251221/gcc/config/riscv/riscv-ext-corev.def
*** gcc-16-20251214/gcc/config/riscv/riscv-ext-corev.def	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/riscv/riscv-ext-corev.def	Sun Dec 21 22:32:06 2025
*************** Format of DEFINE_RISCV_EXT, please refer
*** 23,29 ****
  
  DEFINE_RISCV_EXT(
    /* NAME */ xcvalu,
!   /* UPPERCAE_NAME */ XCVALU,
    /* FULL_NAME */ "Core-V miscellaneous ALU extension",
    /* DESC */ "",
    /* URL */ ,
--- 23,29 ----
  
  DEFINE_RISCV_EXT(
    /* NAME */ xcvalu,
!   /* UPPERCASE_NAME */ XCVALU,
    /* FULL_NAME */ "Core-V miscellaneous ALU extension",
    /* DESC */ "",
    /* URL */ ,
*************** DEFINE_RISCV_EXT(
*** 36,42 ****
  
  DEFINE_RISCV_EXT(
    /* NAME */ xcvbi,
!   /* UPPERCAE_NAME */ XCVBI,
    /* FULL_NAME */ "xcvbi extension",
    /* DESC */ "",
    /* URL */ ,
--- 36,42 ----
  
  DEFINE_RISCV_EXT(
    /* NAME */ xcvbi,
!   /* UPPERCASE_NAME */ XCVBI,
    /* FULL_NAME */ "xcvbi extension",
    /* DESC */ "",
    /* URL */ ,
*************** DEFINE_RISCV_EXT(
*** 49,55 ****
  
  DEFINE_RISCV_EXT(
    /* NAME */ xcvelw,
!   /* UPPERCAE_NAME */ XCVELW,
    /* FULL_NAME */ "Core-V event load word extension",
    /* DESC */ "",
    /* URL */ ,
--- 49,55 ----
  
  DEFINE_RISCV_EXT(
    /* NAME */ xcvelw,
!   /* UPPERCASE_NAME */ XCVELW,
    /* FULL_NAME */ "Core-V event load word extension",
    /* DESC */ "",
    /* URL */ ,
*************** DEFINE_RISCV_EXT(
*** 62,68 ****
  
  DEFINE_RISCV_EXT(
    /* NAME */ xcvmac,
!   /* UPPERCAE_NAME */ XCVMAC,
    /* FULL_NAME */ "Core-V multiply-accumulate extension",
    /* DESC */ "",
    /* URL */ ,
--- 62,68 ----
  
  DEFINE_RISCV_EXT(
    /* NAME */ xcvmac,
!   /* UPPERCASE_NAME */ XCVMAC,
    /* FULL_NAME */ "Core-V multiply-accumulate extension",
    /* DESC */ "",
    /* URL */ ,
*************** DEFINE_RISCV_EXT(
*** 75,81 ****
  
  DEFINE_RISCV_EXT(
    /* NAME */ xcvsimd,
!   /* UPPERCAE_NAME */ XCVSIMD,
    /* FULL_NAME */ "xcvsimd extension",
    /* DESC */ "",
    /* URL */ ,
--- 75,81 ----
  
  DEFINE_RISCV_EXT(
    /* NAME */ xcvsimd,
!   /* UPPERCASE_NAME */ XCVSIMD,
    /* FULL_NAME */ "xcvsimd extension",
    /* DESC */ "",
    /* URL */ ,
diff -Nrcpad gcc-16-20251214/gcc/config/riscv/riscv-ext-sifive.def gcc-16-20251221/gcc/config/riscv/riscv-ext-sifive.def
*** gcc-16-20251214/gcc/config/riscv/riscv-ext-sifive.def	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/riscv/riscv-ext-sifive.def	Sun Dec 21 22:32:06 2025
*************** Format of DEFINE_RISCV_EXT, please refer
*** 23,29 ****
  
  DEFINE_RISCV_EXT(
    /* NAME */ xsfcease,
!   /* UPPERCAE_NAME */ XSFCEASE,
    /* FULL_NAME */ "xsfcease extension",
    /* DESC */ "",
    /* URL */ ,
--- 23,29 ----
  
  DEFINE_RISCV_EXT(
    /* NAME */ xsfcease,
!   /* UPPERCASE_NAME */ XSFCEASE,
    /* FULL_NAME */ "xsfcease extension",
    /* DESC */ "",
    /* URL */ ,
*************** DEFINE_RISCV_EXT(
*** 36,42 ****
  
  DEFINE_RISCV_EXT(
    /* NAME */ xsfvcp,
!   /* UPPERCAE_NAME */ XSFVCP,
    /* FULL_NAME */ "xsfvcp extension",
    /* DESC */ "",
    /* URL */ ,
--- 36,42 ----
  
  DEFINE_RISCV_EXT(
    /* NAME */ xsfvcp,
!   /* UPPERCASE_NAME */ XSFVCP,
    /* FULL_NAME */ "xsfvcp extension",
    /* DESC */ "",
    /* URL */ ,
*************** DEFINE_RISCV_EXT(
*** 49,55 ****
  
  DEFINE_RISCV_EXT(
    /* NAME */ xsfvfnrclipxfqf,
!   /* UPPERCAE_NAME */ XSFVFNRCLIPXFQF,
    /* FULL_NAME */ "xsfvfnrclipxfqf extension",
    /* DESC */ "",
    /* URL */ ,
--- 49,55 ----
  
  DEFINE_RISCV_EXT(
    /* NAME */ xsfvfnrclipxfqf,
!   /* UPPERCASE_NAME */ XSFVFNRCLIPXFQF,
    /* FULL_NAME */ "xsfvfnrclipxfqf extension",
    /* DESC */ "",
    /* URL */ ,
*************** DEFINE_RISCV_EXT(
*** 62,68 ****
  
  DEFINE_RISCV_EXT(
    /* NAME */ xsfvqmaccdod,
!   /* UPPERCAE_NAME */ XSFVQMACCDOD,
    /* FULL_NAME */ "xsfvqmaccdod extension",
    /* DESC */ "",
    /* URL */ ,
--- 62,68 ----
  
  DEFINE_RISCV_EXT(
    /* NAME */ xsfvqmaccdod,
!   /* UPPERCASE_NAME */ XSFVQMACCDOD,
    /* FULL_NAME */ "xsfvqmaccdod extension",
    /* DESC */ "",
    /* URL */ ,
*************** DEFINE_RISCV_EXT(
*** 75,81 ****
  
  DEFINE_RISCV_EXT(
    /* NAME */ xsfvqmaccqoq,
!   /* UPPERCAE_NAME */ XSFVQMACCQOQ,
    /* FULL_NAME */ "xsfvqmaccqoq extension",
    /* DESC */ "",
    /* URL */ ,
--- 75,81 ----
  
  DEFINE_RISCV_EXT(
    /* NAME */ xsfvqmaccqoq,
!   /* UPPERCASE_NAME */ XSFVQMACCQOQ,
    /* FULL_NAME */ "xsfvqmaccqoq extension",
    /* DESC */ "",
    /* URL */ ,
diff -Nrcpad gcc-16-20251214/gcc/config/riscv/riscv-ext-thead.def gcc-16-20251221/gcc/config/riscv/riscv-ext-thead.def
*** gcc-16-20251214/gcc/config/riscv/riscv-ext-thead.def	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/riscv/riscv-ext-thead.def	Sun Dec 21 22:32:06 2025
*************** Format of DEFINE_RISCV_EXT, please refer
*** 23,29 ****
  
  DEFINE_RISCV_EXT(
    /* NAME */ xtheadba,
!   /* UPPERCAE_NAME */ XTHEADBA,
    /* FULL_NAME */ "T-head address calculation extension",
    /* DESC */ "",
    /* URL */ ,
--- 23,29 ----
  
  DEFINE_RISCV_EXT(
    /* NAME */ xtheadba,
!   /* UPPERCASE_NAME */ XTHEADBA,
    /* FULL_NAME */ "T-head address calculation extension",
    /* DESC */ "",
    /* URL */ ,
*************** DEFINE_RISCV_EXT(
*** 36,42 ****
  
  DEFINE_RISCV_EXT(
    /* NAME */ xtheadbb,
!   /* UPPERCAE_NAME */ XTHEADBB,
    /* FULL_NAME */ "T-head basic bit-manipulation extension",
    /* DESC */ "",
    /* URL */ ,
--- 36,42 ----
  
  DEFINE_RISCV_EXT(
    /* NAME */ xtheadbb,
!   /* UPPERCASE_NAME */ XTHEADBB,
    /* FULL_NAME */ "T-head basic bit-manipulation extension",
    /* DESC */ "",
    /* URL */ ,
*************** DEFINE_RISCV_EXT(
*** 49,55 ****
  
  DEFINE_RISCV_EXT(
    /* NAME */ xtheadbs,
!   /* UPPERCAE_NAME */ XTHEADBS,
    /* FULL_NAME */ "T-head single-bit instructions extension",
    /* DESC */ "",
    /* URL */ ,
--- 49,55 ----
  
  DEFINE_RISCV_EXT(
    /* NAME */ xtheadbs,
!   /* UPPERCASE_NAME */ XTHEADBS,
    /* FULL_NAME */ "T-head single-bit instructions extension",
    /* DESC */ "",
    /* URL */ ,
*************** DEFINE_RISCV_EXT(
*** 62,68 ****
  
  DEFINE_RISCV_EXT(
    /* NAME */ xtheadcmo,
!   /* UPPERCAE_NAME */ XTHEADCMO,
    /* FULL_NAME */ "T-head cache management operations extension",
    /* DESC */ "",
    /* URL */ ,
--- 62,68 ----
  
  DEFINE_RISCV_EXT(
    /* NAME */ xtheadcmo,
!   /* UPPERCASE_NAME */ XTHEADCMO,
    /* FULL_NAME */ "T-head cache management operations extension",
    /* DESC */ "",
    /* URL */ ,
*************** DEFINE_RISCV_EXT(
*** 75,81 ****
  
  DEFINE_RISCV_EXT(
    /* NAME */ xtheadcondmov,
!   /* UPPERCAE_NAME */ XTHEADCONDMOV,
    /* FULL_NAME */ "T-head conditional move extension",
    /* DESC */ "",
    /* URL */ ,
--- 75,81 ----
  
  DEFINE_RISCV_EXT(
    /* NAME */ xtheadcondmov,
!   /* UPPERCASE_NAME */ XTHEADCONDMOV,
    /* FULL_NAME */ "T-head conditional move extension",
    /* DESC */ "",
    /* URL */ ,
*************** DEFINE_RISCV_EXT(
*** 88,94 ****
  
  DEFINE_RISCV_EXT(
    /* NAME */ xtheadfmemidx,
!   /* UPPERCAE_NAME */ XTHEADFMEMIDX,
    /* FULL_NAME */ "T-head indexed memory operations for floating-point registers extension",
    /* DESC */ "",
    /* URL */ ,
--- 88,94 ----
  
  DEFINE_RISCV_EXT(
    /* NAME */ xtheadfmemidx,
!   /* UPPERCASE_NAME */ XTHEADFMEMIDX,
    /* FULL_NAME */ "T-head indexed memory operations for floating-point registers extension",
    /* DESC */ "",
    /* URL */ ,
*************** DEFINE_RISCV_EXT(
*** 101,107 ****
  
  DEFINE_RISCV_EXT(
    /* NAME */ xtheadfmv,
!   /* UPPERCAE_NAME */ XTHEADFMV,
    /* FULL_NAME */ "T-head double floating-point high-bit data transmission extension",
    /* DESC */ "",
    /* URL */ ,
--- 101,107 ----
  
  DEFINE_RISCV_EXT(
    /* NAME */ xtheadfmv,
!   /* UPPERCASE_NAME */ XTHEADFMV,
    /* FULL_NAME */ "T-head double floating-point high-bit data transmission extension",
    /* DESC */ "",
    /* URL */ ,
*************** DEFINE_RISCV_EXT(
*** 114,120 ****
  
  DEFINE_RISCV_EXT(
    /* NAME */ xtheadint,
!   /* UPPERCAE_NAME */ XTHEADINT,
    /* FULL_NAME */ "T-head acceleration interruption extension",
    /* DESC */ "",
    /* URL */ ,
--- 114,120 ----
  
  DEFINE_RISCV_EXT(
    /* NAME */ xtheadint,
!   /* UPPERCASE_NAME */ XTHEADINT,
    /* FULL_NAME */ "T-head acceleration interruption extension",
    /* DESC */ "",
    /* URL */ ,
*************** DEFINE_RISCV_EXT(
*** 127,133 ****
  
  DEFINE_RISCV_EXT(
    /* NAME */ xtheadmac,
!   /* UPPERCAE_NAME */ XTHEADMAC,
    /* FULL_NAME */ "T-head multiply-accumulate extension",
    /* DESC */ "",
    /* URL */ ,
--- 127,133 ----
  
  DEFINE_RISCV_EXT(
    /* NAME */ xtheadmac,
!   /* UPPERCASE_NAME */ XTHEADMAC,
    /* FULL_NAME */ "T-head multiply-accumulate extension",
    /* DESC */ "",
    /* URL */ ,
*************** DEFINE_RISCV_EXT(
*** 140,146 ****
  
  DEFINE_RISCV_EXT(
    /* NAME */ xtheadmemidx,
!   /* UPPERCAE_NAME */ XTHEADMEMIDX,
    /* FULL_NAME */ "T-head indexed memory operation extension",
    /* DESC */ "",
    /* URL */ ,
--- 140,146 ----
  
  DEFINE_RISCV_EXT(
    /* NAME */ xtheadmemidx,
!   /* UPPERCASE_NAME */ XTHEADMEMIDX,
    /* FULL_NAME */ "T-head indexed memory operation extension",
    /* DESC */ "",
    /* URL */ ,
*************** DEFINE_RISCV_EXT(
*** 153,159 ****
  
  DEFINE_RISCV_EXT(
    /* NAME */ xtheadmempair,
!   /* UPPERCAE_NAME */ XTHEADMEMPAIR,
    /* FULL_NAME */ "T-head two-GPR memory operation extension",
    /* DESC */ "",
    /* URL */ ,
--- 153,159 ----
  
  DEFINE_RISCV_EXT(
    /* NAME */ xtheadmempair,
!   /* UPPERCASE_NAME */ XTHEADMEMPAIR,
    /* FULL_NAME */ "T-head two-GPR memory operation extension",
    /* DESC */ "",
    /* URL */ ,
*************** DEFINE_RISCV_EXT(
*** 166,172 ****
  
  DEFINE_RISCV_EXT(
    /* NAME */ xtheadsync,
!   /* UPPERCAE_NAME */ XTHEADSYNC,
    /* FULL_NAME */ "T-head multi-core synchronization extension",
    /* DESC */ "",
    /* URL */ ,
--- 166,172 ----
  
  DEFINE_RISCV_EXT(
    /* NAME */ xtheadsync,
!   /* UPPERCASE_NAME */ XTHEADSYNC,
    /* FULL_NAME */ "T-head multi-core synchronization extension",
    /* DESC */ "",
    /* URL */ ,
*************** DEFINE_RISCV_EXT(
*** 179,185 ****
  
  DEFINE_RISCV_EXT(
    /* NAME */ xtheadvector,
!   /* UPPERCAE_NAME */ XTHEADVECTOR,
    /* FULL_NAME */ "xtheadvector extension",
    /* DESC */ "",
    /* URL */ ,
--- 179,185 ----
  
  DEFINE_RISCV_EXT(
    /* NAME */ xtheadvector,
!   /* UPPERCASE_NAME */ XTHEADVECTOR,
    /* FULL_NAME */ "xtheadvector extension",
    /* DESC */ "",
    /* URL */ ,
diff -Nrcpad gcc-16-20251214/gcc/config/riscv/riscv-ext-ventana.def gcc-16-20251221/gcc/config/riscv/riscv-ext-ventana.def
*** gcc-16-20251214/gcc/config/riscv/riscv-ext-ventana.def	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/riscv/riscv-ext-ventana.def	Sun Dec 21 22:32:06 2025
*************** Format of DEFINE_RISCV_EXT, please refer
*** 23,29 ****
  
  DEFINE_RISCV_EXT(
    /* NAME */ xventanacondops,
!   /* UPPERCAE_NAME */ XVENTANACONDOPS,
    /* FULL_NAME */ "Ventana integer conditional operations extension",
    /* DESC */ "",
    /* URL */ ,
--- 23,29 ----
  
  DEFINE_RISCV_EXT(
    /* NAME */ xventanacondops,
!   /* UPPERCASE_NAME */ XVENTANACONDOPS,
    /* FULL_NAME */ "Ventana integer conditional operations extension",
    /* DESC */ "",
    /* URL */ ,
diff -Nrcpad gcc-16-20251214/gcc/config/riscv/riscv-protos.h gcc-16-20251221/gcc/config/riscv/riscv-protos.h
*** gcc-16-20251214/gcc/config/riscv/riscv-protos.h	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/riscv/riscv-protos.h	Sun Dec 21 22:32:06 2025
*************** extern rtx riscv_gen_gpr_save_insn (stru
*** 169,177 ****
  extern bool riscv_gpr_save_operation_p (rtx);
  extern void riscv_reinit (void);
  extern poly_uint64 riscv_regmode_natural_size (machine_mode);
! extern bool riscv_v_ext_vector_mode_p (machine_mode);
! extern bool riscv_v_ext_tuple_mode_p (machine_mode);
! extern bool riscv_v_ext_vls_mode_p (machine_mode);
  extern int riscv_get_v_regno_alignment (machine_mode);
  extern bool riscv_shamt_matches_mask_p (int, HOST_WIDE_INT);
  extern void riscv_subword_address (rtx, rtx *, rtx *, rtx *, rtx *);
--- 169,177 ----
  extern bool riscv_gpr_save_operation_p (rtx);
  extern void riscv_reinit (void);
  extern poly_uint64 riscv_regmode_natural_size (machine_mode);
! extern bool riscv_vla_mode_p (machine_mode);
! extern bool riscv_tuple_mode_p (machine_mode);
! extern bool riscv_vls_mode_p (machine_mode);
  extern int riscv_get_v_regno_alignment (machine_mode);
  extern bool riscv_shamt_matches_mask_p (int, HOST_WIDE_INT);
  extern void riscv_subword_address (rtx, rtx *, rtx *, rtx *, rtx *);
diff -Nrcpad gcc-16-20251214/gcc/config/riscv/riscv-selftests.cc gcc-16-20251221/gcc/config/riscv/riscv-selftests.cc
*** gcc-16-20251214/gcc/config/riscv/riscv-selftests.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/riscv/riscv-selftests.cc	Sun Dec 21 22:32:06 2025
*************** run_const_vector_selftests (void)
*** 258,264 ****
  
    FOR_EACH_MODE_IN_CLASS (mode, MODE_VECTOR_INT)
      {
!       if (riscv_v_ext_vector_mode_p (mode))
  	{
  	  for (const HOST_WIDE_INT &val : worklist)
  	    {
--- 258,264 ----
  
    FOR_EACH_MODE_IN_CLASS (mode, MODE_VECTOR_INT)
      {
!       if (riscv_vla_mode_p (mode))
  	{
  	  for (const HOST_WIDE_INT &val : worklist)
  	    {
*************** run_const_vector_selftests (void)
*** 282,288 ****
  
    FOR_EACH_MODE_IN_CLASS (mode, MODE_VECTOR_FLOAT)
      {
!       if (riscv_v_ext_vector_mode_p (mode))
  	{
  	  scalar_mode inner_mode = GET_MODE_INNER (mode);
  	  REAL_VALUE_TYPE f = REAL_VALUE_ATOF ("0.2928932", inner_mode);
--- 282,288 ----
  
    FOR_EACH_MODE_IN_CLASS (mode, MODE_VECTOR_FLOAT)
      {
!       if (riscv_vla_mode_p (mode))
  	{
  	  scalar_mode inner_mode = GET_MODE_INNER (mode);
  	  REAL_VALUE_TYPE f = REAL_VALUE_ATOF ("0.2928932", inner_mode);
*************** run_const_vector_selftests (void)
*** 303,309 ****
    FOR_EACH_MODE_IN_CLASS (mode, MODE_VECTOR_BOOL)
      {
        /* Test vmset.m.  */
!       if (riscv_v_ext_vector_mode_p (mode))
  	{
  	  start_sequence ();
  	  rtx dest = gen_reg_rtx (mode);
--- 303,309 ----
    FOR_EACH_MODE_IN_CLASS (mode, MODE_VECTOR_BOOL)
      {
        /* Test vmset.m.  */
!       if (riscv_vla_mode_p (mode))
  	{
  	  start_sequence ();
  	  rtx dest = gen_reg_rtx (mode);
*************** run_broadcast_selftests (void)
*** 330,336 ****
  #define BROADCAST_TEST(MODE_CLASS)                                             \
    FOR_EACH_MODE_IN_CLASS (mode, MODE_VECTOR_INT)                               \
      {                                                                          \
!       if (riscv_v_ext_vector_mode_p (mode))                                    \
  	{                                                                      \
  	  rtx_insn *insn;                                                      \
  	  rtx src;                                                             \
--- 330,336 ----
  #define BROADCAST_TEST(MODE_CLASS)                                             \
    FOR_EACH_MODE_IN_CLASS (mode, MODE_VECTOR_INT)                               \
      {                                                                          \
!       if (riscv_vla_mode_p (mode))					       \
  	{                                                                      \
  	  rtx_insn *insn;                                                      \
  	  rtx src;                                                             \
diff -Nrcpad gcc-16-20251214/gcc/config/riscv/riscv-v.cc gcc-16-20251221/gcc/config/riscv/riscv-v.cc
*** gcc-16-20251214/gcc/config/riscv/riscv-v.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/riscv/riscv-v.cc	Sun Dec 21 22:32:06 2025
*************** imm_avl_p (machine_mode mode)
*** 67,73 ****
       registers.  Therefore divide the mode size by NF before checking if it is
       in range.  */
    int nf = 1;
!   if (riscv_v_ext_tuple_mode_p (mode))
      nf = get_nf (mode);
  
    return nunits.is_constant ()
--- 67,73 ----
       registers.  Therefore divide the mode size by NF before checking if it is
       in range.  */
    int nf = 1;
!   if (riscv_tuple_mode_p (mode))
      nf = get_nf (mode);
  
    return nunits.is_constant ()
*************** public:
*** 329,335 ****
      bool vls_p = false;
      if (m_vlmax_p)
        {
! 	if (riscv_v_ext_vls_mode_p (vtype_mode))
  	  {
  	    /* VLS modes always set VSETVL by
  	       "vsetvl zero, rs1/imm".  */
--- 329,335 ----
      bool vls_p = false;
      if (m_vlmax_p)
        {
! 	if (riscv_vls_mode_p (vtype_mode))
  	  {
  	    /* VLS modes always set VSETVL by
  	       "vsetvl zero, rs1/imm".  */
*************** expand_const_vector_interleaved_stepped_
*** 1632,1638 ****
      {
        int elem_count = XVECLEN (src, 0);
        uint64_t step1_val = step1.to_constant ();
!       uint64_t base1_val = base1_poly.to_constant ();
        uint64_t elem_val = base1_val + (elem_count - 1) * step1_val;
  
        if ((elem_val >> builder->inner_bits_size ()) != 0)
--- 1632,1642 ----
      {
        int elem_count = XVECLEN (src, 0);
        uint64_t step1_val = step1.to_constant ();
!       int64_t base1_signed = base1_poly.to_constant ();
!       /* Reinterpret as type of inner bits size so we can properly check
! 	 overflow.  */
!       uint64_t base1_val
! 	= base1_signed & ((1ULL << builder->inner_bits_size ()) - 1);
        uint64_t elem_val = base1_val + (elem_count - 1) * step1_val;
  
        if ((elem_val >> builder->inner_bits_size ()) != 0)
*************** get_frm_mode (rtx operand)
*** 1880,1885 ****
--- 1884,1959 ----
    gcc_unreachable ();
  }
  
+ /* Expand vector extraction from a SUBREG source using slidedown.
+    Handles patterns like (subreg:V4DI (reg:V8DI) 32) by emitting
+    a slidedown instruction when extracting non-low parts.
+    Return true if the move was handled and emitted.  */
+ static bool
+ expand_vector_subreg_extract (rtx dest, rtx src)
+ {
+   gcc_assert (SUBREG_P (src) && REG_P (SUBREG_REG (src)));
+ 
+   machine_mode mode = GET_MODE (dest);
+   machine_mode inner_mode = GET_MODE (SUBREG_REG (src));
+ 
+   gcc_assert (VECTOR_MODE_P (mode));
+   gcc_assert (VECTOR_MODE_P (inner_mode));
+ 
+   poly_uint16 outer_size = GET_MODE_BITSIZE (mode);
+   poly_uint16 inner_size = GET_MODE_BITSIZE (inner_mode);
+ 
+   poly_uint16 factor;
+   if (riscv_tuple_mode_p (inner_mode)
+       || !multiple_p (inner_size, outer_size, &factor)
+       || !factor.is_constant ()
+       || !pow2p_hwi (factor.to_constant ())
+       || factor.to_constant () <= 1)
+     return false;
+ 
+   enum vlmul_type lmul = get_vlmul (mode);
+   enum vlmul_type inner_lmul = get_vlmul (inner_mode);
+ 
+   /* These are just "renames".  */
+   if ((inner_lmul == LMUL_2 || inner_lmul == LMUL_4 || inner_lmul == LMUL_8)
+       && (lmul == LMUL_1 || lmul == LMUL_2 || lmul == LMUL_4))
+     return false;
+ 
+   poly_uint64 outer_nunits = GET_MODE_NUNITS (mode);
+   poly_uint64 subreg_byte = SUBREG_BYTE (src);
+ 
+   /* Calculate which part we're extracting (0 for low half, 1 for
+      higher half/quarter, etc.)  */
+   uint64_t part;
+   if (!exact_div (subreg_byte * BITS_PER_UNIT, outer_size).is_constant (&part))
+     return false;
+ 
+   rtx inner_reg = SUBREG_REG (src);
+   rtx tmp_out = gen_reg_rtx (mode);
+ 
+   if (part == 0)
+     {
+       /* Emit a direct reg-reg set here instead of emit_move_insn as that
+ 	 would trigger another legitimize_move.  */
+       emit_insn (gen_rtx_SET (tmp_out, gen_lowpart (mode, inner_reg)));
+     }
+   else
+     {
+       /* Extracting a non-zero part means we need to slide down.  */
+       poly_uint64 slide_count = part * outer_nunits;
+ 
+       rtx tmp = gen_reg_rtx (inner_mode);
+       rtx ops[] = {tmp, inner_reg, gen_int_mode (slide_count, Pmode)};
+       insn_code icode = code_for_pred_slide (UNSPEC_VSLIDEDOWN, inner_mode);
+       emit_vlmax_insn (icode, BINARY_OP, ops);
+ 
+       /* Extract the low part after sliding.  */
+       emit_insn (gen_rtx_SET (tmp_out, gen_lowpart (mode, tmp)));
+     }
+ 
+   emit_move_insn (dest, tmp_out);
+   return true;
+ }
+ 
  /* Expand a pre-RA RVV data move from SRC to DEST.
     It expands move for RVV fractional vector modes.
     Return true if the move as already been emitted.  */
*************** legitimize_move (rtx dest, rtx *srcp)
*** 1894,1900 ****
        return true;
      }
  
!   if (riscv_v_ext_vls_mode_p (mode))
      {
        if (GET_MODE_NUNITS (mode).to_constant () <= 31)
  	{
--- 1968,1992 ----
        return true;
      }
  
!   /* The canonical way of extracting vectors from vectors is the vec_extract
!      optab with appropriate source and dest modes.  This is rather a VLS style
!      approach, though as we would need to enumerate all dest modes that are
!      half, quarter, etc. the size of the source.  It becomes particularly
!      cumbersome if we have a mix of VLA and VLS, i.e. extracting a smaller
!      VLS vector from a "VLA" vector.  Therefore we recognize patterns like
!        (set reg:V4DI
! 	  (subreg:V4DI (reg:V8DI) offset))
!      and transform them into vector slidedowns.  */
!   if (SUBREG_P (src) && REG_P (SUBREG_REG (src))
!       && VECTOR_MODE_P (GET_MODE (SUBREG_REG (src)))
!       && VECTOR_MODE_P (mode)
!       && !lra_in_progress)
!     {
!       if (expand_vector_subreg_extract (dest, src))
! 	return true;
!     }
! 
!   if (riscv_vls_mode_p (mode))
      {
        if (GET_MODE_NUNITS (mode).to_constant () <= 31)
  	{
*************** get_vlmul (machine_mode mode)
*** 2002,2008 ****
    /* For VLS modes, the vlmul should be dynamically
       calculated since we need to adjust VLMUL according
       to TARGET_MIN_VLEN.  */
!   if (riscv_v_ext_vls_mode_p (mode))
      {
        int size = GET_MODE_BITSIZE (mode).to_constant ();
        int inner_size = GET_MODE_BITSIZE (GET_MODE_INNER (mode));
--- 2094,2100 ----
    /* For VLS modes, the vlmul should be dynamically
       calculated since we need to adjust VLMUL according
       to TARGET_MIN_VLEN.  */
!   if (riscv_vls_mode_p (mode))
      {
        int size = GET_MODE_BITSIZE (mode).to_constant ();
        int inner_size = GET_MODE_BITSIZE (GET_MODE_INNER (mode));
*************** get_vlmul (machine_mode mode)
*** 2063,2069 ****
  rtx
  get_vlmax_rtx (machine_mode mode)
  {
!   gcc_assert (riscv_v_ext_vector_mode_p (mode));
    return gen_int_mode (GET_MODE_NUNITS (mode), Pmode);
  }
  
--- 2155,2161 ----
  rtx
  get_vlmax_rtx (machine_mode mode)
  {
!   gcc_assert (riscv_vla_mode_p (mode));
    return gen_int_mode (GET_MODE_NUNITS (mode), Pmode);
  }
  
*************** unsigned int
*** 2072,2078 ****
  get_nf (machine_mode mode)
  {
    /* We don't allow non-tuple modes go through this function.  */
!   gcc_assert (riscv_v_ext_tuple_mode_p (mode));
    return mode_vtype_infos.nf[mode];
  }
  
--- 2164,2170 ----
  get_nf (machine_mode mode)
  {
    /* We don't allow non-tuple modes go through this function.  */
!   gcc_assert (riscv_tuple_mode_p (mode));
    return mode_vtype_infos.nf[mode];
  }
  
*************** machine_mode
*** 2083,2089 ****
  get_subpart_mode (machine_mode mode)
  {
    /* We don't allow non-tuple modes go through this function.  */
!   gcc_assert (riscv_v_ext_tuple_mode_p (mode));
    return mode_vtype_infos.subpart_mode[mode];
  }
  
--- 2175,2181 ----
  get_subpart_mode (machine_mode mode)
  {
    /* We don't allow non-tuple modes go through this function.  */
!   gcc_assert (riscv_tuple_mode_p (mode));
    return mode_vtype_infos.subpart_mode[mode];
  }
  
*************** get_subpart_mode (machine_mode mode)
*** 2091,2097 ****
  unsigned int
  get_ratio (machine_mode mode)
  {
!   if (riscv_v_ext_vls_mode_p (mode))
      {
        unsigned int sew = get_sew (mode);
        vlmul_type vlmul = get_vlmul (mode);
--- 2183,2189 ----
  unsigned int
  get_ratio (machine_mode mode)
  {
!   if (riscv_vls_mode_p (mode))
      {
        unsigned int sew = get_sew (mode);
        vlmul_type vlmul = get_vlmul (mode);
*************** machine_mode
*** 2168,2178 ****
  get_mask_mode (machine_mode mode)
  {
    poly_int64 nunits = GET_MODE_NUNITS (mode);
!   if (riscv_v_ext_tuple_mode_p (mode))
      {
        unsigned int nf = get_nf (mode);
        nunits = exact_div (nunits, nf);
      }
    return get_vector_mode (BImode, nunits).require ();
  }
  
--- 2260,2271 ----
  get_mask_mode (machine_mode mode)
  {
    poly_int64 nunits = GET_MODE_NUNITS (mode);
!   if (riscv_tuple_mode_p (mode))
      {
        unsigned int nf = get_nf (mode);
        nunits = exact_div (nunits, nf);
      }
+ 
    return get_vector_mode (BImode, nunits).require ();
  }
  
*************** get_vector_mode (scalar_mode inner_mode,
*** 2213,2223 ****
    else
      mclass = MODE_VECTOR_INT;
    machine_mode mode;
    FOR_EACH_MODE_IN_CLASS (mode, mclass)
      if (inner_mode == GET_MODE_INNER (mode)
  	&& known_eq (nunits, GET_MODE_NUNITS (mode))
! 	&& (riscv_v_ext_vector_mode_p (mode)
! 	    || riscv_v_ext_vls_mode_p (mode)))
        return mode;
    return opt_machine_mode ();
  }
--- 2306,2317 ----
    else
      mclass = MODE_VECTOR_INT;
    machine_mode mode;
+ 
    FOR_EACH_MODE_IN_CLASS (mode, mclass)
      if (inner_mode == GET_MODE_INNER (mode)
  	&& known_eq (nunits, GET_MODE_NUNITS (mode))
! 	&& (riscv_vla_mode_p (mode)
! 	    || riscv_vls_mode_p (mode)))
        return mode;
    return opt_machine_mode ();
  }
*************** get_tuple_mode (machine_mode subpart_mod
*** 2234,2240 ****
    FOR_EACH_MODE_IN_CLASS (mode, mclass)
      if (inner_mode == GET_MODE_INNER (mode)
  	&& known_eq (nunits, GET_MODE_NUNITS (mode))
! 	&& riscv_v_ext_tuple_mode_p (mode)
  	&& get_subpart_mode (mode) == subpart_mode)
        return mode;
    return opt_machine_mode ();
--- 2328,2334 ----
    FOR_EACH_MODE_IN_CLASS (mode, mclass)
      if (inner_mode == GET_MODE_INNER (mode)
  	&& known_eq (nunits, GET_MODE_NUNITS (mode))
! 	&& riscv_tuple_mode_p (mode)
  	&& get_subpart_mode (mode) == subpart_mode)
        return mode;
    return opt_machine_mode ();
*************** can_find_related_mode_p (machine_mode ve
*** 3056,3066 ****
  {
    if (!autovec_use_vlmax_p ())
      return false;
!   if (riscv_v_ext_vector_mode_p (vector_mode)
        && multiple_p (BYTES_PER_RISCV_VECTOR * TARGET_MAX_LMUL,
  		     GET_MODE_SIZE (element_mode), nunits))
      return true;
!   if (riscv_v_ext_vls_mode_p (vector_mode)
        && multiple_p ((TARGET_MIN_VLEN * TARGET_MAX_LMUL) / BITS_PER_UNIT,
  		     GET_MODE_SIZE (element_mode), nunits))
      return true;
--- 3150,3160 ----
  {
    if (!autovec_use_vlmax_p ())
      return false;
!   if (riscv_vla_mode_p (vector_mode)
        && multiple_p (BYTES_PER_RISCV_VECTOR * TARGET_MAX_LMUL,
  		     GET_MODE_SIZE (element_mode), nunits))
      return true;
!   if (riscv_vls_mode_p (vector_mode)
        && multiple_p ((TARGET_MIN_VLEN * TARGET_MAX_LMUL) / BITS_PER_UNIT,
  		     GET_MODE_SIZE (element_mode), nunits))
      return true;
*************** expand_cond_binop (unsigned icode, rtx *
*** 4692,4744 ****
  
  /* Prepare insn_code for gather_load/scatter_store according to
     the vector mode and index mode.  */
! static insn_code
! prepare_gather_scatter (machine_mode vec_mode, machine_mode idx_mode,
! 			bool is_load)
  {
!   if (!is_load)
!     return code_for_pred_indexed_store (UNSPEC_UNORDERED, vec_mode, idx_mode);
!   else
      {
!       unsigned src_eew_bitsize = GET_MODE_BITSIZE (GET_MODE_INNER (idx_mode));
!       unsigned dst_eew_bitsize = GET_MODE_BITSIZE (GET_MODE_INNER (vec_mode));
!       if (dst_eew_bitsize == src_eew_bitsize)
! 	return code_for_pred_indexed_load_same_eew (UNSPEC_UNORDERED, vec_mode);
!       else if (dst_eew_bitsize > src_eew_bitsize)
  	{
! 	  unsigned factor = dst_eew_bitsize / src_eew_bitsize;
! 	  switch (factor)
! 	    {
! 	    case 2:
! 	      return code_for_pred_indexed_load_x2_greater_eew (
! 		UNSPEC_UNORDERED, vec_mode);
! 	    case 4:
! 	      return code_for_pred_indexed_load_x4_greater_eew (
! 		UNSPEC_UNORDERED, vec_mode);
! 	    case 8:
! 	      return code_for_pred_indexed_load_x8_greater_eew (
! 		UNSPEC_UNORDERED, vec_mode);
! 	    default:
! 	      gcc_unreachable ();
! 	    }
  	}
!       else
  	{
! 	  unsigned factor = src_eew_bitsize / dst_eew_bitsize;
! 	  switch (factor)
! 	    {
! 	    case 2:
! 	      return code_for_pred_indexed_load_x2_smaller_eew (
! 		UNSPEC_UNORDERED, vec_mode);
! 	    case 4:
! 	      return code_for_pred_indexed_load_x4_smaller_eew (
! 		UNSPEC_UNORDERED, vec_mode);
! 	    case 8:
! 	      return code_for_pred_indexed_load_x8_smaller_eew (
! 		UNSPEC_UNORDERED, vec_mode);
! 	    default:
! 	      gcc_unreachable ();
! 	    }
  	}
      }
  }
--- 4786,4866 ----
  
  /* Prepare insn_code for gather_load/scatter_store according to
     the vector mode and index mode.  */
! insn_code
! get_gather_scatter_code (machine_mode vec_mode, machine_mode idx_mode,
! 			 bool is_load)
  {
!   unsigned src_eew_bitsize = GET_MODE_BITSIZE (GET_MODE_INNER (idx_mode));
!   unsigned dst_eew_bitsize = GET_MODE_BITSIZE (GET_MODE_INNER (vec_mode));
!   if (dst_eew_bitsize == src_eew_bitsize)
      {
!       if (is_load)
! 	return code_for_pred_indexed_load_same_eew
! 	  (UNSPEC_UNORDERED, vec_mode);
!       else
! 	return code_for_pred_indexed_store_same_eew
! 	  (UNSPEC_UNORDERED, vec_mode);
!     }
!   else if (dst_eew_bitsize > src_eew_bitsize)
!     {
!       unsigned factor = dst_eew_bitsize / src_eew_bitsize;
!       switch (factor)
  	{
! 	case 2:
! 	  if (is_load)
! 	    return
! 	      code_for_pred_indexed_load_x2_greater_eew
! 		(UNSPEC_UNORDERED, vec_mode);
! 	  else
! 	    return
! 	      code_for_pred_indexed_store_x2_greater_eew
! 		(UNSPEC_UNORDERED, vec_mode);
! 	case 4:
! 	  if (is_load)
! 	    return code_for_pred_indexed_load_x4_greater_eew
! 		(UNSPEC_UNORDERED, vec_mode);
! 	  else
! 	    return code_for_pred_indexed_store_x4_greater_eew
! 		(UNSPEC_UNORDERED, vec_mode);
! 	case 8:
! 	  if (is_load)
! 	    return code_for_pred_indexed_load_x8_greater_eew
! 	      (UNSPEC_UNORDERED, vec_mode);
! 	  else
! 	    return code_for_pred_indexed_store_x8_greater_eew
! 	      (UNSPEC_UNORDERED, vec_mode);
! 	default:
! 	  gcc_unreachable ();
  	}
!     }
!   else
!     {
!       unsigned factor = src_eew_bitsize / dst_eew_bitsize;
!       switch (factor)
  	{
! 	case 2:
! 	  if (is_load)
! 	    return code_for_pred_indexed_load_x2_smaller_eew
! 	      (UNSPEC_UNORDERED, vec_mode);
! 	  else
! 	    return code_for_pred_indexed_store_x2_smaller_eew
! 	      (UNSPEC_UNORDERED, vec_mode);
! 	case 4:
! 	  if (is_load)
! 	    return code_for_pred_indexed_load_x4_smaller_eew
! 	      (UNSPEC_UNORDERED, vec_mode);
! 	  else
! 	    return code_for_pred_indexed_store_x4_smaller_eew
! 	      (UNSPEC_UNORDERED, vec_mode);
! 	case 8:
! 	  if (is_load)
! 	    return code_for_pred_indexed_load_x8_smaller_eew
! 	      (UNSPEC_UNORDERED, vec_mode);
! 	  else
! 	    return code_for_pred_indexed_store_x8_smaller_eew
! 	      (UNSPEC_UNORDERED, vec_mode);
! 	default:
! 	  gcc_unreachable ();
  	}
      }
  }
*************** expand_gather_scatter (rtx *ops, bool is
*** 4769,4775 ****
    machine_mode idx_mode = GET_MODE (vec_offset);
    bool is_vlmax = is_vlmax_len_p (vec_mode, len);
  
!   insn_code icode = prepare_gather_scatter (vec_mode, idx_mode, is_load);
    if (is_vlmax)
      {
        if (is_load)
--- 4891,4897 ----
    machine_mode idx_mode = GET_MODE (vec_offset);
    bool is_vlmax = is_vlmax_len_p (vec_mode, len);
  
!   insn_code icode = get_gather_scatter_code (vec_mode, idx_mode, is_load);
    if (is_vlmax)
      {
        if (is_load)
*************** expand_fold_extract_last (rtx *ops)
*** 5081,5089 ****
  bool
  cmp_lmul_le_one (machine_mode mode)
  {
!   if (riscv_v_ext_vector_mode_p (mode))
      return known_le (GET_MODE_SIZE (mode), BYTES_PER_RISCV_VECTOR);
!   else if (riscv_v_ext_vls_mode_p (mode))
      return known_le (GET_MODE_BITSIZE (mode), TARGET_MIN_VLEN);
    return false;
  }
--- 5203,5211 ----
  bool
  cmp_lmul_le_one (machine_mode mode)
  {
!   if (riscv_vla_mode_p (mode))
      return known_le (GET_MODE_SIZE (mode), BYTES_PER_RISCV_VECTOR);
!   else if (riscv_vls_mode_p (mode))
      return known_le (GET_MODE_BITSIZE (mode), TARGET_MIN_VLEN);
    return false;
  }
*************** cmp_lmul_le_one (machine_mode mode)
*** 5092,5100 ****
  bool
  cmp_lmul_gt_one (machine_mode mode)
  {
!   if (riscv_v_ext_vector_mode_p (mode))
      return known_gt (GET_MODE_SIZE (mode), BYTES_PER_RISCV_VECTOR);
!   else if (riscv_v_ext_vls_mode_p (mode))
      return known_gt (GET_MODE_BITSIZE (mode), TARGET_MIN_VLEN);
    return false;
  }
--- 5214,5222 ----
  bool
  cmp_lmul_gt_one (machine_mode mode)
  {
!   if (riscv_vla_mode_p (mode))
      return known_gt (GET_MODE_SIZE (mode), BYTES_PER_RISCV_VECTOR);
!   else if (riscv_vls_mode_p (mode))
      return known_gt (GET_MODE_BITSIZE (mode), TARGET_MIN_VLEN);
    return false;
  }
*************** cmp_lmul_gt_one (machine_mode mode)
*** 5168,5181 ****
     Then we can have the condition for VLS mode in fixed-vlmax, aka:
       PRECISION (VLSmode) < VLEN / (64 / PRECISION(VLS_inner_mode)).  */
  bool
! vls_mode_valid_p (machine_mode vls_mode, bool allow_up_to_lmul_8)
  {
    if (!TARGET_VECTOR || TARGET_XTHEADVECTOR)
      return false;
  
    if (rvv_vector_bits == RVV_VECTOR_BITS_SCALABLE)
      {
!       if (GET_MODE_CLASS (vls_mode) != MODE_VECTOR_BOOL)
  	return true;
        if (allow_up_to_lmul_8)
  	return true;
--- 5290,5303 ----
     Then we can have the condition for VLS mode in fixed-vlmax, aka:
       PRECISION (VLSmode) < VLEN / (64 / PRECISION(VLS_inner_mode)).  */
  bool
! vls_mode_valid_p (machine_mode mode, bool allow_up_to_lmul_8)
  {
    if (!TARGET_VECTOR || TARGET_XTHEADVECTOR)
      return false;
  
    if (rvv_vector_bits == RVV_VECTOR_BITS_SCALABLE)
      {
!       if (GET_MODE_CLASS (mode) != MODE_VECTOR_BOOL)
  	return true;
        if (allow_up_to_lmul_8)
  	return true;
*************** vls_mode_valid_p (machine_mode vls_mode,
*** 5188,5203 ****
  	 with size = 128 bits, we will end up with multiple ICEs in
  	 middle-end generic codes.  */
        return !ordered_p (TARGET_MAX_LMUL * BITS_PER_RISCV_VECTOR,
! 			 GET_MODE_PRECISION (vls_mode));
      }
  
    if (rvv_vector_bits == RVV_VECTOR_BITS_ZVL)
      {
!       machine_mode inner_mode = GET_MODE_INNER (vls_mode);
        int precision = GET_MODE_PRECISION (inner_mode).to_constant ();
        int min_vlmax_bitsize = TARGET_MIN_VLEN / (64 / precision);
  
!       return GET_MODE_PRECISION (vls_mode).to_constant () < min_vlmax_bitsize;
      }
  
    return false;
--- 5310,5325 ----
  	 with size = 128 bits, we will end up with multiple ICEs in
  	 middle-end generic codes.  */
        return !ordered_p (TARGET_MAX_LMUL * BITS_PER_RISCV_VECTOR,
! 			 GET_MODE_PRECISION (mode));
      }
  
    if (rvv_vector_bits == RVV_VECTOR_BITS_ZVL)
      {
!       machine_mode inner_mode = GET_MODE_INNER (mode);
        int precision = GET_MODE_PRECISION (inner_mode).to_constant ();
        int min_vlmax_bitsize = TARGET_MIN_VLEN / (64 / precision);
  
!       return GET_MODE_PRECISION (mode).to_constant () < min_vlmax_bitsize;
      }
  
    return false;
diff -Nrcpad gcc-16-20251214/gcc/config/riscv/riscv-vector-builtins-bases.cc gcc-16-20251221/gcc/config/riscv/riscv-vector-builtins-bases.cc
*** gcc-16-20251214/gcc/config/riscv/riscv-vector-builtins-bases.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/riscv/riscv-vector-builtins-bases.cc	Sun Dec 21 22:32:06 2025
*************** public:
*** 199,207 ****
        {
  	int unspec = ORDERED_P ? UNSPEC_ORDERED : UNSPEC_UNORDERED;
  	if (STORE_P)
! 	  return e.use_exact_insn (
! 	    code_for_pred_indexed_store (unspec, e.vector_mode (),
! 					 e.index_mode ()));
  	else
  	  {
  	    unsigned src_eew_bitsize
--- 199,255 ----
        {
  	int unspec = ORDERED_P ? UNSPEC_ORDERED : UNSPEC_UNORDERED;
  	if (STORE_P)
! 	  {
! 	    unsigned src_eew_bitsize
! 	      = GET_MODE_BITSIZE (GET_MODE_INNER (e.index_mode ()));
! 	    unsigned dst_eew_bitsize
! 	      = GET_MODE_BITSIZE (GET_MODE_INNER (e.vector_mode ()));
! 	    if (dst_eew_bitsize == src_eew_bitsize)
! 	      return e.use_exact_insn (
! 		code_for_pred_indexed_store_same_eew (unspec, e.vector_mode ()));
! 	    else if (dst_eew_bitsize > src_eew_bitsize)
! 	      {
! 		unsigned factor = dst_eew_bitsize / src_eew_bitsize;
! 		switch (factor)
! 		  {
! 		  case 2:
! 		    return e.use_exact_insn (
! 		      code_for_pred_indexed_store_x2_greater_eew (
! 			unspec, e.vector_mode ()));
! 		  case 4:
! 		    return e.use_exact_insn (
! 		      code_for_pred_indexed_store_x4_greater_eew (
! 			unspec, e.vector_mode ()));
! 		  case 8:
! 		    return e.use_exact_insn (
! 		      code_for_pred_indexed_store_x8_greater_eew (
! 			unspec, e.vector_mode ()));
! 		  default:
! 		    gcc_unreachable ();
! 		  }
! 	      }
! 	    else
! 	      {
! 		unsigned factor = src_eew_bitsize / dst_eew_bitsize;
! 		switch (factor)
! 		  {
! 		  case 2:
! 		    return e.use_exact_insn (
! 		      code_for_pred_indexed_store_x2_smaller_eew (
! 			unspec, e.vector_mode ()));
! 		  case 4:
! 		    return e.use_exact_insn (
! 		      code_for_pred_indexed_store_x4_smaller_eew (
! 			unspec, e.vector_mode ()));
! 		  case 8:
! 		    return e.use_exact_insn (
! 		      code_for_pred_indexed_store_x8_smaller_eew (
! 			unspec, e.vector_mode ()));
! 		  default:
! 		    gcc_unreachable ();
! 		  }
! 	      }
! 	  }
  	else
  	  {
  	    unsigned src_eew_bitsize
*************** public:
*** 1782,1788 ****
      tree rhs_tuple = gimple_call_arg (f.call, 0);
      /* LMUL > 1 non-tuple vector types are not structure,
         we can't use __val[index] to set the subpart.  */
!     if (!riscv_v_ext_tuple_mode_p (TYPE_MODE (TREE_TYPE (rhs_tuple))))
        return NULL;
      tree index = gimple_call_arg (f.call, 1);
      tree rhs_vector = gimple_call_arg (f.call, 2);
--- 1830,1836 ----
      tree rhs_tuple = gimple_call_arg (f.call, 0);
      /* LMUL > 1 non-tuple vector types are not structure,
         we can't use __val[index] to set the subpart.  */
!     if (!riscv_tuple_mode_p (TYPE_MODE (TREE_TYPE (rhs_tuple))))
        return NULL;
      tree index = gimple_call_arg (f.call, 1);
      tree rhs_vector = gimple_call_arg (f.call, 2);
*************** public:
*** 1813,1819 ****
      if (!e.target)
        return NULL_RTX;
      rtx dest = expand_normal (CALL_EXPR_ARG (e.exp, 0));
!     gcc_assert (riscv_v_ext_vector_mode_p (GET_MODE (dest)));
      rtx index = expand_normal (CALL_EXPR_ARG (e.exp, 1));
      rtx src = expand_normal (CALL_EXPR_ARG (e.exp, 2));
      poly_int64 offset = INTVAL (index) * GET_MODE_SIZE (GET_MODE (src));
--- 1861,1867 ----
      if (!e.target)
        return NULL_RTX;
      rtx dest = expand_normal (CALL_EXPR_ARG (e.exp, 0));
!     gcc_assert (riscv_vla_mode_p (GET_MODE (dest)));
      rtx index = expand_normal (CALL_EXPR_ARG (e.exp, 1));
      rtx src = expand_normal (CALL_EXPR_ARG (e.exp, 2));
      poly_int64 offset = INTVAL (index) * GET_MODE_SIZE (GET_MODE (src));
*************** public:
*** 1836,1842 ****
      tree rhs_tuple = gimple_call_arg (f.call, 0);
      /* LMUL > 1 non-tuple vector types are not structure,
         we can't use __val[index] to get the subpart.  */
!     if (!riscv_v_ext_tuple_mode_p (TYPE_MODE (TREE_TYPE (rhs_tuple))))
        return NULL;
      tree index = gimple_call_arg (f.call, 1);
      tree field = tuple_type_field (TREE_TYPE (rhs_tuple));
--- 1884,1890 ----
      tree rhs_tuple = gimple_call_arg (f.call, 0);
      /* LMUL > 1 non-tuple vector types are not structure,
         we can't use __val[index] to get the subpart.  */
!     if (!riscv_tuple_mode_p (TYPE_MODE (TREE_TYPE (rhs_tuple))))
        return NULL;
      tree index = gimple_call_arg (f.call, 1);
      tree field = tuple_type_field (TREE_TYPE (rhs_tuple));
*************** public:
*** 1852,1858 ****
      if (!e.target)
        return NULL_RTX;
      rtx src = expand_normal (CALL_EXPR_ARG (e.exp, 0));
!     gcc_assert (riscv_v_ext_vector_mode_p (GET_MODE (src)));
      rtx index = expand_normal (CALL_EXPR_ARG (e.exp, 1));
      poly_int64 offset = INTVAL (index) * GET_MODE_SIZE (GET_MODE (e.target));
      rtx subreg
--- 1900,1906 ----
      if (!e.target)
        return NULL_RTX;
      rtx src = expand_normal (CALL_EXPR_ARG (e.exp, 0));
!     gcc_assert (riscv_vla_mode_p (GET_MODE (src)));
      rtx index = expand_normal (CALL_EXPR_ARG (e.exp, 1));
      poly_int64 offset = INTVAL (index) * GET_MODE_SIZE (GET_MODE (e.target));
      rtx subreg
*************** public:
*** 1870,1876 ****
      tree lhs_type = TREE_TYPE (f.lhs);
      /* LMUL > 1 non-tuple vector types are not structure,
     we can't use __val[index] to set the subpart.  */
!     if (!riscv_v_ext_tuple_mode_p (TYPE_MODE (lhs_type)))
        return NULL;
  
      /* Replace the call with a clobber of the result (to prevent it from
--- 1918,1924 ----
      tree lhs_type = TREE_TYPE (f.lhs);
      /* LMUL > 1 non-tuple vector types are not structure,
     we can't use __val[index] to set the subpart.  */
!     if (!riscv_tuple_mode_p (TYPE_MODE (lhs_type)))
        return NULL;
  
      /* Replace the call with a clobber of the result (to prevent it from
*************** public:
*** 1901,1907 ****
    {
      if (!e.target)
        return NULL_RTX;
!     gcc_assert (riscv_v_ext_vector_mode_p (GET_MODE (e.target)));
      unsigned int nargs = call_expr_nargs (e.exp);
      for (unsigned int i = 0; i < nargs; i++)
        {
--- 1949,1955 ----
    {
      if (!e.target)
        return NULL_RTX;
!     gcc_assert (riscv_vla_mode_p (GET_MODE (e.target)));
      unsigned int nargs = call_expr_nargs (e.exp);
      for (unsigned int i = 0; i < nargs; i++)
        {
diff -Nrcpad gcc-16-20251214/gcc/config/riscv/riscv-vector-builtins.cc gcc-16-20251221/gcc/config/riscv/riscv-vector-builtins.cc
*** gcc-16-20251214/gcc/config/riscv/riscv-vector-builtins.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/riscv/riscv-vector-builtins.cc	Sun Dec 21 22:32:06 2025
*************** rvv_switcher::rvv_switcher (bool pollute
*** 3679,3685 ****
    memcpy (m_old_have_regs_of_mode, have_regs_of_mode,
  	  sizeof (have_regs_of_mode));
    for (int i = 0; i < NUM_MACHINE_MODES; ++i)
!     if (riscv_v_ext_vector_mode_p ((machine_mode) i))
        have_regs_of_mode[i] = true;
  
    /* Not necessary to adjust mode and register type if we don't pollute
--- 3679,3685 ----
    memcpy (m_old_have_regs_of_mode, have_regs_of_mode,
  	  sizeof (have_regs_of_mode));
    for (int i = 0; i < NUM_MACHINE_MODES; ++i)
!     if (riscv_vla_mode_p ((machine_mode) i))
        have_regs_of_mode[i] = true;
  
    /* Not necessary to adjust mode and register type if we don't pollute
*************** register_builtin_type (vector_type_index
*** 3770,3776 ****
       Ideally, we should report error message more friendly instead of
       reporting "unknown" type. Support more friendly error message in
       the future.  */
!   if (!riscv_v_ext_vector_mode_p (mode))
      return;
  
    tree vectype = build_vector_type_for_mode (eltype, mode);
--- 3770,3776 ----
       Ideally, we should report error message more friendly instead of
       reporting "unknown" type. Support more friendly error message in
       the future.  */
!   if (!riscv_vla_mode_p (mode))
      return;
  
    tree vectype = build_vector_type_for_mode (eltype, mode);
diff -Nrcpad gcc-16-20251214/gcc/config/riscv/riscv-vector-costs.cc gcc-16-20251221/gcc/config/riscv/riscv-vector-costs.cc
*** gcc-16-20251214/gcc/config/riscv/riscv-vector-costs.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/riscv/riscv-vector-costs.cc	Sun Dec 21 22:32:06 2025
*************** max_number_of_live_regs (loop_vec_info l
*** 545,551 ****
      {
        machine_mode mode = TYPE_MODE (TREE_TYPE (t));
        if (!lookup_vector_type_attribute (TREE_TYPE (t))
! 	  && !riscv_v_ext_vls_mode_p (mode))
  	continue;
  
        gimple *def = SSA_NAME_DEF_STMT (t);
--- 545,551 ----
      {
        machine_mode mode = TYPE_MODE (TREE_TYPE (t));
        if (!lookup_vector_type_attribute (TREE_TYPE (t))
! 	  && !riscv_vls_mode_p (mode))
  	continue;
  
        gimple *def = SSA_NAME_DEF_STMT (t);
*************** compute_estimated_lmul (loop_vec_info lo
*** 624,630 ****
  {
    gcc_assert (GET_MODE_BITSIZE (mode).is_constant ());
    int regno_alignment = riscv_get_v_regno_alignment (loop_vinfo->vector_mode);
!   if (riscv_v_ext_vls_mode_p (loop_vinfo->vector_mode))
      return regno_alignment;
    else
      {
--- 624,630 ----
  {
    gcc_assert (GET_MODE_BITSIZE (mode).is_constant ());
    int regno_alignment = riscv_get_v_regno_alignment (loop_vinfo->vector_mode);
!   if (riscv_vls_mode_p (loop_vinfo->vector_mode))
      return regno_alignment;
    else
      {
*************** costs::costs (vec_info *vinfo, bool cost
*** 895,901 ****
  {
    if (costing_for_scalar)
      m_cost_type = SCALAR_COST;
!   else if (riscv_v_ext_vector_mode_p (vinfo->vector_mode))
      m_cost_type = VLA_VECTOR_COST;
    else
      m_cost_type = VLS_VECTOR_COST;
--- 895,901 ----
  {
    if (costing_for_scalar)
      m_cost_type = SCALAR_COST;
!   else if (riscv_vla_mode_p (vinfo->vector_mode))
      m_cost_type = VLA_VECTOR_COST;
    else
      m_cost_type = VLS_VECTOR_COST;
*************** costs::better_main_loop_than_p (const ve
*** 1043,1049 ****
  			     " it has unexpected spills\n");
  	  return true;
  	}
!       else if (riscv_v_ext_vector_mode_p (other_loop_vinfo->vector_mode))
  	{
  	  if (LOOP_VINFO_NITERS_KNOWN_P (other_loop_vinfo))
  	    {
--- 1043,1049 ----
  			     " it has unexpected spills\n");
  	  return true;
  	}
!       else if (riscv_vla_mode_p (other_loop_vinfo->vector_mode))
  	{
  	  if (LOOP_VINFO_NITERS_KNOWN_P (other_loop_vinfo))
  	    {
*************** costs::adjust_stmt_cost (enum vect_cost_
*** 1137,1179 ****
  		  switch (group_size)
  		    {
  		    case 2:
! 		      if (riscv_v_ext_vector_mode_p (loop->vector_mode))
  			stmt_cost += costs->vla->segment_permute_2;
  		      else
  			stmt_cost += costs->vls->segment_permute_2;
  		      break;
  		    case 3:
! 		      if (riscv_v_ext_vector_mode_p (loop->vector_mode))
  			stmt_cost += costs->vla->segment_permute_3;
  		      else
  			stmt_cost += costs->vls->segment_permute_3;
  		      break;
  		    case 4:
! 		      if (riscv_v_ext_vector_mode_p (loop->vector_mode))
  			stmt_cost += costs->vla->segment_permute_4;
  		      else
  			stmt_cost += costs->vls->segment_permute_4;
  		      break;
  		    case 5:
! 		      if (riscv_v_ext_vector_mode_p (loop->vector_mode))
  			stmt_cost += costs->vla->segment_permute_5;
  		      else
  			stmt_cost += costs->vls->segment_permute_5;
  		      break;
  		    case 6:
! 		      if (riscv_v_ext_vector_mode_p (loop->vector_mode))
  			stmt_cost += costs->vla->segment_permute_6;
  		      else
  			stmt_cost += costs->vls->segment_permute_6;
  		      break;
  		    case 7:
! 		      if (riscv_v_ext_vector_mode_p (loop->vector_mode))
  			stmt_cost += costs->vla->segment_permute_7;
  		      else
  			stmt_cost += costs->vls->segment_permute_7;
  		      break;
  		    case 8:
! 		      if (riscv_v_ext_vector_mode_p (loop->vector_mode))
  			stmt_cost += costs->vla->segment_permute_8;
  		      else
  			stmt_cost += costs->vls->segment_permute_8;
--- 1137,1179 ----
  		  switch (group_size)
  		    {
  		    case 2:
! 		      if (riscv_vla_mode_p (loop->vector_mode))
  			stmt_cost += costs->vla->segment_permute_2;
  		      else
  			stmt_cost += costs->vls->segment_permute_2;
  		      break;
  		    case 3:
! 		      if (riscv_vla_mode_p (loop->vector_mode))
  			stmt_cost += costs->vla->segment_permute_3;
  		      else
  			stmt_cost += costs->vls->segment_permute_3;
  		      break;
  		    case 4:
! 		      if (riscv_vla_mode_p (loop->vector_mode))
  			stmt_cost += costs->vla->segment_permute_4;
  		      else
  			stmt_cost += costs->vls->segment_permute_4;
  		      break;
  		    case 5:
! 		      if (riscv_vla_mode_p (loop->vector_mode))
  			stmt_cost += costs->vla->segment_permute_5;
  		      else
  			stmt_cost += costs->vls->segment_permute_5;
  		      break;
  		    case 6:
! 		      if (riscv_vla_mode_p (loop->vector_mode))
  			stmt_cost += costs->vla->segment_permute_6;
  		      else
  			stmt_cost += costs->vls->segment_permute_6;
  		      break;
  		    case 7:
! 		      if (riscv_vla_mode_p (loop->vector_mode))
  			stmt_cost += costs->vla->segment_permute_7;
  		      else
  			stmt_cost += costs->vls->segment_permute_7;
  		      break;
  		    case 8:
! 		      if (riscv_vla_mode_p (loop->vector_mode))
  			stmt_cost += costs->vla->segment_permute_8;
  		      else
  			stmt_cost += costs->vls->segment_permute_8;
diff -Nrcpad gcc-16-20251214/gcc/config/riscv/riscv.cc gcc-16-20251221/gcc/config/riscv/riscv.cc
*** gcc-16-20251214/gcc/config/riscv/riscv.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/riscv/riscv.cc	Sun Dec 21 22:32:06 2025
*************** riscv_valid_lo_sum_p (enum riscv_symbol_
*** 2241,2247 ****
     whereas 'RVVM1SI' mode is enabled if MIN_VLEN == 32.  */
  
  bool
! riscv_v_ext_vector_mode_p (machine_mode mode)
  {
  #define ENTRY(MODE, REQUIREMENT, ...)                                          \
    case MODE##mode:                                                             \
--- 2241,2247 ----
     whereas 'RVVM1SI' mode is enabled if MIN_VLEN == 32.  */
  
  bool
! riscv_vla_mode_p (machine_mode mode)
  {
  #define ENTRY(MODE, REQUIREMENT, ...)                                          \
    case MODE##mode:                                                             \
*************** riscv_v_ext_vector_mode_p (machine_mode
*** 2259,2265 ****
  /* Return true if mode is the RVV enabled tuple mode.  */
  
  bool
! riscv_v_ext_tuple_mode_p (machine_mode mode)
  {
  #define TUPLE_ENTRY(MODE, REQUIREMENT, ...)                                    \
    case MODE##mode:                                                             \
--- 2259,2265 ----
  /* Return true if mode is the RVV enabled tuple mode.  */
  
  bool
! riscv_tuple_mode_p (machine_mode mode)
  {
  #define TUPLE_ENTRY(MODE, REQUIREMENT, ...)                                    \
    case MODE##mode:                                                             \
*************** riscv_v_ext_tuple_mode_p (machine_mode m
*** 2277,2283 ****
  /* Return true if mode is the RVV enabled vls mode.  */
  
  bool
! riscv_v_ext_vls_mode_p (machine_mode mode)
  {
  #define VLS_ENTRY(MODE, REQUIREMENT)                                           \
    case MODE##mode:                                                             \
--- 2277,2283 ----
  /* Return true if mode is the RVV enabled vls mode.  */
  
  bool
! riscv_vls_mode_p (machine_mode mode)
  {
  #define VLS_ENTRY(MODE, REQUIREMENT)                                           \
    case MODE##mode:                                                             \
*************** riscv_v_ext_vls_mode_p (machine_mode mod
*** 2298,2307 ****
     3. RVV vls mode.  */
  
  static bool
! riscv_v_ext_mode_p (machine_mode mode)
  {
!   return riscv_v_ext_vector_mode_p (mode) || riscv_v_ext_tuple_mode_p (mode)
! 	 || riscv_v_ext_vls_mode_p (mode);
  }
  
  static unsigned
--- 2298,2307 ----
     3. RVV vls mode.  */
  
  static bool
! riscv_vector_mode_p (machine_mode mode)
  {
!   return riscv_vla_mode_p (mode) || riscv_tuple_mode_p (mode)
! 	 || riscv_vls_mode_p (mode);
  }
  
  static unsigned
*************** poly_int64
*** 2346,2352 ****
  riscv_v_adjust_nunits (machine_mode mode, int scale)
  {
    gcc_assert (GET_MODE_CLASS (mode) == MODE_VECTOR_BOOL);
!   if (riscv_v_ext_mode_p (mode))
      {
        if (TARGET_MIN_VLEN == 32)
  	scale = scale / 2;
--- 2346,2352 ----
  riscv_v_adjust_nunits (machine_mode mode, int scale)
  {
    gcc_assert (GET_MODE_CLASS (mode) == MODE_VECTOR_BOOL);
!   if (riscv_vector_mode_p (mode))
      {
        if (TARGET_MIN_VLEN == 32)
  	scale = scale / 2;
*************** riscv_v_adjust_nunits (machine_mode mode
*** 2361,2367 ****
  poly_int64
  riscv_v_adjust_nunits (machine_mode mode, bool fractional_p, int lmul, int nf)
  {
!   if (riscv_v_ext_mode_p (mode))
      {
        scalar_mode smode = GET_MODE_INNER (mode);
        int size = GET_MODE_SIZE (smode);
--- 2361,2367 ----
  poly_int64
  riscv_v_adjust_nunits (machine_mode mode, bool fractional_p, int lmul, int nf)
  {
!   if (riscv_vector_mode_p (mode))
      {
        scalar_mode smode = GET_MODE_INNER (mode);
        int size = GET_MODE_SIZE (smode);
*************** riscv_v_adjust_nunits (machine_mode mode
*** 2381,2387 ****
  poly_int64
  riscv_v_adjust_bytesize (machine_mode mode, int scale)
  {
!   if (riscv_v_ext_vector_mode_p (mode))
      {
        if (TARGET_XTHEADVECTOR)
  	return BYTES_PER_RISCV_VECTOR;
--- 2381,2387 ----
  poly_int64
  riscv_v_adjust_bytesize (machine_mode mode, int scale)
  {
!   if (riscv_vla_mode_p (mode))
      {
        if (TARGET_XTHEADVECTOR)
  	return BYTES_PER_RISCV_VECTOR;
*************** riscv_classify_address (struct riscv_add
*** 2430,2436 ****
  
      case PLUS:
        /* RVV load/store disallow any offset.  */
!       if (riscv_v_ext_mode_p (mode))
  	return false;
  
        info->type = ADDRESS_REG;
--- 2430,2436 ----
  
      case PLUS:
        /* RVV load/store disallow any offset.  */
!       if (riscv_vector_mode_p (mode))
  	return false;
  
        info->type = ADDRESS_REG;
*************** riscv_classify_address (struct riscv_add
*** 2441,2447 ****
  
      case LO_SUM:
        /* RVV load/store disallow LO_SUM.  */
!       if (riscv_v_ext_mode_p (mode))
  	return false;
  
        info->type = ADDRESS_LO_SUM;
--- 2441,2447 ----
  
      case LO_SUM:
        /* RVV load/store disallow LO_SUM.  */
!       if (riscv_vector_mode_p (mode))
  	return false;
  
        info->type = ADDRESS_LO_SUM;
*************** riscv_classify_address (struct riscv_add
*** 2476,2482 ****
  	 | vs1r.v  v24,0(a0)					    |
  	 +----------------------------------------------------------+
  	 This behavior will benefit the underlying RVV auto vectorization.  */
!       if (riscv_v_ext_mode_p (mode))
  	return x == const0_rtx;
  
        /* Small-integer addresses don't occur very often, but they
--- 2476,2482 ----
  	 | vs1r.v  v24,0(a0)					    |
  	 +----------------------------------------------------------+
  	 This behavior will benefit the underlying RVV auto vectorization.  */
!       if (riscv_vector_mode_p (mode))
  	return x == const0_rtx;
  
        /* Small-integer addresses don't occur very often, but they
*************** riscv_legitimate_address_p (machine_mode
*** 2497,2503 ****
  {
    /* Disallow RVV modes base address.
       E.g. (mem:SI (subreg:DI (reg:V1DI 155) 0).  */
!   if (SUBREG_P (x) && riscv_v_ext_mode_p (GET_MODE (SUBREG_REG (x))))
      return false;
    struct riscv_address_info addr;
  
--- 2497,2503 ----
  {
    /* Disallow RVV modes base address.
       E.g. (mem:SI (subreg:DI (reg:V1DI 155) 0).  */
!   if (SUBREG_P (x) && riscv_vector_mode_p (GET_MODE (SUBREG_REG (x))))
      return false;
    struct riscv_address_info addr;
  
*************** riscv_address_insns (rtx x, machine_mode
*** 2570,2576 ****
  
    /* BLKmode is used for single unaligned loads and stores and should
       not count as a multiword mode. */
!   if (!riscv_v_ext_vector_mode_p (mode) && mode != BLKmode && might_split_p)
      n += (GET_MODE_SIZE (mode).to_constant () + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
  
    if (addr.type == ADDRESS_LO_SUM)
--- 2570,2576 ----
  
    /* BLKmode is used for single unaligned loads and stores and should
       not count as a multiword mode. */
!   if (!riscv_vla_mode_p (mode) && mode != BLKmode && might_split_p)
      n += (GET_MODE_SIZE (mode).to_constant () + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
  
    if (addr.type == ADDRESS_LO_SUM)
*************** riscv_const_insns (rtx x, bool allow_new
*** 2628,2634 ****
  	       out range of [-16, 15].
  	  - 3. const series vector.
  	  ...etc.  */
! 	if (riscv_v_ext_mode_p (GET_MODE (x)))
  	  {
  	    rtx elt;
  	    if (const_vec_duplicate_p (x, &elt))
--- 2628,2634 ----
  	       out range of [-16, 15].
  	  - 3. const series vector.
  	  ...etc.  */
! 	if (riscv_vector_mode_p (GET_MODE (x)))
  	  {
  	    rtx elt;
  	    if (const_vec_duplicate_p (x, &elt))
*************** riscv_legitimize_move (machine_mode mode
*** 3786,3792 ****
         (set (reg:DI target) (subreg:DI (reg:V8QI reg) 0))
       Since RVV mode and scalar mode are in different REG_CLASS,
       we need to explicitly move data from V_REGS to GR_REGS by scalar move.  */
!   if (SUBREG_P (src) && riscv_v_ext_mode_p (GET_MODE (SUBREG_REG (src))))
      {
        machine_mode vmode = GET_MODE (SUBREG_REG (src));
        unsigned int mode_size = GET_MODE_SIZE (mode).to_constant ();
--- 3786,3792 ----
         (set (reg:DI target) (subreg:DI (reg:V8QI reg) 0))
       Since RVV mode and scalar mode are in different REG_CLASS,
       we need to explicitly move data from V_REGS to GR_REGS by scalar move.  */
!   if (SUBREG_P (src) && riscv_vector_mode_p (GET_MODE (SUBREG_REG (src))))
      {
        machine_mode vmode = GET_MODE (SUBREG_REG (src));
        unsigned int mode_size = GET_MODE_SIZE (mode).to_constant ();
*************** riscv_immediate_operand_p (int code, HOS
*** 4053,4059 ****
  static int
  riscv_binary_cost (rtx x, int single_insns, int double_insns)
  {
!   if (!riscv_v_ext_mode_p (GET_MODE (x))
        && riscv_2x_xlen_mode_p (GET_MODE (x)))
      return COSTS_N_INSNS (double_insns);
    return COSTS_N_INSNS (single_insns);
--- 4053,4059 ----
  static int
  riscv_binary_cost (rtx x, int single_insns, int double_insns)
  {
!   if (!riscv_vector_mode_p (GET_MODE (x))
        && riscv_2x_xlen_mode_p (GET_MODE (x)))
      return COSTS_N_INSNS (double_insns);
    return COSTS_N_INSNS (single_insns);
*************** riscv_rtx_costs (rtx x, machine_mode mod
*** 4107,4113 ****
  {
    /* TODO: We set RVV instruction cost as 1 by default.
       Cost Model need to be well analyzed and supported in the future. */
!   if (riscv_v_ext_mode_p (mode))
      {
        int gr2vr_cost = get_gr2vr_cost ();
        int fr2vr_cost = get_fr2vr_cost ();
--- 4107,4113 ----
  {
    /* TODO: We set RVV instruction cost as 1 by default.
       Cost Model need to be well analyzed and supported in the future. */
!   if (riscv_vector_mode_p (mode))
      {
        int gr2vr_cost = get_gr2vr_cost ();
        int fr2vr_cost = get_fr2vr_cost ();
*************** static rtx
*** 6404,6410 ****
  riscv_pass_vls_aggregate_in_gpr (struct riscv_arg_info *info, machine_mode mode,
  				 unsigned gpr_base)
  {
!   gcc_assert (riscv_v_ext_vls_mode_p (mode));
  
    unsigned count = 0;
    unsigned regnum = 0;
--- 6404,6410 ----
  riscv_pass_vls_aggregate_in_gpr (struct riscv_arg_info *info, machine_mode mode,
  				 unsigned gpr_base)
  {
!   gcc_assert (riscv_vls_mode_p (mode));
  
    unsigned count = 0;
    unsigned regnum = 0;
*************** static rtx
*** 6475,6481 ****
  riscv_get_vector_arg (struct riscv_arg_info *info, const CUMULATIVE_ARGS *cum,
  		      machine_mode mode, bool return_p, bool vls_p = false)
  {
!   gcc_assert (riscv_v_ext_mode_p (mode));
  
    info->mr_offset = cum->num_mrs;
    if (GET_MODE_CLASS (mode) == MODE_VECTOR_BOOL)
--- 6475,6481 ----
  riscv_get_vector_arg (struct riscv_arg_info *info, const CUMULATIVE_ARGS *cum,
  		      machine_mode mode, bool return_p, bool vls_p = false)
  {
!   gcc_assert (riscv_vector_mode_p (mode));
  
    info->mr_offset = cum->num_mrs;
    if (GET_MODE_CLASS (mode) == MODE_VECTOR_BOOL)
*************** riscv_get_vector_arg (struct riscv_arg_i
*** 6502,6508 ****
       register to pass. Just call TARGET_HARD_REGNO_NREGS for the number
       information.  */
    int nregs = riscv_hard_regno_nregs (V_ARG_FIRST, mode);
!   int LMUL = riscv_v_ext_tuple_mode_p (mode)
  	       ? nregs / riscv_vector::get_nf (mode)
  	       : nregs;
    int arg_reg_start = V_ARG_FIRST - V_REG_FIRST;
--- 6502,6508 ----
       register to pass. Just call TARGET_HARD_REGNO_NREGS for the number
       information.  */
    int nregs = riscv_hard_regno_nregs (V_ARG_FIRST, mode);
!   int LMUL = riscv_tuple_mode_p (mode)
  	       ? nregs / riscv_vector::get_nf (mode)
  	       : nregs;
    int arg_reg_start = V_ARG_FIRST - V_REG_FIRST;
*************** static rtx
*** 6672,6678 ****
  riscv_pass_vls_in_vr (struct riscv_arg_info *info, const CUMULATIVE_ARGS *cum,
  		      machine_mode mode, bool return_p)
  {
!   gcc_assert (riscv_v_ext_vls_mode_p (mode));
  
    unsigned int abi_vlen = riscv_get_cc_abi_vlen (cum->variant_cc);
    unsigned int mode_size = GET_MODE_SIZE (mode).to_constant ();
--- 6672,6678 ----
  riscv_pass_vls_in_vr (struct riscv_arg_info *info, const CUMULATIVE_ARGS *cum,
  		      machine_mode mode, bool return_p)
  {
!   gcc_assert (riscv_vls_mode_p (mode));
  
    unsigned int abi_vlen = riscv_get_cc_abi_vlen (cum->variant_cc);
    unsigned int mode_size = GET_MODE_SIZE (mode).to_constant ();
*************** riscv_get_arg_info (struct riscv_arg_inf
*** 6789,6795 ****
    info->fpr_offset = cum->num_fprs;
  
    /* Passed by reference when the scalable vector argument is anonymous.  */
!   if (riscv_v_ext_mode_p (mode) && !named)
      return NULL_RTX;
  
    if (named)
--- 6789,6795 ----
    info->fpr_offset = cum->num_fprs;
  
    /* Passed by reference when the scalable vector argument is anonymous.  */
!   if (riscv_vector_mode_p (mode) && !named)
      return NULL_RTX;
  
    if (named)
*************** riscv_get_arg_info (struct riscv_arg_inf
*** 6855,6866 ****
  	}
  
        /* For scalable vector argument.  */
!       if (riscv_vector_type_p (type) && riscv_v_ext_mode_p (mode))
  	return riscv_get_vector_arg (info, cum, mode, return_p);
  
        if (riscv_vls_cc_p (cum->variant_cc))
  	{
! 	  if (riscv_v_ext_vls_mode_p (mode))
  	    return riscv_pass_vls_in_vr (info, cum, mode, return_p);
  
  	  rtx ret = riscv_pass_aggregate_in_vr (info, cum, type, return_p);
--- 6855,6866 ----
  	}
  
        /* For scalable vector argument.  */
!       if (riscv_vector_type_p (type) && riscv_vector_mode_p (mode))
  	return riscv_get_vector_arg (info, cum, mode, return_p);
  
        if (riscv_vls_cc_p (cum->variant_cc))
  	{
! 	  if (riscv_vls_mode_p (mode))
  	    return riscv_pass_vls_in_vr (info, cum, mode, return_p);
  
  	  rtx ret = riscv_pass_aggregate_in_vr (info, cum, type, return_p);
*************** riscv_get_arg_info (struct riscv_arg_inf
*** 6869,6875 ****
  	}
  
        /* For vls mode aggregated in gpr (for non-VLS-CC).  */
!       if (riscv_v_ext_vls_mode_p (mode))
  	return riscv_pass_vls_aggregate_in_gpr (info, mode, gpr_base);
      }
  
--- 6869,6875 ----
  	}
  
        /* For vls mode aggregated in gpr (for non-VLS-CC).  */
!       if (riscv_vls_mode_p (mode))
  	return riscv_pass_vls_aggregate_in_gpr (info, mode, gpr_base);
      }
  
*************** riscv_pass_by_reference (cumulative_args
*** 7018,7024 ****
  	return false;
  
        /* Don't pass by reference if we can use general register(s) for vls.  */
!       if (info.num_gprs && riscv_v_ext_vls_mode_p (arg.mode))
  	return false;
  
        /* Don't pass by reference if we can use vector register groups.  */
--- 7018,7024 ----
  	return false;
  
        /* Don't pass by reference if we can use general register(s) for vls.  */
!       if (info.num_gprs && riscv_vls_mode_p (arg.mode))
  	return false;
  
        /* Don't pass by reference if we can use vector register groups.  */
*************** riscv_pass_by_reference (cumulative_args
*** 7029,7035 ****
    /* Passed by reference when:
       1. The scalable vector argument is anonymous.
       2. Args cannot be passed through vector registers.  */
!   if (riscv_v_ext_mode_p (arg.mode))
      return true;
  
    /* Pass by reference if the data do not fit in two integer registers.  */
--- 7029,7035 ----
    /* Passed by reference when:
       1. The scalable vector argument is anonymous.
       2. Args cannot be passed through vector registers.  */
!   if (riscv_vector_mode_p (arg.mode))
      return true;
  
    /* Pass by reference if the data do not fit in two integer registers.  */
*************** riscv_vector_required_min_vlen (const_tr
*** 7169,7175 ****
  {
    machine_mode mode = TYPE_MODE (type);
  
!   if (riscv_v_ext_mode_p (mode))
      return TARGET_MIN_VLEN;
  
    int element_bitsize = riscv_vector_element_bitsize (type);
--- 7169,7175 ----
  {
    machine_mode mode = TYPE_MODE (type);
  
!   if (riscv_vector_mode_p (mode))
      return TARGET_MIN_VLEN;
  
    int element_bitsize = riscv_vector_element_bitsize (type);
*************** riscv_get_v_regno_alignment (machine_mod
*** 7771,7777 ****
       but for mask vector register, register numbers can be any number. */
    int lmul = 1;
    machine_mode rvv_mode = mode;
!   if (riscv_v_ext_vls_mode_p (rvv_mode))
      {
        int size = GET_MODE_BITSIZE (rvv_mode).to_constant ();
        if (size < TARGET_MIN_VLEN)
--- 7771,7777 ----
       but for mask vector register, register numbers can be any number. */
    int lmul = 1;
    machine_mode rvv_mode = mode;
!   if (riscv_vls_mode_p (rvv_mode))
      {
        int size = GET_MODE_BITSIZE (rvv_mode).to_constant ();
        if (size < TARGET_MIN_VLEN)
*************** riscv_get_v_regno_alignment (machine_mod
*** 7779,7785 ****
        else
  	return size / TARGET_MIN_VLEN;
      }
!   if (riscv_v_ext_tuple_mode_p (rvv_mode))
      rvv_mode = riscv_vector::get_subpart_mode (rvv_mode);
    poly_int64 size = GET_MODE_SIZE (rvv_mode);
    if (known_gt (size, UNITS_PER_V_REG))
--- 7779,7785 ----
        else
  	return size / TARGET_MIN_VLEN;
      }
!   if (riscv_tuple_mode_p (rvv_mode))
      rvv_mode = riscv_vector::get_subpart_mode (rvv_mode);
    poly_int64 size = GET_MODE_SIZE (rvv_mode);
    if (known_gt (size, UNITS_PER_V_REG))
*************** riscv_print_operand (FILE *file, rtx op,
*** 7841,7847 ****
  	   1. If the operand is VECTOR REG, we print 'v'(vnsrl.wv).
  	   2. If the operand is CONST_INT/CONST_VECTOR, we print 'i'(vnsrl.wi).
  	   3. If the operand is SCALAR REG, we print 'x'(vnsrl.wx).  */
! 	if (riscv_v_ext_mode_p (mode))
  	  {
  	    if (REG_P (op))
  	      asm_fprintf (file, "v");
--- 7841,7847 ----
  	   1. If the operand is VECTOR REG, we print 'v'(vnsrl.wv).
  	   2. If the operand is CONST_INT/CONST_VECTOR, we print 'i'(vnsrl.wi).
  	   3. If the operand is SCALAR REG, we print 'x'(vnsrl.wx).  */
! 	if (riscv_vector_mode_p (mode))
  	  {
  	    if (REG_P (op))
  	      asm_fprintf (file, "v");
*************** riscv_print_operand (FILE *file, rtx op,
*** 7890,7896 ****
  	break;
        }
        case 'm': {
! 	if (riscv_v_ext_mode_p (mode))
  	  {
  	    /* Calculate lmul according to mode and print the value.  */
  	    int lmul = riscv_get_v_regno_alignment (mode);
--- 7890,7896 ----
  	break;
        }
        case 'm': {
! 	if (riscv_vector_mode_p (mode))
  	  {
  	    /* Calculate lmul according to mode and print the value.  */
  	    int lmul = riscv_get_v_regno_alignment (mode);
*************** riscv_secondary_memory_needed (machine_m
*** 10594,10600 ****
  {
    bool class1_is_fpr = class1 == FP_REGS || class1 == RVC_FP_REGS;
    bool class2_is_fpr = class2 == FP_REGS || class2 == RVC_FP_REGS;
!   return (!riscv_v_ext_mode_p (mode)
  	  && GET_MODE_SIZE (mode).to_constant () > UNITS_PER_WORD
  	  && (class1_is_fpr != class2_is_fpr)
  	  && !TARGET_XTHEADFMV
--- 10594,10600 ----
  {
    bool class1_is_fpr = class1 == FP_REGS || class1 == RVC_FP_REGS;
    bool class2_is_fpr = class2 == FP_REGS || class2 == RVC_FP_REGS;
!   return (!riscv_vector_mode_p (mode)
  	  && GET_MODE_SIZE (mode).to_constant () > UNITS_PER_WORD
  	  && (class1_is_fpr != class2_is_fpr)
  	  && !TARGET_XTHEADFMV
*************** riscv_register_move_cost (machine_mode m
*** 10638,10644 ****
  static unsigned int
  riscv_hard_regno_nregs (unsigned int regno, machine_mode mode)
  {
!   if (riscv_v_ext_vector_mode_p (mode))
      {
        /* Handle fractional LMUL, it only occupy part of vector register but
  	 still need one vector register to hold.  */
--- 10638,10644 ----
  static unsigned int
  riscv_hard_regno_nregs (unsigned int regno, machine_mode mode)
  {
!   if (riscv_vla_mode_p (mode))
      {
        /* Handle fractional LMUL, it only occupy part of vector register but
  	 still need one vector register to hold.  */
*************** riscv_hard_regno_nregs (unsigned int reg
*** 10649,10655 ****
      }
  
    /* For tuple modes, the number of register = NF * LMUL.  */
!   if (riscv_v_ext_tuple_mode_p (mode))
      {
        unsigned int nf = riscv_vector::get_nf (mode);
        machine_mode subpart_mode = riscv_vector::get_subpart_mode (mode);
--- 10649,10655 ----
      }
  
    /* For tuple modes, the number of register = NF * LMUL.  */
!   if (riscv_tuple_mode_p (mode))
      {
        unsigned int nf = riscv_vector::get_nf (mode);
        machine_mode subpart_mode = riscv_vector::get_subpart_mode (mode);
*************** riscv_hard_regno_nregs (unsigned int reg
*** 10665,10671 ****
      }
  
    /* For VLS modes, we allocate registers according to TARGET_MIN_VLEN.  */
!   if (riscv_v_ext_vls_mode_p (mode))
      {
        int size = GET_MODE_BITSIZE (mode).to_constant ();
        if (size < TARGET_MIN_VLEN)
--- 10665,10671 ----
      }
  
    /* For VLS modes, we allocate registers according to TARGET_MIN_VLEN.  */
!   if (riscv_vls_mode_p (mode))
      {
        int size = GET_MODE_BITSIZE (mode).to_constant ();
        if (size < TARGET_MIN_VLEN)
*************** riscv_hard_regno_mode_ok (unsigned int r
*** 10700,10706 ****
  
    if (GP_REG_P (regno))
      {
!       if (riscv_v_ext_mode_p (mode))
  	return false;
  
        /* Zilsd require load/store with even-odd reg pair.  */
--- 10700,10706 ----
  
    if (GP_REG_P (regno))
      {
!       if (riscv_vector_mode_p (mode))
  	return false;
  
        /* Zilsd require load/store with even-odd reg pair.  */
*************** riscv_hard_regno_mode_ok (unsigned int r
*** 10712,10718 ****
      }
    else if (FP_REG_P (regno))
      {
!       if (riscv_v_ext_mode_p (mode))
  	return false;
  
        if (!FP_REG_P (regno + nregs - 1))
--- 10712,10718 ----
      }
    else if (FP_REG_P (regno))
      {
!       if (riscv_vector_mode_p (mode))
  	return false;
  
        if (!FP_REG_P (regno + nregs - 1))
*************** riscv_hard_regno_mode_ok (unsigned int r
*** 10731,10737 ****
      }
    else if (V_REG_P (regno))
      {
!       if (!riscv_v_ext_mode_p (mode))
  	return false;
  
        if (!V_REG_P (regno + nregs - 1))
--- 10731,10737 ----
      }
    else if (V_REG_P (regno))
      {
!       if (!riscv_vector_mode_p (mode))
  	return false;
  
        if (!V_REG_P (regno + nregs - 1))
*************** riscv_modes_tieable_p (machine_mode mode
*** 10774,10780 ****
    /* We don't allow different REG_CLASS modes tieable since it
       will cause ICE in register allocation (RA).
       E.g. V2SI and DI are not tieable.  */
!   if (riscv_v_ext_mode_p (mode1) != riscv_v_ext_mode_p (mode2))
      return false;
    return (mode1 == mode2
  	  || !(GET_MODE_CLASS (mode1) == MODE_FLOAT
--- 10774,10780 ----
    /* We don't allow different REG_CLASS modes tieable since it
       will cause ICE in register allocation (RA).
       E.g. V2SI and DI are not tieable.  */
!   if (riscv_vector_mode_p (mode1) != riscv_vector_mode_p (mode2))
      return false;
    return (mode1 == mode2
  	  || !(GET_MODE_CLASS (mode1) == MODE_FLOAT
*************** riscv_can_change_mode_class (machine_mod
*** 12987,12993 ****
       we cannot, statically, determine which part of it to extract.
       Therefore prevent that.  */
    if (reg_classes_intersect_p (V_REGS, rclass)
!       && riscv_v_ext_vls_mode_p (from)
        && !ordered_p (BITS_PER_RISCV_VECTOR, GET_MODE_PRECISION (from)))
        return false;
  
--- 12987,12993 ----
       we cannot, statically, determine which part of it to extract.
       Therefore prevent that.  */
    if (reg_classes_intersect_p (V_REGS, rclass)
!       && riscv_vls_mode_p (from)
        && !ordered_p (BITS_PER_RISCV_VECTOR, GET_MODE_PRECISION (from)))
        return false;
  
*************** static bool
*** 13342,13348 ****
  riscv_vector_mode_supported_p (machine_mode mode)
  {
    if (TARGET_VECTOR)
!     return riscv_v_ext_mode_p (mode);
  
    return false;
  }
--- 13342,13348 ----
  riscv_vector_mode_supported_p (machine_mode mode)
  {
    if (TARGET_VECTOR)
!     return riscv_vector_mode_p (mode);
  
    return false;
  }
*************** riscv_regmode_natural_size (machine_mode
*** 13385,13400 ****
    /* ??? For now, only do this for variable-width RVV registers.
       Doing it for constant-sized registers breaks lower-subreg.c.  */
  
!   if (riscv_v_ext_mode_p (mode))
      {
        poly_uint64 size = GET_MODE_SIZE (mode);
!       if (riscv_v_ext_tuple_mode_p (mode))
  	{
  	  size = GET_MODE_SIZE (riscv_vector::get_subpart_mode (mode));
  	  if (known_lt (size, BYTES_PER_RISCV_VECTOR))
  	    return size;
  	}
!       else if (riscv_v_ext_vector_mode_p (mode))
  	{
  	  /* RVV mask modes always consume a single register.  */
  	  if (GET_MODE_CLASS (mode) == MODE_VECTOR_BOOL)
--- 13385,13400 ----
    /* ??? For now, only do this for variable-width RVV registers.
       Doing it for constant-sized registers breaks lower-subreg.c.  */
  
!   if (riscv_vector_mode_p (mode))
      {
        poly_uint64 size = GET_MODE_SIZE (mode);
!       if (riscv_tuple_mode_p (mode))
  	{
  	  size = GET_MODE_SIZE (riscv_vector::get_subpart_mode (mode));
  	  if (known_lt (size, BYTES_PER_RISCV_VECTOR))
  	    return size;
  	}
!       else if (riscv_vla_mode_p (mode))
  	{
  	  /* RVV mask modes always consume a single register.  */
  	  if (GET_MODE_CLASS (mode) == MODE_VECTOR_BOOL)
*************** riscv_regmode_natural_size (machine_mode
*** 13402,13408 ****
  	}
        if (!size.is_constant ())
  	return BYTES_PER_RISCV_VECTOR;
!       else if (!riscv_v_ext_vls_mode_p (mode))
  	/* For -march=rv64gc_zve32f, the natural vector register size
  	   is 32bits which is smaller than scalar register size, so we
  	   return minimum size between vector register size and scalar
--- 13402,13408 ----
  	}
        if (!size.is_constant ())
  	return BYTES_PER_RISCV_VECTOR;
!       else if (!riscv_vls_mode_p (mode))
  	/* For -march=rv64gc_zve32f, the natural vector register size
  	   is 32bits which is smaller than scalar register size, so we
  	   return minimum size between vector register size and scalar
*************** riscv_support_vector_misalignment (machi
*** 13480,13486 ****
  static opt_machine_mode
  riscv_get_mask_mode (machine_mode mode)
  {
!   if (TARGET_VECTOR && riscv_v_ext_mode_p (mode))
      return riscv_vector::get_mask_mode (mode);
  
    return default_get_mask_mode (mode);
--- 13480,13486 ----
  static opt_machine_mode
  riscv_get_mask_mode (machine_mode mode)
  {
!   if (TARGET_VECTOR && riscv_vector_mode_p (mode))
      return riscv_vector::get_mask_mode (mode);
  
    return default_get_mask_mode (mode);
*************** riscv_preferred_simd_mode (scalar_mode m
*** 13677,13683 ****
  static poly_uint64
  riscv_vectorize_preferred_vector_alignment (const_tree type)
  {
!   if (riscv_v_ext_mode_p (TYPE_MODE (type)))
      return TYPE_ALIGN (TREE_TYPE (type));
    return TYPE_ALIGN (type);
  }
--- 13677,13683 ----
  static poly_uint64
  riscv_vectorize_preferred_vector_alignment (const_tree type)
  {
!   if (riscv_vector_mode_p (TYPE_MODE (type)))
      return TYPE_ALIGN (TREE_TYPE (type));
    return TYPE_ALIGN (type);
  }
*************** riscv_vectorize_vec_perm_const (machine_
*** 14052,14058 ****
  				rtx target, rtx op0, rtx op1,
  				const vec_perm_indices &sel)
  {
!   if (TARGET_VECTOR && riscv_v_ext_mode_p (vmode))
      return riscv_vector::expand_vec_perm_const (vmode, op_mode, target, op0,
  						op1, sel);
  
--- 14052,14058 ----
  				rtx target, rtx op0, rtx op1,
  				const vec_perm_indices &sel)
  {
!   if (TARGET_VECTOR && riscv_vector_mode_p (vmode))
      return riscv_vector::expand_vec_perm_const (vmode, op_mode, target, op0,
  						op1, sel);
  
*************** get_common_costs (const cpu_vector_cost
*** 14071,14077 ****
  {
    gcc_assert (costs);
  
!   if (vectype && riscv_v_ext_vls_mode_p (TYPE_MODE (vectype)))
      return costs->vls;
    return costs->vla;
  }
--- 14071,14077 ----
  {
    gcc_assert (costs);
  
!   if (vectype && riscv_vls_mode_p (TYPE_MODE (vectype)))
      return costs->vls;
    return costs->vla;
  }
*************** static tree
*** 14211,14217 ****
  riscv_preferred_else_value (unsigned ifn, tree vectype, unsigned int nops,
  			    tree *ops)
  {
!   if (riscv_v_ext_mode_p (TYPE_MODE (vectype)))
      {
        tree tmp_var = create_tmp_var (vectype);
        TREE_NO_WARNING (tmp_var) = 1;
--- 14211,14217 ----
  riscv_preferred_else_value (unsigned ifn, tree vectype, unsigned int nops,
  			    tree *ops)
  {
!   if (riscv_vector_mode_p (TYPE_MODE (vectype)))
      {
        tree tmp_var = create_tmp_var (vectype);
        TREE_NO_WARNING (tmp_var) = 1;
diff -Nrcpad gcc-16-20251214/gcc/config/riscv/sync.md gcc-16-20251221/gcc/config/riscv/sync.md
*** gcc-16-20251214/gcc/config/riscv/sync.md	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/riscv/sync.md	Sun Dec 21 22:32:06 2025
***************
*** 528,560 ****
  
  ; Atomic CAS ops
  
- (define_insn "zalrsc_atomic_cas_value_strong<mode>"
-   [(set (match_operand:GPR 0 "register_operand" "=&r")
- 	(match_operand:GPR 1 "memory_operand" "+A"))
-    (set (match_dup 1)
- 	(unspec_volatile:GPR [(match_operand:GPR 2 "reg_or_0_operand" "rJ")
- 			      (match_operand:GPR 3 "reg_or_0_operand" "rJ")
- 			      (match_operand:SI 4 "const_int_operand")  ;; mod_s
- 			      (match_operand:SI 5 "const_int_operand")] ;; mod_f
- 	 UNSPEC_COMPARE_AND_SWAP))
-    (clobber (match_scratch:GPR 6 "=&r"))]
-   "TARGET_ZALRSC"
-   {
-     enum memmodel model_success = (enum memmodel) INTVAL (operands[4]);
-     enum memmodel model_failure = (enum memmodel) INTVAL (operands[5]);
-     /* Find the union of the two memory models so we can satisfy both success
-        and failure memory models.  */
-     operands[5] = GEN_INT (riscv_union_memmodels (model_success, model_failure));
-     return "1:\;"
- 	   "lr.<amo>%I5\t%0,%1\;"
- 	   "bne\t%0,%z2,1f\;"
- 	   "sc.<amo>%J5\t%6,%z3,%1\;"
- 	   "bnez\t%6,1b\;"
- 	   "1:";
-   }
-   [(set_attr "type" "multi")
-    (set (attr "length") (const_int 16))])
- 
  ;; Implement compare_exchange with a conservative leading fence when
  ;; model_failure is seq_cst.
  ;; This allows us to be compatible with the ISA manual Table A.6 and Table A.7
--- 528,533 ----
***************
*** 588,593 ****
--- 561,593 ----
  	(symbol_ref "(is_mm_seq_cst (memmodel_from_int (INTVAL (operands[5]))) ? 8
  		      : 4)"))])
  
+ (define_insn "zalrsc_atomic_cas_value_strong<mode>"
+   [(set (match_operand:GPR 0 "register_operand" "=&r")
+ 	(match_operand:GPR 1 "memory_operand" "+A"))
+    (set (match_dup 1)
+ 	(unspec_volatile:GPR [(match_operand:GPR 2 "reg_or_0_operand" "rJ")
+ 			      (match_operand:GPR 3 "reg_or_0_operand" "rJ")
+ 			      (match_operand:SI 4 "const_int_operand")  ;; mod_s
+ 			      (match_operand:SI 5 "const_int_operand")] ;; mod_f
+ 	 UNSPEC_COMPARE_AND_SWAP))
+    (clobber (match_scratch:GPR 6 "=&r"))]
+   "TARGET_ZALRSC"
+   {
+     enum memmodel model_success = (enum memmodel) INTVAL (operands[4]);
+     enum memmodel model_failure = (enum memmodel) INTVAL (operands[5]);
+     /* Find the union of the two memory models so we can satisfy both success
+        and failure memory models.  */
+     operands[5] = GEN_INT (riscv_union_memmodels (model_success, model_failure));
+     return "1:\;"
+ 	   "lr.<amo>%I5\t%0,%1\;"
+ 	   "bne\t%0,%z2,1f\;"
+ 	   "sc.<amo>%J5\t%6,%z3,%1\;"
+ 	   "bnez\t%6,1b\;"
+ 	   "1:";
+   }
+   [(set_attr "type" "multi")
+    (set (attr "length") (const_int 16))])
+ 
  (define_expand "atomic_compare_and_swap<mode>"
    [(match_operand:SI 0 "register_operand" "")   ;; bool output
     (match_operand:GPR 1 "register_operand" "")  ;; val output
diff -Nrcpad gcc-16-20251214/gcc/config/riscv/vector-crypto.md gcc-16-20251221/gcc/config/riscv/vector-crypto.md
*** gcc-16-20251214/gcc/config/riscv/vector-crypto.md	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/riscv/vector-crypto.md	Sun Dec 21 22:32:06 2025
***************
*** 223,230 ****
     (set_attr "mode" "<MODE>")])
  
  (define_insn "@pred_v<bitmanip_optab><mode>"
!   [(set (match_operand:VI 0 "register_operand"        "=vd,vd, vr, vr")
!      (if_then_else:VI
         (unspec:<VM>
           [(match_operand:<VM> 1 "vector_mask_operand" " vm,vm,Wc1,Wc1")
            (match_operand 5 "vector_length_operand"    " rK,rK, rK, rK")
--- 223,230 ----
     (set_attr "mode" "<MODE>")])
  
  (define_insn "@pred_v<bitmanip_optab><mode>"
!   [(set (match_operand:V_VLSI 0 "register_operand"        "=vd,vd, vr, vr")
!      (if_then_else:V_VLSI
         (unspec:<VM>
           [(match_operand:<VM> 1 "vector_mask_operand" " vm,vm,Wc1,Wc1")
            (match_operand 5 "vector_length_operand"    " rK,rK, rK, rK")
***************
*** 233,250 ****
            (match_operand 8 "const_int_operand"        "  i, i,  i,  i")
            (reg:SI VL_REGNUM)
            (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
!        (bitmanip_rotate:VI
!          (match_operand:VI 3 "register_operand"       " vr,vr, vr, vr")
!          (match_operand:VI 4 "register_operand"       " vr,vr, vr, vr"))
!        (match_operand:VI 2 "vector_merge_operand"     " vu, 0, vu,  0")))]
    "TARGET_ZVBB || TARGET_ZVKB"
    "v<bitmanip_insn>.vv\t%0,%3,%4%p1"
    [(set_attr "type" "v<bitmanip_insn>")
     (set_attr "mode" "<MODE>")])
  
  (define_insn "@pred_v<bitmanip_optab><mode>_scalar"
!   [(set (match_operand:VI 0 "register_operand"        "=vd,vd, vr, vr")
!      (if_then_else:VI
         (unspec:<VM>
           [(match_operand:<VM> 1 "vector_mask_operand" " vm,vm,Wc1,Wc1")
            (match_operand 5 "vector_length_operand"    " rK,rK, rK, rK")
--- 233,250 ----
            (match_operand 8 "const_int_operand"        "  i, i,  i,  i")
            (reg:SI VL_REGNUM)
            (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
!        (bitmanip_rotate:V_VLSI
!          (match_operand:V_VLSI 3 "register_operand"       " vr,vr, vr, vr")
!          (match_operand:V_VLSI 4 "register_operand"       " vr,vr, vr, vr"))
!        (match_operand:V_VLSI 2 "vector_merge_operand"     " vu, 0, vu,  0")))]
    "TARGET_ZVBB || TARGET_ZVKB"
    "v<bitmanip_insn>.vv\t%0,%3,%4%p1"
    [(set_attr "type" "v<bitmanip_insn>")
     (set_attr "mode" "<MODE>")])
  
  (define_insn "@pred_v<bitmanip_optab><mode>_scalar"
!   [(set (match_operand:V_VLSI 0 "register_operand"        "=vd,vd, vr, vr")
!      (if_then_else:V_VLSI
         (unspec:<VM>
           [(match_operand:<VM> 1 "vector_mask_operand" " vm,vm,Wc1,Wc1")
            (match_operand 5 "vector_length_operand"    " rK,rK, rK, rK")
***************
*** 253,270 ****
            (match_operand 8 "const_int_operand"        "  i, i,  i,  i")
            (reg:SI VL_REGNUM)
            (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
!        (bitmanip_rotate:VI
!          (match_operand:VI 3 "register_operand"       " vr,vr, vr, vr")
           (match_operand 4 "pmode_register_operand"    "  r, r,  r,  r"))
!        (match_operand:VI 2 "vector_merge_operand"     " vu, 0, vu,  0")))]
    "TARGET_ZVBB || TARGET_ZVKB"
    "v<bitmanip_insn>.vx\t%0,%3,%4%p1"
    [(set_attr "type" "v<bitmanip_insn>")
     (set_attr "mode" "<MODE>")])
  
  (define_insn "*pred_vror<mode>_scalar"
!   [(set (match_operand:VI 0 "register_operand"        "=vd,vd, vr,vr")
!      (if_then_else:VI
         (unspec:<VM>
           [(match_operand:<VM> 1 "vector_mask_operand" " vm,vm,Wc1,Wc1")
            (match_operand 5 "vector_length_operand"    " rK,rK, rK, rK")
--- 253,270 ----
            (match_operand 8 "const_int_operand"        "  i, i,  i,  i")
            (reg:SI VL_REGNUM)
            (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
!        (bitmanip_rotate:V_VLSI
!          (match_operand:V_VLSI 3 "register_operand"       " vr,vr, vr, vr")
           (match_operand 4 "pmode_register_operand"    "  r, r,  r,  r"))
!        (match_operand:V_VLSI 2 "vector_merge_operand"     " vu, 0, vu,  0")))]
    "TARGET_ZVBB || TARGET_ZVKB"
    "v<bitmanip_insn>.vx\t%0,%3,%4%p1"
    [(set_attr "type" "v<bitmanip_insn>")
     (set_attr "mode" "<MODE>")])
  
  (define_insn "*pred_vror<mode>_scalar"
!   [(set (match_operand:V_VLSI 0 "register_operand"        "=vd,vd, vr,vr")
!      (if_then_else:V_VLSI
         (unspec:<VM>
           [(match_operand:<VM> 1 "vector_mask_operand" " vm,vm,Wc1,Wc1")
            (match_operand 5 "vector_length_operand"    " rK,rK, rK, rK")
***************
*** 273,282 ****
            (match_operand 8 "const_int_operand"        "  i, i,  i,  i")
            (reg:SI VL_REGNUM)
            (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
!        (rotatert:VI
!          (match_operand:VI 3 "register_operand"       " vr,vr, vr, vr")
           (match_operand    4 "const_csr_operand"      "  K, K,  K,  K"))
!        (match_operand:VI 2 "vector_merge_operand"     " vu, 0, vu,  0")))]
    "TARGET_ZVBB || TARGET_ZVKB"
    "vror.vi\t%0,%3,%4%p1"
    [(set_attr "type" "vror")
--- 273,282 ----
            (match_operand 8 "const_int_operand"        "  i, i,  i,  i")
            (reg:SI VL_REGNUM)
            (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
!        (rotatert:V_VLSI
!          (match_operand:V_VLSI 3 "register_operand"       " vr,vr, vr, vr")
           (match_operand    4 "const_csr_operand"      "  K, K,  K,  K"))
!        (match_operand:V_VLSI 2 "vector_merge_operand"     " vu, 0, vu,  0")))]
    "TARGET_ZVBB || TARGET_ZVKB"
    "vror.vi\t%0,%3,%4%p1"
    [(set_attr "type" "vror")
***************
*** 365,372 ****
  ;; vclmul.vv vclmul.vx
  ;; vclmulh.vv vclmulh.vx
  (define_insn "@pred_vclmul<h><mode>"
!   [(set (match_operand:VI_D 0  "register_operand"     "=vd,vr,vd, vr")
!      (if_then_else:VI_D
         (unspec:<VM>
           [(match_operand:<VM> 1 "vector_mask_operand" "vm,Wc1,vm,Wc1")
            (match_operand 5 "vector_length_operand"    "rK, rK,rK, rK")
--- 365,372 ----
  ;; vclmul.vv vclmul.vx
  ;; vclmulh.vv vclmulh.vx
  (define_insn "@pred_vclmul<h><mode>"
!   [(set (match_operand:V_VLSI_D 0  "register_operand"     "=vd,vr,vd, vr")
!      (if_then_else:V_VLSI_D
         (unspec:<VM>
           [(match_operand:<VM> 1 "vector_mask_operand" "vm,Wc1,vm,Wc1")
            (match_operand 5 "vector_length_operand"    "rK, rK,rK, rK")
***************
*** 375,384 ****
            (match_operand 8 "const_int_operand"        " i,  i, i,  i")
            (reg:SI VL_REGNUM)
            (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
!        (unspec:VI_D
!          [(match_operand:VI_D 3 "register_operand"     "vr, vr,vr, vr")
!           (match_operand:VI_D 4 "register_operand"     "vr, vr,vr, vr")] UNSPEC_CLMUL_VC)
!        (match_operand:VI_D 2 "vector_merge_operand"    "vu, vu, 0,  0")))]
    "TARGET_ZVBC"
    "vclmul<h>.vv\t%0,%3,%4%p1"
    [(set_attr "type" "vclmul<h>")
--- 375,384 ----
            (match_operand 8 "const_int_operand"        " i,  i, i,  i")
            (reg:SI VL_REGNUM)
            (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
!        (unspec:V_VLSI_D
!          [(match_operand:V_VLSI_D 3 "register_operand"     "vr, vr,vr, vr")
!           (match_operand:V_VLSI_D 4 "register_operand"     "vr, vr,vr, vr")] UNSPEC_CLMUL_VC)
!        (match_operand:V_VLSI_D 2 "vector_merge_operand"    "vu, vu, 0,  0")))]
    "TARGET_ZVBC"
    "vclmul<h>.vv\t%0,%3,%4%p1"
    [(set_attr "type" "vclmul<h>")
***************
*** 386,393 ****
  
  ;; Deal with SEW = 64 in RV32 system.
  (define_expand "@pred_vclmul<h><mode>_scalar"
!   [(set (match_operand:VI_D 0 "register_operand")
!      (if_then_else:VI_D
         (unspec:<VM>
           [(match_operand:<VM> 1 "vector_mask_operand")
            (match_operand 5 "vector_length_operand")
--- 386,393 ----
  
  ;; Deal with SEW = 64 in RV32 system.
  (define_expand "@pred_vclmul<h><mode>_scalar"
!   [(set (match_operand:V_VLSI_D 0 "register_operand")
!      (if_then_else:V_VLSI_D
         (unspec:<VM>
           [(match_operand:<VM> 1 "vector_mask_operand")
            (match_operand 5 "vector_length_operand")
***************
*** 396,406 ****
            (match_operand 8 "const_int_operand")
            (reg:SI VL_REGNUM)
            (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
!        (unspec:VI_D
!          [(vec_duplicate:VI_D
              (match_operand:<VEL> 4 "register_operand"))
!           (match_operand:VI_D 3 "register_operand")] UNSPEC_CLMUL_VC)
!        (match_operand:VI_D 2 "vector_merge_operand")))]
    "TARGET_ZVBC"
  {
    if (riscv_vector::sew64_scalar_helper (
--- 396,406 ----
            (match_operand 8 "const_int_operand")
            (reg:SI VL_REGNUM)
            (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
!        (unspec:V_VLSI_D
!          [(vec_duplicate:V_VLSI_D
              (match_operand:<VEL> 4 "register_operand"))
!           (match_operand:V_VLSI_D 3 "register_operand")] UNSPEC_CLMUL_VC)
!        (match_operand:V_VLSI_D 2 "vector_merge_operand")))]
    "TARGET_ZVBC"
  {
    if (riscv_vector::sew64_scalar_helper (
***************
*** 419,426 ****
  })
  
  (define_insn "*pred_vclmul<h><mode>_scalar"
!   [(set (match_operand:VI_D 0 "register_operand"       "=vd,vr,vd, vr")
!     (if_then_else:VI_D
        (unspec:<VM>
          [(match_operand:<VM> 1 "vector_mask_operand"  "vm,Wc1,vm,Wc1")
          (match_operand 5 "vector_length_operand"      "rK, rK,rK, rK")
--- 419,426 ----
  })
  
  (define_insn "*pred_vclmul<h><mode>_scalar"
!   [(set (match_operand:V_VLSI_D 0 "register_operand"       "=vd,vr,vd, vr")
!     (if_then_else:V_VLSI_D
        (unspec:<VM>
          [(match_operand:<VM> 1 "vector_mask_operand"  "vm,Wc1,vm,Wc1")
          (match_operand 5 "vector_length_operand"      "rK, rK,rK, rK")
***************
*** 429,447 ****
          (match_operand 8 "const_int_operand"          " i,  i, i,  i")
          (reg:SI VL_REGNUM)
          (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
!       (unspec:VI_D
!         [(vec_duplicate:VI_D
             (match_operand:<VEL> 4 "reg_or_0_operand"   "rJ, rJ,rJ, rJ"))
!          (match_operand:VI_D 3 "register_operand"      "vr, vr,vr, vr")] UNSPEC_CLMUL_VC)
!       (match_operand:VI_D 2 "vector_merge_operand"     "vu, vu, 0,  0")))]
    "TARGET_ZVBC"
    "vclmul<h>.vx\t%0,%3,%4%p1"
    [(set_attr "type" "vclmul<h>")
     (set_attr "mode" "<MODE>")])
  
  (define_insn "*pred_vclmul<h><mode>_extend_scalar"
!   [(set (match_operand:VI_D 0 "register_operand"         "=vd,vr,vd, vr")
!     (if_then_else:VI_D
        (unspec:<VM>
          [(match_operand:<VM> 1 "vector_mask_operand"    "vm,Wc1,vm,Wc1")
          (match_operand 5 "vector_length_operand"        "rK, rK,rK, rK")
--- 429,447 ----
          (match_operand 8 "const_int_operand"          " i,  i, i,  i")
          (reg:SI VL_REGNUM)
          (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
!       (unspec:V_VLSI_D
!         [(vec_duplicate:V_VLSI_D
             (match_operand:<VEL> 4 "reg_or_0_operand"   "rJ, rJ,rJ, rJ"))
!          (match_operand:V_VLSI_D 3 "register_operand"      "vr, vr,vr, vr")] UNSPEC_CLMUL_VC)
!       (match_operand:V_VLSI_D 2 "vector_merge_operand"     "vu, vu, 0,  0")))]
    "TARGET_ZVBC"
    "vclmul<h>.vx\t%0,%3,%4%p1"
    [(set_attr "type" "vclmul<h>")
     (set_attr "mode" "<MODE>")])
  
  (define_insn "*pred_vclmul<h><mode>_extend_scalar"
!   [(set (match_operand:V_VLSI_D 0 "register_operand"         "=vd,vr,vd, vr")
!     (if_then_else:V_VLSI_D
        (unspec:<VM>
          [(match_operand:<VM> 1 "vector_mask_operand"    "vm,Wc1,vm,Wc1")
          (match_operand 5 "vector_length_operand"        "rK, rK,rK, rK")
***************
*** 450,461 ****
          (match_operand 8 "const_int_operand"            " i,  i, i,  i")
          (reg:SI VL_REGNUM)
          (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
!       (unspec:VI_D
!         [(vec_duplicate:VI_D
  	   (sign_extend:<VEL>
               (match_operand:<VSUBEL> 4 "reg_or_0_operand" " rJ, rJ,rJ, rJ")))
!          (match_operand:VI_D 3 "register_operand"        "vr, vr,vr, vr")] UNSPEC_CLMUL_VC)
!       (match_operand:VI_D 2 "vector_merge_operand"       "vu, vu, 0,  0")))]
    "TARGET_ZVBC"
    "vclmul<h>.vx\t%0,%3,%4%p1"
    [(set_attr "type" "vclmul<h>")
--- 450,461 ----
          (match_operand 8 "const_int_operand"            " i,  i, i,  i")
          (reg:SI VL_REGNUM)
          (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
!       (unspec:V_VLSI_D
!         [(vec_duplicate:V_VLSI_D
  	   (sign_extend:<VEL>
               (match_operand:<VSUBEL> 4 "reg_or_0_operand" " rJ, rJ,rJ, rJ")))
!          (match_operand:V_VLSI_D 3 "register_operand"        "vr, vr,vr, vr")] UNSPEC_CLMUL_VC)
!       (match_operand:V_VLSI_D 2 "vector_merge_operand"       "vu, vu, 0,  0")))]
    "TARGET_ZVBC"
    "vclmul<h>.vx\t%0,%3,%4%p1"
    [(set_attr "type" "vclmul<h>")
***************
*** 487,503 ****
  ;; vaesef.[vv,vs] vaesem.[vv,vs] vaesdf.[vv,vs] vaesdm.[vv,vs]
  ;; vsm4r.[vv,vs]
  (define_insn "@pred_crypto_vv<vv_ins_name><ins_type><mode>"
!   [(set (match_operand:VSI 0 "register_operand"    "=vr")
!      (if_then_else:VSI
         (unspec:<VM>
           [(match_operand 3 "vector_length_operand" " rK")
            (match_operand 4 "const_int_operand"     "  i")
            (match_operand 5 "const_int_operand"     "  i")
            (reg:SI VL_REGNUM)
            (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
!        (unspec:VSI
!          [(match_operand:VSI 1 "register_operand" " 0")
!           (match_operand:VSI 2 "register_operand" "vr")] UNSPEC_CRYPTO_VV)
         (match_dup 1)))]
    "TARGET_ZVKNED || TARGET_ZVKSED || TARGET_ZVKG"
    "v<vv_ins_name>.<ins_type>\t%0,%2"
--- 487,503 ----
  ;; vaesef.[vv,vs] vaesem.[vv,vs] vaesdf.[vv,vs] vaesdm.[vv,vs]
  ;; vsm4r.[vv,vs]
  (define_insn "@pred_crypto_vv<vv_ins_name><ins_type><mode>"
!   [(set (match_operand:V_VLSI_S 0 "register_operand"    "=vr")
!      (if_then_else:V_VLSI_S
         (unspec:<VM>
           [(match_operand 3 "vector_length_operand" " rK")
            (match_operand 4 "const_int_operand"     "  i")
            (match_operand 5 "const_int_operand"     "  i")
            (reg:SI VL_REGNUM)
            (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
!        (unspec:V_VLSI_S
!          [(match_operand:V_VLSI_S 1 "register_operand" " 0")
!           (match_operand:V_VLSI_S 2 "register_operand" "vr")] UNSPEC_CRYPTO_VV)
         (match_dup 1)))]
    "TARGET_ZVKNED || TARGET_ZVKSED || TARGET_ZVKG"
    "v<vv_ins_name>.<ins_type>\t%0,%2"
***************
*** 505,521 ****
     (set_attr "mode" "<MODE>")])
  
  (define_insn "@pred_crypto_vv<vv_ins_name><ins_type>x1<mode>_scalar"
!   [(set (match_operand:VSI 0 "register_operand"    "=&vr")
!      (if_then_else:VSI
         (unspec:<VM>
           [(match_operand 3 "vector_length_operand" "  rK")
            (match_operand 4 "const_int_operand"     "   i")
            (match_operand 5 "const_int_operand"     "   i")
            (reg:SI VL_REGNUM)
            (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
!        (unspec:VSI
!          [(match_operand:VSI 1 "register_operand" " 0")
!           (match_operand:VSI 2 "register_operand" "vr")] UNSPEC_CRYPTO_VV)
         (match_dup 1)))]
    "TARGET_ZVKNED || TARGET_ZVKSED"
    "v<vv_ins_name>.<ins_type>\t%0,%2"
--- 505,521 ----
     (set_attr "mode" "<MODE>")])
  
  (define_insn "@pred_crypto_vv<vv_ins_name><ins_type>x1<mode>_scalar"
!   [(set (match_operand:V_VLSI_S 0 "register_operand"    "=&vr")
!      (if_then_else:V_VLSI_S
         (unspec:<VM>
           [(match_operand 3 "vector_length_operand" "  rK")
            (match_operand 4 "const_int_operand"     "   i")
            (match_operand 5 "const_int_operand"     "   i")
            (reg:SI VL_REGNUM)
            (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
!        (unspec:V_VLSI_S
!          [(match_operand:V_VLSI_S 1 "register_operand" " 0")
!           (match_operand:V_VLSI_S 2 "register_operand" "vr")] UNSPEC_CRYPTO_VV)
         (match_dup 1)))]
    "TARGET_ZVKNED || TARGET_ZVKSED"
    "v<vv_ins_name>.<ins_type>\t%0,%2"
***************
*** 523,539 ****
     (set_attr "mode" "<MODE>")])
  
  (define_insn "@pred_crypto_vv<vv_ins_name><ins_type>x2<mode>_scalar"
!   [(set (match_operand:<VSIX2> 0 "register_operand" "=&vr")
!      (if_then_else:<VSIX2>
         (unspec:<VM>
           [(match_operand 3 "vector_length_operand"  "rK")
            (match_operand 4 "const_int_operand"      " i")
            (match_operand 5 "const_int_operand"      " i")
            (reg:SI VL_REGNUM)
            (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
!        (unspec:<VSIX2>
!          [(match_operand:<VSIX2> 1  "register_operand"   " 0")
!           (match_operand:VLMULX2_SI 2 "register_operand" "vr")] UNSPEC_CRYPTO_VV)
         (match_dup 1)))]
    "TARGET_ZVKNED || TARGET_ZVKSED"
    "v<vv_ins_name>.<ins_type>\t%0,%2"
--- 523,539 ----
     (set_attr "mode" "<MODE>")])
  
  (define_insn "@pred_crypto_vv<vv_ins_name><ins_type>x2<mode>_scalar"
!   [(set (match_operand:<V_VLSI_S_X2> 0 "register_operand" "=&vr")
!      (if_then_else:<V_VLSI_S_X2>
         (unspec:<VM>
           [(match_operand 3 "vector_length_operand"  "rK")
            (match_operand 4 "const_int_operand"      " i")
            (match_operand 5 "const_int_operand"      " i")
            (reg:SI VL_REGNUM)
            (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
!        (unspec:<V_VLSI_S_X2>
!          [(match_operand:<V_VLSI_S_X2> 1  "register_operand"   " 0")
!           (match_operand:V_VLSI_S_LMULX2 2 "register_operand" "vr")] UNSPEC_CRYPTO_VV)
         (match_dup 1)))]
    "TARGET_ZVKNED || TARGET_ZVKSED"
    "v<vv_ins_name>.<ins_type>\t%0,%2"
***************
*** 541,557 ****
     (set_attr "mode" "<MODE>")])
  
  (define_insn "@pred_crypto_vv<vv_ins_name><ins_type>x4<mode>_scalar"
!  [(set (match_operand:<VSIX4> 0 "register_operand"      "=&vr")
!     (if_then_else:<VSIX4>
        (unspec:<VM>
          [(match_operand 3 "vector_length_operand"       " rK")
           (match_operand 4 "const_int_operand"           "  i")
           (match_operand 5 "const_int_operand"           "  i")
           (reg:SI VL_REGNUM)
           (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
!        (unspec:<VSIX4>
!          [(match_operand:<VSIX4> 1 "register_operand"    " 0")
!           (match_operand:VLMULX4_SI 2 "register_operand" "vr")] UNSPEC_CRYPTO_VV)
         (match_dup 1)))]
   "TARGET_ZVKNED || TARGET_ZVKSED"
   "v<vv_ins_name>.<ins_type>\t%0,%2"
--- 541,557 ----
     (set_attr "mode" "<MODE>")])
  
  (define_insn "@pred_crypto_vv<vv_ins_name><ins_type>x4<mode>_scalar"
!  [(set (match_operand:<V_VLSI_S_X4> 0 "register_operand"      "=&vr")
!     (if_then_else:<V_VLSI_S_X4>
        (unspec:<VM>
          [(match_operand 3 "vector_length_operand"       " rK")
           (match_operand 4 "const_int_operand"           "  i")
           (match_operand 5 "const_int_operand"           "  i")
           (reg:SI VL_REGNUM)
           (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
!        (unspec:<V_VLSI_S_X4>
!          [(match_operand:<V_VLSI_S_X4> 1 "register_operand"    " 0")
!           (match_operand:V_VLSI_S_LMULX4 2 "register_operand" "vr")] UNSPEC_CRYPTO_VV)
         (match_dup 1)))]
   "TARGET_ZVKNED || TARGET_ZVKSED"
   "v<vv_ins_name>.<ins_type>\t%0,%2"
***************
*** 559,575 ****
    (set_attr "mode" "<MODE>")])
  
  (define_insn "@pred_crypto_vv<vv_ins_name><ins_type>x8<mode>_scalar"
!  [(set (match_operand:<VSIX8> 0 "register_operand"      "=&vr")
!     (if_then_else:<VSIX8>
        (unspec:<VM>
          [(match_operand 3 "vector_length_operand"       " rK")
           (match_operand 4 "const_int_operand"           "  i")
           (match_operand 5 "const_int_operand"           "  i")
           (reg:SI VL_REGNUM)
           (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
!       (unspec:<VSIX8>
!         [(match_operand:<VSIX8> 1 "register_operand"    "  0")
!          (match_operand:VLMULX8_SI 2 "register_operand" " vr")] UNSPEC_CRYPTO_VV)
        (match_dup 1)))]
   "TARGET_ZVKNED || TARGET_ZVKSED"
   "v<vv_ins_name>.<ins_type>\t%0,%2"
--- 559,575 ----
    (set_attr "mode" "<MODE>")])
  
  (define_insn "@pred_crypto_vv<vv_ins_name><ins_type>x8<mode>_scalar"
!  [(set (match_operand:<V_VLSI_S_X8> 0 "register_operand"      "=&vr")
!     (if_then_else:<V_VLSI_S_X8>
        (unspec:<VM>
          [(match_operand 3 "vector_length_operand"       " rK")
           (match_operand 4 "const_int_operand"           "  i")
           (match_operand 5 "const_int_operand"           "  i")
           (reg:SI VL_REGNUM)
           (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
!       (unspec:<V_VLSI_S_X8>
!         [(match_operand:<V_VLSI_S_X8> 1 "register_operand"    "  0")
!          (match_operand:V_VLSI_S_LMULX8 2 "register_operand" " vr")] UNSPEC_CRYPTO_VV)
        (match_dup 1)))]
   "TARGET_ZVKNED || TARGET_ZVKSED"
   "v<vv_ins_name>.<ins_type>\t%0,%2"
***************
*** 577,593 ****
    (set_attr "mode" "<MODE>")])
  
  (define_insn "@pred_crypto_vv<vv_ins_name><ins_type>x16<mode>_scalar"
!  [(set (match_operand:<VSIX16> 0 "register_operand"      "=&vr")
!     (if_then_else:<VSIX16>
        (unspec:<VM>
          [(match_operand 3 "vector_length_operand"        "  rK")
           (match_operand 4 "const_int_operand"            "   i")
           (match_operand 5 "const_int_operand"            "   i")
           (reg:SI VL_REGNUM)
           (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
!       (unspec:<VSIX16>
!         [(match_operand:<VSIX16> 1 "register_operand"    "   0")
!          (match_operand:VLMULX16_SI 2 "register_operand" "  vr")] UNSPEC_CRYPTO_VV)
        (match_dup 1)))]
   "TARGET_ZVKNED || TARGET_ZVKSED"
   "v<vv_ins_name>.<ins_type>\t%0,%2"
--- 577,593 ----
    (set_attr "mode" "<MODE>")])
  
  (define_insn "@pred_crypto_vv<vv_ins_name><ins_type>x16<mode>_scalar"
!  [(set (match_operand:<V_VLSI_S_X16> 0 "register_operand"      "=&vr")
!     (if_then_else:<V_VLSI_S_X16>
        (unspec:<VM>
          [(match_operand 3 "vector_length_operand"        "  rK")
           (match_operand 4 "const_int_operand"            "   i")
           (match_operand 5 "const_int_operand"            "   i")
           (reg:SI VL_REGNUM)
           (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
!       (unspec:<V_VLSI_S_X16>
!         [(match_operand:<V_VLSI_S_X16> 1 "register_operand"    "   0")
!          (match_operand:V_VLSI_S_LMULX16 2 "register_operand" "  vr")] UNSPEC_CRYPTO_VV)
        (match_dup 1)))]
   "TARGET_ZVKNED || TARGET_ZVKSED"
   "v<vv_ins_name>.<ins_type>\t%0,%2"
***************
*** 596,613 ****
  
  ;; vaeskf1.vi vsm4k.vi
  (define_insn "@pred_crypto_vi<vi_ins_name><mode>_scalar"
!   [(set (match_operand:VSI 0 "register_operand"        "=vr, vr")
!      (if_then_else:VSI
         (unspec:<VM>
           [(match_operand 4 "vector_length_operand"      "rK, rK")
            (match_operand 5 "const_int_operand"          " i,  i")
            (match_operand 6 "const_int_operand"          " i,  i")
            (reg:SI VL_REGNUM)
            (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
!        (unspec:VSI
!          [(match_operand:VSI 2       "register_operand" "vr, vr")
            (match_operand 3  "const_int_operand"         " i,  i")] UNSPEC_CRYPTO_VI)
!        (match_operand:VSI 1 "vector_merge_operand"      "vu,  0")))]
    "TARGET_ZVKNED || TARGET_ZVKSED"
    "v<vi_ins_name>.vi\t%0,%2,%3"
    [(set_attr "type" "v<vi_ins_name>")
--- 596,613 ----
  
  ;; vaeskf1.vi vsm4k.vi
  (define_insn "@pred_crypto_vi<vi_ins_name><mode>_scalar"
!   [(set (match_operand:V_VLSI_S 0 "register_operand"        "=vr, vr")
!      (if_then_else:V_VLSI_S
         (unspec:<VM>
           [(match_operand 4 "vector_length_operand"      "rK, rK")
            (match_operand 5 "const_int_operand"          " i,  i")
            (match_operand 6 "const_int_operand"          " i,  i")
            (reg:SI VL_REGNUM)
            (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
!        (unspec:V_VLSI_S
!          [(match_operand:V_VLSI_S 2       "register_operand" "vr, vr")
            (match_operand 3  "const_int_operand"         " i,  i")] UNSPEC_CRYPTO_VI)
!        (match_operand:V_VLSI_S 1 "vector_merge_operand"      "vu,  0")))]
    "TARGET_ZVKNED || TARGET_ZVKSED"
    "v<vi_ins_name>.vi\t%0,%2,%3"
    [(set_attr "type" "v<vi_ins_name>")
***************
*** 615,631 ****
  
  ;; vaeskf2.vi vsm3c.vi
  (define_insn "@pred_vi<vi_ins1_name><mode>_nomaskedoff_scalar"
!   [(set (match_operand:VSI 0 "register_operand"       "=vr")
!      (if_then_else:VSI
         (unspec:<VM>
           [(match_operand 4 "vector_length_operand"    "rK")
            (match_operand 5 "const_int_operand"        " i")
            (match_operand 6 "const_int_operand"        " i")
            (reg:SI VL_REGNUM)
            (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
!        (unspec:VSI
!           [(match_operand:VSI 1   "register_operand"  " 0")
!            (match_operand:VSI 2   "register_operand"  "vr")
             (match_operand 3 "const_int_operand" " i")] UNSPEC_CRYPTO_VI1)
         (match_dup 1)))]
    "TARGET_ZVKNED || TARGET_ZVKSH"
--- 615,631 ----
  
  ;; vaeskf2.vi vsm3c.vi
  (define_insn "@pred_vi<vi_ins1_name><mode>_nomaskedoff_scalar"
!   [(set (match_operand:V_VLSI_S 0 "register_operand"       "=vr")
!      (if_then_else:V_VLSI_S
         (unspec:<VM>
           [(match_operand 4 "vector_length_operand"    "rK")
            (match_operand 5 "const_int_operand"        " i")
            (match_operand 6 "const_int_operand"        " i")
            (reg:SI VL_REGNUM)
            (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
!        (unspec:V_VLSI_S
!           [(match_operand:V_VLSI_S 1   "register_operand"  " 0")
!            (match_operand:V_VLSI_S 2   "register_operand"  "vr")
             (match_operand 3 "const_int_operand" " i")] UNSPEC_CRYPTO_VI1)
         (match_dup 1)))]
    "TARGET_ZVKNED || TARGET_ZVKSH"
***************
*** 636,653 ****
  ;; zvksh instructions patterns.
  ;; vsm3me.vv
  (define_insn "@pred_vsm3me<mode>"
!   [(set (match_operand:VSI 0 "register_operand"    "=vr, vr")
!      (if_then_else:VSI
         (unspec:<VM>
           [(match_operand 4 "vector_length_operand" " rK, rK")
            (match_operand 5 "const_int_operand"     "  i,  i")
            (match_operand 6 "const_int_operand"     "  i,  i")
            (reg:SI VL_REGNUM)
            (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
!        (unspec:VSI
!           [(match_operand:VSI 2 "register_operand" " vr, vr")
!            (match_operand:VSI 3 "register_operand" " vr, vr")] UNSPEC_VSM3ME)
!        (match_operand:VSI 1 "vector_merge_operand" " vu, 0")))]
    "TARGET_ZVKSH"
    "vsm3me.vv\t%0,%2,%3"
    [(set_attr "type" "vsm3me")
--- 636,653 ----
  ;; zvksh instructions patterns.
  ;; vsm3me.vv
  (define_insn "@pred_vsm3me<mode>"
!   [(set (match_operand:V_VLSI_S 0 "register_operand"    "=vr, vr")
!      (if_then_else:V_VLSI_S
         (unspec:<VM>
           [(match_operand 4 "vector_length_operand" " rK, rK")
            (match_operand 5 "const_int_operand"     "  i,  i")
            (match_operand 6 "const_int_operand"     "  i,  i")
            (reg:SI VL_REGNUM)
            (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
!        (unspec:V_VLSI_S
!           [(match_operand:V_VLSI_S 2 "register_operand" " vr, vr")
!            (match_operand:V_VLSI_S 3 "register_operand" " vr, vr")] UNSPEC_VSM3ME)
!        (match_operand:V_VLSI_S 1 "vector_merge_operand" " vu, 0")))]
    "TARGET_ZVKSH"
    "vsm3me.vv\t%0,%2,%3"
    [(set_attr "type" "vsm3me")
diff -Nrcpad gcc-16-20251214/gcc/config/riscv/vector-iterators.md gcc-16-20251221/gcc/config/riscv/vector-iterators.md
*** gcc-16-20251214/gcc/config/riscv/vector-iterators.md	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/riscv/vector-iterators.md	Sun Dec 21 22:32:06 2025
***************
*** 121,126 ****
--- 121,130 ----
    UNSPEC_SF_VFNRCLIP
    UNSPEC_SF_VFNRCLIPU
    UNSPEC_SF_CV
+ 
+   ;; Vector conditional branch optabs
+   UNSPEC_COND_LEN_CMP_ALL
+   UNSPEC_COND_LEN_CMP_ANY
  ])
  
  (define_c_enum "unspecv" [
***************
*** 341,346 ****
--- 345,429 ----
  
    (RVVM8DF "TARGET_VECTOR_ELEN_FP_64") (RVVM4DF "TARGET_VECTOR_ELEN_FP_64")
    (RVVM2DF "TARGET_VECTOR_ELEN_FP_64") (RVVM1DF "TARGET_VECTOR_ELEN_FP_64")
+ 
+   (V1HI "riscv_vector::vls_mode_valid_p (V1HImode)")
+   (V2HI "riscv_vector::vls_mode_valid_p (V2HImode)")
+   (V4HI "riscv_vector::vls_mode_valid_p (V4HImode)")
+   (V8HI "riscv_vector::vls_mode_valid_p (V8HImode)")
+   (V16HI "riscv_vector::vls_mode_valid_p (V16HImode)")
+   (V32HI "riscv_vector::vls_mode_valid_p (V32HImode) && TARGET_MIN_VLEN >= 64")
+   (V64HI "riscv_vector::vls_mode_valid_p (V64HImode) && TARGET_MIN_VLEN >= 128")
+   (V128HI "riscv_vector::vls_mode_valid_p (V128HImode) && TARGET_MIN_VLEN >= 256")
+   (V256HI "riscv_vector::vls_mode_valid_p (V256HImode) && TARGET_MIN_VLEN >= 512")
+   (V512HI "riscv_vector::vls_mode_valid_p (V512HImode) && TARGET_MIN_VLEN >= 1024")
+   (V1024HI "riscv_vector::vls_mode_valid_p (V1024HImode) && TARGET_MIN_VLEN >= 2048")
+   (V1SI "riscv_vector::vls_mode_valid_p (V1SImode)")
+   (V2SI "riscv_vector::vls_mode_valid_p (V2SImode)")
+   (V4SI "riscv_vector::vls_mode_valid_p (V4SImode)")
+   (V8SI "riscv_vector::vls_mode_valid_p (V8SImode)")
+   (V16SI "riscv_vector::vls_mode_valid_p (V16SImode) && TARGET_MIN_VLEN >= 64")
+   (V32SI "riscv_vector::vls_mode_valid_p (V32SImode) && TARGET_MIN_VLEN >= 128")
+   (V64SI "riscv_vector::vls_mode_valid_p (V64SImode) && TARGET_MIN_VLEN >= 256")
+   (V128SI "riscv_vector::vls_mode_valid_p (V128SImode) && TARGET_MIN_VLEN >= 512")
+   (V256SI "riscv_vector::vls_mode_valid_p (V256SImode) && TARGET_MIN_VLEN >= 1024")
+   (V512SI "riscv_vector::vls_mode_valid_p (V512SImode) && TARGET_MIN_VLEN >= 2048")
+   (V1024SI "riscv_vector::vls_mode_valid_p (V1024SImode) && TARGET_MIN_VLEN >= 4096")
+   (V1DI "riscv_vector::vls_mode_valid_p (V1DImode) && TARGET_VECTOR_ELEN_64")
+   (V2DI "riscv_vector::vls_mode_valid_p (V2DImode) && TARGET_VECTOR_ELEN_64")
+   (V4DI "riscv_vector::vls_mode_valid_p (V4DImode) && TARGET_VECTOR_ELEN_64")
+   (V8DI "riscv_vector::vls_mode_valid_p (V8DImode) && TARGET_VECTOR_ELEN_64 && TARGET_MIN_VLEN >= 64")
+   (V16DI "riscv_vector::vls_mode_valid_p (V16DImode) && TARGET_VECTOR_ELEN_64 && TARGET_MIN_VLEN >= 128")
+   (V32DI "riscv_vector::vls_mode_valid_p (V32DImode) && TARGET_VECTOR_ELEN_64 && TARGET_MIN_VLEN >= 256")
+   (V64DI "riscv_vector::vls_mode_valid_p (V64DImode) && TARGET_VECTOR_ELEN_64 && TARGET_MIN_VLEN >= 512")
+   (V128DI "riscv_vector::vls_mode_valid_p (V128DImode) && TARGET_VECTOR_ELEN_64 && TARGET_MIN_VLEN >= 1024")
+   (V256DI "riscv_vector::vls_mode_valid_p (V256DImode) && TARGET_VECTOR_ELEN_64 && TARGET_MIN_VLEN >= 2048")
+   (V512DI "riscv_vector::vls_mode_valid_p (V512DImode) && TARGET_VECTOR_ELEN_64 && TARGET_MIN_VLEN >= 4096")
+ 
+   (V1HF "riscv_vector::vls_mode_valid_p (V1HFmode) && TARGET_VECTOR_ELEN_FP_16")
+   (V2HF "riscv_vector::vls_mode_valid_p (V2HFmode) && TARGET_VECTOR_ELEN_FP_16")
+   (V4HF "riscv_vector::vls_mode_valid_p (V4HFmode) && TARGET_VECTOR_ELEN_FP_16")
+   (V8HF "riscv_vector::vls_mode_valid_p (V8HFmode) && TARGET_VECTOR_ELEN_FP_16")
+   (V16HF "riscv_vector::vls_mode_valid_p (V16HFmode) && TARGET_VECTOR_ELEN_FP_16")
+   (V32HF "riscv_vector::vls_mode_valid_p (V32HFmode) && TARGET_VECTOR_ELEN_FP_16 && TARGET_MIN_VLEN >= 64")
+   (V64HF "riscv_vector::vls_mode_valid_p (V64HFmode) && TARGET_VECTOR_ELEN_FP_16 && TARGET_MIN_VLEN >= 128")
+   (V128HF "riscv_vector::vls_mode_valid_p (V128HFmode) && TARGET_VECTOR_ELEN_FP_16 && TARGET_MIN_VLEN >= 256")
+   (V256HF "riscv_vector::vls_mode_valid_p (V256HFmode) && TARGET_VECTOR_ELEN_FP_16 && TARGET_MIN_VLEN >= 512")
+   (V512HF "riscv_vector::vls_mode_valid_p (V512HFmode) && TARGET_VECTOR_ELEN_FP_16 && TARGET_MIN_VLEN >= 1024")
+   (V1024HF "riscv_vector::vls_mode_valid_p (V1024HFmode) && TARGET_VECTOR_ELEN_FP_16 && TARGET_MIN_VLEN >= 2048")
+   (V2048HF "riscv_vector::vls_mode_valid_p (V2048HFmode) && TARGET_VECTOR_ELEN_FP_16 && TARGET_MIN_VLEN >= 4096")
+   (V1BF "riscv_vector::vls_mode_valid_p (V1BFmode) && TARGET_VECTOR_ELEN_BF_16")
+   (V2BF "riscv_vector::vls_mode_valid_p (V2BFmode) && TARGET_VECTOR_ELEN_BF_16")
+   (V4BF "riscv_vector::vls_mode_valid_p (V4BFmode) && TARGET_VECTOR_ELEN_BF_16")
+   (V8BF "riscv_vector::vls_mode_valid_p (V8BFmode) && TARGET_VECTOR_ELEN_BF_16")
+   (V16BF "riscv_vector::vls_mode_valid_p (V16BFmode) && TARGET_VECTOR_ELEN_BF_16")
+   (V32BF "riscv_vector::vls_mode_valid_p (V32BFmode) && TARGET_VECTOR_ELEN_BF_16 && TARGET_MIN_VLEN >= 64")
+   (V64BF "riscv_vector::vls_mode_valid_p (V64BFmode) && TARGET_VECTOR_ELEN_BF_16 && TARGET_MIN_VLEN >= 128")
+   (V128BF "riscv_vector::vls_mode_valid_p (V128BFmode) && TARGET_VECTOR_ELEN_BF_16 && TARGET_MIN_VLEN >= 256")
+   (V256BF "riscv_vector::vls_mode_valid_p (V256BFmode) && TARGET_VECTOR_ELEN_BF_16 && TARGET_MIN_VLEN >= 512")
+   (V512BF "riscv_vector::vls_mode_valid_p (V512BFmode) && TARGET_VECTOR_ELEN_BF_16 && TARGET_MIN_VLEN >= 1024")
+   (V1024BF "riscv_vector::vls_mode_valid_p (V1024BFmode) && TARGET_VECTOR_ELEN_BF_16 && TARGET_MIN_VLEN >= 2048")
+   (V2048BF "riscv_vector::vls_mode_valid_p (V2048BFmode) && TARGET_VECTOR_ELEN_BF_16 && TARGET_MIN_VLEN >= 4096")
+   (V1SF "riscv_vector::vls_mode_valid_p (V1SFmode) && TARGET_VECTOR_ELEN_FP_32")
+   (V2SF "riscv_vector::vls_mode_valid_p (V2SFmode) && TARGET_VECTOR_ELEN_FP_32")
+   (V4SF "riscv_vector::vls_mode_valid_p (V4SFmode) && TARGET_VECTOR_ELEN_FP_32")
+   (V8SF "riscv_vector::vls_mode_valid_p (V8SFmode) && TARGET_VECTOR_ELEN_FP_32")
+   (V16SF "riscv_vector::vls_mode_valid_p (V16SFmode) && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 64")
+   (V32SF "riscv_vector::vls_mode_valid_p (V32SFmode) && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 128")
+   (V64SF "riscv_vector::vls_mode_valid_p (V64SFmode) && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 256")
+   (V128SF "riscv_vector::vls_mode_valid_p (V128SFmode) && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 512")
+   (V256SF "riscv_vector::vls_mode_valid_p (V256SFmode) && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 1024")
+   (V512SF "riscv_vector::vls_mode_valid_p (V512SFmode) && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 2048")
+   (V1024SF "riscv_vector::vls_mode_valid_p (V1024SFmode) && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 4096")
+   (V1DF "riscv_vector::vls_mode_valid_p (V1DFmode) && TARGET_VECTOR_ELEN_FP_64")
+   (V2DF "riscv_vector::vls_mode_valid_p (V2DFmode) && TARGET_VECTOR_ELEN_FP_64")
+   (V4DF "riscv_vector::vls_mode_valid_p (V4DFmode) && TARGET_VECTOR_ELEN_FP_64")
+   (V8DF "riscv_vector::vls_mode_valid_p (V8DFmode) && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 64")
+   (V16DF "riscv_vector::vls_mode_valid_p (V16DFmode) && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 128")
+   (V32DF "riscv_vector::vls_mode_valid_p (V32DFmode) && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 256")
+   (V64DF "riscv_vector::vls_mode_valid_p (V64DFmode) && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 512")
+   (V128DF "riscv_vector::vls_mode_valid_p (V128DFmode) && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 1024")
+   (V256DF "riscv_vector::vls_mode_valid_p (V256DFmode) && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 2048")
+   (V512DF "riscv_vector::vls_mode_valid_p (V512DFmode) && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 4096")
  ])
  
  (define_mode_iterator VEEWEXT4 [
***************
*** 354,359 ****
--- 437,486 ----
  
    (RVVM8DF "TARGET_VECTOR_ELEN_FP_64") (RVVM4DF "TARGET_VECTOR_ELEN_FP_64")
    (RVVM2DF "TARGET_VECTOR_ELEN_FP_64") (RVVM1DF "TARGET_VECTOR_ELEN_FP_64")
+ 
+   (V1SI "riscv_vector::vls_mode_valid_p (V1SImode)")
+   (V2SI "riscv_vector::vls_mode_valid_p (V2SImode)")
+   (V4SI "riscv_vector::vls_mode_valid_p (V4SImode)")
+   (V8SI "riscv_vector::vls_mode_valid_p (V8SImode)")
+   (V16SI "riscv_vector::vls_mode_valid_p (V16SImode) && TARGET_MIN_VLEN >= 64")
+   (V32SI "riscv_vector::vls_mode_valid_p (V32SImode) && TARGET_MIN_VLEN >= 128")
+   (V64SI "riscv_vector::vls_mode_valid_p (V64SImode) && TARGET_MIN_VLEN >= 256")
+   (V128SI "riscv_vector::vls_mode_valid_p (V128SImode) && TARGET_MIN_VLEN >= 512")
+   (V256SI "riscv_vector::vls_mode_valid_p (V256SImode) && TARGET_MIN_VLEN >= 1024")
+   (V512SI "riscv_vector::vls_mode_valid_p (V512SImode) && TARGET_MIN_VLEN >= 2048")
+   (V1024SI "riscv_vector::vls_mode_valid_p (V1024SImode) && TARGET_MIN_VLEN >= 4096")
+   (V1DI "riscv_vector::vls_mode_valid_p (V1DImode) && TARGET_VECTOR_ELEN_64")
+   (V2DI "riscv_vector::vls_mode_valid_p (V2DImode) && TARGET_VECTOR_ELEN_64")
+   (V4DI "riscv_vector::vls_mode_valid_p (V4DImode) && TARGET_VECTOR_ELEN_64")
+   (V8DI "riscv_vector::vls_mode_valid_p (V8DImode) && TARGET_VECTOR_ELEN_64 && TARGET_MIN_VLEN >= 64")
+   (V16DI "riscv_vector::vls_mode_valid_p (V16DImode) && TARGET_VECTOR_ELEN_64 && TARGET_MIN_VLEN >= 128")
+   (V32DI "riscv_vector::vls_mode_valid_p (V32DImode) && TARGET_VECTOR_ELEN_64 && TARGET_MIN_VLEN >= 256")
+   (V64DI "riscv_vector::vls_mode_valid_p (V64DImode) && TARGET_VECTOR_ELEN_64 && TARGET_MIN_VLEN >= 512")
+   (V128DI "riscv_vector::vls_mode_valid_p (V128DImode) && TARGET_VECTOR_ELEN_64 && TARGET_MIN_VLEN >= 1024")
+   (V256DI "riscv_vector::vls_mode_valid_p (V256DImode) && TARGET_VECTOR_ELEN_64 && TARGET_MIN_VLEN >= 2048")
+   (V512DI "riscv_vector::vls_mode_valid_p (V512DImode) && TARGET_VECTOR_ELEN_64 && TARGET_MIN_VLEN >= 4096")
+ 
+   (V1SF "riscv_vector::vls_mode_valid_p (V1SFmode) && TARGET_VECTOR_ELEN_FP_32")
+   (V2SF "riscv_vector::vls_mode_valid_p (V2SFmode) && TARGET_VECTOR_ELEN_FP_32")
+   (V4SF "riscv_vector::vls_mode_valid_p (V4SFmode) && TARGET_VECTOR_ELEN_FP_32")
+   (V8SF "riscv_vector::vls_mode_valid_p (V8SFmode) && TARGET_VECTOR_ELEN_FP_32")
+   (V16SF "riscv_vector::vls_mode_valid_p (V16SFmode) && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 64")
+   (V32SF "riscv_vector::vls_mode_valid_p (V32SFmode) && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 128")
+   (V64SF "riscv_vector::vls_mode_valid_p (V64SFmode) && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 256")
+   (V128SF "riscv_vector::vls_mode_valid_p (V128SFmode) && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 512")
+   (V256SF "riscv_vector::vls_mode_valid_p (V256SFmode) && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 1024")
+   (V512SF "riscv_vector::vls_mode_valid_p (V512SFmode) && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 2048")
+   (V1024SF "riscv_vector::vls_mode_valid_p (V1024SFmode) && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 4096")
+   (V1DF "riscv_vector::vls_mode_valid_p (V1DFmode) && TARGET_VECTOR_ELEN_FP_64")
+   (V2DF "riscv_vector::vls_mode_valid_p (V2DFmode) && TARGET_VECTOR_ELEN_FP_64")
+   (V4DF "riscv_vector::vls_mode_valid_p (V4DFmode) && TARGET_VECTOR_ELEN_FP_64")
+   (V8DF "riscv_vector::vls_mode_valid_p (V8DFmode) && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 64")
+   (V16DF "riscv_vector::vls_mode_valid_p (V16DFmode) && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 128")
+   (V32DF "riscv_vector::vls_mode_valid_p (V32DFmode) && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 256")
+   (V64DF "riscv_vector::vls_mode_valid_p (V64DFmode) && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 512")
+   (V128DF "riscv_vector::vls_mode_valid_p (V128DFmode) && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 1024")
+   (V256DF "riscv_vector::vls_mode_valid_p (V256DFmode) && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 2048")
+   (V512DF "riscv_vector::vls_mode_valid_p (V512DFmode) && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 4096")
  ])
  
  (define_mode_iterator VEEWEXT8 [
***************
*** 362,367 ****
--- 489,516 ----
  
    (RVVM8DF "TARGET_VECTOR_ELEN_FP_64") (RVVM4DF "TARGET_VECTOR_ELEN_FP_64")
    (RVVM2DF "TARGET_VECTOR_ELEN_FP_64") (RVVM1DF "TARGET_VECTOR_ELEN_FP_64")
+ 
+   (V1DI "riscv_vector::vls_mode_valid_p (V1DImode) && TARGET_VECTOR_ELEN_64")
+   (V2DI "riscv_vector::vls_mode_valid_p (V2DImode) && TARGET_VECTOR_ELEN_64")
+   (V4DI "riscv_vector::vls_mode_valid_p (V4DImode) && TARGET_VECTOR_ELEN_64")
+   (V8DI "riscv_vector::vls_mode_valid_p (V8DImode) && TARGET_VECTOR_ELEN_64 && TARGET_MIN_VLEN >= 64")
+   (V16DI "riscv_vector::vls_mode_valid_p (V16DImode) && TARGET_VECTOR_ELEN_64 && TARGET_MIN_VLEN >= 128")
+   (V32DI "riscv_vector::vls_mode_valid_p (V32DImode) && TARGET_VECTOR_ELEN_64 && TARGET_MIN_VLEN >= 256")
+   (V64DI "riscv_vector::vls_mode_valid_p (V64DImode) && TARGET_VECTOR_ELEN_64 && TARGET_MIN_VLEN >= 512")
+   (V128DI "riscv_vector::vls_mode_valid_p (V128DImode) && TARGET_VECTOR_ELEN_64 && TARGET_MIN_VLEN >= 1024")
+   (V256DI "riscv_vector::vls_mode_valid_p (V256DImode) && TARGET_VECTOR_ELEN_64 && TARGET_MIN_VLEN >= 2048")
+   (V512DI "riscv_vector::vls_mode_valid_p (V512DImode) && TARGET_VECTOR_ELEN_64 && TARGET_MIN_VLEN >= 4096")
+ 
+   (V1DF "riscv_vector::vls_mode_valid_p (V1DFmode) && TARGET_VECTOR_ELEN_FP_64")
+   (V2DF "riscv_vector::vls_mode_valid_p (V2DFmode) && TARGET_VECTOR_ELEN_FP_64")
+   (V4DF "riscv_vector::vls_mode_valid_p (V4DFmode) && TARGET_VECTOR_ELEN_FP_64")
+   (V8DF "riscv_vector::vls_mode_valid_p (V8DFmode) && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 64")
+   (V16DF "riscv_vector::vls_mode_valid_p (V16DFmode) && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 128")
+   (V32DF "riscv_vector::vls_mode_valid_p (V32DFmode) && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 256")
+   (V64DF "riscv_vector::vls_mode_valid_p (V64DFmode) && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 512")
+   (V128DF "riscv_vector::vls_mode_valid_p (V128DFmode) && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 1024")
+   (V256DF "riscv_vector::vls_mode_valid_p (V256DFmode) && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 2048")
+   (V512DF "riscv_vector::vls_mode_valid_p (V512DFmode) && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 4096")
  ])
  
  (define_mode_iterator VEEWTRUNC2 [
***************
*** 386,391 ****
--- 535,607 ----
    (RVVM2SF "TARGET_VECTOR_ELEN_FP_32 && TARGET_64BIT")
    (RVVM1SF "TARGET_VECTOR_ELEN_FP_32 && TARGET_64BIT")
    (RVVMF2SF "TARGET_VECTOR_ELEN_FP_32 && TARGET_VECTOR_ELEN_64 && TARGET_64BIT")
+ 
+   (V1QI "riscv_vector::vls_mode_valid_p (V1QImode)")
+   (V2QI "riscv_vector::vls_mode_valid_p (V2QImode)")
+   (V4QI "riscv_vector::vls_mode_valid_p (V4QImode)")
+   (V8QI "riscv_vector::vls_mode_valid_p (V8QImode)")
+   (V16QI "riscv_vector::vls_mode_valid_p (V16QImode)")
+   (V32QI "riscv_vector::vls_mode_valid_p (V32QImode) && TARGET_MIN_VLEN >= 64")
+   (V64QI "riscv_vector::vls_mode_valid_p (V64QImode) && TARGET_MIN_VLEN >= 128")
+   (V128QI "riscv_vector::vls_mode_valid_p (V128QImode) && TARGET_MIN_VLEN >= 256")
+   (V256QI "riscv_vector::vls_mode_valid_p (V256QImode) && TARGET_MIN_VLEN >= 512")
+   (V512QI "riscv_vector::vls_mode_valid_p (V512QImode) && TARGET_MIN_VLEN >= 1024")
+   (V1024QI "riscv_vector::vls_mode_valid_p (V1024QImode) && TARGET_MIN_VLEN >= 2048")
+   (V2048QI "riscv_vector::vls_mode_valid_p (V1024QImode) && TARGET_MIN_VLEN >= 2048")
+   (V1HI "riscv_vector::vls_mode_valid_p (V1HImode)")
+   (V2HI "riscv_vector::vls_mode_valid_p (V2HImode)")
+   (V4HI "riscv_vector::vls_mode_valid_p (V4HImode)")
+   (V8HI "riscv_vector::vls_mode_valid_p (V8HImode)")
+   (V16HI "riscv_vector::vls_mode_valid_p (V16HImode)")
+   (V32HI "riscv_vector::vls_mode_valid_p (V32HImode) && TARGET_MIN_VLEN >= 64")
+   (V64HI "riscv_vector::vls_mode_valid_p (V64HImode) && TARGET_MIN_VLEN >= 128")
+   (V128HI "riscv_vector::vls_mode_valid_p (V128HImode) && TARGET_MIN_VLEN >= 256")
+   (V256HI "riscv_vector::vls_mode_valid_p (V256HImode) && TARGET_MIN_VLEN >= 512")
+   (V512HI "riscv_vector::vls_mode_valid_p (V512HImode) && TARGET_MIN_VLEN >= 1024")
+   (V1024HI "riscv_vector::vls_mode_valid_p (V1024HImode) && TARGET_MIN_VLEN >= 2048")
+   (V1SI "riscv_vector::vls_mode_valid_p (V1SImode)")
+   (V2SI "riscv_vector::vls_mode_valid_p (V2SImode)")
+   (V4SI "riscv_vector::vls_mode_valid_p (V4SImode)")
+   (V8SI "riscv_vector::vls_mode_valid_p (V8SImode)")
+   (V16SI "riscv_vector::vls_mode_valid_p (V16SImode) && TARGET_MIN_VLEN >= 64")
+   (V32SI "riscv_vector::vls_mode_valid_p (V32SImode) && TARGET_MIN_VLEN >= 128")
+   (V64SI "riscv_vector::vls_mode_valid_p (V64SImode) && TARGET_MIN_VLEN >= 256")
+   (V128SI "riscv_vector::vls_mode_valid_p (V128SImode) && TARGET_MIN_VLEN >= 512")
+   (V256SI "riscv_vector::vls_mode_valid_p (V256SImode) && TARGET_MIN_VLEN >= 1024")
+   (V512SI "riscv_vector::vls_mode_valid_p (V512SImode) && TARGET_MIN_VLEN >= 2048")
+ 
+   (V1HF "riscv_vector::vls_mode_valid_p (V1HFmode) && TARGET_VECTOR_ELEN_FP_16")
+   (V2HF "riscv_vector::vls_mode_valid_p (V2HFmode) && TARGET_VECTOR_ELEN_FP_16")
+   (V4HF "riscv_vector::vls_mode_valid_p (V4HFmode) && TARGET_VECTOR_ELEN_FP_16")
+   (V8HF "riscv_vector::vls_mode_valid_p (V8HFmode) && TARGET_VECTOR_ELEN_FP_16")
+   (V16HF "riscv_vector::vls_mode_valid_p (V16HFmode) && TARGET_VECTOR_ELEN_FP_16")
+   (V32HF "riscv_vector::vls_mode_valid_p (V32HFmode) && TARGET_VECTOR_ELEN_FP_16 && TARGET_MIN_VLEN >= 64")
+   (V64HF "riscv_vector::vls_mode_valid_p (V64HFmode) && TARGET_VECTOR_ELEN_FP_16 && TARGET_MIN_VLEN >= 128")
+   (V128HF "riscv_vector::vls_mode_valid_p (V128HFmode) && TARGET_VECTOR_ELEN_FP_16 && TARGET_MIN_VLEN >= 256")
+   (V256HF "riscv_vector::vls_mode_valid_p (V256HFmode) && TARGET_VECTOR_ELEN_FP_16 && TARGET_MIN_VLEN >= 512")
+   (V512HF "riscv_vector::vls_mode_valid_p (V512HFmode) && TARGET_VECTOR_ELEN_FP_16 && TARGET_MIN_VLEN >= 1024")
+   (V1024HF "riscv_vector::vls_mode_valid_p (V1024HFmode) && TARGET_VECTOR_ELEN_FP_16 && TARGET_MIN_VLEN >= 2048")
+   (V1BF "riscv_vector::vls_mode_valid_p (V1BFmode) && TARGET_VECTOR_ELEN_BF_16")
+   (V2BF "riscv_vector::vls_mode_valid_p (V2BFmode) && TARGET_VECTOR_ELEN_BF_16")
+   (V4BF "riscv_vector::vls_mode_valid_p (V4BFmode) && TARGET_VECTOR_ELEN_BF_16")
+   (V8BF "riscv_vector::vls_mode_valid_p (V8BFmode) && TARGET_VECTOR_ELEN_BF_16")
+   (V16BF "riscv_vector::vls_mode_valid_p (V16BFmode) && TARGET_VECTOR_ELEN_BF_16")
+   (V32BF "riscv_vector::vls_mode_valid_p (V32BFmode) && TARGET_VECTOR_ELEN_BF_16 && TARGET_MIN_VLEN >= 64")
+   (V64BF "riscv_vector::vls_mode_valid_p (V64BFmode) && TARGET_VECTOR_ELEN_BF_16 && TARGET_MIN_VLEN >= 128")
+   (V128BF "riscv_vector::vls_mode_valid_p (V128BFmode) && TARGET_VECTOR_ELEN_BF_16 && TARGET_MIN_VLEN >= 256")
+   (V256BF "riscv_vector::vls_mode_valid_p (V256BFmode) && TARGET_VECTOR_ELEN_BF_16 && TARGET_MIN_VLEN >= 512")
+   (V512BF "riscv_vector::vls_mode_valid_p (V512BFmode) && TARGET_VECTOR_ELEN_BF_16 && TARGET_MIN_VLEN >= 1024")
+   (V1024BF "riscv_vector::vls_mode_valid_p (V1024BFmode) && TARGET_VECTOR_ELEN_BF_16 && TARGET_MIN_VLEN >= 2048")
+   (V1SF "riscv_vector::vls_mode_valid_p (V1SFmode) && TARGET_VECTOR_ELEN_FP_32")
+   (V2SF "riscv_vector::vls_mode_valid_p (V2SFmode) && TARGET_VECTOR_ELEN_FP_32")
+   (V4SF "riscv_vector::vls_mode_valid_p (V4SFmode) && TARGET_VECTOR_ELEN_FP_32")
+   (V8SF "riscv_vector::vls_mode_valid_p (V8SFmode) && TARGET_VECTOR_ELEN_FP_32")
+   (V16SF "riscv_vector::vls_mode_valid_p (V16SFmode) && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 64")
+   (V32SF "riscv_vector::vls_mode_valid_p (V32SFmode) && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 128")
+   (V64SF "riscv_vector::vls_mode_valid_p (V64SFmode) && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 256")
+   (V128SF "riscv_vector::vls_mode_valid_p (V128SFmode) && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 512")
+   (V256SF "riscv_vector::vls_mode_valid_p (V256SFmode) && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 1024")
+   (V512SF "riscv_vector::vls_mode_valid_p (V512SFmode) && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 2048")
  ])
  
  (define_mode_iterator VEEWTRUNC4 [
***************
*** 405,410 ****
--- 621,669 ----
    (RVVM1HF "TARGET_VECTOR_ELEN_FP_16 && TARGET_64BIT")
    (RVVMF2HF "TARGET_VECTOR_ELEN_FP_16 && TARGET_64BIT")
    (RVVMF4HF "TARGET_VECTOR_ELEN_FP_16 && TARGET_VECTOR_ELEN_64 && TARGET_64BIT")
+ 
+   (V1QI "riscv_vector::vls_mode_valid_p (V1QImode)")
+   (V2QI "riscv_vector::vls_mode_valid_p (V2QImode)")
+   (V4QI "riscv_vector::vls_mode_valid_p (V4QImode)")
+   (V8QI "riscv_vector::vls_mode_valid_p (V8QImode)")
+   (V16QI "riscv_vector::vls_mode_valid_p (V16QImode)")
+   (V32QI "riscv_vector::vls_mode_valid_p (V32QImode) && TARGET_MIN_VLEN >= 64")
+   (V64QI "riscv_vector::vls_mode_valid_p (V64QImode) && TARGET_MIN_VLEN >= 128")
+   (V128QI "riscv_vector::vls_mode_valid_p (V128QImode) && TARGET_MIN_VLEN >= 256")
+   (V256QI "riscv_vector::vls_mode_valid_p (V256QImode) && TARGET_MIN_VLEN >= 512")
+   (V512QI "riscv_vector::vls_mode_valid_p (V512QImode) && TARGET_MIN_VLEN >= 1024")
+   (V1024QI "riscv_vector::vls_mode_valid_p (V1024QImode) && TARGET_MIN_VLEN >= 2048")
+   (V1HI "riscv_vector::vls_mode_valid_p (V1HImode)")
+   (V2HI "riscv_vector::vls_mode_valid_p (V2HImode)")
+   (V4HI "riscv_vector::vls_mode_valid_p (V4HImode)")
+   (V8HI "riscv_vector::vls_mode_valid_p (V8HImode)")
+   (V16HI "riscv_vector::vls_mode_valid_p (V16HImode)")
+   (V32HI "riscv_vector::vls_mode_valid_p (V32HImode) && TARGET_MIN_VLEN >= 64")
+   (V64HI "riscv_vector::vls_mode_valid_p (V64HImode) && TARGET_MIN_VLEN >= 128")
+   (V128HI "riscv_vector::vls_mode_valid_p (V128HImode) && TARGET_MIN_VLEN >= 256")
+   (V256HI "riscv_vector::vls_mode_valid_p (V256HImode) && TARGET_MIN_VLEN >= 512")
+   (V512HI "riscv_vector::vls_mode_valid_p (V512HImode) && TARGET_MIN_VLEN >= 1024")
+ 
+   (V1HF "riscv_vector::vls_mode_valid_p (V1HFmode) && TARGET_VECTOR_ELEN_FP_16")
+   (V2HF "riscv_vector::vls_mode_valid_p (V2HFmode) && TARGET_VECTOR_ELEN_FP_16")
+   (V4HF "riscv_vector::vls_mode_valid_p (V4HFmode) && TARGET_VECTOR_ELEN_FP_16")
+   (V8HF "riscv_vector::vls_mode_valid_p (V8HFmode) && TARGET_VECTOR_ELEN_FP_16")
+   (V16HF "riscv_vector::vls_mode_valid_p (V16HFmode) && TARGET_VECTOR_ELEN_FP_16")
+   (V32HF "riscv_vector::vls_mode_valid_p (V32HFmode) && TARGET_VECTOR_ELEN_FP_16 && TARGET_MIN_VLEN >= 64")
+   (V64HF "riscv_vector::vls_mode_valid_p (V64HFmode) && TARGET_VECTOR_ELEN_FP_16 && TARGET_MIN_VLEN >= 128")
+   (V128HF "riscv_vector::vls_mode_valid_p (V128HFmode) && TARGET_VECTOR_ELEN_FP_16 && TARGET_MIN_VLEN >= 256")
+   (V256HF "riscv_vector::vls_mode_valid_p (V256HFmode) && TARGET_VECTOR_ELEN_FP_16 && TARGET_MIN_VLEN >= 512")
+   (V512HF "riscv_vector::vls_mode_valid_p (V512HFmode) && TARGET_VECTOR_ELEN_FP_16 && TARGET_MIN_VLEN >= 1024")
+   (V1BF "riscv_vector::vls_mode_valid_p (V1BFmode) && TARGET_VECTOR_ELEN_BF_16")
+   (V2BF "riscv_vector::vls_mode_valid_p (V2BFmode) && TARGET_VECTOR_ELEN_BF_16")
+   (V4BF "riscv_vector::vls_mode_valid_p (V4BFmode) && TARGET_VECTOR_ELEN_BF_16")
+   (V8BF "riscv_vector::vls_mode_valid_p (V8BFmode) && TARGET_VECTOR_ELEN_BF_16")
+   (V16BF "riscv_vector::vls_mode_valid_p (V16BFmode) && TARGET_VECTOR_ELEN_BF_16")
+   (V32BF "riscv_vector::vls_mode_valid_p (V32BFmode) && TARGET_VECTOR_ELEN_BF_16 && TARGET_MIN_VLEN >= 64")
+   (V64BF "riscv_vector::vls_mode_valid_p (V64BFmode) && TARGET_VECTOR_ELEN_BF_16 && TARGET_MIN_VLEN >= 128")
+   (V128BF "riscv_vector::vls_mode_valid_p (V128BFmode) && TARGET_VECTOR_ELEN_BF_16 && TARGET_MIN_VLEN >= 256")
+   (V256BF "riscv_vector::vls_mode_valid_p (V256BFmode) && TARGET_VECTOR_ELEN_BF_16 && TARGET_MIN_VLEN >= 512")
+   (V512BF "riscv_vector::vls_mode_valid_p (V512BFmode) && TARGET_VECTOR_ELEN_BF_16 && TARGET_MIN_VLEN >= 1024")
  ])
  
  (define_mode_iterator VEEWTRUNC8 [
***************
*** 412,417 ****
--- 671,687 ----
    (RVVMF2QI "TARGET_64BIT")
    (RVVMF4QI "TARGET_64BIT")
    (RVVMF8QI "TARGET_VECTOR_ELEN_64 && TARGET_64BIT")
+ 
+   (V1QI "riscv_vector::vls_mode_valid_p (V1QImode)")
+   (V2QI "riscv_vector::vls_mode_valid_p (V2QImode)")
+   (V4QI "riscv_vector::vls_mode_valid_p (V4QImode)")
+   (V8QI "riscv_vector::vls_mode_valid_p (V8QImode)")
+   (V16QI "riscv_vector::vls_mode_valid_p (V16QImode)")
+   (V32QI "riscv_vector::vls_mode_valid_p (V32QImode) && TARGET_MIN_VLEN >= 64")
+   (V64QI "riscv_vector::vls_mode_valid_p (V64QImode) && TARGET_MIN_VLEN >= 128")
+   (V128QI "riscv_vector::vls_mode_valid_p (V128QImode) && TARGET_MIN_VLEN >= 256")
+   (V256QI "riscv_vector::vls_mode_valid_p (V256QImode) && TARGET_MIN_VLEN >= 512")
+   (V512QI "riscv_vector::vls_mode_valid_p (V512QImode) && TARGET_MIN_VLEN >= 1024")
  ])
  
  (define_mode_iterator VEI16 [
***************
*** 575,580 ****
--- 845,876 ----
    RVVM8QI RVVM4QI RVVM2QI RVVM1QI RVVMF2QI RVVMF4QI (RVVMF8QI "TARGET_VECTOR_ELEN_64")
  
    RVVM8HI RVVM4HI RVVM2HI RVVM1HI RVVMF2HI (RVVMF4HI "TARGET_VECTOR_ELEN_64")
+ 
+   (V1QI "riscv_vector::vls_mode_valid_p (V1QImode)")
+   (V2QI "riscv_vector::vls_mode_valid_p (V2QImode)")
+   (V4QI "riscv_vector::vls_mode_valid_p (V4QImode)")
+   (V8QI "riscv_vector::vls_mode_valid_p (V8QImode)")
+   (V16QI "riscv_vector::vls_mode_valid_p (V16QImode)")
+   (V32QI "riscv_vector::vls_mode_valid_p (V32QImode)")
+   (V64QI "riscv_vector::vls_mode_valid_p (V64QImode) && TARGET_MIN_VLEN >= 64")
+   (V128QI "riscv_vector::vls_mode_valid_p (V128QImode) && TARGET_MIN_VLEN >= 128")
+   (V256QI "riscv_vector::vls_mode_valid_p (V256QImode) && TARGET_MIN_VLEN >= 256")
+   (V512QI "riscv_vector::vls_mode_valid_p (V512QImode) && TARGET_MIN_VLEN >= 512")
+   (V1024QI "riscv_vector::vls_mode_valid_p (V1024QImode) && TARGET_MIN_VLEN >= 1024")
+   (V2048QI "riscv_vector::vls_mode_valid_p (V2048QImode) && TARGET_MIN_VLEN >= 2048")
+   (V4096QI "riscv_vector::vls_mode_valid_p (V4096QImode) && TARGET_MIN_VLEN >= 4096")
+   (V1HI "riscv_vector::vls_mode_valid_p (V1HImode)")
+   (V2HI "riscv_vector::vls_mode_valid_p (V2HImode)")
+   (V4HI "riscv_vector::vls_mode_valid_p (V4HImode)")
+   (V8HI "riscv_vector::vls_mode_valid_p (V8HImode)")
+   (V16HI "riscv_vector::vls_mode_valid_p (V16HImode)")
+   (V32HI "riscv_vector::vls_mode_valid_p (V32HImode) && TARGET_MIN_VLEN >= 64")
+   (V64HI "riscv_vector::vls_mode_valid_p (V64HImode) && TARGET_MIN_VLEN >= 128")
+   (V128HI "riscv_vector::vls_mode_valid_p (V128HImode) && TARGET_MIN_VLEN >= 256")
+   (V256HI "riscv_vector::vls_mode_valid_p (V256HImode) && TARGET_MIN_VLEN >= 512")
+   (V512HI "riscv_vector::vls_mode_valid_p (V512HImode) && TARGET_MIN_VLEN >= 1024")
+   (V1024HI "riscv_vector::vls_mode_valid_p (V1024HImode) && TARGET_MIN_VLEN >= 2048")
+   (V2048HI "riscv_vector::vls_mode_valid_p (V2048HImode) && TARGET_MIN_VLEN >= 4096")
  ])
  
  (define_mode_iterator VI_QHS [
***************
*** 1920,1925 ****
--- 2216,2332 ----
    (V512DF "V512DI")
  ])
  
+ (define_mode_attr vindex [
+   (RVVM8QI "rvvm8qi") (RVVM4QI "rvvm4qi") (RVVM2QI "rvvm2qi") (RVVM1QI "rvvm1qi")
+   (RVVMF2QI "rvvmf2qi") (RVVMF4QI "rvvmf4qi") (RVVMF8QI "rvvmf8qi")
+ 
+   (RVVM8HI "rvvm8hi") (RVVM4HI "rvvm4hi") (RVVM2HI "rvvm2hi") (RVVM1HI "rvvm1hi") (RVVMF2HI "rvvmf2hi") (RVVMF4HI "rvvmf4hi")
+ 
+   (RVVM8BF "rvvm8hi") (RVVM4BF "rvvm4hi") (RVVM2BF "rvvm2hi") (RVVM1BF "rvvm1hi") (RVVMF2BF "rvvmf2hi") (RVVMF4BF "rvvmf4hi")
+ 
+   (RVVM8HF "rvvm8hi") (RVVM4HF "rvvm4hi") (RVVM2HF "rvvm2hi") (RVVM1HF "rvvm1hi") (RVVMF2HF "rvvmf2hi") (RVVMF4HF "rvvmf4hi")
+ 
+   (RVVM8SI "rvvm8si") (RVVM4SI "rvvm4si") (RVVM2SI "rvvm2si") (RVVM1SI "rvvm1si") (RVVMF2SI "rvvmf2si")
+ 
+   (RVVM8SF "rvvm8si") (RVVM4SF "rvvm4si") (RVVM2SF "rvvm2si") (RVVM1SF "rvvm1si") (RVVMF2SF "rvvmf2si")
+ 
+   (RVVM8DI "rvvm8di") (RVVM4DI "rvvm4di") (RVVM2DI "rvvm2di") (RVVM1DI "rvvm1di")
+ 
+   (RVVM8DF "rvvm8di") (RVVM4DF "rvvm4di") (RVVM2DF "rvvm2di") (RVVM1DF "rvvm1di")
+ 
+   (V1QI "v1qi")
+   (V2QI "v2qi")
+   (V4QI "v4qi")
+   (V8QI "v8qi")
+   (V16QI "v16qi")
+   (V32QI "v32qi")
+   (V64QI "v64qi")
+   (V128QI "v128qi")
+   (V256QI "v256qi")
+   (V512QI "v512qi")
+   (V1024QI "v1024qi")
+   (V2048QI "v2048qi")
+   (V4096QI "v4096qi")
+   (V1HI "v1hi")
+   (V2HI "v2hi")
+   (V4HI "v4hi")
+   (V8HI "v8hi")
+   (V16HI "v16hi")
+   (V32HI "v32hi")
+   (V64HI "v64hi")
+   (V128HI "v128hi")
+   (V256HI "v256hi")
+   (V512HI "v512hi")
+   (V1024HI "v1024hi")
+   (V2048HI "v2048hi")
+   (V1SI "v1si")
+   (V2SI "v2si")
+   (V4SI "v4si")
+   (V8SI "V8SI")
+   (V16SI "v16si")
+   (V32SI "v32si")
+   (V64SI "v64si")
+   (V128SI "v128si")
+   (V256SI "v256si")
+   (V512SI "v512si")
+   (V1024SI "v1024si")
+   (V1DI "v1di")
+   (V2DI "v2di")
+   (V4DI "v4di")
+   (V8DI "v8di")
+   (V16DI "v16di")
+   (V32DI "v32di")
+   (V64DI "v64di")
+   (V128DI "v128di")
+   (V256DI "v256di")
+   (V512DI "v512di")
+   (V1HF "v1hi")
+   (V2HF "v2hi")
+   (V4HF "v4hi")
+   (V8HF "v8hi")
+   (V16HF "v16hi")
+   (V32HF "v32hi")
+   (V64HF "v64hi")
+   (V128HF "v128hi")
+   (V256HF "v256hi")
+   (V512HF "v512hi")
+   (V1024HF "v1024hi")
+   (V2048HF "v2048hi")
+   (V1BF "v1hi")
+   (V2BF "v2hi")
+   (V4BF "v4hi")
+   (V8BF "v8hi")
+   (V16BF "v16hi")
+   (V32BF "v32hi")
+   (V64BF "v64hi")
+   (V128BF "v128hi")
+   (V256BF "v256hi")
+   (V512BF "v512hi")
+   (V1024BF "v1024hi")
+   (V2048BF "v2048hi")
+   (V1SF "v1si")
+   (V2SF "v2si")
+   (V4SF "v4si")
+   (V8SF "v8si")
+   (V16SF "v16si")
+   (V32SF "v32si")
+   (V64SF "v64si")
+   (V128SF "v128si")
+   (V256SF "v256si")
+   (V512SF "v512si")
+   (V1024SF "v1024si")
+   (V1DF "v1di")
+   (V2DF "v2di")
+   (V4DF "v4di")
+   (V8DF "v8di")
+   (V16DF "v16di")
+   (V32DF "v32di")
+   (V64DF "v64di")
+   (V128DF "v128di")
+   (V256DF "v256di")
+   (V512DF "v512di")
+ ])
+ 
  (define_mode_attr VINDEXEI16 [
    (RVVM4QI "RVVM8HI") (RVVM2QI "RVVM4HI") (RVVM1QI "RVVM2HI") (RVVMF2QI "RVVM1HI") (RVVMF4QI "RVVMF2HI") (RVVMF8QI "RVVMF4HI")
  
***************
*** 2775,2780 ****
--- 3182,3266 ----
    (RVVM8DI "32") (RVVM4DI "32") (RVVM2DI "32") (RVVM1DI "32")
  
    (RVVM8DF "32") (RVVM4DF "32") (RVVM2DF "32") (RVVM1DF "32")
+ 
+   (V1HI "8")
+   (V2HI "8")
+   (V4HI "8")
+   (V8HI "8")
+   (V16HI "8")
+   (V32HI "8")
+   (V64HI "8")
+   (V128HI "8")
+   (V256HI "8")
+   (V512HI "8")
+   (V1024HI "8")
+   (V2048HI "8")
+   (V1SI "16")
+   (V2SI "16")
+   (V4SI "16")
+   (V8SI "16")
+   (V16SI "16")
+   (V32SI "16")
+   (V64SI "16")
+   (V128SI "16")
+   (V256SI "16")
+   (V512SI "16")
+   (V1024SI "16")
+   (V1DI "32")
+   (V2DI "32")
+   (V4DI "32")
+   (V8DI "32")
+   (V16DI "32")
+   (V32DI "32")
+   (V64DI "32")
+   (V128DI "32")
+   (V256DI "32")
+   (V512DI "32")
+   (V1HF "8")
+   (V2HF "8")
+   (V4HF "8")
+   (V8HF "8")
+   (V16HF "8")
+   (V32HF "8")
+   (V64HF "8")
+   (V128HF "8")
+   (V256HF "8")
+   (V512HF "8")
+   (V1024HF "8")
+   (V2048HF "8")
+   (V1BF "8")
+   (V2BF "8")
+   (V4BF "8")
+   (V8BF "8")
+   (V16BF "8")
+   (V32BF "8")
+   (V64BF "8")
+   (V128BF "8")
+   (V256BF "8")
+   (V512BF "8")
+   (V1024BF "8")
+   (V2048BF "8")
+   (V1SF "16")
+   (V2SF "16")
+   (V4SF "16")
+   (V8SF "16")
+   (V16SF "16")
+   (V32SF "16")
+   (V64SF "16")
+   (V128SF "16")
+   (V256SF "16")
+   (V512SF "16")
+   (V1024SF "16")
+   (V1DF "32")
+   (V2DF "32")
+   (V4DF "32")
+   (V8DF "32")
+   (V16DF "32")
+   (V32DF "32")
+   (V64DF "32")
+   (V128DF "32")
+   (V256DF "32")
+   (V512DF "32")
  ])
  
  (define_mode_attr quad_trunc_sew [
***************
*** 2785,2796 ****
--- 3271,3346 ----
    (RVVM8DI "16") (RVVM4DI "16") (RVVM2DI "16") (RVVM1DI "16")
  
    (RVVM8DF "16") (RVVM4DF "16") (RVVM2DF "16") (RVVM1DF "16")
+ 
+   (V1SI "8")
+   (V2SI "8")
+   (V4SI "8")
+   (V8SI "8")
+   (V16SI "8")
+   (V32SI "8")
+   (V64SI "8")
+   (V128SI "8")
+   (V256SI "8")
+   (V512SI "8")
+   (V1024SI "8")
+   (V1DI "16")
+   (V2DI "16")
+   (V4DI "16")
+   (V8DI "16")
+   (V16DI "16")
+   (V32DI "16")
+   (V64DI "16")
+   (V128DI "16")
+   (V256DI "16")
+   (V512DI "16")
+   (V1SF "8")
+   (V2SF "8")
+   (V4SF "8")
+   (V8SF "8")
+   (V16SF "8")
+   (V32SF "8")
+   (V64SF "8")
+   (V128SF "8")
+   (V256SF "8")
+   (V512SF "8")
+   (V1024SF "8")
+   (V1DF "16")
+   (V2DF "16")
+   (V4DF "16")
+   (V8DF "16")
+   (V16DF "16")
+   (V32DF "16")
+   (V64DF "16")
+   (V128DF "16")
+   (V256DF "16")
+   (V512DF "16")
  ])
  
  (define_mode_attr oct_trunc_sew [
    (RVVM8DI "8") (RVVM4DI "8") (RVVM2DI "8") (RVVM1DI "8")
  
    (RVVM8DF "8") (RVVM4DF "8") (RVVM2DF "8") (RVVM1DF "8")
+ 
+   (V1DI "8")
+   (V2DI "8")
+   (V4DI "8")
+   (V8DI "8")
+   (V16DI "8")
+   (V32DI "8")
+   (V64DI "8")
+   (V128DI "8")
+   (V256DI "8")
+   (V512DI "8")
+   (V1DF "8")
+   (V2DF "8")
+   (V4DF "8")
+   (V8DF "8")
+   (V16DF "8")
+   (V32DF "8")
+   (V64DF "8")
+   (V128DF "8")
+   (V256DF "8")
+   (V512DF "8")
  ])
  
  (define_mode_attr double_ext_sew [
***************
*** 2805,2810 ****
--- 3355,3426 ----
    (RVVM4SI "64") (RVVM2SI "64") (RVVM1SI "64") (RVVMF2SI "64")
  
    (RVVM4SF "64") (RVVM2SF "64") (RVVM1SF "64") (RVVMF2SF "64")
+ 
+   (V1QI "16")
+   (V2QI "16")
+   (V4QI "16")
+   (V8QI "16")
+   (V16QI "16")
+   (V32QI "16")
+   (V64QI "16")
+   (V128QI "16")
+   (V256QI "16")
+   (V512QI "16")
+   (V1024QI "16")
+   (V2048QI "16")
+   (V1HI "32")
+   (V2HI "32")
+   (V4HI "32")
+   (V8HI "32")
+   (V16HI "32")
+   (V32HI "32")
+   (V64HI "32")
+   (V128HI "32")
+   (V256HI "32")
+   (V512HI "32")
+   (V1024HI "32")
+   (V1SI "64")
+   (V2SI "64")
+   (V4SI "64")
+   (V8SI "64")
+   (V16SI "64")
+   (V32SI "64")
+   (V64SI "64")
+   (V128SI "64")
+   (V256SI "64")
+   (V512SI "64")
+   (V1HF "32")
+   (V2HF "32")
+   (V4HF "32")
+   (V8HF "32")
+   (V16HF "32")
+   (V32HF "32")
+   (V64HF "32")
+   (V128HF "32")
+   (V256HF "32")
+   (V512HF "32")
+   (V1024HF "32")
+   (V1BF "32")
+   (V2BF "32")
+   (V4BF "32")
+   (V8BF "32")
+   (V16BF "32")
+   (V32BF "32")
+   (V64BF "32")
+   (V128BF "32")
+   (V256BF "32")
+   (V512BF "32")
+   (V1024BF "32")
+   (V1SF "64")
+   (V2SF "64")
+   (V4SF "64")
+   (V8SF "64")
+   (V16SF "64")
+   (V32SF "64")
+   (V64SF "64")
+   (V128SF "64")
+   (V256SF "64")
+   (V512SF "64")
  ])
  
  (define_mode_attr quad_ext_sew [
***************
*** 2813,2822 ****
--- 3429,3491 ----
    (RVVM2HI "64") (RVVM1HI "64") (RVVMF2HI "64") (RVVMF4HI "64")
  
    (RVVM2HF "64") (RVVM1HF "64") (RVVMF2HF "64") (RVVMF4HF "64")
+ 
+   (V1QI "32")
+   (V2QI "32")
+   (V4QI "32")
+   (V8QI "32")
+   (V16QI "32")
+   (V32QI "32")
+   (V64QI "32")
+   (V128QI "32")
+   (V256QI "32")
+   (V512QI "32")
+   (V1024QI "32")
+   (V1HI "64")
+   (V2HI "64")
+   (V4HI "64")
+   (V8HI "64")
+   (V16HI "64")
+   (V32HI "64")
+   (V64HI "64")
+   (V128HI "64")
+   (V256HI "64")
+   (V512HI "64")
+   (V1HF "64")
+   (V2HF "64")
+   (V4HF "64")
+   (V8HF "64")
+   (V16HF "64")
+   (V32HF "64")
+   (V64HF "64")
+   (V128HF "64")
+   (V256HF "64")
+   (V512HF "64")
+   (V1BF "64")
+   (V2BF "64")
+   (V4BF "64")
+   (V8BF "64")
+   (V16BF "64")
+   (V32BF "64")
+   (V64BF "64")
+   (V128BF "64")
+   (V256BF "64")
+   (V512BF "64")
  ])
  
  (define_mode_attr oct_ext_sew [
    (RVVM1QI "64") (RVVMF2QI "64") (RVVMF4QI "64") (RVVMF8QI "64")
+ 
+   (V1QI "64")
+   (V2QI "64")
+   (V4QI "64")
+   (V8QI "64")
+   (V16QI "64")
+   (V32QI "64")
+   (V64QI "64")
+   (V128QI "64")
+   (V256QI "64")
+   (V512QI "64")
  ])
  
  (define_mode_attr V_DOUBLE_EXTEND [
***************
*** 2953,2958 ****
--- 3622,3655 ----
    (V512DF "V512SF")
  ])
  
+ (define_mode_attr VF_DOUBLE_TRUNC_INDEX [
+   (RVVM8SF "RVVM4HI") (RVVM4SF "RVVM2HI") (RVVM2SF "RVVM1HI") (RVVM1SF "RVVMF2HI") (RVVMF2SF "RVVMF4HI")
+ 
+   (RVVM8DF "RVVM4SI") (RVVM4DF "RVVM2SI") (RVVM2DF "RVVM1SI") (RVVM1DF "RVVMF2SI")
+ 
+   (V1SF "V1HI")
+   (V2SF "V2HI")
+   (V4SF "V4HI")
+   (V8SF "V8HI")
+   (V16SF "V16HI")
+   (V32SF "V32HI")
+   (V64SF "V64HI")
+   (V128SF "V128HI")
+   (V256SF "V256HI")
+   (V512SF "V512HI")
+   (V1024SF "V1024HI")
+   (V1DF "V1SI")
+   (V2DF "V2SI")
+   (V4DF "V4SI")
+   (V8DF "V8SI")
+   (V16DF "V16SI")
+   (V32DF "V32SI")
+   (V64DF "V64SI")
+   (V128DF "V128SI")
+   (V256DF "V256SI")
+   (V512DF "V512SI")
+ ])
+ 
  (define_mode_attr V_QUAD_TRUNC [
    (RVVM8SI "RVVM2QI") (RVVM4SI "RVVM1QI") (RVVM2SI "RVVMF2QI") (RVVM1SI "RVVMF4QI") (RVVMF2SI "RVVMF8QI")
  
***************
*** 3145,3150 ****
--- 3842,4021 ----
    (RVVM8DI "RVVM4SI") (RVVM4DI "RVVM2SI") (RVVM2DI "RVVM1SI") (RVVM1DI "RVVMF2SI")
  
    (RVVM8DF "RVVM4SI") (RVVM4DF "RVVM2SI") (RVVM2DF "RVVM1SI") (RVVM1DF "RVVMF2SI")
+ 
+   (V1HI "V1QI")
+   (V2HI "V2QI")
+   (V4HI "V4QI")
+   (V8HI "V8QI")
+   (V16HI "V16QI")
+   (V32HI "V32QI")
+   (V64HI "V64QI")
+   (V128HI "V128QI")
+   (V256HI "V256QI")
+   (V512HI "V512QI")
+   (V1024HI "V1024QI")
+   (V2048HI "V2048QI")
+   (V1SI "V1HI")
+   (V2SI "V2HI")
+   (V4SI "V4HI")
+   (V8SI "V8HI")
+   (V16SI "V16HI")
+   (V32SI "V32HI")
+   (V64SI "V64HI")
+   (V128SI "V128HI")
+   (V256SI "V256HI")
+   (V512SI "V512HI")
+   (V1024SI "V1024HI")
+   (V1DI "V1SI")
+   (V2DI "V2SI")
+   (V4DI "V4SI")
+   (V8DI "V8SI")
+   (V16DI "V16SI")
+   (V32DI "V32SI")
+   (V64DI "V64SI")
+   (V128DI "V128SI")
+   (V256DI "V256SI")
+   (V512DI "V512SI")
+   (V1HF "V1QI")
+   (V2HF "V2QI")
+   (V4HF "V4QI")
+   (V8HF "V8QI")
+   (V16HF "V16QI")
+   (V32HF "V32QI")
+   (V64HF "V64QI")
+   (V128HF "V128QI")
+   (V256HF "V256QI")
+   (V512HF "V512QI")
+   (V1024HF "V1024QI")
+   (V2048HF "V2048QI")
+   (V1BF "V1QI")
+   (V2BF "V2QI")
+   (V4BF "V4QI")
+   (V8BF "V8QI")
+   (V16BF "V16QI")
+   (V32BF "V32QI")
+   (V64BF "V64QI")
+   (V128BF "V128QI")
+   (V256BF "V256QI")
+   (V512BF "V512QI")
+   (V1024BF "V1024QI")
+   (V2048BF "V2048QI")
+   (V1SF "V1HI")
+   (V2SF "V2HI")
+   (V4SF "V4HI")
+   (V8SF "V8HI")
+   (V16SF "V16HI")
+   (V32SF "V32HI")
+   (V64SF "V64HI")
+   (V128SF "V128HI")
+   (V256SF "V256HI")
+   (V512SF "V512HI")
+   (V1024SF "V1024HI")
+   (V1DF "V1SI")
+   (V2DF "V2SI")
+   (V4DF "V4SI")
+   (V8DF "V8SI")
+   (V16DF "V16SI")
+   (V32DF "V32SI")
+   (V64DF "V64SI")
+   (V128DF "V128SI")
+   (V256DF "V256SI")
+   (V512DF "V512SI")
+ ])
+ 
+ (define_mode_attr vindex_double_trunc [
+   (RVVM8HI "rvvm4qi") (RVVM4HI "rvvm2qi") (RVVM2HI "rvvm1qi") (RVVM1HI "rvvmf2qi") (RVVMF2HI "rvvmf4qi") (RVVMF4HI "rvvmf8qi")
+ 
+   (RVVM8BF "rvvm4qi") (RVVM4BF "rvvm2qi") (RVVM2BF "rvvm1qi") (RVVM1BF "rvvmf2qi") (RVVMF2BF "rvvmf4qi") (RVVMF4BF "rvvmf8qi")
+ 
+   (RVVM8HF "rvvm4qi") (RVVM4HF "rvvm2qi") (RVVM2HF "rvvm1qi") (RVVM1HF "rvvmf2qi") (RVVMF2HF "rvvmf4qi") (RVVMF4HF "rvvmf8qi")
+ 
+   (RVVM8SI "rvvm4hi") (RVVM4SI "rvvm2hi") (RVVM2SI "rvvm1hi") (RVVM1SI "rvvmf2hi") (RVVMF2SI "rvvmf4hi")
+ 
+   (RVVM8SF "rvvm4hi") (RVVM4SF "rvvm2hi") (RVVM2SF "rvvm1hi") (RVVM1SF "rvvmf2hi") (RVVMF2SF "rvvmf4hi")
+ 
+   (RVVM8DI "rvvm4si") (RVVM4DI "rvvm2si") (RVVM2DI "rvvm1si") (RVVM1DI "rvvmf2si")
+ 
+   (RVVM8DF "rvvm4si") (RVVM4DF "rvvm2si") (RVVM2DF "rvvm1si") (RVVM1DF "rvvmf2si")
+ 
+   (V1HI "v1qi")
+   (V2HI "v2qi")
+   (V4HI "v4qi")
+   (V8HI "v8qi")
+   (V16HI "v16qi")
+   (V32HI "v32qi")
+   (V64HI "v64qi")
+   (V128HI "v128qi")
+   (V256HI "v256qi")
+   (V512HI "v512qi")
+   (V1024HI "v1024qi")
+   (V2048HI "v2048qi")
+   (V1SI "v1hi")
+   (V2SI "v2hi")
+   (V4SI "v4hi")
+   (V8SI "v8hi")
+   (V16SI "v16hi")
+   (V32SI "v32hi")
+   (V64SI "v64hi")
+   (V128SI "v128hi")
+   (V256SI "v256hi")
+   (V512SI "v512hi")
+   (V1024SI "v1024hi")
+   (V1DI "v1si")
+   (V2DI "v2si")
+   (V4DI "v4si")
+   (V8DI "v8si")
+   (V16DI "v16si")
+   (V32DI "v32si")
+   (V64DI "v64si")
+   (V128DI "v128si")
+   (V256DI "v256si")
+   (V512DI "v512si")
+   (V1HF "v1qi")
+   (V2HF "v2qi")
+   (V4HF "v4qi")
+   (V8HF "v8qi")
+   (V16HF "v16qi")
+   (V32HF "v32qi")
+   (V64HF "v64qi")
+   (V128HF "v128qi")
+   (V256HF "v256qi")
+   (V512HF "v512qi")
+   (V1024HF "v1024qi")
+   (V2048HF "v2048qi")
+   (V1BF "v1qi")
+   (V2BF "v2qi")
+   (V4BF "v4qi")
+   (V8BF "v8qi")
+   (V16BF "v16qi")
+   (V32BF "v32qi")
+   (V64BF "v64qi")
+   (V128BF "v128qi")
+   (V256BF "v256qi")
+   (V512BF "v512qi")
+   (V1024BF "v1024qi")
+   (V2048BF "v2048qi")
+   (V1SF "v1hi")
+   (V2SF "v2hi")
+   (V4SF "v4hi")
+   (V8SF "v8hi")
+   (V16SF "v16hi")
+   (V32SF "v32hi")
+   (V64SF "v64hi")
+   (V128SF "v128hi")
+   (V256SF "v256hi")
+   (V512SF "v512hi")
+   (V1024SF "v1024hi")
+   (V1DF "v1si")
+   (V2DF "v2si")
+   (V4DF "v4si")
+   (V8DF "v8si")
+   (V16DF "v16si")
+   (V32DF "v32si")
+   (V64DF "v64si")
+   (V128DF "v128si")
+   (V256DF "v256si")
+   (V512DF "v512si")
  ])
  
  (define_mode_attr VINDEX_QUAD_TRUNC [
***************
*** 3155,3166 ****
--- 4026,4181 ----
    (RVVM8DI "RVVM2HI") (RVVM4DI "RVVM1HI") (RVVM2DI "RVVMF2HI") (RVVM1DI "RVVMF4HI")
  
    (RVVM8DF "RVVM2HI") (RVVM4DF "RVVM1HI") (RVVM2DF "RVVMF2HI") (RVVM1DF "RVVMF4HI")
+ 
+   (V1SI "V1QI")
+   (V2SI "V2QI")
+   (V4SI "V4QI")
+   (V8SI "V8QI")
+   (V16SI "V16QI")
+   (V32SI "V32QI")
+   (V64SI "V64QI")
+   (V128SI "V128QI")
+   (V256SI "V256QI")
+   (V512SI "V512QI")
+   (V1024SI "V1024QI")
+   (V1DI "V1HI")
+   (V2DI "V2HI")
+   (V4DI "V4HI")
+   (V8DI "V8HI")
+   (V16DI "V16HI")
+   (V32DI "V32HI")
+   (V64DI "V64HI")
+   (V128DI "V128HI")
+   (V256DI "V256HI")
+   (V512DI "V512HI")
+   (V1SF "V1QI")
+   (V2SF "V2QI")
+   (V4SF "V4QI")
+   (V8SF "V8QI")
+   (V16SF "V16QI")
+   (V32SF "V32QI")
+   (V64SF "V64QI")
+   (V128SF "V128QI")
+   (V256SF "V256QI")
+   (V512SF "V512QI")
+   (V1024SF "V512QI")
+   (V1DF "V1HI")
+   (V2DF "V2HI")
+   (V4DF "V4HI")
+   (V8DF "V8HI")
+   (V16DF "V16HI")
+   (V32DF "V32HI")
+   (V64DF "V64HI")
+   (V128DF "V128HI")
+   (V256DF "V256HI")
+   (V512DF "V512HI")
+ ])
+ 
+ (define_mode_attr vindex_quad_trunc [
+   (RVVM8SI "rvvm2qi") (RVVM4SI "rvvm1qi") (RVVM2SI "rvvmf2qi") (RVVM1SI "rvvmf4qi") (RVVMF2SI "rvvmf8qi")
+ 
+   (RVVM8SF "rvvm2qi") (RVVM4SF "rvvm1qi") (RVVM2SF "rvvmf2qi") (RVVM1SF "rvvmf4qi") (RVVMF2SF "rvvmf8qi")
+ 
+   (RVVM8DI "rvvm2hi") (RVVM4DI "rvvm1hi") (RVVM2DI "rvvmf2hi") (RVVM1DI "rvvmf4hi")
+ 
+   (RVVM8DF "rvvm2hi") (RVVM4DF "rvvm1hi") (RVVM2DF "rvvmf2hi") (RVVM1DF "rvvmf4hi")
+ 
+   (V1SI "v1qi")
+   (V2SI "v2qi")
+   (V4SI "v4qi")
+   (V8SI "v8qi")
+   (V16SI "v16qi")
+   (V32SI "v32qi")
+   (V64SI "v64qi")
+   (V128SI "v128qi")
+   (V256SI "v256qi")
+   (V512SI "v512qi")
+   (V1024SI "v1024qi")
+   (V1DI "v1hi")
+   (V2DI "v2hi")
+   (V4DI "v4hi")
+   (V8DI "v8hi")
+   (V16DI "v16hi")
+   (V32DI "v32hi")
+   (V64DI "v64hi")
+   (V128DI "v128hi")
+   (V256DI "v256hi")
+   (V512DI "v512hi")
+   (V1SF "v1qi")
+   (V2SF "v2qi")
+   (V4SF "v4qi")
+   (V8SF "v8qi")
+   (V16SF "v16qi")
+   (V32SF "v32qi")
+   (V64SF "v64qi")
+   (V128SF "v128qi")
+   (V256SF "v256qi")
+   (V512SF "v512qi")
+   (V1024SF "v512qi")
+   (V1DF "v1hi")
+   (V2DF "v2hi")
+   (V4DF "v4hi")
+   (V8DF "v8hi")
+   (V16DF "v16hi")
+   (V32DF "v32hi")
+   (V64DF "v64hi")
+   (V128DF "v128hi")
+   (V256DF "v256hi")
+   (V512DF "v512hi")
  ])
  
  (define_mode_attr VINDEX_OCT_TRUNC [
    (RVVM8DI "RVVM1QI") (RVVM4DI "RVVMF2QI") (RVVM2DI "RVVMF4QI") (RVVM1DI "RVVMF8QI")
  
    (RVVM8DF "RVVM1QI") (RVVM4DF "RVVMF2QI") (RVVM2DF "RVVMF4QI") (RVVM1DF "RVVMF8QI")
+ 
+   (V1DI "V1QI")
+   (V2DI "V2QI")
+   (V4DI "V4QI")
+   (V8DI "V8QI")
+   (V16DI "V16QI")
+   (V32DI "V32QI")
+   (V64DI "V64QI")
+   (V128DI "V128QI")
+   (V256DI "V256QI")
+   (V512DI "V512QI")
+   (V1DF "V1QI")
+   (V2DF "V2QI")
+   (V4DF "V4QI")
+   (V8DF "V8QI")
+   (V16DF "V16QI")
+   (V32DF "V32QI")
+   (V64DF "V64QI")
+   (V128DF "V128QI")
+   (V256DF "V256QI")
+   (V512DF "V512QI")
+ ])
+ 
+ (define_mode_attr vindex_oct_trunc [
+   (RVVM8DI "rvvm1qi") (RVVM4DI "rvvmf2qi") (RVVM2DI "rvvmf4qi") (RVVM1DI "rvvmf8qi")
+ 
+   (RVVM8DF "rvvm1qi") (RVVM4DF "rvvmf2qi") (RVVM2DF "rvvmf4qi") (RVVM1DF "rvvmf8qi")
+ 
+   (V1DI "v1qi")
+   (V2DI "v2qi")
+   (V4DI "v4qi")
+   (V8DI "v8qi")
+   (V16DI "v16qi")
+   (V32DI "v32qi")
+   (V64DI "v64qi")
+   (V128DI "v128qi")
+   (V256DI "v256qi")
+   (V512DI "v512qi")
+   (V1DF "v1qi")
+   (V2DF "v2qi")
+   (V4DF "v4qi")
+   (V8DF "v8qi")
+   (V16DF "v16qi")
+   (V32DF "v32qi")
+   (V64DF "v64qi")
+   (V128DF "v128qi")
+   (V256DF "v256qi")
+   (V512DF "v512qi")
  ])
  
  (define_mode_attr VINDEX_DOUBLE_EXT [
***************
*** 3175,3180 ****
--- 4190,4341 ----
    (RVVM4SI "RVVM8DI") (RVVM2SI "RVVM4DI") (RVVM1SI "RVVM2DI") (RVVMF2SI "RVVM1DI")
  
    (RVVM4SF "RVVM8DI") (RVVM2SF "RVVM4DI") (RVVM1SF "RVVM2DI") (RVVMF2SF "RVVM1DI")
+ 
+   (V1QI "V1HI")
+   (V2QI "V2HI")
+   (V4QI "V4HI")
+   (V8QI "V8HI")
+   (V16QI "V16HI")
+   (V32QI "V32HI")
+   (V64QI "V64HI")
+   (V128QI "V128HI")
+   (V256QI "V256HI")
+   (V512QI "V512HI")
+   (V1024QI "V1024HI")
+   (V2048QI "V2048HI")
+   (V1HI "V1SI")
+   (V2HI "V2SI")
+   (V4HI "V4SI")
+   (V8HI "V8SI")
+   (V16HI "V16SI")
+   (V32HI "V32SI")
+   (V64HI "V64SI")
+   (V128HI "V128SI")
+   (V256HI "V256SI")
+   (V512HI "V512SI")
+   (V1024HI "V1024SI")
+   (V1SI "V1DI")
+   (V2SI "V2DI")
+   (V4SI "V4DI")
+   (V8SI "V8DI")
+   (V16SI "V16DI")
+   (V32SI "V32DI")
+   (V64SI "V64DI")
+   (V128SI "V128DI")
+   (V256SI "V256DI")
+   (V512SI "V512DI")
+   (V1HF "V1SI")
+   (V2HF "V2SI")
+   (V4HF "V4SI")
+   (V8HF "V8SI")
+   (V16HF "V16SI")
+   (V32HF "V32SI")
+   (V64HF "V64SI")
+   (V128HF "V128SI")
+   (V256HF "V256SI")
+   (V512HF "V512SI")
+   (V1024HF "V1024SI")
+   (V1BF "V1SI")
+   (V2BF "V2SI")
+   (V4BF "V4SI")
+   (V8BF "V8SI")
+   (V16BF "V16SI")
+   (V32BF "V32SI")
+   (V64BF "V64SI")
+   (V128BF "V128SI")
+   (V256BF "V256SI")
+   (V512BF "V512SI")
+   (V1024BF "V1024SI")
+   (V1SF "V1DI")
+   (V2SF "V2DI")
+   (V4SF "V4DI")
+   (V8SF "V8DI")
+   (V16SF "V16DI")
+   (V32SF "V32DI")
+   (V64SF "V64DI")
+   (V128SF "V128DI")
+   (V256SF "V256DI")
+   (V512SF "V512DI")
+ ])
+ 
+ (define_mode_attr vindex_double_ext [
+   (RVVM4QI "rvvm8hi") (RVVM2QI "rvvm4hi") (RVVM1QI "rvvm2hi") (RVVMF2QI "rvvm1hi") (RVVMF4QI "rvvmf2hi") (RVVMF8QI "rvvmf4hi")
+ 
+   (RVVM4HI "rvvm8si") (RVVM2HI "rvvm4si") (RVVM1HI "rvvm2si") (RVVMF2HI "rvvm1si") (RVVMF4HI "rvvmf2si")
+ 
+   (RVVM4BF "rvvm8si") (RVVM2BF "rvvm4si") (RVVM1BF "rvvm2si") (RVVMF2BF "rvvm1si") (RVVMF4BF "rvvmf2si")
+ 
+   (RVVM4HF "rvvm8si") (RVVM2HF "rvvm4si") (RVVM1HF "rvvm2si") (RVVMF2HF "rvvm1si") (RVVMF4HF "rvvmf2si")
+ 
+   (RVVM4SI "rvvm8di") (RVVM2SI "rvvm4di") (RVVM1SI "rvvm2di") (RVVMF2SI "rvvm1di")
+ 
+   (RVVM4SF "rvvm8di") (RVVM2SF "rvvm4di") (RVVM1SF "rvvm2di") (RVVMF2SF "rvvm1di")
+ 
+   (V1QI "v1hi")
+   (V2QI "v2hi")
+   (V4QI "v4hi")
+   (V8QI "v8hi")
+   (V16QI "v16hi")
+   (V32QI "v32hi")
+   (V64QI "v64hi")
+   (V128QI "v128hi")
+   (V256QI "v256hi")
+   (V512QI "v512hi")
+   (V1024QI "v1024hi")
+   (V2048QI "v2048hi")
+   (V1HI "v1si")
+   (V2HI "v2si")
+   (V4HI "v4si")
+   (V8HI "v8si")
+   (V16HI "v16si")
+   (V32HI "v32si")
+   (V64HI "v64si")
+   (V128HI "v128si")
+   (V256HI "v256si")
+   (V512HI "v512si")
+   (V1024HI "v1024si")
+   (V1SI "v1di")
+   (V2SI "v2di")
+   (V4SI "v4di")
+   (V8SI "v8di")
+   (V16SI "v16di")
+   (V32SI "v32di")
+   (V64SI "v64di")
+   (V128SI "v128di")
+   (V256SI "v256di")
+   (V512SI "v512di")
+   (V1HF "v1si")
+   (V2HF "v2si")
+   (V4HF "v4si")
+   (V8HF "v8si")
+   (V16HF "v16si")
+   (V32HF "v32si")
+   (V64HF "v64si")
+   (V128HF "v128si")
+   (V256HF "v256si")
+   (V512HF "v512si")
+   (V1024HF "v1024si")
+   (V1BF "v1si")
+   (V2BF "v2si")
+   (V4BF "v4si")
+   (V8BF "v8si")
+   (V16BF "v16si")
+   (V32BF "v32si")
+   (V64BF "v64si")
+   (V128BF "v128si")
+   (V256BF "v256si")
+   (V512BF "v512si")
+   (V1024BF "v1024si")
+   (V1SF "v1di")
+   (V2SF "v2di")
+   (V4SF "v4di")
+   (V8SF "v8di")
+   (V16SF "v16di")
+   (V32SF "v32di")
+   (V64SF "v64di")
+   (V128SF "v128di")
+   (V256SF "v256di")
+   (V512SF "v512di")
  ])
  
  (define_mode_attr VINDEX_QUAD_EXT [
***************
*** 3185,3194 ****
--- 4346,4475 ----
    (RVVM2BF "RVVM8DI") (RVVM1BF "RVVM4DI") (RVVMF2BF "RVVM2DI") (RVVMF4BF "RVVM1DI")
  
    (RVVM2HF "RVVM8DI") (RVVM1HF "RVVM4DI") (RVVMF2HF "RVVM2DI") (RVVMF4HF "RVVM1DI")
+ 
+   (V1QI "V1SI")
+   (V2QI "V2SI")
+   (V4QI "V4SI")
+   (V8QI "V8SI")
+   (V16QI "V16SI")
+   (V32QI "V32SI")
+   (V64QI "V64SI")
+   (V128QI "V128SI")
+   (V256QI "V256SI")
+   (V512QI "V512SI")
+   (V1024QI "V1024SI")
+   (V1HI "V1DI")
+   (V2HI "V2DI")
+   (V4HI "V4DI")
+   (V8HI "V8DI")
+   (V16HI "V16DI")
+   (V32HI "V32DI")
+   (V64HI "V64DI")
+   (V128HI "V128DI")
+   (V256HI "V256DI")
+   (V512HI "V512DI")
+   (V1HF "V1DI")
+   (V2HF "V2DI")
+   (V4HF "V4DI")
+   (V8HF "V8DI")
+   (V16HF "V16DI")
+   (V32HF "V32DI")
+   (V64HF "V64DI")
+   (V128HF "V128DI")
+   (V256HF "V256DI")
+   (V512HF "V512DI")
+   (V1BF "V1DI")
+   (V2BF "V2DI")
+   (V4BF "V4DI")
+   (V8BF "V8DI")
+   (V16BF "V16DI")
+   (V32BF "V32DI")
+   (V64BF "V64DI")
+   (V128BF "V128DI")
+   (V256BF "V256DI")
+   (V512BF "V512DI")
+ ])
+ 
+ (define_mode_attr vindex_quad_ext [
+   (RVVM2QI "rvvm8si") (RVVM1QI "rvvm4si") (RVVMF2QI "rvvm2si") (RVVMF4QI "rvvm1si") (RVVMF8QI "rvvmf2si")
+ 
+   (RVVM2HI "rvvm8di") (RVVM1HI "rvvm4di") (RVVMF2HI "rvvm2di") (RVVMF4HI "rvvm1di")
+ 
+   (RVVM2BF "rvvm8di") (RVVM1BF "rvvm4di") (RVVMF2BF "rvvm2di") (RVVMF4BF "rvvm1di")
+ 
+   (RVVM2HF "rvvm8di") (RVVM1HF "rvvm4di") (RVVMF2HF "rvvm2di") (RVVMF4HF "rvvm1di")
+ 
+   (V1QI "v1si")
+   (V2QI "v2si")
+   (V4QI "v4si")
+   (V8QI "v8si")
+   (V16QI "v16si")
+   (V32QI "v32si")
+   (V64QI "v64si")
+   (V128QI "v128si")
+   (V256QI "v256si")
+   (V512QI "v512si")
+   (V1024QI "v1024si")
+   (V1HI "v1di")
+   (V2HI "v2di")
+   (V4HI "v4di")
+   (V8HI "v8di")
+   (V16HI "v16di")
+   (V32HI "v32di")
+   (V64HI "v64di")
+   (V128HI "v1d8di")
+   (V256HI "v256di")
+   (V512HI "v512di")
+   (V1HF "v1di")
+   (V2HF "v2di")
+   (V4HF "v4di")
+   (V8HF "v8di")
+   (V16HF "v16di")
+   (V32HF "v32di")
+   (V64HF "v64di")
+   (V128HF "v128di")
+   (V256HF "v256di")
+   (V512HF "v512di")
+   (V1BF "v1di")
+   (V2BF "v2di")
+   (V4BF "v4di")
+   (V8BF "v8di")
+   (V16BF "v16di")
+   (V32BF "v32di")
+   (V64BF "v64di")
+   (V128BF "v128di")
+   (V256BF "v256di")
+   (V512BF "v512di")
  ])
  
  (define_mode_attr VINDEX_OCT_EXT [
    (RVVM1QI "RVVM8DI") (RVVMF2QI "RVVM4DI") (RVVMF4QI "RVVM2DI") (RVVMF8QI "RVVM1DI")
+ 
+   (V1QI "V1DI")
+   (V2QI "V2DI")
+   (V4QI "V4DI")
+   (V8QI "V8DI")
+   (V16QI "V16DI")
+   (V32QI "V32DI")
+   (V64QI "V64DI")
+   (V128QI "V128DI")
+   (V256QI "V256DI")
+   (V512QI "V512DI")
+ ])
+ 
+ (define_mode_attr vindex_oct_ext [
+   (RVVM1QI "rvvm8di") (RVVMF2QI "rvvm4di") (RVVMF4QI "rvvm2di") (RVVMF8QI "rvvm1di")
+ 
+   (V1QI "v1di")
+   (V2QI "v2di")
+   (V4QI "v4di")
+   (V8QI "v8di")
+   (V16QI "v16di")
+   (V32QI "v32di")
+   (V64QI "v64di")
+   (V128QI "v128di")
+   (V256QI "v256di")
+   (V512QI "v512di")
  ])
  
  (define_mode_attr VCONVERT [
***************
*** 4597,4636 ****
    (V2048BI "riscv_vector::vls_mode_valid_p (V2048BImode) && TARGET_MIN_VLEN >= 2048")
    (V4096BI "riscv_vector::vls_mode_valid_p (V4096BImode) && TARGET_MIN_VLEN >= 4096")])
  
! (define_mode_iterator VSI [
    RVVM8SI RVVM4SI RVVM2SI RVVM1SI (RVVMF2SI "TARGET_VECTOR_ELEN_64")
  ])
  
! (define_mode_iterator VLMULX2_SI [
    RVVM4SI RVVM2SI RVVM1SI (RVVMF2SI "TARGET_VECTOR_ELEN_64")
  ])
  
! (define_mode_iterator VLMULX4_SI [
    RVVM2SI RVVM1SI (RVVMF2SI "TARGET_VECTOR_ELEN_64")
  ])
  
! (define_mode_iterator VLMULX8_SI [
    RVVM1SI (RVVMF2SI "TARGET_VECTOR_ELEN_64")
  ])
  
! (define_mode_iterator VLMULX16_SI [
    (RVVMF2SI "TARGET_VECTOR_ELEN_64")
  ])
  
! (define_mode_attr VSIX2 [
!   (RVVM8SI "RVVM8SI") (RVVM4SI "RVVM8SI") (RVVM2SI "RVVM4SI") (RVVM1SI "RVVM2SI") (RVVMF2SI "RVVM1SI")
  ])
  
! (define_mode_attr VSIX4 [
    (RVVM2SI "RVVM8SI") (RVVM1SI "RVVM4SI") (RVVMF2SI "RVVM2SI")
  ])
  
! (define_mode_attr VSIX8 [
    (RVVM1SI "RVVM8SI") (RVVMF2SI "RVVM4SI")
  ])
  
! (define_mode_attr VSIX16 [
    (RVVMF2SI "RVVM8SI")
  ])
  
  (define_mode_iterator VLS_HAS_HALF [
--- 5878,6005 ----
    (V2048BI "riscv_vector::vls_mode_valid_p (V2048BImode) && TARGET_MIN_VLEN >= 2048")
    (V4096BI "riscv_vector::vls_mode_valid_p (V4096BImode) && TARGET_MIN_VLEN >= 4096")])
  
! (define_mode_iterator V_VLSI_S [
    RVVM8SI RVVM4SI RVVM2SI RVVM1SI (RVVMF2SI "TARGET_VECTOR_ELEN_64")
+ 
+   (V1SI "riscv_vector::vls_mode_valid_p (V1SImode)")
+   (V2SI "riscv_vector::vls_mode_valid_p (V2SImode)")
+   (V4SI "riscv_vector::vls_mode_valid_p (V4SImode)")
+   (V8SI "riscv_vector::vls_mode_valid_p (V8SImode)")
+   (V16SI "riscv_vector::vls_mode_valid_p (V16SImode) && TARGET_MIN_VLEN >= 64")
+   (V32SI "riscv_vector::vls_mode_valid_p (V32SImode) && TARGET_MIN_VLEN >= 128")
+   (V64SI "riscv_vector::vls_mode_valid_p (V64SImode) && TARGET_MIN_VLEN >= 256")
+   (V128SI "riscv_vector::vls_mode_valid_p (V128SImode) && TARGET_MIN_VLEN >= 512")
+   (V256SI "riscv_vector::vls_mode_valid_p (V256SImode) && TARGET_MIN_VLEN >= 1024")
+   (V512SI "riscv_vector::vls_mode_valid_p (V512SImode) && TARGET_MIN_VLEN >= 2048")
+   (V1024SI "riscv_vector::vls_mode_valid_p (V1024SImode) && TARGET_MIN_VLEN >= 4096")
  ])
  
! (define_mode_iterator V_VLSI_S_LMULX2 [
    RVVM4SI RVVM2SI RVVM1SI (RVVMF2SI "TARGET_VECTOR_ELEN_64")
+ 
+   (V1SI "riscv_vector::vls_mode_valid_p (V1SImode)")
+   (V2SI "riscv_vector::vls_mode_valid_p (V2SImode)")
+   (V4SI "riscv_vector::vls_mode_valid_p (V4SImode)")
+   (V8SI "riscv_vector::vls_mode_valid_p (V8SImode)")
+   (V16SI "riscv_vector::vls_mode_valid_p (V16SImode) && TARGET_MIN_VLEN >= 64")
+   (V32SI "riscv_vector::vls_mode_valid_p (V32SImode) && TARGET_MIN_VLEN >= 128")
+   (V64SI "riscv_vector::vls_mode_valid_p (V64SImode) && TARGET_MIN_VLEN >= 256")
+   (V128SI "riscv_vector::vls_mode_valid_p (V128SImode) && TARGET_MIN_VLEN >= 512")
+   (V256SI "riscv_vector::vls_mode_valid_p (V256SImode) && TARGET_MIN_VLEN >= 1024")
+   (V512SI "riscv_vector::vls_mode_valid_p (V512SImode) && TARGET_MIN_VLEN >= 2048")
  ])
  
! (define_mode_iterator V_VLSI_S_LMULX4 [
    RVVM2SI RVVM1SI (RVVMF2SI "TARGET_VECTOR_ELEN_64")
+ 
+   (V1SI "riscv_vector::vls_mode_valid_p (V1SImode)")
+   (V2SI "riscv_vector::vls_mode_valid_p (V2SImode)")
+   (V4SI "riscv_vector::vls_mode_valid_p (V4SImode)")
+   (V8SI "riscv_vector::vls_mode_valid_p (V8SImode)")
+   (V16SI "riscv_vector::vls_mode_valid_p (V16SImode) && TARGET_MIN_VLEN >= 64")
+   (V32SI "riscv_vector::vls_mode_valid_p (V32SImode) && TARGET_MIN_VLEN >= 128")
+   (V64SI "riscv_vector::vls_mode_valid_p (V64SImode) && TARGET_MIN_VLEN >= 256")
+   (V128SI "riscv_vector::vls_mode_valid_p (V128SImode) && TARGET_MIN_VLEN >= 512")
+   (V256SI "riscv_vector::vls_mode_valid_p (V256SImode) && TARGET_MIN_VLEN >= 1024")
  ])
  
! (define_mode_iterator V_VLSI_S_LMULX8 [
    RVVM1SI (RVVMF2SI "TARGET_VECTOR_ELEN_64")
+ 
+   (V1SI "riscv_vector::vls_mode_valid_p (V1SImode)")
+   (V2SI "riscv_vector::vls_mode_valid_p (V2SImode)")
+   (V4SI "riscv_vector::vls_mode_valid_p (V4SImode)")
+   (V8SI "riscv_vector::vls_mode_valid_p (V8SImode)")
+   (V16SI "riscv_vector::vls_mode_valid_p (V16SImode) && TARGET_MIN_VLEN >= 64")
+   (V32SI "riscv_vector::vls_mode_valid_p (V32SImode) && TARGET_MIN_VLEN >= 128")
+   (V64SI "riscv_vector::vls_mode_valid_p (V64SImode) && TARGET_MIN_VLEN >= 256")
+   (V128SI "riscv_vector::vls_mode_valid_p (V128SImode) && TARGET_MIN_VLEN >= 512")
  ])
  
! (define_mode_iterator V_VLSI_S_LMULX16 [
    (RVVMF2SI "TARGET_VECTOR_ELEN_64")
+ 
+   (V1SI "riscv_vector::vls_mode_valid_p (V1SImode)")
+   (V2SI "riscv_vector::vls_mode_valid_p (V2SImode)")
+   (V4SI "riscv_vector::vls_mode_valid_p (V4SImode)")
+   (V8SI "riscv_vector::vls_mode_valid_p (V8SImode)")
+   (V16SI "riscv_vector::vls_mode_valid_p (V16SImode) && TARGET_MIN_VLEN >= 64")
+   (V32SI "riscv_vector::vls_mode_valid_p (V32SImode) && TARGET_MIN_VLEN >= 128")
+   (V64SI "riscv_vector::vls_mode_valid_p (V64SImode) && TARGET_MIN_VLEN >= 256")
  ])
  
! (define_mode_attr V_VLSI_S_X2 [
!   (RVVM4SI "RVVM8SI") (RVVM2SI "RVVM4SI") (RVVM1SI "RVVM2SI") (RVVMF2SI "RVVM1SI")
! 
!   (V1SI "V2SI")
!   (V2SI "V4SI")
!   (V4SI "V8SI")
!   (V8SI "V16SI")
!   (V16SI "V32SI")
!   (V32SI "V64SI")
!   (V64SI "V128SI")
!   (V128SI "V256SI")
!   (V256SI "V512SI")
!   (V512SI "V1024SI")
  ])
  
! (define_mode_attr V_VLSI_S_X4 [
    (RVVM2SI "RVVM8SI") (RVVM1SI "RVVM4SI") (RVVMF2SI "RVVM2SI")
+ 
+   (V1SI "V4SI")
+   (V2SI "V8SI")
+   (V4SI "V16SI")
+   (V8SI "V32SI")
+   (V16SI "V64SI")
+   (V32SI "V128SI")
+   (V64SI "V256SI")
+   (V128SI "V512SI")
+   (V256SI "V1024SI")
  ])
  
! (define_mode_attr V_VLSI_S_X8 [
    (RVVM1SI "RVVM8SI") (RVVMF2SI "RVVM4SI")
+ 
+   (V1SI "V8SI")
+   (V2SI "V16SI")
+   (V4SI "V32SI")
+   (V8SI "V64SI")
+   (V16SI "V128SI")
+   (V32SI "V256SI")
+   (V64SI "V512SI")
+   (V128SI "V1024SI")
  ])
  
! (define_mode_attr V_VLSI_S_X16 [
    (RVVMF2SI "RVVM8SI")
+ 
+   (V1SI "V16SI")
+   (V2SI "V32SI")
+   (V4SI "V64SI")
+   (V8SI "V128SI")
+   (V16SI "V256SI")
+   (V32SI "V512SI")
+   (V64SI "V1024SI")
  ])
  
  (define_mode_iterator VLS_HAS_HALF [
***************
*** 5154,5156 ****
--- 6523,6539 ----
    (V32DI "V32HI") (V64DI "V64HI") (V128DI "V128HI") (V256DI "V256HI")
    (V512DI "V512HI")
  ])
+ 
+ ;; Vector conditional branch iterators
+ (define_int_iterator COND_LEN_CBRANCH_CMP
+  [UNSPEC_COND_LEN_CMP_ALL UNSPEC_COND_LEN_CMP_ANY])
+ 
+ (define_int_attr cbranch_op [
+   (UNSPEC_COND_LEN_CMP_ALL "EQ")
+   (UNSPEC_COND_LEN_CMP_ANY "NE")
+ ])
+ 
+ (define_int_attr cbranch_optab [
+   (UNSPEC_COND_LEN_CMP_ALL "cond_len_vec_cbranch_all")
+   (UNSPEC_COND_LEN_CMP_ANY "cond_len_vec_cbranch_any")
+ ])
diff -Nrcpad gcc-16-20251214/gcc/config/riscv/vector.md gcc-16-20251221/gcc/config/riscv/vector.md
*** gcc-16-20251214/gcc/config/riscv/vector.md	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/riscv/vector.md	Sun Dec 21 22:32:06 2025
***************
*** 1033,1047 ****
  ;; -----------------------------------------------------------------
  
  (define_insn "@vundefined<mode>"
!   [(set (match_operand:V 0 "register_operand" "=vr")
! 	(unspec:V [(reg:SI X0_REGNUM)] UNSPEC_VUNDEF))]
    "TARGET_VECTOR"
    ""
    [(set_attr "type" "vector")])
  
  (define_insn "@vundefined<mode>"
!   [(set (match_operand:VB 0 "register_operand" "=vr")
! 	(unspec:VB [(reg:SI X0_REGNUM)] UNSPEC_VUNDEF))]
    "TARGET_VECTOR"
    ""
    [(set_attr "type" "vector")])
--- 1033,1047 ----
  ;; -----------------------------------------------------------------
  
  (define_insn "@vundefined<mode>"
!   [(set (match_operand:V_VLS 0 "register_operand" "=vr")
! 	(unspec:V_VLS [(reg:SI X0_REGNUM)] UNSPEC_VUNDEF))]
    "TARGET_VECTOR"
    ""
    [(set_attr "type" "vector")])
  
  (define_insn "@vundefined<mode>"
!   [(set (match_operand:VB_VLS 0 "register_operand" "=vr")
! 	(unspec:VB_VLS [(reg:SI X0_REGNUM)] UNSPEC_VUNDEF))]
    "TARGET_VECTOR"
    ""
    [(set_attr "type" "vector")])
***************
*** 1054,1060 ****
    [(set_attr "type" "vector")])
  
  (define_expand "@vreinterpret<mode>"
!   [(set (match_operand:V 0 "register_operand")
  	(match_operand 1 "vector_any_register_operand"))]
    "TARGET_VECTOR"
    {
--- 1054,1060 ----
    [(set_attr "type" "vector")])
  
  (define_expand "@vreinterpret<mode>"
!   [(set (match_operand:V_VLS 0 "register_operand")
  	(match_operand 1 "vector_any_register_operand"))]
    "TARGET_VECTOR"
    {
***************
*** 1974,1988 ****
  ;; Dedicated pattern for vse.v instruction since we can't reuse pred_mov pattern to include
  ;; memory operand as input which will produce inferior codegen.
  (define_insn "@pred_store<mode>"
!   [(set (match_operand:V 0 "memory_operand"                 "+m")
! 	(if_then_else:V
  	  (unspec:<VM>
  	    [(match_operand:<VM> 1 "vector_mask_operand" "vmWc1")
  	     (match_operand 3 "vector_length_operand"    "  rvl")
  	     (match_operand 4 "const_int_operand"        "    i")
  	     (reg:SI VL_REGNUM)
  	     (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
! 	  (match_operand:V 2 "register_operand"         "    vr")
  	  (match_dup 0)))]
    "TARGET_VECTOR"
    "vse<sew>.v\t%2,%0%p1"
--- 1974,1988 ----
  ;; Dedicated pattern for vse.v instruction since we can't reuse pred_mov pattern to include
  ;; memory operand as input which will produce inferior codegen.
  (define_insn "@pred_store<mode>"
!   [(set (match_operand:V_VLS 0 "memory_operand"                 "+m")
! 	(if_then_else:V_VLS
  	  (unspec:<VM>
  	    [(match_operand:<VM> 1 "vector_mask_operand" "vmWc1")
  	     (match_operand 3 "vector_length_operand"    "  rvl")
  	     (match_operand 4 "const_int_operand"        "    i")
  	     (reg:SI VL_REGNUM)
  	     (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
! 	  (match_operand:V_VLS 2 "register_operand"         "    vr")
  	  (match_dup 0)))]
    "TARGET_VECTOR"
    "vse<sew>.v\t%2,%0%p1"
***************
*** 2680,2686 ****
    [(set_attr "type" "vld<order>x")
     (set_attr "mode" "<MODE>")])
  
! (define_insn "@pred_indexed_<order>store<RATIO64:mode><RATIO64I:mode>"
    [(set (mem:BLK (scratch))
  	(unspec:BLK
  	  [(unspec:<VM>
--- 2680,2686 ----
    [(set_attr "type" "vld<order>x")
     (set_attr "mode" "<MODE>")])
  
! (define_insn "@pred_indexed_<order>store<mode>_same_eew"
    [(set (mem:BLK (scratch))
  	(unspec:BLK
  	  [(unspec:<VM>
***************
*** 2690,2703 ****
  	     (reg:SI VL_REGNUM)
  	     (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
  	   (match_operand 1 "pmode_reg_or_0_operand"      "  rJ")
! 	   (match_operand:RATIO64I 2 "register_operand" "  vr")
! 	   (match_operand:RATIO64 3 "register_operand"  "  vr")] ORDER))]
    "TARGET_VECTOR"
!   "vs<order>xei<RATIO64I:sew>.v\t%3,(%z1),%2%p0"
    [(set_attr "type" "vst<order>x")
!    (set_attr "mode" "<RATIO64:MODE>")])
  
! (define_insn "@pred_indexed_<order>store<RATIO32:mode><RATIO32I:mode>"
    [(set (mem:BLK (scratch))
  	(unspec:BLK
  	  [(unspec:<VM>
--- 2690,2703 ----
  	     (reg:SI VL_REGNUM)
  	     (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
  	   (match_operand 1 "pmode_reg_or_0_operand"      "  rJ")
! 	   (match_operand:<VINDEX> 2 "register_operand" "  vr")
! 	   (match_operand:VINDEXED 3 "register_operand"  "  vr")] ORDER))]
    "TARGET_VECTOR"
!   "vs<order>xei<sew>.v\t%3,(%z1),%2%p0"
    [(set_attr "type" "vst<order>x")
!    (set_attr "mode" "<MODE>")])
  
! (define_insn "@pred_indexed_<order>store<mode>_x2_greater_eew"
    [(set (mem:BLK (scratch))
  	(unspec:BLK
  	  [(unspec:<VM>
***************
*** 2707,2720 ****
  	     (reg:SI VL_REGNUM)
  	     (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
  	   (match_operand 1 "pmode_reg_or_0_operand"      "  rJ")
! 	   (match_operand:RATIO32I 2 "register_operand" "  vr")
! 	   (match_operand:RATIO32 3 "register_operand"  "  vr")] ORDER))]
    "TARGET_VECTOR"
!   "vs<order>xei<RATIO32I:sew>.v\t%3,(%z1),%2%p0"
    [(set_attr "type" "vst<order>x")
!    (set_attr "mode" "<RATIO32:MODE>")])
  
! (define_insn "@pred_indexed_<order>store<RATIO16:mode><RATIO16I:mode>"
    [(set (mem:BLK (scratch))
  	(unspec:BLK
  	  [(unspec:<VM>
--- 2707,2720 ----
  	     (reg:SI VL_REGNUM)
  	     (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
  	   (match_operand 1 "pmode_reg_or_0_operand"      "  rJ")
! 	   (match_operand:<VINDEX_DOUBLE_TRUNC> 2 "register_operand" "  vr")
! 	   (match_operand:VEEWEXT2 3 "register_operand"  "  vr")] ORDER))]
    "TARGET_VECTOR"
!   "vs<order>xei<double_trunc_sew>.v\t%3,(%z1),%2%p0"
    [(set_attr "type" "vst<order>x")
!    (set_attr "mode" "<MODE>")])
  
! (define_insn "@pred_indexed_<order>store<mode>_x4_greater_eew"
    [(set (mem:BLK (scratch))
  	(unspec:BLK
  	  [(unspec:<VM>
***************
*** 2724,2737 ****
  	     (reg:SI VL_REGNUM)
  	     (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
  	   (match_operand 1 "pmode_reg_or_0_operand"      "  rJ")
! 	   (match_operand:RATIO16I 2 "register_operand" "  vr")
! 	   (match_operand:RATIO16 3 "register_operand"  "  vr")] ORDER))]
    "TARGET_VECTOR"
!   "vs<order>xei<RATIO16I:sew>.v\t%3,(%z1),%2%p0"
    [(set_attr "type" "vst<order>x")
!    (set_attr "mode" "<RATIO16:MODE>")])
  
! (define_insn "@pred_indexed_<order>store<RATIO8:mode><RATIO8I:mode>"
    [(set (mem:BLK (scratch))
  	(unspec:BLK
  	  [(unspec:<VM>
--- 2724,2737 ----
  	     (reg:SI VL_REGNUM)
  	     (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
  	   (match_operand 1 "pmode_reg_or_0_operand"      "  rJ")
! 	   (match_operand:<VINDEX_QUAD_TRUNC> 2 "register_operand" "  vr")
! 	   (match_operand:VEEWEXT4 3 "register_operand"  "  vr")] ORDER))]
    "TARGET_VECTOR"
!   "vs<order>xei<quad_trunc_sew>.v\t%3,(%z1),%2%p0"
    [(set_attr "type" "vst<order>x")
!    (set_attr "mode" "<MODE>")])
  
! (define_insn "@pred_indexed_<order>store<mode>_x8_greater_eew"
    [(set (mem:BLK (scratch))
  	(unspec:BLK
  	  [(unspec:<VM>
***************
*** 2741,2754 ****
  	     (reg:SI VL_REGNUM)
  	     (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
  	   (match_operand 1 "pmode_reg_or_0_operand"      "  rJ")
! 	   (match_operand:RATIO8I 2 "register_operand" "  vr")
! 	   (match_operand:RATIO8 3 "register_operand"  "  vr")] ORDER))]
    "TARGET_VECTOR"
!   "vs<order>xei<RATIO8I:sew>.v\t%3,(%z1),%2%p0"
    [(set_attr "type" "vst<order>x")
!    (set_attr "mode" "<RATIO8:MODE>")])
  
! (define_insn "@pred_indexed_<order>store<RATIO4:mode><RATIO4I:mode>"
    [(set (mem:BLK (scratch))
  	(unspec:BLK
  	  [(unspec:<VM>
--- 2741,2754 ----
  	     (reg:SI VL_REGNUM)
  	     (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
  	   (match_operand 1 "pmode_reg_or_0_operand"      "  rJ")
! 	   (match_operand:<VINDEX_OCT_TRUNC> 2 "register_operand" "  vr")
! 	   (match_operand:VEEWEXT8 3 "register_operand"  "  vr")] ORDER))]
    "TARGET_VECTOR"
!   "vs<order>xei<quad_trunc_sew>.v\t%3,(%z1),%2%p0"
    [(set_attr "type" "vst<order>x")
!    (set_attr "mode" "<MODE>")])
  
! (define_insn "@pred_indexed_<order>store<mode>_x2_smaller_eew"
    [(set (mem:BLK (scratch))
  	(unspec:BLK
  	  [(unspec:<VM>
***************
*** 2758,2771 ****
  	     (reg:SI VL_REGNUM)
  	     (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
  	   (match_operand 1 "pmode_reg_or_0_operand"      "  rJ")
! 	   (match_operand:RATIO4I 2 "register_operand" "  vr")
! 	   (match_operand:RATIO4 3 "register_operand"  "  vr")] ORDER))]
    "TARGET_VECTOR"
!   "vs<order>xei<RATIO4I:sew>.v\t%3,(%z1),%2%p0"
    [(set_attr "type" "vst<order>x")
!    (set_attr "mode" "<RATIO4:MODE>")])
  
! (define_insn "@pred_indexed_<order>store<RATIO2:mode><RATIO2I:mode>"
    [(set (mem:BLK (scratch))
  	(unspec:BLK
  	  [(unspec:<VM>
--- 2758,2771 ----
  	     (reg:SI VL_REGNUM)
  	     (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
  	   (match_operand 1 "pmode_reg_or_0_operand"      "  rJ")
! 	   (match_operand:<VINDEX_DOUBLE_EXT> 2 "register_operand" "  vr")
! 	   (match_operand:VEEWTRUNC2 3 "register_operand"  "  vr")] ORDER))]
    "TARGET_VECTOR"
!   "vs<order>xei<double_ext_sew>.v\t%3,(%z1),%2%p0"
    [(set_attr "type" "vst<order>x")
!    (set_attr "mode" "<MODE>")])
  
! (define_insn "@pred_indexed_<order>store<mode>_x4_smaller_eew"
    [(set (mem:BLK (scratch))
  	(unspec:BLK
  	  [(unspec:<VM>
***************
*** 2774,2788 ****
  	     (match_operand 5 "const_int_operand"        "    i")
  	     (reg:SI VL_REGNUM)
  	     (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
! 	   (match_operand 1 "pmode_reg_or_0_operand"       "  rJ")
! 	   (match_operand:RATIO2I 2 "register_operand"  "  vr")
! 	   (match_operand:RATIO2 3 "register_operand"   "  vr")] ORDER))]
    "TARGET_VECTOR"
!   "vs<order>xei<RATIO2I:sew>.v\t%3,(%z1),%2%p0"
    [(set_attr "type" "vst<order>x")
!    (set_attr "mode" "<RATIO2:MODE>")])
  
! (define_insn "@pred_indexed_<order>store<RATIO1:mode><RATIO1:mode>"
    [(set (mem:BLK (scratch))
  	(unspec:BLK
  	  [(unspec:<VM>
--- 2774,2788 ----
  	     (match_operand 5 "const_int_operand"        "    i")
  	     (reg:SI VL_REGNUM)
  	     (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
! 	   (match_operand 1 "pmode_reg_or_0_operand"      "  rJ")
! 	   (match_operand:<VINDEX_QUAD_EXT> 2 "register_operand" "  vr")
! 	   (match_operand:VEEWTRUNC4 3 "register_operand"  "  vr")] ORDER))]
    "TARGET_VECTOR"
!   "vs<order>xei<quad_ext_sew>.v\t%3,(%z1),%2%p0"
    [(set_attr "type" "vst<order>x")
!    (set_attr "mode" "<MODE>")])
  
! (define_insn "@pred_indexed_<order>store<mode>_x8_smaller_eew"
    [(set (mem:BLK (scratch))
  	(unspec:BLK
  	  [(unspec:<VM>
***************
*** 2792,2803 ****
  	     (reg:SI VL_REGNUM)
  	     (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
  	   (match_operand 1 "pmode_reg_or_0_operand"       "  rJ")
! 	   (match_operand:RATIO1 2 "register_operand"   "  vr")
! 	   (match_operand:RATIO1 3 "register_operand"    "  vr")] ORDER))]
    "TARGET_VECTOR"
!   "vs<order>xei<RATIO1:sew>.v\t%3,(%z1),%2%p0"
    [(set_attr "type" "vst<order>x")
!    (set_attr "mode" "<RATIO1:MODE>")])
  
  ;; -------------------------------------------------------------------------------
  ;; ---- Predicated integer binary operations
--- 2792,2803 ----
  	     (reg:SI VL_REGNUM)
  	     (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
  	   (match_operand 1 "pmode_reg_or_0_operand"       "  rJ")
! 	   (match_operand:<VINDEX_OCT_EXT> 2 "register_operand"  "  vr")
! 	   (match_operand:VEEWTRUNC8 3 "register_operand"   "  vr")] ORDER))]
    "TARGET_VECTOR"
!   "vs<order>xei<oct_ext_sew>.v\t%3,(%z1),%2%p0"
    [(set_attr "type" "vst<order>x")
!    (set_attr "mode" "<MODE>")])
  
  ;; -------------------------------------------------------------------------------
  ;; ---- Predicated integer binary operations
***************
*** 6260,6273 ****
    [(set_attr "type" "vmpop")
     (set_attr "mode" "<VB_VLS:MODE>")])
  
! (define_insn "@pred_ffs<VB:mode><P:mode>"
    [(set (match_operand:P 0 "register_operand"                 "=r")
  	(plus:P
  	  (ffs:P
! 	    (unspec:VB
! 	      [(and:VB
! 	         (match_operand:VB 1 "vector_mask_operand" "vmWc1")
! 	         (match_operand:VB 2 "register_operand"    "   vr"))
  	       (match_operand 3 "vector_length_operand"    "  rvl")
  	       (match_operand 4 "const_int_operand"        "    i")
  	       (reg:SI VL_REGNUM)
--- 6260,6273 ----
    [(set_attr "type" "vmpop")
     (set_attr "mode" "<VB_VLS:MODE>")])
  
! (define_insn "@pred_ffs<VB_VLS:mode><P:mode>"
    [(set (match_operand:P 0 "register_operand"                 "=r")
  	(plus:P
  	  (ffs:P
! 	    (unspec:VB_VLS
! 	      [(and:VB_VLS
! 	         (match_operand:VB_VLS 1 "vector_mask_operand" "vmWc1")
! 	         (match_operand:VB_VLS 2 "register_operand"    "   vr"))
  	       (match_operand 3 "vector_length_operand"    "  rvl")
  	       (match_operand 4 "const_int_operand"        "    i")
  	       (reg:SI VL_REGNUM)
***************
*** 6276,6304 ****
    "TARGET_VECTOR"
    "vfirst.m\t%0,%2%p1"
    [(set_attr "type" "vmffs")
!    (set_attr "mode" "<VB:MODE>")])
  
  (define_insn "@pred_<misc_op><mode>"
!   [(set (match_operand:VB 0 "register_operand"          "=&vr,  &vr")
! 	(if_then_else:VB
! 	  (unspec:VB
! 	    [(match_operand:VB 1 "vector_mask_operand" "vmWc1,vmWc1")
  	     (match_operand 4 "vector_length_operand"  "  rvl,  rvl")
  	     (match_operand 5 "const_int_operand"      "    i,    i")
  	     (match_operand 6 "const_int_operand"      "    i,    i")
  	     (reg:SI VL_REGNUM)
  	     (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
! 	  (unspec:VB
! 	    [(match_operand:VB 3 "register_operand"    "   vr,   vr")] VMISC)
! 	  (match_operand:VB 2 "vector_merge_operand"   "   vu,    0")))]
    "TARGET_VECTOR"
    "vm<misc_op>.m\t%0,%3%p1"
    [(set_attr "type" "vmsfs")
     (set_attr "mode" "<MODE>")])
  
  (define_insn "@pred_iota<mode>"
!   [(set (match_operand:VI 0 "register_operand"            "=&vr,  &vr")
! 	(if_then_else:VI
  	  (unspec:<VM>
  	    [(match_operand:<VM> 1 "vector_mask_operand" "vmWc1,vmWc1")
  	     (match_operand 4 "vector_length_operand"    "  rvl,  rvl")
--- 6276,6304 ----
    "TARGET_VECTOR"
    "vfirst.m\t%0,%2%p1"
    [(set_attr "type" "vmffs")
!    (set_attr "mode" "<VB_VLS:MODE>")])
  
  (define_insn "@pred_<misc_op><mode>"
!   [(set (match_operand:VB_VLS 0 "register_operand"          "=&vr,  &vr")
! 	(if_then_else:VB_VLS
! 	  (unspec:VB_VLS
! 	    [(match_operand:VB_VLS 1 "vector_mask_operand" "vmWc1,vmWc1")
  	     (match_operand 4 "vector_length_operand"  "  rvl,  rvl")
  	     (match_operand 5 "const_int_operand"      "    i,    i")
  	     (match_operand 6 "const_int_operand"      "    i,    i")
  	     (reg:SI VL_REGNUM)
  	     (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
! 	  (unspec:VB_VLS
! 	    [(match_operand:VB_VLS 3 "register_operand"    "   vr,   vr")] VMISC)
! 	  (match_operand:VB_VLS 2 "vector_merge_operand"   "   vu,    0")))]
    "TARGET_VECTOR"
    "vm<misc_op>.m\t%0,%3%p1"
    [(set_attr "type" "vmsfs")
     (set_attr "mode" "<MODE>")])
  
  (define_insn "@pred_iota<mode>"
!   [(set (match_operand:V_VLSI 0 "register_operand"            "=&vr,  &vr")
! 	(if_then_else:V_VLSI
  	  (unspec:<VM>
  	    [(match_operand:<VM> 1 "vector_mask_operand" "vmWc1,vmWc1")
  	     (match_operand 4 "vector_length_operand"    "  rvl,  rvl")
***************
*** 6307,6315 ****
  	     (match_operand 7 "const_int_operand"        "    i,    i")
  	     (reg:SI VL_REGNUM)
  	     (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
! 	  (unspec:VI
  	    [(match_operand:<VM> 3 "register_operand"    "   vr,   vr")] UNSPEC_VIOTA)
! 	  (match_operand:VI 2 "vector_merge_operand"     "   vu,    0")))]
    "TARGET_VECTOR"
    "viota.m\t%0,%3%p1"
    [(set_attr "type" "vmiota")
--- 6307,6315 ----
  	     (match_operand 7 "const_int_operand"        "    i,    i")
  	     (reg:SI VL_REGNUM)
  	     (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
! 	  (unspec:V_VLSI
  	    [(match_operand:<VM> 3 "register_operand"    "   vr,   vr")] UNSPEC_VIOTA)
! 	  (match_operand:V_VLSI 2 "vector_merge_operand"     "   vu,    0")))]
    "TARGET_VECTOR"
    "viota.m\t%0,%3%p1"
    [(set_attr "type" "vmiota")
***************
*** 6547,6554 ****
     (set_attr "mode" "<MODE>")])
  
  (define_insn "@pred_ncopysign<mode>"
!   [(set (match_operand:VF 0 "register_operand"           "=vd, vd, vr, vr")
! 	(if_then_else:VF
  	  (unspec:<VM>
  	    [(match_operand:<VM> 1 "vector_mask_operand" " vm, vm,Wc1,Wc1")
  	     (match_operand 5 "vector_length_operand"    "rvl,rvl,rvl,rvl")
--- 6547,6554 ----
     (set_attr "mode" "<MODE>")])
  
  (define_insn "@pred_ncopysign<mode>"
!   [(set (match_operand:V_VLSF 0 "register_operand"           "=vd, vd, vr, vr")
! 	(if_then_else:V_VLSF
  	  (unspec:<VM>
  	    [(match_operand:<VM> 1 "vector_mask_operand" " vm, vm,Wc1,Wc1")
  	     (match_operand 5 "vector_length_operand"    "rvl,rvl,rvl,rvl")
***************
*** 6557,6567 ****
  	     (match_operand 8 "const_int_operand"        "  i,  i,  i,  i")
  	     (reg:SI VL_REGNUM)
  	     (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
! 	  (neg:VF
! 	    (unspec:VF
! 	      [(match_operand:VF 3 "register_operand"       " vr, vr, vr, vr")
! 	       (match_operand:VF 4 "register_operand"       " vr, vr, vr, vr")] UNSPEC_VCOPYSIGN))
! 	  (match_operand:VF 2 "vector_merge_operand"     " vu,  0, vu,  0")))]
    "TARGET_VECTOR"
    "vfsgnjn.vv\t%0,%3,%4%p1"
    [(set_attr "type" "vfsgnj")
--- 6557,6567 ----
  	     (match_operand 8 "const_int_operand"        "  i,  i,  i,  i")
  	     (reg:SI VL_REGNUM)
  	     (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
! 	  (neg:V_VLSF
! 	    (unspec:V_VLSF
! 	      [(match_operand:V_VLSF 3 "register_operand"       " vr, vr, vr, vr")
! 	       (match_operand:V_VLSF 4 "register_operand"       " vr, vr, vr, vr")] UNSPEC_VCOPYSIGN))
! 	  (match_operand:V_VLSF 2 "vector_merge_operand"     " vu,  0, vu,  0")))]
    "TARGET_VECTOR"
    "vfsgnjn.vv\t%0,%3,%4%p1"
    [(set_attr "type" "vfsgnj")
***************
*** 6589,6596 ****
     (set_attr "mode" "<MODE>")])
  
  (define_insn "@pred_ncopysign<mode>_scalar"
!   [(set (match_operand:VF 0 "register_operand"           "=vd, vd, vr, vr")
! 	(if_then_else:VF
  	  (unspec:<VM>
  	    [(match_operand:<VM> 1 "vector_mask_operand" " vm, vm,Wc1,Wc1")
  	     (match_operand 5 "vector_length_operand"    "rvl,rvl,rvl,rvl")
--- 6589,6596 ----
     (set_attr "mode" "<MODE>")])
  
  (define_insn "@pred_ncopysign<mode>_scalar"
!   [(set (match_operand:V_VLSF 0 "register_operand"           "=vd, vd, vr, vr")
! 	(if_then_else:V_VLSF
  	  (unspec:<VM>
  	    [(match_operand:<VM> 1 "vector_mask_operand" " vm, vm,Wc1,Wc1")
  	     (match_operand 5 "vector_length_operand"    "rvl,rvl,rvl,rvl")
***************
*** 6599,6610 ****
  	     (match_operand 8 "const_int_operand"        "  i,  i,  i,  i")
  	     (reg:SI VL_REGNUM)
  	     (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
! 	  (neg:VF
! 	    (unspec:VF
! 	      [(match_operand:VF 3 "register_operand"      " vr, vr, vr, vr")
! 	       (vec_duplicate:VF
  		 (match_operand:<VEL> 4 "register_operand" "  f,  f,  f,  f"))] UNSPEC_VCOPYSIGN))
! 	  (match_operand:VF 2 "vector_merge_operand"     " vu,  0, vu,  0")))]
    "TARGET_VECTOR"
    "vfsgnjn.vf\t%0,%3,%4%p1"
    [(set_attr "type" "vfsgnj")
--- 6599,6610 ----
  	     (match_operand 8 "const_int_operand"        "  i,  i,  i,  i")
  	     (reg:SI VL_REGNUM)
  	     (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
! 	  (neg:V_VLSF
! 	    (unspec:V_VLSF
! 	      [(match_operand:V_VLSF 3 "register_operand"      " vr, vr, vr, vr")
! 	       (vec_duplicate:V_VLSF
  		 (match_operand:<VEL> 4 "register_operand" "  f,  f,  f,  f"))] UNSPEC_VCOPYSIGN))
! 	  (match_operand:V_VLSF 2 "vector_merge_operand"     " vu,  0, vu,  0")))]
    "TARGET_VECTOR"
    "vfsgnjn.vf\t%0,%3,%4%p1"
    [(set_attr "type" "vfsgnj")
***************
*** 7175,7182 ****
     (set (attr "avl_type_idx") (const_int 7))])
  
  (define_insn "@pred_<misc_op><mode>"
!   [(set (match_operand:VF 0 "register_operand"           "=vd, vd, vr, vr")
! 	(if_then_else:VF
  	  (unspec:<VM>
  	    [(match_operand:<VM> 1 "vector_mask_operand" " vm, vm,Wc1,Wc1")
  	     (match_operand 4 "vector_length_operand"    "rvl,rvl,rvl,rvl")
--- 7175,7182 ----
     (set (attr "avl_type_idx") (const_int 7))])
  
  (define_insn "@pred_<misc_op><mode>"
!   [(set (match_operand:V_VLSF 0 "register_operand"           "=vd, vd, vr, vr")
! 	(if_then_else:V_VLSF
  	  (unspec:<VM>
  	    [(match_operand:<VM> 1 "vector_mask_operand" " vm, vm,Wc1,Wc1")
  	     (match_operand 4 "vector_length_operand"    "rvl,rvl,rvl,rvl")
***************
*** 7185,7201 ****
  	     (match_operand 7 "const_int_operand"        "  i,  i,  i,  i")
  	     (reg:SI VL_REGNUM)
  	     (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
! 	  (unspec:VF
! 	    [(match_operand:VF 3 "register_operand"       " vr, vr, vr, vr")] VFMISC)
! 	  (match_operand:VF 2 "vector_merge_operand"     " vu,  0, vu,  0")))]
    "TARGET_VECTOR"
    "vf<misc_op>.v\t%0,%3%p1"
    [(set_attr "type" "<float_insn_type>")
     (set_attr "mode" "<MODE>")])
  
  (define_insn "@pred_<misc_frm_op><mode>"
!   [(set (match_operand:VF 0 "register_operand"           "=vd, vd, vr, vr")
! 	(if_then_else:VF
  	  (unspec:<VM>
  	    [(match_operand:<VM> 1 "vector_mask_operand" " vm, vm,Wc1,Wc1")
  	     (match_operand 4 "vector_length_operand"    "rvl,rvl,rvl,rvl")
--- 7185,7201 ----
  	     (match_operand 7 "const_int_operand"        "  i,  i,  i,  i")
  	     (reg:SI VL_REGNUM)
  	     (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
! 	  (unspec:V_VLSF
! 	    [(match_operand:V_VLSF 3 "register_operand"       " vr, vr, vr, vr")] VFMISC)
! 	  (match_operand:V_VLSF 2 "vector_merge_operand"     " vu,  0, vu,  0")))]
    "TARGET_VECTOR"
    "vf<misc_op>.v\t%0,%3%p1"
    [(set_attr "type" "<float_insn_type>")
     (set_attr "mode" "<MODE>")])
  
  (define_insn "@pred_<misc_frm_op><mode>"
!   [(set (match_operand:V_VLSF 0 "register_operand"           "=vd, vd, vr, vr")
! 	(if_then_else:V_VLSF
  	  (unspec:<VM>
  	    [(match_operand:<VM> 1 "vector_mask_operand" " vm, vm,Wc1,Wc1")
  	     (match_operand 4 "vector_length_operand"    "rvl,rvl,rvl,rvl")
***************
*** 7206,7214 ****
  	     (reg:SI VL_REGNUM)
  	     (reg:SI VTYPE_REGNUM)
  	     (reg:SI FRM_REGNUM)] UNSPEC_VPREDICATE)
! 	  (unspec:VF
! 	    [(match_operand:VF 3 "register_operand"       " vr, vr, vr, vr")] VFMISC_FRM)
! 	  (match_operand:VF 2 "vector_merge_operand"     " vu,  0, vu,  0")))]
    "TARGET_VECTOR"
    "vf<misc_frm_op>.v\t%0,%3%p1"
    [(set_attr "type" "<float_frm_insn_type>")
--- 7206,7214 ----
  	     (reg:SI VL_REGNUM)
  	     (reg:SI VTYPE_REGNUM)
  	     (reg:SI FRM_REGNUM)] UNSPEC_VPREDICATE)
! 	  (unspec:V_VLSF
! 	    [(match_operand:V_VLSF 3 "register_operand"       " vr, vr, vr, vr")] VFMISC_FRM)
! 	  (match_operand:V_VLSF 2 "vector_merge_operand"     " vu,  0, vu,  0")))]
    "TARGET_VECTOR"
    "vf<misc_frm_op>.v\t%0,%3%p1"
    [(set_attr "type" "<float_frm_insn_type>")
***************
*** 7228,7234 ****
  	     (reg:SI VL_REGNUM)
  	     (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
  	  (unspec:<VCONVERT>
! 	    [(match_operand:VF 3 "register_operand"          " vr, vr, vr, vr")] UNSPEC_VFCLASS)
  	  (match_operand:<VCONVERT> 2 "vector_merge_operand" " vu,  0, vu,  0")))]
    "TARGET_VECTOR"
    "vfclass.v\t%0,%3%p1"
--- 7228,7234 ----
  	     (reg:SI VL_REGNUM)
  	     (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
  	  (unspec:<VCONVERT>
! 	    [(match_operand:V_VLSF 3 "register_operand"          " vr, vr, vr, vr")] UNSPEC_VFCLASS)
  	  (match_operand:<VCONVERT> 2 "vector_merge_operand" " vu,  0, vu,  0")))]
    "TARGET_VECTOR"
    "vfclass.v\t%0,%3%p1"
***************
*** 8552,8559 ****
     (set_attr "mode" "DI")])
  
  (define_insn "@pred_fault_load<mode>"
!   [(set (match_operand:V 0 "register_operand"              "=vd,    vd,    vr,    vr")
! 	(if_then_else:V
  	  (unspec:<VM>
  	    [(match_operand:<VM> 1 "vector_mask_operand" "   vm,    vm,   Wc1,   Wc1")
  	     (match_operand 4 "vector_length_operand"    "  rvl,   rvl,   rvl,   rvl")
--- 8552,8559 ----
     (set_attr "mode" "DI")])
  
  (define_insn "@pred_fault_load<mode>"
!   [(set (match_operand:V_VLS 0 "register_operand"              "=vd,    vd,    vr,    vr")
! 	(if_then_else:V_VLS
  	  (unspec:<VM>
  	    [(match_operand:<VM> 1 "vector_mask_operand" "   vm,    vm,   Wc1,   Wc1")
  	     (match_operand 4 "vector_length_operand"    "  rvl,   rvl,   rvl,   rvl")
***************
*** 8562,8578 ****
  	     (match_operand 7 "const_int_operand"        "    i,     i,     i,     i")
  	     (reg:SI VL_REGNUM)
  	     (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
! 	  (unspec:V
! 	    [(match_operand:V 3 "memory_operand"         "    m,     m,     m,     m")] UNSPEC_VLEFF)
! 	  (match_operand:V 2 "vector_merge_operand"      "   vu,     0,    vu,     0")))
     (set (reg:SI VL_REGNUM)
  	  (unspec:SI
! 	    [(if_then_else:V
  	       (unspec:<VM>
  		[(match_dup 1) (match_dup 4) (match_dup 5)
  		 (match_dup 6) (match_dup 7)
  		 (reg:SI VL_REGNUM) (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
! 	       (unspec:V [(match_dup 3)] UNSPEC_VLEFF)
  	       (match_dup 2))] UNSPEC_MODIFY_VL))]
    "TARGET_VECTOR"
    "vle<sew>ff.v\t%0,%3%p1"
--- 8562,8578 ----
  	     (match_operand 7 "const_int_operand"        "    i,     i,     i,     i")
  	     (reg:SI VL_REGNUM)
  	     (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
! 	  (unspec:V_VLS
! 	    [(match_operand:V_VLS 3 "memory_operand"         "    m,     m,     m,     m")] UNSPEC_VLEFF)
! 	  (match_operand:V_VLS 2 "vector_merge_operand"      "   vu,     0,    vu,     0")))
     (set (reg:SI VL_REGNUM)
  	  (unspec:SI
! 	    [(if_then_else:V_VLS
  	       (unspec:<VM>
  		[(match_dup 1) (match_dup 4) (match_dup 5)
  		 (match_dup 6) (match_dup 7)
  		 (reg:SI VL_REGNUM) (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
! 	       (unspec:V_VLS [(match_dup 3)] UNSPEC_VLEFF)
  	       (match_dup 2))] UNSPEC_MODIFY_VL))]
    "TARGET_VECTOR"
    "vle<sew>ff.v\t%0,%3%p1"
diff -Nrcpad gcc-16-20251214/gcc/config/rs6000/rs6000.h gcc-16-20251221/gcc/config/rs6000/rs6000.h
*** gcc-16-20251214/gcc/config/rs6000/rs6000.h	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/rs6000/rs6000.h	Sun Dec 21 22:32:06 2025
*************** extern int rs6000_vector_align[];
*** 550,556 ****
  			 && (TARGET_PPC_GFXOPT || VECTOR_UNIT_VSX_P (DFmode)))
  
  /* Macro to say whether we can do optimizations where we need to do parts of
!    the calculation in 64-bit GPRs and then is transfered to the vector
     registers.  */
  #define TARGET_DIRECT_MOVE_64BIT	(TARGET_DIRECT_MOVE		\
  					 && TARGET_POWERPC64)
--- 550,556 ----
  			 && (TARGET_PPC_GFXOPT || VECTOR_UNIT_VSX_P (DFmode)))
  
  /* Macro to say whether we can do optimizations where we need to do parts of
!    the calculation in 64-bit GPRs and then is transferred to the vector
     registers.  */
  #define TARGET_DIRECT_MOVE_64BIT	(TARGET_DIRECT_MOVE		\
  					 && TARGET_POWERPC64)
diff -Nrcpad gcc-16-20251214/gcc/config/s390/s390.cc gcc-16-20251221/gcc/config/s390/s390.cc
*** gcc-16-20251214/gcc/config/s390/s390.cc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config/s390/s390.cc	Sun Dec 21 22:32:06 2025
*************** s390_encode_section_info (tree decl, rtx
*** 14273,14279 ****
  	 -munaligned-symbols switch.
  	 For all external symbols without explicit alignment
  	 DECL_ALIGN is already trimmed down to 8, however for weak
! 	 symbols this does not happen.  These cases are catched by the
  	 type size check.  */
        const_tree size = TYPE_SIZE (TREE_TYPE (decl));
        unsigned HOST_WIDE_INT size_num = (tree_fits_uhwi_p (size)
--- 14273,14279 ----
  	 -munaligned-symbols switch.
  	 For all external symbols without explicit alignment
  	 DECL_ALIGN is already trimmed down to 8, however for weak
! 	 symbols this does not happen.  These cases are caught by the
  	 type size check.  */
        const_tree size = TYPE_SIZE (TREE_TYPE (decl));
        unsigned HOST_WIDE_INT size_num = (tree_fits_uhwi_p (size)
diff -Nrcpad gcc-16-20251214/gcc/config/xtensa/predicates.md gcc-16-20251221/gcc/config/xtensa/predicates.md
*** gcc-16-20251214/gcc/config/xtensa/predicates.md	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/config/xtensa/predicates.md	Sun Dec 21 22:32:06 2025
***************
*** 202,208 ****
    (match_code "plus,minus"))
  
  (define_predicate "xtensa_cstoresi_operator"
!   (match_code "eq,ne,gt,ge,lt,le,gtu,geu,ltu,leu"))
  
  (define_predicate "xtensa_shift_per_byte_operator"
    (match_code "ashift,ashiftrt,lshiftrt"))
--- 202,210 ----
    (match_code "plus,minus"))
  
  (define_predicate "xtensa_cstoresi_operator"
!   (if_then_else (match_test "TARGET_SALT")
! 		(match_code "eq,ne,gt,ge,lt,le,gtu,geu,ltu,leu")
! 		(match_code "eq,ne,gt,ge,lt,le")))
  
  (define_predicate "xtensa_shift_per_byte_operator"
    (match_code "ashift,ashiftrt,lshiftrt"))
diff -Nrcpad gcc-16-20251214/gcc/config/xtensa/xtensa.cc gcc-16-20251221/gcc/config/xtensa/xtensa.cc
*** gcc-16-20251214/gcc/config/xtensa/xtensa.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/config/xtensa/xtensa.cc	Sun Dec 21 22:32:06 2025
*************** xtensa_expand_conditional_move (rtx *ope
*** 993,1062 ****
  }
  
  
! int
! xtensa_expand_scc (rtx operands[4], machine_mode cmp_mode)
  {
!   rtx dest = operands[0];
!   rtx cmp;
!   rtx one_tmp, zero_tmp;
!   rtx (*gen_fn) (rtx, rtx, rtx, rtx, rtx);
  
!   if (cmp_mode == SImode && TARGET_SALT)
      {
!       rtx a = operands[2], b = force_reg (SImode, operands[3]);
!       enum rtx_code code = GET_CODE (operands[1]);
!       bool invert_res = false;
  
!       switch (code)
! 	{
! 	case GE:
! 	case GEU:
! 	  invert_res = true;
! 	  break;
! 	case GT:
! 	case GTU:
! 	  std::swap (a, b);
! 	  break;
! 	case LE:
! 	case LEU:
! 	  invert_res = true;
! 	  std::swap (a, b);
! 	  break;
! 	default:
! 	  break;
! 	}
  
!       switch (code)
! 	{
! 	case GE:
! 	case GT:
! 	case LE:
! 	case LT:
! 	  emit_insn (gen_salt (dest, a, b));
! 	  if (!invert_res)
! 	    return 1;
! 	  break;
! 	case GEU:
! 	case GTU:
! 	case LEU:
! 	case LTU:
! 	  emit_insn (gen_saltu (dest, a, b));
! 	  if (!invert_res)
! 	    return 1;
! 	  break;
! 	default:
! 	  break;
! 	}
  
!       if (invert_res)
! 	{
! 	  emit_insn (gen_negsi2 (dest, dest));
! 	  emit_insn (gen_addsi3 (dest, dest, const1_rtx));
! 	  return 1;
! 	}
!     }
  
!   if (! (cmp = gen_conditional_move (GET_CODE (operands[1]), cmp_mode,
  				     operands[2], operands[3])))
      return 0;
  
--- 993,1063 ----
  }
  
  
! static bool
! xtensa_expand_scc_SALT (rtx dest, enum rtx_code code, rtx op0, rtx op1)
  {
!   int flags;
  
!   /* Revert back the canonicalization of '(lt[u]:SI (reg:SI) (const_int N)'
!      to '(le[u]:SI (reg:SI) (const_int N-1)'.
!      Note that a comparison like '(le[u]:SI (reg:SI) (const_int [U]INT_MAX))'
!      will never be passed; because the result of such a comparison is a mere
!      constant.  */
!   if (CONST_INT_P (op1))
!     switch (code)
!       {
!       case LE:
! 	code = LT, op1 = GEN_INT (INTVAL (op1) + 1);
! 	break;
!       case LEU:
! 	code = LTU, op1 = GEN_INT (UINTVAL (op1) + 1u);
! 	break;
!       default:
! 	break;
!       }
! 
!   /* b0: inverting, b1: swap(op0,op1), b2: unsigned */
!   switch (code)
      {
!     case GE:	flags = 1; break;
!     case GT:	flags = 2; break;
!     case LE:	flags = 3; break;
!     case LT:	flags = 0; break;
!     case GEU:	flags = 5; break;
!     case GTU:	flags = 6; break;
!     case LEU:	flags = 7; break;
!     case LTU:	flags = 4; break;
!     default:	return false;
!     }
  
!   op1 = force_reg (SImode, op1);
!   if (flags & 2)
!     std::swap (op0, op1);
!   emit_insn ((flags & 4) ? gen_saltu (dest, op0, op1)
! 			 : gen_salt (dest, op0, op1));
!   if (flags & 1)
!     /* XORing with a temporary register with a value of 1 is advantageous
!        over negation followed by addition of 1 because the temporary register
!        assignment can be subject to CSE, constant propagation, or loop-
!        invariant hoisting.  */
!     emit_insn (gen_xorsi3 (dest, dest, force_reg (SImode, const1_rtx)));
  
!   return true;
! }
  
! int
! xtensa_expand_scc (rtx operands[4], machine_mode cmp_mode)
! {
!   rtx dest = operands[0];
!   rtx cmp, one_tmp, zero_tmp;
!   rtx (*gen_fn) (rtx, rtx, rtx, rtx, rtx);
!   enum rtx_code code = GET_CODE (operands[1]);
  
!   if (TARGET_SALT && cmp_mode == SImode
!       && xtensa_expand_scc_SALT (dest, code, operands[2], operands[3]))
!     return 1;
! 
!   if (! (cmp = gen_conditional_move (code, cmp_mode,
  				     operands[2], operands[3])))
      return 0;
  
*************** xtensa_expand_block_set_libcall (rtx dst
*** 1425,1431 ****
  				 HOST_WIDE_INT bytes)
  {
    rtx reg;
-   rtx_insn *seq;
  
    start_sequence ();
  
--- 1426,1431 ----
*************** xtensa_expand_block_set_libcall (rtx dst
*** 1439,1447 ****
  		     GEN_INT (value), SImode,
  		     GEN_INT (bytes), SImode);
  
!   seq = end_sequence ();
! 
!   return seq;
  }
  
  /* Worker function for xtensa_expand_block_set().
--- 1439,1445 ----
  		     GEN_INT (value), SImode,
  		     GEN_INT (bytes), SImode);
  
!   return end_sequence ();
  }
  
  /* Worker function for xtensa_expand_block_set().
*************** xtensa_expand_block_set_unrolled_loop (r
*** 1458,1464 ****
  {
    rtx reg;
    int offset;
-   rtx_insn *seq;
  
    if (bytes > 64)
      return NULL;
--- 1456,1461 ----
*************** xtensa_expand_block_set_unrolled_loop (r
*** 1500,1508 ****
      }
    while (bytes > 0);
  
!   seq = end_sequence ();
! 
!   return seq;
  }
  
  /* Worker function for xtensa_expand_block_set(),
--- 1497,1503 ----
      }
    while (bytes > 0);
  
!   return end_sequence ();
  }
  
  /* Worker function for xtensa_expand_block_set(),
*************** xtensa_expand_block_set_small_loop (rtx
*** 1520,1526 ****
    rtx reg, dst, end;
    machine_mode unit_mode;
    rtx_code_label *label;
-   rtx_insn *seq;
  
    /* Totally-aligned block only.  */
    if (bytes % align != 0)
--- 1515,1520 ----
*************** xtensa_expand_block_set_small_loop (rtx
*** 1581,1589 ****
    emit_insn (gen_addsi3 (dst, dst, GEN_INT (align)));
    emit_cmp_and_jump_insns (dst, end, NE, const0_rtx, SImode, true, label);
  
!   seq = end_sequence ();
! 
!   return seq;
  }
  
  
--- 1575,1581 ----
    emit_insn (gen_addsi3 (dst, dst, GEN_INT (align)));
    emit_cmp_and_jump_insns (dst, end, NE, const0_rtx, SImode, true, label);
  
!   return end_sequence ();
  }
  
  
*************** static rtx_insn *
*** 2247,2253 ****
  xtensa_call_tls_desc (rtx sym, rtx *retp)
  {
    rtx fn, arg, a_io;
!   rtx_insn *call_insn, *insns;
  
    start_sequence ();
    fn = gen_reg_rtx (Pmode);
--- 2239,2245 ----
  xtensa_call_tls_desc (rtx sym, rtx *retp)
  {
    rtx fn, arg, a_io;
!   rtx_insn *call_insn;
  
    start_sequence ();
    fn = gen_reg_rtx (Pmode);
*************** xtensa_call_tls_desc (rtx sym, rtx *retp
*** 2259,2268 ****
    emit_move_insn (a_io, arg);
    call_insn = emit_call_insn (gen_tls_call (a_io, fn, sym, const1_rtx));
    use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), a_io);
-   insns = end_sequence ();
  
    *retp = a_io;
!   return insns;
  }
  
  
--- 2251,2259 ----
    emit_move_insn (a_io, arg);
    call_insn = emit_call_insn (gen_tls_call (a_io, fn, sym, const1_rtx));
    use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), a_io);
  
    *retp = a_io;
!   return end_sequence ();
  }
  
  
diff -Nrcpad gcc-16-20251214/gcc/config.gcc gcc-16-20251221/gcc/config.gcc
*** gcc-16-20251214/gcc/config.gcc	Sun Dec 14 22:32:06 2025
--- gcc-16-20251221/gcc/config.gcc	Sun Dec 21 22:32:06 2025
*************** i[34567]86-*-* | x86_64-*-*)
*** 465,471 ****
  		       avx10_2bf16intrin.h avx10_2satcvtintrin.h
  		       avx10_2minmaxintrin.h avx10_2copyintrin.h
  		       amxavx512intrin.h amxtf32intrin.h amxfp8intrin.h
! 		       movrsintrin.h amxmovrsintrin.h"
  	;;
  ia64-*-*)
  	extra_headers=ia64intrin.h
--- 465,472 ----
  		       avx10_2bf16intrin.h avx10_2satcvtintrin.h
  		       avx10_2minmaxintrin.h avx10_2copyintrin.h
  		       amxavx512intrin.h amxtf32intrin.h amxfp8intrin.h
! 		       movrsintrin.h amxmovrsintrin.h avx512bmmintrin.h
! 		       avx512bmmvlintrin.h"
  	;;
  ia64-*-*)
  	extra_headers=ia64intrin.h
*************** c7 esther"
*** 722,728 ****
  # 64-bit x86 processors supported by --with-arch=.  Each processor
  # MUST be separated by exactly one space.
  x86_64_archs="amdfam10 athlon64 athlon64-sse3 barcelona bdver1 bdver2 \
! bdver3 bdver4 znver1 znver2 znver3 znver4 znver5 btver1 btver2 k8 k8-sse3 \
  opteron opteron-sse3 nocona core2 corei7 corei7-avx core-avx-i core-avx2 \
  atom slm nehalem westmere sandybridge ivybridge haswell broadwell bonnell \
  silvermont skylake-avx512 cannonlake icelake-client icelake-server \
--- 723,729 ----
  # 64-bit x86 processors supported by --with-arch=.  Each processor
  # MUST be separated by exactly one space.
  x86_64_archs="amdfam10 athlon64 athlon64-sse3 barcelona bdver1 bdver2 \
! bdver3 bdver4 znver1 znver2 znver3 znver4 znver5 znver6 btver1 btver2 k8 k8-sse3 \
  opteron opteron-sse3 nocona core2 corei7 corei7-avx core-avx-i core-avx2 \
  atom slm nehalem westmere sandybridge ivybridge haswell broadwell bonnell \
  silvermont skylake-avx512 cannonlake icelake-client icelake-server \
*************** case ${target} in
*** 3829,3834 ****
--- 3830,3839 ----
  	arch=znver5
  	cpu=znver5
  	;;
+       znver6-*)
+ 	arch=znver6
+ 	cpu=znver6
+ 	;;
        bdver4-*)
          arch=bdver4
          cpu=bdver4
*************** case ${target} in
*** 3974,3979 ****
--- 3979,3988 ----
  	arch=znver5
  	cpu=znver5
  	;;
+       znver6-*)
+ 	arch=znver6
+ 	cpu=znver6
+ 	;;
        bdver4-*)
          arch=bdver4
          cpu=bdver4
diff -Nrcpad gcc-16-20251214/gcc/config.in gcc-16-20251221/gcc/config.in
*** gcc-16-20251214/gcc/config.in	Sun Dec 14 22:32:20 2025
--- gcc-16-20251221/gcc/config.in	Sun Dec 21 22:32:18 2025
***************
*** 95,100 ****
--- 95,106 ----
  #endif
  
  
+ /* Define to enable the use of a default windres. */
+ #ifndef USED_FOR_TARGET
+ #undef DEFAULT_WINDRES
+ #endif
+ 
+ 
  /* The default for -fdiagnostics-color option */
  #ifndef USED_FOR_TARGET
  #undef DIAGNOSTICS_COLOR_DEFAULT
diff -Nrcpad gcc-16-20251214/gcc/configure gcc-16-20251221/gcc/configure
*** gcc-16-20251214/gcc/configure	Sun Dec 14 22:32:20 2025
--- gcc-16-20251221/gcc/configure	Sun Dec 21 22:32:18 2025
*************** with_demangler_in_ld
*** 974,979 ****
--- 974,980 ----
  with_dsymutil
  with_gnu_as
  with_as
+ with_windres
  enable_largefile
  enable_build_format_warnings
  enable_werror_always
*************** Optional Packages:
*** 1872,1877 ****
--- 1873,1879 ----
                            pathname)
    --with-gnu-as           arrange to work with GNU as
    --with-as               arrange to use the specified as (full pathname)
+   --with-windres          arrange to use the specified windres (full pathname)
    --with-stack-clash-protection-guard-size=size
                            Set the default stack clash protection guard size
                            for specific targets as a power of two in bytes.
*************** else
*** 4069,4074 ****
--- 4071,4108 ----
  $as_echo "no" >&6; }
  fi
  
+ # --------------------
+ # Find default windres
+ # --------------------
+ 
+ 
+ # Check whether --with-windres was given.
+ if test "${with_windres+set}" = set; then :
+   withval=$with_windres; DEFAULT_WINDRES="$with_windres"
+ fi
+ 
+ if test x"${DEFAULT_WINDRES+set}" = x"set"; then
+   if test ! -x "$DEFAULT_WINDRES"; then
+     as_fn_error $? "cannot execute: $DEFAULT_WINDRES: check --with-windres or env. var. DEFAULT_WINDRES" "$LINENO" 5
+   fi
+ 
+ cat >>confdefs.h <<_ACEOF
+ #define DEFAULT_WINDRES "$DEFAULT_WINDRES"
+ _ACEOF
+ 
+ fi
+ 
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a default windres was specified" >&5
+ $as_echo_n "checking whether a default windres was specified... " >&6; }
+ if test x"${DEFAULT_WINDRES+set}" = x"set"; then
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes ($DEFAULT_WINDRES)" >&5
+ $as_echo "yes ($DEFAULT_WINDRES)" >&6; }
+ else
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+ $as_echo "no" >&6; }
+ fi
+ 
+ 
  # ---------------
  # Find C compiler
  # ---------------
*************** else
*** 21876,21882 ****
    lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
    lt_status=$lt_dlunknown
    cat > conftest.$ac_ext <<_LT_EOF
! #line 21879 "configure"
  #include "confdefs.h"
  
  #if HAVE_DLFCN_H
--- 21910,21916 ----
    lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
    lt_status=$lt_dlunknown
    cat > conftest.$ac_ext <<_LT_EOF
! #line 21913 "configure"
  #include "confdefs.h"
  
  #if HAVE_DLFCN_H
*************** else
*** 21982,21988 ****
    lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
    lt_status=$lt_dlunknown
    cat > conftest.$ac_ext <<_LT_EOF
! #line 21985 "configure"
  #include "confdefs.h"
  
  #if HAVE_DLFCN_H
--- 22016,22022 ----
    lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
    lt_status=$lt_dlunknown
    cat > conftest.$ac_ext <<_LT_EOF
! #line 22019 "configure"
  #include "confdefs.h"
  
  #if HAVE_DLFCN_H
diff -Nrcpad gcc-16-20251214/gcc/configure.ac gcc-16-20251221/gcc/configure.ac
*** gcc-16-20251214/gcc/configure.ac	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/configure.ac	Sun Dec 21 22:32:06 2025
*************** else
*** 441,446 ****
--- 441,469 ----
    AC_MSG_RESULT(no)
  fi
  
+ # --------------------
+ # Find default windres
+ # --------------------
+ 
+ AC_ARG_WITH(windres,
+ [AS_HELP_STRING([--with-windres], [arrange to use the specified windres (full pathname)])],
+ DEFAULT_WINDRES="$with_windres")
+ if test x"${DEFAULT_WINDRES+set}" = x"set"; then
+   if test ! -x "$DEFAULT_WINDRES"; then
+     AC_MSG_ERROR([cannot execute: $DEFAULT_WINDRES: check --with-windres or env. var. DEFAULT_WINDRES])
+   fi
+   AC_DEFINE_UNQUOTED(DEFAULT_WINDRES,"$DEFAULT_WINDRES",
+ 	[Define to enable the use of a default windres.])
+ fi
+ 
+ AC_MSG_CHECKING([whether a default windres was specified])
+ if test x"${DEFAULT_WINDRES+set}" = x"set"; then
+   AC_MSG_RESULT([yes ($DEFAULT_WINDRES)])
+ else
+   AC_MSG_RESULT(no)
+ fi
+ 
+ 
  # ---------------
  # Find C compiler
  # ---------------
diff -Nrcpad gcc-16-20251214/gcc/cp/ChangeLog gcc-16-20251221/gcc/cp/ChangeLog
*** gcc-16-20251214/gcc/cp/ChangeLog	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/cp/ChangeLog	Sun Dec 21 22:32:06 2025
***************
*** 1,3 ****
--- 1,249 ----
+ 2025-12-20  Nathaniel Shead  <nathanieloshead@gmail.com>
+ 
+ 	PR c++/122712
+ 	* module.cc (depset::hash::dep_adl_info): New type.
+ 	(depset::hash::dep_adl_entity_list): New work list.
+ 	(depset::hash::hash): Create it.
+ 	(depset::hash::~hash): Release it.
+ 	(trees_out::tree_value): Cache possibly dependent
+ 	calls during tree walk.
+ 	(depset::hash::add_dependent_adl_entities): New function.
+ 	(depset::hash::find_dependencies): Process cached entities.
+ 	* name-lookup.cc (name_lookup::tentative): New member.
+ 	(name_lookup::name_lookup): Initialize it.
+ 	(name_lookup::preserve_state): Propagate tentative from previous
+ 	lookup.
+ 	(name_lookup::adl_namespace_fns): Don't search imported bindings
+ 	during tentative lookup.
+ 	(name_lookup::adl_class): Don't attempt to complete class types
+ 	during tentative lookup.
+ 	(name_lookup::search_adl): Skip type-dependent args and avoid
+ 	unnecessary work during tentative lookup.
+ 	(lookup_arg_dependent): Add tentative parameter.
+ 	* name-lookup.h (lookup_arg_dependent): Likewise.
+ 
+ 2025-12-20  Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	PR c++/122690
+ 	* tree.cc (implicit_lifetime_type_p): Don't test is_trivially_xible,
+ 	instead try to lazily declare dtor and default, copy and move ctors
+ 	if needed and check for their triviality and whether they are
+ 	deleted.
+ 
+ 2025-12-19  Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	PR c++/91388
+ 	* semantics.cc (finish_static_assert): Suppress -Wreturn-type warnings
+ 	in functions with failed assertions.
+ 
+ 2025-12-19  Jason Merrill  <jason@redhat.com>
+ 	    Egas Ribeiro  <egas.g.ribeiro@tecnico.ulisboa.pt>
+ 
+ 	PR c++/117034
+ 	* parser.cc (maybe_start_implicit_template): Split out from...
+ 	(synthesize_implicit_template_parm): ...here.
+ 	(cp_parser_template_id): Call it.
+ 
+ 2025-12-19  Egas Ribeiro  <egas.g.ribeiro@tecnico.ulisboa.pt>
+ 
+ 	* decl2.cc (mark_single_function): Return false for error_mark_node.
+ 	(mark_used): Likewise.
+ 
+ 2025-12-19  Egas Ribeiro  <egas.g.ribeiro@tecnico.ulisboa.pt>
+ 
+ 	PR c++/123044
+ 	* typeck2.cc (build_functional_cast_1): Call convert_from_reference
+ 	on template CAST_EXPR to match C-style cast behavior.
+ 
+ 2025-12-19  Egas Ribeiro  <egas.g.ribeiro@gmail.com>
+ 
+ 	PR c++/122509
+ 	* parser.cc (cp_parser_lookup_name): Use protect=2 instead of
+ 	protect=0 when calling lookup_member.
+ 
+ 2025-12-19  Tobias Burnus  <tburnus@baylibre.com>
+ 
+ 	* parser.cc (cp_parser_omp_clause_uses_allocators): Accept
+ 	multiple clause-argument-specifications separated by ';'.
+ 
+ 2025-12-19  Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	PR c++/122772
+ 	* tree.cc (cp_stabilize_bitfield_reference): New function.
+ 	(cp_stabilize_reference): Use it for stabilization of
+ 	clk_bitfield or clk_packed lvalues.
+ 
+ 2025-12-19  Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	PR debug/122968
+ 	* decl.cc (cp_finish_decomp): For structured bindings at namespace
+ 	scope which have DECL_HAS_VALUE_EXPR_P set, call early_global_decl
+ 	debug hook and put all such structured bindings into
+ 	"structured bindings" attribute arguments on the underlying decl.
+ 
+ 2025-12-19  Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	PR c++/122834
+ 	* typeck.cc (cp_compare_floating_point_conversion_ranks): Return
+ 	3 if fmt2->b is 10 except for _Float16 vs. _Decimal128, in that
+ 	case return -2.
+ 
+ 2025-12-19  Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	PR c++/123030
+ 	* init.cc (build_vec_init): Call build_vec_delete_1 for -fexceptions
+ 	even if just type_build_dtor_call, not only when
+ 	TYPE_HAS_NONTRIVIAL_DESTRUCTOR.  But register cleanups only
+ 	for TYPE_HAS_NONTRIVIAL_DESTRUCTOR.
+ 
+ 2025-12-19  Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	* parser.cc (cp_build_range_for_decls): If expansion_stmt_p,
+ 	where we are setting DECL_DECLARED_CONSTEXPR_P on begin/end, use
+ 	const qualified iter_type.
+ 	* pt.cc (finish_expansion_stmt): Use build_target_expr_with_type
+ 	with cv_unqualified to create it instead of get_target_expr to
+ 	make it non-const qualified.  When creating VAR_DECLs with
+ 	DECL_DECLARED_CONSTEXPR_P, make sure they have const qualified
+ 	type unless they are references.
+ 
+ 2025-12-19  Nathaniel Shead  <nathanieloshead@gmail.com>
+ 
+ 	PR c++/122922
+ 	* module.cc (trees_in::post_types): New member.
+ 	(trees_in::trees_in): Initialize it.
+ 	(trees_in::~trees_in): Clean it up.
+ 	(trees_in::post_process_type): New functions.
+ 	(trees_in::tree_node): Save incomplete ARRAY_TYPEs for later
+ 	post-processing.
+ 	(module_state::read_cluster): Attempt to complete any
+ 	ARRAY_TYPEs we saved earlier.
+ 
+ 2025-12-19  Nathaniel Shead  <nathanieloshead@gmail.com>
+ 
+ 	PR c++/122995
+ 	* name-lookup.cc (maybe_record_mergeable_decl): Don't build a
+ 	STAT_HACK for namespaces.
+ 
+ 2025-12-18  Tobias Burnus  <tburnus@baylibre.com>
+ 
+ 	* parser.cc (cp_parser_omp_assumption_clauses): Add
+ 	no_openmp_constructs clause.
+ 
+ 2025-12-18  Patrick Palka  <ppalka@redhat.com>
+ 
+ 	* decl.cc (tag_name) <case none_type>: Return "typename" as if
+ 	typename_type.
+ 
+ 2025-12-18  Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	PR c++/123186
+ 	* parser.cc (cp_parser_template_id): Use TYPE_IDENTIFIER instead of
+ 	TYPE_NAME in second build_typename_type argument.
+ 
+ 2025-12-18  Egas Ribeiro  <egas.g.ribeiro@gmail.com>
+ 	    Patrick Palka  <ppalka@redhat.com>
+ 
+ 	PR c++/122070
+ 	* pt.cc (type_targs_deducible_from): Fall back to
+ 	TYPE_TEMPLATE_INFO when TYPE_TEMPLATE_INFO_MAYBE_ALIAS is NULL.
+ 
+ 2025-12-18  Tobias Burnus  <tburnus@baylibre.com>
+ 
+ 	* parser.cc (OMP_TARGET_CLAUSE_MASK): Add
+ 	device_type clause.
+ 
+ 2025-12-17  benwu25  <soggysocks206@gmail.com>
+ 
+ 	* parser.cc (cp_parser_init_declarator): Adjust comment.
+ 
+ 2025-12-17  benwu25  <soggysocks206@gmail.com>
+ 
+ 	PR c++/121443
+ 	* parser.cc (cp_parser_lambda_expression): Clear
+ 	in_declarator_p.
+ 
+ 2025-12-17  Nathaniel Shead  <nathanieloshead@gmail.com>
+ 
+ 	PR c++/123075
+ 	* constraint.cc (evaluate_concept_check): Push to an unrelated
+ 	scope, but keep the same access context.
+ 	* pt.cc (tsubst_lambda_expr): Don't record lambda scopes for
+ 	lambdas attached to a concept.
+ 
+ 2025-12-15  Patrick Palka  <ppalka@redhat.com>
+ 
+ 	* parser.cc (cp_parser_template_id): Rebuild instead of modifying
+ 	a TYPENAME_TYPE corresponding to a dependently-scoped template.
+ 
+ 2025-12-15  Patrick Palka  <ppalka@redhat.com>
+ 
+ 	* cp-tree.h (TYPENAME_TYPE_TAG_BIT_0): New.
+ 	(TYPENAME_TYPE_TAG_BIT_1): New.
+ 	(TYPENAME_TYPE_TAG_BIT_2): New.
+ 	(TYPENAME_IS_ENUM_P): Use get_typename_tag.
+ 	(TYPENAME_IS_CLASS_P): Rename to ...
+ 	(TYPENAME_IS_CLASS_OR_STRUCT_P): ... this, and use
+ 	get_typename_tag.
+ 	(TYPENAME_IS_UNION_P): Use get_typename_tag.
+ 	(TYPENAME_IS_RESOLVING_P): Use TREE_LANG_FLAG_3
+ 	instead of _2.
+ 	(get_typename_tag): New.
+ 	(set_typename_tag): New.
+ 	(tag_name): Declare.
+ 	* decl.cc (typename_info): Replace bool fields with a single
+ 	tag_types field.
+ 	(typename_hasher::equal): Adjust.
+ 	(build_typename_type): Adjust.
+ 	(tag_name): Handle none_type and scope_type.
+ 	* error.cc (dump_type) <case TYPENAME_TYPE>: Use tag_name.
+ 	* module.cc (trees_out::type_node) <case TYPENAME_TYPE>: Use
+ 	get_typename_tag.
+ 	* pt.cc (tsubst) <case TYPENAME_TYPE>: Likewise.
+ 
+ 2025-12-15  Patrick Palka  <ppalka@redhat.com>
+ 
+ 	* cp-tree.h (CLASSTYPE_LAMBDA_EXPR): Check CLASS_TYPE_P before
+ 	inspecting TYPE_POLYMORPHIC_P.
+ 	(TYPE_POLYMORPHIC_P): Restrict to RECORD_TYPE or UNION_TYPE.
+ 	Document its use of TREE_LANG_FLAG_2.
+ 	* parser.cc (noexcept_override_late_checks): Only
+ 	check TYPE_POLYMORPHIC_P on CLASS_TYPE_P types.
+ 	* rtti.cc (build_headof): Likewise.
+ 	(get_tinfo_ptr_dynamic): Likewise.
+ 	(build_typeid): Likewise.
+ 
+ 2025-12-15  Patrick Palka  <ppalka@redhat.com>
+ 
+ 	PR c++/122752
+ 	* pt.cc (tsubst) <case TYPENAME_TYPE>: Allow TYPENAME_TYPE
+ 	resolving to another wildcard type.
+ 
+ 2025-12-15  Patrick Palka  <ppalka@redhat.com>
+ 
+ 	PR c++/122668
+ 	PR c++/114764
+ 	* parser.cc (cp_parser_class_specifier): Adjust after
+ 	changing the element type of unparsed_noexcepts.  Pass
+ 	the class type to noexcept_override_late_checks.
+ 	(cp_parser_member_declaration): Set
+ 	CP_PARSER_FLAGS_DELAY_NOEXCEPT also for templated friends.
+ 	(noexcept_override_late_checks): Add class_type parameter.
+ 	(cp_parser_single_declaration): Set
+ 	CP_PARSER_FLAGS_DELAY_NOEXCEPT also for template friends
+ 	at class template scope.
+ 	(cp_parser_save_default_args): Push current_class_type
+ 	to unparsed_noexcepts.
+ 	* parser.h (cp_unparsed_functions_entry::noexcepts):
+ 	Change element type to cp_default_arg_entry.
+ 	* pt.cc (dependentish_scope_p): Revert r16-5425 change.
+ 
+ 2025-12-15  Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	PR c++/123128
+ 	* parser.cc (cp_parser_omp_clause_linear): Initialize next to NULL
+ 	rather than UNKNOWN_LOCATION.
+ 
  2025-12-13  Jakub Jelinek  <jakub@redhat.com>
  
  	* parser.cc (cp_parser_omp_clause_reduction): Provide fixit hints
diff -Nrcpad gcc-16-20251214/gcc/cp/constraint.cc gcc-16-20251221/gcc/cp/constraint.cc
*** gcc-16-20251214/gcc/cp/constraint.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/cp/constraint.cc	Sun Dec 21 22:32:06 2025
*************** evaluate_concept_check (tree check)
*** 2860,2868 ****
  
    gcc_assert (concept_check_p (check));
  
    /* Check for satisfaction without diagnostics.  */
    sat_info quiet (tf_none, NULL_TREE);
!   return constraint_satisfaction_value (check, /*args=*/NULL_TREE, quiet);
  }
  
  /* Evaluate the requires-expression T, returning either boolean_true_node
--- 2860,2886 ----
  
    gcc_assert (concept_check_p (check));
  
+   /* We don't want any declarations instantiated from a concept evaluation
+      to enter the binding table for the current scope, such as lambdas, so
+      leave that scope.  But maintain the access context (PR104111).  */
+   tree scope = current_scope ();
+   if (CLASS_TYPE_P (scope))
+     scope = TYPE_MAIN_DECL (scope);
+   else if (TREE_CODE (scope) != FUNCTION_DECL)
+     scope = NULL_TREE;
+ 
+   push_to_top_level ();
+   if (scope)
+     push_access_scope (scope);
+ 
    /* Check for satisfaction without diagnostics.  */
    sat_info quiet (tf_none, NULL_TREE);
!   tree r = constraint_satisfaction_value (check, /*args=*/NULL_TREE, quiet);
! 
!   if (scope)
!     pop_access_scope (scope);
!   pop_from_top_level ();
!   return r;
  }
  
  /* Evaluate the requires-expression T, returning either boolean_true_node
diff -Nrcpad gcc-16-20251214/gcc/cp/cp-tree.h gcc-16-20251221/gcc/cp/cp-tree.h
*** gcc-16-20251214/gcc/cp/cp-tree.h	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/cp/cp-tree.h	Sun Dec 21 22:32:06 2025
*************** extern GTY(()) tree cp_global_trees[CPTI
*** 417,423 ****
        EXPR_STMT_STMT_EXPR_RESULT (in EXPR_STMT)
        STMT_EXPR_NO_SCOPE (in STMT_EXPR)
        BIND_EXPR_TRY_BLOCK (in BIND_EXPR)
!       TYPENAME_IS_ENUM_P (in TYPENAME_TYPE)
        OMP_FOR_GIMPLIFYING_P (in OMP_FOR, OMP_SIMD, OMP_DISTRIBUTE,
  			     and OMP_TASKLOOP)
        BASELINK_QUALIFIED_P (in BASELINK)
--- 417,423 ----
        EXPR_STMT_STMT_EXPR_RESULT (in EXPR_STMT)
        STMT_EXPR_NO_SCOPE (in STMT_EXPR)
        BIND_EXPR_TRY_BLOCK (in BIND_EXPR)
!       TYPENAME_TYPE_TAG_BIT_0 (in TYPENAME_TYPE)
        OMP_FOR_GIMPLIFYING_P (in OMP_FOR, OMP_SIMD, OMP_DISTRIBUTE,
  			     and OMP_TASKLOOP)
        BASELINK_QUALIFIED_P (in BASELINK)
*************** extern GTY(()) tree cp_global_trees[CPTI
*** 460,466 ****
        DELETE_EXPR_USE_VEC (in DELETE_EXPR).
        ICS_ELLIPSIS_FLAG (in _CONV)
        DECL_INITIALIZED_P (in VAR_DECL)
!       TYPENAME_IS_CLASS_P (in TYPENAME_TYPE)
        STMT_IS_FULL_EXPR_P (in _STMT)
        TARGET_EXPR_LIST_INIT_P (in TARGET_EXPR)
        DECL_FINAL_P (in FUNCTION_DECL)
--- 460,466 ----
        DELETE_EXPR_USE_VEC (in DELETE_EXPR).
        ICS_ELLIPSIS_FLAG (in _CONV)
        DECL_INITIALIZED_P (in VAR_DECL)
!       TYPENAME_TYPE_TAG_BIT_1 (in TYPENAME_TYPE)
        STMT_IS_FULL_EXPR_P (in _STMT)
        TARGET_EXPR_LIST_INIT_P (in TARGET_EXPR)
        DECL_FINAL_P (in FUNCTION_DECL)
*************** extern GTY(()) tree cp_global_trees[CPTI
*** 480,486 ****
        ICS_THIS_FLAG (in _CONV)
        DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL)
        STATEMENT_LIST_TRY_BLOCK (in STATEMENT_LIST)
!       TYPENAME_IS_RESOLVING_P (in TYPENAME_TYPE)
        TARGET_EXPR_DIRECT_INIT_P (in TARGET_EXPR)
        FNDECL_USED_AUTO (in FUNCTION_DECL)
        DECLTYPE_FOR_LAMBDA_PROXY (in DECLTYPE_TYPE)
--- 480,487 ----
        ICS_THIS_FLAG (in _CONV)
        DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL)
        STATEMENT_LIST_TRY_BLOCK (in STATEMENT_LIST)
!       TYPENAME_TYPE_TAG_BIT_2 (in TYPENAME_TYPE)
!       TYPE_POLYMORPHIC_P (in RECORD_TYPE and UNION_TYPE)
        TARGET_EXPR_DIRECT_INIT_P (in TARGET_EXPR)
        FNDECL_USED_AUTO (in FUNCTION_DECL)
        DECLTYPE_FOR_LAMBDA_PROXY (in DECLTYPE_TYPE)
*************** extern GTY(()) tree cp_global_trees[CPTI
*** 512,518 ****
        TARGET_EXPR_ELIDING_P (in TARGET_EXPR)
        IF_STMT_VACUOUS_INIT_P (IF_STMT)
        contract_semantic (in ASSERTION_, PRECONDITION_, POSTCONDITION_STMT)
!       TYPENAME_IS_UNION_P (in TYPENAME_TYPE)
     4: IDENTIFIER_MARKED (IDENTIFIER_NODEs)
        TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR,
  	  CALL_EXPR, or FIELD_DECL).
--- 513,519 ----
        TARGET_EXPR_ELIDING_P (in TARGET_EXPR)
        IF_STMT_VACUOUS_INIT_P (IF_STMT)
        contract_semantic (in ASSERTION_, PRECONDITION_, POSTCONDITION_STMT)
!       TYPENAME_IS_RESOLVING_P (in TYPENAME_TYPE)
     4: IDENTIFIER_MARKED (IDENTIFIER_NODEs)
        TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR,
  	  CALL_EXPR, or FIELD_DECL).
*************** struct GTY(()) lang_type {
*** 2815,2821 ****
  
  /* The associated LAMBDA_EXPR that made this class.  */
  #define CLASSTYPE_LAMBDA_EXPR(NODE) \
!   (TYPE_POLYMORPHIC_P (NODE)				\
     ? NULL_TREE						\
     : LANG_TYPE_CLASS_CHECK (NODE)->key_method)
  #define SET_CLASSTYPE_LAMBDA_EXPR(NODE, VALUE) \
--- 2816,2822 ----
  
  /* The associated LAMBDA_EXPR that made this class.  */
  #define CLASSTYPE_LAMBDA_EXPR(NODE) \
!   (CLASS_TYPE_P (NODE) && TYPE_POLYMORPHIC_P (NODE)	\
     ? NULL_TREE						\
     : LANG_TYPE_CLASS_CHECK (NODE)->key_method)
  #define SET_CLASSTYPE_LAMBDA_EXPR(NODE, VALUE) \
*************** get_vec_init_expr (tree t)
*** 4550,4576 ****
  #define TYPENAME_TYPE_FULLNAME(NODE) \
    (TYPE_VALUES_RAW (TYPENAME_TYPE_CHECK (NODE)))
  
  /* True if a TYPENAME_TYPE was declared as an "enum".  */
  #define TYPENAME_IS_ENUM_P(NODE) \
!   (TREE_LANG_FLAG_0 (TYPENAME_TYPE_CHECK (NODE)))
  
  /* True if a TYPENAME_TYPE was declared as a "class" or "struct".  */
! #define TYPENAME_IS_CLASS_P(NODE) \
!   (TREE_LANG_FLAG_1 (TYPENAME_TYPE_CHECK (NODE)))
  
  /* True if a TYPENAME_TYPE was declared as a "union".  */
  #define TYPENAME_IS_UNION_P(NODE) \
!   (TREE_LANG_FLAG_3 (TYPENAME_TYPE_CHECK (NODE)))
  
  /* True if a TYPENAME_TYPE is in the process of being resolved.  */
  #define TYPENAME_IS_RESOLVING_P(NODE) \
!   (TREE_LANG_FLAG_2 (TYPENAME_TYPE_CHECK (NODE)))
  
  /* [class.virtual]
  
     A class that declares or inherits a virtual function is called a
     polymorphic class.  */
! #define TYPE_POLYMORPHIC_P(NODE) (TREE_LANG_FLAG_2 (NODE))
  
  /* Nonzero if this class has a virtual function table pointer.  */
  #define TYPE_CONTAINS_VPTR_P(NODE)		\
--- 4551,4587 ----
  #define TYPENAME_TYPE_FULLNAME(NODE) \
    (TYPE_VALUES_RAW (TYPENAME_TYPE_CHECK (NODE)))
  
+ /* Storage for the tag type of a TYPENAME_TYPE.  */
+ #define TYPENAME_TYPE_TAG_BIT_0(NODE) \
+   (TREE_LANG_FLAG_0 (TYPENAME_TYPE_CHECK (NODE)))
+ #define TYPENAME_TYPE_TAG_BIT_1(NODE) \
+   (TREE_LANG_FLAG_1 (TYPENAME_TYPE_CHECK (NODE)))
+ #define TYPENAME_TYPE_TAG_BIT_2(NODE) \
+   (TREE_LANG_FLAG_2 (TYPENAME_TYPE_CHECK (NODE)))
+ 
  /* True if a TYPENAME_TYPE was declared as an "enum".  */
  #define TYPENAME_IS_ENUM_P(NODE) \
!   (get_typename_tag (NODE) == enum_type)
  
  /* True if a TYPENAME_TYPE was declared as a "class" or "struct".  */
! #define TYPENAME_IS_CLASS_OR_STRUCT_P(NODE) \
!   (get_typename_tag (NODE) == class_type \
!    || get_typename_tag (NODE) == record_type)
  
  /* True if a TYPENAME_TYPE was declared as a "union".  */
  #define TYPENAME_IS_UNION_P(NODE) \
!   (get_typename_tag (NODE) == union_type)
  
  /* True if a TYPENAME_TYPE is in the process of being resolved.  */
  #define TYPENAME_IS_RESOLVING_P(NODE) \
!   (TREE_LANG_FLAG_3 (TYPENAME_TYPE_CHECK (NODE)))
  
  /* [class.virtual]
  
     A class that declares or inherits a virtual function is called a
     polymorphic class.  */
! #define TYPE_POLYMORPHIC_P(NODE) \
!   (TREE_LANG_FLAG_2 (RECORD_OR_UNION_CHECK (NODE)))
  
  /* Nonzero if this class has a virtual function table pointer.  */
  #define TYPE_CONTAINS_VPTR_P(NODE)		\
*************** enum tag_types {
*** 5789,5794 ****
--- 5800,5827 ----
    scope_type	 /* namespace or tagged type name followed by :: */
  };
  
+ /* Return the tag type of the given TYPENAME_TYPE.  */
+ 
+ inline tag_types
+ get_typename_tag (tree t)
+ {
+   unsigned bit0 = TYPENAME_TYPE_TAG_BIT_0 (t);
+   unsigned bit1 = TYPENAME_TYPE_TAG_BIT_1 (t);
+   unsigned bit2 = TYPENAME_TYPE_TAG_BIT_2 (t);
+   return tag_types ((bit2 << 2) | (bit1 << 1) | bit0);
+ }
+ 
+ /* Set the tag type of the given TYPENAME_TYPE.  */
+ 
+ inline void
+ set_typename_tag (tree t, tag_types tag)
+ {
+   gcc_checking_assert ((tag & 7) == tag);
+   TYPENAME_TYPE_TAG_BIT_0 (t) = (tag >> 0) & 1;
+   TYPENAME_TYPE_TAG_BIT_1 (t) = (tag >> 1) & 1;
+   TYPENAME_TYPE_TAG_BIT_2 (t) = (tag >> 2) & 1;
+ }
+ 
  /* The various kinds of lvalues we distinguish.  */
  enum cp_lvalue_kind_flags {
    clk_none = 0,     /* Things that are not an lvalue.  */
*************** extern bool use_eh_spec_block			(tree);
*** 7362,7367 ****
--- 7395,7401 ----
  extern void do_push_parm_decls			(tree, tree, tree *);
  extern tree do_aggregate_paren_init		(tree, tree);
  extern void maybe_mark_function_versioned	(tree);
+ extern const char *tag_name 			(enum tag_types);
  
  /* in decl2.cc */
  extern void record_mangling			(tree, bool);
diff -Nrcpad gcc-16-20251214/gcc/cp/decl.cc gcc-16-20251221/gcc/cp/decl.cc
*** gcc-16-20251214/gcc/cp/decl.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/cp/decl.cc	Sun Dec 21 22:32:06 2025
*************** static void check_static_variable_defini
*** 85,91 ****
  static void record_unknown_type (tree, const char *);
  static int member_function_or_else (tree, tree, enum overload_flags);
  static tree local_variable_p_walkfn (tree *, int *, void *);
- static const char *tag_name (enum tag_types);
  static tree lookup_and_check_tag (enum tag_types, tree, TAG_how, bool);
  static void maybe_deduce_size_from_array_init (tree, tree);
  static void layout_var_decl (tree);
--- 85,90 ----
*************** struct typename_info {
*** 4843,4851 ****
    tree scope;
    tree name;
    tree template_id;
!   bool enum_p;
!   bool class_p;
!   bool union_p;
  };
  
  struct typename_hasher : ggc_ptr_hash<tree_node>
--- 4842,4848 ----
    tree scope;
    tree name;
    tree template_id;
!   tag_types tag_type;
  };
  
  struct typename_hasher : ggc_ptr_hash<tree_node>
*************** struct typename_hasher : ggc_ptr_hash<tr
*** 4883,4891 ****
      return (TYPE_IDENTIFIER (t1) == t2->name
  	    && TYPE_CONTEXT (t1) == t2->scope
  	    && TYPENAME_TYPE_FULLNAME (t1) == t2->template_id
! 	    && TYPENAME_IS_ENUM_P (t1) == t2->enum_p
! 	    && TYPENAME_IS_CLASS_P (t1) == t2->class_p
! 	    && TYPENAME_IS_UNION_P (t1) == t2->union_p);
    }
  };
  
--- 4880,4886 ----
      return (TYPE_IDENTIFIER (t1) == t2->name
  	    && TYPE_CONTEXT (t1) == t2->scope
  	    && TYPENAME_TYPE_FULLNAME (t1) == t2->template_id
! 	    && get_typename_tag (t1) == t2->tag_type);
    }
  };
  
*************** build_typename_type (tree context, tree
*** 4908,4916 ****
    ti.scope = FROB_CONTEXT (context);
    ti.name = name;
    ti.template_id = fullname;
!   ti.enum_p = tag_type == enum_type;
!   ti.class_p = (tag_type == class_type || tag_type == record_type);
!   ti.union_p = tag_type == union_type;
    hashval_t hash = typename_hasher::hash (&ti);
  
    /* See if we already have this type.  */
--- 4903,4909 ----
    ti.scope = FROB_CONTEXT (context);
    ti.name = name;
    ti.template_id = fullname;
!   ti.tag_type = tag_type;
    hashval_t hash = typename_hasher::hash (&ti);
  
    /* See if we already have this type.  */
*************** build_typename_type (tree context, tree
*** 4924,4932 ****
        t = cxx_make_type (TYPENAME_TYPE);
        TYPE_CONTEXT (t) = ti.scope;
        TYPENAME_TYPE_FULLNAME (t) = ti.template_id;
!       TYPENAME_IS_ENUM_P (t) = ti.enum_p;
!       TYPENAME_IS_CLASS_P (t) = ti.class_p;
!       TYPENAME_IS_UNION_P (t) = ti.union_p;
  
        /* Build the corresponding TYPE_DECL.  */
        tree d = build_decl (input_location, TYPE_DECL, name, t);
--- 4917,4923 ----
        t = cxx_make_type (TYPENAME_TYPE);
        TYPE_CONTEXT (t) = ti.scope;
        TYPENAME_TYPE_FULLNAME (t) = ti.template_id;
!       set_typename_tag (t, ti.tag_type);
  
        /* Build the corresponding TYPE_DECL.  */
        tree d = build_decl (input_location, TYPE_DECL, name, t);
*************** cp_finish_decomp (tree decl, cp_decomp *
*** 11092,11097 ****
--- 11083,11105 ----
  	    DECL_HAS_VALUE_EXPR_P (v[i]) = 1;
  	  }
      }
+   else if (DECL_NAMESPACE_SCOPE_P (decl) && !seen_error ())
+     {
+       tree attr = NULL_TREE, *pa = &attr;
+       for (unsigned int i = 0; i < count; i++)
+ 	if ((unsigned) pack != i
+ 	    && DECL_HAS_VALUE_EXPR_P (v[i])
+ 	    && !DECL_IGNORED_P (v[i]))
+ 	  {
+ 	    (*debug_hooks->early_global_decl) (v[i]);
+ 	    *pa = build_tree_list (NULL_TREE, v[i]);
+ 	    pa = &TREE_CHAIN (*pa);
+ 	  }
+       if (attr)
+ 	DECL_ATTRIBUTES (decl)
+ 	  = tree_cons (get_identifier ("structured bindings"),
+ 		       attr, DECL_ATTRIBUTES (decl));
+     }
    return false;
  }
  
*************** grok_op_properties (tree decl, bool comp
*** 17941,17947 ****
  
  /* Return a string giving the keyword associate with CODE.  */
  
! static const char *
  tag_name (enum tag_types code)
  {
    switch (code)
--- 17949,17955 ----
  
  /* Return a string giving the keyword associate with CODE.  */
  
! const char *
  tag_name (enum tag_types code)
  {
    switch (code)
*************** tag_name (enum tag_types code)
*** 17955,17964 ****
      case enum_type:
        return "enum";
      case typename_type:
        return "typename";
!     default:
!       gcc_unreachable ();
      }
  }
  
  /* Name lookup in an elaborated-type-specifier (after the keyword
--- 17963,17974 ----
      case enum_type:
        return "enum";
      case typename_type:
+     case none_type:
        return "typename";
!     case scope_type:
!       return nullptr;
      }
+   gcc_unreachable ();
  }
  
  /* Name lookup in an elaborated-type-specifier (after the keyword
diff -Nrcpad gcc-16-20251214/gcc/cp/decl2.cc gcc-16-20251221/gcc/cp/decl2.cc
*** gcc-16-20251214/gcc/cp/decl2.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/cp/decl2.cc	Sun Dec 21 22:32:06 2025
*************** mark_single_function (tree expr, tsubst_
*** 6301,6306 ****
--- 6301,6309 ----
    expr = maybe_undo_parenthesized_ref (expr);
    expr = tree_strip_any_location_wrapper (expr);
  
+   if (expr == error_mark_node)
+     return false;
+ 
    if (is_overloaded_fn (expr) == 1
        && !mark_used (expr, complain)
        && !(complain & tf_error))
*************** fn_template_being_defined (tree decl)
*** 6343,6348 ****
--- 6346,6354 ----
  bool
  mark_used (tree decl, tsubst_flags_t complain /* = tf_warning_or_error */)
  {
+   if (decl == error_mark_node)
+     return false;
+ 
    /* If we're just testing conversions or resolving overloads, we
       don't want any permanent effects like forcing functions to be
       output or instantiating templates.  */
diff -Nrcpad gcc-16-20251214/gcc/cp/error.cc gcc-16-20251221/gcc/cp/error.cc
*** gcc-16-20251214/gcc/cp/error.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/cp/error.cc	Sun Dec 21 22:32:06 2025
*************** dump_type (cxx_pretty_printer *pp, tree
*** 822,832 ****
  	  break;
  	}
        pp_cxx_cv_qualifier_seq (pp, t);
!       pp_cxx_ws_string (pp,
! 			 TYPENAME_IS_ENUM_P (t) ? "enum"
! 			 : TYPENAME_IS_CLASS_P (t) ? "class"
! 			 : TYPENAME_IS_UNION_P (t) ? "union"
! 			 : "typename");
        dump_typename (pp, t, flags);
        break;
  
--- 822,829 ----
  	  break;
  	}
        pp_cxx_cv_qualifier_seq (pp, t);
!       if (const char *tag = tag_name (get_typename_tag (t)))
! 	pp_cxx_ws_string (pp, tag);
        dump_typename (pp, t, flags);
        break;
  
diff -Nrcpad gcc-16-20251214/gcc/cp/init.cc gcc-16-20251221/gcc/cp/init.cc
*** gcc-16-20251214/gcc/cp/init.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/cp/init.cc	Sun Dec 21 22:32:06 2025
*************** build_vec_init (tree base, tree maxindex
*** 4785,4795 ****
    /* Protect the entire array initialization so that we can destroy
       the partially constructed array if an exception is thrown.
       But don't do this if we're assigning.  */
!   if (flag_exceptions && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)
        /* And don't clean up from clobbers, the actual initialization will
  	 follow as a separate build_vec_init.  */
        && !(init && TREE_CLOBBER_P (init))
!       && from_array != 2)
      {
        tree e;
        tree m = cp_build_binary_op (input_location,
--- 4785,4796 ----
    /* Protect the entire array initialization so that we can destroy
       the partially constructed array if an exception is thrown.
       But don't do this if we're assigning.  */
!   if (flag_exceptions
        /* And don't clean up from clobbers, the actual initialization will
  	 follow as a separate build_vec_init.  */
        && !(init && TREE_CLOBBER_P (init))
!       && from_array != 2
!       && type_build_dtor_call (type))
      {
        tree e;
        tree m = cp_build_binary_op (input_location,
*************** build_vec_init (tree base, tree maxindex
*** 4812,4835 ****
  			      /*in_cleanup*/true);
        if (e == error_mark_node)
  	errors = true;
!       TARGET_EXPR_CLEANUP (iterator_targ) = e;
!       CLEANUP_EH_ONLY (iterator_targ) = true;
  
!       /* Since we push this cleanup before doing any initialization, cleanups
! 	 for any temporaries in the initialization are naturally within our
! 	 cleanup region, so we don't want wrap_temporary_cleanups to do
! 	 anything for arrays.  But if the array is a subobject, we need to
! 	 tell split_nonconstant_init or cp_genericize_target_expr how to turn
! 	 off this cleanup in favor of the cleanup for the complete object.
  
! 	 ??? For an array temporary such as an initializer_list backing array,
! 	 it would avoid redundancy to leave this cleanup active, clear
! 	 CLEANUP_EH_ONLY, and not build another cleanup for the temporary
! 	 itself.  But that breaks when gimplify_target_expr adds a clobber
! 	 cleanup that runs before the build_vec_init cleanup.  */
!       if (cleanup_flags)
! 	vec_safe_push (*cleanup_flags,
! 		       build_tree_list (rval, build_zero_cst (ptype)));
      }
  
    /* Should we try to create a constant initializer?  */
--- 4813,4840 ----
  			      /*in_cleanup*/true);
        if (e == error_mark_node)
  	errors = true;
!       else if (TREE_SIDE_EFFECTS (e))
! 	{
! 	  TARGET_EXPR_CLEANUP (iterator_targ) = e;
! 	  CLEANUP_EH_ONLY (iterator_targ) = true;
  
! 	  /* Since we push this cleanup before doing any initialization,
! 	     cleanups for any temporaries in the initialization are naturally
! 	     within our cleanup region, so we don't want
! 	     wrap_temporary_cleanups to do anything for arrays.  But if the
! 	     array is a subobject, we need to tell split_nonconstant_init or
! 	     cp_genericize_target_expr how to turn off this cleanup in favor
! 	     of the cleanup for the complete object.
  
! 	     ??? For an array temporary such as an initializer_list backing
! 	     array, it would avoid redundancy to leave this cleanup active,
! 	     clear CLEANUP_EH_ONLY, and not build another cleanup for the
! 	     temporary itself.  But that breaks when gimplify_target_expr adds
! 	     a clobber cleanup that runs before the build_vec_init cleanup.  */
! 	  if (cleanup_flags)
! 	    vec_safe_push (*cleanup_flags,
! 			   build_tree_list (rval, build_zero_cst (ptype)));
! 	}
      }
  
    /* Should we try to create a constant initializer?  */
diff -Nrcpad gcc-16-20251214/gcc/cp/module.cc gcc-16-20251221/gcc/cp/module.cc
*** gcc-16-20251214/gcc/cp/module.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/cp/module.cc	Sun Dec 21 22:32:06 2025
*************** public:
*** 2628,2633 ****
--- 2628,2647 ----
      bool ignore_tu_local;    /* In a context where referencing a TU-local
  				entity is not an exposure.  */
  
+   private:
+     /* Information needed to do dependent ADL for discovering
+        more decl-reachable entities.  Cached during walking to
+        prevent tree marking from interfering with lookup.  */
+     struct dep_adl_info {
+       /* The name of the call or operator.  */
+       tree name = NULL_TREE;
+       /* If not ERROR_MARK, a rewrite candidate for this operator.  */
+       tree_code rewrite = ERROR_MARK;
+       /* Argument list for the call.  */
+       vec<tree, va_gc>* args = make_tree_vector ();
+     };
+     vec<dep_adl_info> dep_adl_entity_list;
+ 
    public:
      hash (size_t size, hash *c = NULL)
        : parent (size), chain (c), current (NULL), section (0),
*************** public:
*** 2635,2644 ****
--- 2649,2660 ----
  	ignore_tu_local (false)
      {
        worklist.create (size);
+       dep_adl_entity_list.create (16);
      }
      ~hash ()
      {
        worklist.release ();
+       dep_adl_entity_list.release ();
      }
  
    public:
*************** public:
*** 2671,2676 ****
--- 2687,2693 ----
      void add_specializations (bool decl_p);
      void add_partial_entities (vec<tree, va_gc> *);
      void add_class_entities (vec<tree, va_gc> *);
+     void add_dependent_adl_entities (tree expr);
  
    private:
      void add_deduction_guides (tree decl);
*************** private:
*** 2985,2990 ****
--- 3002,3008 ----
    vec<tree> back_refs;		/* Back references.  */
    duplicate_hash_map *duplicates;	/* Map from existings to duplicate.  */
    vec<post_process_data> post_decls;	/* Decls to post process.  */
+   vec<tree> post_types;		/* Types to post process.  */
    unsigned unused;		/* Inhibit any interior TREE_USED
  				   marking.  */
  
*************** public:
*** 3089,3100 ****
--- 3107,3129 ----
    {
      return post_decls;
    }
+   /* Return the types to postprocess.  */
+   const vec<tree>& post_process_type ()
+   {
+     return post_types;
+   }
  private:
    /* Register DATA for postprocessing.  */
    void post_process (post_process_data data)
    {
      post_decls.safe_push (data);
    }
+   /* Register TYPE for postprocessing.  */
+   void post_process_type (tree type)
+   {
+     gcc_checking_assert (TYPE_P (type));
+     post_types.safe_push (type);
+   }
  
  private:
    void assert_definition (tree, bool installing);
*************** trees_in::trees_in (module_state *state)
*** 3107,3112 ****
--- 3136,3142 ----
    duplicates = NULL;
    back_refs.create (500);
    post_decls.create (0);
+   post_types.create (0);
  }
  
  trees_in::~trees_in ()
*************** trees_in::~trees_in ()
*** 3114,3119 ****
--- 3144,3150 ----
    delete (duplicates);
    back_refs.release ();
    post_decls.release ();
+   post_types.release ();
  }
  
  /* Tree stream writer.  */
*************** trees_out::type_node (tree type)
*** 9727,9742 ****
  	tree_node (DECL_NAME (TYPE_NAME (type)));
  	tree_node (TYPENAME_TYPE_FULLNAME (type));
  	if (streaming_p ())
! 	  {
! 	    enum tag_types tag_type = none_type;
! 	    if (TYPENAME_IS_ENUM_P (type))
! 	      tag_type = enum_type;
! 	    else if (TYPENAME_IS_CLASS_P (type))
! 	      tag_type = class_type;
! 	    else if (TYPENAME_IS_UNION_P (type))
! 	      tag_type = union_type;
! 	    u (int (tag_type));
! 	  }
  	}
        break;
  
--- 9758,9764 ----
  	tree_node (DECL_NAME (TYPE_NAME (type)));
  	tree_node (TYPENAME_TYPE_FULLNAME (type));
  	if (streaming_p ())
! 	  u (get_typename_tag (type));
  	}
        break;
  
*************** trees_out::tree_value (tree t)
*** 9798,9803 ****
--- 9820,9828 ----
  				  && !DECL_CONTEXT (t)))
  			  && TREE_CODE (t) != FUNCTION_DECL));
  
+   if (is_initial_scan () && EXPR_P (t))
+     dep_hash->add_dependent_adl_entities (t);
+ 
    if (streaming_p ())
      {
        /* A new node -> tt_node.  */
*************** trees_in::tree_node (bool is_use)
*** 10411,10420 ****
  
  	  case ARRAY_TYPE:
  	    {
  	      tree domain = tree_node ();
  	      int dep = u ();
  	      if (!get_overrun ())
! 		res = build_cplus_array_type (res, domain, dep);
  	    }
  	    break;
  
--- 10436,10458 ----
  
  	  case ARRAY_TYPE:
  	    {
+ 	      tree elt_type = res;
  	      tree domain = tree_node ();
  	      int dep = u ();
  	      if (!get_overrun ())
! 		{
! 		  res = build_cplus_array_type (elt_type, domain, dep);
! 		  /* If we're an array of an incomplete imported type,
! 		     save it for post-processing so that we can attempt
! 		     to complete the type later if it will get a
! 		     definition later in the cluster.  */
! 		  if (!dep
! 		      && !COMPLETE_TYPE_P (elt_type)
! 		      && CLASS_TYPE_P (elt_type)
! 		      && DECL_LANG_SPECIFIC (TYPE_NAME (elt_type))
! 		      && DECL_MODULE_IMPORT_P (TYPE_NAME (elt_type)))
! 		    post_process_type (res);
! 		}
  	    }
  	    break;
  
*************** depset::hash::add_class_entities (vec<tr
*** 14962,14967 ****
--- 15000,15089 ----
      }
  }
  
+ /* Add any entities found via dependent ADL.  */
+ 
+ void
+ depset::hash::add_dependent_adl_entities (tree expr)
+ {
+   gcc_checking_assert (!is_key_order ());
+   if (TREE_CODE (current->get_entity ()) != TEMPLATE_DECL)
+     return;
+ 
+   dep_adl_info info;
+   switch (TREE_CODE (expr))
+     {
+     case CALL_EXPR:
+       if (!KOENIG_LOOKUP_P (expr))
+ 	return;
+       info.name = CALL_EXPR_FN (expr);
+       if (!info.name)
+ 	return;
+       if (TREE_CODE (info.name) == TEMPLATE_ID_EXPR)
+ 	info.name = TREE_OPERAND (info.name, 0);
+       if (TREE_CODE (info.name) == TU_LOCAL_ENTITY)
+ 	return;
+       if (!identifier_p (info.name))
+ 	info.name = OVL_NAME (info.name);
+       for (int ix = 0; ix < call_expr_nargs (expr); ix++)
+ 	vec_safe_push (info.args, CALL_EXPR_ARG (expr, ix));
+       break;
+ 
+     case LE_EXPR:
+     case GE_EXPR:
+     case LT_EXPR:
+     case GT_EXPR:
+       info.rewrite = SPACESHIP_EXPR;
+       goto overloadable_expr;
+ 
+     case NE_EXPR:
+       info.rewrite = EQ_EXPR;
+       goto overloadable_expr;
+ 
+     case EQ_EXPR:
+       /* Not strictly a rewrite candidate, but we need to ensure
+ 	 that lookup of a matching NE_EXPR can succeed if that
+ 	 would inhibit a rewrite with reversed parameters.  */
+       info.rewrite = NE_EXPR;
+       goto overloadable_expr;
+ 
+     case COMPOUND_EXPR:
+     case MEMBER_REF:
+     case MULT_EXPR:
+     case TRUNC_DIV_EXPR:
+     case TRUNC_MOD_EXPR:
+     case PLUS_EXPR:
+     case MINUS_EXPR:
+     case LSHIFT_EXPR:
+     case RSHIFT_EXPR:
+     case SPACESHIP_EXPR:
+     case BIT_AND_EXPR:
+     case BIT_XOR_EXPR:
+     case BIT_IOR_EXPR:
+     case TRUTH_ANDIF_EXPR:
+     case TRUTH_ORIF_EXPR:
+     overloadable_expr:
+       info.name = ovl_op_identifier (TREE_CODE (expr));
+       gcc_checking_assert (tree_operand_length (expr) == 2);
+       vec_safe_push (info.args, TREE_OPERAND (expr, 0));
+       vec_safe_push (info.args, TREE_OPERAND (expr, 1));
+       break;
+ 
+     default:
+       return;
+     }
+ 
+   /* If all arguments are type-dependent we don't need to do
+      anything further, we won't find new entities.  */
+   processing_template_decl_sentinel ptds;
+   ++processing_template_decl;
+   if (!any_type_dependent_arguments_p (info.args))
+     return;
+ 
+   /* We need to defer name lookup until after walking, otherwise
+      we get confused by stray TREE_VISITEDs.  */
+   dep_adl_entity_list.safe_push (info);
+ }
+ 
  /* We add the partial & explicit specializations, and the explicit
     instantiations.  */
  
*************** depset::hash::find_dependencies (module_
*** 15323,15328 ****
--- 15445,15475 ----
  		  && deduction_guide_p (decl))
  		add_deduction_guides (TYPE_NAME (TREE_TYPE (TREE_TYPE (decl))));
  
+ 	      /* Handle dependent ADL for [module.global.frag] p3.3.  */
+ 	      if (!is_key_order () && !dep_adl_entity_list.is_empty ())
+ 		{
+ 		  processing_template_decl_sentinel ptds;
+ 		  ++processing_template_decl;
+ 		  for (auto &info : dep_adl_entity_list)
+ 		    {
+ 		      tree lookup = lookup_arg_dependent (info.name, NULL_TREE,
+ 							  info.args, true);
+ 		      for (tree fn : lkp_range (lookup))
+ 			add_dependency (make_dependency (fn, EK_DECL));
+ 
+ 		      if (info.rewrite)
+ 			{
+ 			  tree rewrite_name = ovl_op_identifier (info.rewrite);
+ 			  lookup = lookup_arg_dependent (rewrite_name, NULL_TREE,
+ 							 info.args, true);
+ 			  for (tree fn : lkp_range (lookup))
+ 			    add_dependency (make_dependency (fn, EK_DECL));
+ 			}
+ 		      release_tree_vector (info.args);
+ 		    }
+ 		  dep_adl_entity_list.truncate (0);
+ 		}
+ 
  	      if (!is_key_order ()
  		  && TREE_CODE (decl) == TEMPLATE_DECL
  		  && !DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (decl))
*************** module_state::read_cluster (unsigned snu
*** 17398,17403 ****
--- 17545,17557 ----
  	}
  
      }
+   for (const tree& type : sec.post_process_type ())
+     {
+       /* Attempt to complete an array type now in case its element type
+ 	 had a definition streamed later in the cluster.  */
+       gcc_checking_assert (TREE_CODE (type) == ARRAY_TYPE);
+       complete_type (type);
+     }
    set_cfun (old_cfun);
    current_function_decl = old_cfd;
    comparing_dependent_aliases--;
diff -Nrcpad gcc-16-20251214/gcc/cp/name-lookup.cc gcc-16-20251221/gcc/cp/name-lookup.cc
*** gcc-16-20251214/gcc/cp/name-lookup.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/cp/name-lookup.cc	Sun Dec 21 22:32:06 2025
*************** public:
*** 449,454 ****
--- 449,456 ----
  
    LOOK_want want;  /* What kind of entity we want.  */
  
+   bool tentative;  /* The lookup is just to find additional decl-reachable
+ 		      entities in this TU during modules streaming.  */
    bool deduping; /* Full deduping is needed because using declarations
  		    are in play.  */
    vec<tree, va_heap, vl_embed> *scopes;
*************** protected:
*** 463,469 ****
  public:
    name_lookup (tree n, LOOK_want w = LOOK_want::NORMAL)
    : name (n), value (NULL_TREE), type (NULL_TREE),
!     want (w),
      deduping (false), scopes (NULL), previous (NULL)
    {
      preserve_state ();
--- 465,471 ----
  public:
    name_lookup (tree n, LOOK_want w = LOOK_want::NORMAL)
    : name (n), value (NULL_TREE), type (NULL_TREE),
!     want (w), tentative (false),
      deduping (false), scopes (NULL), previous (NULL)
    {
      preserve_state ();
*************** name_lookup::preserve_state ()
*** 602,607 ****
--- 604,611 ----
  	    }
  	}
  
+       tentative = previous->tentative;
+ 
        /* Unmark the outer partial lookup.  */
        if (previous->deduping)
  	lookup_mark (previous->value, false);
*************** name_lookup::adl_namespace_fns (tree sco
*** 1252,1257 ****
--- 1256,1266 ----
  	      add_fns (ovl_skip_hidden (MAYBE_STAT_DECL (bind)));
  	    }
  
+ 	  /* When doing tentative name lookup we only care about entities
+ 	     in the current TU.  */
+ 	  if (tentative)
+ 	    return;
+ 
  	  /* Scan the imported bindings.  */
  	  unsigned ix = BINDING_VECTOR_NUM_CLUSTERS (val);
  	  if (BINDING_VECTOR_SLOTS_PER_CLUSTER == BINDING_SLOTS_FIXED)
*************** name_lookup::adl_class (tree type)
*** 1484,1490 ****
    if (found_p (type))
      return;
  
!   complete_type (type);
    adl_bases (type);
    mark_found (type);
  
--- 1493,1504 ----
    if (found_p (type))
      return;
  
!   /* Don't instantiate if we don't have to so we don't unnecessarily error
!      on incomplete types during modules streaming.  This does however mean
!      we incorrectly miss some decl-reachable entities (PR c++/123235).  */
!   if (!tentative)
!     complete_type (type);
! 
    adl_bases (type);
    mark_found (type);
  
*************** name_lookup::search_adl (tree fns, vec<t
*** 1679,1685 ****
         first arg. */
      if (TYPE_P (arg))
        adl_type (arg);
!     else
        adl_expr (arg);
  
    if (vec_safe_length (scopes))
--- 1693,1702 ----
         first arg. */
      if (TYPE_P (arg))
        adl_type (arg);
!     /* When processing a module CMI we might get a type-dependent
!        argument: treat as a placeholder with no associated namespace
!        or entities.  */
!     else if (!tentative || !type_dependent_expression_p (arg))
        adl_expr (arg);
  
    if (vec_safe_length (scopes))
*************** name_lookup::search_adl (tree fns, vec<t
*** 1690,1699 ****
  	dedup (true);
  
        /* First get the attached modules for each innermost non-inline
! 	 namespace of an associated entity.  */
        bitmap_obstack_initialize (NULL);
        hash_map<tree, bitmap> ns_mod_assocs;
!       if (modules_p ())
  	{
  	  for (tree scope : scopes)
  	    if (TYPE_P (scope))
--- 1707,1717 ----
  	dedup (true);
  
        /* First get the attached modules for each innermost non-inline
! 	 namespace of an associated entity.  This isn't needed for
! 	 tentative lookup, as we're only interested in the current TU.  */
        bitmap_obstack_initialize (NULL);
        hash_map<tree, bitmap> ns_mod_assocs;
!       if (modules_p () && !tentative)
  	{
  	  for (tree scope : scopes)
  	    if (TYPE_P (scope))
*************** name_lookup::search_adl (tree fns, vec<t
*** 1732,1738 ****
  	      adl_namespace_fns (scope, visible, inst_path,
  				 assocs ? *assocs : NULL);
  	    }
! 	  else if (RECORD_OR_UNION_TYPE_P (scope))
  	    adl_class_fns (scope);
  	}
  
--- 1750,1759 ----
  	      adl_namespace_fns (scope, visible, inst_path,
  				 assocs ? *assocs : NULL);
  	    }
! 	  else if (RECORD_OR_UNION_TYPE_P (scope) && !tentative)
! 	    /* We don't need to look at friends when searching for
! 	       new decl-reachable entities as they will already be
! 	       considered reachable by importers.  */
  	    adl_class_fns (scope);
  	}
  
*************** static void consider_binding_level (tree
*** 1756,1768 ****
  
  /* ADL lookup of NAME.  FNS is the result of regular lookup, and we
     don't add duplicates to it.  ARGS is the vector of call
!    arguments (which will not be empty).  */
  
  tree
! lookup_arg_dependent (tree name, tree fns, vec<tree, va_gc> *args)
  {
    auto_cond_timevar tv (TV_NAME_LOOKUP);
    name_lookup lookup (name);
    return lookup.search_adl (fns, args);
  }
  
--- 1777,1793 ----
  
  /* ADL lookup of NAME.  FNS is the result of regular lookup, and we
     don't add duplicates to it.  ARGS is the vector of call
!    arguments (which will not be empty).  TENTATIVE is true when
!    this is early lookup only for the purpose of finding more
!    decl-reachable declarations.  */
  
  tree
! lookup_arg_dependent (tree name, tree fns, vec<tree, va_gc> *args,
! 		      bool tentative/*=false*/)
  {
    auto_cond_timevar tv (TV_NAME_LOOKUP);
    name_lookup lookup (name);
+   lookup.tentative = tentative;
    return lookup.search_adl (fns, args);
  }
  
*************** maybe_record_mergeable_decl (tree *slot,
*** 3791,3797 ****
      (slot, name, is_attached ? BINDING_SLOT_PARTITION : BINDING_SLOT_GLOBAL,
       true);
  
!   if (!is_attached)
      {
        binding_slot &orig
  	= BINDING_VECTOR_CLUSTER (*slot, 0).slots[BINDING_SLOT_CURRENT];
--- 3816,3824 ----
      (slot, name, is_attached ? BINDING_SLOT_PARTITION : BINDING_SLOT_GLOBAL,
       true);
  
!   /* A namespace is always global module so there's no need to mark
!      the current binding slot as such.  */
!   if (!is_attached && TREE_CODE (decl) != NAMESPACE_DECL)
      {
        binding_slot &orig
  	= BINDING_VECTOR_CLUSTER (*slot, 0).slots[BINDING_SLOT_CURRENT];
diff -Nrcpad gcc-16-20251214/gcc/cp/name-lookup.h gcc-16-20251221/gcc/cp/name-lookup.h
*** gcc-16-20251214/gcc/cp/name-lookup.h	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/cp/name-lookup.h	Sun Dec 21 22:32:06 2025
*************** extern void push_decl_namespace (tree);
*** 461,467 ****
  extern void pop_decl_namespace (void);
  extern void do_namespace_alias (location_t, tree, tree);
  extern tree do_class_using_decl (tree, tree);
! extern tree lookup_arg_dependent (tree, tree, vec<tree, va_gc> *);
  extern tree search_anon_aggr (tree, tree, bool = false);
  extern tree get_class_binding_direct (tree, tree, bool want_type = false);
  extern tree get_class_binding (tree, tree, bool want_type = false);
--- 461,468 ----
  extern void pop_decl_namespace (void);
  extern void do_namespace_alias (location_t, tree, tree);
  extern tree do_class_using_decl (tree, tree);
! extern tree lookup_arg_dependent (tree, tree, vec<tree, va_gc> *,
! 				  bool tentative = false);
  extern tree search_anon_aggr (tree, tree, bool = false);
  extern tree get_class_binding_direct (tree, tree, bool want_type = false);
  extern tree get_class_binding (tree, tree, bool want_type = false);
diff -Nrcpad gcc-16-20251214/gcc/cp/parser.cc gcc-16-20251221/gcc/cp/parser.cc
*** gcc-16-20251214/gcc/cp/parser.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/cp/parser.cc	Sun Dec 21 22:32:06 2025
*************** static cp_token_cache *cp_token_cache_ne
*** 260,266 ****
  static tree cp_parser_late_noexcept_specifier
    (cp_parser *, tree);
  static void noexcept_override_late_checks
!   (tree);
  
  static void cp_parser_initial_pragma
    (cp_token *);
--- 260,266 ----
  static tree cp_parser_late_noexcept_specifier
    (cp_parser *, tree);
  static void noexcept_override_late_checks
!   (tree, tree);
  
  static void cp_parser_initial_pragma
    (cp_token *);
*************** static tree omp_start_variant_function
*** 277,282 ****
--- 277,283 ----
    (cp_declarator *, tree);
  static int omp_finish_variant_function
    (cp_parser *, tree, tree, tree, bool, bool);
+ static void maybe_start_implicit_template (cp_parser *parser);
  
  /* Manifest constants.  */
  #define CP_LEXER_BUFFER_SIZE ((256 * 1024) / sizeof (cp_token))
*************** cp_parser_lambda_expression (cp_parser*
*** 12041,12046 ****
--- 12042,12048 ----
          = parser->auto_is_implicit_function_template_parm_p;
      bool saved_omp_array_section_p = parser->omp_array_section_p;
      bool saved_in_targ = parser->in_template_argument_list_p;
+     bool saved_in_declarator_p = parser->in_declarator_p;
  
      parser->num_template_parameter_lists = 0;
      parser->in_statement = 0;
*************** cp_parser_lambda_expression (cp_parser*
*** 12051,12056 ****
--- 12053,12059 ----
      parser->auto_is_implicit_function_template_parm_p = false;
      parser->omp_array_section_p = false;
      parser->in_template_argument_list_p = false;
+     parser->in_declarator_p = false;
  
      /* Inside the lambda, outside unevaluated context do not apply.  */
      cp_evaluated ev;
*************** cp_parser_lambda_expression (cp_parser*
*** 12118,12123 ****
--- 12121,12127 ----
  	= auto_is_implicit_function_template_parm_p;
      parser->omp_array_section_p = saved_omp_array_section_p;
      parser->in_template_argument_list_p = saved_in_targ;
+     parser->in_declarator_p = saved_in_declarator_p;
    }
  
    /* This lambda shouldn't have any proxies left at this point.  */
*************** cp_build_range_for_decls (location_t loc
*** 15284,15289 ****
--- 15288,15295 ----
      }
  
    /* The new for initialization statement.  */
+   if (expansion_stmt_p && !TYPE_REF_P (iter_type))
+     iter_type = cp_build_qualified_type (iter_type, TYPE_QUAL_CONST);
    tree begin = build_decl (loc, VAR_DECL, for_begin__identifier, iter_type);
    TREE_USED (begin) = 1;
    DECL_ARTIFICIAL (begin) = 1;
*************** cp_build_range_for_decls (location_t loc
*** 15299,15305 ****
  		  LOOKUP_ONLYCONVERTING);
  
    if (cxx_dialect >= cxx17)
!     iter_type = cv_unqualified (TREE_TYPE (end_expr));
    tree end = build_decl (loc, VAR_DECL, for_end__identifier, iter_type);
    TREE_USED (end) = 1;
    DECL_ARTIFICIAL (end) = 1;
--- 15305,15315 ----
  		  LOOKUP_ONLYCONVERTING);
  
    if (cxx_dialect >= cxx17)
!     {
!       iter_type = cv_unqualified (TREE_TYPE (end_expr));
!       if (expansion_stmt_p && !TYPE_REF_P (iter_type))
! 	iter_type = cp_build_qualified_type (iter_type, TYPE_QUAL_CONST);
!     }
    tree end = build_decl (loc, VAR_DECL, for_end__identifier, iter_type);
    TREE_USED (end) = 1;
    DECL_ARTIFICIAL (end) = 1;
*************** cp_parser_template_id (cp_parser *parser
*** 20284,20289 ****
--- 20294,20306 ----
    if (templ == error_mark_node || is_identifier)
      return templ;
  
+   /* If we see a concept name in a parameter-list, it's a type-constraint in an
+      abbreviated function template, so enter template scope before parsing the
+      template arguments.  */
+   if (parser->auto_is_implicit_function_template_parm_p
+       && concept_definition_p (templ))
+     maybe_start_implicit_template (parser);
+ 
    /* Since we're going to preserve any side-effects from this parse, set up a
       firewall to protect our callers from cp_parser_commit_to_tentative_parse
       in the template arguments.  */
*************** cp_parser_template_id (cp_parser *parser
*** 20426,20435 ****
  	   && TREE_CODE (TREE_TYPE (templ)) == TYPENAME_TYPE)
      {
        /* Some type template in dependent scope.  */
!       tree &name = TYPENAME_TYPE_FULLNAME (TREE_TYPE (templ));
!       name = build_min_nt_loc (combined_loc,
! 			       TEMPLATE_ID_EXPR,
! 			       name, arguments);
        template_id = templ;
      }
    else
--- 20443,20457 ----
  	   && TREE_CODE (TREE_TYPE (templ)) == TYPENAME_TYPE)
      {
        /* Some type template in dependent scope.  */
!       tree fullname = TYPENAME_TYPE_FULLNAME (TREE_TYPE (templ));
!       fullname = build_min_nt_loc (combined_loc,
! 				   TEMPLATE_ID_EXPR,
! 				   fullname, arguments);
!       TREE_TYPE (templ)
! 	= build_typename_type (TYPE_CONTEXT (TREE_TYPE (templ)),
! 			       TYPE_IDENTIFIER (TREE_TYPE (templ)),
! 			       fullname,
! 			       get_typename_tag (TREE_TYPE (templ)));
        template_id = templ;
      }
    else
*************** omp_maybe_record_variant_base (cp_parser
*** 24880,24887 ****
     befriended it).
  
     If FUNCTION_DEFINITION_ALLOWED_P then we handle the declarator and
!    for a function-definition here as well.  If the declarator is a
!    declarator for a function-definition, *FUNCTION_DEFINITION_P will
     be TRUE upon return.  By that point, the function-definition will
     have been completely parsed.
  
--- 24902,24909 ----
     befriended it).
  
     If FUNCTION_DEFINITION_ALLOWED_P then we handle the declarator and
!    the rest of a function-definition here as well.  If the declarator is
!    a declarator for a function-definition, *FUNCTION_DEFINITION_P will
     be TRUE upon return.  By that point, the function-definition will
     have been completely parsed.
  
*************** cp_parser_class_specifier (cp_parser* pa
*** 28982,28990 ****
        /* If there are noexcept-specifiers that have not yet been processed,
  	 take care of them now.  Do this before processing NSDMIs as they
  	 may depend on noexcept-specifiers already having been processed.  */
!       FOR_EACH_VEC_SAFE_ELT (unparsed_noexcepts, ix, decl)
  	{
! 	  tree ctx = DECL_CONTEXT (decl);
  	  switch_to_class (ctx);
  
  	  tree def_parse = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (decl));
--- 29004,29013 ----
        /* If there are noexcept-specifiers that have not yet been processed,
  	 take care of them now.  Do this before processing NSDMIs as they
  	 may depend on noexcept-specifiers already having been processed.  */
!       FOR_EACH_VEC_SAFE_ELT (unparsed_noexcepts, ix, e)
  	{
! 	  decl = e->decl;
! 	  tree ctx = e->class_type;
  	  switch_to_class (ctx);
  
  	  tree def_parse = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (decl));
*************** cp_parser_class_specifier (cp_parser* pa
*** 29027,29033 ****
  	  /* The finish_struct call above performed various override checking,
  	     but it skipped unparsed noexcept-specifier operands.  Now that we
  	     have resolved them, check again.  */
! 	  noexcept_override_late_checks (decl);
  
  	  /* Remove any member-function parameters from the symbol table.  */
  	  pop_injected_parms ();
--- 29050,29056 ----
  	  /* The finish_struct call above performed various override checking,
  	     but it skipped unparsed noexcept-specifier operands.  Now that we
  	     have resolved them, check again.  */
! 	  noexcept_override_late_checks (decl, ctx);
  
  	  /* Remove any member-function parameters from the symbol table.  */
  	  pop_injected_parms ();
*************** cp_parser_member_declaration (cp_parser*
*** 30305,30314 ****
  	      int ctor_dtor_or_conv_p;
  	      bool static_p = (decl_specifiers.storage_class == sc_static);
  	      cp_parser_flags flags = CP_PARSER_FLAGS_TYPENAME_OPTIONAL;
! 	      /* We can't delay parsing for friends,
! 		 alias-declarations, and typedefs, even though the
! 		 standard seems to require it.  */
! 	      if (!friend_p
  		  && !decl_spec_seq_has_spec_p (&decl_specifiers, ds_typedef))
  		flags |= CP_PARSER_FLAGS_DELAY_NOEXCEPT;
  
--- 30328,30338 ----
  	      int ctor_dtor_or_conv_p;
  	      bool static_p = (decl_specifiers.storage_class == sc_static);
  	      cp_parser_flags flags = CP_PARSER_FLAGS_TYPENAME_OPTIONAL;
! 	      /* We can't delay parsing for alias-declarations and typedefs,
! 		 even though the standard seems to require it.  */
! 	      /* FIXME: Delay parsing for all friends, not just templated
! 		 ones (PR114764).  */
! 	      if ((!friend_p || current_template_depth > 0)
  		  && !decl_spec_seq_has_spec_p (&decl_specifiers, ds_typedef))
  		flags |= CP_PARSER_FLAGS_DELAY_NOEXCEPT;
  
*************** cp_parser_late_noexcept_specifier (cp_pa
*** 31046,31054 ****
     overrides some virtual function with the same signature.  */
  
  static void
! noexcept_override_late_checks (tree fndecl)
  {
!   tree binfo = TYPE_BINFO (DECL_CONTEXT (fndecl));
    tree base_binfo;
  
    if (DECL_STATIC_FUNCTION_P (fndecl))
--- 31070,31078 ----
     overrides some virtual function with the same signature.  */
  
  static void
! noexcept_override_late_checks (tree fndecl, tree class_type)
  {
!   tree binfo = TYPE_BINFO (class_type);
    tree base_binfo;
  
    if (DECL_STATIC_FUNCTION_P (fndecl))
*************** noexcept_override_late_checks (tree fnde
*** 31058,31064 ****
      {
        tree basetype = BINFO_TYPE (base_binfo);
  
!       if (!TYPE_POLYMORPHIC_P (basetype))
  	continue;
  
        tree fn = look_for_overrides_here (basetype, fndecl);
--- 31082,31088 ----
      {
        tree basetype = BINFO_TYPE (base_binfo);
  
!       if (!CLASS_TYPE_P (basetype) || !TYPE_POLYMORPHIC_P (basetype))
  	continue;
  
        tree fn = look_for_overrides_here (basetype, fndecl);
*************** cp_parser_lookup_name (cp_parser *parser
*** 34225,34231 ****
  	   parse, those errors are valid.  */
  	decl = lookup_member (object_type,
  			      name,
! 			      /*protect=*/0,
  			      /*prefer_type=*/tag_type != none_type,
  			      tf_warning_or_error);
        else
--- 34249,34255 ----
  	   parse, those errors are valid.  */
  	decl = lookup_member (object_type,
  			      name,
! 			      /*protect=*/2,
  			      /*prefer_type=*/tag_type != none_type,
  			      tf_warning_or_error);
        else
*************** cp_parser_single_declaration (cp_parser*
*** 35349,35357 ****
  	  || decl_specifiers.type != error_mark_node))
      {
        int flags = CP_PARSER_FLAGS_TYPENAME_OPTIONAL;
!       /* We don't delay parsing for friends, though CWG 2510 may change
! 	 that.  */
!       if (member_p && !(friend_p && *friend_p))
  	flags |= CP_PARSER_FLAGS_DELAY_NOEXCEPT;
        decl = cp_parser_init_declarator (parser,
  					flags,
--- 35373,35382 ----
  	  || decl_specifiers.type != error_mark_node))
      {
        int flags = CP_PARSER_FLAGS_TYPENAME_OPTIONAL;
!       /* FIXME: Delay parsing for all template friends, not just class
! 	 template scope ones (PR114764).  */
!       if (member_p && (!(friend_p && *friend_p)
! 		       || current_template_depth > 1))
  	flags |= CP_PARSER_FLAGS_DELAY_NOEXCEPT;
        decl = cp_parser_init_declarator (parser,
  					flags,
*************** cp_parser_save_default_args (cp_parser*
*** 35854,35860 ****
    /* Remember if there is a noexcept-specifier to post process.  */
    tree spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (decl));
    if (UNPARSED_NOEXCEPT_SPEC_P (spec))
!     vec_safe_push (unparsed_noexcepts, decl);
  
    /* Contracts are deferred.  */
    for (tree attr = DECL_ATTRIBUTES (decl); attr; attr = TREE_CHAIN (attr))
--- 35879,35888 ----
    /* Remember if there is a noexcept-specifier to post process.  */
    tree spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (decl));
    if (UNPARSED_NOEXCEPT_SPEC_P (spec))
!     {
!       cp_default_arg_entry entry = {current_class_type, decl};
!       vec_safe_push (unparsed_noexcepts, entry);
!     }
  
    /* Contracts are deferred.  */
    for (tree attr = DECL_ATTRIBUTES (decl); attr; attr = TREE_CHAIN (attr))
*************** cp_parser_omp_clause_allocate (cp_parser
*** 42795,42805 ****
--- 42823,42838 ----
     allocator ( traits-array )
     allocator ( traits-array ) , allocator-list
  
+    Deprecated in 5.2, removed in 6.0: 'allocator(trait-array)' syntax.
+ 
     OpenMP 5.2:
  
     uses_allocators ( modifier : allocator-list )
     uses_allocators ( modifier , modifier : allocator-list )
  
+    OpenMP 6.0:
+    uses_allocators ( [modifier-list :] allocator-list [; ...] )
+ 
     modifier:
     traits ( traits-array )
     memspace ( mem-space-handle )  */
*************** cp_parser_omp_clause_uses_allocators (cp
*** 42814,42819 ****
--- 42847,42854 ----
    if (!parens.require_open (parser))
      return list;
  
+ parse_next:
+ 
    bool has_modifiers = false;
    bool seen_allocators = false;
    tree memspace_expr = NULL_TREE;
*************** cp_parser_omp_clause_uses_allocators (cp
*** 42968,42976 ****
--- 43003,43018 ----
  	break;
      }
  
+   if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
+     {
+       cp_lexer_consume_token (parser->lexer);
+       goto parse_next;
+     }
+ 
    if (!parens.require_close (parser))
      goto end;
    return nl;
+ 
   end:
    cp_parser_skip_to_closing_parenthesis (parser,
  					 /*recovering=*/true,
*************** cp_parser_omp_clause_linear (cp_parser *
*** 43084,43090 ****
    else
      {
        size_t end = cp_parser_skip_balanced_tokens (parser, 1);
!       cp_token *next = UNKNOWN_LOCATION;
        if (end > 1
  	  && cp_lexer_nth_token_is (parser->lexer, end - 1, CPP_CLOSE_PAREN))
  	{
--- 43126,43132 ----
    else
      {
        size_t end = cp_parser_skip_balanced_tokens (parser, 1);
!       cp_token *next = NULL;
        if (end > 1
  	  && cp_lexer_nth_token_is (parser->lexer, end - 1, CPP_CLOSE_PAREN))
  	{
*************** cp_parser_omp_target_update (cp_parser *
*** 50649,50654 ****
--- 50691,50697 ----
  	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULTMAP)	\
  	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND)	\
  	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE)	\
+ 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE_TYPE)	\
  	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DYN_GROUPPRIVATE) \
  	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE)	\
  	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_HAS_DEVICE_ADDR) \
*************** cp_parser_omp_context_selector_specifica
*** 51944,51963 ****
    return nreverse (ret);
  }
  
! /* Assumption clauses:
!    OpenMP 5.1
     absent (directive-name-list)
     contains (directive-name-list)
     holds (expression)
     no_openmp
     no_openmp_routines
!    no_parallelism  */
  
  static void
  cp_parser_omp_assumption_clauses (cp_parser *parser, cp_token *pragma_tok,
  				  bool is_assume)
  {
    bool no_openmp = false;
    bool no_openmp_routines = false;
    bool no_parallelism = false;
    bitmap_head absent_head, contains_head;
--- 51987,52010 ----
    return nreverse (ret);
  }
  
! /* Assumption clauses
!    OpenMP 5.1:
     absent (directive-name-list)
     contains (directive-name-list)
     holds (expression)
     no_openmp
     no_openmp_routines
!    no_parallelism
! 
!    OpenMP 6.0:
!    no_openmp_constructs  */
  
  static void
  cp_parser_omp_assumption_clauses (cp_parser *parser, cp_token *pragma_tok,
  				  bool is_assume)
  {
    bool no_openmp = false;
+   bool no_openmp_constructs = false;
    bool no_openmp_routines = false;
    bool no_parallelism = false;
    bitmap_head absent_head, contains_head;
*************** cp_parser_omp_assumption_clauses (cp_par
*** 51990,51995 ****
--- 52037,52049 ----
  	    error_at (cloc, "too many %qs clauses", "no_openmp");
  	  no_openmp = true;
  	}
+       else if (!strcmp (p, "no_openmp_constructs"))
+ 	{
+ 	  cp_lexer_consume_token (parser->lexer);
+ 	  if (no_openmp_constructs)
+ 	    error_at (cloc, "too many %qs clauses", "no_openmp_constructs");
+ 	  no_openmp_constructs = true;
+ 	}
        else if (!strcmp (p, "no_openmp_routines"))
  	{
  	  cp_lexer_consume_token (parser->lexer);
*************** make_generic_type_name ()
*** 56277,56314 ****
    return get_identifier (buf);
  }
  
! /* Add an implicit template type parameter to the CURRENT_TEMPLATE_PARMS
!    (creating a new template parameter list if necessary).  Returns the newly
!    created template type parm.  */
  
! static tree
! synthesize_implicit_template_parm  (cp_parser *parser, tree constr)
  {
-   /* A requires-clause is not a function and cannot have placeholders.  */
-   if (current_binding_level->requires_expression)
-     {
-       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
-      parameters.  */
- 
-   cp_binding_level *const entry_scope = current_binding_level;
- 
-   bool become_template = false;
-   cp_binding_level *parent_scope = 0;
- 
    if (parser->implicit_template_scope)
!     {
!       gcc_assert (parser->implicit_template_parms);
! 
!       current_binding_level = parser->implicit_template_scope;
!     }
    else
      {
        /* Roll back to the existing template parameter scope (in the case of
--- 56331,56344 ----
    return get_identifier (buf);
  }
  
! /* We're declaring an abbreviated function template, make sure that
!    parser->implicit_template_scope is set. */
  
! static void
! maybe_start_implicit_template (cp_parser *parser)
  {
    if (parser->implicit_template_scope)
!     return;
    else
      {
        /* Roll back to the existing template parameter scope (in the case of
*************** synthesize_implicit_template_parm  (cp_p
*** 56317,56323 ****
--- 56347,56355 ----
  	 in the case of out-of-line member definitions).  The function scope is
  	 added back after template parameter synthesis below.  */
  
+       cp_binding_level *const entry_scope = current_binding_level;
        cp_binding_level *scope = entry_scope;
+       cp_binding_level *parent_scope = nullptr;
  
        while (scope->kind == sk_function_parms)
  	{
*************** synthesize_implicit_template_parm  (cp_p
*** 56370,56377 ****
  	  /* Introduce a new template parameter list for implicit template
  	     parameters.  */
  
- 	  become_template = true;
- 
  	  parser->implicit_template_scope
  	      = begin_scope (sk_template_parms, NULL);
  
--- 56402,56407 ----
*************** synthesize_implicit_template_parm  (cp_p
*** 56379,56384 ****
--- 56409,56420 ----
  
  	  parser->fully_implicit_function_template_p = true;
  	  ++parser->num_template_parameter_lists;
+ 
+ 	  parent_scope->level_chain = current_binding_level;
+ 
+ 	  current_template_parms
+ 	    = tree_cons (size_int (current_template_depth + 1),
+ 			 make_tree_vec (0), current_template_parms);
  	}
        else
  	{
*************** synthesize_implicit_template_parm  (cp_p
*** 56393,56400 ****
--- 56429,56465 ----
  	  parser->implicit_template_parms
  	    = TREE_VEC_ELT (v, TREE_VEC_LENGTH (v) - 1);
  	}
+ 
+       current_binding_level = entry_scope;
+     }
+ }
+ 
+ /* Add an implicit template type parameter to the CURRENT_TEMPLATE_PARMS
+    (creating a new template parameter list if necessary).  Returns the newly
+    created template type parm.  */
+ 
+ static tree
+ synthesize_implicit_template_parm  (cp_parser *parser, tree constr)
+ {
+   /* A requires-clause is not a function and cannot have placeholders.  */
+   if (current_binding_level->requires_expression)
+     {
+       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
+      parameters.  */
+ 
+   cp_binding_level *const entry_scope = current_binding_level;
+ 
+   maybe_start_implicit_template (parser);
+   current_binding_level = parser->implicit_template_scope;
+ 
    /* Synthesize a new template parameter and track the current template
       parameter chain with implicit_template_parms.  */
  
*************** synthesize_implicit_template_parm  (cp_p
*** 56406,56415 ****
    gcc_assert(!proto || TREE_CODE (proto) == TYPE_DECL);
    tree synth_tmpl_parm = finish_template_type_parm (class_type_node, synth_id);
  
-   if (become_template)
-     current_template_parms = tree_cons (size_int (current_template_depth + 1),
- 					NULL_TREE, current_template_parms);
- 
    /* Attach the constraint to the parm before processing.  */
    tree node = build_tree_list (NULL_TREE, synth_tmpl_parm);
    TREE_TYPE (node) = constr;
--- 56471,56476 ----
*************** synthesize_implicit_template_parm  (cp_p
*** 56449,56469 ****
       template parameter list with this synthesized type, otherwise grow the
       current template parameter list.  */
  
!   if (become_template)
!     {
!       parent_scope->level_chain = current_binding_level;
! 
!       tree new_parms = make_tree_vec (1);
!       TREE_VEC_ELT (new_parms, 0) = parser->implicit_template_parms;
!       TREE_VALUE (current_template_parms) = new_parms;
!     }
!   else
!     {
!       tree& new_parms = INNERMOST_TEMPLATE_PARMS (current_template_parms);
!       int new_parm_idx = TREE_VEC_LENGTH (new_parms);
!       new_parms = grow_tree_vec (new_parms, new_parm_idx + 1);
!       TREE_VEC_ELT (new_parms, new_parm_idx) = parser->implicit_template_parms;
!     }
  
    /* If the new parameter was constrained, we need to add that to the
       constraints in the template parameter list.  */
--- 56510,56519 ----
       template parameter list with this synthesized type, otherwise grow the
       current template parameter list.  */
  
!   tree& new_parms = INNERMOST_TEMPLATE_PARMS (current_template_parms);
!   int new_parm_idx = TREE_VEC_LENGTH (new_parms);
!   new_parms = grow_tree_vec (new_parms, new_parm_idx + 1);
!   TREE_VEC_ELT (new_parms, new_parm_idx) = parser->implicit_template_parms;
  
    /* If the new parameter was constrained, we need to add that to the
       constraints in the template parameter list.  */
diff -Nrcpad gcc-16-20251214/gcc/cp/parser.h gcc-16-20251221/gcc/cp/parser.h
*** gcc-16-20251214/gcc/cp/parser.h	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/cp/parser.h	Sun Dec 21 22:32:06 2025
*************** struct GTY(()) cp_unparsed_functions_ent
*** 181,187 ****
    vec<tree, va_gc> *nsdmis;
  
    /* Functions with noexcept-specifiers that require post-processing.  */
!   vec<tree, va_gc> *noexcepts;
  
    /* Functions with contract attributes that require post-processing.  */
    vec<tree, va_gc> *contracts;
--- 181,187 ----
    vec<tree, va_gc> *nsdmis;
  
    /* Functions with noexcept-specifiers that require post-processing.  */
!   vec<cp_default_arg_entry, va_gc> *noexcepts;
  
    /* Functions with contract attributes that require post-processing.  */
    vec<tree, va_gc> *contracts;
diff -Nrcpad gcc-16-20251214/gcc/cp/pt.cc gcc-16-20251221/gcc/cp/pt.cc
*** gcc-16-20251214/gcc/cp/pt.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/cp/pt.cc	Sun Dec 21 22:32:06 2025
*************** tsubst (tree t, tree args, tsubst_flags_
*** 17323,17336 ****
  	      return error_mark_node;
  	  }
  
! 	/* FIXME: TYPENAME_IS_CLASS_P conflates 'class' vs 'struct' tags.
! 	   TYPENAME_TYPE should probably remember the exact tag that
! 	   was written for -Wmismatched-tags.  */
! 	enum tag_types tag_type
! 	  = (TYPENAME_IS_CLASS_P (t) ? class_type
! 	     : TYPENAME_IS_UNION_P (t) ? union_type
! 	     : TYPENAME_IS_ENUM_P (t) ? enum_type
! 	     : typename_type);
  	tsubst_flags_t tcomplain = complain | tf_keep_type_decl;
  	tcomplain |= tst_ok_flag | qualifying_scope_flag;
  	f = make_typename_type (ctx, f, tag_type, tcomplain);
--- 17323,17329 ----
  	      return error_mark_node;
  	  }
  
! 	enum tag_types tag_type = get_typename_tag (t);
  	tsubst_flags_t tcomplain = complain | tf_keep_type_decl;
  	tcomplain |= tst_ok_flag | qualifying_scope_flag;
  	f = make_typename_type (ctx, f, tag_type, tcomplain);
*************** tsubst (tree t, tree args, tsubst_flags_
*** 17342,17348 ****
  	    f = TREE_TYPE (f);
  	  }
  
! 	if (TREE_CODE (f) != TYPENAME_TYPE)
  	  {
  	    if (TYPENAME_IS_ENUM_P (t) && TREE_CODE (f) != ENUMERAL_TYPE)
  	      {
--- 17335,17341 ----
  	    f = TREE_TYPE (f);
  	  }
  
! 	if (!WILDCARD_TYPE_P (f))
  	  {
  	    if (TYPENAME_IS_ENUM_P (t) && TREE_CODE (f) != ENUMERAL_TYPE)
  	      {
*************** tsubst (tree t, tree args, tsubst_flags_
*** 17352,17358 ****
  		else
  		  return error_mark_node;
  	      }
! 	    else if (TYPENAME_IS_CLASS_P (t) && !NON_UNION_CLASS_TYPE_P (f))
  	      {
  		if (complain & tf_error)
  		  error ("%qT resolves to %qT, which is not a non-union "
--- 17345,17352 ----
  		else
  		  return error_mark_node;
  	      }
! 	    else if (TYPENAME_IS_CLASS_OR_STRUCT_P (t)
! 		     && !NON_UNION_CLASS_TYPE_P (f))
  	      {
  		if (complain & tf_error)
  		  error ("%qT resolves to %qT, which is not a non-union "
*************** tsubst_lambda_expr (tree t, tree args, t
*** 20589,20595 ****
        return error_mark_node;
      }
  
!   if (LAMBDA_EXPR_EXTRA_SCOPE (t))
      record_lambda_scope (r);
    if (TYPE_NAMESPACE_SCOPE_P (TREE_TYPE (t)))
      /* If we're pushed into another scope (PR105652), fix it.  */
--- 20583,20594 ----
        return error_mark_node;
      }
  
!   if (LAMBDA_EXPR_EXTRA_SCOPE (t)
!       /* When evaluating a concept we instantiate any lambda bodies
! 	 in the context of the evaluation.  For ABI reasons don't
! 	 record a scope for this instantiated lambda so we don't
! 	 throw off the scope counter.  */
!       && TREE_CODE (LAMBDA_EXPR_EXTRA_SCOPE (t)) != CONCEPT_DECL)
      record_lambda_scope (r);
    if (TYPE_NAMESPACE_SCOPE_P (TREE_TYPE (t)))
      /* If we're pushed into another scope (PR105652), fix it.  */
*************** dependent_scope_p (tree scope)
*** 29072,29087 ****
  bool
  dependentish_scope_p (tree scope)
  {
!   return dependent_scope_p (scope) || any_dependent_bases_p (scope)
!     /* A noexcept-spec is a complete-class context, so this should never hold.
!        But since we don't implement deferred noexcept-spec parsing of a friend
!        declaration (PR114764) we compensate by treating the current
!        instantiation as dependent to avoid bogus name lookup failures in this
!        case (PR122668).  */
!     || (cp_noexcept_operand
! 	&& CLASS_TYPE_P (scope)
! 	&& TYPE_BEING_DEFINED (scope)
! 	&& dependent_type_p (scope));
  }
  
  /* T is a SCOPE_REF.  Return whether it represents a non-static member of
--- 29071,29077 ----
  bool
  dependentish_scope_p (tree scope)
  {
!   return dependent_scope_p (scope) || any_dependent_bases_p (scope);
  }
  
  /* T is a SCOPE_REF.  Return whether it represents a non-static member of
*************** type_targs_deducible_from (tree tmpl, tr
*** 31641,31647 ****
  	 per alias_ctad_tweaks.  */
        tparms = INNERMOST_TEMPLATE_PARMS (TREE_PURPOSE (tmpl));
        ttype = TREE_VALUE (tmpl);
!       tmpl = TI_TEMPLATE (TYPE_TEMPLATE_INFO_MAYBE_ALIAS (ttype));
      }
  
    int len = TREE_VEC_LENGTH (tparms);
--- 31631,31641 ----
  	 per alias_ctad_tweaks.  */
        tparms = INNERMOST_TEMPLATE_PARMS (TREE_PURPOSE (tmpl));
        ttype = TREE_VALUE (tmpl);
!       tree ti = TYPE_TEMPLATE_INFO_MAYBE_ALIAS (ttype);
!       if (!ti)
! 	/* TTYPE is a typedef to a template-id.  */
! 	ti = TYPE_TEMPLATE_INFO (ttype);
!       tmpl = TI_TEMPLATE (ti);
      }
  
    int len = TREE_VEC_LENGTH (tparms);
*************** finish_expansion_stmt (tree expansion_st
*** 32857,32863 ****
        begin = cp_build_range_for_decls (loc, expansion_init, &end, true);
        if (!error_operand_p (begin) && !error_operand_p (end))
  	{
! 	  tree i = get_target_expr (begin);
  	  tree w = build_stmt (loc, WHILE_STMT, NULL_TREE, NULL_TREE,
  			       NULL_TREE, NULL_TREE, NULL_TREE);
  	  tree r = get_target_expr (build_zero_cst (ptrdiff_type_node));
--- 32851,32860 ----
        begin = cp_build_range_for_decls (loc, expansion_init, &end, true);
        if (!error_operand_p (begin) && !error_operand_p (end))
  	{
! 	  tree i
! 	    = build_target_expr_with_type (begin,
! 					   cv_unqualified (TREE_TYPE (begin)),
! 					   tf_warning_or_error);
  	  tree w = build_stmt (loc, WHILE_STMT, NULL_TREE, NULL_TREE,
  			       NULL_TREE, NULL_TREE, NULL_TREE);
  	  tree r = get_target_expr (build_zero_cst (ptrdiff_type_node));
*************** finish_expansion_stmt (tree expansion_st
*** 32905,32911 ****
        destruct_decls.safe_grow (n, true);
        for (unsigned HOST_WIDE_INT i = 0; i < n; ++i)
  	{
! 	  tree this_decl = build_decl (loc, VAR_DECL, NULL_TREE, make_auto ());
  	  TREE_USED (this_decl) = 1;
  	  DECL_ARTIFICIAL (this_decl) = 1;
  	  DECL_DECLARED_CONSTEXPR_P (this_decl)
--- 32902,32911 ----
        destruct_decls.safe_grow (n, true);
        for (unsigned HOST_WIDE_INT i = 0; i < n; ++i)
  	{
! 	  tree this_type = make_auto ();
! 	  if (DECL_DECLARED_CONSTEXPR_P (decl))
! 	    this_type = cp_build_qualified_type (this_type, TYPE_QUAL_CONST);
! 	  tree this_decl = build_decl (loc, VAR_DECL, NULL_TREE, this_type);
  	  TREE_USED (this_decl) = 1;
  	  DECL_ARTIFICIAL (this_decl) = 1;
  	  DECL_DECLARED_CONSTEXPR_P (this_decl)
*************** finish_expansion_stmt (tree expansion_st
*** 32946,32951 ****
--- 32946,32953 ----
        tree type = TREE_TYPE (range_decl);
        if (args)
  	type = tsubst (type, args, complain | tf_tst_ok, in_decl);
+       if (DECL_DECLARED_CONSTEXPR_P (range_decl) && !TYPE_REF_P (type))
+ 	type = cp_build_qualified_type (type, TYPE_QUAL_CONST);
        tree decl = build_decl (loc, VAR_DECL, DECL_NAME (range_decl), type);
        DECL_ATTRIBUTES (decl) = DECL_ATTRIBUTES (range_decl);
        TREE_USED (decl) |= TREE_USED (range_decl);
*************** finish_expansion_stmt (tree expansion_st
*** 32975,32980 ****
--- 32977,32984 ----
  				 tf_warning_or_error);
  	  auto_node = make_auto ();
  	  iter_type = do_auto_deduction (auto_node, iter_init, auto_node);
+ 	  if (!TYPE_REF_P (iter_type))
+ 	    iter_type = cp_build_qualified_type (iter_type, TYPE_QUAL_CONST);
  	  iter = build_decl (loc, VAR_DECL, NULL_TREE, iter_type);
  	  TREE_USED (iter) = 1;
  	  DECL_ARTIFICIAL (iter) = 1;
*************** finish_expansion_stmt (tree expansion_st
*** 33000,33009 ****
  	  this_decomp.count = TREE_VEC_LENGTH (v) - 1;
  	  for (unsigned i = 0; i < this_decomp.count; ++i)
  	    {
  	      tree this_decl
  		= build_decl (loc, VAR_DECL,
  			      DECL_NAME (TREE_VEC_ELT (v, i + 1)),
! 			      make_auto ());
  	      TREE_USED (this_decl) = 1;
  	      DECL_ARTIFICIAL (this_decl) = 1;
  	      DECL_ATTRIBUTES (this_decl)
--- 33004,33017 ----
  	  this_decomp.count = TREE_VEC_LENGTH (v) - 1;
  	  for (unsigned i = 0; i < this_decomp.count; ++i)
  	    {
+ 	      tree this_type = make_auto ();
+ 	      if (DECL_DECLARED_CONSTEXPR_P (decl))
+ 		this_type = cp_build_qualified_type (this_type,
+ 						     TYPE_QUAL_CONST);
  	      tree this_decl
  		= build_decl (loc, VAR_DECL,
  			      DECL_NAME (TREE_VEC_ELT (v, i + 1)),
! 			      this_type);
  	      TREE_USED (this_decl) = 1;
  	      DECL_ARTIFICIAL (this_decl) = 1;
  	      DECL_ATTRIBUTES (this_decl)
diff -Nrcpad gcc-16-20251214/gcc/cp/rtti.cc gcc-16-20251221/gcc/cp/rtti.cc
*** gcc-16-20251214/gcc/cp/rtti.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/cp/rtti.cc	Sun Dec 21 22:32:06 2025
*************** build_headof (tree exp)
*** 166,172 ****
    gcc_assert (TYPE_PTR_P (type));
    type = TREE_TYPE (type);
  
!   if (!TYPE_POLYMORPHIC_P (type))
      return exp;
  
    /* We use this a couple of times below, protect it.  */
--- 166,172 ----
    gcc_assert (TYPE_PTR_P (type));
    type = TREE_TYPE (type);
  
!   if (!CLASS_TYPE_P (type) || !TYPE_POLYMORPHIC_P (type))
      return exp;
  
    /* We use this a couple of times below, protect it.  */
*************** get_tinfo_ptr_dynamic (tree exp, tsubst_
*** 280,286 ****
      return error_mark_node;
  
    /* If exp is a reference to polymorphic type, get the real type_info.  */
!   if (TYPE_POLYMORPHIC_P (type) && ! resolves_to_fixed_type_p (exp, 0))
      {
        /* build reference to type_info from vtable.  */
        tree index;
--- 280,288 ----
      return error_mark_node;
  
    /* If exp is a reference to polymorphic type, get the real type_info.  */
!   if (CLASS_TYPE_P (type)
!       && TYPE_POLYMORPHIC_P (type)
!       && ! resolves_to_fixed_type_p (exp, 0))
      {
        /* build reference to type_info from vtable.  */
        tree index;
*************** build_typeid (tree exp, tsubst_flags_t c
*** 353,359 ****
    if (processing_template_decl)
      return build_min (TYPEID_EXPR, const_type_info_type_node, exp);
  
!   if (TYPE_POLYMORPHIC_P (TREE_TYPE (exp))
        && ! resolves_to_fixed_type_p (exp, &nonnull)
        && ! nonnull)
      {
--- 355,362 ----
    if (processing_template_decl)
      return build_min (TYPEID_EXPR, const_type_info_type_node, exp);
  
!   if (CLASS_TYPE_P (TREE_TYPE (exp))
!       && TYPE_POLYMORPHIC_P (TREE_TYPE (exp))
        && ! resolves_to_fixed_type_p (exp, &nonnull)
        && ! nonnull)
      {
diff -Nrcpad gcc-16-20251214/gcc/cp/semantics.cc gcc-16-20251221/gcc/cp/semantics.cc
*** gcc-16-20251214/gcc/cp/semantics.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/cp/semantics.cc	Sun Dec 21 22:32:06 2025
*************** finish_static_assert (tree condition, tr
*** 12927,12932 ****
--- 12927,12942 ----
  	    error_at (cloc, "static assertion failed: %.*s", len, msg);
  
  	  diagnose_failing_condition (bad, cloc, show_expr_p);
+ 
+ 	  /* Suppress -Wreturn-type for functions with failed static_asserts.
+ 	     Otherwise templates like:
+ 	     if constexpr (whatever)
+ 	       return something (args);
+ 	     else
+ 	       static_assert (false, "explanation");
+ 	     get a useless extra -Wreturn-type warning.  */
+ 	  if (current_function_decl)
+ 	    suppress_warning (current_function_decl, OPT_Wreturn_type);
  	}
        else if (condition && condition != error_mark_node)
  	{
diff -Nrcpad gcc-16-20251214/gcc/cp/tree.cc gcc-16-20251221/gcc/cp/tree.cc
*** gcc-16-20251214/gcc/cp/tree.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/cp/tree.cc	Sun Dec 21 22:32:06 2025
*************** non_mergeable_glvalue_p (const_tree ref)
*** 424,429 ****
--- 424,506 ----
  	  && !(kind & (clk_class|clk_mergeable)));
  }
  
+ /* C++-specific version of stabilize_reference for bit-fields and
+    DECL_PACKED fields.  We can't bind a reference to those.  */
+ 
+ static tree
+ cp_stabilize_bitfield_reference (tree ref)
+ {
+   tree op1, op2, op3;
+   STRIP_ANY_LOCATION_WRAPPER (ref);
+   switch (TREE_CODE (ref))
+     {
+     case VAR_DECL:
+     case PARM_DECL:
+     case RESULT_DECL:
+     CASE_CONVERT:
+     case FLOAT_EXPR:
+     case FIX_TRUNC_EXPR:
+     case INDIRECT_REF:
+     case COMPONENT_REF:
+     case BIT_FIELD_REF:
+     case ARRAY_REF:
+     case ARRAY_RANGE_REF:
+     case ERROR_MARK:
+     case REALPART_EXPR:
+     case IMAGPART_EXPR:
+     default:
+       break;
+     case COMPOUND_EXPR:
+       op2 = cp_stabilize_bitfield_reference (TREE_OPERAND (ref, 1));
+       if (op2 == TREE_OPERAND (ref, 1))
+ 	return ref;
+       op1 = TREE_OPERAND (ref, 0);
+       if (TREE_SIDE_EFFECTS (op1))
+ 	{
+ 	  if (VOID_TYPE_P (TREE_TYPE (op1)))
+ 	    op1 = save_expr (op1);
+ 	  else
+ 	    {
+ 	      op1 = build2 (COMPOUND_EXPR, void_type_node, op1,
+ 			    void_node);
+ 	      op1 = save_expr (op1);
+ 	    }
+ 	}
+       return build2 (COMPOUND_EXPR, TREE_TYPE (op2), op1, op2);
+     case COND_EXPR:
+       op1 = TREE_OPERAND (ref, 0);
+       op2 = TREE_OPERAND (ref, 1);
+       op3 = TREE_OPERAND (ref, 2);
+       if (op2 && TREE_CODE (op2) != THROW_EXPR)
+ 	op2 = cp_stabilize_bitfield_reference (op2);
+       if (TREE_CODE (op3) != THROW_EXPR)
+ 	op3 = cp_stabilize_bitfield_reference (op3);
+       if (op2 == NULL_TREE)
+ 	op1 = cp_stabilize_bitfield_reference (op1);
+       if (op1 == TREE_OPERAND (ref, 0)
+ 	  && op2 == TREE_OPERAND (ref, 1)
+ 	  && op3 == TREE_OPERAND (ref, 2))
+ 	return ref;
+       if (op2 != NULL_TREE && TREE_SIDE_EFFECTS (op1))
+ 	op1 = save_expr (op1);
+       return build3 (COND_EXPR, TREE_TYPE (ref), op1, op2, op3);
+     case PREINCREMENT_EXPR:
+     case PREDECREMENT_EXPR:
+       op1 = cp_stabilize_bitfield_reference (TREE_OPERAND (ref, 0));
+       if (op1 == TREE_OPERAND (ref, 0))
+ 	return ref;
+       return build2 (COMPOUND_EXPR, TREE_TYPE (ref),
+ 		     build2 (TREE_CODE (ref), TREE_TYPE (ref), op1,
+ 			     TREE_OPERAND (ref, 0)), op1);
+     case PAREN_EXPR:
+       op1 = cp_stabilize_bitfield_reference (TREE_OPERAND (ref, 0));
+       if (op1 == TREE_OPERAND (ref, 0))
+ 	return ref;
+       return build1 (PAREN_EXPR, TREE_TYPE (ref), op1);
+     }
+   return stabilize_reference (ref);
+ }
+ 
  /* C++-specific version of stabilize_reference.  */
  
  tree
*************** cp_stabilize_reference (tree ref)
*** 455,460 ****
--- 532,539 ----
        cp_lvalue_kind kind = lvalue_kind (ref);
        if ((kind & ~clk_class) != clk_none)
  	{
+ 	  if (kind & (clk_bitfield | clk_packed))
+ 	    return cp_stabilize_bitfield_reference (ref);
  	  tree type = unlowered_expr_type (ref);
  	  bool rval = !!(kind & clk_rvalueref);
  	  type = cp_build_reference_type (type, rval);
*************** implicit_lifetime_type_p (tree t)
*** 4829,4846 ****
        && (!CLASSTYPE_DESTRUCTOR (t)
  	  || !user_provided_p (CLASSTYPE_DESTRUCTOR (t))))
      return true;
!   if (is_trivially_xible (BIT_NOT_EXPR, t, NULL_TREE))
      {
!       if (is_trivially_xible (INIT_EXPR, t, make_tree_vec (0)))
! 	return true;
!       tree arg = make_tree_vec (1);
!       tree ct
! 	= cp_build_qualified_type (t, (cp_type_quals (t) | TYPE_QUAL_CONST));
!       TREE_VEC_ELT (arg, 0) = cp_build_reference_type (ct, /*rval=*/false);
!       if (is_trivially_xible (INIT_EXPR, t, arg))
! 	return true;
!       TREE_VEC_ELT (arg, 0) = t;
!       if (is_trivially_xible (INIT_EXPR, t, arg))
  	return true;
      }
    return false;
--- 4908,4931 ----
        && (!CLASSTYPE_DESTRUCTOR (t)
  	  || !user_provided_p (CLASSTYPE_DESTRUCTOR (t))))
      return true;
!   if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t))
!     return false;
!   if (TYPE_HAS_COMPLEX_DFLT (t)
!       && TYPE_HAS_COMPLEX_COPY_CTOR (t)
!       && TYPE_HAS_COMPLEX_MOVE_CTOR (t))
!     return false;
!   if (CLASSTYPE_LAZY_DESTRUCTOR (t))
!     lazily_declare_fn (sfk_destructor, t);
!   tree fn = CLASSTYPE_DESTRUCTOR (t);
!   if (!fn || DECL_DELETED_FN (fn))
!     return false;
!   for (ovl_iterator iter (get_class_binding (t, complete_ctor_identifier));
!        iter; ++iter)
      {
!       fn = *iter;
!       if ((default_ctor_p (fn) || copy_fn_p (fn) || move_fn_p (fn))
! 	  && trivial_fn_p (fn)
! 	  && !DECL_DELETED_FN (fn))
  	return true;
      }
    return false;
diff -Nrcpad gcc-16-20251214/gcc/cp/typeck.cc gcc-16-20251221/gcc/cp/typeck.cc
*** gcc-16-20251214/gcc/cp/typeck.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/cp/typeck.cc	Sun Dec 21 22:32:06 2025
*************** cp_compare_floating_point_conversion_ran
*** 305,311 ****
  
    const struct real_format *fmt1 = REAL_MODE_FORMAT (TYPE_MODE (t1));
    const struct real_format *fmt2 = REAL_MODE_FORMAT (TYPE_MODE (t2));
!   gcc_assert (fmt1->b == 2 && fmt2->b == 2);
    /* For {ibm,mips}_extended_format formats, the type has variable
       precision up to ~2150 bits when the first double is around maximum
       representable double and second double is subnormal minimum.
--- 305,334 ----
  
    const struct real_format *fmt1 = REAL_MODE_FORMAT (TYPE_MODE (t1));
    const struct real_format *fmt2 = REAL_MODE_FORMAT (TYPE_MODE (t2));
!   /* Currently, extended floating point types are only binary, and
!      they never have a proper subset or superset of values with
!      decimal floating point types except for the _Float16 vs. _Decimal128
!      pair, so return 3 for unordered conversion ranks.  */
!   gcc_assert (fmt1->b == 2);
!   if (fmt2->b == 10)
!     {
!       /* _Float16 needs at most 21 decimal digits (e.g.
! 	 0x1.a3cp-14f16 is exactly 0.000100076198577880859375DL),
! 	 so it is not a proper subset of _Decimal64 but is subset
! 	 of _Decimal128.  While std::bfloat16_t needs at most 96
! 	 decimal digits, so even _Decimal128 doesn't cover it.
! 	 _Float32 has at least one value which needs 112 decimal
! 	 digits, _Float64 at least 767 decimal digits.  */
!       if (fmt1->emin == -13
! 	  && fmt1->emax == 16
! 	  && fmt1->p == 11
! 	  && fmt2->emin == -6142
! 	  && fmt2->emax == 6145
! 	  && fmt2->p == 34)
! 	return -2;
!       return 3;
!     }
!   gcc_assert (fmt2->b == 2);
    /* For {ibm,mips}_extended_format formats, the type has variable
       precision up to ~2150 bits when the first double is around maximum
       representable double and second double is subnormal minimum.
diff -Nrcpad gcc-16-20251214/gcc/cp/typeck2.cc gcc-16-20251221/gcc/cp/typeck2.cc
*** gcc-16-20251214/gcc/cp/typeck2.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/cp/typeck2.cc	Sun Dec 21 22:32:06 2025
*************** build_functional_cast_1 (location_t loc,
*** 2630,2636 ****
        t = build_min (CAST_EXPR, type, parms);
        /* We don't know if it will or will not have side effects.  */
        TREE_SIDE_EFFECTS (t) = 1;
!       return t;
      }
  
    if (! MAYBE_CLASS_TYPE_P (type))
--- 2630,2636 ----
        t = build_min (CAST_EXPR, type, parms);
        /* We don't know if it will or will not have side effects.  */
        TREE_SIDE_EFFECTS (t) = 1;
!       return convert_from_reference (t);
      }
  
    if (! MAYBE_CLASS_TYPE_P (type))
diff -Nrcpad gcc-16-20251214/gcc/cselib.cc gcc-16-20251221/gcc/cselib.cc
*** gcc-16-20251214/gcc/cselib.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/cselib.cc	Sun Dec 21 22:32:06 2025
*************** cselib_redundant_set_p (rtx set)
*** 1194,1200 ****
    if (cselib_reg_set_mode (dest) != GET_MODE (dest))
      return false;
  
!   if (!rtx_equal_for_cselib_p (dest, SET_SRC (set)))
      return false;
  
    while (GET_CODE (dest) == SUBREG
--- 1194,1202 ----
    if (cselib_reg_set_mode (dest) != GET_MODE (dest))
      return false;
  
!   rtx src = SET_SRC (set);
!   if ((MEM_P (src) && MEM_VOLATILE_P (src))
!        || !rtx_equal_for_cselib_p (dest, src))
      return false;
  
    while (GET_CODE (dest) == SUBREG
*************** cselib_redundant_set_p (rtx set)
*** 1205,1210 ****
--- 1207,1215 ----
    if (!flag_strict_aliasing || !MEM_P (dest))
      return true;
  
+   if (MEM_VOLATILE_P (dest))
+     return false;
+ 
    /* For a store we need to check that suppressing it will not change
       the effective alias set.  */
    rtx dest_addr = XEXP (dest, 0);
*************** cselib_redundant_set_p (rtx set)
*** 1242,1248 ****
    /* We failed to find a recorded value in the cselib history, so try
       the source of this set; this catches cases such as *p = *q when p
       and q have the same value.  */
-   rtx src = SET_SRC (set);
    while (GET_CODE (src) == SUBREG)
      src = XEXP (src, 0);
  
--- 1247,1252 ----
diff -Nrcpad gcc-16-20251214/gcc/doc/extend.texi gcc-16-20251221/gcc/doc/extend.texi
*** gcc-16-20251214/gcc/doc/extend.texi	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/doc/extend.texi	Sun Dec 21 22:32:06 2025
*************** last argument is not a pointer, but some
*** 16318,16324 ****
  than enumerated or boolean type.
  
  The built-in functions promote the first two operands into infinite precision signed type
! and perform addition on those promoted operands. The result is then
  cast to the type of the third argument.  If the cast result is equal to the infinite
  precision result, the built-in functions return @code{false}, otherwise they return @code{true}.
  The value of the third argument is ignored, just the side effects in the third argument
--- 16318,16324 ----
  than enumerated or boolean type.
  
  The built-in functions promote the first two operands into infinite precision signed type
! and perform the corresponding operation on those promoted operands. The result is then
  cast to the type of the third argument.  If the cast result is equal to the infinite
  precision result, the built-in functions return @code{false}, otherwise they return @code{true}.
  The value of the third argument is ignored, just the side effects in the third argument
*************** AMD Family 19h Zen version 3.
*** 29088,29095 ****
--- 29088,29101 ----
  @item znver4
  AMD Family 19h Zen version 4.
  
+ @item amdfam1ah
+ AMD Family 1ah CPU.
+ 
  @item znver5
  AMD Family 1ah Zen version 5.
+ 
+ @item znver6
+ AMD Family 1ah Zen version 6.
  @end table
  
  Here is an example:
diff -Nrcpad gcc-16-20251214/gcc/doc/install.texi gcc-16-20251221/gcc/doc/install.texi
*** gcc-16-20251214/gcc/doc/install.texi	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/doc/install.texi	Sun Dec 21 22:32:06 2025
*************** but for the linker.
*** 1244,1251 ****
  Same as @uref{#with-as,,@option{--with-as}}
  but for the debug linker (only used on Darwin platforms so far).
  
  @item --with-tls=@var{dialect}
! Specify the default TLS dialect, for systems were there is a choice.
  For ARM targets, possible values for @var{dialect} are @code{gnu} or
  @code{gnu2}, which select between the original GNU dialect and the GNU TLS
  descriptor-based dialect.
--- 1244,1255 ----
  Same as @uref{#with-as,,@option{--with-as}}
  but for the debug linker (only used on Darwin platforms so far).
  
+ @item --with-windres=@var{pathname}
+ Same as @uref{#with-as,,@option{--with-as}}
+ but for the Windows resource compiler.
+ 
  @item --with-tls=@var{dialect}
! Specify the default TLS dialect, for systems where there is a choice.
  For ARM targets, possible values for @var{dialect} are @code{gnu} or
  @code{gnu2}, which select between the original GNU dialect and the GNU TLS
  descriptor-based dialect.
*************** this option is still experimental and no
*** 2095,2101 ****
  
  Default is the traditional behavior @option{--with-aix-soname=@samp{aix}}.
  
! @item --enable-languages=@var{lang1},@var{lang2},@dots{}
  Specify that only a particular subset of compilers and
  their runtime libraries should be built.  For a list of valid values for
  @var{langN} you can issue the following command in the
--- 2099,2105 ----
  
  Default is the traditional behavior @option{--with-aix-soname=@samp{aix}}.
  
! @item --enable-languages=[^]@var{lang1},[^]@var{lang2},@dots{}
  Specify that only a particular subset of compilers and
  their runtime libraries should be built.  For a list of valid values for
  @var{langN} you can issue the following command in the
*************** LTO is not a
*** 2115,2123 ****
  default language, but is built by default because @option{--enable-lto} is
  enabled by default.  The other languages are default languages.  If
  @code{all} is specified, then all available languages are built.  An
! exception is @code{jit} language, which requires
  @option{--enable-host-shared} to be included with @code{all}.
  
  @item --enable-stage1-languages=@var{lang1},@var{lang2},@dots{}
  Specify that a particular subset of compilers and their runtime
  libraries should be built with the system C compiler during stage 1 of
--- 2119,2137 ----
  default language, but is built by default because @option{--enable-lto} is
  enabled by default.  The other languages are default languages.  If
  @code{all} is specified, then all available languages are built.  An
! exception is the @code{jit} language, which requires
  @option{--enable-host-shared} to be included with @code{all}.
  
+ If a language name is prefixed with a caret, such as
+ @samp{--enable-languages=all,^obj-c++}, then that language will
+ not be built.  This is most useful when combined with @code{all} or
+ @code{default}.  A language disabled in this way will be disabled even
+ if it is also included without the leading caret earlier or later in
+ the argument to @option{--enable-languages}.  An attempt to disable a
+ language that is a prerequisite for an enabled languaged---(whether
+ the latter language was enabled explicitly, or implicitly via the
+ @code{default} or @code{all} directives)---is invalid.
+ 
  @item --enable-stage1-languages=@var{lang1},@var{lang2},@dots{}
  Specify that a particular subset of compilers and their runtime
  libraries should be built with the system C compiler during stage 1 of
diff -Nrcpad gcc-16-20251214/gcc/doc/invoke.texi gcc-16-20251221/gcc/doc/invoke.texi
*** gcc-16-20251214/gcc/doc/invoke.texi	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/doc/invoke.texi	Sun Dec 21 22:32:06 2025
*************** Objective-C and Objective-C++ Dialects}.
*** 677,683 ****
  -fsemantic-interposition  -fshrink-wrap  -fshrink-wrap-separate
  -fsignaling-nans
  -fsingle-precision-constant  -fsplit-ivs-in-unroller  -fsplit-loops
! -fsplit-paths
  -fsplit-wide-types  -fsplit-wide-types-early  -fssa-backprop  -fssa-phiopt
  -fstdarg-opt  -fstore-merging  -fstrict-aliasing -fipa-strict-aliasing
  -fthread-jumps  -ftracer  -ftree-bit-ccp
--- 677,683 ----
  -fsemantic-interposition  -fshrink-wrap  -fshrink-wrap-separate
  -fsignaling-nans
  -fsingle-precision-constant  -fsplit-ivs-in-unroller  -fsplit-loops
! -fspeculatively-call-stored-functions  -fsplit-paths
  -fsplit-wide-types  -fsplit-wide-types-early  -fssa-backprop  -fssa-phiopt
  -fstdarg-opt  -fstore-merging  -fstrict-aliasing -fipa-strict-aliasing
  -fthread-jumps  -ftracer  -ftree-bit-ccp
*************** See RS/6000 and PowerPC Options.
*** 1540,1546 ****
  -mavx512fp16 -mavxifma -mavxvnniint8 -mavxneconvert -mcmpccxadd -mamx-fp16
  -mprefetchi -mraoint -mamx-complex -mavxvnniint16 -msm3 -msha512 -msm4 -mapxf
  -musermsr -mavx10.1 -mavx10.2 -mamx-avx512 -mamx-tf32 -mmovrs -mamx-movrs
! -mcldemote  -mms-bitfields  -mno-align-stringops  -minline-all-stringops
  -minline-stringops-dynamically  -mstringop-strategy=@var{alg}
  -mkl -mwidekl
  -mmemcpy-strategy=@var{strategy}  -mmemset-strategy=@var{strategy}
--- 1540,1546 ----
  -mavx512fp16 -mavxifma -mavxvnniint8 -mavxneconvert -mcmpccxadd -mamx-fp16
  -mprefetchi -mraoint -mamx-complex -mavxvnniint16 -msm3 -msha512 -msm4 -mapxf
  -musermsr -mavx10.1 -mavx10.2 -mamx-avx512 -mamx-tf32 -mmovrs -mamx-movrs
! -mavx512bmm -mcldemote -mms-bitfields -mno-align-stringops -minline-all-stringops
  -minline-stringops-dynamically  -mstringop-strategy=@var{alg}
  -mkl -mwidekl
  -mmemcpy-strategy=@var{strategy}  -mmemset-strategy=@var{strategy}
*************** also turns on the following optimization
*** 13336,13341 ****
--- 13336,13342 ----
  -frerun-cse-after-loop
  -fschedule-insns  -fschedule-insns2
  -fsched-interblock  -fsched-spec
+ -fspeculatively-call-stored-functions
  -fstore-merging
  -fstrict-aliasing
  -fthread-jumps
*************** This is enabled by default when scheduli
*** 14275,14280 ****
--- 14276,14291 ----
  with @option{-fschedule-insns} or @option{-fschedule-insns2} or
  at @option{-O2} or higher.
  
+ @opindex fspeculatively-call-stored-functions
+ @item -fspeculatively-call-stored-functions
+ Attempt to convert indirect calls of function pointers to pointers
+ loaded from a structure field if all visible stores to that field store
+ just a single candidate.  When doing so, turn the call into a
+ conditional deciding between the direct call and the original indirect
+ one.  These speculative calls often enable more optimizations, such as
+ inlining.  When they seem useless after further optimization, they are
+ converted back into original form.
+ 
  @opindex freschedule-modulo-scheduled-loops
  @item -freschedule-modulo-scheduled-loops
  Modulo scheduling is performed before traditional scheduling.  If a loop
*************** When using stack instrumentation, decide
*** 17687,17693 ****
  deterministic sequence beginning at a random tag for each frame.  With this
  parameter unset tags are chosen using the same sequence but beginning from 1.
  This is enabled by default for @option{-fsanitize=hwaddress} and unavailable
! for @option{-fsanitize=kernel-hwaddress}.
  To disable it use @option{--param hwasan-random-frame-tag=0}.
  
  @item hwasan-instrument-allocas
--- 17698,17704 ----
  deterministic sequence beginning at a random tag for each frame.  With this
  parameter unset tags are chosen using the same sequence but beginning from 1.
  This is enabled by default for @option{-fsanitize=hwaddress} and unavailable
! for @option{-fsanitize=kernel-hwaddress} and @option{-fsanitize=memtag-stack}.
  To disable it use @option{--param hwasan-random-frame-tag=0}.
  
  @item hwasan-instrument-allocas
*************** and @option{-fsanitize=kernel-hwaddress}
*** 17720,17725 ****
--- 17731,17741 ----
  To disable instrumentation of builtin functions use
  @option{--param hwasan-instrument-mem-intrinsics=0}.
  
+ @item memtag-instrument-allocas
+ Enable hardware-assisted memory tagging of dynamically sized stack-allocated
+ variables.  This kind of code generation is enabled by default when using
+ @option{-fsanitize=memtag-stack}.
+ 
  @item use-after-scope-direct-emission-threshold
  If the size of a local variable in bytes is smaller or equal to this
  number, directly poison (or unpoison) shadow memory instead of using
*************** would be beneficial to unroll the main v
*** 18132,18137 ****
--- 18148,18158 ----
  parameter set's the upper bound of how much the vectorizer will unroll the main
  loop.  The default value is four.
  
+ @item aarch64-tag-memory-loop-threshold
+ Param to control the treshold in number of granules beyond which an
+ explicit loop for tagging a memory block is emitted.  The memory block
+ is tagged using MTE instructions.
+ 
  @end table
  
  The following choices of @var{name} are available on GCN targets:
*************** for a list of supported options.
*** 18619,18626 ****
  The option cannot be combined with @option{-fsanitize=thread} or
  @option{-fsanitize=hwaddress}.  Note that the only targets
  @option{-fsanitize=hwaddress} is currently supported on are x86-64
! (only with @code{-mlam=u48} or @code{-mlam=u57} options) and AArch64,
! in both cases only in ABIs with 64-bit pointers.
  
  When compiling with @option{-fsanitize=address}, you should also
  use @option{-g} to produce more meaningful output.
--- 18640,18649 ----
  The option cannot be combined with @option{-fsanitize=thread} or
  @option{-fsanitize=hwaddress}.  Note that the only targets
  @option{-fsanitize=hwaddress} is currently supported on are x86-64
! (only with @code{-mlam=u48} or @code{-mlam=u57} options) and AArch64, in both
! cases only in ABIs with 64-bit pointers.  Similarly,
! @option{-fsanitize=memtag-stack} is currently only supported on AArch64 ABIs
! with 64-bit pointers.
  
  When compiling with @option{-fsanitize=address}, you should also
  use @option{-g} to produce more meaningful output.
*************** possible by specifying the command-line
*** 18673,18678 ****
--- 18696,18708 ----
  @option{--param hwasan-instrument-allocas=1} respectively. Using a random frame
  tag is not implemented for kernel instrumentation.
  
+ @opindex fsanitize=memtag-stack
+ @item -fsanitize=memtag-stack
+ Use Memory Tagging Extension instructions instead of instrumentation
+ to allow the detection of memory errors.  Similar to HWASAN, it is
+ also a probabilistic method.  This option is available only on those
+ AArch64 architectures that support Memory Tagging Extensions.
+ 
  @opindex fsanitize=pointer-compare
  @item -fsanitize=pointer-compare
  Instrument comparison operation (<, <=, >, >=) with pointer operands.
*************** AVX512BW, AVX512VL, AVX512BF16, AVX512VB
*** 35814,35819 ****
--- 35844,35860 ----
  AVX512BITALG, AVX512VPOPCNTDQ, GFNI, AVXVNNI, MOVDIRI, MOVDIR64B,
  AVX512VP2INTERSECT, PREFETCHI and 64-bit instruction set extensions.)
  
+ @item znver6
+ AMD Family 1ah core based CPUs with x86-64 instruction set support. (This
+ supersets BMI, BMI2, CLWB, F16C, FMA, FSGSBASE, AVX, AVX2, ADCX, RDSEED,
+ MWAITX, SHA, CLZERO, AES, PCLMUL, CX16, MOVBE, MMX, SSE, SSE2, SSE3, SSE4A,
+ SSSE3, SSE4.1, SSE4.2, ABM, XSAVEC, XSAVES, CLFLUSHOPT, POPCNT, RDPID,
+ WBNOINVD, PKU, VPCLMULQDQ, VAES, AVX512F, AVX512DQ, AVX512IFMA, AVX512CD,
+ AVX512BW, AVX512VL, AVX512BF16, AVX512VBMI, AVX512VBMI2, AVX512VNNI,
+ AVX512BITALG, AVX512VPOPCNTDQ, GFNI, AVXVNNI, MOVDIRI, MOVDIR64B,
+ AVX512VP2INTERSECT, PREFETCHI, AVXVNNIINT8, AVXIFMA, AVX512FP16, AVXNECONVERT,
+ AVX512BMM and 64-bit instruction set extensions.)
+ 
  @item btver1
  CPUs based on AMD Family 14h cores with x86-64 instruction set support.  (This
  supersets MMX, SSE, SSE2, SSE3, SSSE3, SSE4A, CX16, ABM and 64-bit
*************** preferred alignment to @option{-mpreferr
*** 36618,36623 ****
--- 36659,36667 ----
  @need 200
  @opindex mamx-movrs
  @itemx -mamx-movrs
+ @need 200
+ @opindex mavx512bmm
+ @itemx -mavx512bmm
  These switches enable the use of instructions in the MMX, SSE,
  AVX512CD, AVX512VL, AVX512BW, AVX512DQ, AVX512IFMA, AVX512VBMI, SHA, AES,
  PCLMUL, CLFLUSHOPT, CLWB, FSGSBASE, PTWRITE, RDRND, F16C, FMA, PCONFIG,
*************** AVX512VPOPCNTDQ, AVX512VNNI, SERIALIZE,
*** 36629,36636 ****
  AMXBF16, KL, WIDEKL, AVXVNNI, AVX512-FP16, AVXIFMA, AVXVNNIINT8, AVXNECONVERT,
  CMPCCXADD, AMX-FP16, PREFETCHI, RAOINT, AMX-COMPLEX, AVXVNNIINT16, SM3, SHA512,
  SM4, APX_F, USER_MSR, AVX10.1, AVX10.2, AMX-AVX512, AMX-TF32, AMX-FP8, MOVRS,
! AMX-MOVRS or CLDEMOTE extended instruction sets. Each has a corresponding
! @option{-mno-} option to disable use of these instructions.
  
  These extensions are also available as built-in functions: see
  @ref{x86 Built-in Functions}, for details of the functions enabled and
--- 36673,36680 ----
  AMXBF16, KL, WIDEKL, AVXVNNI, AVX512-FP16, AVXIFMA, AVXVNNIINT8, AVXNECONVERT,
  CMPCCXADD, AMX-FP16, PREFETCHI, RAOINT, AMX-COMPLEX, AVXVNNIINT16, SM3, SHA512,
  SM4, APX_F, USER_MSR, AVX10.1, AVX10.2, AMX-AVX512, AMX-TF32, AMX-FP8, MOVRS,
! AMX-MOVRS, AVX512BMM or CLDEMOTE extended instruction sets. Each has a
! corresponding @option{-mno-} option to disable use of these instructions.
  
  These extensions are also available as built-in functions: see
  @ref{x86 Built-in Functions}, for details of the functions enabled and
diff -Nrcpad gcc-16-20251214/gcc/doc/md.texi gcc-16-20251221/gcc/doc/md.texi
*** gcc-16-20251214/gcc/doc/md.texi	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/doc/md.texi	Sun Dec 21 22:32:06 2025
*************** This pattern is not allowed to @code{FAI
*** 5411,5417 ****
  Load (operand 3 + operand 4) elements from memory operand 1
  into vector register operand 0.  Operands 0 and 1 have mode @var{m},
  which must be a vector mode.  Operand 3 has whichever integer mode the
! target prefers.  Operand 2 (the “else value”) is of mode @var{m} and
  specifies which value is loaded for the remaining elements.  The predicate
  of operand 2 must only accept the else values that the target actually
  supports.  Operand 4 conceptually has mode @code{QI}.
--- 5411,5417 ----
  Load (operand 3 + operand 4) elements from memory operand 1
  into vector register operand 0.  Operands 0 and 1 have mode @var{m},
  which must be a vector mode.  Operand 3 has whichever integer mode the
! target prefers.  Operand 2 (the ``else value'') is of mode @var{m} and
  specifies which value is loaded for the remaining elements.  The predicate
  of operand 2 must only accept the else values that the target actually
  supports.  Operand 4 conceptually has mode @code{QI}.
*************** the values were equal.
*** 8679,8684 ****
--- 8679,8694 ----
  If this pattern is not defined, then a plain compare pattern and
  conditional branch pattern is used.
  
+ @cindex @code{tag_memory} instruction pattern
+ This pattern tags an object that begins at the address specified by
+ operand 0, has the byte size indicated by the operand 2, and uses the
+ tag from operand 1.
+ 
+ @cindex @code{compose_tag} instruction pattern
+ This pattern composes a tagged address specified by operand 1 with
+ mode @code{ptr_mode}, with an integer operand 2 representing the tag
+ offset.  It returns the result in operand 0 with mode @code{ptr_mode}.
+ 
  @cindex @code{clear_cache} instruction pattern
  @item @samp{clear_cache}
  This pattern, if defined, flushes the instruction cache for a region of
diff -Nrcpad gcc-16-20251214/gcc/doc/tm.texi gcc-16-20251221/gcc/doc/tm.texi
*** gcc-16-20251214/gcc/doc/tm.texi	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/doc/tm.texi	Sun Dec 21 22:32:06 2025
*************** Return an RTX representing the value of
*** 13001,13006 ****
--- 13001,13008 ----
  (possibly) random tag in it.
  Put that value into @var{target} if it is convenient to do so.
  This function is used to generate a tagged base for the current stack frame.
+ It is also used by memtag-stack sanitizer to emit specific memory tagging
+ instructions.
  @end deftypefn
  
  @deftypefn {Target Hook} rtx TARGET_MEMTAG_ADD_TAG (rtx @var{base}, poly_int64 @var{addr_offset}, uint8_t @var{tag_offset})
*************** The resulting RTX must either be a valid
*** 13011,13017 ****
  put into an operand with @code{force_operand}.
  
  Unlike other memtag hooks, this must return an expression and not emit any
! RTL.
  @end deftypefn
  
  @deftypefn {Target Hook} rtx TARGET_MEMTAG_SET_TAG (rtx @var{untagged_base}, rtx @var{tag}, rtx @var{target})
--- 13013,13019 ----
  put into an operand with @code{force_operand}.
  
  Unlike other memtag hooks, this must return an expression and not emit any
! RTL.  In the case of memtag-stack sanitizer, this constraint is not enforced.
  @end deftypefn
  
  @deftypefn {Target Hook} rtx TARGET_MEMTAG_SET_TAG (rtx @var{untagged_base}, rtx @var{tag}, rtx @var{target})
*************** The default of this hook is to set the t
*** 13026,13031 ****
--- 13028,13035 ----
  Return an RTX representing the tag stored in @var{tagged_pointer}.
  Store the result in @var{target} if it is convenient.
  The default represents the top byte of the original pointer.
+ In the case of memtag-stack sanitizer for targets that can process
+ tagged pointers (i.e. AArch64), this hook can return a tagged pointer.
  @end deftypefn
  
  @deftypefn {Target Hook} rtx TARGET_MEMTAG_UNTAGGED_POINTER (rtx @var{tagged_pointer}, rtx @var{target})
diff -Nrcpad gcc-16-20251214/gcc/dwarf2out.cc gcc-16-20251221/gcc/dwarf2out.cc
*** gcc-16-20251214/gcc/dwarf2out.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/dwarf2out.cc	Sun Dec 21 22:32:06 2025
*************** static GTY(()) vec<dw_die_ref, va_gc> *a
*** 3618,3624 ****
  
  /* A hash map to remember the stack usage for DWARF procedures.  The value
     stored is the stack size difference between before the DWARF procedure
!    invokation and after it returned.  In other words, for a DWARF procedure
     that consumes N stack slots and that pushes M ones, this stores M - N.  */
  static hash_map<dw_die_ref, int> *dwarf_proc_stack_usage_map;
  
--- 3618,3624 ----
  
  /* A hash map to remember the stack usage for DWARF procedures.  The value
     stored is the stack size difference between before the DWARF procedure
!    invocation and after it returned.  In other words, for a DWARF procedure
     that consumes N stack slots and that pushes M ones, this stores M - N.  */
  static hash_map<dw_die_ref, int> *dwarf_proc_stack_usage_map;
  
*************** equate_block_to_die (tree block, dw_die_
*** 6034,6040 ****
  
  
  /* For DECL which might have early dwarf output query a SYMBOL + OFFSET
!    style reference.  Return true if we found one refering to a DIE for
     DECL, otherwise return false.  */
  
  static bool
--- 6034,6040 ----
  
  
  /* For DECL which might have early dwarf output query a SYMBOL + OFFSET
!    style reference.  Return true if we found one referring to a DIE for
     DECL, otherwise return false.  */
  
  static bool
*************** loc_list_from_tree_1 (tree loc, int want
*** 19156,19162 ****
      case PREDECREMENT_EXPR:
      case POSTINCREMENT_EXPR:
      case POSTDECREMENT_EXPR:
!       expansion_failed (loc, NULL_RTX, "PRE/POST INDCREMENT/DECREMENT");
        /* There are no opcodes for these operations.  */
        return 0;
  
--- 19156,19162 ----
      case PREDECREMENT_EXPR:
      case POSTINCREMENT_EXPR:
      case POSTDECREMENT_EXPR:
!       expansion_failed (loc, NULL_RTX, "PRE/POST INCREMENT/DECREMENT");
        /* There are no opcodes for these operations.  */
        return 0;
  
*************** field_byte_offset (const_tree decl, stru
*** 20325,20331 ****
      tree_result = fold_build2 (PLUS_EXPR, TREE_TYPE (tree_result),
  			       ctx->variant_part_offset, tree_result);
  
!   /* If the byte offset is a constant, it's simplier to handle a native
       constant rather than a DWARF expression.  */
    if (TREE_CODE (tree_result) == INTEGER_CST)
      {
--- 20325,20331 ----
      tree_result = fold_build2 (PLUS_EXPR, TREE_TYPE (tree_result),
  			       ctx->variant_part_offset, tree_result);
  
!   /* If the byte offset is a constant, it's simpler to handle a native
       constant rather than a DWARF expression.  */
    if (TREE_CODE (tree_result) == INTEGER_CST)
      {
*************** add_data_member_location_attribute (dw_d
*** 20506,20512 ****
        /* While DW_AT_data_bit_offset has been added already in DWARF4,
  	 e.g. GDB only added support to it in November 2016.  For DWARF5
  	 we need newer debug info consumers anyway.  We might change this
! 	 to dwarf_version >= 4 once most consumers catched up.  */
        if (dwarf_version >= 5
  	  && TREE_CODE (decl) == FIELD_DECL
  	  && DECL_BIT_FIELD_TYPE (decl)
--- 20506,20512 ----
        /* While DW_AT_data_bit_offset has been added already in DWARF4,
  	 e.g. GDB only added support to it in November 2016.  For DWARF5
  	 we need newer debug info consumers anyway.  We might change this
! 	 to dwarf_version >= 4 once most consumers caught up.  */
        if (dwarf_version >= 5
  	  && TREE_CODE (decl) == FIELD_DECL
  	  && DECL_BIT_FIELD_TYPE (decl)
*************** premark_used_variables (void)
*** 23877,23883 ****
      {
        dw_die_ref die = lookup_decl_die (var->decl);
        if (die)
! 	die->die_perennial_p = 1;
      }
  }
  
--- 23877,23893 ----
      {
        dw_die_ref die = lookup_decl_die (var->decl);
        if (die)
! 	{
! 	  die->die_perennial_p = 1;
! 	  if (tree attr = lookup_attribute ("structured bindings",
! 					    DECL_ATTRIBUTES (var->decl)))
! 	    for (tree d = TREE_VALUE (attr); d; d = TREE_CHAIN (d))
! 	      {
! 		die = lookup_decl_die (TREE_VALUE (d));
! 		if (die)
! 		  die->die_perennial_p = 1;
! 	      }
! 	}
      }
  }
  
*************** gen_lexical_block_die (tree stmt, dw_die
*** 25469,25475 ****
  
    if (BLOCK_ABSTRACT_ORIGIN (stmt))
      {
!       /* If this is an inlined or conrecte instance, create a new lexical
  	 die for anything below to attach DW_AT_abstract_origin to.  */
        if (old_die)
  	stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
--- 25479,25485 ----
  
    if (BLOCK_ABSTRACT_ORIGIN (stmt))
      {
!       /* If this is an inlined or concrete instance, create a new lexical
  	 die for anything below to attach DW_AT_abstract_origin to.  */
        if (old_die)
  	stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
*************** analyze_variants_discr (tree variant_par
*** 26097,26103 ****
  		goto abort;
  
  	      /* Extract the discriminant from the first operand and check it
! 		 is consistant with the same analysis in the second
  		 operand.  */
  	      candidate_discr_1
  	        = analyze_discr_in_predicate (TREE_OPERAND (lower_op, 0),
--- 26107,26113 ----
  		goto abort;
  
  	      /* Extract the discriminant from the first operand and check it
! 		 is consistent with the same analysis in the second
  		 operand.  */
  	      candidate_discr_1
  	        = analyze_discr_in_predicate (TREE_OPERAND (lower_op, 0),
*************** analyze_variants_discr (tree variant_par
*** 26153,26159 ****
  	       matching discriminant values.  Abort everything.  */
  	    goto abort;
  
! 	  /* If the discriminant info is not consistant with what we saw so
  	     far, consider the analysis failed and abort everything.  */
  	  if (candidate_discr == NULL_TREE
  	      || (*discr_decl != NULL_TREE && candidate_discr != *discr_decl))
--- 26163,26169 ----
  	       matching discriminant values.  Abort everything.  */
  	    goto abort;
  
! 	  /* If the discriminant info is not consistent with what we saw so
  	     far, consider the analysis failed and abort everything.  */
  	  if (candidate_discr == NULL_TREE
  	      || (*discr_decl != NULL_TREE && candidate_discr != *discr_decl))
*************** gen_decl_die (tree decl, tree origin, st
*** 27624,27630 ****
  	 DW_TAG_union_type, or DW_TAG_enumeration_type DIE here.  But nothing
  	 should be actually referencing those DIEs, as variable DIEs with that
  	 type would be emitted already in the abstract origin, so it was always
! 	 removed during unused type prunning.  Don't add anything in this
  	 case.  */
        if (TYPE_DECL_IS_STUB (decl) && decl_ultimate_origin (decl) != NULL_TREE)
  	break;
--- 27634,27640 ----
  	 DW_TAG_union_type, or DW_TAG_enumeration_type DIE here.  But nothing
  	 should be actually referencing those DIEs, as variable DIEs with that
  	 type would be emitted already in the abstract origin, so it was always
! 	 removed during unused type pruning.  Don't add anything in this
  	 case.  */
        if (TYPE_DECL_IS_STUB (decl) && decl_ultimate_origin (decl) != NULL_TREE)
  	break;
*************** dwarf2out_late_global_decl (tree decl)
*** 27896,27902 ****
  		    && is_trivial_indirect_ref (DECL_VALUE_EXPR (decl))))
  	    tree_add_const_value_attribute_for_decl (die, decl);
  	  else
! 	    add_location_or_const_value_attribute (die, decl, false);
  	}
      }
  }
--- 27906,27928 ----
  		    && is_trivial_indirect_ref (DECL_VALUE_EXPR (decl))))
  	    tree_add_const_value_attribute_for_decl (die, decl);
  	  else
! 	    {
! 	      add_location_or_const_value_attribute (die, decl, false);
! 	      /* For C++ structured bindings at namespace scope when processing
! 		 the underlying variable also add locations on the structured
! 		 bindings which refer to it (unless they are tuple-based, then
! 		 they are separate VAR_DECLs registered in varpool).  */
! 	      if (tree attr = lookup_attribute ("structured bindings",
! 						DECL_ATTRIBUTES (decl)))
! 		for (tree d = TREE_VALUE (attr); d; d = TREE_CHAIN (d))
! 		  {
! 		    die = lookup_decl_die (TREE_VALUE (d));
! 		    if (die)
! 		      add_location_or_const_value_attribute (die,
! 							     TREE_VALUE (d),
! 							     false);
! 		  }
! 	    }
  	}
      }
  }
*************** resolve_variable_value (dw_die_ref die)
*** 33428,33434 ****
        }
  }
  
! /* Attempt to optimize DW_OP_GNU_variable_value refering to
     temporaries in the current function.  */
  
  static void
--- 33454,33460 ----
        }
  }
  
! /* Attempt to optimize DW_OP_GNU_variable_value referring to
     temporaries in the current function.  */
  
  static void
diff -Nrcpad gcc-16-20251214/gcc/flag-types.h gcc-16-20251221/gcc/flag-types.h
*** gcc-16-20251214/gcc/flag-types.h	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/flag-types.h	Sun Dec 21 22:32:06 2025
*************** enum sanitize_code {
*** 338,343 ****
--- 338,347 ----
    SANITIZE_KERNEL_HWADDRESS = 1UL << 30,
    /* Shadow Call Stack.  */
    SANITIZE_SHADOW_CALL_STACK = 1UL << 31,
+   /* Memory Tagging for Stack.  */
+   SANITIZE_MEMTAG_STACK = 1ULL << 32,
+   /* Memory Tagging.  */
+   SANITIZE_MEMTAG = SANITIZE_MEMTAG_STACK,
    SANITIZE_SHIFT = SANITIZE_SHIFT_BASE | SANITIZE_SHIFT_EXPONENT,
    SANITIZE_UNDEFINED = SANITIZE_SHIFT | SANITIZE_DIVIDE | SANITIZE_UNREACHABLE
  		       | SANITIZE_VLA | SANITIZE_NULL | SANITIZE_RETURN
diff -Nrcpad gcc-16-20251214/gcc/fortran/ChangeLog gcc-16-20251221/gcc/fortran/ChangeLog
*** gcc-16-20251214/gcc/fortran/ChangeLog	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/fortran/ChangeLog	Sun Dec 21 22:32:06 2025
***************
*** 1,3 ****
--- 1,59 ----
+ 2025-12-19  Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	* dump-parse-tree.cc (show_omp_clauses): Add default: with
+ 	gcc_unreachable () to avoid spurious -Wmaybe-uninitialized warnings.
+ 
+ 2025-12-19  Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	* gfortran.texi: Fix typo, transfered -> transferred.
+ 	* resolve.cc (resolve_where): Fix comment typo, outmost -> outermost.
+ 
+ 2025-12-19  Harald Anlauf  <anlauf@gmx.de>
+ 
+ 	PR fortran/71565
+ 	* expr.cc (gfc_check_vardef_context): Fix treatment of INTENT(IN)
+ 	checks for ASSOCIATE variables.  Correct checking of PROTECTED
+ 	objects, as subobjects inherit the PROTECTED attribute.
+ 
+ 2025-12-19  Christopher Albert  <albert@tugraz.at>
+ 
+ 	PR fortran/92613
+ 	* cpp.cc (gfc_cpp_preprocess): Skip libcpp for -fpreprocessed.
+ 	Error out for -fpreprocessed -E.
+ 	* f95-lang.cc (gfc_init): Skip libcpp init for -fpreprocessed.
+ 	* scanner.cc (gfc_new_file): Load source directly if preprocessed.
+ 	* invoke.texi (Preprocessing Options): Document -fpreprocessed.
+ 
+ 2025-12-19  Tobias Burnus  <tburnus@baylibre.com>
+ 
+ 	* openmp.cc (gfc_match_omp_clause_uses_allocators): Accept
+ 	multiple clause-argument-specifications separated by ';'.
+ 
+ 2025-12-18  Tobias Burnus  <tburnus@baylibre.com>
+ 
+ 	* dump-parse-tree.cc (show_omp_assumes): Handle
+ 	no_openmp_constructs clause.
+ 	* gfortran.h (struct gfc_omp_assumptions): Add
+ 	no_openmp_constructs.
+ 	* openmp.cc (gfc_match_dupl_check): For free-form
+ 	Fortran, avoid substring matching.
+ 	(gfc_match_omp_clauses): Match no_openmp_constructs clause.
+ 	Remove no longer needed 'needs_space', match 'order' followed by
+ 	parenthesis instead of 'order' with parenthesis; reorder 'order'
+ 	and 'ordering' clauses for free-form Fortran.
+ 	(gfc_match_omp_assumes): Handle no_openmp_constructs clause.
+ 
+ 2025-12-18  Tobias Burnus  <tburnus@baylibre.com>
+ 
+ 	* dump-parse-tree.cc (show_omp_clauses): Handle
+ 	device_type clause.
+ 	* openmp.cc (gfc_match_omp_clauses): Reorder to
+ 	match 'device' after 'device_...' to avoid parse
+ 	errors.
+ 	(OMP_TARGET_CLAUSES): Add device_type clause.
+ 	* trans-openmp.cc (gfc_trans_omp_clauses,
+ 	gfc_split_omp_clauses): Handle device_type clause.
+ 
  2025-12-12  Tobias Burnus  <tburnus@baylibre.com>
  
  	* openmp.cc (gfc_match_omp_clause_uses_allocators): Mention
diff -Nrcpad gcc-16-20251214/gcc/fortran/cpp.cc gcc-16-20251221/gcc/fortran/cpp.cc
*** gcc-16-20251214/gcc/fortran/cpp.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/fortran/cpp.cc	Sun Dec 21 22:32:06 2025
*************** gfc_cpp_preprocess (const char *source_f
*** 679,684 ****
--- 679,691 ----
    if (!gfc_cpp_enabled ())
      return false;
  
+   if (gfc_option.flag_preprocessed)
+     {
+       if (gfc_cpp_preprocess_only ())
+ 	gfc_fatal_error ("%<-E%> is not supported with %<-fpreprocessed%>");
+       return false;
+     }
+ 
    cpp_change_file (cpp_in, LC_RENAME, source_file);
  
    if (cpp_option->traditional)
diff -Nrcpad gcc-16-20251214/gcc/fortran/dump-parse-tree.cc gcc-16-20251221/gcc/fortran/dump-parse-tree.cc
*** gcc-16-20251214/gcc/fortran/dump-parse-tree.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/fortran/dump-parse-tree.cc	Sun Dec 21 22:32:06 2025
*************** show_omp_assumes (gfc_omp_assumptions *a
*** 1736,1741 ****
--- 1736,1743 ----
      }
    if (assume->no_openmp)
      fputs (" NO_OPENMP", dumpfile);
+   if (assume->no_openmp_constructs)
+     fputs (" NO_OPENMP_CONSTRUCTS", dumpfile);
    if (assume->no_openmp_routines)
      fputs (" NO_OPENMP_ROUTINES", dumpfile);
    if (assume->no_parallelism)
*************** show_omp_clauses (gfc_omp_clauses *omp_c
*** 1984,1989 ****
--- 1986,2007 ----
      fputs (" NOWAIT", dumpfile);
    if (omp_clauses->collapse)
      fprintf (dumpfile, " COLLAPSE(%d)", omp_clauses->collapse);
+   if (omp_clauses->device_type != OMP_DEVICE_TYPE_UNSET)
+     {
+       const char *s;
+       switch (omp_clauses->device_type)
+ 	{
+ 	case OMP_DEVICE_TYPE_HOST: s = "host"; break;
+ 	case OMP_DEVICE_TYPE_NOHOST: s = "nohost"; break;
+ 	case OMP_DEVICE_TYPE_ANY: s = "any"; break;
+ 	case OMP_DEVICE_TYPE_UNSET:
+ 	default:
+ 	  gcc_unreachable ();
+ 	}
+       fputs (" DEVICE_TYPE(", dumpfile);
+       fputs (s, dumpfile);
+       fputc (')', dumpfile);
+     }
    for (list_type = 0; list_type < OMP_LIST_NUM; list_type++)
      if (omp_clauses->lists[list_type] != NULL)
        {
diff -Nrcpad gcc-16-20251214/gcc/fortran/expr.cc gcc-16-20251221/gcc/fortran/expr.cc
*** gcc-16-20251214/gcc/fortran/expr.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/fortran/expr.cc	Sun Dec 21 22:32:06 2025
*************** gfc_check_vardef_context (gfc_expr* e, b
*** 6757,6763 ****
  		  ? CLASS_DATA (sym)->attr.class_pointer : sym->attr.pointer;
    for (ref = e->ref; ref && check_intentin; ref = ref->next)
      {
!       if (ptr_component && ref->type == REF_COMPONENT)
  	check_intentin = false;
        if (ref->type == REF_COMPONENT)
  	{
--- 6757,6766 ----
  		  ? CLASS_DATA (sym)->attr.class_pointer : sym->attr.pointer;
    for (ref = e->ref; ref && check_intentin; ref = ref->next)
      {
!       /* Associate-targets need special handling.  Subobjects of an object with
! 	 the PROTECTED attribute inherit this attribute.  */
!       if (ptr_component && ref->type == REF_COMPONENT
! 	  && !sym->assoc && !sym->attr.is_protected)
  	check_intentin = false;
        if (ref->type == REF_COMPONENT)
  	{
*************** gfc_check_vardef_context (gfc_expr* e, b
*** 6780,6803 ****
  	}
      }
  
    if (check_intentin
        && (sym->attr.intent == INTENT_IN
  	  || (sym->attr.select_type_temporary && sym->assoc
  	      && sym->assoc->target && sym->assoc->target->symtree
  	      && sym->assoc->target->symtree->n.sym->attr.intent == INTENT_IN)))
      {
        if (pointer && is_pointer)
  	{
  	  if (context)
  	    gfc_error ("Dummy argument %qs with INTENT(IN) in pointer"
  		       " association context (%s) at %L",
! 		       sym->name, context, &e->where);
  	  return false;
  	}
        if (!pointer && !is_pointer && !sym->attr.pointer)
  	{
- 	  const char *name = sym->attr.select_type_temporary
- 			   ? sym->assoc->target->symtree->name : sym->name;
  	  if (context)
  	    gfc_error ("Dummy argument %qs with INTENT(IN) in variable"
  		       " definition context (%s) at %L",
--- 6783,6816 ----
  	}
      }
  
+   /* See if the INTENT(IN) check should apply to an ASSOCIATE target.  */
+   if (check_intentin
+       && sym->assoc
+       && sym->assoc->target
+       && sym->assoc->target->symtree
+       && sym->assoc->target->symtree->n.sym
+       && sym->assoc->target->symtree->n.sym->attr.dummy
+       && sym->assoc->target->symtree->n.sym->attr.intent != INTENT_IN)
+     check_intentin = false;
+ 
    if (check_intentin
        && (sym->attr.intent == INTENT_IN
  	  || (sym->attr.select_type_temporary && sym->assoc
  	      && sym->assoc->target && sym->assoc->target->symtree
  	      && sym->assoc->target->symtree->n.sym->attr.intent == INTENT_IN)))
      {
+       const char *name = (sym->attr.select_type_temporary
+ 			  ? sym->assoc->target->symtree->name : sym->name);
        if (pointer && is_pointer)
  	{
  	  if (context)
  	    gfc_error ("Dummy argument %qs with INTENT(IN) in pointer"
  		       " association context (%s) at %L",
! 		       name, context, &e->where);
  	  return false;
  	}
        if (!pointer && !is_pointer && !sym->attr.pointer)
  	{
  	  if (context)
  	    gfc_error ("Dummy argument %qs with INTENT(IN) in variable"
  		       " definition context (%s) at %L",
*************** gfc_check_vardef_context (gfc_expr* e, b
*** 6810,6816 ****
    if (sym->attr.is_protected
        && (sym->attr.use_assoc
  	  || (sym->attr.used_in_submodule && !sym_is_from_ancestor (sym)))
!       && check_intentin)
      {
        if (pointer && is_pointer)
  	{
--- 6823,6830 ----
    if (sym->attr.is_protected
        && (sym->attr.use_assoc
  	  || (sym->attr.used_in_submodule && !sym_is_from_ancestor (sym)))
!       && !own_scope
!       && (check_intentin || !pointer))
      {
        if (pointer && is_pointer)
  	{
*************** gfc_check_vardef_context (gfc_expr* e, b
*** 6863,6869 ****
  	}
      }
    /* Check variable definition context for associate-names.  */
!   if (!pointer && sym->assoc && !sym->attr.select_rank_temporary)
      {
        const char* name;
        gfc_association_list* assoc;
--- 6877,6884 ----
  	}
      }
    /* Check variable definition context for associate-names.  */
!   if ((!pointer || check_intentin)
!       && sym->assoc && !sym->attr.select_rank_temporary)
      {
        const char* name;
        gfc_association_list* assoc;
*************** gfc_check_vardef_context (gfc_expr* e, b
*** 6927,6934 ****
  	    }
  	}
  
!       /* Target must be allowed to appear in a variable definition context.  */
!       if (!gfc_check_vardef_context (assoc->target, pointer, false, false, NULL))
  	{
  	  if (context)
  	    gfc_error ("Associate-name %qs cannot appear in a variable"
--- 6942,6951 ----
  	    }
  	}
  
!       /* Target must be allowed to appear in a variable definition context.
! 	 Check valid assignment to pointers and invalid reassociations.  */
!       if (!gfc_check_vardef_context (assoc->target, pointer, false, false, NULL)
! 	  && (!ptr_component || pointer))
  	{
  	  if (context)
  	    gfc_error ("Associate-name %qs cannot appear in a variable"
diff -Nrcpad gcc-16-20251214/gcc/fortran/f95-lang.cc gcc-16-20251221/gcc/fortran/f95-lang.cc
*** gcc-16-20251214/gcc/fortran/f95-lang.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/fortran/f95-lang.cc	Sun Dec 21 22:32:06 2025
*************** gfc_be_parse_file (void)
*** 274,280 ****
  static bool
  gfc_init (void)
  {
!   if (!gfc_cpp_enabled ())
      {
        linemap_add (line_table, LC_ENTER, false, gfc_source_file, 1);
        linemap_add (line_table, LC_RENAME, false, special_fname_builtin (), 0);
--- 274,280 ----
  static bool
  gfc_init (void)
  {
!   if (!gfc_cpp_enabled () || gfc_option.flag_preprocessed)
      {
        linemap_add (line_table, LC_ENTER, false, gfc_source_file, 1);
        linemap_add (line_table, LC_RENAME, false, special_fname_builtin (), 0);
*************** gfc_init (void)
*** 285,291 ****
    gfc_init_decl_processing ();
    gfc_static_ctors = NULL_TREE;
  
!   if (gfc_cpp_enabled ())
      gfc_cpp_init ();
  
    gfc_init_1 ();
--- 285,291 ----
    gfc_init_decl_processing ();
    gfc_static_ctors = NULL_TREE;
  
!   if (gfc_cpp_enabled () && !gfc_option.flag_preprocessed)
      gfc_cpp_init ();
  
    gfc_init_1 ();
diff -Nrcpad gcc-16-20251214/gcc/fortran/gfortran.h gcc-16-20251221/gcc/fortran/gfortran.h
*** gcc-16-20251214/gcc/fortran/gfortran.h	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/fortran/gfortran.h	Sun Dec 21 22:32:07 2025
*************** typedef struct gfc_omp_assumptions
*** 1631,1637 ****
    int n_absent, n_contains;
    enum gfc_statement *absent, *contains;
    gfc_expr_list *holds;
!   bool no_openmp:1, no_openmp_routines:1, no_parallelism:1;
  }
  gfc_omp_assumptions;
  
--- 1631,1638 ----
    int n_absent, n_contains;
    enum gfc_statement *absent, *contains;
    gfc_expr_list *holds;
!   bool no_openmp:1, no_openmp_routines:1, no_openmp_constructs:1;
!   bool no_parallelism:1;
  }
  gfc_omp_assumptions;
  
diff -Nrcpad gcc-16-20251214/gcc/fortran/gfortran.texi gcc-16-20251221/gcc/fortran/gfortran.texi
*** gcc-16-20251214/gcc/fortran/gfortran.texi	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/fortran/gfortran.texi	Sun Dec 21 22:32:07 2025
*************** then this needs to be set to the byte si
*** 4892,4898 ****
  a @code{CHARACTER (KIND=4)} string.  The length of the string is then given
  in @code{opt_src_charlen} and @code{opt_dst_charlen} (also for string arrays).
  @item @var{scalar_transfer} @tab intent(in)  Is set to true when the data to be
! transfered between the two images is not an array with a descriptor.
  @item @var{dst_stat} @tab intent(out) When non-@code{NULL} give the result of
  the operation on the receiving side, i.e., zero on success and non-zero on
  error.  When @code{NULL} and an error occurs, then an error message is printed
--- 4892,4898 ----
  a @code{CHARACTER (KIND=4)} string.  The length of the string is then given
  in @code{opt_src_charlen} and @code{opt_dst_charlen} (also for string arrays).
  @item @var{scalar_transfer} @tab intent(in)  Is set to true when the data to be
! transferred between the two images is not an array with a descriptor.
  @item @var{dst_stat} @tab intent(out) When non-@code{NULL} give the result of
  the operation on the receiving side, i.e., zero on success and non-zero on
  error.  When @code{NULL} and an error occurs, then an error message is printed
diff -Nrcpad gcc-16-20251214/gcc/fortran/invoke.texi gcc-16-20251221/gcc/fortran/invoke.texi
*** gcc-16-20251214/gcc/fortran/invoke.texi	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/fortran/invoke.texi	Sun Dec 21 22:32:07 2025
*************** invoke the preprocessor on any file, use
*** 647,652 ****
--- 647,656 ----
  preprocessing on files where the preprocessor is run automatically, use
  @option{-nocpp}.
  
+ When compiling a preprocessed file, use @option{-fpreprocessed}
+ (@pxref{Preprocessor Options,,Options Controlling the Preprocessor,gcc,
+ Using the GNU Compiler Collection (GCC)}).  This skips the C preprocessor.
+ 
  If a preprocessed file includes another file with the Fortran @code{INCLUDE}
  statement, the included file is not preprocessed.  To preprocess included
  files, use the equivalent preprocessor statement @code{#include}.
diff -Nrcpad gcc-16-20251214/gcc/fortran/openmp.cc gcc-16-20251221/gcc/fortran/openmp.cc
*** gcc-16-20251214/gcc/fortran/openmp.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/fortran/openmp.cc	Sun Dec 21 22:32:07 2025
*************** omp_verify_merge_absent_contains (gfc_st
*** 1795,1803 ****
--- 1795,1808 ----
       predefined-allocator
       variable ( traits-array )
  
+    OpenMP 5.2 deprecated, 6.0 deleted: 'variable ( traits-array )'
+ 
     OpenMP 5.2:
     uses_allocators ( [modifier-list :] allocator-list )
  
+    OpenMP 6.0:
+    uses_allocators ( [modifier-list :] allocator-list [; ...])
+ 
     allocator:
       variable or predefined-allocator
     modifier:
*************** omp_verify_merge_absent_contains (gfc_st
*** 1807,1812 ****
--- 1812,1818 ----
  static match
  gfc_match_omp_clause_uses_allocators (gfc_omp_clauses *c)
  {
+ parse_next:
    gfc_symbol *memspace_sym = NULL;
    gfc_symbol *traits_sym = NULL;
    gfc_omp_namelist *head = NULL;
*************** gfc_match_omp_clause_uses_allocators (gf
*** 1878,1888 ****
  	  p->u.memspace_sym = memspace_sym;
  	  p->u2.traits_sym = traits_sym;
  	}
!       if (gfc_match (", ") == MATCH_YES)
! 	continue;
!       if (gfc_match (") ") == MATCH_YES)
  	break;
!       goto error;
      } while (true);
  
    list = &c->lists[OMP_LIST_USES_ALLOCATORS];
--- 1884,1900 ----
  	  p->u.memspace_sym = memspace_sym;
  	  p->u2.traits_sym = traits_sym;
  	}
!       gfc_gobble_whitespace ();
!       const char c = gfc_peek_ascii_char ();
!       if (c == ';' || c == ')')
  	break;
!       if (c != ',')
! 	{
! 	  gfc_error ("Expected %<,%>, %<)%> or %<;%> at %C");
! 	  goto error;
! 	}
!       gfc_match_char (',');
!       gfc_gobble_whitespace ();
      } while (true);
  
    list = &c->lists[OMP_LIST_USES_ALLOCATORS];
*************** gfc_match_omp_clause_uses_allocators (gf
*** 1890,1895 ****
--- 1902,1911 ----
      list = &(*list)->next;
    *list = head;
  
+   if (gfc_match_char (';') == MATCH_YES)
+     goto parse_next;
+ 
+   gfc_match_char (')');
    return MATCH_YES;
  
  error:
*************** gfc_match_dupl_check (bool not_dupl, con
*** 2313,2321 ****
--- 2329,2346 ----
  		      gfc_expr **expr = NULL, const char *dupl_msg = NULL)
  {
    match m;
+   char c;
    locus old_loc = gfc_current_locus;
    if ((m = gfc_match (name)) != MATCH_YES)
      return m;
+   /* Ensure that no partial string is matched.  */
+   if (gfc_current_form == FORM_FREE
+       && gfc_match_eos () != MATCH_YES
+       && ((c = gfc_peek_ascii_char ()) == '_' || ISALNUM (c)))
+     {
+       gfc_current_locus = old_loc;
+       return MATCH_NO;
+     }
    if (!not_dupl)
      {
        if (dupl_msg)
*************** gfc_match_omp_clauses (gfc_omp_clauses *
*** 2442,2448 ****
  	      if (m == MATCH_ERROR)
  		goto error;
  	      c->memorder = OMP_MEMORDER_ACQ_REL;
- 	      needs_space = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_MEMORDER)
--- 2467,2472 ----
*************** gfc_match_omp_clauses (gfc_omp_clauses *
*** 2453,2459 ****
  	      if (m == MATCH_ERROR)
  		goto error;
  	      c->memorder = OMP_MEMORDER_ACQUIRE;
- 	      needs_space = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_AFFINITY)
--- 2477,2482 ----
*************** gfc_match_omp_clauses (gfc_omp_clauses *
*** 2574,2580 ****
  					     gfc_default_integer_kind,
  					     &gfc_current_locus);
  		  mpz_set_si (c->async_expr->value.integer, GOMP_ASYNC_NOVAL);
- 		  needs_space = true;
  		}
  	      continue;
  	    }
--- 2597,2602 ----
*************** gfc_match_omp_clauses (gfc_omp_clauses *
*** 2585,2591 ****
  	      if (m == MATCH_ERROR)
  		goto error;
  	      c->par_auto = true;
- 	      needs_space = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_ATTACH)
--- 2607,2612 ----
*************** gfc_match_omp_clauses (gfc_omp_clauses *
*** 2625,2631 ****
  	      if (m == MATCH_ERROR)
  		goto error;
  	      c->capture = true;
- 	      needs_space = true;
  	      continue;
  	    }
  	  if (mask & OMP_CLAUSE_COLLAPSE)
--- 2646,2651 ----
*************** gfc_match_omp_clauses (gfc_omp_clauses *
*** 2657,2663 ****
  	      if (m == MATCH_ERROR)
  		goto error;
  	      c->compare = true;
- 	      needs_space = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_ASSUMPTIONS)
--- 2677,2682 ----
*************** gfc_match_omp_clauses (gfc_omp_clauses *
*** 3013,3018 ****
--- 3032,3074 ----
  					   OMP_MAP_DETACH, false,
  					   allow_derived))
  	    continue;
+ 	  if ((mask & OMP_CLAUSE_DEVICEPTR)
+ 	      && gfc_match ("deviceptr ( ") == MATCH_YES
+ 	      && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP],
+ 					   OMP_MAP_FORCE_DEVICEPTR, false,
+ 					   allow_derived))
+ 	    continue;
+ 	  if ((mask & OMP_CLAUSE_DEVICE_TYPE)
+ 	      && gfc_match_dupl_check (c->device_type == OMP_DEVICE_TYPE_UNSET,
+ 				       "device_type", true) == MATCH_YES)
+ 	    {
+ 	      if (gfc_match ("host") == MATCH_YES)
+ 		c->device_type = OMP_DEVICE_TYPE_HOST;
+ 	      else if (gfc_match ("nohost") == MATCH_YES)
+ 		c->device_type = OMP_DEVICE_TYPE_NOHOST;
+ 	      else if (gfc_match ("any") == MATCH_YES)
+ 		c->device_type = OMP_DEVICE_TYPE_ANY;
+ 	      else
+ 		{
+ 		  gfc_error ("Expected HOST, NOHOST or ANY at %C");
+ 		  break;
+ 		}
+ 	      if (gfc_match (" )") != MATCH_YES)
+ 		break;
+ 	      continue;
+ 	    }
+ 	  if ((mask & OMP_CLAUSE_DEVICE_RESIDENT)
+ 	      && gfc_match_omp_variable_list
+ 		   ("device_resident (",
+ 		    &c->lists[OMP_LIST_DEVICE_RESIDENT], true) == MATCH_YES)
+ 	    continue;
+ 	  if ((mask & OMP_CLAUSE_DEVICE)
+ 	      && openacc
+ 	      && gfc_match ("device ( ") == MATCH_YES
+ 	      && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP],
+ 					   OMP_MAP_FORCE_TO, true,
+ 					   /* allow_derived = */ true))
+ 	    continue;
  	  if ((mask & OMP_CLAUSE_DEVICE)
  	      && !openacc
  	      && ((m = gfc_match_dupl_check (!c->device, "device", true))
*************** gfc_match_omp_clauses (gfc_omp_clauses *
*** 3072,3113 ****
  		}
  	      continue;
  	    }
- 	  if ((mask & OMP_CLAUSE_DEVICE)
- 	      && openacc
- 	      && gfc_match ("device ( ") == MATCH_YES
- 	      && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP],
- 					   OMP_MAP_FORCE_TO, true,
- 					   /* allow_derived = */ true))
- 	    continue;
- 	  if ((mask & OMP_CLAUSE_DEVICEPTR)
- 	      && gfc_match ("deviceptr ( ") == MATCH_YES
- 	      && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP],
- 					   OMP_MAP_FORCE_DEVICEPTR, false,
- 					   allow_derived))
- 	    continue;
- 	  if ((mask & OMP_CLAUSE_DEVICE_TYPE)
- 	      && gfc_match ("device_type ( ") == MATCH_YES)
- 	    {
- 	      if (gfc_match ("host") == MATCH_YES)
- 		c->device_type = OMP_DEVICE_TYPE_HOST;
- 	      else if (gfc_match ("nohost") == MATCH_YES)
- 		c->device_type = OMP_DEVICE_TYPE_NOHOST;
- 	      else if (gfc_match ("any") == MATCH_YES)
- 		c->device_type = OMP_DEVICE_TYPE_ANY;
- 	      else
- 		{
- 		  gfc_error ("Expected HOST, NOHOST or ANY at %C");
- 		  break;
- 		}
- 	      if (gfc_match (" )") != MATCH_YES)
- 		break;
- 	      continue;
- 	    }
- 	  if ((mask & OMP_CLAUSE_DEVICE_RESIDENT)
- 	      && gfc_match_omp_variable_list
- 		   ("device_resident (",
- 		    &c->lists[OMP_LIST_DEVICE_RESIDENT], true) == MATCH_YES)
- 	    continue;
  	  if ((mask & OMP_CLAUSE_DIST_SCHEDULE)
  	      && c->dist_sched_kind == OMP_SCHED_NONE
  	      && gfc_match ("dist_schedule ( static") == MATCH_YES)
--- 3128,3133 ----
*************** gfc_match_omp_clauses (gfc_omp_clauses *
*** 3197,3203 ****
  	      if (m == MATCH_ERROR)
  		goto error;
  	      c->finalize = true;
- 	      needs_space = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_FIRSTPRIVATE)
--- 3217,3222 ----
*************** gfc_match_omp_clauses (gfc_omp_clauses *
*** 3214,3220 ****
  	    {
  	      if (m == MATCH_ERROR)
  		goto error;
! 	      c->full = needs_space = true;
  	      continue;
  	    }
  	  break;
--- 3233,3239 ----
  	    {
  	      if (m == MATCH_ERROR)
  		goto error;
! 	      c->full = true;
  	      continue;
  	    }
  	  break;
*************** gfc_match_omp_clauses (gfc_omp_clauses *
*** 3231,3238 ****
  		  gfc_current_locus = old_loc;
  		  break;
  		}
- 	      else if (m == MATCH_NO)
- 		needs_space = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_GRAINSIZE)
--- 3250,3255 ----
*************** gfc_match_omp_clauses (gfc_omp_clauses *
*** 3291,3297 ****
  	      if (m == MATCH_ERROR)
  		goto error;
  	      c->if_present = true;
- 	      needs_space = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_IF)
--- 3308,3313 ----
*************** gfc_match_omp_clauses (gfc_omp_clauses *
*** 3336,3342 ****
  	    {
  	      if (m == MATCH_ERROR)
  		goto error;
! 	      c->inbranch = needs_space = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_INDEPENDENT)
--- 3352,3358 ----
  	    {
  	      if (m == MATCH_ERROR)
  		goto error;
! 	      c->inbranch = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_INDEPENDENT)
*************** gfc_match_omp_clauses (gfc_omp_clauses *
*** 3346,3352 ****
  	      if (m == MATCH_ERROR)
  		goto error;
  	      c->independent = true;
- 	      needs_space = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_INDIRECT)
--- 3362,3367 ----
*************** gfc_match_omp_clauses (gfc_omp_clauses *
*** 3734,3740 ****
  	    {
  	      if (m == MATCH_ERROR)
  		goto error;
! 	      c->mergeable = needs_space = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_MESSAGE)
--- 3749,3755 ----
  	    {
  	      if (m == MATCH_ERROR)
  		goto error;
! 	      c->mergeable = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_MESSAGE)
*************** gfc_match_omp_clauses (gfc_omp_clauses *
*** 3755,3791 ****
  	    continue;
  	  if ((mask & OMP_CLAUSE_ASSUMPTIONS)
  	      && (m = gfc_match_dupl_check (!c->assume
  					    || !c->assume->no_openmp_routines,
! 					    "no_openmp_routines")) == MATCH_YES)
  	    {
  	      if (m == MATCH_ERROR)
  		goto error;
  	      if (c->assume == NULL)
  		c->assume = gfc_get_omp_assumptions ();
! 	      c->assume->no_openmp_routines = needs_space = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_ASSUMPTIONS)
  	      && (m = gfc_match_dupl_check (!c->assume || !c->assume->no_openmp,
! 					    "no_openmp")) == MATCH_YES)
  	    {
  	      if (m == MATCH_ERROR)
  		goto error;
  	      if (c->assume == NULL)
  		c->assume = gfc_get_omp_assumptions ();
! 	      c->assume->no_openmp = needs_space = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_ASSUMPTIONS)
  	      && (m = gfc_match_dupl_check (!c->assume
  					    || !c->assume->no_parallelism,
! 					    "no_parallelism")) == MATCH_YES)
  	    {
  	      if (m == MATCH_ERROR)
  		goto error;
  	      if (c->assume == NULL)
  		c->assume = gfc_get_omp_assumptions ();
! 	      c->assume->no_parallelism = needs_space = true;
  	      continue;
  	    }
  
--- 3770,3818 ----
  	    continue;
  	  if ((mask & OMP_CLAUSE_ASSUMPTIONS)
  	      && (m = gfc_match_dupl_check (!c->assume
+ 					    || !c->assume->no_openmp_constructs,
+ 					    "no_openmp_constructs")) != MATCH_NO)
+ 	    {
+ 	      if (m == MATCH_ERROR)
+ 		goto error;
+ 	      if (c->assume == NULL)
+ 		c->assume = gfc_get_omp_assumptions ();
+ 	      c->assume->no_openmp_constructs = true;
+ 	      continue;
+ 	    }
+ 	  if ((mask & OMP_CLAUSE_ASSUMPTIONS)
+ 	      && (m = gfc_match_dupl_check (!c->assume
  					    || !c->assume->no_openmp_routines,
! 					    "no_openmp_routines")) != MATCH_NO)
  	    {
  	      if (m == MATCH_ERROR)
  		goto error;
  	      if (c->assume == NULL)
  		c->assume = gfc_get_omp_assumptions ();
! 	      c->assume->no_openmp_routines = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_ASSUMPTIONS)
  	      && (m = gfc_match_dupl_check (!c->assume || !c->assume->no_openmp,
! 					    "no_openmp")) != MATCH_NO)
  	    {
  	      if (m == MATCH_ERROR)
  		goto error;
  	      if (c->assume == NULL)
  		c->assume = gfc_get_omp_assumptions ();
! 	      c->assume->no_openmp = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_ASSUMPTIONS)
  	      && (m = gfc_match_dupl_check (!c->assume
  					    || !c->assume->no_parallelism,
! 					    "no_parallelism")) != MATCH_NO)
  	    {
  	      if (m == MATCH_ERROR)
  		goto error;
  	      if (c->assume == NULL)
  		c->assume = gfc_get_omp_assumptions ();
! 	      c->assume->no_parallelism = true;
  	      continue;
  	    }
  
*************** gfc_match_omp_clauses (gfc_omp_clauses *
*** 3813,3819 ****
  	    {
  	      if (m == MATCH_ERROR)
  		goto error;
! 	      c->nogroup = needs_space = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_NOHOST)
--- 3840,3846 ----
  	    {
  	      if (m == MATCH_ERROR)
  		goto error;
! 	      c->nogroup = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_NOHOST)
*************** gfc_match_omp_clauses (gfc_omp_clauses *
*** 3821,3827 ****
  	    {
  	      if (m == MATCH_ERROR)
  		goto error;
! 	      c->nohost = needs_space = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_NOTEMPORAL)
--- 3848,3854 ----
  	    {
  	      if (m == MATCH_ERROR)
  		goto error;
! 	      c->nohost = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_NOTEMPORAL)
*************** gfc_match_omp_clauses (gfc_omp_clauses *
*** 3835,3841 ****
  	    {
  	      if (m == MATCH_ERROR)
  		goto error;
! 	      c->notinbranch = needs_space = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_NOWAIT)
--- 3862,3868 ----
  	    {
  	      if (m == MATCH_ERROR)
  		goto error;
! 	      c->notinbranch = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_NOWAIT)
*************** gfc_match_omp_clauses (gfc_omp_clauses *
*** 3843,3849 ****
  	    {
  	      if (m == MATCH_ERROR)
  		goto error;
! 	      c->nowait = needs_space = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_NUM_GANGS)
--- 3870,3876 ----
  	    {
  	      if (m == MATCH_ERROR)
  		goto error;
! 	      c->nowait = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_NUM_GANGS)
*************** gfc_match_omp_clauses (gfc_omp_clauses *
*** 3906,3933 ****
  	    }
  	  break;
  	case 'o':
- 	  if ((mask & OMP_CLAUSE_ORDER)
- 	      && (m = gfc_match_dupl_check (!c->order_concurrent, "order ("))
- 		 != MATCH_NO)
- 	    {
- 	      if (m == MATCH_ERROR)
- 		goto error;
- 	      if (gfc_match (" reproducible : concurrent )") == MATCH_YES)
- 		c->order_reproducible = true;
- 	      else if (gfc_match (" concurrent )") == MATCH_YES)
- 		;
- 	      else if (gfc_match (" unconstrained : concurrent )") == MATCH_YES)
- 		c->order_unconstrained = true;
- 	      else
- 		{
- 		  gfc_error ("Expected ORDER(CONCURRENT) at %C "
- 			     "with optional %<reproducible%> or "
- 			     "%<unconstrained%> modifier");
- 		  goto error;
- 		}
- 	      c->order_concurrent = true;
- 	      continue;
- 	    }
  	  if ((mask & OMP_CLAUSE_ORDERED)
  	      && (m = gfc_match_dupl_check (!c->ordered, "ordered"))
  		 != MATCH_NO)
--- 3933,3938 ----
*************** gfc_match_omp_clauses (gfc_omp_clauses *
*** 3954,3960 ****
  		  continue;
  		}
  
! 	      needs_space = true;
  	      continue;
  	    }
  	  break;
--- 3959,3986 ----
  		  continue;
  		}
  
! 	      continue;
! 	    }
! 	  if ((mask & OMP_CLAUSE_ORDER)
! 	      && (m = gfc_match_dupl_check (!c->order_concurrent, "order", true))
! 		 != MATCH_NO)
! 	    {
! 	      if (m == MATCH_ERROR)
! 		goto error;
! 	      if (gfc_match (" reproducible : concurrent )") == MATCH_YES)
! 		c->order_reproducible = true;
! 	      else if (gfc_match (" concurrent )") == MATCH_YES)
! 		;
! 	      else if (gfc_match (" unconstrained : concurrent )") == MATCH_YES)
! 		c->order_unconstrained = true;
! 	      else
! 		{
! 		  gfc_error ("Expected ORDER(CONCURRENT) at %C "
! 			     "with optional %<reproducible%> or "
! 			     "%<unconstrained%> modifier");
! 		  goto error;
! 		}
! 	      c->order_concurrent = true;
  	      continue;
  	    }
  	  break;
*************** gfc_match_omp_clauses (gfc_omp_clauses *
*** 4079,4085 ****
  	      if (m == MATCH_ERROR)
  		goto error;
  	      c->atomic_op = GFC_OMP_ATOMIC_READ;
- 	      needs_space = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_REDUCTION)
--- 4105,4110 ----
*************** gfc_match_omp_clauses (gfc_omp_clauses *
*** 4094,4100 ****
  	      if (m == MATCH_ERROR)
  		goto error;
  	      c->memorder = OMP_MEMORDER_RELAXED;
- 	      needs_space = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_MEMORDER)
--- 4119,4124 ----
*************** gfc_match_omp_clauses (gfc_omp_clauses *
*** 4105,4111 ****
  	      if (m == MATCH_ERROR)
  		goto error;
  	      c->memorder = OMP_MEMORDER_RELEASE;
- 	      needs_space = true;
  	      continue;
  	    }
  	  break;
--- 4129,4134 ----
*************** gfc_match_omp_clauses (gfc_omp_clauses *
*** 4199,4209 ****
  		  break;
  		}
  	      else if (m == MATCH_NO)
! 		{
! 		  c->self_expr = gfc_get_logical_expr (gfc_default_logical_kind,
! 						       NULL, true);
! 		  needs_space = true;
! 		}
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_SELF)
--- 4222,4229 ----
  		  break;
  		}
  	      else if (m == MATCH_NO)
! 		c->self_expr = gfc_get_logical_expr (gfc_default_logical_kind,
! 						     NULL, true);
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_SELF)
*************** gfc_match_omp_clauses (gfc_omp_clauses *
*** 4219,4225 ****
  	      if (m == MATCH_ERROR)
  		goto error;
  	      c->seq = true;
- 	      needs_space = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_MEMORDER)
--- 4239,4244 ----
*************** gfc_match_omp_clauses (gfc_omp_clauses *
*** 4230,4236 ****
  	      if (m == MATCH_ERROR)
  		goto error;
  	      c->memorder = OMP_MEMORDER_SEQ_CST;
- 	      needs_space = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_SHARED)
--- 4249,4254 ----
*************** gfc_match_omp_clauses (gfc_omp_clauses *
*** 4251,4257 ****
  	    {
  	      if (m == MATCH_ERROR)
  		goto error;
! 	      c->simd = needs_space = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_SEVERITY)
--- 4269,4275 ----
  	    {
  	      if (m == MATCH_ERROR)
  		goto error;
! 	      c->simd = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_SEVERITY)
*************** gfc_match_omp_clauses (gfc_omp_clauses *
*** 4307,4313 ****
  	    {
  	      if (m == MATCH_ERROR)
  		goto error;
! 	      c->threads = needs_space = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_TILE)
--- 4325,4331 ----
  	    {
  	      if (m == MATCH_ERROR)
  		goto error;
! 	      c->threads = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_TILE)
*************** gfc_match_omp_clauses (gfc_omp_clauses *
*** 4347,4353 ****
  	    {
  	      if (m == MATCH_ERROR)
  		goto error;
! 	      c->untied = needs_space = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_ATOMIC)
--- 4365,4371 ----
  	    {
  	      if (m == MATCH_ERROR)
  		goto error;
! 	      c->untied = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_ATOMIC)
*************** gfc_match_omp_clauses (gfc_omp_clauses *
*** 4358,4364 ****
  	      if (m == MATCH_ERROR)
  		goto error;
  	      c->atomic_op = GFC_OMP_ATOMIC_UPDATE;
- 	      needs_space = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_USE)
--- 4376,4381 ----
*************** gfc_match_omp_clauses (gfc_omp_clauses *
*** 4411,4418 ****
  	      m = match_oacc_clause_gwv (c, GOMP_DIM_VECTOR);
  	      if (m == MATCH_ERROR)
  		goto error;
- 	      if (m == MATCH_NO)
- 		needs_space = true;
  	      continue;
  	    }
  	  break;
--- 4428,4433 ----
*************** gfc_match_omp_clauses (gfc_omp_clauses *
*** 4446,4452 ****
  	      if (m == MATCH_ERROR)
  		goto error;
  	      c->weak = true;
- 	      needs_space = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_WORKER)
--- 4461,4466 ----
*************** gfc_match_omp_clauses (gfc_omp_clauses *
*** 4458,4465 ****
  	      m = match_oacc_clause_gwv (c, GOMP_DIM_WORKER);
  	      if (m == MATCH_ERROR)
  		goto error;
- 	      else if (m == MATCH_NO)
- 		needs_space = true;
  	      continue;
  	    }
  	  if ((mask & OMP_CLAUSE_ATOMIC)
--- 4472,4477 ----
*************** gfc_match_omp_clauses (gfc_omp_clauses *
*** 4470,4476 ****
  	      if (m == MATCH_ERROR)
  		goto error;
  	      c->atomic_op = GFC_OMP_ATOMIC_WRITE;
- 	      needs_space = true;
  	      continue;
  	    }
  	  break;
--- 4482,4487 ----
*************** cleanup:
*** 5136,5142 ****
     | OMP_CLAUSE_IS_DEVICE_PTR | OMP_CLAUSE_IN_REDUCTION			\
     | OMP_CLAUSE_THREAD_LIMIT | OMP_CLAUSE_ALLOCATE			\
     | OMP_CLAUSE_HAS_DEVICE_ADDR | OMP_CLAUSE_USES_ALLOCATORS		\
!    | OMP_CLAUSE_DYN_GROUPPRIVATE)
  #define OMP_TARGET_DATA_CLAUSES \
    (omp_mask (OMP_CLAUSE_DEVICE) | OMP_CLAUSE_MAP | OMP_CLAUSE_IF	\
     | OMP_CLAUSE_USE_DEVICE_PTR | OMP_CLAUSE_USE_DEVICE_ADDR)
--- 5147,5153 ----
     | OMP_CLAUSE_IS_DEVICE_PTR | OMP_CLAUSE_IN_REDUCTION			\
     | OMP_CLAUSE_THREAD_LIMIT | OMP_CLAUSE_ALLOCATE			\
     | OMP_CLAUSE_HAS_DEVICE_ADDR | OMP_CLAUSE_USES_ALLOCATORS		\
!    | OMP_CLAUSE_DYN_GROUPPRIVATE | OMP_CLAUSE_DEVICE_TYPE)
  #define OMP_TARGET_DATA_CLAUSES \
    (omp_mask (OMP_CLAUSE_DEVICE) | OMP_CLAUSE_MAP | OMP_CLAUSE_IF	\
     | OMP_CLAUSE_USE_DEVICE_PTR | OMP_CLAUSE_USE_DEVICE_ADDR)
*************** gfc_match_omp_assumes (void)
*** 5355,5360 ****
--- 5366,5373 ----
        gfc_current_ns->omp_assumes->no_openmp |= c->assume->no_openmp;
        gfc_current_ns->omp_assumes->no_openmp_routines
  	|= c->assume->no_openmp_routines;
+       gfc_current_ns->omp_assumes->no_openmp_constructs
+ 	|= c->assume->no_openmp_constructs;
        gfc_current_ns->omp_assumes->no_parallelism |= c->assume->no_parallelism;
        if (gfc_current_ns->omp_assumes->holds && c->assume->holds)
  	{
diff -Nrcpad gcc-16-20251214/gcc/fortran/resolve.cc gcc-16-20251221/gcc/fortran/resolve.cc
*** gcc-16-20251214/gcc/fortran/resolve.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/fortran/resolve.cc	Sun Dec 21 22:32:07 2025
*************** over:
*** 12173,12179 ****
  
  
  /* Check whether a WHERE assignment target or a WHERE mask expression
!    has the same shape as the outmost WHERE mask expression.  */
  
  static void
  resolve_where (gfc_code *code, gfc_expr *mask)
--- 12173,12179 ----
  
  
  /* Check whether a WHERE assignment target or a WHERE mask expression
!    has the same shape as the outermost WHERE mask expression.  */
  
  static void
  resolve_where (gfc_code *code, gfc_expr *mask)
*************** resolve_where (gfc_code *code, gfc_expr
*** 12185,12192 ****
    cblock = code->block;
  
    /* Store the first WHERE mask-expr of the WHERE statement or construct.
!      In case of nested WHERE, only the outmost one is stored.  */
!   if (mask == NULL) /* outmost WHERE */
      e = cblock->expr1;
    else /* inner WHERE */
      e = mask;
--- 12185,12192 ----
    cblock = code->block;
  
    /* Store the first WHERE mask-expr of the WHERE statement or construct.
!      In case of nested WHERE, only the outermost one is stored.  */
!   if (mask == NULL) /* outermost WHERE */
      e = cblock->expr1;
    else /* inner WHERE */
      e = mask;
*************** resolve_where (gfc_code *code, gfc_expr
*** 12196,12202 ****
        if (cblock->expr1)
  	{
  	  /* Check if the mask-expr has a consistent shape with the
! 	     outmost WHERE mask-expr.  */
  	  if (!resolve_where_shape (cblock->expr1, e))
  	    gfc_error ("WHERE mask at %L has inconsistent shape",
  		       &cblock->expr1->where);
--- 12196,12202 ----
        if (cblock->expr1)
  	{
  	  /* Check if the mask-expr has a consistent shape with the
! 	     outermost WHERE mask-expr.  */
  	  if (!resolve_where_shape (cblock->expr1, e))
  	    gfc_error ("WHERE mask at %L has inconsistent shape",
  		       &cblock->expr1->where);
diff -Nrcpad gcc-16-20251214/gcc/fortran/scanner.cc gcc-16-20251221/gcc/fortran/scanner.cc
*** gcc-16-20251214/gcc/fortran/scanner.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/fortran/scanner.cc	Sun Dec 21 22:32:07 2025
*************** gfc_new_file (void)
*** 2775,2783 ****
  
    if (gfc_cpp_enabled ())
      {
!       gfc_cpp_preprocess (gfc_source_file);
!       if (!gfc_cpp_preprocess_only ())
! 	load_file (gfc_cpp_temporary_file (), gfc_source_file, true);
      }
    else
      load_file (gfc_source_file, NULL, true);
--- 2775,2787 ----
  
    if (gfc_cpp_enabled ())
      {
!       if (gfc_cpp_preprocess (gfc_source_file))
! 	{
! 	  if (!gfc_cpp_preprocess_only ())
! 	    load_file (gfc_cpp_temporary_file (), gfc_source_file, true);
! 	}
!       else
! 	load_file (gfc_source_file, NULL, true);
      }
    else
      load_file (gfc_source_file, NULL, true);
diff -Nrcpad gcc-16-20251214/gcc/fortran/trans-expr.cc gcc-16-20251221/gcc/fortran/trans-expr.cc
*** gcc-16-20251214/gcc/fortran/trans-expr.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/fortran/trans-expr.cc	Sun Dec 21 22:32:07 2025
*************** conv_dummy_value (gfc_se * parmse, gfc_e
*** 6654,6659 ****
--- 6654,6667 ----
  						  e->value.character.string);
        parmse->string_length = build_int_cst (gfc_charlen_type_node, flen);
  
+       if (flen == 1)
+ 	{
+ 	  tree slen1 = build_int_cst (gfc_charlen_type_node, 1);
+ 	  gfc_conv_string_parameter (parmse);
+ 	  parmse->expr = gfc_string_to_single_character (slen1, parmse->expr,
+ 							 e->ts.kind);
+ 	}
+ 
        /* Indicate value,optional scalar dummy argument as present.  */
        if (fsym->attr.optional)
  	vec_safe_push (optionalargs, boolean_true_node);
diff -Nrcpad gcc-16-20251214/gcc/fortran/trans-openmp.cc gcc-16-20251221/gcc/fortran/trans-openmp.cc
*** gcc-16-20251214/gcc/fortran/trans-openmp.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/fortran/trans-openmp.cc	Sun Dec 21 22:32:07 2025
*************** gfc_trans_omp_clauses (stmtblock_t *bloc
*** 5266,5271 ****
--- 5266,5294 ----
        omp_clauses = gfc_trans_add_clause (c, omp_clauses);
      }
  
+   if (clauses->device_type != OMP_DEVICE_TYPE_UNSET)
+     {
+       enum omp_clause_device_type_kind type;
+       switch (clauses->device_type)
+ 	{
+ 	case OMP_DEVICE_TYPE_HOST:
+ 	  type = OMP_CLAUSE_DEVICE_TYPE_HOST;
+ 	  break;
+ 	case OMP_DEVICE_TYPE_NOHOST:
+ 	  type = OMP_CLAUSE_DEVICE_TYPE_NOHOST;
+ 	  break;
+ 	case OMP_DEVICE_TYPE_ANY:
+ 	  type = OMP_CLAUSE_DEVICE_TYPE_ANY;
+ 	  break;
+ 	case OMP_DEVICE_TYPE_UNSET:
+ 	default:
+ 	  gcc_unreachable ();
+ 	}
+       c = build_omp_clause (gfc_get_location (&where), OMP_CLAUSE_DEVICE_TYPE);
+       OMP_CLAUSE_DEVICE_TYPE_KIND (c) = type;
+       omp_clauses = gfc_trans_add_clause (c, omp_clauses);
+     }
+ 
    if (clauses->dyn_groupprivate)
      {
        gfc_init_se (&se, NULL);
*************** gfc_split_omp_clauses (gfc_code *code,
*** 8051,8056 ****
--- 8074,8081 ----
  	    = code->ext.omp_clauses->if_expr;
  	  clausesa[GFC_OMP_SPLIT_TARGET].nowait
  	    = code->ext.omp_clauses->nowait;
+ 	  clausesa[GFC_OMP_SPLIT_TARGET].device_type
+ 	    = code->ext.omp_clauses->device_type;
  	}
        if (mask & GFC_OMP_MASK_TEAMS)
  	{
diff -Nrcpad gcc-16-20251214/gcc/fortran/trans.cc gcc-16-20251221/gcc/fortran/trans.cc
*** gcc-16-20251214/gcc/fortran/trans.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/fortran/trans.cc	Sun Dec 21 22:32:07 2025
*************** gfc_finalize_tree_expr (gfc_se *se, gfc_
*** 1623,1629 ****
    if (derived && (derived->attr.is_c_interop
  		  || derived->attr.is_iso_c
  		  || derived->attr.is_bind_c
! 		  || derived->attr.defined_assign_comp))
      return;
  
    if (is_class)
--- 1623,1632 ----
    if (derived && (derived->attr.is_c_interop
  		  || derived->attr.is_iso_c
  		  || derived->attr.is_bind_c
! 		  || (derived->attr.extension && derived->f2k_derived
! 		      && derived->f2k_derived->tb_op[INTRINSIC_ASSIGN])
! 		  || (!derived->attr.extension
! 		      && derived->attr.defined_assign_comp)))
      return;
  
    if (is_class)
*************** gfc_finalize_tree_expr (gfc_se *se, gfc_
*** 1638,1649 ****
      }
    else if (derived && gfc_is_finalizable (derived, NULL))
      {
!       if (!derived->components && (!rank || attr.elemental))
  	{
  	  /* Any attempt to assign zero length entities, causes the gimplifier
  	     all manner of problems. Instead, a variable is created to act as
! 	     as the argument for the final call.  */
! 	  desc = gfc_create_var (TREE_TYPE (se->expr), "zero");
  	}
        else if (se->direct_byref)
  	{
--- 1641,1655 ----
      }
    else if (derived && gfc_is_finalizable (derived, NULL))
      {
!       tree type = TREE_TYPE (se->expr);
!       if (type && TYPE_SIZE_UNIT (type)
! 	  && integer_zerop (TYPE_SIZE_UNIT (type))
! 	  && (!rank || attr.elemental))
  	{
  	  /* Any attempt to assign zero length entities, causes the gimplifier
  	     all manner of problems. Instead, a variable is created to act as
! 	     the argument for the final call.  */
! 	  desc = gfc_create_var (type, "zero");
  	}
        else if (se->direct_byref)
  	{
diff -Nrcpad gcc-16-20251214/gcc/gcc.cc gcc-16-20251221/gcc/gcc.cc
*** gcc-16-20251214/gcc/gcc.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/gcc.cc	Sun Dec 21 22:32:07 2025
*************** static const struct compiler default_com
*** 1517,1522 ****
--- 1517,1527 ----
  #endif
     , 0, 0, 0},
  
+ #ifndef EXTRA_DEFAULT_COMPILERS
+ #define EXTRA_DEFAULT_COMPILERS
+ #endif
+   EXTRA_DEFAULT_COMPILERS
+ 
  #include "specs.h"
    /* Mark end of table.  */
    {0, 0, 0, 0, 0}
*************** find_a_program (const char *name)
*** 3092,3097 ****
--- 3097,3107 ----
      return xstrdup (DEFAULT_DSYMUTIL);
  #endif
  
+ #ifdef DEFAULT_WINDRES
+   if (! strcmp (name, "windres") && access (DEFAULT_WINDRES, X_OK) == 0)
+     return xstrdup (DEFAULT_WINDRES);
+ #endif
+ 
    return find_a_file (&exec_prefixes, name, X_OK, false);
  }
  
*************** sanitize_spec_function (int argc, const
*** 10552,10557 ****
--- 10562,10569 ----
      return (flag_sanitize & SANITIZE_KERNEL_ADDRESS) ? "" : NULL;
    if (strcmp (argv[0], "kernel-hwaddress") == 0)
      return (flag_sanitize & SANITIZE_KERNEL_HWADDRESS) ? "" : NULL;
+   if (strcmp (argv[0], "memtag-stack") == 0)
+     return (flag_sanitize & SANITIZE_MEMTAG_STACK) ? "" : NULL;
    if (strcmp (argv[0], "thread") == 0)
      return (flag_sanitize & SANITIZE_THREAD) ? "" : NULL;
    if (strcmp (argv[0], "undefined") == 0)
diff -Nrcpad gcc-16-20251214/gcc/gengtype.cc gcc-16-20251221/gcc/gengtype.cc
*** gcc-16-20251214/gcc/gengtype.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/gengtype.cc	Sun Dec 21 22:32:07 2025
*************** walk_subclasses (type_p base, struct wal
*** 2635,2640 ****
--- 2635,2641 ----
  	  d->indent += 2;
  	  oprintf (d->of, "%*s%s *sub = static_cast <%s *> (x);\n",
  		   d->indent, "", sub->u.s.tag, sub->u.s.tag);
+ 	  oprintf (d->of, "%*s(void) sub;\n", d->indent, "");
  	  const char *old_val = d->val;
  	  d->val = "(*sub)";
  	  walk_type (sub, d);
diff -Nrcpad gcc-16-20251214/gcc/genmatch.cc gcc-16-20251221/gcc/genmatch.cc
*** gcc-16-20251214/gcc/genmatch.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/genmatch.cc	Sun Dec 21 22:32:07 2025
*************** public:
*** 1520,1526 ****
    /* The operator and its operands.  */
    id_base *operation;
    vec<operand *> ops;
!   /* An explicitely specified type - used exclusively for conversions.  */
    const char *expr_type;
    /* Whether the operation is to be applied commutatively.  This is
       later lowered to two separate patterns.  */
--- 1520,1526 ----
    /* The operator and its operands.  */
    id_base *operation;
    vec<operand *> ops;
!   /* An explicitly specified type - used exclusively for conversions.  */
    const char *expr_type;
    /* Whether the operation is to be applied commutatively.  This is
       later lowered to two separate patterns.  */
diff -Nrcpad gcc-16-20251214/gcc/gimple-range-gori.cc gcc-16-20251221/gcc/gimple-range-gori.cc
*** gcc-16-20251214/gcc/gimple-range-gori.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/gimple-range-gori.cc	Sun Dec 21 22:32:07 2025
*************** gori_compute::may_recompute_p (tree name
*** 1325,1333 ****
    if (!dep1)
      return false;
  
!   // Don't recalculate PHIs or statements with side_effects.
    gimple *s = SSA_NAME_DEF_STMT (name);
!   if (is_a<gphi *> (s) || gimple_has_side_effects (s))
      return false;
  
    if (!dep2)
--- 1325,1334 ----
    if (!dep1)
      return false;
  
!   // Only recalculate range-op statements that are recomputable.
    gimple *s = SSA_NAME_DEF_STMT (name);
!   gimple_range_op_handler handler (s);
!   if (!handler || !handler.recomputable_p ())
      return false;
  
    if (!dep2)
diff -Nrcpad gcc-16-20251214/gcc/gimple-range-op.cc gcc-16-20251221/gcc/gimple-range-op.cc
*** gcc-16-20251214/gcc/gimple-range-op.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/gimple-range-op.cc	Sun Dec 21 22:32:07 2025
*************** gimple_range_op_handler::gimple_range_op
*** 125,130 ****
--- 125,132 ----
    m_stmt = s;
    m_op1 = NULL_TREE;
    m_op2 = NULL_TREE;
+   // Recomputation defaults to TRUE.
+   m_recomputable = true;
  
    if (oper)
      switch (gimple_code (m_stmt))
*************** gimple_range_op_handler::maybe_builtin_c
*** 1413,1418 ****
--- 1415,1422 ----
  	m_operator = &op_cfn_constant_p;
        else if (frange::supports_p (TREE_TYPE (m_op1)))
  	m_operator = &op_cfn_constant_float_p;
+       // builtin_constant_p should not be recomputed.  See PR 123205.
+       m_recomputable = false;
        break;
  
      CASE_FLT_FN (CFN_BUILT_IN_SIGNBIT):
diff -Nrcpad gcc-16-20251214/gcc/gimple-range-op.h gcc-16-20251221/gcc/gimple-range-op.h
*** gcc-16-20251214/gcc/gimple-range-op.h	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/gimple-range-op.h	Sun Dec 21 22:32:07 2025
*************** public:
*** 39,49 ****
--- 39,51 ----
  		 relation_trio = TRIO_VARYING);
    bool calc_op2 (vrange &r, const vrange &lhs_range, const vrange &op1_range,
  		 relation_trio = TRIO_VARYING);
+   inline bool recomputable_p () { return m_recomputable; }
  private:
    void maybe_builtin_call ();
    void maybe_non_standard ();
    gimple *m_stmt;
    tree m_op1, m_op2;
+   bool m_recomputable;
  };
  
  // Given stmt S, fill VEC, up to VEC_SIZE elements, with relevant ssa-names
diff -Nrcpad gcc-16-20251214/gcc/gimple-range-phi.cc gcc-16-20251221/gcc/gimple-range-phi.cc
*** gcc-16-20251214/gcc/gimple-range-phi.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/gimple-range-phi.cc	Sun Dec 21 22:32:07 2025
*************** phi_group::phi_group (bitmap bm, irange
*** 82,88 ****
    m_vr.set_varying (init_range.type ());
  }
  
! // Return 0 if S is not a modifier statment for group members BM.
  // If it could be a modifier, return which operand position (1 or 2)
  // the phi member occurs in.
  unsigned
--- 82,88 ----
    m_vr.set_varying (init_range.type ());
  }
  
! // Return 0 if S is not a modifier statement for group members BM.
  // If it could be a modifier, return which operand position (1 or 2)
  // the phi member occurs in.
  unsigned
diff -Nrcpad gcc-16-20251214/gcc/gimple-ssa-store-merging.cc gcc-16-20251221/gcc/gimple-ssa-store-merging.cc
*** gcc-16-20251214/gcc/gimple-ssa-store-merging.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/gimple-ssa-store-merging.cc	Sun Dec 21 22:32:07 2025
*************** maybe_optimize_vector_constructor (gimpl
*** 1534,1541 ****
  }
  
  /* Find manual byte swap implementations as well as load in a given
!    endianness. Byte swaps are turned into a bswap builtin invokation
!    while endian loads are converted to bswap builtin invokation or
     simple load according to the target endianness.  */
  
  unsigned int
--- 1534,1541 ----
  }
  
  /* Find manual byte swap implementations as well as load in a given
!    endianness.  Byte swaps are turned into a bswap builtin invocation
!    while endian loads are converted to bswap builtin invocation or
     simple load according to the target endianness.  */
  
  unsigned int
diff -Nrcpad gcc-16-20251214/gcc/gimple-walk.cc gcc-16-20251221/gcc/gimple-walk.cc
*** gcc-16-20251214/gcc/gimple-walk.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/gimple-walk.cc	Sun Dec 21 22:32:07 2025
*************** walk_gimple_op (gimple *stmt, walk_tree_
*** 535,541 ****
        break;
  
      case GIMPLE_PHI:
!       /* PHIs are not GSS_WITH_OPS so we need to handle them explicitely.  */
        {
  	gphi *phi = as_a <gphi *> (stmt);
  	if (wi)
--- 535,541 ----
        break;
  
      case GIMPLE_PHI:
!       /* PHIs are not GSS_WITH_OPS so we need to handle them explicitly.  */
        {
  	gphi *phi = as_a <gphi *> (stmt);
  	if (wi)
diff -Nrcpad gcc-16-20251214/gcc/gimplify.cc gcc-16-20251221/gcc/gimplify.cc
*** gcc-16-20251214/gcc/gimplify.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/gimplify.cc	Sun Dec 21 22:32:07 2025
*************** gimple_add_tmp_var (tree tmp)
*** 901,907 ****
  /* This page contains routines to unshare tree nodes, i.e. to duplicate tree
     nodes that are referenced more than once in GENERIC functions.  This is
     necessary because gimplification (translation into GIMPLE) is performed
!    by modifying tree nodes in-place, so gimplication of a shared node in a
     first context could generate an invalid GIMPLE form in a second context.
  
     This is achieved with a simple mark/copy/unmark algorithm that walks the
--- 901,907 ----
  /* This page contains routines to unshare tree nodes, i.e. to duplicate tree
     nodes that are referenced more than once in GENERIC functions.  This is
     necessary because gimplification (translation into GIMPLE) is performed
!    by modifying tree nodes in-place, so gimplification of a shared node in a
     first context could generate an invalid GIMPLE form in a second context.
  
     This is achieved with a simple mark/copy/unmark algorithm that walks the
*************** asan_poison_variable (tree decl, bool po
*** 1318,1326 ****
  
    /* It's necessary to have all stack variables aligned to ASAN granularity
       bytes.  */
!   gcc_assert (!hwasan_sanitize_p () || hwasan_sanitize_stack_p ());
    unsigned shadow_granularity
!     = hwasan_sanitize_p () ? HWASAN_TAG_GRANULE_SIZE : ASAN_SHADOW_GRANULARITY;
    if (DECL_ALIGN_UNIT (decl) <= shadow_granularity)
      SET_DECL_ALIGN (decl, BITS_PER_UNIT * shadow_granularity);
  
--- 1318,1327 ----
  
    /* It's necessary to have all stack variables aligned to ASAN granularity
       bytes.  */
!   gcc_assert (!hwassist_sanitize_p () || hwassist_sanitize_stack_p ());
    unsigned shadow_granularity
!     = (hwassist_sanitize_p ()
!        ? HWASAN_TAG_GRANULE_SIZE : ASAN_SHADOW_GRANULARITY);
    if (DECL_ALIGN_UNIT (decl) <= shadow_granularity)
      SET_DECL_ALIGN (decl, BITS_PER_UNIT * shadow_granularity);
  
*************** gimple_add_padding_init_for_auto_var (tr
*** 2100,2106 ****
    gimplify_seq_add_stmt (seq_p, call);
  }
  
! /* Return true if the DECL need to be automaticly initialized by the
     compiler.  */
  static bool
  var_needs_auto_init_p (tree decl)
--- 2101,2107 ----
    gimplify_seq_add_stmt (seq_p, call);
  }
  
! /* Return true if the DECL need to be automatically initialized by the
     compiler.  */
  static bool
  var_needs_auto_init_p (tree decl)
*************** gimplify_decl_expr (tree *stmt_p, gimple
*** 2157,2163 ****
        /* Check whether a decl has FE created VALUE_EXPR here BEFORE
  	 gimplify_vla_decl creates VALUE_EXPR for a vla decl.
  	 If the decl has VALUE_EXPR that was created by FE (usually
! 	 C++FE), it's a proxy varaible, and FE already initialized
  	 the VALUE_EXPR of it, we should not initialize it anymore.  */
        bool decl_had_value_expr_p = DECL_HAS_VALUE_EXPR_P (decl);
  
--- 2158,2164 ----
        /* Check whether a decl has FE created VALUE_EXPR here BEFORE
  	 gimplify_vla_decl creates VALUE_EXPR for a vla decl.
  	 If the decl has VALUE_EXPR that was created by FE (usually
! 	 C++FE), it's a proxy variable, and FE already initialized
  	 the VALUE_EXPR of it, we should not initialize it anymore.  */
        bool decl_had_value_expr_p = DECL_HAS_VALUE_EXPR_P (decl);
  
*************** gimplify_decl_expr (tree *stmt_p, gimple
*** 2235,2241 ****
  	     pattern initialization.
  	     In order to make the paddings as zeroes for pattern init, We
  	     should add a call to __builtin_clear_padding to clear the
! 	     paddings to zero in compatiple with CLANG.
  	     We cannot insert this call if the variable is a gimple register
  	     since __builtin_clear_padding will take the address of the
  	     variable.  As a result, if a long double/_Complex long double
--- 2236,2242 ----
  	     pattern initialization.
  	     In order to make the paddings as zeroes for pattern init, We
  	     should add a call to __builtin_clear_padding to clear the
! 	     paddings to zero in compatible with CLANG.
  	     We cannot insert this call if the variable is a gimple register
  	     since __builtin_clear_padding will take the address of the
  	     variable.  As a result, if a long double/_Complex long double
*************** gimplify_statement_list (tree *expr_p, g
*** 2304,2310 ****
  }
  
  
! /* Emit warning for the unreachable statment STMT if needed.
     Return the gimple itself when the warning is emitted, otherwise
     return NULL.  */
  static gimple *
--- 2305,2311 ----
  }
  
  
! /* Emit warning for the unreachable statement STMT if needed.
     Return the gimple itself when the warning is emitted, otherwise
     return NULL.  */
  static gimple *
*************** collect_fallthrough_labels (gimple_stmt_
*** 2710,2716 ****
    return prev;
  }
  
! /* Return true if the switch fallthough warning should occur.  LABEL is
     the label statement that we're falling through to.  */
  
  static bool
--- 2711,2717 ----
    return prev;
  }
  
! /* Return true if the switch fallthrough warning should occur.  LABEL is
     the label statement that we're falling through to.  */
  
  static bool
*************** modify_call_for_omp_dispatch (tree expr,
*** 4094,4100 ****
  	      }
  
  	  /* Initialize the arrays, generating temp vars and clobbers for
! 	     the interobject objects.  (The constructed array holding the
  	     pointers to these objects shouldn't need clobbering as there's
  	     no reason for GOMP_interop to modify its contents.)  */
  	  for (j = ninterop, a = apparg; j < nappend; j++, a = TREE_CHAIN (a))
--- 4095,4101 ----
  	      }
  
  	  /* Initialize the arrays, generating temp vars and clobbers for
! 	     the interop objects.  (The constructed array holding the
  	     pointers to these objects shouldn't need clobbering as there's
  	     no reason for GOMP_interop to modify its contents.)  */
  	  for (j = ninterop, a = apparg; j < nappend; j++, a = TREE_CHAIN (a))
*************** oacc_default_clause (struct gimplify_omp
*** 9180,9186 ****
      type = TREE_TYPE (type);
  
    /* For Fortran COMMON blocks, only used variables in those blocks are
!      transfered and remapped.  The block itself will have a private clause to
       avoid transfering the data twice.
       The hook evaluates to false by default.  For a variable in Fortran's COMMON
       or EQUIVALENCE block, returns 'true' (as we have shared=false) - as only
--- 9181,9187 ----
      type = TREE_TYPE (type);
  
    /* For Fortran COMMON blocks, only used variables in those blocks are
!      transferred and remapped.  The block itself will have a private clause to
       avoid transfering the data twice.
       The hook evaluates to false by default.  For a variable in Fortran's COMMON
       or EQUIVALENCE block, returns 'true' (as we have shared=false) - as only
*************** omp_notice_variable (struct gimplify_omp
*** 9302,9309 ****
  	{
  	  if (ctx->region_type & ORT_ACC)
  	    /* For OpenACC, defer expansion of value to avoid transfering
! 	       privatized common block data instead of im-/explicitly transfered
! 	       variables which are in common blocks.  */
  	    ;
  	  else
  	    {
--- 9303,9310 ----
  	{
  	  if (ctx->region_type & ORT_ACC)
  	    /* For OpenACC, defer expansion of value to avoid transfering
! 	       privatized common block data instead of im-/explicitly
! 	       transferred variables which are in common blocks.  */
  	    ;
  	  else
  	    {
*************** gimplify_scan_omp_clauses (tree *list_p,
*** 14884,14889 ****
--- 14885,14891 ----
  	case OMP_CLAUSE_INIT:
  	case OMP_CLAUSE_USE:
  	case OMP_CLAUSE_DESTROY:
+ 	case OMP_CLAUSE_DEVICE_TYPE:
  	  break;
  
  	case OMP_CLAUSE_DYN_GROUPPRIVATE:
*************** end_adjust_omp_map_clause:
*** 16372,16377 ****
--- 16374,16380 ----
  	case OMP_CLAUSE_INCLUSIVE:
  	case OMP_CLAUSE_EXCLUSIVE:
  	case OMP_CLAUSE_USES_ALLOCATORS:
+ 	case OMP_CLAUSE_DEVICE_TYPE:
  	  break;
  
  	case OMP_CLAUSE_NOHOST:
diff -Nrcpad gcc-16-20251214/gcc/go/gofrontend/MERGE gcc-16-20251221/gcc/go/gofrontend/MERGE
*** gcc-16-20251214/gcc/go/gofrontend/MERGE	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/go/gofrontend/MERGE	Sun Dec 21 22:32:07 2025
***************
*** 1,4 ****
! c4d7bfb9895efc196b04f18f5da77fd99b39212a
  
  The first line of this file holds the git revision number of the last
  merge done from the gofrontend repository.
--- 1,4 ----
! 6e421340885c87c4987f27be4a16b7bedb86faaa
  
  The first line of this file holds the git revision number of the last
  merge done from the gofrontend repository.
diff -Nrcpad gcc-16-20251214/gcc/graphite-isl-ast-to-gimple.cc gcc-16-20251221/gcc/graphite-isl-ast-to-gimple.cc
*** gcc-16-20251214/gcc/graphite-isl-ast-to-gimple.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/graphite-isl-ast-to-gimple.cc	Sun Dec 21 22:32:07 2025
*************** binary_op_to_tree (tree type, __isl_take
*** 319,325 ****
    isl_ast_expr_free (expr);
  
    /* From our constraint generation we may get modulo operations that
!      we cannot represent explicitely but that are no-ops for TYPE.
       Elide those.  */
    if ((expr_type == isl_ast_op_pdiv_r
         || expr_type == isl_ast_op_zdiv_r
--- 319,325 ----
    isl_ast_expr_free (expr);
  
    /* From our constraint generation we may get modulo operations that
!      we cannot represent explicitly but that are no-ops for TYPE.
       Elide those.  */
    if ((expr_type == isl_ast_op_pdiv_r
         || expr_type == isl_ast_op_zdiv_r
diff -Nrcpad gcc-16-20251214/gcc/haifa-sched.cc gcc-16-20251221/gcc/haifa-sched.cc
*** gcc-16-20251214/gcc/haifa-sched.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/haifa-sched.cc	Sun Dec 21 22:32:07 2025
*************** choose_ready (struct ready_list *ready,
*** 6132,6140 ****
        return -1;
      }
  
!   if (dfa_lookahead <= 0 || SCHED_GROUP_P (ready_element (ready, 0))
        || DEBUG_INSN_P (ready_element (ready, 0)))
      {
        if (targetm.sched.dispatch (NULL, IS_DISPATCH_ON))
  	*insn_ptr = ready_remove_first_dispatch (ready);
        else
--- 6132,6145 ----
        return -1;
      }
  
!   if (SCHED_GROUP_P (ready_element (ready, 0))
        || DEBUG_INSN_P (ready_element (ready, 0)))
      {
+       *insn_ptr = ready_remove_first (ready);
+       return 0;
+     }
+   else if (dfa_lookahead <= 0)
+     {
        if (targetm.sched.dispatch (NULL, IS_DISPATCH_ON))
  	*insn_ptr = ready_remove_first_dispatch (ready);
        else
diff -Nrcpad gcc-16-20251214/gcc/internal-fn.cc gcc-16-20251221/gcc/internal-fn.cc
*** gcc-16-20251214/gcc/internal-fn.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/internal-fn.cc	Sun Dec 21 22:32:07 2025
*************** expand_HWASAN_CHECK (internal_fn, gcall
*** 751,756 ****
--- 751,804 ----
  }
  
  /* For hwasan stack tagging:
+    Tag memory which is dynamically allocated.  */
+ static void
+ expand_HWASAN_ALLOCA_POISON (internal_fn, gcall *gc)
+ {
+   gcc_assert (ptr_mode == Pmode);
+   tree g_target = gimple_call_lhs (gc);
+   tree g_ptr = gimple_call_arg (gc, 0);
+   tree g_size = gimple_call_arg (gc, 1);
+ 
+   /* There is no target; this happens, usually, when we have an alloca of zero
+      size.  */
+   if (!g_target)
+     return;
+   rtx target = expand_normal (g_target);
+   rtx ptr = expand_normal (g_ptr);
+   rtx size = expand_normal (g_size);
+ 
+   /* No size, nothing to do.  */
+   if (size == const0_rtx)
+     return;
+ 
+   /* Get new tag for the alloca'd memory.
+      Doing a regular add_tag () like so:
+ 	rtx tag = targetm.memtag.add_tag (hwasan_frame_base (), 0,
+ 					  hwasan_current_frame_tag ());
+      gets a new tag, which can be used for tagging memory.  But for alloca, we
+      need both tagged memory and a tagged pointer to pass to consumers.  Invoke
+      insert_random_tag () instead to add a random tag to ptr to get a tagged
+      pointer that will work for both purposes.  */
+   rtx tagged_ptr
+     = force_reg (Pmode, targetm.memtag.insert_random_tag (ptr, NULL_RTX));
+   rtx tag = targetm.memtag.extract_tag (tagged_ptr, NULL_RTX);
+ 
+   if (memtag_sanitize_p ())
+     {
+       /* Need to put the tagged ptr into the `target` RTX for consumers
+ 	 of alloca'd memory.  */
+       if (tagged_ptr != target)
+ 	emit_move_insn (target, tagged_ptr);
+       /* Tag the memory.  */
+       emit_insn (targetm.gen_tag_memory (ptr, tag, size));
+       hwasan_increment_frame_tag ();
+     }
+   else
+     gcc_unreachable ();
+ }
+ 
+ /* For hwasan stack tagging:
     Clear tags on the dynamically allocated space.
     For use after an object dynamically allocated on the stack goes out of
     scope.  */
*************** expand_HWASAN_ALLOCA_UNPOISON (internal_
*** 761,774 ****
    tree restored_position = gimple_call_arg (gc, 0);
    rtx restored_rtx = expand_expr (restored_position, NULL_RTX, VOIDmode,
  				  EXPAND_NORMAL);
-   rtx func = init_one_libfunc ("__hwasan_tag_memory");
    rtx off = expand_simple_binop (Pmode, MINUS, restored_rtx,
  				 stack_pointer_rtx, NULL_RTX, 0,
  				 OPTAB_WIDEN);
!   emit_library_call_value (func, NULL_RTX, LCT_NORMAL, VOIDmode,
! 			   virtual_stack_dynamic_rtx, Pmode,
! 			   HWASAN_STACK_BACKGROUND, QImode,
! 			   off, Pmode);
  }
  
  /* For hwasan stack tagging:
--- 809,830 ----
    tree restored_position = gimple_call_arg (gc, 0);
    rtx restored_rtx = expand_expr (restored_position, NULL_RTX, VOIDmode,
  				  EXPAND_NORMAL);
    rtx off = expand_simple_binop (Pmode, MINUS, restored_rtx,
  				 stack_pointer_rtx, NULL_RTX, 0,
  				 OPTAB_WIDEN);
! 
!   if (memtag_sanitize_p ())
!     emit_insn (targetm.gen_tag_memory (virtual_stack_dynamic_rtx,
! 				       HWASAN_STACK_BACKGROUND,
! 				       off));
!   else
!     {
!       rtx func = init_one_libfunc ("__hwasan_tag_memory");
!       emit_library_call_value (func, NULL_RTX, LCT_NORMAL, VOIDmode,
! 			       virtual_stack_dynamic_rtx, Pmode,
! 			       HWASAN_STACK_BACKGROUND, QImode,
! 			       off, Pmode);
!     }
  }
  
  /* For hwasan stack tagging:
*************** expand_HWASAN_MARK (internal_fn, gcall *
*** 822,830 ****
    tree len = gimple_call_arg (gc, 2);
    rtx r_len = expand_normal (len);
  
!   rtx func = init_one_libfunc ("__hwasan_tag_memory");
!   emit_library_call (func, LCT_NORMAL, VOIDmode, address, Pmode,
! 		     tag, QImode, r_len, Pmode);
  }
  
  /* For hwasan stack tagging:
--- 878,891 ----
    tree len = gimple_call_arg (gc, 2);
    rtx r_len = expand_normal (len);
  
!   if (memtag_sanitize_p ())
!     emit_insn (targetm.gen_tag_memory (address, tag, r_len));
!   else
!     {
!       rtx func = init_one_libfunc ("__hwasan_tag_memory");
!       emit_library_call (func, LCT_NORMAL, VOIDmode, address, Pmode,
! 			 tag, QImode, r_len, Pmode);
!     }
  }
  
  /* For hwasan stack tagging:
diff -Nrcpad gcc-16-20251214/gcc/internal-fn.def gcc-16-20251221/gcc/internal-fn.def
*** gcc-16-20251214/gcc/internal-fn.def	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/internal-fn.def	Sun Dec 21 22:32:07 2025
*************** DEF_INTERNAL_FN (UBSAN_PTR, ECF_LEAF | E
*** 499,504 ****
--- 499,505 ----
  DEF_INTERNAL_FN (UBSAN_OBJECT_SIZE, ECF_LEAF | ECF_NOTHROW, NULL)
  DEF_INTERNAL_FN (ABNORMAL_DISPATCHER, ECF_NORETURN, NULL)
  DEF_INTERNAL_FN (BUILTIN_EXPECT, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
+ DEF_INTERNAL_FN (HWASAN_ALLOCA_POISON, ECF_LEAF | ECF_NOTHROW, NULL)
  DEF_INTERNAL_FN (HWASAN_ALLOCA_UNPOISON, ECF_LEAF | ECF_NOTHROW, ". R ")
  DEF_INTERNAL_FN (HWASAN_CHOOSE_TAG, ECF_LEAF | ECF_NOTHROW, ". ")
  DEF_INTERNAL_FN (HWASAN_CHECK, ECF_TM_PURE | ECF_LEAF | ECF_NOTHROW,
diff -Nrcpad gcc-16-20251214/gcc/ipa-cp.cc gcc-16-20251221/gcc/ipa-cp.cc
*** gcc-16-20251214/gcc/ipa-cp.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/ipa-cp.cc	Sun Dec 21 22:32:07 2025
*************** initialize_node_lattices (struct cgraph_
*** 1482,1494 ****
      }
  
    for (ie = node->indirect_calls; ie; ie = ie->next_callee)
!     if (ie->indirect_info->polymorphic
! 	&& ie->indirect_info->param_index >= 0)
!       {
! 	gcc_checking_assert (ie->indirect_info->param_index >= 0);
! 	ipa_get_parm_lattices (info,
! 			       ie->indirect_info->param_index)->virt_call = 1;
!       }
  }
  
  /* Return VALUE if it is NULL_TREE or if it can be directly safely IPA-CP
--- 1482,1491 ----
      }
  
    for (ie = node->indirect_calls; ie; ie = ie->next_callee)
!     if (ie->indirect_info->param_index >= 0
! 	&& is_a <cgraph_polymorphic_indirect_info *> (ie->indirect_info))
!       ipa_get_parm_lattices (info,
! 			     ie->indirect_info->param_index)->virt_call = 1;
  }
  
  /* Return VALUE if it is NULL_TREE or if it can be directly safely IPA-CP
*************** ipa_get_indirect_edge_target_1 (struct c
*** 3106,3137 ****
  				bool *speculative)
  {
    int param_index = ie->indirect_info->param_index;
-   HOST_WIDE_INT anc_offset;
-   tree t = NULL;
-   tree target = NULL;
- 
    *speculative = false;
  
    if (param_index == -1)
      return NULL_TREE;
  
!   if (!ie->indirect_info->polymorphic)
      {
        tree t = NULL;
  
!       if (ie->indirect_info->agg_contents)
  	{
  	  t = NULL;
  	  if ((unsigned) param_index < known_csts.length ()
  	      && known_csts[param_index])
  	    t = ipa_find_agg_cst_from_init (known_csts[param_index],
! 					    ie->indirect_info->offset,
! 					    ie->indirect_info->by_ref);
  
! 	  if (!t && ie->indirect_info->guaranteed_unmodified)
! 	    t = avs.get_value (param_index,
! 			       ie->indirect_info->offset / BITS_PER_UNIT,
! 			       ie->indirect_info->by_ref);
  	}
        else if ((unsigned) param_index < known_csts.length ())
  	t = known_csts[param_index];
--- 3103,3130 ----
  				bool *speculative)
  {
    int param_index = ie->indirect_info->param_index;
    *speculative = false;
  
    if (param_index == -1)
      return NULL_TREE;
  
!   if (cgraph_simple_indirect_info *sii
!       = dyn_cast <cgraph_simple_indirect_info *> (ie->indirect_info))
      {
        tree t = NULL;
  
!       if (sii->agg_contents)
  	{
  	  t = NULL;
  	  if ((unsigned) param_index < known_csts.length ()
  	      && known_csts[param_index])
  	    t = ipa_find_agg_cst_from_init (known_csts[param_index],
! 					    sii->offset,
! 					    sii->by_ref);
  
! 	  if (!t && sii->guaranteed_unmodified)
! 	    t = avs.get_value (param_index, sii->offset / BITS_PER_UNIT,
! 			       sii->by_ref);
  	}
        else if ((unsigned) param_index < known_csts.length ())
  	t = known_csts[param_index];
*************** ipa_get_indirect_edge_target_1 (struct c
*** 3147,3169 ****
    if (!opt_for_fn (ie->caller->decl, flag_devirtualize))
      return NULL_TREE;
  
!   gcc_assert (!ie->indirect_info->agg_contents);
!   gcc_assert (!ie->indirect_info->by_ref);
!   anc_offset = ie->indirect_info->offset;
! 
!   t = NULL;
  
    if ((unsigned) param_index < known_csts.length ()
        && known_csts[param_index])
!     t = ipa_find_agg_cst_from_init (known_csts[param_index],
! 				    ie->indirect_info->offset, true);
  
    /* Try to work out value of virtual table pointer value in replacements.  */
    /* or known aggregate values.  */
    if (!t)
!     t = avs.get_value (param_index,
! 		       ie->indirect_info->offset / BITS_PER_UNIT,
! 		       true);
  
    /* If we found the virtual table pointer, lookup the target.  */
    if (t)
--- 3140,3161 ----
    if (!opt_for_fn (ie->caller->decl, flag_devirtualize))
      return NULL_TREE;
  
!   cgraph_polymorphic_indirect_info *pii
!     = as_a <cgraph_polymorphic_indirect_info *> (ie->indirect_info);
!   if (!pii->usable_p ())
!     return NULL_TREE;
  
+   HOST_WIDE_INT anc_offset = pii->offset;
+   tree t = NULL;
+   tree target = NULL;
    if ((unsigned) param_index < known_csts.length ()
        && known_csts[param_index])
!     t = ipa_find_agg_cst_from_init (known_csts[param_index], anc_offset, true);
  
    /* Try to work out value of virtual table pointer value in replacements.  */
    /* or known aggregate values.  */
    if (!t)
!     t = avs.get_value (param_index, anc_offset / BITS_PER_UNIT, true);
  
    /* If we found the virtual table pointer, lookup the target.  */
    if (t)
*************** ipa_get_indirect_edge_target_1 (struct c
*** 3173,3180 ****
        if (vtable_pointer_value_to_vtable (t, &vtable, &offset))
  	{
  	  bool can_refer;
! 	  target = gimple_get_virt_method_for_vtable (ie->indirect_info->otr_token,
! 						      vtable, offset, &can_refer);
  	  if (can_refer)
  	    {
  	      if (!target
--- 3165,3172 ----
        if (vtable_pointer_value_to_vtable (t, &vtable, &offset))
  	{
  	  bool can_refer;
! 	  target = gimple_get_virt_method_for_vtable (pii->otr_token, vtable,
! 						      offset, &can_refer);
  	  if (can_refer)
  	    {
  	      if (!target
*************** ipa_get_indirect_edge_target_1 (struct c
*** 3183,3193 ****
  		       (ie, cgraph_node::get (target)))
  		{
  		  /* Do not speculate builtin_unreachable, it is stupid!  */
! 		  if (ie->indirect_info->vptr_changed)
  		    return NULL;
  		  target = ipa_impossible_devirt_target (ie, target);
  		}
! 	      *speculative = ie->indirect_info->vptr_changed;
  	      if (!*speculative)
  		return target;
  	    }
--- 3175,3185 ----
  		       (ie, cgraph_node::get (target)))
  		{
  		  /* Do not speculate builtin_unreachable, it is stupid!  */
! 		  if (pii->vptr_changed)
  		    return NULL;
  		  target = ipa_impossible_devirt_target (ie, target);
  		}
! 	      *speculative = pii->vptr_changed;
  	      if (!*speculative)
  		return target;
  	    }
*************** ipa_get_indirect_edge_target_1 (struct c
*** 3198,3228 ****
    if (!t && (unsigned) param_index < known_csts.length ())
      t = known_csts[param_index];
  
-   gcc_checking_assert (!t || TREE_CODE (t) != TREE_BINFO);
- 
    ipa_polymorphic_call_context context;
    if (known_contexts.length () > (unsigned int) param_index)
      {
        context = known_contexts[param_index];
        context.offset_by (anc_offset);
!       if (ie->indirect_info->vptr_changed)
  	context.possible_dynamic_type_change (ie->in_polymorphic_cdtor,
! 					      ie->indirect_info->otr_type);
        if (t)
  	{
! 	  ipa_polymorphic_call_context ctx2 = ipa_polymorphic_call_context
! 	    (t, ie->indirect_info->otr_type, anc_offset);
  	  if (!ctx2.useless_p ())
! 	    context.combine_with (ctx2, ie->indirect_info->otr_type);
  	}
      }
    else if (t)
      {
!       context = ipa_polymorphic_call_context (t, ie->indirect_info->otr_type,
! 					      anc_offset);
!       if (ie->indirect_info->vptr_changed)
  	context.possible_dynamic_type_change (ie->in_polymorphic_cdtor,
! 					      ie->indirect_info->otr_type);
      }
    else
      return NULL_TREE;
--- 3190,3217 ----
    if (!t && (unsigned) param_index < known_csts.length ())
      t = known_csts[param_index];
  
    ipa_polymorphic_call_context context;
    if (known_contexts.length () > (unsigned int) param_index)
      {
        context = known_contexts[param_index];
        context.offset_by (anc_offset);
!       if (pii->vptr_changed)
  	context.possible_dynamic_type_change (ie->in_polymorphic_cdtor,
! 					      pii->otr_type);
        if (t)
  	{
! 	  ipa_polymorphic_call_context ctx2
! 	    = ipa_polymorphic_call_context (t, pii->otr_type, anc_offset);
  	  if (!ctx2.useless_p ())
! 	    context.combine_with (ctx2, pii->otr_type);
  	}
      }
    else if (t)
      {
!       context = ipa_polymorphic_call_context (t, pii->otr_type, anc_offset);
!       if (pii->vptr_changed)
  	context.possible_dynamic_type_change (ie->in_polymorphic_cdtor,
! 					      pii->otr_type);
      }
    else
      return NULL_TREE;
*************** ipa_get_indirect_edge_target_1 (struct c
*** 3230,3239 ****
    vec <cgraph_node *>targets;
    bool final;
  
!   targets = possible_polymorphic_call_targets
!     (ie->indirect_info->otr_type,
!      ie->indirect_info->otr_token,
!      context, &final);
    if (!final || targets.length () > 1)
      {
        struct cgraph_node *node;
--- 3219,3226 ----
    vec <cgraph_node *>targets;
    bool final;
  
!   targets = possible_polymorphic_call_targets (pii->otr_type, pii->otr_token,
! 					       context, &final);
    if (!final || targets.length () > 1)
      {
        struct cgraph_node *node;
*************** ipa_get_indirect_edge_target_1 (struct c
*** 3242,3249 ****
        if (!opt_for_fn (ie->caller->decl, flag_devirtualize_speculatively)
  	  || ie->speculative || !ie->maybe_hot_p ())
  	return NULL;
!       node = try_speculative_devirtualization (ie->indirect_info->otr_type,
! 					       ie->indirect_info->otr_token,
  					       context);
        if (node)
  	{
--- 3229,3235 ----
        if (!opt_for_fn (ie->caller->decl, flag_devirtualize_speculatively)
  	  || ie->speculative || !ie->maybe_hot_p ())
  	return NULL;
!       node = try_speculative_devirtualization (pii->otr_type, pii->otr_token,
  					       context);
        if (node)
  	{
*************** ipcp_discover_new_direct_edges (struct c
*** 4142,4149 ****
  					       avs, &speculative);
        if (target)
  	{
! 	  bool agg_contents = ie->indirect_info->agg_contents;
! 	  bool polymorphic = ie->indirect_info->polymorphic;
  	  int param_index = ie->indirect_info->param_index;
  	  struct cgraph_edge *cs = ipa_make_edge_direct_to_target (ie, target,
  								   speculative);
--- 4128,4139 ----
  					       avs, &speculative);
        if (target)
  	{
! 	  cgraph_polymorphic_indirect_info *pii
! 	    = dyn_cast <cgraph_polymorphic_indirect_info *> (ie->indirect_info);
! 	  cgraph_simple_indirect_info *sii
! 	    = dyn_cast <cgraph_simple_indirect_info *> (ie->indirect_info);
! 	  bool agg_contents = sii && sii->agg_contents;
! 	  bool polymorphic = !!pii;
  	  int param_index = ie->indirect_info->param_index;
  	  struct cgraph_edge *cs = ipa_make_edge_direct_to_target (ie, target,
  								   speculative);
*************** ipcp_generate_summary (void)
*** 6523,6528 ****
--- 6513,6522 ----
  
    FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
      ipa_analyze_node (node);
+ 
+   varpool_node *vnode;
+   FOR_EACH_STATIC_INITIALIZER (vnode)
+     ipa_analyze_var_static_initializer (vnode);
  }
  
  namespace {
diff -Nrcpad gcc-16-20251214/gcc/ipa-devirt.cc gcc-16-20251221/gcc/ipa-devirt.cc
*** gcc-16-20251214/gcc/ipa-devirt.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/ipa-devirt.cc	Sun Dec 21 22:32:07 2025
*************** try_speculative_devirtualization (tree o
*** 3648,3653 ****
--- 3648,3709 ----
    return likely_target;
  }
  
+ /* Various statistics counters collected during devirtualization.  */
+ 
+ struct devirt_stats
+ {
+   int npolymorphic, nspeculated, nconverted, ncold;
+   int nmultiple, noverwritable, ndevirtualized, nnotdefined;
+   int nwrong, nok, nexternal, nartificial;
+   int ndropped;
+ };
+ 
+ /* Check LIKELY_TARGET and return true if it a suitable target for
+    devirtualization or speculative devirtualization.  Increase the respective
+    counter in STATS if any check fails.  */
+ 
+ static bool
+ devirt_target_ok_p (cgraph_node *likely_target, struct devirt_stats *stats)
+ {
+   if (!likely_target->definition)
+     {
+       if (dump_file)
+ 	fprintf (dump_file, "Target is not a definition\n\n");
+       stats->nnotdefined++;
+       return false;
+     }
+   /* Do not introduce new references to external symbols.  While we
+      can handle these just well, it is common for programs to
+      incorrectly with headers defining methods they are linked
+      with.  */
+   if (DECL_EXTERNAL (likely_target->decl))
+     {
+       if (dump_file)
+ 	fprintf (dump_file, "Target is external\n\n");
+       stats->nexternal++;
+       return false;
+     }
+   /* Don't use an implicitly-declared destructor (c++/58678).  */
+   struct cgraph_node *non_thunk_target
+     = likely_target->function_symbol ();
+   if (DECL_ARTIFICIAL (non_thunk_target->decl))
+     {
+       if (dump_file)
+ 	fprintf (dump_file, "Target is artificial\n\n");
+       stats->nartificial++;
+       return false;
+     }
+   if (likely_target->get_availability () <= AVAIL_INTERPOSABLE
+       && likely_target->can_be_discarded_p ())
+     {
+       if (dump_file)
+ 	fprintf (dump_file, "Target is overwritable\n\n");
+       stats->noverwritable++;
+       return false;
+     }
+   return true;
+ }
+ 
  /* The ipa-devirt pass.
     When polymorphic call has only one likely target in the unit,
     turn it into a speculative call.  */
*************** ipa_devirt (void)
*** 3658,3681 ****
    struct cgraph_node *n;
    hash_set<void *> bad_call_targets;
    struct cgraph_edge *e;
! 
!   int npolymorphic = 0, nspeculated = 0, nconverted = 0, ncold = 0;
!   int nmultiple = 0, noverwritable = 0, ndevirtualized = 0, nnotdefined = 0;
!   int nwrong = 0, nok = 0, nexternal = 0, nartificial = 0;
!   int ndropped = 0;
! 
!   if (!odr_types_ptr)
!     return 0;
  
    if (dump_file)
!     dump_type_inheritance_graph (dump_file);
  
    /* We can output -Wsuggest-final-methods and -Wsuggest-final-types warnings.
       This is implemented by setting up final_warning_records that are updated
       by get_polymorphic_call_targets.
       We need to clear cache in this case to trigger recomputation of all
       entries.  */
!   if (warn_suggest_final_methods || warn_suggest_final_types)
      {
        final_warning_records = new (final_warning_record);
        final_warning_records->dyn_count = profile_count::zero ();
--- 3714,3734 ----
    struct cgraph_node *n;
    hash_set<void *> bad_call_targets;
    struct cgraph_edge *e;
!   struct devirt_stats stats;
!   memset (&stats, 0, sizeof (stats));
  
    if (dump_file)
!     {
!       dump_type_inheritance_graph (dump_file);
!       ipa_dump_noted_record_fnptrs (dump_file);
!     }
  
    /* We can output -Wsuggest-final-methods and -Wsuggest-final-types warnings.
       This is implemented by setting up final_warning_records that are updated
       by get_polymorphic_call_targets.
       We need to clear cache in this case to trigger recomputation of all
       entries.  */
!   if (odr_types_ptr && (warn_suggest_final_methods || warn_suggest_final_types))
      {
        final_warning_records = new (final_warning_record);
        final_warning_records->dyn_count = profile_count::zero ();
*************** ipa_devirt (void)
*** 3692,3699 ****
  	fprintf (dump_file, "\n\nProcesing function %s\n",
  		 n->dump_name ());
        for (e = n->indirect_calls; e; e = e->next_callee)
! 	if (e->indirect_info->polymorphic)
  	  {
  	    void *cache_token;
  	    bool final;
  
--- 3745,3763 ----
  	fprintf (dump_file, "\n\nProcesing function %s\n",
  		 n->dump_name ());
        for (e = n->indirect_calls; e; e = e->next_callee)
! 	if (!e->maybe_hot_p ())
! 	  {
! 	    if (dump_file)
! 	      fprintf (dump_file, "Call is cold\n\n");
! 	    stats.ncold++;
! 	    continue;
! 	  }
! 	else if (cgraph_polymorphic_indirect_info *pii
! 	    = dyn_cast <cgraph_polymorphic_indirect_info *> (e->indirect_info))
  	  {
+ 	    if (!pii->usable_p () || !odr_types_ptr)
+ 	      continue;
+ 
  	    void *cache_token;
  	    bool final;
  
*************** ipa_devirt (void)
*** 3713,3719 ****
  	      dump_possible_polymorphic_call_targets
  		(dump_file, e, (dump_flags & TDF_DETAILS));
  
! 	    npolymorphic++;
  
  	    /* See if the call can be devirtualized by means of ipa-prop's
  	       polymorphic call context propagation.  If not, we can just
--- 3777,3783 ----
  	      dump_possible_polymorphic_call_targets
  		(dump_file, e, (dump_flags & TDF_DETAILS));
  
! 	    stats.npolymorphic++;
  
  	    /* See if the call can be devirtualized by means of ipa-prop's
  	       polymorphic call context propagation.  If not, we can just
*************** ipa_devirt (void)
*** 3725,3737 ****
  	       This may need to be revisited once we add further ways to use
  	       the may edges, but it is a reasonable thing to do right now.  */
  
! 	    if ((e->indirect_info->param_index == -1
  		|| (!opt_for_fn (n->decl, flag_devirtualize_speculatively)
! 		    && e->indirect_info->vptr_changed))
  		&& !flag_ltrans_devirtualize)
  	      {
! 		e->indirect_info->polymorphic = false;
! 		ndropped++;
  	        if (dump_file)
  		  fprintf (dump_file, "Dropping polymorphic call info;"
  			   " it cannot be used by ipa-prop\n");
--- 3789,3801 ----
  	       This may need to be revisited once we add further ways to use
  	       the may edges, but it is a reasonable thing to do right now.  */
  
! 	    if ((pii->param_index == -1
  		|| (!opt_for_fn (n->decl, flag_devirtualize_speculatively)
! 		    && pii->vptr_changed))
  		&& !flag_ltrans_devirtualize)
  	      {
! 		pii->mark_unusable ();
! 		stats.ndropped++;
  	        if (dump_file)
  		  fprintf (dump_file, "Dropping polymorphic call info;"
  			   " it cannot be used by ipa-prop\n");
*************** ipa_devirt (void)
*** 3740,3757 ****
  	    if (!opt_for_fn (n->decl, flag_devirtualize_speculatively))
  	      continue;
  
- 	    if (!e->maybe_hot_p ())
- 	      {
- 		if (dump_file)
- 		  fprintf (dump_file, "Call is cold\n\n");
- 		ncold++;
- 		continue;
- 	      }
  	    if (e->speculative)
  	      {
  		if (dump_file)
  		  fprintf (dump_file, "Call is already speculated\n\n");
! 		nspeculated++;
  
  		/* When dumping see if we agree with speculation.  */
  		if (!dump_file)
--- 3804,3814 ----
  	    if (!opt_for_fn (n->decl, flag_devirtualize_speculatively))
  	      continue;
  
  	    if (e->speculative)
  	      {
  		if (dump_file)
  		  fprintf (dump_file, "Call is already speculated\n\n");
! 		stats.nspeculated++;
  
  		/* When dumping see if we agree with speculation.  */
  		if (!dump_file)
*************** ipa_devirt (void)
*** 3761,3767 ****
  	      {
  		if (dump_file)
  		  fprintf (dump_file, "Target list is known to be useless\n\n");
! 		nmultiple++;
  		continue;
  	      }
  	    auto_vec <cgraph_node *, 20> likely_targets;
--- 3818,3824 ----
  	      {
  		if (dump_file)
  		  fprintf (dump_file, "Target list is known to be useless\n\n");
! 		stats.nmultiple++;
  		continue;
  	      }
  	    auto_vec <cgraph_node *, 20> likely_targets;
*************** ipa_devirt (void)
*** 3774,3780 ****
  		      if (dump_file)
  			fprintf (dump_file, "More than %i likely targets\n\n",
  				 param_max_devirt_targets);
! 		      nmultiple++;
  		      break;
  		    }
  		  likely_targets.safe_push (targets[i]);
--- 3831,3837 ----
  		      if (dump_file)
  			fprintf (dump_file, "More than %i likely targets\n\n",
  				 param_max_devirt_targets);
! 		      stats.nmultiple++;
  		      break;
  		    }
  		  likely_targets.safe_push (targets[i]);
*************** ipa_devirt (void)
*** 3798,3809 ****
  		if (found)
  		  {
  		    fprintf (dump_file, "We agree with speculation\n\n");
! 		    nok++;
  		  }
  		else
  		  {
  		    fprintf (dump_file, "We disagree with speculation\n\n");
! 		    nwrong++;
  		  }
  		continue;
  	      }
--- 3855,3866 ----
  		if (found)
  		  {
  		    fprintf (dump_file, "We agree with speculation\n\n");
! 		    stats.nok++;
  		  }
  		else
  		  {
  		    fprintf (dump_file, "We disagree with speculation\n\n");
! 		    stats.nwrong++;
  		  }
  		continue;
  	      }
*************** ipa_devirt (void)
*** 3811,3852 ****
  	    unsigned speculative_id = 0;
  	    for (cgraph_node * likely_target: likely_targets)
  	      {
! 		if (!likely_target->definition)
! 		  {
! 		    if (dump_file)
! 		      fprintf (dump_file, "Target is not a definition\n\n");
! 		    nnotdefined++;
! 		    continue;
! 		  }
! 		/* Do not introduce new references to external symbols.  While we
! 		   can handle these just well, it is common for programs to
! 		   incorrectly with headers defining methods they are linked
! 		   with.  */
! 		if (DECL_EXTERNAL (likely_target->decl))
! 		  {
! 		    if (dump_file)
! 		      fprintf (dump_file, "Target is external\n\n");
! 		    nexternal++;
! 		    continue;
! 		  }
! 		/* Don't use an implicitly-declared destructor (c++/58678).  */
! 		struct cgraph_node *non_thunk_target
! 		  = likely_target->function_symbol ();
! 		if (DECL_ARTIFICIAL (non_thunk_target->decl))
! 		  {
! 		    if (dump_file)
! 		      fprintf (dump_file, "Target is artificial\n\n");
! 		    nartificial++;
! 		    continue;
! 		  }
! 		if (likely_target->get_availability () <= AVAIL_INTERPOSABLE
! 		    && likely_target->can_be_discarded_p ())
! 		  {
! 		    if (dump_file)
! 		      fprintf (dump_file, "Target is overwritable\n\n");
! 		    noverwritable++;
! 		    continue;
! 		  }
  		else if (dbg_cnt (devirt))
  		  {
  		    if (dump_enabled_p ())
--- 3868,3875 ----
  	    unsigned speculative_id = 0;
  	    for (cgraph_node * likely_target: likely_targets)
  	      {
! 		if (!devirt_target_ok_p (likely_target, &stats))
! 		  continue;
  		else if (dbg_cnt (devirt))
  		  {
  		    if (dump_enabled_p ())
*************** ipa_devirt (void)
*** 3865,3871 ****
  			  likely_target = alias;
  		      }
  		    if (first)
! 		      nconverted++;
  		    first = false;
  		    update = true;
  		    e->make_speculative
--- 3888,3894 ----
  			  likely_target = alias;
  		      }
  		    if (first)
! 		      stats.nconverted++;
  		    first = false;
  		    update = true;
  		    e->make_speculative
*************** ipa_devirt (void)
*** 3882,3891 ****
  				 speculative_id);
  	      }
  	  }
        if (update)
  	ipa_update_overall_fn_summary (n);
      }
!   if (warn_suggest_final_methods || warn_suggest_final_types)
      {
        if (warn_suggest_final_types)
  	{
--- 3905,3953 ----
  				 speculative_id);
  	      }
  	  }
+ 	else if (cgraph_simple_indirect_info *sii
+ 		 = dyn_cast <cgraph_simple_indirect_info *> (e->indirect_info))
+ 	  {
+ 	    if (!sii->fnptr_loaded_from_record
+ 		|| !opt_for_fn (n->decl,
+ 				flag_speculatively_call_stored_functions))
+ 	      continue;
+ 
+ 	    tree rec_type = sii->rec_type;
+ 	    unsigned fld_off = sii->fld_offset;
+ 	    tree likely_tgt_decl = ipa_single_noted_fnptr_in_record (rec_type,
+ 								     fld_off);
+ 	    cgraph_node *likely_tgt_node;
+ 	    if (likely_tgt_decl
+ 		&& (likely_tgt_node = cgraph_node::get (likely_tgt_decl))
+ 		&& devirt_target_ok_p (likely_tgt_node, &stats))
+ 	      {
+ 		if (!likely_tgt_node->can_be_discarded_p ())
+ 		  {
+ 		    cgraph_node *alias;
+ 		    alias = dyn_cast<cgraph_node *> (likely_tgt_node
+ 						    ->noninterposable_alias ());
+ 		    if (alias)
+ 		      likely_tgt_node = alias;
+ 		  }
+ 
+ 		if (dump_enabled_p ())
+ 		  dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, e->call_stmt,
+ 				   "speculatively turning an indirect call "
+ 				   "in %s to a direct one to %s\n",
+ 				   n->dump_name (),
+ 				   likely_tgt_node->dump_name ());
+ 
+ 		update = true;
+ 		e->make_speculative (likely_tgt_node,
+ 				     e->count.apply_scale (8, 10));
+ 	      }
+ 	  }
        if (update)
  	ipa_update_overall_fn_summary (n);
      }
!   ipa_free_noted_fnptr_calls ();
!   if (odr_types_ptr && (warn_suggest_final_methods || warn_suggest_final_types))
      {
        if (warn_suggest_final_types)
  	{
*************** ipa_devirt (void)
*** 3990,3999 ****
  	     "%i have multiple targets, %i overwritable,"
  	     " %i already speculated (%i agree, %i disagree),"
  	     " %i external, %i not defined, %i artificial, %i infos dropped\n",
! 	     npolymorphic, ndevirtualized, nconverted, ncold,
! 	     nmultiple, noverwritable, nspeculated, nok, nwrong,
! 	     nexternal, nnotdefined, nartificial, ndropped);
!   return ndevirtualized || ndropped ? TODO_remove_functions : 0;
  }
  
  namespace {
--- 4052,4063 ----
  	     "%i have multiple targets, %i overwritable,"
  	     " %i already speculated (%i agree, %i disagree),"
  	     " %i external, %i not defined, %i artificial, %i infos dropped\n",
! 	     stats.npolymorphic, stats.ndevirtualized, stats.nconverted,
! 	     stats.ncold, stats.nmultiple, stats.noverwritable,
! 	     stats.nspeculated, stats.nok, stats.nwrong,
! 	     stats.nexternal, stats.nnotdefined, stats.nartificial,
! 	     stats.ndropped);
!   return stats.ndevirtualized || stats.ndropped ? TODO_remove_functions : 0;
  }
  
  namespace {
*************** public:
*** 4034,4044 ****
  	 pass is enabled.  */
        if (in_lto_p)
  	return true;
!       return (flag_devirtualize
! 	      && (flag_devirtualize_speculatively
! 		  || (warn_suggest_final_methods
! 		      || warn_suggest_final_types))
! 	      && optimize);
      }
  
    unsigned int execute (function *) final override { return ipa_devirt (); }
--- 4098,4109 ----
  	 pass is enabled.  */
        if (in_lto_p)
  	return true;
!       return (optimize
! 	      && ((flag_devirtualize
! 		   && (flag_devirtualize_speculatively
! 		       || (warn_suggest_final_methods
! 			   || warn_suggest_final_types)))
! 		  || flag_speculatively_call_stored_functions));
      }
  
    unsigned int execute (function *) final override { return ipa_devirt (); }
diff -Nrcpad gcc-16-20251214/gcc/ipa-inline.cc gcc-16-20251221/gcc/ipa-inline.cc
*** gcc-16-20251214/gcc/ipa-inline.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/ipa-inline.cc	Sun Dec 21 22:32:07 2025
*************** dump_inline_stats (void)
*** 2758,2764 ****
  	  }
        }
      for (e = node->indirect_calls; e; e = e->next_callee)
!       if (e->indirect_info->polymorphic
  	  & e->count.ipa ().initialized_p ())
  	indirect_poly_cnt += e->count.ipa ().to_gcov_type ();
        else if (e->count.ipa ().initialized_p ())
--- 2758,2764 ----
  	  }
        }
      for (e = node->indirect_calls; e; e = e->next_callee)
!       if (is_a <cgraph_polymorphic_indirect_info *> (e->indirect_info)
  	  & e->count.ipa ().initialized_p ())
  	indirect_poly_cnt += e->count.ipa ().to_gcov_type ();
        else if (e->count.ipa ().initialized_p ())
diff -Nrcpad gcc-16-20251214/gcc/ipa-param-manipulation.cc gcc-16-20251221/gcc/ipa-param-manipulation.cc
*** gcc-16-20251214/gcc/ipa-param-manipulation.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/ipa-param-manipulation.cc	Sun Dec 21 22:32:07 2025
*************** push_function_arg_decls (vec<tree> *args
*** 155,161 ****
  
    /* Safety check that we do not attempt to use the function in WPA, except
       when the function is a thunk and then we have DECL_ARGUMENTS or when we
!      have already explicitely loaded its body.  */
    gcc_assert (!flag_wpa
  	      || DECL_ARGUMENTS (fndecl)
  	      || gimple_has_body_p (fndecl));
--- 155,161 ----
  
    /* Safety check that we do not attempt to use the function in WPA, except
       when the function is a thunk and then we have DECL_ARGUMENTS or when we
!      have already explicitly loaded its body.  */
    gcc_assert (!flag_wpa
  	      || DECL_ARGUMENTS (fndecl)
  	      || gimple_has_body_p (fndecl));
diff -Nrcpad gcc-16-20251214/gcc/ipa-profile.cc gcc-16-20251221/gcc/ipa-profile.cc
*** gcc-16-20251214/gcc/ipa-profile.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/ipa-profile.cc	Sun Dec 21 22:32:07 2025
*************** ipa_profile (void)
*** 921,927 ****
  				     "Not speculating: "
  				     "parameter count mismatch\n");
  			}
! 		      else if (e->indirect_info->polymorphic
  			       && !opt_for_fn (n->decl, flag_devirtualize)
  			       && !possible_polymorphic_call_target_p (e, n2))
  			{
--- 921,927 ----
  				     "Not speculating: "
  				     "parameter count mismatch\n");
  			}
! 		      else if (usable_polymorphic_info_p (e->indirect_info)
  			       && !opt_for_fn (n->decl, flag_devirtualize)
  			       && !possible_polymorphic_call_target_p (e, n2))
  			{
diff -Nrcpad gcc-16-20251214/gcc/ipa-prop.cc gcc-16-20251221/gcc/ipa-prop.cc
*** gcc-16-20251214/gcc/ipa-prop.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/ipa-prop.cc	Sun Dec 21 22:32:07 2025
*************** public:
*** 283,288 ****
--- 283,331 ----
    }
  };
  
+ /* Structure holding the information that all stores to FLD_OFFSET (measured in
+    bytes) of a particular record type REC_TYPE was storing a pointer to
+    function FN or that there were multiple functions, which is denoted by fn
+    being nullptr. */
+ 
+ struct GTY((for_user)) noted_fnptr_store
+ {
+   tree rec_type;
+   tree fn;
+   unsigned fld_offset;
+ };
+ 
+ /* Hash traits to have a hash table of noted_fnptr_stores.  */
+ 
+ struct noted_fnptr_hasher : ggc_ptr_hash <noted_fnptr_store>
+ {
+   static hashval_t hash (noted_fnptr_store *);
+   static bool equal (noted_fnptr_store *,
+ 		     noted_fnptr_store *);
+ };
+ 
+ hashval_t
+ noted_fnptr_hasher::hash (noted_fnptr_store *val)
+ {
+   return iterative_hash_host_wide_int (val->fld_offset,
+ 				       TYPE_UID (val->rec_type));
+ }
+ 
+ bool
+ noted_fnptr_hasher::equal (noted_fnptr_store *v1,
+ 			   noted_fnptr_store *v2)
+ {
+   return (v1->rec_type == v2->rec_type
+ 	  && v1->fld_offset == v2->fld_offset);
+ }
+ 
+ 
+ /* Structore holding the information that all stores to OFFSET of a particular
+    record type RECTYPE was storing a pointer to specific function or that there
+    were multiple such functions. */
+ 
+ static GTY(()) hash_table <noted_fnptr_hasher> *noted_fnptrs_in_records;
+ 
  /* Variable hoding the return value summary.  */
  static GTY(()) function_summary <ipa_return_value_summary *> *ipa_return_value_sum;
  
*************** ipa_print_node_jump_functions (FILE *f,
*** 599,619 ****
  
    for (cs = node->indirect_calls; cs; cs = cs->next_callee)
      {
!       class cgraph_indirect_call_info *ii;
! 
!       ii = cs->indirect_info;
!       if (ii->agg_contents)
! 	fprintf (f, "    indirect %s callsite, calling param %i, "
! 		 "offset " HOST_WIDE_INT_PRINT_DEC ", %s",
! 		 ii->member_ptr ? "member ptr" : "aggregate",
! 		 ii->param_index, ii->offset,
! 		 ii->by_ref ? "by reference" : "by_value");
!       else
! 	fprintf (f, "    indirect %s callsite, calling param %i, "
! 		 "offset " HOST_WIDE_INT_PRINT_DEC,
! 		 ii->polymorphic ? "polymorphic" : "simple", ii->param_index,
! 		 ii->offset);
! 
        if (cs->call_stmt)
  	{
  	  fprintf (f, ", for stmt ");
--- 642,649 ----
  
    for (cs = node->indirect_calls; cs; cs = cs->next_callee)
      {
!       fprintf (f, "    ");
!       cs->indirect_info->dump (f, false);
        if (cs->call_stmt)
  	{
  	  fprintf (f, ", for stmt ");
*************** ipa_print_node_jump_functions (FILE *f,
*** 621,628 ****
  	}
        else
  	fprintf (f, "\n");
-       if (ii->polymorphic)
- 	ii->context.dump (f);
        if (!ipa_edge_args_info_available_for_edge_p (cs))
  	fprintf (f, "       no arg info\n");
        else
--- 651,656 ----
*************** ipa_compute_jump_functions_for_bb (struc
*** 2706,2711 ****
--- 2734,2794 ----
      }
  }
  
+ /* If REF is a memory access that loads a function pointer (but not a method
+    pointer) from a RECORD_TYPE, return true and store the type of the RECORD to
+    *REC_TYPE and the byte offset of the field to *FLD_OFFSET.  Otherwise return
+    false.  OHS es the "other hand side" which is used to check type
+    compatibility with field in question, when possible.  */
+ 
+ static bool
+ is_func_ptr_from_record (tree ref, tree *rec_type, unsigned *fld_offset,
+ 			 tree ohs)
+ {
+   if (!POINTER_TYPE_P (TREE_TYPE (ref))
+       || TREE_CODE (TREE_TYPE (TREE_TYPE (ref))) != FUNCTION_TYPE)
+     return false;
+ 
+   if (TREE_CODE (ref) == COMPONENT_REF
+       && TREE_CODE (TREE_TYPE (TREE_OPERAND (ref, 0))) == RECORD_TYPE)
+     {
+       gcc_assert (POINTER_TYPE_P (TREE_TYPE (ohs)));
+       ohs = TREE_TYPE (TREE_TYPE (ohs));
+       tree ftype = TREE_TYPE (TREE_OPERAND (ref, 1));
+       if (!POINTER_TYPE_P (ftype))
+ 	return false;
+       ftype = TREE_TYPE (ftype);
+       if (!types_compatible_p (ohs, ftype))
+ 	return false;
+ 
+       tree tree_off = bit_position (TREE_OPERAND (ref, 1));
+       if (!tree_fits_shwi_p (tree_off))
+ 	return false;
+       HOST_WIDE_INT bit_offset = tree_to_shwi (tree_off);
+       if (bit_offset % BITS_PER_UNIT)
+ 	return false;
+       HOST_WIDE_INT unit_offset = bit_offset / BITS_PER_UNIT;
+       if (unit_offset > UINT_MAX)
+ 	return false;
+       *rec_type = TREE_TYPE (TREE_OPERAND (ref, 0));
+       *fld_offset = unit_offset;
+       return true;
+     }
+   else if (TREE_CODE (ref) == MEM_REF
+ 	   && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (ref, 0)))
+ 	   && (TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (ref, 0))))
+ 	       == RECORD_TYPE)
+ 	   && tree_fits_shwi_p (TREE_OPERAND (ref, 1)))
+     {
+       HOST_WIDE_INT unit_offset = tree_to_shwi (TREE_OPERAND (ref, 1));
+       if (unit_offset > UINT_MAX)
+ 	return false;
+       *rec_type = TREE_TYPE (TREE_TYPE (TREE_OPERAND (ref, 0)));
+       *fld_offset = unit_offset;
+       return true;
+     }
+   return false;
+ }
+ 
  /* If STMT looks like a statement loading a value from a member pointer formal
     parameter, return that parameter and store the offset of the field to
     *OFFSET_P, if it is non-NULL.  Otherwise return NULL (but *OFFSET_P still
*************** ipa_is_ssa_with_stmt_def (tree t)
*** 2790,2818 ****
      return false;
  }
  
- /* Find the indirect call graph edge corresponding to STMT and mark it as a
-    call to a parameter number PARAM_INDEX.  NODE is the caller.  Return the
-    indirect call graph edge.
-    If POLYMORPHIC is true record is as a destination of polymorphic call.  */
- 
- static struct cgraph_edge *
- ipa_note_param_call (struct cgraph_node *node, int param_index,
- 		     gcall *stmt, bool polymorphic)
- {
-   struct cgraph_edge *cs;
- 
-   cs = node->get_edge (stmt);
-   cs->indirect_info->param_index = param_index;
-   cs->indirect_info->agg_contents = 0;
-   cs->indirect_info->member_ptr = 0;
-   cs->indirect_info->guaranteed_unmodified = 0;
-   ipa_node_params *info = ipa_node_params_sum->get (node);
-   ipa_set_param_used_by_indirect_call (info, param_index, true);
-   if (cs->indirect_info->polymorphic || polymorphic)
-     ipa_set_param_used_by_polymorphic_call (info, param_index, true);
-   return cs;
- }
- 
  /* Analyze the CALL and examine uses of formal parameters of the caller NODE
     (described by INFO).  PARMS_AINFO is a pointer to a vector containing
     intermediate information about each formal parameter.  Currently it checks
--- 2873,2878 ----
*************** ipa_analyze_indirect_call_uses (struct i
*** 2886,2910 ****
        tree var = SSA_NAME_VAR (target);
        int index = ipa_get_param_decl_index (info, var);
        if (index >= 0)
! 	ipa_note_param_call (fbi->node, index, call, false);
        return;
      }
  
    int index;
    gimple *def = SSA_NAME_DEF_STMT (target);
    bool guaranteed_unmodified;
!   if (gimple_assign_single_p (def)
!       && ipa_load_from_parm_agg (fbi, info->descriptors, def,
! 				 gimple_assign_rhs1 (def), &index, &offset,
! 				 NULL, &by_ref, &guaranteed_unmodified))
      {
!       struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index,
! 	 					    call, false);
!       cs->indirect_info->offset = offset;
!       cs->indirect_info->agg_contents = 1;
!       cs->indirect_info->by_ref = by_ref;
!       cs->indirect_info->guaranteed_unmodified = guaranteed_unmodified;
!       return;
      }
  
    /* Now we need to try to match the complex pattern of calling a member
--- 2946,2991 ----
        tree var = SSA_NAME_VAR (target);
        int index = ipa_get_param_decl_index (info, var);
        if (index >= 0)
! 	{
! 	  cgraph_edge *cs = fbi->node->get_edge (call);
! 	  cgraph_simple_indirect_info *sii =
! 	    as_a <cgraph_simple_indirect_info *> (cs->indirect_info);
! 	  sii->param_index = index;
! 	  gcc_assert (!sii->agg_contents && !sii->member_ptr);
! 	  ipa_set_param_used_by_indirect_call (info, index, true);
! 	}
        return;
      }
  
    int index;
    gimple *def = SSA_NAME_DEF_STMT (target);
    bool guaranteed_unmodified;
!   if (gimple_assign_single_p (def))
      {
!       cgraph_edge *cs = fbi->node->get_edge (call);
!       cgraph_simple_indirect_info *sii =
! 	as_a <cgraph_simple_indirect_info *> (cs->indirect_info);
!       tree rectype;
!       unsigned fldoff;
!       if (is_func_ptr_from_record (gimple_assign_rhs1 (def), &rectype, &fldoff,
! 				   target))
! 	{
! 	  sii->fnptr_loaded_from_record = 1;
! 	  sii->fld_offset = fldoff;
! 	  sii->rec_type = rectype;
! 	}
!       if (ipa_load_from_parm_agg (fbi, info->descriptors, def,
! 				  gimple_assign_rhs1 (def), &index, &offset,
! 				  NULL, &by_ref, &guaranteed_unmodified))
! 	{
! 	  sii->param_index = index;
! 	  sii->offset = offset;
! 	  sii->agg_contents = 1;
! 	  sii->by_ref = by_ref;
! 	  sii->guaranteed_unmodified = guaranteed_unmodified;
! 	  ipa_set_param_used_by_indirect_call (info, index, true);
! 	  return;
! 	}
      }
  
    /* Now we need to try to match the complex pattern of calling a member
*************** ipa_analyze_indirect_call_uses (struct i
*** 3027,3040 ****
        by_ref = false;
      }
  
!   struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index,
! 						call, false);
!   cs->indirect_info->offset = offset;
!   cs->indirect_info->agg_contents = 1;
!   cs->indirect_info->member_ptr = 1;
!   cs->indirect_info->by_ref = by_ref;
!   cs->indirect_info->guaranteed_unmodified = 1;
! 
    return;
  }
  
--- 3108,3123 ----
        by_ref = false;
      }
  
!   cgraph_edge *cs = fbi->node->get_edge (call);
!   cgraph_simple_indirect_info *sii =
!     as_a <cgraph_simple_indirect_info *> (cs->indirect_info);
!   sii->param_index = index;
!   sii->offset = offset;
!   sii->agg_contents = 1;
!   sii->member_ptr = 1;
!   sii->by_ref = by_ref;
!   sii->guaranteed_unmodified = 1;
!   ipa_set_param_used_by_indirect_call (info, index, true);
    return;
  }
  
*************** ipa_analyze_virtual_call_uses (struct ip
*** 3086,3098 ****
  	return;
      }
  
!   struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index,
!      						call, true);
!   class cgraph_indirect_call_info *ii = cs->indirect_info;
!   ii->offset = anc_offset;
!   ii->otr_token = tree_to_uhwi (OBJ_TYPE_REF_TOKEN (target));
!   ii->otr_type = obj_type_ref_class (target);
!   ii->polymorphic = 1;
  }
  
  /* Analyze a call statement CALL whether and how it utilizes formal parameters
--- 3169,3183 ----
  	return;
      }
  
!   cgraph_edge *cs = fbi->node->get_edge (call);
!   cgraph_polymorphic_indirect_info *pii =
!     as_a <cgraph_polymorphic_indirect_info *> (cs->indirect_info);
!   pii->param_index = index;
!   pii->offset = anc_offset;
!   gcc_assert (pii->otr_token == tree_to_shwi (OBJ_TYPE_REF_TOKEN (target)));
!   gcc_assert (pii->otr_type = obj_type_ref_class (target));
!   ipa_set_param_used_by_indirect_call (info, index, true);
!   ipa_set_param_used_by_polymorphic_call (info, index, true);
  }
  
  /* Analyze a call statement CALL whether and how it utilizes formal parameters
*************** ipa_analyze_call_uses (struct ipa_func_b
*** 3115,3138 ****
    if (cs && !cs->indirect_unknown_callee)
      return;
  
!   if (cs->indirect_info->polymorphic && flag_devirtualize)
      {
        tree instance;
        tree target = gimple_call_fn (call);
        ipa_polymorphic_call_context context (current_function_decl,
  					    target, call, &instance);
  
!       gcc_checking_assert (cs->indirect_info->otr_type
! 			   == obj_type_ref_class (target));
!       gcc_checking_assert (cs->indirect_info->otr_token
  			   == tree_to_shwi (OBJ_TYPE_REF_TOKEN (target)));
  
!       cs->indirect_info->vptr_changed
  	= !context.get_dynamic_type (instance,
  				     OBJ_TYPE_REF_OBJECT (target),
  				     obj_type_ref_class (target), call,
  				     &fbi->aa_walk_budget);
!       cs->indirect_info->context = context;
      }
  
    if (TREE_CODE (target) == SSA_NAME)
--- 3200,3225 ----
    if (cs && !cs->indirect_unknown_callee)
      return;
  
!   cgraph_polymorphic_indirect_info *pii;
!   if (flag_devirtualize
!       && (pii
! 	  = dyn_cast <cgraph_polymorphic_indirect_info *> (cs->indirect_info)))
      {
        tree instance;
        tree target = gimple_call_fn (call);
        ipa_polymorphic_call_context context (current_function_decl,
  					    target, call, &instance);
  
!       gcc_checking_assert (pii->otr_type == obj_type_ref_class (target));
!       gcc_checking_assert (pii->otr_token
  			   == tree_to_shwi (OBJ_TYPE_REF_TOKEN (target)));
  
!       pii->vptr_changed
  	= !context.get_dynamic_type (instance,
  				     OBJ_TYPE_REF_OBJECT (target),
  				     obj_type_ref_class (target), call,
  				     &fbi->aa_walk_budget);
!       pii->context = context;
      }
  
    if (TREE_CODE (target) == SSA_NAME)
*************** ipa_analyze_call_uses (struct ipa_func_b
*** 3141,3156 ****
      ipa_analyze_virtual_call_uses (fbi, call, target);
  }
  
  
  /* Analyze the call statement STMT with respect to formal parameters (described
!    in INFO) of caller given by FBI->NODE.  Currently it only checks whether
!    formal parameters are called.  */
  
  static void
  ipa_analyze_stmt_uses (struct ipa_func_body_info *fbi, gimple *stmt)
  {
    if (is_gimple_call (stmt))
      ipa_analyze_call_uses (fbi, as_a <gcall *> (stmt));
  }
  
  /* Callback of walk_stmt_load_store_addr_ops for the visit_load.
--- 3228,3357 ----
      ipa_analyze_virtual_call_uses (fbi, call, target);
  }
  
+ /* Store that that there was a store of FN to a record of type REC_TYPE and
+    FLD_OFFSET.  */
+ 
+ static void
+ note_fnptr_in_record (tree rec_type, unsigned fld_offset, tree fn)
+ {
+   gcc_assert (TREE_CODE (fn) == FUNCTION_DECL);
+   gcc_assert (TREE_CODE (rec_type) == RECORD_TYPE);
+   if (!noted_fnptrs_in_records)
+     noted_fnptrs_in_records = hash_table<noted_fnptr_hasher>::create_ggc (37);
+ 
+   noted_fnptr_store repr;
+   repr.rec_type = rec_type;
+   repr.fld_offset = fld_offset;
+ 
+   noted_fnptr_store **slot = noted_fnptrs_in_records->find_slot (&repr,
+ 								NO_INSERT);
+   if (slot)
+     {
+       if ((*slot)->fn && (*slot)->fn != fn)
+ 	(*slot)->fn = nullptr;
+       return;
+     }
+ 
+   slot = noted_fnptrs_in_records->find_slot (&repr, INSERT);
+   *slot = ggc_cleared_alloc<noted_fnptr_store> ();
+   (*slot)->rec_type = rec_type;
+   (*slot)->fn = fn;
+   (*slot)->fld_offset = fld_offset;
+ 
+   return;
+ }
+ 
+ /* Dump contents of noted_fnptrs_in_records to F in humad readable form.  */
+ 
+ void DEBUG_FUNCTION
+ ipa_dump_noted_record_fnptrs (FILE *f)
+ {
+   if (!noted_fnptrs_in_records)
+     {
+       fprintf (f, "No noted function pointers stored in records.\n\n");
+       return;
+     }
+ 
+   fprintf (f, "Noted function pointers stored in records:\n");
+   for (auto iter = noted_fnptrs_in_records->begin ();
+        iter != noted_fnptrs_in_records->end ();
+        ++iter)
+     {
+       const noted_fnptr_store *elem = *iter;
+       fprintf (f, "  Type:");
+       print_generic_expr (f, elem->rec_type);
+       fprintf (f, ", offset %ul, function: ", elem->fld_offset);
+       print_generic_expr (f, elem->fn);
+       fprintf (f, "\n");
+     }
+   fprintf (f, "\n");
+ }
+ 
+ /* Dump contents of noted_fnptrs_in_records to stderr in humad readable
+    form.  */
+ 
+ void DEBUG_FUNCTION
+ ipa_debug_noted_record_fnptrs (void)
+ {
+   ipa_dump_noted_record_fnptrs (stderr);
+ }
+ 
+ 
+ /* If we have noticed a single function pointer stored into a record of type
+    REC_TYPE at the given FLD_OFFSET (measured in bytes), return its
+    declaration.  Otherwise return NULL_TREE.  */
+ 
+ tree
+ ipa_single_noted_fnptr_in_record (tree rec_type, unsigned fld_offset)
+ {
+   if (!noted_fnptrs_in_records)
+     return NULL_TREE;
+ 
+   noted_fnptr_store repr;
+   repr.rec_type = rec_type;
+   repr.fld_offset = fld_offset;
+ 
+   noted_fnptr_store **slot = noted_fnptrs_in_records->find_slot (&repr,
+ 								NO_INSERT);
+   if (!slot)
+     return NULL_TREE;
+   return (*slot)->fn;
+ }
+ 
+ /* Free the hash table storing the information about function pointers stored
+    to a particular position in record typed strucutres.  */
+ 
+ void
+ ipa_free_noted_fnptr_calls ()
+ {
+   if (noted_fnptrs_in_records)
+     {
+       noted_fnptrs_in_records->empty ();
+       noted_fnptrs_in_records = nullptr;
+     }
+ }
  
  /* Analyze the call statement STMT with respect to formal parameters (described
!    in INFO) of caller given by FBI->NODE.  Also note any stores of function
!    pointers to record typed memory.   */
  
  static void
  ipa_analyze_stmt_uses (struct ipa_func_body_info *fbi, gimple *stmt)
  {
    if (is_gimple_call (stmt))
      ipa_analyze_call_uses (fbi, as_a <gcall *> (stmt));
+   else if (gimple_assign_single_p (stmt)
+ 	   && TREE_CODE (gimple_assign_rhs1 (stmt)) == ADDR_EXPR
+ 	   && (TREE_CODE (TREE_OPERAND (gimple_assign_rhs1 (stmt), 0))
+ 	       == FUNCTION_DECL))
+     {
+       tree rec_type;
+       unsigned fld_offset;
+       if (is_func_ptr_from_record (gimple_assign_lhs (stmt), &rec_type,
+ 				   &fld_offset, gimple_assign_rhs1 (stmt)))
+ 	note_fnptr_in_record (rec_type, fld_offset,
+ 			      TREE_OPERAND (gimple_assign_rhs1 (stmt), 0));
+     }
  }
  
  /* Callback of walk_stmt_load_store_addr_ops for the visit_load.
*************** ipa_analyze_node (struct cgraph_node *no
*** 3413,3418 ****
--- 3614,3654 ----
    pop_cfun ();
  }
  
+ /* Analyze NODE and note any function pointers in record-typed static
+    initializers.
+ 
+    TODO: The current implementation does not traverse the initializers to scan
+    records nested inside other types.  It should catch the most basic way of
+    writing "virtual functions" in C but can be extended, of course.
+ */
+ 
+ void
+ ipa_analyze_var_static_initializer (varpool_node *node)
+ {
+   tree decl = node->decl;
+   tree rec_type = TREE_TYPE (decl);
+   if (TREE_CODE (rec_type) != RECORD_TYPE
+       || TREE_CODE (DECL_INITIAL (decl)) != CONSTRUCTOR)
+     return;
+ 
+   unsigned ix;
+   tree index, val;
+   FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (DECL_INITIAL (decl)), ix, index,
+ 			    val)
+     {
+       if (TREE_CODE (val) != ADDR_EXPR
+ 	  || TREE_CODE (TREE_OPERAND (val, 0)) != FUNCTION_DECL)
+ 	continue;
+       HOST_WIDE_INT elt_offset = int_bit_position (index);
+       if ((elt_offset % BITS_PER_UNIT) != 0)
+ 	continue;
+       elt_offset = elt_offset / BITS_PER_UNIT;
+       if (elt_offset > UINT_MAX)
+ 	continue;
+       note_fnptr_in_record (rec_type, elt_offset, TREE_OPERAND (val, 0));
+     }
+ }
+ 
  /* Update the jump functions associated with call graph edge E when the call
     graph edge CS is being inlined, assuming that E->caller is already (possibly
     indirectly) inlined into CS->callee and that E has not been inlined.  */
*************** ipa_make_edge_direct_to_target (struct c
*** 3755,3770 ****
        target = canonicalize_constructor_val (target, NULL);
        if (!target || TREE_CODE (target) != FUNCTION_DECL)
  	{
  	  /* Member pointer call that goes through a VMT lookup.  */
! 	  if (ie->indirect_info->member_ptr
  	      /* Or if target is not an invariant expression and we do not
  		 know if it will evaulate to function at runtime.
  		 This can happen when folding through &VAR, where &VAR
  		 is IP invariant, but VAR itself is not.
  
! 		 TODO: Revisit this when GCC 5 is branched.  It seems that
! 		 member_ptr check is not needed and that we may try to fold
! 		 the expression and see if VAR is readonly.  */
  	      || !is_gimple_ip_invariant (target))
  	    {
  	      if (dump_enabled_p ())
--- 3991,4007 ----
        target = canonicalize_constructor_val (target, NULL);
        if (!target || TREE_CODE (target) != FUNCTION_DECL)
  	{
+ 	  cgraph_simple_indirect_info *sii
+ 	    = dyn_cast <cgraph_simple_indirect_info *> (ie->indirect_info);
  	  /* Member pointer call that goes through a VMT lookup.  */
! 	  if ((sii && sii->member_ptr)
  	      /* Or if target is not an invariant expression and we do not
  		 know if it will evaulate to function at runtime.
  		 This can happen when folding through &VAR, where &VAR
  		 is IP invariant, but VAR itself is not.
  
! 		 TODO: It seems that we may try to fold the expression and see
! 		 if VAR is readonly.  */
  	      || !is_gimple_ip_invariant (target))
  	    {
  	      if (dump_enabled_p ())
*************** ipa_make_edge_direct_to_target (struct c
*** 3795,3801 ****
    else
      callee = cgraph_node::get (target);
  
!   /* Because may-edges are not explicitely represented and vtable may be external,
       we may create the first reference to the object in the unit.  */
    if (!callee || callee->inlined_to)
      {
--- 4032,4038 ----
    else
      callee = cgraph_node::get (target);
  
!   /* Because may-edges are not explicitly represented and vtable may be external,
       we may create the first reference to the object in the unit.  */
    if (!callee || callee->inlined_to)
      {
*************** ipa_make_edge_direct_to_target (struct c
*** 3857,3863 ****
      {
        fprintf (dump_file, "ipa-prop: Discovered %s call to a %s target "
  	       "(%s -> %s), for stmt ",
! 	       ie->indirect_info->polymorphic ? "a virtual" : "an indirect",
  	       speculative ? "speculative" : "known",
  	       ie->caller->dump_name (),
  	       callee->dump_name ());
--- 4094,4101 ----
      {
        fprintf (dump_file, "ipa-prop: Discovered %s call to a %s target "
  	       "(%s -> %s), for stmt ",
! 	       is_a <cgraph_polymorphic_indirect_info *> (ie->indirect_info)
! 	       ? "a virtual" : "an indirect",
  	       speculative ? "speculative" : "known",
  	       ie->caller->dump_name (),
  	       callee->dump_name ());
*************** try_make_edge_direct_simple_call (struct
*** 4114,4139 ****
  				  struct cgraph_node *new_root,
  				  class ipa_node_params *new_root_info)
  {
-   struct cgraph_edge *cs;
    tree target = NULL_TREE;
!   bool agg_contents = ie->indirect_info->agg_contents;
    tree scalar = ipa_value_from_jfunc (new_root_info, jfunc, target_type);
    if (agg_contents)
      {
        if (scalar)
! 	target = ipa_find_agg_cst_from_init (scalar, ie->indirect_info->offset,
! 					     ie->indirect_info->by_ref);
!       if (!target && ie->indirect_info->guaranteed_unmodified)
  	target = ipa_find_agg_cst_from_jfunc_items (&jfunc->agg, new_root_info,
! 						    new_root,
! 						    ie->indirect_info->offset,
! 						    ie->indirect_info->by_ref);
      }
    else
      target = scalar;
    if (!target)
      return NULL;
!   cs = ipa_make_edge_direct_to_target (ie, target);
  
    if (cs && !agg_contents)
      {
--- 4352,4376 ----
  				  struct cgraph_node *new_root,
  				  class ipa_node_params *new_root_info)
  {
    tree target = NULL_TREE;
!   cgraph_simple_indirect_info *sii
!     = as_a <cgraph_simple_indirect_info *> (ie->indirect_info);
!   bool agg_contents = sii->agg_contents;
    tree scalar = ipa_value_from_jfunc (new_root_info, jfunc, target_type);
    if (agg_contents)
      {
        if (scalar)
! 	target = ipa_find_agg_cst_from_init (scalar, sii->offset, sii->by_ref);
!       if (!target && sii->guaranteed_unmodified)
  	target = ipa_find_agg_cst_from_jfunc_items (&jfunc->agg, new_root_info,
! 						    new_root, sii->offset,
! 						    sii->by_ref);
      }
    else
      target = scalar;
    if (!target)
      return NULL;
!   cgraph_edge *cs = ipa_make_edge_direct_to_target (ie, target);
  
    if (cs && !agg_contents)
      {
*************** try_make_edge_direct_virtual_call (struc
*** 4193,4203 ****
  
    if (!opt_for_fn (ie->caller->decl, flag_devirtualize))
      return NULL;
! 
!   gcc_assert (!ie->indirect_info->by_ref);
  
    /* Try to do lookup via known virtual table pointer value.  */
!   if (!ie->indirect_info->vptr_changed
        || opt_for_fn (ie->caller->decl, flag_devirtualize_speculatively))
      {
        tree vtable;
--- 4430,4442 ----
  
    if (!opt_for_fn (ie->caller->decl, flag_devirtualize))
      return NULL;
!   cgraph_polymorphic_indirect_info *pii
!     = as_a <cgraph_polymorphic_indirect_info *> (ie->indirect_info);
!   if (!pii->usable_p ())
!     return nullptr;
  
    /* Try to do lookup via known virtual table pointer value.  */
!   if (!pii->vptr_changed
        || opt_for_fn (ie->caller->decl, flag_devirtualize_speculatively))
      {
        tree vtable;
*************** try_make_edge_direct_virtual_call (struc
*** 4205,4220 ****
        tree t = NULL_TREE;
        if (jfunc->type == IPA_JF_CONST)
  	t = ipa_find_agg_cst_from_init (ipa_get_jf_constant (jfunc),
! 					ie->indirect_info->offset, true);
        if (!t)
  	t = ipa_find_agg_cst_from_jfunc_items (&jfunc->agg, new_root_info,
! 					       new_root,
! 					       ie->indirect_info->offset, true);
        if (t && vtable_pointer_value_to_vtable (t, &vtable, &offset))
  	{
  	  bool can_refer;
! 	  t = gimple_get_virt_method_for_vtable (ie->indirect_info->otr_token,
! 						 vtable, offset, &can_refer);
  	  if (can_refer)
  	    {
  	      if (!t
--- 4444,4458 ----
        tree t = NULL_TREE;
        if (jfunc->type == IPA_JF_CONST)
  	t = ipa_find_agg_cst_from_init (ipa_get_jf_constant (jfunc),
! 					pii->offset, true);
        if (!t)
  	t = ipa_find_agg_cst_from_jfunc_items (&jfunc->agg, new_root_info,
! 					       new_root, pii->offset, true);
        if (t && vtable_pointer_value_to_vtable (t, &vtable, &offset))
  	{
  	  bool can_refer;
! 	  t = gimple_get_virt_method_for_vtable (pii->otr_token, vtable, offset,
! 						 &can_refer);
  	  if (can_refer)
  	    {
  	      if (!t
*************** try_make_edge_direct_virtual_call (struc
*** 4224,4230 ****
  		       (ie, cgraph_node::get (t)))
  		{
  		  /* Do not speculate builtin_unreachable, it is stupid!  */
! 		  if (!ie->indirect_info->vptr_changed)
  		    target = ipa_impossible_devirt_target (ie, target);
  		  else
  		    target = NULL;
--- 4462,4468 ----
  		       (ie, cgraph_node::get (t)))
  		{
  		  /* Do not speculate builtin_unreachable, it is stupid!  */
! 		  if (!pii->vptr_changed)
  		    target = ipa_impossible_devirt_target (ie, target);
  		  else
  		    target = NULL;
*************** try_make_edge_direct_virtual_call (struc
*** 4232,4238 ****
  	      else
  		{
  		  target = t;
! 		  speculative = ie->indirect_info->vptr_changed;
  		}
  	    }
  	}
--- 4470,4476 ----
  	      else
  		{
  		  target = t;
! 		  speculative = pii->vptr_changed;
  		}
  	    }
  	}
*************** try_make_edge_direct_virtual_call (struc
*** 4242,4256 ****
    vec <cgraph_node *>targets;
    bool final;
  
!   ctx.offset_by (ie->indirect_info->offset);
!   if (ie->indirect_info->vptr_changed)
      ctx.possible_dynamic_type_change (ie->in_polymorphic_cdtor,
! 				      ie->indirect_info->otr_type);
!   ctx.combine_with (ie_context, ie->indirect_info->otr_type);
!   targets = possible_polymorphic_call_targets
!     (ie->indirect_info->otr_type,
!      ie->indirect_info->otr_token,
!      ctx, &final);
    if (final && targets.length () <= 1)
      {
        speculative = false;
--- 4480,4492 ----
    vec <cgraph_node *>targets;
    bool final;
  
!   ctx.offset_by (pii->offset);
!   if (pii->vptr_changed)
      ctx.possible_dynamic_type_change (ie->in_polymorphic_cdtor,
! 				      pii->otr_type);
!   ctx.combine_with (ie_context, pii->otr_type);
!   targets = possible_polymorphic_call_targets (pii->otr_type, pii->otr_token,
! 					       ctx, &final);
    if (final && targets.length () <= 1)
      {
        speculative = false;
*************** try_make_edge_direct_virtual_call (struc
*** 4259,4271 ****
        else
  	target = ipa_impossible_devirt_target (ie, NULL_TREE);
      }
!   else if (!target && opt_for_fn (ie->caller->decl, flag_devirtualize_speculatively)
  	   && !ie->speculative && ie->maybe_hot_p ())
      {
        cgraph_node *n;
!       n = try_speculative_devirtualization (ie->indirect_info->otr_type,
! 					    ie->indirect_info->otr_token,
! 					    ie->indirect_info->context);
        if (n)
  	{
  	  target = n->decl;
--- 4495,4507 ----
        else
  	target = ipa_impossible_devirt_target (ie, NULL_TREE);
      }
!   else if (!target && opt_for_fn (ie->caller->decl,
! 				  flag_devirtualize_speculatively)
  	   && !ie->speculative && ie->maybe_hot_p ())
      {
        cgraph_node *n;
!       n = try_speculative_devirtualization (pii->otr_type, pii->otr_token,
! 					    pii->context);
        if (n)
  	{
  	  target = n->decl;
*************** update_indirect_edges_after_inlining (st
*** 4299,4337 ****
  				      struct cgraph_node *node,
  				      vec<cgraph_edge *> *new_edges)
  {
-   class ipa_edge_args *top;
-   struct cgraph_edge *ie, *next_ie, *new_direct_edge;
-   struct cgraph_node *new_root;
-   class ipa_node_params *new_root_info, *inlined_node_info;
    bool res = false;
  
    ipa_check_create_edge_args ();
!   top = ipa_edge_args_sum->get (cs);
!   new_root = cs->caller->inlined_to
! 		? cs->caller->inlined_to : cs->caller;
!   new_root_info = ipa_node_params_sum->get (new_root);
!   inlined_node_info = ipa_node_params_sum->get (cs->callee->function_symbol ());
  
!   for (ie = node->indirect_calls; ie; ie = next_ie)
      {
-       class cgraph_indirect_call_info *ici = ie->indirect_info;
-       struct ipa_jump_func *jfunc;
-       int param_index;
- 
        next_ie = ie->next_callee;
  
!       if (ici->param_index == -1)
! 	continue;
! 
!       /* We must check range due to calls with variable number of arguments:  */
!       if (!top || ici->param_index >= ipa_get_cs_argument_count (top))
  	{
! 	  ici->param_index = -1;
  	  continue;
  	}
  
!       param_index = ici->param_index;
!       jfunc = ipa_get_ith_jump_func (top, param_index);
  
        auto_vec<cgraph_node *, 4> spec_targets;
        if (ie->speculative)
--- 4535,4570 ----
  				      struct cgraph_node *node,
  				      vec<cgraph_edge *> *new_edges)
  {
    bool res = false;
  
    ipa_check_create_edge_args ();
!   class ipa_edge_args *top = ipa_edge_args_sum->get (cs);
!   if (!top)
!     return res;
!   cgraph_node *new_root
!     = cs->caller->inlined_to ? cs->caller->inlined_to : cs->caller;
!   ipa_node_params *new_root_info = ipa_node_params_sum->get (new_root);
!   ipa_node_params *inlined_node_info
!     = ipa_node_params_sum->get (cs->callee->function_symbol ());
  
!   cgraph_edge *next_ie;
!   for (cgraph_edge *ie = node->indirect_calls; ie; ie = next_ie)
      {
        next_ie = ie->next_callee;
  
!       if (ie->indirect_info->param_index < 0
! 	  || ie->indirect_info->param_index >= ipa_get_cs_argument_count (top))
  	{
! 	  ie->indirect_info->param_index = -1;
  	  continue;
  	}
  
!       int param_index = ie->indirect_info->param_index;
!       cgraph_polymorphic_indirect_info *pii
! 	= dyn_cast <cgraph_polymorphic_indirect_info *> (ie->indirect_info);
!       cgraph_simple_indirect_info *sii
! 	= dyn_cast <cgraph_simple_indirect_info *> (ie->indirect_info);
!       struct ipa_jump_func *jfunc = ipa_get_ith_jump_func (top, param_index);
  
        auto_vec<cgraph_node *, 4> spec_targets;
        if (ie->speculative)
*************** update_indirect_edges_after_inlining (st
*** 4340,4348 ****
  	     direct = direct->next_speculative_call_target ())
  	  spec_targets.safe_push (direct->callee);
  
        if (!opt_for_fn (node->decl, flag_indirect_inlining))
  	new_direct_edge = NULL;
!       else if (ici->polymorphic)
  	{
            ipa_polymorphic_call_context ctx;
  	  ctx = ipa_context_from_jfunc (new_root_info, cs, param_index, jfunc);
--- 4573,4582 ----
  	     direct = direct->next_speculative_call_target ())
  	  spec_targets.safe_push (direct->callee);
  
+       cgraph_edge *new_direct_edge;
        if (!opt_for_fn (node->decl, flag_indirect_inlining))
  	new_direct_edge = NULL;
!       else if (pii)
  	{
            ipa_polymorphic_call_context ctx;
  	  ctx = ipa_context_from_jfunc (new_root_info, cs, param_index, jfunc);
*************** update_indirect_edges_after_inlining (st
*** 4350,4356 ****
  							       new_root,
  							       new_root_info);
  	}
!       else
  	{
  	  tree target_type =  ipa_get_type (inlined_node_info, param_index);
  	  new_direct_edge = try_make_edge_direct_simple_call (ie, jfunc,
--- 4584,4590 ----
  							       new_root,
  							       new_root_info);
  	}
!       else if (sii)
  	{
  	  tree target_type =  ipa_get_type (inlined_node_info, param_index);
  	  new_direct_edge = try_make_edge_direct_simple_call (ie, jfunc,
*************** update_indirect_edges_after_inlining (st
*** 4358,4363 ****
--- 4592,4599 ----
  							      new_root,
  							      new_root_info);
  	}
+       else
+ 	gcc_unreachable ();
  
        /* If speculation was removed, then we need to do nothing.  */
        if (new_direct_edge && new_direct_edge != ie
*************** update_indirect_edges_after_inlining (st
*** 4384,4429 ****
        if (jfunc->type == IPA_JF_PASS_THROUGH
            && ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR)
  	{
! 	  if (ici->agg_contents
! 	      && !ipa_get_jf_pass_through_agg_preserved (jfunc)
! 	      && !ici->polymorphic)
! 	    ici->param_index = -1;
  	  else
  	    {
! 	      ici->param_index = ipa_get_jf_pass_through_formal_id (jfunc);
! 	      if (ici->polymorphic
! 		  && !ipa_get_jf_pass_through_type_preserved (jfunc))
! 		ici->vptr_changed = true;
! 	      ipa_set_param_used_by_indirect_call (new_root_info,
! 			     			   ici->param_index, true);
! 	      if (ici->polymorphic)
! 		ipa_set_param_used_by_polymorphic_call (new_root_info,
! 						        ici->param_index, true);
  	    }
  	}
        else if (jfunc->type == IPA_JF_ANCESTOR)
  	{
! 	  if (ici->agg_contents
! 	      && !ipa_get_jf_ancestor_agg_preserved (jfunc)
! 	      && !ici->polymorphic)
! 	    ici->param_index = -1;
  	  else
  	    {
! 	      ici->param_index = ipa_get_jf_ancestor_formal_id (jfunc);
! 	      ici->offset += ipa_get_jf_ancestor_offset (jfunc);
! 	      if (ici->polymorphic
! 		  && !ipa_get_jf_ancestor_type_preserved (jfunc))
! 		ici->vptr_changed = true;
! 	      ipa_set_param_used_by_indirect_call (new_root_info,
! 			     			   ici->param_index, true);
! 	      if (ici->polymorphic)
! 		ipa_set_param_used_by_polymorphic_call (new_root_info,
! 						        ici->param_index, true);
  	    }
  	}
        else
  	/* Either we can find a destination for this edge now or never. */
! 	ici->param_index = -1;
      }
  
    return res;
--- 4620,4671 ----
        if (jfunc->type == IPA_JF_PASS_THROUGH
            && ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR)
  	{
! 	  if (!pii
! 	      && sii->agg_contents
! 	      && !ipa_get_jf_pass_through_agg_preserved (jfunc))
! 	    ie->indirect_info->param_index = -1;
  	  else
  	    {
! 	      param_index = ipa_get_jf_pass_through_formal_id (jfunc);
! 	      ie->indirect_info->param_index = param_index;
! 	      ipa_set_param_used_by_indirect_call (new_root_info, param_index,
! 						   true);
! 	      if (pii)
! 		{
! 		  if (!ipa_get_jf_pass_through_type_preserved (jfunc))
! 		    pii->vptr_changed = true;
! 		  ipa_set_param_used_by_polymorphic_call (new_root_info,
! 							  param_index, true);
! 		}
  	    }
  	}
        else if (jfunc->type == IPA_JF_ANCESTOR)
  	{
! 	  if (!pii
! 	      && sii->agg_contents
! 	      && !ipa_get_jf_ancestor_agg_preserved (jfunc))
! 	    ie->indirect_info->param_index = -1;
  	  else
  	    {
! 	      param_index = ipa_get_jf_ancestor_formal_id (jfunc);
! 	      ie->indirect_info->param_index = param_index;
! 	      ipa_set_param_used_by_indirect_call (new_root_info, param_index,
! 						   true);
! 	      if (pii)
! 		{
! 		  pii->offset += ipa_get_jf_ancestor_offset (jfunc);
! 		  if (!ipa_get_jf_ancestor_type_preserved (jfunc))
! 		    pii->vptr_changed = true;
! 		  ipa_set_param_used_by_polymorphic_call (new_root_info,
! 							  param_index, true);
! 		}
! 	      else
! 		sii->offset += ipa_get_jf_ancestor_offset (jfunc);
  	    }
  	}
        else
  	/* Either we can find a destination for this edge now or never. */
! 	ie->indirect_info->param_index = -1;
      }
  
    return res;
*************** static void
*** 5312,5340 ****
  ipa_write_indirect_edge_info (struct output_block *ob,
  			      struct cgraph_edge *cs)
  {
-   class cgraph_indirect_call_info *ii = cs->indirect_info;
    struct bitpack_d bp;
  
-   streamer_write_hwi (ob, ii->param_index);
    bp = bitpack_create (ob->main_stream);
!   bp_pack_value (&bp, ii->polymorphic, 1);
!   bp_pack_value (&bp, ii->agg_contents, 1);
!   bp_pack_value (&bp, ii->member_ptr, 1);
!   bp_pack_value (&bp, ii->by_ref, 1);
!   bp_pack_value (&bp, ii->guaranteed_unmodified, 1);
!   bp_pack_value (&bp, ii->vptr_changed, 1);
    streamer_write_bitpack (&bp);
-   if (ii->agg_contents || ii->polymorphic)
-     streamer_write_hwi (ob, ii->offset);
-   else
-     gcc_assert (ii->offset == 0);
  
!   if (ii->polymorphic)
      {
!       streamer_write_hwi (ob, ii->otr_token);
!       stream_write_tree (ob, ii->otr_type, true);
!       ii->context.stream_out (ob);
      }
  }
  
  /* Read in parts of cgraph_indirect_call_info corresponding to CS that are
--- 5554,5603 ----
  ipa_write_indirect_edge_info (struct output_block *ob,
  			      struct cgraph_edge *cs)
  {
    struct bitpack_d bp;
  
    bp = bitpack_create (ob->main_stream);
!   bp_pack_enum (&bp, cgraph_indirect_info_kind, CIIK_N_KINDS,
! 		cs->indirect_info->kind);
    streamer_write_bitpack (&bp);
  
!   if (cgraph_polymorphic_indirect_info *pii
!       = dyn_cast <cgraph_polymorphic_indirect_info *> (cs->indirect_info))
      {
!       bp = bitpack_create (ob->main_stream);
!       bp_pack_value (&bp, pii->vptr_changed, 1);
!       streamer_write_bitpack (&bp);
! 
!       streamer_write_hwi (ob, pii->param_index);
!       pii->context.stream_out (ob);
!       streamer_write_hwi (ob, pii->otr_token);
!       stream_write_tree (ob, pii->otr_type, true);
!       streamer_write_hwi (ob, pii->offset);
      }
+   else if (cgraph_simple_indirect_info *sii
+ 	   = dyn_cast <cgraph_simple_indirect_info *> (cs->indirect_info))
+     {
+       bp = bitpack_create (ob->main_stream);
+       bp_pack_value (&bp, sii->agg_contents, 1);
+       bp_pack_value (&bp, sii->member_ptr, 1);
+       bp_pack_value (&bp, sii->fnptr_loaded_from_record, 1);
+       bp_pack_value (&bp, sii->by_ref, 1);
+       bp_pack_value (&bp, sii->guaranteed_unmodified, 1);
+       streamer_write_bitpack (&bp);
+ 
+       streamer_write_hwi (ob, sii->param_index);
+       if (sii->agg_contents)
+ 	streamer_write_hwi (ob, sii->offset);
+       else
+ 	gcc_assert (sii->offset == 0);
+       if (sii->fnptr_loaded_from_record)
+ 	{
+ 	  stream_write_tree (ob, sii->rec_type, true);
+ 	  streamer_write_uhwi (ob, sii->fld_offset);
+ 	}
+     }
+   else
+     gcc_assert (cs->indirect_info->param_index == -1);
  }
  
  /* Read in parts of cgraph_indirect_call_info corresponding to CS that are
*************** ipa_read_indirect_edge_info (class lto_i
*** 5346,5380 ****
  			     struct cgraph_edge *cs,
  			     class ipa_node_params *info)
  {
-   class cgraph_indirect_call_info *ii = cs->indirect_info;
    struct bitpack_d bp;
  
-   ii->param_index = (int) streamer_read_hwi (ib);
    bp = streamer_read_bitpack (ib);
!   ii->polymorphic = bp_unpack_value (&bp, 1);
!   ii->agg_contents = bp_unpack_value (&bp, 1);
!   ii->member_ptr = bp_unpack_value (&bp, 1);
!   ii->by_ref = bp_unpack_value (&bp, 1);
!   ii->guaranteed_unmodified = bp_unpack_value (&bp, 1);
!   ii->vptr_changed = bp_unpack_value (&bp, 1);
!   if (ii->agg_contents || ii->polymorphic)
!     ii->offset = (HOST_WIDE_INT) streamer_read_hwi (ib);
!   else
!     ii->offset = 0;
!   if (ii->polymorphic)
      {
!       ii->otr_token = (HOST_WIDE_INT) streamer_read_hwi (ib);
!       ii->otr_type = stream_read_tree (ib, data_in);
!       ii->context.stream_in (ib, data_in);
      }
!   if (info && ii->param_index >= 0)
      {
!       if (ii->polymorphic)
! 	ipa_set_param_used_by_polymorphic_call (info,
! 						ii->param_index , true);
!       ipa_set_param_used_by_indirect_call (info,
! 					   ii->param_index, true);
      }
  }
  
  /* Stream out NODE info to OB.  */
--- 5609,5664 ----
  			     struct cgraph_edge *cs,
  			     class ipa_node_params *info)
  {
    struct bitpack_d bp;
  
    bp = streamer_read_bitpack (ib);
!   enum cgraph_indirect_info_kind ii_kind
!     = bp_unpack_enum (&bp, cgraph_indirect_info_kind, CIIK_N_KINDS);
!   gcc_assert (ii_kind == cs->indirect_info->kind);
! 
!   if (cgraph_polymorphic_indirect_info *pii
!       = dyn_cast <cgraph_polymorphic_indirect_info *> (cs->indirect_info))
      {
!       bp = streamer_read_bitpack (ib);
!       pii->vptr_changed = bp_unpack_value (&bp, 1);
! 
!       pii->param_index = (int) streamer_read_hwi (ib);
!       pii->context.stream_in (ib, data_in);
!       pii->otr_token = (HOST_WIDE_INT) streamer_read_hwi (ib);
!       pii->otr_type = stream_read_tree (ib, data_in);
!       pii->offset = (HOST_WIDE_INT) streamer_read_hwi (ib);
! 
!       if (info && pii->param_index >= 0)
! 	{
! 	  ipa_set_param_used_by_polymorphic_call (info, pii->param_index, true);
! 	  ipa_set_param_used_by_indirect_call (info, pii->param_index, true);
! 	}
      }
!   else if (cgraph_simple_indirect_info *sii
! 	   = dyn_cast <cgraph_simple_indirect_info *> (cs->indirect_info))
      {
!       bp = streamer_read_bitpack (ib);
!       sii->agg_contents = bp_unpack_value (&bp, 1);
!       sii->member_ptr = bp_unpack_value (&bp, 1);
!       sii->fnptr_loaded_from_record = bp_unpack_value (&bp, 1);
!       sii->by_ref = bp_unpack_value (&bp, 1);
!       sii->guaranteed_unmodified = bp_unpack_value (&bp, 1);
! 
!       sii->param_index = (int) streamer_read_hwi (ib);
!       if (sii->agg_contents)
! 	sii->offset = (HOST_WIDE_INT) streamer_read_hwi (ib);
!       else
! 	sii->offset = 0;
!       if (sii->fnptr_loaded_from_record)
! 	{
! 	  sii->rec_type = stream_read_tree (ib, data_in);
! 	  sii->fld_offset = (unsigned) streamer_read_uhwi (ib);
! 	}
!       if (info && sii->param_index >= 0)
! 	ipa_set_param_used_by_indirect_call (info, sii->param_index, true);
      }
+   else
+     cs->indirect_info->param_index = -1;
  }
  
  /* Stream out NODE info to OB.  */
*************** ipa_prop_write_jump_functions (void)
*** 5643,5648 ****
--- 5927,5956 ----
          ipa_write_node_info (ob, node);
      }
    ipa_write_return_summaries (ob);
+ 
+   if (noted_fnptrs_in_records)
+     {
+       count = 0;
+       for (auto iter = noted_fnptrs_in_records->begin ();
+ 	   iter != noted_fnptrs_in_records->end();
+ 	   ++iter)
+ 	if ((*iter)->fn)
+ 	  count++;
+       streamer_write_uhwi (ob, count);
+ 
+       for (auto iter = noted_fnptrs_in_records->begin ();
+ 	   iter != noted_fnptrs_in_records->end();
+ 	   ++iter)
+ 	if ((*iter)->fn)
+ 	  {
+ 	    stream_write_tree (ob, (*iter)->rec_type, true);
+ 	    stream_write_tree (ob, (*iter)->fn, true);
+ 	    streamer_write_uhwi (ob, (*iter)->fld_offset);
+ 	  }
+     }
+   else
+     streamer_write_uhwi (ob, 0);
+ 
    produce_asm (ob);
    destroy_output_block (ob);
  }
*************** ipa_prop_read_section (struct lto_file_d
*** 5731,5736 ****
--- 6039,6054 ----
        ipa_read_node_info (&ib_main, node, data_in);
      }
    ipa_read_return_summaries (&ib_main, file_data, data_in);
+ 
+   count = streamer_read_uhwi (&ib_main);
+   for (i = 0; i < count; i++)
+     {
+       tree rec_type = stream_read_tree (&ib_main, data_in);
+       tree fn = stream_read_tree (&ib_main, data_in);
+       unsigned fld_offset = (unsigned) streamer_read_uhwi (&ib_main);
+       note_fnptr_in_record (rec_type, fld_offset, fn);
+     }
+ 
    lto_free_section_data (file_data, LTO_section_jump_functions, NULL, data,
  			 len);
    lto_data_in_delete (data_in);
diff -Nrcpad gcc-16-20251214/gcc/ipa-prop.h gcc-16-20251221/gcc/ipa-prop.h
*** gcc-16-20251214/gcc/ipa-prop.h	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/ipa-prop.h	Sun Dec 21 22:32:07 2025
*************** public:
*** 666,672 ****
    /* Node has been completely replaced by clones and will be removed after
       ipa-cp is finished.  */
    unsigned node_dead : 1;
!   /* Node is involved in a recursion, potentionally indirect.  */
    unsigned node_within_scc : 1;
    /* Node contains only direct recursion.  */
    unsigned node_is_self_scc : 1;
--- 666,672 ----
    /* Node has been completely replaced by clones and will be removed after
       ipa-cp is finished.  */
    unsigned node_dead : 1;
!   /* Node is involved in a recursion, potentially indirect.  */
    unsigned node_within_scc : 1;
    /* Node contains only direct recursion.  */
    unsigned node_is_self_scc : 1;
*************** tree ipa_impossible_devirt_target (struc
*** 1209,1214 ****
--- 1209,1215 ----
  
  /* Functions related to both.  */
  void ipa_analyze_node (struct cgraph_node *);
+ void ipa_analyze_var_static_initializer (varpool_node *node);
  
  /* Aggregate jump function related functions.  */
  tree ipa_find_agg_cst_from_init (tree scalar, HOST_WIDE_INT offset,
*************** void ipa_push_agg_values_from_jfunc (ipa
*** 1265,1270 ****
--- 1266,1273 ----
  void ipa_dump_param (FILE *, class ipa_node_params *info, int i);
  void ipa_dump_jump_function (FILE *f, ipa_jump_func *jfunc,
  			     class ipa_polymorphic_call_context *ctx = NULL);
+ void ipa_dump_noted_record_fnptrs (FILE *f);
+ void ipa_debug_noted_record_fnptrs (void);
  void ipa_release_body_info (struct ipa_func_body_info *);
  tree ipa_get_callee_param_type (struct cgraph_edge *e, int i);
  bool ipcp_get_parm_bits (tree, tree *, widest_int *);
*************** tree ipcp_get_aggregate_const (struct fu
*** 1274,1280 ****
--- 1277,1285 ----
  bool unadjusted_ptr_and_unit_offset (tree op, tree *ret,
  				     poly_int64 *offset_ret);
  void ipa_get_range_from_ip_invariant (vrange &r, tree val, cgraph_node *node);
+ tree ipa_single_noted_fnptr_in_record (tree rectype, unsigned offset);
  void ipa_prop_cc_finalize (void);
+ void ipa_free_noted_fnptr_calls ();
  
  /* In ipa-cp.cc  */
  void ipa_cp_cc_finalize (void);
diff -Nrcpad gcc-16-20251214/gcc/ipa-utils.h gcc-16-20251221/gcc/ipa-utils.h
*** gcc-16-20251214/gcc/ipa-utils.h	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/ipa-utils.h	Sun Dec 21 22:32:07 2025
*************** possible_polymorphic_call_targets (struc
*** 134,141 ****
  {
    ipa_polymorphic_call_context context(e);
  
!   return possible_polymorphic_call_targets (e->indirect_info->otr_type,
! 					    e->indirect_info->otr_token,
  					    context,
  					    completep, cache_token,
  					    speculative);
--- 134,144 ----
  {
    ipa_polymorphic_call_context context(e);
  
!   cgraph_polymorphic_indirect_info *pii
!     = as_a <cgraph_polymorphic_indirect_info *> (e->indirect_info);
!   gcc_checking_assert (pii->usable_p ());
!   return possible_polymorphic_call_targets (pii->otr_type,
! 					    pii->otr_token,
  					    context,
  					    completep, cache_token,
  					    speculative);
*************** dump_possible_polymorphic_call_targets (
*** 166,173 ****
  {
    ipa_polymorphic_call_context context(e);
  
!   dump_possible_polymorphic_call_targets (f, e->indirect_info->otr_type,
! 					  e->indirect_info->otr_token,
  					  context, verbose);
  }
  
--- 169,180 ----
  {
    ipa_polymorphic_call_context context(e);
  
!   cgraph_polymorphic_indirect_info *pii
!     = as_a <cgraph_polymorphic_indirect_info *> (e->indirect_info);
!   if (!pii->usable_p ())
!     return;
!   dump_possible_polymorphic_call_targets (f, pii->otr_type,
! 					  pii->otr_token,
  					  context, verbose);
  }
  
*************** possible_polymorphic_call_target_p (stru
*** 180,187 ****
  {
    ipa_polymorphic_call_context context(e);
  
!   return possible_polymorphic_call_target_p (e->indirect_info->otr_type,
! 					     e->indirect_info->otr_token,
  					     context, n);
  }
  
--- 187,198 ----
  {
    ipa_polymorphic_call_context context(e);
  
!   cgraph_polymorphic_indirect_info *pii
!     = as_a <cgraph_polymorphic_indirect_info *> (e->indirect_info);
!   if (!pii->usable_p ())
!     return true;
!   return possible_polymorphic_call_target_p (pii->otr_type,
! 					     pii->otr_token,
  					     context, n);
  }
  
diff -Nrcpad gcc-16-20251214/gcc/ipa.cc gcc-16-20251221/gcc/ipa.cc
*** gcc-16-20251214/gcc/ipa.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/ipa.cc	Sun Dec 21 22:32:07 2025
*************** symbol_table::remove_unreachable_nodes (
*** 428,434 ****
  		  for (e = cnode->indirect_calls; e; e = next)
  		    {
  		      next = e->next_callee;
! 		      if (e->indirect_info->polymorphic)
  			walk_polymorphic_call_targets (&reachable_call_targets,
  						       e, &first, &reachable);
  		    }
--- 428,434 ----
  		  for (e = cnode->indirect_calls; e; e = next)
  		    {
  		      next = e->next_callee;
! 		      if (usable_polymorphic_info_p (e->indirect_info))
  			walk_polymorphic_call_targets (&reachable_call_targets,
  						       e, &first, &reachable);
  		    }
diff -Nrcpad gcc-16-20251214/gcc/loop-init.cc gcc-16-20251221/gcc/loop-init.cc
*** gcc-16-20251214/gcc/loop-init.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/loop-init.cc	Sun Dec 21 22:32:07 2025
*************** fix_loop_structure (bitmap changed_bbs)
*** 314,320 ****
  	n_deleted++;
        }
  
!   /* If we deleted loops then the cached scalar evolutions refering to
       those loops become invalid.  */
    if (n_deleted > 0 && scev_initialized_p ())
      scev_reset_htab ();
--- 314,320 ----
  	n_deleted++;
        }
  
!   /* If we deleted loops then the cached scalar evolutions referring to
       those loops become invalid.  */
    if (n_deleted > 0 && scev_initialized_p ())
      scev_reset_htab ();
diff -Nrcpad gcc-16-20251214/gcc/lra-constraints.cc gcc-16-20251221/gcc/lra-constraints.cc
*** gcc-16-20251214/gcc/lra-constraints.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/lra-constraints.cc	Sun Dec 21 22:32:07 2025
*************** match_reload (signed char out, signed ch
*** 1243,1251 ****
      return;
    /* See a comment for the input operand above.  */
    narrow_reload_pseudo_class (out_rtx, goal_class);
!   if (find_reg_note (curr_insn, REG_UNUSED, out_rtx) == NULL_RTX)
      {
-       reg = SUBREG_P (out_rtx) ? SUBREG_REG (out_rtx) : out_rtx;
        start_sequence ();
        /* If we had strict_low_part, use it also in reload to keep other
  	 parts unchanged but do it only for regs as strict_low_part
--- 1243,1252 ----
      return;
    /* See a comment for the input operand above.  */
    narrow_reload_pseudo_class (out_rtx, goal_class);
!   reg = SUBREG_P (out_rtx) ? SUBREG_REG (out_rtx) : out_rtx;
!   if (find_reg_note (curr_insn, REG_UNUSED, reg) == NULL_RTX
!       && (!REG_P (reg) || !ira_former_scratch_p (REGNO (reg))))
      {
        start_sequence ();
        /* If we had strict_low_part, use it also in reload to keep other
  	 parts unchanged but do it only for regs as strict_low_part
*************** process_alt_operands (int only_alternati
*** 3002,3008 ****
  		 objects with a REG_UNUSED note.  */
  	      if ((curr_static_id->operand[nop].type != OP_IN
  		   && no_output_reloads_p
! 		   && ! find_reg_note (curr_insn, REG_UNUSED, op))
  		  || (curr_static_id->operand[nop].type != OP_OUT
  		      && no_input_reloads_p && ! const_to_mem)
  		  || (this_alternative_matches >= 0
--- 3003,3010 ----
  		 objects with a REG_UNUSED note.  */
  	      if ((curr_static_id->operand[nop].type != OP_IN
  		   && no_output_reloads_p
! 		   && ! find_reg_note (curr_insn, REG_UNUSED, op)
! 		   && ! scratch_p)
  		  || (curr_static_id->operand[nop].type != OP_OUT
  		      && no_input_reloads_p && ! const_to_mem)
  		  || (this_alternative_matches >= 0
*************** process_alt_operands (int only_alternati
*** 3012,3018 ****
  				  [this_alternative_matches].type != OP_IN)
  			      && ! find_reg_note (curr_insn, REG_UNUSED,
  						  no_subreg_reg_operand
! 						  [this_alternative_matches])))))
  		{
  		  if (lra_dump_file != NULL)
  		    fprintf
--- 3014,3021 ----
  				  [this_alternative_matches].type != OP_IN)
  			      && ! find_reg_note (curr_insn, REG_UNUSED,
  						  no_subreg_reg_operand
! 						  [this_alternative_matches])
! 			      && ! scratch_p))))
  		{
  		  if (lra_dump_file != NULL)
  		    fprintf
*************** curr_insn_transform (bool check_only_p)
*** 4856,4862 ****
  	  if (type != OP_IN
  	      && find_reg_note (curr_insn, REG_UNUSED, old) == NULL_RTX
  	      /* OLD can be an equivalent constant here.  */
! 	      && !CONSTANT_P (old))
  	    {
  	      start_sequence ();
  	      lra_emit_move (type == OP_INOUT ? copy_rtx (old) : old, new_reg);
--- 4859,4866 ----
  	  if (type != OP_IN
  	      && find_reg_note (curr_insn, REG_UNUSED, old) == NULL_RTX
  	      /* OLD can be an equivalent constant here.  */
! 	      && !CONSTANT_P (old)
! 	      && (!REG_P(old) || !ira_former_scratch_p (REGNO (old))))
  	    {
  	      start_sequence ();
  	      lra_emit_move (type == OP_INOUT ? copy_rtx (old) : old, new_reg);
diff -Nrcpad gcc-16-20251214/gcc/lto/ChangeLog gcc-16-20251221/gcc/lto/ChangeLog
*** gcc-16-20251214/gcc/lto/ChangeLog	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/lto/ChangeLog	Sun Dec 21 22:32:07 2025
***************
*** 1,3 ****
--- 1,8 ----
+ 2025-12-19  Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	* lto-common.cc (lto_resolution_read): Fix comment typo, explicitely
+ 	-> explicitly.
+ 
  2025-12-13  Andrew Pinski  <andrew.pinski@oss.qualcomm.com>
  
  	PR ipa/122955
diff -Nrcpad gcc-16-20251214/gcc/lto/lto-common.cc gcc-16-20251221/gcc/lto/lto-common.cc
*** gcc-16-20251214/gcc/lto/lto-common.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/lto/lto-common.cc	Sun Dec 21 22:32:07 2025
*************** lto_resolution_read (splay_tree file_ids
*** 2141,2147 ****
  		 somewhat contradictionary (as the point of incremental linking
  		 is to allow re-linking with more symbols later) but it is
  		 used to build LTO kernel.  We want to hide all symbols that
! 		 are not explicitely marked as exported and thus turn
  		 LDPR_PREVAILING_DEF_IRONLY_EXP
  		 to LDPR_PREVAILING_DEF_IRONLY.  */
  	      if (flag_whole_program
--- 2141,2147 ----
  		 somewhat contradictionary (as the point of incremental linking
  		 is to allow re-linking with more symbols later) but it is
  		 used to build LTO kernel.  We want to hide all symbols that
! 		 are not explicitly marked as exported and thus turn
  		 LDPR_PREVAILING_DEF_IRONLY_EXP
  		 to LDPR_PREVAILING_DEF_IRONLY.  */
  	      if (flag_whole_program
diff -Nrcpad gcc-16-20251214/gcc/lto-cgraph.cc gcc-16-20251221/gcc/lto-cgraph.cc
*** gcc-16-20251214/gcc/lto-cgraph.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/lto-cgraph.cc	Sun Dec 21 22:32:07 2025
*************** lto_output_edge (struct lto_simple_outpu
*** 286,291 ****
--- 286,293 ----
    bp_pack_value (&bp, edge->in_polymorphic_cdtor, 1);
    if (edge->indirect_unknown_callee)
      {
+       bp_pack_enum (&bp, cgraph_indirect_info_kind, CIIK_N_KINDS,
+ 		    edge->indirect_info->kind);
        int flags = edge->indirect_info->ecf_flags;
        bp_pack_value (&bp, (flags & ECF_CONST) != 0, 1);
        bp_pack_value (&bp, (flags & ECF_PURE) != 0, 1);
*************** compute_ltrans_boundary (lto_symtab_enco
*** 935,941 ****
        /* Add all possible targets for late devirtualization.  */
        if (flag_ltrans_devirtualize || !flag_wpa)
  	for (edge = node->indirect_calls; edge; edge = edge->next_callee)
! 	  if (edge->indirect_info->polymorphic)
  	    {
  	      unsigned int i;
  	      void *cache_token;
--- 937,943 ----
        /* Add all possible targets for late devirtualization.  */
        if (flag_ltrans_devirtualize || !flag_wpa)
  	for (edge = node->indirect_calls; edge; edge = edge->next_callee)
! 	  if (usable_polymorphic_info_p (edge->indirect_info))
  	    {
  	      unsigned int i;
  	      void *cache_token;
*************** input_edge (class lto_input_block *ib, v
*** 1523,1529 ****
    profile_count count;
    cgraph_inline_failed_t inline_failed;
    struct bitpack_d bp;
-   int ecf_flags = 0;
  
    caller = dyn_cast<cgraph_node *> (nodes[streamer_read_hwi (ib)]);
    if (caller == NULL || caller->decl == NULL_TREE)
--- 1525,1530 ----
*************** input_edge (class lto_input_block *ib, v
*** 1546,1552 ****
    speculative_id = bp_unpack_value (&bp, 16);
  
    if (indirect)
!     edge = caller->create_indirect_edge (NULL, 0, count);
    else
      edge = caller->create_edge (callee, NULL, count);
  
--- 1547,1553 ----
    speculative_id = bp_unpack_value (&bp, 16);
  
    if (indirect)
!     edge = caller->create_indirect_edge (NULL, 0, count, true);
    else
      edge = caller->create_edge (callee, NULL, count);
  
*************** input_edge (class lto_input_block *ib, v
*** 1563,1568 ****
--- 1564,1572 ----
    edge->in_polymorphic_cdtor = bp_unpack_value (&bp, 1);
    if (indirect)
      {
+       enum cgraph_indirect_info_kind ii_kind
+ 	= bp_unpack_enum (&bp, cgraph_indirect_info_kind, CIIK_N_KINDS);
+       int ecf_flags = 0;
        if (bp_unpack_value (&bp, 1))
  	ecf_flags |= ECF_CONST;
        if (bp_unpack_value (&bp, 1))
*************** input_edge (class lto_input_block *ib, v
*** 1575,1581 ****
  	ecf_flags |= ECF_NOTHROW;
        if (bp_unpack_value (&bp, 1))
  	ecf_flags |= ECF_RETURNS_TWICE;
!       edge->indirect_info->ecf_flags = ecf_flags;
  
        edge->indirect_info->num_speculative_call_targets
  	= bp_unpack_value (&bp, 16);
--- 1579,1597 ----
  	ecf_flags |= ECF_NOTHROW;
        if (bp_unpack_value (&bp, 1))
  	ecf_flags |= ECF_RETURNS_TWICE;
! 
!       if (ii_kind == CIIK_POLYMORPHIC)
! 	edge->indirect_info
! 	  = (new (ggc_alloc<cgraph_polymorphic_indirect_info> ())
! 	     cgraph_polymorphic_indirect_info (ecf_flags));
!       else if (ii_kind == CIIK_SIMPLE)
! 	edge->indirect_info
! 	  = (new (ggc_alloc<cgraph_simple_indirect_info> ())
! 	     cgraph_simple_indirect_info (ecf_flags));
!       else
! 	edge->indirect_info
! 	  = (new (ggc_alloc<cgraph_indirect_call_info> ())
! 	     cgraph_indirect_call_info(CIIK_UNSPECIFIED, ecf_flags));
  
        edge->indirect_info->num_speculative_call_targets
  	= bp_unpack_value (&bp, 16);
diff -Nrcpad gcc-16-20251214/gcc/m2/ChangeLog gcc-16-20251221/gcc/m2/ChangeLog
*** gcc-16-20251214/gcc/m2/ChangeLog	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/m2/ChangeLog	Sun Dec 21 22:32:07 2025
***************
*** 1,3 ****
--- 1,27 ----
+ 2025-12-19  Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	* gm2-compiler/FilterError.mod: Fix comment typo, refering
+ 	-> referring.
+ 	* gm2-compiler/M2Batch.mod (LookupOuterModule): Likewise.
+ 
+ 2025-12-17  Gaius Mulley  <gaiusmod2@gmail.com>
+ 
+ 	PR modula2/23178
+ 	* gm2-compiler/P3SymBuild.mod (CheckCanBeImported): Reimplement to
+ 	use MetaError2 and provide spell hints if possible for unknown symbols.
+ 
+ 2025-12-17  Gaius Mulley  <gaiusmod2@gmail.com>
+ 
+ 	PR modula2/123151
+ 	* gm2-libs/FIO.def (IsError): New procedure function.
+ 	(IsActive): Rewrite the comment.
+ 	(Exists): Ditto.
+ 	(OpenToRead): Ditto.
+ 	(OpenToWrite): Ditto.
+ 	(Close): Add an optional BOOLEAN return result.
+ 	* gm2-libs/FIO.mod (Close): Reimplement with an
+ 	optional BOOLEAN return result.
+ 
  2025-12-12  Pietro Monteiro  <pietro@sociotechnical.xyz>
  
  	* lang.opt.urls: Regenerate.
diff -Nrcpad gcc-16-20251214/gcc/m2/gm2-compiler/FilterError.mod gcc-16-20251221/gcc/m2/gm2-compiler/FilterError.mod
*** gcc-16-20251214/gcc/m2/gm2-compiler/FilterError.mod	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/m2/gm2-compiler/FilterError.mod	Sun Dec 21 22:32:07 2025
*************** along with GNU Modula-2; see the file CO
*** 22,28 ****
  IMPLEMENTATION MODULE FilterError ;
  
  (* The purpose of this module is to be able to filter out multiple error
!    reports refering to the same symbol and token.  This is achieved by
     maintaining a dictionary of symbols each pointing to a dictionary of
     tokens.  *)
  
--- 22,28 ----
  IMPLEMENTATION MODULE FilterError ;
  
  (* The purpose of this module is to be able to filter out multiple error
!    reports referring to the same symbol and token.  This is achieved by
     maintaining a dictionary of symbols each pointing to a dictionary of
     tokens.  *)
  
diff -Nrcpad gcc-16-20251214/gcc/m2/gm2-compiler/M2Batch.mod gcc-16-20251221/gcc/m2/gm2-compiler/M2Batch.mod
*** gcc-16-20251214/gcc/m2/gm2-compiler/M2Batch.mod	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/m2/gm2-compiler/M2Batch.mod	Sun Dec 21 22:32:07 2025
*************** BEGIN
*** 461,467 ****
        END ;
        IF sym = NulSym
        THEN
!          (* not a local module, so it must be refering to a definition module.  *)
           sym := MakeDefinitionSource (tok, n)
        END
     END ;
--- 461,467 ----
        END ;
        IF sym = NulSym
        THEN
!          (* not a local module, so it must be referring to a definition module.  *)
           sym := MakeDefinitionSource (tok, n)
        END
     END ;
diff -Nrcpad gcc-16-20251214/gcc/m2/gm2-compiler/P3SymBuild.mod gcc-16-20251221/gcc/m2/gm2-compiler/P3SymBuild.mod
*** gcc-16-20251214/gcc/m2/gm2-compiler/P3SymBuild.mod	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/m2/gm2-compiler/P3SymBuild.mod	Sun Dec 21 22:32:07 2025
*************** FROM SymbolTable IMPORT NulSym, ModeOfAd
*** 35,40 ****
--- 35,41 ----
                          SetCurrentModule, GetCurrentModule, SetFileModule,
                          GetExported, IsExported, IsImplicityExported,
                          IsDefImp, IsModule, IsImported, IsIncludedByDefinition,
+                         IsUnknown,
                          RequestSym,
                          IsProcedure, PutOptArgInit,
                          IsFieldEnumeration, GetType,
*************** FROM M2Comp IMPORT CompilingDefinitionMo
*** 62,67 ****
--- 63,69 ----
  
  FROM FifoQueue IMPORT GetSubrangeFromFifoQueue ;
  FROM M2Reserved IMPORT NulTok, ImportTok ;
+ FROM M2MetaError IMPORT MetaError2 ;
  
  IMPORT M2Error ;
  IMPORT M2StackSpell ;
*************** END CheckImportListOuterModule ;
*** 419,450 ****
  
  
  (*
!    CheckCanBeImported - checks to see that it is legal to import, Sym, from, ModSym.
  *)
  
  PROCEDURE CheckCanBeImported (ModSym, Sym: CARDINAL) ;
- VAR
-    n1, n2: Name ;
  BEGIN
!    IF IsDefImp(ModSym)
     THEN
!       IF IsExported(ModSym, Sym)
        THEN
!          (* great all done *)
           RETURN
        ELSE
!          IF IsImplicityExported(ModSym, Sym)
           THEN
!             (* this is also legal *)
              RETURN
!          ELSIF IsDefImp(Sym) AND IsIncludedByDefinition(ModSym, Sym)
           THEN
!             (* this is also legal (for a definition module) *)
              RETURN
           END ;
!          n1 := GetSymName(ModSym) ;
!          n2 := GetSymName(Sym) ;
!          WriteFormat2('symbol %a is not exported from definition module %a', n2, n1)
        END
     END
  END CheckCanBeImported ;
--- 421,455 ----
  
  
  (*
!    CheckCanBeImported - checks to see that it is legal to import Sym from ModSym.
  *)
  
  PROCEDURE CheckCanBeImported (ModSym, Sym: CARDINAL) ;
  BEGIN
!    IF IsDefImp (ModSym)
     THEN
!       IF IsExported (ModSym, Sym)
        THEN
!          (* All done.  *)
           RETURN
        ELSE
!          IF IsImplicityExported (ModSym, Sym)
           THEN
!             (* This is also legal.  *)
              RETURN
!          ELSIF IsDefImp (Sym) AND IsIncludedByDefinition (ModSym, Sym)
           THEN
!             (* This is also legal (for a definition module).  *)
              RETURN
           END ;
!          (* Use spell checker for Unknown symbols.  *)
!          IF IsUnknown (Sym)
!          THEN
!             (* Spellcheck.  *)
!             MetaError2 ('{%1Ua} is not exported from definition module {%2a} {%1&s}', Sym, ModSym)
!          ELSE
!             MetaError2 ('{%1Ua} is not exported from definition module {%2a}', Sym, ModSym)
!          END
        END
     END
  END CheckCanBeImported ;
diff -Nrcpad gcc-16-20251214/gcc/m2/gm2-libs/FIO.def gcc-16-20251221/gcc/m2/gm2-libs/FIO.def
*** gcc-16-20251214/gcc/m2/gm2-libs/FIO.def	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/m2/gm2-libs/FIO.def	Sun Dec 21 22:32:07 2025
*************** EXPORT QUALIFIED (* types *)
*** 35,41 ****
                   File,
                   (* procedures *)
                   OpenToRead, OpenToWrite, OpenForRandom, Close,
!                  EOF, EOLN, WasEOLN, IsNoError, Exists, IsActive,
                   exists, openToRead, openToWrite, openForRandom,
                   SetPositionFromBeginning,
                   SetPositionFromEnd,
--- 35,41 ----
                   File,
                   (* procedures *)
                   OpenToRead, OpenToWrite, OpenForRandom, Close,
!                  EOF, EOLN, WasEOLN, IsError, IsNoError, Exists, IsActive,
                   exists, openToRead, openToWrite, openForRandom,
                   SetPositionFromBeginning,
                   SetPositionFromEnd,
*************** EXPORT QUALIFIED (* types *)
*** 55,89 ****
  TYPE
     File = CARDINAL ;
  
! (* the following variables are initialized to their UNIX equivalents *)
  VAR
     StdIn, StdOut, StdErr: File ;
  
  
  
  (*
!    IsNoError - returns a TRUE if no error has occured on file, f.
  *)
  
  PROCEDURE IsNoError (f: File) : BOOLEAN ;
  
  
  (*
!    IsActive - returns TRUE if the file, f, is still active.
  *)
  
  PROCEDURE IsActive (f: File) : BOOLEAN ;
  
  
  (*
!    Exists - returns TRUE if a file named, fname exists for reading.
  *)
  
  PROCEDURE Exists (fname: ARRAY OF CHAR) : BOOLEAN ;
  
  
  (*
!    OpenToRead - attempts to open a file, fname, for reading and
                  it returns this file.
                  The success of this operation can be checked by
                  calling IsNoError.
--- 55,96 ----
  TYPE
     File = CARDINAL ;
  
! (* The following variables are initialized to their UNIX equivalents.  *)
  VAR
     StdIn, StdOut, StdErr: File ;
  
  
  
  (*
!    IsNoError - returns TRUE if no error has occured on file f.
  *)
  
  PROCEDURE IsNoError (f: File) : BOOLEAN ;
  
  
  (*
!    IsError - returns TRUE if an error has occured on file f.
! *)
! 
! PROCEDURE IsError (f: File) : BOOLEAN ;
! 
! 
! (*
!    IsActive - returns TRUE if the file f is still active.
  *)
  
  PROCEDURE IsActive (f: File) : BOOLEAN ;
  
  
  (*
!    Exists - returns TRUE if a file fname exists for reading.
  *)
  
  PROCEDURE Exists (fname: ARRAY OF CHAR) : BOOLEAN ;
  
  
  (*
!    OpenToRead - attempts to open a file fname for reading and
                  it returns this file.
                  The success of this operation can be checked by
                  calling IsNoError.
*************** PROCEDURE OpenToRead (fname: ARRAY OF CH
*** 93,99 ****
  
  
  (*
!    OpenToWrite - attempts to open a file, fname, for write and
                   it returns this file.
                   The success of this operation can be checked by
                   calling IsNoError.
--- 100,106 ----
  
  
  (*
!    OpenToWrite - attempts to open a file fname for write and
                   it returns this file.
                   The success of this operation can be checked by
                   calling IsNoError.
*************** PROCEDURE OpenToWrite (fname: ARRAY OF C
*** 103,109 ****
  
  
  (*
!    OpenForRandom - attempts to open a file, fname, for random access
                     read or write and it returns this file.
                     The success of this operation can be checked by
                     calling IsNoError.
--- 110,116 ----
  
  
  (*
!    OpenForRandom - attempts to open a file fname for random access
                     read or write and it returns this file.
                     The success of this operation can be checked by
                     calling IsNoError.
*************** PROCEDURE OpenForRandom (fname: ARRAY OF
*** 124,132 ****
     Close - close a file which has been previously opened using:
             OpenToRead, OpenToWrite, OpenForRandom.
             It is correct to close a file which has an error status.
  *)
  
! PROCEDURE Close (f: File) ;
  
  
  (* the following functions are functionally equivalent to the above
--- 131,144 ----
     Close - close a file which has been previously opened using:
             OpenToRead, OpenToWrite, OpenForRandom.
             It is correct to close a file which has an error status.
+            Close has an optional return value:
+              TRUE  signifies that the close was successful and all
+                    state associated with f is deallocated.
+              FALSE signifies that the close was unsuccessful and no
+                    state associated with f has been deallocated.
  *)
  
! PROCEDURE Close (f: File) : [BOOLEAN] ;
  
  
  (* the following functions are functionally equivalent to the above
diff -Nrcpad gcc-16-20251214/gcc/m2/gm2-libs/FIO.mod gcc-16-20251221/gcc/m2/gm2-libs/FIO.mod
*** gcc-16-20251214/gcc/m2/gm2-libs/FIO.mod	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/m2/gm2-libs/FIO.mod	Sun Dec 21 22:32:07 2025
*************** END GetNextFreeDescriptor ;
*** 194,200 ****
  
  
  (*
!    IsNoError - returns a TRUE if no error has occured on file, f.
  *)
  
  PROCEDURE IsNoError (f: File) : BOOLEAN ;
--- 194,200 ----
  
  
  (*
!    IsNoError - returns a TRUE if no error has occured on file f.
  *)
  
  PROCEDURE IsNoError (f: File) : BOOLEAN ;
*************** END IsNoError ;
*** 212,217 ****
--- 212,235 ----
  
  
  (*
+    IsError - returns a TRUE if an error has occured on file f.
+ *)
+ 
+ PROCEDURE IsError (f: File) : BOOLEAN ;
+ VAR
+    fd: FileDescriptor ;
+ BEGIN
+    IF f=Error
+    THEN
+       RETURN( FALSE )
+    ELSE
+       fd := GetIndice (FileInfo, f) ;
+       RETURN( (fd#NIL) AND ((fd^.state#successful) AND (fd^.state#endoffile) AND (fd^.state#endofline)) )
+    END
+ END IsError ;
+ 
+ 
+ (*
     IsActive - returns TRUE if the file, f, is still active.
  *)
  
*************** END OpenForRandom ;
*** 474,501 ****
     Close - close a file which has been previously opened using:
             OpenToRead, OpenToWrite, OpenForRandom.
             It is correct to close a file which has an error status.
  *)
  
! PROCEDURE Close (f: File) ;
  VAR
     fd: FileDescriptor ;
  BEGIN
!    IF f#Error
     THEN
!       fd := GetIndice(FileInfo, f) ;
!       (*
!          we allow users to close files which have an error status
!       *)
!       IF fd#NIL
        THEN
!          FlushBuffer(f) ;
           WITH fd^ DO
!             IF unixfd>=0
              THEN
!                IF close(unixfd)#0
                 THEN
!                   FormatError1('failed to close file (%s)\n', name.address) ;
!                   state := failed   (* --fixme-- too late to notify user (unless we return a BOOLEAN) *)
                 END
              END ;
              IF name.address#NIL
--- 492,523 ----
     Close - close a file which has been previously opened using:
             OpenToRead, OpenToWrite, OpenForRandom.
             It is correct to close a file which has an error status.
+            Close has an optional return value:
+              TRUE  signifies that the close was successful and all
+                    state associated with f is deallocated.
+              FALSE signifies that the close was unsuccessful and no
+                    state associated with f has been deallocated.
  *)
  
! PROCEDURE Close (f: File) : [BOOLEAN] ;
  VAR
     fd: FileDescriptor ;
  BEGIN
!    IF f # Error
     THEN
!       fd := GetIndice (FileInfo, f) ;
!       (* We allow users to close files which have an error status.  *)
!       IF fd # NIL
        THEN
!          FlushBuffer (f) ;
           WITH fd^ DO
!             IF unixfd >= 0
              THEN
!                IF close (unixfd) # 0
                 THEN
!                   FormatError1 ('failed to close file (%s)\n', name.address) ;
!                   state := failed ;
!                   RETURN FALSE
                 END
              END ;
              IF name.address#NIL
*************** BEGIN
*** 516,522 ****
           END ;
           DISPOSE(fd) ;
           PutIndice(FileInfo, f, NIL)
!       END
     END
  END Close ;
  
--- 538,547 ----
           END ;
           DISPOSE(fd) ;
           PutIndice(FileInfo, f, NIL)
!       END ;
!       RETURN TRUE
!    ELSE
!       RETURN FALSE
     END
  END Close ;
  
diff -Nrcpad gcc-16-20251214/gcc/match.pd gcc-16-20251221/gcc/match.pd
*** gcc-16-20251214/gcc/match.pd	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/match.pd	Sun Dec 21 22:32:07 2025
*************** DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
*** 598,604 ****
     But not for 1 / 0 so that we can get proper warnings and errors,
     and not for 1-bit integers as they are edge cases better handled
     elsewhere.  Delay the conversion of the signed division until late
!    because `1 / X` is simplier to handle than the resulting COND_EXPR.  */
  (simplify
   (trunc_div integer_onep@0 @1)
   (if (INTEGRAL_TYPE_P (type)
--- 598,604 ----
     But not for 1 / 0 so that we can get proper warnings and errors,
     and not for 1-bit integers as they are edge cases better handled
     elsewhere.  Delay the conversion of the signed division until late
!    because `1 / X` is simpler to handle than the resulting COND_EXPR.  */
  (simplify
   (trunc_div integer_onep@0 @1)
   (if (INTEGRAL_TYPE_P (type)
diff -Nrcpad gcc-16-20251214/gcc/omp-low.cc gcc-16-20251221/gcc/omp-low.cc
*** gcc-16-20251214/gcc/omp-low.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/omp-low.cc	Sun Dec 21 22:32:07 2025
*************** scan_sharing_clauses (tree clauses, omp_
*** 1768,1773 ****
--- 1768,1774 ----
  	case OMP_CLAUSE_FINALIZE:
  	case OMP_CLAUSE_TASK_REDUCTION:
  	case OMP_CLAUSE_ALLOCATE:
+ 	case OMP_CLAUSE_DEVICE_TYPE:
  	  break;
  
  	case OMP_CLAUSE_ALIGNED:
*************** scan_sharing_clauses (tree clauses, omp_
*** 1994,1999 ****
--- 1995,2001 ----
  	case OMP_CLAUSE_INIT:
  	case OMP_CLAUSE_USE:
  	case OMP_CLAUSE_DESTROY:
+ 	case OMP_CLAUSE_DEVICE_TYPE:
  	  break;
  
  	case OMP_CLAUSE__CACHE_:
*************** lower_omp_target (gimple_stmt_iterator *
*** 13098,13103 ****
--- 13100,13112 ----
  	    DECL_HAS_VALUE_EXPR_P (new_var) = 1;
  	  }
  	break;
+ 	case OMP_CLAUSE_DEVICE_TYPE:
+ 	  /* FIXME: Ensure that 'nohost' also has not implied before that
+ 	     'g->have_offload = true' or an implicit declare target.  */
+ 	  if (OMP_CLAUSE_DEVICE_TYPE_KIND (c) != OMP_CLAUSE_DEVICE_TYPE_ANY)
+ 	    sorry_at (OMP_CLAUSE_LOCATION (c),
+ 		      "only the %<device_type(any)%> is supported");
+ 	  break;
        }
  
    if (offloaded)
diff -Nrcpad gcc-16-20251214/gcc/optabs.cc gcc-16-20251221/gcc/optabs.cc
*** gcc-16-20251214/gcc/optabs.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/optabs.cc	Sun Dec 21 22:32:07 2025
*************** emit_cmp_and_jump_insns (rtx x, rtx y, e
*** 4928,4938 ****
  		  rtx len_bias_rtx = expand_normal (len_bias);
  		  tree lhs = gimple_get_lhs (def_stmt);
  		  auto mask_mode = TYPE_MODE (TREE_TYPE (lhs));
  		  create_input_operand (&ops[0], CONSTM1_RTX (mask_mode),
  					mask_mode);
! 		  create_input_operand (&ops[3], len_rtx, GET_MODE (len_rtx));
! 		  create_input_operand (&ops[4], len_bias_rtx,
! 					GET_MODE (len_bias_rtx));
  		}
  
  	      int unsignedp2 = TYPE_UNSIGNED (TREE_TYPE (t_op0));
--- 4928,4943 ----
  		  rtx len_bias_rtx = expand_normal (len_bias);
  		  tree lhs = gimple_get_lhs (def_stmt);
  		  auto mask_mode = TYPE_MODE (TREE_TYPE (lhs));
+ 		  /* ??? We could use something like internal_fn's
+ 		     add_mask_else_and_len_args here.  Currently it
+ 		     only supports a fixed, consecutive order of
+ 		     mask and len, though.  */
  		  create_input_operand (&ops[0], CONSTM1_RTX (mask_mode),
  					mask_mode);
! 		  create_convert_operand_from
! 		    (&ops[3], len_rtx, TYPE_MODE (TREE_TYPE (len_op)),
! 		     TYPE_UNSIGNED (TREE_TYPE (len_op)));
! 		  create_input_operand (&ops[4], len_bias_rtx, QImode);
  		}
  
  	      int unsignedp2 = TYPE_UNSIGNED (TREE_TYPE (t_op0));
diff -Nrcpad gcc-16-20251214/gcc/opts-common.cc gcc-16-20251221/gcc/opts-common.cc
*** gcc-16-20251214/gcc/opts-common.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/opts-common.cc	Sun Dec 21 22:32:07 2025
*************** jobserver_info::jobserver_info ()
*** 2110,2116 ****
        if (n != string::npos)
  	{
  	  string ending = makeflags.substr (n + js_needle.size ());
! 	  if (ending.find (fifo_prefix) == 0)
  	    {
  	      ending = ending.substr (fifo_prefix.size ());
  	      pipe_path = ending.substr (0, ending.find (' '));
--- 2110,2117 ----
        if (n != string::npos)
  	{
  	  string ending = makeflags.substr (n + js_needle.size ());
! 	  bool is_named_pipe = ending.find (fifo_prefix) == 0;
! 	  if (is_named_pipe)
  	    {
  	      ending = ending.substr (fifo_prefix.size ());
  	      pipe_path = ending.substr (0, ending.find (' '));
*************** jobserver_info::jobserver_info ()
*** 2125,2135 ****
  	    is_active = true;
  	  else
  	    {
! 	      string dup = makeflags.substr (0, n);
! 	      size_t pos = makeflags.find (' ', n);
! 	      if (pos != string::npos)
! 		dup += makeflags.substr (pos);
! 	      skipped_makeflags = "MAKEFLAGS=" + dup;
  	      error_msg
  		= "cannot access %<" + js_needle + "%> file descriptors";
  	    }
--- 2126,2140 ----
  	    is_active = true;
  	  else
  	    {
! 	      bool negative_fds = !is_named_pipe && rfd < 0 && wfd < 0;
! 	      if (!negative_fds)
! 	        {
! 	          string dup = makeflags.substr (0, n);
! 	          size_t pos = makeflags.find (' ', n);
! 	          if (pos != string::npos)
! 	            dup += makeflags.substr (pos);
! 	         skipped_makeflags = "MAKEFLAGS=" + dup;
! 	        }
  	      error_msg
  		= "cannot access %<" + js_needle + "%> file descriptors";
  	    }
diff -Nrcpad gcc-16-20251214/gcc/opts.cc gcc-16-20251221/gcc/opts.cc
*** gcc-16-20251214/gcc/opts.cc	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/opts.cc	Sun Dec 21 22:32:07 2025
*************** bool dwarf_based_debuginfo_p ()
*** 190,196 ****
  	  || (write_symbols & CODEVIEW_DEBUG));
  }
  
! /* All flag uses below need to explicitely reference the option sets
     to operate on.  */
  #define global_options DO_NOT_USE
  #define global_options_set DO_NOT_USE
--- 190,196 ----
  	  || (write_symbols & CODEVIEW_DEBUG));
  }
  
! /* All flag uses below need to explicitly reference the option sets
     to operate on.  */
  #define global_options DO_NOT_USE
  #define global_options_set DO_NOT_USE
*************** static const struct default_options defa
*** 662,667 ****
--- 662,668 ----
      { OPT_LEVELS_2_PLUS, OPT_fpeephole2, NULL, 1 },
      { OPT_LEVELS_2_PLUS, OPT_freorder_functions, NULL, 1 },
      { OPT_LEVELS_2_PLUS, OPT_frerun_cse_after_loop, NULL, 1 },
+     { OPT_LEVELS_2_PLUS, OPT_fspeculatively_call_stored_functions, NULL, 1 },
  #ifdef INSN_SCHEDULING
      { OPT_LEVELS_2_PLUS, OPT_fschedule_insns2, NULL, 1 },
  #endif
*************** finish_options (struct gcc_options *opts
*** 1318,1323 ****
--- 1319,1342 ----
    report_conflicting_sanitizer_options (opts, loc, SANITIZE_USER_ADDRESS,
  					SANITIZE_KERNEL_ADDRESS);
  
+   /* Sanitizers using Memory-Tagging Extension conflict with HWASAN and
+      ASAN.  */
+   report_conflicting_sanitizer_options (opts, loc, SANITIZE_MEMTAG,
+ 					SANITIZE_HWADDRESS);
+   report_conflicting_sanitizer_options (opts, loc, SANITIZE_MEMTAG,
+ 					SANITIZE_ADDRESS);
+ 
+   /* Memtag sanitizer implies HWASAN but with tags always generated by
+      the hardware randomly.  */
+   if ((opts->x_flag_sanitize & SANITIZE_MEMTAG_STACK)
+       && opts->x_param_hwasan_random_frame_tag == 0)
+     {
+        warning_at (loc, OPT_fsanitize_,
+ 		   "%<--param hwasan-random-frame-tag=0%> is ignored when "
+ 		   "%<-fsanitize=memtag-stack%> is present");
+        opts->x_param_hwasan_random_frame_tag = 1;
+     }
+ 
    /* Check error recovery for -fsanitize-recover option.  */
    for (int i = 0; sanitizer_opts[i].name != NULL; ++i)
      if ((opts->x_flag_sanitize_recover & sanitizer_opts[i].flag)
*************** const struct sanitizer_opts_s sanitizer_
*** 2182,2187 ****
--- 2201,2207 ----
    SANITIZER_OPT (pointer-overflow, SANITIZE_POINTER_OVERFLOW, true, true),
    SANITIZER_OPT (builtin, SANITIZE_BUILTIN, true, true),
    SANITIZER_OPT (shadow-call-stack, SANITIZE_SHADOW_CALL_STACK, false, false),
+   SANITIZER_OPT (memtag-stack, SANITIZE_MEMTAG_STACK, false, false),
    SANITIZER_OPT (all, ~sanitize_code_type (0), true, true),
  #undef SANITIZER_OPT
    { NULL, sanitize_code_type (0), 0UL, false, false }
*************** parse_sanitizer_options (const char *p,
*** 2320,2326 ****
  		else if (code == OPT_fsanitize_recover_)
  		  flags |= ~(SANITIZE_THREAD | SANITIZE_LEAK
  			     | SANITIZE_UNREACHABLE | SANITIZE_RETURN
! 			     | SANITIZE_SHADOW_CALL_STACK);
  		else /* if (code == OPT_fsanitize_trap_) */
  		  flags |= (SANITIZE_UNDEFINED
  			    | SANITIZE_UNDEFINED_NONDEFAULT);
--- 2340,2347 ----
  		else if (code == OPT_fsanitize_recover_)
  		  flags |= ~(SANITIZE_THREAD | SANITIZE_LEAK
  			     | SANITIZE_UNREACHABLE | SANITIZE_RETURN
! 			     | SANITIZE_SHADOW_CALL_STACK
! 			     | SANITIZE_MEMTAG_STACK);
  		else /* if (code == OPT_fsanitize_trap_) */
  		  flags |= (SANITIZE_UNDEFINED
  			    | SANITIZE_UNDEFINED_NONDEFAULT);
*************** common_handle_option (struct gcc_options
*** 3168,3175 ****
  	/* Indirect call profiling should do all useful transformations
  	   speculative devirtualization does.  */
        if (opts->x_flag_value_profile_transformations)
! 	SET_OPTION_IF_UNSET (opts, opts_set, flag_devirtualize_speculatively,
! 			     false);
        break;
  
      case OPT_fauto_profile_:
--- 3189,3200 ----
  	/* Indirect call profiling should do all useful transformations
  	   speculative devirtualization does.  */
        if (opts->x_flag_value_profile_transformations)
! 	{
! 	  SET_OPTION_IF_UNSET (opts, opts_set, flag_devirtualize_speculatively,
! 			       false);
! 	  SET_OPTION_IF_UNSET (opts, opts_set,
! 			       flag_speculatively_call_stored_functions, false);
! 	}
        break;
  
      case OPT_fauto_profile_:
diff -Nrcpad gcc-16-20251214/gcc/params.opt gcc-16-20251221/gcc/params.opt
*** gcc-16-20251214/gcc/params.opt	Sun Dec 14 22:32:07 2025
--- gcc-16-20251221/gcc/params.opt	Sun Dec 21 22:32:07 2025
*************** Enable hwasan instrumentation of store o
*** 98,103 ****
--- 98,111 ----
  Common Joined UInteger Var(param_hwasan_instrument_mem_intrinsics) Init(1) IntegerRange(0, 1) Param Optimization
  Enable hwasan instrumentation of builtin functions.
  
+ -param=memtag-instrument-allocas=
+ Target Joined UInteger Var(param_memtag_instrument_allocas) Init(1) IntegerRange(0, 1) Param
+ When sanitizing using MTE instructions, add checks for all stack allocas.
+ 
+ -param=memtag-instrument-mem-intrinsics=
+ Common Joined UInteger Var(param_memtag_instrument_mem_intrinsics) Init(1) IntegerRange(0, 1) Param Optimization
+ When sanitizing using MTE instructions, include builtin functions.
+ 
  -param=avg-loop-niter=
  Common Joined UInteger Var(param_avg_loop_niter) Init(10) IntegerRange(1, 65536) Param Optimization
  Average number of iterations of a loop.
diff -Nrcpad gcc-16-20251214/gcc/predict.cc gcc-16-20251221/gcc/predict.cc
*** gcc-16-20251214/gcc/predict.cc	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/predict.cc	Sun Dec 21 22:32:07 2025
*************** unlikely_executed_stmt_p (gimple *stmt)
*** 839,845 ****
    if (gimple_call_builtin_p (stmt, BUILT_IN_UNREACHABLE)
        || gimple_call_builtin_p (stmt, BUILT_IN_UNREACHABLE_TRAP)
        || gimple_call_builtin_p (stmt, BUILT_IN_TRAP))
!     return false;
  
    /* Checks below do not need to be fully reliable.  Cold attribute may be
       misplaced by user and in the presence of comdat we may result in call to
--- 839,845 ----
    if (gimple_call_builtin_p (stmt, BUILT_IN_UNREACHABLE)
        || gimple_call_builtin_p (stmt, BUILT_IN_UNREACHABLE_TRAP)
        || gimple_call_builtin_p (stmt, BUILT_IN_TRAP))
!     return true;
  
    /* Checks below do not need to be fully reliable.  Cold attribute may be
       misplaced by user and in the presence of comdat we may result in call to
diff -Nrcpad gcc-16-20251214/gcc/rust/ChangeLog gcc-16-20251221/gcc/rust/ChangeLog
*** gcc-16-20251214/gcc/rust/ChangeLog	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/rust/ChangeLog	Sun Dec 21 22:32:07 2025
***************
*** 1,3 ****
--- 1,311 ----
+ 2025-12-17  Pierre-Emmanuel Patry  <pierre-emmanuel.patry@embecosm.com>
+ 
+ 	* parse/rust-parse-impl-lexer.cc: Fix included file name.
+ 	* parse/rust-parse-impl-macro.cc: Likewise.
+ 	* parse/rust-parse-impl-proc-macro.cc: Likewise.
+ 	* parse/rust-parse-impl.h: Move to...
+ 	* parse/rust-parse-impl.hxx: ...here.
+ 
+ 2025-12-17  Pierre-Emmanuel Patry  <pierre-emmanuel.patry@embecosm.com>
+ 
+ 	* parse/rust-parse-impl.h (Parser::parse_inner_attributes): Move to
+ 	rust-parse-impl-XXX.hxx implementation file.
+ 	(Parser::parse_doc_comment): Likewise. Change return type to
+ 	AttributeBody.
+ 	(Parser::parse_inner_attribute): Likewise.
+ 	(Parser::parse_attribute_body): Likewise.
+ 	(Parser::parse_identifier_or_keyword_token): Likewise.
+ 	(Parser::parse_outer_attributes): Likewise.
+ 	(Parser::is_macro_rules_def): Likewise.
+ 	(Parser::parse_simple_path): Likewise.
+ 	(Parser::parse_item): Likewise.
+ 	(Parser::parse_simple_path_segment): Likewise.
+ 	(Parser::parse_path_ident_segment): Likewise.
+ 	(Parser::parse_vis_item): Likewise.
+ 	(Parser::parse_attr_input): Likewise.
+ 	(Parser::parse_async_item): Likewise.
+ 	(Parser::parse_delim_token_tree): Likewise.
+ 	(Parser::parse_macro_rules_def): Likewise.
+ 	(Parser::parse_decl_macro_def): Likewise.
+ 	(Parser::parse_token_tree): Likewise.
+ 	(Parser::parse_visibility): Likewise.
+ 	(Parser::parse_module): Likewise.
+ 	(Parser::parse_outer_attribute): Likewise.
+ 	(Parser::parse_extern_crate): Likewise.
+ 	(Parser::parse_use_decl): Likewise.
+ 	(Parser::parse_use_tree): Likewise.
+ 	(Parser::parse_function): Likewise.
+ 	(Parser::parse_macro_invocation): Likewise.
+ 	(Parser::parse_macro_rule): Likewise.
+ 	(Parser::parse_function_qualifiers): Likewise.
+ 	(Parser::parse_macro_matcher): Likewise.
+ 	(Parser::parse_generic_params_in_angles): Likewise.
+ 	(Parser::parse_macro_match): Likewise.
+ 	(Parser::parse_generic_param): Likewise.
+ 	(Parser::parse_macro_match_fragment): Likewise.
+ 	(Parser::parse_macro_match_repetition): Likewise.
+ 	(Parser::parse_generic_params): Likewise.
+ 	(Parser::parse_lifetime_params): Likewise.
+ 	(Parser::parse_lifetime_params_objs): Likewise.
+ 	(Parser::parse_lifetime_param): Likewise.
+ 	(Parser::parse_type_params): Likewise.
+ 	(Parser::parse_type_param): Likewise.
+ 	(Parser::parse_function_params): Likewise.
+ 	(Parser::parse_function_param): Likewise.
+ 	(Parser::parse_function_return_type): Likewise.
+ 	(Parser::parse_where_clause): Likewise.
+ 	(Parser::parse_lifetime_where_clause_item): Likewise.
+ 	(Parser::parse_for_lifetimes): Likewise.
+ 	(Parser::parse_type_param_bounds): Likewise.
+ 	(Parser::parse_type_param_bound): Likewise.
+ 	(Parser::parse_trait_bound): Likewise.
+ 	(Parser::parse_lifetime_bounds): Likewise.
+ 	(Parser::parse_lifetime): Likewise.
+ 	(Parser::lifetime_from_token): Likewise.
+ 	(Parser::parse_external_type_item): Likewise.
+ 	(Parser::parse_type_alias): Likewise.
+ 	(Parser::parse_struct): Likewise.
+ 	(Parser::parse_struct_fields): Likewise.
+ 	(Parser::parse_struct_field): Likewise.
+ 	(Parser::parse_tuple_fields): Likewise.
+ 	(Parser::parse_tuple_field): Likewise.
+ 	(Parser::parse_enum): Likewise.
+ 	(Parser::parse_enum_items): Likewise.
+ 	(Parser::parse_enum_item): Likewise.
+ 	(Parser::parse_union): Likewise.
+ 	(Parser::parse_const_item): Likewise.
+ 	(Parser::parse_static_item): Likewise.
+ 	(Parser::parse_trait): Likewise.
+ 	(Parser::parse_trait_item): Likewise.
+ 	(Parser::parse_trait_type): Likewise.
+ 	(Parser::parse_trait_const): Likewise.
+ 	(Parser::parse_impl): Likewise.
+ 	(Parser::parse_inherent_impl_item): Likewise.
+ 	(Parser::parse_trait_impl_item): Likewise.
+ 	(Parser::parse_extern_block): Likewise.
+ 	(Parser::parse_external_item): Likewise.
+ 	(Parser::parse_stmt): Likewise.
+ 	(Parser::parse_let_stmt): Likewise.
+ 	(Parser::parse_generic_arg): Likewise.
+ 	(Parser::parse_path_generic_args): Likewise.
+ 	(Parser::parse_generic_args_binding): Likewise.
+ 	(Parser::parse_self_param): Likewise.
+ 	(Parser::parse_expr_stmt): Likewise.
+ 	(Parser::parse_anon_const): Likewise.
+ 	(Parser::parse_const_block_expr): Likewise.
+ 	(Parser::parse_grouped_expr): Likewise.
+ 	(Parser::parse_type_path): Likewise.
+ 	(Parser::parse_closure_expr): Likewise.
+ 	(Parser::parse_literal_expr): Likewise.
+ 	(Parser::parse_box_expr): Likewise.
+ 	(Parser::parse_return_expr): Likewise.
+ 	(Parser::parse_try_expr): Likewise.
+ 	(Parser::parse_break_expr): Likewise.
+ 	(Parser::parse_continue_expr): Likewise.
+ 	(Parser::parse_type_path_segment): Likewise.
+ 	(Parser::parse_loop_label): Likewise.
+ 	(Parser::parse_type_path_function): Likewise.
+ 	(Parser::parse_if_expr): Likewise.
+ 	(Parser::parse_path_in_expression): Likewise.
+ 	(Parser::parse_path_expr_segment): Likewise.
+ 	(Parser::parse_if_let_expr): Likewise.
+ 	(Parser::parse_loop_expr): Likewise.
+ 	(Parser::parse_qualified_path_in_type): Likewise.
+ 	(Parser::parse_labelled_loop_expr): Likewise.
+ 	(Parser::parse_match_expr): Likewise.
+ 	(Parser::parse_match_arm): Likewise.
+ 	(Parser::parse_match_arm_patterns): Likewise.
+ 	(Parser::parse_async_block_expr): Likewise.
+ 	(Parser::parse_array_expr): Likewise.
+ 	(Parser::parse_closure_param): Likewise.
+ 	(Parser::parse_type): Likewise.
+ 	(Parser::parse_paren_prefixed_type): Likewise.
+ 	(Parser::parse_for_prefixed_type): Likewise.
+ 	(Parser::parse_maybe_named_param): Likewise.
+ 	(Parser::parse_reference_type_inner): Likewise.
+ 	(Parser::parse_reference_type): Likewise.
+ 	(Parser::parse_raw_pointer_type): Likewise.
+ 	(Parser::parse_slice_or_array_type): Likewise.
+ 	(Parser::parse_type_no_bounds): Likewise.
+ 	(Parser::parse_paren_prefixed_type_no_bounds): Likewise.
+ 	(Parser::parse_literal_or_range_pattern): Likewise.
+ 	(Parser::parse_range_pattern_bound): Likewise.
+ 	(Parser::parse_pattern): Likewise.
+ 	(Parser::parse_pattern_no_alt): Likewise.
+ 	(Parser::parse_reference_pattern): Likewise.
+ 	(Parser::parse_grouped_or_tuple_pattern): Likewise.
+ 	(Parser::parse_slice_pattern): Likewise.
+ 	(Parser::parse_identifier_pattern): Likewise.
+ 	(Parser::parse_ident_leading_pattern): Likewise.
+ 	(Parser::parse_struct_pattern_elems): Likewise.
+ 	(Parser::parse_struct_pattern_field): Likewise.
+ 	(Parser::unexpected_token): Likewise.
+ 	(Parser::skip_after_semicolon): Likewise.
+ 	(Parser::skip_token): Likewise.
+ 	(Parser::maybe_skip_token): Likewise.
+ 	(Parser::expect_token): Likewise.
+ 	(Parser::skip_after_end): Likewise.
+ 	(Parser::skip_after_end_block): Likewise.
+ 	(Parser::skip_after_next_block): Likewise.
+ 	(Parser::skip_after_end_attribute): Likewise.
+ 	(Parser::done_end_or_else): Likewise.
+ 	(Parser::done_end): Likewise.
+ 	* parse/rust-parse.h: Change function return type to AttributeBody
+ 	instead of a tuple (parse_doc_comment). Move enum binding powers from
+ 	impl file.
+ 	* parse/rust-parse-impl-attribute.hxx: New file.
+ 	* parse/rust-parse-impl-macro.hxx: New file.
+ 	* parse/rust-parse-impl-path.hxx: New file.
+ 	* parse/rust-parse-impl-pattern.hxx: New file.
+ 	* parse/rust-parse-impl-ttree.hxx: New file.
+ 	* parse/rust-parse-impl-utils.hxx: New file.
+ 	* parse/rust-parse-impl-expr.hxx: New file.
+ 
+ 2025-12-17  Pierre-Emmanuel Patry  <pierre-emmanuel.patry@embecosm.com>
+ 
+ 	* parse/rust-parse-impl.h (can_tok_start_type): Move function from ...
+ 	* parse/rust-parse-utils.h (can_tok_start_type): ... to here.
+ 
+ 2025-12-17  Pierre-Emmanuel Patry  <pierre-emmanuel.patry@embecosm.com>
+ 
+ 	* parse/rust-parse-impl.h (is_right_angle_tok): Move function ...
+ 	(Parser::parse_generic_params_in_angles): Change call.
+ 	(Parser::parse_for_lifetimes): Likewise.
+ 	(Parser::parse_path_generic_args): Likewise.
+ 	* parse/rust-parse-utils.h (is_right_angle_tok): ... to here.
+ 
+ 2025-12-17  Pierre-Emmanuel Patry  <pierre-emmanuel.patry@embecosm.com>
+ 
+ 	* rust-session-manager.cc (Session::enable_dump): Rework error message
+ 	and remove magic value.
+ 	(Session::handle_excluded_node): Remove static buffer size.
+ 
+ 2025-12-17  Pierre-Emmanuel Patry  <pierre-emmanuel.patry@embecosm.com>
+ 
+ 	* ast/rust-ast-collector.cc (TokenCollector::begin_describe_node):
+ 	Remove function.
+ 	(TokenCollector::end_describe_node): Likewise.
+ 	(TokenCollector::describe_node): Remove calls to begin/end.
+ 	* ast/rust-ast-collector.h: Specialize begin and end collect items. Add
+ 	more constructors to begin/end description.
+ 	* ast/rust-ast-dump.cc (Dump::Dump): Adapt to new configuration
+ 	options.
+ 	* ast/rust-ast-dump.h: Add new configuration options.
+ 	* rust-session-manager.cc (Session::dump_ast_pretty_internal): Use new
+ 	configuration options.
+ 
+ 2025-12-17  Pierre-Emmanuel Patry  <pierre-emmanuel.patry@embecosm.com>
+ 
+ 	* ast/rust-ast-collector.cc (TokenCollector::comment): Use comment kind
+ 	(TokenCollector::begin_internal_comment): Rename from this...
+ 	(TokenCollector::begin_describe_node): ... to this.
+ 	(TokenCollector::end_internal_comment): Rename from this...
+ 	(TokenCollector::end_describe_node): ... to this.
+ 	(TokenCollector::internal_comment): Rename from this...
+ 	(TokenCollector::describe_node): ... to this.
+ 	(TokenCollector::visit): Change name in function calls.
+ 	(TokenCollector::visit_closure_common): Likewise.
+ 	(TokenCollector::visit_loop_common): Likewise.
+ 	* ast/rust-ast-collector.h: Adapt function prototypes, add a new
+ 	collect item kind for node description.
+ 
+ 2025-12-17  Benjamin Thos  <benjamin.thos@epita.fr>
+ 
+ 	* ast/rust-ast-collector.cc (TokenCollector::internal_comment):
+ 		Wrapper function to add both  comment.
+ 	(TokenCollector::visit): call of the wrapper function.
+ 	(TokenCollector::visit_closure_common): Same.
+ 	(TokenCollector::visit_loop_common): Same.
+ 	* ast/rust-ast-collector.h: Prototype of the wrapper function
+ 
+ 2025-12-17  Benjamin Thos  <benjamin.thos@epita.fr>
+ 
+ 	* ast/rust-ast-collector.cc (TokenCollector::begin_internal_comment):
+ 	Change a boolean with an enum.
+ 	(TokenCollector::end_internal_comment): Likewise.
+ 	* ast/rust-ast-collector.h: Likewise + change include.
+ 	* ast/rust-ast-dump.cc (Dump::Dump): Change variable name.
+ 	* ast/rust-ast-dump.h: Likewise + replace vector with a set.
+ 	* rust-session-manager.cc (Session::enable_dump): Change variable
+ 	name.
+ 	(Session::handle_internal_blacklist): Change function name.
+ 	(Session::handle_excluded_node): Likewise.
+ 	(Session::dump_ast_pretty_internal): Change vector with a set.
+ 	* rust-session-manager.h (struct CompileOptions): Likewise + change
+ 	variable name.
+ 
+ 2025-12-17  Benjamin Thos  <benjamin.thos@epita.fr>
+ 
+ 	* ast/rust-ast-collector.cc (TokenCollector::begin_internal_comment):
+ 	Add internal comment to print node beginning.
+ 	(TokenCollector::end_internal_comment): Add internal comment to print
+ 	node end.
+ 	(TokenCollector::visit): Add the comments of the node visited.
+ 	(TokenCollector::visit_closure_common): Likewise.
+ 	(TokenCollector::visit_loop_common): Likewise.
+ 	* ast/rust-ast-collector.h: Add internal comment as a nes Kind.
+ 	* ast/rust-ast-dump.cc (Dump::Dump): add a Dump constructor to enable
+ 	internal.
+ 	* ast/rust-ast-dump.h: Add printing of internal comment in the dump
+ 	* rust-session-manager.cc (Session::enable_dump): Activate ast dump
+ 	and fill the blacklist.
+ 	(Session::handle_internal_blacklist): Parse the flag to get node to
+ 	be blacklisted.
+ 	(Session::compile_crate): Launch ast dump internal when asked.
+ 	(Session::dump_ast_pretty_internal): Call the visitor to dump
+ 	the internals.
+ 	* rust-session-manager.h (struct CompileOptions): add Interal in
+ 	Dump option enum.
+ 
+ 2025-12-17  Pierre-Emmanuel Patry  <pierre-emmanuel.patry@embecosm.com>
+ 
+ 	* ast/rust-expr.h: Use path locus.
+ 
+ 2025-12-17  Pierre-Emmanuel Patry  <pierre-emmanuel.patry@embecosm.com>
+ 
+ 	* parse/rust-parse-impl.h (Parser::parse_inner_attributes): Change
+ 	return type to avoid empty/error values that may break invariants in
+ 	the AST.
+ 	(Parser::parse_inner_attribute): Likewise.
+ 	(Parser::parse_outer_attribute): Likewise.
+ 	(Parser::parse_outer_attributes): Likewise.
+ 	(Parser::parse_attribute_body): Likewise.
+ 	(Parser::parse_simple_path): Likewise.
+ 	(Parser::parse_macro_invocation): Likewise.
+ 	(Parser::parse_visibility): Likewise.
+ 	(Parser::parse_use_tree): Likewise.
+ 	(Parser::parse_delim_token_tree): Likewise.
+ 	(Parser::parse_identifier_or_keyword_token): Likewise.
+ 	(Parser::parse_token_tree): Likewise.
+ 	(Parser::parse_macro_rules_def): Likewise.
+ 	(Parser::parse_decl_macro_def): Likewise.
+ 	(Parser::parse_macro_invocation): Likewise.
+ 	(Parser::parse_macro_rule): Likewise.
+ 	(Parser::parse_macro_matcher): Likewise.
+ 	(Parser::parse_type_path_segment): Likewise.
+ 	(Parser::parse_path_expr_segment): Likewise.
+ 	(Parser::parse_type): Likewise.
+ 	(Parser::parse_type_no_bounds): Likewise.
+ 	(Parser::parse_items): Circumvent GCC 5 to 7 bug.
+ 	(is_simple_path_segment): Move to utility file.
+ 	(token_id_matches_delims): Likewise.
+ 	(is_likely_path_next): Remove unused function.
+ 	(Parser::parse_attr_input): Return a structure instead of a tuple.
+ 	* expand/rust-macro-builtins-offset-of.cc: Adapt call to expected.
+ 	* ast/rust-ast.cc (AttributeParser::parse_path_meta_item): Use empty
+ 	vector when an error is encountered.
+ 	* expand/rust-macro-builtins-include.cc: Likewise.
+ 	* parse/rust-parse.h: Update prototypes.
+ 	* parse/rust-parse-impl-proc-macro.cc: Likewise.
+ 	* ast/rust-ast.h: Remove error state from Visibility.
+ 	* ast/rust-item.h: Use private visibility instead of error.
+ 	* ast/rust-macro.h: Likewise.
+ 	* expand/rust-macro-expand.cc: Likewise.
+ 	* hir/rust-ast-lower.cc: Remove error case.
+ 	* rust-session-manager.cc: Use private visibility
+ 	* parse/rust-parse-utils.h: New file.
+ 	* parse/rust-parse-error.h: New file.
+ 
  2025-12-12  Pietro Monteiro  <pietro@sociotechnical.xyz>
  
  	* lang.opt.urls: Regenerate.
diff -Nrcpad gcc-16-20251214/gcc/rust/ast/rust-ast-collector.cc gcc-16-20251221/gcc/rust/ast/rust-ast-collector.cc
*** gcc-16-20251214/gcc/rust/ast/rust-ast-collector.cc	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/rust/ast/rust-ast-collector.cc	Sun Dec 21 22:32:07 2025
***************
*** 23,29 ****
  #include "rust-expr.h"
  #include "rust-item.h"
  #include "rust-keyword-values.h"
- #include "rust-location.h"
  #include "rust-path.h"
  #include "rust-system.h"
  #include "rust-token.h"
--- 23,28 ----
*************** TokenCollector::decrement_indentation ()
*** 101,107 ****
  void
  TokenCollector::comment (std::string comment)
  {
!   tokens.emplace_back (comment);
  }
  
  void
--- 100,117 ----
  void
  TokenCollector::comment (std::string comment)
  {
!   tokens.emplace_back (CollectItem::make_comment (comment));
! }
! 
! void
! TokenCollector::describe_node (const std::string &node_name,
! 			       std::function<void ()> visitor)
! {
!   tokens.emplace_back (CollectItem::make_begin_node_description (node_name));
! 
!   visitor ();
! 
!   tokens.push_back (CollectItem::make_end_node_description (node_name));
  }
  
  void
*************** TokenCollector::visit (Visitable &v)
*** 113,303 ****
  void
  TokenCollector::visit (FunctionParam &param)
  {
!   visit_items_as_lines (param.get_outer_attrs ());
!   if (!param.is_variadic ())
!     {
!       visit (param.get_pattern ());
!       push (Rust::Token::make (COLON, UNDEF_LOCATION));
!       visit (param.get_type ());
!     }
!   else
!     {
!       if (param.has_name ())
! 	{
! 	  visit (param.get_pattern ());
! 	  push (Rust::Token::make (COLON, UNDEF_LOCATION));
! 	}
!       push (Rust::Token::make (ELLIPSIS, UNDEF_LOCATION));
!     }
  }
  
  void
  TokenCollector::visit (VariadicParam &param)
  {
!   if (param.has_pattern ())
!     {
!       visit (param.get_pattern ());
!       push (Rust::Token::make (COLON, UNDEF_LOCATION));
!     }
!   push (Rust::Token::make (ELLIPSIS, UNDEF_LOCATION));
  }
  
  void
  TokenCollector::visit (Attribute &attrib)
  {
!   push (Rust::Token::make (HASH, attrib.get_locus ()));
!   if (attrib.is_inner_attribute ())
!     push (Rust::Token::make (EXCLAM, UNDEF_LOCATION));
!   push (Rust::Token::make (LEFT_SQUARE, UNDEF_LOCATION));
!   visit (attrib.get_path ());
  
!   if (attrib.has_attr_input ())
!     {
!       switch (attrib.get_attr_input ().get_attr_input_type ())
! 	{
! 	case AST::AttrInput::AttrInputType::LITERAL:
! 	  {
! 	    visit (static_cast<AttrInputLiteral &> (attrib.get_attr_input ()));
! 	    break;
! 	  }
! 	case AST::AttrInput::AttrInputType::MACRO:
! 	  {
! 	    visit (static_cast<AttrInputMacro &> (attrib.get_attr_input ()));
! 	    break;
! 	  }
! 	case AST::AttrInput::AttrInputType::META_ITEM:
! 	  {
! 	    visit (static_cast<AttrInputMetaItemContainer &> (
! 	      attrib.get_attr_input ()));
! 	    break;
! 	  }
! 	case AST::AttrInput::AttrInputType::TOKEN_TREE:
  	  {
! 	    visit (static_cast<DelimTokenTree &> (attrib.get_attr_input ()));
! 	    break;
  	  }
! 	default:
! 	  rust_unreachable ();
! 	}
!     }
!   push (Rust::Token::make (RIGHT_SQUARE, UNDEF_LOCATION));
  }
  
  void
  TokenCollector::visit (SimplePath &path)
  {
!   if (path.has_opening_scope_resolution ())
!     {
!       push (Rust::Token::make (SCOPE_RESOLUTION, path.get_locus ()));
!     }
!   visit_items_joined_by_separator (path.get_segments (), SCOPE_RESOLUTION);
  }
  
  void
  TokenCollector::visit (SimplePathSegment &segment)
  {
!   auto name = segment.get_segment_name ();
!   if (segment.is_crate_path_seg ())
!     {
!       push (Rust::Token::make (CRATE, segment.get_locus ()));
!     }
!   else if (segment.is_super_path_seg ())
!     {
!       push (Rust::Token::make (SUPER, segment.get_locus ()));
!     }
!   else if (segment.is_lower_self_seg ())
!     {
!       push (Rust::Token::make (SELF, segment.get_locus ()));
!     }
!   else if (segment.is_big_self ())
!     {
!       push (Rust::Token::make (SELF_ALIAS, segment.get_locus ()));
!     }
!   else
!     {
!       push (
! 	Rust::Token::make_identifier (segment.get_locus (), std::move (name)));
!     }
  }
  
  void
  TokenCollector::visit (Visibility &vis)
  {
!   switch (vis.get_vis_type ())
!     {
!     case Visibility::PUB:
!       push (Rust::Token::make (PUB, vis.get_locus ()));
!       break;
!     case Visibility::PUB_CRATE:
!       push (Rust::Token::make (PUB, vis.get_locus ()));
!       push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
!       push (Rust::Token::make (CRATE, UNDEF_LOCATION));
!       push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
!       break;
!     case Visibility::PUB_SELF:
!       push (Rust::Token::make (PUB, vis.get_locus ()));
!       push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
!       push (Rust::Token::make (SELF, UNDEF_LOCATION));
!       push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
!       break;
!     case Visibility::PUB_SUPER:
!       push (Rust::Token::make (PUB, vis.get_locus ()));
!       push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
!       push (Rust::Token::make (SUPER, UNDEF_LOCATION));
!       push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
!       break;
!     case Visibility::PUB_IN_PATH:
!       push (Rust::Token::make (PUB, vis.get_locus ()));
!       push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
!       push (Rust::Token::make (IN, UNDEF_LOCATION));
!       visit (vis.get_path ());
!       push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
!       break;
!     case Visibility::PRIV:
!       break;
!     }
  }
  
  void
  TokenCollector::visit (std::vector<std::unique_ptr<GenericParam>> &params)
  {
!   push (Rust::Token::make (LEFT_ANGLE, UNDEF_LOCATION));
!   visit_items_joined_by_separator (params, COMMA);
!   push (Rust::Token::make (RIGHT_ANGLE, UNDEF_LOCATION));
  }
  
  void
  TokenCollector::visit (TupleField &field)
  {
!   for (auto attr : field.get_outer_attrs ())
!     {
!       visit (attr);
!     }
!   visit (field.get_visibility ());
!   visit (field.get_field_type ());
  }
  
  void
  TokenCollector::visit (StructField &field)
  {
!   for (auto attr : field.get_outer_attrs ())
!     {
!       visit (attr);
!     }
!   visit (field.get_visibility ());
!   auto name = field.get_field_name ().as_string ();
!   push (Rust::Token::make_identifier (field.get_locus (), std::move (name)));
!   push (Rust::Token::make (COLON, UNDEF_LOCATION));
!   visit (field.get_field_type ());
  }
  
  void
  TokenCollector::visit (std::vector<LifetimeParam> &for_lifetimes)
  {
!   push (Rust::Token::make (FOR, UNDEF_LOCATION));
!   push (Rust::Token::make (LEFT_ANGLE, UNDEF_LOCATION));
!   visit_items_joined_by_separator (for_lifetimes, COMMA);
!   push (Rust::Token::make (RIGHT_ANGLE, UNDEF_LOCATION));
  }
  
  void
--- 123,334 ----
  void
  TokenCollector::visit (FunctionParam &param)
  {
!   describe_node (std::string ("FunctionParam"), [this, &param] () {
!     visit_items_as_lines (param.get_outer_attrs ());
!     if (!param.is_variadic ())
!       {
! 	visit (param.get_pattern ());
! 	push (Rust::Token::make (COLON, UNDEF_LOCATION));
! 	visit (param.get_type ());
!       }
!     else
!       {
! 	if (param.has_name ())
! 	  {
! 	    visit (param.get_pattern ());
! 	    push (Rust::Token::make (COLON, UNDEF_LOCATION));
! 	  }
! 	push (Rust::Token::make (ELLIPSIS, UNDEF_LOCATION));
!       }
!   });
  }
  
  void
  TokenCollector::visit (VariadicParam &param)
  {
!   describe_node (std::string ("VariadicParam"), [this, &param] () {
!     if (param.has_pattern ())
!       {
! 	visit (param.get_pattern ());
! 	push (Rust::Token::make (COLON, UNDEF_LOCATION));
!       }
!     push (Rust::Token::make (ELLIPSIS, UNDEF_LOCATION));
!   });
  }
  
  void
  TokenCollector::visit (Attribute &attrib)
  {
!   describe_node (std::string ("Attribute"), [this, &attrib] () {
!     push (Rust::Token::make (HASH, attrib.get_locus ()));
!     if (attrib.is_inner_attribute ())
!       push (Rust::Token::make (EXCLAM, UNDEF_LOCATION));
!     push (Rust::Token::make (LEFT_SQUARE, UNDEF_LOCATION));
!     visit (attrib.get_path ());
  
!     if (attrib.has_attr_input ())
!       {
! 	switch (attrib.get_attr_input ().get_attr_input_type ())
  	  {
! 	  case AST::AttrInput::AttrInputType::LITERAL:
! 	    {
! 	      visit (
! 		static_cast<AttrInputLiteral &> (attrib.get_attr_input ()));
! 	      break;
! 	    }
! 	  case AST::AttrInput::AttrInputType::MACRO:
! 	    {
! 	      visit (static_cast<AttrInputMacro &> (attrib.get_attr_input ()));
! 	      break;
! 	    }
! 	  case AST::AttrInput::AttrInputType::META_ITEM:
! 	    {
! 	      visit (static_cast<AttrInputMetaItemContainer &> (
! 		attrib.get_attr_input ()));
! 	      break;
! 	    }
! 	  case AST::AttrInput::AttrInputType::TOKEN_TREE:
! 	    {
! 	      visit (static_cast<DelimTokenTree &> (attrib.get_attr_input ()));
! 	      break;
! 	    }
! 	  default:
! 	    rust_unreachable ();
  	  }
!       }
!     push (Rust::Token::make (RIGHT_SQUARE, UNDEF_LOCATION));
!   });
  }
  
  void
  TokenCollector::visit (SimplePath &path)
  {
!   describe_node (std::string ("SimplePath"), [this, &path] () {
!     if (path.has_opening_scope_resolution ())
!       {
! 	push (Rust::Token::make (SCOPE_RESOLUTION, path.get_locus ()));
!       }
!     visit_items_joined_by_separator (path.get_segments (), SCOPE_RESOLUTION);
!   });
  }
  
  void
  TokenCollector::visit (SimplePathSegment &segment)
  {
!   describe_node (std::string ("SimplePathSegment"), [this, &segment] () {
!     auto name = segment.get_segment_name ();
!     if (segment.is_crate_path_seg ())
!       {
! 	push (Rust::Token::make (CRATE, segment.get_locus ()));
!       }
!     else if (segment.is_super_path_seg ())
!       {
! 	push (Rust::Token::make (SUPER, segment.get_locus ()));
!       }
!     else if (segment.is_lower_self_seg ())
!       {
! 	push (Rust::Token::make (SELF, segment.get_locus ()));
!       }
!     else if (segment.is_big_self ())
!       {
! 	push (Rust::Token::make (SELF_ALIAS, segment.get_locus ()));
!       }
!     else
!       {
! 	push (Rust::Token::make_identifier (segment.get_locus (),
! 					    std::move (name)));
!       }
!   });
  }
  
  void
  TokenCollector::visit (Visibility &vis)
  {
!   describe_node (std::string ("Visibility"), [this, &vis] () {
!     switch (vis.get_vis_type ())
!       {
!       case Visibility::PUB:
! 	push (Rust::Token::make (PUB, vis.get_locus ()));
! 	break;
!       case Visibility::PUB_CRATE:
! 	push (Rust::Token::make (PUB, vis.get_locus ()));
! 	push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
! 	push (Rust::Token::make (CRATE, UNDEF_LOCATION));
! 	push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
! 	break;
!       case Visibility::PUB_SELF:
! 	push (Rust::Token::make (PUB, vis.get_locus ()));
! 	push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
! 	push (Rust::Token::make (SELF, UNDEF_LOCATION));
! 	push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
! 	break;
!       case Visibility::PUB_SUPER:
! 	push (Rust::Token::make (PUB, vis.get_locus ()));
! 	push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
! 	push (Rust::Token::make (SUPER, UNDEF_LOCATION));
! 	push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
! 	break;
!       case Visibility::PUB_IN_PATH:
! 	push (Rust::Token::make (PUB, vis.get_locus ()));
! 	push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
! 	push (Rust::Token::make (IN, UNDEF_LOCATION));
! 	visit (vis.get_path ());
! 	push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
! 	break;
!       case Visibility::PRIV:
! 	break;
!       }
!   });
  }
  
  void
  TokenCollector::visit (std::vector<std::unique_ptr<GenericParam>> &params)
  {
!   describe_node (std::string ("GenericParam"), [this, &params] () {
!     push (Rust::Token::make (LEFT_ANGLE, UNDEF_LOCATION));
!     visit_items_joined_by_separator (params, COMMA);
!     push (Rust::Token::make (RIGHT_ANGLE, UNDEF_LOCATION));
!   });
  }
  
  void
  TokenCollector::visit (TupleField &field)
  {
!   describe_node (std::string ("TupleField"), [this, &field] () {
!     for (auto attr : field.get_outer_attrs ())
!       {
! 	visit (attr);
!       }
!     visit (field.get_visibility ());
!     visit (field.get_field_type ());
!   });
  }
  
  void
  TokenCollector::visit (StructField &field)
  {
!   describe_node (std::string ("StructField"), [this, &field] () {
!     for (auto attr : field.get_outer_attrs ())
!       {
! 	visit (attr);
!       }
!     visit (field.get_visibility ());
!     auto name = field.get_field_name ().as_string ();
!     push (Rust::Token::make_identifier (field.get_locus (), std::move (name)));
!     push (Rust::Token::make (COLON, UNDEF_LOCATION));
!     visit (field.get_field_type ());
!   });
  }
  
  void
  TokenCollector::visit (std::vector<LifetimeParam> &for_lifetimes)
  {
!   describe_node (std::string ("LifetimeParam"), [this, &for_lifetimes] () {
!     push (Rust::Token::make (FOR, UNDEF_LOCATION));
!     push (Rust::Token::make (LEFT_ANGLE, UNDEF_LOCATION));
!     visit_items_joined_by_separator (for_lifetimes, COMMA);
!     push (Rust::Token::make (RIGHT_ANGLE, UNDEF_LOCATION));
!   });
  }
  
  void
*************** TokenCollector::visit (FunctionQualifier
*** 306,327 ****
    // Syntax:
    //    `const`? `async`? `unsafe`? (`extern` Abi?)?
    //    unsafe? (extern Abi?)?
! 
!   if (qualifiers.is_async ())
!     push (Rust::Token::make (ASYNC, qualifiers.get_locus ()));
!   if (qualifiers.is_const ())
!     push (Rust::Token::make (CONST, qualifiers.get_locus ()));
!   if (qualifiers.is_unsafe ())
!     push (Rust::Token::make (UNSAFE, qualifiers.get_locus ()));
!   if (qualifiers.is_extern ())
!     {
!       push (Rust::Token::make (EXTERN_KW, qualifiers.get_locus ()));
!       if (qualifiers.has_abi ())
! 	{
! 	  push (Rust::Token::make_string (UNDEF_LOCATION,
! 					  qualifiers.get_extern_abi ()));
! 	}
!     }
  }
  
  void
--- 337,359 ----
    // Syntax:
    //    `const`? `async`? `unsafe`? (`extern` Abi?)?
    //    unsafe? (extern Abi?)?
!   describe_node (std::string ("FunctionQualifiers"), [this, &qualifiers] () {
!     if (qualifiers.is_async ())
!       push (Rust::Token::make (ASYNC, qualifiers.get_locus ()));
!     if (qualifiers.is_const ())
!       push (Rust::Token::make (CONST, qualifiers.get_locus ()));
!     if (qualifiers.is_unsafe ())
!       push (Rust::Token::make (UNSAFE, qualifiers.get_locus ()));
!     if (qualifiers.is_extern ())
!       {
! 	push (Rust::Token::make (EXTERN_KW, qualifiers.get_locus ()));
! 	if (qualifiers.has_abi ())
! 	  {
! 	    push (Rust::Token::make_string (UNDEF_LOCATION,
! 					    qualifiers.get_extern_abi ()));
! 	  }
!       }
!   });
  }
  
  void
*************** TokenCollector::visit (MaybeNamedParam &
*** 330,355 ****
    // Syntax:
    //     OuterAttribute* ( ( IDENTIFIER | _ ) : )? Type
  
!   for (auto attr : param.get_outer_attrs ())
!     {
!       visit (attr);
!     }
!   auto param_name = param.get_name ().as_string ();
!   switch (param.get_param_kind ())
!     {
!     case MaybeNamedParam::UNNAMED:
!       break;
!     case MaybeNamedParam::IDENTIFIER:
!       push (
! 	Rust::Token::make_identifier (UNDEF_LOCATION, std::move (param_name)));
!       push (Rust::Token::make (COLON, UNDEF_LOCATION));
!       break;
!     case MaybeNamedParam::WILDCARD:
!       push (Rust::Token::make (UNDERSCORE, UNDEF_LOCATION));
!       push (Rust::Token::make (COLON, UNDEF_LOCATION));
!       break;
!     }
!   visit (param.get_type ());
  }
  
  void
--- 362,389 ----
    // Syntax:
    //     OuterAttribute* ( ( IDENTIFIER | _ ) : )? Type
  
!   describe_node (std::string ("MaybeNamedParam"), [this, &param] () {
!     for (auto attr : param.get_outer_attrs ())
!       {
! 	visit (attr);
!       }
!     auto param_name = param.get_name ().as_string ();
!     switch (param.get_param_kind ())
!       {
!       case MaybeNamedParam::UNNAMED:
! 	break;
!       case MaybeNamedParam::IDENTIFIER:
! 	push (Rust::Token::make_identifier (UNDEF_LOCATION,
! 					    std::move (param_name)));
! 	push (Rust::Token::make (COLON, UNDEF_LOCATION));
! 	break;
!       case MaybeNamedParam::WILDCARD:
! 	push (Rust::Token::make (UNDERSCORE, UNDEF_LOCATION));
! 	push (Rust::Token::make (COLON, UNDEF_LOCATION));
! 	break;
!       }
!     visit (param.get_type ());
!   });
  }
  
  void
*************** TokenCollector::visit (Token &tok)
*** 407,433 ****
  void
  TokenCollector::visit (DelimTokenTree &delim_tok_tree)
  {
!   for (auto &token : delim_tok_tree.to_token_stream ())
!     {
!       visit (token);
!     }
  }
  
  void
  TokenCollector::visit (AttrInputMetaItemContainer &container)
  {
!   for (auto &item : container.get_items ())
!     {
!       visit (item);
!     }
  }
  
  void
  TokenCollector::visit (IdentifierExpr &ident_expr)
  {
!   auto ident = ident_expr.get_ident ().as_string ();
!   push (
!     Rust::Token::make_identifier (ident_expr.get_locus (), std::move (ident)));
  }
  
  void
--- 441,474 ----
  void
  TokenCollector::visit (DelimTokenTree &delim_tok_tree)
  {
!   describe_node (std::string ("DelimTokenTree"), [this, &delim_tok_tree] () {
!     for (auto &token : delim_tok_tree.to_token_stream ())
!       {
! 	visit (token);
!       }
!   });
  }
  
  void
  TokenCollector::visit (AttrInputMetaItemContainer &container)
  {
!   describe_node (std::string ("AttrInputMetaItemContainer"),
! 		 [this, &container] () {
! 		   for (auto &item : container.get_items ())
! 		     {
! 		       visit (item);
! 		     }
! 		 });
  }
  
  void
  TokenCollector::visit (IdentifierExpr &ident_expr)
  {
!   describe_node (std::string ("IdentifierExpr"), [this, &ident_expr] () {
!     auto ident = ident_expr.get_ident ().as_string ();
!     push (Rust::Token::make_identifier (ident_expr.get_locus (),
! 					std::move (ident)));
!   });
  }
  
  void
*************** TokenCollector::visit (Lifetime &lifetim
*** 439,460 ****
    // 	| 'static
    // 	| '_
  
!   auto name = lifetime.get_lifetime_name ();
!   switch (lifetime.get_lifetime_type ())
!     {
!     case Lifetime::LifetimeType::NAMED:
!       push (
! 	Rust::Token::make_lifetime (lifetime.get_locus (), std::move (name)));
!       break;
!     case Lifetime::LifetimeType::STATIC:
!       push (Rust::Token::make_lifetime (lifetime.get_locus (),
! 					Values::Keywords::STATIC_KW));
!       break;
!     case Lifetime::LifetimeType::WILDCARD:
!       push (Rust::Token::make_lifetime (lifetime.get_locus (),
! 					Values::Keywords::UNDERSCORE));
!       break;
!     }
  }
  
  void
--- 480,503 ----
    // 	| 'static
    // 	| '_
  
!   describe_node (std::string ("Lifetime"), [this, &lifetime] () {
!     auto name = lifetime.get_lifetime_name ();
!     switch (lifetime.get_lifetime_type ())
!       {
!       case Lifetime::LifetimeType::NAMED:
! 	push (
! 	  Rust::Token::make_lifetime (lifetime.get_locus (), std::move (name)));
! 	break;
!       case Lifetime::LifetimeType::STATIC:
! 	push (Rust::Token::make_lifetime (lifetime.get_locus (),
! 					  Values::Keywords::STATIC_KW));
! 	break;
!       case Lifetime::LifetimeType::WILDCARD:
! 	push (Rust::Token::make_lifetime (lifetime.get_locus (),
! 					  Values::Keywords::UNDERSCORE));
! 	break;
!       }
!   });
  }
  
  void
*************** TokenCollector::visit (LifetimeParam &li
*** 466,484 ****
    //   ( Lifetime + )* Lifetime?
  
    // TODO what to do with outer attr? They are not mentioned in the reference.
  
!   visit_items_as_lines (lifetime_param.get_outer_attrs ());
!   auto lifetime = lifetime_param.get_lifetime ();
!   visit (lifetime);
! 
!   if (lifetime_param.has_lifetime_bounds ())
!     {
!       push (Rust::Token::make (COLON, UNDEF_LOCATION));
!       for (auto &bound : lifetime_param.get_lifetime_bounds ())
! 	{
! 	  visit (bound);
! 	}
!     }
  }
  
  void
--- 509,528 ----
    //   ( Lifetime + )* Lifetime?
  
    // TODO what to do with outer attr? They are not mentioned in the reference.
+   describe_node (std::string ("LifetimeParam"), [this, &lifetime_param] () {
+     visit_items_as_lines (lifetime_param.get_outer_attrs ());
+     auto lifetime = lifetime_param.get_lifetime ();
+     visit (lifetime);
  
!     if (lifetime_param.has_lifetime_bounds ())
!       {
! 	push (Rust::Token::make (COLON, UNDEF_LOCATION));
! 	for (auto &bound : lifetime_param.get_lifetime_bounds ())
! 	  {
! 	    visit (bound);
! 	  }
!       }
!   });
  }
  
  void
*************** TokenCollector::visit (ConstGenericParam
*** 486,562 ****
  {
    // Syntax:
    // const IDENTIFIER : Type ( = Block | IDENTIFIER | -?LITERAL )?
! 
!   visit_items_as_lines (param.get_outer_attrs ());
!   push (Rust::Token::make (CONST, param.get_locus ()));
!   auto id = param.get_name ().as_string ();
!   push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
!   push (Rust::Token::make (COLON, UNDEF_LOCATION));
!   if (param.has_type ())
!     visit (param.get_type ());
!   if (param.has_default_value ())
!     {
!       push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
!       visit (param.get_default_value_unchecked ());
!     }
  }
  
  void
  TokenCollector::visit (PathExprSegment &segment)
  {
!   visit (segment.get_ident_segment ());
!   if (segment.has_generic_args ())
!     {
!       auto generics = segment.get_generic_args ();
!       push (Rust::Token::make (SCOPE_RESOLUTION, segment.get_locus ()));
!       push (Rust::Token::make (LEFT_ANGLE, generics.get_locus ()));
  
!       auto &lifetime_args = generics.get_lifetime_args ();
!       auto &generic_args = generics.get_generic_args ();
!       auto &binding_args = generics.get_binding_args ();
  
!       visit_items_joined_by_separator (generic_args, COMMA);
  
!       if (!lifetime_args.empty ()
! 	  && (!generic_args.empty () || !binding_args.empty ()))
! 	{
! 	  push (Rust::Token::make (COMMA, UNDEF_LOCATION));
! 	}
  
!       visit_items_joined_by_separator (binding_args, COMMA);
  
!       if (!generic_args.empty () && !binding_args.empty ())
! 	{
! 	  push (Rust::Token::make (COMMA, UNDEF_LOCATION));
! 	}
  
!       visit_items_joined_by_separator (lifetime_args, COMMA);
  
!       push (Rust::Token::make (RIGHT_ANGLE, UNDEF_LOCATION));
!     }
  }
  
  void
  TokenCollector::visit (PathInExpression &path)
  {
!   if (path.is_lang_item ())
!     {
!       push (Rust::Token::make (TokenId::HASH, path.get_locus ()));
!       push (Rust::Token::make (TokenId::LEFT_SQUARE, path.get_locus ()));
!       push (Rust::Token::make_identifier (path.get_locus (), "lang"));
!       push (Rust::Token::make (TokenId::EQUAL, path.get_locus ()));
!       push (
! 	Rust::Token::make_string (path.get_locus (),
! 				  LangItem::ToString (path.get_lang_item ())));
!       push (Rust::Token::make (TokenId::RIGHT_SQUARE, path.get_locus ()));
  
!       return;
!     }
  
!   if (path.opening_scope_resolution ())
!     push (Rust::Token::make (SCOPE_RESOLUTION, path.get_locus ()));
  
!   visit_items_joined_by_separator (path.get_segments (), SCOPE_RESOLUTION);
  }
  
  void
--- 530,610 ----
  {
    // Syntax:
    // const IDENTIFIER : Type ( = Block | IDENTIFIER | -?LITERAL )?
!   describe_node (std::string ("ConstGenericParam"), [this, &param] () {
!     visit_items_as_lines (param.get_outer_attrs ());
!     push (Rust::Token::make (CONST, param.get_locus ()));
!     auto id = param.get_name ().as_string ();
!     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
!     push (Rust::Token::make (COLON, UNDEF_LOCATION));
!     if (param.has_type ())
!       visit (param.get_type ());
!     if (param.has_default_value ())
!       {
! 	push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
! 	visit (param.get_default_value_unchecked ());
!       }
!   });
  }
  
  void
  TokenCollector::visit (PathExprSegment &segment)
  {
!   describe_node (std::string ("PathExprSegment"), [this, &segment] () {
!     visit (segment.get_ident_segment ());
!     if (segment.has_generic_args ())
!       {
! 	auto generics = segment.get_generic_args ();
! 	push (Rust::Token::make (SCOPE_RESOLUTION, segment.get_locus ()));
! 	push (Rust::Token::make (LEFT_ANGLE, generics.get_locus ()));
  
! 	auto &lifetime_args = generics.get_lifetime_args ();
! 	auto &generic_args = generics.get_generic_args ();
! 	auto &binding_args = generics.get_binding_args ();
  
! 	visit_items_joined_by_separator (generic_args, COMMA);
  
! 	if (!lifetime_args.empty ()
! 	    && (!generic_args.empty () || !binding_args.empty ()))
! 	  {
! 	    push (Rust::Token::make (COMMA, UNDEF_LOCATION));
! 	  }
  
! 	visit_items_joined_by_separator (binding_args, COMMA);
  
! 	if (!generic_args.empty () && !binding_args.empty ())
! 	  {
! 	    push (Rust::Token::make (COMMA, UNDEF_LOCATION));
! 	  }
  
! 	visit_items_joined_by_separator (lifetime_args, COMMA);
  
! 	push (Rust::Token::make (RIGHT_ANGLE, UNDEF_LOCATION));
!       }
!   });
  }
  
  void
  TokenCollector::visit (PathInExpression &path)
  {
!   describe_node (std::string ("PathInExpression"), [this, &path] () {
!     if (path.is_lang_item ())
!       {
! 	push (Rust::Token::make (TokenId::HASH, path.get_locus ()));
! 	push (Rust::Token::make (TokenId::LEFT_SQUARE, path.get_locus ()));
! 	push (Rust::Token::make_identifier (path.get_locus (), "lang"));
! 	push (Rust::Token::make (TokenId::EQUAL, path.get_locus ()));
! 	push (Rust::Token::make_string (
! 	  path.get_locus (), LangItem::ToString (path.get_lang_item ())));
! 	push (Rust::Token::make (TokenId::RIGHT_SQUARE, path.get_locus ()));
  
! 	return;
!       }
  
!     if (path.opening_scope_resolution ())
!       push (Rust::Token::make (SCOPE_RESOLUTION, path.get_locus ()));
  
!     visit_items_joined_by_separator (path.get_segments (), SCOPE_RESOLUTION);
!   });
  }
  
  void
*************** TokenCollector::visit (TypePathSegment &
*** 564,577 ****
  {
    // Syntax:
    //    PathIdentSegment
! 
!   auto locus = segment.is_lang_item ()
! 		 ? segment.get_locus ()
! 		 : segment.get_ident_segment ().get_locus ();
!   auto segment_string = segment.is_lang_item ()
! 			  ? LangItem::PrettyString (segment.get_lang_item ())
! 			  : segment.get_ident_segment ().as_string ();
!   push (Rust::Token::make_identifier (locus, std::move (segment_string)));
  }
  
  void
--- 612,626 ----
  {
    // Syntax:
    //    PathIdentSegment
!   describe_node (std::string ("TypePathSegment"), [this, &segment] () {
!     auto locus = segment.is_lang_item ()
! 		   ? segment.get_locus ()
! 		   : segment.get_ident_segment ().get_locus ();
!     auto segment_string = segment.is_lang_item ()
! 			    ? LangItem::PrettyString (segment.get_lang_item ())
! 			    : segment.get_ident_segment ().as_string ();
!     push (Rust::Token::make_identifier (locus, std::move (segment_string)));
!   });
  }
  
  void
*************** TokenCollector::visit (TypePathSegmentGe
*** 582,617 ****
    // GenericArgs :
    //    `<` `>`
    //    | `<` ( GenericArg `,` )* GenericArg `,`? `>`
  
!   auto locus = segment.is_lang_item ()
! 		 ? segment.get_locus ()
! 		 : segment.get_ident_segment ().get_locus ();
!   auto segment_string = segment.is_lang_item ()
! 			  ? LangItem::PrettyString (segment.get_lang_item ())
! 			  : segment.get_ident_segment ().as_string ();
!   push (Rust::Token::make_identifier (locus, std::move (segment_string)));
! 
!   if (segment.get_separating_scope_resolution ())
!     push (Rust::Token::make (SCOPE_RESOLUTION, UNDEF_LOCATION));
  
!   push (Rust::Token::make (LEFT_ANGLE, UNDEF_LOCATION));
  
!   {
!     auto &lifetime_args = segment.get_generic_args ().get_lifetime_args ();
!     auto &generic_args = segment.get_generic_args ().get_generic_args ();
!     auto &binding_args = segment.get_generic_args ().get_binding_args ();
  
!     visit_items_joined_by_separator (lifetime_args, COMMA);
!     if (!lifetime_args.empty ()
! 	&& (!generic_args.empty () || !binding_args.empty ()))
!       push (Rust::Token::make (COMMA, UNDEF_LOCATION));
!     visit_items_joined_by_separator (generic_args, COMMA);
!     if (!generic_args.empty () && !binding_args.empty ())
!       push (Rust::Token::make (COMMA, UNDEF_LOCATION));
!     visit_items_joined_by_separator (binding_args, COMMA);
!   }
  
!   push (Rust::Token::make (RIGHT_ANGLE, UNDEF_LOCATION));
  }
  
  void
--- 631,669 ----
    // GenericArgs :
    //    `<` `>`
    //    | `<` ( GenericArg `,` )* GenericArg `,`? `>`
+   describe_node (std::string ("TypePathSegmentGeneric"), [this, &segment] () {
+     auto ident_segment = segment.get_ident_segment ();
+     auto id = ident_segment.as_string ();
+     push (Rust::Token::make_identifier (ident_segment.get_locus (),
+ 					std::move (id)));
  
!     auto locus = segment.is_lang_item ()
! 		   ? segment.get_locus ()
! 		   : segment.get_ident_segment ().get_locus ();
!     auto segment_string = segment.is_lang_item ()
! 			    ? LangItem::PrettyString (segment.get_lang_item ())
! 			    : segment.get_ident_segment ().as_string ();
!     push (Rust::Token::make_identifier (locus, std::move (segment_string)));
  
!     push (Rust::Token::make (LEFT_ANGLE, UNDEF_LOCATION));
  
!     {
!       auto &lifetime_args = segment.get_generic_args ().get_lifetime_args ();
!       auto &generic_args = segment.get_generic_args ().get_generic_args ();
!       auto &binding_args = segment.get_generic_args ().get_binding_args ();
  
!       visit_items_joined_by_separator (lifetime_args, COMMA);
!       if (!lifetime_args.empty ()
! 	  && (!generic_args.empty () || !binding_args.empty ()))
! 	push (Rust::Token::make (COMMA, UNDEF_LOCATION));
!       visit_items_joined_by_separator (generic_args, COMMA);
!       if (!generic_args.empty () && !binding_args.empty ())
! 	push (Rust::Token::make (COMMA, UNDEF_LOCATION));
!       visit_items_joined_by_separator (binding_args, COMMA);
!     }
  
!     push (Rust::Token::make (RIGHT_ANGLE, UNDEF_LOCATION));
!   });
  }
  
  void
*************** TokenCollector::visit (GenericArgsBindin
*** 619,652 ****
  {
    // Syntax:
    //    IDENTIFIER `=` Type
!   auto identifier = binding.get_identifier ().as_string ();
!   push (Rust::Token::make_identifier (binding.get_locus (),
! 				      std::move (identifier)));
  
!   push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
!   visit (binding.get_type ());
  }
  
  void
  TokenCollector::visit (GenericArg &arg)
  {
!   // `GenericArg` implements `accept_vis` but it is not useful for this case as
!   // it ignores unresolved cases (`Kind::Either`).
!   switch (arg.get_kind ())
!     {
!     case GenericArg::Kind::Const:
!       visit (arg.get_expression ());
!       break;
!     case GenericArg::Kind::Type:
!       visit (arg.get_type ());
!       break;
!     case GenericArg::Kind::Either:
        {
! 	auto path = arg.get_path ();
! 	push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (path)));
        }
!       break;
!     }
  }
  
  void
--- 671,709 ----
  {
    // Syntax:
    //    IDENTIFIER `=` Type
!   describe_node (std::string ("GenericArgsBinding"), [this, &binding] () {
!     auto identifier = binding.get_identifier ().as_string ();
!     push (Rust::Token::make_identifier (binding.get_locus (),
! 					std::move (identifier)));
  
!     push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
!     visit (binding.get_type ());
!   });
  }
  
  void
  TokenCollector::visit (GenericArg &arg)
  {
!   // `GenericArg` implements `accept_vis` but it is not useful for this case
!   // as it ignores unresolved cases (`Kind::Either`).
!   describe_node (std::string ("GenericArg"), [this, &arg] () {
!     switch (arg.get_kind ())
        {
!       case GenericArg::Kind::Const:
! 	visit (arg.get_expression ());
! 	break;
!       case GenericArg::Kind::Type:
! 	visit (arg.get_type ());
! 	break;
!       case GenericArg::Kind::Either:
! 	{
! 	  auto path = arg.get_path ();
! 	  push (
! 	    Rust::Token::make_identifier (UNDEF_LOCATION, std::move (path)));
! 	}
! 	break;
        }
!   });
  }
  
  void
*************** TokenCollector::visit (TypePathSegmentFu
*** 654,670 ****
  {
    // Syntax:
    //   PathIdentSegment `::`? (TypePathFn)?
  
!   auto ident_segment = segment.get_ident_segment ();
!   auto id = ident_segment.as_string ();
!   push (
!     Rust::Token::make_identifier (ident_segment.get_locus (), std::move (id)));
! 
!   if (segment.get_separating_scope_resolution ())
!     push (Rust::Token::make (SCOPE_RESOLUTION, UNDEF_LOCATION));
  
!   if (!segment.is_ident_only ())
!     visit (segment.get_type_path_function ());
  }
  
  void
--- 711,728 ----
  {
    // Syntax:
    //   PathIdentSegment `::`? (TypePathFn)?
+   describe_node (std::string ("TypePathSegmentFunction"), [this, &segment] () {
+     auto ident_segment = segment.get_ident_segment ();
+     auto id = ident_segment.as_string ();
+     push (Rust::Token::make_identifier (ident_segment.get_locus (),
+ 					std::move (id)));
  
!     if (segment.get_separating_scope_resolution ())
!       push (Rust::Token::make (SCOPE_RESOLUTION, UNDEF_LOCATION));
  
!     if (!segment.is_ident_only ())
!       visit (segment.get_type_path_function ());
!   });
  }
  
  void
*************** TokenCollector::visit (TypePathFunction
*** 674,690 ****
    //   `(` TypePathFnInputs? `)` (`->` Type)?
    // TypePathFnInputs :
    //   Type (`,` Type)* `,`?
  
!   push (Rust::Token::make (LEFT_PAREN, type_path_fn.get_locus ()));
!   if (type_path_fn.has_inputs ())
!     visit_items_joined_by_separator (type_path_fn.get_params (), COMMA);
!   push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
! 
!   if (type_path_fn.has_return_type ())
!     {
!       push (Rust::Token::make (RETURN_TYPE, UNDEF_LOCATION));
!       visit (type_path_fn.get_return_type ());
!     }
  }
  
  void
--- 732,749 ----
    //   `(` TypePathFnInputs? `)` (`->` Type)?
    // TypePathFnInputs :
    //   Type (`,` Type)* `,`?
+   describe_node (std::string ("TypePathFunction"), [this, &type_path_fn] () {
+     push (Rust::Token::make (LEFT_PAREN, type_path_fn.get_locus ()));
+     if (type_path_fn.has_inputs ())
+       visit_items_joined_by_separator (type_path_fn.get_params (), COMMA);
+     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
  
!     if (type_path_fn.has_return_type ())
!       {
! 	push (Rust::Token::make (RETURN_TYPE, UNDEF_LOCATION));
! 	visit (type_path_fn.get_return_type ());
!       }
!   });
  }
  
  void
*************** TokenCollector::visit (TypePath &path)
*** 692,767 ****
  {
    // Syntax:
    //    `::`? TypePathSegment (`::` TypePathSegment)*
  
!   if (path.has_opening_scope_resolution_op ())
!     push (Rust::Token::make (SCOPE_RESOLUTION, path.get_locus ()));
! 
!   visit_items_joined_by_separator (path.get_segments (), SCOPE_RESOLUTION);
  }
  
  void
  TokenCollector::visit (PathIdentSegment &segment)
  {
!   if (segment.is_super_path_seg ())
!     {
!       push (Rust::Token::make (SUPER, segment.get_locus ()));
!     }
!   else if (segment.is_crate_path_seg ())
!     {
!       push (Rust::Token::make (CRATE, segment.get_locus ()));
!     }
!   else if (segment.is_lower_self_seg ())
!     {
!       push (Rust::Token::make (SELF, segment.get_locus ()));
!     }
!   else if (segment.is_big_self_seg ())
!     {
!       push (Rust::Token::make (SELF_ALIAS, segment.get_locus ()));
!     }
!   else
!     {
!       auto id = segment.as_string ();
!       push (
! 	Rust::Token::make_identifier (segment.get_locus (), std::move (id)));
!     }
  }
  
  void
  TokenCollector::visit (QualifiedPathInExpression &path)
  {
!   visit (path.get_qualified_path_type ());
!   for (auto &segment : path.get_segments ())
!     {
!       push (Rust::Token::make (SCOPE_RESOLUTION, UNDEF_LOCATION));
!       visit (segment);
!     }
  }
  
  void
  TokenCollector::visit (QualifiedPathType &path)
  {
!   push (Rust::Token::make (LEFT_ANGLE, path.get_locus ()));
!   visit (path.get_type ());
!   if (path.has_as_clause ())
!     {
!       push (Rust::Token::make (AS, UNDEF_LOCATION));
!       visit (path.get_as_type_path ());
!     }
!   push (Rust::Token::make (RIGHT_ANGLE, UNDEF_LOCATION));
  }
  
  void
  TokenCollector::visit (QualifiedPathInType &path)
  {
!   visit (path.get_qualified_path_type ());
  
!   push (Rust::Token::make (SCOPE_RESOLUTION, UNDEF_LOCATION));
!   visit (path.get_associated_segment ());
!   for (auto &segment : path.get_segments ())
!     {
!       push (Rust::Token::make (SCOPE_RESOLUTION, UNDEF_LOCATION));
!       visit (segment);
!     }
  }
  
  void
--- 751,835 ----
  {
    // Syntax:
    //    `::`? TypePathSegment (`::` TypePathSegment)*
+   describe_node (std::string ("TypePath"), [this, &path] () {
+     if (path.has_opening_scope_resolution_op ())
+       push (Rust::Token::make (SCOPE_RESOLUTION, path.get_locus ()));
  
!     visit_items_joined_by_separator (path.get_segments (), SCOPE_RESOLUTION);
!   });
  }
  
  void
  TokenCollector::visit (PathIdentSegment &segment)
  {
!   describe_node (std::string ("PathIdentSegment"), [this, &segment] () {
!     if (segment.is_super_path_seg ())
!       {
! 	push (Rust::Token::make (SUPER, segment.get_locus ()));
!       }
!     else if (segment.is_crate_path_seg ())
!       {
! 	push (Rust::Token::make (CRATE, segment.get_locus ()));
!       }
!     else if (segment.is_lower_self_seg ())
!       {
! 	push (Rust::Token::make (SELF, segment.get_locus ()));
!       }
!     else if (segment.is_big_self_seg ())
!       {
! 	push (Rust::Token::make (SELF_ALIAS, segment.get_locus ()));
!       }
!     else
!       {
! 	auto id = segment.as_string ();
! 	push (
! 	  Rust::Token::make_identifier (segment.get_locus (), std::move (id)));
!       }
!   });
  }
  
  void
  TokenCollector::visit (QualifiedPathInExpression &path)
  {
!   describe_node (std::string ("QualifiedPathInExpression"), [this, &path] () {
!     visit (path.get_qualified_path_type ());
!     for (auto &segment : path.get_segments ())
!       {
! 	push (Rust::Token::make (SCOPE_RESOLUTION, UNDEF_LOCATION));
! 	visit (segment);
!       }
!   });
  }
  
  void
  TokenCollector::visit (QualifiedPathType &path)
  {
!   describe_node (std::string ("QualifiedPathType"), [this, &path] () {
!     push (Rust::Token::make (LEFT_ANGLE, path.get_locus ()));
!     visit (path.get_type ());
!     if (path.has_as_clause ())
!       {
! 	push (Rust::Token::make (AS, UNDEF_LOCATION));
! 	visit (path.get_as_type_path ());
!       }
!     push (Rust::Token::make (RIGHT_ANGLE, UNDEF_LOCATION));
!   });
  }
  
  void
  TokenCollector::visit (QualifiedPathInType &path)
  {
!   describe_node (std::string ("QualifiedPathInType"), [this, &path] () {
!     visit (path.get_qualified_path_type ());
  
!     push (Rust::Token::make (SCOPE_RESOLUTION, UNDEF_LOCATION));
!     visit (path.get_associated_segment ());
!     for (auto &segment : path.get_segments ())
!       {
! 	push (Rust::Token::make (SCOPE_RESOLUTION, UNDEF_LOCATION));
! 	visit (segment);
!       }
!   });
  }
  
  void
*************** TokenCollector::visit (Literal &lit, loc
*** 815,1179 ****
  void
  TokenCollector::visit (LiteralExpr &expr)
  {
!   auto lit = expr.get_literal ();
!   visit (lit, expr.get_locus ());
  }
  
  void
  TokenCollector::visit (AttrInputLiteral &literal)
  {
!   push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
!   visit (literal.get_literal ());
  }
  
  void
  TokenCollector::visit (AttrInputMacro &macro)
  {
!   push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
!   visit (macro.get_macro ());
  }
  
  void
  TokenCollector::visit (MetaItemLitExpr &item)
  {
!   auto lit = item.get_literal ();
!   visit (lit);
  }
  
  void
  TokenCollector::visit (MetaItemPathExpr &item)
  {
!   auto &path = item.get_path ();
!   auto &expr = item.get_expr ();
!   visit (path);
!   push (Rust::Token::make (EQUAL, item.get_locus ()));
!   visit (expr);
  }
  
  void
  TokenCollector::visit (BorrowExpr &expr)
  {
!   push (Rust::Token::make (AMP, expr.get_locus ()));
!   if (expr.get_is_double_borrow ())
!     push (Rust::Token::make (AMP, UNDEF_LOCATION));
  
!   if (expr.is_raw_borrow ())
!     {
!       push (Rust::Token::make_identifier (expr.get_locus (),
! 					  Values::WeakKeywords::RAW));
!       if (expr.get_is_mut ())
! 	push (Rust::Token::make (MUT, UNDEF_LOCATION));
!       else
! 	push (Rust::Token::make (CONST, UNDEF_LOCATION));
!     }
!   else
!     {
!       if (expr.get_is_mut ())
! 	push (Rust::Token::make (MUT, UNDEF_LOCATION));
!     }
  
!   if (expr.has_borrow_expr ())
!     visit (expr.get_borrowed_expr ());
  }
  
  void
  TokenCollector::visit (DereferenceExpr &expr)
  {
!   push (Rust::Token::make (ASTERISK, expr.get_locus ()));
!   visit (expr.get_dereferenced_expr ());
  }
  
  void
  TokenCollector::visit (ErrorPropagationExpr &expr)
  {
!   visit (expr.get_propagating_expr ());
!   push (Rust::Token::make (QUESTION_MARK, expr.get_locus ()));
  }
  
  void
  TokenCollector::visit (NegationExpr &expr)
  {
!   switch (expr.get_expr_type ())
!     {
!     case NegationOperator::NEGATE:
!       push (Rust::Token::make (MINUS, expr.get_locus ()));
!       break;
!     case NegationOperator::NOT:
!       push (Rust::Token::make (EXCLAM, expr.get_locus ()));
!       break;
!     }
!   visit (expr.get_negated_expr ());
  }
  
  void
  TokenCollector::visit (ArithmeticOrLogicalExpr &expr)
  {
!   visit (expr.get_left_expr ());
!   switch (expr.get_expr_type ())
!     {
!     case ArithmeticOrLogicalOperator::ADD:
!       push (Rust::Token::make (PLUS, expr.get_locus ()));
!       break;
  
!     case ArithmeticOrLogicalOperator::SUBTRACT:
!       push (Rust::Token::make (MINUS, expr.get_locus ()));
!       break;
  
!     case ArithmeticOrLogicalOperator::MULTIPLY:
!       push (Rust::Token::make (ASTERISK, expr.get_locus ()));
!       break;
  
!     case ArithmeticOrLogicalOperator::DIVIDE:
!       push (Rust::Token::make (DIV, expr.get_locus ()));
!       break;
  
!     case ArithmeticOrLogicalOperator::MODULUS:
!       push (Rust::Token::make (PERCENT, expr.get_locus ()));
!       break;
  
!     case ArithmeticOrLogicalOperator::BITWISE_AND:
!       push (Rust::Token::make (AMP, expr.get_locus ()));
!       break;
  
!     case ArithmeticOrLogicalOperator::BITWISE_OR:
!       push (Rust::Token::make (PIPE, expr.get_locus ()));
!       break;
  
!     case ArithmeticOrLogicalOperator::BITWISE_XOR:
!       push (Rust::Token::make (CARET, expr.get_locus ()));
!       break;
  
!     case ArithmeticOrLogicalOperator::LEFT_SHIFT:
!       push (Rust::Token::make (LEFT_SHIFT, expr.get_locus ()));
!       break;
  
!     case ArithmeticOrLogicalOperator::RIGHT_SHIFT:
!       push (Rust::Token::make (RIGHT_SHIFT, expr.get_locus ()));
!       break;
!     }
  
!   visit (expr.get_right_expr ());
  }
  
  void
  TokenCollector::visit (ComparisonExpr &expr)
  {
!   visit (expr.get_left_expr ());
  
!   switch (expr.get_expr_type ())
!     {
!     case ComparisonOperator::EQUAL:
!       push (Rust::Token::make (EQUAL_EQUAL, expr.get_locus ()));
!       break;
!     case ComparisonOperator::NOT_EQUAL:
!       push (Rust::Token::make (NOT_EQUAL, expr.get_locus ()));
!       break;
!     case ComparisonOperator::GREATER_THAN:
!       push (Rust::Token::make (RIGHT_ANGLE, expr.get_locus ()));
!       break;
!     case ComparisonOperator::LESS_THAN:
!       push (Rust::Token::make (LEFT_ANGLE, expr.get_locus ()));
!       break;
!     case ComparisonOperator::GREATER_OR_EQUAL:
!       push (Rust::Token::make (GREATER_OR_EQUAL, expr.get_locus ()));
!       break;
  
!     case ComparisonOperator::LESS_OR_EQUAL:
!       push (Rust::Token::make (LESS_OR_EQUAL, expr.get_locus ()));
!       break;
!     }
!   visit (expr.get_right_expr ());
  }
  
  void
  TokenCollector::visit (LazyBooleanExpr &expr)
  {
!   visit (expr.get_left_expr ());
  
!   switch (expr.get_expr_type ())
!     {
!     case LazyBooleanOperator::LOGICAL_AND:
!       push (Rust::Token::make (LOGICAL_AND, expr.get_locus ()));
!       break;
!     case LazyBooleanOperator::LOGICAL_OR:
!       push (Rust::Token::make (OR, expr.get_locus ()));
!       break;
!     }
  
!   visit (expr.get_right_expr ());
  }
  
  void
  TokenCollector::visit (TypeCastExpr &expr)
  {
!   visit (expr.get_casted_expr ());
!   push (Rust::Token::make (AS, expr.get_locus ()));
!   visit (expr.get_type_to_cast_to ());
  }
  
  void
  TokenCollector::visit (AssignmentExpr &expr)
  {
!   expr.visit_lhs (*this);
!   push (Rust::Token::make (EQUAL, expr.get_locus ()));
!   expr.visit_rhs (*this);
  }
  
  void
  TokenCollector::visit (CompoundAssignmentExpr &expr)
  {
!   visit (expr.get_left_expr ());
  
!   switch (expr.get_expr_type ())
!     {
!     case CompoundAssignmentOperator::ADD:
!       push (Rust::Token::make (PLUS_EQ, expr.get_locus ()));
!       break;
!     case CompoundAssignmentOperator::SUBTRACT:
!       push (Rust::Token::make (MINUS_EQ, expr.get_locus ()));
!       break;
!     case CompoundAssignmentOperator::MULTIPLY:
!       push (Rust::Token::make (ASTERISK_EQ, expr.get_locus ()));
!       break;
!     case CompoundAssignmentOperator::DIVIDE:
!       push (Rust::Token::make (DIV_EQ, expr.get_locus ()));
!       break;
!     case CompoundAssignmentOperator::MODULUS:
!       push (Rust::Token::make (PERCENT_EQ, expr.get_locus ()));
!       break;
!     case CompoundAssignmentOperator::BITWISE_AND:
!       push (Rust::Token::make (AMP_EQ, expr.get_locus ()));
!       break;
!     case CompoundAssignmentOperator::BITWISE_OR:
!       push (Rust::Token::make (PIPE_EQ, expr.get_locus ()));
!       break;
!     case CompoundAssignmentOperator::BITWISE_XOR:
!       push (Rust::Token::make (CARET_EQ, expr.get_locus ()));
!       break;
!     case CompoundAssignmentOperator::LEFT_SHIFT:
!       push (Rust::Token::make (LEFT_SHIFT_EQ, expr.get_locus ()));
!       break;
!     case CompoundAssignmentOperator::RIGHT_SHIFT:
!       push (Rust::Token::make (RIGHT_SHIFT_EQ, expr.get_locus ()));
!       break;
!     }
!   visit (expr.get_right_expr ());
  }
  
  void
  TokenCollector::visit (GroupedExpr &expr)
  {
!   push (Rust::Token::make (LEFT_PAREN, expr.get_locus ()));
!   visit (expr.get_expr_in_parens ());
!   push (Rust::Token::make (RIGHT_PAREN, expr.get_locus ()));
  }
  
  void
  TokenCollector::visit (ArrayElemsValues &elems)
  {
!   visit_items_joined_by_separator (elems.get_values (), COMMA);
  }
  
  void
  TokenCollector::visit (ArrayElemsCopied &elems)
  {
!   visit (elems.get_elem_to_copy ());
!   push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
!   visit (elems.get_num_copies ());
  }
  
  void
  TokenCollector::visit (ArrayExpr &expr)
  {
!   push (Rust::Token::make (LEFT_SQUARE, expr.get_locus ()));
!   visit (expr.get_array_elems ());
!   push (Rust::Token::make (RIGHT_SQUARE, UNDEF_LOCATION));
  }
  
  void
  TokenCollector::visit (ArrayIndexExpr &expr)
  {
!   visit (expr.get_array_expr ());
!   push (Rust::Token::make (LEFT_SQUARE, expr.get_locus ()));
!   visit (expr.get_index_expr ());
!   push (Rust::Token::make (RIGHT_SQUARE, UNDEF_LOCATION));
  }
  
  void
  TokenCollector::visit (TupleExpr &expr)
  {
!   visit_items_as_lines (expr.get_outer_attrs ());
!   push (Rust::Token::make (LEFT_PAREN, expr.get_locus ()));
!   visit_items_joined_by_separator (expr.get_tuple_elems (), COMMA);
!   push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
  }
  
  void
  TokenCollector::visit (TupleIndexExpr &expr)
  {
!   visit (expr.get_tuple_expr ());
!   push (Rust::Token::make (DOT, expr.get_locus ()));
!   push (Rust::Token::make_int (UNDEF_LOCATION,
! 			       std::to_string (expr.get_tuple_index ())));
  }
  
  void
  TokenCollector::visit (StructExprStruct &expr)
  {
!   visit (expr.get_struct_name ());
  }
  
  void
  TokenCollector::visit (StructExprFieldIdentifier &expr)
  {
!   visit_items_as_lines (expr.get_outer_attrs ());
!   auto id = expr.get_field_name ().as_string ();
!   push (Rust::Token::make_identifier (expr.get_locus (), std::move (id)));
  }
  
  void
  TokenCollector::visit (StructExprFieldIdentifierValue &expr)
  {
!   visit_items_as_lines (expr.get_outer_attrs ());
!   auto id = expr.get_field_name ();
!   push (Rust::Token::make_identifier (expr.get_locus (), std::move (id)));
!   push (Rust::Token::make (COLON, UNDEF_LOCATION));
!   visit (expr.get_value ());
  }
  
  void
  TokenCollector::visit (StructExprFieldIndexValue &expr)
  {
!   visit_items_as_lines (expr.get_outer_attrs ());
!   push (Rust::Token::make_int (expr.get_locus (),
! 			       std::to_string (expr.get_index ())));
!   push (Rust::Token::make (COLON, UNDEF_LOCATION));
!   visit (expr.get_value ());
  }
  
  void
  TokenCollector::visit (StructBase &base)
  {
!   push (Rust::Token::make (DOT_DOT, UNDEF_LOCATION));
!   visit (base.get_base_struct ());
  }
  
  void
  TokenCollector::visit (StructExprStructFields &expr)
  {
!   visit (expr.get_struct_name ());
!   push (Rust::Token::make (LEFT_CURLY, expr.get_locus ()));
!   visit_items_joined_by_separator (expr.get_fields (), COMMA);
!   if (expr.has_struct_base ())
!     {
!       push (Rust::Token::make (COMMA, UNDEF_LOCATION));
!       visit (expr.get_struct_base ());
!     }
!   else
!     {
!       trailing_comma ();
!     }
!   push (Rust::Token::make (RIGHT_CURLY, expr.get_locus ()));
  }
  
  void
--- 883,1318 ----
  void
  TokenCollector::visit (LiteralExpr &expr)
  {
!   describe_node (std::string ("LiteralExpr"), [this, &expr] () {
!     auto lit = expr.get_literal ();
!     visit (lit, expr.get_locus ());
!   });
  }
  
  void
  TokenCollector::visit (AttrInputLiteral &literal)
  {
!   describe_node (std::string ("AttrInputLiteral"), [this, &literal] () {
!     push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
!     visit (literal.get_literal ());
!   });
  }
  
  void
  TokenCollector::visit (AttrInputMacro &macro)
  {
!   describe_node (std::string ("AttrInputMacro"), [this, &macro] () {
!     push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
!     visit (macro.get_macro ());
!   });
  }
  
  void
  TokenCollector::visit (MetaItemLitExpr &item)
  {
!   describe_node (std::string ("MetaItemLitExpr"), [this, &item] () {
!     auto lit = item.get_literal ();
!     visit (lit);
!   });
  }
  
  void
  TokenCollector::visit (MetaItemPathExpr &item)
  {
!   describe_node (std::string ("MetaItemPathLit"), [this, &item] () {
!     auto &path = item.get_path ();
!     auto &expr = item.get_expr ();
!     visit (path);
!     push (Rust::Token::make (EQUAL, item.get_locus ()));
!     visit (expr);
!   });
  }
  
  void
  TokenCollector::visit (BorrowExpr &expr)
  {
!   describe_node (std::string ("BorrowExpr"), [this, &expr] () {
!     push (Rust::Token::make (AMP, expr.get_locus ()));
!     if (expr.get_is_double_borrow ())
!       push (Rust::Token::make (AMP, UNDEF_LOCATION));
  
!     if (expr.is_raw_borrow ())
!       {
! 	push (Rust::Token::make_identifier (expr.get_locus (),
! 					    Values::WeakKeywords::RAW));
! 	if (expr.get_is_mut ())
! 	  push (Rust::Token::make (MUT, UNDEF_LOCATION));
! 	else
! 	  push (Rust::Token::make (CONST, UNDEF_LOCATION));
!       }
!     else
!       {
! 	if (expr.get_is_mut ())
! 	  push (Rust::Token::make (MUT, UNDEF_LOCATION));
!       }
  
!     if (expr.is_raw_borrow ())
!       {
! 	push (Rust::Token::make_identifier (expr.get_locus (),
! 					    Values::WeakKeywords::RAW));
! 	if (expr.get_is_mut ())
! 	  push (Rust::Token::make (MUT, UNDEF_LOCATION));
! 	else
! 	  push (Rust::Token::make (CONST, UNDEF_LOCATION));
!       }
!     else
!       {
! 	if (expr.get_is_mut ())
! 	  push (Rust::Token::make (MUT, UNDEF_LOCATION));
!       }
! 
!     if (expr.has_borrow_expr ())
!       visit (expr.get_borrowed_expr ());
!   });
  }
  
  void
  TokenCollector::visit (DereferenceExpr &expr)
  {
!   describe_node (std::string ("DereferenceExpr"), [this, &expr] () {
!     push (Rust::Token::make (ASTERISK, expr.get_locus ()));
!     visit (expr.get_dereferenced_expr ());
!   });
  }
  
  void
  TokenCollector::visit (ErrorPropagationExpr &expr)
  {
!   describe_node (std::string ("ErrorPropagationExpr"), [this, &expr] () {
!     visit (expr.get_propagating_expr ());
!     push (Rust::Token::make (QUESTION_MARK, expr.get_locus ()));
!   });
  }
  
  void
  TokenCollector::visit (NegationExpr &expr)
  {
!   describe_node (std::string ("NegationExpr"), [this, &expr] () {
!     switch (expr.get_expr_type ())
!       {
!       case NegationOperator::NEGATE:
! 	push (Rust::Token::make (MINUS, expr.get_locus ()));
! 	break;
!       case NegationOperator::NOT:
! 	push (Rust::Token::make (EXCLAM, expr.get_locus ()));
! 	break;
!       }
!     visit (expr.get_negated_expr ());
!   });
  }
  
  void
  TokenCollector::visit (ArithmeticOrLogicalExpr &expr)
  {
!   describe_node (std::string ("ArithmeticOrLogicalExpr"), [this, &expr] () {
!     visit (expr.get_left_expr ());
!     switch (expr.get_expr_type ())
!       {
!       case ArithmeticOrLogicalOperator::ADD:
! 	push (Rust::Token::make (PLUS, expr.get_locus ()));
! 	break;
  
!       case ArithmeticOrLogicalOperator::SUBTRACT:
! 	push (Rust::Token::make (MINUS, expr.get_locus ()));
! 	break;
  
!       case ArithmeticOrLogicalOperator::MULTIPLY:
! 	push (Rust::Token::make (ASTERISK, expr.get_locus ()));
! 	break;
  
!       case ArithmeticOrLogicalOperator::DIVIDE:
! 	push (Rust::Token::make (DIV, expr.get_locus ()));
! 	break;
  
!       case ArithmeticOrLogicalOperator::MODULUS:
! 	push (Rust::Token::make (PERCENT, expr.get_locus ()));
! 	break;
  
!       case ArithmeticOrLogicalOperator::BITWISE_AND:
! 	push (Rust::Token::make (AMP, expr.get_locus ()));
! 	break;
  
!       case ArithmeticOrLogicalOperator::BITWISE_OR:
! 	push (Rust::Token::make (PIPE, expr.get_locus ()));
! 	break;
  
!       case ArithmeticOrLogicalOperator::BITWISE_XOR:
! 	push (Rust::Token::make (CARET, expr.get_locus ()));
! 	break;
  
!       case ArithmeticOrLogicalOperator::LEFT_SHIFT:
! 	push (Rust::Token::make (LEFT_SHIFT, expr.get_locus ()));
! 	break;
  
!       case ArithmeticOrLogicalOperator::RIGHT_SHIFT:
! 	push (Rust::Token::make (RIGHT_SHIFT, expr.get_locus ()));
! 	break;
!       }
  
!     visit (expr.get_right_expr ());
!   });
  }
  
  void
  TokenCollector::visit (ComparisonExpr &expr)
  {
!   describe_node (std::string ("ComparisonExpr"), [this, &expr] () {
!     visit (expr.get_left_expr ());
  
!     switch (expr.get_expr_type ())
!       {
!       case ComparisonOperator::EQUAL:
! 	push (Rust::Token::make (EQUAL_EQUAL, expr.get_locus ()));
! 	break;
!       case ComparisonOperator::NOT_EQUAL:
! 	push (Rust::Token::make (NOT_EQUAL, expr.get_locus ()));
! 	break;
!       case ComparisonOperator::GREATER_THAN:
! 	push (Rust::Token::make (RIGHT_ANGLE, expr.get_locus ()));
! 	break;
!       case ComparisonOperator::LESS_THAN:
! 	push (Rust::Token::make (LEFT_ANGLE, expr.get_locus ()));
! 	break;
!       case ComparisonOperator::GREATER_OR_EQUAL:
! 	push (Rust::Token::make (GREATER_OR_EQUAL, expr.get_locus ()));
! 	break;
  
!       case ComparisonOperator::LESS_OR_EQUAL:
! 	push (Rust::Token::make (LESS_OR_EQUAL, expr.get_locus ()));
! 	break;
!       }
!     visit (expr.get_right_expr ());
!   });
  }
  
  void
  TokenCollector::visit (LazyBooleanExpr &expr)
  {
!   describe_node (std::string ("LazyBooleanExpr"), [this, &expr] () {
!     visit (expr.get_left_expr ());
  
!     switch (expr.get_expr_type ())
!       {
!       case LazyBooleanOperator::LOGICAL_AND:
! 	push (Rust::Token::make (LOGICAL_AND, expr.get_locus ()));
! 	break;
!       case LazyBooleanOperator::LOGICAL_OR:
! 	push (Rust::Token::make (OR, expr.get_locus ()));
! 	break;
!       }
  
!     visit (expr.get_right_expr ());
!   });
  }
  
  void
  TokenCollector::visit (TypeCastExpr &expr)
  {
!   describe_node (std::string ("TypeCastExpr"), [this, &expr] () {
!     visit (expr.get_casted_expr ());
!     push (Rust::Token::make (AS, expr.get_locus ()));
!     visit (expr.get_type_to_cast_to ());
!   });
  }
  
  void
  TokenCollector::visit (AssignmentExpr &expr)
  {
!   describe_node (std::string ("AssignementExpr"), [this, &expr] () {
!     expr.visit_lhs (*this);
!     push (Rust::Token::make (EQUAL, expr.get_locus ()));
!     expr.visit_rhs (*this);
!   });
  }
  
  void
  TokenCollector::visit (CompoundAssignmentExpr &expr)
  {
!   describe_node (std::string ("CompoundAssignmentExpr"), [this, &expr] () {
!     visit (expr.get_left_expr ());
  
!     switch (expr.get_expr_type ())
!       {
!       case CompoundAssignmentOperator::ADD:
! 	push (Rust::Token::make (PLUS_EQ, expr.get_locus ()));
! 	break;
!       case CompoundAssignmentOperator::SUBTRACT:
! 	push (Rust::Token::make (MINUS_EQ, expr.get_locus ()));
! 	break;
!       case CompoundAssignmentOperator::MULTIPLY:
! 	push (Rust::Token::make (ASTERISK_EQ, expr.get_locus ()));
! 	break;
!       case CompoundAssignmentOperator::DIVIDE:
! 	push (Rust::Token::make (DIV_EQ, expr.get_locus ()));
! 	break;
!       case CompoundAssignmentOperator::MODULUS:
! 	push (Rust::Token::make (PERCENT_EQ, expr.get_locus ()));
! 	break;
!       case CompoundAssignmentOperator::BITWISE_AND:
! 	push (Rust::Token::make (AMP_EQ, expr.get_locus ()));
! 	break;
!       case CompoundAssignmentOperator::BITWISE_OR:
! 	push (Rust::Token::make (PIPE_EQ, expr.get_locus ()));
! 	break;
!       case CompoundAssignmentOperator::BITWISE_XOR:
! 	push (Rust::Token::make (CARET_EQ, expr.get_locus ()));
! 	break;
!       case CompoundAssignmentOperator::LEFT_SHIFT:
! 	push (Rust::Token::make (LEFT_SHIFT_EQ, expr.get_locus ()));
! 	break;
!       case CompoundAssignmentOperator::RIGHT_SHIFT:
! 	push (Rust::Token::make (RIGHT_SHIFT_EQ, expr.get_locus ()));
! 	break;
!       }
!     visit (expr.get_right_expr ());
!   });
  }
  
  void
  TokenCollector::visit (GroupedExpr &expr)
  {
!   describe_node (std::string ("GroupedExpr"), [this, &expr] () {
!     push (Rust::Token::make (LEFT_PAREN, expr.get_locus ()));
!     visit (expr.get_expr_in_parens ());
!     push (Rust::Token::make (RIGHT_PAREN, expr.get_locus ()));
!   });
  }
  
  void
  TokenCollector::visit (ArrayElemsValues &elems)
  {
!   describe_node (std::string ("ArraysElemValues"), [this, &elems] () {
!     visit_items_joined_by_separator (elems.get_values (), COMMA);
!   });
  }
  
  void
  TokenCollector::visit (ArrayElemsCopied &elems)
  {
!   describe_node (std::string ("ArrayElemsCopied"), [this, &elems] () {
!     visit (elems.get_elem_to_copy ());
!     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
!     visit (elems.get_num_copies ());
!   });
  }
  
  void
  TokenCollector::visit (ArrayExpr &expr)
  {
!   describe_node (std::string ("ArrayExpr"), [this, &expr] () {
!     push (Rust::Token::make (LEFT_SQUARE, expr.get_locus ()));
!     visit (expr.get_array_elems ());
!     push (Rust::Token::make (RIGHT_SQUARE, UNDEF_LOCATION));
!   });
  }
  
  void
  TokenCollector::visit (ArrayIndexExpr &expr)
  {
!   describe_node (std::string ("ArrayIndexExpr"), [this, &expr] () {
!     visit (expr.get_array_expr ());
!     push (Rust::Token::make (LEFT_SQUARE, expr.get_locus ()));
!     visit (expr.get_index_expr ());
!     push (Rust::Token::make (RIGHT_SQUARE, UNDEF_LOCATION));
!   });
  }
  
  void
  TokenCollector::visit (TupleExpr &expr)
  {
!   describe_node (std::string ("TupleExpr"), [this, &expr] () {
!     visit_items_as_lines (expr.get_outer_attrs ());
!     push (Rust::Token::make (LEFT_PAREN, expr.get_locus ()));
!     visit_items_joined_by_separator (expr.get_tuple_elems (), COMMA);
!     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
!   });
  }
  
  void
  TokenCollector::visit (TupleIndexExpr &expr)
  {
!   describe_node (std::string ("TupleIndexExpr"), [this, &expr] () {
!     visit (expr.get_tuple_expr ());
!     push (Rust::Token::make (DOT, expr.get_locus ()));
!     push (Rust::Token::make_int (UNDEF_LOCATION,
! 				 std::to_string (expr.get_tuple_index ())));
!   });
  }
  
  void
  TokenCollector::visit (StructExprStruct &expr)
  {
!   describe_node (std::string ("StructExprStruct"),
! 		 [this, &expr] () { visit (expr.get_struct_name ()); });
  }
  
  void
  TokenCollector::visit (StructExprFieldIdentifier &expr)
  {
!   describe_node (std::string ("StructExprFieldIdentifier"), [this, &expr] () {
!     visit_items_as_lines (expr.get_outer_attrs ());
!     auto id = expr.get_field_name ().as_string ();
!     push (Rust::Token::make_identifier (expr.get_locus (), std::move (id)));
!   });
  }
  
  void
  TokenCollector::visit (StructExprFieldIdentifierValue &expr)
  {
!   describe_node (std::string ("StructExprFieldIdentifierValue"), [this,
! 								  &expr] () {
!     visit_items_as_lines (expr.get_outer_attrs ());
!     auto id = expr.get_field_name ();
!     push (Rust::Token::make_identifier (expr.get_locus (), std::move (id)));
!     push (Rust::Token::make (COLON, UNDEF_LOCATION));
!     visit (expr.get_value ());
!   });
  }
  
  void
  TokenCollector::visit (StructExprFieldIndexValue &expr)
  {
!   describe_node (std::string ("StructExprFieldIndexValue"), [this, &expr] () {
!     visit_items_as_lines (expr.get_outer_attrs ());
!     push (Rust::Token::make_int (expr.get_locus (),
! 				 std::to_string (expr.get_index ())));
!     push (Rust::Token::make (COLON, UNDEF_LOCATION));
!     visit (expr.get_value ());
!   });
  }
  
  void
  TokenCollector::visit (StructBase &base)
  {
!   describe_node (std::string ("StructBase"), [this, &base] () {
!     push (Rust::Token::make (DOT_DOT, UNDEF_LOCATION));
!     visit (base.get_base_struct ());
!   });
  }
  
  void
  TokenCollector::visit (StructExprStructFields &expr)
  {
!   describe_node (std::string ("StructExprStructFields"), [this, &expr] () {
!     visit (expr.get_struct_name ());
!     push (Rust::Token::make (LEFT_CURLY, expr.get_locus ()));
!     visit_items_joined_by_separator (expr.get_fields (), COMMA);
!     if (expr.has_struct_base ())
!       {
! 	push (Rust::Token::make (COMMA, UNDEF_LOCATION));
! 	visit (expr.get_struct_base ());
!       }
!     else
!       {
! 	trailing_comma ();
!       }
!     push (Rust::Token::make (RIGHT_CURLY, expr.get_locus ()));
!   });
  }
  
  void
*************** TokenCollector::visit (StructExprStructB
*** 1186,1275 ****
  void
  TokenCollector::visit (CallExpr &expr)
  {
!   visit (expr.get_function_expr ());
  
!   push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
  
!   visit_items_joined_by_separator (expr.get_params (), COMMA);
  
!   push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
  }
  
  void
  TokenCollector::visit (MethodCallExpr &expr)
  {
!   visit (expr.get_receiver_expr ());
!   push (Rust::Token::make (DOT, expr.get_locus ()));
!   visit (expr.get_method_name ());
!   push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
!   visit_items_joined_by_separator (expr.get_params (), COMMA);
!   trailing_comma ();
!   push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
  }
  
  void
  TokenCollector::visit (FieldAccessExpr &expr)
  {
!   visit (expr.get_receiver_expr ());
!   push (Rust::Token::make (DOT, expr.get_locus ()));
!   auto field_name = expr.get_field_name ().as_string ();
!   push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (field_name)));
  }
  
  void
  TokenCollector::visit (ClosureParam &param)
  {
!   visit_items_as_lines (param.get_outer_attrs ());
!   visit (param.get_pattern ());
!   if (param.has_type_given ())
!     {
!       push (Rust::Token::make (COLON, param.get_locus ()));
!       visit (param.get_type ());
!     }
  }
  
  void
  TokenCollector::visit_closure_common (ClosureExpr &expr)
  {
!   if (expr.get_has_move ())
!     {
!       push (Rust::Token::make (MOVE, expr.get_locus ()));
!     }
!   push (Rust::Token::make (PIPE, UNDEF_LOCATION));
!   visit_items_joined_by_separator (expr.get_params (), COMMA);
!   push (Rust::Token::make (PIPE, UNDEF_LOCATION));
  }
  
  void
  TokenCollector::visit (ClosureExprInner &expr)
  {
!   visit_closure_common (expr);
!   visit (expr.get_definition_expr ());
  }
  
  void
  TokenCollector::visit (BlockExpr &expr)
  {
!   visit_items_as_lines (expr.get_outer_attrs ());
!   push (Rust::Token::make (LEFT_CURLY, expr.get_locus ()));
!   newline ();
!   increment_indentation ();
!   visit_items_as_lines (expr.get_inner_attrs ());
  
!   visit_items_as_lines (expr.get_statements (), {});
  
!   if (expr.has_tail_expr ())
!     {
!       indentation ();
!       visit (expr.get_tail_expr ());
!       comment ("tail expr");
!       newline ();
!     }
  
!   decrement_indentation ();
!   indentation ();
!   push (Rust::Token::make (RIGHT_CURLY, expr.get_locus ()));
!   newline ();
  }
  
  void
--- 1325,1428 ----
  void
  TokenCollector::visit (CallExpr &expr)
  {
!   describe_node (std::string ("CallExpr"), [this, &expr] () {
!     visit (expr.get_function_expr ());
  
!     push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
  
!     visit_items_joined_by_separator (expr.get_params (), COMMA);
  
!     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
!   });
  }
  
  void
  TokenCollector::visit (MethodCallExpr &expr)
  {
!   describe_node (std::string ("MethodCallExpr"), [this, &expr] () {
!     visit (expr.get_receiver_expr ());
!     push (Rust::Token::make (DOT, expr.get_locus ()));
!     visit (expr.get_method_name ());
!     push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
!     visit_items_joined_by_separator (expr.get_params (), COMMA);
!     trailing_comma ();
!     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
!   });
  }
  
  void
  TokenCollector::visit (FieldAccessExpr &expr)
  {
!   describe_node (std::string ("FieldAccessExpr"), [this, &expr] () {
!     visit (expr.get_receiver_expr ());
!     push (Rust::Token::make (DOT, expr.get_locus ()));
!     auto field_name = expr.get_field_name ().as_string ();
!     push (
!       Rust::Token::make_identifier (UNDEF_LOCATION, std::move (field_name)));
!   });
  }
  
  void
  TokenCollector::visit (ClosureParam &param)
  {
!   describe_node (std::string ("ClosureParam"), [this, &param] () {
!     visit_items_as_lines (param.get_outer_attrs ());
!     visit (param.get_pattern ());
!     if (param.has_type_given ())
!       {
! 	push (Rust::Token::make (COLON, param.get_locus ()));
! 	visit (param.get_type ());
!       }
!   });
  }
  
  void
  TokenCollector::visit_closure_common (ClosureExpr &expr)
  {
!   describe_node (std::string ("ClosureExpr"), [this, &expr] () {
!     if (expr.get_has_move ())
!       {
! 	push (Rust::Token::make (MOVE, expr.get_locus ()));
!       }
!     push (Rust::Token::make (PIPE, UNDEF_LOCATION));
!     visit_items_joined_by_separator (expr.get_params (), COMMA);
!     push (Rust::Token::make (PIPE, UNDEF_LOCATION));
!   });
  }
  
  void
  TokenCollector::visit (ClosureExprInner &expr)
  {
!   describe_node (std::string ("ClosureExprInner"), [this, &expr] () {
!     visit_closure_common (expr);
!     visit (expr.get_definition_expr ());
!   });
  }
  
  void
  TokenCollector::visit (BlockExpr &expr)
  {
!   describe_node (std::string ("BlockExpr"), [this, &expr] () {
!     visit_items_as_lines (expr.get_outer_attrs ());
!     push (Rust::Token::make (LEFT_CURLY, expr.get_locus ()));
!     newline ();
!     increment_indentation ();
!     visit_items_as_lines (expr.get_inner_attrs ());
  
!     visit_items_as_lines (expr.get_statements (), {});
  
!     if (expr.has_tail_expr ())
!       {
! 	indentation ();
! 	visit (expr.get_tail_expr ());
! 	newline ();
!       }
  
!     decrement_indentation ();
!     indentation ();
!     push (Rust::Token::make (RIGHT_CURLY, expr.get_locus ()));
!     newline ();
!   });
  }
  
  void
*************** TokenCollector::visit (ConstBlock &expr)
*** 1297,1382 ****
  void
  TokenCollector::visit (ClosureExprInnerTyped &expr)
  {
!   visit_closure_common (expr);
!   push (Rust::Token::make (RETURN_TYPE, expr.get_locus ()));
!   visit (expr.get_return_type ());
!   visit (expr.get_definition_expr ());
  }
  
  void
  TokenCollector::visit (ContinueExpr &expr)
  {
!   push (Rust::Token::make (CONTINUE, expr.get_locus ()));
!   if (expr.has_label ())
!     visit (expr.get_label_unchecked ());
  }
  
  void
  TokenCollector::visit (BreakExpr &expr)
  {
!   push (Rust::Token::make (BREAK, expr.get_locus ()));
!   if (expr.has_label ())
!     visit (expr.get_label_unchecked ());
!   if (expr.has_break_expr ())
!     visit (expr.get_break_expr ());
  }
  
  void
  TokenCollector::visit (RangeFromToExpr &expr)
  {
!   visit (expr.get_from_expr ());
!   push (Rust::Token::make (DOT_DOT, expr.get_locus ()));
!   visit (expr.get_to_expr ());
  }
  
  void
  TokenCollector::visit (RangeFromExpr &expr)
  {
!   visit (expr.get_from_expr ());
!   push (Rust::Token::make (DOT_DOT, expr.get_locus ()));
  }
  
  void
  TokenCollector::visit (RangeToExpr &expr)
  {
!   push (Rust::Token::make (DOT_DOT, expr.get_locus ()));
!   visit (expr.get_to_expr ());
  }
  
  void
  TokenCollector::visit (RangeFullExpr &expr)
  {
!   push (Rust::Token::make (DOT_DOT, expr.get_locus ()));
  }
  
  void
  TokenCollector::visit (RangeFromToInclExpr &expr)
  {
!   visit (expr.get_from_expr ());
!   push (Rust::Token::make (DOT_DOT_EQ, expr.get_locus ()));
!   visit (expr.get_to_expr ());
  }
  
  void
  TokenCollector::visit (RangeToInclExpr &expr)
  {
!   push (Rust::Token::make (DOT_DOT_EQ, expr.get_locus ()));
!   visit (expr.get_to_expr ());
  }
  
  void
  TokenCollector::visit (BoxExpr &expr)
  {
!   push (Rust::Token::make (BOX, expr.get_locus ()));
!   visit (expr.get_boxed_expr ());
  }
  
  void
  TokenCollector::visit (ReturnExpr &expr)
  {
!   push (Rust::Token::make (RETURN_KW, expr.get_locus ()));
!   if (expr.has_returned_expr ())
!     visit (expr.get_returned_expr ());
  }
  
  void
--- 1450,1558 ----
  void
  TokenCollector::visit (ClosureExprInnerTyped &expr)
  {
!   describe_node (std::string ("ClosureExprInnerTyped"), [this, &expr] () {
!     visit_closure_common (expr);
!     push (Rust::Token::make (RETURN_TYPE, expr.get_locus ()));
!     visit (expr.get_return_type ());
! 
!     visit (expr.get_definition_expr ());
!   });
  }
  
  void
  TokenCollector::visit (ContinueExpr &expr)
  {
!   describe_node (std::string ("ContinueExpr"), [this, &expr] () {
!     push (Rust::Token::make (CONTINUE, expr.get_locus ()));
!     if (expr.has_label ())
!       visit (expr.get_label_unchecked ());
!   });
  }
  
  void
  TokenCollector::visit (BreakExpr &expr)
  {
!   describe_node (std::string ("BreakExpr"), [this, &expr] () {
!     push (Rust::Token::make (BREAK, expr.get_locus ()));
!     if (expr.has_label ())
!       visit (expr.get_label_unchecked ());
!     if (expr.has_break_expr ())
!       visit (expr.get_break_expr ());
!   });
  }
  
  void
  TokenCollector::visit (RangeFromToExpr &expr)
  {
!   describe_node (std::string ("RangeFromToExpr"), [this, &expr] () {
!     visit (expr.get_from_expr ());
!     push (Rust::Token::make (DOT_DOT, expr.get_locus ()));
!     visit (expr.get_to_expr ());
!   });
  }
  
  void
  TokenCollector::visit (RangeFromExpr &expr)
  {
!   describe_node (std::string ("RangeFromExpr"), [this, &expr] () {
!     visit (expr.get_from_expr ());
!     push (Rust::Token::make (DOT_DOT, expr.get_locus ()));
!   });
  }
  
  void
  TokenCollector::visit (RangeToExpr &expr)
  {
!   describe_node (std::string ("RangeToExpr"), [this, &expr] () {
!     push (Rust::Token::make (DOT_DOT, expr.get_locus ()));
!     visit (expr.get_to_expr ());
!   });
  }
  
  void
  TokenCollector::visit (RangeFullExpr &expr)
  {
!   describe_node (std::string ("RangeFullExpr"), [this, &expr] () {
!     push (Rust::Token::make (DOT_DOT, expr.get_locus ()));
!   });
  }
  
  void
  TokenCollector::visit (RangeFromToInclExpr &expr)
  {
!   describe_node (std::string ("RangeFromToInclExpr"), [this, &expr] () {
!     visit (expr.get_from_expr ());
!     push (Rust::Token::make (DOT_DOT_EQ, expr.get_locus ()));
!     visit (expr.get_to_expr ());
!   });
  }
  
  void
  TokenCollector::visit (RangeToInclExpr &expr)
  {
!   describe_node (std::string ("RangeToInclExpr"), [this, &expr] () {
!     push (Rust::Token::make (DOT_DOT_EQ, expr.get_locus ()));
!     visit (expr.get_to_expr ());
!   });
  }
  
  void
  TokenCollector::visit (BoxExpr &expr)
  {
!   describe_node (std::string ("BoxExpr"), [this, &expr] () {
!     push (Rust::Token::make (BOX, expr.get_locus ()));
!     visit (expr.get_boxed_expr ());
!   });
  }
  
  void
  TokenCollector::visit (ReturnExpr &expr)
  {
!   describe_node (std::string ("ReturnExpr"), [this, &expr] () {
!     push (Rust::Token::make (RETURN_KW, expr.get_locus ()));
!     if (expr.has_returned_expr ())
!       visit (expr.get_returned_expr ());
!   });
  }
  
  void
*************** TokenCollector::visit (TryExpr &expr)
*** 1389,1557 ****
  void
  TokenCollector::visit (UnsafeBlockExpr &expr)
  {
!   push (Rust::Token::make (UNSAFE, expr.get_locus ()));
!   visit (expr.get_block_expr ());
  }
  
  void
  TokenCollector::visit (LoopLabel &label)
  {
!   visit (label.get_lifetime ());
!   push (Rust::Token::make (COLON, label.get_locus ()));
  }
  
  void
  TokenCollector::visit_loop_common (BaseLoopExpr &expr)
  {
!   if (expr.has_loop_label ())
!     visit (expr.get_loop_label ());
  }
  
  void
  TokenCollector::visit (LoopExpr &expr)
  {
!   visit_loop_common (expr);
!   push (Rust::Token::make (LOOP, expr.get_locus ()));
!   visit (expr.get_loop_block ());
  }
  
  void
  TokenCollector::visit (WhileLoopExpr &expr)
  {
!   visit_loop_common (expr);
!   push (Rust::Token::make (WHILE, expr.get_locus ()));
!   visit (expr.get_predicate_expr ());
!   visit (expr.get_loop_block ());
  }
  
  void
  TokenCollector::visit (WhileLetLoopExpr &expr)
  {
!   visit_loop_common (expr);
!   push (Rust::Token::make (WHILE, expr.get_locus ()));
!   push (Rust::Token::make (LET, UNDEF_LOCATION));
!   // TODO: The reference mention only one Pattern
!   for (auto &item : expr.get_patterns ())
!     {
!       visit (item);
!     }
!   push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
!   visit (expr.get_scrutinee_expr ());
!   visit (expr.get_loop_block ());
  }
  
  void
  TokenCollector::visit (ForLoopExpr &expr)
  {
!   visit_loop_common (expr);
!   push (Rust::Token::make (FOR, expr.get_locus ()));
!   visit (expr.get_pattern ());
!   push (Rust::Token::make (IN, UNDEF_LOCATION));
!   visit (expr.get_iterator_expr ());
!   visit (expr.get_loop_block ());
  }
  
  void
  TokenCollector::visit (IfExpr &expr)
  {
!   push (Rust::Token::make (IF, expr.get_locus ()));
!   visit (expr.get_condition_expr ());
!   visit (expr.get_if_block ());
  }
  
  void
  TokenCollector::visit (IfExprConseqElse &expr)
  {
!   visit (static_cast<IfExpr &> (expr));
!   indentation ();
!   push (Rust::Token::make (ELSE, expr.get_locus ()));
!   visit (expr.get_else_block ());
  }
  
  void
  TokenCollector::visit (IfLetExpr &expr)
  {
!   push (Rust::Token::make (IF, expr.get_locus ()));
!   push (Rust::Token::make (LET, UNDEF_LOCATION));
!   for (auto &pattern : expr.get_patterns ())
!     {
!       visit (pattern);
!     }
!   push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
!   visit (expr.get_value_expr ());
!   visit (expr.get_if_block ());
  }
  
  void
  TokenCollector::visit (IfLetExprConseqElse &expr)
  {
!   visit (static_cast<IfLetExpr &> (expr));
!   indentation ();
!   push (Rust::Token::make (ELSE, expr.get_locus ()));
!   visit (expr.get_else_block ());
  }
  
  void
  TokenCollector::visit (MatchArm &arm)
  {
!   visit_items_as_lines (arm.get_outer_attrs ());
!   for (auto &pattern : arm.get_patterns ())
!     {
!       visit (pattern);
!     }
!   if (arm.has_match_arm_guard ())
!     {
!       push (Rust::Token::make (IF, UNDEF_LOCATION));
!       visit (arm.get_guard_expr ());
!     }
  }
  
  void
  TokenCollector::visit (MatchCase &match_case)
  {
!   indentation ();
!   visit (match_case.get_arm ());
!   push (Rust::Token::make (MATCH_ARROW, UNDEF_LOCATION));
!   visit (match_case.get_expr ());
!   indentation ();
!   push (Rust::Token::make (COMMA, UNDEF_LOCATION));
!   newline ();
  }
  
  void
  TokenCollector::visit (MatchExpr &expr)
  {
!   push (Rust::Token::make (MATCH_KW, expr.get_locus ()));
!   visit (expr.get_scrutinee_expr ());
!   push (Rust::Token::make (LEFT_CURLY, UNDEF_LOCATION));
!   newline ();
!   increment_indentation ();
!   visit_items_as_lines (expr.get_inner_attrs ());
!   for (auto &arm : expr.get_match_cases ())
!     {
!       visit (arm);
!     }
!   decrement_indentation ();
!   indentation ();
!   push (Rust::Token::make (RIGHT_CURLY, UNDEF_LOCATION));
  }
  
  void
  TokenCollector::visit (AwaitExpr &expr)
  {
!   visit (expr.get_awaited_expr ());
!   push (Rust::Token::make (DOT, expr.get_locus ()));
!   // TODO: Check status of await keyword (Context dependant ?)
!   push (Rust::Token::make_identifier (UNDEF_LOCATION, Values::Keywords::AWAIT));
  }
  
  void
  TokenCollector::visit (AsyncBlockExpr &expr)
  {
!   push (Rust::Token::make (ASYNC, expr.get_locus ()));
!   if (expr.get_has_move ())
!     push (Rust::Token::make (MOVE, UNDEF_LOCATION));
!   visit (expr.get_block_expr ());
  }
  
  void
--- 1565,1767 ----
  void
  TokenCollector::visit (UnsafeBlockExpr &expr)
  {
!   describe_node (std::string ("UnsafeBlockExpr"), [this, &expr] () {
!     push (Rust::Token::make (UNSAFE, expr.get_locus ()));
!     visit (expr.get_block_expr ());
!   });
  }
  
  void
  TokenCollector::visit (LoopLabel &label)
  {
!   describe_node (std::string ("LoopLabel"), [this, &label] () {
!     visit (label.get_lifetime ());
!     push (Rust::Token::make (COLON, label.get_locus ()));
!   });
  }
  
  void
  TokenCollector::visit_loop_common (BaseLoopExpr &expr)
  {
!   describe_node (std::string ("BaseLoopExpr"), [this, &expr] () {
!     if (expr.has_loop_label ())
!       visit (expr.get_loop_label ());
!   });
  }
  
  void
  TokenCollector::visit (LoopExpr &expr)
  {
!   describe_node (std::string ("LoopExpr"), [this, &expr] () {
!     visit_loop_common (expr);
!     push (Rust::Token::make (LOOP, expr.get_locus ()));
!     visit (expr.get_loop_block ());
!   });
  }
  
  void
  TokenCollector::visit (WhileLoopExpr &expr)
  {
!   describe_node (std::string ("WhileLoopExpr"), [this, &expr] () {
!     visit_loop_common (expr);
!     push (Rust::Token::make (WHILE, expr.get_locus ()));
!     visit (expr.get_predicate_expr ());
!     visit (expr.get_loop_block ());
!   });
  }
  
  void
  TokenCollector::visit (WhileLetLoopExpr &expr)
  {
!   describe_node (std::string ("WhileLetLoopExpr"), [this, &expr] () {
!     visit_loop_common (expr);
!     push (Rust::Token::make (WHILE, expr.get_locus ()));
!     push (Rust::Token::make (LET, UNDEF_LOCATION));
!     // TODO: The reference mention only one Pattern
!     for (auto &item : expr.get_patterns ())
!       {
! 	visit (item);
!       }
!     push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
!     visit (expr.get_scrutinee_expr ());
!     visit (expr.get_loop_block ());
!   });
  }
  
  void
  TokenCollector::visit (ForLoopExpr &expr)
  {
!   describe_node (std::string ("ForLoopExpr"), [this, &expr] () {
!     visit_loop_common (expr);
!     push (Rust::Token::make (FOR, expr.get_locus ()));
!     visit (expr.get_pattern ());
!     push (Rust::Token::make (IN, UNDEF_LOCATION));
!     visit (expr.get_iterator_expr ());
!     visit (expr.get_loop_block ());
!   });
  }
  
  void
  TokenCollector::visit (IfExpr &expr)
  {
!   describe_node (std::string ("IfExpr"), [this, &expr] () {
!     push (Rust::Token::make (IF, expr.get_locus ()));
! 
!     visit (expr.get_condition_expr ());
!     visit (expr.get_if_block ());
!   });
  }
  
  void
  TokenCollector::visit (IfExprConseqElse &expr)
  {
!   describe_node (std::string ("IfExprConseqElse"), [this, &expr] () {
!     visit (static_cast<IfExpr &> (expr));
!     indentation ();
!     push (Rust::Token::make (ELSE, expr.get_locus ()));
!     visit (expr.get_else_block ());
!   });
  }
  
  void
  TokenCollector::visit (IfLetExpr &expr)
  {
!   describe_node (std::string ("IfLetExpr"), [this, &expr] () {
!     push (Rust::Token::make (IF, expr.get_locus ()));
!     push (Rust::Token::make (LET, UNDEF_LOCATION));
!     for (auto &pattern : expr.get_patterns ())
!       {
! 	visit (pattern);
!       }
!     push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
!     visit (expr.get_value_expr ());
!     visit (expr.get_if_block ());
!   });
  }
  
  void
  TokenCollector::visit (IfLetExprConseqElse &expr)
  {
!   describe_node (std::string ("IfLetExprConseqElse"), [this, &expr] () {
!     visit (static_cast<IfLetExpr &> (expr));
!     indentation ();
!     push (Rust::Token::make (ELSE, expr.get_locus ()));
!     visit (expr.get_else_block ());
!   });
  }
  
  void
  TokenCollector::visit (MatchArm &arm)
  {
!   describe_node (std::string ("MatchArm"), [this, &arm] () {
!     visit_items_as_lines (arm.get_outer_attrs ());
!     for (auto &pattern : arm.get_patterns ())
!       {
! 	visit (pattern);
!       }
!     if (arm.has_match_arm_guard ())
!       {
! 	push (Rust::Token::make (IF, UNDEF_LOCATION));
! 	visit (arm.get_guard_expr ());
!       }
!   });
  }
  
  void
  TokenCollector::visit (MatchCase &match_case)
  {
!   describe_node (std::string ("MatchCase"), [this, &match_case] () {
!     indentation ();
!     visit (match_case.get_arm ());
!     push (Rust::Token::make (MATCH_ARROW, UNDEF_LOCATION));
!     visit (match_case.get_expr ());
!     indentation ();
!     push (Rust::Token::make (COMMA, UNDEF_LOCATION));
!     newline ();
!   });
  }
  
  void
  TokenCollector::visit (MatchExpr &expr)
  {
!   describe_node (std::string ("MatchExpr"), [this, &expr] () {
!     push (Rust::Token::make (MATCH_KW, expr.get_locus ()));
!     visit (expr.get_scrutinee_expr ());
!     push (Rust::Token::make (LEFT_CURLY, UNDEF_LOCATION));
!     newline ();
!     increment_indentation ();
!     visit_items_as_lines (expr.get_inner_attrs ());
!     for (auto &arm : expr.get_match_cases ())
!       {
! 	visit (arm);
!       }
!     decrement_indentation ();
!     indentation ();
!     push (Rust::Token::make (RIGHT_CURLY, UNDEF_LOCATION));
!   });
  }
  
  void
  TokenCollector::visit (AwaitExpr &expr)
  {
!   describe_node (std::string ("AwaitExpr"), [this, &expr] () {
!     visit (expr.get_awaited_expr ());
!     push (Rust::Token::make (DOT, expr.get_locus ()));
!     // TODO: Check status of await keyword (Context dependant ?)
!     push (
!       Rust::Token::make_identifier (UNDEF_LOCATION, Values::Keywords::AWAIT));
!   });
  }
  
  void
  TokenCollector::visit (AsyncBlockExpr &expr)
  {
!   describe_node (std::string ("AsyncBlockExpr"), [this, &expr] () {
!     push (Rust::Token::make (ASYNC, expr.get_locus ()));
!     if (expr.get_has_move ())
!       push (Rust::Token::make (MOVE, UNDEF_LOCATION));
!     visit (expr.get_block_expr ());
!   });
  }
  
  void
*************** TokenCollector::visit (TypeParam &param)
*** 1696,1715 ****
    //    IDENTIFIER( : TypeParamBounds? )? ( = Type )?
    // TypeParamBounds :
    //    TypeParamBound ( + TypeParamBound )* +?
! 
!   visit_items_as_lines (param.get_outer_attrs ());
!   auto id = param.get_type_representation ().as_string ();
!   push (Rust::Token::make_identifier (param.get_locus (), std::move (id)));
!   if (param.has_type_param_bounds ())
!     {
!       push (Rust::Token::make (COLON, UNDEF_LOCATION));
!       visit_items_joined_by_separator (param.get_type_param_bounds (), PLUS);
!     }
!   if (param.has_type ())
!     {
!       push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
!       visit (param.get_type ());
!     }
  }
  
  void
--- 1906,1926 ----
    //    IDENTIFIER( : TypeParamBounds? )? ( = Type )?
    // TypeParamBounds :
    //    TypeParamBound ( + TypeParamBound )* +?
!   describe_node (std::string ("TypeParam"), [this, &param] () {
!     visit_items_as_lines (param.get_outer_attrs ());
!     auto id = param.get_type_representation ().as_string ();
!     push (Rust::Token::make_identifier (param.get_locus (), std::move (id)));
!     if (param.has_type_param_bounds ())
!       {
! 	push (Rust::Token::make (COLON, UNDEF_LOCATION));
! 	visit_items_joined_by_separator (param.get_type_param_bounds (), PLUS);
!       }
!     if (param.has_type ())
!       {
! 	push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
! 	visit (param.get_type ());
!       }
!   });
  }
  
  void
*************** TokenCollector::visit (WhereClause &rule
*** 1720,1731 ****
    // WhereClauseItem :
    // 	LifetimeWhereClauseItem
    //  	| TypeBoundWhereClauseItem
! 
!   push (Rust::Token::make (WHERE, UNDEF_LOCATION));
!   newline ();
!   increment_indentation ();
!   visit_items_joined_by_separator (rule.get_items (), COMMA);
!   decrement_indentation ();
  }
  
  void
--- 1931,1943 ----
    // WhereClauseItem :
    // 	LifetimeWhereClauseItem
    //  	| TypeBoundWhereClauseItem
!   describe_node (std::string ("WhereClause"), [this, &rule] () {
!     push (Rust::Token::make (WHERE, UNDEF_LOCATION));
!     newline ();
!     increment_indentation ();
!     visit_items_joined_by_separator (rule.get_items (), COMMA);
!     decrement_indentation ();
!   });
  }
  
  void
*************** TokenCollector::visit (LifetimeWhereClau
*** 1736,1744 ****
    // LifetimeBounds :
    //   ( Lifetime + )* Lifetime?
  
!   visit (item.get_lifetime ());
!   push (Rust::Token::make (COLON, UNDEF_LOCATION));
!   visit_items_joined_by_separator (item.get_lifetime_bounds (), PLUS);
  }
  
  void
--- 1948,1958 ----
    // LifetimeBounds :
    //   ( Lifetime + )* Lifetime?
  
!   describe_node (std::string ("LifetimeWhereClauseItem"), [this, &item] () {
!     visit (item.get_lifetime ());
!     push (Rust::Token::make (COLON, UNDEF_LOCATION));
!     visit_items_joined_by_separator (item.get_lifetime_bounds (), PLUS);
!   });
  }
  
  void
*************** TokenCollector::visit (TypeBoundWhereCla
*** 1751,1763 ****
    // TypeParamBound :
    //    Lifetime | TraitBound
  
!   if (item.has_for_lifetimes ())
!     visit (item.get_for_lifetimes ());
  
!   visit (item.get_type ());
  
!   push (Rust::Token::make (COLON, UNDEF_LOCATION));
!   visit_items_joined_by_separator (item.get_type_param_bounds (), PLUS);
  }
  
  void
--- 1965,1979 ----
    // TypeParamBound :
    //    Lifetime | TraitBound
  
!   describe_node (std::string ("TypeBoundWhereClauseItem"), [this, &item] () {
!     if (item.has_for_lifetimes ())
!       visit (item.get_for_lifetimes ());
  
!     visit (item.get_type ());
  
!     push (Rust::Token::make (COLON, UNDEF_LOCATION));
!     visit_items_joined_by_separator (item.get_type_param_bounds (), PLUS);
!   });
  }
  
  void
*************** TokenCollector::visit (Module &module)
*** 1769,1901 ****
    //	  InnerAttribute*
    //	  Item*
    //	}
  
!   visit_items_as_lines (module.get_outer_attrs ());
!   visit (module.get_visibility ());
!   auto name = module.get_name ().as_string ();
!   push (Rust::Token::make (MOD, module.get_locus ()));
!   push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (name)));
! 
!   if (module.get_kind () == Module::UNLOADED)
!     {
!       push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
!       newline ();
!     }
!   else /* Module::LOADED */
!     {
!       push (Rust::Token::make (LEFT_CURLY, UNDEF_LOCATION));
!       newline ();
!       increment_indentation ();
  
!       visit_items_as_lines (module.get_inner_attrs ());
!       visit_items_as_lines (module.get_items ());
  
!       decrement_indentation ();
  
!       push (Rust::Token::make (RIGHT_CURLY, UNDEF_LOCATION));
!       newline ();
!     }
  }
  
  void
  TokenCollector::visit (ExternCrate &crate)
  {
!   visit_items_as_lines (crate.get_outer_attrs ());
!   push (Rust::Token::make (EXTERN_KW, crate.get_locus ()));
!   push (Rust::Token::make (CRATE, UNDEF_LOCATION));
!   auto ref = crate.get_referenced_crate ();
!   push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (ref)));
!   if (crate.has_as_clause ())
!     {
!       auto as_clause = crate.get_as_clause ();
!       push (Rust::Token::make (AS, UNDEF_LOCATION));
!       push (
! 	Rust::Token::make_identifier (UNDEF_LOCATION, std::move (as_clause)));
!     }
!   push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
!   newline ();
  }
  
  void
  TokenCollector::visit (UseTreeGlob &use_tree)
  {
!   switch (use_tree.get_glob_type ())
!     {
!     case UseTreeGlob::PathType::PATH_PREFIXED:
        {
! 	auto path = use_tree.get_path ();
! 	visit (path);
  	push (Rust::Token::make (SCOPE_RESOLUTION, UNDEF_LOCATION));
        }
!       break;
!     case UseTreeGlob::PathType::NO_PATH:
!       push (Rust::Token::make (SCOPE_RESOLUTION, UNDEF_LOCATION));
!       break;
!     case UseTreeGlob::PathType::GLOBAL:
!       break;
!     }
!   push (Rust::Token::make (ASTERISK, UNDEF_LOCATION));
  }
  
  void
  TokenCollector::visit (UseTreeList &use_tree)
  {
!   switch (use_tree.get_path_type ())
!     {
!     case UseTreeList::PathType::PATH_PREFIXED:
        {
! 	auto path = use_tree.get_path ();
! 	visit (path);
  	push (Rust::Token::make (SCOPE_RESOLUTION, UNDEF_LOCATION));
        }
-       break;
-     case UseTreeList::PathType::NO_PATH:
-       push (Rust::Token::make (SCOPE_RESOLUTION, UNDEF_LOCATION));
-       break;
-     case UseTreeList::PathType::GLOBAL:
-       break;
-     }
  
!   push (Rust::Token::make (LEFT_CURLY, UNDEF_LOCATION));
!   if (use_tree.has_trees ())
!     {
!       visit_items_joined_by_separator (use_tree.get_trees (), COMMA);
!     }
!   push (Rust::Token::make (RIGHT_CURLY, UNDEF_LOCATION));
  }
  
  void
  TokenCollector::visit (UseTreeRebind &use_tree)
  {
!   auto path = use_tree.get_path ();
!   visit (path);
!   switch (use_tree.get_new_bind_type ())
!     {
!     case UseTreeRebind::NewBindType::IDENTIFIER:
        {
  	push (Rust::Token::make (AS, UNDEF_LOCATION));
! 	auto id = use_tree.get_identifier ().as_string ();
! 	push (
! 	  Rust::Token::make_identifier (use_tree.get_locus (), std::move (id)));
        }
!       break;
!     case UseTreeRebind::NewBindType::WILDCARD:
!       push (Rust::Token::make (AS, UNDEF_LOCATION));
!       push (Rust::Token::make (UNDERSCORE, use_tree.get_locus ()));
!       break;
!     case UseTreeRebind::NewBindType::NONE:
!       break;
!     }
  }
  
  void
  TokenCollector::visit (UseDeclaration &decl)
  {
!   visit_items_as_lines (decl.get_outer_attrs ());
!   push (Rust::Token::make (USE, decl.get_locus ()));
!   visit (*decl.get_tree ());
!   push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
!   newline ();
  }
  
  void
--- 1985,2129 ----
    //	  InnerAttribute*
    //	  Item*
    //	}
+   describe_node (std::string ("Module"), [this, &module] () {
+     visit_items_as_lines (module.get_outer_attrs ());
+     visit (module.get_visibility ());
+     auto name = module.get_name ().as_string ();
+     push (Rust::Token::make (MOD, module.get_locus ()));
+     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (name)));
  
!     if (module.get_kind () == Module::UNLOADED)
!       {
! 	push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
! 	newline ();
!       }
!     else /* Module::LOADED */
!       {
! 	push (Rust::Token::make (LEFT_CURLY, UNDEF_LOCATION));
! 	newline ();
! 	increment_indentation ();
  
! 	visit_items_as_lines (module.get_inner_attrs ());
! 	visit_items_as_lines (module.get_items ());
  
! 	decrement_indentation ();
  
! 	push (Rust::Token::make (RIGHT_CURLY, UNDEF_LOCATION));
! 	newline ();
!       }
!   });
  }
  
  void
  TokenCollector::visit (ExternCrate &crate)
  {
!   describe_node (std::string ("ExternCrate"), [this, &crate] () {
!     visit_items_as_lines (crate.get_outer_attrs ());
!     push (Rust::Token::make (EXTERN_KW, crate.get_locus ()));
!     push (Rust::Token::make (CRATE, UNDEF_LOCATION));
!     auto ref = crate.get_referenced_crate ();
!     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (ref)));
!     if (crate.has_as_clause ())
!       {
! 	auto as_clause = crate.get_as_clause ();
! 	push (Rust::Token::make (AS, UNDEF_LOCATION));
! 	push (
! 	  Rust::Token::make_identifier (UNDEF_LOCATION, std::move (as_clause)));
!       }
!     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
!     newline ();
!   });
  }
  
  void
  TokenCollector::visit (UseTreeGlob &use_tree)
  {
!   describe_node (std::string ("UseTreeGlob"), [this, &use_tree] () {
!     switch (use_tree.get_glob_type ())
        {
!       case UseTreeGlob::PathType::PATH_PREFIXED:
! 	{
! 	  auto path = use_tree.get_path ();
! 	  visit (path);
! 	  push (Rust::Token::make (SCOPE_RESOLUTION, UNDEF_LOCATION));
! 	}
! 	break;
!       case UseTreeGlob::PathType::NO_PATH:
  	push (Rust::Token::make (SCOPE_RESOLUTION, UNDEF_LOCATION));
+ 	break;
+       case UseTreeGlob::PathType::GLOBAL:
+ 	break;
        }
!     push (Rust::Token::make (ASTERISK, UNDEF_LOCATION));
!   });
  }
  
  void
  TokenCollector::visit (UseTreeList &use_tree)
  {
!   describe_node (std::string ("UseTreeList"), [this, &use_tree] () {
!     switch (use_tree.get_path_type ())
        {
!       case UseTreeList::PathType::PATH_PREFIXED:
! 	{
! 	  auto path = use_tree.get_path ();
! 	  visit (path);
! 
! 	  push (Rust::Token::make (SCOPE_RESOLUTION, UNDEF_LOCATION));
! 	}
! 	break;
!       case UseTreeList::PathType::NO_PATH:
  	push (Rust::Token::make (SCOPE_RESOLUTION, UNDEF_LOCATION));
+ 	break;
+       case UseTreeList::PathType::GLOBAL:
+ 	break;
        }
  
!     push (Rust::Token::make (LEFT_CURLY, UNDEF_LOCATION));
!     if (use_tree.has_trees ())
!       {
! 	visit_items_joined_by_separator (use_tree.get_trees (), COMMA);
!       }
!     push (Rust::Token::make (RIGHT_CURLY, UNDEF_LOCATION));
!   });
  }
  
  void
  TokenCollector::visit (UseTreeRebind &use_tree)
  {
!   describe_node (std::string ("UseTreeRebind"), [this, &use_tree] () {
!     auto path = use_tree.get_path ();
!     visit (path);
!     switch (use_tree.get_new_bind_type ())
        {
+       case UseTreeRebind::NewBindType::IDENTIFIER:
+ 	{
+ 	  push (Rust::Token::make (AS, UNDEF_LOCATION));
+ 	  auto id = use_tree.get_identifier ().as_string ();
+ 	  push (Rust::Token::make_identifier (use_tree.get_locus (),
+ 					      std::move (id)));
+ 	}
+ 	break;
+       case UseTreeRebind::NewBindType::WILDCARD:
  	push (Rust::Token::make (AS, UNDEF_LOCATION));
! 	push (Rust::Token::make (UNDERSCORE, use_tree.get_locus ()));
! 	break;
!       case UseTreeRebind::NewBindType::NONE:
! 	break;
        }
!   });
  }
  
  void
  TokenCollector::visit (UseDeclaration &decl)
  {
!   describe_node (std::string ("UseDeclaration"), [this, &decl] () {
!     visit_items_as_lines (decl.get_outer_attrs ());
!     push (Rust::Token::make (USE, decl.get_locus ()));
!     visit (*decl.get_tree ());
!     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
!     newline ();
!   });
  }
  
  void
*************** TokenCollector::visit (Function &functio
*** 1906,1942 ****
    //      ( FunctionParameters? )
    //      FunctionReturnType? WhereClause?
    //      ( BlockExpression | ; )
!   visit_items_as_lines (function.get_outer_attrs ());
  
!   visit (function.get_visibility ());
!   auto qualifiers = function.get_qualifiers ();
!   visit (qualifiers);
  
!   push (Rust::Token::make (FN_KW, function.get_locus ()));
!   auto name = function.get_function_name ().as_string ();
!   push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (name)));
!   if (function.has_generics ())
!     visit (function.get_generic_params ());
  
!   push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
  
!   visit_items_joined_by_separator (function.get_function_params ());
!   push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
  
!   if (function.has_return_type ())
!     {
!       push (Rust::Token::make (RETURN_TYPE, UNDEF_LOCATION));
!       visit (function.get_return_type ());
!     }
  
!   if (function.has_where_clause ())
!     visit (function.get_where_clause ());
  
!   if (function.has_body ())
!     visit (*function.get_definition ());
!   else
!     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
!   newline ();
  }
  
  void
--- 2134,2172 ----
    //      ( FunctionParameters? )
    //      FunctionReturnType? WhereClause?
    //      ( BlockExpression | ; )
!   describe_node (std::string ("Function"), [this, &function] () {
!     visit_items_as_lines (function.get_outer_attrs ());
  
!     visit (function.get_visibility ());
!     auto qualifiers = function.get_qualifiers ();
!     visit (qualifiers);
  
!     push (Rust::Token::make (FN_KW, function.get_locus ()));
!     auto name = function.get_function_name ().as_string ();
!     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (name)));
!     if (function.has_generics ())
!       visit (function.get_generic_params ());
  
!     push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
  
!     visit_items_joined_by_separator (function.get_function_params ());
!     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
  
!     if (function.has_return_type ())
!       {
! 	push (Rust::Token::make (RETURN_TYPE, UNDEF_LOCATION));
! 	visit (function.get_return_type ());
!       }
  
!     if (function.has_where_clause ())
!       visit (function.get_where_clause ());
  
!     if (function.has_body ())
!       visit (*function.get_definition ());
!     else
!       push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
!     newline ();
!   });
  }
  
  void
*************** TokenCollector::visit (TypeAlias &type_a
*** 1946,2130 ****
    // Visibility? type IDENTIFIER GenericParams? WhereClause? = Type;
  
    // Note: Associated types are handled by `AST::TraitItemType`.
  
!   visit_items_as_lines (type_alias.get_outer_attrs ());
!   if (type_alias.has_visibility ())
!     visit (type_alias.get_visibility ());
!   auto alias_name = type_alias.get_new_type_name ().as_string ();
!   push (Rust::Token::make (TYPE, type_alias.get_locus ()));
!   push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (alias_name)));
! 
!   if (type_alias.has_generics ())
!     visit (type_alias.get_generic_params ());
  
!   if (type_alias.has_where_clause ())
!     visit (type_alias.get_where_clause ());
  
!   push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
!   visit (type_alias.get_type_aliased ());
!   push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
  }
  
  void
  TokenCollector::visit (StructStruct &struct_item)
  {
!   visit_items_as_lines (struct_item.get_outer_attrs ());
!   if (struct_item.has_visibility ())
!     visit (struct_item.get_visibility ());
!   auto struct_name = struct_item.get_identifier ().as_string ();
!   push (Rust::Token::make (STRUCT_KW, struct_item.get_locus ()));
!   push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (struct_name)));
  
!   if (struct_item.has_generics ())
!     visit (struct_item.get_generic_params ());
!   if (struct_item.has_where_clause ())
!     visit (struct_item.get_where_clause ());
!   if (struct_item.is_unit_struct ())
!     {
!       push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
!       newline ();
!     }
!   else
!     visit_items_as_block (struct_item.get_fields (),
! 			  {Rust::Token::make (COMMA, UNDEF_LOCATION)});
  }
  
  void
  TokenCollector::visit (TupleStruct &tuple_struct)
  {
!   visit_items_as_lines (tuple_struct.get_outer_attrs ());
!   auto struct_name = tuple_struct.get_identifier ().as_string ();
!   push (Rust::Token::make (STRUCT_KW, tuple_struct.get_locus ()));
!   push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (struct_name)));
!   if (tuple_struct.has_generics ())
!     visit (tuple_struct.get_generic_params ());
!   if (tuple_struct.has_where_clause ())
!     visit (tuple_struct.get_where_clause ());
  
!   push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
!   visit_items_joined_by_separator (tuple_struct.get_fields (), COMMA);
!   push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
!   push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
!   newline ();
  }
  
  void
  TokenCollector::visit (EnumItem &item)
  {
!   visit_items_as_lines (item.get_outer_attrs ());
!   auto id = item.get_identifier ().as_string ();
!   push (Rust::Token::make_identifier (item.get_locus (), std::move (id)));
  }
  
  void
  TokenCollector::visit (EnumItemTuple &item)
  {
!   auto id = item.get_identifier ().as_string ();
!   push (Rust::Token::make_identifier (item.get_locus (), std::move (id)));
!   push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
!   visit_items_joined_by_separator (item.get_tuple_fields (), COMMA);
!   push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
  }
  
  void
  TokenCollector::visit (EnumItemStruct &item)
  {
!   auto id = item.get_identifier ().as_string ();
!   push (Rust::Token::make_identifier (item.get_locus (), std::move (id)));
!   visit_items_as_block (item.get_struct_fields (),
! 			{Rust::Token::make (COMMA, UNDEF_LOCATION)});
  }
  
  void
  TokenCollector::visit (EnumItemDiscriminant &item)
  {
!   auto id = item.get_identifier ().as_string ();
!   push (Rust::Token::make_identifier (item.get_locus (), std::move (id)));
!   push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
!   visit (item.get_expr ());
  }
  
  void
  TokenCollector::visit (Enum &enumeration)
  {
!   visit_items_as_lines (enumeration.get_outer_attrs ());
!   if (enumeration.has_visibility ())
!     visit (enumeration.get_visibility ());
!   push (Rust::Token::make (ENUM_KW, enumeration.get_locus ()));
!   auto id = enumeration.get_identifier ().as_string ();
!   push (
!     Rust::Token::make_identifier (enumeration.get_locus (), std::move (id)));
!   if (enumeration.has_generics ())
!     visit (enumeration.get_generic_params ());
!   if (enumeration.has_where_clause ())
!     visit (enumeration.get_where_clause ());
  
!   visit_items_as_block (enumeration.get_variants (),
! 			{Rust::Token::make (COMMA, UNDEF_LOCATION)});
  }
  
  void
  TokenCollector::visit (Union &union_item)
  {
!   visit_items_as_lines (union_item.get_outer_attrs ());
!   auto id = union_item.get_identifier ().as_string ();
!   push (Rust::Token::make_identifier (union_item.get_locus (),
! 				      Values::WeakKeywords::UNION));
!   push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
  
!   if (union_item.has_generics ())
!     visit (union_item.get_generic_params ());
  
!   if (union_item.has_where_clause ())
!     visit (union_item.get_where_clause ());
  
!   visit_items_as_block (union_item.get_variants (),
! 			{Rust::Token::make (COMMA, UNDEF_LOCATION)});
  }
  
  void
  TokenCollector::visit (ConstantItem &item)
  {
!   visit_items_as_lines (item.get_outer_attrs ());
!   push (Rust::Token::make (CONST, item.get_locus ()));
!   if (item.is_unnamed ())
!     {
!       push (Rust::Token::make (UNDERSCORE, UNDEF_LOCATION));
!     }
!   else
!     {
!       push (Rust::Token::make_identifier (item.get_identifier ()));
!     }
!   push (Rust::Token::make (COLON, UNDEF_LOCATION));
!   visit (item.get_type ());
!   if (item.has_expr ())
!     {
!       push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
!       visit (item.get_expr ());
!     }
!   push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
  }
  
  void
  TokenCollector::visit (StaticItem &item)
  {
!   visit_items_as_lines (item.get_outer_attrs ());
!   push (Rust::Token::make (STATIC_KW, item.get_locus ()));
!   if (item.is_mutable ())
!     push (Rust::Token::make (MUT, UNDEF_LOCATION));
  
!   auto id = item.get_identifier ().as_string ();
!   push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
!   push (Rust::Token::make (COLON, UNDEF_LOCATION));
  
!   visit (item.get_type ());
  
!   if (item.has_expr ())
!     {
!       push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
!       visit (item.get_expr ());
!     }
!   push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
  }
  
  void
--- 2176,2384 ----
    // Visibility? type IDENTIFIER GenericParams? WhereClause? = Type;
  
    // Note: Associated types are handled by `AST::TraitItemType`.
+   describe_node (std::string ("TypeAlias"), [this, &type_alias] () {
+     visit_items_as_lines (type_alias.get_outer_attrs ());
+     if (type_alias.has_visibility ())
+       visit (type_alias.get_visibility ());
+     auto alias_name = type_alias.get_new_type_name ().as_string ();
+     push (Rust::Token::make (TYPE, type_alias.get_locus ()));
+     push (
+       Rust::Token::make_identifier (UNDEF_LOCATION, std::move (alias_name)));
  
!     if (type_alias.has_generics ())
!       visit (type_alias.get_generic_params ());
  
!     if (type_alias.has_where_clause ())
!       visit (type_alias.get_where_clause ());
  
!     push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
!     visit (type_alias.get_type_aliased ());
!     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
!   });
  }
  
  void
  TokenCollector::visit (StructStruct &struct_item)
  {
!   describe_node (std::string ("StructStruct"), [this, &struct_item] () {
!     visit_items_as_lines (struct_item.get_outer_attrs ());
!     if (struct_item.has_visibility ())
!       visit (struct_item.get_visibility ());
!     auto struct_name = struct_item.get_identifier ().as_string ();
!     push (Rust::Token::make (STRUCT_KW, struct_item.get_locus ()));
!     push (
!       Rust::Token::make_identifier (UNDEF_LOCATION, std::move (struct_name)));
  
!     if (struct_item.has_generics ())
!       visit (struct_item.get_generic_params ());
!     if (struct_item.has_where_clause ())
!       visit (struct_item.get_where_clause ());
!     if (struct_item.is_unit_struct ())
!       {
! 	push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
! 	newline ();
!       }
!     else
!       visit_items_as_block (struct_item.get_fields (),
! 			    {Rust::Token::make (COMMA, UNDEF_LOCATION)});
!   });
  }
  
  void
  TokenCollector::visit (TupleStruct &tuple_struct)
  {
!   describe_node (std::string ("TupleStruct"), [this, &tuple_struct] () {
!     visit_items_as_lines (tuple_struct.get_outer_attrs ());
!     auto struct_name = tuple_struct.get_identifier ().as_string ();
!     push (Rust::Token::make (STRUCT_KW, tuple_struct.get_locus ()));
!     push (
!       Rust::Token::make_identifier (UNDEF_LOCATION, std::move (struct_name)));
!     if (tuple_struct.has_generics ())
!       visit (tuple_struct.get_generic_params ());
!     if (tuple_struct.has_where_clause ())
!       visit (tuple_struct.get_where_clause ());
  
!     push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
!     visit_items_joined_by_separator (tuple_struct.get_fields (), COMMA);
!     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
!     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
!     newline ();
!   });
  }
  
  void
  TokenCollector::visit (EnumItem &item)
  {
!   describe_node (std::string ("EnumItem"), [this, &item] () {
!     visit_items_as_lines (item.get_outer_attrs ());
!     auto id = item.get_identifier ().as_string ();
!     push (Rust::Token::make_identifier (item.get_locus (), std::move (id)));
!   });
  }
  
  void
  TokenCollector::visit (EnumItemTuple &item)
  {
!   describe_node (std::string ("EnumItemTuple"), [this, &item] () {
!     auto id = item.get_identifier ().as_string ();
!     push (Rust::Token::make_identifier (item.get_locus (), std::move (id)));
!     push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
!     visit_items_joined_by_separator (item.get_tuple_fields (), COMMA);
!     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
!   });
  }
  
  void
  TokenCollector::visit (EnumItemStruct &item)
  {
!   describe_node (std::string ("EnumItemStruct"), [this, &item] () {
!     auto id = item.get_identifier ().as_string ();
!     push (Rust::Token::make_identifier (item.get_locus (), std::move (id)));
!     visit_items_as_block (item.get_struct_fields (),
! 			  {Rust::Token::make (COMMA, UNDEF_LOCATION)});
!   });
  }
  
  void
  TokenCollector::visit (EnumItemDiscriminant &item)
  {
!   describe_node (std::string ("EnumItemDiscriminant"), [this, &item] () {
!     auto id = item.get_identifier ().as_string ();
!     push (Rust::Token::make_identifier (item.get_locus (), std::move (id)));
!     push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
!     visit (item.get_expr ());
!   });
  }
  
  void
  TokenCollector::visit (Enum &enumeration)
  {
!   describe_node (std::string ("Enum"), [this, &enumeration] () {
!     visit_items_as_lines (enumeration.get_outer_attrs ());
!     if (enumeration.has_visibility ())
!       visit (enumeration.get_visibility ());
!     push (Rust::Token::make (ENUM_KW, enumeration.get_locus ()));
!     auto id = enumeration.get_identifier ().as_string ();
!     push (
!       Rust::Token::make_identifier (enumeration.get_locus (), std::move (id)));
!     if (enumeration.has_generics ())
!       visit (enumeration.get_generic_params ());
!     if (enumeration.has_where_clause ())
!       visit (enumeration.get_where_clause ());
  
!     visit_items_as_block (enumeration.get_variants (),
! 			  {Rust::Token::make (COMMA, UNDEF_LOCATION)});
!   });
  }
  
  void
  TokenCollector::visit (Union &union_item)
  {
!   describe_node (std::string ("Union"), [this, &union_item] () {
!     visit_items_as_lines (union_item.get_outer_attrs ());
!     auto id = union_item.get_identifier ().as_string ();
!     push (Rust::Token::make_identifier (union_item.get_locus (),
! 					Values::WeakKeywords::UNION));
!     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
  
!     if (union_item.has_generics ())
!       visit (union_item.get_generic_params ());
  
!     if (union_item.has_where_clause ())
!       visit (union_item.get_where_clause ());
  
!     visit_items_as_block (union_item.get_variants (),
! 			  {Rust::Token::make (COMMA, UNDEF_LOCATION)});
!   });
  }
  
  void
  TokenCollector::visit (ConstantItem &item)
  {
!   describe_node (std::string ("ConstantItem"), [this, &item] () {
!     visit_items_as_lines (item.get_outer_attrs ());
!     push (Rust::Token::make (CONST, item.get_locus ()));
!     if (item.is_unnamed ())
!       {
! 	push (Rust::Token::make (UNDERSCORE, UNDEF_LOCATION));
!       }
!     else
!       {
! 	push (Rust::Token::make_identifier (item.get_identifier ()));
!       }
!     push (Rust::Token::make (COLON, UNDEF_LOCATION));
!     visit (item.get_type ());
!     if (item.has_expr ())
!       {
! 	push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
! 	visit (item.get_expr ());
!       }
!     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
!   });
  }
  
  void
  TokenCollector::visit (StaticItem &item)
  {
!   describe_node (std::string ("StaticItem"), [this, &item] () {
!     visit_items_as_lines (item.get_outer_attrs ());
!     push (Rust::Token::make (STATIC_KW, item.get_locus ()));
!     if (item.is_mutable ())
!       push (Rust::Token::make (MUT, UNDEF_LOCATION));
  
!     auto id = item.get_identifier ().as_string ();
!     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
!     push (Rust::Token::make (COLON, UNDEF_LOCATION));
  
!     visit (item.get_type ());
  
!     if (item.has_expr ())
!       {
! 	push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
! 	visit (item.get_expr ());
!       }
!     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
!   });
  }
  
  void
*************** TokenCollector::visit_function_common (s
*** 2152,2288 ****
  void
  TokenCollector::visit (SelfParam &param)
  {
!   if (param.get_has_ref ())
!     {
!       push (Rust::Token::make (AMP, UNDEF_LOCATION));
!       if (param.has_lifetime ())
! 	{
! 	  auto lifetime = param.get_lifetime ();
! 	  visit (lifetime);
! 	}
!       if (param.get_is_mut ())
! 	push (Rust::Token::make (MUT, UNDEF_LOCATION));
!     }
!   push (Rust::Token::make (SELF, UNDEF_LOCATION));
!   if (param.has_type ())
!     {
!       push (Rust::Token::make (COLON, UNDEF_LOCATION));
!       visit (param.get_type ());
!     }
  }
  
  void
  TokenCollector::visit (TraitItemType &item)
  {
!   visit_items_as_lines (item.get_outer_attrs ());
!   auto id = item.get_identifier ().as_string ();
!   indentation ();
  
!   push (Rust::Token::make (TYPE, item.get_locus ()));
!   push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
!   push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
!   newline ();
  }
  
  void
  TokenCollector::visit (Trait &trait)
  {
!   for (auto &attr : trait.get_outer_attrs ())
!     {
!       visit (attr);
!       newline ();
!       indentation ();
!     }
  
!   visit (trait.get_visibility ());
  
!   auto id = trait.get_identifier ().as_string ();
!   push (Rust::Token::make (TRAIT, trait.get_locus ()));
!   push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
  
!   visit (trait.get_generic_params ());
  
!   visit_items_as_block (trait.get_trait_items (), {});
  }
  
  void
  TokenCollector::visit (InherentImpl &impl)
  {
!   visit_items_as_lines (impl.get_outer_attrs ());
!   push (Rust::Token::make (IMPL, impl.get_locus ()));
!   visit (impl.get_generic_params ());
  
!   visit (impl.get_type ());
  
!   if (impl.has_where_clause ())
!     visit (impl.get_where_clause ());
  
!   // FIXME: Handle inner attributes
  
!   visit_items_as_block (impl.get_impl_items (), {});
  }
  
  void
  TokenCollector::visit (TraitImpl &impl)
  {
!   visit_items_as_lines (impl.get_outer_attrs ());
!   push (Rust::Token::make (IMPL, impl.get_locus ()));
!   visit (impl.get_generic_params ());
!   if (impl.is_exclam ())
!     push (Rust::Token::make (EXCLAM, UNDEF_LOCATION));
!   visit (impl.get_trait_path ());
!   push (Rust::Token::make (FOR, UNDEF_LOCATION));
!   visit (impl.get_type ());
! 
!   if (impl.has_where_clause ())
!     visit (impl.get_where_clause ());
  
    visit_items_as_block (impl.get_impl_items ());
  }
  
  void
  TokenCollector::visit (ExternalTypeItem &type)
  {
!   visit (type.get_visibility ());
  
!   auto id = type.get_identifier ().as_string ();
  
!   push (Rust::Token::make (TYPE, UNDEF_LOCATION));
!   push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
!   push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
  }
  
  void
  TokenCollector::visit (ExternalStaticItem &item)
  {
!   auto id = item.get_identifier ().as_string ();
!   visit_items_as_lines (item.get_outer_attrs ());
!   if (item.has_visibility ())
!     visit (item.get_visibility ());
!   push (Rust::Token::make (STATIC_KW, item.get_locus ()));
!   if (item.is_mut ())
!     push (Rust::Token::make (MUT, UNDEF_LOCATION));
!   push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
!   push (Rust::Token::make (COLON, UNDEF_LOCATION));
!   visit (item.get_type ());
!   // TODO: No expr ? The "(= Expression)?" part from the reference seems missing
!   // in the ast.
!   push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
  }
  
  void
  TokenCollector::visit (ExternBlock &block)
  {
!   visit_items_as_lines (block.get_outer_attrs ());
!   push (Rust::Token::make (EXTERN_KW, block.get_locus ()));
  
!   if (block.has_abi ())
!     {
!       auto abi = block.get_abi ();
!       push (Rust::Token::make_string (UNDEF_LOCATION, std::move (abi)));
!     }
  
!   visit_items_as_block (block.get_extern_items (), {});
  }
  
  static std::pair<TokenId, TokenId>
--- 2406,2557 ----
  void
  TokenCollector::visit (SelfParam &param)
  {
!   describe_node (std::string ("SelfParam"), [this, &param] () {
!     if (param.get_has_ref ())
!       {
! 	push (Rust::Token::make (AMP, UNDEF_LOCATION));
! 	if (param.has_lifetime ())
! 	  {
! 	    auto lifetime = param.get_lifetime ();
! 	    visit (lifetime);
! 	  }
! 	if (param.get_is_mut ())
! 	  push (Rust::Token::make (MUT, UNDEF_LOCATION));
!       }
!     push (Rust::Token::make (SELF, UNDEF_LOCATION));
!     if (param.has_type ())
!       {
! 	push (Rust::Token::make (COLON, UNDEF_LOCATION));
! 	visit (param.get_type ());
!       }
!   });
  }
  
  void
  TokenCollector::visit (TraitItemType &item)
  {
!   describe_node (std::string ("TraitItemType"), [this, &item] () {
!     visit_items_as_lines (item.get_outer_attrs ());
!     auto id = item.get_identifier ().as_string ();
!     indentation ();
  
!     push (Rust::Token::make (TYPE, item.get_locus ()));
!     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
!     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
!     newline ();
!   });
  }
  
  void
  TokenCollector::visit (Trait &trait)
  {
!   describe_node (std::string ("Trait"), [this, &trait] () {
!     for (auto &attr : trait.get_outer_attrs ())
!       {
! 	visit (attr);
! 	newline ();
! 	indentation ();
!       }
  
!     visit (trait.get_visibility ());
  
!     auto id = trait.get_identifier ().as_string ();
!     push (Rust::Token::make (TRAIT, trait.get_locus ()));
!     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
  
!     visit (trait.get_generic_params ());
  
!     visit_items_as_block (trait.get_trait_items (), {});
!   });
  }
  
  void
  TokenCollector::visit (InherentImpl &impl)
  {
!   describe_node (std::string ("InherentImpl"), [this, &impl] () {
!     visit_items_as_lines (impl.get_outer_attrs ());
!     push (Rust::Token::make (IMPL, impl.get_locus ()));
!     visit (impl.get_generic_params ());
  
!     visit (impl.get_type ());
  
!     if (impl.has_where_clause ())
!       visit (impl.get_where_clause ());
  
!     // FIXME: Handle inner attributes
  
!     visit_items_as_block (impl.get_impl_items (), {});
!   });
  }
  
  void
  TokenCollector::visit (TraitImpl &impl)
  {
!   describe_node (std::string ("TraitImpl"), [this, &impl] () {
!     visit_items_as_lines (impl.get_outer_attrs ());
!     push (Rust::Token::make (IMPL, impl.get_locus ()));
!     visit (impl.get_generic_params ());
!     if (impl.is_exclam ())
!       push (Rust::Token::make (EXCLAM, UNDEF_LOCATION));
!     visit (impl.get_trait_path ());
!     push (Rust::Token::make (FOR, UNDEF_LOCATION));
!     visit (impl.get_type ());
  
+     if (impl.has_where_clause ())
+       visit (impl.get_where_clause ());
+   });
    visit_items_as_block (impl.get_impl_items ());
  }
  
  void
  TokenCollector::visit (ExternalTypeItem &type)
  {
!   describe_node (std::string ("ExternalTypeItem"), [this, &type] () {
!     visit (type.get_visibility ());
  
!     auto id = type.get_identifier ().as_string ();
  
!     push (Rust::Token::make (TYPE, UNDEF_LOCATION));
!     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
!     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
!   });
  }
  
  void
  TokenCollector::visit (ExternalStaticItem &item)
  {
!   describe_node (std::string ("ExternalStaticItem"), [this, &item] () {
!     auto id = item.get_identifier ().as_string ();
!     visit_items_as_lines (item.get_outer_attrs ());
!     if (item.has_visibility ())
!       visit (item.get_visibility ());
!     push (Rust::Token::make (STATIC_KW, item.get_locus ()));
!     if (item.is_mut ())
!       push (Rust::Token::make (MUT, UNDEF_LOCATION));
!     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
!     push (Rust::Token::make (COLON, UNDEF_LOCATION));
!     visit (item.get_type ());
!     // TODO: No expr ? The "(= Expression)?" part from the reference seems
!     // missing in the ast.
!     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
!   });
  }
  
  void
  TokenCollector::visit (ExternBlock &block)
  {
!   describe_node (std::string ("ExternBlock"), [this, &block] () {
!     visit_items_as_lines (block.get_outer_attrs ());
!     push (Rust::Token::make (EXTERN_KW, block.get_locus ()));
  
!     if (block.has_abi ())
!       {
! 	auto abi = block.get_abi ();
! 	push (Rust::Token::make_string (UNDEF_LOCATION, std::move (abi)));
!       }
  
!     visit_items_as_block (block.get_extern_items (), {});
!   });
  }
  
  static std::pair<TokenId, TokenId>
*************** get_delimiters (DelimType delim)
*** 2304,2507 ****
  void
  TokenCollector::visit (MacroMatchFragment &match)
  {
!   auto id = match.get_ident ().as_string ();
!   auto frag_spec = match.get_frag_spec ().as_string ();
!   push (Rust::Token::make (DOLLAR_SIGN, UNDEF_LOCATION));
!   push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
!   push (Rust::Token::make (COLON, UNDEF_LOCATION));
!   push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (frag_spec)));
  }
  
  void
  TokenCollector::visit (MacroMatchRepetition &repetition)
  {
!   push (Rust::Token::make (DOLLAR_SIGN, UNDEF_LOCATION));
!   push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
  
!   for (auto &match : repetition.get_matches ())
!     {
!       visit (match);
!     }
  
!   push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
  
!   if (repetition.has_sep ())
!     {
!       push (Rust::Token::make (repetition.get_sep ()->get_id (),
! 			       repetition.get_sep ()->get_locus ()));
!     }
!   switch (repetition.get_op ())
!     {
!     case MacroMatchRepetition::ANY:
!       push (Rust::Token::make (ASTERISK, UNDEF_LOCATION));
!       break;
!     case MacroMatchRepetition::ONE_OR_MORE:
!       push (Rust::Token::make (PLUS, UNDEF_LOCATION));
!       break;
!     case MacroMatchRepetition::ZERO_OR_ONE:
!       push (Rust::Token::make (QUESTION_MARK, UNDEF_LOCATION));
!       break;
!     case MacroMatchRepetition::NONE:
!       break;
!     }
  }
  
  void
  TokenCollector::visit (MacroMatcher &matcher)
  {
!   auto delimiters = get_delimiters (matcher.get_delim_type ());
  
!   push (Rust::Token::make (delimiters.first, UNDEF_LOCATION));
  
!   for (auto &item : matcher.get_matches ())
!     {
!       visit (item);
!     }
  
!   push (Rust::Token::make (delimiters.second, UNDEF_LOCATION));
  }
  
  void
  TokenCollector::visit (MacroRule &rule)
  {
!   visit (rule.get_matcher ());
!   push (Rust::Token::make (MATCH_ARROW, rule.get_locus ()));
!   visit (rule.get_transcriber ().get_token_tree ());
  }
  
  void
  TokenCollector::visit (MacroRulesDefinition &rules_def)
  {
!   for (auto &outer_attr : rules_def.get_outer_attrs ())
!     visit (outer_attr);
  
!   auto rule_name = rules_def.get_rule_name ().as_string ();
  
!   push (Rust::Token::make_identifier (rules_def.get_locus (),
! 				      Values::WeakKeywords::MACRO_RULES));
!   push (Rust::Token::make (EXCLAM, UNDEF_LOCATION));
  
!   push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (rule_name)));
  
!   visit_items_as_block (rules_def.get_rules (),
! 			{Rust::Token::make (SEMICOLON, UNDEF_LOCATION)});
  }
  
  void
  TokenCollector::visit (MacroInvocation &invocation)
  {
!   auto data = invocation.get_invoc_data ();
!   visit (data.get_path ());
!   push (Rust::Token::make (EXCLAM, UNDEF_LOCATION));
!   visit (data.get_delim_tok_tree ());
!   if (invocation.has_semicolon ())
!     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
  }
  
  void
  TokenCollector::visit (MetaItemPath &item)
  {
!   auto path = item.to_path_item ();
!   visit (path);
  }
  
  void
  TokenCollector::visit (MetaItemSeq &item)
  {
!   visit (item.get_path ());
!   // TODO: Double check this, there is probably a mistake.
!   push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
!   visit_items_joined_by_separator (item.get_seq (), COMMA);
!   push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
  }
  
  void
  TokenCollector::visit (MetaWord &word)
  {
!   auto id = word.get_ident ().as_string ();
  
!   push (Rust::Token::make_identifier (word.get_locus (), std::move (id)));
  }
  
  void
  TokenCollector::visit (MetaNameValueStr &name)
  {
!   auto pair = name.get_name_value_pair ();
!   auto id = std::get<0> (pair).as_string ();
!   auto value = std::get<1> (pair);
  
!   push (Rust::Token::make_identifier (name.get_locus (), std::move (id)));
!   push (Rust::Token::make (EQUAL, name.get_locus ()));
!   push (Rust::Token::make (DOUBLE_QUOTE, UNDEF_LOCATION));
!   push (Rust::Token::make_identifier (name.get_locus (), std::move (value)));
!   push (Rust::Token::make (DOUBLE_QUOTE, UNDEF_LOCATION));
  }
  
  void
  TokenCollector::visit (MetaListPaths &list)
  {
!   auto id = list.get_ident ().as_string ();
  
!   push (Rust::Token::make_identifier (list.get_locus (), std::move (id)));
!   push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
  
!   visit_items_joined_by_separator (list.get_paths (), COMMA);
  
!   push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
  }
  
  void
  TokenCollector::visit (MetaListNameValueStr &list)
  {
!   auto id = list.get_ident ().as_string ();
  
!   push (Rust::Token::make_identifier (list.get_locus (), std::move (id)));
!   push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
  
!   visit_items_joined_by_separator (list.get_values (), COMMA);
  
!   push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
  }
  
  // rust-pattern.h
  void
  TokenCollector::visit (LiteralPattern &pattern)
  {
!   visit (pattern.get_literal (), pattern.get_locus ());
  }
  
  void
  TokenCollector::visit (IdentifierPattern &pattern)
  {
!   if (pattern.get_is_ref ())
!     {
!       push (Rust::Token::make (REF, pattern.get_locus ()));
!     }
!   if (pattern.get_is_mut ())
!     {
!       push (Rust::Token::make (MUT, UNDEF_LOCATION));
!     }
  
!   auto id = pattern.get_ident ().as_string ();
!   push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
  
!   if (pattern.has_subpattern ())
!     {
!       push (Rust::Token::make (PATTERN_BIND, UNDEF_LOCATION));
!       visit (pattern.get_subpattern ());
!     }
  }
  
  void
  TokenCollector::visit (WildcardPattern &pattern)
  {
!   push (Rust::Token::make (UNDERSCORE, pattern.get_locus ()));
  }
  
  void
  TokenCollector::visit (RestPattern &pattern)
  {
!   push (Rust::Token::make (DOT_DOT, pattern.get_locus ()));
  }
  
  // void TokenCollector::visit(RangePatternBound& ){}
--- 2573,2808 ----
  void
  TokenCollector::visit (MacroMatchFragment &match)
  {
!   describe_node (std::string ("MacroMatchFragment"), [this, &match] () {
!     auto id = match.get_ident ().as_string ();
!     auto frag_spec = match.get_frag_spec ().as_string ();
!     push (Rust::Token::make (DOLLAR_SIGN, UNDEF_LOCATION));
!     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
!     push (Rust::Token::make (COLON, UNDEF_LOCATION));
!     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (frag_spec)));
!   });
  }
  
  void
  TokenCollector::visit (MacroMatchRepetition &repetition)
  {
!   describe_node (std::string ("MacroMatchRepetition"), [this, &repetition] () {
!     push (Rust::Token::make (DOLLAR_SIGN, UNDEF_LOCATION));
!     push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
  
!     for (auto &match : repetition.get_matches ())
!       {
! 	visit (match);
!       }
  
!     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
  
!     if (repetition.has_sep ())
!       {
! 	push (Rust::Token::make (repetition.get_sep ()->get_id (),
! 				 repetition.get_sep ()->get_locus ()));
!       }
!     switch (repetition.get_op ())
!       {
!       case MacroMatchRepetition::ANY:
! 	push (Rust::Token::make (ASTERISK, UNDEF_LOCATION));
! 	break;
!       case MacroMatchRepetition::ONE_OR_MORE:
! 	push (Rust::Token::make (PLUS, UNDEF_LOCATION));
! 	break;
!       case MacroMatchRepetition::ZERO_OR_ONE:
! 	push (Rust::Token::make (QUESTION_MARK, UNDEF_LOCATION));
! 	break;
!       case MacroMatchRepetition::NONE:
! 	break;
!       }
!   });
  }
  
  void
  TokenCollector::visit (MacroMatcher &matcher)
  {
!   describe_node (std::string ("MacroMatcher"), [this, &matcher] () {
!     auto delimiters = get_delimiters (matcher.get_delim_type ());
  
!     push (Rust::Token::make (delimiters.first, UNDEF_LOCATION));
  
!     for (auto &item : matcher.get_matches ())
!       {
! 	visit (item);
!       }
  
!     push (Rust::Token::make (delimiters.second, UNDEF_LOCATION));
!   });
  }
  
  void
  TokenCollector::visit (MacroRule &rule)
  {
!   describe_node (std::string ("MacroRule"), [this, &rule] () {
!     visit (rule.get_matcher ());
!     push (Rust::Token::make (MATCH_ARROW, rule.get_locus ()));
!     visit (rule.get_transcriber ().get_token_tree ());
!   });
  }
  
  void
  TokenCollector::visit (MacroRulesDefinition &rules_def)
  {
!   describe_node (std::string ("MacroRulesDefinition"), [this, &rules_def] () {
!     for (auto &outer_attr : rules_def.get_outer_attrs ())
!       visit (outer_attr);
  
!     auto rule_name = rules_def.get_rule_name ().as_string ();
  
!     push (Rust::Token::make_identifier (rules_def.get_locus (),
! 					Values::WeakKeywords::MACRO_RULES));
!     push (Rust::Token::make (EXCLAM, UNDEF_LOCATION));
  
!     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (rule_name)));
  
!     visit_items_as_block (rules_def.get_rules (),
! 			  {Rust::Token::make (SEMICOLON, UNDEF_LOCATION)});
!   });
  }
  
  void
  TokenCollector::visit (MacroInvocation &invocation)
  {
!   describe_node (std::string ("MacroInvocation"), [this, &invocation] () {
!     auto data = invocation.get_invoc_data ();
!     visit (data.get_path ());
!     push (Rust::Token::make (EXCLAM, UNDEF_LOCATION));
!     visit (data.get_delim_tok_tree ());
!     if (invocation.has_semicolon ())
!       push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
!   });
  }
  
  void
  TokenCollector::visit (MetaItemPath &item)
  {
!   describe_node (std::string ("MetaItemPath"), [this, &item] () {
!     auto path = item.to_path_item ();
!     visit (path);
!   });
  }
  
  void
  TokenCollector::visit (MetaItemSeq &item)
  {
!   describe_node (std::string ("MetaItemSeq"), [this, &item] () {
!     visit (item.get_path ());
!     // TODO: Double check this, there is probably a mistake.
!     push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
!     visit_items_joined_by_separator (item.get_seq (), COMMA);
!     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
!   });
  }
  
  void
  TokenCollector::visit (MetaWord &word)
  {
!   describe_node (std::string ("MetaWord"), [this, &word] () {
!     auto id = word.get_ident ().as_string ();
  
!     push (Rust::Token::make_identifier (word.get_locus (), std::move (id)));
!   });
  }
  
  void
  TokenCollector::visit (MetaNameValueStr &name)
  {
!   describe_node (std::string ("MetaNameValueStr"), [this, &name] () {
!     auto pair = name.get_name_value_pair ();
!     auto id = std::get<0> (pair).as_string ();
!     auto value = std::get<1> (pair);
  
!     push (Rust::Token::make_identifier (name.get_locus (), std::move (id)));
!     push (Rust::Token::make (EQUAL, name.get_locus ()));
!     push (Rust::Token::make (DOUBLE_QUOTE, UNDEF_LOCATION));
!     push (Rust::Token::make_identifier (name.get_locus (), std::move (value)));
!     push (Rust::Token::make (DOUBLE_QUOTE, UNDEF_LOCATION));
!   });
  }
  
  void
  TokenCollector::visit (MetaListPaths &list)
  {
!   describe_node (std::string ("MetaListPath"), [this, &list] () {
!     auto id = list.get_ident ().as_string ();
  
!     push (Rust::Token::make_identifier (list.get_locus (), std::move (id)));
!     push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
  
!     visit_items_joined_by_separator (list.get_paths (), COMMA);
  
!     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
!   });
  }
  
  void
  TokenCollector::visit (MetaListNameValueStr &list)
  {
!   describe_node (std::string ("MetaListNameValueStr"), [this, &list] () {
!     auto id = list.get_ident ().as_string ();
  
!     push (Rust::Token::make_identifier (list.get_locus (), std::move (id)));
!     push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
  
!     visit_items_joined_by_separator (list.get_values (), COMMA);
  
!     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
!   });
  }
  
  // rust-pattern.h
  void
  TokenCollector::visit (LiteralPattern &pattern)
  {
!   describe_node (std::string ("LiteralPattern"), [this, &pattern] () {
!     visit (pattern.get_literal (), pattern.get_locus ());
!   });
  }
  
  void
  TokenCollector::visit (IdentifierPattern &pattern)
  {
!   describe_node (std::string ("IdentifierPattern"), [this, &pattern] () {
!     if (pattern.get_is_ref ())
!       {
! 	push (Rust::Token::make (REF, pattern.get_locus ()));
!       }
!     if (pattern.get_is_mut ())
!       {
! 	push (Rust::Token::make (MUT, UNDEF_LOCATION));
!       }
  
!     auto id = pattern.get_ident ().as_string ();
!     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
  
!     if (pattern.has_subpattern ())
!       {
! 	push (Rust::Token::make (PATTERN_BIND, UNDEF_LOCATION));
! 	visit (pattern.get_subpattern ());
!       }
!   });
  }
  
  void
  TokenCollector::visit (WildcardPattern &pattern)
  {
!   describe_node (std::string ("WildcardPattern"), [this, &pattern] () {
!     push (Rust::Token::make (UNDERSCORE, pattern.get_locus ()));
!   });
  }
  
  void
  TokenCollector::visit (RestPattern &pattern)
  {
!   describe_node (std::string ("RestPattern"), [this, &pattern] () {
!     push (Rust::Token::make (DOT_DOT, pattern.get_locus ()));
!   });
  }
  
  // void TokenCollector::visit(RangePatternBound& ){}
*************** TokenCollector::visit (RestPattern &patt
*** 2509,2576 ****
  void
  TokenCollector::visit (RangePatternBoundLiteral &pattern)
  {
!   if (pattern.get_has_minus ())
!     {
!       push (Rust::Token::make (MINUS, pattern.get_locus ()));
!     }
!   auto literal = pattern.get_literal ();
!   visit (literal);
  }
  
  void
  TokenCollector::visit (RangePatternBoundPath &pattern)
  {
!   visit (pattern.get_path ());
  }
  
  void
  TokenCollector::visit (RangePatternBoundQualPath &pattern)
  {
!   visit (pattern.get_qualified_path ());
  }
  
  void
  TokenCollector::visit (RangePattern &pattern)
  {
!   if (pattern.get_has_lower_bound () && pattern.get_has_upper_bound ())
!     {
!       visit (pattern.get_lower_bound ());
!       if (pattern.get_has_ellipsis_syntax ())
! 	push (Rust::Token::make (ELLIPSIS, pattern.get_locus ()));
!       else
  	push (Rust::Token::make (DOT_DOT_EQ, pattern.get_locus ()));
!       visit (pattern.get_upper_bound ());
!     }
!   else if (pattern.get_has_lower_bound ())
!     {
!       visit (pattern.get_lower_bound ());
!       push (Rust::Token::make (DOT_DOT, pattern.get_locus ()));
!     }
!   else
!     {
!       push (Rust::Token::make (DOT_DOT_EQ, pattern.get_locus ()));
!       visit (pattern.get_upper_bound ());
!     }
  }
  
  void
  TokenCollector::visit (ReferencePattern &pattern)
  {
!   if (pattern.is_double_reference ())
!     {
!       push (Rust::Token::make (LOGICAL_AND, pattern.get_locus ()));
!     }
!   else
!     {
!       push (Rust::Token::make (AMP, pattern.get_locus ()));
!     }
  
!   if (pattern.get_is_mut ())
!     {
!       push (Rust::Token::make (MUT, UNDEF_LOCATION));
!     }
  
!   visit (pattern.get_referenced_pattern ());
  }
  
  // void TokenCollector::visit(StructPatternField& ){}
--- 2810,2888 ----
  void
  TokenCollector::visit (RangePatternBoundLiteral &pattern)
  {
!   describe_node (std::string ("RangePatternBoundLiteral"), [this, &pattern] () {
!     if (pattern.get_has_minus ())
!       {
! 	push (Rust::Token::make (MINUS, pattern.get_locus ()));
!       }
!     auto literal = pattern.get_literal ();
!     visit (literal);
!   });
  }
  
  void
  TokenCollector::visit (RangePatternBoundPath &pattern)
  {
!   describe_node (std::string ("RangePatternBoundPath"),
! 		 [this, &pattern] () { visit (pattern.get_path ()); });
  }
  
  void
  TokenCollector::visit (RangePatternBoundQualPath &pattern)
  {
!   describe_node (std::string ("RangePatternBoundQualPath"),
! 		 [this, &pattern] () {
! 		   visit (pattern.get_qualified_path ());
! 		 });
  }
  
  void
  TokenCollector::visit (RangePattern &pattern)
  {
!   describe_node (std::string ("RangePattern"), [this, &pattern] () {
!     if (pattern.get_has_lower_bound () && pattern.get_has_upper_bound ())
!       {
! 	visit (pattern.get_lower_bound ());
! 	if (pattern.get_has_ellipsis_syntax ())
! 	  push (Rust::Token::make (ELLIPSIS, pattern.get_locus ()));
! 	else
! 	  push (Rust::Token::make (DOT_DOT_EQ, pattern.get_locus ()));
! 	visit (pattern.get_upper_bound ());
!       }
!     else if (pattern.get_has_lower_bound ())
!       {
! 	visit (pattern.get_lower_bound ());
! 	push (Rust::Token::make (DOT_DOT, pattern.get_locus ()));
!       }
!     else
!       {
  	push (Rust::Token::make (DOT_DOT_EQ, pattern.get_locus ()));
! 	visit (pattern.get_upper_bound ());
!       }
!   });
  }
  
  void
  TokenCollector::visit (ReferencePattern &pattern)
+ 
  {
!   describe_node (std::string ("ReferencePattern"), [this, &pattern] () {
!     if (pattern.is_double_reference ())
!       {
! 	push (Rust::Token::make (LOGICAL_AND, pattern.get_locus ()));
!       }
!     else
!       {
! 	push (Rust::Token::make (AMP, pattern.get_locus ()));
!       }
  
!     if (pattern.get_is_mut ())
!       {
! 	push (Rust::Token::make (MUT, UNDEF_LOCATION));
!       }
  
!     visit (pattern.get_referenced_pattern ());
!   });
  }
  
  // void TokenCollector::visit(StructPatternField& ){}
*************** TokenCollector::visit (ReferencePattern
*** 2578,2637 ****
  void
  TokenCollector::visit (StructPatternFieldTuplePat &pattern)
  {
!   visit_items_as_lines (pattern.get_outer_attrs ());
!   push (Rust::Token::make_int (pattern.get_locus (),
! 			       std::to_string (pattern.get_index ())));
!   push (Rust::Token::make (COLON, pattern.get_locus ()));
!   visit (pattern.get_index_pattern ());
  }
  
  void
  TokenCollector::visit (StructPatternFieldIdentPat &pattern)
  {
!   visit_items_as_lines (pattern.get_outer_attrs ());
  
!   auto id = pattern.get_identifier ().as_string ();
!   push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
  
!   push (Rust::Token::make (COLON, pattern.get_locus ()));
  
!   visit (pattern.get_ident_pattern ());
  }
  
  void
  TokenCollector::visit (StructPatternFieldIdent &pattern)
  {
!   visit_items_as_lines (pattern.get_outer_attrs ());
!   if (pattern.is_ref ())
!     push (Rust::Token::make (REF, UNDEF_LOCATION));
!   if (pattern.is_mut ())
!     push (Rust::Token::make (MUT, UNDEF_LOCATION));
  
!   auto id = pattern.get_identifier ().as_string ();
!   push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
  }
  
  void
  TokenCollector::visit (StructPattern &pattern)
  {
!   visit (pattern.get_path ());
!   push (Rust::Token::make (LEFT_CURLY, pattern.get_locus ()));
!   auto elems = pattern.get_struct_pattern_elems ();
!   if (elems.has_struct_pattern_fields ())
!     {
!       visit_items_joined_by_separator (elems.get_struct_pattern_fields ());
!       if (elems.has_rest ())
! 	{
! 	  push (Rust::Token::make (COMMA, UNDEF_LOCATION));
! 	  visit_items_as_lines (elems.get_etc_outer_attrs ());
! 	}
!     }
!   else
!     {
!       visit_items_as_lines (elems.get_etc_outer_attrs ());
!     }
  
!   push (Rust::Token::make (RIGHT_CURLY, UNDEF_LOCATION));
  }
  
  // void TokenCollector::visit(TupleStructItems& ){}
--- 2890,2959 ----
  void
  TokenCollector::visit (StructPatternFieldTuplePat &pattern)
  {
!   describe_node (std::string ("StructPatternFieldTuplePat"), [this,
! 							      &pattern] () {
!     visit_items_as_lines (pattern.get_outer_attrs ());
!     push (Rust::Token::make_int (pattern.get_locus (),
! 				 std::to_string (pattern.get_index ())));
!     push (Rust::Token::make (COLON, pattern.get_locus ()));
!     visit (pattern.get_index_pattern ());
!   });
  }
  
  void
  TokenCollector::visit (StructPatternFieldIdentPat &pattern)
  {
!   describe_node (std::string ("StructPatternFieldIdentPat"), [this,
! 							      &pattern] () {
!     visit_items_as_lines (pattern.get_outer_attrs ());
  
!     auto id = pattern.get_identifier ().as_string ();
!     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
  
!     push (Rust::Token::make (COLON, pattern.get_locus ()));
  
!     visit (pattern.get_ident_pattern ());
!   });
  }
  
  void
  TokenCollector::visit (StructPatternFieldIdent &pattern)
  {
!   describe_node (std::string ("StructPatternFieldIdent"), [this, &pattern] () {
!     visit_items_as_lines (pattern.get_outer_attrs ());
!     if (pattern.is_ref ())
!       push (Rust::Token::make (REF, UNDEF_LOCATION));
!     if (pattern.is_mut ())
!       push (Rust::Token::make (MUT, UNDEF_LOCATION));
  
!     auto id = pattern.get_identifier ().as_string ();
!     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
!   });
  }
  
  void
  TokenCollector::visit (StructPattern &pattern)
  {
!   describe_node (std::string ("StructPattern"), [this, &pattern] () {
!     visit (pattern.get_path ());
!     push (Rust::Token::make (LEFT_CURLY, pattern.get_locus ()));
!     auto elems = pattern.get_struct_pattern_elems ();
!     if (elems.has_struct_pattern_fields ())
!       {
! 	visit_items_joined_by_separator (elems.get_struct_pattern_fields ());
! 	if (elems.has_rest ())
! 	  {
! 	    push (Rust::Token::make (COMMA, UNDEF_LOCATION));
! 	    visit_items_as_lines (elems.get_etc_outer_attrs ());
! 	  }
!       }
!     else
!       {
! 	visit_items_as_lines (elems.get_etc_outer_attrs ());
!       }
  
!     push (Rust::Token::make (RIGHT_CURLY, UNDEF_LOCATION));
!   });
  }
  
  // void TokenCollector::visit(TupleStructItems& ){}
*************** TokenCollector::visit (StructPattern &pa
*** 2639,2668 ****
  void
  TokenCollector::visit (TupleStructItemsNoRest &pattern)
  {
!   visit_items_joined_by_separator (pattern.get_patterns ());
  }
  
  void
  TokenCollector::visit (TupleStructItemsHasRest &pattern)
  {
!   for (auto &lower : pattern.get_lower_patterns ())
!     {
!       visit (lower);
!     }
!   push (Rust::Token::make (DOT_DOT, UNDEF_LOCATION));
!   for (auto &upper : pattern.get_lower_patterns ())
!     {
!       visit (upper);
!     }
  }
  
  void
  TokenCollector::visit (TupleStructPattern &pattern)
  {
!   visit (pattern.get_path ());
!   push (Rust::Token::make (LEFT_PAREN, pattern.get_locus ()));
!   visit (pattern.get_items ());
!   push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
  }
  
  // void
--- 2961,2996 ----
  void
  TokenCollector::visit (TupleStructItemsNoRest &pattern)
  {
!   describe_node (std::string ("TupleStructItemsNoRange"), [this, &pattern] () {
!     visit_items_joined_by_separator (pattern.get_patterns ());
!   });
  }
  
  void
  TokenCollector::visit (TupleStructItemsHasRest &pattern)
  {
!   describe_node (std::string ("TupleStructItemsRange"), [this, &pattern] () {
!     for (auto &lower : pattern.get_lower_patterns ())
!       {
! 	visit (lower);
!       }
!     push (Rust::Token::make (DOT_DOT, UNDEF_LOCATION));
!     for (auto &upper : pattern.get_lower_patterns ())
!       {
! 	visit (upper);
!       }
!   });
  }
  
  void
  TokenCollector::visit (TupleStructPattern &pattern)
  {
!   describe_node (std::string ("TupleStructPattern"), [this, &pattern] () {
!     visit (pattern.get_path ());
!     push (Rust::Token::make (LEFT_PAREN, pattern.get_locus ()));
!     visit (pattern.get_items ());
!     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
!   });
  }
  
  // void
*************** TokenCollector::visit (TupleStructPatter
*** 2672,2708 ****
  void
  TokenCollector::visit (TuplePatternItemsNoRest &pattern)
  {
!   visit_items_joined_by_separator (pattern.get_patterns (), COMMA);
  }
  
  void
  TokenCollector::visit (TuplePatternItemsHasRest &pattern)
  {
!   for (auto &lower : pattern.get_lower_patterns ())
!     {
!       visit (lower);
!     }
!   push (Rust::Token::make (DOT_DOT, UNDEF_LOCATION));
!   for (auto &upper : pattern.get_lower_patterns ())
!     {
!       visit (upper);
!     }
  }
  
  void
  TokenCollector::visit (TuplePattern &pattern)
  {
!   push (Rust::Token::make (LEFT_PAREN, pattern.get_locus ()));
!   visit (pattern.get_items ());
!   push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
  }
  
  void
  TokenCollector::visit (GroupedPattern &pattern)
  {
!   push (Rust::Token::make (LEFT_PAREN, pattern.get_locus ()));
!   visit (pattern.get_pattern_in_parens ());
!   push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
  }
  
  void
--- 3000,3045 ----
  void
  TokenCollector::visit (TuplePatternItemsNoRest &pattern)
  {
!   describe_node (std::string ("TuplePatternItemsMultiple"), [this,
! 							     &pattern] () {
!     visit_items_joined_by_separator (pattern.get_patterns (), COMMA);
!   });
  }
  
  void
  TokenCollector::visit (TuplePatternItemsHasRest &pattern)
  {
!   describe_node (std::string ("TuplePatternItemsRanged"), [this, &pattern] () {
!     for (auto &lower : pattern.get_lower_patterns ())
!       {
! 	visit (lower);
!       }
!     push (Rust::Token::make (DOT_DOT, UNDEF_LOCATION));
!     for (auto &upper : pattern.get_lower_patterns ())
!       {
! 	visit (upper);
!       }
!   });
  }
  
  void
  TokenCollector::visit (TuplePattern &pattern)
  {
!   describe_node (std::string ("TuplePattern"), [this, &pattern] () {
!     push (Rust::Token::make (LEFT_PAREN, pattern.get_locus ()));
!     visit (pattern.get_items ());
!     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
!   });
  }
  
  void
  TokenCollector::visit (GroupedPattern &pattern)
  {
!   describe_node (std::string ("GroupedPattern"), [this, &pattern] () {
!     push (Rust::Token::make (LEFT_PAREN, pattern.get_locus ()));
!     visit (pattern.get_pattern_in_parens ());
!     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
!   });
  }
  
  void
*************** TokenCollector::visit (SlicePatternItems
*** 2732,2746 ****
  void
  TokenCollector::visit (SlicePattern &pattern)
  {
!   push (Rust::Token::make (LEFT_SQUARE, pattern.get_locus ()));
!   visit (pattern.get_items ());
!   push (Rust::Token::make (RIGHT_SQUARE, UNDEF_LOCATION));
  }
  
  void
  TokenCollector::visit (AltPattern &pattern)
  {
!   visit_items_joined_by_separator (pattern.get_alts (), PIPE);
  }
  
  // rust-stmt.h
--- 3069,3087 ----
  void
  TokenCollector::visit (SlicePattern &pattern)
  {
!   describe_node (std::string ("SlicePattern"), [this, &pattern] () {
!     push (Rust::Token::make (LEFT_SQUARE, pattern.get_locus ()));
!     visit (pattern.get_items ());
!     push (Rust::Token::make (RIGHT_SQUARE, UNDEF_LOCATION));
!   });
  }
  
  void
  TokenCollector::visit (AltPattern &pattern)
  {
!   describe_node (std::string ("AltPattern"), [this, &pattern] () {
!     visit_items_joined_by_separator (pattern.get_alts (), PIPE);
!   });
  }
  
  // rust-stmt.h
*************** TokenCollector::visit (EmptyStmt &)
*** 2751,2787 ****
  void
  TokenCollector::visit (LetStmt &stmt)
  {
!   push (Rust::Token::make (LET, stmt.get_locus ()));
!   auto &pattern = stmt.get_pattern ();
!   visit (pattern);
  
!   if (stmt.has_type ())
!     {
!       push (Rust::Token::make (COLON, UNDEF_LOCATION));
!       visit (stmt.get_type ());
!     }
  
!   if (stmt.has_init_expr ())
!     {
!       push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
!       visit (stmt.get_init_expr ());
!     }
  
!   if (stmt.has_else_expr ())
!     {
!       push (Rust::Token::make (ELSE, UNDEF_LOCATION));
!       visit (stmt.get_else_expr ());
!     }
  
!   push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
  }
  
  void
  TokenCollector::visit (ExprStmt &stmt)
  {
!   visit (stmt.get_expr ());
!   if (stmt.is_semicolon_followed ())
!     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
  }
  
  // rust-type.h
--- 3092,3139 ----
  void
  TokenCollector::visit (LetStmt &stmt)
  {
!   describe_node (std::string ("LetStmt"), [this, &stmt] () {
!     push (Rust::Token::make (LET, stmt.get_locus ()));
!     auto &pattern = stmt.get_pattern ();
!     visit (pattern);
  
!     if (stmt.has_type ())
!       {
! 	push (Rust::Token::make (COLON, UNDEF_LOCATION));
! 	visit (stmt.get_type ());
!       }
  
!     if (stmt.has_type ())
!       {
! 	push (Rust::Token::make (COLON, UNDEF_LOCATION));
! 	visit (stmt.get_type ());
!       }
  
!     if (stmt.has_init_expr ())
!       {
! 	push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
! 	visit (stmt.get_init_expr ());
!       }
  
!     if (stmt.has_else_expr ())
!       {
! 	push (Rust::Token::make (ELSE, UNDEF_LOCATION));
! 	visit (stmt.get_else_expr ());
!       }
! 
!     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
!   });
  }
  
  void
  TokenCollector::visit (ExprStmt &stmt)
  {
!   describe_node (std::string ("ExprStmt"), [this, &stmt] () {
!     visit (stmt.get_expr ());
! 
!     if (stmt.is_semicolon_followed ())
!       push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
!   });
  }
  
  // rust-type.h
*************** TokenCollector::visit (TraitBound &bound
*** 2791,2804 ****
    // Syntax:
    //      ?? ForLifetimes? TypePath
    //   | ( ?? ForLifetimes? TypePath )
  
!   if (bound.has_opening_question_mark ())
!     push (Rust::Token::make (QUESTION_MARK, bound.get_locus ()));
! 
!   if (bound.has_for_lifetimes ())
!     visit (bound.get_for_lifetimes ());
  
!   visit (bound.get_type_path ());
  }
  
  void
--- 3143,3157 ----
    // Syntax:
    //      ?? ForLifetimes? TypePath
    //   | ( ?? ForLifetimes? TypePath )
+   describe_node (std::string ("TraitBound"), [this, &bound] () {
+     if (bound.has_opening_question_mark ())
+       push (Rust::Token::make (QUESTION_MARK, bound.get_locus ()));
  
!     if (bound.has_for_lifetimes ())
!       visit (bound.get_for_lifetimes ());
  
!     visit (bound.get_type_path ());
!   });
  }
  
  void
*************** TokenCollector::visit (ImplTraitType &ty
*** 2808,2816 ****
    //    impl TypeParamBounds
    // TypeParamBounds :
    //    TypeParamBound ( + TypeParamBound )* +?
! 
!   push (Rust::Token::make (IMPL, type.get_locus ()));
!   visit_items_joined_by_separator (type.get_type_param_bounds (), PLUS);
  }
  
  void
--- 3161,3170 ----
    //    impl TypeParamBounds
    // TypeParamBounds :
    //    TypeParamBound ( + TypeParamBound )* +?
!   describe_node (std::string ("ImplTraitType"), [this, &type] () {
!     push (Rust::Token::make (IMPL, type.get_locus ()));
!     visit_items_joined_by_separator (type.get_type_param_bounds (), PLUS);
!   });
  }
  
  void
*************** TokenCollector::visit (TraitObjectType &
*** 2820,2829 ****
    //   dyn? TypeParamBounds
    // TypeParamBounds :
    //   TypeParamBound ( + TypeParamBound )* +?
! 
!   if (type.is_dyn ())
!     push (Rust::Token::make (DYN, type.get_locus ()));
!   visit_items_joined_by_separator (type.get_type_param_bounds (), PLUS);
  }
  
  void
--- 3174,3184 ----
    //   dyn? TypeParamBounds
    // TypeParamBounds :
    //   TypeParamBound ( + TypeParamBound )* +?
!   describe_node (std::string ("TraiObjectType"), [this, &type] () {
!     if (type.is_dyn ())
!       push (Rust::Token::make (DYN, type.get_locus ()));
!     visit_items_joined_by_separator (type.get_type_param_bounds (), PLUS);
!   });
  }
  
  void
*************** TokenCollector::visit (ParenthesisedType
*** 2831,2840 ****
  {
    // Syntax:
    //    ( Type )
! 
!   push (Rust::Token::make (LEFT_PAREN, type.get_locus ()));
!   visit (type.get_type_in_parens ());
!   push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
  }
  
  void
--- 3186,3196 ----
  {
    // Syntax:
    //    ( Type )
!   describe_node (std::string ("ParenthesisedType"), [this, &type] () {
!     push (Rust::Token::make (LEFT_PAREN, type.get_locus ()));
!     visit (type.get_type_in_parens ());
!     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
!   });
  }
  
  void
*************** TokenCollector::visit (ImplTraitTypeOneB
*** 2843,2850 ****
    // Syntax:
    //    impl TraitBound
  
!   push (Rust::Token::make (IMPL, type.get_locus ()));
!   visit (type.get_trait_bound ());
  }
  
  void
--- 3199,3208 ----
    // Syntax:
    //    impl TraitBound
  
!   describe_node (std::string ("ImplTraitTypeOneBound"), [this, &type] () {
!     push (Rust::Token::make (IMPL, type.get_locus ()));
!     visit (type.get_trait_bound ());
!   });
  }
  
  void
*************** TokenCollector::visit (TraitObjectTypeOn
*** 2852,2861 ****
  {
    // Syntax:
    //    dyn? TraitBound
! 
!   if (type.is_dyn ())
!     push (Rust::Token::make (DYN, type.get_locus ()));
!   visit (type.get_trait_bound ());
  }
  
  void
--- 3210,3220 ----
  {
    // Syntax:
    //    dyn? TraitBound
!   describe_node (std::string ("TraitObjectTypeOneBound"), [this, &type] () {
!     if (type.is_dyn ())
!       push (Rust::Token::make (DYN, type.get_locus ()));
!     visit (type.get_trait_bound ());
!   });
  }
  
  void
*************** TokenCollector::visit (TupleType &type)
*** 2865,2873 ****
    //   ( )
    //   | ( ( Type , )+ Type? )
  
!   push (Rust::Token::make (LEFT_PAREN, type.get_locus ()));
!   visit_items_joined_by_separator (type.get_elems (), COMMA);
!   push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
  }
  
  void
--- 3224,3234 ----
    //   ( )
    //   | ( ( Type , )+ Type? )
  
!   describe_node (std::string ("TupleType"), [this, &type] () {
!     push (Rust::Token::make (LEFT_PAREN, type.get_locus ()));
!     visit_items_joined_by_separator (type.get_elems (), COMMA);
!     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
!   });
  }
  
  void
*************** TokenCollector::visit (NeverType &type)
*** 2876,2882 ****
    // Syntax:
    //  !
  
!   push (Rust::Token::make (EXCLAM, type.get_locus ()));
  }
  
  void
--- 3237,3245 ----
    // Syntax:
    //  !
  
!   describe_node (std::string ("NeverType"), [this, &type] () {
!     push (Rust::Token::make (EXCLAM, type.get_locus ()));
!   });
  }
  
  void
*************** TokenCollector::visit (RawPointerType &t
*** 2884,2897 ****
  {
    // Syntax:
    //    * ( mut | const ) TypeNoBounds
  
!   push (Rust::Token::make (ASTERISK, type.get_locus ()));
!   if (type.get_pointer_type () == RawPointerType::MUT)
!     push (Rust::Token::make (MUT, UNDEF_LOCATION));
!   else /* RawPointerType::CONST */
!     push (Rust::Token::make (CONST, UNDEF_LOCATION));
! 
!   visit (type.get_type_pointed_to ());
  }
  
  void
--- 3247,3261 ----
  {
    // Syntax:
    //    * ( mut | const ) TypeNoBounds
+   describe_node (std::string ("RawPointerType"), [this, &type] () {
+     push (Rust::Token::make (ASTERISK, type.get_locus ()));
+     if (type.get_pointer_type () == RawPointerType::MUT)
+       push (Rust::Token::make (MUT, UNDEF_LOCATION));
+     else /* RawPointerType::CONST */
+       push (Rust::Token::make (CONST, UNDEF_LOCATION));
  
!     visit (type.get_type_pointed_to ());
!   });
  }
  
  void
*************** TokenCollector::visit (ReferenceType &ty
*** 2899,2940 ****
  {
    // Syntax:
    //    & Lifetime? mut? TypeNoBounds
  
!   push (Rust::Token::make (AMP, type.get_locus ()));
! 
!   if (type.has_lifetime ())
!     {
!       visit (type.get_lifetime ());
!     }
  
!   if (type.get_has_mut ())
!     push (Rust::Token::make (MUT, UNDEF_LOCATION));
  
!   visit (type.get_type_referenced ());
  }
  
  void
  TokenCollector::visit (ArrayType &type)
  {
    // Syntax:
!   //    [ Type ; Expression ]
! 
!   push (Rust::Token::make (LEFT_SQUARE, type.get_locus ()));
!   visit (type.get_elem_type ());
!   push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
!   visit (type.get_size_expr ());
!   push (Rust::Token::make (RIGHT_SQUARE, UNDEF_LOCATION));
  }
  
  void
  TokenCollector::visit (SliceType &type)
  {
    // Syntax:
!   //    [ Type ]
  
!   push (Rust::Token::make (LEFT_SQUARE, type.get_locus ()));
!   visit (type.get_elem_type ());
!   push (Rust::Token::make (RIGHT_SQUARE, UNDEF_LOCATION));
  }
  
  void
--- 3263,3308 ----
  {
    // Syntax:
    //    & Lifetime? mut? TypeNoBounds
+   describe_node (std::string ("ReferenceType"), [this, &type] () {
+     push (Rust::Token::make (AMP, type.get_locus ()));
  
!     if (type.has_lifetime ())
!       {
! 	visit (type.get_lifetime ());
!       }
  
!     if (type.get_has_mut ())
!       push (Rust::Token::make (MUT, UNDEF_LOCATION));
  
!     visit (type.get_type_referenced ());
!   });
  }
  
  void
  TokenCollector::visit (ArrayType &type)
  {
    // Syntax:
!   //    [type Type ; Expression ]
!   describe_node (std::string ("ArrayType"), [this, &type] () {
!     push (Rust::Token::make (LEFT_SQUARE, type.get_locus ()));
!     visit (type.get_elem_type ());
!     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
!     visit (type.get_size_expr ());
!     push (Rust::Token::make (RIGHT_SQUARE, UNDEF_LOCATION));
!   });
  }
  
  void
  TokenCollector::visit (SliceType &type)
  {
    // Syntax:
!   //    [type Type ]
  
!   describe_node (std::string ("SliceType"), [this, &type] () {
!     push (Rust::Token::make (LEFT_SQUARE, type.get_locus ()));
!     visit (type.get_elem_type ());
!     push (Rust::Token::make (RIGHT_SQUARE, UNDEF_LOCATION));
!   });
  }
  
  void
*************** TokenCollector::visit (InferredType &typ
*** 2942,2949 ****
  {
    // Syntax:
    //    _
! 
!   push (Rust::Token::make (UNDERSCORE, type.get_locus ()));
  }
  
  void
--- 3310,3318 ----
  {
    // Syntax:
    //    _
!   describe_node (std::string ("InferredType"), [this, &type] () {
!     push (Rust::Token::make (UNDERSCORE, type.get_locus ()));
!   });
  }
  
  void
*************** TokenCollector::visit (BareFunctionType
*** 2951,2997 ****
  {
    // Syntax:
    //    ForLifetimes? FunctionTypeQualifiers fn
!   //      ( FunctionParametersMaybeNamedVariadic? ) BareFunctionReturnType?
    //
    //    BareFunctionReturnType:
    //      -> TypeNoBounds
    //
    //    FunctionParametersMaybeNamedVariadic :
!   //      MaybeNamedFunctionParameters | MaybeNamedFunctionParametersVariadic
    //
    //    MaybeNamedFunctionParameters :
    //      MaybeNamedParam ( , MaybeNamedParam )* ,?
    //
    //    MaybeNamedFunctionParametersVariadic :
    //      ( MaybeNamedParam , )* MaybeNamedParam , OuterAttribute* ...
  
!   if (type.has_for_lifetimes ())
!     visit (type.get_for_lifetimes ());
! 
!   visit (type.get_function_qualifiers ());
  
!   push (Rust::Token::make (FN_KW, type.get_locus ()));
!   push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
  
!   visit_items_joined_by_separator (type.get_function_params (), COMMA);
  
!   if (type.is_variadic ())
!     {
!       push (Rust::Token::make (COMMA, UNDEF_LOCATION));
!       for (auto &item : type.get_variadic_attr ())
! 	{
! 	  visit (item);
! 	}
!       push (Rust::Token::make (ELLIPSIS, UNDEF_LOCATION));
!     }
  
!   push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
  
!   if (type.has_return_type ())
!     {
!       push (Rust::Token::make (RETURN_TYPE, UNDEF_LOCATION));
!       visit (type.get_return_type ());
!     }
  }
  
  void
--- 3320,3369 ----
  {
    // Syntax:
    //    ForLifetimes? FunctionTypeQualifiers fn
!   //      ( FunctionParametersMaybeNamedVariadic? )
!   //      BareFunctionReturnType?
    //
    //    BareFunctionReturnType:
    //      -> TypeNoBounds
    //
    //    FunctionParametersMaybeNamedVariadic :
!   //      MaybeNamedFunctionParameters |
!   //      MaybeNamedFunctionParametersVariadic
    //
    //    MaybeNamedFunctionParameters :
    //      MaybeNamedParam ( , MaybeNamedParam )* ,?
    //
    //    MaybeNamedFunctionParametersVariadic :
    //      ( MaybeNamedParam , )* MaybeNamedParam , OuterAttribute* ...
+   describe_node (std::string ("BareFunctionType"), [this, &type] () {
+     if (type.has_for_lifetimes ())
+       visit (type.get_for_lifetimes ());
  
!     visit (type.get_function_qualifiers ());
  
!     push (Rust::Token::make (FN_KW, type.get_locus ()));
!     push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
  
!     visit_items_joined_by_separator (type.get_function_params (), COMMA);
  
!     if (type.is_variadic ())
!       {
! 	push (Rust::Token::make (COMMA, UNDEF_LOCATION));
! 	for (auto &item : type.get_variadic_attr ())
! 	  {
! 	    visit (item);
! 	  }
! 	push (Rust::Token::make (ELLIPSIS, UNDEF_LOCATION));
!       }
  
!     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
  
!     if (type.has_return_type ())
!       {
! 	push (Rust::Token::make (RETURN_TYPE, UNDEF_LOCATION));
! 	visit (type.get_return_type ());
!       }
!   });
  }
  
  void
*************** TokenCollector::visit (AST::FormatArgs &
*** 3059,3066 ****
  	  bool has_format_spec = false;
  	  std::string format_part;
  
! 	  // For now, skipping the complex format specifications that use FFIOpt
! 	  // since FFIOpt::get_opt() has a bug.
  
  	  // Alignment
  	  if (format_spec.align != Fmt::ffi::Alignment::AlignUnknown)
--- 3431,3438 ----
  	  bool has_format_spec = false;
  	  std::string format_part;
  
! 	  // For now, skipping the complex format specifications that
! 	  // use FFIOpt since FFIOpt::get_opt() has a bug.
  
  	  // Alignment
  	  if (format_spec.align != Fmt::ffi::Alignment::AlignUnknown)
*************** TokenCollector::visit (AST::FormatArgs &
*** 3197,3205 ****
  						  std::move (ident)));
  	      push (Rust::Token::make (EQUAL, fmt.get_locus ()));
  	    }
! 	  // Note: Captured arguments are handled implicitly in the template
! 	  // reconstruction They don't need explicit "name =" syntax in the
! 	  // reconstructed macro call
  
  	  auto &expr = args[i].get_expr ();
  	  expr.accept_vis (*this);
--- 3569,3577 ----
  						  std::move (ident)));
  	      push (Rust::Token::make (EQUAL, fmt.get_locus ()));
  	    }
! 	  // Note: Captured arguments are handled implicitly in the
! 	  // template reconstruction They don't need explicit "name ="
! 	  // syntax in the reconstructed macro call
  
  	  auto &expr = args[i].get_expr ();
  	  expr.accept_vis (*this);
diff -Nrcpad gcc-16-20251214/gcc/rust/ast/rust-ast-collector.h gcc-16-20251221/gcc/rust/ast/rust-ast-collector.h
*** gcc-16-20251214/gcc/rust/ast/rust-ast-collector.h	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/rust/ast/rust-ast-collector.h	Sun Dec 21 22:32:07 2025
***************
*** 23,28 ****
--- 23,29 ----
  #include "rust-ast-visitor.h"
  #include "rust-ast.h"
  #include "rust-ast-full.h"
+ #include "rust-system.h"
  
  namespace Rust {
  namespace AST {
*************** public:
*** 33,48 ****
    enum class Kind
    {
      Comment,
      Newline,
      Indentation,
      Token,
    };
  
    CollectItem (TokenPtr token) : token (token), kind (Kind::Token) {}
-   CollectItem (std::string comment) : comment (comment), kind (Kind::Comment) {}
    CollectItem (Kind kind) : kind (kind) { rust_assert (kind != Kind::Token); }
    CollectItem (size_t level) : indent_level (level), kind (Kind::Indentation) {}
  
    Kind get_kind () { return kind; }
  
    TokenPtr get_token ()
--- 34,73 ----
    enum class Kind
    {
      Comment,
+     InternalComment,
+     BeginNodeDescription,
+     EndNodeDescription,
      Newline,
      Indentation,
      Token,
    };
  
    CollectItem (TokenPtr token) : token (token), kind (Kind::Token) {}
    CollectItem (Kind kind) : kind (kind) { rust_assert (kind != Kind::Token); }
    CollectItem (size_t level) : indent_level (level), kind (Kind::Indentation) {}
  
+   static CollectItem make_internal_comment (const std::string &internal_comment)
+   {
+     return CollectItem (internal_comment, Kind::InternalComment);
+   }
+ 
+   static CollectItem make_comment (const std::string &comment)
+   {
+     return CollectItem (comment, Kind::Comment);
+   }
+ 
+   static CollectItem
+   make_begin_node_description (const std::string &node_description)
+   {
+     return CollectItem (node_description, Kind::BeginNodeDescription);
+   }
+ 
+   static CollectItem
+   make_end_node_description (const std::string &node_description)
+   {
+     return CollectItem (node_description, Kind::EndNodeDescription);
+   }
+ 
    Kind get_kind () { return kind; }
  
    TokenPtr get_token ()
*************** public:
*** 63,73 ****
--- 88,117 ----
      return indent_level;
    }
  
+   std::string get_internal_comment ()
+   {
+     rust_assert (kind == Kind::InternalComment);
+     return comment;
+   }
+ 
+   std::string get_node_description ()
+   {
+     rust_assert (kind == Kind::BeginNodeDescription
+ 		 || kind == Kind::EndNodeDescription);
+     return comment;
+   }
+ 
+   bool is_debug () { return debug; }
+ 
  private:
+   CollectItem (std::string comment, Kind kind) : comment (comment), kind (kind)
+   {}
+ 
    TokenPtr token;
    std::string comment;
    size_t indent_level;
    Kind kind;
+   bool debug = false;
  };
  
  class TokenCollector : public ASTVisitor
*************** private:
*** 164,169 ****
--- 208,216 ----
        }
    }
  
+   void describe_node (const std::string &node_name,
+ 		      std::function<void ()> visitor);
+ 
    void trailing_comma ();
    void newline ();
    void indentation ();
diff -Nrcpad gcc-16-20251214/gcc/rust/ast/rust-ast-dump.cc gcc-16-20251221/gcc/rust/ast/rust-ast-dump.cc
*** gcc-16-20251214/gcc/rust/ast/rust-ast-dump.cc	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/rust/ast/rust-ast-dump.cc	Sun Dec 21 22:32:07 2025
***************
*** 22,28 ****
  namespace Rust {
  namespace AST {
  
! Dump::Dump (std::ostream &stream) : stream (stream), indentation (Indent ()) {}
  
  bool
  Dump::require_spacing (TokenPtr previous, TokenPtr current)
--- 22,41 ----
  namespace Rust {
  namespace AST {
  
! Dump::Dump (std::ostream &stream)
!   : stream (stream), indentation (Indent ()),
!     configuration (Configuration{
!       Configuration::InternalComment::Hide,
!       Configuration::NodeDescription::Hide,
!       Configuration::Comment::Dump,
!     })
! {}
! 
! Dump::Dump (std::ostream &stream, Configuration configuration,
! 	    std::set<std::string> excluded_node)
!   : stream (stream), indentation (Indent ()), configuration (configuration),
!     excluded_node (excluded_node)
! {}
  
  bool
  Dump::require_spacing (TokenPtr previous, TokenPtr current)
diff -Nrcpad gcc-16-20251214/gcc/rust/ast/rust-ast-dump.h gcc-16-20251221/gcc/rust/ast/rust-ast-dump.h
*** gcc-16-20251214/gcc/rust/ast/rust-ast-dump.h	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/rust/ast/rust-ast-dump.h	Sun Dec 21 22:32:07 2025
***************
*** 22,27 ****
--- 22,28 ----
  #include "rust-ast.h"
  #include "rust-ast-full.h"
  #include "rust-dump.h"
+ #include "rust-system.h"
  
  #include "rust-ast-collector.h"
  
*************** namespace AST {
*** 31,37 ****
--- 32,59 ----
  class Dump
  {
  public:
+   struct Configuration
+   {
+     enum class InternalComment
+     {
+       Dump,
+       Hide,
+     } dump_internal_comments;
+     enum class NodeDescription
+     {
+       Dump,
+       Hide,
+     } dump_node_description;
+     enum class Comment
+     {
+       Dump,
+       Hide,
+     } dump_comments;
+   };
+ 
    Dump (std::ostream &stream);
+   Dump (std::ostream &stream, Configuration configuration,
+ 	std::set<std::string> excluded_node);
  
    /**
     * Run the visitor on an entire crate and its items
*************** public:
*** 59,65 ****
  	    }
  	    break;
  	  case AST::CollectItem::Kind::Comment:
! 	    stream << " /* " << item.get_comment () << " */ ";
  	    break;
  	  case AST::CollectItem::Kind::Indentation:
  	    for (size_t i = 0; i < item.get_indent_level (); i++)
--- 81,88 ----
  	    }
  	    break;
  	  case AST::CollectItem::Kind::Comment:
! 	    if (configuration.dump_comments == Configuration::Comment::Dump)
! 	      stream << " /* " << item.get_comment () << " */ ";
  	    break;
  	  case AST::CollectItem::Kind::Indentation:
  	    for (size_t i = 0; i < item.get_indent_level (); i++)
*************** public:
*** 71,76 ****
--- 94,125 ----
  	    stream << "\n";
  	    previous = nullptr;
  	    break;
+ 	  case AST::CollectItem::Kind::BeginNodeDescription:
+ 	    if (configuration.dump_node_description
+ 		== Configuration::NodeDescription::Dump)
+ 	      {
+ 		std::string comment = item.get_node_description ();
+ 		if (excluded_node.find (comment) == excluded_node.end ())
+ 		  stream << " /* " << comment << " */ ";
+ 	      }
+ 	    break;
+ 	  case AST::CollectItem::Kind::EndNodeDescription:
+ 	    if (configuration.dump_node_description
+ 		== Configuration::NodeDescription::Dump)
+ 	      {
+ 		std::string comment = item.get_node_description ();
+ 		if (excluded_node.find (comment) == excluded_node.end ())
+ 		  stream << " /* !" << comment << " */ ";
+ 	      }
+ 	    break;
+ 	  case AST::CollectItem::Kind::InternalComment:
+ 	    if (configuration.dump_internal_comments
+ 		== Configuration::InternalComment::Dump)
+ 	      {
+ 		std::string comment = item.get_internal_comment ();
+ 		stream << " /* " << comment << " */ ";
+ 	      }
+ 	    break;
  	  default:
  	    rust_unreachable ();
  	  }
*************** public:
*** 83,88 ****
--- 132,139 ----
  private:
    std::ostream &stream;
    Indent indentation;
+   Configuration configuration;
+   std::set<std::string> excluded_node;
  
    static bool require_spacing (TokenPtr previous, TokenPtr current);
  };
diff -Nrcpad gcc-16-20251214/gcc/rust/ast/rust-ast.cc gcc-16-20251221/gcc/rust/ast/rust-ast.cc
*** gcc-16-20251214/gcc/rust/ast/rust-ast.cc	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/rust/ast/rust-ast.cc	Sun Dec 21 22:32:07 2025
*************** Module::load_items ()
*** 3490,3496 ****
  
    // we need to parse any possible inner attributes for this module
    inner_attrs = parser.parse_inner_attributes ();
!   auto parsed_items = parser.parse_items ();
    for (const auto &error : parser.get_errors ())
      error.emit ();
  
--- 3490,3498 ----
  
    // we need to parse any possible inner attributes for this module
    inner_attrs = parser.parse_inner_attributes ();
!   auto parsed_items = parser.parse_items ().value_or (
!     std::vector<std::unique_ptr<AST::Item>>{});
! 
    for (const auto &error : parser.get_errors ())
      error.emit ();
  
*************** AttributeParser::is_end_meta_item_tok (T
*** 3705,3712 ****
  std::unique_ptr<MetaItem>
  AttributeParser::parse_path_meta_item ()
  {
!   SimplePath path = parser->parse_simple_path ();
!   if (path.is_empty ())
      {
        rust_error_at (lexer->peek_token ()->get_locus (),
  		     "failed to parse simple path in attribute");
--- 3707,3714 ----
  std::unique_ptr<MetaItem>
  AttributeParser::parse_path_meta_item ()
  {
!   auto path = parser->parse_simple_path ();
!   if (!path)
      {
        rust_error_at (lexer->peek_token ()->get_locus (),
  		     "failed to parse simple path in attribute");
*************** AttributeParser::parse_path_meta_item ()
*** 3721,3727 ****
  	  = parse_meta_item_seq ();
  
  	return std::unique_ptr<MetaItemSeq> (
! 	  new MetaItemSeq (std::move (path), std::move (meta_items)));
        }
      case EQUAL:
        {
--- 3723,3729 ----
  	  = parse_meta_item_seq ();
  
  	return std::unique_ptr<MetaItemSeq> (
! 	  new MetaItemSeq (std::move (path.value ()), std::move (meta_items)));
        }
      case EQUAL:
        {
*************** AttributeParser::parse_path_meta_item ()
*** 3735,3746 ****
  	  return nullptr;
  
  	return std::unique_ptr<MetaItemPathExpr> (
! 	  new MetaItemPathExpr (std::move (path), std::move (expr)));
        }
      case COMMA:
        // just simple path
        return std::unique_ptr<MetaItemPath> (
! 	new MetaItemPath (std::move (path)));
      default:
        rust_error_at (lexer->peek_token ()->get_locus (),
  		     "unrecognised token '%s' in meta item",
--- 3737,3748 ----
  	  return nullptr;
  
  	return std::unique_ptr<MetaItemPathExpr> (
! 	  new MetaItemPathExpr (std::move (path.value ()), std::move (expr)));
        }
      case COMMA:
        // just simple path
        return std::unique_ptr<MetaItemPath> (
! 	new MetaItemPath (std::move (path.value ())));
      default:
        rust_error_at (lexer->peek_token ()->get_locus (),
  		     "unrecognised token '%s' in meta item",
diff -Nrcpad gcc-16-20251214/gcc/rust/ast/rust-ast.h gcc-16-20251221/gcc/rust/ast/rust-ast.h
*** gcc-16-20251214/gcc/rust/ast/rust-ast.h	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/rust/ast/rust-ast.h	Sun Dec 21 22:32:07 2025
*************** private:
*** 477,514 ****
    SimplePath in_path;
    location_t locus;
  
-   // should this store location info?
- 
- public:
-   // Creates a Visibility - TODO make constructor protected or private?
    Visibility (VisType vis_type, SimplePath in_path, location_t locus)
      : vis_type (vis_type), in_path (std::move (in_path)), locus (locus)
    {}
  
    VisType get_vis_type () const { return vis_type; }
  
-   // Returns whether visibility is in an error state.
-   bool is_error () const
-   {
-     return vis_type == PUB_IN_PATH && in_path.is_empty ();
-   }
- 
    // Returns whether a visibility has a path
!   bool has_path () const { return !is_error () && vis_type >= PUB_CRATE; }
  
    // Returns whether visibility is public or not.
!   bool is_public () const { return vis_type != PRIV && !is_error (); }
  
    location_t get_locus () const { return locus; }
  
-   // empty?
-   // Creates an error visibility.
-   static Visibility create_error ()
-   {
-     return Visibility (PUB_IN_PATH, SimplePath::create_empty (),
- 		       UNDEF_LOCATION);
-   }
- 
    // Unique pointer custom clone function
    /*std::unique_ptr<Visibility> clone_visibility() const {
        return std::unique_ptr<Visibility>(clone_visibility_impl());
--- 477,497 ----
    SimplePath in_path;
    location_t locus;
  
    Visibility (VisType vis_type, SimplePath in_path, location_t locus)
      : vis_type (vis_type), in_path (std::move (in_path)), locus (locus)
    {}
  
+ public:
    VisType get_vis_type () const { return vis_type; }
  
    // Returns whether a visibility has a path
!   bool has_path () const { return vis_type >= PUB_CRATE; }
  
    // Returns whether visibility is public or not.
!   bool is_public () const { return vis_type != PRIV; }
  
    location_t get_locus () const { return locus; }
  
    // Unique pointer custom clone function
    /*std::unique_ptr<Visibility> clone_visibility() const {
        return std::unique_ptr<Visibility>(clone_visibility_impl());
diff -Nrcpad gcc-16-20251214/gcc/rust/ast/rust-expr.h gcc-16-20251221/gcc/rust/ast/rust-expr.h
*** gcc-16-20251214/gcc/rust/ast/rust-expr.h	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/rust/ast/rust-expr.h	Sun Dec 21 22:32:07 2025
*************** public:
*** 294,308 ****
      return MetaItem::ItemKind::PathExpr;
    }
  
!   // There are two Locations in MetaItemPathExpr (path and expr),
!   //  we have no idea use which of them, just simply return UNKNOWN_LOCATION
!   //  now.
!   // Maybe we will figure out when we really need the location in the future.
!   location_t get_locus () const override
!   {
!     rust_unreachable ();
!     return UNKNOWN_LOCATION;
!   }
  
    void accept_vis (ASTVisitor &vis) override;
  
--- 294,300 ----
      return MetaItem::ItemKind::PathExpr;
    }
  
!   location_t get_locus () const override { return path.get_locus (); }
  
    void accept_vis (ASTVisitor &vis) override;
  
diff -Nrcpad gcc-16-20251214/gcc/rust/ast/rust-item.h gcc-16-20251221/gcc/rust/ast/rust-item.h
*** gcc-16-20251214/gcc/rust/ast/rust-item.h	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/rust/ast/rust-item.h	Sun Dec 21 22:32:07 2025
*************** public:
*** 814,820 ****
    // Loaded module constructor, with items
    Module (Identifier name, location_t locus,
  	  std::vector<std::unique_ptr<Item>> items,
! 	  Visibility visibility = Visibility::create_error (),
  	  Unsafety safety = Unsafety::Normal,
  	  std::vector<Attribute> inner_attrs = std::vector<Attribute> (),
  	  std::vector<Attribute> outer_attrs = std::vector<Attribute> ())
--- 814,820 ----
    // Loaded module constructor, with items
    Module (Identifier name, location_t locus,
  	  std::vector<std::unique_ptr<Item>> items,
! 	  Visibility visibility = Visibility::create_private (),
  	  Unsafety safety = Unsafety::Normal,
  	  std::vector<Attribute> inner_attrs = std::vector<Attribute> (),
  	  std::vector<Attribute> outer_attrs = std::vector<Attribute> ())
*************** public:
*** 1743,1749 ****
    bool has_outer_attributes () const { return !outer_attrs.empty (); }
  
    // Returns whether struct field has a non-private (non-default) visibility.
!   bool has_visibility () const { return !visibility.is_error (); }
  
    StructField (Identifier field_name, std::unique_ptr<Type> field_type,
  	       Visibility vis, location_t locus,
--- 1743,1749 ----
    bool has_outer_attributes () const { return !outer_attrs.empty (); }
  
    // Returns whether struct field has a non-private (non-default) visibility.
!   bool has_visibility () const { return true; }
  
    StructField (Identifier field_name, std::unique_ptr<Type> field_type,
  	       Visibility vis, location_t locus,
*************** public:
*** 1797,1804 ****
    // Creates an error state struct field.
    static StructField create_error ()
    {
!     return StructField (std::string (""), nullptr, Visibility::create_error (),
! 			UNDEF_LOCATION);
    }
  
    std::string as_string () const;
--- 1797,1804 ----
    // Creates an error state struct field.
    static StructField create_error ()
    {
!     return StructField (std::string (""), nullptr,
! 			Visibility::create_private (), UNDEF_LOCATION);
    }
  
    std::string as_string () const;
*************** public:
*** 1902,1908 ****
  
    /* Returns whether tuple field has a non-default visibility (i.e. a public
     * one) */
!   bool has_visibility () const { return !visibility.is_error (); }
  
    // Complete constructor
    TupleField (std::unique_ptr<Type> field_type, Visibility vis,
--- 1902,1908 ----
  
    /* Returns whether tuple field has a non-default visibility (i.e. a public
     * one) */
!   bool has_visibility () const { return true; }
  
    // Complete constructor
    TupleField (std::unique_ptr<Type> field_type, Visibility vis,
*************** public:
*** 1952,1958 ****
    // Creates an error state tuple field.
    static TupleField create_error ()
    {
!     return TupleField (nullptr, Visibility::create_error (), UNDEF_LOCATION);
    }
  
    std::string as_string () const;
--- 1952,1958 ----
    // Creates an error state tuple field.
    static TupleField create_error ()
    {
!     return TupleField (nullptr, Visibility::create_private (), UNDEF_LOCATION);
    }
  
    std::string as_string () const;
*************** public:
*** 3389,3395 ****
    bool has_outer_attrs () const { return !outer_attrs.empty (); }
  
    // Returns whether item has non-default visibility.
!   bool has_visibility () const { return !visibility.is_error (); }
  
    location_t get_locus () const { return locus; }
  
--- 3389,3395 ----
    bool has_outer_attrs () const { return !outer_attrs.empty (); }
  
    // Returns whether item has non-default visibility.
!   bool has_visibility () const { return true; }
  
    location_t get_locus () const { return locus; }
  
*************** public:
*** 3481,3487 ****
    bool has_outer_attrs () const { return !outer_attrs.empty (); }
  
    // Returns whether item has non-default visibility.
!   bool has_visibility () const { return !visibility.is_error (); }
  
    location_t get_locus () const { return locus; }
  
--- 3481,3487 ----
    bool has_outer_attrs () const { return !outer_attrs.empty (); }
  
    // Returns whether item has non-default visibility.
!   bool has_visibility () const { return true; }
  
    location_t get_locus () const { return locus; }
  
diff -Nrcpad gcc-16-20251214/gcc/rust/ast/rust-macro.h gcc-16-20251221/gcc/rust/ast/rust-macro.h
*** gcc-16-20251214/gcc/rust/ast/rust-macro.h	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/rust/ast/rust-macro.h	Sun Dec 21 22:32:07 2025
*************** public:
*** 529,535 ****
      return std::make_unique<MacroRulesDefinition> (
        MacroRulesDefinition (rule_name, delim_type, rules, outer_attrs, locus,
  			    AST::MacroRulesDefinition::MacroKind::MBE,
! 			    AST::Visibility::create_error ()));
    }
  
    static std::unique_ptr<MacroRulesDefinition>
--- 529,535 ----
      return std::make_unique<MacroRulesDefinition> (
        MacroRulesDefinition (rule_name, delim_type, rules, outer_attrs, locus,
  			    AST::MacroRulesDefinition::MacroKind::MBE,
! 			    AST::Visibility::create_private ()));
    }
  
    static std::unique_ptr<MacroRulesDefinition>
diff -Nrcpad gcc-16-20251214/gcc/rust/expand/rust-macro-builtins-include.cc gcc-16-20251221/gcc/rust/expand/rust-macro-builtins-include.cc
*** gcc-16-20251214/gcc/rust/expand/rust-macro-builtins-include.cc	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/rust/expand/rust-macro-builtins-include.cc	Sun Dec 21 22:32:07 2025
*************** MacroBuiltin::include_handler (location_
*** 248,254 ****
    std::vector<std::unique_ptr<AST::Item>> parsed_items{};
  
    if (is_semicoloned)
!     parsed_items = parser.parse_items ();
    else
      parsed_expr = parser.parse_expr ();
  
--- 248,255 ----
    std::vector<std::unique_ptr<AST::Item>> parsed_items{};
  
    if (is_semicoloned)
!     parsed_items = parser.parse_items ().value_or (
!       std::vector<std::unique_ptr<AST::Item>>{});
    else
      parsed_expr = parser.parse_expr ();
  
diff -Nrcpad gcc-16-20251214/gcc/rust/expand/rust-macro-builtins-offset-of.cc gcc-16-20251221/gcc/rust/expand/rust-macro-builtins-offset-of.cc
*** gcc-16-20251214/gcc/rust/expand/rust-macro-builtins-offset-of.cc	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/rust/expand/rust-macro-builtins-offset-of.cc	Sun Dec 21 22:32:07 2025
*************** MacroBuiltin::offset_of_handler (locatio
*** 56,62 ****
    parser.skip_token (COMMA);
  
    auto field_tok = parser.parse_identifier_or_keyword_token ();
!   auto invalid_field = !field_tok || !field_tok->should_have_str ();
  
    if (invalid_field)
      rust_error_at (invoc_locus, "could not parse field argument for %qs",
--- 56,62 ----
    parser.skip_token (COMMA);
  
    auto field_tok = parser.parse_identifier_or_keyword_token ();
!   auto invalid_field = !field_tok || !field_tok.value ()->should_have_str ();
  
    if (invalid_field)
      rust_error_at (invoc_locus, "could not parse field argument for %qs",
*************** MacroBuiltin::offset_of_handler (locatio
*** 65,71 ****
    if (!type || invalid_field)
      return tl::nullopt;
  
!   auto field = Identifier (field_tok->get_str ());
  
    // FIXME: Do we need to do anything to handle the optional comma at the end?
    parser.maybe_skip_token (COMMA);
--- 65,71 ----
    if (!type || invalid_field)
      return tl::nullopt;
  
!   auto field = Identifier (field_tok.value ()->get_str ());
  
    // FIXME: Do we need to do anything to handle the optional comma at the end?
    parser.maybe_skip_token (COMMA);
diff -Nrcpad gcc-16-20251214/gcc/rust/expand/rust-macro-expand.cc gcc-16-20251221/gcc/rust/expand/rust-macro-expand.cc
*** gcc-16-20251214/gcc/rust/expand/rust-macro-expand.cc	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/rust/expand/rust-macro-expand.cc	Sun Dec 21 22:32:07 2025
*************** transcribe_many_items (Parser<MacroInvoc
*** 858,864 ****
  {
    return parse_many (parser, delimiter, [&parser] () {
      auto item = parser.parse_item (true);
!     return AST::SingleASTNode (std::move (item));
    });
  }
  
--- 858,866 ----
  {
    return parse_many (parser, delimiter, [&parser] () {
      auto item = parser.parse_item (true);
!     if (!item)
!       return AST::SingleASTNode (std::unique_ptr<AST::Item> (nullptr));
!     return AST::SingleASTNode (std::move (item.value ()));
    });
  }
  
*************** MacroExpander::parse_proc_macro_output (
*** 1191,1199 ****
        while (lex.peek_token ()->get_id () != END_OF_FILE)
  	{
  	  auto result = parser.parse_item (false);
! 	  if (result == nullptr)
  	    break;
! 	  nodes.emplace_back (std::move (result));
  	}
        break;
      case ContextType::STMT:
--- 1193,1201 ----
        while (lex.peek_token ()->get_id () != END_OF_FILE)
  	{
  	  auto result = parser.parse_item (false);
! 	  if (!result)
  	    break;
! 	  nodes.emplace_back (std::move (result.value ()));
  	}
        break;
      case ContextType::STMT:
diff -Nrcpad gcc-16-20251214/gcc/rust/hir/rust-ast-lower.cc gcc-16-20251221/gcc/rust/hir/rust-ast-lower.cc
*** gcc-16-20251214/gcc/rust/hir/rust-ast-lower.cc	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/rust/hir/rust-ast-lower.cc	Sun Dec 21 22:32:07 2025
*************** translate_visibility (const AST::Visibil
*** 38,45 ****
    // the AST vis is an error?
    // FIXME: We need to add a `create_private()` static function to the
    // AST::Visibility class and use it when the vis is empty in the parser...
-   if (vis.is_error ())
-     return Visibility::create_error ();
  
    switch (vis.get_vis_type ())
      {
--- 38,43 ----
*************** translate_visibility (const AST::Visibil
*** 57,63 ****
        break;
      }
  
!   return Visibility::create_error ();
  }
  
  ASTLowering::ASTLowering (AST::Crate &astCrate) : astCrate (astCrate) {}
--- 55,61 ----
        break;
      }
  
!   rust_unreachable ();
  }
  
  ASTLowering::ASTLowering (AST::Crate &astCrate) : astCrate (astCrate) {}
diff -Nrcpad gcc-16-20251214/gcc/rust/parse/rust-parse-error.h gcc-16-20251221/gcc/rust/parse/rust-parse-error.h
*** gcc-16-20251214/gcc/rust/parse/rust-parse-error.h	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/rust/parse/rust-parse-error.h	Sun Dec 21 22:32:07 2025
***************
*** 0 ****
--- 1,326 ----
+ // Copyright (C) 2025 Free Software Foundation, Inc.
+ 
+ // This file is part of GCC.
+ 
+ // GCC is free software; you can redistribute it and/or modify it under
+ // the terms of the GNU General Public License as published by the Free
+ // Software Foundation; either version 3, or (at your option) any later
+ // version.
+ 
+ // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+ // WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ // for more details.
+ 
+ // You should have received a copy of the GNU General Public License
+ // along with GCC; see the file COPYING3.  If not see
+ // <http://www.gnu.org/licenses/>.
+ 
+ #ifndef RUST_PARSE_ERROR_H
+ #define RUST_PARSE_ERROR_H
+ 
+ #include "expected.h"
+ #include "rust-ast.h"
+ #include "rust-parse-utils.h"
+ 
+ namespace Rust {
+ namespace Parse {
+ namespace Error {
+ 
+ struct Attribute
+ {
+   static tl::expected<AST::Attribute, Attribute> make_malformed ()
+   {
+     return tl::unexpected<Attribute> (Attribute (Kind::MALFORMED));
+   }
+ 
+   static tl::expected<AST::Attribute, Attribute> make_malformed_body ()
+   {
+     return tl::unexpected<Attribute> (Attribute (Kind::MALFORMED_BODY));
+   }
+ 
+   static tl::expected<AST::Attribute, Attribute> make_unexpected_inner ()
+   {
+     return tl::unexpected<Attribute> (Attribute (Kind::UNEXPECTED_INNER));
+   }
+ 
+   enum class Kind
+   {
+     MALFORMED,
+     MALFORMED_BODY,
+     UNEXPECTED_INNER,
+   } kind;
+ 
+ private:
+   Attribute (Kind kind) : kind (kind) {}
+ };
+ 
+ struct SimplePath
+ {
+   static tl::expected<AST::SimplePath, SimplePath> make_malformed ()
+   {
+     return tl::unexpected<SimplePath> (SimplePath (Kind::MALFORMED));
+   }
+ 
+   enum class Kind
+   {
+     MALFORMED,
+   } kind;
+ 
+ private:
+   SimplePath (Kind kind) : kind (kind) {}
+ };
+ 
+ struct AttributeBody
+ {
+   static tl::expected<Parse::AttributeBody, AttributeBody> make_invalid_path ()
+   {
+     return tl::unexpected<AttributeBody> (AttributeBody (Kind::INVALID_PATH));
+   }
+ 
+   static tl::expected<Parse::AttributeBody, AttributeBody>
+   make_invalid_attrinput ()
+   {
+     return tl::unexpected<AttributeBody> (
+       AttributeBody (Kind::INVALID_ATTRINPUT));
+   }
+ 
+   enum class Kind
+   {
+     INVALID_PATH,
+     INVALID_ATTRINPUT,
+   } kind;
+ 
+ private:
+   AttributeBody (Kind kind) : kind (kind) {}
+ };
+ 
+ struct SimplePathSegment
+ {
+   static tl::expected<AST::SimplePathSegment, SimplePathSegment>
+   make_invalid_token_or_path_end ()
+   {
+     return tl::unexpected<SimplePathSegment> (
+       SimplePathSegment (Kind::INVALID_SIMPLE_PATH_TOKEN));
+   }
+ 
+   enum class Kind
+   {
+     /* Invalid token found whilst parsing a simple path segment, could be an
+        error or the end of the path */
+     INVALID_SIMPLE_PATH_TOKEN,
+   } kind;
+ 
+ private:
+   SimplePathSegment (Kind kind) : kind (kind) {}
+ };
+ 
+ struct PathIdentSegment
+ {
+   static tl::expected<AST::PathIdentSegment, PathIdentSegment>
+   make_invalid_token ()
+   {
+     return tl::unexpected<PathIdentSegment> (
+       PathIdentSegment (Kind::INVALID_PATH_IDENT_TOKEN));
+   }
+ 
+   enum class Kind
+   {
+     INVALID_PATH_IDENT_TOKEN,
+   } kind;
+ 
+ private:
+   PathIdentSegment (Kind kind) : kind (kind) {}
+ };
+ 
+ struct AttrInput
+ {
+   static tl::expected<std::unique_ptr<AST::AttrInput>, AttrInput>
+   make_malformed ()
+   {
+     return tl::unexpected<AttrInput> (AttrInput (Kind::MALFORMED));
+   }
+ 
+   static tl::expected<std::unique_ptr<AST::AttrInput>, AttrInput>
+   make_bad_macro_invocation ()
+   {
+     return tl::unexpected<AttrInput> (AttrInput (Kind::BAD_MACRO_INVOCATION));
+   }
+ 
+   static tl::expected<std::unique_ptr<AST::AttrInput>, AttrInput>
+   make_missing_attrinput ()
+   {
+     return tl::unexpected<AttrInput> (AttrInput (Kind::MISSING));
+   }
+ 
+   static tl::expected<std::unique_ptr<AST::AttrInput>, AttrInput>
+   make_bad_token_tree ()
+   {
+     return tl::unexpected<AttrInput> (AttrInput (Kind::BAD_TOKEN_TREE));
+   }
+ 
+   enum class Kind
+   {
+     MALFORMED,
+     BAD_MACRO_INVOCATION,
+     BAD_TOKEN_TREE,
+     // Not an hard error in some context
+     MISSING,
+   } kind;
+ 
+ private:
+   AttrInput (Kind kind) : kind (kind) {}
+ };
+ 
+ struct DelimTokenTree
+ {
+   static tl::expected<AST::DelimTokenTree, DelimTokenTree>
+   make_expected_delimiter ()
+   {
+     return tl::unexpected<DelimTokenTree> (
+       DelimTokenTree (Kind::EXPECTED_DELIMITER));
+   }
+ 
+   static tl::expected<AST::DelimTokenTree, DelimTokenTree>
+   make_invalid_token_tree ()
+   {
+     return tl::unexpected<DelimTokenTree> (
+       DelimTokenTree (Kind::INVALID_TOKEN_TREE));
+   }
+ 
+   static tl::expected<AST::DelimTokenTree, DelimTokenTree>
+   make_mismatched_delimiters ()
+   {
+     return tl::unexpected<DelimTokenTree> (
+       DelimTokenTree (Kind::INVALID_TOKEN_TREE));
+   }
+ 
+   enum class Kind
+   {
+     EXPECTED_DELIMITER,
+     INVALID_TOKEN_TREE,
+     MISMATCHED_DELIMITERS,
+   } kind;
+ 
+ private:
+   DelimTokenTree (Kind kind) : kind (kind) {}
+ };
+ 
+ struct Token
+ {
+   static tl::expected<std::unique_ptr<AST::Token>, Token> make_malformed ()
+   {
+     return tl::unexpected<Token> (Token (Kind::MALFORMED));
+   }
+ 
+   enum class Kind
+   {
+     MALFORMED,
+   } kind;
+ 
+ private:
+   Token (Kind kind) : kind (kind) {}
+ };
+ 
+ struct TokenTree
+ {
+   static tl::expected<std::unique_ptr<AST::TokenTree>, TokenTree>
+   make_malformed ()
+   {
+     return tl::unexpected<TokenTree> (TokenTree (Kind::MALFORMED));
+   }
+ 
+   static tl::expected<std::unique_ptr<AST::TokenTree>, TokenTree>
+   make_malformed_delimited_token_tree ()
+   {
+     return tl::unexpected<TokenTree> (
+       TokenTree (Kind::MALFORMED_DELIMITED_TOKEN_TREE));
+   }
+ 
+   enum class Kind
+   {
+     MALFORMED,
+     MALFORMED_DELIMITED_TOKEN_TREE,
+   } kind;
+ 
+ private:
+   TokenTree (Kind kind) : kind (kind) {}
+ };
+ 
+ struct Item
+ {
+   static tl::expected<std::unique_ptr<AST::Item>, Item> make_end_of_file ()
+   {
+     return tl::unexpected<Item> (Item (Kind::END_OF_FILE));
+   }
+ 
+   static tl::expected<std::unique_ptr<AST::Item>, Item> make_malformed ()
+   {
+     return tl::unexpected<Item> (Item (Kind::MALFORMED));
+   }
+ 
+   enum class Kind
+   {
+     END_OF_FILE,
+     MALFORMED,
+   } kind;
+ 
+ private:
+   Item (Kind kind) : kind (kind) {}
+ };
+ 
+ struct Items
+ {
+   static tl::expected<std::vector<std::unique_ptr<AST::Item>>, Items>
+   make_malformed (std::vector<std::unique_ptr<AST::Item>> items)
+   {
+     return tl::unexpected<Items> (Items (Kind::MALFORMED, std::move (items)));
+   }
+ 
+   enum class Kind
+   {
+     MALFORMED,
+   } kind;
+ 
+   Items (Items const &) = delete;
+   Items &operator= (Items const &) = delete;
+ 
+   Items (Items &&items) = default;
+   Items &operator= (Items &&) = default;
+ 
+   // Should we do anything with valid items ?
+   std::vector<std::unique_ptr<AST::Item>> items;
+ 
+ private:
+   Items (Kind kind, std::vector<std::unique_ptr<AST::Item>> items)
+     : kind (kind), items (std::move (items))
+   {}
+ };
+ 
+ struct Visibility
+ {
+   static tl::expected<AST::Visibility, Visibility> make_malformed ()
+   {
+     return tl::unexpected<Visibility> (Visibility (Kind::MALFORMED));
+   }
+ 
+   static tl::expected<AST::Visibility, Visibility> make_missing_path ()
+   {
+     return tl::unexpected<Visibility> (Visibility (Kind::MISSING_PATH));
+   }
+ 
+   enum class Kind
+   {
+     MISSING_PATH,
+     MALFORMED,
+   } kind;
+ 
+ private:
+   Visibility (Kind kind) : kind (kind) {}
+ };
+ 
+ } // namespace Error
+ } // namespace Parse
+ } // namespace Rust
+ 
+ #endif /* !RUST_PARSE_ERROR_H */
diff -Nrcpad gcc-16-20251214/gcc/rust/parse/rust-parse-impl-attribute.hxx gcc-16-20251221/gcc/rust/parse/rust-parse-impl-attribute.hxx
*** gcc-16-20251214/gcc/rust/parse/rust-parse-impl-attribute.hxx	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/rust/parse/rust-parse-impl-attribute.hxx	Sun Dec 21 22:32:07 2025
***************
*** 0 ****
--- 1,390 ----
+ // Copyright (C) 2025 Free Software Foundation, Inc.
+ 
+ // This file is part of GCC.
+ 
+ // GCC is free software; you can redistribute it and/or modify it under
+ // the terms of the GNU General Public License as published by the Free
+ // Software Foundation; either version 3, or (at your option) any later
+ // version.
+ 
+ // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+ // WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ // for more details.
+ 
+ // You should have received a copy of the GNU General Public License
+ // along with GCC; see the file COPYING3.  If not see
+ // <http://www.gnu.org/licenses/>.
+ 
+ /* DO NOT INCLUDE ANYWHERE - this is automatically included
+  *   by rust-parse-impl*.h
+  * This is also the reason why there are no include guards. */
+ 
+ #include "rust-parse.h"
+ #include "rust-parse-error.h"
+ #include "rust-attribute-values.h"
+ #include "expected.h"
+ 
+ namespace Rust {
+ 
+ // Parse a inner or outer doc comment into an doc attribute
+ template <typename ManagedTokenSource>
+ Parse::AttributeBody
+ Parser<ManagedTokenSource>::parse_doc_comment ()
+ {
+   const_TokenPtr token = lexer.peek_token ();
+   location_t locus = token->get_locus ();
+   AST::SimplePathSegment segment (Values::Attributes::DOC, locus);
+   std::vector<AST::SimplePathSegment> segments;
+   segments.push_back (std::move (segment));
+   AST::SimplePath attr_path (std::move (segments), false, locus);
+   AST::LiteralExpr lit_expr (token->get_str (), AST::Literal::STRING,
+ 			     PrimitiveCoreType::CORETYPE_STR, {}, locus);
+   std::unique_ptr<AST::AttrInput> attr_input (
+     new AST::AttrInputLiteral (std::move (lit_expr)));
+   lexer.skip_token ();
+ 
+   return Parse::AttributeBody{std::move (attr_path), std::move (attr_input),
+ 			      locus};
+ }
+ 
+ // Parse a single inner attribute.
+ template <typename ManagedTokenSource>
+ tl::expected<AST::Attribute, Parse::Error::Attribute>
+ Parser<ManagedTokenSource>::parse_inner_attribute ()
+ {
+   if (lexer.peek_token ()->get_id () == INNER_DOC_COMMENT)
+     {
+       auto body = parse_doc_comment ();
+       return AST::Attribute (std::move (body.path), std::move (body.input),
+ 			     body.locus, true);
+     }
+ 
+   rust_assert (lexer.peek_token ()->get_id () == HASH);
+ 
+   lexer.skip_token ();
+ 
+   if (lexer.peek_token ()->get_id () != EXCLAM)
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "expected %<!%> or %<[%> for inner attribute");
+       add_error (std::move (error));
+ 
+       return Parse::Error::Attribute::make_malformed ();
+     }
+   lexer.skip_token ();
+ 
+   if (!skip_token (LEFT_SQUARE))
+     return Parse::Error::Attribute::make_malformed ();
+ 
+   auto body_res = parse_attribute_body ();
+   if (!body_res)
+     return Parse::Error::Attribute::make_malformed ();
+   auto body = std::move (body_res.value ());
+ 
+   auto actual_attribute
+     = AST::Attribute (std::move (body.path), std::move (body.input), body.locus,
+ 		      true);
+ 
+   if (!skip_token (RIGHT_SQUARE))
+     return Parse::Error::Attribute::make_malformed ();
+ 
+   return actual_attribute;
+ }
+ 
+ // Parse a single outer attribute.
+ template <typename ManagedTokenSource>
+ tl::expected<AST::Attribute, Parse::Error::Attribute>
+ Parser<ManagedTokenSource>::parse_outer_attribute ()
+ {
+   if (lexer.peek_token ()->get_id () == OUTER_DOC_COMMENT)
+     {
+       auto body = parse_doc_comment ();
+       return AST::Attribute (std::move (body.path), std::move (body.input),
+ 			     body.locus, false);
+     }
+ 
+   if (lexer.peek_token ()->get_id () == INNER_DOC_COMMENT)
+     {
+       Error error (
+ 	lexer.peek_token ()->get_locus (), ErrorCode::E0753,
+ 	"expected outer doc comment, inner doc (%<//!%> or %</*!%>) only "
+ 	"allowed at start of item "
+ 	"and before any outer attribute or doc (%<#[%>, %<///%> or %</**%>)");
+       add_error (std::move (error));
+       lexer.skip_token ();
+       return Parse::Error::Attribute::make_unexpected_inner ();
+     }
+ 
+   /* OuterAttribute -> '#' '[' Attr ']' */
+ 
+   if (lexer.peek_token ()->get_id () != HASH)
+     return Parse::Error::Attribute::make_malformed ();
+ 
+   lexer.skip_token ();
+ 
+   TokenId id = lexer.peek_token ()->get_id ();
+   if (id != LEFT_SQUARE)
+     {
+       if (id == EXCLAM)
+ 	{
+ 	  // this is inner attribute syntax, so throw error
+ 	  // inner attributes were either already parsed or not allowed here.
+ 	  Error error (
+ 	    lexer.peek_token ()->get_locus (),
+ 	    "token %<!%> found, indicating inner attribute definition. Inner "
+ 	    "attributes are not possible at this location");
+ 	  add_error (std::move (error));
+ 	}
+       return Parse::Error::Attribute::make_unexpected_inner ();
+     }
+ 
+   lexer.skip_token ();
+ 
+   auto body_res = parse_attribute_body ();
+   if (!body_res)
+     return Parse::Error::Attribute::make_malformed_body ();
+   auto body = std::move (body_res.value ());
+ 
+   auto actual_attribute
+     = AST::Attribute (std::move (body.path), std::move (body.input), body.locus,
+ 		      false);
+ 
+   if (lexer.peek_token ()->get_id () != RIGHT_SQUARE)
+     return Parse::Error::Attribute::make_malformed ();
+ 
+   lexer.skip_token ();
+ 
+   return actual_attribute;
+ }
+ 
+ // Parses the body of an attribute (inner or outer).
+ template <typename ManagedTokenSource>
+ tl::expected<Parse::AttributeBody, Parse::Error::AttributeBody>
+ Parser<ManagedTokenSource>::parse_attribute_body ()
+ {
+   location_t locus = lexer.peek_token ()->get_locus ();
+ 
+   auto attr_path = parse_simple_path ();
+   // ensure path is valid to parse attribute input
+   if (!attr_path)
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "empty simple path in attribute");
+       add_error (std::move (error));
+ 
+       // Skip past potential further info in attribute (i.e. attr_input)
+       skip_after_end_attribute ();
+       return Parse::Error::AttributeBody::make_invalid_path ();
+     }
+ 
+   auto attr_input = parse_attr_input ();
+   // AttrInput is allowed to be null, so no checks here
+   if (attr_input)
+     return Parse::AttributeBody{std::move (attr_path.value ()),
+ 				std::move (attr_input.value ()), locus};
+   else if (attr_input.error ().kind == Parse::Error::AttrInput::Kind::MISSING)
+     return Parse::AttributeBody{std::move (attr_path.value ()), nullptr, locus};
+   else
+     return Parse::Error::AttributeBody::make_invalid_attrinput ();
+ }
+ 
+ // Parse a contiguous block of inner attributes.
+ template <typename ManagedTokenSource>
+ AST::AttrVec
+ Parser<ManagedTokenSource>::parse_inner_attributes ()
+ {
+   AST::AttrVec inner_attributes;
+ 
+   auto has_valid_inner_attribute_prefix = [&] () {
+     auto id = lexer.peek_token ()->get_id ();
+     /* Outer attribute `#[` is not allowed, only accepts `#!` */
+     return (id == HASH && lexer.peek_token (1)->get_id () == EXCLAM)
+ 	   || id == INNER_DOC_COMMENT;
+   };
+ 
+   while (has_valid_inner_attribute_prefix ())
+     {
+       auto inner_attr = parse_inner_attribute ();
+ 
+       /* Ensure only valid inner attributes are added to the inner_attributes
+        * list */
+       if (inner_attr)
+ 	{
+ 	  inner_attributes.push_back (std::move (inner_attr.value ()));
+ 	}
+       else
+ 	{
+ 	  /* If no more valid inner attributes, break out of loop (only
+ 	   * contiguous inner attributes parsed). */
+ 	  break;
+ 	}
+     }
+ 
+   inner_attributes.shrink_to_fit ();
+   return inner_attributes;
+ }
+ 
+ // Parses a contiguous block of outer attributes.
+ template <typename ManagedTokenSource>
+ AST::AttrVec
+ Parser<ManagedTokenSource>::parse_outer_attributes ()
+ {
+   AST::AttrVec outer_attributes;
+ 
+   auto has_valid_attribute_prefix = [&] () {
+     auto id = lexer.peek_token ()->get_id ();
+     /* We allow inner attributes `#!` and catch the error later  */
+     return id == HASH || id == OUTER_DOC_COMMENT || id == INNER_DOC_COMMENT;
+   };
+ 
+   while (has_valid_attribute_prefix ()) /* For error handling.  */
+     {
+       auto outer_attr = parse_outer_attribute ();
+ 
+       /* Ensure only valid outer attributes are added to the outer_attributes
+        * list */
+       if (outer_attr)
+ 	{
+ 	  outer_attributes.push_back (std::move (outer_attr.value ()));
+ 	}
+       else
+ 	{
+ 	  /* If no more valid outer attributes, break out of loop (only
+ 	   * contiguous outer attributes parsed). */
+ 	  break;
+ 	}
+     }
+ 
+   outer_attributes.shrink_to_fit ();
+   return outer_attributes;
+ 
+   /* TODO: this shares basically all code with parse_inner_attributes except
+    * function call - find way of making it more modular? function pointer? */
+ }
+ 
+ // Parses an AttrInput AST node (polymorphic, as AttrInput is abstract)
+ template <typename ManagedTokenSource>
+ tl::expected<std::unique_ptr<AST::AttrInput>, Parse::Error::AttrInput>
+ Parser<ManagedTokenSource>::parse_attr_input ()
+ {
+   const_TokenPtr t = lexer.peek_token ();
+   switch (t->get_id ())
+     {
+     case LEFT_PAREN:
+     case LEFT_SQUARE:
+     case LEFT_CURLY:
+       {
+ 	auto dtoken_tree = parse_delim_token_tree ();
+ 	if (!dtoken_tree)
+ 	  return Parse::Error::AttrInput::make_bad_token_tree ();
+ 
+ 	// must be a delimited token tree, so parse that
+ 	std::unique_ptr<AST::AttrInput> input_tree (
+ 	  new AST::DelimTokenTree (dtoken_tree.value ()));
+ 
+ 	return tl::expected<std::unique_ptr<AST::AttrInput>,
+ 			    Parse::Error::AttrInput>{std::move (input_tree)};
+       }
+     case EQUAL:
+       {
+ 	// = LiteralExpr
+ 	lexer.skip_token ();
+ 
+ 	t = lexer.peek_token ();
+ 
+ 	// attempt to parse macro
+ 	// TODO: macros may/may not be allowed in attributes
+ 	// this is needed for "#[doc = include_str!(...)]"
+ 	if (Parse::Utils::is_simple_path_segment (t->get_id ()))
+ 	  {
+ 	    std::unique_ptr<AST::MacroInvocation> invoke
+ 	      = parse_macro_invocation ({});
+ 
+ 	    if (!invoke)
+ 	      return Parse::Error::AttrInput::make_bad_macro_invocation ();
+ 
+ 	    return std::unique_ptr<AST::AttrInput> (
+ 	      new AST::AttrInputMacro (std::move (invoke)));
+ 	  }
+ 
+ 	/* Ensure token is a "literal expression" (literally only a literal
+ 	 * token of any type) */
+ 	if (!t->is_literal ())
+ 	  {
+ 	    Error error (
+ 	      t->get_locus (),
+ 	      "unknown token %qs in attribute body - literal expected",
+ 	      t->get_token_description ());
+ 	    add_error (std::move (error));
+ 
+ 	    skip_after_end_attribute ();
+ 	    return Parse::Error::AttrInput::make_malformed ();
+ 	  }
+ 
+ 	AST::Literal::LitType lit_type = AST::Literal::STRING;
+ 	// Crappy mapping of token type to literal type
+ 	switch (t->get_id ())
+ 	  {
+ 	  case INT_LITERAL:
+ 	    lit_type = AST::Literal::INT;
+ 	    break;
+ 	  case FLOAT_LITERAL:
+ 	    lit_type = AST::Literal::FLOAT;
+ 	    break;
+ 	  case CHAR_LITERAL:
+ 	    lit_type = AST::Literal::CHAR;
+ 	    break;
+ 	  case BYTE_CHAR_LITERAL:
+ 	    lit_type = AST::Literal::BYTE;
+ 	    break;
+ 	  case BYTE_STRING_LITERAL:
+ 	    lit_type = AST::Literal::BYTE_STRING;
+ 	    break;
+ 	  case RAW_STRING_LITERAL:
+ 	    lit_type = AST::Literal::RAW_STRING;
+ 	    break;
+ 	  case STRING_LITERAL:
+ 	  default:
+ 	    lit_type = AST::Literal::STRING;
+ 	    break; // TODO: raw string? don't eliminate it from lexer?
+ 	  }
+ 
+ 	// create actual LiteralExpr
+ 	AST::LiteralExpr lit_expr (t->get_str (), lit_type, t->get_type_hint (),
+ 				   {}, t->get_locus ());
+ 	lexer.skip_token ();
+ 
+ 	std::unique_ptr<AST::AttrInput> attr_input_lit (
+ 	  new AST::AttrInputLiteral (std::move (lit_expr)));
+ 
+ 	// do checks or whatever? none required, really
+ 
+ 	// FIXME: shouldn't a skip token be required here?
+ 
+ 	return tl::expected<std::unique_ptr<AST::AttrInput>,
+ 			    Parse::Error::AttrInput>{
+ 	  std::move (attr_input_lit)};
+       }
+       break;
+     case RIGHT_PAREN:
+     case RIGHT_SQUARE:
+     case RIGHT_CURLY:
+     case END_OF_FILE:
+       // means AttrInput is missing, which is allowed
+       return Parse::Error::AttrInput::make_missing_attrinput ();
+     default:
+       add_error (
+ 	Error (t->get_locus (),
+ 	       "unknown token %qs in attribute body - attribute input or "
+ 	       "none expected",
+ 	       t->get_token_description ()));
+ 
+       skip_after_end_attribute ();
+       return Parse::Error::AttrInput::make_malformed ();
+     }
+   rust_unreachable ();
+   // TODO: find out how to stop gcc error on "no return value"
+ }
+ 
+ } // namespace Rust
diff -Nrcpad gcc-16-20251214/gcc/rust/parse/rust-parse-impl-expr.hxx gcc-16-20251221/gcc/rust/parse/rust-parse-impl-expr.hxx
*** gcc-16-20251214/gcc/rust/parse/rust-parse-impl-expr.hxx	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/rust/parse/rust-parse-impl-expr.hxx	Sun Dec 21 22:32:07 2025
***************
*** 0 ****
--- 1,4106 ----
+ // Copyright (C) 2025 Free Software Foundation, Inc.
+ 
+ // This file is part of GCC.
+ 
+ // GCC is free software; you can redistribute it and/or modify it under
+ // the terms of the GNU General Public License as published by the Free
+ // Software Foundation; either version 3, or (at your option) any later
+ // version.
+ 
+ // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+ // WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ // for more details.
+ 
+ // You should have received a copy of the GNU General Public License
+ // along with GCC; see the file COPYING3.  If not see
+ // <http://www.gnu.org/licenses/>.
+ 
+ /* DO NOT INCLUDE ANYWHERE - this is automatically included
+  *   by rust-parse-impl.h
+  * This is also the reason why there are no include guards. */
+ 
+ #include "rust-parse.h"
+ 
+ namespace Rust {
+ 
+ // Parses a block expression, including the curly braces at start and end.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::BlockExpr>
+ Parser<ManagedTokenSource>::parse_block_expr (
+   AST::AttrVec outer_attrs, tl::optional<AST::LoopLabel> label,
+   location_t pratt_parsed_loc)
+ {
+   location_t locus = pratt_parsed_loc;
+   if (locus == UNKNOWN_LOCATION)
+     {
+       locus = lexer.peek_token ()->get_locus ();
+       if (!skip_token (LEFT_CURLY))
+ 	{
+ 	  skip_after_end_block ();
+ 	  return nullptr;
+ 	}
+     }
+ 
+   AST::AttrVec inner_attrs = parse_inner_attributes ();
+ 
+   // parse statements and expression
+   std::vector<std::unique_ptr<AST::Stmt>> stmts;
+   std::unique_ptr<AST::Expr> expr = nullptr;
+ 
+   const_TokenPtr t = lexer.peek_token ();
+   while (t->get_id () != RIGHT_CURLY)
+     {
+       ExprOrStmt expr_or_stmt = parse_stmt_or_expr ();
+       if (expr_or_stmt.is_error ())
+ 	{
+ 	  skip_after_end_block ();
+ 	  return nullptr;
+ 	}
+ 
+       t = lexer.peek_token ();
+ 
+       if (expr_or_stmt.stmt != nullptr)
+ 	{
+ 	  stmts.push_back (std::move (expr_or_stmt.stmt));
+ 	}
+       else
+ 	{
+ 	  // assign to expression and end parsing inside
+ 	  expr = std::move (expr_or_stmt.expr);
+ 	  break;
+ 	}
+     }
+ 
+   location_t end_locus = t->get_locus ();
+ 
+   if (!skip_token (RIGHT_CURLY))
+     {
+       Error error (t->get_locus (),
+ 		   "error may be from having an expression (as opposed to "
+ 		   "statement) in the body of the function but not last");
+       add_error (std::move (error));
+ 
+       skip_after_end_block ();
+       return nullptr;
+     }
+ 
+   // grammar allows for empty block expressions
+ 
+   stmts.shrink_to_fit ();
+ 
+   return std::unique_ptr<AST::BlockExpr> (
+     new AST::BlockExpr (std::move (stmts), std::move (expr),
+ 			std::move (inner_attrs), std::move (outer_attrs),
+ 			std::move (label), locus, end_locus));
+ }
+ 
+ /* Parse an anonymous const expression. This can be a regular const expression
+  * or an underscore for deferred const inference */
+ template <typename ManagedTokenSource>
+ tl::expected<AST::AnonConst, AnonConstError>
+ Parser<ManagedTokenSource>::parse_anon_const ()
+ {
+   auto current = lexer.peek_token ();
+   auto locus = current->get_locus ();
+ 
+   // Special case deferred inference constants
+   if (maybe_skip_token (UNDERSCORE))
+     return AST::AnonConst (locus);
+ 
+   auto expr = parse_expr ();
+ 
+   if (!expr)
+     return tl::make_unexpected (AnonConstError::InvalidSizeExpr);
+ 
+   return AST::AnonConst (std::move (expr), locus);
+ }
+ 
+ /* Parse a "const block", a block preceded by the `const` keyword whose
+  * statements can be const evaluated and used in constant contexts */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::ConstBlock>
+ Parser<ManagedTokenSource>::parse_const_block_expr (AST::AttrVec outer_attrs,
+ 						    location_t locus)
+ {
+   auto block = parse_block_expr ();
+ 
+   if (!block)
+     {
+       add_error (Error (locus, "failed to parse inner block in const block"));
+       skip_after_end_block ();
+ 
+       return nullptr;
+     }
+ 
+   auto block_locus = block->get_locus ();
+ 
+   return std::make_unique<AST::ConstBlock> (AST::AnonConst (std::move (block),
+ 							    block_locus),
+ 					    locus, std::move (outer_attrs));
+ }
+ 
+ /* Parses a "grouped" expression (expression in parentheses), used to control
+  * precedence. */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::GroupedExpr>
+ Parser<ManagedTokenSource>::parse_grouped_expr (AST::AttrVec outer_attrs)
+ {
+   location_t locus = lexer.peek_token ()->get_locus ();
+   skip_token (LEFT_PAREN);
+ 
+   AST::AttrVec inner_attrs = parse_inner_attributes ();
+ 
+   // parse required expr inside parentheses
+   std::unique_ptr<AST::Expr> expr_in_parens = parse_expr ();
+   if (expr_in_parens == nullptr)
+     {
+       // skip after somewhere?
+       // error?
+       return nullptr;
+     }
+ 
+   if (!skip_token (RIGHT_PAREN))
+     {
+       // skip after somewhere?
+       return nullptr;
+     }
+ 
+   return std::unique_ptr<AST::GroupedExpr> (
+     new AST::GroupedExpr (std::move (expr_in_parens), std::move (inner_attrs),
+ 			  std::move (outer_attrs), locus));
+ }
+ 
+ // Parses a closure expression (closure definition).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::ClosureExpr>
+ Parser<ManagedTokenSource>::parse_closure_expr (AST::AttrVec outer_attrs)
+ {
+   location_t locus = lexer.peek_token ()->get_locus ();
+   // detect optional "move"
+   bool has_move = false;
+   if (lexer.peek_token ()->get_id () == MOVE)
+     {
+       lexer.skip_token ();
+       has_move = true;
+     }
+ 
+   // handle parameter list
+   std::vector<AST::ClosureParam> params;
+ 
+   const_TokenPtr t = lexer.peek_token ();
+   switch (t->get_id ())
+     {
+     case OR:
+       // skip token, no parameters
+       lexer.skip_token ();
+       break;
+     case PIPE:
+       // actually may have parameters
+       lexer.skip_token ();
+       t = lexer.peek_token ();
+ 
+       while (t->get_id () != PIPE)
+ 	{
+ 	  AST::ClosureParam param = parse_closure_param ();
+ 	  if (param.is_error ())
+ 	    {
+ 	      // TODO is this really an error?
+ 	      Error error (t->get_locus (), "could not parse closure param");
+ 	      add_error (std::move (error));
+ 
+ 	      break;
+ 	    }
+ 	  params.push_back (std::move (param));
+ 
+ 	  if (lexer.peek_token ()->get_id () != COMMA)
+ 	    {
+ 	      lexer.skip_token ();
+ 	      // not an error but means param list is done
+ 	      break;
+ 	    }
+ 	  // skip comma
+ 	  lexer.skip_token ();
+ 
+ 	  t = lexer.peek_token ();
+ 	}
+       params.shrink_to_fit ();
+       break;
+     default:
+       add_error (Error (t->get_locus (),
+ 			"unexpected token %qs in closure expression - expected "
+ 			"%<|%> or %<||%>",
+ 			t->get_token_description ()));
+ 
+       // skip somewhere?
+       return nullptr;
+     }
+ 
+   // again branch based on next token
+   t = lexer.peek_token ();
+   if (t->get_id () == RETURN_TYPE)
+     {
+       // must be return type closure with block expr
+ 
+       // skip "return type" token
+       lexer.skip_token ();
+ 
+       // parse actual type, which is required
+       std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
+       if (type == nullptr)
+ 	{
+ 	  // error
+ 	  Error error (t->get_locus (), "failed to parse type for closure");
+ 	  add_error (std::move (error));
+ 
+ 	  // skip somewhere?
+ 	  return nullptr;
+ 	}
+ 
+       // parse block expr, which is required
+       std::unique_ptr<AST::BlockExpr> block = parse_block_expr ();
+       if (block == nullptr)
+ 	{
+ 	  // error
+ 	  Error error (lexer.peek_token ()->get_locus (),
+ 		       "failed to parse block expr in closure");
+ 	  add_error (std::move (error));
+ 
+ 	  // skip somewhere?
+ 	  return nullptr;
+ 	}
+ 
+       return std::unique_ptr<AST::ClosureExprInnerTyped> (
+ 	new AST::ClosureExprInnerTyped (std::move (type), std::move (block),
+ 					std::move (params), locus, has_move,
+ 					std::move (outer_attrs)));
+     }
+   else
+     {
+       // must be expr-only closure
+ 
+       // parse expr, which is required
+       std::unique_ptr<AST::Expr> expr = parse_expr ();
+       if (expr == nullptr)
+ 	{
+ 	  Error error (t->get_locus (),
+ 		       "failed to parse expression in closure");
+ 	  add_error (std::move (error));
+ 
+ 	  // skip somewhere?
+ 	  return nullptr;
+ 	}
+ 
+       return std::unique_ptr<AST::ClosureExprInner> (
+ 	new AST::ClosureExprInner (std::move (expr), std::move (params), locus,
+ 				   has_move, std::move (outer_attrs)));
+     }
+ }
+ 
+ // Parses a literal token (to literal expression).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::LiteralExpr>
+ Parser<ManagedTokenSource>::parse_literal_expr (AST::AttrVec outer_attrs)
+ {
+   // TODO: change if literal representation in lexer changes
+ 
+   std::string literal_value;
+   AST::Literal::LitType type = AST::Literal::STRING;
+ 
+   // branch based on token
+   const_TokenPtr t = lexer.peek_token ();
+   switch (t->get_id ())
+     {
+     case CHAR_LITERAL:
+       type = AST::Literal::CHAR;
+       literal_value = t->get_str ();
+       lexer.skip_token ();
+       break;
+     case STRING_LITERAL:
+       type = AST::Literal::STRING;
+       literal_value = t->get_str ();
+       lexer.skip_token ();
+       break;
+     case BYTE_CHAR_LITERAL:
+       type = AST::Literal::BYTE;
+       literal_value = t->get_str ();
+       lexer.skip_token ();
+       break;
+     case BYTE_STRING_LITERAL:
+       type = AST::Literal::BYTE_STRING;
+       literal_value = t->get_str ();
+       lexer.skip_token ();
+       break;
+     case RAW_STRING_LITERAL:
+       type = AST::Literal::RAW_STRING;
+       literal_value = t->get_str ();
+       lexer.skip_token ();
+       break;
+     case INT_LITERAL:
+       type = AST::Literal::INT;
+       literal_value = t->get_str ();
+       lexer.skip_token ();
+       break;
+     case FLOAT_LITERAL:
+       type = AST::Literal::FLOAT;
+       literal_value = t->get_str ();
+       lexer.skip_token ();
+       break;
+     // case BOOL_LITERAL
+     // use true and false keywords rather than "bool literal" Rust terminology
+     case TRUE_LITERAL:
+       type = AST::Literal::BOOL;
+       literal_value = Values::Keywords::TRUE_LITERAL;
+       lexer.skip_token ();
+       break;
+     case FALSE_LITERAL:
+       type = AST::Literal::BOOL;
+       literal_value = Values::Keywords::FALSE_LITERAL;
+       lexer.skip_token ();
+       break;
+     default:
+       // error - cannot be a literal expr
+       add_error (Error (t->get_locus (),
+ 			"unexpected token %qs when parsing literal expression",
+ 			t->get_token_description ()));
+ 
+       // skip?
+       return nullptr;
+     }
+ 
+   // create literal based on stuff in switch
+   return std::unique_ptr<AST::LiteralExpr> (
+     new AST::LiteralExpr (std::move (literal_value), std::move (type),
+ 			  t->get_type_hint (), std::move (outer_attrs),
+ 			  t->get_locus ()));
+ }
+ 
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::BoxExpr>
+ Parser<ManagedTokenSource>::parse_box_expr (AST::AttrVec outer_attrs,
+ 					    location_t pratt_parsed_loc)
+ {
+   location_t locus = pratt_parsed_loc;
+   if (locus == UNKNOWN_LOCATION)
+     {
+       locus = lexer.peek_token ()->get_locus ();
+       skip_token (BOX);
+     }
+ 
+   ParseRestrictions restrictions;
+   restrictions.expr_can_be_null = false;
+ 
+   std::unique_ptr<AST::Expr> expr = parse_expr (AST::AttrVec (), restrictions);
+ 
+   return std::unique_ptr<AST::BoxExpr> (
+     new AST::BoxExpr (std::move (expr), std::move (outer_attrs), locus));
+ }
+ 
+ // Parses a return expression (including any expression to return).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::ReturnExpr>
+ Parser<ManagedTokenSource>::parse_return_expr (AST::AttrVec outer_attrs,
+ 					       location_t pratt_parsed_loc)
+ {
+   location_t locus = pratt_parsed_loc;
+   if (locus == UNKNOWN_LOCATION)
+     {
+       locus = lexer.peek_token ()->get_locus ();
+       skip_token (RETURN_KW);
+     }
+ 
+   // parse expression to return, if it exists
+   ParseRestrictions restrictions;
+   restrictions.expr_can_be_null = true;
+   std::unique_ptr<AST::Expr> returned_expr
+     = parse_expr (AST::AttrVec (), restrictions);
+ 
+   return std::unique_ptr<AST::ReturnExpr> (
+     new AST::ReturnExpr (std::move (returned_expr), std::move (outer_attrs),
+ 			 locus));
+ }
+ 
+ // Parses a try expression.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::TryExpr>
+ Parser<ManagedTokenSource>::parse_try_expr (AST::AttrVec outer_attrs,
+ 					    location_t pratt_parsed_loc)
+ {
+   location_t locus = pratt_parsed_loc;
+   if (locus == UNKNOWN_LOCATION)
+     {
+       locus = lexer.peek_token ()->get_locus ();
+       skip_token (TRY);
+     }
+ 
+   std::unique_ptr<AST::BlockExpr> block_expr = parse_block_expr ();
+ 
+   if (!block_expr)
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "failed to parse try block expression");
+       add_error (std::move (error));
+ 
+       return nullptr;
+     }
+ 
+   return std::unique_ptr<AST::TryExpr> (
+     new AST::TryExpr (std::move (block_expr), std::move (outer_attrs), locus));
+ }
+ 
+ /* Parses a break expression (including any label to break to AND any return
+  * expression). */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::BreakExpr>
+ Parser<ManagedTokenSource>::parse_break_expr (AST::AttrVec outer_attrs,
+ 					      location_t pratt_parsed_loc)
+ {
+   location_t locus = pratt_parsed_loc;
+   if (locus == UNKNOWN_LOCATION)
+     {
+       locus = lexer.peek_token ()->get_locus ();
+       skip_token (BREAK);
+     }
+ 
+   auto parsed_label = parse_lifetime (false);
+   auto label = (parsed_label)
+ 		 ? tl::optional<AST::Lifetime> (parsed_label.value ())
+ 		 : tl::nullopt;
+ 
+   // parse break return expression if it exists
+   ParseRestrictions restrictions;
+   restrictions.expr_can_be_null = true;
+   std::unique_ptr<AST::Expr> return_expr
+     = parse_expr (AST::AttrVec (), restrictions);
+ 
+   return std::unique_ptr<AST::BreakExpr> (
+     new AST::BreakExpr (std::move (label), std::move (return_expr),
+ 			std::move (outer_attrs), locus));
+ }
+ 
+ // Parses a continue expression (including any label to continue from).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::ContinueExpr>
+ Parser<ManagedTokenSource>::parse_continue_expr (AST::AttrVec outer_attrs,
+ 						 location_t pratt_parsed_loc)
+ {
+   location_t locus = pratt_parsed_loc;
+   if (locus == UNKNOWN_LOCATION)
+     {
+       locus = lexer.peek_token ()->get_locus ();
+       skip_token (CONTINUE);
+     }
+ 
+   auto parsed_label = parse_lifetime (false);
+   auto label = (parsed_label)
+ 		 ? tl::optional<AST::Lifetime> (parsed_label.value ())
+ 		 : tl::nullopt;
+ 
+   return std::unique_ptr<AST::ContinueExpr> (
+     new AST::ContinueExpr (std::move (label), std::move (outer_attrs), locus));
+ }
+ 
+ /* Parses an if expression of any kind, including with else, else if, else if
+  * let, and neither. Note that any outer attributes will be ignored because if
+  * expressions don't support them. */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::IfExpr>
+ Parser<ManagedTokenSource>::parse_if_expr (AST::AttrVec outer_attrs,
+ 					   location_t pratt_parsed_loc)
+ {
+   // TODO: make having outer attributes an error?
+   location_t locus = pratt_parsed_loc;
+   if (locus == UNKNOWN_LOCATION)
+     {
+       locus = lexer.peek_token ()->get_locus ();
+       if (!skip_token (IF))
+ 	{
+ 	  skip_after_end_block ();
+ 	  return nullptr;
+ 	}
+     }
+ 
+   // detect accidental if let
+   if (lexer.peek_token ()->get_id () == LET)
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "if let expression probably exists, but is being parsed "
+ 		   "as an if expression. This may be a parser error");
+       add_error (std::move (error));
+ 
+       // skip somewhere?
+       return nullptr;
+     }
+ 
+   /* parse required condition expr - HACK to prevent struct expr from being
+    * parsed */
+   ParseRestrictions no_struct_expr;
+   no_struct_expr.can_be_struct_expr = false;
+   std::unique_ptr<AST::Expr> condition = parse_expr ({}, no_struct_expr);
+   if (condition == nullptr)
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "failed to parse condition expression in if expression");
+       add_error (std::move (error));
+ 
+       // skip somewhere?
+       return nullptr;
+     }
+ 
+   // parse required block expr
+   std::unique_ptr<AST::BlockExpr> if_body = parse_block_expr ();
+   if (if_body == nullptr)
+     return nullptr;
+ 
+   // branch to parse end or else (and then else, else if, or else if let)
+   if (lexer.peek_token ()->get_id () != ELSE)
+     {
+       // single selection - end of if expression
+       return std::unique_ptr<AST::IfExpr> (
+ 	new AST::IfExpr (std::move (condition), std::move (if_body),
+ 			 std::move (outer_attrs), locus));
+     }
+   else
+     {
+       // double or multiple selection - branch on end, else if, or else if let
+ 
+       // skip "else"
+       lexer.skip_token ();
+ 
+       // branch on whether next token is '{' or 'if'
+       const_TokenPtr t = lexer.peek_token ();
+       switch (t->get_id ())
+ 	{
+ 	case LEFT_CURLY:
+ 	  {
+ 	    // double selection - else
+ 	    // parse else block expr (required)
+ 	    std::unique_ptr<AST::BlockExpr> else_body = parse_block_expr ();
+ 	    if (else_body == nullptr)
+ 	      {
+ 		Error error (lexer.peek_token ()->get_locus (),
+ 			     "failed to parse else body block expression in "
+ 			     "if expression");
+ 		add_error (std::move (error));
+ 
+ 		// skip somewhere?
+ 		return nullptr;
+ 	      }
+ 
+ 	    return std::unique_ptr<AST::IfExprConseqElse> (
+ 	      new AST::IfExprConseqElse (std::move (condition),
+ 					 std::move (if_body),
+ 					 std::move (else_body),
+ 					 std::move (outer_attrs), locus));
+ 	  }
+ 	case IF:
+ 	  {
+ 	    // multiple selection - else if or else if let
+ 	    // branch on whether next token is 'let' or not
+ 	    if (lexer.peek_token (1)->get_id () == LET)
+ 	      {
+ 		// parse if let expr (required)
+ 		std::unique_ptr<AST::IfLetExpr> if_let_expr
+ 		  = parse_if_let_expr ();
+ 		if (if_let_expr == nullptr)
+ 		  {
+ 		    Error error (lexer.peek_token ()->get_locus (),
+ 				 "failed to parse (else) if let expression "
+ 				 "after if expression");
+ 		    add_error (std::move (error));
+ 
+ 		    // skip somewhere?
+ 		    return nullptr;
+ 		  }
+ 
+ 		return std::unique_ptr<AST::IfExprConseqElse> (
+ 		  new AST::IfExprConseqElse (std::move (condition),
+ 					     std::move (if_body),
+ 					     std::move (if_let_expr),
+ 					     std::move (outer_attrs), locus));
+ 	      }
+ 	    else
+ 	      {
+ 		// parse if expr (required)
+ 		std::unique_ptr<AST::IfExpr> if_expr = parse_if_expr ();
+ 		if (if_expr == nullptr)
+ 		  {
+ 		    Error error (lexer.peek_token ()->get_locus (),
+ 				 "failed to parse (else) if expression after "
+ 				 "if expression");
+ 		    add_error (std::move (error));
+ 
+ 		    // skip somewhere?
+ 		    return nullptr;
+ 		  }
+ 
+ 		return std::unique_ptr<AST::IfExprConseqElse> (
+ 		  new AST::IfExprConseqElse (std::move (condition),
+ 					     std::move (if_body),
+ 					     std::move (if_expr),
+ 					     std::move (outer_attrs), locus));
+ 	      }
+ 	  }
+ 	default:
+ 	  // error - invalid token
+ 	  add_error (Error (t->get_locus (),
+ 			    "unexpected token %qs after else in if expression",
+ 			    t->get_token_description ()));
+ 
+ 	  // skip somewhere?
+ 	  return nullptr;
+ 	}
+     }
+ }
+ 
+ /* Parses an if let expression of any kind, including with else, else if, else
+  * if let, and none. Note that any outer attributes will be ignored as if let
+  * expressions don't support them. */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::IfLetExpr>
+ Parser<ManagedTokenSource>::parse_if_let_expr (AST::AttrVec outer_attrs,
+ 					       location_t pratt_parsed_loc)
+ {
+   // TODO: make having outer attributes an error?
+   location_t locus = pratt_parsed_loc;
+   if (locus == UNKNOWN_LOCATION)
+     {
+       locus = lexer.peek_token ()->get_locus ();
+       if (!skip_token (IF))
+ 	{
+ 	  skip_after_end_block ();
+ 	  return nullptr;
+ 	}
+     }
+ 
+   // detect accidental if expr parsed as if let expr
+   if (lexer.peek_token ()->get_id () != LET)
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "if expression probably exists, but is being parsed as an "
+ 		   "if let expression. This may be a parser error");
+       add_error (std::move (error));
+ 
+       // skip somewhere?
+       return nullptr;
+     }
+   lexer.skip_token ();
+ 
+   // parse match arm patterns (which are required)
+   std::vector<std::unique_ptr<AST::Pattern>> match_arm_patterns
+     = parse_match_arm_patterns (EQUAL);
+   if (match_arm_patterns.empty ())
+     {
+       Error error (
+ 	lexer.peek_token ()->get_locus (),
+ 	"failed to parse any match arm patterns in if let expression");
+       add_error (std::move (error));
+ 
+       // skip somewhere?
+       return nullptr;
+     }
+ 
+   if (!skip_token (EQUAL))
+     {
+       // skip somewhere?
+       return nullptr;
+     }
+ 
+   // parse expression (required) - HACK to prevent struct expr being parsed
+   ParseRestrictions no_struct_expr;
+   no_struct_expr.can_be_struct_expr = false;
+   std::unique_ptr<AST::Expr> scrutinee_expr = parse_expr ({}, no_struct_expr);
+   if (scrutinee_expr == nullptr)
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "failed to parse scrutinee expression in if let expression");
+       add_error (std::move (error));
+ 
+       // skip somewhere?
+       return nullptr;
+     }
+   /* TODO: check for expression not being a struct expression or lazy boolean
+    * expression here? or actually probably in semantic analysis. */
+ 
+   // parse block expression (required)
+   std::unique_ptr<AST::BlockExpr> if_let_body = parse_block_expr ();
+   if (if_let_body == nullptr)
+     {
+       Error error (
+ 	lexer.peek_token ()->get_locus (),
+ 	"failed to parse if let body block expression in if let expression");
+       add_error (std::move (error));
+ 
+       // skip somewhere?
+       return nullptr;
+     }
+ 
+   // branch to parse end or else (and then else, else if, or else if let)
+   if (lexer.peek_token ()->get_id () != ELSE)
+     {
+       // single selection - end of if let expression
+       return std::unique_ptr<AST::IfLetExpr> (
+ 	new AST::IfLetExpr (std::move (match_arm_patterns),
+ 			    std::move (scrutinee_expr), std::move (if_let_body),
+ 			    std::move (outer_attrs), locus));
+     }
+   else
+     {
+       // double or multiple selection - branch on end, else if, or else if let
+ 
+       // skip "else"
+       lexer.skip_token ();
+ 
+       // branch on whether next token is '{' or 'if'
+       const_TokenPtr t = lexer.peek_token ();
+       switch (t->get_id ())
+ 	{
+ 	case LEFT_CURLY:
+ 	  {
+ 	    // double selection - else
+ 	    // parse else block expr (required)
+ 	    std::unique_ptr<AST::BlockExpr> else_body = parse_block_expr ();
+ 	    if (else_body == nullptr)
+ 	      {
+ 		Error error (lexer.peek_token ()->get_locus (),
+ 			     "failed to parse else body block expression in "
+ 			     "if let expression");
+ 		add_error (std::move (error));
+ 
+ 		// skip somewhere?
+ 		return nullptr;
+ 	      }
+ 
+ 	    return std::unique_ptr<AST::IfLetExprConseqElse> (
+ 	      new AST::IfLetExprConseqElse (std::move (match_arm_patterns),
+ 					    std::move (scrutinee_expr),
+ 					    std::move (if_let_body),
+ 					    std::move (else_body),
+ 					    std::move (outer_attrs), locus));
+ 	  }
+ 	case IF:
+ 	  {
+ 	    // multiple selection - else if or else if let
+ 	    // branch on whether next token is 'let' or not
+ 	    if (lexer.peek_token (1)->get_id () == LET)
+ 	      {
+ 		// parse if let expr (required)
+ 		std::unique_ptr<AST::IfLetExpr> if_let_expr
+ 		  = parse_if_let_expr ();
+ 		if (if_let_expr == nullptr)
+ 		  {
+ 		    Error error (lexer.peek_token ()->get_locus (),
+ 				 "failed to parse (else) if let expression "
+ 				 "after if let expression");
+ 		    add_error (std::move (error));
+ 
+ 		    // skip somewhere?
+ 		    return nullptr;
+ 		  }
+ 
+ 		return std::unique_ptr<AST::IfLetExprConseqElse> (
+ 		  new AST::IfLetExprConseqElse (
+ 		    std::move (match_arm_patterns), std::move (scrutinee_expr),
+ 		    std::move (if_let_body), std::move (if_let_expr),
+ 		    std::move (outer_attrs), locus));
+ 	      }
+ 	    else
+ 	      {
+ 		// parse if expr (required)
+ 		std::unique_ptr<AST::IfExpr> if_expr = parse_if_expr ();
+ 		if (if_expr == nullptr)
+ 		  {
+ 		    Error error (lexer.peek_token ()->get_locus (),
+ 				 "failed to parse (else) if expression after "
+ 				 "if let expression");
+ 		    add_error (std::move (error));
+ 
+ 		    // skip somewhere?
+ 		    return nullptr;
+ 		  }
+ 
+ 		return std::unique_ptr<AST::IfLetExprConseqElse> (
+ 		  new AST::IfLetExprConseqElse (
+ 		    std::move (match_arm_patterns), std::move (scrutinee_expr),
+ 		    std::move (if_let_body), std::move (if_expr),
+ 		    std::move (outer_attrs), locus));
+ 	      }
+ 	  }
+ 	default:
+ 	  // error - invalid token
+ 	  add_error (
+ 	    Error (t->get_locus (),
+ 		   "unexpected token %qs after else in if let expression",
+ 		   t->get_token_description ()));
+ 
+ 	  // skip somewhere?
+ 	  return nullptr;
+ 	}
+     }
+ }
+ 
+ /* TODO: possibly decide on different method of handling label (i.e. not
+  * parameter) */
+ 
+ /* Parses a "loop" infinite loop expression. Label is not parsed and should be
+  * parsed via parse_labelled_loop_expr, which would call this. */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::LoopExpr>
+ Parser<ManagedTokenSource>::parse_loop_expr (AST::AttrVec outer_attrs,
+ 					     tl::optional<AST::LoopLabel> label,
+ 					     location_t pratt_parsed_loc)
+ {
+   location_t locus = pratt_parsed_loc;
+   if (locus == UNKNOWN_LOCATION)
+     {
+       if (label)
+ 	locus = label->get_locus ();
+       else
+ 	locus = lexer.peek_token ()->get_locus ();
+ 
+       if (!skip_token (LOOP))
+ 	{
+ 	  skip_after_end_block ();
+ 	  return nullptr;
+ 	}
+     }
+   else
+     {
+       if (label)
+ 	locus = label->get_locus ();
+     }
+ 
+   // parse loop body, which is required
+   std::unique_ptr<AST::BlockExpr> loop_body = parse_block_expr ();
+   if (loop_body == nullptr)
+     return nullptr;
+ 
+   return std::unique_ptr<AST::LoopExpr> (
+     new AST::LoopExpr (std::move (loop_body), locus, std::move (label),
+ 		       std::move (outer_attrs)));
+ }
+ 
+ /* Parses a "while" loop expression. Label is not parsed and should be parsed
+  * via parse_labelled_loop_expr, which would call this. */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::WhileLoopExpr>
+ Parser<ManagedTokenSource>::parse_while_loop_expr (
+   AST::AttrVec outer_attrs, tl::optional<AST::LoopLabel> label,
+   location_t pratt_parsed_loc)
+ {
+   location_t locus = pratt_parsed_loc;
+   if (locus == UNKNOWN_LOCATION)
+     {
+       if (label)
+ 	locus = label->get_locus ();
+       else
+ 	locus = lexer.peek_token ()->get_locus ();
+ 
+       if (!skip_token (WHILE))
+ 	{
+ 	  skip_after_end_block ();
+ 	  return nullptr;
+ 	}
+     }
+   else
+     {
+       if (label)
+ 	locus = label->get_locus ();
+     }
+ 
+   // ensure it isn't a while let loop
+   if (lexer.peek_token ()->get_id () == LET)
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "appears to be while let loop but is being parsed by "
+ 		   "while loop - this may be a compiler issue");
+       add_error (std::move (error));
+ 
+       // skip somewhere?
+       return nullptr;
+     }
+ 
+   // parse loop predicate (required) with HACK to prevent struct expr parsing
+   ParseRestrictions no_struct_expr;
+   no_struct_expr.can_be_struct_expr = false;
+   std::unique_ptr<AST::Expr> predicate = parse_expr ({}, no_struct_expr);
+   if (predicate == nullptr)
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "failed to parse predicate expression in while loop");
+       add_error (std::move (error));
+ 
+       // skip somewhere?
+       return nullptr;
+     }
+   /* TODO: check that it isn't struct expression here? actually, probably in
+    * semantic analysis */
+ 
+   // parse loop body (required)
+   std::unique_ptr<AST::BlockExpr> body = parse_block_expr ();
+   if (body == nullptr)
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "failed to parse loop body block expression in while loop");
+       add_error (std::move (error));
+ 
+       // skip somewhere
+       return nullptr;
+     }
+ 
+   return std::unique_ptr<AST::WhileLoopExpr> (
+     new AST::WhileLoopExpr (std::move (predicate), std::move (body), locus,
+ 			    std::move (label), std::move (outer_attrs)));
+ }
+ 
+ /* Parses a "while let" loop expression. Label is not parsed and should be
+  * parsed via parse_labelled_loop_expr, which would call this. */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::WhileLetLoopExpr>
+ Parser<ManagedTokenSource>::parse_while_let_loop_expr (
+   AST::AttrVec outer_attrs, tl::optional<AST::LoopLabel> label)
+ {
+   location_t locus = UNKNOWN_LOCATION;
+   if (label)
+     locus = label->get_locus ();
+   else
+     locus = lexer.peek_token ()->get_locus ();
+   maybe_skip_token (WHILE);
+ 
+   /* check for possible accidental recognition of a while loop as a while let
+    * loop */
+   if (lexer.peek_token ()->get_id () != LET)
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "appears to be a while loop but is being parsed by "
+ 		   "while let loop - this may be a compiler issue");
+       add_error (std::move (error));
+ 
+       // skip somewhere
+       return nullptr;
+     }
+   // as this token is definitely let now, save the computation of comparison
+   lexer.skip_token ();
+ 
+   // parse predicate patterns
+   std::vector<std::unique_ptr<AST::Pattern>> predicate_patterns
+     = parse_match_arm_patterns (EQUAL);
+   // ensure that there is at least 1 pattern
+   if (predicate_patterns.empty ())
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "should be at least 1 pattern");
+       add_error (std::move (error));
+       return nullptr;
+     }
+ 
+   if (!skip_token (EQUAL))
+     {
+       // skip somewhere?
+       return nullptr;
+     }
+ 
+   /* parse predicate expression, which is required (and HACK to prevent struct
+    * expr) */
+   ParseRestrictions no_struct_expr;
+   no_struct_expr.can_be_struct_expr = false;
+   std::unique_ptr<AST::Expr> predicate_expr = parse_expr ({}, no_struct_expr);
+   if (predicate_expr == nullptr)
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "failed to parse predicate expression in while let loop");
+       add_error (std::move (error));
+ 
+       // skip somewhere?
+       return nullptr;
+     }
+   /* TODO: ensure that struct expression is not parsed? Actually, probably in
+    * semantic analysis. */
+ 
+   // parse loop body, which is required
+   std::unique_ptr<AST::BlockExpr> body = parse_block_expr ();
+   if (body == nullptr)
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "failed to parse block expr (loop body) of while let loop");
+       add_error (std::move (error));
+ 
+       // skip somewhere?
+       return nullptr;
+     }
+ 
+   return std::unique_ptr<AST::WhileLetLoopExpr> (new AST::WhileLetLoopExpr (
+     std::move (predicate_patterns), std::move (predicate_expr),
+     std::move (body), locus, std::move (label), std::move (outer_attrs)));
+ }
+ 
+ /* Parses a "for" iterative loop. Label is not parsed and should be parsed via
+  * parse_labelled_loop_expr, which would call this. */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::ForLoopExpr>
+ Parser<ManagedTokenSource>::parse_for_loop_expr (
+   AST::AttrVec outer_attrs, tl::optional<AST::LoopLabel> label)
+ {
+   location_t locus = UNKNOWN_LOCATION;
+   if (label)
+     locus = label->get_locus ();
+   else
+     locus = lexer.peek_token ()->get_locus ();
+   maybe_skip_token (FOR);
+ 
+   // parse pattern, which is required
+   std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
+   if (pattern == nullptr)
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "failed to parse iterator pattern in for loop");
+       add_error (std::move (error));
+ 
+       // skip somewhere?
+       return nullptr;
+     }
+ 
+   if (!skip_token (IN))
+     {
+       // skip somewhere?
+       return nullptr;
+     }
+ 
+   /* parse iterator expression, which is required - also HACK to prevent
+    * struct expr */
+   ParseRestrictions no_struct_expr;
+   no_struct_expr.can_be_struct_expr = false;
+   std::unique_ptr<AST::Expr> expr = parse_expr ({}, no_struct_expr);
+   if (expr == nullptr)
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "failed to parse iterator expression in for loop");
+       add_error (std::move (error));
+ 
+       // skip somewhere?
+       return nullptr;
+     }
+   // TODO: check to ensure this isn't struct expr? Or in semantic analysis.
+ 
+   // parse loop body, which is required
+   std::unique_ptr<AST::BlockExpr> body = parse_block_expr ();
+   if (body == nullptr)
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "failed to parse loop body block expression in for loop");
+       add_error (std::move (error));
+ 
+       // skip somewhere?
+       return nullptr;
+     }
+ 
+   return std::unique_ptr<AST::ForLoopExpr> (
+     new AST::ForLoopExpr (std::move (pattern), std::move (expr),
+ 			  std::move (body), locus, std::move (label),
+ 			  std::move (outer_attrs)));
+ }
+ 
+ // Parses a loop expression with label (any kind of loop - disambiguates).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::Expr>
+ Parser<ManagedTokenSource>::parse_labelled_loop_expr (const_TokenPtr tok,
+ 						      AST::AttrVec outer_attrs)
+ {
+   /* TODO: decide whether it should not work if there is no label, or parse it
+    * with no label at the moment, I will make it not work with no label
+    * because that's the implication. */
+ 
+   if (tok->get_id () != LIFETIME)
+     {
+       Error error (tok->get_locus (),
+ 		   "expected lifetime in labelled loop expr (to parse loop "
+ 		   "label) - found %qs",
+ 		   tok->get_token_description ());
+       add_error (std::move (error));
+ 
+       // skip?
+       return nullptr;
+     }
+ 
+   // parse loop label (required)
+   // TODO: Convert this return type to tl::expected instead of tl::optional
+   auto parsed_label = parse_loop_label (tok);
+   if (!parsed_label)
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "failed to parse loop label in labelled loop expr");
+       add_error (std::move (error));
+ 
+       // skip?
+       return nullptr;
+     }
+ 
+   auto label = parsed_label
+ 		 ? tl::optional<AST::LoopLabel> (parsed_label.value ())
+ 		 : tl::nullopt;
+ 
+   // branch on next token
+   const_TokenPtr t = lexer.peek_token ();
+   switch (t->get_id ())
+     {
+     case LOOP:
+       return parse_loop_expr (std::move (outer_attrs), std::move (label));
+     case FOR:
+       return parse_for_loop_expr (std::move (outer_attrs), std::move (label));
+     case WHILE:
+       // further disambiguate into while vs while let
+       if (lexer.peek_token (1)->get_id () == LET)
+ 	{
+ 	  return parse_while_let_loop_expr (std::move (outer_attrs),
+ 					    std::move (label));
+ 	}
+       else
+ 	{
+ 	  return parse_while_loop_expr (std::move (outer_attrs),
+ 					std::move (label));
+ 	}
+     case LEFT_CURLY:
+       return parse_block_expr (std::move (outer_attrs), std::move (label));
+     default:
+       // error
+       add_error (Error (t->get_locus (),
+ 			"unexpected token %qs when parsing labelled loop",
+ 			t->get_token_description ()));
+ 
+       // skip?
+       return nullptr;
+     }
+ }
+ 
+ // Parses a match expression.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::MatchExpr>
+ Parser<ManagedTokenSource>::parse_match_expr (AST::AttrVec outer_attrs,
+ 					      location_t pratt_parsed_loc)
+ {
+   location_t locus = pratt_parsed_loc;
+   if (locus == UNKNOWN_LOCATION)
+     {
+       locus = lexer.peek_token ()->get_locus ();
+       skip_token (MATCH_KW);
+     }
+ 
+   /* parse scrutinee expression, which is required (and HACK to prevent struct
+    * expr) */
+   ParseRestrictions no_struct_expr;
+   no_struct_expr.can_be_struct_expr = false;
+   std::unique_ptr<AST::Expr> scrutinee = parse_expr ({}, no_struct_expr);
+   if (scrutinee == nullptr)
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "failed to parse scrutinee expression in match expression");
+       add_error (std::move (error));
+ 
+       // skip somewhere?
+       return nullptr;
+     }
+   /* TODO: check for scrutinee expr not being struct expr? or do so in
+    * semantic analysis */
+ 
+   if (!skip_token (LEFT_CURLY))
+     {
+       // skip somewhere?
+       return nullptr;
+     }
+ 
+   // parse inner attributes (if they exist)
+   AST::AttrVec inner_attrs = parse_inner_attributes ();
+ 
+   // parse match arms (if they exist)
+   // std::vector<std::unique_ptr<AST::MatchCase> > match_arms;
+   std::vector<AST::MatchCase> match_arms;
+ 
+   // parse match cases
+   while (lexer.peek_token ()->get_id () != RIGHT_CURLY)
+     {
+       // parse match arm itself, which is required
+       AST::MatchArm arm = parse_match_arm ();
+       if (arm.is_error ())
+ 	{
+ 	  // TODO is this worth throwing everything away?
+ 	  Error error (lexer.peek_token ()->get_locus (),
+ 		       "failed to parse match arm in match arms");
+ 	  add_error (std::move (error));
+ 
+ 	  return nullptr;
+ 	}
+ 
+       if (!skip_token (MATCH_ARROW))
+ 	{
+ 	  // skip after somewhere?
+ 	  // TODO is returning here a good idea? or is break better?
+ 	  return nullptr;
+ 	}
+ 
+       ParseRestrictions restrictions;
+       restrictions.expr_can_be_stmt = true;
+ 
+       std::unique_ptr<AST::Expr> expr = parse_expr ({}, restrictions);
+ 
+       if (expr == nullptr)
+ 	{
+ 	  Error error (lexer.peek_token ()->get_locus (),
+ 		       "failed to parse expr in match arm in match expr");
+ 	  add_error (std::move (error));
+ 
+ 	  // skip somewhere?
+ 	  return nullptr;
+ 	}
+ 
+       bool is_expr_without_block = expr->is_expr_without_block ();
+ 
+       match_arms.push_back (AST::MatchCase (std::move (arm), std::move (expr)));
+ 
+       // handle comma presence
+       if (lexer.peek_token ()->get_id () != COMMA)
+ 	{
+ 	  if (!is_expr_without_block)
+ 	    {
+ 	      // allowed even if not final case
+ 	      continue;
+ 	    }
+ 	  else if (is_expr_without_block
+ 		   && lexer.peek_token ()->get_id () != RIGHT_CURLY)
+ 	    {
+ 	      // not allowed if not final case
+ 	      Error error (lexer.peek_token ()->get_locus (),
+ 			   "exprwithoutblock requires comma after match case "
+ 			   "expression in match arm (if not final case)");
+ 	      add_error (std::move (error));
+ 
+ 	      return nullptr;
+ 	    }
+ 	  else
+ 	    {
+ 	      // otherwise, must be final case, so fine
+ 	      break;
+ 	    }
+ 	}
+       lexer.skip_token ();
+     }
+ 
+   if (!skip_token (RIGHT_CURLY))
+     {
+       // skip somewhere?
+       return nullptr;
+     }
+ 
+   match_arms.shrink_to_fit ();
+ 
+   return std::unique_ptr<AST::MatchExpr> (
+     new AST::MatchExpr (std::move (scrutinee), std::move (match_arms),
+ 			std::move (inner_attrs), std::move (outer_attrs),
+ 			locus));
+ }
+ 
+ // Parses an async block expression.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::AsyncBlockExpr>
+ Parser<ManagedTokenSource>::parse_async_block_expr (AST::AttrVec outer_attrs)
+ {
+   location_t locus = lexer.peek_token ()->get_locus ();
+   skip_token (ASYNC);
+ 
+   // detect optional move token
+   bool has_move = false;
+   if (lexer.peek_token ()->get_id () == MOVE)
+     {
+       lexer.skip_token ();
+       has_move = true;
+     }
+ 
+   // parse block expression (required)
+   std::unique_ptr<AST::BlockExpr> block_expr = parse_block_expr ();
+   if (block_expr == nullptr)
+     {
+       Error error (
+ 	lexer.peek_token ()->get_locus (),
+ 	"failed to parse block expression of async block expression");
+       add_error (std::move (error));
+ 
+       // skip somewhere?
+       return nullptr;
+     }
+ 
+   return std::unique_ptr<AST::AsyncBlockExpr> (
+     new AST::AsyncBlockExpr (std::move (block_expr), has_move,
+ 			     std::move (outer_attrs), locus));
+ }
+ 
+ // Parses an unsafe block expression.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::UnsafeBlockExpr>
+ Parser<ManagedTokenSource>::parse_unsafe_block_expr (
+   AST::AttrVec outer_attrs, location_t pratt_parsed_loc)
+ {
+   location_t locus = pratt_parsed_loc;
+   if (locus == UNKNOWN_LOCATION)
+     {
+       locus = lexer.peek_token ()->get_locus ();
+       skip_token (UNSAFE);
+     }
+ 
+   // parse block expression (required)
+   std::unique_ptr<AST::BlockExpr> block_expr = parse_block_expr ();
+   if (block_expr == nullptr)
+     {
+       Error error (
+ 	lexer.peek_token ()->get_locus (),
+ 	"failed to parse block expression of unsafe block expression");
+       add_error (std::move (error));
+ 
+       // skip somewhere?
+       return nullptr;
+     }
+ 
+   return std::unique_ptr<AST::UnsafeBlockExpr> (
+     new AST::UnsafeBlockExpr (std::move (block_expr), std::move (outer_attrs),
+ 			      locus));
+ }
+ 
+ // Parses an array definition expression.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::ArrayExpr>
+ Parser<ManagedTokenSource>::parse_array_expr (AST::AttrVec outer_attrs,
+ 					      location_t pratt_parsed_loc)
+ {
+   location_t locus = pratt_parsed_loc;
+   if (locus == UNKNOWN_LOCATION)
+     {
+       locus = lexer.peek_token ()->get_locus ();
+       skip_token (LEFT_SQUARE);
+     }
+ 
+   // parse optional inner attributes
+   AST::AttrVec inner_attrs = parse_inner_attributes ();
+ 
+   // parse the "array elements" section, which is optional
+   if (lexer.peek_token ()->get_id () == RIGHT_SQUARE)
+     {
+       // no array elements
+       lexer.skip_token ();
+ 
+       std::vector<std::unique_ptr<AST::Expr>> exprs;
+       auto array_elems
+ 	= std::make_unique<AST::ArrayElemsValues> (std::move (exprs), locus);
+       return std::make_unique<AST::ArrayExpr> (std::move (array_elems),
+ 					       std::move (inner_attrs),
+ 					       std::move (outer_attrs), locus);
+     }
+   else
+     {
+       // should have array elements
+       // parse initial expression, which is required for either
+       std::unique_ptr<AST::Expr> initial_expr = parse_expr ();
+       if (initial_expr == nullptr)
+ 	{
+ 	  Error error (lexer.peek_token ()->get_locus (),
+ 		       "could not parse expression in array expression "
+ 		       "(even though arrayelems seems to be present)");
+ 	  add_error (std::move (error));
+ 
+ 	  // skip somewhere?
+ 	  return nullptr;
+ 	}
+ 
+       if (lexer.peek_token ()->get_id () == SEMICOLON)
+ 	{
+ 	  // copy array elems
+ 	  lexer.skip_token ();
+ 
+ 	  // parse copy amount expression (required)
+ 	  std::unique_ptr<AST::Expr> copy_amount = parse_expr ();
+ 	  if (copy_amount == nullptr)
+ 	    {
+ 	      Error error (lexer.peek_token ()->get_locus (),
+ 			   "could not parse copy amount expression in array "
+ 			   "expression (arrayelems)");
+ 	      add_error (std::move (error));
+ 
+ 	      // skip somewhere?
+ 	      return nullptr;
+ 	    }
+ 
+ 	  skip_token (RIGHT_SQUARE);
+ 
+ 	  std::unique_ptr<AST::ArrayElemsCopied> copied_array_elems (
+ 	    new AST::ArrayElemsCopied (std::move (initial_expr),
+ 				       std::move (copy_amount), locus));
+ 	  return std::unique_ptr<AST::ArrayExpr> (
+ 	    new AST::ArrayExpr (std::move (copied_array_elems),
+ 				std::move (inner_attrs),
+ 				std::move (outer_attrs), locus));
+ 	}
+       else if (lexer.peek_token ()->get_id () == RIGHT_SQUARE)
+ 	{
+ 	  // single-element array expression
+ 	  std::vector<std::unique_ptr<AST::Expr>> exprs;
+ 	  exprs.reserve (1);
+ 	  exprs.push_back (std::move (initial_expr));
+ 	  exprs.shrink_to_fit ();
+ 
+ 	  skip_token (RIGHT_SQUARE);
+ 
+ 	  std::unique_ptr<AST::ArrayElemsValues> array_elems (
+ 	    new AST::ArrayElemsValues (std::move (exprs), locus));
+ 	  return std::unique_ptr<AST::ArrayExpr> (
+ 	    new AST::ArrayExpr (std::move (array_elems),
+ 				std::move (inner_attrs),
+ 				std::move (outer_attrs), locus));
+ 	}
+       else if (lexer.peek_token ()->get_id () == COMMA)
+ 	{
+ 	  // multi-element array expression (or trailing comma)
+ 	  std::vector<std::unique_ptr<AST::Expr>> exprs;
+ 	  exprs.push_back (std::move (initial_expr));
+ 
+ 	  const_TokenPtr t = lexer.peek_token ();
+ 	  while (t->get_id () == COMMA)
+ 	    {
+ 	      lexer.skip_token ();
+ 
+ 	      // quick break if right square bracket
+ 	      if (lexer.peek_token ()->get_id () == RIGHT_SQUARE)
+ 		break;
+ 
+ 	      // parse expression (required)
+ 	      std::unique_ptr<AST::Expr> expr = parse_expr ();
+ 	      if (expr == nullptr)
+ 		{
+ 		  Error error (lexer.peek_token ()->get_locus (),
+ 			       "failed to parse element in array expression");
+ 		  add_error (std::move (error));
+ 
+ 		  // skip somewhere?
+ 		  return nullptr;
+ 		}
+ 	      exprs.push_back (std::move (expr));
+ 
+ 	      t = lexer.peek_token ();
+ 	    }
+ 
+ 	  skip_token (RIGHT_SQUARE);
+ 
+ 	  exprs.shrink_to_fit ();
+ 
+ 	  std::unique_ptr<AST::ArrayElemsValues> array_elems (
+ 	    new AST::ArrayElemsValues (std::move (exprs), locus));
+ 	  return std::unique_ptr<AST::ArrayExpr> (
+ 	    new AST::ArrayExpr (std::move (array_elems),
+ 				std::move (inner_attrs),
+ 				std::move (outer_attrs), locus));
+ 	}
+       else
+ 	{
+ 	  // error
+ 	  Error error (lexer.peek_token ()->get_locus (),
+ 		       "unexpected token %qs in array expression (arrayelems)",
+ 		       lexer.peek_token ()->get_token_description ());
+ 	  add_error (std::move (error));
+ 
+ 	  // skip somewhere?
+ 	  return nullptr;
+ 	}
+     }
+ }
+ 
+ // Parses a grouped or tuple expression (disambiguates).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::ExprWithoutBlock>
+ Parser<ManagedTokenSource>::parse_grouped_or_tuple_expr (
+   AST::AttrVec outer_attrs, location_t pratt_parsed_loc)
+ {
+   // adjustment to allow Pratt parsing to reuse function without copy-paste
+   location_t locus = pratt_parsed_loc;
+   if (locus == UNKNOWN_LOCATION)
+     {
+       locus = lexer.peek_token ()->get_locus ();
+       skip_token (LEFT_PAREN);
+     }
+ 
+   // parse optional inner attributes
+   AST::AttrVec inner_attrs = parse_inner_attributes ();
+ 
+   if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
+     {
+       // must be empty tuple
+       lexer.skip_token ();
+ 
+       // create tuple with empty tuple elems
+       return std::unique_ptr<AST::TupleExpr> (
+ 	new AST::TupleExpr (std::vector<std::unique_ptr<AST::Expr>> (),
+ 			    std::move (inner_attrs), std::move (outer_attrs),
+ 			    locus));
+     }
+ 
+   // parse first expression (required)
+   std::unique_ptr<AST::Expr> first_expr = parse_expr ();
+   if (first_expr == nullptr)
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "failed to parse expression in grouped or tuple expression");
+       add_error (std::move (error));
+ 
+       // skip after somewhere?
+       return nullptr;
+     }
+ 
+   // detect whether grouped expression with right parentheses as next token
+   if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
+     {
+       // must be grouped expr
+       lexer.skip_token ();
+ 
+       // create grouped expr
+       return std::unique_ptr<AST::GroupedExpr> (
+ 	new AST::GroupedExpr (std::move (first_expr), std::move (inner_attrs),
+ 			      std::move (outer_attrs), locus));
+     }
+   else if (lexer.peek_token ()->get_id () == COMMA)
+     {
+       // tuple expr
+       std::vector<std::unique_ptr<AST::Expr>> exprs;
+       exprs.push_back (std::move (first_expr));
+ 
+       // parse potential other tuple exprs
+       const_TokenPtr t = lexer.peek_token ();
+       while (t->get_id () == COMMA)
+ 	{
+ 	  lexer.skip_token ();
+ 
+ 	  // break out if right paren
+ 	  if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
+ 	    break;
+ 
+ 	  // parse expr, which is now required
+ 	  std::unique_ptr<AST::Expr> expr = parse_expr ();
+ 	  if (expr == nullptr)
+ 	    {
+ 	      Error error (lexer.peek_token ()->get_locus (),
+ 			   "failed to parse expr in tuple expr");
+ 	      add_error (std::move (error));
+ 
+ 	      // skip somewhere?
+ 	      return nullptr;
+ 	    }
+ 	  exprs.push_back (std::move (expr));
+ 
+ 	  t = lexer.peek_token ();
+ 	}
+ 
+       // skip right paren
+       skip_token (RIGHT_PAREN);
+ 
+       return std::unique_ptr<AST::TupleExpr> (
+ 	new AST::TupleExpr (std::move (exprs), std::move (inner_attrs),
+ 			    std::move (outer_attrs), locus));
+     }
+   else
+     {
+       // error
+       const_TokenPtr t = lexer.peek_token ();
+       Error error (t->get_locus (),
+ 		   "unexpected token %qs in grouped or tuple expression "
+ 		   "(parenthesised expression) - expected %<)%> for grouped "
+ 		   "expr and %<,%> for tuple expr",
+ 		   t->get_token_description ());
+       add_error (std::move (error));
+ 
+       // skip somewhere?
+       return nullptr;
+     }
+ }
+ 
+ // Parses a struct expression field.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::StructExprField>
+ Parser<ManagedTokenSource>::parse_struct_expr_field ()
+ {
+   AST::AttrVec outer_attrs = parse_outer_attributes ();
+   const_TokenPtr t = lexer.peek_token ();
+   switch (t->get_id ())
+     {
+     case IDENTIFIER:
+       if (lexer.peek_token (1)->get_id () == COLON)
+ 	{
+ 	  // struct expr field with identifier and expr
+ 	  Identifier ident = {t};
+ 	  lexer.skip_token (1);
+ 
+ 	  // parse expression (required)
+ 	  std::unique_ptr<AST::Expr> expr = parse_expr ();
+ 	  if (expr == nullptr)
+ 	    {
+ 	      Error error (t->get_locus (),
+ 			   "failed to parse struct expression field with "
+ 			   "identifier and expression");
+ 	      add_error (std::move (error));
+ 
+ 	      return nullptr;
+ 	    }
+ 
+ 	  return std::unique_ptr<AST::StructExprFieldIdentifierValue> (
+ 	    new AST::StructExprFieldIdentifierValue (std::move (ident),
+ 						     std::move (expr),
+ 						     std::move (outer_attrs),
+ 						     t->get_locus ()));
+ 	}
+       else
+ 	{
+ 	  // struct expr field with identifier only
+ 	  Identifier ident{t};
+ 	  lexer.skip_token ();
+ 
+ 	  return std::unique_ptr<AST::StructExprFieldIdentifier> (
+ 	    new AST::StructExprFieldIdentifier (std::move (ident),
+ 						std::move (outer_attrs),
+ 						t->get_locus ()));
+ 	}
+     case INT_LITERAL:
+       {
+ 	// parse tuple index field
+ 	int index = atoi (t->get_str ().c_str ());
+ 	lexer.skip_token ();
+ 
+ 	if (!skip_token (COLON))
+ 	  {
+ 	    // skip somewhere?
+ 	    return nullptr;
+ 	  }
+ 
+ 	// parse field expression (required)
+ 	std::unique_ptr<AST::Expr> expr = parse_expr ();
+ 	if (expr == nullptr)
+ 	  {
+ 	    Error error (t->get_locus (),
+ 			 "failed to parse expr in struct (or enum) expr "
+ 			 "field with tuple index");
+ 	    add_error (std::move (error));
+ 
+ 	    return nullptr;
+ 	  }
+ 
+ 	return std::unique_ptr<AST::StructExprFieldIndexValue> (
+ 	  new AST::StructExprFieldIndexValue (index, std::move (expr),
+ 					      std::move (outer_attrs),
+ 					      t->get_locus ()));
+       }
+     case DOT_DOT:
+       /* this is a struct base and can't be parsed here, so just return
+        * nothing without erroring */
+ 
+       return nullptr;
+     default:
+       add_error (
+ 	Error (t->get_locus (),
+ 	       "unrecognised token %qs as first token of struct expr field - "
+ 	       "expected identifier or integer literal",
+ 	       t->get_token_description ()));
+ 
+       return nullptr;
+     }
+ }
+ 
+ /* Pratt parser impl of parse_expr. FIXME: this is only provisional and
+  * probably will be changed. */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::Expr>
+ Parser<ManagedTokenSource>::parse_expr (int right_binding_power,
+ 					AST::AttrVec outer_attrs,
+ 					ParseRestrictions restrictions)
+ {
+   const_TokenPtr current_token = lexer.peek_token ();
+   // Special hack because we are allowed to return nullptr, in that case we
+   // don't want to skip the token, since we don't actually parse it. But if
+   // null isn't allowed it indicates an error, and we want to skip past that.
+   // So return early if it is one of the tokens that ends an expression
+   // (or at least cannot start a new expression).
+   if (restrictions.expr_can_be_null)
+     {
+       TokenId id = current_token->get_id ();
+       if (id == SEMICOLON || id == RIGHT_PAREN || id == RIGHT_CURLY
+ 	  || id == RIGHT_SQUARE || id == COMMA || id == LEFT_CURLY)
+ 	return nullptr;
+     }
+ 
+   ParseRestrictions null_denotation_restrictions = restrictions;
+   null_denotation_restrictions.expr_can_be_stmt = false;
+ 
+   // parse null denotation (unary part of expression)
+   std::unique_ptr<AST::Expr> expr
+     = null_denotation ({}, null_denotation_restrictions);
+   if (expr == nullptr)
+     return nullptr;
+ 
+   return left_denotations (std::move (expr), right_binding_power,
+ 			   std::move (outer_attrs), restrictions);
+ }
+ 
+ // Parse expression with lowest left binding power.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::Expr>
+ Parser<ManagedTokenSource>::parse_expr (AST::AttrVec outer_attrs,
+ 					ParseRestrictions restrictions)
+ {
+   return parse_expr (LBP_LOWEST, std::move (outer_attrs), restrictions);
+ }
+ 
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::Expr>
+ Parser<ManagedTokenSource>::left_denotations (std::unique_ptr<AST::Expr> expr,
+ 					      int right_binding_power,
+ 					      AST::AttrVec outer_attrs,
+ 					      ParseRestrictions restrictions)
+ {
+   if (expr == nullptr)
+     {
+       // DEBUG
+       rust_debug ("null denotation is null; returning null for parse_expr");
+       return nullptr;
+     }
+ 
+   const_TokenPtr current_token = lexer.peek_token ();
+ 
+   if (restrictions.expr_can_be_stmt && !expr->is_expr_without_block ()
+       && current_token->get_id () != DOT
+       && current_token->get_id () != QUESTION_MARK)
+     {
+       rust_debug ("statement expression with block");
+       expr->set_outer_attrs (std::move (outer_attrs));
+       return expr;
+     }
+ 
+   restrictions.expr_can_be_stmt = false;
+ 
+   // stop parsing if find lower priority token - parse higher priority first
+   while (right_binding_power < left_binding_power (current_token))
+     {
+       lexer.skip_token ();
+ 
+       // FIXME attributes should generally be applied to the null denotation.
+       expr = left_denotation (current_token, std::move (expr),
+ 			      std::move (outer_attrs), restrictions);
+ 
+       if (expr == nullptr)
+ 	{
+ 	  // DEBUG
+ 	  rust_debug ("left denotation is null; returning null for parse_expr");
+ 
+ 	  return nullptr;
+ 	}
+ 
+       current_token = lexer.peek_token ();
+     }
+ 
+   return expr;
+ }
+ 
+ /* Determines action to take when finding token at beginning of expression. */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::Expr>
+ Parser<ManagedTokenSource>::null_denotation (AST::AttrVec outer_attrs,
+ 					     ParseRestrictions restrictions)
+ {
+   /* note: tok is previous character in input stream, not current one, as
+    * parse_expr skips it before passing it in */
+ 
+   /* as a Pratt parser (which works by decomposing expressions into a null
+    * denotation and then a left denotation), null denotations handle primaries
+    * and unary operands (but only prefix unary operands) */
+ 
+   auto tok = lexer.peek_token ();
+ 
+   switch (tok->get_id ())
+     {
+     case IDENTIFIER:
+     case SELF:
+     case SELF_ALIAS:
+     case DOLLAR_SIGN:
+     case CRATE:
+     case SUPER:
+     case SCOPE_RESOLUTION:
+       {
+ 	// DEBUG
+ 	rust_debug ("beginning null denotation identifier handling");
+ 
+ 	/* best option: parse as path, then extract identifier, macro,
+ 	 * struct/enum, or just path info from it */
+ 	AST::PathInExpression path = parse_path_in_expression ();
+ 
+ 	return null_denotation_path (std::move (path), std::move (outer_attrs),
+ 				     restrictions);
+       }
+     default:
+       if (tok->get_id () == LEFT_SHIFT)
+ 	{
+ 	  lexer.split_current_token (LEFT_ANGLE, LEFT_ANGLE);
+ 	  tok = lexer.peek_token ();
+ 	}
+ 
+       lexer.skip_token ();
+       return null_denotation_not_path (std::move (tok), std::move (outer_attrs),
+ 				       restrictions);
+     }
+ }
+ 
+ // Handling of expresions that start with a path for `null_denotation`.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::Expr>
+ Parser<ManagedTokenSource>::null_denotation_path (
+   AST::PathInExpression path, AST::AttrVec outer_attrs,
+   ParseRestrictions restrictions)
+ {
+   rust_debug ("parsing null denotation after path");
+ 
+   // HACK: always make "self" by itself a path (regardless of next
+   // tokens)
+   if (path.is_single_segment () && path.get_segments ()[0].is_lower_self_seg ())
+     {
+       // HACK: add outer attrs to path
+       path.set_outer_attrs (std::move (outer_attrs));
+       return std::unique_ptr<AST::PathInExpression> (
+ 	new AST::PathInExpression (std::move (path)));
+     }
+ 
+   // branch on next token
+   const_TokenPtr t = lexer.peek_token ();
+   switch (t->get_id ())
+     {
+     case EXCLAM:
+       // macro
+       return parse_macro_invocation_partial (std::move (path),
+ 					     std::move (outer_attrs));
+     case LEFT_CURLY:
+       {
+ 	bool not_a_block = lexer.peek_token (1)->get_id () == IDENTIFIER
+ 			   && (lexer.peek_token (2)->get_id () == COMMA
+ 			       || (lexer.peek_token (2)->get_id () == COLON
+ 				   && (lexer.peek_token (4)->get_id () == COMMA
+ 				       || !Parse::Utils::can_tok_start_type (
+ 					 lexer.peek_token (3)->get_id ()))));
+ 
+ 	/* definitely not a block:
+ 	 *  path '{' ident ','
+ 	 *  path '{' ident ':' [anything] ','
+ 	 *  path '{' ident ':' [not a type]
+ 	 * otherwise, assume block expr and thus path */
+ 	// DEBUG
+ 	rust_debug ("values of lookahead: '%s' '%s' '%s' '%s' ",
+ 		    lexer.peek_token (1)->get_token_description (),
+ 		    lexer.peek_token (2)->get_token_description (),
+ 		    lexer.peek_token (3)->get_token_description (),
+ 		    lexer.peek_token (4)->get_token_description ());
+ 
+ 	rust_debug ("can be struct expr: '%s', not a block: '%s'",
+ 		    restrictions.can_be_struct_expr ? "true" : "false",
+ 		    not_a_block ? "true" : "false");
+ 
+ 	// struct/enum expr struct
+ 	if (!restrictions.can_be_struct_expr && !not_a_block)
+ 	  {
+ 	    // HACK: add outer attrs to path
+ 	    path.set_outer_attrs (std::move (outer_attrs));
+ 	    return std::unique_ptr<AST::PathInExpression> (
+ 	      new AST::PathInExpression (std::move (path)));
+ 	  }
+ 	return parse_struct_expr_struct_partial (std::move (path),
+ 						 std::move (outer_attrs));
+       }
+     case LEFT_PAREN:
+       // struct/enum expr tuple
+       if (!restrictions.can_be_struct_expr)
+ 	{
+ 	  // assume path is returned
+ 	  // HACK: add outer attributes to path
+ 	  path.set_outer_attrs (std::move (outer_attrs));
+ 	  return std::unique_ptr<AST::PathInExpression> (
+ 	    new AST::PathInExpression (std::move (path)));
+ 	}
+       return parse_struct_expr_tuple_partial (std::move (path),
+ 					      std::move (outer_attrs));
+     default:
+       // assume path is returned if not single segment
+       if (path.is_single_segment ())
+ 	{
+ 	  // FIXME: This should probably be returned as a path.
+ 	  /* HACK: may have to become permanent, but this is my current
+ 	   * identifier expression */
+ 	  return std::unique_ptr<AST::IdentifierExpr> (new AST::IdentifierExpr (
+ 	    path.get_segments ()[0].get_ident_segment ().as_string (), {},
+ 	    path.get_locus ()));
+ 	}
+       // HACK: add outer attrs to path
+       path.set_outer_attrs (std::move (outer_attrs));
+       return std::unique_ptr<AST::PathInExpression> (
+ 	new AST::PathInExpression (std::move (path)));
+     }
+   rust_unreachable ();
+ }
+ 
+ // Handling of expresions that do not start with a path for `null_denotation`.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::Expr>
+ Parser<ManagedTokenSource>::null_denotation_not_path (
+   const_TokenPtr tok, AST::AttrVec outer_attrs, ParseRestrictions restrictions)
+ {
+   switch (tok->get_id ())
+     {
+     // FIXME: Handle in null_denotation_path?
+     case LEFT_SHIFT:
+     case LEFT_ANGLE:
+       {
+ 	// qualified path
+ 	// HACK: add outer attrs to path
+ 	AST::QualifiedPathInExpression path
+ 	  = parse_qualified_path_in_expression (tok->get_locus ());
+ 	path.set_outer_attrs (std::move (outer_attrs));
+ 	return std::unique_ptr<AST::QualifiedPathInExpression> (
+ 	  new AST::QualifiedPathInExpression (std::move (path)));
+       }
+     // FIXME: delegate to parse_literal_expr instead? would have to rejig
+     // tokens and whatever.
+     // FIXME: for literal exprs, outer attrs should be passed in, and later
+     // error if it does not make up the entire statement.
+     case INT_LITERAL:
+       // we should check the range, but ignore for now
+       // encode as int?
+       return std::unique_ptr<AST::LiteralExpr> (
+ 	new AST::LiteralExpr (tok->get_str (), AST::Literal::INT,
+ 			      tok->get_type_hint (), {}, tok->get_locus ()));
+     case FLOAT_LITERAL:
+       // encode as float?
+       return std::unique_ptr<AST::LiteralExpr> (
+ 	new AST::LiteralExpr (tok->get_str (), AST::Literal::FLOAT,
+ 			      tok->get_type_hint (), {}, tok->get_locus ()));
+     case STRING_LITERAL:
+       return std::unique_ptr<AST::LiteralExpr> (
+ 	new AST::LiteralExpr (tok->get_str (), AST::Literal::STRING,
+ 			      tok->get_type_hint (), {}, tok->get_locus ()));
+     case BYTE_STRING_LITERAL:
+       return std::unique_ptr<AST::LiteralExpr> (
+ 	new AST::LiteralExpr (tok->get_str (), AST::Literal::BYTE_STRING,
+ 			      tok->get_type_hint (), {}, tok->get_locus ()));
+     case RAW_STRING_LITERAL:
+       return std::unique_ptr<AST::LiteralExpr> (
+ 	new AST::LiteralExpr (tok->get_str (), AST::Literal::RAW_STRING,
+ 			      tok->get_type_hint (), {}, tok->get_locus ()));
+     case CHAR_LITERAL:
+       return std::unique_ptr<AST::LiteralExpr> (
+ 	new AST::LiteralExpr (tok->get_str (), AST::Literal::CHAR,
+ 			      tok->get_type_hint (), {}, tok->get_locus ()));
+     case BYTE_CHAR_LITERAL:
+       return std::unique_ptr<AST::LiteralExpr> (
+ 	new AST::LiteralExpr (tok->get_str (), AST::Literal::BYTE,
+ 			      tok->get_type_hint (), {}, tok->get_locus ()));
+     case TRUE_LITERAL:
+       return std::unique_ptr<AST::LiteralExpr> (
+ 	new AST::LiteralExpr (Values::Keywords::TRUE_LITERAL,
+ 			      AST::Literal::BOOL, tok->get_type_hint (), {},
+ 			      tok->get_locus ()));
+     case FALSE_LITERAL:
+       return std::unique_ptr<AST::LiteralExpr> (
+ 	new AST::LiteralExpr (Values::Keywords::FALSE_LITERAL,
+ 			      AST::Literal::BOOL, tok->get_type_hint (), {},
+ 			      tok->get_locus ()));
+     case LEFT_PAREN:
+       return parse_grouped_or_tuple_expr (std::move (outer_attrs),
+ 					  tok->get_locus ());
+ 
+     /*case PLUS: { // unary plus operator
+ 	// invoke parse_expr recursively with appropriate priority, etc. for
+     below AST::Expr* expr = parse_expr(LBP_UNARY_PLUS);
+ 
+ 	if (expr == nullptr)
+ 	    return nullptr;
+ 	// can only apply to integer and float expressions
+ 	if (expr->get_type() != integer_type_node || expr->get_type() !=
+     float_type_node) { rust_error_at(tok->get_locus(), "operand of unary
+     plus must be int or float but it is %s", print_type(expr->get_type()));
+     return nullptr;
+ 	}
+ 
+ 	return Tree(expr, tok->get_locus());
+     }*/
+     // Rust has no unary plus operator
+     case MINUS:
+       { // unary minus
+ 	ParseRestrictions entered_from_unary;
+ 	entered_from_unary.entered_from_unary = true;
+ 	if (!restrictions.can_be_struct_expr)
+ 	  entered_from_unary.can_be_struct_expr = false;
+ 	std::unique_ptr<AST::Expr> expr
+ 	  = parse_expr (LBP_UNARY_MINUS, {}, entered_from_unary);
+ 
+ 	if (expr == nullptr)
+ 	  return nullptr;
+ 	// can only apply to integer and float expressions
+ 	/*if (expr.get_type() != integer_type_node || expr.get_type() !=
+ 	float_type_node) { rust_error_at(tok->get_locus(), "operand of unary
+ 	minus must be int or float but it is %s",
+ 	print_type(expr.get_type())); return Tree::error();
+ 	}*/
+ 	/* FIXME: when implemented the "get type" method on expr, ensure it is
+ 	 * int or float type (except unsigned int). Actually, this would
+ 	 * probably have to be done in semantic analysis (as type checking).
+ 	 */
+ 
+ 	/* FIXME: allow outer attributes on these expressions by having an
+ 	 * outer attrs parameter in function*/
+ 	return std::unique_ptr<AST::NegationExpr> (
+ 	  new AST::NegationExpr (std::move (expr), NegationOperator::NEGATE,
+ 				 std::move (outer_attrs), tok->get_locus ()));
+       }
+     case EXCLAM:
+       { // logical or bitwise not
+ 	ParseRestrictions entered_from_unary;
+ 	entered_from_unary.entered_from_unary = true;
+ 	if (!restrictions.can_be_struct_expr)
+ 	  entered_from_unary.can_be_struct_expr = false;
+ 	std::unique_ptr<AST::Expr> expr
+ 	  = parse_expr (LBP_UNARY_EXCLAM, {}, entered_from_unary);
+ 
+ 	if (expr == nullptr)
+ 	  return nullptr;
+ 	// can only apply to boolean expressions
+ 	/*if (expr.get_type() != boolean_type_node) {
+ 	    rust_error_at(tok->get_locus(),
+ 	      "operand of logical not must be a boolean but it is %s",
+ 	      print_type(expr.get_type()));
+ 	    return Tree::error();
+ 	}*/
+ 	/* FIXME: type checking for boolean or integer expressions in semantic
+ 	 * analysis */
+ 
+ 	// FIXME: allow outer attributes on these expressions
+ 	return std::unique_ptr<AST::NegationExpr> (
+ 	  new AST::NegationExpr (std::move (expr), NegationOperator::NOT,
+ 				 std::move (outer_attrs), tok->get_locus ()));
+       }
+     case ASTERISK:
+       {
+ 	/* pointer dereference only - HACK: as struct expressions should
+ 	 * always be value expressions, cannot be dereferenced */
+ 	ParseRestrictions entered_from_unary;
+ 	entered_from_unary.entered_from_unary = true;
+ 	entered_from_unary.can_be_struct_expr = false;
+ 	std::unique_ptr<AST::Expr> expr
+ 	  = parse_expr (LBP_UNARY_ASTERISK, {}, entered_from_unary);
+ 	// FIXME: allow outer attributes on expression
+ 	return std::unique_ptr<AST::DereferenceExpr> (
+ 	  new AST::DereferenceExpr (std::move (expr), std::move (outer_attrs),
+ 				    tok->get_locus ()));
+       }
+     case AMP:
+       {
+ 	// (single) "borrow" expression - shared (mutable) or immutable
+ 	std::unique_ptr<AST::Expr> expr = nullptr;
+ 	Mutability mutability = Mutability::Imm;
+ 	bool raw_borrow = false;
+ 
+ 	ParseRestrictions entered_from_unary;
+ 	entered_from_unary.entered_from_unary = true;
+ 	if (!restrictions.can_be_struct_expr)
+ 	  entered_from_unary.can_be_struct_expr = false;
+ 
+ 	auto is_mutability = [] (const_TokenPtr token) {
+ 	  return token->get_id () == CONST || token->get_id () == MUT;
+ 	};
+ 
+ 	auto t = lexer.peek_token ();
+ 	// Weak raw keyword, we look (1) ahead and treat it as an identifier if
+ 	// there is no mut nor const.
+ 	if (t->get_id () == IDENTIFIER
+ 	    && t->get_str () == Values::WeakKeywords::RAW
+ 	    && is_mutability (lexer.peek_token (1)))
+ 	  {
+ 	    lexer.skip_token ();
+ 	    switch (lexer.peek_token ()->get_id ())
+ 	      {
+ 	      case MUT:
+ 		mutability = Mutability::Mut;
+ 		break;
+ 	      case CONST:
+ 		mutability = Mutability::Imm;
+ 		break;
+ 	      default:
+ 		rust_error_at (lexer.peek_token ()->get_locus (),
+ 			       "raw borrow should be either const or mut");
+ 	      }
+ 	    lexer.skip_token ();
+ 	    expr = parse_expr (LBP_UNARY_AMP_MUT, {}, entered_from_unary);
+ 	    raw_borrow = true;
+ 	  }
+ 	else if (t->get_id () == MUT)
+ 	  {
+ 	    lexer.skip_token ();
+ 	    expr = parse_expr (LBP_UNARY_AMP_MUT, {}, entered_from_unary);
+ 	    mutability = Mutability::Mut;
+ 	    raw_borrow = false;
+ 	  }
+ 	else
+ 	  {
+ 	    expr = parse_expr (LBP_UNARY_AMP, {}, entered_from_unary);
+ 	    raw_borrow = false;
+ 	  }
+ 
+ 	// FIXME: allow outer attributes on expression
+ 	return std::unique_ptr<AST::BorrowExpr> (
+ 	  new AST::BorrowExpr (std::move (expr), mutability, raw_borrow, false,
+ 			       std::move (outer_attrs), tok->get_locus ()));
+       }
+     case LOGICAL_AND:
+       {
+ 	// (double) "borrow" expression - shared (mutable) or immutable
+ 	std::unique_ptr<AST::Expr> expr = nullptr;
+ 	Mutability mutability = Mutability::Imm;
+ 
+ 	ParseRestrictions entered_from_unary;
+ 	entered_from_unary.entered_from_unary = true;
+ 
+ 	if (lexer.peek_token ()->get_id () == MUT)
+ 	  {
+ 	    lexer.skip_token ();
+ 	    expr = parse_expr (LBP_UNARY_AMP_MUT, {}, entered_from_unary);
+ 	    mutability = Mutability::Mut;
+ 	  }
+ 	else
+ 	  {
+ 	    expr = parse_expr (LBP_UNARY_AMP, {}, entered_from_unary);
+ 	    mutability = Mutability::Imm;
+ 	  }
+ 
+ 	// FIXME: allow outer attributes on expression
+ 	return std::unique_ptr<AST::BorrowExpr> (
+ 	  new AST::BorrowExpr (std::move (expr), mutability, false, true,
+ 			       std::move (outer_attrs), tok->get_locus ()));
+       }
+     case OR:
+     case PIPE:
+     case MOVE:
+       // closure expression
+       return parse_closure_expr_pratt (tok, std::move (outer_attrs));
+     case DOT_DOT:
+       // either "range to" or "range full" expressions
+       return parse_nud_range_exclusive_expr (tok, std::move (outer_attrs));
+     case DOT_DOT_EQ:
+       // range to inclusive expr
+       return parse_range_to_inclusive_expr (tok, std::move (outer_attrs));
+     case RETURN_KW:
+       // FIXME: is this really a null denotation expression?
+       return parse_return_expr (std::move (outer_attrs), tok->get_locus ());
+     case TRY:
+       // FIXME: is this really a null denotation expression?
+       return parse_try_expr (std::move (outer_attrs), tok->get_locus ());
+     case BREAK:
+       // FIXME: is this really a null denotation expression?
+       return parse_break_expr (std::move (outer_attrs), tok->get_locus ());
+     case CONTINUE:
+       return parse_continue_expr (std::move (outer_attrs), tok->get_locus ());
+     case LEFT_CURLY:
+       // ok - this is an expression with block for once.
+       return parse_block_expr (std::move (outer_attrs), tl::nullopt,
+ 			       tok->get_locus ());
+     case IF:
+       // if or if let, so more lookahead to find out
+       if (lexer.peek_token ()->get_id () == LET)
+ 	{
+ 	  // if let expr
+ 	  return parse_if_let_expr (std::move (outer_attrs), tok->get_locus ());
+ 	}
+       else
+ 	{
+ 	  // if expr
+ 	  return parse_if_expr (std::move (outer_attrs), tok->get_locus ());
+ 	}
+     case LIFETIME:
+       return parse_labelled_loop_expr (tok, std::move (outer_attrs));
+     case LOOP:
+       return parse_loop_expr (std::move (outer_attrs), tl::nullopt,
+ 			      tok->get_locus ());
+     case WHILE:
+       if (lexer.peek_token ()->get_id () == LET)
+ 	{
+ 	  return parse_while_let_loop_expr (std::move (outer_attrs));
+ 	}
+       else
+ 	{
+ 	  return parse_while_loop_expr (std::move (outer_attrs), tl::nullopt,
+ 					tok->get_locus ());
+ 	}
+     case FOR:
+       return parse_for_loop_expr (std::move (outer_attrs), tl::nullopt);
+     case MATCH_KW:
+       // also an expression with block
+       return parse_match_expr (std::move (outer_attrs), tok->get_locus ());
+     case LEFT_SQUARE:
+       // array definition expr (not indexing)
+       return parse_array_expr (std::move (outer_attrs), tok->get_locus ());
+     case UNSAFE:
+       return parse_unsafe_block_expr (std::move (outer_attrs),
+ 				      tok->get_locus ());
+     case BOX:
+       return parse_box_expr (std::move (outer_attrs), tok->get_locus ());
+     case UNDERSCORE:
+       add_error (
+ 	Error (tok->get_locus (),
+ 	       "use of %qs is not allowed on the right-side of an assignment",
+ 	       tok->get_token_description ()));
+       return nullptr;
+     case CONST:
+       return parse_const_block_expr (std::move (outer_attrs),
+ 				     tok->get_locus ());
+     default:
+       if (!restrictions.expr_can_be_null)
+ 	add_error (Error (tok->get_locus (),
+ 			  "found unexpected token %qs in null denotation",
+ 			  tok->get_token_description ()));
+       return nullptr;
+     }
+ }
+ 
+ /* Called for each token that can appear in infix (between) position. Can be
+  * operators or other punctuation. Returns a function pointer to member
+  * function that implements the left denotation for the token given. */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::Expr>
+ Parser<ManagedTokenSource>::left_denotation (const_TokenPtr tok,
+ 					     std::unique_ptr<AST::Expr> left,
+ 					     AST::AttrVec outer_attrs,
+ 					     ParseRestrictions restrictions)
+ {
+   // Token passed in has already been skipped, so peek gives "next" token
+   switch (tok->get_id ())
+     {
+     // FIXME: allow for outer attributes to be applied
+     case QUESTION_MARK:
+       {
+ 	location_t left_locus = left->get_locus ();
+ 	// error propagation expression - unary postfix
+ 	return std::unique_ptr<AST::ErrorPropagationExpr> (
+ 	  new AST::ErrorPropagationExpr (std::move (left),
+ 					 std::move (outer_attrs), left_locus));
+       }
+     case PLUS:
+       // sum expression - binary infix
+       /*return parse_binary_plus_expr (tok, std::move (left),
+ 				     std::move (outer_attrs), restrictions);*/
+       return parse_arithmetic_or_logical_expr (tok, std::move (left),
+ 					       std::move (outer_attrs),
+ 					       ArithmeticOrLogicalOperator::ADD,
+ 					       restrictions);
+     case MINUS:
+       // difference expression - binary infix
+       /*return parse_binary_minus_expr (tok, std::move (left),
+ 				      std::move (outer_attrs),
+ 	 restrictions);*/
+       return parse_arithmetic_or_logical_expr (
+ 	tok, std::move (left), std::move (outer_attrs),
+ 	ArithmeticOrLogicalOperator::SUBTRACT, restrictions);
+     case ASTERISK:
+       // product expression - binary infix
+       /*return parse_binary_mult_expr (tok, std::move (left),
+ 				     std::move (outer_attrs), restrictions);*/
+       return parse_arithmetic_or_logical_expr (
+ 	tok, std::move (left), std::move (outer_attrs),
+ 	ArithmeticOrLogicalOperator::MULTIPLY, restrictions);
+     case DIV:
+       // quotient expression - binary infix
+       /*return parse_binary_div_expr (tok, std::move (left),
+ 				    std::move (outer_attrs), restrictions);*/
+       return parse_arithmetic_or_logical_expr (
+ 	tok, std::move (left), std::move (outer_attrs),
+ 	ArithmeticOrLogicalOperator::DIVIDE, restrictions);
+     case PERCENT:
+       // modulo expression - binary infix
+       /*return parse_binary_mod_expr (tok, std::move (left),
+ 				    std::move (outer_attrs), restrictions);*/
+       return parse_arithmetic_or_logical_expr (
+ 	tok, std::move (left), std::move (outer_attrs),
+ 	ArithmeticOrLogicalOperator::MODULUS, restrictions);
+     case AMP:
+       // logical or bitwise and expression - binary infix
+       /*return parse_bitwise_and_expr (tok, std::move (left),
+ 				     std::move (outer_attrs), restrictions);*/
+       return parse_arithmetic_or_logical_expr (
+ 	tok, std::move (left), std::move (outer_attrs),
+ 	ArithmeticOrLogicalOperator::BITWISE_AND, restrictions);
+     case PIPE:
+       // logical or bitwise or expression - binary infix
+       /*return parse_bitwise_or_expr (tok, std::move (left),
+ 				    std::move (outer_attrs), restrictions);*/
+       return parse_arithmetic_or_logical_expr (
+ 	tok, std::move (left), std::move (outer_attrs),
+ 	ArithmeticOrLogicalOperator::BITWISE_OR, restrictions);
+     case CARET:
+       // logical or bitwise xor expression - binary infix
+       /*return parse_bitwise_xor_expr (tok, std::move (left),
+ 				     std::move (outer_attrs), restrictions);*/
+       return parse_arithmetic_or_logical_expr (
+ 	tok, std::move (left), std::move (outer_attrs),
+ 	ArithmeticOrLogicalOperator::BITWISE_XOR, restrictions);
+     case LEFT_SHIFT:
+       // left shift expression - binary infix
+       /*return parse_left_shift_expr (tok, std::move (left),
+ 				    std::move (outer_attrs), restrictions);*/
+       return parse_arithmetic_or_logical_expr (
+ 	tok, std::move (left), std::move (outer_attrs),
+ 	ArithmeticOrLogicalOperator::LEFT_SHIFT, restrictions);
+     case RIGHT_SHIFT:
+       // right shift expression - binary infix
+       /*return parse_right_shift_expr (tok, std::move (left),
+ 				     std::move (outer_attrs), restrictions);*/
+       return parse_arithmetic_or_logical_expr (
+ 	tok, std::move (left), std::move (outer_attrs),
+ 	ArithmeticOrLogicalOperator::RIGHT_SHIFT, restrictions);
+     case EQUAL_EQUAL:
+       // equal to expression - binary infix (no associativity)
+       /*return parse_binary_equal_expr (tok, std::move (left),
+ 				      std::move (outer_attrs),
+ 	 restrictions);*/
+       return parse_comparison_expr (tok, std::move (left),
+ 				    std::move (outer_attrs),
+ 				    ComparisonOperator::EQUAL, restrictions);
+     case NOT_EQUAL:
+       // not equal to expression - binary infix (no associativity)
+       /*return parse_binary_not_equal_expr (tok, std::move (left),
+ 					  std::move (outer_attrs),
+ 					  restrictions);*/
+       return parse_comparison_expr (tok, std::move (left),
+ 				    std::move (outer_attrs),
+ 				    ComparisonOperator::NOT_EQUAL,
+ 				    restrictions);
+     case RIGHT_ANGLE:
+       // greater than expression - binary infix (no associativity)
+       /*return parse_binary_greater_than_expr (tok, std::move (left),
+ 					     std::move (outer_attrs),
+ 					     restrictions);*/
+       return parse_comparison_expr (tok, std::move (left),
+ 				    std::move (outer_attrs),
+ 				    ComparisonOperator::GREATER_THAN,
+ 				    restrictions);
+     case LEFT_ANGLE:
+       // less than expression - binary infix (no associativity)
+       /*return parse_binary_less_than_expr (tok, std::move (left),
+ 					  std::move (outer_attrs),
+ 					  restrictions);*/
+       return parse_comparison_expr (tok, std::move (left),
+ 				    std::move (outer_attrs),
+ 				    ComparisonOperator::LESS_THAN,
+ 				    restrictions);
+     case GREATER_OR_EQUAL:
+       // greater than or equal to expression - binary infix (no associativity)
+       /*return parse_binary_greater_equal_expr (tok, std::move (left),
+ 					      std::move (outer_attrs),
+ 					      restrictions);*/
+       return parse_comparison_expr (tok, std::move (left),
+ 				    std::move (outer_attrs),
+ 				    ComparisonOperator::GREATER_OR_EQUAL,
+ 				    restrictions);
+     case LESS_OR_EQUAL:
+       // less than or equal to expression - binary infix (no associativity)
+       /*return parse_binary_less_equal_expr (tok, std::move (left),
+ 					   std::move (outer_attrs),
+ 					   restrictions);*/
+       return parse_comparison_expr (tok, std::move (left),
+ 				    std::move (outer_attrs),
+ 				    ComparisonOperator::LESS_OR_EQUAL,
+ 				    restrictions);
+     case OR:
+       // lazy logical or expression - binary infix
+       return parse_lazy_or_expr (tok, std::move (left), std::move (outer_attrs),
+ 				 restrictions);
+     case LOGICAL_AND:
+       // lazy logical and expression - binary infix
+       return parse_lazy_and_expr (tok, std::move (left),
+ 				  std::move (outer_attrs), restrictions);
+     case AS:
+       /* type cast expression - kind of binary infix (RHS is actually a
+        * TypeNoBounds) */
+       return parse_type_cast_expr (tok, std::move (left),
+ 				   std::move (outer_attrs), restrictions);
+     case EQUAL:
+       // assignment expression - binary infix (note right-to-left
+       // associativity)
+       return parse_assig_expr (tok, std::move (left), std::move (outer_attrs),
+ 			       restrictions);
+     case PLUS_EQ:
+       /* plus-assignment expression - binary infix (note right-to-left
+        * associativity) */
+       /*return parse_plus_assig_expr (tok, std::move (left),
+ 				    std::move (outer_attrs), restrictions);*/
+       return parse_compound_assignment_expr (tok, std::move (left),
+ 					     std::move (outer_attrs),
+ 					     CompoundAssignmentOperator::ADD,
+ 					     restrictions);
+     case MINUS_EQ:
+       /* minus-assignment expression - binary infix (note right-to-left
+        * associativity) */
+       /*return parse_minus_assig_expr (tok, std::move (left),
+ 				     std::move (outer_attrs), restrictions);*/
+       return parse_compound_assignment_expr (
+ 	tok, std::move (left), std::move (outer_attrs),
+ 	CompoundAssignmentOperator::SUBTRACT, restrictions);
+     case ASTERISK_EQ:
+       /* multiply-assignment expression - binary infix (note right-to-left
+        * associativity) */
+       /*return parse_mult_assig_expr (tok, std::move (left),
+ 				    std::move (outer_attrs), restrictions);*/
+       return parse_compound_assignment_expr (
+ 	tok, std::move (left), std::move (outer_attrs),
+ 	CompoundAssignmentOperator::MULTIPLY, restrictions);
+     case DIV_EQ:
+       /* division-assignment expression - binary infix (note right-to-left
+        * associativity) */
+       /*return parse_div_assig_expr (tok, std::move (left),
+ 				   std::move (outer_attrs), restrictions);*/
+       return parse_compound_assignment_expr (tok, std::move (left),
+ 					     std::move (outer_attrs),
+ 					     CompoundAssignmentOperator::DIVIDE,
+ 					     restrictions);
+     case PERCENT_EQ:
+       /* modulo-assignment expression - binary infix (note right-to-left
+        * associativity) */
+       /*return parse_mod_assig_expr (tok, std::move (left),
+ 				   std::move (outer_attrs), restrictions);*/
+       return parse_compound_assignment_expr (
+ 	tok, std::move (left), std::move (outer_attrs),
+ 	CompoundAssignmentOperator::MODULUS, restrictions);
+     case AMP_EQ:
+       /* bitwise and-assignment expression - binary infix (note right-to-left
+        * associativity) */
+       /*return parse_and_assig_expr (tok, std::move (left),
+ 				   std::move (outer_attrs), restrictions);*/
+       return parse_compound_assignment_expr (
+ 	tok, std::move (left), std::move (outer_attrs),
+ 	CompoundAssignmentOperator::BITWISE_AND, restrictions);
+     case PIPE_EQ:
+       /* bitwise or-assignment expression - binary infix (note right-to-left
+        * associativity) */
+       /*return parse_or_assig_expr (tok, std::move (left),
+ 				  std::move (outer_attrs), restrictions);*/
+       return parse_compound_assignment_expr (
+ 	tok, std::move (left), std::move (outer_attrs),
+ 	CompoundAssignmentOperator::BITWISE_OR, restrictions);
+     case CARET_EQ:
+       /* bitwise xor-assignment expression - binary infix (note right-to-left
+        * associativity) */
+       /*return parse_xor_assig_expr (tok, std::move (left),
+ 				   std::move (outer_attrs), restrictions);*/
+       return parse_compound_assignment_expr (
+ 	tok, std::move (left), std::move (outer_attrs),
+ 	CompoundAssignmentOperator::BITWISE_XOR, restrictions);
+     case LEFT_SHIFT_EQ:
+       /* left shift-assignment expression - binary infix (note right-to-left
+        * associativity) */
+       /*return parse_left_shift_assig_expr (tok, std::move (left),
+ 					  std::move (outer_attrs),
+ 					  restrictions);*/
+       return parse_compound_assignment_expr (
+ 	tok, std::move (left), std::move (outer_attrs),
+ 	CompoundAssignmentOperator::LEFT_SHIFT, restrictions);
+     case RIGHT_SHIFT_EQ:
+       /* right shift-assignment expression - binary infix (note right-to-left
+        * associativity) */
+       /*return parse_right_shift_assig_expr (tok, std::move (left),
+ 					   std::move (outer_attrs),
+ 					   restrictions);*/
+       return parse_compound_assignment_expr (
+ 	tok, std::move (left), std::move (outer_attrs),
+ 	CompoundAssignmentOperator::RIGHT_SHIFT, restrictions);
+     case DOT_DOT:
+       /* range exclusive expression - binary infix (no associativity)
+        * either "range" or "range from" */
+       return parse_led_range_exclusive_expr (tok, std::move (left),
+ 					     std::move (outer_attrs),
+ 					     restrictions);
+     case DOT_DOT_EQ:
+       /* range inclusive expression - binary infix (no associativity)
+        * unambiguously RangeInclusiveExpr */
+       return parse_range_inclusive_expr (tok, std::move (left),
+ 					 std::move (outer_attrs), restrictions);
+     case SCOPE_RESOLUTION:
+       // path expression - binary infix? FIXME should this even be parsed
+       // here?
+       add_error (
+ 	Error (tok->get_locus (),
+ 	       "found scope resolution operator in left denotation "
+ 	       "function - this should probably be handled elsewhere"));
+ 
+       return nullptr;
+     case DOT:
+       {
+ 	/* field expression or method call - relies on parentheses after next
+ 	 * identifier or await if token after is "await" (unary postfix) or
+ 	 * tuple index if token after is a decimal int literal */
+ 
+ 	const_TokenPtr next_tok = lexer.peek_token ();
+ 	if (next_tok->get_id () == IDENTIFIER
+ 	    && next_tok->get_str () == Values::Keywords::AWAIT)
+ 	  {
+ 	    // await expression
+ 	    return parse_await_expr (tok, std::move (left),
+ 				     std::move (outer_attrs));
+ 	  }
+ 	else if (next_tok->get_id () == INT_LITERAL)
+ 	  {
+ 	    // tuple index expression - TODO check for decimal int literal
+ 	    return parse_tuple_index_expr (tok, std::move (left),
+ 					   std::move (outer_attrs),
+ 					   restrictions);
+ 	  }
+ 	else if (next_tok->get_id () == FLOAT_LITERAL)
+ 	  {
+ 	    // Lexer has misidentified a tuple index as a float literal
+ 	    // eg: `(x, (y, z)).1.0` -> 1.0 has been identified as a float
+ 	    // literal. This means we should split it into three new separate
+ 	    // tokens, the first tuple index, the dot and the second tuple
+ 	    // index.
+ 	    auto current_loc = next_tok->get_locus ();
+ 	    auto str = next_tok->get_str ();
+ 	    auto dot_pos = str.find (".");
+ 	    auto prefix = str.substr (0, dot_pos);
+ 	    auto suffix = str.substr (dot_pos + 1);
+ 	    if (dot_pos == str.size () - 1)
+ 	      lexer.split_current_token (
+ 		{Token::make_int (current_loc, std::move (prefix),
+ 				  CORETYPE_PURE_DECIMAL),
+ 		 Token::make (DOT, current_loc + 1)});
+ 	    else
+ 	      lexer.split_current_token (
+ 		{Token::make_int (current_loc, std::move (prefix),
+ 				  CORETYPE_PURE_DECIMAL),
+ 		 Token::make (DOT, current_loc + 1),
+ 		 Token::make_int (current_loc + 2, std::move (suffix),
+ 				  CORETYPE_PURE_DECIMAL)});
+ 	    return parse_tuple_index_expr (tok, std::move (left),
+ 					   std::move (outer_attrs),
+ 					   restrictions);
+ 	  }
+ 	else if (next_tok->get_id () == IDENTIFIER
+ 		 && lexer.peek_token (1)->get_id () != LEFT_PAREN
+ 		 && lexer.peek_token (1)->get_id () != SCOPE_RESOLUTION)
+ 	  {
+ 	    /* field expression (or should be) - FIXME: scope resolution right
+ 	     * after identifier should always be method, I'm pretty sure */
+ 	    return parse_field_access_expr (tok, std::move (left),
+ 					    std::move (outer_attrs),
+ 					    restrictions);
+ 	  }
+ 	else
+ 	  {
+ 	    // method call (probably)
+ 	    return parse_method_call_expr (tok, std::move (left),
+ 					   std::move (outer_attrs),
+ 					   restrictions);
+ 	  }
+       }
+     case LEFT_PAREN:
+       // function call - method call is based on dot notation first
+       return parse_function_call_expr (tok, std::move (left),
+ 				       std::move (outer_attrs), restrictions);
+     case LEFT_SQUARE:
+       // array or slice index expression (pseudo binary infix)
+       return parse_index_expr (tok, std::move (left), std::move (outer_attrs),
+ 			       restrictions);
+     default:
+       add_error (Error (tok->get_locus (),
+ 			"found unexpected token %qs in left denotation",
+ 			tok->get_token_description ()));
+ 
+       return nullptr;
+     }
+ }
+ 
+ /* Returns the left binding power for the given ArithmeticOrLogicalExpr type.
+  * TODO make constexpr? Would that even do anything useful? */
+ inline binding_powers
+ get_lbp_for_arithmetic_or_logical_expr (
+   AST::ArithmeticOrLogicalExpr::ExprType expr_type)
+ {
+   switch (expr_type)
+     {
+     case ArithmeticOrLogicalOperator::ADD:
+       return LBP_PLUS;
+     case ArithmeticOrLogicalOperator::SUBTRACT:
+       return LBP_MINUS;
+     case ArithmeticOrLogicalOperator::MULTIPLY:
+       return LBP_MUL;
+     case ArithmeticOrLogicalOperator::DIVIDE:
+       return LBP_DIV;
+     case ArithmeticOrLogicalOperator::MODULUS:
+       return LBP_MOD;
+     case ArithmeticOrLogicalOperator::BITWISE_AND:
+       return LBP_AMP;
+     case ArithmeticOrLogicalOperator::BITWISE_OR:
+       return LBP_PIPE;
+     case ArithmeticOrLogicalOperator::BITWISE_XOR:
+       return LBP_CARET;
+     case ArithmeticOrLogicalOperator::LEFT_SHIFT:
+       return LBP_L_SHIFT;
+     case ArithmeticOrLogicalOperator::RIGHT_SHIFT:
+       return LBP_R_SHIFT;
+     default:
+       // WTF? should not happen, this is an error
+       rust_unreachable ();
+ 
+       return LBP_PLUS;
+     }
+ }
+ 
+ // Parses an arithmetic or logical expression (with Pratt parsing).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::ArithmeticOrLogicalExpr>
+ Parser<ManagedTokenSource>::parse_arithmetic_or_logical_expr (
+   const_TokenPtr, std::unique_ptr<AST::Expr> left, AST::AttrVec,
+   AST::ArithmeticOrLogicalExpr::ExprType expr_type,
+   ParseRestrictions restrictions)
+ {
+   // parse RHS (as tok has already been consumed in parse_expression)
+   std::unique_ptr<AST::Expr> right
+     = parse_expr (get_lbp_for_arithmetic_or_logical_expr (expr_type),
+ 		  AST::AttrVec (), restrictions);
+   if (right == nullptr)
+     return nullptr;
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   location_t locus = left->get_locus ();
+ 
+   return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
+     new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
+ 				      expr_type, locus));
+ }
+ 
+ // Parses a binary addition expression (with Pratt parsing).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::ArithmeticOrLogicalExpr>
+ Parser<ManagedTokenSource>::parse_binary_plus_expr (
+   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
+   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
+ {
+   // parse RHS (as tok has already been consumed in parse_expression)
+   std::unique_ptr<AST::Expr> right
+     = parse_expr (LBP_PLUS, AST::AttrVec (), restrictions);
+   if (right == nullptr)
+     return nullptr;
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   location_t locus = left->get_locus ();
+ 
+   return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
+     new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
+ 				      ArithmeticOrLogicalOperator::ADD, locus));
+ }
+ 
+ // Parses a binary subtraction expression (with Pratt parsing).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::ArithmeticOrLogicalExpr>
+ Parser<ManagedTokenSource>::parse_binary_minus_expr (
+   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
+   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
+ {
+   // parse RHS (as tok has already been consumed in parse_expression)
+   std::unique_ptr<AST::Expr> right
+     = parse_expr (LBP_MINUS, AST::AttrVec (), restrictions);
+   if (right == nullptr)
+     return nullptr;
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   location_t locus = left->get_locus ();
+ 
+   return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
+     new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
+ 				      ArithmeticOrLogicalOperator::SUBTRACT,
+ 				      locus));
+ }
+ 
+ // Parses a binary multiplication expression (with Pratt parsing).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::ArithmeticOrLogicalExpr>
+ Parser<ManagedTokenSource>::parse_binary_mult_expr (
+   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
+   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
+ {
+   // parse RHS (as tok has already been consumed in parse_expression)
+   std::unique_ptr<AST::Expr> right
+     = parse_expr (LBP_MUL, AST::AttrVec (), restrictions);
+   if (right == nullptr)
+     return nullptr;
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   location_t locus = left->get_locus ();
+ 
+   return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
+     new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
+ 				      ArithmeticOrLogicalOperator::MULTIPLY,
+ 				      locus));
+ }
+ 
+ // Parses a binary division expression (with Pratt parsing).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::ArithmeticOrLogicalExpr>
+ Parser<ManagedTokenSource>::parse_binary_div_expr (
+   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
+   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
+ {
+   // parse RHS (as tok has already been consumed in parse_expression)
+   std::unique_ptr<AST::Expr> right
+     = parse_expr (LBP_DIV, AST::AttrVec (), restrictions);
+   if (right == nullptr)
+     return nullptr;
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   location_t locus = left->get_locus ();
+ 
+   return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
+     new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
+ 				      ArithmeticOrLogicalOperator::DIVIDE,
+ 				      locus));
+ }
+ 
+ // Parses a binary modulo expression (with Pratt parsing).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::ArithmeticOrLogicalExpr>
+ Parser<ManagedTokenSource>::parse_binary_mod_expr (
+   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
+   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
+ {
+   // parse RHS (as tok has already been consumed in parse_expression)
+   std::unique_ptr<AST::Expr> right
+     = parse_expr (LBP_MOD, AST::AttrVec (), restrictions);
+   if (right == nullptr)
+     return nullptr;
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   location_t locus = left->get_locus ();
+ 
+   return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
+     new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
+ 				      ArithmeticOrLogicalOperator::MODULUS,
+ 				      locus));
+ }
+ 
+ /* Parses a binary bitwise (or eager logical) and expression (with Pratt
+  * parsing). */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::ArithmeticOrLogicalExpr>
+ Parser<ManagedTokenSource>::parse_bitwise_and_expr (
+   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
+   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
+ {
+   // parse RHS (as tok has already been consumed in parse_expression)
+   std::unique_ptr<AST::Expr> right
+     = parse_expr (LBP_AMP, AST::AttrVec (), restrictions);
+   if (right == nullptr)
+     return nullptr;
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   location_t locus = left->get_locus ();
+ 
+   return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
+     new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
+ 				      ArithmeticOrLogicalOperator::BITWISE_AND,
+ 				      locus));
+ }
+ 
+ /* Parses a binary bitwise (or eager logical) or expression (with Pratt
+  * parsing). */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::ArithmeticOrLogicalExpr>
+ Parser<ManagedTokenSource>::parse_bitwise_or_expr (
+   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
+   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
+ {
+   // parse RHS (as tok has already been consumed in parse_expression)
+   std::unique_ptr<AST::Expr> right
+     = parse_expr (LBP_PIPE, AST::AttrVec (), restrictions);
+   if (right == nullptr)
+     return nullptr;
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   location_t locus = left->get_locus ();
+ 
+   return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
+     new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
+ 				      ArithmeticOrLogicalOperator::BITWISE_OR,
+ 				      locus));
+ }
+ 
+ /* Parses a binary bitwise (or eager logical) xor expression (with Pratt
+  * parsing). */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::ArithmeticOrLogicalExpr>
+ Parser<ManagedTokenSource>::parse_bitwise_xor_expr (
+   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
+   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
+ {
+   // parse RHS (as tok has already been consumed in parse_expression)
+   std::unique_ptr<AST::Expr> right
+     = parse_expr (LBP_CARET, AST::AttrVec (), restrictions);
+   if (right == nullptr)
+     return nullptr;
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   location_t locus = left->get_locus ();
+ 
+   return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
+     new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
+ 				      ArithmeticOrLogicalOperator::BITWISE_XOR,
+ 				      locus));
+ }
+ 
+ // Parses a binary left shift expression (with Pratt parsing).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::ArithmeticOrLogicalExpr>
+ Parser<ManagedTokenSource>::parse_left_shift_expr (
+   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
+   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
+ {
+   // parse RHS (as tok has already been consumed in parse_expression)
+   std::unique_ptr<AST::Expr> right
+     = parse_expr (LBP_L_SHIFT, AST::AttrVec (), restrictions);
+   if (right == nullptr)
+     return nullptr;
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   location_t locus = left->get_locus ();
+ 
+   return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
+     new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
+ 				      ArithmeticOrLogicalOperator::LEFT_SHIFT,
+ 				      locus));
+ }
+ 
+ // Parses a binary right shift expression (with Pratt parsing).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::ArithmeticOrLogicalExpr>
+ Parser<ManagedTokenSource>::parse_right_shift_expr (
+   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
+   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
+ {
+   // parse RHS (as tok has already been consumed in parse_expression)
+   std::unique_ptr<AST::Expr> right
+     = parse_expr (LBP_R_SHIFT, AST::AttrVec (), restrictions);
+   if (right == nullptr)
+     return nullptr;
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   location_t locus = left->get_locus ();
+ 
+   return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
+     new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
+ 				      ArithmeticOrLogicalOperator::RIGHT_SHIFT,
+ 				      locus));
+ }
+ 
+ /* Returns the left binding power for the given ComparisonExpr type.
+  * TODO make constexpr? Would that even do anything useful? */
+ inline binding_powers
+ get_lbp_for_comparison_expr (AST::ComparisonExpr::ExprType expr_type)
+ {
+   switch (expr_type)
+     {
+     case ComparisonOperator::EQUAL:
+       return LBP_EQUAL;
+     case ComparisonOperator::NOT_EQUAL:
+       return LBP_NOT_EQUAL;
+     case ComparisonOperator::GREATER_THAN:
+       return LBP_GREATER_THAN;
+     case ComparisonOperator::LESS_THAN:
+       return LBP_SMALLER_THAN;
+     case ComparisonOperator::GREATER_OR_EQUAL:
+       return LBP_GREATER_EQUAL;
+     case ComparisonOperator::LESS_OR_EQUAL:
+       return LBP_SMALLER_EQUAL;
+     default:
+       // WTF? should not happen, this is an error
+       rust_unreachable ();
+ 
+       return LBP_EQUAL;
+     }
+ }
+ 
+ /* Parses a ComparisonExpr of given type and LBP. TODO find a way to only
+  * specify one and have the other looked up - e.g. specify ExprType and
+  * binding power is looked up? */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::ComparisonExpr>
+ Parser<ManagedTokenSource>::parse_comparison_expr (
+   const_TokenPtr, std::unique_ptr<AST::Expr> left, AST::AttrVec,
+   AST::ComparisonExpr::ExprType expr_type, ParseRestrictions restrictions)
+ {
+   // parse RHS (as tok has already been consumed in parse_expression)
+   std::unique_ptr<AST::Expr> right
+     = parse_expr (get_lbp_for_comparison_expr (expr_type), AST::AttrVec (),
+ 		  restrictions);
+   if (right == nullptr)
+     return nullptr;
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   location_t locus = left->get_locus ();
+ 
+   return std::unique_ptr<AST::ComparisonExpr> (
+     new AST::ComparisonExpr (std::move (left), std::move (right), expr_type,
+ 			     locus));
+ }
+ 
+ // Parses a binary equal to expression (with Pratt parsing).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::ComparisonExpr>
+ Parser<ManagedTokenSource>::parse_binary_equal_expr (
+   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
+   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
+ {
+   // parse RHS (as tok has already been consumed in parse_expression)
+   std::unique_ptr<AST::Expr> right
+     = parse_expr (LBP_EQUAL, AST::AttrVec (), restrictions);
+   if (right == nullptr)
+     return nullptr;
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   location_t locus = left->get_locus ();
+ 
+   return std::unique_ptr<AST::ComparisonExpr> (
+     new AST::ComparisonExpr (std::move (left), std::move (right),
+ 			     ComparisonOperator::EQUAL, locus));
+ }
+ 
+ // Parses a binary not equal to expression (with Pratt parsing).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::ComparisonExpr>
+ Parser<ManagedTokenSource>::parse_binary_not_equal_expr (
+   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
+   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
+ {
+   // parse RHS (as tok has already been consumed in parse_expression)
+   std::unique_ptr<AST::Expr> right
+     = parse_expr (LBP_NOT_EQUAL, AST::AttrVec (), restrictions);
+   if (right == nullptr)
+     return nullptr;
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   location_t locus = left->get_locus ();
+ 
+   return std::unique_ptr<AST::ComparisonExpr> (
+     new AST::ComparisonExpr (std::move (left), std::move (right),
+ 			     ComparisonOperator::NOT_EQUAL, locus));
+ }
+ 
+ // Parses a binary greater than expression (with Pratt parsing).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::ComparisonExpr>
+ Parser<ManagedTokenSource>::parse_binary_greater_than_expr (
+   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
+   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
+ {
+   // parse RHS (as tok has already been consumed in parse_expression)
+   std::unique_ptr<AST::Expr> right
+     = parse_expr (LBP_GREATER_THAN, AST::AttrVec (), restrictions);
+   if (right == nullptr)
+     return nullptr;
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   location_t locus = left->get_locus ();
+ 
+   return std::unique_ptr<AST::ComparisonExpr> (
+     new AST::ComparisonExpr (std::move (left), std::move (right),
+ 			     ComparisonOperator::GREATER_THAN, locus));
+ }
+ 
+ // Parses a binary less than expression (with Pratt parsing).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::ComparisonExpr>
+ Parser<ManagedTokenSource>::parse_binary_less_than_expr (
+   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
+   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
+ {
+   // parse RHS (as tok has already been consumed in parse_expression)
+   std::unique_ptr<AST::Expr> right
+     = parse_expr (LBP_SMALLER_THAN, AST::AttrVec (), restrictions);
+   if (right == nullptr)
+     return nullptr;
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   location_t locus = left->get_locus ();
+ 
+   return std::unique_ptr<AST::ComparisonExpr> (
+     new AST::ComparisonExpr (std::move (left), std::move (right),
+ 			     ComparisonOperator::LESS_THAN, locus));
+ }
+ 
+ // Parses a binary greater than or equal to expression (with Pratt parsing).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::ComparisonExpr>
+ Parser<ManagedTokenSource>::parse_binary_greater_equal_expr (
+   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
+   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
+ {
+   // parse RHS (as tok has already been consumed in parse_expression)
+   std::unique_ptr<AST::Expr> right
+     = parse_expr (LBP_GREATER_EQUAL, AST::AttrVec (), restrictions);
+   if (right == nullptr)
+     return nullptr;
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   location_t locus = left->get_locus ();
+ 
+   return std::unique_ptr<AST::ComparisonExpr> (
+     new AST::ComparisonExpr (std::move (left), std::move (right),
+ 			     ComparisonOperator::GREATER_OR_EQUAL, locus));
+ }
+ 
+ // Parses a binary less than or equal to expression (with Pratt parsing).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::ComparisonExpr>
+ Parser<ManagedTokenSource>::parse_binary_less_equal_expr (
+   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
+   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
+ {
+   // parse RHS (as tok has already been consumed in parse_expression)
+   std::unique_ptr<AST::Expr> right
+     = parse_expr (LBP_SMALLER_EQUAL, AST::AttrVec (), restrictions);
+   if (right == nullptr)
+     return nullptr;
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   location_t locus = left->get_locus ();
+ 
+   return std::unique_ptr<AST::ComparisonExpr> (
+     new AST::ComparisonExpr (std::move (left), std::move (right),
+ 			     ComparisonOperator::LESS_OR_EQUAL, locus));
+ }
+ 
+ // Parses a binary lazy boolean or expression (with Pratt parsing).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::LazyBooleanExpr>
+ Parser<ManagedTokenSource>::parse_lazy_or_expr (
+   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
+   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
+ {
+   // parse RHS (as tok has already been consumed in parse_expression)
+   std::unique_ptr<AST::Expr> right
+     = parse_expr (LBP_LOGICAL_OR, AST::AttrVec (), restrictions);
+   if (right == nullptr)
+     return nullptr;
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   location_t locus = left->get_locus ();
+ 
+   return std::unique_ptr<AST::LazyBooleanExpr> (
+     new AST::LazyBooleanExpr (std::move (left), std::move (right),
+ 			      LazyBooleanOperator::LOGICAL_OR, locus));
+ }
+ 
+ // Parses a binary lazy boolean and expression (with Pratt parsing).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::LazyBooleanExpr>
+ Parser<ManagedTokenSource>::parse_lazy_and_expr (
+   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
+   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
+ {
+   // parse RHS (as tok has already been consumed in parse_expression)
+   std::unique_ptr<AST::Expr> right
+     = parse_expr (LBP_LOGICAL_AND, AST::AttrVec (), restrictions);
+   if (right == nullptr)
+     return nullptr;
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   location_t locus = left->get_locus ();
+ 
+   return std::unique_ptr<AST::LazyBooleanExpr> (
+     new AST::LazyBooleanExpr (std::move (left), std::move (right),
+ 			      LazyBooleanOperator::LOGICAL_AND, locus));
+ }
+ 
+ // Parses a pseudo-binary infix type cast expression (with Pratt parsing).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::TypeCastExpr>
+ Parser<ManagedTokenSource>::parse_type_cast_expr (
+   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> expr_to_cast,
+   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED,
+   ParseRestrictions restrictions ATTRIBUTE_UNUSED)
+ {
+   // parse RHS (as tok has already been consumed in parse_expression)
+   std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
+   if (type == nullptr)
+     return nullptr;
+   // FIXME: how do I get precedence put in here?
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   location_t locus = expr_to_cast->get_locus ();
+ 
+   return std::unique_ptr<AST::TypeCastExpr> (
+     new AST::TypeCastExpr (std::move (expr_to_cast), std::move (type), locus));
+ }
+ 
+ // Parses a binary assignment expression (with Pratt parsing).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::AssignmentExpr>
+ Parser<ManagedTokenSource>::parse_assig_expr (
+   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
+   AST::AttrVec outer_attrs, ParseRestrictions restrictions)
+ {
+   // parse RHS (as tok has already been consumed in parse_expression)
+   std::unique_ptr<AST::Expr> right
+     = parse_expr (LBP_ASSIG - 1, AST::AttrVec (), restrictions);
+   if (right == nullptr)
+     return nullptr;
+   // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   location_t locus = left->get_locus ();
+ 
+   return std::unique_ptr<AST::AssignmentExpr> (
+     new AST::AssignmentExpr (std::move (left), std::move (right),
+ 			     std::move (outer_attrs), locus));
+ }
+ 
+ /* Returns the left binding power for the given CompoundAssignmentExpr type.
+  * TODO make constexpr? Would that even do anything useful? */
+ inline binding_powers
+ get_lbp_for_compound_assignment_expr (
+   AST::CompoundAssignmentExpr::ExprType expr_type)
+ {
+   switch (expr_type)
+     {
+     case CompoundAssignmentOperator::ADD:
+       return LBP_PLUS;
+     case CompoundAssignmentOperator::SUBTRACT:
+       return LBP_MINUS;
+     case CompoundAssignmentOperator::MULTIPLY:
+       return LBP_MUL;
+     case CompoundAssignmentOperator::DIVIDE:
+       return LBP_DIV;
+     case CompoundAssignmentOperator::MODULUS:
+       return LBP_MOD;
+     case CompoundAssignmentOperator::BITWISE_AND:
+       return LBP_AMP;
+     case CompoundAssignmentOperator::BITWISE_OR:
+       return LBP_PIPE;
+     case CompoundAssignmentOperator::BITWISE_XOR:
+       return LBP_CARET;
+     case CompoundAssignmentOperator::LEFT_SHIFT:
+       return LBP_L_SHIFT;
+     case CompoundAssignmentOperator::RIGHT_SHIFT:
+       return LBP_R_SHIFT;
+     default:
+       // WTF? should not happen, this is an error
+       rust_unreachable ();
+ 
+       return LBP_PLUS;
+     }
+ }
+ 
+ // Parses a compound assignment expression (with Pratt parsing).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::CompoundAssignmentExpr>
+ Parser<ManagedTokenSource>::parse_compound_assignment_expr (
+   const_TokenPtr, std::unique_ptr<AST::Expr> left, AST::AttrVec,
+   AST::CompoundAssignmentExpr::ExprType expr_type,
+   ParseRestrictions restrictions)
+ {
+   // parse RHS (as tok has already been consumed in parse_expression)
+   std::unique_ptr<AST::Expr> right
+     = parse_expr (get_lbp_for_compound_assignment_expr (expr_type) - 1,
+ 		  AST::AttrVec (), restrictions);
+   if (right == nullptr)
+     return nullptr;
+   // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   location_t locus = left->get_locus ();
+ 
+   return std::unique_ptr<AST::CompoundAssignmentExpr> (
+     new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
+ 				     expr_type, locus));
+ }
+ 
+ // Parses a binary add-assignment expression (with Pratt parsing).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::CompoundAssignmentExpr>
+ Parser<ManagedTokenSource>::parse_plus_assig_expr (
+   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
+   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
+ {
+   // parse RHS (as tok has already been consumed in parse_expression)
+   std::unique_ptr<AST::Expr> right
+     = parse_expr (LBP_PLUS_ASSIG - 1, AST::AttrVec (), restrictions);
+   if (right == nullptr)
+     return nullptr;
+   // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   location_t locus = left->get_locus ();
+ 
+   return std::unique_ptr<AST::CompoundAssignmentExpr> (
+     new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
+ 				     CompoundAssignmentOperator::ADD, locus));
+ }
+ 
+ // Parses a binary minus-assignment expression (with Pratt parsing).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::CompoundAssignmentExpr>
+ Parser<ManagedTokenSource>::parse_minus_assig_expr (
+   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
+   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
+ {
+   // parse RHS (as tok has already been consumed in parse_expression)
+   std::unique_ptr<AST::Expr> right
+     = parse_expr (LBP_MINUS_ASSIG - 1, AST::AttrVec (), restrictions);
+   if (right == nullptr)
+     return nullptr;
+   // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   location_t locus = left->get_locus ();
+ 
+   return std::unique_ptr<AST::CompoundAssignmentExpr> (
+     new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
+ 				     CompoundAssignmentOperator::SUBTRACT,
+ 				     locus));
+ }
+ 
+ // Parses a binary multiplication-assignment expression (with Pratt parsing).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::CompoundAssignmentExpr>
+ Parser<ManagedTokenSource>::parse_mult_assig_expr (
+   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
+   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
+ {
+   // parse RHS (as tok has already been consumed in parse_expression)
+   std::unique_ptr<AST::Expr> right
+     = parse_expr (LBP_MULT_ASSIG - 1, AST::AttrVec (), restrictions);
+   if (right == nullptr)
+     return nullptr;
+   // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   location_t locus = left->get_locus ();
+ 
+   return std::unique_ptr<AST::CompoundAssignmentExpr> (
+     new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
+ 				     CompoundAssignmentOperator::MULTIPLY,
+ 				     locus));
+ }
+ 
+ // Parses a binary division-assignment expression (with Pratt parsing).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::CompoundAssignmentExpr>
+ Parser<ManagedTokenSource>::parse_div_assig_expr (
+   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
+   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
+ {
+   // parse RHS (as tok has already been consumed in parse_expression)
+   std::unique_ptr<AST::Expr> right
+     = parse_expr (LBP_DIV_ASSIG - 1, AST::AttrVec (), restrictions);
+   if (right == nullptr)
+     return nullptr;
+   // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   location_t locus = left->get_locus ();
+ 
+   return std::unique_ptr<AST::CompoundAssignmentExpr> (
+     new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
+ 				     CompoundAssignmentOperator::DIVIDE,
+ 				     locus));
+ }
+ 
+ // Parses a binary modulo-assignment expression (with Pratt parsing).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::CompoundAssignmentExpr>
+ Parser<ManagedTokenSource>::parse_mod_assig_expr (
+   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
+   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
+ {
+   // parse RHS (as tok has already been consumed in parse_expression)
+   std::unique_ptr<AST::Expr> right
+     = parse_expr (LBP_MOD_ASSIG - 1, AST::AttrVec (), restrictions);
+   if (right == nullptr)
+     return nullptr;
+   // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   location_t locus = left->get_locus ();
+ 
+   return std::unique_ptr<AST::CompoundAssignmentExpr> (
+     new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
+ 				     CompoundAssignmentOperator::MODULUS,
+ 				     locus));
+ }
+ 
+ // Parses a binary and-assignment expression (with Pratt parsing).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::CompoundAssignmentExpr>
+ Parser<ManagedTokenSource>::parse_and_assig_expr (
+   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
+   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
+ {
+   // parse RHS (as tok has already been consumed in parse_expression)
+   std::unique_ptr<AST::Expr> right
+     = parse_expr (LBP_AMP_ASSIG - 1, AST::AttrVec (), restrictions);
+   if (right == nullptr)
+     return nullptr;
+   // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   location_t locus = left->get_locus ();
+ 
+   return std::unique_ptr<AST::CompoundAssignmentExpr> (
+     new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
+ 				     CompoundAssignmentOperator::BITWISE_AND,
+ 				     locus));
+ }
+ 
+ // Parses a binary or-assignment expression (with Pratt parsing).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::CompoundAssignmentExpr>
+ Parser<ManagedTokenSource>::parse_or_assig_expr (
+   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
+   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
+ {
+   // parse RHS (as tok has already been consumed in parse_expression)
+   std::unique_ptr<AST::Expr> right
+     = parse_expr (LBP_PIPE_ASSIG - 1, AST::AttrVec (), restrictions);
+   if (right == nullptr)
+     return nullptr;
+   // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   location_t locus = left->get_locus ();
+ 
+   return std::unique_ptr<AST::CompoundAssignmentExpr> (
+     new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
+ 				     CompoundAssignmentOperator::BITWISE_OR,
+ 				     locus));
+ }
+ 
+ // Parses a binary xor-assignment expression (with Pratt parsing).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::CompoundAssignmentExpr>
+ Parser<ManagedTokenSource>::parse_xor_assig_expr (
+   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
+   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
+ {
+   // parse RHS (as tok has already been consumed in parse_expression)
+   std::unique_ptr<AST::Expr> right
+     = parse_expr (LBP_CARET_ASSIG - 1, AST::AttrVec (), restrictions);
+   if (right == nullptr)
+     return nullptr;
+   // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   location_t locus = left->get_locus ();
+ 
+   return std::unique_ptr<AST::CompoundAssignmentExpr> (
+     new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
+ 				     CompoundAssignmentOperator::BITWISE_XOR,
+ 				     locus));
+ }
+ 
+ // Parses a binary left shift-assignment expression (with Pratt parsing).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::CompoundAssignmentExpr>
+ Parser<ManagedTokenSource>::parse_left_shift_assig_expr (
+   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
+   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
+ {
+   // parse RHS (as tok has already been consumed in parse_expression)
+   std::unique_ptr<AST::Expr> right
+     = parse_expr (LBP_L_SHIFT_ASSIG - 1, AST::AttrVec (), restrictions);
+   if (right == nullptr)
+     return nullptr;
+   // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   location_t locus = left->get_locus ();
+ 
+   return std::unique_ptr<AST::CompoundAssignmentExpr> (
+     new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
+ 				     CompoundAssignmentOperator::LEFT_SHIFT,
+ 				     locus));
+ }
+ 
+ // Parses a binary right shift-assignment expression (with Pratt parsing).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::CompoundAssignmentExpr>
+ Parser<ManagedTokenSource>::parse_right_shift_assig_expr (
+   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
+   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
+ {
+   // parse RHS (as tok has already been consumed in parse_expression)
+   std::unique_ptr<AST::Expr> right
+     = parse_expr (LBP_R_SHIFT_ASSIG - 1, AST::AttrVec (), restrictions);
+   if (right == nullptr)
+     return nullptr;
+   // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   location_t locus = left->get_locus ();
+ 
+   return std::unique_ptr<AST::CompoundAssignmentExpr> (
+     new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
+ 				     CompoundAssignmentOperator::RIGHT_SHIFT,
+ 				     locus));
+ }
+ 
+ // Parses a postfix unary await expression (with Pratt parsing).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::AwaitExpr>
+ Parser<ManagedTokenSource>::parse_await_expr (
+   const_TokenPtr tok, std::unique_ptr<AST::Expr> expr_to_await,
+   AST::AttrVec outer_attrs)
+ {
+   /* skip "await" identifier (as "." has already been consumed in
+    * parse_expression) this assumes that the identifier was already identified
+    * as await */
+   if (!skip_token (IDENTIFIER))
+     {
+       Error error (tok->get_locus (), "failed to skip %<await%> in await expr "
+ 				      "- this is probably a deep issue");
+       add_error (std::move (error));
+ 
+       // skip somewhere?
+       return nullptr;
+     }
+ 
+   // TODO: check inside async block in semantic analysis
+   location_t locus = expr_to_await->get_locus ();
+ 
+   return std::unique_ptr<AST::AwaitExpr> (
+     new AST::AwaitExpr (std::move (expr_to_await), std::move (outer_attrs),
+ 			locus));
+ }
+ 
+ /* Parses an exclusive range ('..') in left denotation position (i.e.
+  * RangeFromExpr or RangeFromToExpr). */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::RangeExpr>
+ Parser<ManagedTokenSource>::parse_led_range_exclusive_expr (
+   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
+   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
+ {
+   // FIXME: this probably parses expressions accidently or whatever
+   // try parsing RHS (as tok has already been consumed in parse_expression)
+   // Can be nullptr, in which case it is a RangeFromExpr, otherwise a
+   // RangeFromToExpr.
+   restrictions.expr_can_be_null = true;
+   std::unique_ptr<AST::Expr> right
+     = parse_expr (LBP_DOT_DOT, AST::AttrVec (), restrictions);
+ 
+   location_t locus = left->get_locus ();
+ 
+   if (right == nullptr)
+     {
+       // range from expr
+       return std::unique_ptr<AST::RangeFromExpr> (
+ 	new AST::RangeFromExpr (std::move (left), locus));
+     }
+   else
+     {
+       return std::unique_ptr<AST::RangeFromToExpr> (
+ 	new AST::RangeFromToExpr (std::move (left), std::move (right), locus));
+     }
+   // FIXME: make non-associative
+ }
+ 
+ /* Parses an exclusive range ('..') in null denotation position (i.e.
+  * RangeToExpr or RangeFullExpr). */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::RangeExpr>
+ Parser<ManagedTokenSource>::parse_nud_range_exclusive_expr (
+   const_TokenPtr tok, AST::AttrVec outer_attrs ATTRIBUTE_UNUSED)
+ {
+   auto restrictions = ParseRestrictions ();
+   restrictions.expr_can_be_null = true;
+ 
+   // FIXME: this probably parses expressions accidently or whatever
+   // try parsing RHS (as tok has already been consumed in parse_expression)
+   std::unique_ptr<AST::Expr> right
+     = parse_expr (LBP_DOT_DOT, AST::AttrVec (), restrictions);
+ 
+   location_t locus = tok->get_locus ();
+ 
+   if (right == nullptr)
+     {
+       // range from expr
+       return std::unique_ptr<AST::RangeFullExpr> (
+ 	new AST::RangeFullExpr (locus));
+     }
+   else
+     {
+       return std::unique_ptr<AST::RangeToExpr> (
+ 	new AST::RangeToExpr (std::move (right), locus));
+     }
+   // FIXME: make non-associative
+ }
+ 
+ // Parses a full binary range inclusive expression.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::RangeFromToInclExpr>
+ Parser<ManagedTokenSource>::parse_range_inclusive_expr (
+   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
+   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
+ {
+   // parse RHS (as tok has already been consumed in parse_expression)
+   std::unique_ptr<AST::Expr> right
+     = parse_expr (LBP_DOT_DOT_EQ, AST::AttrVec (), restrictions);
+   if (right == nullptr)
+     return nullptr;
+   // FIXME: make non-associative
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   location_t locus = left->get_locus ();
+ 
+   return std::unique_ptr<AST::RangeFromToInclExpr> (
+     new AST::RangeFromToInclExpr (std::move (left), std::move (right), locus));
+ }
+ 
+ // Parses an inclusive range-to prefix unary expression.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::RangeToInclExpr>
+ Parser<ManagedTokenSource>::parse_range_to_inclusive_expr (
+   const_TokenPtr tok, AST::AttrVec outer_attrs ATTRIBUTE_UNUSED)
+ {
+   // parse RHS (as tok has already been consumed in parse_expression)
+   std::unique_ptr<AST::Expr> right = parse_expr (LBP_DOT_DOT_EQ);
+   if (right == nullptr)
+     return nullptr;
+   // FIXME: make non-associative
+ 
+   // TODO: check types. actually, do so during semantic analysis
+ 
+   return std::unique_ptr<AST::RangeToInclExpr> (
+     new AST::RangeToInclExpr (std::move (right), tok->get_locus ()));
+ }
+ 
+ // Parses a pseudo-binary infix tuple index expression.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::TupleIndexExpr>
+ Parser<ManagedTokenSource>::parse_tuple_index_expr (
+   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> tuple_expr,
+   AST::AttrVec outer_attrs, ParseRestrictions restrictions ATTRIBUTE_UNUSED)
+ {
+   // parse int literal (as token already skipped)
+   const_TokenPtr index_tok = expect_token (INT_LITERAL);
+   if (index_tok == nullptr)
+     {
+       return nullptr;
+     }
+   std::string index = index_tok->get_str ();
+ 
+   // convert to integer
+   if (!index_tok->is_pure_decimal ())
+     {
+       Error error (index_tok->get_locus (),
+ 		   "tuple index should be a pure decimal literal");
+       add_error (std::move (error));
+     }
+   int index_int = atoi (index.c_str ());
+ 
+   location_t locus = tuple_expr->get_locus ();
+ 
+   return std::unique_ptr<AST::TupleIndexExpr> (
+     new AST::TupleIndexExpr (std::move (tuple_expr), index_int,
+ 			     std::move (outer_attrs), locus));
+ }
+ 
+ // Parses a pseudo-binary infix array (or slice) index expression.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::ArrayIndexExpr>
+ Parser<ManagedTokenSource>::parse_index_expr (
+   const_TokenPtr, std::unique_ptr<AST::Expr> array_expr,
+   AST::AttrVec outer_attrs, ParseRestrictions)
+ {
+   // parse RHS (as tok has already been consumed in parse_expression)
+   /*std::unique_ptr<AST::Expr> index_expr
+     = parse_expr (LBP_ARRAY_REF, AST::AttrVec (),
+     restrictions);*/
+   // TODO: conceptually, should treat [] as brackets, so just parse all expr
+   std::unique_ptr<AST::Expr> index_expr = parse_expr ();
+   if (index_expr == nullptr)
+     return nullptr;
+ 
+   // skip ']' at end of array
+   if (!skip_token (RIGHT_SQUARE))
+     {
+       // skip somewhere?
+       return nullptr;
+     }
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   location_t locus = array_expr->get_locus ();
+ 
+   return std::unique_ptr<AST::ArrayIndexExpr> (
+     new AST::ArrayIndexExpr (std::move (array_expr), std::move (index_expr),
+ 			     std::move (outer_attrs), locus));
+ }
+ 
+ // Parses a pseudo-binary infix struct field access expression.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::FieldAccessExpr>
+ Parser<ManagedTokenSource>::parse_field_access_expr (
+   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> struct_expr,
+   AST::AttrVec outer_attrs, ParseRestrictions restrictions ATTRIBUTE_UNUSED)
+ {
+   /* get field name identifier (assume that this is a field access expr and
+    * not await, for instance) */
+   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
+   if (ident_tok == nullptr)
+     return nullptr;
+ 
+   Identifier ident{ident_tok};
+ 
+   location_t locus = struct_expr->get_locus ();
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   return std::unique_ptr<AST::FieldAccessExpr> (
+     new AST::FieldAccessExpr (std::move (struct_expr), std::move (ident),
+ 			      std::move (outer_attrs), locus));
+ }
+ 
+ // Parses a pseudo-binary infix method call expression.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::MethodCallExpr>
+ Parser<ManagedTokenSource>::parse_method_call_expr (
+   const_TokenPtr tok, std::unique_ptr<AST::Expr> receiver_expr,
+   AST::AttrVec outer_attrs, ParseRestrictions)
+ {
+   // parse path expr segment
+   AST::PathExprSegment segment = parse_path_expr_segment ();
+   if (segment.is_error ())
+     {
+       Error error (tok->get_locus (),
+ 		   "failed to parse path expr segment of method call expr");
+       add_error (std::move (error));
+ 
+       return nullptr;
+     }
+ 
+   // skip left parentheses
+   if (!skip_token (LEFT_PAREN))
+     {
+       return nullptr;
+     }
+ 
+   // parse method params (if they exist)
+   std::vector<std::unique_ptr<AST::Expr>> params;
+ 
+   const_TokenPtr t = lexer.peek_token ();
+   while (t->get_id () != RIGHT_PAREN)
+     {
+       std::unique_ptr<AST::Expr> param = parse_expr ();
+       if (param == nullptr)
+ 	{
+ 	  Error error (t->get_locus (),
+ 		       "failed to parse method param in method call");
+ 	  add_error (std::move (error));
+ 
+ 	  return nullptr;
+ 	}
+       params.push_back (std::move (param));
+ 
+       if (lexer.peek_token ()->get_id () != COMMA)
+ 	break;
+ 
+       lexer.skip_token ();
+       t = lexer.peek_token ();
+     }
+ 
+   // skip right paren
+   if (!skip_token (RIGHT_PAREN))
+     {
+       return nullptr;
+     }
+ 
+   // TODO: check types. actually do so in semantic analysis pass.
+   location_t locus = receiver_expr->get_locus ();
+ 
+   return std::unique_ptr<AST::MethodCallExpr> (
+     new AST::MethodCallExpr (std::move (receiver_expr), std::move (segment),
+ 			     std::move (params), std::move (outer_attrs),
+ 			     locus));
+ }
+ 
+ // Parses a pseudo-binary infix function call expression.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::CallExpr>
+ Parser<ManagedTokenSource>::parse_function_call_expr (
+   const_TokenPtr, std::unique_ptr<AST::Expr> function_expr,
+   AST::AttrVec outer_attrs, ParseRestrictions)
+ {
+   // parse function params (if they exist)
+   std::vector<std::unique_ptr<AST::Expr>> params;
+ 
+   const_TokenPtr t = lexer.peek_token ();
+   while (t->get_id () != RIGHT_PAREN)
+     {
+       std::unique_ptr<AST::Expr> param = parse_expr ();
+       if (param == nullptr)
+ 	{
+ 	  Error error (t->get_locus (),
+ 		       "failed to parse function param in function call");
+ 	  add_error (std::move (error));
+ 
+ 	  return nullptr;
+ 	}
+       params.push_back (std::move (param));
+ 
+       if (lexer.peek_token ()->get_id () != COMMA)
+ 	break;
+ 
+       lexer.skip_token ();
+       t = lexer.peek_token ();
+     }
+ 
+   // skip ')' at end of param list
+   if (!skip_token (RIGHT_PAREN))
+     {
+       // skip somewhere?
+       return nullptr;
+     }
+ 
+   // TODO: check types. actually, do so during semantic analysis
+   location_t locus = function_expr->get_locus ();
+ 
+   return std::unique_ptr<AST::CallExpr> (
+     new AST::CallExpr (std::move (function_expr), std::move (params),
+ 		       std::move (outer_attrs), locus));
+ }
+ 
+ /* Parses a struct expr struct with a path in expression already parsed (but
+  * not
+  * '{' token). */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::StructExprStruct>
+ Parser<ManagedTokenSource>::parse_struct_expr_struct_partial (
+   AST::PathInExpression path, AST::AttrVec outer_attrs)
+ {
+   // assume struct expr struct (as struct-enum disambiguation requires name
+   // lookup) again, make statement if final ';'
+   if (!skip_token (LEFT_CURLY))
+     {
+       return nullptr;
+     }
+ 
+   // parse inner attributes
+   AST::AttrVec inner_attrs = parse_inner_attributes ();
+ 
+   // branch based on next token
+   const_TokenPtr t = lexer.peek_token ();
+   location_t path_locus = path.get_locus ();
+   switch (t->get_id ())
+     {
+     case RIGHT_CURLY:
+       // struct with no body
+       lexer.skip_token ();
+ 
+       return std::unique_ptr<AST::StructExprStruct> (
+ 	new AST::StructExprStruct (std::move (path), std::move (inner_attrs),
+ 				   std::move (outer_attrs), path_locus));
+     case DOT_DOT:
+       /* technically this would give a struct base-only struct, but this
+        * algorithm should work too. As such, AST type not happening. */
+     case IDENTIFIER:
+     case HASH:
+     case INT_LITERAL:
+       {
+ 	// struct with struct expr fields
+ 
+ 	// parse struct expr fields
+ 	std::vector<std::unique_ptr<AST::StructExprField>> fields;
+ 
+ 	while (t->get_id () != RIGHT_CURLY && t->get_id () != DOT_DOT)
+ 	  {
+ 	    std::unique_ptr<AST::StructExprField> field
+ 	      = parse_struct_expr_field ();
+ 	    if (field == nullptr)
+ 	      {
+ 		Error error (t->get_locus (),
+ 			     "failed to parse struct (or enum) expr field");
+ 		add_error (std::move (error));
+ 
+ 		return nullptr;
+ 	      }
+ 
+ 	    // DEBUG:
+ 	    rust_debug ("struct/enum expr field validated to not be null");
+ 
+ 	    fields.push_back (std::move (field));
+ 
+ 	    // DEBUG:
+ 	    rust_debug ("struct/enum expr field pushed back");
+ 
+ 	    if (lexer.peek_token ()->get_id () != COMMA)
+ 	      {
+ 		// DEBUG:
+ 		rust_debug ("lack of comma detected in struct/enum expr "
+ 			    "fields - break");
+ 		break;
+ 	      }
+ 	    lexer.skip_token ();
+ 
+ 	    // DEBUG:
+ 	    rust_debug ("struct/enum expr fields comma skipped ");
+ 
+ 	    t = lexer.peek_token ();
+ 	  }
+ 
+ 	// DEBUG:
+ 	rust_debug ("struct/enum expr about to parse struct base ");
+ 
+ 	// parse struct base if it exists
+ 	AST::StructBase struct_base = AST::StructBase::error ();
+ 	if (lexer.peek_token ()->get_id () == DOT_DOT)
+ 	  {
+ 	    location_t dot_dot_location = lexer.peek_token ()->get_locus ();
+ 	    lexer.skip_token ();
+ 
+ 	    // parse required struct base expr
+ 	    std::unique_ptr<AST::Expr> base_expr = parse_expr ();
+ 	    if (base_expr == nullptr)
+ 	      {
+ 		Error error (lexer.peek_token ()->get_locus (),
+ 			     "failed to parse struct base expression in struct "
+ 			     "expression");
+ 		add_error (std::move (error));
+ 
+ 		return nullptr;
+ 	      }
+ 
+ 	    // DEBUG:
+ 	    rust_debug ("struct/enum expr - parsed and validated base expr");
+ 
+ 	    struct_base
+ 	      = AST::StructBase (std::move (base_expr), dot_dot_location);
+ 
+ 	    // DEBUG:
+ 	    rust_debug ("assigned struct base to new struct base ");
+ 	  }
+ 
+ 	if (!skip_token (RIGHT_CURLY))
+ 	  {
+ 	    return nullptr;
+ 	  }
+ 
+ 	// DEBUG:
+ 	rust_debug (
+ 	  "struct/enum expr skipped right curly - done and ready to return");
+ 
+ 	return std::unique_ptr<AST::StructExprStructFields> (
+ 	  new AST::StructExprStructFields (std::move (path), std::move (fields),
+ 					   path_locus, std::move (struct_base),
+ 					   std::move (inner_attrs),
+ 					   std::move (outer_attrs)));
+       }
+     default:
+       add_error (
+ 	Error (t->get_locus (),
+ 	       "unrecognised token %qs in struct (or enum) expression - "
+ 	       "expected %<}%>, identifier, integer literal, or %<..%>",
+ 	       t->get_token_description ()));
+ 
+       return nullptr;
+     }
+ }
+ 
+ /* Parses a struct expr tuple with a path in expression already parsed (but
+  * not
+  * '(' token).
+  * FIXME: this currently outputs a call expr, as they cannot be disambiguated.
+  * A better solution would be to just get this to call that function directly.
+  * */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::CallExpr>
+ Parser<ManagedTokenSource>::parse_struct_expr_tuple_partial (
+   AST::PathInExpression path, AST::AttrVec outer_attrs)
+ {
+   if (!skip_token (LEFT_PAREN))
+     {
+       return nullptr;
+     }
+ 
+   AST::AttrVec inner_attrs = parse_inner_attributes ();
+ 
+   std::vector<std::unique_ptr<AST::Expr>> exprs;
+ 
+   const_TokenPtr t = lexer.peek_token ();
+   while (t->get_id () != RIGHT_PAREN)
+     {
+       // parse expression (required)
+       std::unique_ptr<AST::Expr> expr = parse_expr ();
+       if (expr == nullptr)
+ 	{
+ 	  Error error (t->get_locus (), "failed to parse expression in "
+ 					"struct (or enum) expression tuple");
+ 	  add_error (std::move (error));
+ 
+ 	  return nullptr;
+ 	}
+       exprs.push_back (std::move (expr));
+ 
+       if (lexer.peek_token ()->get_id () != COMMA)
+ 	break;
+ 
+       lexer.skip_token ();
+ 
+       t = lexer.peek_token ();
+     }
+ 
+   if (!skip_token (RIGHT_PAREN))
+     {
+       return nullptr;
+     }
+ 
+   location_t path_locus = path.get_locus ();
+ 
+   auto pathExpr = std::unique_ptr<AST::PathInExpression> (
+     new AST::PathInExpression (std::move (path)));
+ 
+   return std::unique_ptr<AST::CallExpr> (
+     new AST::CallExpr (std::move (pathExpr), std::move (exprs),
+ 		       std::move (outer_attrs), path_locus));
+ }
+ 
+ // Parses a closure expression with pratt parsing (from null denotation).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::ClosureExpr>
+ Parser<ManagedTokenSource>::parse_closure_expr_pratt (const_TokenPtr tok,
+ 						      AST::AttrVec outer_attrs)
+ {
+   // TODO: does this need pratt parsing (for precedence)? probably not, but
+   // idk
+   location_t locus = tok->get_locus ();
+   bool has_move = false;
+   if (tok->get_id () == MOVE)
+     {
+       has_move = true;
+       tok = lexer.peek_token ();
+       lexer.skip_token ();
+       // skip token and reassign
+     }
+ 
+   // handle parameter list
+   std::vector<AST::ClosureParam> params;
+ 
+   switch (tok->get_id ())
+     {
+     case OR:
+       // no parameters, don't skip token
+       break;
+     case PIPE:
+       {
+ 	// actually may have parameters
+ 	// don't skip token
+ 	const_TokenPtr t = lexer.peek_token ();
+ 	while (t->get_id () != PIPE)
+ 	  {
+ 	    AST::ClosureParam param = parse_closure_param ();
+ 	    if (param.is_error ())
+ 	      {
+ 		// TODO is this really an error?
+ 		Error error (t->get_locus (), "could not parse closure param");
+ 		add_error (std::move (error));
+ 
+ 		return nullptr;
+ 	      }
+ 	    params.push_back (std::move (param));
+ 
+ 	    if (lexer.peek_token ()->get_id () != COMMA)
+ 	      {
+ 		if (lexer.peek_token ()->get_id () == OR)
+ 		  lexer.split_current_token (PIPE, PIPE);
+ 		// not an error but means param list is done
+ 		break;
+ 	      }
+ 	    // skip comma
+ 	    lexer.skip_token ();
+ 
+ 	    if (lexer.peek_token ()->get_id () == OR)
+ 	      lexer.split_current_token (PIPE, PIPE);
+ 
+ 	    t = lexer.peek_token ();
+ 	  }
+ 
+ 	if (!skip_token (PIPE))
+ 	  {
+ 	    return nullptr;
+ 	  }
+ 	break;
+       }
+     default:
+       add_error (Error (tok->get_locus (),
+ 			"unexpected token %qs in closure expression - expected "
+ 			"%<|%> or %<||%>",
+ 			tok->get_token_description ()));
+ 
+       // skip somewhere?
+       return nullptr;
+     }
+ 
+   // again branch based on next token
+   tok = lexer.peek_token ();
+   if (tok->get_id () == RETURN_TYPE)
+     {
+       // must be return type closure with block expr
+ 
+       // skip "return type" token
+       lexer.skip_token ();
+ 
+       // parse actual type, which is required
+       std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
+       if (type == nullptr)
+ 	{
+ 	  // error
+ 	  Error error (tok->get_locus (), "failed to parse type for closure");
+ 	  add_error (std::move (error));
+ 
+ 	  // skip somewhere?
+ 	  return nullptr;
+ 	}
+ 
+       // parse block expr, which is required
+       std::unique_ptr<AST::BlockExpr> block = parse_block_expr ();
+       if (block == nullptr)
+ 	{
+ 	  // error
+ 	  Error error (lexer.peek_token ()->get_locus (),
+ 		       "failed to parse block expr in closure");
+ 	  add_error (std::move (error));
+ 
+ 	  // skip somewhere?
+ 	  return nullptr;
+ 	}
+ 
+       return std::unique_ptr<AST::ClosureExprInnerTyped> (
+ 	new AST::ClosureExprInnerTyped (std::move (type), std::move (block),
+ 					std::move (params), locus, has_move,
+ 					std::move (outer_attrs)));
+     }
+   else
+     {
+       // must be expr-only closure
+ 
+       // parse expr, which is required
+       std::unique_ptr<AST::Expr> expr = parse_expr ();
+       if (expr == nullptr)
+ 	{
+ 	  Error error (tok->get_locus (),
+ 		       "failed to parse expression in closure");
+ 	  add_error (std::move (error));
+ 
+ 	  // skip somewhere?
+ 	  return nullptr;
+ 	}
+ 
+       return std::unique_ptr<AST::ClosureExprInner> (
+ 	new AST::ClosureExprInner (std::move (expr), std::move (params), locus,
+ 				   has_move, std::move (outer_attrs)));
+     }
+ }
+ 
+ } // namespace Rust
diff -Nrcpad gcc-16-20251214/gcc/rust/parse/rust-parse-impl-lexer.cc gcc-16-20251221/gcc/rust/parse/rust-parse-impl-lexer.cc
*** gcc-16-20251214/gcc/rust/parse/rust-parse-impl-lexer.cc	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/rust/parse/rust-parse-impl-lexer.cc	Sun Dec 21 22:32:07 2025
***************
*** 16,22 ****
  // along with GCC; see the file COPYING3.  If not see
  // <http://www.gnu.org/licenses/>.
  
! #include "rust-parse-impl.h"
  
  namespace Rust {
  
--- 16,22 ----
  // along with GCC; see the file COPYING3.  If not see
  // <http://www.gnu.org/licenses/>.
  
! #include "rust-parse-impl.hxx"
  
  namespace Rust {
  
diff -Nrcpad gcc-16-20251214/gcc/rust/parse/rust-parse-impl-macro.cc gcc-16-20251221/gcc/rust/parse/rust-parse-impl-macro.cc
*** gcc-16-20251214/gcc/rust/parse/rust-parse-impl-macro.cc	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/rust/parse/rust-parse-impl-macro.cc	Sun Dec 21 22:32:07 2025
***************
*** 16,22 ****
  // along with GCC; see the file COPYING3.  If not see
  // <http://www.gnu.org/licenses/>.
  
! #include "rust-parse-impl.h"
  #include "rust-macro-invoc-lexer.h"
  
  namespace Rust {
--- 16,22 ----
  // along with GCC; see the file COPYING3.  If not see
  // <http://www.gnu.org/licenses/>.
  
! #include "rust-parse-impl.hxx"
  #include "rust-macro-invoc-lexer.h"
  
  namespace Rust {
diff -Nrcpad gcc-16-20251214/gcc/rust/parse/rust-parse-impl-macro.hxx gcc-16-20251221/gcc/rust/parse/rust-parse-impl-macro.hxx
*** gcc-16-20251214/gcc/rust/parse/rust-parse-impl-macro.hxx	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/rust/parse/rust-parse-impl-macro.hxx	Sun Dec 21 22:32:07 2025
***************
*** 0 ****
--- 1,621 ----
+ // Copyright (C) 2025 Free Software Foundation, Inc.
+ 
+ // This file is part of GCC.
+ 
+ // GCC is free software; you can redistribute it and/or modify it under
+ // the terms of the GNU General Public License as published by the Free
+ // Software Foundation; either version 3, or (at your option) any later
+ // version.
+ 
+ // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+ // WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ // for more details.
+ 
+ // You should have received a copy of the GNU General Public License
+ // along with GCC; see the file COPYING3.  If not see
+ // <http://www.gnu.org/licenses/>.
+ 
+ /* DO NOT INCLUDE ANYWHERE - this is automatically included
+  *   by rust-parse-impl.h
+  * This is also the reason why there are no include guards. */
+ 
+ #include "rust-parse.h"
+ 
+ namespace Rust {
+ 
+ // Parses a semi-coloned (except for full block) macro invocation item.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::MacroInvocation>
+ Parser<ManagedTokenSource>::parse_macro_invocation_semi (
+   AST::AttrVec outer_attrs)
+ {
+   location_t macro_locus = lexer.peek_token ()->get_locus ();
+   auto path = parse_simple_path ();
+   if (!path)
+     return nullptr;
+ 
+   if (!skip_token (EXCLAM))
+     {
+       // skip after somewhere?
+       return nullptr;
+     }
+ 
+   // save delim type to ensure it is reused later
+   AST::DelimType delim_type = AST::PARENS;
+ 
+   // Map tokens to DelimType
+   const_TokenPtr t = lexer.peek_token ();
+   switch (t->get_id ())
+     {
+     case LEFT_PAREN:
+       delim_type = AST::PARENS;
+       break;
+     case LEFT_SQUARE:
+       delim_type = AST::SQUARE;
+       break;
+     case LEFT_CURLY:
+       delim_type = AST::CURLY;
+       break;
+     default:
+       add_error (Error (t->get_locus (),
+ 			"unexpected token %qs - expecting delimiters (for a "
+ 			"macro invocation semi body)",
+ 			t->get_token_description ()));
+ 
+       return nullptr;
+     }
+   location_t tok_tree_locus = t->get_locus ();
+   lexer.skip_token ();
+ 
+   // parse actual token trees
+   std::vector<std::unique_ptr<AST::TokenTree>> token_trees;
+   auto delim_open
+     = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
+   token_trees.push_back (std::move (delim_open));
+ 
+   t = lexer.peek_token ();
+   // parse token trees until the initial delimiter token is found again
+   while (!Parse::Utils::token_id_matches_delims (t->get_id (), delim_type)
+ 	 && t->get_id () != END_OF_FILE)
+     {
+       auto tree = parse_token_tree ();
+       if (!tree)
+ 	return nullptr;
+ 
+       token_trees.push_back (std::move (tree.value ()));
+ 
+       t = lexer.peek_token ();
+     }
+   auto delim_close
+     = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
+   token_trees.push_back (std::move (delim_close));
+ 
+   AST::DelimTokenTree delim_tok_tree (delim_type, std::move (token_trees),
+ 				      tok_tree_locus);
+   AST::MacroInvocData invoc_data (std::move (path.value ()),
+ 				  std::move (delim_tok_tree));
+ 
+   // parse end delimiters
+   t = lexer.peek_token ();
+   if (Parse::Utils::token_id_matches_delims (t->get_id (), delim_type))
+     {
+       // tokens match opening delimiter, so skip.
+       lexer.skip_token ();
+ 
+       if (delim_type != AST::CURLY)
+ 	{
+ 	  // skip semicolon at end of non-curly macro invocation semis
+ 	  if (!skip_token (SEMICOLON))
+ 	    {
+ 	      // as this is the end, allow recovery (probably) - may change
+ 
+ 	      return AST::MacroInvocation::Regular (std::move (invoc_data),
+ 						    std::move (outer_attrs),
+ 						    macro_locus, true);
+ 	    }
+ 	}
+ 
+       // DEBUG:
+       rust_debug ("skipped token is '%s', next token (current peek) is '%s'",
+ 		  t->get_token_description (),
+ 		  lexer.peek_token ()->get_token_description ());
+ 
+       return AST::MacroInvocation::Regular (std::move (invoc_data),
+ 					    std::move (outer_attrs),
+ 					    macro_locus, true);
+     }
+   else
+     {
+       // tokens don't match opening delimiters, so produce error
+       Error error (t->get_locus (),
+ 		   "unexpected token %qs - expecting closing delimiter %qs "
+ 		   "(for a macro invocation semi)",
+ 		   t->get_token_description (),
+ 		   (delim_type == AST::PARENS
+ 		      ? ")"
+ 		      : (delim_type == AST::SQUARE ? "]" : "}")));
+       add_error (std::move (error));
+ 
+       /* return empty macro invocation despite possibly parsing mostly valid one
+        * - TODO is this a good idea? */
+       return nullptr;
+     }
+ }
+ 
+ // Parses a non-semicoloned macro invocation (i.e. as pattern or expression).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::MacroInvocation>
+ Parser<ManagedTokenSource>::parse_macro_invocation (AST::AttrVec outer_attrs)
+ {
+   // parse macro path
+   auto macro_path = parse_simple_path ();
+   if (!macro_path)
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "failed to parse macro invocation path");
+       add_error (std::move (error));
+ 
+       // skip?
+       return nullptr;
+     }
+ 
+   if (!skip_token (EXCLAM))
+     {
+       // skip after somewhere?
+       return nullptr;
+     }
+ 
+   // parse internal delim token tree
+   auto delim_tok_tree = parse_delim_token_tree ();
+   if (!delim_tok_tree)
+     return nullptr;
+ 
+   location_t macro_locus = macro_path->get_locus ();
+ 
+   return AST::MacroInvocation::Regular (
+     AST::MacroInvocData (std::move (macro_path.value ()),
+ 			 std::move (delim_tok_tree.value ())),
+     std::move (outer_attrs), macro_locus);
+ }
+ 
+ // Parses a macro rule definition - does not parse semicolons.
+ template <typename ManagedTokenSource>
+ AST::MacroRule
+ Parser<ManagedTokenSource>::parse_macro_rule ()
+ {
+   location_t locus = lexer.peek_token ()->get_locus ();
+ 
+   // parse macro matcher
+   AST::MacroMatcher matcher = parse_macro_matcher ();
+ 
+   if (matcher.is_error ())
+     return AST::MacroRule::create_error (locus);
+ 
+   if (!skip_token (MATCH_ARROW))
+     {
+       // skip after somewhere?
+       return AST::MacroRule::create_error (locus);
+     }
+ 
+   // parse transcriber (this is just a delim token tree)
+   location_t token_tree_loc = lexer.peek_token ()->get_locus ();
+   auto delim_token_tree = parse_delim_token_tree ();
+   if (!delim_token_tree)
+     return AST::MacroRule::create_error (token_tree_loc);
+ 
+   AST::MacroTranscriber transcriber (delim_token_tree.value (), token_tree_loc);
+ 
+   return AST::MacroRule (std::move (matcher), std::move (transcriber), locus);
+ }
+ 
+ // Parses a macro matcher (part of a macro rule definition).
+ template <typename ManagedTokenSource>
+ AST::MacroMatcher
+ Parser<ManagedTokenSource>::parse_macro_matcher ()
+ {
+   // save delim type to ensure it is reused later
+   AST::DelimType delim_type = AST::PARENS;
+ 
+   // DEBUG
+   rust_debug ("begun parsing macro matcher");
+ 
+   // Map tokens to DelimType
+   const_TokenPtr t = lexer.peek_token ();
+   location_t locus = t->get_locus ();
+   switch (t->get_id ())
+     {
+     case LEFT_PAREN:
+       delim_type = AST::PARENS;
+       break;
+     case LEFT_SQUARE:
+       delim_type = AST::SQUARE;
+       break;
+     case LEFT_CURLY:
+       delim_type = AST::CURLY;
+       break;
+     default:
+       add_error (Error (
+ 	t->get_locus (),
+ 	"unexpected token %qs - expecting delimiters (for a macro matcher)",
+ 	t->get_token_description ()));
+ 
+       return AST::MacroMatcher::create_error (t->get_locus ());
+     }
+   lexer.skip_token ();
+ 
+   // parse actual macro matches
+   std::vector<std::unique_ptr<AST::MacroMatch>> matches;
+   // Set of possible preceding macro matches to make sure follow-set
+   // restrictions are respected.
+   // TODO: Consider using std::reference_wrapper instead of raw pointers?
+   std::vector<const AST::MacroMatch *> last_matches;
+ 
+   t = lexer.peek_token ();
+   // parse token trees until the initial delimiter token is found again
+   while (!Parse::Utils::token_id_matches_delims (t->get_id (), delim_type))
+     {
+       std::unique_ptr<AST::MacroMatch> match = parse_macro_match ();
+ 
+       if (match == nullptr)
+ 	{
+ 	  Error error (
+ 	    t->get_locus (),
+ 	    "failed to parse macro match for macro matcher - found %qs",
+ 	    t->get_token_description ());
+ 	  add_error (std::move (error));
+ 
+ 	  return AST::MacroMatcher::create_error (t->get_locus ());
+ 	}
+ 
+       if (matches.size () > 0)
+ 	{
+ 	  const auto *last_match = matches.back ().get ();
+ 
+ 	  // We want to check if we are dealing with a zeroable repetition
+ 	  bool zeroable = false;
+ 	  if (last_match->get_macro_match_type ()
+ 	      == AST::MacroMatch::MacroMatchType::Repetition)
+ 	    {
+ 	      auto repetition
+ 		= static_cast<const AST::MacroMatchRepetition *> (last_match);
+ 
+ 	      if (repetition->get_op ()
+ 		  != AST::MacroMatchRepetition::MacroRepOp::ONE_OR_MORE)
+ 		zeroable = true;
+ 	    }
+ 
+ 	  if (!zeroable)
+ 	    last_matches.clear ();
+ 
+ 	  last_matches.emplace_back (last_match);
+ 
+ 	  for (auto last : last_matches)
+ 	    if (!is_match_compatible (*last, *match))
+ 	      return AST::MacroMatcher::create_error (
+ 		match->get_match_locus ());
+ 	}
+ 
+       matches.push_back (std::move (match));
+ 
+       // DEBUG
+       rust_debug ("pushed back a match in macro matcher");
+ 
+       t = lexer.peek_token ();
+     }
+ 
+   // parse end delimiters
+   t = lexer.peek_token ();
+   if (Parse::Utils::token_id_matches_delims (t->get_id (), delim_type))
+     {
+       // tokens match opening delimiter, so skip.
+       lexer.skip_token ();
+ 
+       return AST::MacroMatcher (delim_type, std::move (matches), locus);
+     }
+   else
+     {
+       // tokens don't match opening delimiters, so produce error
+       Error error (t->get_locus (),
+ 		   "unexpected token %qs - expecting closing delimiter %qs "
+ 		   "(for a macro matcher)",
+ 		   t->get_token_description (),
+ 		   (delim_type == AST::PARENS
+ 		      ? ")"
+ 		      : (delim_type == AST::SQUARE ? "]" : "}")));
+       add_error (std::move (error));
+ 
+       /* return error macro matcher despite possibly parsing mostly correct one?
+        * TODO is this the best idea? */
+       return AST::MacroMatcher::create_error (t->get_locus ());
+     }
+ }
+ 
+ // Parses a macro match (syntax match inside a matcher in a macro rule).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::MacroMatch>
+ Parser<ManagedTokenSource>::parse_macro_match ()
+ {
+   // branch based on token available
+   const_TokenPtr t = lexer.peek_token ();
+   switch (t->get_id ())
+     {
+     case LEFT_PAREN:
+     case LEFT_SQUARE:
+     case LEFT_CURLY:
+       {
+ 	// must be macro matcher as delimited
+ 	AST::MacroMatcher matcher = parse_macro_matcher ();
+ 	if (matcher.is_error ())
+ 	  {
+ 	    Error error (lexer.peek_token ()->get_locus (),
+ 			 "failed to parse macro matcher in macro match");
+ 	    add_error (std::move (error));
+ 
+ 	    return nullptr;
+ 	  }
+ 	return std::unique_ptr<AST::MacroMatcher> (
+ 	  new AST::MacroMatcher (std::move (matcher)));
+       }
+     case DOLLAR_SIGN:
+       {
+ 	// have to do more lookahead to determine if fragment or repetition
+ 	const_TokenPtr t2 = lexer.peek_token (1);
+ 	switch (t2->get_id ())
+ 	  {
+ 	  case IDENTIFIER:
+ 	  case UNDERSCORE:
+ 	    // macro fragment
+ 	    return parse_macro_match_fragment ();
+ 	  case LEFT_PAREN:
+ 	    // macro repetition
+ 	    return parse_macro_match_repetition ();
+ 	  default:
+ 	    if (token_id_is_keyword (t2->get_id ()) && t2->get_id () != CRATE)
+ 	      {
+ 		// keyword as macro fragment
+ 		return parse_macro_match_fragment ();
+ 	      }
+ 	    else
+ 	      {
+ 		// error: unrecognised
+ 		add_error (Error (
+ 		  t2->get_locus (),
+ 		  "unrecognised token combination %<$%s%> at start of "
+ 		  "macro match - did you mean %<$identifier%> or %<$(%>?",
+ 		  t2->get_token_description ()));
+ 
+ 		// skip somewhere?
+ 		return nullptr;
+ 	      }
+ 	  }
+       }
+     case RIGHT_PAREN:
+     case RIGHT_SQUARE:
+     case RIGHT_CURLY:
+       // not allowed
+       add_error (Error (
+ 	t->get_locus (),
+ 	"closing delimiters like %qs are not allowed at the start of a macro "
+ 	"match",
+ 	t->get_token_description ()));
+ 
+       // skip somewhere?
+       return nullptr;
+     default:
+       // just the token
+       lexer.skip_token ();
+       return std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
+     }
+ }
+ 
+ // Parses a fragment macro match.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::MacroMatchFragment>
+ Parser<ManagedTokenSource>::parse_macro_match_fragment ()
+ {
+   location_t fragment_locus = lexer.peek_token ()->get_locus ();
+   skip_token (DOLLAR_SIGN);
+ 
+   Identifier ident;
+   auto identifier = lexer.peek_token ();
+   if (identifier->get_id () == UNDERSCORE)
+     ident = {Values::Keywords::UNDERSCORE, identifier->get_locus ()};
+   else
+     ident = {identifier};
+ 
+   if (ident.empty ())
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "missing identifier in macro match fragment");
+       add_error (std::move (error));
+ 
+       return nullptr;
+     }
+   skip_token (identifier->get_id ());
+ 
+   if (!skip_token (COLON))
+     {
+       // skip after somewhere?
+       return nullptr;
+     }
+ 
+   // get MacroFragSpec for macro
+   const_TokenPtr t = expect_token (IDENTIFIER);
+   if (t == nullptr)
+     return nullptr;
+ 
+   AST::MacroFragSpec frag
+     = AST::MacroFragSpec::get_frag_spec_from_str (t->get_str ());
+   if (frag.is_error ())
+     {
+       Error error (t->get_locus (),
+ 		   "invalid fragment specifier %qs in fragment macro match",
+ 		   t->get_str ().c_str ());
+       add_error (std::move (error));
+ 
+       return nullptr;
+     }
+ 
+   return std::unique_ptr<AST::MacroMatchFragment> (
+     new AST::MacroMatchFragment (std::move (ident), frag, fragment_locus));
+ }
+ 
+ // Parses a repetition macro match.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::MacroMatchRepetition>
+ Parser<ManagedTokenSource>::parse_macro_match_repetition ()
+ {
+   skip_token (DOLLAR_SIGN);
+   skip_token (LEFT_PAREN);
+ 
+   std::vector<std::unique_ptr<AST::MacroMatch>> matches;
+ 
+   // parse required first macro match
+   std::unique_ptr<AST::MacroMatch> initial_match = parse_macro_match ();
+   if (initial_match == nullptr)
+     {
+       Error error (
+ 	lexer.peek_token ()->get_locus (),
+ 	"could not parse required first macro match in macro match repetition");
+       add_error (std::move (error));
+ 
+       // skip after somewhere?
+       return nullptr;
+     }
+   matches.push_back (std::move (initial_match));
+ 
+   // parse optional later macro matches
+   const_TokenPtr t = lexer.peek_token ();
+   while (t->get_id () != RIGHT_PAREN)
+     {
+       std::unique_ptr<AST::MacroMatch> match = parse_macro_match ();
+ 
+       if (match == nullptr)
+ 	{
+ 	  Error error (lexer.peek_token ()->get_locus (),
+ 		       "failed to parse macro match in macro match repetition");
+ 	  add_error (std::move (error));
+ 
+ 	  return nullptr;
+ 	}
+ 
+       matches.push_back (std::move (match));
+ 
+       t = lexer.peek_token ();
+     }
+ 
+   if (!skip_token (RIGHT_PAREN))
+     {
+       // skip after somewhere?
+       return nullptr;
+     }
+ 
+   t = lexer.peek_token ();
+   // see if separator token exists
+   std::unique_ptr<AST::Token> separator = nullptr;
+   switch (t->get_id ())
+     {
+     // repetition operators
+     case ASTERISK:
+     case PLUS:
+     case QUESTION_MARK:
+     // delimiters
+     case LEFT_PAREN:
+     case LEFT_CURLY:
+     case LEFT_SQUARE:
+     case RIGHT_PAREN:
+     case RIGHT_CURLY:
+     case RIGHT_SQUARE:
+       // separator does not exist, so still null and don't skip token
+       break;
+     default:
+       // separator does exist
+       separator = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
+       lexer.skip_token ();
+       break;
+     }
+ 
+   // parse repetition operator
+   t = lexer.peek_token ();
+   AST::MacroMatchRepetition::MacroRepOp op = AST::MacroMatchRepetition::NONE;
+   switch (t->get_id ())
+     {
+     case ASTERISK:
+       op = AST::MacroMatchRepetition::ANY;
+       lexer.skip_token ();
+       break;
+     case PLUS:
+       op = AST::MacroMatchRepetition::ONE_OR_MORE;
+       lexer.skip_token ();
+       break;
+     case QUESTION_MARK:
+       op = AST::MacroMatchRepetition::ZERO_OR_ONE;
+       lexer.skip_token ();
+ 
+       if (separator != nullptr)
+ 	{
+ 	  add_error (
+ 	    Error (separator->get_locus (),
+ 		   "the %<?%> macro repetition operator does not take a "
+ 		   "separator"));
+ 	  separator = nullptr;
+ 	}
+ 
+       break;
+     default:
+       add_error (
+ 	Error (t->get_locus (),
+ 	       "expected macro repetition operator (%<*%>, %<+%>, or %<?%>) in "
+ 	       "macro match - found %qs",
+ 	       t->get_token_description ()));
+ 
+       // skip after somewhere?
+       return nullptr;
+     }
+ 
+   return std::unique_ptr<AST::MacroMatchRepetition> (
+     new AST::MacroMatchRepetition (std::move (matches), op,
+ 				   std::move (separator), t->get_locus ()));
+ }
+ 
+ /* Parses a macro invocation with a path in expression already parsed (but not
+  * '!' token). */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::MacroInvocation>
+ Parser<ManagedTokenSource>::parse_macro_invocation_partial (
+   AST::PathInExpression path, AST::AttrVec outer_attrs,
+   ParseRestrictions restrictions)
+ {
+   // macro invocation
+   if (!skip_token (EXCLAM))
+     {
+       return nullptr;
+     }
+ 
+   // convert PathInExpression to SimplePath - if this isn't possible, error
+   AST::SimplePath converted_path = path.as_simple_path ();
+   if (converted_path.is_empty ())
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "failed to parse simple path in macro invocation");
+       add_error (std::move (error));
+ 
+       return nullptr;
+     }
+ 
+   auto tok_tree = parse_delim_token_tree ();
+   if (!tok_tree)
+     return nullptr;
+ 
+   rust_debug ("successfully parsed macro invocation (via partial)");
+ 
+   location_t macro_locus = converted_path.get_locus ();
+ 
+   return AST::MacroInvocation::Regular (
+     AST::MacroInvocData (std::move (converted_path),
+ 			 std::move (tok_tree.value ())),
+     std::move (outer_attrs), macro_locus);
+ }
+ 
+ } // namespace Rust
diff -Nrcpad gcc-16-20251214/gcc/rust/parse/rust-parse-impl-path.hxx gcc-16-20251221/gcc/rust/parse/rust-parse-impl-path.hxx
*** gcc-16-20251214/gcc/rust/parse/rust-parse-impl-path.hxx	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/rust/parse/rust-parse-impl-path.hxx	Sun Dec 21 22:32:07 2025
***************
*** 0 ****
--- 1,679 ----
+ // Copyright (C) 2025 Free Software Foundation, Inc.
+ 
+ // This file is part of GCC.
+ 
+ // GCC is free software; you can redistribute it and/or modify it under
+ // the terms of the GNU General Public License as published by the Free
+ // Software Foundation; either version 3, or (at your option) any later
+ // version.
+ 
+ // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+ // WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ // for more details.
+ 
+ // You should have received a copy of the GNU General Public License
+ // along with GCC; see the file COPYING3.  If not see
+ // <http://www.gnu.org/licenses/>.
+ 
+ /* DO NOT INCLUDE ANYWHERE - this is automatically included
+  *   by rust-parse-impl.h
+  * This is also the reason why there are no include guards. */
+ 
+ #include "rust-parse.h"
+ 
+ namespace Rust {
+ 
+ // Parses a SimplePath AST node, if it exists. Does nothing otherwise.
+ template <typename ManagedTokenSource>
+ tl::expected<AST::SimplePath, Parse::Error::SimplePath>
+ Parser<ManagedTokenSource>::parse_simple_path ()
+ {
+   bool has_opening_scope_resolution = false;
+   location_t locus = UNKNOWN_LOCATION;
+ 
+   using Parse::Utils::is_simple_path_segment;
+ 
+   // don't parse anything if not a path upfront
+   if (!is_simple_path_segment (lexer.peek_token ()->get_id ())
+       && !is_simple_path_segment (lexer.peek_token (1)->get_id ()))
+     return Parse::Error::SimplePath::make_malformed ();
+ 
+   /* Checks for opening scope resolution (i.e. global scope fully-qualified
+    * path) */
+   if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION)
+     {
+       has_opening_scope_resolution = true;
+ 
+       locus = lexer.peek_token ()->get_locus ();
+ 
+       lexer.skip_token ();
+     }
+ 
+   // Parse single required simple path segment
+   auto segment = parse_simple_path_segment ();
+ 
+   if (!segment)
+     return Parse::Error::SimplePath::make_malformed ();
+ 
+   // get location if not gotten already
+   if (locus == UNKNOWN_LOCATION)
+     locus = segment->get_locus ();
+ 
+   std::vector<AST::SimplePathSegment> segments;
+   segments.push_back (std::move (segment.value ()));
+ 
+   // Parse all other simple path segments
+   while (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION)
+     {
+       auto new_segment = parse_simple_path_segment (1);
+ 
+       using Error = Parse::Error::SimplePathSegment::Kind;
+       // Return path as currently constructed if segment in error state.
+       if (!new_segment)
+ 	{
+ 	  if (new_segment.error ().kind == Error::INVALID_SIMPLE_PATH_TOKEN)
+ 	    break; /* Could be end of path */
+ 	  else	   /* Any other error is an hard error */
+ 	    return Parse::Error::SimplePath::make_malformed ();
+ 	}
+ 
+       segments.push_back (std::move (new_segment.value ()));
+     }
+ 
+   return AST::SimplePath (std::move (segments), has_opening_scope_resolution,
+ 			  locus);
+   /* TODO: now that is_simple_path_segment exists, could probably start
+    * actually making errors upon parse failure of segments and whatever */
+ }
+ 
+ /* Parses a single SimplePathSegment (does not handle the scope resolution
+  * operators)
+  * Starts parsing at an offset of base_peek */
+ template <typename ManagedTokenSource>
+ tl::expected<AST::SimplePathSegment, Parse::Error::SimplePathSegment>
+ Parser<ManagedTokenSource>::parse_simple_path_segment (int base_peek)
+ {
+   using namespace Values;
+   const_TokenPtr t = lexer.peek_token (base_peek);
+   switch (t->get_id ())
+     {
+     case IDENTIFIER:
+       lexer.skip_token (base_peek);
+ 
+       return AST::SimplePathSegment (t->get_str (), t->get_locus ());
+     case SUPER:
+       lexer.skip_token (base_peek);
+ 
+       return AST::SimplePathSegment (Keywords::SUPER, t->get_locus ());
+     case SELF:
+       lexer.skip_token (base_peek);
+ 
+       return AST::SimplePathSegment (Keywords::SELF, t->get_locus ());
+     case CRATE:
+       lexer.skip_token (base_peek);
+ 
+       return AST::SimplePathSegment (Keywords::CRATE, t->get_locus ());
+     case DOLLAR_SIGN:
+       if (lexer.peek_token (base_peek + 1)->get_id () == CRATE)
+ 	{
+ 	  lexer.skip_token (base_peek + 1);
+ 
+ 	  return AST::SimplePathSegment ("$crate", t->get_locus ());
+ 	}
+       gcc_fallthrough ();
+     default:
+       // do nothing but inactivates warning from gcc when compiling
+       /* could put the rust_error_at thing here but fallthrough (from failing
+        * $crate condition) isn't completely obvious if it is. */
+ 
+       return Parse::Error::SimplePathSegment::make_invalid_token_or_path_end ();
+     }
+   rust_unreachable ();
+ }
+ 
+ // Parses a PathIdentSegment - an identifier segment of a non-SimplePath path.
+ template <typename ManagedTokenSource>
+ tl::expected<AST::PathIdentSegment, Parse::Error::PathIdentSegment>
+ Parser<ManagedTokenSource>::parse_path_ident_segment ()
+ {
+   const_TokenPtr t = lexer.peek_token ();
+   switch (t->get_id ())
+     {
+     case IDENTIFIER:
+       lexer.skip_token ();
+ 
+       return AST::PathIdentSegment (t->get_str (), t->get_locus ());
+     case SUPER:
+       lexer.skip_token ();
+ 
+       return AST::PathIdentSegment (Values::Keywords::SUPER, t->get_locus ());
+     case SELF:
+       lexer.skip_token ();
+ 
+       return AST::PathIdentSegment (Values::Keywords::SELF, t->get_locus ());
+     case SELF_ALIAS:
+       lexer.skip_token ();
+ 
+       return AST::PathIdentSegment (Values::Keywords::SELF_ALIAS,
+ 				    t->get_locus ());
+     case CRATE:
+       lexer.skip_token ();
+ 
+       return AST::PathIdentSegment (Values::Keywords::CRATE, t->get_locus ());
+     case DOLLAR_SIGN:
+       if (lexer.peek_token (1)->get_id () == CRATE)
+ 	{
+ 	  lexer.skip_token (1);
+ 
+ 	  return AST::PathIdentSegment ("$crate", t->get_locus ());
+ 	}
+       gcc_fallthrough ();
+     default:
+       /* do nothing but inactivates warning from gcc when compiling
+        * could put the error_at thing here but fallthrough (from failing $crate
+        * condition) isn't completely obvious if it is. */
+ 
+       // test prevent error
+       return Parse::Error::PathIdentSegment::make_invalid_token ();
+     }
+   rust_unreachable ();
+ }
+ 
+ // Parses a type path.
+ template <typename ManagedTokenSource>
+ AST::TypePath
+ Parser<ManagedTokenSource>::parse_type_path ()
+ {
+   bool has_opening_scope_resolution = false;
+   location_t locus = lexer.peek_token ()->get_locus ();
+   if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION)
+     {
+       has_opening_scope_resolution = true;
+       lexer.skip_token ();
+     }
+ 
+   // create segment vector
+   std::vector<std::unique_ptr<AST::TypePathSegment>> segments;
+ 
+   // parse required initial segment
+   std::unique_ptr<AST::TypePathSegment> initial_segment
+     = parse_type_path_segment ();
+   if (initial_segment == nullptr)
+     {
+       // skip after somewhere?
+       // don't necessarily throw error but yeah
+       return AST::TypePath::create_error ();
+     }
+   segments.push_back (std::move (initial_segment));
+ 
+   // parse optional segments (as long as scope resolution operator exists)
+   const_TokenPtr t = lexer.peek_token ();
+   while (t->get_id () == SCOPE_RESOLUTION)
+     {
+       // skip scope resolution operator
+       lexer.skip_token ();
+ 
+       // parse the actual segment - it is an error if it doesn't exist now
+       std::unique_ptr<AST::TypePathSegment> segment
+ 	= parse_type_path_segment ();
+       if (segment == nullptr)
+ 	{
+ 	  // skip after somewhere?
+ 	  Error error (t->get_locus (), "could not parse type path segment");
+ 	  add_error (std::move (error));
+ 
+ 	  return AST::TypePath::create_error ();
+ 	}
+ 
+       segments.push_back (std::move (segment));
+ 
+       t = lexer.peek_token ();
+     }
+ 
+   segments.shrink_to_fit ();
+ 
+   return AST::TypePath (std::move (segments), locus,
+ 			has_opening_scope_resolution);
+ }
+ 
+ /* Parses a single type path segment (not including opening scope resolution,
+  * but includes any internal ones). Includes generic args or type path
+  * functions too. */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::TypePathSegment>
+ Parser<ManagedTokenSource>::parse_type_path_segment ()
+ {
+   location_t locus = lexer.peek_token ()->get_locus ();
+   // parse ident segment part
+   auto ident_segment_res = parse_path_ident_segment ();
+   if (!ident_segment_res)
+     {
+       // not necessarily an error
+       return nullptr;
+     }
+   auto ident_segment = ident_segment_res.value ();
+ 
+   /* lookahead to determine if variants exist - only consume scope resolution
+    * then */
+   bool has_separating_scope_resolution = false;
+   const_TokenPtr next = lexer.peek_token (1);
+   if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION
+       && (next->get_id () == LEFT_ANGLE || next->get_id () == LEFT_PAREN))
+     {
+       has_separating_scope_resolution = true;
+       lexer.skip_token ();
+     }
+ 
+   // branch into variants on next token
+   const_TokenPtr t = lexer.peek_token ();
+   switch (t->get_id ())
+     {
+     case LEFT_SHIFT:
+     case LEFT_ANGLE:
+       {
+ 	// parse generic args
+ 	AST::GenericArgs generic_args = parse_path_generic_args ();
+ 
+ 	return std::unique_ptr<AST::TypePathSegmentGeneric> (
+ 	  new AST::TypePathSegmentGeneric (std::move (ident_segment),
+ 					   has_separating_scope_resolution,
+ 					   std::move (generic_args), locus));
+       }
+     case LEFT_PAREN:
+       {
+ 	// parse type path function
+ 	AST::TypePathFunction type_path_function
+ 	  = parse_type_path_function (locus);
+ 
+ 	if (type_path_function.is_error ())
+ 	  {
+ 	    // skip after somewhere?
+ 	    return nullptr;
+ 	  }
+ 
+ 	return std::unique_ptr<AST::TypePathSegmentFunction> (
+ 	  new AST::TypePathSegmentFunction (std::move (ident_segment),
+ 					    has_separating_scope_resolution,
+ 					    std::move (type_path_function),
+ 					    locus));
+       }
+     default:
+       // neither of them
+       return std::unique_ptr<AST::TypePathSegment> (
+ 	new AST::TypePathSegment (std::move (ident_segment),
+ 				  has_separating_scope_resolution, locus));
+     }
+   rust_unreachable ();
+ }
+ 
+ // Parses a function call representation inside a type path.
+ template <typename ManagedTokenSource>
+ AST::TypePathFunction
+ Parser<ManagedTokenSource>::parse_type_path_function (location_t id_location)
+ {
+   if (!skip_token (LEFT_PAREN))
+     {
+       // skip somewhere?
+       return AST::TypePathFunction::create_error ();
+     }
+ 
+   // parse function inputs
+   std::vector<std::unique_ptr<AST::Type>> inputs;
+ 
+   while (lexer.peek_token ()->get_id () != RIGHT_PAREN)
+     {
+       std::unique_ptr<AST::Type> type = parse_type ();
+       if (type == nullptr)
+ 	{
+ 	  /* this is an error as there should've been a ')' there if there
+ 	   * wasn't a type */
+ 	  Error error (
+ 	    lexer.peek_token ()->get_locus (),
+ 	    "failed to parse type in parameters of type path function");
+ 	  add_error (std::move (error));
+ 
+ 	  // skip somewhere?
+ 	  return AST::TypePathFunction::create_error ();
+ 	}
+ 
+       inputs.push_back (std::move (type));
+ 
+       // skip commas, including trailing commas
+       if (lexer.peek_token ()->get_id () != COMMA)
+ 	break;
+ 
+       lexer.skip_token ();
+     }
+ 
+   if (!skip_token (RIGHT_PAREN))
+     {
+       // skip somewhere?
+       return AST::TypePathFunction::create_error ();
+     }
+ 
+   // parse optional return type
+   std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
+ 
+   inputs.shrink_to_fit ();
+   return AST::TypePathFunction (std::move (inputs), id_location,
+ 				std::move (return_type));
+ }
+ 
+ // Parses a path inside an expression that allows generic arguments.
+ template <typename ManagedTokenSource>
+ AST::PathInExpression
+ Parser<ManagedTokenSource>::parse_path_in_expression ()
+ {
+   location_t locus = UNKNOWN_LOCATION;
+   bool has_opening_scope_resolution = false;
+   if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION)
+     {
+       has_opening_scope_resolution = true;
+ 
+       locus = lexer.peek_token ()->get_locus ();
+ 
+       lexer.skip_token ();
+     }
+ 
+   // create segment vector
+   std::vector<AST::PathExprSegment> segments;
+ 
+   if (locus == UNKNOWN_LOCATION)
+     {
+       locus = lexer.peek_token ()->get_locus ();
+     }
+ 
+   // parse required initial segment
+   AST::PathExprSegment initial_segment = parse_path_expr_segment ();
+   if (initial_segment.is_error ())
+     {
+       // skip after somewhere?
+       // don't necessarily throw error but yeah
+       return AST::PathInExpression::create_error ();
+     }
+   segments.push_back (std::move (initial_segment));
+ 
+   // parse optional segments (as long as scope resolution operator exists)
+   const_TokenPtr t = lexer.peek_token ();
+   while (t->get_id () == SCOPE_RESOLUTION)
+     {
+       // skip scope resolution operator
+       lexer.skip_token ();
+ 
+       // parse the actual segment - it is an error if it doesn't exist now
+       AST::PathExprSegment segment = parse_path_expr_segment ();
+       if (segment.is_error ())
+ 	{
+ 	  // skip after somewhere?
+ 	  Error error (t->get_locus (),
+ 		       "could not parse path expression segment");
+ 	  add_error (std::move (error));
+ 
+ 	  return AST::PathInExpression::create_error ();
+ 	}
+ 
+       segments.push_back (std::move (segment));
+ 
+       t = lexer.peek_token ();
+     }
+ 
+   segments.shrink_to_fit ();
+ 
+   return AST::PathInExpression (std::move (segments), {}, locus,
+ 				has_opening_scope_resolution);
+ }
+ 
+ /* Parses a single path in expression path segment (including generic
+  * arguments). */
+ template <typename ManagedTokenSource>
+ AST::PathExprSegment
+ Parser<ManagedTokenSource>::parse_path_expr_segment ()
+ {
+   location_t locus = lexer.peek_token ()->get_locus ();
+   // parse ident segment
+   auto ident_result = parse_path_ident_segment ();
+   if (!ident_result)
+     {
+       // not necessarily an error?
+       return AST::PathExprSegment::create_error ();
+     }
+   auto ident = ident_result.value ();
+ 
+   // parse generic args (and turbofish), if they exist
+   /* use lookahead to determine if they actually exist (don't want to
+    * accidently parse over next ident segment) */
+   if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION
+       && (lexer.peek_token (1)->get_id () == LEFT_ANGLE
+ 	  || lexer.peek_token (1)->get_id () == LEFT_SHIFT))
+     {
+       // skip scope resolution
+       lexer.skip_token ();
+ 
+       // Let parse_path_generic_args split "<<" tokens
+       AST::GenericArgs generic_args = parse_path_generic_args ();
+ 
+       return AST::PathExprSegment (std::move (ident), locus,
+ 				   std::move (generic_args));
+     }
+ 
+   // return a generic parameter-less expr segment if not found
+   return AST::PathExprSegment (std::move (ident), locus);
+ }
+ 
+ /* Parses a fully qualified path in expression (i.e. a pattern). FIXME does
+  * not parse outer attrs. */
+ template <typename ManagedTokenSource>
+ AST::QualifiedPathInExpression
+ Parser<ManagedTokenSource>::parse_qualified_path_in_expression (
+   location_t pratt_parsed_loc)
+ {
+   /* Note: the Rust grammar is defined in such a way that it is impossible to
+    * determine whether a prospective qualified path is a
+    * QualifiedPathInExpression or QualifiedPathInType in all cases by the
+    * rules themselves (the only possible difference is a TypePathSegment with
+    * function, and lookahead to find this is too difficult). However, as this
+    * is a pattern and QualifiedPathInType is a type, I believe it that their
+    * construction will not be confused (due to rules regarding patterns vs
+    * types).
+    * As such, this function will not attempt to minimise errors created by
+    * their confusion. */
+ 
+   // parse the qualified path type (required)
+   AST::QualifiedPathType qual_path_type
+     = parse_qualified_path_type (pratt_parsed_loc);
+   if (qual_path_type.is_error ())
+     {
+       // TODO: should this create a parse error?
+       return AST::QualifiedPathInExpression::create_error ();
+     }
+   location_t locus = qual_path_type.get_locus ();
+ 
+   // parse path segments
+   std::vector<AST::PathExprSegment> segments;
+ 
+   // parse initial required segment
+   if (!expect_token (SCOPE_RESOLUTION))
+     {
+       // skip after somewhere?
+ 
+       return AST::QualifiedPathInExpression::create_error ();
+     }
+   AST::PathExprSegment initial_segment = parse_path_expr_segment ();
+   if (initial_segment.is_error ())
+     {
+       // skip after somewhere?
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "required initial path expression segment in "
+ 		   "qualified path in expression could not be parsed");
+       add_error (std::move (error));
+ 
+       return AST::QualifiedPathInExpression::create_error ();
+     }
+   segments.push_back (std::move (initial_segment));
+ 
+   // parse optional segments (as long as scope resolution operator exists)
+   const_TokenPtr t = lexer.peek_token ();
+   while (t->get_id () == SCOPE_RESOLUTION)
+     {
+       // skip scope resolution operator
+       lexer.skip_token ();
+ 
+       // parse the actual segment - it is an error if it doesn't exist now
+       AST::PathExprSegment segment = parse_path_expr_segment ();
+       if (segment.is_error ())
+ 	{
+ 	  // skip after somewhere?
+ 	  Error error (t->get_locus (),
+ 		       "could not parse path expression segment in qualified "
+ 		       "path in expression");
+ 	  add_error (std::move (error));
+ 
+ 	  return AST::QualifiedPathInExpression::create_error ();
+ 	}
+ 
+       segments.push_back (std::move (segment));
+ 
+       t = lexer.peek_token ();
+     }
+ 
+   segments.shrink_to_fit ();
+ 
+   // FIXME: outer attr parsing
+   return AST::QualifiedPathInExpression (std::move (qual_path_type),
+ 					 std::move (segments), {}, locus);
+ }
+ 
+ // Parses the type syntactical construction at the start of a qualified path.
+ template <typename ManagedTokenSource>
+ AST::QualifiedPathType
+ Parser<ManagedTokenSource>::parse_qualified_path_type (
+   location_t pratt_parsed_loc)
+ {
+   location_t locus = pratt_parsed_loc;
+   /* TODO: should this actually be error? is there anywhere where this could
+    * be valid? */
+   if (locus == UNKNOWN_LOCATION)
+     {
+       locus = lexer.peek_token ()->get_locus ();
+ 
+       if (lexer.peek_token ()->get_id () == LEFT_SHIFT)
+ 	lexer.split_current_token (LEFT_ANGLE, LEFT_ANGLE);
+ 
+       // skip after somewhere?
+       if (!skip_token (LEFT_ANGLE))
+ 	return AST::QualifiedPathType::create_error ();
+     }
+ 
+   // parse type (required)
+   std::unique_ptr<AST::Type> type = parse_type ();
+   if (type == nullptr)
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "could not parse type in qualified path type");
+       add_error (std::move (error));
+ 
+       // skip somewhere?
+       return AST::QualifiedPathType::create_error ();
+     }
+ 
+   // parse optional as clause
+   AST::TypePath as_type_path = AST::TypePath::create_error ();
+   if (lexer.peek_token ()->get_id () == AS)
+     {
+       lexer.skip_token ();
+ 
+       // parse type path, which is required now
+       as_type_path = parse_type_path ();
+       if (as_type_path.is_error ())
+ 	{
+ 	  Error error (
+ 	    lexer.peek_token ()->get_locus (),
+ 	    "could not parse type path in as clause in qualified path type");
+ 	  add_error (std::move (error));
+ 
+ 	  // skip somewhere?
+ 	  return AST::QualifiedPathType::create_error ();
+ 	}
+     }
+ 
+   /* NOTE: should actually be a right-angle token, so
+    * skip_generics_right_angle shouldn't be required */
+   if (!skip_token (RIGHT_ANGLE))
+     {
+       // skip after somewhere?
+       return AST::QualifiedPathType::create_error ();
+     }
+ 
+   return AST::QualifiedPathType (std::move (type), locus,
+ 				 std::move (as_type_path));
+ }
+ 
+ // Parses a fully qualified path in type (i.e. a type).
+ template <typename ManagedTokenSource>
+ AST::QualifiedPathInType
+ Parser<ManagedTokenSource>::parse_qualified_path_in_type ()
+ {
+   location_t locus = lexer.peek_token ()->get_locus ();
+   // parse the qualified path type (required)
+   AST::QualifiedPathType qual_path_type = parse_qualified_path_type ();
+   if (qual_path_type.is_error ())
+     {
+       // TODO: should this create a parse error?
+       return AST::QualifiedPathInType::create_error ();
+     }
+ 
+   // parse initial required segment
+   if (!expect_token (SCOPE_RESOLUTION))
+     {
+       // skip after somewhere?
+ 
+       return AST::QualifiedPathInType::create_error ();
+     }
+   std::unique_ptr<AST::TypePathSegment> initial_segment
+     = parse_type_path_segment ();
+   if (initial_segment == nullptr)
+     {
+       // skip after somewhere?
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "required initial type path segment in qualified path in "
+ 		   "type could not be parsed");
+       add_error (std::move (error));
+ 
+       return AST::QualifiedPathInType::create_error ();
+     }
+ 
+   // parse optional segments (as long as scope resolution operator exists)
+   std::vector<std::unique_ptr<AST::TypePathSegment>> segments;
+   const_TokenPtr t = lexer.peek_token ();
+   while (t->get_id () == SCOPE_RESOLUTION)
+     {
+       // skip scope resolution operator
+       lexer.skip_token ();
+ 
+       // parse the actual segment - it is an error if it doesn't exist now
+       std::unique_ptr<AST::TypePathSegment> segment
+ 	= parse_type_path_segment ();
+       if (segment == nullptr)
+ 	{
+ 	  // skip after somewhere?
+ 	  Error error (
+ 	    t->get_locus (),
+ 	    "could not parse type path segment in qualified path in type");
+ 	  add_error (std::move (error));
+ 
+ 	  return AST::QualifiedPathInType::create_error ();
+ 	}
+ 
+       segments.push_back (std::move (segment));
+ 
+       t = lexer.peek_token ();
+     }
+ 
+   segments.shrink_to_fit ();
+ 
+   return AST::QualifiedPathInType (std::move (qual_path_type),
+ 				   std::move (initial_segment),
+ 				   std::move (segments), locus);
+ }
+ } // namespace Rust
diff -Nrcpad gcc-16-20251214/gcc/rust/parse/rust-parse-impl-pattern.hxx gcc-16-20251221/gcc/rust/parse/rust-parse-impl-pattern.hxx
*** gcc-16-20251214/gcc/rust/parse/rust-parse-impl-pattern.hxx	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/rust/parse/rust-parse-impl-pattern.hxx	Sun Dec 21 22:32:07 2025
***************
*** 0 ****
--- 1,1253 ----
+ // Copyright (C) 2025 Free Software Foundation, Inc.
+ 
+ // This file is part of GCC.
+ 
+ // GCC is free software; you can redistribute it and/or modify it under
+ // the terms of the GNU General Public License as published by the Free
+ // Software Foundation; either version 3, or (at your option) any later
+ // version.
+ 
+ // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+ // WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ // for more details.
+ 
+ // You should have received a copy of the GNU General Public License
+ // along with GCC; see the file COPYING3.  If not see
+ // <http://www.gnu.org/licenses/>.
+ 
+ /* DO NOT INCLUDE ANYWHERE - this is automatically included
+  *   by rust-parse-impl.h
+  * This is also the reason why there are no include guards. */
+ 
+ #include "rust-parse.h"
+ 
+ namespace Rust {
+ 
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::Pattern>
+ Parser<ManagedTokenSource>::parse_pattern ()
+ {
+   location_t start_locus = lexer.peek_token ()->get_locus ();
+ 
+   /* skip optional starting pipe */
+   maybe_skip_token (PIPE);
+ 
+   auto first = parse_pattern_no_alt ();
+ 
+   if (lexer.peek_token ()->get_id () != PIPE)
+     /* no alternates */
+     return first;
+ 
+   std::vector<std::unique_ptr<AST::Pattern>> alts;
+   if (first != nullptr)
+     alts.push_back (std::move (first));
+ 
+   do
+     {
+       lexer.skip_token ();
+       auto follow = parse_pattern_no_alt ();
+       if (follow != nullptr)
+ 	alts.push_back (std::move (follow));
+     }
+ 
+   while (lexer.peek_token ()->get_id () == PIPE);
+ 
+   if (alts.empty ())
+     return nullptr;
+ 
+   /* alternates */
+   return std::unique_ptr<AST::Pattern> (
+     new AST::AltPattern (std::move (alts), start_locus));
+ }
+ 
+ // Parses a pattern without alternates ('|')
+ // (will further disambiguate any pattern).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::Pattern>
+ Parser<ManagedTokenSource>::parse_pattern_no_alt ()
+ {
+   const_TokenPtr t = lexer.peek_token ();
+   switch (t->get_id ())
+     {
+     case TRUE_LITERAL:
+       lexer.skip_token ();
+       return std::unique_ptr<AST::LiteralPattern> (
+ 	new AST::LiteralPattern (Values::Keywords::TRUE_LITERAL,
+ 				 AST::Literal::BOOL, t->get_locus (),
+ 				 t->get_type_hint ()));
+     case FALSE_LITERAL:
+       lexer.skip_token ();
+       return std::unique_ptr<AST::LiteralPattern> (
+ 	new AST::LiteralPattern (Values::Keywords::FALSE_LITERAL,
+ 				 AST::Literal::BOOL, t->get_locus (),
+ 				 t->get_type_hint ()));
+     case CHAR_LITERAL:
+     case BYTE_CHAR_LITERAL:
+     case INT_LITERAL:
+     case FLOAT_LITERAL:
+       return parse_literal_or_range_pattern ();
+     case STRING_LITERAL:
+       lexer.skip_token ();
+       return std::unique_ptr<AST::LiteralPattern> (
+ 	new AST::LiteralPattern (t->get_str (), AST::Literal::STRING,
+ 				 t->get_locus (), t->get_type_hint ()));
+     case BYTE_STRING_LITERAL:
+       lexer.skip_token ();
+       return std::unique_ptr<AST::LiteralPattern> (
+ 	new AST::LiteralPattern (t->get_str (), AST::Literal::BYTE_STRING,
+ 				 t->get_locus (), t->get_type_hint ()));
+     case RAW_STRING_LITERAL:
+       lexer.skip_token ();
+       return std::unique_ptr<AST::LiteralPattern> (
+ 	new AST::LiteralPattern (t->get_str (), AST::Literal::RAW_STRING,
+ 				 t->get_locus (), t->get_type_hint ()));
+     // raw string and raw byte string literals too if they are readded to
+     // lexer
+     case MINUS:
+       if (lexer.peek_token (1)->get_id () == INT_LITERAL)
+ 	{
+ 	  return parse_literal_or_range_pattern ();
+ 	}
+       else if (lexer.peek_token (1)->get_id () == FLOAT_LITERAL)
+ 	{
+ 	  return parse_literal_or_range_pattern ();
+ 	}
+       else
+ 	{
+ 	  Error error (t->get_locus (), "unexpected token %<-%> in pattern - "
+ 					"did you forget an integer literal");
+ 	  add_error (std::move (error));
+ 
+ 	  return nullptr;
+ 	}
+     case UNDERSCORE:
+       lexer.skip_token ();
+       return std::unique_ptr<AST::WildcardPattern> (
+ 	new AST::WildcardPattern (t->get_locus ()));
+     case DOT_DOT:
+       lexer.skip_token ();
+       return std::unique_ptr<AST::RestPattern> (
+ 	new AST::RestPattern (t->get_locus ()));
+     case REF:
+     case MUT:
+       return parse_identifier_pattern ();
+     case IDENTIFIER:
+       /* if identifier with no scope resolution afterwards, identifier
+        * pattern. if scope resolution afterwards, path pattern (or range
+        * pattern or struct pattern or tuple struct pattern) or macro
+        * invocation */
+       return parse_ident_leading_pattern ();
+     case AMP:
+     case LOGICAL_AND:
+       // reference pattern
+       return parse_reference_pattern ();
+     case LEFT_PAREN:
+       // tuple pattern or grouped pattern
+       return parse_grouped_or_tuple_pattern ();
+     case LEFT_SQUARE:
+       // slice pattern
+       return parse_slice_pattern ();
+     case LEFT_SHIFT:
+     case LEFT_ANGLE:
+       {
+ 	// qualified path in expression or qualified range pattern bound
+ 	AST::QualifiedPathInExpression path
+ 	  = parse_qualified_path_in_expression ();
+ 
+ 	if (lexer.peek_token ()->get_id () == DOT_DOT_EQ
+ 	    || lexer.peek_token ()->get_id () == ELLIPSIS
+ 	    || lexer.peek_token ()->get_id () == DOT_DOT)
+ 	  {
+ 	    // qualified range pattern bound, so parse rest of range pattern
+ 	    AST::RangeKind kind
+ 	      = AST::tokenid_to_rangekind (lexer.peek_token ()->get_id ());
+ 	    lexer.skip_token ();
+ 
+ 	    std::unique_ptr<AST::RangePatternBoundQualPath> lower_bound (
+ 	      new AST::RangePatternBoundQualPath (std::move (path)));
+ 	    std::unique_ptr<AST::RangePatternBound> upper_bound
+ 	      = parse_range_pattern_bound ();
+ 
+ 	    return std::unique_ptr<AST::RangePattern> (
+ 	      new AST::RangePattern (std::move (lower_bound),
+ 				     std::move (upper_bound), kind,
+ 				     t->get_locus ()));
+ 	  }
+ 	else
+ 	  {
+ 	    // just qualified path in expression
+ 	    return std::unique_ptr<AST::QualifiedPathInExpression> (
+ 	      new AST::QualifiedPathInExpression (std::move (path)));
+ 	  }
+       }
+     case SUPER:
+     case SELF:
+     case SELF_ALIAS:
+     case CRATE:
+     case SCOPE_RESOLUTION:
+     case DOLLAR_SIGN:
+       {
+ 	// path in expression or range pattern bound
+ 	AST::PathInExpression path = parse_path_in_expression ();
+ 
+ 	const_TokenPtr next = lexer.peek_token ();
+ 	switch (next->get_id ())
+ 	  {
+ 	  case DOT_DOT_EQ:
+ 	  case DOT_DOT:
+ 	  case ELLIPSIS:
+ 	    {
+ 	      // qualified range pattern bound, so parse rest of range pattern
+ 	      AST::RangeKind kind = AST::tokenid_to_rangekind (next->get_id ());
+ 	      lexer.skip_token ();
+ 
+ 	      std::unique_ptr<AST::RangePatternBoundPath> lower_bound (
+ 		new AST::RangePatternBoundPath (std::move (path)));
+ 	      std::unique_ptr<AST::RangePatternBound> upper_bound
+ 		= parse_range_pattern_bound ();
+ 
+ 	      return std::unique_ptr<AST::RangePattern> (
+ 		new AST::RangePattern (std::move (lower_bound),
+ 				       std::move (upper_bound), kind,
+ 				       next->get_locus ()));
+ 	    }
+ 	  case EXCLAM:
+ 	    return parse_macro_invocation_partial (std::move (path),
+ 						   AST::AttrVec ());
+ 	  case LEFT_PAREN:
+ 	    {
+ 	      // tuple struct
+ 	      lexer.skip_token ();
+ 
+ 	      // parse items
+ 	      std::unique_ptr<AST::TupleStructItems> items
+ 		= parse_tuple_struct_items ();
+ 	      if (items == nullptr)
+ 		{
+ 		  Error error (lexer.peek_token ()->get_locus (),
+ 			       "failed to parse tuple struct items");
+ 		  add_error (std::move (error));
+ 
+ 		  return nullptr;
+ 		}
+ 
+ 	      if (!skip_token (RIGHT_PAREN))
+ 		{
+ 		  return nullptr;
+ 		}
+ 
+ 	      return std::unique_ptr<AST::TupleStructPattern> (
+ 		new AST::TupleStructPattern (std::move (path),
+ 					     std::move (items)));
+ 	    }
+ 	  case LEFT_CURLY:
+ 	    {
+ 	      // struct
+ 	      lexer.skip_token ();
+ 
+ 	      // parse elements (optional)
+ 	      AST::StructPatternElements elems = parse_struct_pattern_elems ();
+ 
+ 	      if (!skip_token (RIGHT_CURLY))
+ 		{
+ 		  return nullptr;
+ 		}
+ 
+ 	      return std::unique_ptr<AST::StructPattern> (
+ 		new AST::StructPattern (std::move (path), t->get_locus (),
+ 					std::move (elems)));
+ 	    }
+ 	  default:
+ 	    // assume path in expression
+ 	    return std::unique_ptr<AST::PathInExpression> (
+ 	      new AST::PathInExpression (std::move (path)));
+ 	  }
+       }
+     default:
+       add_error (Error (t->get_locus (), "unexpected token %qs in pattern",
+ 			t->get_token_description ()));
+ 
+       return nullptr;
+     }
+ }
+ 
+ // Parses a single or double reference pattern.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::ReferencePattern>
+ Parser<ManagedTokenSource>::parse_reference_pattern ()
+ {
+   // parse double or single ref
+   bool is_double_ref = false;
+   const_TokenPtr t = lexer.peek_token ();
+   switch (t->get_id ())
+     {
+     case AMP:
+       // still false
+       lexer.skip_token ();
+       break;
+     case LOGICAL_AND:
+       is_double_ref = true;
+       lexer.skip_token ();
+       break;
+     default:
+       add_error (Error (t->get_locus (),
+ 			"unexpected token %qs in reference pattern",
+ 			t->get_token_description ()));
+ 
+       return nullptr;
+     }
+ 
+   // parse mut (if it exists)
+   bool is_mut = false;
+   if (lexer.peek_token ()->get_id () == MUT)
+     {
+       is_mut = true;
+       lexer.skip_token ();
+     }
+ 
+   // parse pattern to get reference of (required)
+   std::unique_ptr<AST::Pattern> pattern = parse_pattern_no_alt ();
+   if (pattern == nullptr)
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "failed to parse pattern in reference pattern");
+       add_error (std::move (error));
+ 
+       // skip somewhere?
+       return nullptr;
+     }
+ 
+   return std::unique_ptr<AST::ReferencePattern> (
+     new AST::ReferencePattern (std::move (pattern), is_mut, is_double_ref,
+ 			       t->get_locus ()));
+ }
+ 
+ /* Parses a grouped pattern or tuple pattern. Prefers grouped over tuple if
+  * only a single element with no commas. */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::Pattern>
+ Parser<ManagedTokenSource>::parse_grouped_or_tuple_pattern ()
+ {
+   location_t paren_locus = lexer.peek_token ()->get_locus ();
+   skip_token (LEFT_PAREN);
+ 
+   // detect '..' token (ranged with no lower range)
+   if (lexer.peek_token ()->get_id () == DOT_DOT)
+     {
+       lexer.skip_token ();
+ 
+       // parse new patterns while next token is a comma
+       std::vector<std::unique_ptr<AST::Pattern>> patterns;
+ 
+       const_TokenPtr t = lexer.peek_token ();
+       while (t->get_id () == COMMA)
+ 	{
+ 	  lexer.skip_token ();
+ 
+ 	  // break if next token is ')'
+ 	  if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
+ 	    {
+ 	      break;
+ 	    }
+ 
+ 	  // parse pattern, which is required
+ 	  std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
+ 	  if (pattern == nullptr)
+ 	    {
+ 	      Error error (
+ 		lexer.peek_token ()->get_locus (),
+ 		"failed to parse pattern inside ranged tuple pattern");
+ 	      add_error (std::move (error));
+ 
+ 	      // skip somewhere?
+ 	      return nullptr;
+ 	    }
+ 	  patterns.push_back (std::move (pattern));
+ 
+ 	  t = lexer.peek_token ();
+ 	}
+ 
+       if (!skip_token (RIGHT_PAREN))
+ 	{
+ 	  // skip somewhere?
+ 	  return nullptr;
+ 	}
+ 
+       // create tuple pattern items with only upper pattern items
+       std::unique_ptr<AST::TuplePatternItemsHasRest> items (
+ 	new AST::TuplePatternItemsHasRest (
+ 	  std::vector<std::unique_ptr<AST::Pattern>> (), std::move (patterns)));
+       return std::unique_ptr<AST::TuplePattern> (
+ 	new AST::TuplePattern (std::move (items), paren_locus));
+     }
+   else if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
+     {
+       skip_token (RIGHT_PAREN);
+       auto items = std::unique_ptr<AST::TuplePatternItemsNoRest> (
+ 	new AST::TuplePatternItemsNoRest (
+ 	  std::vector<std::unique_ptr<AST::Pattern>> ()));
+       return std::unique_ptr<AST::TuplePattern> (
+ 	new AST::TuplePattern (std::move (items), paren_locus));
+     }
+ 
+   // parse initial pattern (required)
+   std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern ();
+   if (initial_pattern == nullptr)
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "failed to parse pattern in grouped or tuple pattern");
+       add_error (std::move (error));
+ 
+       return nullptr;
+     }
+ 
+   // branch on whether next token is a comma or not
+   const_TokenPtr t = lexer.peek_token ();
+   switch (t->get_id ())
+     {
+     case RIGHT_PAREN:
+       // grouped pattern
+       lexer.skip_token ();
+ 
+       return std::unique_ptr<AST::GroupedPattern> (
+ 	new AST::GroupedPattern (std::move (initial_pattern), paren_locus));
+     case COMMA:
+       {
+ 	// tuple pattern
+ 	lexer.skip_token ();
+ 
+ 	// create vector of patterns
+ 	std::vector<std::unique_ptr<AST::Pattern>> patterns;
+ 	patterns.push_back (std::move (initial_pattern));
+ 
+ 	t = lexer.peek_token ();
+ 	while (t->get_id () != RIGHT_PAREN && t->get_id () != DOT_DOT)
+ 	  {
+ 	    // parse pattern (required)
+ 	    std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
+ 	    if (pattern == nullptr)
+ 	      {
+ 		Error error (t->get_locus (),
+ 			     "failed to parse pattern in tuple pattern");
+ 		add_error (std::move (error));
+ 
+ 		return nullptr;
+ 	      }
+ 	    patterns.push_back (std::move (pattern));
+ 
+ 	    if (lexer.peek_token ()->get_id () != COMMA)
+ 	      break;
+ 
+ 	    lexer.skip_token ();
+ 	    t = lexer.peek_token ();
+ 	  }
+ 
+ 	t = lexer.peek_token ();
+ 	if (t->get_id () == RIGHT_PAREN)
+ 	  {
+ 	    // non-ranged tuple pattern
+ 	    lexer.skip_token ();
+ 
+ 	    std::unique_ptr<AST::TuplePatternItemsNoRest> items (
+ 	      new AST::TuplePatternItemsNoRest (std::move (patterns)));
+ 	    return std::unique_ptr<AST::TuplePattern> (
+ 	      new AST::TuplePattern (std::move (items), paren_locus));
+ 	  }
+ 	else if (t->get_id () == DOT_DOT)
+ 	  {
+ 	    // ranged tuple pattern
+ 	    lexer.skip_token ();
+ 
+ 	    // parse upper patterns
+ 	    std::vector<std::unique_ptr<AST::Pattern>> upper_patterns;
+ 	    t = lexer.peek_token ();
+ 	    while (t->get_id () == COMMA)
+ 	      {
+ 		lexer.skip_token ();
+ 
+ 		// break if end
+ 		if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
+ 		  break;
+ 
+ 		// parse pattern (required)
+ 		std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
+ 		if (pattern == nullptr)
+ 		  {
+ 		    Error error (lexer.peek_token ()->get_locus (),
+ 				 "failed to parse pattern in tuple pattern");
+ 		    add_error (std::move (error));
+ 
+ 		    return nullptr;
+ 		  }
+ 		upper_patterns.push_back (std::move (pattern));
+ 
+ 		t = lexer.peek_token ();
+ 	      }
+ 
+ 	    if (!skip_token (RIGHT_PAREN))
+ 	      {
+ 		return nullptr;
+ 	      }
+ 
+ 	    std::unique_ptr<AST::TuplePatternItemsHasRest> items (
+ 	      new AST::TuplePatternItemsHasRest (std::move (patterns),
+ 						 std::move (upper_patterns)));
+ 	    return std::unique_ptr<AST::TuplePattern> (
+ 	      new AST::TuplePattern (std::move (items), paren_locus));
+ 	  }
+ 	else
+ 	  {
+ 	    // some kind of error
+ 	    Error error (t->get_locus (),
+ 			 "failed to parse tuple pattern (probably) or maybe "
+ 			 "grouped pattern");
+ 	    add_error (std::move (error));
+ 
+ 	    return nullptr;
+ 	  }
+       }
+     default:
+       // error
+       add_error (Error (t->get_locus (),
+ 			"unrecognised token %qs in grouped or tuple pattern "
+ 			"after first pattern",
+ 			t->get_token_description ()));
+ 
+       return nullptr;
+     }
+ }
+ 
+ /* Parses a slice pattern that can match arrays or slices. Parses the square
+  * brackets too. */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::SlicePattern>
+ Parser<ManagedTokenSource>::parse_slice_pattern ()
+ {
+   location_t square_locus = lexer.peek_token ()->get_locus ();
+   std::vector<std::unique_ptr<AST::Pattern>> patterns;
+   tl::optional<std::vector<std::unique_ptr<AST::Pattern>>> upper_patterns
+     = tl::nullopt;
+ 
+   // lambda function to determine which vector to push new patterns into
+   auto get_pattern_ref
+     = [&] () -> std::vector<std::unique_ptr<AST::Pattern>> & {
+     return upper_patterns.has_value () ? upper_patterns.value () : patterns;
+   };
+ 
+   skip_token (LEFT_SQUARE);
+ 
+   if (lexer.peek_token ()->get_id () == RIGHT_SQUARE)
+     {
+       skip_token (RIGHT_SQUARE);
+       std::unique_ptr<AST::SlicePatternItemsNoRest> items (
+ 	new AST::SlicePatternItemsNoRest (std::move (patterns)));
+       return std::unique_ptr<AST::SlicePattern> (
+ 	new AST::SlicePattern (std::move (items), square_locus));
+     }
+ 
+   // parse initial pattern (required)
+   if (lexer.peek_token ()->get_id () == DOT_DOT)
+     {
+       lexer.skip_token ();
+       upper_patterns = std::vector<std::unique_ptr<AST::Pattern>> ();
+     }
+   else
+     {
+       // Not a rest pattern `..`, parse normally
+       std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern ();
+       if (initial_pattern == nullptr)
+ 	{
+ 	  Error error (lexer.peek_token ()->get_locus (),
+ 		       "failed to parse initial pattern in slice pattern");
+ 	  add_error (std::move (error));
+ 
+ 	  return nullptr;
+ 	}
+ 
+       patterns.push_back (std::move (initial_pattern));
+     }
+ 
+   const_TokenPtr t = lexer.peek_token ();
+   while (t->get_id () == COMMA)
+     {
+       lexer.skip_token ();
+ 
+       // break if end bracket
+       if (lexer.peek_token ()->get_id () == RIGHT_SQUARE)
+ 	break;
+ 
+       if (lexer.peek_token ()->get_id () == DOT_DOT)
+ 	{
+ 	  if (upper_patterns.has_value ())
+ 	    {
+ 	      // DOT_DOT has been parsed before
+ 	      Error error (lexer.peek_token ()->get_locus (), "%s",
+ 			   "`..` can only be used once per slice pattern");
+ 	      add_error (std::move (error));
+ 
+ 	      return nullptr;
+ 	    }
+ 	  upper_patterns = std::vector<std::unique_ptr<AST::Pattern>> ();
+ 	  lexer.skip_token ();
+ 	  t = lexer.peek_token ();
+ 	  continue;
+ 	}
+ 
+       // parse pattern (required)
+       std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
+       if (pattern == nullptr)
+ 	{
+ 	  Error error (lexer.peek_token ()->get_locus (),
+ 		       "failed to parse pattern in slice pattern");
+ 	  add_error (std::move (error));
+ 
+ 	  return nullptr;
+ 	}
+       get_pattern_ref ().push_back (std::move (pattern));
+ 
+       t = lexer.peek_token ();
+     }
+ 
+   if (!skip_token (RIGHT_SQUARE))
+     {
+       return nullptr;
+     }
+ 
+   if (upper_patterns.has_value ())
+     {
+       // Slice pattern with rest
+       std::unique_ptr<AST::SlicePatternItemsHasRest> items (
+ 	new AST::SlicePatternItemsHasRest (
+ 	  std::move (patterns), std::move (upper_patterns.value ())));
+       return std::unique_ptr<AST::SlicePattern> (
+ 	new AST::SlicePattern (std::move (items), square_locus));
+     }
+ 
+   // Rest-less slice pattern
+   std::unique_ptr<AST::SlicePatternItemsNoRest> items (
+     new AST::SlicePatternItemsNoRest (std::move (patterns)));
+   return std::unique_ptr<AST::SlicePattern> (
+     new AST::SlicePattern (std::move (items), square_locus));
+ }
+ 
+ /* Parses an identifier pattern (pattern that binds a value matched to a
+  * variable). */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::IdentifierPattern>
+ Parser<ManagedTokenSource>::parse_identifier_pattern ()
+ {
+   location_t locus = lexer.peek_token ()->get_locus ();
+ 
+   bool has_ref = false;
+   if (lexer.peek_token ()->get_id () == REF)
+     {
+       has_ref = true;
+       lexer.skip_token ();
+ 
+       // DEBUG
+       rust_debug ("parsed ref in identifier pattern");
+     }
+ 
+   bool has_mut = false;
+   if (lexer.peek_token ()->get_id () == MUT)
+     {
+       has_mut = true;
+       lexer.skip_token ();
+     }
+ 
+   // parse identifier (required)
+   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
+   if (ident_tok == nullptr)
+     {
+       // skip somewhere?
+       return nullptr;
+     }
+   Identifier ident{ident_tok};
+ 
+   // DEBUG
+   rust_debug ("parsed identifier in identifier pattern");
+ 
+   // parse optional pattern binding thing
+   std::unique_ptr<AST::Pattern> bind_pattern = nullptr;
+   if (lexer.peek_token ()->get_id () == PATTERN_BIND)
+     {
+       lexer.skip_token ();
+ 
+       // parse required pattern to bind
+       bind_pattern = parse_pattern_no_alt ();
+       if (bind_pattern == nullptr)
+ 	{
+ 	  Error error (lexer.peek_token ()->get_locus (),
+ 		       "failed to parse pattern to bind in identifier pattern");
+ 	  add_error (std::move (error));
+ 
+ 	  return nullptr;
+ 	}
+     }
+ 
+   // DEBUG
+   rust_debug ("about to return identifier pattern");
+ 
+   return std::unique_ptr<AST::IdentifierPattern> (
+     new AST::IdentifierPattern (std::move (ident), locus, has_ref, has_mut,
+ 				std::move (bind_pattern)));
+ }
+ 
+ /* Parses a pattern that opens with an identifier. This includes identifier
+  * patterns, path patterns (and derivatives such as struct patterns, tuple
+  * struct patterns, and macro invocations), and ranges. */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::Pattern>
+ Parser<ManagedTokenSource>::parse_ident_leading_pattern ()
+ {
+   // ensure first token is actually identifier
+   const_TokenPtr initial_tok = lexer.peek_token ();
+   if (initial_tok->get_id () != IDENTIFIER)
+     {
+       return nullptr;
+     }
+ 
+   // save initial identifier as it may be useful (but don't skip)
+   std::string initial_ident = initial_tok->get_str ();
+ 
+   // parse next tokens as a PathInExpression
+   AST::PathInExpression path = parse_path_in_expression ();
+ 
+   // branch on next token
+   const_TokenPtr t = lexer.peek_token ();
+   switch (t->get_id ())
+     {
+     case EXCLAM:
+       return parse_macro_invocation_partial (std::move (path), AST::AttrVec ());
+     case LEFT_PAREN:
+       {
+ 	// tuple struct
+ 	lexer.skip_token ();
+ 
+ 	// DEBUG
+ 	rust_debug ("parsing tuple struct pattern");
+ 
+ 	// parse items
+ 	std::unique_ptr<AST::TupleStructItems> items
+ 	  = parse_tuple_struct_items ();
+ 	if (items == nullptr)
+ 	  {
+ 	    Error error (lexer.peek_token ()->get_locus (),
+ 			 "failed to parse tuple struct items");
+ 	    add_error (std::move (error));
+ 
+ 	    return nullptr;
+ 	  }
+ 
+ 	// DEBUG
+ 	rust_debug ("successfully parsed tuple struct items");
+ 
+ 	if (!skip_token (RIGHT_PAREN))
+ 	  {
+ 	    return nullptr;
+ 	  }
+ 
+ 	// DEBUG
+ 	rust_debug ("successfully parsed tuple struct pattern");
+ 
+ 	return std::unique_ptr<AST::TupleStructPattern> (
+ 	  new AST::TupleStructPattern (std::move (path), std::move (items)));
+       }
+     case LEFT_CURLY:
+       {
+ 	// struct
+ 	lexer.skip_token ();
+ 
+ 	// parse elements (optional)
+ 	AST::StructPatternElements elems = parse_struct_pattern_elems ();
+ 
+ 	if (!skip_token (RIGHT_CURLY))
+ 	  {
+ 	    return nullptr;
+ 	  }
+ 
+ 	// DEBUG
+ 	rust_debug ("successfully parsed struct pattern");
+ 
+ 	return std::unique_ptr<AST::StructPattern> (
+ 	  new AST::StructPattern (std::move (path), initial_tok->get_locus (),
+ 				  std::move (elems)));
+       }
+     case DOT_DOT_EQ:
+     case DOT_DOT:
+     case ELLIPSIS:
+       {
+ 	// range
+ 	AST::RangeKind kind
+ 	  = AST::tokenid_to_rangekind (lexer.peek_token ()->get_id ());
+ 
+ 	lexer.skip_token ();
+ 
+ 	std::unique_ptr<AST::RangePatternBoundPath> lower_bound (
+ 	  new AST::RangePatternBoundPath (std::move (path)));
+ 	std::unique_ptr<AST::RangePatternBound> upper_bound
+ 	  = parse_range_pattern_bound ();
+ 
+ 	return std::unique_ptr<AST::RangePattern> (
+ 	  new AST::RangePattern (std::move (lower_bound),
+ 				 std::move (upper_bound), kind,
+ 				 t->get_locus ()));
+       }
+     case PATTERN_BIND:
+       {
+ 	// only allow on single-segment paths
+ 	if (path.is_single_segment ())
+ 	  {
+ 	    // identifier with pattern bind
+ 	    lexer.skip_token ();
+ 
+ 	    std::unique_ptr<AST::Pattern> bind_pattern
+ 	      = parse_pattern_no_alt ();
+ 	    if (bind_pattern == nullptr)
+ 	      {
+ 		Error error (
+ 		  t->get_locus (),
+ 		  "failed to parse pattern to bind to identifier pattern");
+ 		add_error (std::move (error));
+ 
+ 		return nullptr;
+ 	      }
+ 	    return std::unique_ptr<AST::IdentifierPattern> (
+ 	      new AST::IdentifierPattern (std::move (initial_ident),
+ 					  initial_tok->get_locus (), false,
+ 					  false, std::move (bind_pattern)));
+ 	  }
+ 	Error error (
+ 	  t->get_locus (),
+ 	  "failed to parse pattern bind to a path, not an identifier");
+ 	add_error (std::move (error));
+ 
+ 	return nullptr;
+       }
+     default:
+       // assume identifier if single segment
+       if (path.is_single_segment ())
+ 	{
+ 	  return std::unique_ptr<AST::IdentifierPattern> (
+ 	    new AST::IdentifierPattern (std::move (initial_ident),
+ 					initial_tok->get_locus ()));
+ 	}
+       // return path otherwise
+       return std::unique_ptr<AST::PathInExpression> (
+ 	new AST::PathInExpression (std::move (path)));
+     }
+ }
+ 
+ // Parses struct pattern elements if they exist.
+ template <typename ManagedTokenSource>
+ AST::StructPatternElements
+ Parser<ManagedTokenSource>::parse_struct_pattern_elems ()
+ {
+   std::vector<std::unique_ptr<AST::StructPatternField>> fields;
+ 
+   AST::AttrVec etc_attrs;
+   bool has_rest = false;
+ 
+   // try parsing struct pattern fields
+   const_TokenPtr t = lexer.peek_token ();
+   while (t->get_id () != RIGHT_CURLY)
+     {
+       AST::AttrVec outer_attrs = parse_outer_attributes ();
+ 
+       // parse etc (must be last in struct pattern, so breaks)
+       if (lexer.peek_token ()->get_id () == DOT_DOT)
+ 	{
+ 	  lexer.skip_token ();
+ 	  etc_attrs = std::move (outer_attrs);
+ 	  has_rest = true;
+ 	  break;
+ 	}
+ 
+       std::unique_ptr<AST::StructPatternField> field
+ 	= parse_struct_pattern_field_partial (std::move (outer_attrs));
+       if (field == nullptr)
+ 	{
+ 	  Error error (lexer.peek_token ()->get_locus (),
+ 		       "failed to parse struct pattern field");
+ 	  add_error (std::move (error));
+ 
+ 	  // skip after somewhere?
+ 	  return AST::StructPatternElements::create_empty ();
+ 	}
+       fields.push_back (std::move (field));
+ 
+       if (lexer.peek_token ()->get_id () != COMMA)
+ 	break;
+ 
+       // skip comma
+       lexer.skip_token ();
+       t = lexer.peek_token ();
+     }
+ 
+   if (has_rest)
+     return AST::StructPatternElements (std::move (fields),
+ 				       std::move (etc_attrs));
+   else
+     return AST::StructPatternElements (std::move (fields));
+ }
+ 
+ /* Parses a struct pattern field (tuple index/pattern, identifier/pattern, or
+  * identifier). */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::StructPatternField>
+ Parser<ManagedTokenSource>::parse_struct_pattern_field ()
+ {
+   // parse outer attributes (if they exist)
+   AST::AttrVec outer_attrs = parse_outer_attributes ();
+ 
+   return parse_struct_pattern_field_partial (std::move (outer_attrs));
+ }
+ 
+ /* Parses a struct pattern field (tuple index/pattern, identifier/pattern, or
+  * identifier), with outer attributes passed in. */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::StructPatternField>
+ Parser<ManagedTokenSource>::parse_struct_pattern_field_partial (
+   AST::AttrVec outer_attrs)
+ {
+   // branch based on next token
+   const_TokenPtr t = lexer.peek_token ();
+   switch (t->get_id ())
+     {
+     case INT_LITERAL:
+       {
+ 	// tuple index
+ 	std::string index_str = t->get_str ();
+ 	int index = atoi (index_str.c_str ());
+ 
+ 	lexer.skip_token ();
+ 
+ 	if (!skip_token (COLON))
+ 	  {
+ 	    return nullptr;
+ 	  }
+ 
+ 	// parse required pattern
+ 	std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
+ 	if (pattern == nullptr)
+ 	  {
+ 	    Error error (
+ 	      t->get_locus (),
+ 	      "failed to parse pattern in tuple index struct pattern field");
+ 	    add_error (std::move (error));
+ 
+ 	    return nullptr;
+ 	  }
+ 
+ 	return std::unique_ptr<AST::StructPatternFieldTuplePat> (
+ 	  new AST::StructPatternFieldTuplePat (index, std::move (pattern),
+ 					       std::move (outer_attrs),
+ 					       t->get_locus ()));
+       }
+     case IDENTIFIER:
+       // identifier-pattern OR only identifier
+       // branch on next token
+       switch (lexer.peek_token (1)->get_id ())
+ 	{
+ 	case COLON:
+ 	  {
+ 	    // identifier-pattern
+ 	    Identifier ident{t};
+ 	    lexer.skip_token ();
+ 
+ 	    skip_token (COLON);
+ 
+ 	    // parse required pattern
+ 	    std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
+ 	    if (pattern == nullptr)
+ 	      {
+ 		Error error (t->get_locus (),
+ 			     "failed to parse pattern in struct pattern field");
+ 		add_error (std::move (error));
+ 
+ 		return nullptr;
+ 	      }
+ 
+ 	    return std::unique_ptr<AST::StructPatternFieldIdentPat> (
+ 	      new AST::StructPatternFieldIdentPat (std::move (ident),
+ 						   std::move (pattern),
+ 						   std::move (outer_attrs),
+ 						   t->get_locus ()));
+ 	  }
+ 	case COMMA:
+ 	case RIGHT_CURLY:
+ 	  {
+ 	    // identifier only
+ 	    Identifier ident = {t};
+ 	    lexer.skip_token ();
+ 
+ 	    return std::unique_ptr<AST::StructPatternFieldIdent> (
+ 	      new AST::StructPatternFieldIdent (std::move (ident), false, false,
+ 						std::move (outer_attrs),
+ 						t->get_locus ()));
+ 	  }
+ 	default:
+ 	  // error
+ 	  add_error (Error (t->get_locus (),
+ 			    "unrecognised token %qs in struct pattern field",
+ 			    t->get_token_description ()));
+ 
+ 	  return nullptr;
+ 	}
+     case REF:
+     case MUT:
+       {
+ 	// only identifier
+ 	bool has_ref = false;
+ 	if (t->get_id () == REF)
+ 	  {
+ 	    has_ref = true;
+ 	    lexer.skip_token ();
+ 	  }
+ 
+ 	bool has_mut = false;
+ 	if (lexer.peek_token ()->get_id () == MUT)
+ 	  {
+ 	    has_mut = true;
+ 	    lexer.skip_token ();
+ 	  }
+ 
+ 	const_TokenPtr ident_tok = expect_token (IDENTIFIER);
+ 	if (ident_tok == nullptr)
+ 	  {
+ 	    return nullptr;
+ 	  }
+ 	Identifier ident{ident_tok};
+ 
+ 	return std::unique_ptr<AST::StructPatternFieldIdent> (
+ 	  new AST::StructPatternFieldIdent (std::move (ident), has_ref, has_mut,
+ 					    std::move (outer_attrs),
+ 					    t->get_locus ()));
+       }
+     default:
+       // not necessarily an error
+       return nullptr;
+     }
+ }
+ 
+ /* Parses a literal pattern or range pattern. Assumes that literals passed in
+  * are valid range pattern bounds. Do not pass in paths in expressions, for
+  * instance. */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::Pattern>
+ Parser<ManagedTokenSource>::parse_literal_or_range_pattern ()
+ {
+   const_TokenPtr range_lower = lexer.peek_token ();
+   AST::Literal::LitType type = AST::Literal::STRING;
+   bool has_minus = false;
+ 
+   // get lit type
+   switch (range_lower->get_id ())
+     {
+     case CHAR_LITERAL:
+       type = AST::Literal::CHAR;
+       lexer.skip_token ();
+       break;
+     case BYTE_CHAR_LITERAL:
+       type = AST::Literal::BYTE;
+       lexer.skip_token ();
+       break;
+     case INT_LITERAL:
+       type = AST::Literal::INT;
+       lexer.skip_token ();
+       break;
+     case FLOAT_LITERAL:
+       type = AST::Literal::FLOAT;
+       lexer.skip_token ();
+       break;
+     case MINUS:
+       // branch on next token
+       range_lower = lexer.peek_token (1);
+       switch (range_lower->get_id ())
+ 	{
+ 	case INT_LITERAL:
+ 	  type = AST::Literal::INT;
+ 	  has_minus = true;
+ 	  lexer.skip_token (1);
+ 	  break;
+ 	case FLOAT_LITERAL:
+ 	  type = AST::Literal::FLOAT;
+ 	  has_minus = true;
+ 	  lexer.skip_token (1);
+ 	  break;
+ 	default:
+ 	  add_error (Error (range_lower->get_locus (),
+ 			    "token type %qs cannot be parsed as range pattern "
+ 			    "bound or literal after minus symbol",
+ 			    range_lower->get_token_description ()));
+ 
+ 	  return nullptr;
+ 	}
+       break;
+     default:
+       add_error (
+ 	Error (range_lower->get_locus (),
+ 	       "token type %qs cannot be parsed as range pattern bound",
+ 	       range_lower->get_token_description ()));
+ 
+       return nullptr;
+     }
+ 
+   const_TokenPtr next = lexer.peek_token ();
+   if (next->get_id () == DOT_DOT_EQ || next->get_id () == ELLIPSIS
+       || next->get_id () == DOT_DOT)
+     {
+       AST::RangeKind kind = AST::tokenid_to_rangekind (next->get_id ());
+       // range pattern
+       lexer.skip_token ();
+       std::unique_ptr<AST::RangePatternBound> lower (
+ 	new AST::RangePatternBoundLiteral (
+ 	  AST::Literal (range_lower->get_str (), type,
+ 			PrimitiveCoreType::CORETYPE_UNKNOWN),
+ 	  range_lower->get_locus (), has_minus));
+ 
+       std::unique_ptr<AST::RangePatternBound> upper
+ 	= parse_range_pattern_bound ();
+       if (upper == nullptr)
+ 	{
+ 	  Error error (next->get_locus (),
+ 		       "failed to parse range pattern bound in range pattern");
+ 	  add_error (std::move (error));
+ 
+ 	  return nullptr;
+ 	}
+ 
+       return std::unique_ptr<AST::RangePattern> (
+ 	new AST::RangePattern (std::move (lower), std::move (upper), kind,
+ 			       range_lower->get_locus ()));
+     }
+   else
+     {
+       // literal pattern
+       return std::unique_ptr<AST::LiteralPattern> (
+ 	new AST::LiteralPattern (range_lower->get_str (), type,
+ 				 range_lower->get_locus (),
+ 				 range_lower->get_type_hint (), has_minus));
+     }
+ }
+ 
+ // Parses a range pattern bound (value only).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::RangePatternBound>
+ Parser<ManagedTokenSource>::parse_range_pattern_bound ()
+ {
+   const_TokenPtr range_lower = lexer.peek_token ();
+   location_t range_lower_locus = range_lower->get_locus ();
+ 
+   // get lit type
+   switch (range_lower->get_id ())
+     {
+     case CHAR_LITERAL:
+       lexer.skip_token ();
+       return std::unique_ptr<AST::RangePatternBoundLiteral> (
+ 	new AST::RangePatternBoundLiteral (
+ 	  AST::Literal (range_lower->get_str (), AST::Literal::CHAR,
+ 			range_lower->get_type_hint ()),
+ 	  range_lower_locus));
+     case BYTE_CHAR_LITERAL:
+       lexer.skip_token ();
+       return std::unique_ptr<AST::RangePatternBoundLiteral> (
+ 	new AST::RangePatternBoundLiteral (
+ 	  AST::Literal (range_lower->get_str (), AST::Literal::BYTE,
+ 			range_lower->get_type_hint ()),
+ 	  range_lower_locus));
+     case INT_LITERAL:
+       lexer.skip_token ();
+       return std::unique_ptr<AST::RangePatternBoundLiteral> (
+ 	new AST::RangePatternBoundLiteral (
+ 	  AST::Literal (range_lower->get_str (), AST::Literal::INT,
+ 			range_lower->get_type_hint ()),
+ 	  range_lower_locus));
+     case FLOAT_LITERAL:
+       lexer.skip_token ();
+       rust_debug ("warning: used deprecated float range pattern bound");
+       return std::unique_ptr<AST::RangePatternBoundLiteral> (
+ 	new AST::RangePatternBoundLiteral (
+ 	  AST::Literal (range_lower->get_str (), AST::Literal::FLOAT,
+ 			range_lower->get_type_hint ()),
+ 	  range_lower_locus));
+     case MINUS:
+       // branch on next token
+       range_lower = lexer.peek_token (1);
+       switch (range_lower->get_id ())
+ 	{
+ 	case INT_LITERAL:
+ 	  lexer.skip_token (1);
+ 	  return std::unique_ptr<AST::RangePatternBoundLiteral> (
+ 	    new AST::RangePatternBoundLiteral (
+ 	      AST::Literal (range_lower->get_str (), AST::Literal::INT,
+ 			    range_lower->get_type_hint ()),
+ 	      range_lower_locus, true));
+ 	case FLOAT_LITERAL:
+ 	  lexer.skip_token (1);
+ 	  rust_debug ("warning: used deprecated float range pattern bound");
+ 	  return std::unique_ptr<AST::RangePatternBoundLiteral> (
+ 	    new AST::RangePatternBoundLiteral (
+ 	      AST::Literal (range_lower->get_str (), AST::Literal::FLOAT,
+ 			    range_lower->get_type_hint ()),
+ 	      range_lower_locus, true));
+ 	default:
+ 	  add_error (Error (range_lower->get_locus (),
+ 			    "token type %qs cannot be parsed as range pattern "
+ 			    "bound after minus symbol",
+ 			    range_lower->get_token_description ()));
+ 
+ 	  return nullptr;
+ 	}
+     case IDENTIFIER:
+     case SUPER:
+     case SELF:
+     case SELF_ALIAS:
+     case CRATE:
+     case SCOPE_RESOLUTION:
+     case DOLLAR_SIGN:
+       {
+ 	// path in expression
+ 	AST::PathInExpression path = parse_path_in_expression ();
+ 	if (path.is_error ())
+ 	  {
+ 	    Error error (
+ 	      range_lower->get_locus (),
+ 	      "failed to parse path in expression range pattern bound");
+ 	    add_error (std::move (error));
+ 
+ 	    return nullptr;
+ 	  }
+ 	return std::unique_ptr<AST::RangePatternBoundPath> (
+ 	  new AST::RangePatternBoundPath (std::move (path)));
+       }
+     case LEFT_SHIFT:
+     case LEFT_ANGLE:
+       {
+ 	// qualified path in expression
+ 	AST::QualifiedPathInExpression path
+ 	  = parse_qualified_path_in_expression ();
+ 	if (path.is_error ())
+ 	  {
+ 	    Error error (range_lower->get_locus (),
+ 			 "failed to parse qualified path in expression range "
+ 			 "pattern bound");
+ 	    add_error (std::move (error));
+ 
+ 	    return nullptr;
+ 	  }
+ 	return std::unique_ptr<AST::RangePatternBoundQualPath> (
+ 	  new AST::RangePatternBoundQualPath (std::move (path)));
+       }
+     default:
+       add_error (
+ 	Error (range_lower->get_locus (),
+ 	       "token type %qs cannot be parsed as range pattern bound",
+ 	       range_lower->get_token_description ()));
+ 
+       return nullptr;
+     }
+ }
+ 
+ } // namespace Rust
diff -Nrcpad gcc-16-20251214/gcc/rust/parse/rust-parse-impl-proc-macro.cc gcc-16-20251221/gcc/rust/parse/rust-parse-impl-proc-macro.cc
*** gcc-16-20251214/gcc/rust/parse/rust-parse-impl-proc-macro.cc	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/rust/parse/rust-parse-impl-proc-macro.cc	Sun Dec 21 22:32:07 2025
***************
*** 16,27 ****
  // along with GCC; see the file COPYING3.  If not see
  // <http://www.gnu.org/licenses/>.
  
! #include "rust-parse-impl.h"
  #include "rust-proc-macro-invoc-lexer.h"
  
  namespace Rust {
  
! template std::unique_ptr<AST::Item>
  Parser<ProcMacroInvocLexer>::parse_item (bool);
  
  template std::unique_ptr<AST::Stmt>
--- 16,27 ----
  // along with GCC; see the file COPYING3.  If not see
  // <http://www.gnu.org/licenses/>.
  
! #include "rust-parse-impl.hxx"
  #include "rust-proc-macro-invoc-lexer.h"
  
  namespace Rust {
  
! template tl::expected<std::unique_ptr<AST::Item>, Parse::Error::Item>
  Parser<ProcMacroInvocLexer>::parse_item (bool);
  
  template std::unique_ptr<AST::Stmt>
diff -Nrcpad gcc-16-20251214/gcc/rust/parse/rust-parse-impl-ttree.hxx gcc-16-20251221/gcc/rust/parse/rust-parse-impl-ttree.hxx
*** gcc-16-20251214/gcc/rust/parse/rust-parse-impl-ttree.hxx	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/rust/parse/rust-parse-impl-ttree.hxx	Sun Dec 21 22:32:07 2025
***************
*** 0 ****
--- 1,158 ----
+ // Copyright (C) 2025 Free Software Foundation, Inc.
+ 
+ // This file is part of GCC.
+ 
+ // GCC is free software; you can redistribute it and/or modify it under
+ // the terms of the GNU General Public License as published by the Free
+ // Software Foundation; either version 3, or (at your option) any later
+ // version.
+ 
+ // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+ // WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ // for more details.
+ 
+ // You should have received a copy of the GNU General Public License
+ // along with GCC; see the file COPYING3.  If not see
+ // <http://www.gnu.org/licenses/>.
+ 
+ /* DO NOT INCLUDE ANYWHERE - this is automatically included
+  *   by rust-parse-impl.h
+  * This is also the reason why there are no include guards. */
+ 
+ #include "rust-parse.h"
+ #include "rust-parse-error.h"
+ #include "expected.h"
+ 
+ namespace Rust {
+ 
+ /* Parses a TokenTree syntactical production. This is either a delimited token
+  * tree or a non-delimiter token. */
+ template <typename ManagedTokenSource>
+ tl::expected<std::unique_ptr<AST::TokenTree>, Parse::Error::TokenTree>
+ Parser<ManagedTokenSource>::parse_token_tree ()
+ {
+   const_TokenPtr t = lexer.peek_token ();
+ 
+   switch (t->get_id ())
+     {
+     case LEFT_PAREN:
+     case LEFT_SQUARE:
+     case LEFT_CURLY:
+       {
+ 	// Parse delimited token tree
+ 	auto delim_token_tree = parse_delim_token_tree ();
+ 	if (!delim_token_tree)
+ 	  return Parse::Error::TokenTree::
+ 	    make_malformed_delimited_token_tree ();
+ 
+ 	// TODO: use move rather than copy constructor
+ 	return std::unique_ptr<AST::DelimTokenTree> (
+ 	  new AST::DelimTokenTree (delim_token_tree.value ()));
+       }
+     case RIGHT_PAREN:
+     case RIGHT_SQUARE:
+     case RIGHT_CURLY:
+       // error - should not be called when this a token
+       add_error (Error (t->get_locus (), "unexpected closing delimiter %qs",
+ 			t->get_token_description ()));
+ 
+       add_error (Error (Error::Kind::Hint, t->get_locus (),
+ 			"token tree requires either paired delimiters or "
+ 			"non-delimiter tokens"));
+ 
+       lexer.skip_token ();
+       return Parse::Error::TokenTree::make_malformed ();
+     default:
+       // parse token itself as TokenTree
+       lexer.skip_token ();
+       return std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
+     }
+ }
+ 
+ // Parses a delimited token tree
+ template <typename ManagedTokenSource>
+ tl::expected<AST::DelimTokenTree, Parse::Error::DelimTokenTree>
+ Parser<ManagedTokenSource>::parse_delim_token_tree ()
+ {
+   const_TokenPtr t = lexer.peek_token ();
+   lexer.skip_token ();
+   location_t initial_loc = t->get_locus ();
+ 
+   // save delim type to ensure it is reused later
+   AST::DelimType delim_type = AST::PARENS;
+ 
+   // Map tokens to DelimType
+   switch (t->get_id ())
+     {
+     case LEFT_PAREN:
+       delim_type = AST::PARENS;
+       break;
+     case LEFT_SQUARE:
+       delim_type = AST::SQUARE;
+       break;
+     case LEFT_CURLY:
+       delim_type = AST::CURLY;
+       break;
+     default:
+       add_error (Error (t->get_locus (),
+ 			"unexpected token %qs - expecting delimiters (for a "
+ 			"delimited token tree)",
+ 			t->get_token_description ()));
+ 
+       return Parse::Error::DelimTokenTree::make_expected_delimiter ();
+     }
+ 
+   // parse actual token tree vector - 0 or more
+   std::vector<std::unique_ptr<AST::TokenTree>> token_trees_in_tree;
+   auto delim_open
+     = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
+   token_trees_in_tree.push_back (std::move (delim_open));
+ 
+   // repeat loop until finding the matching delimiter
+   t = lexer.peek_token ();
+   while (!Parse::Utils::token_id_matches_delims (t->get_id (), delim_type)
+ 	 && t->get_id () != END_OF_FILE)
+     {
+       auto tok_tree = parse_token_tree ();
+       if (!tok_tree)
+ 	return Parse::Error::DelimTokenTree::make_invalid_token_tree ();
+ 
+       token_trees_in_tree.push_back (std::move (tok_tree.value ()));
+ 
+       // lexer.skip_token();
+       t = lexer.peek_token ();
+     }
+   auto delim_close
+     = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
+   token_trees_in_tree.push_back (std::move (delim_close));
+ 
+   AST::DelimTokenTree token_tree (delim_type, std::move (token_trees_in_tree),
+ 				  initial_loc);
+ 
+   // parse end delimiters
+   t = lexer.peek_token ();
+ 
+   if (Parse::Utils::token_id_matches_delims (t->get_id (), delim_type))
+     {
+       // tokens match opening delimiter, so skip.
+       lexer.skip_token ();
+       return token_tree;
+     }
+   else
+     {
+       // tokens don't match opening delimiters, so produce error
+       Error error (t->get_locus (),
+ 		   "unexpected token %qs - expecting closing delimiter %qs "
+ 		   "(for a delimited token tree)",
+ 		   t->get_token_description (),
+ 		   (delim_type == AST::PARENS
+ 		      ? ")"
+ 		      : (delim_type == AST::SQUARE ? "]" : "}")));
+       add_error (std::move (error));
+ 
+       return Parse::Error::DelimTokenTree::make_mismatched_delimiters ();
+     }
+ }
+ 
+ } // namespace Rust
diff -Nrcpad gcc-16-20251214/gcc/rust/parse/rust-parse-impl-utils.hxx gcc-16-20251221/gcc/rust/parse/rust-parse-impl-utils.hxx
*** gcc-16-20251214/gcc/rust/parse/rust-parse-impl-utils.hxx	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/rust/parse/rust-parse-impl-utils.hxx	Sun Dec 21 22:32:07 2025
***************
*** 0 ****
--- 1,252 ----
+ // Copyright (C) 2025 Free Software Foundation, Inc.
+ 
+ // This file is part of GCC.
+ 
+ // GCC is free software; you can redistribute it and/or modify it under
+ // the terms of the GNU General Public License as published by the Free
+ // Software Foundation; either version 3, or (at your option) any later
+ // version.
+ 
+ // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+ // WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ // for more details.
+ 
+ // You should have received a copy of the GNU General Public License
+ // along with GCC; see the file COPYING3.  If not see
+ // <http://www.gnu.org/licenses/>.
+ 
+ /* DO NOT INCLUDE ANYWHERE - this is automatically included
+  *   by rust-parse-impl.h
+  * This is also the reason why there are no include guards. */
+ 
+ #include "rust-parse.h"
+ 
+ namespace Rust {
+ 
+ // "Unexpected token" panic mode - flags gcc error at unexpected token
+ // TODO: seems to be unused, remove?
+ template <typename ManagedTokenSource>
+ void
+ Parser<ManagedTokenSource>::unexpected_token (const_TokenPtr t)
+ {
+   Error error (t->get_locus (), "unexpected token %qs",
+ 	       t->get_token_description ());
+   add_error (std::move (error));
+ }
+ 
+ /* Crappy "error recovery" performed after error by skipping tokens until a
+  * semi-colon is found */
+ template <typename ManagedTokenSource>
+ void
+ Parser<ManagedTokenSource>::skip_after_semicolon ()
+ {
+   const_TokenPtr t = lexer.peek_token ();
+ 
+   while (t->get_id () != END_OF_FILE && t->get_id () != SEMICOLON)
+     {
+       lexer.skip_token ();
+       t = lexer.peek_token ();
+     }
+ 
+   if (t->get_id () == SEMICOLON)
+     lexer.skip_token ();
+ }
+ 
+ /* Skips the current token */
+ template <typename ManagedTokenSource>
+ void
+ Parser<ManagedTokenSource>::skip_token ()
+ {
+   lexer.skip_token ();
+ }
+ 
+ /* Checks if current token has inputted id - skips it and returns true if so,
+  * diagnoses an error and returns false otherwise. */
+ template <typename ManagedTokenSource>
+ bool
+ Parser<ManagedTokenSource>::skip_token (TokenId token_id)
+ {
+   return expect_token (token_id) != const_TokenPtr ();
+ }
+ 
+ /* Checks if current token is similar to inputted token - skips it and returns
+  * true if so, diagnoses an error and returns false otherwise. */
+ template <typename ManagedTokenSource>
+ bool
+ Parser<ManagedTokenSource>::skip_token (const_TokenPtr token)
+ {
+   return expect_token (token) != const_TokenPtr ();
+ }
+ 
+ /* Checks if current token has inputted id - skips it and returns true if so,
+  * returns false otherwise without diagnosing an error */
+ template <typename ManagedTokenSource>
+ bool
+ Parser<ManagedTokenSource>::maybe_skip_token (TokenId token_id)
+ {
+   if (lexer.peek_token ()->get_id () != token_id)
+     return false;
+   else
+     return skip_token (token_id);
+ }
+ 
+ /* Checks the current token - if id is same as expected, skips and returns it,
+  * otherwise diagnoses error and returns null. */
+ template <typename ManagedTokenSource>
+ const_TokenPtr
+ Parser<ManagedTokenSource>::expect_token (TokenId token_id)
+ {
+   const_TokenPtr t = lexer.peek_token ();
+   if (t->get_id () == token_id)
+     {
+       lexer.skip_token ();
+       return t;
+     }
+   else
+     {
+       Error error (t->get_locus (), "expecting %qs but %qs found",
+ 		   get_token_description (token_id),
+ 		   t->get_token_description ());
+       add_error (std::move (error));
+ 
+       return const_TokenPtr ();
+     }
+ }
+ 
+ /* Checks the current token - if same as expected, skips and returns it,
+  * otherwise diagnoses error and returns null. */
+ template <typename ManagedTokenSource>
+ const_TokenPtr
+ Parser<ManagedTokenSource>::expect_token (const_TokenPtr token_expect)
+ {
+   const_TokenPtr t = lexer.peek_token ();
+   if (t->get_id () == token_expect->get_id ()
+       && (!t->should_have_str () || t->get_str () == token_expect->get_str ()))
+     {
+       lexer.skip_token ();
+       return t;
+     }
+   else
+     {
+       Error error (t->get_locus (), "expecting %qs but %qs found",
+ 		   token_expect->get_token_description (),
+ 		   t->get_token_description ());
+       add_error (std::move (error));
+ 
+       return const_TokenPtr ();
+     }
+ }
+ 
+ // Skips all tokens until EOF or }. Don't use.
+ template <typename ManagedTokenSource>
+ void
+ Parser<ManagedTokenSource>::skip_after_end ()
+ {
+   const_TokenPtr t = lexer.peek_token ();
+ 
+   while (t->get_id () != END_OF_FILE && t->get_id () != RIGHT_CURLY)
+     {
+       lexer.skip_token ();
+       t = lexer.peek_token ();
+     }
+ 
+   if (t->get_id () == RIGHT_CURLY)
+     {
+       lexer.skip_token ();
+     }
+ }
+ 
+ /* A slightly more aware error-handler that skips all tokens until it reaches
+  * the end of the block scope (i.e. when left curly brackets = right curly
+  * brackets). Note: assumes currently in the middle of a block. Use
+  * skip_after_next_block to skip based on the assumption that the block
+  * has not been entered yet. */
+ template <typename ManagedTokenSource>
+ void
+ Parser<ManagedTokenSource>::skip_after_end_block ()
+ {
+   const_TokenPtr t = lexer.peek_token ();
+   int curly_count = 1;
+ 
+   while (curly_count > 0 && t->get_id () != END_OF_FILE)
+     {
+       switch (t->get_id ())
+ 	{
+ 	case LEFT_CURLY:
+ 	  curly_count++;
+ 	  break;
+ 	case RIGHT_CURLY:
+ 	  curly_count--;
+ 	  break;
+ 	default:
+ 	  break;
+ 	}
+       lexer.skip_token ();
+       t = lexer.peek_token ();
+     }
+ }
+ 
+ /* Skips tokens until the end of the next block. i.e. assumes that the block
+  * has not been entered yet. */
+ template <typename ManagedTokenSource>
+ void
+ Parser<ManagedTokenSource>::skip_after_next_block ()
+ {
+   const_TokenPtr t = lexer.peek_token ();
+ 
+   // initial loop - skip until EOF if no left curlies encountered
+   while (t->get_id () != END_OF_FILE && t->get_id () != LEFT_CURLY)
+     {
+       lexer.skip_token ();
+ 
+       t = lexer.peek_token ();
+     }
+ 
+   // if next token is left, skip it and then skip after the block ends
+   if (t->get_id () == LEFT_CURLY)
+     {
+       lexer.skip_token ();
+ 
+       skip_after_end_block ();
+     }
+   // otherwise, do nothing as EOF
+ }
+ 
+ /* Skips all tokens until ] (the end of an attribute) - does not skip the ]
+  * (as designed for attribute body use) */
+ template <typename ManagedTokenSource>
+ void
+ Parser<ManagedTokenSource>::skip_after_end_attribute ()
+ {
+   const_TokenPtr t = lexer.peek_token ();
+ 
+   while (t->get_id () != RIGHT_SQUARE && t->get_id () != END_OF_FILE)
+     {
+       lexer.skip_token ();
+       t = lexer.peek_token ();
+     }
+ 
+   // Don't skip the RIGHT_SQUARE token
+ }
+ 
+ // Returns true if the next token is END, ELSE, or EOF;
+ template <typename ManagedTokenSource>
+ bool
+ Parser<ManagedTokenSource>::done_end_or_else ()
+ {
+   const_TokenPtr t = lexer.peek_token ();
+   return (t->get_id () == RIGHT_CURLY || t->get_id () == ELSE
+ 	  || t->get_id () == END_OF_FILE);
+ }
+ 
+ // Returns true if the next token is END or EOF.
+ template <typename ManagedTokenSource>
+ bool
+ Parser<ManagedTokenSource>::done_end ()
+ {
+   const_TokenPtr t = lexer.peek_token ();
+   return (t->get_id () == RIGHT_CURLY || t->get_id () == END_OF_FILE);
+ }
+ 
+ } // namespace Rust
diff -Nrcpad gcc-16-20251214/gcc/rust/parse/rust-parse-impl.h gcc-16-20251221/gcc/rust/parse/rust-parse-impl.h
*** gcc-16-20251214/gcc/rust/parse/rust-parse-impl.h	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/rust/parse/rust-parse-impl.h	Thu Jan  1 00:00:00 1970
***************
*** 1,14596 ****
- // Copyright (C) 2020-2025 Free Software Foundation, Inc.
- 
- // This file is part of GCC.
- 
- // GCC is free software; you can redistribute it and/or modify it under
- // the terms of the GNU General Public License as published by the Free
- // Software Foundation; either version 3, or (at your option) any later
- // version.
- 
- // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
- // WARRANTY; without even the implied warranty of MERCHANTABILITY or
- // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- // for more details.
- 
- // You should have received a copy of the GNU General Public License
- // along with GCC; see the file COPYING3.  If not see
- // <http://www.gnu.org/licenses/>.
- 
- /* Template implementation for Rust::Parser. Previously in rust-parse.cc (before
-  * Parser was template). Separated from rust-parse.h for readability. */
- 
- /* DO NOT INCLUDE ANYWHERE - this is automatically included
-  *   by rust-parse-impl-*.cc
-  * This is also the reason why there are no include guards. */
- 
- #include "expected.h"
- #include "rust-ast.h"
- #include "rust-common.h"
- #include "rust-expr.h"
- #include "rust-item.h"
- #include "rust-common.h"
- #include "rust-parse.h"
- #include "rust-token.h"
- #define INCLUDE_ALGORITHM
- #include "rust-diagnostics.h"
- #include "rust-dir-owner.h"
- #include "rust-attribute-values.h"
- #include "rust-keyword-values.h"
- #include "rust-edition.h"
- 
- #include "optional.h"
- 
- namespace Rust {
- // Left binding powers of operations.
- enum binding_powers
- {
-   // Highest priority
-   LBP_HIGHEST = 100,
- 
-   LBP_PATH = 95,
- 
-   LBP_METHOD_CALL = 90,
- 
-   LBP_FIELD_EXPR = 85,
- 
-   LBP_FUNCTION_CALL = 80,
-   LBP_ARRAY_REF = LBP_FUNCTION_CALL,
- 
-   LBP_QUESTION_MARK = 75, // unary postfix - counts as left
- 
-   LBP_UNARY_PLUS = 70,		    // Used only when the null denotation is +
-   LBP_UNARY_MINUS = LBP_UNARY_PLUS, // Used only when the null denotation is -
-   LBP_UNARY_ASTERISK = LBP_UNARY_PLUS, // deref operator - unary prefix
-   LBP_UNARY_EXCLAM = LBP_UNARY_PLUS,
-   LBP_UNARY_AMP = LBP_UNARY_PLUS,
-   LBP_UNARY_AMP_MUT = LBP_UNARY_PLUS,
- 
-   LBP_AS = 65,
- 
-   LBP_MUL = 60,
-   LBP_DIV = LBP_MUL,
-   LBP_MOD = LBP_MUL,
- 
-   LBP_PLUS = 55,
-   LBP_MINUS = LBP_PLUS,
- 
-   LBP_L_SHIFT = 50,
-   LBP_R_SHIFT = LBP_L_SHIFT,
- 
-   LBP_AMP = 45,
- 
-   LBP_CARET = 40,
- 
-   LBP_PIPE = 35,
- 
-   LBP_EQUAL = 30,
-   LBP_NOT_EQUAL = LBP_EQUAL,
-   LBP_SMALLER_THAN = LBP_EQUAL,
-   LBP_SMALLER_EQUAL = LBP_EQUAL,
-   LBP_GREATER_THAN = LBP_EQUAL,
-   LBP_GREATER_EQUAL = LBP_EQUAL,
- 
-   LBP_LOGICAL_AND = 25,
- 
-   LBP_LOGICAL_OR = 20,
- 
-   LBP_DOT_DOT = 15,
-   LBP_DOT_DOT_EQ = LBP_DOT_DOT,
- 
-   // TODO: note all these assig operators are RIGHT associative!
-   LBP_ASSIG = 10,
-   LBP_PLUS_ASSIG = LBP_ASSIG,
-   LBP_MINUS_ASSIG = LBP_ASSIG,
-   LBP_MULT_ASSIG = LBP_ASSIG,
-   LBP_DIV_ASSIG = LBP_ASSIG,
-   LBP_MOD_ASSIG = LBP_ASSIG,
-   LBP_AMP_ASSIG = LBP_ASSIG,
-   LBP_PIPE_ASSIG = LBP_ASSIG,
-   LBP_CARET_ASSIG = LBP_ASSIG,
-   LBP_L_SHIFT_ASSIG = LBP_ASSIG,
-   LBP_R_SHIFT_ASSIG = LBP_ASSIG,
- 
-   // return, break, and closures as lowest priority?
-   LBP_RETURN = 5,
-   LBP_BREAK = LBP_RETURN,
-   LBP_CLOSURE = LBP_RETURN, // unary prefix operators
- 
- #if 0
-   // rust precedences
-   // used for closures
-   PREC_CLOSURE = -40,
-   // used for break, continue, return, and yield
-   PREC_JUMP = -30,
-   // used for range (although weird comment in rustc about this)
-   PREC_RANGE = -10,
-   // used for binary operators mentioned below - also cast, colon (type),
-   // assign, assign_op
-   PREC_BINOP = FROM_ASSOC_OP,
-   // used for box, address_of, let, unary (again, weird comment on let)
-   PREC_PREFIX = 50,
-   // used for await, call, method call, field, index, try,
-   // inline asm, macro invocation
-   PREC_POSTFIX = 60,
-   // used for array, repeat, tuple, literal, path, paren, if,
-   // while, for, 'loop', match, block, try block, async, struct
-   PREC_PAREN = 99,
-   PREC_FORCE_PAREN = 100,
- #endif
- 
-   // lowest priority
-   LBP_LOWEST = 0
- };
- 
- /* Returns whether the token can start a type (i.e. there is a valid type
-  * beginning with the token). */
- inline bool
- can_tok_start_type (TokenId id)
- {
-   switch (id)
-     {
-     case EXCLAM:
-     case LEFT_SQUARE:
-     case LEFT_ANGLE:
-     case UNDERSCORE:
-     case ASTERISK:
-     case AMP:
-     case LIFETIME:
-     case IDENTIFIER:
-     case SUPER:
-     case SELF:
-     case SELF_ALIAS:
-     case CRATE:
-     case DOLLAR_SIGN:
-     case SCOPE_RESOLUTION:
-     case LEFT_PAREN:
-     case FOR:
-     case ASYNC:
-     case CONST:
-     case UNSAFE:
-     case EXTERN_KW:
-     case FN_KW:
-     case IMPL:
-     case DYN:
-     case QUESTION_MARK:
-       return true;
-     default:
-       return false;
-     }
- }
- 
- /* Returns whether the token id is (or is likely to be) a right angle bracket.
-  * i.e. '>', '>>', '>=' and '>>=' tokens. */
- inline bool
- is_right_angle_tok (TokenId id)
- {
-   switch (id)
-     {
-     case RIGHT_ANGLE:
-     case RIGHT_SHIFT:
-     case GREATER_OR_EQUAL:
-     case RIGHT_SHIFT_EQ:
-       return true;
-     default:
-       return false;
-     }
- }
- 
- /* HACK-y special handling for skipping a right angle token at the end of
-  * generic arguments.
-  * Currently, this replaces the "current token" with one that is identical
-  * except has the leading '>' removed (e.g. '>>' becomes '>'). This is bad
-  * for several reasons - it modifies the token stream to something that
-  * actually doesn't make syntactic sense, it may not worked if the token
-  * has already been skipped, etc. It was done because it would not
-  * actually require inserting new items into the token stream (which I
-  * thought would take more work to not mess up) and because I wasn't sure
-  * if the "already seen right angle" flag in the parser would work
-  * correctly.
-  * Those two other approaches listed are in my opinion actually better
-  * long-term - insertion is probably best as it reflects syntactically
-  * what occurs. On the other hand, I need to do a code audit to make sure
-  * that insertion doesn't mess anything up. So that's a FIXME. */
- template <typename ManagedTokenSource>
- bool
- Parser<ManagedTokenSource>::skip_generics_right_angle ()
- {
-   /* OK, new great idea. Have a lexer method called
-    * "split_current_token(TokenType newLeft, TokenType newRight)", which is
-    * called here with whatever arguments are appropriate. That lexer method
-    * handles "replacing" the current token with the "newLeft" and "inserting"
-    * the next token with the "newRight" (and creating a location, etc. for it)
-    */
- 
-   /* HACK: special handling for right shift '>>', greater or equal '>=', and
-    * right shift assig */
-   // '>>='
-   const_TokenPtr tok = lexer.peek_token ();
-   switch (tok->get_id ())
-     {
-     case RIGHT_ANGLE:
-       // this is good - skip token
-       lexer.skip_token ();
-       return true;
-     case RIGHT_SHIFT:
-       {
- 	// new implementation that should be better
- 	lexer.split_current_token (RIGHT_ANGLE, RIGHT_ANGLE);
- 	lexer.skip_token ();
- 	return true;
-       }
-     case GREATER_OR_EQUAL:
-       {
- 	// new implementation that should be better
- 	lexer.split_current_token (RIGHT_ANGLE, EQUAL);
- 	lexer.skip_token ();
- 	return true;
-       }
-     case RIGHT_SHIFT_EQ:
-       {
- 	// new implementation that should be better
- 	lexer.split_current_token (RIGHT_ANGLE, GREATER_OR_EQUAL);
- 	lexer.skip_token ();
- 	return true;
-       }
-     default:
-       add_error (Error (tok->get_locus (),
- 			"expected %<>%> at end of generic argument - found %qs",
- 			tok->get_token_description ()));
-       return false;
-     }
- }
- 
- /* Gets left binding power for specified token.
-  * Not suitable for use at the moment or possibly ever because binding power
-  * cannot be purely determined from operator token with Rust grammar - e.g.
-  * method call and field access have
-  * different left binding powers but the same operator token. */
- template <typename ManagedTokenSource>
- int
- Parser<ManagedTokenSource>::left_binding_power (const_TokenPtr token)
- {
-   // HACK: called with "peek_token()", so lookahead is "peek_token(1)"
-   switch (token->get_id ())
-     {
-       /* TODO: issue here - distinguish between method calls and field access
-        * somehow? Also would have to distinguish between paths and function
-        * calls (:: operator), maybe more stuff. */
-       /* Current plan for tackling LBP - don't do it based on token, use
-        * lookahead. Or alternatively, only use Pratt parsing for OperatorExpr
-        * and handle other expressions without it. rustc only considers
-        * arithmetic, logical/relational, 'as',
-        * '?=', ranges, colons, and assignment to have operator precedence and
-        * associativity rules applicable. It then has
-        * a separate "ExprPrecedence" that also includes binary operators. */
- 
-       // TODO: handle operator overloading - have a function replace the
-       // operator?
- 
-       /*case DOT:
- 	  return LBP_DOT;*/
- 
-     case SCOPE_RESOLUTION:
-       rust_debug (
- 	"possible error - looked up LBP of scope resolution operator. should "
- 	"be handled elsewhere.");
-       return LBP_PATH;
- 
-     /* Resolved by lookahead HACK that should work with current code. If next
-      * token is identifier and token after that isn't parenthesised expression
-      * list, it is a field reference. */
-     case DOT:
-       if (lexer.peek_token (1)->get_id () == IDENTIFIER
- 	  && lexer.peek_token (2)->get_id () != LEFT_PAREN)
- 	{
- 	  return LBP_FIELD_EXPR;
- 	}
-       return LBP_METHOD_CALL;
- 
-     case LEFT_PAREN:
-       return LBP_FUNCTION_CALL;
- 
-     case LEFT_SQUARE:
-       return LBP_ARRAY_REF;
- 
-     // postfix question mark (i.e. error propagation expression)
-     case QUESTION_MARK:
-       return LBP_QUESTION_MARK;
- 
-     case AS:
-       return LBP_AS;
- 
-     case ASTERISK:
-       return LBP_MUL;
-     case DIV:
-       return LBP_DIV;
-     case PERCENT:
-       return LBP_MOD;
- 
-     case PLUS:
-       return LBP_PLUS;
-     case MINUS:
-       return LBP_MINUS;
- 
-     case LEFT_SHIFT:
-       return LBP_L_SHIFT;
-     case RIGHT_SHIFT:
-       return LBP_R_SHIFT;
- 
-     // binary & operator
-     case AMP:
-       return LBP_AMP;
- 
-     // binary ^ operator
-     case CARET:
-       return LBP_CARET;
- 
-     // binary | operator
-     case PIPE:
-       return LBP_PIPE;
- 
-     case EQUAL_EQUAL:
-       return LBP_EQUAL;
-     case NOT_EQUAL:
-       return LBP_NOT_EQUAL;
-     case RIGHT_ANGLE:
-       return LBP_GREATER_THAN;
-     case GREATER_OR_EQUAL:
-       return LBP_GREATER_EQUAL;
-     case LEFT_ANGLE:
-       return LBP_SMALLER_THAN;
-     case LESS_OR_EQUAL:
-       return LBP_SMALLER_EQUAL;
- 
-     case LOGICAL_AND:
-       return LBP_LOGICAL_AND;
- 
-     case OR:
-       return LBP_LOGICAL_OR;
- 
-     case DOT_DOT:
-       return LBP_DOT_DOT;
- 
-     case DOT_DOT_EQ:
-       return LBP_DOT_DOT_EQ;
- 
-     case EQUAL:
-       return LBP_ASSIG;
-     case PLUS_EQ:
-       return LBP_PLUS_ASSIG;
-     case MINUS_EQ:
-       return LBP_MINUS_ASSIG;
-     case ASTERISK_EQ:
-       return LBP_MULT_ASSIG;
-     case DIV_EQ:
-       return LBP_DIV_ASSIG;
-     case PERCENT_EQ:
-       return LBP_MOD_ASSIG;
-     case AMP_EQ:
-       return LBP_AMP_ASSIG;
-     case PIPE_EQ:
-       return LBP_PIPE_ASSIG;
-     case CARET_EQ:
-       return LBP_CARET_ASSIG;
-     case LEFT_SHIFT_EQ:
-       return LBP_L_SHIFT_ASSIG;
-     case RIGHT_SHIFT_EQ:
-       return LBP_R_SHIFT_ASSIG;
- 
-     /* HACK: float literal due to lexer misidentifying a dot then an integer as
-      * a float */
-     case FLOAT_LITERAL:
-       return LBP_FIELD_EXPR;
-       // field expr is same as tuple expr in precedence, i imagine
-       // TODO: is this needed anymore? lexer shouldn't do that anymore
- 
-     // anything that can't appear in an infix position is given lowest priority
-     default:
-       return LBP_LOWEST;
-     }
- }
- 
- // Returns true when current token is EOF.
- template <typename ManagedTokenSource>
- bool
- Parser<ManagedTokenSource>::done_end_of_file ()
- {
-   return lexer.peek_token ()->get_id () == END_OF_FILE;
- }
- 
- // Parses a sequence of items within a module or the implicit top-level module
- // in a crate
- template <typename ManagedTokenSource>
- std::vector<std::unique_ptr<AST::Item>>
- Parser<ManagedTokenSource>::parse_items ()
- {
-   std::vector<std::unique_ptr<AST::Item>> items;
- 
-   const_TokenPtr t = lexer.peek_token ();
-   while (t->get_id () != END_OF_FILE)
-     {
-       std::unique_ptr<AST::Item> item = parse_item (false);
-       if (item == nullptr)
- 	{
- 	  // TODO: should all items be cleared?
- 	  items = std::vector<std::unique_ptr<AST::Item>> ();
- 	  break;
- 	}
- 
-       items.push_back (std::move (item));
- 
-       t = lexer.peek_token ();
-     }
- 
-   return items;
- }
- 
- // Parses a crate (compilation unit) - entry point
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::Crate>
- Parser<ManagedTokenSource>::parse_crate ()
- {
-   // parse inner attributes
-   AST::AttrVec inner_attrs = parse_inner_attributes ();
- 
-   // parse items
-   std::vector<std::unique_ptr<AST::Item>> items = parse_items ();
- 
-   // emit all errors
-   for (const auto &error : error_table)
-     error.emit ();
- 
-   return std::unique_ptr<AST::Crate> (
-     new AST::Crate (std::move (items), std::move (inner_attrs)));
- }
- 
- // Parse a contiguous block of inner attributes.
- template <typename ManagedTokenSource>
- AST::AttrVec
- Parser<ManagedTokenSource>::parse_inner_attributes ()
- {
-   AST::AttrVec inner_attributes;
- 
-   // only try to parse it if it starts with "#!" not only "#"
-   while ((lexer.peek_token ()->get_id () == HASH
- 	  && lexer.peek_token (1)->get_id () == EXCLAM)
- 	 || lexer.peek_token ()->get_id () == INNER_DOC_COMMENT)
-     {
-       AST::Attribute inner_attr = parse_inner_attribute ();
- 
-       /* Ensure only valid inner attributes are added to the inner_attributes
-        * list */
-       if (!inner_attr.is_empty ())
- 	{
- 	  inner_attributes.push_back (std::move (inner_attr));
- 	}
-       else
- 	{
- 	  /* If no more valid inner attributes, break out of loop (only
- 	   * contiguous inner attributes parsed). */
- 	  break;
- 	}
-     }
- 
-   inner_attributes.shrink_to_fit ();
-   return inner_attributes;
- }
- 
- // Parse a inner or outer doc comment into an doc attribute
- template <typename ManagedTokenSource>
- std::tuple<AST::SimplePath, std::unique_ptr<AST::AttrInput>, location_t>
- Parser<ManagedTokenSource>::parse_doc_comment ()
- {
-   const_TokenPtr token = lexer.peek_token ();
-   location_t locus = token->get_locus ();
-   AST::SimplePathSegment segment (Values::Attributes::DOC, locus);
-   std::vector<AST::SimplePathSegment> segments;
-   segments.push_back (std::move (segment));
-   AST::SimplePath attr_path (std::move (segments), false, locus);
-   AST::LiteralExpr lit_expr (token->get_str (), AST::Literal::STRING,
- 			     PrimitiveCoreType::CORETYPE_STR, {}, locus);
-   std::unique_ptr<AST::AttrInput> attr_input (
-     new AST::AttrInputLiteral (std::move (lit_expr)));
-   lexer.skip_token ();
-   return std::make_tuple (std::move (attr_path), std::move (attr_input), locus);
- }
- 
- // Parse a single inner attribute.
- template <typename ManagedTokenSource>
- AST::Attribute
- Parser<ManagedTokenSource>::parse_inner_attribute ()
- {
-   if (lexer.peek_token ()->get_id () == INNER_DOC_COMMENT)
-     {
-       auto values = parse_doc_comment ();
-       auto path = std::move (std::get<0> (values));
-       auto input = std::move (std::get<1> (values));
-       auto loc = std::get<2> (values);
-       return AST::Attribute (std::move (path), std::move (input), loc, true);
-     }
- 
-   if (lexer.peek_token ()->get_id () != HASH)
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "BUG: token %<#%> is missing, but %<parse_inner_attribute%> "
- 		   "was invoked");
-       add_error (std::move (error));
- 
-       return AST::Attribute::create_empty ();
-     }
-   lexer.skip_token ();
- 
-   if (lexer.peek_token ()->get_id () != EXCLAM)
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "expected %<!%> or %<[%> for inner attribute");
-       add_error (std::move (error));
- 
-       return AST::Attribute::create_empty ();
-     }
-   lexer.skip_token ();
- 
-   if (!skip_token (LEFT_SQUARE))
-     return AST::Attribute::create_empty ();
- 
-   auto values = parse_attribute_body ();
- 
-   auto path = std::move (std::get<0> (values));
-   auto input = std::move (std::get<1> (values));
-   auto loc = std::get<2> (values);
-   auto actual_attribute
-     = AST::Attribute (std::move (path), std::move (input), loc, true);
- 
-   if (!skip_token (RIGHT_SQUARE))
-     return AST::Attribute::create_empty ();
- 
-   return actual_attribute;
- }
- 
- // Parses the body of an attribute (inner or outer).
- template <typename ManagedTokenSource>
- std::tuple<AST::SimplePath, std::unique_ptr<AST::AttrInput>, location_t>
- Parser<ManagedTokenSource>::parse_attribute_body ()
- {
-   location_t locus = lexer.peek_token ()->get_locus ();
- 
-   AST::SimplePath attr_path = parse_simple_path ();
-   // ensure path is valid to parse attribute input
-   if (attr_path.is_empty ())
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "empty simple path in attribute");
-       add_error (std::move (error));
- 
-       // Skip past potential further info in attribute (i.e. attr_input)
-       skip_after_end_attribute ();
-       return std::make_tuple (std::move (attr_path), nullptr, UNDEF_LOCATION);
-     }
- 
-   std::unique_ptr<AST::AttrInput> attr_input = parse_attr_input ();
-   // AttrInput is allowed to be null, so no checks here
- 
-   return std::make_tuple (std::move (attr_path), std::move (attr_input), locus);
- }
- 
- /* Determines whether token is a valid simple path segment. This does not
-  * include scope resolution operators. */
- inline bool
- is_simple_path_segment (TokenId id)
- {
-   switch (id)
-     {
-     case IDENTIFIER:
-     case SUPER:
-     case SELF:
-     case CRATE:
-       return true;
-     case DOLLAR_SIGN:
-       // assume that dollar sign leads to $crate
-       return true;
-     default:
-       return false;
-     }
- }
- 
- // Parses a SimplePath AST node, if it exists. Does nothing otherwise.
- template <typename ManagedTokenSource>
- AST::SimplePath
- Parser<ManagedTokenSource>::parse_simple_path ()
- {
-   bool has_opening_scope_resolution = false;
-   location_t locus = UNKNOWN_LOCATION;
- 
-   // don't parse anything if not a path upfront
-   if (!is_simple_path_segment (lexer.peek_token ()->get_id ())
-       && !is_simple_path_segment (lexer.peek_token (1)->get_id ()))
-     return AST::SimplePath::create_empty ();
- 
-   /* Checks for opening scope resolution (i.e. global scope fully-qualified
-    * path) */
-   if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION)
-     {
-       has_opening_scope_resolution = true;
- 
-       locus = lexer.peek_token ()->get_locus ();
- 
-       lexer.skip_token ();
-     }
- 
-   // Parse single required simple path segment
-   AST::SimplePathSegment segment = parse_simple_path_segment ();
- 
-   // get location if not gotten already
-   if (locus == UNKNOWN_LOCATION)
-     locus = segment.get_locus ();
- 
-   std::vector<AST::SimplePathSegment> segments;
- 
-   // Return empty vector if first, actually required segment is an error
-   if (segment.is_error ())
-     return AST::SimplePath::create_empty ();
- 
-   segments.push_back (std::move (segment));
- 
-   // Parse all other simple path segments
-   while (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION)
-     {
-       AST::SimplePathSegment new_segment = parse_simple_path_segment (1);
- 
-       // Return path as currently constructed if segment in error state.
-       if (new_segment.is_error ())
- 	break;
- 
-       segments.push_back (std::move (new_segment));
-     }
- 
-   // DEBUG: check for any empty segments
-   for (const auto &seg : segments)
-     {
-       if (seg.is_error ())
- 	{
- 	  rust_debug (
- 	    "when parsing simple path, somehow empty path segment was "
- 	    "not filtered out. Path begins with '%s'",
- 	    segments.at (0).as_string ().c_str ());
- 	}
-     }
- 
-   return AST::SimplePath (std::move (segments), has_opening_scope_resolution,
- 			  locus);
-   /* TODO: now that is_simple_path_segment exists, could probably start
-    * actually making errors upon parse failure of segments and whatever */
- }
- 
- /* Parses a single SimplePathSegment (does not handle the scope resolution
-  * operators)
-  * Starts parsing at an offset of base_peek */
- template <typename ManagedTokenSource>
- AST::SimplePathSegment
- Parser<ManagedTokenSource>::parse_simple_path_segment (int base_peek)
- {
-   using namespace Values;
-   const_TokenPtr t = lexer.peek_token (base_peek);
-   switch (t->get_id ())
-     {
-     case IDENTIFIER:
-       lexer.skip_token (base_peek);
- 
-       return AST::SimplePathSegment (t->get_str (), t->get_locus ());
-     case SUPER:
-       lexer.skip_token (base_peek);
- 
-       return AST::SimplePathSegment (Keywords::SUPER, t->get_locus ());
-     case SELF:
-       lexer.skip_token (base_peek);
- 
-       return AST::SimplePathSegment (Keywords::SELF, t->get_locus ());
-     case CRATE:
-       lexer.skip_token (base_peek);
- 
-       return AST::SimplePathSegment (Keywords::CRATE, t->get_locus ());
-     case DOLLAR_SIGN:
-       if (lexer.peek_token (base_peek + 1)->get_id () == CRATE)
- 	{
- 	  lexer.skip_token (base_peek + 1);
- 
- 	  return AST::SimplePathSegment ("$crate", t->get_locus ());
- 	}
-       gcc_fallthrough ();
-     default:
-       // do nothing but inactivates warning from gcc when compiling
-       /* could put the rust_error_at thing here but fallthrough (from failing
-        * $crate condition) isn't completely obvious if it is. */
- 
-       // test prevent error
-       return AST::SimplePathSegment::create_error ();
-     }
-   rust_unreachable ();
-   /*rust_error_at(
-     t->get_locus(), "invalid token '%s' in simple path segment",
-     t->get_token_description());*/
-   // this is not necessarily an error, e.g. end of path
-   // return AST::SimplePathSegment::create_error();
- }
- 
- // Parses a PathIdentSegment - an identifier segment of a non-SimplePath path.
- template <typename ManagedTokenSource>
- AST::PathIdentSegment
- Parser<ManagedTokenSource>::parse_path_ident_segment ()
- {
-   const_TokenPtr t = lexer.peek_token ();
-   switch (t->get_id ())
-     {
-     case IDENTIFIER:
-       lexer.skip_token ();
- 
-       return AST::PathIdentSegment (t->get_str (), t->get_locus ());
-     case SUPER:
-       lexer.skip_token ();
- 
-       return AST::PathIdentSegment (Values::Keywords::SUPER, t->get_locus ());
-     case SELF:
-       lexer.skip_token ();
- 
-       return AST::PathIdentSegment (Values::Keywords::SELF, t->get_locus ());
-     case SELF_ALIAS:
-       lexer.skip_token ();
- 
-       return AST::PathIdentSegment (Values::Keywords::SELF_ALIAS,
- 				    t->get_locus ());
-     case CRATE:
-       lexer.skip_token ();
- 
-       return AST::PathIdentSegment (Values::Keywords::CRATE, t->get_locus ());
-     case DOLLAR_SIGN:
-       if (lexer.peek_token (1)->get_id () == CRATE)
- 	{
- 	  lexer.skip_token (1);
- 
- 	  return AST::PathIdentSegment ("$crate", t->get_locus ());
- 	}
-       gcc_fallthrough ();
-     default:
-       /* do nothing but inactivates warning from gcc when compiling
-        * could put the error_at thing here but fallthrough (from failing $crate
-        * condition) isn't completely obvious if it is. */
- 
-       // test prevent error
-       return AST::PathIdentSegment::create_error ();
-     }
-   rust_unreachable ();
-   // not necessarily an error
- }
- 
- // Parses an AttrInput AST node (polymorphic, as AttrInput is abstract)
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::AttrInput>
- Parser<ManagedTokenSource>::parse_attr_input ()
- {
-   const_TokenPtr t = lexer.peek_token ();
-   switch (t->get_id ())
-     {
-     case LEFT_PAREN:
-     case LEFT_SQUARE:
-     case LEFT_CURLY:
-       {
- 	// must be a delimited token tree, so parse that
- 	std::unique_ptr<AST::AttrInput> input_tree (
- 	  new AST::DelimTokenTree (parse_delim_token_tree ()));
- 
- 	// TODO: potential checks on DelimTokenTree before returning
- 
- 	return input_tree;
-       }
-     case EQUAL:
-       {
- 	// = LiteralExpr
- 	lexer.skip_token ();
- 
- 	t = lexer.peek_token ();
- 
- 	// attempt to parse macro
- 	// TODO: macros may/may not be allowed in attributes
- 	// this is needed for "#[doc = include_str!(...)]"
- 	if (is_simple_path_segment (t->get_id ()))
- 	  {
- 	    std::unique_ptr<AST::MacroInvocation> invoke
- 	      = parse_macro_invocation ({});
- 
- 	    if (!invoke)
- 	      return nullptr;
- 
- 	    return std::unique_ptr<AST::AttrInput> (
- 	      new AST::AttrInputMacro (std::move (invoke)));
- 	  }
- 
- 	/* Ensure token is a "literal expression" (literally only a literal
- 	 * token of any type) */
- 	if (!t->is_literal ())
- 	  {
- 	    Error error (
- 	      t->get_locus (),
- 	      "unknown token %qs in attribute body - literal expected",
- 	      t->get_token_description ());
- 	    add_error (std::move (error));
- 
- 	    skip_after_end_attribute ();
- 	    return nullptr;
- 	  }
- 
- 	AST::Literal::LitType lit_type = AST::Literal::STRING;
- 	// Crappy mapping of token type to literal type
- 	switch (t->get_id ())
- 	  {
- 	  case INT_LITERAL:
- 	    lit_type = AST::Literal::INT;
- 	    break;
- 	  case FLOAT_LITERAL:
- 	    lit_type = AST::Literal::FLOAT;
- 	    break;
- 	  case CHAR_LITERAL:
- 	    lit_type = AST::Literal::CHAR;
- 	    break;
- 	  case BYTE_CHAR_LITERAL:
- 	    lit_type = AST::Literal::BYTE;
- 	    break;
- 	  case BYTE_STRING_LITERAL:
- 	    lit_type = AST::Literal::BYTE_STRING;
- 	    break;
- 	  case RAW_STRING_LITERAL:
- 	    lit_type = AST::Literal::RAW_STRING;
- 	    break;
- 	  case STRING_LITERAL:
- 	  default:
- 	    lit_type = AST::Literal::STRING;
- 	    break; // TODO: raw string? don't eliminate it from lexer?
- 	  }
- 
- 	// create actual LiteralExpr
- 	AST::LiteralExpr lit_expr (t->get_str (), lit_type, t->get_type_hint (),
- 				   {}, t->get_locus ());
- 	lexer.skip_token ();
- 
- 	std::unique_ptr<AST::AttrInput> attr_input_lit (
- 	  new AST::AttrInputLiteral (std::move (lit_expr)));
- 
- 	// do checks or whatever? none required, really
- 
- 	// FIXME: shouldn't a skip token be required here?
- 
- 	return attr_input_lit;
-       }
-       break;
-     case RIGHT_PAREN:
-     case RIGHT_SQUARE:
-     case RIGHT_CURLY:
-     case END_OF_FILE:
-       // means AttrInput is missing, which is allowed
-       return nullptr;
-     default:
-       add_error (
- 	Error (t->get_locus (),
- 	       "unknown token %qs in attribute body - attribute input or "
- 	       "none expected",
- 	       t->get_token_description ()));
- 
-       skip_after_end_attribute ();
-       return nullptr;
-     }
-   rust_unreachable ();
-   // TODO: find out how to stop gcc error on "no return value"
- }
- 
- /* Returns true if the token id matches the delimiter type. Note that this only
-  * operates for END delimiter tokens. */
- inline bool
- token_id_matches_delims (TokenId token_id, AST::DelimType delim_type)
- {
-   return ((token_id == RIGHT_PAREN && delim_type == AST::PARENS)
- 	  || (token_id == RIGHT_SQUARE && delim_type == AST::SQUARE)
- 	  || (token_id == RIGHT_CURLY && delim_type == AST::CURLY));
- }
- 
- /* Returns true if the likely result of parsing the next few tokens is a path.
-  * Not guaranteed, though, especially in the case of syntax errors. */
- inline bool
- is_likely_path_next (TokenId next_token_id)
- {
-   switch (next_token_id)
-     {
-     case IDENTIFIER:
-     case SUPER:
-     case SELF:
-     case SELF_ALIAS:
-     case CRATE:
-     // maybe - maybe do extra check. But then requires another TokenId.
-     case DOLLAR_SIGN:
-     case SCOPE_RESOLUTION:
-       return true;
-     default:
-       return false;
-     }
- }
- 
- // Parses a delimited token tree
- template <typename ManagedTokenSource>
- AST::DelimTokenTree
- Parser<ManagedTokenSource>::parse_delim_token_tree ()
- {
-   const_TokenPtr t = lexer.peek_token ();
-   lexer.skip_token ();
-   location_t initial_loc = t->get_locus ();
- 
-   // save delim type to ensure it is reused later
-   AST::DelimType delim_type = AST::PARENS;
- 
-   // Map tokens to DelimType
-   switch (t->get_id ())
-     {
-     case LEFT_PAREN:
-       delim_type = AST::PARENS;
-       break;
-     case LEFT_SQUARE:
-       delim_type = AST::SQUARE;
-       break;
-     case LEFT_CURLY:
-       delim_type = AST::CURLY;
-       break;
-     default:
-       add_error (Error (t->get_locus (),
- 			"unexpected token %qs - expecting delimiters (for a "
- 			"delimited token tree)",
- 			t->get_token_description ()));
- 
-       return AST::DelimTokenTree::create_empty ();
-     }
- 
-   // parse actual token tree vector - 0 or more
-   std::vector<std::unique_ptr<AST::TokenTree>> token_trees_in_tree;
-   auto delim_open
-     = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
-   token_trees_in_tree.push_back (std::move (delim_open));
- 
-   // repeat loop until finding the matching delimiter
-   t = lexer.peek_token ();
-   while (!token_id_matches_delims (t->get_id (), delim_type)
- 	 && t->get_id () != END_OF_FILE)
-     {
-       std::unique_ptr<AST::TokenTree> tok_tree = parse_token_tree ();
- 
-       if (tok_tree == nullptr)
- 	return AST::DelimTokenTree::create_empty ();
- 
-       token_trees_in_tree.push_back (std::move (tok_tree));
- 
-       // lexer.skip_token();
-       t = lexer.peek_token ();
-     }
-   auto delim_close
-     = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
-   token_trees_in_tree.push_back (std::move (delim_close));
- 
-   AST::DelimTokenTree token_tree (delim_type, std::move (token_trees_in_tree),
- 				  initial_loc);
- 
-   // parse end delimiters
-   t = lexer.peek_token ();
- 
-   if (token_id_matches_delims (t->get_id (), delim_type))
-     {
-       // tokens match opening delimiter, so skip.
-       lexer.skip_token ();
- 
-       // DEBUG
-       rust_debug ("finished parsing new delim token tree - peeked token is now "
- 		  "'%s' while t is '%s'",
- 		  lexer.peek_token ()->get_token_description (),
- 		  t->get_token_description ());
- 
-       return token_tree;
-     }
-   else
-     {
-       // tokens don't match opening delimiters, so produce error
-       Error error (t->get_locus (),
- 		   "unexpected token %qs - expecting closing delimiter %qs "
- 		   "(for a delimited token tree)",
- 		   t->get_token_description (),
- 		   (delim_type == AST::PARENS
- 		      ? ")"
- 		      : (delim_type == AST::SQUARE ? "]" : "}")));
-       add_error (std::move (error));
- 
-       /* return empty token tree despite possibly parsing valid token tree -
-        * TODO is this a good idea? */
-       return AST::DelimTokenTree::create_empty ();
-     }
- }
- 
- // Parses an identifier/keyword as a Token
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::Token>
- Parser<ManagedTokenSource>::parse_identifier_or_keyword_token ()
- {
-   const_TokenPtr t = lexer.peek_token ();
- 
-   if (t->get_id () == IDENTIFIER || token_id_is_keyword (t->get_id ()))
-     {
-       lexer.skip_token ();
-       return std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
-     }
-   else
-     {
-       add_error (Error (t->get_locus (), "expected keyword or identifier"));
-       return nullptr;
-     }
- }
- 
- /* Parses a TokenTree syntactical production. This is either a delimited token
-  * tree or a non-delimiter token. */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::TokenTree>
- Parser<ManagedTokenSource>::parse_token_tree ()
- {
-   const_TokenPtr t = lexer.peek_token ();
- 
-   switch (t->get_id ())
-     {
-     case LEFT_PAREN:
-     case LEFT_SQUARE:
-     case LEFT_CURLY:
-       // Parse delimited token tree
-       // TODO: use move rather than copy constructor
-       return std::unique_ptr<AST::DelimTokenTree> (
- 	new AST::DelimTokenTree (parse_delim_token_tree ()));
-     case RIGHT_PAREN:
-     case RIGHT_SQUARE:
-     case RIGHT_CURLY:
-       // error - should not be called when this a token
-       add_error (Error (t->get_locus (), "unexpected closing delimiter %qs",
- 			t->get_token_description ()));
- 
-       add_error (Error (Error::Kind::Hint, t->get_locus (),
- 			"token tree requires either paired delimiters or "
- 			"non-delimiter tokens"));
- 
-       lexer.skip_token ();
-       return nullptr;
-     default:
-       // parse token itself as TokenTree
-       lexer.skip_token ();
-       return std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
-     }
- }
- 
- template <typename ManagedTokenSource>
- bool
- Parser<ManagedTokenSource>::is_macro_rules_def (const_TokenPtr t)
- {
-   auto macro_name = lexer.peek_token (2)->get_id ();
- 
-   bool allowed_macro_name = (macro_name == IDENTIFIER || macro_name == TRY);
- 
-   return t->get_str () == Values::WeakKeywords::MACRO_RULES
- 	 && lexer.peek_token (1)->get_id () == EXCLAM && allowed_macro_name;
- }
- 
- // Parses a single item
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::Item>
- Parser<ManagedTokenSource>::parse_item (bool called_from_statement)
- {
-   // has a "called_from_statement" parameter for better error message handling
- 
-   // parse outer attributes for item
-   AST::AttrVec outer_attrs = parse_outer_attributes ();
-   const_TokenPtr t = lexer.peek_token ();
- 
-   switch (t->get_id ())
-     {
-     case END_OF_FILE:
-       // not necessarily an error, unless we just read outer
-       // attributes which needs to be attached
-       if (!outer_attrs.empty ())
- 	{
- 	  Rust::AST::Attribute attr = outer_attrs.back ();
- 	  Error error (attr.get_locus (),
- 		       "expected item after outer attribute or doc comment");
- 	  add_error (std::move (error));
- 	}
-       return nullptr;
- 
-     case ASYNC:
-     case PUB:
-     case MOD:
-     case EXTERN_KW:
-     case USE:
-     case FN_KW:
-     case TYPE:
-     case STRUCT_KW:
-     case ENUM_KW:
-     case CONST:
-     case STATIC_KW:
-     case AUTO:
-     case TRAIT:
-     case IMPL:
-     case MACRO:
-     /* TODO: implement union keyword but not really because of
-      * context-dependence crappy hack way to parse a union written below to
-      * separate it from the good code. */
-     // case UNION:
-     case UNSAFE: // maybe - unsafe traits are a thing
-       // if any of these (should be all possible VisItem prefixes), parse a
-       // VisItem
-       return parse_vis_item (std::move (outer_attrs));
-       break;
-     case SUPER:
-     case SELF:
-     case CRATE:
-     case DOLLAR_SIGN:
-       // almost certainly macro invocation semi
-       return parse_macro_invocation_semi (std::move (outer_attrs));
-       break;
-     // crappy hack to do union "keyword"
-     case IDENTIFIER:
-       // TODO: ensure std::string and literal comparison works
-       if (t->get_str () == Values::WeakKeywords::UNION
- 	  && lexer.peek_token (1)->get_id () == IDENTIFIER)
- 	{
- 	  return parse_vis_item (std::move (outer_attrs));
- 	  // or should this go straight to parsing union?
- 	}
-       else if (t->get_str () == Values::WeakKeywords::DEFAULT
- 	       && lexer.peek_token (1)->get_id () != EXCLAM)
- 	{
- 	  add_error (Error (t->get_locus (),
- 			    "%qs is only allowed on items within %qs blocks",
- 			    "default", "impl"));
- 	  return nullptr;
- 	}
-       else if (is_macro_rules_def (t))
- 	{
- 	  // macro_rules! macro item
- 	  return parse_macro_rules_def (std::move (outer_attrs));
- 	}
-       else if (lexer.peek_token (1)->get_id () == SCOPE_RESOLUTION
- 	       || lexer.peek_token (1)->get_id () == EXCLAM)
- 	{
- 	  /* path (probably) or macro invocation, so probably a macro invocation
- 	   * semi */
- 	  return parse_macro_invocation_semi (std::move (outer_attrs));
- 	}
-       gcc_fallthrough ();
-     default:
-       // otherwise unrecognised
-       add_error (Error (t->get_locus (),
- 			"unrecognised token %qs for start of %s",
- 			t->get_token_description (),
- 			called_from_statement ? "statement" : "item"));
- 
-       // skip somewhere?
-       return nullptr;
-       break;
-     }
- }
- 
- // Parses a contiguous block of outer attributes.
- template <typename ManagedTokenSource>
- AST::AttrVec
- Parser<ManagedTokenSource>::parse_outer_attributes ()
- {
-   AST::AttrVec outer_attributes;
- 
-   while (lexer.peek_token ()->get_id ()
- 	   == HASH /* Can also be #!, which catches errors.  */
- 	 || lexer.peek_token ()->get_id () == OUTER_DOC_COMMENT
- 	 || lexer.peek_token ()->get_id ()
- 	      == INNER_DOC_COMMENT) /* For error handling.  */
-     {
-       AST::Attribute outer_attr = parse_outer_attribute ();
- 
-       /* Ensure only valid outer attributes are added to the outer_attributes
-        * list */
-       if (!outer_attr.is_empty ())
- 	{
- 	  outer_attributes.push_back (std::move (outer_attr));
- 	}
-       else
- 	{
- 	  /* If no more valid outer attributes, break out of loop (only
- 	   * contiguous outer attributes parsed). */
- 	  break;
- 	}
-     }
- 
-   outer_attributes.shrink_to_fit ();
-   return outer_attributes;
- 
-   /* TODO: this shares basically all code with parse_inner_attributes except
-    * function call - find way of making it more modular? function pointer? */
- }
- 
- // Parse a single outer attribute.
- template <typename ManagedTokenSource>
- AST::Attribute
- Parser<ManagedTokenSource>::parse_outer_attribute ()
- {
-   if (lexer.peek_token ()->get_id () == OUTER_DOC_COMMENT)
-     {
-       auto values = parse_doc_comment ();
-       auto path = std::move (std::get<0> (values));
-       auto input = std::move (std::get<1> (values));
-       auto loc = std::get<2> (values);
-       return AST::Attribute (std::move (path), std::move (input), loc, false);
-     }
- 
-   if (lexer.peek_token ()->get_id () == INNER_DOC_COMMENT)
-     {
-       Error error (
- 	lexer.peek_token ()->get_locus (), ErrorCode::E0753,
- 	"expected outer doc comment, inner doc (%<//!%> or %</*!%>) only "
- 	"allowed at start of item "
- 	"and before any outer attribute or doc (%<#[%>, %<///%> or %</**%>)");
-       add_error (std::move (error));
-       lexer.skip_token ();
-       return AST::Attribute::create_empty ();
-     }
- 
-   /* OuterAttribute -> '#' '[' Attr ']' */
- 
-   if (lexer.peek_token ()->get_id () != HASH)
-     return AST::Attribute::create_empty ();
- 
-   lexer.skip_token ();
- 
-   TokenId id = lexer.peek_token ()->get_id ();
-   if (id != LEFT_SQUARE)
-     {
-       if (id == EXCLAM)
- 	{
- 	  // this is inner attribute syntax, so throw error
- 	  // inner attributes were either already parsed or not allowed here.
- 	  Error error (
- 	    lexer.peek_token ()->get_locus (),
- 	    "token %<!%> found, indicating inner attribute definition. Inner "
- 	    "attributes are not possible at this location");
- 	  add_error (std::move (error));
- 	}
-       return AST::Attribute::create_empty ();
-     }
- 
-   lexer.skip_token ();
- 
-   auto values = parse_attribute_body ();
-   auto path = std::move (std::get<0> (values));
-   auto input = std::move (std::get<1> (values));
-   auto loc = std::get<2> (values);
-   auto actual_attribute
-     = AST::Attribute (std::move (path), std::move (input), loc, false);
- 
-   if (lexer.peek_token ()->get_id () != RIGHT_SQUARE)
-     return AST::Attribute::create_empty ();
- 
-   lexer.skip_token ();
- 
-   return actual_attribute;
- }
- 
- // Parses a VisItem (item that can have non-default visibility).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::VisItem>
- Parser<ManagedTokenSource>::parse_vis_item (AST::AttrVec outer_attrs)
- {
-   // parse visibility, which may or may not exist
-   AST::Visibility vis = parse_visibility ();
- 
-   // select VisItem to create depending on keyword
-   const_TokenPtr t = lexer.peek_token ();
- 
-   switch (t->get_id ())
-     {
-     case MOD:
-       return parse_module (std::move (vis), std::move (outer_attrs));
-     case EXTERN_KW:
-       // lookahead to resolve syntactical production
-       t = lexer.peek_token (1);
- 
-       switch (t->get_id ())
- 	{
- 	case CRATE:
- 	  return parse_extern_crate (std::move (vis), std::move (outer_attrs));
- 	case FN_KW: // extern function
- 	  return parse_function (std::move (vis), std::move (outer_attrs));
- 	case LEFT_CURLY: // extern block
- 	  return parse_extern_block (std::move (vis), std::move (outer_attrs));
- 	case STRING_LITERAL: // for specifying extern ABI
- 	  // could be extern block or extern function, so more lookahead
- 	  t = lexer.peek_token (2);
- 
- 	  switch (t->get_id ())
- 	    {
- 	    case FN_KW:
- 	      return parse_function (std::move (vis), std::move (outer_attrs));
- 	    case LEFT_CURLY:
- 	      return parse_extern_block (std::move (vis),
- 					 std::move (outer_attrs));
- 	    default:
- 	      add_error (
- 		Error (t->get_locus (),
- 		       "unexpected token %qs in some sort of extern production",
- 		       t->get_token_description ()));
- 
- 	      lexer.skip_token (2); // TODO: is this right thing to do?
- 	      return nullptr;
- 	    }
- 	default:
- 	  add_error (
- 	    Error (t->get_locus (),
- 		   "unexpected token %qs in some sort of extern production",
- 		   t->get_token_description ()));
- 
- 	  lexer.skip_token (1); // TODO: is this right thing to do?
- 	  return nullptr;
- 	}
-     case USE:
-       return parse_use_decl (std::move (vis), std::move (outer_attrs));
-     case FN_KW:
-       return parse_function (std::move (vis), std::move (outer_attrs));
-     case TYPE:
-       return parse_type_alias (std::move (vis), std::move (outer_attrs));
-     case STRUCT_KW:
-       return parse_struct (std::move (vis), std::move (outer_attrs));
-     case ENUM_KW:
-       return parse_enum (std::move (vis), std::move (outer_attrs));
-     // TODO: implement union keyword but not really because of
-     // context-dependence case UNION: crappy hack to do union "keyword"
-     case IDENTIFIER:
-       if (t->get_str () == Values::WeakKeywords::UNION
- 	  && lexer.peek_token (1)->get_id () == IDENTIFIER)
- 	{
- 	  return parse_union (std::move (vis), std::move (outer_attrs));
- 	  // or should item switch go straight to parsing union?
- 	}
-       else
- 	{
- 	  break;
- 	}
-     case CONST:
-       // lookahead to resolve syntactical production
-       t = lexer.peek_token (1);
- 
-       switch (t->get_id ())
- 	{
- 	case IDENTIFIER:
- 	case UNDERSCORE:
- 	  return parse_const_item (std::move (vis), std::move (outer_attrs));
- 	case ASYNC:
- 	  return parse_async_item (std::move (vis), std::move (outer_attrs));
- 	case UNSAFE:
- 	case EXTERN_KW:
- 	case FN_KW:
- 	  return parse_function (std::move (vis), std::move (outer_attrs));
- 	default:
- 	  add_error (
- 	    Error (t->get_locus (),
- 		   "unexpected token %qs in some sort of const production",
- 		   t->get_token_description ()));
- 
- 	  lexer.skip_token (1); // TODO: is this right thing to do?
- 	  return nullptr;
- 	}
-     // for async functions
-     case ASYNC:
-       return parse_async_item (std::move (vis), std::move (outer_attrs));
- 
-     case STATIC_KW:
-       return parse_static_item (std::move (vis), std::move (outer_attrs));
-     case AUTO:
-     case TRAIT:
-       return parse_trait (std::move (vis), std::move (outer_attrs));
-     case IMPL:
-       return parse_impl (std::move (vis), std::move (outer_attrs));
-     case UNSAFE: // unsafe traits, unsafe functions, unsafe impls (trait impls),
-       // lookahead to resolve syntactical production
-       t = lexer.peek_token (1);
- 
-       switch (t->get_id ())
- 	{
- 	case AUTO:
- 	case TRAIT:
- 	  return parse_trait (std::move (vis), std::move (outer_attrs));
- 	case EXTERN_KW:
- 	case FN_KW:
- 	  return parse_function (std::move (vis), std::move (outer_attrs));
- 	case IMPL:
- 	  return parse_impl (std::move (vis), std::move (outer_attrs));
- 	case MOD:
- 	  return parse_module (std::move (vis), std::move (outer_attrs));
- 	default:
- 	  add_error (
- 	    Error (t->get_locus (),
- 		   "unexpected token %qs in some sort of unsafe production",
- 		   t->get_token_description ()));
- 
- 	  lexer.skip_token (1); // TODO: is this right thing to do?
- 	  return nullptr;
- 	}
-     case MACRO:
-       return parse_decl_macro_def (std::move (vis), std::move (outer_attrs));
-     default:
-       // otherwise vis item clearly doesn't exist, which is not an error
-       // has a catch-all post-switch return to allow other breaks to occur
-       break;
-     }
-   return nullptr;
- }
- 
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::Function>
- Parser<ManagedTokenSource>::parse_async_item (AST::Visibility vis,
- 					      AST::AttrVec outer_attrs)
- {
-   auto offset = (lexer.peek_token ()->get_id () == CONST) ? 1 : 0;
-   const_TokenPtr t = lexer.peek_token (offset);
- 
-   if (get_rust_edition () == Edition::E2015)
-     {
-       add_error (Error (t->get_locus (), ErrorCode::E0670,
- 			"%<async fn%> is not permitted in Rust 2015"));
-       add_error (
- 	Error::Hint (t->get_locus (),
- 		     "to use %<async fn%>, switch to Rust 2018 or later"));
-     }
- 
-   t = lexer.peek_token (offset + 1);
- 
-   switch (t->get_id ())
-     {
-     case UNSAFE:
-     case FN_KW:
-       return parse_function (std::move (vis), std::move (outer_attrs));
- 
-     default:
-       add_error (
- 	Error (t->get_locus (), "expected item, found keyword %<async%>"));
- 
-       lexer.skip_token (1);
-       return nullptr;
-     }
- }
- 
- // Parses a macro rules definition syntax extension whatever thing.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::MacroRulesDefinition>
- Parser<ManagedTokenSource>::parse_macro_rules_def (AST::AttrVec outer_attrs)
- {
-   // ensure that first token is identifier saying "macro_rules"
-   const_TokenPtr t = lexer.peek_token ();
-   if (t->get_id () != IDENTIFIER
-       || t->get_str () != Values::WeakKeywords::MACRO_RULES)
-     {
-       Error error (
- 	t->get_locus (),
- 	"macro rules definition does not start with %<macro_rules%>");
-       add_error (std::move (error));
- 
-       // skip after somewhere?
-       return nullptr;
-     }
-   lexer.skip_token ();
-   location_t macro_locus = t->get_locus ();
- 
-   if (!skip_token (EXCLAM))
-     {
-       // skip after somewhere?
-       return nullptr;
-     }
- 
-   // parse macro name
-   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
-   if (ident_tok == nullptr)
-     {
-       return nullptr;
-     }
-   Identifier rule_name{ident_tok};
- 
-   // DEBUG
-   rust_debug ("in macro rules def, about to parse parens.");
- 
-   // save delim type to ensure it is reused later
-   AST::DelimType delim_type = AST::PARENS;
- 
-   // Map tokens to DelimType
-   t = lexer.peek_token ();
-   switch (t->get_id ())
-     {
-     case LEFT_PAREN:
-       delim_type = AST::PARENS;
-       break;
-     case LEFT_SQUARE:
-       delim_type = AST::SQUARE;
-       break;
-     case LEFT_CURLY:
-       delim_type = AST::CURLY;
-       break;
-     default:
-       add_error (Error (t->get_locus (),
- 			"unexpected token %qs - expecting delimiters (for a "
- 			"macro rules definition)",
- 			t->get_token_description ()));
- 
-       return nullptr;
-     }
-   lexer.skip_token ();
- 
-   // parse actual macro rules
-   std::vector<AST::MacroRule> macro_rules;
- 
-   // must be at least one macro rule, so parse it
-   AST::MacroRule initial_rule = parse_macro_rule ();
-   if (initial_rule.is_error ())
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "required first macro rule in macro rules definition "
- 		   "could not be parsed");
-       add_error (std::move (error));
- 
-       // skip after somewhere?
-       return nullptr;
-     }
-   macro_rules.push_back (std::move (initial_rule));
- 
-   // DEBUG
-   rust_debug ("successfully pushed back initial macro rule");
- 
-   t = lexer.peek_token ();
-   // parse macro rules
-   while (t->get_id () == SEMICOLON)
-     {
-       // skip semicolon
-       lexer.skip_token ();
- 
-       // don't parse if end of macro rules
-       if (token_id_matches_delims (lexer.peek_token ()->get_id (), delim_type))
- 	{
- 	  // DEBUG
- 	  rust_debug (
- 	    "broke out of parsing macro rules loop due to finding delim");
- 
- 	  break;
- 	}
- 
-       // try to parse next rule
-       AST::MacroRule rule = parse_macro_rule ();
-       if (rule.is_error ())
- 	{
- 	  Error error (lexer.peek_token ()->get_locus (),
- 		       "failed to parse macro rule in macro rules definition");
- 	  add_error (std::move (error));
- 
- 	  return nullptr;
- 	}
- 
-       macro_rules.push_back (std::move (rule));
- 
-       // DEBUG
-       rust_debug ("successfully pushed back another macro rule");
- 
-       t = lexer.peek_token ();
-     }
- 
-   // parse end delimiters
-   t = lexer.peek_token ();
-   if (token_id_matches_delims (t->get_id (), delim_type))
-     {
-       // tokens match opening delimiter, so skip.
-       lexer.skip_token ();
- 
-       if (delim_type != AST::CURLY)
- 	{
- 	  // skip semicolon at end of non-curly macro definitions
- 	  if (!skip_token (SEMICOLON))
- 	    {
- 	      // as this is the end, allow recovery (probably) - may change
- 	      return std::unique_ptr<AST::MacroRulesDefinition> (
- 		AST::MacroRulesDefinition::mbe (
- 		  std::move (rule_name), delim_type, std::move (macro_rules),
- 		  std::move (outer_attrs), macro_locus));
- 	    }
- 	}
- 
-       return std::unique_ptr<AST::MacroRulesDefinition> (
- 	AST::MacroRulesDefinition::mbe (std::move (rule_name), delim_type,
- 					std::move (macro_rules),
- 					std::move (outer_attrs), macro_locus));
-     }
-   else
-     {
-       // tokens don't match opening delimiters, so produce error
-       Error error (t->get_locus (),
- 		   "unexpected token %qs - expecting closing delimiter %qs "
- 		   "(for a macro rules definition)",
- 		   t->get_token_description (),
- 		   (delim_type == AST::PARENS
- 		      ? ")"
- 		      : (delim_type == AST::SQUARE ? "]" : "}")));
-       add_error (std::move (error));
- 
-       /* return empty macro definiton despite possibly parsing mostly valid one
-        * - TODO is this a good idea? */
-       return nullptr;
-     }
- }
- 
- // Parses a declarative macro 2.0 definition.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::MacroRulesDefinition>
- Parser<ManagedTokenSource>::parse_decl_macro_def (AST::Visibility vis,
- 						  AST::AttrVec outer_attrs)
- {
-   // ensure that first token is identifier saying "macro"
-   const_TokenPtr t = lexer.peek_token ();
-   if (t->get_id () != MACRO)
-     {
-       Error error (
- 	t->get_locus (),
- 	"declarative macro definition does not start with %<macro%>");
-       add_error (std::move (error));
- 
-       // skip after somewhere?
-       return nullptr;
-     }
-   lexer.skip_token ();
-   location_t macro_locus = t->get_locus ();
- 
-   // parse macro name
-   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
-   if (ident_tok == nullptr)
-     {
-       return nullptr;
-     }
-   Identifier rule_name{ident_tok};
- 
-   t = lexer.peek_token ();
-   if (t->get_id () == LEFT_PAREN)
-     {
-       // single definiton of macro rule
-       // e.g. `macro foo($e:expr) {}`
- 
-       // parse macro matcher
-       location_t locus = lexer.peek_token ()->get_locus ();
-       AST::MacroMatcher matcher = parse_macro_matcher ();
-       if (matcher.is_error ())
- 	return nullptr;
- 
-       // check delimiter of macro matcher
-       if (matcher.get_delim_type () != AST::DelimType::PARENS)
- 	{
- 	  Error error (locus, "only parenthesis can be used for a macro "
- 			      "matcher in declarative macro definition");
- 	  add_error (std::move (error));
- 	  return nullptr;
- 	}
- 
-       location_t transcriber_loc = lexer.peek_token ()->get_locus ();
-       AST::DelimTokenTree delim_tok_tree = parse_delim_token_tree ();
-       AST::MacroTranscriber transcriber (delim_tok_tree, transcriber_loc);
- 
-       if (transcriber.get_token_tree ().get_delim_type ()
- 	  != AST::DelimType::CURLY)
- 	{
- 	  Error error (transcriber_loc,
- 		       "only braces can be used for a macro transcriber "
- 		       "in declarative macro definition");
- 	  add_error (std::move (error));
- 	  return nullptr;
- 	}
- 
-       std::vector<AST::MacroRule> macro_rules;
-       macro_rules.emplace_back (std::move (matcher), std::move (transcriber),
- 				locus);
- 
-       return std::unique_ptr<AST::MacroRulesDefinition> (
- 	AST::MacroRulesDefinition::decl_macro (std::move (rule_name),
- 					       macro_rules,
- 					       std::move (outer_attrs),
- 					       macro_locus, vis));
-     }
-   else if (t->get_id () == LEFT_CURLY)
-     {
-       // multiple definitions of macro rule separated by comma
-       // e.g. `macro foo { () => {}, ($e:expr) => {}, }`
- 
-       // parse left curly
-       const_TokenPtr left_curly = expect_token (LEFT_CURLY);
-       if (left_curly == nullptr)
- 	{
- 	  return nullptr;
- 	}
- 
-       // parse actual macro rules
-       std::vector<AST::MacroRule> macro_rules;
- 
-       // must be at least one macro rule, so parse it
-       AST::MacroRule initial_rule = parse_macro_rule ();
-       if (initial_rule.is_error ())
- 	{
- 	  Error error (
- 	    lexer.peek_token ()->get_locus (),
- 	    "required first macro rule in declarative macro definition "
- 	    "could not be parsed");
- 	  add_error (std::move (error));
- 
- 	  // skip after somewhere?
- 	  return nullptr;
- 	}
-       macro_rules.push_back (std::move (initial_rule));
- 
-       t = lexer.peek_token ();
-       // parse macro rules
-       while (t->get_id () == COMMA)
- 	{
- 	  // skip comma
- 	  lexer.skip_token ();
- 
- 	  // don't parse if end of macro rules
- 	  if (token_id_matches_delims (lexer.peek_token ()->get_id (),
- 				       AST::CURLY))
- 	    {
- 	      break;
- 	    }
- 
- 	  // try to parse next rule
- 	  AST::MacroRule rule = parse_macro_rule ();
- 	  if (rule.is_error ())
- 	    {
- 	      Error error (
- 		lexer.peek_token ()->get_locus (),
- 		"failed to parse macro rule in declarative macro definition");
- 	      add_error (std::move (error));
- 
- 	      return nullptr;
- 	    }
- 
- 	  macro_rules.push_back (std::move (rule));
- 
- 	  t = lexer.peek_token ();
- 	}
- 
-       // parse right curly
-       const_TokenPtr right_curly = expect_token (RIGHT_CURLY);
-       if (right_curly == nullptr)
- 	{
- 	  return nullptr;
- 	}
- 
-       return std::unique_ptr<AST::MacroRulesDefinition> (
- 	AST::MacroRulesDefinition::decl_macro (std::move (rule_name),
- 					       std::move (macro_rules),
- 					       std::move (outer_attrs),
- 					       macro_locus, vis));
-     }
-   else
-     {
-       add_error (Error (t->get_locus (),
- 			"unexpected token %qs - expecting delimiters "
- 			"(for a declarative macro definiton)",
- 			t->get_token_description ()));
-       return nullptr;
-     }
- }
- 
- // Parses a semi-coloned (except for full block) macro invocation item.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::MacroInvocation>
- Parser<ManagedTokenSource>::parse_macro_invocation_semi (
-   AST::AttrVec outer_attrs)
- {
-   location_t macro_locus = lexer.peek_token ()->get_locus ();
-   AST::SimplePath path = parse_simple_path ();
- 
-   if (!skip_token (EXCLAM))
-     {
-       // skip after somewhere?
-       return nullptr;
-     }
- 
-   // save delim type to ensure it is reused later
-   AST::DelimType delim_type = AST::PARENS;
- 
-   // Map tokens to DelimType
-   const_TokenPtr t = lexer.peek_token ();
-   switch (t->get_id ())
-     {
-     case LEFT_PAREN:
-       delim_type = AST::PARENS;
-       break;
-     case LEFT_SQUARE:
-       delim_type = AST::SQUARE;
-       break;
-     case LEFT_CURLY:
-       delim_type = AST::CURLY;
-       break;
-     default:
-       add_error (Error (t->get_locus (),
- 			"unexpected token %qs - expecting delimiters (for a "
- 			"macro invocation semi body)",
- 			t->get_token_description ()));
- 
-       return nullptr;
-     }
-   location_t tok_tree_locus = t->get_locus ();
-   lexer.skip_token ();
- 
-   // parse actual token trees
-   std::vector<std::unique_ptr<AST::TokenTree>> token_trees;
-   auto delim_open
-     = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
-   token_trees.push_back (std::move (delim_open));
- 
-   t = lexer.peek_token ();
-   // parse token trees until the initial delimiter token is found again
-   while (!token_id_matches_delims (t->get_id (), delim_type)
- 	 && t->get_id () != END_OF_FILE)
-     {
-       std::unique_ptr<AST::TokenTree> tree = parse_token_tree ();
- 
-       if (tree == nullptr)
- 	return nullptr;
- 
-       token_trees.push_back (std::move (tree));
- 
-       t = lexer.peek_token ();
-     }
-   auto delim_close
-     = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
-   token_trees.push_back (std::move (delim_close));
- 
-   AST::DelimTokenTree delim_tok_tree (delim_type, std::move (token_trees),
- 				      tok_tree_locus);
-   AST::MacroInvocData invoc_data (std::move (path), std::move (delim_tok_tree));
- 
-   // parse end delimiters
-   t = lexer.peek_token ();
-   if (token_id_matches_delims (t->get_id (), delim_type))
-     {
-       // tokens match opening delimiter, so skip.
-       lexer.skip_token ();
- 
-       if (delim_type != AST::CURLY)
- 	{
- 	  // skip semicolon at end of non-curly macro invocation semis
- 	  if (!skip_token (SEMICOLON))
- 	    {
- 	      // as this is the end, allow recovery (probably) - may change
- 
- 	      return AST::MacroInvocation::Regular (std::move (invoc_data),
- 						    std::move (outer_attrs),
- 						    macro_locus, true);
- 	    }
- 	}
- 
-       // DEBUG:
-       rust_debug ("skipped token is '%s', next token (current peek) is '%s'",
- 		  t->get_token_description (),
- 		  lexer.peek_token ()->get_token_description ());
- 
-       return AST::MacroInvocation::Regular (std::move (invoc_data),
- 					    std::move (outer_attrs),
- 					    macro_locus, true);
-     }
-   else
-     {
-       // tokens don't match opening delimiters, so produce error
-       Error error (t->get_locus (),
- 		   "unexpected token %qs - expecting closing delimiter %qs "
- 		   "(for a macro invocation semi)",
- 		   t->get_token_description (),
- 		   (delim_type == AST::PARENS
- 		      ? ")"
- 		      : (delim_type == AST::SQUARE ? "]" : "}")));
-       add_error (std::move (error));
- 
-       /* return empty macro invocation despite possibly parsing mostly valid one
-        * - TODO is this a good idea? */
-       return nullptr;
-     }
- }
- 
- // Parses a non-semicoloned macro invocation (i.e. as pattern or expression).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::MacroInvocation>
- Parser<ManagedTokenSource>::parse_macro_invocation (AST::AttrVec outer_attrs)
- {
-   // parse macro path
-   AST::SimplePath macro_path = parse_simple_path ();
-   if (macro_path.is_empty ())
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "failed to parse macro invocation path");
-       add_error (std::move (error));
- 
-       // skip?
-       return nullptr;
-     }
- 
-   if (!skip_token (EXCLAM))
-     {
-       // skip after somewhere?
-       return nullptr;
-     }
- 
-   // parse internal delim token tree
-   AST::DelimTokenTree delim_tok_tree = parse_delim_token_tree ();
- 
-   location_t macro_locus = macro_path.get_locus ();
- 
-   return AST::MacroInvocation::Regular (
-     AST::MacroInvocData (std::move (macro_path), std::move (delim_tok_tree)),
-     std::move (outer_attrs), macro_locus);
- }
- 
- // Parses a macro rule definition - does not parse semicolons.
- template <typename ManagedTokenSource>
- AST::MacroRule
- Parser<ManagedTokenSource>::parse_macro_rule ()
- {
-   location_t locus = lexer.peek_token ()->get_locus ();
- 
-   // parse macro matcher
-   AST::MacroMatcher matcher = parse_macro_matcher ();
- 
-   if (matcher.is_error ())
-     return AST::MacroRule::create_error (locus);
- 
-   if (!skip_token (MATCH_ARROW))
-     {
-       // skip after somewhere?
-       return AST::MacroRule::create_error (locus);
-     }
- 
-   // parse transcriber (this is just a delim token tree)
-   location_t token_tree_loc = lexer.peek_token ()->get_locus ();
-   AST::MacroTranscriber transcriber (parse_delim_token_tree (), token_tree_loc);
- 
-   return AST::MacroRule (std::move (matcher), std::move (transcriber), locus);
- }
- 
- // Parses a macro matcher (part of a macro rule definition).
- template <typename ManagedTokenSource>
- AST::MacroMatcher
- Parser<ManagedTokenSource>::parse_macro_matcher ()
- {
-   // save delim type to ensure it is reused later
-   AST::DelimType delim_type = AST::PARENS;
- 
-   // DEBUG
-   rust_debug ("begun parsing macro matcher");
- 
-   // Map tokens to DelimType
-   const_TokenPtr t = lexer.peek_token ();
-   location_t locus = t->get_locus ();
-   switch (t->get_id ())
-     {
-     case LEFT_PAREN:
-       delim_type = AST::PARENS;
-       break;
-     case LEFT_SQUARE:
-       delim_type = AST::SQUARE;
-       break;
-     case LEFT_CURLY:
-       delim_type = AST::CURLY;
-       break;
-     default:
-       add_error (Error (
- 	t->get_locus (),
- 	"unexpected token %qs - expecting delimiters (for a macro matcher)",
- 	t->get_token_description ()));
- 
-       return AST::MacroMatcher::create_error (t->get_locus ());
-     }
-   lexer.skip_token ();
- 
-   // parse actual macro matches
-   std::vector<std::unique_ptr<AST::MacroMatch>> matches;
-   // Set of possible preceding macro matches to make sure follow-set
-   // restrictions are respected.
-   // TODO: Consider using std::reference_wrapper instead of raw pointers?
-   std::vector<const AST::MacroMatch *> last_matches;
- 
-   t = lexer.peek_token ();
-   // parse token trees until the initial delimiter token is found again
-   while (!token_id_matches_delims (t->get_id (), delim_type))
-     {
-       std::unique_ptr<AST::MacroMatch> match = parse_macro_match ();
- 
-       if (match == nullptr)
- 	{
- 	  Error error (
- 	    t->get_locus (),
- 	    "failed to parse macro match for macro matcher - found %qs",
- 	    t->get_token_description ());
- 	  add_error (std::move (error));
- 
- 	  return AST::MacroMatcher::create_error (t->get_locus ());
- 	}
- 
-       if (matches.size () > 0)
- 	{
- 	  const auto *last_match = matches.back ().get ();
- 
- 	  // We want to check if we are dealing with a zeroable repetition
- 	  bool zeroable = false;
- 	  if (last_match->get_macro_match_type ()
- 	      == AST::MacroMatch::MacroMatchType::Repetition)
- 	    {
- 	      auto repetition
- 		= static_cast<const AST::MacroMatchRepetition *> (last_match);
- 
- 	      if (repetition->get_op ()
- 		  != AST::MacroMatchRepetition::MacroRepOp::ONE_OR_MORE)
- 		zeroable = true;
- 	    }
- 
- 	  if (!zeroable)
- 	    last_matches.clear ();
- 
- 	  last_matches.emplace_back (last_match);
- 
- 	  for (auto last : last_matches)
- 	    if (!is_match_compatible (*last, *match))
- 	      return AST::MacroMatcher::create_error (
- 		match->get_match_locus ());
- 	}
- 
-       matches.push_back (std::move (match));
- 
-       // DEBUG
-       rust_debug ("pushed back a match in macro matcher");
- 
-       t = lexer.peek_token ();
-     }
- 
-   // parse end delimiters
-   t = lexer.peek_token ();
-   if (token_id_matches_delims (t->get_id (), delim_type))
-     {
-       // tokens match opening delimiter, so skip.
-       lexer.skip_token ();
- 
-       return AST::MacroMatcher (delim_type, std::move (matches), locus);
-     }
-   else
-     {
-       // tokens don't match opening delimiters, so produce error
-       Error error (t->get_locus (),
- 		   "unexpected token %qs - expecting closing delimiter %qs "
- 		   "(for a macro matcher)",
- 		   t->get_token_description (),
- 		   (delim_type == AST::PARENS
- 		      ? ")"
- 		      : (delim_type == AST::SQUARE ? "]" : "}")));
-       add_error (std::move (error));
- 
-       /* return error macro matcher despite possibly parsing mostly correct one?
-        * TODO is this the best idea? */
-       return AST::MacroMatcher::create_error (t->get_locus ());
-     }
- }
- 
- // Parses a macro match (syntax match inside a matcher in a macro rule).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::MacroMatch>
- Parser<ManagedTokenSource>::parse_macro_match ()
- {
-   // branch based on token available
-   const_TokenPtr t = lexer.peek_token ();
-   switch (t->get_id ())
-     {
-     case LEFT_PAREN:
-     case LEFT_SQUARE:
-     case LEFT_CURLY:
-       {
- 	// must be macro matcher as delimited
- 	AST::MacroMatcher matcher = parse_macro_matcher ();
- 	if (matcher.is_error ())
- 	  {
- 	    Error error (lexer.peek_token ()->get_locus (),
- 			 "failed to parse macro matcher in macro match");
- 	    add_error (std::move (error));
- 
- 	    return nullptr;
- 	  }
- 	return std::unique_ptr<AST::MacroMatcher> (
- 	  new AST::MacroMatcher (std::move (matcher)));
-       }
-     case DOLLAR_SIGN:
-       {
- 	// have to do more lookahead to determine if fragment or repetition
- 	const_TokenPtr t2 = lexer.peek_token (1);
- 	switch (t2->get_id ())
- 	  {
- 	  case IDENTIFIER:
- 	  case UNDERSCORE:
- 	    // macro fragment
- 	    return parse_macro_match_fragment ();
- 	  case LEFT_PAREN:
- 	    // macro repetition
- 	    return parse_macro_match_repetition ();
- 	  default:
- 	    if (token_id_is_keyword (t2->get_id ()) && t2->get_id () != CRATE)
- 	      {
- 		// keyword as macro fragment
- 		return parse_macro_match_fragment ();
- 	      }
- 	    else
- 	      {
- 		// error: unrecognised
- 		add_error (Error (
- 		  t2->get_locus (),
- 		  "unrecognised token combination %<$%s%> at start of "
- 		  "macro match - did you mean %<$identifier%> or %<$(%>?",
- 		  t2->get_token_description ()));
- 
- 		// skip somewhere?
- 		return nullptr;
- 	      }
- 	  }
-       }
-     case RIGHT_PAREN:
-     case RIGHT_SQUARE:
-     case RIGHT_CURLY:
-       // not allowed
-       add_error (Error (
- 	t->get_locus (),
- 	"closing delimiters like %qs are not allowed at the start of a macro "
- 	"match",
- 	t->get_token_description ()));
- 
-       // skip somewhere?
-       return nullptr;
-     default:
-       // just the token
-       lexer.skip_token ();
-       return std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
-     }
- }
- 
- // Parses a fragment macro match.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::MacroMatchFragment>
- Parser<ManagedTokenSource>::parse_macro_match_fragment ()
- {
-   location_t fragment_locus = lexer.peek_token ()->get_locus ();
-   skip_token (DOLLAR_SIGN);
- 
-   Identifier ident;
-   auto identifier = lexer.peek_token ();
-   if (identifier->get_id () == UNDERSCORE)
-     ident = {Values::Keywords::UNDERSCORE, identifier->get_locus ()};
-   else
-     ident = {identifier};
- 
-   if (ident.empty ())
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "missing identifier in macro match fragment");
-       add_error (std::move (error));
- 
-       return nullptr;
-     }
-   skip_token (identifier->get_id ());
- 
-   if (!skip_token (COLON))
-     {
-       // skip after somewhere?
-       return nullptr;
-     }
- 
-   // get MacroFragSpec for macro
-   const_TokenPtr t = expect_token (IDENTIFIER);
-   if (t == nullptr)
-     return nullptr;
- 
-   AST::MacroFragSpec frag
-     = AST::MacroFragSpec::get_frag_spec_from_str (t->get_str ());
-   if (frag.is_error ())
-     {
-       Error error (t->get_locus (),
- 		   "invalid fragment specifier %qs in fragment macro match",
- 		   t->get_str ().c_str ());
-       add_error (std::move (error));
- 
-       return nullptr;
-     }
- 
-   return std::unique_ptr<AST::MacroMatchFragment> (
-     new AST::MacroMatchFragment (std::move (ident), frag, fragment_locus));
- }
- 
- // Parses a repetition macro match.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::MacroMatchRepetition>
- Parser<ManagedTokenSource>::parse_macro_match_repetition ()
- {
-   skip_token (DOLLAR_SIGN);
-   skip_token (LEFT_PAREN);
- 
-   std::vector<std::unique_ptr<AST::MacroMatch>> matches;
- 
-   // parse required first macro match
-   std::unique_ptr<AST::MacroMatch> initial_match = parse_macro_match ();
-   if (initial_match == nullptr)
-     {
-       Error error (
- 	lexer.peek_token ()->get_locus (),
- 	"could not parse required first macro match in macro match repetition");
-       add_error (std::move (error));
- 
-       // skip after somewhere?
-       return nullptr;
-     }
-   matches.push_back (std::move (initial_match));
- 
-   // parse optional later macro matches
-   const_TokenPtr t = lexer.peek_token ();
-   while (t->get_id () != RIGHT_PAREN)
-     {
-       std::unique_ptr<AST::MacroMatch> match = parse_macro_match ();
- 
-       if (match == nullptr)
- 	{
- 	  Error error (lexer.peek_token ()->get_locus (),
- 		       "failed to parse macro match in macro match repetition");
- 	  add_error (std::move (error));
- 
- 	  return nullptr;
- 	}
- 
-       matches.push_back (std::move (match));
- 
-       t = lexer.peek_token ();
-     }
- 
-   if (!skip_token (RIGHT_PAREN))
-     {
-       // skip after somewhere?
-       return nullptr;
-     }
- 
-   t = lexer.peek_token ();
-   // see if separator token exists
-   std::unique_ptr<AST::Token> separator = nullptr;
-   switch (t->get_id ())
-     {
-     // repetition operators
-     case ASTERISK:
-     case PLUS:
-     case QUESTION_MARK:
-     // delimiters
-     case LEFT_PAREN:
-     case LEFT_CURLY:
-     case LEFT_SQUARE:
-     case RIGHT_PAREN:
-     case RIGHT_CURLY:
-     case RIGHT_SQUARE:
-       // separator does not exist, so still null and don't skip token
-       break;
-     default:
-       // separator does exist
-       separator = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
-       lexer.skip_token ();
-       break;
-     }
- 
-   // parse repetition operator
-   t = lexer.peek_token ();
-   AST::MacroMatchRepetition::MacroRepOp op = AST::MacroMatchRepetition::NONE;
-   switch (t->get_id ())
-     {
-     case ASTERISK:
-       op = AST::MacroMatchRepetition::ANY;
-       lexer.skip_token ();
-       break;
-     case PLUS:
-       op = AST::MacroMatchRepetition::ONE_OR_MORE;
-       lexer.skip_token ();
-       break;
-     case QUESTION_MARK:
-       op = AST::MacroMatchRepetition::ZERO_OR_ONE;
-       lexer.skip_token ();
- 
-       if (separator != nullptr)
- 	{
- 	  add_error (
- 	    Error (separator->get_locus (),
- 		   "the %<?%> macro repetition operator does not take a "
- 		   "separator"));
- 	  separator = nullptr;
- 	}
- 
-       break;
-     default:
-       add_error (
- 	Error (t->get_locus (),
- 	       "expected macro repetition operator (%<*%>, %<+%>, or %<?%>) in "
- 	       "macro match - found %qs",
- 	       t->get_token_description ()));
- 
-       // skip after somewhere?
-       return nullptr;
-     }
- 
-   return std::unique_ptr<AST::MacroMatchRepetition> (
-     new AST::MacroMatchRepetition (std::move (matches), op,
- 				   std::move (separator), t->get_locus ()));
- }
- 
- /* Parses a visibility syntactical production (i.e. creating a non-default
-  * visibility) */
- template <typename ManagedTokenSource>
- AST::Visibility
- Parser<ManagedTokenSource>::parse_visibility ()
- {
-   // check for no visibility
-   if (lexer.peek_token ()->get_id () != PUB)
-     {
-       return AST::Visibility::create_private ();
-     }
- 
-   auto vis_loc = lexer.peek_token ()->get_locus ();
-   lexer.skip_token ();
- 
-   // create simple pub visibility if
-   // - found no parentheses
-   // - found unit type `()`
-   if (lexer.peek_token ()->get_id () != LEFT_PAREN
-       || lexer.peek_token (1)->get_id () == RIGHT_PAREN)
-     {
-       return AST::Visibility::create_public (vis_loc);
-       // or whatever
-     }
- 
-   lexer.skip_token ();
- 
-   const_TokenPtr t = lexer.peek_token ();
-   auto path_loc = t->get_locus ();
- 
-   switch (t->get_id ())
-     {
-     case CRATE:
-       lexer.skip_token ();
- 
-       skip_token (RIGHT_PAREN);
- 
-       return AST::Visibility::create_crate (path_loc, vis_loc);
-     case SELF:
-       lexer.skip_token ();
- 
-       skip_token (RIGHT_PAREN);
- 
-       return AST::Visibility::create_self (path_loc, vis_loc);
-     case SUPER:
-       lexer.skip_token ();
- 
-       skip_token (RIGHT_PAREN);
- 
-       return AST::Visibility::create_super (path_loc, vis_loc);
-     case IN:
-       {
- 	lexer.skip_token ();
- 
- 	// parse the "in" path as well
- 	AST::SimplePath path = parse_simple_path ();
- 	if (path.is_empty ())
- 	  {
- 	    Error error (lexer.peek_token ()->get_locus (),
- 			 "missing path in pub(in path) visibility");
- 	    add_error (std::move (error));
- 
- 	    // skip after somewhere?
- 	    return AST::Visibility::create_error ();
- 	  }
- 
- 	skip_token (RIGHT_PAREN);
- 
- 	return AST::Visibility::create_in_path (std::move (path), vis_loc);
-       }
-     default:
-       add_error (Error (t->get_locus (), "unexpected token %qs in visibility",
- 			t->get_token_description ()));
- 
-       lexer.skip_token ();
-       return AST::Visibility::create_error ();
-     }
- }
- 
- // Parses a module - either a bodied module or a module defined in another file.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::Module>
- Parser<ManagedTokenSource>::parse_module (AST::Visibility vis,
- 					  AST::AttrVec outer_attrs)
- {
-   location_t locus = lexer.peek_token ()->get_locus ();
- 
-   Unsafety safety = Unsafety::Normal;
-   if (lexer.peek_token ()->get_id () == UNSAFE)
-     {
-       safety = Unsafety::Unsafe;
-       skip_token (UNSAFE);
-     }
- 
-   skip_token (MOD);
- 
-   const_TokenPtr module_name = expect_token (IDENTIFIER);
-   if (module_name == nullptr)
-     {
-       return nullptr;
-     }
-   Identifier name{module_name};
- 
-   const_TokenPtr t = lexer.peek_token ();
- 
-   switch (t->get_id ())
-     {
-     case SEMICOLON:
-       lexer.skip_token ();
- 
-       // Construct an external module
-       return std::unique_ptr<AST::Module> (
- 	new AST::Module (std::move (name), std::move (vis),
- 			 std::move (outer_attrs), locus, safety,
- 			 lexer.get_filename (), inline_module_stack));
-     case LEFT_CURLY:
-       {
- 	lexer.skip_token ();
- 
- 	// parse inner attributes
- 	AST::AttrVec inner_attrs = parse_inner_attributes ();
- 
- 	std::string default_path = name.as_string ();
- 
- 	if (inline_module_stack.empty ())
- 	  {
- 	    std::string filename = lexer.get_filename ();
- 	    auto slash_idx = filename.rfind (file_separator);
- 	    if (slash_idx == std::string::npos)
- 	      slash_idx = 0;
- 	    else
- 	      slash_idx++;
- 	    filename = filename.substr (slash_idx);
- 
- 	    std::string subdir;
- 	    if (get_file_subdir (filename, subdir))
- 	      default_path = subdir + file_separator + name.as_string ();
- 	  }
- 
- 	std::string module_path_name
- 	  = extract_module_path (inner_attrs, outer_attrs, default_path);
- 	InlineModuleStackScope scope (*this, std::move (module_path_name));
- 
- 	// parse items
- 	std::vector<std::unique_ptr<AST::Item>> items;
- 	const_TokenPtr tok = lexer.peek_token ();
- 	while (tok->get_id () != RIGHT_CURLY)
- 	  {
- 	    std::unique_ptr<AST::Item> item = parse_item (false);
- 	    if (item == nullptr)
- 	      {
- 		Error error (tok->get_locus (),
- 			     "failed to parse item in module");
- 		add_error (std::move (error));
- 
- 		return nullptr;
- 	      }
- 
- 	    items.push_back (std::move (item));
- 
- 	    tok = lexer.peek_token ();
- 	  }
- 
- 	if (!skip_token (RIGHT_CURLY))
- 	  {
- 	    // skip somewhere?
- 	    return nullptr;
- 	  }
- 
- 	return std::unique_ptr<AST::Module> (
- 	  new AST::Module (std::move (name), locus, std::move (items),
- 			   std::move (vis), safety, std::move (inner_attrs),
- 			   std::move (outer_attrs))); // module name?
-       }
-     default:
-       add_error (
- 	Error (t->get_locus (),
- 	       "unexpected token %qs in module declaration/definition item",
- 	       t->get_token_description ()));
- 
-       lexer.skip_token ();
-       return nullptr;
-     }
- }
- 
- // Parses an extern crate declaration (dependency on external crate)
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::ExternCrate>
- Parser<ManagedTokenSource>::parse_extern_crate (AST::Visibility vis,
- 						AST::AttrVec outer_attrs)
- {
-   location_t locus = lexer.peek_token ()->get_locus ();
-   if (!skip_token (EXTERN_KW))
-     {
-       skip_after_semicolon ();
-       return nullptr;
-     }
- 
-   if (!skip_token (CRATE))
-     {
-       skip_after_semicolon ();
-       return nullptr;
-     }
- 
-   /* parse crate reference name - this has its own syntactical rule in reference
-    * but seems to not be used elsewhere, so i'm putting it here */
-   const_TokenPtr crate_name_tok = lexer.peek_token ();
-   std::string crate_name;
- 
-   switch (crate_name_tok->get_id ())
-     {
-     case IDENTIFIER:
-       crate_name = crate_name_tok->get_str ();
-       lexer.skip_token ();
-       break;
-     case SELF:
-       crate_name = Values::Keywords::SELF;
-       lexer.skip_token ();
-       break;
-     default:
-       add_error (
- 	Error (crate_name_tok->get_locus (),
- 	       "expecting crate name (identifier or %<self%>), found %qs",
- 	       crate_name_tok->get_token_description ()));
- 
-       skip_after_semicolon ();
-       return nullptr;
-     }
- 
-   // don't parse as clause if it doesn't exist
-   if (lexer.peek_token ()->get_id () == SEMICOLON)
-     {
-       lexer.skip_token ();
- 
-       return std::unique_ptr<AST::ExternCrate> (
- 	new AST::ExternCrate (std::move (crate_name), std::move (vis),
- 			      std::move (outer_attrs), locus));
-     }
- 
-   /* parse as clause - this also has its own syntactical rule in reference and
-    * also seems to not be used elsewhere, so including here again. */
-   if (!skip_token (AS))
-     {
-       skip_after_semicolon ();
-       return nullptr;
-     }
- 
-   const_TokenPtr as_name_tok = lexer.peek_token ();
-   std::string as_name;
- 
-   switch (as_name_tok->get_id ())
-     {
-     case IDENTIFIER:
-       as_name = as_name_tok->get_str ();
-       lexer.skip_token ();
-       break;
-     case UNDERSCORE:
-       as_name = Values::Keywords::UNDERSCORE;
-       lexer.skip_token ();
-       break;
-     default:
-       add_error (
- 	Error (as_name_tok->get_locus (),
- 	       "expecting as clause name (identifier or %<_%>), found %qs",
- 	       as_name_tok->get_token_description ()));
- 
-       skip_after_semicolon ();
-       return nullptr;
-     }
- 
-   if (!skip_token (SEMICOLON))
-     {
-       skip_after_semicolon ();
-       return nullptr;
-     }
- 
-   return std::unique_ptr<AST::ExternCrate> (
-     new AST::ExternCrate (std::move (crate_name), std::move (vis),
- 			  std::move (outer_attrs), locus, std::move (as_name)));
- }
- 
- // Parses a use declaration.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::UseDeclaration>
- Parser<ManagedTokenSource>::parse_use_decl (AST::Visibility vis,
- 					    AST::AttrVec outer_attrs)
- {
-   location_t locus = lexer.peek_token ()->get_locus ();
-   if (!skip_token (USE))
-     {
-       skip_after_semicolon ();
-       return nullptr;
-     }
- 
-   // parse use tree, which is required
-   std::unique_ptr<AST::UseTree> use_tree = parse_use_tree ();
-   if (use_tree == nullptr)
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "could not parse use tree in use declaration");
-       add_error (std::move (error));
- 
-       skip_after_semicolon ();
-       return nullptr;
-     }
- 
-   if (!skip_token (SEMICOLON))
-     {
-       skip_after_semicolon ();
-       return nullptr;
-     }
- 
-   return std::unique_ptr<AST::UseDeclaration> (
-     new AST::UseDeclaration (std::move (use_tree), std::move (vis),
- 			     std::move (outer_attrs), locus));
- }
- 
- // Parses a use tree (which can be recursive and is actually a base class).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::UseTree>
- Parser<ManagedTokenSource>::parse_use_tree ()
- {
-   /* potential syntax definitions in attempt to get algorithm:
-    *  Glob:
-    *      <- SimplePath :: *
-    *      <- :: *
-    *      <- *
-    *  Nested tree thing:
-    *      <- SimplePath :: { COMPLICATED_INNER_TREE_THING }
-    *      <- :: COMPLICATED_INNER_TREE_THING }
-    *      <- { COMPLICATED_INNER_TREE_THING }
-    *  Rebind thing:
-    *      <- SimplePath as IDENTIFIER
-    *      <- SimplePath as _
-    *      <- SimplePath
-    */
- 
-   /* current plan of attack: try to parse SimplePath first - if fails, one of
-    * top two then try parse :: - if fails, one of top two. Next is deciding
-    * character for top two. */
- 
-   /* Thus, parsing smaller parts of use tree may require feeding into function
-    * via parameters (or could handle all in this single function because other
-    * use tree types aren't recognised as separate in the spec) */
- 
-   // TODO: I think this function is too complex, probably should split it
- 
-   location_t locus = lexer.peek_token ()->get_locus ();
- 
-   // bool has_path = false;
-   AST::SimplePath path = parse_simple_path ();
- 
-   if (path.is_empty ())
-     {
-       // has no path, so must be glob or nested tree UseTree type
- 
-       bool is_global = false;
- 
-       // check for global scope resolution operator
-       if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION)
- 	{
- 	  lexer.skip_token ();
- 	  is_global = true;
- 	}
- 
-       const_TokenPtr t = lexer.peek_token ();
-       switch (t->get_id ())
- 	{
- 	case ASTERISK:
- 	  // glob UseTree type
- 	  lexer.skip_token ();
- 
- 	  if (is_global)
- 	    return std::unique_ptr<AST::UseTreeGlob> (
- 	      new AST::UseTreeGlob (AST::UseTreeGlob::GLOBAL,
- 				    AST::SimplePath::create_empty (), locus));
- 	  else
- 	    return std::unique_ptr<AST::UseTreeGlob> (
- 	      new AST::UseTreeGlob (AST::UseTreeGlob::NO_PATH,
- 				    AST::SimplePath::create_empty (), locus));
- 	case LEFT_CURLY:
- 	  {
- 	    // nested tree UseTree type
- 	    lexer.skip_token ();
- 
- 	    std::vector<std::unique_ptr<AST::UseTree>> use_trees;
- 
- 	    const_TokenPtr t = lexer.peek_token ();
- 	    while (t->get_id () != RIGHT_CURLY)
- 	      {
- 		std::unique_ptr<AST::UseTree> use_tree = parse_use_tree ();
- 		if (use_tree == nullptr)
- 		  {
- 		    break;
- 		  }
- 
- 		use_trees.push_back (std::move (use_tree));
- 
- 		if (lexer.peek_token ()->get_id () != COMMA)
- 		  break;
- 
- 		lexer.skip_token ();
- 		t = lexer.peek_token ();
- 	      }
- 
- 	    // skip end curly delimiter
- 	    if (!skip_token (RIGHT_CURLY))
- 	      {
- 		// skip after somewhere?
- 		return nullptr;
- 	      }
- 
- 	    if (is_global)
- 	      return std::unique_ptr<AST::UseTreeList> (
- 		new AST::UseTreeList (AST::UseTreeList::GLOBAL,
- 				      AST::SimplePath::create_empty (),
- 				      std::move (use_trees), locus));
- 	    else
- 	      return std::unique_ptr<AST::UseTreeList> (
- 		new AST::UseTreeList (AST::UseTreeList::NO_PATH,
- 				      AST::SimplePath::create_empty (),
- 				      std::move (use_trees), locus));
- 	  }
- 	case AS:
- 	  // this is not allowed
- 	  add_error (Error (
- 	    t->get_locus (),
- 	    "use declaration with rebind %<as%> requires a valid simple path - "
- 	    "none found"));
- 
- 	  skip_after_semicolon ();
- 	  return nullptr;
- 	default:
- 	  add_error (Error (t->get_locus (),
- 			    "unexpected token %qs in use tree with "
- 			    "no valid simple path (i.e. list"
- 			    " or glob use tree)",
- 			    t->get_token_description ()));
- 
- 	  skip_after_semicolon ();
- 	  return nullptr;
- 	}
-     }
-   else
-     {
-       const_TokenPtr t = lexer.peek_token ();
- 
-       switch (t->get_id ())
- 	{
- 	case AS:
- 	  {
- 	    // rebind UseTree type
- 	    lexer.skip_token ();
- 
- 	    const_TokenPtr t = lexer.peek_token ();
- 	    switch (t->get_id ())
- 	      {
- 	      case IDENTIFIER:
- 		// skip lexer token
- 		lexer.skip_token ();
- 
- 		return std::unique_ptr<AST::UseTreeRebind> (
- 		  new AST::UseTreeRebind (AST::UseTreeRebind::IDENTIFIER,
- 					  std::move (path), locus, t));
- 	      case UNDERSCORE:
- 		// skip lexer token
- 		lexer.skip_token ();
- 
- 		return std::unique_ptr<AST::UseTreeRebind> (
- 		  new AST::UseTreeRebind (AST::UseTreeRebind::WILDCARD,
- 					  std::move (path), locus,
- 					  {Values::Keywords::UNDERSCORE,
- 					   t->get_locus ()}));
- 	      default:
- 		add_error (Error (
- 		  t->get_locus (),
- 		  "unexpected token %qs in use tree with as clause - expected "
- 		  "identifier or %<_%>",
- 		  t->get_token_description ()));
- 
- 		skip_after_semicolon ();
- 		return nullptr;
- 	      }
- 	  }
- 	case SEMICOLON:
- 	  // rebind UseTree type without rebinding - path only
- 
- 	  // don't skip semicolon - handled in parse_use_tree
- 	  // lexer.skip_token();
- 	case COMMA:
- 	case RIGHT_CURLY:
- 	  // this may occur in recursive calls - assume it is ok and ignore it
- 	  return std::unique_ptr<AST::UseTreeRebind> (
- 	    new AST::UseTreeRebind (AST::UseTreeRebind::NONE, std::move (path),
- 				    locus));
- 	case SCOPE_RESOLUTION:
- 	  // keep going
- 	  break;
- 	default:
- 	  add_error (Error (t->get_locus (),
- 			    "unexpected token %qs in use tree with valid path",
- 			    t->get_token_description ()));
- 	  return nullptr;
- 	}
- 
-       skip_token ();
-       t = lexer.peek_token ();
- 
-       switch (t->get_id ())
- 	{
- 	case ASTERISK:
- 	  // glob UseTree type
- 	  lexer.skip_token ();
- 
- 	  return std::unique_ptr<AST::UseTreeGlob> (
- 	    new AST::UseTreeGlob (AST::UseTreeGlob::PATH_PREFIXED,
- 				  std::move (path), locus));
- 	case LEFT_CURLY:
- 	  {
- 	    // nested tree UseTree type
- 	    lexer.skip_token ();
- 
- 	    std::vector<std::unique_ptr<AST::UseTree>> use_trees;
- 
- 	    // TODO: think of better control structure
- 	    const_TokenPtr t = lexer.peek_token ();
- 	    while (t->get_id () != RIGHT_CURLY)
- 	      {
- 		std::unique_ptr<AST::UseTree> use_tree = parse_use_tree ();
- 		if (use_tree == nullptr)
- 		  {
- 		    break;
- 		  }
- 
- 		use_trees.push_back (std::move (use_tree));
- 
- 		if (lexer.peek_token ()->get_id () != COMMA)
- 		  break;
- 
- 		lexer.skip_token ();
- 		t = lexer.peek_token ();
- 	      }
- 
- 	    // skip end curly delimiter
- 	    if (!skip_token (RIGHT_CURLY))
- 	      {
- 		// skip after somewhere?
- 		return nullptr;
- 	      }
- 
- 	    return std::unique_ptr<AST::UseTreeList> (
- 	      new AST::UseTreeList (AST::UseTreeList::PATH_PREFIXED,
- 				    std::move (path), std::move (use_trees),
- 				    locus));
- 	  }
- 	default:
- 	  add_error (Error (t->get_locus (),
- 			    "unexpected token %qs in use tree with valid path",
- 			    t->get_token_description ()));
- 
- 	  // skip_after_semicolon();
- 	  return nullptr;
- 	}
-     }
- }
- 
- // Parses a function (not a method).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::Function>
- Parser<ManagedTokenSource>::parse_function (AST::Visibility vis,
- 					    AST::AttrVec outer_attrs,
- 					    bool is_external)
- {
-   location_t locus = lexer.peek_token ()->get_locus ();
-   // Get qualifiers for function if they exist
-   AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
- 
-   skip_token (FN_KW);
- 
-   // Save function name token
-   const_TokenPtr function_name_tok = expect_token (IDENTIFIER);
-   if (function_name_tok == nullptr)
-     {
-       skip_after_next_block ();
-       return nullptr;
-     }
-   Identifier function_name{function_name_tok};
- 
-   // parse generic params - if exist
-   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
-     = parse_generic_params_in_angles ();
- 
-   if (!skip_token (LEFT_PAREN))
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "function declaration missing opening parentheses before "
- 		   "parameter list");
-       add_error (std::move (error));
- 
-       skip_after_next_block ();
-       return nullptr;
-     }
- 
-   auto initial_param = parse_self_param ();
- 
-   if (!initial_param.has_value ()
-       && initial_param.error () != ParseSelfError::NOT_SELF)
-     return nullptr;
- 
-   if (initial_param.has_value () && lexer.peek_token ()->get_id () == COMMA)
-     skip_token ();
- 
-   // parse function parameters (only if next token isn't right paren)
-   std::vector<std::unique_ptr<AST::Param>> function_params;
- 
-   if (lexer.peek_token ()->get_id () != RIGHT_PAREN)
-     function_params
-       = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
- 
-   if (initial_param.has_value ())
-     function_params.insert (function_params.begin (),
- 			    std::move (*initial_param));
- 
-   if (!skip_token (RIGHT_PAREN))
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "function declaration missing closing parentheses after "
- 		   "parameter list");
-       add_error (std::move (error));
- 
-       skip_after_next_block ();
-       return nullptr;
-     }
- 
-   // parse function return type - if exists
-   std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
- 
-   // parse where clause - if exists
-   AST::WhereClause where_clause = parse_where_clause ();
- 
-   tl::optional<std::unique_ptr<AST::BlockExpr>> body = tl::nullopt;
-   if (lexer.peek_token ()->get_id () == SEMICOLON)
-     lexer.skip_token ();
-   else
-     {
-       std::unique_ptr<AST::BlockExpr> block_expr = parse_block_expr ();
-       if (block_expr == nullptr)
- 	return nullptr;
-       body = std::move (block_expr);
-     }
- 
-   return std::unique_ptr<AST::Function> (
-     new AST::Function (std::move (function_name), std::move (qualifiers),
- 		       std::move (generic_params), std::move (function_params),
- 		       std::move (return_type), std::move (where_clause),
- 		       std::move (body), std::move (vis),
- 		       std::move (outer_attrs), locus, false, is_external));
- }
- 
- // Parses function or method qualifiers (i.e. const, unsafe, and extern).
- template <typename ManagedTokenSource>
- AST::FunctionQualifiers
- Parser<ManagedTokenSource>::parse_function_qualifiers ()
- {
-   Async async_status = Async::No;
-   Const const_status = Const::No;
-   Unsafety unsafe_status = Unsafety::Normal;
-   bool has_extern = false;
-   std::string abi;
- 
-   const_TokenPtr t;
-   location_t locus;
-   // Check in order of const, unsafe, then extern
-   for (int i = 0; i < 2; i++)
-     {
-       t = lexer.peek_token ();
-       locus = t->get_locus ();
- 
-       switch (t->get_id ())
- 	{
- 	case CONST:
- 	  lexer.skip_token ();
- 	  const_status = Const::Yes;
- 	  break;
- 	case ASYNC:
- 	  lexer.skip_token ();
- 	  async_status = Async::Yes;
- 	  break;
- 	default:
- 	  // const status is still none
- 	  break;
- 	}
-     }
- 
-   if (lexer.peek_token ()->get_id () == UNSAFE)
-     {
-       lexer.skip_token ();
-       unsafe_status = Unsafety::Unsafe;
-     }
- 
-   if (lexer.peek_token ()->get_id () == EXTERN_KW)
-     {
-       lexer.skip_token ();
-       has_extern = true;
- 
-       // detect optional abi name
-       const_TokenPtr next_tok = lexer.peek_token ();
-       if (next_tok->get_id () == STRING_LITERAL)
- 	{
- 	  lexer.skip_token ();
- 	  abi = next_tok->get_str ();
- 	}
-     }
- 
-   return AST::FunctionQualifiers (locus, async_status, const_status,
- 				  unsafe_status, has_extern, std::move (abi));
- }
- 
- // Parses generic (lifetime or type) params inside angle brackets (optional).
- template <typename ManagedTokenSource>
- std::vector<std::unique_ptr<AST::GenericParam>>
- Parser<ManagedTokenSource>::parse_generic_params_in_angles ()
- {
-   if (lexer.peek_token ()->get_id () != LEFT_ANGLE)
-     {
-       // seems to be no generic params, so exit with empty vector
-       return std::vector<std::unique_ptr<AST::GenericParam>> ();
-     }
-   lexer.skip_token ();
- 
-   // DEBUG:
-   rust_debug ("skipped left angle in generic param");
- 
-   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
-     = parse_generic_params (is_right_angle_tok);
- 
-   // DEBUG:
-   rust_debug ("finished parsing actual generic params (i.e. inside angles)");
- 
-   if (!skip_generics_right_angle ())
-     {
-       // DEBUG
-       rust_debug ("failed to skip generics right angle - returning empty "
- 		  "generic params");
- 
-       return std::vector<std::unique_ptr<AST::GenericParam>> ();
-     }
- 
-   return generic_params;
- }
- 
- template <typename ManagedTokenSource>
- template <typename EndTokenPred>
- std::unique_ptr<AST::GenericParam>
- Parser<ManagedTokenSource>::parse_generic_param (EndTokenPred is_end_token)
- {
-   auto outer_attrs = parse_outer_attributes ();
-   std::unique_ptr<AST::GenericParam> param;
-   auto token = lexer.peek_token ();
- 
-   switch (token->get_id ())
-     {
-     case LIFETIME:
-       {
- 	auto lifetime = parse_lifetime (false);
- 	if (!lifetime)
- 	  {
- 	    rust_error_at (
- 	      token->get_locus (),
- 	      "failed to parse lifetime in generic parameter list");
- 	    return nullptr;
- 	  }
- 
- 	std::vector<AST::Lifetime> lifetime_bounds;
- 	if (lexer.peek_token ()->get_id () == COLON)
- 	  {
- 	    lexer.skip_token ();
- 	    // parse required bounds
- 	    lifetime_bounds
- 	      = parse_lifetime_bounds ([is_end_token] (TokenId id) {
- 		  return is_end_token (id) || id == COMMA;
- 		});
- 	  }
- 
- 	param = std::unique_ptr<AST::LifetimeParam> (new AST::LifetimeParam (
- 	  std::move (lifetime.value ()), std::move (lifetime_bounds),
- 	  std::move (outer_attrs), token->get_locus ()));
- 	break;
-       }
-     case IDENTIFIER:
-       {
- 	auto type_ident = token->get_str ();
- 	lexer.skip_token ();
- 
- 	std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
- 	if (lexer.peek_token ()->get_id () == COLON)
- 	  {
- 	    lexer.skip_token ();
- 
- 	    // parse optional type param bounds
- 	    type_param_bounds = parse_type_param_bounds ();
- 	  }
- 
- 	std::unique_ptr<AST::Type> type = nullptr;
- 	if (lexer.peek_token ()->get_id () == EQUAL)
- 	  {
- 	    lexer.skip_token ();
- 
- 	    // parse required type
- 	    type = parse_type ();
- 	    if (!type)
- 	      {
- 		rust_error_at (
- 		  lexer.peek_token ()->get_locus (),
- 		  "failed to parse type in type param in generic params");
- 		return nullptr;
- 	      }
- 	  }
- 
- 	param = std::unique_ptr<AST::TypeParam> (
- 	  new AST::TypeParam (std::move (type_ident), token->get_locus (),
- 			      std::move (type_param_bounds), std::move (type),
- 			      std::move (outer_attrs)));
- 	break;
-       }
-     case CONST:
-       {
- 	lexer.skip_token ();
- 
- 	auto name_token = expect_token (IDENTIFIER);
- 
- 	if (!name_token || !expect_token (COLON))
- 	  return nullptr;
- 
- 	auto type = parse_type ();
- 	if (!type)
- 	  return nullptr;
- 
- 	// optional default value
- 	tl::optional<AST::GenericArg> default_expr = tl::nullopt;
- 	if (lexer.peek_token ()->get_id () == EQUAL)
- 	  {
- 	    lexer.skip_token ();
- 	    auto tok = lexer.peek_token ();
- 	    default_expr = parse_generic_arg ();
- 
- 	    if (!default_expr)
- 	      {
- 		rust_error_at (tok->get_locus (),
- 			       "invalid token for start of default value for "
- 			       "const generic parameter: expected %<block%>, "
- 			       "%<identifier%> or %<literal%>, got %qs",
- 			       token_id_to_str (tok->get_id ()));
- 		return nullptr;
- 	      }
- 
- 	    // At this point, we *know* that we are parsing a const
- 	    // expression
- 	    if (default_expr.value ().get_kind ()
- 		== AST::GenericArg::Kind::Either)
- 	      default_expr = default_expr.value ().disambiguate_to_const ();
- 	  }
- 
- 	param = std::unique_ptr<AST::ConstGenericParam> (
- 	  new AST::ConstGenericParam (name_token->get_str (), std::move (type),
- 				      default_expr, std::move (outer_attrs),
- 				      token->get_locus ()));
- 
- 	break;
-       }
-     default:
-       // FIXME: Can we clean this last call with a method call?
-       rust_error_at (token->get_locus (),
- 		     "unexpected token when parsing generic parameters: %qs",
- 		     token->as_string ().c_str ());
-       return nullptr;
-     }
- 
-   return param;
- }
- 
- /* Parse generic (lifetime or type) params NOT INSIDE ANGLE BRACKETS!!! Almost
-  * always parse_generic_params_in_angles is what is wanted. */
- template <typename ManagedTokenSource>
- template <typename EndTokenPred>
- std::vector<std::unique_ptr<AST::GenericParam>>
- Parser<ManagedTokenSource>::parse_generic_params (EndTokenPred is_end_token)
- {
-   std::vector<std::unique_ptr<AST::GenericParam>> generic_params;
- 
-   /* can't parse lifetime and type params separately due to lookahead issues
-    * thus, parse them all here */
- 
-   /* HACK: used to retain attribute data if a lifetime param is tentatively
-    * parsed but it turns out to be type param */
-   AST::Attribute parsed_outer_attr = AST::Attribute::create_empty ();
- 
-   // Did we parse a generic type param yet
-   auto type_seen = false;
-   // Did we parse a const param with a default value yet
-   auto const_with_default_seen = false;
-   // Did the user write a lifetime parameter after a type one
-   auto order_error = false;
-   // Did the user write a const param with a default value after a type one
-   auto const_with_default_order_error = false;
- 
-   // parse lifetime params
-   while (!is_end_token (lexer.peek_token ()->get_id ()))
-     {
-       auto param = parse_generic_param (is_end_token);
-       if (param)
- 	{
- 	  if (param->get_kind () == AST::GenericParam::Kind::Type)
- 	    {
- 	      type_seen = true;
- 	      if (const_with_default_seen)
- 		const_with_default_order_error = true;
- 	    }
- 	  else if (param->get_kind () == AST::GenericParam::Kind::Lifetime
- 		   && type_seen)
- 	    {
- 	      order_error = true;
- 	      if (const_with_default_seen)
- 		const_with_default_order_error = true;
- 	    }
- 	  else if (param->get_kind () == AST::GenericParam::Kind::Const)
- 	    {
- 	      type_seen = true;
- 	      AST::ConstGenericParam *const_param
- 		= static_cast<AST::ConstGenericParam *> (param.get ());
- 	      if (const_param->has_default_value ())
- 		const_with_default_seen = true;
- 	      else if (const_with_default_seen)
- 		const_with_default_order_error = true;
- 	    }
- 
- 	  generic_params.emplace_back (std::move (param));
- 	  maybe_skip_token (COMMA);
- 	}
-       else
- 	break;
-     }
- 
-   // FIXME: Add reordering hint
-   if (order_error)
-     {
-       Error error (generic_params.front ()->get_locus (),
- 		   "invalid order for generic parameters: lifetime parameters "
- 		   "must be declared prior to type and const parameters");
-       add_error (std::move (error));
-     }
-   if (const_with_default_order_error)
-     {
-       Error error (generic_params.front ()->get_locus (),
- 		   "invalid order for generic parameters: generic parameters "
- 		   "with a default must be trailing");
-       add_error (std::move (error));
-     }
- 
-   generic_params.shrink_to_fit ();
-   return generic_params;
- }
- 
- /* Parses lifetime generic parameters (pointers). Will also consume any
-  * trailing comma. No extra checks for end token. */
- template <typename ManagedTokenSource>
- std::vector<std::unique_ptr<AST::LifetimeParam>>
- Parser<ManagedTokenSource>::parse_lifetime_params ()
- {
-   std::vector<std::unique_ptr<AST::LifetimeParam>> lifetime_params;
- 
-   while (lexer.peek_token ()->get_id () != END_OF_FILE)
-     {
-       auto lifetime_param = parse_lifetime_param ();
- 
-       if (!lifetime_param)
- 	{
- 	  // can't treat as error as only way to get out with trailing comma
- 	  break;
- 	}
- 
-       lifetime_params.emplace_back (
- 	new AST::LifetimeParam (std::move (lifetime_param.value ())));
- 
-       if (lexer.peek_token ()->get_id () != COMMA)
- 	break;
- 
-       // skip commas, including trailing commas
-       lexer.skip_token ();
-     }
- 
-   lifetime_params.shrink_to_fit ();
- 
-   return lifetime_params;
- }
- 
- /* Parses lifetime generic parameters (pointers). Will also consume any
-  * trailing comma. Has extra is_end_token predicate checking. */
- template <typename ManagedTokenSource>
- template <typename EndTokenPred>
- std::vector<std::unique_ptr<AST::LifetimeParam>>
- Parser<ManagedTokenSource>::parse_lifetime_params (EndTokenPred is_end_token)
- {
-   std::vector<std::unique_ptr<AST::LifetimeParam>> lifetime_params;
- 
-   // if end_token is not specified, it defaults to EOF, so should work fine
-   while (!is_end_token (lexer.peek_token ()->get_id ()))
-     {
-       auto lifetime_param = parse_lifetime_param ();
- 
-       if (!lifetime_param)
- 	{
- 	  /* TODO: is it worth throwing away all lifetime params just because
- 	   * one failed? */
- 	  Error error (lexer.peek_token ()->get_locus (),
- 		       "failed to parse lifetime param in lifetime params");
- 	  add_error (std::move (error));
- 
- 	  return {};
- 	}
- 
-       lifetime_params.emplace_back (
- 	new AST::LifetimeParam (std::move (lifetime_param)));
- 
-       if (lexer.peek_token ()->get_id () != COMMA)
- 	break;
- 
-       // skip commas, including trailing commas
-       lexer.skip_token ();
-     }
- 
-   lifetime_params.shrink_to_fit ();
- 
-   return lifetime_params;
- }
- 
- /* Parses lifetime generic parameters (objects). Will also consume any
-  * trailing comma. No extra checks for end token.
-  * TODO: is this best solution? implements most of the same algorithm.
-  * TODO: seems to be unused, remove? */
- template <typename ManagedTokenSource>
- std::vector<AST::LifetimeParam>
- Parser<ManagedTokenSource>::parse_lifetime_params_objs ()
- {
-   std::vector<AST::LifetimeParam> lifetime_params;
- 
-   // bad control structure as end token cannot be guaranteed
-   while (true)
-     {
-       auto lifetime_param = parse_lifetime_param ();
- 
-       if (!lifetime_param)
- 	{
- 	  // not an error as only way to exit if trailing comma
- 	  break;
- 	}
- 
-       lifetime_params.push_back (std::move (lifetime_param.value ()));
- 
-       if (lexer.peek_token ()->get_id () != COMMA)
- 	break;
- 
-       // skip commas, including trailing commas
-       lexer.skip_token ();
-     }
- 
-   lifetime_params.shrink_to_fit ();
- 
-   return lifetime_params;
- }
- 
- /* Parses lifetime generic parameters (objects). Will also consume any
-  * trailing comma. Has extra is_end_token predicate checking.
-  * TODO: is this best solution? implements most of the same algorithm. */
- template <typename ManagedTokenSource>
- template <typename EndTokenPred>
- std::vector<AST::LifetimeParam>
- Parser<ManagedTokenSource>::parse_lifetime_params_objs (
-   EndTokenPred is_end_token)
- {
-   std::vector<AST::LifetimeParam> lifetime_params;
- 
-   while (!is_end_token (lexer.peek_token ()->get_id ()))
-     {
-       auto lifetime_param = parse_lifetime_param ();
- 
-       if (!lifetime_param)
- 	{
- 	  /* TODO: is it worth throwing away all lifetime params just because
- 	   * one failed? */
- 	  Error error (lexer.peek_token ()->get_locus (),
- 		       "failed to parse lifetime param in lifetime params");
- 	  add_error (std::move (error));
- 
- 	  return {};
- 	}
- 
-       lifetime_params.push_back (std::move (lifetime_param.value ()));
- 
-       if (lexer.peek_token ()->get_id () != COMMA)
- 	break;
- 
-       // skip commas, including trailing commas
-       lexer.skip_token ();
-     }
- 
-   lifetime_params.shrink_to_fit ();
- 
-   return lifetime_params;
- }
- 
- /* Parses a sequence of a certain grammar rule in object form (not pointer or
-  * smart pointer), delimited by commas and ending when 'is_end_token' is
-  * satisfied (templated). Will also consume any trailing comma.
-  * FIXME: this cannot be used due to member function pointer problems (i.e.
-  * parsing_function cannot be specified properly) */
- template <typename ManagedTokenSource>
- template <typename ParseFunction, typename EndTokenPred>
- auto
- Parser<ManagedTokenSource>::parse_non_ptr_sequence (
-   ParseFunction parsing_function, EndTokenPred is_end_token,
-   std::string error_msg) -> std::vector<decltype (parsing_function ())>
- {
-   std::vector<decltype (parsing_function ())> params;
- 
-   while (!is_end_token (lexer.peek_token ()->get_id ()))
-     {
-       auto param = parsing_function ();
- 
-       if (param.is_error ())
- 	{
- 	  // TODO: is it worth throwing away all params just because one
- 	  // failed?
- 	  Error error (lexer.peek_token ()->get_locus (),
- 		       std::move (error_msg));
- 	  add_error (std::move (error));
- 
- 	  return {};
- 	}
- 
-       params.push_back (std::move (param));
- 
-       if (lexer.peek_token ()->get_id () != COMMA)
- 	break;
- 
-       // skip commas, including trailing commas
-       lexer.skip_token ();
-     }
- 
-   params.shrink_to_fit ();
- 
-   return params;
- }
- 
- /* Parses a single lifetime generic parameter (not including comma). */
- template <typename ManagedTokenSource>
- tl::expected<AST::LifetimeParam, ParseLifetimeParamError>
- Parser<ManagedTokenSource>::parse_lifetime_param ()
- {
-   // parse outer attributes, which are optional and may not exist
-   auto outer_attrs = parse_outer_attributes ();
- 
-   // save lifetime token - required
-   const_TokenPtr lifetime_tok = lexer.peek_token ();
-   if (lifetime_tok->get_id () != LIFETIME)
-     {
-       // if lifetime is missing, must not be a lifetime param, so return error
-       return tl::make_unexpected<ParseLifetimeParamError> ({});
-     }
-   lexer.skip_token ();
-   AST::Lifetime lifetime (AST::Lifetime::NAMED, lifetime_tok->get_str (),
- 			  lifetime_tok->get_locus ());
- 
-   // parse lifetime bounds, if it exists
-   std::vector<AST::Lifetime> lifetime_bounds;
-   if (lexer.peek_token ()->get_id () == COLON)
-     {
-       // parse lifetime bounds
-       lifetime_bounds = parse_lifetime_bounds ();
-       // TODO: have end token passed in?
-     }
- 
-   return AST::LifetimeParam (std::move (lifetime), std::move (lifetime_bounds),
- 			     std::move (outer_attrs),
- 			     lifetime_tok->get_locus ());
- }
- 
- // Parses type generic parameters. Will also consume any trailing comma.
- template <typename ManagedTokenSource>
- std::vector<std::unique_ptr<AST::TypeParam>>
- Parser<ManagedTokenSource>::parse_type_params ()
- {
-   std::vector<std::unique_ptr<AST::TypeParam>> type_params;
- 
-   // infinite loop with break on failure as no info on ending token
-   while (true)
-     {
-       std::unique_ptr<AST::TypeParam> type_param = parse_type_param ();
- 
-       if (type_param == nullptr)
- 	{
- 	  // break if fails to parse
- 	  break;
- 	}
- 
-       type_params.push_back (std::move (type_param));
- 
-       if (lexer.peek_token ()->get_id () != COMMA)
- 	break;
- 
-       // skip commas, including trailing commas
-       lexer.skip_token ();
-     }
- 
-   type_params.shrink_to_fit ();
-   return type_params;
- }
- 
- // Parses type generic parameters. Will also consume any trailing comma.
- template <typename ManagedTokenSource>
- template <typename EndTokenPred>
- std::vector<std::unique_ptr<AST::TypeParam>>
- Parser<ManagedTokenSource>::parse_type_params (EndTokenPred is_end_token)
- {
-   std::vector<std::unique_ptr<AST::TypeParam>> type_params;
- 
-   while (!is_end_token (lexer.peek_token ()->get_id ()))
-     {
-       std::unique_ptr<AST::TypeParam> type_param = parse_type_param ();
- 
-       if (type_param == nullptr)
- 	{
- 	  Error error (lexer.peek_token ()->get_locus (),
- 		       "failed to parse type param in type params");
- 	  add_error (std::move (error));
- 
- 	  return {};
- 	}
- 
-       type_params.push_back (std::move (type_param));
- 
-       if (lexer.peek_token ()->get_id () != COMMA)
- 	break;
- 
-       // skip commas, including trailing commas
-       lexer.skip_token ();
-     }
- 
-   type_params.shrink_to_fit ();
-   return type_params;
-   /* TODO: this shares most code with parse_lifetime_params - good place to
-    * use template (i.e. parse_non_ptr_sequence if doable) */
- }
- 
- /* Parses a single type (generic) parameter, not including commas. May change
-  * to return value. */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::TypeParam>
- Parser<ManagedTokenSource>::parse_type_param ()
- {
-   // parse outer attributes, which are optional and may not exist
-   auto outer_attrs = parse_outer_attributes ();
- 
-   const_TokenPtr identifier_tok = lexer.peek_token ();
-   if (identifier_tok->get_id () != IDENTIFIER)
-     {
-       // return null as type param can't exist without this required
-       // identifier
-       return nullptr;
-     }
-   Identifier ident{identifier_tok};
-   lexer.skip_token ();
- 
-   // parse type param bounds (if they exist)
-   std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
-   if (lexer.peek_token ()->get_id () == COLON)
-     {
-       lexer.skip_token ();
- 
-       // parse type param bounds, which may or may not exist
-       type_param_bounds = parse_type_param_bounds ();
-     }
- 
-   // parse type (if it exists)
-   std::unique_ptr<AST::Type> type = nullptr;
-   if (lexer.peek_token ()->get_id () == EQUAL)
-     {
-       lexer.skip_token ();
- 
-       // parse type (now required)
-       type = parse_type ();
-       if (type == nullptr)
- 	{
- 	  Error error (lexer.peek_token ()->get_locus (),
- 		       "failed to parse type in type param");
- 	  add_error (std::move (error));
- 
- 	  return nullptr;
- 	}
-     }
- 
-   return std::unique_ptr<AST::TypeParam> (
-     new AST::TypeParam (std::move (ident), identifier_tok->get_locus (),
- 			std::move (type_param_bounds), std::move (type),
- 			std::move (outer_attrs)));
- }
- 
- /* Parses regular (i.e. non-generic) parameters in functions or methods. Also
-  * has end token handling. */
- template <typename ManagedTokenSource>
- template <typename EndTokenPred>
- std::vector<std::unique_ptr<AST::Param>>
- Parser<ManagedTokenSource>::parse_function_params (EndTokenPred is_end_token)
- {
-   std::vector<std::unique_ptr<AST::Param>> params;
- 
-   if (is_end_token (lexer.peek_token ()->get_id ()))
-     return params;
- 
-   auto initial_param = parse_function_param ();
- 
-   // Return empty parameter list if no parameter there
-   if (initial_param == nullptr)
-     {
-       // TODO: is this an error?
-       return params;
-     }
- 
-   params.push_back (std::move (initial_param));
- 
-   // maybe think of a better control structure here - do-while with an initial
-   // error state? basically, loop through parameter list until can't find any
-   // more params
-   const_TokenPtr t = lexer.peek_token ();
-   while (t->get_id () == COMMA)
-     {
-       // skip comma if applies
-       lexer.skip_token ();
- 
-       // TODO: strictly speaking, shouldn't there be no trailing comma?
-       if (is_end_token (lexer.peek_token ()->get_id ()))
- 	break;
- 
-       // now, as right paren would break, function param is required
-       auto param = parse_function_param ();
-       if (param == nullptr)
- 	{
- 	  Error error (lexer.peek_token ()->get_locus (),
- 		       "failed to parse function param (in function params)");
- 	  add_error (std::move (error));
- 
- 	  // skip somewhere?
- 	  return std::vector<std::unique_ptr<AST::Param>> ();
- 	}
- 
-       params.push_back (std::move (param));
- 
-       t = lexer.peek_token ();
-     }
- 
-   params.shrink_to_fit ();
-   return params;
- }
- 
- /* Parses a single regular (i.e. non-generic) parameter in a function or
-  * method, i.e. the "name: type" bit. Also handles it not existing. */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::Param>
- Parser<ManagedTokenSource>::parse_function_param ()
- {
-   // parse outer attributes if they exist
-   AST::AttrVec outer_attrs = parse_outer_attributes ();
- 
-   // TODO: should saved location be at start of outer attributes or pattern?
-   location_t locus = lexer.peek_token ()->get_locus ();
- 
-   if (lexer.peek_token ()->get_id () == ELLIPSIS) // Unnamed variadic
-     {
-       lexer.skip_token (); // Skip ellipsis
-       return std::make_unique<AST::VariadicParam> (
- 	AST::VariadicParam (std::move (outer_attrs), locus));
-     }
- 
-   std::unique_ptr<AST::Pattern> param_pattern = parse_pattern ();
- 
-   // create error function param if it doesn't exist
-   if (param_pattern == nullptr)
-     {
-       // skip after something
-       return nullptr;
-     }
- 
-   if (!skip_token (COLON))
-     {
-       // skip after something
-       return nullptr;
-     }
- 
-   if (lexer.peek_token ()->get_id () == ELLIPSIS) // Named variadic
-     {
-       lexer.skip_token (); // Skip ellipsis
-       return std::make_unique<AST::VariadicParam> (
- 	AST::VariadicParam (std::move (param_pattern), std::move (outer_attrs),
- 			    locus));
-     }
-   else
-     {
-       std::unique_ptr<AST::Type> param_type = parse_type ();
-       if (param_type == nullptr)
- 	{
- 	  return nullptr;
- 	}
-       return std::make_unique<AST::FunctionParam> (
- 	AST::FunctionParam (std::move (param_pattern), std::move (param_type),
- 			    std::move (outer_attrs), locus));
-     }
- }
- 
- /* Parses a function or method return type syntactical construction. Also
-  * handles a function return type not existing. */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::Type>
- Parser<ManagedTokenSource>::parse_function_return_type ()
- {
-   if (lexer.peek_token ()->get_id () != RETURN_TYPE)
-     return nullptr;
- 
-   // skip return type, as it now obviously exists
-   lexer.skip_token ();
- 
-   std::unique_ptr<AST::Type> type = parse_type ();
- 
-   return type;
- }
- 
- /* Parses a "where clause" (in a function, struct, method, etc.). Also handles
-  * a where clause not existing, in which it will return
-  * WhereClause::create_empty(), which can be checked via
-  * WhereClause::is_empty(). */
- template <typename ManagedTokenSource>
- AST::WhereClause
- Parser<ManagedTokenSource>::parse_where_clause ()
- {
-   const_TokenPtr where_tok = lexer.peek_token ();
-   if (where_tok->get_id () != WHERE)
-     {
-       // where clause doesn't exist, so create empty one
-       return AST::WhereClause::create_empty ();
-     }
- 
-   lexer.skip_token ();
- 
-   /* parse where clause items - this is not a separate rule in the reference
-    * so won't be here */
-   std::vector<std::unique_ptr<AST::WhereClauseItem>> where_clause_items;
- 
-   std::vector<AST::LifetimeParam> for_lifetimes;
-   if (lexer.peek_token ()->get_id () == FOR)
-     for_lifetimes = parse_for_lifetimes ();
- 
-   /* HACK: where clauses end with a right curly or semicolon or equals in all
-    * uses currently */
-   const_TokenPtr t = lexer.peek_token ();
-   while (t->get_id () != LEFT_CURLY && t->get_id () != SEMICOLON
- 	 && t->get_id () != EQUAL)
-     {
-       std::unique_ptr<AST::WhereClauseItem> where_clause_item
- 	= parse_where_clause_item (for_lifetimes);
- 
-       if (where_clause_item == nullptr)
- 	{
- 	  Error error (t->get_locus (), "failed to parse where clause item");
- 	  add_error (std::move (error));
- 
- 	  return AST::WhereClause::create_empty ();
- 	}
- 
-       where_clause_items.push_back (std::move (where_clause_item));
- 
-       // also skip comma if it exists
-       if (lexer.peek_token ()->get_id () != COMMA)
- 	break;
- 
-       lexer.skip_token ();
-       t = lexer.peek_token ();
-     }
- 
-   where_clause_items.shrink_to_fit ();
-   return AST::WhereClause (std::move (where_clause_items));
- }
- 
- /* Parses a where clause item (lifetime or type bound). Does not parse any
-  * commas. */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::WhereClauseItem>
- Parser<ManagedTokenSource>::parse_where_clause_item (
-   const std::vector<AST::LifetimeParam> &outer_for_lifetimes)
- {
-   // shitty cheat way of determining lifetime or type bound - test for
-   // lifetime
-   const_TokenPtr t = lexer.peek_token ();
- 
-   if (t->get_id () == LIFETIME)
-     return parse_lifetime_where_clause_item ();
-   else
-     return parse_type_bound_where_clause_item (outer_for_lifetimes);
- }
- 
- // Parses a lifetime where clause item.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::LifetimeWhereClauseItem>
- Parser<ManagedTokenSource>::parse_lifetime_where_clause_item ()
- {
-   auto parsed_lifetime = parse_lifetime (false);
-   if (!parsed_lifetime)
-     {
-       // TODO: error here?
-       return nullptr;
-     }
-   auto lifetime = parsed_lifetime.value ();
- 
-   if (!skip_token (COLON))
-     {
-       // TODO: skip after somewhere
-       return nullptr;
-     }
- 
-   std::vector<AST::Lifetime> lifetime_bounds = parse_lifetime_bounds ();
-   // TODO: have end token passed in?
- 
-   location_t locus = lifetime.get_locus ();
- 
-   return std::unique_ptr<AST::LifetimeWhereClauseItem> (
-     new AST::LifetimeWhereClauseItem (std::move (lifetime),
- 				      std::move (lifetime_bounds), locus));
- }
- 
- // Parses a type bound where clause item.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::TypeBoundWhereClauseItem>
- Parser<ManagedTokenSource>::parse_type_bound_where_clause_item (
-   const std::vector<AST::LifetimeParam> &outer_for_lifetimes)
- {
-   std::vector<AST::LifetimeParam> for_lifetimes = outer_for_lifetimes;
- 
-   std::unique_ptr<AST::Type> type = parse_type ();
-   if (type == nullptr)
-     {
-       return nullptr;
-     }
- 
-   if (!skip_token (COLON))
-     {
-       // TODO: skip after somewhere
-       return nullptr;
-     }
- 
-   if (lexer.peek_token ()->get_id () == FOR)
-     {
-       auto for_lifetimes_inner = parse_for_lifetimes ();
-       for_lifetimes.insert (for_lifetimes.end (), for_lifetimes_inner.begin (),
- 			    for_lifetimes_inner.end ());
-     }
- 
-   // parse type param bounds if they exist
-   std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds
-     = parse_type_param_bounds ();
- 
-   location_t locus = lexer.peek_token ()->get_locus ();
- 
-   return std::unique_ptr<AST::TypeBoundWhereClauseItem> (
-     new AST::TypeBoundWhereClauseItem (std::move (for_lifetimes),
- 				       std::move (type),
- 				       std::move (type_param_bounds), locus));
- }
- 
- // Parses a for lifetimes clause, including the for keyword and angle
- // brackets.
- template <typename ManagedTokenSource>
- std::vector<AST::LifetimeParam>
- Parser<ManagedTokenSource>::parse_for_lifetimes ()
- {
-   std::vector<AST::LifetimeParam> params;
- 
-   if (!skip_token (FOR))
-     {
-       // skip after somewhere?
-       return params;
-     }
- 
-   if (!skip_token (LEFT_ANGLE))
-     {
-       // skip after somewhere?
-       return params;
-     }
- 
-   /* cannot specify end token due to parsing problems with '>' tokens being
-    * nested */
-   params = parse_lifetime_params_objs (is_right_angle_tok);
- 
-   if (!skip_generics_right_angle ())
-     {
-       // DEBUG
-       rust_debug ("failed to skip generics right angle after (supposedly) "
- 		  "finished parsing where clause items");
-       // ok, well this gets called.
- 
-       // skip after somewhere?
-       return params;
-     }
- 
-   return params;
- }
- 
- // Parses type parameter bounds in where clause or generic arguments.
- template <typename ManagedTokenSource>
- std::vector<std::unique_ptr<AST::TypeParamBound>>
- Parser<ManagedTokenSource>::parse_type_param_bounds ()
- {
-   std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
- 
-   std::unique_ptr<AST::TypeParamBound> initial_bound
-     = parse_type_param_bound ();
- 
-   // quick exit if null
-   if (initial_bound == nullptr)
-     {
-       /* error? type param bounds must have at least one term, but are bounds
-        * optional? */
-       return type_param_bounds;
-     }
-   type_param_bounds.push_back (std::move (initial_bound));
- 
-   while (lexer.peek_token ()->get_id () == PLUS)
-     {
-       lexer.skip_token ();
- 
-       std::unique_ptr<AST::TypeParamBound> bound = parse_type_param_bound ();
-       if (bound == nullptr)
- 	{
- 	  /* not an error: bound is allowed to be null as trailing plus is
- 	   * allowed */
- 	  return type_param_bounds;
- 	}
- 
-       type_param_bounds.push_back (std::move (bound));
-     }
- 
-   type_param_bounds.shrink_to_fit ();
-   return type_param_bounds;
- }
- 
- /* Parses type parameter bounds in where clause or generic arguments, with end
-  * token handling. */
- template <typename ManagedTokenSource>
- template <typename EndTokenPred>
- std::vector<std::unique_ptr<AST::TypeParamBound>>
- Parser<ManagedTokenSource>::parse_type_param_bounds (EndTokenPred is_end_token)
- {
-   std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
- 
-   std::unique_ptr<AST::TypeParamBound> initial_bound
-     = parse_type_param_bound ();
- 
-   // quick exit if null
-   if (initial_bound == nullptr)
-     {
-       /* error? type param bounds must have at least one term, but are bounds
-        * optional? */
-       return type_param_bounds;
-     }
-   type_param_bounds.push_back (std::move (initial_bound));
- 
-   while (lexer.peek_token ()->get_id () == PLUS)
-     {
-       lexer.skip_token ();
- 
-       // break if end token character
-       if (is_end_token (lexer.peek_token ()->get_id ()))
- 	break;
- 
-       std::unique_ptr<AST::TypeParamBound> bound = parse_type_param_bound ();
-       if (bound == nullptr)
- 	{
- 	  // TODO how wise is it to ditch all bounds if only one failed?
- 	  Error error (lexer.peek_token ()->get_locus (),
- 		       "failed to parse type param bound in type param bounds");
- 	  add_error (std::move (error));
- 
- 	  return {};
- 	}
- 
-       type_param_bounds.push_back (std::move (bound));
-     }
- 
-   type_param_bounds.shrink_to_fit ();
-   return type_param_bounds;
- }
- 
- /* Parses a single type parameter bound in a where clause or generic argument.
-  * Does not parse the '+' between arguments. */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::TypeParamBound>
- Parser<ManagedTokenSource>::parse_type_param_bound ()
- {
-   // shitty cheat way of determining lifetime or trait bound - test for
-   // lifetime
-   const_TokenPtr t = lexer.peek_token ();
-   switch (t->get_id ())
-     {
-     case LIFETIME:
-       return std::unique_ptr<AST::Lifetime> (
- 	new AST::Lifetime (parse_lifetime (false).value ()));
-     case LEFT_PAREN:
-     case QUESTION_MARK:
-     case FOR:
-     case IDENTIFIER:
-     case SUPER:
-     case SELF:
-     case SELF_ALIAS:
-     case CRATE:
-     case DOLLAR_SIGN:
-     case SCOPE_RESOLUTION:
-       return parse_trait_bound ();
-     default:
-       // don't error - assume this is fine TODO
-       return nullptr;
-     }
- }
- 
- // Parses a trait bound type param bound.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::TraitBound>
- Parser<ManagedTokenSource>::parse_trait_bound ()
- {
-   bool has_parens = false;
-   bool has_question_mark = false;
- 
-   location_t locus = lexer.peek_token ()->get_locus ();
- 
-   /* parse optional `for lifetimes`. */
-   std::vector<AST::LifetimeParam> for_lifetimes;
-   if (lexer.peek_token ()->get_id () == FOR)
-     for_lifetimes = parse_for_lifetimes ();
- 
-   // handle trait bound being in parentheses
-   if (lexer.peek_token ()->get_id () == LEFT_PAREN)
-     {
-       has_parens = true;
-       lexer.skip_token ();
-     }
- 
-   // handle having question mark (optional)
-   if (lexer.peek_token ()->get_id () == QUESTION_MARK)
-     {
-       has_question_mark = true;
-       lexer.skip_token ();
-     }
- 
-   // handle TypePath
-   AST::TypePath type_path = parse_type_path ();
- 
-   // handle closing parentheses
-   if (has_parens)
-     {
-       if (!skip_token (RIGHT_PAREN))
- 	{
- 	  return nullptr;
- 	}
-     }
- 
-   return std::unique_ptr<AST::TraitBound> (
-     new AST::TraitBound (std::move (type_path), locus, has_parens,
- 			 has_question_mark, std::move (for_lifetimes)));
- }
- 
- // Parses lifetime bounds.
- template <typename ManagedTokenSource>
- std::vector<AST::Lifetime>
- Parser<ManagedTokenSource>::parse_lifetime_bounds ()
- {
-   std::vector<AST::Lifetime> lifetime_bounds;
- 
-   while (true)
-     {
-       auto lifetime = parse_lifetime (false);
- 
-       // quick exit for parsing failure
-       if (!lifetime)
- 	break;
- 
-       lifetime_bounds.push_back (std::move (lifetime.value ()));
- 
-       /* plus is maybe not allowed at end - spec defines it weirdly, so
-        * assuming allowed at end */
-       if (lexer.peek_token ()->get_id () != PLUS)
- 	break;
- 
-       lexer.skip_token ();
-     }
- 
-   lifetime_bounds.shrink_to_fit ();
-   return lifetime_bounds;
- }
- 
- // Parses lifetime bounds, with added check for ending token.
- template <typename ManagedTokenSource>
- template <typename EndTokenPred>
- std::vector<AST::Lifetime>
- Parser<ManagedTokenSource>::parse_lifetime_bounds (EndTokenPred is_end_token)
- {
-   std::vector<AST::Lifetime> lifetime_bounds;
- 
-   while (!is_end_token (lexer.peek_token ()->get_id ()))
-     {
-       auto lifetime = parse_lifetime (false);
- 
-       if (!lifetime)
- 	{
- 	  /* TODO: is it worth throwing away all lifetime bound info just
- 	   * because one failed? */
- 	  Error error (lexer.peek_token ()->get_locus (),
- 		       "failed to parse lifetime in lifetime bounds");
- 	  add_error (std::move (error));
- 
- 	  return {};
- 	}
- 
-       lifetime_bounds.push_back (std::move (lifetime.value ()));
- 
-       /* plus is maybe not allowed at end - spec defines it weirdly, so
-        * assuming allowed at end */
-       if (lexer.peek_token ()->get_id () != PLUS)
- 	break;
- 
-       lexer.skip_token ();
-     }
- 
-   lifetime_bounds.shrink_to_fit ();
-   return lifetime_bounds;
- }
- 
- /* Parses a lifetime token (named, 'static, or '_). Also handles lifetime not
-  * existing. */
- template <typename ManagedTokenSource>
- tl::expected<AST::Lifetime, ParseLifetimeError>
- Parser<ManagedTokenSource>::parse_lifetime (bool allow_elided)
- {
-   const_TokenPtr lifetime_tok = lexer.peek_token ();
-   if (lifetime_tok->get_id () != LIFETIME)
-     {
-       if (allow_elided)
- 	{
- 	  return AST::Lifetime::elided ();
- 	}
-       else
- 	{
- 	  return tl::make_unexpected<ParseLifetimeError> ({});
- 	}
-     }
-   lexer.skip_token ();
- 
-   return lifetime_from_token (lifetime_tok);
- }
- 
- template <typename ManagedTokenSource>
- AST::Lifetime
- Parser<ManagedTokenSource>::lifetime_from_token (const_TokenPtr tok)
- {
-   location_t locus = tok->get_locus ();
-   std::string lifetime_ident = tok->get_str ();
- 
-   if (lifetime_ident == "static")
-     {
-       return AST::Lifetime (AST::Lifetime::STATIC, "", locus);
-     }
-   else if (lifetime_ident == "_")
-     {
-       // Explicitly and implicitly elided lifetimes follow the same rules.
-       return AST::Lifetime (AST::Lifetime::WILDCARD, "", locus);
-     }
-   else
-     {
-       return AST::Lifetime (AST::Lifetime::NAMED, std::move (lifetime_ident),
- 			    locus);
-     }
- }
- 
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::ExternalTypeItem>
- Parser<ManagedTokenSource>::parse_external_type_item (AST::Visibility vis,
- 						      AST::AttrVec outer_attrs)
- {
-   location_t locus = lexer.peek_token ()->get_locus ();
-   skip_token (TYPE);
- 
-   const_TokenPtr alias_name_tok = expect_token (IDENTIFIER);
-   if (alias_name_tok == nullptr)
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "could not parse identifier in external opaque type");
-       add_error (std::move (error));
- 
-       skip_after_semicolon ();
-       return nullptr;
-     }
- 
-   if (!skip_token (SEMICOLON))
-     return nullptr;
- 
-   return std::unique_ptr<AST::ExternalTypeItem> (
-     new AST::ExternalTypeItem (alias_name_tok->get_str (), std::move (vis),
- 			       std::move (outer_attrs), std::move (locus)));
- }
- 
- // Parses a "type alias" (typedef) item.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::TypeAlias>
- Parser<ManagedTokenSource>::parse_type_alias (AST::Visibility vis,
- 					      AST::AttrVec outer_attrs)
- {
-   location_t locus = lexer.peek_token ()->get_locus ();
-   skip_token (TYPE);
- 
-   // TODO: use this token for identifier when finished that
-   const_TokenPtr alias_name_tok = expect_token (IDENTIFIER);
-   if (alias_name_tok == nullptr)
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "could not parse identifier in type alias");
-       add_error (std::move (error));
- 
-       skip_after_semicolon ();
-       return nullptr;
-     }
-   Identifier alias_name{alias_name_tok};
- 
-   // parse generic params, which may not exist
-   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
-     = parse_generic_params_in_angles ();
- 
-   // parse where clause, which may not exist
-   AST::WhereClause where_clause = parse_where_clause ();
- 
-   if (!skip_token (EQUAL))
-     {
-       skip_after_semicolon ();
-       return nullptr;
-     }
- 
-   std::unique_ptr<AST::Type> type_to_alias = parse_type ();
- 
-   if (!skip_token (SEMICOLON))
-     {
-       // should be skipping past this, not the next line
-       return nullptr;
-     }
- 
-   return std::unique_ptr<AST::TypeAlias> (
-     new AST::TypeAlias (std::move (alias_name), std::move (generic_params),
- 			std::move (where_clause), std::move (type_to_alias),
- 			std::move (vis), std::move (outer_attrs), locus));
- }
- 
- // Parse a struct item AST node.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::Struct>
- Parser<ManagedTokenSource>::parse_struct (AST::Visibility vis,
- 					  AST::AttrVec outer_attrs)
- {
-   /* TODO: determine best way to parse the proper struct vs tuple struct -
-    * share most of initial constructs so lookahead might be impossible, and if
-    * not probably too expensive. Best way is probably unified parsing for the
-    * initial parts and then pass them in as params to more derived functions.
-    * Alternatively, just parse everything in this one function - do this if
-    * function not too long. */
- 
-   /* Proper struct <- 'struct' IDENTIFIER generic_params? where_clause? ( '{'
-    * struct_fields? '}' | ';' ) */
-   /* Tuple struct <- 'struct' IDENTIFIER generic_params? '(' tuple_fields? ')'
-    * where_clause? ';' */
-   location_t locus = lexer.peek_token ()->get_locus ();
-   skip_token (STRUCT_KW);
- 
-   // parse struct name
-   const_TokenPtr name_tok = expect_token (IDENTIFIER);
-   if (name_tok == nullptr)
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "could not parse struct or tuple struct identifier");
-       add_error (std::move (error));
- 
-       // skip after somewhere?
-       return nullptr;
-     }
-   Identifier struct_name{name_tok};
- 
-   // parse generic params, which may or may not exist
-   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
-     = parse_generic_params_in_angles ();
- 
-   // branch on next token - determines whether proper struct or tuple struct
-   if (lexer.peek_token ()->get_id () == LEFT_PAREN)
-     {
-       // tuple struct
- 
-       // skip left parenthesis
-       lexer.skip_token ();
- 
-       // parse tuple fields
-       std::vector<AST::TupleField> tuple_fields;
-       // Might be empty tuple for unit tuple struct.
-       if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
- 	tuple_fields = std::vector<AST::TupleField> ();
-       else
- 	tuple_fields = parse_tuple_fields ();
- 
-       // tuple parameters must have closing parenthesis
-       if (!skip_token (RIGHT_PAREN))
- 	{
- 	  skip_after_semicolon ();
- 	  return nullptr;
- 	}
- 
-       // parse where clause, which is optional
-       AST::WhereClause where_clause = parse_where_clause ();
- 
-       if (!skip_token (SEMICOLON))
- 	{
- 	  // can't skip after semicolon because it's meant to be here
- 	  return nullptr;
- 	}
- 
-       return std::unique_ptr<AST::TupleStruct> (
- 	new AST::TupleStruct (std::move (tuple_fields), std::move (struct_name),
- 			      std::move (generic_params),
- 			      std::move (where_clause), std::move (vis),
- 			      std::move (outer_attrs), locus));
-     }
- 
-   // assume it is a proper struct being parsed and continue outside of switch
-   // - label only here to suppress warning
- 
-   // parse where clause, which is optional
-   AST::WhereClause where_clause = parse_where_clause ();
- 
-   // branch on next token - determines whether struct is a unit struct
-   const_TokenPtr t = lexer.peek_token ();
-   switch (t->get_id ())
-     {
-     case LEFT_CURLY:
-       {
- 	// struct with body
- 
- 	// skip curly bracket
- 	lexer.skip_token ();
- 
- 	// parse struct fields, if any
- 	std::vector<AST::StructField> struct_fields
- 	  = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
- 
- 	if (!skip_token (RIGHT_CURLY))
- 	  {
- 	    // skip somewhere?
- 	    return nullptr;
- 	  }
- 
- 	return std::unique_ptr<AST::StructStruct> (new AST::StructStruct (
- 	  std::move (struct_fields), std::move (struct_name),
- 	  std::move (generic_params), std::move (where_clause), false,
- 	  std::move (vis), std::move (outer_attrs), locus));
-       }
-     case SEMICOLON:
-       // unit struct declaration
- 
-       lexer.skip_token ();
- 
-       return std::unique_ptr<AST::StructStruct> (
- 	new AST::StructStruct (std::move (struct_name),
- 			       std::move (generic_params),
- 			       std::move (where_clause), std::move (vis),
- 			       std::move (outer_attrs), locus));
-     default:
-       add_error (Error (t->get_locus (),
- 			"unexpected token %qs in struct declaration",
- 			t->get_token_description ()));
- 
-       // skip somewhere?
-       return nullptr;
-     }
- }
- 
- // Parses struct fields in struct declarations.
- template <typename ManagedTokenSource>
- std::vector<AST::StructField>
- Parser<ManagedTokenSource>::parse_struct_fields ()
- {
-   std::vector<AST::StructField> fields;
- 
-   AST::StructField initial_field = parse_struct_field ();
- 
-   // Return empty field list if no field there
-   if (initial_field.is_error ())
-     return fields;
- 
-   fields.push_back (std::move (initial_field));
- 
-   while (lexer.peek_token ()->get_id () == COMMA)
-     {
-       lexer.skip_token ();
- 
-       AST::StructField field = parse_struct_field ();
- 
-       if (field.is_error ())
- 	{
- 	  // would occur with trailing comma, so allowed
- 	  break;
- 	}
- 
-       fields.push_back (std::move (field));
-     }
- 
-   fields.shrink_to_fit ();
-   return fields;
-   // TODO: template if possible (parse_non_ptr_seq)
- }
- 
- // Parses struct fields in struct declarations.
- template <typename ManagedTokenSource>
- template <typename EndTokenPred>
- std::vector<AST::StructField>
- Parser<ManagedTokenSource>::parse_struct_fields (EndTokenPred is_end_tok)
- {
-   std::vector<AST::StructField> fields;
- 
-   AST::StructField initial_field = parse_struct_field ();
- 
-   // Return empty field list if no field there
-   if (initial_field.is_error ())
-     return fields;
- 
-   fields.push_back (std::move (initial_field));
- 
-   while (lexer.peek_token ()->get_id () == COMMA)
-     {
-       lexer.skip_token ();
- 
-       if (is_end_tok (lexer.peek_token ()->get_id ()))
- 	break;
- 
-       AST::StructField field = parse_struct_field ();
-       if (field.is_error ())
- 	{
- 	  /* TODO: should every field be ditched just because one couldn't be
- 	   * parsed? */
- 	  Error error (lexer.peek_token ()->get_locus (),
- 		       "failed to parse struct field in struct fields");
- 	  add_error (std::move (error));
- 
- 	  return {};
- 	}
- 
-       fields.push_back (std::move (field));
-     }
- 
-   fields.shrink_to_fit ();
-   return fields;
-   // TODO: template if possible (parse_non_ptr_seq)
- }
- 
- // Parses a single struct field (in a struct definition). Does not parse
- // commas.
- template <typename ManagedTokenSource>
- AST::StructField
- Parser<ManagedTokenSource>::parse_struct_field ()
- {
-   // parse outer attributes, if they exist
-   AST::AttrVec outer_attrs = parse_outer_attributes ();
- 
-   // parse visibility, if it exists
-   AST::Visibility vis = parse_visibility ();
- 
-   location_t locus = lexer.peek_token ()->get_locus ();
- 
-   // parse field name
-   const_TokenPtr field_name_tok = lexer.peek_token ();
-   if (field_name_tok->get_id () != IDENTIFIER)
-     {
-       // if not identifier, assumes there is no struct field and exits - not
-       // necessarily error
-       return AST::StructField::create_error ();
-     }
-   Identifier field_name{field_name_tok};
-   lexer.skip_token ();
- 
-   if (!skip_token (COLON))
-     {
-       // skip after somewhere?
-       return AST::StructField::create_error ();
-     }
- 
-   // parse field type - this is required
-   std::unique_ptr<AST::Type> field_type = parse_type ();
-   if (field_type == nullptr)
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "could not parse type in struct field definition");
-       add_error (std::move (error));
- 
-       // skip after somewhere
-       return AST::StructField::create_error ();
-     }
- 
-   return AST::StructField (std::move (field_name), std::move (field_type),
- 			   std::move (vis), locus, std::move (outer_attrs));
- }
- 
- // Parses tuple fields in tuple/tuple struct declarations.
- template <typename ManagedTokenSource>
- std::vector<AST::TupleField>
- Parser<ManagedTokenSource>::parse_tuple_fields ()
- {
-   std::vector<AST::TupleField> fields;
- 
-   AST::TupleField initial_field = parse_tuple_field ();
- 
-   // Return empty field list if no field there
-   if (initial_field.is_error ())
-     {
-       return fields;
-     }
- 
-   fields.push_back (std::move (initial_field));
- 
-   // maybe think of a better control structure here - do-while with an initial
-   // error state? basically, loop through field list until can't find any more
-   // params HACK: all current syntax uses of tuple fields have them ending
-   // with a right paren token
-   const_TokenPtr t = lexer.peek_token ();
-   while (t->get_id () == COMMA)
-     {
-       // skip comma if applies - e.g. trailing comma
-       lexer.skip_token ();
- 
-       // break out due to right paren if it exists
-       if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
- 	{
- 	  break;
- 	}
- 
-       AST::TupleField field = parse_tuple_field ();
-       if (field.is_error ())
- 	{
- 	  Error error (lexer.peek_token ()->get_locus (),
- 		       "failed to parse tuple field in tuple fields");
- 	  add_error (std::move (error));
- 
- 	  return std::vector<AST::TupleField> ();
- 	}
- 
-       fields.push_back (std::move (field));
- 
-       t = lexer.peek_token ();
-     }
- 
-   fields.shrink_to_fit ();
-   return fields;
- 
-   // TODO: this shares basically all code with function params and struct
-   // fields
-   // - templates?
- }
- 
- /* Parses a single tuple struct field in a tuple struct definition. Does not
-  * parse commas. */
- template <typename ManagedTokenSource>
- AST::TupleField
- Parser<ManagedTokenSource>::parse_tuple_field ()
- {
-   // parse outer attributes if they exist
-   AST::AttrVec outer_attrs = parse_outer_attributes ();
- 
-   // parse visibility if it exists
-   AST::Visibility vis = parse_visibility ();
- 
-   location_t locus = lexer.peek_token ()->get_locus ();
- 
-   // parse type, which is required
-   std::unique_ptr<AST::Type> field_type = parse_type ();
-   if (field_type == nullptr)
-     {
-       // error if null
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "could not parse type in tuple struct field");
-       add_error (std::move (error));
- 
-       // skip after something
-       return AST::TupleField::create_error ();
-     }
- 
-   return AST::TupleField (std::move (field_type), std::move (vis), locus,
- 			  std::move (outer_attrs));
- }
- 
- // Parses a Rust "enum" tagged union item definition.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::Enum>
- Parser<ManagedTokenSource>::parse_enum (AST::Visibility vis,
- 					AST::AttrVec outer_attrs)
- {
-   location_t locus = lexer.peek_token ()->get_locus ();
-   skip_token (ENUM_KW);
- 
-   // parse enum name
-   const_TokenPtr enum_name_tok = expect_token (IDENTIFIER);
-   if (enum_name_tok == nullptr)
-     return nullptr;
- 
-   Identifier enum_name = {enum_name_tok};
- 
-   // parse generic params (of enum container, not enum variants) if they exist
-   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
-     = parse_generic_params_in_angles ();
- 
-   // parse where clause if it exists
-   AST::WhereClause where_clause = parse_where_clause ();
- 
-   if (!skip_token (LEFT_CURLY))
-     {
-       skip_after_end_block ();
-       return nullptr;
-     }
- 
-   // parse actual enum variant definitions
-   std::vector<std::unique_ptr<AST::EnumItem>> enum_items
-     = parse_enum_items ([] (TokenId id) { return id == RIGHT_CURLY; });
- 
-   if (!skip_token (RIGHT_CURLY))
-     {
-       skip_after_end_block ();
-       return nullptr;
-     }
- 
-   return std::unique_ptr<AST::Enum> (
-     new AST::Enum (std::move (enum_name), std::move (vis),
- 		   std::move (generic_params), std::move (where_clause),
- 		   std::move (enum_items), std::move (outer_attrs), locus));
- }
- 
- // Parses the enum variants inside an enum definiton.
- template <typename ManagedTokenSource>
- std::vector<std::unique_ptr<AST::EnumItem>>
- Parser<ManagedTokenSource>::parse_enum_items ()
- {
-   std::vector<std::unique_ptr<AST::EnumItem>> items;
- 
-   std::unique_ptr<AST::EnumItem> initial_item = parse_enum_item ();
- 
-   // Return empty item list if no field there
-   if (initial_item == nullptr)
-     return items;
- 
-   items.push_back (std::move (initial_item));
- 
-   while (lexer.peek_token ()->get_id () == COMMA)
-     {
-       lexer.skip_token ();
- 
-       std::unique_ptr<AST::EnumItem> item = parse_enum_item ();
-       if (item == nullptr)
- 	{
- 	  // this would occur with a trailing comma, which is allowed
- 	  break;
- 	}
- 
-       items.push_back (std::move (item));
-     }
- 
-   items.shrink_to_fit ();
-   return items;
- 
-   /* TODO: use template if doable (parse_non_ptr_sequence) */
- }
- 
- // Parses the enum variants inside an enum definiton.
- template <typename ManagedTokenSource>
- template <typename EndTokenPred>
- std::vector<std::unique_ptr<AST::EnumItem>>
- Parser<ManagedTokenSource>::parse_enum_items (EndTokenPred is_end_tok)
- {
-   std::vector<std::unique_ptr<AST::EnumItem>> items;
- 
-   std::unique_ptr<AST::EnumItem> initial_item = parse_enum_item ();
- 
-   // Return empty item list if no field there
-   if (initial_item == nullptr)
-     return items;
- 
-   items.push_back (std::move (initial_item));
- 
-   while (lexer.peek_token ()->get_id () == COMMA)
-     {
-       lexer.skip_token ();
- 
-       if (is_end_tok (lexer.peek_token ()->get_id ()))
- 	break;
- 
-       std::unique_ptr<AST::EnumItem> item = parse_enum_item ();
-       if (item == nullptr)
- 	{
- 	  /* TODO should this ignore all successfully parsed enum items just
- 	   * because one failed? */
- 	  Error error (lexer.peek_token ()->get_locus (),
- 		       "failed to parse enum item in enum items");
- 	  add_error (std::move (error));
- 
- 	  return {};
- 	}
- 
-       items.push_back (std::move (item));
-     }
- 
-   items.shrink_to_fit ();
-   return items;
- 
-   /* TODO: use template if doable (parse_non_ptr_sequence) */
- }
- 
- /* Parses a single enum variant item in an enum definition. Does not parse
-  * commas. */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::EnumItem>
- Parser<ManagedTokenSource>::parse_enum_item ()
- {
-   // parse outer attributes if they exist
-   AST::AttrVec outer_attrs = parse_outer_attributes ();
- 
-   // parse visibility, which may or may not exist
-   AST::Visibility vis = parse_visibility ();
- 
-   // parse name for enum item, which is required
-   const_TokenPtr item_name_tok = lexer.peek_token ();
-   if (item_name_tok->get_id () != IDENTIFIER)
-     {
-       // this may not be an error but it means there is no enum item here
-       return nullptr;
-     }
-   lexer.skip_token ();
-   Identifier item_name{item_name_tok};
- 
-   // branch based on next token
-   const_TokenPtr t = lexer.peek_token ();
-   switch (t->get_id ())
-     {
-     case LEFT_PAREN:
-       {
- 	// tuple enum item
- 	lexer.skip_token ();
- 
- 	std::vector<AST::TupleField> tuple_fields;
- 	// Might be empty tuple for unit tuple enum variant.
- 	if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
- 	  tuple_fields = std::vector<AST::TupleField> ();
- 	else
- 	  tuple_fields = parse_tuple_fields ();
- 
- 	if (!skip_token (RIGHT_PAREN))
- 	  {
- 	    // skip after somewhere
- 	    return nullptr;
- 	  }
- 
- 	return std::unique_ptr<AST::EnumItemTuple> (new AST::EnumItemTuple (
- 	  std::move (item_name), std::move (vis), std::move (tuple_fields),
- 	  std::move (outer_attrs), item_name_tok->get_locus ()));
-       }
-     case LEFT_CURLY:
-       {
- 	// struct enum item
- 	lexer.skip_token ();
- 
- 	std::vector<AST::StructField> struct_fields
- 	  = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
- 
- 	if (!skip_token (RIGHT_CURLY))
- 	  {
- 	    // skip after somewhere
- 	    return nullptr;
- 	  }
- 
- 	return std::unique_ptr<AST::EnumItemStruct> (new AST::EnumItemStruct (
- 	  std::move (item_name), std::move (vis), std::move (struct_fields),
- 	  std::move (outer_attrs), item_name_tok->get_locus ()));
-       }
-     case EQUAL:
-       {
- 	// discriminant enum item
- 	lexer.skip_token ();
- 
- 	std::unique_ptr<AST::Expr> discriminant_expr = parse_expr ();
- 
- 	return std::unique_ptr<AST::EnumItemDiscriminant> (
- 	  new AST::EnumItemDiscriminant (std::move (item_name), std::move (vis),
- 					 std::move (discriminant_expr),
- 					 std::move (outer_attrs),
- 					 item_name_tok->get_locus ()));
-       }
-     default:
-       // regular enum with just an identifier
-       return std::unique_ptr<AST::EnumItem> (
- 	new AST::EnumItem (std::move (item_name), std::move (vis),
- 			   std::move (outer_attrs),
- 			   item_name_tok->get_locus ()));
-     }
- }
- 
- // Parses a C-style (and C-compat) untagged union declaration.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::Union>
- Parser<ManagedTokenSource>::parse_union (AST::Visibility vis,
- 					 AST::AttrVec outer_attrs)
- {
-   /* hack - "weak keyword" by finding identifier called "union" (lookahead in
-    * item switch) */
-   const_TokenPtr union_keyword = expect_token (IDENTIFIER);
-   rust_assert (union_keyword->get_str () == Values::WeakKeywords::UNION);
-   location_t locus = union_keyword->get_locus ();
- 
-   // parse actual union name
-   const_TokenPtr union_name_tok = expect_token (IDENTIFIER);
-   if (union_name_tok == nullptr)
-     {
-       skip_after_next_block ();
-       return nullptr;
-     }
-   Identifier union_name{union_name_tok};
- 
-   // parse optional generic parameters
-   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
-     = parse_generic_params_in_angles ();
- 
-   // parse optional where clause
-   AST::WhereClause where_clause = parse_where_clause ();
- 
-   if (!skip_token (LEFT_CURLY))
-     {
-       skip_after_end_block ();
-       return nullptr;
-     }
- 
-   /* parse union inner items as "struct fields" because hey, syntax reuse.
-    * Spec said so. */
-   std::vector<AST::StructField> union_fields
-     = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
- 
-   if (!skip_token (RIGHT_CURLY))
-     {
-       // skip after somewhere
-       return nullptr;
-     }
- 
-   return std::unique_ptr<AST::Union> (
-     new AST::Union (std::move (union_name), std::move (vis),
- 		    std::move (generic_params), std::move (where_clause),
- 		    std::move (union_fields), std::move (outer_attrs), locus));
- }
- 
- /* Parses a "constant item" (compile-time constant to maybe "inline"
-  * throughout the program - like constexpr). */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::ConstantItem>
- Parser<ManagedTokenSource>::parse_const_item (AST::Visibility vis,
- 					      AST::AttrVec outer_attrs)
- {
-   location_t locus = lexer.peek_token ()->get_locus ();
-   skip_token (CONST);
- 
-   /* get constant identifier - this is either a proper identifier or the _
-    * wildcard */
-   const_TokenPtr ident_tok = lexer.peek_token ();
-   // make default identifier the underscore wildcard one
-   std::string ident (Values::Keywords::UNDERSCORE);
-   switch (ident_tok->get_id ())
-     {
-     case IDENTIFIER:
-       ident = ident_tok->get_str ();
-       lexer.skip_token ();
-       break;
-     case UNDERSCORE:
-       // do nothing - identifier is already "_"
-       lexer.skip_token ();
-       break;
-     default:
-       add_error (
- 	Error (ident_tok->get_locus (),
- 	       "expected item name (identifier or %<_%>) in constant item "
- 	       "declaration - found %qs",
- 	       ident_tok->get_token_description ()));
- 
-       skip_after_semicolon ();
-       return nullptr;
-     }
- 
-   if (!skip_token (COLON))
-     {
-       skip_after_semicolon ();
-       return nullptr;
-     }
- 
-   // parse constant type (required)
-   std::unique_ptr<AST::Type> type = parse_type ();
- 
-   // A const with no given expression value
-   if (lexer.peek_token ()->get_id () == SEMICOLON)
-     {
-       lexer.skip_token ();
-       return std::unique_ptr<AST::ConstantItem> (
- 	new AST::ConstantItem (std::move (ident), std::move (vis),
- 			       std::move (type), std::move (outer_attrs),
- 			       locus));
-     }
- 
-   if (!skip_token (EQUAL))
-     {
-       skip_after_semicolon ();
-       return nullptr;
-     }
- 
-   // parse constant expression (required)
-   std::unique_ptr<AST::Expr> expr = parse_expr ();
- 
-   if (!skip_token (SEMICOLON))
-     {
-       // skip somewhere?
-       return nullptr;
-     }
- 
-   return std::unique_ptr<AST::ConstantItem> (
-     new AST::ConstantItem (std::move (ident), std::move (vis), std::move (type),
- 			   std::move (expr), std::move (outer_attrs), locus));
- }
- 
- // Parses a "static item" (static storage item, with 'static lifetime).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::StaticItem>
- Parser<ManagedTokenSource>::parse_static_item (AST::Visibility vis,
- 					       AST::AttrVec outer_attrs)
- {
-   location_t locus = lexer.peek_token ()->get_locus ();
-   skip_token (STATIC_KW);
- 
-   // determine whether static item is mutable
-   bool is_mut = false;
-   if (lexer.peek_token ()->get_id () == MUT)
-     {
-       is_mut = true;
-       lexer.skip_token ();
-     }
- 
-   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
-   if (ident_tok == nullptr)
-     return nullptr;
- 
-   Identifier ident{ident_tok};
- 
-   if (!skip_token (COLON))
-     {
-       skip_after_semicolon ();
-       return nullptr;
-     }
- 
-   // parse static item type (required)
-   std::unique_ptr<AST::Type> type = parse_type ();
- 
-   if (!skip_token (EQUAL))
-     {
-       skip_after_semicolon ();
-       return nullptr;
-     }
- 
-   // parse static item expression (required)
-   std::unique_ptr<AST::Expr> expr = parse_expr ();
- 
-   if (!skip_token (SEMICOLON))
-     {
-       // skip after somewhere
-       return nullptr;
-     }
- 
-   return std::unique_ptr<AST::StaticItem> (
-     new AST::StaticItem (std::move (ident), is_mut, std::move (type),
- 			 std::move (expr), std::move (vis),
- 			 std::move (outer_attrs), locus));
- }
- 
- // Parses a trait definition item, including unsafe ones.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::Trait>
- Parser<ManagedTokenSource>::parse_trait (AST::Visibility vis,
- 					 AST::AttrVec outer_attrs)
- {
-   location_t locus = lexer.peek_token ()->get_locus ();
-   bool is_unsafe = false;
-   bool is_auto_trait = false;
- 
-   if (lexer.peek_token ()->get_id () == UNSAFE)
-     {
-       is_unsafe = true;
-       lexer.skip_token ();
-     }
- 
-   if (lexer.peek_token ()->get_id () == AUTO)
-     {
-       is_auto_trait = true;
-       lexer.skip_token ();
-     }
- 
-   skip_token (TRAIT);
- 
-   // parse trait name
-   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
-   if (ident_tok == nullptr)
-     return nullptr;
- 
-   Identifier ident{ident_tok};
- 
-   // parse generic parameters (if they exist)
-   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
-     = parse_generic_params_in_angles ();
- 
-   // create placeholder type param bounds in case they don't exist
-   std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
- 
-   // parse type param bounds (if they exist)
-   if (lexer.peek_token ()->get_id () == COLON)
-     {
-       lexer.skip_token ();
- 
-       type_param_bounds = parse_type_param_bounds (
- 	[] (TokenId id) { return id == WHERE || id == LEFT_CURLY; });
-       // type_param_bounds = parse_type_param_bounds ();
-     }
- 
-   // parse where clause (if it exists)
-   AST::WhereClause where_clause = parse_where_clause ();
- 
-   if (!skip_token (LEFT_CURLY))
-     {
-       skip_after_end_block ();
-       return nullptr;
-     }
- 
-   // parse inner attrs (if they exist)
-   AST::AttrVec inner_attrs = parse_inner_attributes ();
- 
-   // parse trait items
-   std::vector<std::unique_ptr<AST::AssociatedItem>> trait_items;
- 
-   const_TokenPtr t = lexer.peek_token ();
-   while (t->get_id () != RIGHT_CURLY)
-     {
-       std::unique_ptr<AST::AssociatedItem> trait_item = parse_trait_item ();
- 
-       if (trait_item == nullptr)
- 	{
- 	  Error error (lexer.peek_token ()->get_locus (),
- 		       "failed to parse trait item in trait");
- 	  add_error (std::move (error));
- 
- 	  return nullptr;
- 	}
-       trait_items.push_back (std::move (trait_item));
- 
-       t = lexer.peek_token ();
-     }
- 
-   if (!skip_token (RIGHT_CURLY))
-     {
-       // skip after something
-       return nullptr;
-     }
- 
-   trait_items.shrink_to_fit ();
-   return std::unique_ptr<AST::Trait> (
-     new AST::Trait (std::move (ident), is_unsafe, is_auto_trait,
- 		    std::move (generic_params), std::move (type_param_bounds),
- 		    std::move (where_clause), std::move (trait_items),
- 		    std::move (vis), std::move (outer_attrs),
- 		    std::move (inner_attrs), locus));
- }
- 
- // Parses a trait item used inside traits (not trait, the Item).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::AssociatedItem>
- Parser<ManagedTokenSource>::parse_trait_item ()
- {
-   // parse outer attributes (if they exist)
-   AST::AttrVec outer_attrs = parse_outer_attributes ();
- 
-   AST::Visibility vis = parse_visibility ();
- 
-   // lookahead to determine what type of trait item to parse
-   const_TokenPtr tok = lexer.peek_token ();
-   switch (tok->get_id ())
-     {
-     case SUPER:
-     case SELF:
-     case CRATE:
-     case DOLLAR_SIGN:
-       // these seem to be SimplePath tokens, so this is a macro invocation
-       // semi
-       return parse_macro_invocation_semi (std::move (outer_attrs));
-     case IDENTIFIER:
-       if (lexer.peek_token ()->get_str () == Values::WeakKeywords::DEFAULT)
- 	return parse_function (std::move (vis), std::move (outer_attrs));
-       else
- 	return parse_macro_invocation_semi (std::move (outer_attrs));
-     case TYPE:
-       return parse_trait_type (std::move (outer_attrs), vis);
-     case CONST:
-       // disambiguate with function qualifier
-       if (lexer.peek_token (1)->get_id () == IDENTIFIER)
- 	{
- 	  return parse_trait_const (std::move (outer_attrs));
- 	}
-       // else, fallthrough to function
-       // TODO: find out how to disable gcc "implicit fallthrough" error
-       gcc_fallthrough ();
-     case ASYNC:
-     case UNSAFE:
-     case EXTERN_KW:
-     case FN_KW:
-       return parse_function (std::move (vis), std::move (outer_attrs));
-     default:
-       break;
-     }
-   add_error (Error (tok->get_locus (),
- 		    "unrecognised token %qs for item in trait",
- 		    tok->get_token_description ()));
-   // skip?
-   return nullptr;
- }
- 
- // Parse a typedef trait item.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::TraitItemType>
- Parser<ManagedTokenSource>::parse_trait_type (AST::AttrVec outer_attrs,
- 					      AST::Visibility vis)
- {
-   location_t locus = lexer.peek_token ()->get_locus ();
-   skip_token (TYPE);
- 
-   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
-   if (ident_tok == nullptr)
-     return nullptr;
- 
-   Identifier ident{ident_tok};
- 
-   // Parse optional generic parameters for GATs (Generic Associated Types)
-   std::vector<std::unique_ptr<AST::GenericParam>> generic_params;
-   if (lexer.peek_token ()->get_id () == LEFT_ANGLE)
-     {
-       generic_params = parse_generic_params_in_angles ();
-     }
- 
-   std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
- 
-   // parse optional colon
-   if (lexer.peek_token ()->get_id () == COLON)
-     {
-       lexer.skip_token ();
- 
-       // parse optional type param bounds
-       bounds
- 	= parse_type_param_bounds ([] (TokenId id) { return id == SEMICOLON; });
-       // bounds = parse_type_param_bounds ();
-     }
- 
-   if (!skip_token (SEMICOLON))
-     {
-       // skip?
-       return nullptr;
-     }
- 
-   return std::unique_ptr<AST::TraitItemType> (
-     new AST::TraitItemType (std::move (ident), std::move (generic_params),
- 			    std::move (bounds), std::move (outer_attrs), vis,
- 			    locus));
- }
- 
- // Parses a constant trait item.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::ConstantItem>
- Parser<ManagedTokenSource>::parse_trait_const (AST::AttrVec outer_attrs)
- {
-   location_t locus = lexer.peek_token ()->get_locus ();
-   skip_token (CONST);
- 
-   // parse constant item name
-   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
-   if (ident_tok == nullptr)
-     return nullptr;
- 
-   Identifier ident{ident_tok};
- 
-   if (!skip_token (COLON))
-     {
-       skip_after_semicolon ();
-       return nullptr;
-     }
- 
-   // parse constant trait item type
-   std::unique_ptr<AST::Type> type = parse_type ();
- 
-   // parse constant trait body expression, if it exists
-   std::unique_ptr<AST::Expr> const_body = nullptr;
-   if (lexer.peek_token ()->get_id () == EQUAL)
-     {
-       lexer.skip_token ();
- 
-       // expression must exist, so parse it
-       const_body = parse_expr ();
-     }
- 
-   if (!skip_token (SEMICOLON))
-     {
-       // skip after something?
-       return nullptr;
-     }
- 
-   return std::unique_ptr<AST::ConstantItem> (new AST::ConstantItem (
-     std::move (ident), AST::Visibility::create_private (), std::move (type),
-     std::move (const_body), std::move (outer_attrs), locus));
- }
- 
- /* Parses a struct "impl" item (both inherent impl and trait impl can be
-  * parsed here), */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::Impl>
- Parser<ManagedTokenSource>::parse_impl (AST::Visibility vis,
- 					AST::AttrVec outer_attrs)
- {
-   /* Note that only trait impls are allowed to be unsafe. So if unsafe, it
-    * must be a trait impl. However, this isn't enough for full disambiguation,
-    * so don't branch here. */
-   location_t locus = lexer.peek_token ()->get_locus ();
-   bool is_unsafe = false;
-   if (lexer.peek_token ()->get_id () == UNSAFE)
-     {
-       lexer.skip_token ();
-       is_unsafe = true;
-     }
- 
-   if (!skip_token (IMPL))
-     {
-       skip_after_next_block ();
-       return nullptr;
-     }
- 
-   // parse generic params (shared by trait and inherent impls)
-   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
-     = parse_generic_params_in_angles ();
- 
-   // Again, trait impl-only feature, but optional one, so can be used for
-   // branching yet.
-   bool has_exclam = false;
-   if (lexer.peek_token ()->get_id () == EXCLAM)
-     {
-       lexer.skip_token ();
-       has_exclam = true;
-     }
- 
-   /* FIXME: code that doesn't look shit for TypePath. Also, make sure this
-    * doesn't parse too much and not work. */
-   AST::TypePath type_path = parse_type_path ();
-   if (type_path.is_error () || lexer.peek_token ()->get_id () != FOR)
-     {
-       /* cannot parse type path (or not for token next, at least), so must be
-        * inherent impl */
- 
-       // hacky conversion of TypePath stack object to Type pointer
-       std::unique_ptr<AST::Type> type = nullptr;
-       if (!type_path.is_error ())
- 	type = std::unique_ptr<AST::TypePath> (
- 	  new AST::TypePath (std::move (type_path)));
-       else
- 	type = parse_type ();
- 
-       // Type is required, so error if null
-       if (type == nullptr)
- 	{
- 	  Error error (lexer.peek_token ()->get_locus (),
- 		       "could not parse type in inherent impl");
- 	  add_error (std::move (error));
- 
- 	  skip_after_next_block ();
- 	  return nullptr;
- 	}
- 
-       // parse optional where clause
-       AST::WhereClause where_clause = parse_where_clause ();
- 
-       if (!skip_token (LEFT_CURLY))
- 	{
- 	  // TODO: does this still skip properly?
- 	  skip_after_end_block ();
- 	  return nullptr;
- 	}
- 
-       // parse inner attributes (optional)
-       AST::AttrVec inner_attrs = parse_inner_attributes ();
- 
-       // parse inherent impl items
-       std::vector<std::unique_ptr<AST::AssociatedItem>> impl_items;
- 
-       const_TokenPtr t = lexer.peek_token ();
-       while (t->get_id () != RIGHT_CURLY)
- 	{
- 	  std::unique_ptr<AST::AssociatedItem> impl_item
- 	    = parse_inherent_impl_item ();
- 
- 	  if (impl_item == nullptr)
- 	    {
- 	      Error error (
- 		lexer.peek_token ()->get_locus (),
- 		"failed to parse inherent impl item in inherent impl");
- 	      add_error (std::move (error));
- 
- 	      return nullptr;
- 	    }
- 
- 	  impl_items.push_back (std::move (impl_item));
- 
- 	  t = lexer.peek_token ();
- 	}
- 
-       if (!skip_token (RIGHT_CURLY))
- 	{
- 	  // skip somewhere
- 	  return nullptr;
- 	}
- 
-       // DEBUG
-       rust_debug ("successfully parsed inherent impl");
- 
-       impl_items.shrink_to_fit ();
- 
-       return std::unique_ptr<AST::InherentImpl> (new AST::InherentImpl (
- 	std::move (impl_items), std::move (generic_params), std::move (type),
- 	std::move (where_clause), std::move (vis), std::move (inner_attrs),
- 	std::move (outer_attrs), locus));
-     }
-   else
-     {
-       // type path must both be valid and next token is for, so trait impl
-       if (!skip_token (FOR))
- 	{
- 	  skip_after_next_block ();
- 	  return nullptr;
- 	}
- 
-       // parse type
-       std::unique_ptr<AST::Type> type = parse_type ();
-       // ensure type is included as it is required
-       if (type == nullptr)
- 	{
- 	  Error error (lexer.peek_token ()->get_locus (),
- 		       "could not parse type in trait impl");
- 	  add_error (std::move (error));
- 
- 	  skip_after_next_block ();
- 	  return nullptr;
- 	}
- 
-       // parse optional where clause
-       AST::WhereClause where_clause = parse_where_clause ();
- 
-       if (!skip_token (LEFT_CURLY))
- 	{
- 	  // TODO: does this still skip properly?
- 	  skip_after_end_block ();
- 	  return nullptr;
- 	}
- 
-       // parse inner attributes (optional)
-       AST::AttrVec inner_attrs = parse_inner_attributes ();
- 
-       // parse trait impl items
-       std::vector<std::unique_ptr<AST::AssociatedItem>> impl_items;
- 
-       const_TokenPtr t = lexer.peek_token ();
-       while (t->get_id () != RIGHT_CURLY)
- 	{
- 	  std::unique_ptr<AST::AssociatedItem> impl_item
- 	    = parse_trait_impl_item ();
- 
- 	  if (impl_item == nullptr)
- 	    {
- 	      Error error (lexer.peek_token ()->get_locus (),
- 			   "failed to parse trait impl item in trait impl");
- 	      add_error (std::move (error));
- 
- 	      return nullptr;
- 	    }
- 
- 	  impl_items.push_back (std::move (impl_item));
- 
- 	  t = lexer.peek_token ();
- 
- 	  // DEBUG
- 	  rust_debug ("successfully parsed a trait impl item");
- 	}
-       // DEBUG
-       rust_debug ("successfully finished trait impl items");
- 
-       if (!skip_token (RIGHT_CURLY))
- 	{
- 	  // skip somewhere
- 	  return nullptr;
- 	}
- 
-       // DEBUG
-       rust_debug ("successfully parsed trait impl");
- 
-       impl_items.shrink_to_fit ();
- 
-       return std::unique_ptr<AST::TraitImpl> (
- 	new AST::TraitImpl (std::move (type_path), is_unsafe, has_exclam,
- 			    std::move (impl_items), std::move (generic_params),
- 			    std::move (type), std::move (where_clause),
- 			    std::move (vis), std::move (inner_attrs),
- 			    std::move (outer_attrs), locus));
-     }
- }
- 
- // Parses a single inherent impl item (item inside an inherent impl block).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::AssociatedItem>
- Parser<ManagedTokenSource>::parse_inherent_impl_item ()
- {
-   // parse outer attributes (if they exist)
-   AST::AttrVec outer_attrs = parse_outer_attributes ();
- 
-   // TODO: cleanup - currently an unreadable mess
- 
-   // branch on next token:
-   const_TokenPtr t = lexer.peek_token ();
-   switch (t->get_id ())
-     {
-     case IDENTIFIER:
-       // FIXME: Arthur: Do we need to some lookahead here?
-       return parse_macro_invocation_semi (outer_attrs);
-     case SUPER:
-     case SELF:
-     case CRATE:
-     case PUB:
-       {
- 	// visibility, so not a macro invocation semi - must be constant,
- 	// function, or method
- 	AST::Visibility vis = parse_visibility ();
- 
- 	// TODO: is a recursive call to parse_inherent_impl_item better?
- 	switch (lexer.peek_token ()->get_id ())
- 	  {
- 	  case EXTERN_KW:
- 	  case UNSAFE:
- 	  case FN_KW:
- 	    // function or method
- 	    return parse_inherent_impl_function_or_method (std::move (vis),
- 							   std::move (
- 							     outer_attrs));
- 	  case CONST:
- 	    // lookahead to resolve production - could be function/method or
- 	    // const item
- 	    t = lexer.peek_token (1);
- 
- 	    switch (t->get_id ())
- 	      {
- 	      case IDENTIFIER:
- 	      case UNDERSCORE:
- 		return parse_const_item (std::move (vis),
- 					 std::move (outer_attrs));
- 	      case UNSAFE:
- 	      case EXTERN_KW:
- 	      case FN_KW:
- 		return parse_inherent_impl_function_or_method (std::move (vis),
- 							       std::move (
- 								 outer_attrs));
- 	      default:
- 		add_error (Error (t->get_locus (),
- 				  "unexpected token %qs in some sort of const "
- 				  "item in inherent impl",
- 				  t->get_token_description ()));
- 
- 		lexer.skip_token (1); // TODO: is this right thing to do?
- 		return nullptr;
- 	      }
- 	  default:
- 	    add_error (
- 	      Error (t->get_locus (),
- 		     "unrecognised token %qs for item in inherent impl",
- 		     t->get_token_description ()));
- 	    // skip?
- 	    return nullptr;
- 	  }
-       }
-     case ASYNC:
-     case EXTERN_KW:
-     case UNSAFE:
-     case FN_KW:
-       // function or method
-       return parse_inherent_impl_function_or_method (
- 	AST::Visibility::create_private (), std::move (outer_attrs));
-     case CONST:
-       /* lookahead to resolve production - could be function/method or const
-        * item */
-       t = lexer.peek_token (1);
- 
-       switch (t->get_id ())
- 	{
- 	case IDENTIFIER:
- 	case UNDERSCORE:
- 	  return parse_const_item (AST::Visibility::create_private (),
- 				   std::move (outer_attrs));
- 	case UNSAFE:
- 	case EXTERN_KW:
- 	case FN_KW:
- 	  return parse_inherent_impl_function_or_method (
- 	    AST::Visibility::create_private (), std::move (outer_attrs));
- 	default:
- 	  add_error (Error (t->get_locus (),
- 			    "unexpected token %qs in some sort of const item "
- 			    "in inherent impl",
- 			    t->get_token_description ()));
- 
- 	  lexer.skip_token (1); // TODO: is this right thing to do?
- 	  return nullptr;
- 	}
-       rust_unreachable ();
-     default:
-       add_error (Error (t->get_locus (),
- 			"unrecognised token %qs for item in inherent impl",
- 			t->get_token_description ()));
- 
-       // skip?
-       return nullptr;
-     }
- }
- 
- /* For internal use only by parse_inherent_impl_item() - splits giant method
-  * into smaller ones and prevents duplication of logic. Strictly, this parses
-  * a function or method item inside an inherent impl item block. */
- // TODO: make this a templated function with "return type" as type param -
- // InherentImplItem is this specialisation of the template while TraitImplItem
- // will be the other.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::AssociatedItem>
- Parser<ManagedTokenSource>::parse_inherent_impl_function_or_method (
-   AST::Visibility vis, AST::AttrVec outer_attrs)
- {
-   location_t locus = lexer.peek_token ()->get_locus ();
-   // parse function or method qualifiers
-   AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
- 
-   skip_token (FN_KW);
- 
-   // parse function or method name
-   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
-   if (ident_tok == nullptr)
-     return nullptr;
- 
-   Identifier ident{ident_tok};
- 
-   // parse generic params
-   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
-     = parse_generic_params_in_angles ();
- 
-   if (!skip_token (LEFT_PAREN))
-     {
-       // skip after somewhere?
-       return nullptr;
-     }
- 
-   // now for function vs method disambiguation - method has opening "self"
-   // param
-   auto initial_param = parse_self_param ();
- 
-   if (!initial_param.has_value ()
-       && initial_param.error () != ParseSelfError::NOT_SELF)
-     return nullptr;
- 
-   /* FIXME: ensure that self param doesn't accidently consume tokens for a
-    * function one idea is to lookahead up to 4 tokens to see whether self is
-    * one of them */
-   bool is_method = false;
-   if (initial_param.has_value ())
-     {
-       if ((*initial_param)->is_self ())
- 	is_method = true;
- 
-       /* skip comma so function and method regular params can be parsed in
-        * same way */
-       if (lexer.peek_token ()->get_id () == COMMA)
- 	lexer.skip_token ();
-     }
- 
-   // parse trait function params
-   std::vector<std::unique_ptr<AST::Param>> function_params
-     = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
- 
-   if (initial_param.has_value ())
-     function_params.insert (function_params.begin (),
- 			    std::move (*initial_param));
- 
-   if (!skip_token (RIGHT_PAREN))
-     {
-       skip_after_end_block ();
-       return nullptr;
-     }
- 
-   // parse return type (optional)
-   std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
- 
-   // parse where clause (optional)
-   AST::WhereClause where_clause = parse_where_clause ();
- 
-   tl::optional<std::unique_ptr<AST::BlockExpr>> body = tl::nullopt;
-   if (lexer.peek_token ()->get_id () == SEMICOLON)
-     lexer.skip_token ();
-   else
-     {
-       auto result = parse_block_expr ();
- 
-       if (result == nullptr)
- 	{
- 	  Error error (
- 	    lexer.peek_token ()->get_locus (),
- 	    "could not parse definition in inherent impl %s definition",
- 	    is_method ? "method" : "function");
- 	  add_error (std::move (error));
- 
- 	  skip_after_end_block ();
- 	  return nullptr;
- 	}
-       body = std::move (result);
-     }
- 
-   return std::unique_ptr<AST::Function> (
-     new AST::Function (std::move (ident), std::move (qualifiers),
- 		       std::move (generic_params), std::move (function_params),
- 		       std::move (return_type), std::move (where_clause),
- 		       std::move (body), std::move (vis),
- 		       std::move (outer_attrs), locus));
- }
- 
- // Parses a single trait impl item (item inside a trait impl block).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::AssociatedItem>
- Parser<ManagedTokenSource>::parse_trait_impl_item ()
- {
-   // parse outer attributes (if they exist)
-   AST::AttrVec outer_attrs = parse_outer_attributes ();
- 
-   auto visibility = AST::Visibility::create_private ();
-   if (lexer.peek_token ()->get_id () == PUB)
-     visibility = parse_visibility ();
- 
-   // branch on next token:
-   const_TokenPtr t = lexer.peek_token ();
-   switch (t->get_id ())
-     {
-     case SUPER:
-     case SELF:
-     case CRATE:
-     case DOLLAR_SIGN:
-       // these seem to be SimplePath tokens, so this is a macro invocation
-       // semi
-       return parse_macro_invocation_semi (std::move (outer_attrs));
-     case IDENTIFIER:
-       if (lexer.peek_token ()->get_str () == Values::WeakKeywords::DEFAULT)
- 	return parse_trait_impl_function_or_method (visibility,
- 						    std::move (outer_attrs));
-       else
- 	return parse_macro_invocation_semi (std::move (outer_attrs));
-     case TYPE:
-       return parse_type_alias (visibility, std::move (outer_attrs));
-     case EXTERN_KW:
-     case UNSAFE:
-     case FN_KW:
-       // function or method
-       return parse_trait_impl_function_or_method (visibility,
- 						  std::move (outer_attrs));
-     case ASYNC:
-       return parse_async_item (visibility, std::move (outer_attrs));
-     case CONST:
-       // lookahead to resolve production - could be function/method or const
-       // item
-       t = lexer.peek_token (1);
- 
-       switch (t->get_id ())
- 	{
- 	case IDENTIFIER:
- 	case UNDERSCORE:
- 	  return parse_const_item (visibility, std::move (outer_attrs));
- 	case UNSAFE:
- 	case EXTERN_KW:
- 	case FN_KW:
- 	  return parse_trait_impl_function_or_method (visibility,
- 						      std::move (outer_attrs));
- 	default:
- 	  add_error (Error (
- 	    t->get_locus (),
- 	    "unexpected token %qs in some sort of const item in trait impl",
- 	    t->get_token_description ()));
- 
- 	  lexer.skip_token (1); // TODO: is this right thing to do?
- 	  return nullptr;
- 	}
-       rust_unreachable ();
-     default:
-       break;
-     }
-   add_error (Error (t->get_locus (),
- 		    "unrecognised token %qs for item in trait impl",
- 		    t->get_token_description ()));
- 
-   // skip?
-   return nullptr;
- }
- 
- /* For internal use only by parse_trait_impl_item() - splits giant method into
-  * smaller ones and prevents duplication of logic. Strictly, this parses a
-  * function or method item inside a trait impl item block. */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::AssociatedItem>
- Parser<ManagedTokenSource>::parse_trait_impl_function_or_method (
-   AST::Visibility vis, AST::AttrVec outer_attrs)
- {
-   // this shares virtually all logic with
-   // parse_inherent_impl_function_or_method
-   // - template?
-   location_t locus = lexer.peek_token ()->get_locus ();
- 
-   auto is_default = false;
-   auto t = lexer.peek_token ();
-   if (t->get_id () == IDENTIFIER
-       && t->get_str () == Values::WeakKeywords::DEFAULT)
-     {
-       is_default = true;
-       lexer.skip_token ();
-     }
- 
-   // parse function or method qualifiers
-   AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
- 
-   skip_token (FN_KW);
- 
-   // parse function or method name
-   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
-   if (ident_tok == nullptr)
-     {
-       return nullptr;
-     }
-   Identifier ident{ident_tok};
- 
-   // DEBUG:
-   rust_debug (
-     "about to start parsing generic params in trait impl function or method");
- 
-   // parse generic params
-   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
-     = parse_generic_params_in_angles ();
- 
-   // DEBUG:
-   rust_debug (
-     "finished parsing generic params in trait impl function or method");
- 
-   if (!skip_token (LEFT_PAREN))
-     {
-       // skip after somewhere?
-       return nullptr;
-     }
- 
-   // now for function vs method disambiguation - method has opening "self"
-   // param
-   auto initial_param = parse_self_param ();
- 
-   if (!initial_param.has_value ()
-       && initial_param.error () != ParseSelfError::NOT_SELF)
-     return nullptr;
- 
-   // FIXME: ensure that self param doesn't accidently consume tokens for a
-   // function
-   bool is_method = false;
-   if (initial_param.has_value ())
-     {
-       if ((*initial_param)->is_self ())
- 	is_method = true;
- 
-       // skip comma so function and method regular params can be parsed in
-       // same way
-       if (lexer.peek_token ()->get_id () == COMMA)
- 	{
- 	  lexer.skip_token ();
- 	}
- 
-       // DEBUG
-       rust_debug ("successfully parsed self param in method trait impl item");
-     }
- 
-   // DEBUG
-   rust_debug (
-     "started to parse function params in function or method trait impl item");
- 
-   // parse trait function params (only if next token isn't right paren)
-   std::vector<std::unique_ptr<AST::Param>> function_params;
-   if (lexer.peek_token ()->get_id () != RIGHT_PAREN)
-     {
-       function_params
- 	= parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
- 
-       if (function_params.empty ())
- 	{
- 	  Error error (
- 	    lexer.peek_token ()->get_locus (),
- 	    "failed to parse function params in trait impl %s definition",
- 	    is_method ? "method" : "function");
- 	  add_error (std::move (error));
- 
- 	  skip_after_next_block ();
- 	  return nullptr;
- 	}
-     }
- 
-   if (initial_param.has_value ())
-     function_params.insert (function_params.begin (),
- 			    std::move (*initial_param));
- 
-   // DEBUG
-   rust_debug ("successfully parsed function params in function or method "
- 	      "trait impl item");
- 
-   if (!skip_token (RIGHT_PAREN))
-     {
-       skip_after_next_block ();
-       return nullptr;
-     }
- 
-   // parse return type (optional)
-   std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
- 
-   // DEBUG
-   rust_debug (
-     "successfully parsed return type in function or method trait impl item");
- 
-   // parse where clause (optional)
-   AST::WhereClause where_clause = parse_where_clause ();
- 
-   // DEBUG
-   rust_debug (
-     "successfully parsed where clause in function or method trait impl item");
- 
-   // parse function definition (in block) - semicolon not allowed
-   tl::optional<std::unique_ptr<AST::BlockExpr>> body = tl::nullopt;
- 
-   if (lexer.peek_token ()->get_id () == SEMICOLON)
-     lexer.skip_token ();
-   else
-     {
-       auto result = parse_block_expr ();
-       if (result == nullptr)
- 	{
- 	  Error error (lexer.peek_token ()->get_locus (),
- 		       "could not parse definition in trait impl %s definition",
- 		       is_method ? "method" : "function");
- 	  add_error (std::move (error));
- 
- 	  skip_after_end_block ();
- 	  return nullptr;
- 	}
-       body = std::move (result);
-     }
- 
-   return std::unique_ptr<AST::Function> (
-     new AST::Function (std::move (ident), std::move (qualifiers),
- 		       std::move (generic_params), std::move (function_params),
- 		       std::move (return_type), std::move (where_clause),
- 		       std::move (body), std::move (vis),
- 		       std::move (outer_attrs), locus, is_default));
- }
- 
- // Parses an extern block of declarations.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::ExternBlock>
- Parser<ManagedTokenSource>::parse_extern_block (AST::Visibility vis,
- 						AST::AttrVec outer_attrs)
- {
-   location_t locus = lexer.peek_token ()->get_locus ();
-   skip_token (EXTERN_KW);
- 
-   // detect optional abi name
-   std::string abi;
-   const_TokenPtr next_tok = lexer.peek_token ();
-   if (next_tok->get_id () == STRING_LITERAL)
-     {
-       lexer.skip_token ();
-       abi = next_tok->get_str ();
-     }
- 
-   if (!skip_token (LEFT_CURLY))
-     {
-       skip_after_end_block ();
-       return nullptr;
-     }
- 
-   AST::AttrVec inner_attrs = parse_inner_attributes ();
- 
-   // parse declarations inside extern block
-   std::vector<std::unique_ptr<AST::ExternalItem>> extern_items;
- 
-   const_TokenPtr t = lexer.peek_token ();
-   while (t->get_id () != RIGHT_CURLY)
-     {
-       std::unique_ptr<AST::ExternalItem> extern_item = parse_external_item ();
- 
-       if (extern_item == nullptr)
- 	{
- 	  Error error (t->get_locus (),
- 		       "failed to parse external item despite not reaching "
- 		       "end of extern block");
- 	  add_error (std::move (error));
- 
- 	  return nullptr;
- 	}
- 
-       extern_items.push_back (std::move (extern_item));
- 
-       t = lexer.peek_token ();
-     }
- 
-   if (!skip_token (RIGHT_CURLY))
-     {
-       // skip somewhere
-       return nullptr;
-     }
- 
-   extern_items.shrink_to_fit ();
- 
-   return std::unique_ptr<AST::ExternBlock> (
-     new AST::ExternBlock (std::move (abi), std::move (extern_items),
- 			  std::move (vis), std::move (inner_attrs),
- 			  std::move (outer_attrs), locus));
- }
- 
- // Parses a single extern block item (static or function declaration).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::ExternalItem>
- Parser<ManagedTokenSource>::parse_external_item ()
- {
-   // parse optional outer attributes
-   AST::AttrVec outer_attrs = parse_outer_attributes ();
- 
-   location_t locus = lexer.peek_token ()->get_locus ();
- 
-   // parse optional visibility
-   AST::Visibility vis = parse_visibility ();
- 
-   const_TokenPtr t = lexer.peek_token ();
-   switch (t->get_id ())
-     {
-     case IDENTIFIER:
-       return parse_macro_invocation_semi (outer_attrs);
-     case STATIC_KW:
-       {
- 	// parse extern static item
- 	lexer.skip_token ();
- 
- 	// parse mut (optional)
- 	bool has_mut = false;
- 	if (lexer.peek_token ()->get_id () == MUT)
- 	  {
- 	    lexer.skip_token ();
- 	    has_mut = true;
- 	  }
- 
- 	// parse identifier
- 	const_TokenPtr ident_tok = expect_token (IDENTIFIER);
- 	if (ident_tok == nullptr)
- 	  {
- 	    skip_after_semicolon ();
- 	    return nullptr;
- 	  }
- 	Identifier ident{ident_tok};
- 
- 	if (!skip_token (COLON))
- 	  {
- 	    skip_after_semicolon ();
- 	    return nullptr;
- 	  }
- 
- 	// parse type (required)
- 	std::unique_ptr<AST::Type> type = parse_type ();
- 	if (type == nullptr)
- 	  {
- 	    Error error (lexer.peek_token ()->get_locus (),
- 			 "failed to parse type in external static item");
- 	    add_error (std::move (error));
- 
- 	    skip_after_semicolon ();
- 	    return nullptr;
- 	  }
- 
- 	if (!skip_token (SEMICOLON))
- 	  {
- 	    // skip after somewhere?
- 	    return nullptr;
- 	  }
- 
- 	return std::unique_ptr<AST::ExternalStaticItem> (
- 	  new AST::ExternalStaticItem (std::move (ident), std::move (type),
- 				       has_mut, std::move (vis),
- 				       std::move (outer_attrs), locus));
-       }
-     case FN_KW:
-       return parse_function (std::move (vis), std::move (outer_attrs), true);
- 
-     case TYPE:
-       return parse_external_type_item (std::move (vis),
- 				       std::move (outer_attrs));
-     default:
-       // error
-       add_error (
- 	Error (t->get_locus (),
- 	       "unrecognised token %qs in extern block item declaration",
- 	       t->get_token_description ()));
- 
-       skip_after_semicolon ();
-       return nullptr;
-     }
- }
- 
- // Parses a statement (will further disambiguate any statement).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::Stmt>
- Parser<ManagedTokenSource>::parse_stmt (ParseRestrictions restrictions)
- {
-   // quick exit for empty statement
-   // FIXME: Can we have empty statements without semicolons? Just nothing?
-   const_TokenPtr t = lexer.peek_token ();
-   if (t->get_id () == SEMICOLON)
-     {
-       lexer.skip_token ();
-       return std::unique_ptr<AST::EmptyStmt> (
- 	new AST::EmptyStmt (t->get_locus ()));
-     }
- 
-   // parse outer attributes
-   AST::AttrVec outer_attrs = parse_outer_attributes ();
- 
-   // parsing this will be annoying because of the many different possibilities
-   /* best may be just to copy paste in parse_item switch, and failing that try
-    * to parse outer attributes, and then pass them in to either a let
-    * statement or (fallback) expression statement. */
-   // FIXME: think of a way to do this without such a large switch?
-   t = lexer.peek_token ();
-   switch (t->get_id ())
-     {
-     case LET:
-       // let statement
-       return parse_let_stmt (std::move (outer_attrs), restrictions);
-     case PUB:
-     case MOD:
-     case EXTERN_KW:
-     case USE:
-     case FN_KW:
-     case TYPE:
-     case STRUCT_KW:
-     case ENUM_KW:
-     case CONST:
-     case STATIC_KW:
-     case AUTO:
-     case TRAIT:
-     case IMPL:
-     case MACRO:
-     /* TODO: implement union keyword but not really because of
-      * context-dependence crappy hack way to parse a union written below to
-      * separate it from the good code. */
-     // case UNION:
-     case UNSAFE: // maybe - unsafe traits are a thing
-       /* if any of these (should be all possible VisItem prefixes), parse a
-        * VisItem can't parse item because would require reparsing outer
-        * attributes */
-       // may also be unsafe block
-       if (lexer.peek_token (1)->get_id () == LEFT_CURLY)
- 	{
- 	  return parse_expr_stmt (std::move (outer_attrs), restrictions);
- 	}
-       else
- 	{
- 	  return parse_vis_item (std::move (outer_attrs));
- 	}
-       break;
-     // crappy hack to do union "keyword"
-     case IDENTIFIER:
-       if (t->get_str () == Values::WeakKeywords::UNION
- 	  && lexer.peek_token (1)->get_id () == IDENTIFIER)
- 	{
- 	  return parse_vis_item (std::move (outer_attrs));
- 	  // or should this go straight to parsing union?
- 	}
-       else if (is_macro_rules_def (t))
- 	{
- 	  // macro_rules! macro item
- 	  return parse_macro_rules_def (std::move (outer_attrs));
- 	}
-       gcc_fallthrough ();
-       // TODO: find out how to disable gcc "implicit fallthrough" warning
-     default:
-       // fallback: expression statement
-       return parse_expr_stmt (std::move (outer_attrs), restrictions);
-       break;
-     }
- }
- 
- // Parses a let statement.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::LetStmt>
- Parser<ManagedTokenSource>::parse_let_stmt (AST::AttrVec outer_attrs,
- 					    ParseRestrictions restrictions)
- {
-   location_t locus = lexer.peek_token ()->get_locus ();
-   skip_token (LET);
- 
-   // parse pattern (required)
-   std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
-   if (pattern == nullptr)
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "failed to parse pattern in let statement");
-       add_error (std::move (error));
- 
-       skip_after_semicolon ();
-       return nullptr;
-     }
- 
-   // parse type declaration (optional)
-   std::unique_ptr<AST::Type> type = nullptr;
-   if (lexer.peek_token ()->get_id () == COLON)
-     {
-       // must have a type declaration
-       lexer.skip_token ();
- 
-       type = parse_type ();
-       if (type == nullptr)
- 	{
- 	  Error error (lexer.peek_token ()->get_locus (),
- 		       "failed to parse type in let statement");
- 	  add_error (std::move (error));
- 
- 	  skip_after_semicolon ();
- 	  return nullptr;
- 	}
-     }
- 
-   // parse expression to set variable to (optional)
-   std::unique_ptr<AST::Expr> expr = nullptr;
-   if (lexer.peek_token ()->get_id () == EQUAL)
-     {
-       // must have an expression
-       lexer.skip_token ();
- 
-       expr = parse_expr ();
-       if (expr == nullptr)
- 	{
- 	  skip_after_semicolon ();
- 	  return nullptr;
- 	}
-     }
- 
-   tl::optional<std::unique_ptr<AST::Expr>> else_expr = tl::nullopt;
-   if (maybe_skip_token (ELSE))
-     else_expr = parse_block_expr ();
- 
-   if (restrictions.consume_semi)
-     {
-       // `stmt` macro variables are parsed without a semicolon, but should be
-       // parsed as a full statement when interpolated. This should be handled
-       // by having the interpolated statement be distinguishable from normal
-       // tokens, e.g. by NT tokens.
-       if (restrictions.allow_close_after_expr_stmt)
- 	maybe_skip_token (SEMICOLON);
-       else if (!skip_token (SEMICOLON))
- 	return nullptr;
-     }
- 
-   return std::unique_ptr<AST::LetStmt> (
-     new AST::LetStmt (std::move (pattern), std::move (expr), std::move (type),
- 		      std::move (else_expr), std::move (outer_attrs), locus));
- }
- 
- // Parses a type path.
- template <typename ManagedTokenSource>
- AST::TypePath
- Parser<ManagedTokenSource>::parse_type_path ()
- {
-   bool has_opening_scope_resolution = false;
-   location_t locus = lexer.peek_token ()->get_locus ();
-   if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION)
-     {
-       has_opening_scope_resolution = true;
-       lexer.skip_token ();
-     }
- 
-   // create segment vector
-   std::vector<std::unique_ptr<AST::TypePathSegment>> segments;
- 
-   // parse required initial segment
-   std::unique_ptr<AST::TypePathSegment> initial_segment
-     = parse_type_path_segment ();
-   if (initial_segment == nullptr)
-     {
-       // skip after somewhere?
-       // don't necessarily throw error but yeah
-       return AST::TypePath::create_error ();
-     }
-   segments.push_back (std::move (initial_segment));
- 
-   // parse optional segments (as long as scope resolution operator exists)
-   const_TokenPtr t = lexer.peek_token ();
-   while (t->get_id () == SCOPE_RESOLUTION)
-     {
-       // skip scope resolution operator
-       lexer.skip_token ();
- 
-       // parse the actual segment - it is an error if it doesn't exist now
-       std::unique_ptr<AST::TypePathSegment> segment
- 	= parse_type_path_segment ();
-       if (segment == nullptr)
- 	{
- 	  // skip after somewhere?
- 	  Error error (t->get_locus (), "could not parse type path segment");
- 	  add_error (std::move (error));
- 
- 	  return AST::TypePath::create_error ();
- 	}
- 
-       segments.push_back (std::move (segment));
- 
-       t = lexer.peek_token ();
-     }
- 
-   segments.shrink_to_fit ();
- 
-   return AST::TypePath (std::move (segments), locus,
- 			has_opening_scope_resolution);
- }
- 
- template <typename ManagedTokenSource>
- tl::optional<AST::GenericArg>
- Parser<ManagedTokenSource>::parse_generic_arg ()
- {
-   auto tok = lexer.peek_token ();
-   std::unique_ptr<AST::Expr> expr = nullptr;
- 
-   switch (tok->get_id ())
-     {
-     case IDENTIFIER:
-       {
- 	// This is a bit of a weird situation: With an identifier token, we
- 	// could either have a valid type or a macro (FIXME: anything else?). So
- 	// we need one bit of lookahead to differentiate if this is really
- 	auto next_tok = lexer.peek_token (1);
- 	if (next_tok->get_id () == LEFT_ANGLE
- 	    || next_tok->get_id () == SCOPE_RESOLUTION
- 	    || next_tok->get_id () == EXCLAM)
- 	  {
- 	    auto type = parse_type ();
- 	    if (type)
- 	      return AST::GenericArg::create_type (std::move (type));
- 	    else
- 	      return tl::nullopt;
- 	  }
- 	else if (next_tok->get_id () == COLON)
- 	  {
- 	    lexer.skip_token (); // skip ident
- 	    lexer.skip_token (); // skip colon
- 
- 	    auto tok = lexer.peek_token ();
- 	    std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
- 	      = parse_type_param_bounds ();
- 
- 	    auto type = std::unique_ptr<AST::TraitObjectType> (
- 	      new AST::TraitObjectType (std::move (bounds), tok->get_locus (),
- 					false));
- 	    if (type)
- 	      return AST::GenericArg::create_type (std::move (type));
- 	    else
- 	      return tl::nullopt;
- 	  }
- 	lexer.skip_token ();
- 	return AST::GenericArg::create_ambiguous (tok->get_str (),
- 						  tok->get_locus ());
-       }
-     case LEFT_CURLY:
-       expr = parse_block_expr ();
-       break;
-     case MINUS:
-     case STRING_LITERAL:
-     case CHAR_LITERAL:
-     case INT_LITERAL:
-     case FLOAT_LITERAL:
-     case TRUE_LITERAL:
-     case FALSE_LITERAL:
-       expr = parse_literal_expr ();
-       break;
-     // FIXME: Because of this, error reporting is garbage for const generic
-     // parameter's default values
-     default:
-       {
- 	auto type = parse_type ();
- 	// FIXME: Find a better way to do this?
- 	if (type)
- 	  return AST::GenericArg::create_type (std::move (type));
- 	else
- 	  return tl::nullopt;
-       }
-     }
- 
-   if (!expr)
-     return tl::nullopt;
- 
-   return AST::GenericArg::create_const (std::move (expr));
- }
- 
- // Parses the generic arguments in each path segment.
- template <typename ManagedTokenSource>
- AST::GenericArgs
- Parser<ManagedTokenSource>::parse_path_generic_args ()
- {
-   if (lexer.peek_token ()->get_id () == LEFT_SHIFT)
-     lexer.split_current_token (LEFT_ANGLE, LEFT_ANGLE);
- 
-   if (!skip_token (LEFT_ANGLE))
-     {
-       // skip after somewhere?
-       return AST::GenericArgs::create_empty ();
-     }
- 
-   // We need to parse all lifetimes, then parse types and const generics in
-   // any order.
- 
-   // try to parse lifetimes first
-   std::vector<AST::Lifetime> lifetime_args;
- 
-   const_TokenPtr t = lexer.peek_token ();
-   location_t locus = t->get_locus ();
-   while (!is_right_angle_tok (t->get_id ()))
-     {
-       auto lifetime = parse_lifetime (false);
-       if (!lifetime)
- 	{
- 	  // not necessarily an error
- 	  break;
- 	}
- 
-       lifetime_args.push_back (std::move (lifetime.value ()));
- 
-       // if next token isn't comma, then it must be end of list
-       if (lexer.peek_token ()->get_id () != COMMA)
- 	{
- 	  break;
- 	}
-       // skip comma
-       lexer.skip_token ();
- 
-       t = lexer.peek_token ();
-     }
- 
-   // try to parse types and const generics second
-   std::vector<AST::GenericArg> generic_args;
- 
-   // TODO: think of better control structure
-   t = lexer.peek_token ();
-   while (!is_right_angle_tok (t->get_id ()))
-     {
-       // FIXME: Is it fine to break if there is one binding? Can't there be
-       // bindings in between types?
- 
-       // ensure not binding being parsed as type accidently
-       if (t->get_id () == IDENTIFIER
- 	  && lexer.peek_token (1)->get_id () == EQUAL)
- 	break;
- 
-       auto arg = parse_generic_arg ();
-       if (arg)
- 	{
- 	  generic_args.emplace_back (std::move (arg.value ()));
- 	}
- 
-       // FIXME: Do we need to break if we encounter an error?
- 
-       // if next token isn't comma, then it must be end of list
-       if (lexer.peek_token ()->get_id () != COMMA)
- 	break;
- 
-       // skip comma
-       lexer.skip_token ();
-       t = lexer.peek_token ();
-     }
- 
-   // try to parse bindings third
-   std::vector<AST::GenericArgsBinding> binding_args;
- 
-   // TODO: think of better control structure
-   t = lexer.peek_token ();
-   while (!is_right_angle_tok (t->get_id ()))
-     {
-       AST::GenericArgsBinding binding = parse_generic_args_binding ();
-       if (binding.is_error ())
- 	{
- 	  // not necessarily an error
- 	  break;
- 	}
- 
-       binding_args.push_back (std::move (binding));
- 
-       // if next token isn't comma, then it must be end of list
-       if (lexer.peek_token ()->get_id () != COMMA)
- 	{
- 	  break;
- 	}
-       // skip comma
-       lexer.skip_token ();
- 
-       t = lexer.peek_token ();
-     }
- 
-   // skip any trailing commas
-   if (lexer.peek_token ()->get_id () == COMMA)
-     lexer.skip_token ();
- 
-   if (!skip_generics_right_angle ())
-     return AST::GenericArgs::create_empty ();
- 
-   lifetime_args.shrink_to_fit ();
-   generic_args.shrink_to_fit ();
-   binding_args.shrink_to_fit ();
- 
-   return AST::GenericArgs (std::move (lifetime_args), std::move (generic_args),
- 			   std::move (binding_args), locus);
- }
- 
- // Parses a binding in a generic args path segment.
- template <typename ManagedTokenSource>
- AST::GenericArgsBinding
- Parser<ManagedTokenSource>::parse_generic_args_binding ()
- {
-   const_TokenPtr ident_tok = lexer.peek_token ();
-   if (ident_tok->get_id () != IDENTIFIER)
-     {
-       // allow non error-inducing use
-       // skip somewhere?
-       return AST::GenericArgsBinding::create_error ();
-     }
-   lexer.skip_token ();
-   Identifier ident{ident_tok};
- 
-   if (!skip_token (EQUAL))
-     {
-       // skip after somewhere?
-       return AST::GenericArgsBinding::create_error ();
-     }
- 
-   // parse type (required)
-   std::unique_ptr<AST::Type> type = parse_type ();
-   if (type == nullptr)
-     {
-       // skip somewhere?
-       return AST::GenericArgsBinding::create_error ();
-     }
- 
-   return AST::GenericArgsBinding (std::move (ident), std::move (type),
- 				  ident_tok->get_locus ());
- }
- 
- /* Parses a single type path segment (not including opening scope resolution,
-  * but includes any internal ones). Includes generic args or type path
-  * functions too. */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::TypePathSegment>
- Parser<ManagedTokenSource>::parse_type_path_segment ()
- {
-   location_t locus = lexer.peek_token ()->get_locus ();
-   // parse ident segment part
-   AST::PathIdentSegment ident_segment = parse_path_ident_segment ();
-   if (ident_segment.is_error ())
-     {
-       // not necessarily an error
-       return nullptr;
-     }
- 
-   /* lookahead to determine if variants exist - only consume scope resolution
-    * then */
-   bool has_separating_scope_resolution = false;
-   const_TokenPtr next = lexer.peek_token (1);
-   if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION
-       && (next->get_id () == LEFT_ANGLE || next->get_id () == LEFT_PAREN))
-     {
-       has_separating_scope_resolution = true;
-       lexer.skip_token ();
-     }
- 
-   // branch into variants on next token
-   const_TokenPtr t = lexer.peek_token ();
-   switch (t->get_id ())
-     {
-     case LEFT_SHIFT:
-     case LEFT_ANGLE:
-       {
- 	// parse generic args
- 	AST::GenericArgs generic_args = parse_path_generic_args ();
- 
- 	return std::unique_ptr<AST::TypePathSegmentGeneric> (
- 	  new AST::TypePathSegmentGeneric (std::move (ident_segment),
- 					   has_separating_scope_resolution,
- 					   std::move (generic_args), locus));
-       }
-     case LEFT_PAREN:
-       {
- 	// parse type path function
- 	AST::TypePathFunction type_path_function
- 	  = parse_type_path_function (locus);
- 
- 	if (type_path_function.is_error ())
- 	  {
- 	    // skip after somewhere?
- 	    return nullptr;
- 	  }
- 
- 	return std::unique_ptr<AST::TypePathSegmentFunction> (
- 	  new AST::TypePathSegmentFunction (std::move (ident_segment),
- 					    has_separating_scope_resolution,
- 					    std::move (type_path_function),
- 					    locus));
-       }
-     default:
-       // neither of them
-       return std::unique_ptr<AST::TypePathSegment> (
- 	new AST::TypePathSegment (std::move (ident_segment),
- 				  has_separating_scope_resolution, locus));
-     }
-   rust_unreachable ();
- }
- 
- // Parses a function call representation inside a type path.
- template <typename ManagedTokenSource>
- AST::TypePathFunction
- Parser<ManagedTokenSource>::parse_type_path_function (location_t id_location)
- {
-   if (!skip_token (LEFT_PAREN))
-     {
-       // skip somewhere?
-       return AST::TypePathFunction::create_error ();
-     }
- 
-   // parse function inputs
-   std::vector<std::unique_ptr<AST::Type>> inputs;
- 
-   while (lexer.peek_token ()->get_id () != RIGHT_PAREN)
-     {
-       std::unique_ptr<AST::Type> type = parse_type ();
-       if (type == nullptr)
- 	{
- 	  /* this is an error as there should've been a ')' there if there
- 	   * wasn't a type */
- 	  Error error (
- 	    lexer.peek_token ()->get_locus (),
- 	    "failed to parse type in parameters of type path function");
- 	  add_error (std::move (error));
- 
- 	  // skip somewhere?
- 	  return AST::TypePathFunction::create_error ();
- 	}
- 
-       inputs.push_back (std::move (type));
- 
-       // skip commas, including trailing commas
-       if (lexer.peek_token ()->get_id () != COMMA)
- 	break;
- 
-       lexer.skip_token ();
-     }
- 
-   if (!skip_token (RIGHT_PAREN))
-     {
-       // skip somewhere?
-       return AST::TypePathFunction::create_error ();
-     }
- 
-   // parse optional return type
-   std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
- 
-   inputs.shrink_to_fit ();
-   return AST::TypePathFunction (std::move (inputs), id_location,
- 				std::move (return_type));
- }
- 
- // Parses a path inside an expression that allows generic arguments.
- template <typename ManagedTokenSource>
- AST::PathInExpression
- Parser<ManagedTokenSource>::parse_path_in_expression ()
- {
-   location_t locus = UNKNOWN_LOCATION;
-   bool has_opening_scope_resolution = false;
-   if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION)
-     {
-       has_opening_scope_resolution = true;
- 
-       locus = lexer.peek_token ()->get_locus ();
- 
-       lexer.skip_token ();
-     }
- 
-   // create segment vector
-   std::vector<AST::PathExprSegment> segments;
- 
-   if (locus == UNKNOWN_LOCATION)
-     {
-       locus = lexer.peek_token ()->get_locus ();
-     }
- 
-   // parse required initial segment
-   AST::PathExprSegment initial_segment = parse_path_expr_segment ();
-   if (initial_segment.is_error ())
-     {
-       // skip after somewhere?
-       // don't necessarily throw error but yeah
-       return AST::PathInExpression::create_error ();
-     }
-   segments.push_back (std::move (initial_segment));
- 
-   // parse optional segments (as long as scope resolution operator exists)
-   const_TokenPtr t = lexer.peek_token ();
-   while (t->get_id () == SCOPE_RESOLUTION)
-     {
-       // skip scope resolution operator
-       lexer.skip_token ();
- 
-       // parse the actual segment - it is an error if it doesn't exist now
-       AST::PathExprSegment segment = parse_path_expr_segment ();
-       if (segment.is_error ())
- 	{
- 	  // skip after somewhere?
- 	  Error error (t->get_locus (),
- 		       "could not parse path expression segment");
- 	  add_error (std::move (error));
- 
- 	  return AST::PathInExpression::create_error ();
- 	}
- 
-       segments.push_back (std::move (segment));
- 
-       t = lexer.peek_token ();
-     }
- 
-   segments.shrink_to_fit ();
- 
-   return AST::PathInExpression (std::move (segments), {}, locus,
- 				has_opening_scope_resolution);
- }
- 
- /* Parses a single path in expression path segment (including generic
-  * arguments). */
- template <typename ManagedTokenSource>
- AST::PathExprSegment
- Parser<ManagedTokenSource>::parse_path_expr_segment ()
- {
-   location_t locus = lexer.peek_token ()->get_locus ();
-   // parse ident segment
-   AST::PathIdentSegment ident = parse_path_ident_segment ();
-   if (ident.is_error ())
-     {
-       // not necessarily an error?
-       return AST::PathExprSegment::create_error ();
-     }
- 
-   // parse generic args (and turbofish), if they exist
-   /* use lookahead to determine if they actually exist (don't want to
-    * accidently parse over next ident segment) */
-   if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION
-       && (lexer.peek_token (1)->get_id () == LEFT_ANGLE
- 	  || lexer.peek_token (1)->get_id () == LEFT_SHIFT))
-     {
-       // skip scope resolution
-       lexer.skip_token ();
- 
-       // Let parse_path_generic_args split "<<" tokens
-       AST::GenericArgs generic_args = parse_path_generic_args ();
- 
-       return AST::PathExprSegment (std::move (ident), locus,
- 				   std::move (generic_args));
-     }
- 
-   // return a generic parameter-less expr segment if not found
-   return AST::PathExprSegment (std::move (ident), locus);
- }
- 
- /* Parses a fully qualified path in expression (i.e. a pattern). FIXME does
-  * not parse outer attrs. */
- template <typename ManagedTokenSource>
- AST::QualifiedPathInExpression
- Parser<ManagedTokenSource>::parse_qualified_path_in_expression (
-   location_t pratt_parsed_loc)
- {
-   /* Note: the Rust grammar is defined in such a way that it is impossible to
-    * determine whether a prospective qualified path is a
-    * QualifiedPathInExpression or QualifiedPathInType in all cases by the
-    * rules themselves (the only possible difference is a TypePathSegment with
-    * function, and lookahead to find this is too difficult). However, as this
-    * is a pattern and QualifiedPathInType is a type, I believe it that their
-    * construction will not be confused (due to rules regarding patterns vs
-    * types).
-    * As such, this function will not attempt to minimise errors created by
-    * their confusion. */
- 
-   // parse the qualified path type (required)
-   AST::QualifiedPathType qual_path_type
-     = parse_qualified_path_type (pratt_parsed_loc);
-   if (qual_path_type.is_error ())
-     {
-       // TODO: should this create a parse error?
-       return AST::QualifiedPathInExpression::create_error ();
-     }
-   location_t locus = qual_path_type.get_locus ();
- 
-   // parse path segments
-   std::vector<AST::PathExprSegment> segments;
- 
-   // parse initial required segment
-   if (!expect_token (SCOPE_RESOLUTION))
-     {
-       // skip after somewhere?
- 
-       return AST::QualifiedPathInExpression::create_error ();
-     }
-   AST::PathExprSegment initial_segment = parse_path_expr_segment ();
-   if (initial_segment.is_error ())
-     {
-       // skip after somewhere?
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "required initial path expression segment in "
- 		   "qualified path in expression could not be parsed");
-       add_error (std::move (error));
- 
-       return AST::QualifiedPathInExpression::create_error ();
-     }
-   segments.push_back (std::move (initial_segment));
- 
-   // parse optional segments (as long as scope resolution operator exists)
-   const_TokenPtr t = lexer.peek_token ();
-   while (t->get_id () == SCOPE_RESOLUTION)
-     {
-       // skip scope resolution operator
-       lexer.skip_token ();
- 
-       // parse the actual segment - it is an error if it doesn't exist now
-       AST::PathExprSegment segment = parse_path_expr_segment ();
-       if (segment.is_error ())
- 	{
- 	  // skip after somewhere?
- 	  Error error (t->get_locus (),
- 		       "could not parse path expression segment in qualified "
- 		       "path in expression");
- 	  add_error (std::move (error));
- 
- 	  return AST::QualifiedPathInExpression::create_error ();
- 	}
- 
-       segments.push_back (std::move (segment));
- 
-       t = lexer.peek_token ();
-     }
- 
-   segments.shrink_to_fit ();
- 
-   // FIXME: outer attr parsing
-   return AST::QualifiedPathInExpression (std::move (qual_path_type),
- 					 std::move (segments), {}, locus);
- }
- 
- // Parses the type syntactical construction at the start of a qualified path.
- template <typename ManagedTokenSource>
- AST::QualifiedPathType
- Parser<ManagedTokenSource>::parse_qualified_path_type (
-   location_t pratt_parsed_loc)
- {
-   location_t locus = pratt_parsed_loc;
-   /* TODO: should this actually be error? is there anywhere where this could
-    * be valid? */
-   if (locus == UNKNOWN_LOCATION)
-     {
-       locus = lexer.peek_token ()->get_locus ();
- 
-       if (lexer.peek_token ()->get_id () == LEFT_SHIFT)
- 	lexer.split_current_token (LEFT_ANGLE, LEFT_ANGLE);
- 
-       // skip after somewhere?
-       if (!skip_token (LEFT_ANGLE))
- 	return AST::QualifiedPathType::create_error ();
-     }
- 
-   // parse type (required)
-   std::unique_ptr<AST::Type> type = parse_type ();
-   if (type == nullptr)
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "could not parse type in qualified path type");
-       add_error (std::move (error));
- 
-       // skip somewhere?
-       return AST::QualifiedPathType::create_error ();
-     }
- 
-   // parse optional as clause
-   AST::TypePath as_type_path = AST::TypePath::create_error ();
-   if (lexer.peek_token ()->get_id () == AS)
-     {
-       lexer.skip_token ();
- 
-       // parse type path, which is required now
-       as_type_path = parse_type_path ();
-       if (as_type_path.is_error ())
- 	{
- 	  Error error (
- 	    lexer.peek_token ()->get_locus (),
- 	    "could not parse type path in as clause in qualified path type");
- 	  add_error (std::move (error));
- 
- 	  // skip somewhere?
- 	  return AST::QualifiedPathType::create_error ();
- 	}
-     }
- 
-   /* NOTE: should actually be a right-angle token, so
-    * skip_generics_right_angle shouldn't be required */
-   if (!skip_token (RIGHT_ANGLE))
-     {
-       // skip after somewhere?
-       return AST::QualifiedPathType::create_error ();
-     }
- 
-   return AST::QualifiedPathType (std::move (type), locus,
- 				 std::move (as_type_path));
- }
- 
- // Parses a fully qualified path in type (i.e. a type).
- template <typename ManagedTokenSource>
- AST::QualifiedPathInType
- Parser<ManagedTokenSource>::parse_qualified_path_in_type ()
- {
-   location_t locus = lexer.peek_token ()->get_locus ();
-   // parse the qualified path type (required)
-   AST::QualifiedPathType qual_path_type = parse_qualified_path_type ();
-   if (qual_path_type.is_error ())
-     {
-       // TODO: should this create a parse error?
-       return AST::QualifiedPathInType::create_error ();
-     }
- 
-   // parse initial required segment
-   if (!expect_token (SCOPE_RESOLUTION))
-     {
-       // skip after somewhere?
- 
-       return AST::QualifiedPathInType::create_error ();
-     }
-   std::unique_ptr<AST::TypePathSegment> initial_segment
-     = parse_type_path_segment ();
-   if (initial_segment == nullptr)
-     {
-       // skip after somewhere?
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "required initial type path segment in qualified path in "
- 		   "type could not be parsed");
-       add_error (std::move (error));
- 
-       return AST::QualifiedPathInType::create_error ();
-     }
- 
-   // parse optional segments (as long as scope resolution operator exists)
-   std::vector<std::unique_ptr<AST::TypePathSegment>> segments;
-   const_TokenPtr t = lexer.peek_token ();
-   while (t->get_id () == SCOPE_RESOLUTION)
-     {
-       // skip scope resolution operator
-       lexer.skip_token ();
- 
-       // parse the actual segment - it is an error if it doesn't exist now
-       std::unique_ptr<AST::TypePathSegment> segment
- 	= parse_type_path_segment ();
-       if (segment == nullptr)
- 	{
- 	  // skip after somewhere?
- 	  Error error (
- 	    t->get_locus (),
- 	    "could not parse type path segment in qualified path in type");
- 	  add_error (std::move (error));
- 
- 	  return AST::QualifiedPathInType::create_error ();
- 	}
- 
-       segments.push_back (std::move (segment));
- 
-       t = lexer.peek_token ();
-     }
- 
-   segments.shrink_to_fit ();
- 
-   return AST::QualifiedPathInType (std::move (qual_path_type),
- 				   std::move (initial_segment),
- 				   std::move (segments), locus);
- }
- 
- // Parses a self param. Also handles self param not existing.
- template <typename ManagedTokenSource>
- tl::expected<std::unique_ptr<AST::Param>, ParseSelfError>
- Parser<ManagedTokenSource>::parse_self_param ()
- {
-   bool has_reference = false;
-   AST::Lifetime lifetime = AST::Lifetime::elided ();
- 
-   location_t locus = lexer.peek_token ()->get_locus ();
- 
-   // TODO: Feels off, find a better way to clearly express this
-   std::vector<std::vector<TokenId>> ptrs
-     = {{ASTERISK, SELF} /* *self */,
-        {ASTERISK, CONST, SELF} /* *const self */,
-        {ASTERISK, MUT, SELF} /* *mut self */};
- 
-   for (auto &s : ptrs)
-     {
-       size_t i = 0;
-       for (i = 0; i < s.size (); i++)
- 	if (lexer.peek_token (i)->get_id () != s[i])
- 	  break;
-       if (i == s.size ())
- 	{
- 	  rust_error_at (lexer.peek_token ()->get_locus (),
- 			 "cannot pass %<self%> by raw pointer");
- 	  return tl::make_unexpected (ParseSelfError::SELF_PTR);
- 	}
-     }
- 
-   // Trying to find those patterns:
-   //
-   // &'lifetime mut self
-   // &'lifetime self
-   // & mut self
-   // & self
-   // mut self
-   // self
-   //
-   // If not found, it is probably a function, exit and let function parsing
-   // handle it.
-   bool is_self = false;
-   for (size_t i = 0; i < 5; i++)
-     if (lexer.peek_token (i)->get_id () == SELF)
-       is_self = true;
- 
-   if (!is_self)
-     return tl::make_unexpected (ParseSelfError::NOT_SELF);
- 
-   // test if self is a reference parameter
-   if (lexer.peek_token ()->get_id () == AMP)
-     {
-       has_reference = true;
-       lexer.skip_token ();
- 
-       // now test whether it has a lifetime
-       if (lexer.peek_token ()->get_id () == LIFETIME)
- 	{
- 	  // something went wrong somehow
- 	  if (auto parsed_lifetime = parse_lifetime (true))
- 	    {
- 	      lifetime = parsed_lifetime.value ();
- 	    }
- 	  else
- 	    {
- 	      Error error (lexer.peek_token ()->get_locus (),
- 			   "failed to parse lifetime in self param");
- 	      add_error (std::move (error));
- 
- 	      // skip after somewhere?
- 	      return tl::make_unexpected (ParseSelfError::PARSING);
- 	    }
- 	}
-     }
- 
-   // test for mut
-   bool has_mut = false;
-   if (lexer.peek_token ()->get_id () == MUT)
-     {
-       has_mut = true;
-       lexer.skip_token ();
-     }
- 
-   // skip self token
-   const_TokenPtr self_tok = lexer.peek_token ();
-   if (self_tok->get_id () != SELF)
-     {
-       // skip after somewhere?
-       return tl::make_unexpected (ParseSelfError::NOT_SELF);
-     }
-   lexer.skip_token ();
- 
-   // parse optional type
-   std::unique_ptr<AST::Type> type = nullptr;
-   if (lexer.peek_token ()->get_id () == COLON)
-     {
-       lexer.skip_token ();
- 
-       // type is now required
-       type = parse_type ();
-       if (type == nullptr)
- 	{
- 	  Error error (lexer.peek_token ()->get_locus (),
- 		       "could not parse type in self param");
- 	  add_error (std::move (error));
- 
- 	  // skip after somewhere?
- 	  return tl::make_unexpected (ParseSelfError::PARSING);
- 	}
-     }
- 
-   // ensure that cannot have both type and reference
-   if (type != nullptr && has_reference)
-     {
-       Error error (
- 	lexer.peek_token ()->get_locus (),
- 	"cannot have both a reference and a type specified in a self param");
-       add_error (std::move (error));
- 
-       // skip after somewhere?
-       return tl::make_unexpected (ParseSelfError::PARSING);
-     }
- 
-   if (has_reference)
-     {
-       return std::make_unique<AST::SelfParam> (std::move (lifetime), has_mut,
- 					       locus);
-     }
-   else
-     {
-       // note that type may be nullptr here and that's fine
-       return std::make_unique<AST::SelfParam> (std::move (type), has_mut,
- 					       locus);
-     }
- }
- 
- /* Parses an expression or macro statement. */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::Stmt>
- Parser<ManagedTokenSource>::parse_expr_stmt (AST::AttrVec outer_attrs,
- 					     ParseRestrictions restrictions)
- {
-   location_t locus = lexer.peek_token ()->get_locus ();
- 
-   std::unique_ptr<AST::Expr> expr;
- 
-   switch (lexer.peek_token ()->get_id ())
-     {
-     case IDENTIFIER:
-     case CRATE:
-     case SUPER:
-     case SELF:
-     case SELF_ALIAS:
-     case DOLLAR_SIGN:
-     case SCOPE_RESOLUTION:
-       {
- 	AST::PathInExpression path = parse_path_in_expression ();
- 	std::unique_ptr<AST::Expr> null_denotation;
- 
- 	if (lexer.peek_token ()->get_id () == EXCLAM)
- 	  {
- 	    std::unique_ptr<AST::MacroInvocation> invoc
- 	      = parse_macro_invocation_partial (std::move (path),
- 						std::move (outer_attrs));
- 
- 	    if (restrictions.consume_semi && maybe_skip_token (SEMICOLON))
- 	      {
- 		invoc->add_semicolon ();
- 		// Macro invocation with semicolon.
- 		return invoc;
- 	      }
- 
- 	    TokenId after_macro = lexer.peek_token ()->get_id ();
- 
- 	    if (restrictions.allow_close_after_expr_stmt
- 		&& (after_macro == RIGHT_PAREN || after_macro == RIGHT_CURLY
- 		    || after_macro == RIGHT_SQUARE))
- 	      return invoc;
- 
- 	    if (invoc->get_invoc_data ().get_delim_tok_tree ().get_delim_type ()
- 		  == AST::CURLY
- 		&& after_macro != DOT && after_macro != QUESTION_MARK)
- 	      {
- 		rust_debug ("braced macro statement");
- 		return invoc;
- 	      }
- 
- 	    null_denotation = std::move (invoc);
- 	  }
- 	else
- 	  {
- 	    null_denotation
- 	      = null_denotation_path (std::move (path), {}, restrictions);
- 	  }
- 
- 	expr = left_denotations (std::move (null_denotation), LBP_LOWEST,
- 				 std::move (outer_attrs), restrictions);
- 	break;
-       }
-     default:
-       restrictions.expr_can_be_stmt = true;
-       expr = parse_expr (std::move (outer_attrs), restrictions);
-       break;
-     }
- 
-   if (expr == nullptr)
-     {
-       // expr is required, error
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "failed to parse expr in expr statement");
-       add_error (std::move (error));
- 
-       skip_after_semicolon ();
-       return nullptr;
-     }
- 
-   bool has_semi = false;
- 
-   if (restrictions.consume_semi)
-     {
-       if (maybe_skip_token (SEMICOLON))
- 	{
- 	  has_semi = true;
- 	}
-       else if (expr->is_expr_without_block ())
- 	{
- 	  if (restrictions.allow_close_after_expr_stmt)
- 	    {
- 	      TokenId id = lexer.peek_token ()->get_id ();
- 	      if (id != RIGHT_PAREN && id != RIGHT_CURLY && id != RIGHT_SQUARE)
- 		{
- 		  expect_token (SEMICOLON);
- 		  return nullptr;
- 		}
- 	    }
- 	  else
- 	    {
- 	      expect_token (SEMICOLON);
- 	      return nullptr;
- 	    }
- 	}
-     }
- 
-   return std::unique_ptr<AST::ExprStmt> (
-     new AST::ExprStmt (std::move (expr), locus, has_semi));
- }
- 
- // Parses a block expression, including the curly braces at start and end.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::BlockExpr>
- Parser<ManagedTokenSource>::parse_block_expr (
-   AST::AttrVec outer_attrs, tl::optional<AST::LoopLabel> label,
-   location_t pratt_parsed_loc)
- {
-   location_t locus = pratt_parsed_loc;
-   if (locus == UNKNOWN_LOCATION)
-     {
-       locus = lexer.peek_token ()->get_locus ();
-       if (!skip_token (LEFT_CURLY))
- 	{
- 	  skip_after_end_block ();
- 	  return nullptr;
- 	}
-     }
- 
-   AST::AttrVec inner_attrs = parse_inner_attributes ();
- 
-   // parse statements and expression
-   std::vector<std::unique_ptr<AST::Stmt>> stmts;
-   std::unique_ptr<AST::Expr> expr = nullptr;
- 
-   const_TokenPtr t = lexer.peek_token ();
-   while (t->get_id () != RIGHT_CURLY)
-     {
-       ExprOrStmt expr_or_stmt = parse_stmt_or_expr ();
-       if (expr_or_stmt.is_error ())
- 	{
- 	  skip_after_end_block ();
- 	  return nullptr;
- 	}
- 
-       t = lexer.peek_token ();
- 
-       if (expr_or_stmt.stmt != nullptr)
- 	{
- 	  stmts.push_back (std::move (expr_or_stmt.stmt));
- 	}
-       else
- 	{
- 	  // assign to expression and end parsing inside
- 	  expr = std::move (expr_or_stmt.expr);
- 	  break;
- 	}
-     }
- 
-   location_t end_locus = t->get_locus ();
- 
-   if (!skip_token (RIGHT_CURLY))
-     {
-       Error error (t->get_locus (),
- 		   "error may be from having an expression (as opposed to "
- 		   "statement) in the body of the function but not last");
-       add_error (std::move (error));
- 
-       skip_after_end_block ();
-       return nullptr;
-     }
- 
-   // grammar allows for empty block expressions
- 
-   stmts.shrink_to_fit ();
- 
-   return std::unique_ptr<AST::BlockExpr> (
-     new AST::BlockExpr (std::move (stmts), std::move (expr),
- 			std::move (inner_attrs), std::move (outer_attrs),
- 			std::move (label), locus, end_locus));
- }
- 
- /* Parse an anonymous const expression. This can be a regular const expression
-  * or an underscore for deferred const inference */
- template <typename ManagedTokenSource>
- tl::expected<AST::AnonConst, AnonConstError>
- Parser<ManagedTokenSource>::parse_anon_const ()
- {
-   auto current = lexer.peek_token ();
-   auto locus = current->get_locus ();
- 
-   // Special case deferred inference constants
-   if (maybe_skip_token (UNDERSCORE))
-     return AST::AnonConst (locus);
- 
-   auto expr = parse_expr ();
- 
-   if (!expr)
-     return tl::make_unexpected (AnonConstError::InvalidSizeExpr);
- 
-   return AST::AnonConst (std::move (expr), locus);
- }
- 
- /* Parse a "const block", a block preceded by the `const` keyword whose
-  * statements can be const evaluated and used in constant contexts */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::ConstBlock>
- Parser<ManagedTokenSource>::parse_const_block_expr (AST::AttrVec outer_attrs,
- 						    location_t locus)
- {
-   auto block = parse_block_expr ();
- 
-   if (!block)
-     {
-       add_error (Error (locus, "failed to parse inner block in const block"));
-       skip_after_end_block ();
- 
-       return nullptr;
-     }
- 
-   auto block_locus = block->get_locus ();
- 
-   return std::make_unique<AST::ConstBlock> (AST::AnonConst (std::move (block),
- 							    block_locus),
- 					    locus, std::move (outer_attrs));
- }
- 
- /* Parses a "grouped" expression (expression in parentheses), used to control
-  * precedence. */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::GroupedExpr>
- Parser<ManagedTokenSource>::parse_grouped_expr (AST::AttrVec outer_attrs)
- {
-   location_t locus = lexer.peek_token ()->get_locus ();
-   skip_token (LEFT_PAREN);
- 
-   AST::AttrVec inner_attrs = parse_inner_attributes ();
- 
-   // parse required expr inside parentheses
-   std::unique_ptr<AST::Expr> expr_in_parens = parse_expr ();
-   if (expr_in_parens == nullptr)
-     {
-       // skip after somewhere?
-       // error?
-       return nullptr;
-     }
- 
-   if (!skip_token (RIGHT_PAREN))
-     {
-       // skip after somewhere?
-       return nullptr;
-     }
- 
-   return std::unique_ptr<AST::GroupedExpr> (
-     new AST::GroupedExpr (std::move (expr_in_parens), std::move (inner_attrs),
- 			  std::move (outer_attrs), locus));
- }
- 
- // Parses a closure expression (closure definition).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::ClosureExpr>
- Parser<ManagedTokenSource>::parse_closure_expr (AST::AttrVec outer_attrs)
- {
-   location_t locus = lexer.peek_token ()->get_locus ();
-   // detect optional "move"
-   bool has_move = false;
-   if (lexer.peek_token ()->get_id () == MOVE)
-     {
-       lexer.skip_token ();
-       has_move = true;
-     }
- 
-   // handle parameter list
-   std::vector<AST::ClosureParam> params;
- 
-   const_TokenPtr t = lexer.peek_token ();
-   switch (t->get_id ())
-     {
-     case OR:
-       // skip token, no parameters
-       lexer.skip_token ();
-       break;
-     case PIPE:
-       // actually may have parameters
-       lexer.skip_token ();
-       t = lexer.peek_token ();
- 
-       while (t->get_id () != PIPE)
- 	{
- 	  AST::ClosureParam param = parse_closure_param ();
- 	  if (param.is_error ())
- 	    {
- 	      // TODO is this really an error?
- 	      Error error (t->get_locus (), "could not parse closure param");
- 	      add_error (std::move (error));
- 
- 	      break;
- 	    }
- 	  params.push_back (std::move (param));
- 
- 	  if (lexer.peek_token ()->get_id () != COMMA)
- 	    {
- 	      lexer.skip_token ();
- 	      // not an error but means param list is done
- 	      break;
- 	    }
- 	  // skip comma
- 	  lexer.skip_token ();
- 
- 	  t = lexer.peek_token ();
- 	}
-       params.shrink_to_fit ();
-       break;
-     default:
-       add_error (Error (t->get_locus (),
- 			"unexpected token %qs in closure expression - expected "
- 			"%<|%> or %<||%>",
- 			t->get_token_description ()));
- 
-       // skip somewhere?
-       return nullptr;
-     }
- 
-   // again branch based on next token
-   t = lexer.peek_token ();
-   if (t->get_id () == RETURN_TYPE)
-     {
-       // must be return type closure with block expr
- 
-       // skip "return type" token
-       lexer.skip_token ();
- 
-       // parse actual type, which is required
-       std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
-       if (type == nullptr)
- 	{
- 	  // error
- 	  Error error (t->get_locus (), "failed to parse type for closure");
- 	  add_error (std::move (error));
- 
- 	  // skip somewhere?
- 	  return nullptr;
- 	}
- 
-       // parse block expr, which is required
-       std::unique_ptr<AST::BlockExpr> block = parse_block_expr ();
-       if (block == nullptr)
- 	{
- 	  // error
- 	  Error error (lexer.peek_token ()->get_locus (),
- 		       "failed to parse block expr in closure");
- 	  add_error (std::move (error));
- 
- 	  // skip somewhere?
- 	  return nullptr;
- 	}
- 
-       return std::unique_ptr<AST::ClosureExprInnerTyped> (
- 	new AST::ClosureExprInnerTyped (std::move (type), std::move (block),
- 					std::move (params), locus, has_move,
- 					std::move (outer_attrs)));
-     }
-   else
-     {
-       // must be expr-only closure
- 
-       // parse expr, which is required
-       std::unique_ptr<AST::Expr> expr = parse_expr ();
-       if (expr == nullptr)
- 	{
- 	  Error error (t->get_locus (),
- 		       "failed to parse expression in closure");
- 	  add_error (std::move (error));
- 
- 	  // skip somewhere?
- 	  return nullptr;
- 	}
- 
-       return std::unique_ptr<AST::ClosureExprInner> (
- 	new AST::ClosureExprInner (std::move (expr), std::move (params), locus,
- 				   has_move, std::move (outer_attrs)));
-     }
- }
- 
- // Parses a literal token (to literal expression).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::LiteralExpr>
- Parser<ManagedTokenSource>::parse_literal_expr (AST::AttrVec outer_attrs)
- {
-   // TODO: change if literal representation in lexer changes
- 
-   std::string literal_value;
-   AST::Literal::LitType type = AST::Literal::STRING;
- 
-   // branch based on token
-   const_TokenPtr t = lexer.peek_token ();
-   switch (t->get_id ())
-     {
-     case CHAR_LITERAL:
-       type = AST::Literal::CHAR;
-       literal_value = t->get_str ();
-       lexer.skip_token ();
-       break;
-     case STRING_LITERAL:
-       type = AST::Literal::STRING;
-       literal_value = t->get_str ();
-       lexer.skip_token ();
-       break;
-     case BYTE_CHAR_LITERAL:
-       type = AST::Literal::BYTE;
-       literal_value = t->get_str ();
-       lexer.skip_token ();
-       break;
-     case BYTE_STRING_LITERAL:
-       type = AST::Literal::BYTE_STRING;
-       literal_value = t->get_str ();
-       lexer.skip_token ();
-       break;
-     case RAW_STRING_LITERAL:
-       type = AST::Literal::RAW_STRING;
-       literal_value = t->get_str ();
-       lexer.skip_token ();
-       break;
-     case INT_LITERAL:
-       type = AST::Literal::INT;
-       literal_value = t->get_str ();
-       lexer.skip_token ();
-       break;
-     case FLOAT_LITERAL:
-       type = AST::Literal::FLOAT;
-       literal_value = t->get_str ();
-       lexer.skip_token ();
-       break;
-     // case BOOL_LITERAL
-     // use true and false keywords rather than "bool literal" Rust terminology
-     case TRUE_LITERAL:
-       type = AST::Literal::BOOL;
-       literal_value = Values::Keywords::TRUE_LITERAL;
-       lexer.skip_token ();
-       break;
-     case FALSE_LITERAL:
-       type = AST::Literal::BOOL;
-       literal_value = Values::Keywords::FALSE_LITERAL;
-       lexer.skip_token ();
-       break;
-     default:
-       // error - cannot be a literal expr
-       add_error (Error (t->get_locus (),
- 			"unexpected token %qs when parsing literal expression",
- 			t->get_token_description ()));
- 
-       // skip?
-       return nullptr;
-     }
- 
-   // create literal based on stuff in switch
-   return std::unique_ptr<AST::LiteralExpr> (
-     new AST::LiteralExpr (std::move (literal_value), std::move (type),
- 			  t->get_type_hint (), std::move (outer_attrs),
- 			  t->get_locus ()));
- }
- 
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::BoxExpr>
- Parser<ManagedTokenSource>::parse_box_expr (AST::AttrVec outer_attrs,
- 					    location_t pratt_parsed_loc)
- {
-   location_t locus = pratt_parsed_loc;
-   if (locus == UNKNOWN_LOCATION)
-     {
-       locus = lexer.peek_token ()->get_locus ();
-       skip_token (BOX);
-     }
- 
-   ParseRestrictions restrictions;
-   restrictions.expr_can_be_null = false;
- 
-   std::unique_ptr<AST::Expr> expr = parse_expr (AST::AttrVec (), restrictions);
- 
-   return std::unique_ptr<AST::BoxExpr> (
-     new AST::BoxExpr (std::move (expr), std::move (outer_attrs), locus));
- }
- 
- // Parses a return expression (including any expression to return).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::ReturnExpr>
- Parser<ManagedTokenSource>::parse_return_expr (AST::AttrVec outer_attrs,
- 					       location_t pratt_parsed_loc)
- {
-   location_t locus = pratt_parsed_loc;
-   if (locus == UNKNOWN_LOCATION)
-     {
-       locus = lexer.peek_token ()->get_locus ();
-       skip_token (RETURN_KW);
-     }
- 
-   // parse expression to return, if it exists
-   ParseRestrictions restrictions;
-   restrictions.expr_can_be_null = true;
-   std::unique_ptr<AST::Expr> returned_expr
-     = parse_expr (AST::AttrVec (), restrictions);
- 
-   return std::unique_ptr<AST::ReturnExpr> (
-     new AST::ReturnExpr (std::move (returned_expr), std::move (outer_attrs),
- 			 locus));
- }
- 
- // Parses a try expression.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::TryExpr>
- Parser<ManagedTokenSource>::parse_try_expr (AST::AttrVec outer_attrs,
- 					    location_t pratt_parsed_loc)
- {
-   location_t locus = pratt_parsed_loc;
-   if (locus == UNKNOWN_LOCATION)
-     {
-       locus = lexer.peek_token ()->get_locus ();
-       skip_token (TRY);
-     }
- 
-   std::unique_ptr<AST::BlockExpr> block_expr = parse_block_expr ();
- 
-   if (!block_expr)
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "failed to parse try block expression");
-       add_error (std::move (error));
- 
-       return nullptr;
-     }
- 
-   return std::unique_ptr<AST::TryExpr> (
-     new AST::TryExpr (std::move (block_expr), std::move (outer_attrs), locus));
- }
- 
- /* Parses a break expression (including any label to break to AND any return
-  * expression). */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::BreakExpr>
- Parser<ManagedTokenSource>::parse_break_expr (AST::AttrVec outer_attrs,
- 					      location_t pratt_parsed_loc)
- {
-   location_t locus = pratt_parsed_loc;
-   if (locus == UNKNOWN_LOCATION)
-     {
-       locus = lexer.peek_token ()->get_locus ();
-       skip_token (BREAK);
-     }
- 
-   auto parsed_label = parse_lifetime (false);
-   auto label = (parsed_label)
- 		 ? tl::optional<AST::Lifetime> (parsed_label.value ())
- 		 : tl::nullopt;
- 
-   // parse break return expression if it exists
-   ParseRestrictions restrictions;
-   restrictions.expr_can_be_null = true;
-   std::unique_ptr<AST::Expr> return_expr
-     = parse_expr (AST::AttrVec (), restrictions);
- 
-   return std::unique_ptr<AST::BreakExpr> (
-     new AST::BreakExpr (std::move (label), std::move (return_expr),
- 			std::move (outer_attrs), locus));
- }
- 
- // Parses a continue expression (including any label to continue from).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::ContinueExpr>
- Parser<ManagedTokenSource>::parse_continue_expr (AST::AttrVec outer_attrs,
- 						 location_t pratt_parsed_loc)
- {
-   location_t locus = pratt_parsed_loc;
-   if (locus == UNKNOWN_LOCATION)
-     {
-       locus = lexer.peek_token ()->get_locus ();
-       skip_token (CONTINUE);
-     }
- 
-   auto parsed_label = parse_lifetime (false);
-   auto label = (parsed_label)
- 		 ? tl::optional<AST::Lifetime> (parsed_label.value ())
- 		 : tl::nullopt;
- 
-   return std::unique_ptr<AST::ContinueExpr> (
-     new AST::ContinueExpr (std::move (label), std::move (outer_attrs), locus));
- }
- 
- // Parses a loop label used in loop expressions.
- template <typename ManagedTokenSource>
- tl::expected<AST::LoopLabel, ParseLoopLabelError>
- Parser<ManagedTokenSource>::parse_loop_label (const_TokenPtr tok)
- {
-   // parse lifetime - if doesn't exist, assume no label
-   if (tok->get_id () != LIFETIME)
-     {
-       // not necessarily an error
-       return tl::unexpected<ParseLoopLabelError> (
- 	ParseLoopLabelError::NOT_LOOP_LABEL);
-     }
-   /* FIXME: check for named lifetime requirement here? or check in semantic
-    * analysis phase? */
-   AST::Lifetime label = lifetime_from_token (tok);
- 
-   if (!skip_token (COLON))
-     {
-       // skip somewhere?
-       return tl::unexpected<ParseLoopLabelError> (
- 	ParseLoopLabelError::MISSING_COLON);
-     }
- 
-   return tl::expected<AST::LoopLabel, ParseLoopLabelError> (
-     AST::LoopLabel (std::move (label), tok->get_locus ()));
- }
- 
- /* Parses an if expression of any kind, including with else, else if, else if
-  * let, and neither. Note that any outer attributes will be ignored because if
-  * expressions don't support them. */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::IfExpr>
- Parser<ManagedTokenSource>::parse_if_expr (AST::AttrVec outer_attrs,
- 					   location_t pratt_parsed_loc)
- {
-   // TODO: make having outer attributes an error?
-   location_t locus = pratt_parsed_loc;
-   if (locus == UNKNOWN_LOCATION)
-     {
-       locus = lexer.peek_token ()->get_locus ();
-       if (!skip_token (IF))
- 	{
- 	  skip_after_end_block ();
- 	  return nullptr;
- 	}
-     }
- 
-   // detect accidental if let
-   if (lexer.peek_token ()->get_id () == LET)
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "if let expression probably exists, but is being parsed "
- 		   "as an if expression. This may be a parser error");
-       add_error (std::move (error));
- 
-       // skip somewhere?
-       return nullptr;
-     }
- 
-   /* parse required condition expr - HACK to prevent struct expr from being
-    * parsed */
-   ParseRestrictions no_struct_expr;
-   no_struct_expr.can_be_struct_expr = false;
-   std::unique_ptr<AST::Expr> condition = parse_expr ({}, no_struct_expr);
-   if (condition == nullptr)
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "failed to parse condition expression in if expression");
-       add_error (std::move (error));
- 
-       // skip somewhere?
-       return nullptr;
-     }
- 
-   // parse required block expr
-   std::unique_ptr<AST::BlockExpr> if_body = parse_block_expr ();
-   if (if_body == nullptr)
-     return nullptr;
- 
-   // branch to parse end or else (and then else, else if, or else if let)
-   if (lexer.peek_token ()->get_id () != ELSE)
-     {
-       // single selection - end of if expression
-       return std::unique_ptr<AST::IfExpr> (
- 	new AST::IfExpr (std::move (condition), std::move (if_body),
- 			 std::move (outer_attrs), locus));
-     }
-   else
-     {
-       // double or multiple selection - branch on end, else if, or else if let
- 
-       // skip "else"
-       lexer.skip_token ();
- 
-       // branch on whether next token is '{' or 'if'
-       const_TokenPtr t = lexer.peek_token ();
-       switch (t->get_id ())
- 	{
- 	case LEFT_CURLY:
- 	  {
- 	    // double selection - else
- 	    // parse else block expr (required)
- 	    std::unique_ptr<AST::BlockExpr> else_body = parse_block_expr ();
- 	    if (else_body == nullptr)
- 	      {
- 		Error error (lexer.peek_token ()->get_locus (),
- 			     "failed to parse else body block expression in "
- 			     "if expression");
- 		add_error (std::move (error));
- 
- 		// skip somewhere?
- 		return nullptr;
- 	      }
- 
- 	    return std::unique_ptr<AST::IfExprConseqElse> (
- 	      new AST::IfExprConseqElse (std::move (condition),
- 					 std::move (if_body),
- 					 std::move (else_body),
- 					 std::move (outer_attrs), locus));
- 	  }
- 	case IF:
- 	  {
- 	    // multiple selection - else if or else if let
- 	    // branch on whether next token is 'let' or not
- 	    if (lexer.peek_token (1)->get_id () == LET)
- 	      {
- 		// parse if let expr (required)
- 		std::unique_ptr<AST::IfLetExpr> if_let_expr
- 		  = parse_if_let_expr ();
- 		if (if_let_expr == nullptr)
- 		  {
- 		    Error error (lexer.peek_token ()->get_locus (),
- 				 "failed to parse (else) if let expression "
- 				 "after if expression");
- 		    add_error (std::move (error));
- 
- 		    // skip somewhere?
- 		    return nullptr;
- 		  }
- 
- 		return std::unique_ptr<AST::IfExprConseqElse> (
- 		  new AST::IfExprConseqElse (std::move (condition),
- 					     std::move (if_body),
- 					     std::move (if_let_expr),
- 					     std::move (outer_attrs), locus));
- 	      }
- 	    else
- 	      {
- 		// parse if expr (required)
- 		std::unique_ptr<AST::IfExpr> if_expr = parse_if_expr ();
- 		if (if_expr == nullptr)
- 		  {
- 		    Error error (lexer.peek_token ()->get_locus (),
- 				 "failed to parse (else) if expression after "
- 				 "if expression");
- 		    add_error (std::move (error));
- 
- 		    // skip somewhere?
- 		    return nullptr;
- 		  }
- 
- 		return std::unique_ptr<AST::IfExprConseqElse> (
- 		  new AST::IfExprConseqElse (std::move (condition),
- 					     std::move (if_body),
- 					     std::move (if_expr),
- 					     std::move (outer_attrs), locus));
- 	      }
- 	  }
- 	default:
- 	  // error - invalid token
- 	  add_error (Error (t->get_locus (),
- 			    "unexpected token %qs after else in if expression",
- 			    t->get_token_description ()));
- 
- 	  // skip somewhere?
- 	  return nullptr;
- 	}
-     }
- }
- 
- /* Parses an if let expression of any kind, including with else, else if, else
-  * if let, and none. Note that any outer attributes will be ignored as if let
-  * expressions don't support them. */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::IfLetExpr>
- Parser<ManagedTokenSource>::parse_if_let_expr (AST::AttrVec outer_attrs,
- 					       location_t pratt_parsed_loc)
- {
-   // TODO: make having outer attributes an error?
-   location_t locus = pratt_parsed_loc;
-   if (locus == UNKNOWN_LOCATION)
-     {
-       locus = lexer.peek_token ()->get_locus ();
-       if (!skip_token (IF))
- 	{
- 	  skip_after_end_block ();
- 	  return nullptr;
- 	}
-     }
- 
-   // detect accidental if expr parsed as if let expr
-   if (lexer.peek_token ()->get_id () != LET)
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "if expression probably exists, but is being parsed as an "
- 		   "if let expression. This may be a parser error");
-       add_error (std::move (error));
- 
-       // skip somewhere?
-       return nullptr;
-     }
-   lexer.skip_token ();
- 
-   // parse match arm patterns (which are required)
-   std::vector<std::unique_ptr<AST::Pattern>> match_arm_patterns
-     = parse_match_arm_patterns (EQUAL);
-   if (match_arm_patterns.empty ())
-     {
-       Error error (
- 	lexer.peek_token ()->get_locus (),
- 	"failed to parse any match arm patterns in if let expression");
-       add_error (std::move (error));
- 
-       // skip somewhere?
-       return nullptr;
-     }
- 
-   if (!skip_token (EQUAL))
-     {
-       // skip somewhere?
-       return nullptr;
-     }
- 
-   // parse expression (required) - HACK to prevent struct expr being parsed
-   ParseRestrictions no_struct_expr;
-   no_struct_expr.can_be_struct_expr = false;
-   std::unique_ptr<AST::Expr> scrutinee_expr = parse_expr ({}, no_struct_expr);
-   if (scrutinee_expr == nullptr)
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "failed to parse scrutinee expression in if let expression");
-       add_error (std::move (error));
- 
-       // skip somewhere?
-       return nullptr;
-     }
-   /* TODO: check for expression not being a struct expression or lazy boolean
-    * expression here? or actually probably in semantic analysis. */
- 
-   // parse block expression (required)
-   std::unique_ptr<AST::BlockExpr> if_let_body = parse_block_expr ();
-   if (if_let_body == nullptr)
-     {
-       Error error (
- 	lexer.peek_token ()->get_locus (),
- 	"failed to parse if let body block expression in if let expression");
-       add_error (std::move (error));
- 
-       // skip somewhere?
-       return nullptr;
-     }
- 
-   // branch to parse end or else (and then else, else if, or else if let)
-   if (lexer.peek_token ()->get_id () != ELSE)
-     {
-       // single selection - end of if let expression
-       return std::unique_ptr<AST::IfLetExpr> (
- 	new AST::IfLetExpr (std::move (match_arm_patterns),
- 			    std::move (scrutinee_expr), std::move (if_let_body),
- 			    std::move (outer_attrs), locus));
-     }
-   else
-     {
-       // double or multiple selection - branch on end, else if, or else if let
- 
-       // skip "else"
-       lexer.skip_token ();
- 
-       // branch on whether next token is '{' or 'if'
-       const_TokenPtr t = lexer.peek_token ();
-       switch (t->get_id ())
- 	{
- 	case LEFT_CURLY:
- 	  {
- 	    // double selection - else
- 	    // parse else block expr (required)
- 	    std::unique_ptr<AST::BlockExpr> else_body = parse_block_expr ();
- 	    if (else_body == nullptr)
- 	      {
- 		Error error (lexer.peek_token ()->get_locus (),
- 			     "failed to parse else body block expression in "
- 			     "if let expression");
- 		add_error (std::move (error));
- 
- 		// skip somewhere?
- 		return nullptr;
- 	      }
- 
- 	    return std::unique_ptr<AST::IfLetExprConseqElse> (
- 	      new AST::IfLetExprConseqElse (std::move (match_arm_patterns),
- 					    std::move (scrutinee_expr),
- 					    std::move (if_let_body),
- 					    std::move (else_body),
- 					    std::move (outer_attrs), locus));
- 	  }
- 	case IF:
- 	  {
- 	    // multiple selection - else if or else if let
- 	    // branch on whether next token is 'let' or not
- 	    if (lexer.peek_token (1)->get_id () == LET)
- 	      {
- 		// parse if let expr (required)
- 		std::unique_ptr<AST::IfLetExpr> if_let_expr
- 		  = parse_if_let_expr ();
- 		if (if_let_expr == nullptr)
- 		  {
- 		    Error error (lexer.peek_token ()->get_locus (),
- 				 "failed to parse (else) if let expression "
- 				 "after if let expression");
- 		    add_error (std::move (error));
- 
- 		    // skip somewhere?
- 		    return nullptr;
- 		  }
- 
- 		return std::unique_ptr<AST::IfLetExprConseqElse> (
- 		  new AST::IfLetExprConseqElse (
- 		    std::move (match_arm_patterns), std::move (scrutinee_expr),
- 		    std::move (if_let_body), std::move (if_let_expr),
- 		    std::move (outer_attrs), locus));
- 	      }
- 	    else
- 	      {
- 		// parse if expr (required)
- 		std::unique_ptr<AST::IfExpr> if_expr = parse_if_expr ();
- 		if (if_expr == nullptr)
- 		  {
- 		    Error error (lexer.peek_token ()->get_locus (),
- 				 "failed to parse (else) if expression after "
- 				 "if let expression");
- 		    add_error (std::move (error));
- 
- 		    // skip somewhere?
- 		    return nullptr;
- 		  }
- 
- 		return std::unique_ptr<AST::IfLetExprConseqElse> (
- 		  new AST::IfLetExprConseqElse (
- 		    std::move (match_arm_patterns), std::move (scrutinee_expr),
- 		    std::move (if_let_body), std::move (if_expr),
- 		    std::move (outer_attrs), locus));
- 	      }
- 	  }
- 	default:
- 	  // error - invalid token
- 	  add_error (
- 	    Error (t->get_locus (),
- 		   "unexpected token %qs after else in if let expression",
- 		   t->get_token_description ()));
- 
- 	  // skip somewhere?
- 	  return nullptr;
- 	}
-     }
- }
- 
- /* TODO: possibly decide on different method of handling label (i.e. not
-  * parameter) */
- 
- /* Parses a "loop" infinite loop expression. Label is not parsed and should be
-  * parsed via parse_labelled_loop_expr, which would call this. */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::LoopExpr>
- Parser<ManagedTokenSource>::parse_loop_expr (AST::AttrVec outer_attrs,
- 					     tl::optional<AST::LoopLabel> label,
- 					     location_t pratt_parsed_loc)
- {
-   location_t locus = pratt_parsed_loc;
-   if (locus == UNKNOWN_LOCATION)
-     {
-       if (label)
- 	locus = label->get_locus ();
-       else
- 	locus = lexer.peek_token ()->get_locus ();
- 
-       if (!skip_token (LOOP))
- 	{
- 	  skip_after_end_block ();
- 	  return nullptr;
- 	}
-     }
-   else
-     {
-       if (label)
- 	locus = label->get_locus ();
-     }
- 
-   // parse loop body, which is required
-   std::unique_ptr<AST::BlockExpr> loop_body = parse_block_expr ();
-   if (loop_body == nullptr)
-     return nullptr;
- 
-   return std::unique_ptr<AST::LoopExpr> (
-     new AST::LoopExpr (std::move (loop_body), locus, std::move (label),
- 		       std::move (outer_attrs)));
- }
- 
- /* Parses a "while" loop expression. Label is not parsed and should be parsed
-  * via parse_labelled_loop_expr, which would call this. */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::WhileLoopExpr>
- Parser<ManagedTokenSource>::parse_while_loop_expr (
-   AST::AttrVec outer_attrs, tl::optional<AST::LoopLabel> label,
-   location_t pratt_parsed_loc)
- {
-   location_t locus = pratt_parsed_loc;
-   if (locus == UNKNOWN_LOCATION)
-     {
-       if (label)
- 	locus = label->get_locus ();
-       else
- 	locus = lexer.peek_token ()->get_locus ();
- 
-       if (!skip_token (WHILE))
- 	{
- 	  skip_after_end_block ();
- 	  return nullptr;
- 	}
-     }
-   else
-     {
-       if (label)
- 	locus = label->get_locus ();
-     }
- 
-   // ensure it isn't a while let loop
-   if (lexer.peek_token ()->get_id () == LET)
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "appears to be while let loop but is being parsed by "
- 		   "while loop - this may be a compiler issue");
-       add_error (std::move (error));
- 
-       // skip somewhere?
-       return nullptr;
-     }
- 
-   // parse loop predicate (required) with HACK to prevent struct expr parsing
-   ParseRestrictions no_struct_expr;
-   no_struct_expr.can_be_struct_expr = false;
-   std::unique_ptr<AST::Expr> predicate = parse_expr ({}, no_struct_expr);
-   if (predicate == nullptr)
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "failed to parse predicate expression in while loop");
-       add_error (std::move (error));
- 
-       // skip somewhere?
-       return nullptr;
-     }
-   /* TODO: check that it isn't struct expression here? actually, probably in
-    * semantic analysis */
- 
-   // parse loop body (required)
-   std::unique_ptr<AST::BlockExpr> body = parse_block_expr ();
-   if (body == nullptr)
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "failed to parse loop body block expression in while loop");
-       add_error (std::move (error));
- 
-       // skip somewhere
-       return nullptr;
-     }
- 
-   return std::unique_ptr<AST::WhileLoopExpr> (
-     new AST::WhileLoopExpr (std::move (predicate), std::move (body), locus,
- 			    std::move (label), std::move (outer_attrs)));
- }
- 
- /* Parses a "while let" loop expression. Label is not parsed and should be
-  * parsed via parse_labelled_loop_expr, which would call this. */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::WhileLetLoopExpr>
- Parser<ManagedTokenSource>::parse_while_let_loop_expr (
-   AST::AttrVec outer_attrs, tl::optional<AST::LoopLabel> label)
- {
-   location_t locus = UNKNOWN_LOCATION;
-   if (label)
-     locus = label->get_locus ();
-   else
-     locus = lexer.peek_token ()->get_locus ();
-   maybe_skip_token (WHILE);
- 
-   /* check for possible accidental recognition of a while loop as a while let
-    * loop */
-   if (lexer.peek_token ()->get_id () != LET)
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "appears to be a while loop but is being parsed by "
- 		   "while let loop - this may be a compiler issue");
-       add_error (std::move (error));
- 
-       // skip somewhere
-       return nullptr;
-     }
-   // as this token is definitely let now, save the computation of comparison
-   lexer.skip_token ();
- 
-   // parse predicate patterns
-   std::vector<std::unique_ptr<AST::Pattern>> predicate_patterns
-     = parse_match_arm_patterns (EQUAL);
-   // ensure that there is at least 1 pattern
-   if (predicate_patterns.empty ())
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "should be at least 1 pattern");
-       add_error (std::move (error));
-       return nullptr;
-     }
- 
-   if (!skip_token (EQUAL))
-     {
-       // skip somewhere?
-       return nullptr;
-     }
- 
-   /* parse predicate expression, which is required (and HACK to prevent struct
-    * expr) */
-   ParseRestrictions no_struct_expr;
-   no_struct_expr.can_be_struct_expr = false;
-   std::unique_ptr<AST::Expr> predicate_expr = parse_expr ({}, no_struct_expr);
-   if (predicate_expr == nullptr)
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "failed to parse predicate expression in while let loop");
-       add_error (std::move (error));
- 
-       // skip somewhere?
-       return nullptr;
-     }
-   /* TODO: ensure that struct expression is not parsed? Actually, probably in
-    * semantic analysis. */
- 
-   // parse loop body, which is required
-   std::unique_ptr<AST::BlockExpr> body = parse_block_expr ();
-   if (body == nullptr)
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "failed to parse block expr (loop body) of while let loop");
-       add_error (std::move (error));
- 
-       // skip somewhere?
-       return nullptr;
-     }
- 
-   return std::unique_ptr<AST::WhileLetLoopExpr> (new AST::WhileLetLoopExpr (
-     std::move (predicate_patterns), std::move (predicate_expr),
-     std::move (body), locus, std::move (label), std::move (outer_attrs)));
- }
- 
- /* Parses a "for" iterative loop. Label is not parsed and should be parsed via
-  * parse_labelled_loop_expr, which would call this. */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::ForLoopExpr>
- Parser<ManagedTokenSource>::parse_for_loop_expr (
-   AST::AttrVec outer_attrs, tl::optional<AST::LoopLabel> label)
- {
-   location_t locus = UNKNOWN_LOCATION;
-   if (label)
-     locus = label->get_locus ();
-   else
-     locus = lexer.peek_token ()->get_locus ();
-   maybe_skip_token (FOR);
- 
-   // parse pattern, which is required
-   std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
-   if (pattern == nullptr)
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "failed to parse iterator pattern in for loop");
-       add_error (std::move (error));
- 
-       // skip somewhere?
-       return nullptr;
-     }
- 
-   if (!skip_token (IN))
-     {
-       // skip somewhere?
-       return nullptr;
-     }
- 
-   /* parse iterator expression, which is required - also HACK to prevent
-    * struct expr */
-   ParseRestrictions no_struct_expr;
-   no_struct_expr.can_be_struct_expr = false;
-   std::unique_ptr<AST::Expr> expr = parse_expr ({}, no_struct_expr);
-   if (expr == nullptr)
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "failed to parse iterator expression in for loop");
-       add_error (std::move (error));
- 
-       // skip somewhere?
-       return nullptr;
-     }
-   // TODO: check to ensure this isn't struct expr? Or in semantic analysis.
- 
-   // parse loop body, which is required
-   std::unique_ptr<AST::BlockExpr> body = parse_block_expr ();
-   if (body == nullptr)
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "failed to parse loop body block expression in for loop");
-       add_error (std::move (error));
- 
-       // skip somewhere?
-       return nullptr;
-     }
- 
-   return std::unique_ptr<AST::ForLoopExpr> (
-     new AST::ForLoopExpr (std::move (pattern), std::move (expr),
- 			  std::move (body), locus, std::move (label),
- 			  std::move (outer_attrs)));
- }
- 
- // Parses a loop expression with label (any kind of loop - disambiguates).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::Expr>
- Parser<ManagedTokenSource>::parse_labelled_loop_expr (const_TokenPtr tok,
- 						      AST::AttrVec outer_attrs)
- {
-   /* TODO: decide whether it should not work if there is no label, or parse it
-    * with no label at the moment, I will make it not work with no label
-    * because that's the implication. */
- 
-   if (tok->get_id () != LIFETIME)
-     {
-       Error error (tok->get_locus (),
- 		   "expected lifetime in labelled loop expr (to parse loop "
- 		   "label) - found %qs",
- 		   tok->get_token_description ());
-       add_error (std::move (error));
- 
-       // skip?
-       return nullptr;
-     }
- 
-   // parse loop label (required)
-   // TODO: Convert this return type to tl::expected instead of tl::optional
-   auto parsed_label = parse_loop_label (tok);
-   if (!parsed_label)
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "failed to parse loop label in labelled loop expr");
-       add_error (std::move (error));
- 
-       // skip?
-       return nullptr;
-     }
- 
-   auto label = parsed_label
- 		 ? tl::optional<AST::LoopLabel> (parsed_label.value ())
- 		 : tl::nullopt;
- 
-   // branch on next token
-   const_TokenPtr t = lexer.peek_token ();
-   switch (t->get_id ())
-     {
-     case LOOP:
-       return parse_loop_expr (std::move (outer_attrs), std::move (label));
-     case FOR:
-       return parse_for_loop_expr (std::move (outer_attrs), std::move (label));
-     case WHILE:
-       // further disambiguate into while vs while let
-       if (lexer.peek_token (1)->get_id () == LET)
- 	{
- 	  return parse_while_let_loop_expr (std::move (outer_attrs),
- 					    std::move (label));
- 	}
-       else
- 	{
- 	  return parse_while_loop_expr (std::move (outer_attrs),
- 					std::move (label));
- 	}
-     case LEFT_CURLY:
-       return parse_block_expr (std::move (outer_attrs), std::move (label));
-     default:
-       // error
-       add_error (Error (t->get_locus (),
- 			"unexpected token %qs when parsing labelled loop",
- 			t->get_token_description ()));
- 
-       // skip?
-       return nullptr;
-     }
- }
- 
- // Parses a match expression.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::MatchExpr>
- Parser<ManagedTokenSource>::parse_match_expr (AST::AttrVec outer_attrs,
- 					      location_t pratt_parsed_loc)
- {
-   location_t locus = pratt_parsed_loc;
-   if (locus == UNKNOWN_LOCATION)
-     {
-       locus = lexer.peek_token ()->get_locus ();
-       skip_token (MATCH_KW);
-     }
- 
-   /* parse scrutinee expression, which is required (and HACK to prevent struct
-    * expr) */
-   ParseRestrictions no_struct_expr;
-   no_struct_expr.can_be_struct_expr = false;
-   std::unique_ptr<AST::Expr> scrutinee = parse_expr ({}, no_struct_expr);
-   if (scrutinee == nullptr)
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "failed to parse scrutinee expression in match expression");
-       add_error (std::move (error));
- 
-       // skip somewhere?
-       return nullptr;
-     }
-   /* TODO: check for scrutinee expr not being struct expr? or do so in
-    * semantic analysis */
- 
-   if (!skip_token (LEFT_CURLY))
-     {
-       // skip somewhere?
-       return nullptr;
-     }
- 
-   // parse inner attributes (if they exist)
-   AST::AttrVec inner_attrs = parse_inner_attributes ();
- 
-   // parse match arms (if they exist)
-   // std::vector<std::unique_ptr<AST::MatchCase> > match_arms;
-   std::vector<AST::MatchCase> match_arms;
- 
-   // parse match cases
-   while (lexer.peek_token ()->get_id () != RIGHT_CURLY)
-     {
-       // parse match arm itself, which is required
-       AST::MatchArm arm = parse_match_arm ();
-       if (arm.is_error ())
- 	{
- 	  // TODO is this worth throwing everything away?
- 	  Error error (lexer.peek_token ()->get_locus (),
- 		       "failed to parse match arm in match arms");
- 	  add_error (std::move (error));
- 
- 	  return nullptr;
- 	}
- 
-       if (!skip_token (MATCH_ARROW))
- 	{
- 	  // skip after somewhere?
- 	  // TODO is returning here a good idea? or is break better?
- 	  return nullptr;
- 	}
- 
-       ParseRestrictions restrictions;
-       restrictions.expr_can_be_stmt = true;
- 
-       std::unique_ptr<AST::Expr> expr = parse_expr ({}, restrictions);
- 
-       if (expr == nullptr)
- 	{
- 	  Error error (lexer.peek_token ()->get_locus (),
- 		       "failed to parse expr in match arm in match expr");
- 	  add_error (std::move (error));
- 
- 	  // skip somewhere?
- 	  return nullptr;
- 	}
- 
-       bool is_expr_without_block = expr->is_expr_without_block ();
- 
-       match_arms.push_back (AST::MatchCase (std::move (arm), std::move (expr)));
- 
-       // handle comma presence
-       if (lexer.peek_token ()->get_id () != COMMA)
- 	{
- 	  if (!is_expr_without_block)
- 	    {
- 	      // allowed even if not final case
- 	      continue;
- 	    }
- 	  else if (is_expr_without_block
- 		   && lexer.peek_token ()->get_id () != RIGHT_CURLY)
- 	    {
- 	      // not allowed if not final case
- 	      Error error (lexer.peek_token ()->get_locus (),
- 			   "exprwithoutblock requires comma after match case "
- 			   "expression in match arm (if not final case)");
- 	      add_error (std::move (error));
- 
- 	      return nullptr;
- 	    }
- 	  else
- 	    {
- 	      // otherwise, must be final case, so fine
- 	      break;
- 	    }
- 	}
-       lexer.skip_token ();
-     }
- 
-   if (!skip_token (RIGHT_CURLY))
-     {
-       // skip somewhere?
-       return nullptr;
-     }
- 
-   match_arms.shrink_to_fit ();
- 
-   return std::unique_ptr<AST::MatchExpr> (
-     new AST::MatchExpr (std::move (scrutinee), std::move (match_arms),
- 			std::move (inner_attrs), std::move (outer_attrs),
- 			locus));
- }
- 
- // Parses the "pattern" part of the match arm (the 'case x:' equivalent).
- template <typename ManagedTokenSource>
- AST::MatchArm
- Parser<ManagedTokenSource>::parse_match_arm ()
- {
-   // parse optional outer attributes
-   AST::AttrVec outer_attrs = parse_outer_attributes ();
- 
-   // DEBUG
-   rust_debug ("about to start parsing match arm patterns");
- 
-   // break early if find right curly
-   if (lexer.peek_token ()->get_id () == RIGHT_CURLY)
-     {
-       // not an error
-       return AST::MatchArm::create_error ();
-     }
- 
-   // parse match arm patterns - at least 1 is required
-   std::vector<std::unique_ptr<AST::Pattern>> match_arm_patterns
-     = parse_match_arm_patterns (RIGHT_CURLY);
-   if (match_arm_patterns.empty ())
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "failed to parse any patterns in match arm");
-       add_error (std::move (error));
- 
-       // skip somewhere?
-       return AST::MatchArm::create_error ();
-     }
- 
-   // DEBUG
-   rust_debug ("successfully parsed match arm patterns");
- 
-   // parse match arm guard expr if it exists
-   std::unique_ptr<AST::Expr> guard_expr = nullptr;
-   if (lexer.peek_token ()->get_id () == IF)
-     {
-       lexer.skip_token ();
- 
-       guard_expr = parse_expr ();
-       if (guard_expr == nullptr)
- 	{
- 	  Error error (lexer.peek_token ()->get_locus (),
- 		       "failed to parse guard expression in match arm");
- 	  add_error (std::move (error));
- 
- 	  // skip somewhere?
- 	  return AST::MatchArm::create_error ();
- 	}
-     }
- 
-   // DEBUG
-   rust_debug ("successfully parsed match arm");
- 
-   return AST::MatchArm (std::move (match_arm_patterns),
- 			lexer.peek_token ()->get_locus (),
- 			std::move (guard_expr), std::move (outer_attrs));
- }
- 
- /* Parses the patterns used in a match arm. End token id is the id of the
-  * token that would exist after the patterns are done (e.g. '}' for match
-  * expr, '=' for if let and while let). */
- template <typename ManagedTokenSource>
- std::vector<std::unique_ptr<AST::Pattern>>
- Parser<ManagedTokenSource>::parse_match_arm_patterns (TokenId end_token_id)
- {
-   // skip optional leading '|'
-   if (lexer.peek_token ()->get_id () == PIPE)
-     lexer.skip_token ();
-   /* TODO: do I even need to store the result of this? can't be used.
-    * If semantically different, I need a wrapped "match arm patterns" object
-    * for this. */
- 
-   std::vector<std::unique_ptr<AST::Pattern>> patterns;
- 
-   // quick break out if end_token_id
-   if (lexer.peek_token ()->get_id () == end_token_id)
-     return patterns;
- 
-   // parse required pattern - if doesn't exist, return empty
-   std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern ();
-   if (initial_pattern == nullptr)
-     {
-       // FIXME: should this be an error?
-       return patterns;
-     }
-   patterns.push_back (std::move (initial_pattern));
- 
-   // DEBUG
-   rust_debug ("successfully parsed initial match arm pattern");
- 
-   // parse new patterns as long as next char is '|'
-   const_TokenPtr t = lexer.peek_token ();
-   while (t->get_id () == PIPE)
-     {
-       // skip pipe token
-       lexer.skip_token ();
- 
-       // break if hit end token id
-       if (lexer.peek_token ()->get_id () == end_token_id)
- 	break;
- 
-       // parse pattern
-       std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
-       if (pattern == nullptr)
- 	{
- 	  // this is an error
- 	  Error error (lexer.peek_token ()->get_locus (),
- 		       "failed to parse pattern in match arm patterns");
- 	  add_error (std::move (error));
- 
- 	  // skip somewhere?
- 	  return {};
- 	}
- 
-       patterns.push_back (std::move (pattern));
- 
-       t = lexer.peek_token ();
-     }
- 
-   patterns.shrink_to_fit ();
- 
-   return patterns;
- }
- 
- // Parses an async block expression.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::AsyncBlockExpr>
- Parser<ManagedTokenSource>::parse_async_block_expr (AST::AttrVec outer_attrs)
- {
-   location_t locus = lexer.peek_token ()->get_locus ();
-   skip_token (ASYNC);
- 
-   // detect optional move token
-   bool has_move = false;
-   if (lexer.peek_token ()->get_id () == MOVE)
-     {
-       lexer.skip_token ();
-       has_move = true;
-     }
- 
-   // parse block expression (required)
-   std::unique_ptr<AST::BlockExpr> block_expr = parse_block_expr ();
-   if (block_expr == nullptr)
-     {
-       Error error (
- 	lexer.peek_token ()->get_locus (),
- 	"failed to parse block expression of async block expression");
-       add_error (std::move (error));
- 
-       // skip somewhere?
-       return nullptr;
-     }
- 
-   return std::unique_ptr<AST::AsyncBlockExpr> (
-     new AST::AsyncBlockExpr (std::move (block_expr), has_move,
- 			     std::move (outer_attrs), locus));
- }
- 
- // Parses an unsafe block expression.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::UnsafeBlockExpr>
- Parser<ManagedTokenSource>::parse_unsafe_block_expr (
-   AST::AttrVec outer_attrs, location_t pratt_parsed_loc)
- {
-   location_t locus = pratt_parsed_loc;
-   if (locus == UNKNOWN_LOCATION)
-     {
-       locus = lexer.peek_token ()->get_locus ();
-       skip_token (UNSAFE);
-     }
- 
-   // parse block expression (required)
-   std::unique_ptr<AST::BlockExpr> block_expr = parse_block_expr ();
-   if (block_expr == nullptr)
-     {
-       Error error (
- 	lexer.peek_token ()->get_locus (),
- 	"failed to parse block expression of unsafe block expression");
-       add_error (std::move (error));
- 
-       // skip somewhere?
-       return nullptr;
-     }
- 
-   return std::unique_ptr<AST::UnsafeBlockExpr> (
-     new AST::UnsafeBlockExpr (std::move (block_expr), std::move (outer_attrs),
- 			      locus));
- }
- 
- // Parses an array definition expression.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::ArrayExpr>
- Parser<ManagedTokenSource>::parse_array_expr (AST::AttrVec outer_attrs,
- 					      location_t pratt_parsed_loc)
- {
-   location_t locus = pratt_parsed_loc;
-   if (locus == UNKNOWN_LOCATION)
-     {
-       locus = lexer.peek_token ()->get_locus ();
-       skip_token (LEFT_SQUARE);
-     }
- 
-   // parse optional inner attributes
-   AST::AttrVec inner_attrs = parse_inner_attributes ();
- 
-   // parse the "array elements" section, which is optional
-   if (lexer.peek_token ()->get_id () == RIGHT_SQUARE)
-     {
-       // no array elements
-       lexer.skip_token ();
- 
-       std::vector<std::unique_ptr<AST::Expr>> exprs;
-       auto array_elems
- 	= std::make_unique<AST::ArrayElemsValues> (std::move (exprs), locus);
-       return std::make_unique<AST::ArrayExpr> (std::move (array_elems),
- 					       std::move (inner_attrs),
- 					       std::move (outer_attrs), locus);
-     }
-   else
-     {
-       // should have array elements
-       // parse initial expression, which is required for either
-       std::unique_ptr<AST::Expr> initial_expr = parse_expr ();
-       if (initial_expr == nullptr)
- 	{
- 	  Error error (lexer.peek_token ()->get_locus (),
- 		       "could not parse expression in array expression "
- 		       "(even though arrayelems seems to be present)");
- 	  add_error (std::move (error));
- 
- 	  // skip somewhere?
- 	  return nullptr;
- 	}
- 
-       if (lexer.peek_token ()->get_id () == SEMICOLON)
- 	{
- 	  // copy array elems
- 	  lexer.skip_token ();
- 
- 	  // parse copy amount expression (required)
- 	  std::unique_ptr<AST::Expr> copy_amount = parse_expr ();
- 	  if (copy_amount == nullptr)
- 	    {
- 	      Error error (lexer.peek_token ()->get_locus (),
- 			   "could not parse copy amount expression in array "
- 			   "expression (arrayelems)");
- 	      add_error (std::move (error));
- 
- 	      // skip somewhere?
- 	      return nullptr;
- 	    }
- 
- 	  skip_token (RIGHT_SQUARE);
- 
- 	  std::unique_ptr<AST::ArrayElemsCopied> copied_array_elems (
- 	    new AST::ArrayElemsCopied (std::move (initial_expr),
- 				       std::move (copy_amount), locus));
- 	  return std::unique_ptr<AST::ArrayExpr> (
- 	    new AST::ArrayExpr (std::move (copied_array_elems),
- 				std::move (inner_attrs),
- 				std::move (outer_attrs), locus));
- 	}
-       else if (lexer.peek_token ()->get_id () == RIGHT_SQUARE)
- 	{
- 	  // single-element array expression
- 	  std::vector<std::unique_ptr<AST::Expr>> exprs;
- 	  exprs.reserve (1);
- 	  exprs.push_back (std::move (initial_expr));
- 	  exprs.shrink_to_fit ();
- 
- 	  skip_token (RIGHT_SQUARE);
- 
- 	  std::unique_ptr<AST::ArrayElemsValues> array_elems (
- 	    new AST::ArrayElemsValues (std::move (exprs), locus));
- 	  return std::unique_ptr<AST::ArrayExpr> (
- 	    new AST::ArrayExpr (std::move (array_elems),
- 				std::move (inner_attrs),
- 				std::move (outer_attrs), locus));
- 	}
-       else if (lexer.peek_token ()->get_id () == COMMA)
- 	{
- 	  // multi-element array expression (or trailing comma)
- 	  std::vector<std::unique_ptr<AST::Expr>> exprs;
- 	  exprs.push_back (std::move (initial_expr));
- 
- 	  const_TokenPtr t = lexer.peek_token ();
- 	  while (t->get_id () == COMMA)
- 	    {
- 	      lexer.skip_token ();
- 
- 	      // quick break if right square bracket
- 	      if (lexer.peek_token ()->get_id () == RIGHT_SQUARE)
- 		break;
- 
- 	      // parse expression (required)
- 	      std::unique_ptr<AST::Expr> expr = parse_expr ();
- 	      if (expr == nullptr)
- 		{
- 		  Error error (lexer.peek_token ()->get_locus (),
- 			       "failed to parse element in array expression");
- 		  add_error (std::move (error));
- 
- 		  // skip somewhere?
- 		  return nullptr;
- 		}
- 	      exprs.push_back (std::move (expr));
- 
- 	      t = lexer.peek_token ();
- 	    }
- 
- 	  skip_token (RIGHT_SQUARE);
- 
- 	  exprs.shrink_to_fit ();
- 
- 	  std::unique_ptr<AST::ArrayElemsValues> array_elems (
- 	    new AST::ArrayElemsValues (std::move (exprs), locus));
- 	  return std::unique_ptr<AST::ArrayExpr> (
- 	    new AST::ArrayExpr (std::move (array_elems),
- 				std::move (inner_attrs),
- 				std::move (outer_attrs), locus));
- 	}
-       else
- 	{
- 	  // error
- 	  Error error (lexer.peek_token ()->get_locus (),
- 		       "unexpected token %qs in array expression (arrayelems)",
- 		       lexer.peek_token ()->get_token_description ());
- 	  add_error (std::move (error));
- 
- 	  // skip somewhere?
- 	  return nullptr;
- 	}
-     }
- }
- 
- // Parses a single parameter used in a closure definition.
- template <typename ManagedTokenSource>
- AST::ClosureParam
- Parser<ManagedTokenSource>::parse_closure_param ()
- {
-   AST::AttrVec outer_attrs = parse_outer_attributes ();
- 
-   // parse pattern (which is required)
-   std::unique_ptr<AST::Pattern> pattern = parse_pattern_no_alt ();
-   if (pattern == nullptr)
-     {
-       // not necessarily an error
-       return AST::ClosureParam::create_error ();
-     }
- 
-   // parse optional type of param
-   std::unique_ptr<AST::Type> type = nullptr;
-   if (lexer.peek_token ()->get_id () == COLON)
-     {
-       lexer.skip_token ();
- 
-       // parse type, which is now required
-       type = parse_type ();
-       if (type == nullptr)
- 	{
- 	  Error error (lexer.peek_token ()->get_locus (),
- 		       "failed to parse type in closure parameter");
- 	  add_error (std::move (error));
- 
- 	  // skip somewhere?
- 	  return AST::ClosureParam::create_error ();
- 	}
-     }
- 
-   location_t loc = pattern->get_locus ();
-   return AST::ClosureParam (std::move (pattern), loc, std::move (type),
- 			    std::move (outer_attrs));
- }
- 
- // Parses a grouped or tuple expression (disambiguates).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::ExprWithoutBlock>
- Parser<ManagedTokenSource>::parse_grouped_or_tuple_expr (
-   AST::AttrVec outer_attrs, location_t pratt_parsed_loc)
- {
-   // adjustment to allow Pratt parsing to reuse function without copy-paste
-   location_t locus = pratt_parsed_loc;
-   if (locus == UNKNOWN_LOCATION)
-     {
-       locus = lexer.peek_token ()->get_locus ();
-       skip_token (LEFT_PAREN);
-     }
- 
-   // parse optional inner attributes
-   AST::AttrVec inner_attrs = parse_inner_attributes ();
- 
-   if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
-     {
-       // must be empty tuple
-       lexer.skip_token ();
- 
-       // create tuple with empty tuple elems
-       return std::unique_ptr<AST::TupleExpr> (
- 	new AST::TupleExpr (std::vector<std::unique_ptr<AST::Expr>> (),
- 			    std::move (inner_attrs), std::move (outer_attrs),
- 			    locus));
-     }
- 
-   // parse first expression (required)
-   std::unique_ptr<AST::Expr> first_expr = parse_expr ();
-   if (first_expr == nullptr)
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "failed to parse expression in grouped or tuple expression");
-       add_error (std::move (error));
- 
-       // skip after somewhere?
-       return nullptr;
-     }
- 
-   // detect whether grouped expression with right parentheses as next token
-   if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
-     {
-       // must be grouped expr
-       lexer.skip_token ();
- 
-       // create grouped expr
-       return std::unique_ptr<AST::GroupedExpr> (
- 	new AST::GroupedExpr (std::move (first_expr), std::move (inner_attrs),
- 			      std::move (outer_attrs), locus));
-     }
-   else if (lexer.peek_token ()->get_id () == COMMA)
-     {
-       // tuple expr
-       std::vector<std::unique_ptr<AST::Expr>> exprs;
-       exprs.push_back (std::move (first_expr));
- 
-       // parse potential other tuple exprs
-       const_TokenPtr t = lexer.peek_token ();
-       while (t->get_id () == COMMA)
- 	{
- 	  lexer.skip_token ();
- 
- 	  // break out if right paren
- 	  if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
- 	    break;
- 
- 	  // parse expr, which is now required
- 	  std::unique_ptr<AST::Expr> expr = parse_expr ();
- 	  if (expr == nullptr)
- 	    {
- 	      Error error (lexer.peek_token ()->get_locus (),
- 			   "failed to parse expr in tuple expr");
- 	      add_error (std::move (error));
- 
- 	      // skip somewhere?
- 	      return nullptr;
- 	    }
- 	  exprs.push_back (std::move (expr));
- 
- 	  t = lexer.peek_token ();
- 	}
- 
-       // skip right paren
-       skip_token (RIGHT_PAREN);
- 
-       return std::unique_ptr<AST::TupleExpr> (
- 	new AST::TupleExpr (std::move (exprs), std::move (inner_attrs),
- 			    std::move (outer_attrs), locus));
-     }
-   else
-     {
-       // error
-       const_TokenPtr t = lexer.peek_token ();
-       Error error (t->get_locus (),
- 		   "unexpected token %qs in grouped or tuple expression "
- 		   "(parenthesised expression) - expected %<)%> for grouped "
- 		   "expr and %<,%> for tuple expr",
- 		   t->get_token_description ());
-       add_error (std::move (error));
- 
-       // skip somewhere?
-       return nullptr;
-     }
- }
- 
- // Parses a type (will further disambiguate any type).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::Type>
- Parser<ManagedTokenSource>::parse_type (bool save_errors)
- {
-   /* rules for all types:
-    * NeverType:               '!'
-    * SliceType:               '[' Type ']'
-    * InferredType:            '_'
-    * MacroInvocation:         SimplePath '!' DelimTokenTree
-    * ParenthesisedType:       '(' Type ')'
-    * ImplTraitType:           'impl' TypeParamBounds
-    *  TypeParamBounds (not type)  TypeParamBound ( '+' TypeParamBound )* '+'?
-    *  TypeParamBound          Lifetime | TraitBound
-    * ImplTraitTypeOneBound:   'impl' TraitBound
-    * TraitObjectType:         'dyn'? TypeParamBounds
-    * TraitObjectTypeOneBound: 'dyn'? TraitBound
-    *  TraitBound              '?'? ForLifetimes? TypePath | '(' '?'?
-    * ForLifetimes? TypePath ')' BareFunctionType:        ForLifetimes?
-    * FunctionQualifiers 'fn' etc. ForLifetimes (not type) 'for' '<'
-    * LifetimeParams '>' FunctionQualifiers      ( 'async' | 'const' )?
-    * 'unsafe'?
-    * ('extern' abi?)? QualifiedPathInType:     '<' Type ( 'as' TypePath )? '>'
-    * (
-    * '::' TypePathSegment )+ TypePath:                '::'? TypePathSegment (
-    * '::' TypePathSegment)* ArrayType:               '[' Type ';' Expr ']'
-    * ReferenceType:           '&' Lifetime? 'mut'? TypeNoBounds
-    * RawPointerType:          '*' ( 'mut' | 'const' ) TypeNoBounds
-    * TupleType:               '(' Type etc. - regular tuple stuff. Also
-    * regular tuple vs parenthesised precedence
-    *
-    * Disambiguate between macro and type path via type path being parsed, and
-    * then if '!' found, convert type path to simple path for macro. Usual
-    * disambiguation for tuple vs parenthesised. For ImplTraitType and
-    * TraitObjectType individual disambiguations, they seem more like "special
-    * cases", so probably just try to parse the more general ImplTraitType or
-    * TraitObjectType and return OneBound versions if they satisfy those
-    * criteria. */
- 
-   const_TokenPtr t = lexer.peek_token ();
-   switch (t->get_id ())
-     {
-     case EXCLAM:
-       // never type - can't be macro as no path beforehand
-       lexer.skip_token ();
-       return std::unique_ptr<AST::NeverType> (
- 	new AST::NeverType (t->get_locus ()));
-     case LEFT_SQUARE:
-       // slice type or array type - requires further disambiguation
-       return parse_slice_or_array_type ();
-     case LEFT_SHIFT:
-     case LEFT_ANGLE:
-       {
- 	// qualified path in type
- 	AST::QualifiedPathInType path = parse_qualified_path_in_type ();
- 	if (path.is_error ())
- 	  {
- 	    if (save_errors)
- 	      {
- 		Error error (t->get_locus (),
- 			     "failed to parse qualified path in type");
- 		add_error (std::move (error));
- 	      }
- 
- 	    return nullptr;
- 	  }
- 	return std::unique_ptr<AST::QualifiedPathInType> (
- 	  new AST::QualifiedPathInType (std::move (path)));
-       }
-     case UNDERSCORE:
-       // inferred type
-       lexer.skip_token ();
-       return std::unique_ptr<AST::InferredType> (
- 	new AST::InferredType (t->get_locus ()));
-     case ASTERISK:
-       // raw pointer type
-       return parse_raw_pointer_type ();
-     case AMP: // does this also include AMP_AMP?
-     case LOGICAL_AND:
-       // reference type
-       return parse_reference_type ();
-     case LIFETIME:
-       {
- 	/* probably a lifetime bound, so probably type param bounds in
- 	 * TraitObjectType */
- 	std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
- 	  = parse_type_param_bounds ();
- 
- 	return std::unique_ptr<AST::TraitObjectType> (
- 	  new AST::TraitObjectType (std::move (bounds), t->get_locus (),
- 				    false));
-       }
-     case IDENTIFIER:
-     case SUPER:
-     case SELF:
-     case SELF_ALIAS:
-     case CRATE:
-     case DOLLAR_SIGN:
-     case SCOPE_RESOLUTION:
-       {
- 	// macro invocation or type path - requires further disambiguation.
- 	/* for parsing path component of each rule, perhaps parse it as a
- 	 * typepath and attempt conversion to simplepath if a trailing '!' is
- 	 * found */
- 	/* Type path also includes TraitObjectTypeOneBound BUT if it starts
- 	 * with it, it is exactly the same as a TypePath syntactically, so
- 	 * this is a syntactical ambiguity. As such, the parser will parse it
- 	 * as a TypePath. This, however, does not prevent TraitObjectType from
- 	 * starting with a typepath. */
- 
- 	// parse path as type path
- 	AST::TypePath path = parse_type_path ();
- 	if (path.is_error ())
- 	  {
- 	    if (save_errors)
- 	      {
- 		Error error (t->get_locus (),
- 			     "failed to parse path as first component of type");
- 		add_error (std::move (error));
- 	      }
- 
- 	    return nullptr;
- 	  }
- 	location_t locus = path.get_locus ();
- 
- 	// branch on next token
- 	t = lexer.peek_token ();
- 	switch (t->get_id ())
- 	  {
- 	  case EXCLAM:
- 	    {
- 	      // macro invocation
- 	      // convert to simple path
- 	      AST::SimplePath macro_path = path.as_simple_path ();
- 	      if (macro_path.is_empty ())
- 		{
- 		  if (save_errors)
- 		    {
- 		      Error error (t->get_locus (),
- 				   "failed to parse simple path in macro "
- 				   "invocation (for type)");
- 		      add_error (std::move (error));
- 		    }
- 
- 		  return nullptr;
- 		}
- 
- 	      lexer.skip_token ();
- 
- 	      AST::DelimTokenTree tok_tree = parse_delim_token_tree ();
- 
- 	      return AST::MacroInvocation::Regular (
- 		AST::MacroInvocData (std::move (macro_path),
- 				     std::move (tok_tree)),
- 		{}, locus);
- 	    }
- 	  case PLUS:
- 	    {
- 	      // type param bounds
- 	      std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
- 
- 	      // convert type path to trait bound
- 	      std::unique_ptr<AST::TraitBound> path_bound (
- 		new AST::TraitBound (std::move (path), locus, false, false));
- 	      bounds.push_back (std::move (path_bound));
- 
- 	      /* parse rest of bounds - FIXME: better way to find when to stop
- 	       * parsing */
- 	      while (t->get_id () == PLUS)
- 		{
- 		  lexer.skip_token ();
- 
- 		  // parse bound if it exists - if not, assume end of sequence
- 		  std::unique_ptr<AST::TypeParamBound> bound
- 		    = parse_type_param_bound ();
- 		  if (bound == nullptr)
- 		    {
- 		      break;
- 		    }
- 		  bounds.push_back (std::move (bound));
- 
- 		  t = lexer.peek_token ();
- 		}
- 
- 	      return std::unique_ptr<AST::TraitObjectType> (
- 		new AST::TraitObjectType (std::move (bounds), locus, false));
- 	    }
- 	  default:
- 	    // assume that this is a type path and not an error
- 	    return std::unique_ptr<AST::TypePath> (
- 	      new AST::TypePath (std::move (path)));
- 	  }
-       }
-     case LEFT_PAREN:
-       /* tuple type or parenthesised type - requires further disambiguation
-        * (the usual). ok apparently can be a parenthesised TraitBound too, so
-        * could be TraitObjectTypeOneBound or TraitObjectType */
-       return parse_paren_prefixed_type ();
-     case FOR:
-       // TraitObjectTypeOneBound or BareFunctionType
-       return parse_for_prefixed_type ();
-     case ASYNC:
-     case CONST:
-     case UNSAFE:
-     case EXTERN_KW:
-     case FN_KW:
-       // bare function type (with no for lifetimes)
-       return parse_bare_function_type (std::vector<AST::LifetimeParam> ());
-     case IMPL:
-       lexer.skip_token ();
-       if (lexer.peek_token ()->get_id () == LIFETIME)
- 	{
- 	  /* cannot be one bound because lifetime prevents it from being
- 	   * traitbound */
- 	  std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
- 	    = parse_type_param_bounds ();
- 
- 	  return std::unique_ptr<AST::ImplTraitType> (
- 	    new AST::ImplTraitType (std::move (bounds), t->get_locus ()));
- 	}
-       else
- 	{
- 	  // should be trait bound, so parse trait bound
- 	  std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound ();
- 	  if (initial_bound == nullptr)
- 	    {
- 	      if (save_errors)
- 		{
- 		  Error error (lexer.peek_token ()->get_locus (),
- 			       "failed to parse ImplTraitType initial bound");
- 		  add_error (std::move (error));
- 		}
- 
- 	      return nullptr;
- 	    }
- 
- 	  location_t locus = t->get_locus ();
- 
- 	  // short cut if next token isn't '+'
- 	  t = lexer.peek_token ();
- 	  if (t->get_id () != PLUS)
- 	    {
- 	      return std::unique_ptr<AST::ImplTraitTypeOneBound> (
- 		new AST::ImplTraitTypeOneBound (std::move (initial_bound),
- 						locus));
- 	    }
- 
- 	  // parse additional type param bounds
- 	  std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
- 	  bounds.push_back (std::move (initial_bound));
- 	  while (t->get_id () == PLUS)
- 	    {
- 	      lexer.skip_token ();
- 
- 	      // parse bound if it exists
- 	      std::unique_ptr<AST::TypeParamBound> bound
- 		= parse_type_param_bound ();
- 	      if (bound == nullptr)
- 		{
- 		  // not an error as trailing plus may exist
- 		  break;
- 		}
- 	      bounds.push_back (std::move (bound));
- 
- 	      t = lexer.peek_token ();
- 	    }
- 
- 	  return std::unique_ptr<AST::ImplTraitType> (
- 	    new AST::ImplTraitType (std::move (bounds), locus));
- 	}
-     case DYN:
-     case QUESTION_MARK:
-       {
- 	// either TraitObjectType or TraitObjectTypeOneBound
- 	bool has_dyn = false;
- 	if (t->get_id () == DYN)
- 	  {
- 	    lexer.skip_token ();
- 	    has_dyn = true;
- 	  }
- 
- 	if (lexer.peek_token ()->get_id () == LIFETIME)
- 	  {
- 	    /* cannot be one bound because lifetime prevents it from being
- 	     * traitbound */
- 	    std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
- 	      = parse_type_param_bounds ();
- 
- 	    return std::unique_ptr<AST::TraitObjectType> (
- 	      new AST::TraitObjectType (std::move (bounds), t->get_locus (),
- 					has_dyn));
- 	  }
- 	else
- 	  {
- 	    // should be trait bound, so parse trait bound
- 	    std::unique_ptr<AST::TraitBound> initial_bound
- 	      = parse_trait_bound ();
- 	    if (initial_bound == nullptr)
- 	      {
- 		if (save_errors)
- 		  {
- 		    Error error (
- 		      lexer.peek_token ()->get_locus (),
- 		      "failed to parse TraitObjectType initial bound");
- 		    add_error (std::move (error));
- 		  }
- 
- 		return nullptr;
- 	      }
- 
- 	    // short cut if next token isn't '+'
- 	    t = lexer.peek_token ();
- 	    if (t->get_id () != PLUS)
- 	      {
- 		// convert trait bound to value object
- 		AST::TraitBound value_bound (*initial_bound);
- 
- 		// DEBUG: removed as unique ptr, so should auto delete
- 		// delete initial_bound;
- 
- 		return std::unique_ptr<AST::TraitObjectTypeOneBound> (
- 		  new AST::TraitObjectTypeOneBound (std::move (value_bound),
- 						    t->get_locus (), has_dyn));
- 	      }
- 
- 	    // parse additional type param bounds
- 	    std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
- 	    bounds.push_back (std::move (initial_bound));
- 	    while (t->get_id () == PLUS)
- 	      {
- 		lexer.skip_token ();
- 
- 		// parse bound if it exists
- 		std::unique_ptr<AST::TypeParamBound> bound
- 		  = parse_type_param_bound ();
- 		if (bound == nullptr)
- 		  {
- 		    // not an error as trailing plus may exist
- 		    break;
- 		  }
- 		bounds.push_back (std::move (bound));
- 
- 		t = lexer.peek_token ();
- 	      }
- 
- 	    return std::unique_ptr<AST::TraitObjectType> (
- 	      new AST::TraitObjectType (std::move (bounds), t->get_locus (),
- 					has_dyn));
- 	  }
-       }
-     default:
-       if (save_errors)
- 	add_error (Error (t->get_locus (), "unrecognised token %qs in type",
- 			  t->get_token_description ()));
- 
-       return nullptr;
-     }
- }
- 
- /* Parses a type that has '(' as its first character. Returns a tuple type,
-  * parenthesised type, TraitObjectTypeOneBound, or TraitObjectType depending
-  * on following characters. */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::Type>
- Parser<ManagedTokenSource>::parse_paren_prefixed_type ()
- {
-   /* NOTE: Syntactical ambiguity of a parenthesised trait bound is considered
-    * a trait bound, not a parenthesised type, so that it can still be used in
-    * type param bounds. */
- 
-   /* NOTE: this implementation is really shit but I couldn't think of a better
-    * one. It requires essentially breaking polymorphism and downcasting via
-    * virtual method abuse, as it was copied from the rustc implementation (in
-    * which types are reified due to tagged union), after a more OOP attempt by
-    * me failed. */
-   location_t left_delim_locus = lexer.peek_token ()->get_locus ();
- 
-   // skip left delim
-   lexer.skip_token ();
-   /* while next token isn't close delim, parse comma-separated types, saving
-    * whether trailing comma happens */
-   const_TokenPtr t = lexer.peek_token ();
-   bool trailing_comma = true;
-   std::vector<std::unique_ptr<AST::Type>> types;
- 
-   while (t->get_id () != RIGHT_PAREN)
-     {
-       std::unique_ptr<AST::Type> type = parse_type ();
-       if (type == nullptr)
- 	{
- 	  Error error (t->get_locus (),
- 		       "failed to parse type inside parentheses (probably "
- 		       "tuple or parenthesised)");
- 	  add_error (std::move (error));
- 
- 	  return nullptr;
- 	}
-       types.push_back (std::move (type));
- 
-       t = lexer.peek_token ();
-       if (t->get_id () != COMMA)
- 	{
- 	  trailing_comma = false;
- 	  break;
- 	}
-       lexer.skip_token ();
- 
-       t = lexer.peek_token ();
-     }
- 
-   if (!skip_token (RIGHT_PAREN))
-     {
-       return nullptr;
-     }
- 
-   // if only one type and no trailing comma, then not a tuple type
-   if (types.size () == 1 && !trailing_comma)
-     {
-       // must be a TraitObjectType (with more than one bound)
-       if (lexer.peek_token ()->get_id () == PLUS)
- 	{
- 	  // create type param bounds vector
- 	  std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
- 
- 	  // HACK: convert type to traitbound and add to bounds
- 	  std::unique_ptr<AST::Type> released_ptr = std::move (types[0]);
- 	  std::unique_ptr<AST::TraitBound> converted_bound (
- 	    released_ptr->to_trait_bound (true));
- 	  if (converted_bound == nullptr)
- 	    {
- 	      Error error (
- 		lexer.peek_token ()->get_locus (),
- 		"failed to hackily converted parsed type to trait bound");
- 	      add_error (std::move (error));
- 
- 	      return nullptr;
- 	    }
- 	  bounds.push_back (std::move (converted_bound));
- 
- 	  t = lexer.peek_token ();
- 	  while (t->get_id () == PLUS)
- 	    {
- 	      lexer.skip_token ();
- 
- 	      // attempt to parse typeparambound
- 	      std::unique_ptr<AST::TypeParamBound> bound
- 		= parse_type_param_bound ();
- 	      if (bound == nullptr)
- 		{
- 		  // not an error if null
- 		  break;
- 		}
- 	      bounds.push_back (std::move (bound));
- 
- 	      t = lexer.peek_token ();
- 	    }
- 
- 	  return std::unique_ptr<AST::TraitObjectType> (
- 	    new AST::TraitObjectType (std::move (bounds), left_delim_locus,
- 				      false));
- 	}
-       else
- 	{
- 	  // release vector pointer
- 	  std::unique_ptr<AST::Type> released_ptr = std::move (types[0]);
- 	  /* HACK: attempt to convert to trait bound. if fails, parenthesised
- 	   * type */
- 	  std::unique_ptr<AST::TraitBound> converted_bound (
- 	    released_ptr->to_trait_bound (true));
- 	  if (converted_bound == nullptr)
- 	    {
- 	      // parenthesised type
- 	      return std::unique_ptr<AST::ParenthesisedType> (
- 		new AST::ParenthesisedType (std::move (released_ptr),
- 					    left_delim_locus));
- 	    }
- 	  else
- 	    {
- 	      // trait object type (one bound)
- 
- 	      // get value semantics trait bound
- 	      AST::TraitBound value_bound (*converted_bound);
- 
- 	      return std::unique_ptr<AST::TraitObjectTypeOneBound> (
- 		new AST::TraitObjectTypeOneBound (value_bound,
- 						  left_delim_locus));
- 	    }
- 	}
-     }
-   else
-     {
-       return std::unique_ptr<AST::TupleType> (
- 	new AST::TupleType (std::move (types), left_delim_locus));
-     }
-   /* TODO: ensure that this ensures that dynamic dispatch for traits is not
-    * lost somehow */
- }
- 
- /* Parses a type that has 'for' as its first character. This means it has a
-  * "for lifetimes", so returns either a BareFunctionType, TraitObjectType, or
-  * TraitObjectTypeOneBound depending on following characters. */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::Type>
- Parser<ManagedTokenSource>::parse_for_prefixed_type ()
- {
-   location_t for_locus = lexer.peek_token ()->get_locus ();
-   // parse for lifetimes in type
-   std::vector<AST::LifetimeParam> for_lifetimes = parse_for_lifetimes ();
- 
-   // branch on next token - either function or a trait type
-   const_TokenPtr t = lexer.peek_token ();
-   switch (t->get_id ())
-     {
-     case ASYNC:
-     case CONST:
-     case UNSAFE:
-     case EXTERN_KW:
-     case FN_KW:
-       return parse_bare_function_type (std::move (for_lifetimes));
-     case SCOPE_RESOLUTION:
-     case IDENTIFIER:
-     case SUPER:
-     case SELF:
-     case SELF_ALIAS:
-     case CRATE:
-     case DOLLAR_SIGN:
-       {
- 	// path, so trait type
- 
- 	// parse type path to finish parsing trait bound
- 	AST::TypePath path = parse_type_path ();
- 
- 	t = lexer.peek_token ();
- 	if (t->get_id () != PLUS)
- 	  {
- 	    // must be one-bound trait type
- 	    // create trait bound value object
- 	    AST::TraitBound bound (std::move (path), for_locus, false, false,
- 				   std::move (for_lifetimes));
- 
- 	    return std::unique_ptr<AST::TraitObjectTypeOneBound> (
- 	      new AST::TraitObjectTypeOneBound (std::move (bound), for_locus));
- 	  }
- 
- 	/* more than one bound trait type (or at least parsed as it - could be
- 	 * trailing '+') create trait bound pointer and bounds */
- 	std::unique_ptr<AST::TraitBound> initial_bound (
- 	  new AST::TraitBound (std::move (path), for_locus, false, false,
- 			       std::move (for_lifetimes)));
- 	std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
- 	bounds.push_back (std::move (initial_bound));
- 
- 	while (t->get_id () == PLUS)
- 	  {
- 	    lexer.skip_token ();
- 
- 	    // parse type param bound if it exists
- 	    std::unique_ptr<AST::TypeParamBound> bound
- 	      = parse_type_param_bound ();
- 	    if (bound == nullptr)
- 	      {
- 		// not an error - e.g. trailing plus
- 		return nullptr;
- 	      }
- 	    bounds.push_back (std::move (bound));
- 
- 	    t = lexer.peek_token ();
- 	  }
- 
- 	return std::unique_ptr<AST::TraitObjectType> (
- 	  new AST::TraitObjectType (std::move (bounds), for_locus, false));
-       }
-     default:
-       // error
-       add_error (Error (t->get_locus (),
- 			"unrecognised token %qs in bare function type or trait "
- 			"object type or trait object type one bound",
- 			t->get_token_description ()));
- 
-       return nullptr;
-     }
- }
- 
- // Parses a maybe named param used in bare function types.
- template <typename ManagedTokenSource>
- AST::MaybeNamedParam
- Parser<ManagedTokenSource>::parse_maybe_named_param (AST::AttrVec outer_attrs)
- {
-   /* Basically guess that param is named if first token is identifier or
-    * underscore and second token is semicolon. This should probably have no
-    * exceptions. rustc uses backtracking to parse these, but at the time of
-    * writing gccrs has no backtracking capabilities. */
-   const_TokenPtr current = lexer.peek_token ();
-   const_TokenPtr next = lexer.peek_token (1);
- 
-   Identifier name;
-   AST::MaybeNamedParam::ParamKind kind = AST::MaybeNamedParam::UNNAMED;
- 
-   if (current->get_id () == IDENTIFIER && next->get_id () == COLON)
-     {
-       // named param
-       name = {current};
-       kind = AST::MaybeNamedParam::IDENTIFIER;
-       lexer.skip_token (1);
-     }
-   else if (current->get_id () == UNDERSCORE && next->get_id () == COLON)
-     {
-       // wildcard param
-       name = {Values::Keywords::UNDERSCORE, current->get_locus ()};
-       kind = AST::MaybeNamedParam::WILDCARD;
-       lexer.skip_token (1);
-     }
- 
-   // parse type (required)
-   std::unique_ptr<AST::Type> type = parse_type ();
-   if (type == nullptr)
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "failed to parse type in maybe named param");
-       add_error (std::move (error));
- 
-       return AST::MaybeNamedParam::create_error ();
-     }
- 
-   return AST::MaybeNamedParam (std::move (name), kind, std::move (type),
- 			       std::move (outer_attrs), current->get_locus ());
- }
- 
- /* Parses a bare function type (with the given for lifetimes for convenience -
-  * does not parse them itself). */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::BareFunctionType>
- Parser<ManagedTokenSource>::parse_bare_function_type (
-   std::vector<AST::LifetimeParam> for_lifetimes)
- {
-   // TODO: pass in for lifetime location as param
-   location_t best_try_locus = lexer.peek_token ()->get_locus ();
- 
-   AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
- 
-   if (!skip_token (FN_KW))
-     return nullptr;
- 
-   if (!skip_token (LEFT_PAREN))
-     return nullptr;
- 
-   // parse function params, if they exist
-   std::vector<AST::MaybeNamedParam> params;
-   bool is_variadic = false;
-   AST::AttrVec variadic_attrs;
- 
-   const_TokenPtr t = lexer.peek_token ();
-   while (t->get_id () != RIGHT_PAREN)
-     {
-       AST::AttrVec temp_attrs = parse_outer_attributes ();
- 
-       if (lexer.peek_token ()->get_id () == ELLIPSIS)
- 	{
- 	  lexer.skip_token ();
- 	  is_variadic = true;
- 	  variadic_attrs = std::move (temp_attrs);
- 
- 	  t = lexer.peek_token ();
- 
- 	  if (t->get_id () != RIGHT_PAREN)
- 	    {
- 	      Error error (t->get_locus (),
- 			   "expected right parentheses after variadic in maybe "
- 			   "named function "
- 			   "parameters, found %qs",
- 			   t->get_token_description ());
- 	      add_error (std::move (error));
- 
- 	      return nullptr;
- 	    }
- 
- 	  break;
- 	}
- 
-       AST::MaybeNamedParam param
- 	= parse_maybe_named_param (std::move (temp_attrs));
-       if (param.is_error ())
- 	{
- 	  Error error (
- 	    lexer.peek_token ()->get_locus (),
- 	    "failed to parse maybe named param in bare function type");
- 	  add_error (std::move (error));
- 
- 	  return nullptr;
- 	}
-       params.push_back (std::move (param));
- 
-       if (lexer.peek_token ()->get_id () != COMMA)
- 	break;
- 
-       lexer.skip_token ();
-       t = lexer.peek_token ();
-     }
- 
-   if (!skip_token (RIGHT_PAREN))
-     return nullptr;
- 
-   // bare function return type, if exists
-   std::unique_ptr<AST::TypeNoBounds> return_type = nullptr;
-   if (lexer.peek_token ()->get_id () == RETURN_TYPE)
-     {
-       lexer.skip_token ();
- 
-       // parse required TypeNoBounds
-       return_type = parse_type_no_bounds ();
-       if (return_type == nullptr)
- 	{
- 	  Error error (lexer.peek_token ()->get_locus (),
- 		       "failed to parse return type (type no bounds) in bare "
- 		       "function type");
- 	  add_error (std::move (error));
- 
- 	  return nullptr;
- 	}
-     }
- 
-   return std::unique_ptr<AST::BareFunctionType> (
-     new AST::BareFunctionType (std::move (for_lifetimes),
- 			       std::move (qualifiers), std::move (params),
- 			       is_variadic, std::move (variadic_attrs),
- 			       std::move (return_type), best_try_locus));
- }
- 
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::ReferenceType>
- Parser<ManagedTokenSource>::parse_reference_type_inner (location_t locus)
- {
-   // parse optional lifetime
-   AST::Lifetime lifetime = AST::Lifetime::elided ();
-   if (lexer.peek_token ()->get_id () == LIFETIME)
-     {
-       auto parsed_lifetime = parse_lifetime (true);
-       if (parsed_lifetime)
- 	{
- 	  lifetime = parsed_lifetime.value ();
- 	}
-       else
- 	{
- 	  Error error (lexer.peek_token ()->get_locus (),
- 		       "failed to parse lifetime in reference type");
- 	  add_error (std::move (error));
- 
- 	  return nullptr;
- 	}
-     }
- 
-   bool is_mut = false;
-   if (lexer.peek_token ()->get_id () == MUT)
-     {
-       lexer.skip_token ();
-       is_mut = true;
-     }
- 
-   // parse type no bounds, which is required
-   std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
-   if (type == nullptr)
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "failed to parse referenced type in reference type");
-       add_error (std::move (error));
- 
-       return nullptr;
-     }
- 
-   return std::unique_ptr<AST::ReferenceType> (
-     new AST::ReferenceType (is_mut, std::move (type), locus,
- 			    std::move (lifetime)));
- }
- 
- // Parses a reference type (mutable or immutable, with given lifetime).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::ReferenceType>
- Parser<ManagedTokenSource>::parse_reference_type ()
- {
-   auto t = lexer.peek_token ();
-   auto locus = t->get_locus ();
- 
-   switch (t->get_id ())
-     {
-     case AMP:
-       skip_token (AMP);
-       return parse_reference_type_inner (locus);
-     case LOGICAL_AND:
-       skip_token (LOGICAL_AND);
-       return std::unique_ptr<AST::ReferenceType> (
- 	new AST::ReferenceType (false, parse_reference_type_inner (locus),
- 				locus));
-     default:
-       rust_unreachable ();
-     }
- }
- 
- // Parses a raw (unsafe) pointer type.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::RawPointerType>
- Parser<ManagedTokenSource>::parse_raw_pointer_type ()
- {
-   location_t locus = lexer.peek_token ()->get_locus ();
-   skip_token (ASTERISK);
- 
-   AST::RawPointerType::PointerType kind = AST::RawPointerType::CONST;
- 
-   // branch on next token for pointer kind info
-   const_TokenPtr t = lexer.peek_token ();
-   switch (t->get_id ())
-     {
-     case MUT:
-       kind = AST::RawPointerType::MUT;
-       lexer.skip_token ();
-       break;
-     case CONST:
-       kind = AST::RawPointerType::CONST;
-       lexer.skip_token ();
-       break;
-     default:
-       add_error (Error (t->get_locus (),
- 			"unrecognised token %qs in raw pointer type",
- 			t->get_token_description ()));
- 
-       return nullptr;
-     }
- 
-   // parse type no bounds (required)
-   std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
-   if (type == nullptr)
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "failed to parse pointed type of raw pointer type");
-       add_error (std::move (error));
- 
-       return nullptr;
-     }
- 
-   return std::unique_ptr<AST::RawPointerType> (
-     new AST::RawPointerType (kind, std::move (type), locus));
- }
- 
- /* Parses a slice or array type, depending on following arguments (as
-  * lookahead is not possible). */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::TypeNoBounds>
- Parser<ManagedTokenSource>::parse_slice_or_array_type ()
- {
-   location_t locus = lexer.peek_token ()->get_locus ();
-   skip_token (LEFT_SQUARE);
- 
-   // parse inner type (required)
-   std::unique_ptr<AST::Type> inner_type = parse_type ();
-   if (inner_type == nullptr)
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "failed to parse inner type in slice or array type");
-       add_error (std::move (error));
- 
-       return nullptr;
-     }
- 
-   // branch on next token
-   const_TokenPtr t = lexer.peek_token ();
-   switch (t->get_id ())
-     {
-     case RIGHT_SQUARE:
-       // slice type
-       lexer.skip_token ();
- 
-       return std::unique_ptr<AST::SliceType> (
- 	new AST::SliceType (std::move (inner_type), locus));
-     case SEMICOLON:
-       {
- 	// array type
- 	lexer.skip_token ();
- 
- 	// parse required array size expression
- 	auto size = parse_anon_const ();
- 
- 	if (!size)
- 	  {
- 	    Error error (lexer.peek_token ()->get_locus (),
- 			 "failed to parse size expression in array type");
- 	    add_error (std::move (error));
- 
- 	    return nullptr;
- 	  }
- 
- 	if (!skip_token (RIGHT_SQUARE))
- 	  {
- 	    return nullptr;
- 	  }
- 
- 	return std::unique_ptr<AST::ArrayType> (
- 	  new AST::ArrayType (std::move (inner_type), std::move (*size),
- 			      locus));
-       }
-     default:
-       // error
-       add_error (
- 	Error (t->get_locus (),
- 	       "unrecognised token %qs in slice or array type after inner type",
- 	       t->get_token_description ()));
- 
-       return nullptr;
-     }
- }
- 
- // Parses a type, taking into account type boundary disambiguation.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::TypeNoBounds>
- Parser<ManagedTokenSource>::parse_type_no_bounds ()
- {
-   const_TokenPtr t = lexer.peek_token ();
-   switch (t->get_id ())
-     {
-     case EXCLAM:
-       // never type - can't be macro as no path beforehand
-       lexer.skip_token ();
-       return std::unique_ptr<AST::NeverType> (
- 	new AST::NeverType (t->get_locus ()));
-     case LEFT_SQUARE:
-       // slice type or array type - requires further disambiguation
-       return parse_slice_or_array_type ();
-     case LEFT_SHIFT:
-     case LEFT_ANGLE:
-       {
- 	// qualified path in type
- 	AST::QualifiedPathInType path = parse_qualified_path_in_type ();
- 	if (path.is_error ())
- 	  {
- 	    Error error (t->get_locus (),
- 			 "failed to parse qualified path in type");
- 	    add_error (std::move (error));
- 
- 	    return nullptr;
- 	  }
- 	return std::unique_ptr<AST::QualifiedPathInType> (
- 	  new AST::QualifiedPathInType (std::move (path)));
-       }
-     case UNDERSCORE:
-       // inferred type
-       lexer.skip_token ();
-       return std::unique_ptr<AST::InferredType> (
- 	new AST::InferredType (t->get_locus ()));
-     case ASTERISK:
-       // raw pointer type
-       return parse_raw_pointer_type ();
-     case AMP: // does this also include AMP_AMP? Yes! Which is... LOGICAL_AND?
-     case LOGICAL_AND:
-       // reference type
-       return parse_reference_type ();
-     case LIFETIME:
-       /* probably a lifetime bound, so probably type param bounds in
-        * TraitObjectType. this is not allowed, but detection here for error
-        * message */
-       add_error (Error (t->get_locus (),
- 			"lifetime bounds (i.e. in type param bounds, in "
- 			"TraitObjectType) are not allowed as TypeNoBounds"));
- 
-       return nullptr;
-     case IDENTIFIER:
-     case SUPER:
-     case SELF:
-     case SELF_ALIAS:
-     case CRATE:
-     case DOLLAR_SIGN:
-     case SCOPE_RESOLUTION:
-       {
- 	// macro invocation or type path - requires further disambiguation.
- 	/* for parsing path component of each rule, perhaps parse it as a
- 	 * typepath and attempt conversion to simplepath if a trailing '!' is
- 	 * found */
- 	/* Type path also includes TraitObjectTypeOneBound BUT if it starts
- 	 * with it, it is exactly the same as a TypePath syntactically, so
- 	 * this is a syntactical ambiguity. As such, the parser will parse it
- 	 * as a TypePath. This, however, does not prevent TraitObjectType from
- 	 * starting with a typepath. */
- 
- 	// parse path as type path
- 	AST::TypePath path = parse_type_path ();
- 	if (path.is_error ())
- 	  {
- 	    Error error (
- 	      t->get_locus (),
- 	      "failed to parse path as first component of type no bounds");
- 	    add_error (std::move (error));
- 
- 	    return nullptr;
- 	  }
- 	location_t locus = path.get_locus ();
- 
- 	// branch on next token
- 	t = lexer.peek_token ();
- 	switch (t->get_id ())
- 	  {
- 	  case EXCLAM:
- 	    {
- 	      // macro invocation
- 	      // convert to simple path
- 	      AST::SimplePath macro_path = path.as_simple_path ();
- 	      if (macro_path.is_empty ())
- 		{
- 		  Error error (t->get_locus (),
- 			       "failed to parse simple path in macro "
- 			       "invocation (for type)");
- 		  add_error (std::move (error));
- 
- 		  return nullptr;
- 		}
- 
- 	      lexer.skip_token ();
- 
- 	      AST::DelimTokenTree tok_tree = parse_delim_token_tree ();
- 
- 	      return AST::MacroInvocation::Regular (
- 		AST::MacroInvocData (std::move (macro_path),
- 				     std::move (tok_tree)),
- 		{}, locus);
- 	    }
- 	  default:
- 	    // assume that this is a type path and not an error
- 	    return std::unique_ptr<AST::TypePath> (
- 	      new AST::TypePath (std::move (path)));
- 	  }
-       }
-     case LEFT_PAREN:
-       /* tuple type or parenthesised type - requires further disambiguation
-        * (the usual). ok apparently can be a parenthesised TraitBound too, so
-        * could be TraitObjectTypeOneBound */
-       return parse_paren_prefixed_type_no_bounds ();
-     case FOR:
-     case ASYNC:
-     case CONST:
-     case UNSAFE:
-     case EXTERN_KW:
-     case FN_KW:
-       // bare function type (with no for lifetimes)
-       return parse_bare_function_type (std::vector<AST::LifetimeParam> ());
-     case IMPL:
-       lexer.skip_token ();
-       if (lexer.peek_token ()->get_id () == LIFETIME)
- 	{
- 	  /* cannot be one bound because lifetime prevents it from being
- 	   * traitbound not allowed as type no bounds, only here for error
- 	   * message */
- 	  Error error (
- 	    lexer.peek_token ()->get_locus (),
- 	    "lifetime (probably lifetime bound, in type param "
- 	    "bounds, in ImplTraitType) is not allowed in TypeNoBounds");
- 	  add_error (std::move (error));
- 
- 	  return nullptr;
- 	}
-       else
- 	{
- 	  // should be trait bound, so parse trait bound
- 	  std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound ();
- 	  if (initial_bound == nullptr)
- 	    {
- 	      Error error (lexer.peek_token ()->get_locus (),
- 			   "failed to parse ImplTraitTypeOneBound bound");
- 	      add_error (std::move (error));
- 
- 	      return nullptr;
- 	    }
- 
- 	  location_t locus = t->get_locus ();
- 
- 	  // ensure not a trait with multiple bounds
- 	  t = lexer.peek_token ();
- 	  if (t->get_id () == PLUS)
- 	    {
- 	      Error error (t->get_locus (),
- 			   "plus after trait bound means an ImplTraitType, "
- 			   "which is not allowed as a TypeNoBounds");
- 	      add_error (std::move (error));
- 
- 	      return nullptr;
- 	    }
- 
- 	  return std::unique_ptr<AST::ImplTraitTypeOneBound> (
- 	    new AST::ImplTraitTypeOneBound (std::move (initial_bound), locus));
- 	}
-     case DYN:
-     case QUESTION_MARK:
-       {
- 	// either TraitObjectTypeOneBound
- 	bool has_dyn = false;
- 	if (t->get_id () == DYN)
- 	  {
- 	    lexer.skip_token ();
- 	    has_dyn = true;
- 	  }
- 
- 	if (lexer.peek_token ()->get_id () == LIFETIME)
- 	  {
- 	    /* means that cannot be TraitObjectTypeOneBound - so here for
- 	     * error message */
- 	    Error error (lexer.peek_token ()->get_locus (),
- 			 "lifetime as bound in TraitObjectTypeOneBound "
- 			 "is not allowed, so cannot be TypeNoBounds");
- 	    add_error (std::move (error));
- 
- 	    return nullptr;
- 	  }
- 
- 	// should be trait bound, so parse trait bound
- 	std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound ();
- 	if (initial_bound == nullptr)
- 	  {
- 	    Error error (
- 	      lexer.peek_token ()->get_locus (),
- 	      "failed to parse TraitObjectTypeOneBound initial bound");
- 	    add_error (std::move (error));
- 
- 	    return nullptr;
- 	  }
- 
- 	location_t locus = t->get_locus ();
- 
- 	// detect error with plus as next token
- 	t = lexer.peek_token ();
- 	if (t->get_id () == PLUS)
- 	  {
- 	    Error error (t->get_locus (),
- 			 "plus after trait bound means a TraitObjectType, "
- 			 "which is not allowed as a TypeNoBounds");
- 	    add_error (std::move (error));
- 
- 	    return nullptr;
- 	  }
- 
- 	// convert trait bound to value object
- 	AST::TraitBound value_bound (*initial_bound);
- 
- 	return std::unique_ptr<AST::TraitObjectTypeOneBound> (
- 	  new AST::TraitObjectTypeOneBound (std::move (value_bound), locus,
- 					    has_dyn));
-       }
-     default:
-       add_error (Error (t->get_locus (),
- 			"unrecognised token %qs in type no bounds",
- 			t->get_token_description ()));
- 
-       return nullptr;
-     }
- }
- 
- // Parses a type no bounds beginning with '('.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::TypeNoBounds>
- Parser<ManagedTokenSource>::parse_paren_prefixed_type_no_bounds ()
- {
-   /* NOTE: this could probably be parsed without the HACK solution of
-    * parse_paren_prefixed_type, but I was lazy. So FIXME for future.*/
- 
-   /* NOTE: again, syntactical ambiguity of a parenthesised trait bound is
-    * considered a trait bound, not a parenthesised type, so that it can still
-    * be used in type param bounds. */
- 
-   location_t left_paren_locus = lexer.peek_token ()->get_locus ();
- 
-   // skip left delim
-   lexer.skip_token ();
-   /* while next token isn't close delim, parse comma-separated types, saving
-    * whether trailing comma happens */
-   const_TokenPtr t = lexer.peek_token ();
-   bool trailing_comma = true;
-   std::vector<std::unique_ptr<AST::Type>> types;
- 
-   while (t->get_id () != RIGHT_PAREN)
-     {
-       std::unique_ptr<AST::Type> type = parse_type ();
-       if (type == nullptr)
- 	{
- 	  Error error (t->get_locus (),
- 		       "failed to parse type inside parentheses (probably "
- 		       "tuple or parenthesised)");
- 	  add_error (std::move (error));
- 
- 	  return nullptr;
- 	}
-       types.push_back (std::move (type));
- 
-       t = lexer.peek_token ();
-       if (t->get_id () != COMMA)
- 	{
- 	  trailing_comma = false;
- 	  break;
- 	}
-       lexer.skip_token ();
- 
-       t = lexer.peek_token ();
-     }
- 
-   if (!skip_token (RIGHT_PAREN))
-     {
-       return nullptr;
-     }
- 
-   // if only one type and no trailing comma, then not a tuple type
-   if (types.size () == 1 && !trailing_comma)
-     {
-       // must be a TraitObjectType (with more than one bound)
-       if (lexer.peek_token ()->get_id () == PLUS)
- 	{
- 	  // error - this is not allowed for type no bounds
- 	  Error error (lexer.peek_token ()->get_locus (),
- 		       "plus (implying TraitObjectType as type param "
- 		       "bounds) is not allowed in type no bounds");
- 	  add_error (std::move (error));
- 
- 	  return nullptr;
- 	}
-       else
- 	{
- 	  // release vector pointer
- 	  std::unique_ptr<AST::Type> released_ptr = std::move (types[0]);
- 	  /* HACK: attempt to convert to trait bound. if fails, parenthesised
- 	   * type */
- 	  std::unique_ptr<AST::TraitBound> converted_bound (
- 	    released_ptr->to_trait_bound (true));
- 	  if (converted_bound == nullptr)
- 	    {
- 	      // parenthesised type
- 	      return std::unique_ptr<AST::ParenthesisedType> (
- 		new AST::ParenthesisedType (std::move (released_ptr),
- 					    left_paren_locus));
- 	    }
- 	  else
- 	    {
- 	      // trait object type (one bound)
- 
- 	      // get value semantics trait bound
- 	      AST::TraitBound value_bound (*converted_bound);
- 
- 	      return std::unique_ptr<AST::TraitObjectTypeOneBound> (
- 		new AST::TraitObjectTypeOneBound (value_bound,
- 						  left_paren_locus));
- 	    }
- 	}
-     }
-   else
-     {
-       return std::unique_ptr<AST::TupleType> (
- 	new AST::TupleType (std::move (types), left_paren_locus));
-     }
-   /* TODO: ensure that this ensures that dynamic dispatch for traits is not
-    * lost somehow */
- }
- 
- /* Parses a literal pattern or range pattern. Assumes that literals passed in
-  * are valid range pattern bounds. Do not pass in paths in expressions, for
-  * instance. */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::Pattern>
- Parser<ManagedTokenSource>::parse_literal_or_range_pattern ()
- {
-   const_TokenPtr range_lower = lexer.peek_token ();
-   AST::Literal::LitType type = AST::Literal::STRING;
-   bool has_minus = false;
- 
-   // get lit type
-   switch (range_lower->get_id ())
-     {
-     case CHAR_LITERAL:
-       type = AST::Literal::CHAR;
-       lexer.skip_token ();
-       break;
-     case BYTE_CHAR_LITERAL:
-       type = AST::Literal::BYTE;
-       lexer.skip_token ();
-       break;
-     case INT_LITERAL:
-       type = AST::Literal::INT;
-       lexer.skip_token ();
-       break;
-     case FLOAT_LITERAL:
-       type = AST::Literal::FLOAT;
-       lexer.skip_token ();
-       break;
-     case MINUS:
-       // branch on next token
-       range_lower = lexer.peek_token (1);
-       switch (range_lower->get_id ())
- 	{
- 	case INT_LITERAL:
- 	  type = AST::Literal::INT;
- 	  has_minus = true;
- 	  lexer.skip_token (1);
- 	  break;
- 	case FLOAT_LITERAL:
- 	  type = AST::Literal::FLOAT;
- 	  has_minus = true;
- 	  lexer.skip_token (1);
- 	  break;
- 	default:
- 	  add_error (Error (range_lower->get_locus (),
- 			    "token type %qs cannot be parsed as range pattern "
- 			    "bound or literal after minus symbol",
- 			    range_lower->get_token_description ()));
- 
- 	  return nullptr;
- 	}
-       break;
-     default:
-       add_error (
- 	Error (range_lower->get_locus (),
- 	       "token type %qs cannot be parsed as range pattern bound",
- 	       range_lower->get_token_description ()));
- 
-       return nullptr;
-     }
- 
-   const_TokenPtr next = lexer.peek_token ();
-   if (next->get_id () == DOT_DOT_EQ || next->get_id () == ELLIPSIS
-       || next->get_id () == DOT_DOT)
-     {
-       AST::RangeKind kind = AST::tokenid_to_rangekind (next->get_id ());
-       // range pattern
-       lexer.skip_token ();
-       std::unique_ptr<AST::RangePatternBound> lower (
- 	new AST::RangePatternBoundLiteral (
- 	  AST::Literal (range_lower->get_str (), type,
- 			PrimitiveCoreType::CORETYPE_UNKNOWN),
- 	  range_lower->get_locus (), has_minus));
- 
-       std::unique_ptr<AST::RangePatternBound> upper
- 	= parse_range_pattern_bound ();
-       if (upper == nullptr)
- 	{
- 	  Error error (next->get_locus (),
- 		       "failed to parse range pattern bound in range pattern");
- 	  add_error (std::move (error));
- 
- 	  return nullptr;
- 	}
- 
-       return std::unique_ptr<AST::RangePattern> (
- 	new AST::RangePattern (std::move (lower), std::move (upper), kind,
- 			       range_lower->get_locus ()));
-     }
-   else
-     {
-       // literal pattern
-       return std::unique_ptr<AST::LiteralPattern> (
- 	new AST::LiteralPattern (range_lower->get_str (), type,
- 				 range_lower->get_locus (),
- 				 range_lower->get_type_hint (), has_minus));
-     }
- }
- 
- // Parses a range pattern bound (value only).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::RangePatternBound>
- Parser<ManagedTokenSource>::parse_range_pattern_bound ()
- {
-   const_TokenPtr range_lower = lexer.peek_token ();
-   location_t range_lower_locus = range_lower->get_locus ();
- 
-   // get lit type
-   switch (range_lower->get_id ())
-     {
-     case CHAR_LITERAL:
-       lexer.skip_token ();
-       return std::unique_ptr<AST::RangePatternBoundLiteral> (
- 	new AST::RangePatternBoundLiteral (
- 	  AST::Literal (range_lower->get_str (), AST::Literal::CHAR,
- 			range_lower->get_type_hint ()),
- 	  range_lower_locus));
-     case BYTE_CHAR_LITERAL:
-       lexer.skip_token ();
-       return std::unique_ptr<AST::RangePatternBoundLiteral> (
- 	new AST::RangePatternBoundLiteral (
- 	  AST::Literal (range_lower->get_str (), AST::Literal::BYTE,
- 			range_lower->get_type_hint ()),
- 	  range_lower_locus));
-     case INT_LITERAL:
-       lexer.skip_token ();
-       return std::unique_ptr<AST::RangePatternBoundLiteral> (
- 	new AST::RangePatternBoundLiteral (
- 	  AST::Literal (range_lower->get_str (), AST::Literal::INT,
- 			range_lower->get_type_hint ()),
- 	  range_lower_locus));
-     case FLOAT_LITERAL:
-       lexer.skip_token ();
-       rust_debug ("warning: used deprecated float range pattern bound");
-       return std::unique_ptr<AST::RangePatternBoundLiteral> (
- 	new AST::RangePatternBoundLiteral (
- 	  AST::Literal (range_lower->get_str (), AST::Literal::FLOAT,
- 			range_lower->get_type_hint ()),
- 	  range_lower_locus));
-     case MINUS:
-       // branch on next token
-       range_lower = lexer.peek_token (1);
-       switch (range_lower->get_id ())
- 	{
- 	case INT_LITERAL:
- 	  lexer.skip_token (1);
- 	  return std::unique_ptr<AST::RangePatternBoundLiteral> (
- 	    new AST::RangePatternBoundLiteral (
- 	      AST::Literal (range_lower->get_str (), AST::Literal::INT,
- 			    range_lower->get_type_hint ()),
- 	      range_lower_locus, true));
- 	case FLOAT_LITERAL:
- 	  lexer.skip_token (1);
- 	  rust_debug ("warning: used deprecated float range pattern bound");
- 	  return std::unique_ptr<AST::RangePatternBoundLiteral> (
- 	    new AST::RangePatternBoundLiteral (
- 	      AST::Literal (range_lower->get_str (), AST::Literal::FLOAT,
- 			    range_lower->get_type_hint ()),
- 	      range_lower_locus, true));
- 	default:
- 	  add_error (Error (range_lower->get_locus (),
- 			    "token type %qs cannot be parsed as range pattern "
- 			    "bound after minus symbol",
- 			    range_lower->get_token_description ()));
- 
- 	  return nullptr;
- 	}
-     case IDENTIFIER:
-     case SUPER:
-     case SELF:
-     case SELF_ALIAS:
-     case CRATE:
-     case SCOPE_RESOLUTION:
-     case DOLLAR_SIGN:
-       {
- 	// path in expression
- 	AST::PathInExpression path = parse_path_in_expression ();
- 	if (path.is_error ())
- 	  {
- 	    Error error (
- 	      range_lower->get_locus (),
- 	      "failed to parse path in expression range pattern bound");
- 	    add_error (std::move (error));
- 
- 	    return nullptr;
- 	  }
- 	return std::unique_ptr<AST::RangePatternBoundPath> (
- 	  new AST::RangePatternBoundPath (std::move (path)));
-       }
-     case LEFT_SHIFT:
-     case LEFT_ANGLE:
-       {
- 	// qualified path in expression
- 	AST::QualifiedPathInExpression path
- 	  = parse_qualified_path_in_expression ();
- 	if (path.is_error ())
- 	  {
- 	    Error error (range_lower->get_locus (),
- 			 "failed to parse qualified path in expression range "
- 			 "pattern bound");
- 	    add_error (std::move (error));
- 
- 	    return nullptr;
- 	  }
- 	return std::unique_ptr<AST::RangePatternBoundQualPath> (
- 	  new AST::RangePatternBoundQualPath (std::move (path)));
-       }
-     default:
-       add_error (
- 	Error (range_lower->get_locus (),
- 	       "token type %qs cannot be parsed as range pattern bound",
- 	       range_lower->get_token_description ()));
- 
-       return nullptr;
-     }
- }
- 
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::Pattern>
- Parser<ManagedTokenSource>::parse_pattern ()
- {
-   location_t start_locus = lexer.peek_token ()->get_locus ();
- 
-   /* skip optional starting pipe */
-   maybe_skip_token (PIPE);
- 
-   auto first = parse_pattern_no_alt ();
- 
-   if (lexer.peek_token ()->get_id () != PIPE)
-     /* no alternates */
-     return first;
- 
-   std::vector<std::unique_ptr<AST::Pattern>> alts;
-   if (first != nullptr)
-     alts.push_back (std::move (first));
- 
-   do
-     {
-       lexer.skip_token ();
-       auto follow = parse_pattern_no_alt ();
-       if (follow != nullptr)
- 	alts.push_back (std::move (follow));
-     }
- 
-   while (lexer.peek_token ()->get_id () == PIPE);
- 
-   if (alts.empty ())
-     return nullptr;
- 
-   /* alternates */
-   return std::unique_ptr<AST::Pattern> (
-     new AST::AltPattern (std::move (alts), start_locus));
- }
- 
- // Parses a pattern without alternates ('|')
- // (will further disambiguate any pattern).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::Pattern>
- Parser<ManagedTokenSource>::parse_pattern_no_alt ()
- {
-   const_TokenPtr t = lexer.peek_token ();
-   switch (t->get_id ())
-     {
-     case TRUE_LITERAL:
-       lexer.skip_token ();
-       return std::unique_ptr<AST::LiteralPattern> (
- 	new AST::LiteralPattern (Values::Keywords::TRUE_LITERAL,
- 				 AST::Literal::BOOL, t->get_locus (),
- 				 t->get_type_hint ()));
-     case FALSE_LITERAL:
-       lexer.skip_token ();
-       return std::unique_ptr<AST::LiteralPattern> (
- 	new AST::LiteralPattern (Values::Keywords::FALSE_LITERAL,
- 				 AST::Literal::BOOL, t->get_locus (),
- 				 t->get_type_hint ()));
-     case CHAR_LITERAL:
-     case BYTE_CHAR_LITERAL:
-     case INT_LITERAL:
-     case FLOAT_LITERAL:
-       return parse_literal_or_range_pattern ();
-     case STRING_LITERAL:
-       lexer.skip_token ();
-       return std::unique_ptr<AST::LiteralPattern> (
- 	new AST::LiteralPattern (t->get_str (), AST::Literal::STRING,
- 				 t->get_locus (), t->get_type_hint ()));
-     case BYTE_STRING_LITERAL:
-       lexer.skip_token ();
-       return std::unique_ptr<AST::LiteralPattern> (
- 	new AST::LiteralPattern (t->get_str (), AST::Literal::BYTE_STRING,
- 				 t->get_locus (), t->get_type_hint ()));
-     case RAW_STRING_LITERAL:
-       lexer.skip_token ();
-       return std::unique_ptr<AST::LiteralPattern> (
- 	new AST::LiteralPattern (t->get_str (), AST::Literal::RAW_STRING,
- 				 t->get_locus (), t->get_type_hint ()));
-     // raw string and raw byte string literals too if they are readded to
-     // lexer
-     case MINUS:
-       if (lexer.peek_token (1)->get_id () == INT_LITERAL)
- 	{
- 	  return parse_literal_or_range_pattern ();
- 	}
-       else if (lexer.peek_token (1)->get_id () == FLOAT_LITERAL)
- 	{
- 	  return parse_literal_or_range_pattern ();
- 	}
-       else
- 	{
- 	  Error error (t->get_locus (), "unexpected token %<-%> in pattern - "
- 					"did you forget an integer literal");
- 	  add_error (std::move (error));
- 
- 	  return nullptr;
- 	}
-     case UNDERSCORE:
-       lexer.skip_token ();
-       return std::unique_ptr<AST::WildcardPattern> (
- 	new AST::WildcardPattern (t->get_locus ()));
-     case DOT_DOT:
-       lexer.skip_token ();
-       return std::unique_ptr<AST::RestPattern> (
- 	new AST::RestPattern (t->get_locus ()));
-     case REF:
-     case MUT:
-       return parse_identifier_pattern ();
-     case IDENTIFIER:
-       /* if identifier with no scope resolution afterwards, identifier
-        * pattern. if scope resolution afterwards, path pattern (or range
-        * pattern or struct pattern or tuple struct pattern) or macro
-        * invocation */
-       return parse_ident_leading_pattern ();
-     case AMP:
-     case LOGICAL_AND:
-       // reference pattern
-       return parse_reference_pattern ();
-     case LEFT_PAREN:
-       // tuple pattern or grouped pattern
-       return parse_grouped_or_tuple_pattern ();
-     case LEFT_SQUARE:
-       // slice pattern
-       return parse_slice_pattern ();
-     case LEFT_SHIFT:
-     case LEFT_ANGLE:
-       {
- 	// qualified path in expression or qualified range pattern bound
- 	AST::QualifiedPathInExpression path
- 	  = parse_qualified_path_in_expression ();
- 
- 	if (lexer.peek_token ()->get_id () == DOT_DOT_EQ
- 	    || lexer.peek_token ()->get_id () == ELLIPSIS
- 	    || lexer.peek_token ()->get_id () == DOT_DOT)
- 	  {
- 	    // qualified range pattern bound, so parse rest of range pattern
- 	    AST::RangeKind kind
- 	      = AST::tokenid_to_rangekind (lexer.peek_token ()->get_id ());
- 	    lexer.skip_token ();
- 
- 	    std::unique_ptr<AST::RangePatternBoundQualPath> lower_bound (
- 	      new AST::RangePatternBoundQualPath (std::move (path)));
- 	    std::unique_ptr<AST::RangePatternBound> upper_bound
- 	      = parse_range_pattern_bound ();
- 
- 	    return std::unique_ptr<AST::RangePattern> (
- 	      new AST::RangePattern (std::move (lower_bound),
- 				     std::move (upper_bound), kind,
- 				     t->get_locus ()));
- 	  }
- 	else
- 	  {
- 	    // just qualified path in expression
- 	    return std::unique_ptr<AST::QualifiedPathInExpression> (
- 	      new AST::QualifiedPathInExpression (std::move (path)));
- 	  }
-       }
-     case SUPER:
-     case SELF:
-     case SELF_ALIAS:
-     case CRATE:
-     case SCOPE_RESOLUTION:
-     case DOLLAR_SIGN:
-       {
- 	// path in expression or range pattern bound
- 	AST::PathInExpression path = parse_path_in_expression ();
- 
- 	const_TokenPtr next = lexer.peek_token ();
- 	switch (next->get_id ())
- 	  {
- 	  case DOT_DOT_EQ:
- 	  case DOT_DOT:
- 	  case ELLIPSIS:
- 	    {
- 	      // qualified range pattern bound, so parse rest of range pattern
- 	      AST::RangeKind kind = AST::tokenid_to_rangekind (next->get_id ());
- 	      lexer.skip_token ();
- 
- 	      std::unique_ptr<AST::RangePatternBoundPath> lower_bound (
- 		new AST::RangePatternBoundPath (std::move (path)));
- 	      std::unique_ptr<AST::RangePatternBound> upper_bound
- 		= parse_range_pattern_bound ();
- 
- 	      return std::unique_ptr<AST::RangePattern> (
- 		new AST::RangePattern (std::move (lower_bound),
- 				       std::move (upper_bound), kind,
- 				       next->get_locus ()));
- 	    }
- 	  case EXCLAM:
- 	    return parse_macro_invocation_partial (std::move (path),
- 						   AST::AttrVec ());
- 	  case LEFT_PAREN:
- 	    {
- 	      // tuple struct
- 	      lexer.skip_token ();
- 
- 	      // parse items
- 	      std::unique_ptr<AST::TupleStructItems> items
- 		= parse_tuple_struct_items ();
- 	      if (items == nullptr)
- 		{
- 		  Error error (lexer.peek_token ()->get_locus (),
- 			       "failed to parse tuple struct items");
- 		  add_error (std::move (error));
- 
- 		  return nullptr;
- 		}
- 
- 	      if (!skip_token (RIGHT_PAREN))
- 		{
- 		  return nullptr;
- 		}
- 
- 	      return std::unique_ptr<AST::TupleStructPattern> (
- 		new AST::TupleStructPattern (std::move (path),
- 					     std::move (items)));
- 	    }
- 	  case LEFT_CURLY:
- 	    {
- 	      // struct
- 	      lexer.skip_token ();
- 
- 	      // parse elements (optional)
- 	      AST::StructPatternElements elems = parse_struct_pattern_elems ();
- 
- 	      if (!skip_token (RIGHT_CURLY))
- 		{
- 		  return nullptr;
- 		}
- 
- 	      return std::unique_ptr<AST::StructPattern> (
- 		new AST::StructPattern (std::move (path), t->get_locus (),
- 					std::move (elems)));
- 	    }
- 	  default:
- 	    // assume path in expression
- 	    return std::unique_ptr<AST::PathInExpression> (
- 	      new AST::PathInExpression (std::move (path)));
- 	  }
-       }
-     default:
-       add_error (Error (t->get_locus (), "unexpected token %qs in pattern",
- 			t->get_token_description ()));
- 
-       return nullptr;
-     }
- }
- 
- // Parses a single or double reference pattern.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::ReferencePattern>
- Parser<ManagedTokenSource>::parse_reference_pattern ()
- {
-   // parse double or single ref
-   bool is_double_ref = false;
-   const_TokenPtr t = lexer.peek_token ();
-   switch (t->get_id ())
-     {
-     case AMP:
-       // still false
-       lexer.skip_token ();
-       break;
-     case LOGICAL_AND:
-       is_double_ref = true;
-       lexer.skip_token ();
-       break;
-     default:
-       add_error (Error (t->get_locus (),
- 			"unexpected token %qs in reference pattern",
- 			t->get_token_description ()));
- 
-       return nullptr;
-     }
- 
-   // parse mut (if it exists)
-   bool is_mut = false;
-   if (lexer.peek_token ()->get_id () == MUT)
-     {
-       is_mut = true;
-       lexer.skip_token ();
-     }
- 
-   // parse pattern to get reference of (required)
-   std::unique_ptr<AST::Pattern> pattern = parse_pattern_no_alt ();
-   if (pattern == nullptr)
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "failed to parse pattern in reference pattern");
-       add_error (std::move (error));
- 
-       // skip somewhere?
-       return nullptr;
-     }
- 
-   return std::unique_ptr<AST::ReferencePattern> (
-     new AST::ReferencePattern (std::move (pattern), is_mut, is_double_ref,
- 			       t->get_locus ()));
- }
- 
- /* Parses a grouped pattern or tuple pattern. Prefers grouped over tuple if
-  * only a single element with no commas. */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::Pattern>
- Parser<ManagedTokenSource>::parse_grouped_or_tuple_pattern ()
- {
-   location_t paren_locus = lexer.peek_token ()->get_locus ();
-   skip_token (LEFT_PAREN);
- 
-   // detect '..' token (ranged with no lower range)
-   if (lexer.peek_token ()->get_id () == DOT_DOT)
-     {
-       lexer.skip_token ();
- 
-       // parse new patterns while next token is a comma
-       std::vector<std::unique_ptr<AST::Pattern>> patterns;
- 
-       const_TokenPtr t = lexer.peek_token ();
-       while (t->get_id () == COMMA)
- 	{
- 	  lexer.skip_token ();
- 
- 	  // break if next token is ')'
- 	  if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
- 	    {
- 	      break;
- 	    }
- 
- 	  // parse pattern, which is required
- 	  std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
- 	  if (pattern == nullptr)
- 	    {
- 	      Error error (
- 		lexer.peek_token ()->get_locus (),
- 		"failed to parse pattern inside ranged tuple pattern");
- 	      add_error (std::move (error));
- 
- 	      // skip somewhere?
- 	      return nullptr;
- 	    }
- 	  patterns.push_back (std::move (pattern));
- 
- 	  t = lexer.peek_token ();
- 	}
- 
-       if (!skip_token (RIGHT_PAREN))
- 	{
- 	  // skip somewhere?
- 	  return nullptr;
- 	}
- 
-       // create tuple pattern items with only upper pattern items
-       std::unique_ptr<AST::TuplePatternItemsHasRest> items (
- 	new AST::TuplePatternItemsHasRest (
- 	  std::vector<std::unique_ptr<AST::Pattern>> (), std::move (patterns)));
-       return std::unique_ptr<AST::TuplePattern> (
- 	new AST::TuplePattern (std::move (items), paren_locus));
-     }
-   else if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
-     {
-       skip_token (RIGHT_PAREN);
-       auto items = std::unique_ptr<AST::TuplePatternItemsNoRest> (
- 	new AST::TuplePatternItemsNoRest (
- 	  std::vector<std::unique_ptr<AST::Pattern>> ()));
-       return std::unique_ptr<AST::TuplePattern> (
- 	new AST::TuplePattern (std::move (items), paren_locus));
-     }
- 
-   // parse initial pattern (required)
-   std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern ();
-   if (initial_pattern == nullptr)
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "failed to parse pattern in grouped or tuple pattern");
-       add_error (std::move (error));
- 
-       return nullptr;
-     }
- 
-   // branch on whether next token is a comma or not
-   const_TokenPtr t = lexer.peek_token ();
-   switch (t->get_id ())
-     {
-     case RIGHT_PAREN:
-       // grouped pattern
-       lexer.skip_token ();
- 
-       return std::unique_ptr<AST::GroupedPattern> (
- 	new AST::GroupedPattern (std::move (initial_pattern), paren_locus));
-     case COMMA:
-       {
- 	// tuple pattern
- 	lexer.skip_token ();
- 
- 	// create vector of patterns
- 	std::vector<std::unique_ptr<AST::Pattern>> patterns;
- 	patterns.push_back (std::move (initial_pattern));
- 
- 	t = lexer.peek_token ();
- 	while (t->get_id () != RIGHT_PAREN && t->get_id () != DOT_DOT)
- 	  {
- 	    // parse pattern (required)
- 	    std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
- 	    if (pattern == nullptr)
- 	      {
- 		Error error (t->get_locus (),
- 			     "failed to parse pattern in tuple pattern");
- 		add_error (std::move (error));
- 
- 		return nullptr;
- 	      }
- 	    patterns.push_back (std::move (pattern));
- 
- 	    if (lexer.peek_token ()->get_id () != COMMA)
- 	      break;
- 
- 	    lexer.skip_token ();
- 	    t = lexer.peek_token ();
- 	  }
- 
- 	t = lexer.peek_token ();
- 	if (t->get_id () == RIGHT_PAREN)
- 	  {
- 	    // non-ranged tuple pattern
- 	    lexer.skip_token ();
- 
- 	    std::unique_ptr<AST::TuplePatternItemsNoRest> items (
- 	      new AST::TuplePatternItemsNoRest (std::move (patterns)));
- 	    return std::unique_ptr<AST::TuplePattern> (
- 	      new AST::TuplePattern (std::move (items), paren_locus));
- 	  }
- 	else if (t->get_id () == DOT_DOT)
- 	  {
- 	    // ranged tuple pattern
- 	    lexer.skip_token ();
- 
- 	    // parse upper patterns
- 	    std::vector<std::unique_ptr<AST::Pattern>> upper_patterns;
- 	    t = lexer.peek_token ();
- 	    while (t->get_id () == COMMA)
- 	      {
- 		lexer.skip_token ();
- 
- 		// break if end
- 		if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
- 		  break;
- 
- 		// parse pattern (required)
- 		std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
- 		if (pattern == nullptr)
- 		  {
- 		    Error error (lexer.peek_token ()->get_locus (),
- 				 "failed to parse pattern in tuple pattern");
- 		    add_error (std::move (error));
- 
- 		    return nullptr;
- 		  }
- 		upper_patterns.push_back (std::move (pattern));
- 
- 		t = lexer.peek_token ();
- 	      }
- 
- 	    if (!skip_token (RIGHT_PAREN))
- 	      {
- 		return nullptr;
- 	      }
- 
- 	    std::unique_ptr<AST::TuplePatternItemsHasRest> items (
- 	      new AST::TuplePatternItemsHasRest (std::move (patterns),
- 						 std::move (upper_patterns)));
- 	    return std::unique_ptr<AST::TuplePattern> (
- 	      new AST::TuplePattern (std::move (items), paren_locus));
- 	  }
- 	else
- 	  {
- 	    // some kind of error
- 	    Error error (t->get_locus (),
- 			 "failed to parse tuple pattern (probably) or maybe "
- 			 "grouped pattern");
- 	    add_error (std::move (error));
- 
- 	    return nullptr;
- 	  }
-       }
-     default:
-       // error
-       add_error (Error (t->get_locus (),
- 			"unrecognised token %qs in grouped or tuple pattern "
- 			"after first pattern",
- 			t->get_token_description ()));
- 
-       return nullptr;
-     }
- }
- 
- /* Parses a slice pattern that can match arrays or slices. Parses the square
-  * brackets too. */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::SlicePattern>
- Parser<ManagedTokenSource>::parse_slice_pattern ()
- {
-   location_t square_locus = lexer.peek_token ()->get_locus ();
-   std::vector<std::unique_ptr<AST::Pattern>> patterns;
-   tl::optional<std::vector<std::unique_ptr<AST::Pattern>>> upper_patterns
-     = tl::nullopt;
- 
-   // lambda function to determine which vector to push new patterns into
-   auto get_pattern_ref
-     = [&] () -> std::vector<std::unique_ptr<AST::Pattern>> & {
-     return upper_patterns.has_value () ? upper_patterns.value () : patterns;
-   };
- 
-   skip_token (LEFT_SQUARE);
- 
-   if (lexer.peek_token ()->get_id () == RIGHT_SQUARE)
-     {
-       skip_token (RIGHT_SQUARE);
-       std::unique_ptr<AST::SlicePatternItemsNoRest> items (
- 	new AST::SlicePatternItemsNoRest (std::move (patterns)));
-       return std::unique_ptr<AST::SlicePattern> (
- 	new AST::SlicePattern (std::move (items), square_locus));
-     }
- 
-   // parse initial pattern (required)
-   if (lexer.peek_token ()->get_id () == DOT_DOT)
-     {
-       lexer.skip_token ();
-       upper_patterns = std::vector<std::unique_ptr<AST::Pattern>> ();
-     }
-   else
-     {
-       // Not a rest pattern `..`, parse normally
-       std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern ();
-       if (initial_pattern == nullptr)
- 	{
- 	  Error error (lexer.peek_token ()->get_locus (),
- 		       "failed to parse initial pattern in slice pattern");
- 	  add_error (std::move (error));
- 
- 	  return nullptr;
- 	}
- 
-       patterns.push_back (std::move (initial_pattern));
-     }
- 
-   const_TokenPtr t = lexer.peek_token ();
-   while (t->get_id () == COMMA)
-     {
-       lexer.skip_token ();
- 
-       // break if end bracket
-       if (lexer.peek_token ()->get_id () == RIGHT_SQUARE)
- 	break;
- 
-       if (lexer.peek_token ()->get_id () == DOT_DOT)
- 	{
- 	  if (upper_patterns.has_value ())
- 	    {
- 	      // DOT_DOT has been parsed before
- 	      Error error (lexer.peek_token ()->get_locus (), "%s",
- 			   "`..` can only be used once per slice pattern");
- 	      add_error (std::move (error));
- 
- 	      return nullptr;
- 	    }
- 	  upper_patterns = std::vector<std::unique_ptr<AST::Pattern>> ();
- 	  lexer.skip_token ();
- 	  t = lexer.peek_token ();
- 	  continue;
- 	}
- 
-       // parse pattern (required)
-       std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
-       if (pattern == nullptr)
- 	{
- 	  Error error (lexer.peek_token ()->get_locus (),
- 		       "failed to parse pattern in slice pattern");
- 	  add_error (std::move (error));
- 
- 	  return nullptr;
- 	}
-       get_pattern_ref ().push_back (std::move (pattern));
- 
-       t = lexer.peek_token ();
-     }
- 
-   if (!skip_token (RIGHT_SQUARE))
-     {
-       return nullptr;
-     }
- 
-   if (upper_patterns.has_value ())
-     {
-       // Slice pattern with rest
-       std::unique_ptr<AST::SlicePatternItemsHasRest> items (
- 	new AST::SlicePatternItemsHasRest (
- 	  std::move (patterns), std::move (upper_patterns.value ())));
-       return std::unique_ptr<AST::SlicePattern> (
- 	new AST::SlicePattern (std::move (items), square_locus));
-     }
- 
-   // Rest-less slice pattern
-   std::unique_ptr<AST::SlicePatternItemsNoRest> items (
-     new AST::SlicePatternItemsNoRest (std::move (patterns)));
-   return std::unique_ptr<AST::SlicePattern> (
-     new AST::SlicePattern (std::move (items), square_locus));
- }
- 
- /* Parses an identifier pattern (pattern that binds a value matched to a
-  * variable). */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::IdentifierPattern>
- Parser<ManagedTokenSource>::parse_identifier_pattern ()
- {
-   location_t locus = lexer.peek_token ()->get_locus ();
- 
-   bool has_ref = false;
-   if (lexer.peek_token ()->get_id () == REF)
-     {
-       has_ref = true;
-       lexer.skip_token ();
- 
-       // DEBUG
-       rust_debug ("parsed ref in identifier pattern");
-     }
- 
-   bool has_mut = false;
-   if (lexer.peek_token ()->get_id () == MUT)
-     {
-       has_mut = true;
-       lexer.skip_token ();
-     }
- 
-   // parse identifier (required)
-   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
-   if (ident_tok == nullptr)
-     {
-       // skip somewhere?
-       return nullptr;
-     }
-   Identifier ident{ident_tok};
- 
-   // DEBUG
-   rust_debug ("parsed identifier in identifier pattern");
- 
-   // parse optional pattern binding thing
-   std::unique_ptr<AST::Pattern> bind_pattern = nullptr;
-   if (lexer.peek_token ()->get_id () == PATTERN_BIND)
-     {
-       lexer.skip_token ();
- 
-       // parse required pattern to bind
-       bind_pattern = parse_pattern_no_alt ();
-       if (bind_pattern == nullptr)
- 	{
- 	  Error error (lexer.peek_token ()->get_locus (),
- 		       "failed to parse pattern to bind in identifier pattern");
- 	  add_error (std::move (error));
- 
- 	  return nullptr;
- 	}
-     }
- 
-   // DEBUG
-   rust_debug ("about to return identifier pattern");
- 
-   return std::unique_ptr<AST::IdentifierPattern> (
-     new AST::IdentifierPattern (std::move (ident), locus, has_ref, has_mut,
- 				std::move (bind_pattern)));
- }
- 
- /* Parses a pattern that opens with an identifier. This includes identifier
-  * patterns, path patterns (and derivatives such as struct patterns, tuple
-  * struct patterns, and macro invocations), and ranges. */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::Pattern>
- Parser<ManagedTokenSource>::parse_ident_leading_pattern ()
- {
-   // ensure first token is actually identifier
-   const_TokenPtr initial_tok = lexer.peek_token ();
-   if (initial_tok->get_id () != IDENTIFIER)
-     {
-       return nullptr;
-     }
- 
-   // save initial identifier as it may be useful (but don't skip)
-   std::string initial_ident = initial_tok->get_str ();
- 
-   // parse next tokens as a PathInExpression
-   AST::PathInExpression path = parse_path_in_expression ();
- 
-   // branch on next token
-   const_TokenPtr t = lexer.peek_token ();
-   switch (t->get_id ())
-     {
-     case EXCLAM:
-       return parse_macro_invocation_partial (std::move (path), AST::AttrVec ());
-     case LEFT_PAREN:
-       {
- 	// tuple struct
- 	lexer.skip_token ();
- 
- 	// DEBUG
- 	rust_debug ("parsing tuple struct pattern");
- 
- 	// parse items
- 	std::unique_ptr<AST::TupleStructItems> items
- 	  = parse_tuple_struct_items ();
- 	if (items == nullptr)
- 	  {
- 	    Error error (lexer.peek_token ()->get_locus (),
- 			 "failed to parse tuple struct items");
- 	    add_error (std::move (error));
- 
- 	    return nullptr;
- 	  }
- 
- 	// DEBUG
- 	rust_debug ("successfully parsed tuple struct items");
- 
- 	if (!skip_token (RIGHT_PAREN))
- 	  {
- 	    return nullptr;
- 	  }
- 
- 	// DEBUG
- 	rust_debug ("successfully parsed tuple struct pattern");
- 
- 	return std::unique_ptr<AST::TupleStructPattern> (
- 	  new AST::TupleStructPattern (std::move (path), std::move (items)));
-       }
-     case LEFT_CURLY:
-       {
- 	// struct
- 	lexer.skip_token ();
- 
- 	// parse elements (optional)
- 	AST::StructPatternElements elems = parse_struct_pattern_elems ();
- 
- 	if (!skip_token (RIGHT_CURLY))
- 	  {
- 	    return nullptr;
- 	  }
- 
- 	// DEBUG
- 	rust_debug ("successfully parsed struct pattern");
- 
- 	return std::unique_ptr<AST::StructPattern> (
- 	  new AST::StructPattern (std::move (path), initial_tok->get_locus (),
- 				  std::move (elems)));
-       }
-     case DOT_DOT_EQ:
-     case DOT_DOT:
-     case ELLIPSIS:
-       {
- 	// range
- 	AST::RangeKind kind
- 	  = AST::tokenid_to_rangekind (lexer.peek_token ()->get_id ());
- 
- 	lexer.skip_token ();
- 
- 	std::unique_ptr<AST::RangePatternBoundPath> lower_bound (
- 	  new AST::RangePatternBoundPath (std::move (path)));
- 	std::unique_ptr<AST::RangePatternBound> upper_bound
- 	  = parse_range_pattern_bound ();
- 
- 	return std::unique_ptr<AST::RangePattern> (
- 	  new AST::RangePattern (std::move (lower_bound),
- 				 std::move (upper_bound), kind,
- 				 t->get_locus ()));
-       }
-     case PATTERN_BIND:
-       {
- 	// only allow on single-segment paths
- 	if (path.is_single_segment ())
- 	  {
- 	    // identifier with pattern bind
- 	    lexer.skip_token ();
- 
- 	    std::unique_ptr<AST::Pattern> bind_pattern
- 	      = parse_pattern_no_alt ();
- 	    if (bind_pattern == nullptr)
- 	      {
- 		Error error (
- 		  t->get_locus (),
- 		  "failed to parse pattern to bind to identifier pattern");
- 		add_error (std::move (error));
- 
- 		return nullptr;
- 	      }
- 	    return std::unique_ptr<AST::IdentifierPattern> (
- 	      new AST::IdentifierPattern (std::move (initial_ident),
- 					  initial_tok->get_locus (), false,
- 					  false, std::move (bind_pattern)));
- 	  }
- 	Error error (
- 	  t->get_locus (),
- 	  "failed to parse pattern bind to a path, not an identifier");
- 	add_error (std::move (error));
- 
- 	return nullptr;
-       }
-     default:
-       // assume identifier if single segment
-       if (path.is_single_segment ())
- 	{
- 	  return std::unique_ptr<AST::IdentifierPattern> (
- 	    new AST::IdentifierPattern (std::move (initial_ident),
- 					initial_tok->get_locus ()));
- 	}
-       // return path otherwise
-       return std::unique_ptr<AST::PathInExpression> (
- 	new AST::PathInExpression (std::move (path)));
-     }
- }
- 
- // Parses tuple struct items if they exist. Does not parse parentheses.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::TupleStructItems>
- Parser<ManagedTokenSource>::parse_tuple_struct_items ()
- {
-   std::vector<std::unique_ptr<AST::Pattern>> lower_patterns;
- 
-   // DEBUG
-   rust_debug ("started parsing tuple struct items");
- 
-   // check for '..' at front
-   if (lexer.peek_token ()->get_id () == DOT_DOT)
-     {
-       // only parse upper patterns
-       lexer.skip_token ();
- 
-       // DEBUG
-       rust_debug ("'..' at front in tuple struct items detected");
- 
-       std::vector<std::unique_ptr<AST::Pattern>> upper_patterns;
- 
-       const_TokenPtr t = lexer.peek_token ();
-       while (t->get_id () == COMMA)
- 	{
- 	  lexer.skip_token ();
- 
- 	  // break if right paren
- 	  if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
- 	    break;
- 
- 	  // parse pattern, which is now required
- 	  std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
- 	  if (pattern == nullptr)
- 	    {
- 	      Error error (lexer.peek_token ()->get_locus (),
- 			   "failed to parse pattern in tuple struct items");
- 	      add_error (std::move (error));
- 
- 	      return nullptr;
- 	    }
- 	  upper_patterns.push_back (std::move (pattern));
- 
- 	  t = lexer.peek_token ();
- 	}
- 
-       // DEBUG
-       rust_debug (
- 	"finished parsing tuple struct items ranged (upper/none only)");
- 
-       return std::unique_ptr<AST::TupleStructItemsHasRest> (
- 	new AST::TupleStructItemsHasRest (std::move (lower_patterns),
- 					  std::move (upper_patterns)));
-     }
- 
-   // has at least some lower patterns
-   const_TokenPtr t = lexer.peek_token ();
-   while (t->get_id () != RIGHT_PAREN && t->get_id () != DOT_DOT)
-     {
-       // DEBUG
-       rust_debug ("about to parse pattern in tuple struct items");
- 
-       // parse pattern, which is required
-       std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
-       if (pattern == nullptr)
- 	{
- 	  Error error (t->get_locus (),
- 		       "failed to parse pattern in tuple struct items");
- 	  add_error (std::move (error));
- 
- 	  return nullptr;
- 	}
-       lower_patterns.push_back (std::move (pattern));
- 
-       // DEBUG
-       rust_debug ("successfully parsed pattern in tuple struct items");
- 
-       if (lexer.peek_token ()->get_id () != COMMA)
- 	{
- 	  // DEBUG
- 	  rust_debug ("broke out of parsing patterns in tuple struct "
- 		      "items as no comma");
- 
- 	  break;
- 	}
-       lexer.skip_token ();
-       t = lexer.peek_token ();
-     }
- 
-   // branch on next token
-   t = lexer.peek_token ();
-   switch (t->get_id ())
-     {
-     case RIGHT_PAREN:
-       return std::unique_ptr<AST::TupleStructItemsNoRest> (
- 	new AST::TupleStructItemsNoRest (std::move (lower_patterns)));
-     case DOT_DOT:
-       {
- 	// has an upper range that must be parsed separately
- 	lexer.skip_token ();
- 
- 	std::vector<std::unique_ptr<AST::Pattern>> upper_patterns;
- 
- 	t = lexer.peek_token ();
- 	while (t->get_id () == COMMA)
- 	  {
- 	    lexer.skip_token ();
- 
- 	    // break if next token is right paren
- 	    if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
- 	      break;
- 
- 	    // parse pattern, which is required
- 	    std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
- 	    if (pattern == nullptr)
- 	      {
- 		Error error (lexer.peek_token ()->get_locus (),
- 			     "failed to parse pattern in tuple struct items");
- 		add_error (std::move (error));
- 
- 		return nullptr;
- 	      }
- 	    upper_patterns.push_back (std::move (pattern));
- 
- 	    t = lexer.peek_token ();
- 	  }
- 
- 	return std::unique_ptr<AST::TupleStructItemsHasRest> (
- 	  new AST::TupleStructItemsHasRest (std::move (lower_patterns),
- 					    std::move (upper_patterns)));
-       }
-     default:
-       // error
-       add_error (Error (t->get_locus (),
- 			"unexpected token %qs in tuple struct items",
- 			t->get_token_description ()));
- 
-       return nullptr;
-     }
- }
- 
- // Parses struct pattern elements if they exist.
- template <typename ManagedTokenSource>
- AST::StructPatternElements
- Parser<ManagedTokenSource>::parse_struct_pattern_elems ()
- {
-   std::vector<std::unique_ptr<AST::StructPatternField>> fields;
- 
-   AST::AttrVec etc_attrs;
-   bool has_rest = false;
- 
-   // try parsing struct pattern fields
-   const_TokenPtr t = lexer.peek_token ();
-   while (t->get_id () != RIGHT_CURLY)
-     {
-       AST::AttrVec outer_attrs = parse_outer_attributes ();
- 
-       // parse etc (must be last in struct pattern, so breaks)
-       if (lexer.peek_token ()->get_id () == DOT_DOT)
- 	{
- 	  lexer.skip_token ();
- 	  etc_attrs = std::move (outer_attrs);
- 	  has_rest = true;
- 	  break;
- 	}
- 
-       std::unique_ptr<AST::StructPatternField> field
- 	= parse_struct_pattern_field_partial (std::move (outer_attrs));
-       if (field == nullptr)
- 	{
- 	  Error error (lexer.peek_token ()->get_locus (),
- 		       "failed to parse struct pattern field");
- 	  add_error (std::move (error));
- 
- 	  // skip after somewhere?
- 	  return AST::StructPatternElements::create_empty ();
- 	}
-       fields.push_back (std::move (field));
- 
-       if (lexer.peek_token ()->get_id () != COMMA)
- 	break;
- 
-       // skip comma
-       lexer.skip_token ();
-       t = lexer.peek_token ();
-     }
- 
-   if (has_rest)
-     return AST::StructPatternElements (std::move (fields),
- 				       std::move (etc_attrs));
-   else
-     return AST::StructPatternElements (std::move (fields));
- }
- 
- /* Parses a struct pattern field (tuple index/pattern, identifier/pattern, or
-  * identifier). */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::StructPatternField>
- Parser<ManagedTokenSource>::parse_struct_pattern_field ()
- {
-   // parse outer attributes (if they exist)
-   AST::AttrVec outer_attrs = parse_outer_attributes ();
- 
-   return parse_struct_pattern_field_partial (std::move (outer_attrs));
- }
- 
- /* Parses a struct pattern field (tuple index/pattern, identifier/pattern, or
-  * identifier), with outer attributes passed in. */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::StructPatternField>
- Parser<ManagedTokenSource>::parse_struct_pattern_field_partial (
-   AST::AttrVec outer_attrs)
- {
-   // branch based on next token
-   const_TokenPtr t = lexer.peek_token ();
-   switch (t->get_id ())
-     {
-     case INT_LITERAL:
-       {
- 	// tuple index
- 	std::string index_str = t->get_str ();
- 	int index = atoi (index_str.c_str ());
- 
- 	lexer.skip_token ();
- 
- 	if (!skip_token (COLON))
- 	  {
- 	    return nullptr;
- 	  }
- 
- 	// parse required pattern
- 	std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
- 	if (pattern == nullptr)
- 	  {
- 	    Error error (
- 	      t->get_locus (),
- 	      "failed to parse pattern in tuple index struct pattern field");
- 	    add_error (std::move (error));
- 
- 	    return nullptr;
- 	  }
- 
- 	return std::unique_ptr<AST::StructPatternFieldTuplePat> (
- 	  new AST::StructPatternFieldTuplePat (index, std::move (pattern),
- 					       std::move (outer_attrs),
- 					       t->get_locus ()));
-       }
-     case IDENTIFIER:
-       // identifier-pattern OR only identifier
-       // branch on next token
-       switch (lexer.peek_token (1)->get_id ())
- 	{
- 	case COLON:
- 	  {
- 	    // identifier-pattern
- 	    Identifier ident{t};
- 	    lexer.skip_token ();
- 
- 	    skip_token (COLON);
- 
- 	    // parse required pattern
- 	    std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
- 	    if (pattern == nullptr)
- 	      {
- 		Error error (t->get_locus (),
- 			     "failed to parse pattern in struct pattern field");
- 		add_error (std::move (error));
- 
- 		return nullptr;
- 	      }
- 
- 	    return std::unique_ptr<AST::StructPatternFieldIdentPat> (
- 	      new AST::StructPatternFieldIdentPat (std::move (ident),
- 						   std::move (pattern),
- 						   std::move (outer_attrs),
- 						   t->get_locus ()));
- 	  }
- 	case COMMA:
- 	case RIGHT_CURLY:
- 	  {
- 	    // identifier only
- 	    Identifier ident = {t};
- 	    lexer.skip_token ();
- 
- 	    return std::unique_ptr<AST::StructPatternFieldIdent> (
- 	      new AST::StructPatternFieldIdent (std::move (ident), false, false,
- 						std::move (outer_attrs),
- 						t->get_locus ()));
- 	  }
- 	default:
- 	  // error
- 	  add_error (Error (t->get_locus (),
- 			    "unrecognised token %qs in struct pattern field",
- 			    t->get_token_description ()));
- 
- 	  return nullptr;
- 	}
-     case REF:
-     case MUT:
-       {
- 	// only identifier
- 	bool has_ref = false;
- 	if (t->get_id () == REF)
- 	  {
- 	    has_ref = true;
- 	    lexer.skip_token ();
- 	  }
- 
- 	bool has_mut = false;
- 	if (lexer.peek_token ()->get_id () == MUT)
- 	  {
- 	    has_mut = true;
- 	    lexer.skip_token ();
- 	  }
- 
- 	const_TokenPtr ident_tok = expect_token (IDENTIFIER);
- 	if (ident_tok == nullptr)
- 	  {
- 	    return nullptr;
- 	  }
- 	Identifier ident{ident_tok};
- 
- 	return std::unique_ptr<AST::StructPatternFieldIdent> (
- 	  new AST::StructPatternFieldIdent (std::move (ident), has_ref, has_mut,
- 					    std::move (outer_attrs),
- 					    t->get_locus ()));
-       }
-     default:
-       // not necessarily an error
-       return nullptr;
-     }
- }
- 
- /* Parses a statement or expression (depending on whether a trailing semicolon
-  * exists). Useful for block expressions where it cannot be determined through
-  * lookahead whether it is a statement or expression to be parsed. */
- template <typename ManagedTokenSource>
- ExprOrStmt
- Parser<ManagedTokenSource>::parse_stmt_or_expr ()
- {
-   // quick exit for empty statement
-   const_TokenPtr t = lexer.peek_token ();
-   if (t->get_id () == SEMICOLON)
-     {
-       lexer.skip_token ();
-       std::unique_ptr<AST::EmptyStmt> stmt (
- 	new AST::EmptyStmt (t->get_locus ()));
-       return ExprOrStmt (std::move (stmt));
-     }
- 
-   // parse outer attributes
-   AST::AttrVec outer_attrs = parse_outer_attributes ();
-   ParseRestrictions restrictions;
-   restrictions.expr_can_be_stmt = true;
-   std::unique_ptr<AST::Expr> expr;
- 
-   // parsing this will be annoying because of the many different possibilities
-   /* best may be just to copy paste in parse_item switch, and failing that try
-    * to parse outer attributes, and then pass them in to either a let
-    * statement or (fallback) expression statement. */
-   // FIXME: think of a way to do this without such a large switch?
- 
-   /* FIXME: for expressions at least, the only way that they can really be
-    * parsed properly in this way is if they don't support operators on them.
-    * They must be pratt-parsed otherwise. As such due to composability, only
-    * explicit statements will have special cases here. This should roughly
-    * correspond to "expr-with-block", but this warning is here in case it
-    * isn't the case. */
-   t = lexer.peek_token ();
-   switch (t->get_id ())
-     {
-     case LET:
-       {
- 	// let statement
- 	std::unique_ptr<AST::LetStmt> stmt (
- 	  parse_let_stmt (std::move (outer_attrs)));
- 	return ExprOrStmt (std::move (stmt));
-       }
-     case PUB:
-     case MOD:
-     case EXTERN_KW:
-     case USE:
-     case FN_KW:
-     case TYPE:
-     case STRUCT_KW:
-     case ENUM_KW:
-     case CONST:
-     case STATIC_KW:
-     case AUTO:
-     case TRAIT:
-     case IMPL:
-       {
- 	std::unique_ptr<AST::VisItem> item (
- 	  parse_vis_item (std::move (outer_attrs)));
- 	return ExprOrStmt (std::move (item));
-       }
-     /* TODO: implement union keyword but not really because of
-      * context-dependence crappy hack way to parse a union written below to
-      * separate it from the good code. */
-     // case UNION:
-     case UNSAFE:
-       { // maybe - unsafe traits are a thing
- 	/* if any of these (should be all possible VisItem prefixes), parse a
- 	 * VisItem - can't parse item because would require reparsing outer
- 	 * attributes */
- 	const_TokenPtr t2 = lexer.peek_token (1);
- 	switch (t2->get_id ())
- 	  {
- 	  case LEFT_CURLY:
- 	    {
- 	      // unsafe block: parse as expression
- 	      expr = parse_expr (std::move (outer_attrs), restrictions);
- 	      break;
- 	    }
- 	  case AUTO:
- 	  case TRAIT:
- 	    {
- 	      // unsafe trait
- 	      std::unique_ptr<AST::VisItem> item (
- 		parse_vis_item (std::move (outer_attrs)));
- 	      return ExprOrStmt (std::move (item));
- 	    }
- 	  case EXTERN_KW:
- 	  case FN_KW:
- 	    {
- 	      // unsafe function
- 	      std::unique_ptr<AST::VisItem> item (
- 		parse_vis_item (std::move (outer_attrs)));
- 	      return ExprOrStmt (std::move (item));
- 	    }
- 	  case IMPL:
- 	    {
- 	      // unsafe trait impl
- 	      std::unique_ptr<AST::VisItem> item (
- 		parse_vis_item (std::move (outer_attrs)));
- 	      return ExprOrStmt (std::move (item));
- 	    }
- 	  default:
- 	    add_error (Error (t2->get_locus (),
- 			      "unrecognised token %qs after parsing unsafe - "
- 			      "expected beginning of expression or statement",
- 			      t->get_token_description ()));
- 
- 	    // skip somewhere?
- 	    return ExprOrStmt::create_error ();
- 	  }
- 	break;
-       }
-       /* FIXME: this is either a macro invocation or macro invocation semi.
-        * start parsing to determine which one it is. */
-       // FIXME: old code there
- 
-     // crappy hack to do union "keyword"
-     case IDENTIFIER:
-       if (t->get_str () == Values::WeakKeywords::UNION
- 	  && lexer.peek_token (1)->get_id () == IDENTIFIER)
- 	{
- 	  std::unique_ptr<AST::VisItem> item (
- 	    parse_vis_item (std::move (outer_attrs)));
- 	  return ExprOrStmt (std::move (item));
- 	  // or should this go straight to parsing union?
- 	}
-       else if (t->get_str () == Values::WeakKeywords::MACRO_RULES
- 	       && lexer.peek_token (1)->get_id () == EXCLAM)
- 	{
- 	  // macro_rules! macro item
- 	  std::unique_ptr<AST::Item> item (
- 	    parse_macro_rules_def (std::move (outer_attrs)));
- 	  return ExprOrStmt (std::move (item));
- 	}
-       gcc_fallthrough ();
-     case SUPER:
-     case SELF:
-     case SELF_ALIAS:
-     case CRATE:
-     case SCOPE_RESOLUTION:
-     case DOLLAR_SIGN:
-       {
- 	AST::PathInExpression path = parse_path_in_expression ();
- 	std::unique_ptr<AST::Expr> null_denotation;
- 
- 	if (lexer.peek_token ()->get_id () == EXCLAM)
- 	  {
- 	    std::unique_ptr<AST::MacroInvocation> invoc
- 	      = parse_macro_invocation_partial (std::move (path),
- 						std::move (outer_attrs));
- 	    if (invoc == nullptr)
- 	      return ExprOrStmt::create_error ();
- 
- 	    if (restrictions.consume_semi && maybe_skip_token (SEMICOLON))
- 	      {
- 		invoc->add_semicolon ();
- 		// Macro invocation with semicolon.
- 		return ExprOrStmt (
- 		  std::unique_ptr<AST::Stmt> (std::move (invoc)));
- 	      }
- 
- 	    TokenId after_macro = lexer.peek_token ()->get_id ();
- 
- 	    AST::DelimType delim_type = invoc->get_invoc_data ()
- 					  .get_delim_tok_tree ()
- 					  .get_delim_type ();
- 
- 	    if (delim_type == AST::CURLY && after_macro != DOT
- 		&& after_macro != QUESTION_MARK)
- 	      {
- 		rust_debug ("braced macro statement");
- 		return ExprOrStmt (
- 		  std::unique_ptr<AST::Stmt> (std::move (invoc)));
- 	      }
- 
- 	    null_denotation = std::move (invoc);
- 	  }
- 	else
- 	  {
- 	    null_denotation
- 	      = null_denotation_path (std::move (path), {}, restrictions);
- 	  }
- 
- 	expr = left_denotations (std::move (null_denotation), LBP_LOWEST,
- 				 std::move (outer_attrs), restrictions);
- 	break;
-       }
-     default:
-       /* expression statement or expression itself - parse
-        * expression then make it statement if semi afterwards */
-       expr = parse_expr (std::move (outer_attrs), restrictions);
-       break;
-     }
- 
-   const_TokenPtr after_expr = lexer.peek_token ();
-   if (after_expr->get_id () == SEMICOLON)
-     {
-       // must be expression statement
-       lexer.skip_token ();
- 
-       if (expr)
- 	{
- 	  std::unique_ptr<AST::ExprStmt> stmt (
- 	    new AST::ExprStmt (std::move (expr), t->get_locus (), true));
- 	  return ExprOrStmt (std::move (stmt));
- 	}
-       else
- 	{
- 	  return ExprOrStmt::create_error ();
- 	}
-     }
- 
-   if (expr && !expr->is_expr_without_block ()
-       && after_expr->get_id () != RIGHT_CURLY)
-     {
-       // block expression statement.
-       std::unique_ptr<AST::ExprStmt> stmt (
- 	new AST::ExprStmt (std::move (expr), t->get_locus (), false));
-       return ExprOrStmt (std::move (stmt));
-     }
- 
-   // return expression
-   return ExprOrStmt (std::move (expr));
- }
- 
- // Parses a struct expression field.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::StructExprField>
- Parser<ManagedTokenSource>::parse_struct_expr_field ()
- {
-   AST::AttrVec outer_attrs = parse_outer_attributes ();
-   const_TokenPtr t = lexer.peek_token ();
-   switch (t->get_id ())
-     {
-     case IDENTIFIER:
-       if (lexer.peek_token (1)->get_id () == COLON)
- 	{
- 	  // struct expr field with identifier and expr
- 	  Identifier ident = {t};
- 	  lexer.skip_token (1);
- 
- 	  // parse expression (required)
- 	  std::unique_ptr<AST::Expr> expr = parse_expr ();
- 	  if (expr == nullptr)
- 	    {
- 	      Error error (t->get_locus (),
- 			   "failed to parse struct expression field with "
- 			   "identifier and expression");
- 	      add_error (std::move (error));
- 
- 	      return nullptr;
- 	    }
- 
- 	  return std::unique_ptr<AST::StructExprFieldIdentifierValue> (
- 	    new AST::StructExprFieldIdentifierValue (std::move (ident),
- 						     std::move (expr),
- 						     std::move (outer_attrs),
- 						     t->get_locus ()));
- 	}
-       else
- 	{
- 	  // struct expr field with identifier only
- 	  Identifier ident{t};
- 	  lexer.skip_token ();
- 
- 	  return std::unique_ptr<AST::StructExprFieldIdentifier> (
- 	    new AST::StructExprFieldIdentifier (std::move (ident),
- 						std::move (outer_attrs),
- 						t->get_locus ()));
- 	}
-     case INT_LITERAL:
-       {
- 	// parse tuple index field
- 	int index = atoi (t->get_str ().c_str ());
- 	lexer.skip_token ();
- 
- 	if (!skip_token (COLON))
- 	  {
- 	    // skip somewhere?
- 	    return nullptr;
- 	  }
- 
- 	// parse field expression (required)
- 	std::unique_ptr<AST::Expr> expr = parse_expr ();
- 	if (expr == nullptr)
- 	  {
- 	    Error error (t->get_locus (),
- 			 "failed to parse expr in struct (or enum) expr "
- 			 "field with tuple index");
- 	    add_error (std::move (error));
- 
- 	    return nullptr;
- 	  }
- 
- 	return std::unique_ptr<AST::StructExprFieldIndexValue> (
- 	  new AST::StructExprFieldIndexValue (index, std::move (expr),
- 					      std::move (outer_attrs),
- 					      t->get_locus ()));
-       }
-     case DOT_DOT:
-       /* this is a struct base and can't be parsed here, so just return
-        * nothing without erroring */
- 
-       return nullptr;
-     default:
-       add_error (
- 	Error (t->get_locus (),
- 	       "unrecognised token %qs as first token of struct expr field - "
- 	       "expected identifier or integer literal",
- 	       t->get_token_description ()));
- 
-       return nullptr;
-     }
- }
- 
- // "Unexpected token" panic mode - flags gcc error at unexpected token
- // TODO: seems to be unused, remove?
- template <typename ManagedTokenSource>
- void
- Parser<ManagedTokenSource>::unexpected_token (const_TokenPtr t)
- {
-   Error error (t->get_locus (), "unexpected token %qs",
- 	       t->get_token_description ());
-   add_error (std::move (error));
- }
- 
- /* Crappy "error recovery" performed after error by skipping tokens until a
-  * semi-colon is found */
- template <typename ManagedTokenSource>
- void
- Parser<ManagedTokenSource>::skip_after_semicolon ()
- {
-   const_TokenPtr t = lexer.peek_token ();
- 
-   while (t->get_id () != END_OF_FILE && t->get_id () != SEMICOLON)
-     {
-       lexer.skip_token ();
-       t = lexer.peek_token ();
-     }
- 
-   if (t->get_id () == SEMICOLON)
-     lexer.skip_token ();
- }
- 
- /* Skips the current token */
- template <typename ManagedTokenSource>
- void
- Parser<ManagedTokenSource>::skip_token ()
- {
-   lexer.skip_token ();
- }
- 
- /* Checks if current token has inputted id - skips it and returns true if so,
-  * diagnoses an error and returns false otherwise. */
- template <typename ManagedTokenSource>
- bool
- Parser<ManagedTokenSource>::skip_token (TokenId token_id)
- {
-   return expect_token (token_id) != const_TokenPtr ();
- }
- 
- /* Checks if current token is similar to inputted token - skips it and returns
-  * true if so, diagnoses an error and returns false otherwise. */
- template <typename ManagedTokenSource>
- bool
- Parser<ManagedTokenSource>::skip_token (const_TokenPtr token)
- {
-   return expect_token (token) != const_TokenPtr ();
- }
- 
- /* Checks if current token has inputted id - skips it and returns true if so,
-  * returns false otherwise without diagnosing an error */
- template <typename ManagedTokenSource>
- bool
- Parser<ManagedTokenSource>::maybe_skip_token (TokenId token_id)
- {
-   if (lexer.peek_token ()->get_id () != token_id)
-     return false;
-   else
-     return skip_token (token_id);
- }
- 
- /* Checks the current token - if id is same as expected, skips and returns it,
-  * otherwise diagnoses error and returns null. */
- template <typename ManagedTokenSource>
- const_TokenPtr
- Parser<ManagedTokenSource>::expect_token (TokenId token_id)
- {
-   const_TokenPtr t = lexer.peek_token ();
-   if (t->get_id () == token_id)
-     {
-       lexer.skip_token ();
-       return t;
-     }
-   else
-     {
-       Error error (t->get_locus (), "expecting %qs but %qs found",
- 		   get_token_description (token_id),
- 		   t->get_token_description ());
-       add_error (std::move (error));
- 
-       return const_TokenPtr ();
-     }
- }
- 
- /* Checks the current token - if same as expected, skips and returns it,
-  * otherwise diagnoses error and returns null. */
- template <typename ManagedTokenSource>
- const_TokenPtr
- Parser<ManagedTokenSource>::expect_token (const_TokenPtr token_expect)
- {
-   const_TokenPtr t = lexer.peek_token ();
-   if (t->get_id () == token_expect->get_id ()
-       && (!t->should_have_str () || t->get_str () == token_expect->get_str ()))
-     {
-       lexer.skip_token ();
-       return t;
-     }
-   else
-     {
-       Error error (t->get_locus (), "expecting %qs but %qs found",
- 		   token_expect->get_token_description (),
- 		   t->get_token_description ());
-       add_error (std::move (error));
- 
-       return const_TokenPtr ();
-     }
- }
- 
- // Skips all tokens until EOF or }. Don't use.
- template <typename ManagedTokenSource>
- void
- Parser<ManagedTokenSource>::skip_after_end ()
- {
-   const_TokenPtr t = lexer.peek_token ();
- 
-   while (t->get_id () != END_OF_FILE && t->get_id () != RIGHT_CURLY)
-     {
-       lexer.skip_token ();
-       t = lexer.peek_token ();
-     }
- 
-   if (t->get_id () == RIGHT_CURLY)
-     {
-       lexer.skip_token ();
-     }
- }
- 
- /* A slightly more aware error-handler that skips all tokens until it reaches
-  * the end of the block scope (i.e. when left curly brackets = right curly
-  * brackets). Note: assumes currently in the middle of a block. Use
-  * skip_after_next_block to skip based on the assumption that the block
-  * has not been entered yet. */
- template <typename ManagedTokenSource>
- void
- Parser<ManagedTokenSource>::skip_after_end_block ()
- {
-   const_TokenPtr t = lexer.peek_token ();
-   int curly_count = 1;
- 
-   while (curly_count > 0 && t->get_id () != END_OF_FILE)
-     {
-       switch (t->get_id ())
- 	{
- 	case LEFT_CURLY:
- 	  curly_count++;
- 	  break;
- 	case RIGHT_CURLY:
- 	  curly_count--;
- 	  break;
- 	default:
- 	  break;
- 	}
-       lexer.skip_token ();
-       t = lexer.peek_token ();
-     }
- }
- 
- /* Skips tokens until the end of the next block. i.e. assumes that the block
-  * has not been entered yet. */
- template <typename ManagedTokenSource>
- void
- Parser<ManagedTokenSource>::skip_after_next_block ()
- {
-   const_TokenPtr t = lexer.peek_token ();
- 
-   // initial loop - skip until EOF if no left curlies encountered
-   while (t->get_id () != END_OF_FILE && t->get_id () != LEFT_CURLY)
-     {
-       lexer.skip_token ();
- 
-       t = lexer.peek_token ();
-     }
- 
-   // if next token is left, skip it and then skip after the block ends
-   if (t->get_id () == LEFT_CURLY)
-     {
-       lexer.skip_token ();
- 
-       skip_after_end_block ();
-     }
-   // otherwise, do nothing as EOF
- }
- 
- /* Skips all tokens until ] (the end of an attribute) - does not skip the ]
-  * (as designed for attribute body use) */
- template <typename ManagedTokenSource>
- void
- Parser<ManagedTokenSource>::skip_after_end_attribute ()
- {
-   const_TokenPtr t = lexer.peek_token ();
- 
-   while (t->get_id () != RIGHT_SQUARE && t->get_id () != END_OF_FILE)
-     {
-       lexer.skip_token ();
-       t = lexer.peek_token ();
-     }
- 
-   // Don't skip the RIGHT_SQUARE token
- }
- 
- /* Pratt parser impl of parse_expr. FIXME: this is only provisional and
-  * probably will be changed. */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::Expr>
- Parser<ManagedTokenSource>::parse_expr (int right_binding_power,
- 					AST::AttrVec outer_attrs,
- 					ParseRestrictions restrictions)
- {
-   const_TokenPtr current_token = lexer.peek_token ();
-   // Special hack because we are allowed to return nullptr, in that case we
-   // don't want to skip the token, since we don't actually parse it. But if
-   // null isn't allowed it indicates an error, and we want to skip past that.
-   // So return early if it is one of the tokens that ends an expression
-   // (or at least cannot start a new expression).
-   if (restrictions.expr_can_be_null)
-     {
-       TokenId id = current_token->get_id ();
-       if (id == SEMICOLON || id == RIGHT_PAREN || id == RIGHT_CURLY
- 	  || id == RIGHT_SQUARE || id == COMMA || id == LEFT_CURLY)
- 	return nullptr;
-     }
- 
-   ParseRestrictions null_denotation_restrictions = restrictions;
-   null_denotation_restrictions.expr_can_be_stmt = false;
- 
-   // parse null denotation (unary part of expression)
-   std::unique_ptr<AST::Expr> expr
-     = null_denotation ({}, null_denotation_restrictions);
-   if (expr == nullptr)
-     return nullptr;
- 
-   return left_denotations (std::move (expr), right_binding_power,
- 			   std::move (outer_attrs), restrictions);
- }
- 
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::Expr>
- Parser<ManagedTokenSource>::left_denotations (std::unique_ptr<AST::Expr> expr,
- 					      int right_binding_power,
- 					      AST::AttrVec outer_attrs,
- 					      ParseRestrictions restrictions)
- {
-   if (expr == nullptr)
-     {
-       // DEBUG
-       rust_debug ("null denotation is null; returning null for parse_expr");
-       return nullptr;
-     }
- 
-   const_TokenPtr current_token = lexer.peek_token ();
- 
-   if (restrictions.expr_can_be_stmt && !expr->is_expr_without_block ()
-       && current_token->get_id () != DOT
-       && current_token->get_id () != QUESTION_MARK)
-     {
-       rust_debug ("statement expression with block");
-       expr->set_outer_attrs (std::move (outer_attrs));
-       return expr;
-     }
- 
-   restrictions.expr_can_be_stmt = false;
- 
-   // stop parsing if find lower priority token - parse higher priority first
-   while (right_binding_power < left_binding_power (current_token))
-     {
-       lexer.skip_token ();
- 
-       // FIXME attributes should generally be applied to the null denotation.
-       expr = left_denotation (current_token, std::move (expr),
- 			      std::move (outer_attrs), restrictions);
- 
-       if (expr == nullptr)
- 	{
- 	  // DEBUG
- 	  rust_debug ("left denotation is null; returning null for parse_expr");
- 
- 	  return nullptr;
- 	}
- 
-       current_token = lexer.peek_token ();
-     }
- 
-   return expr;
- }
- 
- // Parse expression with lowest left binding power.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::Expr>
- Parser<ManagedTokenSource>::parse_expr (AST::AttrVec outer_attrs,
- 					ParseRestrictions restrictions)
- {
-   return parse_expr (LBP_LOWEST, std::move (outer_attrs), restrictions);
- }
- 
- /* Determines action to take when finding token at beginning of expression. */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::Expr>
- Parser<ManagedTokenSource>::null_denotation (AST::AttrVec outer_attrs,
- 					     ParseRestrictions restrictions)
- {
-   /* note: tok is previous character in input stream, not current one, as
-    * parse_expr skips it before passing it in */
- 
-   /* as a Pratt parser (which works by decomposing expressions into a null
-    * denotation and then a left denotation), null denotations handle primaries
-    * and unary operands (but only prefix unary operands) */
- 
-   auto tok = lexer.peek_token ();
- 
-   switch (tok->get_id ())
-     {
-     case IDENTIFIER:
-     case SELF:
-     case SELF_ALIAS:
-     case DOLLAR_SIGN:
-     case CRATE:
-     case SUPER:
-     case SCOPE_RESOLUTION:
-       {
- 	// DEBUG
- 	rust_debug ("beginning null denotation identifier handling");
- 
- 	/* best option: parse as path, then extract identifier, macro,
- 	 * struct/enum, or just path info from it */
- 	AST::PathInExpression path = parse_path_in_expression ();
- 
- 	return null_denotation_path (std::move (path), std::move (outer_attrs),
- 				     restrictions);
-       }
-     default:
-       if (tok->get_id () == LEFT_SHIFT)
- 	{
- 	  lexer.split_current_token (LEFT_ANGLE, LEFT_ANGLE);
- 	  tok = lexer.peek_token ();
- 	}
- 
-       lexer.skip_token ();
-       return null_denotation_not_path (std::move (tok), std::move (outer_attrs),
- 				       restrictions);
-     }
- }
- 
- // Handling of expresions that start with a path for `null_denotation`.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::Expr>
- Parser<ManagedTokenSource>::null_denotation_path (
-   AST::PathInExpression path, AST::AttrVec outer_attrs,
-   ParseRestrictions restrictions)
- {
-   rust_debug ("parsing null denotation after path");
- 
-   // HACK: always make "self" by itself a path (regardless of next
-   // tokens)
-   if (path.is_single_segment () && path.get_segments ()[0].is_lower_self_seg ())
-     {
-       // HACK: add outer attrs to path
-       path.set_outer_attrs (std::move (outer_attrs));
-       return std::unique_ptr<AST::PathInExpression> (
- 	new AST::PathInExpression (std::move (path)));
-     }
- 
-   // branch on next token
-   const_TokenPtr t = lexer.peek_token ();
-   switch (t->get_id ())
-     {
-     case EXCLAM:
-       // macro
-       return parse_macro_invocation_partial (std::move (path),
- 					     std::move (outer_attrs));
-     case LEFT_CURLY:
-       {
- 	bool not_a_block = lexer.peek_token (1)->get_id () == IDENTIFIER
- 			   && (lexer.peek_token (2)->get_id () == COMMA
- 			       || (lexer.peek_token (2)->get_id () == COLON
- 				   && (lexer.peek_token (4)->get_id () == COMMA
- 				       || !can_tok_start_type (
- 					 lexer.peek_token (3)->get_id ()))));
- 
- 	/* definitely not a block:
- 	 *  path '{' ident ','
- 	 *  path '{' ident ':' [anything] ','
- 	 *  path '{' ident ':' [not a type]
- 	 * otherwise, assume block expr and thus path */
- 	// DEBUG
- 	rust_debug ("values of lookahead: '%s' '%s' '%s' '%s' ",
- 		    lexer.peek_token (1)->get_token_description (),
- 		    lexer.peek_token (2)->get_token_description (),
- 		    lexer.peek_token (3)->get_token_description (),
- 		    lexer.peek_token (4)->get_token_description ());
- 
- 	rust_debug ("can be struct expr: '%s', not a block: '%s'",
- 		    restrictions.can_be_struct_expr ? "true" : "false",
- 		    not_a_block ? "true" : "false");
- 
- 	// struct/enum expr struct
- 	if (!restrictions.can_be_struct_expr && !not_a_block)
- 	  {
- 	    // HACK: add outer attrs to path
- 	    path.set_outer_attrs (std::move (outer_attrs));
- 	    return std::unique_ptr<AST::PathInExpression> (
- 	      new AST::PathInExpression (std::move (path)));
- 	  }
- 	return parse_struct_expr_struct_partial (std::move (path),
- 						 std::move (outer_attrs));
-       }
-     case LEFT_PAREN:
-       // struct/enum expr tuple
-       if (!restrictions.can_be_struct_expr)
- 	{
- 	  // assume path is returned
- 	  // HACK: add outer attributes to path
- 	  path.set_outer_attrs (std::move (outer_attrs));
- 	  return std::unique_ptr<AST::PathInExpression> (
- 	    new AST::PathInExpression (std::move (path)));
- 	}
-       return parse_struct_expr_tuple_partial (std::move (path),
- 					      std::move (outer_attrs));
-     default:
-       // assume path is returned if not single segment
-       if (path.is_single_segment ())
- 	{
- 	  // FIXME: This should probably be returned as a path.
- 	  /* HACK: may have to become permanent, but this is my current
- 	   * identifier expression */
- 	  return std::unique_ptr<AST::IdentifierExpr> (new AST::IdentifierExpr (
- 	    path.get_segments ()[0].get_ident_segment ().as_string (), {},
- 	    path.get_locus ()));
- 	}
-       // HACK: add outer attrs to path
-       path.set_outer_attrs (std::move (outer_attrs));
-       return std::unique_ptr<AST::PathInExpression> (
- 	new AST::PathInExpression (std::move (path)));
-     }
-   rust_unreachable ();
- }
- 
- // Handling of expresions that do not start with a path for `null_denotation`.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::Expr>
- Parser<ManagedTokenSource>::null_denotation_not_path (
-   const_TokenPtr tok, AST::AttrVec outer_attrs, ParseRestrictions restrictions)
- {
-   switch (tok->get_id ())
-     {
-     // FIXME: Handle in null_denotation_path?
-     case LEFT_SHIFT:
-     case LEFT_ANGLE:
-       {
- 	// qualified path
- 	// HACK: add outer attrs to path
- 	AST::QualifiedPathInExpression path
- 	  = parse_qualified_path_in_expression (tok->get_locus ());
- 	path.set_outer_attrs (std::move (outer_attrs));
- 	return std::unique_ptr<AST::QualifiedPathInExpression> (
- 	  new AST::QualifiedPathInExpression (std::move (path)));
-       }
-     // FIXME: delegate to parse_literal_expr instead? would have to rejig
-     // tokens and whatever.
-     // FIXME: for literal exprs, outer attrs should be passed in, and later
-     // error if it does not make up the entire statement.
-     case INT_LITERAL:
-       // we should check the range, but ignore for now
-       // encode as int?
-       return std::unique_ptr<AST::LiteralExpr> (
- 	new AST::LiteralExpr (tok->get_str (), AST::Literal::INT,
- 			      tok->get_type_hint (), {}, tok->get_locus ()));
-     case FLOAT_LITERAL:
-       // encode as float?
-       return std::unique_ptr<AST::LiteralExpr> (
- 	new AST::LiteralExpr (tok->get_str (), AST::Literal::FLOAT,
- 			      tok->get_type_hint (), {}, tok->get_locus ()));
-     case STRING_LITERAL:
-       return std::unique_ptr<AST::LiteralExpr> (
- 	new AST::LiteralExpr (tok->get_str (), AST::Literal::STRING,
- 			      tok->get_type_hint (), {}, tok->get_locus ()));
-     case BYTE_STRING_LITERAL:
-       return std::unique_ptr<AST::LiteralExpr> (
- 	new AST::LiteralExpr (tok->get_str (), AST::Literal::BYTE_STRING,
- 			      tok->get_type_hint (), {}, tok->get_locus ()));
-     case RAW_STRING_LITERAL:
-       return std::unique_ptr<AST::LiteralExpr> (
- 	new AST::LiteralExpr (tok->get_str (), AST::Literal::RAW_STRING,
- 			      tok->get_type_hint (), {}, tok->get_locus ()));
-     case CHAR_LITERAL:
-       return std::unique_ptr<AST::LiteralExpr> (
- 	new AST::LiteralExpr (tok->get_str (), AST::Literal::CHAR,
- 			      tok->get_type_hint (), {}, tok->get_locus ()));
-     case BYTE_CHAR_LITERAL:
-       return std::unique_ptr<AST::LiteralExpr> (
- 	new AST::LiteralExpr (tok->get_str (), AST::Literal::BYTE,
- 			      tok->get_type_hint (), {}, tok->get_locus ()));
-     case TRUE_LITERAL:
-       return std::unique_ptr<AST::LiteralExpr> (
- 	new AST::LiteralExpr (Values::Keywords::TRUE_LITERAL,
- 			      AST::Literal::BOOL, tok->get_type_hint (), {},
- 			      tok->get_locus ()));
-     case FALSE_LITERAL:
-       return std::unique_ptr<AST::LiteralExpr> (
- 	new AST::LiteralExpr (Values::Keywords::FALSE_LITERAL,
- 			      AST::Literal::BOOL, tok->get_type_hint (), {},
- 			      tok->get_locus ()));
-     case LEFT_PAREN:
-       return parse_grouped_or_tuple_expr (std::move (outer_attrs),
- 					  tok->get_locus ());
- 
-     /*case PLUS: { // unary plus operator
- 	// invoke parse_expr recursively with appropriate priority, etc. for
-     below AST::Expr* expr = parse_expr(LBP_UNARY_PLUS);
- 
- 	if (expr == nullptr)
- 	    return nullptr;
- 	// can only apply to integer and float expressions
- 	if (expr->get_type() != integer_type_node || expr->get_type() !=
-     float_type_node) { rust_error_at(tok->get_locus(), "operand of unary
-     plus must be int or float but it is %s", print_type(expr->get_type()));
-     return nullptr;
- 	}
- 
- 	return Tree(expr, tok->get_locus());
-     }*/
-     // Rust has no unary plus operator
-     case MINUS:
-       { // unary minus
- 	ParseRestrictions entered_from_unary;
- 	entered_from_unary.entered_from_unary = true;
- 	if (!restrictions.can_be_struct_expr)
- 	  entered_from_unary.can_be_struct_expr = false;
- 	std::unique_ptr<AST::Expr> expr
- 	  = parse_expr (LBP_UNARY_MINUS, {}, entered_from_unary);
- 
- 	if (expr == nullptr)
- 	  return nullptr;
- 	// can only apply to integer and float expressions
- 	/*if (expr.get_type() != integer_type_node || expr.get_type() !=
- 	float_type_node) { rust_error_at(tok->get_locus(), "operand of unary
- 	minus must be int or float but it is %s",
- 	print_type(expr.get_type())); return Tree::error();
- 	}*/
- 	/* FIXME: when implemented the "get type" method on expr, ensure it is
- 	 * int or float type (except unsigned int). Actually, this would
- 	 * probably have to be done in semantic analysis (as type checking).
- 	 */
- 
- 	/* FIXME: allow outer attributes on these expressions by having an
- 	 * outer attrs parameter in function*/
- 	return std::unique_ptr<AST::NegationExpr> (
- 	  new AST::NegationExpr (std::move (expr), NegationOperator::NEGATE,
- 				 std::move (outer_attrs), tok->get_locus ()));
-       }
-     case EXCLAM:
-       { // logical or bitwise not
- 	ParseRestrictions entered_from_unary;
- 	entered_from_unary.entered_from_unary = true;
- 	if (!restrictions.can_be_struct_expr)
- 	  entered_from_unary.can_be_struct_expr = false;
- 	std::unique_ptr<AST::Expr> expr
- 	  = parse_expr (LBP_UNARY_EXCLAM, {}, entered_from_unary);
- 
- 	if (expr == nullptr)
- 	  return nullptr;
- 	// can only apply to boolean expressions
- 	/*if (expr.get_type() != boolean_type_node) {
- 	    rust_error_at(tok->get_locus(),
- 	      "operand of logical not must be a boolean but it is %s",
- 	      print_type(expr.get_type()));
- 	    return Tree::error();
- 	}*/
- 	/* FIXME: type checking for boolean or integer expressions in semantic
- 	 * analysis */
- 
- 	// FIXME: allow outer attributes on these expressions
- 	return std::unique_ptr<AST::NegationExpr> (
- 	  new AST::NegationExpr (std::move (expr), NegationOperator::NOT,
- 				 std::move (outer_attrs), tok->get_locus ()));
-       }
-     case ASTERISK:
-       {
- 	/* pointer dereference only - HACK: as struct expressions should
- 	 * always be value expressions, cannot be dereferenced */
- 	ParseRestrictions entered_from_unary;
- 	entered_from_unary.entered_from_unary = true;
- 	entered_from_unary.can_be_struct_expr = false;
- 	std::unique_ptr<AST::Expr> expr
- 	  = parse_expr (LBP_UNARY_ASTERISK, {}, entered_from_unary);
- 	// FIXME: allow outer attributes on expression
- 	return std::unique_ptr<AST::DereferenceExpr> (
- 	  new AST::DereferenceExpr (std::move (expr), std::move (outer_attrs),
- 				    tok->get_locus ()));
-       }
-     case AMP:
-       {
- 	// (single) "borrow" expression - shared (mutable) or immutable
- 	std::unique_ptr<AST::Expr> expr = nullptr;
- 	Mutability mutability = Mutability::Imm;
- 	bool raw_borrow = false;
- 
- 	ParseRestrictions entered_from_unary;
- 	entered_from_unary.entered_from_unary = true;
- 	if (!restrictions.can_be_struct_expr)
- 	  entered_from_unary.can_be_struct_expr = false;
- 
- 	auto is_mutability = [] (const_TokenPtr token) {
- 	  return token->get_id () == CONST || token->get_id () == MUT;
- 	};
- 
- 	auto t = lexer.peek_token ();
- 	// Weak raw keyword, we look (1) ahead and treat it as an identifier if
- 	// there is no mut nor const.
- 	if (t->get_id () == IDENTIFIER
- 	    && t->get_str () == Values::WeakKeywords::RAW
- 	    && is_mutability (lexer.peek_token (1)))
- 	  {
- 	    lexer.skip_token ();
- 	    switch (lexer.peek_token ()->get_id ())
- 	      {
- 	      case MUT:
- 		mutability = Mutability::Mut;
- 		break;
- 	      case CONST:
- 		mutability = Mutability::Imm;
- 		break;
- 	      default:
- 		rust_error_at (lexer.peek_token ()->get_locus (),
- 			       "raw borrow should be either const or mut");
- 	      }
- 	    lexer.skip_token ();
- 	    expr = parse_expr (LBP_UNARY_AMP_MUT, {}, entered_from_unary);
- 	    raw_borrow = true;
- 	  }
- 	else if (t->get_id () == MUT)
- 	  {
- 	    lexer.skip_token ();
- 	    expr = parse_expr (LBP_UNARY_AMP_MUT, {}, entered_from_unary);
- 	    mutability = Mutability::Mut;
- 	    raw_borrow = false;
- 	  }
- 	else
- 	  {
- 	    expr = parse_expr (LBP_UNARY_AMP, {}, entered_from_unary);
- 	    raw_borrow = false;
- 	  }
- 
- 	// FIXME: allow outer attributes on expression
- 	return std::unique_ptr<AST::BorrowExpr> (
- 	  new AST::BorrowExpr (std::move (expr), mutability, raw_borrow, false,
- 			       std::move (outer_attrs), tok->get_locus ()));
-       }
-     case LOGICAL_AND:
-       {
- 	// (double) "borrow" expression - shared (mutable) or immutable
- 	std::unique_ptr<AST::Expr> expr = nullptr;
- 	Mutability mutability = Mutability::Imm;
- 
- 	ParseRestrictions entered_from_unary;
- 	entered_from_unary.entered_from_unary = true;
- 
- 	if (lexer.peek_token ()->get_id () == MUT)
- 	  {
- 	    lexer.skip_token ();
- 	    expr = parse_expr (LBP_UNARY_AMP_MUT, {}, entered_from_unary);
- 	    mutability = Mutability::Mut;
- 	  }
- 	else
- 	  {
- 	    expr = parse_expr (LBP_UNARY_AMP, {}, entered_from_unary);
- 	    mutability = Mutability::Imm;
- 	  }
- 
- 	// FIXME: allow outer attributes on expression
- 	return std::unique_ptr<AST::BorrowExpr> (
- 	  new AST::BorrowExpr (std::move (expr), mutability, false, true,
- 			       std::move (outer_attrs), tok->get_locus ()));
-       }
-     case OR:
-     case PIPE:
-     case MOVE:
-       // closure expression
-       return parse_closure_expr_pratt (tok, std::move (outer_attrs));
-     case DOT_DOT:
-       // either "range to" or "range full" expressions
-       return parse_nud_range_exclusive_expr (tok, std::move (outer_attrs));
-     case DOT_DOT_EQ:
-       // range to inclusive expr
-       return parse_range_to_inclusive_expr (tok, std::move (outer_attrs));
-     case RETURN_KW:
-       // FIXME: is this really a null denotation expression?
-       return parse_return_expr (std::move (outer_attrs), tok->get_locus ());
-     case TRY:
-       // FIXME: is this really a null denotation expression?
-       return parse_try_expr (std::move (outer_attrs), tok->get_locus ());
-     case BREAK:
-       // FIXME: is this really a null denotation expression?
-       return parse_break_expr (std::move (outer_attrs), tok->get_locus ());
-     case CONTINUE:
-       return parse_continue_expr (std::move (outer_attrs), tok->get_locus ());
-     case LEFT_CURLY:
-       // ok - this is an expression with block for once.
-       return parse_block_expr (std::move (outer_attrs), tl::nullopt,
- 			       tok->get_locus ());
-     case IF:
-       // if or if let, so more lookahead to find out
-       if (lexer.peek_token ()->get_id () == LET)
- 	{
- 	  // if let expr
- 	  return parse_if_let_expr (std::move (outer_attrs), tok->get_locus ());
- 	}
-       else
- 	{
- 	  // if expr
- 	  return parse_if_expr (std::move (outer_attrs), tok->get_locus ());
- 	}
-     case LIFETIME:
-       return parse_labelled_loop_expr (tok, std::move (outer_attrs));
-     case LOOP:
-       return parse_loop_expr (std::move (outer_attrs), tl::nullopt,
- 			      tok->get_locus ());
-     case WHILE:
-       if (lexer.peek_token ()->get_id () == LET)
- 	{
- 	  return parse_while_let_loop_expr (std::move (outer_attrs));
- 	}
-       else
- 	{
- 	  return parse_while_loop_expr (std::move (outer_attrs), tl::nullopt,
- 					tok->get_locus ());
- 	}
-     case FOR:
-       return parse_for_loop_expr (std::move (outer_attrs), tl::nullopt);
-     case MATCH_KW:
-       // also an expression with block
-       return parse_match_expr (std::move (outer_attrs), tok->get_locus ());
-     case LEFT_SQUARE:
-       // array definition expr (not indexing)
-       return parse_array_expr (std::move (outer_attrs), tok->get_locus ());
-     case UNSAFE:
-       return parse_unsafe_block_expr (std::move (outer_attrs),
- 				      tok->get_locus ());
-     case BOX:
-       return parse_box_expr (std::move (outer_attrs), tok->get_locus ());
-     case UNDERSCORE:
-       add_error (
- 	Error (tok->get_locus (),
- 	       "use of %qs is not allowed on the right-side of an assignment",
- 	       tok->get_token_description ()));
-       return nullptr;
-     case CONST:
-       return parse_const_block_expr (std::move (outer_attrs),
- 				     tok->get_locus ());
-     default:
-       if (!restrictions.expr_can_be_null)
- 	add_error (Error (tok->get_locus (),
- 			  "found unexpected token %qs in null denotation",
- 			  tok->get_token_description ()));
-       return nullptr;
-     }
- }
- 
- /* Called for each token that can appear in infix (between) position. Can be
-  * operators or other punctuation. Returns a function pointer to member
-  * function that implements the left denotation for the token given. */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::Expr>
- Parser<ManagedTokenSource>::left_denotation (const_TokenPtr tok,
- 					     std::unique_ptr<AST::Expr> left,
- 					     AST::AttrVec outer_attrs,
- 					     ParseRestrictions restrictions)
- {
-   // Token passed in has already been skipped, so peek gives "next" token
-   switch (tok->get_id ())
-     {
-     // FIXME: allow for outer attributes to be applied
-     case QUESTION_MARK:
-       {
- 	location_t left_locus = left->get_locus ();
- 	// error propagation expression - unary postfix
- 	return std::unique_ptr<AST::ErrorPropagationExpr> (
- 	  new AST::ErrorPropagationExpr (std::move (left),
- 					 std::move (outer_attrs), left_locus));
-       }
-     case PLUS:
-       // sum expression - binary infix
-       /*return parse_binary_plus_expr (tok, std::move (left),
- 				     std::move (outer_attrs), restrictions);*/
-       return parse_arithmetic_or_logical_expr (tok, std::move (left),
- 					       std::move (outer_attrs),
- 					       ArithmeticOrLogicalOperator::ADD,
- 					       restrictions);
-     case MINUS:
-       // difference expression - binary infix
-       /*return parse_binary_minus_expr (tok, std::move (left),
- 				      std::move (outer_attrs),
- 	 restrictions);*/
-       return parse_arithmetic_or_logical_expr (
- 	tok, std::move (left), std::move (outer_attrs),
- 	ArithmeticOrLogicalOperator::SUBTRACT, restrictions);
-     case ASTERISK:
-       // product expression - binary infix
-       /*return parse_binary_mult_expr (tok, std::move (left),
- 				     std::move (outer_attrs), restrictions);*/
-       return parse_arithmetic_or_logical_expr (
- 	tok, std::move (left), std::move (outer_attrs),
- 	ArithmeticOrLogicalOperator::MULTIPLY, restrictions);
-     case DIV:
-       // quotient expression - binary infix
-       /*return parse_binary_div_expr (tok, std::move (left),
- 				    std::move (outer_attrs), restrictions);*/
-       return parse_arithmetic_or_logical_expr (
- 	tok, std::move (left), std::move (outer_attrs),
- 	ArithmeticOrLogicalOperator::DIVIDE, restrictions);
-     case PERCENT:
-       // modulo expression - binary infix
-       /*return parse_binary_mod_expr (tok, std::move (left),
- 				    std::move (outer_attrs), restrictions);*/
-       return parse_arithmetic_or_logical_expr (
- 	tok, std::move (left), std::move (outer_attrs),
- 	ArithmeticOrLogicalOperator::MODULUS, restrictions);
-     case AMP:
-       // logical or bitwise and expression - binary infix
-       /*return parse_bitwise_and_expr (tok, std::move (left),
- 				     std::move (outer_attrs), restrictions);*/
-       return parse_arithmetic_or_logical_expr (
- 	tok, std::move (left), std::move (outer_attrs),
- 	ArithmeticOrLogicalOperator::BITWISE_AND, restrictions);
-     case PIPE:
-       // logical or bitwise or expression - binary infix
-       /*return parse_bitwise_or_expr (tok, std::move (left),
- 				    std::move (outer_attrs), restrictions);*/
-       return parse_arithmetic_or_logical_expr (
- 	tok, std::move (left), std::move (outer_attrs),
- 	ArithmeticOrLogicalOperator::BITWISE_OR, restrictions);
-     case CARET:
-       // logical or bitwise xor expression - binary infix
-       /*return parse_bitwise_xor_expr (tok, std::move (left),
- 				     std::move (outer_attrs), restrictions);*/
-       return parse_arithmetic_or_logical_expr (
- 	tok, std::move (left), std::move (outer_attrs),
- 	ArithmeticOrLogicalOperator::BITWISE_XOR, restrictions);
-     case LEFT_SHIFT:
-       // left shift expression - binary infix
-       /*return parse_left_shift_expr (tok, std::move (left),
- 				    std::move (outer_attrs), restrictions);*/
-       return parse_arithmetic_or_logical_expr (
- 	tok, std::move (left), std::move (outer_attrs),
- 	ArithmeticOrLogicalOperator::LEFT_SHIFT, restrictions);
-     case RIGHT_SHIFT:
-       // right shift expression - binary infix
-       /*return parse_right_shift_expr (tok, std::move (left),
- 				     std::move (outer_attrs), restrictions);*/
-       return parse_arithmetic_or_logical_expr (
- 	tok, std::move (left), std::move (outer_attrs),
- 	ArithmeticOrLogicalOperator::RIGHT_SHIFT, restrictions);
-     case EQUAL_EQUAL:
-       // equal to expression - binary infix (no associativity)
-       /*return parse_binary_equal_expr (tok, std::move (left),
- 				      std::move (outer_attrs),
- 	 restrictions);*/
-       return parse_comparison_expr (tok, std::move (left),
- 				    std::move (outer_attrs),
- 				    ComparisonOperator::EQUAL, restrictions);
-     case NOT_EQUAL:
-       // not equal to expression - binary infix (no associativity)
-       /*return parse_binary_not_equal_expr (tok, std::move (left),
- 					  std::move (outer_attrs),
- 					  restrictions);*/
-       return parse_comparison_expr (tok, std::move (left),
- 				    std::move (outer_attrs),
- 				    ComparisonOperator::NOT_EQUAL,
- 				    restrictions);
-     case RIGHT_ANGLE:
-       // greater than expression - binary infix (no associativity)
-       /*return parse_binary_greater_than_expr (tok, std::move (left),
- 					     std::move (outer_attrs),
- 					     restrictions);*/
-       return parse_comparison_expr (tok, std::move (left),
- 				    std::move (outer_attrs),
- 				    ComparisonOperator::GREATER_THAN,
- 				    restrictions);
-     case LEFT_ANGLE:
-       // less than expression - binary infix (no associativity)
-       /*return parse_binary_less_than_expr (tok, std::move (left),
- 					  std::move (outer_attrs),
- 					  restrictions);*/
-       return parse_comparison_expr (tok, std::move (left),
- 				    std::move (outer_attrs),
- 				    ComparisonOperator::LESS_THAN,
- 				    restrictions);
-     case GREATER_OR_EQUAL:
-       // greater than or equal to expression - binary infix (no associativity)
-       /*return parse_binary_greater_equal_expr (tok, std::move (left),
- 					      std::move (outer_attrs),
- 					      restrictions);*/
-       return parse_comparison_expr (tok, std::move (left),
- 				    std::move (outer_attrs),
- 				    ComparisonOperator::GREATER_OR_EQUAL,
- 				    restrictions);
-     case LESS_OR_EQUAL:
-       // less than or equal to expression - binary infix (no associativity)
-       /*return parse_binary_less_equal_expr (tok, std::move (left),
- 					   std::move (outer_attrs),
- 					   restrictions);*/
-       return parse_comparison_expr (tok, std::move (left),
- 				    std::move (outer_attrs),
- 				    ComparisonOperator::LESS_OR_EQUAL,
- 				    restrictions);
-     case OR:
-       // lazy logical or expression - binary infix
-       return parse_lazy_or_expr (tok, std::move (left), std::move (outer_attrs),
- 				 restrictions);
-     case LOGICAL_AND:
-       // lazy logical and expression - binary infix
-       return parse_lazy_and_expr (tok, std::move (left),
- 				  std::move (outer_attrs), restrictions);
-     case AS:
-       /* type cast expression - kind of binary infix (RHS is actually a
-        * TypeNoBounds) */
-       return parse_type_cast_expr (tok, std::move (left),
- 				   std::move (outer_attrs), restrictions);
-     case EQUAL:
-       // assignment expression - binary infix (note right-to-left
-       // associativity)
-       return parse_assig_expr (tok, std::move (left), std::move (outer_attrs),
- 			       restrictions);
-     case PLUS_EQ:
-       /* plus-assignment expression - binary infix (note right-to-left
-        * associativity) */
-       /*return parse_plus_assig_expr (tok, std::move (left),
- 				    std::move (outer_attrs), restrictions);*/
-       return parse_compound_assignment_expr (tok, std::move (left),
- 					     std::move (outer_attrs),
- 					     CompoundAssignmentOperator::ADD,
- 					     restrictions);
-     case MINUS_EQ:
-       /* minus-assignment expression - binary infix (note right-to-left
-        * associativity) */
-       /*return parse_minus_assig_expr (tok, std::move (left),
- 				     std::move (outer_attrs), restrictions);*/
-       return parse_compound_assignment_expr (
- 	tok, std::move (left), std::move (outer_attrs),
- 	CompoundAssignmentOperator::SUBTRACT, restrictions);
-     case ASTERISK_EQ:
-       /* multiply-assignment expression - binary infix (note right-to-left
-        * associativity) */
-       /*return parse_mult_assig_expr (tok, std::move (left),
- 				    std::move (outer_attrs), restrictions);*/
-       return parse_compound_assignment_expr (
- 	tok, std::move (left), std::move (outer_attrs),
- 	CompoundAssignmentOperator::MULTIPLY, restrictions);
-     case DIV_EQ:
-       /* division-assignment expression - binary infix (note right-to-left
-        * associativity) */
-       /*return parse_div_assig_expr (tok, std::move (left),
- 				   std::move (outer_attrs), restrictions);*/
-       return parse_compound_assignment_expr (tok, std::move (left),
- 					     std::move (outer_attrs),
- 					     CompoundAssignmentOperator::DIVIDE,
- 					     restrictions);
-     case PERCENT_EQ:
-       /* modulo-assignment expression - binary infix (note right-to-left
-        * associativity) */
-       /*return parse_mod_assig_expr (tok, std::move (left),
- 				   std::move (outer_attrs), restrictions);*/
-       return parse_compound_assignment_expr (
- 	tok, std::move (left), std::move (outer_attrs),
- 	CompoundAssignmentOperator::MODULUS, restrictions);
-     case AMP_EQ:
-       /* bitwise and-assignment expression - binary infix (note right-to-left
-        * associativity) */
-       /*return parse_and_assig_expr (tok, std::move (left),
- 				   std::move (outer_attrs), restrictions);*/
-       return parse_compound_assignment_expr (
- 	tok, std::move (left), std::move (outer_attrs),
- 	CompoundAssignmentOperator::BITWISE_AND, restrictions);
-     case PIPE_EQ:
-       /* bitwise or-assignment expression - binary infix (note right-to-left
-        * associativity) */
-       /*return parse_or_assig_expr (tok, std::move (left),
- 				  std::move (outer_attrs), restrictions);*/
-       return parse_compound_assignment_expr (
- 	tok, std::move (left), std::move (outer_attrs),
- 	CompoundAssignmentOperator::BITWISE_OR, restrictions);
-     case CARET_EQ:
-       /* bitwise xor-assignment expression - binary infix (note right-to-left
-        * associativity) */
-       /*return parse_xor_assig_expr (tok, std::move (left),
- 				   std::move (outer_attrs), restrictions);*/
-       return parse_compound_assignment_expr (
- 	tok, std::move (left), std::move (outer_attrs),
- 	CompoundAssignmentOperator::BITWISE_XOR, restrictions);
-     case LEFT_SHIFT_EQ:
-       /* left shift-assignment expression - binary infix (note right-to-left
-        * associativity) */
-       /*return parse_left_shift_assig_expr (tok, std::move (left),
- 					  std::move (outer_attrs),
- 					  restrictions);*/
-       return parse_compound_assignment_expr (
- 	tok, std::move (left), std::move (outer_attrs),
- 	CompoundAssignmentOperator::LEFT_SHIFT, restrictions);
-     case RIGHT_SHIFT_EQ:
-       /* right shift-assignment expression - binary infix (note right-to-left
-        * associativity) */
-       /*return parse_right_shift_assig_expr (tok, std::move (left),
- 					   std::move (outer_attrs),
- 					   restrictions);*/
-       return parse_compound_assignment_expr (
- 	tok, std::move (left), std::move (outer_attrs),
- 	CompoundAssignmentOperator::RIGHT_SHIFT, restrictions);
-     case DOT_DOT:
-       /* range exclusive expression - binary infix (no associativity)
-        * either "range" or "range from" */
-       return parse_led_range_exclusive_expr (tok, std::move (left),
- 					     std::move (outer_attrs),
- 					     restrictions);
-     case DOT_DOT_EQ:
-       /* range inclusive expression - binary infix (no associativity)
-        * unambiguously RangeInclusiveExpr */
-       return parse_range_inclusive_expr (tok, std::move (left),
- 					 std::move (outer_attrs), restrictions);
-     case SCOPE_RESOLUTION:
-       // path expression - binary infix? FIXME should this even be parsed
-       // here?
-       add_error (
- 	Error (tok->get_locus (),
- 	       "found scope resolution operator in left denotation "
- 	       "function - this should probably be handled elsewhere"));
- 
-       return nullptr;
-     case DOT:
-       {
- 	/* field expression or method call - relies on parentheses after next
- 	 * identifier or await if token after is "await" (unary postfix) or
- 	 * tuple index if token after is a decimal int literal */
- 
- 	const_TokenPtr next_tok = lexer.peek_token ();
- 	if (next_tok->get_id () == IDENTIFIER
- 	    && next_tok->get_str () == Values::Keywords::AWAIT)
- 	  {
- 	    // await expression
- 	    return parse_await_expr (tok, std::move (left),
- 				     std::move (outer_attrs));
- 	  }
- 	else if (next_tok->get_id () == INT_LITERAL)
- 	  {
- 	    // tuple index expression - TODO check for decimal int literal
- 	    return parse_tuple_index_expr (tok, std::move (left),
- 					   std::move (outer_attrs),
- 					   restrictions);
- 	  }
- 	else if (next_tok->get_id () == FLOAT_LITERAL)
- 	  {
- 	    // Lexer has misidentified a tuple index as a float literal
- 	    // eg: `(x, (y, z)).1.0` -> 1.0 has been identified as a float
- 	    // literal. This means we should split it into three new separate
- 	    // tokens, the first tuple index, the dot and the second tuple
- 	    // index.
- 	    auto current_loc = next_tok->get_locus ();
- 	    auto str = next_tok->get_str ();
- 	    auto dot_pos = str.find (".");
- 	    auto prefix = str.substr (0, dot_pos);
- 	    auto suffix = str.substr (dot_pos + 1);
- 	    if (dot_pos == str.size () - 1)
- 	      lexer.split_current_token (
- 		{Token::make_int (current_loc, std::move (prefix),
- 				  CORETYPE_PURE_DECIMAL),
- 		 Token::make (DOT, current_loc + 1)});
- 	    else
- 	      lexer.split_current_token (
- 		{Token::make_int (current_loc, std::move (prefix),
- 				  CORETYPE_PURE_DECIMAL),
- 		 Token::make (DOT, current_loc + 1),
- 		 Token::make_int (current_loc + 2, std::move (suffix),
- 				  CORETYPE_PURE_DECIMAL)});
- 	    return parse_tuple_index_expr (tok, std::move (left),
- 					   std::move (outer_attrs),
- 					   restrictions);
- 	  }
- 	else if (next_tok->get_id () == IDENTIFIER
- 		 && lexer.peek_token (1)->get_id () != LEFT_PAREN
- 		 && lexer.peek_token (1)->get_id () != SCOPE_RESOLUTION)
- 	  {
- 	    /* field expression (or should be) - FIXME: scope resolution right
- 	     * after identifier should always be method, I'm pretty sure */
- 	    return parse_field_access_expr (tok, std::move (left),
- 					    std::move (outer_attrs),
- 					    restrictions);
- 	  }
- 	else
- 	  {
- 	    // method call (probably)
- 	    return parse_method_call_expr (tok, std::move (left),
- 					   std::move (outer_attrs),
- 					   restrictions);
- 	  }
-       }
-     case LEFT_PAREN:
-       // function call - method call is based on dot notation first
-       return parse_function_call_expr (tok, std::move (left),
- 				       std::move (outer_attrs), restrictions);
-     case LEFT_SQUARE:
-       // array or slice index expression (pseudo binary infix)
-       return parse_index_expr (tok, std::move (left), std::move (outer_attrs),
- 			       restrictions);
-     default:
-       add_error (Error (tok->get_locus (),
- 			"found unexpected token %qs in left denotation",
- 			tok->get_token_description ()));
- 
-       return nullptr;
-     }
- }
- 
- /* Returns the left binding power for the given ArithmeticOrLogicalExpr type.
-  * TODO make constexpr? Would that even do anything useful? */
- inline binding_powers
- get_lbp_for_arithmetic_or_logical_expr (
-   AST::ArithmeticOrLogicalExpr::ExprType expr_type)
- {
-   switch (expr_type)
-     {
-     case ArithmeticOrLogicalOperator::ADD:
-       return LBP_PLUS;
-     case ArithmeticOrLogicalOperator::SUBTRACT:
-       return LBP_MINUS;
-     case ArithmeticOrLogicalOperator::MULTIPLY:
-       return LBP_MUL;
-     case ArithmeticOrLogicalOperator::DIVIDE:
-       return LBP_DIV;
-     case ArithmeticOrLogicalOperator::MODULUS:
-       return LBP_MOD;
-     case ArithmeticOrLogicalOperator::BITWISE_AND:
-       return LBP_AMP;
-     case ArithmeticOrLogicalOperator::BITWISE_OR:
-       return LBP_PIPE;
-     case ArithmeticOrLogicalOperator::BITWISE_XOR:
-       return LBP_CARET;
-     case ArithmeticOrLogicalOperator::LEFT_SHIFT:
-       return LBP_L_SHIFT;
-     case ArithmeticOrLogicalOperator::RIGHT_SHIFT:
-       return LBP_R_SHIFT;
-     default:
-       // WTF? should not happen, this is an error
-       rust_unreachable ();
- 
-       return LBP_PLUS;
-     }
- }
- 
- // Parses an arithmetic or logical expression (with Pratt parsing).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::ArithmeticOrLogicalExpr>
- Parser<ManagedTokenSource>::parse_arithmetic_or_logical_expr (
-   const_TokenPtr, std::unique_ptr<AST::Expr> left, AST::AttrVec,
-   AST::ArithmeticOrLogicalExpr::ExprType expr_type,
-   ParseRestrictions restrictions)
- {
-   // parse RHS (as tok has already been consumed in parse_expression)
-   std::unique_ptr<AST::Expr> right
-     = parse_expr (get_lbp_for_arithmetic_or_logical_expr (expr_type),
- 		  AST::AttrVec (), restrictions);
-   if (right == nullptr)
-     return nullptr;
- 
-   // TODO: check types. actually, do so during semantic analysis
-   location_t locus = left->get_locus ();
- 
-   return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
-     new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
- 				      expr_type, locus));
- }
- 
- // Parses a binary addition expression (with Pratt parsing).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::ArithmeticOrLogicalExpr>
- Parser<ManagedTokenSource>::parse_binary_plus_expr (
-   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
-   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
- {
-   // parse RHS (as tok has already been consumed in parse_expression)
-   std::unique_ptr<AST::Expr> right
-     = parse_expr (LBP_PLUS, AST::AttrVec (), restrictions);
-   if (right == nullptr)
-     return nullptr;
- 
-   // TODO: check types. actually, do so during semantic analysis
-   location_t locus = left->get_locus ();
- 
-   return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
-     new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
- 				      ArithmeticOrLogicalOperator::ADD, locus));
- }
- 
- // Parses a binary subtraction expression (with Pratt parsing).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::ArithmeticOrLogicalExpr>
- Parser<ManagedTokenSource>::parse_binary_minus_expr (
-   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
-   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
- {
-   // parse RHS (as tok has already been consumed in parse_expression)
-   std::unique_ptr<AST::Expr> right
-     = parse_expr (LBP_MINUS, AST::AttrVec (), restrictions);
-   if (right == nullptr)
-     return nullptr;
- 
-   // TODO: check types. actually, do so during semantic analysis
-   location_t locus = left->get_locus ();
- 
-   return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
-     new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
- 				      ArithmeticOrLogicalOperator::SUBTRACT,
- 				      locus));
- }
- 
- // Parses a binary multiplication expression (with Pratt parsing).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::ArithmeticOrLogicalExpr>
- Parser<ManagedTokenSource>::parse_binary_mult_expr (
-   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
-   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
- {
-   // parse RHS (as tok has already been consumed in parse_expression)
-   std::unique_ptr<AST::Expr> right
-     = parse_expr (LBP_MUL, AST::AttrVec (), restrictions);
-   if (right == nullptr)
-     return nullptr;
- 
-   // TODO: check types. actually, do so during semantic analysis
-   location_t locus = left->get_locus ();
- 
-   return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
-     new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
- 				      ArithmeticOrLogicalOperator::MULTIPLY,
- 				      locus));
- }
- 
- // Parses a binary division expression (with Pratt parsing).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::ArithmeticOrLogicalExpr>
- Parser<ManagedTokenSource>::parse_binary_div_expr (
-   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
-   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
- {
-   // parse RHS (as tok has already been consumed in parse_expression)
-   std::unique_ptr<AST::Expr> right
-     = parse_expr (LBP_DIV, AST::AttrVec (), restrictions);
-   if (right == nullptr)
-     return nullptr;
- 
-   // TODO: check types. actually, do so during semantic analysis
-   location_t locus = left->get_locus ();
- 
-   return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
-     new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
- 				      ArithmeticOrLogicalOperator::DIVIDE,
- 				      locus));
- }
- 
- // Parses a binary modulo expression (with Pratt parsing).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::ArithmeticOrLogicalExpr>
- Parser<ManagedTokenSource>::parse_binary_mod_expr (
-   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
-   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
- {
-   // parse RHS (as tok has already been consumed in parse_expression)
-   std::unique_ptr<AST::Expr> right
-     = parse_expr (LBP_MOD, AST::AttrVec (), restrictions);
-   if (right == nullptr)
-     return nullptr;
- 
-   // TODO: check types. actually, do so during semantic analysis
-   location_t locus = left->get_locus ();
- 
-   return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
-     new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
- 				      ArithmeticOrLogicalOperator::MODULUS,
- 				      locus));
- }
- 
- /* Parses a binary bitwise (or eager logical) and expression (with Pratt
-  * parsing). */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::ArithmeticOrLogicalExpr>
- Parser<ManagedTokenSource>::parse_bitwise_and_expr (
-   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
-   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
- {
-   // parse RHS (as tok has already been consumed in parse_expression)
-   std::unique_ptr<AST::Expr> right
-     = parse_expr (LBP_AMP, AST::AttrVec (), restrictions);
-   if (right == nullptr)
-     return nullptr;
- 
-   // TODO: check types. actually, do so during semantic analysis
-   location_t locus = left->get_locus ();
- 
-   return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
-     new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
- 				      ArithmeticOrLogicalOperator::BITWISE_AND,
- 				      locus));
- }
- 
- /* Parses a binary bitwise (or eager logical) or expression (with Pratt
-  * parsing). */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::ArithmeticOrLogicalExpr>
- Parser<ManagedTokenSource>::parse_bitwise_or_expr (
-   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
-   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
- {
-   // parse RHS (as tok has already been consumed in parse_expression)
-   std::unique_ptr<AST::Expr> right
-     = parse_expr (LBP_PIPE, AST::AttrVec (), restrictions);
-   if (right == nullptr)
-     return nullptr;
- 
-   // TODO: check types. actually, do so during semantic analysis
-   location_t locus = left->get_locus ();
- 
-   return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
-     new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
- 				      ArithmeticOrLogicalOperator::BITWISE_OR,
- 				      locus));
- }
- 
- /* Parses a binary bitwise (or eager logical) xor expression (with Pratt
-  * parsing). */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::ArithmeticOrLogicalExpr>
- Parser<ManagedTokenSource>::parse_bitwise_xor_expr (
-   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
-   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
- {
-   // parse RHS (as tok has already been consumed in parse_expression)
-   std::unique_ptr<AST::Expr> right
-     = parse_expr (LBP_CARET, AST::AttrVec (), restrictions);
-   if (right == nullptr)
-     return nullptr;
- 
-   // TODO: check types. actually, do so during semantic analysis
-   location_t locus = left->get_locus ();
- 
-   return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
-     new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
- 				      ArithmeticOrLogicalOperator::BITWISE_XOR,
- 				      locus));
- }
- 
- // Parses a binary left shift expression (with Pratt parsing).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::ArithmeticOrLogicalExpr>
- Parser<ManagedTokenSource>::parse_left_shift_expr (
-   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
-   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
- {
-   // parse RHS (as tok has already been consumed in parse_expression)
-   std::unique_ptr<AST::Expr> right
-     = parse_expr (LBP_L_SHIFT, AST::AttrVec (), restrictions);
-   if (right == nullptr)
-     return nullptr;
- 
-   // TODO: check types. actually, do so during semantic analysis
-   location_t locus = left->get_locus ();
- 
-   return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
-     new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
- 				      ArithmeticOrLogicalOperator::LEFT_SHIFT,
- 				      locus));
- }
- 
- // Parses a binary right shift expression (with Pratt parsing).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::ArithmeticOrLogicalExpr>
- Parser<ManagedTokenSource>::parse_right_shift_expr (
-   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
-   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
- {
-   // parse RHS (as tok has already been consumed in parse_expression)
-   std::unique_ptr<AST::Expr> right
-     = parse_expr (LBP_R_SHIFT, AST::AttrVec (), restrictions);
-   if (right == nullptr)
-     return nullptr;
- 
-   // TODO: check types. actually, do so during semantic analysis
-   location_t locus = left->get_locus ();
- 
-   return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
-     new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
- 				      ArithmeticOrLogicalOperator::RIGHT_SHIFT,
- 				      locus));
- }
- 
- /* Returns the left binding power for the given ComparisonExpr type.
-  * TODO make constexpr? Would that even do anything useful? */
- inline binding_powers
- get_lbp_for_comparison_expr (AST::ComparisonExpr::ExprType expr_type)
- {
-   switch (expr_type)
-     {
-     case ComparisonOperator::EQUAL:
-       return LBP_EQUAL;
-     case ComparisonOperator::NOT_EQUAL:
-       return LBP_NOT_EQUAL;
-     case ComparisonOperator::GREATER_THAN:
-       return LBP_GREATER_THAN;
-     case ComparisonOperator::LESS_THAN:
-       return LBP_SMALLER_THAN;
-     case ComparisonOperator::GREATER_OR_EQUAL:
-       return LBP_GREATER_EQUAL;
-     case ComparisonOperator::LESS_OR_EQUAL:
-       return LBP_SMALLER_EQUAL;
-     default:
-       // WTF? should not happen, this is an error
-       rust_unreachable ();
- 
-       return LBP_EQUAL;
-     }
- }
- 
- /* Parses a ComparisonExpr of given type and LBP. TODO find a way to only
-  * specify one and have the other looked up - e.g. specify ExprType and
-  * binding power is looked up? */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::ComparisonExpr>
- Parser<ManagedTokenSource>::parse_comparison_expr (
-   const_TokenPtr, std::unique_ptr<AST::Expr> left, AST::AttrVec,
-   AST::ComparisonExpr::ExprType expr_type, ParseRestrictions restrictions)
- {
-   // parse RHS (as tok has already been consumed in parse_expression)
-   std::unique_ptr<AST::Expr> right
-     = parse_expr (get_lbp_for_comparison_expr (expr_type), AST::AttrVec (),
- 		  restrictions);
-   if (right == nullptr)
-     return nullptr;
- 
-   // TODO: check types. actually, do so during semantic analysis
-   location_t locus = left->get_locus ();
- 
-   return std::unique_ptr<AST::ComparisonExpr> (
-     new AST::ComparisonExpr (std::move (left), std::move (right), expr_type,
- 			     locus));
- }
- 
- // Parses a binary equal to expression (with Pratt parsing).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::ComparisonExpr>
- Parser<ManagedTokenSource>::parse_binary_equal_expr (
-   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
-   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
- {
-   // parse RHS (as tok has already been consumed in parse_expression)
-   std::unique_ptr<AST::Expr> right
-     = parse_expr (LBP_EQUAL, AST::AttrVec (), restrictions);
-   if (right == nullptr)
-     return nullptr;
- 
-   // TODO: check types. actually, do so during semantic analysis
-   location_t locus = left->get_locus ();
- 
-   return std::unique_ptr<AST::ComparisonExpr> (
-     new AST::ComparisonExpr (std::move (left), std::move (right),
- 			     ComparisonOperator::EQUAL, locus));
- }
- 
- // Parses a binary not equal to expression (with Pratt parsing).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::ComparisonExpr>
- Parser<ManagedTokenSource>::parse_binary_not_equal_expr (
-   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
-   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
- {
-   // parse RHS (as tok has already been consumed in parse_expression)
-   std::unique_ptr<AST::Expr> right
-     = parse_expr (LBP_NOT_EQUAL, AST::AttrVec (), restrictions);
-   if (right == nullptr)
-     return nullptr;
- 
-   // TODO: check types. actually, do so during semantic analysis
-   location_t locus = left->get_locus ();
- 
-   return std::unique_ptr<AST::ComparisonExpr> (
-     new AST::ComparisonExpr (std::move (left), std::move (right),
- 			     ComparisonOperator::NOT_EQUAL, locus));
- }
- 
- // Parses a binary greater than expression (with Pratt parsing).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::ComparisonExpr>
- Parser<ManagedTokenSource>::parse_binary_greater_than_expr (
-   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
-   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
- {
-   // parse RHS (as tok has already been consumed in parse_expression)
-   std::unique_ptr<AST::Expr> right
-     = parse_expr (LBP_GREATER_THAN, AST::AttrVec (), restrictions);
-   if (right == nullptr)
-     return nullptr;
- 
-   // TODO: check types. actually, do so during semantic analysis
-   location_t locus = left->get_locus ();
- 
-   return std::unique_ptr<AST::ComparisonExpr> (
-     new AST::ComparisonExpr (std::move (left), std::move (right),
- 			     ComparisonOperator::GREATER_THAN, locus));
- }
- 
- // Parses a binary less than expression (with Pratt parsing).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::ComparisonExpr>
- Parser<ManagedTokenSource>::parse_binary_less_than_expr (
-   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
-   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
- {
-   // parse RHS (as tok has already been consumed in parse_expression)
-   std::unique_ptr<AST::Expr> right
-     = parse_expr (LBP_SMALLER_THAN, AST::AttrVec (), restrictions);
-   if (right == nullptr)
-     return nullptr;
- 
-   // TODO: check types. actually, do so during semantic analysis
-   location_t locus = left->get_locus ();
- 
-   return std::unique_ptr<AST::ComparisonExpr> (
-     new AST::ComparisonExpr (std::move (left), std::move (right),
- 			     ComparisonOperator::LESS_THAN, locus));
- }
- 
- // Parses a binary greater than or equal to expression (with Pratt parsing).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::ComparisonExpr>
- Parser<ManagedTokenSource>::parse_binary_greater_equal_expr (
-   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
-   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
- {
-   // parse RHS (as tok has already been consumed in parse_expression)
-   std::unique_ptr<AST::Expr> right
-     = parse_expr (LBP_GREATER_EQUAL, AST::AttrVec (), restrictions);
-   if (right == nullptr)
-     return nullptr;
- 
-   // TODO: check types. actually, do so during semantic analysis
-   location_t locus = left->get_locus ();
- 
-   return std::unique_ptr<AST::ComparisonExpr> (
-     new AST::ComparisonExpr (std::move (left), std::move (right),
- 			     ComparisonOperator::GREATER_OR_EQUAL, locus));
- }
- 
- // Parses a binary less than or equal to expression (with Pratt parsing).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::ComparisonExpr>
- Parser<ManagedTokenSource>::parse_binary_less_equal_expr (
-   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
-   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
- {
-   // parse RHS (as tok has already been consumed in parse_expression)
-   std::unique_ptr<AST::Expr> right
-     = parse_expr (LBP_SMALLER_EQUAL, AST::AttrVec (), restrictions);
-   if (right == nullptr)
-     return nullptr;
- 
-   // TODO: check types. actually, do so during semantic analysis
-   location_t locus = left->get_locus ();
- 
-   return std::unique_ptr<AST::ComparisonExpr> (
-     new AST::ComparisonExpr (std::move (left), std::move (right),
- 			     ComparisonOperator::LESS_OR_EQUAL, locus));
- }
- 
- // Parses a binary lazy boolean or expression (with Pratt parsing).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::LazyBooleanExpr>
- Parser<ManagedTokenSource>::parse_lazy_or_expr (
-   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
-   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
- {
-   // parse RHS (as tok has already been consumed in parse_expression)
-   std::unique_ptr<AST::Expr> right
-     = parse_expr (LBP_LOGICAL_OR, AST::AttrVec (), restrictions);
-   if (right == nullptr)
-     return nullptr;
- 
-   // TODO: check types. actually, do so during semantic analysis
-   location_t locus = left->get_locus ();
- 
-   return std::unique_ptr<AST::LazyBooleanExpr> (
-     new AST::LazyBooleanExpr (std::move (left), std::move (right),
- 			      LazyBooleanOperator::LOGICAL_OR, locus));
- }
- 
- // Parses a binary lazy boolean and expression (with Pratt parsing).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::LazyBooleanExpr>
- Parser<ManagedTokenSource>::parse_lazy_and_expr (
-   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
-   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
- {
-   // parse RHS (as tok has already been consumed in parse_expression)
-   std::unique_ptr<AST::Expr> right
-     = parse_expr (LBP_LOGICAL_AND, AST::AttrVec (), restrictions);
-   if (right == nullptr)
-     return nullptr;
- 
-   // TODO: check types. actually, do so during semantic analysis
-   location_t locus = left->get_locus ();
- 
-   return std::unique_ptr<AST::LazyBooleanExpr> (
-     new AST::LazyBooleanExpr (std::move (left), std::move (right),
- 			      LazyBooleanOperator::LOGICAL_AND, locus));
- }
- 
- // Parses a pseudo-binary infix type cast expression (with Pratt parsing).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::TypeCastExpr>
- Parser<ManagedTokenSource>::parse_type_cast_expr (
-   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> expr_to_cast,
-   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED,
-   ParseRestrictions restrictions ATTRIBUTE_UNUSED)
- {
-   // parse RHS (as tok has already been consumed in parse_expression)
-   std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
-   if (type == nullptr)
-     return nullptr;
-   // FIXME: how do I get precedence put in here?
- 
-   // TODO: check types. actually, do so during semantic analysis
-   location_t locus = expr_to_cast->get_locus ();
- 
-   return std::unique_ptr<AST::TypeCastExpr> (
-     new AST::TypeCastExpr (std::move (expr_to_cast), std::move (type), locus));
- }
- 
- // Parses a binary assignment expression (with Pratt parsing).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::AssignmentExpr>
- Parser<ManagedTokenSource>::parse_assig_expr (
-   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
-   AST::AttrVec outer_attrs, ParseRestrictions restrictions)
- {
-   // parse RHS (as tok has already been consumed in parse_expression)
-   std::unique_ptr<AST::Expr> right
-     = parse_expr (LBP_ASSIG - 1, AST::AttrVec (), restrictions);
-   if (right == nullptr)
-     return nullptr;
-   // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
- 
-   // TODO: check types. actually, do so during semantic analysis
-   location_t locus = left->get_locus ();
- 
-   return std::unique_ptr<AST::AssignmentExpr> (
-     new AST::AssignmentExpr (std::move (left), std::move (right),
- 			     std::move (outer_attrs), locus));
- }
- 
- /* Returns the left binding power for the given CompoundAssignmentExpr type.
-  * TODO make constexpr? Would that even do anything useful? */
- inline binding_powers
- get_lbp_for_compound_assignment_expr (
-   AST::CompoundAssignmentExpr::ExprType expr_type)
- {
-   switch (expr_type)
-     {
-     case CompoundAssignmentOperator::ADD:
-       return LBP_PLUS;
-     case CompoundAssignmentOperator::SUBTRACT:
-       return LBP_MINUS;
-     case CompoundAssignmentOperator::MULTIPLY:
-       return LBP_MUL;
-     case CompoundAssignmentOperator::DIVIDE:
-       return LBP_DIV;
-     case CompoundAssignmentOperator::MODULUS:
-       return LBP_MOD;
-     case CompoundAssignmentOperator::BITWISE_AND:
-       return LBP_AMP;
-     case CompoundAssignmentOperator::BITWISE_OR:
-       return LBP_PIPE;
-     case CompoundAssignmentOperator::BITWISE_XOR:
-       return LBP_CARET;
-     case CompoundAssignmentOperator::LEFT_SHIFT:
-       return LBP_L_SHIFT;
-     case CompoundAssignmentOperator::RIGHT_SHIFT:
-       return LBP_R_SHIFT;
-     default:
-       // WTF? should not happen, this is an error
-       rust_unreachable ();
- 
-       return LBP_PLUS;
-     }
- }
- 
- // Parses a compound assignment expression (with Pratt parsing).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::CompoundAssignmentExpr>
- Parser<ManagedTokenSource>::parse_compound_assignment_expr (
-   const_TokenPtr, std::unique_ptr<AST::Expr> left, AST::AttrVec,
-   AST::CompoundAssignmentExpr::ExprType expr_type,
-   ParseRestrictions restrictions)
- {
-   // parse RHS (as tok has already been consumed in parse_expression)
-   std::unique_ptr<AST::Expr> right
-     = parse_expr (get_lbp_for_compound_assignment_expr (expr_type) - 1,
- 		  AST::AttrVec (), restrictions);
-   if (right == nullptr)
-     return nullptr;
-   // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
- 
-   // TODO: check types. actually, do so during semantic analysis
-   location_t locus = left->get_locus ();
- 
-   return std::unique_ptr<AST::CompoundAssignmentExpr> (
-     new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
- 				     expr_type, locus));
- }
- 
- // Parses a binary add-assignment expression (with Pratt parsing).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::CompoundAssignmentExpr>
- Parser<ManagedTokenSource>::parse_plus_assig_expr (
-   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
-   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
- {
-   // parse RHS (as tok has already been consumed in parse_expression)
-   std::unique_ptr<AST::Expr> right
-     = parse_expr (LBP_PLUS_ASSIG - 1, AST::AttrVec (), restrictions);
-   if (right == nullptr)
-     return nullptr;
-   // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
- 
-   // TODO: check types. actually, do so during semantic analysis
-   location_t locus = left->get_locus ();
- 
-   return std::unique_ptr<AST::CompoundAssignmentExpr> (
-     new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
- 				     CompoundAssignmentOperator::ADD, locus));
- }
- 
- // Parses a binary minus-assignment expression (with Pratt parsing).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::CompoundAssignmentExpr>
- Parser<ManagedTokenSource>::parse_minus_assig_expr (
-   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
-   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
- {
-   // parse RHS (as tok has already been consumed in parse_expression)
-   std::unique_ptr<AST::Expr> right
-     = parse_expr (LBP_MINUS_ASSIG - 1, AST::AttrVec (), restrictions);
-   if (right == nullptr)
-     return nullptr;
-   // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
- 
-   // TODO: check types. actually, do so during semantic analysis
-   location_t locus = left->get_locus ();
- 
-   return std::unique_ptr<AST::CompoundAssignmentExpr> (
-     new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
- 				     CompoundAssignmentOperator::SUBTRACT,
- 				     locus));
- }
- 
- // Parses a binary multiplication-assignment expression (with Pratt parsing).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::CompoundAssignmentExpr>
- Parser<ManagedTokenSource>::parse_mult_assig_expr (
-   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
-   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
- {
-   // parse RHS (as tok has already been consumed in parse_expression)
-   std::unique_ptr<AST::Expr> right
-     = parse_expr (LBP_MULT_ASSIG - 1, AST::AttrVec (), restrictions);
-   if (right == nullptr)
-     return nullptr;
-   // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
- 
-   // TODO: check types. actually, do so during semantic analysis
-   location_t locus = left->get_locus ();
- 
-   return std::unique_ptr<AST::CompoundAssignmentExpr> (
-     new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
- 				     CompoundAssignmentOperator::MULTIPLY,
- 				     locus));
- }
- 
- // Parses a binary division-assignment expression (with Pratt parsing).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::CompoundAssignmentExpr>
- Parser<ManagedTokenSource>::parse_div_assig_expr (
-   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
-   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
- {
-   // parse RHS (as tok has already been consumed in parse_expression)
-   std::unique_ptr<AST::Expr> right
-     = parse_expr (LBP_DIV_ASSIG - 1, AST::AttrVec (), restrictions);
-   if (right == nullptr)
-     return nullptr;
-   // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
- 
-   // TODO: check types. actually, do so during semantic analysis
-   location_t locus = left->get_locus ();
- 
-   return std::unique_ptr<AST::CompoundAssignmentExpr> (
-     new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
- 				     CompoundAssignmentOperator::DIVIDE,
- 				     locus));
- }
- 
- // Parses a binary modulo-assignment expression (with Pratt parsing).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::CompoundAssignmentExpr>
- Parser<ManagedTokenSource>::parse_mod_assig_expr (
-   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
-   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
- {
-   // parse RHS (as tok has already been consumed in parse_expression)
-   std::unique_ptr<AST::Expr> right
-     = parse_expr (LBP_MOD_ASSIG - 1, AST::AttrVec (), restrictions);
-   if (right == nullptr)
-     return nullptr;
-   // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
- 
-   // TODO: check types. actually, do so during semantic analysis
-   location_t locus = left->get_locus ();
- 
-   return std::unique_ptr<AST::CompoundAssignmentExpr> (
-     new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
- 				     CompoundAssignmentOperator::MODULUS,
- 				     locus));
- }
- 
- // Parses a binary and-assignment expression (with Pratt parsing).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::CompoundAssignmentExpr>
- Parser<ManagedTokenSource>::parse_and_assig_expr (
-   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
-   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
- {
-   // parse RHS (as tok has already been consumed in parse_expression)
-   std::unique_ptr<AST::Expr> right
-     = parse_expr (LBP_AMP_ASSIG - 1, AST::AttrVec (), restrictions);
-   if (right == nullptr)
-     return nullptr;
-   // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
- 
-   // TODO: check types. actually, do so during semantic analysis
-   location_t locus = left->get_locus ();
- 
-   return std::unique_ptr<AST::CompoundAssignmentExpr> (
-     new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
- 				     CompoundAssignmentOperator::BITWISE_AND,
- 				     locus));
- }
- 
- // Parses a binary or-assignment expression (with Pratt parsing).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::CompoundAssignmentExpr>
- Parser<ManagedTokenSource>::parse_or_assig_expr (
-   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
-   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
- {
-   // parse RHS (as tok has already been consumed in parse_expression)
-   std::unique_ptr<AST::Expr> right
-     = parse_expr (LBP_PIPE_ASSIG - 1, AST::AttrVec (), restrictions);
-   if (right == nullptr)
-     return nullptr;
-   // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
- 
-   // TODO: check types. actually, do so during semantic analysis
-   location_t locus = left->get_locus ();
- 
-   return std::unique_ptr<AST::CompoundAssignmentExpr> (
-     new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
- 				     CompoundAssignmentOperator::BITWISE_OR,
- 				     locus));
- }
- 
- // Parses a binary xor-assignment expression (with Pratt parsing).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::CompoundAssignmentExpr>
- Parser<ManagedTokenSource>::parse_xor_assig_expr (
-   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
-   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
- {
-   // parse RHS (as tok has already been consumed in parse_expression)
-   std::unique_ptr<AST::Expr> right
-     = parse_expr (LBP_CARET_ASSIG - 1, AST::AttrVec (), restrictions);
-   if (right == nullptr)
-     return nullptr;
-   // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
- 
-   // TODO: check types. actually, do so during semantic analysis
-   location_t locus = left->get_locus ();
- 
-   return std::unique_ptr<AST::CompoundAssignmentExpr> (
-     new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
- 				     CompoundAssignmentOperator::BITWISE_XOR,
- 				     locus));
- }
- 
- // Parses a binary left shift-assignment expression (with Pratt parsing).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::CompoundAssignmentExpr>
- Parser<ManagedTokenSource>::parse_left_shift_assig_expr (
-   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
-   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
- {
-   // parse RHS (as tok has already been consumed in parse_expression)
-   std::unique_ptr<AST::Expr> right
-     = parse_expr (LBP_L_SHIFT_ASSIG - 1, AST::AttrVec (), restrictions);
-   if (right == nullptr)
-     return nullptr;
-   // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
- 
-   // TODO: check types. actually, do so during semantic analysis
-   location_t locus = left->get_locus ();
- 
-   return std::unique_ptr<AST::CompoundAssignmentExpr> (
-     new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
- 				     CompoundAssignmentOperator::LEFT_SHIFT,
- 				     locus));
- }
- 
- // Parses a binary right shift-assignment expression (with Pratt parsing).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::CompoundAssignmentExpr>
- Parser<ManagedTokenSource>::parse_right_shift_assig_expr (
-   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
-   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
- {
-   // parse RHS (as tok has already been consumed in parse_expression)
-   std::unique_ptr<AST::Expr> right
-     = parse_expr (LBP_R_SHIFT_ASSIG - 1, AST::AttrVec (), restrictions);
-   if (right == nullptr)
-     return nullptr;
-   // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
- 
-   // TODO: check types. actually, do so during semantic analysis
-   location_t locus = left->get_locus ();
- 
-   return std::unique_ptr<AST::CompoundAssignmentExpr> (
-     new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
- 				     CompoundAssignmentOperator::RIGHT_SHIFT,
- 				     locus));
- }
- 
- // Parses a postfix unary await expression (with Pratt parsing).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::AwaitExpr>
- Parser<ManagedTokenSource>::parse_await_expr (
-   const_TokenPtr tok, std::unique_ptr<AST::Expr> expr_to_await,
-   AST::AttrVec outer_attrs)
- {
-   /* skip "await" identifier (as "." has already been consumed in
-    * parse_expression) this assumes that the identifier was already identified
-    * as await */
-   if (!skip_token (IDENTIFIER))
-     {
-       Error error (tok->get_locus (), "failed to skip %<await%> in await expr "
- 				      "- this is probably a deep issue");
-       add_error (std::move (error));
- 
-       // skip somewhere?
-       return nullptr;
-     }
- 
-   // TODO: check inside async block in semantic analysis
-   location_t locus = expr_to_await->get_locus ();
- 
-   return std::unique_ptr<AST::AwaitExpr> (
-     new AST::AwaitExpr (std::move (expr_to_await), std::move (outer_attrs),
- 			locus));
- }
- 
- /* Parses an exclusive range ('..') in left denotation position (i.e.
-  * RangeFromExpr or RangeFromToExpr). */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::RangeExpr>
- Parser<ManagedTokenSource>::parse_led_range_exclusive_expr (
-   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
-   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
- {
-   // FIXME: this probably parses expressions accidently or whatever
-   // try parsing RHS (as tok has already been consumed in parse_expression)
-   // Can be nullptr, in which case it is a RangeFromExpr, otherwise a
-   // RangeFromToExpr.
-   restrictions.expr_can_be_null = true;
-   std::unique_ptr<AST::Expr> right
-     = parse_expr (LBP_DOT_DOT, AST::AttrVec (), restrictions);
- 
-   location_t locus = left->get_locus ();
- 
-   if (right == nullptr)
-     {
-       // range from expr
-       return std::unique_ptr<AST::RangeFromExpr> (
- 	new AST::RangeFromExpr (std::move (left), locus));
-     }
-   else
-     {
-       return std::unique_ptr<AST::RangeFromToExpr> (
- 	new AST::RangeFromToExpr (std::move (left), std::move (right), locus));
-     }
-   // FIXME: make non-associative
- }
- 
- /* Parses an exclusive range ('..') in null denotation position (i.e.
-  * RangeToExpr or RangeFullExpr). */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::RangeExpr>
- Parser<ManagedTokenSource>::parse_nud_range_exclusive_expr (
-   const_TokenPtr tok, AST::AttrVec outer_attrs ATTRIBUTE_UNUSED)
- {
-   auto restrictions = ParseRestrictions ();
-   restrictions.expr_can_be_null = true;
- 
-   // FIXME: this probably parses expressions accidently or whatever
-   // try parsing RHS (as tok has already been consumed in parse_expression)
-   std::unique_ptr<AST::Expr> right
-     = parse_expr (LBP_DOT_DOT, AST::AttrVec (), restrictions);
- 
-   location_t locus = tok->get_locus ();
- 
-   if (right == nullptr)
-     {
-       // range from expr
-       return std::unique_ptr<AST::RangeFullExpr> (
- 	new AST::RangeFullExpr (locus));
-     }
-   else
-     {
-       return std::unique_ptr<AST::RangeToExpr> (
- 	new AST::RangeToExpr (std::move (right), locus));
-     }
-   // FIXME: make non-associative
- }
- 
- // Parses a full binary range inclusive expression.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::RangeFromToInclExpr>
- Parser<ManagedTokenSource>::parse_range_inclusive_expr (
-   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
-   AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
- {
-   // parse RHS (as tok has already been consumed in parse_expression)
-   std::unique_ptr<AST::Expr> right
-     = parse_expr (LBP_DOT_DOT_EQ, AST::AttrVec (), restrictions);
-   if (right == nullptr)
-     return nullptr;
-   // FIXME: make non-associative
- 
-   // TODO: check types. actually, do so during semantic analysis
-   location_t locus = left->get_locus ();
- 
-   return std::unique_ptr<AST::RangeFromToInclExpr> (
-     new AST::RangeFromToInclExpr (std::move (left), std::move (right), locus));
- }
- 
- // Parses an inclusive range-to prefix unary expression.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::RangeToInclExpr>
- Parser<ManagedTokenSource>::parse_range_to_inclusive_expr (
-   const_TokenPtr tok, AST::AttrVec outer_attrs ATTRIBUTE_UNUSED)
- {
-   // parse RHS (as tok has already been consumed in parse_expression)
-   std::unique_ptr<AST::Expr> right = parse_expr (LBP_DOT_DOT_EQ);
-   if (right == nullptr)
-     return nullptr;
-   // FIXME: make non-associative
- 
-   // TODO: check types. actually, do so during semantic analysis
- 
-   return std::unique_ptr<AST::RangeToInclExpr> (
-     new AST::RangeToInclExpr (std::move (right), tok->get_locus ()));
- }
- 
- // Parses a pseudo-binary infix tuple index expression.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::TupleIndexExpr>
- Parser<ManagedTokenSource>::parse_tuple_index_expr (
-   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> tuple_expr,
-   AST::AttrVec outer_attrs, ParseRestrictions restrictions ATTRIBUTE_UNUSED)
- {
-   // parse int literal (as token already skipped)
-   const_TokenPtr index_tok = expect_token (INT_LITERAL);
-   if (index_tok == nullptr)
-     {
-       return nullptr;
-     }
-   std::string index = index_tok->get_str ();
- 
-   // convert to integer
-   if (!index_tok->is_pure_decimal ())
-     {
-       Error error (index_tok->get_locus (),
- 		   "tuple index should be a pure decimal literal");
-       add_error (std::move (error));
-     }
-   int index_int = atoi (index.c_str ());
- 
-   location_t locus = tuple_expr->get_locus ();
- 
-   return std::unique_ptr<AST::TupleIndexExpr> (
-     new AST::TupleIndexExpr (std::move (tuple_expr), index_int,
- 			     std::move (outer_attrs), locus));
- }
- 
- // Parses a pseudo-binary infix array (or slice) index expression.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::ArrayIndexExpr>
- Parser<ManagedTokenSource>::parse_index_expr (
-   const_TokenPtr, std::unique_ptr<AST::Expr> array_expr,
-   AST::AttrVec outer_attrs, ParseRestrictions)
- {
-   // parse RHS (as tok has already been consumed in parse_expression)
-   /*std::unique_ptr<AST::Expr> index_expr
-     = parse_expr (LBP_ARRAY_REF, AST::AttrVec (),
-     restrictions);*/
-   // TODO: conceptually, should treat [] as brackets, so just parse all expr
-   std::unique_ptr<AST::Expr> index_expr = parse_expr ();
-   if (index_expr == nullptr)
-     return nullptr;
- 
-   // skip ']' at end of array
-   if (!skip_token (RIGHT_SQUARE))
-     {
-       // skip somewhere?
-       return nullptr;
-     }
- 
-   // TODO: check types. actually, do so during semantic analysis
-   location_t locus = array_expr->get_locus ();
- 
-   return std::unique_ptr<AST::ArrayIndexExpr> (
-     new AST::ArrayIndexExpr (std::move (array_expr), std::move (index_expr),
- 			     std::move (outer_attrs), locus));
- }
- 
- // Parses a pseudo-binary infix struct field access expression.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::FieldAccessExpr>
- Parser<ManagedTokenSource>::parse_field_access_expr (
-   const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> struct_expr,
-   AST::AttrVec outer_attrs, ParseRestrictions restrictions ATTRIBUTE_UNUSED)
- {
-   /* get field name identifier (assume that this is a field access expr and
-    * not await, for instance) */
-   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
-   if (ident_tok == nullptr)
-     return nullptr;
- 
-   Identifier ident{ident_tok};
- 
-   location_t locus = struct_expr->get_locus ();
- 
-   // TODO: check types. actually, do so during semantic analysis
-   return std::unique_ptr<AST::FieldAccessExpr> (
-     new AST::FieldAccessExpr (std::move (struct_expr), std::move (ident),
- 			      std::move (outer_attrs), locus));
- }
- 
- // Parses a pseudo-binary infix method call expression.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::MethodCallExpr>
- Parser<ManagedTokenSource>::parse_method_call_expr (
-   const_TokenPtr tok, std::unique_ptr<AST::Expr> receiver_expr,
-   AST::AttrVec outer_attrs, ParseRestrictions)
- {
-   // parse path expr segment
-   AST::PathExprSegment segment = parse_path_expr_segment ();
-   if (segment.is_error ())
-     {
-       Error error (tok->get_locus (),
- 		   "failed to parse path expr segment of method call expr");
-       add_error (std::move (error));
- 
-       return nullptr;
-     }
- 
-   // skip left parentheses
-   if (!skip_token (LEFT_PAREN))
-     {
-       return nullptr;
-     }
- 
-   // parse method params (if they exist)
-   std::vector<std::unique_ptr<AST::Expr>> params;
- 
-   const_TokenPtr t = lexer.peek_token ();
-   while (t->get_id () != RIGHT_PAREN)
-     {
-       std::unique_ptr<AST::Expr> param = parse_expr ();
-       if (param == nullptr)
- 	{
- 	  Error error (t->get_locus (),
- 		       "failed to parse method param in method call");
- 	  add_error (std::move (error));
- 
- 	  return nullptr;
- 	}
-       params.push_back (std::move (param));
- 
-       if (lexer.peek_token ()->get_id () != COMMA)
- 	break;
- 
-       lexer.skip_token ();
-       t = lexer.peek_token ();
-     }
- 
-   // skip right paren
-   if (!skip_token (RIGHT_PAREN))
-     {
-       return nullptr;
-     }
- 
-   // TODO: check types. actually do so in semantic analysis pass.
-   location_t locus = receiver_expr->get_locus ();
- 
-   return std::unique_ptr<AST::MethodCallExpr> (
-     new AST::MethodCallExpr (std::move (receiver_expr), std::move (segment),
- 			     std::move (params), std::move (outer_attrs),
- 			     locus));
- }
- 
- // Parses a pseudo-binary infix function call expression.
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::CallExpr>
- Parser<ManagedTokenSource>::parse_function_call_expr (
-   const_TokenPtr, std::unique_ptr<AST::Expr> function_expr,
-   AST::AttrVec outer_attrs, ParseRestrictions)
- {
-   // parse function params (if they exist)
-   std::vector<std::unique_ptr<AST::Expr>> params;
- 
-   const_TokenPtr t = lexer.peek_token ();
-   while (t->get_id () != RIGHT_PAREN)
-     {
-       std::unique_ptr<AST::Expr> param = parse_expr ();
-       if (param == nullptr)
- 	{
- 	  Error error (t->get_locus (),
- 		       "failed to parse function param in function call");
- 	  add_error (std::move (error));
- 
- 	  return nullptr;
- 	}
-       params.push_back (std::move (param));
- 
-       if (lexer.peek_token ()->get_id () != COMMA)
- 	break;
- 
-       lexer.skip_token ();
-       t = lexer.peek_token ();
-     }
- 
-   // skip ')' at end of param list
-   if (!skip_token (RIGHT_PAREN))
-     {
-       // skip somewhere?
-       return nullptr;
-     }
- 
-   // TODO: check types. actually, do so during semantic analysis
-   location_t locus = function_expr->get_locus ();
- 
-   return std::unique_ptr<AST::CallExpr> (
-     new AST::CallExpr (std::move (function_expr), std::move (params),
- 		       std::move (outer_attrs), locus));
- }
- 
- /* Parses a macro invocation with a path in expression already parsed (but not
-  * '!' token). */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::MacroInvocation>
- Parser<ManagedTokenSource>::parse_macro_invocation_partial (
-   AST::PathInExpression path, AST::AttrVec outer_attrs,
-   ParseRestrictions restrictions)
- {
-   // macro invocation
-   if (!skip_token (EXCLAM))
-     {
-       return nullptr;
-     }
- 
-   // convert PathInExpression to SimplePath - if this isn't possible, error
-   AST::SimplePath converted_path = path.as_simple_path ();
-   if (converted_path.is_empty ())
-     {
-       Error error (lexer.peek_token ()->get_locus (),
- 		   "failed to parse simple path in macro invocation");
-       add_error (std::move (error));
- 
-       return nullptr;
-     }
- 
-   AST::DelimTokenTree tok_tree = parse_delim_token_tree ();
- 
-   rust_debug ("successfully parsed macro invocation (via partial)");
- 
-   location_t macro_locus = converted_path.get_locus ();
- 
-   return AST::MacroInvocation::Regular (
-     AST::MacroInvocData (std::move (converted_path), std::move (tok_tree)),
-     std::move (outer_attrs), macro_locus);
- }
- 
- /* Parses a struct expr struct with a path in expression already parsed (but
-  * not
-  * '{' token). */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::StructExprStruct>
- Parser<ManagedTokenSource>::parse_struct_expr_struct_partial (
-   AST::PathInExpression path, AST::AttrVec outer_attrs)
- {
-   // assume struct expr struct (as struct-enum disambiguation requires name
-   // lookup) again, make statement if final ';'
-   if (!skip_token (LEFT_CURLY))
-     {
-       return nullptr;
-     }
- 
-   // parse inner attributes
-   AST::AttrVec inner_attrs = parse_inner_attributes ();
- 
-   // branch based on next token
-   const_TokenPtr t = lexer.peek_token ();
-   location_t path_locus = path.get_locus ();
-   switch (t->get_id ())
-     {
-     case RIGHT_CURLY:
-       // struct with no body
-       lexer.skip_token ();
- 
-       return std::unique_ptr<AST::StructExprStruct> (
- 	new AST::StructExprStruct (std::move (path), std::move (inner_attrs),
- 				   std::move (outer_attrs), path_locus));
-     case DOT_DOT:
-       /* technically this would give a struct base-only struct, but this
-        * algorithm should work too. As such, AST type not happening. */
-     case IDENTIFIER:
-     case HASH:
-     case INT_LITERAL:
-       {
- 	// struct with struct expr fields
- 
- 	// parse struct expr fields
- 	std::vector<std::unique_ptr<AST::StructExprField>> fields;
- 
- 	while (t->get_id () != RIGHT_CURLY && t->get_id () != DOT_DOT)
- 	  {
- 	    std::unique_ptr<AST::StructExprField> field
- 	      = parse_struct_expr_field ();
- 	    if (field == nullptr)
- 	      {
- 		Error error (t->get_locus (),
- 			     "failed to parse struct (or enum) expr field");
- 		add_error (std::move (error));
- 
- 		return nullptr;
- 	      }
- 
- 	    // DEBUG:
- 	    rust_debug ("struct/enum expr field validated to not be null");
- 
- 	    fields.push_back (std::move (field));
- 
- 	    // DEBUG:
- 	    rust_debug ("struct/enum expr field pushed back");
- 
- 	    if (lexer.peek_token ()->get_id () != COMMA)
- 	      {
- 		// DEBUG:
- 		rust_debug ("lack of comma detected in struct/enum expr "
- 			    "fields - break");
- 		break;
- 	      }
- 	    lexer.skip_token ();
- 
- 	    // DEBUG:
- 	    rust_debug ("struct/enum expr fields comma skipped ");
- 
- 	    t = lexer.peek_token ();
- 	  }
- 
- 	// DEBUG:
- 	rust_debug ("struct/enum expr about to parse struct base ");
- 
- 	// parse struct base if it exists
- 	AST::StructBase struct_base = AST::StructBase::error ();
- 	if (lexer.peek_token ()->get_id () == DOT_DOT)
- 	  {
- 	    location_t dot_dot_location = lexer.peek_token ()->get_locus ();
- 	    lexer.skip_token ();
- 
- 	    // parse required struct base expr
- 	    std::unique_ptr<AST::Expr> base_expr = parse_expr ();
- 	    if (base_expr == nullptr)
- 	      {
- 		Error error (lexer.peek_token ()->get_locus (),
- 			     "failed to parse struct base expression in struct "
- 			     "expression");
- 		add_error (std::move (error));
- 
- 		return nullptr;
- 	      }
- 
- 	    // DEBUG:
- 	    rust_debug ("struct/enum expr - parsed and validated base expr");
- 
- 	    struct_base
- 	      = AST::StructBase (std::move (base_expr), dot_dot_location);
- 
- 	    // DEBUG:
- 	    rust_debug ("assigned struct base to new struct base ");
- 	  }
- 
- 	if (!skip_token (RIGHT_CURLY))
- 	  {
- 	    return nullptr;
- 	  }
- 
- 	// DEBUG:
- 	rust_debug (
- 	  "struct/enum expr skipped right curly - done and ready to return");
- 
- 	return std::unique_ptr<AST::StructExprStructFields> (
- 	  new AST::StructExprStructFields (std::move (path), std::move (fields),
- 					   path_locus, std::move (struct_base),
- 					   std::move (inner_attrs),
- 					   std::move (outer_attrs)));
-       }
-     default:
-       add_error (
- 	Error (t->get_locus (),
- 	       "unrecognised token %qs in struct (or enum) expression - "
- 	       "expected %<}%>, identifier, integer literal, or %<..%>",
- 	       t->get_token_description ()));
- 
-       return nullptr;
-     }
- }
- 
- /* Parses a struct expr tuple with a path in expression already parsed (but
-  * not
-  * '(' token).
-  * FIXME: this currently outputs a call expr, as they cannot be disambiguated.
-  * A better solution would be to just get this to call that function directly.
-  * */
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::CallExpr>
- Parser<ManagedTokenSource>::parse_struct_expr_tuple_partial (
-   AST::PathInExpression path, AST::AttrVec outer_attrs)
- {
-   if (!skip_token (LEFT_PAREN))
-     {
-       return nullptr;
-     }
- 
-   AST::AttrVec inner_attrs = parse_inner_attributes ();
- 
-   std::vector<std::unique_ptr<AST::Expr>> exprs;
- 
-   const_TokenPtr t = lexer.peek_token ();
-   while (t->get_id () != RIGHT_PAREN)
-     {
-       // parse expression (required)
-       std::unique_ptr<AST::Expr> expr = parse_expr ();
-       if (expr == nullptr)
- 	{
- 	  Error error (t->get_locus (), "failed to parse expression in "
- 					"struct (or enum) expression tuple");
- 	  add_error (std::move (error));
- 
- 	  return nullptr;
- 	}
-       exprs.push_back (std::move (expr));
- 
-       if (lexer.peek_token ()->get_id () != COMMA)
- 	break;
- 
-       lexer.skip_token ();
- 
-       t = lexer.peek_token ();
-     }
- 
-   if (!skip_token (RIGHT_PAREN))
-     {
-       return nullptr;
-     }
- 
-   location_t path_locus = path.get_locus ();
- 
-   auto pathExpr = std::unique_ptr<AST::PathInExpression> (
-     new AST::PathInExpression (std::move (path)));
- 
-   return std::unique_ptr<AST::CallExpr> (
-     new AST::CallExpr (std::move (pathExpr), std::move (exprs),
- 		       std::move (outer_attrs), path_locus));
- }
- 
- // Parses a closure expression with pratt parsing (from null denotation).
- template <typename ManagedTokenSource>
- std::unique_ptr<AST::ClosureExpr>
- Parser<ManagedTokenSource>::parse_closure_expr_pratt (const_TokenPtr tok,
- 						      AST::AttrVec outer_attrs)
- {
-   // TODO: does this need pratt parsing (for precedence)? probably not, but
-   // idk
-   location_t locus = tok->get_locus ();
-   bool has_move = false;
-   if (tok->get_id () == MOVE)
-     {
-       has_move = true;
-       tok = lexer.peek_token ();
-       lexer.skip_token ();
-       // skip token and reassign
-     }
- 
-   // handle parameter list
-   std::vector<AST::ClosureParam> params;
- 
-   switch (tok->get_id ())
-     {
-     case OR:
-       // no parameters, don't skip token
-       break;
-     case PIPE:
-       {
- 	// actually may have parameters
- 	// don't skip token
- 	const_TokenPtr t = lexer.peek_token ();
- 	while (t->get_id () != PIPE)
- 	  {
- 	    AST::ClosureParam param = parse_closure_param ();
- 	    if (param.is_error ())
- 	      {
- 		// TODO is this really an error?
- 		Error error (t->get_locus (), "could not parse closure param");
- 		add_error (std::move (error));
- 
- 		return nullptr;
- 	      }
- 	    params.push_back (std::move (param));
- 
- 	    if (lexer.peek_token ()->get_id () != COMMA)
- 	      {
- 		if (lexer.peek_token ()->get_id () == OR)
- 		  lexer.split_current_token (PIPE, PIPE);
- 		// not an error but means param list is done
- 		break;
- 	      }
- 	    // skip comma
- 	    lexer.skip_token ();
- 
- 	    if (lexer.peek_token ()->get_id () == OR)
- 	      lexer.split_current_token (PIPE, PIPE);
- 
- 	    t = lexer.peek_token ();
- 	  }
- 
- 	if (!skip_token (PIPE))
- 	  {
- 	    return nullptr;
- 	  }
- 	break;
-       }
-     default:
-       add_error (Error (tok->get_locus (),
- 			"unexpected token %qs in closure expression - expected "
- 			"%<|%> or %<||%>",
- 			tok->get_token_description ()));
- 
-       // skip somewhere?
-       return nullptr;
-     }
- 
-   // again branch based on next token
-   tok = lexer.peek_token ();
-   if (tok->get_id () == RETURN_TYPE)
-     {
-       // must be return type closure with block expr
- 
-       // skip "return type" token
-       lexer.skip_token ();
- 
-       // parse actual type, which is required
-       std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
-       if (type == nullptr)
- 	{
- 	  // error
- 	  Error error (tok->get_locus (), "failed to parse type for closure");
- 	  add_error (std::move (error));
- 
- 	  // skip somewhere?
- 	  return nullptr;
- 	}
- 
-       // parse block expr, which is required
-       std::unique_ptr<AST::BlockExpr> block = parse_block_expr ();
-       if (block == nullptr)
- 	{
- 	  // error
- 	  Error error (lexer.peek_token ()->get_locus (),
- 		       "failed to parse block expr in closure");
- 	  add_error (std::move (error));
- 
- 	  // skip somewhere?
- 	  return nullptr;
- 	}
- 
-       return std::unique_ptr<AST::ClosureExprInnerTyped> (
- 	new AST::ClosureExprInnerTyped (std::move (type), std::move (block),
- 					std::move (params), locus, has_move,
- 					std::move (outer_attrs)));
-     }
-   else
-     {
-       // must be expr-only closure
- 
-       // parse expr, which is required
-       std::unique_ptr<AST::Expr> expr = parse_expr ();
-       if (expr == nullptr)
- 	{
- 	  Error error (tok->get_locus (),
- 		       "failed to parse expression in closure");
- 	  add_error (std::move (error));
- 
- 	  // skip somewhere?
- 	  return nullptr;
- 	}
- 
-       return std::unique_ptr<AST::ClosureExprInner> (
- 	new AST::ClosureExprInner (std::move (expr), std::move (params), locus,
- 				   has_move, std::move (outer_attrs)));
-     }
- }
- 
- // Returns true if the next token is END, ELSE, or EOF;
- template <typename ManagedTokenSource>
- bool
- Parser<ManagedTokenSource>::done_end_or_else ()
- {
-   const_TokenPtr t = lexer.peek_token ();
-   return (t->get_id () == RIGHT_CURLY || t->get_id () == ELSE
- 	  || t->get_id () == END_OF_FILE);
- }
- 
- // Returns true if the next token is END or EOF.
- template <typename ManagedTokenSource>
- bool
- Parser<ManagedTokenSource>::done_end ()
- {
-   const_TokenPtr t = lexer.peek_token ();
-   return (t->get_id () == RIGHT_CURLY || t->get_id () == END_OF_FILE);
- }
- } // namespace Rust
--- 0 ----
diff -Nrcpad gcc-16-20251214/gcc/rust/parse/rust-parse-impl.hxx gcc-16-20251221/gcc/rust/parse/rust-parse-impl.hxx
*** gcc-16-20251214/gcc/rust/parse/rust-parse-impl.hxx	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/rust/parse/rust-parse-impl.hxx	Sun Dec 21 22:32:07 2025
***************
*** 0 ****
--- 1,7205 ----
+ // Copyright (C) 2020-2025 Free Software Foundation, Inc.
+ 
+ // This file is part of GCC.
+ 
+ // GCC is free software; you can redistribute it and/or modify it under
+ // the terms of the GNU General Public License as published by the Free
+ // Software Foundation; either version 3, or (at your option) any later
+ // version.
+ 
+ // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+ // WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ // for more details.
+ 
+ // You should have received a copy of the GNU General Public License
+ // along with GCC; see the file COPYING3.  If not see
+ // <http://www.gnu.org/licenses/>.
+ 
+ /* Template implementation for Rust::Parser. Previously in rust-parse.cc (before
+  * Parser was template). Separated from rust-parse.h for readability. */
+ 
+ /* DO NOT INCLUDE ANYWHERE - this is automatically included
+  *   by rust-parse-impl-*.cc
+  * This is also the reason why there are no include guards. */
+ 
+ #include "expected.h"
+ #include "rust-ast.h"
+ #include "rust-common.h"
+ #include "rust-expr.h"
+ #include "rust-item.h"
+ #include "rust-common.h"
+ #include "rust-parse.h"
+ #include "rust-token.h"
+ #define INCLUDE_ALGORITHM
+ #include "rust-diagnostics.h"
+ #include "rust-dir-owner.h"
+ #include "rust-keyword-values.h"
+ #include "rust-edition.h"
+ #include "rust-parse-error.h"
+ 
+ #include "optional.h"
+ 
+ namespace Rust {
+ 
+ /* HACK-y special handling for skipping a right angle token at the end of
+  * generic arguments.
+  * Currently, this replaces the "current token" with one that is identical
+  * except has the leading '>' removed (e.g. '>>' becomes '>'). This is bad
+  * for several reasons - it modifies the token stream to something that
+  * actually doesn't make syntactic sense, it may not worked if the token
+  * has already been skipped, etc. It was done because it would not
+  * actually require inserting new items into the token stream (which I
+  * thought would take more work to not mess up) and because I wasn't sure
+  * if the "already seen right angle" flag in the parser would work
+  * correctly.
+  * Those two other approaches listed are in my opinion actually better
+  * long-term - insertion is probably best as it reflects syntactically
+  * what occurs. On the other hand, I need to do a code audit to make sure
+  * that insertion doesn't mess anything up. So that's a FIXME. */
+ template <typename ManagedTokenSource>
+ bool
+ Parser<ManagedTokenSource>::skip_generics_right_angle ()
+ {
+   /* OK, new great idea. Have a lexer method called
+    * "split_current_token(TokenType newLeft, TokenType newRight)", which is
+    * called here with whatever arguments are appropriate. That lexer method
+    * handles "replacing" the current token with the "newLeft" and "inserting"
+    * the next token with the "newRight" (and creating a location, etc. for it)
+    */
+ 
+   /* HACK: special handling for right shift '>>', greater or equal '>=', and
+    * right shift assig */
+   // '>>='
+   const_TokenPtr tok = lexer.peek_token ();
+   switch (tok->get_id ())
+     {
+     case RIGHT_ANGLE:
+       // this is good - skip token
+       lexer.skip_token ();
+       return true;
+     case RIGHT_SHIFT:
+       {
+ 	// new implementation that should be better
+ 	lexer.split_current_token (RIGHT_ANGLE, RIGHT_ANGLE);
+ 	lexer.skip_token ();
+ 	return true;
+       }
+     case GREATER_OR_EQUAL:
+       {
+ 	// new implementation that should be better
+ 	lexer.split_current_token (RIGHT_ANGLE, EQUAL);
+ 	lexer.skip_token ();
+ 	return true;
+       }
+     case RIGHT_SHIFT_EQ:
+       {
+ 	// new implementation that should be better
+ 	lexer.split_current_token (RIGHT_ANGLE, GREATER_OR_EQUAL);
+ 	lexer.skip_token ();
+ 	return true;
+       }
+     default:
+       add_error (Error (tok->get_locus (),
+ 			"expected %<>%> at end of generic argument - found %qs",
+ 			tok->get_token_description ()));
+       return false;
+     }
+ }
+ 
+ /* Gets left binding power for specified token.
+  * Not suitable for use at the moment or possibly ever because binding power
+  * cannot be purely determined from operator token with Rust grammar - e.g.
+  * method call and field access have
+  * different left binding powers but the same operator token. */
+ template <typename ManagedTokenSource>
+ int
+ Parser<ManagedTokenSource>::left_binding_power (const_TokenPtr token)
+ {
+   // HACK: called with "peek_token()", so lookahead is "peek_token(1)"
+   switch (token->get_id ())
+     {
+       /* TODO: issue here - distinguish between method calls and field access
+        * somehow? Also would have to distinguish between paths and function
+        * calls (:: operator), maybe more stuff. */
+       /* Current plan for tackling LBP - don't do it based on token, use
+        * lookahead. Or alternatively, only use Pratt parsing for OperatorExpr
+        * and handle other expressions without it. rustc only considers
+        * arithmetic, logical/relational, 'as',
+        * '?=', ranges, colons, and assignment to have operator precedence and
+        * associativity rules applicable. It then has
+        * a separate "ExprPrecedence" that also includes binary operators. */
+ 
+       // TODO: handle operator overloading - have a function replace the
+       // operator?
+ 
+       /*case DOT:
+ 	  return LBP_DOT;*/
+ 
+     case SCOPE_RESOLUTION:
+       rust_debug (
+ 	"possible error - looked up LBP of scope resolution operator. should "
+ 	"be handled elsewhere.");
+       return LBP_PATH;
+ 
+     /* Resolved by lookahead HACK that should work with current code. If next
+      * token is identifier and token after that isn't parenthesised expression
+      * list, it is a field reference. */
+     case DOT:
+       if (lexer.peek_token (1)->get_id () == IDENTIFIER
+ 	  && lexer.peek_token (2)->get_id () != LEFT_PAREN)
+ 	{
+ 	  return LBP_FIELD_EXPR;
+ 	}
+       return LBP_METHOD_CALL;
+ 
+     case LEFT_PAREN:
+       return LBP_FUNCTION_CALL;
+ 
+     case LEFT_SQUARE:
+       return LBP_ARRAY_REF;
+ 
+     // postfix question mark (i.e. error propagation expression)
+     case QUESTION_MARK:
+       return LBP_QUESTION_MARK;
+ 
+     case AS:
+       return LBP_AS;
+ 
+     case ASTERISK:
+       return LBP_MUL;
+     case DIV:
+       return LBP_DIV;
+     case PERCENT:
+       return LBP_MOD;
+ 
+     case PLUS:
+       return LBP_PLUS;
+     case MINUS:
+       return LBP_MINUS;
+ 
+     case LEFT_SHIFT:
+       return LBP_L_SHIFT;
+     case RIGHT_SHIFT:
+       return LBP_R_SHIFT;
+ 
+     // binary & operator
+     case AMP:
+       return LBP_AMP;
+ 
+     // binary ^ operator
+     case CARET:
+       return LBP_CARET;
+ 
+     // binary | operator
+     case PIPE:
+       return LBP_PIPE;
+ 
+     case EQUAL_EQUAL:
+       return LBP_EQUAL;
+     case NOT_EQUAL:
+       return LBP_NOT_EQUAL;
+     case RIGHT_ANGLE:
+       return LBP_GREATER_THAN;
+     case GREATER_OR_EQUAL:
+       return LBP_GREATER_EQUAL;
+     case LEFT_ANGLE:
+       return LBP_SMALLER_THAN;
+     case LESS_OR_EQUAL:
+       return LBP_SMALLER_EQUAL;
+ 
+     case LOGICAL_AND:
+       return LBP_LOGICAL_AND;
+ 
+     case OR:
+       return LBP_LOGICAL_OR;
+ 
+     case DOT_DOT:
+       return LBP_DOT_DOT;
+ 
+     case DOT_DOT_EQ:
+       return LBP_DOT_DOT_EQ;
+ 
+     case EQUAL:
+       return LBP_ASSIG;
+     case PLUS_EQ:
+       return LBP_PLUS_ASSIG;
+     case MINUS_EQ:
+       return LBP_MINUS_ASSIG;
+     case ASTERISK_EQ:
+       return LBP_MULT_ASSIG;
+     case DIV_EQ:
+       return LBP_DIV_ASSIG;
+     case PERCENT_EQ:
+       return LBP_MOD_ASSIG;
+     case AMP_EQ:
+       return LBP_AMP_ASSIG;
+     case PIPE_EQ:
+       return LBP_PIPE_ASSIG;
+     case CARET_EQ:
+       return LBP_CARET_ASSIG;
+     case LEFT_SHIFT_EQ:
+       return LBP_L_SHIFT_ASSIG;
+     case RIGHT_SHIFT_EQ:
+       return LBP_R_SHIFT_ASSIG;
+ 
+     /* HACK: float literal due to lexer misidentifying a dot then an integer as
+      * a float */
+     case FLOAT_LITERAL:
+       return LBP_FIELD_EXPR;
+       // field expr is same as tuple expr in precedence, i imagine
+       // TODO: is this needed anymore? lexer shouldn't do that anymore
+ 
+     // anything that can't appear in an infix position is given lowest priority
+     default:
+       return LBP_LOWEST;
+     }
+ }
+ 
+ // Returns true when current token is EOF.
+ template <typename ManagedTokenSource>
+ bool
+ Parser<ManagedTokenSource>::done_end_of_file ()
+ {
+   return lexer.peek_token ()->get_id () == END_OF_FILE;
+ }
+ 
+ // Parses a sequence of items within a module or the implicit top-level module
+ // in a crate
+ template <typename ManagedTokenSource>
+ tl::expected<std::vector<std::unique_ptr<AST::Item>>, Parse::Error::Items>
+ Parser<ManagedTokenSource>::parse_items ()
+ {
+   std::vector<std::unique_ptr<AST::Item>> items;
+ 
+   const_TokenPtr t = lexer.peek_token ();
+   while (t->get_id () != END_OF_FILE)
+     {
+       auto item = parse_item (false);
+       if (!item)
+ 	return Parse::Error::Items::make_malformed (std::move (items));
+ 
+       items.push_back (std::move (item.value ()));
+ 
+       t = lexer.peek_token ();
+     }
+ 
+     // GCC 5->7 bug doesn't threat lvalue as an rvalue for the overload
+ #if __GNUC__ <= 7
+   return std::move (items);
+ #else
+   return items;
+ #endif
+ }
+ 
+ // Parses a crate (compilation unit) - entry point
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::Crate>
+ Parser<ManagedTokenSource>::parse_crate ()
+ {
+   // parse inner attributes
+   AST::AttrVec inner_attrs = parse_inner_attributes ();
+ 
+   // parse items
+   auto items
+     = parse_items ().value_or (std::vector<std::unique_ptr<AST::Item>>{});
+ 
+   // emit all errors
+   for (const auto &error : error_table)
+     error.emit ();
+ 
+   return std::unique_ptr<AST::Crate> (
+     new AST::Crate (std::move (items), std::move (inner_attrs)));
+ }
+ 
+ // Parses an identifier/keyword as a Token
+ template <typename ManagedTokenSource>
+ tl::expected<std::unique_ptr<AST::Token>, Parse::Error::Token>
+ Parser<ManagedTokenSource>::parse_identifier_or_keyword_token ()
+ {
+   const_TokenPtr t = lexer.peek_token ();
+ 
+   if (t->get_id () == IDENTIFIER || token_id_is_keyword (t->get_id ()))
+     {
+       lexer.skip_token ();
+       return std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
+     }
+   else
+     {
+       add_error (Error (t->get_locus (), "expected keyword or identifier"));
+       return Parse::Error::Token::make_malformed ();
+     }
+ }
+ 
+ template <typename ManagedTokenSource>
+ bool
+ Parser<ManagedTokenSource>::is_macro_rules_def (const_TokenPtr t)
+ {
+   auto macro_name = lexer.peek_token (2)->get_id ();
+ 
+   bool allowed_macro_name = (macro_name == IDENTIFIER || macro_name == TRY);
+ 
+   return t->get_str () == Values::WeakKeywords::MACRO_RULES
+ 	 && lexer.peek_token (1)->get_id () == EXCLAM && allowed_macro_name;
+ }
+ 
+ // Parses a single item
+ template <typename ManagedTokenSource>
+ tl::expected<std::unique_ptr<AST::Item>, Parse::Error::Item>
+ Parser<ManagedTokenSource>::parse_item (bool called_from_statement)
+ {
+   // has a "called_from_statement" parameter for better error message handling
+ 
+   // TODO: GCC 5 does not handle implicit return type correctly so we're forced
+   // to specify it almost every time until the baseline GCC gets bumped.
+   // Since this type is quite long and the code is dense we use an alias.
+   //
+   // When support for GCC 5 stops: remove this alias as well as the explicit
+   // ctor calls.
+   using RType = tl::expected<std::unique_ptr<AST::Item>, Parse::Error::Item>;
+ 
+   // parse outer attributes for item
+   AST::AttrVec outer_attrs = parse_outer_attributes ();
+   const_TokenPtr t = lexer.peek_token ();
+ 
+   switch (t->get_id ())
+     {
+     case END_OF_FILE:
+       // not necessarily an error, unless we just read outer
+       // attributes which needs to be attached
+       if (!outer_attrs.empty ())
+ 	{
+ 	  Rust::AST::Attribute attr = outer_attrs.back ();
+ 	  Error error (attr.get_locus (),
+ 		       "expected item after outer attribute or doc comment");
+ 	  add_error (std::move (error));
+ 	}
+       return Parse::Error::Item::make_end_of_file ();
+ 
+     case ASYNC:
+     case PUB:
+     case MOD:
+     case EXTERN_KW:
+     case USE:
+     case FN_KW:
+     case TYPE:
+     case STRUCT_KW:
+     case ENUM_KW:
+     case CONST:
+     case STATIC_KW:
+     case AUTO:
+     case TRAIT:
+     case IMPL:
+     case MACRO:
+     /* TODO: implement union keyword but not really because of
+      * context-dependence crappy hack way to parse a union written below to
+      * separate it from the good code. */
+     // case UNION:
+     case UNSAFE: // maybe - unsafe traits are a thing
+       // if any of these (should be all possible VisItem prefixes), parse a
+       // VisItem
+       {
+ 	auto vis_item = parse_vis_item (std::move (outer_attrs));
+ 	if (!vis_item)
+ 	  return Parse::Error::Item::make_malformed ();
+ 	return RType{std::move (vis_item)};
+       }
+     case SUPER:
+     case SELF:
+     case CRATE:
+     case DOLLAR_SIGN:
+       // almost certainly macro invocation semi
+       {
+ 	auto macro_invoc_semi
+ 	  = parse_macro_invocation_semi (std::move (outer_attrs));
+ 	if (!macro_invoc_semi)
+ 	  return Parse::Error::Item::make_malformed ();
+ 	return RType{std::move (macro_invoc_semi)};
+       }
+     // crappy hack to do union "keyword"
+     case IDENTIFIER:
+       // TODO: ensure std::string and literal comparison works
+       if (t->get_str () == Values::WeakKeywords::UNION
+ 	  && lexer.peek_token (1)->get_id () == IDENTIFIER)
+ 	{
+ 	  auto vis_item = parse_vis_item (std::move (outer_attrs));
+ 	  if (!vis_item)
+ 	    return Parse::Error::Item::make_malformed ();
+ 	  return RType{std::move (vis_item)};
+ 	  // or should this go straight to parsing union?
+ 	}
+       else if (t->get_str () == Values::WeakKeywords::DEFAULT
+ 	       && lexer.peek_token (1)->get_id () != EXCLAM)
+ 	{
+ 	  add_error (Error (t->get_locus (),
+ 			    "%qs is only allowed on items within %qs blocks",
+ 			    "default", "impl"));
+ 	  return Parse::Error::Item::make_malformed ();
+ 	}
+       else if (is_macro_rules_def (t))
+ 	{
+ 	  // macro_rules! macro item
+ 	  auto macro_rule_def = parse_macro_rules_def (std::move (outer_attrs));
+ 	  if (!macro_rule_def)
+ 	    return Parse::Error::Item::make_malformed ();
+ 	  return RType{std::move (macro_rule_def)};
+ 	}
+       else if (lexer.peek_token (1)->get_id () == SCOPE_RESOLUTION
+ 	       || lexer.peek_token (1)->get_id () == EXCLAM)
+ 	{
+ 	  /* path (probably) or macro invocation, so probably a macro invocation
+ 	   * semi */
+ 	  auto macro_invocation_semi
+ 	    = parse_macro_invocation_semi (std::move (outer_attrs));
+ 	  if (!macro_invocation_semi)
+ 	    return Parse::Error::Item::make_malformed ();
+ 	  return RType{std::move (macro_invocation_semi)};
+ 	}
+       gcc_fallthrough ();
+     default:
+       // otherwise unrecognised
+       add_error (Error (t->get_locus (),
+ 			"unrecognised token %qs for start of %s",
+ 			t->get_token_description (),
+ 			called_from_statement ? "statement" : "item"));
+ 
+       // skip somewhere?
+       return Parse::Error::Item::make_malformed ();
+       break;
+     }
+ }
+ 
+ // Parses a VisItem (item that can have non-default visibility).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::VisItem>
+ Parser<ManagedTokenSource>::parse_vis_item (AST::AttrVec outer_attrs)
+ {
+   // parse visibility, which may or may not exist
+   auto vis_res = parse_visibility ();
+   if (!vis_res)
+     return nullptr;
+   auto vis = vis_res.value ();
+ 
+   // select VisItem to create depending on keyword
+   const_TokenPtr t = lexer.peek_token ();
+ 
+   switch (t->get_id ())
+     {
+     case MOD:
+       return parse_module (std::move (vis), std::move (outer_attrs));
+     case EXTERN_KW:
+       // lookahead to resolve syntactical production
+       t = lexer.peek_token (1);
+ 
+       switch (t->get_id ())
+ 	{
+ 	case CRATE:
+ 	  return parse_extern_crate (std::move (vis), std::move (outer_attrs));
+ 	case FN_KW: // extern function
+ 	  return parse_function (std::move (vis), std::move (outer_attrs));
+ 	case LEFT_CURLY: // extern block
+ 	  return parse_extern_block (std::move (vis), std::move (outer_attrs));
+ 	case STRING_LITERAL: // for specifying extern ABI
+ 	  // could be extern block or extern function, so more lookahead
+ 	  t = lexer.peek_token (2);
+ 
+ 	  switch (t->get_id ())
+ 	    {
+ 	    case FN_KW:
+ 	      return parse_function (std::move (vis), std::move (outer_attrs));
+ 	    case LEFT_CURLY:
+ 	      return parse_extern_block (std::move (vis),
+ 					 std::move (outer_attrs));
+ 	    default:
+ 	      add_error (
+ 		Error (t->get_locus (),
+ 		       "unexpected token %qs in some sort of extern production",
+ 		       t->get_token_description ()));
+ 
+ 	      lexer.skip_token (2); // TODO: is this right thing to do?
+ 	      return nullptr;
+ 	    }
+ 	default:
+ 	  add_error (
+ 	    Error (t->get_locus (),
+ 		   "unexpected token %qs in some sort of extern production",
+ 		   t->get_token_description ()));
+ 
+ 	  lexer.skip_token (1); // TODO: is this right thing to do?
+ 	  return nullptr;
+ 	}
+     case USE:
+       return parse_use_decl (std::move (vis), std::move (outer_attrs));
+     case FN_KW:
+       return parse_function (std::move (vis), std::move (outer_attrs));
+     case TYPE:
+       return parse_type_alias (std::move (vis), std::move (outer_attrs));
+     case STRUCT_KW:
+       return parse_struct (std::move (vis), std::move (outer_attrs));
+     case ENUM_KW:
+       return parse_enum (std::move (vis), std::move (outer_attrs));
+     // TODO: implement union keyword but not really because of
+     // context-dependence case UNION: crappy hack to do union "keyword"
+     case IDENTIFIER:
+       if (t->get_str () == Values::WeakKeywords::UNION
+ 	  && lexer.peek_token (1)->get_id () == IDENTIFIER)
+ 	{
+ 	  return parse_union (std::move (vis), std::move (outer_attrs));
+ 	  // or should item switch go straight to parsing union?
+ 	}
+       else
+ 	{
+ 	  break;
+ 	}
+     case CONST:
+       // lookahead to resolve syntactical production
+       t = lexer.peek_token (1);
+ 
+       switch (t->get_id ())
+ 	{
+ 	case IDENTIFIER:
+ 	case UNDERSCORE:
+ 	  return parse_const_item (std::move (vis), std::move (outer_attrs));
+ 	case ASYNC:
+ 	  return parse_async_item (std::move (vis), std::move (outer_attrs));
+ 	case UNSAFE:
+ 	case EXTERN_KW:
+ 	case FN_KW:
+ 	  return parse_function (std::move (vis), std::move (outer_attrs));
+ 	default:
+ 	  add_error (
+ 	    Error (t->get_locus (),
+ 		   "unexpected token %qs in some sort of const production",
+ 		   t->get_token_description ()));
+ 
+ 	  lexer.skip_token (1); // TODO: is this right thing to do?
+ 	  return nullptr;
+ 	}
+     // for async functions
+     case ASYNC:
+       return parse_async_item (std::move (vis), std::move (outer_attrs));
+ 
+     case STATIC_KW:
+       return parse_static_item (std::move (vis), std::move (outer_attrs));
+     case AUTO:
+     case TRAIT:
+       return parse_trait (std::move (vis), std::move (outer_attrs));
+     case IMPL:
+       return parse_impl (std::move (vis), std::move (outer_attrs));
+     case UNSAFE: // unsafe traits, unsafe functions, unsafe impls (trait impls),
+       // lookahead to resolve syntactical production
+       t = lexer.peek_token (1);
+ 
+       switch (t->get_id ())
+ 	{
+ 	case AUTO:
+ 	case TRAIT:
+ 	  return parse_trait (std::move (vis), std::move (outer_attrs));
+ 	case EXTERN_KW:
+ 	case FN_KW:
+ 	  return parse_function (std::move (vis), std::move (outer_attrs));
+ 	case IMPL:
+ 	  return parse_impl (std::move (vis), std::move (outer_attrs));
+ 	case MOD:
+ 	  return parse_module (std::move (vis), std::move (outer_attrs));
+ 	default:
+ 	  add_error (
+ 	    Error (t->get_locus (),
+ 		   "unexpected token %qs in some sort of unsafe production",
+ 		   t->get_token_description ()));
+ 
+ 	  lexer.skip_token (1); // TODO: is this right thing to do?
+ 	  return nullptr;
+ 	}
+     case MACRO:
+       return parse_decl_macro_def (std::move (vis), std::move (outer_attrs));
+     default:
+       // otherwise vis item clearly doesn't exist, which is not an error
+       // has a catch-all post-switch return to allow other breaks to occur
+       break;
+     }
+   return nullptr;
+ }
+ 
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::Function>
+ Parser<ManagedTokenSource>::parse_async_item (AST::Visibility vis,
+ 					      AST::AttrVec outer_attrs)
+ {
+   auto offset = (lexer.peek_token ()->get_id () == CONST) ? 1 : 0;
+   const_TokenPtr t = lexer.peek_token (offset);
+ 
+   if (get_rust_edition () == Edition::E2015)
+     {
+       add_error (Error (t->get_locus (), ErrorCode::E0670,
+ 			"%<async fn%> is not permitted in Rust 2015"));
+       add_error (
+ 	Error::Hint (t->get_locus (),
+ 		     "to use %<async fn%>, switch to Rust 2018 or later"));
+     }
+ 
+   t = lexer.peek_token (offset + 1);
+ 
+   switch (t->get_id ())
+     {
+     case UNSAFE:
+     case FN_KW:
+       return parse_function (std::move (vis), std::move (outer_attrs));
+ 
+     default:
+       add_error (
+ 	Error (t->get_locus (), "expected item, found keyword %<async%>"));
+ 
+       lexer.skip_token (1);
+       return nullptr;
+     }
+ }
+ 
+ // Parses a macro rules definition syntax extension whatever thing.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::MacroRulesDefinition>
+ Parser<ManagedTokenSource>::parse_macro_rules_def (AST::AttrVec outer_attrs)
+ {
+   // ensure that first token is identifier saying "macro_rules"
+   const_TokenPtr t = lexer.peek_token ();
+   if (t->get_id () != IDENTIFIER
+       || t->get_str () != Values::WeakKeywords::MACRO_RULES)
+     {
+       Error error (
+ 	t->get_locus (),
+ 	"macro rules definition does not start with %<macro_rules%>");
+       add_error (std::move (error));
+ 
+       // skip after somewhere?
+       return nullptr;
+     }
+   lexer.skip_token ();
+   location_t macro_locus = t->get_locus ();
+ 
+   if (!skip_token (EXCLAM))
+     {
+       // skip after somewhere?
+       return nullptr;
+     }
+ 
+   // parse macro name
+   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
+   if (ident_tok == nullptr)
+     {
+       return nullptr;
+     }
+   Identifier rule_name{ident_tok};
+ 
+   // DEBUG
+   rust_debug ("in macro rules def, about to parse parens.");
+ 
+   // save delim type to ensure it is reused later
+   AST::DelimType delim_type = AST::PARENS;
+ 
+   // Map tokens to DelimType
+   t = lexer.peek_token ();
+   switch (t->get_id ())
+     {
+     case LEFT_PAREN:
+       delim_type = AST::PARENS;
+       break;
+     case LEFT_SQUARE:
+       delim_type = AST::SQUARE;
+       break;
+     case LEFT_CURLY:
+       delim_type = AST::CURLY;
+       break;
+     default:
+       add_error (Error (t->get_locus (),
+ 			"unexpected token %qs - expecting delimiters (for a "
+ 			"macro rules definition)",
+ 			t->get_token_description ()));
+ 
+       return nullptr;
+     }
+   lexer.skip_token ();
+ 
+   // parse actual macro rules
+   std::vector<AST::MacroRule> macro_rules;
+ 
+   // must be at least one macro rule, so parse it
+   AST::MacroRule initial_rule = parse_macro_rule ();
+   if (initial_rule.is_error ())
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "required first macro rule in macro rules definition "
+ 		   "could not be parsed");
+       add_error (std::move (error));
+ 
+       // skip after somewhere?
+       return nullptr;
+     }
+   macro_rules.push_back (std::move (initial_rule));
+ 
+   // DEBUG
+   rust_debug ("successfully pushed back initial macro rule");
+ 
+   t = lexer.peek_token ();
+   // parse macro rules
+   while (t->get_id () == SEMICOLON)
+     {
+       // skip semicolon
+       lexer.skip_token ();
+ 
+       // don't parse if end of macro rules
+       if (Parse::Utils::token_id_matches_delims (lexer.peek_token ()->get_id (),
+ 						 delim_type))
+ 	{
+ 	  // DEBUG
+ 	  rust_debug (
+ 	    "broke out of parsing macro rules loop due to finding delim");
+ 
+ 	  break;
+ 	}
+ 
+       // try to parse next rule
+       AST::MacroRule rule = parse_macro_rule ();
+       if (rule.is_error ())
+ 	{
+ 	  Error error (lexer.peek_token ()->get_locus (),
+ 		       "failed to parse macro rule in macro rules definition");
+ 	  add_error (std::move (error));
+ 
+ 	  return nullptr;
+ 	}
+ 
+       macro_rules.push_back (std::move (rule));
+ 
+       // DEBUG
+       rust_debug ("successfully pushed back another macro rule");
+ 
+       t = lexer.peek_token ();
+     }
+ 
+   // parse end delimiters
+   t = lexer.peek_token ();
+   if (Parse::Utils::token_id_matches_delims (t->get_id (), delim_type))
+     {
+       // tokens match opening delimiter, so skip.
+       lexer.skip_token ();
+ 
+       if (delim_type != AST::CURLY)
+ 	{
+ 	  // skip semicolon at end of non-curly macro definitions
+ 	  if (!skip_token (SEMICOLON))
+ 	    {
+ 	      // as this is the end, allow recovery (probably) - may change
+ 	      return std::unique_ptr<AST::MacroRulesDefinition> (
+ 		AST::MacroRulesDefinition::mbe (
+ 		  std::move (rule_name), delim_type, std::move (macro_rules),
+ 		  std::move (outer_attrs), macro_locus));
+ 	    }
+ 	}
+ 
+       return std::unique_ptr<AST::MacroRulesDefinition> (
+ 	AST::MacroRulesDefinition::mbe (std::move (rule_name), delim_type,
+ 					std::move (macro_rules),
+ 					std::move (outer_attrs), macro_locus));
+     }
+   else
+     {
+       // tokens don't match opening delimiters, so produce error
+       Error error (t->get_locus (),
+ 		   "unexpected token %qs - expecting closing delimiter %qs "
+ 		   "(for a macro rules definition)",
+ 		   t->get_token_description (),
+ 		   (delim_type == AST::PARENS
+ 		      ? ")"
+ 		      : (delim_type == AST::SQUARE ? "]" : "}")));
+       add_error (std::move (error));
+ 
+       /* return empty macro definiton despite possibly parsing mostly valid one
+        * - TODO is this a good idea? */
+       return nullptr;
+     }
+ }
+ 
+ // Parses a declarative macro 2.0 definition.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::MacroRulesDefinition>
+ Parser<ManagedTokenSource>::parse_decl_macro_def (AST::Visibility vis,
+ 						  AST::AttrVec outer_attrs)
+ {
+   // ensure that first token is identifier saying "macro"
+   const_TokenPtr t = lexer.peek_token ();
+   if (t->get_id () != MACRO)
+     {
+       Error error (
+ 	t->get_locus (),
+ 	"declarative macro definition does not start with %<macro%>");
+       add_error (std::move (error));
+ 
+       // skip after somewhere?
+       return nullptr;
+     }
+   lexer.skip_token ();
+   location_t macro_locus = t->get_locus ();
+ 
+   // parse macro name
+   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
+   if (ident_tok == nullptr)
+     {
+       return nullptr;
+     }
+   Identifier rule_name{ident_tok};
+ 
+   t = lexer.peek_token ();
+   if (t->get_id () == LEFT_PAREN)
+     {
+       // single definiton of macro rule
+       // e.g. `macro foo($e:expr) {}`
+ 
+       // parse macro matcher
+       location_t locus = lexer.peek_token ()->get_locus ();
+       AST::MacroMatcher matcher = parse_macro_matcher ();
+       if (matcher.is_error ())
+ 	return nullptr;
+ 
+       // check delimiter of macro matcher
+       if (matcher.get_delim_type () != AST::DelimType::PARENS)
+ 	{
+ 	  Error error (locus, "only parenthesis can be used for a macro "
+ 			      "matcher in declarative macro definition");
+ 	  add_error (std::move (error));
+ 	  return nullptr;
+ 	}
+ 
+       location_t transcriber_loc = lexer.peek_token ()->get_locus ();
+       auto delim_tok_tree = parse_delim_token_tree ();
+       if (!delim_tok_tree)
+ 	return nullptr;
+ 
+       AST::MacroTranscriber transcriber (delim_tok_tree.value (),
+ 					 transcriber_loc);
+ 
+       if (transcriber.get_token_tree ().get_delim_type ()
+ 	  != AST::DelimType::CURLY)
+ 	{
+ 	  Error error (transcriber_loc,
+ 		       "only braces can be used for a macro transcriber "
+ 		       "in declarative macro definition");
+ 	  add_error (std::move (error));
+ 	  return nullptr;
+ 	}
+ 
+       std::vector<AST::MacroRule> macro_rules;
+       macro_rules.emplace_back (std::move (matcher), std::move (transcriber),
+ 				locus);
+ 
+       return std::unique_ptr<AST::MacroRulesDefinition> (
+ 	AST::MacroRulesDefinition::decl_macro (std::move (rule_name),
+ 					       macro_rules,
+ 					       std::move (outer_attrs),
+ 					       macro_locus, vis));
+     }
+   else if (t->get_id () == LEFT_CURLY)
+     {
+       // multiple definitions of macro rule separated by comma
+       // e.g. `macro foo { () => {}, ($e:expr) => {}, }`
+ 
+       // parse left curly
+       const_TokenPtr left_curly = expect_token (LEFT_CURLY);
+       if (left_curly == nullptr)
+ 	{
+ 	  return nullptr;
+ 	}
+ 
+       // parse actual macro rules
+       std::vector<AST::MacroRule> macro_rules;
+ 
+       // must be at least one macro rule, so parse it
+       AST::MacroRule initial_rule = parse_macro_rule ();
+       if (initial_rule.is_error ())
+ 	{
+ 	  Error error (
+ 	    lexer.peek_token ()->get_locus (),
+ 	    "required first macro rule in declarative macro definition "
+ 	    "could not be parsed");
+ 	  add_error (std::move (error));
+ 
+ 	  // skip after somewhere?
+ 	  return nullptr;
+ 	}
+       macro_rules.push_back (std::move (initial_rule));
+ 
+       t = lexer.peek_token ();
+       // parse macro rules
+       while (t->get_id () == COMMA)
+ 	{
+ 	  // skip comma
+ 	  lexer.skip_token ();
+ 
+ 	  // don't parse if end of macro rules
+ 	  if (Parse::Utils::token_id_matches_delims (
+ 		lexer.peek_token ()->get_id (), AST::CURLY))
+ 	    {
+ 	      break;
+ 	    }
+ 
+ 	  // try to parse next rule
+ 	  AST::MacroRule rule = parse_macro_rule ();
+ 	  if (rule.is_error ())
+ 	    {
+ 	      Error error (
+ 		lexer.peek_token ()->get_locus (),
+ 		"failed to parse macro rule in declarative macro definition");
+ 	      add_error (std::move (error));
+ 
+ 	      return nullptr;
+ 	    }
+ 
+ 	  macro_rules.push_back (std::move (rule));
+ 
+ 	  t = lexer.peek_token ();
+ 	}
+ 
+       // parse right curly
+       const_TokenPtr right_curly = expect_token (RIGHT_CURLY);
+       if (right_curly == nullptr)
+ 	{
+ 	  return nullptr;
+ 	}
+ 
+       return std::unique_ptr<AST::MacroRulesDefinition> (
+ 	AST::MacroRulesDefinition::decl_macro (std::move (rule_name),
+ 					       std::move (macro_rules),
+ 					       std::move (outer_attrs),
+ 					       macro_locus, vis));
+     }
+   else
+     {
+       add_error (Error (t->get_locus (),
+ 			"unexpected token %qs - expecting delimiters "
+ 			"(for a declarative macro definiton)",
+ 			t->get_token_description ()));
+       return nullptr;
+     }
+ }
+ 
+ /* Parses a visibility syntactical production (i.e. creating a non-default
+  * visibility) */
+ template <typename ManagedTokenSource>
+ tl::expected<AST::Visibility, Parse::Error::Visibility>
+ Parser<ManagedTokenSource>::parse_visibility ()
+ {
+   // check for no visibility
+   if (lexer.peek_token ()->get_id () != PUB)
+     {
+       return AST::Visibility::create_private ();
+     }
+ 
+   auto vis_loc = lexer.peek_token ()->get_locus ();
+   lexer.skip_token ();
+ 
+   // create simple pub visibility if
+   // - found no parentheses
+   // - found unit type `()`
+   if (lexer.peek_token ()->get_id () != LEFT_PAREN
+       || lexer.peek_token (1)->get_id () == RIGHT_PAREN)
+     {
+       return AST::Visibility::create_public (vis_loc);
+       // or whatever
+     }
+ 
+   lexer.skip_token ();
+ 
+   const_TokenPtr t = lexer.peek_token ();
+   auto path_loc = t->get_locus ();
+ 
+   switch (t->get_id ())
+     {
+     case CRATE:
+       lexer.skip_token ();
+ 
+       skip_token (RIGHT_PAREN);
+ 
+       return AST::Visibility::create_crate (path_loc, vis_loc);
+     case SELF:
+       lexer.skip_token ();
+ 
+       skip_token (RIGHT_PAREN);
+ 
+       return AST::Visibility::create_self (path_loc, vis_loc);
+     case SUPER:
+       lexer.skip_token ();
+ 
+       skip_token (RIGHT_PAREN);
+ 
+       return AST::Visibility::create_super (path_loc, vis_loc);
+     case IN:
+       {
+ 	lexer.skip_token ();
+ 
+ 	// parse the "in" path as well
+ 	auto path = parse_simple_path ();
+ 	if (!path)
+ 	  {
+ 	    Error error (lexer.peek_token ()->get_locus (),
+ 			 "missing path in pub(in path) visibility");
+ 	    add_error (std::move (error));
+ 
+ 	    // skip after somewhere?
+ 	    return Parse::Error::Visibility::make_missing_path ();
+ 	  }
+ 
+ 	skip_token (RIGHT_PAREN);
+ 
+ 	return AST::Visibility::create_in_path (std::move (path.value ()),
+ 						vis_loc);
+       }
+     default:
+       add_error (Error (t->get_locus (), "unexpected token %qs in visibility",
+ 			t->get_token_description ()));
+ 
+       lexer.skip_token ();
+       return Parse::Error::Visibility::make_malformed ();
+     }
+ }
+ 
+ // Parses a module - either a bodied module or a module defined in another file.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::Module>
+ Parser<ManagedTokenSource>::parse_module (AST::Visibility vis,
+ 					  AST::AttrVec outer_attrs)
+ {
+   location_t locus = lexer.peek_token ()->get_locus ();
+ 
+   Unsafety safety = Unsafety::Normal;
+   if (lexer.peek_token ()->get_id () == UNSAFE)
+     {
+       safety = Unsafety::Unsafe;
+       skip_token (UNSAFE);
+     }
+ 
+   skip_token (MOD);
+ 
+   const_TokenPtr module_name = expect_token (IDENTIFIER);
+   if (module_name == nullptr)
+     {
+       return nullptr;
+     }
+   Identifier name{module_name};
+ 
+   const_TokenPtr t = lexer.peek_token ();
+ 
+   switch (t->get_id ())
+     {
+     case SEMICOLON:
+       lexer.skip_token ();
+ 
+       // Construct an external module
+       return std::unique_ptr<AST::Module> (
+ 	new AST::Module (std::move (name), std::move (vis),
+ 			 std::move (outer_attrs), locus, safety,
+ 			 lexer.get_filename (), inline_module_stack));
+     case LEFT_CURLY:
+       {
+ 	lexer.skip_token ();
+ 
+ 	// parse inner attributes
+ 	AST::AttrVec inner_attrs = parse_inner_attributes ();
+ 
+ 	std::string default_path = name.as_string ();
+ 
+ 	if (inline_module_stack.empty ())
+ 	  {
+ 	    std::string filename = lexer.get_filename ();
+ 	    auto slash_idx = filename.rfind (file_separator);
+ 	    if (slash_idx == std::string::npos)
+ 	      slash_idx = 0;
+ 	    else
+ 	      slash_idx++;
+ 	    filename = filename.substr (slash_idx);
+ 
+ 	    std::string subdir;
+ 	    if (get_file_subdir (filename, subdir))
+ 	      default_path = subdir + file_separator + name.as_string ();
+ 	  }
+ 
+ 	std::string module_path_name
+ 	  = extract_module_path (inner_attrs, outer_attrs, default_path);
+ 	InlineModuleStackScope scope (*this, std::move (module_path_name));
+ 
+ 	// parse items
+ 	std::vector<std::unique_ptr<AST::Item>> items;
+ 	const_TokenPtr tok = lexer.peek_token ();
+ 	while (tok->get_id () != RIGHT_CURLY)
+ 	  {
+ 	    auto item = parse_item (false);
+ 	    if (!item)
+ 	      {
+ 		Error error (tok->get_locus (),
+ 			     "failed to parse item in module");
+ 		add_error (std::move (error));
+ 
+ 		return nullptr;
+ 	      }
+ 
+ 	    items.push_back (std::move (item.value ()));
+ 
+ 	    tok = lexer.peek_token ();
+ 	  }
+ 
+ 	if (!skip_token (RIGHT_CURLY))
+ 	  {
+ 	    // skip somewhere?
+ 	    return nullptr;
+ 	  }
+ 
+ 	return std::unique_ptr<AST::Module> (
+ 	  new AST::Module (std::move (name), locus, std::move (items),
+ 			   std::move (vis), safety, std::move (inner_attrs),
+ 			   std::move (outer_attrs))); // module name?
+       }
+     default:
+       add_error (
+ 	Error (t->get_locus (),
+ 	       "unexpected token %qs in module declaration/definition item",
+ 	       t->get_token_description ()));
+ 
+       lexer.skip_token ();
+       return nullptr;
+     }
+ }
+ 
+ // Parses an extern crate declaration (dependency on external crate)
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::ExternCrate>
+ Parser<ManagedTokenSource>::parse_extern_crate (AST::Visibility vis,
+ 						AST::AttrVec outer_attrs)
+ {
+   location_t locus = lexer.peek_token ()->get_locus ();
+   if (!skip_token (EXTERN_KW))
+     {
+       skip_after_semicolon ();
+       return nullptr;
+     }
+ 
+   if (!skip_token (CRATE))
+     {
+       skip_after_semicolon ();
+       return nullptr;
+     }
+ 
+   /* parse crate reference name - this has its own syntactical rule in reference
+    * but seems to not be used elsewhere, so i'm putting it here */
+   const_TokenPtr crate_name_tok = lexer.peek_token ();
+   std::string crate_name;
+ 
+   switch (crate_name_tok->get_id ())
+     {
+     case IDENTIFIER:
+       crate_name = crate_name_tok->get_str ();
+       lexer.skip_token ();
+       break;
+     case SELF:
+       crate_name = Values::Keywords::SELF;
+       lexer.skip_token ();
+       break;
+     default:
+       add_error (
+ 	Error (crate_name_tok->get_locus (),
+ 	       "expecting crate name (identifier or %<self%>), found %qs",
+ 	       crate_name_tok->get_token_description ()));
+ 
+       skip_after_semicolon ();
+       return nullptr;
+     }
+ 
+   // don't parse as clause if it doesn't exist
+   if (lexer.peek_token ()->get_id () == SEMICOLON)
+     {
+       lexer.skip_token ();
+ 
+       return std::unique_ptr<AST::ExternCrate> (
+ 	new AST::ExternCrate (std::move (crate_name), std::move (vis),
+ 			      std::move (outer_attrs), locus));
+     }
+ 
+   /* parse as clause - this also has its own syntactical rule in reference and
+    * also seems to not be used elsewhere, so including here again. */
+   if (!skip_token (AS))
+     {
+       skip_after_semicolon ();
+       return nullptr;
+     }
+ 
+   const_TokenPtr as_name_tok = lexer.peek_token ();
+   std::string as_name;
+ 
+   switch (as_name_tok->get_id ())
+     {
+     case IDENTIFIER:
+       as_name = as_name_tok->get_str ();
+       lexer.skip_token ();
+       break;
+     case UNDERSCORE:
+       as_name = Values::Keywords::UNDERSCORE;
+       lexer.skip_token ();
+       break;
+     default:
+       add_error (
+ 	Error (as_name_tok->get_locus (),
+ 	       "expecting as clause name (identifier or %<_%>), found %qs",
+ 	       as_name_tok->get_token_description ()));
+ 
+       skip_after_semicolon ();
+       return nullptr;
+     }
+ 
+   if (!skip_token (SEMICOLON))
+     {
+       skip_after_semicolon ();
+       return nullptr;
+     }
+ 
+   return std::unique_ptr<AST::ExternCrate> (
+     new AST::ExternCrate (std::move (crate_name), std::move (vis),
+ 			  std::move (outer_attrs), locus, std::move (as_name)));
+ }
+ 
+ // Parses a use declaration.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::UseDeclaration>
+ Parser<ManagedTokenSource>::parse_use_decl (AST::Visibility vis,
+ 					    AST::AttrVec outer_attrs)
+ {
+   location_t locus = lexer.peek_token ()->get_locus ();
+   if (!skip_token (USE))
+     {
+       skip_after_semicolon ();
+       return nullptr;
+     }
+ 
+   // parse use tree, which is required
+   std::unique_ptr<AST::UseTree> use_tree = parse_use_tree ();
+   if (use_tree == nullptr)
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "could not parse use tree in use declaration");
+       add_error (std::move (error));
+ 
+       skip_after_semicolon ();
+       return nullptr;
+     }
+ 
+   if (!skip_token (SEMICOLON))
+     {
+       skip_after_semicolon ();
+       return nullptr;
+     }
+ 
+   return std::unique_ptr<AST::UseDeclaration> (
+     new AST::UseDeclaration (std::move (use_tree), std::move (vis),
+ 			     std::move (outer_attrs), locus));
+ }
+ 
+ // Parses a use tree (which can be recursive and is actually a base class).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::UseTree>
+ Parser<ManagedTokenSource>::parse_use_tree ()
+ {
+   /* potential syntax definitions in attempt to get algorithm:
+    *  Glob:
+    *      <- SimplePath :: *
+    *      <- :: *
+    *      <- *
+    *  Nested tree thing:
+    *      <- SimplePath :: { COMPLICATED_INNER_TREE_THING }
+    *      <- :: COMPLICATED_INNER_TREE_THING }
+    *      <- { COMPLICATED_INNER_TREE_THING }
+    *  Rebind thing:
+    *      <- SimplePath as IDENTIFIER
+    *      <- SimplePath as _
+    *      <- SimplePath
+    */
+ 
+   /* current plan of attack: try to parse SimplePath first - if fails, one of
+    * top two then try parse :: - if fails, one of top two. Next is deciding
+    * character for top two. */
+ 
+   /* Thus, parsing smaller parts of use tree may require feeding into function
+    * via parameters (or could handle all in this single function because other
+    * use tree types aren't recognised as separate in the spec) */
+ 
+   // TODO: I think this function is too complex, probably should split it
+ 
+   location_t locus = lexer.peek_token ()->get_locus ();
+ 
+   // bool has_path = false;
+   auto path = parse_simple_path ();
+ 
+   if (!path)
+     {
+       // has no path, so must be glob or nested tree UseTree type
+ 
+       bool is_global = false;
+ 
+       // check for global scope resolution operator
+       if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION)
+ 	{
+ 	  lexer.skip_token ();
+ 	  is_global = true;
+ 	}
+ 
+       const_TokenPtr t = lexer.peek_token ();
+       switch (t->get_id ())
+ 	{
+ 	case ASTERISK:
+ 	  // glob UseTree type
+ 	  lexer.skip_token ();
+ 
+ 	  if (is_global)
+ 	    return std::unique_ptr<AST::UseTreeGlob> (
+ 	      new AST::UseTreeGlob (AST::UseTreeGlob::GLOBAL,
+ 				    AST::SimplePath::create_empty (), locus));
+ 	  else
+ 	    return std::unique_ptr<AST::UseTreeGlob> (
+ 	      new AST::UseTreeGlob (AST::UseTreeGlob::NO_PATH,
+ 				    AST::SimplePath::create_empty (), locus));
+ 	case LEFT_CURLY:
+ 	  {
+ 	    // nested tree UseTree type
+ 	    lexer.skip_token ();
+ 
+ 	    std::vector<std::unique_ptr<AST::UseTree>> use_trees;
+ 
+ 	    const_TokenPtr t = lexer.peek_token ();
+ 	    while (t->get_id () != RIGHT_CURLY)
+ 	      {
+ 		std::unique_ptr<AST::UseTree> use_tree = parse_use_tree ();
+ 		if (use_tree == nullptr)
+ 		  {
+ 		    break;
+ 		  }
+ 
+ 		use_trees.push_back (std::move (use_tree));
+ 
+ 		if (lexer.peek_token ()->get_id () != COMMA)
+ 		  break;
+ 
+ 		lexer.skip_token ();
+ 		t = lexer.peek_token ();
+ 	      }
+ 
+ 	    // skip end curly delimiter
+ 	    if (!skip_token (RIGHT_CURLY))
+ 	      {
+ 		// skip after somewhere?
+ 		return nullptr;
+ 	      }
+ 
+ 	    if (is_global)
+ 	      return std::unique_ptr<AST::UseTreeList> (
+ 		new AST::UseTreeList (AST::UseTreeList::GLOBAL,
+ 				      AST::SimplePath::create_empty (),
+ 				      std::move (use_trees), locus));
+ 	    else
+ 	      return std::unique_ptr<AST::UseTreeList> (
+ 		new AST::UseTreeList (AST::UseTreeList::NO_PATH,
+ 				      AST::SimplePath::create_empty (),
+ 				      std::move (use_trees), locus));
+ 	  }
+ 	case AS:
+ 	  // this is not allowed
+ 	  add_error (Error (
+ 	    t->get_locus (),
+ 	    "use declaration with rebind %<as%> requires a valid simple path - "
+ 	    "none found"));
+ 
+ 	  skip_after_semicolon ();
+ 	  return nullptr;
+ 	default:
+ 	  add_error (Error (t->get_locus (),
+ 			    "unexpected token %qs in use tree with "
+ 			    "no valid simple path (i.e. list"
+ 			    " or glob use tree)",
+ 			    t->get_token_description ()));
+ 
+ 	  skip_after_semicolon ();
+ 	  return nullptr;
+ 	}
+     }
+   else
+     {
+       const_TokenPtr t = lexer.peek_token ();
+ 
+       switch (t->get_id ())
+ 	{
+ 	case AS:
+ 	  {
+ 	    // rebind UseTree type
+ 	    lexer.skip_token ();
+ 
+ 	    const_TokenPtr t = lexer.peek_token ();
+ 	    switch (t->get_id ())
+ 	      {
+ 	      case IDENTIFIER:
+ 		// skip lexer token
+ 		lexer.skip_token ();
+ 
+ 		return std::unique_ptr<AST::UseTreeRebind> (
+ 		  new AST::UseTreeRebind (AST::UseTreeRebind::IDENTIFIER,
+ 					  std::move (path.value ()), locus, t));
+ 	      case UNDERSCORE:
+ 		// skip lexer token
+ 		lexer.skip_token ();
+ 
+ 		return std::unique_ptr<AST::UseTreeRebind> (
+ 		  new AST::UseTreeRebind (AST::UseTreeRebind::WILDCARD,
+ 					  std::move (path.value ()), locus,
+ 					  {Values::Keywords::UNDERSCORE,
+ 					   t->get_locus ()}));
+ 	      default:
+ 		add_error (Error (
+ 		  t->get_locus (),
+ 		  "unexpected token %qs in use tree with as clause - expected "
+ 		  "identifier or %<_%>",
+ 		  t->get_token_description ()));
+ 
+ 		skip_after_semicolon ();
+ 		return nullptr;
+ 	      }
+ 	  }
+ 	case SEMICOLON:
+ 	  // rebind UseTree type without rebinding - path only
+ 
+ 	  // don't skip semicolon - handled in parse_use_tree
+ 	  // lexer.skip_token();
+ 	case COMMA:
+ 	case RIGHT_CURLY:
+ 	  // this may occur in recursive calls - assume it is ok and ignore it
+ 	  return std::unique_ptr<AST::UseTreeRebind> (
+ 	    new AST::UseTreeRebind (AST::UseTreeRebind::NONE,
+ 				    std::move (path.value ()), locus));
+ 	case SCOPE_RESOLUTION:
+ 	  // keep going
+ 	  break;
+ 	default:
+ 	  add_error (Error (t->get_locus (),
+ 			    "unexpected token %qs in use tree with valid path",
+ 			    t->get_token_description ()));
+ 	  return nullptr;
+ 	}
+ 
+       skip_token ();
+       t = lexer.peek_token ();
+ 
+       switch (t->get_id ())
+ 	{
+ 	case ASTERISK:
+ 	  // glob UseTree type
+ 	  lexer.skip_token ();
+ 
+ 	  return std::unique_ptr<AST::UseTreeGlob> (
+ 	    new AST::UseTreeGlob (AST::UseTreeGlob::PATH_PREFIXED,
+ 				  std::move (path.value ()), locus));
+ 	case LEFT_CURLY:
+ 	  {
+ 	    // nested tree UseTree type
+ 	    lexer.skip_token ();
+ 
+ 	    std::vector<std::unique_ptr<AST::UseTree>> use_trees;
+ 
+ 	    // TODO: think of better control structure
+ 	    const_TokenPtr t = lexer.peek_token ();
+ 	    while (t->get_id () != RIGHT_CURLY)
+ 	      {
+ 		std::unique_ptr<AST::UseTree> use_tree = parse_use_tree ();
+ 		if (use_tree == nullptr)
+ 		  {
+ 		    break;
+ 		  }
+ 
+ 		use_trees.push_back (std::move (use_tree));
+ 
+ 		if (lexer.peek_token ()->get_id () != COMMA)
+ 		  break;
+ 
+ 		lexer.skip_token ();
+ 		t = lexer.peek_token ();
+ 	      }
+ 
+ 	    // skip end curly delimiter
+ 	    if (!skip_token (RIGHT_CURLY))
+ 	      {
+ 		// skip after somewhere?
+ 		return nullptr;
+ 	      }
+ 
+ 	    return std::unique_ptr<AST::UseTreeList> (
+ 	      new AST::UseTreeList (AST::UseTreeList::PATH_PREFIXED,
+ 				    std::move (path.value ()),
+ 				    std::move (use_trees), locus));
+ 	  }
+ 	default:
+ 	  add_error (Error (t->get_locus (),
+ 			    "unexpected token %qs in use tree with valid path",
+ 			    t->get_token_description ()));
+ 
+ 	  // skip_after_semicolon();
+ 	  return nullptr;
+ 	}
+     }
+ }
+ 
+ // Parses a function (not a method).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::Function>
+ Parser<ManagedTokenSource>::parse_function (AST::Visibility vis,
+ 					    AST::AttrVec outer_attrs,
+ 					    bool is_external)
+ {
+   location_t locus = lexer.peek_token ()->get_locus ();
+   // Get qualifiers for function if they exist
+   AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
+ 
+   skip_token (FN_KW);
+ 
+   // Save function name token
+   const_TokenPtr function_name_tok = expect_token (IDENTIFIER);
+   if (function_name_tok == nullptr)
+     {
+       skip_after_next_block ();
+       return nullptr;
+     }
+   Identifier function_name{function_name_tok};
+ 
+   // parse generic params - if exist
+   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
+     = parse_generic_params_in_angles ();
+ 
+   if (!skip_token (LEFT_PAREN))
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "function declaration missing opening parentheses before "
+ 		   "parameter list");
+       add_error (std::move (error));
+ 
+       skip_after_next_block ();
+       return nullptr;
+     }
+ 
+   auto initial_param = parse_self_param ();
+ 
+   if (!initial_param.has_value ()
+       && initial_param.error () != ParseSelfError::NOT_SELF)
+     return nullptr;
+ 
+   if (initial_param.has_value () && lexer.peek_token ()->get_id () == COMMA)
+     skip_token ();
+ 
+   // parse function parameters (only if next token isn't right paren)
+   std::vector<std::unique_ptr<AST::Param>> function_params;
+ 
+   if (lexer.peek_token ()->get_id () != RIGHT_PAREN)
+     function_params
+       = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
+ 
+   if (initial_param.has_value ())
+     function_params.insert (function_params.begin (),
+ 			    std::move (*initial_param));
+ 
+   if (!skip_token (RIGHT_PAREN))
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "function declaration missing closing parentheses after "
+ 		   "parameter list");
+       add_error (std::move (error));
+ 
+       skip_after_next_block ();
+       return nullptr;
+     }
+ 
+   // parse function return type - if exists
+   std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
+ 
+   // parse where clause - if exists
+   AST::WhereClause where_clause = parse_where_clause ();
+ 
+   tl::optional<std::unique_ptr<AST::BlockExpr>> body = tl::nullopt;
+   if (lexer.peek_token ()->get_id () == SEMICOLON)
+     lexer.skip_token ();
+   else
+     {
+       std::unique_ptr<AST::BlockExpr> block_expr = parse_block_expr ();
+       if (block_expr == nullptr)
+ 	return nullptr;
+       body = std::move (block_expr);
+     }
+ 
+   return std::unique_ptr<AST::Function> (
+     new AST::Function (std::move (function_name), std::move (qualifiers),
+ 		       std::move (generic_params), std::move (function_params),
+ 		       std::move (return_type), std::move (where_clause),
+ 		       std::move (body), std::move (vis),
+ 		       std::move (outer_attrs), locus, false, is_external));
+ }
+ 
+ // Parses function or method qualifiers (i.e. const, unsafe, and extern).
+ template <typename ManagedTokenSource>
+ AST::FunctionQualifiers
+ Parser<ManagedTokenSource>::parse_function_qualifiers ()
+ {
+   Async async_status = Async::No;
+   Const const_status = Const::No;
+   Unsafety unsafe_status = Unsafety::Normal;
+   bool has_extern = false;
+   std::string abi;
+ 
+   const_TokenPtr t;
+   location_t locus;
+   // Check in order of const, unsafe, then extern
+   for (int i = 0; i < 2; i++)
+     {
+       t = lexer.peek_token ();
+       locus = t->get_locus ();
+ 
+       switch (t->get_id ())
+ 	{
+ 	case CONST:
+ 	  lexer.skip_token ();
+ 	  const_status = Const::Yes;
+ 	  break;
+ 	case ASYNC:
+ 	  lexer.skip_token ();
+ 	  async_status = Async::Yes;
+ 	  break;
+ 	default:
+ 	  // const status is still none
+ 	  break;
+ 	}
+     }
+ 
+   if (lexer.peek_token ()->get_id () == UNSAFE)
+     {
+       lexer.skip_token ();
+       unsafe_status = Unsafety::Unsafe;
+     }
+ 
+   if (lexer.peek_token ()->get_id () == EXTERN_KW)
+     {
+       lexer.skip_token ();
+       has_extern = true;
+ 
+       // detect optional abi name
+       const_TokenPtr next_tok = lexer.peek_token ();
+       if (next_tok->get_id () == STRING_LITERAL)
+ 	{
+ 	  lexer.skip_token ();
+ 	  abi = next_tok->get_str ();
+ 	}
+     }
+ 
+   return AST::FunctionQualifiers (locus, async_status, const_status,
+ 				  unsafe_status, has_extern, std::move (abi));
+ }
+ 
+ // Parses generic (lifetime or type) params inside angle brackets (optional).
+ template <typename ManagedTokenSource>
+ std::vector<std::unique_ptr<AST::GenericParam>>
+ Parser<ManagedTokenSource>::parse_generic_params_in_angles ()
+ {
+   if (lexer.peek_token ()->get_id () != LEFT_ANGLE)
+     {
+       // seems to be no generic params, so exit with empty vector
+       return std::vector<std::unique_ptr<AST::GenericParam>> ();
+     }
+   lexer.skip_token ();
+ 
+   // DEBUG:
+   rust_debug ("skipped left angle in generic param");
+ 
+   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
+     = parse_generic_params (Parse::Utils::is_right_angle_tok);
+ 
+   // DEBUG:
+   rust_debug ("finished parsing actual generic params (i.e. inside angles)");
+ 
+   if (!skip_generics_right_angle ())
+     {
+       // DEBUG
+       rust_debug ("failed to skip generics right angle - returning empty "
+ 		  "generic params");
+ 
+       return std::vector<std::unique_ptr<AST::GenericParam>> ();
+     }
+ 
+   return generic_params;
+ }
+ 
+ template <typename ManagedTokenSource>
+ template <typename EndTokenPred>
+ std::unique_ptr<AST::GenericParam>
+ Parser<ManagedTokenSource>::parse_generic_param (EndTokenPred is_end_token)
+ {
+   auto outer_attrs = parse_outer_attributes ();
+   std::unique_ptr<AST::GenericParam> param;
+   auto token = lexer.peek_token ();
+ 
+   switch (token->get_id ())
+     {
+     case LIFETIME:
+       {
+ 	auto lifetime = parse_lifetime (false);
+ 	if (!lifetime)
+ 	  {
+ 	    rust_error_at (
+ 	      token->get_locus (),
+ 	      "failed to parse lifetime in generic parameter list");
+ 	    return nullptr;
+ 	  }
+ 
+ 	std::vector<AST::Lifetime> lifetime_bounds;
+ 	if (lexer.peek_token ()->get_id () == COLON)
+ 	  {
+ 	    lexer.skip_token ();
+ 	    // parse required bounds
+ 	    lifetime_bounds
+ 	      = parse_lifetime_bounds ([is_end_token] (TokenId id) {
+ 		  return is_end_token (id) || id == COMMA;
+ 		});
+ 	  }
+ 
+ 	param = std::unique_ptr<AST::LifetimeParam> (new AST::LifetimeParam (
+ 	  std::move (lifetime.value ()), std::move (lifetime_bounds),
+ 	  std::move (outer_attrs), token->get_locus ()));
+ 	break;
+       }
+     case IDENTIFIER:
+       {
+ 	auto type_ident = token->get_str ();
+ 	lexer.skip_token ();
+ 
+ 	std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
+ 	if (lexer.peek_token ()->get_id () == COLON)
+ 	  {
+ 	    lexer.skip_token ();
+ 
+ 	    // parse optional type param bounds
+ 	    type_param_bounds = parse_type_param_bounds ();
+ 	  }
+ 
+ 	std::unique_ptr<AST::Type> type = nullptr;
+ 	if (lexer.peek_token ()->get_id () == EQUAL)
+ 	  {
+ 	    lexer.skip_token ();
+ 
+ 	    // parse required type
+ 	    type = parse_type ();
+ 	    if (!type)
+ 	      {
+ 		rust_error_at (
+ 		  lexer.peek_token ()->get_locus (),
+ 		  "failed to parse type in type param in generic params");
+ 		return nullptr;
+ 	      }
+ 	  }
+ 
+ 	param = std::unique_ptr<AST::TypeParam> (
+ 	  new AST::TypeParam (std::move (type_ident), token->get_locus (),
+ 			      std::move (type_param_bounds), std::move (type),
+ 			      std::move (outer_attrs)));
+ 	break;
+       }
+     case CONST:
+       {
+ 	lexer.skip_token ();
+ 
+ 	auto name_token = expect_token (IDENTIFIER);
+ 
+ 	if (!name_token || !expect_token (COLON))
+ 	  return nullptr;
+ 
+ 	auto type = parse_type ();
+ 	if (!type)
+ 	  return nullptr;
+ 
+ 	// optional default value
+ 	tl::optional<AST::GenericArg> default_expr = tl::nullopt;
+ 	if (lexer.peek_token ()->get_id () == EQUAL)
+ 	  {
+ 	    lexer.skip_token ();
+ 	    auto tok = lexer.peek_token ();
+ 	    default_expr = parse_generic_arg ();
+ 
+ 	    if (!default_expr)
+ 	      {
+ 		rust_error_at (tok->get_locus (),
+ 			       "invalid token for start of default value for "
+ 			       "const generic parameter: expected %<block%>, "
+ 			       "%<identifier%> or %<literal%>, got %qs",
+ 			       token_id_to_str (tok->get_id ()));
+ 		return nullptr;
+ 	      }
+ 
+ 	    // At this point, we *know* that we are parsing a const
+ 	    // expression
+ 	    if (default_expr.value ().get_kind ()
+ 		== AST::GenericArg::Kind::Either)
+ 	      default_expr = default_expr.value ().disambiguate_to_const ();
+ 	  }
+ 
+ 	param = std::unique_ptr<AST::ConstGenericParam> (
+ 	  new AST::ConstGenericParam (name_token->get_str (), std::move (type),
+ 				      default_expr, std::move (outer_attrs),
+ 				      token->get_locus ()));
+ 
+ 	break;
+       }
+     default:
+       // FIXME: Can we clean this last call with a method call?
+       rust_error_at (token->get_locus (),
+ 		     "unexpected token when parsing generic parameters: %qs",
+ 		     token->as_string ().c_str ());
+       return nullptr;
+     }
+ 
+   return param;
+ }
+ 
+ /* Parse generic (lifetime or type) params NOT INSIDE ANGLE BRACKETS!!! Almost
+  * always parse_generic_params_in_angles is what is wanted. */
+ template <typename ManagedTokenSource>
+ template <typename EndTokenPred>
+ std::vector<std::unique_ptr<AST::GenericParam>>
+ Parser<ManagedTokenSource>::parse_generic_params (EndTokenPred is_end_token)
+ {
+   std::vector<std::unique_ptr<AST::GenericParam>> generic_params;
+ 
+   /* can't parse lifetime and type params separately due to lookahead issues
+    * thus, parse them all here */
+ 
+   /* HACK: used to retain attribute data if a lifetime param is tentatively
+    * parsed but it turns out to be type param */
+   AST::Attribute parsed_outer_attr = AST::Attribute::create_empty ();
+ 
+   // Did we parse a generic type param yet
+   auto type_seen = false;
+   // Did we parse a const param with a default value yet
+   auto const_with_default_seen = false;
+   // Did the user write a lifetime parameter after a type one
+   auto order_error = false;
+   // Did the user write a const param with a default value after a type one
+   auto const_with_default_order_error = false;
+ 
+   // parse lifetime params
+   while (!is_end_token (lexer.peek_token ()->get_id ()))
+     {
+       auto param = parse_generic_param (is_end_token);
+       if (param)
+ 	{
+ 	  if (param->get_kind () == AST::GenericParam::Kind::Type)
+ 	    {
+ 	      type_seen = true;
+ 	      if (const_with_default_seen)
+ 		const_with_default_order_error = true;
+ 	    }
+ 	  else if (param->get_kind () == AST::GenericParam::Kind::Lifetime
+ 		   && type_seen)
+ 	    {
+ 	      order_error = true;
+ 	      if (const_with_default_seen)
+ 		const_with_default_order_error = true;
+ 	    }
+ 	  else if (param->get_kind () == AST::GenericParam::Kind::Const)
+ 	    {
+ 	      type_seen = true;
+ 	      AST::ConstGenericParam *const_param
+ 		= static_cast<AST::ConstGenericParam *> (param.get ());
+ 	      if (const_param->has_default_value ())
+ 		const_with_default_seen = true;
+ 	      else if (const_with_default_seen)
+ 		const_with_default_order_error = true;
+ 	    }
+ 
+ 	  generic_params.emplace_back (std::move (param));
+ 	  maybe_skip_token (COMMA);
+ 	}
+       else
+ 	break;
+     }
+ 
+   // FIXME: Add reordering hint
+   if (order_error)
+     {
+       Error error (generic_params.front ()->get_locus (),
+ 		   "invalid order for generic parameters: lifetime parameters "
+ 		   "must be declared prior to type and const parameters");
+       add_error (std::move (error));
+     }
+   if (const_with_default_order_error)
+     {
+       Error error (generic_params.front ()->get_locus (),
+ 		   "invalid order for generic parameters: generic parameters "
+ 		   "with a default must be trailing");
+       add_error (std::move (error));
+     }
+ 
+   generic_params.shrink_to_fit ();
+   return generic_params;
+ }
+ 
+ /* Parses lifetime generic parameters (pointers). Will also consume any
+  * trailing comma. No extra checks for end token. */
+ template <typename ManagedTokenSource>
+ std::vector<std::unique_ptr<AST::LifetimeParam>>
+ Parser<ManagedTokenSource>::parse_lifetime_params ()
+ {
+   std::vector<std::unique_ptr<AST::LifetimeParam>> lifetime_params;
+ 
+   while (lexer.peek_token ()->get_id () != END_OF_FILE)
+     {
+       auto lifetime_param = parse_lifetime_param ();
+ 
+       if (!lifetime_param)
+ 	{
+ 	  // can't treat as error as only way to get out with trailing comma
+ 	  break;
+ 	}
+ 
+       lifetime_params.emplace_back (
+ 	new AST::LifetimeParam (std::move (lifetime_param.value ())));
+ 
+       if (lexer.peek_token ()->get_id () != COMMA)
+ 	break;
+ 
+       // skip commas, including trailing commas
+       lexer.skip_token ();
+     }
+ 
+   lifetime_params.shrink_to_fit ();
+ 
+   return lifetime_params;
+ }
+ 
+ /* Parses lifetime generic parameters (pointers). Will also consume any
+  * trailing comma. Has extra is_end_token predicate checking. */
+ template <typename ManagedTokenSource>
+ template <typename EndTokenPred>
+ std::vector<std::unique_ptr<AST::LifetimeParam>>
+ Parser<ManagedTokenSource>::parse_lifetime_params (EndTokenPred is_end_token)
+ {
+   std::vector<std::unique_ptr<AST::LifetimeParam>> lifetime_params;
+ 
+   // if end_token is not specified, it defaults to EOF, so should work fine
+   while (!is_end_token (lexer.peek_token ()->get_id ()))
+     {
+       auto lifetime_param = parse_lifetime_param ();
+ 
+       if (!lifetime_param)
+ 	{
+ 	  /* TODO: is it worth throwing away all lifetime params just because
+ 	   * one failed? */
+ 	  Error error (lexer.peek_token ()->get_locus (),
+ 		       "failed to parse lifetime param in lifetime params");
+ 	  add_error (std::move (error));
+ 
+ 	  return {};
+ 	}
+ 
+       lifetime_params.emplace_back (
+ 	new AST::LifetimeParam (std::move (lifetime_param)));
+ 
+       if (lexer.peek_token ()->get_id () != COMMA)
+ 	break;
+ 
+       // skip commas, including trailing commas
+       lexer.skip_token ();
+     }
+ 
+   lifetime_params.shrink_to_fit ();
+ 
+   return lifetime_params;
+ }
+ 
+ /* Parses lifetime generic parameters (objects). Will also consume any
+  * trailing comma. No extra checks for end token.
+  * TODO: is this best solution? implements most of the same algorithm.
+  * TODO: seems to be unused, remove? */
+ template <typename ManagedTokenSource>
+ std::vector<AST::LifetimeParam>
+ Parser<ManagedTokenSource>::parse_lifetime_params_objs ()
+ {
+   std::vector<AST::LifetimeParam> lifetime_params;
+ 
+   // bad control structure as end token cannot be guaranteed
+   while (true)
+     {
+       auto lifetime_param = parse_lifetime_param ();
+ 
+       if (!lifetime_param)
+ 	{
+ 	  // not an error as only way to exit if trailing comma
+ 	  break;
+ 	}
+ 
+       lifetime_params.push_back (std::move (lifetime_param.value ()));
+ 
+       if (lexer.peek_token ()->get_id () != COMMA)
+ 	break;
+ 
+       // skip commas, including trailing commas
+       lexer.skip_token ();
+     }
+ 
+   lifetime_params.shrink_to_fit ();
+ 
+   return lifetime_params;
+ }
+ 
+ /* Parses lifetime generic parameters (objects). Will also consume any
+  * trailing comma. Has extra is_end_token predicate checking.
+  * TODO: is this best solution? implements most of the same algorithm. */
+ template <typename ManagedTokenSource>
+ template <typename EndTokenPred>
+ std::vector<AST::LifetimeParam>
+ Parser<ManagedTokenSource>::parse_lifetime_params_objs (
+   EndTokenPred is_end_token)
+ {
+   std::vector<AST::LifetimeParam> lifetime_params;
+ 
+   while (!is_end_token (lexer.peek_token ()->get_id ()))
+     {
+       auto lifetime_param = parse_lifetime_param ();
+ 
+       if (!lifetime_param)
+ 	{
+ 	  /* TODO: is it worth throwing away all lifetime params just because
+ 	   * one failed? */
+ 	  Error error (lexer.peek_token ()->get_locus (),
+ 		       "failed to parse lifetime param in lifetime params");
+ 	  add_error (std::move (error));
+ 
+ 	  return {};
+ 	}
+ 
+       lifetime_params.push_back (std::move (lifetime_param.value ()));
+ 
+       if (lexer.peek_token ()->get_id () != COMMA)
+ 	break;
+ 
+       // skip commas, including trailing commas
+       lexer.skip_token ();
+     }
+ 
+   lifetime_params.shrink_to_fit ();
+ 
+   return lifetime_params;
+ }
+ 
+ /* Parses a sequence of a certain grammar rule in object form (not pointer or
+  * smart pointer), delimited by commas and ending when 'is_end_token' is
+  * satisfied (templated). Will also consume any trailing comma.
+  * FIXME: this cannot be used due to member function pointer problems (i.e.
+  * parsing_function cannot be specified properly) */
+ template <typename ManagedTokenSource>
+ template <typename ParseFunction, typename EndTokenPred>
+ auto
+ Parser<ManagedTokenSource>::parse_non_ptr_sequence (
+   ParseFunction parsing_function, EndTokenPred is_end_token,
+   std::string error_msg) -> std::vector<decltype (parsing_function ())>
+ {
+   std::vector<decltype (parsing_function ())> params;
+ 
+   while (!is_end_token (lexer.peek_token ()->get_id ()))
+     {
+       auto param = parsing_function ();
+ 
+       if (param.is_error ())
+ 	{
+ 	  // TODO: is it worth throwing away all params just because one
+ 	  // failed?
+ 	  Error error (lexer.peek_token ()->get_locus (),
+ 		       std::move (error_msg));
+ 	  add_error (std::move (error));
+ 
+ 	  return {};
+ 	}
+ 
+       params.push_back (std::move (param));
+ 
+       if (lexer.peek_token ()->get_id () != COMMA)
+ 	break;
+ 
+       // skip commas, including trailing commas
+       lexer.skip_token ();
+     }
+ 
+   params.shrink_to_fit ();
+ 
+   return params;
+ }
+ 
+ /* Parses a single lifetime generic parameter (not including comma). */
+ template <typename ManagedTokenSource>
+ tl::expected<AST::LifetimeParam, ParseLifetimeParamError>
+ Parser<ManagedTokenSource>::parse_lifetime_param ()
+ {
+   // parse outer attributes, which are optional and may not exist
+   auto outer_attrs = parse_outer_attributes ();
+ 
+   // save lifetime token - required
+   const_TokenPtr lifetime_tok = lexer.peek_token ();
+   if (lifetime_tok->get_id () != LIFETIME)
+     {
+       // if lifetime is missing, must not be a lifetime param, so return error
+       return tl::make_unexpected<ParseLifetimeParamError> ({});
+     }
+   lexer.skip_token ();
+   AST::Lifetime lifetime (AST::Lifetime::NAMED, lifetime_tok->get_str (),
+ 			  lifetime_tok->get_locus ());
+ 
+   // parse lifetime bounds, if it exists
+   std::vector<AST::Lifetime> lifetime_bounds;
+   if (lexer.peek_token ()->get_id () == COLON)
+     {
+       // parse lifetime bounds
+       lifetime_bounds = parse_lifetime_bounds ();
+       // TODO: have end token passed in?
+     }
+ 
+   return AST::LifetimeParam (std::move (lifetime), std::move (lifetime_bounds),
+ 			     std::move (outer_attrs),
+ 			     lifetime_tok->get_locus ());
+ }
+ 
+ // Parses type generic parameters. Will also consume any trailing comma.
+ template <typename ManagedTokenSource>
+ std::vector<std::unique_ptr<AST::TypeParam>>
+ Parser<ManagedTokenSource>::parse_type_params ()
+ {
+   std::vector<std::unique_ptr<AST::TypeParam>> type_params;
+ 
+   // infinite loop with break on failure as no info on ending token
+   while (true)
+     {
+       std::unique_ptr<AST::TypeParam> type_param = parse_type_param ();
+ 
+       if (type_param == nullptr)
+ 	{
+ 	  // break if fails to parse
+ 	  break;
+ 	}
+ 
+       type_params.push_back (std::move (type_param));
+ 
+       if (lexer.peek_token ()->get_id () != COMMA)
+ 	break;
+ 
+       // skip commas, including trailing commas
+       lexer.skip_token ();
+     }
+ 
+   type_params.shrink_to_fit ();
+   return type_params;
+ }
+ 
+ // Parses type generic parameters. Will also consume any trailing comma.
+ template <typename ManagedTokenSource>
+ template <typename EndTokenPred>
+ std::vector<std::unique_ptr<AST::TypeParam>>
+ Parser<ManagedTokenSource>::parse_type_params (EndTokenPred is_end_token)
+ {
+   std::vector<std::unique_ptr<AST::TypeParam>> type_params;
+ 
+   while (!is_end_token (lexer.peek_token ()->get_id ()))
+     {
+       std::unique_ptr<AST::TypeParam> type_param = parse_type_param ();
+ 
+       if (type_param == nullptr)
+ 	{
+ 	  Error error (lexer.peek_token ()->get_locus (),
+ 		       "failed to parse type param in type params");
+ 	  add_error (std::move (error));
+ 
+ 	  return {};
+ 	}
+ 
+       type_params.push_back (std::move (type_param));
+ 
+       if (lexer.peek_token ()->get_id () != COMMA)
+ 	break;
+ 
+       // skip commas, including trailing commas
+       lexer.skip_token ();
+     }
+ 
+   type_params.shrink_to_fit ();
+   return type_params;
+   /* TODO: this shares most code with parse_lifetime_params - good place to
+    * use template (i.e. parse_non_ptr_sequence if doable) */
+ }
+ 
+ /* Parses a single type (generic) parameter, not including commas. May change
+  * to return value. */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::TypeParam>
+ Parser<ManagedTokenSource>::parse_type_param ()
+ {
+   // parse outer attributes, which are optional and may not exist
+   auto outer_attrs = parse_outer_attributes ();
+ 
+   const_TokenPtr identifier_tok = lexer.peek_token ();
+   if (identifier_tok->get_id () != IDENTIFIER)
+     {
+       // return null as type param can't exist without this required
+       // identifier
+       return nullptr;
+     }
+   Identifier ident{identifier_tok};
+   lexer.skip_token ();
+ 
+   // parse type param bounds (if they exist)
+   std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
+   if (lexer.peek_token ()->get_id () == COLON)
+     {
+       lexer.skip_token ();
+ 
+       // parse type param bounds, which may or may not exist
+       type_param_bounds = parse_type_param_bounds ();
+     }
+ 
+   // parse type (if it exists)
+   std::unique_ptr<AST::Type> type = nullptr;
+   if (lexer.peek_token ()->get_id () == EQUAL)
+     {
+       lexer.skip_token ();
+ 
+       // parse type (now required)
+       type = parse_type ();
+       if (type == nullptr)
+ 	{
+ 	  Error error (lexer.peek_token ()->get_locus (),
+ 		       "failed to parse type in type param");
+ 	  add_error (std::move (error));
+ 
+ 	  return nullptr;
+ 	}
+     }
+ 
+   return std::unique_ptr<AST::TypeParam> (
+     new AST::TypeParam (std::move (ident), identifier_tok->get_locus (),
+ 			std::move (type_param_bounds), std::move (type),
+ 			std::move (outer_attrs)));
+ }
+ 
+ /* Parses regular (i.e. non-generic) parameters in functions or methods. Also
+  * has end token handling. */
+ template <typename ManagedTokenSource>
+ template <typename EndTokenPred>
+ std::vector<std::unique_ptr<AST::Param>>
+ Parser<ManagedTokenSource>::parse_function_params (EndTokenPred is_end_token)
+ {
+   std::vector<std::unique_ptr<AST::Param>> params;
+ 
+   if (is_end_token (lexer.peek_token ()->get_id ()))
+     return params;
+ 
+   auto initial_param = parse_function_param ();
+ 
+   // Return empty parameter list if no parameter there
+   if (initial_param == nullptr)
+     {
+       // TODO: is this an error?
+       return params;
+     }
+ 
+   params.push_back (std::move (initial_param));
+ 
+   // maybe think of a better control structure here - do-while with an initial
+   // error state? basically, loop through parameter list until can't find any
+   // more params
+   const_TokenPtr t = lexer.peek_token ();
+   while (t->get_id () == COMMA)
+     {
+       // skip comma if applies
+       lexer.skip_token ();
+ 
+       // TODO: strictly speaking, shouldn't there be no trailing comma?
+       if (is_end_token (lexer.peek_token ()->get_id ()))
+ 	break;
+ 
+       // now, as right paren would break, function param is required
+       auto param = parse_function_param ();
+       if (param == nullptr)
+ 	{
+ 	  Error error (lexer.peek_token ()->get_locus (),
+ 		       "failed to parse function param (in function params)");
+ 	  add_error (std::move (error));
+ 
+ 	  // skip somewhere?
+ 	  return std::vector<std::unique_ptr<AST::Param>> ();
+ 	}
+ 
+       params.push_back (std::move (param));
+ 
+       t = lexer.peek_token ();
+     }
+ 
+   params.shrink_to_fit ();
+   return params;
+ }
+ 
+ /* Parses a single regular (i.e. non-generic) parameter in a function or
+  * method, i.e. the "name: type" bit. Also handles it not existing. */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::Param>
+ Parser<ManagedTokenSource>::parse_function_param ()
+ {
+   // parse outer attributes if they exist
+   AST::AttrVec outer_attrs = parse_outer_attributes ();
+ 
+   // TODO: should saved location be at start of outer attributes or pattern?
+   location_t locus = lexer.peek_token ()->get_locus ();
+ 
+   if (lexer.peek_token ()->get_id () == ELLIPSIS) // Unnamed variadic
+     {
+       lexer.skip_token (); // Skip ellipsis
+       return std::make_unique<AST::VariadicParam> (
+ 	AST::VariadicParam (std::move (outer_attrs), locus));
+     }
+ 
+   std::unique_ptr<AST::Pattern> param_pattern = parse_pattern ();
+ 
+   // create error function param if it doesn't exist
+   if (param_pattern == nullptr)
+     {
+       // skip after something
+       return nullptr;
+     }
+ 
+   if (!skip_token (COLON))
+     {
+       // skip after something
+       return nullptr;
+     }
+ 
+   if (lexer.peek_token ()->get_id () == ELLIPSIS) // Named variadic
+     {
+       lexer.skip_token (); // Skip ellipsis
+       return std::make_unique<AST::VariadicParam> (
+ 	AST::VariadicParam (std::move (param_pattern), std::move (outer_attrs),
+ 			    locus));
+     }
+   else
+     {
+       std::unique_ptr<AST::Type> param_type = parse_type ();
+       if (param_type == nullptr)
+ 	{
+ 	  return nullptr;
+ 	}
+       return std::make_unique<AST::FunctionParam> (
+ 	AST::FunctionParam (std::move (param_pattern), std::move (param_type),
+ 			    std::move (outer_attrs), locus));
+     }
+ }
+ 
+ /* Parses a function or method return type syntactical construction. Also
+  * handles a function return type not existing. */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::Type>
+ Parser<ManagedTokenSource>::parse_function_return_type ()
+ {
+   if (lexer.peek_token ()->get_id () != RETURN_TYPE)
+     return nullptr;
+ 
+   // skip return type, as it now obviously exists
+   lexer.skip_token ();
+ 
+   std::unique_ptr<AST::Type> type = parse_type ();
+ 
+   return type;
+ }
+ 
+ /* Parses a "where clause" (in a function, struct, method, etc.). Also handles
+  * a where clause not existing, in which it will return
+  * WhereClause::create_empty(), which can be checked via
+  * WhereClause::is_empty(). */
+ template <typename ManagedTokenSource>
+ AST::WhereClause
+ Parser<ManagedTokenSource>::parse_where_clause ()
+ {
+   const_TokenPtr where_tok = lexer.peek_token ();
+   if (where_tok->get_id () != WHERE)
+     {
+       // where clause doesn't exist, so create empty one
+       return AST::WhereClause::create_empty ();
+     }
+ 
+   lexer.skip_token ();
+ 
+   /* parse where clause items - this is not a separate rule in the reference
+    * so won't be here */
+   std::vector<std::unique_ptr<AST::WhereClauseItem>> where_clause_items;
+ 
+   std::vector<AST::LifetimeParam> for_lifetimes;
+   if (lexer.peek_token ()->get_id () == FOR)
+     for_lifetimes = parse_for_lifetimes ();
+ 
+   /* HACK: where clauses end with a right curly or semicolon or equals in all
+    * uses currently */
+   const_TokenPtr t = lexer.peek_token ();
+   while (t->get_id () != LEFT_CURLY && t->get_id () != SEMICOLON
+ 	 && t->get_id () != EQUAL)
+     {
+       std::unique_ptr<AST::WhereClauseItem> where_clause_item
+ 	= parse_where_clause_item (for_lifetimes);
+ 
+       if (where_clause_item == nullptr)
+ 	{
+ 	  Error error (t->get_locus (), "failed to parse where clause item");
+ 	  add_error (std::move (error));
+ 
+ 	  return AST::WhereClause::create_empty ();
+ 	}
+ 
+       where_clause_items.push_back (std::move (where_clause_item));
+ 
+       // also skip comma if it exists
+       if (lexer.peek_token ()->get_id () != COMMA)
+ 	break;
+ 
+       lexer.skip_token ();
+       t = lexer.peek_token ();
+     }
+ 
+   where_clause_items.shrink_to_fit ();
+   return AST::WhereClause (std::move (where_clause_items));
+ }
+ 
+ /* Parses a where clause item (lifetime or type bound). Does not parse any
+  * commas. */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::WhereClauseItem>
+ Parser<ManagedTokenSource>::parse_where_clause_item (
+   const std::vector<AST::LifetimeParam> &outer_for_lifetimes)
+ {
+   // shitty cheat way of determining lifetime or type bound - test for
+   // lifetime
+   const_TokenPtr t = lexer.peek_token ();
+ 
+   if (t->get_id () == LIFETIME)
+     return parse_lifetime_where_clause_item ();
+   else
+     return parse_type_bound_where_clause_item (outer_for_lifetimes);
+ }
+ 
+ // Parses a lifetime where clause item.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::LifetimeWhereClauseItem>
+ Parser<ManagedTokenSource>::parse_lifetime_where_clause_item ()
+ {
+   auto parsed_lifetime = parse_lifetime (false);
+   if (!parsed_lifetime)
+     {
+       // TODO: error here?
+       return nullptr;
+     }
+   auto lifetime = parsed_lifetime.value ();
+ 
+   if (!skip_token (COLON))
+     {
+       // TODO: skip after somewhere
+       return nullptr;
+     }
+ 
+   std::vector<AST::Lifetime> lifetime_bounds = parse_lifetime_bounds ();
+   // TODO: have end token passed in?
+ 
+   location_t locus = lifetime.get_locus ();
+ 
+   return std::unique_ptr<AST::LifetimeWhereClauseItem> (
+     new AST::LifetimeWhereClauseItem (std::move (lifetime),
+ 				      std::move (lifetime_bounds), locus));
+ }
+ 
+ // Parses a type bound where clause item.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::TypeBoundWhereClauseItem>
+ Parser<ManagedTokenSource>::parse_type_bound_where_clause_item (
+   const std::vector<AST::LifetimeParam> &outer_for_lifetimes)
+ {
+   std::vector<AST::LifetimeParam> for_lifetimes = outer_for_lifetimes;
+ 
+   std::unique_ptr<AST::Type> type = parse_type ();
+   if (type == nullptr)
+     {
+       return nullptr;
+     }
+ 
+   if (!skip_token (COLON))
+     {
+       // TODO: skip after somewhere
+       return nullptr;
+     }
+ 
+   if (lexer.peek_token ()->get_id () == FOR)
+     {
+       auto for_lifetimes_inner = parse_for_lifetimes ();
+       for_lifetimes.insert (for_lifetimes.end (), for_lifetimes_inner.begin (),
+ 			    for_lifetimes_inner.end ());
+     }
+ 
+   // parse type param bounds if they exist
+   std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds
+     = parse_type_param_bounds ();
+ 
+   location_t locus = lexer.peek_token ()->get_locus ();
+ 
+   return std::unique_ptr<AST::TypeBoundWhereClauseItem> (
+     new AST::TypeBoundWhereClauseItem (std::move (for_lifetimes),
+ 				       std::move (type),
+ 				       std::move (type_param_bounds), locus));
+ }
+ 
+ // Parses a for lifetimes clause, including the for keyword and angle
+ // brackets.
+ template <typename ManagedTokenSource>
+ std::vector<AST::LifetimeParam>
+ Parser<ManagedTokenSource>::parse_for_lifetimes ()
+ {
+   std::vector<AST::LifetimeParam> params;
+ 
+   if (!skip_token (FOR))
+     {
+       // skip after somewhere?
+       return params;
+     }
+ 
+   if (!skip_token (LEFT_ANGLE))
+     {
+       // skip after somewhere?
+       return params;
+     }
+ 
+   /* cannot specify end token due to parsing problems with '>' tokens being
+    * nested */
+   params = parse_lifetime_params_objs (Parse::Utils::is_right_angle_tok);
+ 
+   if (!skip_generics_right_angle ())
+     {
+       // DEBUG
+       rust_debug ("failed to skip generics right angle after (supposedly) "
+ 		  "finished parsing where clause items");
+       // ok, well this gets called.
+ 
+       // skip after somewhere?
+       return params;
+     }
+ 
+   return params;
+ }
+ 
+ // Parses type parameter bounds in where clause or generic arguments.
+ template <typename ManagedTokenSource>
+ std::vector<std::unique_ptr<AST::TypeParamBound>>
+ Parser<ManagedTokenSource>::parse_type_param_bounds ()
+ {
+   std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
+ 
+   std::unique_ptr<AST::TypeParamBound> initial_bound
+     = parse_type_param_bound ();
+ 
+   // quick exit if null
+   if (initial_bound == nullptr)
+     {
+       /* error? type param bounds must have at least one term, but are bounds
+        * optional? */
+       return type_param_bounds;
+     }
+   type_param_bounds.push_back (std::move (initial_bound));
+ 
+   while (lexer.peek_token ()->get_id () == PLUS)
+     {
+       lexer.skip_token ();
+ 
+       std::unique_ptr<AST::TypeParamBound> bound = parse_type_param_bound ();
+       if (bound == nullptr)
+ 	{
+ 	  /* not an error: bound is allowed to be null as trailing plus is
+ 	   * allowed */
+ 	  return type_param_bounds;
+ 	}
+ 
+       type_param_bounds.push_back (std::move (bound));
+     }
+ 
+   type_param_bounds.shrink_to_fit ();
+   return type_param_bounds;
+ }
+ 
+ /* Parses type parameter bounds in where clause or generic arguments, with end
+  * token handling. */
+ template <typename ManagedTokenSource>
+ template <typename EndTokenPred>
+ std::vector<std::unique_ptr<AST::TypeParamBound>>
+ Parser<ManagedTokenSource>::parse_type_param_bounds (EndTokenPred is_end_token)
+ {
+   std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
+ 
+   std::unique_ptr<AST::TypeParamBound> initial_bound
+     = parse_type_param_bound ();
+ 
+   // quick exit if null
+   if (initial_bound == nullptr)
+     {
+       /* error? type param bounds must have at least one term, but are bounds
+        * optional? */
+       return type_param_bounds;
+     }
+   type_param_bounds.push_back (std::move (initial_bound));
+ 
+   while (lexer.peek_token ()->get_id () == PLUS)
+     {
+       lexer.skip_token ();
+ 
+       // break if end token character
+       if (is_end_token (lexer.peek_token ()->get_id ()))
+ 	break;
+ 
+       std::unique_ptr<AST::TypeParamBound> bound = parse_type_param_bound ();
+       if (bound == nullptr)
+ 	{
+ 	  // TODO how wise is it to ditch all bounds if only one failed?
+ 	  Error error (lexer.peek_token ()->get_locus (),
+ 		       "failed to parse type param bound in type param bounds");
+ 	  add_error (std::move (error));
+ 
+ 	  return {};
+ 	}
+ 
+       type_param_bounds.push_back (std::move (bound));
+     }
+ 
+   type_param_bounds.shrink_to_fit ();
+   return type_param_bounds;
+ }
+ 
+ /* Parses a single type parameter bound in a where clause or generic argument.
+  * Does not parse the '+' between arguments. */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::TypeParamBound>
+ Parser<ManagedTokenSource>::parse_type_param_bound ()
+ {
+   // shitty cheat way of determining lifetime or trait bound - test for
+   // lifetime
+   const_TokenPtr t = lexer.peek_token ();
+   switch (t->get_id ())
+     {
+     case LIFETIME:
+       return std::unique_ptr<AST::Lifetime> (
+ 	new AST::Lifetime (parse_lifetime (false).value ()));
+     case LEFT_PAREN:
+     case QUESTION_MARK:
+     case FOR:
+     case IDENTIFIER:
+     case SUPER:
+     case SELF:
+     case SELF_ALIAS:
+     case CRATE:
+     case DOLLAR_SIGN:
+     case SCOPE_RESOLUTION:
+       return parse_trait_bound ();
+     default:
+       // don't error - assume this is fine TODO
+       return nullptr;
+     }
+ }
+ 
+ // Parses a trait bound type param bound.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::TraitBound>
+ Parser<ManagedTokenSource>::parse_trait_bound ()
+ {
+   bool has_parens = false;
+   bool has_question_mark = false;
+ 
+   location_t locus = lexer.peek_token ()->get_locus ();
+ 
+   /* parse optional `for lifetimes`. */
+   std::vector<AST::LifetimeParam> for_lifetimes;
+   if (lexer.peek_token ()->get_id () == FOR)
+     for_lifetimes = parse_for_lifetimes ();
+ 
+   // handle trait bound being in parentheses
+   if (lexer.peek_token ()->get_id () == LEFT_PAREN)
+     {
+       has_parens = true;
+       lexer.skip_token ();
+     }
+ 
+   // handle having question mark (optional)
+   if (lexer.peek_token ()->get_id () == QUESTION_MARK)
+     {
+       has_question_mark = true;
+       lexer.skip_token ();
+     }
+ 
+   // handle TypePath
+   AST::TypePath type_path = parse_type_path ();
+ 
+   // handle closing parentheses
+   if (has_parens)
+     {
+       if (!skip_token (RIGHT_PAREN))
+ 	{
+ 	  return nullptr;
+ 	}
+     }
+ 
+   return std::unique_ptr<AST::TraitBound> (
+     new AST::TraitBound (std::move (type_path), locus, has_parens,
+ 			 has_question_mark, std::move (for_lifetimes)));
+ }
+ 
+ // Parses lifetime bounds.
+ template <typename ManagedTokenSource>
+ std::vector<AST::Lifetime>
+ Parser<ManagedTokenSource>::parse_lifetime_bounds ()
+ {
+   std::vector<AST::Lifetime> lifetime_bounds;
+ 
+   while (true)
+     {
+       auto lifetime = parse_lifetime (false);
+ 
+       // quick exit for parsing failure
+       if (!lifetime)
+ 	break;
+ 
+       lifetime_bounds.push_back (std::move (lifetime.value ()));
+ 
+       /* plus is maybe not allowed at end - spec defines it weirdly, so
+        * assuming allowed at end */
+       if (lexer.peek_token ()->get_id () != PLUS)
+ 	break;
+ 
+       lexer.skip_token ();
+     }
+ 
+   lifetime_bounds.shrink_to_fit ();
+   return lifetime_bounds;
+ }
+ 
+ // Parses lifetime bounds, with added check for ending token.
+ template <typename ManagedTokenSource>
+ template <typename EndTokenPred>
+ std::vector<AST::Lifetime>
+ Parser<ManagedTokenSource>::parse_lifetime_bounds (EndTokenPred is_end_token)
+ {
+   std::vector<AST::Lifetime> lifetime_bounds;
+ 
+   while (!is_end_token (lexer.peek_token ()->get_id ()))
+     {
+       auto lifetime = parse_lifetime (false);
+ 
+       if (!lifetime)
+ 	{
+ 	  /* TODO: is it worth throwing away all lifetime bound info just
+ 	   * because one failed? */
+ 	  Error error (lexer.peek_token ()->get_locus (),
+ 		       "failed to parse lifetime in lifetime bounds");
+ 	  add_error (std::move (error));
+ 
+ 	  return {};
+ 	}
+ 
+       lifetime_bounds.push_back (std::move (lifetime.value ()));
+ 
+       /* plus is maybe not allowed at end - spec defines it weirdly, so
+        * assuming allowed at end */
+       if (lexer.peek_token ()->get_id () != PLUS)
+ 	break;
+ 
+       lexer.skip_token ();
+     }
+ 
+   lifetime_bounds.shrink_to_fit ();
+   return lifetime_bounds;
+ }
+ 
+ /* Parses a lifetime token (named, 'static, or '_). Also handles lifetime not
+  * existing. */
+ template <typename ManagedTokenSource>
+ tl::expected<AST::Lifetime, ParseLifetimeError>
+ Parser<ManagedTokenSource>::parse_lifetime (bool allow_elided)
+ {
+   const_TokenPtr lifetime_tok = lexer.peek_token ();
+   if (lifetime_tok->get_id () != LIFETIME)
+     {
+       if (allow_elided)
+ 	{
+ 	  return AST::Lifetime::elided ();
+ 	}
+       else
+ 	{
+ 	  return tl::make_unexpected<ParseLifetimeError> ({});
+ 	}
+     }
+   lexer.skip_token ();
+ 
+   return lifetime_from_token (lifetime_tok);
+ }
+ 
+ template <typename ManagedTokenSource>
+ AST::Lifetime
+ Parser<ManagedTokenSource>::lifetime_from_token (const_TokenPtr tok)
+ {
+   location_t locus = tok->get_locus ();
+   std::string lifetime_ident = tok->get_str ();
+ 
+   if (lifetime_ident == "static")
+     {
+       return AST::Lifetime (AST::Lifetime::STATIC, "", locus);
+     }
+   else if (lifetime_ident == "_")
+     {
+       // Explicitly and implicitly elided lifetimes follow the same rules.
+       return AST::Lifetime (AST::Lifetime::WILDCARD, "", locus);
+     }
+   else
+     {
+       return AST::Lifetime (AST::Lifetime::NAMED, std::move (lifetime_ident),
+ 			    locus);
+     }
+ }
+ 
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::ExternalTypeItem>
+ Parser<ManagedTokenSource>::parse_external_type_item (AST::Visibility vis,
+ 						      AST::AttrVec outer_attrs)
+ {
+   location_t locus = lexer.peek_token ()->get_locus ();
+   skip_token (TYPE);
+ 
+   const_TokenPtr alias_name_tok = expect_token (IDENTIFIER);
+   if (alias_name_tok == nullptr)
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "could not parse identifier in external opaque type");
+       add_error (std::move (error));
+ 
+       skip_after_semicolon ();
+       return nullptr;
+     }
+ 
+   if (!skip_token (SEMICOLON))
+     return nullptr;
+ 
+   return std::unique_ptr<AST::ExternalTypeItem> (
+     new AST::ExternalTypeItem (alias_name_tok->get_str (), std::move (vis),
+ 			       std::move (outer_attrs), std::move (locus)));
+ }
+ 
+ // Parses a "type alias" (typedef) item.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::TypeAlias>
+ Parser<ManagedTokenSource>::parse_type_alias (AST::Visibility vis,
+ 					      AST::AttrVec outer_attrs)
+ {
+   location_t locus = lexer.peek_token ()->get_locus ();
+   skip_token (TYPE);
+ 
+   // TODO: use this token for identifier when finished that
+   const_TokenPtr alias_name_tok = expect_token (IDENTIFIER);
+   if (alias_name_tok == nullptr)
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "could not parse identifier in type alias");
+       add_error (std::move (error));
+ 
+       skip_after_semicolon ();
+       return nullptr;
+     }
+   Identifier alias_name{alias_name_tok};
+ 
+   // parse generic params, which may not exist
+   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
+     = parse_generic_params_in_angles ();
+ 
+   // parse where clause, which may not exist
+   AST::WhereClause where_clause = parse_where_clause ();
+ 
+   if (!skip_token (EQUAL))
+     {
+       skip_after_semicolon ();
+       return nullptr;
+     }
+ 
+   std::unique_ptr<AST::Type> type_to_alias = parse_type ();
+ 
+   if (!skip_token (SEMICOLON))
+     {
+       // should be skipping past this, not the next line
+       return nullptr;
+     }
+ 
+   return std::unique_ptr<AST::TypeAlias> (
+     new AST::TypeAlias (std::move (alias_name), std::move (generic_params),
+ 			std::move (where_clause), std::move (type_to_alias),
+ 			std::move (vis), std::move (outer_attrs), locus));
+ }
+ 
+ // Parse a struct item AST node.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::Struct>
+ Parser<ManagedTokenSource>::parse_struct (AST::Visibility vis,
+ 					  AST::AttrVec outer_attrs)
+ {
+   /* TODO: determine best way to parse the proper struct vs tuple struct -
+    * share most of initial constructs so lookahead might be impossible, and if
+    * not probably too expensive. Best way is probably unified parsing for the
+    * initial parts and then pass them in as params to more derived functions.
+    * Alternatively, just parse everything in this one function - do this if
+    * function not too long. */
+ 
+   /* Proper struct <- 'struct' IDENTIFIER generic_params? where_clause? ( '{'
+    * struct_fields? '}' | ';' ) */
+   /* Tuple struct <- 'struct' IDENTIFIER generic_params? '(' tuple_fields? ')'
+    * where_clause? ';' */
+   location_t locus = lexer.peek_token ()->get_locus ();
+   skip_token (STRUCT_KW);
+ 
+   // parse struct name
+   const_TokenPtr name_tok = expect_token (IDENTIFIER);
+   if (name_tok == nullptr)
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "could not parse struct or tuple struct identifier");
+       add_error (std::move (error));
+ 
+       // skip after somewhere?
+       return nullptr;
+     }
+   Identifier struct_name{name_tok};
+ 
+   // parse generic params, which may or may not exist
+   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
+     = parse_generic_params_in_angles ();
+ 
+   // branch on next token - determines whether proper struct or tuple struct
+   if (lexer.peek_token ()->get_id () == LEFT_PAREN)
+     {
+       // tuple struct
+ 
+       // skip left parenthesis
+       lexer.skip_token ();
+ 
+       // parse tuple fields
+       std::vector<AST::TupleField> tuple_fields;
+       // Might be empty tuple for unit tuple struct.
+       if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
+ 	tuple_fields = std::vector<AST::TupleField> ();
+       else
+ 	tuple_fields = parse_tuple_fields ();
+ 
+       // tuple parameters must have closing parenthesis
+       if (!skip_token (RIGHT_PAREN))
+ 	{
+ 	  skip_after_semicolon ();
+ 	  return nullptr;
+ 	}
+ 
+       // parse where clause, which is optional
+       AST::WhereClause where_clause = parse_where_clause ();
+ 
+       if (!skip_token (SEMICOLON))
+ 	{
+ 	  // can't skip after semicolon because it's meant to be here
+ 	  return nullptr;
+ 	}
+ 
+       return std::unique_ptr<AST::TupleStruct> (
+ 	new AST::TupleStruct (std::move (tuple_fields), std::move (struct_name),
+ 			      std::move (generic_params),
+ 			      std::move (where_clause), std::move (vis),
+ 			      std::move (outer_attrs), locus));
+     }
+ 
+   // assume it is a proper struct being parsed and continue outside of switch
+   // - label only here to suppress warning
+ 
+   // parse where clause, which is optional
+   AST::WhereClause where_clause = parse_where_clause ();
+ 
+   // branch on next token - determines whether struct is a unit struct
+   const_TokenPtr t = lexer.peek_token ();
+   switch (t->get_id ())
+     {
+     case LEFT_CURLY:
+       {
+ 	// struct with body
+ 
+ 	// skip curly bracket
+ 	lexer.skip_token ();
+ 
+ 	// parse struct fields, if any
+ 	std::vector<AST::StructField> struct_fields
+ 	  = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
+ 
+ 	if (!skip_token (RIGHT_CURLY))
+ 	  {
+ 	    // skip somewhere?
+ 	    return nullptr;
+ 	  }
+ 
+ 	return std::unique_ptr<AST::StructStruct> (new AST::StructStruct (
+ 	  std::move (struct_fields), std::move (struct_name),
+ 	  std::move (generic_params), std::move (where_clause), false,
+ 	  std::move (vis), std::move (outer_attrs), locus));
+       }
+     case SEMICOLON:
+       // unit struct declaration
+ 
+       lexer.skip_token ();
+ 
+       return std::unique_ptr<AST::StructStruct> (
+ 	new AST::StructStruct (std::move (struct_name),
+ 			       std::move (generic_params),
+ 			       std::move (where_clause), std::move (vis),
+ 			       std::move (outer_attrs), locus));
+     default:
+       add_error (Error (t->get_locus (),
+ 			"unexpected token %qs in struct declaration",
+ 			t->get_token_description ()));
+ 
+       // skip somewhere?
+       return nullptr;
+     }
+ }
+ 
+ // Parses struct fields in struct declarations.
+ template <typename ManagedTokenSource>
+ std::vector<AST::StructField>
+ Parser<ManagedTokenSource>::parse_struct_fields ()
+ {
+   std::vector<AST::StructField> fields;
+ 
+   AST::StructField initial_field = parse_struct_field ();
+ 
+   // Return empty field list if no field there
+   if (initial_field.is_error ())
+     return fields;
+ 
+   fields.push_back (std::move (initial_field));
+ 
+   while (lexer.peek_token ()->get_id () == COMMA)
+     {
+       lexer.skip_token ();
+ 
+       AST::StructField field = parse_struct_field ();
+ 
+       if (field.is_error ())
+ 	{
+ 	  // would occur with trailing comma, so allowed
+ 	  break;
+ 	}
+ 
+       fields.push_back (std::move (field));
+     }
+ 
+   fields.shrink_to_fit ();
+   return fields;
+   // TODO: template if possible (parse_non_ptr_seq)
+ }
+ 
+ // Parses struct fields in struct declarations.
+ template <typename ManagedTokenSource>
+ template <typename EndTokenPred>
+ std::vector<AST::StructField>
+ Parser<ManagedTokenSource>::parse_struct_fields (EndTokenPred is_end_tok)
+ {
+   std::vector<AST::StructField> fields;
+ 
+   AST::StructField initial_field = parse_struct_field ();
+ 
+   // Return empty field list if no field there
+   if (initial_field.is_error ())
+     return fields;
+ 
+   fields.push_back (std::move (initial_field));
+ 
+   while (lexer.peek_token ()->get_id () == COMMA)
+     {
+       lexer.skip_token ();
+ 
+       if (is_end_tok (lexer.peek_token ()->get_id ()))
+ 	break;
+ 
+       AST::StructField field = parse_struct_field ();
+       if (field.is_error ())
+ 	{
+ 	  /* TODO: should every field be ditched just because one couldn't be
+ 	   * parsed? */
+ 	  Error error (lexer.peek_token ()->get_locus (),
+ 		       "failed to parse struct field in struct fields");
+ 	  add_error (std::move (error));
+ 
+ 	  return {};
+ 	}
+ 
+       fields.push_back (std::move (field));
+     }
+ 
+   fields.shrink_to_fit ();
+   return fields;
+   // TODO: template if possible (parse_non_ptr_seq)
+ }
+ 
+ // Parses a single struct field (in a struct definition). Does not parse
+ // commas.
+ template <typename ManagedTokenSource>
+ AST::StructField
+ Parser<ManagedTokenSource>::parse_struct_field ()
+ {
+   // parse outer attributes, if they exist
+   AST::AttrVec outer_attrs = parse_outer_attributes ();
+ 
+   // parse visibility, if it exists
+   auto vis = parse_visibility ();
+   if (!vis)
+     return AST::StructField::create_error ();
+ 
+   location_t locus = lexer.peek_token ()->get_locus ();
+ 
+   // parse field name
+   const_TokenPtr field_name_tok = lexer.peek_token ();
+   if (field_name_tok->get_id () != IDENTIFIER)
+     {
+       // if not identifier, assumes there is no struct field and exits - not
+       // necessarily error
+       return AST::StructField::create_error ();
+     }
+   Identifier field_name{field_name_tok};
+   lexer.skip_token ();
+ 
+   if (!skip_token (COLON))
+     {
+       // skip after somewhere?
+       return AST::StructField::create_error ();
+     }
+ 
+   // parse field type - this is required
+   std::unique_ptr<AST::Type> field_type = parse_type ();
+   if (field_type == nullptr)
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "could not parse type in struct field definition");
+       add_error (std::move (error));
+ 
+       // skip after somewhere
+       return AST::StructField::create_error ();
+     }
+ 
+   return AST::StructField (std::move (field_name), std::move (field_type),
+ 			   std::move (vis.value ()), locus,
+ 			   std::move (outer_attrs));
+ }
+ 
+ // Parses tuple fields in tuple/tuple struct declarations.
+ template <typename ManagedTokenSource>
+ std::vector<AST::TupleField>
+ Parser<ManagedTokenSource>::parse_tuple_fields ()
+ {
+   std::vector<AST::TupleField> fields;
+ 
+   AST::TupleField initial_field = parse_tuple_field ();
+ 
+   // Return empty field list if no field there
+   if (initial_field.is_error ())
+     {
+       return fields;
+     }
+ 
+   fields.push_back (std::move (initial_field));
+ 
+   // maybe think of a better control structure here - do-while with an initial
+   // error state? basically, loop through field list until can't find any more
+   // params HACK: all current syntax uses of tuple fields have them ending
+   // with a right paren token
+   const_TokenPtr t = lexer.peek_token ();
+   while (t->get_id () == COMMA)
+     {
+       // skip comma if applies - e.g. trailing comma
+       lexer.skip_token ();
+ 
+       // break out due to right paren if it exists
+       if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
+ 	{
+ 	  break;
+ 	}
+ 
+       AST::TupleField field = parse_tuple_field ();
+       if (field.is_error ())
+ 	{
+ 	  Error error (lexer.peek_token ()->get_locus (),
+ 		       "failed to parse tuple field in tuple fields");
+ 	  add_error (std::move (error));
+ 
+ 	  return std::vector<AST::TupleField> ();
+ 	}
+ 
+       fields.push_back (std::move (field));
+ 
+       t = lexer.peek_token ();
+     }
+ 
+   fields.shrink_to_fit ();
+   return fields;
+ 
+   // TODO: this shares basically all code with function params and struct
+   // fields
+   // - templates?
+ }
+ 
+ /* Parses a single tuple struct field in a tuple struct definition. Does not
+  * parse commas. */
+ template <typename ManagedTokenSource>
+ AST::TupleField
+ Parser<ManagedTokenSource>::parse_tuple_field ()
+ {
+   // parse outer attributes if they exist
+   AST::AttrVec outer_attrs = parse_outer_attributes ();
+ 
+   // parse visibility if it exists
+   auto visibility = parse_visibility ();
+   if (!visibility)
+     return AST::TupleField::create_error ();
+ 
+   location_t locus = lexer.peek_token ()->get_locus ();
+ 
+   // parse type, which is required
+   std::unique_ptr<AST::Type> field_type = parse_type ();
+   if (field_type == nullptr)
+     {
+       // error if null
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "could not parse type in tuple struct field");
+       add_error (std::move (error));
+ 
+       // skip after something
+       return AST::TupleField::create_error ();
+     }
+ 
+   return AST::TupleField (std::move (field_type),
+ 			  std::move (visibility.value ()), locus,
+ 			  std::move (outer_attrs));
+ }
+ 
+ // Parses a Rust "enum" tagged union item definition.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::Enum>
+ Parser<ManagedTokenSource>::parse_enum (AST::Visibility vis,
+ 					AST::AttrVec outer_attrs)
+ {
+   location_t locus = lexer.peek_token ()->get_locus ();
+   skip_token (ENUM_KW);
+ 
+   // parse enum name
+   const_TokenPtr enum_name_tok = expect_token (IDENTIFIER);
+   if (enum_name_tok == nullptr)
+     return nullptr;
+ 
+   Identifier enum_name = {enum_name_tok};
+ 
+   // parse generic params (of enum container, not enum variants) if they exist
+   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
+     = parse_generic_params_in_angles ();
+ 
+   // parse where clause if it exists
+   AST::WhereClause where_clause = parse_where_clause ();
+ 
+   if (!skip_token (LEFT_CURLY))
+     {
+       skip_after_end_block ();
+       return nullptr;
+     }
+ 
+   // parse actual enum variant definitions
+   std::vector<std::unique_ptr<AST::EnumItem>> enum_items
+     = parse_enum_items ([] (TokenId id) { return id == RIGHT_CURLY; });
+ 
+   if (!skip_token (RIGHT_CURLY))
+     {
+       skip_after_end_block ();
+       return nullptr;
+     }
+ 
+   return std::unique_ptr<AST::Enum> (
+     new AST::Enum (std::move (enum_name), std::move (vis),
+ 		   std::move (generic_params), std::move (where_clause),
+ 		   std::move (enum_items), std::move (outer_attrs), locus));
+ }
+ 
+ // Parses the enum variants inside an enum definiton.
+ template <typename ManagedTokenSource>
+ std::vector<std::unique_ptr<AST::EnumItem>>
+ Parser<ManagedTokenSource>::parse_enum_items ()
+ {
+   std::vector<std::unique_ptr<AST::EnumItem>> items;
+ 
+   std::unique_ptr<AST::EnumItem> initial_item = parse_enum_item ();
+ 
+   // Return empty item list if no field there
+   if (initial_item == nullptr)
+     return items;
+ 
+   items.push_back (std::move (initial_item));
+ 
+   while (lexer.peek_token ()->get_id () == COMMA)
+     {
+       lexer.skip_token ();
+ 
+       std::unique_ptr<AST::EnumItem> item = parse_enum_item ();
+       if (item == nullptr)
+ 	{
+ 	  // this would occur with a trailing comma, which is allowed
+ 	  break;
+ 	}
+ 
+       items.push_back (std::move (item));
+     }
+ 
+   items.shrink_to_fit ();
+   return items;
+ 
+   /* TODO: use template if doable (parse_non_ptr_sequence) */
+ }
+ 
+ // Parses the enum variants inside an enum definiton.
+ template <typename ManagedTokenSource>
+ template <typename EndTokenPred>
+ std::vector<std::unique_ptr<AST::EnumItem>>
+ Parser<ManagedTokenSource>::parse_enum_items (EndTokenPred is_end_tok)
+ {
+   std::vector<std::unique_ptr<AST::EnumItem>> items;
+ 
+   std::unique_ptr<AST::EnumItem> initial_item = parse_enum_item ();
+ 
+   // Return empty item list if no field there
+   if (initial_item == nullptr)
+     return items;
+ 
+   items.push_back (std::move (initial_item));
+ 
+   while (lexer.peek_token ()->get_id () == COMMA)
+     {
+       lexer.skip_token ();
+ 
+       if (is_end_tok (lexer.peek_token ()->get_id ()))
+ 	break;
+ 
+       std::unique_ptr<AST::EnumItem> item = parse_enum_item ();
+       if (item == nullptr)
+ 	{
+ 	  /* TODO should this ignore all successfully parsed enum items just
+ 	   * because one failed? */
+ 	  Error error (lexer.peek_token ()->get_locus (),
+ 		       "failed to parse enum item in enum items");
+ 	  add_error (std::move (error));
+ 
+ 	  return {};
+ 	}
+ 
+       items.push_back (std::move (item));
+     }
+ 
+   items.shrink_to_fit ();
+   return items;
+ 
+   /* TODO: use template if doable (parse_non_ptr_sequence) */
+ }
+ 
+ /* Parses a single enum variant item in an enum definition. Does not parse
+  * commas. */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::EnumItem>
+ Parser<ManagedTokenSource>::parse_enum_item ()
+ {
+   // parse outer attributes if they exist
+   AST::AttrVec outer_attrs = parse_outer_attributes ();
+ 
+   // parse visibility, which may or may not exist
+   auto vis_res = parse_visibility ();
+   if (!vis_res)
+     return nullptr;
+   auto vis = vis_res.value ();
+ 
+   // parse name for enum item, which is required
+   const_TokenPtr item_name_tok = lexer.peek_token ();
+   if (item_name_tok->get_id () != IDENTIFIER)
+     {
+       // this may not be an error but it means there is no enum item here
+       return nullptr;
+     }
+   lexer.skip_token ();
+   Identifier item_name{item_name_tok};
+ 
+   // branch based on next token
+   const_TokenPtr t = lexer.peek_token ();
+   switch (t->get_id ())
+     {
+     case LEFT_PAREN:
+       {
+ 	// tuple enum item
+ 	lexer.skip_token ();
+ 
+ 	std::vector<AST::TupleField> tuple_fields;
+ 	// Might be empty tuple for unit tuple enum variant.
+ 	if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
+ 	  tuple_fields = std::vector<AST::TupleField> ();
+ 	else
+ 	  tuple_fields = parse_tuple_fields ();
+ 
+ 	if (!skip_token (RIGHT_PAREN))
+ 	  {
+ 	    // skip after somewhere
+ 	    return nullptr;
+ 	  }
+ 
+ 	return std::unique_ptr<AST::EnumItemTuple> (new AST::EnumItemTuple (
+ 	  std::move (item_name), std::move (vis), std::move (tuple_fields),
+ 	  std::move (outer_attrs), item_name_tok->get_locus ()));
+       }
+     case LEFT_CURLY:
+       {
+ 	// struct enum item
+ 	lexer.skip_token ();
+ 
+ 	std::vector<AST::StructField> struct_fields
+ 	  = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
+ 
+ 	if (!skip_token (RIGHT_CURLY))
+ 	  {
+ 	    // skip after somewhere
+ 	    return nullptr;
+ 	  }
+ 
+ 	return std::unique_ptr<AST::EnumItemStruct> (new AST::EnumItemStruct (
+ 	  std::move (item_name), std::move (vis), std::move (struct_fields),
+ 	  std::move (outer_attrs), item_name_tok->get_locus ()));
+       }
+     case EQUAL:
+       {
+ 	// discriminant enum item
+ 	lexer.skip_token ();
+ 
+ 	std::unique_ptr<AST::Expr> discriminant_expr = parse_expr ();
+ 
+ 	return std::unique_ptr<AST::EnumItemDiscriminant> (
+ 	  new AST::EnumItemDiscriminant (std::move (item_name), std::move (vis),
+ 					 std::move (discriminant_expr),
+ 					 std::move (outer_attrs),
+ 					 item_name_tok->get_locus ()));
+       }
+     default:
+       // regular enum with just an identifier
+       return std::unique_ptr<AST::EnumItem> (
+ 	new AST::EnumItem (std::move (item_name), std::move (vis),
+ 			   std::move (outer_attrs),
+ 			   item_name_tok->get_locus ()));
+     }
+ }
+ 
+ // Parses a C-style (and C-compat) untagged union declaration.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::Union>
+ Parser<ManagedTokenSource>::parse_union (AST::Visibility vis,
+ 					 AST::AttrVec outer_attrs)
+ {
+   /* hack - "weak keyword" by finding identifier called "union" (lookahead in
+    * item switch) */
+   const_TokenPtr union_keyword = expect_token (IDENTIFIER);
+   rust_assert (union_keyword->get_str () == Values::WeakKeywords::UNION);
+   location_t locus = union_keyword->get_locus ();
+ 
+   // parse actual union name
+   const_TokenPtr union_name_tok = expect_token (IDENTIFIER);
+   if (union_name_tok == nullptr)
+     {
+       skip_after_next_block ();
+       return nullptr;
+     }
+   Identifier union_name{union_name_tok};
+ 
+   // parse optional generic parameters
+   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
+     = parse_generic_params_in_angles ();
+ 
+   // parse optional where clause
+   AST::WhereClause where_clause = parse_where_clause ();
+ 
+   if (!skip_token (LEFT_CURLY))
+     {
+       skip_after_end_block ();
+       return nullptr;
+     }
+ 
+   /* parse union inner items as "struct fields" because hey, syntax reuse.
+    * Spec said so. */
+   std::vector<AST::StructField> union_fields
+     = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
+ 
+   if (!skip_token (RIGHT_CURLY))
+     {
+       // skip after somewhere
+       return nullptr;
+     }
+ 
+   return std::unique_ptr<AST::Union> (
+     new AST::Union (std::move (union_name), std::move (vis),
+ 		    std::move (generic_params), std::move (where_clause),
+ 		    std::move (union_fields), std::move (outer_attrs), locus));
+ }
+ 
+ /* Parses a "constant item" (compile-time constant to maybe "inline"
+  * throughout the program - like constexpr). */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::ConstantItem>
+ Parser<ManagedTokenSource>::parse_const_item (AST::Visibility vis,
+ 					      AST::AttrVec outer_attrs)
+ {
+   location_t locus = lexer.peek_token ()->get_locus ();
+   skip_token (CONST);
+ 
+   /* get constant identifier - this is either a proper identifier or the _
+    * wildcard */
+   const_TokenPtr ident_tok = lexer.peek_token ();
+   // make default identifier the underscore wildcard one
+   std::string ident (Values::Keywords::UNDERSCORE);
+   switch (ident_tok->get_id ())
+     {
+     case IDENTIFIER:
+       ident = ident_tok->get_str ();
+       lexer.skip_token ();
+       break;
+     case UNDERSCORE:
+       // do nothing - identifier is already "_"
+       lexer.skip_token ();
+       break;
+     default:
+       add_error (
+ 	Error (ident_tok->get_locus (),
+ 	       "expected item name (identifier or %<_%>) in constant item "
+ 	       "declaration - found %qs",
+ 	       ident_tok->get_token_description ()));
+ 
+       skip_after_semicolon ();
+       return nullptr;
+     }
+ 
+   if (!skip_token (COLON))
+     {
+       skip_after_semicolon ();
+       return nullptr;
+     }
+ 
+   // parse constant type (required)
+   std::unique_ptr<AST::Type> type = parse_type ();
+ 
+   // A const with no given expression value
+   if (lexer.peek_token ()->get_id () == SEMICOLON)
+     {
+       lexer.skip_token ();
+       return std::unique_ptr<AST::ConstantItem> (
+ 	new AST::ConstantItem (std::move (ident), std::move (vis),
+ 			       std::move (type), std::move (outer_attrs),
+ 			       locus));
+     }
+ 
+   if (!skip_token (EQUAL))
+     {
+       skip_after_semicolon ();
+       return nullptr;
+     }
+ 
+   // parse constant expression (required)
+   std::unique_ptr<AST::Expr> expr = parse_expr ();
+ 
+   if (!skip_token (SEMICOLON))
+     {
+       // skip somewhere?
+       return nullptr;
+     }
+ 
+   return std::unique_ptr<AST::ConstantItem> (
+     new AST::ConstantItem (std::move (ident), std::move (vis), std::move (type),
+ 			   std::move (expr), std::move (outer_attrs), locus));
+ }
+ 
+ // Parses a "static item" (static storage item, with 'static lifetime).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::StaticItem>
+ Parser<ManagedTokenSource>::parse_static_item (AST::Visibility vis,
+ 					       AST::AttrVec outer_attrs)
+ {
+   location_t locus = lexer.peek_token ()->get_locus ();
+   skip_token (STATIC_KW);
+ 
+   // determine whether static item is mutable
+   bool is_mut = false;
+   if (lexer.peek_token ()->get_id () == MUT)
+     {
+       is_mut = true;
+       lexer.skip_token ();
+     }
+ 
+   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
+   if (ident_tok == nullptr)
+     return nullptr;
+ 
+   Identifier ident{ident_tok};
+ 
+   if (!skip_token (COLON))
+     {
+       skip_after_semicolon ();
+       return nullptr;
+     }
+ 
+   // parse static item type (required)
+   std::unique_ptr<AST::Type> type = parse_type ();
+ 
+   if (!skip_token (EQUAL))
+     {
+       skip_after_semicolon ();
+       return nullptr;
+     }
+ 
+   // parse static item expression (required)
+   std::unique_ptr<AST::Expr> expr = parse_expr ();
+ 
+   if (!skip_token (SEMICOLON))
+     {
+       // skip after somewhere
+       return nullptr;
+     }
+ 
+   return std::unique_ptr<AST::StaticItem> (
+     new AST::StaticItem (std::move (ident), is_mut, std::move (type),
+ 			 std::move (expr), std::move (vis),
+ 			 std::move (outer_attrs), locus));
+ }
+ 
+ // Parses a trait definition item, including unsafe ones.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::Trait>
+ Parser<ManagedTokenSource>::parse_trait (AST::Visibility vis,
+ 					 AST::AttrVec outer_attrs)
+ {
+   location_t locus = lexer.peek_token ()->get_locus ();
+   bool is_unsafe = false;
+   bool is_auto_trait = false;
+ 
+   if (lexer.peek_token ()->get_id () == UNSAFE)
+     {
+       is_unsafe = true;
+       lexer.skip_token ();
+     }
+ 
+   if (lexer.peek_token ()->get_id () == AUTO)
+     {
+       is_auto_trait = true;
+       lexer.skip_token ();
+     }
+ 
+   skip_token (TRAIT);
+ 
+   // parse trait name
+   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
+   if (ident_tok == nullptr)
+     return nullptr;
+ 
+   Identifier ident{ident_tok};
+ 
+   // parse generic parameters (if they exist)
+   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
+     = parse_generic_params_in_angles ();
+ 
+   // create placeholder type param bounds in case they don't exist
+   std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
+ 
+   // parse type param bounds (if they exist)
+   if (lexer.peek_token ()->get_id () == COLON)
+     {
+       lexer.skip_token ();
+ 
+       type_param_bounds = parse_type_param_bounds (
+ 	[] (TokenId id) { return id == WHERE || id == LEFT_CURLY; });
+       // type_param_bounds = parse_type_param_bounds ();
+     }
+ 
+   // parse where clause (if it exists)
+   AST::WhereClause where_clause = parse_where_clause ();
+ 
+   if (!skip_token (LEFT_CURLY))
+     {
+       skip_after_end_block ();
+       return nullptr;
+     }
+ 
+   // parse inner attrs (if they exist)
+   AST::AttrVec inner_attrs = parse_inner_attributes ();
+ 
+   // parse trait items
+   std::vector<std::unique_ptr<AST::AssociatedItem>> trait_items;
+ 
+   const_TokenPtr t = lexer.peek_token ();
+   while (t->get_id () != RIGHT_CURLY)
+     {
+       std::unique_ptr<AST::AssociatedItem> trait_item = parse_trait_item ();
+ 
+       if (trait_item == nullptr)
+ 	{
+ 	  Error error (lexer.peek_token ()->get_locus (),
+ 		       "failed to parse trait item in trait");
+ 	  add_error (std::move (error));
+ 
+ 	  return nullptr;
+ 	}
+       trait_items.push_back (std::move (trait_item));
+ 
+       t = lexer.peek_token ();
+     }
+ 
+   if (!skip_token (RIGHT_CURLY))
+     {
+       // skip after something
+       return nullptr;
+     }
+ 
+   trait_items.shrink_to_fit ();
+   return std::unique_ptr<AST::Trait> (
+     new AST::Trait (std::move (ident), is_unsafe, is_auto_trait,
+ 		    std::move (generic_params), std::move (type_param_bounds),
+ 		    std::move (where_clause), std::move (trait_items),
+ 		    std::move (vis), std::move (outer_attrs),
+ 		    std::move (inner_attrs), locus));
+ }
+ 
+ // Parses a trait item used inside traits (not trait, the Item).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::AssociatedItem>
+ Parser<ManagedTokenSource>::parse_trait_item ()
+ {
+   // parse outer attributes (if they exist)
+   AST::AttrVec outer_attrs = parse_outer_attributes ();
+ 
+   auto vis_res = parse_visibility ();
+   if (!vis_res)
+     return nullptr;
+ 
+   auto vis = vis_res.value ();
+ 
+   // lookahead to determine what type of trait item to parse
+   const_TokenPtr tok = lexer.peek_token ();
+   switch (tok->get_id ())
+     {
+     case SUPER:
+     case SELF:
+     case CRATE:
+     case DOLLAR_SIGN:
+       // these seem to be SimplePath tokens, so this is a macro invocation
+       // semi
+       return parse_macro_invocation_semi (std::move (outer_attrs));
+     case IDENTIFIER:
+       if (lexer.peek_token ()->get_str () == Values::WeakKeywords::DEFAULT)
+ 	return parse_function (std::move (vis), std::move (outer_attrs));
+       else
+ 	return parse_macro_invocation_semi (std::move (outer_attrs));
+     case TYPE:
+       return parse_trait_type (std::move (outer_attrs), vis);
+     case CONST:
+       // disambiguate with function qualifier
+       if (lexer.peek_token (1)->get_id () == IDENTIFIER)
+ 	{
+ 	  return parse_trait_const (std::move (outer_attrs));
+ 	}
+       // else, fallthrough to function
+       // TODO: find out how to disable gcc "implicit fallthrough" error
+       gcc_fallthrough ();
+     case ASYNC:
+     case UNSAFE:
+     case EXTERN_KW:
+     case FN_KW:
+       return parse_function (std::move (vis), std::move (outer_attrs));
+     default:
+       break;
+     }
+   add_error (Error (tok->get_locus (),
+ 		    "unrecognised token %qs for item in trait",
+ 		    tok->get_token_description ()));
+   // skip?
+   return nullptr;
+ }
+ 
+ // Parse a typedef trait item.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::TraitItemType>
+ Parser<ManagedTokenSource>::parse_trait_type (AST::AttrVec outer_attrs,
+ 					      AST::Visibility vis)
+ {
+   location_t locus = lexer.peek_token ()->get_locus ();
+   skip_token (TYPE);
+ 
+   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
+   if (ident_tok == nullptr)
+     return nullptr;
+ 
+   Identifier ident{ident_tok};
+ 
+   // Parse optional generic parameters for GATs (Generic Associated Types)
+   std::vector<std::unique_ptr<AST::GenericParam>> generic_params;
+   if (lexer.peek_token ()->get_id () == LEFT_ANGLE)
+     {
+       generic_params = parse_generic_params_in_angles ();
+     }
+ 
+   std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
+ 
+   // parse optional colon
+   if (lexer.peek_token ()->get_id () == COLON)
+     {
+       lexer.skip_token ();
+ 
+       // parse optional type param bounds
+       bounds
+ 	= parse_type_param_bounds ([] (TokenId id) { return id == SEMICOLON; });
+       // bounds = parse_type_param_bounds ();
+     }
+ 
+   if (!skip_token (SEMICOLON))
+     {
+       // skip?
+       return nullptr;
+     }
+ 
+   return std::unique_ptr<AST::TraitItemType> (
+     new AST::TraitItemType (std::move (ident), std::move (generic_params),
+ 			    std::move (bounds), std::move (outer_attrs), vis,
+ 			    locus));
+ }
+ 
+ // Parses a constant trait item.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::ConstantItem>
+ Parser<ManagedTokenSource>::parse_trait_const (AST::AttrVec outer_attrs)
+ {
+   location_t locus = lexer.peek_token ()->get_locus ();
+   skip_token (CONST);
+ 
+   // parse constant item name
+   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
+   if (ident_tok == nullptr)
+     return nullptr;
+ 
+   Identifier ident{ident_tok};
+ 
+   if (!skip_token (COLON))
+     {
+       skip_after_semicolon ();
+       return nullptr;
+     }
+ 
+   // parse constant trait item type
+   std::unique_ptr<AST::Type> type = parse_type ();
+ 
+   // parse constant trait body expression, if it exists
+   std::unique_ptr<AST::Expr> const_body = nullptr;
+   if (lexer.peek_token ()->get_id () == EQUAL)
+     {
+       lexer.skip_token ();
+ 
+       // expression must exist, so parse it
+       const_body = parse_expr ();
+     }
+ 
+   if (!skip_token (SEMICOLON))
+     {
+       // skip after something?
+       return nullptr;
+     }
+ 
+   return std::unique_ptr<AST::ConstantItem> (new AST::ConstantItem (
+     std::move (ident), AST::Visibility::create_private (), std::move (type),
+     std::move (const_body), std::move (outer_attrs), locus));
+ }
+ 
+ /* Parses a struct "impl" item (both inherent impl and trait impl can be
+  * parsed here), */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::Impl>
+ Parser<ManagedTokenSource>::parse_impl (AST::Visibility vis,
+ 					AST::AttrVec outer_attrs)
+ {
+   /* Note that only trait impls are allowed to be unsafe. So if unsafe, it
+    * must be a trait impl. However, this isn't enough for full disambiguation,
+    * so don't branch here. */
+   location_t locus = lexer.peek_token ()->get_locus ();
+   bool is_unsafe = false;
+   if (lexer.peek_token ()->get_id () == UNSAFE)
+     {
+       lexer.skip_token ();
+       is_unsafe = true;
+     }
+ 
+   if (!skip_token (IMPL))
+     {
+       skip_after_next_block ();
+       return nullptr;
+     }
+ 
+   // parse generic params (shared by trait and inherent impls)
+   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
+     = parse_generic_params_in_angles ();
+ 
+   // Again, trait impl-only feature, but optional one, so can be used for
+   // branching yet.
+   bool has_exclam = false;
+   if (lexer.peek_token ()->get_id () == EXCLAM)
+     {
+       lexer.skip_token ();
+       has_exclam = true;
+     }
+ 
+   /* FIXME: code that doesn't look shit for TypePath. Also, make sure this
+    * doesn't parse too much and not work. */
+   AST::TypePath type_path = parse_type_path ();
+   if (type_path.is_error () || lexer.peek_token ()->get_id () != FOR)
+     {
+       /* cannot parse type path (or not for token next, at least), so must be
+        * inherent impl */
+ 
+       // hacky conversion of TypePath stack object to Type pointer
+       std::unique_ptr<AST::Type> type = nullptr;
+       if (!type_path.is_error ())
+ 	type = std::unique_ptr<AST::TypePath> (
+ 	  new AST::TypePath (std::move (type_path)));
+       else
+ 	type = parse_type ();
+ 
+       // Type is required, so error if null
+       if (type == nullptr)
+ 	{
+ 	  Error error (lexer.peek_token ()->get_locus (),
+ 		       "could not parse type in inherent impl");
+ 	  add_error (std::move (error));
+ 
+ 	  skip_after_next_block ();
+ 	  return nullptr;
+ 	}
+ 
+       // parse optional where clause
+       AST::WhereClause where_clause = parse_where_clause ();
+ 
+       if (!skip_token (LEFT_CURLY))
+ 	{
+ 	  // TODO: does this still skip properly?
+ 	  skip_after_end_block ();
+ 	  return nullptr;
+ 	}
+ 
+       // parse inner attributes (optional)
+       AST::AttrVec inner_attrs = parse_inner_attributes ();
+ 
+       // parse inherent impl items
+       std::vector<std::unique_ptr<AST::AssociatedItem>> impl_items;
+ 
+       const_TokenPtr t = lexer.peek_token ();
+       while (t->get_id () != RIGHT_CURLY)
+ 	{
+ 	  std::unique_ptr<AST::AssociatedItem> impl_item
+ 	    = parse_inherent_impl_item ();
+ 
+ 	  if (impl_item == nullptr)
+ 	    {
+ 	      Error error (
+ 		lexer.peek_token ()->get_locus (),
+ 		"failed to parse inherent impl item in inherent impl");
+ 	      add_error (std::move (error));
+ 
+ 	      return nullptr;
+ 	    }
+ 
+ 	  impl_items.push_back (std::move (impl_item));
+ 
+ 	  t = lexer.peek_token ();
+ 	}
+ 
+       if (!skip_token (RIGHT_CURLY))
+ 	{
+ 	  // skip somewhere
+ 	  return nullptr;
+ 	}
+ 
+       // DEBUG
+       rust_debug ("successfully parsed inherent impl");
+ 
+       impl_items.shrink_to_fit ();
+ 
+       return std::unique_ptr<AST::InherentImpl> (new AST::InherentImpl (
+ 	std::move (impl_items), std::move (generic_params), std::move (type),
+ 	std::move (where_clause), std::move (vis), std::move (inner_attrs),
+ 	std::move (outer_attrs), locus));
+     }
+   else
+     {
+       // type path must both be valid and next token is for, so trait impl
+       if (!skip_token (FOR))
+ 	{
+ 	  skip_after_next_block ();
+ 	  return nullptr;
+ 	}
+ 
+       // parse type
+       std::unique_ptr<AST::Type> type = parse_type ();
+       // ensure type is included as it is required
+       if (type == nullptr)
+ 	{
+ 	  Error error (lexer.peek_token ()->get_locus (),
+ 		       "could not parse type in trait impl");
+ 	  add_error (std::move (error));
+ 
+ 	  skip_after_next_block ();
+ 	  return nullptr;
+ 	}
+ 
+       // parse optional where clause
+       AST::WhereClause where_clause = parse_where_clause ();
+ 
+       if (!skip_token (LEFT_CURLY))
+ 	{
+ 	  // TODO: does this still skip properly?
+ 	  skip_after_end_block ();
+ 	  return nullptr;
+ 	}
+ 
+       // parse inner attributes (optional)
+       AST::AttrVec inner_attrs = parse_inner_attributes ();
+ 
+       // parse trait impl items
+       std::vector<std::unique_ptr<AST::AssociatedItem>> impl_items;
+ 
+       const_TokenPtr t = lexer.peek_token ();
+       while (t->get_id () != RIGHT_CURLY)
+ 	{
+ 	  std::unique_ptr<AST::AssociatedItem> impl_item
+ 	    = parse_trait_impl_item ();
+ 
+ 	  if (impl_item == nullptr)
+ 	    {
+ 	      Error error (lexer.peek_token ()->get_locus (),
+ 			   "failed to parse trait impl item in trait impl");
+ 	      add_error (std::move (error));
+ 
+ 	      return nullptr;
+ 	    }
+ 
+ 	  impl_items.push_back (std::move (impl_item));
+ 
+ 	  t = lexer.peek_token ();
+ 
+ 	  // DEBUG
+ 	  rust_debug ("successfully parsed a trait impl item");
+ 	}
+       // DEBUG
+       rust_debug ("successfully finished trait impl items");
+ 
+       if (!skip_token (RIGHT_CURLY))
+ 	{
+ 	  // skip somewhere
+ 	  return nullptr;
+ 	}
+ 
+       // DEBUG
+       rust_debug ("successfully parsed trait impl");
+ 
+       impl_items.shrink_to_fit ();
+ 
+       return std::unique_ptr<AST::TraitImpl> (
+ 	new AST::TraitImpl (std::move (type_path), is_unsafe, has_exclam,
+ 			    std::move (impl_items), std::move (generic_params),
+ 			    std::move (type), std::move (where_clause),
+ 			    std::move (vis), std::move (inner_attrs),
+ 			    std::move (outer_attrs), locus));
+     }
+ }
+ 
+ // Parses a single inherent impl item (item inside an inherent impl block).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::AssociatedItem>
+ Parser<ManagedTokenSource>::parse_inherent_impl_item ()
+ {
+   // parse outer attributes (if they exist)
+   AST::AttrVec outer_attrs = parse_outer_attributes ();
+ 
+   // TODO: cleanup - currently an unreadable mess
+ 
+   // branch on next token:
+   const_TokenPtr t = lexer.peek_token ();
+   switch (t->get_id ())
+     {
+     case IDENTIFIER:
+       // FIXME: Arthur: Do we need to some lookahead here?
+       return parse_macro_invocation_semi (outer_attrs);
+     case SUPER:
+     case SELF:
+     case CRATE:
+     case PUB:
+       {
+ 	// visibility, so not a macro invocation semi - must be constant,
+ 	// function, or method
+ 	auto vis_res = parse_visibility ();
+ 	if (!vis_res)
+ 	  return nullptr;
+ 	auto vis = vis_res.value ();
+ 
+ 	// TODO: is a recursive call to parse_inherent_impl_item better?
+ 	switch (lexer.peek_token ()->get_id ())
+ 	  {
+ 	  case EXTERN_KW:
+ 	  case UNSAFE:
+ 	  case FN_KW:
+ 	    // function or method
+ 	    return parse_inherent_impl_function_or_method (std::move (vis),
+ 							   std::move (
+ 							     outer_attrs));
+ 	  case CONST:
+ 	    // lookahead to resolve production - could be function/method or
+ 	    // const item
+ 	    t = lexer.peek_token (1);
+ 
+ 	    switch (t->get_id ())
+ 	      {
+ 	      case IDENTIFIER:
+ 	      case UNDERSCORE:
+ 		return parse_const_item (std::move (vis),
+ 					 std::move (outer_attrs));
+ 	      case UNSAFE:
+ 	      case EXTERN_KW:
+ 	      case FN_KW:
+ 		return parse_inherent_impl_function_or_method (std::move (vis),
+ 							       std::move (
+ 								 outer_attrs));
+ 	      default:
+ 		add_error (Error (t->get_locus (),
+ 				  "unexpected token %qs in some sort of const "
+ 				  "item in inherent impl",
+ 				  t->get_token_description ()));
+ 
+ 		lexer.skip_token (1); // TODO: is this right thing to do?
+ 		return nullptr;
+ 	      }
+ 	  default:
+ 	    add_error (
+ 	      Error (t->get_locus (),
+ 		     "unrecognised token %qs for item in inherent impl",
+ 		     t->get_token_description ()));
+ 	    // skip?
+ 	    return nullptr;
+ 	  }
+       }
+     case ASYNC:
+     case EXTERN_KW:
+     case UNSAFE:
+     case FN_KW:
+       // function or method
+       return parse_inherent_impl_function_or_method (
+ 	AST::Visibility::create_private (), std::move (outer_attrs));
+     case CONST:
+       /* lookahead to resolve production - could be function/method or const
+        * item */
+       t = lexer.peek_token (1);
+ 
+       switch (t->get_id ())
+ 	{
+ 	case IDENTIFIER:
+ 	case UNDERSCORE:
+ 	  return parse_const_item (AST::Visibility::create_private (),
+ 				   std::move (outer_attrs));
+ 	case UNSAFE:
+ 	case EXTERN_KW:
+ 	case FN_KW:
+ 	  return parse_inherent_impl_function_or_method (
+ 	    AST::Visibility::create_private (), std::move (outer_attrs));
+ 	default:
+ 	  add_error (Error (t->get_locus (),
+ 			    "unexpected token %qs in some sort of const item "
+ 			    "in inherent impl",
+ 			    t->get_token_description ()));
+ 
+ 	  lexer.skip_token (1); // TODO: is this right thing to do?
+ 	  return nullptr;
+ 	}
+       rust_unreachable ();
+     default:
+       add_error (Error (t->get_locus (),
+ 			"unrecognised token %qs for item in inherent impl",
+ 			t->get_token_description ()));
+ 
+       // skip?
+       return nullptr;
+     }
+ }
+ 
+ /* For internal use only by parse_inherent_impl_item() - splits giant method
+  * into smaller ones and prevents duplication of logic. Strictly, this parses
+  * a function or method item inside an inherent impl item block. */
+ // TODO: make this a templated function with "return type" as type param -
+ // InherentImplItem is this specialisation of the template while TraitImplItem
+ // will be the other.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::AssociatedItem>
+ Parser<ManagedTokenSource>::parse_inherent_impl_function_or_method (
+   AST::Visibility vis, AST::AttrVec outer_attrs)
+ {
+   location_t locus = lexer.peek_token ()->get_locus ();
+   // parse function or method qualifiers
+   AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
+ 
+   skip_token (FN_KW);
+ 
+   // parse function or method name
+   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
+   if (ident_tok == nullptr)
+     return nullptr;
+ 
+   Identifier ident{ident_tok};
+ 
+   // parse generic params
+   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
+     = parse_generic_params_in_angles ();
+ 
+   if (!skip_token (LEFT_PAREN))
+     {
+       // skip after somewhere?
+       return nullptr;
+     }
+ 
+   // now for function vs method disambiguation - method has opening "self"
+   // param
+   auto initial_param = parse_self_param ();
+ 
+   if (!initial_param.has_value ()
+       && initial_param.error () != ParseSelfError::NOT_SELF)
+     return nullptr;
+ 
+   /* FIXME: ensure that self param doesn't accidently consume tokens for a
+    * function one idea is to lookahead up to 4 tokens to see whether self is
+    * one of them */
+   bool is_method = false;
+   if (initial_param.has_value ())
+     {
+       if ((*initial_param)->is_self ())
+ 	is_method = true;
+ 
+       /* skip comma so function and method regular params can be parsed in
+        * same way */
+       if (lexer.peek_token ()->get_id () == COMMA)
+ 	lexer.skip_token ();
+     }
+ 
+   // parse trait function params
+   std::vector<std::unique_ptr<AST::Param>> function_params
+     = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
+ 
+   if (initial_param.has_value ())
+     function_params.insert (function_params.begin (),
+ 			    std::move (*initial_param));
+ 
+   if (!skip_token (RIGHT_PAREN))
+     {
+       skip_after_end_block ();
+       return nullptr;
+     }
+ 
+   // parse return type (optional)
+   std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
+ 
+   // parse where clause (optional)
+   AST::WhereClause where_clause = parse_where_clause ();
+ 
+   tl::optional<std::unique_ptr<AST::BlockExpr>> body = tl::nullopt;
+   if (lexer.peek_token ()->get_id () == SEMICOLON)
+     lexer.skip_token ();
+   else
+     {
+       auto result = parse_block_expr ();
+ 
+       if (result == nullptr)
+ 	{
+ 	  Error error (
+ 	    lexer.peek_token ()->get_locus (),
+ 	    "could not parse definition in inherent impl %s definition",
+ 	    is_method ? "method" : "function");
+ 	  add_error (std::move (error));
+ 
+ 	  skip_after_end_block ();
+ 	  return nullptr;
+ 	}
+       body = std::move (result);
+     }
+ 
+   return std::unique_ptr<AST::Function> (
+     new AST::Function (std::move (ident), std::move (qualifiers),
+ 		       std::move (generic_params), std::move (function_params),
+ 		       std::move (return_type), std::move (where_clause),
+ 		       std::move (body), std::move (vis),
+ 		       std::move (outer_attrs), locus));
+ }
+ 
+ // Parses a single trait impl item (item inside a trait impl block).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::AssociatedItem>
+ Parser<ManagedTokenSource>::parse_trait_impl_item ()
+ {
+   // parse outer attributes (if they exist)
+   AST::AttrVec outer_attrs = parse_outer_attributes ();
+ 
+   auto vis_res = parse_visibility ();
+   if (!vis_res)
+     return nullptr;
+   auto visibility = vis_res.value ();
+ 
+   // branch on next token:
+   const_TokenPtr t = lexer.peek_token ();
+   switch (t->get_id ())
+     {
+     case SUPER:
+     case SELF:
+     case CRATE:
+     case DOLLAR_SIGN:
+       // these seem to be SimplePath tokens, so this is a macro invocation
+       // semi
+       return parse_macro_invocation_semi (std::move (outer_attrs));
+     case IDENTIFIER:
+       if (lexer.peek_token ()->get_str () == Values::WeakKeywords::DEFAULT)
+ 	return parse_trait_impl_function_or_method (visibility,
+ 						    std::move (outer_attrs));
+       else
+ 	return parse_macro_invocation_semi (std::move (outer_attrs));
+     case TYPE:
+       return parse_type_alias (visibility, std::move (outer_attrs));
+     case EXTERN_KW:
+     case UNSAFE:
+     case FN_KW:
+       // function or method
+       return parse_trait_impl_function_or_method (visibility,
+ 						  std::move (outer_attrs));
+     case ASYNC:
+       return parse_async_item (visibility, std::move (outer_attrs));
+     case CONST:
+       // lookahead to resolve production - could be function/method or const
+       // item
+       t = lexer.peek_token (1);
+ 
+       switch (t->get_id ())
+ 	{
+ 	case IDENTIFIER:
+ 	case UNDERSCORE:
+ 	  return parse_const_item (visibility, std::move (outer_attrs));
+ 	case UNSAFE:
+ 	case EXTERN_KW:
+ 	case FN_KW:
+ 	  return parse_trait_impl_function_or_method (visibility,
+ 						      std::move (outer_attrs));
+ 	default:
+ 	  add_error (Error (
+ 	    t->get_locus (),
+ 	    "unexpected token %qs in some sort of const item in trait impl",
+ 	    t->get_token_description ()));
+ 
+ 	  lexer.skip_token (1); // TODO: is this right thing to do?
+ 	  return nullptr;
+ 	}
+       rust_unreachable ();
+     default:
+       break;
+     }
+   add_error (Error (t->get_locus (),
+ 		    "unrecognised token %qs for item in trait impl",
+ 		    t->get_token_description ()));
+ 
+   // skip?
+   return nullptr;
+ }
+ 
+ /* For internal use only by parse_trait_impl_item() - splits giant method into
+  * smaller ones and prevents duplication of logic. Strictly, this parses a
+  * function or method item inside a trait impl item block. */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::AssociatedItem>
+ Parser<ManagedTokenSource>::parse_trait_impl_function_or_method (
+   AST::Visibility vis, AST::AttrVec outer_attrs)
+ {
+   // this shares virtually all logic with
+   // parse_inherent_impl_function_or_method
+   // - template?
+   location_t locus = lexer.peek_token ()->get_locus ();
+ 
+   auto is_default = false;
+   auto t = lexer.peek_token ();
+   if (t->get_id () == IDENTIFIER
+       && t->get_str () == Values::WeakKeywords::DEFAULT)
+     {
+       is_default = true;
+       lexer.skip_token ();
+     }
+ 
+   // parse function or method qualifiers
+   AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
+ 
+   skip_token (FN_KW);
+ 
+   // parse function or method name
+   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
+   if (ident_tok == nullptr)
+     {
+       return nullptr;
+     }
+   Identifier ident{ident_tok};
+ 
+   // DEBUG:
+   rust_debug (
+     "about to start parsing generic params in trait impl function or method");
+ 
+   // parse generic params
+   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
+     = parse_generic_params_in_angles ();
+ 
+   // DEBUG:
+   rust_debug (
+     "finished parsing generic params in trait impl function or method");
+ 
+   if (!skip_token (LEFT_PAREN))
+     {
+       // skip after somewhere?
+       return nullptr;
+     }
+ 
+   // now for function vs method disambiguation - method has opening "self"
+   // param
+   auto initial_param = parse_self_param ();
+ 
+   if (!initial_param.has_value ()
+       && initial_param.error () != ParseSelfError::NOT_SELF)
+     return nullptr;
+ 
+   // FIXME: ensure that self param doesn't accidently consume tokens for a
+   // function
+   bool is_method = false;
+   if (initial_param.has_value ())
+     {
+       if ((*initial_param)->is_self ())
+ 	is_method = true;
+ 
+       // skip comma so function and method regular params can be parsed in
+       // same way
+       if (lexer.peek_token ()->get_id () == COMMA)
+ 	{
+ 	  lexer.skip_token ();
+ 	}
+ 
+       // DEBUG
+       rust_debug ("successfully parsed self param in method trait impl item");
+     }
+ 
+   // DEBUG
+   rust_debug (
+     "started to parse function params in function or method trait impl item");
+ 
+   // parse trait function params (only if next token isn't right paren)
+   std::vector<std::unique_ptr<AST::Param>> function_params;
+   if (lexer.peek_token ()->get_id () != RIGHT_PAREN)
+     {
+       function_params
+ 	= parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
+ 
+       if (function_params.empty ())
+ 	{
+ 	  Error error (
+ 	    lexer.peek_token ()->get_locus (),
+ 	    "failed to parse function params in trait impl %s definition",
+ 	    is_method ? "method" : "function");
+ 	  add_error (std::move (error));
+ 
+ 	  skip_after_next_block ();
+ 	  return nullptr;
+ 	}
+     }
+ 
+   if (initial_param.has_value ())
+     function_params.insert (function_params.begin (),
+ 			    std::move (*initial_param));
+ 
+   // DEBUG
+   rust_debug ("successfully parsed function params in function or method "
+ 	      "trait impl item");
+ 
+   if (!skip_token (RIGHT_PAREN))
+     {
+       skip_after_next_block ();
+       return nullptr;
+     }
+ 
+   // parse return type (optional)
+   std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
+ 
+   // DEBUG
+   rust_debug (
+     "successfully parsed return type in function or method trait impl item");
+ 
+   // parse where clause (optional)
+   AST::WhereClause where_clause = parse_where_clause ();
+ 
+   // DEBUG
+   rust_debug (
+     "successfully parsed where clause in function or method trait impl item");
+ 
+   // parse function definition (in block) - semicolon not allowed
+   tl::optional<std::unique_ptr<AST::BlockExpr>> body = tl::nullopt;
+ 
+   if (lexer.peek_token ()->get_id () == SEMICOLON)
+     lexer.skip_token ();
+   else
+     {
+       auto result = parse_block_expr ();
+       if (result == nullptr)
+ 	{
+ 	  Error error (lexer.peek_token ()->get_locus (),
+ 		       "could not parse definition in trait impl %s definition",
+ 		       is_method ? "method" : "function");
+ 	  add_error (std::move (error));
+ 
+ 	  skip_after_end_block ();
+ 	  return nullptr;
+ 	}
+       body = std::move (result);
+     }
+ 
+   return std::unique_ptr<AST::Function> (
+     new AST::Function (std::move (ident), std::move (qualifiers),
+ 		       std::move (generic_params), std::move (function_params),
+ 		       std::move (return_type), std::move (where_clause),
+ 		       std::move (body), std::move (vis),
+ 		       std::move (outer_attrs), locus, is_default));
+ }
+ 
+ // Parses an extern block of declarations.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::ExternBlock>
+ Parser<ManagedTokenSource>::parse_extern_block (AST::Visibility vis,
+ 						AST::AttrVec outer_attrs)
+ {
+   location_t locus = lexer.peek_token ()->get_locus ();
+   skip_token (EXTERN_KW);
+ 
+   // detect optional abi name
+   std::string abi;
+   const_TokenPtr next_tok = lexer.peek_token ();
+   if (next_tok->get_id () == STRING_LITERAL)
+     {
+       lexer.skip_token ();
+       abi = next_tok->get_str ();
+     }
+ 
+   if (!skip_token (LEFT_CURLY))
+     {
+       skip_after_end_block ();
+       return nullptr;
+     }
+ 
+   AST::AttrVec inner_attrs = parse_inner_attributes ();
+ 
+   // parse declarations inside extern block
+   std::vector<std::unique_ptr<AST::ExternalItem>> extern_items;
+ 
+   const_TokenPtr t = lexer.peek_token ();
+   while (t->get_id () != RIGHT_CURLY)
+     {
+       std::unique_ptr<AST::ExternalItem> extern_item = parse_external_item ();
+ 
+       if (extern_item == nullptr)
+ 	{
+ 	  Error error (t->get_locus (),
+ 		       "failed to parse external item despite not reaching "
+ 		       "end of extern block");
+ 	  add_error (std::move (error));
+ 
+ 	  return nullptr;
+ 	}
+ 
+       extern_items.push_back (std::move (extern_item));
+ 
+       t = lexer.peek_token ();
+     }
+ 
+   if (!skip_token (RIGHT_CURLY))
+     {
+       // skip somewhere
+       return nullptr;
+     }
+ 
+   extern_items.shrink_to_fit ();
+ 
+   return std::unique_ptr<AST::ExternBlock> (
+     new AST::ExternBlock (std::move (abi), std::move (extern_items),
+ 			  std::move (vis), std::move (inner_attrs),
+ 			  std::move (outer_attrs), locus));
+ }
+ 
+ // Parses a single extern block item (static or function declaration).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::ExternalItem>
+ Parser<ManagedTokenSource>::parse_external_item ()
+ {
+   // parse optional outer attributes
+   AST::AttrVec outer_attrs = parse_outer_attributes ();
+ 
+   location_t locus = lexer.peek_token ()->get_locus ();
+ 
+   // parse optional visibility
+   auto vis_res = parse_visibility ();
+   if (!vis_res)
+     return nullptr;
+   auto vis = vis_res.value ();
+ 
+   const_TokenPtr t = lexer.peek_token ();
+   switch (t->get_id ())
+     {
+     case IDENTIFIER:
+       return parse_macro_invocation_semi (outer_attrs);
+     case STATIC_KW:
+       {
+ 	// parse extern static item
+ 	lexer.skip_token ();
+ 
+ 	// parse mut (optional)
+ 	bool has_mut = false;
+ 	if (lexer.peek_token ()->get_id () == MUT)
+ 	  {
+ 	    lexer.skip_token ();
+ 	    has_mut = true;
+ 	  }
+ 
+ 	// parse identifier
+ 	const_TokenPtr ident_tok = expect_token (IDENTIFIER);
+ 	if (ident_tok == nullptr)
+ 	  {
+ 	    skip_after_semicolon ();
+ 	    return nullptr;
+ 	  }
+ 	Identifier ident{ident_tok};
+ 
+ 	if (!skip_token (COLON))
+ 	  {
+ 	    skip_after_semicolon ();
+ 	    return nullptr;
+ 	  }
+ 
+ 	// parse type (required)
+ 	std::unique_ptr<AST::Type> type = parse_type ();
+ 	if (type == nullptr)
+ 	  {
+ 	    Error error (lexer.peek_token ()->get_locus (),
+ 			 "failed to parse type in external static item");
+ 	    add_error (std::move (error));
+ 
+ 	    skip_after_semicolon ();
+ 	    return nullptr;
+ 	  }
+ 
+ 	if (!skip_token (SEMICOLON))
+ 	  {
+ 	    // skip after somewhere?
+ 	    return nullptr;
+ 	  }
+ 
+ 	return std::unique_ptr<AST::ExternalStaticItem> (
+ 	  new AST::ExternalStaticItem (std::move (ident), std::move (type),
+ 				       has_mut, std::move (vis),
+ 				       std::move (outer_attrs), locus));
+       }
+     case FN_KW:
+       return parse_function (std::move (vis), std::move (outer_attrs), true);
+ 
+     case TYPE:
+       return parse_external_type_item (std::move (vis),
+ 				       std::move (outer_attrs));
+     default:
+       // error
+       add_error (
+ 	Error (t->get_locus (),
+ 	       "unrecognised token %qs in extern block item declaration",
+ 	       t->get_token_description ()));
+ 
+       skip_after_semicolon ();
+       return nullptr;
+     }
+ }
+ 
+ // Parses a statement (will further disambiguate any statement).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::Stmt>
+ Parser<ManagedTokenSource>::parse_stmt (ParseRestrictions restrictions)
+ {
+   // quick exit for empty statement
+   // FIXME: Can we have empty statements without semicolons? Just nothing?
+   const_TokenPtr t = lexer.peek_token ();
+   if (t->get_id () == SEMICOLON)
+     {
+       lexer.skip_token ();
+       return std::unique_ptr<AST::EmptyStmt> (
+ 	new AST::EmptyStmt (t->get_locus ()));
+     }
+ 
+   // parse outer attributes
+   AST::AttrVec outer_attrs = parse_outer_attributes ();
+ 
+   // parsing this will be annoying because of the many different possibilities
+   /* best may be just to copy paste in parse_item switch, and failing that try
+    * to parse outer attributes, and then pass them in to either a let
+    * statement or (fallback) expression statement. */
+   // FIXME: think of a way to do this without such a large switch?
+   t = lexer.peek_token ();
+   switch (t->get_id ())
+     {
+     case LET:
+       // let statement
+       return parse_let_stmt (std::move (outer_attrs), restrictions);
+     case PUB:
+     case MOD:
+     case EXTERN_KW:
+     case USE:
+     case FN_KW:
+     case TYPE:
+     case STRUCT_KW:
+     case ENUM_KW:
+     case CONST:
+     case STATIC_KW:
+     case AUTO:
+     case TRAIT:
+     case IMPL:
+     case MACRO:
+     /* TODO: implement union keyword but not really because of
+      * context-dependence crappy hack way to parse a union written below to
+      * separate it from the good code. */
+     // case UNION:
+     case UNSAFE: // maybe - unsafe traits are a thing
+       /* if any of these (should be all possible VisItem prefixes), parse a
+        * VisItem can't parse item because would require reparsing outer
+        * attributes */
+       // may also be unsafe block
+       if (lexer.peek_token (1)->get_id () == LEFT_CURLY)
+ 	{
+ 	  return parse_expr_stmt (std::move (outer_attrs), restrictions);
+ 	}
+       else
+ 	{
+ 	  return parse_vis_item (std::move (outer_attrs));
+ 	}
+       break;
+     // crappy hack to do union "keyword"
+     case IDENTIFIER:
+       if (t->get_str () == Values::WeakKeywords::UNION
+ 	  && lexer.peek_token (1)->get_id () == IDENTIFIER)
+ 	{
+ 	  return parse_vis_item (std::move (outer_attrs));
+ 	  // or should this go straight to parsing union?
+ 	}
+       else if (is_macro_rules_def (t))
+ 	{
+ 	  // macro_rules! macro item
+ 	  return parse_macro_rules_def (std::move (outer_attrs));
+ 	}
+       gcc_fallthrough ();
+       // TODO: find out how to disable gcc "implicit fallthrough" warning
+     default:
+       // fallback: expression statement
+       return parse_expr_stmt (std::move (outer_attrs), restrictions);
+       break;
+     }
+ }
+ 
+ // Parses a let statement.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::LetStmt>
+ Parser<ManagedTokenSource>::parse_let_stmt (AST::AttrVec outer_attrs,
+ 					    ParseRestrictions restrictions)
+ {
+   location_t locus = lexer.peek_token ()->get_locus ();
+   skip_token (LET);
+ 
+   // parse pattern (required)
+   std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
+   if (pattern == nullptr)
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "failed to parse pattern in let statement");
+       add_error (std::move (error));
+ 
+       skip_after_semicolon ();
+       return nullptr;
+     }
+ 
+   // parse type declaration (optional)
+   std::unique_ptr<AST::Type> type = nullptr;
+   if (lexer.peek_token ()->get_id () == COLON)
+     {
+       // must have a type declaration
+       lexer.skip_token ();
+ 
+       type = parse_type ();
+       if (type == nullptr)
+ 	{
+ 	  Error error (lexer.peek_token ()->get_locus (),
+ 		       "failed to parse type in let statement");
+ 	  add_error (std::move (error));
+ 
+ 	  skip_after_semicolon ();
+ 	  return nullptr;
+ 	}
+     }
+ 
+   // parse expression to set variable to (optional)
+   std::unique_ptr<AST::Expr> expr = nullptr;
+   if (lexer.peek_token ()->get_id () == EQUAL)
+     {
+       // must have an expression
+       lexer.skip_token ();
+ 
+       expr = parse_expr ();
+       if (expr == nullptr)
+ 	{
+ 	  skip_after_semicolon ();
+ 	  return nullptr;
+ 	}
+     }
+ 
+   tl::optional<std::unique_ptr<AST::Expr>> else_expr = tl::nullopt;
+   if (maybe_skip_token (ELSE))
+     else_expr = parse_block_expr ();
+ 
+   if (restrictions.consume_semi)
+     {
+       // `stmt` macro variables are parsed without a semicolon, but should be
+       // parsed as a full statement when interpolated. This should be handled
+       // by having the interpolated statement be distinguishable from normal
+       // tokens, e.g. by NT tokens.
+       if (restrictions.allow_close_after_expr_stmt)
+ 	maybe_skip_token (SEMICOLON);
+       else if (!skip_token (SEMICOLON))
+ 	return nullptr;
+     }
+ 
+   return std::unique_ptr<AST::LetStmt> (
+     new AST::LetStmt (std::move (pattern), std::move (expr), std::move (type),
+ 		      std::move (else_expr), std::move (outer_attrs), locus));
+ }
+ 
+ template <typename ManagedTokenSource>
+ tl::optional<AST::GenericArg>
+ Parser<ManagedTokenSource>::parse_generic_arg ()
+ {
+   auto tok = lexer.peek_token ();
+   std::unique_ptr<AST::Expr> expr = nullptr;
+ 
+   switch (tok->get_id ())
+     {
+     case IDENTIFIER:
+       {
+ 	// This is a bit of a weird situation: With an identifier token, we
+ 	// could either have a valid type or a macro (FIXME: anything else?). So
+ 	// we need one bit of lookahead to differentiate if this is really
+ 	auto next_tok = lexer.peek_token (1);
+ 	if (next_tok->get_id () == LEFT_ANGLE
+ 	    || next_tok->get_id () == SCOPE_RESOLUTION
+ 	    || next_tok->get_id () == EXCLAM)
+ 	  {
+ 	    auto type = parse_type ();
+ 	    if (type)
+ 	      return AST::GenericArg::create_type (std::move (type));
+ 	    else
+ 	      return tl::nullopt;
+ 	  }
+ 	else if (next_tok->get_id () == COLON)
+ 	  {
+ 	    lexer.skip_token (); // skip ident
+ 	    lexer.skip_token (); // skip colon
+ 
+ 	    auto tok = lexer.peek_token ();
+ 	    std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
+ 	      = parse_type_param_bounds ();
+ 
+ 	    auto type = std::unique_ptr<AST::TraitObjectType> (
+ 	      new AST::TraitObjectType (std::move (bounds), tok->get_locus (),
+ 					false));
+ 	    if (type)
+ 	      return AST::GenericArg::create_type (std::move (type));
+ 	    else
+ 	      return tl::nullopt;
+ 	  }
+ 	lexer.skip_token ();
+ 	return AST::GenericArg::create_ambiguous (tok->get_str (),
+ 						  tok->get_locus ());
+       }
+     case LEFT_CURLY:
+       expr = parse_block_expr ();
+       break;
+     case MINUS:
+     case STRING_LITERAL:
+     case CHAR_LITERAL:
+     case INT_LITERAL:
+     case FLOAT_LITERAL:
+     case TRUE_LITERAL:
+     case FALSE_LITERAL:
+       expr = parse_literal_expr ();
+       break;
+     // FIXME: Because of this, error reporting is garbage for const generic
+     // parameter's default values
+     default:
+       {
+ 	auto type = parse_type ();
+ 	// FIXME: Find a better way to do this?
+ 	if (type)
+ 	  return AST::GenericArg::create_type (std::move (type));
+ 	else
+ 	  return tl::nullopt;
+       }
+     }
+ 
+   if (!expr)
+     return tl::nullopt;
+ 
+   return AST::GenericArg::create_const (std::move (expr));
+ }
+ 
+ // Parses the generic arguments in each path segment.
+ template <typename ManagedTokenSource>
+ AST::GenericArgs
+ Parser<ManagedTokenSource>::parse_path_generic_args ()
+ {
+   if (lexer.peek_token ()->get_id () == LEFT_SHIFT)
+     lexer.split_current_token (LEFT_ANGLE, LEFT_ANGLE);
+ 
+   if (!skip_token (LEFT_ANGLE))
+     {
+       // skip after somewhere?
+       return AST::GenericArgs::create_empty ();
+     }
+ 
+   // We need to parse all lifetimes, then parse types and const generics in
+   // any order.
+ 
+   // try to parse lifetimes first
+   std::vector<AST::Lifetime> lifetime_args;
+ 
+   const_TokenPtr t = lexer.peek_token ();
+   location_t locus = t->get_locus ();
+   while (!Parse::Utils::is_right_angle_tok (t->get_id ()))
+     {
+       auto lifetime = parse_lifetime (false);
+       if (!lifetime)
+ 	{
+ 	  // not necessarily an error
+ 	  break;
+ 	}
+ 
+       lifetime_args.push_back (std::move (lifetime.value ()));
+ 
+       // if next token isn't comma, then it must be end of list
+       if (lexer.peek_token ()->get_id () != COMMA)
+ 	{
+ 	  break;
+ 	}
+       // skip comma
+       lexer.skip_token ();
+ 
+       t = lexer.peek_token ();
+     }
+ 
+   // try to parse types and const generics second
+   std::vector<AST::GenericArg> generic_args;
+ 
+   // TODO: think of better control structure
+   t = lexer.peek_token ();
+   while (!Parse::Utils::is_right_angle_tok (t->get_id ()))
+     {
+       // FIXME: Is it fine to break if there is one binding? Can't there be
+       // bindings in between types?
+ 
+       // ensure not binding being parsed as type accidently
+       if (t->get_id () == IDENTIFIER
+ 	  && lexer.peek_token (1)->get_id () == EQUAL)
+ 	break;
+ 
+       auto arg = parse_generic_arg ();
+       if (arg)
+ 	{
+ 	  generic_args.emplace_back (std::move (arg.value ()));
+ 	}
+ 
+       // FIXME: Do we need to break if we encounter an error?
+ 
+       // if next token isn't comma, then it must be end of list
+       if (lexer.peek_token ()->get_id () != COMMA)
+ 	break;
+ 
+       // skip comma
+       lexer.skip_token ();
+       t = lexer.peek_token ();
+     }
+ 
+   // try to parse bindings third
+   std::vector<AST::GenericArgsBinding> binding_args;
+ 
+   // TODO: think of better control structure
+   t = lexer.peek_token ();
+   while (!Parse::Utils::is_right_angle_tok (t->get_id ()))
+     {
+       AST::GenericArgsBinding binding = parse_generic_args_binding ();
+       if (binding.is_error ())
+ 	{
+ 	  // not necessarily an error
+ 	  break;
+ 	}
+ 
+       binding_args.push_back (std::move (binding));
+ 
+       // if next token isn't comma, then it must be end of list
+       if (lexer.peek_token ()->get_id () != COMMA)
+ 	{
+ 	  break;
+ 	}
+       // skip comma
+       lexer.skip_token ();
+ 
+       t = lexer.peek_token ();
+     }
+ 
+   // skip any trailing commas
+   if (lexer.peek_token ()->get_id () == COMMA)
+     lexer.skip_token ();
+ 
+   if (!skip_generics_right_angle ())
+     return AST::GenericArgs::create_empty ();
+ 
+   lifetime_args.shrink_to_fit ();
+   generic_args.shrink_to_fit ();
+   binding_args.shrink_to_fit ();
+ 
+   return AST::GenericArgs (std::move (lifetime_args), std::move (generic_args),
+ 			   std::move (binding_args), locus);
+ }
+ 
+ // Parses a binding in a generic args path segment.
+ template <typename ManagedTokenSource>
+ AST::GenericArgsBinding
+ Parser<ManagedTokenSource>::parse_generic_args_binding ()
+ {
+   const_TokenPtr ident_tok = lexer.peek_token ();
+   if (ident_tok->get_id () != IDENTIFIER)
+     {
+       // allow non error-inducing use
+       // skip somewhere?
+       return AST::GenericArgsBinding::create_error ();
+     }
+   lexer.skip_token ();
+   Identifier ident{ident_tok};
+ 
+   if (!skip_token (EQUAL))
+     {
+       // skip after somewhere?
+       return AST::GenericArgsBinding::create_error ();
+     }
+ 
+   // parse type (required)
+   std::unique_ptr<AST::Type> type = parse_type ();
+   if (type == nullptr)
+     {
+       // skip somewhere?
+       return AST::GenericArgsBinding::create_error ();
+     }
+ 
+   return AST::GenericArgsBinding (std::move (ident), std::move (type),
+ 				  ident_tok->get_locus ());
+ }
+ 
+ // Parses a self param. Also handles self param not existing.
+ template <typename ManagedTokenSource>
+ tl::expected<std::unique_ptr<AST::Param>, ParseSelfError>
+ Parser<ManagedTokenSource>::parse_self_param ()
+ {
+   bool has_reference = false;
+   AST::Lifetime lifetime = AST::Lifetime::elided ();
+ 
+   location_t locus = lexer.peek_token ()->get_locus ();
+ 
+   // TODO: Feels off, find a better way to clearly express this
+   std::vector<std::vector<TokenId>> ptrs
+     = {{ASTERISK, SELF} /* *self */,
+        {ASTERISK, CONST, SELF} /* *const self */,
+        {ASTERISK, MUT, SELF} /* *mut self */};
+ 
+   for (auto &s : ptrs)
+     {
+       size_t i = 0;
+       for (i = 0; i < s.size (); i++)
+ 	if (lexer.peek_token (i)->get_id () != s[i])
+ 	  break;
+       if (i == s.size ())
+ 	{
+ 	  rust_error_at (lexer.peek_token ()->get_locus (),
+ 			 "cannot pass %<self%> by raw pointer");
+ 	  return tl::make_unexpected (ParseSelfError::SELF_PTR);
+ 	}
+     }
+ 
+   // Trying to find those patterns:
+   //
+   // &'lifetime mut self
+   // &'lifetime self
+   // & mut self
+   // & self
+   // mut self
+   // self
+   //
+   // If not found, it is probably a function, exit and let function parsing
+   // handle it.
+   bool is_self = false;
+   for (size_t i = 0; i < 5; i++)
+     if (lexer.peek_token (i)->get_id () == SELF)
+       is_self = true;
+ 
+   if (!is_self)
+     return tl::make_unexpected (ParseSelfError::NOT_SELF);
+ 
+   // test if self is a reference parameter
+   if (lexer.peek_token ()->get_id () == AMP)
+     {
+       has_reference = true;
+       lexer.skip_token ();
+ 
+       // now test whether it has a lifetime
+       if (lexer.peek_token ()->get_id () == LIFETIME)
+ 	{
+ 	  // something went wrong somehow
+ 	  if (auto parsed_lifetime = parse_lifetime (true))
+ 	    {
+ 	      lifetime = parsed_lifetime.value ();
+ 	    }
+ 	  else
+ 	    {
+ 	      Error error (lexer.peek_token ()->get_locus (),
+ 			   "failed to parse lifetime in self param");
+ 	      add_error (std::move (error));
+ 
+ 	      // skip after somewhere?
+ 	      return tl::make_unexpected (ParseSelfError::PARSING);
+ 	    }
+ 	}
+     }
+ 
+   // test for mut
+   bool has_mut = false;
+   if (lexer.peek_token ()->get_id () == MUT)
+     {
+       has_mut = true;
+       lexer.skip_token ();
+     }
+ 
+   // skip self token
+   const_TokenPtr self_tok = lexer.peek_token ();
+   if (self_tok->get_id () != SELF)
+     {
+       // skip after somewhere?
+       return tl::make_unexpected (ParseSelfError::NOT_SELF);
+     }
+   lexer.skip_token ();
+ 
+   // parse optional type
+   std::unique_ptr<AST::Type> type = nullptr;
+   if (lexer.peek_token ()->get_id () == COLON)
+     {
+       lexer.skip_token ();
+ 
+       // type is now required
+       type = parse_type ();
+       if (type == nullptr)
+ 	{
+ 	  Error error (lexer.peek_token ()->get_locus (),
+ 		       "could not parse type in self param");
+ 	  add_error (std::move (error));
+ 
+ 	  // skip after somewhere?
+ 	  return tl::make_unexpected (ParseSelfError::PARSING);
+ 	}
+     }
+ 
+   // ensure that cannot have both type and reference
+   if (type != nullptr && has_reference)
+     {
+       Error error (
+ 	lexer.peek_token ()->get_locus (),
+ 	"cannot have both a reference and a type specified in a self param");
+       add_error (std::move (error));
+ 
+       // skip after somewhere?
+       return tl::make_unexpected (ParseSelfError::PARSING);
+     }
+ 
+   if (has_reference)
+     {
+       return std::make_unique<AST::SelfParam> (std::move (lifetime), has_mut,
+ 					       locus);
+     }
+   else
+     {
+       // note that type may be nullptr here and that's fine
+       return std::make_unique<AST::SelfParam> (std::move (type), has_mut,
+ 					       locus);
+     }
+ }
+ 
+ /* Parses an expression or macro statement. */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::Stmt>
+ Parser<ManagedTokenSource>::parse_expr_stmt (AST::AttrVec outer_attrs,
+ 					     ParseRestrictions restrictions)
+ {
+   location_t locus = lexer.peek_token ()->get_locus ();
+ 
+   std::unique_ptr<AST::Expr> expr;
+ 
+   switch (lexer.peek_token ()->get_id ())
+     {
+     case IDENTIFIER:
+     case CRATE:
+     case SUPER:
+     case SELF:
+     case SELF_ALIAS:
+     case DOLLAR_SIGN:
+     case SCOPE_RESOLUTION:
+       {
+ 	AST::PathInExpression path = parse_path_in_expression ();
+ 	std::unique_ptr<AST::Expr> null_denotation;
+ 
+ 	if (lexer.peek_token ()->get_id () == EXCLAM)
+ 	  {
+ 	    std::unique_ptr<AST::MacroInvocation> invoc
+ 	      = parse_macro_invocation_partial (std::move (path),
+ 						std::move (outer_attrs));
+ 
+ 	    if (restrictions.consume_semi && maybe_skip_token (SEMICOLON))
+ 	      {
+ 		invoc->add_semicolon ();
+ 		// Macro invocation with semicolon.
+ 		return invoc;
+ 	      }
+ 
+ 	    TokenId after_macro = lexer.peek_token ()->get_id ();
+ 
+ 	    if (restrictions.allow_close_after_expr_stmt
+ 		&& (after_macro == RIGHT_PAREN || after_macro == RIGHT_CURLY
+ 		    || after_macro == RIGHT_SQUARE))
+ 	      return invoc;
+ 
+ 	    if (invoc->get_invoc_data ().get_delim_tok_tree ().get_delim_type ()
+ 		  == AST::CURLY
+ 		&& after_macro != DOT && after_macro != QUESTION_MARK)
+ 	      {
+ 		rust_debug ("braced macro statement");
+ 		return invoc;
+ 	      }
+ 
+ 	    null_denotation = std::move (invoc);
+ 	  }
+ 	else
+ 	  {
+ 	    null_denotation
+ 	      = null_denotation_path (std::move (path), {}, restrictions);
+ 	  }
+ 
+ 	expr = left_denotations (std::move (null_denotation), LBP_LOWEST,
+ 				 std::move (outer_attrs), restrictions);
+ 	break;
+       }
+     default:
+       restrictions.expr_can_be_stmt = true;
+       expr = parse_expr (std::move (outer_attrs), restrictions);
+       break;
+     }
+ 
+   if (expr == nullptr)
+     {
+       // expr is required, error
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "failed to parse expr in expr statement");
+       add_error (std::move (error));
+ 
+       skip_after_semicolon ();
+       return nullptr;
+     }
+ 
+   bool has_semi = false;
+ 
+   if (restrictions.consume_semi)
+     {
+       if (maybe_skip_token (SEMICOLON))
+ 	{
+ 	  has_semi = true;
+ 	}
+       else if (expr->is_expr_without_block ())
+ 	{
+ 	  if (restrictions.allow_close_after_expr_stmt)
+ 	    {
+ 	      TokenId id = lexer.peek_token ()->get_id ();
+ 	      if (id != RIGHT_PAREN && id != RIGHT_CURLY && id != RIGHT_SQUARE)
+ 		{
+ 		  expect_token (SEMICOLON);
+ 		  return nullptr;
+ 		}
+ 	    }
+ 	  else
+ 	    {
+ 	      expect_token (SEMICOLON);
+ 	      return nullptr;
+ 	    }
+ 	}
+     }
+ 
+   return std::unique_ptr<AST::ExprStmt> (
+     new AST::ExprStmt (std::move (expr), locus, has_semi));
+ }
+ 
+ // Parses a loop label used in loop expressions.
+ template <typename ManagedTokenSource>
+ tl::expected<AST::LoopLabel, ParseLoopLabelError>
+ Parser<ManagedTokenSource>::parse_loop_label (const_TokenPtr tok)
+ {
+   // parse lifetime - if doesn't exist, assume no label
+   if (tok->get_id () != LIFETIME)
+     {
+       // not necessarily an error
+       return tl::unexpected<ParseLoopLabelError> (
+ 	ParseLoopLabelError::NOT_LOOP_LABEL);
+     }
+   /* FIXME: check for named lifetime requirement here? or check in semantic
+    * analysis phase? */
+   AST::Lifetime label = lifetime_from_token (tok);
+ 
+   if (!skip_token (COLON))
+     {
+       // skip somewhere?
+       return tl::unexpected<ParseLoopLabelError> (
+ 	ParseLoopLabelError::MISSING_COLON);
+     }
+ 
+   return tl::expected<AST::LoopLabel, ParseLoopLabelError> (
+     AST::LoopLabel (std::move (label), tok->get_locus ()));
+ }
+ 
+ // Parses the "pattern" part of the match arm (the 'case x:' equivalent).
+ template <typename ManagedTokenSource>
+ AST::MatchArm
+ Parser<ManagedTokenSource>::parse_match_arm ()
+ {
+   // parse optional outer attributes
+   AST::AttrVec outer_attrs = parse_outer_attributes ();
+ 
+   // DEBUG
+   rust_debug ("about to start parsing match arm patterns");
+ 
+   // break early if find right curly
+   if (lexer.peek_token ()->get_id () == RIGHT_CURLY)
+     {
+       // not an error
+       return AST::MatchArm::create_error ();
+     }
+ 
+   // parse match arm patterns - at least 1 is required
+   std::vector<std::unique_ptr<AST::Pattern>> match_arm_patterns
+     = parse_match_arm_patterns (RIGHT_CURLY);
+   if (match_arm_patterns.empty ())
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "failed to parse any patterns in match arm");
+       add_error (std::move (error));
+ 
+       // skip somewhere?
+       return AST::MatchArm::create_error ();
+     }
+ 
+   // DEBUG
+   rust_debug ("successfully parsed match arm patterns");
+ 
+   // parse match arm guard expr if it exists
+   std::unique_ptr<AST::Expr> guard_expr = nullptr;
+   if (lexer.peek_token ()->get_id () == IF)
+     {
+       lexer.skip_token ();
+ 
+       guard_expr = parse_expr ();
+       if (guard_expr == nullptr)
+ 	{
+ 	  Error error (lexer.peek_token ()->get_locus (),
+ 		       "failed to parse guard expression in match arm");
+ 	  add_error (std::move (error));
+ 
+ 	  // skip somewhere?
+ 	  return AST::MatchArm::create_error ();
+ 	}
+     }
+ 
+   // DEBUG
+   rust_debug ("successfully parsed match arm");
+ 
+   return AST::MatchArm (std::move (match_arm_patterns),
+ 			lexer.peek_token ()->get_locus (),
+ 			std::move (guard_expr), std::move (outer_attrs));
+ }
+ 
+ /* Parses the patterns used in a match arm. End token id is the id of the
+  * token that would exist after the patterns are done (e.g. '}' for match
+  * expr, '=' for if let and while let). */
+ template <typename ManagedTokenSource>
+ std::vector<std::unique_ptr<AST::Pattern>>
+ Parser<ManagedTokenSource>::parse_match_arm_patterns (TokenId end_token_id)
+ {
+   // skip optional leading '|'
+   if (lexer.peek_token ()->get_id () == PIPE)
+     lexer.skip_token ();
+   /* TODO: do I even need to store the result of this? can't be used.
+    * If semantically different, I need a wrapped "match arm patterns" object
+    * for this. */
+ 
+   std::vector<std::unique_ptr<AST::Pattern>> patterns;
+ 
+   // quick break out if end_token_id
+   if (lexer.peek_token ()->get_id () == end_token_id)
+     return patterns;
+ 
+   // parse required pattern - if doesn't exist, return empty
+   std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern ();
+   if (initial_pattern == nullptr)
+     {
+       // FIXME: should this be an error?
+       return patterns;
+     }
+   patterns.push_back (std::move (initial_pattern));
+ 
+   // DEBUG
+   rust_debug ("successfully parsed initial match arm pattern");
+ 
+   // parse new patterns as long as next char is '|'
+   const_TokenPtr t = lexer.peek_token ();
+   while (t->get_id () == PIPE)
+     {
+       // skip pipe token
+       lexer.skip_token ();
+ 
+       // break if hit end token id
+       if (lexer.peek_token ()->get_id () == end_token_id)
+ 	break;
+ 
+       // parse pattern
+       std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
+       if (pattern == nullptr)
+ 	{
+ 	  // this is an error
+ 	  Error error (lexer.peek_token ()->get_locus (),
+ 		       "failed to parse pattern in match arm patterns");
+ 	  add_error (std::move (error));
+ 
+ 	  // skip somewhere?
+ 	  return {};
+ 	}
+ 
+       patterns.push_back (std::move (pattern));
+ 
+       t = lexer.peek_token ();
+     }
+ 
+   patterns.shrink_to_fit ();
+ 
+   return patterns;
+ }
+ 
+ // Parses a single parameter used in a closure definition.
+ template <typename ManagedTokenSource>
+ AST::ClosureParam
+ Parser<ManagedTokenSource>::parse_closure_param ()
+ {
+   AST::AttrVec outer_attrs = parse_outer_attributes ();
+ 
+   // parse pattern (which is required)
+   std::unique_ptr<AST::Pattern> pattern = parse_pattern_no_alt ();
+   if (pattern == nullptr)
+     {
+       // not necessarily an error
+       return AST::ClosureParam::create_error ();
+     }
+ 
+   // parse optional type of param
+   std::unique_ptr<AST::Type> type = nullptr;
+   if (lexer.peek_token ()->get_id () == COLON)
+     {
+       lexer.skip_token ();
+ 
+       // parse type, which is now required
+       type = parse_type ();
+       if (type == nullptr)
+ 	{
+ 	  Error error (lexer.peek_token ()->get_locus (),
+ 		       "failed to parse type in closure parameter");
+ 	  add_error (std::move (error));
+ 
+ 	  // skip somewhere?
+ 	  return AST::ClosureParam::create_error ();
+ 	}
+     }
+ 
+   location_t loc = pattern->get_locus ();
+   return AST::ClosureParam (std::move (pattern), loc, std::move (type),
+ 			    std::move (outer_attrs));
+ }
+ 
+ // Parses a type (will further disambiguate any type).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::Type>
+ Parser<ManagedTokenSource>::parse_type (bool save_errors)
+ {
+   /* rules for all types:
+    * NeverType:               '!'
+    * SliceType:               '[' Type ']'
+    * InferredType:            '_'
+    * MacroInvocation:         SimplePath '!' DelimTokenTree
+    * ParenthesisedType:       '(' Type ')'
+    * ImplTraitType:           'impl' TypeParamBounds
+    *  TypeParamBounds (not type)  TypeParamBound ( '+' TypeParamBound )* '+'?
+    *  TypeParamBound          Lifetime | TraitBound
+    * ImplTraitTypeOneBound:   'impl' TraitBound
+    * TraitObjectType:         'dyn'? TypeParamBounds
+    * TraitObjectTypeOneBound: 'dyn'? TraitBound
+    *  TraitBound              '?'? ForLifetimes? TypePath | '(' '?'?
+    * ForLifetimes? TypePath ')' BareFunctionType:        ForLifetimes?
+    * FunctionQualifiers 'fn' etc. ForLifetimes (not type) 'for' '<'
+    * LifetimeParams '>' FunctionQualifiers      ( 'async' | 'const' )?
+    * 'unsafe'?
+    * ('extern' abi?)? QualifiedPathInType:     '<' Type ( 'as' TypePath )? '>'
+    * (
+    * '::' TypePathSegment )+ TypePath:                '::'? TypePathSegment (
+    * '::' TypePathSegment)* ArrayType:               '[' Type ';' Expr ']'
+    * ReferenceType:           '&' Lifetime? 'mut'? TypeNoBounds
+    * RawPointerType:          '*' ( 'mut' | 'const' ) TypeNoBounds
+    * TupleType:               '(' Type etc. - regular tuple stuff. Also
+    * regular tuple vs parenthesised precedence
+    *
+    * Disambiguate between macro and type path via type path being parsed, and
+    * then if '!' found, convert type path to simple path for macro. Usual
+    * disambiguation for tuple vs parenthesised. For ImplTraitType and
+    * TraitObjectType individual disambiguations, they seem more like "special
+    * cases", so probably just try to parse the more general ImplTraitType or
+    * TraitObjectType and return OneBound versions if they satisfy those
+    * criteria. */
+ 
+   const_TokenPtr t = lexer.peek_token ();
+   switch (t->get_id ())
+     {
+     case EXCLAM:
+       // never type - can't be macro as no path beforehand
+       lexer.skip_token ();
+       return std::unique_ptr<AST::NeverType> (
+ 	new AST::NeverType (t->get_locus ()));
+     case LEFT_SQUARE:
+       // slice type or array type - requires further disambiguation
+       return parse_slice_or_array_type ();
+     case LEFT_SHIFT:
+     case LEFT_ANGLE:
+       {
+ 	// qualified path in type
+ 	AST::QualifiedPathInType path = parse_qualified_path_in_type ();
+ 	if (path.is_error ())
+ 	  {
+ 	    if (save_errors)
+ 	      {
+ 		Error error (t->get_locus (),
+ 			     "failed to parse qualified path in type");
+ 		add_error (std::move (error));
+ 	      }
+ 
+ 	    return nullptr;
+ 	  }
+ 	return std::unique_ptr<AST::QualifiedPathInType> (
+ 	  new AST::QualifiedPathInType (std::move (path)));
+       }
+     case UNDERSCORE:
+       // inferred type
+       lexer.skip_token ();
+       return std::unique_ptr<AST::InferredType> (
+ 	new AST::InferredType (t->get_locus ()));
+     case ASTERISK:
+       // raw pointer type
+       return parse_raw_pointer_type ();
+     case AMP: // does this also include AMP_AMP?
+     case LOGICAL_AND:
+       // reference type
+       return parse_reference_type ();
+     case LIFETIME:
+       {
+ 	/* probably a lifetime bound, so probably type param bounds in
+ 	 * TraitObjectType */
+ 	std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
+ 	  = parse_type_param_bounds ();
+ 
+ 	return std::unique_ptr<AST::TraitObjectType> (
+ 	  new AST::TraitObjectType (std::move (bounds), t->get_locus (),
+ 				    false));
+       }
+     case IDENTIFIER:
+     case SUPER:
+     case SELF:
+     case SELF_ALIAS:
+     case CRATE:
+     case DOLLAR_SIGN:
+     case SCOPE_RESOLUTION:
+       {
+ 	// macro invocation or type path - requires further disambiguation.
+ 	/* for parsing path component of each rule, perhaps parse it as a
+ 	 * typepath and attempt conversion to simplepath if a trailing '!' is
+ 	 * found */
+ 	/* Type path also includes TraitObjectTypeOneBound BUT if it starts
+ 	 * with it, it is exactly the same as a TypePath syntactically, so
+ 	 * this is a syntactical ambiguity. As such, the parser will parse it
+ 	 * as a TypePath. This, however, does not prevent TraitObjectType from
+ 	 * starting with a typepath. */
+ 
+ 	// parse path as type path
+ 	AST::TypePath path = parse_type_path ();
+ 	if (path.is_error ())
+ 	  {
+ 	    if (save_errors)
+ 	      {
+ 		Error error (t->get_locus (),
+ 			     "failed to parse path as first component of type");
+ 		add_error (std::move (error));
+ 	      }
+ 
+ 	    return nullptr;
+ 	  }
+ 	location_t locus = path.get_locus ();
+ 
+ 	// branch on next token
+ 	t = lexer.peek_token ();
+ 	switch (t->get_id ())
+ 	  {
+ 	  case EXCLAM:
+ 	    {
+ 	      // macro invocation
+ 	      // convert to simple path
+ 	      AST::SimplePath macro_path = path.as_simple_path ();
+ 	      if (macro_path.is_empty ())
+ 		{
+ 		  if (save_errors)
+ 		    {
+ 		      Error error (t->get_locus (),
+ 				   "failed to parse simple path in macro "
+ 				   "invocation (for type)");
+ 		      add_error (std::move (error));
+ 		    }
+ 
+ 		  return nullptr;
+ 		}
+ 
+ 	      lexer.skip_token ();
+ 
+ 	      auto tok_tree = parse_delim_token_tree ();
+ 	      if (!tok_tree)
+ 		return nullptr;
+ 
+ 	      return AST::MacroInvocation::Regular (
+ 		AST::MacroInvocData (std::move (macro_path),
+ 				     std::move (tok_tree.value ())),
+ 		{}, locus);
+ 	    }
+ 	  case PLUS:
+ 	    {
+ 	      // type param bounds
+ 	      std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
+ 
+ 	      // convert type path to trait bound
+ 	      std::unique_ptr<AST::TraitBound> path_bound (
+ 		new AST::TraitBound (std::move (path), locus, false, false));
+ 	      bounds.push_back (std::move (path_bound));
+ 
+ 	      /* parse rest of bounds - FIXME: better way to find when to stop
+ 	       * parsing */
+ 	      while (t->get_id () == PLUS)
+ 		{
+ 		  lexer.skip_token ();
+ 
+ 		  // parse bound if it exists - if not, assume end of sequence
+ 		  std::unique_ptr<AST::TypeParamBound> bound
+ 		    = parse_type_param_bound ();
+ 		  if (bound == nullptr)
+ 		    {
+ 		      break;
+ 		    }
+ 		  bounds.push_back (std::move (bound));
+ 
+ 		  t = lexer.peek_token ();
+ 		}
+ 
+ 	      return std::unique_ptr<AST::TraitObjectType> (
+ 		new AST::TraitObjectType (std::move (bounds), locus, false));
+ 	    }
+ 	  default:
+ 	    // assume that this is a type path and not an error
+ 	    return std::unique_ptr<AST::TypePath> (
+ 	      new AST::TypePath (std::move (path)));
+ 	  }
+       }
+     case LEFT_PAREN:
+       /* tuple type or parenthesised type - requires further disambiguation
+        * (the usual). ok apparently can be a parenthesised TraitBound too, so
+        * could be TraitObjectTypeOneBound or TraitObjectType */
+       return parse_paren_prefixed_type ();
+     case FOR:
+       // TraitObjectTypeOneBound or BareFunctionType
+       return parse_for_prefixed_type ();
+     case ASYNC:
+     case CONST:
+     case UNSAFE:
+     case EXTERN_KW:
+     case FN_KW:
+       // bare function type (with no for lifetimes)
+       return parse_bare_function_type (std::vector<AST::LifetimeParam> ());
+     case IMPL:
+       lexer.skip_token ();
+       if (lexer.peek_token ()->get_id () == LIFETIME)
+ 	{
+ 	  /* cannot be one bound because lifetime prevents it from being
+ 	   * traitbound */
+ 	  std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
+ 	    = parse_type_param_bounds ();
+ 
+ 	  return std::unique_ptr<AST::ImplTraitType> (
+ 	    new AST::ImplTraitType (std::move (bounds), t->get_locus ()));
+ 	}
+       else
+ 	{
+ 	  // should be trait bound, so parse trait bound
+ 	  std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound ();
+ 	  if (initial_bound == nullptr)
+ 	    {
+ 	      if (save_errors)
+ 		{
+ 		  Error error (lexer.peek_token ()->get_locus (),
+ 			       "failed to parse ImplTraitType initial bound");
+ 		  add_error (std::move (error));
+ 		}
+ 
+ 	      return nullptr;
+ 	    }
+ 
+ 	  location_t locus = t->get_locus ();
+ 
+ 	  // short cut if next token isn't '+'
+ 	  t = lexer.peek_token ();
+ 	  if (t->get_id () != PLUS)
+ 	    {
+ 	      return std::unique_ptr<AST::ImplTraitTypeOneBound> (
+ 		new AST::ImplTraitTypeOneBound (std::move (initial_bound),
+ 						locus));
+ 	    }
+ 
+ 	  // parse additional type param bounds
+ 	  std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
+ 	  bounds.push_back (std::move (initial_bound));
+ 	  while (t->get_id () == PLUS)
+ 	    {
+ 	      lexer.skip_token ();
+ 
+ 	      // parse bound if it exists
+ 	      std::unique_ptr<AST::TypeParamBound> bound
+ 		= parse_type_param_bound ();
+ 	      if (bound == nullptr)
+ 		{
+ 		  // not an error as trailing plus may exist
+ 		  break;
+ 		}
+ 	      bounds.push_back (std::move (bound));
+ 
+ 	      t = lexer.peek_token ();
+ 	    }
+ 
+ 	  return std::unique_ptr<AST::ImplTraitType> (
+ 	    new AST::ImplTraitType (std::move (bounds), locus));
+ 	}
+     case DYN:
+     case QUESTION_MARK:
+       {
+ 	// either TraitObjectType or TraitObjectTypeOneBound
+ 	bool has_dyn = false;
+ 	if (t->get_id () == DYN)
+ 	  {
+ 	    lexer.skip_token ();
+ 	    has_dyn = true;
+ 	  }
+ 
+ 	if (lexer.peek_token ()->get_id () == LIFETIME)
+ 	  {
+ 	    /* cannot be one bound because lifetime prevents it from being
+ 	     * traitbound */
+ 	    std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
+ 	      = parse_type_param_bounds ();
+ 
+ 	    return std::unique_ptr<AST::TraitObjectType> (
+ 	      new AST::TraitObjectType (std::move (bounds), t->get_locus (),
+ 					has_dyn));
+ 	  }
+ 	else
+ 	  {
+ 	    // should be trait bound, so parse trait bound
+ 	    std::unique_ptr<AST::TraitBound> initial_bound
+ 	      = parse_trait_bound ();
+ 	    if (initial_bound == nullptr)
+ 	      {
+ 		if (save_errors)
+ 		  {
+ 		    Error error (
+ 		      lexer.peek_token ()->get_locus (),
+ 		      "failed to parse TraitObjectType initial bound");
+ 		    add_error (std::move (error));
+ 		  }
+ 
+ 		return nullptr;
+ 	      }
+ 
+ 	    // short cut if next token isn't '+'
+ 	    t = lexer.peek_token ();
+ 	    if (t->get_id () != PLUS)
+ 	      {
+ 		// convert trait bound to value object
+ 		AST::TraitBound value_bound (*initial_bound);
+ 
+ 		// DEBUG: removed as unique ptr, so should auto delete
+ 		// delete initial_bound;
+ 
+ 		return std::unique_ptr<AST::TraitObjectTypeOneBound> (
+ 		  new AST::TraitObjectTypeOneBound (std::move (value_bound),
+ 						    t->get_locus (), has_dyn));
+ 	      }
+ 
+ 	    // parse additional type param bounds
+ 	    std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
+ 	    bounds.push_back (std::move (initial_bound));
+ 	    while (t->get_id () == PLUS)
+ 	      {
+ 		lexer.skip_token ();
+ 
+ 		// parse bound if it exists
+ 		std::unique_ptr<AST::TypeParamBound> bound
+ 		  = parse_type_param_bound ();
+ 		if (bound == nullptr)
+ 		  {
+ 		    // not an error as trailing plus may exist
+ 		    break;
+ 		  }
+ 		bounds.push_back (std::move (bound));
+ 
+ 		t = lexer.peek_token ();
+ 	      }
+ 
+ 	    return std::unique_ptr<AST::TraitObjectType> (
+ 	      new AST::TraitObjectType (std::move (bounds), t->get_locus (),
+ 					has_dyn));
+ 	  }
+       }
+     default:
+       if (save_errors)
+ 	add_error (Error (t->get_locus (), "unrecognised token %qs in type",
+ 			  t->get_token_description ()));
+ 
+       return nullptr;
+     }
+ }
+ 
+ /* Parses a type that has '(' as its first character. Returns a tuple type,
+  * parenthesised type, TraitObjectTypeOneBound, or TraitObjectType depending
+  * on following characters. */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::Type>
+ Parser<ManagedTokenSource>::parse_paren_prefixed_type ()
+ {
+   /* NOTE: Syntactical ambiguity of a parenthesised trait bound is considered
+    * a trait bound, not a parenthesised type, so that it can still be used in
+    * type param bounds. */
+ 
+   /* NOTE: this implementation is really shit but I couldn't think of a better
+    * one. It requires essentially breaking polymorphism and downcasting via
+    * virtual method abuse, as it was copied from the rustc implementation (in
+    * which types are reified due to tagged union), after a more OOP attempt by
+    * me failed. */
+   location_t left_delim_locus = lexer.peek_token ()->get_locus ();
+ 
+   // skip left delim
+   lexer.skip_token ();
+   /* while next token isn't close delim, parse comma-separated types, saving
+    * whether trailing comma happens */
+   const_TokenPtr t = lexer.peek_token ();
+   bool trailing_comma = true;
+   std::vector<std::unique_ptr<AST::Type>> types;
+ 
+   while (t->get_id () != RIGHT_PAREN)
+     {
+       std::unique_ptr<AST::Type> type = parse_type ();
+       if (type == nullptr)
+ 	{
+ 	  Error error (t->get_locus (),
+ 		       "failed to parse type inside parentheses (probably "
+ 		       "tuple or parenthesised)");
+ 	  add_error (std::move (error));
+ 
+ 	  return nullptr;
+ 	}
+       types.push_back (std::move (type));
+ 
+       t = lexer.peek_token ();
+       if (t->get_id () != COMMA)
+ 	{
+ 	  trailing_comma = false;
+ 	  break;
+ 	}
+       lexer.skip_token ();
+ 
+       t = lexer.peek_token ();
+     }
+ 
+   if (!skip_token (RIGHT_PAREN))
+     {
+       return nullptr;
+     }
+ 
+   // if only one type and no trailing comma, then not a tuple type
+   if (types.size () == 1 && !trailing_comma)
+     {
+       // must be a TraitObjectType (with more than one bound)
+       if (lexer.peek_token ()->get_id () == PLUS)
+ 	{
+ 	  // create type param bounds vector
+ 	  std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
+ 
+ 	  // HACK: convert type to traitbound and add to bounds
+ 	  std::unique_ptr<AST::Type> released_ptr = std::move (types[0]);
+ 	  std::unique_ptr<AST::TraitBound> converted_bound (
+ 	    released_ptr->to_trait_bound (true));
+ 	  if (converted_bound == nullptr)
+ 	    {
+ 	      Error error (
+ 		lexer.peek_token ()->get_locus (),
+ 		"failed to hackily converted parsed type to trait bound");
+ 	      add_error (std::move (error));
+ 
+ 	      return nullptr;
+ 	    }
+ 	  bounds.push_back (std::move (converted_bound));
+ 
+ 	  t = lexer.peek_token ();
+ 	  while (t->get_id () == PLUS)
+ 	    {
+ 	      lexer.skip_token ();
+ 
+ 	      // attempt to parse typeparambound
+ 	      std::unique_ptr<AST::TypeParamBound> bound
+ 		= parse_type_param_bound ();
+ 	      if (bound == nullptr)
+ 		{
+ 		  // not an error if null
+ 		  break;
+ 		}
+ 	      bounds.push_back (std::move (bound));
+ 
+ 	      t = lexer.peek_token ();
+ 	    }
+ 
+ 	  return std::unique_ptr<AST::TraitObjectType> (
+ 	    new AST::TraitObjectType (std::move (bounds), left_delim_locus,
+ 				      false));
+ 	}
+       else
+ 	{
+ 	  // release vector pointer
+ 	  std::unique_ptr<AST::Type> released_ptr = std::move (types[0]);
+ 	  /* HACK: attempt to convert to trait bound. if fails, parenthesised
+ 	   * type */
+ 	  std::unique_ptr<AST::TraitBound> converted_bound (
+ 	    released_ptr->to_trait_bound (true));
+ 	  if (converted_bound == nullptr)
+ 	    {
+ 	      // parenthesised type
+ 	      return std::unique_ptr<AST::ParenthesisedType> (
+ 		new AST::ParenthesisedType (std::move (released_ptr),
+ 					    left_delim_locus));
+ 	    }
+ 	  else
+ 	    {
+ 	      // trait object type (one bound)
+ 
+ 	      // get value semantics trait bound
+ 	      AST::TraitBound value_bound (*converted_bound);
+ 
+ 	      return std::unique_ptr<AST::TraitObjectTypeOneBound> (
+ 		new AST::TraitObjectTypeOneBound (value_bound,
+ 						  left_delim_locus));
+ 	    }
+ 	}
+     }
+   else
+     {
+       return std::unique_ptr<AST::TupleType> (
+ 	new AST::TupleType (std::move (types), left_delim_locus));
+     }
+   /* TODO: ensure that this ensures that dynamic dispatch for traits is not
+    * lost somehow */
+ }
+ 
+ /* Parses a type that has 'for' as its first character. This means it has a
+  * "for lifetimes", so returns either a BareFunctionType, TraitObjectType, or
+  * TraitObjectTypeOneBound depending on following characters. */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::Type>
+ Parser<ManagedTokenSource>::parse_for_prefixed_type ()
+ {
+   location_t for_locus = lexer.peek_token ()->get_locus ();
+   // parse for lifetimes in type
+   std::vector<AST::LifetimeParam> for_lifetimes = parse_for_lifetimes ();
+ 
+   // branch on next token - either function or a trait type
+   const_TokenPtr t = lexer.peek_token ();
+   switch (t->get_id ())
+     {
+     case ASYNC:
+     case CONST:
+     case UNSAFE:
+     case EXTERN_KW:
+     case FN_KW:
+       return parse_bare_function_type (std::move (for_lifetimes));
+     case SCOPE_RESOLUTION:
+     case IDENTIFIER:
+     case SUPER:
+     case SELF:
+     case SELF_ALIAS:
+     case CRATE:
+     case DOLLAR_SIGN:
+       {
+ 	// path, so trait type
+ 
+ 	// parse type path to finish parsing trait bound
+ 	AST::TypePath path = parse_type_path ();
+ 
+ 	t = lexer.peek_token ();
+ 	if (t->get_id () != PLUS)
+ 	  {
+ 	    // must be one-bound trait type
+ 	    // create trait bound value object
+ 	    AST::TraitBound bound (std::move (path), for_locus, false, false,
+ 				   std::move (for_lifetimes));
+ 
+ 	    return std::unique_ptr<AST::TraitObjectTypeOneBound> (
+ 	      new AST::TraitObjectTypeOneBound (std::move (bound), for_locus));
+ 	  }
+ 
+ 	/* more than one bound trait type (or at least parsed as it - could be
+ 	 * trailing '+') create trait bound pointer and bounds */
+ 	std::unique_ptr<AST::TraitBound> initial_bound (
+ 	  new AST::TraitBound (std::move (path), for_locus, false, false,
+ 			       std::move (for_lifetimes)));
+ 	std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
+ 	bounds.push_back (std::move (initial_bound));
+ 
+ 	while (t->get_id () == PLUS)
+ 	  {
+ 	    lexer.skip_token ();
+ 
+ 	    // parse type param bound if it exists
+ 	    std::unique_ptr<AST::TypeParamBound> bound
+ 	      = parse_type_param_bound ();
+ 	    if (bound == nullptr)
+ 	      {
+ 		// not an error - e.g. trailing plus
+ 		return nullptr;
+ 	      }
+ 	    bounds.push_back (std::move (bound));
+ 
+ 	    t = lexer.peek_token ();
+ 	  }
+ 
+ 	return std::unique_ptr<AST::TraitObjectType> (
+ 	  new AST::TraitObjectType (std::move (bounds), for_locus, false));
+       }
+     default:
+       // error
+       add_error (Error (t->get_locus (),
+ 			"unrecognised token %qs in bare function type or trait "
+ 			"object type or trait object type one bound",
+ 			t->get_token_description ()));
+ 
+       return nullptr;
+     }
+ }
+ 
+ // Parses a maybe named param used in bare function types.
+ template <typename ManagedTokenSource>
+ AST::MaybeNamedParam
+ Parser<ManagedTokenSource>::parse_maybe_named_param (AST::AttrVec outer_attrs)
+ {
+   /* Basically guess that param is named if first token is identifier or
+    * underscore and second token is semicolon. This should probably have no
+    * exceptions. rustc uses backtracking to parse these, but at the time of
+    * writing gccrs has no backtracking capabilities. */
+   const_TokenPtr current = lexer.peek_token ();
+   const_TokenPtr next = lexer.peek_token (1);
+ 
+   Identifier name;
+   AST::MaybeNamedParam::ParamKind kind = AST::MaybeNamedParam::UNNAMED;
+ 
+   if (current->get_id () == IDENTIFIER && next->get_id () == COLON)
+     {
+       // named param
+       name = {current};
+       kind = AST::MaybeNamedParam::IDENTIFIER;
+       lexer.skip_token (1);
+     }
+   else if (current->get_id () == UNDERSCORE && next->get_id () == COLON)
+     {
+       // wildcard param
+       name = {Values::Keywords::UNDERSCORE, current->get_locus ()};
+       kind = AST::MaybeNamedParam::WILDCARD;
+       lexer.skip_token (1);
+     }
+ 
+   // parse type (required)
+   std::unique_ptr<AST::Type> type = parse_type ();
+   if (type == nullptr)
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "failed to parse type in maybe named param");
+       add_error (std::move (error));
+ 
+       return AST::MaybeNamedParam::create_error ();
+     }
+ 
+   return AST::MaybeNamedParam (std::move (name), kind, std::move (type),
+ 			       std::move (outer_attrs), current->get_locus ());
+ }
+ 
+ /* Parses a bare function type (with the given for lifetimes for convenience -
+  * does not parse them itself). */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::BareFunctionType>
+ Parser<ManagedTokenSource>::parse_bare_function_type (
+   std::vector<AST::LifetimeParam> for_lifetimes)
+ {
+   // TODO: pass in for lifetime location as param
+   location_t best_try_locus = lexer.peek_token ()->get_locus ();
+ 
+   AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
+ 
+   if (!skip_token (FN_KW))
+     return nullptr;
+ 
+   if (!skip_token (LEFT_PAREN))
+     return nullptr;
+ 
+   // parse function params, if they exist
+   std::vector<AST::MaybeNamedParam> params;
+   bool is_variadic = false;
+   AST::AttrVec variadic_attrs;
+ 
+   const_TokenPtr t = lexer.peek_token ();
+   while (t->get_id () != RIGHT_PAREN)
+     {
+       AST::AttrVec temp_attrs = parse_outer_attributes ();
+ 
+       if (lexer.peek_token ()->get_id () == ELLIPSIS)
+ 	{
+ 	  lexer.skip_token ();
+ 	  is_variadic = true;
+ 	  variadic_attrs = std::move (temp_attrs);
+ 
+ 	  t = lexer.peek_token ();
+ 
+ 	  if (t->get_id () != RIGHT_PAREN)
+ 	    {
+ 	      Error error (t->get_locus (),
+ 			   "expected right parentheses after variadic in maybe "
+ 			   "named function "
+ 			   "parameters, found %qs",
+ 			   t->get_token_description ());
+ 	      add_error (std::move (error));
+ 
+ 	      return nullptr;
+ 	    }
+ 
+ 	  break;
+ 	}
+ 
+       AST::MaybeNamedParam param
+ 	= parse_maybe_named_param (std::move (temp_attrs));
+       if (param.is_error ())
+ 	{
+ 	  Error error (
+ 	    lexer.peek_token ()->get_locus (),
+ 	    "failed to parse maybe named param in bare function type");
+ 	  add_error (std::move (error));
+ 
+ 	  return nullptr;
+ 	}
+       params.push_back (std::move (param));
+ 
+       if (lexer.peek_token ()->get_id () != COMMA)
+ 	break;
+ 
+       lexer.skip_token ();
+       t = lexer.peek_token ();
+     }
+ 
+   if (!skip_token (RIGHT_PAREN))
+     return nullptr;
+ 
+   // bare function return type, if exists
+   std::unique_ptr<AST::TypeNoBounds> return_type = nullptr;
+   if (lexer.peek_token ()->get_id () == RETURN_TYPE)
+     {
+       lexer.skip_token ();
+ 
+       // parse required TypeNoBounds
+       return_type = parse_type_no_bounds ();
+       if (return_type == nullptr)
+ 	{
+ 	  Error error (lexer.peek_token ()->get_locus (),
+ 		       "failed to parse return type (type no bounds) in bare "
+ 		       "function type");
+ 	  add_error (std::move (error));
+ 
+ 	  return nullptr;
+ 	}
+     }
+ 
+   return std::unique_ptr<AST::BareFunctionType> (
+     new AST::BareFunctionType (std::move (for_lifetimes),
+ 			       std::move (qualifiers), std::move (params),
+ 			       is_variadic, std::move (variadic_attrs),
+ 			       std::move (return_type), best_try_locus));
+ }
+ 
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::ReferenceType>
+ Parser<ManagedTokenSource>::parse_reference_type_inner (location_t locus)
+ {
+   // parse optional lifetime
+   AST::Lifetime lifetime = AST::Lifetime::elided ();
+   if (lexer.peek_token ()->get_id () == LIFETIME)
+     {
+       auto parsed_lifetime = parse_lifetime (true);
+       if (parsed_lifetime)
+ 	{
+ 	  lifetime = parsed_lifetime.value ();
+ 	}
+       else
+ 	{
+ 	  Error error (lexer.peek_token ()->get_locus (),
+ 		       "failed to parse lifetime in reference type");
+ 	  add_error (std::move (error));
+ 
+ 	  return nullptr;
+ 	}
+     }
+ 
+   bool is_mut = false;
+   if (lexer.peek_token ()->get_id () == MUT)
+     {
+       lexer.skip_token ();
+       is_mut = true;
+     }
+ 
+   // parse type no bounds, which is required
+   std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
+   if (type == nullptr)
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "failed to parse referenced type in reference type");
+       add_error (std::move (error));
+ 
+       return nullptr;
+     }
+ 
+   return std::unique_ptr<AST::ReferenceType> (
+     new AST::ReferenceType (is_mut, std::move (type), locus,
+ 			    std::move (lifetime)));
+ }
+ 
+ // Parses a reference type (mutable or immutable, with given lifetime).
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::ReferenceType>
+ Parser<ManagedTokenSource>::parse_reference_type ()
+ {
+   auto t = lexer.peek_token ();
+   auto locus = t->get_locus ();
+ 
+   switch (t->get_id ())
+     {
+     case AMP:
+       skip_token (AMP);
+       return parse_reference_type_inner (locus);
+     case LOGICAL_AND:
+       skip_token (LOGICAL_AND);
+       return std::unique_ptr<AST::ReferenceType> (
+ 	new AST::ReferenceType (false, parse_reference_type_inner (locus),
+ 				locus));
+     default:
+       rust_unreachable ();
+     }
+ }
+ 
+ // Parses a raw (unsafe) pointer type.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::RawPointerType>
+ Parser<ManagedTokenSource>::parse_raw_pointer_type ()
+ {
+   location_t locus = lexer.peek_token ()->get_locus ();
+   skip_token (ASTERISK);
+ 
+   AST::RawPointerType::PointerType kind = AST::RawPointerType::CONST;
+ 
+   // branch on next token for pointer kind info
+   const_TokenPtr t = lexer.peek_token ();
+   switch (t->get_id ())
+     {
+     case MUT:
+       kind = AST::RawPointerType::MUT;
+       lexer.skip_token ();
+       break;
+     case CONST:
+       kind = AST::RawPointerType::CONST;
+       lexer.skip_token ();
+       break;
+     default:
+       add_error (Error (t->get_locus (),
+ 			"unrecognised token %qs in raw pointer type",
+ 			t->get_token_description ()));
+ 
+       return nullptr;
+     }
+ 
+   // parse type no bounds (required)
+   std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
+   if (type == nullptr)
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "failed to parse pointed type of raw pointer type");
+       add_error (std::move (error));
+ 
+       return nullptr;
+     }
+ 
+   return std::unique_ptr<AST::RawPointerType> (
+     new AST::RawPointerType (kind, std::move (type), locus));
+ }
+ 
+ /* Parses a slice or array type, depending on following arguments (as
+  * lookahead is not possible). */
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::TypeNoBounds>
+ Parser<ManagedTokenSource>::parse_slice_or_array_type ()
+ {
+   location_t locus = lexer.peek_token ()->get_locus ();
+   skip_token (LEFT_SQUARE);
+ 
+   // parse inner type (required)
+   std::unique_ptr<AST::Type> inner_type = parse_type ();
+   if (inner_type == nullptr)
+     {
+       Error error (lexer.peek_token ()->get_locus (),
+ 		   "failed to parse inner type in slice or array type");
+       add_error (std::move (error));
+ 
+       return nullptr;
+     }
+ 
+   // branch on next token
+   const_TokenPtr t = lexer.peek_token ();
+   switch (t->get_id ())
+     {
+     case RIGHT_SQUARE:
+       // slice type
+       lexer.skip_token ();
+ 
+       return std::unique_ptr<AST::SliceType> (
+ 	new AST::SliceType (std::move (inner_type), locus));
+     case SEMICOLON:
+       {
+ 	// array type
+ 	lexer.skip_token ();
+ 
+ 	// parse required array size expression
+ 	auto size = parse_anon_const ();
+ 
+ 	if (!size)
+ 	  {
+ 	    Error error (lexer.peek_token ()->get_locus (),
+ 			 "failed to parse size expression in array type");
+ 	    add_error (std::move (error));
+ 
+ 	    return nullptr;
+ 	  }
+ 
+ 	if (!skip_token (RIGHT_SQUARE))
+ 	  {
+ 	    return nullptr;
+ 	  }
+ 
+ 	return std::unique_ptr<AST::ArrayType> (
+ 	  new AST::ArrayType (std::move (inner_type), std::move (*size),
+ 			      locus));
+       }
+     default:
+       // error
+       add_error (
+ 	Error (t->get_locus (),
+ 	       "unrecognised token %qs in slice or array type after inner type",
+ 	       t->get_token_description ()));
+ 
+       return nullptr;
+     }
+ }
+ 
+ // Parses a type, taking into account type boundary disambiguation.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::TypeNoBounds>
+ Parser<ManagedTokenSource>::parse_type_no_bounds ()
+ {
+   const_TokenPtr t = lexer.peek_token ();
+   switch (t->get_id ())
+     {
+     case EXCLAM:
+       // never type - can't be macro as no path beforehand
+       lexer.skip_token ();
+       return std::unique_ptr<AST::NeverType> (
+ 	new AST::NeverType (t->get_locus ()));
+     case LEFT_SQUARE:
+       // slice type or array type - requires further disambiguation
+       return parse_slice_or_array_type ();
+     case LEFT_SHIFT:
+     case LEFT_ANGLE:
+       {
+ 	// qualified path in type
+ 	AST::QualifiedPathInType path = parse_qualified_path_in_type ();
+ 	if (path.is_error ())
+ 	  {
+ 	    Error error (t->get_locus (),
+ 			 "failed to parse qualified path in type");
+ 	    add_error (std::move (error));
+ 
+ 	    return nullptr;
+ 	  }
+ 	return std::unique_ptr<AST::QualifiedPathInType> (
+ 	  new AST::QualifiedPathInType (std::move (path)));
+       }
+     case UNDERSCORE:
+       // inferred type
+       lexer.skip_token ();
+       return std::unique_ptr<AST::InferredType> (
+ 	new AST::InferredType (t->get_locus ()));
+     case ASTERISK:
+       // raw pointer type
+       return parse_raw_pointer_type ();
+     case AMP: // does this also include AMP_AMP? Yes! Which is... LOGICAL_AND?
+     case LOGICAL_AND:
+       // reference type
+       return parse_reference_type ();
+     case LIFETIME:
+       /* probably a lifetime bound, so probably type param bounds in
+        * TraitObjectType. this is not allowed, but detection here for error
+        * message */
+       add_error (Error (t->get_locus (),
+ 			"lifetime bounds (i.e. in type param bounds, in "
+ 			"TraitObjectType) are not allowed as TypeNoBounds"));
+ 
+       return nullptr;
+     case IDENTIFIER:
+     case SUPER:
+     case SELF:
+     case SELF_ALIAS:
+     case CRATE:
+     case DOLLAR_SIGN:
+     case SCOPE_RESOLUTION:
+       {
+ 	// macro invocation or type path - requires further disambiguation.
+ 	/* for parsing path component of each rule, perhaps parse it as a
+ 	 * typepath and attempt conversion to simplepath if a trailing '!' is
+ 	 * found */
+ 	/* Type path also includes TraitObjectTypeOneBound BUT if it starts
+ 	 * with it, it is exactly the same as a TypePath syntactically, so
+ 	 * this is a syntactical ambiguity. As such, the parser will parse it
+ 	 * as a TypePath. This, however, does not prevent TraitObjectType from
+ 	 * starting with a typepath. */
+ 
+ 	// parse path as type path
+ 	AST::TypePath path = parse_type_path ();
+ 	if (path.is_error ())
+ 	  {
+ 	    Error error (
+ 	      t->get_locus (),
+ 	      "failed to parse path as first component of type no bounds");
+ 	    add_error (std::move (error));
+ 
+ 	    return nullptr;
+ 	  }
+ 	location_t locus = path.get_locus ();
+ 
+ 	// branch on next token
+ 	t = lexer.peek_token ();
+ 	switch (t->get_id ())
+ 	  {
+ 	  case EXCLAM:
+ 	    {
+ 	      // macro invocation
+ 	      // convert to simple path
+ 	      AST::SimplePath macro_path = path.as_simple_path ();
+ 	      if (macro_path.is_empty ())
+ 		{
+ 		  Error error (t->get_locus (),
+ 			       "failed to parse simple path in macro "
+ 			       "invocation (for type)");
+ 		  add_error (std::move (error));
+ 
+ 		  return nullptr;
+ 		}
+ 
+ 	      lexer.skip_token ();
+ 
+ 	      auto tok_tree = parse_delim_token_tree ();
+ 	      if (!tok_tree)
+ 		return nullptr;
+ 
+ 	      return AST::MacroInvocation::Regular (
+ 		AST::MacroInvocData (std::move (macro_path),
+ 				     std::move (tok_tree.value ())),
+ 		{}, locus);
+ 	    }
+ 	  default:
+ 	    // assume that this is a type path and not an error
+ 	    return std::unique_ptr<AST::TypePath> (
+ 	      new AST::TypePath (std::move (path)));
+ 	  }
+       }
+     case LEFT_PAREN:
+       /* tuple type or parenthesised type - requires further disambiguation
+        * (the usual). ok apparently can be a parenthesised TraitBound too, so
+        * could be TraitObjectTypeOneBound */
+       return parse_paren_prefixed_type_no_bounds ();
+     case FOR:
+     case ASYNC:
+     case CONST:
+     case UNSAFE:
+     case EXTERN_KW:
+     case FN_KW:
+       // bare function type (with no for lifetimes)
+       return parse_bare_function_type (std::vector<AST::LifetimeParam> ());
+     case IMPL:
+       lexer.skip_token ();
+       if (lexer.peek_token ()->get_id () == LIFETIME)
+ 	{
+ 	  /* cannot be one bound because lifetime prevents it from being
+ 	   * traitbound not allowed as type no bounds, only here for error
+ 	   * message */
+ 	  Error error (
+ 	    lexer.peek_token ()->get_locus (),
+ 	    "lifetime (probably lifetime bound, in type param "
+ 	    "bounds, in ImplTraitType) is not allowed in TypeNoBounds");
+ 	  add_error (std::move (error));
+ 
+ 	  return nullptr;
+ 	}
+       else
+ 	{
+ 	  // should be trait bound, so parse trait bound
+ 	  std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound ();
+ 	  if (initial_bound == nullptr)
+ 	    {
+ 	      Error error (lexer.peek_token ()->get_locus (),
+ 			   "failed to parse ImplTraitTypeOneBound bound");
+ 	      add_error (std::move (error));
+ 
+ 	      return nullptr;
+ 	    }
+ 
+ 	  location_t locus = t->get_locus ();
+ 
+ 	  // ensure not a trait with multiple bounds
+ 	  t = lexer.peek_token ();
+ 	  if (t->get_id () == PLUS)
+ 	    {
+ 	      Error error (t->get_locus (),
+ 			   "plus after trait bound means an ImplTraitType, "
+ 			   "which is not allowed as a TypeNoBounds");
+ 	      add_error (std::move (error));
+ 
+ 	      return nullptr;
+ 	    }
+ 
+ 	  return std::unique_ptr<AST::ImplTraitTypeOneBound> (
+ 	    new AST::ImplTraitTypeOneBound (std::move (initial_bound), locus));
+ 	}
+     case DYN:
+     case QUESTION_MARK:
+       {
+ 	// either TraitObjectTypeOneBound
+ 	bool has_dyn = false;
+ 	if (t->get_id () == DYN)
+ 	  {
+ 	    lexer.skip_token ();
+ 	    has_dyn = true;
+ 	  }
+ 
+ 	if (lexer.peek_token ()->get_id () == LIFETIME)
+ 	  {
+ 	    /* means that cannot be TraitObjectTypeOneBound - so here for
+ 	     * error message */
+ 	    Error error (lexer.peek_token ()->get_locus (),
+ 			 "lifetime as bound in TraitObjectTypeOneBound "
+ 			 "is not allowed, so cannot be TypeNoBounds");
+ 	    add_error (std::move (error));
+ 
+ 	    return nullptr;
+ 	  }
+ 
+ 	// should be trait bound, so parse trait bound
+ 	std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound ();
+ 	if (initial_bound == nullptr)
+ 	  {
+ 	    Error error (
+ 	      lexer.peek_token ()->get_locus (),
+ 	      "failed to parse TraitObjectTypeOneBound initial bound");
+ 	    add_error (std::move (error));
+ 
+ 	    return nullptr;
+ 	  }
+ 
+ 	location_t locus = t->get_locus ();
+ 
+ 	// detect error with plus as next token
+ 	t = lexer.peek_token ();
+ 	if (t->get_id () == PLUS)
+ 	  {
+ 	    Error error (t->get_locus (),
+ 			 "plus after trait bound means a TraitObjectType, "
+ 			 "which is not allowed as a TypeNoBounds");
+ 	    add_error (std::move (error));
+ 
+ 	    return nullptr;
+ 	  }
+ 
+ 	// convert trait bound to value object
+ 	AST::TraitBound value_bound (*initial_bound);
+ 
+ 	return std::unique_ptr<AST::TraitObjectTypeOneBound> (
+ 	  new AST::TraitObjectTypeOneBound (std::move (value_bound), locus,
+ 					    has_dyn));
+       }
+     default:
+       add_error (Error (t->get_locus (),
+ 			"unrecognised token %qs in type no bounds",
+ 			t->get_token_description ()));
+ 
+       return nullptr;
+     }
+ }
+ 
+ // Parses a type no bounds beginning with '('.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::TypeNoBounds>
+ Parser<ManagedTokenSource>::parse_paren_prefixed_type_no_bounds ()
+ {
+   /* NOTE: this could probably be parsed without the HACK solution of
+    * parse_paren_prefixed_type, but I was lazy. So FIXME for future.*/
+ 
+   /* NOTE: again, syntactical ambiguity of a parenthesised trait bound is
+    * considered a trait bound, not a parenthesised type, so that it can still
+    * be used in type param bounds. */
+ 
+   location_t left_paren_locus = lexer.peek_token ()->get_locus ();
+ 
+   // skip left delim
+   lexer.skip_token ();
+   /* while next token isn't close delim, parse comma-separated types, saving
+    * whether trailing comma happens */
+   const_TokenPtr t = lexer.peek_token ();
+   bool trailing_comma = true;
+   std::vector<std::unique_ptr<AST::Type>> types;
+ 
+   while (t->get_id () != RIGHT_PAREN)
+     {
+       std::unique_ptr<AST::Type> type = parse_type ();
+       if (type == nullptr)
+ 	{
+ 	  Error error (t->get_locus (),
+ 		       "failed to parse type inside parentheses (probably "
+ 		       "tuple or parenthesised)");
+ 	  add_error (std::move (error));
+ 
+ 	  return nullptr;
+ 	}
+       types.push_back (std::move (type));
+ 
+       t = lexer.peek_token ();
+       if (t->get_id () != COMMA)
+ 	{
+ 	  trailing_comma = false;
+ 	  break;
+ 	}
+       lexer.skip_token ();
+ 
+       t = lexer.peek_token ();
+     }
+ 
+   if (!skip_token (RIGHT_PAREN))
+     {
+       return nullptr;
+     }
+ 
+   // if only one type and no trailing comma, then not a tuple type
+   if (types.size () == 1 && !trailing_comma)
+     {
+       // must be a TraitObjectType (with more than one bound)
+       if (lexer.peek_token ()->get_id () == PLUS)
+ 	{
+ 	  // error - this is not allowed for type no bounds
+ 	  Error error (lexer.peek_token ()->get_locus (),
+ 		       "plus (implying TraitObjectType as type param "
+ 		       "bounds) is not allowed in type no bounds");
+ 	  add_error (std::move (error));
+ 
+ 	  return nullptr;
+ 	}
+       else
+ 	{
+ 	  // release vector pointer
+ 	  std::unique_ptr<AST::Type> released_ptr = std::move (types[0]);
+ 	  /* HACK: attempt to convert to trait bound. if fails, parenthesised
+ 	   * type */
+ 	  std::unique_ptr<AST::TraitBound> converted_bound (
+ 	    released_ptr->to_trait_bound (true));
+ 	  if (converted_bound == nullptr)
+ 	    {
+ 	      // parenthesised type
+ 	      return std::unique_ptr<AST::ParenthesisedType> (
+ 		new AST::ParenthesisedType (std::move (released_ptr),
+ 					    left_paren_locus));
+ 	    }
+ 	  else
+ 	    {
+ 	      // trait object type (one bound)
+ 
+ 	      // get value semantics trait bound
+ 	      AST::TraitBound value_bound (*converted_bound);
+ 
+ 	      return std::unique_ptr<AST::TraitObjectTypeOneBound> (
+ 		new AST::TraitObjectTypeOneBound (value_bound,
+ 						  left_paren_locus));
+ 	    }
+ 	}
+     }
+   else
+     {
+       return std::unique_ptr<AST::TupleType> (
+ 	new AST::TupleType (std::move (types), left_paren_locus));
+     }
+   /* TODO: ensure that this ensures that dynamic dispatch for traits is not
+    * lost somehow */
+ }
+ 
+ // Parses tuple struct items if they exist. Does not parse parentheses.
+ template <typename ManagedTokenSource>
+ std::unique_ptr<AST::TupleStructItems>
+ Parser<ManagedTokenSource>::parse_tuple_struct_items ()
+ {
+   std::vector<std::unique_ptr<AST::Pattern>> lower_patterns;
+ 
+   // DEBUG
+   rust_debug ("started parsing tuple struct items");
+ 
+   // check for '..' at front
+   if (lexer.peek_token ()->get_id () == DOT_DOT)
+     {
+       // only parse upper patterns
+       lexer.skip_token ();
+ 
+       // DEBUG
+       rust_debug ("'..' at front in tuple struct items detected");
+ 
+       std::vector<std::unique_ptr<AST::Pattern>> upper_patterns;
+ 
+       const_TokenPtr t = lexer.peek_token ();
+       while (t->get_id () == COMMA)
+ 	{
+ 	  lexer.skip_token ();
+ 
+ 	  // break if right paren
+ 	  if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
+ 	    break;
+ 
+ 	  // parse pattern, which is now required
+ 	  std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
+ 	  if (pattern == nullptr)
+ 	    {
+ 	      Error error (lexer.peek_token ()->get_locus (),
+ 			   "failed to parse pattern in tuple struct items");
+ 	      add_error (std::move (error));
+ 
+ 	      return nullptr;
+ 	    }
+ 	  upper_patterns.push_back (std::move (pattern));
+ 
+ 	  t = lexer.peek_token ();
+ 	}
+ 
+       // DEBUG
+       rust_debug (
+ 	"finished parsing tuple struct items ranged (upper/none only)");
+ 
+       return std::unique_ptr<AST::TupleStructItemsHasRest> (
+ 	new AST::TupleStructItemsHasRest (std::move (lower_patterns),
+ 					  std::move (upper_patterns)));
+     }
+ 
+   // has at least some lower patterns
+   const_TokenPtr t = lexer.peek_token ();
+   while (t->get_id () != RIGHT_PAREN && t->get_id () != DOT_DOT)
+     {
+       // DEBUG
+       rust_debug ("about to parse pattern in tuple struct items");
+ 
+       // parse pattern, which is required
+       std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
+       if (pattern == nullptr)
+ 	{
+ 	  Error error (t->get_locus (),
+ 		       "failed to parse pattern in tuple struct items");
+ 	  add_error (std::move (error));
+ 
+ 	  return nullptr;
+ 	}
+       lower_patterns.push_back (std::move (pattern));
+ 
+       // DEBUG
+       rust_debug ("successfully parsed pattern in tuple struct items");
+ 
+       if (lexer.peek_token ()->get_id () != COMMA)
+ 	{
+ 	  // DEBUG
+ 	  rust_debug ("broke out of parsing patterns in tuple struct "
+ 		      "items as no comma");
+ 
+ 	  break;
+ 	}
+       lexer.skip_token ();
+       t = lexer.peek_token ();
+     }
+ 
+   // branch on next token
+   t = lexer.peek_token ();
+   switch (t->get_id ())
+     {
+     case RIGHT_PAREN:
+       return std::unique_ptr<AST::TupleStructItemsNoRest> (
+ 	new AST::TupleStructItemsNoRest (std::move (lower_patterns)));
+     case DOT_DOT:
+       {
+ 	// has an upper range that must be parsed separately
+ 	lexer.skip_token ();
+ 
+ 	std::vector<std::unique_ptr<AST::Pattern>> upper_patterns;
+ 
+ 	t = lexer.peek_token ();
+ 	while (t->get_id () == COMMA)
+ 	  {
+ 	    lexer.skip_token ();
+ 
+ 	    // break if next token is right paren
+ 	    if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
+ 	      break;
+ 
+ 	    // parse pattern, which is required
+ 	    std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
+ 	    if (pattern == nullptr)
+ 	      {
+ 		Error error (lexer.peek_token ()->get_locus (),
+ 			     "failed to parse pattern in tuple struct items");
+ 		add_error (std::move (error));
+ 
+ 		return nullptr;
+ 	      }
+ 	    upper_patterns.push_back (std::move (pattern));
+ 
+ 	    t = lexer.peek_token ();
+ 	  }
+ 
+ 	return std::unique_ptr<AST::TupleStructItemsHasRest> (
+ 	  new AST::TupleStructItemsHasRest (std::move (lower_patterns),
+ 					    std::move (upper_patterns)));
+       }
+     default:
+       // error
+       add_error (Error (t->get_locus (),
+ 			"unexpected token %qs in tuple struct items",
+ 			t->get_token_description ()));
+ 
+       return nullptr;
+     }
+ }
+ 
+ /* Parses a statement or expression (depending on whether a trailing semicolon
+  * exists). Useful for block expressions where it cannot be determined through
+  * lookahead whether it is a statement or expression to be parsed. */
+ template <typename ManagedTokenSource>
+ ExprOrStmt
+ Parser<ManagedTokenSource>::parse_stmt_or_expr ()
+ {
+   // quick exit for empty statement
+   const_TokenPtr t = lexer.peek_token ();
+   if (t->get_id () == SEMICOLON)
+     {
+       lexer.skip_token ();
+       std::unique_ptr<AST::EmptyStmt> stmt (
+ 	new AST::EmptyStmt (t->get_locus ()));
+       return ExprOrStmt (std::move (stmt));
+     }
+ 
+   // parse outer attributes
+   AST::AttrVec outer_attrs = parse_outer_attributes ();
+   ParseRestrictions restrictions;
+   restrictions.expr_can_be_stmt = true;
+   std::unique_ptr<AST::Expr> expr;
+ 
+   // parsing this will be annoying because of the many different possibilities
+   /* best may be just to copy paste in parse_item switch, and failing that try
+    * to parse outer attributes, and then pass them in to either a let
+    * statement or (fallback) expression statement. */
+   // FIXME: think of a way to do this without such a large switch?
+ 
+   /* FIXME: for expressions at least, the only way that they can really be
+    * parsed properly in this way is if they don't support operators on them.
+    * They must be pratt-parsed otherwise. As such due to composability, only
+    * explicit statements will have special cases here. This should roughly
+    * correspond to "expr-with-block", but this warning is here in case it
+    * isn't the case. */
+   t = lexer.peek_token ();
+   switch (t->get_id ())
+     {
+     case LET:
+       {
+ 	// let statement
+ 	std::unique_ptr<AST::LetStmt> stmt (
+ 	  parse_let_stmt (std::move (outer_attrs)));
+ 	return ExprOrStmt (std::move (stmt));
+       }
+     case PUB:
+     case MOD:
+     case EXTERN_KW:
+     case USE:
+     case FN_KW:
+     case TYPE:
+     case STRUCT_KW:
+     case ENUM_KW:
+     case CONST:
+     case STATIC_KW:
+     case AUTO:
+     case TRAIT:
+     case IMPL:
+       {
+ 	std::unique_ptr<AST::VisItem> item (
+ 	  parse_vis_item (std::move (outer_attrs)));
+ 	return ExprOrStmt (std::move (item));
+       }
+     /* TODO: implement union keyword but not really because of
+      * context-dependence crappy hack way to parse a union written below to
+      * separate it from the good code. */
+     // case UNION:
+     case UNSAFE:
+       { // maybe - unsafe traits are a thing
+ 	/* if any of these (should be all possible VisItem prefixes), parse a
+ 	 * VisItem - can't parse item because would require reparsing outer
+ 	 * attributes */
+ 	const_TokenPtr t2 = lexer.peek_token (1);
+ 	switch (t2->get_id ())
+ 	  {
+ 	  case LEFT_CURLY:
+ 	    {
+ 	      // unsafe block: parse as expression
+ 	      expr = parse_expr (std::move (outer_attrs), restrictions);
+ 	      break;
+ 	    }
+ 	  case AUTO:
+ 	  case TRAIT:
+ 	    {
+ 	      // unsafe trait
+ 	      std::unique_ptr<AST::VisItem> item (
+ 		parse_vis_item (std::move (outer_attrs)));
+ 	      return ExprOrStmt (std::move (item));
+ 	    }
+ 	  case EXTERN_KW:
+ 	  case FN_KW:
+ 	    {
+ 	      // unsafe function
+ 	      std::unique_ptr<AST::VisItem> item (
+ 		parse_vis_item (std::move (outer_attrs)));
+ 	      return ExprOrStmt (std::move (item));
+ 	    }
+ 	  case IMPL:
+ 	    {
+ 	      // unsafe trait impl
+ 	      std::unique_ptr<AST::VisItem> item (
+ 		parse_vis_item (std::move (outer_attrs)));
+ 	      return ExprOrStmt (std::move (item));
+ 	    }
+ 	  default:
+ 	    add_error (Error (t2->get_locus (),
+ 			      "unrecognised token %qs after parsing unsafe - "
+ 			      "expected beginning of expression or statement",
+ 			      t->get_token_description ()));
+ 
+ 	    // skip somewhere?
+ 	    return ExprOrStmt::create_error ();
+ 	  }
+ 	break;
+       }
+       /* FIXME: this is either a macro invocation or macro invocation semi.
+        * start parsing to determine which one it is. */
+       // FIXME: old code there
+ 
+     // crappy hack to do union "keyword"
+     case IDENTIFIER:
+       if (t->get_str () == Values::WeakKeywords::UNION
+ 	  && lexer.peek_token (1)->get_id () == IDENTIFIER)
+ 	{
+ 	  std::unique_ptr<AST::VisItem> item (
+ 	    parse_vis_item (std::move (outer_attrs)));
+ 	  return ExprOrStmt (std::move (item));
+ 	  // or should this go straight to parsing union?
+ 	}
+       else if (t->get_str () == Values::WeakKeywords::MACRO_RULES
+ 	       && lexer.peek_token (1)->get_id () == EXCLAM)
+ 	{
+ 	  // macro_rules! macro item
+ 	  std::unique_ptr<AST::Item> item (
+ 	    parse_macro_rules_def (std::move (outer_attrs)));
+ 	  return ExprOrStmt (std::move (item));
+ 	}
+       gcc_fallthrough ();
+     case SUPER:
+     case SELF:
+     case SELF_ALIAS:
+     case CRATE:
+     case SCOPE_RESOLUTION:
+     case DOLLAR_SIGN:
+       {
+ 	AST::PathInExpression path = parse_path_in_expression ();
+ 	std::unique_ptr<AST::Expr> null_denotation;
+ 
+ 	if (lexer.peek_token ()->get_id () == EXCLAM)
+ 	  {
+ 	    std::unique_ptr<AST::MacroInvocation> invoc
+ 	      = parse_macro_invocation_partial (std::move (path),
+ 						std::move (outer_attrs));
+ 	    if (invoc == nullptr)
+ 	      return ExprOrStmt::create_error ();
+ 
+ 	    if (restrictions.consume_semi && maybe_skip_token (SEMICOLON))
+ 	      {
+ 		invoc->add_semicolon ();
+ 		// Macro invocation with semicolon.
+ 		return ExprOrStmt (
+ 		  std::unique_ptr<AST::Stmt> (std::move (invoc)));
+ 	      }
+ 
+ 	    TokenId after_macro = lexer.peek_token ()->get_id ();
+ 
+ 	    AST::DelimType delim_type = invoc->get_invoc_data ()
+ 					  .get_delim_tok_tree ()
+ 					  .get_delim_type ();
+ 
+ 	    if (delim_type == AST::CURLY && after_macro != DOT
+ 		&& after_macro != QUESTION_MARK)
+ 	      {
+ 		rust_debug ("braced macro statement");
+ 		return ExprOrStmt (
+ 		  std::unique_ptr<AST::Stmt> (std::move (invoc)));
+ 	      }
+ 
+ 	    null_denotation = std::move (invoc);
+ 	  }
+ 	else
+ 	  {
+ 	    null_denotation
+ 	      = null_denotation_path (std::move (path), {}, restrictions);
+ 	  }
+ 
+ 	expr = left_denotations (std::move (null_denotation), LBP_LOWEST,
+ 				 std::move (outer_attrs), restrictions);
+ 	break;
+       }
+     default:
+       /* expression statement or expression itself - parse
+        * expression then make it statement if semi afterwards */
+       expr = parse_expr (std::move (outer_attrs), restrictions);
+       break;
+     }
+ 
+   const_TokenPtr after_expr = lexer.peek_token ();
+   if (after_expr->get_id () == SEMICOLON)
+     {
+       // must be expression statement
+       lexer.skip_token ();
+ 
+       if (expr)
+ 	{
+ 	  std::unique_ptr<AST::ExprStmt> stmt (
+ 	    new AST::ExprStmt (std::move (expr), t->get_locus (), true));
+ 	  return ExprOrStmt (std::move (stmt));
+ 	}
+       else
+ 	{
+ 	  return ExprOrStmt::create_error ();
+ 	}
+     }
+ 
+   if (expr && !expr->is_expr_without_block ()
+       && after_expr->get_id () != RIGHT_CURLY)
+     {
+       // block expression statement.
+       std::unique_ptr<AST::ExprStmt> stmt (
+ 	new AST::ExprStmt (std::move (expr), t->get_locus (), false));
+       return ExprOrStmt (std::move (stmt));
+     }
+ 
+   // return expression
+   return ExprOrStmt (std::move (expr));
+ }
+ 
+ } // namespace Rust
+ 
+ #include "rust-parse-impl-utils.hxx"
+ #include "rust-parse-impl-attribute.hxx"
+ #include "rust-parse-impl-ttree.hxx"
+ #include "rust-parse-impl-macro.hxx"
+ #include "rust-parse-impl-path.hxx"
+ #include "rust-parse-impl-pattern.hxx"
+ #include "rust-parse-impl-expr.hxx"
diff -Nrcpad gcc-16-20251214/gcc/rust/parse/rust-parse-utils.h gcc-16-20251221/gcc/rust/parse/rust-parse-utils.h
*** gcc-16-20251214/gcc/rust/parse/rust-parse-utils.h	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/rust/parse/rust-parse-utils.h	Sun Dec 21 22:32:07 2025
***************
*** 0 ****
--- 1,127 ----
+ 
+ // Copyright (C) 2025 Free Software Foundation, Inc.
+ 
+ // This file is part of GCC.
+ 
+ // GCC is free software; you can redistribute it and/or modify it under
+ // the terms of the GNU General Public License as published by the Free
+ // Software Foundation; either version 3, or (at your option) any later
+ // version.
+ 
+ // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+ // WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ // for more details.
+ 
+ // You should have received a copy of the GNU General Public License
+ // along with GCC; see the file COPYING3.  If not see
+ // <http://www.gnu.org/licenses/>.
+ 
+ #ifndef RUST_PARSE_UTILS_H
+ #define RUST_PARSE_UTILS_H
+ 
+ #include "rust-ast.h"
+ 
+ namespace Rust {
+ namespace Parse {
+ /* Utility structure to return members of an attribute body, was initially a
+  * tuple but tuples are ugly*/
+ struct AttributeBody
+ {
+   AST::SimplePath path;
+   std::unique_ptr<AST::AttrInput> input;
+   location_t locus;
+ };
+ 
+ namespace Utils {
+ 
+ /* Returns true if the token id matches the delimiter type. Note that this only
+  * operates for END delimiter tokens. */
+ inline bool
+ token_id_matches_delims (TokenId token_id, AST::DelimType delim_type)
+ {
+   return ((token_id == RIGHT_PAREN && delim_type == AST::PARENS)
+ 	  || (token_id == RIGHT_SQUARE && delim_type == AST::SQUARE)
+ 	  || (token_id == RIGHT_CURLY && delim_type == AST::CURLY));
+ }
+ 
+ /* Determines whether token is a valid simple path segment. This does not
+  * include scope resolution operators. */
+ inline bool
+ is_simple_path_segment (TokenId id)
+ {
+   switch (id)
+     {
+     case IDENTIFIER:
+     case SUPER:
+     case SELF:
+     case CRATE:
+       return true;
+     case DOLLAR_SIGN:
+       // assume that dollar sign leads to $crate
+       return true;
+     default:
+       return false;
+     }
+ }
+ 
+ /* Returns whether the token id is (or is likely to be) a right angle bracket.
+  * i.e. '>', '>>', '>=' and '>>=' tokens. */
+ inline bool
+ is_right_angle_tok (TokenId id)
+ {
+   switch (id)
+     {
+     case RIGHT_ANGLE:
+     case RIGHT_SHIFT:
+     case GREATER_OR_EQUAL:
+     case RIGHT_SHIFT_EQ:
+       return true;
+     default:
+       return false;
+     }
+ }
+ 
+ /* Returns whether the token can start a type (i.e. there is a valid type
+  * beginning with the token). */
+ inline bool
+ can_tok_start_type (TokenId id)
+ {
+   switch (id)
+     {
+     case EXCLAM:
+     case LEFT_SQUARE:
+     case LEFT_ANGLE:
+     case UNDERSCORE:
+     case ASTERISK:
+     case AMP:
+     case LIFETIME:
+     case IDENTIFIER:
+     case SUPER:
+     case SELF:
+     case SELF_ALIAS:
+     case CRATE:
+     case DOLLAR_SIGN:
+     case SCOPE_RESOLUTION:
+     case LEFT_PAREN:
+     case FOR:
+     case ASYNC:
+     case CONST:
+     case UNSAFE:
+     case EXTERN_KW:
+     case FN_KW:
+     case IMPL:
+     case DYN:
+     case QUESTION_MARK:
+       return true;
+     default:
+       return false;
+     }
+ }
+ 
+ } // namespace Utils
+ 
+ } // namespace Parse
+ } // namespace Rust
+ 
+ #endif /* !RUST_PARSE_UTILS_H */
diff -Nrcpad gcc-16-20251214/gcc/rust/parse/rust-parse.h gcc-16-20251221/gcc/rust/parse/rust-parse.h
*** gcc-16-20251214/gcc/rust/parse/rust-parse.h	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/rust/parse/rust-parse.h	Sun Dec 21 22:32:07 2025
*************** along with GCC; see the file COPYING3.
*** 22,27 ****
--- 22,29 ----
  #include "rust-lex.h"
  #include "rust-ast-full.h"
  #include "rust-diagnostics.h"
+ #include "rust-parse-error.h"
+ #include "rust-parse-utils.h"
  
  #include "expected.h"
  
*************** enum class ParseSelfError
*** 53,58 ****
--- 55,160 ----
    NOT_SELF,
  };
  
+ // Left binding powers of operations.
+ enum binding_powers
+ {
+   // Highest priority
+   LBP_HIGHEST = 100,
+ 
+   LBP_PATH = 95,
+ 
+   LBP_METHOD_CALL = 90,
+ 
+   LBP_FIELD_EXPR = 85,
+ 
+   LBP_FUNCTION_CALL = 80,
+   LBP_ARRAY_REF = LBP_FUNCTION_CALL,
+ 
+   LBP_QUESTION_MARK = 75, // unary postfix - counts as left
+ 
+   LBP_UNARY_PLUS = 70,		    // Used only when the null denotation is +
+   LBP_UNARY_MINUS = LBP_UNARY_PLUS, // Used only when the null denotation is -
+   LBP_UNARY_ASTERISK = LBP_UNARY_PLUS, // deref operator - unary prefix
+   LBP_UNARY_EXCLAM = LBP_UNARY_PLUS,
+   LBP_UNARY_AMP = LBP_UNARY_PLUS,
+   LBP_UNARY_AMP_MUT = LBP_UNARY_PLUS,
+ 
+   LBP_AS = 65,
+ 
+   LBP_MUL = 60,
+   LBP_DIV = LBP_MUL,
+   LBP_MOD = LBP_MUL,
+ 
+   LBP_PLUS = 55,
+   LBP_MINUS = LBP_PLUS,
+ 
+   LBP_L_SHIFT = 50,
+   LBP_R_SHIFT = LBP_L_SHIFT,
+ 
+   LBP_AMP = 45,
+ 
+   LBP_CARET = 40,
+ 
+   LBP_PIPE = 35,
+ 
+   LBP_EQUAL = 30,
+   LBP_NOT_EQUAL = LBP_EQUAL,
+   LBP_SMALLER_THAN = LBP_EQUAL,
+   LBP_SMALLER_EQUAL = LBP_EQUAL,
+   LBP_GREATER_THAN = LBP_EQUAL,
+   LBP_GREATER_EQUAL = LBP_EQUAL,
+ 
+   LBP_LOGICAL_AND = 25,
+ 
+   LBP_LOGICAL_OR = 20,
+ 
+   LBP_DOT_DOT = 15,
+   LBP_DOT_DOT_EQ = LBP_DOT_DOT,
+ 
+   // TODO: note all these assig operators are RIGHT associative!
+   LBP_ASSIG = 10,
+   LBP_PLUS_ASSIG = LBP_ASSIG,
+   LBP_MINUS_ASSIG = LBP_ASSIG,
+   LBP_MULT_ASSIG = LBP_ASSIG,
+   LBP_DIV_ASSIG = LBP_ASSIG,
+   LBP_MOD_ASSIG = LBP_ASSIG,
+   LBP_AMP_ASSIG = LBP_ASSIG,
+   LBP_PIPE_ASSIG = LBP_ASSIG,
+   LBP_CARET_ASSIG = LBP_ASSIG,
+   LBP_L_SHIFT_ASSIG = LBP_ASSIG,
+   LBP_R_SHIFT_ASSIG = LBP_ASSIG,
+ 
+   // return, break, and closures as lowest priority?
+   LBP_RETURN = 5,
+   LBP_BREAK = LBP_RETURN,
+   LBP_CLOSURE = LBP_RETURN, // unary prefix operators
+ 
+ #if 0
+   // rust precedences
+   // used for closures
+   PREC_CLOSURE = -40,
+   // used for break, continue, return, and yield
+   PREC_JUMP = -30,
+   // used for range (although weird comment in rustc about this)
+   PREC_RANGE = -10,
+   // used for binary operators mentioned below - also cast, colon (type),
+   // assign, assign_op
+   PREC_BINOP = FROM_ASSOC_OP,
+   // used for box, address_of, let, unary (again, weird comment on let)
+   PREC_PREFIX = 50,
+   // used for await, call, method call, field, index, try,
+   // inline asm, macro invocation
+   PREC_POSTFIX = 60,
+   // used for array, repeat, tuple, literal, path, paren, if,
+   // while, for, 'loop', match, block, try block, async, struct
+   PREC_PAREN = 99,
+   PREC_FORCE_PAREN = 100,
+ #endif
+ 
+   // lowest priority
+   LBP_LOWEST = 0
+ };
+ 
  /* HACK: used to resolve the expression-or-statement problem at the end of a
   * block by allowing either to be returned (technically). Tagged union would
   * probably take up the same amount of space. */
*************** public:
*** 180,186 ****
  			  location_t loc = UNKNOWN_LOCATION);
  
    bool is_macro_rules_def (const_TokenPtr t);
!   std::unique_ptr<AST::Item> parse_item (bool called_from_statement);
    std::unique_ptr<AST::Pattern> parse_pattern ();
    std::unique_ptr<AST::Pattern> parse_pattern_no_alt ();
  
--- 282,289 ----
  			  location_t loc = UNKNOWN_LOCATION);
  
    bool is_macro_rules_def (const_TokenPtr t);
!   tl::expected<std::unique_ptr<AST::Item>, Parse::Error::Item>
!   parse_item (bool called_from_statement);
    std::unique_ptr<AST::Pattern> parse_pattern ();
    std::unique_ptr<AST::Pattern> parse_pattern_no_alt ();
  
*************** public:
*** 202,212 ****
    std::unique_ptr<AST::AssociatedItem> parse_trait_impl_item ();
    AST::PathInExpression parse_path_in_expression ();
    std::vector<std::unique_ptr<AST::LifetimeParam>> parse_lifetime_params ();
!   AST::Visibility parse_visibility ();
    std::unique_ptr<AST::IdentifierPattern> parse_identifier_pattern ();
!   std::unique_ptr<AST::Token> parse_identifier_or_keyword_token ();
!   std::unique_ptr<AST::TokenTree> parse_token_tree ();
!   std::tuple<AST::SimplePath, std::unique_ptr<AST::AttrInput>, location_t>
    parse_attribute_body ();
    AST::AttrVec parse_inner_attributes ();
    std::unique_ptr<AST::MacroInvocation>
--- 305,318 ----
    std::unique_ptr<AST::AssociatedItem> parse_trait_impl_item ();
    AST::PathInExpression parse_path_in_expression ();
    std::vector<std::unique_ptr<AST::LifetimeParam>> parse_lifetime_params ();
!   tl::expected<AST::Visibility, Parse::Error::Visibility> parse_visibility ();
    std::unique_ptr<AST::IdentifierPattern> parse_identifier_pattern ();
!   tl::expected<std::unique_ptr<AST::Token>, Parse::Error::Token>
!   parse_identifier_or_keyword_token ();
!   tl::expected<std::unique_ptr<AST::TokenTree>, Parse::Error::TokenTree>
!   parse_token_tree ();
! 
!   tl::expected<Parse::AttributeBody, Parse::Error::AttributeBody>
    parse_attribute_body ();
    AST::AttrVec parse_inner_attributes ();
    std::unique_ptr<AST::MacroInvocation>
*************** private:
*** 232,249 ****
    void parse_statement_seq (bool (Parser::*done) ());
  
    // AST-related stuff - maybe move or something?
!   AST::Attribute parse_inner_attribute ();
!   AST::Attribute parse_outer_attribute ();
!   std::unique_ptr<AST::AttrInput> parse_attr_input ();
!   std::tuple<AST::SimplePath, std::unique_ptr<AST::AttrInput>, location_t>
!   parse_doc_comment ();
  
    // Path-related
!   AST::SimplePath parse_simple_path ();
!   AST::SimplePathSegment parse_simple_path_segment (int base_peek = 0);
    AST::TypePath parse_type_path ();
    std::unique_ptr<AST::TypePathSegment> parse_type_path_segment ();
!   AST::PathIdentSegment parse_path_ident_segment ();
    tl::optional<AST::GenericArg> parse_generic_arg ();
    AST::GenericArgs parse_path_generic_args ();
    AST::GenericArgsBinding parse_generic_args_binding ();
--- 338,359 ----
    void parse_statement_seq (bool (Parser::*done) ());
  
    // AST-related stuff - maybe move or something?
!   tl::expected<AST::Attribute, Parse::Error::Attribute>
!   parse_inner_attribute ();
!   tl::expected<AST::Attribute, Parse::Error::Attribute>
!   parse_outer_attribute ();
!   tl::expected<std::unique_ptr<AST::AttrInput>, Parse::Error::AttrInput>
!   parse_attr_input ();
!   Parse::AttributeBody parse_doc_comment ();
  
    // Path-related
!   tl::expected<AST::SimplePath, Parse::Error::SimplePath> parse_simple_path ();
!   tl::expected<AST::SimplePathSegment, Parse::Error::SimplePathSegment>
!   parse_simple_path_segment (int base_peek = 0);
    AST::TypePath parse_type_path ();
    std::unique_ptr<AST::TypePathSegment> parse_type_path_segment ();
!   tl::expected<AST::PathIdentSegment, Parse::Error::PathIdentSegment>
!   parse_path_ident_segment ();
    tl::optional<AST::GenericArg> parse_generic_arg ();
    AST::GenericArgs parse_path_generic_args ();
    AST::GenericArgsBinding parse_generic_args_binding ();
*************** private:
*** 260,266 ****
    AST::QualifiedPathInType parse_qualified_path_in_type ();
  
    // Token tree or macro related
!   AST::DelimTokenTree parse_delim_token_tree ();
    std::unique_ptr<AST::MacroRulesDefinition>
    parse_macro_rules_def (AST::AttrVec outer_attrs);
    std::unique_ptr<AST::MacroRulesDefinition>
--- 370,377 ----
    AST::QualifiedPathInType parse_qualified_path_in_type ();
  
    // Token tree or macro related
!   tl::expected<AST::DelimTokenTree, Parse::Error::DelimTokenTree>
!   parse_delim_token_tree ();
    std::unique_ptr<AST::MacroRulesDefinition>
    parse_macro_rules_def (AST::AttrVec outer_attrs);
    std::unique_ptr<AST::MacroRulesDefinition>
*************** public:
*** 742,748 ****
  
    // Parse items without parsing an entire crate. This function is the main
    // parsing loop of AST::Crate::parse_crate().
!   std::vector<std::unique_ptr<AST::Item>> parse_items ();
  
    // Main entry point for parser.
    std::unique_ptr<AST::Crate> parse_crate ();
--- 853,860 ----
  
    // Parse items without parsing an entire crate. This function is the main
    // parsing loop of AST::Crate::parse_crate().
!   tl::expected<std::vector<std::unique_ptr<AST::Item>>, Parse::Error::Items>
!   parse_items ();
  
    // Main entry point for parser.
    std::unique_ptr<AST::Crate> parse_crate ();
diff -Nrcpad gcc-16-20251214/gcc/rust/rust-session-manager.cc gcc-16-20251221/gcc/rust/rust-session-manager.cc
*** gcc-16-20251214/gcc/rust/rust-session-manager.cc	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/rust/rust-session-manager.cc	Sun Dec 21 22:32:07 2025
***************
*** 25,30 ****
--- 25,31 ----
  #include "rust-expression-yeast.h"
  #include "rust-hir-pattern-analysis.h"
  #include "rust-immutable-name-resolution-context.h"
+ #include "rust-location.h"
  #include "rust-unsafe-checker.h"
  #include "rust-lex.h"
  #include "rust-parse.h"
***************
*** 61,66 ****
--- 62,68 ----
  #include "selftest.h"
  #include "tm.h"
  #include "rust-target.h"
+ #include "rust-system.h"
  
  extern bool saw_errors (void);
  
*************** namespace Rust {
*** 71,76 ****
--- 73,79 ----
  const char *kLexDumpFile = "gccrs.lex.dump";
  const char *kASTDumpFile = "gccrs.ast.dump";
  const char *kASTPrettyDumpFile = "gccrs.ast-pretty.dump";
+ const char *kASTPrettyInternalDumpFile = "gccrs.ast-pretty-internal.dump";
  const char *kASTPrettyDumpFileExpanded = "gccrs.ast-pretty-expanded.dump";
  const char *kASTExpandedDumpFile = "gccrs.ast-expanded.dump";
  const char *kASTmacroResolutionDumpFile = "gccrs.ast-macro-resolution.dump";
*************** Session::handle_cfg_option (std::string
*** 325,330 ****
--- 328,335 ----
  bool
  Session::enable_dump (std::string arg)
  {
+   const std::string INTERNAL_DUMP_OPTION_TEXT = "internal";
+ 
    if (arg.empty ())
      {
        rust_error_at (
*************** Session::enable_dump (std::string arg)
*** 380,399 ****
      {
        options.enable_dump_option (CompileOptions::BIR_DUMP);
      }
    else
      {
        rust_error_at (
  	UNDEF_LOCATION,
  	"dump option %qs was unrecognised. choose %<lex%>, %<ast-pretty%>, "
! 	"%<register_plugins%>, %<injection%>, "
! 	"%<expansion%>, %<resolution%>, %<target_options%>, %<hir%>, "
! 	"%<hir-pretty%>, or %<all%>",
  	arg.c_str ());
        return false;
      }
    return true;
  }
  
  /* Actual main entry point for front-end. Called from langhook to parse files.
   */
  void
--- 385,443 ----
      {
        options.enable_dump_option (CompileOptions::BIR_DUMP);
      }
+   else if (!arg.compare (0, INTERNAL_DUMP_OPTION_TEXT.size (),
+ 			 INTERNAL_DUMP_OPTION_TEXT))
+     {
+       if (arg.size () == INTERNAL_DUMP_OPTION_TEXT.size ())
+ 	{
+ 	  options.enable_dump_option (CompileOptions::INTERNAL_DUMP);
+ 	}
+       else
+ 	{
+ 	  if (arg[INTERNAL_DUMP_OPTION_TEXT.size ()] != ':')
+ 	    {
+ 	      rust_error_at (UNDEF_LOCATION, "bad format for %qs",
+ 			     arg.c_str ());
+ 	      rust_inform (UNDEF_LOCATION,
+ 			   "to specify the nodes to ignore when "
+ 			   "dumping their description put a "
+ 			   "%<:%> then all the Nodes separated by comma");
+ 	      return false;
+ 	    }
+ 	  handle_excluded_node (arg);
+ 	  options.enable_dump_option (CompileOptions::INTERNAL_DUMP);
+ 	}
+     }
    else
      {
        rust_error_at (
  	UNDEF_LOCATION,
  	"dump option %qs was unrecognised. choose %<lex%>, %<ast-pretty%>, "
! 	"%<internal[:ignore1,ignore2,...]%>, %<register_plugins%>, "
! 	"%<injection%>, %<expansion%>, %<resolution%>, %<target_options%>, "
! 	"%<hir%>, %<hir-pretty%>, or %<all%>",
  	arg.c_str ());
        return false;
      }
    return true;
  }
  
+ /* Helper function to parse a string when dump internal to get node to blacklist
+  */
+ 
+ void
+ Session::handle_excluded_node (std::string arg)
+ {
+   size_t colon = arg.find (":");
+   size_t suffix_size = arg.size () - colon;
+   std::istringstream blist_str (arg.substr (colon + 1, suffix_size));
+   std::string token;
+   while (std::getline (blist_str, token, ','))
+     {
+       options.add_excluded (token);
+     }
+ }
+ 
  /* Actual main entry point for front-end. Called from langhook to parse files.
   */
  void
*************** Session::compile_crate (const char *file
*** 561,566 ****
--- 605,614 ----
      {
        dump_ast_pretty (*ast_crate.get ());
      }
+   if (options.dump_option_enabled (CompileOptions::INTERNAL_DUMP))
+     {
+       dump_ast_pretty_internal (*ast_crate.get ());
+     }
  
    // setup the mappings for this AST
    CrateNum current_crate = mappings.get_current_crate ();
*************** Session::injection (AST::Crate &crate)
*** 873,879 ****
  
        // create "extern crate" item with the name
        std::unique_ptr<AST::ExternCrate> extern_crate (
! 	new AST::ExternCrate (*it, AST::Visibility::create_error (),
  			      {std::move (attr)}, UNKNOWN_LOCATION));
  
        // insert at beginning
--- 921,927 ----
  
        // create "extern crate" item with the name
        std::unique_ptr<AST::ExternCrate> extern_crate (
! 	new AST::ExternCrate (*it, AST::Visibility::create_private (),
  			      {std::move (attr)}, UNKNOWN_LOCATION));
  
        // insert at beginning
*************** Session::dump_ast_pretty (AST::Crate &cr
*** 1021,1026 ****
--- 1069,1101 ----
  
    out.close ();
  }
+ 
+ void
+ Session::dump_ast_pretty_internal (AST::Crate &crate) const
+ {
+   std::ofstream out;
+   out.open (kASTPrettyInternalDumpFile);
+ 
+   if (out.fail ())
+     {
+       rust_error_at (UNKNOWN_LOCATION, "cannot open %s:%m; ignored",
+ 		     kASTDumpFile);
+       return;
+     }
+ 
+   std::set<std::string> str_tmp = options.get_excluded ();
+ 
+   AST::Dump (out,
+ 	     AST::Dump::Configuration{
+ 	       AST::Dump::Configuration::InternalComment::Dump,
+ 	       AST::Dump::Configuration::NodeDescription::Dump,
+ 	       AST::Dump::Configuration::Comment::Dump,
+ 	     },
+ 	     str_tmp)
+     .go (crate);
+ 
+   out.close ();
+ }
  
  void
  Session::dump_name_resolution (Resolver2_0::NameResolutionContext &ctx) const
diff -Nrcpad gcc-16-20251214/gcc/rust/rust-session-manager.h gcc-16-20251221/gcc/rust/rust-session-manager.h
*** gcc-16-20251214/gcc/rust/rust-session-manager.h	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/rust/rust-session-manager.h	Sun Dec 21 22:32:07 2025
*************** struct CompileOptions
*** 223,232 ****
--- 223,237 ----
      HIR_DUMP,
      HIR_DUMP_PRETTY,
      BIR_DUMP,
+     INTERNAL_DUMP,
    };
  
    std::set<DumpOption> dump_options;
  
+   /* List of node that is not print during the dump of the ast with internal
+    * comment */
+   std::set<std::string> excluded_node;
+ 
    /* configuration options - actually useful for conditional compilation and
     * whatever data related to target arch, features, os, family, env, endian,
     * pointer width, vendor */
*************** struct CompileOptions
*** 290,297 ****
--- 295,311 ----
      enable_dump_option (DumpOption::HIR_DUMP);
      enable_dump_option (DumpOption::HIR_DUMP_PRETTY);
      enable_dump_option (DumpOption::BIR_DUMP);
+     enable_dump_option (DumpOption::INTERNAL_DUMP);
    }
  
+   void add_excluded (std::string node)
+   {
+     rust_assert (!node.empty ());
+     excluded_node.insert (node);
+   }
+ 
+   const std::set<std::string> get_excluded () const { return excluded_node; }
+ 
    void set_crate_name (std::string name)
    {
      rust_assert (!name.empty ());
*************** private:
*** 410,419 ****
--- 424,436 ----
  
    void dump_lex (Parser<Lexer> &parser) const;
    void dump_ast_pretty (AST::Crate &crate, bool expanded = false) const;
+   void dump_ast_pretty_internal (AST::Crate &crate) const;
    void dump_name_resolution (Resolver2_0::NameResolutionContext &ctx) const;
    void dump_hir (HIR::Crate &crate) const;
    void dump_hir_pretty (HIR::Crate &crate) const;
  
+   void handle_excluded_node (std::string arg);
+ 
    // pipeline stages - TODO maybe move?
    /* Register plugins pipeline stage. TODO maybe move to another object?
     * Currently dummy stage. In future will handle attribute injection
diff -Nrcpad gcc-16-20251214/gcc/sanopt.cc gcc-16-20251221/gcc/sanopt.cc
*** gcc-16-20251214/gcc/sanopt.cc	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/sanopt.cc	Sun Dec 21 22:32:07 2025
*************** sanopt_optimize_walker (basic_block bb,
*** 814,820 ****
        if (!is_gimple_call (stmt))
  	{
  	  /* Handle asm volatile or asm with "memory" clobber
! 	     the same as potentionally freeing call.  */
  	  gasm *asm_stmt = dyn_cast <gasm *> (stmt);
  	  if (asm_stmt
  	      && asan_check_optimize
--- 814,820 ----
        if (!is_gimple_call (stmt))
  	{
  	  /* Handle asm volatile or asm with "memory" clobber
! 	     the same as potentially freeing call.  */
  	  gasm *asm_stmt = dyn_cast <gasm *> (stmt);
  	  if (asm_stmt
  	      && asan_check_optimize
*************** pass_sanopt::execute (function *fun)
*** 1330,1336 ****
        sanitize_asan_mark_poison ();
      }
  
!   if (asan_sanitize_stack_p () || hwasan_sanitize_stack_p ())
      sanitize_rewrite_addressable_params (fun);
  
    bool use_calls = param_asan_instrumentation_with_call_threshold < INT_MAX
--- 1330,1336 ----
        sanitize_asan_mark_poison ();
      }
  
!   if (asan_sanitize_stack_p () || hwassist_sanitize_stack_p ())
      sanitize_rewrite_addressable_params (fun);
  
    bool use_calls = param_asan_instrumentation_with_call_threshold < INT_MAX
diff -Nrcpad gcc-16-20251214/gcc/target-insns.def gcc-16-20251221/gcc/target-insns.def
*** gcc-16-20251214/gcc/target-insns.def	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/target-insns.def	Sun Dec 21 22:32:07 2025
*************** DEF_TARGET_INSN (call_value_pop, (rtx x0
*** 47,52 ****
--- 47,53 ----
  DEF_TARGET_INSN (casesi, (rtx x0, rtx x1, rtx x2, rtx x3, rtx x4))
  DEF_TARGET_INSN (check_stack, (rtx x0))
  DEF_TARGET_INSN (clear_cache, (rtx x0, rtx x1))
+ DEF_TARGET_INSN (compose_tag, (rtx x0, rtx x1, rtx x2))
  DEF_TARGET_INSN (doloop_begin, (rtx x0, rtx x1))
  DEF_TARGET_INSN (doloop_end, (rtx x0, rtx x1))
  DEF_TARGET_INSN (eh_return, (rtx x0))
*************** DEF_TARGET_INSN (stack_protect_combined_
*** 102,107 ****
--- 103,109 ----
  DEF_TARGET_INSN (stack_protect_test, (rtx x0, rtx x1, rtx x2))
  DEF_TARGET_INSN (store_multiple, (rtx x0, rtx x1, rtx x2))
  DEF_TARGET_INSN (tablejump, (rtx x0, rtx x1))
+ DEF_TARGET_INSN (tag_memory, (rtx x0, rtx x1, rtx x2))
  DEF_TARGET_INSN (trap, (void))
  DEF_TARGET_INSN (unique, (void))
  DEF_TARGET_INSN (untyped_call, (rtx x0, rtx x1, rtx x2))
diff -Nrcpad gcc-16-20251214/gcc/target.def gcc-16-20251221/gcc/target.def
*** gcc-16-20251214/gcc/target.def	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/target.def	Sun Dec 21 22:32:07 2025
*************** DEFHOOK
*** 7577,7583 ****
   "Return an RTX representing the value of @var{untagged} but with a\n\
  (possibly) random tag in it.\n\
  Put that value into @var{target} if it is convenient to do so.\n\
! This function is used to generate a tagged base for the current stack frame.",
    rtx, (rtx untagged, rtx target), default_memtag_insert_random_tag)
  
  DEFHOOK
--- 7577,7585 ----
   "Return an RTX representing the value of @var{untagged} but with a\n\
  (possibly) random tag in it.\n\
  Put that value into @var{target} if it is convenient to do so.\n\
! This function is used to generate a tagged base for the current stack frame.\n\
! It is also used by memtag-stack sanitizer to emit specific memory tagging\n\
! instructions.",
    rtx, (rtx untagged, rtx target), default_memtag_insert_random_tag)
  
  DEFHOOK
*************** The resulting RTX must either be a valid
*** 7589,7595 ****
  put into an operand with @code{force_operand}.\n\
  \n\
  Unlike other memtag hooks, this must return an expression and not emit any\n\
! RTL.",
    rtx, (rtx base, poly_int64 addr_offset, uint8_t tag_offset),
    default_memtag_add_tag)
  
--- 7591,7597 ----
  put into an operand with @code{force_operand}.\n\
  \n\
  Unlike other memtag hooks, this must return an expression and not emit any\n\
! RTL.  In the case of memtag-stack sanitizer, this constraint is not enforced.",
    rtx, (rtx base, poly_int64 addr_offset, uint8_t tag_offset),
    default_memtag_add_tag)
  
*************** DEFHOOK
*** 7606,7612 ****
  (extract_tag,
   "Return an RTX representing the tag stored in @var{tagged_pointer}.\n\
  Store the result in @var{target} if it is convenient.\n\
! The default represents the top byte of the original pointer.",
    rtx, (rtx tagged_pointer, rtx target), default_memtag_extract_tag)
  
  DEFHOOK
--- 7608,7616 ----
  (extract_tag,
   "Return an RTX representing the tag stored in @var{tagged_pointer}.\n\
  Store the result in @var{target} if it is convenient.\n\
! The default represents the top byte of the original pointer.\n\
! In the case of memtag-stack sanitizer for targets that can process\n\
! tagged pointers (i.e. AArch64), this hook can return a tagged pointer.",
    rtx, (rtx tagged_pointer, rtx target), default_memtag_extract_tag)
  
  DEFHOOK
diff -Nrcpad gcc-16-20251214/gcc/testsuite/ChangeLog gcc-16-20251221/gcc/testsuite/ChangeLog
*** gcc-16-20251214/gcc/testsuite/ChangeLog	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/testsuite/ChangeLog	Sun Dec 21 22:32:07 2025
***************
*** 1,3 ****
--- 1,555 ----
+ 2025-12-20  Nathaniel Shead  <nathanieloshead@gmail.com>
+ 
+ 	PR c++/122712
+ 	* g++.dg/modules/adl-12_a.C: New test.
+ 	* g++.dg/modules/adl-12_b.C: New test.
+ 
+ 2025-12-20  Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	PR c++/122690
+ 	* g++.dg/ext/is_implicit_lifetime2.C: New test.
+ 
+ 2025-12-20  Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	PR target/123217
+ 	* gcc.target/i386/keylocker-pr123217.c: New test.
+ 	* gcc.target/i386/user_msr-pr123217.c: New test.
+ 
+ 2025-12-19  Victor Do Nascimento  <victor.donascimento@arm.com>
+ 
+ 	* gcc.dg/vect/vect-uncounted-prolog-peel_2.c: New.
+ 	* gcc.dg/vect/vect-uncounted-prolog-peel_3.c: Likewise.
+ 	* g++.dg/vect/vect-uncounted-prolog-peel_1.cc: Likewise.
+ 
+ 2025-12-19  Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	* gcc.c-torture/compile/20030323-1.c: Fix comment typo,
+ 	statment -> statement.
+ 	* gcc.dg/tree-ssa/pr96779.c: Fix comment typo, transfered
+ 	-> transferred.
+ 	* gcc.dg/tree-ssa/pr96779-disabled.c: Likewise.
+ 	* gcc.dg/tree-ssa/ssa-thread-16.c (foo): Fix comment typo,
+ 	catched -> caught.
+ 	* gcc.target/s390/larl-1.c: Fix comment typo, explicitely
+ 	-> explicitly.
+ 	* g++.dg/tree-ssa/pr44706.C: Fix comment typo, invokation
+ 	-> invocation.
+ 	* g++.dg/tree-ssa/pr87502.C: Fix comment typo, explicitely
+ 	-> explicitly.
+ 	* gfortran.dg/bound_8.f90: Likewise.
+ 	* gfortran.dg/coarray_14.f90: Fix comment typo, statment
+ 	-> statement.
+ 
+ 2025-12-19  Harald Anlauf  <anlauf@gmx.de>
+ 
+ 	PR fortran/71565
+ 	* gfortran.dg/protected_8.f90: Adjust patterns.
+ 	* gfortran.dg/associate_76.f90: New test.
+ 
+ 2025-12-19  Robin Dapp  <rdapp@qti.qualcomm.com>
+ 
+ 	PR target/122970
+ 	* lib/target-supports.exp: Add rvv_zvl128b_ok.
+ 	* gcc.target/riscv/rvv/autovec/pr122970.c: New test.
+ 
+ 2025-12-19  Robin Dapp  <rdapp@ventanamicro.com>
+ 
+ 	* gcc.target/riscv/rvv/autovec/pr120378-1.c: Dump "optimized".
+ 	* gcc.target/riscv/rvv/autovec/pr121510.c: Add semicolon.
+ 	* gcc.target/riscv/rvv/base/pr112431-21.c: Add -Wno-pedantic.
+ 
+ 2025-12-19  Robin Dapp  <rdapp@ventanamicro.com>
+ 
+ 	* gcc.target/riscv/rvv/autovec/subreg-extract.c: New test.
+ 
+ 2025-12-19  Robin Dapp  <rdapp@ventanamicro.com>
+ 
+ 	* gcc.target/riscv/rvv/autovec/gather-scatter/strided_store-2.c:
+ 	Adjust test expectation.
+ 	* gcc.target/riscv/rvv/autovec/param-autovec-mode.c: Ditto.
+ 	* gcc.target/riscv/rvv/autovec/partial/select_vl-2.c: Ditto.
+ 	* gcc.target/riscv/rvv/autovec/zve64d-1.c: Ditto.
+ 	* gcc.target/riscv/rvv/autovec/zve64f-1.c: Ditto.
+ 
+ 2025-12-19  Robin Dapp  <rdapp@qti.qualcomm.com>
+ 
+ 	PR tree-optimization/123118
+ 	* g++.target/riscv/rvv/autovec/pr123118.C: New test.
+ 
+ 2025-12-19  Robin Dapp  <rdapp@qti.qualcomm.com>
+ 
+ 	PR tree-optimization/123117
+ 	* gcc.target/loongarch/vector/lsx/pr123117.c: New test.
+ 
+ 2025-12-19  Robin Dapp  <rdapp@ventanamicro.com>
+ 
+ 	* gcc.target/riscv/rvv/autovec/early-break-3.c: New test.
+ 	* gcc.target/riscv/rvv/autovec/early-break-4.c: New test.
+ 	* gcc.target/riscv/rvv/autovec/early-break-5.c: New test.
+ 
+ 2025-12-19  Robin Dapp  <rdapp@ventanamicro.com>
+ 
+ 	PR tree-optimization/123097
+ 	* gcc.target/riscv/rvv/autovec/pr123097-run.c: New test.
+ 	* gcc.target/riscv/rvv/autovec/pr123097.c: New test.
+ 
+ 2025-12-19  Robin Dapp  <rdapp.gcc@gmail.com>
+ 
+ 	PR tree-optimization/123192
+ 	* gcc.dg/tree-ssa/ctz-ch.c: Require ctz target.
+ 
+ 2025-12-19  Christopher Albert  <albert@tugraz.at>
+ 
+ 	PR fortran/92613
+ 	* gfortran.dg/pr92613.f90: New test.
+ 	* gfortran.dg/pr92613_2.f90: New test for -E error.
+ 
+ 2025-12-19  Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	PR c++/91388
+ 	* g++.dg/cpp1z/static_assert1.C: New test.
+ 
+ 2025-12-19  Andrew MacLeod  <amacleod@redhat.com>
+ 
+ 	PR tree-optimization/123205
+ 	* gcc.dg/pr123205.c: New.
+ 
+ 2025-12-19  Jason Merrill  <jason@redhat.com>
+ 	    Egas Ribeiro  <egas.g.ribeiro@tecnico.ulisboa.pt>
+ 
+ 	PR c++/117034
+ 	* g++.dg/cpp2a/lambda-template-pr117034.C: New test.
+ 
+ 2025-12-19  Egas Ribeiro  <egas.g.ribeiro@tecnico.ulisboa.pt>
+ 
+ 	* g++.dg/DRs/dr3061.C: Remove cascading error expectation.
+ 	* g++.dg/cpp0x/initlist31.C: Likewise.
+ 
+ 2025-12-19  Egas Ribeiro  <egas.g.ribeiro@tecnico.ulisboa.pt>
+ 
+ 	PR c++/123044
+ 	* g++.dg/template/implicit-func-cast.C: New test.
+ 
+ 2025-12-19  Egas Ribeiro  <egas.g.ribeiro@gmail.com>
+ 
+ 	PR c++/122509
+ 	* g++.dg/tc1/dr176-2.C: New test.
+ 
+ 2025-12-19  Tobias Burnus  <tburnus@baylibre.com>
+ 
+ 	* c-c++-common/gomp/uses_allocators-8.c: New test.
+ 
+ 2025-12-19  Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	PR c++/122772
+ 	* g++.dg/cpp1z/eval-order14.C: New test.
+ 
+ 2025-12-19  Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	PR debug/122968
+ 	* g++.dg/guality/decomp1.C: New test.
+ 
+ 2025-12-19  Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	PR c++/122834
+ 	* g++.dg/dfp/pr122834-1.C: New test.
+ 	* g++.dg/dfp/pr122834-2.C: New test.
+ 
+ 2025-12-19  Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	PR c++/123030
+ 	* g++.dg/cpp0x/deleted18.C: New test.
+ 	* g++.dg/cpp0x/new4.C: Expect an error.
+ 
+ 2025-12-19  Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	* g++.dg/cpp26/expansion-stmt1.C (A::operator *, A::operator !=,
+ 	A::operator +, C::operator *, C::operator !=, C::operator +): Add
+ 	const qualification.
+ 	* g++.dg/cpp26/expansion-stmt2.C (A::operator *, A::operator !=,
+ 	A::operator +, C::operator *, C::operator !=, C::operator +):
+ 	Likewise.
+ 	* g++.dg/cpp26/expansion-stmt3.C (A::operator *, A::operator !=,
+ 	A::operator +, C::operator *, C::operator !=, C::operator +):
+ 	Likewise.
+ 	* g++.dg/cpp26/expansion-stmt18.C (A::operator *, A::operator !=,
+ 	A::operator +): Likewise.
+ 
+ 2025-12-19  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
+ 
+ 	* gcc.target/i386/shift-gf2p8affine-2.c: Require gfni, avx512vl,
+ 	avx512bw, avx512f support instead of skipping with Solaris as.
+ 
+ 2025-12-19  Nathaniel Shead  <nathanieloshead@gmail.com>
+ 
+ 	PR c++/122922
+ 	* g++.dg/modules/pr122922_a.C: New test.
+ 	* g++.dg/modules/pr122922_b.C: New test.
+ 
+ 2025-12-19  Nathaniel Shead  <nathanieloshead@gmail.com>
+ 
+ 	PR c++/122995
+ 	* g++.dg/modules/namespace-17_a.C: New test.
+ 	* g++.dg/modules/namespace-17_b.C: New test.
+ 
+ 2025-12-19  Oleg Endo  <olegendo@gcc.gnu.org>
+ 
+ 	PR target/55212
+ 	* g++.target/sh/torture/pr55212-c413.C: New.
+ 
+ 2025-12-19  Oleg Endo  <olegendo@gcc.gnu.org>
+ 
+ 	PR target/55212
+ 	* g++.target/sh/torture/pr55212-c384.C: New.
+ 
+ 2025-12-19  Oleg Endo  <olegendo@gcc.gnu.org>
+ 
+ 	PR target/55212
+ 	* g++.target/sh/torture/pr55212-c373.C: New.
+ 
+ 2025-12-19  Oleg Endo  <olegendo@gcc.gnu.org>
+ 
+ 	PR target/55212
+ 	* g++.target/sh/torture/pr55212-c333.C: New.
+ 
+ 2025-12-19  Oleg Endo  <olegendo@gcc.gnu.org>
+ 
+ 	PR target/55212
+ 	* g++.target/sh/sh.exp: New.
+ 	* g++.target/sh/torture/sh-torture.exp: New.
+ 	* g++.target/sh/torture/pr55212-c311.C: New
+ 
+ 2025-12-19  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+ 
+ 	PR target/55212
+ 	* gcc.target/sh/pr55212-c248.c: New test.
+ 
+ 2025-12-18  Tobias Burnus  <tburnus@baylibre.com>
+ 
+ 	* gfortran.dg/goacc/update-if_present-2.f90: Update dg-error.
+ 	* gfortran.dg/gomp/order-8.f90: Likewise.
+ 	* gfortran.dg/gomp/order-9.f90: Likewise.
+ 	* c-c++-common/gomp/assume-5.c: New test.
+ 	* gfortran.dg/gomp/assume-6.f90: New test.
+ 
+ 2025-12-18  Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	PR c++/123186
+ 	* g++.dg/template/crash133.C: New test.
+ 
+ 2025-12-18  Egas Ribeiro  <egas.g.ribeiro@gmail.com>
+ 	    Patrick Palka  <ppalka@redhat.com>
+ 
+ 	PR c++/122070
+ 	* g++.dg/cpp23/class-deduction-inherited10.C: New test.
+ 	* g++.dg/cpp23/class-deduction-inherited9.C: New test.
+ 
+ 2025-12-18  Tobias Burnus  <tburnus@baylibre.com>
+ 
+ 	* c-c++-common/gomp/target-device-type-1.c: New test.
+ 	* gfortran.dg/gomp/target-device-type-1.f90: New test.
+ 
+ 2025-12-18  Tejas Belagod  <tejas.belagod@arm.com>
+ 
+ 	* gcc.target/aarch64/sve/acle/general/attributes_1.c: Update test for
+ 	__ARM_FEATURE_SVE_PREDICATE_OPERATORS.
+ 	* gcc.target/aarch64/sve/acle/general/attributes_9.c: New.
+ 
+ 2025-12-18  Alfie Richards  <alfie.richards@arm.com>
+ 
+ 	* gcc.target/aarch64/pragma_cpp_predefs_5.c: New test.
+ 	* gcc.target/aarch64/options_set_30.c: Likewise.
+ 	* lib/target-supports.exp (exts): Add sve-sm4, sve-aes, sve-bitperm.
+ 
+ 2025-12-18  WANG Xuerui  <git@xen0n.name>
+ 
+ 	PR target/123171
+ 	* gcc.target/loongarch/pr123171.c: New test.
+ 
+ 2025-12-18  chenxiaolong  <chenxiaolong@loongson.cn>
+ 
+ 	* gcc.target/loongarch/vector/lasx/vect-extract-256-128.c:
+ 	After supporting the vectorized type corresponding to subreg in
+ 	the backend, the cost of rtx becomes 0. In fwprop1 pass,
+ 	memory-loaded rtx cannot be propagated to this insn, which leads
+ 	to xvld not being optimized into vld instructions.
+ 	* gcc.target/loongarch/vect-mode-tieable.c: New test.
+ 
+ 2025-12-18  Richard Biener  <rguenther@suse.de>
+ 
+ 	PR c/123156
+ 	* gcc.dg/torture/builtin-shufflevector-pr123156.c: New testcase.
+ 
+ 2025-12-18  Andrew Pinski  <andrew.pinski@oss.qualcomm.com>
+ 
+ 	PR tree-optimization/122734
+ 	* gcc.dg/tree-ssa/copy-headers-13.c: New test.
+ 
+ 2025-12-18  Andrew Pinski  <andrew.pinski@oss.qualcomm.com>
+ 
+ 	* gcc.target/i386/pr121572-1a.c: Turn off -freorder-blocks-and-partition
+ 	as it interferes with the check-body.
+ 
+ 2025-12-17  H.J. Lu  <hjl.tools@gmail.com>
+ 
+ 	PR target/122343
+ 	* gcc.dg/pr122343-1.c: New test.
+ 
+ 2025-12-17  Jose E. Marchesi  <jose.marchesi@oracle.com>
+ 
+ 	* algol68/execute/modules/module11.a68: Remove multiple definition
+ 	module.
+ 
+ 2025-12-17  Gaius Mulley  <gaiusmod2@gmail.com>
+ 
+ 	PR modula2/23178
+ 	* gm2/pim/fail/badprocedure.mod: New test.
+ 
+ 2025-12-17  Ulrich Weigand  <ulrich.weigand@de.ibm.com>
+ 
+ 	PR testsuite/123166
+ 	* gfortran.dg/bessel_6.f90: Add { dg-do run } annotation.
+ 	* gfortran.dg/erf_2.F90: Likewise.
+ 	* gfortran.dg/integer_exponentiation_3.F90: Likewise.
+ 	* gfortran.dg/integer_exponentiation_5.F90: Likewise.
+ 
+ 2025-12-17  Gaius Mulley  <gaiusmod2@gmail.com>
+ 
+ 	PR modula2/123151
+ 	* gm2/pimlib/base/run/pass/FIO.mod: Reimplement.
+ 	Copy from gm2-libs/FIO.mod since FIO.def api has changed.
+ 	* gm2/pimlib/run/pass/testclose.mod: New test.
+ 
+ 2025-12-17  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
+ 
+ 	* gcc.target/i386/pr120881-1a.c: Restrict to Linux.
+ 	* gcc.target/i386/pr120881-1b.c: Likewise.
+ 
+ 2025-12-17  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
+ 
+ 	PR c++/112652
+ 	* g++.dg/cpp26/literals2.C: Skip on Solaris.
+ 
+ 2025-12-17  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
+ 
+ 	* gcc.dg/plugin/crash-test-nested-write-through-null-html.py:
+ 	Import re.
+ 	(test_results): Allow for "Segmentation Fault", too.
+ 	* gcc.dg/plugin/crash-test-nested-write-through-null-sarif.py:
+ 	Likewise.
+ 	* gcc.dg/plugin/crash-test-write-through-null-stderr.c
+ 	(test_inject_write_through_null): Likewise.
+ 
+ 2025-12-17  benwu25  <soggysocks206@gmail.com>
+ 
+ 	PR c++/121443
+ 	* g++.dg/parse/pr121443.C: New test.
+ 
+ 2025-12-17  Nathaniel Shead  <nathanieloshead@gmail.com>
+ 
+ 	PR c++/123075
+ 	* g++.dg/cpp2a/concepts-lambda25.C: New test.
+ 	* g++.dg/modules/lambda-13.h: New test.
+ 	* g++.dg/modules/lambda-13_a.H: New test.
+ 	* g++.dg/modules/lambda-13_b.C: New test.
+ 
+ 2025-12-17  Pierre-Emmanuel Patry  <pierre-emmanuel.patry@embecosm.com>
+ 
+ 	* rust/compile/issue-4301.rs: New test.
+ 
+ 2025-12-17  Pierre-Emmanuel Patry  <pierre-emmanuel.patry@embecosm.com>
+ 
+ 	* rust/compile/macros/mbe/macro-issue3608.rs: Update error messages.
+ 
+ 2025-12-17  Umesh Kalvakuntla  <umesh.kalvakuntla@amd.com>
+ 
+ 	* g++.target/i386/mv29.C: Likewise.
+ 	* gcc.target/i386/funcspec-56.inc: Likewise.
+ 	* gcc.target/i386/avx512bmm-1.c: New test.
+ 	* gcc.target/i386/avx512bmmvl-1.c: New test.
+ 
+ 2025-12-16  Jose E. Marchesi  <jose.marchesi@oracle.com>
+ 
+ 	PR algol68/123131
+ 	* algol68/compile/modules/compile.exp: Pass module include path
+ 	via extra_flags to algol68-dg-runtest.
+ 	* algol68/execute/modules/execute.exp: Pass module include path
+ 	via algol68_compile_args.
+ 	* lib/algol68-dg.exp (MODULES_OPTIONS): Delete.
+ 	(algol68-dg-runtest): Do not use MODULE_OPTIONS.
+ 	* lib/algol68-torture.exp (BUILT_MODULES_DIR): Delete.
+ 	(algol68-torture-execute): Do not use BUILT_MODULES_DIR.
+ 
+ 2025-12-16  David Malcolm  <dmalcolm@redhat.com>
+ 
+ 	PR diagnostics/123142
+ 	* gcc.dg/plugin/diagnostic-test-graphs-html.c: Add
+ 	dg-require-dot directive.
+ 
+ 2025-12-16  Jose E. Marchesi  <jose.marchesi@oracle.com>
+ 
+ 	* algol68/compile/error-compile-unknown-tag-1.a68: Use a single
+ 	module per packet.
+ 	* algol68/compile/error-module-coercions-1.a68: Likewise.
+ 	* algol68/compile/error-module-ranges-1.a68: Likewise.
+ 	* algol68/compile/module-2.a68: Likewise.
+ 	* algol68/compile/module-pub-mangling-1.a68: Likewise.
+ 	* algol68/compile/module-pub-mangling-2.a68: Likewise.
+ 	* algol68/compile/module-pub-mangling-3.a68: Likewise.
+ 	* algol68/compile/module-pub-mangling-4.a68: Likewise.
+ 	* algol68/compile/module-pub-mangling-5.a68: Likewise.
+ 	* algol68/compile/module-pub-mangling-6.a68: Likewise.
+ 	* algol68/compile/warning-module-hidding-1.a68: Likewise.
+ 
+ 2025-12-16  Jose E. Marchesi  <jose.marchesi@oracle.com>
+ 
+ 	* algol68/execute/modules/Modules20.map: New file.
+ 	* algol68/execute/modules/module-bar.a68: New file.
+ 	* algol68/execute/modules/module-foo.a68: New file.
+ 	* algol68/execute/modules/program-19.a68: New file.
+ 	* algol68/execute/modules/program-20.a68: New file.
+ 
+ 2025-12-16  Richard Biener  <rguenther@suse.de>
+ 
+ 	PR testsuite/123137
+ 	* g++.dg/vect/pr64410.cc: Add -mfpmath=sse -msse on x86.
+ 
+ 2025-12-16  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
+ 
+ 	* gcc.target/i386/shift-gf2p8affine-2.c: Skip on Solaris
+ 	without gas.
+ 
+ 2025-12-16  Claudiu Zissulescu  <claudiu.zissulescu-ianculescu@oracle.com>
+ 	    Indu Bhagat  <indu.bhagat@oracle.com>
+ 
+ 	* gcc.target/aarch64/memtag/alloca-1.c: New test.
+ 	* gcc.target/aarch64/memtag/alloca-2.c: New test.
+ 	* gcc.target/aarch64/memtag/alloca-3.c: New test.
+ 	* gcc.target/aarch64/memtag/arguments-1.c: New test.
+ 	* gcc.target/aarch64/memtag/arguments-2.c: New test.
+ 	* gcc.target/aarch64/memtag/arguments-3.c: New test.
+ 	* gcc.target/aarch64/memtag/arguments-4.c: New test.
+ 	* gcc.target/aarch64/memtag/arguments.c: New test.
+ 	* gcc.target/aarch64/memtag/basic-1.c: New test.
+ 	* gcc.target/aarch64/memtag/basic-3.c: New test.
+ 	* gcc.target/aarch64/memtag/basic-struct.c: New test.
+ 	* gcc.target/aarch64/memtag/large-array.c: New test.
+ 	* gcc.target/aarch64/memtag/local-no-escape.c: New test.
+ 	* gcc.target/aarch64/memtag/memtag.exp: New file.
+ 	* gcc.target/aarch64/memtag/no-sanitize-attribute.c: New test.
+ 	* gcc.target/aarch64/memtag/value-init.c: New test.
+ 	* gcc.target/aarch64/memtag/vararray-gimple.c: New test.
+ 	* gcc.target/aarch64/memtag/vararray.c: New test.
+ 	* gcc.target/aarch64/memtag/zero-init.c: New test.
+ 	* gcc.target/aarch64/memtag/texec-1.c: New test.
+ 	* gcc.target/aarch64/memtag/texec-2.c: New test.
+ 	* gcc.target/aarch64/memtag/texec-3.c: New test.
+ 	* gcc.target/aarch64/memtag/vla-1.c: New test.
+ 	* gcc.target/aarch64/memtag/vla-2.c: New test.
+ 	* lib/target-supports.exp (check_effective_target_aarch64_mte):
+ 	New function.
+ 	* gcc.target/aarch64/memtag/cfi-mte-memtag-frame-1.c: New file.
+ 	* gcc.target/aarch64/memtag/mte-sig.h: New file.
+ 
+ 2025-12-16  Claudiu Zissulescu  <claudiu.zissulescu-ianculescu@oracle.com>
+ 	    Indu Bhagat  <indu.bhagat@oracle.com>
+ 
+ 	* gcc.target/aarch64/acle/memtag_1.c: Update test.
+ 
+ 2025-12-16  Andrew Pinski  <andrew.pinski@oss.qualcomm.com>
+ 
+ 	PR tree-optimization/123110
+ 	* gcc.dg/pr123110-1.c: New test.
+ 
+ 2025-12-15  Martin Jambor  <mjambor@suse.cz>
+ 
+ 	* gcc.dg/lto/fnptr-from-rec-1_0.c: New test.
+ 	* gcc.dg/lto/fnptr-from-rec-1_1.c: Likewise.
+ 	* gcc.dg/lto/fnptr-from-rec-2_0.c: Likewise.
+ 	* gcc.dg/lto/fnptr-from-rec-2_1.c: Likewise.
+ 	* gcc.dg/lto/fnptr-from-rec-3_0.c: Likewise.
+ 	* gcc.dg/lto/fnptr-from-rec-3_1.c: Likewise.
+ 
+ 2025-12-15  Eric Botcazou  <ebotcazou@adacore.com>
+ 
+ 	* gnat.dg/reduce4.adb: New test.
+ 	* gnat.dg/reduce5.adb: Likewise.
+ 
+ 2025-12-15  Jerry DeLisle  <jvdelisle@gcc.gnu.org>
+ 
+ 	PR libfortran/122936
+ 	* gfortran.dg/pr122936.f90: New test.
+ 
+ 2025-12-15  Patrick Palka  <ppalka@redhat.com>
+ 
+ 	PR c++/122752
+ 	* g++.dg/template/dependent-name19.C: New test.
+ 
+ 2025-12-15  Patrick Palka  <ppalka@redhat.com>
+ 
+ 	PR c++/122668
+ 	PR c++/114764
+ 	* g++.dg/cpp0x/noexcept91a.C: New test.
+ 
+ 2025-12-15  Joseph Myers  <josmyers@redhat.com>
+ 
+ 	* lib/plugin-support.exp (plugin-test-execute): Support installed
+ 	testing.
+ 	* g++.dg/plugin/plugin.exp, gcc.dg/plugin/plugin.exp,
+ 	obj-c++.dg/plugin/plugin.exp, objc.dg/plugin/plugin.exp: Do not
+ 	disable for installed testing.
+ 
+ 2025-12-15  David Malcolm  <dmalcolm@redhat.com>
+ 
+ 	PR analyzer/123085
+ 	* c-c++-common/analyzer/strlen-pr123085.c: New test.
+ 
+ 2025-12-15  David Malcolm  <dmalcolm@redhat.com>
+ 
+ 	PR analyzer/122975
+ 	* c-c++-common/analyzer/arith-1.c: New test.
+ 	* c-c++-common/analyzer/infinite-recursion-pr122975.c: New test.
+ 
+ 2025-12-15  Victor Do Nascimento  <victor.donascimento@arm.com>
+ 
+ 	* gcc.dg/vect/vect-early-break_40.c: Fix.
+ 	* gcc.dg/gomp/static-chunk-size-one.c: Likewise.
+ 	* gcc.dg/vect/vect-uncounted_1.c: New.
+ 	* gcc.dg/vect/vect-uncounted_2.c: Likewise.
+ 	* gcc.dg/vect/vect-uncounted_3.c: Likewise.
+ 	* gcc.dg/vect/vect-uncounted_4.c: Likewise.
+ 	* gcc.dg/vect/vect-uncounted_5.c: Likewise.
+ 	* gcc.dg/vect/vect-uncounted_6.c: Likewise.
+ 	* gcc.dg/vect/vect-uncounted_7.c: Likewise.
+ 	* gcc.dg/vect/vect-uncounted-run_1.c: Likewise.
+ 	* gcc.dg/vect/vect-uncounted-run_2.c: Likewise.
+ 	* gcc.dg/vect/vect-uncounted-run_3.c: Likewise.
+ 	* gcc.dg/vect/vect-uncounted-prolog-peel_1.c: Likewise.
+ 
+ 2025-12-15  Tamar Christina  <tamar.christina@arm.com>
+ 
+ 	PR tree-optimization/123032
+ 	* gcc.dg/vect/pr123032.c: New test.
+ 
+ 2025-12-15  Tamar Christina  <tamar.christina@arm.com>
+ 
+ 	PR tree-optimization/123043
+ 	* gcc.dg/vect/pr123043.c: New test.
+ 
+ 2025-12-15  Eric Botcazou  <ebotcazou@adacore.com>
+ 
+ 	* gnat.dg/lto30.ads, gnat.dg/lto30.adb: New test.
+ 
+ 2025-12-14  Lewis Hyatt  <lhyatt@gmail.com>
+ 
+ 	PR tree-optimization/106409
+ 	* g++.dg/lto/pr106409_0.C: New test.
+ 
+ 2025-12-14  Surya Kumari Jangala  <jskumari@linux.ibm.com>
+ 
+ 	PR rtl-optimization/122274
+ 	* gcc.dg/rtl/powerpc/test-frame-related.c: New test.
+ 
  2025-12-13  Jose E. Marchesi  <jose.marchesi@oracle.com>
  
  	* algol68/execute/modules/module1.a68: Also test contracted
diff -Nrcpad gcc-16-20251214/gcc/testsuite/algol68/compile/error-compile-unknown-tag-1.a68 gcc-16-20251221/gcc/testsuite/algol68/compile/error-compile-unknown-tag-1.a68
*** gcc-16-20251214/gcc/testsuite/algol68/compile/error-compile-unknown-tag-1.a68	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/testsuite/algol68/compile/error-compile-unknown-tag-1.a68	Sun Dec 21 22:32:08 2025
***************
*** 1,8 ****
! module Foo = def pub int idpublic = 10;
!                  int idprivate = 20;
!                  skip
!              fed,
!        Bar = def pub int idpublic = 30;
                   int idprivate = 40;
                   xxx { dg-error "" }
               fed
--- 1,4 ----
! module Bar = def pub int idpublic = 30;
                   int idprivate = 40;
                   xxx { dg-error "" }
               fed
diff -Nrcpad gcc-16-20251214/gcc/testsuite/algol68/compile/error-module-coercions-1.a68 gcc-16-20251221/gcc/testsuite/algol68/compile/error-module-coercions-1.a68
*** gcc-16-20251214/gcc/testsuite/algol68/compile/error-module-coercions-1.a68	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/testsuite/algol68/compile/error-module-coercions-1.a68	Sun Dec 21 22:32:08 2025
*************** module Foo = def
*** 5,15 ****
               postlude
                  int i = "foo"; { dg-error "coerced" }
                  skip
!              fed,
!        Bar = def
!                 int i = 3.14; { dg-error "coerced" }
!                 skip
!              postlude
!                 skip
!              fed,
!        Baz = def skip fed
--- 5,8 ----
               postlude
                  int i = "foo"; { dg-error "coerced" }
                  skip
!              fed
diff -Nrcpad gcc-16-20251214/gcc/testsuite/algol68/compile/error-module-ranges-1.a68 gcc-16-20251221/gcc/testsuite/algol68/compile/error-module-ranges-1.a68
*** gcc-16-20251214/gcc/testsuite/algol68/compile/error-module-ranges-1.a68	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/testsuite/algol68/compile/error-module-ranges-1.a68	Sun Dec 21 22:32:08 2025
*************** module Foo = def int i;
*** 5,13 ****
                   x := 20 { dg-error "" }
               postlude
                   i := 10 { this is ok }
-              fed,
-        Bar = def int x;
-                  skip
-              postlude
-                  x := 20 { this is ok }
               fed
--- 5,8 ----
diff -Nrcpad gcc-16-20251214/gcc/testsuite/algol68/compile/module-2.a68 gcc-16-20251221/gcc/testsuite/algol68/compile/module-2.a68
*** gcc-16-20251214/gcc/testsuite/algol68/compile/module-2.a68	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/testsuite/algol68/compile/module-2.a68	Sun Dec 21 22:32:08 2025
*************** module Foo = def pub int idpublic = 10;
*** 5,16 ****
                   pub proc lala = (int a, b) int: a + b;
                   pub proc lele := (int a, b) int: a - b;
                   skip
-              fed,
-        Bar = def pub int idpublic = 30;
-                  int idprivate = 40;
-                  pub int varpublic := 100;
-                  real varprivate := 3.14;
-                  pub proc lala = (int a, b) int: a + b;
-                  pub proc lele := (int a, b) int: a - b;
-                  skip
               fed
--- 5,8 ----
diff -Nrcpad gcc-16-20251214/gcc/testsuite/algol68/compile/module-pub-mangling-1.a68 gcc-16-20251221/gcc/testsuite/algol68/compile/module-pub-mangling-1.a68
*** gcc-16-20251214/gcc/testsuite/algol68/compile/module-pub-mangling-1.a68	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/testsuite/algol68/compile/module-pub-mangling-1.a68	Sun Dec 21 22:32:08 2025
***************
*** 3,15 ****
  module Foo = def pub int foo;    { dg-final { scan-assembler "FOO_foo" } }
                   int bar;        { dg-final { scan-assembler "FOO_bar" } }
                   skip
-              fed,
-        Bar = def pub int foo;    { dg-final { scan-assembler "BAR_foo" } }
-                  int bar;        { dg-final { scan-assembler "BAR_bar" } }
-                  skip
               fed
  
  { dg-final { scan-assembler "FOO__prelude" } }
  { dg-final { scan-assembler "FOO__postlude" } }
- { dg-final { scan-assembler "BAR__prelude" } }
- { dg-final { scan-assembler "BAR__postlude" } }
--- 3,9 ----
diff -Nrcpad gcc-16-20251214/gcc/testsuite/algol68/compile/module-pub-mangling-2.a68 gcc-16-20251221/gcc/testsuite/algol68/compile/module-pub-mangling-2.a68
*** gcc-16-20251214/gcc/testsuite/algol68/compile/module-pub-mangling-2.a68	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/testsuite/algol68/compile/module-pub-mangling-2.a68	Sun Dec 21 22:32:08 2025
***************
*** 3,15 ****
  module Foo = def pub struct (int i, real r) foo;{ dg-final { scan-assembler "FOO_foo" } }
                   struct (int i, real r) bar;    { dg-final { scan-assembler "FOO_bar" } }
                   skip
-              fed,
-        Bar = def pub struct (int i, real r) foo;{ dg-final { scan-assembler "BAR_foo" } }
-                  struct (int i, real r) bar;    { dg-final { scan-assembler "BAR_bar" } }
-                  skip
               fed
  
  { dg-final { scan-assembler "FOO__prelude" } }
  { dg-final { scan-assembler "FOO__postlude" } }
- { dg-final { scan-assembler "BAR__prelude" } }
- { dg-final { scan-assembler "BAR__postlude" } }
--- 3,9 ----
diff -Nrcpad gcc-16-20251214/gcc/testsuite/algol68/compile/module-pub-mangling-3.a68 gcc-16-20251221/gcc/testsuite/algol68/compile/module-pub-mangling-3.a68
*** gcc-16-20251214/gcc/testsuite/algol68/compile/module-pub-mangling-3.a68	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/testsuite/algol68/compile/module-pub-mangling-3.a68	Sun Dec 21 22:32:08 2025
***************
*** 3,15 ****
  module Foo = def pub int foo = 10; { dg-final { scan-assembler "FOO_foo" } }
                   int bar = 20;     { dg-final { scan-assembler "FOO_bar" } }
                   skip
-              fed,
-        Bar = def pub int foo = 30; { dg-final { scan-assembler "BAR_foo" } }
-                  int bar = 40;     { dg-final { scan-assembler "BAR_bar" } }
-                  skip
               fed
  
  { dg-final { scan-assembler "FOO__prelude" } }
  { dg-final { scan-assembler "FOO__postlude" } }
- { dg-final { scan-assembler "BAR__prelude" } }
- { dg-final { scan-assembler "BAR__postlude" } }
--- 3,9 ----
diff -Nrcpad gcc-16-20251214/gcc/testsuite/algol68/compile/module-pub-mangling-4.a68 gcc-16-20251221/gcc/testsuite/algol68/compile/module-pub-mangling-4.a68
*** gcc-16-20251214/gcc/testsuite/algol68/compile/module-pub-mangling-4.a68	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/testsuite/algol68/compile/module-pub-mangling-4.a68	Sun Dec 21 22:32:08 2025
***************
*** 5,17 ****
  module Foo = def pub proc int foo;          { dg-final { scan-assembler "FOO_foo" } }
                   proc int bar := int: skip; { dg-final { scan-assembler "FOO_bar" } }
                   skip
-              fed,
-        Bar = def pub proc int foo;    { dg-final { scan-assembler "BAR_foo" } }
-                  proc int bar := foo; { dg-final { scan-assembler "BAR_bar" } }
-                  skip
               fed
  
  { dg-final { scan-assembler "FOO__prelude" } }
  { dg-final { scan-assembler "FOO__postlude" } }
- { dg-final { scan-assembler "BAR__prelude" } }
- { dg-final { scan-assembler "BAR__postlude" } }
--- 5,11 ----
diff -Nrcpad gcc-16-20251214/gcc/testsuite/algol68/compile/module-pub-mangling-5.a68 gcc-16-20251221/gcc/testsuite/algol68/compile/module-pub-mangling-5.a68
*** gcc-16-20251214/gcc/testsuite/algol68/compile/module-pub-mangling-5.a68	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/testsuite/algol68/compile/module-pub-mangling-5.a68	Sun Dec 21 22:32:08 2025
***************
*** 5,17 ****
  module Foo = def pub proc foo = int: skip; { dg-final { scan-assembler "FOO_foo" } }
                   proc bar = int: skip;     { dg-final { scan-assembler "FOO_bar" } }
                   skip
-              fed,
-        Bar = def pub proc foo = int: skip; { dg-final { scan-assembler "BAR_foo" } }
-                  proc bar = int: skip;     { dg-final { scan-assembler "BAR_bar" } }
-                  skip
               fed
  
  { dg-final { scan-assembler "FOO__prelude" } }
  { dg-final { scan-assembler "FOO__postlude" } }
- { dg-final { scan-assembler "BAR__prelude" } }
- { dg-final { scan-assembler "BAR__postlude" } }
--- 5,11 ----
diff -Nrcpad gcc-16-20251214/gcc/testsuite/algol68/compile/module-pub-mangling-6.a68 gcc-16-20251221/gcc/testsuite/algol68/compile/module-pub-mangling-6.a68
*** gcc-16-20251214/gcc/testsuite/algol68/compile/module-pub-mangling-6.a68	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/testsuite/algol68/compile/module-pub-mangling-6.a68	Sun Dec 21 22:32:08 2025
*************** module Foo = def pub op + = (int a, b) i
*** 7,21 ****
                   op - = (int a, b) int: a - b;
                   { dg-final { scan-assembler "FOO_m_" } }
                   skip
-              fed,
-        Bar = def pub op + = (int a, b) int: a + b;
-                  { dg-final { scan-assembler "BAR_u_" } }
-                  op - = (int a, b) int: a - b;
-                  { dg-final { scan-assembler "BAR_m_" } }
-                  skip
               fed
  
  { dg-final { scan-assembler "FOO__prelude" } }
  { dg-final { scan-assembler "FOO__postlude" } }
- { dg-final { scan-assembler "BAR__prelude" } }
- { dg-final { scan-assembler "BAR__postlude" } }
--- 7,13 ----
diff -Nrcpad gcc-16-20251214/gcc/testsuite/algol68/compile/modules/compile.exp gcc-16-20251221/gcc/testsuite/algol68/compile/modules/compile.exp
*** gcc-16-20251214/gcc/testsuite/algol68/compile/modules/compile.exp	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/testsuite/algol68/compile/modules/compile.exp	Sun Dec 21 22:32:08 2025
*************** dg-init
*** 26,39 ****
  # The programs need to be able to find the built modules, which are
  # left in objdir.
  
- global MODULES_OPTIONS
- set MODULES_OPTIONS "-I $objdir"
- 
  # Main loop.
  set saved-dg-do-what-default ${dg-do-what-default}
  
  set dg-do-what-default "compile"
! algol68-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/program*.a68]] "" ""
  set dg-do-what-default ${saved-dg-do-what-default}
  
  # All done.
--- 26,36 ----
  # The programs need to be able to find the built modules, which are
  # left in objdir.
  
  # Main loop.
  set saved-dg-do-what-default ${dg-do-what-default}
  
  set dg-do-what-default "compile"
! algol68-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/program*.a68]] "" "-I $objdir"
  set dg-do-what-default ${saved-dg-do-what-default}
  
  # All done.
diff -Nrcpad gcc-16-20251214/gcc/testsuite/algol68/compile/warning-module-hidding-1.a68 gcc-16-20251221/gcc/testsuite/algol68/compile/warning-module-hidding-1.a68
*** gcc-16-20251214/gcc/testsuite/algol68/compile/warning-module-hidding-1.a68	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/testsuite/algol68/compile/warning-module-hidding-1.a68	Sun Dec 21 22:32:08 2025
***************
*** 1,6 ****
  { dg-options "-Whidden-declarations=all" }
  
! module Foo = def int i; i := 10 postlude puts ("bye foo'n") fed,
!        Bar = def int j; j := 20
!              postlude int j; puts ("bye bar'n") fed, { dg-warning "hidden" }
!        Baz = def skip fed
--- 1,6 ----
  { dg-options "-Whidden-declarations=all" }
  
! module Bar =
! def int j; j := 20
! postlude int j; puts ("bye bar'n")  { dg-warning "hidden" }
! fed
diff -Nrcpad gcc-16-20251214/gcc/testsuite/algol68/execute/modules/Modules20.map gcc-16-20251221/gcc/testsuite/algol68/execute/modules/Modules20.map
*** gcc-16-20251214/gcc/testsuite/algol68/execute/modules/Modules20.map	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/algol68/execute/modules/Modules20.map	Sun Dec 21 22:32:08 2025
***************
*** 0 ****
--- 1,2 ----
+ module-foo=Foo:
+ module-bar=Bar
diff -Nrcpad gcc-16-20251214/gcc/testsuite/algol68/execute/modules/execute.exp gcc-16-20251221/gcc/testsuite/algol68/execute/modules/execute.exp
*** gcc-16-20251214/gcc/testsuite/algol68/execute/modules/execute.exp	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/testsuite/algol68/execute/modules/execute.exp	Sun Dec 21 22:32:08 2025
*************** load_lib torture-options.exp
*** 25,40 ****
  torture-init
  set-torture-options $TORTURE_OPTIONS
  
- # The programs need to be able to find the built modules, which are
- # left in objdir.
- global BUILT_MODULES_DIR
- set BUILT_MODULES_DIR "$objdir"
- 
  foreach testcase [lsort [glob -nocomplain $srcdir/$subdir/program-*.a68]] {
      # If we're only testing specific files and this isn't one of them, skip it.
      if ![runtest_file_p $runtests $testcase] then {
  	continue
      }
      algol68-torture-execute $testcase
      set algol68_compile_args ""
  }
--- 25,36 ----
  torture-init
  set-torture-options $TORTURE_OPTIONS
  
  foreach testcase [lsort [glob -nocomplain $srcdir/$subdir/program-*.a68]] {
      # If we're only testing specific files and this isn't one of them, skip it.
      if ![runtest_file_p $runtests $testcase] then {
  	continue
      }
+     set algol68_compile_args "-I$objdir"
      algol68-torture-execute $testcase
      set algol68_compile_args ""
  }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/algol68/execute/modules/module-bar.a68 gcc-16-20251221/gcc/testsuite/algol68/execute/modules/module-bar.a68
*** gcc-16-20251214/gcc/testsuite/algol68/execute/modules/module-bar.a68	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/algol68/execute/modules/module-bar.a68	Sun Dec 21 22:32:08 2025
***************
*** 0 ****
--- 1 ----
+ module Bar = def pub int bar = 20; skip fed
diff -Nrcpad gcc-16-20251214/gcc/testsuite/algol68/execute/modules/module-foo.a68 gcc-16-20251221/gcc/testsuite/algol68/execute/modules/module-foo.a68
*** gcc-16-20251214/gcc/testsuite/algol68/execute/modules/module-foo.a68	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/algol68/execute/modules/module-foo.a68	Sun Dec 21 22:32:08 2025
***************
*** 0 ****
--- 1 ----
+ module Foo = def pub int foo = 10; skip fed
diff -Nrcpad gcc-16-20251214/gcc/testsuite/algol68/execute/modules/module11.a68 gcc-16-20251221/gcc/testsuite/algol68/execute/modules/module11.a68
*** gcc-16-20251214/gcc/testsuite/algol68/execute/modules/module11.a68	Sun Dec 14 22:32:08 2025
--- gcc-16-20251221/gcc/testsuite/algol68/execute/modules/module11.a68	Sun Dec 21 22:32:08 2025
*************** module Module11 =
*** 6,11 ****
                skip
            postlude
                skip
!           fed,
!        Foo = def skip postlude skip fed,
!        Bar = def skip fed
--- 6,9 ----
                skip
            postlude
                skip
!           fed
diff -Nrcpad gcc-16-20251214/gcc/testsuite/algol68/execute/modules/program-19.a68 gcc-16-20251221/gcc/testsuite/algol68/execute/modules/program-19.a68
*** gcc-16-20251214/gcc/testsuite/algol68/execute/modules/program-19.a68	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/algol68/execute/modules/program-19.a68	Sun Dec 21 22:32:08 2025
***************
*** 0 ****
--- 1,6 ----
+ { dg-modules "module-foo module-bar" }
+ { dg-options {-fmodules-map=module-foo=Foo:module-bar=Bar} }
+ 
+ begin access Foo (assert (foo = 10));
+       access Bar (assert (bar = 20))
+ end
diff -Nrcpad gcc-16-20251214/gcc/testsuite/algol68/execute/modules/program-20.a68 gcc-16-20251221/gcc/testsuite/algol68/execute/modules/program-20.a68
*** gcc-16-20251214/gcc/testsuite/algol68/execute/modules/program-20.a68	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/algol68/execute/modules/program-20.a68	Sun Dec 21 22:32:08 2025
***************
*** 0 ****
--- 1,6 ----
+ { dg-modules "module-foo module-bar" }
+ { dg-options "-fmodules-map-file=$srcdir/algol68/execute/modules/Modules20.map" }
+ 
+ begin access Foo (assert (foo = 10));
+       access Bar (assert (bar = 20))
+ end
diff -Nrcpad gcc-16-20251214/gcc/testsuite/c-c++-common/analyzer/arith-1.c gcc-16-20251221/gcc/testsuite/c-c++-common/analyzer/arith-1.c
*** gcc-16-20251214/gcc/testsuite/c-c++-common/analyzer/arith-1.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/c-c++-common/analyzer/arith-1.c	Sun Dec 21 22:32:08 2025
***************
*** 0 ****
--- 1,13 ----
+ #include "analyzer-decls.h"
+ 
+ static int __attribute__((noipa))
+ negate_int (int x)
+ {
+   return -x;
+ }
+ 
+ void
+ test_1 (int a)
+ {
+   __analyzer_eval (a + negate_int (a) == 0); /* { dg-warning "TRUE" } */
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/c-c++-common/analyzer/infinite-recursion-pr122975.c gcc-16-20251221/gcc/testsuite/c-c++-common/analyzer/infinite-recursion-pr122975.c
*** gcc-16-20251214/gcc/testsuite/c-c++-common/analyzer/infinite-recursion-pr122975.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/c-c++-common/analyzer/infinite-recursion-pr122975.c	Sun Dec 21 22:32:08 2025
***************
*** 0 ****
--- 1,5 ----
+ void fun(int x, int y)
+ {
+   if (x + y != 0) 
+     fun(x, -x); /* { dg-bogus "infinite recursion" } */
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/c-c++-common/analyzer/strlen-pr123085.c gcc-16-20251221/gcc/testsuite/c-c++-common/analyzer/strlen-pr123085.c
*** gcc-16-20251214/gcc/testsuite/c-c++-common/analyzer/strlen-pr123085.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/c-c++-common/analyzer/strlen-pr123085.c	Sun Dec 21 22:32:08 2025
***************
*** 0 ****
--- 1,8 ----
+ static int bug(const char *dirname) {
+     dirname++;
+     return __builtin_strlen(dirname); /* { dg-bogus "buffer over-read" } */
+ }
+ 
+ int main (void) {
+     return bug("abcd");
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/c-c++-common/gomp/assume-5.c gcc-16-20251221/gcc/testsuite/c-c++-common/gomp/assume-5.c
*** gcc-16-20251214/gcc/testsuite/c-c++-common/gomp/assume-5.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/c-c++-common/gomp/assume-5.c	Sun Dec 21 22:32:08 2025
***************
*** 0 ****
--- 1,18 ----
+ #pragma omp assumes no_openmp_constructs
+ 
+ #pragma omp begin assumes no_openmp_constructs no_parallelism
+ void g(int x)
+ {
+     if (x <= 0)
+       return;
+ }
+ #pragma omp end assumes
+ 
+ void f()
+ {
+   #pragma omp assume no_openmp no_openmp_something  // { dg-error "32: expected assumption clause" }
+     ;
+ 
+   #pragma omp assume no_openmp no_openmp_routines no_openmp_constructs no_openmp_constructs // { dg-error "72: too many 'no_openmp_constructs' clauses" }
+     ;
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/c-c++-common/gomp/target-device-type-1.c gcc-16-20251221/gcc/testsuite/c-c++-common/gomp/target-device-type-1.c
*** gcc-16-20251214/gcc/testsuite/c-c++-common/gomp/target-device-type-1.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/c-c++-common/gomp/target-device-type-1.c	Sun Dec 21 22:32:08 2025
***************
*** 0 ****
--- 1,24 ----
+ // { dg-do compile }
+ // { dg-additional-options "-fdump-tree-gimple" }
+ 
+ void f ()
+ {
+ 
+ #pragma omp target
+   ;
+ 
+ #pragma omp target device_type ( any )
+   ;
+ 
+ #pragma omp target device_type ( nohost )  // { dg-message "sorry, unimplemented: only the 'device_type\\(any\\)' is supported" }
+   ;
+ 
+ #pragma omp target device_type ( host )
+   ;
+ 
+ }
+ 
+ // { dg-final { scan-tree-dump-times "#pragma omp target num_teams\\(-2\\) thread_limit\\(0\\)\[\\r\\n\]" 1 "gimple" } }
+ // { dg-final { scan-tree-dump-times "#pragma omp target num_teams\\(-2\\) thread_limit\\(0\\) device_type\\(any\\)" 1 "gimple" } }
+ // { dg-final { scan-tree-dump-times "#pragma omp target num_teams\\(-2\\) thread_limit\\(0\\) device_type\\(nohost\\)" 1 "gimple" } }
+ // { dg-final { scan-tree-dump-times "#pragma omp target num_teams\\(-2\\) thread_limit\\(0\\) device_type\\(host\\)" 1 "gimple" } }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/c-c++-common/gomp/uses_allocators-8.c gcc-16-20251221/gcc/testsuite/c-c++-common/gomp/uses_allocators-8.c
*** gcc-16-20251214/gcc/testsuite/c-c++-common/gomp/uses_allocators-8.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/c-c++-common/gomp/uses_allocators-8.c	Sun Dec 21 22:32:08 2025
***************
*** 0 ****
--- 1,59 ----
+ // { dg-do compile }
+ 
+ //#include <omp.h>
+ 
+ typedef __UINTPTR_TYPE__ omp_uintptr_t;
+ 
+ #if __cplusplus >= 201103L
+ # define __GOMP_UINTPTR_T_ENUM : omp_uintptr_t
+ #else
+ # define __GOMP_UINTPTR_T_ENUM
+ #endif
+ 
+ typedef enum omp_memspace_handle_t __GOMP_UINTPTR_T_ENUM
+ {
+   omp_default_mem_space = 0,
+   omp_large_cap_mem_space = 1,
+   omp_const_mem_space = 2,
+   omp_high_bw_mem_space = 3,
+   omp_low_lat_mem_space = 4,
+   ompx_gnu_managed_mem_space = 200,
+   __omp_memspace_handle_t_max__ = __UINTPTR_MAX__
+ } omp_memspace_handle_t;
+ 
+ typedef enum omp_allocator_handle_t __GOMP_UINTPTR_T_ENUM
+ {
+   omp_null_allocator = 0,
+   omp_default_mem_alloc = 1,
+   omp_large_cap_mem_alloc = 2,
+   omp_const_mem_alloc = 3,
+   omp_high_bw_mem_alloc = 4,
+   omp_low_lat_mem_alloc = 5,
+   omp_cgroup_mem_alloc = 6,
+   omp_pteam_mem_alloc = 7,
+   omp_thread_mem_alloc = 8,
+   ompx_gnu_pinned_mem_alloc = 200,
+   ompx_gnu_managed_mem_alloc = 201,
+   __omp_allocator_handle_t_max__ = __UINTPTR_MAX__
+ } omp_allocator_handle_t;
+ 
+ typedef struct omp_alloctrait_t
+ {
+ //  omp_alloctrait_key_t key;
+ //  omp_uintptr_t value;
+ } omp_alloctrait_t;
+ 
+ 
+ void f()
+ {
+  omp_allocator_handle_t my, my2, my3, my4;
+ const omp_alloctrait_t t[] = {};
+ const omp_alloctrait_t t2[] = {};
+  #pragma omp target uses_allocators(traits(t), memspace(omp_high_bw_mem_space) : my; omp_default_mem_alloc, omp_null_allocator; my2; traits(t2) : my3; memspace(omp_large_cap_mem_space) : my4)
+    ;
+ }
+ 
+ // { dg-final { scan-tree-dump "#pragma omp target uses_allocators\\(memspace\\(1\\), traits\\(\\) : my4\\) uses_allocators\\(memspace\\(\\), traits\\(t2\\) : my3\\) uses_allocators\\(memspace\\(\\), traits\\(\\) : my2\\) uses_allocators\\(memspace\\(3\\), traits\\(t\\) : my\\)" "original" } }
+ 
+ 
+ // { dg-message "sorry, unimplemented: 'uses_allocators' clause" "" { target *-*-* } 52 }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/DRs/dr3061.C gcc-16-20251221/gcc/testsuite/g++.dg/DRs/dr3061.C
*** gcc-16-20251214/gcc/testsuite/g++.dg/DRs/dr3061.C	Sun Dec 14 22:32:09 2025
--- gcc-16-20251221/gcc/testsuite/g++.dg/DRs/dr3061.C	Sun Dec 21 22:32:08 2025
*************** foo ()
*** 12,18 ****
    template for (int x : { 1, })		// { dg-warning "'template for' only available with" "" { target c++23_down } }
      ;
    for (int x : { , })			// { dg-error "expected primary-expression before ',' token" }
!     ;					// { dg-error "unable to deduce" "" { target *-*-* } .-1 }
    template for (int x : { , })		// { dg-warning "'template for' only available with" "" { target c++23_down } }
      ;					// { dg-error "expected primary-expression before ',' token" "" { target *-*-* } .-1 }
  }
--- 12,18 ----
    template for (int x : { 1, })		// { dg-warning "'template for' only available with" "" { target c++23_down } }
      ;
    for (int x : { , })			// { dg-error "expected primary-expression before ',' token" }
!     ;
    template for (int x : { , })		// { dg-warning "'template for' only available with" "" { target c++23_down } }
      ;					// { dg-error "expected primary-expression before ',' token" "" { target *-*-* } .-1 }
  }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/cpp0x/deleted18.C gcc-16-20251221/gcc/testsuite/g++.dg/cpp0x/deleted18.C
*** gcc-16-20251214/gcc/testsuite/g++.dg/cpp0x/deleted18.C	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/g++.dg/cpp0x/deleted18.C	Sun Dec 21 22:32:08 2025
***************
*** 0 ****
--- 1,20 ----
+ // PR c++/123030
+ // { dg-do compile { target c++11 } }
+ 
+ int n;
+ struct Y {
+   Y () { if (++n == 2) throw 42; }
+   ~Y () = delete;	// { dg-message "declared here" }
+ };
+ 
+ int
+ main ()
+ {
+   try
+     {
+       new Y[2];		// { dg-error "use of deleted function 'Y::~Y\\\(\\\)'" }
+     }
+   catch (...)
+     {
+     }
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/cpp0x/initlist31.C gcc-16-20251221/gcc/testsuite/g++.dg/cpp0x/initlist31.C
*** gcc-16-20251214/gcc/testsuite/g++.dg/cpp0x/initlist31.C	Sun Dec 14 22:32:09 2025
--- gcc-16-20251221/gcc/testsuite/g++.dg/cpp0x/initlist31.C	Sun Dec 21 22:32:08 2025
*************** void f() {
*** 9,13 ****
    auto y =
    {
      string(Equation()) // { dg-error "12:'Equation' was not declared" }
!   }; // { dg-error "unable to deduce" }
  }
--- 9,13 ----
    auto y =
    {
      string(Equation()) // { dg-error "12:'Equation' was not declared" }
!   };
  }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/cpp0x/new4.C gcc-16-20251221/gcc/testsuite/g++.dg/cpp0x/new4.C
*** gcc-16-20251214/gcc/testsuite/g++.dg/cpp0x/new4.C	Sun Dec 14 22:32:09 2025
--- gcc-16-20251221/gcc/testsuite/g++.dg/cpp0x/new4.C	Sun Dec 21 22:32:08 2025
***************
*** 3,9 ****
  
  struct A { ~A () = delete; };
  A *pa{new A{}};
! A *pa2{new A[2]{}};
  
  class B { ~B () = default; };
  B *pb{new B{}};
--- 3,9 ----
  
  struct A { ~A () = delete; };
  A *pa{new A{}};
! A *pa2{new A[2]{}};		// { dg-error "use of deleted function 'A::~A\\\(\\\)'" }
  
  class B { ~B () = default; };
  B *pb{new B{}};
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/cpp0x/noexcept91a.C gcc-16-20251221/gcc/testsuite/g++.dg/cpp0x/noexcept91a.C
*** gcc-16-20251214/gcc/testsuite/g++.dg/cpp0x/noexcept91a.C	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/g++.dg/cpp0x/noexcept91a.C	Sun Dec 21 22:32:08 2025
***************
*** 0 ****
--- 1,26 ----
+ // PR c++/122668
+ // A version of noexcept91.C where the lookup to be deferred isn't nested
+ // inside a noexcept-expr.
+ // { dg-do compile { target c++11 } }
+ 
+ template<class T>
+ struct A {
+   friend void f(A& a) noexcept(g(0)) { }
+   static constexpr bool g(int) { return true; }
+ };
+ 
+ template<class T>
+ struct B {
+   struct C {
+     friend void f(C& a) noexcept(g(0)) { }
+     static constexpr bool g(int) { return false; }
+   };
+ };
+ 
+ int main() {
+   A<int> a;
+   static_assert(noexcept(f(a)), "");
+ 
+   B<int>::C c;
+   static_assert(!noexcept(f(c)), "");
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/cpp1z/eval-order14.C gcc-16-20251221/gcc/testsuite/g++.dg/cpp1z/eval-order14.C
*** gcc-16-20251214/gcc/testsuite/g++.dg/cpp1z/eval-order14.C	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/g++.dg/cpp1z/eval-order14.C	Sun Dec 21 22:32:08 2025
***************
*** 0 ****
--- 1,114 ----
+ // PR c++/122772
+ // { dg-do run }
+ 
+ struct S { int y : 7; } s;
+ struct T { int x; int z : 7; } t;
+ int cnt, mode;
+ 
+ int
+ foo ()
+ {
+ #if __cplusplus >= 201703L
+   if (cnt != 1 + (mode & 1))
+     __builtin_abort ();
+ #endif
+   ++cnt;
+   return 2;
+ }
+ 
+ int
+ bar ()
+ {
+ #if __cplusplus >= 201703L
+   if (cnt != 0)
+     __builtin_abort ();
+ #endif
+   ++cnt;
+   return 40;
+ }
+ 
+ S &
+ baz ()
+ {
+ #if __cplusplus >= 201703L
+   if (cnt != 2 + (mode & 1))
+     __builtin_abort ();
+ #endif
+   if (mode & 2)
+     __builtin_abort ();
+   ++cnt;
+   return s;
+ }
+ 
+ T &
+ qux ()
+ {
+ #if __cplusplus >= 201703L
+   if (cnt != 2 + (mode & 1))
+     __builtin_abort ();
+ #endif
+   if ((mode & 2) == 0)
+     __builtin_abort ();
+   ++cnt;
+   return t;
+ }
+ 
+ bool
+ fred (bool x)
+ {
+ #if __cplusplus >= 201703L
+   if (cnt != 1)
+     __builtin_abort ();
+ #endif
+   ++cnt;
+   return x;
+ }
+ 
+ void
+ plugh (bool b)
+ {
+   S x;
+   x.y = 5;
+   mode = 0;
+   cnt = 0;
+   (x.y = foo ()) += bar ();
+   if (cnt != 2 || x.y != 42)
+     __builtin_abort ();
+   x.y = 5;
+   cnt = 0;
+   (baz ().y = foo ()) += bar ();
+   if (cnt != 3 || s.y != 42)
+     __builtin_abort ();
+   s.y = 5;
+   mode = (b ? 0 : 2);
+   cnt = 0;
+   (b ? (baz ().y = foo ()) : (qux ().z = foo ())) += bar ();
+   if (cnt != 3 || (b ? (s.y != 42) : (t.z != 42)))
+     __builtin_abort ();
+   s.y = 5;
+   t.z = 5;
+   mode |= 1;
+   cnt = 0;
+   (fred (b) ? (baz ().y = foo ()) : (qux ().z = foo ())) += bar ();
+   if (cnt != 4 || (b ? (s.y != 42) : (t.z != 42)))
+     __builtin_abort ();
+   s.y = 5;
+   t.z = 5;
+   mode = 0;
+   cnt = 0;
+   ++x.y += bar ();
+   if (cnt != 1 || x.y != 46)
+     __builtin_abort ();
+   cnt = 0;
+   x.y = 9;
+   --x.y += bar ();
+   if (cnt != 1 || x.y != 48)
+     __builtin_abort ();
+ }
+ 
+ int
+ main ()
+ {
+   plugh (false);
+   plugh (true);
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/cpp1z/static_assert1.C gcc-16-20251221/gcc/testsuite/g++.dg/cpp1z/static_assert1.C
*** gcc-16-20251214/gcc/testsuite/g++.dg/cpp1z/static_assert1.C	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/g++.dg/cpp1z/static_assert1.C	Sun Dec 21 22:32:08 2025
***************
*** 0 ****
--- 1,17 ----
+ // PR c++/91388
+ // Make sure we don't emit -Wreturn-type in functions with failed static_asserts.
+ // { dg-do compile { target c++17 } }
+ 
+ template <int N>
+ int
+ foo ()
+ {
+   if constexpr (N <= 42)
+     return N;
+   else
+     static_assert (false, "too high N");	// { dg-error "too high N" }
+ }						// { dg-bogus "no return statement in function returning non-void" }
+ 
+ int a = foo <0> ();
+ int b = foo <42> ();
+ int c = foo <100> ();
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/cpp23/class-deduction-inherited10.C gcc-16-20251221/gcc/testsuite/g++.dg/cpp23/class-deduction-inherited10.C
*** gcc-16-20251214/gcc/testsuite/g++.dg/cpp23/class-deduction-inherited10.C	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/g++.dg/cpp23/class-deduction-inherited10.C	Sun Dec 21 22:32:08 2025
***************
*** 0 ****
--- 1,11 ----
+ // PR c++/122070
+ // { dg-do compile { target c++23 } }
+ 
+ template<class T> struct A { A(T) {}; };
+ 
+ using B = A<int>;
+ 
+ template<class T=void>
+ struct C : B { using B::B; };
+ 
+ C c = 0;
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/cpp23/class-deduction-inherited9.C gcc-16-20251221/gcc/testsuite/g++.dg/cpp23/class-deduction-inherited9.C
*** gcc-16-20251214/gcc/testsuite/g++.dg/cpp23/class-deduction-inherited9.C	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/g++.dg/cpp23/class-deduction-inherited9.C	Sun Dec 21 22:32:08 2025
***************
*** 0 ****
--- 1,31 ----
+ // PR c++/122070
+ // { dg-do compile { target c++23 } }
+ 
+ namespace std {
+     using size_t = decltype(sizeof(0));
+     template<typename CharT>
+     struct basic_string_view {
+         const CharT* ptr;
+         size_t len;
+         constexpr basic_string_view(const CharT* p) : ptr(p), len(0) { while (p && p[len]) ++len; }
+     };
+     using string_view = basic_string_view<char>;
+ }
+ 
+ template<std::size_t N>
+ struct sized_string_view: std::string_view {
+     using std::string_view::string_view;
+ };
+ template<std::size_t N>
+ sized_string_view(const char (&str)[N]) -> sized_string_view<N - 1>;
+ 
+ constexpr auto string_builder(auto first, auto second, auto... trailing) {
+     constexpr auto is_last = sizeof...(trailing) == 0;
+     auto buffer = 1;
+     if constexpr (is_last) {
+         return buffer;
+     } else
+         return string_builder(buffer, trailing...);
+ }
+ 
+ constexpr auto copyright = string_builder(sized_string_view("a"), sized_string_view("b"), sized_string_view("c"));
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/cpp26/expansion-stmt1.C gcc-16-20251221/gcc/testsuite/g++.dg/cpp26/expansion-stmt1.C
*** gcc-16-20251214/gcc/testsuite/g++.dg/cpp26/expansion-stmt1.C	Sun Dec 14 22:32:09 2025
--- gcc-16-20251221/gcc/testsuite/g++.dg/cpp26/expansion-stmt1.C	Sun Dec 21 22:32:08 2025
*************** struct A
*** 21,38 ****
    int x;
    constexpr explicit A (int v) : x(v) {}
    constexpr A &operator ++ () { ++x; return *this; }
!   constexpr int operator * () { return x; }
!   constexpr bool operator != (const A &o) { return x != o.x; }
!   constexpr A operator + (int o) { A r (x + o); return r; }
  };
  struct C
  {
    int x, y, z;
    constexpr explicit C (int u, int v, int w) : x(u), y(v), z(w) {}
    constexpr C &operator ++ () { ++x; --y; ++z; return *this; }
!   constexpr C operator * () { return *this; }
!   constexpr bool operator != (const C &o) { return x != o.x || y != o.y || z != o.z; }
!   constexpr C operator + (int o) { C r (x + o, y - o, z + o); return r; }
  };
  
  namespace N
--- 21,38 ----
    int x;
    constexpr explicit A (int v) : x(v) {}
    constexpr A &operator ++ () { ++x; return *this; }
!   constexpr int operator * () const { return x; }
!   constexpr bool operator != (const A &o) const { return x != o.x; }
!   constexpr A operator + (int o) const { A r (x + o); return r; }
  };
  struct C
  {
    int x, y, z;
    constexpr explicit C (int u, int v, int w) : x(u), y(v), z(w) {}
    constexpr C &operator ++ () { ++x; --y; ++z; return *this; }
!   constexpr C operator * () const { return *this; }
!   constexpr bool operator != (const C &o) const { return x != o.x || y != o.y || z != o.z; }
!   constexpr C operator + (int o) const { C r (x + o, y - o, z + o); return r; }
  };
  
  namespace N
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/cpp26/expansion-stmt18.C gcc-16-20251221/gcc/testsuite/g++.dg/cpp26/expansion-stmt18.C
*** gcc-16-20251214/gcc/testsuite/g++.dg/cpp26/expansion-stmt18.C	Sun Dec 14 22:32:09 2025
--- gcc-16-20251221/gcc/testsuite/g++.dg/cpp26/expansion-stmt18.C	Sun Dec 21 22:32:08 2025
*************** struct A
*** 8,16 ****
    int x;
    constexpr explicit A (int v) : x(v) {}
    constexpr A &operator ++ () { ++x; return *this; }
!   constexpr int operator * () { return x; }
!   constexpr bool operator != (const A &o) { return x != o.x; }
!   constexpr A operator + (int o) { A r (x + o); return r; }
  };
  
  namespace N
--- 8,16 ----
    int x;
    constexpr explicit A (int v) : x(v) {}
    constexpr A &operator ++ () { ++x; return *this; }
!   constexpr int operator * () const { return x; }
!   constexpr bool operator != (const A &o) const { return x != o.x; }
!   constexpr A operator + (int o) const { A r (x + o); return r; }
  };
  
  namespace N
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/cpp26/expansion-stmt2.C gcc-16-20251221/gcc/testsuite/g++.dg/cpp26/expansion-stmt2.C
*** gcc-16-20251214/gcc/testsuite/g++.dg/cpp26/expansion-stmt2.C	Sun Dec 14 22:32:09 2025
--- gcc-16-20251221/gcc/testsuite/g++.dg/cpp26/expansion-stmt2.C	Sun Dec 21 22:32:08 2025
*************** struct A
*** 21,38 ****
    int x;
    constexpr explicit A (int v) : x(v) {}
    constexpr A &operator ++ () { ++x; return *this; }
!   constexpr int operator * () { return x; }
!   constexpr bool operator != (const A &o) { return x != o.x; }
!   constexpr A operator + (int o) { A r (x + o); return r; }
  };
  struct C
  {
    int x, y, z;
    constexpr explicit C (int u, int v, int w) : x(u), y(v), z(w) {}
    constexpr C &operator ++ () { ++x; --y; ++z; return *this; }
!   constexpr C operator * () { return *this; }
!   constexpr bool operator != (const C &o) { return x != o.x || y != o.y || z != o.z; }
!   constexpr C operator + (int o) { C r (x + o, y - o, z + o); return r; }
  };
  
  namespace N
--- 21,38 ----
    int x;
    constexpr explicit A (int v) : x(v) {}
    constexpr A &operator ++ () { ++x; return *this; }
!   constexpr int operator * () const { return x; }
!   constexpr bool operator != (const A &o) const { return x != o.x; }
!   constexpr A operator + (int o) const { A r (x + o); return r; }
  };
  struct C
  {
    int x, y, z;
    constexpr explicit C (int u, int v, int w) : x(u), y(v), z(w) {}
    constexpr C &operator ++ () { ++x; --y; ++z; return *this; }
!   constexpr C operator * () const { return *this; }
!   constexpr bool operator != (const C &o) const { return x != o.x || y != o.y || z != o.z; }
!   constexpr C operator + (int o) const { C r (x + o, y - o, z + o); return r; }
  };
  
  namespace N
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/cpp26/expansion-stmt3.C gcc-16-20251221/gcc/testsuite/g++.dg/cpp26/expansion-stmt3.C
*** gcc-16-20251214/gcc/testsuite/g++.dg/cpp26/expansion-stmt3.C	Sun Dec 14 22:32:09 2025
--- gcc-16-20251221/gcc/testsuite/g++.dg/cpp26/expansion-stmt3.C	Sun Dec 21 22:32:08 2025
*************** struct A
*** 21,38 ****
    int x;
    constexpr explicit A (int v) : x(v) {}
    constexpr A &operator ++ () { ++x; return *this; }
!   constexpr int operator * () { return x; }
!   constexpr bool operator != (const A &o) { return x != o.x; }
!   constexpr A operator + (int o) { A r (x + o); return r; }
  };
  struct C
  {
    int x, y, z;
    constexpr explicit C (int u, int v, int w) : x(u), y(v), z(w) {}
    constexpr C &operator ++ () { ++x; --y; ++z; return *this; }
!   constexpr C operator * () { return *this; }
!   constexpr bool operator != (const C &o) { return x != o.x || y != o.y || z != o.z; }
!   constexpr C operator + (int o) { C r (x + o, y - o, z + o); return r; }
  };
  
  namespace N
--- 21,38 ----
    int x;
    constexpr explicit A (int v) : x(v) {}
    constexpr A &operator ++ () { ++x; return *this; }
!   constexpr int operator * () const { return x; }
!   constexpr bool operator != (const A &o) const { return x != o.x; }
!   constexpr A operator + (int o) const { A r (x + o); return r; }
  };
  struct C
  {
    int x, y, z;
    constexpr explicit C (int u, int v, int w) : x(u), y(v), z(w) {}
    constexpr C &operator ++ () { ++x; --y; ++z; return *this; }
!   constexpr C operator * () const { return *this; }
!   constexpr bool operator != (const C &o) const { return x != o.x || y != o.y || z != o.z; }
!   constexpr C operator + (int o) const { C r (x + o, y - o, z + o); return r; }
  };
  
  namespace N
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/cpp26/literals2.C gcc-16-20251221/gcc/testsuite/g++.dg/cpp26/literals2.C
*** gcc-16-20251214/gcc/testsuite/g++.dg/cpp26/literals2.C	Sun Dec 14 22:32:09 2025
--- gcc-16-20251221/gcc/testsuite/g++.dg/cpp26/literals2.C	Sun Dec 21 22:32:08 2025
***************
*** 3,8 ****
--- 3,9 ----
  // { dg-require-effective-target int32 }
  // { dg-options "-pedantic-errors -finput-charset=UTF-8 -fexec-charset=ISO-8859-1" }
  /* { dg-require-iconv "ISO-8859-1" } */
+ /* { dg-skip-if "PR c++/112652" *-*-solaris2* } */
  
  int a = 'abcd';						// { dg-warning "multi-character character constant" }
  int b = '\x61\x62\x63\x64';				// { dg-warning "multi-character character constant" }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/cpp2a/concepts-lambda25.C gcc-16-20251221/gcc/testsuite/g++.dg/cpp2a/concepts-lambda25.C
*** gcc-16-20251214/gcc/testsuite/g++.dg/cpp2a/concepts-lambda25.C	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/g++.dg/cpp2a/concepts-lambda25.C	Sun Dec 21 22:32:08 2025
***************
*** 0 ****
--- 1,28 ----
+ // PR c++/123075
+ // { dg-do compile { target c++20 } }
+ // { dg-additional-options "-fkeep-inline-functions" }
+ 
+ template <typename T>
+ concept r = []{ return true; }();
+ 
+ template <typename T, typename U>
+ inline auto foo() {
+   static_assert(r<T>);
+   r<U>;
+   return []{ return false; };
+ }
+ 
+ template <typename T>
+ struct S {
+   static_assert(r<T>);
+   decltype([]{ return true; }) l;
+ };
+ S<char> s;
+ 
+ bool use = (foo<int, double>()() || s.l());
+ 
+ // There should only be one lambda keyed to 'foo()' and 'S::l'
+ // { dg-final { scan-assembler {_ZZ3fooIidEDavENKUlvE_clEv:} } }
+ // { dg-final { scan-assembler {_ZNK1SIcEUlvE_clEv:} } }
+ // { dg-final { scan-assembler-not {_ZZ3fooIidEDavENKUlvE0_clEv:} } }
+ // { dg-final { scan-assembler-not {_ZNK1SIcEUlvE0_clEv:} } }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/cpp2a/lambda-template-pr117034.C gcc-16-20251221/gcc/testsuite/g++.dg/cpp2a/lambda-template-pr117034.C
*** gcc-16-20251214/gcc/testsuite/g++.dg/cpp2a/lambda-template-pr117034.C	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/g++.dg/cpp2a/lambda-template-pr117034.C	Sun Dec 21 22:32:08 2025
***************
*** 0 ****
--- 1,12 ----
+ // { dg-do compile { target c++20 } }
+ // PR c++/117034
+ 
+ template<typename, auto>
+ concept A = true;
+ 
+ void f(A<[] {}> auto) {}
+ 
+ int main()
+ {
+   f(42);
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/dfp/pr122834-1.C gcc-16-20251221/gcc/testsuite/g++.dg/dfp/pr122834-1.C
*** gcc-16-20251214/gcc/testsuite/g++.dg/dfp/pr122834-1.C	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/g++.dg/dfp/pr122834-1.C	Sun Dec 21 22:32:08 2025
***************
*** 0 ****
--- 1,17 ----
+ // PR c++/122834
+ // { dg-do compile { target { c++11 && float128 } } }
+ // { dg-options "" }
+ // { dg-add-options float128 }
+ 
+ typedef decltype (0.0DL) A;
+ typedef _Float128 B;
+ void bar (A);			// { dg-message "initializing argument 1 of" }
+ 
+ void
+ foo (B x)
+ {
+   bar (x);			// { dg-warning "with unordered conversion rank" }
+ }
+ 
+ auto a = 0.0DL + 1.0F128;	// { dg-error "invalid operands to binary \\\+" }
+ auto b = 1.0F128 + 0.0DL;	// { dg-error "invalid operands to binary \\\+" }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/dfp/pr122834-2.C gcc-16-20251221/gcc/testsuite/g++.dg/dfp/pr122834-2.C
*** gcc-16-20251214/gcc/testsuite/g++.dg/dfp/pr122834-2.C	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/g++.dg/dfp/pr122834-2.C	Sun Dec 21 22:32:08 2025
***************
*** 0 ****
--- 1,19 ----
+ // PR c++/122834
+ // { dg-do compile { target { c++11 && float16 } } }
+ // { dg-options "" }
+ // { dg-add-options float16 }
+ 
+ typedef decltype (0.0DL) A;
+ typedef _Float16 B;
+ void bar (A);
+ 
+ void
+ foo (B x)
+ {
+   bar (x);
+ }
+ 
+ auto a = 0.0DL + 1.0F16;
+ auto b = 1.0F16 + 0.0DL;
+ static_assert (__is_same_as (decltype (0.0DL + 1.0F16), decltype (0.0DL)));
+ static_assert (__is_same_as (decltype (1.0F16 + 0.0DL), decltype (0.0DL)));
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/ext/is_implicit_lifetime2.C gcc-16-20251221/gcc/testsuite/g++.dg/ext/is_implicit_lifetime2.C
*** gcc-16-20251214/gcc/testsuite/g++.dg/ext/is_implicit_lifetime2.C	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/g++.dg/ext/is_implicit_lifetime2.C	Sun Dec 21 22:32:08 2025
***************
*** 0 ****
--- 1,91 ----
+ // PR c++/122690
+ // { dg-do compile { target c++11 } }
+ 
+ class A {
+   int i;
+ public:
+   A () = default;
+   A (int i) : i(i) { }
+   A (A const &x) : i(x.i) {}
+   A (A &&x) : i(x.i) {}
+ };
+ class B {
+   int i;
+ protected:
+   B () = default;
+ public:
+   B (int i) : i(i) { }
+   B (B const &x) : i(x.i) {}
+   B (B &&x) : i(x.i) {}
+ };
+ class C {
+   int i;
+ private:
+   C () = default;
+ public:
+   C (int i) : i(i) { }
+   C (C const &x) : i(x.i) {}
+   C (C &&x) : i(x.i) {}
+ };
+ class D {
+   int i;
+ public:
+   D (D const &) = default;
+   D () : i(0) {}
+   D (int i) : i(i) { }
+   D (D &&x) : i(x.i) {}
+ };
+ class E {
+   int i;
+ protected:
+   E (E const &) = default;
+ public:
+   E () : i(0) {}
+   E (int i) : i(i) { }
+   E (E &&x) : i(x.i) {}
+ };
+ class F {
+   int i;
+ private:
+   F (F const &) = default;
+ public:
+   F () : i(0) {}
+   F (int i) : i(i) { }
+   F (F &&x) : i(x.i) {}
+ };
+ class G {
+   int i;
+ public:
+   G (G &&) = default;
+   G () : i(0) {}
+   G (int i) : i(i) { }
+   G (const G &x) : i(x.i) {}
+ };
+ class H {
+   int i;
+ protected:
+   H (H &&) = default;
+ public:
+   H () : i(0) {}
+   H (int i) : i(i) { }
+   H (const H &x) : i(x.i) {}
+ };
+ class I {
+   int i;
+ private:
+   I (I &&) = default;
+ public:
+   I () : i(0) {}
+   I (int i) : i(i) { }
+   I (const I &x) : i(x.i) {}
+ };
+ 
+ static_assert (__builtin_is_implicit_lifetime (A), "");
+ static_assert (__builtin_is_implicit_lifetime (B), "");
+ static_assert (__builtin_is_implicit_lifetime (C), "");
+ static_assert (__builtin_is_implicit_lifetime (D), "");
+ static_assert (__builtin_is_implicit_lifetime (E), "");
+ static_assert (__builtin_is_implicit_lifetime (F), "");
+ static_assert (__builtin_is_implicit_lifetime (G), "");
+ static_assert (__builtin_is_implicit_lifetime (H), "");
+ static_assert (__builtin_is_implicit_lifetime (I), "");
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/guality/decomp1.C gcc-16-20251221/gcc/testsuite/g++.dg/guality/decomp1.C
*** gcc-16-20251214/gcc/testsuite/g++.dg/guality/decomp1.C	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/g++.dg/guality/decomp1.C	Sun Dec 21 22:32:09 2025
***************
*** 0 ****
--- 1,38 ----
+ // PR debug/122968
+ // { dg-do run { target int32plus } }
+ // { dg-options "-g" }
+ 
+ struct S { unsigned a; unsigned long long b; short c; } s = { 10, 53967718, -42 };
+ auto [ a, b, c ] = s;
+ static auto [ d, e, f ] = S { 5, 1245234412, -231 };
+ auto *p = &d;
+ volatile int v;
+ namespace N {
+   auto [ a, b, c ] = S { 8, 7135498, 256 };
+   int arr[4] = { 1, 2, 3, 4 };
+   auto [ d, e, f, g ] = arr;
+ }
+ 
+ int
+ main ()
+ {
+   asm volatile ("" : : "g" (&a), "g" (&b), "g" (&c) : "memory");
+   asm volatile ("" : : "g" (&d), "g" (&e), "g" (&f) : "memory");
+   asm volatile ("" : : "g" (&N::a), "g" (&N::b), "g" (&N::c) : "memory");
+   asm volatile ("" : : "g" (&N::d), "g" (&N::e), "g" (&N::f) : "memory");
+   asm volatile ("" : : "g" (&N::g) : "memory");
+   v = 1;
+ // { dg-final { gdb-test 24 "a" "10" } }
+ // { dg-final { gdb-test 24 "b" "53967718" } }
+ // { dg-final { gdb-test 24 "c" "-42" } }
+ // { dg-final { gdb-test 24 "d" "5" } }
+ // { dg-final { gdb-test 24 "e" "1245234412" } }
+ // { dg-final { gdb-test 24 "f" "-231" } }
+ // { dg-final { gdb-test 24 "N::a" "8" } }
+ // { dg-final { gdb-test 24 "N::b" "7135498" } }
+ // { dg-final { gdb-test 24 "N::c" "256" } }
+ // { dg-final { gdb-test 24 "N::d" "1" } }
+ // { dg-final { gdb-test 24 "N::e" "2" } }
+ // { dg-final { gdb-test 24 "N::f" "3" } }
+ // { dg-final { gdb-test 24 "N::g" "4" } }
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/modules/adl-12_a.C gcc-16-20251221/gcc/testsuite/g++.dg/modules/adl-12_a.C
*** gcc-16-20251214/gcc/testsuite/g++.dg/modules/adl-12_a.C	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/g++.dg/modules/adl-12_a.C	Sun Dec 21 22:32:09 2025
***************
*** 0 ****
--- 1,94 ----
+ // { dg-additional-options "-fmodules -Wno-global-module -fdump-lang-module" }
+ // { dg-module-cmi M }
+ 
+ // Check we implement [module.global.frag] p2.3:
+ // A declaration D is decl-reachable from a declaration S in the same
+ // translation unit if: [...] S contains a dependent call E ([temp.dep]) and
+ // D is found by any name lookup performed for an expression synthesized from
+ // E by replacing each type-dependent argument or operand with a value of a
+ // placeholder type with no associated namespaces or entities.
+ 
+ module;
+ namespace Q {
+   struct X {};
+   void g_impl(X, X);
+   void operator-(X, X);
+   void go_partial(X, int);
+   void operator/(X, int);
+ }
+ namespace P {
+   struct X {};
+ }
+ #if __cpp_impl_three_way_comparison >= 201907L
+ namespace ops1 {
+   struct Y {};
+   int operator<=>(Y, int);
+   bool operator==(Y, int);
+ }
+ namespace ops2 {
+   struct Y {};
+   bool operator==(Y, int);
+   bool operator!=(Y, int);
+ }
+ #endif
+ namespace Incomplete {
+   template <typename T> struct Holder { T t; };
+   struct Z;
+   void go(int, void*);
+ }
+ namespace C {
+   struct G {};
+   void qux(int, void*);
+ }
+ template <typename T> struct H : C::G {};
+ export module M;
+ 
+ export template <typename T>
+ void g(T t) {
+   g_impl(t, Q::X{});  // ADL in definition finds Q::g_impl, g_impl not discarded
+   // { dg-final { scan-lang-dump "Bindings '::Q::g_impl'" module } }
+ 
+   t - Q::X{};  // Similarly for Q::operator-
+   // { dg-final { scan-lang-dump "Bindings '::Q::operator-'" module } }
+ }
+ 
+ export template <typename T> struct Partial {
+   template <typename U> static decltype(go_partial(T{}, U{})) f();
+   template <typename U> static decltype(T{} / U{}) o();
+ };
+ // The instantantiation of Partial<Q::X> should emit go_partial and operator/
+ template struct Partial<Q::X>;
+ // { dg-final { scan-lang-dump "Bindings '::Q::go_partial'" module } }
+ // { dg-final { scan-lang-dump "Bindings '::Q::operator/'" module } }
+ 
+ #if __cpp_impl_three_way_comparison >= 201907L
+ export template <typename T>
+ void rewrite_ops(T t) {
+   // Rewritten operators should also look for the ops they rewrite to.
+   t < ops1::Y{};
+   t != ops1::Y{};
+   // { dg-final { scan-lang-dump {Bindings '::ops1::operator<=>'} module { target c++20 } } }
+   // { dg-final { scan-lang-dump {Bindings '::ops1::operator=='} module { target c++20 } } }
+ }
+ export template <typename T>
+ void rewrite_ops_error(T t) {
+   // Test we bind != to prevent considering == as a rewrite target.
+   t == ops2::Y{};
+   // { dg-final { scan-lang-dump "Bindings '::ops2::operator!='" module { target c++20 } } }
+ }
+ #endif
+ 
+ export template <typename T>
+ void incomplete(T t) {
+   Incomplete::Holder<Incomplete::Z>* holder;
+   go(t, holder);  // Shouldn't attempt to instantiate unnecessarily here
+ }
+ 
+ export template <typename T>
+ void needs_completion(T t) {
+   H<int>* holder;
+   // C::qux should be found via H<T>'s base, C::G.
+   // But we don't see this because we don't attempt to complete the type.
+   qux(t, holder);
+   // { dg-final { scan-lang-dump "Bindings '::C::qux'" module { xfail *-*-* } } }
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/modules/adl-12_b.C gcc-16-20251221/gcc/testsuite/g++.dg/modules/adl-12_b.C
*** gcc-16-20251214/gcc/testsuite/g++.dg/modules/adl-12_b.C	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/g++.dg/modules/adl-12_b.C	Sun Dec 21 22:32:09 2025
***************
*** 0 ****
--- 1,29 ----
+ // { dg-additional-options "-fmodules" }
+ // Example from [temp.dep.candidate]
+ 
+ namespace Q {
+   struct X {};
+ }
+ namespace Incomplete {
+   struct Z {};
+ };
+ 
+ import M;
+ 
+ void test(Q::X x) {
+   g(x);  // OK
+   Partial<Q::X>::f<int>();
+   Partial<Q::X>::o<int>();
+   incomplete(0);  // OK
+   needs_completion(0);  // { dg-bogus "required from here" "PR123235" { xfail *-*-* } }
+   // { dg-prune-output "not declared in this scope" }
+ 
+ #if __cpp_impl_three_way_comparison >= 201907L
+   rewrite_ops(0);  // OK
+ 
+   // This should error, but lookup_qualified_name in add_candidates
+   // doesn't look in the instantiation context of this call, so
+   // we don't see the operator!= and think we can validly rewrite.
+   rewrite_ops_error(0);  // { dg-error "required from here" "PR122609" { xfail *-*-* } }
+ #endif
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/modules/lambda-13.h gcc-16-20251221/gcc/testsuite/g++.dg/modules/lambda-13.h
*** gcc-16-20251214/gcc/testsuite/g++.dg/modules/lambda-13.h	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/g++.dg/modules/lambda-13.h	Sun Dec 21 22:32:09 2025
***************
*** 0 ****
--- 1,22 ----
+ // PR c++/123075
+ 
+ template <typename T>
+ concept r = []{ return true; }();
+ 
+ template <typename T>
+ inline void foo() {
+   static_assert(r<T>);
+ }
+ 
+ template void foo<int>();
+ 
+ template <typename T>
+ struct S {
+   static_assert(r<T>);
+ };
+ 
+ template struct S<double>;
+ 
+ enum E {
+   X = r<E>,
+ };
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/modules/lambda-13_a.H gcc-16-20251221/gcc/testsuite/g++.dg/modules/lambda-13_a.H
*** gcc-16-20251214/gcc/testsuite/g++.dg/modules/lambda-13_a.H	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/g++.dg/modules/lambda-13_a.H	Sun Dec 21 22:32:09 2025
***************
*** 0 ****
--- 1,6 ----
+ // PR c++/123075
+ // { dg-do compile { target c++20 } }
+ // { dg-additional-options "-fmodule-header" }
+ // { dg-module-cmi {} }
+ 
+ #include "lambda-13.h"
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/modules/lambda-13_b.C gcc-16-20251221/gcc/testsuite/g++.dg/modules/lambda-13_b.C
*** gcc-16-20251214/gcc/testsuite/g++.dg/modules/lambda-13_b.C	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/g++.dg/modules/lambda-13_b.C	Sun Dec 21 22:32:09 2025
***************
*** 0 ****
--- 1,6 ----
+ // PR c++/123075
+ // { dg-do compile { target c++20 } }
+ // { dg-additional-options "-fmodules -fno-module-lazy" }
+ 
+ #include "lambda-13.h"
+ import "lambda-13_a.H";
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/modules/namespace-17_a.C gcc-16-20251221/gcc/testsuite/g++.dg/modules/namespace-17_a.C
*** gcc-16-20251214/gcc/testsuite/g++.dg/modules/namespace-17_a.C	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/g++.dg/modules/namespace-17_a.C	Sun Dec 21 22:32:09 2025
***************
*** 0 ****
--- 1,8 ----
+ // PR c++/122995
+ // { dg-additional-options "-fmodules" }
+ // { dg-module-cmi bug2 }
+ 
+ export module bug2;
+ namespace N {
+   namespace C { struct r3_cpo; } export extern inline C::r3_cpo const r3;
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/modules/namespace-17_b.C gcc-16-20251221/gcc/testsuite/g++.dg/modules/namespace-17_b.C
*** gcc-16-20251214/gcc/testsuite/g++.dg/modules/namespace-17_b.C	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/g++.dg/modules/namespace-17_b.C	Sun Dec 21 22:32:09 2025
***************
*** 0 ****
--- 1,10 ----
+ // PR c++/122995
+ // { dg-additional-options "-fmodules" }
+ // { dg-module-cmi bug }
+ 
+ export module bug;
+ import bug2;
+ namespace N {
+   namespace C { struct r1_cpo; } export extern inline C::r1_cpo const r1;
+   namespace C { struct r2_cpo; } export extern inline C::r2_cpo const r2;
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/modules/pr122922_a.C gcc-16-20251221/gcc/testsuite/g++.dg/modules/pr122922_a.C
*** gcc-16-20251214/gcc/testsuite/g++.dg/modules/pr122922_a.C	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/g++.dg/modules/pr122922_a.C	Sun Dec 21 22:32:09 2025
***************
*** 0 ****
--- 1,18 ----
+ // PR c++/122922
+ // { dg-additional-options "-fmodules" }
+ // { dg-module-cmi VF }
+ 
+ export module VF;
+ 
+ template <int N> struct TTensor {
+   friend void foo(TTensor) {}
+   TTensor<N - 1> TensorArr[1];
+ };
+ 
+ template <> struct TTensor<0> {
+   friend void foo(TTensor) {}
+ };
+ 
+ template <typename T = void> void TCampo() {
+   foo(TTensor<1>());
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/modules/pr122922_b.C gcc-16-20251221/gcc/testsuite/g++.dg/modules/pr122922_b.C
*** gcc-16-20251214/gcc/testsuite/g++.dg/modules/pr122922_b.C	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/g++.dg/modules/pr122922_b.C	Sun Dec 21 22:32:09 2025
***************
*** 0 ****
--- 1,8 ----
+ // PR c++/122922
+ // { dg-additional-options "-fmodules" }
+ 
+ module VF;
+ 
+ void go() {
+   TCampo();
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/parse/pr121443.C gcc-16-20251221/gcc/testsuite/g++.dg/parse/pr121443.C
*** gcc-16-20251214/gcc/testsuite/g++.dg/parse/pr121443.C	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/g++.dg/parse/pr121443.C	Sun Dec 21 22:32:09 2025
***************
*** 0 ****
--- 1,11 ----
+ // PR c++/121443
+ // { dg-do compile { target c++11 } }
+ 
+ void f(int i = []() {
+   struct X {
+     int val;
+     X(int v) : val(v) { }
+   };
+   X x(2);
+   return x.val;
+ }()) {}
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/plugin/plugin.exp gcc-16-20251221/gcc/testsuite/g++.dg/plugin/plugin.exp
*** gcc-16-20251214/gcc/testsuite/g++.dg/plugin/plugin.exp	Sun Dec 14 22:32:09 2025
--- gcc-16-20251221/gcc/testsuite/g++.dg/plugin/plugin.exp	Sun Dec 21 22:32:09 2025
***************
*** 19,30 ****
  load_lib target-supports.exp
  load_lib g++-dg.exp
  
- global TESTING_IN_BUILD_TREE
  global ENABLE_PLUGIN
  
! # The plugin testcases currently only work when the build tree is available.
! # Also check whether the host supports plugins.
! if { ![info exists TESTING_IN_BUILD_TREE] || ![info exists ENABLE_PLUGIN] } {
      return
  }
  
--- 19,28 ----
  load_lib target-supports.exp
  load_lib g++-dg.exp
  
  global ENABLE_PLUGIN
  
! # Check whether the host supports plugins.
! if { ![info exists ENABLE_PLUGIN] } {
      return
  }
  
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/tc1/dr176-2.C gcc-16-20251221/gcc/testsuite/g++.dg/tc1/dr176-2.C
*** gcc-16-20251214/gcc/testsuite/g++.dg/tc1/dr176-2.C	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/g++.dg/tc1/dr176-2.C	Sun Dec 21 22:32:09 2025
***************
*** 0 ****
--- 1,13 ----
+ // { dg-do compile }
+ // PR c++/122509
+ 
+ namespace s {
+   template<class A>
+   struct v {
+     void size() {}
+   };
+ }
+ struct D : public s::v<double>, public s::v<int> {};
+ int main() {
+   D().v<int>::size();
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/template/crash133.C gcc-16-20251221/gcc/testsuite/g++.dg/template/crash133.C
*** gcc-16-20251214/gcc/testsuite/g++.dg/template/crash133.C	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/g++.dg/template/crash133.C	Sun Dec 21 22:32:09 2025
***************
*** 0 ****
--- 1,6 ----
+ // PR c++/123186
+ 
+ template <class T>
+ struct A : T {
+   typename A <T>::template B <42> C;
+ };
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/template/dependent-name19.C gcc-16-20251221/gcc/testsuite/g++.dg/template/dependent-name19.C
*** gcc-16-20251214/gcc/testsuite/g++.dg/template/dependent-name19.C	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/g++.dg/template/dependent-name19.C	Sun Dec 21 22:32:09 2025
***************
*** 0 ****
--- 1,22 ----
+ // PR c++/122752
+ 
+ struct set {
+   typedef unsigned size_type;
+   unsigned size() { return 42; }
+ };
+ 
+ template<class S>
+ struct A {
+   typedef S VertexSet;
+   typename VertexSet::size_type size();
+   VertexSet vertices_;
+ };
+ 
+ template<class S>
+ inline typename A<S>::VertexSet::size_type A<S>::size()
+ { return vertices_.size(); }
+ 
+ int main() {
+   A<set> a;
+   a.size();
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/template/implicit-func-cast.C gcc-16-20251221/gcc/testsuite/g++.dg/template/implicit-func-cast.C
*** gcc-16-20251214/gcc/testsuite/g++.dg/template/implicit-func-cast.C	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/g++.dg/template/implicit-func-cast.C	Sun Dec 21 22:32:09 2025
***************
*** 0 ****
--- 1,9 ----
+ // { dg-do compile }
+ 
+ typedef int& R;
+ 
+ template <typename T>
+ void foo (T x)
+ {
+   foo (R (x));
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/tree-ssa/pr44706.C gcc-16-20251221/gcc/testsuite/g++.dg/tree-ssa/pr44706.C
*** gcc-16-20251214/gcc/testsuite/g++.dg/tree-ssa/pr44706.C	Sun Dec 14 22:32:10 2025
--- gcc-16-20251221/gcc/testsuite/g++.dg/tree-ssa/pr44706.C	Sun Dec 21 22:32:09 2025
*************** XMLExcepts::AttrList_BadIndex, getMemory
*** 41,45 ****
  }
  
  /* Mistake in branch prediction caused us to split away real body of the function keeping
!    only throw () invokation.   This is bad idea.  */
  /* { dg-final { scan-tree-dump-not "Splitting function" "fnsplit"} } */
--- 41,45 ----
  }
  
  /* Mistake in branch prediction caused us to split away real body of the function keeping
!    only throw () invocation.   This is bad idea.  */
  /* { dg-final { scan-tree-dump-not "Splitting function" "fnsplit"} } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/tree-ssa/pr87502.C gcc-16-20251221/gcc/testsuite/g++.dg/tree-ssa/pr87502.C
*** gcc-16-20251214/gcc/testsuite/g++.dg/tree-ssa/pr87502.C	Sun Dec 14 22:32:10 2025
--- gcc-16-20251221/gcc/testsuite/g++.dg/tree-ssa/pr87502.C	Sun Dec 21 22:32:09 2025
*************** bar ()
*** 11,15 ****
  {
    return foo ("abc") + foo (std::string("abc"));
  }
! // We used to add terminating zero explicitely instead of using fact
  // that memcpy source is already 0 terminated.
--- 11,15 ----
  {
    return foo ("abc") + foo (std::string("abc"));
  }
! // We used to add terminating zero explicitly instead of using fact
  // that memcpy source is already 0 terminated.
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/vect/pr64410.cc gcc-16-20251221/gcc/testsuite/g++.dg/vect/pr64410.cc
*** gcc-16-20251214/gcc/testsuite/g++.dg/vect/pr64410.cc	Sun Dec 14 22:32:10 2025
--- gcc-16-20251221/gcc/testsuite/g++.dg/vect/pr64410.cc	Sun Dec 21 22:32:09 2025
***************
*** 1,6 ****
--- 1,9 ----
  // { dg-do compile }
  // { dg-require-effective-target vect_double }
  // { dg-additional-options "-fexcess-precision=fast" }
+ // We require decomposing a structure copy to double load/store pairs which
+ // is not possible with x87 math.
+ // { dg-additional-options "-msse -mfpmath=sse" { target { x86_64-*-* i?86-*-* } } }
  // { dg-skip-if "requires hosted libstdc++ for vector" { ! hostedlib } }
  
  #include <vector>
*************** main(int argc, char** argv)
*** 51,54 ****
    return 0;
  }
  
! // { dg-final { scan-tree-dump "pr64410.cc:46:29: optimized: loop vectorized" "vect" } }
--- 54,57 ----
    return 0;
  }
  
! // { dg-final { scan-tree-dump "pr64410.cc:49:29: optimized: loop vectorized" "vect" } }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.dg/vect/vect-uncounted-prolog-peel_1.cc gcc-16-20251221/gcc/testsuite/g++.dg/vect/vect-uncounted-prolog-peel_1.cc
*** gcc-16-20251214/gcc/testsuite/g++.dg/vect/vect-uncounted-prolog-peel_1.cc	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/g++.dg/vect/vect-uncounted-prolog-peel_1.cc	Sun Dec 21 22:32:09 2025
***************
*** 0 ****
--- 1,51 ----
+ /* { dg-add-options vect_early_break } */
+ /* { dg-do compile } */
+ /* { dg-require-effective-target vect_early_break } */
+ /* { dg-require-effective-target vect_int } */
+ /* { dg-additional-options "-w" } */
+ 
+ namespace a {
+ class b {
+ public:
+   b d(long);
+ };
+ class e : public b {};
+ typedef short f;
+ typedef struct g *h;
+ typedef struct g {
+   f c;
+   e *fp;
+   f j, *k, *l;
+ } m;
+ static h n(m *, unsigned, unsigned *);
+ f o(m *, unsigned);
+ void p(short *t) {
+   m *ffile;
+   int q;
+   unsigned r;
+   int i;
+   q = t[i];
+   n(ffile, q, &r);
+ }
+ h n(m *ffile, unsigned q, unsigned *) {
+   h glyph;
+   for (; glyph;)
+     if (glyph->c)
+       o(ffile, q);
+   int i;
+ s:
+   for (i = 0; ffile->j; i++)
+     if (ffile->k[i]) {
+       if (q)
+         ffile->fp->d(ffile->l[i]);
+       break;
+     }
+   if (q < 6) {
+     q += 61440;
+     goto s;
+   }
+ }
+ } // namespace a
+ 
+ /* { dg-final { scan-tree-dump {note:\s*Alignment of access forced using peeling.} "vect" } } */
+ /* { dg-final { scan-tree-dump {vectorized 1 loops in function} "vect" } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.target/i386/mv29.C gcc-16-20251221/gcc/testsuite/g++.target/i386/mv29.C
*** gcc-16-20251214/gcc/testsuite/g++.target/i386/mv29.C	Sun Dec 14 22:32:10 2025
--- gcc-16-20251221/gcc/testsuite/g++.target/i386/mv29.C	Sun Dec 21 22:32:09 2025
*************** int __attribute__ ((target("arch=znver5"
*** 57,62 ****
--- 57,66 ----
    return 11;
  }
  
+ int __attribute__ ((target("arch=znver6"))) foo () {
+   return 12;
+ }
+ 
  int main ()
  {
    int val = foo ();
*************** int main ()
*** 83,88 ****
--- 87,94 ----
      assert (val == 10);
    else if (__builtin_cpu_is ("znver5"))
      assert (val == 11);
+   else if (__builtin_cpu_is ("znver6"))
+     assert (val == 12);
    else
      assert (val == 0);
  
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.target/riscv/rvv/autovec/pr123118.C gcc-16-20251221/gcc/testsuite/g++.target/riscv/rvv/autovec/pr123118.C
*** gcc-16-20251214/gcc/testsuite/g++.target/riscv/rvv/autovec/pr123118.C	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/g++.target/riscv/rvv/autovec/pr123118.C	Sun Dec 21 22:32:09 2025
***************
*** 0 ****
--- 1,19 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O3 -march=rv64gcv -mabi=lp64d" } */
+ 
+ long long a;
+ short c, d;
+ extern int e[][1][1][1];
+ extern bool f[][1][4][2];
+ #include <vector>
+ 
+ void
+ g ()
+ {
+   for (bool b;;)
+     for (signed char h (c); h < 4; h += -4487 - 119)
+       {
+ 	e[b][b][b][b] = std::max (std::min ((long long) 3, a), (long long) d);
+ 	f[0][0][h][1] = h;
+       }
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.target/sh/sh.exp gcc-16-20251221/gcc/testsuite/g++.target/sh/sh.exp
*** gcc-16-20251214/gcc/testsuite/g++.target/sh/sh.exp	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/g++.target/sh/sh.exp	Sun Dec 21 22:32:09 2025
***************
*** 0 ****
--- 1,297 ----
+ # Copyright (C) 2024 Free Software Foundation, Inc.
+ 
+ # This program 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 of the License, or
+ # (at your option) any later version.
+ #
+ # This program 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/>.
+ 
+ # GCC testsuite that uses the `dg.exp' driver.
+ 
+ # Exit immediately if this isn't an SH target.
+ if ![istarget sh*-*-*] then {
+   return
+ }
+ 
+ # Load support procs.
+ load_lib g++-dg.exp
+ 
+ # Return 1 if target is SH2A
+ proc check_effective_target_sh2a { } {
+     return [check_no_compiler_messages sh2a object {
+ 	     #ifndef __SH2A__
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ # Return 1 if target is SH1
+ proc check_effective_target_sh1 { } {
+     return [check_no_compiler_messages sh1 object {
+ 	     #ifndef __SH1__
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ # Return 1 if target is SH4A
+ proc check_effective_target_sh4a { } {
+     return [check_no_compiler_messages sh4a object {
+ 	     #ifndef __SH4A__
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ # Return 1 if target is big endian
+ proc check_effective_target_big_endian { } {
+     return [check_no_compiler_messages big_endian object {
+ 	     #if __BYTE_ORDER__ != __ORDER_BIG_ENDIAN__
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ # Return 1 if target is little endian
+ proc check_effective_target_little_endian { } {
+     return [check_no_compiler_messages little_endian object {
+ 	     #if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ # Return 1 if the target has any FPU (single or double precision)
+ proc check_effective_target_any_fpu { } {
+     return [check_no_compiler_messages any_fpu object {
+ 	     #ifndef __SH_FPU_ANY__
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ # Return 1 if the target has a double precision FPU which is allowed to be
+ # used by the compiler as such.
+ proc check_effective_target_double_fpu { } {
+     return [check_no_compiler_messages double_fpu object {
+ 	     #ifndef __SH_FPU_DOUBLE__
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ # Return 1 if the target has a double precision FPU but it is only being used
+ # in single precision mode by the compiler
+ proc check_effective_target_use_single_only_fpu { } {
+     return [check_no_compiler_messages use_single_only_fpu object {
+ 	     #if !(defined (__SH2A_SINGLE_ONLY__) \
+ 		   || defined (__SH4_SINGLE_ONLY__))
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ # Return 1 if the target has an FPU and the default mode is single
+ proc check_effective_target_default_single_fpu { } {
+     return [check_no_compiler_messages default_single_fpu object {
+ 	     #if !(defined (__SH2E__) || defined (__SH3E__) \
+ 		   || defined (__SH2A_SINGLE__) \
+ 		   || defined (__SH2A_SINGLE_ONLY__) \
+ 		   || defined (__SH4_SINGLE__) \
+ 		   || defined (__SH4_SINGLE_ONLY__))
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ # Return 1 if the target has no FPU
+ proc check_effective_target_no_fpu { } {
+     return [check_no_compiler_messages no_fpu object {
+ 	     #ifdef __SH_FPU_ANY__
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ 
+ # Return 1 if the target has XF regs
+ proc check_effective_target_has_xf_regs { } {
+     return [check_no_compiler_messages has_xf_regs object {
+ 	     #if !(defined (__SH_FPU_ANY__) \
+ 		   && (defined (__SH4__) \
+ 		       || defined (__SH4_SINGLE__) \
+ 		       || defined (__SH4_SINGLE_ONLY__) \
+ 		       || defined (__SH4A__)))
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ 
+ # Return 1 if the target can do the fsca insn
+ proc check_effective_target_has_fsca { } {
+     return [check_no_compiler_messages has_fsca object {
+ 	     #if !(defined (__SH_FPU_ANY__) \
+ 		   && (defined (__SH4__) \
+ 		       || defined (__SH4_SINGLE__) \
+ 		       || defined (__SH4_SINGLE_ONLY__) \
+ 		       || defined (__SH4A__)))
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ # Return 1 if the target can do the fsrra insn
+ proc check_effective_target_has_fsrra { } {
+     return [check_no_compiler_messages has_fsrra object {
+ 	     #if !(defined (__SH_FPU_ANY__) \
+ 		   && (defined (__SH4__) \
+ 		       || defined (__SH4_SINGLE__) \
+ 		       || defined (__SH4_SINGLE_ONLY__) \
+ 		       || defined (__SH4A__)))
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ # Return 1 if the target can do the fpchg insn
+ proc check_effective_target_has_fpchg { } {
+     return [check_no_compiler_messages has_fpchg object {
+ 	     #if !(defined (__SH4A__) && defined (__SH_FPU_ANY__) \
+ 		   && !defined (__SH4_SINGLE_ONLY__))
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ # Return 1 if the target can do dynamic shifts
+ proc check_effective_target_has_dyn_shift { } {
+     return [check_no_compiler_messages has_dyn_shift object {
+ 	     #if !(defined (__SH3__) \
+ 		   || defined (__SH3E__) \
+ 		   || defined (__SH2A__) \
+ 		   || defined (__SH4__) \
+ 		   || defined (__SH4_NOFPU__) \
+ 		   || defined (__SH4_SINGLE__) \
+ 		   || defined (__SH4_SINGLE_ONLY__) \
+ 		   || defined (__SH4A__))
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ # Return 1 if the mfmovd option is enabled
+ proc check_effective_target_fmovd_enabled { } {
+     return [check_no_compiler_messages fmovd_enabled object {
+ 	     #ifndef __FMOVD_ENABLED__
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ # Return 1 if the target supports privileged mode
+ proc check_effective_target_has_privileged { } {
+     return [check_no_compiler_messages has_privileged object {
+ 	     #if !(defined (__SH3__) \
+ 		   || defined (__SH3E__) \
+ 		   || defined (__SH4__) \
+ 		   || defined (__SH4_NOFPU__) \
+ 		   || defined (__SH4_SINGLE__) \
+ 		   || defined (__SH4_SINGLE_ONLY__) \
+ 		   || defined (__SH4A__))
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ # Return 1 if the target supports the prefetch insn
+ proc check_effective_target_has_pref { } {
+     return [check_no_compiler_messages has_pref object {
+ 	     #if !(defined (__SH3__) \
+ 		   || defined (__SH3E__) \
+ 		   || defined (__SH4__) \
+ 		   || defined (__SH4_NOFPU__) \
+ 		   || defined (__SH4_SINGLE__) \
+ 		   || defined (__SH4_SINGLE_ONLY__) \
+ 		   || defined (__SH4A__))
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ # Return 1 if target does banked r0..r7 regs type of ISRs
+ proc check_effective_target_banked_r0r7_isr { } {
+     return [check_no_compiler_messages banked_r0r7_isr object {
+ 	     #if !(defined (__SH3__) || defined (__SH3E__) \
+ 		   || defined (__SH4__) \
+ 		   || defined (__SH4_SINGLE__) \
+ 		   || defined (__SH4_SINGLE_ONLY__) \
+ 		   || defined (__SH4_NOFPU__) \
+ 		   || defined (__SH4A__))
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ # Return 1 if target does stack only type of ISRs
+ proc check_effective_target_stack_save_isr { } {
+     return [check_no_compiler_messages stack_save_isr object {
+ 	     #if !(defined (__SH1__) \
+ 		   || defined (__SH2__) \
+ 		   || defined (__SH2E__) \
+ 		   || defined (__SH2A__))
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ # Return 1 if target supports atomic-model=soft-gusa
+ proc check_effective_target_atomic_model_soft_gusa_available { } {
+     return [check_no_compiler_messages atomic_model_soft_gusa_available object {
+ 	     int x = 0;
+     } "-matomic-model=soft-gusa"]
+ }
+ 
+ # Return 1 if target supports atomic-model=soft-tcb
+ proc check_effective_target_atomic_model_soft_tcb_available { } {
+     return [check_no_compiler_messages atomic_model_soft_tcb_available object {
+ 	     int x = 0;
+     } "-matomic-model=soft-tcb,gbr-offset=0"]
+ }
+ 
+ # Return 1 if target supports atomic-model=soft-imask
+ proc check_effective_target_atomic_model_soft_imask_available { } {
+     return [check_no_compiler_messages atomic_model_soft_imask_available object {
+ 	     int x = 0;
+     } "-matomic-model=soft-imask -mno-usermode"]
+ }
+ 
+ # Return 1 if target supports atomic-model=hard-llcs
+ proc check_effective_target_atomic_model_hard_llcs_available { } {
+     return [check_no_compiler_messages atomic_model_hard_llcs_available object {
+ 	     int x = 0;
+     } "-matomic-model=hard-llcs"]
+ }
+ 
+ # If a testcase doesn't have special options, use these.
+ global DEFAULT_CXXFLAGS
+ if ![info exists DEFAULT_CXXFLAGS] then {
+     set DEFAULT_CXXFLAGS " -pedantic-errors"
+ }
+ 
+ # Initialize `dg'.
+ dg-init
+ 
+ # Main loop.
+ dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C]] "" $DEFAULT_CXXFLAGS
+ 
+ # All done.
+ dg-finish
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.target/sh/torture/pr55212-c311.C gcc-16-20251221/gcc/testsuite/g++.target/sh/torture/pr55212-c311.C
*** gcc-16-20251214/gcc/testsuite/g++.target/sh/torture/pr55212-c311.C	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/g++.target/sh/torture/pr55212-c311.C	Sun Dec 21 22:32:09 2025
***************
*** 0 ****
--- 1,73 ----
+ /* { dg-additional-options "-mlra -fpic" }  */
+ /* { dg-do compile }  */
+ 
+ 
+ typedef signed int int32_t;
+ typedef signed long long int int64_t;
+ static constexpr int32_t SK_MaxS32 = 214748364;;
+ static constexpr int32_t SK_MinS32 = -SK_MaxS32;
+ 
+ extern double fabs (double __x) noexcept (true) __attribute__ ((__const__));
+ 
+ namespace std __attribute__ ((__visibility__ ("default")))
+ {
+ using ::fabs;
+ 
+ template<typename _Tp> [[__nodiscard__]] constexpr inline const _Tp& min(const _Tp& __a, const _Tp& __b)
+ {
+    if (__b < __a) return __b;
+    return __a;
+ }
+ 
+ template<typename _Tp> [[__nodiscard__]] constexpr inline const _Tp& max(const _Tp& __a, const _Tp& __b)
+ {
+   return __a;
+ }
+ 
+ }
+ 
+ 
+ static constexpr int32_t Sk64_pin_to_s32(int64_t x)
+ {
+   return x < SK_MinS32 ? SK_MinS32 : (x > SK_MaxS32 ? SK_MaxS32 : (int32_t)x);
+ }
+ 
+ static constexpr int32_t Sk32_sat_sub(int32_t a, int32_t b)
+ {
+   return Sk64_pin_to_s32((int64_t)a - (int64_t)b);
+ };
+ 
+ struct SkPoint
+ {
+   float fX;
+   float fY;
+ };
+ 
+ typedef float SkScalar;
+ static inline bool SkScalarNearlyEqual(SkScalar x, SkScalar y, SkScalar tolerance = (1.0f / (1 << 12)))
+ {
+   return std::fabs(x-y) <= tolerance;
+ }
+ 
+ class SkCubicMap
+ {
+ public:
+   SkCubicMap(SkPoint p1, SkPoint p2);
+ private:
+   enum Type
+   {
+     kLine_Type, kCubeRoot_Type, kSolver_Type,
+   };
+ 
+   Type fType;
+ };
+ 
+ SkCubicMap::SkCubicMap(SkPoint p1, SkPoint p2)
+ {
+   p1.fX = std::min(std::max(p1.fX, 0.0f), 1.0f);
+   p2.fX = std::min(std::max(p2.fX, 0.0f), 1.0f);
+   if (SkScalarNearlyEqual(p1.fX, p1.fY) && SkScalarNearlyEqual(p2.fX, p2.fY))
+   {
+     fType = kLine_Type;
+   }
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.target/sh/torture/pr55212-c333.C gcc-16-20251221/gcc/testsuite/g++.target/sh/torture/pr55212-c333.C
*** gcc-16-20251214/gcc/testsuite/g++.target/sh/torture/pr55212-c333.C	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/g++.target/sh/torture/pr55212-c333.C	Sun Dec 21 22:32:09 2025
***************
*** 0 ****
--- 1,259 ----
+ /* { dg-additional-options "-std=c++20 -mlra -fpic -w " }  */
+ /* { dg-do compile }  */
+ 
+ typedef unsigned int size_t;
+ 
+ extern "C++"
+ {
+ 
+ namespace std __attribute__ ((__visibility__ ("default")))
+ {
+ 
+ template<typename _Tp, _Tp __v> struct integral_constant
+ {
+   static constexpr _Tp value = __v;
+   using value_type = _Tp;
+   constexpr operator value_type() const noexcept { return value; }
+ 
+   constexpr value_type operator()() const noexcept { }
+  };
+ 
+ template<bool __v> using __bool_constant = integral_constant<bool, __v>;
+ using true_type = __bool_constant<true>;
+ using false_type = __bool_constant<false>;
+ 
+ template<bool, typename _Tp = void> struct enable_if { };
+ 
+ template<typename _Tp> struct enable_if<true, _Tp> {  using type = _Tp; };
+ 
+ template<bool _Cond, typename _Tp = void> using __enable_if_t = typename enable_if<_Cond, _Tp>::type;
+ template<bool> struct __conditional {  template<typename _Tp, typename> using type = _Tp;  };
+ template<bool _Cond, typename _If, typename _Else> using __conditional_t = typename __conditional<_Cond>::template type<_If, _Else>;
+ template <typename _Type> struct __type_identity {  };
+ 
+ namespace __detail
+ {
+ template<typename _Tp, typename...> using __first_t = _Tp;
+ template<typename... _Bn> auto __and_fn(int) -> __first_t<true_type, __enable_if_t<bool(_Bn::value)>...>;
+ }
+ 
+ template<typename... _Bn> struct __and_ : decltype(__detail::__and_fn<_Bn...>(0)) { };
+ template<typename _Pp> struct __not_ : __bool_constant<!bool(_Pp::value)> { };
+ 
+ template <typename _Tp, size_t = sizeof(_Tp)> constexpr true_type __is_complete_or_unbounded(__type_identity<_Tp>) {  return { }; }
+ template<typename _Tp> struct is_pointer : public __bool_constant<__is_pointer(_Tp)> { };
+ template<typename _Tp> struct is_empty : public __bool_constant<__is_empty(_Tp)> { };
+ template<typename _Tp, typename... _Args> using __is_constructible_impl = __bool_constant<__is_constructible(_Tp, _Args...)>;
+ 
+ template<typename _Tp> struct is_default_constructible : public __is_constructible_impl<_Tp> {  };
+ template<typename _Tp> using __add_lval_ref_t = __add_lvalue_reference(_Tp);
+ template<typename _Tp> using __add_rval_ref_t = __add_rvalue_reference(_Tp);
+ template<typename _Tp> struct is_move_constructible : public __is_constructible_impl<_Tp, __add_rval_ref_t<_Tp>>
+ {
+  static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{ }
+ ), "template argument must be a complete class or an unbounded array");
+ };
+ 
+ template<typename _Tp, typename _Up> using __is_assignable_impl = __bool_constant<__is_assignable(_Tp, _Up)>;
+ template<typename _Tp> struct is_move_assignable : public __is_assignable_impl<__add_lval_ref_t<_Tp>, __add_rval_ref_t<_Tp>>
+ {
+   static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp> {}
+ ), "template argument must be a complete class or an unbounded array");
+ 
+ };
+ 
+ template<size_t __i, typename _Tp> struct tuple_element;
+ template<size_t __i, typename _Tp> using __tuple_element_t = typename tuple_element<__i, _Tp>::type;
+ template<size_t _Np, typename... _Types> struct _Nth_type
+ {
+   using type = __type_pack_element<_Np, _Types...>;
+ };
+ 
+ template<typename...> class tuple;
+ template<size_t __i, typename... _Elements> constexpr const __tuple_element_t<__i, tuple<_Elements...>>& get(const tuple<_Elements...>& __t) noexcept;
+ }
+ }
+ 
+ inline constexpr float SK_FloatSqrt2 = 1.41421356f;
+ 
+ struct SkPoint
+ {
+   float fY;
+ };
+ 
+ extern void sk_free(void*);
+ enum
+ {
+  SK_MALLOC_ZERO_INITIALIZE = 1 << 0, SK_MALLOC_THROW = 1 << 1,
+ };
+ 
+ extern void* sk_malloc_flags(size_t size, unsigned flags);
+ 
+ static inline void* sk_calloc_throw(size_t size)
+ {
+   return sk_malloc_flags(size, SK_MALLOC_THROW | SK_MALLOC_ZERO_INITIALIZE);
+ }
+ 
+ typedef struct
+ {
+    union
+    {
+    } __value;
+ 
+ } __mbstate_t;
+ 
+ namespace std __attribute__ ((__visibility__ ("default")))
+ {
+ template<typename _Tp> struct __is_empty_non_tuple : is_empty<_Tp> { };
+ 
+ template<typename _Tp> using __empty_not_final = __conditional_t<__is_final(_Tp), false_type, __is_empty_non_tuple<_Tp>>;
+ template<size_t _Idx, typename _Head, bool = __empty_not_final<_Head>::value> struct _Head_base;
+ template<size_t _Idx, typename _Head> struct _Head_base<_Idx, _Head, false> { };
+ template<size_t _Idx, typename... _Elements> struct _Tuple_impl;
+ template<size_t _Idx, typename _Head, typename... _Tail> struct _Tuple_impl<_Idx, _Head, _Tail...> : public _Tuple_impl<_Idx + 1, _Tail...>, private _Head_base<_Idx, _Head> { };
+ template<size_t _Idx, typename _Head> struct _Tuple_impl<_Idx, _Head> : private _Head_base<_Idx, _Head> { };
+ template<typename... _Elements> class tuple : public _Tuple_impl<0, _Elements...> { };
+ template<size_t __i, typename... _Types> struct tuple_element<__i, tuple<_Types...>>
+ {
+   using type = typename _Nth_type<__i, _Types...>::type;
+ };
+ 
+ template<typename _Tp> struct default_delete
+ {
+ };
+ 
+ template <typename _Tp, typename _Dp> class __uniq_ptr_impl
+ {
+   template <typename _Up, typename _Ep, typename = void> struct _Ptr {  using type = _Up*;  };
+ 
+ public:
+    using _DeleterConstraint = enable_if< __and_<__not_<is_pointer<_Dp>>, is_default_constructible<_Dp>>::value>;
+    using pointer = typename _Ptr<_Tp, _Dp>::type;
+    constexpr __uniq_ptr_impl(pointer __p) : _M_t() { }
+    constexpr pointer _M_ptr() const noexcept { return std::get<0>(_M_t); }
+ private:
+   tuple<pointer, _Dp> _M_t;
+ };
+ 
+ template <typename _Tp, typename _Dp, bool = is_move_constructible<_Dp>::value, bool = is_move_assignable<_Dp>::value> struct __uniq_ptr_data : __uniq_ptr_impl<_Tp, _Dp>{ };
+ 
+ template <typename _Tp, typename _Dp = default_delete<_Tp>> class unique_ptr
+ {
+   template <typename _Up> using _DeleterConstraint = typename __uniq_ptr_impl<_Tp, _Up>::_DeleterConstraint::type;
+   __uniq_ptr_data<_Tp, _Dp> _M_t;
+ public:
+   using pointer = typename __uniq_ptr_impl<_Tp, _Dp>::pointer;
+   template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>> constexpr explicit unique_ptr(pointer __p) noexcept : _M_t(__p) { }
+ 
+    constexpr pointer get() const noexcept { return _M_t._M_ptr(); }
+ };
+ 
+ }
+ 
+ template <typename T, T* P> struct SkOverloadedFunctionObject
+ {
+ };
+ 
+ namespace skia_private
+ {
+   using UniqueVoidPtr = std::unique_ptr<void, SkOverloadedFunctionObject<void(void*), sk_free>>;
+ }
+ 
+ class SkNoncopyable
+ {
+ };
+ 
+ template <size_t kSizeRequested> class SkAutoSMalloc : SkNoncopyable
+ {
+   public: SkAutoSMalloc() { }
+ 
+   explicit SkAutoSMalloc(size_t size) { }
+ 
+   void* get() const { return fPtr; }
+ 
+   void* fPtr;
+ };
+ 
+          class SkPointPriv {
+        public: enum Side {
+     kLeft_Side = -1, kOn_Side = 0, kRight_Side = 1, };
+        static bool SetLengthFast(SkPoint* pt, float length);
+        };
+          using namespace skia_private;
+          struct DFData {
+        float fAlpha;
+        SkPoint fDistVector;
+        };
+          enum NeighborFlags {
+        kLeft_NeighborFlag = 0x01, kRight_NeighborFlag = 0x02, kTopLeft_NeighborFlag = 0x04, kTop_NeighborFlag = 0x08, kTopRight_NeighborFlag = 0x10, kBottomLeft_NeighborFlag = 0x20, kBottom_NeighborFlag = 0x40, kBottomRight_NeighborFlag = 0x80, kAll_NeighborFlags = 0xff, kNeighborFlagCount = 8 };
+          static void init_glyph_data(DFData* data, unsigned char* edges, const unsigned char* image, int dataWidth, int dataHeight, int imageWidth, int imageHeight, int pad) {
+        for (int j = 0;
+        j < imageHeight;
+        ++j) {
+     for (int i = 0;
+     i < imageWidth;
+     ++i) {
+  if (255 == *image) {
+  }
+  }
+     }
+        }
+ 
+ static void init_distances(DFData* data, unsigned char* edges, int width, int height)
+ {
+   DFData* currData = data;
+   DFData* prevData = data - width;
+   DFData* nextData = data + width;
+   for (int j = 0; j < height; ++j)
+   {
+     for (int i = 0;i < width;++i)
+     {
+       if (*edges)
+       {
+         SkPoint currGrad;
+         currGrad.fY = (nextData-1)->fAlpha - (prevData-1)->fAlpha + SK_FloatSqrt2*nextData->fAlpha - SK_FloatSqrt2*prevData->fAlpha + (nextData+1)->fAlpha - (prevData+1)->fAlpha;
+         SkPointPriv::SetLengthFast(&currGrad, 1.0f);
+         currData->fDistVector.fY = 1000.f;
+       }
+      ++currData;
+      ++prevData;
+      ++nextData;
+     }
+   }
+ }
+ 
+ static void B1(DFData* curr, int width)
+ {
+ }
+ 
+ static bool generate_distance_field_from_image(unsigned char* distanceField, const unsigned char* copyPtr, int width, int height)
+ {
+   int pad = 4 + 1;
+   int dataWidth = width + 2*pad;
+   int dataHeight = height + 2*pad;
+   UniqueVoidPtr storage(sk_calloc_throw(dataWidth*dataHeight*(sizeof(DFData) + 1)));
+   DFData* dataPtr = (DFData*)storage.get();
+   unsigned char* edgePtr = (unsigned char*)storage.get() + dataWidth*dataHeight*sizeof(DFData);
+   init_distances(dataPtr, edgePtr, dataWidth, dataHeight);
+   unsigned char* currEdge = edgePtr+dataWidth+1;
+   for (int j = 1; j < dataHeight-1; ++j)
+   {
+     for (int i = 1; i < dataWidth-1; ++i)
+     {
+       if (!*currEdge)
+       {
+       }
+     }
+   }
+ 
+   // return true;
+   // ICE triggered only without return statement
+ }
+ 
+ 
+ bool SkGenerateDistanceFieldFromA8Image(unsigned char* distanceField, const unsigned char* image, int width, int height, size_t rowBytes)
+ {
+   SkAutoSMalloc<1024> copyStorage((width+2)*(height+2)*sizeof(char));
+   unsigned char* copyPtr = (unsigned char*) copyStorage.get();
+   return generate_distance_field_from_image(distanceField, copyPtr, width, height);
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.target/sh/torture/pr55212-c373.C gcc-16-20251221/gcc/testsuite/g++.target/sh/torture/pr55212-c373.C
*** gcc-16-20251214/gcc/testsuite/g++.target/sh/torture/pr55212-c373.C	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/g++.target/sh/torture/pr55212-c373.C	Sun Dec 21 22:32:09 2025
***************
*** 0 ****
--- 1,612 ----
+ /* { dg-additional-options "-std=c++20 -mlra -fpic -w " }  */
+ /* { dg-do compile }  */
+ 
+       namespace std {
+      typedef unsigned int size_t;
+      }
+        namespace std {
+      __attribute__((__always_inline__)) constexpr inline bool __is_constant_evaluated() noexcept {
+    return __builtin_is_constant_evaluated();
+    }
+      }
+       typedef unsigned int size_t;
+        extern "C" {
+      typedef struct {
+    }
+      lldiv_t;
+      extern "C" {
+    typedef unsigned char __uint8_t;
+    typedef unsigned int __uint32_t;
+    typedef union {
+  struct {
+  }
+  __value32;
+  }
+    __atomic_wide_counter;
+    }
+      }
+       extern "C++" {
+      namespace std __attribute__ ((__visibility__ ("default"))) {
+    }
+      }
+        extern "C++" {
+      namespace std __attribute__ ((__visibility__ ("default"))) {
+    template<typename _Tp, _Tp __v> struct integral_constant {
+  static constexpr _Tp value = __v;
+  using value_type = _Tp;
+  constexpr operator value_type() const noexcept {
+  }
+  };
+    template<bool __v> using __bool_constant = integral_constant<bool, __v>;
+    using true_type = __bool_constant<true>;
+    using false_type = __bool_constant<false>;
+    template<bool, typename _Tp = void> struct enable_if {
+  };
+    template<typename _Tp> struct enable_if<true, _Tp> {
+  using type = _Tp;
+  };
+    template<bool> struct __conditional {
+  };
+    template<bool _Cond, typename _If, typename _Else> using __conditional_t = typename __conditional<_Cond>::template type<_If, _Else>;
+    template <typename _Type> struct __type_identity {
+  };
+    namespace __detail {
+  template<typename... _Bn> auto __and_fn(...) -> false_type;
+  }
+    template<typename... _Bn> struct __and_ : decltype(__detail::__and_fn<_Bn...>(0)) {
+  };
+    template<typename> struct remove_cv;
+    template <typename _Tp, size_t = sizeof(_Tp)> constexpr true_type __is_complete_or_unbounded(__type_identity<_Tp>) {
+  return {
+ };
+  }
+    template<typename _Tp> struct is_void : public false_type {
+  };
+    template<typename _Tp> struct is_member_object_pointer : public __bool_constant<__is_member_object_pointer(_Tp)> {
+  };
+    template<typename _Tp> struct is_member_function_pointer : public __bool_constant<__is_member_function_pointer(_Tp)> {
+  };
+    template<typename _Tp> struct is_empty : public __bool_constant<__is_empty(_Tp)> {
+  };
+    template<typename _Tp> _Tp __declval(long);
+    template<typename _Tp> auto declval() noexcept -> decltype(__declval<_Tp>(0));
+    template<typename _Tp, typename... _Args> using __is_constructible_impl = __bool_constant<__is_constructible(_Tp, _Args...)>;
+    template<typename _Tp> using __add_lval_ref_t = __add_lvalue_reference(_Tp);
+    template<typename _Tp> struct is_copy_constructible : public __is_constructible_impl<_Tp, __add_lval_ref_t<const _Tp>> {
+  static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{
+ }
+ ), "template argument must be a complete class or an unbounded array");
+  };
+    template<typename _Tp> using __add_rval_ref_t = __add_rvalue_reference(_Tp);
+    template<typename _Tp> struct is_move_constructible : public __is_constructible_impl<_Tp, __add_rval_ref_t<_Tp>> {
+  static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{
+ }
+ ), "template argument must be a complete class or an unbounded array");
+  };
+    template<typename _Tp, typename _Up> using __is_assignable_impl = __bool_constant<__is_assignable(_Tp, _Up)>;
+    template<typename _Tp> struct is_copy_assignable : public __is_assignable_impl<__add_lval_ref_t<_Tp>, __add_lval_ref_t<const _Tp>> {
+  static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{
+ }
+ ), "template argument must be a complete class or an unbounded array");
+  };
+    template<typename _Tp, typename _Up> struct is_same : public __bool_constant<__is_same(_Tp, _Up)> {
+  };
+    template<typename _Tp> struct remove_const {
+  };
+    template<typename _Tp> struct add_const {
+  };
+    template<typename _Tp> struct remove_reference {
+  };
+    template<typename _Tp> using remove_reference_t = typename remove_reference<_Tp>::type;
+    template<typename _Tp> struct add_pointer {
+  };
+    template<typename _Tp> using __remove_cvref_t = typename remove_cv<typename remove_reference<_Tp>::type>::type;
+    template<bool _Cond, typename _Iftrue, typename _Iffalse> struct conditional {
+  };
+    struct __failure_type {
+  };
+    struct __invoke_memfun_ref {
+  };
+    struct __invoke_other {
+  };
+    template<typename _Tp, typename _Up = __remove_cvref_t<_Tp>> struct __inv_unwrap {
+  };
+    template<bool, bool, typename _Functor, typename... _ArgTypes> struct __result_of_impl {
+  };
+    template<typename _Functor, typename... _ArgTypes> struct __invoke_result : public __result_of_impl< is_member_object_pointer< typename remove_reference<_Functor>::type >::value, is_member_function_pointer< typename remove_reference<_Functor>::type >::value, _Functor, _ArgTypes... >::type {
+  };
+    template<typename _Result, typename _Ret, bool = is_void<_Ret>::value, typename = void> struct __is_invocable_impl : false_type {
+  };
+    template<typename _Fn, typename _Tp, typename... _Args> constexpr bool __call_is_nt(__invoke_memfun_ref) {
+  using _Up = typename __inv_unwrap<_Tp>::type;
+  return noexcept((std::declval<_Up>().*std::declval<_Fn>())( std::declval<_Args>()...));
+  }
+    template<typename _Result, typename _Fn, typename... _Args> struct __call_is_nothrow : __bool_constant< std::__call_is_nt<_Fn, _Args...>(typename _Result::__invoke_type{
+ }
+   ) > {
+  };
+    template<typename _Ret, typename _Fn, typename... _ArgTypes> struct is_invocable_r : __is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, _Ret>::type {
+  static_assert(std::__is_complete_or_unbounded(__type_identity<_Fn>{
+ }
+ ), "_Fn must be a complete class or an unbounded array");
+  static_assert((std::__is_complete_or_unbounded( __type_identity<_ArgTypes>{
+ }
+ ) && ...), "each argument type must be a complete class or an unbounded array");
+  static_assert(std::__is_complete_or_unbounded(__type_identity<_Ret>{
+ }
+ ), "_Ret must be a complete class or an unbounded array");
+  };
+    template <typename _Tp> inline constexpr bool is_lvalue_reference_v = false;
+    template <typename _Tp> inline constexpr bool is_enum_v = __is_enum(_Tp);
+    template <typename _Tp> inline constexpr bool is_union_v = __is_union(_Tp);
+    template <typename _Tp> inline constexpr bool is_class_v = __is_class(_Tp);
+    template <typename _Tp> inline constexpr bool is_trivial_v = __is_trivial(_Tp);
+    template <typename _Tp> inline constexpr bool is_standard_layout_v = __is_standard_layout(_Tp);
+    template <typename _Tp, typename... _Args> inline constexpr bool is_constructible_v = __is_constructible(_Tp, _Args...);
+    template <typename _Tp, typename _Up> inline constexpr bool is_same_v = __is_same(_Tp, _Up);
+    template <typename _Base, typename _Derived> inline constexpr bool is_base_of_v = __is_base_of(_Base, _Derived);
+    template <typename _From, typename _To> inline constexpr bool is_convertible_v = __is_convertible(_From, _To);
+    template<typename... _Tp> struct common_reference;
+    template<typename... _Tp> using common_reference_t = typename common_reference<_Tp...>::type;
+    }
+      }
+        namespace std __attribute__ ((__visibility__ ("default"))) {
+      template<typename _Tp> inline constexpr _Tp* __addressof(_Tp& __r) noexcept {
+    }
+      template<typename _Tp> [[__nodiscard__]] constexpr typename std::remove_reference<_Tp>::type&& move(_Tp&& __t) noexcept {
+    }
+      namespace __detail {
+    template<typename _Tp, typename _Up> concept __same_as = std::is_same_v<_Tp, _Up>;
+    }
+      template<typename _Tp, typename _Up> concept same_as = __detail::__same_as<_Tp, _Up> && __detail::__same_as<_Up, _Tp>;
+      template<typename _From, typename _To> concept convertible_to = is_convertible_v<_From, _To> && requires {
+    static_cast<_To>(std::declval<_From>());
+    };
+      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>>;
+      namespace __detail {
+    template<typename _Tp> using __cref = const remove_reference_t<_Tp>&;
+    template<typename _Tp> concept __class_or_enum = is_class_v<_Tp> || is_union_v<_Tp> || is_enum_v<_Tp>;
+    template<typename _Tp> constexpr bool __destructible_impl = false;
+    template<typename _Tp> requires requires(_Tp& __t) {
+  {
+  __t.~_Tp() }
+  noexcept;
+  }
+    constexpr bool __destructible_impl<_Tp> = true;
+    template<typename _Tp> constexpr bool __destructible = __destructible_impl<_Tp>;
+    }
+      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>;
+    };
+      template<typename _Tp> concept destructible = __detail::__destructible<_Tp>;
+      template<typename _Tp, typename... _Args> concept constructible_from = destructible<_Tp> && is_constructible_v<_Tp, _Args...>;
+      template<typename _Tp> concept default_initializable = constructible_from<_Tp> && requires {
+    (void) ::new _Tp;
+    };
+      template<typename _Tp> concept move_constructible = constructible_from<_Tp, _Tp> && convertible_to<_Tp, _Tp>;
+      namespace ranges {
+    namespace __swap {
+  template<typename _Tp, typename _Up> concept __adl_swap = (std::__detail::__class_or_enum<remove_reference_t<_Tp>> || std::__detail::__class_or_enum<remove_reference_t<_Up>>) && requires(_Tp&& __t, _Up&& __u) {
+  swap(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u));
+  };
+  struct _Swap {
+  private: template<typename _Tp, typename _Up> static constexpr bool _S_noexcept() {
+  if constexpr (__adl_swap<_Tp, _Up>) return noexcept(swap(std::declval<_Tp>(), std::declval<_Up>()));
+  }
+  public: template<typename _Tp, typename _Up> requires __adl_swap<_Tp, _Up> || (same_as<_Tp, _Up> && is_lvalue_reference_v<_Tp> && move_constructible<remove_reference_t<_Tp>> && assignable_from<_Tp, remove_reference_t<_Tp>>) constexpr void operator()(_Tp&& __t, _Up&& __u) const noexcept(_S_noexcept<_Tp, _Up>()) {
+  if constexpr (__adl_swap<_Tp, _Up>) swap(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u));
+  else {
+  }
+  }
+  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]);
+  }
+  };
+  }
+    inline namespace _Cpo {
+  inline constexpr __swap::_Swap swap{
+ };
+  }
+    }
+      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));
+    };
+      namespace __detail {
+    template<typename _Tp> concept __boolean_testable_impl = convertible_to<_Tp, bool>;
+    template<typename _Tp> concept __boolean_testable = __boolean_testable_impl<_Tp> && requires(_Tp&& __t) {
+  {
+  !static_cast<_Tp&&>(__t) }
+  -> __boolean_testable_impl;
+  };
+    template<typename _Tp, typename _Up> concept __weakly_eq_cmp_with = requires(__detail::__cref<_Tp> __t, __detail::__cref<_Up> __u) {
+  {
+  __t == __u }
+  -> __boolean_testable;
+  {
+  __u == __t }
+  -> __boolean_testable;
+  {
+  __u != __t }
+  -> __boolean_testable;
+  };
+    }
+      namespace __detail {
+    template<typename _Tp, typename _Up> concept __partially_ordered_with = requires(const remove_reference_t<_Tp>& __t, const remove_reference_t<_Up>& __u) {
+  {
+  __t < __u }
+  -> __boolean_testable;
+  {
+  __t <= __u }
+  -> __boolean_testable;
+  {
+  __t >= __u }
+  -> __boolean_testable;
+  {
+  __u < __t }
+  -> __boolean_testable;
+  };
+    }
+      template<typename _Tp> struct __get_first_arg {
+    };
+      template<typename _Ptr, typename = void> struct __ptr_traits_elem : __get_first_arg<_Ptr> {
+    };
+      template<typename _Ptr> requires requires {
+    typename _Ptr::element_type;
+    }
+      struct __ptr_traits_elem<_Ptr, void> {
+    };
+      template<typename _Ptr, typename _Elt, bool = is_void<_Elt>::value> struct __ptr_traits_ptr_to {
+    using pointer = _Ptr;
+    using element_type = _Elt;
+    static pointer pointer_to(element_type& __r) requires requires {
+  {
+  pointer::pointer_to(__r) }
+  -> convertible_to<pointer>;
+  }
+    {
+  }
+    };
+      namespace __detail {
+    template<typename _Tp> using __with_ref = _Tp&;
+    template<typename _Tp> concept __can_reference = requires {
+  typename __with_ref<_Tp>;
+  };
+    template<typename _Tp> concept __dereferenceable = requires(_Tp& __t) {
+  {
+  *__t }
+  -> __can_reference;
+  };
+    }
+      namespace ranges {
+    namespace __imove {
+  template<typename _Tp> concept __adl_imove = (std::__detail::__class_or_enum<remove_reference_t<_Tp>>) && requires(_Tp&& __t) {
+  iter_move(static_cast<_Tp&&>(__t));
+  };
+  struct _IterMove {
+  private: template<typename _Tp> struct __result {
+  };
+  template<typename _Tp> static constexpr bool _S_noexcept() {
+  if constexpr (__adl_imove<_Tp>) return noexcept(iter_move(std::declval<_Tp>()));
+  }
+  public: template<std::__detail::__dereferenceable _Tp> using __type = typename __result<_Tp>::type;
+  template<std::__detail::__dereferenceable _Tp> [[nodiscard]] constexpr __type<_Tp> operator()(_Tp&& __e) const noexcept(_S_noexcept<_Tp>()) {
+  }
+  };
+  }
+    }
+      template<typename> struct incrementable_traits {
+    };
+      namespace __detail {
+    }
+      template<size_t __i, typename _Tp> struct tuple_element;
+      template<size_t __i, typename _Tp> using __tuple_element_t = typename tuple_element<__i, _Tp>::type;
+      template<typename _Tp, typename... _Types> constexpr size_t __find_uniq_type_in_pack() {
+    constexpr size_t __sz = sizeof...(_Types);
+    constexpr bool __found[__sz] = {
+  __is_same(_Tp, _Types) ... };
+    size_t __n = __sz;
+    for (size_t __i = 0;
+    __i < __sz;
+    ++__i) {
+  if (__found[__i]) {
+  if (__n < __sz) return __sz;
+  }
+  }
+    };
+      template<typename _Tp, _Tp... _Idx> struct integer_sequence {
+    };
+      template<typename _Tp, _Tp _Num> using make_integer_sequence = integer_sequence<_Tp, __integer_pack(_Num)...>;
+      template<size_t... _Idx> using index_sequence = integer_sequence<size_t, _Idx...>;
+      template<size_t _Num> using make_index_sequence = make_integer_sequence<size_t, _Num>;
+      template<typename... _Types> using index_sequence_for = make_index_sequence<sizeof...(_Types)>;
+      template<typename _Tp> struct in_place_type_t {
+    };
+      template<typename...> class tuple;
+      template<typename _U1, typename _U2> class __pair_base {
+    };
+      namespace __detail {
+    template<typename _Iterator> struct __move_iter_cat {
+  };
+    }
+      template<typename _Iterator> class move_iterator : public __detail::__move_iter_cat<_Iterator> {
+    };
+      template<typename _IteratorL, typename _IteratorR> [[__nodiscard__]] inline constexpr bool operator<(const move_iterator<_IteratorL>& __x, const move_iterator<_IteratorR>& __y) requires requires {
+    {
+  __x.base() < __y.base() }
+    -> convertible_to<bool>;
+    }
+      {
+    return !(__x < __y);
+    }
+      namespace __ops {
+    template<typename _Compare> struct _Iter_comp_iter {
+  _Compare _M_comp;
+  explicit constexpr _Iter_comp_iter(_Compare __comp) : _M_comp(std::move(__comp)) {
+  }
+  template<typename _Iterator1, typename _Iterator2> constexpr bool operator()(_Iterator1 __it1, _Iterator2 __it2) {
+  return bool(_M_comp(*__it1, *__it2));
+  }
+  };
+    template<typename _Compare> constexpr inline _Iter_comp_iter<_Compare> __iter_comp_iter(_Compare __comp) {
+  }
+    }
+      template<typename _Tp> [[__nodiscard__]] constexpr inline const _Tp& min(const _Tp& __a, const _Tp& __b) {
+    return __a;
+    }
+      template<typename _Tp> [[__nodiscard__]] constexpr inline const _Tp& max(const _Tp& __a, const _Tp& __b) {
+    if (__a < __b) return __b;
+    }
+      template<typename _Iterator, typename _Predicate> constexpr inline _Iterator __find_if(_Iterator __first, _Iterator __last, _Predicate __pred) {
+    }
+      }
+        namespace std __attribute__ ((__visibility__ ("default"))) {
+      struct allocator_arg_t {
+    struct _Sink {
+  void constexpr operator=(const void*) {
+  }
+  }
+    _M_a;
+    };
+      template<typename _Res, typename _Fn, typename... _Args> constexpr _Res __invoke_impl(__invoke_other, _Fn&& __f, _Args&&... __args) {
+    }
+      template<class _E> class initializer_list {
+    typedef size_t size_type;
+    typedef const _E* iterator;
+    private: iterator _M_array;
+    size_type _M_len;
+    };
+      template<typename _Tp> struct __is_empty_non_tuple : is_empty<_Tp> {
+    };
+      template<typename _Tp> using __empty_not_final = __conditional_t<__is_final(_Tp), false_type, __is_empty_non_tuple<_Tp>>;
+      template<size_t _Idx, typename _Head, bool = __empty_not_final<_Head>::value> struct _Head_base;
+      template<size_t _Idx, typename... _Elements> struct _Tuple_impl;
+      template<size_t _Idx, typename _Head, typename... _Tail> struct _Tuple_impl<_Idx, _Head, _Tail...> : public _Tuple_impl<_Idx + 1, _Tail...>, private _Head_base<_Idx, _Head> {
+    };
+      template<size_t __i, typename... _Elements> constexpr __tuple_element_t<__i, tuple<_Elements...>>& get(tuple<_Elements...>& __t) noexcept {
+    }
+      template<typename... _Tps, typename... _Ups> requires (sizeof...(_Tps) == sizeof...(_Ups)) && (requires (const _Tps& __t, const _Ups& __u) {
+    {
+  __t == __u }
+    -> __detail::__boolean_testable;
+    }
+      && ...) constexpr bool operator== [[nodiscard]] (const tuple<_Tps...>& __t, const tuple<_Ups...>& __u) {
+    return [&]<size_t... _Inds>(index_sequence<_Inds...>) {
+  }
+   (index_sequence_for<_Tps...>{
+ }
+   );
+    }
+      }
+        typedef struct {
+      union {
+    }
+      __value;
+      }
+        __mbstate_t;
+        namespace std __attribute__ ((__visibility__ ("default"))) {
+      }
+        static inline int __gthread_yield (void) {
+      }
+       namespace std __attribute__ ((__visibility__ ("default"))) {
+      template <typename _Tp, size_t _Nm> [[nodiscard, __gnu__::__always_inline__]] constexpr _Tp* data(_Tp (&__array)[_Nm]) noexcept {
+    };
+      }
+       typedef __uint8_t uint8_t;
+        typedef __uint32_t uint32_t;
+       namespace std {
+      namespace __detail {
+    inline void __thread_yield() noexcept {
+  }
+    inline void __thread_relax() noexcept {
+  }
+    inline constexpr auto __atomic_spin_count = 16;
+    struct __default_spin_policy {
+  bool operator()() const noexcept {
+  }
+  };
+    template<typename _Pred, typename _Spin = __default_spin_policy> bool __atomic_spin(_Pred& __pred, _Spin __spin = _Spin{
+  }
+   ) noexcept {
+  for (auto __i = 0;
+  __i < __atomic_spin_count;
+  ++__i) {
+  }
+  }
+    }
+      struct __numeric_limits_base {
+    };
+      template<typename _Tp> struct numeric_limits : public __numeric_limits_base {
+    static constexpr bool is_signed = true;
+    static constexpr bool is_integer = true;
+    };
+      template<> struct numeric_limits<unsigned int> {
+    static constexpr bool is_signed = false;
+    static constexpr bool is_integer = true;
+    };
+      }
+        namespace WTF {
+      template <typename T> struct IsSmartPtr {
+    };
+      template <typename ExpectedType, typename ArgType, bool isBaseType = std::is_base_of_v<ExpectedType, ArgType>> struct TypeCastTraits {
+    };
+      template<typename T> class TypeHasRefMemberFunction {
+    };
+      }
+        namespace WTF {
+      }
+        namespace std {
+      namespace experimental {
+    };
+      }
+        namespace std __attribute__ ((__visibility__ ("default"))) {
+      template<typename _Tp, std::size_t _Nm> struct array {
+    };
+      }
+       extern "C" {
+      extern float sqrtf (float __x) noexcept (true);
+      extern float floorf (float __x) noexcept (true) __attribute__ ((__const__));
+      namespace std __attribute__ ((__visibility__ ("default"))) {
+    constexpr bool isnan(float __x) {
+  return __builtin_isnan(__x);
+  }
+    }
+      }
+        constexpr float piFloat = static_cast<float>( 3.14159265358979323846 );
+        template<typename TargetType, typename SourceType> typename std::enable_if<!std::is_same<TargetType, SourceType>::value && std::numeric_limits<SourceType>::is_integer && std::numeric_limits<TargetType>::is_integer && std::numeric_limits<TargetType>::is_signed && !std::numeric_limits<SourceType>::is_signed && sizeof(SourceType) >= sizeof(TargetType), TargetType>::type clampTo(SourceType value) {
+      return static_cast<TargetType>(value);
+      }
+        namespace WTF {
+      constexpr uint32_t roundUpToPowerOfTwo(uint32_t v) {
+    return v;
+    };
+      template<bool isPod, typename T> struct VectorTraitsBase;
+      template<typename T> struct VectorTraits : VectorTraitsBase<std::is_standard_layout_v<T> && std::is_trivial_v<T>, T> {
+    };
+      }
+        namespace WTF {
+      class StringHasher {
+    };
+      enum class DestructionThread : uint8_t {
+    Any, Main, MainRunLoop };
+      }
+        namespace WebCore {
+      class IntSize {
+    public: constexpr IntSize() = default;
+    void setWidth(int width) {
+  m_width = width;
+  }
+    void setHeight(int height) {
+  m_height = height;
+  }
+    private: int m_width {
+  0 };
+    int m_height {
+  0 };
+    };
+      inline IntSize& operator+=(IntSize& a, const IntSize& b) {
+    }
+      }
+        namespace WebCore {
+      class FloatSize {
+    public: constexpr FloatSize() = default;
+    constexpr float width() const {
+  return m_width;
+  }
+    constexpr float height() const {
+  return m_height;
+  }
+    private: float m_width {
+  0 };
+    float m_height {
+  0 };
+    };
+      }
+        namespace WTF {
+      class ThreadSafeRefCountedBase {
+    };
+      template<typename T, DestructionThread destructionThread = DestructionThread::Any> class ThreadSafeRefCountedAndCanMakeThreadSafeWeakPtr {
+    };
+      }
+        using WTF::ThreadSafeRefCountedAndCanMakeThreadSafeWeakPtr;
+        namespace WebCore {
+      class FloatPoint {
+    };
+      inline FloatSize toFloatSize(const FloatPoint& a) {
+    }
+      }
+        namespace WTF {
+      }
+        namespace WebCore {
+      template<typename T, size_t N> struct ColorComponents {
+    template<typename F> constexpr auto map(F&& function) const -> ColorComponents<decltype(function(std::declval<T>())), N>;
+    };
+      template<typename> struct AlphaTraits;
+      inline constexpr ColorComponents<float, 4> resolveColorComponents(const ColorComponents<float, 4>& colorComponents) {
+    return colorComponents.map([] (float component) {
+  return std::isnan(component) ? 0.0f : component;
+  }
+   );
+    };
+      enum class WhitePoint {
+    D50, D65 };
+      template<typename Parent> struct ColorWithAlphaHelper {
+    };
+      template<typename T, typename D, typename ColorType, typename M, typename TF> struct RGBAType : ColorWithAlphaHelper<ColorType> {
+    constexpr RGBAType(T red, T green, T blue, T alpha = AlphaTraits<T>::opaque) : red {
+  red }
+    {
+  }
+    protected: T red;
+    };
+      }
+        namespace WebCore {
+      class RenderingResource : public ThreadSafeRefCountedAndCanMakeThreadSafeWeakPtr<RenderingResource> {
+    };
+      class FilterFunction : public RenderingResource {
+    };
+      class FilterEffect : public FilterFunction {
+    };
+      class AffineTransform {
+    public: constexpr AffineTransform();
+    private: std::array<double, 6> m_transform;
+    };
+      constexpr AffineTransform::AffineTransform() : m_transform {
+    }
+      {
+    }
+      }
+        namespace WTF {
+      }
+        namespace WebCore {
+      class FEGaussianBlur : public FilterEffect {
+    static IntSize calculateUnscaledKernelSize(FloatSize stdDeviation);
+    };
+      }
+        namespace WTF {
+      }
+        namespace WebCore {
+      static inline float gaussianKernelFactor() {
+    return 3 / 4.f * sqrtf(2 * piFloat);
+    }
+      static int clampedToKernelSize(float value) {
+    static constexpr unsigned maxKernelSize = 500;
+    unsigned size = std::max<unsigned>(2, static_cast<unsigned>(floorf(value * gaussianKernelFactor() + 0.5f)));
+    return clampTo<int>(std::min(size, maxKernelSize));
+    }
+      IntSize FEGaussianBlur::calculateUnscaledKernelSize(FloatSize stdDeviation) {
+    IntSize kernelSize;
+    if (stdDeviation.width()) kernelSize.setWidth(clampedToKernelSize(stdDeviation.width()));
+    if (stdDeviation.height()) kernelSize.setHeight(clampedToKernelSize(stdDeviation.height()));
+    return kernelSize;
+    }
+      }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.target/sh/torture/pr55212-c384.C gcc-16-20251221/gcc/testsuite/g++.target/sh/torture/pr55212-c384.C
*** gcc-16-20251214/gcc/testsuite/g++.target/sh/torture/pr55212-c384.C	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/g++.target/sh/torture/pr55212-c384.C	Sun Dec 21 22:32:09 2025
***************
*** 0 ****
--- 1,429 ----
+ /* { dg-additional-options "-std=c++20 -mlra -fpic -w " }  */
+ /* { dg-do compile }  */
+ 
+    typedef unsigned int size_t;
+         extern "C" {
+       typedef signed int __int32_t;
+       typedef struct {
+     }
+       __fpos64_t;
+       }
+         extern "C++" {
+       namespace std __attribute__ ((__visibility__ ("default"))) {
+     template<typename _Tp, _Tp __v> struct integral_constant {
+   using value_type = _Tp;
+   constexpr operator value_type() const noexcept {
+   }
+   };
+     }
+       typedef __int32_t int32_t;
+       typedef struct {
+     }
+       ldiv_t;
+       }
+         extern "C" {
+       typedef unsigned int hashval_t;
+       enum insert_option {
+    NO_INSERT, INSERT};
+       }
+         typedef const union tree_node *const_tree;
+           struct varpool_node;
+         struct cgraph_edge;
+         template<typename T> inline T * ggc_alloc () {
+       }
+         struct vl_embed {
+       };
+         struct vl_ptr {
+       };
+         struct va_heap {
+       typedef vl_ptr default_layout;
+       };
+        struct va_gc {
+       typedef vl_embed default_layout;
+       };
+         template<typename T, typename A = va_heap, typename L = typename A::default_layout> struct vec {
+       };
+         template<typename T, typename A, typename L> T* begin (vec<T,A,L> *v) {
+       }
+         template<typename T, typename A, typename L> T* end (vec<T,A,L> *v) {
+       }
+         struct vnull {
+       };
+         template<typename T, typename A> struct vec<T, A, vl_embed> {
+       bool is_empty (void) const {
+     }
+       T &operator[] (unsigned);
+       };
+         template<typename T, typename A> inline unsigned vec_safe_length (const vec<T, A, vl_embed> *v) {
+       }
+         template<typename T, size_t N = 0> class auto_vec;
+         template<typename T> struct vec<T, va_heap, vl_ptr> {
+       public: vec () = default;
+       vec (vnull): m_vec () {
+     }
+       T &operator[] (unsigned ix) {
+     return (*m_vec)[ix];
+     }
+       vec<T, va_heap, vl_embed> *m_vec;
+       };
+         template<typename T, size_t N > class auto_vec : public vec<T, va_heap> {
+       public: auto_vec () {
+     }
+       auto_vec (size_t s ) {
+     }
+       };
+         enum mem_alloc_origin {
+       HASH_TABLE_ORIGIN, HASH_MAP_ORIGIN, HASH_SET_ORIGIN, VEC_ORIGIN, BITMAP_ORIGIN, GGC_ORIGIN, ALLOC_POOL_ORIGIN, MEM_ALLOC_ORIGIN_LENGTH };
+         template <typename Type> struct typed_noop_remove {
+       };
+         template <typename Type> struct int_hash_base : typed_noop_remove <Type> {
+       typedef Type value_type;
+       };
+         template <typename Type, Type Empty, Type Deleted = Empty> struct int_hash : int_hash_base <Type> {
+      };
+         template <typename T> struct default_hash_traits : T {
+      };
+         template <typename H, typename Value> struct simple_hashmap_traits {
+       typedef typename H::value_type key_type;
+       static inline hashval_t hash (const key_type &);
+       };
+         template <typename Type> struct xcallocator {
+       };
+         template <typename Descriptor, bool Lazy = false, template<typename Type> class Allocator = xcallocator> class hash_table {
+       typedef typename Descriptor::value_type value_type;
+       typedef typename Descriptor::compare_type compare_type;
+       public: explicit hash_table (size_t, bool ggc = false, bool sanitize_eq_and_hash = true, bool gather_mem_stats = 0, mem_alloc_origin origin = HASH_TABLE_ORIGIN );
+       value_type *find_slot_with_hash (const compare_type &comparable, hashval_t hash, enum insert_option insert);
+       };
+         template<typename Key, typename Value, typename Traits = simple_hashmap_traits<default_hash_traits<Key>, Value> > class hash_map;
+         class mem_location {
+       };
+         const size_t default_hash_map_size = 13;
+         template<typename KeyId, typename Value, typename Traits > class hash_map {
+       typedef typename Traits::key_type Key;
+       struct hash_entry {
+     Value m_value;
+     typedef hash_entry value_type;
+     typedef Key compare_type;
+     };
+       public: explicit hash_map (size_t n = default_hash_map_size, bool ggc = false, bool sanitize_eq_and_hash = true, bool gather_mem_stats = 0 ) : m_table (n, ggc, sanitize_eq_and_hash, gather_mem_stats, HASH_MAP_ORIGIN ) {
+     }
+       Value &get_or_insert (const Key &k, bool *existed = nullptr) {
+     hash_entry *e = m_table.find_slot_with_hash (k, Traits::hash (k), INSERT);
+     return e->m_value;
+     }
+       hash_table<hash_entry> m_table;
+       };
+         enum optgroup_flag {
+       OPTGROUP_NONE = 0, OPTGROUP_IPA = (1 << 1), OPTGROUP_LOOP = (1 << 2), OPTGROUP_INLINE = (1 << 3), OPTGROUP_OMP = (1 << 4), OPTGROUP_VEC = (1 << 5), OPTGROUP_OTHER = (1 << 6), OPTGROUP_ALL = (OPTGROUP_IPA | OPTGROUP_LOOP | OPTGROUP_INLINE | OPTGROUP_OMP | OPTGROUP_VEC | OPTGROUP_OTHER) };
+         typedef enum optgroup_flag optgroup_flags_t;
+         enum reorder_blocks_algorithm {
+       };
+         enum tree_node_structure_enum {
+       TS_BASE, TS_TYPED, TS_COMMON, TS_INT_CST, TS_POLY_INT_CST, TS_REAL_CST, TS_FIXED_CST, TS_VECTOR, TS_STRING, TS_COMPLEX, TS_IDENTIFIER, TS_DECL_MINIMAL, TS_DECL_COMMON, TS_DECL_WRTL, TS_DECL_NON_COMMON, TS_DECL_WITH_VIS, TS_FIELD_DECL, TS_VAR_DECL, TS_PARM_DECL, TS_LABEL_DECL, TS_RESULT_DECL, TS_CONST_DECL, TS_TYPE_DECL, TS_FUNCTION_DECL, TS_TRANSLATION_UNIT_DECL, TS_TYPE_COMMON, TS_TYPE_WITH_LANG_SPECIFIC, TS_TYPE_NON_COMMON, TS_LIST, TS_VEC, TS_EXP, TS_SSA_NAME, TS_BLOCK, TS_BINFO, TS_STATEMENT_LIST, TS_CONSTRUCTOR, TS_OMP_CLAUSE, TS_OPTIMIZATION, TS_TARGET_OPTION, LAST_TS_ENUM };
+         struct tree_base {
+       union {
+     struct {
+   }
+     bits;
+     }
+       u;
+       };
+         struct tree_typed {
+       };
+         inline const_tree contains_struct_check (const_tree __t, const enum tree_node_structure_enum __s, const char *__f, int __l, const char *__g) {
+       }
+         struct gimple {
+       };
+         typedef enum {
+       TV_NONE, TV_TOTAL, TV_PHASE_SETUP, TV_PHASE_PARSING, TV_PHASE_DEFERRED, TV_PHASE_LATE_PARSING_CLEANUPS, TV_PHASE_OPT_GEN, TV_PHASE_LATE_ASM, TV_PHASE_STREAM_IN, TV_PHASE_STREAM_OUT, TV_PHASE_FINALIZE, TV_NAME_LOOKUP, TV_OVERLOAD, TV_GC, TV_DUMP, TV_PCH_SAVE, TV_PCH_CPP_SAVE, TV_PCH_PTR_REALLOC, TV_PCH_PTR_SORT, TV_PCH_RESTORE, TV_PCH_CPP_RESTORE, TV_CGRAPH, TV_CGRAPHOPT, TV_CGRAPH_FUNC_EXPANSION, TV_CGRAPH_IPA_PASSES, TV_IPA_ODR, TV_IPA_FNSUMMARY, TV_IPA_UNREACHABLE, TV_IPA_INHERITANCE, TV_IPA_VIRTUAL_CALL, TV_IPA_DEVIRT, TV_IPA_CONSTANT_PROP, TV_IPA_INLINING, TV_IPA_FNSPLIT, TV_IPA_COMDATS, TV_IPA_OPT, TV_IPA_LTO_DECOMPRESS, TV_IPA_LTO_COMPRESS, TV_IPA_LTO_OUTPUT, TV_IPA_LTO_GIMPLE_IN, TV_IPA_LTO_GIMPLE_OUT, TV_IPA_LTO_DECL_IN, TV_IPA_LTO_DECL_OUT, TV_IPA_LTO_CTORS_IN, TV_IPA_LTO_CTORS_OUT, TV_IPA_LTO_CGRAPH_IO, TV_IPA_LTO_DECL_MERGE, TV_IPA_LTO_CGRAPH_MERGE, TV_LTO, TV_WHOPR_WPA, TV_WHOPR_WPA_IO, TV_WHOPR_PARTITIONING, TV_WHOPR_LTRANS, TV_IPA_REFERENCE, TV_IPA_PROFILE, TV_IPA_AUTOFDO, TV_IPA_PURE_CONST, TV_IPA_ICF, TV_IPA_PTA, TV_IPA_SRA, TV_IPA_FREE_LANG_DATA, TV_IPA_FREE_INLINE_SUMMARY, TV_IPA_MODREF, TV_CFG, TV_CLEANUP_CFG, TV_CFG_VERIFY, TV_DELETE_TRIVIALLY_DEAD, TV_DF_SCAN, TV_DF_MD, TV_DF_RD, TV_DF_LR, TV_DF_LIVE, TV_DF_MIR, TV_DF_CHAIN, TV_DF_WORD_LR, TV_DF_NOTE, TV_REG_STATS, TV_ALIAS_ANALYSIS, TV_ALIAS_STMT_WALK, TV_REG_SCAN, TV_REBUILD_JUMP, TV_CPP, TV_LEX, TV_PARSE_GLOBAL, TV_PARSE_STRUCT, TV_PARSE_ENUM, TV_PARSE_FUNC, TV_PARSE_INLINE, TV_PARSE_INMETH, TV_TEMPLATE_INST, TV_CONSTEXPR, TV_CONSTRAINT_NORM, TV_CONSTRAINT_SAT, TV_CONSTRAINT_SUB, TV_MODULE_IMPORT, TV_MODULE_EXPORT, TV_MODULE_MAPPER, TV_FLATTEN_INLINING, TV_EARLY_INLINING, TV_INLINE_PARAMETERS, TV_INTEGRATION, TV_TREE_GIMPLIFY, TV_TREE_EH, TV_TREE_CFG, TV_TREE_CLEANUP_CFG, TV_TREE_TAIL_MERGE, TV_TREE_VRP, TV_TREE_VRP_THREADER, TV_TREE_EARLY_VRP, TV_TREE_FAST_VRP, TV_TREE_ARRAY_BOUNDS, TV_TREE_COPY_PROP, TV_FIND_REFERENCED_VARS, TV_TREE_PTA, TV_TREE_SSA_OTHER, TV_TREE_INTO_SSA, TV_TREE_SSA_INCREMENTAL, TV_TREE_OPS, TV_TREE_SSA_DOMINATOR_OPTS, TV_TREE_SSA_THREAD_JUMPS, TV_TREE_SRA, TV_ISOLATE_ERRONEOUS_PATHS, TV_TREE_CCP, TV_TREE_SPLIT_EDGES, TV_TREE_REASSOC, TV_TREE_PRE, TV_TREE_FRE, TV_TREE_RPO_VN, TV_TREE_SINK, TV_TREE_PHIOPT, TV_TREE_BACKPROP, TV_TREE_FORWPROP, TV_TREE_PHIPROP, TV_TREE_DCE, TV_TREE_CD_DCE, TV_TREE_CALL_CDCE, TV_TREE_DSE, TV_TREE_MERGE_PHI, TV_TREE_LOOP, TV_TREE_NOLOOP, TV_TREE_LOOP_BOUNDS, TV_LIM, TV_LINTERCHANGE, TV_TREE_LOOP_IVCANON, TV_SCEV_CONST, TV_TREE_LOOP_UNSWITCH, TV_LOOP_SPLIT, TV_LOOP_JAM, TV_COMPLETE_UNROLL, TV_SCALAR_CLEANUP, TV_TREE_PARALLELIZE_LOOPS, TV_TREE_VECTORIZATION, TV_TREE_SLP_VECTORIZATION, TV_GRAPHITE, TV_GRAPHITE_TRANSFORMS, TV_GRAPHITE_DATA_DEPS, TV_GRAPHITE_CODE_GEN, TV_TREE_LOOP_DISTRIBUTION, TV_CHECK_DATA_DEPS, TV_TREE_PREFETCH, TV_TREE_LOOP_IVOPTS, TV_PREDCOM, TV_TREE_CH, TV_TREE_SSA_UNCPROP, TV_TREE_NRV, TV_TREE_COPY_RENAME, TV_TREE_SSA_VERIFY, TV_TREE_STMT_VERIFY, TV_TREE_SWITCH_CONVERSION, TV_TREE_SWITCH_LOWERING, TV_TREE_RECIP, TV_TREE_SINCOS, TV_TREE_POW, TV_TREE_WIDEN_MUL, TV_TRANS_MEM, TV_TREE_STRLEN, TV_TREE_MODREF, TV_TREE_ASSUMPTIONS, TV_CGRAPH_VERIFY, TV_DOM_FRONTIERS, TV_DOMINANCE, TV_CONTROL_DEPENDENCES, TV_OUT_OF_SSA, TV_VAR_EXPAND, TV_EXPAND, TV_POST_EXPAND, TV_VARCONST, TV_LOWER_SUBREG, TV_JUMP, TV_FWPROP, TV_CSE, TV_DCE, TV_DSE1, TV_DSE2, TV_LOOP, TV_LOOP_INIT, TV_LOOP_VERSIONING, TV_LOOP_MOVE_INVARIANTS, TV_LOOP_UNROLL, TV_LOOP_DOLOOP, TV_LOOP_FINI, TV_CPROP, TV_PRE, TV_HOIST, TV_LSM, TV_TRACER, TV_WEB, TV_AUTO_INC_DEC, TV_CSE2, TV_BRANCH_PROB, TV_COMBINE, TV_IFCVT, TV_MODE_SWITCH, TV_SMS, TV_LIVE_RANGE_SHRINKAGE, TV_SCHED, TV_EARLY_REMAT, TV_IRA, TV_LRA, TV_LRA_ELIMINATE, TV_LRA_INHERITANCE, TV_LRA_CREATE_LIVE_RANGES, TV_LRA_ASSIGN, TV_LRA_COALESCE, TV_LRA_REMAT, TV_RELOAD, TV_RELOAD_CSE_REGS, TV_GCSE_AFTER_RELOAD, TV_REE, TV_THREAD_PROLOGUE_AND_EPILOGUE, TV_IFCVT2, TV_SPLIT_PATHS, TV_COMBINE_STACK_ADJUST, TV_PEEPHOLE2, TV_RENAME_REGISTERS, TV_SCHED_FUSION, TV_CPROP_REGISTERS, TV_SCHED2, TV_MACH_DEP, TV_DBR_SCHED, TV_REORDER_BLOCKS, TV_SHORTEN_BRANCH, TV_REG_STACK, TV_FINAL, TV_VAROUT, TV_SYMOUT, TV_VAR_TRACKING, TV_VAR_TRACKING_DATAFLOW, TV_VAR_TRACKING_EMIT, TV_TREE_IFCOMBINE, TV_TREE_IF_TO_SWITCH, TV_TREE_UNINIT, TV_PLUGIN_INIT, TV_PLUGIN_RUN, TV_GIMPLE_SLSR, TV_GIMPLE_STORE_MERGING, TV_VTABLE_VERIFICATION, TV_TREE_UBSAN, TV_INITIALIZE_RTL, TV_GIMPLE_LADDRESS, TV_TREE_LOOP_IFCVT, TV_WARN_ACCESS, TV_EARLY_LOCAL, TV_OPTIMIZE, TV_REST_OF_COMPILATION, TV_POSTRELOAD, TV_LATE_COMPILATION, TV_REMOVE_UNUSED, TV_ADDRESS_TAKEN, TV_TODO, TV_VERIFY_LOOP_CLOSED, TV_VERIFY_RTL_SHARING, TV_REBUILD_FREQUENCIES, TV_REPAIR_LOOPS, TV_JIT_REPLAY, TV_ASSEMBLE, TV_LINK, TV_LOAD, TV_JIT_ACQUIRING_MUTEX, TV_JIT_CLIENT_CODE, TV_ANALYZER, TV_ANALYZER_SUPERGRAPH, TV_ANALYZER_STATE_PURGE, TV_ANALYZER_PLAN, TV_ANALYZER_SCC, TV_ANALYZER_WORKLIST, TV_ANALYZER_INFINITE_LOOPS, TV_ANALYZER_DUMP, TV_ANALYZER_DIAGNOSTICS, TV_ANALYZER_SHORTEST_PATHS, TIMEVAR_LAST }
+         timevar_id_t;
+         enum opt_pass_type {
+       GIMPLE_PASS, RTL_PASS, SIMPLE_IPA_PASS, IPA_PASS };
+         struct pass_data {
+       enum opt_pass_type type;
+       const char *name;
+       optgroup_flags_t optinfo_flags;
+       timevar_id_t tv_id;
+       unsigned int properties_required;
+       unsigned int properties_provided;
+       unsigned int properties_destroyed;
+       unsigned int todo_flags_start;
+       unsigned int todo_flags_finish;
+       };
+         namespace gcc {
+       class context;
+       }
+         class opt_pass : public pass_data {
+       protected: opt_pass (const pass_data&, gcc::context *);
+       };
+         class ipa_opt_pass_d : public opt_pass {
+       public: void (*generate_summary) (void);
+       void (*write_summary) (void);
+       void (*read_summary) (void);
+       void (*write_optimization_summary) (void);
+       void (*read_optimization_summary) (void);
+       void (*stmt_fixup) (struct cgraph_node *, gimple **);
+       unsigned int function_transform_todo_flags_start;
+       unsigned int (*function_transform) (struct cgraph_node *);
+       void (*variable_transform) (varpool_node *);
+       protected: ipa_opt_pass_d (const pass_data& data, gcc::context *ctxt, void (*generate_summary) (void), void (*write_summary) (void), void (*read_summary) (void), void (*write_optimization_summary) (void), void (*read_optimization_summary) (void), void (*stmt_fixup) (struct cgraph_node *, gimple **), unsigned int function_transform_todo_flags_start, unsigned int (*function_transform) (struct cgraph_node *), void (*variable_transform) (varpool_node *)) : opt_pass (data, ctxt), generate_summary (generate_summary), write_summary (write_summary), read_summary (read_summary), write_optimization_summary (write_optimization_summary), read_optimization_summary (read_optimization_summary), stmt_fixup (stmt_fixup), function_transform_todo_flags_start (function_transform_todo_flags_start), function_transform (function_transform), variable_transform (variable_transform) {
+     }
+       };
+         struct symtab_node {
+       struct lto_file_decl_data * lto_file_data;
+       };
+         struct cgraph_node : public symtab_node {
+       cgraph_edge *callees;
+       cgraph_edge *indirect_calls;
+       };
+         class cgraph_edge {
+       public: friend struct cgraph_node;
+       inline int get_uid () {
+     return m_uid;
+     }
+       cgraph_edge *next_callee;
+       private: int m_uid;
+       };
+         template <class T> class function_summary;
+         class symbol_table {
+       };
+         template <class T> class function_summary_base {
+       };
+         template <class T> class function_summary <T *>: public function_summary_base<T> {
+       T* get (cgraph_node *node) __attribute__ ((__pure__)) {
+     }
+       };
+         template <class T> class call_summary_base {
+       };
+         template <class T> class call_summary {
+       };
+         template <class T> class call_summary <T *>: public call_summary_base<T> {
+       public: call_summary (symbol_table *symtab, bool ggc = false ) : call_summary_base<T> (symtab, call_summary::symtab_removal, call_summary::symtab_duplication ), m_ggc (ggc), m_map (13, ggc, true, 0 ) {
+    }
+       T* get_create (cgraph_edge *edge) {
+     bool existed;
+     T **v = &m_map.get_or_insert (edge->get_uid (), &existed);
+     return *v;
+     }
+       protected: bool m_ggc;
+       typedef int_hash <int, 0, -1> map_hash;
+       hash_map <map_hash, T *> m_map;
+       };
+         enum lto_section_type {
+       LTO_section_decls = 0, LTO_section_function_body, LTO_section_static_initializer, LTO_section_symtab, LTO_section_symtab_extension, LTO_section_refs, LTO_section_asm, LTO_section_jump_functions, LTO_section_ipa_pure_const, LTO_section_ipa_reference, LTO_section_ipa_profile, LTO_section_symtab_nodes, LTO_section_opts, LTO_section_cgraph_opt_sum, LTO_section_ipa_fn_summary, LTO_section_ipcp_transform, LTO_section_ipa_icf, LTO_section_offload_table, LTO_section_mode_table, LTO_section_lto, LTO_section_ipa_sra, LTO_section_odr_types, LTO_section_ipa_modref, LTO_N_SECTION_TYPES };
+         class lto_input_block {
+       public: lto_input_block (const char *data_, unsigned int p_, unsigned int len_, const lto_file_decl_data *file_data_) : data (data_), file_data (file_data_), p (p_), len (len_) {
+    }
+       lto_input_block (const char *data_, unsigned int len_, const lto_file_decl_data *file_data_) : data (data_), file_data (file_data_), p (0), len (len_) {
+    }
+       const char *data;
+       const lto_file_decl_data *file_data;
+       unsigned int p;
+       unsigned int len;
+       };
+         struct lto_simple_header {
+       int32_t main_size;
+       };
+         struct lto_simple_header_with_strings : lto_simple_header {
+       };
+         struct lto_function_header : lto_simple_header_with_strings {
+       int32_t cfg_size;
+       };
+         typedef struct lto_symtab_encoder_d *lto_symtab_encoder_t;
+         struct lto_symtab_encoder_iterator {
+       };
+         struct lto_out_decl_state {
+       lto_symtab_encoder_t symtab_node_encoder;
+       };
+         struct output_block {
+       struct lto_out_decl_state *decl_state;
+       };
+         extern struct lto_file_decl_data **lto_get_file_decl_data (void);
+         extern const char *lto_get_summary_section_data (struct lto_file_decl_data *, enum lto_section_type, size_t *);
+         extern struct output_block *create_output_block (enum lto_section_type);
+         inline bool lsei_end_p (lto_symtab_encoder_iterator lsei) {
+       }
+         inline void lsei_next_function_in_partition (lto_symtab_encoder_iterator *lsei) {
+       }
+         inline lto_symtab_encoder_iterator lsei_start_function_in_partition (lto_symtab_encoder_t encoder) {
+       }
+         static unsigned const BITS_PER_BITPACK_WORD = 64;
+         typedef unsigned long long bitpack_word_t;
+         struct bitpack_d {
+       unsigned pos;
+       bitpack_word_t word;
+       void *stream;
+       };
+         unsigned long long streamer_read_uhwi (class lto_input_block *);
+         inline struct bitpack_d bitpack_create (struct lto_output_stream *s) {
+       }
+         inline struct bitpack_d streamer_read_bitpack (class lto_input_block *ib) {
+       struct bitpack_d bp;
+       return bp;
+       }
+         inline bitpack_word_t bp_unpack_value (struct bitpack_d *bp, unsigned nbits) {
+       bitpack_word_t mask, val;
+       int pos = bp->pos;
+       mask = (nbits == BITS_PER_BITPACK_WORD ? (bitpack_word_t) -1 : ((bitpack_word_t) 1 << nbits) - 1);
+       if (pos + nbits > BITS_PER_BITPACK_WORD) {
+     bp->word = val = streamer_read_uhwi ((class lto_input_block *)bp->stream);
+     bp->pos = nbits;
+     return val & mask;
+     }
+       val = bp->word;
+       val >>= pos;
+       bp->pos = pos + nbits;
+       return val & mask;
+       }
+         class ipcp_transformation;
+         class ipa_argagg_value_list {
+       template<typename pred_function> void remove_argaggs_if (pred_function &&predicate) {
+     }
+       };
+         inline ipcp_transformation * ipcp_get_transformation_summary (cgraph_node *node) {
+       }
+         struct param_access {
+       };
+         struct isra_param_desc {
+       vec <param_access *, va_gc> *accesses;
+       unsigned remove_only_when_retval_removed : 1;
+       };
+         class isra_func_summary {
+       public: isra_func_summary () : m_parameters (nullptr), m_candidate (false), m_returns_value (false), m_return_ignored (false), m_queued (false) {
+    }
+       vec<isra_param_desc, va_gc> *m_parameters;
+       unsigned m_candidate : 1;
+       unsigned m_returns_value : 1;
+       unsigned m_return_ignored : 1;
+       unsigned m_queued : 1;
+       };
+         struct isra_param_flow {
+       char length;
+       unsigned char inputs[7];
+       unsigned aggregate_pass_through : 1;
+       unsigned pointer_pass_through : 1;
+       unsigned safe_to_import_accesses : 1;
+       };
+         class isra_call_summary {
+       public: isra_call_summary () : m_arg_flow (), m_return_ignored (false), m_return_returned (false), m_bit_aligned_arg (false), m_before_any_store (false) {
+    }
+       auto_vec <isra_param_flow> m_arg_flow;
+       unsigned m_return_ignored : 1;
+       unsigned m_return_returned : 1;
+       unsigned m_bit_aligned_arg : 1;
+       unsigned m_before_any_store : 1;
+       };
+         class ipa_sra_function_summaries : public function_summary <isra_func_summary *> {
+       };
+         class ipa_sra_call_summaries: public call_summary <isra_call_summary *> {
+       };
+         static ipa_sra_call_summaries *call_sums;
+         namespace {
+       static void verify_splitting_accesses (cgraph_node *node, bool certain_must_exist) {
+     }
+       static void ipa_sra_generate_summary (void) {
+     }
+       static void isra_write_edge_summary (output_block *ob, cgraph_edge *e) {
+     }
+       static void isra_write_node_summary (output_block *ob, cgraph_node *node) {
+     for (cgraph_edge *e = node->callees;
+     e;
+     e = e->next_callee) isra_write_edge_summary (ob, e);
+     }
+       static void ipa_sra_write_summary (void) {
+     struct output_block *ob = create_output_block (LTO_section_ipa_sra);
+     lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder;
+     lto_symtab_encoder_iterator lsei;
+     for (lsei = lsei_start_function_in_partition (encoder);
+     !lsei_end_p (lsei);
+     lsei_next_function_in_partition (&lsei)) {
+   }
+     }
+       static void isra_read_edge_summary (struct lto_input_block *ib, cgraph_edge *cs) {
+     isra_call_summary *csum = call_sums->get_create (cs);
+     unsigned input_count = streamer_read_uhwi (ib);
+     for (unsigned i = 0;
+     i < input_count;
+     i++) {
+   isra_param_flow *ipf = &csum->m_arg_flow[i];
+   bitpack_d bp = streamer_read_bitpack (ib);
+   for (int j = 0;
+   j < ipf->length;
+   j++) ipf->inputs[j] = bp_unpack_value (&bp, 8);
+   ipf->aggregate_pass_through = bp_unpack_value (&bp, 1);
+   ipf->pointer_pass_through = bp_unpack_value (&bp, 1);
+   ipf->safe_to_import_accesses = bp_unpack_value (&bp, 1);
+   }
+     }
+       static void isra_read_node_info (struct lto_input_block *ib, cgraph_node *node, struct data_in *data_in) {
+     for (cgraph_edge *e = node->indirect_calls;
+     e;
+     e = e->next_callee) isra_read_edge_summary (ib, e);
+     }
+       static void isra_read_summary_section (struct lto_file_decl_data *file_data, const char *data, size_t len) {
+     const struct lto_function_header *header = (const struct lto_function_header *) data;
+     const int cfg_offset = sizeof (struct lto_function_header);
+     const int main_offset = cfg_offset + header->cfg_size;
+     struct data_in *data_in;
+     unsigned int i;
+     unsigned int count;
+     lto_input_block ib_main ((const char *) data + main_offset, header->main_size, file_data);
+     count = streamer_read_uhwi (&ib_main);
+     for (i = 0;
+     i < count;
+     i++) {
+   struct cgraph_node *node;
+   isra_read_node_info (&ib_main, node, data_in);
+   }
+     }
+       static void ipa_sra_read_summary (void) {
+     struct lto_file_decl_data **file_data_vec = lto_get_file_decl_data ();
+     struct lto_file_decl_data *file_data;
+     unsigned int j = 0;
+     while ((file_data = file_data_vec[j++])) {
+   size_t len;
+   const char *data = lto_get_summary_section_data (file_data, LTO_section_ipa_sra, &len);
+   if (data) isra_read_summary_section (file_data, data, len);
+   }
+     }
+       static bool all_callee_accesses_present_p (isra_param_desc *param_desc, isra_param_desc *arg_desc) {
+     unsigned aclen = vec_safe_length (arg_desc->accesses);
+     for (unsigned j = 0;
+     j < aclen;
+     j++) {
+   }
+     }
+       enum acc_prop_kind {
+    ACC_PROP_DONT, ACC_PROP_COPY, ACC_PROP_CERTAIN};
+       static const char * pull_accesses_from_callee (cgraph_node *caller, isra_param_desc *param_desc, isra_param_desc *arg_desc, unsigned delta_offset, unsigned arg_size, bool *change_p) {
+     unsigned aclen = vec_safe_length (arg_desc->accesses);
+     for (unsigned j = 0;
+     j < aclen;
+     j++) {
+   }
+     }
+       static bool adjust_parameter_descriptions (cgraph_node *node, isra_func_summary *ifs) {
+     unsigned len = vec_safe_length (ifs->m_parameters);
+     for (unsigned i = 0;
+     i < len;
+     i++) {
+   isra_param_desc *desc = &(*ifs->m_parameters)[i];
+   if (desc->remove_only_when_retval_removed && !ifs->m_return_ignored) {
+   for (const param_access *pa : desc->accesses) {
+   }
+   }
+   }
+     }
+       const pass_data pass_data_ipa_sra = {
+     IPA_PASS, "sra", OPTGROUP_NONE, TV_IPA_SRA, 0, 0, 0, 0, ( (1 << 7) | (1 << 8) ), };
+       class pass_ipa_sra : public ipa_opt_pass_d {
+     public: pass_ipa_sra (gcc::context *ctxt) : ipa_opt_pass_d (pass_data_ipa_sra, ctxt, ipa_sra_generate_summary, ipa_sra_write_summary, ipa_sra_read_summary, nullptr , nullptr, nullptr, 0, nullptr, nullptr) {
+  }
+     };
+       }
+         ipa_opt_pass_d * make_pass_ipa_sra (gcc::context *ctxt) {
+       return new pass_ipa_sra (ctxt);
+       }
+ 
+ 
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.target/sh/torture/pr55212-c413.C gcc-16-20251221/gcc/testsuite/g++.target/sh/torture/pr55212-c413.C
*** gcc-16-20251214/gcc/testsuite/g++.target/sh/torture/pr55212-c413.C	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/g++.target/sh/torture/pr55212-c413.C	Sun Dec 21 22:32:09 2025
***************
*** 0 ****
--- 1,38 ----
+ /* { dg-additional-options "-std=c++20 -mlra -fpic -w " }  */
+ /* { dg-do compile }  */
+ 
+ struct Trans_NS_WTF_HashMap
+ {
+   template <typename V> void set(int *, V);
+ };
+ 
+ struct AscentAndDescent
+ {
+   float ascent;
+   float descent;
+ };
+ 
+ bool isRubyAnnotationBox();
+ 
+ struct EnclosingAscentDescent
+ {
+   float ascent;
+   float descent;
+ };
+ 
+ AscentAndDescent primaryFontMetricsForInlineBox();
+ int adjustInlineBoxHeightsForLineBoxContainIfApplicable___trans_tmp_1;
+ 
+ void adjustInlineBoxHeightsForLineBoxContainIfApplicable()
+ {
+   Trans_NS_WTF_HashMap inlineBoxBoundsMap;
+   auto ensureFontMetricsBasedHeight = [&](auto inlineBox)
+   {
+     auto [ascent, descent] = primaryFontMetricsForInlineBox();
+     auto halfLeading = isRubyAnnotationBox() ? ascent + descent : 0.f;
+     ascent += halfLeading;
+     inlineBoxBoundsMap.set(&inlineBox, EnclosingAscentDescent{ascent, descent});
+   };
+   ensureFontMetricsBasedHeight(
+       adjustInlineBoxHeightsForLineBoxContainIfApplicable___trans_tmp_1);
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/g++.target/sh/torture/sh-torture.exp gcc-16-20251221/gcc/testsuite/g++.target/sh/torture/sh-torture.exp
*** gcc-16-20251214/gcc/testsuite/g++.target/sh/torture/sh-torture.exp	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/g++.target/sh/torture/sh-torture.exp	Sun Dec 21 22:32:09 2025
***************
*** 0 ****
--- 1,299 ----
+ # Copyright (C) 2024 Free Software Foundation, Inc.
+ 
+ # This program 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 of the License, or
+ # (at your option) any later version.
+ #
+ # This program 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/>.
+ 
+ # GCC testsuite that uses the `gcc-dg.exp' driver, looping over
+ # optimization options.
+ 
+ # Exit immediately if this isn't an SH target.
+ if { ![istarget sh*-*-*] } then {
+   return
+ }
+ 
+ # Load support procs.
+ load_lib g++-dg.exp
+ 
+ # Return 1 if target is SH2A
+ proc check_effective_target_sh2a { } {
+     return [check_no_compiler_messages sh2a object {
+ 	     #ifndef __SH2A__
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ # Return 1 if target is SH1
+ proc check_effective_target_sh1 { } {
+     return [check_no_compiler_messages sh1 object {
+ 	     #ifndef __SH1__
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ # Return 1 if target is SH4A
+ proc check_effective_target_sh4a { } {
+     return [check_no_compiler_messages sh4a object {
+ 	     #ifndef __SH4A__
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ # Return 1 if target is big endian
+ proc check_effective_target_big_endian { } {
+     return [check_no_compiler_messages big_endian object {
+ 	     #if __BYTE_ORDER__ != __ORDER_BIG_ENDIAN__
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ # Return 1 if target is little endian
+ proc check_effective_target_little_endian { } {
+     return [check_no_compiler_messages little_endian object {
+ 	     #if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ # Return 1 if the target has any FPU (single or double precision)
+ proc check_effective_target_any_fpu { } {
+     return [check_no_compiler_messages any_fpu object {
+ 	     #ifndef __SH_FPU_ANY__
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ # Return 1 if the target has a double precision FPU which is allowed to be
+ # used by the compiler as such.
+ proc check_effective_target_double_fpu { } {
+     return [check_no_compiler_messages double_fpu object {
+ 	     #ifndef __SH_FPU_DOUBLE__
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ # Return 1 if the target has a double precision FPU but it is only being used
+ # in single precision mode by the compiler
+ proc check_effective_target_use_single_only_fpu { } {
+     return [check_no_compiler_messages use_single_only_fpu object {
+ 	     #if !(defined (__SH2A_SINGLE_ONLY__) \
+ 		   || defined (__SH4_SINGLE_ONLY__))
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ # Return 1 if the target has an FPU and the default mode is single
+ proc check_effective_target_default_single_fpu { } {
+     return [check_no_compiler_messages default_single_fpu object {
+ 	     #if !(defined (__SH2E__) || defined (__SH3E__) \
+ 		   || defined (__SH2A_SINGLE__) \
+ 		   || defined (__SH2A_SINGLE_ONLY__) \
+ 		   || defined (__SH4_SINGLE__) \
+ 		   || defined (__SH4_SINGLE_ONLY__))
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ # Return 1 if the target has no FPU
+ proc check_effective_target_no_fpu { } {
+     return [check_no_compiler_messages no_fpu object {
+ 	     #ifdef __SH_FPU_ANY__
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ 
+ # Return 1 if the target has XF regs
+ proc check_effective_target_has_xf_regs { } {
+     return [check_no_compiler_messages has_xf_regs object {
+ 	     #if !(defined (__SH_FPU_ANY__) \
+ 		   && (defined (__SH4__) \
+ 		       || defined (__SH4_SINGLE__) \
+ 		       || defined (__SH4_SINGLE_ONLY__) \
+ 		       || defined (__SH4A__)))
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ 
+ # Return 1 if the target can do the fsca insn
+ proc check_effective_target_has_fsca { } {
+     return [check_no_compiler_messages has_fsca object {
+ 	     #if !(defined (__SH_FPU_ANY__) \
+ 		   && (defined (__SH4__) \
+ 		       || defined (__SH4_SINGLE__) \
+ 		       || defined (__SH4_SINGLE_ONLY__) \
+ 		       || defined (__SH4A__)))
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ # Return 1 if the target can do the fsrra insn
+ proc check_effective_target_has_fsrra { } {
+     return [check_no_compiler_messages has_fsrra object {
+ 	     #if !(defined (__SH_FPU_ANY__) \
+ 		   && (defined (__SH4__) \
+ 		       || defined (__SH4_SINGLE__) \
+ 		       || defined (__SH4_SINGLE_ONLY__) \
+ 		       || defined (__SH4A__)))
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ # Return 1 if the target can do the fpchg insn
+ proc check_effective_target_has_fpchg { } {
+     return [check_no_compiler_messages has_fpchg object {
+ 	     #if !(defined (__SH4A__) && defined (__SH_FPU_ANY__) \
+ 		   && !defined (__SH4_SINGLE_ONLY__))
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ # Return 1 if the target can do dynamic shifts
+ proc check_effective_target_has_dyn_shift { } {
+     return [check_no_compiler_messages has_dyn_shift object {
+ 	     #if !(defined (__SH3__) \
+ 		   || defined (__SH3E__) \
+ 		   || defined (__SH2A__) \
+ 		   || defined (__SH4__) \
+ 		   || defined (__SH4_NOFPU__) \
+ 		   || defined (__SH4_SINGLE__) \
+ 		   || defined (__SH4_SINGLE_ONLY__) \
+ 		   || defined (__SH4A__))
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ # Return 1 if the mfmovd option is enabled
+ proc check_effective_target_fmovd_enabled { } {
+     return [check_no_compiler_messages fmovd_enabled object {
+ 	     #ifndef __FMOVD_ENABLED__
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ # Return 1 if the target supports privileged mode
+ proc check_effective_target_has_privileged { } {
+     return [check_no_compiler_messages has_privileged object {
+ 	     #if !(defined (__SH3__) \
+ 		   || defined (__SH3E__) \
+ 		   || defined (__SH4__) \
+ 		   || defined (__SH4_NOFPU__) \
+ 		   || defined (__SH4_SINGLE__) \
+ 		   || defined (__SH4_SINGLE_ONLY__) \
+ 		   || defined (__SH4A__))
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ # Return 1 if the target supports the prefetch insn
+ proc check_effective_target_has_pref { } {
+     return [check_no_compiler_messages has_pref object {
+ 	     #if !(defined (__SH3__) \
+ 		   || defined (__SH3E__) \
+ 		   || defined (__SH4__) \
+ 		   || defined (__SH4_NOFPU__) \
+ 		   || defined (__SH4_SINGLE__) \
+ 		   || defined (__SH4_SINGLE_ONLY__) \
+ 		   || defined (__SH4A__))
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ # Return 1 if target does banked r0..r7 regs type of ISRs
+ proc check_effective_target_banked_r0r7_isr { } {
+     return [check_no_compiler_messages banked_r0r7_isr object {
+ 	     #if !(defined (__SH3__) || defined (__SH3E__) \
+ 		   || defined (__SH4__) \
+ 		   || defined (__SH4_SINGLE__) \
+ 		   || defined (__SH4_SINGLE_ONLY__) \
+ 		   || defined (__SH4_NOFPU__) \
+ 		   || defined (__SH4A__))
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ # Return 1 if target does stack only type of ISRs
+ proc check_effective_target_stack_save_isr { } {
+     return [check_no_compiler_messages stack_save_isr object {
+ 	     #if !(defined (__SH1__) \
+ 		   || defined (__SH2__) \
+ 		   || defined (__SH2E__) \
+ 		   || defined (__SH2A__))
+ 	     #error ""
+ 	     #endif
+     } ""]
+ }
+ 
+ # Return 1 if target supports atomic-model=soft-gusa
+ proc check_effective_target_atomic_model_soft_gusa_available { } {
+     return [check_no_compiler_messages atomic_model_soft_gusa_available object {
+ 	     int x = 0;
+     } "-matomic-model=soft-gusa"]
+ }
+ 
+ # Return 1 if target supports atomic-model=soft-tcb
+ proc check_effective_target_atomic_model_soft_tcb_available { } {
+     return [check_no_compiler_messages atomic_model_soft_tcb_available object {
+ 	     int x = 0;
+     } "-matomic-model=soft-tcb,gbr-offset=0"]
+ }
+ 
+ # Return 1 if target supports atomic-model=soft-imask
+ proc check_effective_target_atomic_model_soft_imask_available { } {
+     return [check_no_compiler_messages atomic_model_soft_imask_available object {
+ 	     int x = 0;
+     } "-matomic-model=soft-imask -mno-usermode"]
+ }
+ 
+ # Return 1 if target supports atomic-model=hard-llcs
+ proc check_effective_target_atomic_model_hard_llcs_available { } {
+     return [check_no_compiler_messages atomic_model_hard_llcs_available object {
+ 	     int x = 0;
+     } "-matomic-model=hard-llcs"]
+ }
+ 
+ # If a testcase doesn't have special options, use these.
+ global DEFAULT_CXXFLAGS
+ if ![info exists DEFAULT_CXXFLAGS] then {
+     set DEFAULT_CXXFLAGS " -pedantic-errors"
+ }
+ 
+ # Initialize `dg'.
+ dg-init
+ 
+ # Main loop.
+ gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C]] "" $DEFAULT_CXXFLAGS
+ 
+ 
+ # All done.
+ dg-finish
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.c-torture/compile/20030323-1.c gcc-16-20251221/gcc/testsuite/gcc.c-torture/compile/20030323-1.c
*** gcc-16-20251214/gcc/testsuite/gcc.c-torture/compile/20030323-1.c	Sun Dec 14 22:32:10 2025
--- gcc-16-20251221/gcc/testsuite/gcc.c-torture/compile/20030323-1.c	Sun Dec 21 22:32:09 2025
***************
*** 1,5 ****
  /* PR c/10178.  The following code would ICE because we didn't check for
!    overflow when computing the range of the switch-statment, and therefore
     decided it could be implemented using bit-tests.  */
  
  int
--- 1,5 ----
  /* PR c/10178.  The following code would ICE because we didn't check for
!    overflow when computing the range of the switch-statement, and therefore
     decided it could be implemented using bit-tests.  */
  
  int
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/gomp/static-chunk-size-one.c gcc-16-20251221/gcc/testsuite/gcc.dg/gomp/static-chunk-size-one.c
*** gcc-16-20251214/gcc/testsuite/gcc.dg/gomp/static-chunk-size-one.c	Sun Dec 14 22:32:11 2025
--- gcc-16-20251221/gcc/testsuite/gcc.dg/gomp/static-chunk-size-one.c	Sun Dec 21 22:32:10 2025
***************
*** 1,5 ****
  /* { dg-do compile } */
! /* { dg-options "-fopenmp -O2 -fdump-tree-optimized -fno-tree-pre" } */
  
  int
  bar ()
--- 1,5 ----
  /* { dg-do compile } */
! /* { dg-options "-fopenmp -O2 -fdump-tree-optimized -fno-tree-pre -fno-tree-vectorize" } */
  
  int
  bar ()
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/lto/fnptr-from-rec-1_0.c gcc-16-20251221/gcc/testsuite/gcc.dg/lto/fnptr-from-rec-1_0.c
*** gcc-16-20251214/gcc/testsuite/gcc.dg/lto/fnptr-from-rec-1_0.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.dg/lto/fnptr-from-rec-1_0.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,41 ----
+ /* { dg-lto-do link } */
+ /* { dg-lto-options { { -O3 -flto -fdump-ipa-devirt } } }  */
+ 
+ 
+ struct fnptrs
+ {
+   void (*first)(void);
+   int (*dostuff)(int);
+ };
+ 
+ struct fnptrs fp;
+ 
+ 
+ void __attribute__ ((noinline)) init (void);
+ 
+ volatile int v;
+ 
+ int __attribute__ ((noipa))
+ get_count (void)
+ {
+   return 4;
+ };
+ 
+ 
+ void __attribute__ ((noinline))
+ loop (void)
+ {
+   for (int i = 0; i < get_count (); i++)
+     {
+       v = v + fp.dostuff (v);
+     }
+ }
+ 
+ int main (int argc, char **argv)
+ {
+   init ();
+   loop ();
+   return 0;
+ }
+ 
+ /* { dg-final { scan-wpa-ipa-dump "num speculative call targets: 1" "devirt" } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/lto/fnptr-from-rec-1_1.c gcc-16-20251221/gcc/testsuite/gcc.dg/lto/fnptr-from-rec-1_1.c
*** gcc-16-20251214/gcc/testsuite/gcc.dg/lto/fnptr-from-rec-1_1.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.dg/lto/fnptr-from-rec-1_1.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,19 ----
+ struct fnptrs
+ {
+   void (*first)(void);
+   int (*dostuff)(int);
+ };
+ 
+ extern struct fnptrs fp;
+ 
+ int noop (int n)
+ {
+   return n;
+ }
+ 
+ 
+ void __attribute__ ((noinline))
+ init (void)
+ {
+   fp.dostuff = noop;
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/lto/fnptr-from-rec-2_0.c gcc-16-20251221/gcc/testsuite/gcc.dg/lto/fnptr-from-rec-2_0.c
*** gcc-16-20251214/gcc/testsuite/gcc.dg/lto/fnptr-from-rec-2_0.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.dg/lto/fnptr-from-rec-2_0.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,43 ----
+ /* { dg-lto-do link } */
+ /* { dg-lto-options { { -O3 -flto -fdump-ipa-devirt } } } */
+ 
+ 
+ struct fnptrs
+ {
+   void (*first)(void);
+   int (*dostuff)(int);
+ };
+ 
+ int noop (int n);
+ 
+ struct fnptrs fp = {(void (*)(void)) 0, noop};
+ 
+ 
+ void __attribute__ ((noinline)) init (void);
+ 
+ volatile int v;
+ 
+ int __attribute__ ((noipa))
+ get_count (void)
+ {
+   return 4;
+ };
+ 
+ 
+ void __attribute__ ((noinline))
+ loop (void)
+ {
+   for (int i = 0; i < get_count (); i++)
+     {
+       v = v + fp.dostuff (v);
+     }
+ }
+ 
+ int main (int argc, char **argv)
+ {
+   init ();
+   loop ();
+   return 0;
+ }
+ 
+ /* { dg-final { scan-wpa-ipa-dump "num speculative call targets: 1"  "devirt"  } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/lto/fnptr-from-rec-2_1.c gcc-16-20251221/gcc/testsuite/gcc.dg/lto/fnptr-from-rec-2_1.c
*** gcc-16-20251214/gcc/testsuite/gcc.dg/lto/fnptr-from-rec-2_1.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.dg/lto/fnptr-from-rec-2_1.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,22 ----
+ struct fnptrs
+ {
+   void (*first)(void);
+   int (*dostuff)(int);
+ };
+ 
+ extern struct fnptrs fp;
+ 
+ int noop (int n)
+ {
+   return n;
+ }
+ 
+ void distraction (void)
+ {
+ }
+ 
+ void __attribute__ ((noinline))
+ init (void)
+ {
+   fp.first = distraction;
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/lto/fnptr-from-rec-3_0.c gcc-16-20251221/gcc/testsuite/gcc.dg/lto/fnptr-from-rec-3_0.c
*** gcc-16-20251214/gcc/testsuite/gcc.dg/lto/fnptr-from-rec-3_0.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.dg/lto/fnptr-from-rec-3_0.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,43 ----
+ /* { dg-lto-do link } */
+ /* { dg-lto-options { { -O3 -flto -fdump-ipa-devirt } } } */
+ 
+ 
+ struct fnptrs
+ {
+   void (*first)(void);
+   int (*dostuff)(int);
+ };
+ 
+ int noop (int n);
+ 
+ struct fnptrs fp = {(void (*)(void)) 0, noop};
+ 
+ 
+ void __attribute__ ((noinline)) init (void);
+ 
+ volatile int v;
+ 
+ int __attribute__ ((noipa))
+ get_count (void)
+ {
+   return 4;
+ };
+ 
+ 
+ void __attribute__ ((noinline))
+ loop (void)
+ {
+   for (int i = 0; i < get_count (); i++)
+     {
+       v = v + fp.dostuff (v);
+     }
+ }
+ 
+ int main (int argc, char **argv)
+ {
+   init ();
+   loop ();
+   return 0;
+ }
+ 
+ /* { dg-final { scan-wpa-ipa-dump "num speculative call targets: 1"  "devirt"  } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/lto/fnptr-from-rec-3_1.c gcc-16-20251221/gcc/testsuite/gcc.dg/lto/fnptr-from-rec-3_1.c
*** gcc-16-20251214/gcc/testsuite/gcc.dg/lto/fnptr-from-rec-3_1.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.dg/lto/fnptr-from-rec-3_1.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,19 ----
+ struct fnptrs
+ {
+   void (*first)(void);
+   int (*dostuff)(int);
+ };
+ 
+ extern struct fnptrs fp;
+ 
+ int noop (int n)
+ {
+   return n;
+ }
+ 
+ 
+ void __attribute__ ((noinline))
+ init (void)
+ {
+   fp.dostuff = noop;
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/plugin/crash-test-nested-write-through-null-html.py gcc-16-20251221/gcc/testsuite/gcc.dg/plugin/crash-test-nested-write-through-null-html.py
*** gcc-16-20251214/gcc/testsuite/gcc.dg/plugin/crash-test-nested-write-through-null-html.py	Sun Dec 14 22:32:11 2025
--- gcc-16-20251221/gcc/testsuite/gcc.dg/plugin/crash-test-nested-write-through-null-html.py	Sun Dec 21 22:32:10 2025
***************
*** 1,6 ****
--- 1,7 ----
  from htmltest import *
  
  import pytest
+ import re
  
  @pytest.fixture(scope='function', autouse=True)
  def html_tree():
*************** def test_results(html_tree):
*** 39,42 ****
      assert ice is not None
      ice_msg = ice.find("./xhtml:div[@class='gcc-message']", ns)
      assert ice_msg is not None
!     assert ice_msg.text == "Segmentation fault"
--- 40,43 ----
      assert ice is not None
      ice_msg = ice.find("./xhtml:div[@class='gcc-message']", ns)
      assert ice_msg is not None
!     assert re.match("Segmentation [Ff]ault", ice_msg.text)
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/plugin/crash-test-nested-write-through-null-sarif.py gcc-16-20251221/gcc/testsuite/gcc.dg/plugin/crash-test-nested-write-through-null-sarif.py
*** gcc-16-20251214/gcc/testsuite/gcc.dg/plugin/crash-test-nested-write-through-null-sarif.py	Sun Dec 14 22:32:11 2025
--- gcc-16-20251221/gcc/testsuite/gcc.dg/plugin/crash-test-nested-write-through-null-sarif.py	Sun Dec 21 22:32:10 2025
***************
*** 1,6 ****
--- 1,7 ----
  from sarif import *
  
  import pytest
+ import re
  
  @pytest.fixture(scope='function', autouse=True)
  def sarif():
*************** def test_notification(sarif):
*** 32,38 ****
  
      notification = notifications[0]
  
!     assert notification['message']['text'] == "Segmentation fault"
      assert notification['level'] == 'error'
  
      loc0 = notification['locations'][0]
--- 33,39 ----
  
      notification = notifications[0]
  
!     assert re.match("Segmentation [Ff]ault", notification['message']['text'])
      assert notification['level'] == 'error'
  
      loc0 = notification['locations'][0]
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/plugin/crash-test-write-through-null-stderr.c gcc-16-20251221/gcc/testsuite/gcc.dg/plugin/crash-test-write-through-null-stderr.c
*** gcc-16-20251214/gcc/testsuite/gcc.dg/plugin/crash-test-write-through-null-stderr.c	Sun Dec 14 22:32:11 2025
--- gcc-16-20251221/gcc/testsuite/gcc.dg/plugin/crash-test-write-through-null-stderr.c	Sun Dec 21 22:32:10 2025
*************** extern void inject_write_through_null (v
*** 5,10 ****
  
  void test_inject_write_through_null (void)
  {
!   inject_write_through_null (); /* { dg-ice "Segmentation fault" } */ 
    /* { dg-regexp "during GIMPLE pass: crash_test" } */
  }
--- 5,10 ----
  
  void test_inject_write_through_null (void)
  {
!   inject_write_through_null (); /* { dg-ice {Segmentation [Ff]ault} } */ 
    /* { dg-regexp "during GIMPLE pass: crash_test" } */
  }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-html.c gcc-16-20251221/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-html.c
*** gcc-16-20251214/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-html.c	Sun Dec 14 22:32:11 2025
--- gcc-16-20251221/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-html.c	Sun Dec 21 22:32:10 2025
***************
*** 1,6 ****
  /* { dg-do compile } */
  /* { dg-options "-fdiagnostics-add-output=experimental-html:javascript=no" } */
! 
  extern void here (void);
  
  void test_graphs (void)
--- 1,6 ----
  /* { dg-do compile } */
  /* { dg-options "-fdiagnostics-add-output=experimental-html:javascript=no" } */
! /* { dg-require-dot "" } */
  extern void here (void);
  
  void test_graphs (void)
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/plugin/plugin.exp gcc-16-20251221/gcc/testsuite/gcc.dg/plugin/plugin.exp
*** gcc-16-20251214/gcc/testsuite/gcc.dg/plugin/plugin.exp	Sun Dec 14 22:32:11 2025
--- gcc-16-20251221/gcc/testsuite/gcc.dg/plugin/plugin.exp	Sun Dec 21 22:32:10 2025
***************
*** 19,30 ****
  load_lib target-supports.exp
  load_lib gcc-dg.exp
  
- global TESTING_IN_BUILD_TREE
  global ENABLE_PLUGIN
  
! # The plugin testcases currently only work when the build tree is available.
! # Also check whether the host supports plugins.
! if { ![info exists TESTING_IN_BUILD_TREE] || ![info exists ENABLE_PLUGIN] } {
      return
  }
  
--- 19,28 ----
  load_lib target-supports.exp
  load_lib gcc-dg.exp
  
  global ENABLE_PLUGIN
  
! # Check whether the host supports plugins.
! if { ![info exists ENABLE_PLUGIN] } {
      return
  }
  
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/pr122343-1.c gcc-16-20251221/gcc/testsuite/gcc.dg/pr122343-1.c
*** gcc-16-20251214/gcc/testsuite/gcc.dg/pr122343-1.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.dg/pr122343-1.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,9 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O2 -fdump-rtl-final" } */
+ /* { dg-final { scan-rtl-dump "\\\(mem/v:" "final" } } */
+ 
+ void
+ foo (int *p)
+ {
+   *(volatile int *) p = *p;
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/pr123110-1.c gcc-16-20251221/gcc/testsuite/gcc.dg/pr123110-1.c
*** gcc-16-20251214/gcc/testsuite/gcc.dg/pr123110-1.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.dg/pr123110-1.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,31 ----
+ /* { dg-do compile } */
+ /* { dg-options "-Os -fexceptions -finstrument-functions-once" } */
+ /* PR tree-optimization/123110 */
+ 
+ /* Make sure forwarder blocks (with labels) to eh landing pads are handled
+    correctly. */
+ 
+ void baz ();
+ 
+ int g, h;
+ 
+ static inline __attribute__((__always_inline__)) void
+ bar (int *out_base)
+ {
+   if (!g)
+     {
+       baz ();
+       switch (h)
+ 	;
+       return;
+     }
+ fail:
+   *out_base = 0;
+ }
+ 
+ void
+ foo ()
+ {
+   unsigned base;
+   bar (&base);
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/pr123205.c gcc-16-20251221/gcc/testsuite/gcc.dg/pr123205.c
*** gcc-16-20251214/gcc/testsuite/gcc.dg/pr123205.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.dg/pr123205.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,23 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O2 -fdump-tree-optimized" } */
+ void isconst (int, int);
+ void nonconst (int, int);
+ 
+ int foo (int x)
+ {
+  int y =  __builtin_constant_p (x);
+  if (y)
+    isconst (y, x);
+   else
+    nonconst (y, x);
+ 
+  if (x == 24)
+    {
+      /* Y should have the same value as earlier. */
+      if (y)
+        isconst (y, x);
+      else
+        nonconst (y, x);
+    }
+ }
+ /* { dg-final { scan-tree-dump-not "isconst"  "optimized" } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/torture/builtin-shufflevector-pr123156.c gcc-16-20251221/gcc/testsuite/gcc.dg/torture/builtin-shufflevector-pr123156.c
*** gcc-16-20251214/gcc/testsuite/gcc.dg/torture/builtin-shufflevector-pr123156.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.dg/torture/builtin-shufflevector-pr123156.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,40 ----
+ /* { dg-do run } */
+ 
+ #include <stdint.h>
+ 
+ #define BS_VEC(type, num) type __attribute__((vector_size(num * sizeof(type))))
+ #define BITCAST(T, F, arg)                                                     \
+     ((union {                                                                  \
+         F src;                                                                 \
+         T dst;                                                                 \
+     })arg)                                                                     \
+         .dst
+ 
+ uint64_t func_1()
+ {
+     BS_VEC(uint64_t, 32) BS_VAR_0;
+     BS_VAR_0 = BITCAST(
+         BS_VEC(uint64_t, 32), BS_VEC(uint8_t, 256),
+         __builtin_shufflevector(
+             (BS_VEC(uint8_t, 2)){ 2 }, (BS_VEC(uint8_t, 2)){}, 1, 0, 2, 2, 2, 3,
+             1, 2, 3, 1, 3, 3, 2, 1, 3, 0, 2, 2, 1, 2, 1, 3, 1, 1, 0, 0, 2, 0, 3,
+             2, 2, 0, 1, 3, 1, 2, 0, 2, 0, 3, 0, 0, 2, 0, 2, 1, 3, 2, 3, 2, 1, 1,
+             2, 3, 3, 3, 3, 0, 1, 2, 3, 2, 0, 2, 2, 2, 0, 3, 3, 3, 1, 3, 0, 0, 2,
+             3, 1, 1, 2, 2, 1, 2, 0, 0, 3, 2, 2, 3, 2, 2, 3, 2, 0, 2, 2, 0, 2, 1,
+             3, 1, 0, 2, 1, 3, 2, 1, 0, 2, 3, 0, 1, 3, 2, 1, 3, 1, 1, 3, 2, 2, 0,
+             3, 2, 2, 0, 3, 0, 3, 2, 3, 1, 3, 2, 3, 3, 2, 2, 0, 0, 0, 2, 1, 3, 1,
+             2, 2, 3, 0, 1, 3, 1, 1, 2, 0, 1, 2, 1, 2, 0, 2, 0, 2, 3, 3, 3, 1, 2,
+             0, 3, 1, 2, 0, 1, 0, 3, 0, 0, 3, 2, 2, 0, 3, 1, 2, 0, 1, 1, 3, 0, 1,
+             3, 1, 3, 2, 1, 3, 1, 2, 1, 1, 0, 1, 3, 3, 2, 3, 2, 2, 0, 2, 2, 2, 1,
+             1, 0, 3, 1, 3, 0, 3, 0, 0, 1, 3, 3, 1, 2, 1, 1, 3, 1, 0, 2, 1, 3, 2,
+             1, 3, 2, 2, 2, 3, 2, 0, 1, 3, 3, 3, 0, 0, 0, 1, 3, 2, 2, 1));
+     return BS_VAR_0[0];
+ }
+ 
+ int main()
+ {
+     uint64_t BS_CHECKSUM = func_1();
+     if (BS_CHECKSUM != 0x0000000000000200ull)
+       __builtin_abort ();
+     return 0;
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/tree-ssa/copy-headers-13.c gcc-16-20251221/gcc/testsuite/gcc.dg/tree-ssa/copy-headers-13.c
*** gcc-16-20251214/gcc/testsuite/gcc.dg/tree-ssa/copy-headers-13.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.dg/tree-ssa/copy-headers-13.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,25 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O3 -fdump-tree-ch-details -fdump-tree-ldist-details" } */
+ 
+ /* PR tree-optimization/122734 */
+ /* We want to duplicate the block after the one containing the condition going to abort as
+    it is unlikely.
+ /* So in the end ldist can generate a memset. */
+ 
+ static inline int size(int *a)
+ {
+   int t = *a;
+   if (t < 0)  __builtin_abort();
+   return t;
+ }
+ 
+ void f(int *l, short *d)
+ {
+   for(int i = 0; i < size(l); i++)
+     d[i] = 0;
+ }
+ 
+ /* { dg-final { scan-tree-dump-times "Duplicating bb . is a win" 1 "ch2" } } */
+ /* { dg-final { scan-tree-dump-times "Will duplicate bb" 2 "ch2" } } */
+ /* { dg-final { scan-tree-dump "is now do-while loop" "ch2" } } */
+ /* { dg-final { scan-tree-dump "generated memset zero" "ldist" } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/tree-ssa/ctz-ch.c gcc-16-20251221/gcc/testsuite/gcc.dg/tree-ssa/ctz-ch.c
*** gcc-16-20251214/gcc/testsuite/gcc.dg/tree-ssa/ctz-ch.c	Sun Dec 14 22:32:11 2025
--- gcc-16-20251221/gcc/testsuite/gcc.dg/tree-ssa/ctz-ch.c	Sun Dec 21 22:32:10 2025
***************
*** 1,4 ****
--- 1,5 ----
  /* { dg-do compile } */
+ /* { dg-require-effective-target ctz } */
  /* { dg-options "-O2 -fdump-tree-optimized" } */
  
  typedef unsigned long BITMAP_WORD;
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/tree-ssa/pr96779-disabled.c gcc-16-20251221/gcc/testsuite/gcc.dg/tree-ssa/pr96779-disabled.c
*** gcc-16-20251214/gcc/testsuite/gcc.dg/tree-ssa/pr96779-disabled.c	Sun Dec 14 22:32:11 2025
--- gcc-16-20251221/gcc/testsuite/gcc.dg/tree-ssa/pr96779-disabled.c	Sun Dec 21 22:32:10 2025
*************** main (void)
*** 81,85 ****
    return 0;
  }
  
! /* Verify that we have *not* transfered "= -" pattern in any of those functions.  */
  /* { dg-final { scan-tree-dump-times "= -" 4 "optimized" } } */
--- 81,85 ----
    return 0;
  }
  
! /* Verify that we have *not* transferred "= -" pattern in any of those functions.  */
  /* { dg-final { scan-tree-dump-times "= -" 4 "optimized" } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/tree-ssa/pr96779.c gcc-16-20251221/gcc/testsuite/gcc.dg/tree-ssa/pr96779.c
*** gcc-16-20251214/gcc/testsuite/gcc.dg/tree-ssa/pr96779.c	Sun Dec 14 22:32:11 2025
--- gcc-16-20251221/gcc/testsuite/gcc.dg/tree-ssa/pr96779.c	Sun Dec 21 22:32:10 2025
*************** main (void)
*** 76,80 ****
    return 0;
  }
  
! /* Verify that we transfered to "= -" pattern from "_2 = -_1;".  */
  /* { dg-final { scan-tree-dump-not "= -" "optimized" } } */
--- 76,80 ----
    return 0;
  }
  
! /* Verify that we transferred to "= -" pattern from "_2 = -_1;".  */
  /* { dg-final { scan-tree-dump-not "= -" "optimized" } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-16.c gcc-16-20251221/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-16.c
*** gcc-16-20251214/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-16.c	Sun Dec 14 22:32:11 2025
--- gcc-16-20251221/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-16.c	Sun Dec 21 22:32:10 2025
*************** void foo (int a, int b, int c, int d, in
*** 12,18 ****
      res = 7;
    if (d < 2)
      res = 9;
!   /* Accounting whoes makes this not catched.  */
  #if 0
    if (e != 37)
      res = 11;
--- 12,18 ----
      res = 7;
    if (d < 2)
      res = 9;
!   /* Accounting whoes makes this not caught.  */
  #if 0
    if (e != 37)
      res = 11;
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/vect/pr123032.c gcc-16-20251221/gcc/testsuite/gcc.dg/vect/pr123032.c
*** gcc-16-20251214/gcc/testsuite/gcc.dg/vect/pr123032.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.dg/vect/pr123032.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,55 ----
+ /* { dg-require-effective-target vect_int } */
+ /* { dg-final { scan-tree-dump "loop vectorized" "vect" } } */
+ 
+ #include "tree-vect.h"
+ 
+ typedef unsigned char u8;
+ typedef unsigned int u32;
+ 
+ typedef struct {
+     u32 pad; // important
+     u8  buf[64];
+ } s_t;
+ 
+ __attribute__((noipa))
+ void h_bad(s_t *state, const u8 *in, u32 inlen) {
+     for (u32 i = 0; i < inlen; i++) {
+         state->buf[i] = in[i];
+     }
+ }
+ 
+ __attribute__((noipa))
+ void h_good(s_t *state, const u8 *in, u32 inlen) {
+     for (u32 i = 0; i < inlen; i++) {
+         asm volatile("" ::: "memory"); // break vectorizer
+         state->buf[i] = in[i];
+     }
+ }
+ 
+ void h(s_t *state, const u8 *in, u32 inlen) {
+     s_t s1 = {};
+     s_t s2 = {};
+     h_good(&s1, in, inlen);
+     h_bad(&s2, in, inlen);
+     if (__builtin_memcmp(&s1, &s2, sizeof(s1)) != 0) {
+         __builtin_trap();
+     }
+ }
+ 
+ int main(void) {
+ 
+    check_vect ();
+ 
+     s_t s = {};
+     const u8 in[] =
+         "0123456789" /* 0 */
+         " 0123456789"
+         " 0123456789"
+         " 0123456789"
+         " 0123456789"
+     ;
+     for (u32 o = 0; o < 10; o++) {
+         __builtin_memset(&s, 0, sizeof(s));
+         h(&s, &in[o], 33);
+     }
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/vect/pr123043.c gcc-16-20251221/gcc/testsuite/gcc.dg/vect/pr123043.c
*** gcc-16-20251214/gcc/testsuite/gcc.dg/vect/pr123043.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.dg/vect/pr123043.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,17 ----
+ /* { dg-do compile } */
+ /* { dg-require-effective-target vect_int } */
+ /* { dg-final { scan-tree-dump "loop vectorized" "vect" } } */
+ /* { dg-additional-options "-O3 -mgeneral-regs-only" { target aarch64*-*-* } } */
+ /* { dg-additional-options "-O3 -m32 -mno-sse" { target {  { i?86-*-* x86_64-*-* } && ilp32 } } } */
+ /* { dg-additional-options "-w" } */
+ 
+ char sad_memcpy_pout;
+ int inflate_fast_len;
+ void inflate_fast() {
+   char *out = &sad_memcpy_pout, *from;
+   do {
+     *out++ = *from++;
+     *out++ = *from++;
+     inflate_fast_len -= 3;
+   } while (inflate_fast_len > 2);
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/vect/vect-early-break_141-pr123089.c gcc-16-20251221/gcc/testsuite/gcc.dg/vect/vect-early-break_141-pr123089.c
*** gcc-16-20251214/gcc/testsuite/gcc.dg/vect/vect-early-break_141-pr123089.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.dg/vect/vect-early-break_141-pr123089.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,40 ----
+ /* { dg-add-options vect_early_break } */
+ /* { dg-require-effective-target vect_early_break_hw } */
+ /* { dg-require-effective-target vect_int } */
+ /* { dg-require-effective-target avx2_runtime { target { i?86-*-* x86_64-*-* } } } */
+ 
+ /* { dg-additional-options "-O3 -fno-strict-aliasing -march=znver3" { target { i?86-*-* x86_64-*-* } } } */
+ /* { dg-final { scan-tree-dump "loop vectorized" "vect" { target { i?86-*-* x86_64-*-* } } } } */
+ 
+ #include "tree-vect.h"
+ 
+ struct
+ {
+   int d;
+   short e;
+ } i;
+ 
+ int b;
+ int *h = &b;
+ 
+ int
+ main ()
+ {
+   check_vect ();
+ 
+   short f = 1;
+   short *g = &i.e;
+ 
+ a:
+   if (*g = 0 & ++f, *h)
+     ;
+   else
+     {
+       int c = 0;
+       if (f)
+         goto a;
+       h = &c;
+     }
+ 
+   return 0;
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/vect/vect-early-break_40.c gcc-16-20251221/gcc/testsuite/gcc.dg/vect/vect-early-break_40.c
*** gcc-16-20251214/gcc/testsuite/gcc.dg/vect/vect-early-break_40.c	Sun Dec 14 22:32:11 2025
--- gcc-16-20251221/gcc/testsuite/gcc.dg/vect/vect-early-break_40.c	Sun Dec 21 22:32:10 2025
*************** unsigned test4(unsigned x)
*** 23,27 ****
   return ret;
  }
  
! /* SCEV can't currently analyze this loop bounds.  */
! /* { dg-final { scan-tree-dump "vectorized 1 loops in function" "vect" { xfail *-*-* } } } */
\ No newline at end of file
--- 23,26 ----
   return ret;
  }
  
! /* { dg-final { scan-tree-dump "vectorized 1 loops in function" "vect" } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/vect/vect-uncounted-prolog-peel_1.c gcc-16-20251221/gcc/testsuite/gcc.dg/vect/vect-uncounted-prolog-peel_1.c
*** gcc-16-20251214/gcc/testsuite/gcc.dg/vect/vect-uncounted-prolog-peel_1.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.dg/vect/vect-uncounted-prolog-peel_1.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,23 ----
+ /* { dg-add-options vect_early_break } */
+ /* { dg-do compile } */
+ /* { dg-require-effective-target vect_early_break } */
+ /* { dg-require-effective-target vect_int } */
+ 
+ int
+ foo (int *haystack, int needle)
+ {
+   int i = 0;
+   while (1)
+     {
+       if (haystack[i] == needle)
+ 	return i;
+       i++;
+      }
+ }
+ 
+ /* { dg-final { scan-tree-dump {note:\s*Alignment of access forced using peeling.} "vect" } } */
+ /* { dg-final { scan-tree-dump {if \(prolog_loop_niters.[0-9_]+ == 0\)\n\s*goto} "vect" } } */
+ /* { dg-final { scan-tree-dump {ivtmp_[0-9_]+ = PHI <ivtmp_[0-9_]+\([0-9_]+\), 0\([0-9_]+\)>} "vect" } } */
+ /* { dg-final { scan-tree-dump {ivtmp_[0-9_]+ = ivtmp_[0-9_]+ \+ 1;} "vect" } } */
+ /* { dg-final { scan-tree-dump {if \(ivtmp_[0-9_]+ >= prolog_loop_niters.[0-9_]+\)\n\s*goto} "vect" } } */
+ /* { dg-final { scan-tree-dump {vectorized 1 loops in function} "vect" } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/vect/vect-uncounted-prolog-peel_2.c gcc-16-20251221/gcc/testsuite/gcc.dg/vect/vect-uncounted-prolog-peel_2.c
*** gcc-16-20251214/gcc/testsuite/gcc.dg/vect/vect-uncounted-prolog-peel_2.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.dg/vect/vect-uncounted-prolog-peel_2.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,25 ----
+ /* { dg-add-options vect_early_break } */
+ /* { dg-do compile } */
+ /* { dg-require-effective-target vect_early_break } */
+ /* { dg-require-effective-target vect_int } */
+ 
+ char b;
+ int c(char *d) {
+   int *a = 0;
+   while (*d) {
+     while (*a)
+       if (*a++ == 1)
+         return 1;
+     d++;
+   }
+ }
+ void e() {
+   c(&b);
+   char *f = &b;
+   while (f[0])
+     ++b;
+ }
+ 
+ /* { dg-final { scan-tree-dump {note:\s*Alignment of access forced using peeling.} "vect" } } */
+ /* { dg-final { scan-tree-dump {if \(ivtmp_[0-9_]+ >= prolog_loop_niters.[0-9_]+\)\n\s*goto} "vect" } } */
+ /* { dg-final { scan-tree-dump {vectorized 1 loops in function} "vect" } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/vect/vect-uncounted-prolog-peel_3.c gcc-16-20251221/gcc/testsuite/gcc.dg/vect/vect-uncounted-prolog-peel_3.c
*** gcc-16-20251214/gcc/testsuite/gcc.dg/vect/vect-uncounted-prolog-peel_3.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.dg/vect/vect-uncounted-prolog-peel_3.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,26 ----
+ /* { dg-add-options vect_early_break } */
+ /* { dg-do compile } */
+ /* { dg-require-effective-target vect_early_break } */
+ /* { dg-require-effective-target vect_int } */
+ 
+ struct {
+   int segments[];
+ } seek_to_sample_coarse_f;
+ 
+ int seek_to_sample_coarse_i, seek_to_sample_coarse_f_1;
+ 
+ void seek_to_sample_coarse() {
+   int end_pos = seek_to_sample_coarse_f_1;
+   for (;;) {
+     seek_to_sample_coarse_i = end_pos;
+     for (; end_pos > 0; --end_pos)
+       if (seek_to_sample_coarse_f.segments[end_pos - 1])
+         break;
+     if (end_pos)
+       break;
+   }
+ }
+ 
+ /* { dg-final { scan-tree-dump {note:\s*Alignment of access forced using peeling.} "vect" } } */
+ /* { dg-final { scan-tree-dump {if \(ivtmp_[0-9_]+ >= prolog_loop_niters.[0-9_]+\)\n\s*goto} "vect" } } */
+ /* { dg-final { scan-tree-dump {vectorized 1 loops in function} "vect" } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/vect/vect-uncounted-run_1.c gcc-16-20251221/gcc/testsuite/gcc.dg/vect/vect-uncounted-run_1.c
*** gcc-16-20251214/gcc/testsuite/gcc.dg/vect/vect-uncounted-run_1.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.dg/vect/vect-uncounted-run_1.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,56 ----
+ /* Check we can derive scalar IV return value from vectorized IV value,
+    resetting it on entry into the scalar epilogue loop via BIT_FIELD_REF.  */
+ /* { dg-add-options vect_early_break } */
+ /* { dg-require-effective-target vect_early_break_hw } */
+ /* { dg-require-effective-target vect_int } */
+ 
+ #include <assert.h>
+ #include "tree-vect.h"
+ 
+ #define N 128
+ #define VAL 13
+ 
+ __attribute__((noipa, noinline))
+ int
+ foo (int *haystack, int needle)
+ {
+   int i = 0;
+   while (1)
+     {
+       if (haystack[i] == needle)
+ 	return i;
+       i++;
+      }
+ }
+ 
+ #define CHECK_MATCH(POS) 		\
+   void					\
+   check_match_ ## POS (void)		\
+   {					\
+     int input[N] = {[0 ... N-1] = 0};	\
+     input[POS] = VAL;			\
+     int res = foo (input, VAL);		\
+     assert (res == POS);		\
+   }
+ 
+ CHECK_MATCH (0)
+ CHECK_MATCH (3)
+ CHECK_MATCH (127)
+ 
+ #undef CHECK_MATCH
+ #define CHECK_MATCH(POS) check_match_ ## POS ()
+ 
+ int
+ main ()
+ {
+   CHECK_MATCH (0);
+   CHECK_MATCH (3);
+   CHECK_MATCH (127);
+   return 0;
+ }
+ 
+ /* { dg-final { scan-tree-dump "Loop being analyzed as uncounted." "vect" } } */
+ /* { dg-final { scan-tree-dump "vectorized 1 loops in function" "vect" } } */
+ /* Ensure we reset our scalar IV so as to repeat the last vector iteration.  */
+ /* { dg-final { scan-tree-dump {_[0-9_]+ = BIT_FIELD_REF <vect_i_[0-9_.]+, [0-9]+, 0>} "vect" } } */
+ 
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/vect/vect-uncounted-run_2.c gcc-16-20251221/gcc/testsuite/gcc.dg/vect/vect-uncounted-run_2.c
*** gcc-16-20251214/gcc/testsuite/gcc.dg/vect/vect-uncounted-run_2.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.dg/vect/vect-uncounted-run_2.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,41 ----
+ /* execution test for the correct resetting of live out values on epilog loop
+    entry.  */
+ /* { dg-add-options vect_early_break } */
+ /* { dg-do run } */
+ /* { dg-require-effective-target vect_early_break_hw } */
+ /* { dg-require-effective-target vect_int } */
+ 
+ #include <assert.h>
+ #include "tree-vect.h"
+ #define N 9
+ 
+ __attribute__((noipa, noinline))
+ void
+ test01 ()
+ {
+     {
+       int x[N] = {2, 4, 6, 8, 10, 12, 14, 16, 18};
+       const int y[N] = {3, 5, 7, 9, 11, 13, 15, 17, 19};
+       int z[N] = {5, 9, 13, 17, 21, 25, 29, 33, 37};
+ 
+       int *x0 = x;
+       int *xN = x+N;
+       const int *y0 = y;
+       const int *yN = y+N;
+ 
+       int *res = x;
+ 
+       for (; x0 != xN && y0 != yN; ++x0, (void)++y0, ++res)
+ 	*res = *x0 + *y0;
+       assert (x0 == x+N && y0 == y+N && res == x+N);
+       assert (x[0] == z[0] && x[1] == z[1]);
+     }
+ }
+ 
+ int
+ main ()
+ {
+   test01 ();
+ }
+ 
+ /* { dg-final { scan-tree-dump "vectorized 1 loops in function" "vect" } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/vect/vect-uncounted-run_3.c gcc-16-20251221/gcc/testsuite/gcc.dg/vect/vect-uncounted-run_3.c
*** gcc-16-20251214/gcc/testsuite/gcc.dg/vect/vect-uncounted-run_3.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.dg/vect/vect-uncounted-run_3.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,42 ----
+ /* Check vectorization of uncounted reductions.  */
+ /* { dg-add-options vect_early_break } */
+ /* { dg-do run } */
+ /* { dg-require-effective-target vect_early_break_hw } */
+ /* { dg-require-effective-target vect_int } */
+ #include <assert.h>
+ #include "tree-vect.h"
+ 
+ __attribute__((noipa, noinline))
+ int
+ foo (int *a0, int *aN, int accum)
+ {
+   int i = 0;
+   while (1)
+     {
+       if (a0[i++] == *aN)
+ 	return accum;
+       accum += a0[i];
+      }
+ }
+ 
+ void
+ accum_check (int *a0, int len, int accum, int result)
+ {
+   int retval = foo (a0, a0+len, accum);
+   assert (retval == result);
+ }
+ 
+ int
+ main (void)
+ {
+   int a[] = {0,1,2,3,4,5,6,10,11,12};
+   accum_check (a, 5, 0, 15);
+   accum_check (a, 9, 0, 54);
+   accum_check (a, 6, 0, 21);
+   accum_check (a, 6, 5, 26);
+   return 0;
+ }
+ 
+ /* { dg-final { scan-tree-dump "Loop being analyzed as uncounted." "vect" } } */
+ /* { dg-final { scan-tree-dump "Detected reduction." "vect" } } */
+ /* { dg-final { scan-tree-dump "vectorized 1 loops in function" "vect" } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/vect/vect-uncounted_1.c gcc-16-20251221/gcc/testsuite/gcc.dg/vect/vect-uncounted_1.c
*** gcc-16-20251214/gcc/testsuite/gcc.dg/vect/vect-uncounted_1.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.dg/vect/vect-uncounted_1.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,24 ----
+ /* Check we can derive scalar IV return value from vectorized IV value,
+    resetting it on entry into the scalar epilogue loop via BIT_FIELD_REF.  */
+ /* { dg-add-options vect_early_break } */
+ /* { dg-do compile } */
+ /* { dg-require-effective-target vect_early_break } */
+ /* { dg-require-effective-target vect_int } */
+ 
+ int
+ foo (int *haystack, int needle)
+ {
+   int i = 0;
+   while (1)
+     {
+       if (haystack[i] == needle)
+ 	return i;
+       i++;
+      }
+ }
+ 
+ /* { dg-final { scan-tree-dump "Loop being analyzed as uncounted." "vect" } } */
+ /* { dg-final { scan-tree-dump "vectorized 1 loops in function" "vect" } } */
+ /* Ensure we reset our scalar IV so as to repeat the last vector iteration.  */
+ /* { dg-final { scan-tree-dump {_[0-9_]+ = BIT_FIELD_REF <vect_i_[0-9_.]+, [0-9]+, 0>} "vect" } } */
+ 
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/vect/vect-uncounted_2.c gcc-16-20251221/gcc/testsuite/gcc.dg/vect/vect-uncounted_2.c
*** gcc-16-20251214/gcc/testsuite/gcc.dg/vect/vect-uncounted_2.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.dg/vect/vect-uncounted_2.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,21 ----
+ /* { dg-add-options vect_early_break } */
+ /* { dg-do compile } */
+ /* { dg-require-effective-target vect_early_break } */
+ /* { dg-require-effective-target vect_int } */
+ 
+ int
+ foo (int *a0, int *aN, int *b0, int *bN)
+ {
+   int *a = a0;
+   int *b = b0;
+ 
+   for (;a != aN && b != bN; a++, b++)
+     *a += *b;
+ }
+ 
+ /* { dg-final { scan-tree-dump "Loop being analyzed as uncounted." "vect" } } */
+ /* { dg-final { scan-tree-dump "vectorized 1 loops in function" "vect" } } */
+ /* Make sure the values used in peeled epilog loop effectively reset the last vectorized iteration.  */
+ /* { dg-final { scan-tree-dump {<bb ([0-9]+)>[^\n\r]*:.+# (a_[0-9]+) = PHI <a_[0-9]+\([0-9]+\).+<bb [0-9]+>[^\n\r]*:.+# a_[0-9]+ = PHI <\2\(\1\)>} "vect" } } */
+ /* { dg-final { scan-tree-dump {<bb ([0-9]+)>[^\n\r]*:.+# (b_[0-9]+) = PHI <b_[0-9]+\([0-9]+\).+<bb [0-9]+>[^\n\r]*:.+# b_[0-9]+ = PHI <\2\(\1\)>} "vect" } } */
+ 
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/vect/vect-uncounted_3.c gcc-16-20251221/gcc/testsuite/gcc.dg/vect/vect-uncounted_3.c
*** gcc-16-20251214/gcc/testsuite/gcc.dg/vect/vect-uncounted_3.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.dg/vect/vect-uncounted_3.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,27 ----
+ /* Test the correct resetting of live out values on epilog loop entry for IV
+    when it's incremented prior to exit taken.  */
+ /* { dg-add-options vect_early_break } */
+ /* { dg-do compile } */
+ /* { dg-require-effective-target vect_early_break } */
+ /* { dg-require-effective-target vect_int } */
+ 
+ extern int N;
+ 
+ int
+ foo (int c[N], int d[N], int a)
+ {
+   int i = 0;
+   while(c[i] != 0)
+     {
+       i += 1;
+       if (d[i] == a)
+ 	break;
+       if (d[i] == 7)
+ 	break;
+     }
+   return i;
+ }
+ 
+ /* { dg-final { scan-tree-dump "Loop being analyzed as uncounted." "vect" } } */
+ /* { dg-final { scan-tree-dump "BIT_FIELD_REF <vect_vec_iv_.\[0-9_\]+, \[0-9\]+, 0>" "vect" } } */
+ /* { dg-final { scan-tree-dump "vectorized 1 loops in function" "vect" } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/vect/vect-uncounted_4.c gcc-16-20251221/gcc/testsuite/gcc.dg/vect/vect-uncounted_4.c
*** gcc-16-20251214/gcc/testsuite/gcc.dg/vect/vect-uncounted_4.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.dg/vect/vect-uncounted_4.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,22 ----
+ /* Check vectorization of uncounted reductions.  */
+ /* { dg-add-options vect_early_break } */
+ /* { dg-do compile } */
+ /* { dg-require-effective-target vect_early_break } */
+ /* { dg-require-effective-target vect_int } */
+ 
+ int
+ foo (int *a0, int *aN, int accum)
+ {
+   int i = 0;
+   while (1)
+     {
+       if (a0[i++] == *aN)
+ 	return accum;
+       accum += a0[i];
+      }
+ }
+ 
+ /* { dg-final { scan-tree-dump "Loop being analyzed as uncounted." "vect" } } */
+ /* { dg-final { scan-tree-dump "Detected reduction." "vect" } } */
+ /* { dg-final { scan-tree-dump "vectorized 1 loops in function" "vect" } } */
+ /* { dg-final { scan-tree-dump {vect_accum_([0-9_.]+) = PHI <vect_accum_[0-9_.]+\([0-9]+\), { (0, )+0 }\([0-9]+\)>.*# vect_accum_[0-9_.]+ = PHI <vect_accum_\1\([0-9]+\)>} "vect" } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/vect/vect-uncounted_5.c gcc-16-20251221/gcc/testsuite/gcc.dg/vect/vect-uncounted_5.c
*** gcc-16-20251214/gcc/testsuite/gcc.dg/vect/vect-uncounted_5.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.dg/vect/vect-uncounted_5.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,20 ----
+ /* Loop with undetermined increment at compile-time is treated as uncounted.  */
+ /* Adapted from pr102572.cc  */
+ /* { dg-add-options vect_early_break } */
+ /* { dg-do compile } */
+ /* { dg-require-effective-target vect_early_break } */
+ /* { dg-require-effective-target vect_int } */
+ 
+ int a, b, c, f;
+ void g(bool h, int d[][5])
+ {
+   int k = 0;
+   for (short i = f; i; i += 1)
+     {
+       a = h && d[0][i];
+       for (int j = 0; j < 4; j += c)
+ 	b++;
+     }
+ }
+ /* { dg-final { scan-tree-dump "Loop being analyzed as uncounted." "vect" } } */
+ /* { dg-final { scan-tree-dump "vectorized 1 loops in function" "vect" } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/vect/vect-uncounted_6.c gcc-16-20251221/gcc/testsuite/gcc.dg/vect/vect-uncounted_6.c
*** gcc-16-20251214/gcc/testsuite/gcc.dg/vect/vect-uncounted_6.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.dg/vect/vect-uncounted_6.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,24 ----
+ /* Check the vectorization of existing testsuite examples  */
+ /* Taken from pr109331.c  */
+ /* { dg-add-options vect_early_break } */
+ /* { dg-do compile } */
+ /* { dg-require-effective-target vect_early_break } */
+ /* { dg-require-effective-target vect_int } */
+ 
+ char *ustol_dpp;
+ void ustol(int flags)
+ {
+   char *s;
+   if (s)
+     flags |= 3;
+   switch (flags & 3)
+   case 3:
+     while (*s)
+     case '+':
+       ++s;
+   if (flags)
+     ustol_dpp = s;
+ }
+ 
+ /* { dg-final { scan-tree-dump "Loop being analyzed as uncounted." "vect" } } */
+ /* { dg-final { scan-tree-dump "vectorized 1 loops in function" "vect" } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.dg/vect/vect-uncounted_7.c gcc-16-20251221/gcc/testsuite/gcc.dg/vect/vect-uncounted_7.c
*** gcc-16-20251214/gcc/testsuite/gcc.dg/vect/vect-uncounted_7.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.dg/vect/vect-uncounted_7.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,24 ----
+ /* Check the vectorization of existing testsuite examples  */
+ /* Taken from pr54824.c  */
+ /* { dg-additional-options "-w" } */
+ /* { dg-add-options vect_early_break } */
+ /* { dg-do compile } */
+ /* { dg-require-effective-target vect_early_break } */
+ /* { dg-require-effective-target vect_int } */
+ 
+ void __attribute__((noreturn)) bar(void)
+ {
+ }
+ 
+ void foo(int i, char *p, char *q)
+ {
+   while (*p++) {
+       if (i)
+ 	p++;
+       if (!*q++)
+ 	bar();
+   }
+ }
+ 
+ /* { dg-final { scan-tree-dump "Loop being analyzed as uncounted." "vect" } } */
+ /* { dg-final { scan-tree-dump "vectorized 1 loops in function" "vect" } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/acle/memtag_1.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/acle/memtag_1.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/acle/memtag_1.c	Sun Dec 14 22:32:11 2025
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/acle/memtag_1.c	Sun Dec 21 22:32:10 2025
*************** test_memtag_6 (void *p)
*** 54,62 ****
    __arm_mte_set_tag (p);
  }
  
! /* { dg-final { scan-assembler-times {irg\tx..?, x..?, x..?\n} 1 } } */
  /* { dg-final { scan-assembler-times {gmi\tx..?, x..?, x..?\n} 1 } } */
  /* { dg-final { scan-assembler-times {subp\tx..?, x..?, x..?\n} 1 } } */
  /* { dg-final { scan-assembler-times {addg\tx..?, x..?, #0, #1\n} 1 } } */
  /* { dg-final { scan-assembler-times {ldg\tx..?, \[x..?, #0\]\n} 1 } } */
! /* { dg-final { scan-assembler-times {stg\tx..?, \[x..?, #0\]\n} 1 } } */
\ No newline at end of file
--- 54,62 ----
    __arm_mte_set_tag (p);
  }
  
! /* { dg-final { scan-assembler-times {irg\tx..?, x..?\n} 1 } } */
  /* { dg-final { scan-assembler-times {gmi\tx..?, x..?, x..?\n} 1 } } */
  /* { dg-final { scan-assembler-times {subp\tx..?, x..?, x..?\n} 1 } } */
  /* { dg-final { scan-assembler-times {addg\tx..?, x..?, #0, #1\n} 1 } } */
  /* { dg-final { scan-assembler-times {ldg\tx..?, \[x..?, #0\]\n} 1 } } */
! /* { dg-final { scan-assembler-times {stg\tx..?, \[x..?\]\n} 1 } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/alloca-1.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/alloca-1.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/alloca-1.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/alloca-1.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,15 ----
+ /* { dg-do compile } */
+ /* { dg-additional-options "-O2" } */
+ 
+ extern int use (int *b);
+ 
+ int foo (int n)
+ {
+   int *b = __builtin_alloca (n);
+   int a = use (b);
+   return a;
+ }
+ 
+ /* { dg-final { scan-assembler-times {\tirg\t} 1 } } */
+ /* { dg-final { scan-assembler-times {\tstg\t...?, \[...?\], 16\n} 2 } } */
+ /* { dg-final { scan-assembler-times {\tst2g\t...?, \[...?\], 32\n} 2 } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/alloca-2.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/alloca-2.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/alloca-2.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/alloca-2.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,15 ----
+ /* { dg-do compile } */
+ /* { dg-additional-options "-O2" } */
+ 
+ /* Check if we handle alloca size zero cases.  */
+ int a, b, c;
+ void foo (void)
+ {
+   int *d = __builtin_alloca (0);
+   for (;; a = b)
+     d[c] = *d;
+ }
+ 
+ /* We check if and only if we tag the 'd' variable.  */
+ /* { dg-final { scan-assembler-times {\tirg\t} 1 } } */
+ /* { dg-final { scan-assembler-times {stg\t...?, \[sp\]\n} 1 } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/alloca-3.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/alloca-3.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/alloca-3.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/alloca-3.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,28 ----
+ /* { dg-do compile } */
+ /* { dg-additional-options "-O2" } */
+ 
+ extern int use (int *b);
+ 
+ extern int n1;
+ extern int n2;
+ extern int n3;
+ 
+ int foo (void)
+ {
+   int *b1 = __builtin_alloca (n1);
+   int *b2 = __builtin_alloca (n2);
+   int *b3 = __builtin_alloca (n3);
+   int a1 = use (b1);
+   int a2 = use (b2);
+   int a3 = use (b3);
+ 
+   return a1 + a2 + a3;
+ }
+ 
+ /* With HWASAN_ALLOCA_POISON now calling irg of its own,  the number of
+    expected irg is 3, and stg/st2g is 4 (3 for tag, 1 for untag each in their
+    respective loop).  */
+ 
+ /* { dg-final { scan-assembler-times {\tirg\t} 3 } } */
+ /* { dg-final { scan-assembler-times {stg\t...?, \[...?\], 16\n} 4 } } */
+ /* { dg-final { scan-assembler-times {st2g\t...?, \[...?\], 32\n} 4 } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/arguments-1.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/arguments-1.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/arguments-1.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/arguments-1.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,3 ----
+ /* { dg-do compile } */
+ /* { dg-additional-options "-fsanitize=kernel-hwaddress" } */
+ /* { dg-error ".*'-fsanitize=memtag-stack' is incompatible with '-fsanitize=kernel-hwaddress'.*" "" { target *-*-* } 0 } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/arguments-2.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/arguments-2.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/arguments-2.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/arguments-2.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,3 ----
+ /* { dg-do compile } */
+ /* { dg-additional-options "-fsanitize=kernel-address" } */
+ /* { dg-error ".*'-fsanitize=memtag-stack' is incompatible with '-fsanitize=kernel-address'.*" "" { target *-*-* } 0 } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/arguments-3.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/arguments-3.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/arguments-3.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/arguments-3.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,3 ----
+ /* { dg-do compile } */
+ /* { dg-additional-options "--param hwasan-random-frame-tag=0" } */
+ /* { dg-warning "is ignored when \'-fsanitize=memtag-stack\' is present" "" { target *-*-* } 0 } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/arguments-4.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/arguments-4.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/arguments-4.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/arguments-4.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,16 ----
+ /* { dg-do compile } */
+ /* { dg-additional-options "-O2 -fno-sanitize=memtag-stack" } */
+ 
+ int use (int * x);
+ 
+ void foo (int n)
+ {
+   int x = 99;
+   use (&x);
+ }
+ 
+ /* { dg-final { scan-assembler-not "\tirg" } } */
+ /* { dg-final { scan-assembler-not "\tstg" } } */
+ /* { dg-final { scan-assembler-not "\tst2g" } } */
+ /* { dg-final { scan-assembler-not "\tsubg" } } */
+ /* { dg-final { scan-assembler-not "\taddg" } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/arguments.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/arguments.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/arguments.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/arguments.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,3 ----
+ /* { dg-do compile } */
+ /* { dg-additional-options "-fsanitize=address" } */
+ /* { dg-error ".*'-fsanitize=memtag-stack' is incompatible with '-fsanitize=address'.*" "" { target *-*-* } 0 } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/basic-1.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/basic-1.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/basic-1.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/basic-1.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,14 ----
+ /* { dg-do compile } */
+ /* { dg-additional-options "-O2" } */
+ 
+ int use (int *x);
+ 
+ void foo (int n)
+ {
+   int x = 99;
+   use (&x);
+ }
+ 
+ /* { dg-final { scan-assembler-times {\tirg\t} 1 } } */
+ /* { dg-final { scan-assembler-times {\tstg\t} 2 } } */
+ /* { dg-final { scan-assembler-not "\taddg" } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/basic-3.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/basic-3.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/basic-3.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/basic-3.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,28 ----
+ /* { dg-do compile } */
+ /* { dg-additional-options "-O2" } */
+ 
+ int use (int *x);
+ 
+ void foo (int n)
+ {
+  int a, b, c;
+  use (&a);
+  use (&b);
+  use (&c);
+ }
+ 
+ /* 3 stack vars need 48 bytes (16 bytes granule x 3).  Each granule holds the
+    local variable stack address (8 bytes), and a padding (8 bytes).  The rest
+    of the stack holds LR and temporary varaibles (i.e., x19, x20, and x29).
+ 
+    Expected: 3 stg to tag, 1 st2g + 1 stg to untag.  */
+ 
+ /* { dg-final { scan-assembler-times {\tirg\t} 1 } } */
+ /* { dg-final { scan-assembler-times {\taddg\t...?} 2 } } */
+ /* { dg-final { scan-assembler-times {\tsubg\t...?} 3 } } */
+ /* { dg-final { scan-assembler-times {\tstg\t...?, \[sp, 48\]\n} 1 } } */
+ /* { dg-final { scan-assembler-times {\tst2g\t...?, \[sp, 32\]\n} 1 } } */
+ /* { dg-final { scan-assembler-times {\tstg\t...?, \[sp, 32\]\n} 1 } } */
+ /* { dg-final { scan-assembler-times {\tstg\t...?, \[sp, 64\]\n} 2 } } */
+ /* { dg-final { scan-assembler-times {\tstp\tx19, x20, \[sp, 16\]\n} 1 } } */
+ /* { dg-final { scan-assembler-times {\tstp\tx29, x30, \[sp, -80]!\n} 1 } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/basic-struct.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/basic-struct.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/basic-struct.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/basic-struct.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,22 ----
+ /* { dg-do compile } */
+ /* { dg-additional-options "-O2" } */
+ 
+ struct A
+ {
+   long a;
+   long b;
+   long c;
+   long d;
+ };
+ 
+ extern void use (struct A *a);
+ 
+ long f (void)
+ {
+   struct A a = {0, 0, 64, (long) &a};
+   use (&a);
+   return a.b;
+ }
+ 
+ /* { dg-final { scan-assembler-times {\tirg\t} 1 } } */
+ /* { dg-final { scan-assembler-times {\tst2g\t} 2 } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/cfi-mte-memtag-frame-1.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/cfi-mte-memtag-frame-1.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/cfi-mte-memtag-frame-1.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/cfi-mte-memtag-frame-1.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,11 ----
+ /* { dg-do compile } */
+ 
+ int use (int *x);
+ 
+ void foo (int n)
+ {
+   int x = 99;
+   use (&x);
+ }
+ 
+ /* { dg-final { scan-assembler-times ".cfi_mte_tagged_frame" 1 } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/large-array.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/large-array.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/large-array.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/large-array.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,23 ----
+ /* { dg-do compile } */
+ /* { dg-additional-options "-O2" } */
+ 
+ #define ARRAY_LEN 12000
+ 
+ int create (void);
+ 
+ void sort (int *data, int n);
+ 
+ void sort_array (void)
+ {
+   int data[ARRAY_LEN], i;
+ 
+   for (i=0; i < ARRAY_LEN; ++i)
+     {
+       data[i] = create ();
+     }
+ 
+   sort (data, ARRAY_LEN);
+ }
+ 
+ /* { dg-final { scan-assembler-times {\tirg\t} 1 } } */
+ /* { dg-final { scan-assembler-times {st2g\t...?, \[...?\], 32\n} 2 } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/local-no-escape.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/local-no-escape.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/local-no-escape.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/local-no-escape.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,22 ----
+ /* { dg-do compile } */
+ /* { dg-additional-options "-O0" } */
+ 
+ /* Local variable 'x' is saved on the stack.  */
+ 
+ extern int use (int *x);
+ extern int bar (int *x);
+ extern int baz (int *x);
+ 
+ int a[10];
+ 
+ int foo (int n)
+ {
+   int x = use (a);
+   if (x)
+     return bar (a);
+   else
+     return baz (a);
+ }
+ 
+ /* { dg-final { scan-assembler-times {\tirg\t} 1 } } */
+ /* { dg-final { scan-assembler-times {\tsubg\t...?} 1 } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/memtag.exp gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/memtag.exp
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/memtag.exp	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/memtag.exp	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,32 ----
+ # Copyright (C) 2025 Free Software Foundation, Inc.
+ 
+ # This program 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 of the License, or
+ # (at your option) any later version.
+ #
+ # This program 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/>.
+ 
+ # GCC testsuite that uses the `dg.exp' driver.
+ 
+ # Load support procs.
+ load_lib gcc-dg.exp
+ 
+ # Initialize `dg'.
+ dg-init
+ 
+ # Main loop.
+ if [check_effective_target_aarch64_mte] {
+   dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cCS\]]] \
+ 	"" "-fsanitize=memtag-stack -march=armv8.5-a+memtag"
+ }
+ 
+ # All done.
+ dg-finish
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/mte-sig.h gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/mte-sig.h
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/mte-sig.h	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/mte-sig.h	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,15 ----
+ #include <stdlib.h>
+ #include <signal.h>
+ #include <string.h>
+ 
+ void handler (int nSig)
+ {
+   /* We hit the exception.  Return error.  */
+   exit (1);
+ }
+ 
+ 
+ static void setHandler (void)
+ {
+   signal (SIGSEGV, handler);
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/no-sanitize-attribute.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/no-sanitize-attribute.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/no-sanitize-attribute.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/no-sanitize-attribute.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,18 ----
+ /* { dg-do compile } */
+ /* { dg-additional-options "-O2" } */
+ 
+ int use (int *x);
+ 
+ __attribute__((no_sanitize("memtag-stack")))
+ void foo (int n)
+ {
+   int x = 99;
+   use (&x);
+ }
+ 
+ /* { dg-final { scan-assembler-not "\tirg" } } */
+ /* { dg-final { scan-assembler-not "\tgmi" } } */
+ /* { dg-final { scan-assembler-not "\tstg" } } */
+ /* { dg-final { scan-assembler-not "\tst2g" } } */
+ /* { dg-final { scan-assembler-not "\tsubg" } } */
+ /* { dg-final { scan-assembler-not "\taddg" } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/texec-1.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/texec-1.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/texec-1.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/texec-1.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,27 ----
+ /* { dg-do run { xfail *-*-* } } */
+ /* { dg-require-effective-target memtag_exec } */
+ /* { dg-additional-options "-O2" } */
+ 
+ #include "mte-sig.h"
+ 
+ void  __attribute__((noinline))
+ use (volatile unsigned char *ptr)
+ {
+   ptr[0] = 0x41;
+   ptr[1] = 0x42;
+ }
+ 
+ int main(void)
+ {
+   volatile unsigned char array[15];
+   volatile unsigned char *ptr = &array[0];
+ 
+   setHandler();
+   use (ptr);
+ 
+   /* Write to memory beyond the 16 byte granule (offsest 0x10) MTE should
+      generate an exception If the offset is less than 0x10 no SIGSEGV will
+      occur.  */
+   ptr[0x10] = 0x55;
+   return 0;
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/texec-2.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/texec-2.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/texec-2.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/texec-2.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,22 ----
+ /* { dg-do run { xfail *-*-* } } */
+ /* { dg-require-effective-target memtag_exec } */
+ /* { dg-additional-options "-O2" } */
+ #include "mte-sig.h"
+ 
+ void  __attribute__((noinline))
+ use (volatile unsigned char *ptr)
+ {
+   ptr[0] = 0x41;
+   ptr[1] = 0x42;
+ }
+ 
+ int main (void)
+ {
+   volatile unsigned char *ptr = __builtin_alloca (15);
+ 
+   setHandler();
+ 
+   use (ptr);
+   ptr[0x10] = 0x55;
+   return 0;
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/texec-3.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/texec-3.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/texec-3.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/texec-3.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,37 ----
+ /* { dg-do run { xfail *-*-* } } */
+ /* { dg-require-effective-target memtag_exec } */
+ /* { dg-require-effective-target pthread } */
+ /* { dg-additional-options "-O2 -pthread" } */
+ #include "mte-sig.h"
+ #include <pthread.h>
+ 
+ void  __attribute__((noinline))
+ use (volatile unsigned char *ptr)
+ {
+   ptr[0] = 0x41;
+   ptr[1] = 0x42;
+ }
+ 
+ /* The thread in which we allocate and then we try to read out of the
+    allocation pool.  */
+ void *thread_test (void *)
+ {
+   volatile unsigned char *ptr = __builtin_alloca (15);
+ 
+   setHandler();
+ 
+   use (ptr);
+   ptr[0x10] = 0x55;
+   return 0;
+ }
+ 
+ 
+ int main (void)
+ {
+   pthread_t thread;
+   pthread_create (&thread, NULL, thread_test, NULL);
+   pthread_join (thread, NULL);
+   __builtin_printf ("End of line\n");
+ 
+   return 0;
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/value-init.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/value-init.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/value-init.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/value-init.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,14 ----
+ /* { dg-do compile } */
+ /* { dg-additional-options "-O2" } */
+ 
+ void use (int *);
+ 
+ void foo (void)
+ {
+   int x = 42;
+   use(&x);
+ }
+ 
+ /* { dg-final { scan-assembler-times {\tirg\t} 1 } } */
+ /* { dg-final { scan-assembler-times {stg\t...?, \[sp, 16\]\n} 2 } } */
+ 
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/vararray-gimple.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/vararray-gimple.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/vararray-gimple.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/vararray-gimple.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,16 ----
+ /* { dg-do compile } */
+ /* { dg-additional-options "-fdump-tree-asan -O2" } */
+ 
+ extern int *use (int *b, int n);
+ 
+ int *foo (int n)
+ {
+   int b[n];
+   return use (b, n);
+ }
+ 
+ /* HWASAN_ALLOCA_POISON is used for alloca and VLAs when MEMTAG is in effect.
+    Although HWASAN_ALLOCA_UNPOISON is (also) used for untagging frame, it
+    doesnt hurt to check it in context of the current test.  */
+ /* { dg-final { scan-tree-dump "HWASAN_ALLOCA_POISON" "asan1" } } */
+ /* { dg-final { scan-tree-dump "HWASAN_ALLOCA_UNPOISON" "asan1" } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/vararray.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/vararray.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/vararray.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/vararray.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,15 ----
+ /* { dg-do compile } */
+ /* { dg-additional-options "-O2" } */
+ 
+ extern int *use (int *b, int n);
+ 
+ int *foo (int n)
+ {
+   int b[n];
+   return use (b, n);
+ }
+ 
+ /* { dg-final { scan-assembler-times {\tirg\t} 1 } } */
+ /* { dg-final { scan-assembler-times {stg\t...?, \[...?\], 16\n} 3 } } */
+ /* { dg-final { scan-assembler-times {st2g\t...?, \[...?\], 32\n} 3 } } */
+ /* { dg-final { scan-assembler-times {\taddg\t} 0 } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/vla-1.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/vla-1.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/vla-1.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/vla-1.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,39 ----
+ /* { dg-do run } */
+ /* { dg-require-effective-target memtag_exec } */
+ /* { dg-additional-options "-O2" } */
+ 
+ #include <string.h>
+ #include "mte-sig.h"
+ 
+ void
+ bar (int i, char *b)
+ {
+   __builtin_printf ("i = %d, b+i = %s \n", i, b + i);
+ }
+ 
+ void
+ foo (int size)
+ {
+   int i;
+   for (i = 0; i < size; i++)
+     {
+       char temp[size];
+       memset (temp, 'B', size);
+       temp[size-1] = '\0';
+       {
+ 	char temp2[size];
+ 	memset (temp2, 'A', size);
+ 	temp2[size-1] = '\0';
+ 	bar (i, temp2);
+       }
+       bar (i, temp);
+     }
+ }
+ 
+ int main (void)
+ {
+   setHandler ();
+   foo (10);
+   foo (3);
+   return 0;
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/vla-2.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/vla-2.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/vla-2.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/vla-2.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,48 ----
+ 
+ /* { dg-do run { xfail *-*-* } } */
+ /* { dg-require-effective-target memtag_exec } */
+ /* { dg-additional-options "-O2" } */
+ 
+ #include "mte-sig.h"
+ 
+ /* Testing that a function with outgoing arguments correctly decrements the
+    stack pointer when a vararray goes out of scope.  */
+ 
+ const char * __attribute__((noinline))
+ other (int argc, int a, int b, int c, int d, int e, int f,
+        int g, int h, int i, int j, int k, int l)
+ {
+   const char ** other;
+     {
+       const char * test_array[argc];
+       test_array[0] = "test string";
+       test_array[argc - 1] = "hello";
+       /* To prevent optimisation.  */
+       __builtin_printf ("While the value stored in our test_array is: %s\n",
+ 			test_array[argc - 1]);
+       other = test_array;
+     }
+   /* With the below function call (the one with many arguments), some of the
+      arguments have to be put on the stack, which means we have to reserve some
+      space on the stack for these arguments and that the VLA is stored at a
+      position that is not the stack pointer. */
+   __builtin_printf ("Our numbers today are: %d, %d, %d, %d, %d, %d, %d, %d, \
+ %d, %d, %d, %d\n",
+ 		    a, b, c, d, e, f, g, h, i, j, k, l);
+   /* This should fail due to a bad read access.  */
+   return other[0];
+ }
+ 
+ int
+ main (void)
+ {
+   int a, b, c, d, e, f, g, h, i, j, k, l;
+ 
+   setHandler();
+   const char * retval = other (1, a, b, c, d, e, f, g, h, i, j, k, l);
+   /* Numbers don't matter here, just want to ensure the program is reading them
+      so we know they won't be optimised out.  */
+   if (retval)
+     return 1;
+   return 0;
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/zero-init.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/zero-init.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/memtag/zero-init.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/memtag/zero-init.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,14 ----
+ /* { dg-do compile } */
+ /* { dg-additional-options "-O2" } */
+ 
+ void use (int *);
+ 
+ void foo (void)
+ {
+   int x = 0;
+   use (&x);
+ }
+ 
+ /* { dg-final { scan-assembler-times {\tirg\t} 1 } } */
+ /* { dg-final { scan-assembler-times {stg\t...?, \[sp, 16\]\n} 2 } } */
+ 
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/options_set_30.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/options_set_30.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/options_set_30.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/options_set_30.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,10 ----
+ /* { dg-do compile } */
+ /* { dg-additional-options "-march=armv8-a+sve2+sve-aes+sve-bitperm+sve-sm4+sve-sha3" } */
+ 
+ int main ()
+ {
+   return 0;
+ }
+ 
+ /* Make sure we prefer the sve2-X aliases over sve-X. */
+ /* { dg-final { scan-assembler {\.arch armv8-a\+sve2-aes\+sve2-bitperm\+sve2-sha3\+sve2-sm4\n} } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/pragma_cpp_predefs_5.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/pragma_cpp_predefs_5.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/pragma_cpp_predefs_5.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/pragma_cpp_predefs_5.c	Sun Dec 21 22:32:10 2025
***************
*** 0 ****
--- 1,221 ----
+ /* { dg-do assemble { target { { aarch64_asm_sve-sm4_ok && aarch64_asm_sve-sha3_ok } && { aarch64_asm_sve-aes_ok && aarch64_asm_sve-bitperm_ok } } } } */
+ /* { dg-do compile { target { ! { { aarch64_asm_sve-sm4_ok && aarch64_asm_sve-sha3_ok } && { aarch64_asm_sve-aes_ok && aarch64_asm_sve-bitperm_ok } } } } } */
+ /* { dg-options "-O2" } */
+ 
+ #pragma GCC push_options
+ #pragma GCC target ("arch=armv8-a")
+ 
+ #ifdef __ARM_FEATURE_SVE
+ #error "__ARM_FEATURE_SVE is defined but should not be!"
+ #endif
+ 
+ #ifdef __ARM_FEATURE_SVE2
+ #error "__ARM_FEATURE_SVE2 is defined but should not be!"
+ #endif
+ 
+ #ifdef __ARM_FEATURE_AES
+ #error "__ARM_FEATURE_AES is defined but should not be!"
+ #endif
+ 
+ #ifdef __ARM_FEATURE_SVE2_AES
+ #error "__ARM_FEATURE_SVE2_AES is defined but should not be!"
+ #endif
+ 
+ #ifdef __ARM_FEATURE_SVE2_BitPerm
+ #error "__ARM_FEATURE_SVE2_BitPerm is defined but should not be!"
+ #endif
+ 
+ #ifdef __ARM_FEATURE_SM4
+ #error "__ARM_FEATURE_SM4 is defined but should not be!"
+ #endif
+ 
+ #ifdef __ARM_FEATURE_SVE2_SM4
+ #error "__ARM_FEATURE_SVE2_SM4 is defined but should not be!"
+ #endif
+ 
+ #ifdef __ARM_FEATURE_SHA3
+ #error "__ARM_FEATURE_SHA3 is defined but should not be!"
+ #endif
+ 
+ #ifdef __ARM_FEATURE_SVE2_SHA3
+ #error "__ARM_FEATURE_SVE2_SHA3 is defined but should not be!"
+ #endif
+ 
+ #pragma GCC pop_options
+ 
+ #pragma GCC push_options
+ #pragma GCC target ("arch=armv8-a+sve-bitperm")
+ 
+ #ifdef __ARM_FEATURE_SVE
+ #error "__ARM_FEATURE_SVE is defined but should not be!"
+ #endif
+ 
+ #ifdef __ARM_FEATURE_SVE2
+ #error "__ARM_FEATURE_SVE2 is defined but should not be!"
+ #endif
+ 
+ #ifdef __ARM_FEATURE_SVE2_BitPerm
+ #error "__ARM_FEATURE_SVE2_BitPerm is defined but should not be!"
+ #endif
+ 
+ #pragma GCC pop_options
+ 
+ #pragma GCC push_options
+ #pragma GCC target ("arch=armv8-a+sve2-bitperm")
+ 
+ #ifndef __ARM_FEATURE_SVE
+ #error "__ARM_FEATURE_SVE is not defined but should be!"
+ #endif
+ 
+ #ifndef __ARM_FEATURE_SVE2
+ #error "__ARM_FEATURE_SVE2 is not defined but should be!"
+ #endif
+ 
+ #ifndef __ARM_FEATURE_SVE2_BITPERM
+ #error "__ARM_FEATURE_SVE2_BITPERM is not defined but should be!"
+ #endif
+ 
+ #pragma GCC pop_options
+ 
+ #pragma GCC push_options
+ #pragma GCC target ("arch=armv8-a+sve2+sve-bitperm")
+ 
+ #ifndef __ARM_FEATURE_SVE
+ #error "__ARM_FEATURE_SVE is not defined but should be!"
+ #endif
+ 
+ #ifndef __ARM_FEATURE_SVE2
+ #error "__ARM_FEATURE_SVE2 is not defined but should be!"
+ #endif
+ 
+ #ifndef __ARM_FEATURE_SVE2_BITPERM
+ #error "__ARM_FEATURE_SVE2_BITPERMis not defined but should be!"
+ #endif
+ 
+ #pragma GCC push_options
+ #pragma GCC target ("arch=armv8-a+sve-sha3")
+ 
+ #ifdef __ARM_FEATURE_SVE
+ #error "__ARM_FEATURE_SVE is defined but should not be!"
+ #endif
+ 
+ #ifdef __ARM_FEATURE_SVE2
+ #error "__ARM_FEATURE_SVE2 is defined but should not be!"
+ #endif
+ 
+ #ifndef __ARM_FEATURE_SHA3
+ #error "__ARM_FEATURE_SHA3 is not defined but should be!"
+ #endif
+ 
+ #ifdef __ARM_FEATURE_SVE2_SHA3
+ #error "__ARM_FEATURE_SVE2_SHA3 is defined but should not be!"
+ #endif
+ 
+ #pragma GCC pop_options
+ 
+ #pragma GCC push_options
+ #pragma GCC target ("arch=armv8-a+sve2-sha3")
+ 
+ #ifndef __ARM_FEATURE_SVE
+ #error "__ARM_FEATURE_SVE is not defined but should be!"
+ #endif
+ 
+ #ifndef __ARM_FEATURE_SVE2
+ #error "__ARM_FEATURE_SVE2 is not defined but should be!"
+ #endif
+ 
+ #ifndef __ARM_FEATURE_SHA3
+ #error "__ARM_FEATURE_SHA3 is not defined but should be!"
+ #endif
+ 
+ #ifndef __ARM_FEATURE_SVE2_SHA3
+ #error "__ARM_FEATURE_SVE2_SHA3 is not defined but should be!"
+ #endif
+ 
+ #pragma GCC pop_options
+ 
+ #pragma GCC push_options
+ #pragma GCC target ("arch=armv8-a+sve2+sve-sha3")
+ 
+ #ifndef __ARM_FEATURE_SVE
+ #error "__ARM_FEATURE_SVE is not defined but should be!"
+ #endif
+ 
+ #ifndef __ARM_FEATURE_SVE2
+ #error "__ARM_FEATURE_SVE2 is not defined but should be!"
+ #endif
+ 
+ #ifndef __ARM_FEATURE_SHA3
+ #error "__ARM_FEATURE_SHA3 is not defined but should be!"
+ #endif
+ 
+ #ifndef __ARM_FEATURE_SVE2_SHA3
+ #error "__ARM_FEATURE_SVE2_SHA3 is not defined but should be!"
+ #endif
+ #pragma GCC push_options
+ #pragma GCC target ("arch=armv8-a+sve-aes")
+ 
+ #ifdef __ARM_FEATURE_SVE
+ #error "__ARM_FEATURE_SVE is defined but should not be!"
+ #endif
+ 
+ #ifdef __ARM_FEATURE_SVE2
+ #error "__ARM_FEATURE_SVE2 is defined but should not be!"
+ #endif
+ 
+ #ifndef __ARM_FEATURE_AES
+ #error "__ARM_FEATURE_AES is not defined but should be!"
+ #endif
+ 
+ #ifdef __ARM_FEATURE_SVE2_AES
+ #error "__ARM_FEATURE_SVE2_AES is defined but should not be!"
+ #endif
+ 
+ #pragma GCC pop_options
+ 
+ #pragma GCC push_options
+ #pragma GCC target ("arch=armv8-a+sve2-aes")
+ 
+ #ifndef __ARM_FEATURE_SVE
+ #error "__ARM_FEATURE_SVE is not defined but should be!"
+ #endif
+ 
+ #ifndef __ARM_FEATURE_SVE2
+ #error "__ARM_FEATURE_SVE2 is not defined but should be!"
+ #endif
+ 
+ #ifndef __ARM_FEATURE_AES
+ #error "__ARM_FEATURE_AES is not defined but should be!"
+ #endif
+ 
+ #ifndef __ARM_FEATURE_SVE2_AES
+ #error "__ARM_FEATURE_SVE2_AES is not defined but should be!"
+ #endif
+ 
+ #pragma GCC pop_options
+ 
+ #pragma GCC push_options
+ #pragma GCC target ("arch=armv8-a+sve2+sve-aes")
+ 
+ #ifndef __ARM_FEATURE_SVE
+ #error "__ARM_FEATURE_SVE is not defined but should be!"
+ #endif
+ 
+ #ifndef __ARM_FEATURE_SVE2
+ #error "__ARM_FEATURE_SVE2 is not defined but should be!"
+ #endif
+ 
+ #ifndef __ARM_FEATURE_AES
+ #error "__ARM_FEATURE_AES is not defined but should be!"
+ #endif
+ 
+ #ifndef __ARM_FEATURE_SVE2_AES
+ #error "__ARM_FEATURE_SVE2_AES is not defined but should be!"
+ #endif
+ #pragma GCC pop_options
+ 
+ int
+ foo (int a)
+ {
+   return a;
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_1.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_1.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_1.c	Sun Dec 14 22:32:12 2025
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_1.c	Sun Dec 21 22:32:11 2025
***************
*** 10,15 ****
--- 10,19 ----
  #error "__ARM_FEATURE_SVE_VECTOR_OPERATORS should be equal to 1"
  #endif
  
+ #if __ARM_FEATURE_SVE_PREDICATE_OPERATORS != 1
+ #error "__ARM_FEATURE_SVE_PREDICATE_OPERATORS should be equal to 1"
+ #endif
+ 
  #ifndef __cplusplus
  #define alignof _Alignof
  #endif
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_9.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_9.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_9.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_9.c	Sun Dec 21 22:32:11 2025
***************
*** 0 ****
--- 1,9 ----
+ #include <arm_sve.h>
+ 
+ #if __ARM_FEATURE_SVE_VECTOR_OPERATORS != 2
+ #error "__ARM_FEATURE_SVE_VECTOR_OPERATORS should be equal to 2"
+ #endif
+ 
+ #if __ARM_FEATURE_SVE_PREDICATE_OPERATORS != 2
+ #error "__ARM_FEATURE_SVE_PREDICATE_OPERATORS should be equal to 2"
+ #endif
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_14.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_14.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_14.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_14.c	Sun Dec 21 22:32:11 2025
***************
*** 0 ****
--- 1,24 ----
+ /* Fix for PR123089 alignment peeling with vectors and VLS and overflows.  */
+ /* { dg-do compile } */
+ /* { dg-options "-Ofast --param aarch64-autovec-preference=sve-only -fdump-tree-vect-details" } */
+ /* { dg-additional-options "-msve-vector-bits=256" { target aarch64_sve256_hw } } */
+ /* { dg-additional-options "-msve-vector-bits=128" { target aarch64_sve128_hw } } */
+ 
+ /* { dg-final { scan-tree-dump "loop vectorized" "vect" } } */
+ 
+ #define START 2
+ 
+ int __attribute__((noipa))
+ foo (unsigned char n, int *x)
+ {
+   unsigned char i = 0;
+ #pragma GCC unroll 0
+   for (i = START; i < n; ++i)
+     {
+       if (x[i] == 0)
+         return i;
+       x[i] += 1;
+     }
+   return i;
+ }
+ 
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_14_run.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_14_run.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_14_run.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_14_run.c	Sun Dec 21 22:32:11 2025
***************
*** 0 ****
--- 1,42 ----
+ /* Fix for PR123089 alignment peeling with vectors and VLS and overflows.  */
+ /* { dg-do run { target aarch64_sve_hw } } */
+ /* { dg-options "-Ofast --param aarch64-autovec-preference=sve-only" } */
+ /* { dg-additional-options "-msve-vector-bits=256" { target aarch64_sve256_hw } } */
+ /* { dg-additional-options "-msve-vector-bits=128" { target aarch64_sve128_hw } } */
+ 
+ #define START 2
+ 
+ int __attribute__((noipa))
+ foo (unsigned char n, int *x)
+ {
+   unsigned char i = 0;
+ #pragma GCC unroll 0
+   for (i = START; i < n; ++i)
+     {
+       if (x[i] == 0)
+         return i;
+       x[i] += 1;
+     }
+   return i;
+ }
+ 
+ int main ()
+ {
+    int max = 255 - START;
+    int x[255 - START];
+ #pragma GCC unroll 0
+    for (int i = 0; i < max; i++)
+      x[i] = 1;
+ 
+    x[200] = 0;
+    int res = foo (max, x);
+    if (res != 200)
+      __builtin_abort ();
+ 
+    if (x[START] != 2)
+      __builtin_abort ();
+ 
+    if (x[0] != 1)
+      __builtin_abort ();
+    return 0;
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_15.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_15.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_15.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_15.c	Sun Dec 21 22:32:11 2025
***************
*** 0 ****
--- 1,24 ----
+ /* Fix for PR123089 alignment peeling with vectors and VLS and overflows.  */
+ /* { dg-do compile } */
+ /* { dg-options "-Ofast --param aarch64-autovec-preference=sve-only -fdump-tree-vect-details" } */
+ /* { dg-additional-options "-msve-vector-bits=256" { target aarch64_sve256_hw } } */
+ /* { dg-additional-options "-msve-vector-bits=128" { target aarch64_sve128_hw } } */
+ 
+ /* { dg-final { scan-tree-dump "loop vectorized" "vect" } } */
+ 
+ #define START 2
+ 
+ int __attribute__((noipa))
+ foo (unsigned char n, int *x)
+ {
+   unsigned char i = 0;
+ #pragma GCC unroll 0
+   for (i = START; i < n; ++i)
+     {
+       if (x[i] == 0)
+         return i;
+       x[i] += 1;
+     }
+   return i;
+ }
+ 
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_15_run.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_15_run.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_15_run.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_15_run.c	Sun Dec 21 22:32:11 2025
***************
*** 0 ****
--- 1,42 ----
+ /* Fix for PR123089 alignment peeling with vectors and VLS and overflows.  */
+ /* { dg-do run { target aarch64_sve_hw } } */
+ /* { dg-options "-Ofast --param aarch64-autovec-preference=sve-only" } */
+ /* { dg-additional-options "-msve-vector-bits=256" { target aarch64_sve256_hw } } */
+ /* { dg-additional-options "-msve-vector-bits=128" { target aarch64_sve128_hw } } */
+ 
+ #define START 2
+ 
+ int __attribute__((noipa))
+ foo (unsigned char n, int *x)
+ {
+   unsigned char i = 0;
+ #pragma GCC unroll 0
+   for (i = START; i < n; ++i)
+     {
+       if (x[i] == 0)
+         return i;
+       x[i] += 1;
+     }
+   return i;
+ }
+ 
+ int main ()
+ {
+    int max = 255 - START;
+    int x[255 - START];
+ #pragma GCC unroll 0
+    for (int i = 0; i < max; i++)
+      x[i] = 1;
+ 
+    x[33] = 0;
+    int res = foo (max, x);
+    if (res != 33)
+      __builtin_abort ();
+ 
+    if (x[START] != 2)
+      __builtin_abort ();
+ 
+    if (x[0] != 1)
+      __builtin_abort ();
+    return 0;
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_16.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_16.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_16.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_16.c	Sun Dec 21 22:32:11 2025
***************
*** 0 ****
--- 1,24 ----
+ /* Fix for PR123089 alignment peeling with vectors and VLS and overflows.  */
+ /* { dg-do compile } */
+ /* { dg-options "-Ofast --param aarch64-autovec-preference=sve-only -fdump-tree-vect-details" } */
+ /* { dg-additional-options "-msve-vector-bits=256" { target aarch64_sve256_hw } } */
+ /* { dg-additional-options "-msve-vector-bits=128" { target aarch64_sve128_hw } } */
+ 
+ /* { dg-final { scan-tree-dump "loop vectorized" "vect" } } */
+ 
+ #define START 2
+ 
+ int __attribute__((noipa))
+ foo (unsigned char n, int *x)
+ {
+   unsigned char i = 0;
+ #pragma GCC unroll 0
+   for (i = START; i < n; ++i)
+     {
+       if (x[i] == 0)
+         return i;
+       x[i] += 1;
+     }
+   return i;
+ }
+ 
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_16_run.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_16_run.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_16_run.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_16_run.c	Sun Dec 21 22:32:11 2025
***************
*** 0 ****
--- 1,41 ----
+ /* Fix for PR123089 alignment peeling with vectors and VLS and overflows.  */
+ /* { dg-do run { target aarch64_sve_hw } } */
+ /* { dg-options "-Ofast --param aarch64-autovec-preference=sve-only" } */
+ /* { dg-additional-options "-msve-vector-bits=256" { target aarch64_sve256_hw } } */
+ /* { dg-additional-options "-msve-vector-bits=128" { target aarch64_sve128_hw } } */
+ 
+ #define START 2
+ 
+ int __attribute__((noipa))
+ foo (unsigned char n, int *x)
+ {
+   unsigned char i = 0;
+ #pragma GCC unroll 0
+   for (i = START; i < n; ++i)
+     {
+       if (x[i] == 0)
+         return i;
+       x[i] += 1;
+     }
+   return i;
+ }
+ 
+ int main ()
+ {
+    int max = 255 - START;
+    int x[255 - START];
+ #pragma GCC unroll 0
+    for (int i = 0; i < max; i++)
+      x[i] = 1;
+ 
+    int res = foo (max, x);
+    if (res != max)
+      __builtin_abort ();
+ 
+    if (x[START] != 2)
+      __builtin_abort ();
+ 
+    if (x[0] != 1)
+      __builtin_abort ();
+    return 0;
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_17.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_17.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_17.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_17.c	Sun Dec 21 22:32:11 2025
***************
*** 0 ****
--- 1,24 ----
+ /* Fix for PR123089 alignment peeling with vectors and VLS and overflows.  */
+ /* { dg-do compile } */
+ /* { dg-options "-Ofast --param aarch64-autovec-preference=sve-only  -fdump-tree-vect-details" } */
+ /* { dg-additional-options "-msve-vector-bits=256" { target aarch64_sve256_hw } } */
+ /* { dg-additional-options "-msve-vector-bits=128" { target aarch64_sve128_hw } } */
+ 
+ /* { dg-final { scan-tree-dump "loop vectorized" "vect" } } */
+ 
+ #define START 2
+ 
+ int __attribute__((noipa))
+ foo (int *x)
+ {
+   unsigned long i = 0;
+ #pragma GCC unroll 0
+   for (i = START; i < 253; ++i)
+     {
+       if (x[i] == 0)
+         return i;
+       x[i] += 1;
+     }
+   return i;
+ }
+ 
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_17_run.c gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_17_run.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_17_run.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_17_run.c	Sun Dec 21 22:32:11 2025
***************
*** 0 ****
--- 1,41 ----
+ /* Fix for PR123089 alignment peeling with vectors and VLS and overflows.  */
+ /* { dg-do run { target aarch64_sve_hw } } */
+ /* { dg-options "-Ofast --param aarch64-autovec-preference=sve-only" } */
+ /* { dg-additional-options "-msve-vector-bits=256" { target aarch64_sve256_hw } } */
+ /* { dg-additional-options "-msve-vector-bits=128" { target aarch64_sve128_hw } } */
+ 
+ #define START 2
+ 
+ int __attribute__((noipa))
+ foo (int *x)
+ {
+   unsigned int i = 0;
+ #pragma GCC unroll 0
+   for (i = START; i < 253; ++i)
+     {
+       if (x[i] == 0)
+         return i;
+       x[i] += 1;
+     }
+   return i;
+ }
+ 
+ int main ()
+ {
+    int x[255 - START];
+ #pragma GCC unroll 0
+    for (int i = 0; i < 253; i++)
+      x[i] = 1;
+ 
+    x[200] = 0;
+    int res = foo (x);
+    if (res != 200)
+      __builtin_abort ();
+ 
+    if (x[START] != 2)
+      __builtin_abort ();
+ 
+    if (x[0] != 1)
+      __builtin_abort ();
+    return 0;
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/i386/avx512bmm-1.c gcc-16-20251221/gcc/testsuite/gcc.target/i386/avx512bmm-1.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/i386/avx512bmm-1.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/i386/avx512bmm-1.c	Sun Dec 21 22:32:11 2025
***************
*** 0 ****
--- 1,26 ----
+ /* { dg-do compile } */
+ /* { dg-options "-mavx512bmm -O2" } */
+ /* { dg-final { scan-assembler-times "vbmacor16x16x16\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */
+ /* { dg-final { scan-assembler-times "vbmacxor16x16x16\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */
+ /* { dg-final { scan-assembler-times "vbitrevb\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+(?:\n|\[ \\t\]+#)"  1 } } */
+ /* { dg-final { scan-assembler-times "vbitrevb\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */
+ /* { dg-final { scan-assembler-times "vbitrevb\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */
+ 
+ #include <immintrin.h>
+ 
+ volatile __m512i x,y,z;
+ volatile __mmask64 m;
+ 
+ __m512i extern
+ avx512bmm_test (void)
+ {
+   x = _mm512_bmacor16x16x16 (x, y, z);
+ 
+   x = _mm512_bmacxor16x16x16 (x, y, z);
+ 
+   x = _mm512_bitrev_epi8 (x);
+ 
+   x = _mm512_mask_bitrev_epi8 (m, x, y);
+ 
+   x = _mm512_maskz_bitrev_epi8 (m, x);
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/i386/avx512bmmvl-1.c gcc-16-20251221/gcc/testsuite/gcc.target/i386/avx512bmmvl-1.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/i386/avx512bmmvl-1.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/i386/avx512bmmvl-1.c	Sun Dec 21 22:32:11 2025
***************
*** 0 ****
--- 1,35 ----
+ /* { dg-do compile } */
+ /* { dg-options "-mavx512bmm -mavx512vl -O2" } */
+ /* { dg-final { scan-assembler-times "vbmacor16x16x16\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */
+ /* { dg-final { scan-assembler-times "vbmacxor16x16x16\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */
+ /* { dg-final { scan-assembler-times "vbitrevb\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)"  1 } } */
+ /* { dg-final { scan-assembler-times "vbitrevb\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)"  1 } } */
+ /* { dg-final { scan-assembler-times "vbitrevb\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */
+ /* { dg-final { scan-assembler-times "vbitrevb\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */
+ /* { dg-final { scan-assembler-times "vbitrevb\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */
+ /* { dg-final { scan-assembler-times "vbitrevb\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */
+ 
+ 
+ #include <immintrin.h>
+ 
+ volatile __m256i x,y,z;
+ volatile __m128i x_,y_,z_;
+ volatile __mmask32 m;
+ volatile __mmask16 m_;
+ 
+ void extern
+ avx512bmm_test (void)
+ {
+   x = _mm256_bmacor16x16x16 (x, y, z);
+ 
+   x = _mm256_bmacxor16x16x16 (x, y, z);
+ 
+   x = _mm256_mask_bitrev_epi8 (m, x, y);
+   x_ = _mm128_mask_bitrev_epi8 (m_, x_, y_);
+ 
+   x = _mm256_maskz_bitrev_epi8 (m, y);
+   x_ = _mm128_maskz_bitrev_epi8 (m_, y_);
+ 
+   x = _mm256_bitrev_epi8 (x);
+   x_ = _mm128_bitrev_epi8 (x_);
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/i386/funcspec-56.inc gcc-16-20251221/gcc/testsuite/gcc.target/i386/funcspec-56.inc
*** gcc-16-20251214/gcc/testsuite/gcc.target/i386/funcspec-56.inc	Sun Dec 14 22:32:12 2025
--- gcc-16-20251221/gcc/testsuite/gcc.target/i386/funcspec-56.inc	Sun Dec 21 22:32:11 2025
*************** extern void test_arch_znver2 (void)
*** 238,243 ****
--- 238,244 ----
  extern void test_arch_znver3 (void)             __attribute__((__target__("arch=znver3")));
  extern void test_arch_znver4 (void)             __attribute__((__target__("arch=znver4")));
  extern void test_arch_znver5 (void)             __attribute__((__target__("arch=znver5")));
+ extern void test_arch_znver6 (void)             __attribute__((__target__("arch=znver6")));
  
  extern void test_tune_nocona (void)		__attribute__((__target__("tune=nocona")));
  extern void test_tune_core2 (void)		__attribute__((__target__("tune=core2")));
*************** extern void test_tune_znver2 (void)
*** 265,270 ****
--- 266,272 ----
  extern void test_tune_znver3 (void)             __attribute__((__target__("tune=znver3")));
  extern void test_tune_znver4 (void)             __attribute__((__target__("tune=znver4")));
  extern void test_tune_znver5 (void)             __attribute__((__target__("tune=znver5")));
+ extern void test_tune_znver6 (void)             __attribute__((__target__("tune=znver6")));
  
  extern void test_fpmath_sse (void)		__attribute__((__target__("sse2,fpmath=sse")));
  extern void test_fpmath_387 (void)		__attribute__((__target__("sse2,fpmath=387")));
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/i386/keylocker-pr123217.c gcc-16-20251221/gcc/testsuite/gcc.target/i386/keylocker-pr123217.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/i386/keylocker-pr123217.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/i386/keylocker-pr123217.c	Sun Dec 21 22:32:11 2025
***************
*** 0 ****
--- 1,13 ----
+ /* PR target/123217 */
+ /* { dg-do compile } */
+ /* { dg-options "-mkl -O0" } */
+ 
+ __attribute__((__vector_size__(16))) long long v, w;
+ 
+ unsigned
+ foo (void *p, void *q)
+ {
+   unsigned x = __builtin_ia32_encodekey128_u32 (0U, v, p);
+   unsigned y = __builtin_ia32_encodekey256_u32 (0U, v, w, q);
+   return x + y;
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/i386/pr120881-1a.c gcc-16-20251221/gcc/testsuite/gcc.target/i386/pr120881-1a.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/i386/pr120881-1a.c	Sun Dec 14 22:32:13 2025
--- gcc-16-20251221/gcc/testsuite/gcc.target/i386/pr120881-1a.c	Sun Dec 21 22:32:11 2025
***************
*** 1,4 ****
! /* { dg-do compile { target fpic } } */
  /* { dg-require-profiling "-pg" } */
  /* { dg-options "-O2 -pg -mno-fentry -fno-pic" } */
  /* { dg-message "'-pg' without '-mfentry' may be unreliable with shrink wrapping" "" { target *-*-* } 0 } */
--- 1,4 ----
! /* { dg-do compile { target { *-*-linux* && fpic } } } */
  /* { dg-require-profiling "-pg" } */
  /* { dg-options "-O2 -pg -mno-fentry -fno-pic" } */
  /* { dg-message "'-pg' without '-mfentry' may be unreliable with shrink wrapping" "" { target *-*-* } 0 } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/i386/pr120881-1b.c gcc-16-20251221/gcc/testsuite/gcc.target/i386/pr120881-1b.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/i386/pr120881-1b.c	Sun Dec 14 22:32:13 2025
--- gcc-16-20251221/gcc/testsuite/gcc.target/i386/pr120881-1b.c	Sun Dec 21 22:32:11 2025
***************
*** 1,4 ****
! /* { dg-do compile { target { fpic && { ! ia32 } } } } */
  /* { dg-require-profiling "-pg" } */
  /* { dg-options "-O2 -pg -mno-fentry -fpic" } */
  /* { dg-message "'-pg' without '-mfentry' may be unreliable with shrink wrapping" "" { target *-*-* } 0 } */
--- 1,4 ----
! /* { dg-do compile { target { { *-*-linux* && { ! ia32 } } && fpic } } } */
  /* { dg-require-profiling "-pg" } */
  /* { dg-options "-O2 -pg -mno-fentry -fpic" } */
  /* { dg-message "'-pg' without '-mfentry' may be unreliable with shrink wrapping" "" { target *-*-* } 0 } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/i386/pr121572-1a.c gcc-16-20251221/gcc/testsuite/gcc.target/i386/pr121572-1a.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/i386/pr121572-1a.c	Sun Dec 14 22:32:13 2025
--- gcc-16-20251221/gcc/testsuite/gcc.target/i386/pr121572-1a.c	Sun Dec 21 22:32:11 2025
*************** extern __thread int tv_cache __attribute
*** 19,25 ****
  extern void use_cache (int);
  extern int val (int v);
  
! __attribute__ ((optimize (2)))
  void
  bug (void)
  {
--- 19,25 ----
  extern void use_cache (int);
  extern int val (int v);
  
! __attribute__ ((optimize (2,"-fno-reorder-blocks-and-partition")))
  void
  bug (void)
  {
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/i386/shift-gf2p8affine-2.c gcc-16-20251221/gcc/testsuite/gcc.target/i386/shift-gf2p8affine-2.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/i386/shift-gf2p8affine-2.c	Sun Dec 14 22:32:13 2025
--- gcc-16-20251221/gcc/testsuite/gcc.target/i386/shift-gf2p8affine-2.c	Sun Dec 21 22:32:11 2025
***************
*** 1,5 ****
--- 1,9 ----
  /* { dg-do run } */
  /* { dg-options "-mgfni -mavx512vl -mavx512bw -mavx512f -O3 -Wno-shift-count-negative -march=x86-64 -mtune=generic" } */
+ /* { dg-require-effective-target gfni } */
+ /* { dg-require-effective-target avx512vl } */
+ /* { dg-require-effective-target avx512bw } */
+ /* { dg-require-effective-target avx512f } */
  
  #include <string.h>
  
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/i386/user_msr-pr123217.c gcc-16-20251221/gcc/testsuite/gcc.target/i386/user_msr-pr123217.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/i386/user_msr-pr123217.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/i386/user_msr-pr123217.c	Sun Dec 21 22:32:12 2025
***************
*** 0 ****
--- 1,10 ----
+ /* PR target/123217 */
+ /* { dg-do compile { target { ! ia32 } } } */
+ /* { dg-options "-musermsr -O0" } */
+ 
+ unsigned long long
+ foo (unsigned long long x)
+ {
+   unsigned long long y = __builtin_ia32_urdmsr (x);
+   return y;
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/loongarch/pr123171.c gcc-16-20251221/gcc/testsuite/gcc.target/loongarch/pr123171.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/loongarch/pr123171.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/loongarch/pr123171.c	Sun Dec 21 22:32:12 2025
***************
*** 0 ****
--- 1,54 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O2 -march=la32v1.0" } */
+ /* { dg-final { check-function-bodies "**" "" } } */
+ 
+ /*
+ ** orn_la32r:
+ ** 	nor	\$r5,\$r0,\$r5
+ ** 	or	\$r4,\$r5,\$r4
+ ** 	jr	\$r1
+ */
+ #pragma GCC push_options
+ #pragma GCC target "arch=la32rv1.0"
+ int
+ orn_la32r (int a, int b)
+ {
+   return a | ~b;
+ }
+ 
+ /*
+ ** orn_la32s_attr:
+ ** 	orn	\$r4,\$r4,\$r5
+ ** 	jr	\$r1
+ */
+ int
+ __attribute__ ((target ("arch=la32v1.0")))
+ orn_la32s_attr (int a, int b)
+ {
+   return a | ~b;
+ }
+ #pragma GCC pop_options
+ 
+ /*
+ ** orn_la32s:
+ ** 	orn	\$r4,\$r4,\$r5
+ ** 	jr	\$r1
+ */
+ int
+ orn_la32s (int a, int b)
+ {
+   return a | ~b;
+ }
+ 
+ /*
+ ** orn_la32r_attr:
+ ** 	nor	\$r5,\$r0,\$r5
+ ** 	or	\$r4,\$r5,\$r4
+ ** 	jr	\$r1
+ */
+ int
+ __attribute__ ((target ("arch=la32rv1.0")))
+ orn_la32r_attr (int a, int b)
+ {
+   return a | ~b;
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/loongarch/vect-mode-tieable.c gcc-16-20251221/gcc/testsuite/gcc.target/loongarch/vect-mode-tieable.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/loongarch/vect-mode-tieable.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/loongarch/vect-mode-tieable.c	Sun Dec 21 22:32:12 2025
***************
*** 0 ****
--- 1,47 ----
+ /* { dg-do compile { target { loongarch64*-*-* } } } */
+ /* { dg-options "-mabi=lp64d -O2 -mlasx" } */
+ /* { dg-final { check-function-bodies "**" "" } } */
+ 
+ #include <lasxintrin.h>
+ 
+ /*
+ **foo1:
+ **	vinsgr2vr.d	(\$vr[0-9]+),\$r5,0
+ **	vinsgr2vr.d	(\$vr[0-9]+),\$r6,1
+ **	xvadd.d	(\$xr[0-9]+),(\$xr[0-9]+),(\$xr[0-9]+)
+ **	xvst	(\$xr[0-9]+),\$r4,0
+ **	jr	\$r1
+ */
+ __m256i
+ foo1 (__m128i a)
+ {
+   return __lasx_xvadd_d (__lasx_cast_128 (a), __lasx_cast_128 (a));
+ }
+ 
+ /*
+ **foo2:
+ **	vinsgr2vr.d	(\$vr[0-9]+),\$r5,0
+ **	vinsgr2vr.d	(\$vr[0-9]+),\$r6,1
+ **	xvfadd.s	(\$xr[0-9]+),(\$xr[0-9]+),(\$xr[0-9]+)
+ **	xvst	(\$xr[0-9]+),\$r4,0
+ **	jr	\$r1
+ */
+ __m256
+ foo2 (__m128 a)
+ {
+   return __lasx_xvfadd_s (__lasx_cast_128_s (a), __lasx_cast_128_s (a));
+ }
+ 
+ /*
+ **foo3:
+ **	vinsgr2vr.d	(\$vr[0-9]+),\$r5,0
+ **	vinsgr2vr.d	(\$vr[0-9]+),\$r6,1
+ **	xvfadd.d	(\$xr[0-9]+),(\$xr[0-9]+),(\$xr[0-9]+)
+ **	xvst	(\$xr[0-9]+),\$r4,0
+ **	jr	\$r1
+ */
+ __m256d
+ foo3 (__m128d a)
+ {
+   return __lasx_xvfadd_d (__lasx_cast_128_d (a), __lasx_cast_128_d (a));
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/loongarch/vector/lasx/vect-extract-256-128.c gcc-16-20251221/gcc/testsuite/gcc.target/loongarch/vector/lasx/vect-extract-256-128.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/loongarch/vector/lasx/vect-extract-256-128.c	Sun Dec 14 22:32:13 2025
--- gcc-16-20251221/gcc/testsuite/gcc.target/loongarch/vector/lasx/vect-extract-256-128.c	Sun Dec 21 22:32:12 2025
***************
*** 6,12 ****
  
  /*
  **foo1_lo:
! **	vld	(\$vr[0-9]+),\$r4,0
  **	vpickve2gr.du	\$r4,(\$vr[0-9]+),0
  **	vpickve2gr.du	\$r5,(\$vr[0-9]+),1
  **	jr	\$r1
--- 6,12 ----
  
  /*
  **foo1_lo:
! **	xvld	(\$xr[0-9]+),\$r4,0
  **	vpickve2gr.du	\$r4,(\$vr[0-9]+),0
  **	vpickve2gr.du	\$r5,(\$vr[0-9]+),1
  **	jr	\$r1
*************** foo1_hi (__m256 x)
*** 33,39 ****
  
  /*
  **foo2_lo:
! **	vld	(\$vr[0-9]+),\$r4,0
  **	vpickve2gr.du	\$r4,(\$vr[0-9]+),0
  **	vpickve2gr.du	\$r5,(\$vr[0-9]+),1
  **	jr	\$r1
--- 33,39 ----
  
  /*
  **foo2_lo:
! **	xvld	(\$xr[0-9]+),\$r4,0
  **	vpickve2gr.du	\$r4,(\$vr[0-9]+),0
  **	vpickve2gr.du	\$r5,(\$vr[0-9]+),1
  **	jr	\$r1
*************** foo2_hi (__m256d x)
*** 60,66 ****
  
  /*
  **foo3_lo:
! **	vld	(\$vr[0-9]+),\$r4,0
  **	vpickve2gr.du	\$r4,(\$vr[0-9]+),0
  **	vpickve2gr.du	\$r5,(\$vr[0-9]+),1
  **	jr	\$r1
--- 60,66 ----
  
  /*
  **foo3_lo:
! **	xvld	(\$xr[0-9]+),\$r4,0
  **	vpickve2gr.du	\$r4,(\$vr[0-9]+),0
  **	vpickve2gr.du	\$r5,(\$vr[0-9]+),1
  **	jr	\$r1
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/loongarch/vector/lsx/pr123117.c gcc-16-20251221/gcc/testsuite/gcc.target/loongarch/vector/lsx/pr123117.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/loongarch/vector/lsx/pr123117.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/loongarch/vector/lsx/pr123117.c	Sun Dec 21 22:32:12 2025
***************
*** 0 ****
--- 1,16 ----
+ /* { dg-options "-mlsx -O1" } */
+ 
+ #define BS_VEC(type, num) type __attribute__((vector_size(num * sizeof(type))))
+ #define T BS_VEC(unsigned, 4)
+ 
+ int main ()
+ {
+   BS_VEC(long int, 2) BS_VAR_0[1];
+   BS_VEC(int, 4) tt = (BS_VEC(int, 4)){0x9e47d3d2, 0, 0, 0};
+   asm("":"+f"(tt));
+   BS_VEC(unsigned int, 2) SHUF = __builtin_shufflevector((T)tt, (T)tt, 0, 1);
+   BS_VAR_0[0] = __builtin_convertvector(SHUF, BS_VEC(long int, 2));
+ 
+   if (BS_VAR_0[0][0] != 0x000000009e47d3d2)
+     __builtin_abort ();
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/riscv/rvv/autovec/early-break-3.c gcc-16-20251221/gcc/testsuite/gcc.target/riscv/rvv/autovec/early-break-3.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/riscv/rvv/autovec/early-break-3.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/riscv/rvv/autovec/early-break-3.c	Sun Dec 21 22:32:12 2025
***************
*** 0 ****
--- 1,70 ----
+ /* { dg-do compile } */
+ /* { dg-additional-options "-O3 -march=rv64gcv -mabi=lp64d -ftree-vectorize -std=gnu99" } */
+ /* { dg-final { scan-assembler-times {vms[lgen][teq]\.v[vxi]} 6 } } */
+ /* { dg-final { scan-assembler-times {vcpop\.m} 6 } } */
+ 
+ #define N 640
+ int a[N] = {0};
+ int b[N] = {0};
+ 
+ /* Should all generate compare + vcpop + branch.  */
+ 
+ void f1 ()
+ {
+   for (int i = 0; i < N; i++)
+     {
+       b[i] += a[i];
+       if (a[i] > 0)
+         break;
+     }
+ }
+ 
+ void f2 ()
+ {
+   for (int i = 0; i < N; i++)
+     {
+       b[i] += a[i];
+       if (a[i] >= 0)
+         break;
+     }
+ }
+ 
+ void f3 ()
+ {
+   for (int i = 0; i < N; i++)
+     {
+       b[i] += a[i];
+       if (a[i] == 0)
+         break;
+     }
+ }
+ 
+ void f4 ()
+ {
+   for (int i = 0; i < N; i++)
+     {
+       b[i] += a[i];
+       if (a[i] != 0)
+         break;
+     }
+ }
+ 
+ void f5 ()
+ {
+   for (int i = 0; i < N; i++)
+     {
+       b[i] += a[i];
+       if (a[i] < 0)
+         break;
+     }
+ }
+ 
+ void f6 ()
+ {
+   for (int i = 0; i < N; i++)
+     {
+       b[i] += a[i];
+       if (a[i] <= 0)
+         break;
+     }
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/riscv/rvv/autovec/early-break-4.c gcc-16-20251221/gcc/testsuite/gcc.target/riscv/rvv/autovec/early-break-4.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/riscv/rvv/autovec/early-break-4.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/riscv/rvv/autovec/early-break-4.c	Sun Dec 21 22:32:12 2025
***************
*** 0 ****
--- 1,68 ----
+ /* { dg-do compile } */
+ /* { dg-additional-options "-O3 -march=rv64gcv -mabi=lp64d -ftree-vectorize -std=gnu99" } */
+ /* { dg-final { scan-assembler-times {vms[lgen][teq]\.v[vxi]} 6 } } */
+ /* { dg-final { scan-assembler-times {vcpop\.m} 6 } } */
+ 
+ #define N 640
+ int a[N] = {0};
+ int b[N] = {0};
+ 
+ void f1 ()
+ {
+   for (int i = 0; i < N; i++)
+     {
+       b[i] += a[i];
+       if (a[i] > 0)
+         break;
+     }
+ }
+ 
+ void f2 ()
+ {
+   for (int i = 0; i < N; i++)
+     {
+       b[i] += a[i];
+       if (a[i] >= 0)
+         break;
+     }
+ }
+ 
+ void f3 ()
+ {
+   for (int i = 0; i < N; i++)
+     {
+       b[i] += a[i];
+       if (a[i] == 0)
+         break;
+     }
+ }
+ 
+ void f4 ()
+ {
+   for (int i = 0; i < N; i++)
+     {
+       b[i] += a[i];
+       if (a[i] != 0)
+         break;
+     }
+ }
+ 
+ void f5 ()
+ {
+   for (int i = 0; i < N; i++)
+     {
+       b[i] += a[i];
+       if (a[i] < 0)
+         break;
+     }
+ }
+ 
+ void f6 ()
+ {
+   for (int i = 0; i < N; i++)
+     {
+       b[i] += a[i];
+       if (a[i] <= 0)
+         break;
+     }
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/riscv/rvv/autovec/early-break-5.c gcc-16-20251221/gcc/testsuite/gcc.target/riscv/rvv/autovec/early-break-5.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/riscv/rvv/autovec/early-break-5.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/riscv/rvv/autovec/early-break-5.c	Sun Dec 21 22:32:12 2025
***************
*** 0 ****
--- 1,117 ----
+ /* { dg-do run } */
+ /* { dg-require-effective-target riscv_v_ok } */
+ /* { dg-additional-options "-O3 -march=rv64gcv -mabi=lp64d -std=gnu99" } */
+ 
+ #include <stdio.h>
+ 
+ #define N 640
+ #ifndef TYPE
+ #define TYPE int
+ #endif
+ 
+ TYPE a[N] = {0};
+ TYPE b[N] = {0};
+ 
+ char *curr_test;
+ 
+ #define DEFINE_TEST_FUNC(NAME, OP)            \
+   __attribute__((noipa))		      \
+   void NAME(void) {                           \
+     for (int i = 0; i < N; i++) {             \
+       b[i] += a[i];                           \
+       if (a[i] OP 0)                          \
+         break;                                \
+     }                                         \
+   }
+ 
+ DEFINE_TEST_FUNC(f1, >)
+ DEFINE_TEST_FUNC(f2, >=)
+ DEFINE_TEST_FUNC(f3, ==)
+ DEFINE_TEST_FUNC(f4, !=)
+ DEFINE_TEST_FUNC(f5, <)
+ DEFINE_TEST_FUNC(f6, <=)
+ 
+ /* Array setup macro.  */
+ #define RESET_ARRAYS(_aval, _idx, _force, _bval)         \
+   do {                                                   \
+     _Pragma("GCC novector")				 \
+     for (int i = 0; i < N; ++i) {                        \
+       a[i] = _aval;                                      \
+       b[i] = _bval;                                      \
+     }                                                    \
+     if (_idx >= 0 && _idx < N)                           \
+       a[_idx] = _force;                                  \
+   } while (0)
+ 
+ /* Value check macros.  */
+ #define CHECK_EQ(_i, _val)                        \
+   do {                                            \
+     if (b[_i] != _val)                            \
+       __builtin_abort ();			  \
+   } while (0)
+ 
+ #define CHECK_RANGE_EQ(_start, _end, _val)               \
+   do {                                                   \
+     _Pragma("GCC novector")				 \
+     for (int i = _start; i < _end; ++i)                  \
+       if (b[i] != _val)                                  \
+ 	__builtin_abort ();				 \
+   } while (0)
+ 
+ #define str(s) #s
+ #define TEST_FUNC(_func, _aval, _idx, _force, _bval, _check_stmt)  \
+   do {                                                             \
+     curr_test = str (_func);                                       \
+     RESET_ARRAYS((_aval), (_idx), (_force), (_bval));              \
+     _func();                                                       \
+     _check_stmt;                                                   \
+   } while (0)
+ 
+ int main(void) {
+   /* Break on random intervals.  */
+   TEST_FUNC (f1, 1, 0, 1, 10, CHECK_EQ (0, 11); CHECK_EQ (1, 10));
+   TEST_FUNC (f2, -1, 5, 0, 10, CHECK_EQ (0, 9); CHECK_EQ (5, 10));
+   TEST_FUNC (f3, 3, 3, 0, 0, CHECK_EQ (0, 3); CHECK_EQ (3, 0));
+   TEST_FUNC (f4, 0, 4, 1, 1, CHECK_EQ (4, 2); CHECK_EQ (5, 1));
+   TEST_FUNC (f5, 1, 6, -1, 5, CHECK_EQ (6, 4); CHECK_EQ (7, 5));
+   TEST_FUNC (f6, 2, 10, 0, 7, CHECK_EQ (10, 7); CHECK_EQ (11, 7));
+ 
+   /* Break on last iteration.  */
+   TEST_FUNC (f1, 0, N-1, 1, 1,
+     CHECK_RANGE_EQ (0, N-1, 1); CHECK_EQ (N-1, 2));
+ 
+   TEST_FUNC (f2, -5, N-1, 0, 9,
+     CHECK_RANGE_EQ (0, N-1, 4); CHECK_EQ (N-1, 9));
+ 
+   TEST_FUNC (f3, 2, N-1, 0, 0,
+     CHECK_RANGE_EQ(0, N-1, 2); CHECK_EQ (N-1, 0));
+ 
+   TEST_FUNC (f4, 0, N-1, 2, 1,
+     CHECK_RANGE_EQ (0, N-1, 1); CHECK_EQ (N-1, 3));
+ 
+   TEST_FUNC (f5, 2, N-1, -3, 6,
+     CHECK_RANGE_EQ (0, N-1, 8); CHECK_EQ (N-1, 3));
+ 
+   TEST_FUNC (f6, 5, N-1, 0, 7,
+     CHECK_RANGE_EQ (0, N-1, 12); CHECK_EQ (N-1, 7));
+ 
+   TEST_FUNC (f1, 0, -1, 0, 2,
+     CHECK_RANGE_EQ (0, N, 2));
+ 
+   TEST_FUNC (f2, -2, -1, 0, 5,
+     CHECK_RANGE_EQ (0, N, 3));
+ 
+   TEST_FUNC (f3, 1, -1, 0, 0,
+     CHECK_RANGE_EQ (0, N, 1));
+ 
+   TEST_FUNC (f4, 0, -1, 0, 7,
+     CHECK_RANGE_EQ (0, N, 7));
+ 
+   TEST_FUNC (f5, 1, -1, 0, 4,
+     CHECK_RANGE_EQ (0, N, 5));
+ 
+   TEST_FUNC (f6, 5, -1, 0, 3,
+     CHECK_RANGE_EQ (0, N, 8));
+ 
+   return 0;
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/riscv/rvv/autovec/gather-scatter/strided_store-2.c gcc-16-20251221/gcc/testsuite/gcc.target/riscv/rvv/autovec/gather-scatter/strided_store-2.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/riscv/rvv/autovec/gather-scatter/strided_store-2.c	Sun Dec 14 22:32:13 2025
--- gcc-16-20251221/gcc/testsuite/gcc.target/riscv/rvv/autovec/gather-scatter/strided_store-2.c	Sun Dec 21 22:32:12 2025
***************
*** 40,45 ****
  
  TEST_ALL (TEST_LOOP)
  
! /* { dg-final { scan-tree-dump-times " \.MASK_LEN_STRIDED_STORE " 44 "optimized" } } */
  /* { dg-final { scan-tree-dump-not " \.SCATTER_STORE" "optimized" } } */
  /* { dg-final { scan-tree-dump-not " \.MASK_SCATTER_STORE" "optimized" } } */
--- 40,46 ----
  
  TEST_ALL (TEST_LOOP)
  
! /* { dg-final { scan-tree-dump-times " \.MASK_LEN_STRIDED_STORE " 44 "optimized" { target { no-opts "-mrvv-max-lmul=dynamic" "-mrvv-max-lmul=m8" } } } } */
! /* { dg-final { scan-tree-dump-times " \.MASK_LEN_STRIDED_STORE " 49 "optimized" { target { any-opts "-mrvv-max-lmul=dynamic" "-mrvv-max-lmul=m8" } } } } */
  /* { dg-final { scan-tree-dump-not " \.SCATTER_STORE" "optimized" } } */
  /* { dg-final { scan-tree-dump-not " \.MASK_SCATTER_STORE" "optimized" } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/riscv/rvv/autovec/param-autovec-mode.c gcc-16-20251221/gcc/testsuite/gcc.target/riscv/rvv/autovec/param-autovec-mode.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/riscv/rvv/autovec/param-autovec-mode.c	Sun Dec 14 22:32:13 2025
--- gcc-16-20251221/gcc/testsuite/gcc.target/riscv/rvv/autovec/param-autovec-mode.c	Sun Dec 21 22:32:12 2025
*************** foo (int *a, int *b, int n)
*** 13,16 ****
  }
  
  /* { dg-final { scan-tree-dump "Choosing vector mode V4QI" "vect" } } */
! /* { dg-final { scan-tree-dump "Choosing epilogue vector mode RVVM1SI" "vect" } } */
--- 13,16 ----
  }
  
  /* { dg-final { scan-tree-dump "Choosing vector mode V4QI" "vect" } } */
! /* { dg-final { scan-tree-dump "operating on partial vectors." "vect" } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/select_vl-2.c gcc-16-20251221/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/select_vl-2.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/select_vl-2.c	Sun Dec 14 22:32:13 2025
--- gcc-16-20251221/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/select_vl-2.c	Sun Dec 21 22:32:12 2025
***************
*** 6,17 ****
  
  /*
  ** foo:
! **	vsetivli\t[a-x0-9]+,\s*8,\s*e(8?|16?|32?|64),\s*m(1?|2?|4?|8?|f2?|f4?|f8),\s*t[au],\s*m[au]
  **	...
  **	vle32\.v\tv[0-9]+,0\([a-x0-9]+\)
  **	...
- **	vsetvli\tzero,\s*[a-x0-9]+,\s*e(8?|16?|32?|64),\s*m(1?|2?|4?|8?|f2?|f4?|f8),\s*t[au],\s*m[au]
- **	...
  **	vle32\.v\tv[0-9]+,0\([a-x0-9]+\)
  **	...
  */
--- 6,15 ----
  
  /*
  ** foo:
! **      vsetivli\tzero,\s*4,\s*e(8?|16?|32?|64),\s*m(1?|2?|4?|8?|f2?|f4?|f8),\s*t[au],\s*m[au]
  **	...
  **	vle32\.v\tv[0-9]+,0\([a-x0-9]+\)
  **	...
  **	vle32\.v\tv[0-9]+,0\([a-x0-9]+\)
  **	...
  */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-1.c gcc-16-20251221/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-1.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-1.c	Sun Dec 14 22:32:13 2025
--- gcc-16-20251221/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-1.c	Sun Dec 21 22:32:12 2025
***************
*** 1,5 ****
  /* { dg-do compile } */
! /* { dg-options "-march=rv64gcv -mabi=lp64d -O3" } */
  
  #include <stdint.h>
  
--- 1,5 ----
  /* { dg-do compile } */
! /* { dg-options "-march=rv64gcv -mabi=lp64d -O3 -fdump-tree-optimized" } */
  
  #include <stdint.h>
  
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr121510.c gcc-16-20251221/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr121510.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr121510.c	Sun Dec 14 22:32:13 2025
--- gcc-16-20251221/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr121510.c	Sun Dec 21 22:32:12 2025
*************** void print_bfloat() {
*** 8,14 ****
      long j;
      union {
        _Float16 x;
!       char b[]
      } u;
      j = 0;
      for (; j < sizeof 0; j++)
--- 8,14 ----
      long j;
      union {
        _Float16 x;
!       char b[];
      } u;
      j = 0;
      for (; j < sizeof 0; j++)
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr122970.c gcc-16-20251221/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr122970.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr122970.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr122970.c	Sun Dec 21 22:32:12 2025
***************
*** 0 ****
--- 1,71 ----
+ /* { dg-do run } */
+ /* { dg-require-effective-target riscv_v_ok } */
+ /* { dg-require-effective-target rvv_zvl128b_ok } */
+ /* { dg-require-effective-target rv64 } */
+ /* { dg-options "-O3 -march=rv64gcv -mabi=lp64d -mrvv-vector-bits=zvl -mrvv-max-lmul=m4" } */
+ 
+ typedef unsigned char uint8_t;
+ 
+ void
+ f (uint8_t *restrict a, uint8_t *restrict c, uint8_t *restrict d, int n)
+ {
+   for (int i = 0; i < n; ++i)
+     {
+       a[i * 8] = c[i * 8] + d[i * 8];
+       a[i * 8 + 1] = c[i * 8] + d[i * 8 + 1];
+       a[i * 8 + 2] = c[i * 8 + 2] + d[i * 8 + 2];
+       a[i * 8 + 3] = c[i * 8 + 2] + d[i * 8 + 3];
+       a[i * 8 + 4] = c[i * 8 + 4] + d[i * 8 + 4]; a[i * 8 + 5] = c[i * 8 + 4] + d[i * 8 + 5];
+       a[i * 8 + 6] = c[i * 8 + 6] + d[i * 8 + 6];
+       a[i * 8 + 7] = c[i * 8 + 6] + d[i * 8 + 7];
+     }
+ }
+ 
+ void __attribute__ ((noipa))
+ f_golden (uint8_t *restrict a, uint8_t *restrict c, uint8_t *restrict d, int n)
+ {
+ #pragma GCC novector
+   for (int i = 0; i < n; ++i)
+     {
+       a[i * 8] = c[i * 8] + d[i * 8];
+       a[i * 8 + 1] = c[i * 8] + d[i * 8 + 1];
+       a[i * 8 + 2] = c[i * 8 + 2] + d[i * 8 + 2];
+       a[i * 8 + 3] = c[i * 8 + 2] + d[i * 8 + 3];
+       a[i * 8 + 4] = c[i * 8 + 4] + d[i * 8 + 4];
+       a[i * 8 + 5] = c[i * 8 + 4] + d[i * 8 + 5];
+       a[i * 8 + 6] = c[i * 8 + 6] + d[i * 8 + 6];
+       a[i * 8 + 7] = c[i * 8 + 6] + d[i * 8 + 7];
+     }
+ }
+ 
+ #define LIMIT 256
+ #define NUM 32
+ 
+ int
+ main (void)
+ {
+   uint8_t a[NUM * 8 + 8] = {0};
+   uint8_t a_golden[NUM * 8 + 8] = {0};
+   uint8_t c[NUM * 8 + 8] = {0};
+   uint8_t d[NUM * 8 + 8] = {0};
+ 
+   for (int i = 0; i < NUM * 8 + 8; i++)
+     {
+       if (i % NUM == 0)
+ 	c[i] = (i + NUM) % LIMIT;
+       else
+ 	c[i] = (i * 3) % LIMIT;
+       if (i % 2 == 0)
+ 	d[i] = i % LIMIT;
+       else
+ 	d[i] = (i * 7) % LIMIT;
+     }
+ 
+   f (a, c, d, NUM);
+   f_golden (a_golden, c, d, NUM);
+ 
+   if (a[241] != 103)
+     __builtin_abort ();
+ 
+   return 0;
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr123097-run.c gcc-16-20251221/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr123097-run.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr123097-run.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr123097-run.c	Sun Dec 21 22:32:12 2025
***************
*** 0 ****
--- 1,19 ----
+ /* { dg-do run } */
+ /* { dg-require-effective-target riscv_v_ok } */
+ /* { dg-options "-O3 -march=rv64gcv -mabi=lp64d" } */
+ 
+ long long a;
+ int b[22];
+ _Bool c[22];
+ 
+ int main() {
+     for (long f=0; f<10; ++f)
+       b[f] = c[f] = 1;
+     for (int f=0; f<5; f++)
+       for( int g=0; g<5; g++)
+         c[g*2] &= (_Bool)b[2*f];
+     for (long f=0; f<2; ++f)
+       a ^= c[f];
+     if (a != 0)
+       __builtin_abort ();
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr123097.c gcc-16-20251221/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr123097.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr123097.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr123097.c	Sun Dec 21 22:32:12 2025
***************
*** 0 ****
--- 1,20 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O3 -march=rv64gcv -mabi=lp64d -fdump-tree-optimized" } */
+ 
+ long long a;
+ int b[22];
+ _Bool c[22];
+ 
+ int main() {
+     for (long f=0; f<10; ++f)
+       b[f] = c[f] = 1;
+     for (int f=0; f<5; f++)
+       for( int g=0; g<5; g++)
+         c[g*2] &= (_Bool)b[2*f];
+     for (long f=0; f<2; ++f)
+       a ^= c[f];
+     if (a != 0)
+       __builtin_abort ();
+ }
+ 
+ /* { dg-final { scan-tree-dump-not "BIT_FIELD_REF <\\{ -1, -1, -1, -1 \\}," "optimized" } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/riscv/rvv/autovec/subreg-extract.c gcc-16-20251221/gcc/testsuite/gcc.target/riscv/rvv/autovec/subreg-extract.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/riscv/rvv/autovec/subreg-extract.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/riscv/rvv/autovec/subreg-extract.c	Sun Dec 21 22:32:12 2025
***************
*** 0 ****
--- 1,19 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O3 -march=rv64gcv_zvl256b -mabi=lp64d -mrvv-vector-bits=zvl -fno-vect-cost-model" } */
+ 
+ int a[35] = { 1, 1, 3 };
+ 
+ void
+ foo ()
+ {
+   for (int b = 4; b >= 0; b--)
+     {
+       int tem = a[b * 5 + 3 + 1];
+       a[b * 5 + 3] = tem;
+       a[b * 5 + 2] = tem;
+       a[b * 5 + 1] = tem;
+       a[b * 5 + 0] = tem;
+     }
+ }
+ 
+ /* { dg-final { scan-assembler-times "vslidedown" 2 } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d-1.c gcc-16-20251221/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d-1.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d-1.c	Sun Dec 14 22:32:13 2025
--- gcc-16-20251221/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d-1.c	Sun Dec 21 22:32:12 2025
***************
*** 3,6 ****
  
  #include "template-1.h"
  
! /* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 6 "vect" } } */
--- 3,9 ----
  
  #include "template-1.h"
  
! /* With length-control for VLS modes we don't vectorize foo4 anymore.
!    That's due to a very tight costing decision in the small loop.
!    Therefore expect 5 instead of 6 vectorized loops.  */
! /* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 5 "vect" } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64f-1.c gcc-16-20251221/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64f-1.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64f-1.c	Sun Dec 14 22:32:13 2025
--- gcc-16-20251221/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64f-1.c	Sun Dec 21 22:32:12 2025
***************
*** 3,6 ****
  
  #include "template-1.h"
  
! /* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 5 "vect" } } */
--- 3,9 ----
  
  #include "template-1.h"
  
! /* Same as in zve64d-1.c we don't vectorize foo4 anymore due to an
!    unfortunately tight costing decision.  Therefore expect 4 instead of 5
!    vectorized loops.  */
! /* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 4 "vect" } } */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/riscv/rvv/base/pr112431-21.c gcc-16-20251221/gcc/testsuite/gcc.target/riscv/rvv/base/pr112431-21.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/riscv/rvv/base/pr112431-21.c	Sun Dec 14 22:32:13 2025
--- gcc-16-20251221/gcc/testsuite/gcc.target/riscv/rvv/base/pr112431-21.c	Sun Dec 21 22:32:12 2025
***************
*** 1,5 ****
  /* { dg-do run { target { riscv_v } } } */
! /* { dg-additional-options "-O3 -ansi -pedantic-errors -std=gnu99" } */
  
  #include "riscv_vector.h"
  
--- 1,5 ----
  /* { dg-do run { target { riscv_v } } } */
! /* { dg-additional-options "-O3 -ansi -std=gnu99 -Wno-pedantic" } */
  
  #include "riscv_vector.h"
  
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/s390/larl-1.c gcc-16-20251221/gcc/testsuite/gcc.target/s390/larl-1.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/s390/larl-1.c	Sun Dec 14 22:32:13 2025
--- gcc-16-20251221/gcc/testsuite/gcc.target/s390/larl-1.c	Sun Dec 21 22:32:12 2025
***************
*** 3,9 ****
  /* { dg-do compile { target { s390*-*-* } } } */
  /* { dg-options "-O2 -march=z10 -mzarch -fno-section-anchors" } */
  
! /* An explicitely misaligned symbol.  This symbol is NOT aligned as
     mandated by our ABI.  However, the back-end needs to handle that in
     order to make things like __attribute__((packed)) work.  The symbol
     address is expected to be loaded from literal pool.  */
--- 3,9 ----
  /* { dg-do compile { target { s390*-*-* } } } */
  /* { dg-options "-O2 -march=z10 -mzarch -fno-section-anchors" } */
  
! /* An explicitly misaligned symbol.  This symbol is NOT aligned as
     mandated by our ABI.  However, the back-end needs to handle that in
     order to make things like __attribute__((packed)) work.  The symbol
     address is expected to be loaded from literal pool.  */
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gcc.target/sh/pr55212-c248.c gcc-16-20251221/gcc/testsuite/gcc.target/sh/pr55212-c248.c
*** gcc-16-20251214/gcc/testsuite/gcc.target/sh/pr55212-c248.c	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gcc.target/sh/pr55212-c248.c	Sun Dec 21 22:32:12 2025
***************
*** 0 ****
--- 1,31 ----
+ /* { dg-do run }  */
+ /* { dg-options "-O2 -m4 -mlra -ffixed-r7 -ffixed-r8 -ffixed-r9 -ffixed-r10 -ffixed-r11 -ffixed-r12 -ffixed-r13" } */
+ #include <stdlib.h>
+ #include <string.h>
+ 
+ typedef struct { int c[64]; } obj;
+ obj obj0;
+ obj obj1;
+ 
+ void __attribute__ ((noinline))
+ bar (int a, int b, int c, int d, obj *q)
+ {
+   if (q->c[0] != 0x12345678 || q->c[1] != 0xdeadbeef) 
+     abort ();
+ }
+ 
+ void foo (obj *p)
+ {
+   obj bobj;
+   bobj = *p;
+   bar (0, 0, 0, 0, &bobj);
+ }
+ 
+ int
+ main ()
+ {
+   obj0.c[0] = 0x12345678;
+   obj0.c[1] = 0xdeadbeef;
+   foo (&obj0);
+   exit (0);
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gfortran.dg/associate_76.f90 gcc-16-20251221/gcc/testsuite/gfortran.dg/associate_76.f90
*** gcc-16-20251214/gcc/testsuite/gfortran.dg/associate_76.f90	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gfortran.dg/associate_76.f90	Sun Dec 21 22:32:13 2025
***************
*** 0 ****
--- 1,67 ----
+ ! { dg-do compile }
+ ! PR fortran/71565 - INTENT(IN) polymorphic argument with pointer components
+ !
+ ! Contributed by Marco Restelli.
+ 
+ module m
+   implicit none
+ 
+   type, abstract :: t_a
+   end type t_a
+ 
+   type, extends(t_a), abstract :: t_b
+      integer, pointer :: i => null()
+   end type t_b
+ 
+ contains
+ 
+   subroutine s1(var)
+     class(t_a), intent(in) :: var
+     select type(var)
+     class is(t_b)
+        var%i = 3
+        var%i => NULL()      ! { dg-error "pointer association context" }
+     end select
+   end subroutine s1
+ 
+   subroutine s1a(var)
+     class(t_a), intent(in) :: var
+     select type(tmp => var) ! { dg-error "variable definition context" }
+     class is(t_b)
+        tmp%i = 3
+        tmp%i => NULL()      ! { dg-error "variable definition context" }
+     end select
+   end subroutine s1a
+ 
+   subroutine s2(var)
+     class(t_b), intent(in) :: var
+     var%i = 3
+     var%i => NULL()        ! { dg-error "pointer association context" }
+   end subroutine s2
+ 
+   subroutine s2a(var)
+     class(t_b), intent(in) :: var
+     associate (tmp => var) ! { dg-error "variable definition context" }
+       print *, associated (tmp%i)
+       tmp%i = 3
+       tmp%i => NULL()      ! { dg-error "variable definition context" }
+     end associate
+   end subroutine s2a
+ 
+   subroutine s2b(var)
+     class(t_b), intent(in) :: var
+     associate (tmp => var%i)
+       tmp = 3
+     end associate
+   end subroutine s2b
+ 
+   subroutine s3(var)
+     class(t_a), intent(in) :: var
+     integer, pointer :: tmp
+     select type(var); class is(t_b)
+        tmp => var%i
+        tmp =  3
+     end select
+   end subroutine s3
+ 
+ end module m
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gfortran.dg/bessel_6.f90 gcc-16-20251221/gcc/testsuite/gfortran.dg/bessel_6.f90
*** gcc-16-20251214/gcc/testsuite/gfortran.dg/bessel_6.f90	Sun Dec 14 22:32:14 2025
--- gcc-16-20251221/gcc/testsuite/gfortran.dg/bessel_6.f90	Sun Dec 21 22:32:13 2025
***************
*** 1,3 ****
--- 1,4 ----
+ ! { dg-do run }
  ! { dg-add-options ieee }
  !
  ! PR fortran/36158
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gfortran.dg/bound_8.f90 gcc-16-20251221/gcc/testsuite/gfortran.dg/bound_8.f90
*** gcc-16-20251214/gcc/testsuite/gfortran.dg/bound_8.f90	Sun Dec 14 22:32:14 2025
--- gcc-16-20251221/gcc/testsuite/gfortran.dg/bound_8.f90	Sun Dec 21 22:32:13 2025
***************
*** 11,17 ****
  PROGRAM main
    IMPLICIT NONE
  
!   ! Some explicitely shaped arrays and allocatable ones.
    INTEGER :: a(2, 3), b(0:1, 4:6)
    INTEGER, ALLOCATABLE :: x(:, :), y(:, :)
  
--- 11,17 ----
  PROGRAM main
    IMPLICIT NONE
  
!   ! Some explicitly shaped arrays and allocatable ones.
    INTEGER :: a(2, 3), b(0:1, 4:6)
    INTEGER, ALLOCATABLE :: x(:, :), y(:, :)
  
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gfortran.dg/coarray_14.f90 gcc-16-20251221/gcc/testsuite/gfortran.dg/coarray_14.f90
*** gcc-16-20251214/gcc/testsuite/gfortran.dg/coarray_14.f90	Sun Dec 14 22:32:14 2025
--- gcc-16-20251221/gcc/testsuite/gfortran.dg/coarray_14.f90	Sun Dec 21 22:32:13 2025
*************** end subroutine test
*** 43,49 ****
  
  ! Check for C617: "... a data-ref shall not be a polymorphic subobject of a
  ! coindexed object or ..." 
! ! Before, the second allocate statment was failing - though it is no subobject.
  program myTest
  type t
  end type t
--- 43,49 ----
  
  ! Check for C617: "... a data-ref shall not be a polymorphic subobject of a
  ! coindexed object or ..." 
! ! Before, the second allocate statement was failing - though it is no subobject.
  program myTest
  type t
  end type t
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gfortran.dg/erf_2.F90 gcc-16-20251221/gcc/testsuite/gfortran.dg/erf_2.F90
*** gcc-16-20251214/gcc/testsuite/gfortran.dg/erf_2.F90	Sun Dec 14 22:32:14 2025
--- gcc-16-20251221/gcc/testsuite/gfortran.dg/erf_2.F90	Sun Dec 21 22:32:13 2025
***************
*** 1,3 ****
--- 1,4 ----
+ ! { dg-do run }
  ! { dg-options "-fno-range-check -ffree-line-length-none -O0" }
  ! { dg-add-options ieee }
  !
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gfortran.dg/goacc/update-if_present-2.f90 gcc-16-20251221/gcc/testsuite/gfortran.dg/goacc/update-if_present-2.f90
*** gcc-16-20251214/gcc/testsuite/gfortran.dg/goacc/update-if_present-2.f90	Sun Dec 14 22:32:14 2025
--- gcc-16-20251221/gcc/testsuite/gfortran.dg/goacc/update-if_present-2.f90	Sun Dec 21 22:32:13 2025
*************** subroutine t1
*** 12,21 ****
  
    allocate (x, y, z(100))
  
!   !$acc enter data copyin(a) if_present ! { dg-error "Expected '\\(' after 'if'" }
!   !$acc exit data copyout(a) if_present ! { dg-error "Expected '\\(' after 'if'" }
  
!   !$acc data copy(a) if_present ! { dg-error "Expected '\\(' after 'if'" }
    !$acc end data ! { dg-error "Unexpected ..ACC END DATA statement" }
  
    !$acc declare link(a) if_present ! { dg-error "Unexpected junk after" }
--- 12,21 ----
  
    allocate (x, y, z(100))
  
!   !$acc enter data copyin(a) if_present ! { dg-error "Failed to match clause" }
!   !$acc exit data copyout(a) if_present ! { dg-error "Failed to match clause" }
  
!   !$acc data copy(a) if_present ! { dg-error "Failed to match clause" }
    !$acc end data ! { dg-error "Unexpected ..ACC END DATA statement" }
  
    !$acc declare link(a) if_present ! { dg-error "Unexpected junk after" }
*************** subroutine t2
*** 40,56 ****
    end do
    !$acc end parallel
  
!   !$acc kernels loop if_present ! { dg-error "Expected '\\(' after 'if'" }
    do b = 1, 10
    end do
    !$acc end kernels loop ! { dg-error "Unexpected ..ACC END KERNELS LOOP statement" }
  
!   !$acc parallel loop if_present ! { dg-error "Expected '\\(' after 'if'" }
    do b = 1, 10
    end do
    !$acc end parallel loop   ! { dg-error "Unexpected ..ACC END PARALLEL LOOP statement" }
  
!   !$acc serial loop if_present ! { dg-error "Expected '\\(' after 'if'" }
    do b = 1, 10
    end do
    !$acc end serial loop   ! { dg-error "Unexpected ..ACC END SERIAL LOOP statement" }
--- 40,56 ----
    end do
    !$acc end parallel
  
!   !$acc kernels loop if_present ! { dg-error "Failed to match clause" }
    do b = 1, 10
    end do
    !$acc end kernels loop ! { dg-error "Unexpected ..ACC END KERNELS LOOP statement" }
  
!   !$acc parallel loop if_present ! { dg-error "Failed to match clause" }
    do b = 1, 10
    end do
    !$acc end parallel loop   ! { dg-error "Unexpected ..ACC END PARALLEL LOOP statement" }
  
!   !$acc serial loop if_present ! { dg-error "Failed to match clause" }
    do b = 1, 10
    end do
    !$acc end serial loop   ! { dg-error "Unexpected ..ACC END SERIAL LOOP statement" }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gfortran.dg/gomp/assume-6.f90 gcc-16-20251221/gcc/testsuite/gfortran.dg/gomp/assume-6.f90
*** gcc-16-20251214/gcc/testsuite/gfortran.dg/gomp/assume-6.f90	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gfortran.dg/gomp/assume-6.f90	Sun Dec 21 22:32:13 2025
***************
*** 0 ****
--- 1,8 ----
+ !$omp assume no_openmp no_openmp_something  ! { dg-error "24: Failed to match clause" }
+ block
+ end block
+ 
+ !$omp assume no_openmp no_openmp_routines no_openmp_constructs no_openmp_constructs ! { dg-error "63: Duplicated 'no_openmp_constructs' clause" }
+ block
+ end block
+ end
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gfortran.dg/gomp/order-8.f90 gcc-16-20251221/gcc/testsuite/gfortran.dg/gomp/order-8.f90
*** gcc-16-20251214/gcc/testsuite/gfortran.dg/gomp/order-8.f90	Sun Dec 14 22:32:14 2025
--- gcc-16-20251221/gcc/testsuite/gfortran.dg/gomp/order-8.f90	Sun Dec 21 22:32:13 2025
***************
*** 2,12 ****
  subroutine f1 (a)
    integer :: a(*)
    integer i
!   !$omp do order				! { dg-error "Failed to match clause" }
    do i = 1, 128
      a(i) = a(i) + 1
    end do
!   !$omp do simd order :			! { dg-error "Failed to match clause" }
    do i = 1, 128
      a(i) = a(i) + 1
    end do
--- 2,12 ----
  subroutine f1 (a)
    integer :: a(*)
    integer i
!   !$omp do order				! { dg-error "Expected '\\(' after 'order'" }
    do i = 1, 128
      a(i) = a(i) + 1
    end do
!   !$omp do simd order :			! { dg-error "Expected '\\(' after 'order'" }
    do i = 1, 128
      a(i) = a(i) + 1
    end do
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gfortran.dg/gomp/order-9.f90 gcc-16-20251221/gcc/testsuite/gfortran.dg/gomp/order-9.f90
*** gcc-16-20251214/gcc/testsuite/gfortran.dg/gomp/order-9.f90	Sun Dec 14 22:32:14 2025
--- gcc-16-20251221/gcc/testsuite/gfortran.dg/gomp/order-9.f90	Sun Dec 21 22:32:13 2025
***************
*** 1,34 ****
  subroutine foo
!   !$omp do schedule(static) order(concurrent) order(concurrent) ! { dg-error "Duplicated 'order \\(' clause" }
    do i = 1, 8
      call f0 ()
    end do
!   !$omp do schedule(static) order(reproducible:concurrent) order(unconstrained:concurrent)      ! { dg-error "Duplicated 'order \\(' clause" }
    do i = 1, 8
      call f0 ()
    end do
  
!   !$omp loop bind(thread) order(concurrent) order(concurrent)    ! { dg-error "Duplicated 'order \\(' clause" }
    do i = 1, 8
      call f0 ()
    end do
!   !$omp loop bind(thread) order(reproducible:concurrent) order(unconstrained:concurrent) ! { dg-error "Duplicated 'order \\(' clause" }
    do i = 1, 8
      call f0 ()
    end do
!   !$omp simd order(concurrent) order(concurrent) ! { dg-error "Duplicated 'order \\(' clause" }
    do i = 1, 8
      call f0 ()
    end do
!   !$omp simd order(reproducible:concurrent) order(unconstrained:concurrent)      ! { dg-error "Duplicated 'order \\(' clause" }
    do i = 1, 8
      call f0 ()
    end do
!   !$omp distribute dist_schedule(static) order(concurrent) order(concurrent)     ! { dg-error "Duplicated 'order \\(' clause" }
    do i = 1, 8
      call f0 ()
    end do
!   !$omp loop bind(thread) order(reproducible:concurrent) order(unconstrained:concurrent) ! { dg-error "Duplicated 'order \\(' clause" }
    do i = 1, 8
      call f0 ()
    end do
--- 1,34 ----
  subroutine foo
!   !$omp do schedule(static) order(concurrent) order(concurrent) ! { dg-error "Duplicated 'order' clause" }
    do i = 1, 8
      call f0 ()
    end do
!   !$omp do schedule(static) order(reproducible:concurrent) order(unconstrained:concurrent)      ! { dg-error "Duplicated 'order' clause" }
    do i = 1, 8
      call f0 ()
    end do
  
!   !$omp loop bind(thread) order(concurrent) order(concurrent)    ! { dg-error "Duplicated 'order' clause" }
    do i = 1, 8
      call f0 ()
    end do
!   !$omp loop bind(thread) order(reproducible:concurrent) order(unconstrained:concurrent) ! { dg-error "Duplicated 'order' clause" }
    do i = 1, 8
      call f0 ()
    end do
!   !$omp simd order(concurrent) order(concurrent) ! { dg-error "Duplicated 'order' clause" }
    do i = 1, 8
      call f0 ()
    end do
!   !$omp simd order(reproducible:concurrent) order(unconstrained:concurrent)      ! { dg-error "Duplicated 'order' clause" }
    do i = 1, 8
      call f0 ()
    end do
!   !$omp distribute dist_schedule(static) order(concurrent) order(concurrent)     ! { dg-error "Duplicated 'order' clause" }
    do i = 1, 8
      call f0 ()
    end do
!   !$omp loop bind(thread) order(reproducible:concurrent) order(unconstrained:concurrent) ! { dg-error "Duplicated 'order' clause" }
    do i = 1, 8
      call f0 ()
    end do
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gfortran.dg/gomp/target-device-type-1.f90 gcc-16-20251221/gcc/testsuite/gfortran.dg/gomp/target-device-type-1.f90
*** gcc-16-20251214/gcc/testsuite/gfortran.dg/gomp/target-device-type-1.f90	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gfortran.dg/gomp/target-device-type-1.f90	Sun Dec 21 22:32:13 2025
***************
*** 0 ****
--- 1,21 ----
+ ! { dg-do compile }
+ ! { dg-additional-options "-fdump-tree-gimple" }
+ 
+ !$omp target
+ !$omp end target
+ 
+ !$omp target device_type ( any )
+ !$omp end target
+ 
+ !$omp target device_type ( nohost )  ! { dg-message "sorry, unimplemented: only the 'device_type\\(any\\)' is supported" }
+ !$omp end target
+ 
+ !$omp target device_type ( host )
+ !$omp end target
+ 
+ end
+ 
+ ! { dg-final { scan-tree-dump-times "#pragma omp target num_teams\\(-2\\) thread_limit\\(0\\)\[\\r\\n\]" 1 "gimple" } }
+ ! { dg-final { scan-tree-dump-times "#pragma omp target num_teams\\(-2\\) thread_limit\\(0\\) device_type\\(any\\)" 1 "gimple" } }
+ ! { dg-final { scan-tree-dump-times "#pragma omp target num_teams\\(-2\\) thread_limit\\(0\\) device_type\\(nohost\\)" 1 "gimple" } }
+ ! { dg-final { scan-tree-dump-times "#pragma omp target num_teams\\(-2\\) thread_limit\\(0\\) device_type\\(host\\)" 1 "gimple" } }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gfortran.dg/integer_exponentiation_3.F90 gcc-16-20251221/gcc/testsuite/gfortran.dg/integer_exponentiation_3.F90
*** gcc-16-20251214/gcc/testsuite/gfortran.dg/integer_exponentiation_3.F90	Sun Dec 14 22:32:14 2025
--- gcc-16-20251221/gcc/testsuite/gfortran.dg/integer_exponentiation_3.F90	Sun Dec 21 22:32:13 2025
***************
*** 1,3 ****
--- 1,4 ----
+ ! { dg-do run }
  ! { dg-options "" }
  ! { dg-options "-ffloat-store" { target { { i?86-*-* x86_64-*-* } && ilp32 } } } 
  !
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gfortran.dg/integer_exponentiation_5.F90 gcc-16-20251221/gcc/testsuite/gfortran.dg/integer_exponentiation_5.F90
*** gcc-16-20251214/gcc/testsuite/gfortran.dg/integer_exponentiation_5.F90	Sun Dec 14 22:32:14 2025
--- gcc-16-20251221/gcc/testsuite/gfortran.dg/integer_exponentiation_5.F90	Sun Dec 21 22:32:13 2025
***************
*** 1,3 ****
--- 1,4 ----
+ ! { dg-do run }
  ! { dg-options "-fno-range-check" }
  ! { dg-add-options ieee }
  module mod_check
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gfortran.dg/pr121472.f90 gcc-16-20251221/gcc/testsuite/gfortran.dg/pr121472.f90
*** gcc-16-20251214/gcc/testsuite/gfortran.dg/pr121472.f90	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gfortran.dg/pr121472.f90	Sun Dec 21 22:32:13 2025
***************
*** 0 ****
--- 1,33 ----
+ ! { dg-do compile }
+ ! PR fortran/121472 - ICE with constructor for finalized zero-size type
+ 
+ module pr121472_m
+     implicit none
+     type r
+     end type
+ 
+     type ip
+         type(r) :: r_member
+     contains
+         final :: ipd
+     end type
+ 
+     interface ip
+         module procedure ipc
+     end interface
+ contains
+     subroutine ipd(this)
+         type(ip), intent(inout) :: this
+     end subroutine
+ 
+     function ipc() result(res)
+         type(ip) :: res
+     end function
+ end module
+ 
+ program test
+     use pr121472_m
+     implicit none
+     type(ip) :: p
+     p = ip()
+ end program
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gfortran.dg/pr121475.f90 gcc-16-20251221/gcc/testsuite/gfortran.dg/pr121475.f90
*** gcc-16-20251214/gcc/testsuite/gfortran.dg/pr121475.f90	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gfortran.dg/pr121475.f90	Sun Dec 21 22:32:13 2025
***************
*** 0 ****
--- 1,75 ----
+ ! { dg-do run }
+ !
+ ! PR fortran/121475 - Function result not finalized when passed to
+ ! user-defined assignment.
+ !
+ ! F2003 4.5.5.2 requires that function results be finalized after
+ ! execution of the innermost executable construct.  When the function
+ ! result is passed to a user-defined assignment, the finalization was
+ ! being skipped because of early return for types with defined_assign_comp.
+ 
+ ! Test case put together by Christopher Albert.
+ 
+ module m
+   implicit none
+   integer :: final_count = 0
+ 
+   type :: base
+   contains
+     procedure :: assign
+     generic :: assignment(=) => assign
+   end type
+ 
+   type, extends(base) :: derived
+     integer :: val
+   contains
+     final :: finalize
+   end type
+ 
+   interface derived
+     module procedure constructor
+   end interface
+ 
+ contains
+ 
+   subroutine finalize(self)
+     type(derived), intent(inout) :: self
+     final_count = final_count + 1
+   end subroutine
+ 
+   function constructor() result(self)
+     type(derived) :: self
+     self%val = 0
+   end function
+ 
+   subroutine assign(to, from)
+     class(base), intent(out) :: to
+     class(base), intent(in) :: from
+     select type (to)
+     type is (derived)
+       select type (from)
+       type is (derived)
+         to%val = from%val
+       end select
+     end select
+   end subroutine
+ 
+ end module
+ 
+ program test
+   use m
+   implicit none
+ 
+   block
+     type(derived) :: obj
+ 
+     final_count = 0
+     obj = derived()
+ 
+     ! Function result and intermediate temporaries finalized
+     if (final_count /= 2) stop 1
+   end block
+ 
+   ! obj goes out of scope, finalized again
+   if (final_count /= 3) stop 2
+ end program
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gfortran.dg/pr122936.f90 gcc-16-20251221/gcc/testsuite/gfortran.dg/pr122936.f90
*** gcc-16-20251214/gcc/testsuite/gfortran.dg/pr122936.f90	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gfortran.dg/pr122936.f90	Sun Dec 21 22:32:13 2025
***************
*** 0 ****
--- 1,43 ----
+ ! { dg-do run }
+ ! PR122936, derived from the original provided by the reporter.
+ ! Before the patch this gave a runtime error.
+ module test_io
+     TYPE :: MYTYPE
+         REAL :: value
+     END TYPE
+     INTERFACE read(formatted)
+         MODULE PROCEDURE read_formatted
+     END INTERFACE
+     PUBLIC :: read(formatted)
+ contains
+     ! Formatted Input
+     SUBROUTINE read_formatted(dtv, unit, iotype, v_list, iostat, iomsg)
+         CLASS(MYTYPE), INTENT(INOUT) :: dtv
+         INTEGER, INTENT(IN)      :: unit
+         CHARACTER(*), INTENT(IN) :: iotype
+         INTEGER, INTENT(IN)      :: v_list(:)
+         INTEGER, INTENT(OUT)     :: iostat
+         CHARACTER(*), INTENT(INOUT) :: iomsg
+ 
+         REAL   :: tmp
+ 
+         READ(unit, FMT = *, IOSTAT=iostat, IOMSG=iomsg) tmp
+         IF (iostat == 0) dtv%value = tmp
+     END SUBROUTINE read_formatted
+ 
+ end module
+ 
+ PROGRAM MAIN
+     USE test_io
+     INTEGER, PARAMETER  :: NIN = 15
+     TYPE(MYTYPE)       :: V11, V12, V13
+     INTEGER            :: V21, V22, V23
+     OPEN(NIN, status='scratch')
+     WRITE(NIN,*) "    2.5 9 1.5, AValue for V1"
+     WRITE(NIN,*) "    15 2.4 17,  BValue for V2"
+     REWIND(NIN)
+     READ(NIN, FMT = *) V11, V23, V12
+     READ(NIN, FMT = *) V21, V13, V22
+     CLOSE(NIN)
+ END PROGRAM MAIN
+ 
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gfortran.dg/pr92613.f90 gcc-16-20251221/gcc/testsuite/gfortran.dg/pr92613.f90
*** gcc-16-20251214/gcc/testsuite/gfortran.dg/pr92613.f90	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gfortran.dg/pr92613.f90	Sun Dec 21 22:32:13 2025
***************
*** 0 ****
--- 1,13 ----
+ # 1 "<test>"
+ # 1 "<built-in>"
+ # 1 "<command-line>"
+ # 1 "<test>"
+ ! PR fortran/92613
+ ! { dg-do compile }
+ ! { dg-options "-cpp -fpreprocessed" }
+ program test
+   implicit none
+   write(6,*) 'hello'
+ ! Comment with apostrophe: it's good!
+ ! Comment with double quote: "quoted"
+ end program
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gfortran.dg/pr92613_2.f90 gcc-16-20251221/gcc/testsuite/gfortran.dg/pr92613_2.f90
*** gcc-16-20251214/gcc/testsuite/gfortran.dg/pr92613_2.f90	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gfortran.dg/pr92613_2.f90	Sun Dec 21 22:32:13 2025
***************
*** 0 ****
--- 1,11 ----
+ # 1 "<test>"
+ # 1 "<built-in>"
+ # 1 "<command-line>"
+ # 1 "<test>"
+ ! PR fortran/92613
+ ! { dg-do preprocess }
+ ! { dg-options "-cpp -fpreprocessed" }
+ ! { dg-error ".-E. is not supported with .-fpreprocessed." "" { target *-*-* } 0 }
+ ! { dg-prune-output "compilation terminated" }
+ program test
+ end program
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gfortran.dg/protected_8.f90 gcc-16-20251221/gcc/testsuite/gfortran.dg/protected_8.f90
*** gcc-16-20251214/gcc/testsuite/gfortran.dg/protected_8.f90	Sun Dec 14 22:32:14 2025
--- gcc-16-20251221/gcc/testsuite/gfortran.dg/protected_8.f90	Sun Dec 21 22:32:13 2025
*************** PROGRAM test
*** 41,48 ****
     a%j => k ! { dg-error "is PROTECTED" }
     a%j = 5  ! OK 2
     b => c   ! { dg-error "is PROTECTED" }
!    b%i = k  ! OK 3
!    b%j => k ! OK 4
!    b%j = 5  ! OK 5
  
  END PROGRAM test
--- 41,48 ----
     a%j => k ! { dg-error "is PROTECTED" }
     a%j = 5  ! OK 2
     b => c   ! { dg-error "is PROTECTED" }
!    b%i = k  ! { dg-error "is PROTECTED" }
!    b%j => k ! { dg-error "is PROTECTED" }
!    b%j = 5  ! OK 3
  
  END PROGRAM test
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gm2/pim/fail/badprocedure.mod gcc-16-20251221/gcc/testsuite/gm2/pim/fail/badprocedure.mod
*** gcc-16-20251214/gcc/testsuite/gm2/pim/fail/badprocedure.mod	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gm2/pim/fail/badprocedure.mod	Sun Dec 21 22:32:13 2025
***************
*** 0 ****
--- 1,7 ----
+ MODULE badprocedure ;
+ 
+ IMPORT FIO ;
+ 
+ BEGIN
+    FIO.WriteLn (FIO.StdOut)
+ END badprocedure.
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gm2/pimlib/base/run/pass/FIO.mod gcc-16-20251221/gcc/testsuite/gm2/pimlib/base/run/pass/FIO.mod
*** gcc-16-20251214/gcc/testsuite/gm2/pimlib/base/run/pass/FIO.mod	Sun Dec 14 22:32:14 2025
--- gcc-16-20251221/gcc/testsuite/gm2/pimlib/base/run/pass/FIO.mod	Sun Dec 21 22:32:13 2025
***************
*** 1,6 ****
  (* FIO.mod provides a simple buffered file input/output library.
  
! Copyright (C) 2001-2023 Free Software Foundation, Inc.
  Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
  
  This file is part of GNU Modula-2.
--- 1,6 ----
  (* FIO.mod provides a simple buffered file input/output library.
  
! Copyright (C) 2001-2025 Free Software Foundation, Inc.
  Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
  
  This file is part of GNU Modula-2.
*************** IMPLEMENTATION MODULE FIO ;
*** 36,58 ****
                   provides a simple buffered file input/output library.
  *)
  
! FROM SYSTEM IMPORT ADR, TSIZE, SIZE, WORD ;
  FROM ASCII IMPORT nl, nul, tab ;
  FROM StrLib IMPORT StrLen, StrConCat, StrCopy ;
  FROM Storage IMPORT ALLOCATE, DEALLOCATE ;
  FROM NumberIO IMPORT CardToStr ;
- FROM libc IMPORT exit, open, creat, read, write, close, lseek, strncpy, memcpy ;
  FROM Indexing IMPORT Index, InitIndex, InBounds, HighIndice, PutIndice, GetIndice ;
  FROM M2RTS IMPORT InstallTerminationProcedure ;
  
  CONST
-    SEEK_SET            =       0 ;   (* relative from beginning of the file *)
-    SEEK_END            =       2 ;   (* relative to the end of the file     *)
-    UNIXREADONLY        =       0 ;
-    UNIXWRITEONLY       =       1 ;
-    CreatePermissions   =     666B;
     MaxBufferLength     = 1024*16 ;
     MaxErrorString      = 1024* 8 ;
  
  TYPE
     FileUsage         = (unused, openedforread, openedforwrite, openedforrandom) ;
--- 36,56 ----
                   provides a simple buffered file input/output library.
  *)
  
! FROM SYSTEM IMPORT ADR, TSIZE, WORD, COFF_T ;
  FROM ASCII IMPORT nl, nul, tab ;
  FROM StrLib IMPORT StrLen, StrConCat, StrCopy ;
  FROM Storage IMPORT ALLOCATE, DEALLOCATE ;
  FROM NumberIO IMPORT CardToStr ;
  FROM Indexing IMPORT Index, InitIndex, InBounds, HighIndice, PutIndice, GetIndice ;
  FROM M2RTS IMPORT InstallTerminationProcedure ;
+ FROM libc IMPORT exit, open, creat, read, write, close, lseek, strncpy, memcpy ;
+ FROM wrapc IMPORT SeekSet, SeekEnd, ReadOnly, WriteOnly ;
+ 
  
  CONST
     MaxBufferLength     = 1024*16 ;
     MaxErrorString      = 1024* 8 ;
+    CreatePermissions   =     666B;
  
  TYPE
     FileUsage         = (unused, openedforread, openedforwrite, openedforrandom) ;
*************** END GetNextFreeDescriptor ;
*** 196,202 ****
  
  
  (*
!    IsNoError - returns a TRUE if no error has occured on file, f.
  *)
  
  PROCEDURE IsNoError (f: File) : BOOLEAN ;
--- 194,200 ----
  
  
  (*
!    IsNoError - returns a TRUE if no error has occured on file f.
  *)
  
  PROCEDURE IsNoError (f: File) : BOOLEAN ;
*************** END IsNoError ;
*** 214,219 ****
--- 212,235 ----
  
  
  (*
+    IsError - returns a TRUE if an error has occured on file f.
+ *)
+ 
+ PROCEDURE IsError (f: File) : BOOLEAN ;
+ VAR
+    fd: FileDescriptor ;
+ BEGIN
+    IF f=Error
+    THEN
+       RETURN( FALSE )
+    ELSE
+       fd := GetIndice (FileInfo, f) ;
+       RETURN( (fd#NIL) AND ((fd^.state#successful) AND (fd^.state#endoffile) AND (fd^.state#endofline)) )
+    END
+ END IsError ;
+ 
+ 
+ (*
     IsActive - returns TRUE if the file, f, is still active.
  *)
  
*************** BEGIN
*** 428,437 ****
                 THEN
                    unixfd := creat(name.address, CreatePermissions)
                 ELSE
!                   unixfd := open(name.address, UNIXWRITEONLY, 0)
                 END
              ELSE
!                unixfd := open(name.address, UNIXREADONLY, 0)
              END ;
              IF unixfd<0
              THEN
--- 444,453 ----
                 THEN
                    unixfd := creat(name.address, CreatePermissions)
                 ELSE
!                   unixfd := open(name.address, INTEGER (WriteOnly ()), 0)
                 END
              ELSE
!                unixfd := open(name.address, INTEGER (ReadOnly ()), 0)
              END ;
              IF unixfd<0
              THEN
*************** END OpenForRandom ;
*** 476,503 ****
     Close - close a file which has been previously opened using:
             OpenToRead, OpenToWrite, OpenForRandom.
             It is correct to close a file which has an error status.
  *)
  
! PROCEDURE Close (f: File) ;
  VAR
     fd: FileDescriptor ;
  BEGIN
!    IF f#Error
     THEN
!       fd := GetIndice(FileInfo, f) ;
!       (*
!          we allow users to close files which have an error status
!       *)
!       IF fd#NIL
        THEN
!          FlushBuffer(f) ;
           WITH fd^ DO
!             IF unixfd>=0
              THEN
!                IF close(unixfd)#0
                 THEN
!                   FormatError1('failed to close file (%s)\n', name.address) ;
!                   state := failed   (* --fixme-- too late to notify user (unless we return a BOOLEAN) *)
                 END
              END ;
              IF name.address#NIL
--- 492,523 ----
     Close - close a file which has been previously opened using:
             OpenToRead, OpenToWrite, OpenForRandom.
             It is correct to close a file which has an error status.
+            Close has an optional return value:
+              TRUE  signifies that the close was successful and all
+                    state associated with f is deallocated.
+              FALSE signifies that the close was unsuccessful and no
+                    state associated with f has been deallocated.
  *)
  
! PROCEDURE Close (f: File) : [BOOLEAN] ;
  VAR
     fd: FileDescriptor ;
  BEGIN
!    IF f # Error
     THEN
!       fd := GetIndice (FileInfo, f) ;
!       (* We allow users to close files which have an error status.  *)
!       IF fd # NIL
        THEN
!          FlushBuffer (f) ;
           WITH fd^ DO
!             IF unixfd >= 0
              THEN
!                IF close (unixfd) # 0
                 THEN
!                   FormatError1 ('failed to close file (%s)\n', name.address) ;
!                   state := failed ;
!                   RETURN FALSE
                 END
              END ;
              IF name.address#NIL
*************** BEGIN
*** 518,524 ****
           END ;
           DISPOSE(fd) ;
           PutIndice(FileInfo, f, NIL)
!       END
     END
  END Close ;
  
--- 538,547 ----
           END ;
           DISPOSE(fd) ;
           PutIndice(FileInfo, f, NIL)
!       END ;
!       RETURN TRUE
!    ELSE
!       RETURN FALSE
     END
  END Close ;
  
*************** END ReadNBytes ;
*** 664,673 ****
                    Useful when performing small reads.
  *)
  
! PROCEDURE BufferedRead (f: File; nBytes: CARDINAL; a: ADDRESS) : INTEGER ;
  VAR
!    t     : ADDRESS ;
!    result: INTEGER ;
     total,
     n     : INTEGER ;
     p     : POINTER TO BYTE ;
--- 687,695 ----
                    Useful when performing small reads.
  *)
  
! PROCEDURE BufferedRead (f: File; nBytes: CARDINAL; dest: ADDRESS) : INTEGER ;
  VAR
!    src   : ADDRESS ;
     total,
     n     : INTEGER ;
     p     : POINTER TO BYTE ;
*************** VAR
*** 675,726 ****
  BEGIN
     IF f#Error
     THEN
!       fd := GetIndice(FileInfo, f) ;
        total := 0 ;   (* how many bytes have we read *)
        IF fd#NIL
        THEN
           WITH fd^ DO
              (* extract from the buffer first *)
!             IF buffer#NIL
              THEN
                 WITH buffer^ DO
!                   WHILE nBytes>0 DO
!                      IF (left>0) AND valid
                       THEN
!                         IF nBytes=1
                          THEN
                             (* too expensive to call memcpy for 1 character *)
!                            p := a ;
                             p^ := contents^[position] ;
!                            DEC(left) ;         (* remove consumed byte                *)
!                            INC(position) ;     (* move onwards n byte                 *)
!                            INC(total) ;
                             RETURN( total )
                          ELSE
!                            n := Min(left, nBytes) ;
!                            t := address ;
!                            INC(t, position) ;
!                            p := memcpy(a, t, n) ;
!                            DEC(left, n) ;      (* remove consumed bytes               *)
!                            INC(position, n) ;  (* move onwards n bytes                *)
                                                 (* move onwards ready for direct reads *)
!                            INC(a, n) ;
!                            DEC(nBytes, n) ;    (* reduce the amount for future direct *)
                                                 (* read                                *)
!                            INC(total, n)
                          END
                       ELSE
                          (* refill buffer *)
!                         n := read(unixfd, address, size) ;
!                         IF n>=0
                          THEN
                             valid    := TRUE ;
                             position := 0 ;
                             left     := n ;
                             filled   := n ;
                             bufstart := abspos ;
!                            INC(abspos, n) ;
!                            IF n=0
                             THEN
                                (* eof reached *)
                                state := endoffile ;
--- 697,748 ----
  BEGIN
     IF f#Error
     THEN
!       fd := GetIndice (FileInfo, f) ;
        total := 0 ;   (* how many bytes have we read *)
        IF fd#NIL
        THEN
           WITH fd^ DO
              (* extract from the buffer first *)
!             IF buffer # NIL
              THEN
                 WITH buffer^ DO
!                   WHILE nBytes > 0 DO
!                      IF (left > 0) AND valid
                       THEN
!                         IF nBytes = 1
                          THEN
                             (* too expensive to call memcpy for 1 character *)
!                            p := dest ;
                             p^ := contents^[position] ;
!                            DEC (left) ;         (* remove consumed byte                *)
!                            INC (position) ;     (* move onwards n byte                 *)
!                            INC (total) ;
                             RETURN( total )
                          ELSE
!                            n := Min (left, nBytes) ;
!                            src := address ;
!                            INC (src, position) ;
!                            p := memcpy (dest, src, n) ;
!                            DEC (left, n) ;      (* remove consumed bytes               *)
!                            INC (position, n) ;  (* move onwards n bytes                *)
                                                 (* move onwards ready for direct reads *)
!                            INC (dest, n) ;
!                            DEC (nBytes, n) ;    (* reduce the amount for future direct *)
                                                 (* read                                *)
!                            INC (total, n)
                          END
                       ELSE
                          (* refill buffer *)
!                         n := read (unixfd, address, size) ;
!                         IF n >= 0
                          THEN
                             valid    := TRUE ;
                             position := 0 ;
                             left     := n ;
                             filled   := n ;
                             bufstart := abspos ;
!                            INC (abspos, n) ;
!                            IF n = 0
                             THEN
                                (* eof reached *)
                                state := endoffile ;
*************** END UnReadChar ;
*** 1084,1090 ****
  
  
  (*
!    ReadAny - reads HIGH(a) bytes into, a. All input
               is fully buffered, unlike ReadNBytes and thus is more
               suited to small reads.
  *)
--- 1106,1112 ----
  
  
  (*
!    ReadAny - reads HIGH (a) + 1 bytes into, a.  All input
               is fully buffered, unlike ReadNBytes and thus is more
               suited to small reads.
  *)
*************** END UnReadChar ;
*** 1092,1100 ****
  PROCEDURE ReadAny (f: File; VAR a: ARRAY OF BYTE) ;
  BEGIN
     CheckAccess(f, openedforread, FALSE) ;
!    IF BufferedRead (f, HIGH (a), ADR (a)) = VAL (INTEGER, HIGH (a))
     THEN
!       SetEndOfLine(f, a[HIGH(a)])
     END
  END ReadAny ;
  
--- 1114,1122 ----
  PROCEDURE ReadAny (f: File; VAR a: ARRAY OF BYTE) ;
  BEGIN
     CheckAccess(f, openedforread, FALSE) ;
!    IF BufferedRead (f, HIGH (a) + 1, ADR (a)) = VAL (INTEGER, HIGH (a) + 1)
     THEN
!       SetEndOfLine (f, a[HIGH(a)])
     END
  END ReadAny ;
  
*************** END WriteNBytes ;
*** 1233,1284 ****
                     Useful when performing small writes.
  *)
  
! PROCEDURE BufferedWrite (f: File; nBytes: CARDINAL; a: ADDRESS) : INTEGER ;
  VAR
!    t     : ADDRESS ;
!    result: INTEGER ;
     total,
     n     : INTEGER ;
     p     : POINTER TO BYTE ;
     fd    : FileDescriptor ;
  BEGIN
!    IF f#Error
     THEN
!       fd := GetIndice(FileInfo, f) ;
        IF fd#NIL
        THEN
           total := 0 ;   (* how many bytes have we read *)
           WITH fd^ DO
!             IF buffer#NIL
              THEN
                 WITH buffer^ DO
!                   WHILE nBytes>0 DO
                       (* place into the buffer first *)
!                      IF left>0
                       THEN
!                         IF nBytes=1
                          THEN
                             (* too expensive to call memcpy for 1 character *)
!                            p := a ;
                             contents^[position] := p^ ;
!                            DEC(left) ;         (* reduce space                        *)
!                            INC(position) ;     (* move onwards n byte                 *)
!                            INC(total) ;
                             RETURN( total )
                          ELSE
!                            n := Min(left, nBytes) ;
!                            t := address ;
!                            INC(t, position) ;
!                            p := memcpy(a, t, CARDINAL(n)) ;
!                            DEC(left, n) ;      (* remove consumed bytes               *)
!                            INC(position, n) ;  (* move onwards n bytes                *)
!                                                (* move ready for further writes       *)
!                            INC(a, n) ;
!                            DEC(nBytes, n) ;    (* reduce the amount for future writes *)
!                            INC(total, n)
                          END
                       ELSE
!                         FlushBuffer(f) ;
                          IF (state#successful) AND (state#endofline)
                          THEN
                             nBytes := 0
--- 1255,1305 ----
                     Useful when performing small writes.
  *)
  
! PROCEDURE BufferedWrite (f: File; nBytes: CARDINAL; src: ADDRESS) : INTEGER ;
  VAR
!    dest  : ADDRESS ;
     total,
     n     : INTEGER ;
     p     : POINTER TO BYTE ;
     fd    : FileDescriptor ;
  BEGIN
!    IF f # Error
     THEN
!       fd := GetIndice (FileInfo, f) ;
        IF fd#NIL
        THEN
           total := 0 ;   (* how many bytes have we read *)
           WITH fd^ DO
!             IF buffer # NIL
              THEN
                 WITH buffer^ DO
!                   WHILE nBytes > 0 DO
                       (* place into the buffer first *)
!                      IF left > 0
                       THEN
!                         IF nBytes = 1
                          THEN
                             (* too expensive to call memcpy for 1 character *)
!                            p := src ;
                             contents^[position] := p^ ;
!                            DEC (left) ;         (* reduce space                        *)
!                            INC (position) ;     (* move onwards n byte                 *)
!                            INC (total) ;
                             RETURN( total )
                          ELSE
!                            n := Min (left, nBytes) ;
!                            dest := address ;
!                            INC (dest, position) ;
!                            p := memcpy (dest, src, CARDINAL (n)) ;
!                            DEC (left, n) ;      (* remove consumed bytes               *)
!                            INC (position, n) ;  (* move onwards n bytes                *)
!                                                 (* move ready for further writes       *)
!                            INC (src, n) ;
!                            DEC (nBytes, n) ;    (* reduce the amount for future writes *)
!                            INC (total, n)
                          END
                       ELSE
!                         FlushBuffer (f) ;
                          IF (state#successful) AND (state#endofline)
                          THEN
                             nBytes := 0
*************** END FlushBuffer ;
*** 1331,1337 ****
  
  
  (*
!    WriteAny - writes HIGH(a) bytes onto, file, f. All output
                is fully buffered, unlike WriteNBytes and thus is more
                suited to small writes.
  *)
--- 1352,1358 ----
  
  
  (*
!    WriteAny - writes HIGH (a) + 1 bytes onto, file, f.  All output
                is fully buffered, unlike WriteNBytes and thus is more
                suited to small writes.
  *)
*************** END FlushBuffer ;
*** 1339,1345 ****
  PROCEDURE WriteAny (f: File; VAR a: ARRAY OF BYTE) ;
  BEGIN
     CheckAccess (f, openedforwrite, TRUE) ;
!    IF BufferedWrite (f, HIGH (a), ADR (a)) = VAL (INTEGER, HIGH (a))
     THEN
     END
  END WriteAny ;
--- 1360,1366 ----
  PROCEDURE WriteAny (f: File; VAR a: ARRAY OF BYTE) ;
  BEGIN
     CheckAccess (f, openedforwrite, TRUE) ;
!    IF BufferedWrite (f, HIGH (a) + 1, ADR (a)) = VAL (INTEGER, HIGH (a) + 1)
     THEN
     END
  END WriteAny ;
*************** BEGIN
*** 1450,1456 ****
                       filled   := 0
                    END
                 END ;
!                offset := lseek(unixfd, pos, SEEK_SET) ;
                 IF (offset>=0) AND (pos=offset)
                 THEN
                    abspos := pos
--- 1471,1477 ----
                       filled   := 0
                    END
                 END ;
!                offset := lseek (unixfd, VAL (COFF_T, pos), SeekSet ()) ;
                 IF (offset>=0) AND (pos=offset)
                 THEN
                    abspos := pos
*************** BEGIN
*** 1499,1505 ****
                    filled   := 0
                 END
              END ;
!             offset := lseek(unixfd, pos, SEEK_END) ;
              IF offset>=0
              THEN
                 abspos := offset ;
--- 1520,1526 ----
                    filled   := 0
                 END
              END ;
!             offset := lseek (unixfd, VAL (COFF_T, pos), SeekEnd ()) ;
              IF offset>=0
              THEN
                 abspos := offset ;
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gm2/pimlib/run/pass/testclose.mod gcc-16-20251221/gcc/testsuite/gm2/pimlib/run/pass/testclose.mod
*** gcc-16-20251214/gcc/testsuite/gm2/pimlib/run/pass/testclose.mod	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gm2/pimlib/run/pass/testclose.mod	Sun Dec 21 22:32:13 2025
***************
*** 0 ****
--- 1,41 ----
+ MODULE testclose ;
+ 
+ IMPORT FIO ;
+ IMPORT libc ;
+ 
+ 
+ (*
+    assert -
+ *)
+ 
+ PROCEDURE assert (condition: BOOLEAN; line: CARDINAL) ;
+ BEGIN
+    IF NOT condition
+    THEN
+       libc.printf ("%s:%d:assert failed\n", __FILE__, line) ;
+       libc.exit (1)
+    END
+ END assert ;
+ 
+ 
+ (*
+    Init -
+ *)
+ 
+ PROCEDURE Init ;
+ VAR
+    f: FIO.File ;
+ BEGIN
+    f := FIO.OpenToWrite ('testclose.txt') ;
+    assert (FIO.IsNoError (f), __LINE__) ;
+    FIO.WriteString (f, 'hello') ;
+    assert (FIO.IsNoError (f), __LINE__) ;
+    FIO.WriteLine (f) ;
+    assert (FIO.IsNoError (f), __LINE__) ;
+    assert (FIO.Close (f), __LINE__)
+ END Init ;
+ 
+ 
+ BEGIN
+    Init
+ END testclose.
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gnat.dg/lto30.adb gcc-16-20251221/gcc/testsuite/gnat.dg/lto30.adb
*** gcc-16-20251214/gcc/testsuite/gnat.dg/lto30.adb	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gnat.dg/lto30.adb	Sun Dec 21 22:32:13 2025
***************
*** 0 ****
--- 1,31 ----
+ -- { dg-do compile }
+ -- { dg-options "-flto" { target lto } }
+ 
+ with Ada.Unchecked_Conversion;
+ with System;
+ 
+ package body Lto30 is
+ 
+    generic
+       type T is private;
+    package Unbounded_Arrays is
+       type Unbounded_Array is array (Natural range 1 .. Natural'Last) of T;
+       type Unbounded_Array_Access is access Unbounded_Array;
+       function Convert is new
+          Ada.Unchecked_Conversion (System.Address, Unbounded_Array_Access);
+    end Unbounded_Arrays;
+ 
+    package Atom_Arrays is new Unbounded_Arrays (Ptr);
+    use Atom_Arrays;
+ 
+    procedure Proc is
+       procedure Foo (Targets : access Unbounded_Array_Access);
+       pragma Import (Ada, Foo, "Foo");
+ 
+       Output : aliased Unbounded_Array_Access;
+ 
+    begin
+       Foo (Output'Unchecked_Access);
+    end;
+ 
+ end Lto30;
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gnat.dg/lto30.ads gcc-16-20251221/gcc/testsuite/gnat.dg/lto30.ads
*** gcc-16-20251214/gcc/testsuite/gnat.dg/lto30.ads	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gnat.dg/lto30.ads	Sun Dec 21 22:32:13 2025
***************
*** 0 ****
--- 1,13 ----
+ package Lto30 is
+ 
+    type Rec is private;
+ 
+    type Ptr is access all Rec;
+ 
+    procedure Proc;
+ 
+ private
+ 
+    type Rec is null record;
+ 
+ end Lto30;
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gnat.dg/reduce4.adb gcc-16-20251221/gcc/testsuite/gnat.dg/reduce4.adb
*** gcc-16-20251214/gcc/testsuite/gnat.dg/reduce4.adb	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gnat.dg/reduce4.adb	Sun Dec 21 22:32:13 2025
***************
*** 0 ****
--- 1,9 ----
+ -- { dg-do compile }
+ -- { dg-options "-gnat2022" }
+ 
+ procedure Reduce4 (S : String) is
+ begin
+   if [for E of S => 1]'Reduce ("+", 0) = 3 then
+     null;
+   end if;
+ end;
diff -Nrcpad gcc-16-20251214/gcc/testsuite/gnat.dg/reduce5.adb gcc-16-20251221/gcc/testsuite/gnat.dg/reduce5.adb
*** gcc-16-20251214/gcc/testsuite/gnat.dg/reduce5.adb	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/gnat.dg/reduce5.adb	Sun Dec 21 22:32:13 2025
***************
*** 0 ****
--- 1,36 ----
+ -- { dg-do compile }
+ -- { dg-options "-gnat2022" }
+ 
+ with Ada.Text_IO; use Ada.Text_IO;
+ 
+ procedure Reduce5 is
+    subtype Chunk_Number is Natural range 1 .. 8;
+    Grid  : array (1 .. 80, 1 .. 100) of Boolean := (others => (others => False));
+    Partial_Sum, Partial_Max : array (Chunk_Number) of Natural := (others => 0);
+    Partial_Min              : array (Chunk_Number) of Natural := (others => Natural'Last);
+ 
+ begin
+    for I in Grid'Range (1) loop
+       Grid (I, 1) := (for all J in Grid'Range (2) => Grid (I, J) = True);
+    end loop;
+ 
+    for I in Grid'Range (1) loop
+       declare
+          True_Count : constant Natural :=
+            [for J in Grid'Range(2) => (if Grid (I, J) then 1 else 0)]'Reduce("+",0);
+       begin
+          Partial_Sum (I) := @ + True_Count;
+          Partial_Min (I) := Natural'Min (@, True_Count);
+          Partial_Max (I) := Natural'Max (@, True_Count);
+       end;
+    end loop;
+ 
+   Put_Line ("Total=" & Natural'Image (Partial_Sum'Reduce ("+", 0)) &
+             ", Min=" & Natural'Image (Partial_Min'Reduce(Natural'Min, Natural'Last)) &
+             ", Max=" & Natural'Image (Partial_Max'Reduce(Natural'Max, 0)));
+ 
+   Put_Line ("Total=" & Partial_Sum'Reduce ("+", 0)'Image &
+             ", Min=" & Partial_Min'Reduce(Natural'Min, Natural'Last)'Image &
+             ", Max=" & Partial_Max'Reduce(Natural'Max, 0)'Image);
+ 
+ end;
diff -Nrcpad gcc-16-20251214/gcc/testsuite/jit.dg/all-non-failing-tests.h gcc-16-20251221/gcc/testsuite/jit.dg/all-non-failing-tests.h
*** gcc-16-20251214/gcc/testsuite/jit.dg/all-non-failing-tests.h	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/gcc/testsuite/jit.dg/all-non-failing-tests.h	Sun Dec 21 22:32:13 2025
***************
*** 145,152 ****
  #undef create_code
  #undef verify_code
  
! /* test-cold-attribute.c: This can't be in the testcases array as it needs
!    the `-O2` flag.  */
  
  /* test-constants.c */
  #define create_code create_code_constants
--- 145,152 ----
  #undef create_code
  #undef verify_code
  
! /* test-cold-attribute.c: This can't be in the testcases array as it needs a
!    specific optimization flag.  */
  
  /* test-constants.c */
  #define create_code create_code_constants
diff -Nrcpad gcc-16-20251214/gcc/testsuite/jit.dg/test-cold-attribute.c gcc-16-20251221/gcc/testsuite/jit.dg/test-cold-attribute.c
*** gcc-16-20251214/gcc/testsuite/jit.dg/test-cold-attribute.c	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/gcc/testsuite/jit.dg/test-cold-attribute.c	Sun Dec 21 22:32:13 2025
***************
*** 8,15 ****
  #define TEST_ESCHEWS_SET_OPTIONS
  static void set_options (gcc_jit_context *ctxt, const char *argv0)
  {
!   // Set "-O2".
!   gcc_jit_context_set_int_option(ctxt, GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 2);
  }
  
  #define TEST_COMPILING_TO_FILE
--- 8,15 ----
  #define TEST_ESCHEWS_SET_OPTIONS
  static void set_options (gcc_jit_context *ctxt, const char *argv0)
  {
!   // Set "-Oz".
!   gcc_jit_context_add_command_line_option (ctxt, "-Oz");
  }
  
  #define TEST_COMPILING_TO_FILE
diff -Nrcpad gcc-16-20251214/gcc/testsuite/lib/algol68-dg.exp gcc-16-20251221/gcc/testsuite/lib/algol68-dg.exp
*** gcc-16-20251214/gcc/testsuite/lib/algol68-dg.exp	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/gcc/testsuite/lib/algol68-dg.exp	Sun Dec 21 22:32:13 2025
*************** proc algol68-dg-prune { system text } {
*** 26,40 ****
      return [gcc-dg-prune $system $text]
  }
  
- # Global modules options
- set MODULES_OPTIONS ""
- 
  # Modified dg-runtest that can cycle through a list of optimization options
  # as c-torture does.
  proc algol68-dg-runtest { testcases flags default-extra-flags } {
      global runtests
      global TORTURE_OPTIONS
-     global MODULES_OPTIONS
  
      foreach test $testcases {
  	# If we're only testing specific files and this isn't one of
--- 26,36 ----
*************** proc algol68-dg-runtest { testcases flag
*** 55,61 ****
  
  	foreach flags_t $option_list {
  	    verbose "Testing $nshort, $flags $flags_t" 1
! 	    dg-test $test "$MODULES_OPTIONS $flags $flags_t" ${default-extra-flags}
  	}
      }
  }
--- 51,57 ----
  
  	foreach flags_t $option_list {
  	    verbose "Testing $nshort, $flags $flags_t" 1
! 	    dg-test $test "$flags $flags_t" ${default-extra-flags}
  	}
      }
  }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/lib/algol68-torture.exp gcc-16-20251221/gcc/testsuite/lib/algol68-torture.exp
*** gcc-16-20251214/gcc/testsuite/lib/algol68-torture.exp	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/gcc/testsuite/lib/algol68-torture.exp	Sun Dec 21 22:32:13 2025
*************** if ![info exists TORTURE_OPTIONS] {
*** 42,50 ****
      }
  }
  
- # Location of built modules
- set BUILT_MODULES_DIR ""
- 
  # Build a series of modules ACCESSed by this test.
  #
  # The first to dg-modules is a list of module names.  The source file
--- 42,47 ----
*************** proc algol68-torture-execute { src } {
*** 285,293 ****
  	if { $algol68_compile_args != "" } {
  	    lappend options "additional_flags=$algol68_compile_args"
  	}
- 	if { $BUILT_MODULES_DIR != "" } {
- 	    lappend options "additional_flags=-I$BUILT_MODULES_DIR"
- 	}
  	if { $algol68_module_objects != "" } {
  	    lappend options "additional_flags=$algol68_module_objects"
  	}
--- 282,287 ----
diff -Nrcpad gcc-16-20251214/gcc/testsuite/lib/plugin-support.exp gcc-16-20251221/gcc/testsuite/lib/plugin-support.exp
*** gcc-16-20251214/gcc/testsuite/lib/plugin-support.exp	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/gcc/testsuite/lib/plugin-support.exp	Sun Dec 21 22:32:13 2025
*************** proc plugin-get-options { src } {
*** 62,70 ****
--- 62,72 ----
  proc plugin-test-execute { plugin_src plugin_tests } {
      global srcdir objdir
      global verbose
+     global tool
      global GMPINC
      global PLUGINCC
      global PLUGINCFLAGS
+     global TESTING_IN_BUILD_TREE
  
      set basename [file tail $plugin_src]
      set base [file rootname $basename]
*************** proc plugin-test-execute { plugin_src pl
*** 76,91 ****
      # Build the plugin itself
      set extra_flags [plugin-get-options $plugin_src]
  
!     # Note that the plugin test support currently only works when the GCC
!     # build tree is available. (We make sure that is the case in plugin.exp.)
!     # Once we have figured out how/where to package/install GCC header files
!     # for general plugin support, we should modify the following include paths
!     # accordingly.
!     set gcc_srcdir "$srcdir/../.."
!     set gcc_objdir "$objdir/../../.."
!     set includes "-I. -I${srcdir} -I${gcc_srcdir}/gcc -I${gcc_objdir}/gcc \
                    -I${gcc_srcdir}/include -I${gcc_srcdir}/libcpp/include \
                    $GMPINC -I${gcc_objdir}/gettext/intl"
  
      if { [ ishost *-*-darwin* ] } {
  	# -mdynamic-no-pic is incompatible with -fPIC.
--- 78,94 ----
      # Build the plugin itself
      set extra_flags [plugin-get-options $plugin_src]
  
!     if { [info exists TESTING_IN_BUILD_TREE] } {
! 	set gcc_srcdir "$srcdir/../.."
! 	set gcc_objdir "$objdir/../../.."
! 	set includes "-I. -I${srcdir} -I${gcc_srcdir}/gcc -I${gcc_objdir}/gcc \
                    -I${gcc_srcdir}/include -I${gcc_srcdir}/libcpp/include \
                    $GMPINC -I${gcc_objdir}/gettext/intl"
+     } else {
+ 	set options [list "additional_flags=-print-file-name=plugin/include"]
+ 	set plugin_inc [lindex [${tool}_target_compile "" "" "none" $options] 0]
+ 	set includes "-I. -I${srcdir} -I${plugin_inc} $GMPINC"
+     }
  
      if { [ ishost *-*-darwin* ] } {
  	# -mdynamic-no-pic is incompatible with -fPIC.
diff -Nrcpad gcc-16-20251214/gcc/testsuite/lib/target-supports.exp gcc-16-20251221/gcc/testsuite/lib/target-supports.exp
*** gcc-16-20251214/gcc/testsuite/lib/target-supports.exp	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/gcc/testsuite/lib/target-supports.exp	Sun Dec 21 22:32:13 2025
*************** proc check_effective_target_riscv_v { }
*** 2127,2132 ****
--- 2127,2150 ----
      }]
  }
  
+ # Return 1 if the target runtime supports 128-bit vectors, 0 otherwise.
+ # Cache the result.
+ 
+ proc check_effective_target_rvv_zvl128b_ok { } {
+     # Check if the target has a VLENB of 16.
+     set gcc_march [riscv_get_arch]
+     return [check_runtime ${gcc_march}_exec {
+        int main()
+        {
+          int vlenb = 0;
+          asm ("csrr %0,vlenb" : "=r" (vlenb) : : );
+          if (vlenb == 16)
+            return 0;
+          return 1;
+        }
+       } "-march=${gcc_march}"]
+ }
+ 
  # Return 1 if the target runtime supports 256-bit vectors, 0 otherwise.
  # Cache the result.
  
*************** proc check_effective_target_aarch64_sve1
*** 5001,5006 ****
--- 5019,5035 ----
  		   && ![check_effective_target_aarch64_sve2] }]
  }
  
+ # Return 1 if this is an AArch64 target supporting MTE.
+ proc check_effective_target_aarch64_mte { } {
+     if { ![istarget aarch64*-*-*] } {
+ 	return 0
+     }
+     return [check_no_compiler_messages aarch64_mte assembly {
+ 	#if !defined (__ARM_FEATURE_MEMORY_TAGGING)
+ 	#error FOO
+ 	#endif
+     } "-march=armv8.5-a+memtag"]
+ }
  # Return the size in bits of an SVE vector, or 0 if the size is variable.
  proc aarch64_sve_bits { } {
      return [check_cached_effective_target aarch64_sve_bits {
*************** proc check_effective_target_aarch64_gas_
*** 12634,12640 ****
  set exts {
      "bf16" "cmpbr" "crc" "crypto" "dotprod" "f32mm" "f64mm" "faminmax"
      "fp" "fp8" "fp8dot2" "fp8dot4" "fp8fma" "i8mm" "ls64" "lse" "lut"
!     "sb" "simd" "sve-b16b16" "sve" "sve2"
  }
  
  # We don't support SME without SVE2, so we'll use armv9 as the base
--- 12663,12670 ----
  set exts {
      "bf16" "cmpbr" "crc" "crypto" "dotprod" "f32mm" "f64mm" "faminmax"
      "fp" "fp8" "fp8dot2" "fp8dot4" "fp8fma" "i8mm" "ls64" "lse" "lut"
!     "sb" "simd" "sve-b16b16" "sve" "sve2" "sve-sm4" "sve-aes" "sve-bitperm"
!     "sve-sha3"
  }
  
  # We don't support SME without SVE2, so we'll use armv9 as the base
*************** proc check_effective_target_valgrind { }
*** 14780,14782 ****
--- 14810,14844 ----
      }
      return 0
  }
+ 
+ # Return 1 if target can compile and run binary for stack
+ # sanitization, 0 otherwise.
+ proc check_effective_target_memtag_exec {} {
+     if ![check_runtime memtag_exec {
+ 	#ifdef __cplusplus
+ 	extern "C" {
+ 	#endif
+ 	extern int prctl(int, unsigned long, unsigned long, unsigned long, unsigned long);
+ 	#ifdef __cplusplus
+ 	}
+ 	#endif
+ 	int main (void) {
+ 	#define PR_SET_TAGGED_ADDR_CTRL 55
+ 	#define PR_GET_TAGGED_ADDR_CTRL 56
+ 	#define PR_TAGGED_ADDR_ENABLE (1UL << 0)
+ 	#define PR_MTE_TCF_SYNC (1UL << 1)
+ 	#define PR_MTE_TAG_SHIFT 3
+ 	  if (prctl (PR_GET_TAGGED_ADDR_CTRL, 0,0,0,0) == -1)
+ 	    return -1;
+ 	  if (prctl (PR_SET_TAGGED_ADDR_CTRL,
+ 		     PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_SYNC
+ 		     | (0xfffe << PR_MTE_TAG_SHIFT), 0, 0, 0) == -1
+ 	      || !prctl (PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0))
+ 	    return 1;
+ 	  return 0;
+ 	}
+       }] {
+ 	return 0;
+       }
+     return 1;
+ }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/obj-c++.dg/plugin/plugin.exp gcc-16-20251221/gcc/testsuite/obj-c++.dg/plugin/plugin.exp
*** gcc-16-20251214/gcc/testsuite/obj-c++.dg/plugin/plugin.exp	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/gcc/testsuite/obj-c++.dg/plugin/plugin.exp	Sun Dec 21 22:32:13 2025
***************
*** 19,30 ****
  load_lib target-supports.exp
  load_lib obj-c++-dg.exp
  
- global TESTING_IN_BUILD_TREE
  global ENABLE_PLUGIN
  
! # The plugin testcases currently only work when the build tree is available.
! # Also check whether the host supports plugins.
! if { ![info exists TESTING_IN_BUILD_TREE] || ![info exists ENABLE_PLUGIN] } {
      return
  }
  
--- 19,28 ----
  load_lib target-supports.exp
  load_lib obj-c++-dg.exp
  
  global ENABLE_PLUGIN
  
! # Check whether the host supports plugins.
! if { ![info exists ENABLE_PLUGIN] } {
      return
  }
  
diff -Nrcpad gcc-16-20251214/gcc/testsuite/objc.dg/plugin/plugin.exp gcc-16-20251221/gcc/testsuite/objc.dg/plugin/plugin.exp
*** gcc-16-20251214/gcc/testsuite/objc.dg/plugin/plugin.exp	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/gcc/testsuite/objc.dg/plugin/plugin.exp	Sun Dec 21 22:32:13 2025
***************
*** 19,30 ****
  load_lib target-supports.exp
  load_lib objc-dg.exp
  
- global TESTING_IN_BUILD_TREE
  global ENABLE_PLUGIN
  
! # The plugin testcases currently only work when the build tree is available.
! # Also check whether the host supports plugins.
! if { ![info exists TESTING_IN_BUILD_TREE] || ![info exists ENABLE_PLUGIN] } {
      return
  }
  
--- 19,28 ----
  load_lib target-supports.exp
  load_lib objc-dg.exp
  
  global ENABLE_PLUGIN
  
! # Check whether the host supports plugins.
! if { ![info exists ENABLE_PLUGIN] } {
      return
  }
  
diff -Nrcpad gcc-16-20251214/gcc/testsuite/rust/compile/issue-4301.rs gcc-16-20251221/gcc/testsuite/rust/compile/issue-4301.rs
*** gcc-16-20251214/gcc/testsuite/rust/compile/issue-4301.rs	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/gcc/testsuite/rust/compile/issue-4301.rs	Sun Dec 21 22:32:13 2025
***************
*** 0 ****
--- 1,3 ----
+ #![feature(unused_variables, server = b"\0")]
+ // { dg-error {unknown feature .server = .} "" { target *-*-* } .-1 }
+ // { dg-error {unknown feature .unused_variables.} "" { target *-*-* } .-2 }
diff -Nrcpad gcc-16-20251214/gcc/testsuite/rust/compile/macros/mbe/macro-issue3608.rs gcc-16-20251221/gcc/testsuite/rust/compile/macros/mbe/macro-issue3608.rs
*** gcc-16-20251214/gcc/testsuite/rust/compile/macros/mbe/macro-issue3608.rs	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/gcc/testsuite/rust/compile/macros/mbe/macro-issue3608.rs	Sun Dec 21 22:32:13 2025
*************** impl Bar for
*** 6,10 ****
  
  
  fn main() { )// { dg-error "unexpected closing delimiter .\\)." }
-              // { dg-error "unexpected token .end of file. - expecting closing delimiter .\}. .for a delimited token tree." "" { target *-*-* } .+2 }
-              // { dg-error "unexpected token .end of file. - expecting closing delimiter .\\). .for a macro invocation semi." "" { target *-*-* } .+1 }
--- 6,8 ----
diff -Nrcpad gcc-16-20251214/gcc/trans-mem.cc gcc-16-20251221/gcc/trans-mem.cc
*** gcc-16-20251214/gcc/trans-mem.cc	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/gcc/trans-mem.cc	Sun Dec 21 22:32:13 2025
*************** ipa_tm_insert_gettmclone_call (struct cg
*** 5163,5171 ****
  
    update_stmt (stmt);
    cgraph_edge *e = cgraph_node::get (current_function_decl)->get_edge (stmt);
!   if (e && e->indirect_info)
!     e->indirect_info->polymorphic = false;
! 
    return true;
  }
  
--- 5163,5175 ----
  
    update_stmt (stmt);
    cgraph_edge *e = cgraph_node::get (current_function_decl)->get_edge (stmt);
!   if (e)
!     {
!       cgraph_polymorphic_indirect_info *pii
! 	= dyn_cast <cgraph_polymorphic_indirect_info *> (e->indirect_info);
!       if (pii)
! 	pii->mark_unusable ();
!     }
    return true;
  }
  
diff -Nrcpad gcc-16-20251214/gcc/tree-cfg.cc gcc-16-20251221/gcc/tree-cfg.cc
*** gcc-16-20251214/gcc/tree-cfg.cc	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/gcc/tree-cfg.cc	Sun Dec 21 22:32:13 2025
*************** group_case_labels_stmt (gswitch *stmt)
*** 1795,1801 ****
  			   but they will be moved to some neighbouring basic
  			   block. If some later case label refers to one of
  			   those labels, we should throw that case away rather
! 			   than keeping it around and refering to some random
  			   other basic block without an edge to it.  */
  			if (removed_labels == NULL)
  			  removed_labels = new hash_set<tree>;
--- 1795,1801 ----
  			   but they will be moved to some neighbouring basic
  			   block. If some later case label refers to one of
  			   those labels, we should throw that case away rather
! 			   than keeping it around and referring to some random
  			   other basic block without an edge to it.  */
  			if (removed_labels == NULL)
  			  removed_labels = new hash_set<tree>;
*************** dump_function_to_file (tree fndecl, FILE
*** 8413,8419 ****
  	  {
  	    if (!SSA_NAME_VAR (name)
  		/* SSA name with decls without a name still get
! 		   dumped as _N, list those explicitely as well even
  		   though we've dumped the decl declaration as D.xxx
  		   above.  */
  		|| !SSA_NAME_IDENTIFIER (name))
--- 8413,8419 ----
  	  {
  	    if (!SSA_NAME_VAR (name)
  		/* SSA name with decls without a name still get
! 		   dumped as _N, list those explicitly as well even
  		   though we've dumped the decl declaration as D.xxx
  		   above.  */
  		|| !SSA_NAME_IDENTIFIER (name))
*************** sort_phi_args (const void *a_, const voi
*** 10195,10207 ****
      return 0;
  }
  
  /* Look for a non-virtual PHIs and make a forwarder block when all PHIs
     have the same argument on a set of edges.  This is to not consider
     control dependences of individual edges for same values but only for
     the common set.  Returns true if changed the CFG.  */
  
  bool
! make_forwarders_with_degenerate_phis (function *fn)
  {
    bool didsomething = false;
  
--- 10195,10271 ----
      return 0;
  }
  
+ /* Returns true if edge E comes from a possible ifconvertable branch.
+    That is:
+    ```
+    BB0:
+    if (a) goto BB1; else goto BB2;
+    BB1:
+    BB2:
+    ```
+    Returns true for the edge from BB0->BB2 or BB1->BB2.
+    This function assumes we only have one middle block.
+    And the middle block is empty. */
+ 
+ static bool
+ ifconvertable_edge (edge e)
+ {
+   basic_block bb2 = e->dest;
+   basic_block bb0 = e->src;
+   basic_block bb1 = nullptr, rbb1;
+   if (e->src == e->dest)
+     return false;
+   if (EDGE_COUNT (bb0->succs) > 2)
+     return false;
+   if (single_succ_p (bb0))
+     {
+       if (!single_pred_p (bb0))
+ 	return false;
+       /* The middle block can only be empty,
+ 	 otherwise the phis will be
+ 	 different anyways. */
+       if (!empty_block_p (bb0))
+ 	return false;
+       bb1 = bb0;
+       bb0 = single_pred (bb0);
+       if (EDGE_COUNT (bb0->succs) != 2)
+ 	return false;
+     }
+ 
+   /* If convertables are only for conditionals. */
+   if (!is_a<gcond*>(*gsi_last_nondebug_bb (bb0)))
+     return false;
+ 
+   /* Find the other basic block.  */
+   if (EDGE_SUCC (bb0, 0)->dest == bb2)
+     rbb1 = EDGE_SUCC (bb0, 1)->dest;
+   else if (EDGE_SUCC (bb0, 1)->dest == bb2)
+     rbb1 = EDGE_SUCC (bb0, 0)->dest;
+   else
+     return false;
+ 
+   /* If we already know bb1, then just test it. */
+   if (bb1)
+     return rbb1 == bb1;
+ 
+   if (!single_succ_p (rbb1) || !single_pred_p (rbb1))
+     return false;
+   /* The middle block can only be empty,
+      otherwise the phis will be
+      different anyways. */
+   if (!empty_block_p (rbb1))
+     return false;
+ 
+   return single_succ (rbb1) == bb2;
+ }
+ 
  /* Look for a non-virtual PHIs and make a forwarder block when all PHIs
     have the same argument on a set of edges.  This is to not consider
     control dependences of individual edges for same values but only for
     the common set.  Returns true if changed the CFG.  */
  
  bool
! make_forwarders_with_degenerate_phis (function *fn, bool skip_ifcvtable)
  {
    bool didsomething = false;
  
*************** make_forwarders_with_degenerate_phis (fu
*** 10213,10219 ****
  	continue;
        /* Do not touch loop headers or blocks with abnormal predecessors.
  	 ???  This is to avoid creating valid loops here, see PR103458.
! 	 We might want to improve things to either explicitely add those
  	 loops or at least consider blocks with no backedges.  */
        if (bb->loop_father->header == bb
  	  || bb_has_abnormal_pred (bb))
--- 10277,10283 ----
  	continue;
        /* Do not touch loop headers or blocks with abnormal predecessors.
  	 ???  This is to avoid creating valid loops here, see PR103458.
! 	 We might want to improve things to either explicitly add those
  	 loops or at least consider blocks with no backedges.  */
        if (bb->loop_father->header == bb
  	  || bb_has_abnormal_pred (bb))
*************** make_forwarders_with_degenerate_phis (fu
*** 10245,10250 ****
--- 10309,10321 ----
  	      && loop_exit_edge_p (e->src->loop_father, e))
  	    continue;
  
+ 	  /* Skip ifconvertable edges when asked as we want the
+ 	     copy/constant on that edge still when going out of ssa.
+ 	     FIXME: phiopt should produce COND_EXPR but there
+ 	     are regressions with that.  */
+ 	  if (skip_ifcvtable && ifconvertable_edge (e))
+ 	    continue;
+ 
  	  tree arg = gimple_phi_arg_def (phi, i);
  	  if (!CONSTANT_CLASS_P (arg) && TREE_CODE (arg) != SSA_NAME)
  	    need_resort = true;
diff -Nrcpad gcc-16-20251214/gcc/tree-cfg.h gcc-16-20251221/gcc/tree-cfg.h
*** gcc-16-20251214/gcc/tree-cfg.h	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/gcc/tree-cfg.h	Sun Dec 21 22:32:13 2025
*************** extern edge gimple_switch_edge (function
*** 114,120 ****
  extern edge gimple_switch_default_edge (function *, gswitch *);
  extern bool cond_only_block_p (basic_block);
  extern void copy_phi_arg_into_existing_phi (edge, edge, bool = false);
! extern bool make_forwarders_with_degenerate_phis (function *);
  
  /* Return true if the LHS of a call should be removed.  */
  
--- 114,120 ----
  extern edge gimple_switch_default_edge (function *, gswitch *);
  extern bool cond_only_block_p (basic_block);
  extern void copy_phi_arg_into_existing_phi (edge, edge, bool = false);
! extern bool make_forwarders_with_degenerate_phis (function *, bool = false);
  
  /* Return true if the LHS of a call should be removed.  */
  
diff -Nrcpad gcc-16-20251214/gcc/tree-cfgcleanup.cc gcc-16-20251221/gcc/tree-cfgcleanup.cc
*** gcc-16-20251214/gcc/tree-cfgcleanup.cc	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/gcc/tree-cfgcleanup.cc	Sun Dec 21 22:32:13 2025
*************** maybe_remove_forwarder_block (basic_bloc
*** 519,524 ****
--- 519,531 ----
    bool has_phi = !gimple_seq_empty_p (phi_nodes (bb));
    basic_block dest = single_succ_edge (bb)->dest;
  
+   /* If the destination block consists of a nonlocal label or is a
+      EH landing pad, do not merge it.  */
+   if (glabel *label_stmt = safe_dyn_cast <glabel *> (first_stmt (dest)))
+     if (DECL_NONLOCAL (gimple_label_label (label_stmt))
+ 	|| EH_LANDING_PAD_NR (gimple_label_label (label_stmt)))
+     return false;
+ 
    /* If there is an abnormal edge to basic block BB, but not into
       dest, problems might occur during removal of the phi node at out
       of ssa due to overlapping live ranges of registers.
*************** execute_cleanup_cfg_post_optimizing (voi
*** 1418,1424 ****
    /* When optimizing undo the merging of forwarder blocks
       that phis for better out of ssa expansion.  */
    if (optimize)
!     make_forwarders_with_degenerate_phis (cfun);
  
    /* Make sure todo does not have cleanup cfg as we don't want
       remove the forwarder blocks we just created. cleanup cfg
--- 1425,1431 ----
    /* When optimizing undo the merging of forwarder blocks
       that phis for better out of ssa expansion.  */
    if (optimize)
!     make_forwarders_with_degenerate_phis (cfun, true);
  
    /* Make sure todo does not have cleanup cfg as we don't want
       remove the forwarder blocks we just created. cleanup cfg
diff -Nrcpad gcc-16-20251214/gcc/tree-inline.cc gcc-16-20251221/gcc/tree-inline.cc
*** gcc-16-20251214/gcc/tree-inline.cc	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/gcc/tree-inline.cc	Sun Dec 21 22:32:13 2025
*************** replace_locals_op (tree *tp, int *walk_s
*** 5892,5898 ****
        /* Before the omplower pass completes, some OMP clauses can contain
  	 sequences that are neither copied by gimple_seq_copy nor walked by
  	 walk_gimple_seq.  To make copy_gimple_seq_and_replace_locals work even
! 	 in those situations, we have to copy and process them explicitely.  */
  
        if (OMP_CLAUSE_CODE (expr) == OMP_CLAUSE_LASTPRIVATE)
  	{
--- 5892,5898 ----
        /* Before the omplower pass completes, some OMP clauses can contain
  	 sequences that are neither copied by gimple_seq_copy nor walked by
  	 walk_gimple_seq.  To make copy_gimple_seq_and_replace_locals work even
! 	 in those situations, we have to copy and process them explicitly.  */
  
        if (OMP_CLAUSE_CODE (expr) == OMP_CLAUSE_LASTPRIVATE)
  	{
diff -Nrcpad gcc-16-20251214/gcc/tree-loop-distribution.cc gcc-16-20251221/gcc/tree-loop-distribution.cc
*** gcc-16-20251214/gcc/tree-loop-distribution.cc	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/gcc/tree-loop-distribution.cc	Sun Dec 21 22:32:13 2025
*************** loop_distribution::execute (function *fu
*** 3967,3973 ****
    if (changed)
      {
        /* Destroy loop bodies that could not be reused.  Do this late as we
! 	 otherwise can end up refering to stale data in control dependences.  */
        unsigned i;
        class loop *loop;
        FOR_EACH_VEC_ELT (loops_to_be_destroyed, i, loop)
--- 3967,3974 ----
    if (changed)
      {
        /* Destroy loop bodies that could not be reused.  Do this late as we
! 	 otherwise can end up referring to stale data in control
! 	 dependences.  */
        unsigned i;
        class loop *loop;
        FOR_EACH_VEC_ELT (loops_to_be_destroyed, i, loop)
diff -Nrcpad gcc-16-20251214/gcc/tree-pretty-print.cc gcc-16-20251221/gcc/tree-pretty-print.cc
*** gcc-16-20251214/gcc/tree-pretty-print.cc	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/gcc/tree-pretty-print.cc	Sun Dec 21 22:32:13 2025
*************** dump_omp_clause (pretty_printer *pp, tre
*** 908,923 ****
        break;
  
      case OMP_CLAUSE_USES_ALLOCATORS:
!       pp_string (pp, "uses_allocators(");
!       dump_generic_node (pp, OMP_CLAUSE_USES_ALLOCATORS_ALLOCATOR (clause),
! 			 spc, flags, false);
!       pp_string (pp, ": memspace(");
        dump_generic_node (pp, OMP_CLAUSE_USES_ALLOCATORS_MEMSPACE (clause),
  			 spc, flags, false);
        pp_string (pp, "), traits(");
        dump_generic_node (pp, OMP_CLAUSE_USES_ALLOCATORS_TRAITS (clause),
  			 spc, flags, false);
!       pp_right_paren (pp);
        pp_right_paren (pp);
        break;
  
--- 908,922 ----
        break;
  
      case OMP_CLAUSE_USES_ALLOCATORS:
!       pp_string (pp, "uses_allocators(memspace(");
        dump_generic_node (pp, OMP_CLAUSE_USES_ALLOCATORS_MEMSPACE (clause),
  			 spc, flags, false);
        pp_string (pp, "), traits(");
        dump_generic_node (pp, OMP_CLAUSE_USES_ALLOCATORS_TRAITS (clause),
  			 spc, flags, false);
!       pp_string (pp, ") : ");
!       dump_generic_node (pp, OMP_CLAUSE_USES_ALLOCATORS_ALLOCATOR (clause),
! 			 spc, flags, false);
        pp_right_paren (pp);
        break;
  
diff -Nrcpad gcc-16-20251214/gcc/tree-sra.cc gcc-16-20251221/gcc/tree-sra.cc
*** gcc-16-20251214/gcc/tree-sra.cc	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/gcc/tree-sra.cc	Sun Dec 21 22:32:13 2025
*************** generate_subtree_deferred_init (struct a
*** 4614,4620 ****
     there is one, also replace the RHS call to a call to .DEFERRED_INIT of
     the corresponding scalar relacement variable.  Examine the subtree and
     do the scalar replacements in the subtree too.  STMT is the call, GSI is
!    the statment iterator to place newly created statement.  */
  
  static enum assignment_mod_result
  sra_modify_deferred_init (gimple *stmt, gimple_stmt_iterator *gsi)
--- 4614,4620 ----
     there is one, also replace the RHS call to a call to .DEFERRED_INIT of
     the corresponding scalar relacement variable.  Examine the subtree and
     do the scalar replacements in the subtree too.  STMT is the call, GSI is
!    the statement iterator to place newly created statement.  */
  
  static enum assignment_mod_result
  sra_modify_deferred_init (gimple *stmt, gimple_stmt_iterator *gsi)
diff -Nrcpad gcc-16-20251214/gcc/tree-ssa-alias.cc gcc-16-20251221/gcc/tree-ssa-alias.cc
*** gcc-16-20251214/gcc/tree-ssa-alias.cc	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/gcc/tree-ssa-alias.cc	Sun Dec 21 22:32:13 2025
*************** bool
*** 423,429 ****
  ptrs_compare_unequal (tree ptr1, tree ptr2)
  {
    /* First resolve the pointers down to a SSA name pointer base or
!      a VAR_DECL, PARM_DECL or RESULT_DECL.  This explicitely does
       not yet try to handle LABEL_DECLs, FUNCTION_DECLs, CONST_DECLs
       or STRING_CSTs which needs points-to adjustments to track them
       in the points-to sets.  */
--- 423,429 ----
  ptrs_compare_unequal (tree ptr1, tree ptr2)
  {
    /* First resolve the pointers down to a SSA name pointer base or
!      a VAR_DECL, PARM_DECL or RESULT_DECL.  This explicitly does
       not yet try to handle LABEL_DECLs, FUNCTION_DECLs, CONST_DECLs
       or STRING_CSTs which needs points-to adjustments to track them
       in the points-to sets.  */
diff -Nrcpad gcc-16-20251214/gcc/tree-ssa-forwprop.cc gcc-16-20251221/gcc/tree-ssa-forwprop.cc
*** gcc-16-20251214/gcc/tree-ssa-forwprop.cc	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/gcc/tree-ssa-forwprop.cc	Sun Dec 21 22:32:14 2025
*************** struct _vec_perm_simplify_seq
*** 195,201 ****
    gassign *v_2_stmt;
    gassign *v_x_stmt;
    gassign *v_y_stmt;
!   /* Final permute statment.  */
    gassign *stmt;
    /* New selector indices for stmt.  */
    tree new_sel;
--- 195,201 ----
    gassign *v_2_stmt;
    gassign *v_x_stmt;
    gassign *v_y_stmt;
!   /* Final permute statement.  */
    gassign *stmt;
    /* New selector indices for stmt.  */
    tree new_sel;
*************** simplify_vector_constructor (gimple_stmt
*** 3848,3853 ****
--- 3848,3854 ----
  
    orig[0] = NULL;
    orig[1] = NULL;
+   tree orig_elem_type[2] = {};
    conv_code = ERROR_MARK;
    bool maybe_ident = true;
    bool maybe_blend[2] = { true, true };
*************** simplify_vector_constructor (gimple_stmt
*** 3902,3907 ****
--- 3903,3913 ----
  	  if (j < 2)
  	    {
  	      orig[j] = ref;
+ 	      /* Track what element type was actually extracted (which may
+ 		 differ in signedness from the vector's element type due to
+ 		 tree_nop_conversion_p).  */
+ 	      if (!orig_elem_type[j])
+ 		orig_elem_type[j] = TREE_TYPE (op1);
  	      if (elem != i || j != 0)
  		maybe_ident = false;
  	      if (elem != i)
*************** simplify_vector_constructor (gimple_stmt
*** 4011,4016 ****
--- 4017,4025 ----
  	  if (CONVERT_EXPR_CODE_P (conv_code)
  	      && (2 * TYPE_PRECISION (TREE_TYPE (TREE_TYPE (orig[0])))
  		  == TYPE_PRECISION (TREE_TYPE (type)))
+ 	      && orig_elem_type[0]
+ 	      && useless_type_conversion_p (orig_elem_type[0],
+ 					    TREE_TYPE (type))
  	      && mode_for_vector (as_a <scalar_mode>
  				  (TYPE_MODE (TREE_TYPE (TREE_TYPE (orig[0])))),
  				  nelts * 2).exists ()
*************** simplify_vector_constructor (gimple_stmt
*** 4050,4055 ****
--- 4059,4067 ----
  	  else if (CONVERT_EXPR_CODE_P (conv_code)
  		   && (TYPE_PRECISION (TREE_TYPE (TREE_TYPE (orig[0])))
  		       == 2 * TYPE_PRECISION (TREE_TYPE (type)))
+ 		   && orig_elem_type[0]
+ 		   && useless_type_conversion_p (orig_elem_type[0],
+ 						 TREE_TYPE (type))
  		   && mode_for_vector (as_a <scalar_mode>
  				         (TYPE_MODE
  					   (TREE_TYPE (TREE_TYPE (orig[0])))),
*************** narrow_vec_perm_simplify_seq (const vec_
*** 4709,4715 ****
    gassign *stmt = seq->stmt;
    if (dump_file && (dump_flags & TDF_DETAILS))
      {
!       fprintf (dump_file, "Updating VEC_PERM statment:\n");
        fprintf (dump_file, "Old stmt: ");
        print_gimple_stmt (dump_file, stmt, 0);
      }
--- 4721,4727 ----
    gassign *stmt = seq->stmt;
    if (dump_file && (dump_flags & TDF_DETAILS))
      {
!       fprintf (dump_file, "Updating VEC_PERM statement:\n");
        fprintf (dump_file, "Old stmt: ");
        print_gimple_stmt (dump_file, stmt, 0);
      }
*************** blend_vec_perm_simplify_seqs (vec_perm_s
*** 4955,4961 ****
    /* Adjust seq2->stmt: copy RHS1/RHS2 from seq1->stmt and set new sel.  */
    if (dump_file && (dump_flags & TDF_DETAILS))
      {
!       fprintf (dump_file, "Updating VEC_PERM statment:\n");
        fprintf (dump_file, "Old stmt: ");
        print_gimple_stmt (dump_file, seq2->stmt, 0);
      }
--- 4967,4973 ----
    /* Adjust seq2->stmt: copy RHS1/RHS2 from seq1->stmt and set new sel.  */
    if (dump_file && (dump_flags & TDF_DETAILS))
      {
!       fprintf (dump_file, "Updating VEC_PERM statement:\n");
        fprintf (dump_file, "Old stmt: ");
        print_gimple_stmt (dump_file, seq2->stmt, 0);
      }
*************** blend_vec_perm_simplify_seqs (vec_perm_s
*** 4976,4982 ****
    /* Adjust seq1->v_1_stmt: copy RHS2 from seq2->v_1_stmt and set new sel.  */
    if (dump_file && (dump_flags & TDF_DETAILS))
      {
!       fprintf (dump_file, "Updating VEC_PERM statment:\n");
        fprintf (dump_file, "Old stmt: ");
        print_gimple_stmt (dump_file, seq1->v_1_stmt, 0);
      }
--- 4988,4994 ----
    /* Adjust seq1->v_1_stmt: copy RHS2 from seq2->v_1_stmt and set new sel.  */
    if (dump_file && (dump_flags & TDF_DETAILS))
      {
!       fprintf (dump_file, "Updating VEC_PERM statement:\n");
        fprintf (dump_file, "Old stmt: ");
        print_gimple_stmt (dump_file, seq1->v_1_stmt, 0);
      }
*************** blend_vec_perm_simplify_seqs (vec_perm_s
*** 4996,5002 ****
    /* Adjust seq1->v_2_stmt: copy RHS2 from seq2->v_2_stmt and set new sel.  */
    if (dump_file && (dump_flags & TDF_DETAILS))
      {
!       fprintf (dump_file, "Updating VEC_PERM statment:\n");
        fprintf (dump_file, "Old stmt: ");
        print_gimple_stmt (dump_file, seq1->v_2_stmt, 0);
      }
--- 5008,5014 ----
    /* Adjust seq1->v_2_stmt: copy RHS2 from seq2->v_2_stmt and set new sel.  */
    if (dump_file && (dump_flags & TDF_DETAILS))
      {
!       fprintf (dump_file, "Updating VEC_PERM statement:\n");
        fprintf (dump_file, "Old stmt: ");
        print_gimple_stmt (dump_file, seq1->v_2_stmt, 0);
      }
diff -Nrcpad gcc-16-20251214/gcc/tree-ssa-ifcombine.cc gcc-16-20251221/gcc/tree-ssa-ifcombine.cc
*** gcc-16-20251214/gcc/tree-ssa-ifcombine.cc	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/gcc/tree-ssa-ifcombine.cc	Sun Dec 21 22:32:14 2025
*************** ifcombine_ifandif (basic_block inner_con
*** 834,849 ****
  
        /* Do it.  */
        gsi = gsi_for_stmt (inner_cond);
!       t = fold_build2 (LSHIFT_EXPR, TREE_TYPE (name1),
! 		       build_int_cst (TREE_TYPE (name1), 1), bit1);
!       t2 = fold_build2 (LSHIFT_EXPR, TREE_TYPE (name1),
! 		        build_int_cst (TREE_TYPE (name1), 1), bit2);
!       t = fold_build2 (BIT_IOR_EXPR, TREE_TYPE (name1), t, t2);
!       t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
! 				    true, GSI_SAME_STMT);
!       t2 = fold_build2 (BIT_AND_EXPR, TREE_TYPE (name1), name1, t);
!       t2 = force_gimple_operand_gsi (&gsi, t2, true, NULL_TREE,
! 				     true, GSI_SAME_STMT);
  
        t = fold_build2 (EQ_EXPR, boolean_type_node, t2, t);
  
--- 834,851 ----
  
        /* Do it.  */
        gsi = gsi_for_stmt (inner_cond);
!       location_t loc1 = gimple_location (inner_cond);
!       location_t loc2 = gimple_location (outer_cond);
!       t = gimple_build (&gsi, true, GSI_SAME_STMT, loc1, LSHIFT_EXPR,
! 			TREE_TYPE (name1),
! 			build_int_cst (TREE_TYPE (name1), 1), bit1);
!       t2 = gimple_build (&gsi, true, GSI_SAME_STMT, loc2, LSHIFT_EXPR,
! 			 TREE_TYPE (name1),
! 			 build_int_cst (TREE_TYPE (name1), 1), bit2);
!       t = gimple_build (&gsi, true, GSI_SAME_STMT, loc1, BIT_IOR_EXPR,
! 			TREE_TYPE (name1), t, t2);
!       t2 = gimple_build (&gsi, true, GSI_SAME_STMT, loc1, BIT_AND_EXPR,
! 			 TREE_TYPE (name1), name1, t);
  
        t = fold_build2 (EQ_EXPR, boolean_type_node, t2, t);
  
diff -Nrcpad gcc-16-20251214/gcc/tree-ssa-loop-ch.cc gcc-16-20251221/gcc/tree-ssa-loop-ch.cc
*** gcc-16-20251214/gcc/tree-ssa-loop-ch.cc	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/gcc/tree-ssa-loop-ch.cc	Sun Dec 21 22:32:14 2025
*************** should_duplicate_loop_header_p (basic_bl
*** 474,486 ****
        bool hasone = false;
        FOR_EACH_EDGE (e, ei, header->succs)
  	if (loop_exit_edge_p (loop, e)
! 	    && (probably_never_executed_edge_p (cfun, e)
! 		/* We want to rule out paths to noreturns but not
! 		   low probabilities resulting from adjustments
! 		   or combining.
! 		   FIXME: once we have better quality tracking,
! 		   make this more robust.  */
! 		|| e->probability <= profile_probability::very_unlikely ()))
  	  {
  	    hasone = true;
  	    if (dump_file && (dump_flags & TDF_DETAILS))
--- 474,480 ----
        bool hasone = false;
        FOR_EACH_EDGE (e, ei, header->succs)
  	if (loop_exit_edge_p (loop, e)
! 	    && probably_never_executed_edge_p (cfun, e))
  	  {
  	    hasone = true;
  	    if (dump_file && (dump_flags & TDF_DETAILS))
diff -Nrcpad gcc-16-20251214/gcc/tree-ssa-pre.cc gcc-16-20251221/gcc/tree-ssa-pre.cc
*** gcc-16-20251214/gcc/tree-ssa-pre.cc	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/gcc/tree-ssa-pre.cc	Sun Dec 21 22:32:14 2025
*************** compute_antic_aux (basic_block block, bo
*** 2131,2137 ****
  	      /* Unvisited successors get their ANTIC_IN replaced by the
  		 maximal set to arrive at a maximum ANTIC_IN solution.
  		 We can ignore them in the intersection operation and thus
! 		 need not explicitely represent that maximum solution.  */
  	      any_max_on_edge = true;
  	      if (dump_file && (dump_flags & TDF_DETAILS))
  		fprintf (dump_file, "ANTIC_IN is MAX on %d->%d\n",
--- 2131,2137 ----
  	      /* Unvisited successors get their ANTIC_IN replaced by the
  		 maximal set to arrive at a maximum ANTIC_IN solution.
  		 We can ignore them in the intersection operation and thus
! 		 need not explicitly represent that maximum solution.  */
  	      any_max_on_edge = true;
  	      if (dump_file && (dump_flags & TDF_DETAILS))
  		fprintf (dump_file, "ANTIC_IN is MAX on %d->%d\n",
diff -Nrcpad gcc-16-20251214/gcc/tree-vect-data-refs.cc gcc-16-20251221/gcc/tree-vect-data-refs.cc
*** gcc-16-20251214/gcc/tree-vect-data-refs.cc	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/gcc/tree-vect-data-refs.cc	Sun Dec 21 22:32:14 2025
*************** vect_enhance_data_refs_alignment (loop_v
*** 2590,2601 ****
  
    /* Check if we can possibly peel the loop.  */
    if (!vect_can_advance_ivs_p (loop_vinfo)
!       || !slpeel_can_duplicate_loop_p (loop, LOOP_VINFO_IV_EXIT (loop_vinfo),
  				       loop_preheader_edge (loop))
        || loop->inner
        /* We don't currently maintaing the LCSSA for prologue peeled inversed
  	 loops.  */
!       || LOOP_VINFO_EARLY_BREAKS_VECT_PEELED (loop_vinfo))
      do_peeling = false;
  
    struct _vect_peel_extended_info peel_for_known_alignment;
--- 2590,2602 ----
  
    /* Check if we can possibly peel the loop.  */
    if (!vect_can_advance_ivs_p (loop_vinfo)
!       || !slpeel_can_duplicate_loop_p (loop, LOOP_VINFO_MAIN_EXIT (loop_vinfo),
  				       loop_preheader_edge (loop))
        || loop->inner
        /* We don't currently maintaing the LCSSA for prologue peeled inversed
  	 loops.  */
!       || (LOOP_VINFO_EARLY_BREAKS_VECT_PEELED (loop_vinfo)
! 	  && !LOOP_VINFO_NITERS_UNCOUNTED_P (loop_vinfo)))
      do_peeling = false;
  
    struct _vect_peel_extended_info peel_for_known_alignment;
*************** vect_prune_runtime_alias_test_list (loop
*** 4324,4330 ****
  	{
  	  if (!operand_equal_p (DR_STEP (dr_info_a->dr),
  				DR_STEP (dr_info_b->dr), 0))
! 	    length_factor = scalar_loop_iters;
  	  else
  	    length_factor = size_int (vect_factor);
  	  segment_length_a = vect_vfa_segment_size (dr_info_a, length_factor);
--- 4325,4337 ----
  	{
  	  if (!operand_equal_p (DR_STEP (dr_info_a->dr),
  				DR_STEP (dr_info_b->dr), 0))
! 	    {
! 	      length_factor = scalar_loop_iters;
! 	      if (TREE_CODE (length_factor) == SCEV_NOT_KNOWN)
! 		return opt_result::failure_at (vect_location,
! 					       "Unsupported alias check on"
! 					       " uncounted loop\n");
! 	    }
  	  else
  	    length_factor = size_int (vect_factor);
  	  segment_length_a = vect_vfa_segment_size (dr_info_a, length_factor);
*************** vect_gather_scatter_fn_p (vec_info *vinf
*** 4709,4721 ****
        unsigned int precision
  	= TYPE_PRECISION (TREE_TYPE (configs[i].offset_vectype));
        if (configs[i].scale < scale
! 	  && precision >= needed_precision
! 	  && (supportable_convert_operation (CONVERT_EXPR,
! 					    configs[i].offset_vectype,
! 					    offset_vectype, &tmp)
! 	      || (needed_precision == offset_precision
! 		  && tree_nop_conversion_p (configs[i].offset_vectype,
! 					    offset_vectype))))
  	{
  	  *ifn_out = configs[i].ifn;
  	  *offset_vectype_out = configs[i].offset_vectype;
--- 4716,4724 ----
        unsigned int precision
  	= TYPE_PRECISION (TREE_TYPE (configs[i].offset_vectype));
        if (configs[i].scale < scale
! 	  && TYPE_SIGN (configs[i].offset_vectype)
! 	     == TYPE_SIGN (offset_vectype)
! 	  && precision >= needed_precision)
  	{
  	  *ifn_out = configs[i].ifn;
  	  *offset_vectype_out = configs[i].offset_vectype;
diff -Nrcpad gcc-16-20251214/gcc/tree-vect-loop-manip.cc gcc-16-20251221/gcc/tree-vect-loop-manip.cc
*** gcc-16-20251214/gcc/tree-vect-loop-manip.cc	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/gcc/tree-vect-loop-manip.cc	Sun Dec 21 22:32:14 2025
*************** vect_set_loop_controls_directly (class l
*** 545,551 ****
    tree index_before_incr, index_after_incr;
    gimple_stmt_iterator incr_gsi;
    bool insert_after;
!   edge exit_e = LOOP_VINFO_IV_EXIT (loop_vinfo);
    vect_iv_increment_position (exit_e, &incr_gsi, &insert_after);
    if (LOOP_VINFO_USING_DECREMENTING_IV_P (loop_vinfo))
      {
--- 545,551 ----
    tree index_before_incr, index_after_incr;
    gimple_stmt_iterator incr_gsi;
    bool insert_after;
!   edge exit_e = LOOP_VINFO_MAIN_EXIT (loop_vinfo);
    vect_iv_increment_position (exit_e, &incr_gsi, &insert_after);
    if (LOOP_VINFO_USING_DECREMENTING_IV_P (loop_vinfo))
      {
*************** slpeel_tree_duplicate_loop_to_edge_cfg (
*** 1481,1487 ****
  					class loop *scalar_loop,
  					edge scalar_exit, edge e, edge *new_e,
  					bool flow_loops,
! 					vec<basic_block> *updated_doms)
  {
    class loop *new_loop;
    basic_block *new_bbs, *bbs, *pbbs;
--- 1481,1488 ----
  					class loop *scalar_loop,
  					edge scalar_exit, edge e, edge *new_e,
  					bool flow_loops,
! 					vec<basic_block> *updated_doms,
! 					bool uncounted_p, bool create_main_e)
  {
    class loop *new_loop;
    basic_block *new_bbs, *bbs, *pbbs;
*************** slpeel_tree_duplicate_loop_to_edge_cfg (
*** 1652,1658 ****
  	 the continuation values into the epilogue header.
  	 Do not bother with exit PHIs for the early exits but
  	 their live virtual operand.  We'll fix up things below.  */
!       if (multiple_exits_p)
  	{
  	  edge loop_e = single_succ_edge (new_preheader);
  	  new_preheader = split_edge (loop_e);
--- 1653,1659 ----
  	 the continuation values into the epilogue header.
  	 Do not bother with exit PHIs for the early exits but
  	 their live virtual operand.  We'll fix up things below.  */
!       if (multiple_exits_p || uncounted_p)
  	{
  	  edge loop_e = single_succ_edge (new_preheader);
  	  new_preheader = split_edge (loop_e);
*************** slpeel_tree_duplicate_loop_to_edge_cfg (
*** 1707,1713 ****
        if (flow_loops)
  	{
  	  edge loop_entry = single_succ_edge (new_preheader);
! 	  bool peeled_iters = single_pred (loop->latch) != loop_exit->src;
  
  	  /* Record the new SSA names in the cache so that we can skip
  	     materializing them again when we fill in the rest of the LC SSA
--- 1708,1715 ----
        if (flow_loops)
  	{
  	  edge loop_entry = single_succ_edge (new_preheader);
! 	  bool peeled_iters = (uncounted_p
! 			       || single_pred (loop->latch) != loop_exit->src);
  
  	  /* Record the new SSA names in the cache so that we can skip
  	     materializing them again when we fill in the rest of the LC SSA
*************** slpeel_tree_duplicate_loop_to_edge_cfg (
*** 1737,1743 ****
  
  	  /* Create the merge PHI nodes in new_preheader and populate the
  	     arguments for the exits.  */
! 	  if (multiple_exits_p)
  	    {
  	      for (auto gsi_from = gsi_start_phis (loop->header),
  		   gsi_to = gsi_start_phis (new_loop->header);
--- 1739,1745 ----
  
  	  /* Create the merge PHI nodes in new_preheader and populate the
  	     arguments for the exits.  */
! 	  if (multiple_exits_p || uncounted_p)
  	    {
  	      for (auto gsi_from = gsi_start_phis (loop->header),
  		   gsi_to = gsi_start_phis (new_loop->header);
*************** slpeel_tree_duplicate_loop_to_edge_cfg (
*** 1789,1795 ****
--- 1791,1800 ----
  		  /* And adjust the epilog entry value.  */
  		  adjust_phi_and_debug_stmts (to_phi, loop_entry, new_res);
  		}
+ 	    }
  
+ 	  if (multiple_exits_p)
+ 	    {
  	      /* After creating the merge PHIs handle the early exits those
  		 should use the values at the start of the loop.  */
  	      for (auto gsi_from = gsi_start_phis (loop->header),
*************** slpeel_tree_duplicate_loop_to_edge_cfg (
*** 1826,1832 ****
  	  /* For the single exit case only create the missing LC PHI nodes
  	     for the continuation of the loop IVs that are not also already
  	     reductions and thus had LC PHI nodes on the exit already.  */
! 	  else
  	    {
  	      for (auto gsi_from = gsi_start_phis (loop->header),
  		   gsi_to = gsi_start_phis (new_loop->header);
--- 1831,1837 ----
  	  /* For the single exit case only create the missing LC PHI nodes
  	     for the continuation of the loop IVs that are not also already
  	     reductions and thus had LC PHI nodes on the exit already.  */
! 	  if (!multiple_exits_p && !uncounted_p)
  	    {
  	      for (auto gsi_from = gsi_start_phis (loop->header),
  		   gsi_to = gsi_start_phis (new_loop->header);
*************** slpeel_tree_duplicate_loop_to_edge_cfg (
*** 1869,1875 ****
        /* Finally after wiring the new epilogue we need to update its main exit
  	 to the original function exit we recorded.  Other exits are already
  	 correct.  */
!       if (multiple_exits_p)
  	{
  	  class loop *update_loop = new_loop;
  	  doms = get_all_dominated_blocks (CDI_DOMINATORS, loop->header);
--- 1874,1880 ----
        /* Finally after wiring the new epilogue we need to update its main exit
  	 to the original function exit we recorded.  Other exits are already
  	 correct.  */
!       if (multiple_exits_p || uncounted_p)
  	{
  	  class loop *update_loop = new_loop;
  	  doms = get_all_dominated_blocks (CDI_DOMINATORS, loop->header);
*************** slpeel_tree_duplicate_loop_to_edge_cfg (
*** 1935,1940 ****
--- 1940,1990 ----
        flush_pending_stmts (entry_e);
        set_immediate_dominator (CDI_DOMINATORS, new_preheader, entry_e->src);
  
+ 
+       /* `vect_set_loop_condition' replaces the condition in the main exit of
+ 	 loop.  For counted loops, this is the IV counting exit, so in the case
+ 	 of the prolog loop, we are replacing the old IV counting exit limit of
+ 	 total loop niters for the new limit of the prolog niters, as desired.
+ 	 For uncounted loops, we don't have an IV-counting exit to replace, so
+ 	 we add a dummy exit to be consumed by `vect_set_loop_condition' later
+ 	 on.  */
+       if (create_main_e)
+ 	{
+ 	  edge to_latch_e = single_pred_edge (new_loop->latch);
+ 	  bool latch_is_false = to_latch_e->flags & EDGE_FALSE_VALUE ? true
+ 								     : false;
+ 
+ 	  /* Add new bb for duplicate exit.  */
+ 	  basic_block bbcond = split_edge (to_latch_e);
+ 	  gimple_stmt_iterator a = gsi_last_bb (bbcond);
+ 
+ 	  /* Fix flags for the edge leading to the latch.  */
+ 	  to_latch_e = find_edge (bbcond, new_loop->latch);
+ 	  to_latch_e->flags &= ~EDGE_FALLTHRU;
+ 	  to_latch_e->flags |= latch_is_false ? EDGE_FALSE_VALUE
+ 					      : EDGE_TRUE_VALUE;
+ 
+ 	  /* Build the condition.  */
+ 	  tree cone = build_int_cst (sizetype, 1);
+ 	  tree czero = build_int_cst (sizetype, 0);
+ 	  gcond *cond_copy = gimple_build_cond (NE_EXPR, cone, czero, NULL_TREE,
+ 						NULL_TREE);
+ 
+ 	  gsi_insert_after (&a, cond_copy, GSI_NEW_STMT);
+ 
+ 	  /* Add edge for exiting the loop via new condition.  */
+ 	  edge dup_exit = make_edge (bbcond, new_exit->dest, latch_is_false
+ 				? EDGE_TRUE_VALUE : EDGE_FALSE_VALUE);
+ 
+ 	  profile_probability probability = profile_probability::even ();
+ 	  to_latch_e->probability = dup_exit->probability = probability;
+ 
+ 	  set_immediate_dominator (CDI_DOMINATORS, dup_exit->src,
+ 				   new_exit->src);
+ 	  new_exit = dup_exit;
+ 	  *new_e = new_exit;
+ 	}
+ 
        redirect_edge_and_branch_force (new_exit, preheader);
        flush_pending_stmts (new_exit);
        set_immediate_dominator (CDI_DOMINATORS, preheader, new_exit->src);
*************** slpeel_tree_duplicate_loop_to_edge_cfg (
*** 1948,1958 ****
  			       loop_preheader_edge (new_loop)->src);
  
        /* Update dominators for multiple exits.  */
!       if (multiple_exits_p)
  	{
  	  for (edge alt_e : loop_exits)
  	    {
! 	      if (alt_e == loop_exit)
  		continue;
  	      basic_block old_dom
  		= get_immediate_dominator (CDI_DOMINATORS, alt_e->dest);
--- 1998,2008 ----
  			       loop_preheader_edge (new_loop)->src);
  
        /* Update dominators for multiple exits.  */
!       if (multiple_exits_p || create_main_e)
  	{
  	  for (edge alt_e : loop_exits)
  	    {
! 	      if ((alt_e == loop_exit) && !create_main_e)
  		continue;
  	      basic_block old_dom
  		= get_immediate_dominator (CDI_DOMINATORS, alt_e->dest);
*************** slpeel_tree_duplicate_loop_to_edge_cfg (
*** 1969,1974 ****
--- 2019,2033 ----
  		}
  	    }
  	}
+ 
+       /* When loop_exit != scalar_exit due to if-conversion loop versioning,
+ 	 the `scalar_exit' now has two incoming edges, one from the if-converted
+ 	 and one from the peeled prolog loop.  It is therefore dominated by a
+ 	 common block between these.  Update its dominator accordingly.  */
+       if (create_main_e && loop_exit != scalar_exit)
+ 	set_immediate_dominator (CDI_DOMINATORS, scalar_exit->dest,
+ 				 recompute_dominator (CDI_DOMINATORS,
+ 						      scalar_exit->dest));
      }
  
    free (new_bbs);
*************** vect_gen_prolog_loop_niters (loop_vec_in
*** 2550,2556 ****
  {
    dr_vec_info *dr_info = LOOP_VINFO_UNALIGNED_DR (loop_vinfo);
    tree var;
!   tree niters_type = TREE_TYPE (LOOP_VINFO_NITERS (loop_vinfo));
    gimple_seq stmts = NULL, new_stmts = NULL;
    tree iters, iters_name;
    stmt_vec_info stmt_info = dr_info->stmt;
--- 2609,2618 ----
  {
    dr_vec_info *dr_info = LOOP_VINFO_UNALIGNED_DR (loop_vinfo);
    tree var;
!   tree niters_type
!     = LOOP_VINFO_NITERS_UNCOUNTED_P (loop_vinfo) ? sizetype
! 						 : TREE_TYPE (LOOP_VINFO_NITERS
! 							      (loop_vinfo));
    gimple_seq stmts = NULL, new_stmts = NULL;
    tree iters, iters_name;
    stmt_vec_info stmt_info = dr_info->stmt;
*************** vect_prepare_for_masked_peels (loop_vec_
*** 2729,2734 ****
--- 2791,2798 ----
  tree
  vect_build_loop_niters (loop_vec_info loop_vinfo, bool *new_var_p)
  {
+   if (LOOP_VINFO_NITERS_UNCOUNTED_P (loop_vinfo))
+     return NULL_TREE;
    tree ni = unshare_expr (LOOP_VINFO_NITERS (loop_vinfo));
    if (TREE_CODE (ni) == INTEGER_CST)
      return ni;
*************** vect_gen_vector_loop_niters (loop_vec_in
*** 2830,2836 ****
  			     bool niters_no_overflow)
  {
    tree ni_minus_gap, var;
!   tree niters_vector, step_vector, type = TREE_TYPE (niters);
    poly_uint64 vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
    edge pe = loop_preheader_edge (LOOP_VINFO_LOOP (loop_vinfo));
  
--- 2894,2901 ----
  			     bool niters_no_overflow)
  {
    tree ni_minus_gap, var;
!   tree niters_vector, step_vector;
!   tree type = niters ? TREE_TYPE (niters) : sizetype;
    poly_uint64 vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
    edge pe = loop_preheader_edge (LOOP_VINFO_LOOP (loop_vinfo));
  
*************** vect_gen_vector_loop_niters_mult_vf (loo
*** 2945,2951 ****
    int vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo).to_constant ();
    tree type = TREE_TYPE (niters_vector);
    tree tree_vf = build_int_cst (type, vf);
!   basic_block exit_bb = LOOP_VINFO_IV_EXIT (loop_vinfo)->dest;
  
    gcc_assert (niters_vector_mult_vf_ptr != NULL);
    tree niters_vector_mult_vf = fold_build2 (MULT_EXPR, type,
--- 3010,3016 ----
    int vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo).to_constant ();
    tree type = TREE_TYPE (niters_vector);
    tree tree_vf = build_int_cst (type, vf);
!   basic_block exit_bb = LOOP_VINFO_MAIN_EXIT (loop_vinfo)->dest;
  
    gcc_assert (niters_vector_mult_vf_ptr != NULL);
    tree niters_vector_mult_vf = fold_build2 (MULT_EXPR, type,
*************** vect_do_peeling (loop_vec_info loop_vinf
*** 3174,3185 ****
  		 tree *advance)
  {
    edge e, guard_e;
!   tree type = TREE_TYPE (niters), guard_cond;
    basic_block guard_bb, guard_to;
    profile_probability prob_prolog, prob_vector, prob_epilog;
    int estimated_vf;
    int prolog_peeling = 0;
    bool vect_epilogues = loop_vinfo->epilogue_vinfo != NULL;
  
    if (!vect_use_loop_mask_for_alignment_p (loop_vinfo))
      prolog_peeling = LOOP_VINFO_PEELING_FOR_ALIGNMENT (loop_vinfo);
--- 3239,3252 ----
  		 tree *advance)
  {
    edge e, guard_e;
!   tree type = niters ? TREE_TYPE (niters) : sizetype;
!   tree guard_cond;
    basic_block guard_bb, guard_to;
    profile_probability prob_prolog, prob_vector, prob_epilog;
    int estimated_vf;
    int prolog_peeling = 0;
    bool vect_epilogues = loop_vinfo->epilogue_vinfo != NULL;
+   bool uncounted_p = LOOP_VINFO_NITERS_UNCOUNTED_P (loop_vinfo);
  
    if (!vect_use_loop_mask_for_alignment_p (loop_vinfo))
      prolog_peeling = LOOP_VINFO_PEELING_FOR_ALIGNMENT (loop_vinfo);
*************** vect_do_peeling (loop_vec_info loop_vinf
*** 3204,3210 ****
      return NULL;
  
    /* Before doing any peeling make sure to reset debug binds outside of
!      the loop refering to defs not in LC SSA.  */
    class loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
    for (unsigned i = 0; i < loop->num_nodes; ++i)
      {
--- 3271,3277 ----
      return NULL;
  
    /* Before doing any peeling make sure to reset debug binds outside of
!      the loop referring to defs not in LC SSA.  */
    class loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
    for (unsigned i = 0; i < loop->num_nodes; ++i)
      {
*************** vect_do_peeling (loop_vec_info loop_vinf
*** 3320,3330 ****
       because we have asserted that there are enough scalar iterations to enter
       the main loop, so this skip is not necessary.  When we are versioning then
       we only add such a skip if we have chosen to vectorize the epilogue.  */
!   bool skip_vector = (LOOP_VINFO_NITERS_KNOWN_P (loop_vinfo)
! 		      ? maybe_lt (LOOP_VINFO_INT_NITERS (loop_vinfo),
! 				  bound_prolog + bound_epilog)
! 		      : (!LOOP_VINFO_USE_VERSIONING_WITHOUT_PEELING (loop_vinfo)
! 			 || vect_epilogues));
  
    /* Epilog loop must be executed if the number of iterations for epilog
       loop is known at compile time, otherwise we need to add a check at
--- 3387,3399 ----
       because we have asserted that there are enough scalar iterations to enter
       the main loop, so this skip is not necessary.  When we are versioning then
       we only add such a skip if we have chosen to vectorize the epilogue.  */
!   bool skip_vector = false;
!   if (!uncounted_p)
!     skip_vector = (LOOP_VINFO_NITERS_KNOWN_P (loop_vinfo)
! 		   ? maybe_lt (LOOP_VINFO_INT_NITERS (loop_vinfo),
! 			       bound_prolog + bound_epilog)
! 		   : (!LOOP_VINFO_USE_VERSIONING_WITHOUT_PEELING (loop_vinfo)
! 		      || vect_epilogues));
  
    /* Epilog loop must be executed if the number of iterations for epilog
       loop is known at compile time, otherwise we need to add a check at
*************** vect_do_peeling (loop_vec_info loop_vinf
*** 3372,3394 ****
  	 use the original scalar loop as remaining epilogue if necessary.  */
        LOOP_VINFO_SCALAR_LOOP (epilogue_vinfo)
  	= LOOP_VINFO_SCALAR_LOOP (loop_vinfo);
!       LOOP_VINFO_SCALAR_IV_EXIT (epilogue_vinfo)
! 	= LOOP_VINFO_SCALAR_IV_EXIT (loop_vinfo);
      }
  
    if (prolog_peeling)
      {
        e = loop_preheader_edge (loop);
!       edge exit_e = LOOP_VINFO_IV_EXIT (loop_vinfo);
        gcc_checking_assert (slpeel_can_duplicate_loop_p (loop, exit_e, e)
! 			   && !LOOP_VINFO_EARLY_BREAKS_VECT_PEELED (loop_vinfo));
  
        /* Peel prolog and put it on preheader edge of loop.  */
!       edge scalar_e = LOOP_VINFO_SCALAR_IV_EXIT (loop_vinfo);
        edge prolog_e = NULL;
        prolog = slpeel_tree_duplicate_loop_to_edge_cfg (loop, exit_e,
  						       scalar_loop, scalar_e,
! 						       e, &prolog_e);
        gcc_assert (prolog);
        prolog->force_vectorize = false;
  
--- 3441,3466 ----
  	 use the original scalar loop as remaining epilogue if necessary.  */
        LOOP_VINFO_SCALAR_LOOP (epilogue_vinfo)
  	= LOOP_VINFO_SCALAR_LOOP (loop_vinfo);
!       LOOP_VINFO_SCALAR_MAIN_EXIT (epilogue_vinfo)
! 	= LOOP_VINFO_SCALAR_MAIN_EXIT (loop_vinfo);
      }
  
    if (prolog_peeling)
      {
        e = loop_preheader_edge (loop);
!       edge exit_e = LOOP_VINFO_MAIN_EXIT (loop_vinfo);
        gcc_checking_assert (slpeel_can_duplicate_loop_p (loop, exit_e, e)
! 			   && (!LOOP_VINFO_EARLY_BREAKS_VECT_PEELED (loop_vinfo)
! 			       || uncounted_p));
  
        /* Peel prolog and put it on preheader edge of loop.  */
!       edge scalar_e = LOOP_VINFO_SCALAR_MAIN_EXIT (loop_vinfo);
        edge prolog_e = NULL;
        prolog = slpeel_tree_duplicate_loop_to_edge_cfg (loop, exit_e,
  						       scalar_loop, scalar_e,
! 						       e, &prolog_e, true, NULL,
! 						       false, uncounted_p);
! 
        gcc_assert (prolog);
        prolog->force_vectorize = false;
  
*************** vect_do_peeling (loop_vec_info loop_vinf
*** 3441,3452 ****
  
        /* Update init address of DRs.  */
        vect_update_inits_of_drs (loop_vinfo, niters_prolog, PLUS_EXPR);
!       /* Update niters for vector loop.  */
!       LOOP_VINFO_NITERS (loop_vinfo)
! 	= fold_build2 (MINUS_EXPR, type, niters, niters_prolog);
!       LOOP_VINFO_NITERSM1 (loop_vinfo)
! 	= fold_build2 (MINUS_EXPR, type,
! 		       LOOP_VINFO_NITERSM1 (loop_vinfo), niters_prolog);
        bool new_var_p = false;
        niters = vect_build_loop_niters (loop_vinfo, &new_var_p);
        /* It's guaranteed that vector loop bound before vectorization is at
--- 3513,3527 ----
  
        /* Update init address of DRs.  */
        vect_update_inits_of_drs (loop_vinfo, niters_prolog, PLUS_EXPR);
!       if (!uncounted_p)
! 	{
! 	  /* Update niters for vector loop.  */
! 	  LOOP_VINFO_NITERS (loop_vinfo)
! 	    = fold_build2 (MINUS_EXPR, type, niters, niters_prolog);
! 	  LOOP_VINFO_NITERSM1 (loop_vinfo)
! 	    = fold_build2 (MINUS_EXPR, type,
! 			   LOOP_VINFO_NITERSM1 (loop_vinfo), niters_prolog);
! 	}
        bool new_var_p = false;
        niters = vect_build_loop_niters (loop_vinfo, &new_var_p);
        /* It's guaranteed that vector loop bound before vectorization is at
*************** vect_do_peeling (loop_vec_info loop_vinf
*** 3472,3478 ****
  
    if (epilog_peeling)
      {
!       e = LOOP_VINFO_IV_EXIT (loop_vinfo);
        gcc_checking_assert (slpeel_can_duplicate_loop_p (loop, e, e));
  
        /* Peel epilog and put it on exit edge of loop.  If we are vectorizing
--- 3547,3553 ----
  
    if (epilog_peeling)
      {
!       e = LOOP_VINFO_MAIN_EXIT (loop_vinfo);
        gcc_checking_assert (slpeel_can_duplicate_loop_p (loop, e, e));
  
        /* Peel epilog and put it on exit edge of loop.  If we are vectorizing
*************** vect_do_peeling (loop_vec_info loop_vinf
*** 3482,3497 ****
  	 If we are not vectorizing the epilog then we should use the scalar loop
  	 as the transformations mentioned above make less or no sense when not
  	 vectorizing.  */
!       edge scalar_e = LOOP_VINFO_SCALAR_IV_EXIT (loop_vinfo);
        epilog = vect_epilogues ? get_loop_copy (loop) : scalar_loop;
        edge epilog_e = vect_epilogues ? e : scalar_e;
        edge new_epilog_e = NULL;
        auto_vec<basic_block> doms;
        epilog
  	= slpeel_tree_duplicate_loop_to_edge_cfg (loop, e, epilog, epilog_e, e,
! 						  &new_epilog_e, true, &doms);
  
!       LOOP_VINFO_EPILOGUE_IV_EXIT (loop_vinfo) = new_epilog_e;
        gcc_assert (epilog);
        gcc_assert (new_epilog_e);
        epilog->force_vectorize = false;
--- 3557,3573 ----
  	 If we are not vectorizing the epilog then we should use the scalar loop
  	 as the transformations mentioned above make less or no sense when not
  	 vectorizing.  */
!       edge scalar_e = LOOP_VINFO_SCALAR_MAIN_EXIT (loop_vinfo);
        epilog = vect_epilogues ? get_loop_copy (loop) : scalar_loop;
        edge epilog_e = vect_epilogues ? e : scalar_e;
        edge new_epilog_e = NULL;
        auto_vec<basic_block> doms;
        epilog
  	= slpeel_tree_duplicate_loop_to_edge_cfg (loop, e, epilog, epilog_e, e,
! 						  &new_epilog_e, true, &doms,
! 						  uncounted_p);
  
!       LOOP_VINFO_EPILOGUE_MAIN_EXIT (loop_vinfo) = new_epilog_e;
        gcc_assert (epilog);
        gcc_assert (new_epilog_e);
        epilog->force_vectorize = false;
*************** vect_do_peeling (loop_vec_info loop_vinf
*** 3573,3603 ****
  	  bb_before_epilog = loop_preheader_edge (epilog)->src;
  	}
  
!       /* If loop is peeled for non-zero constant times, now niters refers to
! 	 orig_niters - prolog_peeling, it won't overflow even the orig_niters
! 	 overflows.  */
!       niters_no_overflow |= (prolog_peeling > 0);
!       vect_gen_vector_loop_niters (loop_vinfo, niters,
! 				   niters_vector, step_vector,
! 				   niters_no_overflow);
!       if (!integer_onep (*step_vector))
  	{
! 	  /* On exit from the loop we will have an easy way of calcalating
! 	     NITERS_VECTOR / STEP * STEP.  Install a dummy definition
! 	     until then.  */
! 	  niters_vector_mult_vf = make_ssa_name (TREE_TYPE (*niters_vector));
! 	  SSA_NAME_DEF_STMT (niters_vector_mult_vf) = gimple_build_nop ();
! 	  *niters_vector_mult_vf_var = niters_vector_mult_vf;
  	}
-       else
- 	vect_gen_vector_loop_niters_mult_vf (loop_vinfo, *niters_vector,
- 					     &niters_vector_mult_vf);
-       /* Update IVs of original loop as if they were advanced by
- 	 niters_vector_mult_vf steps.  */
-       gcc_checking_assert (vect_can_advance_ivs_p (loop_vinfo));
-       update_e = skip_vector ? e : loop_preheader_edge (epilog);
        if (LOOP_VINFO_EARLY_BREAKS (loop_vinfo))
! 	update_e = single_succ_edge (LOOP_VINFO_IV_EXIT (loop_vinfo)->dest);
  
        /* If we have a peeled vector iteration we will never skip the epilog loop
  	 and we can simplify the cfg a lot by not doing the edge split.  */
--- 3649,3683 ----
  	  bb_before_epilog = loop_preheader_edge (epilog)->src;
  	}
  
!       if (!uncounted_p)
  	{
! 	  /* If loop is peeled for non-zero constant times, now niters refers to
! 	     orig_niters - prolog_peeling, it won't overflow even the
! 	     orig_niters overflows.  */
! 	  niters_no_overflow |= (prolog_peeling > 0);
! 	  vect_gen_vector_loop_niters (loop_vinfo, niters,
! 				       niters_vector, step_vector,
! 				       niters_no_overflow);
! 	  if (!integer_onep (*step_vector))
! 	    {
! 	      /* On exit from the loop we will have an easy way of calcalating
! 		 NITERS_VECTOR / STEP * STEP.  Install a dummy definition
! 		 until then.  */
! 	      niters_vector_mult_vf
! 		= make_ssa_name (TREE_TYPE (*niters_vector));
! 	      SSA_NAME_DEF_STMT (niters_vector_mult_vf) = gimple_build_nop ();
! 	      *niters_vector_mult_vf_var = niters_vector_mult_vf;
! 	    }
! 	  else
! 	    vect_gen_vector_loop_niters_mult_vf (loop_vinfo, *niters_vector,
! 						 &niters_vector_mult_vf);
! 	  /* Update IVs of original loop as if they were advanced by
! 	     niters_vector_mult_vf steps.  */
! 	  gcc_checking_assert (vect_can_advance_ivs_p (loop_vinfo));
! 	  update_e = skip_vector ? e : loop_preheader_edge (epilog);
  	}
        if (LOOP_VINFO_EARLY_BREAKS (loop_vinfo))
! 	update_e = single_succ_edge (LOOP_VINFO_MAIN_EXIT (loop_vinfo)->dest);
  
        /* If we have a peeled vector iteration we will never skip the epilog loop
  	 and we can simplify the cfg a lot by not doing the edge split.  */
*************** vect_do_peeling (loop_vec_info loop_vinf
*** 3608,3615 ****
  	  guard_cond = fold_build2 (EQ_EXPR, boolean_type_node,
  				    niters, niters_vector_mult_vf);
  
! 	  guard_bb = LOOP_VINFO_IV_EXIT (loop_vinfo)->dest;
! 	  edge epilog_e = LOOP_VINFO_EPILOGUE_IV_EXIT (loop_vinfo);
  	  guard_to = epilog_e->dest;
  	  guard_e = slpeel_add_loop_guard (guard_bb, guard_cond, guard_to,
  					   skip_vector ? anchor : guard_bb,
--- 3688,3695 ----
  	  guard_cond = fold_build2 (EQ_EXPR, boolean_type_node,
  				    niters, niters_vector_mult_vf);
  
! 	  guard_bb = LOOP_VINFO_MAIN_EXIT (loop_vinfo)->dest;
! 	  edge epilog_e = LOOP_VINFO_EPILOGUE_MAIN_EXIT (loop_vinfo);
  	  guard_to = epilog_e->dest;
  	  guard_e = slpeel_add_loop_guard (guard_bb, guard_cond, guard_to,
  					   skip_vector ? anchor : guard_bb,
*************** vect_do_peeling (loop_vec_info loop_vinf
*** 3619,3625 ****
  	  doms.safe_push (guard_to);
  	  if (vect_epilogues)
  	    epilogue_vinfo->skip_this_loop_edge = guard_e;
! 	  edge main_iv = LOOP_VINFO_IV_EXIT (loop_vinfo);
  	  gphi_iterator gsi2 = gsi_start_phis (main_iv->dest);
  	  for (gphi_iterator gsi = gsi_start_phis (guard_to);
  	       !gsi_end_p (gsi); gsi_next (&gsi))
--- 3699,3705 ----
  	  doms.safe_push (guard_to);
  	  if (vect_epilogues)
  	    epilogue_vinfo->skip_this_loop_edge = guard_e;
! 	  edge main_iv = LOOP_VINFO_MAIN_EXIT (loop_vinfo);
  	  gphi_iterator gsi2 = gsi_start_phis (main_iv->dest);
  	  for (gphi_iterator gsi = gsi_start_phis (guard_to);
  	       !gsi_end_p (gsi); gsi_next (&gsi))
*************** vect_do_peeling (loop_vec_info loop_vinf
*** 3662,3683 ****
        tree vector_iters_vf = niters_vector_mult_vf;
        if (LOOP_VINFO_EARLY_BREAKS (loop_vinfo))
  	{
! 	  tree scal_iv_ty = signed_type_for (TREE_TYPE (vector_iters_vf));
! 	  tree tmp_niters_vf = make_ssa_name (scal_iv_ty);
! 	  basic_block exit_bb = NULL;
! 
! 	  /* Identify the early exit merge block.  I wish we had stored this.  */
! 	  for (auto e : get_loop_exit_edges (loop))
! 	    if (e != LOOP_VINFO_IV_EXIT (loop_vinfo))
! 	      {
! 		exit_bb = e->dest;
! 		break;
! 	      }
  
! 	  edge update_e = single_succ_edge (exit_bb);
! 	  vect_update_ivs_after_vectorizer (loop_vinfo, tmp_niters_vf,
! 					    update_e, true);
  
  	  if (LOOP_VINFO_EARLY_BREAKS_VECT_PEELED (loop_vinfo))
  	    vector_iters_vf = tmp_niters_vf;
  
--- 3742,3768 ----
        tree vector_iters_vf = niters_vector_mult_vf;
        if (LOOP_VINFO_EARLY_BREAKS (loop_vinfo))
  	{
! 	  tree tmp_niters_vf
! 	    = make_ssa_name (LOOP_VINFO_EARLY_BRK_IV_TYPE (loop_vinfo));
  
! 	  if (!(LOOP_VINFO_NITERS_UNCOUNTED_P (loop_vinfo)
! 		&& get_loop_exit_edges (loop).length () == 1))
! 	  {
! 	    basic_block exit_bb = NULL;
! 	    edge update_e = NULL;
  
+ 	    /* Identify the early exit merge block.  I wish we had stored
+ 	       this.  */
+ 	    for (auto e : get_loop_exit_edges (loop))
+ 	      if (e != LOOP_VINFO_MAIN_EXIT (loop_vinfo))
+ 		{
+ 		  exit_bb = e->dest;
+ 		  update_e = single_succ_edge (exit_bb);
+ 		  break;
+ 		}
+ 	    vect_update_ivs_after_vectorizer (loop_vinfo, tmp_niters_vf,
+ 					      update_e, true);
+ 	  }
  	  if (LOOP_VINFO_EARLY_BREAKS_VECT_PEELED (loop_vinfo))
  	    vector_iters_vf = tmp_niters_vf;
  
*************** vect_do_peeling (loop_vec_info loop_vinf
*** 3734,3741 ****
      {
        epilog->aux = epilogue_vinfo;
        LOOP_VINFO_LOOP (epilogue_vinfo) = epilog;
!       LOOP_VINFO_IV_EXIT (epilogue_vinfo)
! 	= LOOP_VINFO_EPILOGUE_IV_EXIT (loop_vinfo);
  
        loop_constraint_clear (epilog, LOOP_C_INFINITE);
  
--- 3819,3826 ----
      {
        epilog->aux = epilogue_vinfo;
        LOOP_VINFO_LOOP (epilogue_vinfo) = epilog;
!       LOOP_VINFO_MAIN_EXIT (epilogue_vinfo)
! 	= LOOP_VINFO_EPILOGUE_MAIN_EXIT (loop_vinfo);
  
        loop_constraint_clear (epilog, LOOP_C_INFINITE);
  
*************** vect_loop_versioning (loop_vec_info loop
*** 4201,4213 ****
    tree version_simd_if_cond
      = LOOP_REQUIRES_VERSIONING_FOR_SIMD_IF_COND (loop_vinfo);
    unsigned th = LOOP_VINFO_COST_MODEL_THRESHOLD (loop_vinfo);
  
!   if (vect_apply_runtime_profitability_check_p (loop_vinfo)
        && !ordered_p (th, versioning_threshold))
      cond_expr = fold_build2 (GE_EXPR, boolean_type_node, scalar_loop_iters,
  			     build_int_cst (TREE_TYPE (scalar_loop_iters),
  					    th - 1));
!   if (maybe_ne (versioning_threshold, 0U))
      {
        tree expr = fold_build2 (GE_EXPR, boolean_type_node, scalar_loop_iters,
  			       build_int_cst (TREE_TYPE (scalar_loop_iters),
--- 4286,4299 ----
    tree version_simd_if_cond
      = LOOP_REQUIRES_VERSIONING_FOR_SIMD_IF_COND (loop_vinfo);
    unsigned th = LOOP_VINFO_COST_MODEL_THRESHOLD (loop_vinfo);
+   bool uncounted_p = LOOP_VINFO_NITERS_UNCOUNTED_P (loop_vinfo);
  
!   if (!uncounted_p && vect_apply_runtime_profitability_check_p (loop_vinfo)
        && !ordered_p (th, versioning_threshold))
      cond_expr = fold_build2 (GE_EXPR, boolean_type_node, scalar_loop_iters,
  			     build_int_cst (TREE_TYPE (scalar_loop_iters),
  					    th - 1));
!   if (!uncounted_p && maybe_ne (versioning_threshold, 0U))
      {
        tree expr = fold_build2 (GE_EXPR, boolean_type_node, scalar_loop_iters,
  			       build_int_cst (TREE_TYPE (scalar_loop_iters),
*************** vect_loop_versioning (loop_vec_info loop
*** 4371,4377 ****
  	currently using.  */
        edge exit_edge;
        if (loop_to_version == loop)
!        exit_edge = LOOP_VINFO_IV_EXIT (loop_vinfo);
        else
         exit_edge = single_exit (loop_to_version);
        exit_edge->dest->count = preheader->count;
--- 4457,4463 ----
  	currently using.  */
        edge exit_edge;
        if (loop_to_version == loop)
!        exit_edge = LOOP_VINFO_MAIN_EXIT (loop_vinfo);
        else
         exit_edge = single_exit (loop_to_version);
        exit_edge->dest->count = preheader->count;
*************** vect_loop_versioning (loop_vec_info loop
*** 4465,4471 ****
  	 currently using.  */
        edge exit_edge;
        if (loop_to_version == loop)
! 	exit_edge = LOOP_VINFO_IV_EXIT (loop_vinfo);
        else
  	exit_edge = single_exit (loop_to_version);
  
--- 4551,4557 ----
  	 currently using.  */
        edge exit_edge;
        if (loop_to_version == loop)
! 	exit_edge = LOOP_VINFO_MAIN_EXIT (loop_vinfo);
        else
  	exit_edge = single_exit (loop_to_version);
  
diff -Nrcpad gcc-16-20251214/gcc/tree-vect-loop.cc gcc-16-20251221/gcc/tree-vect-loop.cc
*** gcc-16-20251214/gcc/tree-vect-loop.cc	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/gcc/tree-vect-loop.cc	Sun Dec 21 22:32:14 2025
*************** vec_init_loop_exit_info (class loop *loo
*** 657,673 ****
    /* Before we begin we must first determine which exit is the main one and
       which are auxilary exits.  */
    auto_vec<edge> exits = get_loop_exit_edges (loop);
    if (exits.length () == 1)
      return exits[0];
  
!   /* If we have multiple exits we only support counting IV at the moment.
       Analyze all exits and return the last one we can analyze.  */
    class tree_niter_desc niter_desc;
    edge candidate = NULL;
    for (edge exit : exits)
      {
        if (!get_loop_exit_condition (exit))
! 	continue;
  
        if (number_of_iterations_exit_assumptions (loop, exit, &niter_desc, NULL)
  	  && !chrec_contains_undetermined (niter_desc.niter))
--- 657,680 ----
    /* Before we begin we must first determine which exit is the main one and
       which are auxilary exits.  */
    auto_vec<edge> exits = get_loop_exit_edges (loop);
+   if (exits.length () == 0)
+     return NULL;
    if (exits.length () == 1)
      return exits[0];
  
!   /* If we have multiple exits, look for counting IV exit.
       Analyze all exits and return the last one we can analyze.  */
    class tree_niter_desc niter_desc;
    edge candidate = NULL;
    for (edge exit : exits)
      {
        if (!get_loop_exit_condition (exit))
! 	{
! 	  if (dump_enabled_p ())
! 	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
! 			     "Unhandled loop exit detected.\n");
! 	  return NULL;
! 	}
  
        if (number_of_iterations_exit_assumptions (loop, exit, &niter_desc, NULL)
  	  && !chrec_contains_undetermined (niter_desc.niter))
*************** vec_init_loop_exit_info (class loop *loo
*** 688,693 ****
--- 695,705 ----
  	}
      }
  
+   /* If no exit is analyzable by scalar evolution, we return the last exit
+      under the assummption we are dealing with an uncounted loop.  */
+   if (!candidate && single_pred_p (loop->latch))
+     candidate = loop_exits_from_bb_p (loop, single_pred (loop->latch));
+ 
    return candidate;
  }
  
*************** _loop_vec_info::_loop_vec_info (class lo
*** 759,767 ****
      orig_loop_info (NULL),
      epilogue_vinfo (NULL),
      drs_advanced_by (NULL_TREE),
!     vec_loop_iv_exit (NULL),
!     vec_epilogue_loop_iv_exit (NULL),
!     scalar_loop_iv_exit (NULL)
  {
    /* CHECKME: We want to visit all BBs before their successors (except for
       latch blocks, for which this assertion wouldn't hold).  In the simple
--- 771,779 ----
      orig_loop_info (NULL),
      epilogue_vinfo (NULL),
      drs_advanced_by (NULL_TREE),
!     vec_loop_main_exit (NULL),
!     vec_epilogue_loop_main_exit (NULL),
!     scalar_loop_main_exit (NULL)
  {
    /* CHECKME: We want to visit all BBs before their successors (except for
       latch blocks, for which this assertion wouldn't hold).  In the simple
*************** vect_get_max_nscalars_per_iter (loop_vec
*** 916,929 ****
     as an unsigned integer, where MAX_NITERS is the maximum number of
     loop header iterations for the original scalar form of LOOP_VINFO.  */
  
! static unsigned
  vect_min_prec_for_max_niters (loop_vec_info loop_vinfo, unsigned int factor)
  {
    class loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
  
    /* Get the maximum number of iterations that is representable
       in the counter type.  */
!   tree ni_type = TREE_TYPE (LOOP_VINFO_NITERSM1 (loop_vinfo));
    widest_int max_ni = wi::to_widest (TYPE_MAX_VALUE (ni_type)) + 1;
  
    /* Get a more refined estimate for the number of iterations.  */
--- 928,945 ----
     as an unsigned integer, where MAX_NITERS is the maximum number of
     loop header iterations for the original scalar form of LOOP_VINFO.  */
  
! unsigned
  vect_min_prec_for_max_niters (loop_vec_info loop_vinfo, unsigned int factor)
  {
    class loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
  
    /* Get the maximum number of iterations that is representable
       in the counter type.  */
!   tree ni_type;
!   if (!LOOP_VINFO_NITERS_UNCOUNTED_P (loop_vinfo))
!     ni_type = TREE_TYPE (LOOP_VINFO_NITERSM1 (loop_vinfo));
!   else
!     ni_type = sizetype;
    widest_int max_ni = wi::to_widest (TYPE_MAX_VALUE (ni_type)) + 1;
  
    /* Get a more refined estimate for the number of iterations.  */
*************** vect_analyze_loop_form (class loop *loop
*** 1426,1433 ****
    if (!exit_e)
      return opt_result::failure_at (vect_location,
  				   "not vectorized:"
! 				   " could not determine main exit from"
! 				   " loop with multiple exits.\n");
    if (loop_vectorized_call)
      {
        tree arg = gimple_call_arg (loop_vectorized_call, 1);
--- 1442,1448 ----
    if (!exit_e)
      return opt_result::failure_at (vect_location,
  				   "not vectorized:"
! 				   " Infinite loop detected.\n");
    if (loop_vectorized_call)
      {
        tree arg = gimple_call_arg (loop_vectorized_call, 1);
*************** vect_analyze_loop_form (class loop *loop
*** 1458,1463 ****
--- 1473,1492 ----
  				       "not vectorized:"
  				       " unsupported control flow in loop.\n");
        }
+ 
+   /* Check if we have any control flow that doesn't leave the loop.  */
+   bool has_phi = false;
+   for (unsigned i = 0; i < loop->num_nodes; i++)
+     if (!gimple_seq_empty_p (phi_nodes (bbs[i])))
+       {
+ 	has_phi = true;
+ 	break;
+       }
+   if (!has_phi)
+     return opt_result::failure_at (vect_location,
+ 				   "not vectorized:"
+ 				   " no scalar evolution detected in loop.\n");
+ 
    free (bbs);
  
    /* Different restrictions apply when we are considering an inner-most loop,
*************** vect_analyze_loop_form (class loop *loop
*** 1582,1590 ****
  	std::swap (info->conds[0], info->conds[i]);
      }
  
!   if (integer_zerop (info->assumptions)
!       || !info->number_of_iterations
!       || chrec_contains_undetermined (info->number_of_iterations))
      return opt_result::failure_at
        (info->conds[0],
         "not vectorized: number of iterations cannot be computed.\n");
--- 1611,1630 ----
  	std::swap (info->conds[0], info->conds[i]);
      }
  
!   if (chrec_contains_undetermined (info->number_of_iterations))
!     {
!       if (dump_enabled_p ())
! 	dump_printf_loc (MSG_NOTE, vect_location,
! 			 "Loop being analyzed as uncounted.\n");
!       if (loop->inner)
! 	return opt_result::failure_at
! 	  (vect_location,
! 	   "not vectorized: outer loop vectorization of uncounted loops"
! 	   " is unsupported.\n");
!       return opt_result::success ();
!     }
! 
!   if (integer_zerop (info->assumptions))
      return opt_result::failure_at
        (info->conds[0],
         "not vectorized: number of iterations cannot be computed.\n");
*************** vect_create_loop_vinfo (class loop *loop
*** 1649,1659 ****
        STMT_VINFO_DEF_TYPE (loop_cond_info) = vect_condition_def;
      }
  
!   for (unsigned i = 1; i < info->conds.length (); i ++)
!     LOOP_VINFO_LOOP_CONDS (loop_vinfo).safe_push (info->conds[i]);
!   LOOP_VINFO_LOOP_IV_COND (loop_vinfo) = info->conds[0];
  
!   LOOP_VINFO_IV_EXIT (loop_vinfo) = info->loop_exit;
  
    /* Check to see if we're vectorizing multiple exits.  */
    LOOP_VINFO_EARLY_BREAKS (loop_vinfo)
--- 1689,1702 ----
        STMT_VINFO_DEF_TYPE (loop_cond_info) = vect_condition_def;
      }
  
!   unsigned cond_id = 0;
!   if (!LOOP_VINFO_NITERS_UNCOUNTED_P (loop_vinfo))
!       LOOP_VINFO_LOOP_IV_COND (loop_vinfo) = info->conds[cond_id++];
  
!   for (; cond_id < info->conds.length (); cond_id ++)
!     LOOP_VINFO_LOOP_CONDS (loop_vinfo).safe_push (info->conds[cond_id]);
! 
!   LOOP_VINFO_MAIN_EXIT (loop_vinfo) = info->loop_exit;
  
    /* Check to see if we're vectorizing multiple exits.  */
    LOOP_VINFO_EARLY_BREAKS (loop_vinfo)
*************** vect_analyze_loop_2 (loop_vec_info loop_
*** 2090,2095 ****
--- 2133,2142 ----
      orig_loop_vinfo = loop_vinfo;
    gcc_assert (orig_loop_vinfo);
  
+   /* We can't mask on niters for uncounted loops due to unkown upper bound.  */
+   if (LOOP_VINFO_NITERS_UNCOUNTED_P (loop_vinfo))
+     LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
+ 
    /* The first group of checks is independent of the vector size.  */
    fatal = true;
  
*************** start_over:
*** 2474,2481 ****
          dump_printf_loc (MSG_NOTE, vect_location, "epilog loop required\n");
        if (!vect_can_advance_ivs_p (loop_vinfo)
  	  || !slpeel_can_duplicate_loop_p (loop,
! 					   LOOP_VINFO_IV_EXIT (loop_vinfo),
! 					   LOOP_VINFO_IV_EXIT (loop_vinfo)))
          {
  	  ok = opt_result::failure_at (vect_location,
  				       "not vectorized: can't create required "
--- 2521,2528 ----
          dump_printf_loc (MSG_NOTE, vect_location, "epilog loop required\n");
        if (!vect_can_advance_ivs_p (loop_vinfo)
  	  || !slpeel_can_duplicate_loop_p (loop,
! 					   LOOP_VINFO_MAIN_EXIT (loop_vinfo),
! 					   LOOP_VINFO_MAIN_EXIT (loop_vinfo)))
          {
  	  ok = opt_result::failure_at (vect_location,
  				       "not vectorized: can't create required "
*************** vect_create_epilog_for_reduction (loop_v
*** 5389,5395 ****
        /* Create an induction variable.  */
        gimple_stmt_iterator incr_gsi;
        bool insert_after;
!       vect_iv_increment_position (LOOP_VINFO_IV_EXIT (loop_vinfo),
  				  &incr_gsi, &insert_after);
        create_iv (series_vect, PLUS_EXPR, vec_step, NULL_TREE, loop, &incr_gsi,
  		 insert_after, &indx_before_incr, &indx_after_incr);
--- 5436,5442 ----
        /* Create an induction variable.  */
        gimple_stmt_iterator incr_gsi;
        bool insert_after;
!       vect_iv_increment_position (LOOP_VINFO_MAIN_EXIT (loop_vinfo),
  				  &incr_gsi, &insert_after);
        create_iv (series_vect, PLUS_EXPR, vec_step, NULL_TREE, loop, &incr_gsi,
  		 insert_after, &indx_before_incr, &indx_after_incr);
*************** vect_create_epilog_for_reduction (loop_v
*** 5477,5483 ****
        def = vect_get_slp_vect_def (slp_node, i);
        tree new_def = copy_ssa_name (def);
        phi = create_phi_node (new_def, exit_bb);
!       if (LOOP_VINFO_IV_EXIT (loop_vinfo) == loop_exit)
  	SET_PHI_ARG_DEF (phi, loop_exit->dest_idx, def);
        else
  	{
--- 5524,5530 ----
        def = vect_get_slp_vect_def (slp_node, i);
        tree new_def = copy_ssa_name (def);
        phi = create_phi_node (new_def, exit_bb);
!       if (LOOP_VINFO_MAIN_EXIT (loop_vinfo) == loop_exit)
  	SET_PHI_ARG_DEF (phi, loop_exit->dest_idx, def);
        else
  	{
*************** vect_create_epilog_for_reduction (loop_v
*** 5972,5984 ****
  
        if (reduce_with_shift && (!slp_reduc || group_size == 1))
  	{
! 	  tree bitsize = TYPE_SIZE (TREE_TYPE (vectype1));
! 	  int element_bitsize = tree_to_uhwi (bitsize);
  	  /* Enforced by vectorizable_reduction, which disallows SLP reductions
  	     for variable-length vectors and also requires direct target support
  	     for loop reductions.  */
! 	  int vec_size_in_bits = tree_to_uhwi (TYPE_SIZE (vectype1));
! 	  int nelements = vec_size_in_bits / element_bitsize;
  	  vec_perm_builder sel;
  	  vec_perm_indices indices;
  
--- 6019,6029 ----
  
        if (reduce_with_shift && (!slp_reduc || group_size == 1))
  	{
! 	  int element_bitsize = vector_element_bits (vectype1);
  	  /* Enforced by vectorizable_reduction, which disallows SLP reductions
  	     for variable-length vectors and also requires direct target support
  	     for loop reductions.  */
! 	  int nelements = TYPE_VECTOR_SUBPARTS (vectype1).to_constant ();
  	  vec_perm_builder sel;
  	  vec_perm_indices indices;
  
*************** vect_create_epilog_for_reduction (loop_v
*** 6019,6025 ****
  			     "extract scalar result\n");
  
  	  new_temp = gimple_build (&stmts, BIT_FIELD_REF, TREE_TYPE (vectype1),
! 				   new_temp, bitsize, bitsize_zero_node);
  	  new_temp = gimple_convert (&stmts, scalar_type, new_temp);
  	  gsi_insert_seq_before (&exit_gsi, stmts, GSI_SAME_STMT);
  	  scalar_results.safe_push (new_temp);
--- 6064,6071 ----
  			     "extract scalar result\n");
  
  	  new_temp = gimple_build (&stmts, BIT_FIELD_REF, TREE_TYPE (vectype1),
! 				   new_temp, bitsize_int (element_bitsize),
! 				   bitsize_zero_node);
  	  new_temp = gimple_convert (&stmts, scalar_type, new_temp);
  	  gsi_insert_seq_before (&exit_gsi, stmts, GSI_SAME_STMT);
  	  scalar_results.safe_push (new_temp);
*************** vect_create_epilog_for_reduction (loop_v
*** 6041,6048 ****
  			     "Reduce using scalar code.\n");
  
  	  tree compute_type = TREE_TYPE (vectype1);
- 	  unsigned vec_size_in_bits = tree_to_uhwi (TYPE_SIZE (vectype1));
  	  unsigned element_bitsize = vector_element_bits (vectype1);
  	  tree bitsize = bitsize_int (element_bitsize);
  	  gimple_seq stmts = NULL;
  	  FOR_EACH_VEC_ELT (reduc_inputs, i, vec_temp)
--- 6087,6095 ----
  			     "Reduce using scalar code.\n");
  
  	  tree compute_type = TREE_TYPE (vectype1);
  	  unsigned element_bitsize = vector_element_bits (vectype1);
+ 	  unsigned vec_size_in_bits = element_bitsize
+ 	    * TYPE_VECTOR_SUBPARTS (vectype1).to_constant ();
  	  tree bitsize = bitsize_int (element_bitsize);
  	  gimple_seq stmts = NULL;
  	  FOR_EACH_VEC_ELT (reduc_inputs, i, vec_temp)
*************** vectorizable_live_operation (vec_info *v
*** 10105,10111 ****
  	  || !LOOP_VINFO_EARLY_BREAKS_VECT_PEELED (loop_vinfo))
  	vect_create_epilog_for_reduction (loop_vinfo, stmt_info, slp_node,
  					  slp_node_instance,
! 					  LOOP_VINFO_IV_EXIT (loop_vinfo));
  
        /* If early break we only have to materialize the reduction on the merge
  	 block, but we have to find an alternate exit first.  */
--- 10152,10158 ----
  	  || !LOOP_VINFO_EARLY_BREAKS_VECT_PEELED (loop_vinfo))
  	vect_create_epilog_for_reduction (loop_vinfo, stmt_info, slp_node,
  					  slp_node_instance,
! 					  LOOP_VINFO_MAIN_EXIT (loop_vinfo));
  
        /* If early break we only have to materialize the reduction on the merge
  	 block, but we have to find an alternate exit first.  */
*************** vectorizable_live_operation (vec_info *v
*** 10114,10120 ****
  	  slp_tree phis_node = slp_node_instance->reduc_phis;
  	  stmt_info = SLP_TREE_REPRESENTATIVE (phis_node);
  	  for (auto exit : get_loop_exit_edges (LOOP_VINFO_LOOP (loop_vinfo)))
! 	    if (exit != LOOP_VINFO_IV_EXIT (loop_vinfo))
  	      {
  		vect_create_epilog_for_reduction (loop_vinfo, stmt_info,
  						  phis_node, slp_node_instance,
--- 10161,10167 ----
  	  slp_tree phis_node = slp_node_instance->reduc_phis;
  	  stmt_info = SLP_TREE_REPRESENTATIVE (phis_node);
  	  for (auto exit : get_loop_exit_edges (LOOP_VINFO_LOOP (loop_vinfo)))
! 	    if (exit != LOOP_VINFO_MAIN_EXIT (loop_vinfo))
  	      {
  		vect_create_epilog_for_reduction (loop_vinfo, stmt_info,
  						  phis_node, slp_node_instance,
*************** vectorizable_live_operation (vec_info *v
*** 10124,10130 ****
  	  if (LOOP_VINFO_EARLY_BREAKS_VECT_PEELED (loop_vinfo))
  	    vect_create_epilog_for_reduction (loop_vinfo, stmt_info,
  					      phis_node, slp_node_instance,
! 					      LOOP_VINFO_IV_EXIT (loop_vinfo));
  	}
  
        return true;
--- 10171,10178 ----
  	  if (LOOP_VINFO_EARLY_BREAKS_VECT_PEELED (loop_vinfo))
  	    vect_create_epilog_for_reduction (loop_vinfo, stmt_info,
  					      phis_node, slp_node_instance,
! 					      LOOP_VINFO_MAIN_EXIT
! 					      (loop_vinfo));
  	}
  
        return true;
*************** vectorizable_live_operation (vec_info *v
*** 10263,10269 ****
  	 in these cases for an early break we restart the iteration the vector code
  	 did.  For the live values we want the value at the start of the iteration
  	 rather than at the end.  */
!       edge main_e = LOOP_VINFO_IV_EXIT (loop_vinfo);
        bool all_exits_as_early_p = LOOP_VINFO_EARLY_BREAKS_VECT_PEELED (loop_vinfo);
        FOR_EACH_IMM_USE_STMT (use_stmt, imm_iter, lhs)
  	if (!is_gimple_debug (use_stmt)
--- 10311,10317 ----
  	 in these cases for an early break we restart the iteration the vector code
  	 did.  For the live values we want the value at the start of the iteration
  	 rather than at the end.  */
!       edge main_e = LOOP_VINFO_MAIN_EXIT (loop_vinfo);
        bool all_exits_as_early_p = LOOP_VINFO_EARLY_BREAKS_VECT_PEELED (loop_vinfo);
        FOR_EACH_IMM_USE_STMT (use_stmt, imm_iter, lhs)
  	if (!is_gimple_debug (use_stmt)
*************** vectorizable_live_operation (vec_info *v
*** 10399,10404 ****
--- 10447,10454 ----
  static bool
  loop_niters_no_overflow (loop_vec_info loop_vinfo)
  {
+   gcc_assert (!LOOP_VINFO_NITERS_UNCOUNTED_P (loop_vinfo));
+ 
    /* Constant case.  */
    if (LOOP_VINFO_NITERS_KNOWN_P (loop_vinfo))
      {
*************** vect_update_ivs_after_vectorizer_for_ear
*** 11005,11019 ****
       final IV.  */
    if (niters_skip)
      {
!       induc_def = gimple_build (&iv_stmts, MAX_EXPR, TREE_TYPE (induc_def),
! 				induc_def,
! 				build_zero_cst (TREE_TYPE (induc_def)));
!       auto stmt = gimple_build_assign (phi_var, induc_def);
        gimple_seq_add_stmt_without_update (&iv_stmts, stmt);
        basic_block exit_bb = NULL;
        /* Identify the early exit merge block.  I wish we had stored this.  */
        for (auto e : get_loop_exit_edges (loop))
! 	if (e != LOOP_VINFO_IV_EXIT (loop_vinfo))
  	  {
  	    exit_bb = e->dest;
  	    break;
--- 11055,11074 ----
       final IV.  */
    if (niters_skip)
      {
!       tree induc_type = TREE_TYPE (induc_def);
!       tree s_induc_type = signed_type_for (induc_type);
!       induc_def = gimple_build (&iv_stmts, MAX_EXPR, s_induc_type,
! 				gimple_convert (&iv_stmts, s_induc_type,
! 						induc_def),
! 				build_zero_cst (s_induc_type));
!       auto stmt = gimple_build_assign (phi_var,
! 				       gimple_convert (&iv_stmts, induc_type,
! 						       induc_def));
        gimple_seq_add_stmt_without_update (&iv_stmts, stmt);
        basic_block exit_bb = NULL;
        /* Identify the early exit merge block.  I wish we had stored this.  */
        for (auto e : get_loop_exit_edges (loop))
! 	if (e != LOOP_VINFO_MAIN_EXIT (loop_vinfo))
  	  {
  	    exit_bb = e->dest;
  	    break;
*************** vect_transform_loop (loop_vec_info loop_
*** 11056,11061 ****
--- 11111,11117 ----
    bool check_profitability = false;
    unsigned int th;
    bool flat = maybe_flat_loop_profile (loop);
+   bool uncounted_p = LOOP_VINFO_NITERS_UNCOUNTED_P (loop_vinfo);
  
    DUMP_VECT_SCOPE ("vec_transform_loop");
  
*************** vect_transform_loop (loop_vec_info loop_
*** 11079,11085 ****
  
    /* Make sure there exists a single-predecessor exit bb.  Do this before
       versioning.   */
!   edge e = LOOP_VINFO_IV_EXIT (loop_vinfo);
    if (! single_pred_p (e->dest) && !LOOP_VINFO_EARLY_BREAKS (loop_vinfo))
      {
        split_loop_exit_edge (e, true);
--- 11135,11141 ----
  
    /* Make sure there exists a single-predecessor exit bb.  Do this before
       versioning.   */
!   edge e = LOOP_VINFO_MAIN_EXIT (loop_vinfo);
    if (! single_pred_p (e->dest) && !LOOP_VINFO_EARLY_BREAKS (loop_vinfo))
      {
        split_loop_exit_edge (e, true);
*************** vect_transform_loop (loop_vec_info loop_
*** 11105,11111 ****
       loop closed PHI nodes on the exit.  */
    if (LOOP_VINFO_SCALAR_LOOP (loop_vinfo))
      {
!       e = LOOP_VINFO_SCALAR_IV_EXIT (loop_vinfo);
        if (! single_pred_p (e->dest))
  	{
  	  split_loop_exit_edge (e, true);
--- 11161,11167 ----
       loop closed PHI nodes on the exit.  */
    if (LOOP_VINFO_SCALAR_LOOP (loop_vinfo))
      {
!       e = LOOP_VINFO_SCALAR_MAIN_EXIT (loop_vinfo);
        if (! single_pred_p (e->dest))
  	{
  	  split_loop_exit_edge (e, true);
*************** vect_transform_loop (loop_vec_info loop_
*** 11117,11125 ****
    tree niters = vect_build_loop_niters (loop_vinfo);
    LOOP_VINFO_NITERS_UNCHANGED (loop_vinfo) = niters;
    tree nitersm1 = unshare_expr (LOOP_VINFO_NITERSM1 (loop_vinfo));
-   bool niters_no_overflow = loop_niters_no_overflow (loop_vinfo);
    tree advance;
    drs_init_vec orig_drs_init;
  
    epilogue = vect_do_peeling (loop_vinfo, niters, nitersm1, &niters_vector,
  			      &step_vector, &niters_vector_mult_vf, th,
--- 11173,11182 ----
    tree niters = vect_build_loop_niters (loop_vinfo);
    LOOP_VINFO_NITERS_UNCHANGED (loop_vinfo) = niters;
    tree nitersm1 = unshare_expr (LOOP_VINFO_NITERSM1 (loop_vinfo));
    tree advance;
    drs_init_vec orig_drs_init;
+   bool niters_no_overflow = uncounted_p ? false /* Not known.  */
+ 					: loop_niters_no_overflow (loop_vinfo);
  
    epilogue = vect_do_peeling (loop_vinfo, niters, nitersm1, &niters_vector,
  			      &step_vector, &niters_vector_mult_vf, th,
*************** vect_transform_loop (loop_vec_info loop_
*** 11137,11146 ****
  	      (LOOP_VINFO_SCALAR_LOOP_SCALING (loop_vinfo));
        scale_loop_frequencies (LOOP_VINFO_SCALAR_LOOP (loop_vinfo),
  			      LOOP_VINFO_SCALAR_LOOP_SCALING (loop_vinfo));
!       LOOP_VINFO_SCALAR_IV_EXIT (loop_vinfo)->dest->count = preheader->count;
      }
  
!   if (niters_vector == NULL_TREE)
      {
        if (LOOP_VINFO_NITERS_KNOWN_P (loop_vinfo)
  	  && !LOOP_VINFO_USING_PARTIAL_VECTORS_P (loop_vinfo)
--- 11194,11203 ----
  	      (LOOP_VINFO_SCALAR_LOOP_SCALING (loop_vinfo));
        scale_loop_frequencies (LOOP_VINFO_SCALAR_LOOP (loop_vinfo),
  			      LOOP_VINFO_SCALAR_LOOP_SCALING (loop_vinfo));
!       LOOP_VINFO_SCALAR_MAIN_EXIT (loop_vinfo)->dest->count = preheader->count;
      }
  
!   if (niters_vector == NULL_TREE && !uncounted_p)
      {
        if (LOOP_VINFO_NITERS_KNOWN_P (loop_vinfo)
  	  && !LOOP_VINFO_USING_PARTIAL_VECTORS_P (loop_vinfo)
*************** vect_transform_loop (loop_vec_info loop_
*** 11266,11278 ****
  	}
      }
  
!   /* The vectorization factor is always > 1, so if we use an IV increment of 1.
!      a zero NITERS becomes a nonzero NITERS_VECTOR.  */
!   if (integer_onep (step_vector))
!     niters_no_overflow = true;
!   vect_set_loop_condition (loop, LOOP_VINFO_IV_EXIT (loop_vinfo), loop_vinfo,
! 			   niters_vector, step_vector, niters_vector_mult_vf,
! 			   !niters_no_overflow);
  
    unsigned int assumed_vf = vect_vf_for_cost (loop_vinfo);
  
--- 11323,11339 ----
  	}
      }
  
!   if (!uncounted_p)
!     {
!       /* The vectorization factor is always > 1, so if we use an IV increment of
! 	 1.  A zero NITERS becomes a nonzero NITERS_VECTOR.  */
!       if (integer_onep (step_vector))
! 	niters_no_overflow = true;
! 
!       vect_set_loop_condition (loop, LOOP_VINFO_MAIN_EXIT (loop_vinfo),
! 			       loop_vinfo, niters_vector, step_vector,
! 			       niters_vector_mult_vf, !niters_no_overflow);
!     }
  
    unsigned int assumed_vf = vect_vf_for_cost (loop_vinfo);
  
*************** vect_transform_loop (loop_vec_info loop_
*** 11349,11355 ****
  			  assumed_vf) - 1
  	 : wi::udiv_floor (loop->nb_iterations_estimate + bias_for_assumed,
  			   assumed_vf) - 1);
!   scale_profile_for_vect_loop (loop, LOOP_VINFO_IV_EXIT (loop_vinfo),
  			       assumed_vf, flat);
  
    if (dump_enabled_p ())
--- 11410,11416 ----
  			  assumed_vf) - 1
  	 : wi::udiv_floor (loop->nb_iterations_estimate + bias_for_assumed,
  			   assumed_vf) - 1);
!   scale_profile_for_vect_loop (loop, LOOP_VINFO_MAIN_EXIT (loop_vinfo),
  			       assumed_vf, flat);
  
    if (dump_enabled_p ())
diff -Nrcpad gcc-16-20251214/gcc/tree-vect-patterns.cc gcc-16-20251221/gcc/tree-vect-patterns.cc
*** gcc-16-20251214/gcc/tree-vect-patterns.cc	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/gcc/tree-vect-patterns.cc	Sun Dec 21 22:32:14 2025
*************** along with GCC; see the file COPYING3.
*** 59,65 ****
  
  /* TODO:  Note the vectorizer still builds COND_EXPRs with GENERIC compares
     in the first operand.  Disentangling this is future work, the
!    IL is properly transfered to VEC_COND_EXPRs with separate compares.  */
  
  
  /* Return true if we have a useful VR_RANGE range for VAR, storing it
--- 59,65 ----
  
  /* TODO:  Note the vectorizer still builds COND_EXPRs with GENERIC compares
     in the first operand.  Disentangling this is future work, the
!    IL is properly transferred to VEC_COND_EXPRs with separate compares.  */
  
  
  /* Return true if we have a useful VR_RANGE range for VAR, storing it
diff -Nrcpad gcc-16-20251214/gcc/tree-vect-slp.cc gcc-16-20251221/gcc/tree-vect-slp.cc
*** gcc-16-20251214/gcc/tree-vect-slp.cc	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/gcc/tree-vect-slp.cc	Sun Dec 21 22:32:14 2025
*************** vect_build_slp_tree_2 (vec_info *vinfo,
*** 2037,2043 ****
  		  all_same = false;
  	      }
  	    class loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
! 	    /* Reduction initial values are not explicitely represented.  */
  	    if (def_type != vect_first_order_recurrence
  		&& gimple_bb (stmt_info->stmt) == loop->header)
  	      skip_args[loop_preheader_edge (loop)->dest_idx] = true;
--- 2037,2043 ----
  		  all_same = false;
  	      }
  	    class loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
! 	    /* Reduction initial values are not explicitly represented.  */
  	    if (def_type != vect_first_order_recurrence
  		&& gimple_bb (stmt_info->stmt) == loop->header)
  	      skip_args[loop_preheader_edge (loop)->dest_idx] = true;
*************** vect_build_slp_store_interleaving (vec<s
*** 4068,4074 ****
  
  /* Analyze an SLP instance starting from SCALAR_STMTS which are a group
     of KIND.  Return true if successful.  SCALAR_STMTS is owned by this
!    function, REMAIN and ROOT_STMT_INFOS ownership is transfered back to
     the caller upon failure.  */
  
  static bool
--- 4068,4074 ----
  
  /* Analyze an SLP instance starting from SCALAR_STMTS which are a group
     of KIND.  Return true if successful.  SCALAR_STMTS is owned by this
!    function, REMAIN and ROOT_STMT_INFOS ownership is transferred back to
     the caller upon failure.  */
  
  static bool
*************** vect_optimize_slp_pass::build_vertices (
*** 6555,6561 ****
        force_leaf = true;
    /* Since SLP discovery works along use-def edges all cycles have an
       entry - but there's the exception of cycles where we do not handle
!      the entry explicitely (but with a NULL SLP node), like some reductions
       and inductions.  Force those SLP PHIs to act as leafs to make them
       backwards reachable.  */
    if (leaf || force_leaf)
--- 6555,6561 ----
        force_leaf = true;
    /* Since SLP discovery works along use-def edges all cycles have an
       entry - but there's the exception of cycles where we do not handle
!      the entry explicitly (but with a NULL SLP node), like some reductions
       and inductions.  Force those SLP PHIs to act as leafs to make them
       backwards reachable.  */
    if (leaf || force_leaf)
*************** vect_slp_analyze_node_operations (vec_in
*** 8819,8825 ****
      }
  
    /* When the node can be vectorized cost invariant nodes it references.
!      This is not done in DFS order to allow the refering node
       vectorizable_* calls to nail down the invariant nodes vector type
       and possibly unshare it if it needs a different vector type than
       other referrers.  */
--- 8819,8825 ----
      }
  
    /* When the node can be vectorized cost invariant nodes it references.
!      This is not done in DFS order to allow the referring node
       vectorizable_* calls to nail down the invariant nodes vector type
       and possibly unshare it if it needs a different vector type than
       other referrers.  */
*************** vect_slp_analyze_node_operations (vec_in
*** 8854,8860 ****
  
  	      /* For shifts with a scalar argument we don't need
  		 to cost or code-generate anything.
! 		 ???  Represent this more explicitely.  */
  	      gcc_assert (SLP_TREE_TYPE (node) == shift_vec_info_type
  			  && j == 1);
  	      continue;
--- 8854,8860 ----
  
  	      /* For shifts with a scalar argument we don't need
  		 to cost or code-generate anything.
! 		 ???  Represent this more explicitly.  */
  	      gcc_assert (SLP_TREE_TYPE (node) == shift_vec_info_type
  			  && j == 1);
  	      continue;
diff -Nrcpad gcc-16-20251214/gcc/tree-vect-stmts.cc gcc-16-20251221/gcc/tree-vect-stmts.cc
*** gcc-16-20251214/gcc/tree-vect-stmts.cc	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/gcc/tree-vect-stmts.cc	Sun Dec 21 22:32:14 2025
*************** vectorizable_store (vec_info *vinfo,
*** 8875,8881 ****
  	      vec_oprnd = (*gvec_oprnds[0])[j];
  	      if (mask_node)
  		vec_mask = vec_masks[j];
! 	      /* We should have catched mismatched types earlier.  */
  	      gcc_assert (ls.ls_type
  			  || useless_type_conversion_p
  			  (vectype, TREE_TYPE (vec_oprnd)));
--- 8875,8881 ----
  	      vec_oprnd = (*gvec_oprnds[0])[j];
  	      if (mask_node)
  		vec_mask = vec_masks[j];
! 	      /* We should have caught mismatched types earlier.  */
  	      gcc_assert (ls.ls_type
  			  || useless_type_conversion_p
  			  (vectype, TREE_TYPE (vec_oprnd)));
*************** vectorizable_store (vec_info *vinfo,
*** 9230,9236 ****
  	}
      }
  
!   /* We should have catched mismatched types earlier.  */
    gcc_assert (costing_p
  	      || useless_type_conversion_p (vectype, TREE_TYPE (vec_oprnd)));
    bool simd_lane_access_p
--- 9230,9236 ----
  	}
      }
  
!   /* We should have caught mismatched types earlier.  */
    gcc_assert (costing_p
  	      || useless_type_conversion_p (vectype, TREE_TYPE (vec_oprnd)));
    bool simd_lane_access_p
*************** supports_vector_compare_and_branch (loop
*** 12784,12789 ****
--- 12784,12850 ----
    return direct_optab_handler (cbranch_optab, mode) != CODE_FOR_nothing;
  }
  
+ /* Determine the type to use for early break vectorization's scalar IV.  If
+    no type is possible return false.  */
+ 
+ static bool
+ vect_compute_type_for_early_break_scalar_iv (loop_vec_info loop_vinfo)
+ {
+   /* Check if we have a usable scalar IV type for vectorization.  */
+   tree iters_vf_type = sizetype;
+   if (!LOOP_VINFO_NITERS_UNCOUNTED_P (loop_vinfo))
+     {
+       /* Find the type with the minimum precision we can use
+ 	 for the scalar IV.  */
+       tree cand_type = TREE_TYPE (LOOP_VINFO_NITERS (loop_vinfo));
+ 
+       /* Work out how many bits we need to represent the limit.  */
+       unsigned int min_ni_width
+ 	= vect_min_prec_for_max_niters (loop_vinfo, 1);
+ 
+       /* Check if we're using PFA, if so we need a signed IV and an
+ 	 extra bit for the sign.  */
+       if (TYPE_UNSIGNED (cand_type)
+ 	  && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo)
+ 	  && LOOP_VINFO_PEELING_FOR_ALIGNMENT (loop_vinfo))
+ 	min_ni_width += 1;
+ 
+       if (TYPE_PRECISION (cand_type) >= min_ni_width)
+ 	iters_vf_type = unsigned_type_for (cand_type);
+       else
+ 	{
+ 	  opt_scalar_int_mode cmp_mode_iter;
+ 	  tree iv_type = NULL_TREE;
+ 	  FOR_EACH_MODE_IN_CLASS (cmp_mode_iter, MODE_INT)
+ 	    {
+ 	      auto cmp_mode = cmp_mode_iter.require ();
+ 	      unsigned int cmp_bits = GET_MODE_BITSIZE (cmp_mode);
+ 	      if (cmp_bits >= min_ni_width
+ 		  && targetm.scalar_mode_supported_p (cmp_mode))
+ 		{
+ 		  iv_type = build_nonstandard_integer_type (cmp_bits, true);
+ 		  if (iv_type)
+ 		    break;
+ 		}
+ 	    }
+ 
+ 	  if (!iv_type)
+ 	    {
+ 	      if (dump_enabled_p ())
+ 		dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+ 		       "can't vectorize early exit because the "
+ 		       "target doesn't support a scalar type wide "
+ 		       "wide enough to hold niters.\n");
+ 	      return false;
+ 	    }
+ 	  iters_vf_type = iv_type;
+ 	}
+     }
+ 
+   LOOP_VINFO_EARLY_BRK_IV_TYPE (loop_vinfo) = iters_vf_type;
+   return true;
+ }
+ 
  /* Check to see if the current early break given in STMT_INFO is valid for
     vectorization.  */
  
*************** vectorizable_early_exit (loop_vec_info l
*** 12897,12902 ****
--- 12958,12966 ----
  	    vect_record_loop_mask (loop_vinfo, masks, vec_num, vectype, NULL);
  	}
  
+       if (!vect_compute_type_for_early_break_scalar_iv (loop_vinfo))
+ 	return false;
+ 
        return true;
      }
  
diff -Nrcpad gcc-16-20251214/gcc/tree-vectorizer.cc gcc-16-20251221/gcc/tree-vectorizer.cc
*** gcc-16-20251214/gcc/tree-vectorizer.cc	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/gcc/tree-vectorizer.cc	Sun Dec 21 22:32:14 2025
*************** set_uid_loop_bbs (loop_vec_info loop_vin
*** 965,971 ****
    class loop *scalar_loop = get_loop (fun, tree_to_shwi (arg));
  
    LOOP_VINFO_SCALAR_LOOP (loop_vinfo) = scalar_loop;
!   LOOP_VINFO_SCALAR_IV_EXIT (loop_vinfo)
      = vec_init_loop_exit_info (scalar_loop);
    gcc_checking_assert (vect_loop_vectorized_call (scalar_loop)
  		       == loop_vectorized_call);
--- 965,971 ----
    class loop *scalar_loop = get_loop (fun, tree_to_shwi (arg));
  
    LOOP_VINFO_SCALAR_LOOP (loop_vinfo) = scalar_loop;
!   LOOP_VINFO_SCALAR_MAIN_EXIT (loop_vinfo)
      = vec_init_loop_exit_info (scalar_loop);
    gcc_checking_assert (vect_loop_vectorized_call (scalar_loop)
  		       == loop_vectorized_call);
diff -Nrcpad gcc-16-20251214/gcc/tree-vectorizer.h gcc-16-20251221/gcc/tree-vectorizer.h
*** gcc-16-20251214/gcc/tree-vectorizer.h	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/gcc/tree-vectorizer.h	Sun Dec 21 22:32:14 2025
*************** public:
*** 1219,1235 ****
    /* If this is an epilogue loop the DR advancement applied.  */
    tree drs_advanced_by;
  
!   /* The controlling loop IV for the current loop when vectorizing.  This IV
!      controls the natural exits of the loop.  */
!   edge vec_loop_iv_exit;
  
!   /* The controlling loop IV for the epilogue loop when vectorizing.  This IV
!      controls the natural exits of the loop.  */
!   edge vec_epilogue_loop_iv_exit;
  
!   /* The controlling loop IV for the scalar loop being vectorized.  This IV
!      controls the natural exits of the loop.  */
!   edge scalar_loop_iv_exit;
  
    /* Used to store the list of stores needing to be moved if doing early
       break vectorization as they would violate the scalar loop semantics if
--- 1219,1235 ----
    /* If this is an epilogue loop the DR advancement applied.  */
    tree drs_advanced_by;
  
!   /* The controlling loop exit for the current loop when vectorizing.
!      For counted loops, this IV controls the natural exits of the loop.  */
!   edge vec_loop_main_exit;
  
!   /* The controlling loop exit for the epilogue loop when vectorizing.
!      For counted loops, this IV controls the natural exits of the loop.  */
!   edge vec_epilogue_loop_main_exit;
  
!   /* The controlling loop exit for the scalar loop being vectorized.
!      For counted loops, this IV controls the natural exits of the loop.  */
!   edge scalar_loop_main_exit;
  
    /* Used to store the list of stores needing to be moved if doing early
       break vectorization as they would violate the scalar loop semantics if
*************** public:
*** 1249,1254 ****
--- 1249,1258 ----
       inside the relavent exit blocks in order to adjust for early break.  */
    tree early_break_niters_var;
  
+   /* The type of the variable to be used to create the scalar IV for early break
+      loops.  */
+   tree early_break_iv_type;
+ 
    /* Record statements that are needed to be live for early break vectorization
       but may not have an LC PHI node materialized yet in the exits.  */
    auto_vec<stmt_vec_info> early_break_live_ivs;
*************** public:
*** 1256,1268 ****
  
  /* Access Functions.  */
  #define LOOP_VINFO_LOOP(L)                 (L)->loop
! #define LOOP_VINFO_IV_EXIT(L)              (L)->vec_loop_iv_exit
! #define LOOP_VINFO_EPILOGUE_IV_EXIT(L)     (L)->vec_epilogue_loop_iv_exit
! #define LOOP_VINFO_SCALAR_IV_EXIT(L)       (L)->scalar_loop_iv_exit
  #define LOOP_VINFO_BBS(L)                  (L)->bbs
  #define LOOP_VINFO_NBBS(L)                 (L)->nbbs
  #define LOOP_VINFO_NITERSM1(L)             (L)->num_itersm1
  #define LOOP_VINFO_NITERS(L)               (L)->num_iters
  /* Since LOOP_VINFO_NITERS and LOOP_VINFO_NITERSM1 can change after
     prologue peeling retain total unchanged scalar loop iterations for
     cost model.  */
--- 1260,1274 ----
  
  /* Access Functions.  */
  #define LOOP_VINFO_LOOP(L)                 (L)->loop
! #define LOOP_VINFO_MAIN_EXIT(L)              (L)->vec_loop_main_exit
! #define LOOP_VINFO_EPILOGUE_MAIN_EXIT(L)     (L)->vec_epilogue_loop_main_exit
! #define LOOP_VINFO_SCALAR_MAIN_EXIT(L)       (L)->scalar_loop_main_exit
  #define LOOP_VINFO_BBS(L)                  (L)->bbs
  #define LOOP_VINFO_NBBS(L)                 (L)->nbbs
  #define LOOP_VINFO_NITERSM1(L)             (L)->num_itersm1
  #define LOOP_VINFO_NITERS(L)               (L)->num_iters
+ #define LOOP_VINFO_NITERS_UNCOUNTED_P(L)   (LOOP_VINFO_NITERS (L) \
+ 					    == chrec_dont_know)
  /* Since LOOP_VINFO_NITERS and LOOP_VINFO_NITERSM1 can change after
     prologue peeling retain total unchanged scalar loop iterations for
     cost model.  */
*************** public:
*** 1311,1322 ****
  #define LOOP_VINFO_EARLY_BREAKS(L)         (L)->early_breaks
  #define LOOP_VINFO_EARLY_BRK_STORES(L)     (L)->early_break_stores
  #define LOOP_VINFO_EARLY_BREAKS_VECT_PEELED(L)  \
!   (single_pred ((L)->loop->latch) != (L)->vec_loop_iv_exit->src)
  #define LOOP_VINFO_EARLY_BREAKS_LIVE_IVS(L)  \
    (L)->early_break_live_ivs
  #define LOOP_VINFO_EARLY_BRK_DEST_BB(L)    (L)->early_break_dest_bb
  #define LOOP_VINFO_EARLY_BRK_VUSES(L)      (L)->early_break_vuses
  #define LOOP_VINFO_EARLY_BRK_NITERS_VAR(L) (L)->early_break_niters_var
  #define LOOP_VINFO_LOOP_CONDS(L)           (L)->conds
  #define LOOP_VINFO_LOOP_IV_COND(L)         (L)->loop_iv_cond
  #define LOOP_VINFO_NO_DATA_DEPENDENCIES(L) (L)->no_data_dependencies
--- 1317,1330 ----
  #define LOOP_VINFO_EARLY_BREAKS(L)         (L)->early_breaks
  #define LOOP_VINFO_EARLY_BRK_STORES(L)     (L)->early_break_stores
  #define LOOP_VINFO_EARLY_BREAKS_VECT_PEELED(L)  \
!   ((single_pred ((L)->loop->latch) != (L)->vec_loop_main_exit->src) \
!    || LOOP_VINFO_NITERS_UNCOUNTED_P (L))
  #define LOOP_VINFO_EARLY_BREAKS_LIVE_IVS(L)  \
    (L)->early_break_live_ivs
  #define LOOP_VINFO_EARLY_BRK_DEST_BB(L)    (L)->early_break_dest_bb
  #define LOOP_VINFO_EARLY_BRK_VUSES(L)      (L)->early_break_vuses
  #define LOOP_VINFO_EARLY_BRK_NITERS_VAR(L) (L)->early_break_niters_var
+ #define LOOP_VINFO_EARLY_BRK_IV_TYPE(L)    (L)->early_break_iv_type
  #define LOOP_VINFO_LOOP_CONDS(L)           (L)->conds
  #define LOOP_VINFO_LOOP_IV_COND(L)         (L)->loop_iv_cond
  #define LOOP_VINFO_NO_DATA_DEPENDENCIES(L) (L)->no_data_dependencies
*************** extern bool slpeel_can_duplicate_loop_p
*** 2464,2470 ****
  class loop *slpeel_tree_duplicate_loop_to_edge_cfg (class loop *, edge,
  						    class loop *, edge,
  						    edge, edge *, bool = true,
! 						    vec<basic_block> * = NULL);
  class loop *vect_loop_versioning (loop_vec_info, gimple *);
  extern class loop *vect_do_peeling (loop_vec_info, tree, tree,
  				    tree *, tree *, tree *, int, bool, bool,
--- 2472,2479 ----
  class loop *slpeel_tree_duplicate_loop_to_edge_cfg (class loop *, edge,
  						    class loop *, edge,
  						    edge, edge *, bool = true,
! 						    vec<basic_block> * = NULL,
! 						    bool = false, bool = false);
  class loop *vect_loop_versioning (loop_vec_info, gimple *);
  extern class loop *vect_do_peeling (loop_vec_info, tree, tree,
  				    tree *, tree *, tree *, int, bool, bool,
*************** extern tree vect_gen_loop_len_mask (loop
*** 2672,2678 ****
  extern gimple_seq vect_gen_len (tree, tree, tree, tree);
  extern vect_reduc_info info_for_reduction (loop_vec_info, slp_tree);
  extern bool reduction_fn_for_scalar_code (code_helper, internal_fn *);
! 
  /* Drive for loop transformation stage.  */
  extern class loop *vect_transform_loop (loop_vec_info, gimple *);
  struct vect_loop_form_info
--- 2681,2687 ----
  extern gimple_seq vect_gen_len (tree, tree, tree, tree);
  extern vect_reduc_info info_for_reduction (loop_vec_info, slp_tree);
  extern bool reduction_fn_for_scalar_code (code_helper, internal_fn *);
! extern unsigned vect_min_prec_for_max_niters (loop_vec_info, unsigned int);
  /* Drive for loop transformation stage.  */
  extern class loop *vect_transform_loop (loop_vec_info, gimple *);
  struct vect_loop_form_info
diff -Nrcpad gcc-16-20251214/gcc/tree.cc gcc-16-20251221/gcc/tree.cc
*** gcc-16-20251214/gcc/tree.cc	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/gcc/tree.cc	Sun Dec 21 22:32:14 2025
*************** variably_modified_type_p (tree type, tre
*** 8605,8611 ****
      case POINTER_TYPE:
      case REFERENCE_TYPE:
      case VECTOR_TYPE:
!       /* Ada can have pointer types refering to themselves indirectly.  */
        if (TREE_VISITED (type))
  	return false;
        TREE_VISITED (type) = true;
--- 8605,8611 ----
      case POINTER_TYPE:
      case REFERENCE_TYPE:
      case VECTOR_TYPE:
!       /* Ada can have pointer types referring to themselves indirectly.  */
        if (TREE_VISITED (type))
  	return false;
        TREE_VISITED (type) = true;
diff -Nrcpad gcc-16-20251214/gcc/var-tracking.cc gcc-16-20251221/gcc/var-tracking.cc
*** gcc-16-20251214/gcc/var-tracking.cc	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/gcc/var-tracking.cc	Sun Dec 21 22:32:14 2025
*************** vt_expand_var_loc_chain (variable *var,
*** 8397,8403 ****
  	  next = loc;
  	  cloc = cloc->next;
  	  if (unsuitable_loc (loc_from))
! 	    continue;
  	}
        else
  	{
--- 8397,8403 ----
  	  next = loc;
  	  cloc = cloc->next;
  	  if (unsuitable_loc (loc_from))
! 	    goto try_next_loc;
  	}
        else
  	{
*************** vt_expand_var_loc_chain (variable *var,
*** 8437,8442 ****
--- 8437,8443 ----
  	  result = NULL;
  	}
  
+     try_next_loc:
        /* Set it up in case we leave the loop.  */
        depth.complexity = depth.entryvals = 0;
        loc_from = NULL;
diff -Nrcpad gcc-16-20251214/gcc/vec.h gcc-16-20251221/gcc/vec.h
*** gcc-16-20251214/gcc/vec.h	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/gcc/vec.h	Sun Dec 21 22:32:14 2025
*************** public:
*** 1670,1676 ****
    {
      m_auto.embedded_init (N, 0, 1);
      /* ???  Instead of initializing m_vec from &m_auto directly use an
!        expression that avoids refering to a specific member of 'this'
         to derail the -Wstringop-overflow diagnostic code, avoiding
         the impression that data accesses are supposed to be to the
         m_auto member storage.  */
--- 1670,1676 ----
    {
      m_auto.embedded_init (N, 0, 1);
      /* ???  Instead of initializing m_vec from &m_auto directly use an
!        expression that avoids referring to a specific member of 'this'
         to derail the -Wstringop-overflow diagnostic code, avoiding
         the impression that data accesses are supposed to be to the
         m_auto member storage.  */
diff -Nrcpad gcc-16-20251214/libga68/ChangeLog gcc-16-20251221/libga68/ChangeLog
*** gcc-16-20251214/libga68/ChangeLog	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/libga68/ChangeLog	Sun Dec 21 22:32:14 2025
***************
*** 1,3 ****
--- 1,8 ----
+ 2025-12-16  Pietro Monteiro  <pietro@sociotechnical.xyz>
+ 
+ 	* ga68-unistr.c (_libga68_u32_cmp): Add `static' specifier.
+ 	* ga68.h (_libga68_u32_cmp): Remove prototype.
+ 
  2025-11-30  Jose E. Marchesi  <jose.marchesi@oracle.com>
  
  	* Makefile.am: New file.
diff -Nrcpad gcc-16-20251214/libga68/ga68-unistr.c gcc-16-20251221/libga68/ga68-unistr.c
*** gcc-16-20251214/libga68/ga68-unistr.c	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/libga68/ga68-unistr.c	Sun Dec 21 22:32:14 2025
***************
*** 56,62 ****
  /* Compare two UCS-4 strings of same lenght, lexicographically.
     Return -1, 0 or 1.  */
  
! int
  _libga68_u32_cmp (const uint32_t *s1, size_t stride1,
  		  const uint32_t *s2, size_t stride2,
  		  size_t n)
--- 56,62 ----
  /* Compare two UCS-4 strings of same lenght, lexicographically.
     Return -1, 0 or 1.  */
  
! static int
  _libga68_u32_cmp (const uint32_t *s1, size_t stride1,
  		  const uint32_t *s2, size_t stride2,
  		  size_t n)
diff -Nrcpad gcc-16-20251214/libga68/ga68.h gcc-16-20251221/libga68/ga68.h
*** gcc-16-20251214/libga68/ga68.h	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/libga68/ga68.h	Sun Dec 21 22:32:14 2025
*************** long long int _libga68_posixlseek (int f
*** 104,112 ****
  
  /* ga68-unistr.c  */
  
- int _libga68_u32_cmp (const uint32_t *s1, size_t stride1,
- 		      const uint32_t *s2, size_t stride2,
- 		      size_t n);
  int _libga68_u32_cmp2 (const uint32_t *s1, size_t n1, size_t stride1,
  		       const uint32_t *s2, size_t n2, size_t stride2);
  int _libga68_u8_uctomb (uint8_t *s, uint32_t uc, ptrdiff_t n);
--- 104,109 ----
diff -Nrcpad gcc-16-20251214/libgcc/ChangeLog gcc-16-20251221/libgcc/ChangeLog
*** gcc-16-20251214/libgcc/ChangeLog	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/libgcc/ChangeLog	Sun Dec 21 22:32:14 2025
***************
*** 1,3 ****
--- 1,9 ----
+ 2025-12-15  Peter Damianov  <peter0x44@disroot.org>
+ 
+ 	* config/score/crti.S: Delete.
+ 	* config/score/crtn.S: Delete.
+ 	* config/score/sfp-machine.h: Delete.
+ 
  2025-12-12  mengqinggang  <mengqinggang@loongson.cn>
  
  	* configure: Regenerate.
diff -Nrcpad gcc-16-20251214/libgcc/config/score/crti.S gcc-16-20251221/libgcc/config/score/crti.S
*** gcc-16-20251214/libgcc/config/score/crti.S	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/libgcc/config/score/crti.S	Thu Jan  1 00:00:00 1970
***************
*** 1,131 ****
- # crti.S for Sunplus S+CORE
- #
- #   Copyright (C) 2005-2025 Free Software Foundation, Inc.
- #
- # This file 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 file 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/>.
- 
- # This file makes a stack frame for the contents of the .init and
- # .fini sections.
- .extern _stack
- 
- #ifndef __pic__
- .section .init, "ax", @progbits
-         .weak   _start
-         .ent    _start
-         .frame  r0, 0, r3, 0
-         .mask   0x00000000, 0
- _start:
-         la      r28, _gp
-         la      r8, __bss_start
-         la      r9, __bss_end__
-         sub!    r9, r8
-         srli!   r9, 2
-         addi    r9, -1
-         mtsr    r9, sr0
-         li      r9, 0
- 1:
-         sw      r9, [r8]+, 4
-         bcnz    1b
-         la      r0, _stack
-         jl      _init
-         la      r4, _end
-         jl      _init_argv
-         jl      exit
-         .end    _start
- 
-         .weak   _init_argv
-         .ent
-         .frame  r0, 0, r3, 0
-         .mask   0x00000000, 0
- _init_argv:
-         ldiu!   r4, 0
-         ldiu!   r5, 0
-         j       main
-         .end    _init_argv
- 
-         .globl  _init
-         .type   _init, %function
- _init:
-         addi    r0, -32
-         sw      r3, [r0, 20]
- 
-         .section .fini, "ax", @progbits
-         .globl  _fini
-         .type   _fini, %function
- _fini:
-         addi    r0, -32
-         sw      r3, [r0, 20]
- #else
- .section .init, "ax", @progbits
-         .set    pic
-         .weak   _start
-         .ent    _start
-         .frame  r0, 0, r3, 0
-         .mask   0x00000000, 0
- _start:
-         mv      r29, r3
-         bl      0f
- 0:
-         .cpload r3
-         mv      r3, r29
-         la      r8, __bss_start
-         la      r9, __bss_end__
-         sub!    r9, r8
-         srli!   r9, 2
-         addi    r9, -1
-         mtsr    r9, sr0
-         li      r9, 0
- 1:
-         sw      r9, [r8]+, 4
-         bcnz    1b
-         la      r0, _stack
-         bl      _init
-         la      r4, _end
-         la      r29, _init_argv
-         brl     r29
-         la      r29, exit
-         brl     r29
-         .end    _start
- 
-         .weak   _init_argv
-         .ent _init_argv
-         .frame  r0, 0, r3, 0
-         .mask   0x00000000, 0
- _init_argv:
-         ldiu!   r4, 0
-         ldiu!   r5, 0
-         la      r29, main
-         brl     r29
-         .end    _init_argv
- 
-         .globl  _init
-         .type   _init, %function
- _init:
-         addi    r0, -32
-         sw      r3, [r0, 20]
- 
-         .section .fini, "ax", @progbits
-         .globl  _fini
-         .type   _fini, %function
- _fini:
-         addi    r0, -32
-         sw      r3, [r0, 20]
- 
- #endif
--- 0 ----
diff -Nrcpad gcc-16-20251214/libgcc/config/score/crtn.S gcc-16-20251221/libgcc/config/score/crtn.S
*** gcc-16-20251214/libgcc/config/score/crtn.S	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/libgcc/config/score/crtn.S	Thu Jan  1 00:00:00 1970
***************
*** 1,50 ****
- # crtn.S for Sunplus S+CORE
- 
- #   Copyright (C) 2005-2025 Free Software Foundation, Inc.
- #
- # This file 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 file 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/>.
- 
- # This file makes sure that the .init and .fini sections do in
- # fact return.
- 
- #ifndef __pic__
- .section .init, "ax", @progbits
-         lw      r3, [r0, 20]
-         addi    r0, 32
-         br      r3
- 
- .section .fini, "ax", @progbits
-         lw      r3, [r0, 20]
-         addi    r0, 32
-         br      r3
- #else
-         .set    pic
- .section .init, "ax", @progbits
-         lw      r3, [r0, 20]
-         addi    r0, 32
-         br      r3
- 
-         .set    pic
- .section .fini, "ax", @progbits
-         lw      r3, [r0, 20]
-         addi    r0, 32
-         br      r3
- #endif
- 
--- 0 ----
diff -Nrcpad gcc-16-20251214/libgcc/config/score/sfp-machine.h gcc-16-20251221/libgcc/config/score/sfp-machine.h
*** gcc-16-20251214/libgcc/config/score/sfp-machine.h	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/libgcc/config/score/sfp-machine.h	Thu Jan  1 00:00:00 1970
***************
*** 1,61 ****
- #define _FP_W_TYPE_SIZE		32
- #define _FP_W_TYPE		unsigned long
- #define _FP_WS_TYPE		signed long
- #define _FP_I_TYPE		long
- 
- /* The type of the result of a floating point comparison.  This must
-    match `__libgcc_cmp_return__' in GCC for the target.  */
- typedef int __gcc_CMPtype __attribute__ ((mode (__libgcc_cmp_return__)));
- #define CMPtype __gcc_CMPtype
- 
- #define _FP_MUL_MEAT_S(R,X,Y)				\
-   _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_S,R,X,Y,umul_ppmm)
- #define _FP_MUL_MEAT_D(R,X,Y)				\
-   _FP_MUL_MEAT_2_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm)
- #define _FP_MUL_MEAT_Q(R,X,Y)				\
-   _FP_MUL_MEAT_4_wide(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm)
- 
- #define _FP_DIV_MEAT_S(R,X,Y)	_FP_DIV_MEAT_1_loop(S,R,X,Y)
- #define _FP_DIV_MEAT_D(R,X,Y)	_FP_DIV_MEAT_2_udiv(D,R,X,Y)
- #define _FP_DIV_MEAT_Q(R,X,Y)	_FP_DIV_MEAT_4_udiv(Q,R,X,Y)
- 
- #define _FP_NANFRAC_S		((_FP_QNANBIT_S << 1) - 1)
- #define _FP_NANFRAC_D		((_FP_QNANBIT_D << 1) - 1), -1
- #define _FP_NANFRAC_Q		((_FP_QNANBIT_Q << 1) - 1), -1, -1, -1
- #define _FP_NANSIGN_S		0
- #define _FP_NANSIGN_D		0
- #define _FP_NANSIGN_Q		0
- 
- #define _FP_KEEPNANFRACP 1
- #define _FP_QNANNEGATEDP 0
- 
- /* Someone please check this.  */
- #define _FP_CHOOSENAN(fs, wc, R, X, Y, OP)			\
-   do {								\
-     if ((_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs)		\
- 	&& !(_FP_FRAC_HIGH_RAW_##fs(Y) & _FP_QNANBIT_##fs))	\
-       {								\
- 	R##_s = Y##_s;						\
- 	_FP_FRAC_COPY_##wc(R,Y);				\
-       }								\
-     else							\
-       {								\
- 	R##_s = X##_s;						\
- 	_FP_FRAC_COPY_##wc(R,X);				\
-       }								\
-     R##_c = FP_CLS_NAN;						\
-   } while (0)
- 
- /* Not checked.  */
- #define _FP_TININESS_AFTER_ROUNDING 0
- 
- #define	__LITTLE_ENDIAN	1234
- #define	__BIG_ENDIAN	4321
- 
- # define __BYTE_ORDER __BIG_ENDIAN
- 
- /* Define ALIASNAME as a strong alias for NAME.  */
- # define strong_alias(name, aliasname) _strong_alias(name, aliasname)
- # define _strong_alias(name, aliasname) \
-   extern __typeof (name) aliasname __attribute__ ((alias (#name)));
- 
--- 0 ----
diff -Nrcpad gcc-16-20251214/libgfortran/ChangeLog gcc-16-20251221/libgfortran/ChangeLog
*** gcc-16-20251214/libgfortran/ChangeLog	Sun Dec 14 22:32:15 2025
--- gcc-16-20251221/libgfortran/ChangeLog	Sun Dec 21 22:32:14 2025
***************
*** 1,3 ****
--- 1,9 ----
+ 2025-12-15  Jerry DeLisle  <jvdelisle@gcc.gnu.org>
+ 
+ 	PR libfortran/122936
+ 	* io/list_read.c (finish_list_read): Remove the use of hit_eof
+ 	and free_line. Simplify the logic. Add comments to clarify.
+ 
  2025-11-11  Jerry DeLisle  <jvdelisle@gcc.gnu.org>
  
  	PR libfortran/90374
diff -Nrcpad gcc-16-20251214/libgfortran/io/list_read.c gcc-16-20251221/libgfortran/io/list_read.c
*** gcc-16-20251214/libgfortran/io/list_read.c	Sun Dec 14 22:32:16 2025
--- gcc-16-20251221/libgfortran/io/list_read.c	Sun Dec 21 22:32:14 2025
*************** finish_list_read (st_parameter_dt *dtp)
*** 2554,2559 ****
--- 2554,2560 ----
        return;
      }
  
+   /* Only perform the following cleanup on external files or the stdin file.  */
    if (!is_internal_unit (dtp))
      {
        int c;
*************** finish_list_read (st_parameter_dt *dtp)
*** 2561,2583 ****
        /* Set the next_char and push_char worker functions.  */
        set_workers (dtp);
  
!       if (likely (dtp->u.p.child_saved_iostat == LIBERROR_OK)
! 	      && ((dtp->common.flags & IOPARM_DT_HAS_UDTIO) == 0))
  	{
  	  c = next_char (dtp);
! 	  if (c == EOF)
  	    {
! 	      free_line (dtp);
! 	      hit_eof (dtp);
! 	      return;
  	    }
  	  if (c != '\n')
  	    eat_line (dtp);
  	}
      }
- 
-   free_line (dtp);
- 
  }
  
  /*			NAMELIST INPUT
--- 2562,2592 ----
        /* Set the next_char and push_char worker functions.  */
        set_workers (dtp);
  
!       /* Make sure there were no errors from a DTIO child read.  */
!       if (likely (dtp->u.p.child_saved_iostat == LIBERROR_OK))
  	{
+ 	  /* Peek ahead to see where we are in the parent read.  */
  	  c = next_char (dtp);
! 	  unget_char (dtp, c);
! 
! 	  /* If the last read used DTIO, handle end conditions differently.  */
! 	  if ((dtp->common.flags & IOPARM_DT_HAS_UDTIO) != 0)
  	    {
! 	      if ((c == EOF) || (c == ' '))
! 		return;
! 	    }
! 	  else
! 	    {
! 	      if (c == EOF)
! 		{
! 		  hit_eof (dtp);
! 		  return;
! 		}
  	    }
  	  if (c != '\n')
  	    eat_line (dtp);
  	}
      }
  }
  
  /*			NAMELIST INPUT
diff -Nrcpad gcc-16-20251214/libgo/Makefile.am gcc-16-20251221/libgo/Makefile.am
*** gcc-16-20251214/libgo/Makefile.am	Sun Dec 14 22:32:16 2025
--- gcc-16-20251221/libgo/Makefile.am	Sun Dec 21 22:32:14 2025
*************** libgo_go_objs = \
*** 837,843 ****
  	$(golangorg_x_sys_cpu_gccgo_x86_lo)
  
  libgo_ldflags = \
! 	-version-info $(libtool_VERSION) $(PTHREAD_CFLAGS) $(AM_LDFLAGS)
  
  libgo_libadd = \
  	$(libgo_go_objs) ../libbacktrace/libbacktrace.la \
--- 837,844 ----
  	$(golangorg_x_sys_cpu_gccgo_x86_lo)
  
  libgo_ldflags = \
! 	-version-info $(libtool_VERSION) $(PTHREAD_CFLAGS) $(AM_LDFLAGS) \
! 	$(OSLDFLAGS)
  
  libgo_libadd = \
  	$(libgo_go_objs) ../libbacktrace/libbacktrace.la \
diff -Nrcpad gcc-16-20251214/libgo/Makefile.in gcc-16-20251221/libgo/Makefile.in
*** gcc-16-20251214/libgo/Makefile.in	Sun Dec 14 22:32:16 2025
--- gcc-16-20251221/libgo/Makefile.in	Sun Dec 21 22:32:14 2025
*************** OBJCOPY = @OBJCOPY@
*** 453,458 ****
--- 453,459 ----
  OBJDUMP = @OBJDUMP@
  OBJEXT = @OBJEXT@
  OSCFLAGS = @OSCFLAGS@
+ OSLDFLAGS = @OSLDFLAGS@
  OTOOL = @OTOOL@
  OTOOL64 = @OTOOL64@
  PACKAGE = @PACKAGE@
*************** libgo_go_objs = \
*** 972,978 ****
  	$(golangorg_x_sys_cpu_gccgo_x86_lo)
  
  libgo_ldflags = \
! 	-version-info $(libtool_VERSION) $(PTHREAD_CFLAGS) $(AM_LDFLAGS)
  
  libgo_libadd = \
  	$(libgo_go_objs) ../libbacktrace/libbacktrace.la \
--- 973,980 ----
  	$(golangorg_x_sys_cpu_gccgo_x86_lo)
  
  libgo_ldflags = \
! 	-version-info $(libtool_VERSION) $(PTHREAD_CFLAGS) $(AM_LDFLAGS) \
! 	$(OSLDFLAGS)
  
  libgo_libadd = \
  	$(libgo_go_objs) ../libbacktrace/libbacktrace.la \
diff -Nrcpad gcc-16-20251214/libgo/configure gcc-16-20251221/libgo/configure
*** gcc-16-20251214/libgo/configure	Sun Dec 14 22:32:16 2025
--- gcc-16-20251221/libgo/configure	Sun Dec 21 22:32:14 2025
*************** GO_SPLIT_STACK
*** 658,663 ****
--- 658,664 ----
  USING_SPLIT_STACK_FALSE
  USING_SPLIT_STACK_TRUE
  SPLIT_STACK
+ OSLDFLAGS
  HWCAP_CFLAGS
  OSCFLAGS
  GO_SYSCALL_OS_ARCH_FILE
*************** else
*** 11547,11553 ****
    lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
    lt_status=$lt_dlunknown
    cat > conftest.$ac_ext <<_LT_EOF
! #line 11550 "configure"
  #include "confdefs.h"
  
  #if HAVE_DLFCN_H
--- 11548,11554 ----
    lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
    lt_status=$lt_dlunknown
    cat > conftest.$ac_ext <<_LT_EOF
! #line 11551 "configure"
  #include "confdefs.h"
  
  #if HAVE_DLFCN_H
*************** else
*** 11653,11659 ****
    lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
    lt_status=$lt_dlunknown
    cat > conftest.$ac_ext <<_LT_EOF
! #line 11656 "configure"
  #include "confdefs.h"
  
  #if HAVE_DLFCN_H
--- 11654,11660 ----
    lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
    lt_status=$lt_dlunknown
    cat > conftest.$ac_ext <<_LT_EOF
! #line 11657 "configure"
  #include "confdefs.h"
  
  #if HAVE_DLFCN_H
*************** $as_echo "$ac_hwcap_flags" >&6; }
*** 14457,14462 ****
--- 14458,14472 ----
  
  
  
+ case "$target" in
+     *86*-*-solaris2.*)
+ 	# Link with -shared-libgcc on Solaris 11+/x86 as a workaround for
+ 	# PR go/64900.
+ 	OSLDFLAGS="-Wc,-shared-libgcc"
+ 	;;
+ esac
+ 
+ 
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -fsplit-stack is supported" >&5
  $as_echo_n "checking whether -fsplit-stack is supported... " >&6; }
  if ${libgo_cv_c_split_stack_supported+:} false; then :
diff -Nrcpad gcc-16-20251214/libgo/configure.ac gcc-16-20251221/libgo/configure.ac
*** gcc-16-20251214/libgo/configure.ac	Sun Dec 14 22:32:16 2025
--- gcc-16-20251221/libgo/configure.ac	Sun Dec 21 22:32:14 2025
*************** AC_SUBST(OSCFLAGS)
*** 442,447 ****
--- 442,456 ----
  dnl Check if assembler supports disabling hardware capability support.
  GCC_CHECK_ASSEMBLER_HWCAP
  
+ case "$target" in
+     *86*-*-solaris2.*)
+ 	# Link with -shared-libgcc on Solaris 11+/x86 as a workaround for
+ 	# PR go/64900.
+ 	OSLDFLAGS="-Wc,-shared-libgcc"
+ 	;;
+ esac
+ AC_SUBST(OSLDFLAGS)
+ 
  dnl Use -fsplit-stack when compiling C code if available.
  AC_CACHE_CHECK([whether -fsplit-stack is supported],
  [libgo_cv_c_split_stack_supported],
diff -Nrcpad gcc-16-20251214/libgo/go/go.mod gcc-16-20251221/libgo/go/go.mod
*** gcc-16-20251214/libgo/go/go.mod	Sun Dec 14 22:32:16 2025
--- gcc-16-20251221/libgo/go/go.mod	Sun Dec 21 22:32:14 2025
*************** module std
*** 3,9 ****
  go 1.18
  
  require (
! 	golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3
  	golang.org/x/net v0.0.0-20211209124913-491a49abca63
  )
  
--- 3,9 ----
  go 1.18
  
  require (
! 	golang.org/x/crypto v0.33.0
  	golang.org/x/net v0.0.0-20211209124913-491a49abca63
  )
  
diff -Nrcpad gcc-16-20251214/libgo/go/vendor/modules.txt gcc-16-20251221/libgo/go/vendor/modules.txt
*** gcc-16-20251214/libgo/go/vendor/modules.txt	Sun Dec 14 22:32:16 2025
--- gcc-16-20251221/libgo/go/vendor/modules.txt	Sun Dec 21 22:32:15 2025
***************
*** 1,4 ****
! # golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3
  ## explicit; go 1.17
  golang.org/x/crypto/chacha20
  golang.org/x/crypto/chacha20poly1305
--- 1,4 ----
! # golang.org/x/crypto v0.33.0
  ## explicit; go 1.17
  golang.org/x/crypto/chacha20
  golang.org/x/crypto/chacha20poly1305
diff -Nrcpad gcc-16-20251214/libgo/testsuite/Makefile.in gcc-16-20251221/libgo/testsuite/Makefile.in
*** gcc-16-20251214/libgo/testsuite/Makefile.in	Sun Dec 14 22:32:16 2025
--- gcc-16-20251221/libgo/testsuite/Makefile.in	Sun Dec 21 22:32:15 2025
*************** OBJCOPY = @OBJCOPY@
*** 202,207 ****
--- 202,208 ----
  OBJDUMP = @OBJDUMP@
  OBJEXT = @OBJEXT@
  OSCFLAGS = @OSCFLAGS@
+ OSLDFLAGS = @OSLDFLAGS@
  OTOOL = @OTOOL@
  OTOOL64 = @OTOOL64@
  PACKAGE = @PACKAGE@
diff -Nrcpad gcc-16-20251214/libgomp/ChangeLog gcc-16-20251221/libgomp/ChangeLog
*** gcc-16-20251214/libgomp/ChangeLog	Sun Dec 14 22:32:16 2025
--- gcc-16-20251221/libgomp/ChangeLog	Sun Dec 21 22:32:15 2025
***************
*** 1,3 ****
--- 1,22 ----
+ 2025-12-19  Tobias Burnus  <tburnus@baylibre.com>
+ 
+ 	* testsuite/libgomp.fortran/uses_allocators-7.f90: Add ';' test.
+ 
+ 2025-12-18  Tobias Burnus  <tburnus@baylibre.com>
+ 
+ 	* libgomp.texi (OpenMP Implemenation Status): Mark
+ 	no_openmp_constructs as implemented.
+ 
+ 2025-12-17  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
+ 
+ 	* testsuite/libgomp.c/affinity-1.c: Always add warnings.
+ 
+ 2025-12-15  Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	* plugin/build-target-indirect-htab.h (create_target_indirect_map):
+ 	Use (void) htab_find instead of assert (htab_find) to silence
+ 	-Werror=unused-function because the latter triggers -Werror=address.
+ 
  2025-12-12  Tobias Burnus  <tburnus@baylibre.com>
  
  	* testsuite/libgomp.fortran/dep-uses-allocators.f90: Properly
diff -Nrcpad gcc-16-20251214/libgomp/libgomp.texi gcc-16-20251221/libgomp/libgomp.texi
*** gcc-16-20251214/libgomp/libgomp.texi	Sun Dec 14 22:32:16 2025
--- gcc-16-20251221/libgomp/libgomp.texi	Sun Dec 21 22:32:15 2025
*************** to address of matching mapped list item
*** 551,557 ****
  @item @code{message} and @code{severity} clauses to @code{parallel} directive
        @tab N @tab
  @item @code{self_maps} clause to @code{requires} directive @tab Y @tab
! @item @code{no_openmp_constructs} assumptions clause @tab N @tab
  @item Restriction for @code{ordered} regarding loop-transforming directives
        @tab N @tab
  @item @code{apply} clause to loop-transforming constructs @tab N @tab
--- 551,557 ----
  @item @code{message} and @code{severity} clauses to @code{parallel} directive
        @tab N @tab
  @item @code{self_maps} clause to @code{requires} directive @tab Y @tab
! @item @code{no_openmp_constructs} assumptions clause @tab Y @tab
  @item Restriction for @code{ordered} regarding loop-transforming directives
        @tab N @tab
  @item @code{apply} clause to loop-transforming constructs @tab N @tab
diff -Nrcpad gcc-16-20251214/libgomp/plugin/build-target-indirect-htab.h gcc-16-20251221/libgomp/plugin/build-target-indirect-htab.h
*** gcc-16-20251214/libgomp/plugin/build-target-indirect-htab.h	Sun Dec 14 22:32:16 2025
--- gcc-16-20251221/libgomp/plugin/build-target-indirect-htab.h	Sun Dec 21 22:32:15 2025
*************** void*
*** 65,71 ****
  create_target_indirect_map (size_t *h_size, size_t count,
  			    uint64_t *host_addrs, uint64_t *device_addrs)
  {
!   assert (htab_find);  /* Silence -Werror=unused-function.  */
  
    htab_t indirect_htab = htab_create (count);
  
--- 65,71 ----
  create_target_indirect_map (size_t *h_size, size_t count,
  			    uint64_t *host_addrs, uint64_t *device_addrs)
  {
!   (void) htab_find;  /* Silence -Werror=unused-function.  */
  
    htab_t indirect_htab = htab_create (count);
  
diff -Nrcpad gcc-16-20251214/libgomp/testsuite/libgomp.c/affinity-1.c gcc-16-20251221/libgomp/testsuite/libgomp.c/affinity-1.c
*** gcc-16-20251214/libgomp/testsuite/libgomp.c/affinity-1.c	Sun Dec 14 22:32:16 2025
--- gcc-16-20251221/libgomp/testsuite/libgomp.c/affinity-1.c	Sun Dec 21 22:32:15 2025
***************
*** 17,23 ****
  
  /* { dg-do run } */
  /* { dg-set-target-env-var OMP_PROC_BIND "false" } */
! /* { dg-additional-options "-DINTERPOSE_GETAFFINITY -DDO_FORK -ldl -Wno-deprecated-declarations -Wno-deprecated-openmp" { target *-*-linux* } } */
  
  #ifndef _GNU_SOURCE
  #define _GNU_SOURCE
--- 17,24 ----
  
  /* { dg-do run } */
  /* { dg-set-target-env-var OMP_PROC_BIND "false" } */
! /* { dg-additional-options "-Wno-deprecated-declarations -Wno-deprecated-openmp" }
! /* { dg-additional-options "-DINTERPOSE_GETAFFINITY -DDO_FORK -ldl" { target *-*-linux* } } */
  
  #ifndef _GNU_SOURCE
  #define _GNU_SOURCE
diff -Nrcpad gcc-16-20251214/libgomp/testsuite/libgomp.fortran/uses_allocators-7.f90 gcc-16-20251221/libgomp/testsuite/libgomp.fortran/uses_allocators-7.f90
*** gcc-16-20251214/libgomp/testsuite/libgomp.fortran/uses_allocators-7.f90	Sun Dec 14 22:32:16 2025
--- gcc-16-20251221/libgomp/testsuite/libgomp.fortran/uses_allocators-7.f90	Sun Dec 21 22:32:15 2025
*************** program main
*** 6,13 ****
    implicit none (type, external)
    integer :: x, xbuf(10)
    integer(c_intptr_t) :: iptr
!   integer(omp_allocator_handle_kind) :: my_alloc
    type(omp_alloctrait), parameter :: trait(*) = [omp_alloctrait(omp_atk_alignment, 128)]
  
    !$omp target uses_allocators(omp_low_lat_mem_alloc) map(tofrom: x, xbuf) defaultmap(none)
      !$omp parallel allocate(allocator(omp_low_lat_mem_alloc), align(128): x, xbuf) if(.false.) firstprivate(x, xbuf)
--- 6,20 ----
    implicit none (type, external)
    integer :: x, xbuf(10)
    integer(c_intptr_t) :: iptr
!   integer(omp_allocator_handle_kind) :: my_alloc, my, my2, my3, my4
    type(omp_alloctrait), parameter :: trait(*) = [omp_alloctrait(omp_atk_alignment, 128)]
+   type(omp_alloctrait), parameter :: t(*) = [omp_alloctrait:: ]
+   type(omp_alloctrait), parameter :: t2(*) = [omp_alloctrait:: ]
+ 
+   ! FIXME - improve check that that ';' is handled
+   !$omp target uses_allocators(traits(t), memspace(omp_high_bw_mem_space) : my; omp_default_mem_alloc, omp_null_allocator; my2; traits(t2) : my3; memspace(omp_large_cap_mem_space) : my4)
+   block
+   end block
  
    !$omp target uses_allocators(omp_low_lat_mem_alloc) map(tofrom: x, xbuf) defaultmap(none)
      !$omp parallel allocate(allocator(omp_low_lat_mem_alloc), align(128): x, xbuf) if(.false.) firstprivate(x, xbuf)
*************** end
*** 50,58 ****
  ! FIXME ENABLE: 'dg FIXME final' -> 'dg-final'
  ! { dg  FIXME  final { scan-tree-dump-times "#pragma omp target .*private\\(my_alloc\\).*uses_allocators\\(my_alloc: memspace\\(\\), traits\\(trait\\)\\)" 1 "gimple" } }
  ! { dg  FIXME  final { scan-tree-dump-times "#pragma omp target .*private\\(my_alloc\\).*uses_allocators\\(my_alloc: memspace\\(\\), traits\\(\\)\\)" 1 "gimple" } }
  
  ! FIXME ENABLE code above for "gimple" once it has been implemented:
! ! { dg-message "sorry, unimplemented: 'uses_allocators' clause with traits and memory spaces" "" { target *-*-* } 23 }
! ! { dg-message "sorry, unimplemented: 'uses_allocators' clause with traits and memory spaces" "" { target *-*-* } 36 }
! ! { dg-bogus "'my_alloc' not specified in enclosing 'target'" "bogus issue because clause is ignored" { xfail *-*-* } 24 }
! ! { dg-bogus "'my_alloc' not specified in enclosing 'target'" "bogus issue because clause is ignored" { xfail *-*-* } 37 }
--- 57,68 ----
  ! FIXME ENABLE: 'dg FIXME final' -> 'dg-final'
  ! { dg  FIXME  final { scan-tree-dump-times "#pragma omp target .*private\\(my_alloc\\).*uses_allocators\\(my_alloc: memspace\\(\\), traits\\(trait\\)\\)" 1 "gimple" } }
  ! { dg  FIXME  final { scan-tree-dump-times "#pragma omp target .*private\\(my_alloc\\).*uses_allocators\\(my_alloc: memspace\\(\\), traits\\(\\)\\)" 1 "gimple" } }
+ ! { dg  FIXME  final { scan-tree-dump "#pragma omp target uses_allocators\\(memspace\\(1\\), traits\\(\\) : my4\\) uses_allocators\\(memspace\\(\\), traits\\(t2\\) : my3\\) uses_allocators\\(memspace\\(\\), traits\\(\\) : my2\\) uses_allocators\\(memspace\\(3\\), traits\\(t\\) : my\\)" 1 "original" } }
+ 
  
  ! FIXME ENABLE code above for "gimple" once it has been implemented:
! ! { dg-message "sorry, unimplemented: 'uses_allocators' clause with traits and memory spaces" "" { target *-*-* } 15 }
! ! { dg-message "sorry, unimplemented: 'uses_allocators' clause with traits and memory spaces" "" { target *-*-* } 30 }
! ! { dg-message "sorry, unimplemented: 'uses_allocators' clause with traits and memory spaces" "" { target *-*-* } 43 }
! ! { dg-bogus "'my_alloc' not specified in enclosing 'target'" "bogus issue because clause is ignored" { xfail *-*-* } 31 }
! ! { dg-bogus "'my_alloc' not specified in enclosing 'target'" "bogus issue because clause is ignored" { xfail *-*-* } 44 }
diff -Nrcpad gcc-16-20251214/libstdc++-v3/ChangeLog gcc-16-20251221/libstdc++-v3/ChangeLog
*** gcc-16-20251214/libstdc++-v3/ChangeLog	Sun Dec 14 22:32:17 2025
--- gcc-16-20251221/libstdc++-v3/ChangeLog	Sun Dec 21 22:32:15 2025
***************
*** 1,3 ****
--- 1,296 ----
+ 2025-12-19  Tomasz Kamiński  <tkaminsk@redhat.com>
+ 
+ 	PR libstdc++/112591
+ 	* include/std/variant (_Uninitialized::_M_get, __get_n)
+ 	(_Uninitialized<_Type, false>): Add _GLIBCXX_USE_VARIANT_CXX17_OLD_ABI
+ 	check to preprocessor guard.
+ 	* testsuite/20_util/variant/112591.cc: Updated tests.
+ 	* testsuite/20_util/variant/112591_compat.cc: New test.
+ 	* testsuite/20_util/variant/constinit.cc: New test.
+ 	* testsuite/20_util/variant/constinit_compat.cc: New test.
+ 
+ 2025-12-19  Tomasz Kamiński  <tkaminsk@redhat.com>
+ 
+ 	* testsuite/26_numerics/random/uniform_real_distribution/operators/gencanon_eng.cc:
+ 	Test __float128 when available.
+ 
+ 2025-12-19  Tomasz Kamiński  <tkaminsk@redhat.com>
+ 
+ 	* include/bits/random.h (__rand_uint128::operator>)
+ 	(__rand_uint128::operator>=): Define.
+ 	* include/bits/random.tcc (__generate_canonical_pow2):
+ 	Adjust for use of __rand_uint128 in C++11.
+ 	(__gen_can_pow, __gen_can_rng_calls_needed): Replace with
+ 	__gen_canon_log.
+ 	(__gen_canon_log_res, __gen_canon_log): Define.
+ 	(__generate_canonical_any): Reworked how _UInt is determined.
+ 	* testsuite/26_numerics/random/uniform_real_distribution/operators/gencanon_eng.cc:
+ 	New test.
+ 
+ 2025-12-19  Jonathan Wakely  <jwakely@redhat.com>
+ 
+ 	PR libstdc++/123147
+ 	* include/bits/chrono_io.h (_Parser::operator()) <%S>: Use a
+ 	buffer of narrow characters to be parsed by std::from_chars.
+ 	* testsuite/std/time/parse/parse.cc: Check wchar_t parsing.
+ 
+ 2025-12-19  Tomasz Kamiński  <tkaminsk@redhat.com>
+ 
+ 	* include/debug/helper_functions.h (__gnu_debug::__can_advance):
+ 	Declare as _GLIBCXX20_CONSTEXPR.
+ 	* include/debug/safe_iterator.h (__gnu_debug::__can_advance):
+ 	Define as _GLIBCXX20_CONSTEXPR, and return true for constexpr
+ 	evaluation.
+ 	(__gnu_debug::__base): Define as _GLIBCXX20_CONSTEXPR.
+ 
+ 2025-12-19  Jonathan Wakely  <jwakely@redhat.com>
+ 
+ 	* src/c++11/mutex.cc [_GLIBCXX_NO_EXTERN_THREAD_LOCAL]
+ 	(__get_once_call): Use std::add_lvalue_reference.
+ 
+ 2025-12-18  Jonathan Wakely  <jwakely@redhat.com>
+ 
+ 	* include/bits/chrono_io.h (__formatter_chrono::_M_write): Add
+ 	maybe_unused attribute to avoid -Wunused-parameter warning.
+ 	* src/c++20/tzdb.cc (detect_windows_zone): Decay array to
+ 	pointer to avoid -Warray-compare warning.
+ 
+ 2025-12-18  LIU Hao  <lh_mouse@126.com>
+ 	    Jonathan Wakely  <jwakely@redhat.com>
+ 
+ 	* config/os/mingw32-w64/os_defines.h (_GLIBCXX_NO_EXTERN_THREAD_LOCAL):
+ 	New macro.
+ 	* include/std/mutex [_GLIBCXX_NO_EXTERN_THREAD_LOCAL]
+ 	(__get_once_callable, __get_once_call): Declare new functions.
+ 	* src/c++11/mutex.cc [_GLIBCXX_NO_EXTERN_THREAD_LOCAL]
+ 	(__get_once_callable, __get_once_call): Define.
+ 
+ 2025-12-18  Jonathan Wakely  <jwakely@redhat.com>
+ 
+ 	PR libstdc++/123180
+ 	* include/bits/ranges_algo.h (__stable_sort_fn::operator()): Fix
+ 	sense of null check. Replace typedef with alias-declaration.
+ 	* testsuite/25_algorithms/stable_sort/123180.cc: New test.
+ 
+ 2025-12-18  Jonathan Wakely  <jwakely@redhat.com>
+ 	    Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	* include/bits/random.tcc (__generate_canonical_pow2): Adjust
+ 	comments. Remove _UInt template parameter and define it in the
+ 	body using _Select_uint_least_t<__d>. Remove popcount call for
+ 	getting the width of the _UInt type. Cast floating-point
+ 	literal to _RealT.
+ 	(__generate_canonical_any): Remove _UInt template parameter and
+ 	define it in the body using _Select_uint_least_t<__d * 2>. Use
+ 	direct-initialization for _UInt variables. Cast floating-point
+ 	literal to _RealT.
+ 	(generate_canonical): Remove unused typedef. Remove constexpr-if
+ 	branches and remove unsigned type from template argument lists.
+ 
+ 2025-12-17  Jonathan Wakely  <jwakely@redhat.com>
+ 
+ 	* include/bits/version.def (constexpr_exceptions): Add
+ 	cxx11abi=yes.
+ 	* include/bits/version.h: Regenerate.
+ 	* testsuite/18_support/exception/version.cc: Require effectiove
+ 	target cxx11_abi.
+ 	* testsuite/18_support/exception_ptr/exception_ptr_cast.cc: Only
+ 	check for constexpr support in cxx11 ABI.
+ 	* testsuite/19_diagnostics/headers/stdexcept/version.cc: Require
+ 	effective target cxx11_abi.
+ 	* testsuite/19_diagnostics/logic_error/constexpr.cc: Likewise.
+ 	* testsuite/19_diagnostics/runtime_error/constexpr.cc: Likewise.
+ 	* testsuite/20_util/expected/version.cc: Only check for
+ 	__cpp_lib_constexpr_exceptions macro for cxx11 ABI.
+ 	* testsuite/20_util/optional/version.cc: Likewise.
+ 	* testsuite/20_util/variant/version.cc: Likewise.
+ 
+ 2025-12-17  Jonathan Wakely  <jwakely@redhat.com>
+ 	    Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	* include/bits/random.h [!__SIZEOF_INT128__] (__rand_uint128):
+ 	Refactor and rename _Select_uint_least_t<128>::type to a new
+ 	class. Make all members constexpr. Add new member functions for
+ 	additional arithmetic and bitwise operations, and comparisons.
+ 	(__detail::_Select_uint_least_t<>::type): Define as an alias of
+ 	__rand_uint128.
+ 	* include/bits/random.tcc (philox_engine::_M_mulhi): Use
+ 	_Select_uint_least_t<w*2>::type instead of __uint128_t.
+ 	(philox_engine::_M_transition): Likewise.
+ 	* include/bits/version.def (philox_engine): Remove extra_cond.
+ 	* include/bits/version.h: Regenerate.
+ 	* testsuite/26_numerics/random/philox4x32.cc: Remove
+ 	dg-require-cpp-feature-test directive.
+ 	* testsuite/26_numerics/random/philox4x64.cc: Likewise.
+ 	* testsuite/26_numerics/random/philox_engine/cons/copy.cc:
+ 	Likewise.
+ 	* testsuite/26_numerics/random/philox_engine/cons/default.cc:
+ 	Likewise.
+ 	* testsuite/26_numerics/random/philox_engine/cons/seed.cc:
+ 	Likewise.
+ 	* testsuite/26_numerics/random/philox_engine/operators/equal.cc:
+ 	Likewise.
+ 	* testsuite/26_numerics/random/philox_engine/operators/serialize.cc:
+ 	Likewise.
+ 	* testsuite/26_numerics/random/philox_engine/requirements/constants.cc:
+ 	Likewise.
+ 	* testsuite/26_numerics/random/philox_engine/requirements/typedefs.cc:
+ 	Likewise.
+ 
+ 2025-12-17  Jonathan Wakely  <jwakely@redhat.com>
+ 
+ 	* testsuite/26_numerics/random/uniform_real_distribution/operators/64351.cc:
+ 	Add -fexcess-precision=standard to options.
+ 	* testsuite/26_numerics/random/uniform_real_distribution/operators/gencanon.cc:
+ 	Likewise.
+ 
+ 2025-12-17  Jonathan Wakely  <jwakely@redhat.com>
+ 
+ 	* testsuite/26_numerics/random/uniform_real_distribution/operators/64351.cc
+ 	[_GLIBCXX_USE_OLD_GENERATE_CANONICAL]: Restore test01. Do not discard an
+ 	extra value in test02.
+ 	* testsuite/26_numerics/random/uniform_real_distribution/operators/gencanon.cc:
+ 	Skip if _GLIBCXX_USE_OLD_GENERATE_CANONICAL is defined in options.
+ 
+ 2025-12-17  Jonathan Wakely  <jwakely@redhat.com>
+ 
+ 	* include/bits/random.h [!_GLIBCXX_USE_OLD_GENERATE_CANONICAL]
+ 	(generate_canonical): Use inline namespace _V2.
+ 	* include/bits/random.tcc [!_GLIBCXX_USE_OLD_GENERATE_CANONICAL]
+ 	(generate_canonical): Likewise.
+ 	* testsuite/26_numerics/random/pr60037-neg.cc: Remove lineno so
+ 	that one dg-error matches both diagnostics.
+ 
+ 2025-12-17  Jonathan Wakely  <jwakely@redhat.com>
+ 
+ 	* include/bits/random.tcc [_GLIBCXX_USE_OLD_GENERATE_CANONICAL]
+ 	(generate_canonical): Restore braces around statement.
+ 
+ 2025-12-17  Tomasz Kamiński  <tkaminsk@redhat.com>
+ 
+ 	* include/bits/random.tcc (generate_canonical)
+ 	[!_GLIBCXX_USE_OLD_GENERATE_CANONICAL]: Use static_assert
+ 	instead of type-constraint on template parameter.
+ 	* testsuite/26_numerics/random/pr60037-neg.cc: Updated line
+ 	of error.
+ 
+ 2025-12-17  Tomasz Kamiński  <tkaminsk@redhat.com>
+ 
+ 	* include/bits/random.tcc (generate_canonical): Update
+ 	error message to match pre-existing one in random.h.
+ 	* testsuite/26_numerics/random/pr60037-neg.cc: Updated
+ 	line for error message.
+ 
+ 2025-12-17  Jakub Jelinek  <jakub@redhat.com>
+ 
+ 	* include/bits/random.tcc (std::generate_canonical): Use
+ 	__extension__ before __generate_canonical_{pow2,any} calls with
+ 	unsigned __int128 template arguments.
+ 
+ 2025-12-17  Tomasz Kamiński  <tkaminsk@redhat.com>
+ 
+ 	* include/bits/atomic_base.h
+ 	(__atomic_ref_base<const _Tp>::__atomic_ref_base): Accept
+ 	pointer instead of reference. Remove precondition check and
+ 	mark as noexcept.
+ 	(__atomic_ref_base<_Tp>::__atomic_ref_base): Accept pointer
+ 	insted of reference, and mark as noexcept.
+ 	* include/std/atomic (atomic_ref::atomic_ref(_Tp&)): Add
+ 	precondition check and take address of argument.
+ 	(atomic_ref::atomic_ref(_Tp&&)): Define as deleted.
+ 	(atomic_ref::atomic_ref(atomic_ref<_Up>)): Define.
+ 	* include/bits/shared_ptr_atomic.h (_Sp_atomic::_Atomic_count):
+ 	Pass address to __atomic_ref constructor.
+ 	* include/std/barrier (__tree_barrier_base::_M_arrive)
+ 	(__tree_barrier::arrive): Pass address to __atomic_ref constructor.
+ 	* testsuite/29_atomics/atomic_ref/ctor.cc: New test.
+ 
+ 2025-12-16  Jonathan Wakely  <jwakely@redhat.com>
+ 
+ 	* include/std/type_traits (_Integer_kind): New enum type.
+ 	(__is_integral_helper::_S_kind): New static data member in
+ 	primary template and each explicit specialization.
+ 	(__is_signed_integer, __is_unsigned_integer): Use _S_kind
+ 	instead of O(n) disjunction with is_same.
+ 
+ 2025-12-16  Jonathan Wakely  <jwakely@redhat.com>
+ 
+ 	PR libstdc++/122907
+ 	* include/bits/cpp_type_traits.h (__memcpyable_integer<bool>):
+ 	Define as false.
+ 	* testsuite/25_algorithms/copy/122907.cc: New test.
+ 
+ 2025-12-16  Jonathan Wakely  <jwakely@redhat.com>
+ 
+ 	* testsuite/lib/libstdc++.exp (dg-v3-runtest) Set default_std to
+ 	20.
+ 
+ 2025-12-16  Jonathan Wakely  <jwakely@redhat.com>
+ 
+ 	* include/std/chrono (chrono::__detail::__get_leap_second_info):
+ 	Update expiry date for leap seconds list.
+ 	* src/c++20/tzdb.cc (tzdb_list::_Node::_S_read_leap_seconds):
+ 	Likewise.
+ 	* src/c++20/tzdata.zi: Import new file from 2025c release.
+ 
+ 2025-12-16  Nathan Myers  <ncm@cantrip.org>
+ 
+ 	PR libstdc++/119739
+ 	* include/bits/random.tcc: Add generate_canonical impl for C++26.
+ 	* testsuite/26_numerics/random/uniform_real_distribution/operators/64351.cc:
+ 	Adapt test for both pre- and post- C++26.
+ 	* testsuite/26_numerics/random/uniform_real_distribution/operators/gencanon.cc:
+ 	Test for float and double from 32-bit RNG, including 1.0 do-over.
+ 
+ 2025-12-16  Patrick Palka  <ppalka@redhat.com>
+ 
+ 	PR libstdc++/113299
+ 	* include/bits/deque.tcc (__copy_move_a1): Constrain with
+ 	__is_any_random_access_iter instead of __is_random_access_iter.
+ 	(__copy_move_backward_a1): Likewise.
+ 	(__equal_aux1): Likewise.
+ 	* include/bits/stl_algo.h (__search_n): Use
+ 	__iter_concept_or_category instead of __iterator_category
+ 	or iterator_traits::iterator_category.
+ 	(find_end): Likewise.
+ 	(__is_permutation): Likewise.
+ 	(for_each_n): Likewise.
+ 	(unique_copy): Likewise, for constant iterators.
+ 	(sample): Likewise, for constant iterators.
+ 	* include/bits/stl_algobase.h (__copy_move_a1): Adjust
+ 	deque-based forward declaration accordingly.
+ 	(__copy_move_backward_a1): Likewise.
+ 	(__equal_aux1): Likewise.
+ 	(__lexicographical_compare_impl): Use
+ 	__iter_concept_or_category instead of __iterator_category or
+ 	iterator_traits::iterator_category.
+ 	(__equal4): Likewise.
+ 	* include/bits/stl_iterator_base_funcs.h
+ 	(__iter_concept_or_category): New.
+ 	(__is_any_random_access_iter): New.
+ 	(_GLIBCXX_ITER_MOVE): New.
+ 	* include/bits/stl_uninitialized.h (uninitialized_copy_n):
+ 	Use __iterator_concept_or_category instead of
+ 	__iterator_category for the constant iterator __first.
+ 	(__uninitialized_copy_n_pair): Likewise.
+ 	* include/bits/version.def (algorithm_iterator_requirements):
+ 	Define.
+ 	* include/bits/version.h: Regenerate.
+ 	* include/std/algorithm: Provide the FTM
+ 	__cpp_lib_algorithm_iterator_requirements.
+ 	* include/std/memory: Likewise.
+ 	* include/std/numeric: Likewise.  Include
+ 	<bits/stl_iterator_base_funcs.h>.
+ 	(reduce): Use __is_any_random_access_iter instead of
+ 	__is_random_access_iter.
+ 	(transform_reduce): Likewise.
+ 	(inclusive_scan): Use _GLIBCXX_ITER_MOVE instead of std::move.
+ 	* testsuite/25_algorithms/find_end/c++20_iter.cc: New test.
+ 	* testsuite/25_algorithms/sample/c++20_iter.cc: New test.
+ 	* testsuite/25_algorithms/search_n/c++20_iter.cc: New test.
+ 	* testsuite/25_algorithms/unique_copy/c++20_iter.cc: New test.
+ 	* testsuite/26_numerics/inclusive_scan/c++20_iter.cc: New test.
+ 
  2025-12-12  Luc Grosheintz  <luc.grosheintz@gmail.com>
  
  	* include/std/mdspan (submdspan): Fix missing '::template'.
diff -Nrcpad gcc-16-20251214/libstdc++-v3/config/os/mingw32-w64/os_defines.h gcc-16-20251221/libstdc++-v3/config/os/mingw32-w64/os_defines.h
*** gcc-16-20251214/libstdc++-v3/config/os/mingw32-w64/os_defines.h	Sun Dec 14 22:32:17 2025
--- gcc-16-20251221/libstdc++-v3/config/os/mingw32-w64/os_defines.h	Sun Dec 21 22:32:15 2025
***************
*** 96,99 ****
--- 96,103 ----
  // See libstdc++/94268
  #define _GLIBCXX_BUFSIZ 4096
  
+ // Use functions to access thread-local variables from a different module.
+ // Windows does not support exporting thread-local data.
+ #define _GLIBCXX_NO_EXTERN_THREAD_LOCAL 1
+ 
  #endif
diff -Nrcpad gcc-16-20251214/libstdc++-v3/include/bits/atomic_base.h gcc-16-20251221/libstdc++-v3/include/bits/atomic_base.h
*** gcc-16-20251214/libstdc++-v3/include/bits/atomic_base.h	Sun Dec 14 22:32:17 2025
--- gcc-16-20251221/libstdc++-v3/include/bits/atomic_base.h	Sun Dec 21 22:32:15 2025
*************** _GLIBCXX_BEGIN_NAMESPACE_VERSION
*** 1561,1571 ****
        __atomic_ref_base& operator=(const __atomic_ref_base&) = delete;
  
        explicit
!       __atomic_ref_base(const _Tp& __t)
! 	: _M_ptr(const_cast<_Tp*>(std::addressof(__t)))
!       {
! 	__glibcxx_assert(((__UINTPTR_TYPE__)_M_ptr % required_alignment) == 0);
!       }
  
        __atomic_ref_base(const __atomic_ref_base&) noexcept = default;
  
--- 1561,1569 ----
        __atomic_ref_base& operator=(const __atomic_ref_base&) = delete;
  
        explicit
!       __atomic_ref_base(const _Tp* __ptr) noexcept
!       : _M_ptr(const_cast<_Tp*>(__ptr))
!       { }
  
        __atomic_ref_base(const __atomic_ref_base&) noexcept = default;
  
*************** _GLIBCXX_BEGIN_NAMESPACE_VERSION
*** 1607,1613 ****
        using value_type = typename __atomic_ref_base<const _Tp>::value_type;
  
        explicit
!       __atomic_ref_base(_Tp& __t) : __atomic_ref_base<const _Tp>(__t)
        { }
  
        value_type
--- 1605,1612 ----
        using value_type = typename __atomic_ref_base<const _Tp>::value_type;
  
        explicit
!       __atomic_ref_base(_Tp* __ptr) noexcept
!       : __atomic_ref_base<const _Tp>(__ptr)
        { }
  
        value_type
diff -Nrcpad gcc-16-20251214/libstdc++-v3/include/bits/chrono_io.h gcc-16-20251221/libstdc++-v3/include/bits/chrono_io.h
*** gcc-16-20251214/libstdc++-v3/include/bits/chrono_io.h	Sun Dec 14 22:32:17 2025
--- gcc-16-20251221/libstdc++-v3/include/bits/chrono_io.h	Sun Dec 21 22:32:15 2025
*************** namespace __format
*** 919,925 ****
      private:
        template<typename _OutIter>
  	_OutIter
! 	_M_write(_OutIter __out, const locale& __loc, __string_view __s) const
  	{
  #if defined _GLIBCXX_USE_NL_LANGINFO_L && __CHAR_BIT__ == 8
  	  __sso_string __buf;
--- 919,926 ----
      private:
        template<typename _OutIter>
  	_OutIter
! 	_M_write(_OutIter __out, [[maybe_unused]] const locale& __loc,
! 		 __string_view __s) const
  	{
  #if defined _GLIBCXX_USE_NL_LANGINFO_L && __CHAR_BIT__ == 8
  	  __sso_string __buf;
*************** namespace __detail
*** 4976,4989 ****
  		    }
  		  else // Read fractional seconds
  		    {
! 		      basic_stringstream<_CharT> __buf;
  		      auto __digit = _S_try_read_digit(__is, __err);
  		      if (__digit != -1)
  			{
! 			  __buf.put(_CharT('0') + __digit);
  			  __digit = _S_try_read_digit(__is, __err);
  			  if (__digit != -1)
! 			    __buf.put(_CharT('0') + __digit);
  			}
  
  		      auto __i = __is.peek();
--- 4977,4990 ----
  		    }
  		  else // Read fractional seconds
  		    {
! 		      stringstream __buf;
  		      auto __digit = _S_try_read_digit(__is, __err);
  		      if (__digit != -1)
  			{
! 			  __buf.put('0' + __digit);
  			  __digit = _S_try_read_digit(__is, __err);
  			  if (__digit != -1)
! 			    __buf.put('0' + __digit);
  			}
  
  		      auto __i = __is.peek();
*************** namespace __detail
*** 5008,5014 ****
  				{
  				  __digit = _S_try_read_digit(__is, __err);
  				  if (__digit != -1)
! 				    __buf.put(_CharT('0') + __digit);
  				  else
  				    break;
  				}
--- 5009,5015 ----
  				{
  				  __digit = _S_try_read_digit(__is, __err);
  				  if (__digit != -1)
! 				    __buf.put('0' + __digit);
  				  else
  				    break;
  				}
diff -Nrcpad gcc-16-20251214/libstdc++-v3/include/bits/cpp_type_traits.h gcc-16-20251221/libstdc++-v3/include/bits/cpp_type_traits.h
*** gcc-16-20251214/libstdc++-v3/include/bits/cpp_type_traits.h	Sun Dec 14 22:32:17 2025
--- gcc-16-20251221/libstdc++-v3/include/bits/cpp_type_traits.h	Sun Dec 21 22:32:15 2025
*************** __INT_N(__int128)
*** 518,523 ****
--- 518,530 ----
      struct __memcpyable_integer<volatile _Tp>
      { enum { __width = 0 }; };
  
+   // Assigning an integer to bool needs to convert all non-zero values to true
+   // so it is not a memcpyable integer.
+   // __memcpyable<bool*, bool*> is still true though.
+   template<>
+     struct __memcpyable_integer<bool>
+     { enum { __width = 0 }; };
+ 
    // Specializations for __intNN types with padding bits.
  #if defined __GLIBCXX_TYPE_INT_N_0 && __GLIBCXX_BITSIZE_INT_N_0 % __CHAR_BIT__
    __extension__
diff -Nrcpad gcc-16-20251214/libstdc++-v3/include/bits/deque.tcc gcc-16-20251221/libstdc++-v3/include/bits/deque.tcc
*** gcc-16-20251214/libstdc++-v3/include/bits/deque.tcc	Sun Dec 14 22:32:17 2025
--- gcc-16-20251221/libstdc++-v3/include/bits/deque.tcc	Sun Dec 21 22:32:15 2025
*************** _GLIBCXX_END_NAMESPACE_CONTAINER
*** 1225,1231 ****
  
    template<bool _IsMove, typename _II, typename _Tp>
      typename __gnu_cxx::__enable_if<
!       __is_random_access_iter<_II>::__value,
        _GLIBCXX_STD_C::_Deque_iterator<_Tp, _Tp&, _Tp*> >::__type
      __copy_move_a1(_II __first, _II __last,
  		   _GLIBCXX_STD_C::_Deque_iterator<_Tp, _Tp&, _Tp*> __result)
--- 1225,1231 ----
  
    template<bool _IsMove, typename _II, typename _Tp>
      typename __gnu_cxx::__enable_if<
!       __is_any_random_access_iter<_II>::__value,
        _GLIBCXX_STD_C::_Deque_iterator<_Tp, _Tp&, _Tp*> >::__type
      __copy_move_a1(_II __first, _II __last,
  		   _GLIBCXX_STD_C::_Deque_iterator<_Tp, _Tp&, _Tp*> __result)
*************** _GLIBCXX_END_NAMESPACE_CONTAINER
*** 1347,1353 ****
  
    template<bool _IsMove, typename _II, typename _Tp>
      typename __gnu_cxx::__enable_if<
!       __is_random_access_iter<_II>::__value,
        _GLIBCXX_STD_C::_Deque_iterator<_Tp, _Tp&, _Tp*> >::__type
      __copy_move_backward_a1(_II __first, _II __last,
  		_GLIBCXX_STD_C::_Deque_iterator<_Tp, _Tp&, _Tp*> __result)
--- 1347,1353 ----
  
    template<bool _IsMove, typename _II, typename _Tp>
      typename __gnu_cxx::__enable_if<
!       __is_any_random_access_iter<_II>::__value,
        _GLIBCXX_STD_C::_Deque_iterator<_Tp, _Tp&, _Tp*> >::__type
      __copy_move_backward_a1(_II __first, _II __last,
  		_GLIBCXX_STD_C::_Deque_iterator<_Tp, _Tp&, _Tp*> __result)
*************** _GLIBCXX_END_NAMESPACE_CONTAINER
*** 1406,1412 ****
  
    template<typename _Tp, typename _Ref, typename _Ptr, typename _II>
      typename __gnu_cxx::__enable_if<
!       __is_random_access_iter<_II>::__value, bool>::__type
      __equal_aux1(_GLIBCXX_STD_C::_Deque_iterator<_Tp, _Ref, _Ptr> __first1,
  		 _GLIBCXX_STD_C::_Deque_iterator<_Tp, _Ref, _Ptr> __last1,
  		 _II __first2)
--- 1406,1412 ----
  
    template<typename _Tp, typename _Ref, typename _Ptr, typename _II>
      typename __gnu_cxx::__enable_if<
!       __is_any_random_access_iter<_II>::__value, bool>::__type
      __equal_aux1(_GLIBCXX_STD_C::_Deque_iterator<_Tp, _Ref, _Ptr> __first1,
  		 _GLIBCXX_STD_C::_Deque_iterator<_Tp, _Ref, _Ptr> __last1,
  		 _II __first2)
*************** _GLIBCXX_END_NAMESPACE_CONTAINER
*** 1422,1428 ****
  
    template<typename _II, typename _Tp, typename _Ref, typename _Ptr>
      typename __gnu_cxx::__enable_if<
!       __is_random_access_iter<_II>::__value, bool>::__type
      __equal_aux1(_II __first1, _II __last1,
  		_GLIBCXX_STD_C::_Deque_iterator<_Tp, _Ref, _Ptr> __first2)
      {
--- 1422,1428 ----
  
    template<typename _II, typename _Tp, typename _Ref, typename _Ptr>
      typename __gnu_cxx::__enable_if<
!       __is_any_random_access_iter<_II>::__value, bool>::__type
      __equal_aux1(_II __first1, _II __last1,
  		_GLIBCXX_STD_C::_Deque_iterator<_Tp, _Ref, _Ptr> __first2)
      {
diff -Nrcpad gcc-16-20251214/libstdc++-v3/include/bits/random.h gcc-16-20251221/libstdc++-v3/include/bits/random.h
*** gcc-16-20251214/libstdc++-v3/include/bits/random.h	Sun Dec 14 22:32:17 2025
--- gcc-16-20251221/libstdc++-v3/include/bits/random.h	Sun Dec 21 22:32:15 2025
*************** _GLIBCXX_BEGIN_NAMESPACE_VERSION
*** 51,56 ****
--- 51,59 ----
  
    // std::uniform_random_bit_generator is defined in <bits/uniform_int_dist.h>
  
+ #ifndef _GLIBCXX_USE_OLD_GENERATE_CANONICAL
+ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
+ #endif
    /**
     * @brief A function template for converting the output of a (integral)
     * uniform random number generator to a floatng point result in the range
*************** _GLIBCXX_BEGIN_NAMESPACE_VERSION
*** 60,65 ****
--- 63,71 ----
  	   typename _UniformRandomNumberGenerator>
      _RealType
      generate_canonical(_UniformRandomNumberGenerator& __g);
+ #ifndef _GLIBCXX_USE_OLD_GENERATE_CANONICAL
+ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
+ #endif
  
    /// @cond undocumented
    // Implementation-space details.
*************** _GLIBCXX_BEGIN_NAMESPACE_VERSION
*** 68,73 ****
--- 74,505 ----
  #pragma GCC diagnostic push
  #pragma GCC diagnostic ignored "-Wc++17-extensions"
  
+ #ifndef __SIZEOF_INT128__
+     // Emulate 128-bit integer type, for the arithmetic ops used in <random>.
+     // The __detail::__mod function needs: (type(a) * x + c) % m.
+     // std::philox_engine needs multiplication and bitwise ops.
+     struct __rand_uint128
+     {
+       using type = __rand_uint128;
+ 
+       __rand_uint128() = default;
+ 
+       explicit constexpr
+       __rand_uint128(uint64_t __lo) noexcept : _M_lo(__lo) { }
+ 
+       __rand_uint128(const __rand_uint128&) = default;
+       __rand_uint128& operator=(const __rand_uint128&) = default;
+ 
+       _GLIBCXX14_CONSTEXPR type&
+       operator=(uint64_t __x) noexcept
+       { return *this = type(__x); }
+ 
+       _GLIBCXX14_CONSTEXPR type&
+       operator++() noexcept
+       { return *this = *this + 1; }
+ 
+       _GLIBCXX14_CONSTEXPR type&
+       operator--() noexcept
+       { return *this = *this - 1; }
+ 
+       _GLIBCXX14_CONSTEXPR type
+       operator++(int) noexcept
+       {
+ 	auto __tmp = *this;
+ 	++*this;
+ 	return __tmp;
+       }
+ 
+       _GLIBCXX14_CONSTEXPR type
+       operator--(int) noexcept
+       {
+ 	auto __tmp = *this;
+ 	--*this;
+ 	return __tmp;
+       }
+ 
+       _GLIBCXX14_CONSTEXPR type&
+       operator+=(const type& __r) noexcept
+       {
+ 	_M_hi += __r._M_hi + __builtin_add_overflow(_M_lo, __r._M_lo, &_M_lo);
+ 	return *this;
+       }
+ 
+       friend _GLIBCXX14_CONSTEXPR type
+       operator+(type __l, const type& __r) noexcept
+       { return __l += __r; }
+ 
+       // Addition with 64-bit operand
+       friend _GLIBCXX14_CONSTEXPR type
+       operator+(type __l, uint64_t __r) noexcept
+       { return __l += type(__r); }
+ 
+       // Subtraction with 64-bit operand
+       _GLIBCXX14_CONSTEXPR type&
+       operator-=(uint64_t __r) noexcept
+       {
+ 	_M_hi -= __builtin_sub_overflow(_M_lo, __r, &_M_lo);
+ 	return *this;
+       }
+ 
+       friend _GLIBCXX14_CONSTEXPR type
+       operator-(type __l, uint64_t __r) noexcept
+       { return __l -= __r; }
+ 
+       _GLIBCXX14_CONSTEXPR type&
+       operator*=(const type& __x) noexcept
+       {
+ 	uint64_t __a[12] = {
+ 	  uint32_t(_M_lo), _M_lo >> 32,
+ 	  uint32_t(_M_hi), _M_hi >> 32,
+ 	  uint32_t(__x._M_lo), __x._M_lo >> 32,
+ 	  uint32_t(__x._M_hi), __x._M_hi >> 32,
+ 	  0, 0,
+ 	  0, 0 };
+ 	for (int __i = 0; __i < 4; ++__i)
+ 	  {
+ 	    uint64_t __c = 0;
+ 	    for (int __j = __i; __j < 4; ++__j)
+ 	      {
+ 		__c += __a[__i] * __a[4 + __j - __i] + __a[8 + __j];
+ 		__a[8 + __j] = uint32_t(__c);
+ 		__c >>= 32;
+ 	      }
+ 	  }
+ 	_M_lo = __a[8] + (__a[9] << 32);
+ 	_M_hi = __a[10] + (__a[11] << 32);
+ 	return *this;
+       }
+ 
+       // Multiplication with a 64-bit operand is simpler.
+       // pre: _M_hi == 0
+       _GLIBCXX14_CONSTEXPR type&
+       operator*=(uint64_t __x) noexcept
+       {
+ 	// Split 64-bit values _M_lo and __x into high and low 32-bit
+ 	// limbs and multiply those individually.
+ 	// l * x = (l0 + l1) * (x0 + x1) = l0x0 + l0x1 + l1x0 + l1x1
+ 
+ 	constexpr uint64_t __mask = 0xffffffff;
+ 	uint64_t __ll[2] = { _M_lo >> 32, _M_lo & __mask };
+ 	uint64_t __xx[2] = { __x >> 32, __x & __mask };
+ 	uint64_t __l0x0 = __ll[0] * __xx[0];
+ 	uint64_t __l0x1 = __ll[0] * __xx[1];
+ 	uint64_t __l1x0 = __ll[1] * __xx[0];
+ 	uint64_t __l1x1 = __ll[1] * __xx[1];
+ 	// These bits are the low half of _M_hi and the high half of _M_lo.
+ 	uint64_t __mid
+ 	  = (__l0x1 & __mask) + (__l1x0 & __mask) + (__l1x1 >> 32);
+ 	_M_hi = __l0x0 + (__l0x1 >> 32) + (__l1x0 >> 32) + (__mid >> 32);
+ 	_M_lo = (__mid << 32) + (__l1x1 & __mask);
+ 	return *this;
+       }
+ 
+       _GLIBCXX14_CONSTEXPR type&
+       operator/=(const type& __r) noexcept
+       {
+ 	if (!_M_hi)
+ 	  {
+ 	    if (!__r._M_hi)
+ 	      _M_lo = _M_lo / __r._M_lo;
+ 	    else
+ 	      _M_lo = 0;
+ 	  }
+ 	else
+ 	  {
+ 	    uint64_t __a[13] = {
+ 	      uint32_t(_M_lo), _M_lo >> 32,
+ 	      uint32_t(_M_hi), _M_hi >> 32,
+ 	      0,
+ 	      uint32_t(__r._M_lo), __r._M_lo >> 32,
+ 	      uint32_t(__r._M_hi), __r._M_hi >> 32,
+ 	      0, 0,
+ 	      0, 0
+ 	    };
+ 	    uint64_t __c = 0, __w = 0;
+ 	    if (!__r._M_hi && __r._M_lo <= ~uint32_t(0))
+ 	      for (int __i = 3; ; --__i)
+ 		{
+ 		  __w = __a[__i] + (__c << 32);
+ 		  __a[9 + __i] = __w / __r._M_lo;
+ 		  if (__i == 0)
+ 		    break;
+ 		  __c = __w % __r._M_lo;
+ 		}
+ 	    else
+ 	      {
+ 		// See Donald E. Knuth's "Seminumerical Algorithms".
+ 		int __n = 0, __d = 0;
+ 		uint64_t __q = 0, __s = 0;
+ 		for (__d = 3; __a[5 + __d] == 0; --__d)
+ 		  ;
+ 		__s = (uint64_t(1) << 32) / (__a[5 + __d] + 1);
+ 		if (__s > 1)
+ 		  {
+ 		    for (int __i = 0; __i <= 3; ++__i)
+ 		      {
+ 			__w = __a[__i] * __s + __c;
+ 			__a[__i] = uint32_t(__w);
+ 			__c = __w >> 32;
+ 		      }
+ 		    __a[4] = __c;
+ 		    __c = 0;
+ 		    for (int __i = 0; __i <= 3; ++__i)
+ 		      {
+ 			__w = __a[5 + __i] * __s + __c;
+ 			__a[5 + __i] = uint32_t(__w);
+ 			__c = __w >> 32;
+ 			if (__a[5 + __i])
+ 			  __d = __i;
+ 		      }
+ 		  }
+ 		__n = 4;
+ 		for (int __i = __n - __d - 1; __i >= 0; --__i)
+ 		  {
+ 		    __n = __i + __d + 1;
+ 		    __w = (__a[__n] << 32) + __a[__n - 1];
+ 		    if (__a[__n] != __a[5 + __d])
+ 		      __q = __w / __a[5 + __d];
+ 		    else
+ 		      __q = ~uint32_t(0);
+ 		    uint64_t __t = __w - __q * __a[5 + __d];
+ 		    if (__t <= ~uint32_t(0)
+ 			  && __a[4 + __d] * __q > (__t << 32) + __a[__n - 2])
+ 		      --__q;
+ 		    __c = 0;
+ 		    for (int __j = 0; __j <= __d; ++__j)
+ 		      {
+ 			__w = __q * __a[5 + __j] + __c;
+ 			__c = __w >> 32;
+ 			__w = __a[__i + __j] - uint32_t(__w);
+ 			__a[__i + __j] = uint32_t(__w);
+ 			__c += (__w >> 32) != 0;
+ 		      }
+ 		    if (int64_t(__a[__n]) < int64_t(__c))
+ 		      {
+ 			--__q;
+ 			__c = 0;
+ 			for (int __j = 0; __j <= __d; ++__j)
+ 			  {
+ 			    __w = __a[__i + __j] + __a[5 + __j] + __c;
+ 			    __c = __w >> 32;
+ 			    __a[__i + __j] = uint32_t(__w);
+ 			  }
+ 			__a[__n] += __c;
+ 		      }
+ 		    __a[9 + __i] = __q;
+ 		  }
+ 	      }
+ 	    _M_lo = __a[9] + (__a[10] << 32);
+ 	    _M_hi = __a[11] + (__a[12] << 32);
+ 	  }
+ 	return *this;
+       }
+ 
+       // Currently only supported for 64-bit operands.
+       _GLIBCXX14_CONSTEXPR type&
+       operator%=(uint64_t __m) noexcept
+       {
+ 	if (_M_hi == 0)
+ 	  {
+ 	    _M_lo %= __m;
+ 	    return *this;
+ 	  }
+ 
+ 	int __shift = __builtin_clzll(__m) + 64 - __builtin_clzll(_M_hi);
+ 	type __x(0);
+ 	if (__shift >= 64)
+ 	  {
+ 	    __x._M_hi = __m << (__shift - 64);
+ 	    __x._M_lo = 0;
+ 	  }
+ 	else
+ 	  {
+ 	    __x._M_hi = __m >> (64 - __shift);
+ 	    __x._M_lo = __m << __shift;
+ 	  }
+ 
+ 	while (_M_hi != 0 || _M_lo >= __m)
+ 	  {
+ 	    if (__x <= *this)
+ 	      {
+ 		_M_hi -= __x._M_hi;
+ 		_M_hi -= __builtin_sub_overflow(_M_lo, __x._M_lo,
+ 						    &_M_lo);
+ 	      }
+ 	    __x._M_lo = (__x._M_lo >> 1) | (__x._M_hi << 63);
+ 	    __x._M_hi >>= 1;
+ 	  }
+ 	return *this;
+       }
+ 
+       friend _GLIBCXX14_CONSTEXPR type
+       operator*(type __l, const type& __r) noexcept
+       { return __l *= __r; }
+ 
+       friend _GLIBCXX14_CONSTEXPR type
+       operator*(type __l, uint64_t __r) noexcept
+       { return __l *= __r; }
+ 
+       friend _GLIBCXX14_CONSTEXPR type
+       operator/(type __l, const type& __r) noexcept
+       { return __l /= __r; }
+ 
+       friend _GLIBCXX14_CONSTEXPR type
+       operator%(type __l, uint64_t __m) noexcept
+       { return __l %= __m; }
+ 
+       friend _GLIBCXX14_CONSTEXPR type
+       operator~(type __v) noexcept
+       {
+ 	__v._M_hi = ~__v._M_hi;
+ 	__v._M_lo = ~__v._M_lo;
+ 	return __v;
+       }
+ 
+       _GLIBCXX14_CONSTEXPR type&
+       operator>>=(unsigned __c) noexcept
+       {
+ 	if (__c >= 64)
+ 	  {
+ 	    _M_lo = _M_hi >>= (__c - 64);
+ 	    _M_hi = 0;
+ 	  }
+ 	else if (__c != 0)
+ 	  {
+ 	    _M_lo = (_M_lo >> __c) | (_M_hi << (64 - __c));
+ 	    _M_hi >>= __c;
+ 	  }
+ 	return *this;
+       }
+ 
+       _GLIBCXX14_CONSTEXPR type&
+       operator<<=(unsigned __c) noexcept
+       {
+ 	if (__c >= 64)
+ 	  {
+ 	    _M_hi = _M_lo << (__c - 64);
+ 	    _M_lo = 0;
+ 	  }
+ 	else if (__c != 0)
+ 	  {
+ 	    _M_hi = (_M_hi << __c) | (_M_lo >> (64 - __c));
+ 	    _M_lo <<= __c;
+ 	  }
+ 	return *this;
+       }
+ 
+       friend _GLIBCXX14_CONSTEXPR type
+       operator>>(type __x, unsigned __c) noexcept
+       { return __x >>= __c; }
+ 
+       friend _GLIBCXX14_CONSTEXPR type
+       operator<<(type __x, unsigned __c) noexcept
+       { return __x <<= __c; }
+ 
+       _GLIBCXX14_CONSTEXPR type&
+       operator|=(const type& __r) noexcept
+       {
+ 	_M_hi |= __r._M_hi;
+ 	_M_lo |= __r._M_lo;
+ 	return *this;
+       }
+ 
+       _GLIBCXX14_CONSTEXPR type&
+       operator^=(const type& __r) noexcept
+       {
+ 	_M_hi ^= __r._M_hi;
+ 	_M_lo ^= __r._M_lo;
+ 	return *this;
+       }
+ 
+       _GLIBCXX14_CONSTEXPR type&
+       operator&=(const type& __r) noexcept
+       {
+ 	_M_hi &= __r._M_hi;
+ 	_M_lo &= __r._M_lo;
+ 	return *this;
+       }
+ 
+       friend _GLIBCXX14_CONSTEXPR type
+       operator|(type __l, const type& __r) noexcept
+       { return __l |= __r; }
+ 
+       friend _GLIBCXX14_CONSTEXPR type
+       operator^(type __l, const type& __r) noexcept
+       { return __l ^= __r; }
+ 
+       friend _GLIBCXX14_CONSTEXPR type
+       operator&(type __l, const type& __r) noexcept
+       { return __l &= __r; }
+ 
+       friend _GLIBCXX14_CONSTEXPR type
+       operator&(type __l, uint64_t __r) noexcept
+       {
+ 	__l._M_hi = 0;
+ 	__l._M_lo &= __r;
+ 	return __l;
+       }
+ 
+ #if __cpp_impl_three_way_comparison >= 201907L
+       friend std::strong_ordering
+       operator<=>(const type&, const type&) = default;
+ 
+       friend bool
+       operator==(const type&, const type&) = default;
+ #else
+       friend constexpr bool
+       operator==(const type& __l, const type& __r) noexcept
+       { return __l._M_hi == __r._M_hi && __l._M_lo == __r._M_lo; }
+ 
+       friend _GLIBCXX14_CONSTEXPR bool
+       operator<(const type& __l, const type& __r) noexcept
+       {
+ 	if (__l._M_hi < __r._M_hi)
+ 	  return true;
+ 	else if (__l._M_hi == __r._M_hi)
+ 	  return __l._M_lo < __r._M_lo;
+ 	else
+ 	  return false;
+       }
+ 
+       friend _GLIBCXX14_CONSTEXPR bool
+       operator>(const type& __l, const type& __r) noexcept
+       { return __r < __l; }
+ 
+       friend _GLIBCXX14_CONSTEXPR bool
+       operator<=(const type& __l, const type& __r) noexcept
+       { return !(__r < __l); }
+ 
+       friend _GLIBCXX14_CONSTEXPR bool
+       operator>=(const type& __l, const type& __r) noexcept
+       { return !(__l < __r); }
+ #endif
+ 
+       friend _GLIBCXX14_CONSTEXPR bool
+       operator==(const type& __l, uint64_t __r) noexcept
+       { return __l == type(__r); }
+ 
+       template<typename _RealT>
+ 	constexpr explicit operator _RealT() const noexcept
+ 	{
+ 	  static_assert(std::is_floating_point<_RealT>::value,
+ 			"template argument must be a floating point type");
+ 	  return _M_hi == 0
+ 		   ? _RealT(_M_lo)
+ 		   : _RealT(_M_hi) * _RealT(18446744073709551616.0)
+ 		     + _RealT(_M_lo);
+ 	}
+ 
+       // pre: _M_hi == 0
+       constexpr explicit operator uint64_t() const noexcept
+       { return _M_lo; }
+ 
+       uint64_t _M_hi = 0;
+       uint64_t _M_lo = 0;
+     };
+ #endif // ! __SIZEOF_INT128__
+ 
      template<typename _UIntType, size_t __w,
  	     bool = __w < static_cast<size_t>
  			  (std::numeric_limits<_UIntType>::digits)>
*************** _GLIBCXX_BEGIN_NAMESPACE_VERSION
*** 111,213 ****
      && defined __UINT64_TYPE__
      template<int __s>
        struct _Select_uint_least_t<__s, 1>
!       {
! 	// This is NOT a general-purpose 128-bit integer type.
! 	// It only supports (type(a) * x + c) % m as needed by __mod.
! 	struct type
! 	{
! 	  explicit
! 	  type(uint64_t __a) noexcept : _M_lo(__a), _M_hi(0) { }
! 
! 	  // pre: __l._M_hi == 0
! 	  friend type
! 	  operator*(type __l, uint64_t __x) noexcept
! 	  {
! 	    // Split 64-bit values __l._M_lo and __x into high and low 32-bit
! 	    // limbs and multiply those individually.
! 	    // l * x = (l0 + l1) * (x0 + x1) = l0x0 + l0x1 + l1x0 + l1x1
! 
! 	    constexpr uint64_t __mask = 0xffffffff;
! 	    uint64_t __ll[2] = { __l._M_lo >> 32, __l._M_lo & __mask };
! 	    uint64_t __xx[2] = { __x >> 32, __x & __mask };
! 	    uint64_t __l0x0 = __ll[0] * __xx[0];
! 	    uint64_t __l0x1 = __ll[0] * __xx[1];
! 	    uint64_t __l1x0 = __ll[1] * __xx[0];
! 	    uint64_t __l1x1 = __ll[1] * __xx[1];
! 	    // These bits are the low half of __l._M_hi
! 	    // and the high half of __l._M_lo.
! 	    uint64_t __mid
! 	      = (__l0x1 & __mask) + (__l1x0 & __mask) + (__l1x1 >> 32);
! 	    __l._M_hi = __l0x0 + (__l0x1 >> 32) + (__l1x0 >> 32) + (__mid >> 32);
! 	    __l._M_lo = (__mid << 32) + (__l1x1 & __mask);
! 	    return __l;
! 	  }
! 
! 	  friend type
! 	  operator+(type __l, uint64_t __c) noexcept
! 	  {
! 	    __l._M_hi += __builtin_add_overflow(__l._M_lo, __c, &__l._M_lo);
! 	    return __l;
! 	  }
! 
! 	  friend type
! 	  operator%(type __l, uint64_t __m) noexcept
! 	  {
! 	    if (__builtin_expect(__l._M_hi == 0, 0))
! 	      {
! 		__l._M_lo %= __m;
! 		return __l;
! 	      }
! 
! 	    int __shift = __builtin_clzll(__m) + 64
! 			    - __builtin_clzll(__l._M_hi);
! 	    type __x(0);
! 	    if (__shift >= 64)
! 	      {
! 		__x._M_hi = __m << (__shift - 64);
! 		__x._M_lo = 0;
! 	      }
! 	    else
! 	      {
! 		__x._M_hi = __m >> (64 - __shift);
! 		__x._M_lo = __m << __shift;
! 	      }
! 
! 	    while (__l._M_hi != 0 || __l._M_lo >= __m)
! 	      {
! 		if (__x <= __l)
! 		  {
! 		    __l._M_hi -= __x._M_hi;
! 		    __l._M_hi -= __builtin_sub_overflow(__l._M_lo, __x._M_lo,
! 							&__l._M_lo);
! 		  }
! 		__x._M_lo = (__x._M_lo >> 1) | (__x._M_hi << 63);
! 		__x._M_hi >>= 1;
! 	      }
! 	    return __l;
! 	  }
! 
! 	  // pre: __l._M_hi == 0
! 	  explicit operator uint64_t() const noexcept
! 	  { return _M_lo; }
! 
! 	  friend bool operator<(const type& __l, const type& __r) noexcept
! 	  {
! 	    if (__l._M_hi < __r._M_hi)
! 	      return true;
! 	    else if (__l._M_hi == __r._M_hi)
! 	      return __l._M_lo < __r._M_lo;
! 	    else
! 	      return false;
! 	  }
! 
! 	  friend bool operator<=(const type& __l, const type& __r) noexcept
! 	  { return !(__r < __l); }
! 
! 	  uint64_t _M_lo;
! 	  uint64_t _M_hi;
! 	};
!       };
  #endif
  
      // Assume a != 0, a < m, c < m, x < m.
--- 543,549 ----
      && defined __UINT64_TYPE__
      template<int __s>
        struct _Select_uint_least_t<__s, 1>
!       { using type = __rand_uint128; };
  #endif
  
      // Assume a != 0, a < m, c < m, x < m.
diff -Nrcpad gcc-16-20251214/libstdc++-v3/include/bits/random.tcc gcc-16-20251221/libstdc++-v3/include/bits/random.tcc
*** gcc-16-20251214/libstdc++-v3/include/bits/random.tcc	Sun Dec 14 22:32:17 2025
--- gcc-16-20251221/libstdc++-v3/include/bits/random.tcc	Sun Dec 21 22:32:15 2025
*************** _GLIBCXX_BEGIN_NAMESPACE_VERSION
*** 915,923 ****
      philox_engine<_UIntType, __w, __n, __r, __consts...>::
      _S_mulhi(_UIntType __a, _UIntType __b)
      {
!       const __uint128_t __num =
! 	  static_cast<__uint128_t>(__a) * static_cast<__uint128_t>(__b);
!       return static_cast<_UIntType>((__num >> __w) & max());
      }
  
    template<typename _UIntType, size_t __w, size_t __n, size_t __r,
--- 915,923 ----
      philox_engine<_UIntType, __w, __n, __r, __consts...>::
      _S_mulhi(_UIntType __a, _UIntType __b)
      {
!       using __type = typename __detail::_Select_uint_least_t<__w * 2>::type;
!       const __type __num = static_cast<__type>(__a) * __b;
!       return static_cast<_UIntType>(__num >> __w) & max();
      }
  
    template<typename _UIntType, size_t __w, size_t __n, size_t __r,
*************** _GLIBCXX_BEGIN_NAMESPACE_VERSION
*** 938,970 ****
        if (_M_i != __n)
  	return;
  
        _M_philox();
        if constexpr (__n == 4)
  	{
! 	  __uint128_t __uh =
! 	    (static_cast<__uint128_t>(_M_x[1]) << __w)
! 		  | (static_cast<__uint128_t>(_M_x[0]) + 1);
! 	  __uint128_t __lh =
! 	    ((static_cast<__uint128_t>(_M_x[3]) << __w)
! 		  | (_M_x[2]));
! 	  __uint128_t __bigMask =
! 	    (static_cast<__uint128_t>(1) << ((2 * __w) - 1))
! 		  | ((static_cast<__uint128_t>(1) << ((2 * __w) - 1)) - 1);
  	  if ((__uh & __bigMask) == 0)
  	    {
  	      ++__lh;
  	      __uh = 0;
  	    }
! 	  _M_x[0] = __uh & max();
! 	  _M_x[1] = (__uh >> (__w)) & max();
! 	  _M_x[2] = __lh & max();
! 	  _M_x[3] = (__lh >> (__w)) & max();
  	}
        else
  	{
! 	  __uint128_t __num =
! 		  (static_cast<__uint128_t>(_M_x[1]) << __w)
! 		  | (static_cast<__uint128_t>(_M_x[0]) + 1);
  	  _M_x[0] = __num & max();
  	  _M_x[1] = (__num >> __w) & max();
  	}
--- 938,971 ----
        if (_M_i != __n)
  	return;
  
+       using __type = typename __detail::_Select_uint_least_t<__w * 2>::type;
+ 
        _M_philox();
        if constexpr (__n == 4)
  	{
! 	  __type __uh
! 	    = (static_cast<__type>(_M_x[1]) << __w)
! 		| (static_cast<__type>(_M_x[0]) + 1);
! 	  __type __lh
! 	    = (static_cast<__type>(_M_x[3]) << __w)
! 		| static_cast<__type>(_M_x[2]);
! 	  __type __bigMask
! 	    = ~__type(0) >> ((sizeof(__type) * __CHAR_BIT__) - (__w * 2));
  	  if ((__uh & __bigMask) == 0)
  	    {
  	      ++__lh;
  	      __uh = 0;
  	    }
! 	  _M_x[0] = static_cast<_UIntType>(__uh & max());
! 	  _M_x[1] = static_cast<_UIntType>((__uh >> (__w)) & max());
! 	  _M_x[2] = static_cast<_UIntType>(__lh & max());
! 	  _M_x[3] = static_cast<_UIntType>((__lh >> (__w)) & max());
  	}
        else
  	{
! 	  __type __num =
! 		  (static_cast<__type>(_M_x[1]) << __w)
! 		  | (static_cast<__type>(_M_x[0]) + 1);
  	  _M_x[0] = __num & max();
  	  _M_x[1] = (__num >> __w) & max();
  	}
*************** namespace __detail
*** 3472,3493 ****
  	}
      }
  
    template<typename _RealType, size_t __bits,
! 	   typename _UniformRandomNumberGenerator>
      _RealType
      generate_canonical(_UniformRandomNumberGenerator& __urng)
      {
        static_assert(std::is_floating_point<_RealType>::value,
! 		    "template argument must be a floating point type");
  
        const size_t __b
! 	= std::min(static_cast<size_t>(std::numeric_limits<_RealType>::digits),
!                    __bits);
        const long double __r = static_cast<long double>(__urng.max())
! 			    - static_cast<long double>(__urng.min()) + 1.0L;
        const size_t __log2r = std::log(__r) / std::log(2.0L);
        const size_t __m = std::max<size_t>(1UL,
! 					  (__b + __log2r - 1UL) / __log2r);
        _RealType __ret;
        _RealType __sum = _RealType(0);
        _RealType __tmp = _RealType(1);
--- 3473,3746 ----
  	}
      }
  
+ // [rand.util.canonical]
+ // generate_canonical(RNG&)
+ 
+ #ifndef _GLIBCXX_USE_OLD_GENERATE_CANONICAL
+ 
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Wc++14-extensions" // for variable templates
+ #pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr
+ 
+   // __generate_canonical_pow2 is used when Urbg::max()-Urbg::min() is
+   // a power of two less 1. It works by calling urng() as many times as
+   // needed to fill the target mantissa, accumulating entropy into an
+   // integer value, converting that to the float type, and then dividing
+   // by the range of the integer value (a constexpr power of 2,
+   // so only adjusts the exponent) to produce a result in [0..1].
+   // In case of an exact 1.0 result, we re-try.
+   //
+   // It needs to work even when the integer type used is only as big
+   // as the float mantissa, such as uint64_t for long double. So,
+   // commented-out assignments represent computations the Standard
+   // prescribes but cannot be performed, or are not used. Names are
+   // chosen to match the description in the Standard.
+   //
+   // When the result is close to zero, the strict Standard-prescribed
+   // calculation may leave more low-order zeros in the mantissa than
+   // is usually necessary. When spare entropy has been extracted, as
+   // is usual for float and double, some or all of the spare entropy
+   // can commonly be pulled into the result for better randomness.
+   // Defining _GLIBCXX_GENERATE_CANONICAL_STRICT discards it instead.
+   //
+   // When k calls to urng() yield more bits of entropy, log2_Rk_max,
+   // than fit into UInt, we discard some of it by overflowing, which
+   // is OK.  On converting the integer representation of the sample
+   // to the float value, we must divide out the (possibly-truncated)
+   // size log2_Rk.
+   //
+   // This implementation works with std::bfloat16, which can exactly
+   // represent 2^32, but not with std::float16_t, limited to 2^15.
+ 
+   template<typename _RealT, size_t __d, typename _Urbg>
+     _RealT
+     __generate_canonical_pow2(_Urbg& __urng)
+     {
+       using _UInt = typename __detail::_Select_uint_least_t<__d>::type;
+ 
+       // Parameter __d is the actual target number of bits.
+       // Commented-out assignments below are of values specified in
+       //  the Standard, but not used here for reasons noted.
+       // r = 2;  // Redundant, we only support radix 2.
+       using _Rng = decltype(_Urbg::max());
+       const _Rng __rng_range_less_1 = _Urbg::max() - _Urbg::min();
+       // R = _UInt(__rng_range_less_1) + 1;  // May wrap to 0.
+       const auto __log2_R = __builtin_popcountg(__rng_range_less_1);
+       const auto __log2_uint_max = sizeof(_UInt) * __CHAR_BIT__;
+       // rd = _UInt(1) << __d;  // Could overflow, UB.
+       const unsigned __k = (__d + __log2_R - 1) / __log2_R;
+       const unsigned __log2_Rk_max = __k * __log2_R;
+       const unsigned __log2_Rk =  // Bits of entropy actually obtained:
+ 	__log2_uint_max < __log2_Rk_max ? __log2_uint_max : __log2_Rk_max;
+       // Rk = _UInt(1) << __log2_Rk;  // Likely overflows, UB.
+       _GLIBCXX14_CONSTEXPR const _RealT __Rk
+ 	 = _RealT(_UInt(1) << (__log2_Rk - 1)) * _RealT(2.0);
+ #if defined(_GLIBCXX_GENERATE_CANONICAL_STRICT)
+       const unsigned __log2_x = __log2_Rk - __d; // # of spare entropy bits.
+ #else
+       const unsigned __log2_x = 0;
+ #endif
+       _GLIBCXX14_CONSTEXPR const _UInt __x = _UInt(1) << __log2_x;
+       _GLIBCXX14_CONSTEXPR const _RealT __rd = __Rk / _RealT(__x);
+       // xrd = __x << __d;  // Could overflow.
+ 
+       while (true)
+ 	{
+ 	  _UInt __sum = _UInt(__urng() - _Urbg::min());
+ 	  for (unsigned __i = __k - 1, __shift = 0; __i > 0; --__i)
+ 	    {
+ 	      __shift += __log2_R;
+ 	      __sum |= _UInt(__urng() - _Urbg::min()) << __shift;
+ 	    }
+ 	  const _RealT __ret = _RealT(__sum >> __log2_x) / _RealT(__rd);
+ 	  if (__ret < _RealT(1.0))
+ 	    return __ret;
+ 	}
+     }
+ 
+ 
+   template<typename _UInt>
+     struct __gen_canon_log_res
+     {
+        unsigned __floor_log;
+        _UInt __floor_pow;
+ 
+        constexpr __gen_canon_log_res
+        update(_UInt __base) const
+        { return {__floor_log + 1, __floor_pow * __base}; }
+     };
+ 
+ 
+   template <typename _UInt1, typename _UInt2,
+             typename _UComm = __conditional_t<(sizeof(_UInt2) > sizeof(_UInt1)),
+ 					      _UInt2, _UInt1>>
+     constexpr __gen_canon_log_res<_UInt1>
+     __gen_canon_log(_UInt1 __val, _UInt2 __base)
+     {
+ #if __cplusplus >= 201402L
+       __gen_canon_log_res<_UInt1> __res{0, _UInt1(1)};
+       if (_UComm(__base) > _UComm(__val))
+ 	return __res;
+ 
+       const _UInt1 __base1(__base);
+       do
+         { 
+ 	  __val /= __base1;
+           __res = __res.update(__base1);
+         }
+       while (__val >= __base1);
+       return __res;
+ #else
+       return (_UComm(__val) >= _UComm(__base))
+ 	     ? __gen_canon_log(__val / _UInt1(__base), _UInt1(__base))
+ 	         .update(_UInt1(__base))
+ 	     : __gen_canon_log_res<_UInt1>{0, _UInt1(1)};
+ #endif
+     }
+ 
+   // This version must be used when the range of possible RNG results,
+   // Urbg::max()-Urbg::min(), is not a power of two less one. The UInt
+   // type passed must be big enough to represent Rk, R^k, a power of R
+   // (the range of values produced by the rng) up to twice the length
+   // of the mantissa.
+ 
+   template<typename _RealT, size_t __d, typename _Urbg>
+     _RealT
+     __generate_canonical_any(_Urbg& __urng)
+     {
+       // Names below are chosen to match the description in the Standard.
+       // Parameter d is the actual target number of bits.
+ #if (__cplusplus >= 201402L) || defined(__SIZEOF_INT128__)
+ #  define _GLIBCXX_GEN_CANON_CONST constexpr
+ #else
+ #  define _GLIBCXX_GEN_CANON_CONST const
+ #endif
+ 
+       using _UIntR = typename make_unsigned<decltype(_Urbg::max())>::type;
+       // Cannot overflow, as _Urbg::max() - _Urbg::min() is not power of
+       // two minus one
+       constexpr _UIntR __R = _UIntR(_Urbg::max() - _Urbg::min()) + 1;
+       constexpr unsigned __log2R
+ 	= sizeof(_UIntR) * __CHAR_BIT__ - __builtin_clzg(__R) - 1;
+       // We overstimate number of required bits, by computing
+       // r such that l * log2(R) >= d, so:
+       // R^l >= (2 ^ log2(R)) ^ l == 2 ^ (log2(r) * l) >= 2^d
+       // And then requiring l * bit_width(R) bits.
+       constexpr unsigned __l = (__d + __log2R - 1) / __log2R;
+       constexpr unsigned __bits = (__log2R + 1) * __l;
+       using _UInt = typename __detail::_Select_uint_least_t<__bits>::type;
+ 
+       _GLIBCXX_GEN_CANON_CONST _UInt __rd = _UInt(1) << __d;
+       _GLIBCXX_GEN_CANON_CONST auto __logRrd = __gen_canon_log(__rd, __R);
+       _GLIBCXX_GEN_CANON_CONST unsigned __k
+ 	 = __logRrd.__floor_log + (__rd > __logRrd.__floor_pow);
+ 
+       _GLIBCXX_GEN_CANON_CONST _UInt __Rk
+ 	 = (__k > __logRrd.__floor_log)
+ 	   ? _UInt(__logRrd.__floor_pow) * _UInt(__R)
+ 	   : _UInt(__logRrd.__floor_pow);
+       _GLIBCXX_GEN_CANON_CONST _UInt __x =  __Rk / __rd;
+ 
+       while (true)
+ 	{
+ 	  _UInt __Ri{1};
+ 	  _UInt __sum(__urng() - _Urbg::min());
+ 	  for (int __i = __k - 1; __i > 0; --__i)
+ 	    {
+ 	      __Ri *= _UInt(__R);
+ 	      __sum += _UInt(__urng() - _Urbg::min()) * __Ri;
+ 	    }
+ 	  const _RealT __ret = _RealT(__sum / __x) / _RealT(__rd);
+ 	  if (__ret < _RealT(1.0))
+ 	    return __ret;
+ 	}
+ #undef _GLIBCXX_GEN_CANON_CONST 
+     }
+ 
+ #if !defined(_GLIBCXX_GENERATE_CANONICAL_STRICT)
+   template <typename _Tp>
+     const bool __is_rand_dist_float_v = is_floating_point<_Tp>::value;
+ #else
+   template <typename _Tp> const bool __is_rand_dist_float_v = false;
+   template <> const bool __is_rand_dist_float_v<float> = true;
+   template <> const bool __is_rand_dist_float_v<double> = true;
+   template <> const bool __is_rand_dist_float_v<long double> = true;
+ #endif
+ 
+   // Note, this works even when (__range + 1) overflows:
+   template <typename _Rng>
+     constexpr bool __is_power_of_2_less_1(_Rng __range)
+       { return ((__range + 1) & __range) == 0; };
+ 
+ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
+   /** Produce a random floating-point value in the range [0..1)
+    *
+    * The result of `std::generate_canonical<RealT,digits>(urng)` is a
+    * random floating-point value of type `RealT` in the range [0..1),
+    * using entropy provided by the uniform random bit generator `urng`.
+    * A value for `digits` may be passed to limit the precision of the
+    * result to so many bits, but normally `-1u` is passed to get the
+    * native precision of `RealT`. As many `urng()` calls are made as
+    * needed to obtain the required entropy. On rare occasions, more
+    * `urng()` calls are used. It is fastest when the value of
+    * `Urbg::max()` is a power of two less one, such as from a
+    * `std::philox4x32` (for `float`) or `philox4x64` (for `double`).
+    *
+    *  @since C++11
+    */
+   template<typename _RealT, size_t __digits,
+ 	   typename _Urbg>
+     _RealT
+     generate_canonical(_Urbg& __urng)
+     {
+ #ifdef __glibcxx_concepts
+       static_assert(uniform_random_bit_generator<_Urbg>);
+ #endif      
+       static_assert(__is_rand_dist_float_v<_RealT>,
+ 	"template argument must be a floating point type");
+       static_assert(__digits != 0 && _Urbg::max() > _Urbg::min(),
+ 	"random samples with 0 bits are not meaningful");
+       static_assert(std::numeric_limits<_RealT>::radix == 2,
+ 	"only base-2 float types are supported");
+ #if defined(__STDCPP_FLOAT16_T__)
+       static_assert(! is_same_v<_RealT, _Float16>,
+ 	"float16_t type is not supported, consider using bfloat16_t");
+ #endif
+ 
+       const unsigned __d_max = std::numeric_limits<_RealT>::digits;
+       const unsigned __d = __digits > __d_max ? __d_max : __digits;
+ 
+       // If the RNG range is a power of 2 less 1, the float type mantissa
+       // is enough bits. If not, we need more.
+       if constexpr (__is_power_of_2_less_1(_Urbg::max() - _Urbg::min()))
+ 	return __generate_canonical_pow2<_RealT, __d>(__urng);
+       else // Need up to 2x bits.
+ 	return __generate_canonical_any<_RealT, __d>(__urng);
+     }
+ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
+ 
+ #pragma GCC diagnostic pop
+ 
+ #else // _GLIBCXX_USE_OLD_GENERATE_CANONICAL
+ 
+   // This is the pre-P0952 definition, to reproduce old results.
+ 
    template<typename _RealType, size_t __bits,
! 	  typename _UniformRandomNumberGenerator>
      _RealType
      generate_canonical(_UniformRandomNumberGenerator& __urng)
      {
        static_assert(std::is_floating_point<_RealType>::value,
! 		   "template argument must be a floating point type");
  
        const size_t __b
!        = std::min(static_cast<size_t>(std::numeric_limits<_RealType>::digits),
! 		   __bits);
        const long double __r = static_cast<long double>(__urng.max())
! 			   - static_cast<long double>(__urng.min()) + 1.0L;
        const size_t __log2r = std::log(__r) / std::log(2.0L);
        const size_t __m = std::max<size_t>(1UL,
! 					 (__b + __log2r - 1UL) / __log2r);
        _RealType __ret;
        _RealType __sum = _RealType(0);
        _RealType __tmp = _RealType(1);
*************** namespace __detail
*** 3499,3514 ****
        __ret = __sum / __tmp;
        if (__builtin_expect(__ret >= _RealType(1), 0))
  	{
! #if _GLIBCXX_USE_C99_MATH_FUNCS
  	  __ret = std::nextafter(_RealType(1), _RealType(0));
! #else
  	  __ret = _RealType(1)
  	    - std::numeric_limits<_RealType>::epsilon() / _RealType(2);
! #endif
  	}
        return __ret;
      }
  
  _GLIBCXX_END_NAMESPACE_VERSION
  } // namespace
  
--- 3752,3769 ----
        __ret = __sum / __tmp;
        if (__builtin_expect(__ret >= _RealType(1), 0))
  	{
! # if _GLIBCXX_USE_C99_MATH_FUNCS
  	  __ret = std::nextafter(_RealType(1), _RealType(0));
! # else
  	  __ret = _RealType(1)
  	    - std::numeric_limits<_RealType>::epsilon() / _RealType(2);
! # endif
  	}
        return __ret;
      }
  
+ #endif // _GLIBCXX_USE_OLD_GENERATE_CANONICAL
+ 
  _GLIBCXX_END_NAMESPACE_VERSION
  } // namespace
  
diff -Nrcpad gcc-16-20251214/libstdc++-v3/include/bits/ranges_algo.h gcc-16-20251221/libstdc++-v3/include/bits/ranges_algo.h
*** gcc-16-20251214/libstdc++-v3/include/bits/ranges_algo.h	Sun Dec 14 22:32:17 2025
--- gcc-16-20251221/libstdc++-v3/include/bits/ranges_algo.h	Sun Dec 21 22:32:15 2025
*************** namespace ranges
*** 2709,2715 ****
  	    }
  # endif
  
! 	    typedef _Temporary_buffer<_Iter, iter_value_t<_Iter>> _TmpBuf;
  	    // __stable_sort_adaptive sorts the range in two halves,
  	    // so the buffer only needs to fit half the range at once.
  	    _TmpBuf __buf(__first, ptrdiff_t((__last - __first + 1) / 2));
--- 2709,2715 ----
  	    }
  # endif
  
! 	    using _TmpBuf = _Temporary_buffer<_Iter, iter_value_t<_Iter>>;
  	    // __stable_sort_adaptive sorts the range in two halves,
  	    // so the buffer only needs to fit half the range at once.
  	    _TmpBuf __buf(__first, ptrdiff_t((__last - __first + 1) / 2));
*************** namespace ranges
*** 2718,2724 ****
  	      __detail::__stable_sort_adaptive(__first,
  					       __first + _DistanceType(__buf.size()),
  					       __last, __buf.begin(), __comp_proj);
! 	    else if (__buf.begin()) [[unlikely]]
  	      __detail::__inplace_stable_sort(__first, __last, __comp_proj);
  	    else
  	      __detail::__stable_sort_adaptive_resize(__first, __last, __buf.begin(),
--- 2718,2724 ----
  	      __detail::__stable_sort_adaptive(__first,
  					       __first + _DistanceType(__buf.size()),
  					       __last, __buf.begin(), __comp_proj);
! 	    else if (__buf.begin() == nullptr) [[unlikely]]
  	      __detail::__inplace_stable_sort(__first, __last, __comp_proj);
  	    else
  	      __detail::__stable_sort_adaptive_resize(__first, __last, __buf.begin(),
diff -Nrcpad gcc-16-20251214/libstdc++-v3/include/bits/shared_ptr_atomic.h gcc-16-20251221/libstdc++-v3/include/bits/shared_ptr_atomic.h
*** gcc-16-20251214/libstdc++-v3/include/bits/shared_ptr_atomic.h	Sun Dec 14 22:32:17 2025
--- gcc-16-20251221/libstdc++-v3/include/bits/shared_ptr_atomic.h	Sun Dec 21 22:32:15 2025
*************** _GLIBCXX_BEGIN_NAMESPACE_VERSION
*** 421,427 ****
  
  	~_Atomic_count()
  	{
! 	  auto __val = _AtomicRef(_M_val).load(memory_order_relaxed);
  	  _GLIBCXX_TSAN_MUTEX_DESTROY(&_M_val);
  	  __glibcxx_assert(!(__val & _S_lock_bit));
  	  if (auto __pi = reinterpret_cast<pointer>(__val))
--- 421,427 ----
  
  	~_Atomic_count()
  	{
! 	  auto __val = _AtomicRef(&_M_val).load(memory_order_relaxed);
  	  _GLIBCXX_TSAN_MUTEX_DESTROY(&_M_val);
  	  __glibcxx_assert(!(__val & _S_lock_bit));
  	  if (auto __pi = reinterpret_cast<pointer>(__val))
*************** _GLIBCXX_BEGIN_NAMESPACE_VERSION
*** 443,449 ****
  	{
  	  // To acquire the lock we flip the LSB from 0 to 1.
  
! 	  _AtomicRef __aref(_M_val);
  	  auto __current = __aref.load(memory_order_relaxed);
  	  while (__current & _S_lock_bit)
  	    {
--- 443,449 ----
  	{
  	  // To acquire the lock we flip the LSB from 0 to 1.
  
! 	  _AtomicRef __aref(&_M_val);
  	  auto __current = __aref.load(memory_order_relaxed);
  	  while (__current & _S_lock_bit)
  	    {
*************** _GLIBCXX_BEGIN_NAMESPACE_VERSION
*** 476,482 ****
  	unlock(memory_order __o) const noexcept
  	{
  	  _GLIBCXX_TSAN_MUTEX_PRE_UNLOCK(&_M_val);
! 	  _AtomicRef(_M_val).fetch_sub(1, __o);
  	  _GLIBCXX_TSAN_MUTEX_POST_UNLOCK(&_M_val);
  	}
  
--- 476,482 ----
  	unlock(memory_order __o) const noexcept
  	{
  	  _GLIBCXX_TSAN_MUTEX_PRE_UNLOCK(&_M_val);
! 	  _AtomicRef(&_M_val).fetch_sub(1, __o);
  	  _GLIBCXX_TSAN_MUTEX_POST_UNLOCK(&_M_val);
  	}
  
*************** _GLIBCXX_BEGIN_NAMESPACE_VERSION
*** 489,495 ****
  	    __o = memory_order_release;
  	  auto __x = reinterpret_cast<uintptr_t>(__c._M_pi);
  	  _GLIBCXX_TSAN_MUTEX_PRE_UNLOCK(&_M_val);
! 	  __x = _AtomicRef(_M_val).exchange(__x, __o);
  	  _GLIBCXX_TSAN_MUTEX_POST_UNLOCK(&_M_val);
  	  __c._M_pi = reinterpret_cast<pointer>(__x & ~_S_lock_bit);
  	}
--- 489,495 ----
  	    __o = memory_order_release;
  	  auto __x = reinterpret_cast<uintptr_t>(__c._M_pi);
  	  _GLIBCXX_TSAN_MUTEX_PRE_UNLOCK(&_M_val);
! 	  __x = _AtomicRef(&_M_val).exchange(__x, __o);
  	  _GLIBCXX_TSAN_MUTEX_POST_UNLOCK(&_M_val);
  	  __c._M_pi = reinterpret_cast<pointer>(__x & ~_S_lock_bit);
  	}
*************** _GLIBCXX_BEGIN_NAMESPACE_VERSION
*** 502,508 ****
  	  auto __old_ptr = __ptr;
  	  _GLIBCXX_TSAN_MUTEX_PRE_UNLOCK(&_M_val);
  	  uintptr_t __old_pi 
! 	    = _AtomicRef(_M_val).fetch_sub(1, memory_order_relaxed) - 1u;
  	  _GLIBCXX_TSAN_MUTEX_POST_UNLOCK(&_M_val);
  
    	  // Ensure that the correct value of _M_ptr is visible after locking,
--- 502,508 ----
  	  auto __old_ptr = __ptr;
  	  _GLIBCXX_TSAN_MUTEX_PRE_UNLOCK(&_M_val);
  	  uintptr_t __old_pi 
! 	    = _AtomicRef(&_M_val).fetch_sub(1, memory_order_relaxed) - 1u;
  	  _GLIBCXX_TSAN_MUTEX_POST_UNLOCK(&_M_val);
  
    	  // Ensure that the correct value of _M_ptr is visible after locking,
*************** _GLIBCXX_BEGIN_NAMESPACE_VERSION
*** 528,541 ****
  		// wake up if either of the values changed
  		return __new_pi != __old_pi || __new_ptr != __old_ptr;
  	      },
! 	    [__o, this] { return _AtomicRef(_M_val).load(__o); });
  	}
  
  	void
  	notify_one() noexcept
  	{
  	  _GLIBCXX_TSAN_MUTEX_PRE_SIGNAL(&_M_val);
! 	  _AtomicRef(_M_val).notify_one();
  	  _GLIBCXX_TSAN_MUTEX_POST_SIGNAL(&_M_val);
  	}
  
--- 528,541 ----
  		// wake up if either of the values changed
  		return __new_pi != __old_pi || __new_ptr != __old_ptr;
  	      },
! 	    [__o, this] { return _AtomicRef(&_M_val).load(__o); });
  	}
  
  	void
  	notify_one() noexcept
  	{
  	  _GLIBCXX_TSAN_MUTEX_PRE_SIGNAL(&_M_val);
! 	  _AtomicRef(&_M_val).notify_one();
  	  _GLIBCXX_TSAN_MUTEX_POST_SIGNAL(&_M_val);
  	}
  
*************** _GLIBCXX_BEGIN_NAMESPACE_VERSION
*** 543,549 ****
  	notify_all() noexcept
  	{
  	  _GLIBCXX_TSAN_MUTEX_PRE_SIGNAL(&_M_val);
! 	  _AtomicRef(_M_val).notify_all();
  	  _GLIBCXX_TSAN_MUTEX_POST_SIGNAL(&_M_val);
  	}
  #endif
--- 543,549 ----
  	notify_all() noexcept
  	{
  	  _GLIBCXX_TSAN_MUTEX_PRE_SIGNAL(&_M_val);
! 	  _AtomicRef(&_M_val).notify_all();
  	  _GLIBCXX_TSAN_MUTEX_POST_SIGNAL(&_M_val);
  	}
  #endif
diff -Nrcpad gcc-16-20251214/libstdc++-v3/include/bits/stl_algo.h gcc-16-20251221/libstdc++-v3/include/bits/stl_algo.h
*** gcc-16-20251214/libstdc++-v3/include/bits/stl_algo.h	Sun Dec 14 22:32:17 2025
--- gcc-16-20251221/libstdc++-v3/include/bits/stl_algo.h	Sun Dec 21 22:32:15 2025
*************** _GLIBCXX_BEGIN_NAMESPACE_VERSION
*** 226,232 ****
  	return std::__find_if(__first, __last, __unary_pred);
  
        return std::__search_n_aux(__first, __last, __count, __unary_pred,
! 				 std::__iterator_category(__first));
      }
  
    // find_end for forward iterators.
--- 226,232 ----
  	return std::__find_if(__first, __last, __unary_pred);
  
        return std::__search_n_aux(__first, __last, __count, __unary_pred,
! 				 std::__iter_concept_or_category(__first));
      }
  
    // find_end for forward iterators.
*************** _GLIBCXX_BEGIN_NAMESPACE_VERSION
*** 337,344 ****
        __glibcxx_requires_valid_range(__first2, __last2);
  
        return std::__find_end(__first1, __last1, __first2, __last2,
! 			     std::__iterator_category(__first1),
! 			     std::__iterator_category(__first2),
  			     __gnu_cxx::__ops::equal_to());
      }
  
--- 337,344 ----
        __glibcxx_requires_valid_range(__first2, __last2);
  
        return std::__find_end(__first1, __last1, __first2, __last2,
! 			     std::__iter_concept_or_category(__first1),
! 			     std::__iter_concept_or_category(__first2),
  			     __gnu_cxx::__ops::equal_to());
      }
  
*************** _GLIBCXX_BEGIN_NAMESPACE_VERSION
*** 388,395 ****
        __glibcxx_requires_valid_range(__first2, __last2);
  
        return std::__find_end(__first1, __last1, __first2, __last2,
! 			     std::__iterator_category(__first1),
! 			     std::__iterator_category(__first2),
  			     __comp);
      }
  
--- 388,395 ----
        __glibcxx_requires_valid_range(__first2, __last2);
  
        return std::__find_end(__first1, __last1, __first2, __last2,
! 			     std::__iter_concept_or_category(__first1),
! 			     std::__iter_concept_or_category(__first2),
  			     __comp);
      }
  
*************** _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
*** 3494,3503 ****
  		     _ForwardIterator2 __first2, _ForwardIterator2 __last2,
  		     _BinaryPredicate __pred)
      {
!       using _Cat1
! 	= typename iterator_traits<_ForwardIterator1>::iterator_category;
!       using _Cat2
! 	= typename iterator_traits<_ForwardIterator2>::iterator_category;
        using _It1_is_RA = is_same<_Cat1, random_access_iterator_tag>;
        using _It2_is_RA = is_same<_Cat2, random_access_iterator_tag>;
        constexpr bool __ra_iters = __and_<_It1_is_RA, _It2_is_RA>::value;
--- 3494,3501 ----
  		     _ForwardIterator2 __first2, _ForwardIterator2 __last2,
  		     _BinaryPredicate __pred)
      {
!       using _Cat1 = decltype(std::__iter_concept_or_category<_ForwardIterator1>());
!       using _Cat2 = decltype(std::__iter_concept_or_category<_ForwardIterator2>());
        using _It1_is_RA = is_same<_Cat1, random_access_iterator_tag>;
        using _It2_is_RA = is_same<_Cat2, random_access_iterator_tag>;
        constexpr bool __ra_iters = __and_<_It1_is_RA, _It2_is_RA>::value;
*************** _GLIBCXX_BEGIN_NAMESPACE_ALGO
*** 3800,3806 ****
      for_each_n(_InputIterator __first, _Size __n, _Function __f)
      {
        auto __n2 = std::__size_to_integer(__n);
!       using _Cat = typename iterator_traits<_InputIterator>::iterator_category;
        if constexpr (is_base_of_v<random_access_iterator_tag, _Cat>)
  	{
  	  if (__n2 <= 0)
--- 3798,3804 ----
      for_each_n(_InputIterator __first, _Size __n, _Function __f)
      {
        auto __n2 = std::__size_to_integer(__n);
!       using _Cat = decltype(std::__iter_concept_or_category<_InputIterator>());
        if constexpr (is_base_of_v<random_access_iterator_tag, _Cat>)
  	{
  	  if (__n2 <= 0)
*************** _GLIBCXX_BEGIN_NAMESPACE_ALGO
*** 4450,4456 ****
  	return __result;
        return std::__unique_copy(__first, __last, __result,
  				__gnu_cxx::__ops::equal_to(),
! 				std::__iterator_category(__first));
      }
  
    /**
--- 4448,4454 ----
  	return __result;
        return std::__unique_copy(__first, __last, __result,
  				__gnu_cxx::__ops::equal_to(),
! 				std::__iter_concept_or_category(__first));
      }
  
    /**
*************** _GLIBCXX_BEGIN_NAMESPACE_ALGO
*** 4491,4497 ****
        if (__first == __last)
  	return __result;
        return std::__unique_copy(__first, __last, __result, __binary_pred,
! 				std::__iterator_category(__first));
      }
  
  #if __cplusplus <= 201103L || _GLIBCXX_USE_DEPRECATED
--- 4489,4495 ----
        if (__first == __last)
  	return __result;
        return std::__unique_copy(__first, __last, __result, __binary_pred,
! 				std::__iter_concept_or_category(__first));
      }
  
  #if __cplusplus <= 201103L || _GLIBCXX_USE_DEPRECATED
*************** _GLIBCXX_BEGIN_NAMESPACE_ALGO
*** 5881,5890 ****
  	   _SampleIterator __out, _Distance __n,
  	   _UniformRandomBitGenerator&& __g)
      {
!       using __pop_cat = typename
! 	std::iterator_traits<_PopulationIterator>::iterator_category;
!       using __samp_cat = typename
! 	std::iterator_traits<_SampleIterator>::iterator_category;
  
        static_assert(
  	  __or_<is_convertible<__pop_cat, forward_iterator_tag>,
--- 5879,5888 ----
  	   _SampleIterator __out, _Distance __n,
  	   _UniformRandomBitGenerator&& __g)
      {
!       using __pop_cat
! 	= decltype(std::__iter_concept_or_category<_PopulationIterator>());
!       using __samp_cat
! 	= typename iterator_traits<_SampleIterator>::iterator_category;
  
        static_assert(
  	  __or_<is_convertible<__pop_cat, forward_iterator_tag>,
diff -Nrcpad gcc-16-20251214/libstdc++-v3/include/bits/stl_algobase.h gcc-16-20251221/libstdc++-v3/include/bits/stl_algobase.h
*** gcc-16-20251214/libstdc++-v3/include/bits/stl_algobase.h	Sun Dec 14 22:32:17 2025
--- gcc-16-20251221/libstdc++-v3/include/bits/stl_algobase.h	Sun Dec 21 22:32:15 2025
*************** _GLIBCXX_END_NAMESPACE_CONTAINER
*** 479,485 ****
  
    template<bool _IsMove, typename _II, typename _Tp>
      typename __gnu_cxx::__enable_if<
!       __is_random_access_iter<_II>::__value,
        _GLIBCXX_STD_C::_Deque_iterator<_Tp, _Tp&, _Tp*> >::__type
      __copy_move_a1(_II, _II, _GLIBCXX_STD_C::_Deque_iterator<_Tp, _Tp&, _Tp*>);
  
--- 479,485 ----
  
    template<bool _IsMove, typename _II, typename _Tp>
      typename __gnu_cxx::__enable_if<
!       __is_any_random_access_iter<_II>::__value,
        _GLIBCXX_STD_C::_Deque_iterator<_Tp, _Tp&, _Tp*> >::__type
      __copy_move_a1(_II, _II, _GLIBCXX_STD_C::_Deque_iterator<_Tp, _Tp&, _Tp*>);
  
*************** _GLIBCXX_END_NAMESPACE_CONTAINER
*** 768,774 ****
  
    template<bool _IsMove, typename _II, typename _Tp>
      typename __gnu_cxx::__enable_if<
!       __is_random_access_iter<_II>::__value,
        _GLIBCXX_STD_C::_Deque_iterator<_Tp, _Tp&, _Tp*> >::__type
      __copy_move_backward_a1(_II, _II,
  			    _GLIBCXX_STD_C::_Deque_iterator<_Tp, _Tp&, _Tp*>);
--- 768,774 ----
  
    template<bool _IsMove, typename _II, typename _Tp>
      typename __gnu_cxx::__enable_if<
!       __is_any_random_access_iter<_II>::__value,
        _GLIBCXX_STD_C::_Deque_iterator<_Tp, _Tp&, _Tp*> >::__type
      __copy_move_backward_a1(_II, _II,
  			    _GLIBCXX_STD_C::_Deque_iterator<_Tp, _Tp&, _Tp*>);
*************** _GLIBCXX_END_NAMESPACE_CONTAINER
*** 1218,1224 ****
  
    template<typename _Tp, typename _Ref, typename _Ptr, typename _II>
      typename __gnu_cxx::__enable_if<
!       __is_random_access_iter<_II>::__value, bool>::__type
      __equal_aux1(_GLIBCXX_STD_C::_Deque_iterator<_Tp, _Ref, _Ptr>,
  		 _GLIBCXX_STD_C::_Deque_iterator<_Tp, _Ref, _Ptr>,
  		 _II);
--- 1218,1224 ----
  
    template<typename _Tp, typename _Ref, typename _Ptr, typename _II>
      typename __gnu_cxx::__enable_if<
!       __is_any_random_access_iter<_II>::__value, bool>::__type
      __equal_aux1(_GLIBCXX_STD_C::_Deque_iterator<_Tp, _Ref, _Ptr>,
  		 _GLIBCXX_STD_C::_Deque_iterator<_Tp, _Ref, _Ptr>,
  		 _II);
*************** _GLIBCXX_END_NAMESPACE_CONTAINER
*** 1232,1238 ****
  
    template<typename _II, typename _Tp, typename _Ref, typename _Ptr>
      typename __gnu_cxx::__enable_if<
!       __is_random_access_iter<_II>::__value, bool>::__type
      __equal_aux1(_II, _II,
  		_GLIBCXX_STD_C::_Deque_iterator<_Tp, _Ref, _Ptr>);
  
--- 1232,1238 ----
  
    template<typename _II, typename _Tp, typename _Ref, typename _Ptr>
      typename __gnu_cxx::__enable_if<
!       __is_any_random_access_iter<_II>::__value, bool>::__type
      __equal_aux1(_II, _II,
  		_GLIBCXX_STD_C::_Deque_iterator<_Tp, _Ref, _Ptr>);
  
*************** _GLIBCXX_END_NAMESPACE_CONTAINER
*** 1331,1338 ****
  				   _II2 __first2, _II2 __last2,
  				   _Compare __comp)
      {
!       typedef typename iterator_traits<_II1>::iterator_category _Category1;
!       typedef typename iterator_traits<_II2>::iterator_category _Category2;
        typedef std::__lc_rai<_Category1, _Category2> __rai_type;
  
        __last1 = __rai_type::__newlast1(__first1, __last1, __first2, __last2);
--- 1331,1338 ----
  				   _II2 __first2, _II2 __last2,
  				   _Compare __comp)
      {
!       typedef __decltype(std::__iter_concept_or_category<_II1>()) _Category1;
!       typedef __decltype(std::__iter_concept_or_category<_II2>()) _Category2;
        typedef std::__lc_rai<_Category1, _Category2> __rai_type;
  
        __last1 = __rai_type::__newlast1(__first1, __last1, __first2, __last2);
*************** _GLIBCXX_BEGIN_NAMESPACE_ALGO
*** 1648,1655 ****
      __equal4(_II1 __first1, _II1 __last1, _II2 __first2, _II2 __last2)
      {
        using _RATag = random_access_iterator_tag;
!       using _Cat1 = typename iterator_traits<_II1>::iterator_category;
!       using _Cat2 = typename iterator_traits<_II2>::iterator_category;
        using _RAIters = __and_<is_same<_Cat1, _RATag>, is_same<_Cat2, _RATag>>;
        if constexpr (_RAIters::value)
  	{
--- 1648,1655 ----
      __equal4(_II1 __first1, _II1 __last1, _II2 __first2, _II2 __last2)
      {
        using _RATag = random_access_iterator_tag;
!       using _Cat1 = decltype(std::__iter_concept_or_category<_II1>());
!       using _Cat2 = decltype(std::__iter_concept_or_category<_II2>());
        using _RAIters = __and_<is_same<_Cat1, _RATag>, is_same<_Cat2, _RATag>>;
        if constexpr (_RAIters::value)
  	{
*************** _GLIBCXX_BEGIN_NAMESPACE_ALGO
*** 1675,1682 ****
  	     _BinaryPredicate __binary_pred)
      {
        using _RATag = random_access_iterator_tag;
!       using _Cat1 = typename iterator_traits<_II1>::iterator_category;
!       using _Cat2 = typename iterator_traits<_II2>::iterator_category;
        using _RAIters = __and_<is_same<_Cat1, _RATag>, is_same<_Cat2, _RATag>>;
        if constexpr (_RAIters::value)
  	{
--- 1675,1682 ----
  	     _BinaryPredicate __binary_pred)
      {
        using _RATag = random_access_iterator_tag;
!       using _Cat1 = decltype(std::__iter_concept_or_category<_II1>());
!       using _Cat2 = decltype(std::__iter_concept_or_category<_II2>());
        using _RAIters = __and_<is_same<_Cat1, _RATag>, is_same<_Cat2, _RATag>>;
        if constexpr (_RAIters::value)
  	{
diff -Nrcpad gcc-16-20251214/libstdc++-v3/include/bits/stl_iterator_base_funcs.h gcc-16-20251221/libstdc++-v3/include/bits/stl_iterator_base_funcs.h
*** gcc-16-20251214/libstdc++-v3/include/bits/stl_iterator_base_funcs.h	Sun Dec 14 22:32:17 2025
--- gcc-16-20251221/libstdc++-v3/include/bits/stl_iterator_base_funcs.h	Sun Dec 21 22:32:15 2025
*************** namespace __detail
*** 317,322 ****
--- 317,379 ----
  
  #endif // C++11
  
+ #if __glibcxx_algorithm_iterator_requirements // C++ >= 20
+   template<typename _Iter>
+     consteval auto
+     __iter_concept_or_category()
+     {
+       if constexpr (__detail::__promotable_iterator<_Iter>)
+ 	{
+ 	  using __type = __detail::__iter_traits<_Iter>::iterator_concept;
+ 	  if constexpr (derived_from<__type, random_access_iterator_tag>)
+ 	    return random_access_iterator_tag{};
+ 	  else
+ 	    return __type{};
+ 	}
+       else
+ 	return typename iterator_traits<_Iter>::iterator_category{};
+     }
+ 
+   template<typename _Iter>
+     __attribute__((__always_inline__))
+     constexpr auto
+     __iter_concept_or_category(const _Iter&)
+     { return std::__iter_concept_or_category<_Iter>(); }
+ #else
+   template<typename _Iter>
+     __attribute__((__always_inline__))
+     inline _GLIBCXX_CONSTEXPR
+     typename iterator_traits<_Iter>::iterator_category
+     __iter_concept_or_category()
+     { return typename iterator_traits<_Iter>::iterator_category(); }
+ 
+   template<typename _Iter>
+     __attribute__((__always_inline__))
+     inline _GLIBCXX_CONSTEXPR
+     typename iterator_traits<_Iter>::iterator_category
+     __iter_concept_or_category(const _Iter&)
+     { return typename iterator_traits<_Iter>::iterator_category(); }
+ #endif
+ 
+   // Like __is_random_access_iter, but based off of __iter_concept_or_category
+   // instead of iterator_traits::iterator_category.
+   template<typename _Iter,
+ 	   typename _Cat = __decltype(__iter_concept_or_category<_Iter>())>
+     struct __is_any_random_access_iter
+ #if __cplusplus >= 201103L
+       : is_base_of<random_access_iterator_tag, _Cat>
+ #endif
+     { enum { __value = __is_base_of(random_access_iterator_tag, _Cat) }; };
+ 
+ // A wrapper around ranges::iter_move that also converts to the iterator's
+ // value type.
+ #if __cplusplus >= 202002L
+ #define _GLIBCXX_ITER_MOVE(__it) \
+   std::iter_value_t<decltype(__it)>(std::ranges::iter_move(__it))
+ #else
+ #define _GLIBCXX_ITER_MOVE(__it) _GLIBCXX_MOVE(*__it)
+ #endif
+ 
  _GLIBCXX_END_NAMESPACE_VERSION
  } // namespace
  
diff -Nrcpad gcc-16-20251214/libstdc++-v3/include/bits/stl_uninitialized.h gcc-16-20251221/libstdc++-v3/include/bits/stl_uninitialized.h
*** gcc-16-20251214/libstdc++-v3/include/bits/stl_uninitialized.h	Sun Dec 14 22:32:17 2025
--- gcc-16-20251221/libstdc++-v3/include/bits/stl_uninitialized.h	Sun Dec 21 22:32:15 2025
*************** _GLIBCXX_BEGIN_NAMESPACE_VERSION
*** 1177,1183 ****
      uninitialized_copy_n(_InputIterator __first, _Size __n,
  			 _ForwardIterator __result)
      { return std::__uninitialized_copy_n(__first, __n, __result,
! 					 std::__iterator_category(__first)); }
  
    /// @cond undocumented
    template<typename _InputIterator, typename _Size, typename _ForwardIterator>
--- 1177,1183 ----
      uninitialized_copy_n(_InputIterator __first, _Size __n,
  			 _ForwardIterator __result)
      { return std::__uninitialized_copy_n(__first, __n, __result,
! 					 std::__iter_concept_or_category(__first)); }
  
    /// @cond undocumented
    template<typename _InputIterator, typename _Size, typename _ForwardIterator>
*************** _GLIBCXX_BEGIN_NAMESPACE_VERSION
*** 1188,1194 ****
      {
        return
  	std::__uninitialized_copy_n_pair(__first, __n, __result,
! 					 std::__iterator_category(__first));
      }
    /// @endcond
  #endif
--- 1188,1194 ----
      {
        return
  	std::__uninitialized_copy_n_pair(__first, __n, __result,
! 					 std::__iter_concept_or_category(__first));
      }
    /// @endcond
  #endif
diff -Nrcpad gcc-16-20251214/libstdc++-v3/include/bits/version.def gcc-16-20251221/libstdc++-v3/include/bits/version.def
*** gcc-16-20251214/libstdc++-v3/include/bits/version.def	Sun Dec 14 22:32:17 2025
--- gcc-16-20251221/libstdc++-v3/include/bits/version.def	Sun Dec 21 22:32:15 2025
*************** ftms = {
*** 2020,2025 ****
--- 2020,2034 ----
  };
  
  ftms = {
+   name = algorithm_iterator_requirements;
+   values = {
+     v = 202207;
+     // P2408R5 is a C++23 feature, but we support it in C++20.
+     cxxmin = 20;
+   };
+ };
+ 
+ ftms = {
    name = algorithm_default_value_type;
    values = {
      v = 202403;
*************** ftms = {
*** 2224,2229 ****
--- 2233,2239 ----
      v = 202502;
      cxxmin = 26;
      extra_cond = "__cpp_constexpr_exceptions >= 202411L";
+     cxx11abi = yes;
    };
  };
  
*************** ftms = {
*** 2232,2238 ****
    values = {
      v = 202406;
      cxxmin = 26;
-     extra_cond = "__SIZEOF_INT128__";
    };
  };
  
--- 2242,2247 ----
diff -Nrcpad gcc-16-20251214/libstdc++-v3/include/bits/version.h gcc-16-20251221/libstdc++-v3/include/bits/version.h
*** gcc-16-20251214/libstdc++-v3/include/bits/version.h	Sun Dec 14 22:32:17 2025
--- gcc-16-20251221/libstdc++-v3/include/bits/version.h	Sun Dec 21 22:32:15 2025
***************
*** 2256,2261 ****
--- 2256,2271 ----
  #endif /* !defined(__cpp_lib_observable_checkpoint) */
  #undef __glibcxx_want_observable_checkpoint
  
+ #if !defined(__cpp_lib_algorithm_iterator_requirements)
+ # if (__cplusplus >= 202002L)
+ #  define __glibcxx_algorithm_iterator_requirements 202207L
+ #  if defined(__glibcxx_want_all) || defined(__glibcxx_want_algorithm_iterator_requirements)
+ #   define __cpp_lib_algorithm_iterator_requirements 202207L
+ #  endif
+ # endif
+ #endif /* !defined(__cpp_lib_algorithm_iterator_requirements) */
+ #undef __glibcxx_want_algorithm_iterator_requirements
+ 
  #if !defined(__cpp_lib_algorithm_default_value_type)
  # if (__cplusplus >  202302L)
  #  define __glibcxx_algorithm_default_value_type 202403L
***************
*** 2487,2493 ****
  #undef __glibcxx_want_bitset
  
  #if !defined(__cpp_lib_constexpr_exceptions)
! # if (__cplusplus >  202302L) && (__cpp_constexpr_exceptions >= 202411L)
  #  define __glibcxx_constexpr_exceptions 202502L
  #  if defined(__glibcxx_want_all) || defined(__glibcxx_want_constexpr_exceptions)
  #   define __cpp_lib_constexpr_exceptions 202502L
--- 2497,2503 ----
  #undef __glibcxx_want_bitset
  
  #if !defined(__cpp_lib_constexpr_exceptions)
! # if (__cplusplus >  202302L) && _GLIBCXX_USE_CXX11_ABI && (__cpp_constexpr_exceptions >= 202411L)
  #  define __glibcxx_constexpr_exceptions 202502L
  #  if defined(__glibcxx_want_all) || defined(__glibcxx_want_constexpr_exceptions)
  #   define __cpp_lib_constexpr_exceptions 202502L
***************
*** 2497,2503 ****
  #undef __glibcxx_want_constexpr_exceptions
  
  #if !defined(__cpp_lib_philox_engine)
! # if (__cplusplus >  202302L) && (__SIZEOF_INT128__)
  #  define __glibcxx_philox_engine 202406L
  #  if defined(__glibcxx_want_all) || defined(__glibcxx_want_philox_engine)
  #   define __cpp_lib_philox_engine 202406L
--- 2507,2513 ----
  #undef __glibcxx_want_constexpr_exceptions
  
  #if !defined(__cpp_lib_philox_engine)
! # if (__cplusplus >  202302L)
  #  define __glibcxx_philox_engine 202406L
  #  if defined(__glibcxx_want_all) || defined(__glibcxx_want_philox_engine)
  #   define __cpp_lib_philox_engine 202406L
diff -Nrcpad gcc-16-20251214/libstdc++-v3/include/debug/helper_functions.h gcc-16-20251221/libstdc++-v3/include/debug/helper_functions.h
*** gcc-16-20251214/libstdc++-v3/include/debug/helper_functions.h	Sun Dec 14 22:32:17 2025
--- gcc-16-20251221/libstdc++-v3/include/debug/helper_functions.h	Sun Dec 21 22:32:15 2025
*************** namespace __gnu_debug
*** 292,298 ****
  
    template<typename _Iterator, typename _Sequence, typename _Category,
  	   typename _Size>
!     bool
      __can_advance(const _Safe_iterator<_Iterator, _Sequence, _Category>&,
  		  _Size);
  
--- 292,298 ----
  
    template<typename _Iterator, typename _Sequence, typename _Category,
  	   typename _Size>
!     _GLIBCXX20_CONSTEXPR bool
      __can_advance(const _Safe_iterator<_Iterator, _Sequence, _Category>&,
  		  _Size);
  
*************** namespace __gnu_debug
*** 304,310 ****
  
    template<typename _Iterator, typename _Sequence, typename _Category,
  	   typename _Diff>
!     bool
      __can_advance(const _Safe_iterator<_Iterator, _Sequence, _Category>&,
  		  const std::pair<_Diff, _Distance_precision>&, int);
  
--- 304,310 ----
  
    template<typename _Iterator, typename _Sequence, typename _Category,
  	   typename _Diff>
!     _GLIBCXX20_CONSTEXPR bool
      __can_advance(const _Safe_iterator<_Iterator, _Sequence, _Category>&,
  		  const std::pair<_Diff, _Distance_precision>&, int);
  
diff -Nrcpad gcc-16-20251214/libstdc++-v3/include/debug/safe_iterator.h gcc-16-20251221/libstdc++-v3/include/debug/safe_iterator.h
*** gcc-16-20251214/libstdc++-v3/include/debug/safe_iterator.h	Sun Dec 14 22:32:17 2025
--- gcc-16-20251221/libstdc++-v3/include/debug/safe_iterator.h	Sun Dec 21 22:32:15 2025
*************** namespace __gnu_debug
*** 1145,1165 ****
  
    template<typename _Iterator, typename _Sequence, typename _Category,
  	   typename _Size>
      inline bool
      __can_advance(const _Safe_iterator<_Iterator, _Sequence, _Category>& __it,
  		  _Size __n)
!     { return __it._M_can_advance(__n); }
  
    template<typename _Iterator, typename _Sequence, typename _Category,
  	   typename _Diff>
      inline bool
      __can_advance(const _Safe_iterator<_Iterator, _Sequence, _Category>& __it,
  		  const std::pair<_Diff, _Distance_precision>& __dist,
  		  int __way)
!     { return __it._M_can_advance(__dist, __way); }
  
    template<typename _Iterator, typename _Sequence>
!     _Iterator
      __base(const _Safe_iterator<_Iterator, _Sequence,
  				std::random_access_iterator_tag>& __it)
      { return __it.base(); }
--- 1145,1177 ----
  
    template<typename _Iterator, typename _Sequence, typename _Category,
  	   typename _Size>
+     _GLIBCXX20_CONSTEXPR
      inline bool
      __can_advance(const _Safe_iterator<_Iterator, _Sequence, _Category>& __it,
  		  _Size __n)
!     { 
!       if (std::__is_constant_evaluated())
! 	return true;
! 
!       return __it._M_can_advance(__n);
!     }
  
    template<typename _Iterator, typename _Sequence, typename _Category,
  	   typename _Diff>
+     _GLIBCXX20_CONSTEXPR
      inline bool
      __can_advance(const _Safe_iterator<_Iterator, _Sequence, _Category>& __it,
  		  const std::pair<_Diff, _Distance_precision>& __dist,
  		  int __way)
!     {
!       if (std::__is_constant_evaluated())
! 	return true;
!     
!       return __it._M_can_advance(__dist, __way);
!     }
  
    template<typename _Iterator, typename _Sequence>
!     _GLIBCXX20_CONSTEXPR _Iterator
      __base(const _Safe_iterator<_Iterator, _Sequence,
  				std::random_access_iterator_tag>& __it)
      { return __it.base(); }
diff -Nrcpad gcc-16-20251214/libstdc++-v3/include/std/algorithm gcc-16-20251221/libstdc++-v3/include/std/algorithm
*** gcc-16-20251214/libstdc++-v3/include/std/algorithm	Sun Dec 14 22:32:17 2025
--- gcc-16-20251221/libstdc++-v3/include/std/algorithm	Sun Dec 21 22:32:16 2025
***************
*** 66,71 ****
--- 66,72 ----
  #endif
  
  #define __glibcxx_want_algorithm_default_value_type
+ #define __glibcxx_want_algorithm_iterator_requirements
  #define __glibcxx_want_clamp
  #define __glibcxx_want_constexpr_algorithms
  #define __glibcxx_want_freestanding_algorithm
diff -Nrcpad gcc-16-20251214/libstdc++-v3/include/std/atomic gcc-16-20251221/libstdc++-v3/include/std/atomic
*** gcc-16-20251214/libstdc++-v3/include/std/atomic	Sun Dec 14 22:32:17 2025
--- gcc-16-20251221/libstdc++-v3/include/std/atomic	Sun Dec 21 22:32:16 2025
*************** _GLIBCXX_BEGIN_NAMESPACE_VERSION
*** 1766,1779 ****
      struct atomic_ref : __atomic_ref<_Tp>
      {
        explicit
!       atomic_ref(_Tp& __t) noexcept : __atomic_ref<_Tp>(__t)
!       { }
  
        atomic_ref& operator=(const atomic_ref&) = delete;
  
        atomic_ref(const atomic_ref&) = default;
  
        using __atomic_ref<_Tp>::operator=;
      };
  #endif // __cpp_lib_atomic_ref
  
--- 1766,1796 ----
      struct atomic_ref : __atomic_ref<_Tp>
      {
        explicit
!       atomic_ref(_Tp& __t) noexcept
!       : __atomic_ref<_Tp>(std::addressof(__t))
!       {
! 	__glibcxx_assert(((__UINTPTR_TYPE__)this->_M_ptr % this->required_alignment) == 0);
!       }
! 
!       // _GLIBCXX_RESOLVE_LIB_DEFECTS
!       // 4472. std::atomic_ref<const T> can be constructed from temporaries
!       explicit
!       atomic_ref(_Tp&&) = delete;
! 
!       template<typename _Up>
! 	requires is_convertible_v<_Up(*)[1], _Tp(*)[1]>
! 	atomic_ref(atomic_ref<_Up> __other) noexcept
! 	: __atomic_ref<_Tp>(__other._M_ptr)
! 	{ }
  
        atomic_ref& operator=(const atomic_ref&) = delete;
  
        atomic_ref(const atomic_ref&) = default;
  
        using __atomic_ref<_Tp>::operator=;
+ 
+       template<typename>
+ 	friend struct atomic_ref;
      };
  #endif // __cpp_lib_atomic_ref
  
diff -Nrcpad gcc-16-20251214/libstdc++-v3/include/std/barrier gcc-16-20251221/libstdc++-v3/include/std/barrier
*** gcc-16-20251214/libstdc++-v3/include/std/barrier	Sun Dec 14 22:32:17 2025
--- gcc-16-20251221/libstdc++-v3/include/std/barrier	Sun Dec 21 22:32:16 2025
*************** It looks different from literature pseud
*** 146,152 ****
  	      if (__current == __end_node)
  		__current = 0;
  	      auto __expect = __old_phase;
! 	      __atomic_phase_ref_t __phase(__state[__current]
  					      .__tickets[__round]);
  	      if (__current == __last_node && (__current_expected & 1))
  		{
--- 146,152 ----
  	      if (__current == __end_node)
  		__current = 0;
  	      auto __expect = __old_phase;
! 	      __atomic_phase_ref_t __phase(&__state[__current]
  					      .__tickets[__round]);
  	      if (__current == __last_node && (__current_expected & 1))
  		{
*************** It looks different from literature pseud
*** 198,204 ****
  
  	std::hash<std::thread::id> __hasher;
  	size_t __current = __hasher(std::this_thread::get_id());
! 	__atomic_phase_ref_t __phase(_M_phase);
  	const auto __old_phase = __phase.load(memory_order_relaxed);
  	const auto __cur = static_cast<unsigned char>(__old_phase);
  
--- 198,204 ----
  
  	std::hash<std::thread::id> __hasher;
  	size_t __current = __hasher(std::this_thread::get_id());
! 	__atomic_phase_ref_t __phase(&_M_phase);
  	const auto __old_phase = __phase.load(memory_order_relaxed);
  	const auto __cur = static_cast<unsigned char>(__old_phase);
  
*************** It looks different from literature pseud
*** 230,236 ****
        void
        wait(arrival_token&& __old_phase) const
        {
! 	__atomic_phase_const_ref_t __phase(_M_phase);
  	__phase.wait(__old_phase, memory_order_acquire);
        }
  
--- 230,236 ----
        void
        wait(arrival_token&& __old_phase) const
        {
! 	__atomic_phase_const_ref_t __phase(&_M_phase);
  	__phase.wait(__old_phase, memory_order_acquire);
        }
  
diff -Nrcpad gcc-16-20251214/libstdc++-v3/include/std/chrono gcc-16-20251221/libstdc++-v3/include/std/chrono
*** gcc-16-20251214/libstdc++-v3/include/std/chrono	Sun Dec 14 22:32:17 2025
--- gcc-16-20251221/libstdc++-v3/include/std/chrono	Sun Dec 21 22:32:16 2025
*************** namespace __detail
*** 3240,3246 ****
        };
        // The list above is known to be valid until (at least) this date
        // and only contains positive leap seconds.
!       const sys_seconds __expires(1766880000s); // 2025-12-28 00:00:00 UTC
  
  #if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI
        if (__ss > __expires)
--- 3240,3246 ----
        };
        // The list above is known to be valid until (at least) this date
        // and only contains positive leap seconds.
!       constexpr sys_seconds __expires(1782604800s); // 2026-06-28 00:00:00 UTC
  
  #if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI
        if (__ss > __expires)
diff -Nrcpad gcc-16-20251214/libstdc++-v3/include/std/memory gcc-16-20251221/libstdc++-v3/include/std/memory
*** gcc-16-20251214/libstdc++-v3/include/std/memory	Sun Dec 14 22:32:17 2025
--- gcc-16-20251221/libstdc++-v3/include/std/memory	Sun Dec 21 22:32:16 2025
***************
*** 102,107 ****
--- 102,108 ----
  #endif
  
  #define __glibcxx_want_addressof_constexpr
+ #define __glibcxx_want_algorithm_iterator_requirements
  #define __glibcxx_want_allocator_traits_is_always_equal
  #define __glibcxx_want_assume_aligned
  #define __glibcxx_want_atomic_shared_ptr
diff -Nrcpad gcc-16-20251214/libstdc++-v3/include/std/mutex gcc-16-20251221/libstdc++-v3/include/std/mutex
*** gcc-16-20251214/libstdc++-v3/include/std/mutex	Sun Dec 14 22:32:17 2025
--- gcc-16-20251221/libstdc++-v3/include/std/mutex	Sun Dec 21 22:32:16 2025
*************** _GLIBCXX_BEGIN_NAMESPACE_VERSION
*** 817,825 ****
--- 817,841 ----
  # ifdef _GLIBCXX_HAVE_TLS
    // If TLS is available use thread-local state for the type-erased callable
    // that is being run by std::call_once in the current thread.
+ #  ifdef _GLIBCXX_NO_EXTERN_THREAD_LOCAL
+ 
+   void*&
+   __get_once_callable() noexcept;
+ 
+   std::add_lvalue_reference<void (*)()>::type
+   __get_once_call() noexcept;
+ 
+   // These macros mean that all the code below uses the same syntax:
+ #define __once_callable __get_once_callable()
+ #define __once_call __get_once_call()
+ 
+ #  else // ! _GLIBCXX_NO_EXTERN_THREAD_LOCAL
+ 
    extern __thread void* __once_callable;
    extern __thread void (*__once_call)();
  
+ #  endif // ! _GLIBCXX_NO_EXTERN_THREAD_LOCAL
+ 
    // RAII type to set up state for pthread_once call.
    struct once_flag::_Prepare_execution
    {
*************** _GLIBCXX_BEGIN_NAMESPACE_VERSION
*** 844,849 ****
--- 860,868 ----
      _Prepare_execution& operator=(const _Prepare_execution&) = delete;
    };
  
+ #undef __once_callable
+ #undef __once_call
+ 
  # else
    // Without TLS use a global std::mutex and store the callable in a
    // global std::function.
diff -Nrcpad gcc-16-20251214/libstdc++-v3/include/std/numeric gcc-16-20251221/libstdc++-v3/include/std/numeric
*** gcc-16-20251214/libstdc++-v3/include/std/numeric	Sun Dec 14 22:32:17 2025
--- gcc-16-20251221/libstdc++-v3/include/std/numeric	Sun Dec 21 22:32:16 2025
***************
*** 60,66 ****
  #endif
  
  #include <bits/c++config.h>
! #include <bits/stl_iterator_base_types.h>
  #include <bits/stl_numeric.h>
  
  #ifdef _GLIBCXX_PARALLEL
--- 60,66 ----
  #endif
  
  #include <bits/c++config.h>
! #include <bits/stl_iterator_base_funcs.h>
  #include <bits/stl_numeric.h>
  
  #ifdef _GLIBCXX_PARALLEL
***************
*** 81,86 ****
--- 81,87 ----
  # include <limits>
  #endif
  
+ #define __glibcxx_want_algorithm_iterator_requirements
  #define __glibcxx_want_constexpr_numeric
  #define __glibcxx_want_gcd
  #define __glibcxx_want_gcd_lcm
*************** namespace __detail
*** 298,304 ****
        static_assert(is_invocable_r_v<_Tp, _BinaryOperation&, __ref, _Tp&>);
        static_assert(is_invocable_r_v<_Tp, _BinaryOperation&, _Tp&, _Tp&>);
        static_assert(is_invocable_r_v<_Tp, _BinaryOperation&, __ref, __ref>);
!       if constexpr (__is_random_access_iter<_InputIterator>::value)
  	{
  	  while ((__last - __first) >= 4)
  	    {
--- 299,305 ----
        static_assert(is_invocable_r_v<_Tp, _BinaryOperation&, __ref, _Tp&>);
        static_assert(is_invocable_r_v<_Tp, _BinaryOperation&, _Tp&, _Tp&>);
        static_assert(is_invocable_r_v<_Tp, _BinaryOperation&, __ref, __ref>);
!       if constexpr (__is_any_random_access_iter<_InputIterator>::value)
  	{
  	  while ((__last - __first) >= 4)
  	    {
*************** namespace __detail
*** 378,385 ****
  		     _BinaryOperation1 __binary_op1,
  		     _BinaryOperation2 __binary_op2)
      {
!       if constexpr (__and_v<__is_random_access_iter<_InputIterator1>,
! 			    __is_random_access_iter<_InputIterator2>>)
  	{
  	  while ((__last1 - __first1) >= 4)
  	    {
--- 379,386 ----
  		     _BinaryOperation1 __binary_op1,
  		     _BinaryOperation2 __binary_op2)
      {
!       if constexpr (__and_v<__is_any_random_access_iter<_InputIterator1>,
! 			    __is_any_random_access_iter<_InputIterator2>>)
  	{
  	  while ((__last1 - __first1) >= 4)
  	    {
*************** namespace __detail
*** 445,451 ****
      transform_reduce(_InputIterator __first, _InputIterator __last, _Tp __init,
  		     _BinaryOperation __binary_op, _UnaryOperation __unary_op)
      {
!       if constexpr (__is_random_access_iter<_InputIterator>::value)
  	{
  	  while ((__last - __first) >= 4)
  	    {
--- 446,452 ----
      transform_reduce(_InputIterator __first, _InputIterator __last, _Tp __init,
  		     _BinaryOperation __binary_op, _UnaryOperation __unary_op)
      {
!       if constexpr (__is_any_random_access_iter<_InputIterator>::value)
  	{
  	  while ((__last - __first) >= 4)
  	    {
*************** namespace __detail
*** 582,588 ****
      {
        if (__first != __last)
  	{
! 	  auto __init = std::move(*__first);
  	  *__result++ = __init;
  	  ++__first;
  	  if (__first != __last)
--- 583,589 ----
      {
        if (__first != __last)
  	{
! 	  auto __init = _GLIBCXX_ITER_MOVE(__first);
  	  *__result++ = __init;
  	  ++__first;
  	  if (__first != __last)
diff -Nrcpad gcc-16-20251214/libstdc++-v3/include/std/type_traits gcc-16-20251221/libstdc++-v3/include/std/type_traits
*** gcc-16-20251214/libstdc++-v3/include/std/type_traits	Sun Dec 14 22:32:17 2025
--- gcc-16-20251221/libstdc++-v3/include/std/type_traits	Sun Dec 21 22:32:16 2025
*************** _GLIBCXX_BEGIN_NAMESPACE_VERSION
*** 348,425 ****
      : public true_type { };
  
    /// @cond undocumented
    template<typename>
      struct __is_integral_helper
!     : public false_type { };
  
    template<>
      struct __is_integral_helper<bool>
!     : public true_type { };
  
    template<>
      struct __is_integral_helper<char>
!     : public true_type { };
  
    template<>
      struct __is_integral_helper<signed char>
!     : public true_type { };
  
    template<>
      struct __is_integral_helper<unsigned char>
!     : public true_type { };
  
    // We want is_integral<wchar_t> to be true (and make_signed/unsigned to work)
    // even when libc doesn't provide working <wchar.h> and related functions,
    // so don't check _GLIBCXX_USE_WCHAR_T here.
    template<>
      struct __is_integral_helper<wchar_t>
!     : public true_type { };
  
  #ifdef _GLIBCXX_USE_CHAR8_T
    template<>
      struct __is_integral_helper<char8_t>
!     : public true_type { };
  #endif
  
    template<>
      struct __is_integral_helper<char16_t>
!     : public true_type { };
  
    template<>
      struct __is_integral_helper<char32_t>
!     : public true_type { };
  
    template<>
      struct __is_integral_helper<short>
!     : public true_type { };
  
    template<>
      struct __is_integral_helper<unsigned short>
!     : public true_type { };
  
    template<>
      struct __is_integral_helper<int>
!     : public true_type { };
  
    template<>
      struct __is_integral_helper<unsigned int>
!     : public true_type { };
  
    template<>
      struct __is_integral_helper<long>
!     : public true_type { };
  
    template<>
      struct __is_integral_helper<unsigned long>
!     : public true_type { };
  
    template<>
      struct __is_integral_helper<long long>
!     : public true_type { };
  
    template<>
      struct __is_integral_helper<unsigned long long>
!     : public true_type { };
  
    // Conditionalizing on __STRICT_ANSI__ here will break any port that
    // uses one of these types for size_t.
--- 348,449 ----
      : public true_type { };
  
    /// @cond undocumented
+ 
+   // Every integral type is either one of the character types, one of the
+   // signed integer types, one of the unsigned integer types, or bool,
+   // or a cv-qualified version of one of those types ([basic.fundamental]).
+   // For now we only need to distinguish the signed/unsigned integer types.
+   enum class _Integer_kind { _None, _Signed, _Unsigned };
+ 
    template<typename>
      struct __is_integral_helper
!     : public false_type
!     { static constexpr auto _S_kind = _Integer_kind::_None; };
  
    template<>
      struct __is_integral_helper<bool>
!     : public true_type
!     { static constexpr auto _S_kind = _Integer_kind::_None; };
  
    template<>
      struct __is_integral_helper<char>
!     : public true_type
!     { static constexpr auto _S_kind = _Integer_kind::_None; };
  
    template<>
      struct __is_integral_helper<signed char>
!     : public true_type
!     { static constexpr auto _S_kind = _Integer_kind::_Signed; };
  
    template<>
      struct __is_integral_helper<unsigned char>
!     : public true_type
!     { static constexpr auto _S_kind = _Integer_kind::_Unsigned; };
  
    // We want is_integral<wchar_t> to be true (and make_signed/unsigned to work)
    // even when libc doesn't provide working <wchar.h> and related functions,
    // so don't check _GLIBCXX_USE_WCHAR_T here.
    template<>
      struct __is_integral_helper<wchar_t>
!     : public true_type
!     { static constexpr auto _S_kind = _Integer_kind::_None; };
  
  #ifdef _GLIBCXX_USE_CHAR8_T
    template<>
      struct __is_integral_helper<char8_t>
!     : public true_type
!     { static constexpr auto _S_kind = _Integer_kind::_None; };
  #endif
  
    template<>
      struct __is_integral_helper<char16_t>
!     : public true_type
!     { static constexpr auto _S_kind = _Integer_kind::_None; };
  
    template<>
      struct __is_integral_helper<char32_t>
!     : public true_type
!     { static constexpr auto _S_kind = _Integer_kind::_None; };
  
    template<>
      struct __is_integral_helper<short>
!     : public true_type
!     { static constexpr auto _S_kind = _Integer_kind::_Signed; };
  
    template<>
      struct __is_integral_helper<unsigned short>
!     : public true_type
!     { static constexpr auto _S_kind = _Integer_kind::_Unsigned; };
  
    template<>
      struct __is_integral_helper<int>
!     : public true_type
!     { static constexpr auto _S_kind = _Integer_kind::_Signed; };
  
    template<>
      struct __is_integral_helper<unsigned int>
!     : public true_type
!     { static constexpr auto _S_kind = _Integer_kind::_Unsigned; };
  
    template<>
      struct __is_integral_helper<long>
!     : public true_type
!     { static constexpr auto _S_kind = _Integer_kind::_Signed; };
  
    template<>
      struct __is_integral_helper<unsigned long>
!     : public true_type
!     { static constexpr auto _S_kind = _Integer_kind::_Unsigned; };
  
    template<>
      struct __is_integral_helper<long long>
!     : public true_type
!     { static constexpr auto _S_kind = _Integer_kind::_Signed; };
  
    template<>
      struct __is_integral_helper<unsigned long long>
!     : public true_type
!     { static constexpr auto _S_kind = _Integer_kind::_Unsigned; };
  
    // Conditionalizing on __STRICT_ANSI__ here will break any port that
    // uses one of these types for size_t.
*************** _GLIBCXX_BEGIN_NAMESPACE_VERSION
*** 427,485 ****
    __extension__
    template<>
      struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_0>
!     : public true_type { };
  
    __extension__
    template<>
      struct __is_integral_helper<unsigned __GLIBCXX_TYPE_INT_N_0>
!     : public true_type { };
  #endif
  #if defined(__GLIBCXX_TYPE_INT_N_1)
    __extension__
    template<>
      struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_1>
!     : public true_type { };
  
    __extension__
    template<>
      struct __is_integral_helper<unsigned __GLIBCXX_TYPE_INT_N_1>
!     : public true_type { };
  #endif
  #if defined(__GLIBCXX_TYPE_INT_N_2)
    __extension__
    template<>
      struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_2>
!     : public true_type { };
  
    __extension__
    template<>
      struct __is_integral_helper<unsigned __GLIBCXX_TYPE_INT_N_2>
!     : public true_type { };
  #endif
  #if defined(__GLIBCXX_TYPE_INT_N_3)
    __extension__
    template<>
      struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_3>
!     : public true_type { };
  
    __extension__
    template<>
      struct __is_integral_helper<unsigned __GLIBCXX_TYPE_INT_N_3>
!     : public true_type { };
  #endif
  
  #if defined __SIZEOF_INT128__ && defined __STRICT_ANSI__
    __extension__
    template<>
      struct __is_integral_helper<__int128>
!     : public true_type { };
  
    __extension__
    template<>
      struct __is_integral_helper<unsigned __int128>
!     : public true_type { };
  #endif
  
    /// @endcond
  
    /// is_integral
--- 451,538 ----
    __extension__
    template<>
      struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_0>
!     : public true_type
!     { static constexpr auto _S_kind = _Integer_kind::_Signed; };
  
    __extension__
    template<>
      struct __is_integral_helper<unsigned __GLIBCXX_TYPE_INT_N_0>
!     : public true_type
!     { static constexpr auto _S_kind = _Integer_kind::_Unsigned; };
  #endif
  #if defined(__GLIBCXX_TYPE_INT_N_1)
    __extension__
    template<>
      struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_1>
!     : public true_type
!     { static constexpr auto _S_kind = _Integer_kind::_Signed; };
  
    __extension__
    template<>
      struct __is_integral_helper<unsigned __GLIBCXX_TYPE_INT_N_1>
!     : public true_type
!     { static constexpr auto _S_kind = _Integer_kind::_Unsigned; };
  #endif
  #if defined(__GLIBCXX_TYPE_INT_N_2)
    __extension__
    template<>
      struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_2>
!     : public true_type
!     { static constexpr auto _S_kind = _Integer_kind::_Signed; };
  
    __extension__
    template<>
      struct __is_integral_helper<unsigned __GLIBCXX_TYPE_INT_N_2>
!     : public true_type
!     { static constexpr auto _S_kind = _Integer_kind::_Unsigned; };
  #endif
  #if defined(__GLIBCXX_TYPE_INT_N_3)
    __extension__
    template<>
      struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_3>
!     : public true_type
!     { static constexpr auto _S_kind = _Integer_kind::_Signed; };
  
    __extension__
    template<>
      struct __is_integral_helper<unsigned __GLIBCXX_TYPE_INT_N_3>
!     : public true_type
!     { static constexpr auto _S_kind = _Integer_kind::_Unsigned; };
  #endif
  
  #if defined __SIZEOF_INT128__ && defined __STRICT_ANSI__
    __extension__
    template<>
      struct __is_integral_helper<__int128>
!     : public true_type
!     { static constexpr auto _S_kind = _Integer_kind::_Signed; };
  
    __extension__
    template<>
      struct __is_integral_helper<unsigned __int128>
!     : public true_type
!     { static constexpr auto _S_kind = _Integer_kind::_Unsigned; };
  #endif
  
+   // Check if a type is one of the signed integer types.
+   template<typename _Tp>
+     using __is_signed_integer
+       = __bool_constant<__is_integral_helper<_Tp>::_S_kind
+ 			  == _Integer_kind::_Signed>;
+ 
+   // Check if a type is one of the unsigned integer types.
+   template<typename _Tp>
+     using __is_unsigned_integer
+       = __bool_constant<__is_integral_helper<_Tp>::_S_kind
+ 			  == _Integer_kind::_Unsigned>;
+ 
+   // Check if a type is one of the signed or unsigned integer types.
+   // i.e. an integral type except bool, char, wchar_t, and charN_t.
+   template<typename _Tp>
+     using __is_signed_or_unsigned_integer
+       = __bool_constant<__is_integral_helper<_Tp>::_S_kind
+ 			  != _Integer_kind::_None>;
+ 
    /// @endcond
  
    /// is_integral
*************** _GLIBCXX_BEGIN_NAMESPACE_VERSION
*** 823,880 ****
    template<typename _Tp, typename... _Types>
      using __is_one_of = __or_<is_same<_Tp, _Types>...>;
  
-   // Check if a type is one of the signed integer types.
-   __extension__
-   template<typename _Tp>
-     using __is_signed_integer = __is_one_of<_Tp,
- 	  signed char, signed short, signed int, signed long,
- 	  signed long long
- #if defined(__GLIBCXX_TYPE_INT_N_0)
- 	  , signed __GLIBCXX_TYPE_INT_N_0
- #endif
- #if defined(__GLIBCXX_TYPE_INT_N_1)
- 	  , signed __GLIBCXX_TYPE_INT_N_1
- #endif
- #if defined(__GLIBCXX_TYPE_INT_N_2)
- 	  , signed __GLIBCXX_TYPE_INT_N_2
- #endif
- #if defined(__GLIBCXX_TYPE_INT_N_3)
- 	  , signed __GLIBCXX_TYPE_INT_N_3
- #endif
- #if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__
- 	  , signed __int128
- #endif
- 	  >;
- 
-   // Check if a type is one of the unsigned integer types.
-   __extension__
-   template<typename _Tp>
-     using __is_unsigned_integer = __is_one_of<_Tp,
- 	  unsigned char, unsigned short, unsigned int, unsigned long,
- 	  unsigned long long
- #if defined(__GLIBCXX_TYPE_INT_N_0)
- 	  , unsigned __GLIBCXX_TYPE_INT_N_0
- #endif
- #if defined(__GLIBCXX_TYPE_INT_N_1)
- 	  , unsigned __GLIBCXX_TYPE_INT_N_1
- #endif
- #if defined(__GLIBCXX_TYPE_INT_N_2)
- 	  , unsigned __GLIBCXX_TYPE_INT_N_2
- #endif
- #if defined(__GLIBCXX_TYPE_INT_N_3)
- 	  , unsigned __GLIBCXX_TYPE_INT_N_3
- #endif
- #if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__
- 	  , unsigned __int128
- #endif
- 	  >;
- 
-   // Check if a type is one of the signed or unsigned integer types.
-   // i.e. an integral type except bool, char, wchar_t, and charN_t.
-   template<typename _Tp>
-     using __is_signed_or_unsigned_integer
-       = __or_<__is_signed_integer<_Tp>, __is_unsigned_integer<_Tp>>;
- 
    // __void_t (std::void_t for C++11)
    template<typename...> using __void_t = void;
    /// @endcond
--- 876,881 ----
diff -Nrcpad gcc-16-20251214/libstdc++-v3/include/std/variant gcc-16-20251221/libstdc++-v3/include/std/variant
*** gcc-16-20251214/libstdc++-v3/include/std/variant	Sun Dec 14 22:32:17 2025
--- gcc-16-20251221/libstdc++-v3/include/std/variant	Sun Dec 21 22:32:16 2025
*************** namespace __variant
*** 211,217 ****
      __as(const std::variant<_Types...>&& __v) noexcept
      { return std::move(__v); }
  
! #if __cpp_lib_variant < 202106L
    template<typename _Type, bool = std::is_trivially_destructible_v<_Type>>
      struct _Uninitialized;
  #else
--- 211,217 ----
      __as(const std::variant<_Types...>&& __v) noexcept
      { return std::move(__v); }
  
! #if (__cpp_lib_variant < 202106L) && defined(_GLIBCXX_USE_VARIANT_CXX17_OLD_ABI)
    template<typename _Type, bool = std::is_trivially_destructible_v<_Type>>
      struct _Uninitialized;
  #else
*************** namespace __variant
*** 230,236 ****
  	: _M_storage(std::forward<_Args>(__args)...)
  	{ }
  
! #if __cpp_lib_variant < 202106L
        constexpr const _Type& _M_get() const & noexcept
        { return _M_storage; }
  
--- 230,236 ----
  	: _M_storage(std::forward<_Args>(__args)...)
  	{ }
  
! #if (__cpp_lib_variant < 202106L) && defined(_GLIBCXX_USE_VARIANT_CXX17_OLD_ABI)
        constexpr const _Type& _M_get() const & noexcept
        { return _M_storage; }
  
*************** namespace __variant
*** 247,256 ****
        _Type _M_storage;
      };
  
! #if __cpp_lib_variant < 202106L
    // This partial specialization is used for non-trivially destructible types
!   // in C++17, so that _Uninitialized<T> is trivially destructible and can be
!   // used as a union member in _Variadic_union.
    template<typename _Type>
      struct _Uninitialized<_Type, false>
      {
--- 247,255 ----
        _Type _M_storage;
      };
  
! #if (__cpp_lib_variant < 202106L) && defined(_GLIBCXX_USE_VARIANT_CXX17_OLD_ABI)
    // This partial specialization is used for non-trivially destructible types
!   // in C++17.
    template<typename _Type>
      struct _Uninitialized<_Type, false>
      {
*************** namespace __variant
*** 291,297 ****
  	return __variant::__get_n<_Np - 3>(
  		 std::forward<_Union>(__u)._M_rest._M_rest._M_rest);
      }
! #else
    template<size_t _Np, typename _Union>
      constexpr auto&&
      __get_n(_Union&& __u) noexcept
--- 290,296 ----
  	return __variant::__get_n<_Np - 3>(
  		 std::forward<_Union>(__u)._M_rest._M_rest._M_rest);
      }
! #else // !_GLIBCXX_USE_VARIANT_CXX17_OLD_ABI
    template<size_t _Np, typename _Union>
      constexpr auto&&
      __get_n(_Union&& __u) noexcept
*************** namespace __variant
*** 306,312 ****
  	return __variant::__get_n<_Np - 3>(
  		 std::forward<_Union>(__u)._M_rest._M_rest._M_rest);
      }
! #endif
  
    // Returns the typed storage for __v.
    template<size_t _Np, typename _Variant>
--- 305,311 ----
  	return __variant::__get_n<_Np - 3>(
  		 std::forward<_Union>(__u)._M_rest._M_rest._M_rest);
      }
! #endif // !_GLIBCXX_USE_VARIANT_CXX17_OLD_ABI
  
    // Returns the typed storage for __v.
    template<size_t _Np, typename _Variant>
diff -Nrcpad gcc-16-20251214/libstdc++-v3/src/c++11/mutex.cc gcc-16-20251221/libstdc++-v3/src/c++11/mutex.cc
*** gcc-16-20251214/libstdc++-v3/src/c++11/mutex.cc	Sun Dec 14 22:32:17 2025
--- gcc-16-20251221/libstdc++-v3/src/c++11/mutex.cc	Sun Dec 21 22:32:16 2025
*************** _GLIBCXX_BEGIN_NAMESPACE_VERSION
*** 34,39 ****
--- 34,53 ----
    __thread void* __once_callable;
    __thread void (*__once_call)();
  
+ # ifdef _GLIBCXX_NO_EXTERN_THREAD_LOCAL
+ 
+   // When thread-local variables can't be exported, these functions are called
+   // to retrieve these variables.
+   void*&
+   __get_once_callable() noexcept
+   { return __once_callable; }
+ 
+   std::add_lvalue_reference<void (*)()>::type
+   __get_once_call() noexcept
+   { return __once_call; }
+ 
+ # endif // _GLIBCXX_NO_EXTERN_THREAD_LOCAL
+ 
    extern "C" void __once_proxy()
    {
      // The caller stored a function pointer in __once_call. If it requires
diff -Nrcpad gcc-16-20251214/libstdc++-v3/src/c++20/tzdata.zi gcc-16-20251221/libstdc++-v3/src/c++20/tzdata.zi
*** gcc-16-20251214/libstdc++-v3/src/c++20/tzdata.zi	Sun Dec 14 22:32:17 2025
--- gcc-16-20251221/libstdc++-v3/src/c++20/tzdata.zi	Sun Dec 21 22:32:16 2025
***************
*** 1,4 ****
! # version 2025b
  # This zic input file is in the public domain.
  R d 1916 o - Jun 14 23s 1 S
  R d 1916 1919 - O Su>=1 23s 0 -
--- 1,4 ----
! # version 2025c
  # This zic input file is in the public domain.
  R d 1916 o - Jun 14 23s 1 S
  R d 1916 1919 - O Su>=1 23s 0 -
*************** Z America/Tijuana -7:48:4 - LMT 1922 Ja
*** 2951,2959 ****
  -8 1 PDT 1951 S 30 2
  -8 - PST 1952 Ap 27 2
  -8 1 PDT 1952 S 28 2
! -8 - PST 1954
! -8 CA P%sT 1961
! -8 - PST 1976
  -8 u P%sT 1996
  -8 m P%sT 2001
  -8 u P%sT 2002 F 20
--- 2951,2957 ----
  -8 1 PDT 1951 S 30 2
  -8 - PST 1952 Ap 27 2
  -8 1 PDT 1952 S 28 2
! -8 CA P%sT 1967
  -8 u P%sT 1996
  -8 m P%sT 2001
  -8 u P%sT 2002 F 20
diff -Nrcpad gcc-16-20251214/libstdc++-v3/src/c++20/tzdb.cc gcc-16-20251221/libstdc++-v3/src/c++20/tzdb.cc
*** gcc-16-20251214/libstdc++-v3/src/c++20/tzdb.cc	Sun Dec 14 22:32:17 2025
--- gcc-16-20251221/libstdc++-v3/src/c++20/tzdb.cc	Sun Dec 21 22:32:16 2025
*************** namespace std::chrono
*** 1245,1252 ****
    pair<vector<leap_second>, bool>
    tzdb_list::_Node::_S_read_leap_seconds()
    {
!     // This list is valid until at least 2025-12-28 00:00:00 UTC.
!     auto expires = sys_days{2025y/12/28};
      vector<leap_second> leaps
      {
        (leap_second)  78796800, // 1 Jul 1972
--- 1245,1252 ----
    pair<vector<leap_second>, bool>
    tzdb_list::_Node::_S_read_leap_seconds()
    {
!     // This list is valid until at least 2026-06-28 00:00:00 UTC.
!     constexpr auto expires = sys_days{2026y/06/28};
      vector<leap_second> leaps
      {
        (leap_second)  78796800, // 1 Jul 1972
*************** namespace std::chrono
*** 1854,1860 ****
  	return zone_range.front().iana_name;
  
        const auto iter = ranges::lower_bound(
! 	  zone_range, territory, {}, &windows_zone_map_entry::territory);
        if (iter == zone_range.end() || iter->territory != territory)
  	// Territory not within the the map, use "001".
  	return zone_range.front().iana_name;
--- 1854,1860 ----
  	return zone_range.front().iana_name;
  
        const auto iter = ranges::lower_bound(
! 	  zone_range, +territory, {}, &windows_zone_map_entry::territory);
        if (iter == zone_range.end() || iter->territory != territory)
  	// Territory not within the the map, use "001".
  	return zone_range.front().iana_name;
diff -Nrcpad gcc-16-20251214/libstdc++-v3/testsuite/18_support/exception/version.cc gcc-16-20251221/libstdc++-v3/testsuite/18_support/exception/version.cc
*** gcc-16-20251214/libstdc++-v3/testsuite/18_support/exception/version.cc	Sun Dec 14 22:32:17 2025
--- gcc-16-20251221/libstdc++-v3/testsuite/18_support/exception/version.cc	Sun Dec 21 22:32:16 2025
***************
*** 1,5 ****
--- 1,6 ----
  // { dg-do preprocess { target c++26 } }
  // { dg-add-options no_pch }
+ // { dg-require-effective-target cxx11_abi }
  
  #include <exception>
  
diff -Nrcpad gcc-16-20251214/libstdc++-v3/testsuite/18_support/exception_ptr/exception_ptr_cast.cc gcc-16-20251221/libstdc++-v3/testsuite/18_support/exception_ptr/exception_ptr_cast.cc
*** gcc-16-20251214/libstdc++-v3/testsuite/18_support/exception_ptr/exception_ptr_cast.cc	Sun Dec 14 22:32:17 2025
--- gcc-16-20251221/libstdc++-v3/testsuite/18_support/exception_ptr/exception_ptr_cast.cc	Sun Dec 21 22:32:16 2025
*************** constexpr bool test01(bool x)
*** 78,84 ****
--- 78,86 ----
    return true;
  }
  
+ #if _GLIBCXX_USE_CXX11_ABI
  static_assert(test01(false));
+ #endif
  
  int main()
  {
diff -Nrcpad gcc-16-20251214/libstdc++-v3/testsuite/19_diagnostics/headers/stdexcept/version.cc gcc-16-20251221/libstdc++-v3/testsuite/19_diagnostics/headers/stdexcept/version.cc
*** gcc-16-20251214/libstdc++-v3/testsuite/19_diagnostics/headers/stdexcept/version.cc	Sun Dec 14 22:32:17 2025
--- gcc-16-20251221/libstdc++-v3/testsuite/19_diagnostics/headers/stdexcept/version.cc	Sun Dec 21 22:32:16 2025
***************
*** 1,5 ****
--- 1,6 ----
  // { dg-do preprocess { target c++26 } }
  // { dg-add-options no_pch }
+ // { dg-require-effective-target cxx11_abi }
  
  #include <stdexcept>
  
diff -Nrcpad gcc-16-20251214/libstdc++-v3/testsuite/19_diagnostics/logic_error/constexpr.cc gcc-16-20251221/libstdc++-v3/testsuite/19_diagnostics/logic_error/constexpr.cc
*** gcc-16-20251214/libstdc++-v3/testsuite/19_diagnostics/logic_error/constexpr.cc	Sun Dec 14 22:32:17 2025
--- gcc-16-20251221/libstdc++-v3/testsuite/19_diagnostics/logic_error/constexpr.cc	Sun Dec 21 22:32:16 2025
***************
*** 1,4 ****
--- 1,5 ----
  // { dg-do compile { target c++26 } }
+ // { dg-require-effective-target cxx11_abi }
  
  #include <string>
  #include <stdexcept>
diff -Nrcpad gcc-16-20251214/libstdc++-v3/testsuite/19_diagnostics/runtime_error/constexpr.cc gcc-16-20251221/libstdc++-v3/testsuite/19_diagnostics/runtime_error/constexpr.cc
*** gcc-16-20251214/libstdc++-v3/testsuite/19_diagnostics/runtime_error/constexpr.cc	Sun Dec 14 22:32:17 2025
--- gcc-16-20251221/libstdc++-v3/testsuite/19_diagnostics/runtime_error/constexpr.cc	Sun Dec 21 22:32:16 2025
***************
*** 1,4 ****
--- 1,5 ----
  // { dg-do compile { target c++26 } }
+ // { dg-require-effective-target cxx11_abi }
  
  #include <string>
  #include <stdexcept>
diff -Nrcpad gcc-16-20251214/libstdc++-v3/testsuite/20_util/expected/version.cc gcc-16-20251221/libstdc++-v3/testsuite/20_util/expected/version.cc
*** gcc-16-20251214/libstdc++-v3/testsuite/20_util/expected/version.cc	Sun Dec 14 22:32:17 2025
--- gcc-16-20251221/libstdc++-v3/testsuite/20_util/expected/version.cc	Sun Dec 21 22:32:16 2025
***************
*** 15,21 ****
  # error "Feature-test macro for freestanding expected has wrong value in <version>"
  #endif
  
! #if __cplusplus > 202302L
  # ifndef __cpp_lib_constexpr_exceptions
  #  error "Feature test macro for constexpr_exceptions is missing in <version>"
  # elif __cpp_lib_constexpr_exceptions < 202502L
--- 15,21 ----
  # error "Feature-test macro for freestanding expected has wrong value in <version>"
  #endif
  
! #if __cplusplus > 202302L && _GLIBCXX_USE_CXX11_ABI
  # ifndef __cpp_lib_constexpr_exceptions
  #  error "Feature test macro for constexpr_exceptions is missing in <version>"
  # elif __cpp_lib_constexpr_exceptions < 202502L
***************
*** 40,46 ****
  # error "Feature-test macro for freestanding expected has wrong value in <expected>"
  #endif
  
! #if __cplusplus > 202302L
  # ifndef __cpp_lib_constexpr_exceptions
  #  error "Feature test macro for constexpr_exceptions is missing in <expected>"
  # elif __cpp_lib_constexpr_exceptions < 202502L
--- 40,46 ----
  # error "Feature-test macro for freestanding expected has wrong value in <expected>"
  #endif
  
! #if __cplusplus > 202302L && _GLIBCXX_USE_CXX11_ABI
  # ifndef __cpp_lib_constexpr_exceptions
  #  error "Feature test macro for constexpr_exceptions is missing in <expected>"
  # elif __cpp_lib_constexpr_exceptions < 202502L
diff -Nrcpad gcc-16-20251214/libstdc++-v3/testsuite/20_util/optional/version.cc gcc-16-20251221/libstdc++-v3/testsuite/20_util/optional/version.cc
*** gcc-16-20251214/libstdc++-v3/testsuite/20_util/optional/version.cc	Sun Dec 14 22:32:18 2025
--- gcc-16-20251221/libstdc++-v3/testsuite/20_util/optional/version.cc	Sun Dec 21 22:32:16 2025
***************
*** 30,40 ****
--- 30,42 ----
  #  error "Feature test macro for optional range support has wrong value for C++26 in <version>"
  # endif
  
+ # if _GLIBCXX_USE_CXX11_ABI
  # ifndef __cpp_lib_constexpr_exceptions
  #  error "Feature test macro for constexpr_exceptions is missing in <version>"
  # elif __cpp_lib_constexpr_exceptions < 202502L
  #  error "Feature test macro for constexpr_exceptions has wrong value in <version>"
  # endif
+ # endif
  #endif
  
  #undef __cpp_lib_optional
***************
*** 59,67 ****
--- 61,71 ----
  #  error "Feature test macro for optional range support has wrong value for C++26 in <optional>"
  # endif
  
+ # if _GLIBCXX_USE_CXX11_ABI
  # ifndef __cpp_lib_constexpr_exceptions
  #  error "Feature test macro for constexpr_exceptions is missing in <optional>"
  # elif __cpp_lib_constexpr_exceptions < 202502L
  #  error "Feature test macro for constexpr_exceptions has wrong value in <optional>"
  # endif
+ # endif
  #endif
diff -Nrcpad gcc-16-20251214/libstdc++-v3/testsuite/20_util/variant/112591.cc gcc-16-20251221/libstdc++-v3/testsuite/20_util/variant/112591.cc
*** gcc-16-20251214/libstdc++-v3/testsuite/20_util/variant/112591.cc	Sun Dec 14 22:32:18 2025
--- gcc-16-20251221/libstdc++-v3/testsuite/20_util/variant/112591.cc	Sun Dec 21 22:32:16 2025
***************
*** 4,9 ****
--- 4,18 ----
  #include <testsuite_hooks.h>
  
  struct NonEmpty { int x; };
+ struct NonTrivial
+ {
+   constexpr NonTrivial() : x(0) {}
+   constexpr NonTrivial(int p) : x(p) {}
+   ~NonTrivial() {}
+ 
+   int x;
+ };
+ 
  struct TrivialEmpty {};
  struct NonTrivialEmpty { ~NonTrivialEmpty() {} };
  
*************** bool testAlias()
*** 23,32 ****
  int main()
  {
    VERIFY( !testAlias<NonEmpty>() );
    VERIFY( !testAlias<TrivialEmpty>() );
! #if __cplusplus >= 202002L  
    VERIFY( !testAlias<NonTrivialEmpty>() );
! #else  
!   VERIFY( testAlias<NonTrivialEmpty>() );
  #endif
  }
--- 32,42 ----
  int main()
  {
    VERIFY( !testAlias<NonEmpty>() );
+   VERIFY( !testAlias<NonTrivial>() );
    VERIFY( !testAlias<TrivialEmpty>() );
! #if (__cplusplus >= 202002L) || !defined(_GLIBCXX_USE_VARIANT_CXX17_OLD_ABI)
    VERIFY( !testAlias<NonTrivialEmpty>() );
! #else
!   VERIFY(  testAlias<NonTrivialEmpty>() );
  #endif
  }
diff -Nrcpad gcc-16-20251214/libstdc++-v3/testsuite/20_util/variant/112591_compat.cc gcc-16-20251221/libstdc++-v3/testsuite/20_util/variant/112591_compat.cc
*** gcc-16-20251214/libstdc++-v3/testsuite/20_util/variant/112591_compat.cc	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/libstdc++-v3/testsuite/20_util/variant/112591_compat.cc	Sun Dec 21 22:32:16 2025
***************
*** 0 ****
--- 1,4 ----
+ // { dg-options "-D_GLIBCXX_USE_VARIANT_CXX17_OLD_ABI" }
+ // { dg-do run { target c++17 } }
+ 
+ #include "112591.cc"
diff -Nrcpad gcc-16-20251214/libstdc++-v3/testsuite/20_util/variant/constinit.cc gcc-16-20251221/libstdc++-v3/testsuite/20_util/variant/constinit.cc
*** gcc-16-20251214/libstdc++-v3/testsuite/20_util/variant/constinit.cc	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/libstdc++-v3/testsuite/20_util/variant/constinit.cc	Sun Dec 21 22:32:16 2025
***************
*** 0 ****
--- 1,40 ----
+ // { dg-do compile { target c++17 } }
+ 
+ #include <variant>
+ 
+ struct NonEmpty { int x; };
+ struct NonTrivial
+ {
+   constexpr NonTrivial() : x(0) {}
+   NonTrivial(int p) : x(p) {}
+   ~NonTrivial() {}
+ 
+   int x;
+ };
+ 
+ struct TrivialEmpty {};
+ struct NonTrivialEmpty
+ {
+   NonTrivialEmpty() = default;
+   NonTrivialEmpty(float) {}
+   ~NonTrivialEmpty() {}
+ };
+ 
+ std::variant<NonEmpty> vNonEmpty(std::in_place_type<NonEmpty>);
+ // { dg-final { scan-assembler-dem-not "(std::in_place_type_t<NonEmpty>)" } }
+ 
+ std::variant<NonTrivial> vNonTrivial(std::in_place_type<NonTrivial>);
+ // { dg-final { scan-assembler-dem-not "(std::in_place_type_t<NonTrivial>)" } }
+ 
+ std::variant<int, NonTrivial> vNonTrivialNonConstexpr(std::in_place_index<1>, 2);
+ // { dg-final { scan-assembler-dem "(std::in_place_index_t<1ul?>, int&&)" } }
+ 
+ std::variant<TrivialEmpty> vTrivialEmpty(std::in_place_type<TrivialEmpty>);
+ // { dg-final { scan-assembler-dem-not "(std::in_place_type_t<TrivialEmpty>)" } }
+ 
+ std::variant<NonTrivialEmpty> vNonTrivialEmpty(std::in_place_type<NonTrivialEmpty>);
+ // { dg-final { scan-assembler-dem-not "(std::in_place_type_t<NonTrivialEmpty>)" } }
+ 
+ std::variant<int, NonTrivialEmpty> vNonTrivialEmptyNonConstexpr(std::in_place_index<1>, 2.0);
+ // { dg-final { scan-assembler-dem "(std::in_place_index_t<1ul?>, double&&)" } }
+ 
diff -Nrcpad gcc-16-20251214/libstdc++-v3/testsuite/20_util/variant/constinit_compat.cc gcc-16-20251221/libstdc++-v3/testsuite/20_util/variant/constinit_compat.cc
*** gcc-16-20251214/libstdc++-v3/testsuite/20_util/variant/constinit_compat.cc	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/libstdc++-v3/testsuite/20_util/variant/constinit_compat.cc	Sun Dec 21 22:32:16 2025
***************
*** 0 ****
--- 1,43 ----
+ // { dg-options "-D_GLIBCXX_USE_VARIANT_CXX17_OLD_ABI" }
+ // { dg-do compile { target c++17 } }
+ 
+ #include <variant>
+ 
+ struct NonEmpty { int x; };
+ struct NonTrivial
+ {
+   constexpr NonTrivial() : x(0) {}
+   NonTrivial(int p) : x(p) {}
+   ~NonTrivial() {}
+ 
+   int x;
+ };
+ 
+ struct TrivialEmpty {};
+ struct NonTrivialEmpty
+ {
+   NonTrivialEmpty() = default;
+   NonTrivialEmpty(float) {}
+   ~NonTrivialEmpty() {}
+ };
+ 
+ std::variant<NonEmpty> vNonEmpty(std::in_place_type<NonEmpty>);
+ // { dg-final { scan-assembler-dem-not "(std::in_place_type_t<NonEmpty>)" } }
+ 
+ std::variant<NonTrivial> vNonTrivial(std::in_place_type<NonTrivial>);
+ // { dg-final { scan-assembler-dem "(std::in_place_type_t<NonTrivial>)" { target { ! c++20 } } } }
+ // { dg-final { scan-assembler-dem-not "(std::in_place_type_t<NonTrivial>)" { target c++20 } } }
+ 
+ std::variant<int, NonTrivial> vNonTrivialNonConstexpr(std::in_place_index<1>, 2);
+ // { dg-final { scan-assembler-dem "(std::in_place_index_t<1ul?>, int&&)" } }
+ 
+ std::variant<TrivialEmpty> vTrivialEmpty(std::in_place_type<TrivialEmpty>);
+ // { dg-final { scan-assembler-dem-not "(std::in_place_type_t<TrivialEmpty>)" } }
+ 
+ std::variant<NonTrivialEmpty> vNonTrivialEmpty(std::in_place_type<NonTrivialEmpty>);
+ // { dg-final { scan-assembler-dem "(std::in_place_type_t<NonTrivialEmpty>)" { target { ! c++20 } } } }
+ // { dg-final { scan-assembler-dem-not "(std::in_place_type_t<NonTrivialEmpty>)" { target c++20 } } }
+ 
+ std::variant<int, NonTrivialEmpty> vNonTrivialEmptyNonConstexpr(std::in_place_index<1>, 2.0);
+ // { dg-final { scan-assembler-dem "(std::in_place_index_t<1ul?>, double&&)" } } 
+ 
diff -Nrcpad gcc-16-20251214/libstdc++-v3/testsuite/20_util/variant/version.cc gcc-16-20251221/libstdc++-v3/testsuite/20_util/variant/version.cc
*** gcc-16-20251214/libstdc++-v3/testsuite/20_util/variant/version.cc	Sun Dec 14 22:32:18 2025
--- gcc-16-20251221/libstdc++-v3/testsuite/20_util/variant/version.cc	Sun Dec 21 22:32:16 2025
***************
*** 19,25 ****
  #endif
  #endif
  
! #if __cplusplus > 202302L
  #ifndef __cpp_lib_constexpr_exceptions
  # error "Feature test macro for constexpr_exceptions is missing in <version>"
  #elif __cpp_lib_constexpr_exceptions < 202502L
--- 19,25 ----
  #endif
  #endif
  
! #if __cplusplus > 202302L && _GLIBCXX_USE_CXX11_ABI
  #ifndef __cpp_lib_constexpr_exceptions
  # error "Feature test macro for constexpr_exceptions is missing in <version>"
  #elif __cpp_lib_constexpr_exceptions < 202502L
***************
*** 40,46 ****
  #endif
  #endif
  
! #if __cplusplus > 202302L
  #ifndef __cpp_lib_constexpr_exceptions
  # error "Feature test macro for constexpr_exceptions is missing in <variant>"
  #elif __cpp_lib_constexpr_exceptions < 202502L
--- 40,46 ----
  #endif
  #endif
  
! #if __cplusplus > 202302L && _GLIBCXX_USE_CXX11_ABI
  #ifndef __cpp_lib_constexpr_exceptions
  # error "Feature test macro for constexpr_exceptions is missing in <variant>"
  #elif __cpp_lib_constexpr_exceptions < 202502L
diff -Nrcpad gcc-16-20251214/libstdc++-v3/testsuite/25_algorithms/copy/122907.cc gcc-16-20251221/libstdc++-v3/testsuite/25_algorithms/copy/122907.cc
*** gcc-16-20251214/libstdc++-v3/testsuite/25_algorithms/copy/122907.cc	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/libstdc++-v3/testsuite/25_algorithms/copy/122907.cc	Sun Dec 21 22:32:16 2025
***************
*** 0 ****
--- 1,43 ----
+ // { dg-do run }
+ 
+ // Bug libstdc++/122907
+ // std::copy incorrectly uses memcpy when copying from signed or unsigned char
+ // buffer to bool buffer
+ 
+ #include <algorithm>
+ #include <testsuite_hooks.h>
+ 
+ template<typename T>
+ __attribute__((noinline,noipa))
+ void
+ test_pr122907(T (&buf)[4])
+ {
+   unsigned char uc[4];
+   bool bool_buf[4];
+   std::copy(buf, buf+1, bool_buf);
+   std::copy(bool_buf, bool_buf+1, uc);
+   VERIFY(uc[0] == bool(buf[0]));
+   std::copy(buf, buf+4, bool_buf);
+   std::copy(bool_buf, bool_buf+4, uc);
+   VERIFY(uc[0] == bool(buf[0]));
+   VERIFY(uc[1] == bool(buf[1]));
+   VERIFY(uc[2] == bool(buf[2]));
+   VERIFY(uc[3] == bool(buf[3]));
+ }
+ 
+ template<typename T>
+ void
+ test_pr122907()
+ {
+   T buf[4] = { (T)3,  (T)2, (T)1, (T)0 };
+   test_pr122907(buf);
+ }
+ 
+ int main()
+ {
+   test_pr122907<char>();
+   test_pr122907<signed char>();
+   test_pr122907<unsigned char>();
+   test_pr122907<bool>();
+   test_pr122907<int>();
+ }
diff -Nrcpad gcc-16-20251214/libstdc++-v3/testsuite/25_algorithms/find_end/c++20_iter.cc gcc-16-20251221/libstdc++-v3/testsuite/25_algorithms/find_end/c++20_iter.cc
*** gcc-16-20251214/libstdc++-v3/testsuite/25_algorithms/find_end/c++20_iter.cc	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/libstdc++-v3/testsuite/25_algorithms/find_end/c++20_iter.cc	Sun Dec 21 22:32:16 2025
***************
*** 0 ****
--- 1,23 ----
+ // Verify std::find_end is C++20 iterator aware as per P2408R5.
+ // { dg-do compile { target c++20 } }
+ 
+ #include <algorithm>
+ #include <ranges>
+ #include <testsuite_hooks.h>
+ 
+ constexpr bool
+ test01()
+ {
+   auto r = std::views::iota(0, 10);
+   auto s = std::views::iota(5, 10);
+   auto it = r.begin();
+   auto jt = s.begin();
+   static_assert( std::random_access_iterator<decltype(it)>);
+   static_assert( std::same_as<std::iterator_traits<decltype(it)>::iterator_category,
+ 			      std::input_iterator_tag> );
+   it = std::find_end(it, it+10, jt, jt+5);
+   VERIFY( it == r.begin() + 5 );
+   return true;
+ }
+ 
+ static_assert(test01());
diff -Nrcpad gcc-16-20251214/libstdc++-v3/testsuite/25_algorithms/sample/c++20_iter.cc gcc-16-20251221/libstdc++-v3/testsuite/25_algorithms/sample/c++20_iter.cc
*** gcc-16-20251214/libstdc++-v3/testsuite/25_algorithms/sample/c++20_iter.cc	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/libstdc++-v3/testsuite/25_algorithms/sample/c++20_iter.cc	Sun Dec 21 22:32:16 2025
***************
*** 0 ****
--- 1,23 ----
+ // Verify std::sample is C++20 iterator aware as per P2408R5.
+ // { dg-do compile { target c++20 } }
+ 
+ #include <algorithm>
+ #include <random>
+ #include <ranges>
+ #include <testsuite_hooks.h>
+ #include <testsuite_iterators.h>
+ 
+ std::mt19937 rng;
+ 
+ void
+ test01()
+ {
+   auto r = std::views::iota(10);
+   auto it = r.begin();
+   static_assert( std::random_access_iterator<decltype(it)>);
+   static_assert( std::same_as<std::iterator_traits<decltype(it)>::iterator_category,
+ 			      std::input_iterator_tag> );
+   int buf[10];
+   __gnu_test::output_container<int> s(buf);
+   std::sample(it, it+10, s.begin(), 10, rng);
+ }
diff -Nrcpad gcc-16-20251214/libstdc++-v3/testsuite/25_algorithms/search_n/c++20_iter.cc gcc-16-20251221/libstdc++-v3/testsuite/25_algorithms/search_n/c++20_iter.cc
*** gcc-16-20251214/libstdc++-v3/testsuite/25_algorithms/search_n/c++20_iter.cc	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/libstdc++-v3/testsuite/25_algorithms/search_n/c++20_iter.cc	Sun Dec 21 22:32:16 2025
***************
*** 0 ****
--- 1,21 ----
+ // Verify std::search_n is C++20 iterator aware as per P2408R5.
+ // { dg-do compile { target c++20 } }
+ 
+ #include <algorithm>
+ #include <ranges>
+ #include <testsuite_hooks.h>
+ 
+ constexpr bool
+ test01()
+ {
+   auto r = std::views::iota(0, 10);
+   auto it = r.begin();
+   static_assert( std::random_access_iterator<decltype(it)>);
+   static_assert( std::same_as<std::iterator_traits<decltype(it)>::iterator_category,
+ 			      std::input_iterator_tag> );
+   it = std::search_n(it, it+10, 1, 5);
+   VERIFY( it == r.begin() + 5 );
+   return true;
+ }
+ 
+ static_assert(test01());
diff -Nrcpad gcc-16-20251214/libstdc++-v3/testsuite/25_algorithms/stable_sort/123180.cc gcc-16-20251221/libstdc++-v3/testsuite/25_algorithms/stable_sort/123180.cc
*** gcc-16-20251214/libstdc++-v3/testsuite/25_algorithms/stable_sort/123180.cc	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/libstdc++-v3/testsuite/25_algorithms/stable_sort/123180.cc	Sun Dec 21 22:32:16 2025
***************
*** 0 ****
--- 1,66 ----
+ // { dg-do run }
+ 
+ #include <algorithm>
+ #include <new>
+ #include <cstdlib>
+ #include <cstdio>
+ 
+ #if __cplusplus < 201103L
+ # define NOEXCEPT throw()
+ # define nullptr 0
+ # define THROW_BAD_ALLOC throw(std::bad_alloc)
+ #else
+ # define NOEXCEPT noexcept
+ # define THROW_BAD_ALLOC noexcept(false)
+ #endif
+ 
+ std::size_t limit = -1u;
+ 
+ void* operator new(std::size_t n, const std::nothrow_t&) NOEXCEPT
+ {
+   if (n > limit)
+     return NULL;
+   return std::malloc(n);
+ }
+ 
+ void* operator new(std::size_t n) THROW_BAD_ALLOC
+ {
+   return std::malloc(n);
+ }
+ 
+ void operator delete(void* p) NOEXCEPT { std::free(p); }
+ #ifdef __cpp_sized_deallocation
+ void operator delete(void* p, std::size_t) NOEXCEPT { std::free(p); }
+ #endif
+ 
+ void
+ test_stl_algo()
+ {
+   int a[] = { 4, 6, 2, 1, 7, 9, 2, 2, 2, 8 };
+   limit = -1u;
+   std::stable_sort(a, a+10); // gets as much memory as it needs
+   limit = 2 * sizeof(int);
+   std::stable_sort(a, a+10); // only gets memory for two ints
+   limit = 0;
+   std::stable_sort(a, a+10); // gets no memory
+ }
+ 
+ void
+ test_ranges_algo()
+ {
+ #if __cplusplus >= 202002L
+   int a[] = { 4, 6, 2, 1, 7, 9, 2, 2, 2, 8 };
+   limit = -1u;
+   std::ranges::stable_sort(a); // gets as much memory as it needs
+   limit = 2 * sizeof(int);
+   std::ranges::stable_sort(a); // only gets memory for two ints
+   limit = 0;
+   std::ranges::stable_sort(a); // gets no memory
+ #endif
+ }
+ 
+ int main()
+ {
+   test_stl_algo();
+   test_ranges_algo();
+ }
diff -Nrcpad gcc-16-20251214/libstdc++-v3/testsuite/25_algorithms/unique_copy/c++20_iter.cc gcc-16-20251221/libstdc++-v3/testsuite/25_algorithms/unique_copy/c++20_iter.cc
*** gcc-16-20251214/libstdc++-v3/testsuite/25_algorithms/unique_copy/c++20_iter.cc	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/libstdc++-v3/testsuite/25_algorithms/unique_copy/c++20_iter.cc	Sun Dec 21 22:32:16 2025
***************
*** 0 ****
--- 1,33 ----
+ // Verify std::unique_copy is C++20 iterator aware as per P2408R5.
+ // { dg-do compile { target c++20 } }
+ 
+ #include <algorithm>
+ #include <ranges>
+ #include <testsuite_hooks.h>
+ #include <testsuite_iterators.h>
+ 
+ struct noncopyable
+ {
+   constexpr operator int() { return 42; }
+   noncopyable() = default;
+   noncopyable(const noncopyable&) = delete;
+   noncopyable& operator=(const noncopyable&) = delete;
+   friend auto operator<=>(const noncopyable&, const noncopyable&) = default;
+ };
+ 
+ constexpr bool
+ test01()
+ {
+   auto r = std::views::iota(10)
+     | std::views::transform([](int) { return noncopyable{}; });
+   auto it = r.begin();
+   static_assert( std::random_access_iterator<decltype(it)>);
+   static_assert( std::same_as<std::iterator_traits<decltype(it)>::iterator_category,
+ 			      std::input_iterator_tag> );
+   int buf[10];
+   __gnu_test::input_container<int> s(buf);
+   auto jt = std::unique_copy(it, it+10, s.begin());
+   return true;
+ }
+ 
+ static_assert(test01());
diff -Nrcpad gcc-16-20251214/libstdc++-v3/testsuite/26_numerics/inclusive_scan/c++20_iter.cc gcc-16-20251221/libstdc++-v3/testsuite/26_numerics/inclusive_scan/c++20_iter.cc
*** gcc-16-20251214/libstdc++-v3/testsuite/26_numerics/inclusive_scan/c++20_iter.cc	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/libstdc++-v3/testsuite/26_numerics/inclusive_scan/c++20_iter.cc	Sun Dec 21 22:32:16 2025
***************
*** 0 ****
--- 1,26 ----
+ // Verify std::inclusive_scan is C++20 iterator aware as per P2408R5.
+ // { dg-do compile { target c++23 } }
+ 
+ #include <numeric>
+ #include <ranges>
+ #include <testsuite_hooks.h>
+ 
+ constexpr bool
+ test01()
+ {
+   int x[10] = {1,2,3,4,5,6,7,8,9,10};
+   auto r = std::views::zip(x);
+   auto it = r.begin();
+   static_assert( std::random_access_iterator<decltype(it)>);
+   static_assert( std::same_as<std::iterator_traits<decltype(it)>::iterator_category,
+ 			      std::input_iterator_tag> );
+   std::tuple<int> y[10];
+   std::inclusive_scan(it, it+10, y,
+ 		      [](std::tuple<int> a, std::tuple<int> b) -> std::tuple<int> {
+ 			return std::get<0>(a) + std::get<0>(b);
+ 		      });
+   VERIFY( std::get<0>(y[9]) == 55 );
+   return true;
+ }
+ 
+ static_assert(test01());
diff -Nrcpad gcc-16-20251214/libstdc++-v3/testsuite/26_numerics/random/philox4x32.cc gcc-16-20251221/libstdc++-v3/testsuite/26_numerics/random/philox4x32.cc
*** gcc-16-20251214/libstdc++-v3/testsuite/26_numerics/random/philox4x32.cc	Sun Dec 14 22:32:18 2025
--- gcc-16-20251221/libstdc++-v3/testsuite/26_numerics/random/philox4x32.cc	Sun Dec 21 22:32:16 2025
***************
*** 1,5 ****
  // { dg-do run { target c++26 } }
- // { dg-require-cpp-feature-test __cpp_lib_philox_engine }
  
  // N5014 29.5.6 Engines and engine adaptors with predefined parameters
  
--- 1,4 ----
diff -Nrcpad gcc-16-20251214/libstdc++-v3/testsuite/26_numerics/random/philox4x64.cc gcc-16-20251221/libstdc++-v3/testsuite/26_numerics/random/philox4x64.cc
*** gcc-16-20251214/libstdc++-v3/testsuite/26_numerics/random/philox4x64.cc	Sun Dec 14 22:32:18 2025
--- gcc-16-20251221/libstdc++-v3/testsuite/26_numerics/random/philox4x64.cc	Sun Dec 21 22:32:16 2025
***************
*** 1,5 ****
  // { dg-do run { target c++26 } }
- // { dg-require-cpp-feature-test __cpp_lib_philox_engine }
  
  // N5014 29.5.6 Engines and engine adaptors with predefined parameters
  
--- 1,4 ----
diff -Nrcpad gcc-16-20251214/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/copy.cc gcc-16-20251221/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/copy.cc
*** gcc-16-20251214/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/copy.cc	Sun Dec 14 22:32:18 2025
--- gcc-16-20251221/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/copy.cc	Sun Dec 21 22:32:16 2025
***************
*** 1,5 ****
  // { dg-do run { target c++26 } }
- // { dg-require-cpp-feature-test __cpp_lib_philox_engine }
  
  // N5014 29.5.4 Random Number Engine Class Templates
  // N5014 29.5.4.5 Class Template philox_engine
--- 1,4 ----
diff -Nrcpad gcc-16-20251214/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/default.cc gcc-16-20251221/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/default.cc
*** gcc-16-20251214/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/default.cc	Sun Dec 14 22:32:18 2025
--- gcc-16-20251221/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/default.cc	Sun Dec 21 22:32:16 2025
***************
*** 1,5 ****
  // { dg-do run { target c++26 } }
- // { dg-require-cpp-feature-test __cpp_lib_philox_engine }
  
  // N5014 29.5.4.5 Class Template philox_engine
  
--- 1,4 ----
diff -Nrcpad gcc-16-20251214/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed.cc gcc-16-20251221/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed.cc
*** gcc-16-20251214/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed.cc	Sun Dec 14 22:32:18 2025
--- gcc-16-20251221/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed.cc	Sun Dec 21 22:32:16 2025
***************
*** 1,5 ****
  // { dg-do run { target c++26 } }
- // { dg-require-cpp-feature-test __cpp_lib_philox_engine }
  
  #include <random>
  #include <testsuite_hooks.h>
--- 1,4 ----
diff -Nrcpad gcc-16-20251214/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/equal.cc gcc-16-20251221/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/equal.cc
*** gcc-16-20251214/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/equal.cc	Sun Dec 14 22:32:18 2025
--- gcc-16-20251221/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/equal.cc	Sun Dec 21 22:32:16 2025
***************
*** 1,5 ****
  // { dg-do run { target c++26 } }
- // { dg-require-cpp-feature-test __cpp_lib_philox_engine }
  
  // N5014 29.5.4.5 Class Template philox_engine
  
--- 1,4 ----
diff -Nrcpad gcc-16-20251214/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/serialize.cc gcc-16-20251221/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/serialize.cc
*** gcc-16-20251214/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/serialize.cc	Sun Dec 14 22:32:18 2025
--- gcc-16-20251221/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/serialize.cc	Sun Dec 21 22:32:16 2025
***************
*** 1,5 ****
  // { dg-do run { target c++26 } }
- // { dg-require-cpp-feature-test __cpp_lib_philox_engine }
  
  // N5014 29.5.4.5 Class Template philox_engine
  
--- 1,4 ----
diff -Nrcpad gcc-16-20251214/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constants.cc gcc-16-20251221/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constants.cc
*** gcc-16-20251214/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constants.cc	Sun Dec 14 22:32:18 2025
--- gcc-16-20251221/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constants.cc	Sun Dec 21 22:32:16 2025
***************
*** 1,5 ****
  // { dg-do compile { target c++26 } }
- // { dg-require-cpp-feature-test __cpp_lib_philox_engine }
  
  // N5014 29.5.4.5 Class Template philox_engine
  
--- 1,4 ----
diff -Nrcpad gcc-16-20251214/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/typedefs.cc gcc-16-20251221/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/typedefs.cc
*** gcc-16-20251214/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/typedefs.cc	Sun Dec 14 22:32:18 2025
--- gcc-16-20251221/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/typedefs.cc	Sun Dec 21 22:32:16 2025
***************
*** 1,5 ****
  // { dg-do compile { target c++26 } }
- // { dg-require-cpp-feature-test __cpp_lib_philox_engine }
  
  // N5014 29.5.4.5 Class Template philox_engine
  
--- 1,4 ----
diff -Nrcpad gcc-16-20251214/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc gcc-16-20251221/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc
*** gcc-16-20251214/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc	Sun Dec 14 22:32:18 2025
--- gcc-16-20251221/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc	Sun Dec 21 22:32:16 2025
*************** std::__detail::_Adaptor<std::mt19937, un
*** 10,15 ****
  auto x = std::generate_canonical<std::size_t,
  			std::numeric_limits<std::size_t>::digits>(urng);
  
! // { dg-error "static assertion failed: template argument must be a floating point type" "" { target *-*-* } 271 }
! 
! // { dg-error "static assertion failed: template argument must be a floating point type" "" { target *-*-* } 3480 }
--- 10,13 ----
  auto x = std::generate_canonical<std::size_t,
  			std::numeric_limits<std::size_t>::digits>(urng);
  
! // { dg-error "static assertion failed: template argument must be a floating point type" "" { target *-*-* } 0 }
diff -Nrcpad gcc-16-20251214/libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/64351.cc gcc-16-20251221/libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/64351.cc
*** gcc-16-20251214/libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/64351.cc	Sun Dec 14 22:32:18 2025
--- gcc-16-20251221/libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/64351.cc	Sun Dec 21 22:32:16 2025
***************
*** 17,22 ****
--- 17,23 ----
  
  // { dg-do run { target { c++11 && { ! simulator } } } }
  // { dg-require-cstdint "" }
+ // { dg-additional-options -fexcess-precision=standard }
  
  #include <random>
  #include <testsuite_hooks.h>
***************
*** 25,30 ****
--- 26,32 ----
  void
  test01()
  {
+ #ifdef _GLIBCXX_USE_OLD_GENERATE_CANONICAL
    std::mt19937 rng(8890);
    std::uniform_real_distribution<float> dist;
  
*************** test01()
*** 34,39 ****
--- 36,44 ----
        auto n = dist(rng);
        VERIFY( n != 1.f );
      }
+ #else
+   // New generate_canonical is tested in ./gencanon.cc
+ #endif
  }
  
  // libstdc++/63176
*************** test02()
*** 47,60 ****
    std::mt19937 rng2{rng};
    for (int i = 0; i < 20; ++i)
    {
!     float n =
!       std::generate_canonical<float, std::numeric_limits<float>::digits>(rng);
      VERIFY( n != 1.f );
  
-     // PR libstdc++/80137
      rng2.discard(1);
-     VERIFY( rng == rng2 );
    }
  }
  
  int
--- 52,70 ----
    std::mt19937 rng2{rng};
    for (int i = 0; i < 20; ++i)
    {
!     float n = std::generate_canonical<float, -1u>(rng);
      VERIFY( n != 1.f );
  
      rng2.discard(1);
    }
+ 
+   // PR libstdc++/80137
+ #ifdef _GLIBCXX_USE_OLD_GENERATE_CANONICAL
+   // Each std::generate_canonical call should consume exactly one value.
+ #else
+   rng2.discard(1);  // account for a 1.0 generated and discarded.
+ #endif
+   VERIFY( rng == rng2 );
  }
  
  int
diff -Nrcpad gcc-16-20251214/libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/gencanon.cc gcc-16-20251221/libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/gencanon.cc
*** gcc-16-20251214/libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/gencanon.cc	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/gencanon.cc	Sun Dec 21 22:32:16 2025
***************
*** 0 ****
--- 1,226 ----
+ // { dg-do run { target { c++11 && { ! simulator } } } }
+ // { dg-skip-if "requires new impl" { *-*-* } { -D_GLIBCXX_USE_OLD_GENERATE_CANONICAL -D_GLIBCXX_USE_OLD_GENERATE_CANONICAL=1 } }
+ // { dg-additional-options -fexcess-precision=standard }
+ 
+ #include <random>
+ #include <limits>
+ #include <type_traits>
+ #include <cmath>
+ #include <testsuite_hooks.h>
+ #include <array>
+ 
+ template <std::uint64_t max_val>
+ struct local_rng : std::mt19937
+ {
+   static constexpr std::uint64_t min() { return 0; }
+   static constexpr std::uint64_t max() { return max_val; }
+   std::uint64_t operator()()
+     { return static_cast<std::mt19937&>(*this)() % (max() + 1); }
+   local_rng(std::mt19937 const& arg) : std::mt19937(arg) {}
+ };
+ 
+ // Verify P0952R2 implementation requiring a second round-trip
+ // if first yields exactly 1. In this test, the RNG delivering
+ // 32 bits per call is seeded such that this occurs once on the
+ // sixth iteration for float, and not at all for double.
+ // However, each double iteration requires two calls to the RNG.
+ 
+ template <typename T, typename RNG>
+ void
+ test01(RNG& rng, RNG& rng2,
+   int& deviation, int& max, int& rms, int& zero, int& skips)
+ {
+   const auto size = 1000000, buckets = 100;
+   std::array<int, buckets> histo{};
+   for (auto i = 0; i != size; ++i) {
+     T sample = std::generate_canonical<T, -1u>(rng);
+     VERIFY(sample >= T(0.0));
+     VERIFY(sample < T(1.0));  // libstdc++/64351
+     if (sample == T(0.0)) {
+       ++zero;
+     }
+     auto bucket = static_cast<int>(std::floor(sample * buckets));
+     ++histo[bucket];
+     rng2.discard(1);
+     if (rng != rng2) {
+       ++skips;
+       rng2.discard(1);
+       VERIFY(rng == rng2);
+     }
+   }
+   int devsquare = 0;
+   for (int i = 0; i < buckets; ++i) {
+     const auto expected = size / buckets;
+     auto count = histo[i];
+     auto diff = count - expected;
+     if (diff < 0) diff = -diff;
+     deviation += diff;
+     devsquare += diff * diff;
+     if (diff > max) max = diff;
+   }
+   rms = std::sqrt(devsquare);
+ }
+ 
+ // This one is for use with local_rng
+ template <typename T, typename RNG>
+ void
+ test02(RNG& rng, RNG& rng2,
+   int& deviation, int& max, int& rms, int& zero, int& skips)
+ {
+   const auto size = 1000000, buckets = 100;
+   std::array<int, buckets> histo{};
+   for (auto i = 0; i != size; ++i) {
+     T sample = std::generate_canonical<T, -1u>(rng);
+     VERIFY(sample >= T(0.0));
+     VERIFY(sample < T(1.0));  // libstdc++/64351
+     if (sample == T(0.0)) {
+       ++zero;
+     }
+     auto bucket = static_cast<int>(std::floor(sample * buckets));
+     ++histo[bucket];
+     rng2.discard(2);
+     if (rng != rng2) {
+       ++skips;
+       rng2.discard(2);
+       VERIFY(rng == rng2);
+     }
+   }
+   int devsquare = 0;
+   for (int i = 0; i < buckets; ++i) {
+     const auto expected = size / buckets;
+     auto count = histo[i];
+     auto diff = count - expected;
+     if (diff < 0) diff = -diff;
+     deviation += diff;
+     devsquare += diff * diff;
+     if (diff > max) max = diff;
+   }
+   rms = std::sqrt(devsquare);
+ }
+ 
+ // This one is for the edge-case local_rng. It takes a bit count
+ // to use that is smaller than the floating point mantissa's.
+ template <typename T, unsigned bits, typename RNG>
+ void
+ test03(RNG& rng, RNG& rng2,
+   int& deviation, int& max, int& rms, int& zero, int& skips)
+ {
+   const auto size = 1000000, buckets = 100;
+   std::array<int, buckets> histo{};
+   for (auto i = 0; i != size; ++i) {
+     T sample = std::generate_canonical<T, bits>(rng);
+     VERIFY(sample >= T(0.0));
+     VERIFY(sample < T(1.0));  // libstdc++/64351
+     if (sample == T(0.0)) {
+       ++zero;
+     }
+     auto bucket = static_cast<int>(std::floor(sample * buckets));
+     ++histo[bucket];
+     rng2.discard(2);
+     if (rng != rng2) {
+       ++skips;
+       rng2.discard(2);
+       VERIFY(rng == rng2);
+     }
+   }
+   int devsquare = 0;
+   for (int i = 0; i < buckets; ++i) {
+     const auto expected = size / buckets;
+     auto count = histo[i];
+     auto diff = count - expected;
+     if (diff < 0) diff = -diff;
+     deviation += diff;
+     devsquare += diff * diff;
+     if (diff > max) max = diff;
+   }
+   rms = std::sqrt(devsquare);
+ }
+ 
+ void
+ test00()
+ {
+   std::mt19937 rng(8890);
+   std::seed_seq sequence{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+   rng.seed(sequence);
+   rng.discard(12 * 629143);
+ 
+   { // float
+     int deviation{}, max{}, rms{}, zero{}, skips{};
+     auto rng2{rng};
+     auto rng3{rng};
+     test01<float>(rng2, rng3, deviation, max, rms, zero, skips);
+ 
+     if (std::numeric_limits<float>::is_iec559) {
+       VERIFY(deviation == 7032);
+       VERIFY(max == 276);
+       VERIFY(rms == 906);
+       VERIFY(zero == 0);
+     }
+     VERIFY(skips == 1);
+   }
+   { // double
+     int deviation{}, max{}, rms{}, zero{}, skips{};
+     auto rng2{rng};
+     auto rng3{rng};
+     test01<double>(rng2, rng3, deviation, max, rms, zero, skips);
+ 
+     if (std::numeric_limits<double>::is_iec559) {
+       VERIFY(deviation == 7650);
+       VERIFY(max == 259);
+       VERIFY(rms == 975);
+       VERIFY(zero == 0);
+     }
+     VERIFY(skips == 1000000);
+   }
+   { // long double, same answers as double
+     int deviation{}, max{}, rms{}, zero{}, skips{};
+     auto rng2{rng};
+     auto rng3{rng};
+     test01<long double>(rng2, rng3, deviation, max, rms, zero, skips);
+ 
+     if (std::numeric_limits<double>::is_iec559) {
+       VERIFY(deviation == 7650);
+       VERIFY(max == 259);
+       VERIFY(rms == 975);
+       VERIFY(zero == 0);
+     }
+     VERIFY(skips == 1000000);
+   }
+ 
+   { // local RNG, returns [0..999'999)
+     int deviation{}, max{}, rms{}, zero{}, skips{};
+     local_rng<999999ULL> rng2{rng};
+     local_rng<999999ULL> rng3{rng};
+     test02<float>(rng2, rng3, deviation, max, rms, zero, skips);
+ 
+     if (std::numeric_limits<float>::is_iec559)
+     {
+       VERIFY(deviation == 8146);
+       VERIFY(max == 250);
+       VERIFY(rms == 1021);
+       VERIFY(zero == 0);
+     }
+     VERIFY(skips == 18);
+   }
+ 
+   { // local RNG, returns [0..0x0'7fff'fffe)
+     int deviation{}, max{}, rms{}, zero{}, skips{};
+     local_rng<0x07ffffffeULL> rng2{rng};
+     local_rng<0x07ffffffeULL> rng3{rng};
+     test03<double, 32u>(rng2, rng3, deviation, max, rms, zero, skips);
+ 
+     if (std::numeric_limits<double>::is_iec559)
+     {
+       VERIFY(deviation == 7820);
+       VERIFY(max == 240);
+       VERIFY(rms == 950);
+       VERIFY(zero == 0);
+     }
+     VERIFY(skips == 0);
+   }
+ }
+ 
+ int main()
+ {
+   test00();
+ }
diff -Nrcpad gcc-16-20251214/libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/gencanon_eng.cc gcc-16-20251221/libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/gencanon_eng.cc
*** gcc-16-20251214/libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/gencanon_eng.cc	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/gencanon_eng.cc	Sun Dec 21 22:32:16 2025
***************
*** 0 ****
--- 1,44 ----
+ // { dg-do compile { target { c++11 } } }
+ 
+ #include <random>
+ 
+ template<typename _Real, typename _URBG>
+ void
+ test_engine()
+ {
+   _URBG __engine;
+   (void)std::generate_canonical<_Real, size_t(-1)>(__engine);
+ }
+ 
+ template<typename _Real>
+ void
+ test_all_engines()
+ {
+   test_engine<_Real, std::default_random_engine>();
+ 
+   test_engine<_Real, std::minstd_rand0>(); 
+   test_engine<_Real, std::minstd_rand>();
+   test_engine<_Real, std::mt19937>();
+   test_engine<_Real, std::mt19937_64>();
+   test_engine<_Real, std::ranlux24_base>();
+   test_engine<_Real, std::ranlux48_base>();
+   test_engine<_Real, std::ranlux24>();
+   test_engine<_Real, std::ranlux48>();
+   test_engine<_Real, std::knuth_b>();
+ #if __cplusplus > 202302L 
+   test_engine<_Real, std::philox4x32>();
+   test_engine<_Real, std::philox4x64>();
+ #endif
+ }
+ 
+ int main()
+ {
+   test_all_engines<float>();
+   test_all_engines<double>();
+   test_all_engines<long double>();
+ #ifndef _GLIBCXX_GENERATE_CANONICAL_STRICT
+ #  ifdef __SIZEOF_FLOAT128__
+   test_all_engines<__float128>();
+ #  endif
+ #endif 
+ }
diff -Nrcpad gcc-16-20251214/libstdc++-v3/testsuite/29_atomics/atomic_ref/ctor.cc gcc-16-20251221/libstdc++-v3/testsuite/29_atomics/atomic_ref/ctor.cc
*** gcc-16-20251214/libstdc++-v3/testsuite/29_atomics/atomic_ref/ctor.cc	Thu Jan  1 00:00:00 1970
--- gcc-16-20251221/libstdc++-v3/testsuite/29_atomics/atomic_ref/ctor.cc	Sun Dec 21 22:32:16 2025
***************
*** 0 ****
--- 1,193 ----
+ // { dg-do run { target c++26 } }
+ // { dg-require-atomic-cmpxchg-word "" }
+ // { dg-add-options libatomic }
+ 
+ #include <atomic>
+ #include <testsuite_hooks.h>
+ 
+ struct X
+ {
+   X() = default;
+   X(int i) : i(i) { }
+   int i;
+ 
+   friend bool
+   operator==(X, X) = default;
+ };
+ 
+ template<typename T>
+ void testTemporary()
+ {
+   static_assert( !std::is_constructible_v<std::atomic_ref<T>, T> );
+   static_assert( !std::is_constructible_v<std::atomic_ref<const T>, T> );
+   static_assert( !std::is_constructible_v<std::atomic_ref<T>, const T> );
+   static_assert( !std::is_constructible_v<std::atomic_ref<const T>, const T> );
+ 
+   if constexpr (std::atomic_ref<T>::is_always_lock_free)
+   {
+     static_assert( !std::is_constructible_v<std::atomic_ref<volatile T>, T> );
+     static_assert( !std::is_constructible_v<std::atomic_ref<volatile T>, volatile T> );
+     static_assert( !std::is_constructible_v<std::atomic_ref<const volatile T>, T> );
+     static_assert( !std::is_constructible_v<std::atomic_ref<const volatile T>, const volatile T> );
+   }
+ 
+   struct X { X(T) {} };
+   struct Overload 
+   {
+     static int operator()(X) { return 1; }
+     static int operator()(std::atomic_ref<T>) { return 2; }
+   };
+   VERIFY( Overload{}(T()) == 1 );
+   static_assert( !requires { Overload{}({T()}); } );
+ }
+ 
+ template<typename T>
+ bool same_address(const std::atomic_ref<T>& t, const std::type_identity_t<T>& u)
+ {
+ #if (__cplusplus >  202302L)
+   return t.address() == &u;
+ #endif
+   return true;
+ }
+ 
+ template<typename From, typename To = From>
+ void
+ testConv()
+ {
+   alignas(std::atomic_ref<From>::required_alignment) From val{};
+   std::atomic_ref<From> src(val);
+   std::atomic_ref<const From> csrc(val);
+ 
+   std::atomic_ref<const To> d1(src);
+   VERIFY( same_address(d1, val) );
+   std::atomic_ref<const To> d2(csrc);
+   VERIFY( same_address(d2, val) );
+   static_assert( !std::is_convertible_v<std::atomic_ref<const From>,
+ 					std::atomic_ref<To>> );
+  
+   if constexpr (std::atomic_ref<From>::is_always_lock_free)
+   {
+     std::atomic_ref<const volatile To> d4(src);
+     VERIFY( same_address(d4, val) );
+     std::atomic_ref<const volatile To> d5(csrc);
+     VERIFY( same_address(d5, val) );
+     if constexpr (std::is_same_v<From, To>)
+     {	    
+       std::atomic_ref<volatile To> d3(src);
+       VERIFY( same_address(d3, val) );
+     }
+ 
+     static_assert( !std::is_convertible_v<std::atomic_ref<volatile From>,
+ 					  std::atomic_ref<To>> );
+     static_assert( !std::is_convertible_v<std::atomic_ref<volatile From>,
+ 					  std::atomic_ref<const To>> );
+     static_assert( !std::is_convertible_v<std::atomic_ref<const volatile From>,
+ 					  std::atomic_ref<To>> );
+     static_assert( !std::is_convertible_v<std::atomic_ref<const volatile From>,
+ 					  std::atomic_ref<const To>> );
+   }
+ }
+ 
+ template<typename From, typename To>
+ void
+ testSimilarConv()
+ {
+   testConv<From, To>();
+   static_assert( !std::is_convertible_v<      To,       From> );
+   static_assert( !std::is_convertible_v<      To, const From> );
+   static_assert( !std::is_convertible_v<const To,       From> );
+   static_assert( !std::is_convertible_v<const To, const From> );
+ 
+   if constexpr (std::atomic_ref<From>::is_always_lock_free)
+   {
+     static_assert( !std::is_convertible_v<volatile To,          From> );
+     static_assert( !std::is_convertible_v<         To, volatile From> );
+     static_assert( !std::is_convertible_v<volatile To, volatile From> );
+ 
+     static_assert( !std::is_convertible_v<const volatile To,                From> );
+     static_assert( !std::is_convertible_v<               To, const volatile From> );
+     static_assert( !std::is_convertible_v<const volatile To, const volatile From> );
+ 
+     static_assert( !std::is_convertible_v<      To, volatile From> );
+     static_assert( !std::is_convertible_v<const To, volatile From> );
+     static_assert( !std::is_convertible_v<      To, const volatile From> );
+     static_assert( !std::is_convertible_v<const To, const volatile From> );
+ 
+     static_assert( !std::is_convertible_v<volatile To,       From> );
+     static_assert( !std::is_convertible_v<volatile To, const From> );
+     static_assert( !std::is_convertible_v<const volatile To,       From> );
+     static_assert( !std::is_convertible_v<const volatile To, const From> );
+   }
+ }
+ 
+ template<typename T, template<typename> typename MakePtr = std::add_pointer_t>
+ void
+ testPtrConv()
+ {
+   testConv<MakePtr<T>>();
+   testSimilarConv<MakePtr<T>, MakePtr<const T>>(); 
+   testSimilarConv<MakePtr<T*>, MakePtr<const T* const>>(); 
+   testSimilarConv<MakePtr<const T*>, MakePtr<const T* const>>(); 
+   testSimilarConv<MakePtr<T* const>, MakePtr<const T* const>>();
+ 
+   testSimilarConv<MakePtr<T[2]>, MakePtr<const T[2]>>(); 
+   testSimilarConv<MakePtr<T[]>, MakePtr<const T[]>>(); 
+ 
+   testSimilarConv<MakePtr<T[2]>, MakePtr<T[]>>(); 
+   testSimilarConv<MakePtr<T[2]>, MakePtr<const T[]>>(); 
+   testSimilarConv<MakePtr<const T[2]>, MakePtr<const T[]>>(); 
+ 
+   if constexpr (std::atomic_ref<MakePtr<T>>::is_always_lock_free)
+   {
+     testSimilarConv<MakePtr<T>, MakePtr<volatile T>>(); 
+     testSimilarConv<MakePtr<T>, MakePtr<const volatile T>>(); 
+     testSimilarConv<MakePtr<volatile T>, MakePtr<const volatile T>>(); 
+     testSimilarConv<MakePtr<T*>, MakePtr<volatile T* const>>(); 
+     testSimilarConv<MakePtr<volatile T*>, MakePtr<volatile T* const>>();
+     testSimilarConv<MakePtr<T*>, MakePtr<const volatile T* const>>(); 
+     testSimilarConv<MakePtr<volatile T*>, MakePtr<const volatile T* const>>(); 
+     testSimilarConv<MakePtr<volatile T* const>, MakePtr<const volatile T* const>>(); 
+ 
+     testSimilarConv<MakePtr<T[2]>, MakePtr<volatile T[2]>>(); 
+     testSimilarConv<MakePtr<T[2]>, MakePtr<const volatile T[2]>>(); 
+     testSimilarConv<MakePtr<const T[2]>, MakePtr<const volatile T[2]>>(); 
+     testSimilarConv<MakePtr<volatile T[2]>, MakePtr<const volatile T[2]>>(); 
+ 
+     testSimilarConv<MakePtr<T[]>, MakePtr<volatile T[]>>(); 
+     testSimilarConv<MakePtr<T[]>, MakePtr<const volatile T[]>>(); 
+     testSimilarConv<MakePtr<const T[]>, MakePtr<const volatile T[]>>(); 
+     testSimilarConv<MakePtr<volatile T[]>, MakePtr<const volatile T[]>>(); 
+ 
+     testSimilarConv<MakePtr<T[2]>, MakePtr<volatile T[]>>(); 
+     testSimilarConv<MakePtr<volatile T[2]>, MakePtr<volatile T[]>>(); 
+     testSimilarConv<MakePtr<const T[2]>, MakePtr<const volatile T[]>>(); 
+     testSimilarConv<MakePtr<volatile T[2]>, MakePtr<const volatile T[]>>(); 
+     testSimilarConv<MakePtr<const volatile T[2]>, MakePtr<const volatile T[]>>(); 
+   }
+ }
+ 
+ struct D : X {};
+ static_assert( !std::is_convertible_v<std::atomic_ref<D>, std::atomic_ref<X>> );
+ static_assert( !std::is_convertible_v<std::atomic_ref<D>, std::atomic_ref<const X>> );
+ static_assert( !std::is_convertible_v<std::atomic_ref<D*>, std::atomic_ref<const X* const>> );
+ static_assert( !std::is_convertible_v<std::atomic_ref<const D*>, std::atomic_ref<const X* const>> );
+ 
+ template<typename T>
+ using member_pointer_t = T X::*;
+ 
+ int
+ main()
+ {
+   testTemporary<bool>();
+   testTemporary<int>();
+   testTemporary<float>();
+   testTemporary<int*>();
+   testTemporary<X>();
+ 
+   testConv<bool>();
+   testConv<int>();
+   testConv<float>();
+   testConv<X>();
+   testPtrConv<int>();
+   testPtrConv<int, member_pointer_t>();
+ }
diff -Nrcpad gcc-16-20251214/libstdc++-v3/testsuite/lib/libstdc++.exp gcc-16-20251221/libstdc++-v3/testsuite/lib/libstdc++.exp
*** gcc-16-20251214/libstdc++-v3/testsuite/lib/libstdc++.exp	Sun Dec 14 22:32:18 2025
--- gcc-16-20251221/libstdc++-v3/testsuite/lib/libstdc++.exp	Sun Dec 21 22:32:16 2025
*************** proc v3-dg-runtest { testcases flags def
*** 533,539 ****
  		# single test.
  		# These should be adjusted whenever the default -std is
  		# updated or newer C++ effective target is added.
! 		set default_std 17
  		set max_std 26
  		set min_std [v3-minimum-std $test $default_std $max_std]
  		if { $min_std > $default_std } {
--- 533,539 ----
  		# single test.
  		# These should be adjusted whenever the default -std is
  		# updated or newer C++ effective target is added.
! 		set default_std 20
  		set max_std 26
  		set min_std [v3-minimum-std $test $default_std $max_std]
  		if { $min_std > $default_std } {
diff -Nrcpad gcc-16-20251214/libstdc++-v3/testsuite/std/time/parse/parse.cc gcc-16-20251221/libstdc++-v3/testsuite/std/time/parse/parse.cc
*** gcc-16-20251214/libstdc++-v3/testsuite/std/time/parse/parse.cc	Sun Dec 14 22:32:18 2025
--- gcc-16-20251221/libstdc++-v3/testsuite/std/time/parse/parse.cc	Sun Dec 21 22:32:16 2025
*************** test_modifiers()
*** 317,322 ****
--- 317,335 ----
    VERIFY( s == 12s );
  }
  
+ void
+ test_wchar()
+ {
+   std::wistringstream is;
+   std::chrono::duration<double, std::milli> ms;
+ 
+   is.clear();
+   is.str(L"0.125");
+   is >> parse(L"%S", ms);
+   VERIFY( is.good() );
+   VERIFY( ms.count() == 125 );
+ }
+ 
  int main()
  {
    test_recommended_practice();
*************** int main()
*** 324,327 ****
--- 337,341 ----
    test_whitespace();
    test_errors();
    test_modifiers();
+   test_wchar();
  }
diff -Nrcpad gcc-16-20251214/maintainer-scripts/ChangeLog gcc-16-20251221/maintainer-scripts/ChangeLog
*** gcc-16-20251214/maintainer-scripts/ChangeLog	Sun Dec 14 22:32:18 2025
--- gcc-16-20251221/maintainer-scripts/ChangeLog	Sun Dec 21 22:32:16 2025
***************
*** 1,3 ****
--- 1,7 ----
+ 2025-12-16  Pietro Monteiro  <pietro@sociotechnical.xyz>
+ 
+ 	* update_web_docs_git (MANUALS): Add ga68 and ga68-internals.
+ 
  2025-09-01  Gerald Pfeifer  <gerald@pfeifer.com>
  
  	* update_web_docs_libstdcxx_git: Copy our "inner" documentation
diff -Nrcpad gcc-16-20251214/maintainer-scripts/update_web_docs_git gcc-16-20251221/maintainer-scripts/update_web_docs_git
*** gcc-16-20251214/maintainer-scripts/update_web_docs_git	Sun Dec 14 22:32:18 2025
--- gcc-16-20251221/maintainer-scripts/update_web_docs_git	Sun Dec 21 22:32:16 2025
*************** fi
*** 32,37 ****
--- 32,39 ----
  MANUALS="cpp
    cppinternals
    fastjar
+   ga68
+   ga68-internals
    gcc
    gccgo
    gccint
*************** find jit $LIBGDIAGNOSTICS \
*** 307,312 ****
--- 309,322 ----
      -o -name "*.css" -o -name "*.js" \
      -o -name "*.txt" |
    while read file ; do
+     # Avoid bogus redirects stemming from Sphinx stylesheets.
+     case $file in
+       *.html)
+         sed -e 's#<a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>#Alabaster#' \
+             -e 's#<a href="http://sphinx-doc.org/">Sphinx 5.3.0</a>#Sphinx#' \
+             -i $file
+ 	;;
+     esac
      # Note that $file here will contain path fragments beginning
      # with "jit/", e.g. "jit/cp/topics/functions.html"
      mkdir -p $(dirname $DOCSDIR/$file)
