diff options
author | Martin Liska <mliska@suse.cz> | 2022-09-29 10:41:04 +0200 |
---|---|---|
committer | Martin Liska <mliska@suse.cz> | 2022-09-29 10:41:04 +0200 |
commit | 54f3cfaf3a6f50958c71d79c85206a6c722e1a22 (patch) | |
tree | 5f33297a30acc0df71baa0566cffa701eb97ab4e /gcc | |
parent | 3c527a35fa428b727807c81f1225a5e0025446c1 (diff) | |
parent | a1cd4d52d6ef90b977fb2d80c1cf17f3efa5b01d (diff) | |
download | gcc-54f3cfaf3a6f50958c71d79c85206a6c722e1a22.zip gcc-54f3cfaf3a6f50958c71d79c85206a6c722e1a22.tar.gz gcc-54f3cfaf3a6f50958c71d79c85206a6c722e1a22.tar.bz2 |
Merge branch 'master' into devel/sphinx
Diffstat (limited to 'gcc')
292 files changed, 8132 insertions, 1816 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6890dd1..25721e8 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,279 @@ +2022-09-28 Eugene Rozenfeld <erozen@microsoft.com> + + * basic-block.h: Remove discriminator from basic blocks. + * cfghooks.cc (split_block_1): Remove discriminator from basic blocks. + * final.cc (final_start_function_1): Switch from per-bb to per statement + discriminator. + (final_scan_insn_1): Don't keep track of basic block discriminators. + (compute_discriminator): Switch from basic block discriminators to + instruction discriminators. + (insn_discriminator): New function to return instruction discriminator. + (notice_source_line): Use insn_discriminator. + * gimple-pretty-print.cc (dump_gimple_bb_header): Remove dumping of + basic block discriminators. + * gimple-streamer-in.cc (input_bb): Remove reading of basic block + discriminators. + * gimple-streamer-out.cc (output_bb): Remove writing of basic block + discriminators. + * input.cc (make_location): Pass 0 discriminator to COMBINE_LOCATION_DATA. + (location_with_discriminator): New function to combine locus with + a discriminator. + (has_discriminator): New function to check if a location has a discriminator. + (get_discriminator_from_loc): New function to get the discriminator + from a location. + * input.h: Declarations of new functions. + * lto-streamer-in.cc (cmp_loc): Use discriminators in location comparison. + (apply_location_cache): Keep track of current discriminator. + (input_location_and_block): Read discriminator from stream. + * lto-streamer-out.cc (clear_line_info): Set current discriminator to + UINT_MAX. + (lto_output_location_1): Write discriminator to stream. + * lto-streamer.h: Add discriminator to cached_location. + Add current_discr to lto_location_cache. + Add current_discr to output_block. + * print-rtl.cc (print_rtx_operand_code_i): Print discriminator. + * rtl.h: Add extern declaration of insn_discriminator. + * tree-cfg.cc (assign_discriminator): New function to assign a unique + discriminator value to all statements in a basic block that have the given + line number. + (assign_discriminators): Assign discriminators to statement locations. + * tree-pretty-print.cc (dump_location): Dump discriminators. + * tree.cc (set_block): Preserve discriminator when setting block. + (set_source_range): Preserve discriminator when setting source range. + +2022-09-28 H.J. Lu <hjl.tools@gmail.com> + + PR target/107061 + * config/i386/predicates.md (encodekey128_operation): Check + XMM4-XMM6 as clobbered. + (encodekey256_operation): Likewise. + * config/i386/sse.md (encodekey128u32): Clobber XMM4-XMM6. + (encodekey256u32): Likewise. + +2022-09-28 Ju-Zhe Zhong <juzhe.zhong@rivai.ai> + + * config.gcc: Add riscv-vector-builtins.o. + * config/riscv/riscv-builtins.cc (riscv_init_builtins): Add RVV builtin function. + * config/riscv/riscv-protos.h (riscv_v_ext_enabled_vector_mode_p): New function. + * config/riscv/riscv.cc (ENTRY): New macro. + (riscv_v_ext_enabled_vector_mode_p): New function. + (riscv_mangle_type): Add RVV mangle. + (riscv_vector_mode_supported_p): Adjust RVV machine mode. + (riscv_verify_type_context): Add context check for RVV. + (riscv_vector_alignment): Add RVV alignment target hook support. + (TARGET_VECTOR_MODE_SUPPORTED_P): New target hook support. + (TARGET_VERIFY_TYPE_CONTEXT): Ditto. + (TARGET_VECTOR_ALIGNMENT): Ditto. + * config/riscv/t-riscv: Add riscv-vector-builtins.o + * config/riscv/riscv-vector-builtins.cc: New file. + * config/riscv/riscv-vector-builtins.def: New file. + * config/riscv/riscv-vector-builtins.h: New file. + * config/riscv/riscv-vector-switch.def: New file. + +2022-09-28 Stefan Schulze Frielinghaus <stefansf@linux.ibm.com> + + * var-tracking.cc (vt_add_function_parameter): Add entry values + up to maximal register mode. + +2022-09-28 Stefan Schulze Frielinghaus <stefansf@linux.ibm.com> + + * cselib.cc (new_cselib_val): Keep track of further subvalue + relations. + +2022-09-28 Andrea Corallo <andrea.corallo@arm.com> + + * config/arm/arm-c.cc (arm_cpu_builtins): Define + __ARM_FEATURE_AES and __ARM_FEATURE_SHA2. + +2022-09-28 Xi Ruoyao <xry111@xry111.site> + + PR tree-optimization/105414 + * config/loongarch/loongarch.md (UNSPEC_FMAX): New unspec. + (UNSPEC_FMIN): Likewise. + (fmax<mode>3): Use UNSPEC_FMAX instead of smax. + (fmin<mode>3): Use UNSPEC_FMIN instead of smin. + +2022-09-28 Lulu Cheng <chenglulu@loongson.cn> + + * config/loongarch/loongarch.cc (loongarch_asan_shadow_offset): + Fixed typo in "asan_mapping.h". + +2022-09-28 H.J. Lu <hjl.tools@gmail.com> + + PR middle-end/58245 + * calls.cc: Include "tree-eh.h". + (expand_call): Check stack canary before throwing exception. + +2022-09-27 Eugene Rozenfeld <erozen@microsoft.com> + + * ipa-cp.cc (good_cloning_opportunity_p): Fix profile count comparison. + +2022-09-27 Kim Kuparinen <kim.kuparinen@rightware.com> + + * doc/invoke.texi: Update ABI version info. + +2022-09-27 Aldy Hernandez <aldyh@redhat.com> + + * gimple-range-op.cc (cfn_popcount): Calculate the popcount of a + singleton. + +2022-09-27 Aldy Hernandez <aldyh@redhat.com> + + * value-range.cc (irange::set_nonzero_bits): Set range when known. + +2022-09-27 Aldy Hernandez <aldyh@redhat.com> + + * value-range.h (irange::set): New version taking wide_int_ref. + +2022-09-27 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/107029 + * tree-ssa-reassoc.cc (optimize_range_tests_cmp_bitwise): Treat + OFFSET_TYPE like POINTER_TYPE, except that OFFSET_TYPE may be + signed and so can trigger even the (b % 4) == 3 case. + +2022-09-27 Jeff Law <jeffreyalaw@gmail.com> + + * cfgrtl.cc (fixup_reorder_chain): Verify that simple_return + and return are available before trying to use them. + +2022-09-27 Jakub Jelinek <jakub@redhat.com> + + PR c++/106652 + PR c++/85518 + * tree-core.h (enum tree_index): Add TI_FLOAT128T_TYPE + enumerator. + * tree.h (float128t_type_node): Define. + * tree.cc (build_common_tree_nodes): Initialize float128t_type_node. + * builtins.def (DEF_FLOATN_BUILTIN): Adjust comment now that + _Float<N> is supported in C++ too. + * config/i386/i386.cc (ix86_mangle_type): Only mangle as "g" + float128t_type_node. + * config/i386/i386-builtins.cc (ix86_init_builtin_types): Use + float128t_type_node for __float128 instead of float128_type_node + and create it if NULL. + * config/i386/avx512fp16intrin.h (_mm_setzero_ph, _mm256_setzero_ph, + _mm512_setzero_ph, _mm_set_sh, _mm_load_sh): Use 0.0f16 instead of + 0.0f. + * config/ia64/ia64.cc (ia64_init_builtins): Use + float128t_type_node for __float128 instead of float128_type_node + and create it if NULL. + * config/rs6000/rs6000-c.cc (is_float128_p): Also return true + for float128t_type_node if non-NULL. + * config/rs6000/rs6000.cc (rs6000_mangle_type): Don't mangle + float128_type_node as "u9__ieee128". + * config/rs6000/rs6000-builtin.cc (rs6000_init_builtins): Use + float128t_type_node for __float128 instead of float128_type_node + and create it if NULL. + +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. diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 7764f7e..ea4b4d1 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20220926 +20220929 diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index c48bbdf..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". diff --git a/gcc/basic-block.h b/gcc/basic-block.h index c9d1fc9..1eae03d 100644 --- a/gcc/basic-block.h +++ b/gcc/basic-block.h @@ -148,11 +148,6 @@ struct GTY((chain_next ("%h.next_bb"), chain_prev ("%h.prev_bb"))) basic_block_d /* Expected number of executions: calculated in profile.cc. */ profile_count count; - - /* The discriminator for this block. The discriminator distinguishes - among several basic blocks that share a common locus, allowing for - more accurate sample-based profiling. */ - int discriminator; }; /* This ensures that struct gimple_bb_info is smaller than 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..a9ed2f0 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,61 @@ +2022-09-27 Marek Polacek <polacek@redhat.com> + + PR c++/101165 + PR c++/106882 + * c-cppbuiltin.cc (c_cpp_builtins): Define __cpp_implicit_move. + +2022-09-27 Marek Polacek <polacek@redhat.com> + + * c-format.cc (c_keywords): Drop nothrow. + +2022-09-27 Jakub Jelinek <jakub@redhat.com> + + PR c++/106651 + * c-cppbuiltin.cc (c_cpp_builtins): Predefine + __cpp_static_call_operator=202207L for C++23. + +2022-09-27 Jakub Jelinek <jakub@redhat.com> + + * c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_ASSUME, + PRAGMA_OMP_ASSUMES and PRAGMA_OMP_BEGIN. Rename + PRAGMA_OMP_END_DECLARE_TARGET to PRAGMA_OMP_END. + * c-pragma.cc (omp_pragmas): Add assumes and begin. + For end rename PRAGMA_OMP_END_DECLARE_TARGET to PRAGMA_OMP_END. + (omp_pragmas_simd): Add assume. + * c-common.h (c_omp_directives): Declare. + * c-omp.cc (omp_directives): Rename to ... + (c_omp_directives): ... this. No longer static. Uncomment + assume, assumes, begin assumes and end assumes entries. + In end declare target entry rename PRAGMA_OMP_END_DECLARE_TARGET + to PRAGMA_OMP_END. + (c_omp_categorize_directive): Adjust for omp_directives to + c_omp_directives renaming. + +2022-09-27 Jakub Jelinek <jakub@redhat.com> + + PR c++/106652 + PR c++/85518 + * c-common.cc (c_common_reswords): Change _Float{16,32,64,128} and + _Float{32,64,128}x flags from D_CONLY to 0. + (shorten_binary_op): Punt if common_type returns error_mark_node. + (shorten_compare): Likewise. + (c_common_nodes_and_builtins): For C++ record _Float{16,32,64,128} + and _Float{32,64,128}x builtin types if available. For C++ + clear float128t_type_node. + * c-cppbuiltin.cc (c_cpp_builtins): Predefine + __STDCPP_FLOAT{16,32,64,128}_T__ for C++23 if supported. + * c-lex.cc (interpret_float): For q/Q suffixes prefer + float128t_type_node over float128_type_node. Allow + {f,F}{16,32,64,128} suffixes for C++ if supported with pedwarn + for C++20 and older. Allow {f,F}{32,64,128}x suffixes for C++ + with pedwarn. Don't call excess_precision_type for C++. + +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 b709f84..d4de5a0 100644 --- a/gcc/c-family/c-cppbuiltin.cc +++ b/gcc/c-family/c-cppbuiltin.cc @@ -1081,6 +1081,8 @@ 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"); + cpp_define (pfile, "__cpp_implicit_move=202207L"); } if (flag_concepts) { @@ -1246,6 +1248,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-format.cc b/gcc/c-family/c-format.cc index a6c380b..a202659 100644 --- a/gcc/c-family/c-format.cc +++ b/gcc/c-family/c-format.cc @@ -2900,7 +2900,7 @@ static const token_t cxx_opers[] = }; /* Common C/C++ keywords that are expected to be quoted within the format - string. Keywords like auto, inline, or volatile are exccluded because + string. Keywords like auto, inline, or volatile are excluded because they are sometimes used in common terms like /auto variables/, /inline function/, or /volatile access/ where they should not be quoted. */ @@ -2927,7 +2927,6 @@ static const token_t c_keywords[] = NAME ("noinline", NULL), NAME ("nonnull", NULL), NAME ("noreturn", NULL), - NAME ("nothrow", NULL), NAME ("offsetof", NULL), NAME ("readonly", "read-only"), NAME ("readwrite", "read-write"), 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 4b852b8..7b29d78 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,21 @@ +2022-09-27 Jakub Jelinek <jakub@redhat.com> + + * c-lang.h (current_omp_begin_assumes): Declare. + * c-parser.cc: Include bitmap.h. + (c_parser_omp_end_declare_target): Rename to ... + (c_parser_omp_end): ... this. Handle also end assumes. + (c_parser_omp_begin, c_parser_omp_assumption_clauses, + c_parser_omp_assumes, c_parser_omp_assume): New functions. + (c_parser_translation_unit): Also diagnose #pragma omp begin assumes + without corresponding #pragma omp end assumes. + (c_parser_pragma): Use %s in may only be used at file scope + diagnostics to decrease number of translatable messages. Handle + PRAGMA_OMP_BEGIN and PRAGMA_OMP_ASSUMES. Handle PRAGMA_OMP_END + rather than PRAGMA_OMP_END_DECLARE_TARGET and call c_parser_omp_end + for it rather than c_parser_omp_end_declare_target. + (c_parser_omp_construct): Handle PRAGMA_OMP_ASSUME. + * c-decl.cc (current_omp_begin_assumes): Define. + 2022-09-24 Jakub Jelinek <jakub@redhat.com> PR c/106981 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/calls.cc b/gcc/calls.cc index bc96aff..6dd6f73 100644 --- a/gcc/calls.cc +++ b/gcc/calls.cc @@ -60,6 +60,7 @@ along with GCC; see the file COPYING3. If not see #include "attr-fnspec.h" #include "value-query.h" #include "tree-pretty-print.h" +#include "tree-eh.h" /* Like PREFERRED_STACK_BOUNDARY but in units of bytes, not bits. */ #define STACK_BYTES (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT) @@ -3154,7 +3155,10 @@ expand_call (tree exp, rtx target, int ignore) if (pass && (flags & ECF_MALLOC)) start_sequence (); - if (pass == 0 + /* Check the canary value for sibcall or function which doesn't + return and could throw. */ + if ((pass == 0 + || ((flags & ECF_NORETURN) != 0 && tree_could_throw_p (exp))) && crtl->stack_protect_guard && targetm.stack_protect_runtime_enabled_p ()) stack_protect_epilogue (); diff --git a/gcc/cfghooks.cc b/gcc/cfghooks.cc index c6ac953..29ded57 100644 --- a/gcc/cfghooks.cc +++ b/gcc/cfghooks.cc @@ -541,7 +541,6 @@ split_block_1 (basic_block bb, void *i) return NULL; new_bb->count = bb->count; - new_bb->discriminator = bb->discriminator; if (dom_info_available_p (CDI_DOMINATORS)) { diff --git a/gcc/cfgrtl.cc b/gcc/cfgrtl.cc index 90cd6ee..281a432 100644 --- a/gcc/cfgrtl.cc +++ b/gcc/cfgrtl.cc @@ -4049,7 +4049,8 @@ fixup_reorder_chain (void) rtx_insn *ret, *use; basic_block dest; if (bb_is_just_return (e_fall->dest, &ret, &use) - && (PATTERN (ret) == simple_return_rtx || PATTERN (ret) == ret_rtx)) + && ((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); diff --git a/gcc/config.gcc b/gcc/config.gcc index c1b1215..7eb0787 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -516,6 +516,7 @@ pru-*-*) riscv*) cpu_type=riscv extra_objs="riscv-builtins.o riscv-c.o riscv-sr.o riscv-shorten-memrefs.o riscv-selftests.o" + extra_objs="${extra_objs} riscv-vector-builtins.o" d_target_objs="riscv-d.o" ;; rs6000*-*-*) diff --git a/gcc/config/arm/arm-c.cc b/gcc/config/arm/arm-c.cc index a8697b8..86c56bf 100644 --- a/gcc/config/arm/arm-c.cc +++ b/gcc/config/arm/arm-c.cc @@ -202,6 +202,8 @@ arm_cpu_builtins (struct cpp_reader* pfile) def_or_undef_macro (pfile, "__ARM_FEATURE_QBIT", TARGET_ARM_QBIT); def_or_undef_macro (pfile, "__ARM_FEATURE_SAT", TARGET_ARM_SAT); def_or_undef_macro (pfile, "__ARM_FEATURE_CRYPTO", TARGET_CRYPTO); + def_or_undef_macro (pfile, "__ARM_FEATURE_AES", TARGET_CRYPTO); + def_or_undef_macro (pfile, "__ARM_FEATURE_SHA2", TARGET_CRYPTO); def_or_undef_macro (pfile, "__ARM_FEATURE_UNALIGNED", unaligned_access); 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.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/i386/predicates.md b/gcc/config/i386/predicates.md index 655eabf..c4141a9 100644 --- a/gcc/config/i386/predicates.md +++ b/gcc/config/i386/predicates.md @@ -2107,11 +2107,11 @@ for(i = 4; i < 7; i++) { elt = XVECEXP (op, 0, i); - if (GET_CODE (elt) != SET - || GET_CODE (SET_DEST (elt)) != REG - || GET_MODE (SET_DEST (elt)) != V2DImode - || REGNO (SET_DEST (elt)) != GET_SSE_REGNO (i) - || SET_SRC (elt) != CONST0_RTX (V2DImode)) + if (GET_CODE (elt) != CLOBBER + || GET_MODE (elt) != VOIDmode + || GET_CODE (XEXP (elt, 0)) != REG + || GET_MODE (XEXP (elt, 0)) != V2DImode + || REGNO (XEXP (elt, 0)) != GET_SSE_REGNO (i)) return false; } @@ -2157,11 +2157,11 @@ for(i = 4; i < 7; i++) { elt = XVECEXP (op, 0, i + 1); - if (GET_CODE (elt) != SET - || GET_CODE (SET_DEST (elt)) != REG - || GET_MODE (SET_DEST (elt)) != V2DImode - || REGNO (SET_DEST (elt)) != GET_SSE_REGNO (i) - || SET_SRC (elt) != CONST0_RTX (V2DImode)) + if (GET_CODE (elt) != CLOBBER + || GET_MODE (elt) != VOIDmode + || GET_CODE (XEXP (elt, 0)) != REG + || GET_MODE (XEXP (elt, 0)) != V2DImode + || REGNO (XEXP (elt, 0)) != GET_SSE_REGNO (i)) return false; } diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md index 5c18963..076064f 100644 --- a/gcc/config/i386/sse.md +++ b/gcc/config/i386/sse.md @@ -29015,7 +29015,7 @@ for (i = 4; i < 7; i++) XVECEXP (operands[2], 0, i) - = gen_rtx_SET (xmm_regs[i], CONST0_RTX (V2DImode)); + = gen_rtx_CLOBBER (VOIDmode, xmm_regs[i]); XVECEXP (operands[2], 0, 7) = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, FLAGS_REG)); @@ -29072,7 +29072,7 @@ for (i = 4; i < 7; i++) XVECEXP (operands[2], 0, i + 1) - = gen_rtx_SET (xmm_regs[i], CONST0_RTX (V2DImode)); + = gen_rtx_CLOBBER (VOIDmode, xmm_regs[i]); XVECEXP (operands[2], 0, 8) = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, FLAGS_REG)); 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/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc index 98c0e26..e9ba337 100644 --- a/gcc/config/loongarch/loongarch.cc +++ b/gcc/config/loongarch/loongarch.cc @@ -6472,7 +6472,7 @@ static unsigned HOST_WIDE_INT loongarch_asan_shadow_offset (void) { /* We only have libsanitizer support for LOONGARCH64 at present. - This value is taken from the file libsanitizer/asan/asan_mappint.h. */ + This value is taken from the file libsanitizer/asan/asan_mapping.h. */ return TARGET_64BIT ? (HOST_WIDE_INT_1 << 46) : 0; } diff --git a/gcc/config/loongarch/loongarch.md b/gcc/config/loongarch/loongarch.md index 3787fd8..214b14b 100644 --- a/gcc/config/loongarch/loongarch.md +++ b/gcc/config/loongarch/loongarch.md @@ -35,6 +35,8 @@ ;; Floating point unspecs. UNSPEC_FRINT UNSPEC_FCLASS + UNSPEC_FMAX + UNSPEC_FMIN ;; Override return address for exception handling. UNSPEC_EH_RETURN @@ -1032,8 +1034,9 @@ (define_insn "fmax<mode>3" [(set (match_operand:ANYF 0 "register_operand" "=f") - (smax:ANYF (match_operand:ANYF 1 "register_operand" "f") - (match_operand:ANYF 2 "register_operand" "f")))] + (unspec:ANYF [(use (match_operand:ANYF 1 "register_operand" "f")) + (use (match_operand:ANYF 2 "register_operand" "f"))] + UNSPEC_FMAX))] "" "fmax.<fmt>\t%0,%1,%2" [(set_attr "type" "fmove") @@ -1041,8 +1044,9 @@ (define_insn "fmin<mode>3" [(set (match_operand:ANYF 0 "register_operand" "=f") - (smin:ANYF (match_operand:ANYF 1 "register_operand" "f") - (match_operand:ANYF 2 "register_operand" "f")))] + (unspec:ANYF [(use (match_operand:ANYF 1 "register_operand" "f")) + (use (match_operand:ANYF 2 "register_operand" "f"))] + UNSPEC_FMIN))] "" "fmin.<fmt>\t%0,%1,%2" [(set_attr "type" "fmove") diff --git a/gcc/config/riscv/riscv-builtins.cc b/gcc/config/riscv/riscv-builtins.cc index 3009311..a51037a 100644 --- a/gcc/config/riscv/riscv-builtins.cc +++ b/gcc/config/riscv/riscv-builtins.cc @@ -37,6 +37,7 @@ along with GCC; see the file COPYING3. If not see #include "stringpool.h" #include "expr.h" #include "langhooks.h" +#include "riscv-vector-builtins.h" /* Macros to create an enumeration identifier for a function prototype. */ #define RISCV_FTYPE_NAME0(A) RISCV_##A##_FTYPE @@ -213,6 +214,7 @@ void riscv_init_builtins (void) { riscv_init_builtin_types (); + riscv_vector::init_builtins (); for (size_t i = 0; i < ARRAY_SIZE (riscv_builtins); i++) { diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h index f9a2baa..101361a 100644 --- a/gcc/config/riscv/riscv-protos.h +++ b/gcc/config/riscv/riscv-protos.h @@ -75,6 +75,7 @@ extern bool riscv_store_data_bypass_p (rtx_insn *, rtx_insn *); extern rtx riscv_gen_gpr_save_insn (struct riscv_frame_info *); extern bool riscv_gpr_save_operation_p (rtx); extern void riscv_reinit (void); +extern bool riscv_v_ext_enabled_vector_mode_p (machine_mode); /* Routines implemented in riscv-c.cc. */ void riscv_cpu_cpp_builtins (cpp_reader *); diff --git a/gcc/config/riscv/riscv-vector-builtins.cc b/gcc/config/riscv/riscv-vector-builtins.cc new file mode 100644 index 0000000..019a40d --- /dev/null +++ b/gcc/config/riscv/riscv-vector-builtins.cc @@ -0,0 +1,279 @@ +/* Builtins implementation for RISC-V 'V' Extension for GNU compiler. + Copyright (C) 2022-2022 Free Software Foundation, Inc. + Contributed by Ju-Zhe Zhong (juzhe.zhong@rivai.ai), RiVAI Technologies Ltd. + + 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/>. */ + +#define IN_TARGET_CODE 1 + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "rtl.h" +#include "tm_p.h" +#include "memmodel.h" +#include "insn-codes.h" +#include "optabs.h" +#include "recog.h" +#include "diagnostic.h" +#include "expr.h" +#include "function.h" +#include "fold-const.h" +#include "gimplify.h" +#include "explow.h" +#include "stor-layout.h" +#include "alias.h" +#include "langhooks.h" +#include "stringpool.h" +#include "attribs.h" +#include "targhooks.h" +#include "regs.h" +#include "riscv-vector-builtins.h" + +namespace riscv_vector { + +/* Information about each RVV type. */ +static CONSTEXPR const vector_type_info vector_types[] = { +#define DEF_RVV_TYPE(USER_NAME, NCHARS, ABI_NAME, ARGS...) \ + {#USER_NAME, #ABI_NAME, "u" #NCHARS #ABI_NAME}, +#include "riscv-vector-builtins.def" +}; + +/* The scalar type associated with each vector type. */ +static GTY (()) tree scalar_types[NUM_VECTOR_TYPES]; +/* The machine mode associated with each vector type. */ +static GTY (()) machine_mode vector_modes[NUM_VECTOR_TYPES]; +/* The RVV types, with their built-in + "__rvv..._t" name. Allow an index of NUM_VECTOR_TYPES, which always + yields a null tree. */ +static GTY(()) tree abi_vector_types[NUM_VECTOR_TYPES + 1]; + +rvv_switcher::rvv_switcher () +{ + /* Set have_regs_of_mode before targetm.init_builtins (). */ + memcpy (m_old_have_regs_of_mode, have_regs_of_mode, + sizeof (have_regs_of_mode)); + for (int i = 0; i < NUM_MACHINE_MODES; ++i) + if (riscv_v_ext_enabled_vector_mode_p ((machine_mode) i)) + have_regs_of_mode[i] = true; +} + +rvv_switcher::~rvv_switcher () +{ + /* Recover back have_regs_of_mode. */ + memcpy (have_regs_of_mode, m_old_have_regs_of_mode, + sizeof (have_regs_of_mode)); +} + +/* Add type attributes to builtin type tree, currently only the mangled name. */ +static void +add_vector_type_attribute (tree type, const char *mangled_name) +{ + tree mangled_name_tree = get_identifier (mangled_name); + tree value = tree_cons (NULL_TREE, mangled_name_tree, NULL_TREE); + TYPE_ATTRIBUTES (type) = tree_cons (get_identifier ("RVV type"), value, + TYPE_ATTRIBUTES (type)); +} + +/* Force TYPE to be a sizeless type. */ +static void +make_type_sizeless (tree type) +{ + TYPE_ATTRIBUTES (type) = tree_cons (get_identifier ("RVV sizeless type"), + NULL_TREE, TYPE_ATTRIBUTES (type)); +} + +/* Return true if TYPE is a sizeless type. */ +static bool +sizeless_type_p (const_tree type) +{ + if (type == error_mark_node) + return NULL_TREE; + return lookup_attribute ("RVV sizeless type", TYPE_ATTRIBUTES (type)); +} + +/* If TYPE is an ABI-defined RVV type, return its attribute descriptor, + otherwise return null. */ +static tree +lookup_vector_type_attribute (const_tree type) +{ + if (type == error_mark_node) + return NULL_TREE; + return lookup_attribute ("RVV type", TYPE_ATTRIBUTES (type)); +} + +/* If TYPE is a built-in type defined by the RVV ABI, return the mangled name, + otherwise return NULL. */ +const char * +mangle_builtin_type (const_tree type) +{ + if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL) + type = TREE_TYPE (TYPE_NAME (type)); + if (tree attr = lookup_vector_type_attribute (type)) + if (tree id = TREE_VALUE (chain_index (0, TREE_VALUE (attr)))) + return IDENTIFIER_POINTER (id); + return NULL; +} + +/* Register the built-in RVV ABI types, such as __rvv_int32m1_t. */ +static void +register_builtin_types () +{ + /* int32_t/uint32_t defined as `long`/`unsigned long` in RV32, + but intSI_type_node/unsigned_intSI_type_node is + `int` and `unsigned int`, so use long_integer_type_node and + long_unsigned_type_node here for type consistent. */ + tree int32_type_node + = TARGET_64BIT ? intSI_type_node : long_integer_type_node; + tree unsigned_int32_type_node + = TARGET_64BIT ? unsigned_intSI_type_node : long_unsigned_type_node; + + machine_mode mode; +#define DEF_RVV_TYPE(USER_NAME, NCHARS, ABI_NAME, SCALAR_TYPE, VECTOR_MODE, \ + VECTOR_MODE_MIN_VLEN_32) \ + mode = TARGET_MIN_VLEN > 32 ? VECTOR_MODE##mode \ + : VECTOR_MODE_MIN_VLEN_32##mode; \ + scalar_types[VECTOR_TYPE_##USER_NAME] \ + = riscv_v_ext_enabled_vector_mode_p (mode) ? SCALAR_TYPE##_type_node \ + : NULL_TREE; \ + vector_modes[VECTOR_TYPE_##USER_NAME] \ + = riscv_v_ext_enabled_vector_mode_p (mode) ? mode : VOIDmode; +#include "riscv-vector-builtins.def" + + for (unsigned int i = 0; i < NUM_VECTOR_TYPES; ++i) + { + tree eltype = scalar_types[i]; + mode = vector_modes[i]; + /* We disabled the datatypes according '-march'. */ + if (!eltype) + continue; + + tree vectype = build_vector_type_for_mode (eltype, mode); + gcc_assert ( + VECTOR_MODE_P (TYPE_MODE (vectype)) && TYPE_MODE (vectype) == mode + && TYPE_MODE_RAW (vectype) == mode && TYPE_ALIGN (vectype) <= 128 + && known_eq (tree_to_poly_uint64 (TYPE_SIZE (vectype)), + GET_MODE_BITSIZE (mode))); + vectype = build_distinct_type_copy (vectype); + gcc_assert (vectype == TYPE_MAIN_VARIANT (vectype)); + SET_TYPE_STRUCTURAL_EQUALITY (vectype); + TYPE_ARTIFICIAL (vectype) = 1; + TYPE_INDIVISIBLE_P (vectype) = 1; + add_vector_type_attribute (vectype, vector_types[i].mangled_name); + make_type_sizeless (vectype); + abi_vector_types[i] = vectype; + lang_hooks.types.register_builtin_type (vectype, + vector_types[i].abi_name); + } +} + +/* Initialize all compiler built-ins related to RVV that should be + defined at start-up. */ +void +init_builtins () +{ + rvv_switcher rvv; + if (!TARGET_VECTOR) + return; + register_builtin_types (); +} + +/* Implement TARGET_VERIFY_TYPE_CONTEXT for RVV types. */ +bool +verify_type_context (location_t loc, type_context_kind context, const_tree type, + bool silent_p) +{ + if (!sizeless_type_p (type)) + return true; + + switch (context) + { + case TCTX_SIZEOF: + case TCTX_STATIC_STORAGE: + if (!silent_p) + error_at (loc, "RVV type %qT does not have a fixed size", type); + + return false; + + case TCTX_ALIGNOF: + if (!silent_p) + error_at (loc, "RVV type %qT does not have a defined alignment", type); + + return false; + + case TCTX_THREAD_STORAGE: + if (!silent_p) + error_at (loc, + "variables of type %qT cannot have thread-local" + " storage duration", + type); + + return false; + + case TCTX_POINTER_ARITH: + if (!silent_p) + error_at (loc, "arithmetic on pointer to RVV type %qT", type); + + return false; + + case TCTX_FIELD: + if (silent_p) + ; + else if (lang_GNU_CXX ()) + error_at (loc, "member variables cannot have RVV type %qT", type); + else + error_at (loc, "fields cannot have RVV type %qT", type); + + return false; + + case TCTX_ARRAY_ELEMENT: + if (!silent_p) + error_at (loc, "array elements cannot have RVV type %qT", type); + + return false; + + case TCTX_ALLOCATION: + if (!silent_p) + error_at (loc, "cannot allocate objects with RVV type %qT", type); + + return false; + + case TCTX_DEALLOCATION: + if (!silent_p) + error_at (loc, "cannot delete objects with RVV type %qT", type); + + return false; + + case TCTX_EXCEPTIONS: + if (!silent_p) + error_at (loc, "cannot throw or catch RVV type %qT", type); + + return false; + + case TCTX_CAPTURE_BY_COPY: + if (!silent_p) + error_at (loc, "capture by copy of RVV type %qT", type); + + return false; + } + + gcc_unreachable (); +} + +} // end namespace riscv_vector diff --git a/gcc/config/riscv/riscv-vector-builtins.def b/gcc/config/riscv/riscv-vector-builtins.def new file mode 100644 index 0000000..a9001b3 --- /dev/null +++ b/gcc/config/riscv/riscv-vector-builtins.def @@ -0,0 +1,199 @@ +/* Builtins macros for RISC-V 'V' Extension for GNU compiler. + Copyright (C) 2022-2022 Free Software Foundation, Inc. + Contributed by Ju-Zhe Zhong (juzhe.zhong@rivai.ai), RiVAI Technologies Ltd. + +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/>. */ + +/* Use "DEF_RVV_TYPE" macro to define RVV datatype builtins. + 1.The 1 argument is the name exposed to users. + For example, "vint32m1_t". + 2.The 2 argument is the length of ABI-name. + For example, length of "__rvv_int32m1_t" is 15. + 3.The 3 argument is the ABI-name. For example, "__rvv_int32m1_t". + 4.The 4 argument is associated scalar type which is used in + "build_vector_type_for_mode". For "vint32m1_t", we use "intSI_type_node" in + RV64. Otherwise, we use "long_integer_type_node". + 5.The 5 and 6 argument are the machine modes of corresponding RVV type used + in "build_vector_type_for_mode". For "vint32m1_t", we use VNx2SImode when + TARGET_MIN_VLEN > 32. Otherwise the machine mode is VNx1SImode. */ + +#ifndef DEF_RVV_TYPE +#define DEF_RVV_TYPE(USER_NAME, NCHARS, ABI_NAME, SCALAR_TYPE, VECTOR_MODE, \ + VECTOR_MODE_MIN_VLEN_32) +#endif + +/* SEW/LMUL = 64: + Only enable when TARGET_MIN_VLEN > 32 and machine mode = VNx1BImode. */ +DEF_RVV_TYPE (vbool64_t, 14, __rvv_bool64_t, boolean, VNx1BI, VOID) +/* SEW/LMUL = 32: + Machine mode = VNx2BImode when TARGET_MIN_VLEN > 32. + Machine mode = VNx1BImode when TARGET_MIN_VLEN = 32. */ +DEF_RVV_TYPE (vbool32_t, 14, __rvv_bool32_t, boolean, VNx2BI, VNx1BI) +/* SEW/LMUL = 16: + Machine mode = VNx2BImode when TARGET_MIN_VLEN = 32. + Machine mode = VNx4BImode when TARGET_MIN_VLEN > 32. */ +DEF_RVV_TYPE (vbool16_t, 14, __rvv_bool16_t, boolean, VNx4BI, VNx2BI) +/* SEW/LMUL = 8: + Machine mode = VNx8BImode when TARGET_MIN_VLEN > 32. + Machine mode = VNx4BImode when TARGET_MIN_VLEN = 32. */ +DEF_RVV_TYPE (vbool8_t, 13, __rvv_bool8_t, boolean, VNx8BI, VNx4BI) +/* SEW/LMUL = 4: + Machine mode = VNx16BImode when TARGET_MIN_VLEN > 32. + Machine mode = VNx8BImode when TARGET_MIN_VLEN = 32. */ +DEF_RVV_TYPE (vbool4_t, 13, __rvv_bool4_t, boolean, VNx16BI, VNx8BI) +/* SEW/LMUL = 2: + Machine mode = VNx32BImode when TARGET_MIN_VLEN > 32. + Machine mode = VNx16BImode when TARGET_MIN_VLEN = 32. */ +DEF_RVV_TYPE (vbool2_t, 13, __rvv_bool2_t, boolean, VNx32BI, VNx16BI) +/* SEW/LMUL = 1: + Machine mode = VNx64BImode when TARGET_MIN_VLEN > 32. + Machine mode = VNx32BImode when TARGET_MIN_VLEN = 32. */ +DEF_RVV_TYPE (vbool1_t, 13, __rvv_bool1_t, boolean, VNx64BI, VNx32BI) + +/* LMUL = 1/8: + Only enble when TARGET_MIN_VLEN > 32 and machine mode = VNx1QImode. */ +DEF_RVV_TYPE (vint8mf8_t, 15, __rvv_int8mf8_t, intQI, VNx1QI, VOID) +DEF_RVV_TYPE (vuint8mf8_t, 16, __rvv_uint8mf8_t, unsigned_intQI, VNx1QI, VOID) +/* LMUL = 1/4: + Machine mode = VNx2QImode when TARGET_MIN_VLEN > 32. + Machine mode = VNx1QImode when TARGET_MIN_VLEN = 32. */ +DEF_RVV_TYPE (vint8mf4_t, 15, __rvv_int8mf4_t, intQI, VNx2QI, VNx1QI) +DEF_RVV_TYPE (vuint8mf4_t, 16, __rvv_uint8mf4_t, unsigned_intQI, VNx2QI, VNx1QI) +/* LMUL = 1/2: + Machine mode = VNx4QImode when TARGET_MIN_VLEN > 32. + Machine mode = VNx2QImode when TARGET_MIN_VLEN = 32. */ +DEF_RVV_TYPE (vint8mf2_t, 15, __rvv_int8mf2_t, intQI, VNx4QI, VNx2QI) +DEF_RVV_TYPE (vuint8mf2_t, 16, __rvv_uint8mf2_t, unsigned_intQI, VNx4QI, VNx2QI) +/* LMUL = 1: + Machine mode = VNx8QImode when TARGET_MIN_VLEN > 32. + Machine mode = VNx4QImode when TARGET_MIN_VLEN = 32. */ +DEF_RVV_TYPE (vint8m1_t, 14, __rvv_int8m1_t, intQI, VNx8QI, VNx4QI) +DEF_RVV_TYPE (vuint8m1_t, 15, __rvv_uint8m1_t, unsigned_intQI, VNx8QI, VNx4QI) +/* LMUL = 2: + Machine mode = VNx16QImode when TARGET_MIN_VLEN > 32. + Machine mode = VNx8QImode when TARGET_MIN_VLEN = 32. */ +DEF_RVV_TYPE (vint8m2_t, 14, __rvv_int8m2_t, intQI, VNx16QI, VNx8QI) +DEF_RVV_TYPE (vuint8m2_t, 15, __rvv_uint8m2_t, unsigned_intQI, VNx16QI, VNx8QI) +/* LMUL = 4: + Machine mode = VNx32QImode when TARGET_MIN_VLEN > 32. + Machine mode = VNx16QImode when TARGET_MIN_VLEN = 32. */ +DEF_RVV_TYPE (vint8m4_t, 14, __rvv_int8m4_t, intQI, VNx32QI, VNx16QI) +DEF_RVV_TYPE (vuint8m4_t, 15, __rvv_uint8m4_t, unsigned_intQI, VNx32QI, VNx16QI) +/* LMUL = 8: + Machine mode = VNx64QImode when TARGET_MIN_VLEN > 32. + Machine mode = VNx32QImode when TARGET_MIN_VLEN = 32. */ +DEF_RVV_TYPE (vint8m8_t, 14, __rvv_int8m8_t, intQI, VNx64QI, VNx32QI) +DEF_RVV_TYPE (vuint8m8_t, 15, __rvv_uint8m8_t, unsigned_intQI, VNx64QI, VNx32QI) + +/* LMUL = 1/4: + Only enble when TARGET_MIN_VLEN > 32 and machine mode = VNx1HImode. */ +DEF_RVV_TYPE (vint16mf4_t, 16, __rvv_int16mf4_t, intHI, VNx1HI, VOID) +DEF_RVV_TYPE (vuint16mf4_t, 17, __rvv_uint16mf4_t, unsigned_intHI, VNx1HI, VOID) +/* LMUL = 1/2: + Machine mode = VNx2HImode when TARGET_MIN_VLEN > 32. + Machine mode = VNx1HImode when TARGET_MIN_VLEN = 32. */ +DEF_RVV_TYPE (vint16mf2_t, 16, __rvv_int16mf2_t, intHI, VNx2HI, VNx1HI) +DEF_RVV_TYPE (vuint16mf2_t, 17, __rvv_uint16mf2_t, unsigned_intHI, VNx2HI, + VNx1HI) +/* LMUL = 1: + Machine mode = VNx4HImode when TARGET_MIN_VLEN > 32. + Machine mode = VNx2HImode when TARGET_MIN_VLEN = 32. */ +DEF_RVV_TYPE (vint16m1_t, 15, __rvv_int16m1_t, intHI, VNx4HI, VNx2HI) +DEF_RVV_TYPE (vuint16m1_t, 16, __rvv_uint16m1_t, unsigned_intHI, VNx4HI, VNx2HI) +/* LMUL = 2: + Machine mode = VNx8HImode when TARGET_MIN_VLEN > 32. + Machine mode = VNx4HImode when TARGET_MIN_VLEN = 32. */ +DEF_RVV_TYPE (vint16m2_t, 15, __rvv_int16m2_t, intHI, VNx8HI, VNx4HI) +DEF_RVV_TYPE (vuint16m2_t, 16, __rvv_uint16m2_t, unsigned_intHI, VNx8HI, VNx4HI) +/* LMUL = 4: + Machine mode = VNx16HImode when TARGET_MIN_VLEN > 32. + Machine mode = VNx8HImode when TARGET_MIN_VLEN = 32. */ +DEF_RVV_TYPE (vint16m4_t, 15, __rvv_int16m4_t, intHI, VNx16HI, VNx8HI) +DEF_RVV_TYPE (vuint16m4_t, 16, __rvv_uint16m4_t, unsigned_intHI, VNx16HI, + VNx8HI) +/* LMUL = 8: + Machine mode = VNx32HImode when TARGET_MIN_VLEN > 32. + Machine mode = VNx16HImode when TARGET_MIN_VLEN = 32. */ +DEF_RVV_TYPE (vint16m8_t, 15, __rvv_int16m8_t, intHI, VNx32HI, VNx16HI) +DEF_RVV_TYPE (vuint16m8_t, 16, __rvv_uint16m8_t, unsigned_intHI, VNx32HI, + VNx16HI) + +/* LMUL = 1/2: + Only enble when TARGET_MIN_VLEN > 32 and machine mode = VNx1SImode. */ +DEF_RVV_TYPE (vint32mf2_t, 16, __rvv_int32mf2_t, int32, VNx1SI, VOID) +DEF_RVV_TYPE (vuint32mf2_t, 17, __rvv_uint32mf2_t, unsigned_int32, VNx1SI, VOID) +/* LMUL = 1: + Machine mode = VNx2SImode when TARGET_MIN_VLEN > 32. + Machine mode = VNx1SImode when TARGET_MIN_VLEN = 32. */ +DEF_RVV_TYPE (vint32m1_t, 15, __rvv_int32m1_t, int32, VNx2SI, VNx1SI) +DEF_RVV_TYPE (vuint32m1_t, 16, __rvv_uint32m1_t, unsigned_int32, VNx2SI, VNx1SI) +/* LMUL = 2: + Machine mode = VNx4SImode when TARGET_MIN_VLEN > 32. + Machine mode = VNx2SImode when TARGET_MIN_VLEN = 32. */ +DEF_RVV_TYPE (vint32m2_t, 15, __rvv_int32m2_t, int32, VNx4SI, VNx2SI) +DEF_RVV_TYPE (vuint32m2_t, 16, __rvv_uint32m2_t, unsigned_int32, VNx4SI, VNx2SI) +/* LMUL = 4: + Machine mode = VNx8SImode when TARGET_MIN_VLEN > 32. + Machine mode = VNx4SImode when TARGET_MIN_VLEN = 32. */ +DEF_RVV_TYPE (vint32m4_t, 15, __rvv_int32m4_t, int32, VNx8SI, VNx4SI) +DEF_RVV_TYPE (vuint32m4_t, 16, __rvv_uint32m4_t, unsigned_int32, VNx8SI, VNx4SI) +/* LMUL = 8: + Machine mode = VNx16SImode when TARGET_MIN_VLEN > 32. + Machine mode = VNx8SImode when TARGET_MIN_VLEN = 32. */ +DEF_RVV_TYPE (vint32m8_t, 15, __rvv_int32m8_t, int32, VNx16SI, VNx8SI) +DEF_RVV_TYPE (vuint32m8_t, 16, __rvv_uint32m8_t, unsigned_int32, VNx16SI, + VNx8SI) + +/* SEW = 64: + Disable when TARGET_MIN_VLEN > 32. */ +DEF_RVV_TYPE (vint64m1_t, 15, __rvv_int64m1_t, intDI, VNx1DI, VOID) +DEF_RVV_TYPE (vuint64m1_t, 16, __rvv_uint64m1_t, unsigned_intDI, VNx1DI, VOID) +DEF_RVV_TYPE (vint64m2_t, 15, __rvv_int64m2_t, intDI, VNx2DI, VOID) +DEF_RVV_TYPE (vuint64m2_t, 16, __rvv_uint64m2_t, unsigned_intDI, VNx2DI, VOID) +DEF_RVV_TYPE (vint64m4_t, 15, __rvv_int64m4_t, intDI, VNx4DI, VOID) +DEF_RVV_TYPE (vuint64m4_t, 16, __rvv_uint64m4_t, unsigned_intDI, VNx4DI, VOID) +DEF_RVV_TYPE (vint64m8_t, 15, __rvv_int64m8_t, intDI, VNx8DI, VOID) +DEF_RVV_TYPE (vuint64m8_t, 16, __rvv_uint64m8_t, unsigned_intDI, VNx8DI, VOID) + +/* LMUL = 1/2: + Only enble when TARGET_MIN_VLEN > 32 and machine mode = VNx1SFmode. */ +DEF_RVV_TYPE (vfloat32mf2_t, 18, __rvv_float32mf2_t, float, VNx1SF, VOID) +/* LMUL = 1: + Machine mode = VNx2SFmode when TARGET_MIN_VLEN > 32. + Machine mode = VNx1SFmode when TARGET_MIN_VLEN = 32. */ +DEF_RVV_TYPE (vfloat32m1_t, 17, __rvv_float32m1_t, float, VNx2SF, VNx1SF) +/* LMUL = 2: + Machine mode = VNx4SFmode when TARGET_MIN_VLEN > 32. + Machine mode = VNx2SFmode when TARGET_MIN_VLEN = 32. */ +DEF_RVV_TYPE (vfloat32m2_t, 17, __rvv_float32m2_t, float, VNx4SF, VNx2SF) +/* LMUL = 4: + Machine mode = VNx8SFmode when TARGET_MIN_VLEN > 32. + Machine mode = VNx4SFmode when TARGET_MIN_VLEN = 32. */ +DEF_RVV_TYPE (vfloat32m4_t, 17, __rvv_float32m4_t, float, VNx8SF, VNx4SF) +/* LMUL = 8: + Machine mode = VNx16SFmode when TARGET_MIN_VLEN > 32. + Machine mode = VNx8SFmode when TARGET_MIN_VLEN = 32. */ +DEF_RVV_TYPE (vfloat32m8_t, 17, __rvv_float32m8_t, float, VNx16SF, VNx8SF) + +/* SEW = 64: + Disable when TARGET_VECTOR_FP64. */ +DEF_RVV_TYPE (vfloat64m1_t, 17, __rvv_float64m1_t, double, VNx1DF, VOID) +DEF_RVV_TYPE (vfloat64m2_t, 17, __rvv_float64m2_t, double, VNx2DF, VOID) +DEF_RVV_TYPE (vfloat64m4_t, 17, __rvv_float64m4_t, double, VNx4DF, VOID) +DEF_RVV_TYPE (vfloat64m8_t, 17, __rvv_float64m8_t, double, VNx8DF, VOID) + +#undef DEF_RVV_TYPE diff --git a/gcc/config/riscv/riscv-vector-builtins.h b/gcc/config/riscv/riscv-vector-builtins.h new file mode 100644 index 0000000..a4a8c11 --- /dev/null +++ b/gcc/config/riscv/riscv-vector-builtins.h @@ -0,0 +1,79 @@ +/* Builtins definitions for RISC-V 'V' Extension for GNU compiler. + Copyright (C) 2022-2022 Free Software Foundation, Inc. + Contributed by Ju-Zhe Zhong (juzhe.zhong@rivai.ai), RiVAI Technologies Ltd. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GCC is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +#ifndef GCC_RISCV_V_BUILTINS_H +#define GCC_RISCV_V_BUILTINS_H + +namespace riscv_vector { + +/* Static information about each vector type. */ +struct vector_type_info +{ + /* The name of the type as declared by riscv_vector.h + which is recommend to use. For example: 'vint32m1_t'. */ + const char *user_name; + + /* ABI name of vector type. The type is always available + under this name, even when riscv_vector.h isn't included. + For example: '__rvv_int32m1_t'. */ + const char *abi_name; + + /* The C++ mangling of ABI_NAME. */ + const char *mangled_name; +}; + +/* Enumerates the RVV types, together called + "vector types" for brevity. */ +enum vector_type_index +{ +#define DEF_RVV_TYPE(USER_NAME, ABI_NAME, NCHARS, ARGS...) \ + VECTOR_TYPE_##USER_NAME, +#include "riscv-vector-builtins.def" + NUM_VECTOR_TYPES +}; + +/* RAII class for enabling enough RVV features to define the built-in + types and implement the riscv_vector.h pragma. + + Note: According to 'TYPE_MODE' macro implementation, we need set + have_regs_of_mode[mode] to be true if we want to get the exact mode + from 'TYPE_MODE'. However, have_regs_of_mode has not been set yet in + targetm.init_builtins (). We need rvv_switcher to set have_regs_of_mode + before targetm.init_builtins () and recover back have_regs_of_mode + after targetm.init_builtins (). */ +class rvv_switcher +{ +public: + rvv_switcher (); + ~rvv_switcher (); + +private: + bool m_old_have_regs_of_mode[MAX_MACHINE_MODE]; +}; + +void init_builtins (); +const char *mangle_builtin_type (const_tree); +#ifdef GCC_TARGET_H +bool verify_type_context (location_t, type_context_kind, const_tree, bool); +#endif + +} // end namespace riscv_vector + +#endif diff --git a/gcc/config/riscv/riscv-vector-switch.def b/gcc/config/riscv/riscv-vector-switch.def new file mode 100644 index 0000000..cacfccb --- /dev/null +++ b/gcc/config/riscv/riscv-vector-switch.def @@ -0,0 +1,164 @@ +/* Machine mode switch for RISC-V 'V' Extension for GNU compiler. + Copyright (C) 2022-2022 Free Software Foundation, Inc. + Contributed by Ju-Zhe Zhong (juzhe.zhong@rivai.ai), RiVAI Technologies Ltd. + +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/>. */ + +/* This file is enable or disable the RVV modes according '-march'. */ + +/* According to rvv-intrinsic and RISC-V 'V' Extension ISA document: + https://github.com/riscv-non-isa/rvv-intrinsic-doc/blob/master/rvv-intrinsic-rfc.md. + https://github.com/riscv/riscv-v-spec/blob/master/v-spec.adoc. + + Data Types + Encode SEW and LMUL into data types. + We enforce the constraint LMUL ≥ SEW/ELEN in the implementation. + There are the following data types for MIN_VLEN > 32. + +Note: N/A means the corresponding vector type is disabled. + +|Types |LMUL=1|LMUL=2 |LMUL=4 |LMUL=8 |LMUL=1/2|LMUL=1/4|LMUL=1/8| +|int64_t |VNx1DI|VNx2DI |VNx4DI |VNx8DI |N/A |N/A |N/A | +|uint64_t|VNx1DI|VNx2DI |VNx4DI |VNx8DI |N/A |N/A |N/A | +|int32_t |VNx2SI|VNx4SI |VNx8SI |VNx16SI|VNx1SI |N/A |N/A | +|uint32_t|VNx2SI|VNx4SI |VNx8SI |VNx16SI|VNx1SI |N/A |N/A | +|int16_t |VNx4HI|VNx8HI |VNx16HI|VNx32HI|VNx2HI |VNx1HI |N/A | +|uint16_t|VNx4HI|VNx8HI |VNx16HI|VNx32HI|VNx2HI |VNx1HI |N/A | +|int8_t |VNx8QI|VNx16QI|VNx32QI|VNx64QI|VNx4QI |VNx2QI |VNx1QI | +|uint8_t |VNx8QI|VNx16QI|VNx32QI|VNx64QI|VNx4QI |VNx2QI |VNx1QI | +|float64 |VNx1DF|VNx2DF |VNx4DF |VNx8DF |N/A |N/A |N/A | +|float32 |VNx2SF|VNx4SF |VNx8SF |VNx16SF|VNx1SF |N/A |N/A | +|float16 |VNx4HF|VNx8HF |VNx16HF|VNx32HF|VNx2HF |VNx1HF |N/A | + +Mask Types Encode the ratio of SEW/LMUL into the +mask types. There are the following mask types. + +n = SEW/LMUL + +|Types|n=1 |n=2 |n=4 |n=8 |n=16 |n=32 |n=64 | +|bool |VNx64BI|VNx32BI|VNx16BI|VNx8BI|VNx4BI|VNx2BI|VNx1BI| + +There are the following data types for MIN_VLEN = 32. + +|Types |LMUL=1|LMUL=2|LMUL=4 |LMUL=8 |LMUL=1/2|LMUL=1/4|LMUL=1/8| +|int64_t |N/A |N/A |N/A |N/A |N/A |N/A |N/A | +|uint64_t|N/A |N/A |N/A |N/A |N/A |N/A |N/A | +|int32_t |VNx1SI|VNx2SI|VNx4SI |VNx8SI |N/A |N/A |N/A | +|uint32_t|VNx1SI|VNx2SI|VNx4SI |VNx8SI |N/A |N/A |N/A | +|int16_t |VNx2HI|VNx4HI|VNx8HI |VNx16HI|VNx1HI |N/A |N/A | +|uint16_t|VNx2HI|VNx4HI|VNx8HI |VNx16HI|VNx1HI |N/A |N/A | +|int8_t |VNx4QI|VNx8QI|VNx16QI|VNx32QI|VNx2QI |VNx1QI |N/A | +|uint8_t |VNx4QI|VNx8QI|VNx16QI|VNx32QI|VNx2QI |VNx1QI |N/A | +|float64 |N/A |N/A |N/A |N/A |N/A |N/A |N/A | +|float32 |VNx1SF|VNx2SF|VNx4SF |VNx8SF |N/A |N/A |N/A | +|float16 |VNx2HF|VNx4HF|VNx8HF |VNx16HF|VNx1HF |N/A |N/A | + +Mask Types Encode the ratio of SEW/LMUL into the +mask types. There are the following mask types. + +n = SEW/LMUL + +|Types|n=1 |n=2 |n=4 |n=8 |n=16 |n=32 |n=64| +|bool |VNx32BI|VNx16BI|VNx8BI|VNx4BI|VNx2BI|VNx1BI|N/A | + +TODO: FP16 vector needs support of 'zvfh', we don't support it yet. */ + +/* Return 'REQUIREMENT' for machine_mode 'MODE'. + For example: 'MODE' = VNx64BImode needs TARGET_MIN_VLEN > 32. */ +#ifndef ENTRY +#define ENTRY(MODE, REQUIREMENT) +#endif +/* Flag of FP32 vector. */ +#ifndef TARGET_VECTOR_FP32 +#define TARGET_VECTOR_FP32 \ + (TARGET_HARD_FLOAT && (TARGET_VECTOR_ELEN_FP_32 || TARGET_VECTOR_ELEN_FP_64)) +#endif +/* Flag of FP64 vector. */ +#ifndef TARGET_VECTOR_FP64 +#define TARGET_VECTOR_FP64 \ + (TARGET_DOUBLE_FLOAT && TARGET_VECTOR_ELEN_FP_64 && (TARGET_MIN_VLEN > 32)) +#endif + +/* Mask modes. Disable VNx64BImode when TARGET_MIN_VLEN == 32. */ +ENTRY (VNx64BI, TARGET_MIN_VLEN > 32) +ENTRY (VNx32BI, true) +ENTRY (VNx16BI, true) +ENTRY (VNx8BI, true) +ENTRY (VNx4BI, true) +ENTRY (VNx2BI, true) +ENTRY (VNx1BI, true) + +/* SEW = 8. Disable VNx64QImode when TARGET_MIN_VLEN == 32. */ +ENTRY (VNx64QI, TARGET_MIN_VLEN > 32) +ENTRY (VNx32QI, true) +ENTRY (VNx16QI, true) +ENTRY (VNx8QI, true) +ENTRY (VNx4QI, true) +ENTRY (VNx2QI, true) +ENTRY (VNx1QI, true) + +/* SEW = 16. Disable VNx32HImode when TARGET_MIN_VLEN == 32. */ +ENTRY (VNx32HI, TARGET_MIN_VLEN > 32) +ENTRY (VNx16HI, true) +ENTRY (VNx8HI, true) +ENTRY (VNx4HI, true) +ENTRY (VNx2HI, true) +ENTRY (VNx1HI, true) + +/* TODO:Disable all FP16 vector, enable them when 'zvfh' is supported. */ +ENTRY (VNx32HF, false) +ENTRY (VNx16HF, false) +ENTRY (VNx8HF, false) +ENTRY (VNx4HF, false) +ENTRY (VNx2HF, false) +ENTRY (VNx1HF, false) + +/* SEW = 32. Disable VNx16SImode when TARGET_MIN_VLEN == 32. + For single-precision floating-point, we need TARGET_VECTOR_FP32 == + RVV_ENABLE. */ +ENTRY (VNx16SI, TARGET_MIN_VLEN > 32) +ENTRY (VNx8SI, true) +ENTRY (VNx4SI, true) +ENTRY (VNx2SI, true) +ENTRY (VNx1SI, true) + +ENTRY (VNx16SF, TARGET_VECTOR_FP32 && (TARGET_MIN_VLEN > 32)) +ENTRY (VNx8SF, TARGET_VECTOR_FP32) +ENTRY (VNx4SF, TARGET_VECTOR_FP32) +ENTRY (VNx2SF, TARGET_VECTOR_FP32) +ENTRY (VNx1SF, TARGET_VECTOR_FP32) + +/* SEW = 64. Enable when TARGET_MIN_VLEN > 32. + For double-precision floating-point, we need TARGET_VECTOR_FP64 == + RVV_ENABLE. */ +ENTRY (VNx8DI, TARGET_MIN_VLEN > 32) +ENTRY (VNx4DI, TARGET_MIN_VLEN > 32) +ENTRY (VNx2DI, TARGET_MIN_VLEN > 32) +ENTRY (VNx1DI, TARGET_MIN_VLEN > 32) + +ENTRY (VNx8DF, TARGET_VECTOR_FP64 && (TARGET_MIN_VLEN > 32)) +ENTRY (VNx4DF, TARGET_VECTOR_FP64) +ENTRY (VNx2DF, TARGET_VECTOR_FP64) +ENTRY (VNx1DF, TARGET_VECTOR_FP64) + +/* SEW = 128. Disable all of them. */ +ENTRY (VNx2TI, false) +ENTRY (VNx2TF, false) + +#undef TARGET_VECTOR_FP32 +#undef TARGET_VECTOR_FP64 +#undef ENTRY diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index 4d5d887..0d61831 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -59,6 +59,7 @@ along with GCC; see the file COPYING3. If not see #include "opts.h" #include "tm-constrs.h" #include "rtl-iter.h" +#include "riscv-vector-builtins.h" /* True if X is an UNSPEC wrapper around a SYMBOL_REF or LABEL_REF. */ #define UNSPEC_ADDRESS_P(X) \ @@ -375,6 +376,11 @@ static const struct attribute_spec riscv_attribute_table[] = { "interrupt", 0, 1, false, true, true, false, riscv_handle_type_attribute, NULL }, + /* The following two are used for the built-in properties of the Vector type + and are not used externally */ + {"RVV sizeless type", 4, 4, false, true, false, true, NULL, NULL}, + {"RVV type", 0, 0, false, true, false, true, NULL, NULL}, + /* The last attribute spec is set to be NULL. */ { NULL, 0, 0, false, false, false, false, NULL, NULL } }; @@ -942,7 +948,37 @@ riscv_valid_lo_sum_p (enum riscv_symbol_type sym_type, machine_mode mode, static bool riscv_v_ext_vector_mode_p (machine_mode mode) { - return VECTOR_MODE_P (mode); +#define ENTRY(MODE, REQUIREMENT) \ + case MODE##mode: \ + return true; + switch (mode) + { +#include "riscv-vector-switch.def" + default: + return false; + } + + return false; +} + +/* Return true if mode is the RVV enabled mode. + For example: 'VNx1DI' mode is disabled if MIN_VLEN == 32. + 'VNx1SI' mode is enabled if MIN_VLEN == 32. */ + +bool +riscv_v_ext_enabled_vector_mode_p (machine_mode mode) +{ +#define ENTRY(MODE, REQUIREMENT) \ + case MODE##mode: \ + return REQUIREMENT; + switch (mode) + { +#include "riscv-vector-switch.def" + default: + return false; + } + + return false; } /* Return true if X is a valid address for machine mode MODE. If it is, @@ -6180,6 +6216,16 @@ riscv_mangle_type (const_tree type) if (TREE_CODE (type) == REAL_TYPE && TYPE_PRECISION (type) == 16) return "DF16_"; + /* Mangle all vector type for vector extension. */ + /* The mangle name follows the rule of RVV LLVM + that is "u" + length of (abi_name) + abi_name. */ + if (TYPE_NAME (type) != NULL) + { + const char *res = riscv_vector::mangle_builtin_type (type); + if (res) + return res; + } + /* Use the default mangling. */ return NULL; } @@ -6290,6 +6336,44 @@ riscv_reinit (void) #define TARGET_RUN_TARGET_SELFTESTS selftest::riscv_run_selftests #endif /* #if CHECKING_P */ +/* Implement TARGET_VECTOR_MODE_SUPPORTED_P. */ + +static bool +riscv_vector_mode_supported_p (machine_mode mode) +{ + if (TARGET_VECTOR) + return riscv_v_ext_enabled_vector_mode_p (mode); + + return false; +} + +/* Implement TARGET_VERIFY_TYPE_CONTEXT. */ + +static bool +riscv_verify_type_context (location_t loc, type_context_kind context, + const_tree type, bool silent_p) +{ + return riscv_vector::verify_type_context (loc, context, type, silent_p); +} + +/* Implement TARGET_VECTOR_ALIGNMENT. */ + +static HOST_WIDE_INT +riscv_vector_alignment (const_tree type) +{ + /* ??? Checking the mode isn't ideal, but VECTOR_BOOLEAN_TYPE_P can + be set for non-predicate vectors of booleans. Modes are the most + direct way we have of identifying real RVV predicate types. */ + /* FIXME: RVV didn't mention the alignment of bool, we uses + one byte align. */ + if (GET_MODE_CLASS (TYPE_MODE (type)) == MODE_VECTOR_BOOL) + return 8; + + widest_int min_size + = constant_lower_bound (wi::to_poly_widest (TYPE_SIZE (type))); + return wi::umin (min_size, 128).to_uhwi (); +} + /* Initialize the GCC target structure. */ #undef TARGET_ASM_ALIGNED_HI_OP #define TARGET_ASM_ALIGNED_HI_OP "\t.half\t" @@ -6502,6 +6586,15 @@ riscv_reinit (void) #define TARGET_DEFAULT_TARGET_FLAGS (MASK_BIG_ENDIAN) #endif +#undef TARGET_VECTOR_MODE_SUPPORTED_P +#define TARGET_VECTOR_MODE_SUPPORTED_P riscv_vector_mode_supported_p + +#undef TARGET_VERIFY_TYPE_CONTEXT +#define TARGET_VERIFY_TYPE_CONTEXT riscv_verify_type_context + +#undef TARGET_VECTOR_ALIGNMENT +#define TARGET_VECTOR_ALIGNMENT riscv_vector_alignment + struct gcc_target targetm = TARGET_INITIALIZER; #include "gt-riscv.h" diff --git a/gcc/config/riscv/t-riscv b/gcc/config/riscv/t-riscv index 2b82e5f..ad9be09 100644 --- a/gcc/config/riscv/t-riscv +++ b/gcc/config/riscv/t-riscv @@ -5,6 +5,16 @@ riscv-builtins.o: $(srcdir)/config/riscv/riscv-builtins.cc $(CONFIG_H) \ $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ $(srcdir)/config/riscv/riscv-builtins.cc +riscv-vector-builtins.o: $(srcdir)/config/riscv/riscv-vector-builtins.cc \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(RTL_H) $(TM_P_H) \ + memmodel.h insn-codes.h $(OPTABS_H) $(RECOG_H) $(DIAGNOSTIC_H) $(EXPR_H) \ + $(FUNCTION_H) fold-const.h gimplify.h explow.h stor-layout.h $(REGS_H) \ + alias.h langhooks.h attribs.h stringpool.h $(REGS_H) \ + $(srcdir)/config/riscv/riscv-vector-builtins.h \ + $(srcdir)/config/riscv/riscv-vector-builtins.def + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/riscv/riscv-vector-builtins.cc + riscv-sr.o: $(srcdir)/config/riscv/riscv-sr.cc $(CONFIG_H) \ $(SYSTEM_H) $(TM_H) $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ 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.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/cp/ChangeLog b/gcc/cp/ChangeLog index b9b2729..3f512c6 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,159 @@ +2022-09-28 Eugene Rozenfeld <erozen@microsoft.com> + + * module.cc (write_location): Write discriminator. + (read_location): Read discriminator. + +2022-09-28 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (DECL_NTTP_OBJECT_P): New. + (template_parm_object_p): Delete. + (build_template_parm_object): Declare. + * cxx-pretty-print.cc (pp_cx_template_argument_list): Use DECL_NTTP_OBJECT_P. + * error.cc (dump_simple_decl): Likewise. + * mangle.cc (write_template_arg): Likewise. + * pt.cc (template_parm_object_p): Delete. + (create_template_parm_object): Separated out checking from ... + (get_template_parm_object): ... this, new external entry point. + +2022-09-27 Marek Polacek <polacek@redhat.com> + + PR c++/101165 + PR c++/106882 + * call.cc (reference_binding): Check clk_implicit_rval in C++20 only. + * cp-tree.h (unparenthesized_id_or_class_member_access_p): Declare. + * pt.cc (unparenthesized_id_or_class_member_access_p): New function, + broken out of... + (do_auto_deduction): ...here. Use it. In C++23, maybe call + treat_lvalue_as_rvalue_p. + * tree.cc (xvalue_p): Check & clk_rvalueref, not == clk_rvalueref. + * typeck.cc (check_return_expr): Allow implicit move for functions + returning a reference as well, or when the return value type is not + a scalar type. + +2022-09-27 Marek Polacek <polacek@redhat.com> + + * constraint.cc (diagnose_trait_expr): Say "nothrow" without quotes + rather than in quotes. + +2022-09-27 Jonathan Wakely <jwakely@redhat.com> + + PR c++/107049 + * method.cc (is_convertible_helper): Use access check sentinel. + +2022-09-27 Jakub Jelinek <jakub@redhat.com> + + PR c++/106651 + * cp-tree.h (LAMBDA_EXPR_STATIC_P): Implement C++23 + P1169R4 - static operator(). Define. + * parser.cc (CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR): Document + that it also allows static. + (cp_parser_lambda_declarator_opt): Handle static lambda specifier. + (cp_parser_decl_specifier_seq): Allow RID_STATIC for + CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR. + * decl.cc (grok_op_properties): If operator() isn't a method, + use a different error wording, if it is static member function, + allow it (for C++20 and older with a pedwarn unless it is + a lambda function or template instantiation). + * call.cc (joust): Don't ICE if one candidate is static member + function and the other is an indirect call. If the parameter + conversion on the other candidate is user defined conversion, + ellipsis or bad conversion, make static member function candidate + a winner for that parameter. + * lambda.cc (maybe_add_lambda_conv_op): Handle static lambdas. + * error.cc (dump_lambda_function): Print static for static lambdas. + +2022-09-27 Jakub Jelinek <jakub@redhat.com> + + * cp-tree.h (struct omp_begin_assumes_data): New type. + (struct saved_scope): Add omp_begin_assumes member. + * parser.cc: Include bitmap.h. + (cp_parser_omp_assumption_clauses, cp_parser_omp_assume, + cp_parser_omp_assumes, cp_parser_omp_begin): New functions. + (cp_parser_omp_end_declare_target): Rename to ... + (cp_parser_omp_end): ... this. Handle also end assumes. + (cp_parser_omp_construct): Handle PRAGMA_OMP_ASSUME. + (cp_parser_pragma): Handle PRAGMA_OMP_ASSUME, PRAGMA_OMP_ASSUMES + and PRAGMA_OMP_BEGIN. Handle PRAGMA_OMP_END rather than + PRAGMA_OMP_END_DECLARE_TARGET and call cp_parser_omp_end + for it rather than cp_parser_omp_end_declare_target. + * pt.cc (apply_late_template_attributes): Also temporarily clear + omp_begin_assumes. + * semantics.cc (finish_translation_unit): Also diagnose + #pragma omp begin assumes without corresponding + #pragma omp end assumes. + +2022-09-27 Jakub Jelinek <jakub@redhat.com> + + * parser.cc (cp_parser_lambda_declarator_opt): Don't diagnose + conflicting specifiers here. + (cp_storage_class_name): New variable. + (cp_parser_decl_specifier_seq): When setting conflicting_specifiers_p + for the first time, diagnose which exact specifiers conflict. + (cp_parser_set_storage_class): Likewise. Move storage_class + computation earlier. + * decl.cc (grokdeclarator): Don't diagnose conflicting specifiers + here, just return error_mark_node. + +2022-09-27 Jakub Jelinek <jakub@redhat.com> + + PR c++/106652 + PR c++/85518 + * cp-tree.h (cp_compare_floating_point_conversion_ranks): Implement + P1467R9 - Extended floating-point types and standard names except + for std::bfloat16_t for now. Declare. + (extended_float_type_p): New inline function. + * mangle.cc (write_builtin_type): Mangle float{16,32,64,128}_type_node + as DF{16,32,64,128}_. Mangle float{32,64,128}x_type_node as + DF{32,64,128}x. Remove FIXED_POINT_TYPE mangling that conflicts + with that. + * typeck2.cc (check_narrowing): If one of ftype or type is extended + floating-point type, compare floating-point conversion ranks. + * parser.cc (cp_keyword_starts_decl_specifier_p): Handle + CASE_RID_FLOATN_NX. + (cp_parser_simple_type_specifier): Likewise and diagnose missing + _Float<N> or _Float<N>x support if not supported by target. + * typeck.cc (cp_compare_floating_point_conversion_ranks): New function. + (cp_common_type): If both types are REAL_TYPE and one or both are + extended floating-point types, select common type based on comparison + of floating-point conversion ranks and subranks. + (cp_build_binary_op): Diagnose operation with floating point arguments + with unordered conversion ranks. + * call.cc (standard_conversion): For floating-point conversion, if + either from or to are extended floating-point types, set conv->bad_p + for implicit conversion from larger to smaller conversion rank or + with unordered conversion ranks. + (convert_like_internal): Emit a pedwarn on such conversions. + (build_conditional_expr): Diagnose operation with floating point + arguments with unordered conversion ranks. + (convert_arg_to_ellipsis): Don't promote extended floating-point types + narrower than double to double. + (compare_ics): Implement P1467R9 [over.ics.rank]/4 changes. + +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..3506b0f 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)) @@ -1864,8 +1880,10 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags, /* Nor the reverse. */ if (!is_lvalue && !TYPE_REF_IS_RVALUE (rto) - /* Unless it's really an lvalue. */ - && !(cxx_dialect >= cxx20 + /* Unless it's really a C++20 lvalue being treated as an xvalue. + But in C++23, such an expression is just an xvalue, not a special + lvalue, so the binding is once again ill-formed. */ + && !(cxx_dialect == cxx20 && (gl_kind & clk_implicit_rval)) && (!CP_TYPE_CONST_NON_VOLATILE_P (to) || (flags & LOOKUP_NO_RVAL_BIND)) @@ -5842,6 +5860,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 +7939,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 +8585,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 +11774,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 +12263,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 +12279,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/constraint.cc b/gcc/cp/constraint.cc index 5839bfb..266ec58 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -3592,13 +3592,13 @@ diagnose_trait_expr (tree expr, tree args) switch (TRAIT_EXPR_KIND (expr)) { case CPTK_HAS_NOTHROW_ASSIGN: - inform (loc, " %qT is not %<nothrow%> copy assignable", t1); + inform (loc, " %qT is not nothrow copy assignable", t1); break; case CPTK_HAS_NOTHROW_CONSTRUCTOR: - inform (loc, " %qT is not %<nothrow%> default constructible", t1); + inform (loc, " %qT is not nothrow default constructible", t1); break; case CPTK_HAS_NOTHROW_COPY: - inform (loc, " %qT is not %<nothrow%> copy constructible", t1); + inform (loc, " %qT is not nothrow copy constructible", t1); break; case CPTK_HAS_TRIVIAL_ASSIGN: inform (loc, " %qT is not trivially copy assignable", t1); @@ -3674,7 +3674,7 @@ diagnose_trait_expr (tree expr, tree args) inform (loc, " %qT is not trivially assignable from %qT", t1, t2); break; case CPTK_IS_NOTHROW_ASSIGNABLE: - inform (loc, " %qT is not %<nothrow%> assignable from %qT", t1, t2); + inform (loc, " %qT is not nothrow assignable from %qT", t1, t2); break; case CPTK_IS_CONSTRUCTIBLE: if (!t2) @@ -3690,9 +3690,9 @@ diagnose_trait_expr (tree expr, tree args) break; case CPTK_IS_NOTHROW_CONSTRUCTIBLE: if (!t2) - inform (loc, " %qT is not %<nothrow%> default constructible", t1); + inform (loc, " %qT is not nothrow default constructible", t1); else - inform (loc, " %qT is not %<nothrow%> constructible from %qE", t1, t2); + inform (loc, " %qT is not nothrow constructible from %qE", t1, t2); break; case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS: inform (loc, " %qT does not have unique object representations", t1); @@ -3701,7 +3701,7 @@ diagnose_trait_expr (tree expr, tree args) inform (loc, " %qT is not convertible from %qE", t2, t1); break; case CPTK_IS_NOTHROW_CONVERTIBLE: - inform (loc, " %qT is not %<nothrow%> convertible from %qE", t2, t1); + inform (loc, " %qT is not nothrow convertible from %qE", t2, t1); break; case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY: inform (loc, " %qT is not a reference that binds to a temporary " diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index e4d8920..d0f1b18 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). @@ -517,6 +518,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; CALL_EXPR_REVERSE_ARGS (in CALL_EXPR, AGGR_INIT_EXPR) CONSTRUCTOR_PLACEHOLDER_BOUNDARY (in CONSTRUCTOR) OVL_EXPORT_P (in OVERLOAD) + DECL_NTTP_OBJECT_P (in VAR_DECL) 6: TYPE_MARKED_P (in _TYPE) DECL_NONTRIVIALLY_INITIALIZED_P (in VAR_DECL) RANGE_FOR_IVDEP (in RANGE_FOR_STMT) @@ -1490,6 +1492,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 +1840,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 +1891,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; }; @@ -3538,6 +3549,10 @@ struct GTY(()) lang_decl { #define DECL_TINFO_P(NODE) \ TREE_LANG_FLAG_4 (TREE_CHECK2 (NODE,VAR_DECL,TYPE_DECL)) +/* true iff VAR_DECL node NODE is a NTTP object decl. */ +#define DECL_NTTP_OBJECT_P(NODE) \ + TREE_LANG_FLAG_5 (TREE_CHECK (NODE,VAR_DECL)) + /* 1 iff VAR_DECL node NODE is virtual table or VTT. We forward to DECL_VIRTUAL_P from the common code, as that has the semantics we need. But we want a more descriptive name. */ @@ -7282,6 +7297,7 @@ extern tree make_constrained_decltype_auto (tree, tree); extern tree make_template_placeholder (tree); extern bool template_placeholder_p (tree); extern bool ctad_template_p (tree); +extern bool unparenthesized_id_or_class_member_access_p (tree); extern tree do_auto_deduction (tree, tree, tree, tsubst_flags_t = tf_warning_or_error, @@ -7403,7 +7419,7 @@ extern bool alias_type_or_template_p (tree); enum { nt_opaque = false, nt_transparent = true }; extern tree alias_template_specialization_p (const_tree, bool); extern tree dependent_alias_template_spec_p (const_tree, bool); -extern bool template_parm_object_p (const_tree); +extern tree get_template_parm_object (tree expr, tree mangle); extern tree tparm_object_argument (tree); extern bool explicit_class_specialization_p (tree); extern bool push_tinst_level (tree); @@ -7946,6 +7962,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 +8705,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/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc index e18143e3..bbd51bb 100644 --- a/gcc/cp/cxx-pretty-print.cc +++ b/gcc/cp/cxx-pretty-print.cc @@ -1956,7 +1956,7 @@ pp_cxx_template_argument_list (cxx_pretty_printer *pp, tree t) if (TYPE_P (arg) || (TREE_CODE (arg) == TEMPLATE_DECL && TYPE_P (DECL_TEMPLATE_RESULT (arg)))) pp->type_id (arg); - else if (template_parm_object_p (arg)) + else if (TREE_CODE (arg) == VAR_DECL && DECL_NTTP_OBJECT_P (arg)) pp->expression (DECL_INITIAL (arg)); else pp->expression (arg); 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..53904e3 100644 --- a/gcc/cp/error.cc +++ b/gcc/cp/error.cc @@ -1129,7 +1129,7 @@ dump_global_iord (cxx_pretty_printer *pp, tree t) static void dump_simple_decl (cxx_pretty_printer *pp, tree t, tree type, int flags) { - if (template_parm_object_p (t)) + if (TREE_CODE (t) == VAR_DECL && DECL_NTTP_OBJECT_P (t)) return dump_expr (pp, DECL_INITIAL (t), flags); if (flags & TFF_DECL_SPECIFIERS) @@ -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..1a45585 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 (); } @@ -3711,7 +3672,7 @@ write_template_arg (tree node) } } - if (template_parm_object_p (node)) + if (TREE_CODE (node) == VAR_DECL && DECL_NTTP_OBJECT_P (node)) /* We want to mangle the argument, not the var we stored it in. */ node = tparm_object_argument (node); diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc index 9f917f1..55af5c4 100644 --- a/gcc/cp/method.cc +++ b/gcc/cp/method.cc @@ -2246,6 +2246,7 @@ is_convertible_helper (tree from, tree to) return integer_one_node; cp_unevaluated u; tree expr = build_stub_object (from); + deferring_access_check_sentinel acs (dk_no_deferred); return perform_implicit_conversion (to, expr, tf_none); } diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 7496df5..d965017 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -15777,6 +15777,8 @@ module_state::write_location (bytes_out &sec, location_t loc) range.m_start = UNKNOWN_LOCATION; write_location (sec, range.m_start); write_location (sec, range.m_finish); + unsigned discriminator = get_discriminator_from_adhoc_loc (line_table, loc); + sec.u (discriminator); } else if (loc >= LINEMAPS_MACRO_LOWEST_LOCATION (line_table)) { @@ -15902,8 +15904,9 @@ module_state::read_location (bytes_in &sec) const if (range.m_start == UNKNOWN_LOCATION) range.m_start = locus; range.m_finish = read_location (sec); + unsigned discriminator = sec.u (); if (locus != loc && range.m_start != loc && range.m_finish != loc) - locus = get_combined_adhoc_loc (line_table, locus, range, NULL); + locus = get_combined_adhoc_loc (line_table, locus, range, NULL, discriminator); } break; 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 1f088fe..c7adaef 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -7112,16 +7112,6 @@ unify_template_argument_mismatch (bool explain_p, tree parm, tree arg) return unify_invalid (explain_p); } -/* True if T is a C++20 template parameter object to store the argument for a - template parameter of class type. */ - -bool -template_parm_object_p (const_tree t) -{ - return (TREE_CODE (t) == VAR_DECL && DECL_ARTIFICIAL (t) && DECL_NAME (t) - && startswith (IDENTIFIER_POINTER (DECL_NAME (t)), "_ZTA")); -} - /* Subroutine of convert_nontype_argument, to check whether EXPR, as an argument for TYPE, points to an unsuitable object. @@ -7256,16 +7246,11 @@ invalid_tparm_referent_p (tree type, tree expr, tsubst_flags_t complain) } -/* The template arguments corresponding to template parameter objects of types - that contain pointers to members. */ - -static GTY(()) hash_map<tree, tree> *tparm_obj_values; - /* Return a VAR_DECL for the C++20 template parameter object corresponding to template argument EXPR. */ static tree -get_template_parm_object (tree expr, tsubst_flags_t complain) +create_template_parm_object (tree expr, tsubst_flags_t complain) { if (TREE_CODE (expr) == TARGET_EXPR) expr = TARGET_EXPR_INITIAL (expr); @@ -7283,13 +7268,27 @@ get_template_parm_object (tree expr, tsubst_flags_t complain) /* This is no longer a compound literal. */ gcc_assert (!TREE_HAS_CONSTRUCTOR (expr)); - tree name = mangle_template_parm_object (expr); + return get_template_parm_object (expr, mangle_template_parm_object (expr)); +} + +/* The template arguments corresponding to template parameter objects of types + that contain pointers to members. */ + +static GTY(()) hash_map<tree, tree> *tparm_obj_values; + +/* Find or build an nttp object for (already-validated) EXPR with name + NAME. */ + +tree +get_template_parm_object (tree expr, tree name) +{ tree decl = get_global_binding (name); if (decl) return decl; tree type = cp_build_qualified_type (TREE_TYPE (expr), TYPE_QUAL_CONST); decl = create_temporary_var (type); + DECL_NTTP_OBJECT_P (decl) = true; DECL_CONTEXT (decl) = NULL_TREE; TREE_STATIC (decl) = true; DECL_DECLARED_CONSTEXPR_P (decl) = true; @@ -7776,7 +7775,7 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) /* Replace the argument with a reference to the corresponding template parameter object. */ if (!val_dep_p) - expr = get_template_parm_object (expr, complain); + expr = create_template_parm_object (expr, complain); if (expr == error_mark_node) return NULL_TREE; } @@ -11945,6 +11944,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); @@ -30407,6 +30407,26 @@ do_class_deduction (tree ptype, tree tmpl, tree init, cp_type_quals (ptype)); } +/* Return true if INIT is an unparenthesized id-expression or an + unparenthesized class member access. Used for the argument of + decltype(auto). */ + +bool +unparenthesized_id_or_class_member_access_p (tree init) +{ + STRIP_ANY_LOCATION_WRAPPER (init); + + /* We need to be able to tell '(r)' and 'r' apart (when it's of + reference type). Only the latter is an id-expression. */ + if (REFERENCE_REF_P (init) + && !REF_PARENTHESIZED_P (init)) + init = TREE_OPERAND (init, 0); + return (DECL_P (init) + || ((TREE_CODE (init) == COMPONENT_REF + || TREE_CODE (init) == SCOPE_REF) + && !REF_PARENTHESIZED_P (init))); +} + /* Replace occurrences of 'auto' in TYPE with the appropriate type deduced from INIT. AUTO_NODE is the TEMPLATE_TYPE_PARM used for 'auto' in TYPE. The CONTEXT determines the context in which auto deduction is performed @@ -30442,6 +30462,23 @@ do_auto_deduction (tree type, tree init, tree auto_node, auto_node. */ complain &= ~tf_partial; + /* In C++23, we must deduce the type to int&& for code like + decltype(auto) f(int&& x) { return (x); } + or + auto&& f(int x) { return x; } + so we use treat_lvalue_as_rvalue_p. But don't do it for + decltype(auto) f(int x) { return x; } + where we should deduce 'int' rather than 'int&&'; transmogrifying + INIT to an rvalue would break that. */ + tree r; + if (cxx_dialect >= cxx23 + && context == adc_return_type + && (!AUTO_IS_DECLTYPE (auto_node) + || !unparenthesized_id_or_class_member_access_p (init)) + && (r = treat_lvalue_as_rvalue_p (maybe_undo_parenthesized_ref (init), + /*return*/true))) + init = r; + if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node)) /* C++17 class template argument deduction. */ return do_class_deduction (type, tmpl, init, flags, complain); @@ -30503,18 +30540,7 @@ do_auto_deduction (tree type, tree init, tree auto_node, } else if (AUTO_IS_DECLTYPE (auto_node)) { - /* Figure out if INIT is an unparenthesized id-expression or an - unparenthesized class member access. */ - tree stripped_init = tree_strip_any_location_wrapper (init); - /* We need to be able to tell '(r)' and 'r' apart (when it's of - reference type). Only the latter is an id-expression. */ - if (REFERENCE_REF_P (stripped_init) - && !REF_PARENTHESIZED_P (stripped_init)) - stripped_init = TREE_OPERAND (stripped_init, 0); - const bool id = (DECL_P (stripped_init) - || ((TREE_CODE (stripped_init) == COMPONENT_REF - || TREE_CODE (stripped_init) == SCOPE_REF) - && !REF_PARENTHESIZED_P (stripped_init))); + const bool id = unparenthesized_id_or_class_member_access_p (init); tree deduced = finish_decltype_type (init, id, complain); deduced = canonicalize_type_argument (deduced, complain); if (deduced == error_mark_node) 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/tree.cc b/gcc/cp/tree.cc index d0bd41a..ea4dfc6 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -382,7 +382,7 @@ obvalue_p (const_tree ref) bool xvalue_p (const_tree ref) { - return (lvalue_kind (ref) == clk_rvalueref); + return (lvalue_kind (ref) & clk_rvalueref); } /* True if REF is a bit-field. */ diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index 22d834d..5f16c4d 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, @@ -10872,9 +11042,13 @@ check_return_expr (tree retval, bool *no_warning) the conditions for the named return value optimization. */ bool converted = false; tree moved; - /* This is only interesting for class type. */ - if (CLASS_TYPE_P (functype) - && (moved = treat_lvalue_as_rvalue_p (retval, /*return*/true))) + /* Until C++23, this was only interesting for class type, but in C++23, + we should do the below when we're converting rom/to a class/reference + (a non-scalar type). */ + if ((cxx_dialect < cxx23 + ? CLASS_TYPE_P (functype) + : !SCALAR_TYPE_P (functype) || !SCALAR_TYPE_P (TREE_TYPE (retval))) + && (moved = treat_lvalue_as_rvalue_p (retval, /*return*/true))) { if (cxx_dialect < cxx20) { diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc index 739097a..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) { diff --git a/gcc/cselib.cc b/gcc/cselib.cc index 6a56097..9b582e5 100644 --- a/gcc/cselib.cc +++ b/gcc/cselib.cc @@ -1569,6 +1569,26 @@ new_cselib_val (unsigned int hash, machine_mode mode, rtx x) e->locs = 0; e->next_containing_mem = 0; + scalar_int_mode int_mode; + if (REG_P (x) && is_int_mode (mode, &int_mode) + && REG_VALUES (REGNO (x)) != NULL + && (!cselib_current_insn || !DEBUG_INSN_P (cselib_current_insn))) + { + rtx copy = shallow_copy_rtx (x); + scalar_int_mode narrow_mode_iter; + FOR_EACH_MODE_UNTIL (narrow_mode_iter, int_mode) + { + PUT_MODE_RAW (copy, narrow_mode_iter); + cselib_val *v = cselib_lookup (copy, narrow_mode_iter, 0, VOIDmode); + if (v) + { + rtx sub = lowpart_subreg (narrow_mode_iter, e->val_rtx, int_mode); + if (sub) + new_elt_loc_list (v, sub); + } + } + } + if (dump_file && (dump_flags & TDF_CSELIB)) { fprintf (dump_file, "cselib value %u:%u ", e->uid, hash); diff --git a/gcc/d/ChangeLog b/gcc/d/ChangeLog index 9bb29d3..434c1c6 100644 --- a/gcc/d/ChangeLog +++ b/gcc/d/ChangeLog @@ -1,3 +1,15 @@ +2022-09-27 Iain Buclaw <ibuclaw@gdcproject.org> + + * dmd/MERGE: Merge upstream dmd d579c467c1. + * decl.cc (layout_struct_initializer): Update for new front-end + interface. + * expr.cc (ExprVisitor::visit (AssignExp *)): Remove lowering of array + assignments. + (ExprVisitor::visit (NewExp *)): Add new lowering of new'ing + associative arrays to an _aaNew() library call. + * runtime.def (ARRAYSETASSIGN): Remove. + (AANEW): Define. + 2022-09-15 Richard Biener <rguenther@suse.de> * d-builtins.cc (d_build_c_type_nodes): Do not initialize 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/invoke.texi b/gcc/doc/invoke.texi index 4a01cfb..d39dd82 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -2890,10 +2890,17 @@ change in version 12. Version 14, which first appeared in G++ 10, corrects the mangling of the nullptr expression. -Version 15, which first appeared in G++ 11, changes the mangling of +Version 15, which first appeared in G++ 10.3, corrects G++ 10 ABI +tag regression. + +Version 16, which first appeared in G++ 11, changes the mangling of @code{__alignof__} to be distinct from that of @code{alignof}, and dependent operator names. +Version 17, which first appeared in G++ 12, fixes layout of classes +that inherit from aggregate classes with default member initializers +in C++14 and up. + See also @option{-Wabi}. @item -fabi-compat-version=@var{n} @@ -2903,7 +2910,7 @@ works around mangling changes by creating an alias with the correct mangled name when defining a symbol with an incorrect mangled name. This switch specifies which ABI version to use for the alias. -With @option{-fabi-version=0} (the default), this defaults to 11 (GCC 7 +With @option{-fabi-version=0} (the default), this defaults to 13 (GCC 8.2 compatibility). If another ABI version is explicitly selected, this defaults to 0. For compatibility with GCC versions 3.2 through 4.9, use @option{-fabi-compat-version=2}. diff --git a/gcc/final.cc b/gcc/final.cc index c0bfdf6..eea5722 100644 --- a/gcc/final.cc +++ b/gcc/final.cc @@ -118,18 +118,10 @@ static int last_columnnum; /* Discriminator written to assembly. */ static int last_discriminator; -/* Discriminator to be written to assembly for current instruction. +/* Compute discriminator to be written to assembly for current instruction. Note: actual usage depends on loc_discriminator_kind setting. */ -static int discriminator; static inline int compute_discriminator (location_t loc); -/* Discriminator identifying current basic block among others sharing - the same locus. */ -static int bb_discriminator; - -/* Basic block discriminator for previous instruction. */ -static int last_bb_discriminator; - /* Highest line number in current block. */ static int high_block_linenum; @@ -1688,8 +1680,7 @@ final_start_function_1 (rtx_insn **firstp, FILE *file, int *seen, last_filename = LOCATION_FILE (prologue_location); last_linenum = LOCATION_LINE (prologue_location); last_columnnum = LOCATION_COLUMN (prologue_location); - last_discriminator = discriminator = 0; - last_bb_discriminator = bb_discriminator = 0; + last_discriminator = 0; force_source_line = false; high_block_linenum = high_function_linenum = last_linenum; @@ -2234,7 +2225,6 @@ final_scan_insn_1 (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, if (targetm.asm_out.unwind_emit) targetm.asm_out.unwind_emit (asm_out_file, insn); - bb_discriminator = NOTE_BASIC_BLOCK (insn)->discriminator; break; case NOTE_INSN_EH_REGION_BEG: @@ -2939,7 +2929,7 @@ compute_discriminator (location_t loc) int discriminator; if (!decl_to_instance_map) - discriminator = bb_discriminator; + discriminator = get_discriminator_from_loc (loc); else { tree block = LOCATION_BLOCK (loc); @@ -2963,6 +2953,13 @@ compute_discriminator (location_t loc) return discriminator; } +/* Return discriminator of the statement that produced this insn. */ +int +insn_discriminator (const rtx_insn *insn) +{ + return compute_discriminator (INSN_LOCATION (insn)); +} + /* Return whether a source line note needs to be emitted before INSN. Sets IS_STMT to TRUE if the line should be marked as a possible breakpoint location. */ @@ -2972,6 +2969,7 @@ notice_source_line (rtx_insn *insn, bool *is_stmt) { const char *filename; int linenum, columnnum; + int discriminator; if (NOTE_MARKER_P (insn)) { @@ -3001,7 +2999,7 @@ notice_source_line (rtx_insn *insn, bool *is_stmt) filename = xloc.file; linenum = xloc.line; columnnum = xloc.column; - discriminator = compute_discriminator (INSN_LOCATION (insn)); + discriminator = insn_discriminator (insn); } else { diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 6985e62..dcbfd54 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,10 @@ +2022-09-27 Harald Anlauf <anlauf@gmx.de> + + PR fortran/107054 + * simplify.cc (gfc_simplify_unpack): Replace assert by condition + that terminates simplification when there are not enough elements + in the constructor of argument VECTOR. + 2022-09-25 Mikael Morin <mikael@gcc.gnu.org> PR fortran/41453 diff --git a/gcc/fortran/simplify.cc b/gcc/fortran/simplify.cc index c0fbd0e..6ac92cf 100644 --- a/gcc/fortran/simplify.cc +++ b/gcc/fortran/simplify.cc @@ -8458,9 +8458,16 @@ gfc_simplify_unpack (gfc_expr *vector, gfc_expr *mask, gfc_expr *field) { if (mask_ctor->expr->value.logical) { - gcc_assert (vector_ctor); - e = gfc_copy_expr (vector_ctor->expr); - vector_ctor = gfc_constructor_next (vector_ctor); + if (vector_ctor) + { + e = gfc_copy_expr (vector_ctor->expr); + vector_ctor = gfc_constructor_next (vector_ctor); + } + else + { + gfc_free_expr (result); + return NULL; + } } else if (field->expr_type == EXPR_ARRAY) e = gfc_copy_expr (field_ctor->expr); diff --git a/gcc/gimple-pretty-print.cc b/gcc/gimple-pretty-print.cc index f18baec..a87e2ae 100644 --- a/gcc/gimple-pretty-print.cc +++ b/gcc/gimple-pretty-print.cc @@ -2875,8 +2875,6 @@ dump_gimple_bb_header (FILE *outf, basic_block bb, int indent, indent, "", get_lineno (gsi_stmt (gsi))); break; } - if (bb->discriminator) - fprintf (outf, ", discriminator %i", bb->discriminator); fputc ('\n', outf); } } diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc index d7c6dfa..3f5e585 100644 --- a/gcc/gimple-range-op.cc +++ b/gcc/gimple-range-op.cc @@ -397,6 +397,14 @@ public: { if (lh.undefined_p ()) return false; + // Calculating the popcount of a singleton is trivial. + if (lh.singleton_p ()) + { + wide_int nz = lh.get_nonzero_bits (); + wide_int pop = wi::shwi (wi::popcount (nz), TYPE_PRECISION (type)); + r.set (type, pop, pop); + return true; + } // __builtin_ffs* and __builtin_popcount* return [0, prec]. int prec = TYPE_PRECISION (lh.type ()); // If arg is non-zero, then ffs or popcount are non-zero. diff --git a/gcc/gimple-streamer-in.cc b/gcc/gimple-streamer-in.cc index e7f3256..ea8891e 100644 --- a/gcc/gimple-streamer-in.cc +++ b/gcc/gimple-streamer-in.cc @@ -267,7 +267,6 @@ input_bb (class lto_input_block *ib, enum LTO_tags tag, bb->count = bb->count.apply_scale (count_materialization_scale, REG_BR_PROB_BASE); bb->flags = streamer_read_hwi (ib); - bb->discriminator = streamer_read_hwi (ib); /* LTO_bb1 has statements. LTO_bb0 does not. */ if (tag == LTO_bb0) diff --git a/gcc/gimple-streamer-out.cc b/gcc/gimple-streamer-out.cc index 3336525..4583254 100644 --- a/gcc/gimple-streamer-out.cc +++ b/gcc/gimple-streamer-out.cc @@ -208,7 +208,6 @@ output_bb (struct output_block *ob, basic_block bb, struct function *fn) streamer_write_uhwi (ob, bb->index); bb->count.stream_out (ob); streamer_write_hwi (ob, bb->flags); - streamer_write_hwi (ob, bb->discriminator); if (!gsi_end_p (bsi) || phi_nodes (bb)) { diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index f7a7985..4793c82 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -42efec8c126cf3787bc7c89d9c7f224eff7c5a21 +8f1a91aeff400d572857895b7f5e863ec5a4d93e The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/input.cc b/gcc/input.cc index 060ca16..a28abfa 100644 --- a/gcc/input.cc +++ b/gcc/input.cc @@ -1082,7 +1082,8 @@ make_location (location_t caret, location_t start, location_t finish) location_t combined_loc = COMBINE_LOCATION_DATA (line_table, pure_loc, src_range, - NULL); + NULL, + 0); return combined_loc; } @@ -1092,7 +1093,7 @@ location_t make_location (location_t caret, source_range src_range) { location_t pure_loc = get_pure_location (caret); - return COMBINE_LOCATION_DATA (line_table, pure_loc, src_range, NULL); + return COMBINE_LOCATION_DATA (line_table, pure_loc, src_range, NULL, 0); } /* An expanded_location stores the column in byte units. This function @@ -1766,6 +1767,37 @@ get_location_within_string (cpp_reader *pfile, return NULL; } +/* Associate the DISCRIMINATOR with LOCUS, and return a new locus. */ + +location_t +location_with_discriminator (location_t locus, int discriminator) +{ + tree block = LOCATION_BLOCK (locus); + source_range src_range = get_range_from_loc (line_table, locus); + locus = get_pure_location (locus); + + if (locus == UNKNOWN_LOCATION) + return locus; + + return COMBINE_LOCATION_DATA (line_table, locus, src_range, block, discriminator); +} + +/* Return TRUE if LOCUS represents a location with a discriminator. */ + +bool +has_discriminator (location_t locus) +{ + return get_discriminator_from_loc (locus) != 0; +} + +/* Return the discriminator for LOCUS. */ + +int +get_discriminator_from_loc (location_t locus) +{ + return get_discriminator_from_loc (line_table, locus); +} + #if CHECKING_P namespace selftest { diff --git a/gcc/input.h b/gcc/input.h index f1ae3ae..11c571d 100644 --- a/gcc/input.h +++ b/gcc/input.h @@ -165,6 +165,10 @@ extern location_t expansion_point_location (location_t); extern location_t input_location; +extern location_t location_with_discriminator (location_t, int); +extern bool has_discriminator (location_t); +extern int get_discriminator_from_loc (location_t); + #define LOCATION_FILE(LOC) ((expand_location (LOC)).file) #define LOCATION_LINE(LOC) ((expand_location (LOC)).line) #define LOCATION_COLUMN(LOC)((expand_location (LOC)).column) diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc index 543a933..66bba71 100644 --- a/gcc/ipa-cp.cc +++ b/gcc/ipa-cp.cc @@ -3338,9 +3338,9 @@ good_cloning_opportunity_p (struct cgraph_node *node, sreal time_benefit, ipa_node_params *info = ipa_node_params_sum->get (node); int eval_threshold = opt_for_fn (node->decl, param_ipa_cp_eval_threshold); - if (count_sum > profile_count::zero ()) + if (count_sum.nonzero_p ()) { - gcc_assert (base_count > profile_count::zero ()); + gcc_assert (base_count.nonzero_p ()); sreal factor = count_sum.probability_in (base_count).to_sreal (); sreal evaluation = (time_benefit * factor) / size_cost; evaluation = incorporate_penalties (node, info, evaluation); diff --git a/gcc/lto-streamer-in.cc b/gcc/lto-streamer-in.cc index a7dad70..fa89634 100644 --- a/gcc/lto-streamer-in.cc +++ b/gcc/lto-streamer-in.cc @@ -409,6 +409,8 @@ lto_location_cache::cmp_loc (const void *pa, const void *pb) return a->line - b->line; if (a->col != b->col) return a->col - b->col; + if (a->discr != b->discr) + return a->discr - b->discr; if ((a->block == NULL_TREE) != (b->block == NULL_TREE)) return a->block ? 1 : -1; if (a->block) @@ -460,6 +462,8 @@ lto_location_cache::apply_location_cache () current_loc = linemap_position_for_column (line_table, loc.col); if (loc.block) current_loc = set_block (current_loc, loc.block); + if (loc.discr) + current_loc = location_with_discriminator (current_loc, loc.discr); } else if (current_block != loc.block) { @@ -467,12 +471,17 @@ lto_location_cache::apply_location_cache () current_loc = set_block (current_loc, loc.block); else current_loc = LOCATION_LOCUS (current_loc); + if (loc.discr) + current_loc = location_with_discriminator (current_loc, loc.discr); } + else if (current_discr != loc.discr) + current_loc = location_with_discriminator (current_loc, loc.discr); *loc.loc = current_loc; current_line = loc.line; prev_file = current_file = loc.file; current_col = loc.col; current_block = loc.block; + current_discr = loc.discr; } loc_cache.truncate (0); accepted_length = 0; @@ -512,6 +521,7 @@ lto_location_cache::input_location_and_block (location_t *loc, static int stream_col; static bool stream_sysp; static tree stream_block; + static unsigned stream_discr; static const char *stream_relative_path_prefix; gcc_assert (current_cache == this); @@ -538,6 +548,7 @@ lto_location_cache::input_location_and_block (location_t *loc, *loc = RESERVED_LOCATION_COUNT; bool line_change = bp_unpack_value (bp, 1); bool column_change = bp_unpack_value (bp, 1); + bool discr_change = bp_unpack_value (bp, 1); if (file_change) { @@ -563,6 +574,9 @@ lto_location_cache::input_location_and_block (location_t *loc, if (column_change) stream_col = bp_unpack_var_len_unsigned (bp); + if (discr_change) + stream_discr = bp_unpack_var_len_unsigned (bp); + tree block = NULL_TREE; if (ib) { @@ -578,7 +592,8 @@ lto_location_cache::input_location_and_block (location_t *loc, if (current_file == stream_file && current_line == stream_line && current_col == stream_col - && current_sysp == stream_sysp) + && current_sysp == stream_sysp + && current_discr == stream_discr) { if (current_block == block) *loc = current_loc; @@ -590,7 +605,7 @@ lto_location_cache::input_location_and_block (location_t *loc, } struct cached_location entry - = {stream_file, loc, stream_line, stream_col, stream_sysp, block}; + = {stream_file, loc, stream_line, stream_col, stream_sysp, block, stream_discr}; loc_cache.safe_push (entry); } diff --git a/gcc/lto-streamer-out.cc b/gcc/lto-streamer-out.cc index 1bc3f55..2e7af03 100644 --- a/gcc/lto-streamer-out.cc +++ b/gcc/lto-streamer-out.cc @@ -67,6 +67,7 @@ clear_line_info (struct output_block *ob) so that the first location with block in a function etc. always streams a change_block bit and the first block. */ ob->current_block = void_node; + ob->current_discr = UINT_MAX; } @@ -194,6 +195,7 @@ lto_output_location_1 (struct output_block *ob, struct bitpack_d *bp, if (loc >= RESERVED_LOCATION_COUNT) { expanded_location xloc = expand_location (loc); + unsigned discr = get_discriminator_from_loc (orig_loc); if (ob->reset_locus) { @@ -216,6 +218,7 @@ lto_output_location_1 (struct output_block *ob, struct bitpack_d *bp, bp_pack_value (bp, ob->current_line != xloc.line, 1); bp_pack_value (bp, ob->current_col != xloc.column, 1); + bp_pack_value (bp, ob->current_discr != discr, 1); if (ob->current_file != xloc.file) { @@ -242,6 +245,10 @@ lto_output_location_1 (struct output_block *ob, struct bitpack_d *bp, if (ob->current_col != xloc.column) bp_pack_var_len_unsigned (bp, xloc.column); ob->current_col = xloc.column; + + if (ob->current_discr != discr) + bp_pack_var_len_unsigned (bp, discr); + ob->current_discr = discr; } else bp_pack_int_in_range (bp, 0, RESERVED_LOCATION_COUNT + 1, loc); diff --git a/gcc/lto-streamer.h b/gcc/lto-streamer.h index 597e9e4..2e3abd9 100644 --- a/gcc/lto-streamer.h +++ b/gcc/lto-streamer.h @@ -311,6 +311,7 @@ private: int line, col; bool sysp; tree block; + unsigned discr; }; /* The location cache. */ @@ -333,6 +334,7 @@ private: bool current_sysp; location_t current_loc; tree current_block; + unsigned current_discr; }; /* Structure used as buffer for reading an LTO file. */ @@ -723,6 +725,7 @@ struct output_block bool reset_locus; bool emit_pwd; tree current_block; + unsigned current_discr; /* Cache of nodes written in this section. */ struct streamer_tree_cache_d *writer_cache; diff --git a/gcc/print-rtl.cc b/gcc/print-rtl.cc index 60c8454..e115f98 100644 --- a/gcc/print-rtl.cc +++ b/gcc/print-rtl.cc @@ -453,6 +453,10 @@ rtx_writer::print_rtx_operand_code_i (const_rtx in_rtx, int idx) expanded_location xloc = insn_location (in_insn); fprintf (m_outfile, " \"%s\":%i:%i", xloc.file, xloc.line, xloc.column); + int discriminator = insn_discriminator (in_insn); + if (discriminator) + fprintf (m_outfile, " discrim %d", discriminator); + } #endif } @@ -3369,6 +3369,7 @@ extern int insn_line (const rtx_insn *); extern const char * insn_file (const rtx_insn *); extern tree insn_scope (const rtx_insn *); extern expanded_location insn_location (const rtx_insn *); +extern int insn_discriminator (const rtx_insn *); extern location_t prologue_location, epilogue_location; /* In jump.cc */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 0e7cd64e..9007c43 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,233 @@ +2022-09-28 Eugene Rozenfeld <erozen@microsoft.com> + + * c-c++-common/ubsan/pr85213.c: Pass -gno-statement-frontiers. + +2022-09-28 H.J. Lu <hjl.tools@gmail.com> + + PR target/107061 + * gcc.target/i386/keylocker-encodekey128.c: Don't check + XMM4-XMM6. + * gcc.target/i386/keylocker-encodekey256.c: Likewise. + +2022-09-28 Ju-Zhe Zhong <juzhe.zhong@rivai.ai> + + * gcc.target/riscv/rvv/base/abi-1.c: New test. + * gcc.target/riscv/rvv/base/abi-2.c: New test. + * gcc.target/riscv/rvv/base/abi-3.c: New test. + * gcc.target/riscv/rvv/base/abi-4.c: New test. + * gcc.target/riscv/rvv/base/abi-5.c: New test. + * gcc.target/riscv/rvv/base/abi-6.c: New test. + * gcc.target/riscv/rvv/base/abi-7.c: New test. + * gcc.target/riscv/rvv/rvv.exp: New test. + +2022-09-28 Andrea Corallo <andrea.corallo@arm.com> + + * gcc.target/arm/attr-crypto.c: Update test. + +2022-09-28 Torbjörn SVENSSON <torbjorn.svensson@foss.st.com> + Yvan ROUX <yvan.roux@foss.st.com> + + * gcc.target/aarch64/advsimd-intrinsics/vld1x2.c: Rephrase + to unimplemented. + * gcc.target/aarch64/advsimd-intrinsics/vld1x3.c: Likewise. + * gcc.target/aarch64/advsimd-intrinsics/vld1x4.c: Likewise. + * gcc.target/aarch64/advsimd-intrinsics/vst1x2.c: Replace + dg-xfail-if with dg-skip-if. + * gcc.target/aarch64/advsimd-intrinsics/vst1x3.c: Likewise. + * gcc.target/aarch64/advsimd-intrinsics/vst1x4.c: Likewise. + +2022-09-28 H.J. Lu <hjl.tools@gmail.com> + + PR middle-end/58245 + * g++.dg/fstack-protector-strong.C: Adjusted. + * g++.dg/pr58245-1.C: New test. + +2022-09-28 Eugene Rozenfeld <erozen@microsoft.com> + + * gcc.dg/tree-prof/cold_partition_label.c: Don't check for hot/cold splitting with AutoFDO. + * gcc.dg/tree-prof/section-attr-1.c: Don't check for hot/cold splitting with AutoFDO. + * gcc.dg/tree-prof/section-attr-2.c: Don't check for hot/cold splitting with AutoFDO. + * gcc.dg/tree-prof/section-attr-3.c: Don't check for hot/cold splitting with AutoFDO. + +2022-09-27 Marek Polacek <polacek@redhat.com> + + PR c++/101165 + PR c++/106882 + * g++.dg/conversion/pr41426.C: Add dg-error for C++23. + * g++.dg/cpp0x/elision_weak.C: Likewise. + * g++.dg/cpp0x/move-return3.C: Only link in c++20_down. + * g++.dg/cpp1y/decltype-auto2.C: Add dg-error for C++23. + * g++.dg/cpp1y/lambda-generic-89419.C: Likewise. + * g++.dg/cpp23/feat-cxx2b.C: Test __cpp_implicit_move. + * g++.dg/gomp/pr56217.C: Only compile in c++20_down. + * g++.dg/warn/Wno-return-local-addr.C: Add dg-error for C++23. + * g++.dg/warn/Wreturn-local-addr.C: Adjust dg-error. + * g++.old-deja/g++.brendan/crash55.C: Add dg-error for C++23. + * g++.old-deja/g++.jason/temporary2.C: Likewise. + * g++.old-deja/g++.mike/p2846b.C: Adjust. + * g++.dg/cpp1y/decltype-auto6.C: New test. + * g++.dg/cpp23/decltype1.C: New test. + * g++.dg/cpp23/decltype2.C: New test. + * g++.dg/cpp23/elision1.C: New test. + * g++.dg/cpp23/elision2.C: New test. + * g++.dg/cpp23/elision3.C: New test. + * g++.dg/cpp23/elision4.C: New test. + * g++.dg/cpp23/elision5.C: New test. + * g++.dg/cpp23/elision6.C: New test. + * g++.dg/cpp23/elision7.C: New test. + +2022-09-27 Harald Anlauf <anlauf@gmx.de> + + PR fortran/107054 + * gfortran.dg/pr107054.f90: New test. + +2022-09-27 Aldy Hernandez <aldyh@redhat.com> + + * gcc.dg/tree-ssa/popcount6b.c: New test. + +2022-09-27 Marek Polacek <polacek@redhat.com> + + * g++.dg/cpp2a/concepts-traits3.C: Adjust expected diagnostics. + +2022-09-27 Jonathan Wakely <jwakely@redhat.com> + + PR c++/107049 + * g++.dg/ext/is_convertible4.C: New test. + * g++.dg/ext/is_nothrow_convertible4.C: New test. + +2022-09-27 Aldy Hernandez <aldyh@redhat.com> + + * gcc.dg/tree-ssa/popcount6.c: New test. + +2022-09-27 Jakub Jelinek <jakub@redhat.com> + + PR c++/106651 + * g++.dg/template/error30.C: Adjust expected diagnostics. + * g++.dg/cpp1z/constexpr-lambda13.C: Likewise. + * g++.dg/cpp23/feat-cxx2b.C: Test __cpp_static_call_operator. + * g++.dg/cpp23/static-operator-call1.C: New test. + * g++.dg/cpp23/static-operator-call2.C: New test. + * g++.old-deja/g++.jason/operator.C: Adjust expected diagnostics. + * g++.dg/cpp23/static-operator-call3.C: New file. + +2022-09-27 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/107029 + * g++.dg/torture/pr107029.C: New test. + +2022-09-27 Jakub Jelinek <jakub@redhat.com> + + * c-c++-common/gomp/assume-1.c: New test. + * c-c++-common/gomp/assume-2.c: New test. + * c-c++-common/gomp/assume-3.c: New test. + * c-c++-common/gomp/assumes-1.c: New test. + * c-c++-common/gomp/assumes-2.c: New test. + * c-c++-common/gomp/assumes-3.c: New test. + * c-c++-common/gomp/assumes-4.c: New test. + * c-c++-common/gomp/begin-assumes-1.c: New test. + * c-c++-common/gomp/begin-assumes-2.c: New test. + * c-c++-common/gomp/begin-assumes-3.c: New test. + * c-c++-common/gomp/begin-assumes-4.c: New test. + * c-c++-common/gomp/declare-target-6.c: New test. + * g++.dg/gomp/attrs-1.C (bar): Add n1 and n2 arguments, add + tests for assume directive. + * g++.dg/gomp/attrs-2.C (bar): Likewise. + * g++.dg/gomp/attrs-9.C: Add n1 and n2 variables, add tests for + begin assumes directive. + * g++.dg/gomp/attrs-15.C: New test. + * g++.dg/gomp/attrs-16.C: New test. + * g++.dg/gomp/attrs-17.C: New test. + +2022-09-27 Jakub Jelinek <jakub@redhat.com> + + * g++.dg/diagnostic/conflicting-specifiers-1.C: Adjust expected + diagnostics. + * g++.dg/parse/typedef8.C: Likewise. + * g++.dg/parse/crash39.C: Likewise. + * g++.dg/other/mult-stor1.C: Likewise. + * g++.dg/cpp2a/constinit3.C: Likewise. + +2022-09-27 Jakub Jelinek <jakub@redhat.com> + + PR c++/106652 + PR c++/85518 + * g++.dg/cpp23/ext-floating1.C: New test. + * g++.dg/cpp23/ext-floating2.C: New test. + * g++.dg/cpp23/ext-floating3.C: New test. + * g++.dg/cpp23/ext-floating4.C: New test. + * g++.dg/cpp23/ext-floating5.C: New test. + * g++.dg/cpp23/ext-floating6.C: New test. + * g++.dg/cpp23/ext-floating7.C: New test. + * g++.dg/cpp23/ext-floating8.C: New test. + * g++.dg/cpp23/ext-floating9.C: New test. + * g++.dg/cpp23/ext-floating10.C: New test. + * g++.dg/cpp23/ext-floating.h: New file. + * g++.target/i386/float16-1.C: Adjust expected diagnostics. + +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 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/c-c++-common/ubsan/pr85213.c b/gcc/testsuite/c-c++-common/ubsan/pr85213.c index 8a6be81..e903e97 100644 --- a/gcc/testsuite/c-c++-common/ubsan/pr85213.c +++ b/gcc/testsuite/c-c++-common/ubsan/pr85213.c @@ -1,6 +1,11 @@ /* PR sanitizer/85213 */ /* { dg-do compile } */ -/* { dg-options "-O1 -fsanitize=undefined -fcompare-debug" } */ +/* Pass -gno-statement-frontiers to work around + https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100733 : + without it the IR coming from the front end may be different with and without + debug information turned on. That may cause e.g., different discriminator values + and -fcompare-debug failures. */ +/* { dg-options "-O1 -fsanitize=undefined -fcompare-debug -gno-statement-frontiers" } */ int foo (int x) diff --git a/gcc/testsuite/g++.dg/conversion/pr41426.C b/gcc/testsuite/g++.dg/conversion/pr41426.C index 5493a91..b4ecbca 100644 --- a/gcc/testsuite/g++.dg/conversion/pr41426.C +++ b/gcc/testsuite/g++.dg/conversion/pr41426.C @@ -11,19 +11,20 @@ struct A A<float> g1() { float f[] = {1.1f, 2.3f}; - return f; + return f; // { dg-error "cannot bind non-const" "" { target c++23 } } } const A<float> &g3() { float f[] = {1.1f, 2.3f}; - return f; // { dg-warning "returning reference to temporary" } + return f; // { dg-warning "returning reference to temporary" "" { target c++20_down } } +// { dg-error "non-const lvalue|invalid user-defined conversion" "" { target c++23 } .-1 } } A<float> &g4() { float f[] = {1.1f, 2.3f}; - return f; // { dg-error "cannot bind non-const lvalue ref" } + return f; // { dg-error "cannot bind non-const lvalue ref|invalid user-defined conversion" } } struct B @@ -35,6 +36,5 @@ struct B B g2() { int c[10]; - return c; + return c; // { dg-error "non-const lvalue" "" { target c++23 } } } - diff --git a/gcc/testsuite/g++.dg/cpp0x/elision_weak.C b/gcc/testsuite/g++.dg/cpp0x/elision_weak.C index e8ba755..ddd1274 100644 --- a/gcc/testsuite/g++.dg/cpp0x/elision_weak.C +++ b/gcc/testsuite/g++.dg/cpp0x/elision_weak.C @@ -9,11 +9,11 @@ struct S S f() { S s; - return s; + return s; // { dg-error "cannot bind non-const lvalue reference" "" { target c++23 } } } void g() { S s; - throw s; + throw s; // { dg-error "cannot bind non-const lvalue reference" "" { target c++23 } } } diff --git a/gcc/testsuite/g++.dg/cpp0x/move-return3.C b/gcc/testsuite/g++.dg/cpp0x/move-return3.C index c79f059..30a936f 100644 --- a/gcc/testsuite/g++.dg/cpp0x/move-return3.C +++ b/gcc/testsuite/g++.dg/cpp0x/move-return3.C @@ -1,6 +1,7 @@ // PR c++/91212 // Test that C++11 implicit move semantics don't call the const copy. -// { dg-do link } +// In C++23, we call #2. +// { dg-do link { target c++20_down } } struct T { int i; }; diff --git a/gcc/testsuite/g++.dg/cpp1y/decltype-auto2.C b/gcc/testsuite/g++.dg/cpp1y/decltype-auto2.C index 56e011e..24b32ed 100644 --- a/gcc/testsuite/g++.dg/cpp1y/decltype-auto2.C +++ b/gcc/testsuite/g++.dg/cpp1y/decltype-auto2.C @@ -8,5 +8,5 @@ auto constexpr RtoL1(T&& r) -> decltype(auto) { int main() { int t; int x{3}; - decltype (RtoL1(x+0)) y = t; + decltype (RtoL1(x+0)) y = t; // { dg-error "cannot bind rvalue reference" "" { target c++23 } } } diff --git a/gcc/testsuite/g++.dg/cpp1y/decltype-auto6.C b/gcc/testsuite/g++.dg/cpp1y/decltype-auto6.C new file mode 100644 index 0000000..da53278 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/decltype-auto6.C @@ -0,0 +1,19 @@ +// PR c++/101165 - P2266R1 - Simpler implicit move +// { dg-do compile { target c++14 } } +// A variant of cxx23/elision1.C:eight, just with (). + +struct Widget { + Widget(Widget&&); +}; + +Widget val(); + +decltype(auto) +foo () +{ + decltype(auto) x = val(); // OK, x is Widget + // We deduce the return type to int&&, therefore we're doing something + // we ought not to be doing -- returning a reference to a local variable! + // In C++20, we deduce to int&, but that has the same problem! + return (x); // { dg-warning "reference to local variable" } +} diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-89419.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-89419.C index 46ce909..8e64d4e 100644 --- a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-89419.C +++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-89419.C @@ -2,7 +2,7 @@ // { dg-do compile { target c++14 } } struct A; -struct B { +struct B { // { dg-error "cannot bind" "" { target c++23 } } struct C { C (); C (C &); } b; }; struct D { A operator* (); }; @@ -13,12 +13,12 @@ struct E { auto bar () { return e; } D e; }; -struct F { B f; int g; }; +struct F { B f; int g; }; // { dg-error "use of deleted function" "" { target c++23 } } int main () { E e; auto f = *e.bar (); - auto i = [&] { F g; g.g = 1; auto h = [&](auto) { g.g = 0; }; f.foo (h); return g; }; + auto i = [&] { F g; g.g = 1; auto h = [&](auto) { g.g = 0; }; f.foo (h); return g; }; // { dg-error "use of deleted function" "" { target c++23 } } } 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/decltype1.C b/gcc/testsuite/g++.dg/cpp23/decltype1.C new file mode 100644 index 0000000..6f3cd0d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/decltype1.C @@ -0,0 +1,113 @@ +// PR c++/101165 - P2266R1 - Simpler implicit move +// { dg-do compile { target c++23 } } +// Tests from P2266R1, decltype-related changes in +// $ 3.2.1. Interaction with decltype and decltype(auto) + +template<typename T, typename U> +struct same_type { static const bool value = false; }; + +template<typename T> +struct same_type<T, T> { static const bool value = true; }; + +auto f1(int x) -> decltype(x) { return (x); } +static_assert(same_type<decltype(f1), int (int)>::value); +auto f2(int x) -> decltype((x)) { return (x); } // { dg-error "cannot bind" } +static_assert(same_type<decltype(f2), int& (int)>::value); +auto f3(int x) -> decltype(auto) { return (x); } // { dg-warning "reference to local variable" } +static_assert(same_type<decltype(f3), int&& (int)>::value); +auto g1(int x) -> decltype(x) { return x; } +static_assert(same_type<decltype(g1), int (int)>::value); +auto g2(int x) -> decltype((x)) { return x; } // { dg-error "cannot bind" } +static_assert(same_type<decltype(g2), int& (int)>::value); +auto g3(int x) -> decltype(auto) { return x; } +static_assert(same_type<decltype(g3), int (int)>::value); + +// Note that f2 and g2 are well-formed in C++20, but we propose to make +// f2 and g2 ill-formed, because they attempt to bind an lvalue reference +// to a move-eligible xvalue expression. + +struct X { }; + +auto +f4 (X x) +{ + return x; +} +static_assert(same_type<decltype(f4), X(X)>::value); + +auto& +f5 (X x) +{ + return x; // { dg-error "cannot bind non-const lvalue reference" } +} +static_assert(same_type<decltype(f5), X&(X)>::value); + +auto&& +f6 (X x) +{ + return x; // { dg-warning "reference to local variable" } +} +static_assert(same_type<decltype(f6), X&&(X)>::value); + +auto +f7 (X x) +{ + return (x); +} +static_assert(same_type<decltype(f7), X(X)>::value); + +auto& +f8 (X x) +{ + return (x); // { dg-error "cannot bind non-const lvalue reference" } +} +static_assert(same_type<decltype(f8), X&(X)>::value); + +auto&& +f9 (X x) +{ + return (x); // { dg-warning "reference to local variable" } +} +static_assert(same_type<decltype(f9), X&&(X)>::value); + +decltype(auto) +f10 (X x) +{ + return x; +} +static_assert(same_type<decltype(f10), X(X)>::value); + +decltype(auto) +f11 (X x) +{ + return (x); // { dg-warning "reference to local variable" } +} +static_assert(same_type<decltype(f11), X&&(X)>::value); + +decltype(auto) +f12 (X& x) +{ + return x; +} +static_assert(same_type<decltype(f12), X&(X&)>::value); + +decltype(auto) +f13 (X& x) +{ + return (x); +} +static_assert(same_type<decltype(f13), X&(X&)>::value); + +decltype(auto) +f14 (X&& x) +{ + return x; +} +static_assert(same_type<decltype(f14), X&&(X&&)>::value); + +decltype(auto) +f15 (X&& x) +{ + return (x); +} +static_assert(same_type<decltype(f15), X&&(X&&)>::value); diff --git a/gcc/testsuite/g++.dg/cpp23/decltype2.C b/gcc/testsuite/g++.dg/cpp23/decltype2.C new file mode 100644 index 0000000..84679c4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/decltype2.C @@ -0,0 +1,49 @@ +// PR c++/101165 - P2266R1 - Simpler implicit move +// { dg-do compile { target c++23 } } +// Test decltype(auto) more. + +template<typename T, typename U> +struct same_type { static const bool value = false; }; + +template<typename T> +struct same_type<T, T> { static const bool value = true; }; + +struct Widget { + int x; +}; + +Widget wg; + +decltype(auto) fn0(Widget&& x) { + return (::wg); +} +static_assert(same_type<decltype(fn0), Widget& (Widget&&)>::value); + +decltype(auto) fn1(Widget&& x) { + return ::wg; +} +static_assert(same_type<decltype(fn1), Widget (Widget&&)>::value); + +decltype(auto) fn2() { + Widget w; + return w; +} +static_assert(same_type<decltype(fn2), Widget ()>::value); + +decltype(auto) fn3() { + Widget w; + return (w); // { dg-warning "reference to local variable" } +} +static_assert(same_type<decltype(fn3), Widget&& ()>::value); + +decltype(auto) fn4() { + Widget w; + return w.x; +} +static_assert(same_type<decltype(fn4), int ()>::value); + +decltype(auto) fn5() { + Widget w; + return (w.x); // { dg-warning "reference to local variable" } +} +static_assert(same_type<decltype(fn5), int& ()>::value); diff --git a/gcc/testsuite/g++.dg/cpp23/elision1.C b/gcc/testsuite/g++.dg/cpp23/elision1.C new file mode 100644 index 0000000..f44fd2a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/elision1.C @@ -0,0 +1,114 @@ +// PR c++/101165 - P2266R1 - Simpler implicit move +// { dg-do compile { target c++23 } } +// Tests from P2266R1. + +namespace std { + template<typename _Tp> + struct remove_reference + { typedef _Tp type; }; + + template<typename _Tp> + struct remove_reference<_Tp&> + { typedef _Tp type; }; + + template<typename _Tp> + struct remove_reference<_Tp&&> + { typedef _Tp type; }; + + template<typename _Tp> + constexpr typename std::remove_reference<_Tp>::type&& + move(_Tp&& __t) noexcept + { return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); } +} + +template<typename T, typename U> +struct same_type { static const bool value = false; }; + +template<typename T> +struct same_type<T, T> { static const bool value = true; }; + +struct Widget { + Widget(Widget&&); +}; + +struct RRefTaker { + RRefTaker(Widget&&); +}; + +struct Mutt { + operator int*() &&; +}; + +struct Jeff { + operator int&() &&; +}; + +struct Ella { + operator int() &&; +}; + +Widget one(Widget w) { + return w; // OK since C++11 +} + +RRefTaker two(Widget w) { + return w; // OK since C++11 + CWG1579 +} + +RRefTaker three(Widget&& w) { + return w; // OK since C++20 because P0527 +} + +// Tests that implicit move applies even to functions that return references. +Widget&& four(Widget&& w) { + return w; // OK since C++23 +} + +// ... or pointers. +int* five(Mutt x) { + return x; // OK since C++20 because P1155 +} + +int& six(Jeff x) { + return x; +} + +int test_ella(Ella e) { + return e; +} + +template<class T> +T&& seven(T&& x) { return x; } + +void test_seven(Widget w) { + Widget& r = seven(w); + Widget&& rr = seven(std::move(w)); +} + +Widget val(); +Widget& lref(); +Widget&& rref(); + +decltype(auto) eight() { + decltype(auto) x = val(); // OK, x is Widget + return x; // OK, return type is Widget, we get copy elision +} + +decltype(auto) nine() { + decltype(auto) x = lref(); // OK, x is Widget& + return x; // OK, return type is Widget& +} + +decltype(auto) ten() { + decltype(auto) x = rref(); // OK, x is Widget&& + // This was an error: return type is Widget&&, cannot bind to x. + // But in C++23, x is treated as an rvalue. + return x; +} + +// Now returns Widget&&, not Widget&. +// This is from $ 3.2.1. Interaction with decltype and decltype(auto). +decltype(auto) eleven(Widget&& x) { + return (x); +} +static_assert(same_type<decltype(eleven), Widget&& (Widget&&)>::value); diff --git a/gcc/testsuite/g++.dg/cpp23/elision2.C b/gcc/testsuite/g++.dg/cpp23/elision2.C new file mode 100644 index 0000000..a698fc9 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/elision2.C @@ -0,0 +1,46 @@ +// PR c++/101165 - P2266R1 - Simpler implicit move +// { dg-do compile { target c++20 } } +// Test from P2266R1, $ 3.3. Two overload resolutions are overly confusing. + +struct Widget { + Widget(); + Widget(Widget&&); +}; + +struct Frodo { + Frodo(Widget&); + Frodo(Widget&&) = delete; +}; + +struct Sam { + Sam(Widget&) = delete; // #1 + Sam(const Widget&); // #2 +}; + +Sam twelve() { + Widget w; + // This is supposed to call #2 since C++20 because P1155. + // But we actually choose #1 since r11-2411 (in C++20 only). + return w; // { dg-error "deleted" "" { target c++20_only } } +} + +Frodo thirteen() { + Widget w; + // This is a correct error in both C++20 and C++23. + return w; // { dg-error "use of deleted function" } +} + +struct Merry {}; +struct Pippin {}; +struct Together : Merry, Pippin {}; +struct Quest { + Quest(Merry&&); + Quest(Pippin&&); + Quest(Together&); +}; + +Quest fourteen() { + Together t; + // C++20: calls Quest(Together&). Proposed: ill-formed. + return t; // { dg-error "ambiguous" "" { target c++23 } } +} diff --git a/gcc/testsuite/g++.dg/cpp23/elision3.C b/gcc/testsuite/g++.dg/cpp23/elision3.C new file mode 100644 index 0000000..246342e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/elision3.C @@ -0,0 +1,16 @@ +// PR c++/101165 - P2266R1 - Simpler implicit move +// { dg-do compile { target c++23 } } +// Test from P2266R1, $ 3.4. A specific case involving reference_wrapper. + +#include <functional> + +struct Widget { + Widget(); + Widget(Widget&&); +}; + +std::reference_wrapper<Widget> fifteen() { + Widget w; + // OK until CWG1579; OK after LWG2993. Proposed: ill-formed + return w; // { dg-error "could not convert" } +} diff --git a/gcc/testsuite/g++.dg/cpp23/elision4.C b/gcc/testsuite/g++.dg/cpp23/elision4.C new file mode 100644 index 0000000..c19b86b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/elision4.C @@ -0,0 +1,38 @@ +// PR c++/101165 - P2266R1 - Simpler implicit move +// { dg-do compile { target c++23 } } +// Test from P2266R1, $ 5.2. LibreOffice OString constructor. + +struct X { + X(auto&); +}; + +// The following compiles in C++20 (deducing X(char (&)[10])) but not +// after P2266 (because the returned expression now has type char (&&)[10], +// which cannot bind to auto&). +X f() { + char a[10]; + return a; // { dg-error "cannot bind non-const lvalue reference" } +} + +// The solution was to change it by making the return convert explicitly +// rather than implicitly: +X fixed() { + char a[10]; + return X(a); +} + +// $ 5.3. LibreOffice o3tl::temporary + +template<class T> +T& temporary1(T&& x) { return x; } // { dg-error "cannot bind non-const lvalue reference" } + +// Fixed by: +template<class T> +T& temporary2(T&& x) { return static_cast<T&>(x); } + +void +test () +{ + int& r1 = temporary1 (42); + int& r2 = temporary2 (42); +} diff --git a/gcc/testsuite/g++.dg/cpp23/elision5.C b/gcc/testsuite/g++.dg/cpp23/elision5.C new file mode 100644 index 0000000..a7d3e7c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/elision5.C @@ -0,0 +1,53 @@ +// PR c++/101165 - P2266R1 - Simpler implicit move +// { dg-do compile { target c++23 } } +// Test from [class.copy.elision]/4. + +class Thing { +public: + Thing(); + ~Thing(); + Thing(Thing&&); +private: + Thing(const Thing&); +}; + +Thing f(bool b) { + Thing t; + if (b) + throw t; // OK, Thing(Thing&&) used (or elided) to throw t + return t; // OK, Thing(Thing&&) used (or elided) to return t +} + +Thing t2 = f(false); // OK, no extra copy/move performed, t2 constructed by call to f + +struct Weird { + Weird(); + Weird(Weird&); +}; + +Weird g(bool b) { + static Weird w1; + Weird w2; + if (b) { + return w1; // OK: Weird(Weird&) + } else { + return w2; // { dg-error "cannot bind non-const lvalue reference" } + } +} + +int& h(bool b, int i) { + static int s; + if (b) + return s; // OK + else + return i; // { dg-error "cannot bind non-const lvalue reference" } +} + +decltype(auto) h2(Thing t) { + return t; // OK, t is an xvalue and h2's return type is Thing +} + +decltype(auto) h3(Thing t) { + // OK, (t) is an xvalue and h3's return type is Thing&& + return (t); // { dg-warning "reference to local variable" } +} diff --git a/gcc/testsuite/g++.dg/cpp23/elision6.C b/gcc/testsuite/g++.dg/cpp23/elision6.C new file mode 100644 index 0000000..5d58da9 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/elision6.C @@ -0,0 +1,20 @@ +// PR c++/101165 - P2266R1 - Simpler implicit move +// { dg-do compile { target c++23 } } +// From [diff.cpp20.expr]. + +template<typename T, typename U> +struct same_type { static const bool value = false; }; + +template<typename T> +struct same_type<T, T> { static const bool value = true; }; + +// In C++23, returns int&&; previously returned int&. +decltype(auto) f(int&& x) { return (x); } +static_assert(same_type<decltype(f), int&& (int&&)>::value); + +// This used to work in C++20. +int& g(int&& x) { return x; } // { dg-error "cannot bind non-const lvalue reference" } + +template<typename T> +decltype(auto) h(T&& x) { return (x); } +static_assert(same_type<decltype(h(42)), int&&>::value); diff --git a/gcc/testsuite/g++.dg/cpp23/elision7.C b/gcc/testsuite/g++.dg/cpp23/elision7.C new file mode 100644 index 0000000..19fa89a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/elision7.C @@ -0,0 +1,72 @@ +// PR c++/101165 - P2266R1 - Simpler implicit move +// { dg-do compile { target c++23 } } + +struct X { + X (); + X(X&&); +}; + +X&& rref (); + +X&& +f1 (X&& x) +{ + return x; +} + +template<typename T> T&& +f2 (T&& x) +{ + return x; +} +template X& f2<X&>(X&); +template X&& f2<X>(X&&); + +X&& +f3 () +{ + X&& x = rref (); + return x; +} + +void +f4 () +try { + X x; + throw x; +} catch (...) { } + +void +f5 () +{ + auto l1 = [](auto x) -> auto { return x; }; + auto &&x1 = l1(X{}); + auto l2 = [](auto x) -> auto& { return x; }; // { dg-error "cannot bind non-const lvalue reference" } + auto &&x2 = l2(X{}); + auto l3 = [](auto x) -> auto&& { return x; }; // { dg-warning "reference to local" } + auto &&x3 = l3(X{}); +} + +constexpr int & +f6 (int &&n) +{ + return n; // { dg-error "cannot bind non-const lvalue reference" } +} + +void +do_f6 () +{ + auto x = f6 (42); +} + +template<typename T> auto & +f7 (T &&t) +{ + return t; // { dg-error "cannot bind non-const lvalue reference" } +} + +void +do_f7 () +{ + const int &x = f7 (0); +} 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 0537e1d..b52cf37 100644 --- a/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C +++ b/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C @@ -563,3 +563,15 @@ #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 + +#ifndef __cpp_implicit_move +# error "__cpp_implicit_move" +#elif __cpp_implicit_move != 202207 +# error "__cpp_implicit_move != 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/concepts-traits3.C b/gcc/testsuite/g++.dg/cpp2a/concepts-traits3.C index f20608b6..3e87da4 100644 --- a/gcc/testsuite/g++.dg/cpp2a/concepts-traits3.C +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-traits3.C @@ -21,7 +21,7 @@ concept TriviallyAssignable = __is_trivially_assignable(T, U); template<class T, class U> concept NothrowAssignable = __is_nothrow_assignable(T, U); -// { dg-message "'S' is not 'nothrow' assignable from 'int'" "" { target *-*-* } .-1 } +// { dg-message "'S' is not nothrow assignable from 'int'" "" { target *-*-* } .-1 } template<class T, class... Args> concept Constructible = __is_constructible(T, Args...); @@ -37,9 +37,9 @@ concept TriviallyConstructible = __is_trivially_constructible(T, Args...); template<class T, class... Args> concept NothrowConstructible = __is_nothrow_constructible(T, Args...); -// { dg-message "'S' is not 'nothrow' default constructible" "" { target *-*-* } .-1 } -// { dg-message "'S' is not 'nothrow' constructible from 'int'" "" { target *-*-* } .-2 } -// { dg-message "'S' is not 'nothrow' constructible from 'int, char'" "" { target *-*-* } .-3 } +// { dg-message "'S' is not nothrow default constructible" "" { target *-*-* } .-1 } +// { dg-message "'S' is not nothrow constructible from 'int'" "" { target *-*-* } .-2 } +// { dg-message "'S' is not nothrow constructible from 'int, char'" "" { target *-*-* } .-3 } template<class T> concept UniqueObjReps = __has_unique_object_representations(T); 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/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/is_convertible4.C b/gcc/testsuite/g++.dg/ext/is_convertible4.C new file mode 100644 index 0000000..8a7724c --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/is_convertible4.C @@ -0,0 +1,33 @@ +// PR c++/107049 +// { dg-do compile { target c++11 } } +// Failed access check should be a substitution failure, not an error. + +template<bool B> +struct bool_constant { static constexpr bool value = B; }; + +template<typename From, typename To> +struct is_convertible +: public bool_constant<__is_convertible(From, To)> +{ }; + +#if __cpp_variable_templates +template<typename From, typename To> +constexpr bool is_convertible_v = __is_convertible(From, To); +#endif + +class Private +{ + operator int() const + { + static_assert( not is_convertible<Private, int>::value, "" ); +#if __cpp_variable_templates + static_assert( not is_convertible_v<Private, int>, "" ); +#endif + return 0; + } +}; + +static_assert( not is_convertible<Private, int>::value, "" ); +#if __cpp_variable_templates +static_assert( not is_convertible_v<Private, int>, "" ); +#endif diff --git a/gcc/testsuite/g++.dg/ext/is_nothrow_convertible4.C b/gcc/testsuite/g++.dg/ext/is_nothrow_convertible4.C new file mode 100644 index 0000000..f81b594 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/is_nothrow_convertible4.C @@ -0,0 +1,33 @@ +// PR c++/107049 +// { dg-do compile { target c++11 } } +// Failed access check should be a substitution failure, not an error. + +template<bool B> +struct bool_constant { static constexpr bool value = B; }; + +template<typename From, typename To> +struct is_nt_convertible +: public bool_constant<__is_nothrow_convertible(From, To)> +{ }; + +#if __cpp_variable_templates +template<typename From, typename To> +constexpr bool is_nt_convertible_v = __is_nothrow_convertible(From, To); +#endif + +class Private +{ + operator int() const + { + static_assert( not is_nt_convertible<Private, int>::value, "" ); +#if __cpp_variable_templates + static_assert( not is_nt_convertible_v<Private, int>, "" ); +#endif + return 0; + } +}; + +static_assert( not is_nt_convertible<Private, int>::value, "" ); +#if __cpp_variable_templates +static_assert( not is_nt_convertible_v<Private, int>, "" ); +#endif diff --git a/gcc/testsuite/g++.dg/fstack-protector-strong.C b/gcc/testsuite/g++.dg/fstack-protector-strong.C index ae6d2fd..034af2c 100644 --- a/gcc/testsuite/g++.dg/fstack-protector-strong.C +++ b/gcc/testsuite/g++.dg/fstack-protector-strong.C @@ -85,4 +85,4 @@ int foo7 (B *p) return p->return_slot ().a1; } -/* { dg-final { scan-assembler-times "stack_chk_fail" 7 } } */ +/* { dg-final { scan-assembler-times "stack_chk_fail" 8 } } */ 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/gomp/pr56217.C b/gcc/testsuite/g++.dg/gomp/pr56217.C index 03dfc5f..731c0c0 100644 --- a/gcc/testsuite/g++.dg/gomp/pr56217.C +++ b/gcc/testsuite/g++.dg/gomp/pr56217.C @@ -1,5 +1,5 @@ // PR middle-end/56217 -// { dg-do compile } +// { dg-do compile { target c++20_down } } // { dg-options "-fopenmp" } struct S { int *p; S (); S (S &); }; @@ -10,5 +10,7 @@ foo () S s; #pragma omp task shared (s) s.p = 0; + // This fails in C++23, because "cannot bind non-const lvalue reference of + // type 'S&' to an rvalue of type 'S'". return s; } 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/pr58245-1.C b/gcc/testsuite/g++.dg/pr58245-1.C new file mode 100644 index 0000000..1439bc6 --- /dev/null +++ b/gcc/testsuite/g++.dg/pr58245-1.C @@ -0,0 +1,10 @@ +/* { dg-do compile { target i?86-*-* x86_64-*-* rs6000-*-* s390x-*-* } } */ +/* { dg-options "-O2 -fstack-protector-all" } */ + +void +bar (void) +{ + throw 1; +} + +/* { dg-final { scan-assembler-times "stack_chk_fail" 1 } } */ 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++.dg/uninit-pr105646.C b/gcc/testsuite/g++.dg/uninit-pr105646.C new file mode 100644 index 0000000..48ceb98 --- /dev/null +++ b/gcc/testsuite/g++.dg/uninit-pr105646.C @@ -0,0 +1,17 @@ +// { dg-do compile } +// { dg-require-effective-target c++11 } +// { dg-options "-O2 -Wuninitialized" } + +int f1(); +int f2(){ + bool v2{v2}; // { dg-warning "is used uninitialized" } + auto const & a = f1(); + return a; +} +int f3(){ + auto const & a = f1(); + // Diagnose the following when optimizing and as unconditional + // uninitialized use despite f1 possibly throwing + bool v3{v3}; // { dg-warning "is used uninitialized" } + return a; +} diff --git a/gcc/testsuite/g++.dg/warn/Wno-return-local-addr.C b/gcc/testsuite/g++.dg/warn/Wno-return-local-addr.C index e15bfa2..cc9bb59 100644 --- a/gcc/testsuite/g++.dg/warn/Wno-return-local-addr.C +++ b/gcc/testsuite/g++.dg/warn/Wno-return-local-addr.C @@ -4,7 +4,7 @@ int& bad1() { int x = 0; - return x; + return x; // { dg-error "cannot bind non-const lvalue reference" "" { target c++23 } } } int* bad2() diff --git a/gcc/testsuite/g++.dg/warn/Wreturn-local-addr.C b/gcc/testsuite/g++.dg/warn/Wreturn-local-addr.C index 642a576..4c18c2f 100644 --- a/gcc/testsuite/g++.dg/warn/Wreturn-local-addr.C +++ b/gcc/testsuite/g++.dg/warn/Wreturn-local-addr.C @@ -5,7 +5,7 @@ int& bad1() { int x = 0; - return x; // { dg-error "reference to local variable" } + return x; // { dg-error "reference to local variable|cannot bind non-const lvalue reference" } } int* bad2() diff --git a/gcc/testsuite/g++.old-deja/g++.brendan/crash55.C b/gcc/testsuite/g++.old-deja/g++.brendan/crash55.C index fd4d4b6..b93e6e0 100644 --- a/gcc/testsuite/g++.old-deja/g++.brendan/crash55.C +++ b/gcc/testsuite/g++.old-deja/g++.brendan/crash55.C @@ -8,5 +8,6 @@ local = x+2; - return local; // { dg-warning "reference to local" } + return local; // { dg-warning "reference to local" "" { target c++20_down } } +// { dg-error "non-const lvalue" "" { target c++23 } .-1 } } 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++.old-deja/g++.jason/temporary2.C b/gcc/testsuite/g++.old-deja/g++.jason/temporary2.C index c855f8f..2709b50 100644 --- a/gcc/testsuite/g++.old-deja/g++.jason/temporary2.C +++ b/gcc/testsuite/g++.old-deja/g++.jason/temporary2.C @@ -8,7 +8,7 @@ public: int i; }; -X foo() { X x; return x; } +X foo() { X x; return x; } // { dg-error "cannot bind non-const lvalue reference" "" { target c++23 } } int main() { diff --git a/gcc/testsuite/g++.old-deja/g++.mike/p2846b.C b/gcc/testsuite/g++.old-deja/g++.mike/p2846b.C index 57422fe..5bcf9e3 100644 --- a/gcc/testsuite/g++.old-deja/g++.mike/p2846b.C +++ b/gcc/testsuite/g++.old-deja/g++.mike/p2846b.C @@ -42,7 +42,7 @@ public: B A::compute(void) const { B sub(*this, 1); - return sub; + return static_cast<B&>(sub); } int main () 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-prof/cold_partition_label.c b/gcc/testsuite/gcc.dg/tree-prof/cold_partition_label.c index 511b610..b85e6c1 100644 --- a/gcc/testsuite/gcc.dg/tree-prof/cold_partition_label.c +++ b/gcc/testsuite/gcc.dg/tree-prof/cold_partition_label.c @@ -43,6 +43,6 @@ main (int argc, char *argv[]) return 0; } -/* { dg-final-use { scan-assembler "foo\[._\]+cold" { target *-*-linux* *-*-gnu* } } } */ -/* { dg-final-use { scan-assembler "size\[ \ta-zA-Z0-0\]+foo\[._\]+cold" { target *-*-linux* *-*-gnu* } } } */ +/* { dg-final-use-not-autofdo { scan-assembler "foo\[._\]+cold" { target *-*-linux* *-*-gnu* } } } */ +/* { dg-final-use-not-autofdo { scan-assembler "size\[ \ta-zA-Z0-0\]+foo\[._\]+cold" { target *-*-linux* *-*-gnu* } } } */ /* { dg-final-use { scan-tree-dump-not "Invalid sum" "optimized"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-prof/section-attr-1.c b/gcc/testsuite/gcc.dg/tree-prof/section-attr-1.c index 2087d0d..5376de1 100644 --- a/gcc/testsuite/gcc.dg/tree-prof/section-attr-1.c +++ b/gcc/testsuite/gcc.dg/tree-prof/section-attr-1.c @@ -52,5 +52,5 @@ foo (int path) } } -/* { dg-final-use { scan-assembler "\.section\[\t \]*\.text\.unlikely\[\\n\\r\]+\[\t \]*\.size\[\t \]*foo\.cold" { target *-*-linux* *-*-gnu* } } } */ -/* { dg-final-use { scan-assembler {.section[\t ]*__TEXT,__text_cold[^\n]*[\n\r]+_foo.cold:} { target *-*-darwin* } } } */ +/* { dg-final-use-not-autofdo { scan-assembler "\.section\[\t \]*\.text\.unlikely\[\\n\\r\]+\[\t \]*\.size\[\t \]*foo\.cold" { target *-*-linux* *-*-gnu* } } } */ +/* { dg-final-use-not-autofdo { scan-assembler {.section[\t ]*__TEXT,__text_cold[^\n]*[\n\r]+_foo.cold:} { target *-*-darwin* } } } */ diff --git a/gcc/testsuite/gcc.dg/tree-prof/section-attr-2.c b/gcc/testsuite/gcc.dg/tree-prof/section-attr-2.c index b02526b..90de2c0 100644 --- a/gcc/testsuite/gcc.dg/tree-prof/section-attr-2.c +++ b/gcc/testsuite/gcc.dg/tree-prof/section-attr-2.c @@ -51,5 +51,5 @@ foo (int path) } } -/* { dg-final-use { scan-assembler "\.section\[\t \]*\.text\.unlikely\[\\n\\r\]+\[\t \]*\.size\[\t \]*foo\.cold" { target *-*-linux* *-*-gnu* } } } */ -/* { dg-final-use { scan-assembler {.section[\t ]*__TEXT,__text_cold[^\n]*[\n\r]+_foo.cold:} { target *-*-darwin* } } } */ +/* { dg-final-use-not-autofdo { scan-assembler "\.section\[\t \]*\.text\.unlikely\[\\n\\r\]+\[\t \]*\.size\[\t \]*foo\.cold" { target *-*-linux* *-*-gnu* } } } */ +/* { dg-final-use-not-autofdo { scan-assembler {.section[\t ]*__TEXT,__text_cold[^\n]*[\n\r]+_foo.cold:} { target *-*-darwin* } } } */ diff --git a/gcc/testsuite/gcc.dg/tree-prof/section-attr-3.c b/gcc/testsuite/gcc.dg/tree-prof/section-attr-3.c index da06407..29a48f0 100644 --- a/gcc/testsuite/gcc.dg/tree-prof/section-attr-3.c +++ b/gcc/testsuite/gcc.dg/tree-prof/section-attr-3.c @@ -52,5 +52,5 @@ foo (int path) } } -/* { dg-final-use { scan-assembler "\.section\[\t \]*\.text\.unlikely\[\\n\\r\]+\[\t \]*\.size\[\t \]*foo\.cold" { target *-*-linux* *-*-gnu* } } } */ -/* { dg-final-use { scan-assembler {.section[\t ]*__TEXT,__text_cold[^\n]*[\n\r]+_foo.cold:} { target *-*-darwin* } } } */ +/* { dg-final-use-not-autofdo { scan-assembler "\.section\[\t \]*\.text\.unlikely\[\\n\\r\]+\[\t \]*\.size\[\t \]*foo\.cold" { target *-*-linux* *-*-gnu* } } } */ +/* { dg-final-use-not-autofdo { scan-assembler {.section[\t ]*__TEXT,__text_cold[^\n]*[\n\r]+_foo.cold:} { target *-*-darwin* } } } */ 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/popcount6b.c b/gcc/testsuite/gcc.dg/tree-ssa/popcount6b.c new file mode 100644 index 0000000..90336ec --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/popcount6b.c @@ -0,0 +1,6 @@ +// { dg-do compile } +// { dg-options "-O2 -fdump-tree-evrp -fno-tree-ccp" } + +#include "popcount6.c" + +// { dg-final { scan-tree-dump "return 1;" "evrp" } } diff --git a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/vld1x2.c b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/vld1x2.c index f933102..0c45a2b 100644 --- a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/vld1x2.c +++ b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/vld1x2.c @@ -1,6 +1,6 @@ /* We haven't implemented these intrinsics for arm yet. */ /* { dg-do run } */ -/* { dg-skip-if "unsupported" { arm*-*-* } } */ +/* { dg-skip-if "unimplemented" { arm*-*-* } } */ /* { dg-options "-O3" } */ #include <arm_neon.h> diff --git a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/vld1x3.c b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/vld1x3.c index b20dec0..4174dcd 100644 --- a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/vld1x3.c +++ b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/vld1x3.c @@ -1,6 +1,6 @@ /* We haven't implemented these intrinsics for arm yet. */ /* { dg-do run } */ -/* { dg-skip-if "unsupported" { arm*-*-* } } */ +/* { dg-skip-if "unimplemented" { arm*-*-* } } */ /* { dg-options "-O3" } */ #include <arm_neon.h> diff --git a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/vld1x4.c b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/vld1x4.c index e59f845..89b289b 100644 --- a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/vld1x4.c +++ b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/vld1x4.c @@ -1,6 +1,6 @@ /* We haven't implemented these intrinsics for arm yet. */ /* { dg-do run } */ -/* { dg-skip-if "unsupported" { arm*-*-* } } */ +/* { dg-skip-if "unimplemented" { arm*-*-* } } */ /* { dg-options "-O3" } */ #include <arm_neon.h> diff --git a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/vst1x2.c b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/vst1x2.c index cb13da0..6d20a46 100644 --- a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/vst1x2.c +++ b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/vst1x2.c @@ -1,6 +1,6 @@ /* We haven't implemented these intrinsics for arm yet. */ -/* { dg-xfail-if "" { arm*-*-* } } */ /* { dg-do run } */ +/* { dg-skip-if "unimplemented" { arm*-*-* } } */ /* { dg-options "-O3" } */ #include <arm_neon.h> diff --git a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/vst1x3.c b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/vst1x3.c index 3ce272a..87eae4d 100644 --- a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/vst1x3.c +++ b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/vst1x3.c @@ -1,6 +1,6 @@ /* We haven't implemented these intrinsics for arm yet. */ -/* { dg-xfail-if "" { arm*-*-* } } */ /* { dg-do run } */ +/* { dg-skip-if "unimplemented" { arm*-*-* } } */ /* { dg-options "-O3" } */ #include <arm_neon.h> diff --git a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/vst1x4.c b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/vst1x4.c index 1f17b53..829a18d 100644 --- a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/vst1x4.c +++ b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/vst1x4.c @@ -1,6 +1,6 @@ /* We haven't implemented these intrinsics for arm yet. */ -/* { dg-xfail-if "" { arm*-*-* } } */ /* { dg-do run } */ +/* { dg-skip-if "unimplemented" { arm*-*-* } } */ /* { dg-options "-O3" } */ #include <arm_neon.h> diff --git a/gcc/testsuite/gcc.target/arm/attr-crypto.c b/gcc/testsuite/gcc.target/arm/attr-crypto.c index cbd13a7..05e458f 100644 --- a/gcc/testsuite/gcc.target/arm/attr-crypto.c +++ b/gcc/testsuite/gcc.target/arm/attr-crypto.c @@ -16,6 +16,14 @@ #error __ARM_FEATURE_CRYPTO not defined. #endif +#ifndef __ARM_FEATURE_AES +#error __ARM_FEATURE_AES not defined. +#endif + +#ifndef __ARM_FEATURE_SHA2 +#error __ARM_FEATURE_SHA2 not defined. +#endif + #ifndef __ARM_NEON #error __ARM_NEON not defined. #endif diff --git a/gcc/testsuite/gcc.target/i386/keylocker-encodekey128.c b/gcc/testsuite/gcc.target/i386/keylocker-encodekey128.c index 805e062..57fa9bd 100644 --- a/gcc/testsuite/gcc.target/i386/keylocker-encodekey128.c +++ b/gcc/testsuite/gcc.target/i386/keylocker-encodekey128.c @@ -6,7 +6,6 @@ /* { dg-final { scan-assembler "(?:movdqu|movups)\[ \\t\]+\[^\\n\]*%xmm0,\[^\\n\\r\]*" } } */ /* { dg-final { scan-assembler "(?:movdqu|movups)\[ \\t\]+\[^\\n\]*%xmm1,\[^\\n\\r\]*16\[^\\n\\r\]*" } } */ /* { dg-final { scan-assembler "(?:movdqu|movups)\[ \\t\]+\[^\\n\]*%xmm2,\[^\\n\\r\]*32\[^\\n\\r\]*" } } */ -/* { dg-final { scan-assembler "(?:movdqa|movaps)\[ \\t\]+\[^\\n\]*%xmm\[4-6\],\[^\\n\\r\]*" } } */ #include <immintrin.h> diff --git a/gcc/testsuite/gcc.target/i386/keylocker-encodekey256.c b/gcc/testsuite/gcc.target/i386/keylocker-encodekey256.c index 26f04dc..a9398b4 100644 --- a/gcc/testsuite/gcc.target/i386/keylocker-encodekey256.c +++ b/gcc/testsuite/gcc.target/i386/keylocker-encodekey256.c @@ -8,7 +8,6 @@ /* { dg-final { scan-assembler "(?:movdqu|movups)\[ \\t\]+\[^\\n\]*%xmm1,\[^\\n\\r\]*16\[^\\n\\r\]*" } } */ /* { dg-final { scan-assembler "(?:movdqu|movups)\[ \\t\]+\[^\\n\]*%xmm2,\[^\\n\\r\]*32\[^\\n\\r\]*" } } */ /* { dg-final { scan-assembler "(?:movdqu|movups)\[ \\t\]+\[^\\n\]*%xmm3,\[^\\n\\r\]*48\[^\\n\\r\]*" } } */ -/* { dg-final { scan-assembler "(?:movdqa|movaps)\[ \\t\]+\[^\\n\]*%xmm\[4-6\],\[^\\n\\r\]*" } } */ #include <immintrin.h> diff --git a/gcc/testsuite/gcc.target/i386/pr107055.c b/gcc/testsuite/gcc.target/i386/pr107055.c new file mode 100644 index 0000000..63bcb3d --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr107055.c @@ -0,0 +1,4 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fno-tree-dce -fno-vect-cost-model -ftree-vectorize -fprofile-arcs" } */ + +#include "../../gcc.dg/torture/pr24257.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-1.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-1.c new file mode 100644 index 0000000..2e0e12a --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-1.c @@ -0,0 +1,63 @@ +/* { dg-do compile } */ +/* { dg-skip-if "test rvv intrinsic" { *-*-* } { "*" } { "-march=rv*v*" } } */ + +void foo0 () {__rvv_bool64_t t;} +void foo1 () {__rvv_bool32_t t;} +void foo2 () {__rvv_bool16_t t;} +void foo3 () {__rvv_bool8_t t;} +void foo4 () {__rvv_bool4_t t;} +void foo5 () {__rvv_bool2_t t;} +void foo6 () {__rvv_bool1_t t;} +void foo7 () {__rvv_int8mf8_t t;} +void foo8 () {__rvv_uint8mf8_t t;} +void foo9 () {__rvv_int8mf4_t t;} +void foo10 () {__rvv_uint8mf4_t t;} +void foo11 () {__rvv_int8mf2_t t;} +void foo12 () {__rvv_uint8mf2_t t;} +void foo13 () {__rvv_int8m1_t t;} +void foo14 () {__rvv_uint8m1_t t;} +void foo15 () {__rvv_int8m2_t t;} +void foo16 () {__rvv_uint8m2_t t;} +void foo17 () {__rvv_int8m4_t t;} +void foo18 () {__rvv_uint8m4_t t;} +void foo19 () {__rvv_int8m8_t t;} +void foo20 () {__rvv_uint8m8_t t;} +void foo21 () {__rvv_int16mf4_t t;} +void foo22 () {__rvv_uint16mf4_t t;} +void foo23 () {__rvv_int16mf2_t t;} +void foo24 () {__rvv_uint16mf2_t t;} +void foo25 () {__rvv_int16m1_t t;} +void foo26 () {__rvv_uint16m1_t t;} +void foo27 () {__rvv_int16m2_t t;} +void foo28 () {__rvv_uint16m2_t t;} +void foo29 () {__rvv_int16m4_t t;} +void foo30 () {__rvv_uint16m4_t t;} +void foo31 () {__rvv_int16m8_t t;} +void foo32 () {__rvv_uint16m8_t t;} +void foo33 () {__rvv_int32mf2_t t;} +void foo34 () {__rvv_uint32mf2_t t;} +void foo35 () {__rvv_int32m1_t t;} +void foo36 () {__rvv_uint32m1_t t;} +void foo37 () {__rvv_int32m2_t t;} +void foo38 () {__rvv_uint32m2_t t;} +void foo39 () {__rvv_int32m4_t t;} +void foo40 () {__rvv_uint32m4_t t;} +void foo41 () {__rvv_int32m8_t t;} +void foo42 () {__rvv_uint32m8_t t;} +void foo43 () {__rvv_int64m1_t t;} +void foo44 () {__rvv_uint64m1_t t;} +void foo45 () {__rvv_int64m2_t t;} +void foo46 () {__rvv_uint64m2_t t;} +void foo47 () {__rvv_int64m4_t t;} +void foo48 () {__rvv_uint64m4_t t;} +void foo49 () {__rvv_int64m8_t t;} +void foo50 () {__rvv_uint64m8_t t;} +void foo57 () {__rvv_float32mf2_t t;} +void foo58 () {__rvv_float32m1_t t;} +void foo59 () {__rvv_float32m2_t t;} +void foo60 () {__rvv_float32m4_t t;} +void foo61 () {__rvv_float32m8_t t;} +void foo62 () {__rvv_float64m1_t t;} +void foo63 () {__rvv_float64m2_t t;} +void foo64 () {__rvv_float64m4_t t;} +void foo65 () {__rvv_float64m8_t t;} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-2.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-2.c new file mode 100644 index 0000000..92e61c2 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-2.c @@ -0,0 +1,63 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -march=rv32gc -mabi=ilp32d" } */ + +void foo0 () {__rvv_bool64_t t;} /* { dg-error {unknown type name '__rvv_bool64_t'} } */ +void foo1 () {__rvv_bool32_t t;} /* { dg-error {unknown type name '__rvv_bool32_t'} } */ +void foo2 () {__rvv_bool16_t t;} /* { dg-error {unknown type name '__rvv_bool16_t'} } */ +void foo3 () {__rvv_bool8_t t;} /* { dg-error {unknown type name '__rvv_bool8_t'} } */ +void foo4 () {__rvv_bool4_t t;} /* { dg-error {unknown type name '__rvv_bool4_t'} } */ +void foo5 () {__rvv_bool2_t t;} /* { dg-error {unknown type name '__rvv_bool2_t'} } */ +void foo6 () {__rvv_bool1_t t;} /* { dg-error {unknown type name '__rvv_bool1_t'} } */ +void foo7 () {__rvv_int8mf8_t t;} /* { dg-error {unknown type name '__rvv_int8mf8_t'} } */ +void foo8 () {__rvv_uint8mf8_t t;} /* { dg-error {unknown type name '__rvv_uint8mf8_t'} } */ +void foo9 () {__rvv_int8mf4_t t;} /* { dg-error {unknown type name '__rvv_int8mf4_t'} } */ +void foo10 () {__rvv_uint8mf4_t t;} /* { dg-error {unknown type name '__rvv_uint8mf4_t'} } */ +void foo11 () {__rvv_int8mf2_t t;} /* { dg-error {unknown type name '__rvv_int8mf2_t'} } */ +void foo12 () {__rvv_uint8mf2_t t;} /* { dg-error {unknown type name '__rvv_uint8mf2_t'} } */ +void foo13 () {__rvv_int8m1_t t;} /* { dg-error {unknown type name '__rvv_int8m1_t'} } */ +void foo14 () {__rvv_uint8m1_t t;} /* { dg-error {unknown type name '__rvv_uint8m1_t'} } */ +void foo15 () {__rvv_int8m2_t t;} /* { dg-error {unknown type name '__rvv_int8m2_t'} } */ +void foo16 () {__rvv_uint8m2_t t;} /* { dg-error {unknown type name '__rvv_uint8m2_t'} } */ +void foo17 () {__rvv_int8m4_t t;} /* { dg-error {unknown type name '__rvv_int8m4_t'} } */ +void foo18 () {__rvv_uint8m4_t t;} /* { dg-error {unknown type name '__rvv_uint8m4_t'} } */ +void foo19 () {__rvv_int8m8_t t;} /* { dg-error {unknown type name '__rvv_int8m8_t'} } */ +void foo20 () {__rvv_uint8m8_t t;} /* { dg-error {unknown type name '__rvv_uint8m8_t'} } */ +void foo21 () {__rvv_int16mf4_t t;} /* { dg-error {unknown type name '__rvv_int16mf4_t'} } */ +void foo22 () {__rvv_uint16mf4_t t;} /* { dg-error {unknown type name '__rvv_uint16mf4_t'} } */ +void foo23 () {__rvv_int16mf2_t t;} /* { dg-error {unknown type name '__rvv_int16mf2_t'} } */ +void foo24 () {__rvv_uint16mf2_t t;} /* { dg-error {unknown type name '__rvv_uint16mf2_t'} } */ +void foo25 () {__rvv_int16m1_t t;} /* { dg-error {unknown type name '__rvv_int16m1_t'} } */ +void foo26 () {__rvv_uint16m1_t t;} /* { dg-error {unknown type name '__rvv_uint16m1_t'} } */ +void foo27 () {__rvv_int16m2_t t;} /* { dg-error {unknown type name '__rvv_int16m2_t'} } */ +void foo28 () {__rvv_uint16m2_t t;} /* { dg-error {unknown type name '__rvv_uint16m2_t'} } */ +void foo29 () {__rvv_int16m4_t t;} /* { dg-error {unknown type name '__rvv_int16m4_t'} } */ +void foo30 () {__rvv_uint16m4_t t;} /* { dg-error {unknown type name '__rvv_uint16m4_t'} } */ +void foo31 () {__rvv_int16m8_t t;} /* { dg-error {unknown type name '__rvv_int16m8_t'} } */ +void foo32 () {__rvv_uint16m8_t t;} /* { dg-error {unknown type name '__rvv_uint16m8_t'} } */ +void foo33 () {__rvv_int32mf2_t t;} /* { dg-error {unknown type name '__rvv_int32mf2_t'} } */ +void foo34 () {__rvv_uint32mf2_t t;} /* { dg-error {unknown type name '__rvv_uint32mf2_t'} } */ +void foo35 () {__rvv_int32m1_t t;} /* { dg-error {unknown type name '__rvv_int32m1_t'} } */ +void foo36 () {__rvv_uint32m1_t t;} /* { dg-error {unknown type name '__rvv_uint32m1_t'} } */ +void foo37 () {__rvv_int32m2_t t;} /* { dg-error {unknown type name '__rvv_int32m2_t'} } */ +void foo38 () {__rvv_uint32m2_t t;} /* { dg-error {unknown type name '__rvv_uint32m2_t'} } */ +void foo39 () {__rvv_int32m4_t t;} /* { dg-error {unknown type name '__rvv_int32m4_t'} } */ +void foo40 () {__rvv_uint32m4_t t;} /* { dg-error {unknown type name '__rvv_uint32m4_t'} } */ +void foo41 () {__rvv_int32m8_t t;} /* { dg-error {unknown type name '__rvv_int32m8_t'} } */ +void foo42 () {__rvv_uint32m8_t t;} /* { dg-error {unknown type name '__rvv_uint32m8_t'} } */ +void foo43 () {__rvv_int64m1_t t;} /* { dg-error {unknown type name '__rvv_int64m1_t'} } */ +void foo44 () {__rvv_uint64m1_t t;} /* { dg-error {unknown type name '__rvv_uint64m1_t'} } */ +void foo45 () {__rvv_int64m2_t t;} /* { dg-error {unknown type name '__rvv_int64m2_t'} } */ +void foo46 () {__rvv_uint64m2_t t;} /* { dg-error {unknown type name '__rvv_uint64m2_t'} } */ +void foo47 () {__rvv_int64m4_t t;} /* { dg-error {unknown type name '__rvv_int64m4_t'} } */ +void foo48 () {__rvv_uint64m4_t t;} /* { dg-error {unknown type name '__rvv_uint64m4_t'} } */ +void foo49 () {__rvv_int64m8_t t;} /* { dg-error {unknown type name '__rvv_int64m8_t'} } */ +void foo50 () {__rvv_uint64m8_t t;} /* { dg-error {unknown type name '__rvv_uint64m8_t'} } */ +void foo57 () {__rvv_float32mf2_t t;} /* { dg-error {unknown type name '__rvv_float32mf2_t'} } */ +void foo58 () {__rvv_float32m1_t t;} /* { dg-error {unknown type name '__rvv_float32m1_t'} } */ +void foo59 () {__rvv_float32m2_t t;} /* { dg-error {unknown type name '__rvv_float32m2_t'} } */ +void foo60 () {__rvv_float32m4_t t;} /* { dg-error {unknown type name '__rvv_float32m4_t'} } */ +void foo61 () {__rvv_float32m8_t t;} /* { dg-error {unknown type name '__rvv_float32m8_t'} } */ +void foo62 () {__rvv_float64m1_t t;} /* { dg-error {unknown type name '__rvv_float64m1_t'} } */ +void foo63 () {__rvv_float64m2_t t;} /* { dg-error {unknown type name '__rvv_float64m2_t'} } */ +void foo64 () {__rvv_float64m4_t t;} /* { dg-error {unknown type name '__rvv_float64m4_t'} } */ +void foo65 () {__rvv_float64m8_t t;} /* { dg-error {unknown type name '__rvv_float64m8_t'} } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-3.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-3.c new file mode 100644 index 0000000..b9adb30 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-3.c @@ -0,0 +1,63 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -march=rv32gc_zve64x -mabi=ilp32d" } */ + +void foo0 () {__rvv_bool64_t t;} +void foo1 () {__rvv_bool32_t t;} +void foo2 () {__rvv_bool16_t t;} +void foo3 () {__rvv_bool8_t t;} +void foo4 () {__rvv_bool4_t t;} +void foo5 () {__rvv_bool2_t t;} +void foo6 () {__rvv_bool1_t t;} +void foo7 () {__rvv_int8mf8_t t;} +void foo8 () {__rvv_uint8mf8_t t;} +void foo9 () {__rvv_int8mf4_t t;} +void foo10 () {__rvv_uint8mf4_t t;} +void foo11 () {__rvv_int8mf2_t t;} +void foo12 () {__rvv_uint8mf2_t t;} +void foo13 () {__rvv_int8m1_t t;} +void foo14 () {__rvv_uint8m1_t t;} +void foo15 () {__rvv_int8m2_t t;} +void foo16 () {__rvv_uint8m2_t t;} +void foo17 () {__rvv_int8m4_t t;} +void foo18 () {__rvv_uint8m4_t t;} +void foo19 () {__rvv_int8m8_t t;} +void foo20 () {__rvv_uint8m8_t t;} +void foo21 () {__rvv_int16mf4_t t;} +void foo22 () {__rvv_uint16mf4_t t;} +void foo23 () {__rvv_int16mf2_t t;} +void foo24 () {__rvv_uint16mf2_t t;} +void foo25 () {__rvv_int16m1_t t;} +void foo26 () {__rvv_uint16m1_t t;} +void foo27 () {__rvv_int16m2_t t;} +void foo28 () {__rvv_uint16m2_t t;} +void foo29 () {__rvv_int16m4_t t;} +void foo30 () {__rvv_uint16m4_t t;} +void foo31 () {__rvv_int16m8_t t;} +void foo32 () {__rvv_uint16m8_t t;} +void foo33 () {__rvv_int32mf2_t t;} +void foo34 () {__rvv_uint32mf2_t t;} +void foo35 () {__rvv_int32m1_t t;} +void foo36 () {__rvv_uint32m1_t t;} +void foo37 () {__rvv_int32m2_t t;} +void foo38 () {__rvv_uint32m2_t t;} +void foo39 () {__rvv_int32m4_t t;} +void foo40 () {__rvv_uint32m4_t t;} +void foo41 () {__rvv_int32m8_t t;} +void foo42 () {__rvv_uint32m8_t t;} +void foo43 () {__rvv_int64m1_t t;} +void foo44 () {__rvv_uint64m1_t t;} +void foo45 () {__rvv_int64m2_t t;} +void foo46 () {__rvv_uint64m2_t t;} +void foo47 () {__rvv_int64m4_t t;} +void foo48 () {__rvv_uint64m4_t t;} +void foo49 () {__rvv_int64m8_t t;} +void foo50 () {__rvv_uint64m8_t t;} +void foo57 () {__rvv_float32mf2_t t;} /* { dg-error {unknown type name '__rvv_float32mf2_t'} } */ +void foo58 () {__rvv_float32m1_t t;} /* { dg-error {unknown type name '__rvv_float32m1_t'} } */ +void foo59 () {__rvv_float32m2_t t;} /* { dg-error {unknown type name '__rvv_float32m2_t'} } */ +void foo60 () {__rvv_float32m4_t t;} /* { dg-error {unknown type name '__rvv_float32m4_t'} } */ +void foo61 () {__rvv_float32m8_t t;} /* { dg-error {unknown type name '__rvv_float32m8_t'} } */ +void foo62 () {__rvv_float64m1_t t;} /* { dg-error {unknown type name '__rvv_float64m1_t'} } */ +void foo63 () {__rvv_float64m2_t t;} /* { dg-error {unknown type name '__rvv_float64m2_t'} } */ +void foo64 () {__rvv_float64m4_t t;} /* { dg-error {unknown type name '__rvv_float64m4_t'} } */ +void foo65 () {__rvv_float64m8_t t;} /* { dg-error {unknown type name '__rvv_float64m8_t'} } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-4.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-4.c new file mode 100644 index 0000000..56a0ebe --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-4.c @@ -0,0 +1,63 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -march=rv32gc_zve64f -mabi=ilp32d" } */ + +void foo0 () {__rvv_bool64_t t;} +void foo1 () {__rvv_bool32_t t;} +void foo2 () {__rvv_bool16_t t;} +void foo3 () {__rvv_bool8_t t;} +void foo4 () {__rvv_bool4_t t;} +void foo5 () {__rvv_bool2_t t;} +void foo6 () {__rvv_bool1_t t;} +void foo7 () {__rvv_int8mf8_t t;} +void foo8 () {__rvv_uint8mf8_t t;} +void foo9 () {__rvv_int8mf4_t t;} +void foo10 () {__rvv_uint8mf4_t t;} +void foo11 () {__rvv_int8mf2_t t;} +void foo12 () {__rvv_uint8mf2_t t;} +void foo13 () {__rvv_int8m1_t t;} +void foo14 () {__rvv_uint8m1_t t;} +void foo15 () {__rvv_int8m2_t t;} +void foo16 () {__rvv_uint8m2_t t;} +void foo17 () {__rvv_int8m4_t t;} +void foo18 () {__rvv_uint8m4_t t;} +void foo19 () {__rvv_int8m8_t t;} +void foo20 () {__rvv_uint8m8_t t;} +void foo21 () {__rvv_int16mf4_t t;} +void foo22 () {__rvv_uint16mf4_t t;} +void foo23 () {__rvv_int16mf2_t t;} +void foo24 () {__rvv_uint16mf2_t t;} +void foo25 () {__rvv_int16m1_t t;} +void foo26 () {__rvv_uint16m1_t t;} +void foo27 () {__rvv_int16m2_t t;} +void foo28 () {__rvv_uint16m2_t t;} +void foo29 () {__rvv_int16m4_t t;} +void foo30 () {__rvv_uint16m4_t t;} +void foo31 () {__rvv_int16m8_t t;} +void foo32 () {__rvv_uint16m8_t t;} +void foo33 () {__rvv_int32mf2_t t;} +void foo34 () {__rvv_uint32mf2_t t;} +void foo35 () {__rvv_int32m1_t t;} +void foo36 () {__rvv_uint32m1_t t;} +void foo37 () {__rvv_int32m2_t t;} +void foo38 () {__rvv_uint32m2_t t;} +void foo39 () {__rvv_int32m4_t t;} +void foo40 () {__rvv_uint32m4_t t;} +void foo41 () {__rvv_int32m8_t t;} +void foo42 () {__rvv_uint32m8_t t;} +void foo43 () {__rvv_int64m1_t t;} +void foo44 () {__rvv_uint64m1_t t;} +void foo45 () {__rvv_int64m2_t t;} +void foo46 () {__rvv_uint64m2_t t;} +void foo47 () {__rvv_int64m4_t t;} +void foo48 () {__rvv_uint64m4_t t;} +void foo49 () {__rvv_int64m8_t t;} +void foo50 () {__rvv_uint64m8_t t;} +void foo57 () {__rvv_float32mf2_t t;} +void foo58 () {__rvv_float32m1_t t;} +void foo59 () {__rvv_float32m2_t t;} +void foo60 () {__rvv_float32m4_t t;} +void foo61 () {__rvv_float32m8_t t;} +void foo62 () {__rvv_float64m1_t t;} /* { dg-error {unknown type name '__rvv_float64m1_t'} } */ +void foo63 () {__rvv_float64m2_t t;} /* { dg-error {unknown type name '__rvv_float64m2_t'} } */ +void foo64 () {__rvv_float64m4_t t;} /* { dg-error {unknown type name '__rvv_float64m4_t'} } */ +void foo65 () {__rvv_float64m8_t t;} /* { dg-error {unknown type name '__rvv_float64m8_t'} } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-5.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-5.c new file mode 100644 index 0000000..af71609 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-5.c @@ -0,0 +1,63 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -march=rv32gc_zve64d -mabi=ilp32d" } */ + +void foo0 () {__rvv_bool64_t t;} +void foo1 () {__rvv_bool32_t t;} +void foo2 () {__rvv_bool16_t t;} +void foo3 () {__rvv_bool8_t t;} +void foo4 () {__rvv_bool4_t t;} +void foo5 () {__rvv_bool2_t t;} +void foo6 () {__rvv_bool1_t t;} +void foo7 () {__rvv_int8mf8_t t;} +void foo8 () {__rvv_uint8mf8_t t;} +void foo9 () {__rvv_int8mf4_t t;} +void foo10 () {__rvv_uint8mf4_t t;} +void foo11 () {__rvv_int8mf2_t t;} +void foo12 () {__rvv_uint8mf2_t t;} +void foo13 () {__rvv_int8m1_t t;} +void foo14 () {__rvv_uint8m1_t t;} +void foo15 () {__rvv_int8m2_t t;} +void foo16 () {__rvv_uint8m2_t t;} +void foo17 () {__rvv_int8m4_t t;} +void foo18 () {__rvv_uint8m4_t t;} +void foo19 () {__rvv_int8m8_t t;} +void foo20 () {__rvv_uint8m8_t t;} +void foo21 () {__rvv_int16mf4_t t;} +void foo22 () {__rvv_uint16mf4_t t;} +void foo23 () {__rvv_int16mf2_t t;} +void foo24 () {__rvv_uint16mf2_t t;} +void foo25 () {__rvv_int16m1_t t;} +void foo26 () {__rvv_uint16m1_t t;} +void foo27 () {__rvv_int16m2_t t;} +void foo28 () {__rvv_uint16m2_t t;} +void foo29 () {__rvv_int16m4_t t;} +void foo30 () {__rvv_uint16m4_t t;} +void foo31 () {__rvv_int16m8_t t;} +void foo32 () {__rvv_uint16m8_t t;} +void foo33 () {__rvv_int32mf2_t t;} +void foo34 () {__rvv_uint32mf2_t t;} +void foo35 () {__rvv_int32m1_t t;} +void foo36 () {__rvv_uint32m1_t t;} +void foo37 () {__rvv_int32m2_t t;} +void foo38 () {__rvv_uint32m2_t t;} +void foo39 () {__rvv_int32m4_t t;} +void foo40 () {__rvv_uint32m4_t t;} +void foo41 () {__rvv_int32m8_t t;} +void foo42 () {__rvv_uint32m8_t t;} +void foo43 () {__rvv_int64m1_t t;} +void foo44 () {__rvv_uint64m1_t t;} +void foo45 () {__rvv_int64m2_t t;} +void foo46 () {__rvv_uint64m2_t t;} +void foo47 () {__rvv_int64m4_t t;} +void foo48 () {__rvv_uint64m4_t t;} +void foo49 () {__rvv_int64m8_t t;} +void foo50 () {__rvv_uint64m8_t t;} +void foo57 () {__rvv_float32mf2_t t;} +void foo58 () {__rvv_float32m1_t t;} +void foo59 () {__rvv_float32m2_t t;} +void foo60 () {__rvv_float32m4_t t;} +void foo61 () {__rvv_float32m8_t t;} +void foo62 () {__rvv_float64m1_t t;} +void foo63 () {__rvv_float64m2_t t;} +void foo64 () {__rvv_float64m4_t t;} +void foo65 () {__rvv_float64m8_t t;} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-6.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-6.c new file mode 100644 index 0000000..e866c06 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-6.c @@ -0,0 +1,63 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -march=rv32gc_zve32x -mabi=ilp32d" } */ + +void foo0 () {__rvv_bool64_t t;} /* { dg-error {unknown type name '__rvv_bool64_t'} } */ +void foo1 () {__rvv_bool32_t t;} +void foo2 () {__rvv_bool16_t t;} +void foo3 () {__rvv_bool8_t t;} +void foo4 () {__rvv_bool4_t t;} +void foo5 () {__rvv_bool2_t t;} +void foo6 () {__rvv_bool1_t t;} +void foo7 () {__rvv_int8mf8_t t;} /* { dg-error {unknown type name '__rvv_int8mf8_t'} } */ +void foo8 () {__rvv_uint8mf8_t t;} /* { dg-error {unknown type name '__rvv_uint8mf8_t'} } */ +void foo9 () {__rvv_int8mf4_t t;} +void foo10 () {__rvv_uint8mf4_t t;} +void foo11 () {__rvv_int8mf2_t t;} +void foo12 () {__rvv_uint8mf2_t t;} +void foo13 () {__rvv_int8m1_t t;} +void foo14 () {__rvv_uint8m1_t t;} +void foo15 () {__rvv_int8m2_t t;} +void foo16 () {__rvv_uint8m2_t t;} +void foo17 () {__rvv_int8m4_t t;} +void foo18 () {__rvv_uint8m4_t t;} +void foo19 () {__rvv_int8m8_t t;} +void foo20 () {__rvv_uint8m8_t t;} +void foo21 () {__rvv_int16mf4_t t;} /* { dg-error {unknown type name '__rvv_int16mf4_t'} } */ +void foo22 () {__rvv_uint16mf4_t t;} /* { dg-error {unknown type name '__rvv_uint16mf4_t'} } */ +void foo23 () {__rvv_int16mf2_t t;} +void foo24 () {__rvv_uint16mf2_t t;} +void foo25 () {__rvv_int16m1_t t;} +void foo26 () {__rvv_uint16m1_t t;} +void foo27 () {__rvv_int16m2_t t;} +void foo28 () {__rvv_uint16m2_t t;} +void foo29 () {__rvv_int16m4_t t;} +void foo30 () {__rvv_uint16m4_t t;} +void foo31 () {__rvv_int16m8_t t;} +void foo32 () {__rvv_uint16m8_t t;} +void foo33 () {__rvv_int32mf2_t t;} /* { dg-error {unknown type name '__rvv_int32mf2_t'} } */ +void foo34 () {__rvv_uint32mf2_t t;} /* { dg-error {unknown type name '__rvv_uint32mf2_t'} } */ +void foo35 () {__rvv_int32m1_t t;} +void foo36 () {__rvv_uint32m1_t t;} +void foo37 () {__rvv_int32m2_t t;} +void foo38 () {__rvv_uint32m2_t t;} +void foo39 () {__rvv_int32m4_t t;} +void foo40 () {__rvv_uint32m4_t t;} +void foo41 () {__rvv_int32m8_t t;} +void foo42 () {__rvv_uint32m8_t t;} +void foo43 () {__rvv_int64m1_t t;} /* { dg-error {unknown type name '__rvv_int64m1_t'} } */ +void foo44 () {__rvv_uint64m1_t t;} /* { dg-error {unknown type name '__rvv_uint64m1_t'} } */ +void foo45 () {__rvv_int64m2_t t;} /* { dg-error {unknown type name '__rvv_int64m2_t'} } */ +void foo46 () {__rvv_uint64m2_t t;} /* { dg-error {unknown type name '__rvv_uint64m2_t'} } */ +void foo47 () {__rvv_int64m4_t t;} /* { dg-error {unknown type name '__rvv_int64m4_t'} } */ +void foo48 () {__rvv_uint64m4_t t;} /* { dg-error {unknown type name '__rvv_uint64m4_t'} } */ +void foo49 () {__rvv_int64m8_t t;} /* { dg-error {unknown type name '__rvv_int64m8_t'} } */ +void foo50 () {__rvv_uint64m8_t t;} /* { dg-error {unknown type name '__rvv_uint64m8_t'} } */ +void foo57 () {__rvv_float32mf2_t t;} /* { dg-error {unknown type name '__rvv_float32mf2_t'} } */ +void foo58 () {__rvv_float32m1_t t;} /* { dg-error {unknown type name '__rvv_float32m1_t'} } */ +void foo59 () {__rvv_float32m2_t t;} /* { dg-error {unknown type name '__rvv_float32m2_t'} } */ +void foo60 () {__rvv_float32m4_t t;} /* { dg-error {unknown type name '__rvv_float32m4_t'} } */ +void foo61 () {__rvv_float32m8_t t;} /* { dg-error {unknown type name '__rvv_float32m8_t'} } */ +void foo62 () {__rvv_float64m1_t t;} /* { dg-error {unknown type name '__rvv_float64m1_t'} } */ +void foo63 () {__rvv_float64m2_t t;} /* { dg-error {unknown type name '__rvv_float64m2_t'} } */ +void foo64 () {__rvv_float64m4_t t;} /* { dg-error {unknown type name '__rvv_float64m4_t'} } */ +void foo65 () {__rvv_float64m8_t t;} /* { dg-error {unknown type name '__rvv_float64m8_t'} } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-7.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-7.c new file mode 100644 index 0000000..407756d --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-7.c @@ -0,0 +1,63 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -march=rv32gc_zve32f -mabi=ilp32d" } */ + +void foo0 () {__rvv_bool64_t t;} /* { dg-error {unknown type name '__rvv_bool64_t'} } */ +void foo1 () {__rvv_bool32_t t;} +void foo2 () {__rvv_bool16_t t;} +void foo3 () {__rvv_bool8_t t;} +void foo4 () {__rvv_bool4_t t;} +void foo5 () {__rvv_bool2_t t;} +void foo6 () {__rvv_bool1_t t;} +void foo7 () {__rvv_int8mf8_t t;} /* { dg-error {unknown type name '__rvv_int8mf8_t'} } */ +void foo8 () {__rvv_uint8mf8_t t;} /* { dg-error {unknown type name '__rvv_uint8mf8_t'} } */ +void foo9 () {__rvv_int8mf4_t t;} +void foo10 () {__rvv_uint8mf4_t t;} +void foo11 () {__rvv_int8mf2_t t;} +void foo12 () {__rvv_uint8mf2_t t;} +void foo13 () {__rvv_int8m1_t t;} +void foo14 () {__rvv_uint8m1_t t;} +void foo15 () {__rvv_int8m2_t t;} +void foo16 () {__rvv_uint8m2_t t;} +void foo17 () {__rvv_int8m4_t t;} +void foo18 () {__rvv_uint8m4_t t;} +void foo19 () {__rvv_int8m8_t t;} +void foo20 () {__rvv_uint8m8_t t;} +void foo21 () {__rvv_int16mf4_t t;} /* { dg-error {unknown type name '__rvv_int16mf4_t'} } */ +void foo22 () {__rvv_uint16mf4_t t;} /* { dg-error {unknown type name '__rvv_uint16mf4_t'} } */ +void foo23 () {__rvv_int16mf2_t t;} +void foo24 () {__rvv_uint16mf2_t t;} +void foo25 () {__rvv_int16m1_t t;} +void foo26 () {__rvv_uint16m1_t t;} +void foo27 () {__rvv_int16m2_t t;} +void foo28 () {__rvv_uint16m2_t t;} +void foo29 () {__rvv_int16m4_t t;} +void foo30 () {__rvv_uint16m4_t t;} +void foo31 () {__rvv_int16m8_t t;} +void foo32 () {__rvv_uint16m8_t t;} +void foo33 () {__rvv_int32mf2_t t;} /* { dg-error {unknown type name '__rvv_int32mf2_t'} } */ +void foo34 () {__rvv_uint32mf2_t t;} /* { dg-error {unknown type name '__rvv_uint32mf2_t'} } */ +void foo35 () {__rvv_int32m1_t t;} +void foo36 () {__rvv_uint32m1_t t;} +void foo37 () {__rvv_int32m2_t t;} +void foo38 () {__rvv_uint32m2_t t;} +void foo39 () {__rvv_int32m4_t t;} +void foo40 () {__rvv_uint32m4_t t;} +void foo41 () {__rvv_int32m8_t t;} +void foo42 () {__rvv_uint32m8_t t;} +void foo43 () {__rvv_int64m1_t t;} /* { dg-error {unknown type name '__rvv_int64m1_t'} } */ +void foo44 () {__rvv_uint64m1_t t;} /* { dg-error {unknown type name '__rvv_uint64m1_t'} } */ +void foo45 () {__rvv_int64m2_t t;} /* { dg-error {unknown type name '__rvv_int64m2_t'} } */ +void foo46 () {__rvv_uint64m2_t t;} /* { dg-error {unknown type name '__rvv_uint64m2_t'} } */ +void foo47 () {__rvv_int64m4_t t;} /* { dg-error {unknown type name '__rvv_int64m4_t'} } */ +void foo48 () {__rvv_uint64m4_t t;} /* { dg-error {unknown type name '__rvv_uint64m4_t'} } */ +void foo49 () {__rvv_int64m8_t t;} /* { dg-error {unknown type name '__rvv_int64m8_t'} } */ +void foo50 () {__rvv_uint64m8_t t;} /* { dg-error {unknown type name '__rvv_uint64m8_t'} } */ +void foo57 () {__rvv_float32mf2_t t;} /* { dg-error {unknown type name '__rvv_float32mf2_t'} } */ +void foo58 () {__rvv_float32m1_t t;} +void foo59 () {__rvv_float32m2_t t;} +void foo60 () {__rvv_float32m4_t t;} +void foo61 () {__rvv_float32m8_t t;} +void foo62 () {__rvv_float64m1_t t;} /* { dg-error {unknown type name '__rvv_float64m1_t'} } */ +void foo63 () {__rvv_float64m2_t t;} /* { dg-error {unknown type name '__rvv_float64m2_t'} } */ +void foo64 () {__rvv_float64m4_t t;} /* { dg-error {unknown type name '__rvv_float64m4_t'} } */ +void foo65 () {__rvv_float64m8_t t;} /* { dg-error {unknown type name '__rvv_float64m8_t'} } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp b/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp new file mode 100644 index 0000000..25e09f4 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp @@ -0,0 +1,47 @@ +# Copyright (C) 2022-2022 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +# GCC testsuite that uses the `dg.exp' driver. + +# Exit immediately if this isn't a RISC-V target. +if ![istarget riscv*-*-*] then { + return +} + +# Load support procs. +load_lib gcc-dg.exp + +# If a testcase doesn't have special options, use these. +global DEFAULT_CFLAGS +if ![info exists DEFAULT_CFLAGS] then { + set DEFAULT_CFLAGS " -ansi -pedantic-errors" +} + +set gcc_march "rv64gcv_zfh" +if [istarget riscv32-*-*] then { + set gcc_march "rv32gcv_zfh" +} + +# Initialize `dg'. +dg-init + +# Main loop. +set CFLAGS "$DEFAULT_CFLAGS -march=$gcc_march -O3" +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/base/*.\[cS\]]] \ + "" $CFLAGS + +# All done. +dg-finish 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/pr107054.f90 b/gcc/testsuite/gfortran.dg/pr107054.f90 new file mode 100644 index 0000000..bbfe646 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr107054.f90 @@ -0,0 +1,13 @@ +! { dg-do compile } +! PR fortran/107054 - ICE in gfc_simplify_unpack +! Contributed by G.Steinmetz + +program p + type t + integer :: n = 0 + end type + type(t), parameter :: a(4) = t(2) + type(t), parameter :: b(4) = reshape(a,[2]) ! { dg-error "Different shape" } + type(t), parameter :: c(2) = pack(b,[.false.,.true.,.false.,.true.]) ! { dg-error "Different shape" } + type(t), parameter :: d(4) = unpack(c,[.false.,.true.,.false.,.true.],a) +end diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc index 53be0c2..ade66c5 100644 --- a/gcc/tree-cfg.cc +++ b/gcc/tree-cfg.cc @@ -1166,7 +1166,33 @@ same_line_p (location_t locus1, expanded_location *from, location_t locus2) && filename_cmp (from->file, to.file) == 0); } -/* Assign discriminators to each basic block. */ +/* Assign a unique discriminator value to all statements in block bb that + have the same line number as locus. */ + +static void +assign_discriminator (location_t locus, basic_block bb) +{ + gimple_stmt_iterator gsi; + int discriminator; + + if (locus == UNKNOWN_LOCATION) + return; + + expanded_location locus_e = expand_location (locus); + + discriminator = next_discriminator_for_locus (locus_e.line); + + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple *stmt = gsi_stmt (gsi); + location_t stmt_locus = gimple_location (stmt); + if (same_line_p (locus, &locus_e, stmt_locus)) + gimple_set_location (stmt, + location_with_discriminator (stmt_locus, discriminator)); + } +} + +/* Assign discriminators to statement locations. */ static void assign_discriminators (void) @@ -1189,17 +1215,22 @@ assign_discriminators (void) { gimple *first = first_non_label_stmt (e->dest); gimple *last = last_stmt (e->dest); - if ((first && same_line_p (locus, &locus_e, + + gimple *stmt_on_same_line = NULL; + if (first && same_line_p (locus, &locus_e, gimple_location (first))) - || (last && same_line_p (locus, &locus_e, - gimple_location (last)))) + stmt_on_same_line = first; + else if (last && same_line_p (locus, &locus_e, + gimple_location (last))) + stmt_on_same_line = last; + + if (stmt_on_same_line) { - if (e->dest->discriminator != 0 && bb->discriminator == 0) - bb->discriminator - = next_discriminator_for_locus (locus_e.line); + if (has_discriminator (gimple_location (stmt_on_same_line)) + && !has_discriminator (locus)) + assign_discriminator (locus, bb); else - e->dest->discriminator - = next_discriminator_for_locus (locus_e.line); + assign_discriminator (locus, e->dest); } } } 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-pretty-print.cc b/gcc/tree-pretty-print.cc index 33b12c7..e7a8c94 100644 --- a/gcc/tree-pretty-print.cc +++ b/gcc/tree-pretty-print.cc @@ -1455,6 +1455,7 @@ void dump_location (pretty_printer *pp, location_t loc) { expanded_location xloc = expand_location (loc); + int discriminator = get_discriminator_from_loc (loc); pp_left_bracket (pp); if (xloc.file) @@ -1465,6 +1466,11 @@ dump_location (pretty_printer *pp, location_t loc) pp_decimal_int (pp, xloc.line); pp_colon (pp); pp_decimal_int (pp, xloc.column); + if (discriminator) + { + pp_string (pp, " discrim "); + pp_decimal_int (pp, discriminator); + } pp_string (pp, "] "); } 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-ssa-uninit.cc b/gcc/tree-ssa-uninit.cc index eae29f8..bde2399 100644 --- a/gcc/tree-ssa-uninit.cc +++ b/gcc/tree-ssa-uninit.cc @@ -991,14 +991,20 @@ warn_uninitialized_vars (bool wmaybe_uninit) auto_bb_flag ft_reachable (cfun); /* Mark blocks that are always executed when we ignore provably - not executed edges. */ + not executed and EH and abnormal edges. */ basic_block bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)); while (!(bb->flags & ft_reachable)) { bb->flags |= ft_reachable; + edge e = find_fallthru_edge (bb->succs); + if (e && e->flags & EDGE_EXECUTABLE) + { + bb = e->dest; + continue; + } /* Find a single executable edge. */ edge_iterator ei; - edge e, ee = NULL; + edge ee = NULL; FOR_EACH_EDGE (e, ei, bb->succs) if (e->flags & EDGE_EXECUTABLE) { diff --git a/gcc/tree-vect-loop-manip.cc b/gcc/tree-vect-loop-manip.cc index 74b221a..1d96130 100644 --- a/gcc/tree-vect-loop-manip.cc +++ b/gcc/tree-vect-loop-manip.cc @@ -1413,6 +1413,7 @@ vect_can_advance_ivs_p (loop_vec_info loop_vinfo) for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi)) { tree evolution_part; + enum vect_induction_op_type induction_type; gphi *phi = gsi.phi (); stmt_vec_info phi_info = loop_vinfo->lookup_stmt (phi); @@ -1432,6 +1433,15 @@ vect_can_advance_ivs_p (loop_vec_info loop_vinfo) continue; } + induction_type = STMT_VINFO_LOOP_PHI_EVOLUTION_TYPE (phi_info); + if (induction_type != vect_step_op_add) + { + if (!vect_can_peel_nonlinear_iv_p (loop_vinfo, induction_type)) + return false; + + continue; + } + /* Analyze the evolution function. */ evolution_part = STMT_VINFO_LOOP_PHI_EVOLUTION_PART (phi_info); diff --git a/gcc/tree-vect-loop.cc b/gcc/tree-vect-loop.cc index aabdc6f..2536cc3 100644 --- a/gcc/tree-vect-loop.cc +++ b/gcc/tree-vect-loop.cc @@ -8558,6 +8558,50 @@ vect_update_nonlinear_iv (gimple_seq* stmts, tree vectype, return vec_def; } + +/* Return true if vectorizer can peel for nonlinear iv. */ +bool +vect_can_peel_nonlinear_iv_p (loop_vec_info loop_vinfo, + enum vect_induction_op_type induction_type) +{ + tree niters_skip; + /* Init_expr will be update by vect_update_ivs_after_vectorizer, + if niters is unkown: + For shift, when shift mount >= precision, there would be UD. + For mult, don't known how to generate + init_expr * pow (step, niters) for variable niters. + For neg, it should be ok, since niters of vectorized main loop + will always be multiple of 2. */ + if (!LOOP_VINFO_NITERS_KNOWN_P (loop_vinfo) + && induction_type != vect_step_op_neg) + { + if (dump_enabled_p ()) + dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, + "Peeling for epilogue is not supported" + " for nonlinear induction except neg" + " when iteration count is unknown.\n"); + return false; + } + + /* Also doens't support peel for neg when niter is variable. + ??? generate something like niter_expr & 1 ? init_expr : -init_expr? */ + niters_skip = LOOP_VINFO_MASK_SKIP_NITERS (loop_vinfo); + if ((niters_skip != NULL_TREE + && TREE_CODE (niters_skip) != INTEGER_CST) + || (!vect_use_loop_mask_for_alignment_p (loop_vinfo) + && LOOP_VINFO_PEELING_FOR_ALIGNMENT (loop_vinfo) < 0)) + { + if (dump_enabled_p ()) + dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, + "Peeling for alignement is not supported" + " for nonlinear induction when niters_skip" + " is not constant.\n"); + return false; + } + + return true; +} + /* Function vectorizable_induction Check if STMT_INFO performs an nonlinear induction computation that can be @@ -8628,42 +8672,9 @@ vectorizable_nonlinear_induction (loop_vec_info loop_vinfo, return false; } - /* Init_expr will be update by vect_update_ivs_after_vectorizer, - if niters is unkown: - For shift, when shift mount >= precision, there would be UD. - For mult, don't known how to generate - init_expr * pow (step, niters) for variable niters. - For neg, it should be ok, since niters of vectorized main loop - will always be multiple of 2. */ - if (!LOOP_VINFO_NITERS_KNOWN_P (loop_vinfo) - && induction_type != vect_step_op_neg) - { - if (dump_enabled_p ()) - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, - "Peeling for epilogue is not supported" - " for nonlinear induction except neg" - " when iteration count is unknown.\n"); - return false; - } - - /* Also doens't support peel for neg when niter is variable. - ??? generate something like niter_expr & 1 ? init_expr : -init_expr? */ - niters_skip = LOOP_VINFO_MASK_SKIP_NITERS (loop_vinfo); - if ((niters_skip != NULL_TREE - && TREE_CODE (niters_skip) != INTEGER_CST) - || (!vect_use_loop_mask_for_alignment_p (loop_vinfo) - && LOOP_VINFO_PEELING_FOR_ALIGNMENT (loop_vinfo) < 0)) - { - if (dump_enabled_p ()) - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, - "Peeling for alignement is not supported" - " for nonlinear induction when niters_skip" - " is not constant.\n"); - return false; - } + if (!vect_can_peel_nonlinear_iv_p (loop_vinfo, induction_type)) + return false; - if (!LOOP_VINFO_NITERS_KNOWN_P (loop_vinfo) - && induction_type == vect_step_op_mul) if (!INTEGRAL_TYPE_P (TREE_TYPE (vectype))) { if (dump_enabled_p ()) @@ -8799,6 +8810,7 @@ vectorizable_nonlinear_induction (loop_vec_info loop_vinfo, gimple_seq stmts = NULL; + niters_skip = LOOP_VINFO_MASK_SKIP_NITERS (loop_vinfo); /* If we are using the loop mask to "peel" for alignment then we need to adjust the start value here. */ if (niters_skip != NULL_TREE) diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h index 5e75ed1..4870c75 100644 --- a/gcc/tree-vectorizer.h +++ b/gcc/tree-vectorizer.h @@ -2343,6 +2343,9 @@ extern tree cse_and_gimplify_to_preheader (loop_vec_info, tree); /* Nonlinear induction. */ extern tree vect_peel_nonlinear_iv_init (gimple_seq*, tree, tree, tree, enum vect_induction_op_type); +extern bool +vect_can_peel_nonlinear_iv_p (loop_vec_info loop_vinfo, + enum vect_induction_op_type induction_type); /* In tree-vect-slp.cc. */ extern void vect_slp_init (void); diff --git a/gcc/tree.cc b/gcc/tree.cc index 4165cbd..f8d24b5 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); @@ -14252,7 +14253,8 @@ set_block (location_t loc, tree block) { location_t pure_loc = get_pure_location (loc); source_range src_range = get_range_from_loc (line_table, loc); - return COMBINE_LOCATION_DATA (line_table, pure_loc, src_range, block); + unsigned discriminator = get_discriminator_from_loc (line_table, loc); + return COMBINE_LOCATION_DATA (line_table, pure_loc, src_range, block, discriminator); } location_t @@ -14270,11 +14272,14 @@ set_source_range (tree expr, source_range src_range) if (!EXPR_P (expr)) return UNKNOWN_LOCATION; - location_t pure_loc = get_pure_location (EXPR_LOCATION (expr)); + location_t expr_location = EXPR_LOCATION (expr); + location_t pure_loc = get_pure_location (expr_location); + unsigned discriminator = get_discriminator_from_loc (expr_location); location_t adhoc = COMBINE_LOCATION_DATA (line_table, pure_loc, src_range, - NULL); + NULL, + discriminator); SET_EXPR_LOCATION (expr, adhoc); return adhoc; } @@ -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 754379a..6154d73 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -2930,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 { diff --git a/gcc/var-tracking.cc b/gcc/var-tracking.cc index 235981d..9c40ec4 100644 --- a/gcc/var-tracking.cc +++ b/gcc/var-tracking.cc @@ -9906,6 +9906,23 @@ vt_add_function_parameter (tree parm) VAR_INIT_STATUS_INITIALIZED, NULL, INSERT); } } + + if (GET_MODE_CLASS (mode) == MODE_INT) + { + machine_mode wider_mode_iter; + FOR_EACH_WIDER_MODE (wider_mode_iter, mode) + { + if (!HWI_COMPUTABLE_MODE_P (wider_mode_iter)) + break; + rtx wider_reg + = gen_rtx_REG (wider_mode_iter, REGNO (incoming)); + cselib_val *wider_val + = cselib_lookup_from_insn (wider_reg, wider_mode_iter, 1, + VOIDmode, get_insns ()); + preserve_value (wider_val); + record_entry_value (wider_val, wider_reg); + } + } } } else if (GET_CODE (incoming) == PARALLEL && !dv_onepart_p (dv)) |