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 | |
parent | 3c527a35fa428b727807c81f1225a5e0025446c1 (diff) | |
parent | a1cd4d52d6ef90b977fb2d80c1cf17f3efa5b01d (diff) | |
download | gcc-54f3cfaf3a6f50958c71d79c85206a6c722e1a22.zip gcc-54f3cfaf3a6f50958c71d79c85206a6c722e1a22.tar.gz gcc-54f3cfaf3a6f50958c71d79c85206a6c722e1a22.tar.bz2 |
Merge branch 'master' into devel/sphinx
416 files changed, 10691 insertions, 5774 deletions
@@ -1,3 +1,7 @@ +2022-09-26 Jeff Law <jlaw@ventanamicro.com> + + * MAINTAINERS: Update my email address and DCO entry. + 2022-09-23 Paul-Antoine Arras <pa@codesourcery.com> * MAINTAINERS (Write After Approval): Add myself. diff --git a/fixincludes/ChangeLog b/fixincludes/ChangeLog index d67e572..0b88d27 100644 --- a/fixincludes/ChangeLog +++ b/fixincludes/ChangeLog @@ -1,3 +1,19 @@ +2022-09-27 Jakub Jelinek <jakub@redhat.com> + + * inclhack.def (glibc_cxx_floatn_1, glibc_cxx_floatn_2, + glibc_cxx_floatn_3): Add to files also "*/bits/floatn.h" + and "*/bits/floatn-common.h". + * fixincl.x: Regenerated. + +2022-09-27 Jakub Jelinek <jakub@redhat.com> + + PR c++/106652 + PR c++/85518 + * inclhack.def (glibc_cxx_floatn_1, glibc_cxx_floatn_2, + glibc_cxx_floatn_3): New fixes. + * tests/base/bits/floatn.h: New file. + * fixincl.x: Regenerated. + 2022-08-31 Martin Liska <mliska@suse.cz> * configure: Regenerate. diff --git a/fixincludes/fixincl.x b/fixincludes/fixincl.x index bad4904..6309723 100644 --- a/fixincludes/fixincl.x +++ b/fixincludes/fixincl.x @@ -2,11 +2,11 @@ * * DO NOT EDIT THIS FILE (fixincl.x) * - * It has been AutoGen-ed February 27, 2022 at 07:47:03 PM by AutoGen 5.18.16 + * It has been AutoGen-ed September 27, 2022 at 12:21:44 PM by AutoGen 5.18.16 * From the definitions inclhack.def * and the template file fixincl */ -/* DO NOT SVN-MERGE THIS FILE, EITHER Sun Feb 27 19:47:03 UTC 2022 +/* DO NOT SVN-MERGE THIS FILE, EITHER Tue Sep 27 12:21:44 CEST 2022 * * You must regenerate it. Use the ./genfixes script. * @@ -15,7 +15,7 @@ * certain ANSI-incompatible system header files which are fixed to work * correctly with ANSI C and placed in a directory that GNU C will search. * - * This file contains 267 fixup descriptions. + * This file contains 270 fixup descriptions. * * See README for more information. * @@ -4107,6 +4107,132 @@ static const char* apzGlibc_C99_Inline_4Patch[] = { /* * * * * * * * * * * * * * * * * * * * * * * * * * * + * Description of Glibc_Cxx_Floatn_1 fix + */ +tSCC zGlibc_Cxx_Floatn_1Name[] = + "glibc_cxx_floatn_1"; + +/* + * File name selection pattern + */ +tSCC zGlibc_Cxx_Floatn_1List[] = + "bits/floatn.h\0bits/floatn-common.h\0*/bits/floatn.h\0*/bits/floatn-common.h\0"; +/* + * Machine/OS name selection pattern + */ +#define apzGlibc_Cxx_Floatn_1Machs (const char**)NULL + +/* + * content selection pattern - do fix if pattern found + */ +tSCC zGlibc_Cxx_Floatn_1Select0[] = + "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n\ +(([ \t]*/\\*[^\n\ +]*\\*/\n\ +)?([ \t]*#[ \t]*if[^\n\ +]*\n\ +)?[ \t]*#[ \t]*define __f(16|32|64|128)x?\\()"; + +#define GLIBC_CXX_FLOATN_1_TEST_CT 1 +static tTestDesc aGlibc_Cxx_Floatn_1Tests[] = { + { TT_EGREP, zGlibc_Cxx_Floatn_1Select0, (regex_t*)NULL }, }; + +/* + * Fix Command Arguments for Glibc_Cxx_Floatn_1 + */ +static const char* apzGlibc_Cxx_Floatn_1Patch[] = { + "format", + "%1(defined __cplusplus && !__GNUC_PREREQ (13, 0))\n\ +%2", + (char*)NULL }; + +/* * * * * * * * * * * * * * * * * * * * * * * * * * + * + * Description of Glibc_Cxx_Floatn_2 fix + */ +tSCC zGlibc_Cxx_Floatn_2Name[] = + "glibc_cxx_floatn_2"; + +/* + * File name selection pattern + */ +tSCC zGlibc_Cxx_Floatn_2List[] = + "bits/floatn.h\0bits/floatn-common.h\0*/bits/floatn.h\0*/bits/floatn-common.h\0"; +/* + * Machine/OS name selection pattern + */ +#define apzGlibc_Cxx_Floatn_2Machs (const char**)NULL + +/* + * content selection pattern - do fix if pattern found + */ +tSCC zGlibc_Cxx_Floatn_2Select0[] = + "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n\ +(([ \t]*/\\*[^\n\ +]*\\*/\n\ +)?[ \t]*typedef[ \t]+[^\n\ +]*[ \t]+_Float(16|32|64|128)x?([ \t]+__attribute__ \\(\\(__mode__ \\(__HF__\\)\\)\\))?;)"; + +#define GLIBC_CXX_FLOATN_2_TEST_CT 1 +static tTestDesc aGlibc_Cxx_Floatn_2Tests[] = { + { TT_EGREP, zGlibc_Cxx_Floatn_2Select0, (regex_t*)NULL }, }; + +/* + * Fix Command Arguments for Glibc_Cxx_Floatn_2 + */ +static const char* apzGlibc_Cxx_Floatn_2Patch[] = { + "format", + "%1(defined __cplusplus && !__GNUC_PREREQ (13, 0))\n\ +%2", + (char*)NULL }; + +/* * * * * * * * * * * * * * * * * * * * * * * * * * + * + * Description of Glibc_Cxx_Floatn_3 fix + */ +tSCC zGlibc_Cxx_Floatn_3Name[] = + "glibc_cxx_floatn_3"; + +/* + * File name selection pattern + */ +tSCC zGlibc_Cxx_Floatn_3List[] = + "bits/floatn.h\0bits/floatn-common.h\0*/bits/floatn.h\0*/bits/floatn-common.h\0"; +/* + * Machine/OS name selection pattern + */ +#define apzGlibc_Cxx_Floatn_3Machs (const char**)NULL + +/* + * content selection pattern - do fix if pattern found + */ +tSCC zGlibc_Cxx_Floatn_3Select0[] = + "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n\ +(([ \t]*/\\*[^\n\ +]*\n\ +?[^\n\ +]*\\*/\n\ +)?([ \t]*#[ \t]*if[^\n\ +]*\n\ +)?([ \t]*typedef[ \t]+[^\n\ +]*;\n\ +)?[ \t]*#[ \t]*define __CFLOAT(16|32|64|128)X?[ \t]+)"; + +#define GLIBC_CXX_FLOATN_3_TEST_CT 1 +static tTestDesc aGlibc_Cxx_Floatn_3Tests[] = { + { TT_EGREP, zGlibc_Cxx_Floatn_3Select0, (regex_t*)NULL }, }; + +/* + * Fix Command Arguments for Glibc_Cxx_Floatn_3 + */ +static const char* apzGlibc_Cxx_Floatn_3Patch[] = { + "format", + "%1(defined __cplusplus && !__GNUC_PREREQ (13, 0))\n\ +%2", + (char*)NULL }; + +/* * * * * * * * * * * * * * * * * * * * * * * * * * + * * Description of Glibc_Mutex_Init fix */ tSCC zGlibc_Mutex_InitName[] = @@ -10872,9 +10998,9 @@ static const char* apzX11_SprintfPatch[] = { * * List of all fixes */ -#define REGEX_COUNT 305 +#define REGEX_COUNT 308 #define MACH_LIST_SIZE_LIMIT 187 -#define FIX_COUNT 267 +#define FIX_COUNT 270 /* * Enumerate the fixes @@ -10977,6 +11103,9 @@ typedef enum { GLIBC_C99_INLINE_2_FIXIDX, GLIBC_C99_INLINE_3_FIXIDX, GLIBC_C99_INLINE_4_FIXIDX, + GLIBC_CXX_FLOATN_1_FIXIDX, + GLIBC_CXX_FLOATN_2_FIXIDX, + GLIBC_CXX_FLOATN_3_FIXIDX, GLIBC_MUTEX_INIT_FIXIDX, GLIBC_STDINT_FIXIDX, GLIBC_STRNCPY_FIXIDX, @@ -11635,6 +11764,21 @@ tFixDesc fixDescList[ FIX_COUNT ] = { GLIBC_C99_INLINE_4_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE, aGlibc_C99_Inline_4Tests, apzGlibc_C99_Inline_4Patch, 0 }, + { zGlibc_Cxx_Floatn_1Name, zGlibc_Cxx_Floatn_1List, + apzGlibc_Cxx_Floatn_1Machs, + GLIBC_CXX_FLOATN_1_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE, + aGlibc_Cxx_Floatn_1Tests, apzGlibc_Cxx_Floatn_1Patch, 0 }, + + { zGlibc_Cxx_Floatn_2Name, zGlibc_Cxx_Floatn_2List, + apzGlibc_Cxx_Floatn_2Machs, + GLIBC_CXX_FLOATN_2_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE, + aGlibc_Cxx_Floatn_2Tests, apzGlibc_Cxx_Floatn_2Patch, 0 }, + + { zGlibc_Cxx_Floatn_3Name, zGlibc_Cxx_Floatn_3List, + apzGlibc_Cxx_Floatn_3Machs, + GLIBC_CXX_FLOATN_3_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE, + aGlibc_Cxx_Floatn_3Tests, apzGlibc_Cxx_Floatn_3Patch, 0 }, + { zGlibc_Mutex_InitName, zGlibc_Mutex_InitList, apzGlibc_Mutex_InitMachs, GLIBC_MUTEX_INIT_TEST_CT, FD_MACH_ONLY, diff --git a/fixincludes/inclhack.def b/fixincludes/inclhack.def index 7605ac8..88bf28f 100644 --- a/fixincludes/inclhack.def +++ b/fixincludes/inclhack.def @@ -2015,6 +2015,102 @@ fix = { EOT; }; +/* glibc-2.27 to 2.36 assume GCC 7 or later supports some or all + * of _Float{16,32,64,128} and _Float{32,64,128}x keywords for C, + * but doesn't for C++. + */ +fix = { + hackname = glibc_cxx_floatn_1; + files = bits/floatn.h, bits/floatn-common.h, "*/bits/floatn.h", "*/bits/floatn-common.h"; + select = "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n" + "(([ \t]*/\\*[^\n]*\\*/\n)?" + "([ \t]*#[ \t]*if[^\n]*\n)?" + "[ \t]*#[ \t]*define __f(16|32|64|128)x?\\()"; + c_fix = format; + c_fix_arg = "%1(defined __cplusplus && !__GNUC_PREREQ (13, 0))\n%2"; + test_text = <<-EOT + # if !__GNUC_PREREQ (7, 0) || defined __cplusplus + /* The literal suffix f128 exists only since GCC 7.0. */ + # define __f128(x) x##l + # else + # define __f128(x) x##f128 + # endif + # if !__GNUC_PREREQ (7, 0) || defined __cplusplus + /* The literal suffix (f128) exist for powerpc only since GCC 7.0. */ + # if __LDBL_MANT_DIG__ == 113 + # define __f128(x) x##l + # else + # define __f128(x) x##q + # endif + # else + # define __f128(x) x##f128 + # endif + # if !__GNUC_PREREQ (7, 0) || defined __cplusplus + # ifdef __NO_LONG_DOUBLE_MATH + # define __f64(x) x##l + # else + # define __f64(x) x + # endif + # else + # define __f64(x) x##f64 + # endif + EOT; +}; + +fix = { + hackname = glibc_cxx_floatn_2; + files = bits/floatn.h, bits/floatn-common.h, "*/bits/floatn.h", "*/bits/floatn-common.h"; + select = "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n" + "(([ \t]*/\\*[^\n]*\\*/\n)?" + "[ \t]*typedef[ \t]+[^\n]*[ \t]+_Float(16|32|64|128)x?([ \t]+__attribute__ \\(\\(__mode__ \\(__HF__\\)\\)\\))?;)"; + c_fix = format; + c_fix_arg = "%1(defined __cplusplus && !__GNUC_PREREQ (13, 0))\n%2"; + test_text = <<-EOT + # if !__GNUC_PREREQ (7, 0) || defined __cplusplus + typedef float _Float16 __attribute__ ((__mode__ (__HF__))); + # endif + # if !__GNUC_PREREQ (7, 0) || defined __cplusplus + typedef __float128 _Float128; + # endif + EOT; +}; + +fix = { + hackname = glibc_cxx_floatn_3; + files = bits/floatn.h, bits/floatn-common.h, "*/bits/floatn.h", "*/bits/floatn-common.h"; + select = "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n" + "(([ \t]*/\\*[^\n]*\n?[^\n]*\\*/\n)?" + "([ \t]*#[ \t]*if[^\n]*\n)?" + "([ \t]*typedef[ \t]+[^\n]*;\n)?" + "[ \t]*#[ \t]*define __CFLOAT(16|32|64|128)X?[ \t]+)"; + c_fix = format; + c_fix_arg = "%1(defined __cplusplus && !__GNUC_PREREQ (13, 0))\n%2"; + test_text = <<-EOT + # if !__GNUC_PREREQ (7, 0) || defined __cplusplus + # define __CFLOAT128 _Complex long double + # else + # define __CFLOAT128 _Complex _Float128 + # endif + # if !__GNUC_PREREQ (7, 0) || defined __cplusplus + /* Add a typedef for older GCC compilers which don't natively support + _Complex _Float128. */ + typedef _Complex float __cfloat128 __attribute__ ((__mode__ (__TC__))); + # define __CFLOAT128 __cfloat128 + # else + # define __CFLOAT128 _Complex _Float128 + # endif + # if !__GNUC_PREREQ (7, 0) || defined __cplusplus + # ifdef __NO_LONG_DOUBLE_MATH + # define __CFLOAT64 _Complex long double + # else + # define __CFLOAT64 _Complex double + # endif + # else + # define __CFLOAT64 _Complex _Float64 + # endif + EOT; +}; + /* glibc-2.3.5 defines pthread mutex initializers incorrectly, * so we replace them with versions that correspond to the * definition. diff --git a/fixincludes/tests/base/bits/floatn.h b/fixincludes/tests/base/bits/floatn.h new file mode 100644 index 0000000..f09528b --- /dev/null +++ b/fixincludes/tests/base/bits/floatn.h @@ -0,0 +1,74 @@ +/* DO NOT EDIT THIS FILE. + + It has been auto-edited by fixincludes from: + + "fixinc/tests/inc/bits/floatn.h" + + This had to be done to correct non-standard usages in the + original, manufacturer supplied header file. */ + + + +#if defined( GLIBC_CXX_FLOATN_1_CHECK ) +# if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0)) +/* The literal suffix f128 exists only since GCC 7.0. */ +# define __f128(x) x##l +# else +# define __f128(x) x##f128 +# endif +# if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0)) +/* The literal suffix (f128) exist for powerpc only since GCC 7.0. */ +# if __LDBL_MANT_DIG__ == 113 +# define __f128(x) x##l +# else +# define __f128(x) x##q +# endif +# else +# define __f128(x) x##f128 +# endif +# if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0)) +# ifdef __NO_LONG_DOUBLE_MATH +# define __f64(x) x##l +# else +# define __f64(x) x +# endif +# else +# define __f64(x) x##f64 +# endif +#endif /* GLIBC_CXX_FLOATN_1_CHECK */ + + +#if defined( GLIBC_CXX_FLOATN_2_CHECK ) +# if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0)) +typedef float _Float16 __attribute__ ((__mode__ (__HF__))); +# endif +# if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0)) +typedef __float128 _Float128; +# endif +#endif /* GLIBC_CXX_FLOATN_2_CHECK */ + + +#if defined( GLIBC_CXX_FLOATN_3_CHECK ) +# if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0)) +# define __CFLOAT128 _Complex long double +# else +# define __CFLOAT128 _Complex _Float128 +# endif +# if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0)) +/* Add a typedef for older GCC compilers which don't natively support + _Complex _Float128. */ +typedef _Complex float __cfloat128 __attribute__ ((__mode__ (__TC__))); +# define __CFLOAT128 __cfloat128 +# else +# define __CFLOAT128 _Complex _Float128 +# endif +# if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0)) +# ifdef __NO_LONG_DOUBLE_MATH +# define __CFLOAT64 _Complex long double +# else +# define __CFLOAT64 _Complex double +# endif +# else +# define __CFLOAT64 _Complex _Float64 +# endif +#endif /* GLIBC_CXX_FLOATN_3_CHECK */ 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)) diff --git a/include/ChangeLog b/include/ChangeLog index ee23c30..e9fb5b3 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,16 @@ +2022-09-27 Jakub Jelinek <jakub@redhat.com> + + PR c++/106652 + PR c++/85518 + * demangle.h (enum demangle_component_type): Add + DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE. + (struct demangle_component): Add u.s_extended_builtin member. + +2022-09-27 Meghan Denny <hello@nektro.net> + + * dwarf2.h: Update with additional languages from dwarf + standard. + 2022-07-12 Martin Liska <mliska@suse.cz> * plugin-api.h (enum linker_api_version): New enum. diff --git a/include/demangle.h b/include/demangle.h index e2aa4a9..81d4353 100644 --- a/include/demangle.h +++ b/include/demangle.h @@ -457,6 +457,11 @@ enum demangle_component_type DEMANGLE_COMPONENT_MODULE_PARTITION, DEMANGLE_COMPONENT_MODULE_ENTITY, DEMANGLE_COMPONENT_MODULE_INIT, + + /* A builtin type with argument. This holds the builtin type + information. */ + DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE + }; /* Types which are only used internally. */ @@ -543,6 +548,15 @@ struct demangle_component const struct demangle_builtin_type_info *type; } s_builtin; + /* For DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE. */ + struct + { + /* Builtin type. */ + const struct demangle_builtin_type_info *type; + short arg; + char suffix; + } s_extended_builtin; + /* For DEMANGLE_COMPONENT_SUB_STD. */ struct { diff --git a/include/dwarf2.h b/include/dwarf2.h index 40aa5a5..87bf764 100644 --- a/include/dwarf2.h +++ b/include/dwarf2.h @@ -373,6 +373,16 @@ enum dwarf_source_language DW_LANG_Fortran03 = 0x0022, DW_LANG_Fortran08 = 0x0023, DW_LANG_RenderScript = 0x0024, + DW_LANG_BLISS = 0x0025, + DW_LANG_Kotlin = 0x0026, + DW_LANG_Zig = 0x0027, + DW_LANG_Crystal = 0x0028, + DW_LANG_C_plus_plus_17 = 0x002a, + DW_LANG_C_plus_plus_20 = 0x002b, + DW_LANG_C17 = 0x002c, + DW_LANG_Fortran18 = 0x002d, + DW_LANG_Ada2005 = 0x002e, + DW_LANG_Ada2012 = 0x002f, DW_LANG_lo_user = 0x8000, /* Implementation-defined range start. */ DW_LANG_hi_user = 0xffff, /* Implementation-defined range start. */ diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog index 5984915..3b41845 100644 --- a/libcpp/ChangeLog +++ b/libcpp/ChangeLog @@ -1,3 +1,35 @@ +2022-09-28 Eugene Rozenfeld <erozen@microsoft.com> + + * include/line-map.h: Add discriminator to location_adhoc_data. + (get_combined_adhoc_loc): Add discriminator parameter. + (get_discriminator_from_adhoc_loc): Add external declaration. + (get_discriminator_from_loc): Add external declaration. + (COMBINE_LOCATION_DATA): Add discriminator parameter. + * lex.cc (get_location_for_byte_range_in_cur_line) Pass 0 discriminator + in a call to COMBINE_LOCATION_DATA. + (warn_about_normalization): Pass 0 discriminator in a call to + COMBINE_LOCATION_DATA. + (_cpp_lex_direct): Pass 0 discriminator in a call to + COMBINE_LOCATION_DATA. + * line-map.cc (location_adhoc_data_hash): Use discriminator compute + location_adhoc_data hash. + (location_adhoc_data_eq): Use discriminator when comparing + location_adhoc_data. + (can_be_stored_compactly_p): Check discriminator to determine + compact storage. + (get_combined_adhoc_loc): Add discriminator parameter. + (get_discriminator_from_adhoc_loc): New function to get the discriminator + from an ad-hoc location. + (get_discriminator_from_loc): New function to get the discriminator + from a location. + +2022-09-27 Jakub Jelinek <jakub@redhat.com> + + PR c++/106652 + PR c++/85518 + * expr.cc (interpret_float_suffix): Allow {f,F}{16,32,64,128} and + {f,F}{32,64,128}x suffixes for C++. + 2022-09-08 Lewis Hyatt <lhyatt@gmail.com> * line-map.cc (location_adhoc_data_update): Remove reliance on diff --git a/libcpp/expr.cc b/libcpp/expr.cc index 4bb02c4..1d68064 100644 --- a/libcpp/expr.cc +++ b/libcpp/expr.cc @@ -215,7 +215,6 @@ interpret_float_suffix (cpp_reader *pfile, const uchar *s, size_t len) case 'f': case 'F': f++; if (len > 0 - && !CPP_OPTION (pfile, cplusplus) && s[1] >= '1' && s[1] <= '9' && fn_bits == 0) diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h index 9bdd5b9..50207ca 100644 --- a/libcpp/include/line-map.h +++ b/libcpp/include/line-map.h @@ -757,6 +757,7 @@ struct GTY(()) location_adhoc_data { location_t locus; source_range src_range; void * GTY((skip)) data; + unsigned discriminator; }; struct htab; @@ -1034,12 +1035,14 @@ LINEMAPS_LAST_ALLOCATED_MACRO_MAP (const line_maps *set) } extern location_t get_combined_adhoc_loc (line_maps *, location_t, - source_range, void *); + source_range, void *, unsigned); extern void *get_data_from_adhoc_loc (const line_maps *, location_t); +extern unsigned get_discriminator_from_adhoc_loc (const line_maps *, location_t); extern location_t get_location_from_adhoc_loc (const line_maps *, location_t); extern source_range get_range_from_loc (line_maps *set, location_t loc); +extern unsigned get_discriminator_from_loc (line_maps *set, location_t loc); /* Get whether location LOC is a "pure" location, or whether it is an ad-hoc location, or embeds range information. */ @@ -1058,9 +1061,10 @@ inline location_t COMBINE_LOCATION_DATA (class line_maps *set, location_t loc, source_range src_range, - void *block) + void *block, + unsigned discriminator) { - return get_combined_adhoc_loc (set, loc, src_range, block); + return get_combined_adhoc_loc (set, loc, src_range, block, discriminator); } extern void rebuild_location_adhoc_htab (class line_maps *); diff --git a/libcpp/lex.cc b/libcpp/lex.cc index 41f905de..a429a3d 100644 --- a/libcpp/lex.cc +++ b/libcpp/lex.cc @@ -1362,7 +1362,8 @@ get_location_for_byte_range_in_cur_line (cpp_reader *pfile, location_t combined_loc = COMBINE_LOCATION_DATA (pfile->line_table, start_loc, src_range, - NULL); + NULL, + 0); return combined_loc; } @@ -2028,7 +2029,7 @@ warn_about_normalization (cpp_reader *pfile, CPP_BUF_COLUMN (pfile->buffer, pfile->buffer->cur)); loc = COMBINE_LOCATION_DATA (pfile->line_table, - loc, tok_range, NULL); + loc, tok_range, NULL, 0); } encoding_rich_location rich_loc (pfile, loc); @@ -4256,7 +4257,7 @@ _cpp_lex_direct (cpp_reader *pfile) result->src_loc = COMBINE_LOCATION_DATA (pfile->line_table, result->src_loc, - tok_range, NULL); + tok_range, NULL, 0); } return result; diff --git a/libcpp/line-map.cc b/libcpp/line-map.cc index 391f1d4..50e8043 100644 --- a/libcpp/line-map.cc +++ b/libcpp/line-map.cc @@ -67,7 +67,8 @@ location_adhoc_data_hash (const void *l) return ((hashval_t) lb->locus + (hashval_t) lb->src_range.m_start + (hashval_t) lb->src_range.m_finish - + (size_t) lb->data); + + (size_t) lb->data + + lb->discriminator); } /* Compare function for location_adhoc_data hashtable. */ @@ -82,7 +83,8 @@ location_adhoc_data_eq (const void *l1, const void *l2) return (lb1->locus == lb2->locus && lb1->src_range.m_start == lb2->src_range.m_start && lb1->src_range.m_finish == lb2->src_range.m_finish - && lb1->data == lb2->data); + && lb1->data == lb2->data + && lb1->discriminator == lb2->discriminator); } /* Update the hashtable when location_adhoc_data_map::data is reallocated. @@ -127,13 +129,17 @@ static bool can_be_stored_compactly_p (line_maps *set, location_t locus, source_range src_range, - void *data) + void *data, + unsigned discriminator) { /* If there's an ad-hoc pointer, we can't store it directly in the location_t, we need the lookaside. */ if (data) return false; + if (discriminator != 0) + return false; + /* We only store ranges that begin at the locus and that are sufficiently "sane". */ if (src_range.m_start != locus) @@ -168,7 +174,8 @@ location_t get_combined_adhoc_loc (line_maps *set, location_t locus, source_range src_range, - void *data) + void *data, + unsigned discriminator) { struct location_adhoc_data lb; struct location_adhoc_data **slot; @@ -186,7 +193,7 @@ get_combined_adhoc_loc (line_maps *set, || pure_location_p (set, locus)); /* Consider short-range optimization. */ - if (can_be_stored_compactly_p (set, locus, src_range, data)) + if (can_be_stored_compactly_p (set, locus, src_range, data, discriminator)) { /* The low bits ought to be clear. */ linemap_assert (pure_location_p (set, locus)); @@ -206,15 +213,16 @@ get_combined_adhoc_loc (line_maps *set, when locus == start == finish (and data is NULL). */ if (locus == src_range.m_start && locus == src_range.m_finish - && !data) + && !data && discriminator == 0) return locus; - if (!data) + if (!data && discriminator == 0) set->num_unoptimized_ranges++; lb.locus = locus; lb.src_range = src_range; lb.data = data; + lb.discriminator = discriminator; slot = (struct location_adhoc_data **) htab_find_slot (set->location_adhoc_data_map.htab, &lb, INSERT); if (*slot == NULL) @@ -261,6 +269,13 @@ get_data_from_adhoc_loc (const class line_maps *set, location_t loc) return set->location_adhoc_data_map.data[loc & MAX_LOCATION_T].data; } +unsigned +get_discriminator_from_adhoc_loc (const class line_maps *set, location_t loc) +{ + linemap_assert (IS_ADHOC_LOC (loc)); + return set->location_adhoc_data_map.data[loc & MAX_LOCATION_T].discriminator; +} + /* Return the location for the adhoc loc. */ location_t @@ -306,6 +321,15 @@ get_range_from_loc (line_maps *set, return source_range::from_location (loc); } +unsigned +get_discriminator_from_loc (line_maps *set, + location_t loc) +{ + if (IS_ADHOC_LOC (loc)) + return get_discriminator_from_adhoc_loc (set, loc); + return 0; +} + /* Get whether location LOC is a "pure" location, or whether it is an ad-hoc location, or embeds range information. */ diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog index 9ebfaa0..24296185 100644 --- a/libgcc/ChangeLog +++ b/libgcc/ChangeLog @@ -1,3 +1,8 @@ +2022-09-26 Thomas Neumann <tneumann@users.sourceforge.net> + + * unwind-dw2-fde.c: Introduce a constant for in_shutdown + for the non-fast-path case. Drop destructor priority. + 2022-09-22 Thomas Neumann <tneumann@users.sourceforge.net> * unwind-dw2-fde.c: (release_register_frames) Remember diff --git a/libgo/go/runtime/ffi.go b/libgo/go/runtime/ffi.go index cd8479e..86ce5b8 100644 --- a/libgo/go/runtime/ffi.go +++ b/libgo/go/runtime/ffi.go @@ -4,6 +4,7 @@ // Only build this file if libffi is supported. +//go:build libffi // +build libffi package runtime @@ -221,9 +222,6 @@ func stringToFFI() *__ffi_type { // structToFFI returns an ffi_type for a Go struct type. func structToFFI(typ *structtype) *__ffi_type { c := len(typ.fields) - if c == 0 { - return emptyStructToFFI() - } if typ.typ.kind&kindDirectIface != 0 { return ffi_type_pointer() } @@ -231,6 +229,7 @@ func structToFFI(typ *structtype) *__ffi_type { fields := make([]*__ffi_type, 0, c+1) checkPad := false lastzero := false + sawnonzero := false for i, v := range typ.fields { // Skip zero-sized fields; they confuse libffi, // and there is no value to pass in any case. @@ -239,10 +238,13 @@ func structToFFI(typ *structtype) *__ffi_type { // next field. if v.typ.size == 0 { checkPad = true - lastzero = true + if v.name == nil || *v.name != "_" { + lastzero = true + } continue } lastzero = false + sawnonzero = true if checkPad { off := uintptr(0) @@ -263,6 +265,10 @@ func structToFFI(typ *structtype) *__ffi_type { fields = append(fields, typeToFFI(v.typ)) } + if !sawnonzero { + return emptyStructToFFI() + } + if lastzero { // The compiler adds one byte padding to non-empty struct ending // with a zero-sized field (types.cc:get_backend_struct_fields). diff --git a/libgo/go/runtime/os_linux.go b/libgo/go/runtime/os_linux.go index 96fb178..2b2d827 100644 --- a/libgo/go/runtime/os_linux.go +++ b/libgo/go/runtime/os_linux.go @@ -22,6 +22,12 @@ type mOS struct { profileTimerValid uint32 } +// setSigeventTID is written in C to set the sigev_notify_thread_id +// field of a sigevent struct. +// +//go:noescape +func setSigeventTID(*_sigevent, int32) + func getProcID() uint64 { return uint64(gettid()) } @@ -52,9 +58,12 @@ const ( ) // Atomically, +// // if(*addr == val) sleep +// // Might be woken up spuriously; that's allowed. // Don't sleep longer than ns; ns < 0 means forever. +// //go:nosplit func futexsleep(addr *uint32, val uint32, ns int64) { // Some Linux kernels have a bug where futex of @@ -73,6 +82,7 @@ func futexsleep(addr *uint32, val uint32, ns int64) { } // If any procs are sleeping on addr, wake up at most cnt. +// //go:nosplit func futexwakeup(addr *uint32, cnt uint32) { ret := futex(unsafe.Pointer(addr), _FUTEX_WAKE_PRIVATE, cnt, nil, nil, 0) @@ -365,7 +375,7 @@ func setThreadCPUProfiler(hz int32) { var sevp _sigevent sevp.sigev_notify = _SIGEV_THREAD_ID sevp.sigev_signo = _SIGPROF - *((*int32)(unsafe.Pointer(&sevp._sigev_un))) = int32(mp.procid) + setSigeventTID(&sevp, int32(mp.procid)) ret := timer_create(_CLOCK_THREAD_CPUTIME_ID, &sevp, &timerid) if ret != 0 { // If we cannot create a timer for this M, leave profileTimerValid false diff --git a/libgo/runtime/go-signal.c b/libgo/runtime/go-signal.c index 528d9b6..aa1b630 100644 --- a/libgo/runtime/go-signal.c +++ b/libgo/runtime/go-signal.c @@ -183,6 +183,24 @@ setSigactionHandler(struct sigaction* sa, uintptr handler) sa->sa_sigaction = (void*)(handler); } +#ifdef __linux__ + +// Workaround for https://sourceware.org/bugzilla/show_bug.cgi?id=27417 +#ifndef sigev_notify_thread_id + #define sigev_notify_thread_id _sigev_un._tid +#endif + +void setSigeventTID(struct sigevent*, int32_t) + __asm__ (GOSYM_PREFIX "runtime.setSigeventTID"); + +void +setSigeventTID(struct sigevent *sev, int32_t v) +{ + sev->sigev_notify_thread_id = v; +} + +#endif // defined(__linux__) + // C code to fetch values from the siginfo_t and ucontext_t pointers // passed to a signal handler. diff --git a/libgomp/ChangeLog b/libgomp/ChangeLog index a5830a4..97ae4b2 100644 --- a/libgomp/ChangeLog +++ b/libgomp/ChangeLog @@ -1,3 +1,8 @@ +2022-09-28 Tobias Burnus <tobias@codesourcery.com> + + * libgomp.texi (OpenMP 5.1): Mark 'assume' as implemented + for C/C++. Remove duplicated 'begin declare target' entry. + 2022-09-24 Jakub Jelinek <jakub@redhat.com> PR c/106981 diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi index addf2d4..b5d09fe 100644 --- a/libgomp/libgomp.texi +++ b/libgomp/libgomp.texi @@ -287,7 +287,7 @@ The OpenMP 4.5 specification is fully supported. @code{append_args} @tab N @tab @item @code{dispatch} construct @tab N @tab @item device-specific ICV settings with environment variables @tab Y @tab -@item @code{assume} directive @tab N @tab +@item @code{assume} directive @tab P @tab Only C/C++ @item @code{nothing} directive @tab Y @tab @item @code{error} directive @tab Y @tab @item @code{masked} construct @tab Y @tab @@ -348,7 +348,6 @@ The OpenMP 4.5 specification is fully supported. @item Support @code{begin/end declare target} syntax in C/C++ @tab N @tab @item Pointer predetermined firstprivate getting initialized to address of matching mapped list item per 5.1, Sect. 2.21.7.2 @tab N @tab -@item @code{begin declare target} directive @tab N @tab @item For Fortran, diagnose placing declarative before/between @code{USE}, @code{IMPORT}, and @code{IMPLICIT} as invalid @tab N @tab @end multitable diff --git a/libiberty/ChangeLog b/libiberty/ChangeLog index f537372..c22f9d9 100644 --- a/libiberty/ChangeLog +++ b/libiberty/ChangeLog @@ -1,3 +1,25 @@ +2022-09-27 Jakub Jelinek <jakub@redhat.com> + + PR c++/106652 + PR c++/85518 + * cp-demangle.c (d_dump): Handle + DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE. Don't handle + DEMANGLE_COMPONENT_FIXED_TYPE. + (d_make_extended_builtin_type): New function. + (cplus_demangle_builtin_types): Add _Float entry. + (cplus_demangle_type): For DF demangle it as _Float<N> or + _Float<N>x rather than fixed point which conflicts with it. + (d_count_templates_scopes): Handle + DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE. Just break; for + DEMANGLE_COMPONENT_FIXED_TYPE. + (d_find_pack): Handle DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE. + Don't handle DEMANGLE_COMPONENT_FIXED_TYPE. + (d_print_comp_inner): Likewise. + * cp-demangle.h (D_BUILTIN_TYPE_COUNT): Bump. + * testsuite/demangle-expected: Replace _Z3xxxDFyuVb test + with _Z3xxxDF16_DF32_DF64_DF128_CDF16_Vb. Add + _Z3xxxDF32xDF64xDF128xCDF32xVb test. + 2022-09-22 Jonathan Wakely <jwakely@redhat.com> * README: Replace gcc-bugs email address with Bugzilla URL. diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c index d06d80d..7ff225e 100644 --- a/libiberty/cp-demangle.c +++ b/libiberty/cp-demangle.c @@ -648,6 +648,13 @@ d_dump (struct demangle_component *dc, int indent) case DEMANGLE_COMPONENT_BUILTIN_TYPE: printf ("builtin type %s\n", dc->u.s_builtin.type->name); return; + case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE: + { + char suffix[2] = { dc->u.s_extended_builtin.type->suffix, 0 }; + printf ("builtin type %s%d%s\n", dc->u.s_extended_builtin.type->name, + dc->u.s_extended_builtin.type->arg, suffix); + } + return; case DEMANGLE_COMPONENT_OPERATOR: printf ("operator %s\n", dc->u.s_operator.op->name); return; @@ -771,11 +778,6 @@ d_dump (struct demangle_component *dc, int indent) case DEMANGLE_COMPONENT_PTRMEM_TYPE: printf ("pointer to member type\n"); break; - case DEMANGLE_COMPONENT_FIXED_TYPE: - printf ("fixed-point type, accum? %d, sat? %d\n", - dc->u.s_fixed.accum, dc->u.s_fixed.sat); - d_dump (dc->u.s_fixed.length, indent + 2); - break; case DEMANGLE_COMPONENT_ARGLIST: printf ("argument list\n"); break; @@ -1109,6 +1111,28 @@ d_make_builtin_type (struct d_info *di, return p; } +/* Add a new extended builtin type component. */ + +static struct demangle_component * +d_make_extended_builtin_type (struct d_info *di, + const struct demangle_builtin_type_info *type, + short arg, char suffix) +{ + struct demangle_component *p; + + if (type == NULL) + return NULL; + p = d_make_empty (di); + if (p != NULL) + { + p->type = DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE; + p->u.s_extended_builtin.type = type; + p->u.s_extended_builtin.arg = arg; + p->u.s_extended_builtin.suffix = suffix; + } + return p; +} + /* Add a new operator component. */ static struct demangle_component * @@ -2464,6 +2488,7 @@ cplus_demangle_builtin_types[D_BUILTIN_TYPE_COUNT] = /* 32 */ { NL ("char32_t"), NL ("char32_t"), D_PRINT_DEFAULT }, /* 33 */ { NL ("decltype(nullptr)"), NL ("decltype(nullptr)"), D_PRINT_DEFAULT }, + /* 34 */ { NL ("_Float"), NL ("_Float"), D_PRINT_FLOAT }, }; CP_STATIC_IF_GLIBCPP_V3 @@ -2727,19 +2752,26 @@ cplus_demangle_type (struct d_info *di) break; case 'F': - /* Fixed point types. DF<int bits><length><fract bits><sat> */ - ret = d_make_empty (di); - ret->type = DEMANGLE_COMPONENT_FIXED_TYPE; - if ((ret->u.s_fixed.accum = IS_DIGIT (d_peek_char (di)))) - /* For demangling we don't care about the bits. */ - d_number (di); - ret->u.s_fixed.length = cplus_demangle_type (di); - if (ret->u.s_fixed.length == NULL) - return NULL; - d_number (di); - peek = d_next_char (di); - ret->u.s_fixed.sat = (peek == 's'); - break; + /* DF<number>_ - _Float<number>. + DF<number>x - _Float<number>x. */ + { + int arg = d_number (di); + char buf[12]; + char suffix = 0; + if (d_peek_char (di) == 'x') + suffix = 'x'; + if (!suffix && d_peek_char (di) != '_') + return NULL; + ret + = d_make_extended_builtin_type (di, + &cplus_demangle_builtin_types[34], + arg, suffix); + d_advance (di, 1); + sprintf (buf, "%d", arg); + di->expansion += ret->u.s_extended_builtin.type->len + + strlen (buf) + (suffix != 0); + break; + } case 'v': ret = d_vector_type (di); @@ -4202,6 +4234,7 @@ d_count_templates_scopes (struct d_print_info *dpi, case DEMANGLE_COMPONENT_FUNCTION_PARAM: case DEMANGLE_COMPONENT_SUB_STD: case DEMANGLE_COMPONENT_BUILTIN_TYPE: + case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE: case DEMANGLE_COMPONENT_OPERATOR: case DEMANGLE_COMPONENT_CHARACTER: case DEMANGLE_COMPONENT_NUMBER: @@ -4210,6 +4243,7 @@ d_count_templates_scopes (struct d_print_info *dpi, case DEMANGLE_COMPONENT_MODULE_NAME: case DEMANGLE_COMPONENT_MODULE_PARTITION: case DEMANGLE_COMPONENT_MODULE_INIT: + case DEMANGLE_COMPONENT_FIXED_TYPE: break; case DEMANGLE_COMPONENT_TEMPLATE: @@ -4309,10 +4343,6 @@ d_count_templates_scopes (struct d_print_info *dpi, d_count_templates_scopes (dpi, dc->u.s_extended_operator.name); break; - case DEMANGLE_COMPONENT_FIXED_TYPE: - d_count_templates_scopes (dpi, dc->u.s_fixed.length); - break; - case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS: case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS: case DEMANGLE_COMPONENT_MODULE_ENTITY: @@ -4580,11 +4610,11 @@ d_find_pack (struct d_print_info *dpi, case DEMANGLE_COMPONENT_TAGGED_NAME: case DEMANGLE_COMPONENT_OPERATOR: case DEMANGLE_COMPONENT_BUILTIN_TYPE: + case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE: case DEMANGLE_COMPONENT_SUB_STD: case DEMANGLE_COMPONENT_CHARACTER: case DEMANGLE_COMPONENT_FUNCTION_PARAM: case DEMANGLE_COMPONENT_UNNAMED_TYPE: - case DEMANGLE_COMPONENT_FIXED_TYPE: case DEMANGLE_COMPONENT_DEFAULT_ARG: case DEMANGLE_COMPONENT_NUMBER: return NULL; @@ -5387,6 +5417,14 @@ d_print_comp_inner (struct d_print_info *dpi, int options, dc->u.s_builtin.type->java_len); return; + case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE: + d_append_buffer (dpi, dc->u.s_extended_builtin.type->name, + dc->u.s_extended_builtin.type->len); + d_append_num (dpi, dc->u.s_extended_builtin.arg); + if (dc->u.s_extended_builtin.suffix) + d_append_buffer (dpi, &dc->u.s_extended_builtin.suffix, 1); + return; + case DEMANGLE_COMPONENT_VENDOR_TYPE: d_print_comp (dpi, options, d_left (dc)); return; @@ -5525,22 +5563,6 @@ d_print_comp_inner (struct d_print_info *dpi, int options, return; } - case DEMANGLE_COMPONENT_FIXED_TYPE: - if (dc->u.s_fixed.sat) - d_append_string (dpi, "_Sat "); - /* Don't print "int _Accum". */ - if (dc->u.s_fixed.length->u.s_builtin.type - != &cplus_demangle_builtin_types['i'-'a']) - { - d_print_comp (dpi, options, dc->u.s_fixed.length); - d_append_char (dpi, ' '); - } - if (dc->u.s_fixed.accum) - d_append_string (dpi, "_Accum"); - else - d_append_string (dpi, "_Fract"); - return; - case DEMANGLE_COMPONENT_ARGLIST: case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST: if (d_left (dc) != NULL) diff --git a/libiberty/cp-demangle.h b/libiberty/cp-demangle.h index c644503..c5d046b 100644 --- a/libiberty/cp-demangle.h +++ b/libiberty/cp-demangle.h @@ -180,7 +180,7 @@ d_advance (struct d_info *di, int i) extern const struct demangle_operator_info cplus_demangle_operators[]; #endif -#define D_BUILTIN_TYPE_COUNT (34) +#define D_BUILTIN_TYPE_COUNT (35) CP_STATIC_IF_GLIBCPP_V3 const struct demangle_builtin_type_info diff --git a/libiberty/testsuite/demangle-expected b/libiberty/testsuite/demangle-expected index 351af34..8fad689 100644 --- a/libiberty/testsuite/demangle-expected +++ b/libiberty/testsuite/demangle-expected @@ -1242,8 +1242,12 @@ _ZNSt9_Any_data9_M_accessIPZ4postISt8functionIFvvEEEvOT_EUlvE_EERS5_v post<std::function<void ()> >(std::function<void ()>&&)::{lambda()#1}*& std::_Any_data::_M_access<post<std::function<void ()> >(post<std::function<void ()> >(std::function<void ()>&&)::{lambda()#1}*&&)::{lambda()#1}*>() # --format=auto --no-params -_Z3xxxDFyuVb -xxx(unsigned long long _Fract, bool volatile) +_Z3xxxDF16_DF32_DF64_DF128_CDF16_Vb +xxx(_Float16, _Float32, _Float64, _Float128, _Float16 _Complex, bool volatile) +xxx +--format=auto --no-params +_Z3xxxDF32xDF64xDF128xCDF32xVb +xxx(_Float32x, _Float64x, _Float128x, _Float32x _Complex, bool volatile) xxx # https://sourceware.org/bugzilla/show_bug.cgi?id=16817 --format=auto --no-params diff --git a/libitm/ChangeLog b/libitm/ChangeLog index 01f6bfa..9796ef1 100644 --- a/libitm/ChangeLog +++ b/libitm/ChangeLog @@ -1,3 +1,11 @@ +2022-09-28 Lulu Cheng <chenglulu@loongson.cn> + Yang Yujie <yangyujie@loongson.cn> + + * configure.tgt: Add loongarch support. + * config/loongarch/asm.h: New file. + * config/loongarch/sjlj.S: New file. + * config/loongarch/target.h: New file. + 2022-08-31 Martin Liska <mliska@suse.cz> * configure: Regenerate. diff --git a/libitm/config/loongarch/asm.h b/libitm/config/loongarch/asm.h new file mode 100644 index 0000000..a8e3304 --- /dev/null +++ b/libitm/config/loongarch/asm.h @@ -0,0 +1,54 @@ +/* Copyright (C) 2022 Free Software Foundation, Inc. + Contributed by Loongson Co. Ltd. + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm 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. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _LA_ASM_H +#define _LA_ASM_H + +#if defined(__loongarch_lp64) +# define GPR_L ld.d +# define GPR_S st.d +# define SZ_GPR 8 +# define ADDSP(si) addi.d $sp, $sp, si +#elif defined(__loongarch64_ilp32) +# define GPR_L ld.w +# define GPR_S st.w +# define SZ_GPR 4 +# define ADDSP(si) addi.w $sp, $sp, si +#else +# error Unsupported GPR size (must be 64-bit or 32-bit). +#endif + +#if defined(__loongarch_double_float) +# define FPR_L fld.d +# define FPR_S fst.d +# define SZ_FPR 8 +#elif defined(__loongarch_single_float) +# define FPR_L fld.s +# define FPR_S fst.s +# define SZ_FPR 4 +#else +# define SZ_FPR 0 +#endif + +#endif /* _LA_ASM_H */ diff --git a/libitm/config/loongarch/sjlj.S b/libitm/config/loongarch/sjlj.S new file mode 100644 index 0000000..a5f9fad --- /dev/null +++ b/libitm/config/loongarch/sjlj.S @@ -0,0 +1,127 @@ +/* Copyright (C) 2022 Free Software Foundation, Inc. + Contributed by Loongson Co. Ltd. + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm 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. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +#include "asmcfi.h" +#include "asm.h" + + .text + .align 2 + .global _ITM_beginTransaction + .type _ITM_beginTransaction, @function + +_ITM_beginTransaction: + cfi_startproc + move $r5, $sp + ADDSP(-(12*SZ_GPR+8*SZ_FPR)) + cfi_adjust_cfa_offset(12*SZ_GPR+8*SZ_FPR) + + /* Frame Pointer */ + GPR_S $fp, $sp, 0*SZ_GPR + cfi_rel_offset(22, 0) + + /* Return Address */ + GPR_S $r1, $sp, 1*SZ_GPR + cfi_rel_offset(1, SZ_GPR) + + /* Caller's $sp */ + GPR_S $r5, $sp, 2*SZ_GPR + + /* Callee-saved scratch GPRs (r23-r31) */ + GPR_S $s0, $sp, 3*SZ_GPR + GPR_S $s1, $sp, 4*SZ_GPR + GPR_S $s2, $sp, 5*SZ_GPR + GPR_S $s3, $sp, 6*SZ_GPR + GPR_S $s4, $sp, 7*SZ_GPR + GPR_S $s5, $sp, 8*SZ_GPR + GPR_S $s6, $sp, 9*SZ_GPR + GPR_S $s7, $sp, 10*SZ_GPR + GPR_S $s8, $sp, 11*SZ_GPR + +#if !defined(__loongarch_soft_float) + /* Callee-saved scratch FPRs (f24-f31) */ + FPR_S $f24, $sp, 12*SZ_GPR + 0*SZ_FPR + FPR_S $f25, $sp, 12*SZ_GPR + 1*SZ_FPR + FPR_S $f26, $sp, 12*SZ_GPR + 2*SZ_FPR + FPR_S $f27, $sp, 12*SZ_GPR + 3*SZ_FPR + FPR_S $f28, $sp, 12*SZ_GPR + 4*SZ_FPR + FPR_S $f29, $sp, 12*SZ_GPR + 5*SZ_FPR + FPR_S $f30, $sp, 12*SZ_GPR + 6*SZ_FPR + FPR_S $f31, $sp, 12*SZ_GPR + 7*SZ_FPR +#endif + move $fp, $sp + + /* Invoke GTM_begin_transaction with the struct we've just built. */ + move $r5, $sp + bl %plt(GTM_begin_transaction) + + /* Return. (no call-saved scratch reg needs to be restored here) */ + GPR_L $fp, $sp, 0*SZ_GPR + cfi_restore(22) + GPR_L $r1, $sp, 1*SZ_GPR + cfi_restore(1) + + ADDSP(12*SZ_GPR+8*SZ_FPR) + cfi_adjust_cfa_offset(-(12*SZ_GPR+8*SZ_FPR)) + + jr $r1 + cfi_endproc + .size _ITM_beginTransaction, . - _ITM_beginTransaction + + .align 2 + .global GTM_longjmp + .hidden GTM_longjmp + .type GTM_longjmp, @function + +GTM_longjmp: + cfi_startproc + GPR_L $s0, $r5, 3*SZ_GPR + GPR_L $s1, $r5, 4*SZ_GPR + GPR_L $s2, $r5, 5*SZ_GPR + GPR_L $s3, $r5, 6*SZ_GPR + GPR_L $s4, $r5, 7*SZ_GPR + GPR_L $s5, $r5, 8*SZ_GPR + GPR_L $s6, $r5, 9*SZ_GPR + GPR_L $s7, $r5, 10*SZ_GPR + GPR_L $s8, $r5, 11*SZ_GPR + + FPR_L $f24, $r5, 12*SZ_GPR + 0*SZ_FPR + FPR_L $f25, $r5, 12*SZ_GPR + 1*SZ_FPR + FPR_L $f26, $r5, 12*SZ_GPR + 2*SZ_FPR + FPR_L $f27, $r5, 12*SZ_GPR + 3*SZ_FPR + FPR_L $f28, $r5, 12*SZ_GPR + 4*SZ_FPR + FPR_L $f29, $r5, 12*SZ_GPR + 5*SZ_FPR + FPR_L $f30, $r5, 12*SZ_GPR + 6*SZ_FPR + FPR_L $f31, $r5, 12*SZ_GPR + 7*SZ_FPR + + GPR_L $r7, $r5, 2*SZ_GPR + GPR_L $fp, $r5, 0*SZ_GPR + GPR_L $r1, $r5, 1*SZ_GPR + cfi_def_cfa(5, 0) + move $sp, $r7 + jr $r1 + cfi_endproc + .size GTM_longjmp, . - GTM_longjmp + +#ifdef __linux__ +.section .note.GNU-stack, "", @progbits +#endif diff --git a/libitm/config/loongarch/target.h b/libitm/config/loongarch/target.h new file mode 100644 index 0000000..0c5cf3a --- /dev/null +++ b/libitm/config/loongarch/target.h @@ -0,0 +1,50 @@ +/* Copyright (C) 2022 Free Software Foundation, Inc. + Contributed by Loongson Co. Ltd. + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm 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. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +namespace GTM HIDDEN { + +typedef struct gtm_jmpbuf + { + long int fp; /* Frame Pointer: r22 */ + long int pc; /* Return Address: r1 */ + void *cfa; /* CFA: r3 */ + long int gpr[9]; /* Callee-saved scratch GPRs: r23(s0)-r31(s8) */ + + /* Callee-saved scratch FPRs: f24-f31 */ +#if defined(__loongarch_double_float) + double fpr[8]; +#elif defined(__loongarch_single_float) + float fpr[8]; +#endif + } gtm_jmpbuf; + +#define HW_CACHELINE_SIZE 128 + +static inline void +cpu_relax (void) +{ + __asm__ volatile ("" : : : "memory"); +} + +} // namespace GTM diff --git a/libitm/configure.tgt b/libitm/configure.tgt index 06e9097..4c0e78c 100644 --- a/libitm/configure.tgt +++ b/libitm/configure.tgt @@ -80,6 +80,8 @@ EOF ARCH=x86 ;; + loongarch*) ARCH=loongarch ;; + sh*) ARCH=sh ;; sparc) diff --git a/libphobos/ChangeLog b/libphobos/ChangeLog index 88660f6..015782ad 100644 --- a/libphobos/ChangeLog +++ b/libphobos/ChangeLog @@ -1,3 +1,14 @@ +2022-09-27 Iain Buclaw <ibuclaw@gdcproject.org> + + * libdruntime/MERGE: Merge upstream druntime d579c467c1. + * libdruntime/Makefile.am (DRUNTIME_DSOURCES): Remove + rt/arrayassign.d. + * libdruntime/Makefile.in: Regenerate. + * src/MERGE: Merge upstream phobos 88aa69b14. + * src/Makefile.am (PHOBOS_DSOURCES): Remove std/digest/digest.d, + std/xml.d. + * src/Makefile.in: Regenerate. + 2022-08-27 Iain Buclaw <ibuclaw@gdcproject.org> * libdruntime/MERGE: Merge upstream druntime 817610b16d. diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE index 85fc49d..a4c46f3 100644 --- a/libphobos/libdruntime/MERGE +++ b/libphobos/libdruntime/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/libphobos/libdruntime/Makefile.am b/libphobos/libdruntime/Makefile.am index d828749..45749d7 100644 --- a/libphobos/libdruntime/Makefile.am +++ b/libphobos/libdruntime/Makefile.am @@ -211,11 +211,11 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \ gcc/sections/package.d gcc/sections/pecoff.d gcc/simd.d \ gcc/unwind/arm.d gcc/unwind/arm_common.d gcc/unwind/c6x.d \ gcc/unwind/generic.d gcc/unwind/package.d gcc/unwind/pe.d object.d \ - rt/aApply.d rt/aApplyR.d rt/aaA.d rt/adi.d rt/arrayassign.d \ - rt/arraycat.d rt/cast_.d rt/config.d rt/critical_.d rt/deh.d \ - rt/dmain2.d rt/ehalloc.d rt/invariant.d rt/lifetime.d rt/memory.d \ - rt/minfo.d rt/monitor_.d rt/profilegc.d rt/sections.d rt/tlsgc.d \ - rt/util/typeinfo.d rt/util/utility.d + rt/aApply.d rt/aApplyR.d rt/aaA.d rt/adi.d rt/arraycat.d rt/cast_.d \ + rt/config.d rt/critical_.d rt/deh.d rt/dmain2.d rt/ehalloc.d \ + rt/invariant.d rt/lifetime.d rt/memory.d rt/minfo.d rt/monitor_.d \ + rt/profilegc.d rt/sections.d rt/tlsgc.d rt/util/typeinfo.d \ + rt/util/utility.d DRUNTIME_DSOURCES_STDCXX = core/stdcpp/allocator.d core/stdcpp/array.d \ core/stdcpp/exception.d core/stdcpp/memory.d core/stdcpp/new_.d \ diff --git a/libphobos/libdruntime/Makefile.in b/libphobos/libdruntime/Makefile.in index 57660ee..e86721f 100644 --- a/libphobos/libdruntime/Makefile.in +++ b/libphobos/libdruntime/Makefile.in @@ -242,11 +242,11 @@ am__objects_1 = core/atomic.lo core/attribute.lo core/bitop.lo \ gcc/unwind/arm_common.lo gcc/unwind/c6x.lo \ gcc/unwind/generic.lo gcc/unwind/package.lo gcc/unwind/pe.lo \ object.lo rt/aApply.lo rt/aApplyR.lo rt/aaA.lo rt/adi.lo \ - rt/arrayassign.lo rt/arraycat.lo rt/cast_.lo rt/config.lo \ - rt/critical_.lo rt/deh.lo rt/dmain2.lo rt/ehalloc.lo \ - rt/invariant.lo rt/lifetime.lo rt/memory.lo rt/minfo.lo \ - rt/monitor_.lo rt/profilegc.lo rt/sections.lo rt/tlsgc.lo \ - rt/util/typeinfo.lo rt/util/utility.lo + rt/arraycat.lo rt/cast_.lo rt/config.lo rt/critical_.lo \ + rt/deh.lo rt/dmain2.lo rt/ehalloc.lo rt/invariant.lo \ + rt/lifetime.lo rt/memory.lo rt/minfo.lo rt/monitor_.lo \ + rt/profilegc.lo rt/sections.lo rt/tlsgc.lo rt/util/typeinfo.lo \ + rt/util/utility.lo am__objects_2 = core/stdc/libgdruntime_la-errno_.lo am__objects_3 = core/sys/elf/package.lo am__objects_4 = core/stdcpp/allocator.lo core/stdcpp/array.lo \ @@ -880,11 +880,11 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \ gcc/sections/package.d gcc/sections/pecoff.d gcc/simd.d \ gcc/unwind/arm.d gcc/unwind/arm_common.d gcc/unwind/c6x.d \ gcc/unwind/generic.d gcc/unwind/package.d gcc/unwind/pe.d object.d \ - rt/aApply.d rt/aApplyR.d rt/aaA.d rt/adi.d rt/arrayassign.d \ - rt/arraycat.d rt/cast_.d rt/config.d rt/critical_.d rt/deh.d \ - rt/dmain2.d rt/ehalloc.d rt/invariant.d rt/lifetime.d rt/memory.d \ - rt/minfo.d rt/monitor_.d rt/profilegc.d rt/sections.d rt/tlsgc.d \ - rt/util/typeinfo.d rt/util/utility.d + rt/aApply.d rt/aApplyR.d rt/aaA.d rt/adi.d rt/arraycat.d rt/cast_.d \ + rt/config.d rt/critical_.d rt/deh.d rt/dmain2.d rt/ehalloc.d \ + rt/invariant.d rt/lifetime.d rt/memory.d rt/minfo.d rt/monitor_.d \ + rt/profilegc.d rt/sections.d rt/tlsgc.d rt/util/typeinfo.d \ + rt/util/utility.d DRUNTIME_DSOURCES_STDCXX = core/stdcpp/allocator.d core/stdcpp/array.d \ core/stdcpp/exception.d core/stdcpp/memory.d core/stdcpp/new_.d \ @@ -1364,7 +1364,6 @@ rt/aApply.lo: rt/$(am__dirstamp) rt/aApplyR.lo: rt/$(am__dirstamp) rt/aaA.lo: rt/$(am__dirstamp) rt/adi.lo: rt/$(am__dirstamp) -rt/arrayassign.lo: rt/$(am__dirstamp) rt/arraycat.lo: rt/$(am__dirstamp) rt/cast_.lo: rt/$(am__dirstamp) rt/config.lo: rt/$(am__dirstamp) diff --git a/libphobos/libdruntime/__builtins.di b/libphobos/libdruntime/__builtins.di index cf05333..1c49035 100644 --- a/libphobos/libdruntime/__builtins.di +++ b/libphobos/libdruntime/__builtins.di @@ -15,7 +15,7 @@ module __builtins; /* gcc relies on internal __builtin_xxxx functions and templates to * accomplish <stdarg.h>. D does the same thing with templates in core.stdc.stdarg. * Here, we redirect the gcc builtin declarations to the equivalent - * ones in core.stdc.stdarg, thereby avoiding having to hardware them + * ones in core.stdc.stdarg, thereby avoiding having to hardwire them * into the D compiler. */ diff --git a/libphobos/libdruntime/core/demangle.d b/libphobos/libdruntime/core/demangle.d index ca87f90..c2d4032 100644 --- a/libphobos/libdruntime/core/demangle.d +++ b/libphobos/libdruntime/core/demangle.d @@ -82,7 +82,7 @@ pure @safe: static class ParseException : Exception { - @safe pure nothrow this( string msg ) + this(string msg) @safe pure nothrow { super( msg ); } @@ -91,14 +91,14 @@ pure @safe: static class OverflowException : Exception { - @safe pure nothrow this( string msg ) + this(string msg) @safe pure nothrow { super( msg ); } } - static void error( string msg = "Invalid symbol" ) @trusted /* exception only used in module */ + static noreturn error( string msg = "Invalid symbol" ) @trusted /* exception only used in module */ { pragma(inline, false); // tame dmd inliner @@ -110,7 +110,7 @@ pure @safe: } - static void overflow( string msg = "Buffer overflow" ) @trusted /* exception only used in module */ + static noreturn overflow( string msg = "Buffer overflow" ) @trusted /* exception only used in module */ { pragma(inline, false); // tame dmd inliner @@ -156,7 +156,6 @@ pure @safe: if (val >= '0' && val <= '9') return cast(ubyte)(val - '0'); error(); - return 0; } @@ -253,23 +252,22 @@ pure @safe: put(", "); } - char[] put(char c) return scope + void put(char c) return scope { char[1] val = c; - return put(val[]); + put(val[]); } - char[] put( scope const(char)[] val ) return scope + void put(scope const(char)[] val) return scope { pragma(inline, false); // tame dmd inliner - if ( val.length ) - { - if ( !contains( dst[0 .. len], val ) ) - return append( val ); - return shift( val ); - } - return null; + if (!val.length) return; + + if (!contains(dst[0 .. len], val)) + append(val); + else + shift(val); } @@ -948,18 +946,19 @@ pure @safe: return dst[beg .. len]; case 'D': // TypeDelegate (D TypeFunction) popFront(); - auto modbeg = len; - parseModifier(); - auto modend = len; + auto modifiers = parseModifier(); if ( front == 'Q' ) parseBackrefType( () => parseTypeFunction( name, IsDelegate.yes ) ); else parseTypeFunction( name, IsDelegate.yes ); - if (modend > modbeg) + if (modifiers) { - // move modifiers behind the function arguments - shift(dst[modend-1 .. modend]); // trailing space - shift(dst[modbeg .. modend-1]); + // write modifiers behind the function arguments + while (auto str = typeCtors.toStringConsume(modifiers)) + { + put(' '); + put(str); + } } return dst[beg .. len]; case 'n': // TypeNone (n) @@ -1009,7 +1008,6 @@ pure @safe: } } error(); - return null; } } @@ -1110,43 +1108,44 @@ pure @safe: } } - void parseModifier() + /// Returns: Flags of `TypeCtor` + ushort parseModifier() { + TypeCtor res = TypeCtor.None; switch ( front ) { case 'y': popFront(); - put( "immutable " ); - break; + return TypeCtor.Immutable; case 'O': popFront(); - put( "shared " ); - if ( front == 'x' ) + res |= TypeCtor.Shared; + if (front == 'x') goto case 'x'; - if ( front == 'N' ) + if (front == 'N') goto case 'N'; - break; + return TypeCtor.Shared; case 'N': - if ( peek( 1 ) != 'g' ) - break; + if (peek( 1 ) != 'g') + return res; popFront(); popFront(); - put( "inout " ); + res |= TypeCtor.InOut; if ( front == 'x' ) goto case 'x'; - break; + return res; case 'x': popFront(); - put( "const " ); - break; - default: break; + res |= TypeCtor.Const; + return res; + default: return TypeCtor.None; } } - void parseFuncAttr() + ushort parseFuncAttr() { // FuncAttrs - breakFuncAttrs: + ushort result; while ('N' == front) { popFront(); @@ -1154,27 +1153,27 @@ pure @safe: { case 'a': // FuncAttrPure popFront(); - put( "pure " ); + result |= FuncAttributes.Pure; continue; case 'b': // FuncAttrNoThrow popFront(); - put( "nothrow " ); + result |= FuncAttributes.Nothrow; continue; case 'c': // FuncAttrRef popFront(); - put( "ref " ); + result |= FuncAttributes.Ref; continue; case 'd': // FuncAttrProperty popFront(); - put( "@property " ); + result |= FuncAttributes.Property; continue; case 'e': // FuncAttrTrusted popFront(); - put( "@trusted " ); + result |= FuncAttributes.Trusted; continue; case 'f': // FuncAttrSafe popFront(); - put( "@safe " ); + result |= FuncAttributes.Safe; continue; case 'g': case 'h': @@ -1188,27 +1187,42 @@ pure @safe: // if we see these, then we know we're really in // the parameter list. Rewind and break. pos--; - break breakFuncAttrs; + return result; case 'i': // FuncAttrNogc popFront(); - put( "@nogc " ); + result |= FuncAttributes.NoGC; continue; case 'j': // FuncAttrReturn popFront(); - put( "return " ); + if (this.peek(0) == 'N' && this.peek(1) == 'l') + { + result |= FuncAttributes.ReturnScope; + popFront(); + popFront(); + } else { + result |= FuncAttributes.Return; + } continue; case 'l': // FuncAttrScope popFront(); - put( "scope " ); + if (this.peek(0) == 'N' && this.peek(1) == 'j') + { + result |= FuncAttributes.ScopeReturn; + popFront(); + popFront(); + } else { + result |= FuncAttributes.Scope; + } continue; case 'm': // FuncAttrLive popFront(); - put( "@live " ); + result |= FuncAttributes.Live; continue; default: error(); } } + return result; } void parseFuncArguments() scope @@ -1346,19 +1360,20 @@ pure @safe: auto beg = len; parseCallConvention(); - auto attrbeg = len; - parseFuncAttr(); + auto attributes = parseFuncAttr(); auto argbeg = len; put( '(' ); parseFuncArguments(); put( ')' ); - if (attrbeg < argbeg) + if (attributes) { - // move function attributes behind arguments - shift( dst[argbeg - 1 .. argbeg] ); // trailing space - shift( dst[attrbeg .. argbeg - 1] ); // attributes - argbeg = attrbeg; + // write function attributes behind arguments + while (auto str = funcAttrs.toStringConsume(attributes)) + { + put(' '); + put(str); + } } auto retbeg = len; parseType(); @@ -1900,21 +1915,26 @@ pure @safe: { // do not emit "needs this" popFront(); - parseModifier(); + auto modifiers = parseModifier(); + while (auto str = typeCtors.toStringConsume(modifiers)) + { + put(str); + put(' '); + } } if ( isCallConvention( front ) ) { // we don't want calling convention and attributes in the qualified name parseCallConvention(); - parseFuncAttr(); - if ( keepAttr ) - { + auto attributes = parseFuncAttr(); + if (keepAttr) { + while (auto str = funcAttrs.toStringConsume(attributes)) + { + put(str); + put(' '); + } attr = dst[prevlen .. len]; } - else - { - len = prevlen; - } put( '(' ); parseFuncArguments(); @@ -2637,6 +2657,12 @@ else ["_D4test4rrs1FNkMJPiZv", "void test.rrs1(return scope out int*)"], ["_D4test4rrs1FNkMKPiZv", "void test.rrs1(return scope ref int*)"], ["_D4test4rrs1FNkMPiZv", "void test.rrs1(return scope int*)"], + + // `scope` and `return` combinations + ["_D3foo3Foo3barMNgFNjNlNfZNgPv", "inout return scope @safe inout(void*) foo.Foo.bar()"], + ["_D3foo3FooQiMNgFNlNfZv", "inout scope @safe void foo.Foo.foo()"], + ["_D3foo3Foo4foorMNgFNjNfZv", "inout return @safe void foo.Foo.foor()"], + ["_D3foo3Foo3rabMNgFNlNjNfZv", "inout scope return @safe void foo.Foo.rab()"], ]; @@ -2720,7 +2746,12 @@ unittest } /* + * Expand an OMF, DMD-generated compressed identifier into its full form * + * This function only has a visible effect for OMF binaries (Win32), + * as compression is otherwise not used. + * + * See_Also: `compiler/src/dmd/backend/compress.d` */ string decodeDmdString( const(char)[] ln, ref size_t p ) nothrow pure @safe { @@ -2781,3 +2812,92 @@ extern (C) private errno = err; } } + +private struct ManglingFlagInfo +{ + /// The flag value to use + ushort flag; + + /// Human-readable representation + string value; +} + +private enum TypeCtor : ushort { + None = 0, + //// 'x' + Const = (1 << 1), + /// 'y' + Immutable = (1 << 2), + /// 'O' + Shared = (1 << 3), + /// + InOut = (1 << 4), +} + +private immutable ManglingFlagInfo[] typeCtors = [ + ManglingFlagInfo(TypeCtor.Immutable, "immutable"), + ManglingFlagInfo(TypeCtor.Shared, "shared"), + ManglingFlagInfo(TypeCtor.InOut, "inout"), + ManglingFlagInfo(TypeCtor.Const, "const"), +]; + +private enum FuncAttributes : ushort { + None = 0, + //// 'a' + Pure = (1 << 1), + //// 'b' + Nothrow = (1 << 2), + //// 'c' + Ref = (1 << 3), + //// 'd' + Property = (1 << 4), + //// 'e' + Trusted = (1 << 5), + //// 'f' + Safe = (1 << 6), + //// 'i' + NoGC = (1 << 7), + //// 'j' + Return = (1 << 8), + //// 'l' + Scope = (1 << 9), + //// 'm' + Live = (1 << 10), + + /// Their order matter + ReturnScope = (1 << 11), + ScopeReturn = (1 << 12), +} + +// The order in which we process is the same as in compiler/dmd/src/dmangle.d +private immutable ManglingFlagInfo[] funcAttrs = [ + ManglingFlagInfo(FuncAttributes.Pure, "pure"), + ManglingFlagInfo(FuncAttributes.Nothrow, "nothrow"), + ManglingFlagInfo(FuncAttributes.Ref, "ref"), + ManglingFlagInfo(FuncAttributes.Property, "@property"), + ManglingFlagInfo(FuncAttributes.NoGC, "@nogc"), + + ManglingFlagInfo(FuncAttributes.ReturnScope, "return scope"), + ManglingFlagInfo(FuncAttributes.ScopeReturn, "scope return"), + + ManglingFlagInfo(FuncAttributes.Return, "return"), + ManglingFlagInfo(FuncAttributes.Scope, "scope"), + + ManglingFlagInfo(FuncAttributes.Live, "@live"), + ManglingFlagInfo(FuncAttributes.Trusted, "@trusted"), + ManglingFlagInfo(FuncAttributes.Safe, "@safe"), +]; + +private string toStringConsume (immutable ManglingFlagInfo[] infos, ref ushort base) + @safe pure nothrow @nogc +{ + foreach (const ref info; infos) + { + if ((base & info.flag) == info.flag) + { + base &= ~info.flag; + return info.value; + } + } + return null; +} diff --git a/libphobos/libdruntime/core/internal/array/arrayassign.d b/libphobos/libdruntime/core/internal/array/arrayassign.d index 6132e68..6e3c1fd 100644 --- a/libphobos/libdruntime/core/internal/array/arrayassign.d +++ b/libphobos/libdruntime/core/internal/array/arrayassign.d @@ -302,3 +302,151 @@ Tarr _d_arrayassign_r(Tarr : T[], T)(return scope Tarr to, scope Tarr from) @tru assert(!didThrow); assert(counter == 0); } + +/** + * Sets all elements of an array to a single value. Takes into account postblits, + * copy constructors and destructors. For Plain Old Data elements,`rt/memset.d` + * is used. + * + * --- + * struct S + * { + * ~this() {} // destructor, so not Plain Old Data + * } + * + * void main() + * { + * S[3] arr; + * S value; + * + * arr = value; + * // Generates: + * // _d_arraysetassign(arr[], value), arr; + * } + * --- + * + * Params: + * to = destination array + * value = the element to set + * Returns: + * `to` + */ +Tarr _d_arraysetassign(Tarr : T[], T)(return scope Tarr to, scope ref T value) @trusted +{ + import core.internal.traits : Unqual; + import core.lifetime : copyEmplace; + import core.stdc.string : memcpy; + + enum elemSize = T.sizeof; + void[elemSize] tmp = void; + + foreach (ref dst; to) + { + memcpy(&tmp, cast(void*) &dst, elemSize); + // Use `memcpy` if `T` has a `@disable`d postblit. + static if (__traits(isCopyable, T)) + copyEmplace(value, dst); + else + memcpy(cast(void*) &value, cast(void*) &dst, elemSize); + auto elem = cast(Unqual!T*) &tmp; + destroy(*elem); + } + + return to; +} + +// postblit and destructor +@safe unittest +{ + string ops; + struct S + { + int val; + this(this) { ops ~= "="; } + ~this() { ops ~= "~"; } + } + + S[4] arr; + S s = S(1234); + _d_arraysetassign(arr[], s); + assert(ops == "=~=~=~=~"); + assert(arr == [S(1234), S(1234), S(1234), S(1234)]); +} + +// copy constructor +@safe unittest +{ + string ops; + struct S + { + int val; + this(const scope ref S rhs) + { + val = rhs.val; + ops ~= "="; + } + ~this() { ops ~= "~"; } + } + + S[4] arr; + S s = S(1234); + _d_arraysetassign(arr[], s); + assert(ops == "=~=~=~=~"); + assert(arr == [S(1234), S(1234), S(1234), S(1234)]); +} + +// throwing and `nothrow` +@safe nothrow unittest +{ + // Test that throwing works + bool didThrow; + int counter; + struct Throw + { + int val; + this(this) + { + counter++; + if (counter == 2) + throw new Exception("Oh no."); + } + } + + try + { + Throw[4] a; + Throw b = Throw(1); + _d_arraysetassign(a[], b); + } + catch (Exception) + { + didThrow = true; + } + assert(didThrow); + assert(counter == 2); + + // Test that `nothrow` works + didThrow = false; + counter = 0; + struct NoThrow + { + int val; + this(this) { counter++; } + } + + try + { + NoThrow[4] a; + NoThrow b = NoThrow(1); + _d_arraysetassign(a[], b); + foreach (ref e; a) + assert(e == NoThrow(1)); + } + catch (Exception) + { + didThrow = true; + } + assert(!didThrow); + // The array `a` is destroyed when the `try` block ends. + assert(counter == 4); +} diff --git a/libphobos/libdruntime/core/internal/dassert.d b/libphobos/libdruntime/core/internal/dassert.d index 07486c2..dbad0e6 100644 --- a/libphobos/libdruntime/core/internal/dassert.d +++ b/libphobos/libdruntime/core/internal/dassert.d @@ -518,7 +518,7 @@ private auto assumeFakeAttributes(T)(T t) @trusted } /// Wrapper for `miniFormat` which assumes that the implementation is `@safe`, `@nogc`, ... -/// s.t. it does not violate the constraints of the the function containing the `assert`. +/// s.t. it does not violate the constraints of the function containing the `assert`. private string miniFormatFakeAttributes(T)(const scope ref T t) { alias miniT = miniFormat!T; diff --git a/libphobos/libdruntime/core/internal/utf.d b/libphobos/libdruntime/core/internal/utf.d index 27bf7f2b..9808b99 100644 --- a/libphobos/libdruntime/core/internal/utf.d +++ b/libphobos/libdruntime/core/internal/utf.d @@ -567,17 +567,22 @@ ubyte codeLength(C)(dchar c) /*********************************** Checks to see if string is well formed or not. $(D S) can be an array - of $(D char), $(D wchar), or $(D dchar). Throws a $(D UtfException) - if it is not. Use to check all untrusted input for correctness. + of $(D char), $(D wchar), or $(D dchar). Returns $(D false) if it is not. + Use to check all untrusted input for correctness. */ -@safe pure -void validate(S)(const scope S s) +@safe pure nothrow +bool isValidString(S)(const scope S s) { auto len = s.length; for (size_t i = 0; i < len; ) { - decode(s, i); + try + decode(s, i); + catch (Exception e) + return false; } + + return true; } /* =================== Conversion to UTF8 ======================= */ @@ -626,7 +631,7 @@ char[] toUTF8(return scope char[] buf, dchar c) string toUTF8(return scope string s) in { - validate(s); + assert(isValidString(s)); } do { @@ -787,7 +792,7 @@ wptr toUTF16z(const scope char[] s) wstring toUTF16(return scope wstring s) in { - validate(s); + assert(isValidString(s)); } do { @@ -867,7 +872,7 @@ dstring toUTF32(const scope wchar[] s) dstring toUTF32(return scope dstring s) in { - validate(s); + assert(isValidString(s)); } do { diff --git a/libphobos/libdruntime/core/simd.d b/libphobos/libdruntime/core/simd.d index f1bf59b..c2b343a 100644 --- a/libphobos/libdruntime/core/simd.d +++ b/libphobos/libdruntime/core/simd.d @@ -704,7 +704,7 @@ version (D_SIMD) // store `v` to location pointed to by `d` storeUnaligned(cast(T*)d, v); - // check that the the data was stored correctly + // check that the data was stored correctly foreach (j; 0..T.sizeof) { assert(ptrToV[j] == d[j]); diff --git a/libphobos/libdruntime/core/stdc/fenv.d b/libphobos/libdruntime/core/stdc/fenv.d index 88123fb..5242ba9 100644 --- a/libphobos/libdruntime/core/stdc/fenv.d +++ b/libphobos/libdruntime/core/stdc/fenv.d @@ -483,7 +483,7 @@ else version (CRuntime_UClibc) alias fexcept_t = ushort; } - else version (MIPS32) + else version (MIPS_Any) { struct fenv_t { diff --git a/libphobos/libdruntime/core/stdc/math.d b/libphobos/libdruntime/core/stdc/math.d index 0393ea5..2666c95 100644 --- a/libphobos/libdruntime/core/stdc/math.d +++ b/libphobos/libdruntime/core/stdc/math.d @@ -106,21 +106,14 @@ else version (CRuntime_Bionic) } else version (CRuntime_UClibc) { - version (X86) - { - /// - enum int FP_ILOGB0 = int.min; - /// - enum int FP_ILOGBNAN = int.min; - } - else version (X86_64) + version (X86_Any) { /// enum int FP_ILOGB0 = int.min; /// enum int FP_ILOGBNAN = int.min; } - else version (MIPS32) + else version (MIPS_Any) { /// enum int FP_ILOGB0 = -int.max; diff --git a/libphobos/libdruntime/core/sys/darwin/mach/loader.d b/libphobos/libdruntime/core/sys/darwin/mach/loader.d index f46698c..7713eea 100644 --- a/libphobos/libdruntime/core/sys/darwin/mach/loader.d +++ b/libphobos/libdruntime/core/sys/darwin/mach/loader.d @@ -1803,7 +1803,7 @@ version (CoreDdoc) * image. The isub_image field is an index into the sub-images * (sub-frameworks and sub-umbrellas list) that made up the two-level image * that the undefined symbol was found in when it was built by the static - * link editor. If isub-image is 0 the the symbol is expected to be defined + * link editor. If isub-image is 0 the symbol is expected to be defined * in library and not in the sub-images. If isub-image is non-zero it is an * index into the array of sub-images for the umbrella with the first index * in the sub-images being 1. The array of sub-images is the ordered list of diff --git a/libphobos/libdruntime/core/sys/linux/fcntl.d b/libphobos/libdruntime/core/sys/linux/fcntl.d index 11c3745..89dc019 100644 --- a/libphobos/libdruntime/core/sys/linux/fcntl.d +++ b/libphobos/libdruntime/core/sys/linux/fcntl.d @@ -42,7 +42,7 @@ These cmd values will set locks that conflict with process-associated record locks, but are "owned" by the open file description, not the process. This means that they are inherited across fork() like BSD (flock) locks, and they are only released automatically when the last reference to -the the open file against which they were acquired is put. +the open file against which they were acquired is put. */ enum diff --git a/libphobos/libdruntime/core/sys/posix/dlfcn.d b/libphobos/libdruntime/core/sys/posix/dlfcn.d index a9519ca..04a8e8b 100644 --- a/libphobos/libdruntime/core/sys/posix/dlfcn.d +++ b/libphobos/libdruntime/core/sys/posix/dlfcn.d @@ -377,7 +377,7 @@ else version (CRuntime_Musl) } else version (CRuntime_UClibc) { - version (X86_64) + version (X86_Any) { enum RTLD_LAZY = 0x0001; enum RTLD_NOW = 0x0002; @@ -387,7 +387,7 @@ else version (CRuntime_UClibc) enum RTLD_LOCAL = 0; enum RTLD_NODELETE = 0x01000; } - else version (MIPS32) + else version (MIPS_Any) { enum RTLD_LAZY = 0x0001; enum RTLD_NOW = 0x0002; diff --git a/libphobos/libdruntime/core/sys/posix/mqueue.d b/libphobos/libdruntime/core/sys/posix/mqueue.d index 2f1a8c6..7085fc4 100644 --- a/libphobos/libdruntime/core/sys/posix/mqueue.d +++ b/libphobos/libdruntime/core/sys/posix/mqueue.d @@ -147,7 +147,7 @@ int mq_notify (mqd_t mqdes, const(sigevent)* notification); /** - * Receive the oldest message with the highest priority the the message queue + * Receive the oldest message with the highest priority the message queue * * Params: * mqdes = Message queue descriptor. @@ -164,7 +164,7 @@ ssize_t mq_receive (mqd_t mqdes, char* msg_ptr, size_t msg_len, uint* msg_prio); /** - * Receive the oldest message with the highest priority the the message queue, + * Receive the oldest message with the highest priority the message queue, * wait up to a certain timeout. * * Params: diff --git a/libphobos/libdruntime/core/sys/posix/setjmp.d b/libphobos/libdruntime/core/sys/posix/setjmp.d index 91e3a19..5a15d82 100644 --- a/libphobos/libdruntime/core/sys/posix/setjmp.d +++ b/libphobos/libdruntime/core/sys/posix/setjmp.d @@ -370,6 +370,22 @@ else version (CRuntime_UClibc) double[6] __fpregs; } } + else version (MIPS64) + { + struct __jmp_buf + { + long __pc; + long __sp; + long[8] __regs; + long __fp; + long __gp; + int __fpc_csr; + version (MIPS_N64) + double[8] __fpregs; + else + double[6] __fpregs; + } + } else static assert(0, "unimplemented"); diff --git a/libphobos/libdruntime/core/sys/posix/stdlib.d b/libphobos/libdruntime/core/sys/posix/stdlib.d index 4c10d4e..df96a3d 100644 --- a/libphobos/libdruntime/core/sys/posix/stdlib.d +++ b/libphobos/libdruntime/core/sys/posix/stdlib.d @@ -95,44 +95,44 @@ int posix_memalign(void**, size_t, size_t); version (CRuntime_Glibc) { - int posix_memalign(void**, size_t, size_t); + int posix_memalign(scope void**, size_t, size_t) pure; } else version (FreeBSD) { - int posix_memalign(void**, size_t, size_t); + int posix_memalign(scope void**, size_t, size_t) pure; } else version (NetBSD) { - int posix_memalign(void**, size_t, size_t); + int posix_memalign(scope void**, size_t, size_t) pure; } else version (OpenBSD) { - int posix_memalign(void**, size_t, size_t); + int posix_memalign(scope void**, size_t, size_t) pure; } else version (DragonFlyBSD) { - int posix_memalign(void**, size_t, size_t); + int posix_memalign(scope void**, size_t, size_t) pure; } else version (Solaris) { - int posix_memalign(void**, size_t, size_t); + int posix_memalign(scope void**, size_t, size_t) pure; } else version (Darwin) { - int posix_memalign(void**, size_t, size_t); + int posix_memalign(scope void**, size_t, size_t) pure; } else version (CRuntime_Bionic) { // Added since Lollipop - int posix_memalign(void**, size_t, size_t); + int posix_memalign(scope void**, size_t, size_t) pure; } else version (CRuntime_Musl) { - int posix_memalign(void**, size_t, size_t); + int posix_memalign(scope void**, size_t, size_t) pure; } else version (CRuntime_UClibc) { - int posix_memalign(void**, size_t, size_t); + int posix_memalign(scope void**, size_t, size_t) pure; } // diff --git a/libphobos/libdruntime/core/sys/posix/sys/types.d b/libphobos/libdruntime/core/sys/posix/sys/types.d index ec229dd..3e515c4 100644 --- a/libphobos/libdruntime/core/sys/posix/sys/types.d +++ b/libphobos/libdruntime/core/sys/posix/sys/types.d @@ -1140,6 +1140,18 @@ else version (CRuntime_UClibc) enum __SIZEOF_PTHREAD_BARRIER_T = 20; enum __SIZEOF_PTHREAD_BARRIERATTR_T = 4; } + else version (MIPS64) + { + enum __SIZEOF_PTHREAD_ATTR_T = 56; + enum __SIZEOF_PTHREAD_MUTEX_T = 40; + enum __SIZEOF_PTHREAD_MUTEXATTR_T = 4; + enum __SIZEOF_PTHREAD_COND_T = 48; + enum __SIZEOF_PTHREAD_CONDATTR_T = 4; + enum __SIZEOF_PTHREAD_RWLOCK_T = 56; + enum __SIZEOF_PTHREAD_RWLOCKATTR_T = 8; + enum __SIZEOF_PTHREAD_BARRIER_T = 32; + enum __SIZEOF_PTHREAD_BARRIERATTR_T = 4; + } else version (ARM) { enum __SIZEOF_PTHREAD_ATTR_T = 36; diff --git a/libphobos/libdruntime/core/sys/windows/stacktrace.d b/libphobos/libdruntime/core/sys/windows/stacktrace.d index 2922e54..7982085 100644 --- a/libphobos/libdruntime/core/sys/windows/stacktrace.d +++ b/libphobos/libdruntime/core/sys/windows/stacktrace.d @@ -288,7 +288,8 @@ private: auto res = formatStackFrame(pc); res ~= " in "; const(char)[] tempSymName = symName[0 .. strlen(symName)]; - //Deal with dmd mangling of long names + // Deal with dmd mangling of long names for OMF 32 bits builds + // Note that `target.d` only defines `CRuntime_DigitalMars` for OMF builds version (CRuntime_DigitalMars) { size_t decodeIndex = 0; diff --git a/libphobos/libdruntime/core/time.d b/libphobos/libdruntime/core/time.d index 9b8391e..ea163a0 100644 --- a/libphobos/libdruntime/core/time.d +++ b/libphobos/libdruntime/core/time.d @@ -3362,7 +3362,7 @@ struct TickDuration $(D gettimeofday) (the decision is made when $(D TickDuration) is compiled), which unfortunately, is not monotonic, but if $(D mach_absolute_time) and $(D clock_gettime) aren't available, then - $(D gettimeofday) is the the best that there is. + $(D gettimeofday) is the best that there is. $(RED Warning): On some systems, the monotonic clock may stop counting when diff --git a/libphobos/libdruntime/object.d b/libphobos/libdruntime/object.d index d842499..83351f2 100644 --- a/libphobos/libdruntime/object.d +++ b/libphobos/libdruntime/object.d @@ -2700,7 +2700,7 @@ class Exception : Throwable * Creates a new instance of Exception. The nextInChain parameter is used * internally and should always be $(D null) when passed by user code. * This constructor does not automatically throw the newly-created - * Exception; the $(D throw) statement should be used for that purpose. + * Exception; the $(D throw) expression should be used for that purpose. */ @nogc @safe pure nothrow this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable nextInChain = null) { @@ -4617,6 +4617,7 @@ public import core.internal.array.construction : _d_arrayctor; public import core.internal.array.construction : _d_arraysetctor; public import core.internal.array.arrayassign : _d_arrayassign_l; public import core.internal.array.arrayassign : _d_arrayassign_r; +public import core.internal.array.arrayassign : _d_arraysetassign; public import core.internal.array.capacity: _d_arraysetlengthTImpl; public import core.internal.dassert: _d_assert_fail; diff --git a/libphobos/libdruntime/rt/arrayassign.d b/libphobos/libdruntime/rt/arrayassign.d deleted file mode 100644 index c9e2b15..0000000 --- a/libphobos/libdruntime/rt/arrayassign.d +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Implementation of array assignment support routines. - * - * - * Copyright: Copyright Digital Mars 2010 - 2016. - * License: Distributed under the - * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). - * Authors: Walter Bright, Kenji Hara - * Source: $(DRUNTIMESRC rt/_arrayassign.d) - */ - -module rt.arrayassign; - -private -{ - import core.internal.util.array; - import core.stdc.string; - import core.stdc.stdlib; - debug(PRINTF) import core.stdc.stdio; -} - -/** -Set all elements of an array to a single value. - ---- -p[0 .. count] = value; ---- - -Takes into account postblits and destructors, for Plain Old Data elements, -`rt/memset.d` is used. - -Params: - p = pointer to start of array - value = bytes of the element to set. Size is derived from `ti`. - count = amount of array elements to set - ti = type info of the array element type / `value` -Returns: `p` -*/ -extern (C) void* _d_arraysetassign(void* p, void* value, int count, TypeInfo ti) -{ - void* pstart = p; - - auto element_size = ti.tsize; - - // Need a temporary buffer tmp[] big enough to hold one element - immutable maxAllocaSize = 512; - void *ptmp = (element_size > maxAllocaSize) ? malloc(element_size) : alloca(element_size); - - foreach (i; 0 .. count) - { - memcpy(ptmp, p, element_size); - memcpy(p, value, element_size); - ti.postblit(p); - ti.destroy(ptmp); - p += element_size; - } - if (element_size > maxAllocaSize) - free(ptmp); - return pstart; -} diff --git a/libphobos/libdruntime/rt/lifetime.d b/libphobos/libdruntime/rt/lifetime.d index 026001f..f2515c3 100644 --- a/libphobos/libdruntime/rt/lifetime.d +++ b/libphobos/libdruntime/rt/lifetime.d @@ -1232,61 +1232,6 @@ debug(PRINTF) /** * */ -extern (C) void _d_delarray_t(void[]* p, const TypeInfo_Struct ti) @weak -{ - if (p) - { - auto bic = __getBlkInfo(p.ptr); - auto info = bic ? *bic : GC.query(p.ptr); - - if (info.base && (info.attr & BlkAttr.APPENDABLE)) - { - if (ti) // ti non-null only if ti is a struct with dtor - { - void* start = __arrayStart(info); - size_t length = __arrayAllocLength(info, ti); - finalize_array(start, length, ti); - } - - // if p is in the cache, clear it there as well - if (bic) - bic.base = null; - - GC.free(info.base); - *p = null; - } - } -} - -deprecated unittest -{ - __gshared size_t countDtor = 0; - struct S - { - int x; - ~this() { countDtor++; } - } - // destroy large array with x.ptr not base address of allocation - auto x = new S[10000]; - void* p = x.ptr; - assert(GC.addrOf(p) != null); - _d_delarray_t(cast(void[]*)&x, typeid(typeof(x[0]))); // delete x; - assert(GC.addrOf(p) == null); - assert(countDtor == 10000); - - // destroy full array even if only slice passed - auto y = new S[400]; - auto z = y[200 .. 300]; - p = z.ptr; - assert(GC.addrOf(p) != null); - _d_delarray_t(cast(void[]*)&z, typeid(typeof(z[0]))); // delete z; - assert(GC.addrOf(p) == null); - assert(countDtor == 10000 + 400); -} - -/** - * - */ extern (C) void _d_delmemory(void* *p) @weak { if (*p) @@ -2755,11 +2700,6 @@ deprecated unittest } dtorCount = 0; - S1[] arr1 = new S1[7]; - _d_delarray_t(cast(void[]*)&arr1, typeid(typeof(arr1[0]))); // delete arr1; - assert(dtorCount == 7); - - dtorCount = 0; S1* s2 = new S1; GC.runFinalizers((cast(char*)(typeid(S1).xdtor))[0..1]); assert(dtorCount == 1); diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE index c8a3771..4d63826 100644 --- a/libphobos/src/MERGE +++ b/libphobos/src/MERGE @@ -1,4 +1,4 @@ -b578dfad94770574d7e522557a77276c35943daa +88aa69b14f8a28255a0ac7626f6509a13cfdb67a The first line of this file holds the git revision number of the last merge done from the dlang/phobos repository. diff --git a/libphobos/src/Makefile.am b/libphobos/src/Makefile.am index 2413024..655c02e 100644 --- a/libphobos/src/Makefile.am +++ b/libphobos/src/Makefile.am @@ -97,9 +97,9 @@ PHOBOS_DSOURCES = etc/c/curl.d etc/c/zlib.d std/algorithm/comparison.d \ std/datetime/interval.d std/datetime/package.d \ std/datetime/stopwatch.d std/datetime/systime.d \ std/datetime/timezone.d std/demangle.d std/digest/crc.d \ - std/digest/digest.d std/digest/hmac.d std/digest/md.d \ - std/digest/murmurhash.d std/digest/package.d std/digest/ripemd.d \ - std/digest/sha.d std/encoding.d std/exception.d \ + std/digest/hmac.d std/digest/md.d std/digest/murmurhash.d \ + std/digest/package.d std/digest/ripemd.d std/digest/sha.d \ + std/encoding.d std/exception.d \ std/experimental/allocator/building_blocks/affix_allocator.d \ std/experimental/allocator/building_blocks/aligned_block_list.d \ std/experimental/allocator/building_blocks/allocator_list.d \ @@ -156,6 +156,6 @@ PHOBOS_DSOURCES = etc/c/curl.d etc/c/zlib.d std/algorithm/comparison.d \ std/stdio.d std/string.d std/sumtype.d std/system.d std/traits.d \ std/typecons.d std/typetuple.d std/uni/package.d std/uri.d std/utf.d \ std/uuid.d std/variant.d std/windows/charset.d std/windows/registry.d \ - std/windows/syserror.d std/xml.d std/zip.d std/zlib.d + std/windows/syserror.d std/zip.d std/zlib.d endif diff --git a/libphobos/src/Makefile.in b/libphobos/src/Makefile.in index 562a428..a622958 100644 --- a/libphobos/src/Makefile.in +++ b/libphobos/src/Makefile.in @@ -179,7 +179,6 @@ am__dirstamp = $(am__leading_dot)dirstamp @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/datetime/timezone.lo \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/demangle.lo \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/digest/crc.lo \ -@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/digest/digest.lo \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/digest/hmac.lo \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/digest/md.lo \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/digest/murmurhash.lo \ @@ -291,8 +290,7 @@ am__dirstamp = $(am__leading_dot)dirstamp @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/windows/charset.lo \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/windows/registry.lo \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/windows/syserror.lo \ -@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/xml.lo std/zip.lo \ -@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/zlib.lo +@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/zip.lo std/zlib.lo am__objects_2 = $(am__objects_1) am__objects_3 = $(am__objects_2) am_libgphobos_la_OBJECTS = $(am__objects_3) @@ -562,9 +560,9 @@ libgphobos_la_LINK = $(LIBTOOL) --tag=D $(libgphobos_la_LIBTOOLFLAGS) \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/datetime/interval.d std/datetime/package.d \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/datetime/stopwatch.d std/datetime/systime.d \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/datetime/timezone.d std/demangle.d std/digest/crc.d \ -@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/digest/digest.d std/digest/hmac.d std/digest/md.d \ -@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/digest/murmurhash.d std/digest/package.d std/digest/ripemd.d \ -@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/digest/sha.d std/encoding.d std/exception.d \ +@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/digest/hmac.d std/digest/md.d std/digest/murmurhash.d \ +@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/digest/package.d std/digest/ripemd.d std/digest/sha.d \ +@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/encoding.d std/exception.d \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/experimental/allocator/building_blocks/affix_allocator.d \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/experimental/allocator/building_blocks/aligned_block_list.d \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/experimental/allocator/building_blocks/allocator_list.d \ @@ -621,7 +619,7 @@ libgphobos_la_LINK = $(LIBTOOL) --tag=D $(libgphobos_la_LIBTOOLFLAGS) \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/stdio.d std/string.d std/sumtype.d std/system.d std/traits.d \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/typecons.d std/typetuple.d std/uni/package.d std/uri.d std/utf.d \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/uuid.d std/variant.d std/windows/charset.d std/windows/registry.d \ -@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/windows/syserror.d std/xml.d std/zip.d std/zlib.d +@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/windows/syserror.d std/zip.d std/zlib.d # Source file definitions. Boring stuff, auto-generated with @@ -754,7 +752,6 @@ std/digest/$(am__dirstamp): @$(MKDIR_P) std/digest @: > std/digest/$(am__dirstamp) std/digest/crc.lo: std/digest/$(am__dirstamp) -std/digest/digest.lo: std/digest/$(am__dirstamp) std/digest/hmac.lo: std/digest/$(am__dirstamp) std/digest/md.lo: std/digest/$(am__dirstamp) std/digest/murmurhash.lo: std/digest/$(am__dirstamp) @@ -964,7 +961,6 @@ std/windows/$(am__dirstamp): std/windows/charset.lo: std/windows/$(am__dirstamp) std/windows/registry.lo: std/windows/$(am__dirstamp) std/windows/syserror.lo: std/windows/$(am__dirstamp) -std/xml.lo: std/$(am__dirstamp) std/zip.lo: std/$(am__dirstamp) std/zlib.lo: std/$(am__dirstamp) diff --git a/libphobos/src/index.dd b/libphobos/src/index.dd index 45c248e..4812225 100644 --- a/libphobos/src/index.dd +++ b/libphobos/src/index.dd @@ -71,10 +71,6 @@ $(BOOKTABLE , $(TD Read/write data in JSON format.) ) $(TR - $(TDNW $(MREF std,xml)) - $(TD Read/write data in XML format.) - ) - $(TR $(TDNW $(MREF std,zip)) $(TD Read/write data in the ZIP archive format.) ) diff --git a/libphobos/src/std/algorithm/comparison.d b/libphobos/src/std/algorithm/comparison.d index b810fbb..5ecb4f6 100644 --- a/libphobos/src/std/algorithm/comparison.d +++ b/libphobos/src/std/algorithm/comparison.d @@ -577,14 +577,24 @@ Returns: and `T3` are different. */ T1 clamp(T1, T2, T3)(T1 val, T2 lower, T3 upper) -if (is(typeof(val.lessThan(lower) ? lower : val.greaterThan(upper) ? upper : val) : T1)) +if (is(typeof(val.lessThan(lower) ? lower : val.greaterThan(upper) ? upper : val)) + && (is(T2 : T1) && is(T3 : T1))) +// cannot use : +// `if (is(typeof(val.lessThan(lower) ? lower : val.greaterThan(upper) ? upper : val) : T1)) +// because of https://issues.dlang.org/show_bug.cgi?id=16235. +// Once that is fixed, we can simply use the ternary in both the template constraint +// and the template body in { assert(!lower.greaterThan(upper), "Lower can't be greater than upper."); } do { - return val.lessThan(lower) ? lower : val.greaterThan(upper) ? upper : val; + if (val.lessThan(lower)) + return lower; + else if (val.greaterThan(upper)) + return upper; + return val; } /// @@ -637,6 +647,12 @@ do assert(x.clamp(lo, hi).y == 42); } +// https://issues.dlang.org/show_bug.cgi?id=23268 +@safe pure nothrow @nogc unittest +{ + static assert(__traits(compiles, clamp(short.init, short.init, cast(const) short.init))); +} + // cmp /********************************** Performs a lexicographical comparison on two diff --git a/libphobos/src/std/algorithm/iteration.d b/libphobos/src/std/algorithm/iteration.d index 3e828ce..39eff0d 100644 --- a/libphobos/src/std/algorithm/iteration.d +++ b/libphobos/src/std/algorithm/iteration.d @@ -771,6 +771,23 @@ private struct MapResult(alias fun, Range) assert(dd.length == 4); } +// Verify fix for: https://issues.dlang.org/show_bug.cgi?id=16034 +@safe unittest +{ + struct One + { + int entry = 1; + @disable this(this); + } + + One[] ones = [One(), One()]; + + import std.algorithm.comparison : equal; + + assert(ones.map!`a.entry + 1`.equal([2, 2])); +} + + @safe unittest { import std.algorithm.comparison : equal; diff --git a/libphobos/src/std/algorithm/searching.d b/libphobos/src/std/algorithm/searching.d index 870b1b4..15f7ca9 100644 --- a/libphobos/src/std/algorithm/searching.d +++ b/libphobos/src/std/algorithm/searching.d @@ -5002,7 +5002,7 @@ If set to `OpenRight.yes`, then the interval is open to the right (last element is not included). Otherwise if set to `OpenRight.no`, then the interval is closed to the right -(last element included). +including the entire sentinel. */ alias OpenRight = Flag!"openRight"; @@ -5052,6 +5052,7 @@ if (isInputRange!Range) static if (!is(Sentinel == void)) private Sentinel _sentinel; private OpenRight _openRight; + private bool _matchStarted; private bool _done; static if (!is(Sentinel == void)) @@ -5063,7 +5064,19 @@ if (isInputRange!Range) _input = input; _sentinel = sentinel; _openRight = openRight; - _done = _input.empty || openRight && predSatisfied(); + static if (isInputRange!Sentinel) + { + _matchStarted = predSatisfied(); + _done = _input.empty || _sentinel.empty || openRight && _matchStarted; + if (_matchStarted && !_done && !openRight) + { + _sentinel.popFront; + } + } + else + { + _done = _input.empty || openRight && predSatisfied(); + } } private this(Range input, Sentinel sentinel, OpenRight openRight, bool done) @@ -5118,9 +5131,32 @@ if (isInputRange!Range) assert(!empty, "Can not popFront of an empty Until"); if (!_openRight) { - _done = predSatisfied(); - _input.popFront(); - _done = _done || _input.empty; + static if (isInputRange!Sentinel) + { + _input.popFront(); + _done = _input.empty || _sentinel.empty; + if (!_done) + { + if (_matchStarted) + { + _sentinel.popFront; + } + else + { + _matchStarted = predSatisfied(); + if (_matchStarted) + { + _sentinel.popFront; + } + } + } + } + else + { + _done = predSatisfied(); + _input.popFront(); + _done = _done || _input.empty; + } } else { @@ -5212,3 +5248,33 @@ pure @safe unittest assert(equal(r.save, "foo")); } } +// https://issues.dlang.org/show_bug.cgi?id=14543 +pure @safe unittest +{ + import std.algorithm.comparison : equal; + import std.uni : toUpper; + assert("one two three".until("two").equal("one ")); + assert("one two three".until("two", OpenRight.no).equal("one two")); + + assert("one two three".until("two", No.openRight).equal("one two")); + assert("one two three".until("two", Yes.openRight).equal("one ")); + + assert("one two three".until('t', Yes.openRight).equal("one ")); + assert("one two three".until("", Yes.openRight).equal("")); + assert("one two three".until("", No.openRight).equal("")); + + assert("one two three".until("three", No.openRight).equal("one two three")); + assert("one two three".until("three", Yes.openRight).equal("one two ")); + + assert("one two three".until("one", No.openRight).equal("one")); + assert("one two three".until("one", Yes.openRight).equal("")); + + assert("one two three".until("o", No.openRight).equal("o")); + assert("one two three".until("o", Yes.openRight).equal("")); + + assert("one two three".until("", No.openRight).equal("")); + assert("one two three".until("", Yes.openRight).equal("")); + + assert("one two three".until!((a,b)=>a.toUpper == b)("TWO", No.openRight).equal("one two")); +} + diff --git a/libphobos/src/std/algorithm/sorting.d b/libphobos/src/std/algorithm/sorting.d index ee68b23..4fc7ee9 100644 --- a/libphobos/src/std/algorithm/sorting.d +++ b/libphobos/src/std/algorithm/sorting.d @@ -1642,9 +1642,9 @@ private void multiSortImpl(Range, SwapStrategy ss, funs...)(Range r) } // https://issues.dlang.org/show_bug.cgi?id=16413 - @system comparison function -@safe unittest +@system unittest { - bool lt(int a, int b) { return a < b; } static @system + static @system bool lt(int a, int b) { return a < b; } auto a = [2, 1]; a.multiSort!(lt, lt); assert(a == [1, 2]); diff --git a/libphobos/src/std/compiler.d b/libphobos/src/std/compiler.d index 2f983c5..4ea5bd7 100644 --- a/libphobos/src/std/compiler.d +++ b/libphobos/src/std/compiler.d @@ -28,7 +28,7 @@ immutable gnu = 2, /// GNU D Compiler (GDC) llvm = 3, /// LLVM D Compiler (LDC) dotNET = 4, /// D.NET - sdc = 5, /// Stupid D Compiler (SDC) + sdc = 5, /// Snazzy D Compiler (SDC) } /// Which vendor produced this compiler. diff --git a/libphobos/src/std/concurrency.d b/libphobos/src/std/concurrency.d index fb383ae..bc53236 100644 --- a/libphobos/src/std/concurrency.d +++ b/libphobos/src/std/concurrency.d @@ -257,9 +257,12 @@ private @property ref ThreadInfo thisInfo() nothrow { - if (scheduler is null) + import core.atomic : atomicLoad; + + auto localScheduler = atomicLoad(scheduler); + if (localScheduler is null) return ThreadInfo.thisInfo; - return scheduler.thisInfo; + return localScheduler.thisInfo; } } diff --git a/libphobos/src/std/container/array.d b/libphobos/src/std/container/array.d index 08f9ead..ecc4599 100644 --- a/libphobos/src/std/container/array.d +++ b/libphobos/src/std/container/array.d @@ -412,9 +412,9 @@ if (!is(immutable T == immutable bool)) .destroy(e); static if (hasIndirections!T) - GC.removeRange(_payload.ptr); + GC.removeRange(cast(void*) _payload.ptr); - free(_payload.ptr); + free(cast(void*) _payload.ptr); } this(this) @disable; @@ -489,14 +489,14 @@ if (!is(immutable T == immutable bool)) auto newPayload = newPayloadPtr[0 .. oldLength]; // copy old data over to new array - memcpy(newPayload.ptr, _payload.ptr, T.sizeof * oldLength); + memcpy(cast(void*) newPayload.ptr, cast(void*) _payload.ptr, T.sizeof * oldLength); // Zero out unused capacity to prevent gc from seeing false pointers - memset(newPayload.ptr + oldLength, + memset( cast(void*) (newPayload.ptr + oldLength), 0, (elements - oldLength) * T.sizeof); - GC.addRange(newPayload.ptr, sz); - GC.removeRange(_payload.ptr); - free(_payload.ptr); + GC.addRange(cast(void*) newPayload.ptr, sz); + GC.removeRange(cast(void*) _payload.ptr); + free(cast(void*) _payload.ptr); _payload = newPayload; } else @@ -611,12 +611,17 @@ if (!is(immutable T == immutable bool)) return opEquals(rhs); } + // fix https://issues.dlang.org/show_bug.cgi?23140 + private alias Unshared(T) = T; + private alias Unshared(T: shared U, U) = U; + /// ditto bool opEquals(ref const Array rhs) const { if (empty) return rhs.empty; if (rhs.empty) return false; - return _data._payload == rhs._data._payload; + + return cast(Unshared!(T)[]) _data._payload == cast(Unshared!(T)[]) rhs._data._payload; } /** @@ -1740,6 +1745,16 @@ if (!is(immutable T == immutable bool)) assertThrown!AssertError(array.length = 5); } +// https://issues.dlang.org/show_bug.cgi?id=23140 +@system unittest +{ + shared class C + { + } + + Array!C ac; + ac = Array!C([new C]); +} //////////////////////////////////////////////////////////////////////////////// // Array!bool //////////////////////////////////////////////////////////////////////////////// diff --git a/libphobos/src/std/container/dlist.d b/libphobos/src/std/container/dlist.d index 32d56ec..11e3883 100644 --- a/libphobos/src/std/container/dlist.d +++ b/libphobos/src/std/container/dlist.d @@ -111,7 +111,7 @@ private struct DRange static assert(is(ElementType!DRange == BaseNode*)); } -nothrow @safe pure: +nothrow @safe @nogc pure: private BaseNode* _first; private BaseNode* _last; diff --git a/libphobos/src/std/conv.d b/libphobos/src/std/conv.d index 9164e07..0f66065 100644 --- a/libphobos/src/std/conv.d +++ b/libphobos/src/std/conv.d @@ -4894,7 +4894,7 @@ if (isOctalLiteral(num)) template octal(alias decimalInteger) if (is(typeof(decimalInteger)) && isIntegral!(typeof(decimalInteger))) { - enum octal = octal!(typeof(decimalInteger))(to!string(decimalInteger)); + enum octal = convertToOctal(decimalInteger); } /// @@ -4910,6 +4910,19 @@ if (is(typeof(decimalInteger)) && isIntegral!(typeof(decimalInteger))) auto d = octal!"0001_200_000"; } +/************************************* + * Convert a decimal integer to an octal integer with the same digits. + * Params: + * i = integer to convert + * Returns: + * octal integer with the same type and same digits + */ +private T convertToOctal(T)(T i) +{ + assert((i % 10) < 8); + return i ? convertToOctal(i / 10) * 8 + i % 10 : 0; +} + /* Takes a string, num, which is an octal literal, and returns its value, in the type T specified. diff --git a/libphobos/src/std/datetime/stopwatch.d b/libphobos/src/std/datetime/stopwatch.d index d8ecf7d..eedc0ea 100644 --- a/libphobos/src/std/datetime/stopwatch.d +++ b/libphobos/src/std/datetime/stopwatch.d @@ -234,7 +234,7 @@ public: /++ - Peek at the amount of time that the the StopWatch has been running. + Peek at the amount of time that the StopWatch has been running. This does not include any time during which the StopWatch was stopped but does include $(I all) of the time that it was running and not just the diff --git a/libphobos/src/std/datetime/timezone.d b/libphobos/src/std/datetime/timezone.d index 28255f4..b238918 100644 --- a/libphobos/src/std/datetime/timezone.d +++ b/libphobos/src/std/datetime/timezone.d @@ -3397,8 +3397,7 @@ struct TZConversions TZConversions parseTZConversions(string windowsZonesXMLText) @safe pure { // This is a bit hacky, since it doesn't properly read XML, but it avoids - // needing to pull in std.xml (which we're theoretically replacing at some - // point anyway). + // needing to pull in an xml parsing module. import std.algorithm.iteration : uniq; import std.algorithm.searching : find; import std.algorithm.sorting : sort; diff --git a/libphobos/src/std/digest/crc.d b/libphobos/src/std/digest/crc.d index 38563b1..b7922bb 100644 --- a/libphobos/src/std/digest/crc.d +++ b/libphobos/src/std/digest/crc.d @@ -555,7 +555,7 @@ ubyte[8] crc64ECMAOf(T...)(T data) } /** - * This is a convenience alias for $(REF digest, std,digest,digest) using the + * This is a convenience alias for $(REF digest, std,digest) using the * CRC64-ISO implementation. * * Params: @@ -611,7 +611,7 @@ alias CRC32Digest = WrapperDigest!CRC32; * OOP API CRC64-ECMA implementation. * See `std.digest` for differences between template and OOP API. * - * This is an alias for $(D $(REF WrapperDigest, std,digest,digest)!CRC64ECMA), + * This is an alias for $(D $(REF WrapperDigest, std,digest)!CRC64ECMA), * see there for more information. */ alias CRC64ECMADigest = WrapperDigest!CRC64ECMA; @@ -620,7 +620,7 @@ alias CRC64ECMADigest = WrapperDigest!CRC64ECMA; * OOP API CRC64-ISO implementation. * See `std.digest` for differences between template and OOP API. * - * This is an alias for $(D $(REF WrapperDigest, std,digest,digest)!CRC64ISO), + * This is an alias for $(D $(REF WrapperDigest, std,digest)!CRC64ISO), * see there for more information. */ alias CRC64ISODigest = WrapperDigest!CRC64ISO; @@ -628,7 +628,7 @@ alias CRC64ISODigest = WrapperDigest!CRC64ISO; /// @safe unittest { - //Simple example, hashing a string using Digest.digest helper function + //Simple example, hashing a string using CRC32Digest.digest helper function auto crc = new CRC32Digest(); ubyte[] hash = crc.digest("abc"); //Let's get a hash string diff --git a/libphobos/src/std/digest/digest.d b/libphobos/src/std/digest/digest.d deleted file mode 100644 index 01fdbd7..0000000 --- a/libphobos/src/std/digest/digest.d +++ /dev/null @@ -1,3 +0,0 @@ -// @@@DEPRECATED_2.101@@@ -deprecated("import std.digest instead of std.digest.digest. std.digest.digest will be removed in 2.101") -module std.digest.digest; diff --git a/libphobos/src/std/experimental/allocator/building_blocks/affix_allocator.d b/libphobos/src/std/experimental/allocator/building_blocks/affix_allocator.d index 1e3df91..d0d0b7c 100644 --- a/libphobos/src/std/experimental/allocator/building_blocks/affix_allocator.d +++ b/libphobos/src/std/experimental/allocator/building_blocks/affix_allocator.d @@ -521,9 +521,9 @@ version (StdUnittest) @system unittest { - import std.experimental.allocator.building_blocks.region : Region; + import std.experimental.allocator.building_blocks.region : BorrowedRegion; - auto a = AffixAllocator!(Region!(), uint)(Region!()(new ubyte[1024 * 64])); + auto a = AffixAllocator!(BorrowedRegion!(), uint)(BorrowedRegion!()(new ubyte[1024 * 64])); auto b = a.allocate(42); assert(b.length == 42); // Test that expand infers from parent diff --git a/libphobos/src/std/experimental/allocator/building_blocks/aligned_block_list.d b/libphobos/src/std/experimental/allocator/building_blocks/aligned_block_list.d index 14c6de4..99768bc 100644 --- a/libphobos/src/std/experimental/allocator/building_blocks/aligned_block_list.d +++ b/libphobos/src/std/experimental/allocator/building_blocks/aligned_block_list.d @@ -526,7 +526,7 @@ shared struct SharedAlignedBlockList(Allocator, ParentAllocator, ulong theAlignm /// @system unittest { - import std.experimental.allocator.building_blocks.region : SharedRegion; + import std.experimental.allocator.building_blocks.region : SharedBorrowedRegion; import std.experimental.allocator.building_blocks.ascending_page_allocator : SharedAscendingPageAllocator; import std.experimental.allocator.building_blocks.null_allocator : NullAllocator; import core.thread : ThreadGroup; @@ -536,11 +536,11 @@ shared struct SharedAlignedBlockList(Allocator, ParentAllocator, ulong theAlignm enum maxIter = 10; /* - In this example we use 'SharedAlignedBlockList' together with 'SharedRegion', - in order to create a fast, thread-safe allocator. + In this example we use 'SharedAlignedBlockList' together with + 'SharedBorrowedRegion', in order to create a fast, thread-safe allocator. */ alias SuperAllocator = SharedAlignedBlockList!( - SharedRegion!(NullAllocator, 1), + SharedBorrowedRegion!(1), SharedAscendingPageAllocator, 4096); @@ -597,7 +597,7 @@ version (StdUnittest) SpinLock lock = SpinLock(SpinLock.Contention.brief); alias SuperAllocator = SharedAlignedBlockList!( - SharedRegion!(NullAllocator, 1), + SharedBorrowedRegion!(1), SharedAscendingPageAllocator, 1 << 16); void[][totalAllocs] buf; diff --git a/libphobos/src/std/experimental/allocator/building_blocks/allocator_list.d b/libphobos/src/std/experimental/allocator/building_blocks/allocator_list.d index bcab16d..ca83785 100644 --- a/libphobos/src/std/experimental/allocator/building_blocks/allocator_list.d +++ b/libphobos/src/std/experimental/allocator/building_blocks/allocator_list.d @@ -679,8 +679,8 @@ version (Posix) @system unittest { // Create an allocator based upon 4MB regions, fetched from the GC heap. import std.algorithm.comparison : max; - import std.experimental.allocator.building_blocks.region : Region; - AllocatorList!((n) => Region!()(new ubyte[max(n, 1024 * 4096)])) a; + import std.experimental.allocator.building_blocks.region : BorrowedRegion; + AllocatorList!((n) => BorrowedRegion!()(new ubyte[max(n, 1024 * 4096)])) a; auto b1 = a.alignedAllocate(1024 * 8192, 1024); assert(b1 !is null); // still works due to overdimensioning assert(b1.length == 1024 * 8192); @@ -707,8 +707,8 @@ version (Posix) @system unittest // Create an allocator based upon 4MB regions, fetched from the GC heap. import std.algorithm.comparison : max; - import std.experimental.allocator.building_blocks.region : Region; - AllocatorList!((n) => Region!()(new ubyte[max(n, 1024 * 4096)])) a; + import std.experimental.allocator.building_blocks.region : BorrowedRegion; + AllocatorList!((n) => BorrowedRegion!()(new ubyte[max(n, 1024 * 4096)])) a; auto b1 = a.alignedAllocate(0, 1); assert(b1 is null); @@ -728,8 +728,8 @@ version (Posix) @system unittest // Create an allocator based upon 4MB regions, fetched from the GC heap. import std.algorithm.comparison : max; - import std.experimental.allocator.building_blocks.region : Region; - AllocatorList!((n) => Region!()(new ubyte[max(n, 1024 * 4096)])) a; + import std.experimental.allocator.building_blocks.region : BorrowedRegion; + AllocatorList!((n) => BorrowedRegion!()(new ubyte[max(n, 1024 * 4096)])) a; auto b0 = a.alignedAllocate(1, 1024); assert(b0.length == 1); assert(b0.ptr.alignedAt(1024)); @@ -765,8 +765,8 @@ version (Posix) @system unittest { // Create an allocator based upon 4MB regions, fetched from the GC heap. import std.algorithm.comparison : max; - import std.experimental.allocator.building_blocks.region : Region; - AllocatorList!((n) => Region!()(new ubyte[max(n, 1024 * 4096)])) a; + import std.experimental.allocator.building_blocks.region : BorrowedRegion; + AllocatorList!((n) => BorrowedRegion!()(new ubyte[max(n, 1024 * 4096)])) a; auto b1 = a.allocate(1024 * 8192); assert(b1 !is null); // still works due to overdimensioning b1 = a.allocate(1024 * 10); @@ -779,10 +779,10 @@ version (Posix) @system unittest @system unittest { import std.algorithm.comparison : max; - import std.experimental.allocator.building_blocks.region : Region; + import std.experimental.allocator.building_blocks.region : BorrowedRegion; import std.experimental.allocator.mallocator : Mallocator; import std.typecons : Ternary; - AllocatorList!((n) => Region!()(new ubyte[max(n, 1024 * 4096)]), Mallocator) a; + AllocatorList!((n) => BorrowedRegion!()(new ubyte[max(n, 1024 * 4096)]), Mallocator) a; auto b1 = a.allocate(1024 * 8192); assert(b1 !is null); b1 = a.allocate(1024 * 10); diff --git a/libphobos/src/std/experimental/allocator/building_blocks/fallback_allocator.d b/libphobos/src/std/experimental/allocator/building_blocks/fallback_allocator.d index b413d73..3990418 100644 --- a/libphobos/src/std/experimental/allocator/building_blocks/fallback_allocator.d +++ b/libphobos/src/std/experimental/allocator/building_blocks/fallback_allocator.d @@ -342,12 +342,12 @@ struct FallbackAllocator(Primary, Fallback) @system unittest { - import std.experimental.allocator.building_blocks.region : Region; + import std.experimental.allocator.building_blocks.region : BorrowedRegion; import std.typecons : Ternary; - auto a = FallbackAllocator!(Region!(), Region!())( - Region!()(new ubyte[4096 * 1024]), - Region!()(new ubyte[4096 * 1024])); + auto a = FallbackAllocator!(BorrowedRegion!(), BorrowedRegion!())( + BorrowedRegion!()(new ubyte[4096 * 1024]), + BorrowedRegion!()(new ubyte[4096 * 1024])); auto b = a.alignedAllocate(42, 8); assert(b.length == 42); @@ -506,11 +506,11 @@ version (StdUnittest) @system unittest { - import std.experimental.allocator.building_blocks.region : Region; + import std.experimental.allocator.building_blocks.region : BorrowedRegion; import std.typecons : Ternary; - alias A = FallbackAllocator!(Region!(), Region!()); - auto a = A(Region!()(new ubyte[16_384]), Region!()(new ubyte[16_384])); + alias A = FallbackAllocator!(BorrowedRegion!(), BorrowedRegion!()); + auto a = A(BorrowedRegion!()(new ubyte[16_384]), BorrowedRegion!()(new ubyte[16_384])); auto b = a.allocate(42); assert(b.length == 42); diff --git a/libphobos/src/std/experimental/allocator/building_blocks/free_list.d b/libphobos/src/std/experimental/allocator/building_blocks/free_list.d index 7055d66..d2b3209 100644 --- a/libphobos/src/std/experimental/allocator/building_blocks/free_list.d +++ b/libphobos/src/std/experimental/allocator/building_blocks/free_list.d @@ -486,9 +486,9 @@ struct FreeList(ParentAllocator, // Test that deallocateAll infers from parent @system unittest { - import std.experimental.allocator.building_blocks.region : Region; + import std.experimental.allocator.building_blocks.region : BorrowedRegion; - auto fl = FreeList!(Region!(), 0, 16)(Region!()(new ubyte[1024 * 64])); + auto fl = FreeList!(BorrowedRegion!(), 0, 16)(BorrowedRegion!()(new ubyte[1024 * 64])); auto b = fl.allocate(42); assert(b.length == 42); assert((() pure nothrow @safe @nogc => fl.expand(b, 48))()); diff --git a/libphobos/src/std/experimental/allocator/building_blocks/free_tree.d b/libphobos/src/std/experimental/allocator/building_blocks/free_tree.d index bd4bb95..fe59e26 100644 --- a/libphobos/src/std/experimental/allocator/building_blocks/free_tree.d +++ b/libphobos/src/std/experimental/allocator/building_blocks/free_tree.d @@ -502,9 +502,9 @@ version (StdUnittest) @system unittest { - import std.experimental.allocator.building_blocks.region : Region; + import std.experimental.allocator.building_blocks.region : BorrowedRegion; - auto a = FreeTree!(Region!())(Region!()(new ubyte[1024 * 64])); + auto a = FreeTree!(BorrowedRegion!())(BorrowedRegion!()(new ubyte[1024 * 64])); auto b = a.allocate(42); assert(b.length == 42); assert((() pure nothrow @safe @nogc => a.expand(b, 22))()); diff --git a/libphobos/src/std/experimental/allocator/building_blocks/quantizer.d b/libphobos/src/std/experimental/allocator/building_blocks/quantizer.d index 762b379..3334a86 100644 --- a/libphobos/src/std/experimental/allocator/building_blocks/quantizer.d +++ b/libphobos/src/std/experimental/allocator/building_blocks/quantizer.d @@ -315,14 +315,14 @@ version (StdUnittest) version (StdUnittest) @system unittest { - import std.experimental.allocator.building_blocks.region : Region; + import std.experimental.allocator.building_blocks.region : BorrowedRegion; import std.typecons : Ternary; - alias MyAlloc = Quantizer!(Region!(), + alias MyAlloc = Quantizer!(BorrowedRegion!(), (size_t n) => n.roundUpToMultipleOf(64)); - testAllocator!(() => MyAlloc(Region!()(new ubyte[1024 * 64]))); + testAllocator!(() => MyAlloc(BorrowedRegion!()(new ubyte[1024 * 64]))); - auto a = MyAlloc(Region!()(new ubyte[1024 * 64])); + auto a = MyAlloc(BorrowedRegion!()(new ubyte[1024 * 64])); // Check that empty inherits from parent assert((() pure nothrow @safe @nogc => a.empty)() == Ternary.yes); auto b = a.allocate(42); diff --git a/libphobos/src/std/experimental/allocator/building_blocks/region.d b/libphobos/src/std/experimental/allocator/building_blocks/region.d index be0d274..8c39784 100644 --- a/libphobos/src/std/experimental/allocator/building_blocks/region.d +++ b/libphobos/src/std/experimental/allocator/building_blocks/region.d @@ -29,8 +29,7 @@ the store and the limits. One allocation entails rounding up the allocation size for alignment purposes, bumping the current pointer, and comparing it against the limit. -If `ParentAllocator` is different from $(REF_ALTTEXT `NullAllocator`, NullAllocator, std,experimental,allocator,building_blocks,null_allocator), `Region` -deallocates the chunk of memory during destruction. +`Region` deallocates the chunk of memory during destruction. The `minAlign` parameter establishes alignment. If $(D minAlign > 1), the sizes of all allocation requests are rounded up to a multiple of `minAlign`. @@ -38,7 +37,7 @@ Applications aiming at maximum speed may want to choose $(D minAlign = 1) and control alignment externally. */ -struct Region(ParentAllocator = NullAllocator, +struct Region(ParentAllocator, uint minAlign = platformAlignment, Flag!"growDownwards" growDownwards = No.growDownwards) { @@ -63,50 +62,42 @@ struct Region(ParentAllocator = NullAllocator, alias parent = ParentAllocator.instance; } - private void* _current, _begin, _end; + private BorrowedRegion!(minAlign, growDownwards) _impl; private void* roundedBegin() const pure nothrow @trusted @nogc { - return cast(void*) roundUpToAlignment(cast(size_t) _begin, alignment); + return _impl.roundedBegin; } private void* roundedEnd() const pure nothrow @trusted @nogc { - return cast(void*) roundDownToAlignment(cast(size_t) _end, alignment); + return _impl.roundedEnd; } /** Constructs a region backed by a user-provided store. - Assumes the memory was allocated with `ParentAllocator` - (if different from $(REF_ALTTEXT `NullAllocator`, NullAllocator, std,experimental,allocator,building_blocks,null_allocator)). + Assumes the memory was allocated with `ParentAllocator`. Params: - store = User-provided store backing up the region. If $(D - ParentAllocator) is different from $(REF_ALTTEXT `NullAllocator`, NullAllocator, std,experimental,allocator,building_blocks,null_allocator), memory is assumed to - have been allocated with `ParentAllocator`. - n = Bytes to allocate using `ParentAllocator`. This constructor is only - defined If `ParentAllocator` is different from $(REF_ALTTEXT `NullAllocator`, NullAllocator, std,experimental,allocator,building_blocks,null_allocator). If - `parent.allocate(n)` returns `null`, the region will be initialized - as empty (correctly initialized but unable to allocate). + store = User-provided store backing up the region. Assumed to have been + allocated with `ParentAllocator`. + n = Bytes to allocate using `ParentAllocator`. If `parent.allocate(n)` + returns `null`, the region will be initialized as empty (correctly + initialized but unable to allocate). */ this(ubyte[] store) pure nothrow @nogc { - _begin = store.ptr; - _end = store.ptr + store.length; - static if (growDownwards) - _current = roundedEnd(); - else - _current = roundedBegin(); + _impl = store; } /// Ditto - static if (!is(ParentAllocator == NullAllocator) && !stateSize!ParentAllocator) + static if (!stateSize!ParentAllocator) this(size_t n) { this(cast(ubyte[]) (parent.allocate(n.roundUpToAlignment(alignment)))); } /// Ditto - static if (!is(ParentAllocator == NullAllocator) && stateSize!ParentAllocator) + static if (stateSize!ParentAllocator) this(ParentAllocator parent, size_t n) { this.parent = parent; @@ -119,18 +110,299 @@ struct Region(ParentAllocator = NullAllocator, */ /** - If `ParentAllocator` is not $(REF_ALTTEXT `NullAllocator`, NullAllocator, std,experimental,allocator,building_blocks,null_allocator) and defines `deallocate`, - the region defines a destructor that uses `ParentAllocator.deallocate` to free the - memory chunk. + If `ParentAllocator` defines `deallocate`, the region defines a destructor + that uses `ParentAllocator.deallocate` to free the memory chunk. */ - static if (!is(ParentAllocator == NullAllocator) - && hasMember!(ParentAllocator, "deallocate")) + static if (hasMember!(ParentAllocator, "deallocate")) ~this() { - parent.deallocate(_begin[0 .. _end - _begin]); + with (_impl) parent.deallocate(_begin[0 .. _end - _begin]); + } + + /** + Rounds the given size to a multiple of the `alignment` + */ + size_t goodAllocSize(size_t n) const pure nothrow @safe @nogc + { + return _impl.goodAllocSize(n); + } + + /** + Alignment offered. + */ + alias alignment = minAlign; + + /** + Allocates `n` bytes of memory. The shortest path involves an alignment + adjustment (if $(D alignment > 1)), an increment, and a comparison. + + Params: + n = number of bytes to allocate + + Returns: + A properly-aligned buffer of size `n` or `null` if request could not + be satisfied. + */ + void[] allocate(size_t n) pure nothrow @trusted @nogc + { + return _impl.allocate(n); + } + + /** + Allocates `n` bytes of memory aligned at alignment `a`. + + Params: + n = number of bytes to allocate + a = alignment for the allocated block + + Returns: + Either a suitable block of `n` bytes aligned at `a`, or `null`. + */ + void[] alignedAllocate(size_t n, uint a) pure nothrow @trusted @nogc + { + return _impl.alignedAllocate(n, a); + } + + /// Allocates and returns all memory available to this region. + void[] allocateAll() pure nothrow @trusted @nogc + { + return _impl.allocateAll; + } + + /** + Expands an allocated block in place. Expansion will succeed only if the + block is the last allocated. Defined only if `growDownwards` is + `No.growDownwards`. + */ + static if (growDownwards == No.growDownwards) + bool expand(ref void[] b, size_t delta) pure nothrow @safe @nogc + { + return _impl.expand(b, delta); + } + + /** + Deallocates `b`. This works only if `b` was obtained as the last call + to `allocate`; otherwise (i.e. another allocation has occurred since) it + does nothing. + + Params: + b = Block previously obtained by a call to `allocate` against this + allocator (`null` is allowed). + */ + bool deallocate(void[] b) pure nothrow @nogc + { + return _impl.deallocate(b); + } + + /** + Deallocates all memory allocated by this region, which can be subsequently + reused for new allocations. + */ + bool deallocateAll() pure nothrow @nogc + { + return _impl.deallocateAll; + } + + /** + Queries whether `b` has been allocated with this region. + + Params: + b = Arbitrary block of memory (`null` is allowed; `owns(null)` returns + `false`). + + Returns: + `true` if `b` has been allocated with this region, `false` otherwise. + */ + Ternary owns(const void[] b) const pure nothrow @trusted @nogc + { + return _impl.owns(b); + } + + /** + Returns `Ternary.yes` if no memory has been allocated in this region, + `Ternary.no` otherwise. (Never returns `Ternary.unknown`.) + */ + Ternary empty() const pure nothrow @safe @nogc + { + return _impl.empty; + } + + /// Nonstandard property that returns bytes available for allocation. + size_t available() const @safe pure nothrow @nogc + { + return _impl.available; + } +} + +/// +@system nothrow unittest +{ + import std.algorithm.comparison : max; + import std.experimental.allocator.building_blocks.allocator_list + : AllocatorList; + import std.experimental.allocator.mallocator : Mallocator; + import std.typecons : Ternary; + // Create a scalable list of regions. Each gets at least 1MB at a time by + // using malloc. + auto batchAllocator = AllocatorList!( + (size_t n) => Region!Mallocator(max(n, 1024 * 1024)) + )(); + assert(batchAllocator.empty == Ternary.yes); + auto b = batchAllocator.allocate(101); + assert(b.length == 101); + assert(batchAllocator.empty == Ternary.no); + // This will cause a second allocation + b = batchAllocator.allocate(2 * 1024 * 1024); + assert(b.length == 2 * 1024 * 1024); + // Destructor will free the memory +} + +@system nothrow @nogc unittest +{ + import std.experimental.allocator.mallocator : Mallocator; + import std.typecons : Ternary; + + static void testAlloc(Allocator)(ref Allocator a) + { + assert((() pure nothrow @safe @nogc => a.empty)() == Ternary.yes); + const b = a.allocate(101); + assert(b.length == 101); + assert((() nothrow @safe @nogc => a.owns(b))() == Ternary.yes); + + // Ensure deallocate inherits from parent allocators + auto c = a.allocate(42); + assert(c.length == 42); + assert((() nothrow @nogc => a.deallocate(c))()); + assert((() pure nothrow @safe @nogc => a.empty)() == Ternary.no); + } + + // Create a 64 KB region allocated with malloc + auto reg = Region!(Mallocator, Mallocator.alignment, + Yes.growDownwards)(1024 * 64); + testAlloc(reg); + + // Create a 64 KB shared region allocated with malloc + auto sharedReg = SharedRegion!(Mallocator, Mallocator.alignment, + Yes.growDownwards)(1024 * 64); + testAlloc(sharedReg); +} + +@system nothrow @nogc unittest +{ + // test 'this(ubyte[] store)' constructed regions properly clean up + // their inner storage after destruction + import std.experimental.allocator.mallocator : Mallocator; + + static shared struct LocalAllocator + { + nothrow @nogc: + enum alignment = Mallocator.alignment; + void[] buf; + bool deallocate(void[] b) + { + assert(buf.ptr == b.ptr && buf.length == b.length); + return true; + } + + void[] allocate(size_t n) + { + return null; + } + + } + + enum bufLen = 10 * Mallocator.alignment; + void[] tmp = Mallocator.instance.allocate(bufLen); + + LocalAllocator a; + a.buf = cast(typeof(a.buf)) tmp[1 .. $]; + + auto reg = Region!(LocalAllocator, Mallocator.alignment, + Yes.growDownwards)(cast(ubyte[]) a.buf); + auto sharedReg = SharedRegion!(LocalAllocator, Mallocator.alignment, + Yes.growDownwards)(cast(ubyte[]) a.buf); + reg.parent = a; + sharedReg.parent = a; + + Mallocator.instance.deallocate(tmp); +} + +version (StdUnittest) +@system unittest +{ + import std.experimental.allocator.mallocator : Mallocator; + + testAllocator!(() => Region!(Mallocator)(1024 * 64)); + testAllocator!(() => Region!(Mallocator, Mallocator.alignment, Yes.growDownwards)(1024 * 64)); + + testAllocator!(() => SharedRegion!(Mallocator)(1024 * 64)); + testAllocator!(() => SharedRegion!(Mallocator, Mallocator.alignment, Yes.growDownwards)(1024 * 64)); +} + +@system nothrow @nogc unittest +{ + import std.experimental.allocator.mallocator : Mallocator; + + auto reg = Region!(Mallocator)(1024 * 64); + auto b = reg.allocate(101); + assert(b.length == 101); + assert((() pure nothrow @safe @nogc => reg.expand(b, 20))()); + assert((() pure nothrow @safe @nogc => reg.expand(b, 73))()); + assert((() pure nothrow @safe @nogc => !reg.expand(b, 1024 * 64))()); + assert((() nothrow @nogc => reg.deallocateAll())()); +} + +/** +A `BorrowedRegion` allocates directly from a user-provided block of memory. + +Unlike a `Region`, a `BorrowedRegion` does not own the memory it allocates from +and will not deallocate that memory upon destruction. Instead, it is the user's +responsibility to ensure that the memory is properly disposed of. + +In all other respects, a `BorrowedRegion` behaves exactly like a `Region`. +*/ +struct BorrowedRegion(uint minAlign = platformAlignment, + Flag!"growDownwards" growDownwards = No.growDownwards) +{ + static assert(minAlign.isGoodStaticAlignment); + + import std.typecons : Ternary; + + // state + private void* _current, _begin, _end; + + private void* roundedBegin() const pure nothrow @trusted @nogc + { + return cast(void*) roundUpToAlignment(cast(size_t) _begin, alignment); + } + + private void* roundedEnd() const pure nothrow @trusted @nogc + { + return cast(void*) roundDownToAlignment(cast(size_t) _end, alignment); } /** + Constructs a region backed by a user-provided store. + + Params: + store = User-provided store backing up the region. + */ + this(ubyte[] store) pure nothrow @nogc + { + _begin = store.ptr; + _end = store.ptr + store.length; + static if (growDownwards) + _current = roundedEnd(); + else + _current = roundedBegin(); + } + + /* + TODO: The postblit of `BorrowedRegion` should be disabled because such objects + should not be copied around naively. + */ + + /** Rounds the given size to a multiple of the `alignment` */ size_t goodAllocSize(size_t n) const pure nothrow @safe @nogc @@ -362,56 +634,32 @@ struct Region(ParentAllocator = NullAllocator, } /// -@system nothrow unittest -{ - import std.algorithm.comparison : max; - import std.experimental.allocator.building_blocks.allocator_list - : AllocatorList; - import std.experimental.allocator.mallocator : Mallocator; - import std.typecons : Ternary; - // Create a scalable list of regions. Each gets at least 1MB at a time by - // using malloc. - auto batchAllocator = AllocatorList!( - (size_t n) => Region!Mallocator(max(n, 1024 * 1024)) - )(); - assert(batchAllocator.empty == Ternary.yes); - auto b = batchAllocator.allocate(101); - assert(b.length == 101); - assert(batchAllocator.empty == Ternary.no); - // This will cause a second allocation - b = batchAllocator.allocate(2 * 1024 * 1024); - assert(b.length == 2 * 1024 * 1024); - // Destructor will free the memory -} - @system nothrow @nogc unittest { - import std.experimental.allocator.mallocator : Mallocator; import std.typecons : Ternary; - static void testAlloc(Allocator)(ref Allocator a) - { - assert((() pure nothrow @safe @nogc => a.empty)() == Ternary.yes); - const b = a.allocate(101); - assert(b.length == 101); - assert((() nothrow @safe @nogc => a.owns(b))() == Ternary.yes); + ubyte[1024] store; + auto myRegion = BorrowedRegion!(1)(store[]); - // Ensure deallocate inherits from parent allocators - auto c = a.allocate(42); - assert(c.length == 42); - assert((() nothrow @nogc => a.deallocate(c))()); - assert((() pure nothrow @safe @nogc => a.empty)() == Ternary.no); - } + assert(myRegion.empty == Ternary.yes); + assert(myRegion.available == store.length); - // Create a 64 KB region allocated with malloc - auto reg = Region!(Mallocator, Mallocator.alignment, - Yes.growDownwards)(1024 * 64); - testAlloc(reg); + void[] b = myRegion.allocate(101); - // Create a 64 KB shared region allocated with malloc - auto sharedReg = SharedRegion!(Mallocator, Mallocator.alignment, - Yes.growDownwards)(1024 * 64); - testAlloc(sharedReg); + assert(b.length == 101); + assert(myRegion.empty == Ternary.no); + assert(myRegion.owns(b) == Ternary.yes); + assert(myRegion.available == store.length - b.length); + + void[] b2 = myRegion.allocate(256); + + // Can only free the most recent allocation + assert(myRegion.deallocate(b) == false); + assert(myRegion.deallocate(b2) == true); + + myRegion.deallocateAll(); + + assert(myRegion.empty == Ternary.yes); } @system nothrow @nogc unittest @@ -420,76 +668,11 @@ struct Region(ParentAllocator = NullAllocator, import std.typecons : Ternary; ubyte[] buf = cast(ubyte[]) AlignedMallocator.instance.alignedAllocate(64, 64); - auto reg = Region!(NullAllocator, 64, Yes.growDownwards)(buf); + auto reg = BorrowedRegion!(64, Yes.growDownwards)(buf); assert(reg.alignedAllocate(10, 32).length == 10); assert(!reg.available); } -@system nothrow @nogc unittest -{ - // test 'this(ubyte[] store)' constructed regions properly clean up - // their inner storage after destruction - import std.experimental.allocator.mallocator : Mallocator; - - static shared struct LocalAllocator - { - nothrow @nogc: - enum alignment = Mallocator.alignment; - void[] buf; - bool deallocate(void[] b) - { - assert(buf.ptr == b.ptr && buf.length == b.length); - return true; - } - - void[] allocate(size_t n) - { - return null; - } - - } - - enum bufLen = 10 * Mallocator.alignment; - void[] tmp = Mallocator.instance.allocate(bufLen); - - LocalAllocator a; - a.buf = cast(typeof(a.buf)) tmp[1 .. $]; - - auto reg = Region!(LocalAllocator, Mallocator.alignment, - Yes.growDownwards)(cast(ubyte[]) a.buf); - auto sharedReg = SharedRegion!(LocalAllocator, Mallocator.alignment, - Yes.growDownwards)(cast(ubyte[]) a.buf); - reg.parent = a; - sharedReg.parent = a; - - Mallocator.instance.deallocate(tmp); -} - -version (StdUnittest) -@system unittest -{ - import std.experimental.allocator.mallocator : Mallocator; - - testAllocator!(() => Region!(Mallocator)(1024 * 64)); - testAllocator!(() => Region!(Mallocator, Mallocator.alignment, Yes.growDownwards)(1024 * 64)); - - testAllocator!(() => SharedRegion!(Mallocator)(1024 * 64)); - testAllocator!(() => SharedRegion!(Mallocator, Mallocator.alignment, Yes.growDownwards)(1024 * 64)); -} - -@system nothrow @nogc unittest -{ - import std.experimental.allocator.mallocator : Mallocator; - - auto reg = Region!(Mallocator)(1024 * 64); - auto b = reg.allocate(101); - assert(b.length == 101); - assert((() pure nothrow @safe @nogc => reg.expand(b, 20))()); - assert((() pure nothrow @safe @nogc => reg.expand(b, 73))()); - assert((() pure nothrow @safe @nogc => !reg.expand(b, 1024 * 64))()); - assert((() nothrow @nogc => reg.deallocateAll())()); -} - /** `InSituRegion` is a convenient region that carries its storage within itself @@ -535,7 +718,7 @@ struct InSituRegion(size_t size, size_t minAlign = platformAlignment) @disable this(this); // state { - private Region!(NullAllocator, minAlign, growDownwards) _impl; + private BorrowedRegion!(minAlign, growDownwards) _impl; union { private ubyte[size] _store = void; @@ -992,7 +1175,7 @@ version (Posix) @system nothrow @nogc unittest The threadsafe version of the `Region` allocator. Allocations and deallocations are lock-free based using $(REF cas, core,atomic). */ -shared struct SharedRegion(ParentAllocator = NullAllocator, +shared struct SharedRegion(ParentAllocator, uint minAlign = platformAlignment, Flag!"growDownwards" growDownwards = No.growDownwards) { @@ -1016,45 +1199,36 @@ shared struct SharedRegion(ParentAllocator = NullAllocator, { alias parent = ParentAllocator.instance; } - private shared void* _current, _begin, _end; + private shared SharedBorrowedRegion!(minAlign, growDownwards) _impl; private void* roundedBegin() const pure nothrow @trusted @nogc { - return cast(void*) roundUpToAlignment(cast(size_t) _begin, alignment); + return _impl.roundedBegin; } private void* roundedEnd() const pure nothrow @trusted @nogc { - return cast(void*) roundDownToAlignment(cast(size_t) _end, alignment); + return _impl.roundedEnd; } /** Constructs a region backed by a user-provided store. - Assumes the memory was allocated with `ParentAllocator` - (if different from $(REF_ALTTEXT `NullAllocator`, NullAllocator, std,experimental,allocator,building_blocks,null_allocator)). + Assumes the memory was allocated with `ParentAllocator`. Params: - store = User-provided store backing up the region. If `ParentAllocator` - is different from $(REF_ALTTEXT `NullAllocator`, NullAllocator, std,experimental,allocator,building_blocks,null_allocator), memory is assumed to - have been allocated with `ParentAllocator`. - n = Bytes to allocate using `ParentAllocator`. This constructor is only - defined If `ParentAllocator` is different from $(REF_ALTTEXT `NullAllocator`, NullAllocator, std,experimental,allocator,building_blocks,null_allocator). If - `parent.allocate(n)` returns `null`, the region will be initialized - as empty (correctly initialized but unable to allocate). + store = User-provided store backing up the region. Assumed to have been + allocated with `ParentAllocator`. + n = Bytes to allocate using `ParentAllocator`. If `parent.allocate(n)` + returns `null`, the region will be initialized as empty (correctly + initialized but unable to allocate). */ this(ubyte[] store) pure nothrow @nogc { - _begin = cast(typeof(_begin)) store.ptr; - _end = cast(typeof(_end)) (store.ptr + store.length); - static if (growDownwards) - _current = cast(typeof(_current)) roundedEnd(); - else - _current = cast(typeof(_current)) roundedBegin(); + _impl = store; } /// Ditto - static if (!is(ParentAllocator == NullAllocator)) this(size_t n) { this(cast(ubyte[]) (parent.allocate(n.roundUpToAlignment(alignment)))); @@ -1065,7 +1239,7 @@ shared struct SharedRegion(ParentAllocator = NullAllocator, */ size_t goodAllocSize(size_t n) const pure nothrow @safe @nogc { - return n.roundUpToAlignment(alignment); + return _impl.goodAllocSize(n); } /** @@ -1086,38 +1260,7 @@ shared struct SharedRegion(ParentAllocator = NullAllocator, */ void[] allocate(size_t n) pure nothrow @trusted @nogc { - import core.atomic : cas, atomicLoad; - - if (n == 0) return null; - const rounded = goodAllocSize(n); - - shared void* localCurrent, localNewCurrent; - static if (growDownwards) - { - do - { - localCurrent = atomicLoad(_current); - localNewCurrent = localCurrent - rounded; - if (localNewCurrent > localCurrent || localNewCurrent < _begin) - return null; - } while (!cas(&_current, localCurrent, localNewCurrent)); - - return cast(void[]) localNewCurrent[0 .. n]; - } - else - { - do - { - localCurrent = atomicLoad(_current); - localNewCurrent = localCurrent + rounded; - if (localNewCurrent < localCurrent || localNewCurrent > _end) - return null; - } while (!cas(&_current, localCurrent, localNewCurrent)); - - return cast(void[]) localCurrent[0 .. n]; - } - - assert(0, "Unexpected error in SharedRegion.allocate"); + return _impl.allocate(n); } /** @@ -1131,27 +1274,7 @@ shared struct SharedRegion(ParentAllocator = NullAllocator, */ bool deallocate(void[] b) pure nothrow @nogc { - import core.atomic : cas, atomicLoad; - - const rounded = goodAllocSize(b.length); - shared void* localCurrent, localNewCurrent; - - // The cas is done only once, because only the last allocation can be reverted - localCurrent = atomicLoad(_current); - static if (growDownwards) - { - localNewCurrent = localCurrent + rounded; - if (b.ptr == localCurrent) - return cas(&_current, localCurrent, localNewCurrent); - } - else - { - localNewCurrent = localCurrent - rounded; - if (b.ptr == localNewCurrent) - return cas(&_current, localCurrent, localNewCurrent); - } - - return false; + return _impl.deallocate(b); } /** @@ -1160,16 +1283,7 @@ shared struct SharedRegion(ParentAllocator = NullAllocator, */ bool deallocateAll() pure nothrow @nogc { - import core.atomic : atomicStore; - static if (growDownwards) - { - atomicStore(_current, cast(shared(void*)) roundedEnd()); - } - else - { - atomicStore(_current, cast(shared(void*)) roundedBegin()); - } - return true; + return _impl.deallocateAll; } /** @@ -1183,45 +1297,7 @@ shared struct SharedRegion(ParentAllocator = NullAllocator, */ void[] alignedAllocate(size_t n, uint a) pure nothrow @trusted @nogc { - import core.atomic : cas, atomicLoad; - import std.math.traits : isPowerOf2; - - assert(a.isPowerOf2); - if (n == 0) return null; - - const rounded = goodAllocSize(n); - shared void* localCurrent, localNewCurrent; - - static if (growDownwards) - { - do - { - localCurrent = atomicLoad(_current); - auto alignedCurrent = cast(void*)(localCurrent - rounded); - localNewCurrent = cast(shared(void*)) alignedCurrent.alignDownTo(a); - if (alignedCurrent > localCurrent || localNewCurrent > alignedCurrent || - localNewCurrent < _begin) - return null; - } while (!cas(&_current, localCurrent, localNewCurrent)); - - return cast(void[]) localNewCurrent[0 .. n]; - } - else - { - do - { - localCurrent = atomicLoad(_current); - auto alignedCurrent = alignUpTo(cast(void*) localCurrent, a); - localNewCurrent = cast(shared(void*)) (alignedCurrent + rounded); - if (alignedCurrent < localCurrent || localNewCurrent < alignedCurrent || - localNewCurrent > _end) - return null; - } while (!cas(&_current, localCurrent, localNewCurrent)); - - return cast(void[]) (localNewCurrent - rounded)[0 .. n]; - } - - assert(0, "Unexpected error in SharedRegion.alignedAllocate"); + return _impl.alignedAllocate(n, a); } /** @@ -1236,7 +1312,7 @@ shared struct SharedRegion(ParentAllocator = NullAllocator, */ Ternary owns(const void[] b) const pure nothrow @trusted @nogc { - return Ternary(b && (&b[0] >= _begin) && (&b[0] + b.length <= _end)); + return _impl.owns(b); } /** @@ -1245,25 +1321,17 @@ shared struct SharedRegion(ParentAllocator = NullAllocator, */ Ternary empty() const pure nothrow @safe @nogc { - import core.atomic : atomicLoad; - - auto localCurrent = atomicLoad(_current); - static if (growDownwards) - return Ternary(localCurrent == roundedEnd()); - else - return Ternary(localCurrent == roundedBegin()); + return _impl.empty; } /** - If `ParentAllocator` is not $(REF_ALTTEXT `NullAllocator`, NullAllocator, std,experimental,allocator,building_blocks,null_allocator) and defines `deallocate`, - the region defines a destructor that uses `ParentAllocator.deallocate` to free the - memory chunk. + If `ParentAllocator` defines `deallocate`, the region defines a destructor + that uses `ParentAllocator.deallocate` to free the memory chunk. */ - static if (!is(ParentAllocator == NullAllocator) - && hasMember!(ParentAllocator, "deallocate")) + static if (hasMember!(ParentAllocator, "deallocate")) ~this() { - parent.deallocate(cast(void[]) _begin[0 .. _end - _begin]); + with (_impl) parent.deallocate(cast(void[]) _begin[0 .. _end - _begin]); } } @@ -1397,3 +1465,250 @@ shared struct SharedRegion(ParentAllocator = NullAllocator, testAlloc(a1, true); testAlloc(a2, false); } + +/** +A `SharedBorrowedRegion` allocates directly from a user-provided block of memory. + +Unlike a `SharedRegion`, a `SharedBorrowedRegion` does not own the memory it +allocates from and will not deallocate that memory upon destruction. Instead, +it is the user's responsibility to ensure that the memory is properly disposed +of. + +In all other respects, a `SharedBorrowedRegion` behaves exactly like a `SharedRegion`. +*/ +shared struct SharedBorrowedRegion(uint minAlign = platformAlignment, + Flag!"growDownwards" growDownwards = No.growDownwards) +{ + static assert(minAlign.isGoodStaticAlignment); + + import std.typecons : Ternary; + + // state + private void* _current, _begin, _end; + + private void* roundedBegin() shared const pure nothrow @trusted @nogc + { + return cast(void*) roundUpToAlignment(cast(size_t) _begin, alignment); + } + + private void* roundedEnd() shared const pure nothrow @trusted @nogc + { + return cast(void*) roundDownToAlignment(cast(size_t) _end, alignment); + } + + /** + Constructs a region backed by a user-provided store. + + Params: + store = User-provided store backing up the region. Must not be aliased. + */ + this(ubyte[] store) shared pure nothrow @nogc + { + _begin = cast(typeof(_begin)) store.ptr; + _end = cast(typeof(_end)) (store.ptr + store.length); + static if (growDownwards) + _current = cast(typeof(_current)) roundedEnd(); + else + _current = cast(typeof(_current)) roundedBegin(); + } + + /* + TODO: The postblit of `SharedBorrowedRegion` should be disabled because + such objects should not be copied around naively. + */ + + /** + Rounds the given size to a multiple of the `alignment` + */ + size_t goodAllocSize(size_t n) shared const pure nothrow @safe @nogc + { + return n.roundUpToAlignment(alignment); + } + + /** + Alignment offered. + */ + alias alignment = minAlign; + + /** + Allocates `n` bytes of memory. The allocation is served by atomically incrementing + a pointer which keeps track of the current used space. + + Params: + n = number of bytes to allocate + + Returns: + A properly-aligned buffer of size `n`, or `null` if request could not + be satisfied. + */ + void[] allocate(size_t n) shared pure nothrow @trusted @nogc + { + import core.atomic : cas, atomicLoad; + + if (n == 0) return null; + const rounded = goodAllocSize(n); + + shared void* localCurrent, localNewCurrent; + static if (growDownwards) + { + do + { + localCurrent = atomicLoad(_current); + localNewCurrent = localCurrent - rounded; + if (localNewCurrent > localCurrent || localNewCurrent < _begin) + return null; + } while (!cas(&_current, localCurrent, localNewCurrent)); + + return cast(void[]) localNewCurrent[0 .. n]; + } + else + { + do + { + localCurrent = atomicLoad(_current); + localNewCurrent = localCurrent + rounded; + if (localNewCurrent < localCurrent || localNewCurrent > _end) + return null; + } while (!cas(&_current, localCurrent, localNewCurrent)); + + return cast(void[]) localCurrent[0 .. n]; + } + + assert(0, "Unexpected error in SharedBorrowedRegion.allocate"); + } + + /** + Allocates `n` bytes of memory aligned at alignment `a`. + + Params: + n = number of bytes to allocate + a = alignment for the allocated block + + Returns: + Either a suitable block of `n` bytes aligned at `a`, or `null`. + */ + void[] alignedAllocate(size_t n, uint a) shared pure nothrow @trusted @nogc + { + import core.atomic : cas, atomicLoad; + import std.math.traits : isPowerOf2; + + assert(a.isPowerOf2); + if (n == 0) return null; + + const rounded = goodAllocSize(n); + shared void* localCurrent, localNewCurrent; + + static if (growDownwards) + { + do + { + localCurrent = atomicLoad(_current); + auto alignedCurrent = cast(void*)(localCurrent - rounded); + localNewCurrent = cast(shared(void*)) alignedCurrent.alignDownTo(a); + if (alignedCurrent > localCurrent || localNewCurrent > alignedCurrent || + localNewCurrent < _begin) + return null; + } while (!cas(&_current, localCurrent, localNewCurrent)); + + return cast(void[]) localNewCurrent[0 .. n]; + } + else + { + do + { + localCurrent = atomicLoad(_current); + auto alignedCurrent = alignUpTo(cast(void*) localCurrent, a); + localNewCurrent = cast(shared(void*)) (alignedCurrent + rounded); + if (alignedCurrent < localCurrent || localNewCurrent < alignedCurrent || + localNewCurrent > _end) + return null; + } while (!cas(&_current, localCurrent, localNewCurrent)); + + return cast(void[]) (localNewCurrent - rounded)[0 .. n]; + } + + assert(0, "Unexpected error in SharedBorrowedRegion.alignedAllocate"); + } + + /** + Deallocates `b`. This works only if `b` was obtained as the last call + to `allocate`; otherwise (i.e. another allocation has occurred since) it + does nothing. + + Params: + b = Block previously obtained by a call to `allocate` against this + allocator (`null` is allowed). + */ + bool deallocate(void[] b) shared pure nothrow @nogc + { + import core.atomic : cas, atomicLoad; + + const rounded = goodAllocSize(b.length); + shared void* localCurrent, localNewCurrent; + + // The cas is done only once, because only the last allocation can be reverted + localCurrent = atomicLoad(_current); + static if (growDownwards) + { + localNewCurrent = localCurrent + rounded; + if (b.ptr == localCurrent) + return cas(&_current, localCurrent, localNewCurrent); + } + else + { + localNewCurrent = localCurrent - rounded; + if (b.ptr == localNewCurrent) + return cas(&_current, localCurrent, localNewCurrent); + } + + return false; + } + + /** + Deallocates all memory allocated by this region, which can be subsequently + reused for new allocations. + */ + bool deallocateAll() shared pure nothrow @nogc + { + import core.atomic : atomicStore; + static if (growDownwards) + { + atomicStore(_current, cast(shared(void*)) roundedEnd()); + } + else + { + atomicStore(_current, cast(shared(void*)) roundedBegin()); + } + return true; + } + + /** + Queries whether `b` has been allocated with this region. + + Params: + b = Arbitrary block of memory (`null` is allowed; `owns(null)` returns + `false`). + + Returns: + `true` if `b` has been allocated with this region, `false` otherwise. + */ + Ternary owns(const void[] b) shared const pure nothrow @trusted @nogc + { + return Ternary(b && (&b[0] >= _begin) && (&b[0] + b.length <= _end)); + } + + /** + Returns `Ternary.yes` if no memory has been allocated in this region, + `Ternary.no` otherwise. (Never returns `Ternary.unknown`.) + */ + Ternary empty() shared const pure nothrow @safe @nogc + { + import core.atomic : atomicLoad; + + auto localCurrent = atomicLoad(_current); + static if (growDownwards) + return Ternary(localCurrent == roundedEnd()); + else + return Ternary(localCurrent == roundedBegin()); + } +} diff --git a/libphobos/src/std/experimental/allocator/building_blocks/scoped_allocator.d b/libphobos/src/std/experimental/allocator/building_blocks/scoped_allocator.d index 8fc7584..96859b0 100644 --- a/libphobos/src/std/experimental/allocator/building_blocks/scoped_allocator.d +++ b/libphobos/src/std/experimental/allocator/building_blocks/scoped_allocator.d @@ -259,10 +259,10 @@ version (StdUnittest) // Test that deallocateAll infers from parent @system unittest { - import std.experimental.allocator.building_blocks.region : Region; + import std.experimental.allocator.building_blocks.region : BorrowedRegion; - ScopedAllocator!(Region!()) a; - a.parent.parent = Region!()(new ubyte[1024 * 64]); + ScopedAllocator!(BorrowedRegion!()) a; + a.parent.parent = BorrowedRegion!()(new ubyte[1024 * 64]); auto b = a.allocate(42); assert(b.length == 42); assert((() pure nothrow @safe @nogc => a.expand(b, 22))()); diff --git a/libphobos/src/std/experimental/allocator/building_blocks/segregator.d b/libphobos/src/std/experimental/allocator/building_blocks/segregator.d index 655db456..ff089bd 100644 --- a/libphobos/src/std/experimental/allocator/building_blocks/segregator.d +++ b/libphobos/src/std/experimental/allocator/building_blocks/segregator.d @@ -503,12 +503,12 @@ if (Args.length > 3) @system unittest { - import std.experimental.allocator.building_blocks.region : Region; + import std.experimental.allocator.building_blocks.region : BorrowedRegion; import std.typecons : Ternary; - auto a = Segregator!(10_240, Region!(), Region!())( - Region!()(new ubyte[4096 * 1024]), - Region!()(new ubyte[4096 * 1024])); + auto a = Segregator!(10_240, BorrowedRegion!(), BorrowedRegion!())( + BorrowedRegion!()(new ubyte[4096 * 1024]), + BorrowedRegion!()(new ubyte[4096 * 1024])); assert((() nothrow @safe @nogc => a.empty)() == Ternary.yes); auto b = a.alignedAllocate(42, 8); diff --git a/libphobos/src/std/experimental/allocator/building_blocks/stats_collector.d b/libphobos/src/std/experimental/allocator/building_blocks/stats_collector.d index d57b3ed..3770af1 100644 --- a/libphobos/src/std/experimental/allocator/building_blocks/stats_collector.d +++ b/libphobos/src/std/experimental/allocator/building_blocks/stats_collector.d @@ -845,9 +845,9 @@ public: @system unittest { - import std.experimental.allocator.building_blocks.region : Region; + import std.experimental.allocator.building_blocks.region : BorrowedRegion; - auto a = StatsCollector!(Region!(), Options.all, Options.all)(Region!()(new ubyte[1024 * 64])); + auto a = StatsCollector!(BorrowedRegion!(), Options.all, Options.all)(BorrowedRegion!()(new ubyte[1024 * 64])); auto b = a.allocate(42); assert(b.length == 42); // Test that reallocate infers from parent @@ -859,9 +859,9 @@ public: @system unittest { - import std.experimental.allocator.building_blocks.region : Region; + import std.experimental.allocator.building_blocks.region : BorrowedRegion; - auto a = StatsCollector!(Region!(), Options.all)(Region!()(new ubyte[1024 * 64])); + auto a = StatsCollector!(BorrowedRegion!(), Options.all)(BorrowedRegion!()(new ubyte[1024 * 64])); auto b = a.alignedAllocate(42, 128); assert(b.length == 42); assert(b.ptr.alignedAt(128)); diff --git a/libphobos/src/std/experimental/allocator/package.d b/libphobos/src/std/experimental/allocator/package.d index 62f848f..2177926 100644 --- a/libphobos/src/std/experimental/allocator/package.d +++ b/libphobos/src/std/experimental/allocator/package.d @@ -547,24 +547,24 @@ nothrow: @system unittest { - import std.experimental.allocator.building_blocks.region : Region; + import std.experimental.allocator.building_blocks.region : BorrowedRegion; import std.conv : emplace; - auto reg = Region!()(new ubyte[1024]); - auto state = reg.allocate(stateSize!(CAllocatorImpl!(Region!(), Yes.indirect))); - auto regObj = emplace!(CAllocatorImpl!(Region!(), Yes.indirect))(state, ®); + auto reg = BorrowedRegion!()(new ubyte[1024]); + auto state = reg.allocate(stateSize!(CAllocatorImpl!(BorrowedRegion!(), Yes.indirect))); + auto regObj = emplace!(CAllocatorImpl!(BorrowedRegion!(), Yes.indirect))(state, ®); auto rcalloc = RCIAllocator(regObj); auto b = rcalloc.allocate(10); assert(b.length == 10); // The reference counting is zero based - assert((cast(CAllocatorImpl!(Region!(), Yes.indirect))(rcalloc._alloc)).rc == 1); + assert((cast(CAllocatorImpl!(BorrowedRegion!(), Yes.indirect))(rcalloc._alloc)).rc == 1); { auto rca2 = rcalloc; - assert((cast(CAllocatorImpl!(Region!(), Yes.indirect))(rcalloc._alloc)).rc == 2); + assert((cast(CAllocatorImpl!(BorrowedRegion!(), Yes.indirect))(rcalloc._alloc)).rc == 2); } - assert((cast(CAllocatorImpl!(Region!(), Yes.indirect))(rcalloc._alloc)).rc == 1); + assert((cast(CAllocatorImpl!(BorrowedRegion!(), Yes.indirect))(rcalloc._alloc)).rc == 1); } @system unittest diff --git a/libphobos/src/std/file.d b/libphobos/src/std/file.d index d6cac41..8957089 100644 --- a/libphobos/src/std/file.d +++ b/libphobos/src/std/file.d @@ -3714,7 +3714,7 @@ assert(!de2.isFile); @property bool isSymlink() scope; /++ - Returns the size of the the file represented by this `DirEntry` + Returns the size of the file represented by this `DirEntry` in bytes. +/ @property ulong size() scope; diff --git a/libphobos/src/std/format/package.d b/libphobos/src/std/format/package.d index 3f6f33a..d83f028 100644 --- a/libphobos/src/std/format/package.d +++ b/libphobos/src/std/format/package.d @@ -550,7 +550,7 @@ License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(HTTP walterbright.com, Walter Bright), $(HTTP erdani.com, Andrei Alexandrescu), and Kenji Hara -Source: $(PHOBOSSRC std/format.d) +Source: $(PHOBOSSRC std/format/package.d) */ module std.format; diff --git a/libphobos/src/std/internal/math/gammafunction.d b/libphobos/src/std/internal/math/gammafunction.d index 7f72234..703ecb1 100644 --- a/libphobos/src/std/internal/math/gammafunction.d +++ b/libphobos/src/std/internal/math/gammafunction.d @@ -631,7 +631,7 @@ enum real BETA_BIGINV = 1.084202172485504434007e-19L; * betaIncomplete(a, b, x) = Γ(a+b)/(Γ(a) Γ(b)) * * $(INTEGRATE 0, x) $(POWER t, a-1)$(POWER (1-t),b-1) dt * - * and is the same as the the cumulative distribution function. + * and is the same as the cumulative distribution function. * * The domain of definition is 0 <= x <= 1. In this * implementation a and b are restricted to positive values. diff --git a/libphobos/src/std/logger/core.d b/libphobos/src/std/logger/core.d index be2bd8d..846f6ee 100644 --- a/libphobos/src/std/logger/core.d +++ b/libphobos/src/std/logger/core.d @@ -704,7 +704,7 @@ abstract class Logger /** This template provides the log functions for the `Logger` `class` with the `LogLevel` encoded in the function name. - For further information see the the two functions defined inside of this + For further information see the two functions defined inside of this template. The aliases following this template create the public names of these log @@ -1446,7 +1446,7 @@ that the returned reference is only a current snapshot and in the following code, you must make sure no other thread reassigns to it between reading and writing `sharedLog`. -`sharedLog` is only thread-safe if the the used `Logger` is thread-safe. +`sharedLog` is only thread-safe if the used `Logger` is thread-safe. The default `Logger` is thread-safe. ------------- if (sharedLog !is myLogger) @@ -1559,10 +1559,21 @@ class StdForwardLogger : Logger } } + auto oldSharedLog = sharedLog; + sharedLog = new shared RaceLogger; - scope(exit) { sharedLog = null; } - () @trusted { new Thread(() { log("foo"); }).start(); }(); + scope(exit) + { + sharedLog = oldSharedLog; + } + Thread toWaitFor; + () @trusted { toWaitFor = new Thread(() { log("foo"); }).start(); }(); log("bar"); + + () @trusted + { + toWaitFor.join(); + }(); } /** This `LogLevel` is unqiue to every thread. @@ -1897,7 +1908,7 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe assertThrown!Throwable(logf(LogLevel.fatal, msg, "Yet")); } (); lineNumber = __LINE__ - 2; - assert(l.msg == msg.format("Yet")); + assert(l.msg == msg.format("Yet"), l.msg); assert(l.line == lineNumber); assert(l.logLevel == LogLevel.all); diff --git a/libphobos/src/std/net/curl.d b/libphobos/src/std/net/curl.d index 7ea2ceb..2318279 100644 --- a/libphobos/src/std/net/curl.d +++ b/libphobos/src/std/net/curl.d @@ -1973,7 +1973,7 @@ private mixin template Protocol() } /** - * The network interface to use in form of the the IP of the interface. + * The network interface to use in form of the IP of the interface. * * Example: * ---- @@ -2706,7 +2706,7 @@ struct HTTP @property void dnsTimeout(Duration d); /** - * The network interface to use in form of the the IP of the interface. + * The network interface to use in form of the IP of the interface. * * Example: * ---- @@ -3486,7 +3486,7 @@ struct FTP @property void dnsTimeout(Duration d); /** - * The network interface to use in form of the the IP of the interface. + * The network interface to use in form of the IP of the interface. * * Example: * ---- @@ -3912,7 +3912,7 @@ struct SMTP @property void dnsTimeout(Duration d); /** - * The network interface to use in form of the the IP of the interface. + * The network interface to use in form of the IP of the interface. * * Example: * ---- diff --git a/libphobos/src/std/numeric.d b/libphobos/src/std/numeric.d index 96d20c2..df7ac39 100644 --- a/libphobos/src/std/numeric.d +++ b/libphobos/src/std/numeric.d @@ -1124,8 +1124,8 @@ public: * * References: "On Enclosing Simple Roots of Nonlinear Equations", * G. Alefeld, F.A. Potra, Yixun Shi, Mathematics of Computation 61, - * pp733-744 (1993). Fortran code available from $(HTTP - * www.netlib.org,www.netlib.org) as algorithm TOMS478. + * pp733-744 (1993). Fortran code available from + * $(HTTP www.netlib.org,www.netlib.org) as algorithm TOMS478. * */ T findRoot(T, DF, DT)(scope DF f, const T a, const T b, diff --git a/libphobos/src/std/path.d b/libphobos/src/std/path.d index de180fc..4b5a7ef 100644 --- a/libphobos/src/std/path.d +++ b/libphobos/src/std/path.d @@ -3357,8 +3357,10 @@ in { // Verify that pattern[] is valid import std.algorithm.searching : balancedParens; - assert(balancedParens(pattern, '[', ']', 0)); - assert(balancedParens(pattern, '{', '}', 0)); + import std.utf : byUTF; + + assert(balancedParens(pattern.byUTF!C, '[', ']', 0)); + assert(balancedParens(pattern.byUTF!C, '{', '}', 0)); } do { @@ -3959,7 +3961,7 @@ string expandTilde(string inputPath) @safe nothrow version (Posix) { import core.exception : onOutOfMemoryError; - import core.stdc.errno : errno, ERANGE; + import core.stdc.errno : errno, EBADF, ENOENT, EPERM, ERANGE, ESRCH; import core.stdc.stdlib : malloc, free, realloc; /* Joins a path from a C string to the remainder of path. @@ -4065,7 +4067,7 @@ string expandTilde(string inputPath) @safe nothrow char[] extra_memory; passwd result; - while (1) + loop: while (1) { extra_memory.length += extra_memory_size; @@ -4088,10 +4090,23 @@ string expandTilde(string inputPath) @safe nothrow break; } - if (errno != ERANGE && + switch (errno) + { + case ERANGE: // On BSD and OSX, errno can be left at 0 instead of set to ERANGE - errno != 0) - onOutOfMemoryError(); + case 0: + break; + + case ENOENT: + case ESRCH: + case EBADF: + case EPERM: + // The given name or uid was not found. + break loop; + + default: + onOutOfMemoryError(); + } // extra_memory isn't large enough import core.checkedint : mulu; diff --git a/libphobos/src/std/range/primitives.d b/libphobos/src/std/range/primitives.d index 31f58fa..cdab401 100644 --- a/libphobos/src/std/range/primitives.d +++ b/libphobos/src/std/range/primitives.d @@ -172,7 +172,7 @@ Returns: enum bool isInputRange(R) = is(typeof(R.init) == R) && is(ReturnType!((R r) => r.empty) == bool) - && is(typeof((return ref R r) => r.front)) + && (is(typeof((return ref R r) => r.front)) || is(typeof(ref (return ref R r) => r.front))) && !is(ReturnType!((R r) => r.front) == void) && is(typeof((R r) => r.popFront)); @@ -227,6 +227,17 @@ enum bool isInputRange(R) = } static assert(!isInputRange!VoidFront); } +// https://issues.dlang.org/show_bug.cgi?id=16034 +@safe unittest +{ + struct One + { + int entry = 1; + @disable this(this); + } + + assert(isInputRange!(One[])); +} @safe unittest { diff --git a/libphobos/src/std/socket.d b/libphobos/src/std/socket.d index 6ec7985..fb2c2d4 100644 --- a/libphobos/src/std/socket.d +++ b/libphobos/src/std/socket.d @@ -2942,7 +2942,7 @@ public: * Calling `shutdown` before `close` is recommended * for connection-oriented sockets. */ - void close() @trusted nothrow @nogc + void close() scope @trusted nothrow @nogc { _close(sock); sock = socket_t.init; @@ -3641,7 +3641,7 @@ class UdpSocket: Socket { checkAttributes!q{nothrow @nogc @trusted}; } - nothrow @nogc @trusted void close() + nothrow @nogc @trusted scope void close() { checkAttributes!q{nothrow @nogc @trusted}; } diff --git a/libphobos/src/std/stdio.d b/libphobos/src/std/stdio.d index a1fe962..cd1a356 100644 --- a/libphobos/src/std/stdio.d +++ b/libphobos/src/std/stdio.d @@ -85,8 +85,7 @@ else version (CRuntime_Musl) } else version (CRuntime_UClibc) { - // uClibc supports GCC IO - version = GCC_IO; + version = GENERIC_IO; } else version (OSX) { @@ -589,7 +588,7 @@ Throws: `ErrnoException` if the file could not be opened. detach(); } - this(this) @safe nothrow + this(this) @safe pure nothrow @nogc { if (!_p) return; assert(atomicLoad(_p.refs)); diff --git a/libphobos/src/std/sumtype.d b/libphobos/src/std/sumtype.d index 160665c..ee2d73a 100644 --- a/libphobos/src/std/sumtype.d +++ b/libphobos/src/std/sumtype.d @@ -753,23 +753,6 @@ public: } } - invariant - { - this.match!((ref value) { - static if (is(typeof(value) == class)) - { - if (value !is null) - { - assert(value); - } - } - else static if (is(typeof(value) == struct)) - { - assert(&value); - } - }); - } - // Workaround for https://issues.dlang.org/show_bug.cgi?id=21400 version (StdDdoc) { @@ -1330,36 +1313,6 @@ version (D_BetterC) {} else })); } -// Types with invariants -// Disabled in BetterC due to use of exceptions -version (D_BetterC) {} else -version (D_Invariants) -@system unittest -{ - import std.exception : assertThrown; - import core.exception : AssertError; - - struct S - { - int i; - invariant { assert(i >= 0); } - } - - class C - { - int i; - invariant { assert(i >= 0); } - } - - SumType!S x; - x.match!((ref v) { v.i = -1; }); - assertThrown!AssertError(assert(&x)); - - SumType!C y = new C(); - y.match!((ref v) { v.i = -1; }); - assertThrown!AssertError(assert(&y)); -} - // Calls value postblit on self-assignment @safe unittest { diff --git a/libphobos/src/std/typecons.d b/libphobos/src/std/typecons.d index c7cdc24..094628b 100644 --- a/libphobos/src/std/typecons.d +++ b/libphobos/src/std/typecons.d @@ -3793,8 +3793,28 @@ Params: sink.formatValue(_value, fmt); } } + + void toString()(scope void delegate(const(char)[]) sink, scope const ref FormatSpec!char fmt) const + { + if (isNull) + { + sink.formatValue("Nullable.null", fmt); + } + else + { + sink.formatValue(_value, fmt); + } + } } +@system unittest +{ + import std.conv : to; + + const Nullable!(ulong, 0) x = 1; + assert(x.to!string == "1"); +} + /** Check if `this` is in the null state. @@ -4320,8 +4340,28 @@ Params: sink.formatValue(*_value, fmt); } } + + void toString()(scope void delegate(const(char)[]) sink, scope const ref FormatSpec!char fmt) const + { + if (isNull) + { + sink.formatValue("Nullable.null", fmt); + } + else + { + sink.formatValue(*_value, fmt); + } + } } +@system unittest +{ + import std.conv : to; + + const NullableRef!(ulong) x = new ulong(1); + assert(x.to!string == "1"); +} + /** Binds the internal state to `value`. diff --git a/libphobos/src/std/uni/package.d b/libphobos/src/std/uni/package.d index e12a70c..8a032aa 100644 --- a/libphobos/src/std/uni/package.d +++ b/libphobos/src/std/uni/package.d @@ -426,7 +426,7 @@ $(TR $(TD Building blocks) $(TD $(SECTION Construction of lookup tables) $(P The Unicode standard describes a set of algorithms that depend on having the ability to quickly look up various properties - of a code point. Given the the codespace of about 1 million $(CODEPOINTS), + of a code point. Given the codespace of about 1 million $(CODEPOINTS), it is not a trivial task to provide a space-efficient solution for the multitude of properties. ) diff --git a/libphobos/src/std/utf.d b/libphobos/src/std/utf.d index d22dac8..8d94e12 100644 --- a/libphobos/src/std/utf.d +++ b/libphobos/src/std/utf.d @@ -3571,7 +3571,7 @@ enum dchar replacementDchar = '\uFFFD'; * of characters (including strings) or a type that implicitly converts to a string type. * Returns: * If `r` is not an auto-decodable string (i.e. a narrow string or a - * user-defined type that implicits converts to a string type), then `r` + * user-defined type that implicitly converts to a string type), then `r` * is returned. * * Otherwise, `r` is converted to its corresponding string type (if it's diff --git a/libphobos/src/std/xml.d b/libphobos/src/std/xml.d deleted file mode 100644 index fdfdc3f..0000000 --- a/libphobos/src/std/xml.d +++ /dev/null @@ -1,3113 +0,0 @@ -// Written in the D programming language. - -/** -$(RED Warning: This module is considered out-dated and not up to Phobos' - current standards. It will be removed from Phobos in 2.101.0. - If you still need it, go to $(LINK https://github.com/DigitalMars/undeaD)) - */ - -/* -Classes and functions for creating and parsing XML - -The basic architecture of this module is that there are standalone functions, -classes for constructing an XML document from scratch (Tag, Element and -Document), and also classes for parsing a pre-existing XML file (ElementParser -and DocumentParser). The parsing classes <i>may</i> be used to build a -Document, but that is not their primary purpose. The handling capabilities of -DocumentParser and ElementParser are sufficiently customizable that you can -make them do pretty much whatever you want. - -Example: This example creates a DOM (Document Object Model) tree - from an XML file. ------------------------------------------------------------------------------- -import std.xml; -import std.stdio; -import std.string; -import std.file; - -// books.xml is used in various samples throughout the Microsoft XML Core -// Services (MSXML) SDK. -// -// See http://msdn2.microsoft.com/en-us/library/ms762271(VS.85).aspx - -void main() -{ - string s = cast(string) std.file.read("books.xml"); - - // Check for well-formedness - check(s); - - // Make a DOM tree - auto doc = new Document(s); - - // Plain-print it - writeln(doc); -} ------------------------------------------------------------------------------- - -Example: This example does much the same thing, except that the file is - deconstructed and reconstructed by hand. This is more work, but the - techniques involved offer vastly more power. ------------------------------------------------------------------------------- -import std.xml; -import std.stdio; -import std.string; - -struct Book -{ - string id; - string author; - string title; - string genre; - string price; - string pubDate; - string description; -} - -void main() -{ - string s = cast(string) std.file.read("books.xml"); - - // Check for well-formedness - check(s); - - // Take it apart - Book[] books; - - auto xml = new DocumentParser(s); - xml.onStartTag["book"] = (ElementParser xml) - { - Book book; - book.id = xml.tag.attr["id"]; - - xml.onEndTag["author"] = (in Element e) { book.author = e.text(); }; - xml.onEndTag["title"] = (in Element e) { book.title = e.text(); }; - xml.onEndTag["genre"] = (in Element e) { book.genre = e.text(); }; - xml.onEndTag["price"] = (in Element e) { book.price = e.text(); }; - xml.onEndTag["publish-date"] = (in Element e) { book.pubDate = e.text(); }; - xml.onEndTag["description"] = (in Element e) { book.description = e.text(); }; - - xml.parse(); - - books ~= book; - }; - xml.parse(); - - // Put it back together again; - auto doc = new Document(new Tag("catalog")); - foreach (book;books) - { - auto element = new Element("book"); - element.tag.attr["id"] = book.id; - - element ~= new Element("author", book.author); - element ~= new Element("title", book.title); - element ~= new Element("genre", book.genre); - element ~= new Element("price", book.price); - element ~= new Element("publish-date",book.pubDate); - element ~= new Element("description", book.description); - - doc ~= element; - } - - // Pretty-print it - writefln(join(doc.pretty(3),"\n")); -} -------------------------------------------------------------------------------- -Copyright: Copyright Janice Caron 2008 - 2009. -License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). -Authors: Janice Caron -Source: $(PHOBOSSRC std/xml.d) -*/ -/* - Copyright Janice Caron 2008 - 2009. -Distributed under the Boost Software License, Version 1.0. - (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt) -*/ -deprecated("Will be removed from Phobos in 2.101.0. If you still need it, go to https://github.com/DigitalMars/undeaD") -module std.xml; - -enum cdata = "<![CDATA["; - -/* - * Returns true if the character is a character according to the XML standard - * - * Standards: $(LINK2 http://www.w3.org/TR/1998/REC-xml-19980210, XML 1.0) - * - * Params: - * c = the character to be tested - */ -bool isChar(dchar c) @safe @nogc pure nothrow // rule 2 -{ - if (c <= 0xD7FF) - { - if (c >= 0x20) - return true; - switch (c) - { - case 0xA: - case 0x9: - case 0xD: - return true; - default: - return false; - } - } - else if (0xE000 <= c && c <= 0x10FFFF) - { - if ((c & 0x1FFFFE) != 0xFFFE) // U+FFFE and U+FFFF - return true; - } - return false; -} - -@safe @nogc nothrow pure unittest -{ - assert(!isChar(cast(dchar) 0x8)); - assert( isChar(cast(dchar) 0x9)); - assert( isChar(cast(dchar) 0xA)); - assert(!isChar(cast(dchar) 0xB)); - assert(!isChar(cast(dchar) 0xC)); - assert( isChar(cast(dchar) 0xD)); - assert(!isChar(cast(dchar) 0xE)); - assert(!isChar(cast(dchar) 0x1F)); - assert( isChar(cast(dchar) 0x20)); - assert( isChar('J')); - assert( isChar(cast(dchar) 0xD7FF)); - assert(!isChar(cast(dchar) 0xD800)); - assert(!isChar(cast(dchar) 0xDFFF)); - assert( isChar(cast(dchar) 0xE000)); - assert( isChar(cast(dchar) 0xFFFD)); - assert(!isChar(cast(dchar) 0xFFFE)); - assert(!isChar(cast(dchar) 0xFFFF)); - assert( isChar(cast(dchar) 0x10000)); - assert( isChar(cast(dchar) 0x10FFFF)); - assert(!isChar(cast(dchar) 0x110000)); - - debug (stdxml_TestHardcodedChecks) - { - foreach (c; 0 .. dchar.max + 1) - assert(isChar(c) == lookup(CharTable, c)); - } -} - -/* - * Returns true if the character is whitespace according to the XML standard - * - * Only the following characters are considered whitespace in XML - space, tab, - * carriage return and linefeed - * - * Standards: $(LINK2 http://www.w3.org/TR/1998/REC-xml-19980210, XML 1.0) - * - * Params: - * c = the character to be tested - */ -bool isSpace(dchar c) @safe @nogc pure nothrow -{ - return c == '\u0020' || c == '\u0009' || c == '\u000A' || c == '\u000D'; -} - -/* - * Returns true if the character is a digit according to the XML standard - * - * Standards: $(LINK2 http://www.w3.org/TR/1998/REC-xml-19980210, XML 1.0) - * - * Params: - * c = the character to be tested - */ -bool isDigit(dchar c) @safe @nogc pure nothrow -{ - if (c <= 0x0039 && c >= 0x0030) - return true; - else - return lookup(DigitTable,c); -} - -@safe @nogc nothrow pure unittest -{ - debug (stdxml_TestHardcodedChecks) - { - foreach (c; 0 .. dchar.max + 1) - assert(isDigit(c) == lookup(DigitTable, c)); - } -} - -/* - * Returns true if the character is a letter according to the XML standard - * - * Standards: $(LINK2 http://www.w3.org/TR/1998/REC-xml-19980210, XML 1.0) - * - * Params: - * c = the character to be tested - */ -bool isLetter(dchar c) @safe @nogc nothrow pure // rule 84 -{ - return isIdeographic(c) || isBaseChar(c); -} - -/* - * Returns true if the character is an ideographic character according to the - * XML standard - * - * Standards: $(LINK2 http://www.w3.org/TR/1998/REC-xml-19980210, XML 1.0) - * - * Params: - * c = the character to be tested - */ -bool isIdeographic(dchar c) @safe @nogc nothrow pure -{ - if (c == 0x3007) - return true; - if (c <= 0x3029 && c >= 0x3021 ) - return true; - if (c <= 0x9FA5 && c >= 0x4E00) - return true; - return false; -} - -@safe @nogc nothrow pure unittest -{ - assert(isIdeographic('\u4E00')); - assert(isIdeographic('\u9FA5')); - assert(isIdeographic('\u3007')); - assert(isIdeographic('\u3021')); - assert(isIdeographic('\u3029')); - - debug (stdxml_TestHardcodedChecks) - { - foreach (c; 0 .. dchar.max + 1) - assert(isIdeographic(c) == lookup(IdeographicTable, c)); - } -} - -/* - * Returns true if the character is a base character according to the XML - * standard - * - * Standards: $(LINK2 http://www.w3.org/TR/1998/REC-xml-19980210, XML 1.0) - * - * Params: - * c = the character to be tested - */ -bool isBaseChar(dchar c) @safe @nogc nothrow pure -{ - return lookup(BaseCharTable,c); -} - -/* - * Returns true if the character is a combining character according to the - * XML standard - * - * Standards: $(LINK2 http://www.w3.org/TR/1998/REC-xml-19980210, XML 1.0) - * - * Params: - * c = the character to be tested - */ -bool isCombiningChar(dchar c) @safe @nogc nothrow pure -{ - return lookup(CombiningCharTable,c); -} - -/* - * Returns true if the character is an extender according to the XML standard - * - * Standards: $(LINK2 http://www.w3.org/TR/1998/REC-xml-19980210, XML 1.0) - * - * Params: - * c = the character to be tested - */ -bool isExtender(dchar c) @safe @nogc nothrow pure -{ - return lookup(ExtenderTable,c); -} - -/* - * Encodes a string by replacing all characters which need to be escaped with - * appropriate predefined XML entities. - * - * encode() escapes certain characters (ampersand, quote, apostrophe, less-than - * and greater-than), and similarly, decode() unescapes them. These functions - * are provided for convenience only. You do not need to use them when using - * the std.xml classes, because then all the encoding and decoding will be done - * for you automatically. - * - * If the string is not modified, the original will be returned. - * - * Standards: $(LINK2 http://www.w3.org/TR/1998/REC-xml-19980210, XML 1.0) - * - * Params: - * s = The string to be encoded - * - * Returns: The encoded string - * - * Example: - * -------------- - * writefln(encode("a > b")); // writes "a > b" - * -------------- - */ -S encode(S)(S s) -{ - import std.array : appender; - - string r; - size_t lastI; - auto result = appender!S(); - - foreach (i, c; s) - { - switch (c) - { - case '&': r = "&"; break; - case '"': r = """; break; - case '\'': r = "'"; break; - case '<': r = "<"; break; - case '>': r = ">"; break; - default: continue; - } - // Replace with r - result.put(s[lastI .. i]); - result.put(r); - lastI = i + 1; - } - - if (!result.data.ptr) return s; - result.put(s[lastI .. $]); - return result.data; -} - -@safe pure unittest -{ - auto s = "hello"; - assert(encode(s) is s); - assert(encode("a > b") == "a > b", encode("a > b")); - assert(encode("a < b") == "a < b"); - assert(encode("don't") == "don't"); - assert(encode("\"hi\"") == ""hi"", encode("\"hi\"")); - assert(encode("cat & dog") == "cat & dog"); -} - -/* - * Mode to use for decoding. - * - * $(DDOC_ENUM_MEMBERS NONE) Do not decode - * $(DDOC_ENUM_MEMBERS LOOSE) Decode, but ignore errors - * $(DDOC_ENUM_MEMBERS STRICT) Decode, and throw exception on error - */ -enum DecodeMode -{ - NONE, LOOSE, STRICT -} - -/* - * Decodes a string by unescaping all predefined XML entities. - * - * encode() escapes certain characters (ampersand, quote, apostrophe, less-than - * and greater-than), and similarly, decode() unescapes them. These functions - * are provided for convenience only. You do not need to use them when using - * the std.xml classes, because then all the encoding and decoding will be done - * for you automatically. - * - * This function decodes the entities &amp;, &quot;, &apos;, - * &lt; and &gt, - * as well as decimal and hexadecimal entities such as &#x20AC; - * - * If the string does not contain an ampersand, the original will be returned. - * - * Note that the "mode" parameter can be one of DecodeMode.NONE (do not - * decode), DecodeMode.LOOSE (decode, but ignore errors), or DecodeMode.STRICT - * (decode, and throw a DecodeException in the event of an error). - * - * Standards: $(LINK2 http://www.w3.org/TR/1998/REC-xml-19980210, XML 1.0) - * - * Params: - * s = The string to be decoded - * mode = (optional) Mode to use for decoding. (Defaults to LOOSE). - * - * Throws: DecodeException if mode == DecodeMode.STRICT and decode fails - * - * Returns: The decoded string - * - * Example: - * -------------- - * writefln(decode("a > b")); // writes "a > b" - * -------------- - */ -string decode(string s, DecodeMode mode=DecodeMode.LOOSE) @safe pure -{ - import std.algorithm.searching : startsWith; - - if (mode == DecodeMode.NONE) return s; - - string buffer; - foreach (ref i; 0 .. s.length) - { - char c = s[i]; - if (c != '&') - { - if (buffer.length != 0) buffer ~= c; - } - else - { - if (buffer.length == 0) - { - buffer = s[0 .. i].dup; - } - if (startsWith(s[i..$],"&#")) - { - try - { - dchar d; - string t = s[i..$]; - checkCharRef(t, d); - char[4] temp; - import std.utf : encode; - buffer ~= temp[0 .. encode(temp, d)]; - i = s.length - t.length - 1; - } - catch (Err e) - { - if (mode == DecodeMode.STRICT) - throw new DecodeException("Unescaped &"); - buffer ~= '&'; - } - } - else if (startsWith(s[i..$],"&" )) { buffer ~= '&'; i += 4; } - else if (startsWith(s[i..$],""")) { buffer ~= '"'; i += 5; } - else if (startsWith(s[i..$],"'")) { buffer ~= '\''; i += 5; } - else if (startsWith(s[i..$],"<" )) { buffer ~= '<'; i += 3; } - else if (startsWith(s[i..$],">" )) { buffer ~= '>'; i += 3; } - else - { - if (mode == DecodeMode.STRICT) - throw new DecodeException("Unescaped &"); - buffer ~= '&'; - } - } - } - return (buffer.length == 0) ? s : buffer; -} - -@safe pure unittest -{ - void assertNot(string s) pure - { - bool b = false; - try { decode(s,DecodeMode.STRICT); } - catch (DecodeException e) { b = true; } - assert(b,s); - } - - // Assert that things that should work, do - auto s = "hello"; - assert(decode(s, DecodeMode.STRICT) is s); - assert(decode("a > b", DecodeMode.STRICT) == "a > b"); - assert(decode("a < b", DecodeMode.STRICT) == "a < b"); - assert(decode("don't", DecodeMode.STRICT) == "don't"); - assert(decode(""hi"", DecodeMode.STRICT) == "\"hi\""); - assert(decode("cat & dog", DecodeMode.STRICT) == "cat & dog"); - assert(decode("*", DecodeMode.STRICT) == "*"); - assert(decode("*", DecodeMode.STRICT) == "*"); - assert(decode("cat & dog", DecodeMode.LOOSE) == "cat & dog"); - assert(decode("a > b", DecodeMode.LOOSE) == "a > b"); - assert(decode("&#;", DecodeMode.LOOSE) == "&#;"); - assert(decode("&#x;", DecodeMode.LOOSE) == "&#x;"); - assert(decode("G;", DecodeMode.LOOSE) == "G;"); - assert(decode("G;", DecodeMode.LOOSE) == "G;"); - - // Assert that things that shouldn't work, don't - assertNot("cat & dog"); - assertNot("a > b"); - assertNot("&#;"); - assertNot("&#x;"); - assertNot("G;"); - assertNot("G;"); -} - -/* - * Class representing an XML document. - * - * Standards: $(LINK2 http://www.w3.org/TR/1998/REC-xml-19980210, XML 1.0) - * - */ -class Document : Element -{ - /* - * Contains all text which occurs before the root element. - * Defaults to <?xml version="1.0"?> - */ - string prolog = "<?xml version=\"1.0\"?>"; - /* - * Contains all text which occurs after the root element. - * Defaults to the empty string - */ - string epilog; - - /* - * Constructs a Document by parsing XML text. - * - * This function creates a complete DOM (Document Object Model) tree. - * - * The input to this function MUST be valid XML. - * This is enforced by DocumentParser's in contract. - * - * Params: - * s = the complete XML text. - */ - this(string s) - in - { - assert(s.length != 0); - } - do - { - auto xml = new DocumentParser(s); - string tagString = xml.tag.tagString; - - this(xml.tag); - prolog = s[0 .. tagString.ptr - s.ptr]; - parse(xml); - epilog = *xml.s; - } - - /* - * Constructs a Document from a Tag. - * - * Params: - * tag = the start tag of the document. - */ - this(const(Tag) tag) - { - super(tag); - } - - const - { - /* - * Compares two Documents for equality - * - * Example: - * -------------- - * Document d1,d2; - * if (d1 == d2) { } - * -------------- - */ - override bool opEquals(scope const Object o) const - { - const doc = toType!(const Document)(o); - return prolog == doc.prolog - && (cast(const) this).Element.opEquals(cast(const) doc) - && epilog == doc.epilog; - } - - /* - * Compares two Documents - * - * You should rarely need to call this function. It exists so that - * Documents can be used as associative array keys. - * - * Example: - * -------------- - * Document d1,d2; - * if (d1 < d2) { } - * -------------- - */ - override int opCmp(scope const Object o) scope const - { - const doc = toType!(const Document)(o); - if (prolog != doc.prolog) - return prolog < doc.prolog ? -1 : 1; - if (int cmp = this.Element.opCmp(doc)) - return cmp; - if (epilog != doc.epilog) - return epilog < doc.epilog ? -1 : 1; - return 0; - } - - /* - * Returns the hash of a Document - * - * You should rarely need to call this function. It exists so that - * Documents can be used as associative array keys. - */ - override size_t toHash() scope const @trusted - { - return hash(prolog, hash(epilog, (cast() this).Element.toHash())); - } - - /* - * Returns the string representation of a Document. (That is, the - * complete XML of a document). - */ - override string toString() scope const @safe - { - return prolog ~ super.toString() ~ epilog; - } - } -} - -@system unittest -{ - // https://issues.dlang.org/show_bug.cgi?id=14966 - auto xml = `<?xml version="1.0" encoding="UTF-8"?><foo></foo>`; - - auto a = new Document(xml); - auto b = new Document(xml); - assert(a == b); - assert(!(a < b)); - int[Document] aa; - aa[a] = 1; - assert(aa[b] == 1); - - b ~= new Element("b"); - assert(a < b); - assert(b > a); -} - -/* - * Class representing an XML element. - * - * Standards: $(LINK2 http://www.w3.org/TR/1998/REC-xml-19980210, XML 1.0) - */ -class Element : Item -{ - Tag tag; // The start tag of the element - Item[] items; // The element's items - Text[] texts; // The element's text items - CData[] cdatas; // The element's CData items - Comment[] comments; // The element's comments - ProcessingInstruction[] pis; // The element's processing instructions - Element[] elements; // The element's child elements - - /* - * Constructs an Element given a name and a string to be used as a Text - * interior. - * - * Params: - * name = the name of the element. - * interior = (optional) the string interior. - * - * Example: - * ------------------------------------------------------- - * auto element = new Element("title","Serenity") - * // constructs the element <title>Serenity</title> - * ------------------------------------------------------- - */ - this(string name, string interior=null) @safe pure - { - this(new Tag(name)); - if (interior.length != 0) opOpAssign!("~")(new Text(interior)); - } - - /* - * Constructs an Element from a Tag. - * - * Params: - * tag_ = the start or empty tag of the element. - */ - this(const(Tag) tag_) @safe pure - { - this.tag = new Tag(tag_.name); - tag.type = TagType.EMPTY; - foreach (k,v;tag_.attr) tag.attr[k] = v; - tag.tagString = tag_.tagString; - } - - /* - * Append a text item to the interior of this element - * - * Params: - * item = the item you wish to append. - * - * Example: - * -------------- - * Element element; - * element ~= new Text("hello"); - * -------------- - */ - void opOpAssign(string op)(Text item) @safe pure - if (op == "~") - { - texts ~= item; - appendItem(item); - } - - /* - * Append a CData item to the interior of this element - * - * Params: - * item = the item you wish to append. - * - * Example: - * -------------- - * Element element; - * element ~= new CData("hello"); - * -------------- - */ - void opOpAssign(string op)(CData item) @safe pure - if (op == "~") - { - cdatas ~= item; - appendItem(item); - } - - /* - * Append a comment to the interior of this element - * - * Params: - * item = the item you wish to append. - * - * Example: - * -------------- - * Element element; - * element ~= new Comment("hello"); - * -------------- - */ - void opOpAssign(string op)(Comment item) @safe pure - if (op == "~") - { - comments ~= item; - appendItem(item); - } - - /* - * Append a processing instruction to the interior of this element - * - * Params: - * item = the item you wish to append. - * - * Example: - * -------------- - * Element element; - * element ~= new ProcessingInstruction("hello"); - * -------------- - */ - void opOpAssign(string op)(ProcessingInstruction item) @safe pure - if (op == "~") - { - pis ~= item; - appendItem(item); - } - - /* - * Append a complete element to the interior of this element - * - * Params: - * item = the item you wish to append. - * - * Example: - * -------------- - * Element element; - * Element other = new Element("br"); - * element ~= other; - * // appends element representing <br /> - * -------------- - */ - void opOpAssign(string op)(Element item) @safe pure - if (op == "~") - { - elements ~= item; - appendItem(item); - } - - private void appendItem(Item item) @safe pure - { - items ~= item; - if (tag.type == TagType.EMPTY && !item.isEmptyXML) - tag.type = TagType.START; - } - - private void parse(ElementParser xml) - { - xml.onText = (string s) { opOpAssign!("~")(new Text(s)); }; - xml.onCData = (string s) { opOpAssign!("~")(new CData(s)); }; - xml.onComment = (string s) { opOpAssign!("~")(new Comment(s)); }; - xml.onPI = (string s) { opOpAssign!("~")(new ProcessingInstruction(s)); }; - - xml.onStartTag[null] = (ElementParser xml) - { - auto e = new Element(xml.tag); - e.parse(xml); - opOpAssign!("~")(e); - }; - - xml.parse(); - } - - /* - * Compares two Elements for equality - * - * Example: - * -------------- - * Element e1,e2; - * if (e1 == e2) { } - * -------------- - */ - override bool opEquals(scope const Object o) const - { - const element = toType!(const Element)(o); - immutable len = items.length; - if (len != element.items.length) return false; - foreach (i; 0 .. len) - { - if (!items[i].opEquals(element.items[i])) return false; - } - return true; - } - - /* - * Compares two Elements - * - * You should rarely need to call this function. It exists so that Elements - * can be used as associative array keys. - * - * Example: - * -------------- - * Element e1,e2; - * if (e1 < e2) { } - * -------------- - */ - override int opCmp(scope const Object o) @safe const - { - const element = toType!(const Element)(o); - for (uint i=0; ; ++i) - { - if (i == items.length && i == element.items.length) return 0; - if (i == items.length) return -1; - if (i == element.items.length) return 1; - if (!items[i].opEquals(element.items[i])) - return items[i].opCmp(element.items[i]); - } - } - - /* - * Returns the hash of an Element - * - * You should rarely need to call this function. It exists so that Elements - * can be used as associative array keys. - */ - override size_t toHash() scope const @safe - { - size_t hash = tag.toHash(); - foreach (item;items) hash += item.toHash(); - return hash; - } - - const - { - /* - * Returns the decoded interior of an element. - * - * The element is assumed to contain text <i>only</i>. So, for - * example, given XML such as "<title>Good &amp; - * Bad</title>", will return "Good & Bad". - * - * Params: - * mode = (optional) Mode to use for decoding. (Defaults to LOOSE). - * - * Throws: DecodeException if decode fails - */ - string text(DecodeMode mode=DecodeMode.LOOSE) - { - string buffer; - foreach (item;items) - { - Text t = cast(Text) item; - if (t is null) throw new DecodeException(item.toString()); - buffer ~= decode(t.toString(),mode); - } - return buffer; - } - - /* - * Returns an indented string representation of this item - * - * Params: - * indent = (optional) number of spaces by which to indent this - * element. Defaults to 2. - */ - override string[] pretty(uint indent=2) scope - { - import std.algorithm.searching : count; - import std.string : rightJustify; - - if (isEmptyXML) return [ tag.toEmptyString() ]; - - if (items.length == 1) - { - auto t = cast(const(Text))(items[0]); - if (t !is null) - { - return [tag.toStartString() ~ t.toString() ~ tag.toEndString()]; - } - } - - string[] a = [ tag.toStartString() ]; - foreach (item;items) - { - string[] b = item.pretty(indent); - foreach (s;b) - { - a ~= rightJustify(s,count(s) + indent); - } - } - a ~= tag.toEndString(); - return a; - } - - /* - * Returns the string representation of an Element - * - * Example: - * -------------- - * auto element = new Element("br"); - * writefln(element.toString()); // writes "<br />" - * -------------- - */ - override string toString() scope @safe - { - if (isEmptyXML) return tag.toEmptyString(); - - string buffer = tag.toStartString(); - foreach (item;items) { buffer ~= item.toString(); } - buffer ~= tag.toEndString(); - return buffer; - } - - override @property @safe pure @nogc nothrow bool isEmptyXML() const scope { return items.length == 0; } - } -} - -/* - * Tag types. - * - * $(DDOC_ENUM_MEMBERS START) Used for start tags - * $(DDOC_ENUM_MEMBERS END) Used for end tags - * $(DDOC_ENUM_MEMBERS EMPTY) Used for empty tags - * - */ -enum TagType { START, END, EMPTY } - -/* - * Class representing an XML tag. - * - * Standards: $(LINK2 http://www.w3.org/TR/1998/REC-xml-19980210, XML 1.0) - * - * The class invariant guarantees - * <ul> - * <li> that $(B type) is a valid enum TagType value</li> - * <li> that $(B name) consists of valid characters</li> - * <li> that each attribute name consists of valid characters</li> - * </ul> - */ -class Tag -{ - TagType type = TagType.START; // Type of tag - string name; // Tag name - string[string] attr; // Associative array of attributes - private string tagString; - - invariant() - { - string s; - string t; - - assert(type == TagType.START - || type == TagType.END - || type == TagType.EMPTY); - - s = name; - try { checkName(s,t); } - catch (Err e) { assert(false,"Invalid tag name:" ~ e.toString()); } - - foreach (k,v;attr) - { - s = k; - try { checkName(s,t); } - catch (Err e) - { assert(false,"Invalid attribute name:" ~ e.toString()); } - } - } - - /* - * Constructs an instance of Tag with a specified name and type - * - * The constructor does not initialize the attributes. To initialize the - * attributes, you access the $(B attr) member variable. - * - * Params: - * name = the Tag's name - * type = (optional) the Tag's type. If omitted, defaults to - * TagType.START. - * - * Example: - * -------------- - * auto tag = new Tag("img",Tag.EMPTY); - * tag.attr["src"] = "http://example.com/example.jpg"; - * -------------- - */ - this(string name, TagType type=TagType.START) @safe pure - { - this.name = name; - this.type = type; - } - - /* Private constructor (so don't ddoc this!) - * - * Constructs a Tag by parsing the string representation, e.g. "<html>". - * - * The string is passed by reference, and is advanced over all characters - * consumed. - * - * The second parameter is a dummy parameter only, required solely to - * distinguish this constructor from the public one. - */ - private this(ref string s, bool dummy) @safe pure - { - import std.algorithm.searching : countUntil; - import std.ascii : isWhite; - import std.utf : byCodeUnit; - - tagString = s; - try - { - reqc(s,'<'); - if (optc(s,'/')) type = TagType.END; - ptrdiff_t i = s.byCodeUnit.countUntil(">", "/>", " ", "\t", "\v", "\r", "\n", "\f"); - name = s[0 .. i]; - s = s[i .. $]; - - i = s.byCodeUnit.countUntil!(a => !isWhite(a)); - s = s[i .. $]; - - while (s.length > 0 && s[0] != '>' && s[0] != '/') - { - i = s.byCodeUnit.countUntil("=", " ", "\t", "\v", "\r", "\n", "\f"); - string key = s[0 .. i]; - s = s[i .. $]; - - i = s.byCodeUnit.countUntil!(a => !isWhite(a)); - s = s[i .. $]; - reqc(s,'='); - i = s.byCodeUnit.countUntil!(a => !isWhite(a)); - s = s[i .. $]; - - immutable char quote = requireOneOf(s,"'\""); - i = s.byCodeUnit.countUntil(quote); - string val = decode(s[0 .. i], DecodeMode.LOOSE); - s = s[i .. $]; - reqc(s,quote); - - i = s.byCodeUnit.countUntil!(a => !isWhite(a)); - s = s[i .. $]; - attr[key] = val; - } - if (optc(s,'/')) - { - if (type == TagType.END) throw new TagException(""); - type = TagType.EMPTY; - } - reqc(s,'>'); - tagString.length = tagString.length - s.length; - } - catch (XMLException e) - { - tagString.length = tagString.length - s.length; - throw new TagException(tagString); - } - } - - const - { - /* - * Compares two Tags for equality - * - * You should rarely need to call this function. It exists so that Tags - * can be used as associative array keys. - * - * Example: - * -------------- - * Tag tag1,tag2 - * if (tag1 == tag2) { } - * -------------- - */ - override bool opEquals(scope Object o) - { - const tag = toType!(const Tag)(o); - return - (name != tag.name) ? false : ( - (attr != tag.attr) ? false : ( - (type != tag.type) ? false : ( - true ))); - } - - /* - * Compares two Tags - * - * Example: - * -------------- - * Tag tag1,tag2 - * if (tag1 < tag2) { } - * -------------- - */ - override int opCmp(Object o) - { - const tag = toType!(const Tag)(o); - // Note that attr is an AA, so the comparison is nonsensical (bug 10381) - return - ((name != tag.name) ? ( name < tag.name ? -1 : 1 ) : - ((attr != tag.attr) ? ( cast(void *) attr < cast(void*) tag.attr ? -1 : 1 ) : - ((type != tag.type) ? ( type < tag.type ? -1 : 1 ) : - 0 ))); - } - - /* - * Returns the hash of a Tag - * - * You should rarely need to call this function. It exists so that Tags - * can be used as associative array keys. - */ - override size_t toHash() - { - return .hashOf(name); - } - - /* - * Returns the string representation of a Tag - * - * Example: - * -------------- - * auto tag = new Tag("book",TagType.START); - * writefln(tag.toString()); // writes "<book>" - * -------------- - */ - override string toString() @safe - { - if (isEmpty) return toEmptyString(); - return (isEnd) ? toEndString() : toStartString(); - } - - private - { - string toNonEndString() @safe - { - import std.format : format; - - string s = "<" ~ name; - foreach (key,val;attr) - s ~= format(" %s=\"%s\"",key,encode(val)); - return s; - } - - string toStartString() @safe { return toNonEndString() ~ ">"; } - - string toEndString() @safe { return "</" ~ name ~ ">"; } - - string toEmptyString() @safe { return toNonEndString() ~ " />"; } - } - - /* - * Returns true if the Tag is a start tag - * - * Example: - * -------------- - * if (tag.isStart) { } - * -------------- - */ - @property bool isStart() @safe @nogc pure nothrow { return type == TagType.START; } - - /* - * Returns true if the Tag is an end tag - * - * Example: - * -------------- - * if (tag.isEnd) { } - * -------------- - */ - @property bool isEnd() @safe @nogc pure nothrow { return type == TagType.END; } - - /* - * Returns true if the Tag is an empty tag - * - * Example: - * -------------- - * if (tag.isEmpty) { } - * -------------- - */ - @property bool isEmpty() @safe @nogc pure nothrow { return type == TagType.EMPTY; } - } -} - -/* - * Class representing a comment - */ -class Comment : Item -{ - private string content; - - /* - * Construct a comment - * - * Params: - * content = the body of the comment - * - * Throws: CommentException if the comment body is illegal (contains "--" - * or exactly equals "-") - * - * Example: - * -------------- - * auto item = new Comment("This is a comment"); - * // constructs <!--This is a comment--> - * -------------- - */ - this(string content) @safe pure - { - import std.string : indexOf; - - if (content == "-" || content.indexOf("--") != -1) - throw new CommentException(content); - this.content = content; - } - - /* - * Compares two comments for equality - * - * Example: - * -------------- - * Comment item1,item2; - * if (item1 == item2) { } - * -------------- - */ - override bool opEquals(scope const Object o) const - { - const item = toType!(const Item)(o); - const t = cast(const Comment) item; - return t !is null && content == t.content; - } - - /* - * Compares two comments - * - * You should rarely need to call this function. It exists so that Comments - * can be used as associative array keys. - * - * Example: - * -------------- - * Comment item1,item2; - * if (item1 < item2) { } - * -------------- - */ - override int opCmp(scope const Object o) scope const - { - const item = toType!(const Item)(o); - const t = cast(const Comment) item; - return t !is null && (content != t.content - ? (content < t.content ? -1 : 1 ) : 0 ); - } - - /* - * Returns the hash of a Comment - * - * You should rarely need to call this function. It exists so that Comments - * can be used as associative array keys. - */ - override size_t toHash() scope const nothrow { return hash(content); } - - /* - * Returns a string representation of this comment - */ - override string toString() scope const @safe pure nothrow { return "<!--" ~ content ~ "-->"; } - - override @property @safe @nogc pure nothrow scope bool isEmptyXML() const { return false; } // Returns false always -} - -// https://issues.dlang.org/show_bug.cgi?id=16241 -@safe unittest -{ - import std.exception : assertThrown; - auto c = new Comment("=="); - assert(c.content == "=="); - assertThrown!CommentException(new Comment("--")); -} - -/* - * Class representing a Character Data section - */ -class CData : Item -{ - private string content; - - /* - * Construct a character data section - * - * Params: - * content = the body of the character data segment - * - * Throws: CDataException if the segment body is illegal (contains "]]>") - * - * Example: - * -------------- - * auto item = new CData("<b>hello</b>"); - * // constructs <![CDATA[<b>hello</b>]]> - * -------------- - */ - this(string content) @safe pure - { - import std.string : indexOf; - if (content.indexOf("]]>") != -1) throw new CDataException(content); - this.content = content; - } - - /* - * Compares two CDatas for equality - * - * Example: - * -------------- - * CData item1,item2; - * if (item1 == item2) { } - * -------------- - */ - override bool opEquals(scope const Object o) const - { - const item = toType!(const Item)(o); - const t = cast(const CData) item; - return t !is null && content == t.content; - } - - /* - * Compares two CDatas - * - * You should rarely need to call this function. It exists so that CDatas - * can be used as associative array keys. - * - * Example: - * -------------- - * CData item1,item2; - * if (item1 < item2) { } - * -------------- - */ - override int opCmp(scope const Object o) scope const - { - const item = toType!(const Item)(o); - const t = cast(const CData) item; - return t !is null && (content != t.content - ? (content < t.content ? -1 : 1 ) : 0 ); - } - - /* - * Returns the hash of a CData - * - * You should rarely need to call this function. It exists so that CDatas - * can be used as associative array keys. - */ - override size_t toHash() scope const nothrow { return hash(content); } - - /* - * Returns a string representation of this CData section - */ - override string toString() scope const @safe pure nothrow { return cdata ~ content ~ "]]>"; } - - override @property @safe @nogc pure nothrow scope bool isEmptyXML() const { return false; } // Returns false always -} - -/* - * Class representing a text (aka Parsed Character Data) section - */ -class Text : Item -{ - private string content; - - /* - * Construct a text (aka PCData) section - * - * Params: - * content = the text. This function encodes the text before - * insertion, so it is safe to insert any text - * - * Example: - * -------------- - * auto Text = new CData("a < b"); - * // constructs a < b - * -------------- - */ - this(string content) @safe pure - { - this.content = encode(content); - } - - /* - * Compares two text sections for equality - * - * Example: - * -------------- - * Text item1,item2; - * if (item1 == item2) { } - * -------------- - */ - override bool opEquals(scope const Object o) const - { - const item = toType!(const Item)(o); - const t = cast(const Text) item; - return t !is null && content == t.content; - } - - /* - * Compares two text sections - * - * You should rarely need to call this function. It exists so that Texts - * can be used as associative array keys. - * - * Example: - * -------------- - * Text item1,item2; - * if (item1 < item2) { } - * -------------- - */ - override int opCmp(scope const Object o) scope const - { - const item = toType!(const Item)(o); - const t = cast(const Text) item; - return t !is null - && (content != t.content ? (content < t.content ? -1 : 1 ) : 0 ); - } - - /* - * Returns the hash of a text section - * - * You should rarely need to call this function. It exists so that Texts - * can be used as associative array keys. - */ - override size_t toHash() scope const nothrow { return hash(content); } - - /* - * Returns a string representation of this Text section - */ - override string toString() scope const @safe @nogc pure nothrow { return content; } - - /* - * Returns true if the content is the empty string - */ - override @property @safe @nogc pure nothrow scope bool isEmptyXML() const { return content.length == 0; } -} - -/* - * Class representing an XML Instruction section - */ -class XMLInstruction : Item -{ - private string content; - - /* - * Construct an XML Instruction section - * - * Params: - * content = the body of the instruction segment - * - * Throws: XIException if the segment body is illegal (contains ">") - * - * Example: - * -------------- - * auto item = new XMLInstruction("ATTLIST"); - * // constructs <!ATTLIST> - * -------------- - */ - this(string content) @safe pure - { - import std.string : indexOf; - if (content.indexOf(">") != -1) throw new XIException(content); - this.content = content; - } - - /* - * Compares two XML instructions for equality - * - * Example: - * -------------- - * XMLInstruction item1,item2; - * if (item1 == item2) { } - * -------------- - */ - override bool opEquals(scope const Object o) const - { - const item = toType!(const Item)(o); - const t = cast(const XMLInstruction) item; - return t !is null && content == t.content; - } - - /* - * Compares two XML instructions - * - * You should rarely need to call this function. It exists so that - * XmlInstructions can be used as associative array keys. - * - * Example: - * -------------- - * XMLInstruction item1,item2; - * if (item1 < item2) { } - * -------------- - */ - override int opCmp(scope const Object o) scope const - { - const item = toType!(const Item)(o); - const t = cast(const XMLInstruction) item; - return t !is null - && (content != t.content ? (content < t.content ? -1 : 1 ) : 0 ); - } - - /* - * Returns the hash of an XMLInstruction - * - * You should rarely need to call this function. It exists so that - * XmlInstructions can be used as associative array keys. - */ - override size_t toHash() scope const nothrow { return hash(content); } - - /* - * Returns a string representation of this XmlInstruction - */ - override string toString() scope const @safe pure nothrow { return "<!" ~ content ~ ">"; } - - override @property @safe @nogc pure nothrow scope bool isEmptyXML() const { return false; } // Returns false always -} - -/* - * Class representing a Processing Instruction section - */ -class ProcessingInstruction : Item -{ - private string content; - - /* - * Construct a Processing Instruction section - * - * Params: - * content = the body of the instruction segment - * - * Throws: PIException if the segment body is illegal (contains "?>") - * - * Example: - * -------------- - * auto item = new ProcessingInstruction("php"); - * // constructs <?php?> - * -------------- - */ - this(string content) @safe pure - { - import std.string : indexOf; - if (content.indexOf("?>") != -1) throw new PIException(content); - this.content = content; - } - - /* - * Compares two processing instructions for equality - * - * Example: - * -------------- - * ProcessingInstruction item1,item2; - * if (item1 == item2) { } - * -------------- - */ - override bool opEquals(scope const Object o) const - { - const item = toType!(const Item)(o); - const t = cast(const ProcessingInstruction) item; - return t !is null && content == t.content; - } - - /* - * Compares two processing instructions - * - * You should rarely need to call this function. It exists so that - * ProcessingInstructions can be used as associative array keys. - * - * Example: - * -------------- - * ProcessingInstruction item1,item2; - * if (item1 < item2) { } - * -------------- - */ - override int opCmp(scope const Object o) scope const - { - const item = toType!(const Item)(o); - const t = cast(const ProcessingInstruction) item; - return t !is null - && (content != t.content ? (content < t.content ? -1 : 1 ) : 0 ); - } - - /* - * Returns the hash of a ProcessingInstruction - * - * You should rarely need to call this function. It exists so that - * ProcessingInstructions can be used as associative array keys. - */ - override size_t toHash() scope const nothrow { return hash(content); } - - /* - * Returns a string representation of this ProcessingInstruction - */ - override string toString() scope const @safe pure nothrow { return "<?" ~ content ~ "?>"; } - - override @property @safe @nogc pure nothrow bool isEmptyXML() scope const { return false; } // Returns false always -} - -/* - * Abstract base class for XML items - */ -abstract class Item -{ - // Compares with another Item of same type for equality - abstract override bool opEquals(scope const Object o) @safe const; - - // Compares with another Item of same type - abstract override int opCmp(scope const Object o) @safe const; - - // Returns the hash of this item - abstract override size_t toHash() @safe scope const; - - // Returns a string representation of this item - abstract override string toString() @safe scope const; - - /* - * Returns an indented string representation of this item - * - * Params: - * indent = number of spaces by which to indent child elements - */ - string[] pretty(uint indent) @safe scope const - { - import std.string : strip; - string s = strip(toString()); - return s.length == 0 ? [] : [ s ]; - } - - // Returns true if the item represents empty XML text - abstract @property @safe @nogc pure nothrow bool isEmptyXML() scope const; -} - -/* - * Class for parsing an XML Document. - * - * This is a subclass of ElementParser. Most of the useful functions are - * documented there. - * - * Standards: $(LINK2 http://www.w3.org/TR/1998/REC-xml-19980210, XML 1.0) - * - * Bugs: - * Currently only supports UTF documents. - * - * If there is an encoding attribute in the prolog, it is ignored. - * - */ -class DocumentParser : ElementParser -{ - string xmlText; - - /* - * Constructs a DocumentParser. - * - * The input to this function MUST be valid XML. - * This is enforced by the function's in contract. - * - * Params: - * xmlText_ = the entire XML document as text - * - */ - this(string xmlText_) - in - { - assert(xmlText_.length != 0); - try - { - // Confirm that the input is valid XML - check(xmlText_); - } - catch (CheckException e) - { - // And if it's not, tell the user why not - assert(false, "\n" ~ e.toString()); - } - } - do - { - xmlText = xmlText_; - s = &xmlText; - super(); // Initialize everything - parse(); // Parse through the root tag (but not beyond) - } -} - -@system unittest -{ - auto doc = new Document("<root><child><grandchild/></child></root>"); - assert(doc.elements.length == 1); - assert(doc.elements[0].tag.name == "child"); - assert(doc.items == doc.elements); -} - -/* - * Class for parsing an XML element. - * - * Standards: $(LINK2 http://www.w3.org/TR/1998/REC-xml-19980210, XML 1.0) - * - * Note that you cannot construct instances of this class directly. You can - * construct a DocumentParser (which is a subclass of ElementParser), but - * otherwise, Instances of ElementParser will be created for you by the - * library, and passed your way via onStartTag handlers. - * - */ -class ElementParser -{ - alias Handler = void delegate(string); - alias ElementHandler = void delegate(in Element element); - alias ParserHandler = void delegate(ElementParser parser); - - private - { - Tag tag_; - string elementStart; - string* s; - - Handler commentHandler = null; - Handler cdataHandler = null; - Handler xiHandler = null; - Handler piHandler = null; - Handler rawTextHandler = null; - Handler textHandler = null; - - // Private constructor for start tags - this(ElementParser parent) @safe @nogc pure nothrow - { - s = parent.s; - this(); - tag_ = parent.tag_; - } - - // Private constructor for empty tags - this(Tag tag, string* t) @safe @nogc pure nothrow - { - s = t; - this(); - tag_ = tag; - } - } - - /* - * The Tag at the start of the element being parsed. You can read this to - * determine the tag's name and attributes. - */ - @property @safe @nogc pure nothrow const(Tag) tag() const { return tag_; } - - /* - * Register a handler which will be called whenever a start tag is - * encountered which matches the specified name. You can also pass null as - * the name, in which case the handler will be called for any unmatched - * start tag. - * - * Example: - * -------------- - * // Call this function whenever a <podcast> start tag is encountered - * onStartTag["podcast"] = (ElementParser xml) - * { - * // Your code here - * // - * // This is a a closure, so code here may reference - * // variables which are outside of this scope - * }; - * - * // call myEpisodeStartHandler (defined elsewhere) whenever an <episode> - * // start tag is encountered - * onStartTag["episode"] = &myEpisodeStartHandler; - * - * // call delegate dg for all other start tags - * onStartTag[null] = dg; - * -------------- - * - * This library will supply your function with a new instance of - * ElementHandler, which may be used to parse inside the element whose - * start tag was just found, or to identify the tag attributes of the - * element, etc. - * - * Note that your function will be called for both start tags and empty - * tags. That is, we make no distinction between <br></br> - * and <br/>. - */ - ParserHandler[string] onStartTag; - - /* - * Register a handler which will be called whenever an end tag is - * encountered which matches the specified name. You can also pass null as - * the name, in which case the handler will be called for any unmatched - * end tag. - * - * Example: - * -------------- - * // Call this function whenever a </podcast> end tag is encountered - * onEndTag["podcast"] = (in Element e) - * { - * // Your code here - * // - * // This is a a closure, so code here may reference - * // variables which are outside of this scope - * }; - * - * // call myEpisodeEndHandler (defined elsewhere) whenever an </episode> - * // end tag is encountered - * onEndTag["episode"] = &myEpisodeEndHandler; - * - * // call delegate dg for all other end tags - * onEndTag[null] = dg; - * -------------- - * - * Note that your function will be called for both start tags and empty - * tags. That is, we make no distinction between <br></br> - * and <br/>. - */ - ElementHandler[string] onEndTag; - - protected this() @safe @nogc pure nothrow - { - elementStart = *s; - } - - /* - * Register a handler which will be called whenever text is encountered. - * - * Example: - * -------------- - * // Call this function whenever text is encountered - * onText = (string s) - * { - * // Your code here - * - * // The passed parameter s will have been decoded by the time you see - * // it, and so may contain any character. - * // - * // This is a a closure, so code here may reference - * // variables which are outside of this scope - * }; - * -------------- - */ - @property @safe @nogc pure nothrow void onText(Handler handler) { textHandler = handler; } - - /* - * Register an alternative handler which will be called whenever text - * is encountered. This differs from onText in that onText will decode - * the text, whereas onTextRaw will not. This allows you to make design - * choices, since onText will be more accurate, but slower, while - * onTextRaw will be faster, but less accurate. Of course, you can - * still call decode() within your handler, if you want, but you'd - * probably want to use onTextRaw only in circumstances where you - * know that decoding is unnecessary. - * - * Example: - * -------------- - * // Call this function whenever text is encountered - * onText = (string s) - * { - * // Your code here - * - * // The passed parameter s will NOT have been decoded. - * // - * // This is a a closure, so code here may reference - * // variables which are outside of this scope - * }; - * -------------- - */ - @safe @nogc pure nothrow void onTextRaw(Handler handler) { rawTextHandler = handler; } - - /* - * Register a handler which will be called whenever a character data - * segment is encountered. - * - * Example: - * -------------- - * // Call this function whenever a CData section is encountered - * onCData = (string s) - * { - * // Your code here - * - * // The passed parameter s does not include the opening <![CDATA[ - * // nor closing ]]> - * // - * // This is a a closure, so code here may reference - * // variables which are outside of this scope - * }; - * -------------- - */ - @property @safe @nogc pure nothrow void onCData(Handler handler) { cdataHandler = handler; } - - /* - * Register a handler which will be called whenever a comment is - * encountered. - * - * Example: - * -------------- - * // Call this function whenever a comment is encountered - * onComment = (string s) - * { - * // Your code here - * - * // The passed parameter s does not include the opening <!-- nor - * // closing --> - * // - * // This is a a closure, so code here may reference - * // variables which are outside of this scope - * }; - * -------------- - */ - @property @safe @nogc pure nothrow void onComment(Handler handler) { commentHandler = handler; } - - /* - * Register a handler which will be called whenever a processing - * instruction is encountered. - * - * Example: - * -------------- - * // Call this function whenever a processing instruction is encountered - * onPI = (string s) - * { - * // Your code here - * - * // The passed parameter s does not include the opening <? nor - * // closing ?> - * // - * // This is a a closure, so code here may reference - * // variables which are outside of this scope - * }; - * -------------- - */ - @property @safe @nogc pure nothrow void onPI(Handler handler) { piHandler = handler; } - - /* - * Register a handler which will be called whenever an XML instruction is - * encountered. - * - * Example: - * -------------- - * // Call this function whenever an XML instruction is encountered - * // (Note: XML instructions may only occur preceding the root tag of a - * // document). - * onPI = (string s) - * { - * // Your code here - * - * // The passed parameter s does not include the opening <! nor - * // closing > - * // - * // This is a a closure, so code here may reference - * // variables which are outside of this scope - * }; - * -------------- - */ - @property @safe @nogc pure nothrow void onXI(Handler handler) { xiHandler = handler; } - - /* - * Parse an XML element. - * - * Parsing will continue until the end of the current element. Any items - * encountered for which a handler has been registered will invoke that - * handler. - * - * Throws: various kinds of XMLException - */ - void parse() - { - import std.algorithm.searching : startsWith; - import std.string : indexOf; - - string t; - const Tag root = tag_; - Tag[string] startTags; - if (tag_ !is null) startTags[tag_.name] = tag_; - - while (s.length != 0) - { - if (startsWith(*s,"<!--")) - { - chop(*s,4); - t = chop(*s,indexOf(*s,"-->")); - if (commentHandler.funcptr !is null) commentHandler(t); - chop(*s,3); - } - else if (startsWith(*s,"<![CDATA[")) - { - chop(*s,9); - t = chop(*s,indexOf(*s,"]]>")); - if (cdataHandler.funcptr !is null) cdataHandler(t); - chop(*s,3); - } - else if (startsWith(*s,"<!")) - { - chop(*s,2); - t = chop(*s,indexOf(*s,">")); - if (xiHandler.funcptr !is null) xiHandler(t); - chop(*s,1); - } - else if (startsWith(*s,"<?")) - { - chop(*s,2); - t = chop(*s,indexOf(*s,"?>")); - if (piHandler.funcptr !is null) piHandler(t); - chop(*s,2); - } - else if (startsWith(*s,"<")) - { - tag_ = new Tag(*s,true); - if (root is null) - return; // Return to constructor of derived class - - if (tag_.isStart) - { - startTags[tag_.name] = tag_; - - auto parser = new ElementParser(this); - - auto handler = tag_.name in onStartTag; - if (handler !is null) (*handler)(parser); - else - { - handler = null in onStartTag; - if (handler !is null) (*handler)(parser); - } - } - else if (tag_.isEnd) - { - const startTag = startTags[tag_.name]; - string text; - - if (startTag.tagString.length == 0) - assert(0); - - immutable(char)* p = startTag.tagString.ptr - + startTag.tagString.length; - immutable(char)* q = &tag_.tagString[0]; - text = decode(p[0..(q-p)], DecodeMode.LOOSE); - - auto element = new Element(startTag); - if (text.length != 0) element ~= new Text(text); - - auto handler = tag_.name in onEndTag; - if (handler !is null) (*handler)(element); - else - { - handler = null in onEndTag; - if (handler !is null) (*handler)(element); - } - - if (tag_.name == root.name) return; - } - else if (tag_.isEmpty) - { - Tag startTag = new Tag(tag_.name); - - // FIX by hed010gy - // https://issues.dlang.org/show_bug.cgi?id=2979 - if (tag_.attr.length > 0) - foreach (tn,tv; tag_.attr) startTag.attr[tn]=tv; - // END FIX - - // Handle the pretend start tag - string s2; - auto parser = new ElementParser(startTag,&s2); - auto handler1 = startTag.name in onStartTag; - if (handler1 !is null) (*handler1)(parser); - else - { - handler1 = null in onStartTag; - if (handler1 !is null) (*handler1)(parser); - } - - // Handle the pretend end tag - auto element = new Element(startTag); - auto handler2 = tag_.name in onEndTag; - if (handler2 !is null) (*handler2)(element); - else - { - handler2 = null in onEndTag; - if (handler2 !is null) (*handler2)(element); - } - } - } - else - { - t = chop(*s,indexOf(*s,"<")); - if (rawTextHandler.funcptr !is null) - rawTextHandler(t); - else if (textHandler.funcptr !is null) - textHandler(decode(t,DecodeMode.LOOSE)); - } - } - } - - /* - * Returns that part of the element which has already been parsed - */ - override string toString() const @nogc @safe pure nothrow - { - assert(elementStart.length >= s.length); - return elementStart[0 .. elementStart.length - s.length]; - } - -} - -private -{ - template Check(string msg) - { - string old = s; - - void fail() @safe pure - { - s = old; - throw new Err(s,msg); - } - - void fail(Err e) @safe pure - { - s = old; - throw new Err(s,msg,e); - } - - void fail(string msg2) @safe pure - { - fail(new Err(s,msg2)); - } - } - - void checkMisc(ref string s) @safe pure // rule 27 - { - import std.algorithm.searching : startsWith; - - mixin Check!("Misc"); - - try - { - if (s.startsWith("<!--")) { checkComment(s); } - else if (s.startsWith("<?")) { checkPI(s); } - else { checkSpace(s); } - } - catch (Err e) { fail(e); } - } - - void checkDocument(ref string s) @safe pure // rule 1 - { - mixin Check!("Document"); - try - { - checkProlog(s); - checkElement(s); - star!(checkMisc)(s); - } - catch (Err e) { fail(e); } - } - - void checkChars(ref string s) @safe pure // rule 2 - { - // TO DO - Fix std.utf stride and decode functions, then use those - // instead - import std.format : format; - - mixin Check!("Chars"); - - dchar c; - ptrdiff_t n = -1; - // 'i' must not be smaller than size_t because size_t is used internally in - // aApply.d and it will be cast e.g to (int *) which fails on BigEndian targets. - foreach (size_t i, dchar d; s) - { - if (!isChar(d)) - { - c = d; - n = i; - break; - } - } - if (n != -1) - { - s = s[n..$]; - fail(format("invalid character: U+%04X",c)); - } - } - - void checkSpace(ref string s) @safe pure // rule 3 - { - import std.algorithm.searching : countUntil; - import std.ascii : isWhite; - import std.utf : byCodeUnit; - - mixin Check!("Whitespace"); - ptrdiff_t i = s.byCodeUnit.countUntil!(a => !isWhite(a)); - if (i == -1 && s.length > 0 && isWhite(s[0])) - s = s[$ .. $]; - else if (i > -1) - s = s[i .. $]; - if (s is old) fail(); - } - - void checkName(ref string s, out string name) @safe pure // rule 5 - { - mixin Check!("Name"); - - if (s.length == 0) fail(); - ptrdiff_t n; - // 'i' must not be smaller than size_t because size_t is used internally in - // aApply.d and it will be cast e.g to (int *) which fails on BigEndian targets. - foreach (size_t i, dchar c; s) - { - if (c == '_' || c == ':' || isLetter(c)) continue; - if (i == 0) fail(); - if (c == '-' || c == '.' || isDigit(c) - || isCombiningChar(c) || isExtender(c)) continue; - n = i; - break; - } - name = s[0 .. n]; - s = s[n..$]; - } - - void checkAttValue(ref string s) @safe pure // rule 10 - { - import std.algorithm.searching : countUntil; - import std.utf : byCodeUnit; - - mixin Check!("AttValue"); - - if (s.length == 0) fail(); - char c = s[0]; - if (c != '\u0022' && c != '\u0027') - fail("attribute value requires quotes"); - s = s[1..$]; - for (;;) - { - s = s[s.byCodeUnit.countUntil(c) .. $]; - if (s.length == 0) fail("unterminated attribute value"); - if (s[0] == '<') fail("< found in attribute value"); - if (s[0] == c) break; - try { checkReference(s); } catch (Err e) { fail(e); } - } - s = s[1..$]; - } - - void checkCharData(ref string s) @safe pure // rule 14 - { - import std.algorithm.searching : startsWith; - - mixin Check!("CharData"); - - while (s.length != 0) - { - if (s.startsWith("&")) break; - if (s.startsWith("<")) break; - if (s.startsWith("]]>")) fail("]]> found within char data"); - s = s[1..$]; - } - } - - void checkComment(ref string s) @safe pure // rule 15 - { - import std.string : indexOf; - - mixin Check!("Comment"); - - try { checkLiteral("<!--",s); } catch (Err e) { fail(e); } - ptrdiff_t n = s.indexOf("--"); - if (n == -1) fail("unterminated comment"); - s = s[n..$]; - try { checkLiteral("-->",s); } catch (Err e) { fail(e); } - } - - void checkPI(ref string s) @safe pure // rule 16 - { - mixin Check!("PI"); - - try - { - checkLiteral("<?",s); - checkEnd("?>",s); - } - catch (Err e) { fail(e); } - } - - void checkCDSect(ref string s) @safe pure // rule 18 - { - mixin Check!("CDSect"); - - try - { - checkLiteral(cdata,s); - checkEnd("]]>",s); - } - catch (Err e) { fail(e); } - } - - void checkProlog(ref string s) @safe pure // rule 22 - { - mixin Check!("Prolog"); - - try - { - /* The XML declaration is optional - * http://www.w3.org/TR/2008/REC-xml-20081126/#NT-prolog - */ - opt!(checkXMLDecl)(s); - - star!(checkMisc)(s); - opt!(seq!(checkDocTypeDecl,star!(checkMisc)))(s); - } - catch (Err e) { fail(e); } - } - - void checkXMLDecl(ref string s) @safe pure // rule 23 - { - mixin Check!("XMLDecl"); - - try - { - checkLiteral("<?xml",s); - checkVersionInfo(s); - opt!(checkEncodingDecl)(s); - opt!(checkSDDecl)(s); - opt!(checkSpace)(s); - checkLiteral("?>",s); - } - catch (Err e) { fail(e); } - } - - void checkVersionInfo(ref string s) @safe pure // rule 24 - { - mixin Check!("VersionInfo"); - - try - { - checkSpace(s); - checkLiteral("version",s); - checkEq(s); - quoted!(checkVersionNum)(s); - } - catch (Err e) { fail(e); } - } - - void checkEq(ref string s) @safe pure // rule 25 - { - mixin Check!("Eq"); - - try - { - opt!(checkSpace)(s); - checkLiteral("=",s); - opt!(checkSpace)(s); - } - catch (Err e) { fail(e); } - } - - void checkVersionNum(ref string s) @safe pure // rule 26 - { - import std.algorithm.searching : countUntil; - import std.utf : byCodeUnit; - - mixin Check!("VersionNum"); - - s = s[s.byCodeUnit.countUntil('\"') .. $]; - if (s is old) fail(); - } - - void checkDocTypeDecl(ref string s) @safe pure // rule 28 - { - mixin Check!("DocTypeDecl"); - - try - { - checkLiteral("<!DOCTYPE",s); - // - // TO DO -- ensure DOCTYPE is well formed - // (But not yet. That's one of our "future directions") - // - checkEnd(">",s); - } - catch (Err e) { fail(e); } - } - - void checkSDDecl(ref string s) @safe pure // rule 32 - { - import std.algorithm.searching : startsWith; - - mixin Check!("SDDecl"); - - try - { - checkSpace(s); - checkLiteral("standalone",s); - checkEq(s); - } - catch (Err e) { fail(e); } - - int n = 0; - if (s.startsWith("'yes'") || s.startsWith("\"yes\"")) n = 5; - else if (s.startsWith("'no'" ) || s.startsWith("\"no\"" )) n = 4; - else fail("standalone attribute value must be 'yes', \"yes\","~ - " 'no' or \"no\""); - s = s[n..$]; - } - - void checkElement(ref string s) @safe pure // rule 39 - { - mixin Check!("Element"); - - string sname,ename,t; - try { checkTag(s,t,sname); } catch (Err e) { fail(e); } - - if (t == "STag") - { - try - { - checkContent(s); - t = s; - checkETag(s,ename); - } - catch (Err e) { fail(e); } - - if (sname != ename) - { - s = t; - fail("end tag name \"" ~ ename - ~ "\" differs from start tag name \""~sname~"\""); - } - } - } - - // rules 40 and 44 - void checkTag(ref string s, out string type, out string name) @safe pure - { - mixin Check!("Tag"); - - try - { - type = "STag"; - checkLiteral("<",s); - checkName(s,name); - star!(seq!(checkSpace,checkAttribute))(s); - opt!(checkSpace)(s); - if (s.length != 0 && s[0] == '/') - { - s = s[1..$]; - type = "ETag"; - } - checkLiteral(">",s); - } - catch (Err e) { fail(e); } - } - - void checkAttribute(ref string s) @safe pure // rule 41 - { - mixin Check!("Attribute"); - - try - { - string name; - checkName(s,name); - checkEq(s); - checkAttValue(s); - } - catch (Err e) { fail(e); } - } - - void checkETag(ref string s, out string name) @safe pure // rule 42 - { - mixin Check!("ETag"); - - try - { - checkLiteral("</",s); - checkName(s,name); - opt!(checkSpace)(s); - checkLiteral(">",s); - } - catch (Err e) { fail(e); } - } - - void checkContent(ref string s) @safe pure // rule 43 - { - import std.algorithm.searching : startsWith; - - mixin Check!("Content"); - - try - { - while (s.length != 0) - { - old = s; - if (s.startsWith("&")) { checkReference(s); } - else if (s.startsWith("<!--")) { checkComment(s); } - else if (s.startsWith("<?")) { checkPI(s); } - else if (s.startsWith(cdata)) { checkCDSect(s); } - else if (s.startsWith("</")) { break; } - else if (s.startsWith("<")) { checkElement(s); } - else { checkCharData(s); } - } - } - catch (Err e) { fail(e); } - } - - void checkCharRef(ref string s, out dchar c) @safe pure // rule 66 - { - import std.format : format; - - mixin Check!("CharRef"); - - c = 0; - try { checkLiteral("&#",s); } catch (Err e) { fail(e); } - int radix = 10; - if (s.length != 0 && s[0] == 'x') - { - s = s[1..$]; - radix = 16; - } - if (s.length == 0) fail("unterminated character reference"); - if (s[0] == ';') - fail("character reference must have at least one digit"); - while (s.length != 0) - { - immutable char d = s[0]; - int n = 0; - switch (d) - { - case 'F','f': ++n; goto case; - case 'E','e': ++n; goto case; - case 'D','d': ++n; goto case; - case 'C','c': ++n; goto case; - case 'B','b': ++n; goto case; - case 'A','a': ++n; goto case; - case '9': ++n; goto case; - case '8': ++n; goto case; - case '7': ++n; goto case; - case '6': ++n; goto case; - case '5': ++n; goto case; - case '4': ++n; goto case; - case '3': ++n; goto case; - case '2': ++n; goto case; - case '1': ++n; goto case; - case '0': break; - default: n = 100; break; - } - if (n >= radix) break; - c *= radix; - c += n; - s = s[1..$]; - } - if (!isChar(c)) fail(format("U+%04X is not a legal character",c)); - if (s.length == 0 || s[0] != ';') fail("expected ;"); - else s = s[1..$]; - } - - void checkReference(ref string s) @safe pure // rule 67 - { - import std.algorithm.searching : startsWith; - - mixin Check!("Reference"); - - try - { - dchar c; - if (s.startsWith("&#")) checkCharRef(s,c); - else checkEntityRef(s); - } - catch (Err e) { fail(e); } - } - - void checkEntityRef(ref string s) @safe pure // rule 68 - { - mixin Check!("EntityRef"); - - try - { - string name; - checkLiteral("&",s); - checkName(s,name); - checkLiteral(";",s); - } - catch (Err e) { fail(e); } - } - - void checkEncName(ref string s) @safe pure // rule 81 - { - import std.algorithm.searching : countUntil; - import std.ascii : isAlpha; - import std.utf : byCodeUnit; - - mixin Check!("EncName"); - - s = s[s.byCodeUnit.countUntil!(a => !isAlpha(a)) .. $]; - if (s is old) fail(); - s = s[s.byCodeUnit.countUntil('\"', '\'') .. $]; - } - - void checkEncodingDecl(ref string s) @safe pure // rule 80 - { - mixin Check!("EncodingDecl"); - - try - { - checkSpace(s); - checkLiteral("encoding",s); - checkEq(s); - quoted!(checkEncName)(s); - } - catch (Err e) { fail(e); } - } - - // Helper functions - - void checkLiteral(string literal,ref string s) @safe pure - { - import std.string : startsWith; - - mixin Check!("Literal"); - - if (!s.startsWith(literal)) fail("Expected literal \""~literal~"\""); - s = s[literal.length..$]; - } - - void checkEnd(string end,ref string s) @safe pure - { - import std.string : indexOf; - // Deliberately no mixin Check here. - - auto n = s.indexOf(end); - if (n == -1) throw new Err(s,"Unable to find terminating \""~end~"\""); - s = s[n..$]; - checkLiteral(end,s); - } - - // Metafunctions -- none of these use mixin Check - - void opt(alias f)(ref string s) - { - try { f(s); } catch (Err e) {} - } - - void plus(alias f)(ref string s) - { - f(s); - star!(f)(s); - } - - void star(alias f)(ref string s) - { - while (s.length != 0) - { - try { f(s); } - catch (Err e) { return; } - } - } - - void quoted(alias f)(ref string s) - { - import std.string : startsWith; - - if (s.startsWith("'")) - { - checkLiteral("'",s); - f(s); - checkLiteral("'",s); - } - else - { - checkLiteral("\"",s); - f(s); - checkLiteral("\"",s); - } - } - - void seq(alias f,alias g)(ref string s) - { - f(s); - g(s); - } -} - -/* - * Check an entire XML document for well-formedness - * - * Params: - * s = the document to be checked, passed as a string - * - * Throws: CheckException if the document is not well formed - * - * CheckException's toString() method will yield the complete hierarchy of - * parse failure (the XML equivalent of a stack trace), giving the line and - * column number of every failure at every level. - */ -void check(string s) @safe pure -{ - try - { - checkChars(s); - checkDocument(s); - if (s.length != 0) throw new Err(s,"Junk found after document"); - } - catch (Err e) - { - e.complete(s); - throw e; - } -} - -@system pure unittest -{ - import std.string : indexOf; - - try - { - check(q"[<?xml version="1.0"?> - <catalog> - <book id="bk101"> - <author>Gambardella, Matthew</author> - <title>XML Developer's Guide</title> - <genre>Computer</genre> - <price>44.95</price> - <publish_date>2000-10-01</publish_date> - <description>An in-depth look at creating applications - with XML.</description> - </book> - <book id="bk102"> - <author>Ralls, Kim</author> - <title>Midnight Rain</title> - <genre>Fantasy</genres> - <price>5.95</price> - <publish_date>2000-12-16</publish_date> - <description>A former architect battles corporate zombies, - an evil sorceress, and her own childhood to become queen - of the world.</description> - </book> - <book id="bk103"> - <author>Corets, Eva</author> - <title>Maeve Ascendant</title> - <genre>Fantasy</genre> - <price>5.95</price> - <publish_date>2000-11-17</publish_date> - <description>After the collapse of a nanotechnology - society in England, the young survivors lay the - foundation for a new society.</description> - </book> - </catalog> - ]"); - assert(false); - } - catch (CheckException e) - { - auto n = e.toString().indexOf("end tag name \"genres\" differs"~ - " from start tag name \"genre\""); - assert(n != -1); - } -} - -@system unittest -{ - string s = q"EOS -<?xml version="1.0"?> -<set> - <one>A</one> - <!-- comment --> - <two>B</two> -</set> -EOS"; - try - { - check(s); - } - catch (CheckException e) - { - assert(0, e.toString()); - } -} - -@system unittest -{ - string test_xml = `<?xml version="1.0" encoding='UTF-8'?><r><stream:stream - xmlns:stream="http://etherx.'jabber'.org/streams" - xmlns="jabber:'client'" from='jid.pl' id="587a5767" - xml:lang="en" version="1.0" attr='a"b"c'> - </stream:stream></r>`; - - DocumentParser parser = new DocumentParser(test_xml); - bool tested = false; - parser.onStartTag["stream:stream"] = (ElementParser p) { - assert(p.tag.attr["xmlns"] == "jabber:'client'"); - assert(p.tag.attr["from"] == "jid.pl"); - assert(p.tag.attr["attr"] == "a\"b\"c"); - tested = true; - }; - parser.parse(); - assert(tested); -} - -@system unittest -{ - string s = q"EOS -<?xml version="1.0" encoding="utf-8"?> <Tests> - <Test thing="What & Up">What & Up Second</Test> -</Tests> -EOS"; - auto xml = new DocumentParser(s); - - xml.onStartTag["Test"] = (ElementParser xml) { - assert(xml.tag.attr["thing"] == "What & Up"); - }; - - xml.onEndTag["Test"] = (in Element e) { - assert(e.text() == "What & Up Second"); - }; - xml.parse(); -} - -@system unittest -{ - string s = `<tag attr=""value>" />`; - auto doc = new Document(s); - assert(doc.toString() == s); -} - -/* The base class for exceptions thrown by this module */ -class XMLException : Exception { this(string msg) @safe pure { super(msg); } } - -// Other exceptions - -// Thrown during Comment constructor -class CommentException : XMLException -{ private this(string msg) @safe pure { super(msg); } } - -// Thrown during CData constructor -class CDataException : XMLException -{ private this(string msg) @safe pure { super(msg); } } - -// Thrown during XMLInstruction constructor -class XIException : XMLException -{ private this(string msg) @safe pure { super(msg); } } - -// Thrown during ProcessingInstruction constructor -class PIException : XMLException -{ private this(string msg) @safe pure { super(msg); } } - -// Thrown during Text constructor -class TextException : XMLException -{ private this(string msg) @safe pure { super(msg); } } - -// Thrown during decode() -class DecodeException : XMLException -{ private this(string msg) @safe pure { super(msg); } } - -// Thrown if comparing with wrong type -class InvalidTypeException : XMLException -{ private this(string msg) @safe pure { super(msg); } } - -// Thrown when parsing for Tags -class TagException : XMLException -{ private this(string msg) @safe pure { super(msg); } } - -/* - * Thrown during check() - */ -class CheckException : XMLException -{ - CheckException err; // Parent in hierarchy - private string tail; - /* - * Name of production rule which failed to parse, - * or specific error message - */ - string msg; - size_t line = 0; // Line number at which parse failure occurred - size_t column = 0; // Column number at which parse failure occurred - - private this(string tail,string msg,Err err=null) @safe pure - { - super(null); - this.tail = tail; - this.msg = msg; - this.err = err; - } - - private void complete(string entire) @safe pure - { - import std.string : count, lastIndexOf; - import std.utf : toUTF32; - - string head = entire[0..$-tail.length]; - ptrdiff_t n = head.lastIndexOf('\n') + 1; - line = head.count("\n") + 1; - dstring t = toUTF32(head[n..$]); - column = t.length + 1; - if (err !is null) err.complete(entire); - } - - override string toString() const @safe pure - { - import std.format : format; - - string s; - if (line != 0) s = format("Line %d, column %d: ",line,column); - s ~= msg; - s ~= '\n'; - if (err !is null) s = err.toString() ~ s; - return s; - } -} - -private alias Err = CheckException; - -// Private helper functions - -private -{ - inout(T) toType(T)(inout return scope Object o) - { - T t = cast(T)(o); - if (t is null) - { - throw new InvalidTypeException("Attempt to compare a " - ~ T.stringof ~ " with an instance of another type"); - } - return t; - } - - string chop(ref string s, size_t n) @safe pure nothrow - { - if (n == -1) n = s.length; - string t = s[0 .. n]; - s = s[n..$]; - return t; - } - - bool optc(ref string s, char c) @safe pure nothrow - { - immutable bool b = s.length != 0 && s[0] == c; - if (b) s = s[1..$]; - return b; - } - - void reqc(ref string s, char c) @safe pure - { - if (s.length == 0 || s[0] != c) throw new TagException(""); - s = s[1..$]; - } - - char requireOneOf(ref string s, string chars) @safe pure - { - import std.string : indexOf; - - if (s.length == 0 || indexOf(chars,s[0]) == -1) - throw new TagException(""); - immutable char ch = s[0]; - s = s[1..$]; - return ch; - } - - alias hash = .hashOf; - - // Definitions from the XML specification - immutable CharTable=[0x9,0x9,0xA,0xA,0xD,0xD,0x20,0xD7FF,0xE000,0xFFFD, - 0x10000,0x10FFFF]; - immutable BaseCharTable=[0x0041,0x005A,0x0061,0x007A,0x00C0,0x00D6,0x00D8, - 0x00F6,0x00F8,0x00FF,0x0100,0x0131,0x0134,0x013E,0x0141,0x0148,0x014A, - 0x017E,0x0180,0x01C3,0x01CD,0x01F0,0x01F4,0x01F5,0x01FA,0x0217,0x0250, - 0x02A8,0x02BB,0x02C1,0x0386,0x0386,0x0388,0x038A,0x038C,0x038C,0x038E, - 0x03A1,0x03A3,0x03CE,0x03D0,0x03D6,0x03DA,0x03DA,0x03DC,0x03DC,0x03DE, - 0x03DE,0x03E0,0x03E0,0x03E2,0x03F3,0x0401,0x040C,0x040E,0x044F,0x0451, - 0x045C,0x045E,0x0481,0x0490,0x04C4,0x04C7,0x04C8,0x04CB,0x04CC,0x04D0, - 0x04EB,0x04EE,0x04F5,0x04F8,0x04F9,0x0531,0x0556,0x0559,0x0559,0x0561, - 0x0586,0x05D0,0x05EA,0x05F0,0x05F2,0x0621,0x063A,0x0641,0x064A,0x0671, - 0x06B7,0x06BA,0x06BE,0x06C0,0x06CE,0x06D0,0x06D3,0x06D5,0x06D5,0x06E5, - 0x06E6,0x0905,0x0939,0x093D,0x093D,0x0958,0x0961,0x0985,0x098C,0x098F, - 0x0990,0x0993,0x09A8,0x09AA,0x09B0,0x09B2,0x09B2,0x09B6,0x09B9,0x09DC, - 0x09DD,0x09DF,0x09E1,0x09F0,0x09F1,0x0A05,0x0A0A,0x0A0F,0x0A10,0x0A13, - 0x0A28,0x0A2A,0x0A30,0x0A32,0x0A33,0x0A35,0x0A36,0x0A38,0x0A39,0x0A59, - 0x0A5C,0x0A5E,0x0A5E,0x0A72,0x0A74,0x0A85,0x0A8B,0x0A8D,0x0A8D,0x0A8F, - 0x0A91,0x0A93,0x0AA8,0x0AAA,0x0AB0,0x0AB2,0x0AB3,0x0AB5,0x0AB9,0x0ABD, - 0x0ABD,0x0AE0,0x0AE0,0x0B05,0x0B0C,0x0B0F,0x0B10,0x0B13,0x0B28,0x0B2A, - 0x0B30,0x0B32,0x0B33,0x0B36,0x0B39,0x0B3D,0x0B3D,0x0B5C,0x0B5D,0x0B5F, - 0x0B61,0x0B85,0x0B8A,0x0B8E,0x0B90,0x0B92,0x0B95,0x0B99,0x0B9A,0x0B9C, - 0x0B9C,0x0B9E,0x0B9F,0x0BA3,0x0BA4,0x0BA8,0x0BAA,0x0BAE,0x0BB5,0x0BB7, - 0x0BB9,0x0C05,0x0C0C,0x0C0E,0x0C10,0x0C12,0x0C28,0x0C2A,0x0C33,0x0C35, - 0x0C39,0x0C60,0x0C61,0x0C85,0x0C8C,0x0C8E,0x0C90,0x0C92,0x0CA8,0x0CAA, - 0x0CB3,0x0CB5,0x0CB9,0x0CDE,0x0CDE,0x0CE0,0x0CE1,0x0D05,0x0D0C,0x0D0E, - 0x0D10,0x0D12,0x0D28,0x0D2A,0x0D39,0x0D60,0x0D61,0x0E01,0x0E2E,0x0E30, - 0x0E30,0x0E32,0x0E33,0x0E40,0x0E45,0x0E81,0x0E82,0x0E84,0x0E84,0x0E87, - 0x0E88,0x0E8A,0x0E8A,0x0E8D,0x0E8D,0x0E94,0x0E97,0x0E99,0x0E9F,0x0EA1, - 0x0EA3,0x0EA5,0x0EA5,0x0EA7,0x0EA7,0x0EAA,0x0EAB,0x0EAD,0x0EAE,0x0EB0, - 0x0EB0,0x0EB2,0x0EB3,0x0EBD,0x0EBD,0x0EC0,0x0EC4,0x0F40,0x0F47,0x0F49, - 0x0F69,0x10A0,0x10C5,0x10D0,0x10F6,0x1100,0x1100,0x1102,0x1103,0x1105, - 0x1107,0x1109,0x1109,0x110B,0x110C,0x110E,0x1112,0x113C,0x113C,0x113E, - 0x113E,0x1140,0x1140,0x114C,0x114C,0x114E,0x114E,0x1150,0x1150,0x1154, - 0x1155,0x1159,0x1159,0x115F,0x1161,0x1163,0x1163,0x1165,0x1165,0x1167, - 0x1167,0x1169,0x1169,0x116D,0x116E,0x1172,0x1173,0x1175,0x1175,0x119E, - 0x119E,0x11A8,0x11A8,0x11AB,0x11AB,0x11AE,0x11AF,0x11B7,0x11B8,0x11BA, - 0x11BA,0x11BC,0x11C2,0x11EB,0x11EB,0x11F0,0x11F0,0x11F9,0x11F9,0x1E00, - 0x1E9B,0x1EA0,0x1EF9,0x1F00,0x1F15,0x1F18,0x1F1D,0x1F20,0x1F45,0x1F48, - 0x1F4D,0x1F50,0x1F57,0x1F59,0x1F59,0x1F5B,0x1F5B,0x1F5D,0x1F5D,0x1F5F, - 0x1F7D,0x1F80,0x1FB4,0x1FB6,0x1FBC,0x1FBE,0x1FBE,0x1FC2,0x1FC4,0x1FC6, - 0x1FCC,0x1FD0,0x1FD3,0x1FD6,0x1FDB,0x1FE0,0x1FEC,0x1FF2,0x1FF4,0x1FF6, - 0x1FFC,0x2126,0x2126,0x212A,0x212B,0x212E,0x212E,0x2180,0x2182,0x3041, - 0x3094,0x30A1,0x30FA,0x3105,0x312C,0xAC00,0xD7A3]; - immutable IdeographicTable=[0x3007,0x3007,0x3021,0x3029,0x4E00,0x9FA5]; - immutable CombiningCharTable=[0x0300,0x0345,0x0360,0x0361,0x0483,0x0486, - 0x0591,0x05A1,0x05A3,0x05B9,0x05BB,0x05BD,0x05BF,0x05BF,0x05C1,0x05C2, - 0x05C4,0x05C4,0x064B,0x0652,0x0670,0x0670,0x06D6,0x06DC,0x06DD,0x06DF, - 0x06E0,0x06E4,0x06E7,0x06E8,0x06EA,0x06ED,0x0901,0x0903,0x093C,0x093C, - 0x093E,0x094C,0x094D,0x094D,0x0951,0x0954,0x0962,0x0963,0x0981,0x0983, - 0x09BC,0x09BC,0x09BE,0x09BE,0x09BF,0x09BF,0x09C0,0x09C4,0x09C7,0x09C8, - 0x09CB,0x09CD,0x09D7,0x09D7,0x09E2,0x09E3,0x0A02,0x0A02,0x0A3C,0x0A3C, - 0x0A3E,0x0A3E,0x0A3F,0x0A3F,0x0A40,0x0A42,0x0A47,0x0A48,0x0A4B,0x0A4D, - 0x0A70,0x0A71,0x0A81,0x0A83,0x0ABC,0x0ABC,0x0ABE,0x0AC5,0x0AC7,0x0AC9, - 0x0ACB,0x0ACD,0x0B01,0x0B03,0x0B3C,0x0B3C,0x0B3E,0x0B43,0x0B47,0x0B48, - 0x0B4B,0x0B4D,0x0B56,0x0B57,0x0B82,0x0B83,0x0BBE,0x0BC2,0x0BC6,0x0BC8, - 0x0BCA,0x0BCD,0x0BD7,0x0BD7,0x0C01,0x0C03,0x0C3E,0x0C44,0x0C46,0x0C48, - 0x0C4A,0x0C4D,0x0C55,0x0C56,0x0C82,0x0C83,0x0CBE,0x0CC4,0x0CC6,0x0CC8, - 0x0CCA,0x0CCD,0x0CD5,0x0CD6,0x0D02,0x0D03,0x0D3E,0x0D43,0x0D46,0x0D48, - 0x0D4A,0x0D4D,0x0D57,0x0D57,0x0E31,0x0E31,0x0E34,0x0E3A,0x0E47,0x0E4E, - 0x0EB1,0x0EB1,0x0EB4,0x0EB9,0x0EBB,0x0EBC,0x0EC8,0x0ECD,0x0F18,0x0F19, - 0x0F35,0x0F35,0x0F37,0x0F37,0x0F39,0x0F39,0x0F3E,0x0F3E,0x0F3F,0x0F3F, - 0x0F71,0x0F84,0x0F86,0x0F8B,0x0F90,0x0F95,0x0F97,0x0F97,0x0F99,0x0FAD, - 0x0FB1,0x0FB7,0x0FB9,0x0FB9,0x20D0,0x20DC,0x20E1,0x20E1,0x302A,0x302F, - 0x3099,0x3099,0x309A,0x309A]; - immutable DigitTable=[0x0030,0x0039,0x0660,0x0669,0x06F0,0x06F9,0x0966, - 0x096F,0x09E6,0x09EF,0x0A66,0x0A6F,0x0AE6,0x0AEF,0x0B66,0x0B6F,0x0BE7, - 0x0BEF,0x0C66,0x0C6F,0x0CE6,0x0CEF,0x0D66,0x0D6F,0x0E50,0x0E59,0x0ED0, - 0x0ED9,0x0F20,0x0F29]; - immutable ExtenderTable=[0x00B7,0x00B7,0x02D0,0x02D0,0x02D1,0x02D1,0x0387, - 0x0387,0x0640,0x0640,0x0E46,0x0E46,0x0EC6,0x0EC6,0x3005,0x3005,0x3031, - 0x3035,0x309D,0x309E,0x30FC,0x30FE]; - - bool lookup(const(int)[] table, int c) @safe @nogc nothrow pure - { - while (table.length != 0) - { - auto m = (table.length >> 1) & ~1; - if (c < table[m]) - { - table = table[0 .. m]; - } - else if (c > table[m+1]) - { - table = table[m+2..$]; - } - else return true; - } - return false; - } - - string startOf(string s) @safe nothrow pure - { - string r; - foreach (char c;s) - { - r ~= (c < 0x20 || c > 0x7F) ? '.' : c; - if (r.length >= 40) { r ~= "___"; break; } - } - return r; - } - - void exit(string s=null) - { - throw new XMLException(s); - } -} diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index e6722cf..a1585d8 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,87 @@ +2022-09-28 Jonathan Wakely <jwakely@redhat.com> + + * doc/xml/manual/evolution.xml: Document std::bind API + changes. + * doc/xml/manual/intro.xml: Document LWG 2487 status. + * doc/xml/manual/using.xml: Clarify default value of + _GLIBCXX_USE_DEPRECATED. + * doc/html/*: Regenerate. + * include/std/functional (_Bind::operator()(Args&&...) volatile) + (_Bind::operator()(Args&&...) const volatile) + (_Bind_result::operator()(Args&&...) volatile) + (_Bind_result::operator()(Args&&...) const volatile): Replace + with deleted overload for C++20 and later. + * testsuite/20_util/bind/cv_quals.cc: Check for deprecated + warnings in C++17. + * testsuite/20_util/bind/cv_quals_2.cc: Likewise, and check for + ill-formed in C++20. + +2022-09-28 Jonathan Wakely <jwakely@redhat.com> + + PR libstdc++/70692 + * include/bits/invoke.h [__cplusplus < 201703] (__invoke_r): + Remove is_invocable and is_convertible constraints. + * include/std/type_traits (__is_invocable_impl::_S_conv): Use + non-deduced context for parameter. + (__is_invocable_impl::_S_test): Remove _Check_noex template + parameter and use deduced noexcept value in its place. Add bool + parameter to detect dangling references. + (__is_invocable_impl::type): Adjust call to _S_test to avoid + deducing unnecessary noexcept property.. + (__is_invocable_impl::__nothrow_type): Rename to ... + (__is_invocable_impl::__nothrow_conv): ... this. Adjust call + to _S_test to deduce noexcept property. + * testsuite/20_util/bind/dangling_ref.cc: New test. + * testsuite/20_util/function/cons/70692.cc: New test. + * testsuite/20_util/function_objects/invoke/dangling_ref.cc: + New test. + * testsuite/20_util/is_invocable/dangling_ref.cc: New test. + * testsuite/30_threads/packaged_task/cons/dangling_ref.cc: + New test. + +2022-09-27 Jonathan Wakely <jwakely@redhat.com> + + PR c++/107049 + * testsuite/20_util/is_convertible/requirements/access.cc: New + test. + +2022-09-27 Jonathan Wakely <jwakely@redhat.com> + + PR c++/106651 + * include/bits/std_function.h (__function_guide_t): New alias + template. + [__cpp_static_call_operator] (__function_guide_static_helper): + New class template. + (function): Use __function_guide_t in deduction guide. + * include/std/future (packaged_task): Use __function_guide_t in + deduction guide. + * testsuite/20_util/function/cons/deduction_c++23.cc: New test. + * testsuite/30_threads/packaged_task/cons/deduction_c++23.cc: + New test. + +2022-09-26 Jonathan Wakely <jwakely@redhat.com> + + * include/bits/ptr_traits.h (__ptr_traits_elem) [__cpp_concepts]: + Also define the __ptr_traits_elem class template for the + concepts case. + (pointer_traits<Ptr>): Remove constrained partial + specialization. + * testsuite/20_util/pointer_traits/lwg3545.cc: Check for + ambiguitiy with program-defined partial specialization. + +2022-09-26 Jonathan Wakely <jwakely@redhat.com> + + * include/std/type_traits (is_convertible, is_convertible_v): + Define using new built-in. + (is_nothrow_convertible is_nothrow_convertible_v): Likewise. + +2022-09-26 Jonathan Wakely <jwakely@redhat.com> + + PR libstdc++/107037 + * include/std/bitset (_Base_bitset::_M_do_reset): Use + preprocessor conditional around non-C++03 code. + * testsuite/20_util/bitset/107037.cc: New test. + 2022-09-24 Jonathan Wakely <jwakely@redhat.com> * include/bits/alloc_traits.h (allocator_traits::is_always_equal): diff --git a/libstdc++-v3/doc/html/index.html b/libstdc++-v3/doc/html/index.html index 5cc9226..1e0cecb 100644 --- a/libstdc++-v3/doc/html/index.html +++ b/libstdc++-v3/doc/html/index.html @@ -142,7 +142,7 @@ Existing tests </a></span></dt><dt><span class="section"><a href="manual/test.html#test.exception.safety.containers"> C++11 Requirements Test Sequence Descriptions -</a></span></dt></dl></dd></dl></dd></dl></dd><dt><span class="section"><a href="manual/abi.html">ABI Policy and Guidelines</a></span></dt><dd><dl><dt><span class="section"><a href="manual/abi.html#abi.cxx_interface">The C++ Interface</a></span></dt><dt><span class="section"><a href="manual/abi.html#abi.versioning">Versioning</a></span></dt><dd><dl><dt><span class="section"><a href="manual/abi.html#abi.versioning.goals">Goals</a></span></dt><dt><span class="section"><a href="manual/abi.html#abi.versioning.history">History</a></span></dt><dt><span class="section"><a href="manual/abi.html#abi.versioning.prereq">Prerequisites</a></span></dt><dt><span class="section"><a href="manual/abi.html#abi.versioning.config">Configuring</a></span></dt><dt><span class="section"><a href="manual/abi.html#abi.versioning.active">Checking Active</a></span></dt></dl></dd><dt><span class="section"><a href="manual/abi.html#abi.changes_allowed">Allowed Changes</a></span></dt><dt><span class="section"><a href="manual/abi.html#abi.changes_no">Prohibited Changes</a></span></dt><dt><span class="section"><a href="manual/abi.html#abi.impl">Implementation</a></span></dt><dt><span class="section"><a href="manual/abi.html#abi.testing">Testing</a></span></dt><dd><dl><dt><span class="section"><a href="manual/abi.html#abi.testing.single">Single ABI Testing</a></span></dt><dt><span class="section"><a href="manual/abi.html#abi.testing.multi">Multiple ABI Testing</a></span></dt></dl></dd><dt><span class="section"><a href="manual/abi.html#abi.issues">Outstanding Issues</a></span></dt></dl></dd><dt><span class="section"><a href="manual/api.html">API Evolution and Deprecation History</a></span></dt><dd><dl><dt><span class="section"><a href="manual/api.html#api.rel_300"><code class="constant">3.0</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_310"><code class="constant">3.1</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_320"><code class="constant">3.2</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_330"><code class="constant">3.3</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_340"><code class="constant">3.4</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_400"><code class="constant">4.0</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_410"><code class="constant">4.1</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_420"><code class="constant">4.2</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_430"><code class="constant">4.3</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_440"><code class="constant">4.4</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_450"><code class="constant">4.5</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_460"><code class="constant">4.6</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_470"><code class="constant">4.7</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_480"><code class="constant">4.8</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_490"><code class="constant">4.9</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_51"><code class="constant">5</code></a></span></dt><dd><dl><dt><span class="section"><a href="manual/api.html#api.rel_53"><code class="constant">5.3</code></a></span></dt></dl></dd><dt><span class="section"><a href="manual/api.html#api.rel_61"><code class="constant">6</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_71"><code class="constant">7</code></a></span></dt><dd><dl><dt><span class="section"><a href="manual/api.html#api.rel_72"><code class="constant">7.2</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_73"><code class="constant">7.3</code></a></span></dt></dl></dd><dt><span class="section"><a href="manual/api.html#api.rel_81"><code class="constant">8</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_91"><code class="constant">9</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_101"><code class="constant">10</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_111"><code class="constant">11</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_121"><code class="constant">12</code></a></span></dt></dl></dd><dt><span class="section"><a href="manual/backwards.html">Backwards Compatibility</a></span></dt><dd><dl><dt><span class="section"><a href="manual/backwards.html#backwards.first">First</a></span></dt><dt><span class="section"><a href="manual/backwards.html#backwards.second">Second</a></span></dt><dt><span class="section"><a href="manual/backwards.html#backwards.third">Third</a></span></dt><dd><dl><dt><span class="section"><a href="manual/backwards.html#backwards.third.headers">Pre-ISO headers removed</a></span></dt><dt><span class="section"><a href="manual/backwards.html#backwards.third.hash">Extension headers hash_map, hash_set moved to ext or backwards</a></span></dt><dt><span class="section"><a href="manual/backwards.html#backwards.third.nocreate_noreplace">No <code class="code">ios::nocreate/ios::noreplace</code>. +</a></span></dt></dl></dd></dl></dd></dl></dd><dt><span class="section"><a href="manual/abi.html">ABI Policy and Guidelines</a></span></dt><dd><dl><dt><span class="section"><a href="manual/abi.html#abi.cxx_interface">The C++ Interface</a></span></dt><dt><span class="section"><a href="manual/abi.html#abi.versioning">Versioning</a></span></dt><dd><dl><dt><span class="section"><a href="manual/abi.html#abi.versioning.goals">Goals</a></span></dt><dt><span class="section"><a href="manual/abi.html#abi.versioning.history">History</a></span></dt><dt><span class="section"><a href="manual/abi.html#abi.versioning.prereq">Prerequisites</a></span></dt><dt><span class="section"><a href="manual/abi.html#abi.versioning.config">Configuring</a></span></dt><dt><span class="section"><a href="manual/abi.html#abi.versioning.active">Checking Active</a></span></dt></dl></dd><dt><span class="section"><a href="manual/abi.html#abi.changes_allowed">Allowed Changes</a></span></dt><dt><span class="section"><a href="manual/abi.html#abi.changes_no">Prohibited Changes</a></span></dt><dt><span class="section"><a href="manual/abi.html#abi.impl">Implementation</a></span></dt><dt><span class="section"><a href="manual/abi.html#abi.testing">Testing</a></span></dt><dd><dl><dt><span class="section"><a href="manual/abi.html#abi.testing.single">Single ABI Testing</a></span></dt><dt><span class="section"><a href="manual/abi.html#abi.testing.multi">Multiple ABI Testing</a></span></dt></dl></dd><dt><span class="section"><a href="manual/abi.html#abi.issues">Outstanding Issues</a></span></dt></dl></dd><dt><span class="section"><a href="manual/api.html">API Evolution and Deprecation History</a></span></dt><dd><dl><dt><span class="section"><a href="manual/api.html#api.rel_300"><code class="constant">3.0</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_310"><code class="constant">3.1</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_320"><code class="constant">3.2</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_330"><code class="constant">3.3</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_340"><code class="constant">3.4</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_400"><code class="constant">4.0</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_410"><code class="constant">4.1</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_420"><code class="constant">4.2</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_430"><code class="constant">4.3</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_440"><code class="constant">4.4</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_450"><code class="constant">4.5</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_460"><code class="constant">4.6</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_470"><code class="constant">4.7</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_480"><code class="constant">4.8</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_490"><code class="constant">4.9</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_51"><code class="constant">5</code></a></span></dt><dd><dl><dt><span class="section"><a href="manual/api.html#api.rel_53"><code class="constant">5.3</code></a></span></dt></dl></dd><dt><span class="section"><a href="manual/api.html#api.rel_61"><code class="constant">6</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_71"><code class="constant">7</code></a></span></dt><dd><dl><dt><span class="section"><a href="manual/api.html#api.rel_72"><code class="constant">7.2</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_73"><code class="constant">7.3</code></a></span></dt></dl></dd><dt><span class="section"><a href="manual/api.html#api.rel_81"><code class="constant">8</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_91"><code class="constant">9</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_101"><code class="constant">10</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_111"><code class="constant">11</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_121"><code class="constant">12</code></a></span></dt><dt><span class="section"><a href="manual/api.html#api.rel_123"><code class="constant">12.3</code></a></span></dt></dl></dd><dt><span class="section"><a href="manual/backwards.html">Backwards Compatibility</a></span></dt><dd><dl><dt><span class="section"><a href="manual/backwards.html#backwards.first">First</a></span></dt><dt><span class="section"><a href="manual/backwards.html#backwards.second">Second</a></span></dt><dt><span class="section"><a href="manual/backwards.html#backwards.third">Third</a></span></dt><dd><dl><dt><span class="section"><a href="manual/backwards.html#backwards.third.headers">Pre-ISO headers removed</a></span></dt><dt><span class="section"><a href="manual/backwards.html#backwards.third.hash">Extension headers hash_map, hash_set moved to ext or backwards</a></span></dt><dt><span class="section"><a href="manual/backwards.html#backwards.third.nocreate_noreplace">No <code class="code">ios::nocreate/ios::noreplace</code>. </a></span></dt><dt><span class="section"><a href="manual/backwards.html#backwards.third.streamattach"> No <code class="code">stream::attach(int fd)</code> </a></span></dt><dt><span class="section"><a href="manual/backwards.html#backwards.third.support_cxx98"> diff --git a/libstdc++-v3/doc/html/manual/api.html b/libstdc++-v3/doc/html/manual/api.html index bbda6f5..604380e 100644 --- a/libstdc++-v3/doc/html/manual/api.html +++ b/libstdc++-v3/doc/html/manual/api.html @@ -316,6 +316,8 @@ now defaults to zero. <code class="classname">has_trivial_default_constructor</code>, <code class="classname">has_trivial_copy_constructor</code> and <code class="classname">has_trivial_copy_assign</code> removed. +</p><p> +Calling a <code class="code">std::bind</code> result as volatile was deprecated for C++17. </p><p> Profile Mode was deprecated. </p><div class="section"><div class="titlepage"><div><div><h4 class="title"><a id="api.rel_72"></a><code class="constant">7.2</code></h4></div></div></div><p> Library Fundamentals TS header <code class="filename"><experimental/source_location></code> @@ -468,4 +470,7 @@ they both derive from <code class="classname">std::__new_allocator</code> instea <code class="code">noexcept(false)</code> to allow thread cancellation exceptions to be thrown from <code class="function">pthread_cond_wait</code> without aborting the process. +</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="api.rel_123"></a><code class="constant">12.3</code></h3></div></div></div><p> +Calling a <code class="code">std::bind</code> result as volatile is ill-formed for C++20 +and later. </p></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="abi.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="appendix_porting.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="backwards.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">ABI Policy and Guidelines </td><td width="20%" align="center"><a accesskey="h" href="../index.html">Home</a></td><td width="40%" align="right" valign="top"> Backwards Compatibility</td></tr></table></div></body></html>
\ No newline at end of file diff --git a/libstdc++-v3/doc/html/manual/appendix.html b/libstdc++-v3/doc/html/manual/appendix.html index bd462e9..c563372 100644 --- a/libstdc++-v3/doc/html/manual/appendix.html +++ b/libstdc++-v3/doc/html/manual/appendix.html @@ -16,7 +16,7 @@ Existing tests </a></span></dt><dt><span class="section"><a href="test.html#test.exception.safety.containers"> C++11 Requirements Test Sequence Descriptions -</a></span></dt></dl></dd></dl></dd></dl></dd><dt><span class="section"><a href="abi.html">ABI Policy and Guidelines</a></span></dt><dd><dl><dt><span class="section"><a href="abi.html#abi.cxx_interface">The C++ Interface</a></span></dt><dt><span class="section"><a href="abi.html#abi.versioning">Versioning</a></span></dt><dd><dl><dt><span class="section"><a href="abi.html#abi.versioning.goals">Goals</a></span></dt><dt><span class="section"><a href="abi.html#abi.versioning.history">History</a></span></dt><dt><span class="section"><a href="abi.html#abi.versioning.prereq">Prerequisites</a></span></dt><dt><span class="section"><a href="abi.html#abi.versioning.config">Configuring</a></span></dt><dt><span class="section"><a href="abi.html#abi.versioning.active">Checking Active</a></span></dt></dl></dd><dt><span class="section"><a href="abi.html#abi.changes_allowed">Allowed Changes</a></span></dt><dt><span class="section"><a href="abi.html#abi.changes_no">Prohibited Changes</a></span></dt><dt><span class="section"><a href="abi.html#abi.impl">Implementation</a></span></dt><dt><span class="section"><a href="abi.html#abi.testing">Testing</a></span></dt><dd><dl><dt><span class="section"><a href="abi.html#abi.testing.single">Single ABI Testing</a></span></dt><dt><span class="section"><a href="abi.html#abi.testing.multi">Multiple ABI Testing</a></span></dt></dl></dd><dt><span class="section"><a href="abi.html#abi.issues">Outstanding Issues</a></span></dt></dl></dd><dt><span class="section"><a href="api.html">API Evolution and Deprecation History</a></span></dt><dd><dl><dt><span class="section"><a href="api.html#api.rel_300"><code class="constant">3.0</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_310"><code class="constant">3.1</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_320"><code class="constant">3.2</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_330"><code class="constant">3.3</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_340"><code class="constant">3.4</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_400"><code class="constant">4.0</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_410"><code class="constant">4.1</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_420"><code class="constant">4.2</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_430"><code class="constant">4.3</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_440"><code class="constant">4.4</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_450"><code class="constant">4.5</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_460"><code class="constant">4.6</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_470"><code class="constant">4.7</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_480"><code class="constant">4.8</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_490"><code class="constant">4.9</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_51"><code class="constant">5</code></a></span></dt><dd><dl><dt><span class="section"><a href="api.html#api.rel_53"><code class="constant">5.3</code></a></span></dt></dl></dd><dt><span class="section"><a href="api.html#api.rel_61"><code class="constant">6</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_71"><code class="constant">7</code></a></span></dt><dd><dl><dt><span class="section"><a href="api.html#api.rel_72"><code class="constant">7.2</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_73"><code class="constant">7.3</code></a></span></dt></dl></dd><dt><span class="section"><a href="api.html#api.rel_81"><code class="constant">8</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_91"><code class="constant">9</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_101"><code class="constant">10</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_111"><code class="constant">11</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_121"><code class="constant">12</code></a></span></dt></dl></dd><dt><span class="section"><a href="backwards.html">Backwards Compatibility</a></span></dt><dd><dl><dt><span class="section"><a href="backwards.html#backwards.first">First</a></span></dt><dt><span class="section"><a href="backwards.html#backwards.second">Second</a></span></dt><dt><span class="section"><a href="backwards.html#backwards.third">Third</a></span></dt><dd><dl><dt><span class="section"><a href="backwards.html#backwards.third.headers">Pre-ISO headers removed</a></span></dt><dt><span class="section"><a href="backwards.html#backwards.third.hash">Extension headers hash_map, hash_set moved to ext or backwards</a></span></dt><dt><span class="section"><a href="backwards.html#backwards.third.nocreate_noreplace">No <code class="code">ios::nocreate/ios::noreplace</code>. +</a></span></dt></dl></dd></dl></dd></dl></dd><dt><span class="section"><a href="abi.html">ABI Policy and Guidelines</a></span></dt><dd><dl><dt><span class="section"><a href="abi.html#abi.cxx_interface">The C++ Interface</a></span></dt><dt><span class="section"><a href="abi.html#abi.versioning">Versioning</a></span></dt><dd><dl><dt><span class="section"><a href="abi.html#abi.versioning.goals">Goals</a></span></dt><dt><span class="section"><a href="abi.html#abi.versioning.history">History</a></span></dt><dt><span class="section"><a href="abi.html#abi.versioning.prereq">Prerequisites</a></span></dt><dt><span class="section"><a href="abi.html#abi.versioning.config">Configuring</a></span></dt><dt><span class="section"><a href="abi.html#abi.versioning.active">Checking Active</a></span></dt></dl></dd><dt><span class="section"><a href="abi.html#abi.changes_allowed">Allowed Changes</a></span></dt><dt><span class="section"><a href="abi.html#abi.changes_no">Prohibited Changes</a></span></dt><dt><span class="section"><a href="abi.html#abi.impl">Implementation</a></span></dt><dt><span class="section"><a href="abi.html#abi.testing">Testing</a></span></dt><dd><dl><dt><span class="section"><a href="abi.html#abi.testing.single">Single ABI Testing</a></span></dt><dt><span class="section"><a href="abi.html#abi.testing.multi">Multiple ABI Testing</a></span></dt></dl></dd><dt><span class="section"><a href="abi.html#abi.issues">Outstanding Issues</a></span></dt></dl></dd><dt><span class="section"><a href="api.html">API Evolution and Deprecation History</a></span></dt><dd><dl><dt><span class="section"><a href="api.html#api.rel_300"><code class="constant">3.0</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_310"><code class="constant">3.1</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_320"><code class="constant">3.2</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_330"><code class="constant">3.3</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_340"><code class="constant">3.4</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_400"><code class="constant">4.0</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_410"><code class="constant">4.1</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_420"><code class="constant">4.2</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_430"><code class="constant">4.3</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_440"><code class="constant">4.4</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_450"><code class="constant">4.5</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_460"><code class="constant">4.6</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_470"><code class="constant">4.7</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_480"><code class="constant">4.8</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_490"><code class="constant">4.9</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_51"><code class="constant">5</code></a></span></dt><dd><dl><dt><span class="section"><a href="api.html#api.rel_53"><code class="constant">5.3</code></a></span></dt></dl></dd><dt><span class="section"><a href="api.html#api.rel_61"><code class="constant">6</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_71"><code class="constant">7</code></a></span></dt><dd><dl><dt><span class="section"><a href="api.html#api.rel_72"><code class="constant">7.2</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_73"><code class="constant">7.3</code></a></span></dt></dl></dd><dt><span class="section"><a href="api.html#api.rel_81"><code class="constant">8</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_91"><code class="constant">9</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_101"><code class="constant">10</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_111"><code class="constant">11</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_121"><code class="constant">12</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_123"><code class="constant">12.3</code></a></span></dt></dl></dd><dt><span class="section"><a href="backwards.html">Backwards Compatibility</a></span></dt><dd><dl><dt><span class="section"><a href="backwards.html#backwards.first">First</a></span></dt><dt><span class="section"><a href="backwards.html#backwards.second">Second</a></span></dt><dt><span class="section"><a href="backwards.html#backwards.third">Third</a></span></dt><dd><dl><dt><span class="section"><a href="backwards.html#backwards.third.headers">Pre-ISO headers removed</a></span></dt><dt><span class="section"><a href="backwards.html#backwards.third.hash">Extension headers hash_map, hash_set moved to ext or backwards</a></span></dt><dt><span class="section"><a href="backwards.html#backwards.third.nocreate_noreplace">No <code class="code">ios::nocreate/ios::noreplace</code>. </a></span></dt><dt><span class="section"><a href="backwards.html#backwards.third.streamattach"> No <code class="code">stream::attach(int fd)</code> </a></span></dt><dt><span class="section"><a href="backwards.html#backwards.third.support_cxx98"> diff --git a/libstdc++-v3/doc/html/manual/appendix_porting.html b/libstdc++-v3/doc/html/manual/appendix_porting.html index 3d7fb56..55d3f23 100644 --- a/libstdc++-v3/doc/html/manual/appendix_porting.html +++ b/libstdc++-v3/doc/html/manual/appendix_porting.html @@ -14,7 +14,7 @@ Existing tests </a></span></dt><dt><span class="section"><a href="test.html#test.exception.safety.containers"> C++11 Requirements Test Sequence Descriptions -</a></span></dt></dl></dd></dl></dd></dl></dd><dt><span class="section"><a href="abi.html">ABI Policy and Guidelines</a></span></dt><dd><dl><dt><span class="section"><a href="abi.html#abi.cxx_interface">The C++ Interface</a></span></dt><dt><span class="section"><a href="abi.html#abi.versioning">Versioning</a></span></dt><dd><dl><dt><span class="section"><a href="abi.html#abi.versioning.goals">Goals</a></span></dt><dt><span class="section"><a href="abi.html#abi.versioning.history">History</a></span></dt><dt><span class="section"><a href="abi.html#abi.versioning.prereq">Prerequisites</a></span></dt><dt><span class="section"><a href="abi.html#abi.versioning.config">Configuring</a></span></dt><dt><span class="section"><a href="abi.html#abi.versioning.active">Checking Active</a></span></dt></dl></dd><dt><span class="section"><a href="abi.html#abi.changes_allowed">Allowed Changes</a></span></dt><dt><span class="section"><a href="abi.html#abi.changes_no">Prohibited Changes</a></span></dt><dt><span class="section"><a href="abi.html#abi.impl">Implementation</a></span></dt><dt><span class="section"><a href="abi.html#abi.testing">Testing</a></span></dt><dd><dl><dt><span class="section"><a href="abi.html#abi.testing.single">Single ABI Testing</a></span></dt><dt><span class="section"><a href="abi.html#abi.testing.multi">Multiple ABI Testing</a></span></dt></dl></dd><dt><span class="section"><a href="abi.html#abi.issues">Outstanding Issues</a></span></dt></dl></dd><dt><span class="section"><a href="api.html">API Evolution and Deprecation History</a></span></dt><dd><dl><dt><span class="section"><a href="api.html#api.rel_300"><code class="constant">3.0</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_310"><code class="constant">3.1</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_320"><code class="constant">3.2</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_330"><code class="constant">3.3</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_340"><code class="constant">3.4</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_400"><code class="constant">4.0</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_410"><code class="constant">4.1</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_420"><code class="constant">4.2</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_430"><code class="constant">4.3</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_440"><code class="constant">4.4</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_450"><code class="constant">4.5</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_460"><code class="constant">4.6</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_470"><code class="constant">4.7</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_480"><code class="constant">4.8</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_490"><code class="constant">4.9</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_51"><code class="constant">5</code></a></span></dt><dd><dl><dt><span class="section"><a href="api.html#api.rel_53"><code class="constant">5.3</code></a></span></dt></dl></dd><dt><span class="section"><a href="api.html#api.rel_61"><code class="constant">6</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_71"><code class="constant">7</code></a></span></dt><dd><dl><dt><span class="section"><a href="api.html#api.rel_72"><code class="constant">7.2</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_73"><code class="constant">7.3</code></a></span></dt></dl></dd><dt><span class="section"><a href="api.html#api.rel_81"><code class="constant">8</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_91"><code class="constant">9</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_101"><code class="constant">10</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_111"><code class="constant">11</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_121"><code class="constant">12</code></a></span></dt></dl></dd><dt><span class="section"><a href="backwards.html">Backwards Compatibility</a></span></dt><dd><dl><dt><span class="section"><a href="backwards.html#backwards.first">First</a></span></dt><dt><span class="section"><a href="backwards.html#backwards.second">Second</a></span></dt><dt><span class="section"><a href="backwards.html#backwards.third">Third</a></span></dt><dd><dl><dt><span class="section"><a href="backwards.html#backwards.third.headers">Pre-ISO headers removed</a></span></dt><dt><span class="section"><a href="backwards.html#backwards.third.hash">Extension headers hash_map, hash_set moved to ext or backwards</a></span></dt><dt><span class="section"><a href="backwards.html#backwards.third.nocreate_noreplace">No <code class="code">ios::nocreate/ios::noreplace</code>. +</a></span></dt></dl></dd></dl></dd></dl></dd><dt><span class="section"><a href="abi.html">ABI Policy and Guidelines</a></span></dt><dd><dl><dt><span class="section"><a href="abi.html#abi.cxx_interface">The C++ Interface</a></span></dt><dt><span class="section"><a href="abi.html#abi.versioning">Versioning</a></span></dt><dd><dl><dt><span class="section"><a href="abi.html#abi.versioning.goals">Goals</a></span></dt><dt><span class="section"><a href="abi.html#abi.versioning.history">History</a></span></dt><dt><span class="section"><a href="abi.html#abi.versioning.prereq">Prerequisites</a></span></dt><dt><span class="section"><a href="abi.html#abi.versioning.config">Configuring</a></span></dt><dt><span class="section"><a href="abi.html#abi.versioning.active">Checking Active</a></span></dt></dl></dd><dt><span class="section"><a href="abi.html#abi.changes_allowed">Allowed Changes</a></span></dt><dt><span class="section"><a href="abi.html#abi.changes_no">Prohibited Changes</a></span></dt><dt><span class="section"><a href="abi.html#abi.impl">Implementation</a></span></dt><dt><span class="section"><a href="abi.html#abi.testing">Testing</a></span></dt><dd><dl><dt><span class="section"><a href="abi.html#abi.testing.single">Single ABI Testing</a></span></dt><dt><span class="section"><a href="abi.html#abi.testing.multi">Multiple ABI Testing</a></span></dt></dl></dd><dt><span class="section"><a href="abi.html#abi.issues">Outstanding Issues</a></span></dt></dl></dd><dt><span class="section"><a href="api.html">API Evolution and Deprecation History</a></span></dt><dd><dl><dt><span class="section"><a href="api.html#api.rel_300"><code class="constant">3.0</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_310"><code class="constant">3.1</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_320"><code class="constant">3.2</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_330"><code class="constant">3.3</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_340"><code class="constant">3.4</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_400"><code class="constant">4.0</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_410"><code class="constant">4.1</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_420"><code class="constant">4.2</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_430"><code class="constant">4.3</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_440"><code class="constant">4.4</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_450"><code class="constant">4.5</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_460"><code class="constant">4.6</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_470"><code class="constant">4.7</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_480"><code class="constant">4.8</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_490"><code class="constant">4.9</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_51"><code class="constant">5</code></a></span></dt><dd><dl><dt><span class="section"><a href="api.html#api.rel_53"><code class="constant">5.3</code></a></span></dt></dl></dd><dt><span class="section"><a href="api.html#api.rel_61"><code class="constant">6</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_71"><code class="constant">7</code></a></span></dt><dd><dl><dt><span class="section"><a href="api.html#api.rel_72"><code class="constant">7.2</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_73"><code class="constant">7.3</code></a></span></dt></dl></dd><dt><span class="section"><a href="api.html#api.rel_81"><code class="constant">8</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_91"><code class="constant">9</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_101"><code class="constant">10</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_111"><code class="constant">11</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_121"><code class="constant">12</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_123"><code class="constant">12.3</code></a></span></dt></dl></dd><dt><span class="section"><a href="backwards.html">Backwards Compatibility</a></span></dt><dd><dl><dt><span class="section"><a href="backwards.html#backwards.first">First</a></span></dt><dt><span class="section"><a href="backwards.html#backwards.second">Second</a></span></dt><dt><span class="section"><a href="backwards.html#backwards.third">Third</a></span></dt><dd><dl><dt><span class="section"><a href="backwards.html#backwards.third.headers">Pre-ISO headers removed</a></span></dt><dt><span class="section"><a href="backwards.html#backwards.third.hash">Extension headers hash_map, hash_set moved to ext or backwards</a></span></dt><dt><span class="section"><a href="backwards.html#backwards.third.nocreate_noreplace">No <code class="code">ios::nocreate/ios::noreplace</code>. </a></span></dt><dt><span class="section"><a href="backwards.html#backwards.third.streamattach"> No <code class="code">stream::attach(int fd)</code> </a></span></dt><dt><span class="section"><a href="backwards.html#backwards.third.support_cxx98"> diff --git a/libstdc++-v3/doc/html/manual/bugs.html b/libstdc++-v3/doc/html/manual/bugs.html index 384fe8d..8e0bc1f 100644 --- a/libstdc++-v3/doc/html/manual/bugs.html +++ b/libstdc++-v3/doc/html/manual/bugs.html @@ -524,6 +524,12 @@ </em></span> </span></dt><dd><p>Avoid using <code class="code">dynamic_cast</code> when it would be ill-formed. + </p></dd><dt><a id="manual.bugs.dr2487"></a><span class="term"><a class="link" href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2487" target="_top">2487</a>: + <span class="emphasis"><em><code class="code">bind()</code> should be <code class="code">const</code>-overloaded + not cv-overloaded + </em></span> + </span></dt><dd><p>Deprecate volatile-qualified <code class="code">operator()</code> + for C++17, make it ill-formed for C++20. </p></dd><dt><a id="manual.bugs.dr2499"></a><span class="term"><a class="link" href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2499" target="_top">2499</a>: <span class="emphasis"><em><code class="code">operator>>(basic_istream&, CharT*)</code> makes it hard to avoid buffer overflows </em></span> diff --git a/libstdc++-v3/doc/html/manual/index.html b/libstdc++-v3/doc/html/manual/index.html index 7122dde..2949509 100644 --- a/libstdc++-v3/doc/html/manual/index.html +++ b/libstdc++-v3/doc/html/manual/index.html @@ -123,7 +123,7 @@ Existing tests </a></span></dt><dt><span class="section"><a href="test.html#test.exception.safety.containers"> C++11 Requirements Test Sequence Descriptions -</a></span></dt></dl></dd></dl></dd></dl></dd><dt><span class="section"><a href="abi.html">ABI Policy and Guidelines</a></span></dt><dd><dl><dt><span class="section"><a href="abi.html#abi.cxx_interface">The C++ Interface</a></span></dt><dt><span class="section"><a href="abi.html#abi.versioning">Versioning</a></span></dt><dd><dl><dt><span class="section"><a href="abi.html#abi.versioning.goals">Goals</a></span></dt><dt><span class="section"><a href="abi.html#abi.versioning.history">History</a></span></dt><dt><span class="section"><a href="abi.html#abi.versioning.prereq">Prerequisites</a></span></dt><dt><span class="section"><a href="abi.html#abi.versioning.config">Configuring</a></span></dt><dt><span class="section"><a href="abi.html#abi.versioning.active">Checking Active</a></span></dt></dl></dd><dt><span class="section"><a href="abi.html#abi.changes_allowed">Allowed Changes</a></span></dt><dt><span class="section"><a href="abi.html#abi.changes_no">Prohibited Changes</a></span></dt><dt><span class="section"><a href="abi.html#abi.impl">Implementation</a></span></dt><dt><span class="section"><a href="abi.html#abi.testing">Testing</a></span></dt><dd><dl><dt><span class="section"><a href="abi.html#abi.testing.single">Single ABI Testing</a></span></dt><dt><span class="section"><a href="abi.html#abi.testing.multi">Multiple ABI Testing</a></span></dt></dl></dd><dt><span class="section"><a href="abi.html#abi.issues">Outstanding Issues</a></span></dt></dl></dd><dt><span class="section"><a href="api.html">API Evolution and Deprecation History</a></span></dt><dd><dl><dt><span class="section"><a href="api.html#api.rel_300"><code class="constant">3.0</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_310"><code class="constant">3.1</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_320"><code class="constant">3.2</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_330"><code class="constant">3.3</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_340"><code class="constant">3.4</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_400"><code class="constant">4.0</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_410"><code class="constant">4.1</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_420"><code class="constant">4.2</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_430"><code class="constant">4.3</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_440"><code class="constant">4.4</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_450"><code class="constant">4.5</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_460"><code class="constant">4.6</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_470"><code class="constant">4.7</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_480"><code class="constant">4.8</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_490"><code class="constant">4.9</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_51"><code class="constant">5</code></a></span></dt><dd><dl><dt><span class="section"><a href="api.html#api.rel_53"><code class="constant">5.3</code></a></span></dt></dl></dd><dt><span class="section"><a href="api.html#api.rel_61"><code class="constant">6</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_71"><code class="constant">7</code></a></span></dt><dd><dl><dt><span class="section"><a href="api.html#api.rel_72"><code class="constant">7.2</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_73"><code class="constant">7.3</code></a></span></dt></dl></dd><dt><span class="section"><a href="api.html#api.rel_81"><code class="constant">8</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_91"><code class="constant">9</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_101"><code class="constant">10</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_111"><code class="constant">11</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_121"><code class="constant">12</code></a></span></dt></dl></dd><dt><span class="section"><a href="backwards.html">Backwards Compatibility</a></span></dt><dd><dl><dt><span class="section"><a href="backwards.html#backwards.first">First</a></span></dt><dt><span class="section"><a href="backwards.html#backwards.second">Second</a></span></dt><dt><span class="section"><a href="backwards.html#backwards.third">Third</a></span></dt><dd><dl><dt><span class="section"><a href="backwards.html#backwards.third.headers">Pre-ISO headers removed</a></span></dt><dt><span class="section"><a href="backwards.html#backwards.third.hash">Extension headers hash_map, hash_set moved to ext or backwards</a></span></dt><dt><span class="section"><a href="backwards.html#backwards.third.nocreate_noreplace">No <code class="code">ios::nocreate/ios::noreplace</code>. +</a></span></dt></dl></dd></dl></dd></dl></dd><dt><span class="section"><a href="abi.html">ABI Policy and Guidelines</a></span></dt><dd><dl><dt><span class="section"><a href="abi.html#abi.cxx_interface">The C++ Interface</a></span></dt><dt><span class="section"><a href="abi.html#abi.versioning">Versioning</a></span></dt><dd><dl><dt><span class="section"><a href="abi.html#abi.versioning.goals">Goals</a></span></dt><dt><span class="section"><a href="abi.html#abi.versioning.history">History</a></span></dt><dt><span class="section"><a href="abi.html#abi.versioning.prereq">Prerequisites</a></span></dt><dt><span class="section"><a href="abi.html#abi.versioning.config">Configuring</a></span></dt><dt><span class="section"><a href="abi.html#abi.versioning.active">Checking Active</a></span></dt></dl></dd><dt><span class="section"><a href="abi.html#abi.changes_allowed">Allowed Changes</a></span></dt><dt><span class="section"><a href="abi.html#abi.changes_no">Prohibited Changes</a></span></dt><dt><span class="section"><a href="abi.html#abi.impl">Implementation</a></span></dt><dt><span class="section"><a href="abi.html#abi.testing">Testing</a></span></dt><dd><dl><dt><span class="section"><a href="abi.html#abi.testing.single">Single ABI Testing</a></span></dt><dt><span class="section"><a href="abi.html#abi.testing.multi">Multiple ABI Testing</a></span></dt></dl></dd><dt><span class="section"><a href="abi.html#abi.issues">Outstanding Issues</a></span></dt></dl></dd><dt><span class="section"><a href="api.html">API Evolution and Deprecation History</a></span></dt><dd><dl><dt><span class="section"><a href="api.html#api.rel_300"><code class="constant">3.0</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_310"><code class="constant">3.1</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_320"><code class="constant">3.2</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_330"><code class="constant">3.3</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_340"><code class="constant">3.4</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_400"><code class="constant">4.0</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_410"><code class="constant">4.1</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_420"><code class="constant">4.2</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_430"><code class="constant">4.3</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_440"><code class="constant">4.4</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_450"><code class="constant">4.5</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_460"><code class="constant">4.6</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_470"><code class="constant">4.7</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_480"><code class="constant">4.8</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_490"><code class="constant">4.9</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_51"><code class="constant">5</code></a></span></dt><dd><dl><dt><span class="section"><a href="api.html#api.rel_53"><code class="constant">5.3</code></a></span></dt></dl></dd><dt><span class="section"><a href="api.html#api.rel_61"><code class="constant">6</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_71"><code class="constant">7</code></a></span></dt><dd><dl><dt><span class="section"><a href="api.html#api.rel_72"><code class="constant">7.2</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_73"><code class="constant">7.3</code></a></span></dt></dl></dd><dt><span class="section"><a href="api.html#api.rel_81"><code class="constant">8</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_91"><code class="constant">9</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_101"><code class="constant">10</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_111"><code class="constant">11</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_121"><code class="constant">12</code></a></span></dt><dt><span class="section"><a href="api.html#api.rel_123"><code class="constant">12.3</code></a></span></dt></dl></dd><dt><span class="section"><a href="backwards.html">Backwards Compatibility</a></span></dt><dd><dl><dt><span class="section"><a href="backwards.html#backwards.first">First</a></span></dt><dt><span class="section"><a href="backwards.html#backwards.second">Second</a></span></dt><dt><span class="section"><a href="backwards.html#backwards.third">Third</a></span></dt><dd><dl><dt><span class="section"><a href="backwards.html#backwards.third.headers">Pre-ISO headers removed</a></span></dt><dt><span class="section"><a href="backwards.html#backwards.third.hash">Extension headers hash_map, hash_set moved to ext or backwards</a></span></dt><dt><span class="section"><a href="backwards.html#backwards.third.nocreate_noreplace">No <code class="code">ios::nocreate/ios::noreplace</code>. </a></span></dt><dt><span class="section"><a href="backwards.html#backwards.third.streamattach"> No <code class="code">stream::attach(int fd)</code> </a></span></dt><dt><span class="section"><a href="backwards.html#backwards.third.support_cxx98"> diff --git a/libstdc++-v3/doc/html/manual/using_macros.html b/libstdc++-v3/doc/html/manual/using_macros.html index 9823046..62c66b7 100644 --- a/libstdc++-v3/doc/html/manual/using_macros.html +++ b/libstdc++-v3/doc/html/manual/using_macros.html @@ -43,7 +43,7 @@ <a class="link" href="configure.html" title="Configure">Configure</a>), with the various --enable/--disable choices being translated to #define/#undef). - </p><p> <acronym class="acronym">ABI</acronym> means that changing from the default value may + </p><p> <acronym class="acronym">ABI</acronym>-changing means that changing from the default value may mean changing the <acronym class="acronym">ABI</acronym> of compiled code. In other words, these choices control code which has already been compiled (i.e., in a binary such as libstdc++.a/.so). If you explicitly #define or @@ -53,7 +53,8 @@ consistent linkage requires changing the config headers before building/installing the library. </p><div class="variablelist"><dl class="variablelist"><dt><span class="term"><code class="code">_GLIBCXX_USE_DEPRECATED</code></span></dt><dd><p> - Defined by default. Not configurable. ABI-changing. Turning this off + Defined to the value <code class="literal">1</code> by default. + Not configurable. ABI-changing. Turning this off removes older ARM-style iostreams code, and other anachronisms from the API. This macro is dependent on the version of the standard being tracked, and as a result may give different results for diff --git a/libstdc++-v3/doc/xml/manual/evolution.xml b/libstdc++-v3/doc/xml/manual/evolution.xml index 4923e8c..8293618 100644 --- a/libstdc++-v3/doc/xml/manual/evolution.xml +++ b/libstdc++-v3/doc/xml/manual/evolution.xml @@ -817,6 +817,10 @@ now defaults to zero. <classname>has_trivial_copy_assign</classname> removed. </para> +<para> +Calling a <code>std::bind</code> result as volatile was deprecated for C++17. +</para> + <para> Profile Mode was deprecated. </para> <section xml:id="api.rel_72"><info><title><constant>7.2</constant></title></info> @@ -1067,4 +1071,13 @@ the process. </section> + +<section xml:id="api.rel_123"><info><title><constant>12.3</constant></title></info> +<para> +Calling a <code>std::bind</code> result as volatile is ill-formed for C++20 +and later. +</para> + +</section> + </section> diff --git a/libstdc++-v3/doc/xml/manual/intro.xml b/libstdc++-v3/doc/xml/manual/intro.xml index d341c3e..e3a03cf 100644 --- a/libstdc++-v3/doc/xml/manual/intro.xml +++ b/libstdc++-v3/doc/xml/manual/intro.xml @@ -1163,6 +1163,15 @@ requirements of the license of GCC. ill-formed. </para></listitem></varlistentry> + <varlistentry xml:id="manual.bugs.dr2487"><term><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="&DR;#2487">2487</link>: + <emphasis><code>bind()</code> should be <code>const</code>-overloaded + not cv-overloaded + </emphasis> + </term> + <listitem><para>Deprecate volatile-qualified <code>operator()</code> + for C++17, make it ill-formed for C++20. + </para></listitem></varlistentry> + <varlistentry xml:id="manual.bugs.dr2499"><term><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="&DR;#2499">2499</link>: <emphasis><code>operator>>(basic_istream&, CharT*)</code> makes it hard to avoid buffer overflows </emphasis> diff --git a/libstdc++-v3/doc/xml/manual/using.xml b/libstdc++-v3/doc/xml/manual/using.xml index 0acdba6..9c444dd 100644 --- a/libstdc++-v3/doc/xml/manual/using.xml +++ b/libstdc++-v3/doc/xml/manual/using.xml @@ -1062,7 +1062,7 @@ g++ -Winvalid-pch -I. -include stdc++.h -H -g -O2 hello.cc -o test.exe #define/#undef). </para> - <para> <acronym>ABI</acronym> means that changing from the default value may + <para> <acronym>ABI</acronym>-changing means that changing from the default value may mean changing the <acronym>ABI</acronym> of compiled code. In other words, these choices control code which has already been compiled (i.e., in a binary such as libstdc++.a/.so). If you explicitly #define or @@ -1077,7 +1077,8 @@ g++ -Winvalid-pch -I. -include stdc++.h -H -g -O2 hello.cc -o test.exe <varlistentry><term><code>_GLIBCXX_USE_DEPRECATED</code></term> <listitem> <para> - Defined by default. Not configurable. ABI-changing. Turning this off + Defined to the value <literal>1</literal> by default. + Not configurable. ABI-changing. Turning this off removes older ARM-style iostreams code, and other anachronisms from the API. This macro is dependent on the version of the standard being tracked, and as a result may give different results for diff --git a/libstdc++-v3/include/bits/invoke.h b/libstdc++-v3/include/bits/invoke.h index cdecca0..8724a76 100644 --- a/libstdc++-v3/include/bits/invoke.h +++ b/libstdc++-v3/include/bits/invoke.h @@ -115,29 +115,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION std::forward<_Callable>(__fn), std::forward<_Args>(__args)...); } -#else // C++11 - template<typename _Res, typename _Callable, typename... _Args> - using __can_invoke_as_void = __enable_if_t< - __and_<is_void<_Res>, __is_invocable<_Callable, _Args...>>::value, - _Res - >; - - template<typename _Res, typename _Callable, typename... _Args> - using __can_invoke_as_nonvoid = __enable_if_t< - __and_<__not_<is_void<_Res>>, - is_convertible<typename __invoke_result<_Callable, _Args...>::type, - _Res> - >::value, - _Res - >; +#else // C++11 or C++14 + // This is a non-SFINAE-friendly std::invoke_r<R>(fn, args...) for C++11/14. + // It's used in std::function, std::bind, and std::packaged_task. Only + // std::function is constrained on is_invocable_r, but that is checked on + // construction so doesn't need to be checked again when calling __invoke_r. + // Consequently, these __invoke_r overloads do not check for invocable + // arguments, nor check that the invoke result is convertible to R. // INVOKE<R>: Invoke a callable object and convert the result to R. template<typename _Res, typename _Callable, typename... _Args> - constexpr __can_invoke_as_nonvoid<_Res, _Callable, _Args...> + constexpr __enable_if_t<!is_void<_Res>::value, _Res> __invoke_r(_Callable&& __fn, _Args&&... __args) { using __result = __invoke_result<_Callable, _Args...>; using __type = typename __result::type; + static_assert(!__reference_converts_from_temporary(_Res, __type), + "INVOKE<R> must not create a dangling reference"); using __tag = typename __result::__invoke_type; return std::__invoke_impl<__type>(__tag{}, std::forward<_Callable>(__fn), std::forward<_Args>(__args)...); @@ -145,7 +139,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // INVOKE<R> when R is cv void template<typename _Res, typename _Callable, typename... _Args> - _GLIBCXX14_CONSTEXPR __can_invoke_as_void<_Res, _Callable, _Args...> + _GLIBCXX14_CONSTEXPR __enable_if_t<is_void<_Res>::value, _Res> __invoke_r(_Callable&& __fn, _Args&&... __args) { using __result = __invoke_result<_Callable, _Args...>; @@ -154,7 +148,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION std::__invoke_impl<__type>(__tag{}, std::forward<_Callable>(__fn), std::forward<_Args>(__args)...); } -#endif // C++11 +#endif // C++11 or C++14 _GLIBCXX_END_NAMESPACE_VERSION } // namespace std diff --git a/libstdc++-v3/include/bits/ptr_traits.h b/libstdc++-v3/include/bits/ptr_traits.h index ae88107..71370ff 100644 --- a/libstdc++-v3/include/bits/ptr_traits.h +++ b/libstdc++-v3/include/bits/ptr_traits.h @@ -73,25 +73,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __replace_first_arg<_SomeTemplate<_Tp, _Types...>, _Up> { using type = _SomeTemplate<_Up, _Types...>; }; -#if __cpp_concepts - // When concepts are supported detection of _Ptr::element_type is done - // by a requires-clause, so __ptr_traits_elem_t only needs to do this: - template<typename _Ptr> - using __ptr_traits_elem_t = typename __get_first_arg<_Ptr>::type; -#else // Detect the element type of a pointer-like type. template<typename _Ptr, typename = void> struct __ptr_traits_elem : __get_first_arg<_Ptr> { }; // Use _Ptr::element_type if is a valid type. +#if __cpp_concepts + template<typename _Ptr> requires requires { typename _Ptr::element_type; } + struct __ptr_traits_elem<_Ptr, void> + { using type = typename _Ptr::element_type; }; +#else template<typename _Ptr> struct __ptr_traits_elem<_Ptr, __void_t<typename _Ptr::element_type>> { using type = typename _Ptr::element_type; }; +#endif template<typename _Ptr> using __ptr_traits_elem_t = typename __ptr_traits_elem<_Ptr>::type; -#endif /// @endcond @@ -182,13 +181,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct pointer_traits : __ptr_traits_impl<_Ptr, __ptr_traits_elem_t<_Ptr>> { }; -#if __cpp_concepts - template<typename _Ptr> requires requires { typename _Ptr::element_type; } - struct pointer_traits<_Ptr> - : __ptr_traits_impl<_Ptr, typename _Ptr::element_type> - { }; -#endif - /** * @brief Partial specialization for built-in pointers. * @headerfile memory diff --git a/libstdc++-v3/include/bits/std_function.h b/libstdc++-v3/include/bits/std_function.h index 96918a0..f5423a3 100644 --- a/libstdc++-v3/include/bits/std_function.h +++ b/libstdc++-v3/include/bits/std_function.h @@ -697,12 +697,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > { using type = _Res(_Args...); }; +#if __cpp_static_call_operator >= 202207L && __cpp_concepts >= 202002L + template<typename _StaticCallOp> + struct __function_guide_static_helper + { }; + + template<typename _Res, bool _Nx, typename... _Args> + struct __function_guide_static_helper<_Res (*) (_Args...) noexcept(_Nx)> + { using type = _Res(_Args...); }; + + template<typename _Fn, typename _Op> + using __function_guide_t = typename __conditional_t< + requires (_Fn& __f) { (void) __f.operator(); }, + __function_guide_static_helper<_Op>, + __function_guide_helper<_Op>>::type; +#else + template<typename _Fn, typename _Op> + using __function_guide_t = typename __function_guide_helper<_Op>::type; +#endif + template<typename _Res, typename... _ArgTypes> function(_Res(*)(_ArgTypes...)) -> function<_Res(_ArgTypes...)>; - template<typename _Functor, typename _Signature = typename - __function_guide_helper<decltype(&_Functor::operator())>::type> - function(_Functor) -> function<_Signature>; + template<typename _Fn, typename _Signature + = __function_guide_t<_Fn, decltype(&_Fn::operator())>> + function(_Fn) -> function<_Signature>; #endif // [20.7.15.2.6] null pointer comparisons diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional index c4f7588..5235ef2 100644 --- a/libstdc++-v3/include/std/functional +++ b/libstdc++-v3/include/std/functional @@ -465,6 +465,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// @endcond +#if __cplusplus == 201703L && _GLIBCXX_USE_DEPRECATED +# define _GLIBCXX_VOLATILE_BIND +// _GLIBCXX_RESOLVE_LIB_DEFECTS +// 2487. bind() should be const-overloaded, not cv-overloaded +# define _GLIBCXX_DEPR_BIND \ + [[deprecated("std::bind does not support volatile in C++17")]] +#elif __cplusplus < 201703L +# define _GLIBCXX_VOLATILE_BIND +# define _GLIBCXX_DEPR_BIND +#endif + /// Type of the function object returned from bind(). template<typename _Signature> class _Bind; @@ -501,6 +512,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ); } +#ifdef _GLIBCXX_VOLATILE_BIND // Call as volatile template<typename _Result, typename... _Args, std::size_t... _Indexes> _Result @@ -522,6 +534,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Mu<_Bound_args>()(__volget<_Indexes>(_M_bound_args), __args)... ); } +#endif // volatile template<typename _BoundArg, typename _CallArgs> using _Mu_type = decltype( @@ -585,12 +598,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Bound_indexes()); } -#if __cplusplus > 201402L -# define _GLIBCXX_DEPR_BIND \ - [[deprecated("std::bind does not support volatile in C++17")]] -#else -# define _GLIBCXX_DEPR_BIND -#endif +#ifdef _GLIBCXX_VOLATILE_BIND // Call as volatile template<typename... _Args, typename _Result = _Res_type_cv<tuple<_Args...>, add_volatile>> @@ -614,6 +622,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION std::forward_as_tuple(std::forward<_Args>(__args)...), _Bound_indexes()); } +#endif // volatile }; /// Type of the function object returned from bind<R>(). @@ -649,9 +658,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION (std::get<_Indexes>(_M_bound_args), __args)...); } +#ifdef _GLIBCXX_VOLATILE_BIND // Call as volatile template<typename _Res, typename... _Args, std::size_t... _Indexes> - _GLIBCXX20_CONSTEXPR _Res __call(tuple<_Args...>&& __args, _Index_tuple<_Indexes...>) volatile { @@ -661,7 +670,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Call as const volatile template<typename _Res, typename... _Args, std::size_t... _Indexes> - _GLIBCXX20_CONSTEXPR _Res __call(tuple<_Args...>&& __args, _Index_tuple<_Indexes...>) const volatile @@ -669,6 +677,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return std::__invoke_r<_Res>(_M_f, _Mu<_Bound_args>() (__volget<_Indexes>(_M_bound_args), __args)...); } +#endif // volatile public: typedef _Result result_type; @@ -710,6 +719,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Bound_indexes()); } +#ifdef _GLIBCXX_VOLATILE_BIND // Call as volatile template<typename... _Args> _GLIBCXX_DEPR_BIND @@ -731,7 +741,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION std::forward_as_tuple(std::forward<_Args>(__args)...), _Bound_indexes()); } +#else + template<typename... _Args> + void operator()(_Args&&...) const volatile = delete; +#endif // volatile }; + +#undef _GLIBCXX_VOLATILE_BIND #undef _GLIBCXX_DEPR_BIND /** diff --git a/libstdc++-v3/include/std/future b/libstdc++-v3/include/std/future index a1b2d7f..cf08c15 100644 --- a/libstdc++-v3/include/std/future +++ b/libstdc++-v3/include/std/future @@ -1649,8 +1649,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Res, typename... _ArgTypes> packaged_task(_Res(*)(_ArgTypes...)) -> packaged_task<_Res(_ArgTypes...)>; - template<typename _Fun, typename _Signature = typename - __function_guide_helper<decltype(&_Fun::operator())>::type> + template<typename _Fun, typename _Signature + = __function_guide_t<_Fun, decltype(&_Fun::operator())>> packaged_task(_Fun) -> packaged_task<_Signature>; #endif diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits index c5853fc..22c1af2 100644 --- a/libstdc++-v3/include/std/type_traits +++ b/libstdc++-v3/include/std/type_traits @@ -1381,6 +1381,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : public integral_constant<bool, __is_base_of(_Base, _Derived)> { }; +#if __has_builtin(__is_convertible) + template<typename _From, typename _To> + struct is_convertible + : public __bool_constant<__is_convertible(_From, _To)> + { }; +#else template<typename _From, typename _To, bool = __or_<is_void<_From>, is_function<_To>, is_array<_To>>::value> @@ -1416,12 +1422,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct is_convertible : public __is_convertible_helper<_From, _To>::type { }; +#endif // helper trait for unique_ptr<T[]>, shared_ptr<T[]>, and span<T, N> template<typename _ToElementType, typename _FromElementType> using __is_array_convertible = is_convertible<_FromElementType(*)[], _ToElementType(*)[]>; +#if __cplusplus >= 202002L +#define __cpp_lib_is_nothrow_convertible 201806L + +#if __has_builtin(__is_nothrow_convertible) + /// is_nothrow_convertible_v + template<typename _From, typename _To> + inline constexpr bool is_nothrow_convertible_v + = __is_nothrow_convertible(_From, _To); + + /// is_nothrow_convertible + template<typename _From, typename _To> + struct is_nothrow_convertible + : public bool_constant<is_nothrow_convertible_v<_From, _To>> + { }; +#else template<typename _From, typename _To, bool = __or_<is_void<_From>, is_function<_To>, is_array<_To>>::value> @@ -1451,8 +1473,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION }; #pragma GCC diagnostic pop -#if __cplusplus > 201703L -#define __cpp_lib_is_nothrow_convertible 201806L /// is_nothrow_convertible template<typename _From, typename _To> struct is_nothrow_convertible @@ -1463,6 +1483,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _From, typename _To> inline constexpr bool is_nothrow_convertible_v = is_nothrow_convertible<_From, _To>::value; +#endif #endif // C++2a // Const-volatile modifications. @@ -2843,7 +2864,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __is_invocable_impl : false_type { - using __nothrow_type = false_type; // For is_nothrow_invocable_r + using __nothrow_conv = false_type; // For is_nothrow_invocable_r }; // Used for valid INVOKE and INVOKE<void> expressions. @@ -2853,7 +2874,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __void_t<typename _Result::type>> : true_type { - using __nothrow_type = true_type; // For is_nothrow_invocable_r + using __nothrow_conv = true_type; // For is_nothrow_invocable_r }; #pragma GCC diagnostic push @@ -2866,18 +2887,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { private: // The type of the INVOKE expression. + using _Res_t = typename _Result::type; + // Unlike declval, this doesn't add_rvalue_reference, so it respects // guaranteed copy elision. - static typename _Result::type _S_get() noexcept; + static _Res_t _S_get() noexcept; + // Used to check if _Res_t can implicitly convert to _Tp. template<typename _Tp> - static void _S_conv(_Tp) noexcept; + static void _S_conv(__type_identity_t<_Tp>) noexcept; // This overload is viable if INVOKE(f, args...) can convert to _Tp. - template<typename _Tp, bool _Check_Noex = false, + template<typename _Tp, + bool _Nothrow = noexcept(_S_conv<_Tp>(_S_get())), typename = decltype(_S_conv<_Tp>(_S_get())), - bool _Noex = noexcept(_S_conv<_Tp>(_S_get()))> - static __bool_constant<_Check_Noex ? _Noex : true> + bool _Dangle = __reference_converts_from_temporary(_Tp, _Res_t)> + static __bool_constant<_Nothrow && !_Dangle> _S_test(int); template<typename _Tp, bool = false> @@ -2886,10 +2911,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION public: // For is_invocable_r - using type = decltype(_S_test<_Ret>(1)); + using type = decltype(_S_test<_Ret, /* Nothrow = */ true>(1)); // For is_nothrow_invocable_r - using __nothrow_type = decltype(_S_test<_Ret, true>(1)); + using __nothrow_conv = decltype(_S_test<_Ret>(1)); }; #pragma GCC diagnostic pop @@ -3020,9 +3045,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION }; /// @cond undocumented + // This checks that the INVOKE<R> expression is well-formed and that the + // conversion to R does not throw. It does *not* check whether the INVOKE + // expression itself can throw. That is done by __call_is_nothrow_ instead. template<typename _Result, typename _Ret> using __is_nt_invocable_impl - = typename __is_invocable_impl<_Result, _Ret>::__nothrow_type; + = typename __is_invocable_impl<_Result, _Ret>::__nothrow_conv; /// @endcond /// std::is_nothrow_invocable_r @@ -3265,7 +3293,7 @@ template <typename _Tp> template <typename _Base, typename _Derived> inline constexpr bool is_base_of_v = __is_base_of(_Base, _Derived); template <typename _From, typename _To> - inline constexpr bool is_convertible_v = is_convertible<_From, _To>::value; + inline constexpr bool is_convertible_v = __is_convertible(_From, _To); template<typename _Fn, typename... _Args> inline constexpr bool is_invocable_v = is_invocable<_Fn, _Args...>::value; template<typename _Fn, typename... _Args> diff --git a/libstdc++-v3/testsuite/20_util/bind/cv_quals.cc b/libstdc++-v3/testsuite/20_util/bind/cv_quals.cc index 8331239..79e3e2f 100644 --- a/libstdc++-v3/testsuite/20_util/bind/cv_quals.cc +++ b/libstdc++-v3/testsuite/20_util/bind/cv_quals.cc @@ -17,6 +17,7 @@ // 20.7.11 Function template bind +// { dg-options "-Wdeprecated-declarations" } // { dg-do run { target c++11 } } #include <functional> @@ -48,12 +49,12 @@ void test01() const auto b1 = std::bind(X()); VERIFY( b1() == 1 ); -#if __cplusplus <= 201402L +#if __cplusplus <= 201703L volatile auto b2 = std::bind(X()); - VERIFY( b2() == 2 ); + VERIFY( b2() == 2 ); // { dg-warning "deprecated" "" { target c++17_only } } const volatile auto b3 = std::bind(X()); - VERIFY( b3() == 3 ); + VERIFY( b3() == 3 ); // { dg-warning "deprecated" "" { target c++17_only } } #endif } @@ -65,12 +66,12 @@ void test02() const auto b1 = std::bind<int>(X()); VERIFY( b1() == 1 ); -#if __cplusplus <= 201402L +#if __cplusplus <= 201703L volatile auto b2 = std::bind<int>(X()); - VERIFY( b2() == 2 ); + VERIFY( b2() == 2 ); // { dg-warning "deprecated" "" { target c++17_only } } const volatile auto b3 = std::bind<int>(X()); - VERIFY( b3() == 3 ); + VERIFY( b3() == 3 ); // { dg-warning "deprecated" "" { target c++17_only } } #endif } @@ -82,12 +83,12 @@ void test03() const auto b1 = std::bind(X(), _1, 0, _2); VERIFY( b1(0, 0) == 1 ); -#if __cplusplus <= 201402L +#if __cplusplus <= 201703L volatile auto b2 = std::bind(X(), _1, _2, 0); - VERIFY( b2(0, 0) == 2 ); + VERIFY( b2(0, 0) == 2 ); // { dg-warning "deprecated" "" { target c++17_only } } const volatile auto b3 = std::bind(X(), _1, 0, _2); - VERIFY( b3(0, 0) == 3 ); + VERIFY( b3(0, 0) == 3 ); // { dg-warning "deprecated" "" { target c++17_only } } #endif } @@ -99,12 +100,12 @@ void test04() const auto b1 = std::bind<int>(X(), _1, 0, _2); VERIFY( b1(0, 0) == 1 ); -#if __cplusplus <= 201402L +#if __cplusplus <= 201703L volatile auto b2 = std::bind<int>(X(), _1, _2, 0); - VERIFY( b2(0, 0) == 2 ); + VERIFY( b2(0, 0) == 2 ); // { dg-warning "deprecated" "" { target c++17_only } } const volatile auto b3 = std::bind<int>(X(), _1, 0, _2); - VERIFY( b3(0, 0) == 3 ); + VERIFY( b3(0, 0) == 3 ); // { dg-warning "deprecated" "" { target c++17_only } } #endif } diff --git a/libstdc++-v3/testsuite/20_util/bind/cv_quals_2.cc b/libstdc++-v3/testsuite/20_util/bind/cv_quals_2.cc index 7a85568..d2ebad72 100644 --- a/libstdc++-v3/testsuite/20_util/bind/cv_quals_2.cc +++ b/libstdc++-v3/testsuite/20_util/bind/cv_quals_2.cc @@ -15,7 +15,9 @@ // with this library; see the file COPYING3. If not see // <http://www.gnu.org/licenses/>. -// { dg-do run { target c++11 } } +// { dg-options "-Wdeprecated-declarations" } +// { dg-do run { target { c++11 && c++17_down } } } +// { dg-do compile { target c++20 } } #include <functional> #include <testsuite_hooks.h> @@ -33,13 +35,13 @@ void test01() const auto b0 = std::bind(X()); VERIFY( b0() == 0 ); -#if __cplusplus <= 201402L volatile auto b1 = std::bind(X()); - VERIFY( b1() == 1 ); + VERIFY( b1() == 1 ); // { dg-warning "deprecated" "" { target c++17_only } } + // { dg-error "no match" "" { target c++20 } 39 } const volatile auto b2 = std::bind(X()); - VERIFY( b2() == 2 ); -#endif + VERIFY( b2() == 2 ); // { dg-warning "deprecated" "" { target c++17_only } } + // { dg-error "no match" "" { target c++20 } 43 } } int main() diff --git a/libstdc++-v3/testsuite/20_util/bind/dangling_ref.cc b/libstdc++-v3/testsuite/20_util/bind/dangling_ref.cc new file mode 100644 index 0000000..70393e4 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/bind/dangling_ref.cc @@ -0,0 +1,9 @@ +// { dg-do compile { target c++11 } } +#include <functional> + +int f(); +auto b = std::bind<const int&>(f); +int i = b(); // { dg-error "here" "" { target { c++14_down } } } +// { dg-error "dangling reference" "" { target { c++14_down } } 0 } +// { dg-error "no matching function" "" { target c++17 } 0 } +// { dg-error "enable_if" "" { target c++17 } 0 } diff --git a/libstdc++-v3/testsuite/20_util/function/cons/70692.cc b/libstdc++-v3/testsuite/20_util/function/cons/70692.cc new file mode 100644 index 0000000..7cdc472 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/function/cons/70692.cc @@ -0,0 +1,13 @@ +// { dg-do compile { target c++11 } } +// PR libstdc++/70692 +// No warning when function<const int&(...)> binds a reference to a temporary +#include <functional> + +int f(); + +int main() +{ + std::function<const int&()> ff(f); // { dg-error "no matching function" } + std::function<long&&()> f2(f); // { dg-error "no matching function" } +} +// { dg-error "std::enable_if" "" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/20_util/function/cons/deduction_c++23.cc b/libstdc++-v3/testsuite/20_util/function/cons/deduction_c++23.cc new file mode 100644 index 0000000..17454ea --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/function/cons/deduction_c++23.cc @@ -0,0 +1,23 @@ +// { dg-options "-std=gnu++23" } +// { dg-do compile { target c++23 } } + +#include <functional> + +template<typename T, typename U> struct require_same; +template<typename T> struct require_same<T, T> { using type = void; }; + +template<typename T, typename U> + typename require_same<T, U>::type + check_type(U&) { } + +void +test_static_call_operator() +{ + struct F1 { static long operator()() { return 0; } }; + std::function func1 = F1{}; + check_type<std::function<long()>>(func1); + + struct F2 { static float operator()(char, void*) noexcept { return 0; } }; + std::function func2 = F2{}; + check_type<std::function<float(char, void*)>>(func2); +} diff --git a/libstdc++-v3/testsuite/20_util/function_objects/invoke/dangling_ref.cc b/libstdc++-v3/testsuite/20_util/function_objects/invoke/dangling_ref.cc new file mode 100644 index 0000000..1513480 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/function_objects/invoke/dangling_ref.cc @@ -0,0 +1,12 @@ +// { dg-options "-std=gnu++23" } +// { dg-do compile { target c++23 } } +#include <functional> + +int f(); + +template<typename R> +concept can_invoke = requires (int (&f)()) { std::invoke_r<R>(f); }; + +static_assert( not can_invoke<const int&> ); +static_assert( not can_invoke<int&&> ); +static_assert( not can_invoke<const long&> ); diff --git a/libstdc++-v3/testsuite/20_util/is_convertible/requirements/access.cc b/libstdc++-v3/testsuite/20_util/is_convertible/requirements/access.cc new file mode 100644 index 0000000..04a8c52 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/is_convertible/requirements/access.cc @@ -0,0 +1,18 @@ +// { dg-do compile { target c++11 } } +// PR c++/107049 + +#include <type_traits> + +class Private +{ + operator int() const + { + static_assert( not std::is_convertible<Private, int>::value, "" ); +#if __cpp_lib_type_trait_variable_templates + static_assert( not std::is_convertible_v<Private, int>, "" ); +#endif + return 0; + } +}; + +static_assert( not std::is_convertible<Private, int>::value, "" ); diff --git a/libstdc++-v3/testsuite/20_util/is_invocable/dangling_ref.cc b/libstdc++-v3/testsuite/20_util/is_invocable/dangling_ref.cc new file mode 100644 index 0000000..46719b9 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/is_invocable/dangling_ref.cc @@ -0,0 +1,6 @@ +// { dg-do compile { target c++17 } } +#include <type_traits> + +static_assert( not std::is_invocable_r_v<const int&, int()> ); +static_assert( not std::is_invocable_r_v<int&&, int()> ); +static_assert( not std::is_invocable_r_v<const long&, int()> ); diff --git a/libstdc++-v3/testsuite/20_util/pointer_traits/lwg3545.cc b/libstdc++-v3/testsuite/20_util/pointer_traits/lwg3545.cc index 08c3ed0..93c64a3 100644 --- a/libstdc++-v3/testsuite/20_util/pointer_traits/lwg3545.cc +++ b/libstdc++-v3/testsuite/20_util/pointer_traits/lwg3545.cc @@ -99,3 +99,20 @@ static_assert( is_same<pointer<Ctraits>, clever_ptr<char>>::value, "" ); static_assert( is_same<difference_type<Ctraits>, std::ptrdiff_t>::value, "" ); static_assert( is_same<rebind<Ctraits>, clever_ptr<short>>::value, "" ); static_assert( is_same<pointer_to<Ctraits>, clever_ptr<char>>::value, "" ); + +#ifdef __cpp_concepts +struct ptr_base { }; + +// Program-defined specialization must not be ambiguous with primary template. +template<typename P> requires std::derived_from<P, ptr_base> +struct std::pointer_traits<P> +{ + using element_type = int; + using difference_type = long; + using pointer = P; +}; + +struct Ptr : ptr_base { using element_type = int; }; + +using E = std::pointer_traits<Ptr>::element_type; +#endif diff --git a/libstdc++-v3/testsuite/30_threads/packaged_task/cons/dangling_ref.cc b/libstdc++-v3/testsuite/30_threads/packaged_task/cons/dangling_ref.cc new file mode 100644 index 0000000..e9edb5e --- /dev/null +++ b/libstdc++-v3/testsuite/30_threads/packaged_task/cons/dangling_ref.cc @@ -0,0 +1,11 @@ +// { dg-do compile { target c++11 } } +#include <future> + +// C++20 [futures.task.members] +// Mandates: is_invocable_r_v<R, F&, ArgTypes...> is true. + +int f(); +std::packaged_task<const int&()> task(f); +// { dg-error "dangling reference" "" { target { c++14_down } } 0 } +// { dg-error "no matching function" "" { target c++17 } 0 } +// { dg-error "enable_if" "" { target c++17 } 0 } diff --git a/libstdc++-v3/testsuite/30_threads/packaged_task/cons/deduction_c++23.cc b/libstdc++-v3/testsuite/30_threads/packaged_task/cons/deduction_c++23.cc new file mode 100644 index 0000000..e36edfa0 --- /dev/null +++ b/libstdc++-v3/testsuite/30_threads/packaged_task/cons/deduction_c++23.cc @@ -0,0 +1,23 @@ +// { dg-options "-std=gnu++23" } +// { dg-do compile { target c++23 } } + +#include <future> + +template<typename T, typename U> struct require_same; +template<typename T> struct require_same<T, T> { using type = void; }; + +template<typename T, typename U> + typename require_same<T, U>::type + check_type(U&) { } + +void +test_static_call_operator() +{ + struct F1 { static long operator()() { return 0; } }; + std::packaged_task task1{ F1{} }; + check_type<std::packaged_task<long()>>(task1); + + struct F2 { static float operator()(char, void*) noexcept { return 0; } }; + std::packaged_task task2{ F2{} }; + check_type<std::packaged_task<float(char, void*)>>(task2); +} |