diff options
author | Iain Buclaw <ibuclaw@gdcproject.org> | 2022-09-27 13:40:33 +0200 |
---|---|---|
committer | Iain Buclaw <ibuclaw@gdcproject.org> | 2022-09-27 13:40:33 +0200 |
commit | 76425e19243cc310566fe7fd2f772039f9b8ec9f (patch) | |
tree | 96c1066811af285f2e0d4c8bf68351f7c0442280 /gcc | |
parent | cecd314884a285957a110560bbd141a5f39ad7d3 (diff) | |
parent | 614e5696d730a65998ff5b0373f905795a758dd6 (diff) | |
download | gcc-76425e19243cc310566fe7fd2f772039f9b8ec9f.zip gcc-76425e19243cc310566fe7fd2f772039f9b8ec9f.tar.gz gcc-76425e19243cc310566fe7fd2f772039f9b8ec9f.tar.bz2 |
Merge remote-tracking branch 'mainline/master' into ibuclaw/merge_mainline
Fixes: #1544
Diffstat (limited to 'gcc')
268 files changed, 6704 insertions, 3132 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4ff50c3..4bd177d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,126 @@ +2022-09-26 Martin Liska <mliska@suse.cz> + + * doc/invoke.texi: Add missing dash for + Wanalyzer-exposure-through-uninit-copy. + +2022-09-26 Aldy Hernandez <aldyh@redhat.com> + + PR tree-optimization/107009 + * range-op.cc (operator_bitwise_and::op1_range): Optimize 0 = x & MASK. + (range_op_bitwise_and_tests): New test. + +2022-09-26 Aldy Hernandez <aldyh@redhat.com> + + PR tree-optimization/107009 + * tree-ssa-dom.cc + (dom_opt_dom_walker::set_global_ranges_from_unreachable_edges): + Iterate over exports. + +2022-09-26 Thomas Schwinge <thomas@codesourcery.com> + + * config.gcc (with_arch) [nvptx]: Allow '--with-arch' to override + the default. + * config/nvptx/gen-multilib-matches.sh: New. + * config/nvptx/t-nvptx (MULTILIB_OPTIONS, MULTILIB_MATCHES) + (MULTILIB_EXCEPTIONS): Handle this. + * doc/install.texi (Specific) <nvptx-*-none>: Document this. + * doc/invoke.texi (Nvidia PTX Options): Likewise. + +2022-09-26 Thomas Schwinge <thomas@codesourcery.com> + + * config.gcc (TM_MULTILIB_CONFIG) [nvptx]: Set to '$with_arch'. + * config/nvptx/t-nvptx (MULTILIB_OPTIONS, MULTILIB_MATCHES) + (MULTILIB_EXCEPTIONS): Handle it. + +2022-09-26 Thomas Schwinge <thomas@codesourcery.com> + + * config.gcc (with_arch) [nvptx]: Set to 'sm_30'. + * config/nvptx/nvptx.cc (nvptx_option_override): Assert that + '-misa' appeared. + * config/nvptx/nvptx.h (OPTION_DEFAULT_SPECS): Define. + * config/nvptx/nvptx.opt (misa=): Remove 'Init'. + +2022-09-26 Thomas Schwinge <thomas@codesourcery.com> + + * config/nvptx/nvptx.h (ASM_SPEC): Define. + +2022-09-26 Jeff Law <jeffreyalaw@gmail.com> + + * cfgcleanup.cc (bb_is_just_return): No longer static. + * cfgcleanup.h (bb_is_just_return): Add prototype. + * cfgrtl.cc (fixup_reorder_chain): Do not create an + unconditional jump to a return block. Conditionally + remove unreachable blocks. + +2022-09-26 Tobias Burnus <tobias@codesourcery.com> + + PR middle-end/106982 + * omp-low.cc (lower_oacc_reductions): Add some unshare_expr. + +2022-09-26 Martin Liska <mliska@suse.cz> + + * config/s390/s390.cc (s390_rtx_costs): Remove dest variable + and use only dst. + +2022-09-26 Kyrylo Tkachov <kyrylo.tkachov@arm.com> + + * config/aarch64/aarch64-arches.def (armv9.1-a): Define. + (armv9.2-a): Likewise. + (armv9.3-a): Likewise. + * config/aarch64/aarch64.h (AARCH64_FL_V9_1): Likewise. + (AARCH64_FL_V9_2): Likewise. + (AARCH64_FL_V9_3): Likewise. + (AARCH64_FL_FOR_ARCH9_1): Likewise. + (AARCH64_FL_FOR_ARCH9_2): Likewise. + (AARCH64_FL_FOR_ARCH9_3): Likewise. + (AARCH64_ISA_V9_1): Likewise. + (AARCH64_ISA_V9_2): Likewise. + (AARCH64_ISA_V9_3): Likewise. + * doc/invoke.texi (AArch64 Options): Document armv9.1-a, armv9.2-a, + armv9.3-a values to -march. + +2022-09-26 Martin Liska <mliska@suse.cz> + + * value-range.cc (tree_compare): Remove unused function. + +2022-09-26 Kewen Lin <linkw@linux.ibm.com> + + PR target/96072 + * config/rs6000/rs6000-logue.cc (rs6000_emit_epilogue): Update the + condition for adding REG_CFA_DEF_CFA reg note with + frame_pointer_needed_indeed. + +2022-09-26 Kewen Lin <linkw@linux.ibm.com> + + PR target/100645 + * config/rs6000/vector.md (vec_shr_<mode>): Replace condition + TARGET_ALTIVEC with VECTOR_UNIT_ALTIVEC_OR_VSX_P. + +2022-09-26 Hongtao Liu <hongtao.liu@intel.com> + Liwei Xu <liwei.xu@intel.com> + + PR target/53346 + * config/i386/i386-expand.cc (expand_vec_perm_shufps_shufps): + New function. + (ix86_expand_vec_perm_const_1): Insert + expand_vec_perm_shufps_shufps at the end of 2-instruction + expand sequence. + +2022-09-25 Torbjörn SVENSSON <torbjorn.svensson@foss.st.com> + + * doc/sourcebuild.texi: Fix chapter level. + +2022-09-24 Jakub Jelinek <jakub@redhat.com> + + PR c/107001 + * omp-low.cc (lower_omp_taskgroup): Don't add GOMP_RETURN statement + at the end. + * omp-expand.cc (build_omp_regions_1): Clarify GF_OMP_TARGET_KIND_DATA + is not stand-alone directive. For GIMPLE_OMP_TASKGROUP, also don't + update parent. + (omp_make_gimple_edges) <case GIMPLE_OMP_TASKGROUP>: Reset + cur_region back after new_omp_region. + 2022-09-23 Vineet Gupta <vineetg@rivosinc.com> * config/riscv/riscv.h (LOCAL_SYM_P): New. diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index c0c32de..38c805d 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20220924 +20220927 diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index fe048b8..db4ac0d 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,102 @@ +2022-09-26 Ghjuvan Lacambre <lacambre@adacore.com> + + * doc/gnat_rm/implementation_defined_attributes.rst: Rename Valid_Image. + * gnat_rm.texi: Regenerate. + * gnat_ugn.texi: Regenerate. + +2022-09-26 Piotr Trojanek <trojanek@adacore.com> + + * sem_ch12.adb (Build_Instance_Compilation_Unit_Nodes): Relocate + auxiliary declarations from the original compilation unit to the + newly created compilation unit for the spec. + +2022-09-26 Piotr Trojanek <trojanek@adacore.com> + + * rtsfind.ads + (RTU_Id): Remove unreferenced packages; fix whitespace. + (RE_Id): Remove unreferenced entities; add comment about entity + that is only used by GNATprove and not by GNAT. + +2022-09-26 Piotr Trojanek <trojanek@adacore.com> + + * s-oscons-tmplt.c (STR, STR1): Remove. + +2022-09-26 Eric Botcazou <ebotcazou@adacore.com> + + * doc/gnat_ugn/building_executable_programs_with_gnat.rst + (-gnateT): Document new parameter Long_Long_Long_Size. + * gnat_ugn.texi: Regenerate. + +2022-09-26 Steve Baird <baird@adacore.com> + + * bindgen.adb: When the binder is invoked for the device, specify + the CUDA_Global aspect for the adainit and adafinal procedures via + a pragma instead of via an aspect_specification. + +2022-09-26 Kévin Le Gouguec <legouguec@adacore.com> + + * doc/gnat_ugn/building_executable_programs_with_gnat.rst + (Linker Switches): Document support for mold along with gold; add some + advice regarding OpenSSL in the Pro version. + * gnat_ugn.texi: Regenerate. + +2022-09-26 Tucker Taft <taft@adacore.com> + + * sem_util.adb (Original_Aspect_Pragma_Name): Check for Check + pragmas. + +2022-09-26 Piotr Trojanek <trojanek@adacore.com> + + * sem_ch5.adb (Analyze_Iterator_Specification): Delay expansion + based on Full_Analysis flag. + +2022-09-26 Piotr Trojanek <trojanek@adacore.com> + + * sem_ch5.adb (Analyze_Iterator_Specification): Delay expansion of + for iterated component association just like it is done within + quantified expression. + +2022-09-26 Piotr Trojanek <trojanek@adacore.com> + + * contracts.adb (Analyze_Object_Contract): Check SPARK_Mode before + applying SPARK rule. + +2022-09-26 Justin Squirek <squirek@adacore.com> + + * sem_util.adb + (Accessibility_Level): Modify indexed and selected components case + by reducing the scope where Original_Node gets used. + +2022-09-26 Boris Yakobowski <yakobowski@adacore.com> + + * doc/gnat_ugn/gnat_utility_programs.rst: Remove documentation for + gnatmetric. + +2022-09-26 Piotr Trojanek <trojanek@adacore.com> + + * gsocket.h: Remove redefinition of _WIN32_WINNT. + * mingw32.h: Remove conditional definition of _WIN32_WINNT. + +2022-09-26 Piotr Trojanek <trojanek@adacore.com> + + * mingw32.h: Remove condition definition of MAXPATHLEN; the include + directive for stdlib.h was most likely intended to provide the + MAX_PATH. + +2022-09-26 Piotr Trojanek <trojanek@adacore.com> + + * adaint.c: Remove conditional #include directives for old MinGW. + * cal.c: Always include winsock.h, since it is part of modern + MinGW. + * cstreams.c: Remove workaround for old MinGW. + * expect.c: Remove conditional #include directive for old MinGW. + * mingw32.h: Remove STD_MINGW and OLD_MINGW declarations. + * sysdep.c: Remove conditional #include directive for old MinGW. + +2022-09-26 Piotr Trojanek <trojanek@adacore.com> + + * sem_warn.ads (Has_Junk_Name): Reword comment. + 2022-09-20 Martin Liska <mliska@suse.cz> * exp_ch6.adb: Replace "the the" with "the". @@ -66,7 +165,7 @@ 2022-09-12 Eric Botcazou <ebotcazou@adacore.com> - * contracts.adb (uild_Subprogram_Contract_Wrapper): Remove useless + * contracts.adb (Build_Subprogram_Contract_Wrapper): Remove useless local variable. In the case of a function, replace the extended return statement by a block statement declaring a renaming of the call to the local subprogram after removing side effects manually. @@ -1179,14 +1278,14 @@ 2022-09-02 Eric Botcazou <ebotcazou@adacore.com> - * exp_util.adb (Expand_Subtype_From_Expr): Be prepared for - rewritten aggregates as expressions. + * exp_util.adb (Expand_Subtype_From_Expr): Be prepared for rewritten + aggregates as expressions. 2022-09-02 Gary Dismukes <dismukes@adacore.com> - * exp_ch6.adb (Expand_Simple_Function_Return) Bypass creation of an actual - subtype and unchecked conversion to that subtype when the underlying type - of the expression has discriminants without defaults. + * exp_ch6.adb (Expand_Simple_Function_Return) Bypass creation of an + actual subtype and unchecked conversion to that subtype when the + underlying type of the expression has discriminants without defaults. 2022-09-02 Eric Botcazou <ebotcazou@adacore.com> diff --git a/gcc/ada/adaint.c b/gcc/ada/adaint.c index 2ae4ded..199dbe0 100644 --- a/gcc/ada/adaint.c +++ b/gcc/ada/adaint.c @@ -200,11 +200,7 @@ UINT __gnat_current_ccs_encoding; #endif /* wait.h processing */ -#ifdef __MINGW32__ -# if OLD_MINGW -# include <sys/wait.h> -# endif -#elif defined (__vxworks) && defined (__RTP__) +#if defined (__vxworks) && defined (__RTP__) # include <wait.h> #elif defined (__Lynx__) /* ??? We really need wait.h and it includes resource.h on Lynx. GCC @@ -214,7 +210,7 @@ UINT __gnat_current_ccs_encoding; preventing the inclusion of the GCC header from doing anything. */ # define GCC_RESOURCE_H # include <sys/wait.h> -#elif defined (__PikeOS__) +#elif defined (__PikeOS__) || defined (__MINGW32__) /* No wait() or waitpid() calls available. */ #else /* Default case. */ @@ -335,11 +331,6 @@ const char *__gnat_library_template = GNAT_LIBRARY_TEMPLATE; #if defined (__MINGW32__) #include "mingw32.h" - -#if OLD_MINGW -#include <sys/param.h> -#endif - #else #include <sys/param.h> #endif diff --git a/gcc/ada/bindgen.adb b/gcc/ada/bindgen.adb index b2fa44d..f2aaa2d 100644 --- a/gcc/ada/bindgen.adb +++ b/gcc/ada/bindgen.adb @@ -134,9 +134,6 @@ package body Bindgen is -- Text for aspect specifications (if any) given as part of the -- Adainit and Adafinal spec declarations. - function Aspect_Text return String is - (if Enable_CUDA_Device_Expansion then " with CUDA_Global" else ""); - ---------------------------------- -- Interface_State Pragma Table -- ---------------------------------- @@ -2644,10 +2641,11 @@ package body Bindgen is end if; WBI (""); - WBI (" procedure " & Ada_Init_Name.all & Aspect_Text & ";"); + WBI (" procedure " & Ada_Init_Name.all & ";"); if Enable_CUDA_Device_Expansion then WBI (" pragma Export (C, " & Ada_Init_Name.all & ", Link_Name => """ & Device_Ada_Init_Link_Name & """);"); + WBI (" pragma CUDA_Global (" & Ada_Init_Name.all & ");"); else WBI (" pragma Export (C, " & Ada_Init_Name.all & ", """ & Ada_Init_Name.all & """);"); @@ -2662,11 +2660,12 @@ package body Bindgen is if not Cumulative_Restrictions.Set (No_Finalization) then WBI (""); - WBI (" procedure " & Ada_Final_Name.all & Aspect_Text & ";"); + WBI (" procedure " & Ada_Final_Name.all & ";"); if Enable_CUDA_Device_Expansion then WBI (" pragma Export (C, " & Ada_Final_Name.all & ", Link_Name => """ & Device_Ada_Final_Link_Name & """);"); + WBI (" pragma CUDA_Global (" & Ada_Final_Name.all & ");"); else WBI (" pragma Export (C, " & Ada_Final_Name.all & ", """ & Ada_Final_Name.all & """);"); diff --git a/gcc/ada/cal.c b/gcc/ada/cal.c index e1ab692..09bcc15 100644 --- a/gcc/ada/cal.c +++ b/gcc/ada/cal.c @@ -53,10 +53,8 @@ #ifdef __MINGW32__ #include "mingw32.h" -#if STD_MINGW #include <winsock.h> #endif -#endif void __gnat_timeval_to_duration (struct timeval *t, long long *sec, long *usec) diff --git a/gcc/ada/contracts.adb b/gcc/ada/contracts.adb index 34db67a..dd573d3 100644 --- a/gcc/ada/contracts.adb +++ b/gcc/ada/contracts.adb @@ -1207,7 +1207,7 @@ package body Contracts is -- A Ghost object cannot be effectively volatile (SPARK RM 6.9(7) and -- SPARK RM 6.9(19)). - elsif Is_Effectively_Volatile (Obj_Id) then + elsif SPARK_Mode = On and then Is_Effectively_Volatile (Obj_Id) then Error_Msg_N ("ghost object & cannot be volatile", Obj_Id); -- A Ghost object cannot be imported or exported (SPARK RM 6.9(7)). diff --git a/gcc/ada/cstreams.c b/gcc/ada/cstreams.c index 10cc3a6..fc583e1 100644 --- a/gcc/ada/cstreams.c +++ b/gcc/ada/cstreams.c @@ -97,14 +97,6 @@ extern "C" { #undef fileno #endif -/* The _IONBF value in MINGW32 stdio.h is wrong. */ -#if defined (WINNT) || defined (_WINNT) -#if OLD_MINGW -#undef _IONBF -#define _IONBF 0004 -#endif -#endif - int __gnat_feof (FILE *stream) { diff --git a/gcc/ada/doc/gnat_rm/implementation_defined_attributes.rst b/gcc/ada/doc/gnat_rm/implementation_defined_attributes.rst index c25e3d4..d839b1f 100644 --- a/gcc/ada/doc/gnat_rm/implementation_defined_attributes.rst +++ b/gcc/ada/doc/gnat_rm/implementation_defined_attributes.rst @@ -1623,13 +1623,13 @@ Multi-dimensional arrays can be modified, as shown by this example: which changes element (1,2) to 20 and (3,4) to 30. -Attribute Valid_Image +Attribute Valid_Value ======================= -.. index:: Valid_Image +.. index:: Valid_Value -The ``'Valid_Image`` attribute is defined for enumeration types other than +The ``'Valid_Value`` attribute is defined for enumeration types other than those in package Standard. This attribute is a function that takes -a String, and returns Boolean. ``T'Valid_Image (S)`` returns True +a String, and returns Boolean. ``T'Valid_Value (S)`` returns True if and only if ``T'Value (S)`` would not raise Constraint_Error. Attribute Valid_Scalars diff --git a/gcc/ada/doc/gnat_ugn/building_executable_programs_with_gnat.rst b/gcc/ada/doc/gnat_ugn/building_executable_programs_with_gnat.rst index 6a47809..d4bddff 100644 --- a/gcc/ada/doc/gnat_ugn/building_executable_programs_with_gnat.rst +++ b/gcc/ada/doc/gnat_ugn/building_executable_programs_with_gnat.rst @@ -1719,6 +1719,7 @@ Alphabetical List of All Switches Float_Words_BE : Nat; -- Float words stored big-endian? Int_Size : Pos; -- Standard.Integer'Size Long_Double_Size : Pos; -- Standard.Long_Long_Float'Size + Long_Long_Long_Size : Pos; -- Standard.Long_Long_Long_Integer'Size Long_Long_Size : Pos; -- Standard.Long_Long_Integer'Size Long_Size : Pos; -- Standard.Long_Integer'Size Maximum_Alignment : Pos; -- Maximum permitted alignment @@ -1816,6 +1817,7 @@ Alphabetical List of All Switches Float_Words_BE 0 Int_Size 64 Long_Double_Size 128 + Long_Long_Long_Size 128 Long_Long_Size 64 Long_Size 64 Maximum_Alignment 16 @@ -6229,11 +6231,33 @@ Linker switches can be specified after :switch:`-largs` builder switch. .. index:: -fuse-ld=name :switch:`-fuse-ld={name}` - Linker to be used. The default is ``bfd`` for :file:`ld.bfd`, - the alternative being ``gold`` for :file:`ld.gold`. The later is - a more recent and faster linker, but only available on GNU/Linux + Linker to be used. The default is ``bfd`` for :file:`ld.bfd`; ``gold`` + (for :file:`ld.gold`) and ``mold`` (for :file:`ld.mold`) are more + recent and faster alternatives, but only available on GNU/Linux platforms. + .. only:: PRO + + The GNAT distribution for native Linux platforms includes ``mold``, + compiled against OpenSSL version 1.1; however, the distribution does + not include OpenSSL. In order to use this linker, you may either: + + * use your system's OpenSSL library, if the version matches: in this + situation, you need not do anything beside using the + :switch:`-fuse-ld=mold` switch, + + * obtain a source distribution for OpenSSL 1.1, compile the + :file:`libcrypto.so` library and install it in the directory of + your choice, then include this directory in the + :envvar:`LD_LIBRARY_PATH` environment variable, + + * install another copy of ``mold`` by other means in the directory + of your choice, and include this directory in the :envvar:`PATH` + environment variable; you may find this alternative preferable if + the copy of ``mold`` included in GNAT does not suit your needs + (e.g. being able to link against your system's OpenSSL, or using + another version of ``mold``). + .. _Binding_with_gnatbind: Binding with ``gnatbind`` diff --git a/gcc/ada/doc/gnat_ugn/gnat_utility_programs.rst b/gcc/ada/doc/gnat_ugn/gnat_utility_programs.rst index d670839..92877a2 100644 --- a/gcc/ada/doc/gnat_ugn/gnat_utility_programs.rst +++ b/gcc/ada/doc/gnat_ugn/gnat_utility_programs.rst @@ -15,7 +15,6 @@ This chapter describes a number of utility programs: * :ref:`The_File_Cleanup_Utility_gnatclean` * :ref:`The_GNAT_Library_Browser_gnatls` * :ref:`The_Coding_Standard_Verifier_gnatcheck` - * :ref:`The_GNAT_Metrics_Tool_gnatmetric` * :ref:`The_GNAT_Pretty_Printer_gnatpp` * :ref:`The_Body_Stub_Generator_gnatstub` * :ref:`The_Backtrace_Symbolizer_gnatsymbolize` @@ -487,1123 +486,6 @@ building specialized scripts. For full details, plese refer to :title:`GNATcheck Reference Manual`. - -.. only:: PRO or GPL - - .. _The_GNAT_Metrics_Tool_gnatmetric: - - The GNAT Metrics Tool ``gnatmetric`` - ==================================== - - .. index:: ! gnatmetric - .. index:: Metric tool - - The ``gnatmetric`` tool is a utility - for computing various program metrics. - It takes an Ada source file as input and generates a file containing the - metrics data as output. Various switches control which - metrics are reported. - - ``gnatmetric`` is a project-aware tool - (see :ref:`Using_Project_Files_with_GNAT_Tools` for a description of - the project-related switches). The project file package that can specify - ``gnatmetric`` switches is named ``Metrics``. - - The ``gnatmetric`` command has the form - - :: - - $ gnatmetric [ switches ] { filename } - - where: - - * ``switches`` specify the metrics to compute and define the destination for - the output - - * Each ``filename`` is the name of a source file to process. 'Wildcards' are - allowed, and the file name may contain path information. If no - ``filename`` is supplied, then the ``switches`` list must contain at least - one :switch:`--files` switch (see :ref:`Other_gnatmetric_Switches`). - Including both a :switch:`--files` switch and one or more ``filename`` - arguments is permitted. - - Note that it is no longer necessary to specify the Ada language version; - ``gnatmetric`` can process Ada source code written in any version from - Ada 83 onward without specifying any language version switch. - - The following subsections describe the various switches accepted by - ``gnatmetric``, organized by category. - - .. _Output_File_Control-gnatmetric: - - Output File Control - ------------------- - - .. index:: Output file control in gnatmetric - - ``gnatmetric`` has two output formats. It can generate a - textual (human-readable) form, and also XML. By default only textual - output is generated. - - When generating the output in textual form, ``gnatmetric`` creates - for each Ada source file a corresponding text file - containing the computed metrics, except for the case when the set of metrics - specified by gnatmetric parameters consists only of metrics that are computed - for the whole set of analyzed sources, but not for each Ada source. - By default, the name of the file containing metric information for a source - is obtained by appending the :file:`.metrix` suffix to the - name of the input source file. If not otherwise specified and no project file - is specified as ``gnatmetric`` option this file is placed in the same - directory as where the source file is located. If ``gnatmetric`` has a - project file as its parameter, it places all the generated files in the - object directory of the project (or in the project source directory if the - project does not define an object directory). If :switch:`--subdirs` option - is specified, the files are placed in the subrirectory of this directory - specified by this option. - - All the output information generated in XML format is placed in a single - file. By default the name of this file is :file:`metrix.xml`. - If not otherwise specified and if no project file is specified - as ``gnatmetric`` option this file is placed in the - current directory. - - Some of the computed metrics are summed over the units passed to - ``gnatmetric``; for example, the total number of lines of code. - By default this information is sent to :file:`stdout`, but a file - can be specified with the :switch:`--global-file-name` switch. - - The following switches control the ``gnatmetric`` output: - - .. index:: --generate-xml-output (gnatmetric) - - :switch:`--generate-xml-output` - Generate XML output. - - .. index:: --generate-xml-schema (gnatmetric) - - :switch:`--generate-xml-schema` - Generate XML output and an XML schema file that describes the structure - of the XML metric report. This schema is assigned to the XML file. The schema - file has the same name as the XML output file with :file:`.xml` suffix replaced - with :file:`.xsd`. - - .. index:: --no-text-output (gnatmetric) - - - :switch:`--no-text-output` - Do not generate the output in text form (implies :switch:`-x`). - - .. index:: --output-dir (gnatmetric) - - - :switch:`--output-dir={output_dir}` - Put text files with detailed metrics into ``output_dir``. - - .. index:: --output-suffix (gnatmetric) - - - :switch:`--output-suffix={file_suffix}` - Use ``file_suffix``, instead of :file:`.metrix` - in the name of the output file. - - .. index:: --global-file-name (gnatmetric) - - :switch:`--global-file-name={file_name}` - Put global metrics into ``file_name``. - - .. index:: --xml-file-name (gnatmetric) - - - :switch:`--xml-file-name={file_name}` - Put the XML output into ``file_name`` - (also implies :switch:`--generate-xml-output`). - - .. index:: --short-file-names (gnatmetric) - - :switch:`--short-file-names` - Use 'short' source file names in the output. (The ``gnatmetric`` - output includes the name(s) of the Ada source file(s) from which the - metrics are computed. By default each name includes the absolute - path. The :switch:`--short-file-names` switch causes ``gnatmetric`` - to exclude all directory information from the file names that are - output.) - - .. index:: --wide-character-encoding (gnatmetric) - - :switch:`--wide-character-encoding={e}` - Specify the wide character encoding method for the input and output - files. ``e`` is one of the following: - - * *8* - UTF-8 encoding - - * *b* - Brackets encoding (default value) - - - .. index:: Disable Metrics For Local Units in gnatmetric - - .. _Disable_Metrics_For_Local_Units: - - Disable Metrics For Local Units - ------------------------------- - - ``gnatmetric`` relies on the GNAT compilation model -- - one compilation - unit per one source file. It computes line metrics for the whole source - file, and it also computes syntax - and complexity metrics for the file's outermost unit. - - By default, ``gnatmetric`` will also compute all metrics for certain - kinds of locally declared program units: - - * subprogram (and generic subprogram) bodies; - - * package (and generic package) specs and bodies; - - * task object and type specifications and bodies; - - * protected object and type specifications and bodies. - - .. index:: Eligible local unit (for gnatmetric) - - These kinds of entities will be referred to as - *eligible local program units*, or simply *eligible local units*, - in the discussion below. - - Note that a subprogram declaration, generic instantiation, - or renaming declaration only receives metrics - computation when it appear as the outermost entity - in a source file. - - Suppression of metrics computation for eligible local units can be - obtained via the following switch: - - - .. index:: --no-local-metrics (gnatmetric) - - - :switch:`--no-local-metrics` - Do not compute detailed metrics for eligible local program units. - - - .. _Specifying_a_set_of_metrics_to_compute: - - Specifying a set of metrics to compute - -------------------------------------- - - By default all the metrics are reported. The switches described in this - subsection allow you to control, on an individual basis, whether metrics are - reported. If at least one positive metric switch is specified (that is, a - switch that defines that a given metric or set of metrics is to be computed), - then only explicitly specified metrics are reported. - - .. _Line_Metrics_Control: - - Line Metrics Control - ^^^^^^^^^^^^^^^^^^^^ - - .. index:: Line metrics control in gnatmetric - - For each source file, and for each of its eligible local program - units, ``gnatmetric`` computes the following metrics: - - * the total number of lines; - - * the total number of code lines (i.e., non-blank lines that are not - comments) - - * the number of comment lines - - * the number of code lines containing end-of-line comments; - - * the comment percentage: the ratio between the number of lines that - contain comments and the number of all non-blank lines, expressed as - a percentage - - * the number of empty lines and lines containing only space characters - and/or format effectors (blank lines) - - * the average number of code lines in subprogram bodies, task bodies, - entry bodies and statement sequences in package bodies - - ``gnatmetric`` sums the values of the line metrics for all the files - being processed and then generates the cumulative results. The tool - also computes for all the files being processed the average number of - code lines in bodies. - - You can use the following switches to select the specific line metrics - to be reported. - - - .. index:: --lines (gnatmetric) - .. index:: --no-lines (gnatmetric) - - - :switch:`--lines-all` - Report all the line metrics - - - :switch:`--no-lines-all` - Do not report any of line metrics - - - :switch:`--lines` - Report the number of all lines - - - :switch:`--no-lines` - Do not report the number of all lines - - - :switch:`--lines-code` - Report the number of code lines - - - :switch:`--no-lines-code` - Do not report the number of code lines - - - :switch:`--lines-comment` - Report the number of comment lines - - - :switch:`--no-lines-comment` - Do not report the number of comment lines - - - :switch:`--lines-eol-comment` - Report the number of code lines containing - end-of-line comments - - - :switch:`--no-lines-eol-comment` - Do not report the number of code lines containing - end-of-line comments - - - :switch:`--lines-ratio` - Report the comment percentage in the program text - - - :switch:`--no-lines-ratio` - Do not report the comment percentage in the program text - - - :switch:`--lines-blank` - Report the number of blank lines - - - :switch:`--no-lines-blank` - Do not report the number of blank lines - - - :switch:`--lines-average` - Report the average number of code lines in subprogram bodies, task bodies, - entry bodies and statement sequences in package bodies. - - - :switch:`--no-lines-average` - Do not report the average number of code lines in subprogram bodies, - task bodies, entry bodies and statement sequences in package bodies. - - - :switch:`--lines-spark` - Report the number of lines written in SPARK. - - - :switch:`--no-lines-spark` - Do not report the number of lines written in SPARK. - - - .. _Syntax_Metrics_Control: - - Syntax Metrics Control - ^^^^^^^^^^^^^^^^^^^^^^ - - .. index:: Syntax metrics control in gnatmetric - - ``gnatmetric`` computes various syntactic metrics for the - outermost unit and for each eligible local unit: - - * *LSLOC ('Logical Source Lines Of Code')* - The total number of declarations and the total number of - statements. Note that the definition of declarations is the one - given in the reference manual: - - "Each of the following is defined to be a declaration: any - basic_declaration; an enumeration_literal_specification; a - discriminant_specification; a component_declaration; a - loop_parameter_specification; a parameter_specification; a - subprogram_body; an entry_declaration; an - entry_index_specification; a choice_parameter_specification; a - generic_formal_parameter_declaration." - - This means for example that each enumeration literal adds one to - the count, as well as each subprogram parameter. - - * *Maximal static nesting level of inner program units* - According to :title:`Ada Reference Manual`, 10.1(1): - - "A program unit is either a package, a task unit, a protected - unit, a protected entry, a generic unit, or an explicitly - declared subprogram other than an enumeration literal." - - * *Maximal nesting level of composite syntactic constructs* - This corresponds to the notion of the maximum nesting level in the - GNAT built-in style checks (see :ref:`Style_Checking`). - - * *Number of formal parameters* - Number of formal parameters of a subprogram; if a subprogram does - have parameters, then numbers of "in", "out" and "in out" - parameters are also reported. This metric is reported for - subprogram specifications and for subprogram instantiations. For - subprogram bodies, expression functions and null procedures this - metric is reported if the construct acts as a subprogram - declaration but is not a completion of previous declaration. This - metric is not reported for generic and formal subprograms. - - For the outermost unit in the file, ``gnatmetric`` additionally - computes the following metrics: - - * *Public subprograms* - This metric is computed for package specs. It is the number of - subprograms and generic subprograms declared in the visible part - (including the visible part of nested packages, protected objects, - and protected types). - - - * *All subprograms* - This metric is computed for bodies and subunits. The metric is - equal to a total number of subprogram bodies in the compilation - unit. - Neither generic instantiations nor renamings-as-a-body nor body - stubs are counted. Any subprogram body is counted, independently - of its nesting level and enclosing constructs. Generic bodies and - bodies of protected subprograms are counted in the same way as - 'usual' subprogram bodies. - - - * *Public types* - This metric is computed for package specs and generic package - declarations. It is the total number of types that can be - referenced from outside this compilation unit, plus the number of - types from all the visible parts of all the visible generic - packages. Generic formal types are not counted. Only types, not - subtypes, are included. - - Along with the total number of public types, the following - types are counted and reported separately: - - * *Abstract types* - - * *Root tagged types^ (abstract, non-abstract, private, - non-private). Type extensions are *not* counted - - * *Private types* (including private extensions) - - * *Task types* - - * *Protected types* - - * *All types* - This metric is computed for any compilation unit. It is equal to - the total number of the declarations of different types given in - the compilation unit. The private and the corresponding full type - declaration are counted as one type declaration. Incomplete type - declarations and generic formal types are not counted. - No distinction is made among different kinds of types (abstract, - private etc.); the total number of types is reported. - - By default, all the syntax metrics are reported. You can use the following - switches to select specific syntax metrics. - - - .. index:: --syntax (gnatmetric) - .. index:: --no-syntax (gnatmetric) - - - :switch:`--syntax-all` - Report all the syntax metrics - - - :switch:`--no-syntax-all` - Do not report any of syntax metrics - - - :switch:`--declarations` - Report the total number of declarations - - - :switch:`--no-declarations` - Do not report the total number of declarations - - - :switch:`--statements` - Report the total number of statements - - - :switch:`--no-statements` - Do not report the total number of statements - - - :switch:`--public-subprograms` - Report the number of public subprograms in a compilation unit - - - :switch:`--no-public-subprograms` - Do not report the number of public subprograms in a compilation unit - - - :switch:`--all-subprograms` - Report the number of all the subprograms in a compilation unit - - - :switch:`--no-all-subprograms` - Do not report the number of all the subprograms in a compilation unit - - - :switch:`--public-types` - Report the number of public types in a compilation unit - - - :switch:`--no-public-types` - Do not report the number of public types in a compilation unit - - - :switch:`--all-types` - Report the number of all the types in a compilation unit - - - :switch:`--no-all-types` - Do not report the number of all the types in a compilation unit - - - :switch:`--unit-nesting` - Report the maximal program unit nesting level - - - :switch:`--no-unit-nesting` - Do not report the maximal program unit nesting level - - - :switch:`--construct-nesting` - Report the maximal construct nesting level - - - :switch:`--no-construct-nesting` - Do not report the maximal construct nesting level - - :switch:`--param-number` - Report the number of subprogram parameters - - - :switch:`--no-param-number` - Do not report the number of subprogram parameters - - - .. _Contract_Metrics_Control: - - Contract Metrics Control - ^^^^^^^^^^^^^^^^^^^^^^^^ - - .. index:: Contract metrics control in gnatmetric - - :switch:`--contract-all` - Report all the contract metrics - - - :switch:`--no-contract-all` - Do not report any of the contract metrics - - - :switch:`--contract` - Report the number of public subprograms with contracts - - - :switch:`--no-contract` - Do not report the number of public subprograms with contracts - - - :switch:`--post` - Report the number of public subprograms with postconditions - - - :switch:`--no-post` - Do not report the number of public subprograms with postconditions - - - :switch:`--contract-complete` - Report the number of public subprograms with complete contracts - - - :switch:`--no-contract-complete` - Do not report the number of public subprograms with complete contracts - - - :switch:`--contract-cyclomatic` - Report the McCabe complexity of public subprograms - - - :switch:`--no-contract-cyclomatic` - Do not report the McCabe complexity of public subprograms - - - .. _Complexity_Metrics_Control: - - Complexity Metrics Control - ^^^^^^^^^^^^^^^^^^^^^^^^^^ - - .. index:: Complexity metrics control in gnatmetric - - For a program unit that is an executable body (a subprogram body - (including generic bodies), task body, entry body or a package body - containing its own statement sequence) ``gnatmetric`` computes the - following complexity metrics: - - * McCabe cyclomatic complexity; - - * McCabe essential complexity; - - * maximal loop nesting level; - - * extra exit points (for subprograms); - - The McCabe cyclomatic complexity metric is defined - in `http://www.mccabe.com/pdf/mccabe-nist235r.pdf <http://www.mccabe.com/pdf/mccabe-nist235r.pdf>`_ - - According to McCabe, both control statements and short-circuit control - forms should be taken into account when computing cyclomatic - complexity. For Ada 2012 we have also take into account conditional - expressions and quantified expressions. For each body, we compute - three metric values: - - * the complexity introduced by control - statements only, without taking into account short-circuit forms - (referred as ``statement complexity`` in ``gnatmetric`` output), - - * the complexity introduced by short-circuit control forms only - (referred as ``expression complexity`` in ``gnatmetric`` output), - and - - * the total - cyclomatic complexity, which is the sum of these two values - (referred as ``cyclomatic complexity`` in ``gnatmetric`` output). - - The cyclomatic complexity is also computed for Ada 2012 expression functions. - An expression function cannot have statements as its components, so only one - metric value is computed as a cyclomatic complexity of an expression function. - - The origin of cyclomatic complexity metric is the need to estimate the number - of independent paths in the control flow graph that in turn gives the number - of tests needed to satisfy paths coverage testing completeness criterion. - Considered from the testing point of view, a static Ada ``loop`` (that is, - the ``loop`` statement having static subtype in loop parameter - specification) does not add to cyclomatic complexity. By providing - :switch:`--no-static-loop` option a user - may specify that such loops should not be counted when computing the - cyclomatic complexity metric - - The Ada essential complexity metric is a McCabe cyclomatic complexity metric - counted for the code that is reduced by excluding all the pure structural Ada - control statements. An compound statement is considered as a non-structural - if it contains a ``raise`` or ``return`` statement as it subcomponent, - or if it contains a ``goto`` statement that transfers the control outside - the operator. A selective ``accept`` statement with a ``terminate`` alternative - is considered a non-structural statement. When computing this metric, - ``exit`` statements are treated in the same way as ``goto`` - statements unless the :switch:`-ne` option is specified. - - The Ada essential complexity metric defined here is intended to quantify - the extent to which the software is unstructured. It is adapted from - the McCabe essential complexity metric defined in - http://www.mccabe.com/pdf/mccabe-nist235r.pdf - but is modified to be more - suitable for typical Ada usage. For example, short circuit forms - are not penalized as unstructured in the Ada essential complexity metric. - - When computing cyclomatic and essential complexity, ``gnatmetric`` skips - the code in the exception handlers and in all the nested program units. The - code of assertions and predicates (that is, subprogram preconditions and - postconditions, subtype predicates and type invariants) is also skipped. - - By default, all the complexity metrics are reported. For more fine-grained - control you can use the following switches: - - - .. index:: --complexity (gnatmetric) - .. index:: --no-complexity (gnatmetric) - - - :switch:`--complexity-all` - Report all the complexity metrics - - - :switch:`--no-complexity-all` - Do not report any of the complexity metrics - - - :switch:`--complexity-cyclomatic` - Report the McCabe Cyclomatic Complexity - - - :switch:`--no-complexity-cyclomatic` - Do not report the McCabe Cyclomatic Complexity - - - :switch:`--complexity-essential` - Report the Essential Complexity - - - :switch:`--no-complexity-essential` - Do not report the Essential Complexity - - - :switch:`--loop-nesting` - Report maximal loop nesting level - - - :switch:`--no-loop-nesting` - Do not report maximal loop nesting level - - - :switch:`--complexity-average` - Report the average McCabe Cyclomatic Complexity for all the subprogram bodies, - task bodies, entry bodies and statement sequences in package bodies. - The metric is reported for whole set of processed Ada sources only. - - - :switch:`--no-complexity-average` - Do not report the average McCabe Cyclomatic Complexity for all the subprogram - bodies, task bodies, entry bodies and statement sequences in package bodies - - .. index:: --no-treat-exit-as-goto (gnatmetric) - - - :switch:`--no-treat-exit-as-goto` - Do not consider ``exit`` statements as ``goto``\ s when - computing Essential Complexity - - .. index:: --no-static-loop (gnatmetric) - - - :switch:`--no-static-loop` - Do not consider static loops when computing cyclomatic complexity - - - :switch:`--extra-exit-points` - Report the extra exit points for subprogram bodies. As an exit point, this - metric counts ``return`` statements and raise statements in case when the - raised exception is not handled in the same body. In case of a function this - metric subtracts 1 from the number of exit points, because a function body - must contain at least one ``return`` statement. - - - :switch:`--no-extra-exit-points` - Do not report the extra exit points for subprogram bodies - - - .. _Coupling_Metrics_Control: - - Coupling Metrics Control - ^^^^^^^^^^^^^^^^^^^^^^^^ - - .. index:: Coupling metrics control in gnatmetric - - .. index:: Coupling metrics (in gnatmetric) - - Coupling metrics measure the dependencies between a given entity and other - entities in the program. This information is useful since high coupling - may signal potential issues with maintainability as the program evolves. - - ``gnatmetric`` computes the following coupling metrics: - - - * *object-oriented coupling*, for classes in traditional object-oriented - sense; - - * *unit coupling*, for all the program units making up a program; - - * *control coupling*, reflecting dependencies between a unit and - other units that contain subprograms. - - .. index:: fan-out coupling - .. index:: efferent coupling - - Two kinds of coupling metrics are computed: - - * fan-out coupling ('efferent coupling'): - the number of entities the given entity depends upon. This metric - reflects how the given entity depends on the changes in the - 'external world'. - - .. index:: fan-in coupling - .. index:: afferent coupling - - * fan-in coupling ('afferent' coupling): - the number of entities that depend on a given entity. - This metric reflects how the 'external world' depends on the changes in a - given entity. - - Object-oriented coupling metrics measure the dependencies - between a given class (or a group of classes) and the other classes in the - program. In this subsection the term 'class' is used in its traditional - object-oriented programming sense (an instantiable module that contains data - and/or method members). A *category* (of classes) is a group of closely - related classes that are reused and/or modified together. - - A class ``K``\ 's fan-out coupling is the number of classes - that ``K`` depends upon. - A category's fan-out coupling is the number of classes outside the - category that the classes inside the category depend upon. - - A class ``K``\ 's fan-in coupling is the number of classes - that depend upon ``K``. - A category's fan-in coupling is the number of classes outside the - category that depend on classes belonging to the category. - - Ada's object-oriented paradigm separates the instantiable entity - (type) from the module (package), so the definition of the coupling - metrics for Ada maps the class and class category notions - onto Ada constructs. - - For the coupling metrics, several kinds of modules that define a tagged type - or an interface type -- library packages, library generic packages, and - library generic package instantiations -- are considered to be classes. - A category consists of a library package (or - a library generic package) that defines a tagged or an interface type, - together with all its descendant (generic) packages that define tagged - or interface types. Thus a - category is an Ada hierarchy of library-level program units. Class - coupling in Ada is referred to as 'tagged coupling', and category coupling - is referred to as 'hierarchy coupling'. - - For any package serving as a class, its body and subunits (if any) are - considered together with its spec when computing dependencies, and coupling - metrics are reported for spec units only. Dependencies between classes - mean Ada semantic dependencies. For object-oriented coupling - metrics, only dependencies on units treated as classes are - considered. - - Similarly, for unit and control coupling an entity is considered to be the - conceptual construct consisting of the entity's specification, body, and - any subunits (transitively). - ``gnatmetric`` computes - the dependencies of all these units as a whole, but - metrics are only reported for spec - units (or for a subprogram body unit in case if there is no - separate spec for the given subprogram). - - For unit coupling, dependencies are computed between all kinds of program - units. For control coupling, the dependencies of a given unit are limited to - those units that define subprograms. Thus control fan-out coupling is reported - for all units, but control fan-in coupling is only reported for units - that define subprograms. - - The following simple example illustrates the difference between unit coupling - and control coupling metrics: - - .. code-block:: ada - - package Lib_1 is - function F_1 (I : Integer) return Integer; - end Lib_1; - - package Lib_2 is - type T_2 is new Integer; - end Lib_2; - - package body Lib_1 is - function F_1 (I : Integer) return Integer is - begin - return I + 1; - end F_1; - end Lib_1; - - with Lib_2; use Lib_2; - package Pack is - Var : T_2; - function Fun (I : Integer) return Integer; - end Pack; - - with Lib_1; use Lib_1; - package body Pack is - function Fun (I : Integer) return Integer is - begin - return F_1 (I); - end Fun; - end Pack; - - If we apply ``gnatmetric`` with the :switch:`--coupling-all` option to - these units, the result will be: - - :: - - Coupling metrics: - ================= - Unit Lib_1 (C:\\customers\\662\\L406-007\\lib_1.ads) - control fan-out coupling : 0 - control fan-in coupling : 1 - unit fan-out coupling : 0 - unit fan-in coupling : 1 - - Unit Pack (C:\\customers\\662\\L406-007\\pack.ads) - control fan-out coupling : 1 - control fan-in coupling : 0 - unit fan-out coupling : 2 - unit fan-in coupling : 0 - - Unit Lib_2 (C:\\customers\\662\\L406-007\\lib_2.ads) - control fan-out coupling : 0 - unit fan-out coupling : 0 - unit fan-in coupling : 1 - - The result does not contain values for object-oriented - coupling because none of the argument units contains a tagged type and - therefore none of these units can be treated as a class. - - The ``Pack`` package (spec and body) depends on two - units -- ``Lib_1`` and ``Lib_2`` -- and so its unit fan-out coupling - is 2. Since nothing depends on it, its unit fan-in coupling is 0, as - is its control fan-in coupling. Only one of the units ``Pack`` depends - upon defines a subprogram, so its control fan-out coupling is 1. - - ``Lib_2`` depends on nothing, so its fan-out metrics are 0. It does - not define any subprograms, so it has no control fan-in metric. - One unit (``Pack``) depends on it , so its unit fan-in coupling is 1. - - ``Lib_1`` is similar to ``Lib_2``, but it does define a subprogram. - Its control fan-in coupling is 1 (because there is one unit - depending on it). - - When computing coupling metrics, ``gnatmetric`` counts only - dependencies between units that are arguments of the ``gnatmetric`` - invocation. Coupling metrics are program-wide (or project-wide) metrics, so - you should invoke ``gnatmetric`` for - the complete set of sources comprising your program. This can be done - by invoking ``gnatmetric`` with the corresponding project file - and with the :switch:`-U` option. - - By default, all the coupling metrics are reported. You can use the following - switches to select specific syntax metrics. - - .. index:: --tagged-coupling (gnatmetric) - .. index:: --hierarchy-coupling (gnatmetric) - .. index:: --unit-coupling (gnatmetric) - .. index:: --control-coupling (gnatmetric) - - :switch:`--coupling-all` - Report all the coupling metrics - - - :switch:`--tagged-coupling-out` - Report tagged (class) fan-out coupling - - - :switch:`--tagged-coupling-in` - Report tagged (class) fan-in coupling - - - :switch:`--hierarchy-coupling-out` - Report hierarchy (category) fan-out coupling - - - :switch:`--hierarchy-coupling-in` - Report hierarchy (category) fan-in coupling - - - :switch:`--unit-coupling-out` - Report unit fan-out coupling - - - :switch:`--unit-coupling-in` - Report unit fan-in coupling - - - :switch:`--control-coupling-out` - Report control fan-out coupling - - - :switch:`--control-coupling-in` - Report control fan-in coupling - - - .. _Other_gnatmetric_Switches: - - Other ``gnatmetric`` Switches - ----------------------------- - - Additional ``gnatmetric`` switches are as follows: - - - .. index:: --version (gnatmetric) - - :switch:`--version` - Display copyright and version, then exit disregarding all other options. - - - .. index:: --help (gnatmetric) - - :switch:`--help` - Display usage, then exit disregarding all other options. - - - .. index:: -P (gnatmetric) - - :switch:`-P {file}` - Indicates the name of the project file that describes the set of sources - to be processed. The exact set of argument sources depends on other options - specified, see below. An aggregate project is allowed as the file parameter - only if it has exactly one non-aggregate project being aggregated. - - - .. index:: -U (gnatmetric) - - :switch:`-U` - If a project file is specified and no argument source is explicitly - specified (either directly or by means of :switch:`-files` option), process - all the units of the closure of the argument project. Otherwise this option - has no effect. - - - :switch:`-U {main_unit}` - If a project file is specified and no argument source is explicitly - specified (either directly or by means of :switch:`-files` option), process - the closure of units rooted at ``main_unit``. Otherwise this option - has no effect. - - - .. index:: -X (gnatmetric) - - :switch:`-X{name}={value}` - Indicates that external variable ``name`` in the argument project - has the value ``value``. Has no effect if no project is specified. - - - .. index:: --RTS (gnatmetric) - - :switch:`--RTS={rts-path}` - Specifies the default location of the runtime library. Same meaning as the - equivalent ``gnatmake`` flag (see :ref:`Switches_for_gnatmake`). - - - .. index:: --subdirs=dir (gnatmetric) - - :switch:`--subdirs={dir}` - Use the specified subdirectory of the project objects file (or of the - project file directory if the project does not specify an object directory) - for tool output files. Has no effect if no project is specified as - tool argument r if :switch:`--no-objects-dir` is specified. - - - .. index:: --files (gnatmetric) - - :switch:`--files={file}` - Take as arguments the files listed in text file ``file``. - Text file ``file`` may contain empty lines that are ignored. - Each nonempty line should contain the name of an existing file. - Several such switches may be specified simultaneously. - - - .. index:: --ignore (gnatmetric) - - :switch:`--ignore={filename}` - Do not process the sources listed in a specified file. - - - .. index:: --verbose (gnatmetric) - - :switch:`--verbose` - Verbose mode; - ``gnatmetric`` generates version information and then - a trace of sources being processed. - - - .. index:: --quiet (gnatmetric) - - :switch:`--quiet` - Quiet mode. - - If a project file is specified and no argument source is explicitly - specified (either directly or by means of :switch:`-files` option), and no - :switch:`-U` is specified, then the set of processed sources is - all the immediate units of the argument project. - - - Legacy Switches - ^^^^^^^^^^^^^^^ - - Some switches have a short form, mostly for legacy reasons, - as shown below. - - .. index:: -x (gnatmetric) - - :switch:`-x` - :switch:`--generate-xml-output` - - .. index:: -xs (gnatmetric) - - :switch:`-xs` - :switch:`--generate-xml-schema` - - .. index:: -nt (gnatmetric) - - :switch:`-nt` - :switch:`--no-text-output` - - .. index:: -d (gnatmetric) - - :switch:`-d {output-dir}` - :switch:`--output-dir` - - .. index:: -o (gnatmetric) - - :switch:`-o {file-suffix}` - :switch:`--output-suffix` - - .. index:: -og (gnatmetric) - - :switch:`-og {file-name}` - :switch:`--global-file-name` - - .. index:: -ox (gnatmetric) - - :switch:`-ox {file-name}` - :switch:`--xml-file-name` - - .. index:: -sfn (gnatmetric) - - :switch:`-sfn` - :switch:`--short-file-names` - - .. index:: -W (gnatsmetric) - - :switch:`-W{e}` - :switch:`--wide-character-encoding={e}` - - .. index:: -nolocal (gnatmetric) - - :switch:`-nolocal` - :switch:`--no-local-metrics` - - .. index:: -ne (gnatmetric) - - :switch:`-ne` - :switch:`--no-treat-exit-as-goto` - - .. index:: -files (gnatmetric) - - :switch:`-files {filename}` - :switch:`--files` - - .. index:: -v (gnatmetric) - - :switch:`-v` - :switch:`--verbose` - - .. index:: -q (gnatmetric) - - :switch:`-q` - :switch:`--quiet` - .. only:: PRO or GPL .. _The_GNAT_Pretty_Printer_gnatpp: @@ -3026,7 +1908,7 @@ building specialized scripts. naming conventions. Note that it is no longer necessary to specify the Ada language version; - ``gnatmetric`` can process Ada source code written in any version from + ``gnatstub`` can process Ada source code written in any version from Ada 83 onward without specifying any language version switch. * *switches* diff --git a/gcc/ada/expect.c b/gcc/ada/expect.c index b1889fe..48fb107 100644 --- a/gcc/ada/expect.c +++ b/gcc/ada/expect.c @@ -42,17 +42,13 @@ #include "adaint.h" #include <sys/types.h> -#ifdef __MINGW32__ -# if OLD_MINGW -# include <sys/wait.h> -# endif -#elif defined (__vxworks) && defined (__RTP__) +#if defined (__vxworks) && defined (__RTP__) # include <wait.h> #elif defined (__Lynx__) /* ??? See comment in adaint.c. */ # define GCC_RESOURCE_H # include <sys/wait.h> -#elif defined (__PikeOS__) +#elif defined (__PikeOS__) || defined (__MINGW32__) /* No wait.h available */ #else #include <sys/wait.h> diff --git a/gcc/ada/gnat_rm.texi b/gcc/ada/gnat_rm.texi index cdf8605..64f2e79 100644 --- a/gcc/ada/gnat_rm.texi +++ b/gcc/ada/gnat_rm.texi @@ -19,7 +19,7 @@ @copying @quotation -GNAT Reference Manual , Sep 09, 2022 +GNAT Reference Manual , Sep 23, 2022 AdaCore @@ -433,7 +433,7 @@ Implementation Defined Attributes * Attribute Universal_Literal_String:: * Attribute Unrestricted_Access:: * Attribute Update:: -* Attribute Valid_Image:: +* Attribute Valid_Value:: * Attribute Valid_Scalars:: * Attribute VADS_Size:: * Attribute Value_Size:: @@ -10295,7 +10295,7 @@ consideration, you should minimize the use of these attributes. * Attribute Universal_Literal_String:: * Attribute Unrestricted_Access:: * Attribute Update:: -* Attribute Valid_Image:: +* Attribute Valid_Value:: * Attribute Valid_Scalars:: * Attribute VADS_Size:: * Attribute Value_Size:: @@ -12040,7 +12040,7 @@ In general this is a risky approach. It may appear to “work” but such uses o @code{Unrestricted_Access} are potentially non-portable, even from one version of GNAT to another, so are best avoided if possible. -@node Attribute Update,Attribute Valid_Image,Attribute Unrestricted_Access,Implementation Defined Attributes +@node Attribute Update,Attribute Valid_Value,Attribute Unrestricted_Access,Implementation Defined Attributes @anchor{gnat_rm/implementation_defined_attributes attribute-update}@anchor{1ac} @section Attribute Update @@ -12121,19 +12121,19 @@ A := A'Update ((1, 2) => 20, (3, 4) => 30); which changes element (1,2) to 20 and (3,4) to 30. -@node Attribute Valid_Image,Attribute Valid_Scalars,Attribute Update,Implementation Defined Attributes -@anchor{gnat_rm/implementation_defined_attributes attribute-valid-image}@anchor{1ad} -@section Attribute Valid_Image +@node Attribute Valid_Value,Attribute Valid_Scalars,Attribute Update,Implementation Defined Attributes +@anchor{gnat_rm/implementation_defined_attributes attribute-valid-value}@anchor{1ad} +@section Attribute Valid_Value -@geindex Valid_Image +@geindex Valid_Value -The @code{'Valid_Image} attribute is defined for enumeration types other than +The @code{'Valid_Value} attribute is defined for enumeration types other than those in package Standard. This attribute is a function that takes -a String, and returns Boolean. @code{T'Valid_Image (S)} returns True +a String, and returns Boolean. @code{T'Valid_Value (S)} returns True if and only if @code{T'Value (S)} would not raise Constraint_Error. -@node Attribute Valid_Scalars,Attribute VADS_Size,Attribute Valid_Image,Implementation Defined Attributes +@node Attribute Valid_Scalars,Attribute VADS_Size,Attribute Valid_Value,Implementation Defined Attributes @anchor{gnat_rm/implementation_defined_attributes attribute-valid-scalars}@anchor{1ae} @section Attribute Valid_Scalars diff --git a/gcc/ada/gnat_ugn.texi b/gcc/ada/gnat_ugn.texi index f2cb1ed..7d96dbe 100644 --- a/gcc/ada/gnat_ugn.texi +++ b/gcc/ada/gnat_ugn.texi @@ -19,7 +19,7 @@ @copying @quotation -GNAT User's Guide for Native Platforms , Sep 09, 2022 +GNAT User's Guide for Native Platforms , Sep 26, 2022 AdaCore @@ -9220,6 +9220,7 @@ Float_Size : Pos; -- Standard.Float'Size Float_Words_BE : Nat; -- Float words stored big-endian? Int_Size : Pos; -- Standard.Integer'Size Long_Double_Size : Pos; -- Standard.Long_Long_Float'Size +Long_Long_Long_Size : Pos; -- Standard.Long_Long_Long_Integer'Size Long_Long_Size : Pos; -- Standard.Long_Long_Integer'Size Long_Size : Pos; -- Standard.Long_Integer'Size Maximum_Alignment : Pos; -- Maximum permitted alignment @@ -9307,6 +9308,7 @@ Float_Size 32 Float_Words_BE 0 Int_Size 64 Long_Double_Size 128 +Long_Long_Long_Size 128 Long_Long_Size 64 Long_Size 64 Maximum_Alignment 16 @@ -15317,10 +15319,11 @@ Linker switches can be specified after @code{-largs} builder switch. @item @code{-fuse-ld=`name'} -Linker to be used. The default is @code{bfd} for @code{ld.bfd}, -the alternative being @code{gold} for @code{ld.gold}. The later is -a more recent and faster linker, but only available on GNU/Linux +Linker to be used. The default is @code{bfd} for @code{ld.bfd}; @code{gold} +(for @code{ld.gold}) and @code{mold} (for @code{ld.mold}) are more +recent and faster alternatives, but only available on GNU/Linux platforms. + @end table @node Binding with gnatbind,Linking with gnatlink,Linker Switches,Building Executable Programs with GNAT @@ -17932,7 +17935,6 @@ instr.ads - @c -- Example: A |withing| unit has a |with| clause, it |withs| a |withed| unit @node GNAT and Program Execution,Platform-Specific Information,GNAT Utility Programs,Top diff --git a/gcc/ada/gsocket.h b/gcc/ada/gsocket.h index e7284a1..561f2ff 100644 --- a/gcc/ada/gsocket.h +++ b/gcc/ada/gsocket.h @@ -80,12 +80,6 @@ #define FD_SETSIZE 1024 #ifdef __MINGW32__ -/* winsock2.h allows WSAPoll related definitions only when - * _WIN32_WINNT >= 0x0600 */ -#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600 -#define _WIN32_WINNT 0x0600 -#endif - #include <winsock2.h> #include <ws2tcpip.h> #include <versionhelpers.h> diff --git a/gcc/ada/mingw32.h b/gcc/ada/mingw32.h index 1157fc6..d038211 100644 --- a/gcc/ada/mingw32.h +++ b/gcc/ada/mingw32.h @@ -44,11 +44,6 @@ #define UNICODE /* For Win32 API */ #endif -/* We need functionality available only starting with Windows XP */ -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0501 -#endif - #ifndef __CYGWIN__ #include <tchar.h> #endif @@ -99,27 +94,4 @@ extern UINT __gnat_current_ccs_encoding; #define WS2S(str,wstr,len) strncpy(str,wstr,len) #endif -#include <stdlib.h> - -/* STD_MINGW: standard if MINGW32 version > 1.3, we have switched to this - version instead of the previous enhanced version to ease building GNAT on - Windows platforms. By using STD_MINGW or OLD_MINGW it is possible to build - GNAT using both MingW include files (Old MingW + ACT changes and standard - MingW starting with version 1.3. - For w64 Mingw the define STD_MINGW is always set to value 1, because - there is no old header set present. */ -#ifdef _WIN64 -#define STD_MINGW 1 -#else -#define STD_MINGW ((__MINGW32_MAJOR_VERSION == 1 \ - && __MINGW32_MINOR_VERSION >= 3) \ - || (__MINGW32_MAJOR_VERSION >= 2)) -#endif - -#define OLD_MINGW (!(STD_MINGW)) - -#ifndef MAXPATHLEN -#define MAXPATHLEN MAX_PATH -#endif - #endif /* _MINGW32_H */ diff --git a/gcc/ada/rtsfind.ads b/gcc/ada/rtsfind.ads index 65c6409..24aca2c 100644 --- a/gcc/ada/rtsfind.ads +++ b/gcc/ada/rtsfind.ads @@ -189,7 +189,6 @@ package Rtsfind is -- Children of Interfaces Interfaces_C, - Interfaces_Packed_Decimal, -- Children of Interfaces.C @@ -205,7 +204,6 @@ package Rtsfind is System_Address_To_Access_Conversions, System_Arith_64, System_Arith_128, - System_AST_Handling, System_Assertions, System_Atomic_Operations, System_Atomic_Primitives, @@ -257,9 +255,6 @@ package Rtsfind is System_Fat_LFlt, System_Fat_LLF, System_Fat_SFlt, - System_Fat_VAX_D_Float, - System_Fat_VAX_F_Float, - System_Fat_VAX_G_Float, System_Finalization_Masters, System_Finalization_Root, System_Fore_Decimal_32, @@ -288,14 +283,12 @@ package Rtsfind is System_Img_LLLI, System_Img_LLU, System_Img_LLLU, - System_Img_Name, System_Img_Uns, System_Img_WChar, System_Interrupts, System_Long_Long_Float_Expon, System_Machine_Code, System_Mantissa, - System_Memcop, System_Memory, System_Multiprocessors, System_Pack_03, @@ -420,10 +413,7 @@ package Rtsfind is System_Pack_127, System_Parameters, System_Partition_Interface, - System_Pool_32_Global, System_Pool_Global, - System_Pool_Empty, - System_Pool_Local, System_Pool_Size, System_Put_Images, System_Put_Task_Images, @@ -440,7 +430,6 @@ package Rtsfind is System_Stream_Attributes, System_Task_Info, System_Tasking, - System_Threads, System_Unsigned_Types, System_Val_Bool, System_Val_Char, @@ -461,7 +450,6 @@ package Rtsfind is System_Val_LLLI, System_Val_LLU, System_Val_LLLU, - System_Val_Name, System_Val_Uns, System_Val_WChar, System_Version_Control, @@ -475,7 +463,6 @@ package Rtsfind is System_Wid_LLLI, System_Wid_LLU, System_Wid_LLLU, - System_Wid_Name, System_Wid_Uns, System_Wid_WChar, System_WWd_Char, @@ -484,7 +471,7 @@ package Rtsfind is -- Children of System.Atomic_Operations - System_Atomic_Operations_Test_And_Set, + System_Atomic_Operations_Test_And_Set, -- Children of System.Dim @@ -561,17 +548,13 @@ package Rtsfind is RE_Set_Deadline, -- Ada.Dispatching.EDF - RE_Code_Loc, -- Ada.Exceptions RE_Exception_Id, -- Ada.Exceptions - RE_Exception_Identity, -- Ada.Exceptions RE_Exception_Information, -- Ada.Exceptions RE_Exception_Message, -- Ada.Exceptions RE_Exception_Name_Simple, -- Ada.Exceptions RE_Exception_Occurrence, -- Ada.Exceptions - RE_Exception_Occurrence_Access, -- Ada.Exceptions RE_Null_Id, -- Ada.Exceptions RE_Null_Occurrence, -- Ada.Exceptions - RE_Poll, -- Ada.Exceptions RE_Raise_Exception, -- Ada.Exceptions RE_Raise_Exception_Always, -- Ada.Exceptions RE_Raise_From_Controlled_Operation, -- Ada.Exceptions @@ -596,7 +579,7 @@ package Rtsfind is RE_Names, -- Ada.Interrupts.Names RE_Clock, -- Ada.Real_Time - RE_Clock_Time, -- Ada.Real_Time + RE_Clock_Time, -- Ada.Real_Time [used by GNATprove] RE_Time_Span, -- Ada.Real_Time RE_Time_Span_Zero, -- Ada.Real_Time RO_RT_Time, -- Ada.Real_Time @@ -612,8 +595,6 @@ package Rtsfind is RE_Stream_Element_Array, -- Ada.Streams RE_Stream_Element_Offset, -- Ada.Streams - RE_Stream_Access, -- Ada.Streams.Stream_IO - RO_SU_Super_String, -- Ada.Strings.Superbounded RO_WI_Super_String, -- Ada.Strings.Wide_Superbounded @@ -628,8 +609,6 @@ package Rtsfind is RE_Buffer_Type, -- Ada.Strings.Text_Buffers.Unbounded RE_Get, -- Ada.Strings.Text_Buffers.Unbounded - RE_Wide_Get, -- Ada.Strings.Text_Buffers.Unbounded - RE_Wide_Wide_Get, -- Ada.Strings.Text_Buffers.Unbounded RE_Wait_For_Release, -- Ada.Synchronous_Barriers @@ -641,7 +620,6 @@ package Rtsfind is RE_Address_Array, -- Ada.Tags RE_Addr_Ptr, -- Ada.Tags RE_Base_Address, -- Ada.Tags - RE_Check_Interface_Conversion, -- Ada.Tags RE_Check_TSD, -- Ada.Tags RE_Cstring_Ptr, -- Ada.Tags RE_CW_Membership, -- Ada.Tags @@ -656,13 +634,11 @@ package Rtsfind is RE_External_Tag, -- Ada.Tags RO_TA_External_Tag, -- Ada.Tags RE_Get_Access_Level, -- Ada.Tags - RE_Get_Alignment, -- Ada.Tags RE_Get_Entry_Index, -- Ada.Tags RE_Get_Offset_Index, -- Ada.Tags RE_Get_Prim_Op_Kind, -- Ada.Tags RE_Get_Tagged_Kind, -- Ada.Tags RE_HT_Link, -- Ada.Tags - RE_Idepth, -- Ada.Tags RE_Interfaces_Array, -- Ada.Tags RE_Interfaces_Table, -- Ada.Tags RE_Interface_Data, -- Ada.Tags @@ -675,8 +651,6 @@ package Rtsfind is RE_No_Dispatch_Table_Wrapper, -- Ada.Tags RE_No_Tag, -- Ada.Tags RE_NDT_Prims_Ptr, -- Ada.Tags - RE_NDT_TSD, -- Ada.Tags - RE_Num_Prims, -- Ada.Tags RE_Object_Specific_Data, -- Ada.Tags RE_Offset_To_Top, -- Ada.Tags RE_Offset_To_Top_Ptr, -- Ada.Tags @@ -699,11 +673,9 @@ package Rtsfind is RE_Primary_DT, -- Ada.Tags RE_Signature, -- Ada.Tags RE_SSD, -- Ada.Tags - RE_TSD, -- Ada.Tags RE_Type_Specific_Data, -- Ada.Tags RE_Register_Interface_Offset, -- Ada.Tags RE_Register_Tag, -- Ada.Tags - RE_Register_TSD, -- Ada.Tags RE_Transportable, -- Ada.Tags RE_Secondary_DT, -- Ada.Tags RE_Secondary_Tag, -- Ada.Tags @@ -749,7 +721,6 @@ package Rtsfind is RE_Stream_T, -- CUDA.Driver_Types - RE_Fatbin_Wrapper, -- CUDA.Internal RE_Launch_Kernel, -- CUDA.Internal RE_Pop_Call_Configuration, -- CUDA.Internal RE_Push_Call_Configuration, -- CUDA.Internal @@ -772,19 +743,14 @@ package Rtsfind is RO_IC_Unsigned, -- Interfaces.C - RE_Chars_Ptr, -- Interfaces.C.Strings - RE_New_Char_Array, -- Interfaces.C.Strings - RE_Address, -- System RE_Any_Priority, -- System RE_Bit_Order, -- System RE_Default_Priority, -- System RE_High_Order_First, -- System RE_Interrupt_Priority, -- System - RE_Lib_Stop, -- System RE_Low_Order_First, -- System RE_Max_Base_Digits, -- System - RE_Max_Priority, -- System RE_Null_Address, -- System RE_Priority, -- System @@ -802,8 +768,6 @@ package Rtsfind is RE_Subtract_With_Ovflo_Check128, -- System.Arith_128 RE_Scaled_Divide128, -- System.Arith_128 - RE_Create_AST_Handler, -- System.AST_Handling - RE_Assert_Failure, -- System.Assertions RE_Raise_Assert_Failure, -- System.Assertions @@ -824,9 +788,6 @@ package Rtsfind is RE_Atomic_Test_And_Set, -- System.Atomic_Operations.Test_And_Set RE_AST_Handler, -- System.Aux_DEC - RE_Import_Address, -- System.Aux_DEC - RE_Import_Value, -- System.Aux_DEC - RE_No_AST_Handler, -- System.Aux_DEC RE_Type_Class, -- System.Aux_DEC RE_Type_Class_Enumeration, -- System.Aux_DEC RE_Type_Class_Integer, -- System.Aux_DEC @@ -954,15 +915,6 @@ package Rtsfind is RE_Attr_Long_Long_Float, -- System.Fat_LLF - RE_Attr_VAX_D_Float, -- System.Fat_VAX_D_Float - RE_Fat_VAX_D, -- System.Fat_VAX_D_Float - - RE_Attr_VAX_F_Float, -- System.Fat_VAX_F_Float - RE_Fat_VAX_F, -- System.Fat_VAX_F_Float - - RE_Attr_VAX_G_Float, -- System.Fat_VAX_G_Float - RE_Fat_VAX_G, -- System.Fat_VAX_G_Float - RE_Add_Offset_To_Address, -- System.Finalization_Masters RE_Attach, -- System.Finalization_Masters RE_Base_Pool, -- System.Finalization_Masters @@ -970,10 +922,8 @@ package Rtsfind is RE_Finalization_Master_Ptr, -- System.Finalization_Masters RE_Set_Base_Pool, -- System.Finalization_Masters RE_Set_Finalize_Address, -- System.Finalization_Masters - RE_Set_Is_Heterogeneous, -- System.Finalization_Masters RE_Root_Controlled, -- System.Finalization_Root - RE_Root_Controlled_Ptr, -- System.Finalization_Root RE_Fore_Decimal32, -- System.Fore_Decimal_32 @@ -1649,9 +1599,7 @@ package Rtsfind is RE_Set_127, -- System.Pack_127 RE_Adjust_Storage_Size, -- System.Parameters - RE_Default_Secondary_Stack_Size, -- System.Parameters RE_Default_Stack_Size, -- System.Parameters - RE_Garbage_Collected, -- System.Parameters RE_Size_Type, -- System.Parameters RE_Unspecified_Size, -- System.Parameters @@ -1677,8 +1625,6 @@ package Rtsfind is RE_Global_Pool_Object, -- System.Pool_Global - RE_Global_Pool_32_Object, -- System.Pool_32_Global - RE_Stack_Bounded_Pool, -- System.Pool_Size RE_Put_Image_Integer, -- System.Put_Images @@ -1744,11 +1690,8 @@ package Rtsfind is RE_Set_Result, -- System.Partition_Interface RE_Register_Obj_Receiving_Stub, -- System.Partition_Interface RE_Register_Pkg_Receiving_Stub, -- System.Partition_Interface - RE_Is_Nil, -- System.Partition_Interface - RE_Entity_Ptr, -- System.Partition_Interface RE_Entity_Of, -- System.Partition_Interface RE_Inc_Usage, -- System.Partition_Interface - RE_Set_Ref, -- System.Partition_Interface RE_Make_Ref, -- System.Partition_Interface RE_Get_Local_Address, -- System.Partition_Interface RE_Get_Reference, -- System.Partition_Interface @@ -1881,8 +1824,6 @@ package Rtsfind is RE_Deallocate_Any_Controlled, -- System.Storage_Pools.Subpools RE_Header_Size_With_Padding, -- System.Storage_Pools.Subpools RE_Root_Storage_Pool_With_Subpools, -- System.Storage_Pools.Subpools - RE_Root_Subpool, -- System.Storage_Pools.Subpools - RE_Subpool_Handle, -- System.Storage_Pools.Subpools RE_I_AD, -- System.Stream_Attributes RE_I_AS, -- System.Stream_Attributes @@ -2006,7 +1947,6 @@ package Rtsfind is RE_Simple_Mode, -- System.Tasking RE_Terminate_Mode, -- System.Tasking RE_Delay_Mode, -- System.Tasking - RE_Entry_Index, -- System.Tasking RE_Task_Entry_Index, -- System.Tasking RE_Self, -- System.Tasking @@ -2244,17 +2184,13 @@ package Rtsfind is RE_Set_Deadline => Ada_Dispatching_EDF, - RE_Code_Loc => Ada_Exceptions, RE_Exception_Id => Ada_Exceptions, - RE_Exception_Identity => Ada_Exceptions, RE_Exception_Information => Ada_Exceptions, RE_Exception_Message => Ada_Exceptions, RE_Exception_Name_Simple => Ada_Exceptions, RE_Exception_Occurrence => Ada_Exceptions, - RE_Exception_Occurrence_Access => Ada_Exceptions, RE_Null_Id => Ada_Exceptions, RE_Null_Occurrence => Ada_Exceptions, - RE_Poll => Ada_Exceptions, RE_Raise_Exception => Ada_Exceptions, RE_Raise_Exception_Always => Ada_Exceptions, RE_Raise_From_Controlled_Operation => Ada_Exceptions, @@ -2295,8 +2231,6 @@ package Rtsfind is RE_Stream_Element_Array => Ada_Streams, RE_Stream_Element_Offset => Ada_Streams, - RE_Stream_Access => Ada_Streams_Stream_IO, - RO_SU_Super_String => Ada_Strings_Superbounded, RO_WI_Super_String => Ada_Strings_Wide_Superbounded, @@ -2311,8 +2245,6 @@ package Rtsfind is RE_Buffer_Type => Ada_Strings_Text_Buffers_Unbounded, RE_Get => Ada_Strings_Text_Buffers_Unbounded, - RE_Wide_Get => Ada_Strings_Text_Buffers_Unbounded, - RE_Wide_Wide_Get => Ada_Strings_Text_Buffers_Unbounded, RE_Wait_For_Release => Ada_Synchronous_Barriers, @@ -2324,7 +2256,6 @@ package Rtsfind is RE_Address_Array => Ada_Tags, RE_Addr_Ptr => Ada_Tags, RE_Base_Address => Ada_Tags, - RE_Check_Interface_Conversion => Ada_Tags, RE_Check_TSD => Ada_Tags, RE_Cstring_Ptr => Ada_Tags, RE_CW_Membership => Ada_Tags, @@ -2339,13 +2270,11 @@ package Rtsfind is RE_External_Tag => Ada_Tags, RO_TA_External_Tag => Ada_Tags, RE_Get_Access_Level => Ada_Tags, - RE_Get_Alignment => Ada_Tags, RE_Get_Entry_Index => Ada_Tags, RE_Get_Offset_Index => Ada_Tags, RE_Get_Prim_Op_Kind => Ada_Tags, RE_Get_Tagged_Kind => Ada_Tags, RE_HT_Link => Ada_Tags, - RE_Idepth => Ada_Tags, RE_Interfaces_Array => Ada_Tags, RE_Interfaces_Table => Ada_Tags, RE_Interface_Data => Ada_Tags, @@ -2358,8 +2287,6 @@ package Rtsfind is RE_No_Dispatch_Table_Wrapper => Ada_Tags, RE_No_Tag => Ada_Tags, RE_NDT_Prims_Ptr => Ada_Tags, - RE_NDT_TSD => Ada_Tags, - RE_Num_Prims => Ada_Tags, RE_Object_Specific_Data => Ada_Tags, RE_Offset_To_Top => Ada_Tags, RE_Offset_To_Top_Ptr => Ada_Tags, @@ -2382,11 +2309,9 @@ package Rtsfind is RE_Primary_DT => Ada_Tags, RE_Signature => Ada_Tags, RE_SSD => Ada_Tags, - RE_TSD => Ada_Tags, RE_Type_Specific_Data => Ada_Tags, RE_Register_Interface_Offset => Ada_Tags, RE_Register_Tag => Ada_Tags, - RE_Register_TSD => Ada_Tags, RE_Transportable => Ada_Tags, RE_Secondary_DT => Ada_Tags, RE_Secondary_Tag => Ada_Tags, @@ -2432,7 +2357,6 @@ package Rtsfind is RE_Stream_T => CUDA_Driver_Types, - RE_Fatbin_Wrapper => CUDA_Internal, RE_Launch_Kernel => CUDA_Internal, RE_Pop_Call_Configuration => CUDA_Internal, RE_Push_Call_Configuration => CUDA_Internal, @@ -2455,19 +2379,14 @@ package Rtsfind is RO_IC_Unsigned => Interfaces_C, - RE_Chars_Ptr => Interfaces_C_Strings, - RE_New_Char_Array => Interfaces_C_Strings, - RE_Address => System, RE_Any_Priority => System, RE_Bit_Order => System, RE_Default_Priority => System, RE_High_Order_First => System, RE_Interrupt_Priority => System, - RE_Lib_Stop => System, RE_Low_Order_First => System, RE_Max_Base_Digits => System, - RE_Max_Priority => System, RE_Null_Address => System, RE_Priority => System, @@ -2485,8 +2404,6 @@ package Rtsfind is RE_Subtract_With_Ovflo_Check128 => System_Arith_128, RE_Scaled_Divide128 => System_Arith_128, - RE_Create_AST_Handler => System_AST_Handling, - RE_Assert_Failure => System_Assertions, RE_Raise_Assert_Failure => System_Assertions, @@ -2507,9 +2424,6 @@ package Rtsfind is RE_Atomic_Test_And_Set => System_Atomic_Operations_Test_And_Set, RE_AST_Handler => System_Aux_DEC, - RE_Import_Address => System_Aux_DEC, - RE_Import_Value => System_Aux_DEC, - RE_No_AST_Handler => System_Aux_DEC, RE_Type_Class => System_Aux_DEC, RE_Type_Class_Enumeration => System_Aux_DEC, RE_Type_Class_Integer => System_Aux_DEC, @@ -2643,15 +2557,6 @@ package Rtsfind is RE_Attr_Long_Long_Float => System_Fat_LLF, - RE_Attr_VAX_D_Float => System_Fat_VAX_D_Float, - RE_Fat_VAX_D => System_Fat_VAX_D_Float, - - RE_Attr_VAX_F_Float => System_Fat_VAX_F_Float, - RE_Fat_VAX_F => System_Fat_VAX_F_Float, - - RE_Attr_VAX_G_Float => System_Fat_VAX_G_Float, - RE_Fat_VAX_G => System_Fat_VAX_G_Float, - RE_Add_Offset_To_Address => System_Finalization_Masters, RE_Attach => System_Finalization_Masters, RE_Base_Pool => System_Finalization_Masters, @@ -2659,10 +2564,8 @@ package Rtsfind is RE_Finalization_Master_Ptr => System_Finalization_Masters, RE_Set_Base_Pool => System_Finalization_Masters, RE_Set_Finalize_Address => System_Finalization_Masters, - RE_Set_Is_Heterogeneous => System_Finalization_Masters, RE_Root_Controlled => System_Finalization_Root, - RE_Root_Controlled_Ptr => System_Finalization_Root, RE_Fore_Decimal32 => System_Fore_Decimal_32, @@ -3340,9 +3243,7 @@ package Rtsfind is RE_Set_127 => System_Pack_127, RE_Adjust_Storage_Size => System_Parameters, - RE_Default_Secondary_Stack_Size => System_Parameters, RE_Default_Stack_Size => System_Parameters, - RE_Garbage_Collected => System_Parameters, RE_Size_Type => System_Parameters, RE_Unspecified_Size => System_Parameters, @@ -3399,11 +3300,8 @@ package Rtsfind is RE_Set_Result => System_Partition_Interface, RE_Register_Obj_Receiving_Stub => System_Partition_Interface, RE_Register_Pkg_Receiving_Stub => System_Partition_Interface, - RE_Is_Nil => System_Partition_Interface, - RE_Entity_Ptr => System_Partition_Interface, RE_Entity_Of => System_Partition_Interface, RE_Inc_Usage => System_Partition_Interface, - RE_Set_Ref => System_Partition_Interface, RE_Make_Ref => System_Partition_Interface, RE_Get_Local_Address => System_Partition_Interface, RE_Get_Reference => System_Partition_Interface, @@ -3488,8 +3386,6 @@ package Rtsfind is RE_Global_Pool_Object => System_Pool_Global, - RE_Global_Pool_32_Object => System_Pool_32_Global, - RE_Stack_Bounded_Pool => System_Pool_Size, RE_Put_Image_Integer => System_Put_Images, @@ -3572,8 +3468,6 @@ package Rtsfind is RE_Deallocate_Any_Controlled => System_Storage_Pools_Subpools, RE_Header_Size_With_Padding => System_Storage_Pools_Subpools, RE_Root_Storage_Pool_With_Subpools => System_Storage_Pools_Subpools, - RE_Root_Subpool => System_Storage_Pools_Subpools, - RE_Subpool_Handle => System_Storage_Pools_Subpools, RE_I_AD => System_Stream_Attributes, RE_I_AS => System_Stream_Attributes, @@ -3697,7 +3591,6 @@ package Rtsfind is RE_Simple_Mode => System_Tasking, RE_Terminate_Mode => System_Tasking, RE_Delay_Mode => System_Tasking, - RE_Entry_Index => System_Tasking, RE_Task_Entry_Index => System_Tasking, RE_Self => System_Tasking, diff --git a/gcc/ada/s-oscons-tmplt.c b/gcc/ada/s-oscons-tmplt.c index af69190..5394122 100644 --- a/gcc/ada/s-oscons-tmplt.c +++ b/gcc/ada/s-oscons-tmplt.c @@ -237,9 +237,6 @@ int counter = 0; #define CST(name,comment) C(#name,String,name,comment) /* String constant */ -#define STR(x) STR1(x) -#define STR1(x) #x - #ifdef __MINGW32__ unsigned int _CRT_fmode = _O_BINARY; #endif diff --git a/gcc/ada/sem_ch12.adb b/gcc/ada/sem_ch12.adb index 9525140..ab2e182 100644 --- a/gcc/ada/sem_ch12.adb +++ b/gcc/ada/sem_ch12.adb @@ -6296,13 +6296,16 @@ package body Sem_Ch12 is Old_Main : constant Entity_Id := Cunit_Entity (Main_Unit); begin - -- A new compilation unit node is built for the instance declaration + -- A new compilation unit node is built for the instance declaration. + -- It relocates the auxiliary declaration node from the compilation unit + -- where the instance appeared, so that declarations that originally + -- followed the instance will be attached to the spec compilation unit. Decl_Cunit := Make_Compilation_Unit (Sloc (N), Context_Items => Empty_List, Unit => Act_Decl, - Aux_Decls_Node => Make_Compilation_Unit_Aux (Sloc (N))); + Aux_Decls_Node => Relocate_Node (Aux_Decls_Node (Parent (N)))); Set_Parent_Spec (Act_Decl, Parent_Spec (N)); diff --git a/gcc/ada/sem_ch5.adb b/gcc/ada/sem_ch5.adb index 17bf6d9..d0f00b3 100644 --- a/gcc/ada/sem_ch5.adb +++ b/gcc/ada/sem_ch5.adb @@ -2429,13 +2429,9 @@ package body Sem_Ch5 is if not Is_Entity_Name (Iter_Name) - -- When the context is a quantified expression, the renaming - -- declaration is delayed until the expansion phase if we are - -- doing expansion. + -- Do not perform this expansion in preanalysis - and then (Nkind (Parent (N)) /= N_Quantified_Expression - or else (Operating_Mode = Check_Semantics - and then not GNATprove_Mode)) + and then Full_Analysis -- Do not perform this expansion when expansion is disabled, where the -- temporary may hide the transformation of a selected component into diff --git a/gcc/ada/sem_util.adb b/gcc/ada/sem_util.adb index b0babeb..9ae082c 100644 --- a/gcc/ada/sem_util.adb +++ b/gcc/ada/sem_util.adb @@ -531,7 +531,7 @@ package body Sem_Util is -- Local variables - E : Entity_Id := Original_Node (Expr); + E : Node_Id := Original_Node (Expr); Pre : Node_Id; -- Start of processing for Accessibility_Level @@ -777,8 +777,18 @@ package body Sem_Util is -- We don't handle function calls in prefix notation correctly ??? - when N_Indexed_Component | N_Selected_Component => - Pre := Original_Node (Prefix (E)); + when N_Indexed_Component | N_Selected_Component | N_Slice => + Pre := Prefix (E); + + -- Fetch the original node when the prefix comes from the result + -- of expanding a function call since we want to find the level + -- of the original source call. + + if not Comes_From_Source (Pre) + and then Nkind (Original_Node (Pre)) = N_Function_Call + then + Pre := Original_Node (Pre); + end if; -- When E is an indexed component or selected component and -- the current Expr is a function call, we know that we are @@ -26549,6 +26559,14 @@ package body Sem_Util is Item_Nam := Chars (Original_Node (Pragma_Identifier (Original_Node (Item)))); + if Item_Nam = Name_Check then + -- Pragma "Check" preserves the original pragma name as its first + -- argument. + Item_Nam := + Chars (Expression (First (Pragma_Argument_Associations + (Original_Node (Item))))); + end if; + else pragma Assert (Nkind (Item) = N_Aspect_Specification); Item_Nam := Chars (Identifier (Item)); diff --git a/gcc/ada/sem_warn.ads b/gcc/ada/sem_warn.ads index 1894f36..6681e54 100644 --- a/gcc/ada/sem_warn.ads +++ b/gcc/ada/sem_warn.ads @@ -257,12 +257,9 @@ package Sem_Warn is ---------------------- function Has_Junk_Name (E : Entity_Id) return Boolean; - -- Return True if the entity name contains any of the following substrings: - -- discard - -- dummy - -- ignore - -- junk - -- unused + -- Return True if the entity name contains substrings like "junk" or + -- "dummy" (see the body for the complete list). + -- -- Used to suppress warnings on names matching these patterns. The contents -- of Name_Buffer and Name_Len are destroyed by this call. diff --git a/gcc/ada/sysdep.c b/gcc/ada/sysdep.c index 5e9cf70..7bdfcbc 100644 --- a/gcc/ada/sysdep.c +++ b/gcc/ada/sysdep.c @@ -323,11 +323,7 @@ __gnat_ttyname (int filedes ATTRIBUTE_UNUSED) || defined (__QNX__) # ifdef __MINGW32__ -# if OLD_MINGW -# include <termios.h> -# else -# include <conio.h> /* for getch(), kbhit() */ -# endif +# include <conio.h> /* for getch(), kbhit() */ # else # include <termios.h> # endif diff --git a/gcc/builtins.def b/gcc/builtins.def index f023631..109b387 100644 --- a/gcc/builtins.def +++ b/gcc/builtins.def @@ -114,9 +114,8 @@ along with GCC; see the file COPYING3. If not see with an argument such as FLOAT32 to produce the enum value for the type. If we are compiling for the C language with GNU extensions, we enable the name without the __builtin_ prefix as well as the name with the __builtin_ - prefix. C++ does not enable these names by default because they don't have - the _Float<N> and _Float<N>X keywords, and a class based library should use - the __builtin_ names. */ + prefix. C++ does not enable these names by default because a class based + library should use the __builtin_ names. */ #undef DEF_FLOATN_BUILTIN #define DEF_FLOATN_BUILTIN(ENUM, NAME, TYPE, ATTRS) \ DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE, \ diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 415c4cf..4e99c43 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,9 @@ +2022-09-26 Marek Polacek <polacek@redhat.com> + + PR c++/106656 + * c-cppbuiltin.cc (c_cpp_builtins): Update value of __cpp_char8_t + for C++20. + 2022-09-23 Marek Polacek <polacek@redhat.com> PR c++/106784 diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc index dce3045..cda6910 100644 --- a/gcc/c-family/c-common.cc +++ b/gcc/c-family/c-common.cc @@ -352,13 +352,13 @@ const struct c_common_resword c_common_reswords[] = { "_Bool", RID_BOOL, D_CONLY }, { "_Complex", RID_COMPLEX, 0 }, { "_Imaginary", RID_IMAGINARY, D_CONLY }, - { "_Float16", RID_FLOAT16, D_CONLY }, - { "_Float32", RID_FLOAT32, D_CONLY }, - { "_Float64", RID_FLOAT64, D_CONLY }, - { "_Float128", RID_FLOAT128, D_CONLY }, - { "_Float32x", RID_FLOAT32X, D_CONLY }, - { "_Float64x", RID_FLOAT64X, D_CONLY }, - { "_Float128x", RID_FLOAT128X, D_CONLY }, + { "_Float16", RID_FLOAT16, 0 }, + { "_Float32", RID_FLOAT32, 0 }, + { "_Float64", RID_FLOAT64, 0 }, + { "_Float128", RID_FLOAT128, 0 }, + { "_Float32x", RID_FLOAT32X, 0 }, + { "_Float64x", RID_FLOAT64X, 0 }, + { "_Float128x", RID_FLOAT128X, 0 }, { "_Decimal32", RID_DFLOAT32, D_CONLY }, { "_Decimal64", RID_DFLOAT64, D_CONLY }, { "_Decimal128", RID_DFLOAT128, D_CONLY }, @@ -1431,8 +1431,11 @@ shorten_binary_op (tree result_type, tree op0, tree op1, bool bitwise) == TYPE_PRECISION (TREE_TYPE (arg0))) && unsigned0 == unsigned1 && (unsigned0 || !uns)) - return c_common_signed_or_unsigned_type - (unsigned0, common_type (TREE_TYPE (arg0), TREE_TYPE (arg1))); + { + tree ctype = common_type (TREE_TYPE (arg0), TREE_TYPE (arg1)); + if (ctype != error_mark_node) + return c_common_signed_or_unsigned_type (unsigned0, ctype); + } else if (TREE_CODE (arg0) == INTEGER_CST && (unsigned1 || !uns) @@ -3204,9 +3207,10 @@ shorten_compare (location_t loc, tree *op0_ptr, tree *op1_ptr, else if (unsignedp0 == unsignedp1 && real1 == real2 && TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr) - && TYPE_PRECISION (TREE_TYPE (primop1)) < TYPE_PRECISION (*restype_ptr)) + && TYPE_PRECISION (TREE_TYPE (primop1)) < TYPE_PRECISION (*restype_ptr) + && (type = common_type (TREE_TYPE (primop0), TREE_TYPE (primop1))) + != error_mark_node) { - type = common_type (TREE_TYPE (primop0), TREE_TYPE (primop1)); type = c_common_signed_or_unsigned_type (unsignedp0 || TYPE_UNSIGNED (*restype_ptr), type); @@ -4380,11 +4384,18 @@ c_common_nodes_and_builtins (void) record_builtin_type (RID_DOUBLE, NULL, double_type_node); record_builtin_type (RID_MAX, "long double", long_double_type_node); - if (!c_dialect_cxx ()) - for (i = 0; i < NUM_FLOATN_NX_TYPES; i++) + for (i = 0; i < NUM_FLOATN_NX_TYPES; i++) + { if (FLOATN_NX_TYPE_NODE (i) != NULL_TREE) record_builtin_type ((enum rid) (RID_FLOATN_NX_FIRST + i), NULL, FLOATN_NX_TYPE_NODE (i)); + } + + /* For C, let float128t_type_node (__float128 in some backends) be the + same type as float128_type_node (_Float128), for C++ let those + be distinct types that mangle and behave differently. */ + if (c_dialect_cxx ()) + float128t_type_node = NULL_TREE; /* Only supported decimal floating point extension if the target actually supports underlying modes. */ diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 31397d8..50a4691 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1286,6 +1286,7 @@ struct c_omp_directive { bool simd; }; +extern const struct c_omp_directive c_omp_directives[]; extern const struct c_omp_directive *c_omp_categorize_directive (const char *, const char *, const char *); diff --git a/gcc/c-family/c-cppbuiltin.cc b/gcc/c-family/c-cppbuiltin.cc index a1557eb..ca5f500 100644 --- a/gcc/c-family/c-cppbuiltin.cc +++ b/gcc/c-family/c-cppbuiltin.cc @@ -1081,6 +1081,7 @@ c_cpp_builtins (cpp_reader *pfile) cpp_define (pfile, "__cpp_constexpr=202110L"); cpp_define (pfile, "__cpp_multidimensional_subscript=202110L"); cpp_define (pfile, "__cpp_named_character_escapes=202207L"); + cpp_define (pfile, "__cpp_static_call_operator=202207L"); } if (flag_concepts) { @@ -1112,7 +1113,7 @@ c_cpp_builtins (cpp_reader *pfile) if (flag_threadsafe_statics) cpp_define (pfile, "__cpp_threadsafe_static_init=200806L"); if (flag_char8_t) - cpp_define (pfile, "__cpp_char8_t=201811L"); + cpp_define (pfile, "__cpp_char8_t=202207L"); #ifndef THREAD_MODEL_SPEC /* Targets that define THREAD_MODEL_SPEC need to define __STDCPP_THREADS__ in their config/XXX/XXX-c.c themselves. */ @@ -1246,6 +1247,14 @@ c_cpp_builtins (cpp_reader *pfile) { if (FLOATN_NX_TYPE_NODE (i) == NULL_TREE) continue; + if (c_dialect_cxx () + && cxx_dialect > cxx20 + && !floatn_nx_types[i].extended) + { + char name[sizeof ("__STDCPP_FLOAT128_T__=1")]; + sprintf (name, "__STDCPP_FLOAT%d_T__=1", floatn_nx_types[i].n); + cpp_define (pfile, name); + } char prefix[20], csuffix[20]; sprintf (prefix, "FLT%d%s", floatn_nx_types[i].n, floatn_nx_types[i].extended ? "X" : ""); diff --git a/gcc/c-family/c-lex.cc b/gcc/c-family/c-lex.cc index 110d029..4d2252f 100644 --- a/gcc/c-family/c-lex.cc +++ b/gcc/c-family/c-lex.cc @@ -960,6 +960,10 @@ interpret_float (const cpp_token *token, unsigned int flags, pedwarn (input_location, OPT_Wpedantic, "non-standard suffix on floating constant"); type = c_common_type_for_mode (mode, 0); + /* For Q suffix, prefer float128t_type_node (__float128) type + over float128_type_node (_Float128) type if they are distinct. */ + if (type == float128_type_node && float128t_type_node) + type = float128t_type_node; gcc_assert (type); } else if ((flags & (CPP_N_FLOATN | CPP_N_FLOATNX)) != 0) @@ -979,8 +983,17 @@ interpret_float (const cpp_token *token, unsigned int flags, error ("unsupported non-standard suffix on floating constant"); return error_mark_node; } + else if (c_dialect_cxx () && !extended) + { + if (cxx_dialect < cxx23) + pedwarn (input_location, OPT_Wpedantic, + "%<f%d%> or %<F%d%> suffix on floating constant only " + "available with %<-std=c++2b%> or %<-std=gnu++2b%>", + n, n); + } else - pedwarn (input_location, OPT_Wpedantic, "non-standard suffix on floating constant"); + pedwarn (input_location, OPT_Wpedantic, + "non-standard suffix on floating constant"); } else if ((flags & CPP_N_WIDTH) == CPP_N_LARGE) type = long_double_type_node; @@ -990,7 +1003,10 @@ interpret_float (const cpp_token *token, unsigned int flags, else type = double_type_node; - const_type = excess_precision_type (type); + if (c_dialect_cxx ()) + const_type = NULL_TREE; + else + const_type = excess_precision_type (type); if (!const_type) const_type = type; diff --git a/gcc/c-family/c-omp.cc b/gcc/c-family/c-omp.cc index 1b086d8..7a97c40 100644 --- a/gcc/c-family/c-omp.cc +++ b/gcc/c-family/c-omp.cc @@ -3097,21 +3097,21 @@ c_omp_adjust_map_clauses (tree clauses, bool is_target) } } -static const struct c_omp_directive omp_directives[] = { +const struct c_omp_directive c_omp_directives[] = { /* Keep this alphabetically sorted by the first word. Non-null second/third if any should precede null ones. */ { "allocate", nullptr, nullptr, PRAGMA_OMP_ALLOCATE, C_OMP_DIR_DECLARATIVE, false }, - /* { "assume", nullptr, nullptr, PRAGMA_OMP_ASSUME, - C_OMP_DIR_INFORMATIONAL, false }, */ - /* { "assumes", nullptr, nullptr, PRAGMA_OMP_ASSUMES, - C_OMP_DIR_INFORMATIONAL, false }, */ + { "assume", nullptr, nullptr, PRAGMA_OMP_ASSUME, + C_OMP_DIR_INFORMATIONAL, false }, + { "assumes", nullptr, nullptr, PRAGMA_OMP_ASSUMES, + C_OMP_DIR_INFORMATIONAL, false }, { "atomic", nullptr, nullptr, PRAGMA_OMP_ATOMIC, C_OMP_DIR_CONSTRUCT, false }, { "barrier", nullptr, nullptr, PRAGMA_OMP_BARRIER, C_OMP_DIR_STANDALONE, false }, - /* { "begin", "assumes", nullptr, PRAGMA_OMP_BEGIN, - C_OMP_DIR_INFORMATIONAL, false }, */ + { "begin", "assumes", nullptr, PRAGMA_OMP_BEGIN, + C_OMP_DIR_INFORMATIONAL, false }, /* { "begin", "declare", "target", PRAGMA_OMP_BEGIN, C_OMP_DIR_DECLARATIVE, false }, */ /* { "begin", "declare", "variant", PRAGMA_OMP_BEGIN, @@ -3140,9 +3140,9 @@ static const struct c_omp_directive omp_directives[] = { C_OMP_DIR_CONSTRUCT, false }, */ { "distribute", nullptr, nullptr, PRAGMA_OMP_DISTRIBUTE, C_OMP_DIR_CONSTRUCT, true }, - /* { "end", "assumes", nullptr, PRAGMA_OMP_END, - C_OMP_DIR_INFORMATIONAL, false }, */ - { "end", "declare", "target", PRAGMA_OMP_END_DECLARE_TARGET, + { "end", "assumes", nullptr, PRAGMA_OMP_END, + C_OMP_DIR_INFORMATIONAL, false }, + { "end", "declare", "target", PRAGMA_OMP_END, C_OMP_DIR_DECLARATIVE, false }, /* { "end", "declare", "variant", PRAGMA_OMP_END, C_OMP_DIR_DECLARATIVE, false }, */ @@ -3224,26 +3224,26 @@ const struct c_omp_directive * c_omp_categorize_directive (const char *first, const char *second, const char *third) { - const size_t n_omp_directives = ARRAY_SIZE (omp_directives); + const size_t n_omp_directives = ARRAY_SIZE (c_omp_directives); for (size_t i = 0; i < n_omp_directives; i++) { - if ((unsigned char) omp_directives[i].first[0] + if ((unsigned char) c_omp_directives[i].first[0] < (unsigned char) first[0]) continue; - if ((unsigned char) omp_directives[i].first[0] + if ((unsigned char) c_omp_directives[i].first[0] > (unsigned char) first[0]) break; - if (strcmp (omp_directives[i].first, first)) + if (strcmp (c_omp_directives[i].first, first)) continue; - if (!omp_directives[i].second) - return &omp_directives[i]; - if (!second || strcmp (omp_directives[i].second, second)) + if (!c_omp_directives[i].second) + return &c_omp_directives[i]; + if (!second || strcmp (c_omp_directives[i].second, second)) continue; - if (!omp_directives[i].third) - return &omp_directives[i]; - if (!third || strcmp (omp_directives[i].third, third)) + if (!c_omp_directives[i].third) + return &c_omp_directives[i]; + if (!third || strcmp (c_omp_directives[i].third, third)) continue; - return &omp_directives[i]; + return &c_omp_directives[i]; } return NULL; } diff --git a/gcc/c-family/c-pragma.cc b/gcc/c-family/c-pragma.cc index 789719e..b5a4b3c 100644 --- a/gcc/c-family/c-pragma.cc +++ b/gcc/c-family/c-pragma.cc @@ -1546,14 +1546,16 @@ static const struct omp_pragma_def oacc_pragmas[] = { }; static const struct omp_pragma_def omp_pragmas[] = { { "allocate", PRAGMA_OMP_ALLOCATE }, + { "assumes", PRAGMA_OMP_ASSUMES }, { "atomic", PRAGMA_OMP_ATOMIC }, { "barrier", PRAGMA_OMP_BARRIER }, + { "begin", PRAGMA_OMP_BEGIN }, { "cancel", PRAGMA_OMP_CANCEL }, { "cancellation", PRAGMA_OMP_CANCELLATION_POINT }, { "critical", PRAGMA_OMP_CRITICAL }, { "depobj", PRAGMA_OMP_DEPOBJ }, { "error", PRAGMA_OMP_ERROR }, - { "end", PRAGMA_OMP_END_DECLARE_TARGET }, + { "end", PRAGMA_OMP_END }, { "flush", PRAGMA_OMP_FLUSH }, { "nothing", PRAGMA_OMP_NOTHING }, { "requires", PRAGMA_OMP_REQUIRES }, @@ -1568,6 +1570,7 @@ static const struct omp_pragma_def omp_pragmas[] = { { "threadprivate", PRAGMA_OMP_THREADPRIVATE } }; static const struct omp_pragma_def omp_pragmas_simd[] = { + { "assume", PRAGMA_OMP_ASSUME }, { "declare", PRAGMA_OMP_DECLARE }, { "distribute", PRAGMA_OMP_DISTRIBUTE }, { "for", PRAGMA_OMP_FOR }, diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h index c894a25..10a4053 100644 --- a/gcc/c-family/c-pragma.h +++ b/gcc/c-family/c-pragma.h @@ -45,8 +45,11 @@ enum pragma_kind { /* PRAGMA_OMP__START_ should be equal to the first PRAGMA_OMP_* code. */ PRAGMA_OMP_ALLOCATE, PRAGMA_OMP__START_ = PRAGMA_OMP_ALLOCATE, + PRAGMA_OMP_ASSUME, + PRAGMA_OMP_ASSUMES, PRAGMA_OMP_ATOMIC, PRAGMA_OMP_BARRIER, + PRAGMA_OMP_BEGIN, PRAGMA_OMP_CANCEL, PRAGMA_OMP_CANCELLATION_POINT, PRAGMA_OMP_CRITICAL, @@ -54,7 +57,7 @@ enum pragma_kind { PRAGMA_OMP_DEPOBJ, PRAGMA_OMP_DISTRIBUTE, PRAGMA_OMP_ERROR, - PRAGMA_OMP_END_DECLARE_TARGET, + PRAGMA_OMP_END, PRAGMA_OMP_FLUSH, PRAGMA_OMP_FOR, PRAGMA_OMP_LOOP, diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 21248d3..4b852b8 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,10 @@ +2022-09-24 Jakub Jelinek <jakub@redhat.com> + + PR c/106981 + * c-typeck.cc (c_tree_equal): Only strip NON_LVALUE_EXPRs at the + start. For CONSTANT_CLASS_P or CASE_CONVERT: return false if t1 and + t2 have different types. + 2022-09-22 David Malcolm <dmalcolm@redhat.com> PR c/106830 diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index b09c639..740982e 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -156,6 +156,10 @@ static bool undef_nested_function; /* If non-zero, implicit "omp declare target" attribute is added into the attribute lists. */ int current_omp_declare_target_attribute; + +/* If non-zero, we are inside of + #pragma omp begin assumes ... #pragma omp end assumes region. */ +int current_omp_begin_assumes; /* Each c_binding structure describes one binding of an identifier to a decl. All the decls in a scope - irrespective of namespace - are diff --git a/gcc/c/c-lang.h b/gcc/c/c-lang.h index 7bdab47..861abe8 100644 --- a/gcc/c/c-lang.h +++ b/gcc/c/c-lang.h @@ -63,5 +63,8 @@ struct GTY(()) language_function { /* If non-zero, implicit "omp declare target" attribute is added into the attribute lists. */ extern GTY(()) int current_omp_declare_target_attribute; +/* Similarly whether we are in between #pragma omp begin assumes and + #pragma omp end assumes (and how many times when nested). */ +extern GTY(()) int current_omp_begin_assumes; #endif /* ! GCC_C_LANG_H */ diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index bce79d3..f2498dc 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -71,6 +71,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-pretty-print.h" #include "memmodel.h" #include "c-family/known-headers.h" +#include "bitmap.h" /* We need to walk over decls with incomplete struct/union/enum types after parsing the whole translation unit. @@ -1594,10 +1595,13 @@ enum pragma_context { pragma_external, pragma_struct, pragma_param, static bool c_parser_pragma (c_parser *, enum pragma_context, bool *); static bool c_parser_omp_cancellation_point (c_parser *, enum pragma_context); static bool c_parser_omp_target (c_parser *, enum pragma_context, bool *); -static void c_parser_omp_end_declare_target (c_parser *); +static void c_parser_omp_begin (c_parser *); +static void c_parser_omp_end (c_parser *); static bool c_parser_omp_declare (c_parser *, enum pragma_context); static void c_parser_omp_requires (c_parser *); static bool c_parser_omp_error (c_parser *, enum pragma_context); +static void c_parser_omp_assumption_clauses (c_parser *, bool); +static void c_parser_omp_assumes (c_parser *); static bool c_parser_omp_ordered (c_parser *, enum pragma_context, bool *); static void c_parser_oacc_routine (c_parser *, enum pragma_context); @@ -1678,6 +1682,13 @@ c_parser_translation_unit (c_parser *parser) "%<#pragma omp end declare target%>"); current_omp_declare_target_attribute = 0; } + if (current_omp_begin_assumes) + { + if (!errorcount) + error ("%<#pragma omp begin assumes%> without corresponding " + "%<#pragma omp end assumes%>"); + current_omp_begin_assumes = 0; + } } /* Parse an external declaration (C90 6.7, C99 6.9, C11 6.9). @@ -12594,8 +12605,12 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p) case PRAGMA_OMP_TARGET: return c_parser_omp_target (parser, context, if_p); - case PRAGMA_OMP_END_DECLARE_TARGET: - c_parser_omp_end_declare_target (parser); + case PRAGMA_OMP_BEGIN: + c_parser_omp_begin (parser); + return false; + + case PRAGMA_OMP_END: + c_parser_omp_end (parser); return false; case PRAGMA_OMP_SCAN: @@ -12619,13 +12634,26 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p) if (context != pragma_external) { error_at (c_parser_peek_token (parser)->location, - "%<#pragma omp requires%> may only be used at file scope"); + "%<#pragma %s%> may only be used at file scope", + "omp requires"); c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); return false; } c_parser_omp_requires (parser); return false; + case PRAGMA_OMP_ASSUMES: + if (context != pragma_external) + { + error_at (c_parser_peek_token (parser)->location, + "%<#pragma %s%> may only be used at file scope", + "omp assumes"); + c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); + return false; + } + c_parser_omp_assumes (parser); + return false; + case PRAGMA_OMP_NOTHING: c_parser_omp_nothing (parser); return false; @@ -22405,14 +22433,44 @@ c_parser_omp_declare_target (c_parser *parser) "directive with only %<device_type%> clauses ignored"); } +/* OpenMP 5.1 + #pragma omp begin assumes clauses[optseq] new-line */ + +static void +c_parser_omp_begin (c_parser *parser) +{ + const char *p = ""; + c_parser_consume_pragma (parser); + if (c_parser_next_token_is (parser, CPP_NAME)) + p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "assumes") == 0) + { + c_parser_consume_token (parser); + c_parser_omp_assumption_clauses (parser, false); + current_omp_begin_assumes++; + } + else + { + c_parser_error (parser, "expected %<assumes%>"); + c_parser_skip_to_pragma_eol (parser); + } +} + +/* OpenMP 4.0 + #pragma omp end declare target + + OpenMP 5.1 + #pragma omp end assumes */ + static void -c_parser_omp_end_declare_target (c_parser *parser) +c_parser_omp_end (c_parser *parser) { location_t loc = c_parser_peek_token (parser)->location; + const char *p = ""; c_parser_consume_pragma (parser); - if (c_parser_next_token_is (parser, CPP_NAME) - && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value), - "declare") == 0) + if (c_parser_next_token_is (parser, CPP_NAME)) + p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "declare") == 0) { c_parser_consume_token (parser); if (c_parser_next_token_is (parser, CPP_NAME) @@ -22425,22 +22483,30 @@ c_parser_omp_end_declare_target (c_parser *parser) c_parser_skip_to_pragma_eol (parser); return; } + c_parser_skip_to_pragma_eol (parser); + if (!current_omp_declare_target_attribute) + error_at (loc, "%<#pragma omp end declare target%> without " + "corresponding %<#pragma omp declare target%>"); + else + current_omp_declare_target_attribute--; } - else + else if (strcmp (p, "assumes") == 0) { - c_parser_error (parser, "expected %<declare%>"); + c_parser_consume_token (parser); c_parser_skip_to_pragma_eol (parser); - return; + if (!current_omp_begin_assumes) + error_at (loc, "%<#pragma omp end assumes%> without " + "corresponding %<#pragma omp begin assumes%>"); + else + current_omp_begin_assumes--; } - c_parser_skip_to_pragma_eol (parser); - if (!current_omp_declare_target_attribute) - error_at (loc, "%<#pragma omp end declare target%> without corresponding " - "%<#pragma omp declare target%>"); else - current_omp_declare_target_attribute--; + { + c_parser_error (parser, "expected %<declare%> or %<assumes%>"); + c_parser_skip_to_pragma_eol (parser); + } } - /* OpenMP 4.0 #pragma omp declare reduction (reduction-id : typename-list : expression) \ initializer-clause[opt] new-line @@ -23299,6 +23365,211 @@ c_parser_omp_error (c_parser *parser, enum pragma_context context) 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 first = true; + bool no_openmp = false; + bool no_openmp_routines = false; + bool no_parallelism = false; + bitmap_head absent_head, contains_head; + + bitmap_obstack_initialize (NULL); + bitmap_initialize (&absent_head, &bitmap_default_obstack); + bitmap_initialize (&contains_head, &bitmap_default_obstack); + + if (c_parser_next_token_is (parser, CPP_PRAGMA_EOL)) + error_at (c_parser_peek_token (parser)->location, + "expected at least one assumption clause"); + + while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) + { + if (!first + && c_parser_next_token_is (parser, CPP_COMMA) + && c_parser_peek_2nd_token (parser)->type == CPP_NAME) + c_parser_consume_token (parser); + + first = false; + + if (!c_parser_next_token_is (parser, CPP_NAME)) + break; + + const char *p + = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + location_t cloc = c_parser_peek_token (parser)->location; + + if (!strcmp (p, "no_openmp")) + { + c_parser_consume_token (parser); + if (no_openmp) + error_at (cloc, "too many %qs clauses", "no_openmp"); + no_openmp = true; + } + else if (!strcmp (p, "no_openmp_routines")) + { + c_parser_consume_token (parser); + if (no_openmp_routines) + error_at (cloc, "too many %qs clauses", "no_openmp_routines"); + no_openmp_routines = true; + } + else if (!strcmp (p, "no_parallelism")) + { + c_parser_consume_token (parser); + if (no_parallelism) + error_at (cloc, "too many %qs clauses", "no_parallelism"); + no_parallelism = true; + } + else if (!strcmp (p, "holds")) + { + c_parser_consume_token (parser); + matching_parens parens; + if (parens.require_open (parser)) + { + location_t eloc = c_parser_peek_token (parser)->location; + c_expr expr = c_parser_expr_no_commas (parser, NULL); + tree t = convert_lvalue_to_rvalue (eloc, expr, true, true).value; + t = c_objc_common_truthvalue_conversion (eloc, t); + t = c_fully_fold (t, false, NULL); + if (is_assume) + { + /* FIXME: Emit .ASSUME (t) call here. */ + (void) t; + } + parens.skip_until_found_close (parser); + } + } + else if (!strcmp (p, "absent") || !strcmp (p, "contains")) + { + c_parser_consume_token (parser); + matching_parens parens; + if (parens.require_open (parser)) + { + do + { + const char *directive[3] = {}; + int i; + location_t dloc = c_parser_peek_token (parser)->location; + for (i = 0; i < 3; i++) + { + tree id; + if (c_parser_peek_nth_token (parser, i + 1)->type + == CPP_NAME) + id = c_parser_peek_nth_token (parser, i + 1)->value; + else if (c_parser_peek_nth_token (parser, i + 1)->keyword + != RID_MAX) + { + enum rid rid + = c_parser_peek_nth_token (parser, i + 1)->keyword; + id = ridpointers[rid]; + } + else + break; + directive[i] = IDENTIFIER_POINTER (id); + } + if (i == 0) + error_at (dloc, "expected directive name"); + else + { + const struct c_omp_directive *dir + = c_omp_categorize_directive (directive[0], + directive[1], + directive[2]); + if (dir == NULL + || dir->kind == C_OMP_DIR_DECLARATIVE + || dir->kind == C_OMP_DIR_INFORMATIONAL + || dir->id == PRAGMA_OMP_END + || (!dir->second && directive[1]) + || (!dir->third && directive[2])) + error_at (dloc, "unknown OpenMP directive name in " + "%qs clause argument", p); + else + { + int id = dir - c_omp_directives; + if (bitmap_bit_p (p[0] == 'a' ? &contains_head + : &absent_head, id)) + error_at (dloc, "%<%s%s%s%s%s%> directive " + "mentioned in both %<absent%> and " + "%<contains%> clauses", + directive[0], + directive[1] ? " " : "", + directive[1] ? directive[1] : "", + directive[2] ? " " : "", + directive[2] ? directive[2] : ""); + else if (!bitmap_set_bit (p[0] == 'a' + ? &absent_head + : &contains_head, id)) + error_at (dloc, "%<%s%s%s%s%s%> directive " + "mentioned multiple times in %qs " + "clauses", + directive[0], + directive[1] ? " " : "", + directive[1] ? directive[1] : "", + directive[2] ? " " : "", + directive[2] ? directive[2] : "", p); + } + for (; i; --i) + c_parser_consume_token (parser); + } + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + break; + } + while (1); + parens.skip_until_found_close (parser); + } + } + else if (startswith (p, "ext_")) + { + warning_at (cloc, 0, "unknown assumption clause %qs", p); + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + matching_parens parens; + parens.consume_open (parser); + c_parser_balanced_token_sequence (parser); + parens.require_close (parser); + } + } + else + { + c_parser_consume_token (parser); + error_at (cloc, "expected assumption clause"); + break; + } + } + c_parser_skip_to_pragma_eol (parser); +} + +/* OpenMP 5.1 + #pragma omp assume clauses[optseq] new-line */ + +static void +c_parser_omp_assume (c_parser *parser, bool *if_p) +{ + c_parser_omp_assumption_clauses (parser, true); + add_stmt (c_parser_omp_structured_block (parser, if_p)); +} + +/* OpenMP 5.1 + #pragma omp assumes clauses[optseq] new-line */ + +static void +c_parser_omp_assumes (c_parser *parser) +{ + c_parser_consume_pragma (parser); + c_parser_omp_assumption_clauses (parser, false); +} + /* Main entry point to parsing most OpenMP pragmas. */ static void @@ -23404,6 +23675,9 @@ c_parser_omp_construct (c_parser *parser, bool *if_p) strcpy (p_name, "#pragma omp"); stmt = c_parser_omp_teams (loc, parser, p_name, mask, NULL, if_p); break; + case PRAGMA_OMP_ASSUME: + c_parser_omp_assume (parser, if_p); + return; default: gcc_unreachable (); } diff --git a/gcc/cfgcleanup.cc b/gcc/cfgcleanup.cc index a8b0139..a363e0b 100644 --- a/gcc/cfgcleanup.cc +++ b/gcc/cfgcleanup.cc @@ -2599,7 +2599,7 @@ trivially_empty_bb_p (basic_block bb) return value. Fill in *RET and *USE with the return and use insns if any found, otherwise NULL. All CLOBBERs are ignored. */ -static bool +bool bb_is_just_return (basic_block bb, rtx_insn **ret, rtx_insn **use) { *ret = *use = NULL; diff --git a/gcc/cfgcleanup.h b/gcc/cfgcleanup.h index a6d882f..f1021ca 100644 --- a/gcc/cfgcleanup.h +++ b/gcc/cfgcleanup.h @@ -30,5 +30,6 @@ extern int flow_find_head_matching_sequence (basic_block, basic_block, extern bool delete_unreachable_blocks (void); extern void delete_dead_jumptables (void); extern bool cleanup_cfg (int); +extern bool bb_is_just_return (basic_block, rtx_insn **, rtx_insn **); #endif /* GCC_CFGCLEANUP_H */ diff --git a/gcc/cfgrtl.cc b/gcc/cfgrtl.cc index a05c338..281a432 100644 --- a/gcc/cfgrtl.cc +++ b/gcc/cfgrtl.cc @@ -3901,6 +3901,7 @@ fixup_reorder_chain (void) /* Now add jumps and labels as needed to match the blocks new outgoing edges. */ + bool remove_unreachable_blocks = false; for (bb = ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb; bb ; bb = (basic_block) bb->aux) { @@ -4043,10 +4044,31 @@ fixup_reorder_chain (void) continue; } + /* If E_FALL->dest is just a return block, then we can emit a + return rather than a jump to the return block. */ + rtx_insn *ret, *use; + basic_block dest; + if (bb_is_just_return (e_fall->dest, &ret, &use) + && ((PATTERN (ret) == simple_return_rtx && targetm.have_simple_return ()) + || (PATTERN (ret) == ret_rtx && targetm.have_return ()))) + { + ret_label = PATTERN (ret); + dest = EXIT_BLOCK_PTR_FOR_FN (cfun); + + /* E_FALL->dest might become unreachable as a result of + replacing the jump with a return. So arrange to remove + unreachable blocks. */ + remove_unreachable_blocks = true; + } + else + { + dest = e_fall->dest; + } + /* We got here if we need to add a new jump insn. Note force_nonfallthru can delete E_FALL and thus we have to save E_FALL->src prior to the call to force_nonfallthru. */ - nb = force_nonfallthru_and_redirect (e_fall, e_fall->dest, ret_label); + nb = force_nonfallthru_and_redirect (e_fall, dest, ret_label); if (nb) { nb->aux = bb->aux; @@ -4134,6 +4156,12 @@ fixup_reorder_chain (void) ei_next (&ei2); } } + + /* Replacing a jump with a return may have exposed an unreachable + block. Conditionally remove them if such transformations were + made. */ + if (remove_unreachable_blocks) + delete_unreachable_blocks (); } /* Perform sanity checks on the insn chain. diff --git a/gcc/config.gcc b/gcc/config.gcc index 27ffce3..c1b1215 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -3941,6 +3941,9 @@ if test x$with_arch = x ; then mips*-*-vxworks) with_arch=mips2 ;; + nvptx-*) + with_arch=sm_30 + ;; esac # Avoid overriding --with-arch-32 and --with-arch-64 values. @@ -5293,6 +5296,25 @@ case "${target}" in esac ;; + nvptx-*) + supported_defaults=arch + TM_MULTILIB_CONFIG=$with_arch + #TODO 'sm_[...]' list per 'nvptx-sm.def'. + case $with_arch in + sm_30 ) + # OK; default. + ;; + sm_35 | sm_53 | sm_70 | sm_75 | sm_80 ) + # OK, but we'd like 'sm_30', too. + TM_MULTILIB_CONFIG="$TM_MULTILIB_CONFIG sm_30" + ;; + * ) + echo "Unknown arch used in --with-arch=$with_arch" 1>&2 + exit 1 + ;; + esac + ;; + powerpc*-*-* | rs6000-*-*) supported_defaults="abi cpu cpu_32 cpu_64 float tune tune_32 tune_64 advance_toolchain" diff --git a/gcc/config/aarch64/aarch64-arches.def b/gcc/config/aarch64/aarch64-arches.def index 3c2b165..6150448 100644 --- a/gcc/config/aarch64/aarch64-arches.def +++ b/gcc/config/aarch64/aarch64-arches.def @@ -41,5 +41,8 @@ AARCH64_ARCH("armv8.7-a", generic, 8_7A, 8, AARCH64_FL_FOR_ARCH8 AARCH64_ARCH("armv8.8-a", generic, 8_8A, 8, AARCH64_FL_FOR_ARCH8_8) AARCH64_ARCH("armv8-r", generic, 8R , 8, AARCH64_FL_FOR_ARCH8_R) AARCH64_ARCH("armv9-a", generic, 9A , 9, AARCH64_FL_FOR_ARCH9) +AARCH64_ARCH("armv9.1-a", generic, 9_1A, 9, AARCH64_FL_FOR_ARCH9_1) +AARCH64_ARCH("armv9.2-a", generic, 9_2A, 9, AARCH64_FL_FOR_ARCH9_2) +AARCH64_ARCH("armv9.3-a", generic, 9_3A, 9, AARCH64_FL_FOR_ARCH9_3) #undef AARCH64_ARCH diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h index 6f6bb70..f790de1 100644 --- a/gcc/config/aarch64/aarch64.h +++ b/gcc/config/aarch64/aarch64.h @@ -239,6 +239,15 @@ /* Armv8.8-a architecture extensions. */ #define AARCH64_FL_V8_8 (1ULL << 45) +/* Armv9.1-A. */ +#define AARCH64_FL_V9_1 (1ULL << 46) + +/* Armv9.2-A. */ +#define AARCH64_FL_V9_2 (1ULL << 47) + +/* Armv9.3-A. */ +#define AARCH64_FL_V9_3 (1ULL << 48) + /* Has FP and SIMD. */ #define AARCH64_FL_FPSIMD (AARCH64_FL_FP | AARCH64_FL_SIMD) @@ -273,6 +282,12 @@ #define AARCH64_FL_FOR_ARCH9 \ (AARCH64_FL_FOR_ARCH8_5 | AARCH64_FL_SVE | AARCH64_FL_SVE2 | AARCH64_FL_V9 \ | AARCH64_FL_F16) +#define AARCH64_FL_FOR_ARCH9_1 \ + (AARCH64_FL_FOR_ARCH9 | AARCH64_FL_FOR_ARCH8_6 | AARCH64_FL_V9_1) +#define AARCH64_FL_FOR_ARCH9_2 \ + (AARCH64_FL_FOR_ARCH9_1 | AARCH64_FL_FOR_ARCH8_7 | AARCH64_FL_V9_2) +#define AARCH64_FL_FOR_ARCH9_3 \ + (AARCH64_FL_FOR_ARCH9_2 | AARCH64_FL_FOR_ARCH8_8 | AARCH64_FL_V9_3) /* Macros to test ISA flags. */ @@ -312,6 +327,9 @@ #define AARCH64_ISA_V8_R (aarch64_isa_flags & AARCH64_FL_V8_R) #define AARCH64_ISA_PAUTH (aarch64_isa_flags & AARCH64_FL_PAUTH) #define AARCH64_ISA_V9 (aarch64_isa_flags & AARCH64_FL_V9) +#define AARCH64_ISA_V9_1 (aarch64_isa_flags & AARCH64_FL_V9_1) +#define AARCH64_ISA_V9_2 (aarch64_isa_flags & AARCH64_FL_V9_2) +#define AARCH64_ISA_V9_3 (aarch64_isa_flags & AARCH64_FL_V9_3) #define AARCH64_ISA_MOPS (aarch64_isa_flags & AARCH64_FL_MOPS) #define AARCH64_ISA_LS64 (aarch64_isa_flags & AARCH64_FL_LS64) diff --git a/gcc/config/i386/avx512fp16intrin.h b/gcc/config/i386/avx512fp16intrin.h index 2804151..75f7475 100644 --- a/gcc/config/i386/avx512fp16intrin.h +++ b/gcc/config/i386/avx512fp16intrin.h @@ -183,21 +183,21 @@ extern __inline __m128h __attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) _mm_setzero_ph (void) { - return _mm_set1_ph (0.0f); + return _mm_set1_ph (0.0f16); } extern __inline __m256h __attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) _mm256_setzero_ph (void) { - return _mm256_set1_ph (0.0f); + return _mm256_set1_ph (0.0f16); } extern __inline __m512h __attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) _mm512_setzero_ph (void) { - return _mm512_set1_ph (0.0f); + return _mm512_set1_ph (0.0f16); } extern __inline __m128h @@ -358,7 +358,8 @@ extern __inline __m128h __attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) _mm_set_sh (_Float16 __F) { - return _mm_set_ph (0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, __F); + return _mm_set_ph (0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16, + __F); } /* Create a vector with element 0 as *P and the rest zero. */ @@ -366,7 +367,7 @@ extern __inline __m128h __attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) _mm_load_sh (void const *__P) { - return _mm_set_ph (0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + return _mm_set_ph (0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16, *(_Float16 const *) __P); } diff --git a/gcc/config/i386/i386-builtins.cc b/gcc/config/i386/i386-builtins.cc index af2faee..b91aba1 100644 --- a/gcc/config/i386/i386-builtins.cc +++ b/gcc/config/i386/i386-builtins.cc @@ -1409,9 +1409,18 @@ ix86_init_builtin_types (void) lang_hooks.types.register_builtin_type (float80_type_node, "__float80"); /* The __float128 type. The node has already been created as - _Float128, so we only need to register the __float128 name for - it. */ - lang_hooks.types.register_builtin_type (float128_type_node, "__float128"); + _Float128, so for C we only need to register the __float128 name for + it. For C++, we create a distinct type which will mangle differently + (g) vs. _Float128 (DF128_) and behave backwards compatibly. */ + if (float128t_type_node == NULL_TREE) + { + float128t_type_node = make_node (REAL_TYPE); + TYPE_PRECISION (float128t_type_node) + = TYPE_PRECISION (float128_type_node); + SET_TYPE_MODE (float128t_type_node, TYPE_MODE (float128_type_node)); + layout_type (float128t_type_node); + } + lang_hooks.types.register_builtin_type (float128t_type_node, "__float128"); ix86_register_float16_builtin_type (); diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc index 5334363..6baff6d 100644 --- a/gcc/config/i386/i386-expand.cc +++ b/gcc/config/i386/i386-expand.cc @@ -19604,6 +19604,119 @@ expand_vec_perm_1 (struct expand_vec_perm_d *d) return false; } +/* A subroutine of ix86_expand_vec_perm_const_1. Try to implement D + in terms of a pair of shufps+ shufps/pshufd instructions. */ +static bool +expand_vec_perm_shufps_shufps (struct expand_vec_perm_d *d) +{ + unsigned char perm1[4]; + machine_mode vmode = d->vmode; + bool ok; + unsigned i, j, k, count = 0; + + if (d->one_operand_p + || (vmode != V4SImode && vmode != V4SFmode)) + return false; + + if (d->testing_p) + return true; + + for (i = 0; i < 4; ++i) + count += d->perm[i] > 3 ? 1 : 0; + + gcc_assert (count & 3); + + rtx tmp = gen_reg_rtx (vmode); + /* 2 from op0 and 2 from op1. */ + if (count == 2) + { + unsigned char perm2[4]; + for (i = 0, j = 0, k = 2; i < 4; ++i) + if (d->perm[i] & 4) + { + perm1[k++] = d->perm[i]; + perm2[i] = k - 1; + } + else + { + perm1[j++] = d->perm[i]; + perm2[i] = j - 1; + } + + /* shufps. */ + ok = expand_vselect_vconcat (tmp, d->op0, d->op1, + perm1, d->nelt, false); + gcc_assert (ok); + if (vmode == V4SImode && TARGET_SSE2) + /* pshufd. */ + ok = expand_vselect (d->target, tmp, + perm2, d->nelt, false); + else + { + /* shufps. */ + perm2[2] += 4; + perm2[3] += 4; + ok = expand_vselect_vconcat (d->target, tmp, tmp, + perm2, d->nelt, false); + } + gcc_assert (ok); + } + /* 3 from one op and 1 from another. */ + else + { + unsigned pair_idx = 8, lone_idx = 8, shift; + + /* Find the lone index. */ + for (i = 0; i < 4; ++i) + if ((d->perm[i] > 3 && count == 1) + || (d->perm[i] < 4 && count == 3)) + lone_idx = i; + + /* When lone_idx is not 0, it must from second op(count == 1). */ + gcc_assert (count == (lone_idx ? 1 : 3)); + + /* Find the pair index that sits in the same half as the lone index. */ + shift = lone_idx & 2; + pair_idx = 1 - lone_idx + 2 * shift; + + /* First permutate lone index and pair index into the same vector as + [ lone, lone, pair, pair ]. */ + perm1[1] = perm1[0] + = (count == 3) ? d->perm[lone_idx] : d->perm[lone_idx] - 4; + perm1[3] = perm1[2] + = (count == 3) ? d->perm[pair_idx] : d->perm[pair_idx] + 4; + + /* Alway put the vector contains lone indx at the first. */ + if (count == 1) + std::swap (d->op0, d->op1); + + /* shufps. */ + ok = expand_vselect_vconcat (tmp, d->op0, d->op1, + perm1, d->nelt, false); + gcc_assert (ok); + + /* Refine lone and pair index to original order. */ + perm1[shift] = lone_idx << 1; + perm1[shift + 1] = pair_idx << 1; + + /* Select the remaining 2 elements in another vector. */ + for (i = 2 - shift; i < 4 - shift; ++i) + perm1[i] = lone_idx == 1 ? d->perm[i] + 4 : d->perm[i]; + + /* Adjust to original selector. */ + if (lone_idx > 1) + std::swap (tmp, d->op1); + + /* shufps. */ + ok = expand_vselect_vconcat (d->target, tmp, d->op1, + perm1, d->nelt, false); + + gcc_assert (ok); + } + + return true; +} + /* A subroutine of ix86_expand_vec_perm_const_1. Try to implement D in terms of a pair of pshuflw + pshufhw instructions. */ @@ -22152,6 +22265,9 @@ ix86_expand_vec_perm_const_1 (struct expand_vec_perm_d *d) if (expand_vec_perm_2perm_pblendv (d, true)) return true; + if (expand_vec_perm_shufps_shufps (d)) + return true; + /* Try sequences of three instructions. */ if (expand_vec_perm_even_odd_pack (d)) diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc index ca799da..4386caf 100644 --- a/gcc/config/i386/i386.cc +++ b/gcc/config/i386/i386.cc @@ -22735,7 +22735,10 @@ ix86_mangle_type (const_tree type) return "DF16_"; case E_TFmode: /* __float128 is "g". */ - return "g"; + if (type == float128t_type_node) + return "g"; + /* _Float128 should mangle as "DF128_" done in generic code. */ + return NULL; case E_XFmode: /* "long double" or __float80 is "e". */ return "e"; diff --git a/gcc/config/ia64/ia64.cc b/gcc/config/ia64/ia64.cc index 50ae7aa..d510573 100644 --- a/gcc/config/ia64/ia64.cc +++ b/gcc/config/ia64/ia64.cc @@ -10466,11 +10466,19 @@ ia64_init_builtins (void) = build_pointer_type (build_qualified_type (char_type_node, TYPE_QUAL_CONST)); - (*lang_hooks.types.register_builtin_type) (float128_type_node, + if (float128t_type_node == NULL_TREE) + { + float128t_type_node = make_node (REAL_TYPE); + TYPE_PRECISION (float128t_type_node) + = TYPE_PRECISION (float128_type_node); + layout_type (float128t_type_node); + SET_TYPE_MODE (float128t_type_node, TYPE_MODE (float128_type_node)); + } + (*lang_hooks.types.register_builtin_type) (float128t_type_node, "__float128"); /* TFmode support builtins. */ - ftype = build_function_type_list (float128_type_node, NULL_TREE); + ftype = build_function_type_list (float128t_type_node, NULL_TREE); decl = add_builtin_function ("__builtin_infq", ftype, IA64_BUILTIN_INFQ, BUILT_IN_MD, NULL, NULL_TREE); @@ -10481,7 +10489,7 @@ ia64_init_builtins (void) NULL, NULL_TREE); ia64_builtins[IA64_BUILTIN_HUGE_VALQ] = decl; - ftype = build_function_type_list (float128_type_node, + ftype = build_function_type_list (float128t_type_node, const_string_type, NULL_TREE); decl = add_builtin_function ("__builtin_nanq", ftype, @@ -10496,8 +10504,8 @@ ia64_init_builtins (void) TREE_READONLY (decl) = 1; ia64_builtins[IA64_BUILTIN_NANSQ] = decl; - ftype = build_function_type_list (float128_type_node, - float128_type_node, + ftype = build_function_type_list (float128t_type_node, + float128t_type_node, NULL_TREE); decl = add_builtin_function ("__builtin_fabsq", ftype, IA64_BUILTIN_FABSQ, BUILT_IN_MD, @@ -10505,9 +10513,9 @@ ia64_init_builtins (void) TREE_READONLY (decl) = 1; ia64_builtins[IA64_BUILTIN_FABSQ] = decl; - ftype = build_function_type_list (float128_type_node, - float128_type_node, - float128_type_node, + ftype = build_function_type_list (float128t_type_node, + float128t_type_node, + float128t_type_node, NULL_TREE); decl = add_builtin_function ("__builtin_copysignq", ftype, IA64_BUILTIN_COPYSIGNQ, BUILT_IN_MD, diff --git a/gcc/config/nvptx/gen-multilib-matches.sh b/gcc/config/nvptx/gen-multilib-matches.sh new file mode 100755 index 0000000..9a5878e --- /dev/null +++ b/gcc/config/nvptx/gen-multilib-matches.sh @@ -0,0 +1,60 @@ +#!/bin/sh + +# Print nvptx 'MULTILIB_MATCHES' + +# Copyright (C) 2022 Free Software Foundation, Inc. +# +# This file is part of GCC. +# +# GCC is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GCC is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +set -e + +nvptx_sm_def="$1/nvptx-sm.def" +multilib_options_isa_default=$2 +multilib_options_isa_list=$3 + +sms=$(grep ^NVPTX_SM $nvptx_sm_def | sed 's/.*(//;s/,.*//') + +# Every variant in 'sms' has to either be remapped to the default variant +# ('.', which is always built), or does get built as non-default variant +# ('misa=sm_SM'; thus not remapped), or has to be remapped to the "next lower" +# variant that does get built. + +# The "lowest" variant has to be built. +sm_next_lower=INVALID + +for sm in $sms; do + if [ x"sm_$sm" = x"$multilib_options_isa_default" ]; then + sm_map=. + elif expr " $multilib_options_isa_list " : ".* sm_$sm " > /dev/null; then + sm_map= + else + sm_map=$sm_next_lower + fi + + if [ x"$sm_map" = x ]; then + sm_next_lower=$sm + else + # Output format as required for 'MULTILIB_MATCHES'. + if [ x"$sm_map" = x. ]; then + echo ".=misa?sm_$sm" + else + echo "misa?sm_$sm_map=misa?sm_$sm" + fi + + sm_next_lower=$sm_map + fi +done diff --git a/gcc/config/nvptx/nvptx.cc b/gcc/config/nvptx/nvptx.cc index 49cc681..2fe120b 100644 --- a/gcc/config/nvptx/nvptx.cc +++ b/gcc/config/nvptx/nvptx.cc @@ -334,6 +334,10 @@ nvptx_option_override (void) { init_machine_status = nvptx_init_machine_status; + /* Via nvptx 'OPTION_DEFAULT_SPECS', '-misa' always appears on the command + line. */ + gcc_checking_assert (OPTION_SET_P (ptx_isa_option)); + handle_ptx_version_option (); /* Set toplevel_reorder, unless explicitly disabled. We need diff --git a/gcc/config/nvptx/nvptx.h b/gcc/config/nvptx/nvptx.h index dc9cad1..0afc83b 100644 --- a/gcc/config/nvptx/nvptx.h +++ b/gcc/config/nvptx/nvptx.h @@ -27,6 +27,14 @@ /* Run-time Target. */ +/* Use '--with-arch' for default '-misa'. */ +#define OPTION_DEFAULT_SPECS \ + { "arch", "%{!misa=*:-misa=%(VALUE)}" }, \ + +/* Assembler supports '-v' option; handle similar to + '../../gcc.cc:asm_options', 'HAVE_GNU_AS'. */ +#define ASM_SPEC "%{v}" + #define STARTFILE_SPEC "%{mmainkernel:crt0.o}" #define TARGET_CPU_CPP_BUILTINS() nvptx_cpu_cpp_builtins () diff --git a/gcc/config/nvptx/nvptx.opt b/gcc/config/nvptx/nvptx.opt index c5a5668..71d3b68 100644 --- a/gcc/config/nvptx/nvptx.opt +++ b/gcc/config/nvptx/nvptx.opt @@ -53,7 +53,7 @@ Target Mask(GOMP) Generate code for OpenMP offloading: enables -msoft-stack and -muniform-simt. misa= -Target RejectNegative ToLower Joined Enum(ptx_isa) Var(ptx_isa_option) Init(PTX_ISA_SM30) +Target RejectNegative ToLower Joined Enum(ptx_isa) Var(ptx_isa_option) Specify the PTX ISA target architecture to use. march= diff --git a/gcc/config/nvptx/t-nvptx b/gcc/config/nvptx/t-nvptx index 2b68149..9c5cbda 100644 --- a/gcc/config/nvptx/t-nvptx +++ b/gcc/config/nvptx/t-nvptx @@ -31,4 +31,33 @@ s-nvptx-gen-opt: $(srcdir)/config/nvptx/nvptx-sm.def \ tmp-nvptx-gen.opt $(srcdir)/config/nvptx/nvptx-gen.opt $(STAMP) s-nvptx-gen-opt -MULTILIB_OPTIONS = mgomp mptx=3.1 + +# Multilib setup. + +MULTILIB_OPTIONS = +MULTILIB_MATCHES = +MULTILIB_EXCEPTIONS = + +MULTILIB_OPTIONS += mgomp + +multilib_options_isa_list := $(TM_MULTILIB_CONFIG) +multilib_options_isa_default := $(word 1,$(multilib_options_isa_list)) +multilib_options_misa_list := $(addprefix misa=,$(multilib_options_isa_list)) +# Add the requested '-misa' variants as a multilib option ('misa=VAR1/misa=VAR2/misa=VAR3' etc.): +empty := +space := $(empty) $(empty) +MULTILIB_OPTIONS += $(subst $(space),/,$(multilib_options_misa_list)) +# ..., and remap '-misa' variants as appropriate: +multilib_matches := $(shell $(srcdir)/config/nvptx/gen-multilib-matches.sh $(srcdir)/config/nvptx $(multilib_options_isa_default) "$(multilib_options_isa_list)") +MULTILIB_MATCHES += $(multilib_matches) +# ..., and don't actually build what's the default '-misa': +MULTILIB_EXCEPTIONS += *misa=$(multilib_options_isa_default)* + +MULTILIB_OPTIONS += mptx=3.1 +# Filter out invalid '-misa'/'-mptx=3.1' combinations; per 'nvptx-sm.def', +# 'nvptx.opt:ptx_version', 'nvptx.cc:first_ptx_version_supporting_sm' +# (that is, '-mptx=3.1' only for sm_30, sm_35 variants): +MULTILIB_EXCEPTIONS += $(foreach misa,$(filter-out %=sm_30 %=sm_35,$(multilib_options_misa_list)),*$(misa)/mptx=3.1) +# ..., and special care has to be taken if '-mptx=3.1' is invalid for the +# default variant: +MULTILIB_EXCEPTIONS += $(if $(filter-out sm_30 sm_35,$(multilib_options_isa_default)),mgomp/mptx=3.1 mptx=3.1) diff --git a/gcc/config/rs6000/rs6000-builtin.cc b/gcc/config/rs6000/rs6000-builtin.cc index 3ce729c..90ab39d 100644 --- a/gcc/config/rs6000/rs6000-builtin.cc +++ b/gcc/config/rs6000/rs6000-builtin.cc @@ -733,7 +733,22 @@ rs6000_init_builtins (void) if (TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128) ieee128_float_type_node = long_double_type_node; else - ieee128_float_type_node = float128_type_node; + { + /* For C we only need to register the __ieee128 name for + it. For C++, we create a distinct type which will mangle + differently (u9__ieee128) vs. _Float128 (DF128_) and behave + backwards compatibly. */ + if (float128t_type_node == NULL_TREE) + { + float128t_type_node = make_node (REAL_TYPE); + TYPE_PRECISION (float128t_type_node) + = TYPE_PRECISION (float128_type_node); + layout_type (float128t_type_node); + SET_TYPE_MODE (float128t_type_node, + TYPE_MODE (float128_type_node)); + } + ieee128_float_type_node = float128t_type_node; + } t = build_qualified_type (ieee128_float_type_node, TYPE_QUAL_CONST); lang_hooks.types.register_builtin_type (ieee128_float_type_node, "__ieee128"); diff --git a/gcc/config/rs6000/rs6000-c.cc b/gcc/config/rs6000/rs6000-c.cc index ca9cc42..5660946 100644 --- a/gcc/config/rs6000/rs6000-c.cc +++ b/gcc/config/rs6000/rs6000-c.cc @@ -808,6 +808,7 @@ static inline bool is_float128_p (tree t) { return (t == float128_type_node + || (t && t == float128t_type_node) || (TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128 && t == long_double_type_node)); diff --git a/gcc/config/rs6000/rs6000-logue.cc b/gcc/config/rs6000/rs6000-logue.cc index 80a2e0d..f575e69 100644 --- a/gcc/config/rs6000/rs6000-logue.cc +++ b/gcc/config/rs6000/rs6000-logue.cc @@ -4920,7 +4920,7 @@ rs6000_emit_epilogue (enum epilogue_type epilogue_type) a REG_CFA_DEF_CFA note, but that's OK; A duplicate is discarded by dwarf2cfi.cc/dwarf2out.cc, and in any case would be harmless if emitted. */ - if (frame_pointer_needed) + if (frame_pointer_needed_indeed) { insn = get_last_insn (); add_reg_note (insn, REG_CFA_DEF_CFA, diff --git a/gcc/config/rs6000/rs6000.cc b/gcc/config/rs6000/rs6000.cc index 5f347e9..bbe21ea 100644 --- a/gcc/config/rs6000/rs6000.cc +++ b/gcc/config/rs6000/rs6000.cc @@ -20272,7 +20272,11 @@ rs6000_mangle_type (const_tree type) if (SCALAR_FLOAT_TYPE_P (type) && FLOAT128_IBM_P (TYPE_MODE (type))) return "g"; - if (SCALAR_FLOAT_TYPE_P (type) && FLOAT128_IEEE_P (TYPE_MODE (type))) + if (SCALAR_FLOAT_TYPE_P (type) + && FLOAT128_IEEE_P (TYPE_MODE (type)) + /* _Float128 should mangle as DF128_ (done in generic code) + rather than u9__ieee128 (used for __ieee128 and __float128). */ + && type != float128_type_node) return "u9__ieee128"; if (type == vector_pair_type_node) diff --git a/gcc/config/rs6000/vector.md b/gcc/config/rs6000/vector.md index a0d33d2..0171705 100644 --- a/gcc/config/rs6000/vector.md +++ b/gcc/config/rs6000/vector.md @@ -1475,7 +1475,7 @@ [(match_operand:VEC_L 0 "vlogical_operand") (match_operand:VEC_L 1 "vlogical_operand") (match_operand:QI 2 "reg_or_short_operand")] - "TARGET_ALTIVEC" + "VECTOR_UNIT_ALTIVEC_OR_VSX_P (<MODE>mode)" { rtx bitshift = operands[2]; rtx shift; diff --git a/gcc/config/s390/s390.cc b/gcc/config/s390/s390.cc index 3ae586c..9861913 100644 --- a/gcc/config/s390/s390.cc +++ b/gcc/config/s390/s390.cc @@ -3648,7 +3648,7 @@ s390_rtx_costs (rtx x, machine_mode mode, int outer_code, *total = 0; return true; case SET: { - rtx dest = SET_DEST (x); + rtx dst = SET_DEST (x); rtx src = SET_SRC (x); switch (GET_CODE (src)) @@ -3669,7 +3669,6 @@ s390_rtx_costs (rtx x, machine_mode mode, int outer_code, slightly more expensive than a normal load. */ *total = COSTS_N_INSNS (1) + 2; - rtx dst = SET_DEST (src); rtx then = XEXP (src, 1); rtx els = XEXP (src, 2); @@ -3696,25 +3695,25 @@ s390_rtx_costs (rtx x, machine_mode mode, int outer_code, break; } - switch (GET_CODE (dest)) + switch (GET_CODE (dst)) { case SUBREG: - if (!REG_P (SUBREG_REG (dest))) + if (!REG_P (SUBREG_REG (dst))) *total += rtx_cost (SUBREG_REG (src), VOIDmode, SET, 0, speed); /* fallthrough */ case REG: /* If this is a VR -> VR copy, count the number of registers. */ - if (VECTOR_MODE_P (GET_MODE (dest)) && REG_P (src)) + if (VECTOR_MODE_P (GET_MODE (dst)) && REG_P (src)) { - int nregs = s390_hard_regno_nregs (VR0_REGNUM, GET_MODE (dest)); + int nregs = s390_hard_regno_nregs (VR0_REGNUM, GET_MODE (dst)); *total = COSTS_N_INSNS (nregs); } /* Same for GPRs. */ else if (REG_P (src)) { int nregs - = s390_hard_regno_nregs (GPR0_REGNUM, GET_MODE (dest)); + = s390_hard_regno_nregs (GPR0_REGNUM, GET_MODE (dst)); *total = COSTS_N_INSNS (nregs); } else @@ -3722,7 +3721,7 @@ s390_rtx_costs (rtx x, machine_mode mode, int outer_code, *total += rtx_cost (src, mode, SET, 1, speed); return true; case MEM: { - rtx address = XEXP (dest, 0); + rtx address = XEXP (dst, 0); rtx tmp; HOST_WIDE_INT tmp2; if (s390_loadrelative_operand_p (address, &tmp, &tmp2)) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index b9b2729..ca5015e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,28 @@ +2022-09-26 Marek Polacek <polacek@redhat.com> + + PR c++/106656 + * typeck2.cc (array_string_literal_compatible_p): Allow + initializing arrays of char or unsigned char by a UTF-8 string literal. + +2022-09-26 Marek Polacek <polacek@redhat.com> + + PR c++/106784 + * method.cc (is_convertible_helper): New. + (is_convertible): Use it. + (is_nothrow_convertible): Likewise. + +2022-09-26 Patrick Palka <ppalka@redhat.com> + + PR c++/107033 + * module.cc (trees_in::decl_value): In the MK_partial case for + a variable template partial specialization, pass decl_p=true to + add_mergeable_specialization, and set spec to the VAR_DECL not + the TEMPLATE_DECL. + * pt.cc (add_mergeable_specialization): For a variable template + partial specialization, set the TREE_TYPE of the new + DECL_TEMPLATE_SPECIALIZATIONS node to the TREE_TYPE of the + VAR_DECL not the VAR_DECL itself. + 2022-09-23 Marek Polacek <polacek@redhat.com> PR c++/106784 diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 7e9289f..fc86b74 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -1541,6 +1541,22 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p, || (underlying_type && same_type_p (to, underlying_type))) && next_conversion (conv)->rank <= cr_promotion) conv->rank = cr_promotion; + + /* A prvalue of floating-point type can be converted to a prvalue of + another floating-point type with a greater or equal conversion + rank ([conv.rank]). A prvalue of standard floating-point type can + be converted to a prvalue of another standard floating-point type. + For backwards compatibility with handling __float128 and other + non-standard floating point types, allow all implicit floating + point conversions if neither type is extended floating-point + type and if at least one of them is, fail if they have unordered + conversion rank or from has higher conversion rank. */ + if (fcode == REAL_TYPE + && tcode == REAL_TYPE + && (extended_float_type_p (from) + || extended_float_type_p (to)) + && cp_compare_floating_point_conversion_ranks (from, to) >= 2) + conv->bad_p = true; } else if (fcode == VECTOR_TYPE && tcode == VECTOR_TYPE && vector_types_convertible_p (from, to, false)) @@ -5842,6 +5858,21 @@ build_conditional_expr (const op_location_t &loc, /* In this case, there is always a common type. */ result_type = type_after_usual_arithmetic_conversions (arg2_type, arg3_type); + if (result_type == error_mark_node + && TREE_CODE (arg2_type) == REAL_TYPE + && TREE_CODE (arg3_type) == REAL_TYPE + && (extended_float_type_p (arg2_type) + || extended_float_type_p (arg3_type)) + && cp_compare_floating_point_conversion_ranks (arg2_type, + arg3_type) == 3) + { + if (complain & tf_error) + error_at (loc, "operands to %<?:%> of types %qT and %qT " + "have unordered conversion rank", + arg2_type, arg3_type); + return error_mark_node; + } + if (complain & tf_warning) do_warn_double_promotion (result_type, arg2_type, arg3_type, "implicit conversion from %qH to %qI to " @@ -7906,6 +7937,27 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum, "direct-initialization", totype, TREE_TYPE (expr)); + if (TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE + && TREE_CODE (totype) == REAL_TYPE + && (extended_float_type_p (TREE_TYPE (expr)) + || extended_float_type_p (totype))) + switch (cp_compare_floating_point_conversion_ranks (TREE_TYPE (expr), + totype)) + { + case 2: + pedwarn (loc, 0, "converting to %qH from %qI with greater " + "conversion rank", totype, TREE_TYPE (expr)); + complained = true; + break; + case 3: + pedwarn (loc, 0, "converting to %qH from %qI with unordered " + "conversion ranks", totype, TREE_TYPE (expr)); + complained = true; + break; + default: + break; + } + for (; t ; t = next_conversion (t)) { if (t->kind == ck_user && t->cand->reason) @@ -8531,7 +8583,8 @@ convert_arg_to_ellipsis (tree arg, tsubst_flags_t complain) if (TREE_CODE (arg_type) == REAL_TYPE && (TYPE_PRECISION (arg_type) < TYPE_PRECISION (double_type_node)) - && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (arg_type))) + && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (arg_type)) + && !extended_float_type_p (arg_type)) { if ((complain & tf_warning) && warn_double_promotion && !c_inhibit_evaluation_warnings) @@ -11719,6 +11772,81 @@ compare_ics (conversion *ics1, conversion *ics2) return 1; } + { + /* A conversion in either direction between floating-point type FP1 and + floating-point type FP2 is better than a conversion in the same + direction between FP1 and arithmetic type T3 if + - the floating-point conversion rank of FP1 is equal to the rank of + FP2, and + - T3 is not a floating-point type, or T3 is a floating-point type + whose rank is not equal to the rank of FP1, or the floating-point + conversion subrank of FP2 is greater than the subrank of T3. */ + tree fp1 = from_type1; + tree fp2 = to_type1; + tree fp3 = from_type2; + tree t3 = to_type2; + int ret = 1; + if (TYPE_MAIN_VARIANT (fp2) == TYPE_MAIN_VARIANT (t3)) + { + std::swap (fp1, fp2); + std::swap (fp3, t3); + } + if (TYPE_MAIN_VARIANT (fp1) == TYPE_MAIN_VARIANT (fp3) + && TREE_CODE (fp1) == REAL_TYPE + /* Only apply this rule if at least one of the 3 types is + extended floating-point type, otherwise keep them as + before for compatibility reasons with types like __float128. + float, double and long double alone have different conversion + ranks and so when just those 3 types are involved, this + rule doesn't trigger. */ + && (extended_float_type_p (fp1) + || (TREE_CODE (fp2) == REAL_TYPE && extended_float_type_p (fp2)) + || (TREE_CODE (t3) == REAL_TYPE && extended_float_type_p (t3)))) + { + if (TREE_CODE (fp2) != REAL_TYPE) + { + ret = -ret; + std::swap (fp2, t3); + } + if (TREE_CODE (fp2) == REAL_TYPE) + { + /* cp_compare_floating_point_conversion_ranks returns -1, 0 or 1 + if the conversion rank is equal (-1 or 1 if the subrank is + different). */ + if (IN_RANGE (cp_compare_floating_point_conversion_ranks (fp1, + fp2), + -1, 1)) + { + /* Conversion ranks of FP1 and FP2 are equal. */ + if (TREE_CODE (t3) != REAL_TYPE + || !IN_RANGE (cp_compare_floating_point_conversion_ranks + (fp1, t3), + -1, 1)) + /* FP1 <-> FP2 conversion is better. */ + return ret; + int c = cp_compare_floating_point_conversion_ranks (fp2, t3); + gcc_assert (IN_RANGE (c, -1, 1)); + if (c == 1) + /* Conversion subrank of FP2 is greater than subrank of T3. + FP1 <-> FP2 conversion is better. */ + return ret; + else if (c == -1) + /* Conversion subrank of FP2 is less than subrank of T3. + FP1 <-> T3 conversion is better. */ + return -ret; + } + else if (TREE_CODE (t3) == REAL_TYPE + && IN_RANGE (cp_compare_floating_point_conversion_ranks + (fp1, t3), + -1, 1)) + /* Conversion ranks of FP1 and FP2 are not equal, conversion + ranks of FP1 and T3 are equal. + FP1 <-> T3 conversion is better. */ + return -ret; + } + } + } + if (TYPE_PTR_P (from_type1) && TYPE_PTR_P (from_type2) && TYPE_PTR_P (to_type1) @@ -12133,10 +12261,14 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn, len = cand1->num_convs; if (len != cand2->num_convs) { - int static_1 = DECL_STATIC_FUNCTION_P (cand1->fn); - int static_2 = DECL_STATIC_FUNCTION_P (cand2->fn); + int static_1 = (TREE_CODE (cand1->fn) == FUNCTION_DECL + && DECL_STATIC_FUNCTION_P (cand1->fn)); + int static_2 = (TREE_CODE (cand2->fn) == FUNCTION_DECL + && DECL_STATIC_FUNCTION_P (cand2->fn)); - if (DECL_CONSTRUCTOR_P (cand1->fn) + if (TREE_CODE (cand1->fn) == FUNCTION_DECL + && TREE_CODE (cand2->fn) == FUNCTION_DECL + && DECL_CONSTRUCTOR_P (cand1->fn) && is_list_ctor (cand1->fn) != is_list_ctor (cand2->fn)) /* We're comparing a near-match list constructor and a near-match non-list constructor. Just treat them as unordered. */ @@ -12145,9 +12277,20 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn, gcc_assert (static_1 != static_2); if (static_1) - off2 = 1; + { + /* C++23 [over.best.ics.general] says: + When the parameter is the implicit object parameter of a static + member function, the implicit conversion sequence is a standard + conversion sequence that is neither better nor worse than any + other standard conversion sequence. */ + if (CONVERSION_RANK (cand2->convs[0]) >= cr_user) + winner = 1; + off2 = 1; + } else { + if (CONVERSION_RANK (cand1->convs[0]) >= cr_user) + winner = -1; off1 = 1; --len; } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index e4d8920..99b486b8 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -504,6 +504,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; OVL_NESTED_P (in OVERLOAD) DECL_MODULE_EXPORT_P (in _DECL) PACK_EXPANSION_FORCE_EXTRA_ARGS_P (in *_PACK_EXPANSION) + LAMBDA_EXPR_STATIC_P (in LAMBDA_EXPR) 4: IDENTIFIER_MARKED (IDENTIFIER_NODEs) TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR, CALL_EXPR, or FIELD_DECL). @@ -1490,6 +1491,10 @@ enum cp_lambda_default_capture_mode_type { #define LAMBDA_EXPR_CAPTURE_OPTIMIZED(NODE) \ TREE_LANG_FLAG_2 (LAMBDA_EXPR_CHECK (NODE)) +/* Predicate tracking whether the lambda was declared 'static'. */ +#define LAMBDA_EXPR_STATIC_P(NODE) \ + TREE_LANG_FLAG_3 (LAMBDA_EXPR_CHECK (NODE)) + /* True if this TREE_LIST in LAMBDA_EXPR_CAPTURE_LIST is for an explicit capture. */ #define LAMBDA_CAPTURE_EXPLICIT_P(NODE) \ @@ -1834,6 +1839,10 @@ struct GTY(()) omp_declare_target_attr { bool attr_syntax; }; +struct GTY(()) omp_begin_assumes_data { + bool attr_syntax; +}; + /* Global state. */ struct GTY(()) saved_scope { @@ -1881,6 +1890,7 @@ struct GTY(()) saved_scope { hash_map<tree, tree> *GTY((skip)) x_local_specializations; vec<omp_declare_target_attr, va_gc> *omp_declare_target_attribute; + vec<omp_begin_assumes_data, va_gc> *omp_begin_assumes; struct saved_scope *prev; }; @@ -7946,6 +7956,7 @@ extern tree require_complete_type (tree, extern tree complete_type (tree); extern tree complete_type_or_else (tree, tree); extern tree complete_type_or_maybe_complain (tree, tree, tsubst_flags_t); +extern int cp_compare_floating_point_conversion_ranks (tree, tree); inline bool type_unknown_p (const_tree); enum { ce_derived, ce_type, ce_normal, ce_exact }; extern bool comp_except_specs (const_tree, const_tree, int); @@ -8688,6 +8699,18 @@ struct push_access_scope_guard } }; +/* True if TYPE is an extended floating-point type. */ + +inline bool +extended_float_type_p (tree type) +{ + type = TYPE_MAIN_VARIANT (type); + for (int i = 0; i < NUM_FLOATN_NX_TYPES; ++i) + if (type == FLOATN_TYPE_NODE (i)) + return true; + return false; +} + #if CHECKING_P namespace selftest { extern void run_cp_tests (void); diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 80467c1..fb85564 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -12095,12 +12095,7 @@ grokdeclarator (const cp_declarator *declarator, } if (declspecs->conflicting_specifiers_p) - { - error_at (min_location (declspecs->locations[ds_typedef], - declspecs->locations[ds_storage_class]), - "conflicting specifiers in declaration of %qs", name); - return error_mark_node; - } + return error_mark_node; /* Extract the basic type from the decl-specifier-seq. */ type = declspecs->type; @@ -15305,8 +15300,25 @@ grok_op_properties (tree decl, bool complain) an enumeration, or a reference to an enumeration. 13.4.0.6 */ if (! methodp || DECL_STATIC_FUNCTION_P (decl)) { + if (operator_code == CALL_EXPR) + { + if (! DECL_STATIC_FUNCTION_P (decl)) + { + error_at (loc, "%qD must be a member function", decl); + return false; + } + if (cxx_dialect < cxx23 + /* For lambdas we diagnose static lambda specifier elsewhere. */ + && ! LAMBDA_FUNCTION_P (decl) + /* For instantiations, we have diagnosed this already. */ + && ! DECL_USE_TEMPLATE (decl)) + pedwarn (loc, OPT_Wc__23_extensions, "%qD may be a static member " + "function only with %<-std=c++23%> or %<-std=gnu++23%>", decl); + /* There are no further restrictions on the arguments to an + overloaded "operator ()". */ + return true; + } if (operator_code == TYPE_EXPR - || operator_code == CALL_EXPR || operator_code == COMPONENT_REF || operator_code == ARRAY_REF || operator_code == NOP_EXPR) diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc index 94181e7..0389f35 100644 --- a/gcc/cp/error.cc +++ b/gcc/cp/error.cc @@ -1692,7 +1692,13 @@ dump_lambda_function (cxx_pretty_printer *pp, { /* A lambda's signature is essentially its "type". */ dump_type (pp, DECL_CONTEXT (fn), flags); - if (!(TYPE_QUALS (class_of_this_parm (TREE_TYPE (fn))) & TYPE_QUAL_CONST)) + if (TREE_CODE (TREE_TYPE (fn)) == FUNCTION_TYPE) + { + pp->padding = pp_before; + pp_c_ws_string (pp, "static"); + } + else if (!(TYPE_QUALS (class_of_this_parm (TREE_TYPE (fn))) + & TYPE_QUAL_CONST)) { pp->padding = pp_before; pp_c_ws_string (pp, "mutable"); diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc index 3ee1fe9..e9d5d4d 100644 --- a/gcc/cp/lambda.cc +++ b/gcc/cp/lambda.cc @@ -1099,7 +1099,9 @@ maybe_add_lambda_conv_op (tree type) tree optype = TREE_TYPE (callop); tree fn_result = TREE_TYPE (optype); - tree thisarg = build_int_cst (TREE_TYPE (DECL_ARGUMENTS (callop)), 0); + tree thisarg = NULL_TREE; + if (TREE_CODE (optype) == METHOD_TYPE) + thisarg = build_int_cst (TREE_TYPE (DECL_ARGUMENTS (callop)), 0); if (generic_lambda_p) { ++processing_template_decl; @@ -1109,18 +1111,25 @@ maybe_add_lambda_conv_op (tree type) return expression for a deduced return call op to allow for simple implementation of the conversion operator. */ - tree instance = cp_build_fold_indirect_ref (thisarg); - tree objfn = lookup_template_function (DECL_NAME (callop), - DECL_TI_ARGS (callop)); - objfn = build_min (COMPONENT_REF, NULL_TREE, - instance, objfn, NULL_TREE); - int nargs = list_length (DECL_ARGUMENTS (callop)) - 1; + tree objfn; + int nargs = list_length (DECL_ARGUMENTS (callop)); + if (thisarg) + { + tree instance = cp_build_fold_indirect_ref (thisarg); + objfn = lookup_template_function (DECL_NAME (callop), + DECL_TI_ARGS (callop)); + objfn = build_min (COMPONENT_REF, NULL_TREE, + instance, objfn, NULL_TREE); + --nargs; + call = prepare_op_call (objfn, nargs); + } + else + objfn = callop; - call = prepare_op_call (objfn, nargs); if (type_uses_auto (fn_result)) decltype_call = prepare_op_call (objfn, nargs); } - else + else if (thisarg) { direct_argvec = make_tree_vector (); direct_argvec->quick_push (thisarg); @@ -1135,9 +1144,11 @@ maybe_add_lambda_conv_op (tree type) tree fn_args = NULL_TREE; { int ix = 0; - tree src = DECL_CHAIN (DECL_ARGUMENTS (callop)); + tree src = FUNCTION_FIRST_USER_PARM (callop); tree tgt = NULL; + if (!thisarg && !decltype_call) + src = NULL_TREE; while (src) { tree new_node = copy_node (src); @@ -1160,12 +1171,15 @@ maybe_add_lambda_conv_op (tree type) if (generic_lambda_p) { tree a = tgt; - if (DECL_PACK_P (tgt)) + if (thisarg) { - a = make_pack_expansion (a); - PACK_EXPANSION_LOCAL_P (a) = true; + if (DECL_PACK_P (tgt)) + { + a = make_pack_expansion (a); + PACK_EXPANSION_LOCAL_P (a) = true; + } + CALL_EXPR_ARG (call, ix) = a; } - CALL_EXPR_ARG (call, ix) = a; if (decltype_call) { @@ -1193,7 +1207,7 @@ maybe_add_lambda_conv_op (tree type) tf_warning_or_error); } } - else + else if (thisarg) { /* Don't warn on deprecated or unavailable lambda declarations, unless the lambda is actually called. */ @@ -1203,10 +1217,14 @@ maybe_add_lambda_conv_op (tree type) direct_argvec->address ()); } - CALL_FROM_THUNK_P (call) = 1; - SET_EXPR_LOCATION (call, UNKNOWN_LOCATION); + if (thisarg) + { + CALL_FROM_THUNK_P (call) = 1; + SET_EXPR_LOCATION (call, UNKNOWN_LOCATION); + } - tree stattype = build_function_type (fn_result, FUNCTION_ARG_CHAIN (callop)); + tree stattype + = build_function_type (fn_result, FUNCTION_FIRST_USER_PARMTYPE (callop)); stattype = (cp_build_type_attribute_variant (stattype, TYPE_ATTRIBUTES (optype))); if (flag_noexcept_type @@ -1249,6 +1267,41 @@ maybe_add_lambda_conv_op (tree type) add_method (type, fn, false); + if (thisarg == NULL_TREE) + { + /* For static lambda, just return operator(). */ + if (nested) + push_function_context (); + else + /* Still increment function_depth so that we don't GC in the + middle of an expression. */ + ++function_depth; + + /* Generate the body of the conversion op. */ + + start_preparsed_function (convfn, NULL_TREE, + SF_PRE_PARSED | SF_INCLASS_INLINE); + tree body = begin_function_body (); + tree compound_stmt = begin_compound_stmt (0); + + /* decl_needed_p needs to see that it's used. */ + TREE_USED (callop) = 1; + finish_return_stmt (decay_conversion (callop, tf_warning_or_error)); + + finish_compound_stmt (compound_stmt); + finish_function_body (body); + + fn = finish_function (/*inline_p=*/true); + if (!generic_lambda_p) + expand_or_defer_fn (fn); + + if (nested) + pop_function_context (); + else + --function_depth; + return; + } + /* Generic thunk code fails for varargs; we'll complain in mark_used if the conversion op is used. */ if (varargs_function_p (callop)) diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc index 75388e9..00d283f 100644 --- a/gcc/cp/mangle.cc +++ b/gcc/cp/mangle.cc @@ -2648,63 +2648,24 @@ write_builtin_type (tree type) write_string ("Dd"); else if (type == dfloat128_type_node || type == fallback_dfloat128_type) write_string ("De"); + else if (type == float16_type_node) + write_string ("DF16_"); + else if (type == float32_type_node) + write_string ("DF32_"); + else if (type == float64_type_node) + write_string ("DF64_"); + else if (type == float128_type_node) + write_string ("DF128_"); + else if (type == float32x_type_node) + write_string ("DF32x"); + else if (type == float64x_type_node) + write_string ("DF64x"); + else if (type == float128x_type_node) + write_string ("DF128x"); else gcc_unreachable (); break; - case FIXED_POINT_TYPE: - write_string ("DF"); - if (GET_MODE_IBIT (TYPE_MODE (type)) > 0) - write_unsigned_number (GET_MODE_IBIT (TYPE_MODE (type))); - if (type == fract_type_node - || type == sat_fract_type_node - || type == accum_type_node - || type == sat_accum_type_node) - write_char ('i'); - else if (type == unsigned_fract_type_node - || type == sat_unsigned_fract_type_node - || type == unsigned_accum_type_node - || type == sat_unsigned_accum_type_node) - write_char ('j'); - else if (type == short_fract_type_node - || type == sat_short_fract_type_node - || type == short_accum_type_node - || type == sat_short_accum_type_node) - write_char ('s'); - else if (type == unsigned_short_fract_type_node - || type == sat_unsigned_short_fract_type_node - || type == unsigned_short_accum_type_node - || type == sat_unsigned_short_accum_type_node) - write_char ('t'); - else if (type == long_fract_type_node - || type == sat_long_fract_type_node - || type == long_accum_type_node - || type == sat_long_accum_type_node) - write_char ('l'); - else if (type == unsigned_long_fract_type_node - || type == sat_unsigned_long_fract_type_node - || type == unsigned_long_accum_type_node - || type == sat_unsigned_long_accum_type_node) - write_char ('m'); - else if (type == long_long_fract_type_node - || type == sat_long_long_fract_type_node - || type == long_long_accum_type_node - || type == sat_long_long_accum_type_node) - write_char ('x'); - else if (type == unsigned_long_long_fract_type_node - || type == sat_unsigned_long_long_fract_type_node - || type == unsigned_long_long_accum_type_node - || type == sat_unsigned_long_long_accum_type_node) - write_char ('y'); - else - sorry ("mangling unknown fixed point type"); - write_unsigned_number (GET_MODE_FBIT (TYPE_MODE (type))); - if (TYPE_SATURATING (type)) - write_char ('s'); - else - write_char ('n'); - break; - default: gcc_unreachable (); } diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc index c35a59f..9f917f1 100644 --- a/gcc/cp/method.cc +++ b/gcc/cp/method.cc @@ -2236,6 +2236,19 @@ ref_xes_from_temporary (tree to, tree from, bool direct_init_p) return ref_conv_binds_directly (to, val, direct_init_p).is_false (); } +/* Worker for is_{,nothrow_}convertible. Attempt to perform an implicit + conversion from FROM to TO and return the result. */ + +static tree +is_convertible_helper (tree from, tree to) +{ + if (VOID_TYPE_P (from) && VOID_TYPE_P (to)) + return integer_one_node; + cp_unevaluated u; + tree expr = build_stub_object (from); + return perform_implicit_conversion (to, expr, tf_none); +} + /* Return true if FROM can be converted to TO using implicit conversions, or both FROM and TO are possibly cv-qualified void. NB: This doesn't implement the "Access checks are performed as if from a context unrelated @@ -2244,10 +2257,7 @@ ref_xes_from_temporary (tree to, tree from, bool direct_init_p) bool is_convertible (tree from, tree to) { - if (VOID_TYPE_P (from) && VOID_TYPE_P (to)) - return true; - tree expr = build_stub_object (from); - expr = perform_implicit_conversion (to, expr, tf_none); + tree expr = is_convertible_helper (from, to); if (expr == error_mark_node) return false; return !!expr; @@ -2258,10 +2268,7 @@ is_convertible (tree from, tree to) bool is_nothrow_convertible (tree from, tree to) { - if (VOID_TYPE_P (from) && VOID_TYPE_P (to)) - return true; - tree expr = build_stub_object (from); - expr = perform_implicit_conversion (to, expr, tf_none); + tree expr = is_convertible_helper (from, to); if (expr == NULL_TREE || expr == error_mark_node) return false; return expr_noexcept_p (expr, tf_none); diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index f23832c..7496df5 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -8185,13 +8185,18 @@ trees_in::decl_value () /* Set the TEMPLATE_DECL's type. */ TREE_TYPE (decl) = TREE_TYPE (inner); - if (mk & MK_template_mask - || mk == MK_partial) + /* Add to specialization tables now that constraints etc are + added. */ + if (mk == MK_partial) { - /* Add to specialization tables now that constraints etc are - added. */ - bool is_type = mk == MK_partial || !(mk & MK_tmpl_decl_mask); - + bool is_type = TREE_CODE (inner) == TYPE_DECL; + spec.spec = is_type ? type : inner; + add_mergeable_specialization (!is_type, false, + &spec, decl, spec_flags); + } + else if (mk & MK_template_mask) + { + bool is_type = !(mk & MK_tmpl_decl_mask); spec.spec = is_type ? type : mk & MK_tmpl_tmpl_mask ? inner : decl; add_mergeable_specialization (!is_type, !is_type && mk & MK_tmpl_alias_mask, diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index bb83d1c..d501178 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -46,6 +46,7 @@ along with GCC; see the file COPYING3. If not see #include "cp-name-hint.h" #include "memmodel.h" #include "c-family/known-headers.h" +#include "bitmap.h" /* The lexer. */ @@ -1129,6 +1130,7 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword) case RID_UNSIGNED: case RID_FLOAT: case RID_DOUBLE: + CASE_RID_FLOATN_NX: case RID_VOID: /* CV qualifiers. */ case RID_CONST: @@ -1994,7 +1996,7 @@ enum constexpr. */ CP_PARSER_FLAGS_ONLY_TYPE_OR_CONSTEXPR = 0x8, /* When parsing a decl-specifier-seq, only allow mutable, constexpr or - for C++20 consteval. */ + for C++20 consteval or for C++23 static. */ CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR = 0x10, /* When parsing a decl-specifier-seq, allow missing typename. */ CP_PARSER_FLAGS_TYPENAME_OPTIONAL = 0x20, @@ -11728,9 +11730,18 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) { LAMBDA_EXPR_MUTABLE_P (lambda_expr) = 1; quals = TYPE_UNQUALIFIED; - if (lambda_specs.conflicting_specifiers_p) + } + else if (lambda_specs.storage_class == sc_static) + { + if (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda_expr) != CPLD_NONE + || LAMBDA_EXPR_CAPTURE_LIST (lambda_expr)) error_at (lambda_specs.locations[ds_storage_class], - "duplicate %<mutable%>"); + "%<static%> lambda specifier with lambda capture"); + else + { + LAMBDA_EXPR_STATIC_P (lambda_expr) = 1; + quals = TYPE_UNQUALIFIED; + } } tx_qual = cp_parser_tx_qualifier_opt (parser); @@ -11817,6 +11828,12 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) if (lambda_specs.locations[ds_consteval]) return_type_specs.locations[ds_consteval] = lambda_specs.locations[ds_consteval]; + if (LAMBDA_EXPR_STATIC_P (lambda_expr)) + { + return_type_specs.storage_class = sc_static; + return_type_specs.locations[ds_storage_class] + = lambda_specs.locations[ds_storage_class]; + } p = obstack_alloc (&declarator_obstack, 0); @@ -11840,8 +11857,9 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) { DECL_INITIALIZED_IN_CLASS_P (fco) = 1; DECL_ARTIFICIAL (fco) = 1; - /* Give the object parameter a different name. */ - DECL_NAME (DECL_ARGUMENTS (fco)) = closure_identifier; + if (!LAMBDA_EXPR_STATIC_P (lambda_expr)) + /* Give the object parameter a different name. */ + DECL_NAME (DECL_ARGUMENTS (fco)) = closure_identifier; DECL_SET_LAMBDA_FUNCTION (fco, true); } if (template_param_list) @@ -15730,6 +15748,13 @@ cp_parser_decomposition_declaration (cp_parser *parser, return decl; } +/* Names of storage classes. */ + +static const char *const +cp_storage_class_name[] = { + "", "auto", "register", "static", "extern", "mutable" +}; + /* Parse a decl-specifier-seq. decl-specifier-seq: @@ -15951,8 +15976,18 @@ cp_parser_decl_specifier_seq (cp_parser* parser, may as well commit at this point. */ cp_parser_commit_to_tentative_parse (parser); - if (decl_specs->storage_class != sc_none) - decl_specs->conflicting_specifiers_p = true; + if (decl_specs->storage_class != sc_none) + { + if (decl_specs->conflicting_specifiers_p) + break; + gcc_rich_location richloc (token->location); + location_t oloc = decl_specs->locations[ds_storage_class]; + richloc.add_location_if_nearby (oloc); + error_at (&richloc, + "%<typedef%> specifier conflicts with %qs", + cp_storage_class_name[decl_specs->storage_class]); + decl_specs->conflicting_specifiers_p = true; + } break; /* storage-class-specifier: @@ -16018,8 +16053,15 @@ cp_parser_decl_specifier_seq (cp_parser* parser, && token->keyword != RID_MUTABLE && token->keyword != RID_CONSTEXPR && token->keyword != RID_CONSTEVAL) - error_at (token->location, "%qD invalid in lambda", - ridpointers[token->keyword]); + { + if (token->keyword != RID_STATIC) + error_at (token->location, "%qD invalid in lambda", + ridpointers[token->keyword]); + else if (cxx_dialect < cxx23) + pedwarn (token->location, OPT_Wc__23_extensions, + "%qD only valid in lambda with %<-std=c++23%> or " + "%<-std=gnu++23%>", ridpointers[token->keyword]); + } if (ds != ds_last) set_and_check_decl_spec_loc (decl_specs, ds, token); @@ -19716,6 +19758,14 @@ cp_parser_simple_type_specifier (cp_parser* parser, case RID_DOUBLE: type = double_type_node; break; + CASE_RID_FLOATN_NX: + type = FLOATN_NX_TYPE_NODE (token->keyword - RID_FLOATN_NX_FIRST); + if (type == NULL_TREE) + error ("%<_Float%d%s%> is not supported on this target", + floatn_nx_types[token->keyword - RID_FLOATN_NX_FIRST].n, + floatn_nx_types[token->keyword - RID_FLOATN_NX_FIRST].extended + ? "x" : ""); + break; case RID_VOID: type = void_type_node; break; @@ -32836,26 +32886,6 @@ cp_parser_set_storage_class (cp_parser *parser, { cp_storage_class storage_class; - if (parser->in_unbraced_linkage_specification_p) - { - error_at (token->location, "invalid use of %qD in linkage specification", - ridpointers[keyword]); - return; - } - else if (decl_specs->storage_class != sc_none) - { - decl_specs->conflicting_specifiers_p = true; - return; - } - - if ((keyword == RID_EXTERN || keyword == RID_STATIC) - && decl_spec_seq_has_spec_p (decl_specs, ds_thread) - && decl_specs->gnu_thread_keyword_p) - { - pedwarn (decl_specs->locations[ds_thread], 0, - "%<__thread%> before %qD", ridpointers[keyword]); - } - switch (keyword) { case RID_AUTO: @@ -32876,6 +32906,38 @@ cp_parser_set_storage_class (cp_parser *parser, default: gcc_unreachable (); } + + if (parser->in_unbraced_linkage_specification_p) + { + error_at (token->location, "invalid use of %qD in linkage specification", + ridpointers[keyword]); + return; + } + else if (decl_specs->storage_class != sc_none) + { + if (decl_specs->conflicting_specifiers_p) + return; + gcc_rich_location richloc (token->location); + richloc.add_location_if_nearby (decl_specs->locations[ds_storage_class]); + if (decl_specs->storage_class == storage_class) + error_at (&richloc, "duplicate %qD specifier", ridpointers[keyword]); + else + error_at (&richloc, + "%qD specifier conflicts with %qs", + ridpointers[keyword], + cp_storage_class_name[decl_specs->storage_class]); + decl_specs->conflicting_specifiers_p = true; + return; + } + + if ((keyword == RID_EXTERN || keyword == RID_STATIC) + && decl_spec_seq_has_spec_p (decl_specs, ds_thread) + && decl_specs->gnu_thread_keyword_p) + { + pedwarn (decl_specs->locations[ds_thread], 0, + "%<__thread%> before %qD", ridpointers[keyword]); + } + decl_specs->storage_class = storage_class; set_and_check_decl_spec_loc (decl_specs, ds_storage_class, token); @@ -32883,8 +32945,16 @@ cp_parser_set_storage_class (cp_parser *parser, specifier. If there is a typedef specifier present then set conflicting_specifiers_p which will trigger an error later on in grokdeclarator. */ - if (decl_spec_seq_has_spec_p (decl_specs, ds_typedef)) - decl_specs->conflicting_specifiers_p = true; + if (decl_spec_seq_has_spec_p (decl_specs, ds_typedef) + && !decl_specs->conflicting_specifiers_p) + { + gcc_rich_location richloc (token->location); + richloc.add_location_if_nearby (decl_specs->locations[ds_typedef]); + error_at (&richloc, + "%qD specifier conflicts with %<typedef%>", + ridpointers[keyword]); + decl_specs->conflicting_specifiers_p = true; + } } /* Update the DECL_SPECS to reflect the TYPE_SPEC. If TYPE_DEFINITION_P @@ -46018,6 +46088,218 @@ cp_parser_omp_context_selector_specification (cp_parser *parser, 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 first = true; + bool no_openmp = false; + bool no_openmp_routines = false; + bool no_parallelism = false; + bitmap_head absent_head, contains_head; + + bitmap_obstack_initialize (NULL); + bitmap_initialize (&absent_head, &bitmap_default_obstack); + bitmap_initialize (&contains_head, &bitmap_default_obstack); + + if (cp_lexer_next_token_is (parser->lexer, CPP_PRAGMA_EOL)) + error_at (cp_lexer_peek_token (parser->lexer)->location, + "expected at least one assumption clause"); + + while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)) + { + /* For now only in C++ attributes, do it always for OpenMP 5.1. */ + if ((!first || parser->lexer->in_omp_attribute_pragma) + && cp_lexer_next_token_is (parser->lexer, CPP_COMMA) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)) + cp_lexer_consume_token (parser->lexer); + + first = false; + + if (!cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + break; + + const char *p + = IDENTIFIER_POINTER (cp_lexer_peek_token (parser->lexer)->u.value); + location_t cloc = cp_lexer_peek_token (parser->lexer)->location; + + if (!strcmp (p, "no_openmp")) + { + cp_lexer_consume_token (parser->lexer); + if (no_openmp) + error_at (cloc, "too many %qs clauses", "no_openmp"); + no_openmp = true; + } + else if (!strcmp (p, "no_openmp_routines")) + { + cp_lexer_consume_token (parser->lexer); + if (no_openmp_routines) + error_at (cloc, "too many %qs clauses", "no_openmp_routines"); + no_openmp_routines = true; + } + else if (!strcmp (p, "no_parallelism")) + { + cp_lexer_consume_token (parser->lexer); + if (no_parallelism) + error_at (cloc, "too many %qs clauses", "no_parallelism"); + no_parallelism = true; + } + else if (!strcmp (p, "holds")) + { + cp_lexer_consume_token (parser->lexer); + matching_parens parens; + if (parens.require_open (parser)) + { + tree t = cp_parser_assignment_expression (parser); + if (!type_dependent_expression_p (t)) + t = contextual_conv_bool (t, tf_warning_or_error); + if (is_assume) + { + /* FIXME: Emit .ASSUME (t) call here. */ + (void) t; + } + if (!parens.require_close (parser)) + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + } + } + else if (!strcmp (p, "absent") || !strcmp (p, "contains")) + { + cp_lexer_consume_token (parser->lexer); + matching_parens parens; + if (parens.require_open (parser)) + { + do + { + const char *directive[3] = {}; + int i; + location_t dloc + = cp_lexer_peek_token (parser->lexer)->location; + for (i = 0; i < 3; i++) + { + tree id; + if (cp_lexer_nth_token_is (parser->lexer, i + 1, CPP_NAME)) + id = cp_lexer_peek_nth_token (parser->lexer, + i + 1)->u.value; + else if (cp_lexer_nth_token_is (parser->lexer, i + 1, + CPP_KEYWORD)) + { + enum rid rid + = cp_lexer_peek_nth_token (parser->lexer, + i + 1)->keyword; + id = ridpointers[rid]; + } + else + break; + directive[i] = IDENTIFIER_POINTER (id); + } + if (i == 0) + error_at (dloc, "expected directive name"); + else + { + const struct c_omp_directive *dir + = c_omp_categorize_directive (directive[0], + directive[1], + directive[2]); + if (dir == NULL + || dir->kind == C_OMP_DIR_DECLARATIVE + || dir->kind == C_OMP_DIR_INFORMATIONAL + || dir->id == PRAGMA_OMP_END + || (!dir->second && directive[1]) + || (!dir->third && directive[2])) + error_at (dloc, "unknown OpenMP directive name in " + "%qs clause argument", p); + else + { + int id = dir - c_omp_directives; + if (bitmap_bit_p (p[0] == 'a' ? &contains_head + : &absent_head, id)) + error_at (dloc, "%<%s%s%s%s%s%> directive " + "mentioned in both %<absent%> and " + "%<contains%> clauses", + directive[0], + directive[1] ? " " : "", + directive[1] ? directive[1] : "", + directive[2] ? " " : "", + directive[2] ? directive[2] : ""); + else if (!bitmap_set_bit (p[0] == 'a' + ? &absent_head + : &contains_head, id)) + error_at (dloc, "%<%s%s%s%s%s%> directive " + "mentioned multiple times in %qs " + "clauses", + directive[0], + directive[1] ? " " : "", + directive[1] ? directive[1] : "", + directive[2] ? " " : "", + directive[2] ? directive[2] : "", p); + } + for (; i; --i) + cp_lexer_consume_token (parser->lexer); + } + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + cp_lexer_consume_token (parser->lexer); + else + break; + } + while (1); + if (!parens.require_close (parser)) + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + } + } + else if (startswith (p, "ext_")) + { + warning_at (cloc, 0, "unknown assumption clause %qs", p); + cp_lexer_consume_token (parser->lexer); + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) + for (size_t n = cp_parser_skip_balanced_tokens (parser, 1) - 1; + n; --n) + cp_lexer_consume_token (parser->lexer); + } + else + { + cp_lexer_consume_token (parser->lexer); + error_at (cloc, "expected assumption clause"); + break; + } + } + cp_parser_skip_to_pragma_eol (parser, pragma_tok); +} + +/* OpenMP 5.1 + # pragma omp assume clauses[optseq] new-line */ + +static void +cp_parser_omp_assume (cp_parser *parser, cp_token *pragma_tok, bool *if_p) +{ + cp_parser_omp_assumption_clauses (parser, pragma_tok, true); + add_stmt (cp_parser_omp_structured_block (parser, if_p)); +} + +/* OpenMP 5.1 + # pragma omp assumes clauses[optseq] new-line */ + +static bool +cp_parser_omp_assumes (cp_parser *parser, cp_token *pragma_tok) +{ + cp_parser_omp_assumption_clauses (parser, pragma_tok, false); + return false; +} + /* Finalize #pragma omp declare variant after a fndecl has been parsed, and put that into "omp declare variant base" attribute. */ @@ -46467,8 +46749,41 @@ cp_parser_omp_declare_target (cp_parser *parser, cp_token *pragma_tok) "directive with only %<device_type%> clauses ignored"); } +/* OpenMP 5.1 + #pragma omp begin assumes clauses[optseq] new-line */ + static void -cp_parser_omp_end_declare_target (cp_parser *parser, cp_token *pragma_tok) +cp_parser_omp_begin (cp_parser *parser, cp_token *pragma_tok) +{ + const char *p = ""; + bool in_omp_attribute_pragma = parser->lexer->in_omp_attribute_pragma; + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + p = IDENTIFIER_POINTER (id); + } + if (strcmp (p, "assumes") == 0) + { + cp_lexer_consume_token (parser->lexer); + cp_parser_omp_assumption_clauses (parser, pragma_tok, false); + struct omp_begin_assumes_data a = { in_omp_attribute_pragma }; + vec_safe_push (scope_chain->omp_begin_assumes, a); + } + else + { + cp_parser_error (parser, "expected %<assumes%>"); + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + } +} + +/* OpenMP 4.0: + # pragma omp end declare target new-line + + OpenMP 5.1: + # pragma omp end assumes new-line */ + +static void +cp_parser_omp_end (cp_parser *parser, cp_token *pragma_tok) { const char *p = ""; bool in_omp_attribute_pragma = parser->lexer->in_omp_attribute_pragma; @@ -46494,33 +46809,58 @@ cp_parser_omp_end_declare_target (cp_parser *parser, cp_token *pragma_tok) cp_parser_skip_to_pragma_eol (parser, pragma_tok); return; } + cp_parser_require_pragma_eol (parser, pragma_tok); + if (!vec_safe_length (scope_chain->omp_declare_target_attribute)) + error_at (pragma_tok->location, + "%<#pragma omp end declare target%> without corresponding " + "%<#pragma omp declare target%>"); + else + { + omp_declare_target_attr + a = scope_chain->omp_declare_target_attribute->pop (); + if (a.attr_syntax != in_omp_attribute_pragma) + { + if (a.attr_syntax) + error_at (pragma_tok->location, + "%<declare target%> in attribute syntax terminated " + "with %<end declare target%> in pragma syntax"); + else + error_at (pragma_tok->location, + "%<declare target%> in pragma syntax terminated " + "with %<end declare target%> in attribute syntax"); + } + } } - else + else if (strcmp (p, "assumes") == 0) { - cp_parser_error (parser, "expected %<declare%>"); - cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return; + cp_lexer_consume_token (parser->lexer); + cp_parser_require_pragma_eol (parser, pragma_tok); + if (!vec_safe_length (scope_chain->omp_begin_assumes)) + error_at (pragma_tok->location, + "%<#pragma omp end assumes%> without corresponding " + "%<#pragma omp begin assumes%>"); + else + { + omp_begin_assumes_data + a = scope_chain->omp_begin_assumes->pop (); + if (a.attr_syntax != in_omp_attribute_pragma) + { + if (a.attr_syntax) + error_at (pragma_tok->location, + "%<begin assumes%> in attribute syntax terminated " + "with %<end assumes%> in pragma syntax"); + else + error_at (pragma_tok->location, + "%<begin assumes%> in pragma syntax terminated " + "with %<end assumes%> in attribute syntax"); + } + } } - cp_parser_require_pragma_eol (parser, pragma_tok); - if (!vec_safe_length (scope_chain->omp_declare_target_attribute)) - error_at (pragma_tok->location, - "%<#pragma omp end declare target%> without corresponding " - "%<#pragma omp declare target%>"); else { - omp_declare_target_attr - a = scope_chain->omp_declare_target_attribute->pop (); - if (a.attr_syntax != in_omp_attribute_pragma) - { - if (a.attr_syntax) - error_at (pragma_tok->location, - "%<declare target%> in attribute syntax terminated " - "with %<end declare target%> in pragma syntax"); - else - error_at (pragma_tok->location, - "%<declare target%> in pragma syntax terminated " - "with %<end declare target%> in attribute syntax"); - } + cp_parser_error (parser, "expected %<declare%> or %<assumes%>"); + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return; } } @@ -47803,6 +48143,9 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok, bool *if_p) stmt = cp_parser_omp_teams (parser, pragma_tok, p_name, mask, NULL, if_p); break; + case PRAGMA_OMP_ASSUME: + cp_parser_omp_assume (parser, pragma_tok, if_p); + return; default: gcc_unreachable (); } @@ -48406,6 +48749,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) case PRAGMA_OACC_LOOP: case PRAGMA_OACC_PARALLEL: case PRAGMA_OACC_SERIAL: + case PRAGMA_OMP_ASSUME: case PRAGMA_OMP_ATOMIC: case PRAGMA_OMP_CRITICAL: case PRAGMA_OMP_DISTRIBUTE: @@ -48440,6 +48784,17 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) } return cp_parser_omp_requires (parser, pragma_tok); + case PRAGMA_OMP_ASSUMES: + if (context != pragma_external) + { + error_at (pragma_tok->location, + "%<#pragma omp assumes%> may only be used at file or " + "namespace scope"); + ret = true; + break; + } + return cp_parser_omp_assumes (parser, pragma_tok); + case PRAGMA_OMP_NOTHING: cp_parser_omp_nothing (parser, pragma_tok); return false; @@ -48463,8 +48818,12 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) pop_omp_privatization_clauses (stmt); return ret; - case PRAGMA_OMP_END_DECLARE_TARGET: - cp_parser_omp_end_declare_target (parser, pragma_tok); + case PRAGMA_OMP_BEGIN: + cp_parser_omp_begin (parser, pragma_tok); + return false; + + case PRAGMA_OMP_END: + cp_parser_omp_end (parser, pragma_tok); return false; case PRAGMA_OMP_SCAN: diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index db4e808..1c1e573 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -11945,6 +11945,7 @@ apply_late_template_attributes (tree *decl_p, tree attributes, int attr_flags, auto o3 = make_temp_override (current_target_pragma, NULL_TREE); auto o4 = make_temp_override (scope_chain->omp_declare_target_attribute, NULL); + auto o5 = make_temp_override (scope_chain->omp_begin_assumes, NULL); cplus_decl_attributes (decl_p, late_attrs, attr_flags); @@ -31010,7 +31011,7 @@ add_mergeable_specialization (bool decl_p, bool alias_p, spec_entry *elt, /* A partial specialization. */ tree cons = tree_cons (elt->args, decl, DECL_TEMPLATE_SPECIALIZATIONS (elt->tmpl)); - TREE_TYPE (cons) = elt->spec; + TREE_TYPE (cons) = decl_p ? TREE_TYPE (elt->spec) : elt->spec; DECL_TEMPLATE_SPECIALIZATIONS (elt->tmpl) = cons; } } diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 92fc795..e8cd505 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -3363,6 +3363,13 @@ finish_translation_unit (void) "%<#pragma omp end declare target%>"); vec_safe_truncate (scope_chain->omp_declare_target_attribute, 0); } + if (vec_safe_length (scope_chain->omp_begin_assumes)) + { + if (!errorcount) + error ("%<#pragma omp begin assumes%> without corresponding " + "%<#pragma omp end assumes%>"); + vec_safe_truncate (scope_chain->omp_begin_assumes, 0); + } } /* Finish a template type parameter, specified as AGGR IDENTIFIER. diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index 22d834d..4854b98 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -267,6 +267,133 @@ merge_type_attributes_from (tree type, tree other_type) return cp_build_type_attribute_variant (type, attrs); } +/* Compare floating point conversion ranks and subranks of T1 and T2 + types. If T1 and T2 have unordered conversion ranks, return 3. + If T1 has greater conversion rank than T2, return 2. + If T2 has greater conversion rank than T1, return -2. + If T1 has equal conversion rank as T2, return -1, 0 or 1 depending + on if T1 has smaller, equal or greater conversion subrank than + T2. */ + +int +cp_compare_floating_point_conversion_ranks (tree t1, tree t2) +{ + tree mv1 = TYPE_MAIN_VARIANT (t1); + tree mv2 = TYPE_MAIN_VARIANT (t2); + int extended1 = 0; + int extended2 = 0; + + if (mv1 == mv2) + return 0; + + for (int i = 0; i < NUM_FLOATN_NX_TYPES; ++i) + { + if (mv1 == FLOATN_NX_TYPE_NODE (i)) + extended1 = i + 1; + if (mv2 == FLOATN_NX_TYPE_NODE (i)) + extended2 = i + 1; + } + if (extended2 && !extended1) + { + int ret = cp_compare_floating_point_conversion_ranks (t2, t1); + return ret == 3 ? 3 : -ret; + } + + 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. + So, e.g. for __ibm128 vs. std::float128_t, they have unordered + ranks. */ + int p1 = (MODE_COMPOSITE_P (TYPE_MODE (t1)) + ? fmt1->emax - fmt1->emin + fmt1->p - 1 : fmt1->p); + int p2 = (MODE_COMPOSITE_P (TYPE_MODE (t2)) + ? fmt2->emax - fmt2->emin + fmt2->p - 1 : fmt2->p); + /* The rank of a floating point type T is greater than the rank of + any floating-point type whose set of values is a proper subset + of the set of values of T. */ + if ((p1 > p2 && fmt1->emax >= fmt2->emax) + || (p1 == p2 && fmt1->emax > fmt2->emax)) + return 2; + if ((p1 < p2 && fmt1->emax <= fmt2->emax) + || (p1 == p2 && fmt1->emax < fmt2->emax)) + return -2; + if ((p1 > p2 && fmt1->emax < fmt2->emax) + || (p1 < p2 && fmt1->emax > fmt2->emax)) + return 3; + if (!extended1 && !extended2) + { + /* The rank of long double is greater than the rank of double, which + is greater than the rank of float. */ + if (t1 == long_double_type_node) + return 2; + else if (t2 == long_double_type_node) + return -2; + if (t1 == double_type_node) + return 2; + else if (t2 == double_type_node) + return -2; + if (t1 == float_type_node) + return 2; + else if (t2 == float_type_node) + return -2; + return 0; + } + /* Two extended floating-point types with the same set of values have equal + ranks. */ + if (extended1 && extended2) + { + if ((extended1 <= NUM_FLOATN_TYPES) == (extended2 <= NUM_FLOATN_TYPES)) + { + /* Prefer higher extendedN value. */ + if (extended1 > extended2) + return 1; + else if (extended1 < extended2) + return -1; + else + return 0; + } + else if (extended1 <= NUM_FLOATN_TYPES) + /* Prefer _FloatN type over _FloatMx type. */ + return 1; + else if (extended2 <= NUM_FLOATN_TYPES) + return -1; + else + return 0; + } + + /* gcc_assert (extended1 && !extended2); */ + tree *p; + int cnt = 0; + for (p = &float_type_node; p <= &long_double_type_node; ++p) + { + const struct real_format *fmt3 = REAL_MODE_FORMAT (TYPE_MODE (*p)); + gcc_assert (fmt3->b == 2); + int p3 = (MODE_COMPOSITE_P (TYPE_MODE (*p)) + ? fmt3->emax - fmt3->emin + fmt3->p - 1 : fmt3->p); + if (p1 == p3 && fmt1->emax == fmt3->emax) + ++cnt; + } + /* An extended floating-point type with the same set of values + as exactly one cv-unqualified standard floating-point type + has a rank equal to the rank of that standard floating-point + type. + + An extended floating-point type with the same set of values + as more than one cv-unqualified standard floating-point type + has a rank equal to the rank of double. + + Thus, if the latter is true and t2 is long double, t2 + has higher rank. */ + if (cnt > 1 && mv2 == long_double_type_node) + return -2; + /* Otherwise, they have equal rank, but extended types + (other than std::bfloat16_t) have higher subrank. */ + return 1; +} + /* Return the common type for two arithmetic types T1 and T2 under the usual arithmetic conversions. The default conversions have already been applied, and enumerated types converted to their compatible @@ -337,6 +464,23 @@ cp_common_type (tree t1, tree t2) if (code2 == REAL_TYPE && code1 != REAL_TYPE) return build_type_attribute_variant (t2, attributes); + if (code1 == REAL_TYPE + && (extended_float_type_p (t1) || extended_float_type_p (t2))) + { + tree mv1 = TYPE_MAIN_VARIANT (t1); + tree mv2 = TYPE_MAIN_VARIANT (t2); + if (mv1 == mv2) + return build_type_attribute_variant (t1, attributes); + + int cmpret = cp_compare_floating_point_conversion_ranks (mv1, mv2); + if (cmpret == 3) + return error_mark_node; + else if (cmpret >= 0) + return build_type_attribute_variant (t1, attributes); + else + return build_type_attribute_variant (t2, attributes); + } + /* Both real or both integers; use the one with greater precision. */ if (TYPE_PRECISION (t1) > TYPE_PRECISION (t2)) return build_type_attribute_variant (t1, attributes); @@ -5037,7 +5181,20 @@ cp_build_binary_op (const op_location_t &location, = targetm.invalid_binary_op (code, type0, type1))) { if (complain & tf_error) - error (invalid_op_diag); + { + if (code0 == REAL_TYPE + && code1 == REAL_TYPE + && (extended_float_type_p (type0) + || extended_float_type_p (type1)) + && cp_compare_floating_point_conversion_ranks (type0, + type1) == 3) + { + rich_location richloc (line_table, location); + binary_op_error (&richloc, code, type0, type1); + } + else + error (invalid_op_diag); + } return error_mark_node; } @@ -5907,6 +6064,19 @@ cp_build_binary_op (const op_location_t &location, && (shorten || common || short_compare)) { result_type = cp_common_type (type0, type1); + if (result_type == error_mark_node + && code0 == REAL_TYPE + && code1 == REAL_TYPE + && (extended_float_type_p (type0) || extended_float_type_p (type1)) + && cp_compare_floating_point_conversion_ranks (type0, type1) == 3) + { + if (complain & tf_error) + { + rich_location richloc (line_table, location); + binary_op_error (&richloc, code, type0, type1); + } + return error_mark_node; + } if (complain & tf_warning) { do_warn_double_promotion (result_type, type0, type1, diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc index 75fd0e2..d5236d1 100644 --- a/gcc/cp/typeck2.cc +++ b/gcc/cp/typeck2.cc @@ -997,12 +997,25 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain, else if (TREE_CODE (ftype) == REAL_TYPE && TREE_CODE (type) == REAL_TYPE) { - if ((same_type_p (ftype, long_double_type_node) - && (same_type_p (type, double_type_node) - || same_type_p (type, float_type_node))) - || (same_type_p (ftype, double_type_node) - && same_type_p (type, float_type_node)) - || (TYPE_PRECISION (type) < TYPE_PRECISION (ftype))) + if ((extended_float_type_p (ftype) || extended_float_type_p (type)) + ? /* "from a floating-point type T to another floating-point type + whose floating-point conversion rank is neither greater than + nor equal to that of T". + So, it is ok if + cp_compare_floating_point_conversion_ranks (ftype, type) + returns -2 (type has greater conversion rank than ftype) + or [-1..1] (type has equal conversion rank as ftype, possibly + different subrank. Only do this if at least one of the + types is extended floating-point type, otherwise keep doing + what we did before (for the sake of non-standard + backend types). */ + cp_compare_floating_point_conversion_ranks (ftype, type) >= 2 + : ((same_type_p (ftype, long_double_type_node) + && (same_type_p (type, double_type_node) + || same_type_p (type, float_type_node))) + || (same_type_p (ftype, double_type_node) + && same_type_p (type, float_type_node)) + || (TYPE_PRECISION (type) < TYPE_PRECISION (ftype)))) { if (TREE_CODE (init) == REAL_CST) { @@ -1118,6 +1131,15 @@ array_string_literal_compatible_p (tree type, tree init) if (ordinary_char_type_p (to_char_type) && ordinary_char_type_p (from_char_type)) return true; + + /* P2513 (C++20/C++23): "an array of char or unsigned char may + be initialized by a UTF-8 string literal, or by such a string + literal enclosed in braces." */ + if (from_char_type == char8_type_node + && (to_char_type == char_type_node + || to_char_type == unsigned_char_type_node)) + return true; + return false; } diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc index e91aee3..dcfca64 100644 --- a/gcc/d/decl.cc +++ b/gcc/d/decl.cc @@ -2335,7 +2335,7 @@ layout_struct_initializer (StructDeclaration *sd) { StructLiteralExp *sle = StructLiteralExp::create (sd->loc, sd, NULL); - if (!sd->fill (sd->loc, sle->elements, true)) + if (!sd->fill (sd->loc, *sle->elements, true)) gcc_unreachable (); sle->type = sd->type; diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index 85fc49d..a4c46f3 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -817610b16d0f0f469b9fbb28c000956fb910c43f +4219ba670ce9ff92f3e874f0f048f2c28134c008 The first line of this file holds the git revision number of the last merge done from the dlang/dmd repository. diff --git a/gcc/d/dmd/aggregate.d b/gcc/d/dmd/aggregate.d index f4b5e8a..edca17f 100644 --- a/gcc/d/dmd/aggregate.d +++ b/gcc/d/dmd/aggregate.d @@ -355,23 +355,22 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol * false if any errors occur. * Otherwise, returns true and the missing arguments will be pushed in elements[]. */ - final bool fill(const ref Loc loc, Expressions* elements, bool ctorinit) + final bool fill(const ref Loc loc, ref Expressions elements, bool ctorinit) { //printf("AggregateDeclaration::fill() %s\n", toChars()); assert(sizeok == Sizeok.done); - assert(elements); const nfields = nonHiddenFields(); bool errors = false; size_t dim = elements.dim; elements.setDim(nfields); foreach (size_t i; dim .. nfields) - (*elements)[i] = null; + elements[i] = null; // Fill in missing any elements with default initializers foreach (i; 0 .. nfields) { - if ((*elements)[i]) + if (elements[i]) continue; auto vd = fields[i]; @@ -389,7 +388,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol if (!vd.isOverlappedWith(v2)) continue; - if ((*elements)[j]) + if (elements[j]) { vx = null; break; @@ -489,10 +488,10 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol else e = telem.defaultInitLiteral(loc); } - (*elements)[fieldi] = e; + elements[fieldi] = e; } } - foreach (e; *elements) + foreach (e; elements) { if (e && e.op == EXP.error) return false; diff --git a/gcc/d/dmd/aggregate.h b/gcc/d/dmd/aggregate.h index d91e35e..f0909e3 100644 --- a/gcc/d/dmd/aggregate.h +++ b/gcc/d/dmd/aggregate.h @@ -125,7 +125,7 @@ public: bool determineSize(const Loc &loc); virtual void finalizeSize() = 0; uinteger_t size(const Loc &loc) override final; - bool fill(const Loc &loc, Expressions *elements, bool ctorinit); + bool fill(const Loc &loc, Expressions &elements, bool ctorinit); Type *getType() override final; bool isDeprecated() const override final; // is aggregate deprecated? void setDeprecated(); diff --git a/gcc/d/dmd/apply.d b/gcc/d/dmd/apply.d index ac2c80e..3b73771 100644 --- a/gcc/d/dmd/apply.d +++ b/gcc/d/dmd/apply.d @@ -16,6 +16,7 @@ import dmd.dsymbol; import dmd.dsymbolsem; import dmd.dtemplate; import dmd.expression; +import dmd.root.array; import dmd.visitor; bool walkPostorder(Expression e, StoppableVisitor v) @@ -86,12 +87,10 @@ public: return stop; } - bool doCond(Expressions* e) + extern(D) bool doCond(Expression[] e) { - if (!e) - return false; - for (size_t i = 0; i < e.dim && !stop; i++) - doCond((*e)[i]); + for (size_t i = 0; i < e.length && !stop; i++) + doCond(e[i]); return stop; } @@ -110,13 +109,13 @@ public: override void visit(NewExp e) { //printf("NewExp::apply(): %s\n", toChars()); - doCond(e.thisexp) || doCond(e.arguments) || applyTo(e); + doCond(e.thisexp) || doCond(e.arguments.peekSlice()) || applyTo(e); } override void visit(NewAnonClassExp e) { //printf("NewAnonClassExp::apply(): %s\n", toChars()); - doCond(e.thisexp) || doCond(e.arguments) || applyTo(e); + doCond(e.thisexp) || doCond(e.arguments.peekSlice()) || applyTo(e); } override void visit(TypeidExp e) @@ -143,13 +142,13 @@ public: override void visit(CallExp e) { //printf("CallExp::apply(apply_fp_t fp, void *param): %s\n", toChars()); - doCond(e.e1) || doCond(e.arguments) || applyTo(e); + doCond(e.e1) || doCond(e.arguments.peekSlice()) || applyTo(e); } override void visit(ArrayExp e) { //printf("ArrayExp::apply(apply_fp_t fp, void *param): %s\n", toChars()); - doCond(e.e1) || doCond(e.arguments) || applyTo(e); + doCond(e.e1) || doCond(e.arguments.peekSlice()) || applyTo(e); } override void visit(SliceExp e) @@ -159,12 +158,12 @@ public: override void visit(ArrayLiteralExp e) { - doCond(e.basis) || doCond(e.elements) || applyTo(e); + doCond(e.basis) || doCond(e.elements.peekSlice()) || applyTo(e); } override void visit(AssocArrayLiteralExp e) { - doCond(e.keys) || doCond(e.values) || applyTo(e); + doCond(e.keys.peekSlice()) || doCond(e.values.peekSlice()) || applyTo(e); } override void visit(StructLiteralExp e) @@ -173,13 +172,13 @@ public: return; int old = e.stageflags; e.stageflags |= stageApply; - doCond(e.elements) || applyTo(e); + doCond(e.elements.peekSlice()) || applyTo(e); e.stageflags = old; } override void visit(TupleExp e) { - doCond(e.e0) || doCond(e.exps) || applyTo(e); + doCond(e.e0) || doCond(e.exps.peekSlice()) || applyTo(e); } override void visit(CondExp e) diff --git a/gcc/d/dmd/arrayop.d b/gcc/d/dmd/arrayop.d index 272e751..f07a6f4 100644 --- a/gcc/d/dmd/arrayop.d +++ b/gcc/d/dmd/arrayop.d @@ -129,8 +129,7 @@ Expression arrayOp(BinExp e, Scope* sc) return arrayOpInvalidError(e); auto tiargs = new Objects(); - auto args = new Expressions(); - buildArrayOp(sc, e, tiargs, args); + auto args = buildArrayOp(sc, e, tiargs); import dmd.dtemplate : TemplateDeclaration; __gshared TemplateDeclaration arrayOp; @@ -184,7 +183,7 @@ Expression arrayOp(BinAssignExp e, Scope* sc) * using reverse polish notation (RPN) to encode order of operations. * Encode operations as string arguments, using a "u" prefix for unary operations. */ -private void buildArrayOp(Scope* sc, Expression e, Objects* tiargs, Expressions* args) +private Expressions* buildArrayOp(Scope* sc, Expression e, Objects* tiargs) { extern (C++) final class BuildArrayOpVisitor : Visitor { @@ -194,11 +193,11 @@ private void buildArrayOp(Scope* sc, Expression e, Objects* tiargs, Expressions* Expressions* args; public: - extern (D) this(Scope* sc, Objects* tiargs, Expressions* args) + extern (D) this(Scope* sc, Objects* tiargs) { this.sc = sc; this.tiargs = tiargs; - this.args = args; + this.args = new Expressions(); } override void visit(Expression e) @@ -252,8 +251,9 @@ private void buildArrayOp(Scope* sc, Expression e, Objects* tiargs, Expressions* } } - scope v = new BuildArrayOpVisitor(sc, tiargs, args); + scope v = new BuildArrayOpVisitor(sc, tiargs); e.accept(v); + return v.args; } /*********************************************** diff --git a/gcc/d/dmd/attrib.d b/gcc/d/dmd/attrib.d index b569a9c..3472d1c 100644 --- a/gcc/d/dmd/attrib.d +++ b/gcc/d/dmd/attrib.d @@ -1431,7 +1431,7 @@ extern (C++) final class UserAttributeDeclaration : AttribDeclaration if (auto sc = _scope) { _scope = null; - arrayExpressionSemantic(atts, sc); + arrayExpressionSemantic(atts.peekSlice(), sc); } auto exps = new Expressions(); if (userAttribDecl && userAttribDecl !is this) @@ -1554,7 +1554,7 @@ int foreachUda(Dsymbol sym, Scope* sc, int delegate(Expression) dg) return 0; auto udas = sym.userAttribDecl.getAttributes(); - arrayExpressionSemantic(udas, sc, true); + arrayExpressionSemantic(udas.peekSlice(), sc, true); return udas.each!((uda) { if (!uda.isTupleExp()) diff --git a/gcc/d/dmd/canthrow.d b/gcc/d/dmd/canthrow.d index 088ca61..09e3833 100644 --- a/gcc/d/dmd/canthrow.d +++ b/gcc/d/dmd/canthrow.d @@ -111,13 +111,9 @@ extern (C++) /* CT */ BE canThrow(Expression e, FuncDeclaration func, bool mustN auto ts = tbNext.baseElemOf().isTypeStruct(); if (ts) { - import dmd.id : Id; - auto sd = ts.sym; const id = ce.f.ident; - if (sd.postblit && - (id == Id._d_arrayctor || id == Id._d_arraysetctor || - id == Id._d_arrayassign_l || id == Id._d_arrayassign_r)) + if (sd.postblit && isArrayConstructionOrAssign(id)) { checkFuncThrows(ce, sd.postblit); return; diff --git a/gcc/d/dmd/chkformat.d b/gcc/d/dmd/chkformat.d index e118d70..8204961 100644 --- a/gcc/d/dmd/chkformat.d +++ b/gcc/d/dmd/chkformat.d @@ -1079,386 +1079,210 @@ Format parseGenericFormatSpecifier(scope const char[] format, return specifier; // success } -unittest +@("parseGenericFormatSpecifier") unittest { - /* parseGenericFormatSpecifier - */ - char genSpecifier; size_t idx; - assert(parseGenericFormatSpecifier("hhd", idx, genSpecifier) == Format.hhd); - assert(genSpecifier == 'd'); - - idx = 0; - assert(parseGenericFormatSpecifier("hn", idx, genSpecifier) == Format.hn); - assert(genSpecifier == 'n'); - - idx = 0; - assert(parseGenericFormatSpecifier("ji", idx, genSpecifier) == Format.jd); - assert(genSpecifier == 'i'); + void testG(string fmtStr, Format expectedFormat, char expectedGenSpecifier) + { + idx = 0; + assert(parseGenericFormatSpecifier(fmtStr, idx, genSpecifier) == expectedFormat); + assert(genSpecifier == expectedGenSpecifier); + } - idx = 0; - assert(parseGenericFormatSpecifier("lu", idx, genSpecifier) == Format.lu); - assert(genSpecifier == 'u'); + testG("hhd", Format.hhd, 'd'); + testG("hn", Format.hn, 'n'); + testG("ji", Format.jd, 'i'); + testG("lu", Format.lu, 'u'); idx = 0; assert(parseGenericFormatSpecifier("k", idx, genSpecifier) == Format.error); +} - /* parsePrintfFormatSpecifier - */ - - bool widthStar; - bool precisionStar; - - // one for each Format - idx = 0; - assert(parsePrintfFormatSpecifier("%d", idx, widthStar, precisionStar) == Format.d); - assert(idx == 2); - assert(!widthStar && !precisionStar); - - idx = 0; - assert(parsePrintfFormatSpecifier("%ld", idx, widthStar, precisionStar) == Format.ld); - assert(idx == 3); - - idx = 0; - assert(parsePrintfFormatSpecifier("%lld", idx, widthStar, precisionStar) == Format.lld); - assert(idx == 4); - - idx = 0; - assert(parsePrintfFormatSpecifier("%jd", idx, widthStar, precisionStar) == Format.jd); - assert(idx == 3); - - idx = 0; - assert(parsePrintfFormatSpecifier("%zd", idx, widthStar, precisionStar) == Format.zd); - assert(idx == 3); - - idx = 0; - assert(parsePrintfFormatSpecifier("%td", idx, widthStar, precisionStar) == Format.td); - assert(idx == 3); - - idx = 0; - assert(parsePrintfFormatSpecifier("%g", idx, widthStar, precisionStar) == Format.g); - assert(idx == 2); - - idx = 0; - assert(parsePrintfFormatSpecifier("%Lg", idx, widthStar, precisionStar) == Format.Lg); - assert(idx == 3); - - idx = 0; - assert(parsePrintfFormatSpecifier("%p", idx, widthStar, precisionStar) == Format.p); - assert(idx == 2); - - idx = 0; - assert(parsePrintfFormatSpecifier("%n", idx, widthStar, precisionStar) == Format.n); - assert(idx == 2); - - idx = 0; - assert(parsePrintfFormatSpecifier("%ln", idx, widthStar, precisionStar) == Format.ln); - assert(idx == 3); - - idx = 0; - assert(parsePrintfFormatSpecifier("%lln", idx, widthStar, precisionStar) == Format.lln); - assert(idx == 4); +@("parsePrintfFormatSpecifier") unittest +{ + bool useGNUExts = false; - idx = 0; - assert(parsePrintfFormatSpecifier("%hn", idx, widthStar, precisionStar) == Format.hn); - assert(idx == 3); - - idx = 0; - assert(parsePrintfFormatSpecifier("%hhn", idx, widthStar, precisionStar) == Format.hhn); - assert(idx == 4); - - idx = 0; - assert(parsePrintfFormatSpecifier("%jn", idx, widthStar, precisionStar) == Format.jn); - assert(idx == 3); - - idx = 0; - assert(parsePrintfFormatSpecifier("%zn", idx, widthStar, precisionStar) == Format.zn); - assert(idx == 3); - - idx = 0; - assert(parsePrintfFormatSpecifier("%tn", idx, widthStar, precisionStar) == Format.tn); - assert(idx == 3); - - idx = 0; - assert(parsePrintfFormatSpecifier("%c", idx, widthStar, precisionStar) == Format.c); - assert(idx == 2); - - idx = 0; - assert(parsePrintfFormatSpecifier("%lc", idx, widthStar, precisionStar) == Format.lc); - assert(idx == 3); - - idx = 0; - assert(parsePrintfFormatSpecifier("%s", idx, widthStar, precisionStar) == Format.s); - assert(idx == 2); - - idx = 0; - assert(parsePrintfFormatSpecifier("%ls", idx, widthStar, precisionStar) == Format.ls); - assert(idx == 3); - - idx = 0; - assert(parsePrintfFormatSpecifier("%%", idx, widthStar, precisionStar) == Format.percent); - assert(idx == 2); - - // Synonyms - idx = 0; - assert(parsePrintfFormatSpecifier("%i", idx, widthStar, precisionStar) == Format.d); - assert(idx == 2); - - idx = 0; - assert(parsePrintfFormatSpecifier("%u", idx, widthStar, precisionStar) == Format.u); - assert(idx == 2); - - idx = 0; - assert(parsePrintfFormatSpecifier("%o", idx, widthStar, precisionStar) == Format.u); - assert(idx == 2); - - idx = 0; - assert(parsePrintfFormatSpecifier("%x", idx, widthStar, precisionStar) == Format.u); - assert(idx == 2); - - idx = 0; - assert(parsePrintfFormatSpecifier("%X", idx, widthStar, precisionStar) == Format.u); - assert(idx == 2); - - idx = 0; - assert(parsePrintfFormatSpecifier("%f", idx, widthStar, precisionStar) == Format.g); - assert(idx == 2); - - idx = 0; - assert(parsePrintfFormatSpecifier("%F", idx, widthStar, precisionStar) == Format.g); - assert(idx == 2); - - idx = 0; - assert(parsePrintfFormatSpecifier("%G", idx, widthStar, precisionStar) == Format.g); - assert(idx == 2); - - idx = 0; - assert(parsePrintfFormatSpecifier("%a", idx, widthStar, precisionStar) == Format.g); - assert(idx == 2); - - idx = 0; - assert(parsePrintfFormatSpecifier("%La", idx, widthStar, precisionStar) == Format.Lg); - assert(idx == 3); - - idx = 0; - assert(parsePrintfFormatSpecifier("%A", idx, widthStar, precisionStar) == Format.g); - assert(idx == 2); - - idx = 0; - assert(parsePrintfFormatSpecifier("%lg", idx, widthStar, precisionStar) == Format.lg); - assert(idx == 3); - - // width, precision - idx = 0; - assert(parsePrintfFormatSpecifier("%*d", idx, widthStar, precisionStar) == Format.d); - assert(idx == 3); - assert(widthStar && !precisionStar); - - idx = 0; - assert(parsePrintfFormatSpecifier("%.*d", idx, widthStar, precisionStar) == Format.d); - assert(idx == 4); - assert(!widthStar && precisionStar); - - idx = 0; - assert(parsePrintfFormatSpecifier("%*.*d", idx, widthStar, precisionStar) == Format.d); - assert(idx == 5); - assert(widthStar && precisionStar); - - // Too short formats - { - foreach (s; ["%", "%-", "%+", "% ", "%#", "%0", "%*", "%1", "%19", "%.", "%.*", "%.1", "%.12", - "%j", "%z", "%t", "%l", "%h", "%ll", "%hh"]) - { - idx = 0; - assert(parsePrintfFormatSpecifier(s, idx, widthStar, precisionStar) == Format.error); - assert(idx == s.length); - } - } - - // Undefined format combinations - { - foreach (s; ["%#d", "%llg", "%jg", "%zg", "%tg", "%hg", "%hhg", - "%#c", "%0c", "%jc", "%zc", "%tc", "%Lc", "%hc", "%hhc", "%llc", - "%#s", "%0s", "%js", "%zs", "%ts", "%Ls", "%hs", "%hhs", "%lls", - "%jp", "%zp", "%tp", "%Lp", "%hp", "%lp", "%hhp", "%llp", - "%-n", "%+n", "% n", "%#n", "%0n", "%*n", "%1n", "%19n", "%.n", "%.*n", "%.1n", "%.12n", "%Ln", "%K"]) - { - idx = 0; - assert(parsePrintfFormatSpecifier(s, idx, widthStar, precisionStar) == Format.error); - assert(idx == s.length); - } - } - - /* parseScanfFormatSpecifier - */ + size_t idx = 0; + bool widthStar; + bool precisionStar; - bool asterisk; + void testP(string fmtStr, Format expectedFormat, size_t expectedIdx) + { + idx = 0; + assert(parsePrintfFormatSpecifier(fmtStr, idx, widthStar, precisionStar, useGNUExts) == expectedFormat); + assert(idx == expectedIdx); + } // one for each Format - idx = 0; - assert(parseScanfFormatSpecifier("%d", idx, asterisk) == Format.d); - assert(idx == 2); - assert(!asterisk); + testP("%d", Format.d, 2); + assert(!widthStar && !precisionStar); + + testP("%ld", Format.ld, 3); + testP("%lld", Format.lld, 4); + testP("%jd", Format.jd, 3); + testP("%zd", Format.zd, 3); + testP("%td", Format.td, 3); + testP("%g", Format.g, 2); + testP("%Lg", Format.Lg, 3); + testP("%p", Format.p, 2); + testP("%n", Format.n, 2); + testP("%ln", Format.ln, 3); + testP("%lln", Format.lln, 4); + testP("%hn", Format.hn, 3); + testP("%hhn", Format.hhn, 4); + testP("%jn", Format.jn, 3); + testP("%zn", Format.zn, 3); + testP("%tn", Format.tn, 3); + testP("%c", Format.c, 2); + testP("%lc", Format.lc, 3); + testP("%s", Format.s, 2); + testP("%ls", Format.ls, 3); + testP("%%", Format.percent, 2); - idx = 0; - assert(parseScanfFormatSpecifier("%hhd", idx, asterisk) == Format.hhd); - assert(idx == 4); - - idx = 0; - assert(parseScanfFormatSpecifier("%hd", idx, asterisk) == Format.hd); - assert(idx == 3); - - idx = 0; - assert(parseScanfFormatSpecifier("%ld", idx, asterisk) == Format.ld); - assert(idx == 3); - - idx = 0; - assert(parseScanfFormatSpecifier("%lld", idx, asterisk) == Format.lld); - assert(idx == 4); - - idx = 0; - assert(parseScanfFormatSpecifier("%jd", idx, asterisk) == Format.jd); - assert(idx == 3); - - idx = 0; - assert(parseScanfFormatSpecifier("%zd", idx, asterisk) == Format.zd); - assert(idx == 3); - - idx = 0; - assert(parseScanfFormatSpecifier("%td", idx, asterisk,) == Format.td); - assert(idx == 3); - - idx = 0; - assert(parseScanfFormatSpecifier("%u", idx, asterisk) == Format.u); - assert(idx == 2); - - idx = 0; - assert(parseScanfFormatSpecifier("%hhu", idx, asterisk,) == Format.hhu); - assert(idx == 4); - - idx = 0; - assert(parseScanfFormatSpecifier("%hu", idx, asterisk) == Format.hu); - assert(idx == 3); - - idx = 0; - assert(parseScanfFormatSpecifier("%lu", idx, asterisk) == Format.lu); - assert(idx == 3); + // Synonyms + testP("%i", Format.d, 2); + testP("%u", Format.u, 2); + testP("%o", Format.u, 2); + testP("%x", Format.u, 2); + testP("%X", Format.u, 2); + testP("%f", Format.g, 2); + testP("%F", Format.g, 2); + testP("%G", Format.g, 2); + testP("%a", Format.g, 2); + testP("%La", Format.Lg, 3); + testP("%A", Format.g, 2); + testP("%lg", Format.lg, 3); + + // width, precision + testP("%*d", Format.d, 3); + assert(widthStar && !precisionStar); + + testP("%.*d", Format.d, 4); + assert(!widthStar && precisionStar); + + testP("%*.*d", Format.d, 5); + assert(widthStar && precisionStar); - idx = 0; - assert(parseScanfFormatSpecifier("%llu", idx, asterisk) == Format.llu); - assert(idx == 4); + // Too short formats + foreach (s; ["%", "%-", "%+", "% ", "%#", "%0", "%*", "%1", "%19", "%.", "%.*", "%.1", "%.12", + "%j", "%z", "%t", "%l", "%h", "%ll", "%hh"]) + { + testP(s, Format.error, s.length); + } - idx = 0; - assert(parseScanfFormatSpecifier("%ju", idx, asterisk) == Format.ju); - assert(idx == 3); + // Undefined format combinations + foreach (s; ["%#d", "%llg", "%jg", "%zg", "%tg", "%hg", "%hhg", + "%#c", "%0c", "%jc", "%zc", "%tc", "%Lc", "%hc", "%hhc", "%llc", + "%#s", "%0s", "%js", "%zs", "%ts", "%Ls", "%hs", "%hhs", "%lls", + "%jp", "%zp", "%tp", "%Lp", "%hp", "%lp", "%hhp", "%llp", + "%-n", "%+n", "% n", "%#n", "%0n", "%*n", "%1n", "%19n", "%.n", "%.*n", "%.1n", "%.12n", "%Ln", "%K"]) + { + testP(s, Format.error, s.length); + } - idx = 0; - assert(parseScanfFormatSpecifier("%g", idx, asterisk) == Format.g); - assert(idx == 2); + testP("%C", Format.lc, 2); + testP("%S", Format.ls, 2); - idx = 0; - assert(parseScanfFormatSpecifier("%lg", idx, asterisk) == Format.lg); - assert(idx == 3); + // GNU extensions: explicitly toggle ISO/GNU flag. + foreach (s; ["%jm", "%zm", "%tm", "%Lm", "%hm", "%hhm", "%lm", "%llm", + "%#m", "%+m", "%-m", "% m", "%0m"]) + { + useGNUExts = false; + testP(s, Format.error, s.length); + useGNUExts = true; + testP(s, Format.error, s.length); + } - idx = 0; - assert(parseScanfFormatSpecifier("%Lg", idx, asterisk) == Format.Lg); - assert(idx == 3); + foreach (s; ["%m", "%md", "%mz", "%mc", "%mm", "%msyz", "%ml", "%mlz", "%mlc", "%mlm"]) + { + // valid cases, all parsed as `%m` + // GNU printf() + useGNUExts = true; + testP(s, Format.GNU_m, 2); - idx = 0; - assert(parseScanfFormatSpecifier("%p", idx, asterisk) == Format.p); - assert(idx == 2); + // ISO printf() + useGNUExts = false; + testP(s, Format.error, 2); + } +} - idx = 0; - assert(parseScanfFormatSpecifier("%s", idx, asterisk) == Format.s); - assert(idx == 2); +@("parseScanfFormatSpecifier") unittest +{ + size_t idx; + bool asterisk; - idx = 0; - assert(parseScanfFormatSpecifier("%ls", idx, asterisk,) == Format.ls); - assert(idx == 3); + void testS(string fmtStr, Format expectedFormat, size_t expectedIdx) + { + idx = 0; + assert(parseScanfFormatSpecifier(fmtStr, idx, asterisk) == expectedFormat); + assert(idx == expectedIdx); + } - idx = 0; - assert(parseScanfFormatSpecifier("%%", idx, asterisk) == Format.percent); - assert(idx == 2); + // one for each Format + testS("%d", Format.d, 2); + testS("%hhd", Format.hhd, 4); + testS("%hd", Format.hd, 3); + testS("%ld", Format.ld, 3); + testS("%lld", Format.lld, 4); + testS("%jd", Format.jd, 3); + testS("%zd", Format.zd, 3); + testS("%td", Format.td, 3); + testS("%u", Format.u, 2); + testS("%hhu", Format.hhu, 4); + testS("%hu", Format.hu, 3); + testS("%lu", Format.lu, 3); + testS("%llu", Format.llu, 4); + testS("%ju", Format.ju, 3); + testS("%g", Format.g, 2); + testS("%lg", Format.lg, 3); + testS("%Lg", Format.Lg, 3); + testS("%p", Format.p, 2); + testS("%s", Format.s, 2); + testS("%ls", Format.ls, 3); + testS("%%", Format.percent, 2); // Synonyms - idx = 0; - assert(parseScanfFormatSpecifier("%i", idx, asterisk) == Format.d); - assert(idx == 2); + testS("%i", Format.d, 2); + testS("%n", Format.n, 2); - idx = 0; - assert(parseScanfFormatSpecifier("%n", idx, asterisk) == Format.n); - assert(idx == 2); - - idx = 0; - assert(parseScanfFormatSpecifier("%o", idx, asterisk) == Format.u); - assert(idx == 2); - - idx = 0; - assert(parseScanfFormatSpecifier("%x", idx, asterisk) == Format.u); - assert(idx == 2); - - idx = 0; - assert(parseScanfFormatSpecifier("%f", idx, asterisk) == Format.g); - assert(idx == 2); - - idx = 0; - assert(parseScanfFormatSpecifier("%e", idx, asterisk) == Format.g); - assert(idx == 2); - - idx = 0; - assert(parseScanfFormatSpecifier("%a", idx, asterisk) == Format.g); - assert(idx == 2); - - idx = 0; - assert(parseScanfFormatSpecifier("%c", idx, asterisk) == Format.c); - assert(idx == 2); + testS("%o", Format.u, 2); + testS("%x", Format.u, 2); + testS("%f", Format.g, 2); + testS("%e", Format.g, 2); + testS("%a", Format.g, 2); + testS("%c", Format.c, 2); // asterisk - idx = 0; - assert(parseScanfFormatSpecifier("%*d", idx, asterisk) == Format.d); - assert(idx == 3); + testS("%*d", Format.d, 3); assert(asterisk); - idx = 0; - assert(parseScanfFormatSpecifier("%9ld", idx, asterisk) == Format.ld); - assert(idx == 4); + testS("%9ld", Format.ld, 4); assert(!asterisk); - idx = 0; - assert(parseScanfFormatSpecifier("%*25984hhd", idx, asterisk) == Format.hhd); - assert(idx == 10); + testS("%*25984hhd", Format.hhd, 10); assert(asterisk); // scansets - idx = 0; - assert(parseScanfFormatSpecifier("%[a-zA-Z]", idx, asterisk) == Format.s); - assert(idx == 9); + testS("%[a-zA-Z]", Format.s, 9); assert(!asterisk); - idx = 0; - assert(parseScanfFormatSpecifier("%*25l[a-z]", idx, asterisk) == Format.ls); - assert(idx == 10); + testS("%*25l[a-z]", Format.ls, 10); assert(asterisk); - idx = 0; - assert(parseScanfFormatSpecifier("%[]]", idx, asterisk) == Format.s); - assert(idx == 4); + testS("%[]]", Format.s, 4); assert(!asterisk); - idx = 0; - assert(parseScanfFormatSpecifier("%[^]]", idx, asterisk) == Format.s); - assert(idx == 5); + testS("%[^]]", Format.s, 5); assert(!asterisk); // Too short formats foreach (s; ["%", "% ", "%#", "%0", "%*", "%1", "%19", "%j", "%z", "%t", "%l", "%h", "%ll", "%hh", "%K"]) { - idx = 0; - assert(parseScanfFormatSpecifier(s, idx, asterisk) == Format.error); - assert(idx == s.length); + + testS(s, Format.error, s.length); } @@ -1468,18 +1292,16 @@ unittest "%jp", "%zp", "%tp", "%Lp", "%hp", "%lp", "%hhp", "%llp", "%-", "%+", "%#", "%0", "%.", "%Ln"]) { - idx = 0; - assert(parseScanfFormatSpecifier(s, idx, asterisk) == Format.error); - assert(idx == s.length); + + testS(s, Format.error, s.length); } // Invalid scansets foreach (s; ["%[]", "%[^", "%[^]", "%[s", "%[0-9lld", "%[", "%l[^]"]) { - idx = 0; - assert(parseScanfFormatSpecifier(s, idx, asterisk) == Format.error); - assert(idx == s.length); + + testS(s, Format.error, s.length); } // Posix extensions @@ -1488,95 +1310,19 @@ unittest "%LC", "%lC", "%llC", "%jC", "%tC", "%hC", "%hhC", "%zC", "%LS", "%lS", "%llS", "%jS", "%tS", "%hS", "%hhS", "%zS"]) { - idx = 0; - assert(parseScanfFormatSpecifier(s, idx, asterisk) == Format.error); - assert(idx == s.length); - } - idx = 0; - assert(parseScanfFormatSpecifier("%mc", idx, asterisk) == Format.POSIX_ms); - assert(idx == 3); - - idx = 0; - assert(parseScanfFormatSpecifier("%ms", idx, asterisk) == Format.POSIX_ms); - assert(idx == 3); - - idx = 0; - assert(parseScanfFormatSpecifier("%m[0-9]", idx, asterisk) == Format.POSIX_ms); - assert(idx == 7); - - idx = 0; - assert(parseScanfFormatSpecifier("%mlc", idx, asterisk) == Format.POSIX_mls); - assert(idx == 4); - - idx = 0; - assert(parseScanfFormatSpecifier("%mls", idx, asterisk) == Format.POSIX_mls); - assert(idx == 4); - - idx = 0; - assert(parseScanfFormatSpecifier("%ml[^0-9]", idx, asterisk) == Format.POSIX_mls); - assert(idx == 9); - - idx = 0; - assert(parseScanfFormatSpecifier("%mC", idx, asterisk) == Format.POSIX_mls); - assert(idx == 3); - - idx = 0; - assert(parseScanfFormatSpecifier("%mS", idx, asterisk) == Format.POSIX_mls); - assert(idx == 3); - - idx = 0; - assert(parsePrintfFormatSpecifier("%C", idx, widthStar, precisionStar) == Format.lc); - assert(idx == 2); - - idx = 0; - assert(parseScanfFormatSpecifier("%C", idx, asterisk) == Format.lc); - assert(idx == 2); - - idx = 0; - assert(parsePrintfFormatSpecifier("%S", idx, widthStar, precisionStar) == Format.ls); - assert(idx == 2); - - idx = 0; - assert(parseScanfFormatSpecifier("%S", idx, asterisk) == Format.ls); - assert(idx == 2); - - // GNU extensions: explicitly toggle ISO/GNU flag. - // ISO printf() - bool useGNUExts = false; - { - foreach (s; ["%jm", "%zm", "%tm", "%Lm", "%hm", "%hhm", "%lm", "%llm", - "%#m", "%+m", "%-m", "% m", "%0m"]) - { - idx = 0; - assert(parsePrintfFormatSpecifier(s, idx, widthStar, precisionStar, useGNUExts) == Format.error); - assert(idx == s.length); - } - foreach (s; ["%m", "%md", "%mz", "%mc", "%mm", "%msyz", "%ml", "%mlz", "%mlc", "%mlm"]) - { - idx = 0; - assert(parsePrintfFormatSpecifier(s, idx, widthStar, precisionStar, useGNUExts) == Format.error); - assert(idx == 2); - } + testS(s, Format.error, s.length); } - // GNU printf() - useGNUExts = true; - { - foreach (s; ["%jm", "%zm", "%tm", "%Lm", "%hm", "%hhm", "%lm", "%llm", - "%#m", "%+m", "%-m", "% m", "%0m"]) - { - idx = 0; - assert(parsePrintfFormatSpecifier(s, idx, widthStar, precisionStar, useGNUExts) == Format.error); - assert(idx == s.length); - } - - // valid cases, all parsed as `%m` - foreach (s; ["%m", "%md", "%mz", "%mc", "%mm", "%msyz", "%ml", "%mlz", "%mlc", "%mlm"]) - { - idx = 0; - assert(parsePrintfFormatSpecifier(s, idx, widthStar, precisionStar, useGNUExts) == Format.GNU_m); - assert(idx == 2); - } - } + testS("%mc", Format.POSIX_ms, 3); + testS("%ms", Format.POSIX_ms, 3); + testS("%m[0-9]", Format.POSIX_ms, 7); + testS("%mlc", Format.POSIX_mls, 4); + testS("%mls", Format.POSIX_mls, 4); + testS("%ml[^0-9]", Format.POSIX_mls, 9); + testS("%mC", Format.POSIX_mls, 3); + testS("%mS", Format.POSIX_mls, 3); + + testS("%C", Format.lc, 2); + testS("%S", Format.ls, 2); } diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d index 1a26eaa..ba7d590 100644 --- a/gcc/d/dmd/clone.d +++ b/gcc/d/dmd/clone.d @@ -105,8 +105,7 @@ FuncDeclaration hasIdentityOpAssign(AggregateDeclaration ad, Scope* sc) scope er = new NullExp(ad.loc, ad.type); // dummy rvalue scope el = new IdentifierExp(ad.loc, Id.p); // dummy lvalue el.type = ad.type; - Expressions a; - a.setDim(1); + auto a = Expressions(1); const errors = global.startGagging(); // Do not report errors, even if the template opAssign fbody makes it. sc = sc.push(); sc.tinst = null; @@ -465,8 +464,7 @@ private FuncDeclaration hasIdentityOpEquals(AggregateDeclaration ad, Scope* sc) */ scope er = new NullExp(ad.loc, null); // dummy rvalue scope el = new IdentifierExp(ad.loc, Id.p); // dummy lvalue - Expressions a; - a.setDim(1); + auto a = Expressions(1); bool hasIt(Type tthis) { diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d index 2679a63..2c5a4f0 100644 --- a/gcc/d/dmd/cparse.d +++ b/gcc/d/dmd/cparse.d @@ -1886,15 +1886,6 @@ final class CParser(AST) : Parser!AST } if (s !is null) { - s = applySpecifier(s, specifier); - if (level == LVL.local) - { - // Wrap the declaration in `extern (C) { declaration }` - // Necessary for function pointers, but harmless to apply to all. - auto decls = new AST.Dsymbols(1); - (*decls)[0] = s; - s = new AST.LinkDeclaration(s.loc, linkage, decls); - } // Saw `asm("name")` in the function, type, or variable definition. // This is equivalent to `pragma(mangle, "name")` in D if (asmName) @@ -1917,6 +1908,15 @@ final class CParser(AST) : Parser!AST p.mangleOverride = str; } } + s = applySpecifier(s, specifier); + if (level == LVL.local) + { + // Wrap the declaration in `extern (C) { declaration }` + // Necessary for function pointers, but harmless to apply to all. + auto decls = new AST.Dsymbols(1); + (*decls)[0] = s; + s = new AST.LinkDeclaration(s.loc, linkage, decls); + } symbols.push(s); } first = false; @@ -2603,7 +2603,6 @@ final class CParser(AST) : Parser!AST { //printf("cparseDeclarator(%d, %p)\n", declarator, t); AST.Types constTypes; // all the Types that will need `const` applied to them - constTypes.setDim(0); AST.Type parseDecl(AST.Type t) { diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d index afd19f3..8ab3873 100644 --- a/gcc/d/dmd/dcast.d +++ b/gcc/d/dmd/dcast.d @@ -2979,10 +2979,10 @@ Lagain: return Lret(t); if (t1n.ty == Tvoid) // pointers to void are always compatible - return Lret(t2); + return Lret(t1); if (t2n.ty == Tvoid) - return Lret(t); + return Lret(t2); if (t1.implicitConvTo(t2)) return convert(e1, t2); diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h index bc8db44..5bce6b0 100644 --- a/gcc/d/dmd/declaration.h +++ b/gcc/d/dmd/declaration.h @@ -210,7 +210,7 @@ public: Dsymbol *aliassym; const char *kind() const override; - bool equals(const RootObject *o) const override; + bool equals(const RootObject * const o) const override; bool overloadInsert(Dsymbol *s) override; Dsymbol *toAlias() override; @@ -625,7 +625,7 @@ public: FuncDeclaration *syntaxCopy(Dsymbol *) override; bool functionSemantic(); bool functionSemantic3(); - bool equals(const RootObject *o) const override final; + bool equals(const RootObject * const o) const override final; int overrides(FuncDeclaration *fd); int findVtblIndex(Dsymbols *vtbl, int dim); diff --git a/gcc/d/dmd/dimport.d b/gcc/d/dmd/dimport.d index 5cc3772..705acd1 100644 --- a/gcc/d/dmd/dimport.d +++ b/gcc/d/dmd/dimport.d @@ -265,11 +265,16 @@ extern (C++) final class Import : Dsymbol scopesym.addAccessiblePackage(p, visibility); foreach (id; packages[1 .. $]) // [b, c] { - p = cast(Package) p.symtab.lookup(id); + auto sym = p.symtab.lookup(id); // https://issues.dlang.org/show_bug.cgi?id=17991 // An import of truly empty file/package can happen // https://issues.dlang.org/show_bug.cgi?id=20151 // Package in the path conflicts with a module name + if (sym is null) + break; + // https://issues.dlang.org/show_bug.cgi?id=23327 + // Package conflicts with symbol of the same name + p = sym.isPackage(); if (p is null) break; scopesym.addAccessiblePackage(p, visibility); diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d index a9fd0f5..a95d9de 100644 --- a/gcc/d/dmd/dinterpret.d +++ b/gcc/d/dmd/dinterpret.d @@ -2830,7 +2830,7 @@ public: (*exps)[i] = ex; } } - sd.fill(e.loc, exps, false); + sd.fill(e.loc, *exps, false); auto se = ctfeEmplaceExp!StructLiteralExp(e.loc, sd, exps, e.newtype); se.origin = se; @@ -4778,12 +4778,6 @@ public: // If `_d_HookTraceImpl` is found, resolve the underlying hook and replace `e` and `fd` with it. removeHookTraceImpl(e, fd); - bool isArrayConstructionOrAssign(FuncDeclaration fd) - { - return fd.ident == Id._d_arrayctor || fd.ident == Id._d_arraysetctor || - fd.ident == Id._d_arrayassign_l || fd.ident == Id._d_arrayassign_r; - } - if (fd.ident == Id.__ArrayPostblit || fd.ident == Id.__ArrayDtor) { assert(e.arguments.dim == 1); @@ -4837,11 +4831,11 @@ public: result = interpretRegion(ae, istate); return; } - else if (isArrayConstructionOrAssign(fd)) + else if (isArrayConstructionOrAssign(fd.ident)) { // In expressionsem.d, the following lowerings were performed: // * `T[x] ea = eb;` to `_d_array{,set}ctor(ea[], eb[]);`. - // * `ea = eb` (ea and eb are arrays) to `_d_arrayassign_{l,r}(ea[], eb[])`. + // * `ea = eb` to `_d_array{,setassign,assign_l,assign_r}(ea[], eb)`. // The following code will rewrite them back to `ea = eb` and // then interpret that expression. diff --git a/gcc/d/dmd/dmangle.d b/gcc/d/dmd/dmangle.d index 25794e2..be0cbcc 100644 --- a/gcc/d/dmd/dmangle.d +++ b/gcc/d/dmd/dmangle.d @@ -833,6 +833,23 @@ public: printf(" parent = %s %s", s.parent.kind(), s.parent.toChars()); printf("\n"); } + if (s.parent && s.ident) + { + if (auto m = s.parent.isModule()) + { + if (m.filetype == FileType.c) + { + /* C types at global level get mangled into the __C global namespace + * to get the same mangling regardless of which module it + * is declared in. This works because types are the same if the mangling + * is the same. + */ + mangleIdentifier(Id.ImportC, s); // parent + mangleIdentifier(s.ident, s); + return; + } + } + } mangleParent(s); if (s.ident) mangleIdentifier(s.ident, s); diff --git a/gcc/d/dmd/doc.d b/gcc/d/dmd/doc.d index ba83649..e1d5897 100644 --- a/gcc/d/dmd/doc.d +++ b/gcc/d/dmd/doc.d @@ -3294,7 +3294,7 @@ private struct MarkdownLink * Params: * buf = an OutBuffer containing the DDoc * i = the index within `buf` that points to the first character of the URL. - * If this function succeeds `i` will point just after the the end of the URL. + * If this function succeeds `i` will point just after the end of the URL. * Returns: whether a URL was found and parsed */ private bool parseHref(ref OutBuffer buf, ref size_t i) @@ -3362,7 +3362,7 @@ private struct MarkdownLink * Params: * buf = an OutBuffer containing the DDoc * i = the index within `buf` that points to the first character of the title. - * If this function succeeds `i` will point just after the the end of the title. + * If this function succeeds `i` will point just after the end of the title. * Returns: whether a title was found and parsed */ private bool parseTitle(ref OutBuffer buf, ref size_t i) diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d index c940ff0..7e2d02f 100644 --- a/gcc/d/dmd/dsymbol.d +++ b/gcc/d/dmd/dsymbol.d @@ -1544,6 +1544,12 @@ public: if (flags & IgnoreAmbiguous) // if return NULL on ambiguity return null; + + /* If two imports from C import files, pick first one, as C has global name space + */ + if (s.isCsymbol() && s2.isCsymbol()) + continue; + if (!(flags & IgnoreErrors)) ScopeDsymbol.multiplyDefined(loc, s, s2); break; diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h index bea4b77..acf0004 100644 --- a/gcc/d/dmd/dsymbol.h +++ b/gcc/d/dmd/dsymbol.h @@ -189,7 +189,7 @@ public: virtual const char *toPrettyCharsHelper(); // helper to print fully qualified (template) arguments Loc getLoc(); const char *locToChars(); - bool equals(const RootObject *o) const override; + bool equals(const RootObject * const o) const override; bool isAnonymous() const; void error(const Loc &loc, const char *format, ...); void error(const char *format, ...); diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index c3424dc..701f06a 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -58,6 +58,7 @@ import dmd.nspace; import dmd.objc; import dmd.opover; import dmd.parse; +import dmd.root.array; import dmd.root.filename; import dmd.common.outbuffer; import dmd.root.rmem; @@ -983,7 +984,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor // possibilities. if (fd && !(dsym.storage_class & (STC.manifest | STC.static_ | STC.gshared | STC.extern_)) && !dsym._init.isVoidInitializer()) { - //printf("fd = '%s', var = '%s'\n", fd.toChars(), toChars()); + //printf("fd = '%s', var = '%s'\n", fd.toChars(), dsym.toChars()); if (!ei) { ArrayInitializer ai = dsym._init.isArrayInitializer(); @@ -1014,24 +1015,6 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor dsym._init = dsym._init.initializerSemantic(sc, dsym.type, INITinterpret); } - Expression exp = ei.exp; - Expression e1 = new VarExp(dsym.loc, dsym); - if (isBlit) - exp = new BlitExp(dsym.loc, e1, exp); - else - exp = new ConstructExp(dsym.loc, e1, exp); - dsym.canassign++; - exp = exp.expressionSemantic(sc); - dsym.canassign--; - exp = exp.optimize(WANTvalue); - if (exp.op == EXP.error) - { - dsym._init = new ErrorInitializer(); - ei = null; - } - else - ei.exp = exp; - if (ei && dsym.isScope()) { Expression ex = ei.exp.lastComma(); @@ -1054,6 +1037,24 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor f.tookAddressOf--; } } + + Expression exp = ei.exp; + Expression e1 = new VarExp(dsym.loc, dsym); + if (isBlit) + exp = new BlitExp(dsym.loc, e1, exp); + else + exp = new ConstructExp(dsym.loc, e1, exp); + dsym.canassign++; + exp = exp.expressionSemantic(sc); + dsym.canassign--; + exp = exp.optimize(WANTvalue); + if (exp.op == EXP.error) + { + dsym._init = new ErrorInitializer(); + ei = null; + } + else + ei.exp = exp; } else { @@ -1956,7 +1957,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor //printf("UserAttributeDeclaration::semantic() %p\n", this); if (uad.decl && !uad._scope) uad.Dsymbol.setScope(sc); // for function local symbols - arrayExpressionSemantic(uad.atts, sc, true); + arrayExpressionSemantic(uad.atts.peekSlice(), sc, true); return attribSemantic(uad); } @@ -4182,6 +4183,13 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor dd.errors = true; return; } + + if (ad.isClassDeclaration() && ad.classKind == ClassKind.d) + { + // Class destructors are implicitly `scope` + dd.storage_class |= STC.scope_; + } + if (dd.ident == Id.dtor && dd.semanticRun < PASS.semantic) ad.userDtors.push(dd); if (!dd.type) diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index 34cae1d..13efc1c 100644 --- a/gcc/d/dmd/dtemplate.d +++ b/gcc/d/dmd/dtemplate.d @@ -1327,7 +1327,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol Loc instLoc = ti.loc; Objects* tiargs = ti.tiargs; - auto dedargs = new Objects(); + auto dedargs = new Objects(parameters.dim); Objects* dedtypes = &ti.tdtypes; // for T:T*, the dedargs is the T*, dedtypes is the T version (none) @@ -1346,7 +1346,6 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol assert(_scope); - dedargs.setDim(parameters.dim); dedargs.zero(); dedtypes.setDim(parameters.dim); @@ -1511,7 +1510,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol } } - if (toParent().isModule() || (_scope.stc & STC.static_)) + if (toParent().isModule()) tthis = null; if (tthis) { @@ -1534,7 +1533,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol } // Match attributes of tthis against attributes of fd - if (fd.type && !fd.isCtorDeclaration()) + if (fd.type && !fd.isCtorDeclaration() && !(_scope.stc & STC.static_)) { StorageClass stc = _scope.stc | fd.storage_class2; // Propagate parent storage class, https://issues.dlang.org/show_bug.cgi?id=5504 @@ -2716,14 +2715,27 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, if (mfa == MATCH.nomatch) return 0; - if (mfa > m.last) goto LfIsBetter; - if (mfa < m.last) goto LlastIsBetter; + int firstIsBetter() + { + td_best = null; + ti_best = null; + ta_last = MATCH.exact; + m.last = mfa; + m.lastf = fd; + tthis_best = tthis_fd; + ov_index = 0; + m.count = 1; + return 0; + } + + if (mfa > m.last) return firstIsBetter(); + if (mfa < m.last) return 0; /* See if one of the matches overrides the other. */ assert(m.lastf); - if (m.lastf.overrides(fd)) goto LlastIsBetter; - if (fd.overrides(m.lastf)) goto LfIsBetter; + if (m.lastf.overrides(fd)) return 0; + if (fd.overrides(m.lastf)) return firstIsBetter(); /* Try to disambiguate using template-style partial ordering rules. * In essence, if f() and g() are ambiguous, if f() can call g(), @@ -2734,8 +2746,8 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, MATCH c1 = fd.leastAsSpecialized(m.lastf); MATCH c2 = m.lastf.leastAsSpecialized(fd); //printf("c1 = %d, c2 = %d\n", c1, c2); - if (c1 > c2) goto LfIsBetter; - if (c1 < c2) goto LlastIsBetter; + if (c1 > c2) return firstIsBetter(); + if (c1 < c2) return 0; } /* The 'overrides' check above does covariant checking only @@ -2756,12 +2768,12 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, { if (firstCovariant != Covariant.yes && firstCovariant != Covariant.no) { - goto LlastIsBetter; + return 0; } } else if (firstCovariant == Covariant.yes || firstCovariant == Covariant.no) { - goto LfIsBetter; + return firstIsBetter(); } } @@ -2780,37 +2792,22 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, fd._linkage == m.lastf._linkage) { if (fd.fbody && !m.lastf.fbody) - goto LfIsBetter; + return firstIsBetter(); if (!fd.fbody) - goto LlastIsBetter; + return 0; } // https://issues.dlang.org/show_bug.cgi?id=14450 // Prefer exact qualified constructor for the creating object type if (isCtorCall && tf.mod != m.lastf.type.mod) { - if (tthis.mod == tf.mod) goto LfIsBetter; - if (tthis.mod == m.lastf.type.mod) goto LlastIsBetter; + if (tthis.mod == tf.mod) return firstIsBetter(); + if (tthis.mod == m.lastf.type.mod) return 0; } m.nextf = fd; m.count++; return 0; - - LlastIsBetter: - return 0; - - LfIsBetter: - td_best = null; - ti_best = null; - ta_last = MATCH.exact; - m.last = mfa; - m.lastf = fd; - tthis_best = tthis_fd; - ov_index = 0; - m.count = 1; - return 0; - } int applyTemplate(TemplateDeclaration td) @@ -3844,10 +3841,20 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param tp = (*parameters)[i]; else { + Loc loc; + // The "type" (it hasn't been resolved yet) of the function parameter + // does not have a location but the parameter it is related to does, + // so we use that for the resolution (better error message). + if (inferStart < parameters.dim) + { + TemplateParameter loctp = (*parameters)[inferStart]; + loc = loctp.loc; + } + Expression e; Type tx; Dsymbol s; - taa.index.resolve(Loc.initial, sc, e, tx, s); + taa.index.resolve(loc, sc, e, tx, s); edim = s ? getValue(s) : getValue(e); } } diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d index 4f06bac..7ba0a96 100644 --- a/gcc/d/dmd/escape.d +++ b/gcc/d/dmd/escape.d @@ -1423,10 +1423,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) * auto dg = () return { return &x; } * Because dg.ptr points to x, this is returning dt.ptr+offset */ - if (global.params.useDIP1000 == FeatureState.enabled) - { - sc.func.storage_class |= STC.return_ | STC.returninferred; - } + sc.func.storage_class |= STC.return_ | STC.returninferred; } } diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index f871fade..42b4dd4 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -7197,6 +7197,26 @@ extern(D) Modifiable checkModifiable(Expression exp, Scope* sc, ModifyFlags flag } } +/** + * Verify if the given identifier is any of + * _d_array{ctor,setctor,setassign,assign_l, assign_r}. + * + * Params: + * id = the identifier to verify + * + * Returns: + * `true` if the identifier corresponds to a construction of assignement + * runtime hook, `false` otherwise. + */ +bool isArrayConstructionOrAssign(const Identifier id) +{ + import dmd.id : Id; + + return id == Id._d_arrayctor || id == Id._d_arraysetctor || + id == Id._d_arrayassign_l || id == Id._d_arrayassign_r || + id == Id._d_arraysetassign; +} + /****************************** * Provide efficient way to implement isUnaExp(), isBinExp(), isBinAssignExp() */ diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h index 9ab1cab..c9e3978 100644 --- a/gcc/d/dmd/expression.h +++ b/gcc/d/dmd/expression.h @@ -250,7 +250,7 @@ public: static IntegerExp *create(const Loc &loc, dinteger_t value, Type *type); static void emplace(UnionExp *pue, const Loc &loc, dinteger_t value, Type *type); - bool equals(const RootObject *o) const override; + bool equals(const RootObject * const o) const override; dinteger_t toInteger() override; real_t toReal() override; real_t toImaginary() override; @@ -280,7 +280,7 @@ public: static RealExp *create(const Loc &loc, real_t value, Type *type); static void emplace(UnionExp *pue, const Loc &loc, real_t value, Type *type); - bool equals(const RootObject *o) const override; + bool equals(const RootObject * const o) const override; dinteger_t toInteger() override; uinteger_t toUInteger() override; real_t toReal() override; @@ -297,7 +297,7 @@ public: static ComplexExp *create(const Loc &loc, complex_t value, Type *type); static void emplace(UnionExp *pue, const Loc &loc, complex_t value, Type *type); - bool equals(const RootObject *o) const override; + bool equals(const RootObject * const o) const override; dinteger_t toInteger() override; uinteger_t toUInteger() override; real_t toReal() override; @@ -358,7 +358,7 @@ public: class NullExp final : public Expression { public: - bool equals(const RootObject *o) const override; + bool equals(const RootObject * const o) const override; Optional<bool> toBool() override; StringExp *toStringExp() override; void accept(Visitor *v) override { v->visit(this); } @@ -377,7 +377,7 @@ public: static StringExp *create(const Loc &loc, const char *s); static StringExp *create(const Loc &loc, const void *s, d_size_t len); static void emplace(UnionExp *pue, const Loc &loc, const char *s); - bool equals(const RootObject *o) const override; + bool equals(const RootObject * const o) const override; char32_t getCodeUnit(d_size_t i) const; void setCodeUnit(d_size_t i, char32_t c); StringExp *toStringExp() override; @@ -408,7 +408,7 @@ public: static TupleExp *create(const Loc &loc, Expressions *exps); TupleExp *syntaxCopy() override; - bool equals(const RootObject *o) const override; + bool equals(const RootObject * const o) const override; void accept(Visitor *v) override { v->visit(this); } }; @@ -423,7 +423,7 @@ public: static ArrayLiteralExp *create(const Loc &loc, Expressions *elements); static void emplace(UnionExp *pue, const Loc &loc, Expressions *elements); ArrayLiteralExp *syntaxCopy() override; - bool equals(const RootObject *o) const override; + bool equals(const RootObject * const o) const override; Expression *getElement(d_size_t i); // use opIndex instead Expression *opIndex(d_size_t i); Optional<bool> toBool() override; @@ -439,7 +439,7 @@ public: Expressions *values; OwnedBy ownedByCtfe; - bool equals(const RootObject *o) const override; + bool equals(const RootObject * const o) const override; AssocArrayLiteralExp *syntaxCopy() override; Optional<bool> toBool() override; @@ -477,7 +477,7 @@ public: OwnedBy ownedByCtfe; static StructLiteralExp *create(const Loc &loc, StructDeclaration *sd, void *elements, Type *stype = NULL); - bool equals(const RootObject *o) const override; + bool equals(const RootObject * const o) const override; StructLiteralExp *syntaxCopy() override; Expression *getField(Type *type, unsigned offset); int getFieldIndex(Type *type, unsigned offset); @@ -583,7 +583,7 @@ class VarExp final : public SymbolExp public: bool delegateWasExtracted; static VarExp *create(const Loc &loc, Declaration *var, bool hasOverloads = true); - bool equals(const RootObject *o) const override; + bool equals(const RootObject * const o) const override; bool isLvalue() override; Expression *toLvalue(Scope *sc, Expression *e) override; Expression *modifiableLvalue(Scope *sc, Expression *e) override; @@ -612,7 +612,7 @@ public: TemplateDeclaration *td; TOK tok; - bool equals(const RootObject *o) const override; + bool equals(const RootObject * const o) const override; FuncExp *syntaxCopy() override; const char *toChars() const override; bool checkType() override; diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index 3114100..8a4a13c 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -62,6 +62,7 @@ import dmd.opover; import dmd.optimize; import dmd.parse; import dmd.printast; +import dmd.root.array; import dmd.root.ctfloat; import dmd.root.file; import dmd.root.filename; @@ -336,22 +337,18 @@ Expression resolveOpDollar(Scope* sc, ArrayExp ae, IntervalExp ie, Expression* p /****************************** * Perform semantic() on an array of Expressions. */ -bool arrayExpressionSemantic(Expressions* exps, Scope* sc, bool preserveErrors = false) +extern(D) bool arrayExpressionSemantic( + Expression[] exps, Scope* sc, bool preserveErrors = false) { bool err = false; - if (exps) + foreach (ref e; exps) { - foreach (ref e; *exps) - { - if (e) - { - auto e2 = e.expressionSemantic(sc); - if (e2.op == EXP.error) - err = true; - if (preserveErrors || e2.op != EXP.error) - e = e2; - } - } + if (e is null) continue; + auto e2 = e.expressionSemantic(sc); + if (e2.op == EXP.error) + err = true; + if (preserveErrors || e2.op != EXP.error) + e = e2; } return err; } @@ -443,7 +440,7 @@ private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident) } if (!s) - return ue.e1.type.getProperty(sc, loc, ident, 0); + return ue.e1.type.getProperty(sc, loc, ident, 0, ue.e1); FuncDeclaration f = s.isFuncDeclaration(); if (f) @@ -550,7 +547,7 @@ private Expression resolveUFCS(Scope* sc, CallExp ce) if (!global.endGagging(errors)) return e; - if (arrayExpressionSemantic(originalArguments, sc)) + if (arrayExpressionSemantic(originalArguments.peekSlice(), sc)) return ErrorExp.get(); /* fall down to UFCS */ @@ -3111,7 +3108,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (e.basis) e.basis = e.basis.expressionSemantic(sc); - if (arrayExpressionSemantic(e.elements, sc) || (e.basis && e.basis.op == EXP.error)) + if (arrayExpressionSemantic(e.elements.peekSlice(), sc) || (e.basis && e.basis.op == EXP.error)) return setError(); expandTuples(e.elements); @@ -3154,8 +3151,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } // Run semantic() on each element - bool err_keys = arrayExpressionSemantic(e.keys, sc); - bool err_vals = arrayExpressionSemantic(e.values, sc); + bool err_keys = arrayExpressionSemantic(e.keys.peekSlice(), sc); + bool err_vals = arrayExpressionSemantic(e.values.peekSlice(), sc); if (err_keys || err_vals) return setError(); @@ -3201,7 +3198,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); // run semantic() on each element - if (arrayExpressionSemantic(e.elements, sc)) + if (arrayExpressionSemantic(e.elements.peekSlice(), sc)) return setError(); expandTuples(e.elements); @@ -3213,7 +3210,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor /* Fill out remainder of elements[] with default initializers for fields[] */ - if (!e.sd.fill(e.loc, e.elements, false)) + if (!e.sd.fill(e.loc, *e.elements, false)) { /* An error in the initializer needs to be recorded as an error * in the enclosing function or template, since the initializer @@ -3524,7 +3521,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.newtype = exp.type; // in case type gets cast to something else Type tb = exp.type.toBasetype(); //printf("tb: %s, deco = %s\n", tb.toChars(), tb.deco); - if (arrayExpressionSemantic(exp.arguments, sc)) + if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc)) { return setError(); } @@ -3672,7 +3669,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } } - if (cd.disableNew) + if (cd.disableNew && !exp.onstack) { exp.error("cannot allocate `class %s` with `new` because it is annotated with `@disable new()`", originalNewtype.toChars()); @@ -3807,7 +3804,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (!sd.fit(exp.loc, sc, exp.arguments, tb)) return setError(); - if (!sd.fill(exp.loc, exp.arguments, false)) + if (!sd.fill(exp.loc, *exp.arguments, false)) return setError(); if (checkFrameAccess(exp.loc, sc, sd, exp.arguments ? exp.arguments.dim : 0)) @@ -4259,7 +4256,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } if (FuncExp fe = exp.e1.isFuncExp()) { - if (arrayExpressionSemantic(exp.arguments, sc) || preFunctionParameters(sc, exp.arguments)) + if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc) || + preFunctionParameters(sc, exp.arguments)) return setError(); // Run e1 semantic even if arguments have any errors @@ -4497,7 +4495,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = exp.e1; return; } - if (arrayExpressionSemantic(exp.arguments, sc) || preFunctionParameters(sc, exp.arguments)) + if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc) || + preFunctionParameters(sc, exp.arguments)) return setError(); // Check for call operator overload @@ -4543,7 +4542,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor goto Lx; auto sle = new StructLiteralExp(exp.loc, sd, null, exp.e1.type); - if (!sd.fill(exp.loc, sle.elements, true)) + if (!sd.fill(exp.loc, *sle.elements, true)) return setError(); if (checkFrameAccess(exp.loc, sc, sd, sle.elements.dim)) return setError(); @@ -4614,7 +4613,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { Expression e; - // Make sure to use the the enum type itself rather than its + // Make sure to use the enum type itself rather than its // base type // https://issues.dlang.org/show_bug.cgi?id=16346 if (exp.e1.type.ty == Tenum) @@ -8661,7 +8660,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (sd.isNested()) { auto sle = new StructLiteralExp(loc, sd, null, t); - if (!sd.fill(loc, sle.elements, true)) + if (!sd.fill(loc, *sle.elements, true)) return ErrorExp.get(); if (checkFrameAccess(loc, sc, sd, sle.elements.dim)) return ErrorExp.get(); @@ -9991,15 +9990,15 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } /*************************************** - * Lower AssignExp to `_d_arrayassign_{l,r}` if needed. + * Lower AssignExp to `_d_array{setassign,assign_l,assign_r}` if needed. * * Params: * ae = the AssignExp to be lowered * fromCommaExp = indicates whether `ae` is part of a CommaExp or not, * so no unnecessary temporay variable is created. * Returns: - * a CommaExp contiaining call a to `_d_arrayassign_{l,r}` if needed or - * `ae` otherwise + * a CommaExp contiaining call a to `_d_array{setassign,assign_l,assign_r}` + * if needed or `ae` otherwise */ private Expression lowerArrayAssign(AssignExp ae, bool fromCommaExp = false) { @@ -10007,12 +10006,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (t1b.ty != Tsarray && t1b.ty != Tarray) return ae; - const isArrayAssign = - (ae.e1.isSliceExp || ae.e1.type.ty == Tsarray) && + const isArrayAssign = (ae.e1.isSliceExp() || ae.e1.type.ty == Tsarray) && (ae.e2.type.ty == Tsarray || ae.e2.type.ty == Tarray) && - (ae.e1.type.nextOf && ae.e2.type.nextOf && ae.e1.type.nextOf.mutableOf.equals(ae.e2.type.nextOf.mutableOf)); + (ae.e1.type.nextOf() && ae.e2.type.nextOf() && ae.e1.type.nextOf.mutableOf.equals(ae.e2.type.nextOf.mutableOf())); - if (!isArrayAssign) + const isArraySetAssign = (ae.e1.isSliceExp() || ae.e1.type.ty == Tsarray) && + (ae.e1.type.nextOf() && ae.e2.type.implicitConvTo(ae.e1.type.nextOf())); + + if (!isArrayAssign && !isArraySetAssign) return ae; const ts = t1b.nextOf().baseElemOf().isTypeStruct(); @@ -10020,9 +10021,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return ae; Expression res; - auto func = ae.e2.isLvalue || ae.e2.isSliceExp ? Id._d_arrayassign_l : Id._d_arrayassign_r; + Identifier func = isArraySetAssign ? Id._d_arraysetassign : + ae.e2.isLvalue() || ae.e2.isSliceExp() ? Id._d_arrayassign_l : Id._d_arrayassign_r; - // Lower to `.object._d_arrayassign_l{r}(e1, e2)`` + // Lower to `.object._d_array{setassign,assign_l,assign_r}(e1, e2)`` Expression id = new IdentifierExp(ae.loc, Id.empty); id = new DotIdExp(ae.loc, id, Id.object); id = new DotIdExp(ae.loc, id, func); @@ -10032,10 +10034,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor .expressionSemantic(sc)); Expression eValue2, value2 = ae.e2; - if (ae.e2.isLvalue) - value2 = new CastExp(ae.loc, ae.e2, ae.e2.type.nextOf.arrayOf) + if (isArrayAssign && value2.isLvalue()) + value2 = new CastExp(ae.loc, ae.e2, ae.e2.type.nextOf.arrayOf()) .expressionSemantic(sc); - else if (!fromCommaExp) + else if (!fromCommaExp && + (isArrayAssign || (isArraySetAssign && !value2.isLvalue()))) { // Rvalues from CommaExps were introduced in `visit(AssignExp)` // and are temporary variables themselves. Rvalues from trivial @@ -10044,7 +10047,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // `__assigntmp` will be destroyed together with the array `ae.e1`. // When `ae.e2` is a variadic arg array, it is also `scope`, so // `__assigntmp` may also be scope. - auto vd = copyToTemp(STC.rvalue | STC.nodtor | STC.scope_, "__assigntmp", ae.e2); + StorageClass stc = STC.nodtor; + if (isArrayAssign) + stc |= STC.rvalue | STC.scope_; + + auto vd = copyToTemp(stc, "__assigntmp", ae.e2); eValue2 = new DeclarationExp(vd.loc, vd).expressionSemantic(sc); value2 = new VarExp(vd.loc, vd).expressionSemantic(sc); } @@ -10052,7 +10059,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor Expression ce = new CallExp(ae.loc, id, arguments); res = Expression.combine(eValue2, ce).expressionSemantic(sc); - res = Expression.combine(res, ae.e1).expressionSemantic(sc); + if (isArrayAssign) + res = Expression.combine(res, ae.e1).expressionSemantic(sc); if (global.params.verbose) message("lowered %s =>\n %s", ae.toChars(), res.toChars()); diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d index 4c09474..bcae282 100644 --- a/gcc/d/dmd/func.d +++ b/gcc/d/dmd/func.d @@ -3216,11 +3216,12 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, } } - if (tiargs && arrayObjectIsError(tiargs) || - fargs && arrayObjectIsError(cast(Objects*)fargs)) - { + if (tiargs && arrayObjectIsError(tiargs)) return null; - } + if (fargs !is null) + foreach (arg; *fargs) + if (isError(arg)) + return null; MatchAccumulator m; functionResolve(m, s, loc, sc, tiargs, tthis, fargs, null); @@ -3758,9 +3759,9 @@ extern (C++) final class FuncLiteralDeclaration : FuncDeclaration // backend bool deferToObj; - extern (D) this(const ref Loc loc, const ref Loc endloc, Type type, TOK tok, ForeachStatement fes, Identifier id = null) + extern (D) this(const ref Loc loc, const ref Loc endloc, Type type, TOK tok, ForeachStatement fes, Identifier id = null, StorageClass storage_class = STC.undefined_) { - super(loc, endloc, null, STC.undefined_, type); + super(loc, endloc, null, storage_class, type); this.ident = id ? id : Id.empty; this.tok = tok; this.fes = fes; @@ -3774,7 +3775,7 @@ extern (C++) final class FuncLiteralDeclaration : FuncDeclaration { //printf("FuncLiteralDeclaration::syntaxCopy('%s')\n", toChars()); assert(!s); - auto f = new FuncLiteralDeclaration(loc, endloc, type.syntaxCopy(), tok, fes, ident); + auto f = new FuncLiteralDeclaration(loc, endloc, type.syntaxCopy(), tok, fes, ident, storage_class & STC.auto_); f.treq = treq; // don't need to copy FuncDeclaration.syntaxCopy(f); return f; @@ -3833,9 +3834,7 @@ extern (C++) final class FuncLiteralDeclaration : FuncDeclaration { Expression exp = s.exp; if (exp && !exp.type.equals(tret)) - { - s.exp = exp.castTo(sc, tret); - } + s.exp = exp.implicitCastTo(sc, tret); } } diff --git a/gcc/d/dmd/iasmgcc.d b/gcc/d/dmd/iasmgcc.d index 7d4fbc3..7a840ff 100644 --- a/gcc/d/dmd/iasmgcc.d +++ b/gcc/d/dmd/iasmgcc.d @@ -84,13 +84,10 @@ int parseExtAsmOperands(Parser)(Parser p, GccAsmStatement s) case TOK.string_: constraint = p.parsePrimaryExp(); - // @@@DEPRECATED_2.101@@@ - // Old parser allowed omitting parentheses around the expression. - // Deprecated in 2.091. Can be made permanent error after 2.100 if (p.token.value != TOK.leftParenthesis) { arg = p.parseAssignExp(); - deprecation(arg.loc, "`%s` must be surrounded by parentheses", arg.toChars()); + error(arg.loc, "`%s` must be surrounded by parentheses", arg.toChars()); } else { @@ -527,6 +524,9 @@ unittest // Found ',' when expecting ':' q{ asm { "", ""; } }, + + // https://issues.dlang.org/show_bug.cgi?id=20593 + q{ asm { "instruction" : : "operand" 123; } }, ]; foreach (test; passAsmTests) diff --git a/gcc/d/dmd/id.d b/gcc/d/dmd/id.d index 6695faa..48ca766 100644 --- a/gcc/d/dmd/id.d +++ b/gcc/d/dmd/id.d @@ -319,6 +319,7 @@ immutable Msgtable[] msgtable = { "_aaApply2" }, { "_d_arrayctor" }, { "_d_arraysetctor" }, + { "_d_arraysetassign" }, { "_d_arrayassign_l" }, { "_d_arrayassign_r" }, @@ -511,6 +512,7 @@ immutable Msgtable[] msgtable = { "wchar_t" }, // for C compiler + { "ImportC", "__C" }, { "__tag" }, { "dllimport" }, { "dllexport" }, diff --git a/gcc/d/dmd/init.d b/gcc/d/dmd/init.d index 164a5f3..523b5b8 100644 --- a/gcc/d/dmd/init.d +++ b/gcc/d/dmd/init.d @@ -167,6 +167,7 @@ extern (C++) final class ArrayInitializer : Initializer uint dim; // length of array being initialized Type type; // type that array will be used to initialize bool sem; // true if semantic() is run + bool isCarray; // C array semantics extern (D) this(const ref Loc loc) { diff --git a/gcc/d/dmd/init.h b/gcc/d/dmd/init.h index 296c31d..977157f 100644 --- a/gcc/d/dmd/init.h +++ b/gcc/d/dmd/init.h @@ -78,6 +78,7 @@ public: unsigned dim; // length of array being initialized Type *type; // type that array will be used to initialize bool sem; // true if semantic() is run + bool isCarray; // C array semantics bool isAssociativeArray() const; Expression *toAssocArrayLiteral(); diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d index a576712..ef39f59 100644 --- a/gcc/d/dmd/initsem.d +++ b/gcc/d/dmd/initsem.d @@ -225,7 +225,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ assert(sc); auto tm = vd.type.addMod(t.mod); auto iz = i.value[j].initializerSemantic(sc, tm, needInterpret); - auto ex = iz.initializerToExpression(); + auto ex = iz.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0); if (ex.op == EXP.error) { errors = true; @@ -243,7 +243,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ // Make a StructLiteralExp out of elements[] auto sle = new StructLiteralExp(i.loc, sd, elements, t); - if (!sd.fill(i.loc, elements, false)) + if (!sd.fill(i.loc, *elements, false)) return err(); sle.type = t; auto ie = new ExpInitializer(i.loc, sle); @@ -272,7 +272,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ uint length; const(uint) amax = 0x80000000; bool errors = false; - //printf("ArrayInitializer::semantic(%s)\n", t.toChars()); + //printf("ArrayInitializer::semantic(%s), ai: %s %p\n", t.toChars(), i.toChars(), i); if (i.sem) // if semantic() already run { return i; @@ -374,11 +374,22 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ } if (auto tsa = t.isTypeSArray()) { - uinteger_t edim = tsa.dim.toInteger(); - if (i.dim > edim && !(tsa.isIncomplete() && (sc.flags & SCOPE.Cfile))) + if (sc.flags & SCOPE.Cfile && tsa.isIncomplete()) { - error(i.loc, "array initializer has %u elements, but array length is %llu", i.dim, edim); - return err(); + // Change to array of known length + auto tn = tsa.next.toBasetype(); + tsa = new TypeSArray(tn, new IntegerExp(Loc.initial, i.dim, Type.tsize_t)); + tx = tsa; // rewrite caller's type + i.type = tsa; // remember for later passes + } + else + { + uinteger_t edim = tsa.dim.toInteger(); + if (i.dim > edim) + { + error(i.loc, "array initializer has %u elements, but array length is %llu", i.dim, edim); + return err(); + } } } if (errors) @@ -394,6 +405,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ error(i.loc, "array dimension %llu exceeds max of %llu", ulong(i.dim), ulong(amax / sz)); return err(); } + //printf("returns ai: %s\n", i.toChars()); return i; } @@ -661,295 +673,380 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ Initializer visitC(CInitializer ci) { - if (ci.sem) // if semantic() already run - return ci; //printf("CInitializer::semantic() (%s) %s\n", t.toChars(), ci.toChars()); - ci.sem = true; + /* Rewrite CInitializer into ExpInitializer, ArrayInitializer, or StructInitializer + */ t = t.toBasetype(); - ci.type = t; // later passes will need this - - auto dil = ci.initializerList[]; - size_t i = 0; // index into dil[] - const uint amax = 0x8000_0000; - bool errors; /* If `{ expression }` return the expression initializer */ ExpInitializer isBraceExpression() { + auto dil = ci.initializerList[]; return (dil.length == 1 && !dil[0].designatorList) ? dil[0].initializer.isExpInitializer() : null; } - /* Convert struct initializer into ExpInitializer + /******************************** */ - Initializer structs(TypeStruct ts) + bool overlaps(VarDeclaration field, VarDeclaration[] fields, StructInitializer si) { - //printf("structs %s\n", ts.toChars()); + foreach (fld; fields) + { + if (field.isOverlappedWith(fld)) + { + // look for initializer corresponding with fld + foreach (i, ident; si.field[]) + { + if (ident == fld.ident && si.value[i]) + return true; // already an initializer for `field` + } + } + } + return false; + } + + /* Run semantic on ExpInitializer, see if it represents entire struct ts + */ + bool representsStruct(ExpInitializer ei, TypeStruct ts) + { + if (needInterpret) + sc = sc.startCTFE(); + ei.exp = ei.exp.expressionSemantic(sc); + ei.exp = resolveProperties(sc, ei.exp); + if (needInterpret) + sc = sc.endCTFE(); + return ei.exp.implicitConvTo(ts) != MATCH.nomatch; // initializer represents the entire struct + } + + /* If { } are omitted from substructs, use recursion to reconstruct where + * brackets go + * Params: + * ts = substruct to initialize + * index = index into ci.initializer, updated + * Returns: struct initializer for this substruct + */ + Initializer subStruct()(TypeStruct ts, ref size_t index) + { + //printf("subStruct(ts: %s, index %d)\n", ts.toChars(), cast(int)index); + + auto si = new StructInitializer(ci.loc); StructDeclaration sd = ts.sym; sd.size(ci.loc); if (sd.sizeok != Sizeok.done) { - errors = true; + index = ci.initializerList.length; return err(); } - const nfields = sd.nonHiddenFields(); - auto elements = new Expressions(nfields); - auto elems = (*elements)[]; - foreach (ref elem; elems) - elem = null; + const nfields = sd.fields.length; - FieldLoop: - for (size_t fieldi = 0; fieldi < nfields; ++fieldi) + foreach (fieldi; 0 .. nfields) { - if (i == dil.length) - break; - - auto di = dil[i]; - if (di.designatorList) + if (index >= ci.initializerList.length) + break; // ran out of initializers + auto di = ci.initializerList[index]; + if (di.designatorList && fieldi != 0) + break; // back to top level + else { - error(ci.loc, "C designator-list not supported yet"); - errors = true; - break; + VarDeclaration field; + while (1) // skip field if it overlaps with previously seen fields + { + field = sd.fields[fieldi]; + ++fieldi; + if (!overlaps(field, sd.fields[], si)) + break; + if (fieldi == nfields) + break; + } + auto tn = field.type.toBasetype(); + auto tnsa = tn.isTypeSArray(); + auto tns = tn.isTypeStruct(); + auto ix = di.initializer; + if (tnsa && ix.isExpInitializer()) + { + ExpInitializer ei = ix.isExpInitializer(); + if (ei.exp.isStringExp() && tnsa.nextOf().isintegral()) + { + si.addInit(field.ident, ei); + ++index; + } + else + si.addInit(field.ident, subArray(tnsa, index)); // fwd ref of subArray is why subStruct is a template + } + else if (tns && ix.isExpInitializer()) + { + /* Disambiguate between an exp representing the entire + * struct, and an exp representing the first field of the struct + */ + if (representsStruct(ix.isExpInitializer(), tns)) // initializer represents the entire struct + { + si.addInit(field.ident, initializerSemantic(ix, sc, tn, needInterpret)); + ++index; + } + else // field initializers for struct + si.addInit(field.ident, subStruct(tns, index)); // the first field + } + else + { + si.addInit(field.ident, ix); + ++index; + } } + } + //printf("subStruct() returns ai: %s, index: %d\n", si.toChars(), cast(int)index); + return si; + } - VarDeclaration vd = sd.fields[fieldi]; + /* If { } are omitted from subarrays, use recursion to reconstruct where + * brackets go + * Params: + * tsa = subarray to initialize + * index = index into ci.initializer, updated + * Returns: array initializer for this subarray + */ + Initializer subArray(TypeSArray tsa, ref size_t index) + { + //printf("array(tsa: %s, index %d)\n", tsa.toChars(), cast(int)index); + if (tsa.isIncomplete()) + { + // C11 6.2.5-20 "element type shall be complete whenever the array type is specified" + assert(0); // should have been detected by parser + } - // Check for overlapping initializations (can happen with unions) - foreach (k, v2; sd.fields[0 .. nfields]) + auto tnsa = tsa.nextOf().toBasetype().isTypeSArray(); + + auto ai = new ArrayInitializer(ci.loc); + ai.isCarray = true; + + foreach (n; 0 .. cast(size_t)tsa.dim.toInteger()) + { + if (index >= ci.initializerList.length) + break; // ran out of initializers + auto di = ci.initializerList[index]; + if (di.designatorList) + break; // back to top level + else if (tnsa && di.initializer.isExpInitializer()) { - if (vd.isOverlappedWith(v2) && elems[k]) + ExpInitializer ei = di.initializer.isExpInitializer(); + if (ei.exp.isStringExp() && tnsa.nextOf().isintegral()) { - continue FieldLoop; // skip it + ai.addInit(null, ei); + ++index; } + else + ai.addInit(null, subArray(tnsa, index)); } - - ++i; - - // Convert initializer to Expression `ex` - assert(sc); - auto tm = vd.type.addMod(ts.mod); - auto iz = di.initializer.initializerSemantic(sc, tm, needInterpret); - auto ex = iz.initializerToExpression(null, true); - if (ex.op == EXP.error) + else { - errors = true; - continue; + ai.addInit(null, di.initializer); + ++index; } - - elems[fieldi] = ex; } - if (errors) - return err(); - - // Make a StructLiteralExp out of elements[] - Type tx = ts; - auto sle = new StructLiteralExp(ci.loc, sd, elements, tx); - if (!sd.fill(ci.loc, elements, false)) - return err(); - sle.type = tx; - auto ie = new ExpInitializer(ci.loc, sle); - return ie.initializerSemantic(sc, tx, needInterpret); + //printf("array() returns ai: %s, index: %d\n", ai.toChars(), cast(int)index); + return ai; } if (auto ts = t.isTypeStruct()) { - auto ei = structs(ts); - if (errors) - return err(); - if (i < dil.length) + auto si = new StructInitializer(ci.loc); + StructDeclaration sd = ts.sym; + sd.size(ci.loc); // run semantic() on sd to get fields + if (sd.sizeok != Sizeok.done) { - error(ci.loc, "%d extra initializer(s) for `struct %s`", cast(int)(dil.length - i), ts.toChars()); return err(); } - return ei; - } + const nfields = sd.fields.length; - auto tsa = t.isTypeSArray(); - if (!tsa) - { - /* Not an array. See if it is `{ exp }` which can be - * converted to an ExpInitializer - */ - if (ExpInitializer ei = isBraceExpression()) - { - return ei.initializerSemantic(sc, t, needInterpret); - } - - error(ci.loc, "C non-array initializer (%s) %s not supported yet", t.toChars(), ci.toChars()); - return err(); - } + size_t fieldi = 0; - /* If it's an array of integral being initialized by `{ string }` - * replace with `string` - */ - auto tn = t.nextOf(); - if (tn.isintegral()) - { - if (ExpInitializer ei = isBraceExpression()) + for (size_t index = 0; index < ci.initializerList.length; ) { - if (ei.exp.isStringExp()) - return ei.initializerSemantic(sc, t, needInterpret); + auto di = ci.initializerList[index]; + auto dlist = di.designatorList; + if (dlist) + { + const length = (*dlist).length; + if (length == 0 || !(*dlist)[0].ident) + { + error(ci.loc, "`.identifier` expected for C struct field initializer `%s`", ci.toChars()); + return err(); + } + if (length > 1) + { + error(ci.loc, "only 1 designator currently allowed for C struct field initializer `%s`", ci.toChars()); + return err(); + } + auto id = (*dlist)[0].ident; + foreach (k, f; sd.fields[]) // linear search for now + { + if (f.ident == id) + { + fieldi = k; + si.addInit(id, di.initializer); + ++fieldi; + ++index; + break; + } + } + } + else + { + if (fieldi == nfields) + break; + VarDeclaration field; + while (1) // skip field if it overlaps with previously seen fields + { + field = sd.fields[fieldi]; + ++fieldi; + if (!overlaps(field, sd.fields[], si)) + break; + if (fieldi == nfields) + break; + } + auto tn = field.type.toBasetype(); + auto tnsa = tn.isTypeSArray(); + auto tns = tn.isTypeStruct(); + auto ix = di.initializer; + if (tnsa && ix.isExpInitializer()) + { + ExpInitializer ei = ix.isExpInitializer(); + if (ei.exp.isStringExp() && tnsa.nextOf().isintegral()) + { + si.addInit(field.ident, ei); + ++index; + } + else + si.addInit(field.ident, subArray(tnsa, index)); + } + else if (tns && ix.isExpInitializer()) + { + /* Disambiguate between an exp representing the entire + * struct, and an exp representing the first field of the struct + */ + if (representsStruct(ix.isExpInitializer(), tns)) // initializer represents the entire struct + { + si.addInit(field.ident, initializerSemantic(ix, sc, tn, needInterpret)); + ++index; + } + else // field initializers for struct + si.addInit(field.ident, subStruct(tns, index)); // the first field + } + else + { + si.addInit(field.ident, di.initializer); + ++index; + } + } } + return initializerSemantic(si, sc, t, needInterpret); } - - /* Support recursion to handle un-braced array initializers - * Params: - * t = element type - * dim = max number of elements - * simple = true if array of simple elements - * Returns: - * # of elements in array - */ - size_t array(Type t, size_t dim, ref bool simple) + else if (auto ta = t.isTypeSArray()) { - //printf(" type %s i %d dim %d dil.length = %d\n", t.toChars(), cast(int)i, cast(int)dim, cast(int)dil.length); - auto tn = t.nextOf().toBasetype(); - auto tnsa = tn.isTypeSArray(); - if (tnsa && tnsa.isIncomplete()) - { - // C11 6.2.5-20 "element type shall be complete whenever the array type is specified" - error(ci.loc, "incomplete element type `%s` not allowed", tnsa.toChars()); - errors = true; - return 1; - } - if (i == dil.length) - return 0; - size_t n; - const nelems = tnsa ? cast(size_t)tnsa.dim.toInteger() : 0; + auto tn = t.nextOf().toBasetype(); // element type of array - /* Run initializerSemantic on a single element. + /* If it's an array of integral being initialized by `{ string }` + * replace with `string` */ - Initializer elem(Initializer ie) + if (tn.isintegral()) { - ++i; - auto tnx = tn; // in case initializerSemantic tries to change it - ie = ie.initializerSemantic(sc, tnx, needInterpret); - if (ie.isErrorInitializer()) - errors = true; - assert(tnx == tn); // sub-types should not be modified - return ie; + if (ExpInitializer ei = isBraceExpression()) + { + if (ei.exp.isStringExp()) + return ei.initializerSemantic(sc, t, needInterpret); + } } - foreach (j; 0 .. dim) + auto tnsa = tn.isTypeSArray(); // array of array + auto tns = tn.isTypeStruct(); // array of struct + + auto ai = new ArrayInitializer(ci.loc); + ai.isCarray = true; + for (size_t index = 0; index < ci.initializerList.length; ) { - auto di = dil[i]; - if (di.designatorList) - { - error(ci.loc, "C designator-list not supported yet"); - errors = true; - break; - } - if (tnsa && di.initializer.isExpInitializer()) + auto di = ci.initializerList[index]; + if (auto dlist = di.designatorList) { - // no braces enclosing array initializer, so recurse - array(tnsa, nelems, simple); - } - else if (auto tns = tn.isTypeStruct()) - { - if (auto ei = di.initializer.isExpInitializer()) + const length = (*dlist).length; + if (length == 0 || !(*dlist)[0].exp) + { + error(ci.loc, "`[ constant-expression ]` expected for C array element initializer `%s`", ci.toChars()); + return err(); + } + if (length > 1) + { + error(ci.loc, "only 1 designator currently allowed for C array element initializer `%s`", ci.toChars()); + return err(); + } + //printf("tn: %s, di.initializer: %s\n", tn.toChars(), di.initializer.toChars()); + auto ix = di.initializer; + if (tnsa && ix.isExpInitializer()) + { + // Wrap initializer in [ ] + auto ain = new ArrayInitializer(ci.loc); + ain.addInit(null, di.initializer); + ix = ain; + ai.addInit((*dlist)[0].exp, initializerSemantic(ix, sc, tn, needInterpret)); + ++index; + } + else if (tns && ix.isExpInitializer()) { - // no braces enclosing struct initializer - /* Disambiguate between an exp representing the entire * struct, and an exp representing the first field of the struct - */ - if (needInterpret) - sc = sc.startCTFE(); - ei.exp = ei.exp.expressionSemantic(sc); - ei.exp = resolveProperties(sc, ei.exp); - if (needInterpret) - sc = sc.endCTFE(); - if (ei.exp.implicitConvTo(tn)) - di.initializer = elem(di.initializer); // the whole struct - else + */ + if (representsStruct(ix.isExpInitializer(), tns)) // initializer represents the entire struct { - simple = false; - dil[n].initializer = structs(tns); // the first field + ai.addInit((*dlist)[0].exp, initializerSemantic(ix, sc, tn, needInterpret)); + ++index; } + else // field initializers for struct + ai.addInit((*dlist)[0].exp, subStruct(tns, index)); // the first field + } + else + { + ai.addInit((*dlist)[0].exp, initializerSemantic(ix, sc, tn, needInterpret)); + ++index; + } + } + else if (tnsa && di.initializer.isExpInitializer()) + { + ExpInitializer ei = di.initializer.isExpInitializer(); + if (ei.exp.isStringExp() && tnsa.nextOf().isintegral()) + { + ai.addInit(null, ei); + ++index; } else - dil[n].initializer = elem(di.initializer); + ai.addInit(null, subArray(tnsa, index)); + } + else if (tns && di.initializer.isExpInitializer()) + { + /* Disambiguate between an exp representing the entire + * struct, and an exp representing the first field of the struct + */ + if (representsStruct(di.initializer.isExpInitializer(), tns)) // initializer represents the entire struct + { + ai.addInit(null, initializerSemantic(di.initializer, sc, tn, needInterpret)); + ++index; + } + else // field initializers for struct + ai.addInit(null, subStruct(tns, index)); // the first field } else { - di.initializer = elem(di.initializer); + ai.addInit(null, initializerSemantic(di.initializer, sc, tn, needInterpret)); + ++index; } - ++n; - if (i == dil.length) - break; - } - //printf(" n: %d i: %d\n", cast(int)n, cast(int)i); - return n; - } - - size_t dim = tsa.isIncomplete() ? dil.length : cast(size_t)tsa.dim.toInteger(); - bool simple = true; - auto newdim = array(t, dim, simple); - - if (errors) - return err(); - - if (tsa.isIncomplete()) // array of unknown length - { - // Change to array of known length - tsa = new TypeSArray(tn, new IntegerExp(Loc.initial, newdim, Type.tsize_t)); - tx = tsa; // rewrite caller's type - ci.type = tsa; // remember for later passes - } - const uinteger_t edim = tsa.dim.toInteger(); - if (i < dil.length) - { - error(ci.loc, "%d extra initializer(s) for static array length of %d", cast(int)(dil.length - i), cast(int)edim); - return err(); - } - - const sz = tn.size(); // element size - if (sz == SIZE_INVALID) - return err(); - bool overflow; - const max = mulu(edim, sz, overflow); - if (overflow || max >= amax) - { - error(ci.loc, "array dimension %llu exceeds max of %llu", ulong(edim), ulong(amax / sz)); - return err(); - } - - /* If an array of simple elements, replace with an ArrayInitializer - */ - auto tnb = tn.toBasetype(); - if (!tnb.isTypeSArray() && (!tnb.isTypeStruct() || simple)) - { - auto ai = new ArrayInitializer(ci.loc); - ai.dim = cast(uint) dil.length; - ai.index.setDim(dil.length); - ai.value.setDim(dil.length); - foreach (const j; 0 .. dil.length) - { - ai.index[j] = null; - ai.value[j] = dil[j].initializer; } - auto ty = tx; - return ai.initializerSemantic(sc, ty, needInterpret); + return initializerSemantic(ai, sc, tx, needInterpret); } - - if (newdim < ci.initializerList.length && tnb.isTypeStruct()) + else if (ExpInitializer ei = isBraceExpression()) + return visitExp(ei); + else { - // https://issues.dlang.org/show_bug.cgi?id=22375 - // initializerList can be bigger than the number of actual elements - // to initialize for array of structs because it is not required - // for values to have proper bracing. - // i.e: These are all valid initializers for `struct{int a,b;}[3]`: - // {1,2,3,4}, {{1,2},3,4}, {1,2,{3,4}}, {{1,2},{3,4}} - // In all examples above, the new length of the initializer list - // has been shortened from four elements to two. This is important, - // because `dil` is written back to directly, making the lowered - // initializer `{{1,2},{3,4}}` and not `{{1,2},{3,4},3,4}`. - ci.initializerList.length = newdim; + assert(0); } - - return ci; } final switch (init.kind) diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d index 21bbde8..1de89d4 100644 --- a/gcc/d/dmd/lexer.d +++ b/gcc/d/dmd/lexer.d @@ -2582,8 +2582,13 @@ class Lexer { /* C11 6.4.4.2 doesn't actually care if it is not representable if it is not hex */ - const char* suffix = (result == TOK.float32Literal || result == TOK.imaginary32Literal) ? "f" : ""; - error(scanloc, "number `%s%s` is not representable", sbufptr, suffix); + const char* suffix = result == TOK.float32Literal ? "f" : result == TOK.float80Literal ? "L" : ""; + const char* type = [TOK.float32Literal: "`float`".ptr, + TOK.float64Literal: "`double`".ptr, + TOK.float80Literal: "`real` for the current target".ptr][result]; + error(scanloc, "number `%s%s` is not representable as a %s", sbufptr, suffix, type); + const char* extra = result == TOK.float64Literal ? "`real` literals can be written using the `L` suffix. " : ""; + errorSupplemental(scanloc, "%shttps://dlang.org/spec/lex.html#floatliteral", extra); } debug { diff --git a/gcc/d/dmd/module.h b/gcc/d/dmd/module.h index 6bfb729..341ce36 100644 --- a/gcc/d/dmd/module.h +++ b/gcc/d/dmd/module.h @@ -37,7 +37,7 @@ public: const char *kind() const override; - bool equals(const RootObject *o) const override; + bool equals(const RootObject * const o) const override; Package *isPackage() override final { return this; } diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d index f2da41b..1240f5a 100644 --- a/gcc/d/dmd/mtype.d +++ b/gcc/d/dmd/mtype.d @@ -936,7 +936,7 @@ extern (C++) abstract class Type : ASTNode else { // If `typeSemantic` succeeded, there may have been deprecations that - // were gagged due the the `startGagging` above. Run again to display + // were gagged due the `startGagging` above. Run again to display // those deprecations. https://issues.dlang.org/show_bug.cgi?id=19107 if (global.gaggedWarnings > 0) typeSemantic(tcopy, loc, sc); @@ -4656,7 +4656,7 @@ extern (C++) final class TypeFunction : TypeNext // suppress early exit if an error message is wanted, // so we can check any matching args are valid if (!pMessage) - goto Nomatch; + return MATCH.nomatch; } // too many args; no match match = MATCH.convert; // match ... with a "conversion" match level @@ -4669,7 +4669,7 @@ extern (C++) final class TypeFunction : TypeNext buf.printf("too few arguments, expected `%d`, got `%d`", cast(int)nparams, cast(int)nargs); if (pMessage) *pMessage = buf.extractChars(); - goto Nomatch; + return MATCH.nomatch; } foreach (u, p; parameterList) @@ -4710,226 +4710,16 @@ extern (C++) final class TypeFunction : TypeNext MATCH m; assert(p); - if (u >= nargs) - { - if (p.defaultArg) - continue; - // try typesafe variadics - goto L1; - } + + // One or more arguments remain + if (u < nargs) { Expression arg = args[u]; assert(arg); - //printf("arg: %s, type: %s\n", arg.toChars(), arg.type.toChars()); - - Type targ = arg.type; - Type tprm = wildmatch ? p.type.substWildTo(wildmatch) : p.type; - - if (p.isLazy() && tprm.ty == Tvoid && targ.ty != Tvoid) - m = MATCH.convert; - else - { - //printf("%s of type %s implicitConvTo %s\n", arg.toChars(), targ.toChars(), tprm.toChars()); - if (flag) - { - // for partial ordering, value is an irrelevant mockup, just look at the type - m = targ.implicitConvTo(tprm); - } - else - { - const isRef = p.isReference(); - - StructDeclaration argStruct, prmStruct; - - // first look for a copy constructor - if (arg.isLvalue() && !isRef && targ.ty == Tstruct && tprm.ty == Tstruct) - { - // if the argument and the parameter are of the same unqualified struct type - argStruct = (cast(TypeStruct)targ).sym; - prmStruct = (cast(TypeStruct)tprm).sym; - } - - // check if the copy constructor may be called to copy the argument - if (argStruct && argStruct == prmStruct && argStruct.hasCopyCtor) - { - /* this is done by seeing if a call to the copy constructor can be made: - * - * typeof(tprm) __copytmp; - * copytmp.__copyCtor(arg); - */ - auto tmp = new VarDeclaration(arg.loc, tprm, Identifier.generateId("__copytmp"), null); - tmp.storage_class = STC.rvalue | STC.temp | STC.ctfe; - tmp.dsymbolSemantic(sc); - Expression ve = new VarExp(arg.loc, tmp); - Expression e = new DotIdExp(arg.loc, ve, Id.ctor); - e = new CallExp(arg.loc, e, arg); - //printf("e = %s\n", e.toChars()); - if(.trySemantic(e, sc)) - m = MATCH.exact; - else - { - if (pMessage) - { - /* https://issues.dlang.org/show_bug.cgi?id=22202 - * - * If a function was deduced by semantic on the CallExp, - * it means that resolveFuncCall completed succesfully. - * Therefore, there exists a callable copy constructor, - * however, it cannot be called because scope constraints - * such as purity, safety or nogc. - */ - OutBuffer buf; - auto callExp = e.isCallExp(); - if (auto f = callExp.f) - { - char[] s; - if (!f.isPure && sc.func.setImpure()) - s ~= "pure "; - if (!f.isSafe() && !f.isTrusted() && sc.setUnsafe()) - s ~= "@safe "; - if (!f.isNogc && sc.func.setGC()) - s ~= "nogc "; - if (s) - { - s[$-1] = '\0'; - buf.printf("`%s` copy constructor cannot be called from a `%s` context", f.type.toChars(), s.ptr); - } - else if (f.isGenerated() && f.isDisabled()) - { - /* https://issues.dlang.org/show_bug.cgi?id=23097 - * Compiler generated copy constructor failed. - */ - buf.printf("generating a copy constructor for `struct %s` failed, therefore instances of it are uncopyable", - argStruct.toChars()); - } - else - { - /* Although a copy constructor may exist, no suitable match was found. - * i.e: `inout` constructor creates `const` object, not mutable. - * Fallback to using the original generic error before bugzilla 22202. - */ - goto Lnocpctor; - } - } - else - { - Lnocpctor: - buf.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies", - argStruct.toChars(), targ.toChars(), tprm.toChars()); - } - - *pMessage = buf.extractChars(); - } - m = MATCH.nomatch; - goto Nomatch; - } - } - else - { - import dmd.dcast : cimplicitConvTo; - m = (sc && sc.flags & SCOPE.Cfile) ? arg.cimplicitConvTo(tprm) : arg.implicitConvTo(tprm); - } - } - //printf("match %d\n", m); - } - - // Non-lvalues do not match ref or out parameters - if (p.isReference()) - { - // https://issues.dlang.org/show_bug.cgi?id=13783 - // Don't use toBasetype() to handle enum types. - Type ta = targ; - Type tp = tprm; - //printf("fparam[%d] ta = %s, tp = %s\n", u, ta.toChars(), tp.toChars()); - - if (m && !arg.isLvalue()) - { - if (p.storageClass & STC.out_) - { - if (pMessage) *pMessage = getParamError(arg, p); - goto Nomatch; - } - - if (arg.op == EXP.string_ && tp.ty == Tsarray) - { - if (ta.ty != Tsarray) - { - Type tn = tp.nextOf().castMod(ta.nextOf().mod); - dinteger_t dim = (cast(StringExp)arg).len; - ta = tn.sarrayOf(dim); - } - } - else if (arg.op == EXP.slice && tp.ty == Tsarray) - { - // Allow conversion from T[lwr .. upr] to ref T[upr-lwr] - if (ta.ty != Tsarray) - { - Type tn = ta.nextOf(); - dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger(); - ta = tn.sarrayOf(dim); - } - } - else if ((p.storageClass & STC.in_) && global.params.previewIn) - { - // Allow converting a literal to an `in` which is `ref` - if (arg.op == EXP.arrayLiteral && tp.ty == Tsarray) - { - Type tn = tp.nextOf(); - dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger(); - ta = tn.sarrayOf(dim); - } - - // Need to make this a rvalue through a temporary - m = MATCH.convert; - } - else if (global.params.rvalueRefParam != FeatureState.enabled || - p.storageClass & STC.out_ || - !arg.type.isCopyable()) // can't copy to temp for ref parameter - { - if (pMessage) *pMessage = getParamError(arg, p); - goto Nomatch; - } - else - { - /* in functionParameters() we'll convert this - * rvalue into a temporary - */ - m = MATCH.convert; - } - } - - /* If the match is not already perfect or if the arg - is not a lvalue then try the `alias this` chain - see https://issues.dlang.org/show_bug.cgi?id=15674 - and https://issues.dlang.org/show_bug.cgi?id=21905 - */ - if (ta != tp || !arg.isLvalue()) - { - Type firsttab = ta.toBasetype(); - while (1) - { - Type tab = ta.toBasetype(); - Type tat = tab.aliasthisOf(); - if (!tat || !tat.implicitConvTo(tprm)) - break; - if (tat == tab || tat == firsttab) - break; - ta = tat; - } - } - - /* A ref variable should work like a head-const reference. - * e.g. disallows: - * ref T <- an lvalue of const(T) argument - * ref T[dim] <- an lvalue of const(T[dim]) argument - */ - if (!ta.constConv(tp)) - { - if (pMessage) *pMessage = getParamError(arg, p); - goto Nomatch; - } - } + m = argumentMatchParameter(this, p, arg, wildmatch, flag, sc, pMessage); } + else if (p.defaultArg) + continue; /* prefer matching the element type rather than the array * type when more arguments are present with T[]... @@ -4943,100 +4733,33 @@ extern (C++) final class TypeFunction : TypeNext L1: if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams) // if last varargs param { - Type tb = p.type.toBasetype(); - TypeSArray tsa; - dinteger_t sz; - - switch (tb.ty) - { - case Tsarray: - tsa = cast(TypeSArray)tb; - sz = tsa.dim.toInteger(); - if (sz != nargs - u) - { - if (pMessage) - // Windows (Vista) OutBuffer.vprintf issue? 2nd argument always zero - //*pMessage = getMatchError("expected %d variadic argument(s), not %d", sz, nargs - u); - if (!global.gag || global.params.showGaggedErrors) - { - OutBuffer buf; - buf.printf("expected %llu variadic argument(s)", sz); - buf.printf(", not %zu", nargs - u); - *pMessage = buf.extractChars(); - } - goto Nomatch; - } - goto case Tarray; - case Tarray: - { - TypeArray ta = cast(TypeArray)tb; - foreach (arg; args[u .. nargs]) - { - assert(arg); - - /* If lazy array of delegates, - * convert arg(s) to delegate(s) - */ - Type tret = p.isLazyArray(); - if (tret) - { - if (ta.next.equals(arg.type)) - m = MATCH.exact; - else if (tret.toBasetype().ty == Tvoid) - m = MATCH.convert; - else - { - m = arg.implicitConvTo(tret); - if (m == MATCH.nomatch) - m = arg.implicitConvTo(ta.next); - } - } - else - m = arg.implicitConvTo(ta.next); - - if (m == MATCH.nomatch) - { - if (pMessage) *pMessage = getParamError(arg, p); - goto Nomatch; - } - if (m < match) - match = m; - } - goto Ldone; - } - case Tclass: - // Should see if there's a constructor match? - // Or just leave it ambiguous? - goto Ldone; - - default: - break; - } + auto trailingArgs = args[u .. $]; + if (auto vmatch = matchTypeSafeVarArgs(this, p, trailingArgs, pMessage)) + return vmatch < match ? vmatch : match; + // Error message was already generated in `matchTypeSafeVarArgs` + return MATCH.nomatch; } - if (pMessage && u < nargs) - *pMessage = getParamError(args[u], p); - else if (pMessage) + if (pMessage && u >= nargs) *pMessage = getMatchError("missing argument for parameter #%d: `%s`", u + 1, parameterToChars(p, this, false)); - goto Nomatch; + // If an error happened previously, `pMessage` was already filled + else if (pMessage && !*pMessage) + *pMessage = getParamError(args[u], p); + + return MATCH.nomatch; } if (m < match) match = m; // pick worst match } - Ldone: if (pMessage && !parameterList.varargs && nargs > nparams) { // all parameters had a match, but there are surplus args *pMessage = getMatchError("expected %d argument(s), not %d", nparams, nargs); - goto Nomatch; + return MATCH.nomatch; } //printf("match = %d\n", match); return match; - - Nomatch: - //printf("no match\n"); - return MATCH.nomatch; } /+ @@ -6194,6 +5917,11 @@ extern (C++) final class TypeClass : Type if (t && t.ty == Tclass) { ClassDeclaration cd = (cast(TypeClass)t).sym; + if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete()) + cd.dsymbolSemantic(null); + if (sym.semanticRun < PASS.semanticdone && !sym.isBaseInfoComplete()) + sym.dsymbolSemantic(null); + if (sym.isBaseOf(cd, poffset)) return true; } @@ -6355,10 +6083,9 @@ extern (C++) final class TypeTuple : Type extern (D) this(Expressions* exps) { super(Ttuple); - auto arguments = new Parameters(); + auto arguments = new Parameters(exps ? exps.dim : 0); if (exps) { - arguments.setDim(exps.dim); for (size_t i = 0; i < exps.dim; i++) { Expression e = (*exps)[i]; @@ -7330,3 +7057,325 @@ const(char)* toChars(ScopeRef sr) pure nothrow @nogc @safe return names[sr]; } } + +/** + * Used by `callMatch` to check if the copy constructor may be called to + * copy the argument + * + * This is done by seeing if a call to the copy constructor can be made: + * ``` + * typeof(tprm) __copytmp; + * copytmp.__copyCtor(arg); + * ``` + */ +private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct, + Expression arg, Type tprm, Scope* sc, const(char)** pMessage) +{ + auto tmp = new VarDeclaration(arg.loc, tprm, Identifier.generateId("__copytmp"), null); + tmp.storage_class = STC.rvalue | STC.temp | STC.ctfe; + tmp.dsymbolSemantic(sc); + Expression ve = new VarExp(arg.loc, tmp); + Expression e = new DotIdExp(arg.loc, ve, Id.ctor); + e = new CallExp(arg.loc, e, arg); + //printf("e = %s\n", e.toChars()); + if (.trySemantic(e, sc)) + return true; + + if (pMessage) + { + /* https://issues.dlang.org/show_bug.cgi?id=22202 + * + * If a function was deduced by semantic on the CallExp, + * it means that resolveFuncCall completed succesfully. + * Therefore, there exists a callable copy constructor, + * however, it cannot be called because scope constraints + * such as purity, safety or nogc. + */ + OutBuffer buf; + auto callExp = e.isCallExp(); + if (auto f = callExp.f) + { + char[] s; + if (!f.isPure && sc.func.setImpure()) + s ~= "pure "; + if (!f.isSafe() && !f.isTrusted() && sc.setUnsafe()) + s ~= "@safe "; + if (!f.isNogc && sc.func.setGC()) + s ~= "nogc "; + if (s) + { + s[$-1] = '\0'; + buf.printf("`%s` copy constructor cannot be called from a `%s` context", f.type.toChars(), s.ptr); + } + else if (f.isGenerated() && f.isDisabled()) + { + /* https://issues.dlang.org/show_bug.cgi?id=23097 + * Compiler generated copy constructor failed. + */ + buf.printf("generating a copy constructor for `struct %s` failed, therefore instances of it are uncopyable", + argStruct.toChars()); + } + else + { + /* Although a copy constructor may exist, no suitable match was found. + * i.e: `inout` constructor creates `const` object, not mutable. + * Fallback to using the original generic error before bugzilla 22202. + */ + goto Lnocpctor; + } + } + else + { + Lnocpctor: + buf.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies", + argStruct.toChars(), arg.type.toChars(), tprm.toChars()); + } + + *pMessage = buf.extractChars(); + } + return false; +} + +/** + * Match a single parameter to an argument. + * + * This function is called by `TypeFunction.callMatch` while iterating over + * the list of parameter. Here we check if `arg` is a match for `p`, + * which is mostly about checking if `arg.type` converts to `p`'s type + * and some check about value reference. + * + * Params: + * tf = The `TypeFunction`, only used for error reporting + * p = The parameter of `tf` being matched + * arg = Argument being passed (bound) to `p` + * wildmatch = Wild (`inout`) matching level, derived from the full argument list + * flag = A non-zero value means we're doing a partial ordering check + * (no value semantic check) + * sc = Scope we are in + * pMessage = A buffer to write the error in, or `null` + * + * Returns: Whether `trailingArgs` match `p`. + */ +private extern(D) MATCH argumentMatchParameter (TypeFunction tf, Parameter p, + Expression arg, ubyte wildmatch, int flag, Scope* sc, const(char)** pMessage) +{ + //printf("arg: %s, type: %s\n", arg.toChars(), arg.type.toChars()); + MATCH m; + Type targ = arg.type; + Type tprm = wildmatch ? p.type.substWildTo(wildmatch) : p.type; + + if (p.isLazy() && tprm.ty == Tvoid && targ.ty != Tvoid) + m = MATCH.convert; + else if (flag) + { + // for partial ordering, value is an irrelevant mockup, just look at the type + m = targ.implicitConvTo(tprm); + } + else + { + const isRef = p.isReference(); + StructDeclaration argStruct, prmStruct; + + // first look for a copy constructor + if (arg.isLvalue() && !isRef && targ.ty == Tstruct && tprm.ty == Tstruct) + { + // if the argument and the parameter are of the same unqualified struct type + argStruct = (cast(TypeStruct)targ).sym; + prmStruct = (cast(TypeStruct)tprm).sym; + } + + // check if the copy constructor may be called to copy the argument + if (argStruct && argStruct == prmStruct && argStruct.hasCopyCtor) + { + if (!isCopyConstructorCallable(argStruct, arg, tprm, sc, pMessage)) + return MATCH.nomatch; + m = MATCH.exact; + } + else + { + import dmd.dcast : cimplicitConvTo; + m = (sc && sc.flags & SCOPE.Cfile) ? arg.cimplicitConvTo(tprm) : arg.implicitConvTo(tprm); + } + } + + // Non-lvalues do not match ref or out parameters + if (p.isReference()) + { + // https://issues.dlang.org/show_bug.cgi?id=13783 + // Don't use toBasetype() to handle enum types. + Type ta = targ; + Type tp = tprm; + //printf("fparam[%d] ta = %s, tp = %s\n", u, ta.toChars(), tp.toChars()); + + if (m && !arg.isLvalue()) + { + if (p.storageClass & STC.out_) + { + if (pMessage) *pMessage = tf.getParamError(arg, p); + return MATCH.nomatch; + } + + if (arg.op == EXP.string_ && tp.ty == Tsarray) + { + if (ta.ty != Tsarray) + { + Type tn = tp.nextOf().castMod(ta.nextOf().mod); + dinteger_t dim = (cast(StringExp)arg).len; + ta = tn.sarrayOf(dim); + } + } + else if (arg.op == EXP.slice && tp.ty == Tsarray) + { + // Allow conversion from T[lwr .. upr] to ref T[upr-lwr] + if (ta.ty != Tsarray) + { + Type tn = ta.nextOf(); + dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger(); + ta = tn.sarrayOf(dim); + } + } + else if ((p.storageClass & STC.in_) && global.params.previewIn) + { + // Allow converting a literal to an `in` which is `ref` + if (arg.op == EXP.arrayLiteral && tp.ty == Tsarray) + { + Type tn = tp.nextOf(); + dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger(); + ta = tn.sarrayOf(dim); + } + + // Need to make this a rvalue through a temporary + m = MATCH.convert; + } + else if (global.params.rvalueRefParam != FeatureState.enabled || + p.storageClass & STC.out_ || + !arg.type.isCopyable()) // can't copy to temp for ref parameter + { + if (pMessage) *pMessage = tf.getParamError(arg, p); + return MATCH.nomatch; + } + else + { + /* in functionParameters() we'll convert this + * rvalue into a temporary + */ + m = MATCH.convert; + } + } + + /* If the match is not already perfect or if the arg + is not a lvalue then try the `alias this` chain + see https://issues.dlang.org/show_bug.cgi?id=15674 + and https://issues.dlang.org/show_bug.cgi?id=21905 + */ + if (ta != tp || !arg.isLvalue()) + { + Type firsttab = ta.toBasetype(); + while (1) + { + Type tab = ta.toBasetype(); + Type tat = tab.aliasthisOf(); + if (!tat || !tat.implicitConvTo(tprm)) + break; + if (tat == tab || tat == firsttab) + break; + ta = tat; + } + } + + /* A ref variable should work like a head-const reference. + * e.g. disallows: + * ref T <- an lvalue of const(T) argument + * ref T[dim] <- an lvalue of const(T[dim]) argument + */ + if (!ta.constConv(tp)) + { + if (pMessage) *pMessage = tf.getParamError(arg, p); + return MATCH.nomatch; + } + } + return m; +} + +/** + * Match the remaining arguments `trailingArgs` with parameter `p`. + * + * Assume we already checked that `p` is the last parameter of `tf`, + * and we want to know whether the arguments would match `p`. + * + * Params: + * tf = The `TypeFunction`, only used for error reporting + * p = The last parameter of `tf` which is variadic + * trailingArgs = The remaining arguments that should match `p` + * pMessage = A buffer to write the error in, or `null` + * + * Returns: Whether `trailingArgs` match `p`. + */ +private extern(D) MATCH matchTypeSafeVarArgs(TypeFunction tf, Parameter p, + Expression[] trailingArgs, const(char)** pMessage) +{ + Type tb = p.type.toBasetype(); + + switch (tb.ty) + { + case Tsarray: + TypeSArray tsa = cast(TypeSArray)tb; + dinteger_t sz = tsa.dim.toInteger(); + if (sz != trailingArgs.length) + { + if (pMessage) + *pMessage = tf.getMatchError("expected %llu variadic argument(s), not %zu", + sz, trailingArgs.length); + return MATCH.nomatch; + } + goto case Tarray; + case Tarray: + { + MATCH match = MATCH.exact; + TypeArray ta = cast(TypeArray)tb; + foreach (arg; trailingArgs) + { + MATCH m; + assert(arg); + + /* If lazy array of delegates, + * convert arg(s) to delegate(s) + */ + Type tret = p.isLazyArray(); + if (tret) + { + if (ta.next.equals(arg.type)) + m = MATCH.exact; + else if (tret.toBasetype().ty == Tvoid) + m = MATCH.convert; + else + { + m = arg.implicitConvTo(tret); + if (m == MATCH.nomatch) + m = arg.implicitConvTo(ta.next); + } + } + else + m = arg.implicitConvTo(ta.next); + + if (m == MATCH.nomatch) + { + if (pMessage) *pMessage = tf.getParamError(arg, p); + return MATCH.nomatch; + } + if (m < match) + match = m; + } + return match; + } + case Tclass: + // We leave it up to the actual constructor call to do the matching. + return MATCH.exact; + + default: + // We can have things as `foo(int[int] wat...)` but they only match + // with an associative array proper. + if (pMessage && trailingArgs.length) *pMessage = tf.getParamError(trailingArgs[0], p); + return MATCH.nomatch; + } +} diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h index 3e614d8..2b9c94c 100644 --- a/gcc/d/dmd/mtype.h +++ b/gcc/d/dmd/mtype.h @@ -221,7 +221,7 @@ public: virtual const char *kind(); Type *copy() const; virtual Type *syntaxCopy(); - bool equals(const RootObject *o) const override; + bool equals(const RootObject * const o) const override; bool equivalent(Type *t); // kludge for template.isType() DYNCAST dyncast() const override final { return DYNCAST_TYPE; } @@ -877,7 +877,7 @@ public: static TypeTuple *create(Type *t1, Type *t2); const char *kind() override; TypeTuple *syntaxCopy() override; - bool equals(const RootObject *o) const override; + bool equals(const RootObject * const o) const override; void accept(Visitor *v) override { v->visit(this); } }; diff --git a/gcc/d/dmd/opover.d b/gcc/d/dmd/opover.d index 4f6903c..ca99b8b 100644 --- a/gcc/d/dmd/opover.d +++ b/gcc/d/dmd/opover.d @@ -1247,13 +1247,10 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) args2[0] = e.e2; expandTuples(&args2); MatchAccumulator m; - if (s) + functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, &args2); + if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) { - functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, &args2); - if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) - { - return ErrorExp.get(); - } + return ErrorExp.get(); } if (m.count > 1) { diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index ce2769d..ed85a5d 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -2756,7 +2756,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer { auto parameters = new AST.Parameters(); VarArg varargs = VarArg.none; - int hasdefault = 0; StorageClass varargsStc; // Attributes allowed for ... @@ -2921,27 +2920,23 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer //if ((storageClass & STC.scope_) && (storageClass & (STC.ref_ | STC.out_))) //error("scope cannot be ref or out"); - if (tpl && token.value == TOK.identifier) + const tv = peekNext(); + if (tpl && token.value == TOK.identifier && + (tv == TOK.comma || tv == TOK.rightParenthesis || tv == TOK.dotDotDot)) { - const tv = peekNext(); - if (tv == TOK.comma || tv == TOK.rightParenthesis || tv == TOK.dotDotDot) - { - Identifier id = Identifier.generateId("__T"); - const loc = token.loc; - at = new AST.TypeIdentifier(loc, id); - if (!*tpl) - *tpl = new AST.TemplateParameters(); - AST.TemplateParameter tp = new AST.TemplateTypeParameter(loc, id, null, null); - (*tpl).push(tp); - - ai = token.ident; - nextToken(); - } - else goto _else; + Identifier id = Identifier.generateId("__T"); + const loc = token.loc; + at = new AST.TypeIdentifier(loc, id); + if (!*tpl) + *tpl = new AST.TemplateParameters(); + AST.TemplateParameter tp = new AST.TemplateTypeParameter(loc, id, null, null); + (*tpl).push(tp); + + ai = token.ident; + nextToken(); } else { - _else: at = parseType(&ai); } ae = null; @@ -2949,12 +2944,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer { nextToken(); ae = parseDefaultInitExp(); - hasdefault = 1; - } - else - { - if (hasdefault) - error("default argument expected for `%s`", ai ? ai.toChars() : at.toChars()); } auto param = new AST.Parameter(storageClass | STC.parameter, at, ai, ae, null); if (udas) @@ -4484,7 +4473,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer const loc = token.loc; Identifier ident; - auto t = parseDeclarator(ts, alt, &ident, &tpl, storage_class, &disable, &udas); assert(t); if (!tfirst) @@ -4868,6 +4856,10 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer token.value == TOK.identifier && peekNext() == TOK.goesTo || token.value == TOK.ref_ && peekNext() == TOK.leftParenthesis && skipAttributes(peekPastParen(peek(&token)), &tk) && + (tk.value == TOK.goesTo || tk.value == TOK.leftCurly) || + token.value == TOK.auto_ && peekNext() == TOK.ref_ && + peekNext2() == TOK.leftParenthesis && + skipAttributes(peekPastParen(peek(peek(&token))), &tk) && (tk.value == TOK.goesTo || tk.value == TOK.leftCurly) ) { @@ -4879,6 +4871,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer // identifier => expression // ref (parameters) { statements... } // ref (parameters) => expression + // auto ref (parameters) { statements... } + // auto ref (parameters) => expression s = parseFunctionLiteral(); @@ -5006,7 +5000,20 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer case TOK.delegate_: save = token.value; nextToken(); - if (token.value == TOK.ref_) + if (token.value == TOK.auto_) + { + nextToken(); + if (token.value == TOK.ref_) + { + // function auto ref (parameters) { statements... } + // delegate auto ref (parameters) { statements... } + stc = STC.auto_ | STC.ref_; + nextToken(); + } + else + error("`auto` can only be used as part of `auto ref` for function literal return values"); + } + else if (token.value == TOK.ref_) { // function ref (parameters) { statements... } // delegate ref (parameters) { statements... } @@ -5034,6 +5041,20 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } goto case TOK.leftParenthesis; + case TOK.auto_: + { + nextToken(); + if (token.value == TOK.ref_) + { + // auto ref (parameters) => expression + // auto ref (parameters) { statements... } + stc = STC.auto_ | STC.ref_; + nextToken(); + } + else + error("`auto` can only be used as part of `auto ref` for function literal return values"); + goto case TOK.leftParenthesis; + } case TOK.ref_: { // ref (parameters) => expression @@ -5086,7 +5107,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer auto tf = new AST.TypeFunction(parameterList, tret, linkage, stc); tf = cast(AST.TypeFunction)tf.addSTC(stc); - auto fd = new AST.FuncLiteralDeclaration(loc, Loc.initial, tf, save, null); + auto fd = new AST.FuncLiteralDeclaration(loc, Loc.initial, tf, save, null, null, stc & STC.auto_); if (token.value == TOK.goesTo) { @@ -5209,7 +5230,9 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } else { - f.frequires.push(parseStatement(ParseStatementFlags.curly | ParseStatementFlags.scope_)); + auto ret = parseStatement(ParseStatementFlags.curly | ParseStatementFlags.scope_); + assert(ret); + f.frequires.push(ret); requireDo = true; } goto L1; @@ -6550,7 +6573,7 @@ LagainStc: nextToken(); if (token.value == TOK.semicolon) nextToken(); - s = null; + s = new AST.ErrorStatement; break; } if (pEndloc) @@ -8394,6 +8417,22 @@ LagainStc: e = parseNewExp(null); break; + case TOK.auto_: + { + if (peekNext() == TOK.ref_ && peekNext2() == TOK.leftParenthesis) + { + Token* tk = peekPastParen(peek(peek(&token))); + if (skipAttributes(tk, &tk) && (tk.value == TOK.goesTo || tk.value == TOK.leftCurly)) + { + // auto ref (arguments) => expression + // auto ref (arguments) { statements... } + goto case_delegate; + } + } + nextToken(); + error("found `%s` when expecting `ref` and function literal following `auto`", token.toChars()); + goto Lerr; + } case TOK.ref_: { if (peekNext() == TOK.leftParenthesis) @@ -8630,7 +8669,7 @@ LagainStc: if (token.value != TOK.identifier) { error("identifier expected following `(type)`."); - return null; + return AST.ErrorExp.get(); } e = new AST.DotIdExp(loc, new AST.TypeExp(loc, t), token.ident); nextToken(); @@ -8749,7 +8788,8 @@ LagainStc: if (peekNext() != TOK.identifier && peekNext() != TOK.new_) { error("identifier or new keyword expected following `(...)`."); - return null; + nextToken(); + return AST.ErrorExp.get(); } e = new AST.TypeExp(loc, t); e.parens = true; diff --git a/gcc/d/dmd/root/object.h b/gcc/d/dmd/root/object.h index 0c92a9a..b735dd9 100644 --- a/gcc/d/dmd/root/object.h +++ b/gcc/d/dmd/root/object.h @@ -39,7 +39,7 @@ class RootObject public: RootObject() { } - virtual bool equals(const RootObject *o) const; + virtual bool equals(const RootObject * const o) const; /** * Pretty-print an Object. Useful for debugging the old-fashioned way. diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d index ad4487f..d2f9c0a 100644 --- a/gcc/d/dmd/semantic3.d +++ b/gcc/d/dmd/semantic3.d @@ -167,11 +167,18 @@ private extern(C++) final class Semantic3Visitor : Visitor sc = sc.push(tmix.argsym); sc = sc.push(tmix); + + uint olderrors = global.errors; + for (size_t i = 0; i < tmix.members.dim; i++) { Dsymbol s = (*tmix.members)[i]; s.semantic3(sc); } + + if (global.errors != olderrors) + errorSupplemental(tmix.loc, "parent scope from here: `mixin %s`", tmix.toChars()); + sc = sc.pop(); sc.pop(); } @@ -969,6 +976,7 @@ private extern(C++) final class Semantic3Visitor : Visitor /* Do the semantic analysis on the [in] preconditions and * [out] postconditions. */ + immutable bool isnothrow = f.isnothrow && !(funcdecl.flags & FUNCFLAG.nothrowInprocess); if (freq) { /* frequire is composed of the [in] contracts @@ -980,10 +988,22 @@ private extern(C++) final class Semantic3Visitor : Visitor sc2.flags = (sc2.flags & ~SCOPE.contract) | SCOPE.require; // BUG: need to error if accessing out parameters - // BUG: need to disallow returns and throws + // BUG: need to disallow returns // BUG: verify that all in and ref parameters are read freq = freq.statementSemantic(sc2); - freq.blockExit(funcdecl, false); + + // @@@DEPRECATED_2.111@@@ - pass `isnothrow` instead of `false` to print a more detailed error msg` + const blockExit = freq.blockExit(funcdecl, false); + if (blockExit & BE.throw_) + { + if (isnothrow) + // @@@DEPRECATED_2.111@@@ + // Deprecated in 2.101, can be made an error in 2.111 + deprecation(funcdecl.loc, "`%s`: `in` contract may throw but function is marked as `nothrow`", + funcdecl.toPrettyChars()); + else if (funcdecl.flags & FUNCFLAG.nothrowInprocess) + f.isnothrow = false; + } funcdecl.flags &= ~FUNCFLAG.noEH; @@ -992,6 +1012,7 @@ private extern(C++) final class Semantic3Visitor : Visitor if (global.params.useIn == CHECKENABLE.off) freq = null; } + if (fens) { /* fensure is composed of the [out] contracts @@ -1017,7 +1038,19 @@ private extern(C++) final class Semantic3Visitor : Visitor funcdecl.buildResultVar(scout, f.next); fens = fens.statementSemantic(sc2); - fens.blockExit(funcdecl, false); + + // @@@DEPRECATED_2.111@@@ - pass `isnothrow` instead of `false` to print a more detailed error msg` + const blockExit = fens.blockExit(funcdecl, false); + if (blockExit & BE.throw_) + { + if (isnothrow) + // @@@DEPRECATED_2.111@@@ + // Deprecated in 2.101, can be made an error in 2.111 + deprecation(funcdecl.loc, "`%s`: `out` contract may throw but function is marked as `nothrow`", + funcdecl.toPrettyChars()); + else if (funcdecl.flags & FUNCFLAG.nothrowInprocess) + f.isnothrow = false; + } funcdecl.flags &= ~FUNCFLAG.noEH; @@ -1144,7 +1177,6 @@ private extern(C++) final class Semantic3Visitor : Visitor s = s.statementSemantic(sc2); - immutable bool isnothrow = f.isnothrow && !(funcdecl.flags & FUNCFLAG.nothrowInprocess); const blockexit = s.blockExit(funcdecl, isnothrow); if (blockexit & BE.throw_) { diff --git a/gcc/d/dmd/transitivevisitor.d b/gcc/d/dmd/transitivevisitor.d index 5791a88..0d7240f 100644 --- a/gcc/d/dmd/transitivevisitor.d +++ b/gcc/d/dmd/transitivevisitor.d @@ -28,6 +28,7 @@ extern(C++) class ParseTimeTransitiveVisitor(AST) : PermissiveVisitor!AST */ package mixin template ParseVisitMethods(AST) { + import dmd.root.array; // Statement Nodes //=========================================================== @@ -46,7 +47,7 @@ package mixin template ParseVisitMethods(AST) override void visit(AST.CompileStatement s) { //printf("Visiting CompileStatement\n"); - visitArgs(s.exps); + visitArgs(s.exps.peekSlice()); } override void visit(AST.CompoundStatement s) @@ -181,11 +182,9 @@ package mixin template ParseVisitMethods(AST) s.elsebody.accept(this); } - void visitArgs(AST.Expressions* expressions, AST.Expression basis = null) + private extern(D) void visitArgs(AST.Expression[] expressions, AST.Expression basis = null) { - if (!expressions || !expressions.dim) - return; - foreach (el; *expressions) + foreach (el; expressions) { if (!el) el = basis; @@ -197,8 +196,7 @@ package mixin template ParseVisitMethods(AST) override void visit(AST.PragmaStatement s) { //printf("Visiting PragmaStatement\n"); - if (s.args && s.args.dim) - visitArgs(s.args); + visitArgs(s.args.peekSlice()); if (s._body) s._body.accept(this); } @@ -346,19 +344,14 @@ package mixin template ParseVisitMethods(AST) foreach (p; *td.origParameters) p.accept(this); } - visitParameters(t.parameterList.parameters); + visitParameters(t.parameterList.parameters.peekSlice()); } - void visitParameters(AST.Parameters* parameters) + private extern(D) final void visitParameters(AST.Parameter[] parameters) { - if (parameters) + foreach (i; 0 .. parameters.length) { - size_t dim = AST.Parameter.dim(parameters); - foreach(i; 0..dim) - { - AST.Parameter fparam = AST.Parameter.getNth(parameters, i); - fparam.accept(this); - } + parameters[i].accept(this); } } @@ -469,7 +462,7 @@ package mixin template ParseVisitMethods(AST) override void visit(AST.TypeTuple t) { //printf("Visiting TypeTuple\n"); - visitParameters(t.arguments); + visitParameters(t.arguments.peekSlice()); } override void visit(AST.TypeSlice t) @@ -487,7 +480,7 @@ package mixin template ParseVisitMethods(AST) override void visit(AST.TypeMixin t) { - visitArgs(t.exps); + visitArgs(t.exps.peekSlice()); } // Miscellaneous @@ -571,8 +564,7 @@ package mixin template ParseVisitMethods(AST) override void visit(AST.PragmaDeclaration d) { //printf("Visiting PragmaDeclaration\n"); - if (d.args && d.args.dim) - visitArgs(d.args); + visitArgs(d.args.peekSlice()); visitAttribDeclaration(cast(AST.AttribDeclaration)d); } @@ -580,24 +572,22 @@ package mixin template ParseVisitMethods(AST) { //printf("Visiting ConditionalDeclaration\n"); d.condition.accept(this); - if (d.decl) - foreach (de; *d.decl) - de.accept(this); - if (d.elsedecl) - foreach (de; *d.elsedecl) - de.accept(this); + foreach (de; d.decl.peekSlice()) + de.accept(this); + foreach (de; d.elsedecl.peekSlice()) + de.accept(this); } override void visit(AST.CompileDeclaration d) { //printf("Visiting compileDeclaration\n"); - visitArgs(d.exps); + visitArgs(d.exps.peekSlice()); } override void visit(AST.UserAttributeDeclaration d) { //printf("Visiting UserAttributeDeclaration\n"); - visitArgs(d.atts); + visitArgs(d.atts.peekSlice()); visitAttribDeclaration(cast(AST.AttribDeclaration)d); } @@ -791,6 +781,15 @@ package mixin template ParseVisitMethods(AST) s.accept(this); } + override void visit(AST.UnionDeclaration d) + { + //printf("Visiting UnionDeclaration\n"); + if (!d.members) + return; + foreach (s; *d.members) + s.accept(this); + } + override void visit(AST.ClassDeclaration d) { //printf("Visiting ClassDeclaration\n"); @@ -840,7 +839,7 @@ package mixin template ParseVisitMethods(AST) auto tf = f.type.isTypeFunction(); if (!f.inferRetType && tf.next) visitType(tf.next); - visitParameters(tf.parameterList.parameters); + visitParameters(tf.parameterList.parameters.peekSlice()); AST.CompoundStatement cs = f.fbody.isCompoundStatement(); AST.Statement s = !cs ? f.fbody : null; AST.ReturnStatement rs = s ? s.isReturnStatement() : null; @@ -946,7 +945,7 @@ package mixin template ParseVisitMethods(AST) override void visit(AST.ArrayLiteralExp e) { //printf("Visiting ArrayLiteralExp\n"); - visitArgs(e.elements, e.basis); + visitArgs(e.elements.peekSlice(), e.basis); } override void visit(AST.AssocArrayLiteralExp e) @@ -978,8 +977,7 @@ package mixin template ParseVisitMethods(AST) if (e.thisexp) e.thisexp.accept(this); visitType(e.newtype); - if (e.arguments && e.arguments.dim) - visitArgs(e.arguments); + visitArgs(e.arguments.peekSlice()); } override void visit(AST.NewAnonClassExp e) @@ -987,8 +985,7 @@ package mixin template ParseVisitMethods(AST) //printf("Visiting NewAnonClassExp\n"); if (e.thisexp) e.thisexp.accept(this); - if (e.arguments && e.arguments.dim) - visitArgs(e.arguments); + visitArgs(e.arguments.peekSlice()); if (e.cd) e.cd.accept(this); } @@ -998,7 +995,7 @@ package mixin template ParseVisitMethods(AST) //printf("Visiting TupleExp\n"); if (e.e0) e.e0.accept(this); - visitArgs(e.exps); + visitArgs(e.exps.peekSlice()); } override void visit(AST.FuncExp e) @@ -1056,7 +1053,7 @@ package mixin template ParseVisitMethods(AST) override void visit(AST.MixinExp e) { //printf("Visiting MixinExp\n"); - visitArgs(e.exps); + visitArgs(e.exps.peekSlice()); } override void visit(AST.ImportExp e) @@ -1090,7 +1087,7 @@ package mixin template ParseVisitMethods(AST) { //printf("Visiting CallExp\n"); e.e1.accept(this); - visitArgs(e.arguments); + visitArgs(e.arguments.peekSlice()); } override void visit(AST.PtrExp e) @@ -1124,7 +1121,7 @@ package mixin template ParseVisitMethods(AST) { //printf("Visiting ArrayExp\n"); e.e1.accept(this); - visitArgs(e.arguments); + visitArgs(e.arguments.peekSlice()); } override void visit(AST.PostExp e) diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index b21ff79..0ef7705 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -1388,6 +1388,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) // extended index), as we need to run semantic when `oidx` changes. size_t tupleOrigIdx = size_t.max; size_t tupleExtIdx = size_t.max; + bool hasDefault; foreach (oidx, oparam, eidx, eparam; tf.parameterList) { // oparam (original param) will always have the default arg @@ -1396,6 +1397,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) // position to get the offset in it later on. if (oparam.defaultArg) { + hasDefault = true; // Get the obvious case out of the way if (oparam is eparam) errors |= !defaultArgSemantic(eparam, argsc); @@ -1422,6 +1424,11 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) eparam.defaultArg = (*te.exps)[eidx - tupleExtIdx]; } } + else if (hasDefault) + { + .error(loc, "default argument expected for `%s`", oparam.toChars()); + errors = true; + } // We need to know the default argument to resolve `auto ref`, // hence why this has to take place as the very last step. @@ -2089,10 +2096,12 @@ extern (C++) Type merge(Type type) * loc = the location where the property is encountered * ident = the identifier of the property * flag = if flag & 1, don't report "not a property" error and just return NULL. + * src = expression for type `t` or null. * Returns: * expression representing the property, or null if not a property and (flag & 1) */ -Expression getProperty(Type t, Scope* scope_, const ref Loc loc, Identifier ident, int flag) +Expression getProperty(Type t, Scope* scope_, const ref Loc loc, Identifier ident, int flag, + Expression src = null) { Expression visitType(Type mt) { @@ -2169,7 +2178,10 @@ Expression getProperty(Type t, Scope* scope_, const ref Loc loc, Identifier iden error(loc, "no property `%s` for type `%s`, perhaps `import %.*s;` is needed?", ident.toChars(), mt.toChars(), cast(int)n.length, n.ptr); else { - error(loc, "no property `%s` for type `%s`", ident.toChars(), mt.toPrettyChars(true)); + if (src) + error(loc, "no property `%s` for `%s` of type `%s`", ident.toChars(), src.toChars(), mt.toPrettyChars(true)); + else + error(loc, "no property `%s` for type `%s`", ident.toChars(), mt.toPrettyChars(true)); if (auto dsym = mt.toDsymbol(scope_)) if (auto sym = dsym.isAggregateDeclaration()) { @@ -4457,7 +4469,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) /************************ - * Get the the default initialization expression for a type. + * Get the default initialization expression for a type. * Params: * mt = the type for which the init expression is returned * loc = the location where the expression needs to be evaluated diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc index b0ce870..fa5ec90 100644 --- a/gcc/d/expr.cc +++ b/gcc/d/expr.cc @@ -908,21 +908,12 @@ public: if ((postblit || destructor) && e->op != EXP::blit) { - /* Need to call postblit/destructor as part of assignment. - Construction has already been handled by the front-end. */ - gcc_assert (e->op != EXP::construct); - - /* So we can call postblits on const/immutable objects. */ - Type *tm = etype->unSharedOf ()->mutableOf (); - tree ti = build_typeinfo (e, tm); - - /* Generate: _d_arraysetassign (t1.ptr, &t2, t1.length, ti); */ - result = build_libcall (LIBCALL_ARRAYSETASSIGN, Type::tvoid, 4, - d_array_ptr (t1), - build_address (t2), - d_array_length (t1), ti); + /* This case should have been rewritten to `_d_arraysetassign` + in the semantic phase. */ + gcc_unreachable (); } - else if (integer_zerop (t2)) + + if (integer_zerop (t2)) { tree size = size_mult_expr (d_array_length (t1), size_int (etype->size ())); @@ -2473,6 +2464,20 @@ public: if (e->argprefix) result = compound_expr (build_expr (e->argprefix), result); } + else if (tb->ty == TY::Taarray) + { + /* Allocating memory for a new associative array. */ + tree arg = build_typeinfo (e, e->newtype); + tree mem = build_libcall (LIBCALL_AANEW, Type::tvoidptr, 1, arg); + + /* Return an associative array pointed to by MEM. */ + tree aatype = build_ctype (tb); + vec <constructor_elt, va_gc> *ce = NULL; + CONSTRUCTOR_APPEND_ELT (ce, TYPE_FIELDS (aatype), mem); + + result = build_nop (build_ctype (e->type), + build_constructor (aatype, ce)); + } else gcc_unreachable (); diff --git a/gcc/d/runtime.def b/gcc/d/runtime.def index 282f22c..f576bef 100644 --- a/gcc/d/runtime.def +++ b/gcc/d/runtime.def @@ -115,10 +115,6 @@ DEF_D_RUNTIME (ALLOCMEMORY, "_d_allocmemory", RT(VOIDPTR), P1(SIZE_T), DEF_D_RUNTIME (ARRAYCOPY, "_d_arraycopy", RT(ARRAY_VOID), P3(SIZE_T, ARRAY_VOID, ARRAY_VOID), 0) -/* Used for array assignments from a single element. */ -DEF_D_RUNTIME (ARRAYSETASSIGN, "_d_arraysetassign", RT(VOIDPTR), - P4(VOIDPTR, VOIDPTR, SIZE_T, CONST_TYPEINFO), 0) - /* Used for concatenating two or more arrays together. Then `n' variant is for when there is more than two arrays to handle. */ DEF_D_RUNTIME (ARRAYCATT, "_d_arraycatT", RT(ARRAY_BYTE), @@ -140,6 +136,7 @@ DEF_D_RUNTIME (ARRAYAPPENDWD, "_d_arrayappendwd", RT(ARRAY_VOID), /* Used for allocating a new associative array. */ DEF_D_RUNTIME (ASSOCARRAYLITERALTX, "_d_assocarrayliteralTX", RT(VOIDPTR), P3(CONST_TYPEINFO, ARRAY_VOID, ARRAY_VOID), 0) +DEF_D_RUNTIME (AANEW, "_aaNew", RT(VOIDPTR), P1(CONST_TYPEINFO), 0) /* Used for value equality of two associative arrays. */ DEF_D_RUNTIME (AAEQUAL, "_aaEqual", RT(INT), diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi index 7df6345..cc01c69 100644 --- a/gcc/doc/install.texi +++ b/gcc/doc/install.texi @@ -4598,6 +4598,15 @@ the GCC sources. Use the @option{--disable-sjlj-exceptions} and @option{--enable-newlib-io-long-long} options when configuring. +The @option{--with-arch} option may be specified to override the +default value for the @option{-march} option, and to also build +corresponding target libraries. +The default is @option{--with-arch=sm_30}. + +For example, if @option{--with-arch=sm_70} is specified, +@option{-march=sm_30} and @option{-march=sm_70} target libraries are +built, and code generation defaults to @option{-march=sm_70}. + @html <hr /> @end html diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 928ab0f..383d22a 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -9901,7 +9901,7 @@ security-sensitive value is written to an output file See @uref{https://cwe.mitre.org/data/definitions/532.html, CWE-532: Information Exposure Through Log Files}. -@item Wanalyzer-exposure-through-uninit-copy +@item -Wanalyzer-exposure-through-uninit-copy @opindex Wanalyzer-exposure-through-uninit-copy @opindex Wno-analyzer-exposure-through-uninit-copy This warning requires both @option{-fanalyzer} and the use of a plugin @@ -19681,6 +19681,9 @@ and the features that they enable by default: @item @samp{armv8.7-a} @tab Armv8.7-A @tab @samp{armv8.6-a}, @samp{+ls64} @item @samp{armv8.8-a} @tab Armv8.8-a @tab @samp{armv8.7-a}, @samp{+mops} @item @samp{armv9-a} @tab Armv9-A @tab @samp{armv8.5-a}, @samp{+sve}, @samp{+sve2} +@item @samp{armv9.1-a} @tab Armv9.1-A @tab @samp{armv9-a}, @samp{+bf16}, @samp{+i8mm} +@item @samp{armv9.2-a} @tab Armv9.2-A @tab @samp{armv9.1-a}, @samp{+ls64} +@item @samp{armv9.3-a} @tab Armv9.3-A @tab @samp{armv9.2-a}, @samp{+mops} @item @samp{armv8-r} @tab Armv8-R @tab @samp{armv8-r} @end multitable @@ -28055,7 +28058,9 @@ supported. Generate code for the specified PTX ISA target architecture (e.g.@: @samp{sm_35}). Valid architecture strings are @samp{sm_30}, @samp{sm_35}, @samp{sm_53}, @samp{sm_70}, @samp{sm_75} and -@samp{sm_80}. The default target architecture is sm_30. +@samp{sm_80}. +The default depends on how the compiler has been configured, see +@option{--with-arch}. This option sets the value of the preprocessor macro @code{__PTX_SM__}; for instance, for @samp{sm_35}, it has the value diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi index 760ff95..52357cc 100644 --- a/gcc/doc/sourcebuild.texi +++ b/gcc/doc/sourcebuild.texi @@ -2447,7 +2447,7 @@ PowerPC target pre-defines macro _ARCH_PWR9 which means the @code{-mcpu} setting is Power9 or later. @end table -@subsection RISC-V specific attributes +@subsubsection RISC-V specific attributes @table @code diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 998fb1b..6985e62 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,69 @@ +2022-09-25 Mikael Morin <mikael@gcc.gnu.org> + + PR fortran/41453 + * trans-expr.cc (gfc_conv_procedure_call): Allow strictly + matching derived types. + +2022-09-25 Mikael Morin <mikael@gcc.gnu.org> + + PR fortran/41453 + PR fortran/99169 + * trans-expr.cc (gfc_conv_procedure_call): Remove conditions + on ALLOCATABLE and POINTER attributes guarding clobber + generation. + +2022-09-25 Mikael Morin <mikael@gcc.gnu.org> + + PR fortran/41453 + PR fortran/87401 + * trans-expr.cc (gfc_conv_procedure_call): Remove condition + disabling clobber generation for ASSOCIATE variables. + +2022-09-25 Mikael Morin <mikael@gcc.gnu.org> + + PR fortran/41453 + PR fortran/87395 + * trans-expr.cc (gfc_conv_procedure_call): Remove condition + on SAVE attribute guarding clobber generation. + +2022-09-25 Mikael Morin <mikael@gcc.gnu.org> + + PR fortran/41453 + PR fortran/87395 + * trans-expr.cc (gfc_conv_procedure_call): Remove condition + disabling clobber generation for dummy variables. Remove + obsolete comment. + +2022-09-25 Harald Anlauf <anlauf@gmx.de> + Mikael Morin <mikael@gcc.gnu.org> + + PR fortran/105012 + * trans-expr.cc (gfc_conv_procedure_call): Use dummy + information from associated_dummy if there is no information + from the procedure interface. + +2022-09-25 Mikael Morin <mikael@gcc.gnu.org> + + PR fortran/106817 + * trans-expr.cc (gfc_conv_procedure_call): Collect all clobbers + to their own separate block. Append the block of clobbers to + the procedure preliminary block after the argument evaluation + codes for all the arguments. + +2022-09-25 Mikael Morin <mikael@gcc.gnu.org> + + PR fortran/105012 + * trans-expr.cc (gfc_conv_procedure_call): Retrieve variable + from the just calculated variable reference. + +2022-09-25 Mikael Morin <mikael@gcc.gnu.org> + + * trans.h (gfc_conv_expr_reference): Remove add_clobber + argument. + * trans-expr.cc (gfc_conv_expr_reference): Ditto. Inline code + depending on add_clobber and conditions controlling it ... + (gfc_conv_procedure_call): ... to here. + 2022-09-22 José Rui Faustino de Sousa <jrfsousa@gmail.com> PR fortran/100103 diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc index 7895d03..4f3ae82 100644 --- a/gcc/fortran/trans-expr.cc +++ b/gcc/fortran/trans-expr.cc @@ -6018,7 +6018,6 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, gfc_charlen cl; gfc_expr *e; gfc_symbol *fsym; - stmtblock_t post; enum {MISSING = 0, ELEMENTAL, SCALAR, SCALAR_POINTER, ARRAY}; gfc_component *comp = NULL; int arglen; @@ -6062,7 +6061,9 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, else info = NULL; + stmtblock_t post, clobbers; gfc_init_block (&post); + gfc_init_block (&clobbers); gfc_init_interface_mapping (&mapping); if (!comp) { @@ -6395,7 +6396,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, && e->symtree->n.sym->attr.pointer)) && fsym && fsym->attr.target) /* Make sure the function only gets called once. */ - gfc_conv_expr_reference (&parmse, e, false); + gfc_conv_expr_reference (&parmse, e); else if (e->expr_type == EXPR_FUNCTION && e->symtree->n.sym->result && e->symtree->n.sym->result != e->symtree->n.sym @@ -6502,22 +6503,55 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, } else { - bool add_clobber; - add_clobber = fsym && fsym->attr.intent == INTENT_OUT - && !fsym->attr.allocatable && !fsym->attr.pointer - && e->symtree && e->symtree->n.sym - && !e->symtree->n.sym->attr.dimension - && !e->symtree->n.sym->attr.pointer - && !e->symtree->n.sym->attr.allocatable - /* See PR 41453. */ - && !e->symtree->n.sym->attr.dummy - /* FIXME - PR 87395 and PR 41453 */ - && e->symtree->n.sym->attr.save == SAVE_NONE - && !e->symtree->n.sym->attr.associate_var - && e->ts.type != BT_CHARACTER && e->ts.type != BT_DERIVED - && e->ts.type != BT_CLASS && !sym->attr.elemental; - - gfc_conv_expr_reference (&parmse, e, add_clobber); + gfc_conv_expr_reference (&parmse, e); + + gfc_symbol *dsym = fsym; + gfc_dummy_arg *dummy; + + /* Use associated dummy as fallback for formal + argument if there is no explicit interface. */ + if (dsym == NULL + && (dummy = arg->associated_dummy) + && dummy->intrinsicness == GFC_NON_INTRINSIC_DUMMY_ARG + && dummy->u.non_intrinsic->sym) + dsym = dummy->u.non_intrinsic->sym; + + if (dsym + && dsym->attr.intent == INTENT_OUT + && !dsym->attr.allocatable + && !dsym->attr.pointer + && e->expr_type == EXPR_VARIABLE + && e->ref == NULL + && e->symtree + && e->symtree->n.sym + && !e->symtree->n.sym->attr.dimension + && e->ts.type != BT_CHARACTER + && e->ts.type != BT_CLASS + && (e->ts.type != BT_DERIVED + || (dsym->ts.type == BT_DERIVED + && e->ts.u.derived == dsym->ts.u.derived + /* Types with allocatable components are + excluded from clobbering because we need + the unclobbered pointers to free the + allocatable components in the callee. + Same goes for finalizable types or types + with finalizable components, we need to + pass the unclobbered values to the + finalization routines. + For parameterized types, it's less clear + but they may not have a constant size + so better exclude them in any case. */ + && !e->ts.u.derived->attr.alloc_comp + && !e->ts.u.derived->attr.pdt_type + && !gfc_is_finalizable (e->ts.u.derived, NULL))) + && !sym->attr.elemental) + { + tree var; + var = build_fold_indirect_ref_loc (input_location, + parmse.expr); + tree clobber = build_clobber (TREE_TYPE (var)); + gfc_add_modify (&clobbers, var, clobber); + } } /* Catch base objects that are not variables. */ if (e->ts.type == BT_CLASS @@ -7384,6 +7418,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, vec_safe_push (arglist, parmse.expr); } + gfc_add_block_to_block (&se->pre, &clobbers); gfc_finish_interface_mapping (&mapping, &se->pre, &se->post); if (comp) @@ -9484,7 +9519,7 @@ gfc_conv_expr_type (gfc_se * se, gfc_expr * expr, tree type) values only. */ void -gfc_conv_expr_reference (gfc_se * se, gfc_expr * expr, bool add_clobber) +gfc_conv_expr_reference (gfc_se * se, gfc_expr * expr) { gfc_ss *ss; tree var; @@ -9524,16 +9559,6 @@ gfc_conv_expr_reference (gfc_se * se, gfc_expr * expr, bool add_clobber) gfc_add_block_to_block (&se->pre, &se->post); se->expr = var; } - else if (add_clobber && expr->ref == NULL) - { - tree clobber; - tree var; - /* FIXME: This fails if var is passed by reference, see PR - 41453. */ - var = expr->symtree->n.sym->backend_decl; - clobber = build_clobber (TREE_TYPE (var)); - gfc_add_modify (&se->pre, var, clobber); - } return; } diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h index 03d5288..bc9035c 100644 --- a/gcc/fortran/trans.h +++ b/gcc/fortran/trans.h @@ -499,8 +499,7 @@ tree gfc_build_compare_string (tree, tree, tree, tree, int, enum tree_code); void gfc_conv_expr (gfc_se * se, gfc_expr * expr); void gfc_conv_expr_val (gfc_se * se, gfc_expr * expr); void gfc_conv_expr_lhs (gfc_se * se, gfc_expr * expr); -void gfc_conv_expr_reference (gfc_se * se, gfc_expr * expr, - bool add_clobber = false); +void gfc_conv_expr_reference (gfc_se * se, gfc_expr * expr); void gfc_conv_expr_type (gfc_se * se, gfc_expr *, tree); diff --git a/gcc/omp-low.cc b/gcc/omp-low.cc index d9f9aae..dc42c75 100644 --- a/gcc/omp-low.cc +++ b/gcc/omp-low.cc @@ -7631,6 +7631,7 @@ lower_oacc_reductions (location_t loc, tree clauses, tree level, bool inner, incoming = build_simple_mem_ref (incoming); } else + /* Note that 'var' might be a mem ref. */ v1 = v2 = v3 = var; /* Determine position in reduction buffer, which may be used @@ -7659,26 +7660,28 @@ lower_oacc_reductions (location_t loc, tree clauses, tree level, bool inner, = build_call_expr_internal_loc (loc, IFN_GOACC_REDUCTION, TREE_TYPE (var), 6, setup_code, unshare_expr (ref_to_res), - incoming, level, op, off); + unshare_expr (incoming), + level, op, off); tree init_call = build_call_expr_internal_loc (loc, IFN_GOACC_REDUCTION, TREE_TYPE (var), 6, init_code, unshare_expr (ref_to_res), - v1, level, op, off); + unshare_expr (v1), level, op, off); tree fini_call = build_call_expr_internal_loc (loc, IFN_GOACC_REDUCTION, TREE_TYPE (var), 6, fini_code, unshare_expr (ref_to_res), - v2, level, op, off); + unshare_expr (v2), level, op, off); tree teardown_call = build_call_expr_internal_loc (loc, IFN_GOACC_REDUCTION, TREE_TYPE (var), 6, teardown_code, - ref_to_res, v3, level, op, off); + ref_to_res, unshare_expr (v3), + level, op, off); - gimplify_assign (v1, setup_call, &before_fork); - gimplify_assign (v2, init_call, &after_fork); - gimplify_assign (v3, fini_call, &before_join); - gimplify_assign (outgoing, teardown_call, &after_join); + gimplify_assign (unshare_expr (v1), setup_call, &before_fork); + gimplify_assign (unshare_expr (v2), init_call, &after_fork); + gimplify_assign (unshare_expr (v3), fini_call, &before_join); + gimplify_assign (unshare_expr (outgoing), teardown_call, &after_join); } /* Now stitch things together. */ diff --git a/gcc/range-op.cc b/gcc/range-op.cc index 072ebd3..fc930f4 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -2951,6 +2951,15 @@ operator_bitwise_and::op1_range (irange &r, tree type, } if (r.undefined_p ()) set_nonzero_range_from_mask (r, type, lhs); + + // For 0 = op1 & MASK, op1 is ~MASK. + if (lhs.zero_p () && op2.singleton_p ()) + { + wide_int nz = wi::bit_not (op2.get_nonzero_bits ()); + int_range<2> tmp (type); + tmp.set_nonzero_bits (nz); + r.intersect (tmp); + } return true; } @@ -4612,6 +4621,15 @@ range_op_bitwise_and_tests () op_bitwise_and.op1_range (res, integer_type_node, i1, i2); ASSERT_TRUE (res == int_range<1> (integer_type_node)); + // For 0 = x & MASK, x is ~MASK. + { + int_range<2> zero (integer_zero_node, integer_zero_node); + int_range<2> mask = int_range<2> (INT (7), INT (7)); + op_bitwise_and.op1_range (res, integer_type_node, zero, mask); + wide_int inv = wi::shwi (~7U, TYPE_PRECISION (integer_type_node)); + ASSERT_TRUE (res.get_nonzero_bits () == inv); + } + // (NONZERO | X) is nonzero. i1.set_nonzero (integer_type_node); i2.set_varying (integer_type_node); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d37e199..24f4ac5 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,122 @@ +2022-09-26 Marek Polacek <polacek@redhat.com> + + PR c++/106656 + * g++.dg/cpp23/feat-cxx2b.C: Adjust. + * g++.dg/cpp2a/feat-cxx2a.C: Likewise. + * g++.dg/ext/char8_t-feature-test-macro-2.C: Likewise. + * g++.dg/ext/char8_t-init-2.C: Likewise. + * g++.dg/cpp2a/char8_t3.C: New test. + * g++.dg/cpp2a/char8_t4.C: New test. + +2022-09-26 Marek Polacek <polacek@redhat.com> + + PR c++/106784 + * g++.dg/ext/is_convertible3.C: New test. + * g++.dg/ext/is_nothrow_convertible3.C: New test. + +2022-09-26 Patrick Palka <ppalka@redhat.com> + + PR c++/107033 + * g++.dg/modules/partial-2.cc, g++.dg/modules/partial-2.h: New + files, factored out from ... + * g++.dg/modules/partial-2_a.C, g++.dg/modules/partial-2_b.C: ... + these. + * g++.dg/modules/partial-2_c.H: New test. + * g++.dg/modules/partial-2_d.C: New test. + +2022-09-26 Aldy Hernandez <aldyh@redhat.com> + + PR tree-optimization/107009 + * gcc.dg/tree-ssa/pr107009.c: New test. + +2022-09-26 Jeff Law <jeffreyalaw@gmail.com> + + * gcc.target/riscv/ret-1.c: New test. + +2022-09-26 Tobias Burnus <tobias@codesourcery.com> + + PR middle-end/106982 + * c-c++-common/goacc/reduction-7.c: New test. + * c-c++-common/goacc/reduction-8.c: New test. + +2022-09-26 Kewen Lin <linkw@linux.ibm.com> + + PR target/96072 + * gcc.target/powerpc/pr96072.c: New test. + +2022-09-26 Hu, Lin1 <lin1.hu@intel.com> + + PR target/94962 + * gcc.target/i386/avx256-unaligned-store-3.c: Add -mno-avx512f + +2022-09-26 Kewen Lin <linkw@linux.ibm.com> + + PR target/100645 + * gcc.target/powerpc/pr100645.c: New test. + +2022-09-26 Hongtao Liu <hongtao.liu@intel.com> + Liwei Xu <liwei.xu@intel.com> + + * gcc.target/i386/pr53346-1.c: New test. + * gcc.target/i386/pr53346-2.c: New test. + * gcc.target/i386/pr53346-3.c: New test. + * gcc.target/i386/pr53346-4.c: New test. + +2022-09-25 Mikael Morin <mikael@gcc.gnu.org> + + PR fortran/41453 + * gfortran.dg/intent_optimize_10.f90: New test. + +2022-09-25 Mikael Morin <mikael@gcc.gnu.org> + + PR fortran/41453 + PR fortran/99169 + * gfortran.dg/intent_optimize_9.f90: New test. + +2022-09-25 Mikael Morin <mikael@gcc.gnu.org> + + PR fortran/41453 + PR fortran/87401 + * gfortran.dg/intent_optimize_8.f90: New test. + +2022-09-25 Mikael Morin <mikael@gcc.gnu.org> + + PR fortran/41453 + PR fortran/87395 + * gfortran.dg/intent_optimize_7.f90: New test. + +2022-09-25 Mikael Morin <mikael@gcc.gnu.org> + + PR fortran/41453 + PR fortran/87395 + * gfortran.dg/intent_optimize_6.f90: New test. + +2022-09-25 Harald Anlauf <anlauf@gmx.de> + Mikael Morin <mikael@gcc.gnu.org> + + PR fortran/105012 + * gfortran.dg/intent_optimize_5.f90: New test. + +2022-09-25 Mikael Morin <mikael@gcc.gnu.org> + + PR fortran/106817 + * gfortran.dg/intent_optimize_4.f90: New test. + +2022-09-25 Mikael Morin <mikael@gcc.gnu.org> + + PR fortran/105012 + * gfortran.dg/intent_out_15.f90: New test. + +2022-09-24 Jakub Jelinek <jakub@redhat.com> + + PR c/107001 + * c-c++-common/gomp/pr107001.c: New test. + +2022-09-24 Jakub Jelinek <jakub@redhat.com> + + PR c/106981 + * c-c++-common/gomp/pr106981.c: New test. + 2022-09-23 Joseph Myers <joseph@codesourcery.com> * gcc.dg/c2x-complit-1.c, gcc.dg/c2x-concat-1.c, diff --git a/gcc/testsuite/c-c++-common/goacc/reduction-7.c b/gcc/testsuite/c-c++-common/goacc/reduction-7.c new file mode 100644 index 0000000..482b0ab --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/reduction-7.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ + +/* PR middle-end/106982 */ + +long long n = 100; +int multiplicitive_n = 128; + +void test1(double *rand, double *a, double *b, double *c) +{ +#pragma acc data copyin(a[0:10*multiplicitive_n], b[0:10*multiplicitive_n]) copyout(c[0:10]) + { +#pragma acc parallel loop + for (int i = 0; i < 10; ++i) + { + double temp = 1.0; +#pragma acc loop vector reduction(*:temp) + for (int j = 0; j < multiplicitive_n; ++j) + temp *= a[(i * multiplicitive_n) + j] + b[(i * multiplicitive_n) + j]; + c[i] = temp; + } + } +} diff --git a/gcc/testsuite/c-c++-common/goacc/reduction-8.c b/gcc/testsuite/c-c++-common/goacc/reduction-8.c new file mode 100644 index 0000000..2c3ed49 --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/reduction-8.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ + +/* PR middle-end/106982 */ + +void test1(double *c) +{ + double reduced[5]; +#pragma acc parallel loop gang private(reduced) + for (int x = 0; x < 5; ++x) +#pragma acc loop worker reduction(*:reduced) + for (int y = 0; y < 5; ++y) { } +} diff --git a/gcc/testsuite/c-c++-common/gomp/assume-1.c b/gcc/testsuite/c-c++-common/gomp/assume-1.c new file mode 100644 index 0000000..05c64a8 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/assume-1.c @@ -0,0 +1,29 @@ +void +foo (int i, int *a) +{ + #pragma omp assume no_openmp, absent (target, teams) holds (i < 32U) holds (i < 32U) + ; + #pragma omp assume no_openmp_routines, contains (simd) + { + #pragma omp simd + for (int j = 0; j < i; j++) + a[j] = j; + } + #pragma omp assume no_parallelism, contains (error) + { + if (i >= 32) + { + #pragma omp error at (execution) message ("Should not happen") + } + } + #pragma omp assume absent (for) + ; + #pragma omp assume absent (atomic, barrier, cancel, cancellation point) absent (critical, depobj) + ; + #pragma omp assume absent (distribute, flush, loop, masked, master, nothing, ordered) + ; + #pragma omp assume absent (parallel, scan, scope, section, sections, simd, single, task) + ; + #pragma omp assume absent (taskgroup, taskloop, taskwait, taskyield) + ; +} diff --git a/gcc/testsuite/c-c++-common/gomp/assume-2.c b/gcc/testsuite/c-c++-common/gomp/assume-2.c new file mode 100644 index 0000000..4739605 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/assume-2.c @@ -0,0 +1,46 @@ +void +foo (int i, int *a) +{ + #pragma omp assume no_openmp no_openmp /* { dg-error "too many 'no_openmp' clauses" } */ + ; + #pragma omp assume no_openmp_routines, no_openmp_routines /* { dg-error "too many 'no_openmp_routines' clauses" } */ + ; + #pragma omp assume no_parallelism, no_parallelism /* { dg-error "too many 'no_parallelism' clauses" } */ + ; + #pragma omp assume absent (target, target) /* { dg-error "'target' directive mentioned multiple times in 'absent' clauses" } */ + ; + #pragma omp assume absent (target, teams) absent (teams, parallel) /* { dg-error "'teams' directive mentioned multiple times in 'absent' clauses" } */ + ; + #pragma omp assume contains (cancellation point, cancellation point) /* { dg-error "'cancellation point' directive mentioned multiple times in 'contains' clauses" } */ + ; + #pragma omp assume contains (target enter data, target exit data) contains (target exit data, parallel) /* { dg-error "target exit data' directive mentioned multiple times in 'contains' clauses" } */ + ; + #pragma omp assume absent (target enter data, target exit data) contains (target exit data, parallel) /* { dg-error "'target exit data' directive mentioned in both 'absent' and 'contains' clauses" } */ + ; + #pragma omp assume contains (target enter data, target exit data) absent (target enter data, parallel) /* { dg-error "'target enter data' directive mentioned in both 'absent' and 'contains' clauses" } */ + ; + #pragma omp assume contains (declare target) /* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */ + ; + #pragma omp assume absent (parallel for simd) /* { dg-error "unknown OpenMP directive name in 'absent' clause argument" } */ + ; + #pragma omp assume contains (target parallel) /* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */ + ; + #pragma omp assume absent (assume) /* { dg-error "unknown OpenMP directive name in 'absent' clause argument" } */ + ; + #pragma omp assume absent (assumes) /* { dg-error "unknown OpenMP directive name in 'absent' clause argument" } */ + ; + #pragma omp assume contains (begin assumes) /* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */ + ; + #pragma omp assume contains (end assumes) /* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */ + ; + #pragma omp assume contains (foo) /* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */ + ; + #pragma omp assume absent (target enter something) /* { dg-error "unknown OpenMP directive name in 'absent' clause argument" } */ + ; + #pragma omp assume foobar /* { dg-error "expected assumption clause" } */ + ; + #pragma omp assume ext_GCC_foobarbaz, ext_GCC_baz (1, 12, 1 < 17), no_parallelism /* { dg-warning "unknown assumption clause 'ext_GCC_foobarbaz'" } */ + ; /* { dg-warning "unknown assumption clause 'ext_GCC_baz'" "" { target *-*-* } .-1 } */ + #pragma omp assume /* { dg-error "expected at least one assumption clause" } */ + ; +} diff --git a/gcc/testsuite/c-c++-common/gomp/assume-3.c b/gcc/testsuite/c-c++-common/gomp/assume-3.c new file mode 100644 index 0000000..ce38359 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/assume-3.c @@ -0,0 +1,27 @@ +/* { dg-do run } */ +/* { dg-options "-fno-openmp -fopenmp-simd" } */ + +int i, j; + +int +foo (void) +{ + j = 1; + return 1; +} + +int +main () +{ + #pragma omp assume holds (i < 42) + ; + #pragma omp assume holds (++i == 1) + ; + if (i != 0) + __builtin_abort (); + #pragma omp assume holds (foo () == 1) + ; + if (j != 0) + __builtin_abort (); + return 0; +} diff --git a/gcc/testsuite/c-c++-common/gomp/assumes-1.c b/gcc/testsuite/c-c++-common/gomp/assumes-1.c new file mode 100644 index 0000000..8b3fb37 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/assumes-1.c @@ -0,0 +1,26 @@ +int i; + +#pragma omp assumes no_openmp, absent (target, teams) holds (i < 32U) holds (i < 32U) +void +bar (void) +{ +} + +#pragma omp assumes no_openmp_routines + +#pragma omp assumes no_parallelism + +#pragma omp assumes absent (for) +void +fred (void) +{ +} + +#pragma omp assumes absent (atomic, barrier, cancel, cancellation point) absent (critical, depobj) \ + absent (distribute, flush, loop, masked, master, nothing, ordered) \ + absent (parallel, scan, scope, section, sections, simd, single, task) \ + absent (taskgroup, taskloop, taskwait, taskyield) +void +foo (void) +{ +} diff --git a/gcc/testsuite/c-c++-common/gomp/assumes-2.c b/gcc/testsuite/c-c++-common/gomp/assumes-2.c new file mode 100644 index 0000000..924f323 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/assumes-2.c @@ -0,0 +1,23 @@ +#pragma omp assumes no_openmp no_openmp /* { dg-error "too many 'no_openmp' clauses" } */ +#pragma omp assumes no_openmp_routines, no_openmp_routines /* { dg-error "too many 'no_openmp_routines' clauses" } */ +#pragma omp assumes no_parallelism, no_parallelism /* { dg-error "too many 'no_parallelism' clauses" } */ +#pragma omp assumes absent (target, target) /* { dg-error "'target' directive mentioned multiple times in 'absent' clauses" } */ +#pragma omp assumes absent (target, teams) absent (teams, parallel) /* { dg-error "'teams' directive mentioned multiple times in 'absent' clauses" } */ +#pragma omp assumes contains (cancellation point, cancellation point) /* { dg-error "'cancellation point' directive mentioned multiple times in 'contains' clauses" } */ +#pragma omp assumes contains (target enter data, target exit data) contains (target exit data, parallel) /* { dg-error "target exit data' directive mentioned multiple times in 'contains' clauses" } */ +#pragma omp assumes absent (target enter data, target exit data) contains (target exit data, parallel) /* { dg-error "'target exit data' directive mentioned in both 'absent' and 'contains' clauses" } */ +#pragma omp assumes contains (target enter data, target exit data) absent (target enter data, parallel) /* { dg-error "'target enter data' directive mentioned in both 'absent' and 'contains' clauses" } */ +#pragma omp assumes contains (declare target) /* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */ +#pragma omp assumes absent (parallel for simd) /* { dg-error "unknown OpenMP directive name in 'absent' clause argument" } */ +#pragma omp assumes contains (target parallel) /* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */ +#pragma omp assumes absent (assume) /* { dg-error "unknown OpenMP directive name in 'absent' clause argument" } */ +#pragma omp assumes absent (assumes) /* { dg-error "unknown OpenMP directive name in 'absent' clause argument" } */ +#pragma omp assumes contains (begin assumes) /* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */ +#pragma omp assumes contains (end assumes) /* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */ +#pragma omp assumes contains (foo) /* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */ +#pragma omp assumes absent (target enter something) /* { dg-error "unknown OpenMP directive name in 'absent' clause argument" } */ +#pragma omp assumes foobar /* { dg-error "expected assumption clause" } */ +#pragma omp assumes ext_GCC_foobarbaz, ext_GCC_baz (1, 12, 1 < 17), no_parallelism /* { dg-warning "unknown assumption clause 'ext_GCC_foobarbaz'" } */ + /* { dg-warning "unknown assumption clause 'ext_GCC_baz'" "" { target *-*-* } .-1 } */ +#pragma omp assumes /* { dg-error "expected at least one assumption clause" } */ +int i; diff --git a/gcc/testsuite/c-c++-common/gomp/assumes-3.c b/gcc/testsuite/c-c++-common/gomp/assumes-3.c new file mode 100644 index 0000000..0bfadac --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/assumes-3.c @@ -0,0 +1,15 @@ +#pragma omp assumes contains (simd) +#pragma omp assumes contains (error) +#pragma omp assumes contains (simd) + +void +foo (int i, int *a) +{ + #pragma omp simd + for (int j = 0; j < i; j++) + a[j] = j; + if (i >= 32) + { + #pragma omp error at (execution) message ("Should not happen") + } +} diff --git a/gcc/testsuite/c-c++-common/gomp/assumes-4.c b/gcc/testsuite/c-c++-common/gomp/assumes-4.c new file mode 100644 index 0000000..6e77adb --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/assumes-4.c @@ -0,0 +1,6 @@ +void +foo (void) +{ + #pragma omp assumes no_openmp /* { dg-error "'#pragma omp assumes' may only be used at file scope" "" { target c } } */ + ; /* { dg-error "'#pragma omp assumes' may only be used at file or namespace scope" "" { target c++ } .-1 } */ +} diff --git a/gcc/testsuite/c-c++-common/gomp/begin-assumes-1.c b/gcc/testsuite/c-c++-common/gomp/begin-assumes-1.c new file mode 100644 index 0000000..c3332b1 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/begin-assumes-1.c @@ -0,0 +1,46 @@ +int i; + +#pragma omp begin assumes no_openmp, absent (target, teams) holds (i < 32U) holds (i < 32U) +void +bar (void) +{ +} +#pragma omp end assumes + +#pragma omp begin assumes no_openmp_routines, contains (simd) +void +baz (int *a) +{ + #pragma omp simd + for (int j = 0; j < i; j++) + a[j] = j; +} +#pragma omp end assumes + +#pragma omp begin assumes no_parallelism, contains (error) +void +qux (void) +{ + if (i >= 32) + { + #pragma omp error at (execution) message ("Should not happen") + } +} +#pragma omp end assumes + +#pragma omp begin assumes absent (for) +void +fred (void) +{ +} +#pragma omp end assumes + +#pragma omp begin assumes absent (atomic, barrier, cancel, cancellation point) absent (critical, depobj) \ + absent (distribute, flush, loop, masked, master, nothing, ordered) \ + absent (parallel, scan, scope, section, sections, simd, single, task) \ + absent (taskgroup, taskloop, taskwait, taskyield) +void +foo (void) +{ +} +#pragma omp end assumes diff --git a/gcc/testsuite/c-c++-common/gomp/begin-assumes-2.c b/gcc/testsuite/c-c++-common/gomp/begin-assumes-2.c new file mode 100644 index 0000000..15dae64 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/begin-assumes-2.c @@ -0,0 +1,63 @@ +#pragma omp begin assumes no_openmp no_openmp /* { dg-error "too many 'no_openmp' clauses" } */ +void f1 (void) {} +#pragma omp end assumes +#pragma omp begin assumes no_openmp_routines, no_openmp_routines /* { dg-error "too many 'no_openmp_routines' clauses" } */ +void f2 (void) {} +#pragma omp end assumes +#pragma omp begin assumes no_parallelism, no_parallelism /* { dg-error "too many 'no_parallelism' clauses" } */ +void f3 (void) {} +#pragma omp end assumes +#pragma omp begin assumes absent (target, target) /* { dg-error "'target' directive mentioned multiple times in 'absent' clauses" } */ +void f4 (void) {} +#pragma omp end assumes +#pragma omp begin assumes absent (target, teams) absent (teams, parallel) /* { dg-error "'teams' directive mentioned multiple times in 'absent' clauses" } */ +void f5 (void) {} +#pragma omp end assumes +#pragma omp begin assumes contains (cancellation point, cancellation point) /* { dg-error "'cancellation point' directive mentioned multiple times in 'contains' clauses" } */ +void f6 (void) {} +#pragma omp end assumes +#pragma omp begin assumes contains (target enter data, target exit data) contains (target exit data, parallel) /* { dg-error "target exit data' directive mentioned multiple times in 'contains' clauses" } */ +void f7 (void) {} +#pragma omp end assumes +#pragma omp begin assumes absent (target enter data, target exit data) contains (target exit data, parallel) /* { dg-error "'target exit data' directive mentioned in both 'absent' and 'contains' clauses" } */ +void f8 (void) {} +#pragma omp end assumes +#pragma omp begin assumes contains (target enter data, target exit data) absent (target enter data, parallel) /* { dg-error "'target enter data' directive mentioned in both 'absent' and 'contains' clauses" } */ +void f9 (void) {} +#pragma omp end assumes +#pragma omp begin assumes contains (declare target) /* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */ +void f10 (void) {} +#pragma omp end assumes +#pragma omp begin assumes absent (parallel for simd) /* { dg-error "unknown OpenMP directive name in 'absent' clause argument" } */ +void f11 (void) {} +#pragma omp end assumes +#pragma omp begin assumes contains (target parallel) /* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */ +void f12 (void) {} +#pragma omp end assumes +#pragma omp begin assumes absent (assume) /* { dg-error "unknown OpenMP directive name in 'absent' clause argument" } */ +void f13 (void) {} +#pragma omp end assumes +#pragma omp begin assumes absent (assumes) /* { dg-error "unknown OpenMP directive name in 'absent' clause argument" } */ +void f14 (void) {} +#pragma omp end assumes +#pragma omp begin assumes contains (begin assumes) /* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */ +void f15 (void) {} +#pragma omp end assumes +#pragma omp begin assumes contains (end assumes) /* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */ +void f16 (void) {} +#pragma omp end assumes +#pragma omp begin assumes contains (foo) /* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */ +void f17 (void) {} +#pragma omp end assumes +#pragma omp begin assumes absent (target enter something) /* { dg-error "unknown OpenMP directive name in 'absent' clause argument" } */ +void f18 (void) {} +#pragma omp end assumes +#pragma omp begin assumes foobar /* { dg-error "expected assumption clause" } */ +void f19 (void) {} +#pragma omp end assumes +#pragma omp begin assumes ext_GCC_foobarbaz, ext_GCC_baz (1, 12, 1 < 17), no_parallelism /* { dg-warning "unknown assumption clause 'ext_GCC_foobarbaz'" } */ +void f20 (void) {} /* { dg-warning "unknown assumption clause 'ext_GCC_baz'" "" { target *-*-* } .-1 } */ +#pragma omp end assumes +#pragma omp begin assumes /* { dg-error "expected at least one assumption clause" } */ +void f21 (void) {} +#pragma omp end assumes diff --git a/gcc/testsuite/c-c++-common/gomp/begin-assumes-3.c b/gcc/testsuite/c-c++-common/gomp/begin-assumes-3.c new file mode 100644 index 0000000..202d5c7 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/begin-assumes-3.c @@ -0,0 +1,2 @@ +#pragma omp begin assumes no_openmp_routines +void foo (void); /* { dg-error "'#pragma omp begin assumes' without corresponding '#pragma omp end assumes'" } */ diff --git a/gcc/testsuite/c-c++-common/gomp/begin-assumes-4.c b/gcc/testsuite/c-c++-common/gomp/begin-assumes-4.c new file mode 100644 index 0000000..eea6f90 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/begin-assumes-4.c @@ -0,0 +1,2 @@ +#pragma omp end assumes /* { dg-error "'#pragma omp end assumes' without corresponding '#pragma omp begin assumes'" } */ +void foo (void); diff --git a/gcc/testsuite/c-c++-common/gomp/declare-target-6.c b/gcc/testsuite/c-c++-common/gomp/declare-target-6.c new file mode 100644 index 0000000..586eb50 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/declare-target-6.c @@ -0,0 +1,2 @@ +#pragma omp end declare target /* { dg-error "'#pragma omp end declare target' without corresponding '#pragma omp declare target'" } */ +void foo (void); diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda13.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda13.C index 962ec8d..0323a0d 100644 --- a/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda13.C +++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda13.C @@ -2,4 +2,4 @@ auto l1 = []() constexpr constexpr { }; // { dg-error "duplicate" } auto l2 = []() mutable mutable { }; // { dg-error "duplicate" } -auto l3 = []() static { }; // { dg-error "static" } +auto l3 = []() static { }; // { dg-error "static' only valid in lambda with" "" { target c++20_down } } diff --git a/gcc/testsuite/g++.dg/cpp23/ext-floating.h b/gcc/testsuite/g++.dg/cpp23/ext-floating.h new file mode 100644 index 0000000..ffd9e63 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/ext-floating.h @@ -0,0 +1,30 @@ +// P1467R9 - Extended floating-point types and standard names. + +namespace std +{ + #ifdef __STDCPP_FLOAT16_T__ + using float16_t = _Float16; + #endif + #ifdef __STDCPP_FLOAT32_T__ + using float32_t = _Float32; + #endif + #ifdef __STDCPP_FLOAT64_T__ + using float64_t = _Float64; + #endif + #ifdef __STDCPP_FLOAT128_T__ + using float128_t = _Float128; + #endif + #undef __STDCPP_BFLOAT16_T__ + #ifdef __STDCPP_BFLOAT16_T__ + using bfloat16_t = __bf16; // ??? + #endif + template<typename T, T v> struct integral_constant { + static constexpr T value = v; + }; + typedef integral_constant<bool, false> false_type; + typedef integral_constant<bool, true> true_type; + template<class T, class U> + struct is_same : std::false_type {}; + template <class T> + struct is_same<T, T> : std::true_type {}; +} diff --git a/gcc/testsuite/g++.dg/cpp23/ext-floating1.C b/gcc/testsuite/g++.dg/cpp23/ext-floating1.C new file mode 100644 index 0000000..63232af --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/ext-floating1.C @@ -0,0 +1,447 @@ +// P1467R9 - Extended floating-point types and standard names. +// { dg-do compile { target c++23 } } +// { dg-options "" } + +#include "ext-floating.h" + +#ifdef __STRICT_ANSI__ +#undef __SIZEOF_FLOAT128__ +#endif + +using namespace std; + +static_assert (!is_same<float, double>::value); +static_assert (!is_same<float, long double>::value); +static_assert (!is_same<double, long double>::value); +static_assert (is_same<decltype (0.0f), float>::value); +static_assert (is_same<decltype (0.0F), float>::value); +static_assert (is_same<decltype (0.0), double>::value); +static_assert (is_same<decltype (0.0l), long double>::value); +static_assert (is_same<decltype (0.0L), long double>::value); +static_assert (is_same<decltype (0.0f + 0.0F), float>::value); +static_assert (is_same<decltype (0.0F + 0.0f), float>::value); +static_assert (is_same<decltype (0.0 + 0.0), double>::value); +static_assert (is_same<decltype (0.0l + 0.0L), long double>::value); +static_assert (is_same<decltype (0.0L + 0.0l), long double>::value); +#ifdef __SIZEOF_FLOAT128__ +static_assert (is_same<decltype (0.0q), __float128>::value); +static_assert (is_same<decltype (0.0Q), __float128>::value); +static_assert (is_same<decltype (0.0q + 0.0q), __float128>::value); +static_assert (is_same<decltype (0.0Q + 0.0Q), __float128>::value); +#endif +#ifdef __STDCPP_FLOAT16_T__ +static_assert (!is_same<float, float16_t>::value); +static_assert (!is_same<double, float16_t>::value); +static_assert (!is_same<long double, float16_t>::value); +static_assert (is_same<decltype (0.0f16), float16_t>::value); +static_assert (is_same<decltype (0.0F16), float16_t>::value); +static_assert (is_same<decltype (0.0f16 + 0.0f16), float16_t>::value); +static_assert (is_same<decltype (0.0F16 + 0.0F16), float16_t>::value); +#endif +#ifdef __STDCPP_FLOAT32_T__ +static_assert (!is_same<float, float32_t>::value); +static_assert (!is_same<double, float32_t>::value); +static_assert (!is_same<long double, float32_t>::value); +static_assert (!is_same<decltype (0.0f), float32_t>::value); +static_assert (!is_same<decltype (0.0F), float32_t>::value); +static_assert (is_same<decltype (0.0f32), float32_t>::value); +static_assert (is_same<decltype (0.0F32), float32_t>::value); +static_assert (!is_same<decltype (0.0f32), float>::value); +static_assert (!is_same<decltype (0.0F32), float>::value); +static_assert (is_same<decltype (0.0f32 + 0.0f32), float32_t>::value); +static_assert (is_same<decltype (0.0F32 + 0.0F32), float32_t>::value); +#endif +#ifdef __STDCPP_FLOAT64_T__ +static_assert (!is_same<float, float64_t>::value); +static_assert (!is_same<double, float64_t>::value); +static_assert (!is_same<long double, float64_t>::value); +static_assert (!is_same<decltype (0.0), float64_t>::value); +static_assert (is_same<decltype (0.0f64), float64_t>::value); +static_assert (is_same<decltype (0.0F64), float64_t>::value); +static_assert (!is_same<decltype (0.0f64), double>::value); +static_assert (!is_same<decltype (0.0F64), double>::value); +static_assert (is_same<decltype (0.0f64 + 0.0f64), float64_t>::value); +static_assert (is_same<decltype (0.0F64 + 0.0F64), float64_t>::value); +#endif +#ifdef __STDCPP_FLOAT128_T__ +static_assert (!is_same<float, float128_t>::value); +static_assert (!is_same<double, float128_t>::value); +static_assert (!is_same<long double, float128_t>::value); +static_assert (!is_same<decltype (0.0l), float128_t>::value); +static_assert (!is_same<decltype (0.0L), float128_t>::value); +static_assert (is_same<decltype (0.0f128), float128_t>::value); +static_assert (is_same<decltype (0.0F128), float128_t>::value); +static_assert (!is_same<decltype (0.0f128), long double>::value); +static_assert (!is_same<decltype (0.0F128), long double>::value); +static_assert (is_same<decltype (0.0f128 + 0.0f128), float128_t>::value); +static_assert (is_same<decltype (0.0F128 + 0.0F128), float128_t>::value); +#ifdef __SIZEOF_FLOAT128__ +static_assert (!is_same<float128_t, __float128>::value); +static_assert (!is_same<decltype (0.0q), float128_t>::value); +static_assert (!is_same<decltype (0.0Q), float128_t>::value); +static_assert (!is_same<decltype (0.0f128), __float128>::value); +static_assert (!is_same<decltype (0.0F128), __float128>::value); +#endif +#endif +#ifdef __STDCPP_BFLOAT16_T__ +static_assert (!is_same<float, bfloat16_t>::value); +static_assert (!is_same<double, bfloat16_t>::value); +static_assert (!is_same<long double, bfloat16_t>::value); +static_assert (is_same<decltype (0.0bf16), bfloat16_t>::value); +static_assert (is_same<decltype (0.0BF16), bfloat16_t>::value); +static_assert (is_same<decltype (0.0bf16 + 0.0bf16), bfloat16_t>::value); +static_assert (is_same<decltype (0.0BF16 + 0.0BF16), bfloat16_t>::value); +#endif +#ifdef __FLT32X_MANT_DIG__ +static_assert (!is_same<float, _Float32x>::value); +static_assert (!is_same<double, _Float32x>::value); +static_assert (!is_same<long double, _Float32x>::value); +static_assert (!is_same<decltype (0.0f), _Float32x>::value); +static_assert (!is_same<decltype (0.0F), _Float32x>::value); +static_assert (is_same<decltype (0.0f32x), _Float32x>::value); +static_assert (is_same<decltype (0.0F32x), _Float32x>::value); +static_assert (!is_same<decltype (0.0f32x), float>::value); +static_assert (!is_same<decltype (0.0F32x), float>::value); +static_assert (is_same<decltype (0.0f32x + 0.0f32x), _Float32x>::value); +static_assert (is_same<decltype (0.0F32x + 0.0F32x), _Float32x>::value); +#ifdef __STDCPP_FLOAT16_T__ +static_assert (!is_same<float16_t, _Float32x>::value); +static_assert (!is_same<decltype (0.0f16), _Float32x>::value); +static_assert (!is_same<decltype (0.0F16), _Float32x>::value); +static_assert (!is_same<decltype (0.0f32x), float16_t>::value); +static_assert (!is_same<decltype (0.0F32x), float16_t>::value); +#endif +#ifdef __STDCPP_FLOAT32_T__ +static_assert (!is_same<float32_t, _Float32x>::value); +static_assert (!is_same<decltype (0.0f32), _Float32x>::value); +static_assert (!is_same<decltype (0.0F32), _Float32x>::value); +static_assert (!is_same<decltype (0.0f32x), float32_t>::value); +static_assert (!is_same<decltype (0.0F32x), float32_t>::value); +#endif +#ifdef __STDCPP_FLOAT64_T__ +static_assert (!is_same<float64_t, _Float32x>::value); +static_assert (!is_same<decltype (0.0f64), _Float32x>::value); +static_assert (!is_same<decltype (0.0F64), _Float32x>::value); +static_assert (!is_same<decltype (0.0f32x), float64_t>::value); +static_assert (!is_same<decltype (0.0F32x), float64_t>::value); +#endif +#ifdef __STDCPP_FLOAT128_T__ +static_assert (!is_same<float128_t, _Float32x>::value); +static_assert (!is_same<decltype (0.0f128), _Float32x>::value); +static_assert (!is_same<decltype (0.0F128), _Float32x>::value); +static_assert (!is_same<decltype (0.0f32x), float128_t>::value); +static_assert (!is_same<decltype (0.0F32x), float128_t>::value); +#endif +#endif +#ifdef __FLT64X_MANT_DIG__ +static_assert (!is_same<float, _Float64x>::value); +static_assert (!is_same<double, _Float64x>::value); +static_assert (!is_same<long double, _Float64x>::value); +static_assert (!is_same<decltype (0.0), _Float64x>::value); +static_assert (is_same<decltype (0.0f64x), _Float64x>::value); +static_assert (is_same<decltype (0.0F64x), _Float64x>::value); +static_assert (!is_same<decltype (0.0f64x), double>::value); +static_assert (!is_same<decltype (0.0F64x), double>::value); +static_assert (is_same<decltype (0.0f64x + 0.0f64x), _Float64x>::value); +static_assert (is_same<decltype (0.0F64x + 0.0F64x), _Float64x>::value); +#ifdef __STDCPP_FLOAT16_T__ +static_assert (!is_same<float16_t, _Float64x>::value); +static_assert (!is_same<decltype (0.0f16), _Float64x>::value); +static_assert (!is_same<decltype (0.0F16), _Float64x>::value); +static_assert (!is_same<decltype (0.0f64x), float16_t>::value); +static_assert (!is_same<decltype (0.0F64x), float16_t>::value); +#endif +#ifdef __STDCPP_FLOAT32_T__ +static_assert (!is_same<float32_t, _Float64x>::value); +static_assert (!is_same<decltype (0.0f32), _Float64x>::value); +static_assert (!is_same<decltype (0.0F32), _Float64x>::value); +static_assert (!is_same<decltype (0.0f64x), float32_t>::value); +static_assert (!is_same<decltype (0.0F64x), float32_t>::value); +#endif +#ifdef __STDCPP_FLOAT64_T__ +static_assert (!is_same<float64_t, _Float64x>::value); +static_assert (!is_same<decltype (0.0f64), _Float64x>::value); +static_assert (!is_same<decltype (0.0F64), _Float64x>::value); +static_assert (!is_same<decltype (0.0f64x), float64_t>::value); +static_assert (!is_same<decltype (0.0F64x), float64_t>::value); +#endif +#ifdef __STDCPP_FLOAT128_T__ +static_assert (!is_same<float128_t, _Float64x>::value); +static_assert (!is_same<decltype (0.0f128), _Float64x>::value); +static_assert (!is_same<decltype (0.0F128), _Float64x>::value); +static_assert (!is_same<decltype (0.0f64x), float128_t>::value); +static_assert (!is_same<decltype (0.0F64x), float128_t>::value); +#endif +#ifdef __SIZEOF_FLOAT128__ +static_assert (!is_same<_Float64x, __float128>::value); +static_assert (!is_same<decltype (0.0q), _Float64x>::value); +static_assert (!is_same<decltype (0.0Q), _Float64x>::value); +static_assert (!is_same<decltype (0.0f64x), __float128>::value); +static_assert (!is_same<decltype (0.0F64x), __float128>::value); +#endif +#endif +#ifdef __FLT128X_MANT_DIG__ +static_assert (!is_same<float, _Float128x>::value); +static_assert (!is_same<double, _Float128x>::value); +static_assert (!is_same<long double, _Float128x>::value); +static_assert (!is_same<decltype (0.0l), _Float128x>::value); +static_assert (!is_same<decltype (0.0L), _Float128x>::value); +static_assert (is_same<decltype (0.0f128x), _Float128x>::value); +static_assert (is_same<decltype (0.0F128x), _Float128x>::value); +static_assert (!is_same<decltype (0.0f128x), long double>::value); +static_assert (!is_same<decltype (0.0F128x), long double>::value); +static_assert (is_same<decltype (0.0f128x + 0.0f128x), _Float128x>::value); +static_assert (is_same<decltype (0.0F128x + 0.0F128x), _Float128x>::value); +#ifdef __STDCPP_FLOAT16_T__ +static_assert (!is_same<float16_t, _Float128x>::value); +static_assert (!is_same<decltype (0.0f16), _Float128x>::value); +static_assert (!is_same<decltype (0.0F16), _Float128x>::value); +static_assert (!is_same<decltype (0.0f128x), float16_t>::value); +static_assert (!is_same<decltype (0.0F128x), float16_t>::value); +#endif +#ifdef __STDCPP_FLOAT32_T__ +static_assert (!is_same<float32_t, _Float128x>::value); +static_assert (!is_same<decltype (0.0f32), _Float128x>::value); +static_assert (!is_same<decltype (0.0F32), _Float128x>::value); +static_assert (!is_same<decltype (0.0f128x), float32_t>::value); +static_assert (!is_same<decltype (0.0F128x), float32_t>::value); +#endif +#ifdef __STDCPP_FLOAT64_T__ +static_assert (!is_same<float64_t, _Float128x>::value); +static_assert (!is_same<decltype (0.0f64), _Float128x>::value); +static_assert (!is_same<decltype (0.0F64), _Float128x>::value); +static_assert (!is_same<decltype (0.0f128x), float64_t>::value); +static_assert (!is_same<decltype (0.0F128x), float64_t>::value); +#endif +#ifdef __STDCPP_FLOAT128_T__ +static_assert (!is_same<float128_t, _Float128x>::value); +static_assert (!is_same<decltype (0.0f128), _Float128x>::value); +static_assert (!is_same<decltype (0.0F128), _Float128x>::value); +static_assert (!is_same<decltype (0.0f128x), float128_t>::value); +static_assert (!is_same<decltype (0.0F128x), float128_t>::value); +#endif +#ifdef __SIZEOF_FLOAT128__ +static_assert (!is_same<_Float128x, __float128>::value); +static_assert (!is_same<decltype (0.0q), _Float128x>::value); +static_assert (!is_same<decltype (0.0Q), _Float128x>::value); +static_assert (!is_same<decltype (0.0f128x), __float128>::value); +static_assert (!is_same<decltype (0.0F128x), __float128>::value); +#endif +#endif +static_assert (is_same<decltype (0.0f + 0.0), double>::value); +static_assert (is_same<decltype (0.0 + 0.0F), double>::value); +static_assert (is_same<decltype (0.0L + 0.0), long double>::value); +static_assert (is_same<decltype (0.0 + 0.0L), long double>::value); +static_assert (is_same<decltype (0.0L + 0.0f), long double>::value); +static_assert (is_same<decltype (0.0F + 0.0l), long double>::value); +#if defined(__STDCPP_FLOAT16_T__) && defined(__STDCPP_FLOAT32_T__) +static_assert (!is_same<float16_t, float32_t>::value); +static_assert (is_same<decltype (0.0f16 + 0.0f32), float32_t>::value); +static_assert (is_same<decltype (0.0F32 + 0.0F16), float32_t>::value); +#endif +#if defined(__STDCPP_FLOAT16_T__) && defined(__STDCPP_FLOAT64_T__) +static_assert (!is_same<float16_t, float64_t>::value); +static_assert (is_same<decltype (0.0f16 + 0.0f64), float64_t>::value); +static_assert (is_same<decltype (0.0F64 + 0.0F16), float64_t>::value); +#endif +#if defined(__STDCPP_FLOAT16_T__) && defined(__STDCPP_FLOAT128_T__) +static_assert (!is_same<float16_t, float128_t>::value); +static_assert (is_same<decltype (0.0f16 + 0.0f128), float128_t>::value); +static_assert (is_same<decltype (0.0F128 + 0.0F16), float128_t>::value); +#endif +#if defined(__STDCPP_FLOAT16_T__) && defined(__FLT32X_MANT_DIG__) +static_assert (is_same<decltype (0.0f16 + 0.0f32x), _Float32x>::value); +static_assert (is_same<decltype (0.0F32x + 0.0F16), _Float32x>::value); +#endif +#if defined(__STDCPP_FLOAT16_T__) && defined(__FLT64X_MANT_DIG__) +static_assert (is_same<decltype (0.0f16 + 0.0f64x), _Float64x>::value); +static_assert (is_same<decltype (0.0F64x + 0.0F16), _Float64x>::value); +#endif +#if defined(__STDCPP_FLOAT16_T__) && defined(__FLT128X_MANT_DIG__) +static_assert (is_same<decltype (0.0f16 + 0.0f128x), _Float128x>::value); +static_assert (is_same<decltype (0.0F128x + 0.0F16), _Float128x>::value); +#endif +#if defined(__STDCPP_FLOAT32_T__) && defined(__STDCPP_FLOAT64_T__) +static_assert (!is_same<float32_t, float64_t>::value); +static_assert (is_same<decltype (0.0f32 + 0.0f64), float64_t>::value); +static_assert (is_same<decltype (0.0F64 + 0.0F32), float64_t>::value); +#endif +#if defined(__STDCPP_FLOAT32_T__) && defined(__STDCPP_FLOAT128_T__) +static_assert (!is_same<float32_t, float128_t>::value); +static_assert (is_same<decltype (0.0f32 + 0.0f128), float128_t>::value); +static_assert (is_same<decltype (0.0F128 + 0.0F32), float128_t>::value); +#endif +#if defined(__STDCPP_FLOAT32_T__) && defined(__FLT32X_MANT_DIG__) +static_assert (is_same<decltype (0.0f32 + 0.0f32x), _Float32x>::value); +static_assert (is_same<decltype (0.0F32x + 0.0F32), _Float32x>::value); +#endif +#if defined(__STDCPP_FLOAT32_T__) && defined(__FLT64X_MANT_DIG__) +static_assert (is_same<decltype (0.0f32 + 0.0f64x), _Float64x>::value); +static_assert (is_same<decltype (0.0F64x + 0.0F32), _Float64x>::value); +#endif +#if defined(__STDCPP_FLOAT32_T__) && defined(__FLT128X_MANT_DIG__) +static_assert (is_same<decltype (0.0f32 + 0.0f128x), _Float128x>::value); +static_assert (is_same<decltype (0.0F128x + 0.0F32), _Float128x>::value); +#endif +#if defined(__STDCPP_FLOAT64_T__) && defined(__STDCPP_FLOAT128_T__) +static_assert (!is_same<float64_t, float128_t>::value); +static_assert (is_same<decltype (0.0f64 + 0.0f128), float128_t>::value); +static_assert (is_same<decltype (0.0F128 + 0.0F64), float128_t>::value); +#endif +#if defined(__STDCPP_FLOAT64_T__) && defined(__FLT32X_MANT_DIG__) \ + && __FLT64_MAX_EXP__ == __FLT32X_MAX_EXP__ \ + && __FLT64_MANT_DIG__ == __FLT32X_MANT_DIG__ +static_assert (is_same<decltype (0.0f64 + 0.0f32x), float64_t>::value); +static_assert (is_same<decltype (0.0F32x + 0.0F64), float64_t>::value); +#endif +#if defined(__STDCPP_FLOAT64_T__) && defined(__FLT64X_MANT_DIG__) +static_assert (is_same<decltype (0.0f64 + 0.0f64x), _Float64x>::value); +static_assert (is_same<decltype (0.0F64x + 0.0F64), _Float64x>::value); +#endif +#if defined(__STDCPP_FLOAT64_T__) && defined(__FLT128X_MANT_DIG__) +static_assert (is_same<decltype (0.0f64 + 0.0f128x), _Float128x>::value); +static_assert (is_same<decltype (0.0F128x + 0.0F64), _Float128x>::value); +#endif +#if defined(__STDCPP_FLOAT128_T__) && defined(__FLT32X_MANT_DIG__) \ + && __FLT128_MAX_EXP__ >= __FLT32X_MAX_EXP__ \ + && __FLT128_MANT_DIG__ >= __FLT32X_MANT_DIG__ +static_assert (is_same<decltype (0.0f128 + 0.0f32x), float128_t>::value); +static_assert (is_same<decltype (0.0F32x + 0.0F128), float128_t>::value); +#endif +#if defined(__STDCPP_FLOAT128_T__) && defined(__FLT64X_MANT_DIG__) \ + && __FLT128_MAX_EXP__ >= __FLT64X_MAX_EXP__ \ + && __FLT128_MANT_DIG__ >= __FLT64X_MANT_DIG__ +static_assert (is_same<decltype (0.0f128 + 0.0f64x), float128_t>::value); +static_assert (is_same<decltype (0.0F64x + 0.0F128), float128_t>::value); +#endif +#if defined(__STDCPP_FLOAT128_T__) && defined(__FLT128X_MANT_DIG__) +static_assert (is_same<decltype (0.0f128 + 0.0f128x), _Float128>::value); +static_assert (is_same<decltype (0.0F128x + 0.0F128), _Float128>::value); +#endif +#if defined(__STDCPP_BFLOAT16_T__) && defined(__STDCPP_FLOAT32_T__) +static_assert (!is_same<bfloat16_t, float32_t>::value); +static_assert (is_same<decltype (0.0bf16 + 0.0f32), float32_t>::value); +static_assert (is_same<decltype (0.0F32 + 0.0BF16), float32_t>::value); +#endif +#if defined(__STDCPP_BFLOAT16_T__) && defined(__STDCPP_FLOAT64_T__) +static_assert (!is_same<bfloat16_t, float64_t>::value); +static_assert (is_same<decltype (0.0bf16 + 0.0f64), float64_t>::value); +static_assert (is_same<decltype (0.0F64 + 0.0BF16), float64_t>::value); +#endif +#if defined(__STDCPP_BFLOAT16_T__) && defined(__STDCPP_FLOAT128_T__) +static_assert (!is_same<bfloat16_t, float128_t>::value); +static_assert (is_same<decltype (0.0bf16 + 0.0f128), float128_t>::value); +static_assert (is_same<decltype (0.0F128 + 0.0BF16), float128_t>::value); +#endif +#ifdef __STDCPP_FLOAT16_T__ +#if __FLT_MAX_EXP__ > __FLT16_MAX_EXP__ && __FLT_MANT_DIG__ > __FLT16_MANT_DIG__ +static_assert (is_same<decltype (0.0f + 0.0f16), float>::value); +static_assert (is_same<decltype (0.0F16 + 0.0F), float>::value); +#endif +#if __DBL_MAX_EXP__ > __FLT16_MAX_EXP__ && __DBL_MANT_DIG__ > __FLT16_MANT_DIG__ +static_assert (is_same<decltype (0.0 + 0.0f16), double>::value); +static_assert (is_same<decltype (0.0F16 + 0.0), double>::value); +#endif +#if __LDBL_MAX_EXP__ > __FLT16_MAX_EXP__ && __LDBL_MANT_DIG__ > __FLT16_MANT_DIG__ +static_assert (is_same<decltype (0.0L + 0.0f16), long double>::value); +static_assert (is_same<decltype (0.0F16 + 0.0l), long double>::value); +#endif +#endif +#ifdef __STDCPP_FLOAT32_T__ +#if __FLT_MAX_EXP__ == __FLT32_MAX_EXP__ && __FLT_MANT_DIG__ == __FLT32_MANT_DIG__ +static_assert (is_same<decltype (0.0f + 0.0f32), float32_t>::value); +static_assert (is_same<decltype (0.0F32 + 0.0F), float32_t>::value); +#endif +#if __DBL_MAX_EXP__ > __FLT32_MAX_EXP__ && __DBL_MANT_DIG__ > __FLT32_MANT_DIG__ +static_assert (is_same<decltype (0.0 + 0.0f32), double>::value); +static_assert (is_same<decltype (0.0F32 + 0.0), double>::value); +#endif +#if __LDBL_MAX_EXP__ > __FLT32_MAX_EXP__ && __LDBL_MANT_DIG__ > __FLT32_MANT_DIG__ +static_assert (is_same<decltype (0.0L + 0.0f32), long double>::value); +static_assert (is_same<decltype (0.0F32 + 0.0l), long double>::value); +#endif +#endif +#ifdef __STDCPP_FLOAT64_T__ +#if __FLT_MAX_EXP__ < __FLT64_MAX_EXP__ && __FLT_MANT_DIG__ < __FLT64_MANT_DIG__ +static_assert (is_same<decltype (0.0f + 0.0f64), float64_t>::value); +static_assert (is_same<decltype (0.0F64 + 0.0F), float64_t>::value); +#endif +#if __DBL_MAX_EXP__ == __FLT64_MAX_EXP__ && __DBL_MANT_DIG__ == __FLT64_MANT_DIG__ +static_assert (is_same<decltype (0.0 + 0.0f64), float64_t>::value); +static_assert (is_same<decltype (0.0F64 + 0.0), float64_t>::value); +#endif +#if __LDBL_MAX_EXP__ > __FLT64_MAX_EXP__ && __LDBL_MANT_DIG__ > __FLT64_MANT_DIG__ +static_assert (is_same<decltype (0.0L + 0.0f64), long double>::value); +static_assert (is_same<decltype (0.0F64 + 0.0l), long double>::value); +#endif +#if __LDBL_MAX_EXP__ == __FLT64_MAX_EXP__ && __LDBL_MANT_DIG__ == __FLT64_MANT_DIG__ \ + && __DBL_MAX_EXP__ == __FLT64_MAX_EXP__ && __DBL_MANT_DIG__ == __FLT64_MANT_DIG__ +// An extended floating-point type with the same set of values as more than one +// cv-unqualified standard floating-point type has a rank equal to the rank of +// double. +// Then long double will have higher rank than float64_t. +static_assert (is_same<decltype (0.0L + 0.0f64), long double>::value); +static_assert (is_same<decltype (0.0F64 + 0.0l), long double>::value); +#endif +#endif +#ifdef __STDCPP_FLOAT128_T__ +#if __FLT_MAX_EXP__ < __FLT128_MAX_EXP__ && __FLT_MANT_DIG__ < __FLT128_MANT_DIG__ +static_assert (is_same<decltype (0.0f + 0.0f128), float128_t>::value); +static_assert (is_same<decltype (0.0F128 + 0.0F), float128_t>::value); +#endif +#if __DBL_MAX_EXP__ < __FLT128_MAX_EXP__ && __DBL_MANT_DIG__ < __FLT128_MANT_DIG__ +static_assert (is_same<decltype (0.0 + 0.0f128), float128_t>::value); +static_assert (is_same<decltype (0.0F128 + 0.0), float128_t>::value); +#endif +#if __LDBL_MAX_EXP__ <= __FLT128_MAX_EXP__ && __LDBL_MANT_DIG__ <= __FLT128_MANT_DIG__ \ + && __LDBL_MANT_DIG__ != 106 // IBM extended long double and IEEE quad are unordered. +static_assert (is_same<decltype (0.0L + 0.0f128), float128_t>::value); +static_assert (is_same<decltype (0.0F128 + 0.0l), float128_t>::value); +#endif +#ifdef __SIZEOF_FLOAT128__ +static_assert (is_same<decltype (0.0Q + 0.0f128), float128_t>::value); +static_assert (is_same<decltype (0.0F128 + 0.0q), float128_t>::value); +#endif +#endif +#ifdef __STDCPP_BFLOAT16_T__ +#if __FLT_MAX_EXP__ > __BFLT16_MAX_EXP__ && __FLT_MANT_DIG__ > __BFLT16_MANT_DIG__ +static_assert (is_same<decltype (0.0f + 0.0bf16), float>::value); +static_assert (is_same<decltype (0.0BF16 + 0.0F), float>::value); +#endif +#if __DBL_MAX_EXP__ > __BFLT16_MAX_EXP__ && __DBL_MANT_DIG__ > __BFLT16_MANT_DIG__ +static_assert (is_same<decltype (0.0 + 0.0bf16), double>::value); +static_assert (is_same<decltype (0.0BF16 + 0.0), double>::value); +#endif +#if __LDBL_MAX_EXP__ > __BFLT16_MAX_EXP__ && __LDBL_MANT_DIG__ > __BFLT16_MANT_DIG__ +static_assert (is_same<decltype (0.0L + 0.0bf16), long double>::value); +static_assert (is_same<decltype (0.0BF16 + 0.0l), long double>::value); +#endif +#endif + +void foo (float) {} +void foo (double) {} +void foo (long double) {} +#ifdef __STDCPP_FLOAT16_T__ +void foo (float16_t) {} +#endif +#ifdef __STDCPP_FLOAT32_T__ +void foo (float32_t) {} +#endif +#ifdef __STDCPP_FLOAT64_T__ +void foo (float64_t) {} +#endif +#ifdef __STDCPP_FLOAT128_T__ +void foo (float128_t) {} +#endif +#ifdef __STDCPP_BFLOAT16_T__ +void foo (bfloat16_t) {} +#endif +#ifdef __FLT32X_MANT_DIG__ +void foo (_Float32x) {} +#endif +#ifdef __FLT64X_MANT_DIG__ +void foo (_Float64x) {} +#endif +#ifdef __FLT128X_MANT_DIG__ +void foo (_Float128x) {} +#endif diff --git a/gcc/testsuite/g++.dg/cpp23/ext-floating10.C b/gcc/testsuite/g++.dg/cpp23/ext-floating10.C new file mode 100644 index 0000000..f5563fe --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/ext-floating10.C @@ -0,0 +1,13 @@ +// P1467R9 - Extended floating-point types and standard names. +// { dg-do run { target { c++23 && float128_runtime } } } +// { dg-options "" } +// { dg-add-options float128 } + +#ifndef WIDTH +#ifndef __STDCPP_FLOAT128_T__ +#error Unexpected +#endif +#define WIDTH 128 +#endif + +#include "ext-floating7.C" diff --git a/gcc/testsuite/g++.dg/cpp23/ext-floating2.C b/gcc/testsuite/g++.dg/cpp23/ext-floating2.C new file mode 100644 index 0000000..41e9a54 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/ext-floating2.C @@ -0,0 +1,157 @@ +// P1467R9 - Extended floating-point types and standard names. +// { dg-do compile { target c++23 } } +// { dg-options "" } + +#include "ext-floating.h" + +#ifdef __STRICT_ANSI__ +#undef __SIZEOF_FLOAT128__ +#endif + +using namespace std; + +float fa = 1.0f; +float fb = (float) 1.0f; +float fc = 1.0; +float fd = (float) 1.0; +float fe = 1.0L; +float ff = (float) 1.0L; +#ifdef __SIZEOF_FLOAT128__ +float fg = 1.0Q; +float fh = (float) 1.0Q; +#endif +double da = 1.0f; +double db = (double) 1.0f; +double dc = 1.0; +double dd = (double) 1.0; +double de = 1.0L; +double df = (double) 1.0L; +#ifdef __SIZEOF_FLOAT128__ +double dg = 1.0Q; +double dh = (double) 1.0Q; +#endif +long double lda = 1.0f; +long double ldb = (long double) 1.0f; +long double ldc = 1.0; +long double ldd = (long double) 1.0; +long double lde = 1.0L; +long double ldf = (long double) 1.0L; +#ifdef __SIZEOF_FLOAT128__ +long double ldg = 1.0Q; +long double ldh = (long double) 1.0Q; +__float128 qa = 1.0f; +__float128 qb = (__float128) 1.0f; +__float128 qc = 1.0; +__float128 qd = (__float128) 1.0; +__float128 qe = 1.0L; +__float128 qf = (__float128) 1.0L; +__float128 qg = 1.0Q; +__float128 qh = (__float128) 1.0Q; +#endif +#ifdef __STDCPP_FLOAT16_T__ +float16_t f16a = 1.0F16; +float16_t f16b = (float16_t) 1.0F16; +#ifdef __STDCPP_FLOAT32_T__ +float16_t f16c = 1.0F32; // { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from '_Float32' with greater conversion rank" "" { target { float16 && float32 } } } +float16_t f16d = (float16_t) 1.0F32; +#endif +#ifdef __STDCPP_FLOAT64_T__ +float16_t f16e = 1.0F64; // { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from '_Float64' with greater conversion rank" "" { target { float16 && float64 } } } +float16_t f16f = (float16_t) 1.0F64; +#endif +#ifdef __STDCPP_FLOAT128_T__ +float16_t f16g = 1.0F128; // { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from '_Float128' with greater conversion rank" "" { target { float16 && float128 } } } +float16_t f16h = (float16_t) 1.0F128; +#endif +float16_t f16j = (float16_t) 1.0f; +float16_t f16l = (float16_t) 1.0; +float16_t f16n = (float16_t) 1.0L; +#ifdef __SIZEOF_FLOAT128__ +float16_t f16p = (float16_t) 1.0Q; +#endif +#endif +#ifdef __STDCPP_FLOAT32_T__ +#ifdef __STDCPP_FLOAT16_T__ +float32_t f32a = 1.0F16; +float32_t f32b = (float32_t) 1.0F16; +#endif +float32_t f32c = 1.0F32; +float32_t f32d = (float32_t) 1.0F32; +#ifdef __STDCPP_FLOAT64_T__ +float32_t f32e = 1.0F64; // { dg-warning "converting to 'std::float32_t' \\\{aka '_Float32'\\\} from '_Float64' with greater conversion rank" "" { target { float32 && float64 } } } +float32_t f32f = (float32_t) 1.0F64; +#endif +#ifdef __STDCPP_FLOAT128_T__ +float32_t f32g = 1.0F128; // { dg-warning "converting to 'std::float32_t' \\\{aka '_Float32'\\\} from '_Float128' with greater conversion rank" "" { target { float32 && float128 } } } +float32_t f32h = (float32_t) 1.0F128; +#endif +#if __FLT_MAX_EXP__ <= __FLT32_MAX_EXP__ && __FLT_MANT_DIG__ <= __FLT32_MANT_DIG__ +float32_t f32i = 1.0f; +#endif +float32_t f32j = (float32_t) 1.0f; +float32_t f32l = (float32_t) 1.0; +float32_t f32n = (float32_t) 1.0L; +#ifdef __SIZEOF_FLOAT128__ +float32_t f32p = (float32_t) 1.0Q; +#endif +#endif +#ifdef __STDCPP_FLOAT64_T__ +#ifdef __STDCPP_FLOAT16_T__ +float64_t f64a = 1.0F16; +float64_t f64b = (float64_t) 1.0F16; +#endif +#ifdef __STDCPP_FLOAT32_T__ +float64_t f64c = 1.0F32; +float64_t f64d = (float64_t) 1.0F32; +#endif +float64_t f64e = 1.0F64; +float64_t f64f = (float64_t) 1.0F64; +#ifdef __STDCPP_FLOAT128_T__ +float64_t f64g = 1.0F128; // { dg-warning "converting to 'std::float64_t' \\\{aka '_Float64'\\\} from '_Float128' with greater conversion rank" "" { target { float64 && float128 } } } +float64_t f64h = (float64_t) 1.0F128; +#endif +#if __FLT_MAX_EXP__ <= __FLT64_MAX_EXP__ && __FLT_MANT_DIG__ <= __FLT64_MANT_DIG__ +float64_t f64i = 1.0f; +#endif +float64_t f64j = (float64_t) 1.0f; +#if __DBL_MAX_EXP__ <= __FLT64_MAX_EXP__ && __DBL_MANT_DIG__ <= __FLT64_MANT_DIG__ +float64_t f64k = 1.0; +#endif +float64_t f64l = (float64_t) 1.0; +float64_t f64n = (float64_t) 1.0L; +#ifdef __SIZEOF_FLOAT128__ +float64_t f64p = (float64_t) 1.0Q; +#endif +#endif +#ifdef __STDCPP_FLOAT128_T__ +#ifdef __STDCPP_FLOAT16_T__ +float128_t f128a = 1.0F16; +float128_t f128b = (float128_t) 1.0F16; +#endif +#ifdef __STDCPP_FLOAT32_T__ +float128_t f128c = 1.0F32; +float128_t f128d = (float128_t) 1.0F32; +#endif +#ifdef __STDCPP_FLOAT64_T__ +float128_t f128e = 1.0F64; +float128_t f128f = (float128_t) 1.0F64; +#endif +float128_t f128g = 1.0F128; +float128_t f128h = (float128_t) 1.0F128; +#if __FLT_MAX_EXP__ <= __FLT128_MAX_EXP__ && __FLT_MANT_DIG__ <= __FLT128_MANT_DIG__ +float128_t f128i = 1.0f; +#endif +float128_t f128j = (float128_t) 1.0f; +#if __DBL_MAX_EXP__ <= __FLT128_MAX_EXP__ && __DBL_MANT_DIG__ <= __FLT128_MANT_DIG__ +float128_t f128k = 1.0; +#endif +float128_t f128l = (float128_t) 1.0; +#if __LDBL_MAX_EXP__ <= __FLT128_MAX_EXP__ && __LDBL_MANT_DIG__ <= __FLT128_MANT_DIG__ && __LDBL_MANT_DIG__ != 106 +float128_t f128m = 1.0L; +#endif +float128_t f128n = (float128_t) 1.0L; +#ifdef __SIZEOF_FLOAT128__ +float128_t f128o = 1.0Q; +float128_t f128p = (float128_t) 1.0Q; +#endif +#endif diff --git a/gcc/testsuite/g++.dg/cpp23/ext-floating3.C b/gcc/testsuite/g++.dg/cpp23/ext-floating3.C new file mode 100644 index 0000000..ca9399f --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/ext-floating3.C @@ -0,0 +1,134 @@ +// P1467R9 - Extended floating-point types and standard names. +// Variant of ext-floating2.C test with x86 specific assumptions +// about float, double, long double and existence of __float128. +// And some further tests. +// { dg-do compile { target { c++23 && { i?86-*-linux* x86_64-*-linux* } } } } +// { dg-options "" } + +#include "ext-floating.h" + +#if !defined(__STDCPP_FLOAT32_T__) \ + || !defined(__STDCPP_FLOAT64_T__) || !defined(__STDCPP_FLOAT128_T__) \ + || __FLT_MAX_EXP__ != __FLT32_MAX_EXP__ || __FLT_MANT_DIG__ != __FLT32_MANT_DIG__ \ + || __DBL_MAX_EXP__ != __FLT64_MAX_EXP__ || __DBL_MANT_DIG__ != __FLT64_MANT_DIG__ \ + || __LDBL_MAX_EXP__ != __FLT128_MAX_EXP__ || __LDBL_MANT_DIG__ >= __FLT128_MANT_DIG__ \ + || !defined(__SIZEOF_FLOAT128__) +#error Unexpected set of floating point types +#endif + +using namespace std; + +#ifdef __STDCPP_FLOAT16_T__ +float16_t f16i = 1.0f; // { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from 'float' with greater conversion rank" "" { target float16 } } +float16_t f16k = 1.0; // { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from 'double' with greater conversion rank" "" { target float16 } } +float16_t f16m = 1.0L; // { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from 'long double' with greater conversion rank" "" { target float16 } } +float16_t f16o = 1.0Q; // { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from '__float128' with greater conversion rank" "" { target float16 } } +#endif +float32_t f32i = 1.0f; +float32_t f32k = 1.0; // { dg-warning "converting to 'std::float32_t' \\\{aka '_Float32'\\\} from 'double' with greater conversion rank" } +float32_t f32m = 1.0L; // { dg-warning "converting to 'std::float32_t' \\\{aka '_Float32'\\\} from 'long double' with greater conversion rank" } +float32_t f32o = 1.0Q; // { dg-warning "converting to 'std::float32_t' \\\{aka '_Float32'\\\} from '__float128' with greater conversion rank" } +float64_t f64i = 1.0f; +float64_t f64k = 1.0; +float64_t f64m = 1.0L; // { dg-warning "converting to 'std::float64_t' \\\{aka '_Float64'\\\} from 'long double' with greater conversion rank" } +float64_t f64o = 1.0Q; // { dg-warning "converting to 'std::float64_t' \\\{aka '_Float64'\\\} from '__float128' with greater conversion rank" } +float128_t f128i = 1.0f; +float128_t f128k = 1.0; +float128_t f128m = 1.0L; +float128_t f128o = 1.0Q; + +#ifdef __STDCPP_FLOAT16_T__ +constexpr float16_t f16x = 1.0F16; +#endif +constexpr float32_t f32x = 2.0F32; +constexpr float64_t f64x = 3.0F64; +constexpr float128_t f128x = 4.0F128; +constexpr float fx = 5.0f; +constexpr double dx = 6.0; +constexpr long double ldx = 7.0L; + +constexpr int foo (float32_t) { return 1; } +constexpr int foo (float64_t) { return 2; } +constexpr int bar (float) { return 3; } +constexpr int bar (double) { return 4; } +constexpr int bar (long double) { return 5; } +constexpr int baz (float32_t) { return 6; } +constexpr int baz (float64_t) { return 7; } +constexpr int baz (float128_t) { return 8; } +constexpr int qux (float64_t) { return 9; } +constexpr int qux (float32_t) { return 10; } +constexpr int fred (long double) { return 11; } +constexpr int fred (double) { return 12; } +constexpr int fred (float) { return 13; } +constexpr int thud (float128_t) { return 14; } +constexpr int thud (float64_t) { return 15; } +constexpr int thud (float32_t) { return 16; } +struct S { + constexpr operator float32_t () const { return 1.0f32; } + constexpr operator float64_t () const { return 2.0f64; } +}; +struct T { + constexpr operator float64_t () const { return 3.0f64; } + constexpr operator float32_t () const { return 4.0f32; } +}; + +void +test (S s, T t) +{ +#ifdef __STDCPP_FLOAT16_T__ + foo (float16_t (1.0)); // { dg-error "call of overloaded 'foo\\\(std::float16_t\\\)' is ambiguous" "" { target float16 } } +#endif + static_assert (foo (float (2.0)) == 1); + static_assert (foo (double (3.0)) == 2); + constexpr double x (s); + static_assert (x == 2.0); +#ifdef __STDCPP_FLOAT16_T__ + bar (f16x); // { dg-error "call of overloaded 'bar\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } } +#endif + static_assert (bar (f32x) == 3); + static_assert (bar (f64x) == 4); + bar (f128x); // { dg-error "no matching function for call to 'bar\\\(const std::float128_t\\\&\\\)'" } + // { dg-warning "converting to 'float' from 'const std::float128_t' \\\{aka 'const _Float128'\\\} with greater conversion rank" "" { target *-*-* } .-1 } + // { dg-warning "converting to 'double' from 'const std::float128_t' \\\{aka 'const _Float128'\\\} with greater conversion rank" "" { target *-*-* } .-2 } + // { dg-warning "converting to 'long double' from 'const std::float128_t' \\\{aka 'const _Float128'\\\} with greater conversion rank" "" { target *-*-* } .-3 } + static_assert (bar (fx) == 3); + static_assert (bar (dx) == 4); + static_assert (bar (ldx) == 5); +#ifdef __STDCPP_FLOAT16_T__ + baz (f16x); // { dg-error "call of overloaded 'baz\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } } +#endif + static_assert (baz (f32x) == 6); + static_assert (baz (f64x) == 7); + static_assert (baz (f128x) == 8); + static_assert (baz (fx) == 6); + static_assert (baz (dx) == 7); + static_assert (baz (ldx) == 8); +#ifdef __STDCPP_FLOAT16_T__ + qux (float16_t (1.0)); // { dg-error "call of overloaded 'qux\\\(std::float16_t\\\)' is ambiguous" "" { target float16 } } +#endif + static_assert (qux (float (2.0)) == 10); + static_assert (qux (double (3.0)) == 9); + constexpr double y (t); + static_assert (y == 3.0); +#ifdef __STDCPP_FLOAT16_T__ + fred (f16x); // { dg-error "call of overloaded 'fred\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } } +#endif + static_assert (fred (f32x) == 13); + static_assert (fred (f64x) == 12); + fred (f128x); // { dg-error "no matching function for call to 'fred\\\(const std::float128_t\\\&\\\)'" } + // { dg-warning "converting to 'float' from 'const std::float128_t' \\\{aka 'const _Float128'\\\} with greater conversion rank" "" { target *-*-* } .-1 } + // { dg-warning "converting to 'double' from 'const std::float128_t' \\\{aka 'const _Float128'\\\} with greater conversion rank" "" { target *-*-* } .-2 } + // { dg-warning "converting to 'long double' from 'const std::float128_t' \\\{aka 'const _Float128'\\\} with greater conversion rank" "" { target *-*-* } .-3 } + static_assert (fred (fx) == 13); + static_assert (fred (dx) == 12); + static_assert (fred (ldx) == 11); +#ifdef __STDCPP_FLOAT16_T__ + thud (f16x); // { dg-error "call of overloaded 'thud\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } } +#endif + static_assert (thud (f32x) == 16); + static_assert (thud (f64x) == 15); + static_assert (thud (f128x) == 14); + static_assert (thud (fx) == 16); + static_assert (thud (dx) == 15); + static_assert (thud (ldx) == 14); +} diff --git a/gcc/testsuite/g++.dg/cpp23/ext-floating4.C b/gcc/testsuite/g++.dg/cpp23/ext-floating4.C new file mode 100644 index 0000000..1bac105 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/ext-floating4.C @@ -0,0 +1,126 @@ +// P1467R9 - Extended floating-point types and standard names. +// Variant of ext-floating3.C test with different specific assumptions +// about float, double, long double. +// float, double and long double are assumed to be IEEE 754 single, double +// and quad. +// { dg-do compile { target { c++23 && { aarch64*-*-* powerpc64le*-*-linux* riscv*-*-* s390*-*-* sparc*-*-linux* } } } } +// { dg-options "" } +// { dg-additional-options "-mlong-double-128" { target s390*-*-* sparc*-*-linux* } } +// { dg-additional-options "-mvsx -mfloat128 -mlong-double-128 -mabi=ieeelongdouble -Wno-psabi" { target powerpc64le*-*-linux* } } + +#include "ext-floating.h" + +#if !defined(__STDCPP_FLOAT32_T__) \ + || !defined(__STDCPP_FLOAT64_T__) || !defined(__STDCPP_FLOAT128_T__) \ + || __FLT_MAX_EXP__ != __FLT32_MAX_EXP__ || __FLT_MANT_DIG__ != __FLT32_MANT_DIG__ \ + || __DBL_MAX_EXP__ != __FLT64_MAX_EXP__ || __DBL_MANT_DIG__ != __FLT64_MANT_DIG__ \ + || __LDBL_MAX_EXP__ != __FLT128_MAX_EXP__ || __LDBL_MANT_DIG__ != __FLT128_MANT_DIG__ +#error Unexpected set of floating point types +#endif + +using namespace std; + +#ifdef __STDCPP_FLOAT16_T__ +float16_t f16i = 1.0f; // { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from 'float' with greater conversion rank" "" { target float16 } } +float16_t f16k = 1.0; // { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from 'double' with greater conversion rank" "" { target float16 } } +float16_t f16m = 1.0L; // { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from 'long double' with greater conversion rank" "" { target float16 } } +#endif +float32_t f32i = 1.0f; +float32_t f32k = 1.0; // { dg-warning "converting to 'std::float32_t' \\\{aka '_Float32'\\\} from 'double' with greater conversion rank" } +float32_t f32m = 1.0L; // { dg-warning "converting to 'std::float32_t' \\\{aka '_Float32'\\\} from 'long double' with greater conversion rank" } +float64_t f64i = 1.0f; +float64_t f64k = 1.0; +float64_t f64m = 1.0L; // { dg-warning "converting to 'std::float64_t' \\\{aka '_Float64'\\\} from 'long double' with greater conversion rank" } +float128_t f128i = 1.0f; +float128_t f128k = 1.0; +float128_t f128m = 1.0L; + +#ifdef __STDCPP_FLOAT16_T__ +constexpr float16_t f16x = 1.0F16; +#endif +constexpr float32_t f32x = 2.0F32; +constexpr float64_t f64x = 3.0F64; +constexpr float128_t f128x = 4.0F128; +constexpr float fx = 5.0f; +constexpr double dx = 6.0; +constexpr long double ldx = 7.0L; + +constexpr int foo (float32_t) { return 1; } +constexpr int foo (float64_t) { return 2; } +constexpr int bar (float) { return 3; } +constexpr int bar (double) { return 4; } +constexpr int bar (long double) { return 5; } +constexpr int baz (float32_t) { return 6; } +constexpr int baz (float64_t) { return 7; } +constexpr int baz (float128_t) { return 8; } +constexpr int qux (float64_t) { return 9; } +constexpr int qux (float32_t) { return 10; } +constexpr int fred (long double) { return 11; } +constexpr int fred (double) { return 12; } +constexpr int fred (float) { return 13; } +constexpr int thud (float128_t) { return 14; } +constexpr int thud (float64_t) { return 15; } +constexpr int thud (float32_t) { return 16; } +struct S { + constexpr operator float32_t () const { return 1.0f32; } + constexpr operator float64_t () const { return 2.0f64; } +}; +struct T { + constexpr operator float64_t () const { return 3.0f64; } + constexpr operator float32_t () const { return 4.0f32; } +}; + +void +test (S s, T t) +{ +#ifdef __STDCPP_FLOAT16_T__ + foo (float16_t (1.0)); // { dg-error "call of overloaded 'foo\\\(std::float16_t\\\)' is ambiguous" "" { target float16 } } +#endif + static_assert (foo (float (2.0)) == 1); + static_assert (foo (double (3.0)) == 2); + constexpr double x (s); + static_assert (x == 2.0); +#ifdef __STDCPP_FLOAT16_T__ + bar (f16x); // { dg-error "call of overloaded 'bar\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } } +#endif + static_assert (bar (f32x) == 3); + static_assert (bar (f64x) == 4); + static_assert (bar (f128x) == 5); + static_assert (bar (fx) == 3); + static_assert (bar (dx) == 4); + static_assert (bar (ldx) == 5); +#ifdef __STDCPP_FLOAT16_T__ + baz (f16x); // { dg-error "call of overloaded 'baz\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } } +#endif + static_assert (baz (f32x) == 6); + static_assert (baz (f64x) == 7); + static_assert (baz (f128x) == 8); + static_assert (baz (fx) == 6); + static_assert (baz (dx) == 7); + static_assert (baz (ldx) == 8); +#ifdef __STDCPP_FLOAT16_T__ + qux (float16_t (1.0)); // { dg-error "call of overloaded 'qux\\\(std::float16_t\\\)' is ambiguous" "" { target float16 } } +#endif + static_assert (qux (float (2.0)) == 10); + static_assert (qux (double (3.0)) == 9); + constexpr double y (t); + static_assert (y == 3.0); +#ifdef __STDCPP_FLOAT16_T__ + fred (f16x); // { dg-error "call of overloaded 'fred\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } } +#endif + static_assert (fred (f32x) == 13); + static_assert (fred (f64x) == 12); + static_assert (fred (f128x) == 11); + static_assert (fred (fx) == 13); + static_assert (fred (dx) == 12); + static_assert (fred (ldx) == 11); +#ifdef __STDCPP_FLOAT16_T__ + thud (f16x); // { dg-error "call of overloaded 'thud\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } } +#endif + static_assert (thud (f32x) == 16); + static_assert (thud (f64x) == 15); + static_assert (thud (f128x) == 14); + static_assert (thud (fx) == 16); + static_assert (thud (dx) == 15); + static_assert (thud (ldx) == 14); +} diff --git a/gcc/testsuite/g++.dg/cpp23/ext-floating5.C b/gcc/testsuite/g++.dg/cpp23/ext-floating5.C new file mode 100644 index 0000000..7c8bf6a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/ext-floating5.C @@ -0,0 +1,13 @@ +// P1467R9 - Extended floating-point types and standard names. +// IBM extended long double and _Float128 should have unordered conversion +// ranks as IBM extended long double has variable precision from 53 bits +// for denormals to more than 2150 bits for certain numbers. +// { dg-do compile { target { c++23 && { powerpc*-*-linux* } } } } +// { dg-require-effective-target ppc_float128_sw } +// { dg-options "-mvsx -mfloat128 -mlong-double-128 -mabi=ibmlongdouble" } + +auto a = 1.0F128 + 1.0L; // { dg-error "invalid operands to binary \\\+ \\\(have '_Float128' and 'long double'\\\)" } +auto b = 1.0L + 1.0F128; // { dg-error "invalid operands to binary \\\+ \\\(have 'long double' and '_Float128'\\\)" } +bool c; +auto d = c ? 1.0F128 : 1.0L; // { dg-error "operands to '\\\?:' of types '_Float128' and 'long double' have unordered conversion rank" } +auto e = c ? 1.0L : 1.0F128; // { dg-error "operands to '\\\?:' of types 'long double' and '_Float128' have unordered conversion rank" } diff --git a/gcc/testsuite/g++.dg/cpp23/ext-floating6.C b/gcc/testsuite/g++.dg/cpp23/ext-floating6.C new file mode 100644 index 0000000..70272a1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/ext-floating6.C @@ -0,0 +1,30 @@ +// P1467R9 - Extended floating-point types and standard names. +// { dg-do compile { target c++23 } } +// { dg-options "" } + +#include "ext-floating.h" + +#ifdef __STRICT_ANSI__ +#undef __SIZEOF_FLOAT128__ +#endif + +using namespace std; + +float foo (float x, float y, float z) { return x * y + z; } +double foo (double x, double y, double z) { return x * y + z; } +long double foo (long double x, long double y, long double z) { return x * y + z; } +#ifdef __STDCPP_FLOAT16_T__ +float16_t foo (float16_t x, float16_t y, float16_t z) { return x * y + z; } +#endif +#ifdef __STDCPP_FLOAT32_T__ +float32_t foo (float32_t x, float32_t y, float32_t z) { return x * y + z; } +#endif +#ifdef __STDCPP_FLOAT64_T__ +float64_t foo (float64_t x, float64_t y, float64_t z) { return x * y + z; } +#endif +#ifdef __STDCPP_FLOAT128_T__ +float128_t foo (float128_t x, float128_t y, float128_t z) { return x * y + z; } +#endif +#ifdef __STDCPP_BFLOAT16_T__ +bfloat16_t foo (bfloat16_t x, bfloat16_t y, bfloat16_t z) { return x * y + z; } +#endif diff --git a/gcc/testsuite/g++.dg/cpp23/ext-floating7.C b/gcc/testsuite/g++.dg/cpp23/ext-floating7.C new file mode 100644 index 0000000..5c30a59 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/ext-floating7.C @@ -0,0 +1,119 @@ +// P1467R9 - Extended floating-point types and standard names. +// { dg-do run { target { c++23 && float16_runtime } } } +// { dg-options "" } +// { dg-add-options float16 } + +#ifndef WIDTH +#ifndef __STDCPP_FLOAT16_T__ +#error Unexpected +#endif +#define WIDTH 16 +#endif + +#include <stdarg.h> +#include "ext-floating.h" + +#define CONCATX(X, Y) X ## Y +#define CONCAT(X, Y) CONCATX (X, Y) +#define CONCAT3(X, Y, Z) CONCAT (CONCAT (X, Y), Z) +#define TYPE CONCAT (_Float, WIDTH) +#define CST(C) CONCAT3 (C, f, WIDTH) +#define CSTU(C) CONCAT3 (C, F, WIDTH) + +extern "C" void abort (); + +volatile TYPE a = CST (1.0), b = CSTU (2.5), c = -CST (2.5); +volatile TYPE a2 = CST (1.0), z = CST (0.0), nz = -CST (0.0); + +// These types are not subject to default argument promotions. + +TYPE +vafn (TYPE arg1, ...) +{ + va_list ap; + TYPE ret; + va_start (ap, arg1); + ret = arg1 + va_arg (ap, TYPE); + va_end (ap); + return ret; +} + +TYPE +fn (TYPE arg) +{ + return arg / 4; +} + +int +main (void) +{ + volatile TYPE r; + r = -b; + if (r != c) + abort (); + r = a + b; + if (r != CST (3.5)) + abort (); + r = a - b; + if (r != -CST (1.5)) + abort (); + r = 2 * c; + if (r != -5) + abort (); + r = b * c; + if (r != -CST (6.25)) + abort (); + r = b / (a + a); + if (r != CST (1.25)) + abort (); + r = c * 3; + if (r != -CST (7.5)) + abort (); + volatile int i = r; + if (i != -7) + abort (); + r = vafn (a, c); + if (r != -CST (1.5)) + abort (); + r = fn (a); + if (r != CST (0.25)) + abort (); + if ((a < b) != 1) + abort (); + if ((b < a) != 0) + abort (); + if ((a < a2) != 0) + abort (); + if ((nz < z) != 0) + abort (); + if ((a <= b) != 1) + abort (); + if ((b <= a) != 0) + abort (); + if ((a <= a2) != 1) + abort (); + if ((nz <= z) != 1) + abort (); + if ((a > b) != 0) + abort (); + if ((b > a) != 1) + abort (); + if ((a > a2) != 0) + abort (); + if ((nz > z) != 0) + abort (); + if ((a >= b) != 0) + abort (); + if ((b >= a) != 1) + abort (); + if ((a >= a2) != 1) + abort (); + if ((nz >= z) != 1) + abort (); + i = (nz == z); + if (i != 1) + abort (); + i = (a == b); + if (i != 0) + abort (); +} diff --git a/gcc/testsuite/g++.dg/cpp23/ext-floating8.C b/gcc/testsuite/g++.dg/cpp23/ext-floating8.C new file mode 100644 index 0000000..afb74a3 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/ext-floating8.C @@ -0,0 +1,13 @@ +// P1467R9 - Extended floating-point types and standard names. +// { dg-do run { target { c++23 && float32_runtime } } } +// { dg-options "" } +// { dg-add-options float32 } + +#ifndef WIDTH +#ifndef __STDCPP_FLOAT32_T__ +#error Unexpected +#endif +#define WIDTH 32 +#endif + +#include "ext-floating7.C" diff --git a/gcc/testsuite/g++.dg/cpp23/ext-floating9.C b/gcc/testsuite/g++.dg/cpp23/ext-floating9.C new file mode 100644 index 0000000..f0118da --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/ext-floating9.C @@ -0,0 +1,13 @@ +// P1467R9 - Extended floating-point types and standard names. +// { dg-do run { target { c++23 && float64_runtime } } } +// { dg-options "" } +// { dg-add-options float64 } + +#ifndef WIDTH +#ifndef __STDCPP_FLOAT64_T__ +#error Unexpected +#endif +#define WIDTH 64 +#endif + +#include "ext-floating7.C" diff --git a/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C b/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C index d3e4072..2f6b21e 100644 --- a/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C +++ b/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C @@ -504,8 +504,8 @@ #ifndef __cpp_char8_t # error "__cpp_char8_t" -#elif __cpp_char8_t != 201811 -# error "__cpp_char8_t != 201811" +#elif __cpp_char8_t != 202207 +# error "__cpp_char8_t != 202207" #endif #ifndef __cpp_designated_initializers @@ -563,3 +563,9 @@ #elif __cpp_named_character_escapes != 202207 # error "__cpp_named_character_escapes != 202207" #endif + +#ifndef __cpp_static_call_operator +# error "__cpp_static_call_operator" +#elif __cpp_static_call_operator != 202207 +# error "__cpp_static_call_operator != 202207" +#endif diff --git a/gcc/testsuite/g++.dg/cpp23/static-operator-call1.C b/gcc/testsuite/g++.dg/cpp23/static-operator-call1.C new file mode 100644 index 0000000..42219bf --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/static-operator-call1.C @@ -0,0 +1,41 @@ +// P1169R4 - static operator() +// { dg-do compile { target c++11 } } +// { dg-options "" } + +template <typename T> +struct S +{ + static constexpr bool operator () (T const &x, T const &y) { return x < y; }; // { dg-warning "may be a static member function only with" "" { target c++20_down } } + using P = bool (*) (T const &, T const &); + operator P () const { return operator (); } +}; + +static_assert (S<int> {} (1, 2), ""); + +template <typename T> +void +bar (T &x) +{ + x (1, 2); +} + +void +foo () +{ +#if __cpp_constexpr >= 201603L + auto a = [](int x, int y) static constexpr { return x + y; }; // { dg-warning "'static' only valid in lambda with" "" { target { c++17 && c++20_down } } } + static_assert (a (1, 2) == 3, ""); + bar (*a); +#endif + auto b = []() static { return 1; }; // { dg-warning "'static' only valid in lambda with" "" { target c++20_down } } + b (); + auto c = [](int x, int y) static { return x + y; }; // { dg-warning "'static' only valid in lambda with" "" { target c++20_down } } + c (1, 2); + bar (*c); +#if __cpp_generic_lambdas >= 201707L + auto d = []<typename T, typename U>(T x, U y) static { return x + y; }; // { dg-warning "'static' only valid in lambda with" "" { target c++20_only } } + d (1, 2L); +#endif + S<long> s; + s(1L, 2L); +} diff --git a/gcc/testsuite/g++.dg/cpp23/static-operator-call2.C b/gcc/testsuite/g++.dg/cpp23/static-operator-call2.C new file mode 100644 index 0000000..21f3d44 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/static-operator-call2.C @@ -0,0 +1,22 @@ +// P1169R4 - static operator() +// { dg-do compile { target c++11 } } +// { dg-options "" } + +void +foo () +{ + int u = 0; + auto a = [](int x, int y) mutable mutable { return x + y; }; // { dg-error "duplicate 'mutable' specifier" } + auto b = [](int x, int y) static static { return x + y; }; // { dg-error "duplicate 'static' specifier" } + // { dg-warning "'static' only valid in lambda with" "" { target c++20_down } .-1 } + auto c = [](int x, int y) static mutable { return x + y; }; // { dg-error "'mutable' specifier conflicts with 'static'" } + // { dg-warning "'static' only valid in lambda with" "" { target c++20_down } .-1 } + auto d = [](int x, int y) mutable static { return x + y; }; // { dg-error "'static' specifier conflicts with 'mutable'" } + // { dg-warning "'static' only valid in lambda with" "" { target c++20_down } .-1 } + auto e = [=](int x, int y) static { return x + y; }; // { dg-error "lambda specifier with lambda capture" } + // { dg-warning "'static' only valid in lambda with" "" { target c++20_down } .-1 } + auto f = [&](int x, int y) static { return x + y; }; // { dg-error "lambda specifier with lambda capture" } + // { dg-warning "'static' only valid in lambda with" "" { target c++20_down } .-1 } + auto g = [u](int x, int y) static { return x + y; }; // { dg-error "lambda specifier with lambda capture" } + // { dg-warning "'static' only valid in lambda with" "" { target c++20_down } .-1 } +} diff --git a/gcc/testsuite/g++.dg/cpp23/static-operator-call3.C b/gcc/testsuite/g++.dg/cpp23/static-operator-call3.C new file mode 100644 index 0000000..9c84db6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/static-operator-call3.C @@ -0,0 +1,10 @@ +// P1169R4 - static operator() +// { dg-do compile { target c++14 } } +// { dg-options "" } + +void +foo () +{ + auto a = [] (auto x) static { return x; }; // { dg-warning "'static' only valid in lambda with" "" { target c++20_down } } + int (*b) (int) = a; +} diff --git a/gcc/testsuite/g++.dg/cpp2a/char8_t3.C b/gcc/testsuite/g++.dg/cpp2a/char8_t3.C new file mode 100644 index 0000000..071a718 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/char8_t3.C @@ -0,0 +1,37 @@ +// PR c++/106656 - P2513 - char8_t Compatibility and Portability Fixes +// { dg-do compile { target c++20 } } + +const char *p1 = u8""; // { dg-error "invalid conversion" } +const unsigned char *p2 = u8""; // { dg-error "invalid conversion" } +const signed char *p3 = u8""; // { dg-error "invalid conversion" } +const char *p4 = { u8"" }; // { dg-error "invalid conversion" } +const unsigned char *p5 = { u8"" }; // { dg-error "invalid conversion" } +const signed char *p6 = { u8"" }; // { dg-error "invalid conversion" } +const char *p7 = static_cast<const char *>(u8""); // { dg-error "invalid" } +const char a1[] = u8"text"; +const unsigned char a2[] = u8""; +const signed char a3[] = u8""; // { dg-error "cannot initialize array" } +const char a4[] = { u8"text" }; +const unsigned char a5[] = { u8"" }; +const signed char a6[] = { u8"" }; // { dg-error "cannot initialize array" } + +const char * +resource_id () +{ + static const char res_id[] = u8""; + return res_id; +} + +const char8_t x[] = "fail"; // { dg-error "cannot initialize array" } + +void fn (const char a[]); +void +g () +{ + fn (u8"z"); // { dg-error "invalid conversion" } +} + +char c = u8'c'; +unsigned char uc = u8'c'; +signed char sc = u8'c'; +char8_t c8 = 'c'; diff --git a/gcc/testsuite/g++.dg/cpp2a/char8_t4.C b/gcc/testsuite/g++.dg/cpp2a/char8_t4.C new file mode 100644 index 0000000..c18081b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/char8_t4.C @@ -0,0 +1,17 @@ +// PR c++/106656 - P2513 - char8_t Compatibility and Portability Fixes +// { dg-do compile { target c++20 } } +// [diff.cpp20.dcl] + +struct A { + char8_t s[10]; +}; +struct B { + char s[10]; +}; + +void f(A); +void f(B); + +int main() { + f({u8""}); // { dg-error "ambiguous" } +} diff --git a/gcc/testsuite/g++.dg/cpp2a/constinit3.C b/gcc/testsuite/g++.dg/cpp2a/constinit3.C index a29c594..ffa6184 100644 --- a/gcc/testsuite/g++.dg/cpp2a/constinit3.C +++ b/gcc/testsuite/g++.dg/cpp2a/constinit3.C @@ -5,7 +5,7 @@ constinit constinit int v1; // { dg-error "duplicate .constinit." } constexpr constinit int v2 = 1; // { dg-error "can use at most one of the .constinit. and .constexpr. specifiers" } constinit constexpr int v3 = 1; // { dg-error "an use at most one of the .constinit. and .constexpr. specifiers" } -extern static constinit int v4; // { dg-error "conflicting specifiers" } +extern static constinit int v4; // { dg-error "'static' specifier conflicts with 'extern'" } extern thread_local constinit int v5; extern constinit int v6; diff --git a/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C b/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C index c65ea6b..02f3a37 100644 --- a/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C +++ b/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C @@ -504,8 +504,8 @@ #ifndef __cpp_char8_t # error "__cpp_char8_t" -#elif __cpp_char8_t != 201811 -# error "__cpp_char8_t != 201811" +#elif __cpp_char8_t != 202207 +# error "__cpp_char8_t != 202207" #endif #ifndef __cpp_designated_initializers diff --git a/gcc/testsuite/g++.dg/diagnostic/conflicting-specifiers-1.C b/gcc/testsuite/g++.dg/diagnostic/conflicting-specifiers-1.C index 1a8ac02..89e2ebd 100644 --- a/gcc/testsuite/g++.dg/diagnostic/conflicting-specifiers-1.C +++ b/gcc/testsuite/g++.dg/diagnostic/conflicting-specifiers-1.C @@ -1 +1 @@ -static typedef int i __attribute__((unused)); // { dg-error "1:conflicting specifiers" } +static typedef int i __attribute__((unused)); // { dg-error "8:'typedef' specifier conflicts with 'static'" } diff --git a/gcc/testsuite/g++.dg/ext/char8_t-feature-test-macro-2.C b/gcc/testsuite/g++.dg/ext/char8_t-feature-test-macro-2.C index df1063f..2d0f904 100644 --- a/gcc/testsuite/g++.dg/ext/char8_t-feature-test-macro-2.C +++ b/gcc/testsuite/g++.dg/ext/char8_t-feature-test-macro-2.C @@ -5,6 +5,6 @@ #if !defined(__cpp_char8_t) # error __cpp_char8_t is not defined! -#elif __cpp_char8_t != 201811 -# error __cpp_char8_t != 201811 +#elif __cpp_char8_t != 202207 +# error __cpp_char8_t != 202207 #endif diff --git a/gcc/testsuite/g++.dg/ext/char8_t-init-2.C b/gcc/testsuite/g++.dg/ext/char8_t-init-2.C index c713bc1..02a96ff 100644 --- a/gcc/testsuite/g++.dg/ext/char8_t-init-2.C +++ b/gcc/testsuite/g++.dg/ext/char8_t-init-2.C @@ -21,7 +21,7 @@ const char8_t (&rca4)[2] = u8"x"; const char8_t (&rca5)[2] = u"x"; // { dg-error "invalid initialization of reference of type .const char8_t ....... from expression of type .const char16_t ...." "char8_t" } char ca1[] = "x"; -char ca2[] = u8"x"; // { dg-error "from a string literal with type array of .char8_t." "char8_t" } +char ca2[] = u8"x"; char8_t ca3[] = "x"; // { dg-error "from a string literal with type array of .char." "char8_t" } char8_t ca4[] = u8"x"; char8_t ca5[] = u"x"; // { dg-error "from a string literal with type array of .char16_t." "char8_t" } @@ -30,4 +30,4 @@ signed char sca1[] = "x"; signed char sca2[] = u8"x"; // { dg-error "from a string literal with type array of .char8_t." "char8_t" } unsigned char uca1[] = "x"; -unsigned char uca2[] = u8"x"; // { dg-error "from a string literal with type array of .char8_t." "char8_t" } +unsigned char uca2[] = u8"x"; diff --git a/gcc/testsuite/g++.dg/ext/is_convertible3.C b/gcc/testsuite/g++.dg/ext/is_convertible3.C new file mode 100644 index 0000000..7a986d0 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/is_convertible3.C @@ -0,0 +1,9 @@ +// PR c++/106784 +// { dg-do compile { target c++11 } } +// Make sure we don't reject this at runtime by trying to instantiate +// something that would be ill-formed. + +struct A; +struct B { template<class T> B(const T&) noexcept { T::nonexistent; } }; + +static_assert(__is_convertible(const A&, B), ""); diff --git a/gcc/testsuite/g++.dg/ext/is_nothrow_convertible3.C b/gcc/testsuite/g++.dg/ext/is_nothrow_convertible3.C new file mode 100644 index 0000000..05b1e1d --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/is_nothrow_convertible3.C @@ -0,0 +1,9 @@ +// PR c++/106784 +// { dg-do compile { target c++11 } } +// Make sure we don't reject this at runtime by trying to instantiate +// something that would be ill-formed. + +struct A; +struct B { template<class T> B(const T&) noexcept { T::nonexistent; } }; + +static_assert(__is_nothrow_convertible(const A&, B), ""); diff --git a/gcc/testsuite/g++.dg/gomp/attrs-1.C b/gcc/testsuite/g++.dg/gomp/attrs-1.C index 3f366ae..dd33b07 100644 --- a/gcc/testsuite/g++.dg/gomp/attrs-1.C +++ b/gcc/testsuite/g++.dg/gomp/attrs-1.C @@ -123,7 +123,7 @@ baz (int d, int m, int i1, int i2, int p, int *idp, int s, void bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int hda, int s, int nte, int tl, int nth, int g, int nta, int fi, int pp, int *q, int *dd, int ntm, - const char *msg) + const char *msg, int n1, int n2) { [[omp::directive (nothing)]]; [[omp::directive (error at (execution) severity (warning) message (msg))]]; @@ -612,6 +612,19 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int hda, int s, ; [[omp::directive (parallel)]] switch (0) { case 1: break; default: break; } + [[omp::directive (assume no_openmp no_openmp_routines no_parallelism + absent (atomic, barrier, cancel, cancellation point) + absent (critical, depobj) + absent (distribute, flush, loop, masked, master, nothing, ordered) + absent (parallel, scan, scope, section, sections, simd, single, task) + absent (taskgroup, taskloop, taskwait, taskyield) + absent (target, teams, for, error) holds (n1 < n2))]] + if (0) + ; + [[omp::sequence (omp::directive (assume contains (simd)), + omp::directive (for simd))]] + for (int i = 0; i < 64; i++) + ; } void corge1 (); diff --git a/gcc/testsuite/g++.dg/gomp/attrs-15.C b/gcc/testsuite/g++.dg/gomp/attrs-15.C new file mode 100644 index 0000000..d0598f4 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/attrs-15.C @@ -0,0 +1,41 @@ +// { dg-do compile { target c++11 } } + +#pragma omp begin assumes absent (target) +#pragma omp begin assumes absent (target) +[[omp::directive (begin assumes absent (target))]]; +int a; +[[omp::directive (end assumes)]]; +#pragma omp end assumes +#pragma omp end assumes +[[omp::directive (begin assumes absent (target))]]; +int b; +#pragma omp end assumes // { dg-error "'begin assumes' in attribute syntax terminated with 'end assumes' in pragma syntax" } +#pragma omp begin assumes absent (target) +int c; +[[omp::directive (end assumes)]];// { dg-error "'begin assumes' in pragma syntax terminated with 'end assumes' in attribute syntax" } +#pragma omp begin assumes absent (target) +[[omp::directive (begin assumes absent (target))]]; +int d; +#pragma omp end assumes // { dg-error "'begin assumes' in attribute syntax terminated with 'end assumes' in pragma syntax" } +#pragma omp begin assumes absent (target) +int e; +[[omp::directive (end assumes)]];// { dg-error "'begin assumes' in pragma syntax terminated with 'end assumes' in attribute syntax" } +#pragma omp end assumes +[[omp::directive (begin assumes absent (target))]]; +[[omp::directive (begin assumes absent (target))]]; +int f; +#pragma omp end assumes // { dg-error "'begin assumes' in attribute syntax terminated with 'end assumes' in pragma syntax" } +#pragma omp begin assumes absent (target) +int g; +[[omp::directive (end assumes)]];// { dg-error "'begin assumes' in pragma syntax terminated with 'end assumes' in attribute syntax" } +[[omp::directive (end assumes)]]; +[[omp::directive (begin assumes absent (target))]]; +#pragma omp begin assumes absent (target) +int h; +#pragma omp end assumes +#pragma omp end assumes // { dg-error "'begin assumes' in attribute syntax terminated with 'end assumes' in pragma syntax" } +#pragma omp begin assumes absent (target) +[[omp::directive (begin assumes absent (target))]]; +int i; +[[omp::directive (end assumes)]]; +[[omp::directive (end assumes)]];// { dg-error "'begin assumes' in pragma syntax terminated with 'end assumes' in attribute syntax" } diff --git a/gcc/testsuite/g++.dg/gomp/attrs-16.C b/gcc/testsuite/g++.dg/gomp/attrs-16.C new file mode 100644 index 0000000..5c1dcc5 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/attrs-16.C @@ -0,0 +1,26 @@ +// { dg-do compile { target c++11 } } + +int i; + +[[omp::directive (assumes no_openmp, absent (target, teams) holds (i < 32U) holds (i < 32U))]]; +void +bar (void) +{ +} + +[[omp::directive (assumes no_openmp_routines)]]; +[[omp::directive (assumes no_parallelism)]]; +[[omp::directive (assumes absent (for))]]; +void +fred (void) +{ +} + +[[omp::directive (assumes absent (atomic, barrier, cancel, cancellation point) absent (critical, depobj) + absent (distribute, flush, loop, masked, master, nothing, ordered) + absent (parallel, scan, scope, section, sections, simd, single, task) + absent (taskgroup, taskloop, taskwait, taskyield))]]; +void +foo (void) +{ +} diff --git a/gcc/testsuite/g++.dg/gomp/attrs-17.C b/gcc/testsuite/g++.dg/gomp/attrs-17.C new file mode 100644 index 0000000..fe36146 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/attrs-17.C @@ -0,0 +1,17 @@ +// { dg-do compile { target c++11 } } + +[[omp::directive (assumes contains (simd))]]; +[[omp::directive (assumes contains (error))]]; +[[omp::directive (assumes, contains (simd))]]; + +void +foo (int i, int *a) +{ + [[omp::directive (simd)]] + for (int j = 0; j < i; j++) + a[j] = j; + if (i >= 32) + { + [[omp::directive (error at (execution) message ("Should not happen"))]]; + } +} diff --git a/gcc/testsuite/g++.dg/gomp/attrs-2.C b/gcc/testsuite/g++.dg/gomp/attrs-2.C index cb80415..7258d38 100644 --- a/gcc/testsuite/g++.dg/gomp/attrs-2.C +++ b/gcc/testsuite/g++.dg/gomp/attrs-2.C @@ -123,7 +123,7 @@ baz (int d, int m, int i1, int i2, int p, int *idp, int s, void bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int hda, int s, int nte, int tl, int nth, int g, int nta, int fi, int pp, int *q, int *dd, int ntm, - const char *msg) + const char *msg, int n1, int n2) { [[omp::directive (nothing)]]; [[omp::directive (error, at (execution), severity (warning), message (msg))]]; @@ -604,6 +604,19 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int hda, int s, extern int t2; [[omp::directive (declare reduction (dr: int: omp_out += omp_in),initializer (omp_priv = 0))]] ; + [[omp::directive (assume, no_openmp, no_openmp_routines, no_parallelism, + absent (atomic, barrier, cancel, cancellation point), + absent (critical, depobj), + absent (distribute, flush, loop, masked, master, nothing, ordered), + absent (parallel, scan, scope, section, sections, simd, single, task), + absent (taskgroup, taskloop, taskwait, taskyield), + absent (target, teams, for, error), holds (n1 < n2))]] + if (0) + ; + [[omp::sequence (omp::directive (assume, contains (simd)), + omp::directive (for simd))]] + for (int i = 0; i < 64; i++) + ; } void corge1 (); diff --git a/gcc/testsuite/g++.dg/gomp/attrs-9.C b/gcc/testsuite/g++.dg/gomp/attrs-9.C index 19a3b0a..fa02299 100644 --- a/gcc/testsuite/g++.dg/gomp/attrs-9.C +++ b/gcc/testsuite/g++.dg/gomp/attrs-9.C @@ -1,5 +1,6 @@ // { dg-do compile { target c++11 } } +int n1 = 0, n2 = 42; [[omp::sequence (directive (requires, atomic_default_mem_order (seq_cst)))]]; [[omp::directive (declare reduction (plus: int: omp_out += omp_in) initializer (omp_priv = 0))]]; int a; @@ -14,3 +15,22 @@ int d; [[omp::directive (end declare target)]]; [[omp::directive (end declare target)]]; [[omp::directive (nothing)]]; +[[omp::directive (begin assumes no_openmp no_openmp_routines no_parallelism + absent (atomic, barrier, cancel, cancellation point) + absent (critical, depobj) + absent (distribute, flush, loop, masked, master, nothing, ordered) + absent (parallel, scan, scope, section, sections, simd, single, task) + absent (taskgroup, taskloop, taskwait, taskyield) + absent (target, teams, for, error) holds (n1 < n2))]]; +void foo (void) {} +[[omp::directive (end assumes)]]; +[[omp::directive (begin assumes, no_openmp, no_openmp_routines, no_parallelism, + absent (atomic, barrier, cancel, cancellation point), + absent (critical, depobj), + absent (distribute, flush, loop, masked, master, nothing, ordered), + absent (parallel, scan, scope, section, sections, simd, single, task), + absent (taskgroup, taskloop, taskwait, taskyield), + absent (target, teams, for, error), holds (n1 < n2))]]; +[[omp::directive (begin assumes no_openmp)]]; +void bar (void) {} +[[omp::sequence (omp::directive (end assumes), omp::directive (end assumes))]]; diff --git a/gcc/testsuite/g++.dg/modules/partial-2.cc b/gcc/testsuite/g++.dg/modules/partial-2.cc new file mode 100644 index 0000000..1316bf5 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/partial-2.cc @@ -0,0 +1,17 @@ +static_assert(is_reference_v<int&>); +static_assert(is_reference_v<int&&>); +static_assert(!is_reference_v<int>); + +static_assert(A::is_reference_v<long&>); +static_assert(A::is_reference_v<long&&>); +static_assert(!A::is_reference_v<long>); + +#if __cpp_concepts +static_assert(concepts::is_reference_v<char&>); +static_assert(concepts::is_reference_v<char&&>); +static_assert(!concepts::is_reference_v<char>); + +static_assert(concepts::A::is_reference_v<bool&>); +static_assert(concepts::A::is_reference_v<bool&&>); +static_assert(!concepts::A::is_reference_v<bool>); +#endif diff --git a/gcc/testsuite/g++.dg/modules/partial-2.h b/gcc/testsuite/g++.dg/modules/partial-2.h new file mode 100644 index 0000000..afcfce7 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/partial-2.h @@ -0,0 +1,38 @@ +template<class T> constexpr bool is_reference_v = false; +template<class T> constexpr bool is_reference_v<T&> = true; +template<class T> constexpr bool is_reference_v<T&&> = true; + +struct A { + template<class T> static constexpr bool is_reference_v = false; +}; + +template<class T> constexpr bool A::is_reference_v<T&> = true; +template<class T> constexpr bool A::is_reference_v<T&&> = true; + +#if __cpp_concepts +namespace concepts { + template<class T> bool is_reference_v; + + template<class T> requires __is_same(T, T&) + constexpr bool is_reference_v<T> = true; + + template<class T> requires __is_same(T, T&&) && (!__is_same(T, T&)) + constexpr bool is_reference_v<T> = true; + + template<class T> requires (!__is_same(T, T&)) && (!__is_same(T, T&&)) + constexpr bool is_reference_v<T> = false; + + struct A { + template<class T> static bool is_reference_v; + }; + + template<class T> requires __is_same(T, T&) + constexpr bool A::is_reference_v<T> = true; + + template<class T> requires __is_same(T, T&&) && (!__is_same(T, T&)) + constexpr bool A::is_reference_v<T> = true; + + template<class T> requires (!__is_same(T, T&)) && (!__is_same(T, T&&)) + constexpr bool A::is_reference_v<T> = false; +} +#endif diff --git a/gcc/testsuite/g++.dg/modules/partial-2_a.C b/gcc/testsuite/g++.dg/modules/partial-2_a.C index 2681bb5..1582f56 100644 --- a/gcc/testsuite/g++.dg/modules/partial-2_a.C +++ b/gcc/testsuite/g++.dg/modules/partial-2_a.C @@ -3,41 +3,4 @@ // { dg-module-cmi pr106826 } export module pr106826; -template<class T> constexpr bool is_reference_v = false; -template<class T> constexpr bool is_reference_v<T&> = true; -template<class T> constexpr bool is_reference_v<T&&> = true; - -struct A { - template<class T> static constexpr bool is_reference_v = false; -}; - -template<class T> constexpr bool A::is_reference_v<T&> = true; -template<class T> constexpr bool A::is_reference_v<T&&> = true; - -#if __cpp_concepts -namespace concepts { - template<class T> bool is_reference_v; - - template<class T> requires __is_same(T, T&) - constexpr bool is_reference_v<T> = true; - - template<class T> requires __is_same(T, T&&) && (!__is_same(T, T&)) - constexpr bool is_reference_v<T> = true; - - template<class T> requires (!__is_same(T, T&)) && (!__is_same(T, T&&)) - constexpr bool is_reference_v<T> = false; - - struct A { - template<class T> static bool is_reference_v; - }; - - template<class T> requires __is_same(T, T&) - constexpr bool A::is_reference_v<T> = true; - - template<class T> requires __is_same(T, T&&) && (!__is_same(T, T&)) - constexpr bool A::is_reference_v<T> = true; - - template<class T> requires (!__is_same(T, T&)) && (!__is_same(T, T&&)) - constexpr bool A::is_reference_v<T> = false; -} -#endif +#include "partial-2.h" diff --git a/gcc/testsuite/g++.dg/modules/partial-2_b.C b/gcc/testsuite/g++.dg/modules/partial-2_b.C index 0af41ef..1b0c7a5 100644 --- a/gcc/testsuite/g++.dg/modules/partial-2_b.C +++ b/gcc/testsuite/g++.dg/modules/partial-2_b.C @@ -2,20 +2,4 @@ // { dg-additional-options -fmodules-ts } module pr106826; -static_assert(is_reference_v<int&>); -static_assert(is_reference_v<int&&>); -static_assert(!is_reference_v<int>); - -static_assert(A::is_reference_v<long&>); -static_assert(A::is_reference_v<long&&>); -static_assert(!A::is_reference_v<long>); - -#if __cpp_concepts -static_assert(concepts::is_reference_v<char&>); -static_assert(concepts::is_reference_v<char&&>); -static_assert(!concepts::is_reference_v<char>); - -static_assert(concepts::A::is_reference_v<bool&>); -static_assert(concepts::A::is_reference_v<bool&&>); -static_assert(!concepts::A::is_reference_v<bool>); -#endif +#include "partial-2.cc" diff --git a/gcc/testsuite/g++.dg/modules/partial-2_c.H b/gcc/testsuite/g++.dg/modules/partial-2_c.H new file mode 100644 index 0000000..bd83852 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/partial-2_c.H @@ -0,0 +1,5 @@ +// PR c++/107033 +// { dg-additional-options -fmodule-header } +// { dg-module-cmi {} } + +#include "partial-2.h" diff --git a/gcc/testsuite/g++.dg/modules/partial-2_d.C b/gcc/testsuite/g++.dg/modules/partial-2_d.C new file mode 100644 index 0000000..ed54d3c --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/partial-2_d.C @@ -0,0 +1,8 @@ +// PR c++/107033 +// { dg-additional-options -fmodules-ts } +// { dg-module-cmi pr107033 } +export module pr107033; + +import "partial-2_c.H"; + +#include "partial-2.cc" diff --git a/gcc/testsuite/g++.dg/other/mult-stor1.C b/gcc/testsuite/g++.dg/other/mult-stor1.C index 1eaec4f1..e582b03 100644 --- a/gcc/testsuite/g++.dg/other/mult-stor1.C +++ b/gcc/testsuite/g++.dg/other/mult-stor1.C @@ -4,5 +4,5 @@ struct A { - extern static int i; // { dg-error "conflicting specifiers" } + extern static int i; // { dg-error "'static' specifier conflicts with 'extern'" } }; diff --git a/gcc/testsuite/g++.dg/parse/crash39.C b/gcc/testsuite/g++.dg/parse/crash39.C index 2f39c10..5d4e02d 100644 --- a/gcc/testsuite/g++.dg/parse/crash39.C +++ b/gcc/testsuite/g++.dg/parse/crash39.C @@ -1,3 +1,3 @@ // PR c++/31747 -static extern int i; // { dg-error "conflicting specifiers" } +static extern int i; // { dg-error "'extern' specifier conflicts with 'static'" } diff --git a/gcc/testsuite/g++.dg/parse/typedef8.C b/gcc/testsuite/g++.dg/parse/typedef8.C index 60b8f39..e21bdb9 100644 --- a/gcc/testsuite/g++.dg/parse/typedef8.C +++ b/gcc/testsuite/g++.dg/parse/typedef8.C @@ -1,11 +1,11 @@ //PR c++ 29024 -typedef static int a; // { dg-error "conflicting" } -typedef register int b; // { dg-error "conflicting" } -typedef extern int c; // { dg-error "conflicting" } -static typedef int a; // { dg-error "conflicting" } +typedef static int a; // { dg-error "'static' specifier conflicts with 'typedef'" } +typedef register int b; // { dg-error "'register' specifier conflicts with 'typedef'" } +typedef extern int c; // { dg-error "'extern' specifier conflicts with 'typedef'" } +static typedef int a; // { dg-error "'typedef' specifier conflicts with 'static'" } void foo() { - typedef auto int bar; // { dg-error "conflicting|two or more data types" } + typedef auto int bar; // { dg-error "'auto' specifier conflicts with 'typedef'|two or more data types" } } diff --git a/gcc/testsuite/g++.dg/template/error30.C b/gcc/testsuite/g++.dg/template/error30.C index 3a87872..5a3047c 100644 --- a/gcc/testsuite/g++.dg/template/error30.C +++ b/gcc/testsuite/g++.dg/template/error30.C @@ -2,4 +2,4 @@ template<int> struct A; -template<template<typename> class B> A<B<int>::x> operator() (); // { dg-error "51:.A<B<int>::x> operator\\(\\)\\(\\). must be a non-static member function" } +template<template<typename> class B> A<B<int>::x> operator() (); // { dg-error "51:.A<B<int>::x> operator\\(\\)\\(\\). must be a member function" } diff --git a/gcc/testsuite/g++.dg/torture/pr107029.C b/gcc/testsuite/g++.dg/torture/pr107029.C new file mode 100644 index 0000000..93c7f28 --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/pr107029.C @@ -0,0 +1,19 @@ +// PR tree-optimization/107029 +// { dg-do compile } + +struct S { long long a; int b; }; +long long S::*a; +int S::*b; +struct A { void foo (bool, bool); void bar (); int c; }; + +void +A::foo (bool a, bool b) +{ + c = a || b; +} + +void +A::bar() +{ + foo (a, b); +} diff --git a/gcc/testsuite/g++.old-deja/g++.jason/operator.C b/gcc/testsuite/g++.old-deja/g++.jason/operator.C index 79c1932..c187901 100644 --- a/gcc/testsuite/g++.old-deja/g++.jason/operator.C +++ b/gcc/testsuite/g++.old-deja/g++.jason/operator.C @@ -6,7 +6,7 @@ typedef __SIZE_TYPE__ size_t; struct A { int operator?:(int a, int b); // { dg-error "prohibits overloading" } - static int operator()(int a); // { dg-error "14:.static int A::operator\\(\\)\\(int\\). must be a non-static member function" } + static int operator()(int a); // { dg-warning "14:.static int A::operator\\(\\)\\(int\\). may be a static member function only with" "" { target c++20_down } } static int operator+(A,A); // { dg-error "14:.static int A::operator\\+\\(A, A\\). must be either a non-static member function or a non-member function" } int operator+(int a, int b = 1); // { dg-error "7:.int A::operator\\+\\(int, int\\). must have either zero or one argument" } int operator++(char); // { dg-error "7:postfix .int A::operator\\+\\+\\(char\\). must have .int. as its argument" } diff --git a/gcc/testsuite/g++.target/i386/float16-1.C b/gcc/testsuite/g++.target/i386/float16-1.C index 95d1ac2..f96b932 100644 --- a/gcc/testsuite/g++.target/i386/float16-1.C +++ b/gcc/testsuite/g++.target/i386/float16-1.C @@ -1,8 +1,8 @@ /* { dg-do compile } */ /* { dg-options "-O2 -mno-sse2" } */ -_Float16/* { dg-error "does not name a type" } */ +_Float16 /* { dg-error "expected unqualified-id before '_Float16'" } */ foo (_Float16 x) { return x; -} +} /* { dg-error "'_Float16' is not supported on this target" } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/popcount6.c b/gcc/testsuite/gcc.dg/tree-ssa/popcount6.c new file mode 100644 index 0000000..1406ad9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/popcount6.c @@ -0,0 +1,12 @@ +// { dg-do compile } +// { dg-options "-O2 -fdump-tree-evrp" } + +int g(int n) +{ + n &= 0x8000; + if (n == 0) + return 1; + return __builtin_popcount(n); +} + +// { dg-final { scan-tree-dump "return 1;" "evrp" } } diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr107009.c b/gcc/testsuite/gcc.dg/tree-ssa/pr107009.c new file mode 100644 index 0000000..5010aed --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr107009.c @@ -0,0 +1,15 @@ +// { dg-do compile } +// { dg-options "-O2 -fdump-tree-dom2-alias" } + +typedef __SIZE_TYPE__ size_t; + +void saxpy(size_t n) +{ + if (n == 0 || n % 8 != 0) + __builtin_unreachable(); + + extern void foobar (size_t n); + foobar (n); +} + +// { dg-final { scan-tree-dump "NONZERO.*fff8" "dom2" } } diff --git a/gcc/testsuite/gcc.target/i386/avx256-unaligned-store-3.c b/gcc/testsuite/gcc.target/i386/avx256-unaligned-store-3.c index f909099..67635fb 100644 --- a/gcc/testsuite/gcc.target/i386/avx256-unaligned-store-3.c +++ b/gcc/testsuite/gcc.target/i386/avx256-unaligned-store-3.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O3 -dp -mavx -mavx256-split-unaligned-store -mtune=generic -fno-common" } */ +/* { dg-options "-O3 -dp -mavx -mavx256-split-unaligned-store -mtune=generic -fno-common -mno-avx512f" } */ #define N 1024 diff --git a/gcc/testsuite/gcc.target/i386/pr53346-1.c b/gcc/testsuite/gcc.target/i386/pr53346-1.c new file mode 100644 index 0000000..6d230da --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr53346-1.c @@ -0,0 +1,70 @@ +/* { dg-do compile } */ +/* { dg-options "-msse2 -O2 -mno-sse3" } */ +/* { dg-final { scan-assembler-times "shufps" 15 } } */ +/* { dg-final { scan-assembler-times "pshufd" 2 } } */ + +typedef int v4si __attribute__((vector_size(16))); + +v4si +__attribute__((noipa)) +foo (v4si a, v4si b) +{ + return __builtin_shufflevector (a, b, 1, 2, 5, 3); +} + +v4si +__attribute__((noipa)) +foo1 (v4si a, v4si b) +{ + return __builtin_shufflevector (a, b, 1, 5, 2, 3); +} + +v4si +__attribute__((noipa)) +foo2 (v4si a, v4si b) +{ + return __builtin_shufflevector (a, b, 1, 2, 3, 5); +} + +v4si +__attribute__((noipa)) +foo3 (v4si a, v4si b) +{ + return __builtin_shufflevector (a, b, 1, 4, 5, 6); +} + +v4si +__attribute__((noipa)) +foo4 (v4si a, v4si b) +{ + return __builtin_shufflevector (a, b, 3, 6, 7, 5); +} + +v4si +__attribute__((noipa)) +foo5 (v4si a, v4si b) +{ + return __builtin_shufflevector (a, b, 2, 4, 7, 6); +} + +v4si +__attribute__((noipa)) +foo6 (v4si a, v4si b) +{ + return __builtin_shufflevector (a, b, 2, 4, 3, 6); +} + +v4si +__attribute__((noipa)) +foo7 (v4si a, v4si b) +{ + return __builtin_shufflevector (a, b, 2, 3, 4, 6); +} + +v4si +__attribute__((noipa)) +foo8 (v4si a, v4si b) +{ + return __builtin_shufflevector (a, b, 2, 4, 6, 3); +} + diff --git a/gcc/testsuite/gcc.target/i386/pr53346-2.c b/gcc/testsuite/gcc.target/i386/pr53346-2.c new file mode 100644 index 0000000..0c6c7b3 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr53346-2.c @@ -0,0 +1,59 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -msse2" } */ +/* { dg-require-effective-target sse2 } */ + +#include "sse2-check.h" +#include "pr53346-1.c" + +static void +sse2_test () +{ + v4si a = __extension__(v4si) { 0, 1, 2, 3 }; + v4si b = __extension__(v4si) { 4, 5, 6, 7 }; + v4si exp = __extension__(v4si) { 1, 2, 5, 3 }; + v4si dest; + dest = foo (a, b); + if (__builtin_memcmp (&dest, &exp, 16)) + __builtin_abort (); + + exp = __extension__ (v4si) { 1, 5, 2, 3 }; + dest = foo1 (a, b); + if (__builtin_memcmp (&dest, &exp, 16)) + __builtin_abort (); + + exp = __extension__ (v4si) { 1, 2, 3, 5 }; + dest = foo2 (a, b); + if (__builtin_memcmp (&dest, &exp, 16)) + __builtin_abort (); + + exp = __extension__ (v4si) { 1, 4, 5, 6 }; + dest = foo3 (a, b); + if (__builtin_memcmp (&dest, &exp, 16)) + __builtin_abort (); + + exp = __extension__ (v4si) { 3, 6, 7, 5 }; + dest = foo4 (a, b); + if (__builtin_memcmp (&dest, &exp, 16)) + __builtin_abort (); + + exp = __extension__ (v4si) { 2, 4, 7, 6 }; + dest = foo5 (a, b); + if (__builtin_memcmp (&dest, &exp, 16)) + __builtin_abort (); + + exp = __extension__ (v4si) { 2, 4, 3, 6 }; + dest = foo6 (a, b); + if (__builtin_memcmp (&dest, &exp, 16)) + __builtin_abort (); + + exp = __extension__ (v4si) { 2, 3, 4, 6 }; + dest = foo7 (a, b); + if (__builtin_memcmp (&dest, &exp, 16)) + __builtin_abort (); + + exp = __extension__ (v4si) { 2, 4, 6, 3 }; + dest = foo8 (a, b); + if (__builtin_memcmp (&dest, &exp, 16)) + __builtin_abort (); + +} diff --git a/gcc/testsuite/gcc.target/i386/pr53346-3.c b/gcc/testsuite/gcc.target/i386/pr53346-3.c new file mode 100644 index 0000000..0b204f6 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr53346-3.c @@ -0,0 +1,69 @@ +/* { dg-do compile } */ +/* { dg-options "-msse2 -O2 -mno-sse3" } */ +/* { dg-final { scan-assembler-times "shufps" 17 } } */ + +typedef float v4sf __attribute__((vector_size(16))); + +v4sf +__attribute__((noipa)) +foo (v4sf a, v4sf b) +{ + return __builtin_shufflevector (a, b, 1, 2, 5, 3); +} + +v4sf +__attribute__((noipa)) +foo1 (v4sf a, v4sf b) +{ + return __builtin_shufflevector (a, b, 1, 5, 2, 3); +} + +v4sf +__attribute__((noipa)) +foo2 (v4sf a, v4sf b) +{ + return __builtin_shufflevector (a, b, 1, 2, 3, 5); +} + +v4sf +__attribute__((noipa)) +foo3 (v4sf a, v4sf b) +{ + return __builtin_shufflevector (a, b, 1, 4, 5, 6); +} + +v4sf +__attribute__((noipa)) +foo4 (v4sf a, v4sf b) +{ + return __builtin_shufflevector (a, b, 3, 6, 7, 5); +} + +v4sf +__attribute__((noipa)) +foo5 (v4sf a, v4sf b) +{ + return __builtin_shufflevector (a, b, 2, 4, 7, 6); +} + +v4sf +__attribute__((noipa)) +foo6 (v4sf a, v4sf b) +{ + return __builtin_shufflevector (a, b, 2, 4, 3, 6); +} + +v4sf +__attribute__((noipa)) +foo7 (v4sf a, v4sf b) +{ + return __builtin_shufflevector (a, b, 2, 3, 4, 6); +} + +v4sf +__attribute__((noipa)) +foo8 (v4sf a, v4sf b) +{ + return __builtin_shufflevector (a, b, 2, 4, 6, 3); +} + diff --git a/gcc/testsuite/gcc.target/i386/pr53346-4.c b/gcc/testsuite/gcc.target/i386/pr53346-4.c new file mode 100644 index 0000000..9e4e45b --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr53346-4.c @@ -0,0 +1,59 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -msse2" } */ +/* { dg-require-effective-target sse2 } */ + +#include "sse2-check.h" +#include "pr53346-3.c" + +static void +sse2_test () +{ + v4sf a = __extension__(v4sf) { 0, 1, 2, 3 }; + v4sf b = __extension__(v4sf) { 4, 5, 6, 7 }; + v4sf exp = __extension__(v4sf) { 1, 2, 5, 3 }; + v4sf dest; + dest = foo (a, b); + if (__builtin_memcmp (&dest, &exp, 16)) + __builtin_abort (); + + exp = __extension__ (v4sf) { 1, 5, 2, 3 }; + dest = foo1 (a, b); + if (__builtin_memcmp (&dest, &exp, 16)) + __builtin_abort (); + + exp = __extension__ (v4sf) { 1, 2, 3, 5 }; + dest = foo2 (a, b); + if (__builtin_memcmp (&dest, &exp, 16)) + __builtin_abort (); + + exp = __extension__ (v4sf) { 1, 4, 5, 6 }; + dest = foo3 (a, b); + if (__builtin_memcmp (&dest, &exp, 16)) + __builtin_abort (); + + exp = __extension__ (v4sf) { 3, 6, 7, 5 }; + dest = foo4 (a, b); + if (__builtin_memcmp (&dest, &exp, 16)) + __builtin_abort (); + + exp = __extension__ (v4sf) { 2, 4, 7, 6 }; + dest = foo5 (a, b); + if (__builtin_memcmp (&dest, &exp, 16)) + __builtin_abort (); + + exp = __extension__ (v4sf) { 2, 4, 3, 6 }; + dest = foo6 (a, b); + if (__builtin_memcmp (&dest, &exp, 16)) + __builtin_abort (); + + exp = __extension__ (v4sf) { 2, 3, 4, 6 }; + dest = foo7 (a, b); + if (__builtin_memcmp (&dest, &exp, 16)) + __builtin_abort (); + + exp = __extension__ (v4sf) { 2, 4, 6, 3 }; + dest = foo8 (a, b); + if (__builtin_memcmp (&dest, &exp, 16)) + __builtin_abort (); + +} diff --git a/gcc/testsuite/gcc.target/powerpc/pr100645.c b/gcc/testsuite/gcc.target/powerpc/pr100645.c new file mode 100644 index 0000000..c4e92cc --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/pr100645.c @@ -0,0 +1,13 @@ +/* { dg-require-effective-target powerpc_altivec_ok } */ +/* { dg-options "-mdejagnu-cpu=power6 -maltivec" } */ + +/* This used to ICE. */ + +typedef long long v2di __attribute__ ((vector_size (16))); + +v2di +foo_v2di_l (v2di x) +{ + return __builtin_shuffle ((v2di){0, 0}, x, (v2di){3, 0}); +} + diff --git a/gcc/testsuite/gcc.target/powerpc/pr96072.c b/gcc/testsuite/gcc.target/powerpc/pr96072.c new file mode 100644 index 0000000..10341c9 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/pr96072.c @@ -0,0 +1,14 @@ +/* { dg-options "-O2" } */ + +/* This used to ICE with the SYSV ABI (PR96072). */ + +void +he (int jn) +{ + { + int bh[jn]; + if (jn != 0) + goto wa; + } +wa:; +} diff --git a/gcc/testsuite/gcc.target/riscv/ret-1.c b/gcc/testsuite/gcc.target/riscv/ret-1.c new file mode 100644 index 0000000..28133aa --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/ret-1.c @@ -0,0 +1,41 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -dp" } */ +/* This was extracted from coremark. */ + + +typedef signed short ee_s16; +typedef struct list_data_s +{ + ee_s16 data16; + ee_s16 idx; +} list_data; + +typedef struct list_head_s +{ + struct list_head_s *next; + struct list_data_s *info; +} list_head; + + +list_head * +core_list_find(list_head *list, list_data *info) +{ + if (info->idx >= 0) + { + while (list && (list->info->idx != info->idx)) + list = list->next; + return list; + } + else + { + while (list && ((list->info->data16 & 0xff) != info->data16)) + list = list->next; + return list; + } +} + +/* There is only one legitimate unconditional jump, so test for that, + which will catch the case where bb-reorder leaves a jump to a ret + in the IL. */ +/* { dg-final { scan-assembler-times "jump" 1 } } */ + diff --git a/gcc/testsuite/gdc.test/compilable/commontype.d b/gcc/testsuite/gdc.test/compilable/commontype.d index 076e29b..abe956c 100644 --- a/gcc/testsuite/gdc.test/compilable/commontype.d +++ b/gcc/testsuite/gdc.test/compilable/commontype.d @@ -151,19 +151,19 @@ static assert(Error!( uint*, int* )); static assert(is( X!( int function(), int function() ) == int function() )); // void pointer -static assert(is( X!( void*, int* ) == int* )); -static assert(is( X!( int*, void* ) == int* )); -static assert(is( X!( const(int)*, void* ) == const(int)* )); -static assert(is( X!( const(int*), void* ) == const(int*) )); -static assert(is( X!( int*, const(void)* ) == int* )); // `const` -static assert(is( X!( int*, const(void*) ) == int* )); // `const` -static assert(is( X!( int*, shared(void*) ) == int* )); // should fail -static assert(is( X!( int*, shared(void)* ) == int* )); // should fail +static assert(is( X!( void*, int* ) == void* )); +static assert(is( X!( int*, void* ) == void* )); +static assert(is( X!( const(int)*, void* ) == void* )); +static assert(is( X!( const(int*), void* ) == void* )); +static assert(is( X!( int*, const(void)* ) == const(void)* )); // `const` +static assert(is( X!( int*, const(void*) ) == const(void*) )); // `const` +static assert(is( X!( int*, shared(void*) ) == shared(void*) )); // should fail +static assert(is( X!( int*, shared(void)* ) == shared(void)* )); // should fail static assert(Error!( int**, void** )); // should work -static assert(is( X!( void*, int function() ) == int function() )); -static assert(is( X!( immutable(void*), int function() ) == int function() )); // `const` +static assert(is( X!( void*, int function() ) == void* )); +static assert(is( X!( immutable(void*), int function() ) == immutable(void*) )); // `const` // implicit conversion static assert(is( X!( int*, const(int*) ) == const(int*) )); diff --git a/gcc/testsuite/gdc.test/compilable/imports/cimports2a.i b/gcc/testsuite/gdc.test/compilable/imports/cimports2a.i new file mode 100644 index 0000000..c8ff976 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/cimports2a.i @@ -0,0 +1,4 @@ +extern int xx; + +typedef struct Foo *FooRef; +FooRef make_foo(void); diff --git a/gcc/testsuite/gdc.test/compilable/imports/cimports2b.i b/gcc/testsuite/gdc.test/compilable/imports/cimports2b.i new file mode 100644 index 0000000..03b22b2 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/cimports2b.i @@ -0,0 +1,4 @@ +extern int xx; + +typedef struct Foo *FooRef; +void free_foo(FooRef foo); diff --git a/gcc/testsuite/gdc.test/compilable/imports/format23327.d b/gcc/testsuite/gdc.test/compilable/imports/format23327.d new file mode 100644 index 0000000..de9b957 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/format23327.d @@ -0,0 +1,7 @@ +module imports.format23327; + +import imports.format23327.write; + +immutable(string) format23327() { } + +import imports.format23327.internal.write; diff --git a/gcc/testsuite/gdc.test/compilable/imports/format23327/write.d b/gcc/testsuite/gdc.test/compilable/imports/format23327/write.d new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/format23327/write.d diff --git a/gcc/testsuite/gdc.test/compilable/segfaultgolf.d b/gcc/testsuite/gdc.test/compilable/segfaultgolf.d new file mode 100644 index 0000000..2ea125f --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/segfaultgolf.d @@ -0,0 +1,50 @@ +// https://issues.dlang.org/show_bug.cgi?id=23351 +enum strings = +[ +"a[(b).", +"[(a)(b).", +"a(={@.()(", +"a[b,[(c).", +"a[b#([(c).", +"[a@b[(c).", +"[((a).", +"[a)b[(c).", +"a[b)[(c).", +"a(b[(c).", +"a[b()c[(d).", +"a[(b[(c).", +"a(b[(c).", +"[(@@a b[(c).", +"a[(!b)c[(d).", +"[(^a)b[(c).", +"a(b[(c).", +"~[a.b[(c).", +"[a).[(b c d(e[(f).", +"[((a).", +"[a}b[(c).", +"a[b[c..(d).", +"[1a.[(b).", +"a[({in){,", +"a[^in(b[c=])S....,", +"a[({in[({)){," +]; +template KidNamedFinger(T) +{ + +} +void dummy() +{ + static foreach(str; strings) + { + /* + The above strings are all gibberish, they should + fail to parse but not segfault the compiler. + */ + { + enum exp = __traits(compiles, mixin(str)); + static assert(!exp); + enum t = __traits(compiles, KidNamedFinger!(mixin(str))); + static assert(!t); + } + } +} diff --git a/gcc/testsuite/gdc.test/compilable/statictemplatethis.d b/gcc/testsuite/gdc.test/compilable/statictemplatethis.d new file mode 100644 index 0000000..0236f2d --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/statictemplatethis.d @@ -0,0 +1,45 @@ +mixin template Constructors(){ + this(){ } + this()immutable{ } + this()shared{ } +} + +class A { +public: + static T getInstance(this T)() { + return new T(); + } +private: + mixin Constructors; +} + +class B : A { +private: + mixin Constructors; +} + +void f(){ + auto a = (new A).getInstance; + auto b = (new B).getInstance; + static assert(is(typeof(a) == A)); + static assert(is(typeof(b) == B)); + + auto ca = (new immutable A).getInstance; + auto sb = (new shared B).getInstance; + static assert(is(typeof(ca) == immutable A)); + static assert(is(typeof(sb) == shared B)); +} + +// https://issues.dlang.org/show_bug.cgi?id=10488 +version(none) +void g(){ + auto a = A.getInstance(); + auto b = B.getInstance(); + static assert(is(typeof(a)==A)); + static assert(is(typeof(b)==B)); + + auto ai = (immutable(A)).getInstance(); + auto bs = (shared(B)).getInstance(); + static assert(is(typeof(ai)==immutable(A))); + static assert(is(typeof(bs)==shared(B))); +} diff --git a/gcc/testsuite/gdc.test/compilable/test13123.d b/gcc/testsuite/gdc.test/compilable/test13123.d new file mode 100644 index 0000000..881eb1b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test13123.d @@ -0,0 +1,38 @@ +auto inferNothrow() +in +{ +} +out +{ +} +do +{ + return 1; +} + +auto dontInferNothrowIn() +in +{ + throw new Exception(null); +} +do +{ + return 1; +} + +auto dontInferNothrowOut() +out +{ + throw new Exception(null); +} +do +{ + return 1; +} + +enum isNothrow(Attr...) = (Attr.length >= 1) + && (Attr[0] == "nothrow" || isNothrow!(Attr[1 .. $])); + +static assert(isNothrow!(__traits(getFunctionAttributes, inferNothrow))); +static assert(!isNothrow!(__traits(getFunctionAttributes, dontInferNothrowIn))); +static assert(!isNothrow!(__traits(getFunctionAttributes, dontInferNothrowOut))); diff --git a/gcc/testsuite/gdc.test/compilable/test21243.d b/gcc/testsuite/gdc.test/compilable/test21243.d new file mode 100644 index 0000000..20838dc --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test21243.d @@ -0,0 +1,21 @@ +// Parsing - expressions +auto a = auto ref (int x) => x; +auto b = auto ref (int x) { return x; }; +auto c = function auto ref (int x) { return x; }; +auto d = delegate auto ref (int x) { return x; }; + +// Parsing - aliases +alias e = auto ref (int x) => x; +alias f = auto ref (int x) { return x; }; +alias g = function auto ref (int x) { return x; }; +alias h = delegate auto ref (int x) { return x; }; + +// Semantic +void test() +{ + alias fun(alias x) = auto ref () => x; + int n = 123; + auto _ = fun!123(); + static assert(!__traits(compiles, &fun!123())); // rvalue + fun!n() = 456; // lvalue +} diff --git a/gcc/testsuite/gdc.test/compilable/test21956.d b/gcc/testsuite/gdc.test/compilable/test21956.d new file mode 100644 index 0000000..64ebc55 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test21956.d @@ -0,0 +1,16 @@ +// https://issues.dlang.org/show_bug.cgi?id=21956 + +noreturn[noreturn] nrnr; + +void gun() +{ + foreach (a; nrnr){} +} + +int main() +{ + noreturn[] empty; + int val; + foreach(el; empty) val++; + return val; +} diff --git a/gcc/testsuite/gdc.test/compilable/test22674.d b/gcc/testsuite/gdc.test/compilable/test22674.d new file mode 100644 index 0000000..cc6e3bb --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test22674.d @@ -0,0 +1,10 @@ +// https://issues.dlang.org/show_bug.cgi?id=22674 +// EXTRA_FILES: imports/cimports2a.i imports/cimports2b.i + +import imports.cimports2a; +import imports.cimports2b; + +void do_foo(){ + FooRef f = make_foo(); // use_foo.d(5) + free_foo(f); // use_foo.d(6) +} diff --git a/gcc/testsuite/gdc.test/compilable/test23173.d b/gcc/testsuite/gdc.test/compilable/test23173.d new file mode 100644 index 0000000..6b16132 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test23173.d @@ -0,0 +1,6 @@ +// REQUIRED_ARGS: -o- +// https://issues.dlang.org/show_bug.cgi?id=23173 + +mixin("long l = ", long.min, ";"); +static assert(mixin(long.min) == long.min); +static assert(is(typeof(mixin(long.min)) == long)); diff --git a/gcc/testsuite/gdc.test/compilable/test23258.d b/gcc/testsuite/gdc.test/compilable/test23258.d new file mode 100644 index 0000000..1e8e91b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test23258.d @@ -0,0 +1,21 @@ +// https://issues.dlang.org/show_bug.cgi?id=23258 + +struct SumType(Types...) +{ + this(Types[0]) + { + } + this(Types[1]) + { + } +} + +alias A2 = SumType!(C1[], C2[]); + +class C1 +{ +} + +class C2 +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/test23306.d b/gcc/testsuite/gdc.test/compilable/test23306.d new file mode 100644 index 0000000..81b51f6 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test23306.d @@ -0,0 +1,7 @@ +class A { + @disable new(); +} + +void main() { + scope A a = new A(); +} diff --git a/gcc/testsuite/gdc.test/compilable/test23327.d b/gcc/testsuite/gdc.test/compilable/test23327.d new file mode 100644 index 0000000..bbb6346 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test23327.d @@ -0,0 +1,3 @@ +// https://issues.dlang.org/show_bug.cgi?id=23327 +// EXTRA_FILES: imports/format23327.d imports/format23327/write.d +import imports.format23327; diff --git a/gcc/testsuite/gdc.test/compilable/vararg.d b/gcc/testsuite/gdc.test/compilable/vararg.d new file mode 100644 index 0000000..79826a0 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/vararg.d @@ -0,0 +1,20 @@ +void main () +{ + variance([1.0, 2, 3]); +} + +alias meanType(T) = T; + +template variance(bool stable = true) +{ + void variance(Range)(Range r, bool isPopulation = false) + { + .variance!(double, stable)(r, isPopulation); + } +} + +template variance(F, bool stable = true) +{ + void variance(Range)(Range r, bool isPopulation = false) {} + void variance(scope const F[] ar...) {} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10169.d b/gcc/testsuite/gdc.test/fail_compilation/diag10169.d index 72becf2..84d0ad4 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag10169.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag10169.d @@ -2,7 +2,7 @@ EXTRA_FILES: imports/a10169.d TEST_OUTPUT: --- -fail_compilation/diag10169.d(12): Error: no property `x` for type `imports.a10169.B` +fail_compilation/diag10169.d(12): Error: no property `x` for `B(0)` of type `imports.a10169.B` --- */ import imports.a10169; diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10783.d b/gcc/testsuite/gdc.test/fail_compilation/diag10783.d index f18341f..80c7f5e 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag10783.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag10783.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/diag10783.d(14): Error: no property `type` for type `diag10783.Event` +fail_compilation/diag10783.d(14): Error: no property `type` for `event` of type `diag10783.Event` fail_compilation/diag10783.d(14): Error: undefined identifier `En` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag13528.d b/gcc/testsuite/gdc.test/fail_compilation/diag13528.d index 5d908f7..9b5761f 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag13528.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag13528.d @@ -1,10 +1,12 @@ /* TEST_OUTPUT: --- -fail_compilation/diag13528.d(13): Error: value of `this` is not known at compile time -fail_compilation/diag13528.d(13): while evaluating `pragma(msg, __traits(getMember, A, "foo"))` +fail_compilation/diag13528.d(6): Error: value of `this` is not known at compile time +fail_compilation/diag13528.d(6): while evaluating `pragma(msg, __traits(getMember, A, "foo"))` +fail_compilation/diag13528.d(12): parent scope from here: `mixin MyTemplate!()` --- */ +#line 1 mixin template MyTemplate() { diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag14145.d b/gcc/testsuite/gdc.test/fail_compilation/diag14145.d index 6447f5e..fa7c611 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag14145.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag14145.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/diag14145.d(15): Error: no property `i` for type `diag14145.main.Capture!(i)` +fail_compilation/diag14145.d(15): Error: no property `i` for `_` of type `diag14145.main.Capture!(i)` fail_compilation/diag14145.d(15): potentially malformed `opDispatch`. Use an explicit instantiation to get a better error message fail_compilation/diag14145.d(34): Error: expression `*this.ptr` of type `shared(int)` is not implicitly convertible to return type `ref int` fail_compilation/diag14145.d(16): Error: template instance `diag14145.main.Capture!(i).Capture.opDispatch!"i"` error instantiating diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag15713.d b/gcc/testsuite/gdc.test/fail_compilation/diag15713.d index 1c61408..e4cb2a7 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag15713.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag15713.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/diag15713.d(19): Error: no property `widthSign` for type `diag15713.WrData.Data` +fail_compilation/diag15713.d(19): Error: no property `widthSign` for `this` of type `diag15713.WrData.Data` fail_compilation/diag15713.d(39): Error: template instance `diag15713.conwritefImpl!("parse-int", "width", "\n", Data(null))` error instantiating fail_compilation/diag15713.d(44): instantiated from here: `conwritefImpl!("main", "\n", Data(null))` fail_compilation/diag15713.d(49): instantiated from here: `fdwritef!()` diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag23355.d b/gcc/testsuite/gdc.test/fail_compilation/diag23355.d new file mode 100644 index 0000000..586cbb0 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag23355.d @@ -0,0 +1,16 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag23355.d(1): Error: undefined identifier `n` +fail_compilation/diag23355.d(4): Error: none of the overloads of template `diag23355.ffi1` are callable using argument types `!()(int[4])` +fail_compilation/diag23355.d(1): Candidate is: `ffi1(T)(T[n] s)` +fail_compilation/diag23355.d(2): Error: undefined identifier `n` +fail_compilation/diag23355.d(4): Error: none of the overloads of template `diag23355.ffi2` are callable using argument types `!()(int[4])` +fail_compilation/diag23355.d(2): Candidate is: `ffi2()(T[n] s)` +--- +*/ +#line 1 +void ffi1(T)(T[n] s) { } +void ffi2()(T[n] s) { } + +void main() { int[4] x; ffi1(x); ffi2(x); } diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag3438.d b/gcc/testsuite/gdc.test/fail_compilation/diag3438.d index 445f6d5..c4cbc72 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag3438.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag3438.d @@ -1,4 +1,3 @@ -// REQUIRED_ARGS: -de /* TEST_OUTPUT: --- @@ -8,6 +7,7 @@ fail_compilation/diag3438.d(20): Error: constructor `diag3438.F5.this` is marked fail_compilation/diag3438.d(20): Use `@disable this();` if you want to disable default initialization. fail_compilation/diag3438.d(21): Error: constructor `diag3438.F6.this` is marked `@disable`, so it cannot have default arguments for all parameters. fail_compilation/diag3438.d(21): Use `@disable this();` if you want to disable default initialization. +fail_compilation/diag3438.d(24): Error: default argument expected for `y` --- */ @@ -19,3 +19,6 @@ struct F3 { this(...) { } } // ok struct F4 { this(int[] x...) { } } // ok struct F5 { @disable this(int x = 1); } struct F6 { @disable this(int x = 1) { } } + +// Make sure the deprecation doesn't interfere w/ the check for default arguments +struct S { this(int x = 1, int y) { } } diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag3438b.d b/gcc/testsuite/gdc.test/fail_compilation/diag3438b.d deleted file mode 100644 index 46a197d..0000000 --- a/gcc/testsuite/gdc.test/fail_compilation/diag3438b.d +++ /dev/null @@ -1,9 +0,0 @@ -/* -TEST_OUTPUT: ---- -fail_compilation/diag3438b.d(9): Error: default argument expected for `y` ---- -*/ - -// Make sure the deprecation doesn't interfere w/ the check for default arguments -struct S { this(int x = 1, int y) { } } diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8894.d b/gcc/testsuite/gdc.test/fail_compilation/diag8894.d index 9e0dadd..7cf3023 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag8894.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag8894.d @@ -1,10 +1,10 @@ /* TEST_OUTPUT: --- -fail_compilation/diag8894.d(16): Error: no property `x` for type `diag8894.Foo` -fail_compilation/diag8894.d(17): Error: no property `y` for type `diag8894.Foo` -fail_compilation/diag8894.d(18): Error: no property `x` for type `diag8894.Foo` -fail_compilation/diag8894.d(19): Error: no property `x` for type `diag8894.Foo` +fail_compilation/diag8894.d(16): Error: no property `x` for `f` of type `diag8894.Foo` +fail_compilation/diag8894.d(17): Error: no property `y` for `f` of type `diag8894.Foo` +fail_compilation/diag8894.d(18): Error: no property `x` for `f` of type `diag8894.Foo` +fail_compilation/diag8894.d(19): Error: no property `x` for `f` of type `diag8894.Foo` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/dip22a.d b/gcc/testsuite/gdc.test/fail_compilation/dip22a.d index bf04a51..324d217 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/dip22a.d +++ b/gcc/testsuite/gdc.test/fail_compilation/dip22a.d @@ -2,11 +2,11 @@ EXTRA_FILES: imports/dip22a.d TEST_OUTPUT: --- -fail_compilation/dip22a.d(16): Error: no property `bar` for type `imports.dip22a.Klass` -fail_compilation/dip22a.d(17): Error: no property `bar` for type `imports.dip22a.Struct` +fail_compilation/dip22a.d(16): Error: no property `bar` for `new Klass` of type `imports.dip22a.Klass` +fail_compilation/dip22a.d(17): Error: no property `bar` for `Struct()` of type `imports.dip22a.Struct` fail_compilation/dip22a.d(18): Error: undefined identifier `bar` in module `imports.dip22a` -fail_compilation/dip22a.d(19): Error: no property `bar` for type `void` -fail_compilation/dip22a.d(20): Error: no property `bar` for type `int` +fail_compilation/dip22a.d(19): Error: no property `bar` for `Template!int` of type `void` +fail_compilation/dip22a.d(20): Error: no property `bar` for `12` of type `int` --- */ import imports.dip22a; diff --git a/gcc/testsuite/gdc.test/fail_compilation/e15876_1.d b/gcc/testsuite/gdc.test/fail_compilation/e15876_1.d index 33bee25..92e0734 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/e15876_1.d +++ b/gcc/testsuite/gdc.test/fail_compilation/e15876_1.d @@ -1,14 +1,15 @@ /* TEST_OUTPUT: --- -fail_compilation/e15876_1.d(15): Error: valid scope identifiers are `exit`, `failure`, or `success`, not `x` -fail_compilation/e15876_1.d(16): Error: found `End of File` when expecting `)` -fail_compilation/e15876_1.d(16): Error: found `End of File` instead of statement -fail_compilation/e15876_1.d(16): Error: found `End of File` when expecting `}` following compound statement -fail_compilation/e15876_1.d(16): Error: found `End of File` when expecting `]` -fail_compilation/e15876_1.d(16): Error: no identifier for declarator `o[() +fail_compilation/e15876_1.d(16): Error: valid scope identifiers are `exit`, `failure`, or `success`, not `x` +fail_compilation/e15876_1.d(17): Error: found `End of File` when expecting `)` +fail_compilation/e15876_1.d(17): Error: found `End of File` instead of statement +fail_compilation/e15876_1.d(17): Error: found `End of File` when expecting `}` following compound statement +fail_compilation/e15876_1.d(17): Error: found `End of File` when expecting `]` +fail_compilation/e15876_1.d(17): Error: no identifier for declarator `o[() { -scope(exit) } +scope(exit) __error__ +} ]` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/e15876_3.d b/gcc/testsuite/gdc.test/fail_compilation/e15876_3.d index ae5f77a..fe7d546 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/e15876_3.d +++ b/gcc/testsuite/gdc.test/fail_compilation/e15876_3.d @@ -1,25 +1,27 @@ /* TEST_OUTPUT: --- -fail_compilation/e15876_3.d(25): Error: unexpected `(` in declarator -fail_compilation/e15876_3.d(25): Error: basic type expected, not `=` -fail_compilation/e15876_3.d(26): Error: found `End of File` when expecting `(` -fail_compilation/e15876_3.d(26): Error: found `End of File` instead of statement -fail_compilation/e15876_3.d(26): Error: expression expected, not `End of File` -fail_compilation/e15876_3.d(26): Error: found `End of File` when expecting `;` following `for` condition -fail_compilation/e15876_3.d(26): Error: expression expected, not `End of File` -fail_compilation/e15876_3.d(26): Error: found `End of File` when expecting `)` -fail_compilation/e15876_3.d(26): Error: found `End of File` instead of statement -fail_compilation/e15876_3.d(26): Error: found `End of File` when expecting `}` following compound statement -fail_compilation/e15876_3.d(26): Error: found `End of File` when expecting `)` -fail_compilation/e15876_3.d(26): Error: no identifier for declarator `d(_error_ = () +fail_compilation/e15876_3.d(27): Error: unexpected `(` in declarator +fail_compilation/e15876_3.d(27): Error: basic type expected, not `=` +fail_compilation/e15876_3.d(28): Error: found `End of File` when expecting `(` +fail_compilation/e15876_3.d(28): Error: found `End of File` instead of statement +fail_compilation/e15876_3.d(28): Error: expression expected, not `End of File` +fail_compilation/e15876_3.d(28): Error: found `End of File` when expecting `;` following `for` condition +fail_compilation/e15876_3.d(28): Error: expression expected, not `End of File` +fail_compilation/e15876_3.d(28): Error: found `End of File` when expecting `)` +fail_compilation/e15876_3.d(28): Error: found `End of File` instead of statement +fail_compilation/e15876_3.d(28): Error: found `End of File` when expecting `}` following compound statement +fail_compilation/e15876_3.d(28): Error: found `End of File` when expecting `)` +fail_compilation/e15876_3.d(28): Error: no identifier for declarator `d(_error_ = () { -for (; 0; 0) +for (__error__ + 0; 0) { +__error__ } } )` -fail_compilation/e15876_3.d(26): Error: semicolon expected following function declaration +fail_compilation/e15876_3.d(28): Error: semicolon expected following function declaration --- */ d(={for diff --git a/gcc/testsuite/gdc.test/fail_compilation/e15876_4.d b/gcc/testsuite/gdc.test/fail_compilation/e15876_4.d index 6f46633..f4bd407 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/e15876_4.d +++ b/gcc/testsuite/gdc.test/fail_compilation/e15876_4.d @@ -1,20 +1,22 @@ /* TEST_OUTPUT: --- -fail_compilation/e15876_4.d(23): Error: found `)` when expecting `(` -fail_compilation/e15876_4.d(24): Error: found `End of File` when expecting `(` -fail_compilation/e15876_4.d(24): Error: found `End of File` instead of statement -fail_compilation/e15876_4.d(24): Error: expression expected, not `End of File` -fail_compilation/e15876_4.d(24): Error: found `End of File` when expecting `;` following `for` condition -fail_compilation/e15876_4.d(24): Error: expression expected, not `End of File` -fail_compilation/e15876_4.d(24): Error: found `End of File` when expecting `)` -fail_compilation/e15876_4.d(24): Error: found `End of File` instead of statement -fail_compilation/e15876_4.d(24): Error: found `End of File` when expecting `}` following compound statement -fail_compilation/e15876_4.d(24): Error: found `End of File` when expecting `)` -fail_compilation/e15876_4.d(24): Error: no identifier for declarator `typeof(() +fail_compilation/e15876_4.d(25): Error: found `)` when expecting `(` +fail_compilation/e15876_4.d(26): Error: found `End of File` when expecting `(` +fail_compilation/e15876_4.d(26): Error: found `End of File` instead of statement +fail_compilation/e15876_4.d(26): Error: expression expected, not `End of File` +fail_compilation/e15876_4.d(26): Error: found `End of File` when expecting `;` following `for` condition +fail_compilation/e15876_4.d(26): Error: expression expected, not `End of File` +fail_compilation/e15876_4.d(26): Error: found `End of File` when expecting `)` +fail_compilation/e15876_4.d(26): Error: found `End of File` instead of statement +fail_compilation/e15876_4.d(26): Error: found `End of File` when expecting `}` following compound statement +fail_compilation/e15876_4.d(26): Error: found `End of File` when expecting `)` +fail_compilation/e15876_4.d(26): Error: no identifier for declarator `typeof(() { -for (; 0; 0) +for (__error__ + 0; 0) { +__error__ } } )` diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10968.d b/gcc/testsuite/gdc.test/fail_compilation/fail10968.d index e969b24..cfda8f4 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail10968.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail10968.d @@ -1,27 +1,28 @@ /* TEST_OUTPUT: --- -fail_compilation/fail10968.d(42): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit` -fail_compilation/fail10968.d(42): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit` -fail_compilation/fail10968.d(30): `fail10968.SA.__postblit` is declared here fail_compilation/fail10968.d(43): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit` fail_compilation/fail10968.d(43): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit` -fail_compilation/fail10968.d(30): `fail10968.SA.__postblit` is declared here +fail_compilation/fail10968.d(31): `fail10968.SA.__postblit` is declared here fail_compilation/fail10968.d(44): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit` fail_compilation/fail10968.d(44): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit` -fail_compilation/fail10968.d(30): `fail10968.SA.__postblit` is declared here -fail_compilation/fail10968.d(44): Error: `pure` function `fail10968.bar` cannot call impure function `core.internal.array.arrayassign._d_arrayassign_l!(SA[], SA)._d_arrayassign_l` -fail_compilation/fail10968.d(47): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit` -fail_compilation/fail10968.d(47): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit` -fail_compilation/fail10968.d(30): `fail10968.SA.__postblit` is declared here +fail_compilation/fail10968.d(31): `fail10968.SA.__postblit` is declared here +fail_compilation/fail10968.d(44): Error: `pure` function `fail10968.bar` cannot call impure function `core.internal.array.arrayassign._d_arraysetassign!(SA[], SA)._d_arraysetassign` +fail_compilation/fail10968.d(45): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit` +fail_compilation/fail10968.d(45): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit` +fail_compilation/fail10968.d(31): `fail10968.SA.__postblit` is declared here +fail_compilation/fail10968.d(45): Error: `pure` function `fail10968.bar` cannot call impure function `core.internal.array.arrayassign._d_arrayassign_l!(SA[], SA)._d_arrayassign_l` fail_compilation/fail10968.d(48): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit` fail_compilation/fail10968.d(48): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit` -fail_compilation/fail10968.d(30): `fail10968.SA.__postblit` is declared here -fail_compilation/fail10968.d(48): Error: `pure` function `fail10968.bar` cannot call impure function `core.internal.array.construction._d_arraysetctor!(SA[], SA)._d_arraysetctor` +fail_compilation/fail10968.d(31): `fail10968.SA.__postblit` is declared here fail_compilation/fail10968.d(49): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit` fail_compilation/fail10968.d(49): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit` -fail_compilation/fail10968.d(30): `fail10968.SA.__postblit` is declared here -fail_compilation/fail10968.d(49): Error: `pure` function `fail10968.bar` cannot call impure function `core.internal.array.construction._d_arrayctor!(SA[], SA)._d_arrayctor` +fail_compilation/fail10968.d(31): `fail10968.SA.__postblit` is declared here +fail_compilation/fail10968.d(49): Error: `pure` function `fail10968.bar` cannot call impure function `core.internal.array.construction._d_arraysetctor!(SA[], SA)._d_arraysetctor` +fail_compilation/fail10968.d(50): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit` +fail_compilation/fail10968.d(50): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit` +fail_compilation/fail10968.d(31): `fail10968.SA.__postblit` is declared here +fail_compilation/fail10968.d(50): Error: `pure` function `fail10968.bar` cannot call impure function `core.internal.array.construction._d_arrayctor!(SA[], SA)._d_arrayctor` --- */ @@ -52,12 +53,12 @@ void bar() pure @safe /* TEST_OUTPUT: --- -fail_compilation/fail10968.d(75): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit fail_compilation/fail10968.d(76): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit fail_compilation/fail10968.d(77): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit -fail_compilation/fail10968.d(80): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit +fail_compilation/fail10968.d(78): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit fail_compilation/fail10968.d(81): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit fail_compilation/fail10968.d(82): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit +fail_compilation/fail10968.d(83): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail121.d b/gcc/testsuite/gdc.test/fail_compilation/fail121.d index 70e9d0c..8d5af74 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail121.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail121.d @@ -3,8 +3,8 @@ /* TEST_OUTPUT: --- -fail_compilation/fail121.d(23): Error: no property `typeinfo` for type `fail121.myobject` -fail_compilation/fail121.d(23): Error: no property `typeinfo` for type `int` +fail_compilation/fail121.d(23): Error: no property `typeinfo` for `list[1]` of type `fail121.myobject` +fail_compilation/fail121.d(23): Error: no property `typeinfo` for `i` of type `int` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13123.d b/gcc/testsuite/gdc.test/fail_compilation/fail13123.d new file mode 100644 index 0000000..7784cba --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail13123.d @@ -0,0 +1,21 @@ +// REQUIRED_ARGS: -de +/* +TEST_OUTPUT: +--- +fail_compilation/fail13123.d(10): Deprecation: `fail13123.test`: `in` contract may throw but function is marked as `nothrow` +fail_compilation/fail13123.d(10): Deprecation: `fail13123.test`: `out` contract may throw but function is marked as `nothrow` +--- +*/ + +void test() nothrow +in +{ + throw new Exception(null); +} +out +{ + throw new Exception(null); +} +do +{ +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17646.d b/gcc/testsuite/gdc.test/fail_compilation/fail17646.d index 3571e38..39e7cb9 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail17646.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail17646.d @@ -4,9 +4,8 @@ EXTRA_FILES: imports/fail17646.d TEST_OUTPUT: --- fail_compilation/imports/fail17646.d(10): Error: found `}` instead of statement -fail_compilation/imports/fail17646.d(7): Error: function `imports.fail17646.allTestData!"".allTestData` has no `return` statement, but is expected to return a value of type `const(TestData)[]` -fail_compilation/fail17646.d(16): Error: template instance `imports.fail17646.allTestData!""` error instantiating -fail_compilation/fail17646.d(19): instantiated from here: `runTests!""` +fail_compilation/fail17646.d(11): Error: function `fail17646.runTests!"".runTests` has no `return` statement, but is expected to return a value of type `int` +fail_compilation/fail17646.d(18): Error: template instance `fail17646.runTests!""` error instantiating --- */ int runTests(Modules...)() diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail18892.d b/gcc/testsuite/gdc.test/fail_compilation/fail18892.d index 531d1ed..0fb56d3 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail18892.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail18892.d @@ -1,8 +1,8 @@ /* TEST_OUTPUT: --- -fail_compilation/fail18892.d(20): Error: no property `foo` for type `fail18892.MT` -fail_compilation/fail18892.d(21): Error: no property `foo` for type `fail18892.MT` +fail_compilation/fail18892.d(20): Error: no property `foo` for `a` of type `fail18892.MT` +fail_compilation/fail18892.d(21): Error: no property `foo` for `MT` of type `fail18892.MT` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail18970.d b/gcc/testsuite/gdc.test/fail_compilation/fail18970.d index 0973217..a8156fe 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail18970.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail18970.d @@ -1,9 +1,9 @@ /* TEST_OUTPUT: --- -fail_compilation/fail18970.d(24): Error: no property `y` for type `fail18970.S` +fail_compilation/fail18970.d(24): Error: no property `y` for `S()` of type `fail18970.S` fail_compilation/fail18970.d(24): potentially malformed `opDispatch`. Use an explicit instantiation to get a better error message -fail_compilation/fail18970.d(31): Error: no property `yyy` for type `fail18970.S2` +fail_compilation/fail18970.d(31): Error: no property `yyy` for `this` of type `fail18970.S2` fail_compilation/fail18970.d(31): potentially malformed `opDispatch`. Use an explicit instantiation to get a better error message --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail18979.d b/gcc/testsuite/gdc.test/fail_compilation/fail18979.d index 9756570..04e36f6 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail18979.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail18979.d @@ -2,7 +2,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail18979.d(13): Error: no property `__ctor` for type `imports.imp18979.Foo` +fail_compilation/fail18979.d(13): Error: no property `__ctor` for `Foo()` of type `imports.imp18979.Foo` ---- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19103.d b/gcc/testsuite/gdc.test/fail_compilation/fail19103.d index 6b740ac..40fafcd 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail19103.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail19103.d @@ -1,8 +1,8 @@ /* TEST_OUTPUT: --- -fail_compilation/fail19103.d(12): Error: no property `puts` for type `fail19103.C` -fail_compilation/fail19103.d(14): Error: no property `puts` for type `fail19103.S1` +fail_compilation/fail19103.d(12): Error: no property `puts` for `new C` of type `fail19103.C` +fail_compilation/fail19103.d(14): Error: no property `puts` for `s1` of type `fail19103.S1` fail_compilation/fail19103.d(16): Error: no property `puts` for type `S2`, did you mean `core.stdc.stdio.puts`? --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19687.d b/gcc/testsuite/gdc.test/fail_compilation/fail19687.d index 7d1c6e5..0076091 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail19687.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail19687.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail19687.d(17): Error: no property `nonexisting` for type `string` +fail_compilation/fail19687.d(17): Error: no property `nonexisting` for `""` of type `string` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19913.d b/gcc/testsuite/gdc.test/fail_compilation/fail19913.d index fe2655e..c880923 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail19913.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail19913.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail19913.d(11): Error: no property `b` for type `int` +fail_compilation/fail19913.d(11): Error: no property `b` for `a` of type `int` fail_compilation/fail19913.d(11): Error: mixin `fail19913.S.b!()` is not defined --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail21243.d b/gcc/testsuite/gdc.test/fail_compilation/fail21243.d new file mode 100644 index 0000000..25df235 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail21243.d @@ -0,0 +1,19 @@ +/+ TEST_OUTPUT: +--- +fail_compilation/fail21243.d(16): Error: found `(` when expecting `ref` and function literal following `auto` +fail_compilation/fail21243.d(16): Error: semicolon expected following auto declaration, not `int` +fail_compilation/fail21243.d(16): Error: semicolon needed to end declaration of `x` instead of `)` +fail_compilation/fail21243.d(16): Error: declaration expected, not `)` +fail_compilation/fail21243.d(17): Error: `auto` can only be used as part of `auto ref` for function literal return values +fail_compilation/fail21243.d(18): Error: basic type expected, not `(` +fail_compilation/fail21243.d(18): Error: function declaration without return type. (Note that constructors are always named `this`) +fail_compilation/fail21243.d(18): Deprecation: storage class `auto` has no effect in type aliases +fail_compilation/fail21243.d(18): Error: semicolon expected to close `alias` declaration +fail_compilation/fail21243.d(18): Error: declaration expected, not `=>` +fail_compilation/fail21243.d(19): Error: `auto` can only be used as part of `auto ref` for function literal return values +--- ++/ +auto a = auto (int x) => x; +auto b = function auto (int x) { return x; }; +alias c = auto (int x) => x; +alias d = function auto (int x) { return x; }; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail23109.d b/gcc/testsuite/gdc.test/fail_compilation/fail23109.d index 91b4e79..5c5c11b 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail23109.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail23109.d @@ -4,8 +4,8 @@ EXTRA_FILES: imports/test23109a.d imports/test23109b.d imports/test23109c.d EXTRA_SOURCES: extra-files/test23109/object.d TEST_OUTPUT: --- -Error: no property `getHash` for type `object.TypeInfo_Const` -Error: no property `getHash` for type `object.TypeInfo_Const` +Error: no property `getHash` for `typeid(const(Ensure[]))` of type `object.TypeInfo_Const` +Error: no property `getHash` for `typeid(const(Ensure[1]))` of type `object.TypeInfo_Const` fail_compilation/imports/test23109a.d(10): Error: template instance `imports.test23109a.Array!(Ensure)` error instantiating --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7372.d b/gcc/testsuite/gdc.test/fail_compilation/fail7372.d new file mode 100644 index 0000000..2d56e09 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7372.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/imports/fail7372.d(7): Error: undefined identifier `X` +fail_compilation/fail7372.d(4): parent scope from here: `mixin Issue7372!()` +--- +*/ +#line 1 +import imports.fail7372; +interface I {} +class C : I { + mixin Issue7372!(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/faildottypeinfo.d b/gcc/testsuite/gdc.test/fail_compilation/faildottypeinfo.d index d7853e6..c44b289 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/faildottypeinfo.d +++ b/gcc/testsuite/gdc.test/fail_compilation/faildottypeinfo.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/faildottypeinfo.d(11): Error: no property `typeinfo` for type `int` +fail_compilation/faildottypeinfo.d(11): Error: no property `typeinfo` for `0` of type `int` fail_compilation/faildottypeinfo.d(12): Error: no property `typeinfo` for type `object.Object` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/failoffset.d b/gcc/testsuite/gdc.test/fail_compilation/failoffset.d index bbec698..ff0d26b 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/failoffset.d +++ b/gcc/testsuite/gdc.test/fail_compilation/failoffset.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/failoffset.d(12): Error: no property `offset` for type `int` +fail_compilation/failoffset.d(12): Error: no property `offset` for `b` of type `int` fail_compilation/failoffset.d(12): while evaluating: `static assert(b.offset == 4)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10938.d b/gcc/testsuite/gdc.test/fail_compilation/ice10938.d index 2084e32..d21ee47 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice10938.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice10938.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/ice10938.d(13): Error: no property `opts` for type `ice10938.C` +fail_compilation/ice10938.d(13): Error: no property `opts` for `this` of type `ice10938.C` fail_compilation/ice10938.d(13): potentially malformed `opDispatch`. Use an explicit instantiation to get a better error message --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12174.d b/gcc/testsuite/gdc.test/fail_compilation/ice12174.d index 019722a..dbe386e 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice12174.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice12174.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/ice12174.d(12): Error: no property `sum` for type `int[]` +fail_compilation/ice12174.d(12): Error: no property `sum` for `[1, 2, 3]` of type `int[]` fail_compilation/ice12174.d(20): Error: CTFE failed because of previous errors in `this` fail_compilation/ice12174.d(13): called from here: `filter([1, 2, 3])` --- diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice15855.d b/gcc/testsuite/gdc.test/fail_compilation/ice15855.d index e800838..b26fe4c 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice15855.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice15855.d @@ -2,19 +2,21 @@ /* TEST_OUTPUT: --- -fail_compilation/ice15855.d(25): Error: found `End of File` when expecting `(` -fail_compilation/ice15855.d(25): Error: found `End of File` instead of statement -fail_compilation/ice15855.d(25): Error: expression expected, not `End of File` -fail_compilation/ice15855.d(25): Error: found `End of File` when expecting `;` following `for` condition -fail_compilation/ice15855.d(25): Error: expression expected, not `End of File` -fail_compilation/ice15855.d(25): Error: found `End of File` when expecting `)` -fail_compilation/ice15855.d(25): Error: found `End of File` instead of statement -fail_compilation/ice15855.d(25): Error: found `End of File` when expecting `}` following compound statement -fail_compilation/ice15855.d(25): Error: found `End of File` when expecting `]` -fail_compilation/ice15855.d(25): Error: no identifier for declarator `a[() +fail_compilation/ice15855.d(27): Error: found `End of File` when expecting `(` +fail_compilation/ice15855.d(27): Error: found `End of File` instead of statement +fail_compilation/ice15855.d(27): Error: expression expected, not `End of File` +fail_compilation/ice15855.d(27): Error: found `End of File` when expecting `;` following `for` condition +fail_compilation/ice15855.d(27): Error: expression expected, not `End of File` +fail_compilation/ice15855.d(27): Error: found `End of File` when expecting `)` +fail_compilation/ice15855.d(27): Error: found `End of File` instead of statement +fail_compilation/ice15855.d(27): Error: found `End of File` when expecting `}` following compound statement +fail_compilation/ice15855.d(27): Error: found `End of File` when expecting `]` +fail_compilation/ice15855.d(27): Error: no identifier for declarator `a[() { -for (; 0; 0) +for (__error__ + 0; 0) { +__error__ } } ]` diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice18469.d b/gcc/testsuite/gdc.test/fail_compilation/ice18469.d index 8803956..796dd3d 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice18469.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice18469.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/ice18469.d(10): Error: no property `opCall` for type `void` +fail_compilation/ice18469.d(10): Error: no property `opCall` for `this.~this()` of type `void` --- */ class Bar diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice19755.d b/gcc/testsuite/gdc.test/fail_compilation/ice19755.d index f948477..6d60fc4 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice19755.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice19755.d @@ -1,6 +1,6 @@ /* TEST_OUTPUT: --- -fail_compilation/ice19755.d(11): Error: no property `x` for type `ice19755.Thunk!int*` +fail_compilation/ice19755.d(11): Error: no property `x` for `self` of type `ice19755.Thunk!int*` fail_compilation/ice19755.d(16): Error: template instance `ice19755.Thunk!int` error instantiating --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/fail7372.d b/gcc/testsuite/gdc.test/fail_compilation/imports/fail7372.d new file mode 100644 index 0000000..f71c736 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/fail7372.d @@ -0,0 +1,9 @@ +module imports.fail7372; +import imports.imp1; +mixin template Issue7372() +{ + public void f() + { + int foo = X; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/misc_parser_err_cov1.d b/gcc/testsuite/gdc.test/fail_compilation/misc_parser_err_cov1.d index b50a616..11fddf0 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/misc_parser_err_cov1.d +++ b/gcc/testsuite/gdc.test/fail_compilation/misc_parser_err_cov1.d @@ -22,7 +22,6 @@ fail_compilation/misc_parser_err_cov1.d(39): Error: expression expected, not `;` fail_compilation/misc_parser_err_cov1.d(40): Error: semicolon expected following auto declaration, not `auto` fail_compilation/misc_parser_err_cov1.d(40): Error: identifier or `new` expected following `.`, not `+` fail_compilation/misc_parser_err_cov1.d(41): Error: identifier or new keyword expected following `(...)`. -fail_compilation/misc_parser_err_cov1.d(41): Error: found `.` when expecting `;` following statement fail_compilation/misc_parser_err_cov1.d(41): Error: expression expected, not `;` fail_compilation/misc_parser_err_cov1.d(42): Error: found `}` when expecting `;` following statement fail_compilation/misc_parser_err_cov1.d(43): Error: found `End of File` when expecting `}` following compound statement diff --git a/gcc/testsuite/gdc.test/fail_compilation/mixinprop.d b/gcc/testsuite/gdc.test/fail_compilation/mixinprop.d new file mode 100644 index 0000000..db8bf59 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/mixinprop.d @@ -0,0 +1,13 @@ +/* TEST_OUTPUT: +--- +fail_compilation/mixinprop.d(12): Error: no property `x` for `mixin Foo!() F; +` of type `void` +--- +*/ +mixin template Foo() { } + +void main() +{ + mixin Foo F; + F.x; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15785.d b/gcc/testsuite/gdc.test/fail_compilation/test15785.d index 23a3660..594b5d3 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test15785.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test15785.d @@ -2,7 +2,7 @@ /* TEST_OUTPUT: --- -fail_compilation/test15785.d(16): Error: no property `foo` for type `imports.test15785.Base` +fail_compilation/test15785.d(16): Error: no property `foo` for `super` of type `imports.test15785.Base` fail_compilation/test15785.d(17): Error: undefined identifier `bar` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15897.d b/gcc/testsuite/gdc.test/fail_compilation/test15897.d index e4ade7d..db554cb 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test15897.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test15897.d @@ -3,7 +3,7 @@ /* TEST_OUTPUT: --- -fail_compilation/test15897.d(19): Error: no property `create` for type `imports.test15897.Cat` +fail_compilation/test15897.d(19): Error: no property `create` for `cat` of type `imports.test15897.Cat` --- */ module test15897; diff --git a/gcc/testsuite/gdc.test/fail_compilation/test16188.d b/gcc/testsuite/gdc.test/fail_compilation/test16188.d index c4a0fa6..bdaae94 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test16188.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test16188.d @@ -1,7 +1,7 @@ /* REQUIRED_ARGS: -preview=bitfields * TEST_OUTPUT: --- -fail_compilation/test16188.d(101): Error: no property `name` for type `test16188.Where` +fail_compilation/test16188.d(101): Error: no property `name` for `Where()` of type `test16188.Where` fail_compilation/test16188.d(101): potentially malformed `opDispatch`. Use an explicit instantiation to get a better error message --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test17380spec.d b/gcc/testsuite/gdc.test/fail_compilation/test17380spec.d index 2456a59..f523337 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test17380spec.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test17380spec.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- (spec:1) fail_compilation/test17380spec.d(14): Error: cannot resolve identifier `ThisTypeDoesNotExistAndCrashesTheCompiler` -(spec:1) fail_compilation/test17380spec.d(14): Error: no property `ThisTypeDoesNotExistAndCrashesTheCompiler` for type `test17380spec.Uint128` +(spec:1) fail_compilation/test17380spec.d(14): Error: no property `ThisTypeDoesNotExistAndCrashesTheCompiler` for `this.opCast()` of type `test17380spec.Uint128` fail_compilation/test17380spec.d(14): Error: undefined identifier `ThisTypeDoesNotExistAndCrashesTheCompiler` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21096.d b/gcc/testsuite/gdc.test/fail_compilation/test21096.d index e32ad9c..302eb3d 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test21096.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test21096.d @@ -3,10 +3,8 @@ /* TEST_OUTPUT: --- -fail_compilation/test21096.d(13): Error: identifier or new keyword expected following `(...)`. -fail_compilation/test21096.d(13): Error: found `.` when expecting `]` -fail_compilation/test21096.d(13): Error: no identifier for declarator `char` -fail_compilation/test21096.d(13): Error: declaration expected, not `]` +fail_compilation/test21096.d(11): Error: identifier or new keyword expected following `(...)`. +fail_compilation/test21096.d(11): Error: no identifier for declarator `char[(__error)]` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test22680.d b/gcc/testsuite/gdc.test/fail_compilation/test22680.d new file mode 100644 index 0000000..caf0f4a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test22680.d @@ -0,0 +1,17 @@ +/* REQUIRED_ARGS: -preview=dip1000 +TEST_OUTPUT: +--- +fail_compilation/test22680.d(104): Error: scope variable `this` assigned to non-scope `c` +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=22680 + +#line 100 + +C c; +class C { + ~this() @safe { + c = this; + } +} diff --git a/gcc/testsuite/gdc.test/runnable/newaa.d b/gcc/testsuite/gdc.test/runnable/newaa.d new file mode 100644 index 0000000..94e79d5 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/newaa.d @@ -0,0 +1,23 @@ +void main() +{ + alias AA = int[string]; + // aa is not ref + static void test(AA aa) + { + aa[""] = 0; + } + auto aa = new AA(); + auto ab = new int[string]; + auto ac = new typeof(aa); + test(aa); + test(ab); + test(ac); + assert(aa.length); + assert(ab.length); + assert(ac.length); + + int[string] a = new int[string]; + auto b = a; + a["seven"] = 7; + assert(b["seven"] == 7); +} diff --git a/gcc/testsuite/gdc.test/runnable/test23234.d b/gcc/testsuite/gdc.test/runnable/test23234.d new file mode 100644 index 0000000..7872aa7 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/test23234.d @@ -0,0 +1,22 @@ +// https://issues.dlang.org/show_bug.cgi?id=23234 + +class Bar +{ +} + +class Foo +{ + Bar get() { return new Bar; } + alias get this; +} + +void main() +{ + auto foo = new Foo; + void test(Bar delegate() dg) + { + assert(dg() !is null); + } + + test(() => foo); +} diff --git a/gcc/testsuite/gdc.test/runnable/testassign.d b/gcc/testsuite/gdc.test/runnable/testassign.d index f47d2b2..586aea8 100644 --- a/gcc/testsuite/gdc.test/runnable/testassign.d +++ b/gcc/testsuite/gdc.test/runnable/testassign.d @@ -230,6 +230,21 @@ void test5() static assert(!__traits(compiles, s.err += 1)); } +void test6() +{ + int dtors; + struct S6 + { + @disable this(this); + ~this() { dtors++; } + } + + S6[2] arr; + arr = S6(); + + assert(dtors == 2); +} + /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=4424 @@ -1192,6 +1207,7 @@ int main() test3(); test4(); test5(); + test6(); test4424(); test6174a(); test6174b(); diff --git a/gcc/testsuite/gfortran.dg/intent_optimize_10.f90 b/gcc/testsuite/gfortran.dg/intent_optimize_10.f90 new file mode 100644 index 0000000..d8bc1bb --- /dev/null +++ b/gcc/testsuite/gfortran.dg/intent_optimize_10.f90 @@ -0,0 +1,66 @@ +! { dg-do run } +! { dg-additional-options "-fno-inline -fno-ipa-modref -fdump-tree-optimized -fdump-tree-original" } +! +! PR fortran/41453 +! Check that the INTENT(OUT) attribute causes in the case of non-polymorphic derived type arguments: +! - one clobber to be emitted in the caller before calls to FOO in the *.original dump, +! - no clobber to be emitted in the caller before calls to BAR in the *.original dump, +! - the initialization constants to be optimized away in the *.optimized dump. + +module x + implicit none + type :: t + integer :: c + end type t + type, extends(t) :: u + integer :: d + end type u +contains + subroutine foo(a) + type(t), intent(out) :: a + a = t(42) + end subroutine foo + subroutine bar(b) + class(t), intent(out) :: b + b%c = 24 + end subroutine bar +end module x + +program main + use x + implicit none + type(t) :: tc + type(u) :: uc, ud + class(t), allocatable :: te, tf + + tc = t(123456789) + call foo(tc) + if (tc%c /= 42) stop 1 + + uc = u(987654321, 0) + call foo(uc%t) + if (uc%c /= 42) stop 2 + if (uc%d /= 0) stop 3 + + ud = u(11223344, 0) + call bar(ud) + if (ud%c /= 24) stop 4 + + te = t(55667788) + call foo(te) + if (te%c /= 42) stop 5 + + tf = t(99887766) + call bar(tf) + if (tf%c /= 24) stop 6 + +end program main + +! We don't support class descriptors, neither derived type components, so there is a clobber for tc only; +! no clobber for uc, ud, te, tf. +! { dg-final { scan-tree-dump-times "CLOBBER" 1 "original" } } +! { dg-final { scan-tree-dump "tc = {CLOBBER};" "original" } } + +! There is a clobber for tc, so we should manage to optimize away the associated initialization constant (but not other +! initialization constants). +! { dg-final { scan-tree-dump-not "123456789" "optimized" { target __OPTIMIZE__ } } } diff --git a/gcc/testsuite/gfortran.dg/intent_optimize_4.f90 b/gcc/testsuite/gfortran.dg/intent_optimize_4.f90 new file mode 100644 index 0000000..effbaa1 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/intent_optimize_4.f90 @@ -0,0 +1,43 @@ +! { dg-do run } +! { dg-additional-options "-fdump-tree-original" } +! { dg-final { scan-tree-dump-times "CLOBBER" 2 "original" } } +! +! PR fortran/106817 +! Check that for an actual argument whose dummy is INTENT(OUT), +! the clobber that is emitted in the caller before a procedure call +! happens after any expression depending on the argument value has been +! evaluated. +! + +module m + implicit none +contains + subroutine copy1(out, in) + integer, intent(in) :: in + integer, intent(out) :: out + out = in + end subroutine copy1 + subroutine copy2(in, out) + integer, intent(in) :: in + integer, intent(out) :: out + out = in + end subroutine copy2 +end module m + +program p + use m + implicit none + integer :: a, b + + ! Clobbering of a should happen after a+1 has been evaluated. + a = 3 + call copy1(a, a+1) + if (a /= 4) stop 1 + + ! Clobbering order does not depend on the order of arguments. + ! It should also come last with reversed arguments. + b = 12 + call copy2(b+1, b) + if (b /= 13) stop 2 + +end program p diff --git a/gcc/testsuite/gfortran.dg/intent_optimize_5.f90 b/gcc/testsuite/gfortran.dg/intent_optimize_5.f90 new file mode 100644 index 0000000..2f184bf --- /dev/null +++ b/gcc/testsuite/gfortran.dg/intent_optimize_5.f90 @@ -0,0 +1,24 @@ +! { dg-do run } +! { dg-additional-options "-fno-inline -fno-ipa-modref -fdump-tree-optimized -fdump-tree-original" } +! +! PR fortran/105012 +! Check that the INTENT(OUT) attribute causes one clobber to be emitted in +! the caller before the call to Y in the *.original dump, and the +! initialization constant to be optimized away in the *.optimized dump, +! despite the non-explicit interface if the subroutine with the INTENT(OUT) +! is declared in the same file. + +SUBROUTINE Y (Z) + integer, intent(out) :: Z + Z = 42 +END SUBROUTINE Y +PROGRAM TEST + integer :: X + X = 123456789 + CALL Y (X) + if (X.ne.42) STOP 1 +END PROGRAM + +! { dg-final { scan-tree-dump-times "CLOBBER" 1 "original" } } +! { dg-final { scan-tree-dump "x = {CLOBBER};" "original" } } +! { dg-final { scan-tree-dump-not "123456789" "optimized" { target __OPTIMIZE__ } } } diff --git a/gcc/testsuite/gfortran.dg/intent_optimize_6.f90 b/gcc/testsuite/gfortran.dg/intent_optimize_6.f90 new file mode 100644 index 0000000..72fec3d --- /dev/null +++ b/gcc/testsuite/gfortran.dg/intent_optimize_6.f90 @@ -0,0 +1,34 @@ +! { dg-do run } +! { dg-additional-options "-fno-inline -fno-ipa-modref -fdump-tree-optimized -fdump-tree-original" } +! +! PR fortran/41453 +! Check that the INTENT(OUT) attribute causes one clobber to be emitted in +! the caller before each call to FOO in the *.original dump, and the +! initialization constant to be optimized away in the *.optimized dump, +! in the case of an argument passed by reference to the caller. + +module x +implicit none +contains + subroutine foo(a) + integer(kind=4), intent(out) :: a + a = 42 + end subroutine foo + subroutine bar(b) + integer(kind=4) :: b + b = 123456789 + call foo(b) + end subroutine bar +end module x + +program main + use x + implicit none + integer(kind=4) :: c + call bar(c) + if (c /= 42) stop 1 +end program main + +! { dg-final { scan-tree-dump-times "CLOBBER" 1 "original" } } +! { dg-final { scan-tree-dump "\\*\\\(integer\\\(kind=4\\\) \\*\\\) b = {CLOBBER};" "original" } } +! { dg-final { scan-tree-dump-not "123456789" "optimized" { target __OPTIMIZE__ } } } diff --git a/gcc/testsuite/gfortran.dg/intent_optimize_7.f90 b/gcc/testsuite/gfortran.dg/intent_optimize_7.f90 new file mode 100644 index 0000000..c2f2192 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/intent_optimize_7.f90 @@ -0,0 +1,45 @@ +! { dg-do run } +! { dg-additional-options "-fno-inline -fno-ipa-modref -fdump-tree-optimized -fdump-tree-original" } +! +! PR fortran/41453 +! Check that the INTENT(OUT) attribute causes one clobber to be emitted in +! the caller before each call to FOO in the *.original dump, and the +! initialization constants to be optimized away in the *.optimized dump, +! in the case of SAVE variables. + +module x +implicit none +contains + subroutine foo(a) + integer, intent(out) :: a + a = 42 + end subroutine foo +end module x + +program main + use x + implicit none + integer :: c = 0 + + ! implicit SAVE attribute + c = 123456789 + call foo(c) + if (c /= 42) stop 1 + + ! explicit SAVE attribute + call check_save_explicit + +contains + subroutine check_save_explicit + integer, save :: d + d = 987654321 + call foo(d) + if (d /= 42) stop 2 + end subroutine check_save_explicit +end program main + +! { dg-final { scan-tree-dump-times "CLOBBER" 2 "original" } } +! { dg-final { scan-tree-dump "c = {CLOBBER};" "original" } } +! { dg-final { scan-tree-dump "d = {CLOBBER};" "original" } } +! { dg-final { scan-tree-dump-not "123456789" "optimized" { target __OPTIMIZE__ } } } +! { dg-final { scan-tree-dump-not "987654321" "optimized" { target __OPTIMIZE__ } } } diff --git a/gcc/testsuite/gfortran.dg/intent_optimize_8.f90 b/gcc/testsuite/gfortran.dg/intent_optimize_8.f90 new file mode 100644 index 0000000..4336fce --- /dev/null +++ b/gcc/testsuite/gfortran.dg/intent_optimize_8.f90 @@ -0,0 +1,45 @@ +! { dg-do run } +! { dg-additional-options "-fno-inline -fno-ipa-modref -fdump-tree-optimized -fdump-tree-original" } +! +! PR fortran/41453 +! Check that the INTENT(OUT) attribute causes one clobber to be emitted in +! the caller before each call to FOO in the *.original dump, and the +! initialization constants to be optimized away in the *.optimized dump, +! in the case of associate variables. + +module x +implicit none +contains + subroutine foo(a) + integer, intent(out) :: a + a = 42 + end subroutine foo +end module x + +program main + use x + implicit none + integer :: c1, c2 + + c1 = 123456789 + associate (d1 => c1) + call foo(d1) + if (d1 /= 42) stop 1 + end associate + if (c1 /= 42) stop 2 + + c2 = 0 + associate (d2 => c2) + d2 = 987654321 + call foo(d2) + if (d2 /= 42) stop 3 + end associate + if (c2 /= 42) stop 4 + +end program main + +! { dg-final { scan-tree-dump-times "CLOBBER" 2 "original" } } +! { dg-final { scan-tree-dump "d1 = {CLOBBER};" "original" } } +! { dg-final { scan-tree-dump "\\*d2 = {CLOBBER};" "original" } } +! { dg-final { scan-tree-dump-not "123456789" "optimized" { target __OPTIMIZE__ } } } +! { dg-final { scan-tree-dump-not "987654321" "optimized" { target __OPTIMIZE__ } } } diff --git a/gcc/testsuite/gfortran.dg/intent_optimize_9.f90 b/gcc/testsuite/gfortran.dg/intent_optimize_9.f90 new file mode 100644 index 0000000..0146dff --- /dev/null +++ b/gcc/testsuite/gfortran.dg/intent_optimize_9.f90 @@ -0,0 +1,42 @@ +! { dg-do run } +! { dg-additional-options "-fno-inline -fno-ipa-modref -fdump-tree-optimized -fdump-tree-original" } +! +! PR fortran/41453 +! Check that the INTENT(OUT) attribute causes one clobber to be emitted in +! the caller before each call to FOO in the *.original dump, and the +! initialization constants to be optimized away in the *.optimized dump, +! in the case of scalar allocatables and pointers. + +module x +implicit none +contains + subroutine foo(a) + integer, intent(out) :: a + a = 42 + end subroutine foo +end module x + +program main + use x + implicit none + integer, allocatable :: ca + integer, target :: ct + integer, pointer :: cp + + allocate(ca) + ca = 123456789 + call foo(ca) + if (ca /= 42) stop 1 + deallocate(ca) + + ct = 987654321 + cp => ct + call foo(cp) + if (ct /= 42) stop 2 +end program main + +! { dg-final { scan-tree-dump-times "CLOBBER" 2 "original" } } +! { dg-final { scan-tree-dump "\\*ca = {CLOBBER};" "original" } } +! { dg-final { scan-tree-dump "\\*cp = {CLOBBER};" "original" } } +! { dg-final { scan-tree-dump-not "123456789" "optimized" { target __OPTIMIZE__ } } } +! { dg-final { scan-tree-dump-not "987654321" "optimized" { target __OPTIMIZE__ } } } diff --git a/gcc/testsuite/gfortran.dg/intent_out_15.f90 b/gcc/testsuite/gfortran.dg/intent_out_15.f90 new file mode 100644 index 0000000..64334e6 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/intent_out_15.f90 @@ -0,0 +1,27 @@ +! { dg-do compile } +! { dg-additional-options "-fdump-tree-original" } +! +! PR fortran/105012 +! The following case was triggering an ICE because of a clobber +! on the DERFC function decl instead of its result. + +module error_function +integer, parameter :: r8 = selected_real_kind(12) ! 8 byte real +contains +SUBROUTINE CALERF_r8(ARG, RESULT, JINT) + integer, parameter :: rk = r8 + real(rk), intent(in) :: arg + real(rk), intent(out) :: result + IF (Y .LE. THRESH) THEN + END IF +end SUBROUTINE CALERF_r8 +FUNCTION DERFC(X) + integer, parameter :: rk = r8 ! 8 byte real + real(rk), intent(in) :: X + real(rk) :: DERFC + CALL CALERF_r8(X, DERFC, JINT) +END FUNCTION DERFC +end module error_function + +! { dg-final { scan-tree-dump-times "CLOBBER" 1 "original" } } +! { dg-final { scan-tree-dump "__result_derfc = {CLOBBER};" "original" } } diff --git a/gcc/tree-core.h b/gcc/tree-core.h index 80c2bcb..55807fe 100644 --- a/gcc/tree-core.h +++ b/gcc/tree-core.h @@ -690,6 +690,10 @@ enum tree_index { - TI_FLOATN_NX_TYPE_FIRST \ + 1) + /* Type used by certain backends for __float128, which in C++ should be + distinct type from _Float128 for backwards compatibility reasons. */ + TI_FLOAT128T_TYPE, + /* Put the complex types after their component types, so that in (sequential) tree streaming we can assert that their component types have already been handled (see tree-streamer.cc:record_common_node). */ diff --git a/gcc/tree-ssa-dom.cc b/gcc/tree-ssa-dom.cc index 513e0c8..84bef79 100644 --- a/gcc/tree-ssa-dom.cc +++ b/gcc/tree-ssa-dom.cc @@ -1227,29 +1227,30 @@ void dom_opt_dom_walker::set_global_ranges_from_unreachable_edges (basic_block bb) { edge pred_e = single_pred_edge_ignoring_loop_edges (bb, false); - if (!pred_e) return; gimple *stmt = last_stmt (pred_e->src); + if (!stmt + || gimple_code (stmt) != GIMPLE_COND + || !assert_unreachable_fallthru_edge_p (pred_e)) + return; + tree name; - if (stmt - && gimple_code (stmt) == GIMPLE_COND - && (name = gimple_cond_lhs (stmt)) - && TREE_CODE (name) == SSA_NAME - && assert_unreachable_fallthru_edge_p (pred_e) - && all_uses_feed_or_dominated_by_stmt (name, stmt)) - { - Value_Range r (TREE_TYPE (name)); + gori_compute &gori = m_ranger->gori (); + FOR_EACH_GORI_EXPORT_NAME (gori, pred_e->src, name) + if (all_uses_feed_or_dominated_by_stmt (name, stmt)) + { + Value_Range r (TREE_TYPE (name)); - if (m_ranger->range_on_edge (r, pred_e, name) - && !r.varying_p () - && !r.undefined_p ()) - { - set_range_info (name, r); - maybe_set_nonzero_bits (pred_e, name); - } - } + if (m_ranger->range_on_edge (r, pred_e, name) + && !r.varying_p () + && !r.undefined_p ()) + { + set_range_info (name, r); + maybe_set_nonzero_bits (pred_e, name); + } + } } /* Record any equivalences created by the incoming edge to BB into diff --git a/gcc/tree-ssa-reassoc.cc b/gcc/tree-ssa-reassoc.cc index c5c8b68..b39c3c8 100644 --- a/gcc/tree-ssa-reassoc.cc +++ b/gcc/tree-ssa-reassoc.cc @@ -3608,13 +3608,13 @@ optimize_range_tests_cmp_bitwise (enum tree_code opcode, int first, int length, tree type2 = NULL_TREE; bool strict_overflow_p = false; candidates.truncate (0); - if (POINTER_TYPE_P (type1)) + if (POINTER_TYPE_P (type1) || TREE_CODE (type1) == OFFSET_TYPE) type1 = pointer_sized_int_node; for (j = i; j; j = chains[j - 1]) { tree type = TREE_TYPE (ranges[j - 1].exp); strict_overflow_p |= ranges[j - 1].strict_overflow_p; - if (POINTER_TYPE_P (type)) + if (POINTER_TYPE_P (type) || TREE_CODE (type) == OFFSET_TYPE) type = pointer_sized_int_node; if ((b % 4) == 3) { @@ -3646,7 +3646,7 @@ optimize_range_tests_cmp_bitwise (enum tree_code opcode, int first, int length, tree type = TREE_TYPE (ranges[j - 1].exp); if (j == k) continue; - if (POINTER_TYPE_P (type)) + if (POINTER_TYPE_P (type) || TREE_CODE (type) == OFFSET_TYPE) type = pointer_sized_int_node; if ((b % 4) == 3) { @@ -3677,10 +3677,20 @@ optimize_range_tests_cmp_bitwise (enum tree_code opcode, int first, int length, op = r->exp; continue; } - if (id == l || POINTER_TYPE_P (TREE_TYPE (op))) + if (id == l + || POINTER_TYPE_P (TREE_TYPE (op)) + || TREE_CODE (TREE_TYPE (op)) == OFFSET_TYPE) { code = (b % 4) == 3 ? BIT_NOT_EXPR : NOP_EXPR; tree type3 = id >= l ? type1 : pointer_sized_int_node; + if (code == BIT_NOT_EXPR + && TREE_CODE (TREE_TYPE (op)) == OFFSET_TYPE) + { + g = gimple_build_assign (make_ssa_name (type3), + NOP_EXPR, op); + gimple_seq_add_stmt_without_update (&seq, g); + op = gimple_assign_lhs (g); + } g = gimple_build_assign (make_ssa_name (type3), code, op); gimple_seq_add_stmt_without_update (&seq, g); op = gimple_assign_lhs (g); @@ -3688,6 +3698,7 @@ optimize_range_tests_cmp_bitwise (enum tree_code opcode, int first, int length, tree type = TREE_TYPE (r->exp); tree exp = r->exp; if (POINTER_TYPE_P (type) + || TREE_CODE (type) == OFFSET_TYPE || (id >= l && !useless_type_conversion_p (type1, type))) { tree type3 = id >= l ? type1 : pointer_sized_int_node; @@ -3705,7 +3716,7 @@ optimize_range_tests_cmp_bitwise (enum tree_code opcode, int first, int length, op = gimple_assign_lhs (g); } type1 = TREE_TYPE (ranges[k - 1].exp); - if (POINTER_TYPE_P (type1)) + if (POINTER_TYPE_P (type1) || TREE_CODE (type1) == OFFSET_TYPE) { gimple *g = gimple_build_assign (make_ssa_name (type1), NOP_EXPR, op); diff --git a/gcc/tree.cc b/gcc/tree.cc index 4165cbd..756c14f 100644 --- a/gcc/tree.cc +++ b/gcc/tree.cc @@ -9461,6 +9461,7 @@ build_common_tree_nodes (bool signed_char) layout_type (FLOATN_NX_TYPE_NODE (i)); SET_TYPE_MODE (FLOATN_NX_TYPE_NODE (i), mode); } + float128t_type_node = float128_type_node; float_ptr_type_node = build_pointer_type (float_type_node); double_ptr_type_node = build_pointer_type (double_type_node); @@ -4302,6 +4302,10 @@ tree_strip_any_location_wrapper (tree exp) #define float64x_type_node global_trees[TI_FLOAT64X_TYPE] #define float128x_type_node global_trees[TI_FLOAT128X_TYPE] +/* Type used by certain backends for __float128, which in C++ should be + distinct type from _Float128 for backwards compatibility reasons. */ +#define float128t_type_node global_trees[TI_FLOAT128T_TYPE] + #define float_ptr_type_node global_trees[TI_FLOAT_PTR_TYPE] #define double_ptr_type_node global_trees[TI_DOUBLE_PTR_TYPE] #define long_double_ptr_type_node global_trees[TI_LONG_DOUBLE_PTR_TYPE] diff --git a/gcc/value-range.cc b/gcc/value-range.cc index 9ca4424..6154d73 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -258,15 +258,6 @@ frange::accept (const vrange_visitor &v) const v.visit (*this); } -// Helper function to compare floats. Returns TRUE if op1 .CODE. op2 -// is nonzero. - -static inline bool -tree_compare (tree_code code, tree op1, tree op2) -{ - return !integer_zerop (fold_build2 (code, integer_type_node, op1, op2)); -} - // Flush denormal endpoints to the appropriate 0.0. void @@ -2939,6 +2930,19 @@ irange::set_nonzero_bits (const wide_int_ref &bits) set_nonzero_bits (NULL); return; } + // If we have only one bit set in the mask, we can figure out the + // range immediately. + if (wi::popcount (bits) == 1) + { + bool has_zero = contains_p (build_zero_cst (type ())); + set (type (), bits, bits); + if (has_zero) + { + int_range<2> zero; + zero.set_zero (type ()); + union_ (zero); + } + } set_nonzero_bits (wide_int_to_tree (type (), bits)); } diff --git a/gcc/value-range.h b/gcc/value-range.h index 413e54b..556e31a 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -117,6 +117,8 @@ class GTY((user)) irange : public vrange public: // In-place setters. virtual void set (tree, tree, value_range_kind = VR_RANGE) override; + void set (tree type, const wide_int_ref &, const wide_int_ref &, + value_range_kind = VR_RANGE); virtual void set_nonzero (tree type) override; virtual void set_zero (tree type) override; virtual void set_nonnegative (tree type) override; @@ -687,6 +689,13 @@ irange::varying_compatible_p () const return true; } +inline void +irange::set (tree type, const wide_int_ref &min, const wide_int_ref &max, + value_range_kind kind) +{ + set (wide_int_to_tree (type, min), wide_int_to_tree (type, max), kind); +} + inline bool vrange::varying_p () const { |