From 28a61ecdc176edca4bf4affb4c8ac7b9b9a72b06 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sun, 25 Sep 2022 00:18:01 +0000 Subject: Daily bump. --- gcc/ChangeLog | 11 +++++++++++ gcc/DATESTAMP | 2 +- gcc/c/ChangeLog | 7 +++++++ gcc/testsuite/ChangeLog | 10 ++++++++++ 4 files changed, 29 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4ff50c3..1c8a0d9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2022-09-24 Jakub Jelinek + + PR c/107001 + * omp-low.cc (lower_omp_taskgroup): Don't add GOMP_RETURN statement + at the end. + * omp-expand.cc (build_omp_regions_1): Clarify GF_OMP_TARGET_KIND_DATA + is not stand-alone directive. For GIMPLE_OMP_TASKGROUP, also don't + update parent. + (omp_make_gimple_edges) : Reset + cur_region back after new_omp_region. + 2022-09-23 Vineet Gupta * config/riscv/riscv.h (LOCAL_SYM_P): New. diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index c0c32de..38f463d 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20220924 +20220925 diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 21248d3..4b852b8 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,10 @@ +2022-09-24 Jakub Jelinek + + PR c/106981 + * c-typeck.cc (c_tree_equal): Only strip NON_LVALUE_EXPRs at the + start. For CONSTANT_CLASS_P or CASE_CONVERT: return false if t1 and + t2 have different types. + 2022-09-22 David Malcolm PR c/106830 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d37e199..a5ff3de 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,13 @@ +2022-09-24 Jakub Jelinek + + PR c/107001 + * c-c++-common/gomp/pr107001.c: New test. + +2022-09-24 Jakub Jelinek + + PR c/106981 + * c-c++-common/gomp/pr106981.c: New test. + 2022-09-23 Joseph Myers * gcc.dg/c2x-complit-1.c, gcc.dg/c2x-concat-1.c, -- cgit v1.1 From 323c38c915f34883439e9e53b9eac5fe07cb8378 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torbj=C3=B6rn=20SVENSSON?= Date: Fri, 23 Sep 2022 20:38:45 +0200 Subject: Fix typo in chapter level for RISC-V attributes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "RISC-V specific attributes" section should be at the same level as "PowerPC-specific attributes". gcc/ChangeLog: * doc/sourcebuild.texi: Fix chapter level. Signed-off-by: Torbjörn SVENSSON --- gcc/doc/sourcebuild.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi index 760ff95..52357cc 100644 --- a/gcc/doc/sourcebuild.texi +++ b/gcc/doc/sourcebuild.texi @@ -2447,7 +2447,7 @@ PowerPC target pre-defines macro _ARCH_PWR9 which means the @code{-mcpu} setting is Power9 or later. @end table -@subsection RISC-V specific attributes +@subsubsection RISC-V specific attributes @table @code -- cgit v1.1 From 2b393f6f83903cb836676bbd042c1b99a6e7e6f7 Mon Sep 17 00:00:00 2001 From: Mikael Morin Date: Wed, 31 Aug 2022 11:00:45 +0200 Subject: fortran: Move the clobber generation code This change inlines the clobber generation code from gfc_conv_expr_reference to the single caller from where the add_clobber flag can be true, and removes the add_clobber argument. What motivates this is the standard making the procedure call a cause for a variable to become undefined, which translates to a clobber generation, so clobber generation should be closely related to procedure call generation, whereas it is rather orthogonal to variable reference generation. Thus the generation of the clobber feels more appropriate in gfc_conv_procedure_call than in gfc_conv_expr_reference. Behaviour remains unchanged. gcc/fortran/ChangeLog: * trans.h (gfc_conv_expr_reference): Remove add_clobber argument. * trans-expr.cc (gfc_conv_expr_reference): Ditto. Inline code depending on add_clobber and conditions controlling it ... (gfc_conv_procedure_call): ... to here. --- gcc/fortran/trans-expr.cc | 60 +++++++++++++++++++++++++---------------------- gcc/fortran/trans.h | 3 +-- 2 files changed, 33 insertions(+), 30 deletions(-) (limited to 'gcc') diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc index 7895d03..7cdab1c 100644 --- a/gcc/fortran/trans-expr.cc +++ b/gcc/fortran/trans-expr.cc @@ -6395,7 +6395,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, && e->symtree->n.sym->attr.pointer)) && fsym && fsym->attr.target) /* Make sure the function only gets called once. */ - gfc_conv_expr_reference (&parmse, e, false); + gfc_conv_expr_reference (&parmse, e); else if (e->expr_type == EXPR_FUNCTION && e->symtree->n.sym->result && e->symtree->n.sym->result != e->symtree->n.sym @@ -6502,22 +6502,36 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, } else { - bool add_clobber; - add_clobber = fsym && fsym->attr.intent == INTENT_OUT - && !fsym->attr.allocatable && !fsym->attr.pointer - && e->symtree && e->symtree->n.sym - && !e->symtree->n.sym->attr.dimension - && !e->symtree->n.sym->attr.pointer - && !e->symtree->n.sym->attr.allocatable - /* See PR 41453. */ - && !e->symtree->n.sym->attr.dummy - /* FIXME - PR 87395 and PR 41453 */ - && e->symtree->n.sym->attr.save == SAVE_NONE - && !e->symtree->n.sym->attr.associate_var - && e->ts.type != BT_CHARACTER && e->ts.type != BT_DERIVED - && e->ts.type != BT_CLASS && !sym->attr.elemental; - - gfc_conv_expr_reference (&parmse, e, add_clobber); + gfc_conv_expr_reference (&parmse, e); + + if (fsym + && fsym->attr.intent == INTENT_OUT + && !fsym->attr.allocatable + && !fsym->attr.pointer + && e->expr_type == EXPR_VARIABLE + && e->ref == NULL + && e->symtree + && e->symtree->n.sym + && !e->symtree->n.sym->attr.dimension + && !e->symtree->n.sym->attr.pointer + && !e->symtree->n.sym->attr.allocatable + /* See PR 41453. */ + && !e->symtree->n.sym->attr.dummy + /* FIXME - PR 87395 and PR 41453 */ + && e->symtree->n.sym->attr.save == SAVE_NONE + && !e->symtree->n.sym->attr.associate_var + && e->ts.type != BT_CHARACTER + && e->ts.type != BT_DERIVED + && e->ts.type != BT_CLASS + && !sym->attr.elemental) + { + tree var; + /* FIXME: This fails if var is passed by reference, see PR + 41453. */ + var = e->symtree->n.sym->backend_decl; + tree clobber = build_clobber (TREE_TYPE (var)); + gfc_add_modify (&se->pre, var, clobber); + } } /* Catch base objects that are not variables. */ if (e->ts.type == BT_CLASS @@ -9484,7 +9498,7 @@ gfc_conv_expr_type (gfc_se * se, gfc_expr * expr, tree type) values only. */ void -gfc_conv_expr_reference (gfc_se * se, gfc_expr * expr, bool add_clobber) +gfc_conv_expr_reference (gfc_se * se, gfc_expr * expr) { gfc_ss *ss; tree var; @@ -9524,16 +9538,6 @@ gfc_conv_expr_reference (gfc_se * se, gfc_expr * expr, bool add_clobber) gfc_add_block_to_block (&se->pre, &se->post); se->expr = var; } - else if (add_clobber && expr->ref == NULL) - { - tree clobber; - tree var; - /* FIXME: This fails if var is passed by reference, see PR - 41453. */ - var = expr->symtree->n.sym->backend_decl; - clobber = build_clobber (TREE_TYPE (var)); - gfc_add_modify (&se->pre, var, clobber); - } return; } diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h index 03d5288..bc9035c 100644 --- a/gcc/fortran/trans.h +++ b/gcc/fortran/trans.h @@ -499,8 +499,7 @@ tree gfc_build_compare_string (tree, tree, tree, tree, int, enum tree_code); void gfc_conv_expr (gfc_se * se, gfc_expr * expr); void gfc_conv_expr_val (gfc_se * se, gfc_expr * expr); void gfc_conv_expr_lhs (gfc_se * se, gfc_expr * expr); -void gfc_conv_expr_reference (gfc_se * se, gfc_expr * expr, - bool add_clobber = false); +void gfc_conv_expr_reference (gfc_se * se, gfc_expr * expr); void gfc_conv_expr_type (gfc_se * se, gfc_expr *, tree); -- cgit v1.1 From edaf1e005c90b311c39b46d85cea17befbece112 Mon Sep 17 00:00:00 2001 From: Mikael Morin Date: Mon, 29 Aug 2022 11:19:29 +0200 Subject: fortran: Fix invalid function decl clobber ICE [PR105012] The fortran frontend, as result symbol for a function without declared result symbol, uses the function symbol itself. This caused an invalid clobber of a function decl to be emitted, leading to an ICE, whereas the intended behaviour was to clobber the function result variable. This change fixes the problem by getting the decl from the just-retrieved variable reference after the call to gfc_conv_expr_reference, instead of copying it from the frontend symbol. PR fortran/105012 gcc/fortran/ChangeLog: * trans-expr.cc (gfc_conv_procedure_call): Retrieve variable from the just calculated variable reference. gcc/testsuite/ChangeLog: * gfortran.dg/intent_out_15.f90: New test. --- gcc/fortran/trans-expr.cc | 3 ++- gcc/testsuite/gfortran.dg/intent_out_15.f90 | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gfortran.dg/intent_out_15.f90 (limited to 'gcc') diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc index 7cdab1c..8fb6335 100644 --- a/gcc/fortran/trans-expr.cc +++ b/gcc/fortran/trans-expr.cc @@ -6528,7 +6528,8 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, tree var; /* FIXME: This fails if var is passed by reference, see PR 41453. */ - var = e->symtree->n.sym->backend_decl; + var = build_fold_indirect_ref_loc (input_location, + parmse.expr); tree clobber = build_clobber (TREE_TYPE (var)); gfc_add_modify (&se->pre, var, clobber); } diff --git a/gcc/testsuite/gfortran.dg/intent_out_15.f90 b/gcc/testsuite/gfortran.dg/intent_out_15.f90 new file mode 100644 index 0000000..64334e6 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/intent_out_15.f90 @@ -0,0 +1,27 @@ +! { dg-do compile } +! { dg-additional-options "-fdump-tree-original" } +! +! PR fortran/105012 +! The following case was triggering an ICE because of a clobber +! on the DERFC function decl instead of its result. + +module error_function +integer, parameter :: r8 = selected_real_kind(12) ! 8 byte real +contains +SUBROUTINE CALERF_r8(ARG, RESULT, JINT) + integer, parameter :: rk = r8 + real(rk), intent(in) :: arg + real(rk), intent(out) :: result + IF (Y .LE. THRESH) THEN + END IF +end SUBROUTINE CALERF_r8 +FUNCTION DERFC(X) + integer, parameter :: rk = r8 ! 8 byte real + real(rk), intent(in) :: X + real(rk) :: DERFC + CALL CALERF_r8(X, DERFC, JINT) +END FUNCTION DERFC +end module error_function + +! { dg-final { scan-tree-dump-times "CLOBBER" 1 "original" } } +! { dg-final { scan-tree-dump "__result_derfc = {CLOBBER};" "original" } } -- cgit v1.1 From 29919bf3b6449bafd02e795abbb1966e3990c1fc Mon Sep 17 00:00:00 2001 From: Mikael Morin Date: Sat, 3 Sep 2022 11:58:47 +0200 Subject: fortran: Move clobbers after evaluation of all arguments [PR106817] For actual arguments whose dummy is INTENT(OUT), we used to generate clobbers on them at the same time we generated the argument reference for the function call. This was wrong if for an argument coming later, the value expression was depending on the value of the just- clobbered argument, and we passed an undefined value in that case. With this change, clobbers are collected separatedly and appended to the procedure call preliminary code after all the arguments have been evaluated. PR fortran/106817 gcc/fortran/ChangeLog: * trans-expr.cc (gfc_conv_procedure_call): Collect all clobbers to their own separate block. Append the block of clobbers to the procedure preliminary block after the argument evaluation codes for all the arguments. gcc/testsuite/ChangeLog: * gfortran.dg/intent_optimize_4.f90: New test. --- gcc/fortran/trans-expr.cc | 6 ++-- gcc/testsuite/gfortran.dg/intent_optimize_4.f90 | 43 +++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/intent_optimize_4.f90 (limited to 'gcc') diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc index 8fb6335..f93923b 100644 --- a/gcc/fortran/trans-expr.cc +++ b/gcc/fortran/trans-expr.cc @@ -6018,7 +6018,6 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, gfc_charlen cl; gfc_expr *e; gfc_symbol *fsym; - stmtblock_t post; enum {MISSING = 0, ELEMENTAL, SCALAR, SCALAR_POINTER, ARRAY}; gfc_component *comp = NULL; int arglen; @@ -6062,7 +6061,9 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, else info = NULL; + stmtblock_t post, clobbers; gfc_init_block (&post); + gfc_init_block (&clobbers); gfc_init_interface_mapping (&mapping); if (!comp) { @@ -6531,7 +6532,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, var = build_fold_indirect_ref_loc (input_location, parmse.expr); tree clobber = build_clobber (TREE_TYPE (var)); - gfc_add_modify (&se->pre, var, clobber); + gfc_add_modify (&clobbers, var, clobber); } } /* Catch base objects that are not variables. */ @@ -7399,6 +7400,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, vec_safe_push (arglist, parmse.expr); } + gfc_add_block_to_block (&se->pre, &clobbers); gfc_finish_interface_mapping (&mapping, &se->pre, &se->post); if (comp) diff --git a/gcc/testsuite/gfortran.dg/intent_optimize_4.f90 b/gcc/testsuite/gfortran.dg/intent_optimize_4.f90 new file mode 100644 index 0000000..effbaa1 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/intent_optimize_4.f90 @@ -0,0 +1,43 @@ +! { dg-do run } +! { dg-additional-options "-fdump-tree-original" } +! { dg-final { scan-tree-dump-times "CLOBBER" 2 "original" } } +! +! PR fortran/106817 +! Check that for an actual argument whose dummy is INTENT(OUT), +! the clobber that is emitted in the caller before a procedure call +! happens after any expression depending on the argument value has been +! evaluated. +! + +module m + implicit none +contains + subroutine copy1(out, in) + integer, intent(in) :: in + integer, intent(out) :: out + out = in + end subroutine copy1 + subroutine copy2(in, out) + integer, intent(in) :: in + integer, intent(out) :: out + out = in + end subroutine copy2 +end module m + +program p + use m + implicit none + integer :: a, b + + ! Clobbering of a should happen after a+1 has been evaluated. + a = 3 + call copy1(a, a+1) + if (a /= 4) stop 1 + + ! Clobbering order does not depend on the order of arguments. + ! It should also come last with reversed arguments. + b = 12 + call copy2(b+1, b) + if (b /= 13) stop 2 + +end program p -- cgit v1.1 From 20aa1eb6cb84e6a0487b47b28b00109c5f46a7e2 Mon Sep 17 00:00:00 2001 From: Harald Anlauf Date: Wed, 31 Aug 2022 11:50:35 +0200 Subject: fortran: Support clobbering with implicit interfaces [PR105012] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before procedure calls, we clobber actual arguments whose associated dummy is INTENT(OUT). This only applies to procedures with explicit interfaces, as the knowledge of the interface is necessary to know whether an argument has the INTENT(OUT) attribute. This change also enables clobber generation for procedure calls without explicit interface, when the procedure has been defined in the same file because we can use the dummy arguments' characteristics from the procedure definition in that case. The knowledge of the dummy characteristics is directly available through gfc_actual_arglist’s associated_dummy pointers which have been populated as a side effect of calling gfc_check_externals. PR fortran/105012 gcc/fortran/ChangeLog: * trans-expr.cc (gfc_conv_procedure_call): Use dummy information from associated_dummy if there is no information from the procedure interface. gcc/testsuite/ChangeLog: * gfortran.dg/intent_optimize_5.f90: New test. Co-Authored-By: Mikael Morin --- gcc/fortran/trans-expr.cc | 19 +++++++++++++++---- gcc/testsuite/gfortran.dg/intent_optimize_5.f90 | 24 ++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/intent_optimize_5.f90 (limited to 'gcc') diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc index f93923b..2147262 100644 --- a/gcc/fortran/trans-expr.cc +++ b/gcc/fortran/trans-expr.cc @@ -6505,10 +6505,21 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, { gfc_conv_expr_reference (&parmse, e); - if (fsym - && fsym->attr.intent == INTENT_OUT - && !fsym->attr.allocatable - && !fsym->attr.pointer + gfc_symbol *dsym = fsym; + gfc_dummy_arg *dummy; + + /* Use associated dummy as fallback for formal + argument if there is no explicit interface. */ + if (dsym == NULL + && (dummy = arg->associated_dummy) + && dummy->intrinsicness == GFC_NON_INTRINSIC_DUMMY_ARG + && dummy->u.non_intrinsic->sym) + dsym = dummy->u.non_intrinsic->sym; + + if (dsym + && dsym->attr.intent == INTENT_OUT + && !dsym->attr.allocatable + && !dsym->attr.pointer && e->expr_type == EXPR_VARIABLE && e->ref == NULL && e->symtree diff --git a/gcc/testsuite/gfortran.dg/intent_optimize_5.f90 b/gcc/testsuite/gfortran.dg/intent_optimize_5.f90 new file mode 100644 index 0000000..2f184bf --- /dev/null +++ b/gcc/testsuite/gfortran.dg/intent_optimize_5.f90 @@ -0,0 +1,24 @@ +! { dg-do run } +! { dg-additional-options "-fno-inline -fno-ipa-modref -fdump-tree-optimized -fdump-tree-original" } +! +! PR fortran/105012 +! Check that the INTENT(OUT) attribute causes one clobber to be emitted in +! the caller before the call to Y in the *.original dump, and the +! initialization constant to be optimized away in the *.optimized dump, +! despite the non-explicit interface if the subroutine with the INTENT(OUT) +! is declared in the same file. + +SUBROUTINE Y (Z) + integer, intent(out) :: Z + Z = 42 +END SUBROUTINE Y +PROGRAM TEST + integer :: X + X = 123456789 + CALL Y (X) + if (X.ne.42) STOP 1 +END PROGRAM + +! { dg-final { scan-tree-dump-times "CLOBBER" 1 "original" } } +! { dg-final { scan-tree-dump "x = {CLOBBER};" "original" } } +! { dg-final { scan-tree-dump-not "123456789" "optimized" { target __OPTIMIZE__ } } } -- cgit v1.1 From 51c9480f9f0a80ef112ba2aed040b0b2ad0fc2a2 Mon Sep 17 00:00:00 2001 From: Mikael Morin Date: Mon, 29 Aug 2022 13:27:02 +0200 Subject: fortran: Support clobbering of reference variables [PR41453] This adds support for clobbering of variables passed by reference, when the reference is forwarded to a subroutine as actual argument whose associated dummy has the INTENT(OUT) attribute. This was explicitly disabled by a condition added with r9-3032-gee7fb0588c6361b4d77337ab0f7527be64fcdde2 and removing that condition seems to work, as demonstrated by the new testcase. PR fortran/41453 PR fortran/87395 gcc/fortran/ChangeLog: * trans-expr.cc (gfc_conv_procedure_call): Remove condition disabling clobber generation for dummy variables. Remove obsolete comment. gcc/testsuite/ChangeLog: * gfortran.dg/intent_optimize_6.f90: New test. --- gcc/fortran/trans-expr.cc | 4 --- gcc/testsuite/gfortran.dg/intent_optimize_6.f90 | 34 +++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/intent_optimize_6.f90 (limited to 'gcc') diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc index 2147262..11b7c05 100644 --- a/gcc/fortran/trans-expr.cc +++ b/gcc/fortran/trans-expr.cc @@ -6527,8 +6527,6 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, && !e->symtree->n.sym->attr.dimension && !e->symtree->n.sym->attr.pointer && !e->symtree->n.sym->attr.allocatable - /* See PR 41453. */ - && !e->symtree->n.sym->attr.dummy /* FIXME - PR 87395 and PR 41453 */ && e->symtree->n.sym->attr.save == SAVE_NONE && !e->symtree->n.sym->attr.associate_var @@ -6538,8 +6536,6 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, && !sym->attr.elemental) { tree var; - /* FIXME: This fails if var is passed by reference, see PR - 41453. */ var = build_fold_indirect_ref_loc (input_location, parmse.expr); tree clobber = build_clobber (TREE_TYPE (var)); diff --git a/gcc/testsuite/gfortran.dg/intent_optimize_6.f90 b/gcc/testsuite/gfortran.dg/intent_optimize_6.f90 new file mode 100644 index 0000000..72fec3d --- /dev/null +++ b/gcc/testsuite/gfortran.dg/intent_optimize_6.f90 @@ -0,0 +1,34 @@ +! { dg-do run } +! { dg-additional-options "-fno-inline -fno-ipa-modref -fdump-tree-optimized -fdump-tree-original" } +! +! PR fortran/41453 +! Check that the INTENT(OUT) attribute causes one clobber to be emitted in +! the caller before each call to FOO in the *.original dump, and the +! initialization constant to be optimized away in the *.optimized dump, +! in the case of an argument passed by reference to the caller. + +module x +implicit none +contains + subroutine foo(a) + integer(kind=4), intent(out) :: a + a = 42 + end subroutine foo + subroutine bar(b) + integer(kind=4) :: b + b = 123456789 + call foo(b) + end subroutine bar +end module x + +program main + use x + implicit none + integer(kind=4) :: c + call bar(c) + if (c /= 42) stop 1 +end program main + +! { dg-final { scan-tree-dump-times "CLOBBER" 1 "original" } } +! { dg-final { scan-tree-dump "\\*\\\(integer\\\(kind=4\\\) \\*\\\) b = {CLOBBER};" "original" } } +! { dg-final { scan-tree-dump-not "123456789" "optimized" { target __OPTIMIZE__ } } } -- cgit v1.1 From 467ef2c40dbaf9d1219d9642e90df77dc61f4fae Mon Sep 17 00:00:00 2001 From: Mikael Morin Date: Wed, 31 Aug 2022 11:54:47 +0200 Subject: fortran: Support clobbering of SAVE variables [PR41453] This removes a condition added in: r9-3032-gee7fb0588c6361b4d77337ab0f7527be64fcdde2. That commit added a condition to avoid generating ICE with clobbers of variables with the SAVE attribute. The test added at that point continues to pass if we remove that condition now. PR fortran/41453 PR fortran/87395 gcc/fortran/ChangeLog: * trans-expr.cc (gfc_conv_procedure_call): Remove condition on SAVE attribute guarding clobber generation. gcc/testsuite/ChangeLog: * gfortran.dg/intent_optimize_7.f90: New test. --- gcc/fortran/trans-expr.cc | 2 -- gcc/testsuite/gfortran.dg/intent_optimize_7.f90 | 45 +++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/intent_optimize_7.f90 (limited to 'gcc') diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc index 11b7c05..10b4934 100644 --- a/gcc/fortran/trans-expr.cc +++ b/gcc/fortran/trans-expr.cc @@ -6527,8 +6527,6 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, && !e->symtree->n.sym->attr.dimension && !e->symtree->n.sym->attr.pointer && !e->symtree->n.sym->attr.allocatable - /* FIXME - PR 87395 and PR 41453 */ - && e->symtree->n.sym->attr.save == SAVE_NONE && !e->symtree->n.sym->attr.associate_var && e->ts.type != BT_CHARACTER && e->ts.type != BT_DERIVED diff --git a/gcc/testsuite/gfortran.dg/intent_optimize_7.f90 b/gcc/testsuite/gfortran.dg/intent_optimize_7.f90 new file mode 100644 index 0000000..c2f2192 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/intent_optimize_7.f90 @@ -0,0 +1,45 @@ +! { dg-do run } +! { dg-additional-options "-fno-inline -fno-ipa-modref -fdump-tree-optimized -fdump-tree-original" } +! +! PR fortran/41453 +! Check that the INTENT(OUT) attribute causes one clobber to be emitted in +! the caller before each call to FOO in the *.original dump, and the +! initialization constants to be optimized away in the *.optimized dump, +! in the case of SAVE variables. + +module x +implicit none +contains + subroutine foo(a) + integer, intent(out) :: a + a = 42 + end subroutine foo +end module x + +program main + use x + implicit none + integer :: c = 0 + + ! implicit SAVE attribute + c = 123456789 + call foo(c) + if (c /= 42) stop 1 + + ! explicit SAVE attribute + call check_save_explicit + +contains + subroutine check_save_explicit + integer, save :: d + d = 987654321 + call foo(d) + if (d /= 42) stop 2 + end subroutine check_save_explicit +end program main + +! { dg-final { scan-tree-dump-times "CLOBBER" 2 "original" } } +! { dg-final { scan-tree-dump "c = {CLOBBER};" "original" } } +! { dg-final { scan-tree-dump "d = {CLOBBER};" "original" } } +! { dg-final { scan-tree-dump-not "123456789" "optimized" { target __OPTIMIZE__ } } } +! { dg-final { scan-tree-dump-not "987654321" "optimized" { target __OPTIMIZE__ } } } -- cgit v1.1 From d5e1935b09fa05093e31d7ce5e21b7e71957c103 Mon Sep 17 00:00:00 2001 From: Mikael Morin Date: Wed, 31 Aug 2022 11:58:08 +0200 Subject: fortran: Support clobbering of ASSOCIATE variables [PR41453] This is in spirit a revert of: r9-3051-gc109362313623d83fe0a5194bceaf994cf0c6ce0 That commit added a condition to avoid generating ICE with clobbers of ASSOCIATE variables. The test added at that point continues to pass if we remove that condition now. PR fortran/41453 PR fortran/87401 gcc/fortran/ChangeLog: * trans-expr.cc (gfc_conv_procedure_call): Remove condition disabling clobber generation for ASSOCIATE variables. gcc/testsuite/ChangeLog: * gfortran.dg/intent_optimize_8.f90: New test. --- gcc/fortran/trans-expr.cc | 1 - gcc/testsuite/gfortran.dg/intent_optimize_8.f90 | 45 +++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gfortran.dg/intent_optimize_8.f90 (limited to 'gcc') diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc index 10b4934..c2c7382 100644 --- a/gcc/fortran/trans-expr.cc +++ b/gcc/fortran/trans-expr.cc @@ -6527,7 +6527,6 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, && !e->symtree->n.sym->attr.dimension && !e->symtree->n.sym->attr.pointer && !e->symtree->n.sym->attr.allocatable - && !e->symtree->n.sym->attr.associate_var && e->ts.type != BT_CHARACTER && e->ts.type != BT_DERIVED && e->ts.type != BT_CLASS diff --git a/gcc/testsuite/gfortran.dg/intent_optimize_8.f90 b/gcc/testsuite/gfortran.dg/intent_optimize_8.f90 new file mode 100644 index 0000000..4336fce --- /dev/null +++ b/gcc/testsuite/gfortran.dg/intent_optimize_8.f90 @@ -0,0 +1,45 @@ +! { dg-do run } +! { dg-additional-options "-fno-inline -fno-ipa-modref -fdump-tree-optimized -fdump-tree-original" } +! +! PR fortran/41453 +! Check that the INTENT(OUT) attribute causes one clobber to be emitted in +! the caller before each call to FOO in the *.original dump, and the +! initialization constants to be optimized away in the *.optimized dump, +! in the case of associate variables. + +module x +implicit none +contains + subroutine foo(a) + integer, intent(out) :: a + a = 42 + end subroutine foo +end module x + +program main + use x + implicit none + integer :: c1, c2 + + c1 = 123456789 + associate (d1 => c1) + call foo(d1) + if (d1 /= 42) stop 1 + end associate + if (c1 /= 42) stop 2 + + c2 = 0 + associate (d2 => c2) + d2 = 987654321 + call foo(d2) + if (d2 /= 42) stop 3 + end associate + if (c2 /= 42) stop 4 + +end program main + +! { dg-final { scan-tree-dump-times "CLOBBER" 2 "original" } } +! { dg-final { scan-tree-dump "d1 = {CLOBBER};" "original" } } +! { dg-final { scan-tree-dump "\\*d2 = {CLOBBER};" "original" } } +! { dg-final { scan-tree-dump-not "123456789" "optimized" { target __OPTIMIZE__ } } } +! { dg-final { scan-tree-dump-not "987654321" "optimized" { target __OPTIMIZE__ } } } -- cgit v1.1 From 95375ffb3dd59f51e79408dd3b2b620dc1af71b1 Mon Sep 17 00:00:00 2001 From: Mikael Morin Date: Thu, 1 Sep 2022 11:27:36 +0200 Subject: fortran: Support clobbering of allocatables and pointers [PR41453] This adds support for clobbering of allocatable and pointer scalar variables passed as actual argument to a subroutine when the associated dummy has the INTENT(OUT) attribute. Support was explicitly disabled (since the beginning for pointers, since r11-7315-g2df374b337a5f6cf5528e91718e4e12e4006b7ae for allocatables), but the clobber generation code seems to support it well, as demonstrated by the newly added testcase. PR fortran/41453 PR fortran/99169 gcc/fortran/ChangeLog: * trans-expr.cc (gfc_conv_procedure_call): Remove conditions on ALLOCATABLE and POINTER attributes guarding clobber generation. gcc/testsuite/ChangeLog: * gfortran.dg/intent_optimize_9.f90: New test. --- gcc/fortran/trans-expr.cc | 2 -- gcc/testsuite/gfortran.dg/intent_optimize_9.f90 | 42 +++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/intent_optimize_9.f90 (limited to 'gcc') diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc index c2c7382..52b96fa 100644 --- a/gcc/fortran/trans-expr.cc +++ b/gcc/fortran/trans-expr.cc @@ -6525,8 +6525,6 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, && e->symtree && e->symtree->n.sym && !e->symtree->n.sym->attr.dimension - && !e->symtree->n.sym->attr.pointer - && !e->symtree->n.sym->attr.allocatable && e->ts.type != BT_CHARACTER && e->ts.type != BT_DERIVED && e->ts.type != BT_CLASS diff --git a/gcc/testsuite/gfortran.dg/intent_optimize_9.f90 b/gcc/testsuite/gfortran.dg/intent_optimize_9.f90 new file mode 100644 index 0000000..0146dff --- /dev/null +++ b/gcc/testsuite/gfortran.dg/intent_optimize_9.f90 @@ -0,0 +1,42 @@ +! { dg-do run } +! { dg-additional-options "-fno-inline -fno-ipa-modref -fdump-tree-optimized -fdump-tree-original" } +! +! PR fortran/41453 +! Check that the INTENT(OUT) attribute causes one clobber to be emitted in +! the caller before each call to FOO in the *.original dump, and the +! initialization constants to be optimized away in the *.optimized dump, +! in the case of scalar allocatables and pointers. + +module x +implicit none +contains + subroutine foo(a) + integer, intent(out) :: a + a = 42 + end subroutine foo +end module x + +program main + use x + implicit none + integer, allocatable :: ca + integer, target :: ct + integer, pointer :: cp + + allocate(ca) + ca = 123456789 + call foo(ca) + if (ca /= 42) stop 1 + deallocate(ca) + + ct = 987654321 + cp => ct + call foo(cp) + if (ct /= 42) stop 2 +end program main + +! { dg-final { scan-tree-dump-times "CLOBBER" 2 "original" } } +! { dg-final { scan-tree-dump "\\*ca = {CLOBBER};" "original" } } +! { dg-final { scan-tree-dump "\\*cp = {CLOBBER};" "original" } } +! { dg-final { scan-tree-dump-not "123456789" "optimized" { target __OPTIMIZE__ } } } +! { dg-final { scan-tree-dump-not "987654321" "optimized" { target __OPTIMIZE__ } } } -- cgit v1.1 From 77bbf69d2981dafc2ef3e59bfbefb645d88bab9d Mon Sep 17 00:00:00 2001 From: Mikael Morin Date: Thu, 1 Sep 2022 12:35:07 +0200 Subject: fortran: Support clobbering of derived types [PR41453] This adds support for clobbering of non-polymorphic derived type variables, when they are passed as actual argument whose associated dummy has the INTENT(OUT) attribute. We avoid to play with non-constant type sizes or class descriptors by requiring that the types are derived (not class) and strictly matching, and by excluding parameterized derived types. Types that are used in the callee are also excluded: they are types with allocatable components (the components will be deallocated), and finalizable types or types with finalizable components (they will be passed to finalization routines). PR fortran/41453 gcc/fortran/ChangeLog: * trans-expr.cc (gfc_conv_procedure_call): Allow strictly matching derived types. gcc/testsuite/ChangeLog: * gfortran.dg/intent_optimize_10.f90: New test. --- gcc/fortran/trans-expr.cc | 18 ++++++- gcc/testsuite/gfortran.dg/intent_optimize_10.f90 | 66 ++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gfortran.dg/intent_optimize_10.f90 (limited to 'gcc') diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc index 52b96fa..4f3ae82 100644 --- a/gcc/fortran/trans-expr.cc +++ b/gcc/fortran/trans-expr.cc @@ -6526,8 +6526,24 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, && e->symtree->n.sym && !e->symtree->n.sym->attr.dimension && e->ts.type != BT_CHARACTER - && e->ts.type != BT_DERIVED && e->ts.type != BT_CLASS + && (e->ts.type != BT_DERIVED + || (dsym->ts.type == BT_DERIVED + && e->ts.u.derived == dsym->ts.u.derived + /* Types with allocatable components are + excluded from clobbering because we need + the unclobbered pointers to free the + allocatable components in the callee. + Same goes for finalizable types or types + with finalizable components, we need to + pass the unclobbered values to the + finalization routines. + For parameterized types, it's less clear + but they may not have a constant size + so better exclude them in any case. */ + && !e->ts.u.derived->attr.alloc_comp + && !e->ts.u.derived->attr.pdt_type + && !gfc_is_finalizable (e->ts.u.derived, NULL))) && !sym->attr.elemental) { tree var; diff --git a/gcc/testsuite/gfortran.dg/intent_optimize_10.f90 b/gcc/testsuite/gfortran.dg/intent_optimize_10.f90 new file mode 100644 index 0000000..d8bc1bb --- /dev/null +++ b/gcc/testsuite/gfortran.dg/intent_optimize_10.f90 @@ -0,0 +1,66 @@ +! { dg-do run } +! { dg-additional-options "-fno-inline -fno-ipa-modref -fdump-tree-optimized -fdump-tree-original" } +! +! PR fortran/41453 +! Check that the INTENT(OUT) attribute causes in the case of non-polymorphic derived type arguments: +! - one clobber to be emitted in the caller before calls to FOO in the *.original dump, +! - no clobber to be emitted in the caller before calls to BAR in the *.original dump, +! - the initialization constants to be optimized away in the *.optimized dump. + +module x + implicit none + type :: t + integer :: c + end type t + type, extends(t) :: u + integer :: d + end type u +contains + subroutine foo(a) + type(t), intent(out) :: a + a = t(42) + end subroutine foo + subroutine bar(b) + class(t), intent(out) :: b + b%c = 24 + end subroutine bar +end module x + +program main + use x + implicit none + type(t) :: tc + type(u) :: uc, ud + class(t), allocatable :: te, tf + + tc = t(123456789) + call foo(tc) + if (tc%c /= 42) stop 1 + + uc = u(987654321, 0) + call foo(uc%t) + if (uc%c /= 42) stop 2 + if (uc%d /= 0) stop 3 + + ud = u(11223344, 0) + call bar(ud) + if (ud%c /= 24) stop 4 + + te = t(55667788) + call foo(te) + if (te%c /= 42) stop 5 + + tf = t(99887766) + call bar(tf) + if (tf%c /= 24) stop 6 + +end program main + +! We don't support class descriptors, neither derived type components, so there is a clobber for tc only; +! no clobber for uc, ud, te, tf. +! { dg-final { scan-tree-dump-times "CLOBBER" 1 "original" } } +! { dg-final { scan-tree-dump "tc = {CLOBBER};" "original" } } + +! There is a clobber for tc, so we should manage to optimize away the associated initialization constant (but not other +! initialization constants). +! { dg-final { scan-tree-dump-not "123456789" "optimized" { target __OPTIMIZE__ } } } -- cgit v1.1 From de613c6295ea50d75167eaf89f41074a69298108 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Mon, 26 Sep 2022 00:18:09 +0000 Subject: Daily bump. --- gcc/ChangeLog | 4 +++ gcc/DATESTAMP | 2 +- gcc/fortran/ChangeLog | 66 +++++++++++++++++++++++++++++++++++++++++++++++++ gcc/testsuite/ChangeLog | 45 +++++++++++++++++++++++++++++++++ 4 files changed, 116 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1c8a0d9..6890dd1 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,7 @@ +2022-09-25 Torbjörn SVENSSON + + * doc/sourcebuild.texi: Fix chapter level. + 2022-09-24 Jakub Jelinek PR c/107001 diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 38f463d..7764f7e 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20220925 +20220926 diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 998fb1b..6985e62 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,69 @@ +2022-09-25 Mikael Morin + + PR fortran/41453 + * trans-expr.cc (gfc_conv_procedure_call): Allow strictly + matching derived types. + +2022-09-25 Mikael Morin + + PR fortran/41453 + PR fortran/99169 + * trans-expr.cc (gfc_conv_procedure_call): Remove conditions + on ALLOCATABLE and POINTER attributes guarding clobber + generation. + +2022-09-25 Mikael Morin + + PR fortran/41453 + PR fortran/87401 + * trans-expr.cc (gfc_conv_procedure_call): Remove condition + disabling clobber generation for ASSOCIATE variables. + +2022-09-25 Mikael Morin + + PR fortran/41453 + PR fortran/87395 + * trans-expr.cc (gfc_conv_procedure_call): Remove condition + on SAVE attribute guarding clobber generation. + +2022-09-25 Mikael Morin + + PR fortran/41453 + PR fortran/87395 + * trans-expr.cc (gfc_conv_procedure_call): Remove condition + disabling clobber generation for dummy variables. Remove + obsolete comment. + +2022-09-25 Harald Anlauf + Mikael Morin + + PR fortran/105012 + * trans-expr.cc (gfc_conv_procedure_call): Use dummy + information from associated_dummy if there is no information + from the procedure interface. + +2022-09-25 Mikael Morin + + PR fortran/106817 + * trans-expr.cc (gfc_conv_procedure_call): Collect all clobbers + to their own separate block. Append the block of clobbers to + the procedure preliminary block after the argument evaluation + codes for all the arguments. + +2022-09-25 Mikael Morin + + PR fortran/105012 + * trans-expr.cc (gfc_conv_procedure_call): Retrieve variable + from the just calculated variable reference. + +2022-09-25 Mikael Morin + + * trans.h (gfc_conv_expr_reference): Remove add_clobber + argument. + * trans-expr.cc (gfc_conv_expr_reference): Ditto. Inline code + depending on add_clobber and conditions controlling it ... + (gfc_conv_procedure_call): ... to here. + 2022-09-22 José Rui Faustino de Sousa PR fortran/100103 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index a5ff3de..0e7cd64e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,48 @@ +2022-09-25 Mikael Morin + + PR fortran/41453 + * gfortran.dg/intent_optimize_10.f90: New test. + +2022-09-25 Mikael Morin + + PR fortran/41453 + PR fortran/99169 + * gfortran.dg/intent_optimize_9.f90: New test. + +2022-09-25 Mikael Morin + + PR fortran/41453 + PR fortran/87401 + * gfortran.dg/intent_optimize_8.f90: New test. + +2022-09-25 Mikael Morin + + PR fortran/41453 + PR fortran/87395 + * gfortran.dg/intent_optimize_7.f90: New test. + +2022-09-25 Mikael Morin + + PR fortran/41453 + PR fortran/87395 + * gfortran.dg/intent_optimize_6.f90: New test. + +2022-09-25 Harald Anlauf + Mikael Morin + + PR fortran/105012 + * gfortran.dg/intent_optimize_5.f90: New test. + +2022-09-25 Mikael Morin + + PR fortran/106817 + * gfortran.dg/intent_optimize_4.f90: New test. + +2022-09-25 Mikael Morin + + PR fortran/105012 + * gfortran.dg/intent_out_15.f90: New test. + 2022-09-24 Jakub Jelinek PR c/107001 -- cgit v1.1 From 3db8e9c2422d924a958336fd0871b24cce3e65d1 Mon Sep 17 00:00:00 2001 From: liuhongt Date: Wed, 21 Sep 2022 14:56:08 +0800 Subject: Support 2-instruction vector shuffle for V4SI/V4SF in ix86_expand_vec_perm_const_1. 2022-09-23 Hongtao Liu Liwei Xu gcc/ChangeLog: 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. gcc/testsuite/ChangeLog: * 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. --- gcc/config/i386/i386-expand.cc | 116 ++++++++++++++++++++++++++++++ gcc/testsuite/gcc.target/i386/pr53346-1.c | 70 ++++++++++++++++++ gcc/testsuite/gcc.target/i386/pr53346-2.c | 59 +++++++++++++++ gcc/testsuite/gcc.target/i386/pr53346-3.c | 69 ++++++++++++++++++ gcc/testsuite/gcc.target/i386/pr53346-4.c | 59 +++++++++++++++ 5 files changed, 373 insertions(+) create mode 100644 gcc/testsuite/gcc.target/i386/pr53346-1.c create mode 100644 gcc/testsuite/gcc.target/i386/pr53346-2.c create mode 100644 gcc/testsuite/gcc.target/i386/pr53346-3.c create mode 100644 gcc/testsuite/gcc.target/i386/pr53346-4.c (limited to 'gcc') diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc index 5334363..6baff6d 100644 --- a/gcc/config/i386/i386-expand.cc +++ b/gcc/config/i386/i386-expand.cc @@ -19604,6 +19604,119 @@ expand_vec_perm_1 (struct expand_vec_perm_d *d) return false; } +/* A subroutine of ix86_expand_vec_perm_const_1. Try to implement D + in terms of a pair of shufps+ shufps/pshufd instructions. */ +static bool +expand_vec_perm_shufps_shufps (struct expand_vec_perm_d *d) +{ + unsigned char perm1[4]; + machine_mode vmode = d->vmode; + bool ok; + unsigned i, j, k, count = 0; + + if (d->one_operand_p + || (vmode != V4SImode && vmode != V4SFmode)) + return false; + + if (d->testing_p) + return true; + + for (i = 0; i < 4; ++i) + count += d->perm[i] > 3 ? 1 : 0; + + gcc_assert (count & 3); + + rtx tmp = gen_reg_rtx (vmode); + /* 2 from op0 and 2 from op1. */ + if (count == 2) + { + unsigned char perm2[4]; + for (i = 0, j = 0, k = 2; i < 4; ++i) + if (d->perm[i] & 4) + { + perm1[k++] = d->perm[i]; + perm2[i] = k - 1; + } + else + { + perm1[j++] = d->perm[i]; + perm2[i] = j - 1; + } + + /* shufps. */ + ok = expand_vselect_vconcat (tmp, d->op0, d->op1, + perm1, d->nelt, false); + gcc_assert (ok); + if (vmode == V4SImode && TARGET_SSE2) + /* pshufd. */ + ok = expand_vselect (d->target, tmp, + perm2, d->nelt, false); + else + { + /* shufps. */ + perm2[2] += 4; + perm2[3] += 4; + ok = expand_vselect_vconcat (d->target, tmp, tmp, + perm2, d->nelt, false); + } + gcc_assert (ok); + } + /* 3 from one op and 1 from another. */ + else + { + unsigned pair_idx = 8, lone_idx = 8, shift; + + /* Find the lone index. */ + for (i = 0; i < 4; ++i) + if ((d->perm[i] > 3 && count == 1) + || (d->perm[i] < 4 && count == 3)) + lone_idx = i; + + /* When lone_idx is not 0, it must from second op(count == 1). */ + gcc_assert (count == (lone_idx ? 1 : 3)); + + /* Find the pair index that sits in the same half as the lone index. */ + shift = lone_idx & 2; + pair_idx = 1 - lone_idx + 2 * shift; + + /* First permutate lone index and pair index into the same vector as + [ lone, lone, pair, pair ]. */ + perm1[1] = perm1[0] + = (count == 3) ? d->perm[lone_idx] : d->perm[lone_idx] - 4; + perm1[3] = perm1[2] + = (count == 3) ? d->perm[pair_idx] : d->perm[pair_idx] + 4; + + /* Alway put the vector contains lone indx at the first. */ + if (count == 1) + std::swap (d->op0, d->op1); + + /* shufps. */ + ok = expand_vselect_vconcat (tmp, d->op0, d->op1, + perm1, d->nelt, false); + gcc_assert (ok); + + /* Refine lone and pair index to original order. */ + perm1[shift] = lone_idx << 1; + perm1[shift + 1] = pair_idx << 1; + + /* Select the remaining 2 elements in another vector. */ + for (i = 2 - shift; i < 4 - shift; ++i) + perm1[i] = lone_idx == 1 ? d->perm[i] + 4 : d->perm[i]; + + /* Adjust to original selector. */ + if (lone_idx > 1) + std::swap (tmp, d->op1); + + /* shufps. */ + ok = expand_vselect_vconcat (d->target, tmp, d->op1, + perm1, d->nelt, false); + + gcc_assert (ok); + } + + return true; +} + /* A subroutine of ix86_expand_vec_perm_const_1. Try to implement D in terms of a pair of pshuflw + pshufhw instructions. */ @@ -22152,6 +22265,9 @@ ix86_expand_vec_perm_const_1 (struct expand_vec_perm_d *d) if (expand_vec_perm_2perm_pblendv (d, true)) return true; + if (expand_vec_perm_shufps_shufps (d)) + return true; + /* Try sequences of three instructions. */ if (expand_vec_perm_even_odd_pack (d)) diff --git a/gcc/testsuite/gcc.target/i386/pr53346-1.c b/gcc/testsuite/gcc.target/i386/pr53346-1.c new file mode 100644 index 0000000..6d230da --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr53346-1.c @@ -0,0 +1,70 @@ +/* { dg-do compile } */ +/* { dg-options "-msse2 -O2 -mno-sse3" } */ +/* { dg-final { scan-assembler-times "shufps" 15 } } */ +/* { dg-final { scan-assembler-times "pshufd" 2 } } */ + +typedef int v4si __attribute__((vector_size(16))); + +v4si +__attribute__((noipa)) +foo (v4si a, v4si b) +{ + return __builtin_shufflevector (a, b, 1, 2, 5, 3); +} + +v4si +__attribute__((noipa)) +foo1 (v4si a, v4si b) +{ + return __builtin_shufflevector (a, b, 1, 5, 2, 3); +} + +v4si +__attribute__((noipa)) +foo2 (v4si a, v4si b) +{ + return __builtin_shufflevector (a, b, 1, 2, 3, 5); +} + +v4si +__attribute__((noipa)) +foo3 (v4si a, v4si b) +{ + return __builtin_shufflevector (a, b, 1, 4, 5, 6); +} + +v4si +__attribute__((noipa)) +foo4 (v4si a, v4si b) +{ + return __builtin_shufflevector (a, b, 3, 6, 7, 5); +} + +v4si +__attribute__((noipa)) +foo5 (v4si a, v4si b) +{ + return __builtin_shufflevector (a, b, 2, 4, 7, 6); +} + +v4si +__attribute__((noipa)) +foo6 (v4si a, v4si b) +{ + return __builtin_shufflevector (a, b, 2, 4, 3, 6); +} + +v4si +__attribute__((noipa)) +foo7 (v4si a, v4si b) +{ + return __builtin_shufflevector (a, b, 2, 3, 4, 6); +} + +v4si +__attribute__((noipa)) +foo8 (v4si a, v4si b) +{ + return __builtin_shufflevector (a, b, 2, 4, 6, 3); +} + diff --git a/gcc/testsuite/gcc.target/i386/pr53346-2.c b/gcc/testsuite/gcc.target/i386/pr53346-2.c new file mode 100644 index 0000000..0c6c7b3 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr53346-2.c @@ -0,0 +1,59 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -msse2" } */ +/* { dg-require-effective-target sse2 } */ + +#include "sse2-check.h" +#include "pr53346-1.c" + +static void +sse2_test () +{ + v4si a = __extension__(v4si) { 0, 1, 2, 3 }; + v4si b = __extension__(v4si) { 4, 5, 6, 7 }; + v4si exp = __extension__(v4si) { 1, 2, 5, 3 }; + v4si dest; + dest = foo (a, b); + if (__builtin_memcmp (&dest, &exp, 16)) + __builtin_abort (); + + exp = __extension__ (v4si) { 1, 5, 2, 3 }; + dest = foo1 (a, b); + if (__builtin_memcmp (&dest, &exp, 16)) + __builtin_abort (); + + exp = __extension__ (v4si) { 1, 2, 3, 5 }; + dest = foo2 (a, b); + if (__builtin_memcmp (&dest, &exp, 16)) + __builtin_abort (); + + exp = __extension__ (v4si) { 1, 4, 5, 6 }; + dest = foo3 (a, b); + if (__builtin_memcmp (&dest, &exp, 16)) + __builtin_abort (); + + exp = __extension__ (v4si) { 3, 6, 7, 5 }; + dest = foo4 (a, b); + if (__builtin_memcmp (&dest, &exp, 16)) + __builtin_abort (); + + exp = __extension__ (v4si) { 2, 4, 7, 6 }; + dest = foo5 (a, b); + if (__builtin_memcmp (&dest, &exp, 16)) + __builtin_abort (); + + exp = __extension__ (v4si) { 2, 4, 3, 6 }; + dest = foo6 (a, b); + if (__builtin_memcmp (&dest, &exp, 16)) + __builtin_abort (); + + exp = __extension__ (v4si) { 2, 3, 4, 6 }; + dest = foo7 (a, b); + if (__builtin_memcmp (&dest, &exp, 16)) + __builtin_abort (); + + exp = __extension__ (v4si) { 2, 4, 6, 3 }; + dest = foo8 (a, b); + if (__builtin_memcmp (&dest, &exp, 16)) + __builtin_abort (); + +} diff --git a/gcc/testsuite/gcc.target/i386/pr53346-3.c b/gcc/testsuite/gcc.target/i386/pr53346-3.c new file mode 100644 index 0000000..0b204f6 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr53346-3.c @@ -0,0 +1,69 @@ +/* { dg-do compile } */ +/* { dg-options "-msse2 -O2 -mno-sse3" } */ +/* { dg-final { scan-assembler-times "shufps" 17 } } */ + +typedef float v4sf __attribute__((vector_size(16))); + +v4sf +__attribute__((noipa)) +foo (v4sf a, v4sf b) +{ + return __builtin_shufflevector (a, b, 1, 2, 5, 3); +} + +v4sf +__attribute__((noipa)) +foo1 (v4sf a, v4sf b) +{ + return __builtin_shufflevector (a, b, 1, 5, 2, 3); +} + +v4sf +__attribute__((noipa)) +foo2 (v4sf a, v4sf b) +{ + return __builtin_shufflevector (a, b, 1, 2, 3, 5); +} + +v4sf +__attribute__((noipa)) +foo3 (v4sf a, v4sf b) +{ + return __builtin_shufflevector (a, b, 1, 4, 5, 6); +} + +v4sf +__attribute__((noipa)) +foo4 (v4sf a, v4sf b) +{ + return __builtin_shufflevector (a, b, 3, 6, 7, 5); +} + +v4sf +__attribute__((noipa)) +foo5 (v4sf a, v4sf b) +{ + return __builtin_shufflevector (a, b, 2, 4, 7, 6); +} + +v4sf +__attribute__((noipa)) +foo6 (v4sf a, v4sf b) +{ + return __builtin_shufflevector (a, b, 2, 4, 3, 6); +} + +v4sf +__attribute__((noipa)) +foo7 (v4sf a, v4sf b) +{ + return __builtin_shufflevector (a, b, 2, 3, 4, 6); +} + +v4sf +__attribute__((noipa)) +foo8 (v4sf a, v4sf b) +{ + return __builtin_shufflevector (a, b, 2, 4, 6, 3); +} + diff --git a/gcc/testsuite/gcc.target/i386/pr53346-4.c b/gcc/testsuite/gcc.target/i386/pr53346-4.c new file mode 100644 index 0000000..9e4e45b --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr53346-4.c @@ -0,0 +1,59 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -msse2" } */ +/* { dg-require-effective-target sse2 } */ + +#include "sse2-check.h" +#include "pr53346-3.c" + +static void +sse2_test () +{ + v4sf a = __extension__(v4sf) { 0, 1, 2, 3 }; + v4sf b = __extension__(v4sf) { 4, 5, 6, 7 }; + v4sf exp = __extension__(v4sf) { 1, 2, 5, 3 }; + v4sf dest; + dest = foo (a, b); + if (__builtin_memcmp (&dest, &exp, 16)) + __builtin_abort (); + + exp = __extension__ (v4sf) { 1, 5, 2, 3 }; + dest = foo1 (a, b); + if (__builtin_memcmp (&dest, &exp, 16)) + __builtin_abort (); + + exp = __extension__ (v4sf) { 1, 2, 3, 5 }; + dest = foo2 (a, b); + if (__builtin_memcmp (&dest, &exp, 16)) + __builtin_abort (); + + exp = __extension__ (v4sf) { 1, 4, 5, 6 }; + dest = foo3 (a, b); + if (__builtin_memcmp (&dest, &exp, 16)) + __builtin_abort (); + + exp = __extension__ (v4sf) { 3, 6, 7, 5 }; + dest = foo4 (a, b); + if (__builtin_memcmp (&dest, &exp, 16)) + __builtin_abort (); + + exp = __extension__ (v4sf) { 2, 4, 7, 6 }; + dest = foo5 (a, b); + if (__builtin_memcmp (&dest, &exp, 16)) + __builtin_abort (); + + exp = __extension__ (v4sf) { 2, 4, 3, 6 }; + dest = foo6 (a, b); + if (__builtin_memcmp (&dest, &exp, 16)) + __builtin_abort (); + + exp = __extension__ (v4sf) { 2, 3, 4, 6 }; + dest = foo7 (a, b); + if (__builtin_memcmp (&dest, &exp, 16)) + __builtin_abort (); + + exp = __extension__ (v4sf) { 2, 4, 6, 3 }; + dest = foo8 (a, b); + if (__builtin_memcmp (&dest, &exp, 16)) + __builtin_abort (); + +} -- cgit v1.1 From bfad7069b74c97000b698191c1945f07a6192db5 Mon Sep 17 00:00:00 2001 From: Kewen Lin Date: Sun, 25 Sep 2022 22:01:50 -0500 Subject: rs6000: Fix condition of define_expand vec_shr_ [PR100645] PR100645 exposes one latent bug in define_expand vec_shr_ that the current condition TARGET_ALTIVEC is too loose. The mode iterator VEC_L contains a few modes, they are not always supported as vector mode, VECTOR_UNIT_ALTIVEC_OR_VSX_P should be used like some other VEC_L usages. PR target/100645 gcc/ChangeLog: * config/rs6000/vector.md (vec_shr_): Replace condition TARGET_ALTIVEC with VECTOR_UNIT_ALTIVEC_OR_VSX_P. gcc/testsuite/ChangeLog: * gcc.target/powerpc/pr100645.c: New test. --- gcc/config/rs6000/vector.md | 2 +- gcc/testsuite/gcc.target/powerpc/pr100645.c | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.target/powerpc/pr100645.c (limited to 'gcc') diff --git a/gcc/config/rs6000/vector.md b/gcc/config/rs6000/vector.md index a0d33d2..0171705 100644 --- a/gcc/config/rs6000/vector.md +++ b/gcc/config/rs6000/vector.md @@ -1475,7 +1475,7 @@ [(match_operand:VEC_L 0 "vlogical_operand") (match_operand:VEC_L 1 "vlogical_operand") (match_operand:QI 2 "reg_or_short_operand")] - "TARGET_ALTIVEC" + "VECTOR_UNIT_ALTIVEC_OR_VSX_P (mode)" { rtx bitshift = operands[2]; rtx shift; diff --git a/gcc/testsuite/gcc.target/powerpc/pr100645.c b/gcc/testsuite/gcc.target/powerpc/pr100645.c new file mode 100644 index 0000000..c4e92cc --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/pr100645.c @@ -0,0 +1,13 @@ +/* { dg-require-effective-target powerpc_altivec_ok } */ +/* { dg-options "-mdejagnu-cpu=power6 -maltivec" } */ + +/* This used to ICE. */ + +typedef long long v2di __attribute__ ((vector_size (16))); + +v2di +foo_v2di_l (v2di x) +{ + return __builtin_shuffle ((v2di){0, 0}, x, (v2di){3, 0}); +} + -- cgit v1.1 From 9c9cf4f087f28dc3bf8dfa769380b3b58728a0f7 Mon Sep 17 00:00:00 2001 From: "Hu, Lin1" Date: Mon, 26 Sep 2022 10:15:08 +0800 Subject: testsuite: Fix up avx256-unaligned-store-3.c test. gcc/testsuite/ChangeLog: PR target/94962 * gcc.target/i386/avx256-unaligned-store-3.c: Add -mno-avx512f --- gcc/testsuite/gcc.target/i386/avx256-unaligned-store-3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.target/i386/avx256-unaligned-store-3.c b/gcc/testsuite/gcc.target/i386/avx256-unaligned-store-3.c index f909099..67635fb 100644 --- a/gcc/testsuite/gcc.target/i386/avx256-unaligned-store-3.c +++ b/gcc/testsuite/gcc.target/i386/avx256-unaligned-store-3.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O3 -dp -mavx -mavx256-split-unaligned-store -mtune=generic -fno-common" } */ +/* { dg-options "-O3 -dp -mavx -mavx256-split-unaligned-store -mtune=generic -fno-common -mno-avx512f" } */ #define N 1024 -- cgit v1.1 From 5be0950d22209f5ba69d244387228e12389a8470 Mon Sep 17 00:00:00 2001 From: Kewen Lin Date: Mon, 26 Sep 2022 00:33:18 -0500 Subject: rs6000: Fix the condition with frame_pointer_needed_indeed [PR96072] As PR96072 shows, the code adding REG_CFA_DEF_CFA reg note makes one assumption that we have emitted one insn which restores the frame pointer previously. That part of code was guarded with flag frame_pointer_needed before, it was consistent, but it was replaced with flag frame_pointer_needed_indeed since commit r10-7981. It caused ICE due to unexpected NULL insn. PR target/96072 gcc/ChangeLog: * config/rs6000/rs6000-logue.cc (rs6000_emit_epilogue): Update the condition for adding REG_CFA_DEF_CFA reg note with frame_pointer_needed_indeed. gcc/testsuite/ChangeLog: * gcc.target/powerpc/pr96072.c: New test. --- gcc/config/rs6000/rs6000-logue.cc | 2 +- gcc/testsuite/gcc.target/powerpc/pr96072.c | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.target/powerpc/pr96072.c (limited to 'gcc') diff --git a/gcc/config/rs6000/rs6000-logue.cc b/gcc/config/rs6000/rs6000-logue.cc index ddd849e..a11d020 100644 --- a/gcc/config/rs6000/rs6000-logue.cc +++ b/gcc/config/rs6000/rs6000-logue.cc @@ -4920,7 +4920,7 @@ rs6000_emit_epilogue (enum epilogue_type epilogue_type) a REG_CFA_DEF_CFA note, but that's OK; A duplicate is discarded by dwarf2cfi.cc/dwarf2out.cc, and in any case would be harmless if emitted. */ - if (frame_pointer_needed) + if (frame_pointer_needed_indeed) { insn = get_last_insn (); add_reg_note (insn, REG_CFA_DEF_CFA, diff --git a/gcc/testsuite/gcc.target/powerpc/pr96072.c b/gcc/testsuite/gcc.target/powerpc/pr96072.c new file mode 100644 index 0000000..10341c9 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/pr96072.c @@ -0,0 +1,14 @@ +/* { dg-options "-O2" } */ + +/* This used to ICE with the SYSV ABI (PR96072). */ + +void +he (int jn) +{ + { + int bh[jn]; + if (jn != 0) + goto wa; + } +wa:; +} -- cgit v1.1 From 7ed1a816bab15098e959c249bd0aef8452913223 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Mon, 26 Sep 2022 09:30:44 +0200 Subject: ranger: remove unused function gcc/ChangeLog: * value-range.cc (tree_compare): Remove unused function. --- gcc/value-range.cc | 9 --------- 1 file changed, 9 deletions(-) (limited to 'gcc') diff --git a/gcc/value-range.cc b/gcc/value-range.cc index 9ca4424..754379a 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -258,15 +258,6 @@ frange::accept (const vrange_visitor &v) const v.visit (*this); } -// Helper function to compare floats. Returns TRUE if op1 .CODE. op2 -// is nonzero. - -static inline bool -tree_compare (tree_code code, tree op1, tree op2) -{ - return !integer_zerop (fold_build2 (code, integer_type_node, op1, op2)); -} - // Flush denormal endpoints to the appropriate 0.0. void -- cgit v1.1 From 6c37375640f429f68d397be67321c41b8e03fa41 Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Mon, 26 Sep 2022 10:41:21 +0200 Subject: Small tweaks. --- gcc/ada/ChangeLog | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index fe048b8..c48bbdf 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -66,7 +66,7 @@ 2022-09-12 Eric Botcazou - * contracts.adb (uild_Subprogram_Contract_Wrapper): Remove useless + * contracts.adb (Build_Subprogram_Contract_Wrapper): Remove useless local variable. In the case of a function, replace the extended return statement by a block statement declaring a renaming of the call to the local subprogram after removing side effects manually. @@ -1179,14 +1179,14 @@ 2022-09-02 Eric Botcazou - * exp_util.adb (Expand_Subtype_From_Expr): Be prepared for - rewritten aggregates as expressions. + * exp_util.adb (Expand_Subtype_From_Expr): Be prepared for rewritten + aggregates as expressions. 2022-09-02 Gary Dismukes - * exp_ch6.adb (Expand_Simple_Function_Return) Bypass creation of an actual - subtype and unchecked conversion to that subtype when the underlying type - of the expression has discriminants without defaults. + * exp_ch6.adb (Expand_Simple_Function_Return) Bypass creation of an + actual subtype and unchecked conversion to that subtype when the + underlying type of the expression has discriminants without defaults. 2022-09-02 Eric Botcazou -- cgit v1.1 From fb95fb2125230fb594d88a7d73b524853c6604c5 Mon Sep 17 00:00:00 2001 From: Piotr Trojanek Date: Wed, 7 Sep 2022 19:11:06 +0200 Subject: ada: Tune comment of routine for detecting junk names Reword comment to avoid repetition between spec and body. gcc/ada/ * sem_warn.ads (Has_Junk_Name): Reword comment. --- gcc/ada/sem_warn.ads | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/sem_warn.ads b/gcc/ada/sem_warn.ads index 1894f36..6681e54 100644 --- a/gcc/ada/sem_warn.ads +++ b/gcc/ada/sem_warn.ads @@ -257,12 +257,9 @@ package Sem_Warn is ---------------------- function Has_Junk_Name (E : Entity_Id) return Boolean; - -- Return True if the entity name contains any of the following substrings: - -- discard - -- dummy - -- ignore - -- junk - -- unused + -- Return True if the entity name contains substrings like "junk" or + -- "dummy" (see the body for the complete list). + -- -- Used to suppress warnings on names matching these patterns. The contents -- of Name_Buffer and Name_Len are destroyed by this call. -- cgit v1.1 From 09b91bbcddd4900d433ea72f08dd11719bceaa58 Mon Sep 17 00:00:00 2001 From: Piotr Trojanek Date: Mon, 5 Sep 2022 11:40:50 +0200 Subject: ada: Deconstruct build support for ancient MinGW Remove conditional C code for building GNAT with MinGW earlier than 2.0, which was released in 2007. gcc/ada/ * 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. --- gcc/ada/adaint.c | 13 ++----------- gcc/ada/cal.c | 2 -- gcc/ada/cstreams.c | 8 -------- gcc/ada/expect.c | 8 ++------ gcc/ada/mingw32.h | 17 ----------------- gcc/ada/sysdep.c | 6 +----- 6 files changed, 5 insertions(+), 49 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/adaint.c b/gcc/ada/adaint.c index 2ae4ded..199dbe0 100644 --- a/gcc/ada/adaint.c +++ b/gcc/ada/adaint.c @@ -200,11 +200,7 @@ UINT __gnat_current_ccs_encoding; #endif /* wait.h processing */ -#ifdef __MINGW32__ -# if OLD_MINGW -# include -# endif -#elif defined (__vxworks) && defined (__RTP__) +#if defined (__vxworks) && defined (__RTP__) # include #elif defined (__Lynx__) /* ??? We really need wait.h and it includes resource.h on Lynx. GCC @@ -214,7 +210,7 @@ UINT __gnat_current_ccs_encoding; preventing the inclusion of the GCC header from doing anything. */ # define GCC_RESOURCE_H # include -#elif defined (__PikeOS__) +#elif defined (__PikeOS__) || defined (__MINGW32__) /* No wait() or waitpid() calls available. */ #else /* Default case. */ @@ -335,11 +331,6 @@ const char *__gnat_library_template = GNAT_LIBRARY_TEMPLATE; #if defined (__MINGW32__) #include "mingw32.h" - -#if OLD_MINGW -#include -#endif - #else #include #endif diff --git a/gcc/ada/cal.c b/gcc/ada/cal.c index e1ab692..09bcc15 100644 --- a/gcc/ada/cal.c +++ b/gcc/ada/cal.c @@ -53,10 +53,8 @@ #ifdef __MINGW32__ #include "mingw32.h" -#if STD_MINGW #include #endif -#endif void __gnat_timeval_to_duration (struct timeval *t, long long *sec, long *usec) diff --git a/gcc/ada/cstreams.c b/gcc/ada/cstreams.c index 10cc3a6..fc583e1 100644 --- a/gcc/ada/cstreams.c +++ b/gcc/ada/cstreams.c @@ -97,14 +97,6 @@ extern "C" { #undef fileno #endif -/* The _IONBF value in MINGW32 stdio.h is wrong. */ -#if defined (WINNT) || defined (_WINNT) -#if OLD_MINGW -#undef _IONBF -#define _IONBF 0004 -#endif -#endif - int __gnat_feof (FILE *stream) { diff --git a/gcc/ada/expect.c b/gcc/ada/expect.c index b1889fe..48fb107 100644 --- a/gcc/ada/expect.c +++ b/gcc/ada/expect.c @@ -42,17 +42,13 @@ #include "adaint.h" #include -#ifdef __MINGW32__ -# if OLD_MINGW -# include -# endif -#elif defined (__vxworks) && defined (__RTP__) +#if defined (__vxworks) && defined (__RTP__) # include #elif defined (__Lynx__) /* ??? See comment in adaint.c. */ # define GCC_RESOURCE_H # include -#elif defined (__PikeOS__) +#elif defined (__PikeOS__) || defined (__MINGW32__) /* No wait.h available */ #else #include diff --git a/gcc/ada/mingw32.h b/gcc/ada/mingw32.h index 1157fc6..bf8577b 100644 --- a/gcc/ada/mingw32.h +++ b/gcc/ada/mingw32.h @@ -101,23 +101,6 @@ extern UINT __gnat_current_ccs_encoding; #include -/* STD_MINGW: standard if MINGW32 version > 1.3, we have switched to this - version instead of the previous enhanced version to ease building GNAT on - Windows platforms. By using STD_MINGW or OLD_MINGW it is possible to build - GNAT using both MingW include files (Old MingW + ACT changes and standard - MingW starting with version 1.3. - For w64 Mingw the define STD_MINGW is always set to value 1, because - there is no old header set present. */ -#ifdef _WIN64 -#define STD_MINGW 1 -#else -#define STD_MINGW ((__MINGW32_MAJOR_VERSION == 1 \ - && __MINGW32_MINOR_VERSION >= 3) \ - || (__MINGW32_MAJOR_VERSION >= 2)) -#endif - -#define OLD_MINGW (!(STD_MINGW)) - #ifndef MAXPATHLEN #define MAXPATHLEN MAX_PATH #endif diff --git a/gcc/ada/sysdep.c b/gcc/ada/sysdep.c index 5e9cf70..7bdfcbc 100644 --- a/gcc/ada/sysdep.c +++ b/gcc/ada/sysdep.c @@ -323,11 +323,7 @@ __gnat_ttyname (int filedes ATTRIBUTE_UNUSED) || defined (__QNX__) # ifdef __MINGW32__ -# if OLD_MINGW -# include -# else -# include /* for getch(), kbhit() */ -# endif +# include /* for getch(), kbhit() */ # else # include # endif -- cgit v1.1 From af61dc3ffd7c184571bcf1d773d97716cfe6093a Mon Sep 17 00:00:00 2001 From: Piotr Trojanek Date: Mon, 5 Sep 2022 13:17:15 +0200 Subject: ada: Remove definition of MAXPATHLEN for ancient MinGW Modern MinGW defines MAXPATHLEN in sys/param.h, so better to use it directly. gcc/ada/ * mingw32.h: Remove condition definition of MAXPATHLEN; the include directive for stdlib.h was most likely intended to provide the MAX_PATH. --- gcc/ada/mingw32.h | 6 ------ 1 file changed, 6 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/mingw32.h b/gcc/ada/mingw32.h index bf8577b..a190d51 100644 --- a/gcc/ada/mingw32.h +++ b/gcc/ada/mingw32.h @@ -99,10 +99,4 @@ extern UINT __gnat_current_ccs_encoding; #define WS2S(str,wstr,len) strncpy(str,wstr,len) #endif -#include - -#ifndef MAXPATHLEN -#define MAXPATHLEN MAX_PATH -#endif - #endif /* _MINGW32_H */ -- cgit v1.1 From 092d7509db47376a7b910f7af05678058bd9bd3c Mon Sep 17 00:00:00 2001 From: Piotr Trojanek Date: Mon, 5 Sep 2022 13:29:38 +0200 Subject: ada: Remove socket definitions for ancient MinGW Modern MinGW defines _WIN32_WINNT as 0xa00, so there is no need go guard against it being lower than 0x0600 or setting it to 0x0501. gcc/ada/ * gsocket.h: Remove redefinition of _WIN32_WINNT. * mingw32.h: Remove conditional definition of _WIN32_WINNT. --- gcc/ada/gsocket.h | 6 ------ gcc/ada/mingw32.h | 5 ----- 2 files changed, 11 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/gsocket.h b/gcc/ada/gsocket.h index e7284a1..561f2ff 100644 --- a/gcc/ada/gsocket.h +++ b/gcc/ada/gsocket.h @@ -80,12 +80,6 @@ #define FD_SETSIZE 1024 #ifdef __MINGW32__ -/* winsock2.h allows WSAPoll related definitions only when - * _WIN32_WINNT >= 0x0600 */ -#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600 -#define _WIN32_WINNT 0x0600 -#endif - #include #include #include diff --git a/gcc/ada/mingw32.h b/gcc/ada/mingw32.h index a190d51..d038211 100644 --- a/gcc/ada/mingw32.h +++ b/gcc/ada/mingw32.h @@ -44,11 +44,6 @@ #define UNICODE /* For Win32 API */ #endif -/* We need functionality available only starting with Windows XP */ -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0501 -#endif - #ifndef __CYGWIN__ #include #endif -- cgit v1.1 From 9677984d7b230f4fbf22e5cd1f14ca4c976ab1ec Mon Sep 17 00:00:00 2001 From: Boris Yakobowski Date: Wed, 7 Sep 2022 19:37:03 +0200 Subject: ada: Remove GNATmetric's documentation from GNAT's documentation gcc/ada/ * doc/gnat_ugn/gnat_utility_programs.rst: Remove documentation for gnatmetric. --- gcc/ada/doc/gnat_ugn/gnat_utility_programs.rst | 1120 +----------------------- 1 file changed, 1 insertion(+), 1119 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/doc/gnat_ugn/gnat_utility_programs.rst b/gcc/ada/doc/gnat_ugn/gnat_utility_programs.rst index d670839..92877a2 100644 --- a/gcc/ada/doc/gnat_ugn/gnat_utility_programs.rst +++ b/gcc/ada/doc/gnat_ugn/gnat_utility_programs.rst @@ -15,7 +15,6 @@ This chapter describes a number of utility programs: * :ref:`The_File_Cleanup_Utility_gnatclean` * :ref:`The_GNAT_Library_Browser_gnatls` * :ref:`The_Coding_Standard_Verifier_gnatcheck` - * :ref:`The_GNAT_Metrics_Tool_gnatmetric` * :ref:`The_GNAT_Pretty_Printer_gnatpp` * :ref:`The_Body_Stub_Generator_gnatstub` * :ref:`The_Backtrace_Symbolizer_gnatsymbolize` @@ -487,1123 +486,6 @@ building specialized scripts. For full details, plese refer to :title:`GNATcheck Reference Manual`. - -.. only:: PRO or GPL - - .. _The_GNAT_Metrics_Tool_gnatmetric: - - The GNAT Metrics Tool ``gnatmetric`` - ==================================== - - .. index:: ! gnatmetric - .. index:: Metric tool - - The ``gnatmetric`` tool is a utility - for computing various program metrics. - It takes an Ada source file as input and generates a file containing the - metrics data as output. Various switches control which - metrics are reported. - - ``gnatmetric`` is a project-aware tool - (see :ref:`Using_Project_Files_with_GNAT_Tools` for a description of - the project-related switches). The project file package that can specify - ``gnatmetric`` switches is named ``Metrics``. - - The ``gnatmetric`` command has the form - - :: - - $ gnatmetric [ switches ] { filename } - - where: - - * ``switches`` specify the metrics to compute and define the destination for - the output - - * Each ``filename`` is the name of a source file to process. 'Wildcards' are - allowed, and the file name may contain path information. If no - ``filename`` is supplied, then the ``switches`` list must contain at least - one :switch:`--files` switch (see :ref:`Other_gnatmetric_Switches`). - Including both a :switch:`--files` switch and one or more ``filename`` - arguments is permitted. - - Note that it is no longer necessary to specify the Ada language version; - ``gnatmetric`` can process Ada source code written in any version from - Ada 83 onward without specifying any language version switch. - - The following subsections describe the various switches accepted by - ``gnatmetric``, organized by category. - - .. _Output_File_Control-gnatmetric: - - Output File Control - ------------------- - - .. index:: Output file control in gnatmetric - - ``gnatmetric`` has two output formats. It can generate a - textual (human-readable) form, and also XML. By default only textual - output is generated. - - When generating the output in textual form, ``gnatmetric`` creates - for each Ada source file a corresponding text file - containing the computed metrics, except for the case when the set of metrics - specified by gnatmetric parameters consists only of metrics that are computed - for the whole set of analyzed sources, but not for each Ada source. - By default, the name of the file containing metric information for a source - is obtained by appending the :file:`.metrix` suffix to the - name of the input source file. If not otherwise specified and no project file - is specified as ``gnatmetric`` option this file is placed in the same - directory as where the source file is located. If ``gnatmetric`` has a - project file as its parameter, it places all the generated files in the - object directory of the project (or in the project source directory if the - project does not define an object directory). If :switch:`--subdirs` option - is specified, the files are placed in the subrirectory of this directory - specified by this option. - - All the output information generated in XML format is placed in a single - file. By default the name of this file is :file:`metrix.xml`. - If not otherwise specified and if no project file is specified - as ``gnatmetric`` option this file is placed in the - current directory. - - Some of the computed metrics are summed over the units passed to - ``gnatmetric``; for example, the total number of lines of code. - By default this information is sent to :file:`stdout`, but a file - can be specified with the :switch:`--global-file-name` switch. - - The following switches control the ``gnatmetric`` output: - - .. index:: --generate-xml-output (gnatmetric) - - :switch:`--generate-xml-output` - Generate XML output. - - .. index:: --generate-xml-schema (gnatmetric) - - :switch:`--generate-xml-schema` - Generate XML output and an XML schema file that describes the structure - of the XML metric report. This schema is assigned to the XML file. The schema - file has the same name as the XML output file with :file:`.xml` suffix replaced - with :file:`.xsd`. - - .. index:: --no-text-output (gnatmetric) - - - :switch:`--no-text-output` - Do not generate the output in text form (implies :switch:`-x`). - - .. index:: --output-dir (gnatmetric) - - - :switch:`--output-dir={output_dir}` - Put text files with detailed metrics into ``output_dir``. - - .. index:: --output-suffix (gnatmetric) - - - :switch:`--output-suffix={file_suffix}` - Use ``file_suffix``, instead of :file:`.metrix` - in the name of the output file. - - .. index:: --global-file-name (gnatmetric) - - :switch:`--global-file-name={file_name}` - Put global metrics into ``file_name``. - - .. index:: --xml-file-name (gnatmetric) - - - :switch:`--xml-file-name={file_name}` - Put the XML output into ``file_name`` - (also implies :switch:`--generate-xml-output`). - - .. index:: --short-file-names (gnatmetric) - - :switch:`--short-file-names` - Use 'short' source file names in the output. (The ``gnatmetric`` - output includes the name(s) of the Ada source file(s) from which the - metrics are computed. By default each name includes the absolute - path. The :switch:`--short-file-names` switch causes ``gnatmetric`` - to exclude all directory information from the file names that are - output.) - - .. index:: --wide-character-encoding (gnatmetric) - - :switch:`--wide-character-encoding={e}` - Specify the wide character encoding method for the input and output - files. ``e`` is one of the following: - - * *8* - UTF-8 encoding - - * *b* - Brackets encoding (default value) - - - .. index:: Disable Metrics For Local Units in gnatmetric - - .. _Disable_Metrics_For_Local_Units: - - Disable Metrics For Local Units - ------------------------------- - - ``gnatmetric`` relies on the GNAT compilation model -- - one compilation - unit per one source file. It computes line metrics for the whole source - file, and it also computes syntax - and complexity metrics for the file's outermost unit. - - By default, ``gnatmetric`` will also compute all metrics for certain - kinds of locally declared program units: - - * subprogram (and generic subprogram) bodies; - - * package (and generic package) specs and bodies; - - * task object and type specifications and bodies; - - * protected object and type specifications and bodies. - - .. index:: Eligible local unit (for gnatmetric) - - These kinds of entities will be referred to as - *eligible local program units*, or simply *eligible local units*, - in the discussion below. - - Note that a subprogram declaration, generic instantiation, - or renaming declaration only receives metrics - computation when it appear as the outermost entity - in a source file. - - Suppression of metrics computation for eligible local units can be - obtained via the following switch: - - - .. index:: --no-local-metrics (gnatmetric) - - - :switch:`--no-local-metrics` - Do not compute detailed metrics for eligible local program units. - - - .. _Specifying_a_set_of_metrics_to_compute: - - Specifying a set of metrics to compute - -------------------------------------- - - By default all the metrics are reported. The switches described in this - subsection allow you to control, on an individual basis, whether metrics are - reported. If at least one positive metric switch is specified (that is, a - switch that defines that a given metric or set of metrics is to be computed), - then only explicitly specified metrics are reported. - - .. _Line_Metrics_Control: - - Line Metrics Control - ^^^^^^^^^^^^^^^^^^^^ - - .. index:: Line metrics control in gnatmetric - - For each source file, and for each of its eligible local program - units, ``gnatmetric`` computes the following metrics: - - * the total number of lines; - - * the total number of code lines (i.e., non-blank lines that are not - comments) - - * the number of comment lines - - * the number of code lines containing end-of-line comments; - - * the comment percentage: the ratio between the number of lines that - contain comments and the number of all non-blank lines, expressed as - a percentage - - * the number of empty lines and lines containing only space characters - and/or format effectors (blank lines) - - * the average number of code lines in subprogram bodies, task bodies, - entry bodies and statement sequences in package bodies - - ``gnatmetric`` sums the values of the line metrics for all the files - being processed and then generates the cumulative results. The tool - also computes for all the files being processed the average number of - code lines in bodies. - - You can use the following switches to select the specific line metrics - to be reported. - - - .. index:: --lines (gnatmetric) - .. index:: --no-lines (gnatmetric) - - - :switch:`--lines-all` - Report all the line metrics - - - :switch:`--no-lines-all` - Do not report any of line metrics - - - :switch:`--lines` - Report the number of all lines - - - :switch:`--no-lines` - Do not report the number of all lines - - - :switch:`--lines-code` - Report the number of code lines - - - :switch:`--no-lines-code` - Do not report the number of code lines - - - :switch:`--lines-comment` - Report the number of comment lines - - - :switch:`--no-lines-comment` - Do not report the number of comment lines - - - :switch:`--lines-eol-comment` - Report the number of code lines containing - end-of-line comments - - - :switch:`--no-lines-eol-comment` - Do not report the number of code lines containing - end-of-line comments - - - :switch:`--lines-ratio` - Report the comment percentage in the program text - - - :switch:`--no-lines-ratio` - Do not report the comment percentage in the program text - - - :switch:`--lines-blank` - Report the number of blank lines - - - :switch:`--no-lines-blank` - Do not report the number of blank lines - - - :switch:`--lines-average` - Report the average number of code lines in subprogram bodies, task bodies, - entry bodies and statement sequences in package bodies. - - - :switch:`--no-lines-average` - Do not report the average number of code lines in subprogram bodies, - task bodies, entry bodies and statement sequences in package bodies. - - - :switch:`--lines-spark` - Report the number of lines written in SPARK. - - - :switch:`--no-lines-spark` - Do not report the number of lines written in SPARK. - - - .. _Syntax_Metrics_Control: - - Syntax Metrics Control - ^^^^^^^^^^^^^^^^^^^^^^ - - .. index:: Syntax metrics control in gnatmetric - - ``gnatmetric`` computes various syntactic metrics for the - outermost unit and for each eligible local unit: - - * *LSLOC ('Logical Source Lines Of Code')* - The total number of declarations and the total number of - statements. Note that the definition of declarations is the one - given in the reference manual: - - "Each of the following is defined to be a declaration: any - basic_declaration; an enumeration_literal_specification; a - discriminant_specification; a component_declaration; a - loop_parameter_specification; a parameter_specification; a - subprogram_body; an entry_declaration; an - entry_index_specification; a choice_parameter_specification; a - generic_formal_parameter_declaration." - - This means for example that each enumeration literal adds one to - the count, as well as each subprogram parameter. - - * *Maximal static nesting level of inner program units* - According to :title:`Ada Reference Manual`, 10.1(1): - - "A program unit is either a package, a task unit, a protected - unit, a protected entry, a generic unit, or an explicitly - declared subprogram other than an enumeration literal." - - * *Maximal nesting level of composite syntactic constructs* - This corresponds to the notion of the maximum nesting level in the - GNAT built-in style checks (see :ref:`Style_Checking`). - - * *Number of formal parameters* - Number of formal parameters of a subprogram; if a subprogram does - have parameters, then numbers of "in", "out" and "in out" - parameters are also reported. This metric is reported for - subprogram specifications and for subprogram instantiations. For - subprogram bodies, expression functions and null procedures this - metric is reported if the construct acts as a subprogram - declaration but is not a completion of previous declaration. This - metric is not reported for generic and formal subprograms. - - For the outermost unit in the file, ``gnatmetric`` additionally - computes the following metrics: - - * *Public subprograms* - This metric is computed for package specs. It is the number of - subprograms and generic subprograms declared in the visible part - (including the visible part of nested packages, protected objects, - and protected types). - - - * *All subprograms* - This metric is computed for bodies and subunits. The metric is - equal to a total number of subprogram bodies in the compilation - unit. - Neither generic instantiations nor renamings-as-a-body nor body - stubs are counted. Any subprogram body is counted, independently - of its nesting level and enclosing constructs. Generic bodies and - bodies of protected subprograms are counted in the same way as - 'usual' subprogram bodies. - - - * *Public types* - This metric is computed for package specs and generic package - declarations. It is the total number of types that can be - referenced from outside this compilation unit, plus the number of - types from all the visible parts of all the visible generic - packages. Generic formal types are not counted. Only types, not - subtypes, are included. - - Along with the total number of public types, the following - types are counted and reported separately: - - * *Abstract types* - - * *Root tagged types^ (abstract, non-abstract, private, - non-private). Type extensions are *not* counted - - * *Private types* (including private extensions) - - * *Task types* - - * *Protected types* - - * *All types* - This metric is computed for any compilation unit. It is equal to - the total number of the declarations of different types given in - the compilation unit. The private and the corresponding full type - declaration are counted as one type declaration. Incomplete type - declarations and generic formal types are not counted. - No distinction is made among different kinds of types (abstract, - private etc.); the total number of types is reported. - - By default, all the syntax metrics are reported. You can use the following - switches to select specific syntax metrics. - - - .. index:: --syntax (gnatmetric) - .. index:: --no-syntax (gnatmetric) - - - :switch:`--syntax-all` - Report all the syntax metrics - - - :switch:`--no-syntax-all` - Do not report any of syntax metrics - - - :switch:`--declarations` - Report the total number of declarations - - - :switch:`--no-declarations` - Do not report the total number of declarations - - - :switch:`--statements` - Report the total number of statements - - - :switch:`--no-statements` - Do not report the total number of statements - - - :switch:`--public-subprograms` - Report the number of public subprograms in a compilation unit - - - :switch:`--no-public-subprograms` - Do not report the number of public subprograms in a compilation unit - - - :switch:`--all-subprograms` - Report the number of all the subprograms in a compilation unit - - - :switch:`--no-all-subprograms` - Do not report the number of all the subprograms in a compilation unit - - - :switch:`--public-types` - Report the number of public types in a compilation unit - - - :switch:`--no-public-types` - Do not report the number of public types in a compilation unit - - - :switch:`--all-types` - Report the number of all the types in a compilation unit - - - :switch:`--no-all-types` - Do not report the number of all the types in a compilation unit - - - :switch:`--unit-nesting` - Report the maximal program unit nesting level - - - :switch:`--no-unit-nesting` - Do not report the maximal program unit nesting level - - - :switch:`--construct-nesting` - Report the maximal construct nesting level - - - :switch:`--no-construct-nesting` - Do not report the maximal construct nesting level - - :switch:`--param-number` - Report the number of subprogram parameters - - - :switch:`--no-param-number` - Do not report the number of subprogram parameters - - - .. _Contract_Metrics_Control: - - Contract Metrics Control - ^^^^^^^^^^^^^^^^^^^^^^^^ - - .. index:: Contract metrics control in gnatmetric - - :switch:`--contract-all` - Report all the contract metrics - - - :switch:`--no-contract-all` - Do not report any of the contract metrics - - - :switch:`--contract` - Report the number of public subprograms with contracts - - - :switch:`--no-contract` - Do not report the number of public subprograms with contracts - - - :switch:`--post` - Report the number of public subprograms with postconditions - - - :switch:`--no-post` - Do not report the number of public subprograms with postconditions - - - :switch:`--contract-complete` - Report the number of public subprograms with complete contracts - - - :switch:`--no-contract-complete` - Do not report the number of public subprograms with complete contracts - - - :switch:`--contract-cyclomatic` - Report the McCabe complexity of public subprograms - - - :switch:`--no-contract-cyclomatic` - Do not report the McCabe complexity of public subprograms - - - .. _Complexity_Metrics_Control: - - Complexity Metrics Control - ^^^^^^^^^^^^^^^^^^^^^^^^^^ - - .. index:: Complexity metrics control in gnatmetric - - For a program unit that is an executable body (a subprogram body - (including generic bodies), task body, entry body or a package body - containing its own statement sequence) ``gnatmetric`` computes the - following complexity metrics: - - * McCabe cyclomatic complexity; - - * McCabe essential complexity; - - * maximal loop nesting level; - - * extra exit points (for subprograms); - - The McCabe cyclomatic complexity metric is defined - in `http://www.mccabe.com/pdf/mccabe-nist235r.pdf `_ - - According to McCabe, both control statements and short-circuit control - forms should be taken into account when computing cyclomatic - complexity. For Ada 2012 we have also take into account conditional - expressions and quantified expressions. For each body, we compute - three metric values: - - * the complexity introduced by control - statements only, without taking into account short-circuit forms - (referred as ``statement complexity`` in ``gnatmetric`` output), - - * the complexity introduced by short-circuit control forms only - (referred as ``expression complexity`` in ``gnatmetric`` output), - and - - * the total - cyclomatic complexity, which is the sum of these two values - (referred as ``cyclomatic complexity`` in ``gnatmetric`` output). - - The cyclomatic complexity is also computed for Ada 2012 expression functions. - An expression function cannot have statements as its components, so only one - metric value is computed as a cyclomatic complexity of an expression function. - - The origin of cyclomatic complexity metric is the need to estimate the number - of independent paths in the control flow graph that in turn gives the number - of tests needed to satisfy paths coverage testing completeness criterion. - Considered from the testing point of view, a static Ada ``loop`` (that is, - the ``loop`` statement having static subtype in loop parameter - specification) does not add to cyclomatic complexity. By providing - :switch:`--no-static-loop` option a user - may specify that such loops should not be counted when computing the - cyclomatic complexity metric - - The Ada essential complexity metric is a McCabe cyclomatic complexity metric - counted for the code that is reduced by excluding all the pure structural Ada - control statements. An compound statement is considered as a non-structural - if it contains a ``raise`` or ``return`` statement as it subcomponent, - or if it contains a ``goto`` statement that transfers the control outside - the operator. A selective ``accept`` statement with a ``terminate`` alternative - is considered a non-structural statement. When computing this metric, - ``exit`` statements are treated in the same way as ``goto`` - statements unless the :switch:`-ne` option is specified. - - The Ada essential complexity metric defined here is intended to quantify - the extent to which the software is unstructured. It is adapted from - the McCabe essential complexity metric defined in - http://www.mccabe.com/pdf/mccabe-nist235r.pdf - but is modified to be more - suitable for typical Ada usage. For example, short circuit forms - are not penalized as unstructured in the Ada essential complexity metric. - - When computing cyclomatic and essential complexity, ``gnatmetric`` skips - the code in the exception handlers and in all the nested program units. The - code of assertions and predicates (that is, subprogram preconditions and - postconditions, subtype predicates and type invariants) is also skipped. - - By default, all the complexity metrics are reported. For more fine-grained - control you can use the following switches: - - - .. index:: --complexity (gnatmetric) - .. index:: --no-complexity (gnatmetric) - - - :switch:`--complexity-all` - Report all the complexity metrics - - - :switch:`--no-complexity-all` - Do not report any of the complexity metrics - - - :switch:`--complexity-cyclomatic` - Report the McCabe Cyclomatic Complexity - - - :switch:`--no-complexity-cyclomatic` - Do not report the McCabe Cyclomatic Complexity - - - :switch:`--complexity-essential` - Report the Essential Complexity - - - :switch:`--no-complexity-essential` - Do not report the Essential Complexity - - - :switch:`--loop-nesting` - Report maximal loop nesting level - - - :switch:`--no-loop-nesting` - Do not report maximal loop nesting level - - - :switch:`--complexity-average` - Report the average McCabe Cyclomatic Complexity for all the subprogram bodies, - task bodies, entry bodies and statement sequences in package bodies. - The metric is reported for whole set of processed Ada sources only. - - - :switch:`--no-complexity-average` - Do not report the average McCabe Cyclomatic Complexity for all the subprogram - bodies, task bodies, entry bodies and statement sequences in package bodies - - .. index:: --no-treat-exit-as-goto (gnatmetric) - - - :switch:`--no-treat-exit-as-goto` - Do not consider ``exit`` statements as ``goto``\ s when - computing Essential Complexity - - .. index:: --no-static-loop (gnatmetric) - - - :switch:`--no-static-loop` - Do not consider static loops when computing cyclomatic complexity - - - :switch:`--extra-exit-points` - Report the extra exit points for subprogram bodies. As an exit point, this - metric counts ``return`` statements and raise statements in case when the - raised exception is not handled in the same body. In case of a function this - metric subtracts 1 from the number of exit points, because a function body - must contain at least one ``return`` statement. - - - :switch:`--no-extra-exit-points` - Do not report the extra exit points for subprogram bodies - - - .. _Coupling_Metrics_Control: - - Coupling Metrics Control - ^^^^^^^^^^^^^^^^^^^^^^^^ - - .. index:: Coupling metrics control in gnatmetric - - .. index:: Coupling metrics (in gnatmetric) - - Coupling metrics measure the dependencies between a given entity and other - entities in the program. This information is useful since high coupling - may signal potential issues with maintainability as the program evolves. - - ``gnatmetric`` computes the following coupling metrics: - - - * *object-oriented coupling*, for classes in traditional object-oriented - sense; - - * *unit coupling*, for all the program units making up a program; - - * *control coupling*, reflecting dependencies between a unit and - other units that contain subprograms. - - .. index:: fan-out coupling - .. index:: efferent coupling - - Two kinds of coupling metrics are computed: - - * fan-out coupling ('efferent coupling'): - the number of entities the given entity depends upon. This metric - reflects how the given entity depends on the changes in the - 'external world'. - - .. index:: fan-in coupling - .. index:: afferent coupling - - * fan-in coupling ('afferent' coupling): - the number of entities that depend on a given entity. - This metric reflects how the 'external world' depends on the changes in a - given entity. - - Object-oriented coupling metrics measure the dependencies - between a given class (or a group of classes) and the other classes in the - program. In this subsection the term 'class' is used in its traditional - object-oriented programming sense (an instantiable module that contains data - and/or method members). A *category* (of classes) is a group of closely - related classes that are reused and/or modified together. - - A class ``K``\ 's fan-out coupling is the number of classes - that ``K`` depends upon. - A category's fan-out coupling is the number of classes outside the - category that the classes inside the category depend upon. - - A class ``K``\ 's fan-in coupling is the number of classes - that depend upon ``K``. - A category's fan-in coupling is the number of classes outside the - category that depend on classes belonging to the category. - - Ada's object-oriented paradigm separates the instantiable entity - (type) from the module (package), so the definition of the coupling - metrics for Ada maps the class and class category notions - onto Ada constructs. - - For the coupling metrics, several kinds of modules that define a tagged type - or an interface type -- library packages, library generic packages, and - library generic package instantiations -- are considered to be classes. - A category consists of a library package (or - a library generic package) that defines a tagged or an interface type, - together with all its descendant (generic) packages that define tagged - or interface types. Thus a - category is an Ada hierarchy of library-level program units. Class - coupling in Ada is referred to as 'tagged coupling', and category coupling - is referred to as 'hierarchy coupling'. - - For any package serving as a class, its body and subunits (if any) are - considered together with its spec when computing dependencies, and coupling - metrics are reported for spec units only. Dependencies between classes - mean Ada semantic dependencies. For object-oriented coupling - metrics, only dependencies on units treated as classes are - considered. - - Similarly, for unit and control coupling an entity is considered to be the - conceptual construct consisting of the entity's specification, body, and - any subunits (transitively). - ``gnatmetric`` computes - the dependencies of all these units as a whole, but - metrics are only reported for spec - units (or for a subprogram body unit in case if there is no - separate spec for the given subprogram). - - For unit coupling, dependencies are computed between all kinds of program - units. For control coupling, the dependencies of a given unit are limited to - those units that define subprograms. Thus control fan-out coupling is reported - for all units, but control fan-in coupling is only reported for units - that define subprograms. - - The following simple example illustrates the difference between unit coupling - and control coupling metrics: - - .. code-block:: ada - - package Lib_1 is - function F_1 (I : Integer) return Integer; - end Lib_1; - - package Lib_2 is - type T_2 is new Integer; - end Lib_2; - - package body Lib_1 is - function F_1 (I : Integer) return Integer is - begin - return I + 1; - end F_1; - end Lib_1; - - with Lib_2; use Lib_2; - package Pack is - Var : T_2; - function Fun (I : Integer) return Integer; - end Pack; - - with Lib_1; use Lib_1; - package body Pack is - function Fun (I : Integer) return Integer is - begin - return F_1 (I); - end Fun; - end Pack; - - If we apply ``gnatmetric`` with the :switch:`--coupling-all` option to - these units, the result will be: - - :: - - Coupling metrics: - ================= - Unit Lib_1 (C:\\customers\\662\\L406-007\\lib_1.ads) - control fan-out coupling : 0 - control fan-in coupling : 1 - unit fan-out coupling : 0 - unit fan-in coupling : 1 - - Unit Pack (C:\\customers\\662\\L406-007\\pack.ads) - control fan-out coupling : 1 - control fan-in coupling : 0 - unit fan-out coupling : 2 - unit fan-in coupling : 0 - - Unit Lib_2 (C:\\customers\\662\\L406-007\\lib_2.ads) - control fan-out coupling : 0 - unit fan-out coupling : 0 - unit fan-in coupling : 1 - - The result does not contain values for object-oriented - coupling because none of the argument units contains a tagged type and - therefore none of these units can be treated as a class. - - The ``Pack`` package (spec and body) depends on two - units -- ``Lib_1`` and ``Lib_2`` -- and so its unit fan-out coupling - is 2. Since nothing depends on it, its unit fan-in coupling is 0, as - is its control fan-in coupling. Only one of the units ``Pack`` depends - upon defines a subprogram, so its control fan-out coupling is 1. - - ``Lib_2`` depends on nothing, so its fan-out metrics are 0. It does - not define any subprograms, so it has no control fan-in metric. - One unit (``Pack``) depends on it , so its unit fan-in coupling is 1. - - ``Lib_1`` is similar to ``Lib_2``, but it does define a subprogram. - Its control fan-in coupling is 1 (because there is one unit - depending on it). - - When computing coupling metrics, ``gnatmetric`` counts only - dependencies between units that are arguments of the ``gnatmetric`` - invocation. Coupling metrics are program-wide (or project-wide) metrics, so - you should invoke ``gnatmetric`` for - the complete set of sources comprising your program. This can be done - by invoking ``gnatmetric`` with the corresponding project file - and with the :switch:`-U` option. - - By default, all the coupling metrics are reported. You can use the following - switches to select specific syntax metrics. - - .. index:: --tagged-coupling (gnatmetric) - .. index:: --hierarchy-coupling (gnatmetric) - .. index:: --unit-coupling (gnatmetric) - .. index:: --control-coupling (gnatmetric) - - :switch:`--coupling-all` - Report all the coupling metrics - - - :switch:`--tagged-coupling-out` - Report tagged (class) fan-out coupling - - - :switch:`--tagged-coupling-in` - Report tagged (class) fan-in coupling - - - :switch:`--hierarchy-coupling-out` - Report hierarchy (category) fan-out coupling - - - :switch:`--hierarchy-coupling-in` - Report hierarchy (category) fan-in coupling - - - :switch:`--unit-coupling-out` - Report unit fan-out coupling - - - :switch:`--unit-coupling-in` - Report unit fan-in coupling - - - :switch:`--control-coupling-out` - Report control fan-out coupling - - - :switch:`--control-coupling-in` - Report control fan-in coupling - - - .. _Other_gnatmetric_Switches: - - Other ``gnatmetric`` Switches - ----------------------------- - - Additional ``gnatmetric`` switches are as follows: - - - .. index:: --version (gnatmetric) - - :switch:`--version` - Display copyright and version, then exit disregarding all other options. - - - .. index:: --help (gnatmetric) - - :switch:`--help` - Display usage, then exit disregarding all other options. - - - .. index:: -P (gnatmetric) - - :switch:`-P {file}` - Indicates the name of the project file that describes the set of sources - to be processed. The exact set of argument sources depends on other options - specified, see below. An aggregate project is allowed as the file parameter - only if it has exactly one non-aggregate project being aggregated. - - - .. index:: -U (gnatmetric) - - :switch:`-U` - If a project file is specified and no argument source is explicitly - specified (either directly or by means of :switch:`-files` option), process - all the units of the closure of the argument project. Otherwise this option - has no effect. - - - :switch:`-U {main_unit}` - If a project file is specified and no argument source is explicitly - specified (either directly or by means of :switch:`-files` option), process - the closure of units rooted at ``main_unit``. Otherwise this option - has no effect. - - - .. index:: -X (gnatmetric) - - :switch:`-X{name}={value}` - Indicates that external variable ``name`` in the argument project - has the value ``value``. Has no effect if no project is specified. - - - .. index:: --RTS (gnatmetric) - - :switch:`--RTS={rts-path}` - Specifies the default location of the runtime library. Same meaning as the - equivalent ``gnatmake`` flag (see :ref:`Switches_for_gnatmake`). - - - .. index:: --subdirs=dir (gnatmetric) - - :switch:`--subdirs={dir}` - Use the specified subdirectory of the project objects file (or of the - project file directory if the project does not specify an object directory) - for tool output files. Has no effect if no project is specified as - tool argument r if :switch:`--no-objects-dir` is specified. - - - .. index:: --files (gnatmetric) - - :switch:`--files={file}` - Take as arguments the files listed in text file ``file``. - Text file ``file`` may contain empty lines that are ignored. - Each nonempty line should contain the name of an existing file. - Several such switches may be specified simultaneously. - - - .. index:: --ignore (gnatmetric) - - :switch:`--ignore={filename}` - Do not process the sources listed in a specified file. - - - .. index:: --verbose (gnatmetric) - - :switch:`--verbose` - Verbose mode; - ``gnatmetric`` generates version information and then - a trace of sources being processed. - - - .. index:: --quiet (gnatmetric) - - :switch:`--quiet` - Quiet mode. - - If a project file is specified and no argument source is explicitly - specified (either directly or by means of :switch:`-files` option), and no - :switch:`-U` is specified, then the set of processed sources is - all the immediate units of the argument project. - - - Legacy Switches - ^^^^^^^^^^^^^^^ - - Some switches have a short form, mostly for legacy reasons, - as shown below. - - .. index:: -x (gnatmetric) - - :switch:`-x` - :switch:`--generate-xml-output` - - .. index:: -xs (gnatmetric) - - :switch:`-xs` - :switch:`--generate-xml-schema` - - .. index:: -nt (gnatmetric) - - :switch:`-nt` - :switch:`--no-text-output` - - .. index:: -d (gnatmetric) - - :switch:`-d {output-dir}` - :switch:`--output-dir` - - .. index:: -o (gnatmetric) - - :switch:`-o {file-suffix}` - :switch:`--output-suffix` - - .. index:: -og (gnatmetric) - - :switch:`-og {file-name}` - :switch:`--global-file-name` - - .. index:: -ox (gnatmetric) - - :switch:`-ox {file-name}` - :switch:`--xml-file-name` - - .. index:: -sfn (gnatmetric) - - :switch:`-sfn` - :switch:`--short-file-names` - - .. index:: -W (gnatsmetric) - - :switch:`-W{e}` - :switch:`--wide-character-encoding={e}` - - .. index:: -nolocal (gnatmetric) - - :switch:`-nolocal` - :switch:`--no-local-metrics` - - .. index:: -ne (gnatmetric) - - :switch:`-ne` - :switch:`--no-treat-exit-as-goto` - - .. index:: -files (gnatmetric) - - :switch:`-files {filename}` - :switch:`--files` - - .. index:: -v (gnatmetric) - - :switch:`-v` - :switch:`--verbose` - - .. index:: -q (gnatmetric) - - :switch:`-q` - :switch:`--quiet` - .. only:: PRO or GPL .. _The_GNAT_Pretty_Printer_gnatpp: @@ -3026,7 +1908,7 @@ building specialized scripts. naming conventions. Note that it is no longer necessary to specify the Ada language version; - ``gnatmetric`` can process Ada source code written in any version from + ``gnatstub`` can process Ada source code written in any version from Ada 83 onward without specifying any language version switch. * *switches* -- cgit v1.1 From 63055635797e98d9cc67e53c3de44bae2f4c9939 Mon Sep 17 00:00:00 2001 From: Justin Squirek Date: Tue, 6 Sep 2022 15:59:59 +0000 Subject: ada: Improve accessibility check generation Improve accessibility check generation by more precisely identifying cases in which an Original_Node call is needed. Instead of grabbing the Original_Node of a prefix in all cases (since this can cause issues where unanalyzed instance names get referenced) we only obtain the original node when said prefix comes as a result of expanding function calls. gcc/ada/ * sem_util.adb (Accessibility_Level): Modify indexed and selected components case by reducing the scope where Original_Node gets used. --- gcc/ada/sem_util.adb | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/sem_util.adb b/gcc/ada/sem_util.adb index b0babeb..c43a008 100644 --- a/gcc/ada/sem_util.adb +++ b/gcc/ada/sem_util.adb @@ -531,7 +531,7 @@ package body Sem_Util is -- Local variables - E : Entity_Id := Original_Node (Expr); + E : Node_Id := Original_Node (Expr); Pre : Node_Id; -- Start of processing for Accessibility_Level @@ -777,8 +777,18 @@ package body Sem_Util is -- We don't handle function calls in prefix notation correctly ??? - when N_Indexed_Component | N_Selected_Component => - Pre := Original_Node (Prefix (E)); + when N_Indexed_Component | N_Selected_Component | N_Slice => + Pre := Prefix (E); + + -- Fetch the original node when the prefix comes from the result + -- of expanding a function call since we want to find the level + -- of the original source call. + + if not Comes_From_Source (Pre) + and then Nkind (Original_Node (Pre)) = N_Function_Call + then + Pre := Original_Node (Pre); + end if; -- When E is an indexed component or selected component and -- the current Expr is a function call, we know that we are -- cgit v1.1 From 5549d2695a36f1cd97a1a5d2089c9c5a7f3fb03b Mon Sep 17 00:00:00 2001 From: Piotr Trojanek Date: Thu, 8 Sep 2022 14:58:24 +0200 Subject: ada: Only reject volatile ghost objects when SPARK_Mode is On SPARK rule that forbids ghost volatile objects is only affecting proof and not generation of object code. It is now only applied where SPARK_Mode is On. This flexibility is needed to compile code automatically instrumented by GNATcoverage. gcc/ada/ * contracts.adb (Analyze_Object_Contract): Check SPARK_Mode before applying SPARK rule. --- gcc/ada/contracts.adb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ada/contracts.adb b/gcc/ada/contracts.adb index 34db67a..dd573d3 100644 --- a/gcc/ada/contracts.adb +++ b/gcc/ada/contracts.adb @@ -1207,7 +1207,7 @@ package body Contracts is -- A Ghost object cannot be effectively volatile (SPARK RM 6.9(7) and -- SPARK RM 6.9(19)). - elsif Is_Effectively_Volatile (Obj_Id) then + elsif SPARK_Mode = On and then Is_Effectively_Volatile (Obj_Id) then Error_Msg_N ("ghost object & cannot be volatile", Obj_Id); -- A Ghost object cannot be imported or exported (SPARK RM 6.9(7)). -- cgit v1.1 From 2ef56cae72631a7349b4cb2b6bd843f05789e231 Mon Sep 17 00:00:00 2001 From: Piotr Trojanek Date: Mon, 12 Sep 2022 15:33:15 +0200 Subject: ada: Delay expansion of iterated component association When preanalysing spec expression (e.g. expression of an expression function), the name of iterator specification within an iterated component association should not be expanded, especially in GNATprove mode. gcc/ada/ * sem_ch5.adb (Analyze_Iterator_Specification): Delay expansion of for iterated component association just like it is done within quantified expression. --- gcc/ada/sem_ch5.adb | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/sem_ch5.adb b/gcc/ada/sem_ch5.adb index 17bf6d9..6d07f3d 100644 --- a/gcc/ada/sem_ch5.adb +++ b/gcc/ada/sem_ch5.adb @@ -2429,11 +2429,12 @@ package body Sem_Ch5 is if not Is_Entity_Name (Iter_Name) - -- When the context is a quantified expression, the renaming - -- declaration is delayed until the expansion phase if we are - -- doing expansion. + -- When the context is a quantified expression or iterated component + -- association, the renaming declaration is delayed until the + -- expansion phase if we are doing expansion. - and then (Nkind (Parent (N)) /= N_Quantified_Expression + and then (Nkind (Parent (N)) not in N_Quantified_Expression + | N_Iterated_Component_Association or else (Operating_Mode = Check_Semantics and then not GNATprove_Mode)) -- cgit v1.1 From 4450567167e126051e3100de682e09f0902a2106 Mon Sep 17 00:00:00 2001 From: Piotr Trojanek Date: Mon, 12 Sep 2022 18:10:59 +0200 Subject: ada: Delay expansion of iterator specification in preanalysis When preanalysing spec expression (e.g. expression of an expression function), the name of iterator specification should not be expanded. This patch simplifies a complicated condition for delaying expansion within quantified expressions and iterated component associations. gcc/ada/ * sem_ch5.adb (Analyze_Iterator_Specification): Delay expansion based on Full_Analysis flag. --- gcc/ada/sem_ch5.adb | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/sem_ch5.adb b/gcc/ada/sem_ch5.adb index 6d07f3d..d0f00b3 100644 --- a/gcc/ada/sem_ch5.adb +++ b/gcc/ada/sem_ch5.adb @@ -2429,14 +2429,9 @@ package body Sem_Ch5 is if not Is_Entity_Name (Iter_Name) - -- When the context is a quantified expression or iterated component - -- association, the renaming declaration is delayed until the - -- expansion phase if we are doing expansion. - - and then (Nkind (Parent (N)) not in N_Quantified_Expression - | N_Iterated_Component_Association - or else (Operating_Mode = Check_Semantics - and then not GNATprove_Mode)) + -- Do not perform this expansion in preanalysis + + and then Full_Analysis -- Do not perform this expansion when expansion is disabled, where the -- temporary may hide the transformation of a selected component into -- cgit v1.1 From 91c706565f941ac7d317951cf3ab186f197252f0 Mon Sep 17 00:00:00 2001 From: Tucker Taft Date: Tue, 13 Sep 2022 15:28:42 +0200 Subject: ada: Make Original_Aspect_Pragma_Name more precise This commit makes Original_Aspect_Pragma_Name more precise in cases where there is a second level of indirection caused by pragmas being turned into Check pragmas. gcc/ada/ * sem_util.adb (Original_Aspect_Pragma_Name): Check for Check pragmas. --- gcc/ada/sem_util.adb | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'gcc') diff --git a/gcc/ada/sem_util.adb b/gcc/ada/sem_util.adb index c43a008..9ae082c 100644 --- a/gcc/ada/sem_util.adb +++ b/gcc/ada/sem_util.adb @@ -26559,6 +26559,14 @@ package body Sem_Util is Item_Nam := Chars (Original_Node (Pragma_Identifier (Original_Node (Item)))); + if Item_Nam = Name_Check then + -- Pragma "Check" preserves the original pragma name as its first + -- argument. + Item_Nam := + Chars (Expression (First (Pragma_Argument_Associations + (Original_Node (Item))))); + end if; + else pragma Assert (Nkind (Item) = N_Aspect_Specification); Item_Nam := Chars (Identifier (Item)); -- cgit v1.1 From 6b8e3ee10fb7c15a79ebb8739a1fca3b2a62c706 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Le=20Gouguec?= Date: Mon, 4 Jul 2022 11:12:47 +0200 Subject: ada: Document support for the mold linker gcc/ada/ * 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. --- .../building_executable_programs_with_gnat.rst | 28 +++++++++++++++++++--- gcc/ada/gnat_ugn.texi | 10 ++++---- 2 files changed, 30 insertions(+), 8 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/doc/gnat_ugn/building_executable_programs_with_gnat.rst b/gcc/ada/doc/gnat_ugn/building_executable_programs_with_gnat.rst index 6a47809..f675732 100644 --- a/gcc/ada/doc/gnat_ugn/building_executable_programs_with_gnat.rst +++ b/gcc/ada/doc/gnat_ugn/building_executable_programs_with_gnat.rst @@ -6229,11 +6229,33 @@ Linker switches can be specified after :switch:`-largs` builder switch. .. index:: -fuse-ld=name :switch:`-fuse-ld={name}` - Linker to be used. The default is ``bfd`` for :file:`ld.bfd`, - the alternative being ``gold`` for :file:`ld.gold`. The later is - a more recent and faster linker, but only available on GNU/Linux + Linker to be used. The default is ``bfd`` for :file:`ld.bfd`; ``gold`` + (for :file:`ld.gold`) and ``mold`` (for :file:`ld.mold`) are more + recent and faster alternatives, but only available on GNU/Linux platforms. + .. only:: PRO + + The GNAT distribution for native Linux platforms includes ``mold``, + compiled against OpenSSL version 1.1; however, the distribution does + not include OpenSSL. In order to use this linker, you may either: + + * use your system's OpenSSL library, if the version matches: in this + situation, you need not do anything beside using the + :switch:`-fuse-ld=mold` switch, + + * obtain a source distribution for OpenSSL 1.1, compile the + :file:`libcrypto.so` library and install it in the directory of + your choice, then include this directory in the + :envvar:`LD_LIBRARY_PATH` environment variable, + + * install another copy of ``mold`` by other means in the directory + of your choice, and include this directory in the :envvar:`PATH` + environment variable; you may find this alternative preferable if + the copy of ``mold`` included in GNAT does not suit your needs + (e.g. being able to link against your system's OpenSSL, or using + another version of ``mold``). + .. _Binding_with_gnatbind: Binding with ``gnatbind`` diff --git a/gcc/ada/gnat_ugn.texi b/gcc/ada/gnat_ugn.texi index f2cb1ed..d7bcf74 100644 --- a/gcc/ada/gnat_ugn.texi +++ b/gcc/ada/gnat_ugn.texi @@ -19,7 +19,7 @@ @copying @quotation -GNAT User's Guide for Native Platforms , Sep 09, 2022 +GNAT User's Guide for Native Platforms , Sep 26, 2022 AdaCore @@ -15317,10 +15317,11 @@ Linker switches can be specified after @code{-largs} builder switch. @item @code{-fuse-ld=`name'} -Linker to be used. The default is @code{bfd} for @code{ld.bfd}, -the alternative being @code{gold} for @code{ld.gold}. The later is -a more recent and faster linker, but only available on GNU/Linux +Linker to be used. The default is @code{bfd} for @code{ld.bfd}; @code{gold} +(for @code{ld.gold}) and @code{mold} (for @code{ld.mold}) are more +recent and faster alternatives, but only available on GNU/Linux platforms. + @end table @node Binding with gnatbind,Linking with gnatlink,Linker Switches,Building Executable Programs with GNAT @@ -17932,7 +17933,6 @@ instr.ads - @c -- Example: A |withing| unit has a |with| clause, it |withs| a |withed| unit @node GNAT and Program Execution,Platform-Specific Information,GNAT Utility Programs,Top -- cgit v1.1 From 37645e2cd752e2dddcf52d70dc20eadda3e44171 Mon Sep 17 00:00:00 2001 From: Steve Baird Date: Mon, 12 Sep 2022 15:31:19 -0700 Subject: ada: Improve CUDA host-side and device-side binder support Binder-generated code is not allowed to use Ada2012 syntax. In order to specify an aspect, a pragma must be used. gcc/ada/ * 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. --- gcc/ada/bindgen.adb | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/bindgen.adb b/gcc/ada/bindgen.adb index b2fa44d..f2aaa2d 100644 --- a/gcc/ada/bindgen.adb +++ b/gcc/ada/bindgen.adb @@ -134,9 +134,6 @@ package body Bindgen is -- Text for aspect specifications (if any) given as part of the -- Adainit and Adafinal spec declarations. - function Aspect_Text return String is - (if Enable_CUDA_Device_Expansion then " with CUDA_Global" else ""); - ---------------------------------- -- Interface_State Pragma Table -- ---------------------------------- @@ -2644,10 +2641,11 @@ package body Bindgen is end if; WBI (""); - WBI (" procedure " & Ada_Init_Name.all & Aspect_Text & ";"); + WBI (" procedure " & Ada_Init_Name.all & ";"); if Enable_CUDA_Device_Expansion then WBI (" pragma Export (C, " & Ada_Init_Name.all & ", Link_Name => """ & Device_Ada_Init_Link_Name & """);"); + WBI (" pragma CUDA_Global (" & Ada_Init_Name.all & ");"); else WBI (" pragma Export (C, " & Ada_Init_Name.all & ", """ & Ada_Init_Name.all & """);"); @@ -2662,11 +2660,12 @@ package body Bindgen is if not Cumulative_Restrictions.Set (No_Finalization) then WBI (""); - WBI (" procedure " & Ada_Final_Name.all & Aspect_Text & ";"); + WBI (" procedure " & Ada_Final_Name.all & ";"); if Enable_CUDA_Device_Expansion then WBI (" pragma Export (C, " & Ada_Final_Name.all & ", Link_Name => """ & Device_Ada_Final_Link_Name & """);"); + WBI (" pragma CUDA_Global (" & Ada_Final_Name.all & ");"); else WBI (" pragma Export (C, " & Ada_Final_Name.all & ", """ & Ada_Final_Name.all & """);"); -- cgit v1.1 From c381ccdf0642d90f1f5ad07bcfc844a7c6037bea Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Tue, 13 Sep 2022 19:48:02 +0200 Subject: ada: Document Long_Long_Long_Size parameter for -gnateT This was overlooked when the new parameter was created. gcc/ada/ * doc/gnat_ugn/building_executable_programs_with_gnat.rst (-gnateT): Document new parameter Long_Long_Long_Size. * gnat_ugn.texi: Regenerate. --- gcc/ada/doc/gnat_ugn/building_executable_programs_with_gnat.rst | 2 ++ gcc/ada/gnat_ugn.texi | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ada/doc/gnat_ugn/building_executable_programs_with_gnat.rst b/gcc/ada/doc/gnat_ugn/building_executable_programs_with_gnat.rst index f675732..d4bddff 100644 --- a/gcc/ada/doc/gnat_ugn/building_executable_programs_with_gnat.rst +++ b/gcc/ada/doc/gnat_ugn/building_executable_programs_with_gnat.rst @@ -1719,6 +1719,7 @@ Alphabetical List of All Switches Float_Words_BE : Nat; -- Float words stored big-endian? Int_Size : Pos; -- Standard.Integer'Size Long_Double_Size : Pos; -- Standard.Long_Long_Float'Size + Long_Long_Long_Size : Pos; -- Standard.Long_Long_Long_Integer'Size Long_Long_Size : Pos; -- Standard.Long_Long_Integer'Size Long_Size : Pos; -- Standard.Long_Integer'Size Maximum_Alignment : Pos; -- Maximum permitted alignment @@ -1816,6 +1817,7 @@ Alphabetical List of All Switches Float_Words_BE 0 Int_Size 64 Long_Double_Size 128 + Long_Long_Long_Size 128 Long_Long_Size 64 Long_Size 64 Maximum_Alignment 16 diff --git a/gcc/ada/gnat_ugn.texi b/gcc/ada/gnat_ugn.texi index d7bcf74..77d239f 100644 --- a/gcc/ada/gnat_ugn.texi +++ b/gcc/ada/gnat_ugn.texi @@ -9220,6 +9220,7 @@ Float_Size : Pos; -- Standard.Float'Size Float_Words_BE : Nat; -- Float words stored big-endian? Int_Size : Pos; -- Standard.Integer'Size Long_Double_Size : Pos; -- Standard.Long_Long_Float'Size +Long_Long_Long_Size : Pos; -- Standard.Long_Long_Long_Integer'Size Long_Long_Size : Pos; -- Standard.Long_Long_Integer'Size Long_Size : Pos; -- Standard.Long_Integer'Size Maximum_Alignment : Pos; -- Maximum permitted alignment @@ -9307,6 +9308,7 @@ Float_Size 32 Float_Words_BE 0 Int_Size 64 Long_Double_Size 128 +Long_Long_Long_Size 128 Long_Long_Size 64 Long_Size 64 Maximum_Alignment 16 @@ -29317,8 +29319,8 @@ to permit their use in free software. @printindex ge -@anchor{gnat_ugn/gnat_utility_programs switches-related-to-project-files}@w{ } @anchor{cf}@w{ } +@anchor{gnat_ugn/gnat_utility_programs switches-related-to-project-files}@w{ } @c %**end of body @bye -- cgit v1.1 From dda025c9ce1d368f91a379fd31811aec266cc7e9 Mon Sep 17 00:00:00 2001 From: Piotr Trojanek Date: Sat, 10 Sep 2022 11:22:55 +0200 Subject: ada: Remove unreferenced C macro from OS constants template The STR/STR1 macros in OS constants template has been unreferenced since 2005, so we can safely remove them. gcc/ada/ * s-oscons-tmplt.c (STR, STR1): Remove. --- gcc/ada/s-oscons-tmplt.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/s-oscons-tmplt.c b/gcc/ada/s-oscons-tmplt.c index af69190..5394122 100644 --- a/gcc/ada/s-oscons-tmplt.c +++ b/gcc/ada/s-oscons-tmplt.c @@ -237,9 +237,6 @@ int counter = 0; #define CST(name,comment) C(#name,String,name,comment) /* String constant */ -#define STR(x) STR1(x) -#define STR1(x) #x - #ifdef __MINGW32__ unsigned int _CRT_fmode = _O_BINARY; #endif -- cgit v1.1 From 756efb7484f4bbdc74dd9c285fff5c5d4a0730ff Mon Sep 17 00:00:00 2001 From: Piotr Trojanek Date: Fri, 9 Sep 2022 23:32:00 +0200 Subject: ada: Remove unreferenced Rtsfind entries Remove unreferenced entries for finding runtime units and runtime entities by the compiler. Code cleanup using basic grep scripting. gcc/ada/ * 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. --- gcc/ada/rtsfind.ads | 111 +--------------------------------------------------- 1 file changed, 2 insertions(+), 109 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/rtsfind.ads b/gcc/ada/rtsfind.ads index 65c6409..24aca2c 100644 --- a/gcc/ada/rtsfind.ads +++ b/gcc/ada/rtsfind.ads @@ -189,7 +189,6 @@ package Rtsfind is -- Children of Interfaces Interfaces_C, - Interfaces_Packed_Decimal, -- Children of Interfaces.C @@ -205,7 +204,6 @@ package Rtsfind is System_Address_To_Access_Conversions, System_Arith_64, System_Arith_128, - System_AST_Handling, System_Assertions, System_Atomic_Operations, System_Atomic_Primitives, @@ -257,9 +255,6 @@ package Rtsfind is System_Fat_LFlt, System_Fat_LLF, System_Fat_SFlt, - System_Fat_VAX_D_Float, - System_Fat_VAX_F_Float, - System_Fat_VAX_G_Float, System_Finalization_Masters, System_Finalization_Root, System_Fore_Decimal_32, @@ -288,14 +283,12 @@ package Rtsfind is System_Img_LLLI, System_Img_LLU, System_Img_LLLU, - System_Img_Name, System_Img_Uns, System_Img_WChar, System_Interrupts, System_Long_Long_Float_Expon, System_Machine_Code, System_Mantissa, - System_Memcop, System_Memory, System_Multiprocessors, System_Pack_03, @@ -420,10 +413,7 @@ package Rtsfind is System_Pack_127, System_Parameters, System_Partition_Interface, - System_Pool_32_Global, System_Pool_Global, - System_Pool_Empty, - System_Pool_Local, System_Pool_Size, System_Put_Images, System_Put_Task_Images, @@ -440,7 +430,6 @@ package Rtsfind is System_Stream_Attributes, System_Task_Info, System_Tasking, - System_Threads, System_Unsigned_Types, System_Val_Bool, System_Val_Char, @@ -461,7 +450,6 @@ package Rtsfind is System_Val_LLLI, System_Val_LLU, System_Val_LLLU, - System_Val_Name, System_Val_Uns, System_Val_WChar, System_Version_Control, @@ -475,7 +463,6 @@ package Rtsfind is System_Wid_LLLI, System_Wid_LLU, System_Wid_LLLU, - System_Wid_Name, System_Wid_Uns, System_Wid_WChar, System_WWd_Char, @@ -484,7 +471,7 @@ package Rtsfind is -- Children of System.Atomic_Operations - System_Atomic_Operations_Test_And_Set, + System_Atomic_Operations_Test_And_Set, -- Children of System.Dim @@ -561,17 +548,13 @@ package Rtsfind is RE_Set_Deadline, -- Ada.Dispatching.EDF - RE_Code_Loc, -- Ada.Exceptions RE_Exception_Id, -- Ada.Exceptions - RE_Exception_Identity, -- Ada.Exceptions RE_Exception_Information, -- Ada.Exceptions RE_Exception_Message, -- Ada.Exceptions RE_Exception_Name_Simple, -- Ada.Exceptions RE_Exception_Occurrence, -- Ada.Exceptions - RE_Exception_Occurrence_Access, -- Ada.Exceptions RE_Null_Id, -- Ada.Exceptions RE_Null_Occurrence, -- Ada.Exceptions - RE_Poll, -- Ada.Exceptions RE_Raise_Exception, -- Ada.Exceptions RE_Raise_Exception_Always, -- Ada.Exceptions RE_Raise_From_Controlled_Operation, -- Ada.Exceptions @@ -596,7 +579,7 @@ package Rtsfind is RE_Names, -- Ada.Interrupts.Names RE_Clock, -- Ada.Real_Time - RE_Clock_Time, -- Ada.Real_Time + RE_Clock_Time, -- Ada.Real_Time [used by GNATprove] RE_Time_Span, -- Ada.Real_Time RE_Time_Span_Zero, -- Ada.Real_Time RO_RT_Time, -- Ada.Real_Time @@ -612,8 +595,6 @@ package Rtsfind is RE_Stream_Element_Array, -- Ada.Streams RE_Stream_Element_Offset, -- Ada.Streams - RE_Stream_Access, -- Ada.Streams.Stream_IO - RO_SU_Super_String, -- Ada.Strings.Superbounded RO_WI_Super_String, -- Ada.Strings.Wide_Superbounded @@ -628,8 +609,6 @@ package Rtsfind is RE_Buffer_Type, -- Ada.Strings.Text_Buffers.Unbounded RE_Get, -- Ada.Strings.Text_Buffers.Unbounded - RE_Wide_Get, -- Ada.Strings.Text_Buffers.Unbounded - RE_Wide_Wide_Get, -- Ada.Strings.Text_Buffers.Unbounded RE_Wait_For_Release, -- Ada.Synchronous_Barriers @@ -641,7 +620,6 @@ package Rtsfind is RE_Address_Array, -- Ada.Tags RE_Addr_Ptr, -- Ada.Tags RE_Base_Address, -- Ada.Tags - RE_Check_Interface_Conversion, -- Ada.Tags RE_Check_TSD, -- Ada.Tags RE_Cstring_Ptr, -- Ada.Tags RE_CW_Membership, -- Ada.Tags @@ -656,13 +634,11 @@ package Rtsfind is RE_External_Tag, -- Ada.Tags RO_TA_External_Tag, -- Ada.Tags RE_Get_Access_Level, -- Ada.Tags - RE_Get_Alignment, -- Ada.Tags RE_Get_Entry_Index, -- Ada.Tags RE_Get_Offset_Index, -- Ada.Tags RE_Get_Prim_Op_Kind, -- Ada.Tags RE_Get_Tagged_Kind, -- Ada.Tags RE_HT_Link, -- Ada.Tags - RE_Idepth, -- Ada.Tags RE_Interfaces_Array, -- Ada.Tags RE_Interfaces_Table, -- Ada.Tags RE_Interface_Data, -- Ada.Tags @@ -675,8 +651,6 @@ package Rtsfind is RE_No_Dispatch_Table_Wrapper, -- Ada.Tags RE_No_Tag, -- Ada.Tags RE_NDT_Prims_Ptr, -- Ada.Tags - RE_NDT_TSD, -- Ada.Tags - RE_Num_Prims, -- Ada.Tags RE_Object_Specific_Data, -- Ada.Tags RE_Offset_To_Top, -- Ada.Tags RE_Offset_To_Top_Ptr, -- Ada.Tags @@ -699,11 +673,9 @@ package Rtsfind is RE_Primary_DT, -- Ada.Tags RE_Signature, -- Ada.Tags RE_SSD, -- Ada.Tags - RE_TSD, -- Ada.Tags RE_Type_Specific_Data, -- Ada.Tags RE_Register_Interface_Offset, -- Ada.Tags RE_Register_Tag, -- Ada.Tags - RE_Register_TSD, -- Ada.Tags RE_Transportable, -- Ada.Tags RE_Secondary_DT, -- Ada.Tags RE_Secondary_Tag, -- Ada.Tags @@ -749,7 +721,6 @@ package Rtsfind is RE_Stream_T, -- CUDA.Driver_Types - RE_Fatbin_Wrapper, -- CUDA.Internal RE_Launch_Kernel, -- CUDA.Internal RE_Pop_Call_Configuration, -- CUDA.Internal RE_Push_Call_Configuration, -- CUDA.Internal @@ -772,19 +743,14 @@ package Rtsfind is RO_IC_Unsigned, -- Interfaces.C - RE_Chars_Ptr, -- Interfaces.C.Strings - RE_New_Char_Array, -- Interfaces.C.Strings - RE_Address, -- System RE_Any_Priority, -- System RE_Bit_Order, -- System RE_Default_Priority, -- System RE_High_Order_First, -- System RE_Interrupt_Priority, -- System - RE_Lib_Stop, -- System RE_Low_Order_First, -- System RE_Max_Base_Digits, -- System - RE_Max_Priority, -- System RE_Null_Address, -- System RE_Priority, -- System @@ -802,8 +768,6 @@ package Rtsfind is RE_Subtract_With_Ovflo_Check128, -- System.Arith_128 RE_Scaled_Divide128, -- System.Arith_128 - RE_Create_AST_Handler, -- System.AST_Handling - RE_Assert_Failure, -- System.Assertions RE_Raise_Assert_Failure, -- System.Assertions @@ -824,9 +788,6 @@ package Rtsfind is RE_Atomic_Test_And_Set, -- System.Atomic_Operations.Test_And_Set RE_AST_Handler, -- System.Aux_DEC - RE_Import_Address, -- System.Aux_DEC - RE_Import_Value, -- System.Aux_DEC - RE_No_AST_Handler, -- System.Aux_DEC RE_Type_Class, -- System.Aux_DEC RE_Type_Class_Enumeration, -- System.Aux_DEC RE_Type_Class_Integer, -- System.Aux_DEC @@ -954,15 +915,6 @@ package Rtsfind is RE_Attr_Long_Long_Float, -- System.Fat_LLF - RE_Attr_VAX_D_Float, -- System.Fat_VAX_D_Float - RE_Fat_VAX_D, -- System.Fat_VAX_D_Float - - RE_Attr_VAX_F_Float, -- System.Fat_VAX_F_Float - RE_Fat_VAX_F, -- System.Fat_VAX_F_Float - - RE_Attr_VAX_G_Float, -- System.Fat_VAX_G_Float - RE_Fat_VAX_G, -- System.Fat_VAX_G_Float - RE_Add_Offset_To_Address, -- System.Finalization_Masters RE_Attach, -- System.Finalization_Masters RE_Base_Pool, -- System.Finalization_Masters @@ -970,10 +922,8 @@ package Rtsfind is RE_Finalization_Master_Ptr, -- System.Finalization_Masters RE_Set_Base_Pool, -- System.Finalization_Masters RE_Set_Finalize_Address, -- System.Finalization_Masters - RE_Set_Is_Heterogeneous, -- System.Finalization_Masters RE_Root_Controlled, -- System.Finalization_Root - RE_Root_Controlled_Ptr, -- System.Finalization_Root RE_Fore_Decimal32, -- System.Fore_Decimal_32 @@ -1649,9 +1599,7 @@ package Rtsfind is RE_Set_127, -- System.Pack_127 RE_Adjust_Storage_Size, -- System.Parameters - RE_Default_Secondary_Stack_Size, -- System.Parameters RE_Default_Stack_Size, -- System.Parameters - RE_Garbage_Collected, -- System.Parameters RE_Size_Type, -- System.Parameters RE_Unspecified_Size, -- System.Parameters @@ -1677,8 +1625,6 @@ package Rtsfind is RE_Global_Pool_Object, -- System.Pool_Global - RE_Global_Pool_32_Object, -- System.Pool_32_Global - RE_Stack_Bounded_Pool, -- System.Pool_Size RE_Put_Image_Integer, -- System.Put_Images @@ -1744,11 +1690,8 @@ package Rtsfind is RE_Set_Result, -- System.Partition_Interface RE_Register_Obj_Receiving_Stub, -- System.Partition_Interface RE_Register_Pkg_Receiving_Stub, -- System.Partition_Interface - RE_Is_Nil, -- System.Partition_Interface - RE_Entity_Ptr, -- System.Partition_Interface RE_Entity_Of, -- System.Partition_Interface RE_Inc_Usage, -- System.Partition_Interface - RE_Set_Ref, -- System.Partition_Interface RE_Make_Ref, -- System.Partition_Interface RE_Get_Local_Address, -- System.Partition_Interface RE_Get_Reference, -- System.Partition_Interface @@ -1881,8 +1824,6 @@ package Rtsfind is RE_Deallocate_Any_Controlled, -- System.Storage_Pools.Subpools RE_Header_Size_With_Padding, -- System.Storage_Pools.Subpools RE_Root_Storage_Pool_With_Subpools, -- System.Storage_Pools.Subpools - RE_Root_Subpool, -- System.Storage_Pools.Subpools - RE_Subpool_Handle, -- System.Storage_Pools.Subpools RE_I_AD, -- System.Stream_Attributes RE_I_AS, -- System.Stream_Attributes @@ -2006,7 +1947,6 @@ package Rtsfind is RE_Simple_Mode, -- System.Tasking RE_Terminate_Mode, -- System.Tasking RE_Delay_Mode, -- System.Tasking - RE_Entry_Index, -- System.Tasking RE_Task_Entry_Index, -- System.Tasking RE_Self, -- System.Tasking @@ -2244,17 +2184,13 @@ package Rtsfind is RE_Set_Deadline => Ada_Dispatching_EDF, - RE_Code_Loc => Ada_Exceptions, RE_Exception_Id => Ada_Exceptions, - RE_Exception_Identity => Ada_Exceptions, RE_Exception_Information => Ada_Exceptions, RE_Exception_Message => Ada_Exceptions, RE_Exception_Name_Simple => Ada_Exceptions, RE_Exception_Occurrence => Ada_Exceptions, - RE_Exception_Occurrence_Access => Ada_Exceptions, RE_Null_Id => Ada_Exceptions, RE_Null_Occurrence => Ada_Exceptions, - RE_Poll => Ada_Exceptions, RE_Raise_Exception => Ada_Exceptions, RE_Raise_Exception_Always => Ada_Exceptions, RE_Raise_From_Controlled_Operation => Ada_Exceptions, @@ -2295,8 +2231,6 @@ package Rtsfind is RE_Stream_Element_Array => Ada_Streams, RE_Stream_Element_Offset => Ada_Streams, - RE_Stream_Access => Ada_Streams_Stream_IO, - RO_SU_Super_String => Ada_Strings_Superbounded, RO_WI_Super_String => Ada_Strings_Wide_Superbounded, @@ -2311,8 +2245,6 @@ package Rtsfind is RE_Buffer_Type => Ada_Strings_Text_Buffers_Unbounded, RE_Get => Ada_Strings_Text_Buffers_Unbounded, - RE_Wide_Get => Ada_Strings_Text_Buffers_Unbounded, - RE_Wide_Wide_Get => Ada_Strings_Text_Buffers_Unbounded, RE_Wait_For_Release => Ada_Synchronous_Barriers, @@ -2324,7 +2256,6 @@ package Rtsfind is RE_Address_Array => Ada_Tags, RE_Addr_Ptr => Ada_Tags, RE_Base_Address => Ada_Tags, - RE_Check_Interface_Conversion => Ada_Tags, RE_Check_TSD => Ada_Tags, RE_Cstring_Ptr => Ada_Tags, RE_CW_Membership => Ada_Tags, @@ -2339,13 +2270,11 @@ package Rtsfind is RE_External_Tag => Ada_Tags, RO_TA_External_Tag => Ada_Tags, RE_Get_Access_Level => Ada_Tags, - RE_Get_Alignment => Ada_Tags, RE_Get_Entry_Index => Ada_Tags, RE_Get_Offset_Index => Ada_Tags, RE_Get_Prim_Op_Kind => Ada_Tags, RE_Get_Tagged_Kind => Ada_Tags, RE_HT_Link => Ada_Tags, - RE_Idepth => Ada_Tags, RE_Interfaces_Array => Ada_Tags, RE_Interfaces_Table => Ada_Tags, RE_Interface_Data => Ada_Tags, @@ -2358,8 +2287,6 @@ package Rtsfind is RE_No_Dispatch_Table_Wrapper => Ada_Tags, RE_No_Tag => Ada_Tags, RE_NDT_Prims_Ptr => Ada_Tags, - RE_NDT_TSD => Ada_Tags, - RE_Num_Prims => Ada_Tags, RE_Object_Specific_Data => Ada_Tags, RE_Offset_To_Top => Ada_Tags, RE_Offset_To_Top_Ptr => Ada_Tags, @@ -2382,11 +2309,9 @@ package Rtsfind is RE_Primary_DT => Ada_Tags, RE_Signature => Ada_Tags, RE_SSD => Ada_Tags, - RE_TSD => Ada_Tags, RE_Type_Specific_Data => Ada_Tags, RE_Register_Interface_Offset => Ada_Tags, RE_Register_Tag => Ada_Tags, - RE_Register_TSD => Ada_Tags, RE_Transportable => Ada_Tags, RE_Secondary_DT => Ada_Tags, RE_Secondary_Tag => Ada_Tags, @@ -2432,7 +2357,6 @@ package Rtsfind is RE_Stream_T => CUDA_Driver_Types, - RE_Fatbin_Wrapper => CUDA_Internal, RE_Launch_Kernel => CUDA_Internal, RE_Pop_Call_Configuration => CUDA_Internal, RE_Push_Call_Configuration => CUDA_Internal, @@ -2455,19 +2379,14 @@ package Rtsfind is RO_IC_Unsigned => Interfaces_C, - RE_Chars_Ptr => Interfaces_C_Strings, - RE_New_Char_Array => Interfaces_C_Strings, - RE_Address => System, RE_Any_Priority => System, RE_Bit_Order => System, RE_Default_Priority => System, RE_High_Order_First => System, RE_Interrupt_Priority => System, - RE_Lib_Stop => System, RE_Low_Order_First => System, RE_Max_Base_Digits => System, - RE_Max_Priority => System, RE_Null_Address => System, RE_Priority => System, @@ -2485,8 +2404,6 @@ package Rtsfind is RE_Subtract_With_Ovflo_Check128 => System_Arith_128, RE_Scaled_Divide128 => System_Arith_128, - RE_Create_AST_Handler => System_AST_Handling, - RE_Assert_Failure => System_Assertions, RE_Raise_Assert_Failure => System_Assertions, @@ -2507,9 +2424,6 @@ package Rtsfind is RE_Atomic_Test_And_Set => System_Atomic_Operations_Test_And_Set, RE_AST_Handler => System_Aux_DEC, - RE_Import_Address => System_Aux_DEC, - RE_Import_Value => System_Aux_DEC, - RE_No_AST_Handler => System_Aux_DEC, RE_Type_Class => System_Aux_DEC, RE_Type_Class_Enumeration => System_Aux_DEC, RE_Type_Class_Integer => System_Aux_DEC, @@ -2643,15 +2557,6 @@ package Rtsfind is RE_Attr_Long_Long_Float => System_Fat_LLF, - RE_Attr_VAX_D_Float => System_Fat_VAX_D_Float, - RE_Fat_VAX_D => System_Fat_VAX_D_Float, - - RE_Attr_VAX_F_Float => System_Fat_VAX_F_Float, - RE_Fat_VAX_F => System_Fat_VAX_F_Float, - - RE_Attr_VAX_G_Float => System_Fat_VAX_G_Float, - RE_Fat_VAX_G => System_Fat_VAX_G_Float, - RE_Add_Offset_To_Address => System_Finalization_Masters, RE_Attach => System_Finalization_Masters, RE_Base_Pool => System_Finalization_Masters, @@ -2659,10 +2564,8 @@ package Rtsfind is RE_Finalization_Master_Ptr => System_Finalization_Masters, RE_Set_Base_Pool => System_Finalization_Masters, RE_Set_Finalize_Address => System_Finalization_Masters, - RE_Set_Is_Heterogeneous => System_Finalization_Masters, RE_Root_Controlled => System_Finalization_Root, - RE_Root_Controlled_Ptr => System_Finalization_Root, RE_Fore_Decimal32 => System_Fore_Decimal_32, @@ -3340,9 +3243,7 @@ package Rtsfind is RE_Set_127 => System_Pack_127, RE_Adjust_Storage_Size => System_Parameters, - RE_Default_Secondary_Stack_Size => System_Parameters, RE_Default_Stack_Size => System_Parameters, - RE_Garbage_Collected => System_Parameters, RE_Size_Type => System_Parameters, RE_Unspecified_Size => System_Parameters, @@ -3399,11 +3300,8 @@ package Rtsfind is RE_Set_Result => System_Partition_Interface, RE_Register_Obj_Receiving_Stub => System_Partition_Interface, RE_Register_Pkg_Receiving_Stub => System_Partition_Interface, - RE_Is_Nil => System_Partition_Interface, - RE_Entity_Ptr => System_Partition_Interface, RE_Entity_Of => System_Partition_Interface, RE_Inc_Usage => System_Partition_Interface, - RE_Set_Ref => System_Partition_Interface, RE_Make_Ref => System_Partition_Interface, RE_Get_Local_Address => System_Partition_Interface, RE_Get_Reference => System_Partition_Interface, @@ -3488,8 +3386,6 @@ package Rtsfind is RE_Global_Pool_Object => System_Pool_Global, - RE_Global_Pool_32_Object => System_Pool_32_Global, - RE_Stack_Bounded_Pool => System_Pool_Size, RE_Put_Image_Integer => System_Put_Images, @@ -3572,8 +3468,6 @@ package Rtsfind is RE_Deallocate_Any_Controlled => System_Storage_Pools_Subpools, RE_Header_Size_With_Padding => System_Storage_Pools_Subpools, RE_Root_Storage_Pool_With_Subpools => System_Storage_Pools_Subpools, - RE_Root_Subpool => System_Storage_Pools_Subpools, - RE_Subpool_Handle => System_Storage_Pools_Subpools, RE_I_AD => System_Stream_Attributes, RE_I_AS => System_Stream_Attributes, @@ -3697,7 +3591,6 @@ package Rtsfind is RE_Simple_Mode => System_Tasking, RE_Terminate_Mode => System_Tasking, RE_Delay_Mode => System_Tasking, - RE_Entry_Index => System_Tasking, RE_Task_Entry_Index => System_Tasking, RE_Self => System_Tasking, -- cgit v1.1 From a490e7da3ad435d72916564e166f966eabe7328f Mon Sep 17 00:00:00 2001 From: Piotr Trojanek Date: Wed, 14 Sep 2022 21:59:05 +0200 Subject: ada: Fix location of pragmas coming from aspects in top-level instances This patch fixes an AST anomaly where pragmas that correspond to aspects of a generic package declaration appeared as the auxiliary declarations of the compilation unit for the instantiated package body. In particular, this anomaly happened for aspect Annotate and affected GNATprove, which didn't pick pragma corresponding to this aspect. gcc/ada/ * 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. --- gcc/ada/sem_ch12.adb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/sem_ch12.adb b/gcc/ada/sem_ch12.adb index 9525140..ab2e182 100644 --- a/gcc/ada/sem_ch12.adb +++ b/gcc/ada/sem_ch12.adb @@ -6296,13 +6296,16 @@ package body Sem_Ch12 is Old_Main : constant Entity_Id := Cunit_Entity (Main_Unit); begin - -- A new compilation unit node is built for the instance declaration + -- A new compilation unit node is built for the instance declaration. + -- It relocates the auxiliary declaration node from the compilation unit + -- where the instance appeared, so that declarations that originally + -- followed the instance will be attached to the spec compilation unit. Decl_Cunit := Make_Compilation_Unit (Sloc (N), Context_Items => Empty_List, Unit => Act_Decl, - Aux_Decls_Node => Make_Compilation_Unit_Aux (Sloc (N))); + Aux_Decls_Node => Relocate_Node (Aux_Decls_Node (Parent (N)))); Set_Parent_Spec (Act_Decl, Parent_Spec (N)); -- cgit v1.1 From 3a2ae0520895b53ec2c5533c274b47bec33753ec Mon Sep 17 00:00:00 2001 From: Ghjuvan Lacambre Date: Fri, 9 Sep 2022 14:44:03 +0200 Subject: ada: Doc: rename Valid_Image to Valid_Value This renaming happened some time ago in the code, but the documentation was not updated. gcc/ada/ * doc/gnat_rm/implementation_defined_attributes.rst: Rename Valid_Image. * gnat_rm.texi: Regenerate. * gnat_ugn.texi: Regenerate. --- .../gnat_rm/implementation_defined_attributes.rst | 8 ++++---- gcc/ada/gnat_rm.texi | 22 +++++++++++----------- gcc/ada/gnat_ugn.texi | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/doc/gnat_rm/implementation_defined_attributes.rst b/gcc/ada/doc/gnat_rm/implementation_defined_attributes.rst index c25e3d4..d839b1f 100644 --- a/gcc/ada/doc/gnat_rm/implementation_defined_attributes.rst +++ b/gcc/ada/doc/gnat_rm/implementation_defined_attributes.rst @@ -1623,13 +1623,13 @@ Multi-dimensional arrays can be modified, as shown by this example: which changes element (1,2) to 20 and (3,4) to 30. -Attribute Valid_Image +Attribute Valid_Value ======================= -.. index:: Valid_Image +.. index:: Valid_Value -The ``'Valid_Image`` attribute is defined for enumeration types other than +The ``'Valid_Value`` attribute is defined for enumeration types other than those in package Standard. This attribute is a function that takes -a String, and returns Boolean. ``T'Valid_Image (S)`` returns True +a String, and returns Boolean. ``T'Valid_Value (S)`` returns True if and only if ``T'Value (S)`` would not raise Constraint_Error. Attribute Valid_Scalars diff --git a/gcc/ada/gnat_rm.texi b/gcc/ada/gnat_rm.texi index cdf8605..64f2e79 100644 --- a/gcc/ada/gnat_rm.texi +++ b/gcc/ada/gnat_rm.texi @@ -19,7 +19,7 @@ @copying @quotation -GNAT Reference Manual , Sep 09, 2022 +GNAT Reference Manual , Sep 23, 2022 AdaCore @@ -433,7 +433,7 @@ Implementation Defined Attributes * Attribute Universal_Literal_String:: * Attribute Unrestricted_Access:: * Attribute Update:: -* Attribute Valid_Image:: +* Attribute Valid_Value:: * Attribute Valid_Scalars:: * Attribute VADS_Size:: * Attribute Value_Size:: @@ -10295,7 +10295,7 @@ consideration, you should minimize the use of these attributes. * Attribute Universal_Literal_String:: * Attribute Unrestricted_Access:: * Attribute Update:: -* Attribute Valid_Image:: +* Attribute Valid_Value:: * Attribute Valid_Scalars:: * Attribute VADS_Size:: * Attribute Value_Size:: @@ -12040,7 +12040,7 @@ In general this is a risky approach. It may appear to “work” but such uses o @code{Unrestricted_Access} are potentially non-portable, even from one version of GNAT to another, so are best avoided if possible. -@node Attribute Update,Attribute Valid_Image,Attribute Unrestricted_Access,Implementation Defined Attributes +@node Attribute Update,Attribute Valid_Value,Attribute Unrestricted_Access,Implementation Defined Attributes @anchor{gnat_rm/implementation_defined_attributes attribute-update}@anchor{1ac} @section Attribute Update @@ -12121,19 +12121,19 @@ A := A'Update ((1, 2) => 20, (3, 4) => 30); which changes element (1,2) to 20 and (3,4) to 30. -@node Attribute Valid_Image,Attribute Valid_Scalars,Attribute Update,Implementation Defined Attributes -@anchor{gnat_rm/implementation_defined_attributes attribute-valid-image}@anchor{1ad} -@section Attribute Valid_Image +@node Attribute Valid_Value,Attribute Valid_Scalars,Attribute Update,Implementation Defined Attributes +@anchor{gnat_rm/implementation_defined_attributes attribute-valid-value}@anchor{1ad} +@section Attribute Valid_Value -@geindex Valid_Image +@geindex Valid_Value -The @code{'Valid_Image} attribute is defined for enumeration types other than +The @code{'Valid_Value} attribute is defined for enumeration types other than those in package Standard. This attribute is a function that takes -a String, and returns Boolean. @code{T'Valid_Image (S)} returns True +a String, and returns Boolean. @code{T'Valid_Value (S)} returns True if and only if @code{T'Value (S)} would not raise Constraint_Error. -@node Attribute Valid_Scalars,Attribute VADS_Size,Attribute Valid_Image,Implementation Defined Attributes +@node Attribute Valid_Scalars,Attribute VADS_Size,Attribute Valid_Value,Implementation Defined Attributes @anchor{gnat_rm/implementation_defined_attributes attribute-valid-scalars}@anchor{1ae} @section Attribute Valid_Scalars diff --git a/gcc/ada/gnat_ugn.texi b/gcc/ada/gnat_ugn.texi index 77d239f..7d96dbe 100644 --- a/gcc/ada/gnat_ugn.texi +++ b/gcc/ada/gnat_ugn.texi @@ -29319,8 +29319,8 @@ to permit their use in free software. @printindex ge -@anchor{cf}@w{ } @anchor{gnat_ugn/gnat_utility_programs switches-related-to-project-files}@w{ } +@anchor{cf}@w{ } @c %**end of body @bye -- cgit v1.1 From c33e12fa479c01848f4a288883bf1ef848c94ca3 Mon Sep 17 00:00:00 2001 From: Kyrylo Tkachov Date: Mon, 26 Sep 2022 10:10:25 +0100 Subject: aarch64: Add -march support for Armv9.1-A, Armv9.2-A, Armv9.3-A This is a straightforward patch that allows targeting the architecture revisions mentioned in the subject through -march. These are already supported in binutils. Bootstrapped and tested on aarch64-none-linux-gnu. gcc/ChangeLog: * 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. --- gcc/config/aarch64/aarch64-arches.def | 3 +++ gcc/config/aarch64/aarch64.h | 18 ++++++++++++++++++ gcc/doc/invoke.texi | 3 +++ 3 files changed, 24 insertions(+) (limited to 'gcc') diff --git a/gcc/config/aarch64/aarch64-arches.def b/gcc/config/aarch64/aarch64-arches.def index 3c2b165..6150448 100644 --- a/gcc/config/aarch64/aarch64-arches.def +++ b/gcc/config/aarch64/aarch64-arches.def @@ -41,5 +41,8 @@ AARCH64_ARCH("armv8.7-a", generic, 8_7A, 8, AARCH64_FL_FOR_ARCH8 AARCH64_ARCH("armv8.8-a", generic, 8_8A, 8, AARCH64_FL_FOR_ARCH8_8) AARCH64_ARCH("armv8-r", generic, 8R , 8, AARCH64_FL_FOR_ARCH8_R) AARCH64_ARCH("armv9-a", generic, 9A , 9, AARCH64_FL_FOR_ARCH9) +AARCH64_ARCH("armv9.1-a", generic, 9_1A, 9, AARCH64_FL_FOR_ARCH9_1) +AARCH64_ARCH("armv9.2-a", generic, 9_2A, 9, AARCH64_FL_FOR_ARCH9_2) +AARCH64_ARCH("armv9.3-a", generic, 9_3A, 9, AARCH64_FL_FOR_ARCH9_3) #undef AARCH64_ARCH diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h index 6f6bb70..f790de1 100644 --- a/gcc/config/aarch64/aarch64.h +++ b/gcc/config/aarch64/aarch64.h @@ -239,6 +239,15 @@ /* Armv8.8-a architecture extensions. */ #define AARCH64_FL_V8_8 (1ULL << 45) +/* Armv9.1-A. */ +#define AARCH64_FL_V9_1 (1ULL << 46) + +/* Armv9.2-A. */ +#define AARCH64_FL_V9_2 (1ULL << 47) + +/* Armv9.3-A. */ +#define AARCH64_FL_V9_3 (1ULL << 48) + /* Has FP and SIMD. */ #define AARCH64_FL_FPSIMD (AARCH64_FL_FP | AARCH64_FL_SIMD) @@ -273,6 +282,12 @@ #define AARCH64_FL_FOR_ARCH9 \ (AARCH64_FL_FOR_ARCH8_5 | AARCH64_FL_SVE | AARCH64_FL_SVE2 | AARCH64_FL_V9 \ | AARCH64_FL_F16) +#define AARCH64_FL_FOR_ARCH9_1 \ + (AARCH64_FL_FOR_ARCH9 | AARCH64_FL_FOR_ARCH8_6 | AARCH64_FL_V9_1) +#define AARCH64_FL_FOR_ARCH9_2 \ + (AARCH64_FL_FOR_ARCH9_1 | AARCH64_FL_FOR_ARCH8_7 | AARCH64_FL_V9_2) +#define AARCH64_FL_FOR_ARCH9_3 \ + (AARCH64_FL_FOR_ARCH9_2 | AARCH64_FL_FOR_ARCH8_8 | AARCH64_FL_V9_3) /* Macros to test ISA flags. */ @@ -312,6 +327,9 @@ #define AARCH64_ISA_V8_R (aarch64_isa_flags & AARCH64_FL_V8_R) #define AARCH64_ISA_PAUTH (aarch64_isa_flags & AARCH64_FL_PAUTH) #define AARCH64_ISA_V9 (aarch64_isa_flags & AARCH64_FL_V9) +#define AARCH64_ISA_V9_1 (aarch64_isa_flags & AARCH64_FL_V9_1) +#define AARCH64_ISA_V9_2 (aarch64_isa_flags & AARCH64_FL_V9_2) +#define AARCH64_ISA_V9_3 (aarch64_isa_flags & AARCH64_FL_V9_3) #define AARCH64_ISA_MOPS (aarch64_isa_flags & AARCH64_FL_MOPS) #define AARCH64_ISA_LS64 (aarch64_isa_flags & AARCH64_FL_LS64) diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 928ab0f..19275c5 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -19681,6 +19681,9 @@ and the features that they enable by default: @item @samp{armv8.7-a} @tab Armv8.7-A @tab @samp{armv8.6-a}, @samp{+ls64} @item @samp{armv8.8-a} @tab Armv8.8-a @tab @samp{armv8.7-a}, @samp{+mops} @item @samp{armv9-a} @tab Armv9-A @tab @samp{armv8.5-a}, @samp{+sve}, @samp{+sve2} +@item @samp{armv9.1-a} @tab Armv9.1-A @tab @samp{armv9-a}, @samp{+bf16}, @samp{+i8mm} +@item @samp{armv9.2-a} @tab Armv9.2-A @tab @samp{armv9.1-a}, @samp{+ls64} +@item @samp{armv9.3-a} @tab Armv9.3-A @tab @samp{armv9.2-a}, @samp{+mops} @item @samp{armv8-r} @tab Armv8-R @tab @samp{armv8-r} @end multitable -- cgit v1.1 From 2387cfc7f6e2065f5c040d62763f6f3a5997a444 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Mon, 26 Sep 2022 12:06:48 +0200 Subject: s390: fix wrong refactoring Since r13-2251-g1930c5d05ceff2, the refactoring is not 1:1 and we end up with a wrong rtx type. gcc/ChangeLog: * config/s390/s390.cc (s390_rtx_costs): Remove dest variable and use only dst. --- gcc/config/s390/s390.cc | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'gcc') diff --git a/gcc/config/s390/s390.cc b/gcc/config/s390/s390.cc index 3ae586c..9861913 100644 --- a/gcc/config/s390/s390.cc +++ b/gcc/config/s390/s390.cc @@ -3648,7 +3648,7 @@ s390_rtx_costs (rtx x, machine_mode mode, int outer_code, *total = 0; return true; case SET: { - rtx dest = SET_DEST (x); + rtx dst = SET_DEST (x); rtx src = SET_SRC (x); switch (GET_CODE (src)) @@ -3669,7 +3669,6 @@ s390_rtx_costs (rtx x, machine_mode mode, int outer_code, slightly more expensive than a normal load. */ *total = COSTS_N_INSNS (1) + 2; - rtx dst = SET_DEST (src); rtx then = XEXP (src, 1); rtx els = XEXP (src, 2); @@ -3696,25 +3695,25 @@ s390_rtx_costs (rtx x, machine_mode mode, int outer_code, break; } - switch (GET_CODE (dest)) + switch (GET_CODE (dst)) { case SUBREG: - if (!REG_P (SUBREG_REG (dest))) + if (!REG_P (SUBREG_REG (dst))) *total += rtx_cost (SUBREG_REG (src), VOIDmode, SET, 0, speed); /* fallthrough */ case REG: /* If this is a VR -> VR copy, count the number of registers. */ - if (VECTOR_MODE_P (GET_MODE (dest)) && REG_P (src)) + if (VECTOR_MODE_P (GET_MODE (dst)) && REG_P (src)) { - int nregs = s390_hard_regno_nregs (VR0_REGNUM, GET_MODE (dest)); + int nregs = s390_hard_regno_nregs (VR0_REGNUM, GET_MODE (dst)); *total = COSTS_N_INSNS (nregs); } /* Same for GPRs. */ else if (REG_P (src)) { int nregs - = s390_hard_regno_nregs (GPR0_REGNUM, GET_MODE (dest)); + = s390_hard_regno_nregs (GPR0_REGNUM, GET_MODE (dst)); *total = COSTS_N_INSNS (nregs); } else @@ -3722,7 +3721,7 @@ s390_rtx_costs (rtx x, machine_mode mode, int outer_code, *total += rtx_cost (src, mode, SET, 1, speed); return true; case MEM: { - rtx address = XEXP (dest, 0); + rtx address = XEXP (dst, 0); rtx tmp; HOST_WIDE_INT tmp2; if (s390_loadrelative_operand_p (address, &tmp, &tmp2)) -- cgit v1.1 From d3df98807b58df186061ad52ff87cc09ba593e9b Mon Sep 17 00:00:00 2001 From: Tobias Burnus Date: Mon, 26 Sep 2022 12:45:28 +0200 Subject: OpenACC: Fix reduction tree-sharing issue [PR106982] The tree for var == incoming == outgound was 'MEM [(double *)&reduced]' which caused the ICE "incorrect sharing of tree nodes". PR middle-end/106982 gcc/ChangeLog: * omp-low.cc (lower_oacc_reductions): Add some unshare_expr. gcc/testsuite/ChangeLog: * c-c++-common/goacc/reduction-7.c: New test. * c-c++-common/goacc/reduction-8.c: New test. --- gcc/omp-low.cc | 19 +++++++++++-------- gcc/testsuite/c-c++-common/goacc/reduction-7.c | 22 ++++++++++++++++++++++ gcc/testsuite/c-c++-common/goacc/reduction-8.c | 12 ++++++++++++ 3 files changed, 45 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/goacc/reduction-7.c create mode 100644 gcc/testsuite/c-c++-common/goacc/reduction-8.c (limited to 'gcc') diff --git a/gcc/omp-low.cc b/gcc/omp-low.cc index d9f9aae..dc42c75 100644 --- a/gcc/omp-low.cc +++ b/gcc/omp-low.cc @@ -7631,6 +7631,7 @@ lower_oacc_reductions (location_t loc, tree clauses, tree level, bool inner, incoming = build_simple_mem_ref (incoming); } else + /* Note that 'var' might be a mem ref. */ v1 = v2 = v3 = var; /* Determine position in reduction buffer, which may be used @@ -7659,26 +7660,28 @@ lower_oacc_reductions (location_t loc, tree clauses, tree level, bool inner, = build_call_expr_internal_loc (loc, IFN_GOACC_REDUCTION, TREE_TYPE (var), 6, setup_code, unshare_expr (ref_to_res), - incoming, level, op, off); + unshare_expr (incoming), + level, op, off); tree init_call = build_call_expr_internal_loc (loc, IFN_GOACC_REDUCTION, TREE_TYPE (var), 6, init_code, unshare_expr (ref_to_res), - v1, level, op, off); + unshare_expr (v1), level, op, off); tree fini_call = build_call_expr_internal_loc (loc, IFN_GOACC_REDUCTION, TREE_TYPE (var), 6, fini_code, unshare_expr (ref_to_res), - v2, level, op, off); + unshare_expr (v2), level, op, off); tree teardown_call = build_call_expr_internal_loc (loc, IFN_GOACC_REDUCTION, TREE_TYPE (var), 6, teardown_code, - ref_to_res, v3, level, op, off); + ref_to_res, unshare_expr (v3), + level, op, off); - gimplify_assign (v1, setup_call, &before_fork); - gimplify_assign (v2, init_call, &after_fork); - gimplify_assign (v3, fini_call, &before_join); - gimplify_assign (outgoing, teardown_call, &after_join); + gimplify_assign (unshare_expr (v1), setup_call, &before_fork); + gimplify_assign (unshare_expr (v2), init_call, &after_fork); + gimplify_assign (unshare_expr (v3), fini_call, &before_join); + gimplify_assign (unshare_expr (outgoing), teardown_call, &after_join); } /* Now stitch things together. */ diff --git a/gcc/testsuite/c-c++-common/goacc/reduction-7.c b/gcc/testsuite/c-c++-common/goacc/reduction-7.c new file mode 100644 index 0000000..482b0ab --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/reduction-7.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ + +/* PR middle-end/106982 */ + +long long n = 100; +int multiplicitive_n = 128; + +void test1(double *rand, double *a, double *b, double *c) +{ +#pragma acc data copyin(a[0:10*multiplicitive_n], b[0:10*multiplicitive_n]) copyout(c[0:10]) + { +#pragma acc parallel loop + for (int i = 0; i < 10; ++i) + { + double temp = 1.0; +#pragma acc loop vector reduction(*:temp) + for (int j = 0; j < multiplicitive_n; ++j) + temp *= a[(i * multiplicitive_n) + j] + b[(i * multiplicitive_n) + j]; + c[i] = temp; + } + } +} diff --git a/gcc/testsuite/c-c++-common/goacc/reduction-8.c b/gcc/testsuite/c-c++-common/goacc/reduction-8.c new file mode 100644 index 0000000..2c3ed49 --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/reduction-8.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ + +/* PR middle-end/106982 */ + +void test1(double *c) +{ + double reduced[5]; +#pragma acc parallel loop gang private(reduced) + for (int x = 0; x < 5; ++x) +#pragma acc loop worker reduction(*:reduced) + for (int y = 0; y < 5; ++y) { } +} -- cgit v1.1 From 1b74b5cb4e9d7191f298245063a8f9c3a1bbeff4 Mon Sep 17 00:00:00 2001 From: Jeff Law Date: Sun, 25 Sep 2022 12:23:59 -0400 Subject: [RFA] Minor improvement to coremark, avoid unconditional jump to return gcc/ * 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. gcc/testsuite/ * gcc.target/riscv/ret-1.c: New test. --- gcc/cfgcleanup.cc | 2 +- gcc/cfgcleanup.h | 1 + gcc/cfgrtl.cc | 29 +++++++++++++++++++++++- gcc/testsuite/gcc.target/riscv/ret-1.c | 41 ++++++++++++++++++++++++++++++++++ 4 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gcc.target/riscv/ret-1.c (limited to 'gcc') diff --git a/gcc/cfgcleanup.cc b/gcc/cfgcleanup.cc index a8b0139..a363e0b 100644 --- a/gcc/cfgcleanup.cc +++ b/gcc/cfgcleanup.cc @@ -2599,7 +2599,7 @@ trivially_empty_bb_p (basic_block bb) return value. Fill in *RET and *USE with the return and use insns if any found, otherwise NULL. All CLOBBERs are ignored. */ -static bool +bool bb_is_just_return (basic_block bb, rtx_insn **ret, rtx_insn **use) { *ret = *use = NULL; diff --git a/gcc/cfgcleanup.h b/gcc/cfgcleanup.h index a6d882f..f1021ca 100644 --- a/gcc/cfgcleanup.h +++ b/gcc/cfgcleanup.h @@ -30,5 +30,6 @@ extern int flow_find_head_matching_sequence (basic_block, basic_block, extern bool delete_unreachable_blocks (void); extern void delete_dead_jumptables (void); extern bool cleanup_cfg (int); +extern bool bb_is_just_return (basic_block, rtx_insn **, rtx_insn **); #endif /* GCC_CFGCLEANUP_H */ diff --git a/gcc/cfgrtl.cc b/gcc/cfgrtl.cc index a05c338..90cd6ee 100644 --- a/gcc/cfgrtl.cc +++ b/gcc/cfgrtl.cc @@ -3901,6 +3901,7 @@ fixup_reorder_chain (void) /* Now add jumps and labels as needed to match the blocks new outgoing edges. */ + bool remove_unreachable_blocks = false; for (bb = ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb; bb ; bb = (basic_block) bb->aux) { @@ -4043,10 +4044,30 @@ fixup_reorder_chain (void) continue; } + /* If E_FALL->dest is just a return block, then we can emit a + return rather than a jump to the return block. */ + rtx_insn *ret, *use; + basic_block dest; + if (bb_is_just_return (e_fall->dest, &ret, &use) + && (PATTERN (ret) == simple_return_rtx || PATTERN (ret) == ret_rtx)) + { + ret_label = PATTERN (ret); + dest = EXIT_BLOCK_PTR_FOR_FN (cfun); + + /* E_FALL->dest might become unreachable as a result of + replacing the jump with a return. So arrange to remove + unreachable blocks. */ + remove_unreachable_blocks = true; + } + else + { + dest = e_fall->dest; + } + /* We got here if we need to add a new jump insn. Note force_nonfallthru can delete E_FALL and thus we have to save E_FALL->src prior to the call to force_nonfallthru. */ - nb = force_nonfallthru_and_redirect (e_fall, e_fall->dest, ret_label); + nb = force_nonfallthru_and_redirect (e_fall, dest, ret_label); if (nb) { nb->aux = bb->aux; @@ -4134,6 +4155,12 @@ fixup_reorder_chain (void) ei_next (&ei2); } } + + /* Replacing a jump with a return may have exposed an unreachable + block. Conditionally remove them if such transformations were + made. */ + if (remove_unreachable_blocks) + delete_unreachable_blocks (); } /* Perform sanity checks on the insn chain. diff --git a/gcc/testsuite/gcc.target/riscv/ret-1.c b/gcc/testsuite/gcc.target/riscv/ret-1.c new file mode 100644 index 0000000..28133aa --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/ret-1.c @@ -0,0 +1,41 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -dp" } */ +/* This was extracted from coremark. */ + + +typedef signed short ee_s16; +typedef struct list_data_s +{ + ee_s16 data16; + ee_s16 idx; +} list_data; + +typedef struct list_head_s +{ + struct list_head_s *next; + struct list_data_s *info; +} list_head; + + +list_head * +core_list_find(list_head *list, list_data *info) +{ + if (info->idx >= 0) + { + while (list && (list->info->idx != info->idx)) + list = list->next; + return list; + } + else + { + while (list && ((list->info->data16 & 0xff) != info->data16)) + list = list->next; + return list; + } +} + +/* There is only one legitimate unconditional jump, so test for that, + which will catch the case where bb-reorder leaves a jump to a ret + in the IL. */ +/* { dg-final { scan-assembler-times "jump" 1 } } */ + -- cgit v1.1 From 84072a2615ec1f5f35e994128a6dc22af5bf1322 Mon Sep 17 00:00:00 2001 From: Thomas Schwinge Date: Sun, 29 May 2022 22:31:43 +0200 Subject: nvptx: forward '-v' command-line option to assembler For example, for offloading compilation with '-save-temps -v', before vs. after word-diff then looks like: [...] [...]/build-gcc-offload-nvptx-none/gcc/as {+-v -v+} -o ./a.xnvptx-none.mkoffload.o ./a.xnvptx-none.mkoffload.s {+Verifying sm_30 code with sm_35 code generation.+} {+ ptxas -c -o /dev/null ./a.xnvptx-none.mkoffload.o --gpu-name sm_35 -O0+} [...] (This depends on "Put '-v' verbose output onto stderr instead of stdout".) gcc/ * config/nvptx/nvptx.h (ASM_SPEC): Define. --- gcc/config/nvptx/nvptx.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'gcc') diff --git a/gcc/config/nvptx/nvptx.h b/gcc/config/nvptx/nvptx.h index dc9cad1..0b0170d 100644 --- a/gcc/config/nvptx/nvptx.h +++ b/gcc/config/nvptx/nvptx.h @@ -27,6 +27,10 @@ /* Run-time Target. */ +/* Assembler supports '-v' option; handle similar to + '../../gcc.cc:asm_options', 'HAVE_GNU_AS'. */ +#define ASM_SPEC "%{v}" + #define STARTFILE_SPEC "%{mmainkernel:crt0.o}" #define TARGET_CPU_CPP_BUILTINS() nvptx_cpu_cpp_builtins () -- cgit v1.1 From 108b99b6c45ed8fbad6776539a639244b63191f5 Mon Sep 17 00:00:00 2001 From: Thomas Schwinge Date: Sat, 11 Jun 2022 12:28:36 +0200 Subject: nvptx: Make default '-misa=sm_30' explicit ... primarily in preparation for later changes. gcc/ * 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'. --- gcc/config.gcc | 16 ++++++++++++++++ gcc/config/nvptx/nvptx.cc | 4 ++++ gcc/config/nvptx/nvptx.h | 4 ++++ gcc/config/nvptx/nvptx.opt | 2 +- 4 files changed, 25 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/config.gcc b/gcc/config.gcc index 27ffce3..6a47661 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -3941,6 +3941,9 @@ if test x$with_arch = x ; then mips*-*-vxworks) with_arch=mips2 ;; + nvptx-*) + with_arch=sm_30 + ;; esac # Avoid overriding --with-arch-32 and --with-arch-64 values. @@ -5293,6 +5296,19 @@ case "${target}" in esac ;; + nvptx-*) + supported_defaults=arch + case $with_arch in + sm_30 ) + # OK; default. + ;; + * ) + echo "Unknown arch used in --with-arch=$with_arch" 1>&2 + exit 1 + ;; + esac + ;; + powerpc*-*-* | rs6000-*-*) supported_defaults="abi cpu cpu_32 cpu_64 float tune tune_32 tune_64 advance_toolchain" diff --git a/gcc/config/nvptx/nvptx.cc b/gcc/config/nvptx/nvptx.cc index 49cc681..2fe120b 100644 --- a/gcc/config/nvptx/nvptx.cc +++ b/gcc/config/nvptx/nvptx.cc @@ -334,6 +334,10 @@ nvptx_option_override (void) { init_machine_status = nvptx_init_machine_status; + /* Via nvptx 'OPTION_DEFAULT_SPECS', '-misa' always appears on the command + line. */ + gcc_checking_assert (OPTION_SET_P (ptx_isa_option)); + handle_ptx_version_option (); /* Set toplevel_reorder, unless explicitly disabled. We need diff --git a/gcc/config/nvptx/nvptx.h b/gcc/config/nvptx/nvptx.h index 0b0170d..0afc83b 100644 --- a/gcc/config/nvptx/nvptx.h +++ b/gcc/config/nvptx/nvptx.h @@ -27,6 +27,10 @@ /* Run-time Target. */ +/* Use '--with-arch' for default '-misa'. */ +#define OPTION_DEFAULT_SPECS \ + { "arch", "%{!misa=*:-misa=%(VALUE)}" }, \ + /* Assembler supports '-v' option; handle similar to '../../gcc.cc:asm_options', 'HAVE_GNU_AS'. */ #define ASM_SPEC "%{v}" diff --git a/gcc/config/nvptx/nvptx.opt b/gcc/config/nvptx/nvptx.opt index c5a5668..71d3b68 100644 --- a/gcc/config/nvptx/nvptx.opt +++ b/gcc/config/nvptx/nvptx.opt @@ -53,7 +53,7 @@ Target Mask(GOMP) Generate code for OpenMP offloading: enables -msoft-stack and -muniform-simt. misa= -Target RejectNegative ToLower Joined Enum(ptx_isa) Var(ptx_isa_option) Init(PTX_ISA_SM30) +Target RejectNegative ToLower Joined Enum(ptx_isa) Var(ptx_isa_option) Specify the PTX ISA target architecture to use. march= -- cgit v1.1 From 4d94582e0dcbf5fed9d61213715bfff877bf5ecf Mon Sep 17 00:00:00 2001 From: Thomas Schwinge Date: Sat, 11 Jun 2022 12:28:36 +0200 Subject: nvptx: Introduce dummy multilib option for default '-misa=sm_30' ... primarily in preparation for later changes. gcc/ * config.gcc (TM_MULTILIB_CONFIG) [nvptx]: Set to '$with_arch'. * config/nvptx/t-nvptx (MULTILIB_OPTIONS, MULTILIB_MATCHES) (MULTILIB_EXCEPTIONS): Handle it. --- gcc/config.gcc | 1 + gcc/config/nvptx/t-nvptx | 20 +++++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/config.gcc b/gcc/config.gcc index 6a47661..d130f49 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -5298,6 +5298,7 @@ case "${target}" in nvptx-*) supported_defaults=arch + TM_MULTILIB_CONFIG=$with_arch case $with_arch in sm_30 ) # OK; default. diff --git a/gcc/config/nvptx/t-nvptx b/gcc/config/nvptx/t-nvptx index 2b68149..c797d57 100644 --- a/gcc/config/nvptx/t-nvptx +++ b/gcc/config/nvptx/t-nvptx @@ -31,4 +31,22 @@ s-nvptx-gen-opt: $(srcdir)/config/nvptx/nvptx-sm.def \ tmp-nvptx-gen.opt $(srcdir)/config/nvptx/nvptx-gen.opt $(STAMP) s-nvptx-gen-opt -MULTILIB_OPTIONS = mgomp mptx=3.1 + +# Multilib setup. + +MULTILIB_OPTIONS = +MULTILIB_MATCHES = +MULTILIB_EXCEPTIONS = + +MULTILIB_OPTIONS += mgomp + +multilib_options_isa_list := $(TM_MULTILIB_CONFIG) +multilib_options_isa_default := $(word 1,$(multilib_options_isa_list)) +# Add the default '-misa' as a multilib option: +MULTILIB_OPTIONS += misa=$(multilib_options_isa_default) +# ..., but don't handle it specially (remap to default): +MULTILIB_MATCHES += .=misa?$(multilib_options_isa_default) +# ..., and don't actually build it: +MULTILIB_EXCEPTIONS += *misa=$(multilib_options_isa_default)* + +MULTILIB_OPTIONS += mptx=3.1 -- cgit v1.1 From e9019085e17554c209ca8531022f116b2d7f94fe Mon Sep 17 00:00:00 2001 From: Thomas Schwinge Date: Sat, 11 Jun 2022 19:37:10 +0200 Subject: nvptx: Allow '--with-arch' to override the default '-misa' gcc/ * 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) : Document this. * doc/invoke.texi (Nvidia PTX Options): Likewise. --- gcc/config.gcc | 5 +++ gcc/config/nvptx/gen-multilib-matches.sh | 60 ++++++++++++++++++++++++++++++++ gcc/config/nvptx/t-nvptx | 21 ++++++++--- gcc/doc/install.texi | 9 +++++ gcc/doc/invoke.texi | 4 ++- 5 files changed, 93 insertions(+), 6 deletions(-) create mode 100755 gcc/config/nvptx/gen-multilib-matches.sh (limited to 'gcc') diff --git a/gcc/config.gcc b/gcc/config.gcc index d130f49..c1b1215 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -5299,10 +5299,15 @@ case "${target}" in nvptx-*) supported_defaults=arch TM_MULTILIB_CONFIG=$with_arch + #TODO 'sm_[...]' list per 'nvptx-sm.def'. case $with_arch in sm_30 ) # OK; default. ;; + sm_35 | sm_53 | sm_70 | sm_75 | sm_80 ) + # OK, but we'd like 'sm_30', too. + TM_MULTILIB_CONFIG="$TM_MULTILIB_CONFIG sm_30" + ;; * ) echo "Unknown arch used in --with-arch=$with_arch" 1>&2 exit 1 diff --git a/gcc/config/nvptx/gen-multilib-matches.sh b/gcc/config/nvptx/gen-multilib-matches.sh new file mode 100755 index 0000000..9a5878e --- /dev/null +++ b/gcc/config/nvptx/gen-multilib-matches.sh @@ -0,0 +1,60 @@ +#!/bin/sh + +# Print nvptx 'MULTILIB_MATCHES' + +# Copyright (C) 2022 Free Software Foundation, Inc. +# +# This file is part of GCC. +# +# GCC is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GCC is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# . + +set -e + +nvptx_sm_def="$1/nvptx-sm.def" +multilib_options_isa_default=$2 +multilib_options_isa_list=$3 + +sms=$(grep ^NVPTX_SM $nvptx_sm_def | sed 's/.*(//;s/,.*//') + +# Every variant in 'sms' has to either be remapped to the default variant +# ('.', which is always built), or does get built as non-default variant +# ('misa=sm_SM'; thus not remapped), or has to be remapped to the "next lower" +# variant that does get built. + +# The "lowest" variant has to be built. +sm_next_lower=INVALID + +for sm in $sms; do + if [ x"sm_$sm" = x"$multilib_options_isa_default" ]; then + sm_map=. + elif expr " $multilib_options_isa_list " : ".* sm_$sm " > /dev/null; then + sm_map= + else + sm_map=$sm_next_lower + fi + + if [ x"$sm_map" = x ]; then + sm_next_lower=$sm + else + # Output format as required for 'MULTILIB_MATCHES'. + if [ x"$sm_map" = x. ]; then + echo ".=misa?sm_$sm" + else + echo "misa?sm_$sm_map=misa?sm_$sm" + fi + + sm_next_lower=$sm_map + fi +done diff --git a/gcc/config/nvptx/t-nvptx b/gcc/config/nvptx/t-nvptx index c797d57..9c5cbda 100644 --- a/gcc/config/nvptx/t-nvptx +++ b/gcc/config/nvptx/t-nvptx @@ -42,11 +42,22 @@ MULTILIB_OPTIONS += mgomp multilib_options_isa_list := $(TM_MULTILIB_CONFIG) multilib_options_isa_default := $(word 1,$(multilib_options_isa_list)) -# Add the default '-misa' as a multilib option: -MULTILIB_OPTIONS += misa=$(multilib_options_isa_default) -# ..., but don't handle it specially (remap to default): -MULTILIB_MATCHES += .=misa?$(multilib_options_isa_default) -# ..., and don't actually build it: +multilib_options_misa_list := $(addprefix misa=,$(multilib_options_isa_list)) +# Add the requested '-misa' variants as a multilib option ('misa=VAR1/misa=VAR2/misa=VAR3' etc.): +empty := +space := $(empty) $(empty) +MULTILIB_OPTIONS += $(subst $(space),/,$(multilib_options_misa_list)) +# ..., and remap '-misa' variants as appropriate: +multilib_matches := $(shell $(srcdir)/config/nvptx/gen-multilib-matches.sh $(srcdir)/config/nvptx $(multilib_options_isa_default) "$(multilib_options_isa_list)") +MULTILIB_MATCHES += $(multilib_matches) +# ..., and don't actually build what's the default '-misa': MULTILIB_EXCEPTIONS += *misa=$(multilib_options_isa_default)* MULTILIB_OPTIONS += mptx=3.1 +# Filter out invalid '-misa'/'-mptx=3.1' combinations; per 'nvptx-sm.def', +# 'nvptx.opt:ptx_version', 'nvptx.cc:first_ptx_version_supporting_sm' +# (that is, '-mptx=3.1' only for sm_30, sm_35 variants): +MULTILIB_EXCEPTIONS += $(foreach misa,$(filter-out %=sm_30 %=sm_35,$(multilib_options_misa_list)),*$(misa)/mptx=3.1) +# ..., and special care has to be taken if '-mptx=3.1' is invalid for the +# default variant: +MULTILIB_EXCEPTIONS += $(if $(filter-out sm_30 sm_35,$(multilib_options_isa_default)),mgomp/mptx=3.1 mptx=3.1) diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi index 7df6345..cc01c69 100644 --- a/gcc/doc/install.texi +++ b/gcc/doc/install.texi @@ -4598,6 +4598,15 @@ the GCC sources. Use the @option{--disable-sjlj-exceptions} and @option{--enable-newlib-io-long-long} options when configuring. +The @option{--with-arch} option may be specified to override the +default value for the @option{-march} option, and to also build +corresponding target libraries. +The default is @option{--with-arch=sm_30}. + +For example, if @option{--with-arch=sm_70} is specified, +@option{-march=sm_30} and @option{-march=sm_70} target libraries are +built, and code generation defaults to @option{-march=sm_70}. + @html
@end html diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 19275c5..d2e4abd 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -28058,7 +28058,9 @@ supported. Generate code for the specified PTX ISA target architecture (e.g.@: @samp{sm_35}). Valid architecture strings are @samp{sm_30}, @samp{sm_35}, @samp{sm_53}, @samp{sm_70}, @samp{sm_75} and -@samp{sm_80}. The default target architecture is sm_30. +@samp{sm_80}. +The default depends on how the compiler has been configured, see +@option{--with-arch}. This option sets the value of the preprocessor macro @code{__PTX_SM__}; for instance, for @samp{sm_35}, it has the value -- cgit v1.1 From 2460f7cdef7ef9c971de79271afc0db73687a272 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Fri, 23 Sep 2022 19:47:33 +0200 Subject: Set ranges from unreachable edges for all known ranges. In the conversion of DOM+evrp to DOM+ranger, we missed that evrp was exporting ranges for unreachable edges for all SSA names for which we have ranges for. Instead we have only been exporting ranges for the SSA name in the final conditional to the BB involving the unreachable edge. This patch adjusts adjusts DOM to iterate over the exports, similarly to what evrp was doing. Note that I also noticed that we don't calculate the nonzero bit mask for op1, when 0 = op1 & MASK. This isn't needed for this PR, since maybe_set_nonzero_bits() is chasing the definition and parsing the bitwise and on its own. However, I'll be adding the functionality for completeness sake, plus we could probably drop the maybe_set_nonzero_bits legacy call entirely. PR tree-optimization/107009 gcc/ChangeLog: * tree-ssa-dom.cc (dom_opt_dom_walker::set_global_ranges_from_unreachable_edges): Iterate over exports. gcc/testsuite/ChangeLog: * gcc.dg/tree-ssa/pr107009.c: New test. --- gcc/testsuite/gcc.dg/tree-ssa/pr107009.c | 15 ++++++++++++++ gcc/tree-ssa-dom.cc | 35 ++++++++++++++++---------------- 2 files changed, 33 insertions(+), 17 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr107009.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr107009.c b/gcc/testsuite/gcc.dg/tree-ssa/pr107009.c new file mode 100644 index 0000000..5010aed --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr107009.c @@ -0,0 +1,15 @@ +// { dg-do compile } +// { dg-options "-O2 -fdump-tree-dom2-alias" } + +typedef __SIZE_TYPE__ size_t; + +void saxpy(size_t n) +{ + if (n == 0 || n % 8 != 0) + __builtin_unreachable(); + + extern void foobar (size_t n); + foobar (n); +} + +// { dg-final { scan-tree-dump "NONZERO.*fff8" "dom2" } } diff --git a/gcc/tree-ssa-dom.cc b/gcc/tree-ssa-dom.cc index 513e0c8..84bef79 100644 --- a/gcc/tree-ssa-dom.cc +++ b/gcc/tree-ssa-dom.cc @@ -1227,29 +1227,30 @@ void dom_opt_dom_walker::set_global_ranges_from_unreachable_edges (basic_block bb) { edge pred_e = single_pred_edge_ignoring_loop_edges (bb, false); - if (!pred_e) return; gimple *stmt = last_stmt (pred_e->src); + if (!stmt + || gimple_code (stmt) != GIMPLE_COND + || !assert_unreachable_fallthru_edge_p (pred_e)) + return; + tree name; - if (stmt - && gimple_code (stmt) == GIMPLE_COND - && (name = gimple_cond_lhs (stmt)) - && TREE_CODE (name) == SSA_NAME - && assert_unreachable_fallthru_edge_p (pred_e) - && all_uses_feed_or_dominated_by_stmt (name, stmt)) - { - Value_Range r (TREE_TYPE (name)); + gori_compute &gori = m_ranger->gori (); + FOR_EACH_GORI_EXPORT_NAME (gori, pred_e->src, name) + if (all_uses_feed_or_dominated_by_stmt (name, stmt)) + { + Value_Range r (TREE_TYPE (name)); - if (m_ranger->range_on_edge (r, pred_e, name) - && !r.varying_p () - && !r.undefined_p ()) - { - set_range_info (name, r); - maybe_set_nonzero_bits (pred_e, name); - } - } + if (m_ranger->range_on_edge (r, pred_e, name) + && !r.varying_p () + && !r.undefined_p ()) + { + set_range_info (name, r); + maybe_set_nonzero_bits (pred_e, name); + } + } } /* Record any equivalences created by the incoming edge to BB into -- cgit v1.1 From 099a66498bf7a40764002793eba66c881a251b76 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Mon, 26 Sep 2022 11:30:17 -0400 Subject: c++ modules: variable template partial spec fixes [PR107033] In r13-2775-g32d8123cd6ce87 I missed that we need to adjust the call to add_mergeable_specialization in the MK_partial case to correctly handle variable template partial specializations (it currently assumes we're always dealing with one for a class template). This fixes an ICE when converting the testcase from that commit to use an importable header instead of a named module. PR c++/107033 gcc/cp/ChangeLog: * 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. gcc/testsuite/ChangeLog: * 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. --- gcc/cp/module.cc | 17 ++++++++----- gcc/cp/pt.cc | 2 +- gcc/testsuite/g++.dg/modules/partial-2.cc | 17 +++++++++++++ gcc/testsuite/g++.dg/modules/partial-2.h | 38 +++++++++++++++++++++++++++++ gcc/testsuite/g++.dg/modules/partial-2_a.C | 39 +----------------------------- gcc/testsuite/g++.dg/modules/partial-2_b.C | 18 +------------- gcc/testsuite/g++.dg/modules/partial-2_c.H | 5 ++++ gcc/testsuite/g++.dg/modules/partial-2_d.C | 8 ++++++ 8 files changed, 82 insertions(+), 62 deletions(-) create mode 100644 gcc/testsuite/g++.dg/modules/partial-2.cc create mode 100644 gcc/testsuite/g++.dg/modules/partial-2.h create mode 100644 gcc/testsuite/g++.dg/modules/partial-2_c.H create mode 100644 gcc/testsuite/g++.dg/modules/partial-2_d.C (limited to 'gcc') diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index f23832c..7496df5 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -8185,13 +8185,18 @@ trees_in::decl_value () /* Set the TEMPLATE_DECL's type. */ TREE_TYPE (decl) = TREE_TYPE (inner); - if (mk & MK_template_mask - || mk == MK_partial) + /* Add to specialization tables now that constraints etc are + added. */ + if (mk == MK_partial) { - /* Add to specialization tables now that constraints etc are - added. */ - bool is_type = mk == MK_partial || !(mk & MK_tmpl_decl_mask); - + bool is_type = TREE_CODE (inner) == TYPE_DECL; + spec.spec = is_type ? type : inner; + add_mergeable_specialization (!is_type, false, + &spec, decl, spec_flags); + } + else if (mk & MK_template_mask) + { + bool is_type = !(mk & MK_tmpl_decl_mask); spec.spec = is_type ? type : mk & MK_tmpl_tmpl_mask ? inner : decl; add_mergeable_specialization (!is_type, !is_type && mk & MK_tmpl_alias_mask, diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index db4e808..1f088fe 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -31010,7 +31010,7 @@ add_mergeable_specialization (bool decl_p, bool alias_p, spec_entry *elt, /* A partial specialization. */ tree cons = tree_cons (elt->args, decl, DECL_TEMPLATE_SPECIALIZATIONS (elt->tmpl)); - TREE_TYPE (cons) = elt->spec; + TREE_TYPE (cons) = decl_p ? TREE_TYPE (elt->spec) : elt->spec; DECL_TEMPLATE_SPECIALIZATIONS (elt->tmpl) = cons; } } diff --git a/gcc/testsuite/g++.dg/modules/partial-2.cc b/gcc/testsuite/g++.dg/modules/partial-2.cc new file mode 100644 index 0000000..1316bf5 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/partial-2.cc @@ -0,0 +1,17 @@ +static_assert(is_reference_v); +static_assert(is_reference_v); +static_assert(!is_reference_v); + +static_assert(A::is_reference_v); +static_assert(A::is_reference_v); +static_assert(!A::is_reference_v); + +#if __cpp_concepts +static_assert(concepts::is_reference_v); +static_assert(concepts::is_reference_v); +static_assert(!concepts::is_reference_v); + +static_assert(concepts::A::is_reference_v); +static_assert(concepts::A::is_reference_v); +static_assert(!concepts::A::is_reference_v); +#endif diff --git a/gcc/testsuite/g++.dg/modules/partial-2.h b/gcc/testsuite/g++.dg/modules/partial-2.h new file mode 100644 index 0000000..afcfce7 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/partial-2.h @@ -0,0 +1,38 @@ +template constexpr bool is_reference_v = false; +template constexpr bool is_reference_v = true; +template constexpr bool is_reference_v = true; + +struct A { + template static constexpr bool is_reference_v = false; +}; + +template constexpr bool A::is_reference_v = true; +template constexpr bool A::is_reference_v = true; + +#if __cpp_concepts +namespace concepts { + template bool is_reference_v; + + template requires __is_same(T, T&) + constexpr bool is_reference_v = true; + + template requires __is_same(T, T&&) && (!__is_same(T, T&)) + constexpr bool is_reference_v = true; + + template requires (!__is_same(T, T&)) && (!__is_same(T, T&&)) + constexpr bool is_reference_v = false; + + struct A { + template static bool is_reference_v; + }; + + template requires __is_same(T, T&) + constexpr bool A::is_reference_v = true; + + template requires __is_same(T, T&&) && (!__is_same(T, T&)) + constexpr bool A::is_reference_v = true; + + template requires (!__is_same(T, T&)) && (!__is_same(T, T&&)) + constexpr bool A::is_reference_v = false; +} +#endif diff --git a/gcc/testsuite/g++.dg/modules/partial-2_a.C b/gcc/testsuite/g++.dg/modules/partial-2_a.C index 2681bb5..1582f56 100644 --- a/gcc/testsuite/g++.dg/modules/partial-2_a.C +++ b/gcc/testsuite/g++.dg/modules/partial-2_a.C @@ -3,41 +3,4 @@ // { dg-module-cmi pr106826 } export module pr106826; -template constexpr bool is_reference_v = false; -template constexpr bool is_reference_v = true; -template constexpr bool is_reference_v = true; - -struct A { - template static constexpr bool is_reference_v = false; -}; - -template constexpr bool A::is_reference_v = true; -template constexpr bool A::is_reference_v = true; - -#if __cpp_concepts -namespace concepts { - template bool is_reference_v; - - template requires __is_same(T, T&) - constexpr bool is_reference_v = true; - - template requires __is_same(T, T&&) && (!__is_same(T, T&)) - constexpr bool is_reference_v = true; - - template requires (!__is_same(T, T&)) && (!__is_same(T, T&&)) - constexpr bool is_reference_v = false; - - struct A { - template static bool is_reference_v; - }; - - template requires __is_same(T, T&) - constexpr bool A::is_reference_v = true; - - template requires __is_same(T, T&&) && (!__is_same(T, T&)) - constexpr bool A::is_reference_v = true; - - template requires (!__is_same(T, T&)) && (!__is_same(T, T&&)) - constexpr bool A::is_reference_v = false; -} -#endif +#include "partial-2.h" diff --git a/gcc/testsuite/g++.dg/modules/partial-2_b.C b/gcc/testsuite/g++.dg/modules/partial-2_b.C index 0af41ef..1b0c7a5 100644 --- a/gcc/testsuite/g++.dg/modules/partial-2_b.C +++ b/gcc/testsuite/g++.dg/modules/partial-2_b.C @@ -2,20 +2,4 @@ // { dg-additional-options -fmodules-ts } module pr106826; -static_assert(is_reference_v); -static_assert(is_reference_v); -static_assert(!is_reference_v); - -static_assert(A::is_reference_v); -static_assert(A::is_reference_v); -static_assert(!A::is_reference_v); - -#if __cpp_concepts -static_assert(concepts::is_reference_v); -static_assert(concepts::is_reference_v); -static_assert(!concepts::is_reference_v); - -static_assert(concepts::A::is_reference_v); -static_assert(concepts::A::is_reference_v); -static_assert(!concepts::A::is_reference_v); -#endif +#include "partial-2.cc" diff --git a/gcc/testsuite/g++.dg/modules/partial-2_c.H b/gcc/testsuite/g++.dg/modules/partial-2_c.H new file mode 100644 index 0000000..bd83852 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/partial-2_c.H @@ -0,0 +1,5 @@ +// PR c++/107033 +// { dg-additional-options -fmodule-header } +// { dg-module-cmi {} } + +#include "partial-2.h" diff --git a/gcc/testsuite/g++.dg/modules/partial-2_d.C b/gcc/testsuite/g++.dg/modules/partial-2_d.C new file mode 100644 index 0000000..ed54d3c --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/partial-2_d.C @@ -0,0 +1,8 @@ +// PR c++/107033 +// { dg-additional-options -fmodules-ts } +// { dg-module-cmi pr107033 } +export module pr107033; + +import "partial-2_c.H"; + +#include "partial-2.cc" -- cgit v1.1 From be4b32b9ef69b86b662cb7511b48cd1048a55403 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Mon, 26 Sep 2022 10:21:38 -0400 Subject: c++: Instantiate less when evaluating __is_convertible Jon reported that evaluating __is_convertible in a test led to instantiating something ill-formed and so we failed to compile the test. __is_convertible doesn't and shouldn't need to instantiate so much, so let's limit it with a cp_unevaluated guard. Use a helper function to implement both built-ins. PR c++/106784 gcc/cp/ChangeLog: * method.cc (is_convertible_helper): New. (is_convertible): Use it. (is_nothrow_convertible): Likewise. gcc/testsuite/ChangeLog: * g++.dg/ext/is_convertible3.C: New test. * g++.dg/ext/is_nothrow_convertible3.C: New test. --- gcc/cp/method.cc | 23 ++++++++++++++-------- gcc/testsuite/g++.dg/ext/is_convertible3.C | 9 +++++++++ gcc/testsuite/g++.dg/ext/is_nothrow_convertible3.C | 9 +++++++++ 3 files changed, 33 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/g++.dg/ext/is_convertible3.C create mode 100644 gcc/testsuite/g++.dg/ext/is_nothrow_convertible3.C (limited to 'gcc') diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc index c35a59f..9f917f1 100644 --- a/gcc/cp/method.cc +++ b/gcc/cp/method.cc @@ -2236,6 +2236,19 @@ ref_xes_from_temporary (tree to, tree from, bool direct_init_p) return ref_conv_binds_directly (to, val, direct_init_p).is_false (); } +/* Worker for is_{,nothrow_}convertible. Attempt to perform an implicit + conversion from FROM to TO and return the result. */ + +static tree +is_convertible_helper (tree from, tree to) +{ + if (VOID_TYPE_P (from) && VOID_TYPE_P (to)) + return integer_one_node; + cp_unevaluated u; + tree expr = build_stub_object (from); + return perform_implicit_conversion (to, expr, tf_none); +} + /* Return true if FROM can be converted to TO using implicit conversions, or both FROM and TO are possibly cv-qualified void. NB: This doesn't implement the "Access checks are performed as if from a context unrelated @@ -2244,10 +2257,7 @@ ref_xes_from_temporary (tree to, tree from, bool direct_init_p) bool is_convertible (tree from, tree to) { - if (VOID_TYPE_P (from) && VOID_TYPE_P (to)) - return true; - tree expr = build_stub_object (from); - expr = perform_implicit_conversion (to, expr, tf_none); + tree expr = is_convertible_helper (from, to); if (expr == error_mark_node) return false; return !!expr; @@ -2258,10 +2268,7 @@ is_convertible (tree from, tree to) bool is_nothrow_convertible (tree from, tree to) { - if (VOID_TYPE_P (from) && VOID_TYPE_P (to)) - return true; - tree expr = build_stub_object (from); - expr = perform_implicit_conversion (to, expr, tf_none); + tree expr = is_convertible_helper (from, to); if (expr == NULL_TREE || expr == error_mark_node) return false; return expr_noexcept_p (expr, tf_none); diff --git a/gcc/testsuite/g++.dg/ext/is_convertible3.C b/gcc/testsuite/g++.dg/ext/is_convertible3.C new file mode 100644 index 0000000..7a986d0 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/is_convertible3.C @@ -0,0 +1,9 @@ +// PR c++/106784 +// { dg-do compile { target c++11 } } +// Make sure we don't reject this at runtime by trying to instantiate +// something that would be ill-formed. + +struct A; +struct B { template B(const T&) noexcept { T::nonexistent; } }; + +static_assert(__is_convertible(const A&, B), ""); diff --git a/gcc/testsuite/g++.dg/ext/is_nothrow_convertible3.C b/gcc/testsuite/g++.dg/ext/is_nothrow_convertible3.C new file mode 100644 index 0000000..05b1e1d --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/is_nothrow_convertible3.C @@ -0,0 +1,9 @@ +// PR c++/106784 +// { dg-do compile { target c++11 } } +// Make sure we don't reject this at runtime by trying to instantiate +// something that would be ill-formed. + +struct A; +struct B { template B(const T&) noexcept { T::nonexistent; } }; + +static_assert(__is_nothrow_convertible(const A&, B), ""); -- cgit v1.1 From 5e77d4082fa845f1182641a93cfbae71984244d2 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Fri, 23 Sep 2022 19:47:19 +0200 Subject: Optimize [0 = x & MASK] in range-ops. For [0 = x & MASK], we can determine that x is ~MASK. This is something we're picking up in DOM thanks to maybe_set_nonzero_bits, but is something we should handle natively. This is a good example of how much easier to maintain the range-ops entries are versus the ad-hoc pattern matching stuff we had to do before. For the curious, compare the changes to range-op here, versus maybe_set_nonzero_bits. I'm leaving the call to maybe_set_nonzero_bits until I can properly audit it to make sure we're catching it all in range-ops. It won't hurt, since both set_range_info() and set_nonzero_bits() are intersect operations, so we'll never lose information if we do both. PR tree-optimization/107009 gcc/ChangeLog: * range-op.cc (operator_bitwise_and::op1_range): Optimize 0 = x & MASK. (range_op_bitwise_and_tests): New test. --- gcc/range-op.cc | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'gcc') diff --git a/gcc/range-op.cc b/gcc/range-op.cc index 072ebd3..fc930f4 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -2951,6 +2951,15 @@ operator_bitwise_and::op1_range (irange &r, tree type, } if (r.undefined_p ()) set_nonzero_range_from_mask (r, type, lhs); + + // For 0 = op1 & MASK, op1 is ~MASK. + if (lhs.zero_p () && op2.singleton_p ()) + { + wide_int nz = wi::bit_not (op2.get_nonzero_bits ()); + int_range<2> tmp (type); + tmp.set_nonzero_bits (nz); + r.intersect (tmp); + } return true; } @@ -4612,6 +4621,15 @@ range_op_bitwise_and_tests () op_bitwise_and.op1_range (res, integer_type_node, i1, i2); ASSERT_TRUE (res == int_range<1> (integer_type_node)); + // For 0 = x & MASK, x is ~MASK. + { + int_range<2> zero (integer_zero_node, integer_zero_node); + int_range<2> mask = int_range<2> (INT (7), INT (7)); + op_bitwise_and.op1_range (res, integer_type_node, zero, mask); + wide_int inv = wi::shwi (~7U, TYPE_PRECISION (integer_type_node)); + ASSERT_TRUE (res.get_nonzero_bits () == inv); + } + // (NONZERO | X) is nonzero. i1.set_nonzero (integer_type_node); i2.set_varying (integer_type_node); -- cgit v1.1 From 567329fdd9d65a1e6254206fefff89fa151ba7f3 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Fri, 23 Sep 2022 18:06:34 -0400 Subject: c++: P2513R4, char8_t Compatibility and Portability Fix [PR106656] P0482R6, which added char8_t, didn't allow const char arr[] = u8"howdy"; because it said "Declarations of arrays of char may currently be initialized with UTF-8 string literals. Under this proposal, such initializations would become ill-formed." This caused too many issues, so P2513R4 alleviates some of those compatibility problems. In particular, "Arrays of char or unsigned char may now be initialized with a UTF-8 string literal." This restriction has been lifted for initialization only, not implicit conversions. Also, my reading is that 'signed char' was excluded from the allowable conversions. This is supposed to be treated as a DR in C++20. PR c++/106656 gcc/c-family/ChangeLog: * c-cppbuiltin.cc (c_cpp_builtins): Update value of __cpp_char8_t for C++20. gcc/cp/ChangeLog: * typeck2.cc (array_string_literal_compatible_p): Allow initializing arrays of char or unsigned char by a UTF-8 string literal. gcc/testsuite/ChangeLog: * 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. --- gcc/c-family/c-cppbuiltin.cc | 2 +- gcc/cp/typeck2.cc | 9 ++++++ gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C | 4 +-- gcc/testsuite/g++.dg/cpp2a/char8_t3.C | 37 ++++++++++++++++++++++ gcc/testsuite/g++.dg/cpp2a/char8_t4.C | 17 ++++++++++ gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C | 4 +-- .../g++.dg/ext/char8_t-feature-test-macro-2.C | 4 +-- gcc/testsuite/g++.dg/ext/char8_t-init-2.C | 4 +-- 8 files changed, 72 insertions(+), 9 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/char8_t3.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/char8_t4.C (limited to 'gcc') diff --git a/gcc/c-family/c-cppbuiltin.cc b/gcc/c-family/c-cppbuiltin.cc index a1557eb..b709f84 100644 --- a/gcc/c-family/c-cppbuiltin.cc +++ b/gcc/c-family/c-cppbuiltin.cc @@ -1112,7 +1112,7 @@ c_cpp_builtins (cpp_reader *pfile) if (flag_threadsafe_statics) cpp_define (pfile, "__cpp_threadsafe_static_init=200806L"); if (flag_char8_t) - cpp_define (pfile, "__cpp_char8_t=201811L"); + cpp_define (pfile, "__cpp_char8_t=202207L"); #ifndef THREAD_MODEL_SPEC /* Targets that define THREAD_MODEL_SPEC need to define __STDCPP_THREADS__ in their config/XXX/XXX-c.c themselves. */ diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc index 75fd0e2..739097a 100644 --- a/gcc/cp/typeck2.cc +++ b/gcc/cp/typeck2.cc @@ -1118,6 +1118,15 @@ array_string_literal_compatible_p (tree type, tree init) if (ordinary_char_type_p (to_char_type) && ordinary_char_type_p (from_char_type)) return true; + + /* P2513 (C++20/C++23): "an array of char or unsigned char may + be initialized by a UTF-8 string literal, or by such a string + literal enclosed in braces." */ + if (from_char_type == char8_type_node + && (to_char_type == char_type_node + || to_char_type == unsigned_char_type_node)) + return true; + return false; } diff --git a/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C b/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C index d3e4072..0537e1d 100644 --- a/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C +++ b/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C @@ -504,8 +504,8 @@ #ifndef __cpp_char8_t # error "__cpp_char8_t" -#elif __cpp_char8_t != 201811 -# error "__cpp_char8_t != 201811" +#elif __cpp_char8_t != 202207 +# error "__cpp_char8_t != 202207" #endif #ifndef __cpp_designated_initializers diff --git a/gcc/testsuite/g++.dg/cpp2a/char8_t3.C b/gcc/testsuite/g++.dg/cpp2a/char8_t3.C new file mode 100644 index 0000000..071a718 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/char8_t3.C @@ -0,0 +1,37 @@ +// PR c++/106656 - P2513 - char8_t Compatibility and Portability Fixes +// { dg-do compile { target c++20 } } + +const char *p1 = u8""; // { dg-error "invalid conversion" } +const unsigned char *p2 = u8""; // { dg-error "invalid conversion" } +const signed char *p3 = u8""; // { dg-error "invalid conversion" } +const char *p4 = { u8"" }; // { dg-error "invalid conversion" } +const unsigned char *p5 = { u8"" }; // { dg-error "invalid conversion" } +const signed char *p6 = { u8"" }; // { dg-error "invalid conversion" } +const char *p7 = static_cast(u8""); // { dg-error "invalid" } +const char a1[] = u8"text"; +const unsigned char a2[] = u8""; +const signed char a3[] = u8""; // { dg-error "cannot initialize array" } +const char a4[] = { u8"text" }; +const unsigned char a5[] = { u8"" }; +const signed char a6[] = { u8"" }; // { dg-error "cannot initialize array" } + +const char * +resource_id () +{ + static const char res_id[] = u8""; + return res_id; +} + +const char8_t x[] = "fail"; // { dg-error "cannot initialize array" } + +void fn (const char a[]); +void +g () +{ + fn (u8"z"); // { dg-error "invalid conversion" } +} + +char c = u8'c'; +unsigned char uc = u8'c'; +signed char sc = u8'c'; +char8_t c8 = 'c'; diff --git a/gcc/testsuite/g++.dg/cpp2a/char8_t4.C b/gcc/testsuite/g++.dg/cpp2a/char8_t4.C new file mode 100644 index 0000000..c18081b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/char8_t4.C @@ -0,0 +1,17 @@ +// PR c++/106656 - P2513 - char8_t Compatibility and Portability Fixes +// { dg-do compile { target c++20 } } +// [diff.cpp20.dcl] + +struct A { + char8_t s[10]; +}; +struct B { + char s[10]; +}; + +void f(A); +void f(B); + +int main() { + f({u8""}); // { dg-error "ambiguous" } +} diff --git a/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C b/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C index c65ea6b..02f3a37 100644 --- a/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C +++ b/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C @@ -504,8 +504,8 @@ #ifndef __cpp_char8_t # error "__cpp_char8_t" -#elif __cpp_char8_t != 201811 -# error "__cpp_char8_t != 201811" +#elif __cpp_char8_t != 202207 +# error "__cpp_char8_t != 202207" #endif #ifndef __cpp_designated_initializers diff --git a/gcc/testsuite/g++.dg/ext/char8_t-feature-test-macro-2.C b/gcc/testsuite/g++.dg/ext/char8_t-feature-test-macro-2.C index df1063f..2d0f904 100644 --- a/gcc/testsuite/g++.dg/ext/char8_t-feature-test-macro-2.C +++ b/gcc/testsuite/g++.dg/ext/char8_t-feature-test-macro-2.C @@ -5,6 +5,6 @@ #if !defined(__cpp_char8_t) # error __cpp_char8_t is not defined! -#elif __cpp_char8_t != 201811 -# error __cpp_char8_t != 201811 +#elif __cpp_char8_t != 202207 +# error __cpp_char8_t != 202207 #endif diff --git a/gcc/testsuite/g++.dg/ext/char8_t-init-2.C b/gcc/testsuite/g++.dg/ext/char8_t-init-2.C index c713bc1..02a96ff 100644 --- a/gcc/testsuite/g++.dg/ext/char8_t-init-2.C +++ b/gcc/testsuite/g++.dg/ext/char8_t-init-2.C @@ -21,7 +21,7 @@ const char8_t (&rca4)[2] = u8"x"; const char8_t (&rca5)[2] = u"x"; // { dg-error "invalid initialization of reference of type .const char8_t ....... from expression of type .const char16_t ...." "char8_t" } char ca1[] = "x"; -char ca2[] = u8"x"; // { dg-error "from a string literal with type array of .char8_t." "char8_t" } +char ca2[] = u8"x"; char8_t ca3[] = "x"; // { dg-error "from a string literal with type array of .char." "char8_t" } char8_t ca4[] = u8"x"; char8_t ca5[] = u"x"; // { dg-error "from a string literal with type array of .char16_t." "char8_t" } @@ -30,4 +30,4 @@ signed char sca1[] = "x"; signed char sca2[] = u8"x"; // { dg-error "from a string literal with type array of .char8_t." "char8_t" } unsigned char uca1[] = "x"; -unsigned char uca2[] = u8"x"; // { dg-error "from a string literal with type array of .char8_t." "char8_t" } +unsigned char uca2[] = u8"x"; -- cgit v1.1 From 7701ea4a70a5a5c0fd977da90a30ffc4f3f87617 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Mon, 26 Sep 2022 21:04:11 +0200 Subject: docs: add missing dash in option name gcc/ChangeLog: * doc/invoke.texi: Add missing dash for Wanalyzer-exposure-through-uninit-copy. --- gcc/doc/invoke.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index d2e4abd..383d22a 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -9901,7 +9901,7 @@ security-sensitive value is written to an output file See @uref{https://cwe.mitre.org/data/definitions/532.html, CWE-532: Information Exposure Through Log Files}. -@item Wanalyzer-exposure-through-uninit-copy +@item -Wanalyzer-exposure-through-uninit-copy @opindex Wanalyzer-exposure-through-uninit-copy @opindex Wno-analyzer-exposure-through-uninit-copy This warning requires both @option{-fanalyzer} and the use of a plugin -- cgit v1.1 From 220c4d8e44971c87ad9070f1b3d29ab5fbe45dff Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Tue, 27 Sep 2022 00:17:52 +0000 Subject: Daily bump. --- gcc/ChangeLog | 108 ++++++++++++++++++++++++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/ada/ChangeLog | 99 ++++++++++++++++++++++++++++++++++++++++++++ gcc/c-family/ChangeLog | 6 +++ gcc/cp/ChangeLog | 25 +++++++++++ gcc/testsuite/ChangeLog | 64 ++++++++++++++++++++++++++++ 6 files changed, 303 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6890dd1..4bd177d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,111 @@ +2022-09-26 Martin Liska + + * doc/invoke.texi: Add missing dash for + Wanalyzer-exposure-through-uninit-copy. + +2022-09-26 Aldy Hernandez + + 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 + + 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 + + * 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) : Document this. + * doc/invoke.texi (Nvidia PTX Options): Likewise. + +2022-09-26 Thomas Schwinge + + * 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 + + * 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 + + * config/nvptx/nvptx.h (ASM_SPEC): Define. + +2022-09-26 Jeff Law + + * 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 + + PR middle-end/106982 + * omp-low.cc (lower_oacc_reductions): Add some unshare_expr. + +2022-09-26 Martin Liska + + * config/s390/s390.cc (s390_rtx_costs): Remove dest variable + and use only dst. + +2022-09-26 Kyrylo Tkachov + + * 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 + + * value-range.cc (tree_compare): Remove unused function. + +2022-09-26 Kewen Lin + + 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 + + PR target/100645 + * config/rs6000/vector.md (vec_shr_): Replace condition + TARGET_ALTIVEC with VECTOR_UNIT_ALTIVEC_OR_VSX_P. + +2022-09-26 Hongtao Liu + Liwei Xu + + 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 * doc/sourcebuild.texi: Fix chapter level. diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 7764f7e..38c805d 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20220926 +20220927 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 + + * doc/gnat_rm/implementation_defined_attributes.rst: Rename Valid_Image. + * gnat_rm.texi: Regenerate. + * gnat_ugn.texi: Regenerate. + +2022-09-26 Piotr Trojanek + + * 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 + + * 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 + + * s-oscons-tmplt.c (STR, STR1): Remove. + +2022-09-26 Eric Botcazou + + * 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 + + * 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 + + * 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 + + * sem_util.adb (Original_Aspect_Pragma_Name): Check for Check + pragmas. + +2022-09-26 Piotr Trojanek + + * sem_ch5.adb (Analyze_Iterator_Specification): Delay expansion + based on Full_Analysis flag. + +2022-09-26 Piotr Trojanek + + * 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 + + * contracts.adb (Analyze_Object_Contract): Check SPARK_Mode before + applying SPARK rule. + +2022-09-26 Justin Squirek + + * 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 + + * doc/gnat_ugn/gnat_utility_programs.rst: Remove documentation for + gnatmetric. + +2022-09-26 Piotr Trojanek + + * gsocket.h: Remove redefinition of _WIN32_WINNT. + * mingw32.h: Remove conditional definition of _WIN32_WINNT. + +2022-09-26 Piotr Trojanek + + * 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 + + * 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 + + * sem_warn.ads (Has_Junk_Name): Reword comment. + 2022-09-20 Martin Liska * exp_ch6.adb: Replace "the the" with "the". diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 415c4cf..4e99c43 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,9 @@ +2022-09-26 Marek Polacek + + PR c++/106656 + * c-cppbuiltin.cc (c_cpp_builtins): Update value of __cpp_char8_t + for C++20. + 2022-09-23 Marek Polacek PR c++/106784 diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index b9b2729..ca5015e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,28 @@ +2022-09-26 Marek Polacek + + 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 + + PR c++/106784 + * method.cc (is_convertible_helper): New. + (is_convertible): Use it. + (is_nothrow_convertible): Likewise. + +2022-09-26 Patrick Palka + + 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 PR c++/106784 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 0e7cd64e..24f4ac5 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,67 @@ +2022-09-26 Marek Polacek + + 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 + + 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 + + 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 + + PR tree-optimization/107009 + * gcc.dg/tree-ssa/pr107009.c: New test. + +2022-09-26 Jeff Law + + * gcc.target/riscv/ret-1.c: New test. + +2022-09-26 Tobias Burnus + + 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 + + PR target/96072 + * gcc.target/powerpc/pr96072.c: New test. + +2022-09-26 Hu, Lin1 + + PR target/94962 + * gcc.target/i386/avx256-unaligned-store-3.c: Add -mno-avx512f + +2022-09-26 Kewen Lin + + PR target/100645 + * gcc.target/powerpc/pr100645.c: New test. + +2022-09-26 Hongtao Liu + Liwei Xu + + * 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 PR fortran/41453 -- cgit v1.1 From b04208895fed34171eac6bafb60c90048eb1cb0c Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 27 Sep 2022 08:04:06 +0200 Subject: c++: Implement P1467R9 - Extended floating-point types and standard names compiler part except for bfloat16 [PR106652] The following patch implements the compiler part of C++23 P1467R9 - Extended floating-point types and standard names compiler part by introducing _Float{16,32,64,128} as keywords and builtin types like they are implemented for C already since GCC 7, with DF{16,32,64,128}_ mangling. It also introduces _Float{32,64,128}x for C++ with the https://github.com/itanium-cxx-abi/cxx-abi/pull/147 proposed mangling of DF{32,64,128}x. The patch doesn't add anything for bfloat16_t support, as right now __bf16 type refuses all conversions and arithmetic operations. The patch wants to keep backwards compatibility with how __float128 has been handled in C++ before, both for mangling and behavior in binary operations, overload resolution etc. So, there are some backend changes where for C __float128 and _Float128 are the same type (float128_type_node and float128t_type_node are the same pointer), but for C++ they are distinct types which mangle differently and _Float128 is treated as extended floating-point type while __float128 is treated as non-standard floating point type. The various C++23 changes about how floating-point types are changed are actually implemented as written in the spec only if at least one of the types involved is _Float{16,32,64,128,32x,64x,128x} (_FloatNx are also treated as extended floating-point types) and kept previous behavior otherwise. For float/double/long double the rules are actually written that they behave the same as before. There is some backwards incompatibility at least on x86 regarding _Float16, because that type was already used by that name and with the DF16_ mangling (but only since GCC 12 and I think it isn't that widely used in the wild yet). E.g. config/i386/avx512fp16intrin.h shows the issues, where in C or in GCC 12 in C++ one could pass 0.0f to a builtin taking _Float16 argument, but with the changes that is not possible anymore, one needs to either use 0.0f16 or (_Float16) 0.0f. We have also a problem with glibc headers, where since glibc 2.27 math.h and complex.h aren't compilable with these changes. One gets errors like: In file included from /usr/include/math.h:43, from abc.c:1: /usr/include/bits/floatn.h:86:9: error: multiple types in one declaration 86 | typedef __float128 _Float128; | ^~~~~~~~~~ /usr/include/bits/floatn.h:86:20: error: declaration does not declare anything [-fpermissive] 86 | typedef __float128 _Float128; | ^~~~~~~~~ In file included from /usr/include/bits/floatn.h:119: /usr/include/bits/floatn-common.h:214:9: error: multiple types in one declaration 214 | typedef float _Float32; | ^~~~~ /usr/include/bits/floatn-common.h:214:15: error: declaration does not declare anything [-fpermissive] 214 | typedef float _Float32; | ^~~~~~~~ /usr/include/bits/floatn-common.h:251:9: error: multiple types in one declaration 251 | typedef double _Float64; | ^~~~~~ /usr/include/bits/floatn-common.h:251:16: error: declaration does not declare anything [-fpermissive] 251 | typedef double _Float64; | ^~~~~~~~ This is from snippets like: /* The remaining of this file provides support for older compilers. */ # if __HAVE_FLOAT128 /* The type _Float128 exists only since GCC 7.0. */ # if !__GNUC_PREREQ (7, 0) || defined __cplusplus typedef __float128 _Float128; # endif where it hardcodes that C++ doesn't have _Float{16,32,64,128,32x,64x,128x} support nor {f,F}{16,32,64,128}{,x} literal suffixes nor _Complex _Float{16,32,64,128,32x,64x,128x}. The patch fixincludes this for now and hopefully if this is committed, then glibc can change those. The patch changes those # if !__GNUC_PREREQ (7, 0) || defined __cplusplus conditions to # if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0)) Another thing is mangling, as said above, Itanium C++ ABI specifies DF _ as _Float{16,32,64,128} mangling, but GCC was implementing a mangling incompatible with that starting with DF for fixed point types. Fixed point was never supported in C++ though, I believe the reason why the mangling has been added was that due to a bug it would leak into the C++ FE through decltype (0.0r) etc. But that has been shortly after the mangling was added fixed (I think in the same GCC release cycle), so we now reject 0.0r etc. in C++. If we ever need the fixed point mangling, I think it can be readded but better with a different prefix so that it doesn't conflict with the published standard manglings. So, this patch also kills the fixed point mangling and implements the DF _ demangling. The patch predefines __STDCPP_FLOAT{16,32,64,128}_T__ macros when those types are available, but only for C++23, while the underlying types are available in C++98 and later including the {f,F}{16,32,64,128} literal suffixes (but those with a pedwarn for C++20 and earlier). My understanding is that it needs to be predefined by the compiler, on the other side predefining even for older modes when is a new C++23 header would be weird. One can find out if _Float{16,32,64,128,32x,64x,128x} is supported in C++ by __GNUC__ >= 13 && defined(__FLT{16,32,64,128,32X,64X,128X}_MANT_DIG__) (but that doesn't work well with older G++ 13 snapshots). As for std::bfloat16_t, three targets (aarch64, arm and x86) apparently "support" __bf16 type which has the bfloat16 format, but isn't really usable, e.g. {aarch64,arm,ix86}_invalid_conversion disallow any conversions from or to type with BFmode, {aarch64,arm,ix86}_invalid_unary_op disallows any unary operations on those except for ADDR_EXPR and {aarch64,arm,ix86}_invalid_binary_op disallows any binary operation on those. So, I think we satisfy: "If the implementation supports an extended floating-point type with the properties, as specified by ISO/IEC/IEEE 60559, of radix (b) of 2, storage width in bits (k) of 16, precision in bits (p) of 8, maximum exponent (emax) of 127, and exponent field width in bits (w) of 8, then the typedef-name std::bfloat16_t is defined in the header and names such a type, the macro __STDCPP_BFLOAT16_T__ is defined, and the floating-point literal suffixes bf16 and BF16 are supported." because we don't really support those right now. 2022-09-27 Jakub Jelinek PR c++/106652 PR c++/85518 gcc/ * 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 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. gcc/c-family/ * 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++. gcc/cp/ * 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 or _Floatx 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. gcc/testsuite/ * 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. libcpp/ * expr.cc (interpret_float_suffix): Allow {f,F}{16,32,64,128} and {f,F}{32,64,128}x suffixes for C++. include/ * demangle.h (enum demangle_component_type): Add DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE. (struct demangle_component): Add u.s_extended_builtin member. libiberty/ * 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 or _Floatx 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. fixincludes/ * 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. --- gcc/builtins.def | 5 +- gcc/c-family/c-common.cc | 37 ++- gcc/c-family/c-cppbuiltin.cc | 8 + gcc/c-family/c-lex.cc | 20 +- gcc/config/i386/avx512fp16intrin.h | 11 +- gcc/config/i386/i386-builtins.cc | 15 +- gcc/config/i386/i386.cc | 5 +- gcc/config/ia64/ia64.cc | 24 +- gcc/config/rs6000/rs6000-builtin.cc | 17 +- gcc/config/rs6000/rs6000-c.cc | 1 + gcc/config/rs6000/rs6000.cc | 6 +- gcc/cp/call.cc | 130 +++++++- gcc/cp/cp-tree.h | 13 + gcc/cp/mangle.cc | 67 +---- gcc/cp/parser.cc | 9 + gcc/cp/typeck.cc | 172 ++++++++++- gcc/cp/typeck2.cc | 25 +- gcc/testsuite/g++.dg/cpp23/ext-floating.h | 30 ++ gcc/testsuite/g++.dg/cpp23/ext-floating1.C | 447 ++++++++++++++++++++++++++++ gcc/testsuite/g++.dg/cpp23/ext-floating10.C | 13 + gcc/testsuite/g++.dg/cpp23/ext-floating2.C | 157 ++++++++++ gcc/testsuite/g++.dg/cpp23/ext-floating3.C | 134 +++++++++ gcc/testsuite/g++.dg/cpp23/ext-floating4.C | 126 ++++++++ gcc/testsuite/g++.dg/cpp23/ext-floating5.C | 13 + gcc/testsuite/g++.dg/cpp23/ext-floating6.C | 30 ++ gcc/testsuite/g++.dg/cpp23/ext-floating7.C | 119 ++++++++ gcc/testsuite/g++.dg/cpp23/ext-floating8.C | 13 + gcc/testsuite/g++.dg/cpp23/ext-floating9.C | 13 + gcc/testsuite/g++.target/i386/float16-1.C | 4 +- gcc/tree-core.h | 4 + gcc/tree.cc | 1 + gcc/tree.h | 4 + 32 files changed, 1573 insertions(+), 100 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp23/ext-floating.h create mode 100644 gcc/testsuite/g++.dg/cpp23/ext-floating1.C create mode 100644 gcc/testsuite/g++.dg/cpp23/ext-floating10.C create mode 100644 gcc/testsuite/g++.dg/cpp23/ext-floating2.C create mode 100644 gcc/testsuite/g++.dg/cpp23/ext-floating3.C create mode 100644 gcc/testsuite/g++.dg/cpp23/ext-floating4.C create mode 100644 gcc/testsuite/g++.dg/cpp23/ext-floating5.C create mode 100644 gcc/testsuite/g++.dg/cpp23/ext-floating6.C create mode 100644 gcc/testsuite/g++.dg/cpp23/ext-floating7.C create mode 100644 gcc/testsuite/g++.dg/cpp23/ext-floating8.C create mode 100644 gcc/testsuite/g++.dg/cpp23/ext-floating9.C (limited to 'gcc') 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 and _FloatX 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/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-cppbuiltin.cc b/gcc/c-family/c-cppbuiltin.cc index b709f84..e3f4d3d 100644 --- a/gcc/c-family/c-cppbuiltin.cc +++ b/gcc/c-family/c-cppbuiltin.cc @@ -1246,6 +1246,14 @@ c_cpp_builtins (cpp_reader *pfile) { if (FLOATN_NX_TYPE_NODE (i) == NULL_TREE) continue; + if (c_dialect_cxx () + && cxx_dialect > cxx20 + && !floatn_nx_types[i].extended) + { + char name[sizeof ("__STDCPP_FLOAT128_T__=1")]; + sprintf (name, "__STDCPP_FLOAT%d_T__=1", floatn_nx_types[i].n); + cpp_define (pfile, name); + } char prefix[20], csuffix[20]; sprintf (prefix, "FLT%d%s", floatn_nx_types[i].n, floatn_nx_types[i].extended ? "X" : ""); diff --git a/gcc/c-family/c-lex.cc b/gcc/c-family/c-lex.cc index 110d029..4d2252f 100644 --- a/gcc/c-family/c-lex.cc +++ b/gcc/c-family/c-lex.cc @@ -960,6 +960,10 @@ interpret_float (const cpp_token *token, unsigned int flags, pedwarn (input_location, OPT_Wpedantic, "non-standard suffix on floating constant"); type = c_common_type_for_mode (mode, 0); + /* For Q suffix, prefer float128t_type_node (__float128) type + over float128_type_node (_Float128) type if they are distinct. */ + if (type == float128_type_node && float128t_type_node) + type = float128t_type_node; gcc_assert (type); } else if ((flags & (CPP_N_FLOATN | CPP_N_FLOATNX)) != 0) @@ -979,8 +983,17 @@ interpret_float (const cpp_token *token, unsigned int flags, error ("unsupported non-standard suffix on floating constant"); return error_mark_node; } + else if (c_dialect_cxx () && !extended) + { + if (cxx_dialect < cxx23) + pedwarn (input_location, OPT_Wpedantic, + "% or % 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/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/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/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/call.cc b/gcc/cp/call.cc index 7e9289f..3b7e527 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -1541,6 +1541,22 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p, || (underlying_type && same_type_p (to, underlying_type))) && next_conversion (conv)->rank <= cr_promotion) conv->rank = cr_promotion; + + /* A prvalue of floating-point type can be converted to a prvalue of + another floating-point type with a greater or equal conversion + rank ([conv.rank]). A prvalue of standard floating-point type can + be converted to a prvalue of another standard floating-point type. + For backwards compatibility with handling __float128 and other + non-standard floating point types, allow all implicit floating + point conversions if neither type is extended floating-point + type and if at least one of them is, fail if they have unordered + conversion rank or from has higher conversion rank. */ + if (fcode == REAL_TYPE + && tcode == REAL_TYPE + && (extended_float_type_p (from) + || extended_float_type_p (to)) + && cp_compare_floating_point_conversion_ranks (from, to) >= 2) + conv->bad_p = true; } else if (fcode == VECTOR_TYPE && tcode == VECTOR_TYPE && vector_types_convertible_p (from, to, false)) @@ -5842,6 +5858,21 @@ build_conditional_expr (const op_location_t &loc, /* In this case, there is always a common type. */ result_type = type_after_usual_arithmetic_conversions (arg2_type, arg3_type); + if (result_type == error_mark_node + && TREE_CODE (arg2_type) == REAL_TYPE + && TREE_CODE (arg3_type) == REAL_TYPE + && (extended_float_type_p (arg2_type) + || extended_float_type_p (arg3_type)) + && cp_compare_floating_point_conversion_ranks (arg2_type, + arg3_type) == 3) + { + if (complain & tf_error) + error_at (loc, "operands to % of types %qT and %qT " + "have unordered conversion rank", + arg2_type, arg3_type); + return error_mark_node; + } + if (complain & tf_warning) do_warn_double_promotion (result_type, arg2_type, arg3_type, "implicit conversion from %qH to %qI to " @@ -7906,6 +7937,27 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum, "direct-initialization", totype, TREE_TYPE (expr)); + if (TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE + && TREE_CODE (totype) == REAL_TYPE + && (extended_float_type_p (TREE_TYPE (expr)) + || extended_float_type_p (totype))) + switch (cp_compare_floating_point_conversion_ranks (TREE_TYPE (expr), + totype)) + { + case 2: + pedwarn (loc, 0, "converting to %qH from %qI with greater " + "conversion rank", totype, TREE_TYPE (expr)); + complained = true; + break; + case 3: + pedwarn (loc, 0, "converting to %qH from %qI with unordered " + "conversion ranks", totype, TREE_TYPE (expr)); + complained = true; + break; + default: + break; + } + for (; t ; t = next_conversion (t)) { if (t->kind == ck_user && t->cand->reason) @@ -8531,7 +8583,8 @@ convert_arg_to_ellipsis (tree arg, tsubst_flags_t complain) if (TREE_CODE (arg_type) == REAL_TYPE && (TYPE_PRECISION (arg_type) < TYPE_PRECISION (double_type_node)) - && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (arg_type))) + && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (arg_type)) + && !extended_float_type_p (arg_type)) { if ((complain & tf_warning) && warn_double_promotion && !c_inhibit_evaluation_warnings) @@ -11719,6 +11772,81 @@ compare_ics (conversion *ics1, conversion *ics2) return 1; } + { + /* A conversion in either direction between floating-point type FP1 and + floating-point type FP2 is better than a conversion in the same + direction between FP1 and arithmetic type T3 if + - the floating-point conversion rank of FP1 is equal to the rank of + FP2, and + - T3 is not a floating-point type, or T3 is a floating-point type + whose rank is not equal to the rank of FP1, or the floating-point + conversion subrank of FP2 is greater than the subrank of T3. */ + tree fp1 = from_type1; + tree fp2 = to_type1; + tree fp3 = from_type2; + tree t3 = to_type2; + int ret = 1; + if (TYPE_MAIN_VARIANT (fp2) == TYPE_MAIN_VARIANT (t3)) + { + std::swap (fp1, fp2); + std::swap (fp3, t3); + } + if (TYPE_MAIN_VARIANT (fp1) == TYPE_MAIN_VARIANT (fp3) + && TREE_CODE (fp1) == REAL_TYPE + /* Only apply this rule if at least one of the 3 types is + extended floating-point type, otherwise keep them as + before for compatibility reasons with types like __float128. + float, double and long double alone have different conversion + ranks and so when just those 3 types are involved, this + rule doesn't trigger. */ + && (extended_float_type_p (fp1) + || (TREE_CODE (fp2) == REAL_TYPE && extended_float_type_p (fp2)) + || (TREE_CODE (t3) == REAL_TYPE && extended_float_type_p (t3)))) + { + if (TREE_CODE (fp2) != REAL_TYPE) + { + ret = -ret; + std::swap (fp2, t3); + } + if (TREE_CODE (fp2) == REAL_TYPE) + { + /* cp_compare_floating_point_conversion_ranks returns -1, 0 or 1 + if the conversion rank is equal (-1 or 1 if the subrank is + different). */ + if (IN_RANGE (cp_compare_floating_point_conversion_ranks (fp1, + fp2), + -1, 1)) + { + /* Conversion ranks of FP1 and FP2 are equal. */ + if (TREE_CODE (t3) != REAL_TYPE + || !IN_RANGE (cp_compare_floating_point_conversion_ranks + (fp1, t3), + -1, 1)) + /* FP1 <-> FP2 conversion is better. */ + return ret; + int c = cp_compare_floating_point_conversion_ranks (fp2, t3); + gcc_assert (IN_RANGE (c, -1, 1)); + if (c == 1) + /* Conversion subrank of FP2 is greater than subrank of T3. + FP1 <-> FP2 conversion is better. */ + return ret; + else if (c == -1) + /* Conversion subrank of FP2 is less than subrank of T3. + FP1 <-> T3 conversion is better. */ + return -ret; + } + else if (TREE_CODE (t3) == REAL_TYPE + && IN_RANGE (cp_compare_floating_point_conversion_ranks + (fp1, t3), + -1, 1)) + /* Conversion ranks of FP1 and FP2 are not equal, conversion + ranks of FP1 and T3 are equal. + FP1 <-> T3 conversion is better. */ + return -ret; + } + } + } + if (TYPE_PTR_P (from_type1) && TYPE_PTR_P (from_type2) && TYPE_PTR_P (to_type1) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index e4d8920..8779538 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7946,6 +7946,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 +8689,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/mangle.cc b/gcc/cp/mangle.cc index 75388e9..00d283f 100644 --- a/gcc/cp/mangle.cc +++ b/gcc/cp/mangle.cc @@ -2648,63 +2648,24 @@ write_builtin_type (tree type) write_string ("Dd"); else if (type == dfloat128_type_node || type == fallback_dfloat128_type) write_string ("De"); + else if (type == float16_type_node) + write_string ("DF16_"); + else if (type == float32_type_node) + write_string ("DF32_"); + else if (type == float64_type_node) + write_string ("DF64_"); + else if (type == float128_type_node) + write_string ("DF128_"); + else if (type == float32x_type_node) + write_string ("DF32x"); + else if (type == float64x_type_node) + write_string ("DF64x"); + else if (type == float128x_type_node) + write_string ("DF128x"); else gcc_unreachable (); break; - case FIXED_POINT_TYPE: - write_string ("DF"); - if (GET_MODE_IBIT (TYPE_MODE (type)) > 0) - write_unsigned_number (GET_MODE_IBIT (TYPE_MODE (type))); - if (type == fract_type_node - || type == sat_fract_type_node - || type == accum_type_node - || type == sat_accum_type_node) - write_char ('i'); - else if (type == unsigned_fract_type_node - || type == sat_unsigned_fract_type_node - || type == unsigned_accum_type_node - || type == sat_unsigned_accum_type_node) - write_char ('j'); - else if (type == short_fract_type_node - || type == sat_short_fract_type_node - || type == short_accum_type_node - || type == sat_short_accum_type_node) - write_char ('s'); - else if (type == unsigned_short_fract_type_node - || type == sat_unsigned_short_fract_type_node - || type == unsigned_short_accum_type_node - || type == sat_unsigned_short_accum_type_node) - write_char ('t'); - else if (type == long_fract_type_node - || type == sat_long_fract_type_node - || type == long_accum_type_node - || type == sat_long_accum_type_node) - write_char ('l'); - else if (type == unsigned_long_fract_type_node - || type == sat_unsigned_long_fract_type_node - || type == unsigned_long_accum_type_node - || type == sat_unsigned_long_accum_type_node) - write_char ('m'); - else if (type == long_long_fract_type_node - || type == sat_long_long_fract_type_node - || type == long_long_accum_type_node - || type == sat_long_long_accum_type_node) - write_char ('x'); - else if (type == unsigned_long_long_fract_type_node - || type == sat_unsigned_long_long_fract_type_node - || type == unsigned_long_long_accum_type_node - || type == sat_unsigned_long_long_accum_type_node) - write_char ('y'); - else - sorry ("mangling unknown fixed point type"); - write_unsigned_number (GET_MODE_FBIT (TYPE_MODE (type))); - if (TYPE_SATURATING (type)) - write_char ('s'); - else - write_char ('n'); - break; - default: gcc_unreachable (); } diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index bb83d1c..3dedd14 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -1129,6 +1129,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: @@ -19716,6 +19717,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; diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index 22d834d..4854b98 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -267,6 +267,133 @@ merge_type_attributes_from (tree type, tree other_type) return cp_build_type_attribute_variant (type, attrs); } +/* Compare floating point conversion ranks and subranks of T1 and T2 + types. If T1 and T2 have unordered conversion ranks, return 3. + If T1 has greater conversion rank than T2, return 2. + If T2 has greater conversion rank than T1, return -2. + If T1 has equal conversion rank as T2, return -1, 0 or 1 depending + on if T1 has smaller, equal or greater conversion subrank than + T2. */ + +int +cp_compare_floating_point_conversion_ranks (tree t1, tree t2) +{ + tree mv1 = TYPE_MAIN_VARIANT (t1); + tree mv2 = TYPE_MAIN_VARIANT (t2); + int extended1 = 0; + int extended2 = 0; + + if (mv1 == mv2) + return 0; + + for (int i = 0; i < NUM_FLOATN_NX_TYPES; ++i) + { + if (mv1 == FLOATN_NX_TYPE_NODE (i)) + extended1 = i + 1; + if (mv2 == FLOATN_NX_TYPE_NODE (i)) + extended2 = i + 1; + } + if (extended2 && !extended1) + { + int ret = cp_compare_floating_point_conversion_ranks (t2, t1); + return ret == 3 ? 3 : -ret; + } + + const struct real_format *fmt1 = REAL_MODE_FORMAT (TYPE_MODE (t1)); + const struct real_format *fmt2 = REAL_MODE_FORMAT (TYPE_MODE (t2)); + gcc_assert (fmt1->b == 2 && fmt2->b == 2); + /* For {ibm,mips}_extended_format formats, the type has variable + precision up to ~2150 bits when the first double is around maximum + representable double and second double is subnormal minimum. + So, e.g. for __ibm128 vs. std::float128_t, they have unordered + ranks. */ + int p1 = (MODE_COMPOSITE_P (TYPE_MODE (t1)) + ? fmt1->emax - fmt1->emin + fmt1->p - 1 : fmt1->p); + int p2 = (MODE_COMPOSITE_P (TYPE_MODE (t2)) + ? fmt2->emax - fmt2->emin + fmt2->p - 1 : fmt2->p); + /* The rank of a floating point type T is greater than the rank of + any floating-point type whose set of values is a proper subset + of the set of values of T. */ + if ((p1 > p2 && fmt1->emax >= fmt2->emax) + || (p1 == p2 && fmt1->emax > fmt2->emax)) + return 2; + if ((p1 < p2 && fmt1->emax <= fmt2->emax) + || (p1 == p2 && fmt1->emax < fmt2->emax)) + return -2; + if ((p1 > p2 && fmt1->emax < fmt2->emax) + || (p1 < p2 && fmt1->emax > fmt2->emax)) + return 3; + if (!extended1 && !extended2) + { + /* The rank of long double is greater than the rank of double, which + is greater than the rank of float. */ + if (t1 == long_double_type_node) + return 2; + else if (t2 == long_double_type_node) + return -2; + if (t1 == double_type_node) + return 2; + else if (t2 == double_type_node) + return -2; + if (t1 == float_type_node) + return 2; + else if (t2 == float_type_node) + return -2; + return 0; + } + /* Two extended floating-point types with the same set of values have equal + ranks. */ + if (extended1 && extended2) + { + if ((extended1 <= NUM_FLOATN_TYPES) == (extended2 <= NUM_FLOATN_TYPES)) + { + /* Prefer higher extendedN value. */ + if (extended1 > extended2) + return 1; + else if (extended1 < extended2) + return -1; + else + return 0; + } + else if (extended1 <= NUM_FLOATN_TYPES) + /* Prefer _FloatN type over _FloatMx type. */ + return 1; + else if (extended2 <= NUM_FLOATN_TYPES) + return -1; + else + return 0; + } + + /* gcc_assert (extended1 && !extended2); */ + tree *p; + int cnt = 0; + for (p = &float_type_node; p <= &long_double_type_node; ++p) + { + const struct real_format *fmt3 = REAL_MODE_FORMAT (TYPE_MODE (*p)); + gcc_assert (fmt3->b == 2); + int p3 = (MODE_COMPOSITE_P (TYPE_MODE (*p)) + ? fmt3->emax - fmt3->emin + fmt3->p - 1 : fmt3->p); + if (p1 == p3 && fmt1->emax == fmt3->emax) + ++cnt; + } + /* An extended floating-point type with the same set of values + as exactly one cv-unqualified standard floating-point type + has a rank equal to the rank of that standard floating-point + type. + + An extended floating-point type with the same set of values + as more than one cv-unqualified standard floating-point type + has a rank equal to the rank of double. + + Thus, if the latter is true and t2 is long double, t2 + has higher rank. */ + if (cnt > 1 && mv2 == long_double_type_node) + return -2; + /* Otherwise, they have equal rank, but extended types + (other than std::bfloat16_t) have higher subrank. */ + return 1; +} + /* Return the common type for two arithmetic types T1 and T2 under the usual arithmetic conversions. The default conversions have already been applied, and enumerated types converted to their compatible @@ -337,6 +464,23 @@ cp_common_type (tree t1, tree t2) if (code2 == REAL_TYPE && code1 != REAL_TYPE) return build_type_attribute_variant (t2, attributes); + if (code1 == REAL_TYPE + && (extended_float_type_p (t1) || extended_float_type_p (t2))) + { + tree mv1 = TYPE_MAIN_VARIANT (t1); + tree mv2 = TYPE_MAIN_VARIANT (t2); + if (mv1 == mv2) + return build_type_attribute_variant (t1, attributes); + + int cmpret = cp_compare_floating_point_conversion_ranks (mv1, mv2); + if (cmpret == 3) + return error_mark_node; + else if (cmpret >= 0) + return build_type_attribute_variant (t1, attributes); + else + return build_type_attribute_variant (t2, attributes); + } + /* Both real or both integers; use the one with greater precision. */ if (TYPE_PRECISION (t1) > TYPE_PRECISION (t2)) return build_type_attribute_variant (t1, attributes); @@ -5037,7 +5181,20 @@ cp_build_binary_op (const op_location_t &location, = targetm.invalid_binary_op (code, type0, type1))) { if (complain & tf_error) - error (invalid_op_diag); + { + if (code0 == REAL_TYPE + && code1 == REAL_TYPE + && (extended_float_type_p (type0) + || extended_float_type_p (type1)) + && cp_compare_floating_point_conversion_ranks (type0, + type1) == 3) + { + rich_location richloc (line_table, location); + binary_op_error (&richloc, code, type0, type1); + } + else + error (invalid_op_diag); + } return error_mark_node; } @@ -5907,6 +6064,19 @@ cp_build_binary_op (const op_location_t &location, && (shorten || common || short_compare)) { result_type = cp_common_type (type0, type1); + if (result_type == error_mark_node + && code0 == REAL_TYPE + && code1 == REAL_TYPE + && (extended_float_type_p (type0) || extended_float_type_p (type1)) + && cp_compare_floating_point_conversion_ranks (type0, type1) == 3) + { + if (complain & tf_error) + { + rich_location richloc (line_table, location); + binary_op_error (&richloc, code, type0, type1); + } + return error_mark_node; + } if (complain & tf_warning) { do_warn_double_promotion (result_type, type0, type1, diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc index 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/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 struct integral_constant { + static constexpr T value = v; + }; + typedef integral_constant false_type; + typedef integral_constant true_type; + template + struct is_same : std::false_type {}; + template + struct is_same : 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::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +#ifdef __SIZEOF_FLOAT128__ +static_assert (is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +#endif +#ifdef __STDCPP_FLOAT16_T__ +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +#endif +#ifdef __STDCPP_FLOAT32_T__ +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +#endif +#ifdef __STDCPP_FLOAT64_T__ +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +#endif +#ifdef __STDCPP_FLOAT128_T__ +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +#ifdef __SIZEOF_FLOAT128__ +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +#endif +#endif +#ifdef __STDCPP_BFLOAT16_T__ +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +#endif +#ifdef __FLT32X_MANT_DIG__ +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +#ifdef __STDCPP_FLOAT16_T__ +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +#endif +#ifdef __STDCPP_FLOAT32_T__ +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +#endif +#ifdef __STDCPP_FLOAT64_T__ +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +#endif +#ifdef __STDCPP_FLOAT128_T__ +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +#endif +#endif +#ifdef __FLT64X_MANT_DIG__ +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +#ifdef __STDCPP_FLOAT16_T__ +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +#endif +#ifdef __STDCPP_FLOAT32_T__ +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +#endif +#ifdef __STDCPP_FLOAT64_T__ +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +#endif +#ifdef __STDCPP_FLOAT128_T__ +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +#endif +#ifdef __SIZEOF_FLOAT128__ +static_assert (!is_same<_Float64x, __float128>::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +#endif +#endif +#ifdef __FLT128X_MANT_DIG__ +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +#ifdef __STDCPP_FLOAT16_T__ +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +#endif +#ifdef __STDCPP_FLOAT32_T__ +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +#endif +#ifdef __STDCPP_FLOAT64_T__ +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +#endif +#ifdef __STDCPP_FLOAT128_T__ +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +#endif +#ifdef __SIZEOF_FLOAT128__ +static_assert (!is_same<_Float128x, __float128>::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +static_assert (!is_same::value); +#endif +#endif +static_assert (is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +#if defined(__STDCPP_FLOAT16_T__) && defined(__STDCPP_FLOAT32_T__) +static_assert (!is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +#endif +#if defined(__STDCPP_FLOAT16_T__) && defined(__STDCPP_FLOAT64_T__) +static_assert (!is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +#endif +#if defined(__STDCPP_FLOAT16_T__) && defined(__STDCPP_FLOAT128_T__) +static_assert (!is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +#endif +#if defined(__STDCPP_FLOAT16_T__) && defined(__FLT32X_MANT_DIG__) +static_assert (is_same::value); +static_assert (is_same::value); +#endif +#if defined(__STDCPP_FLOAT16_T__) && defined(__FLT64X_MANT_DIG__) +static_assert (is_same::value); +static_assert (is_same::value); +#endif +#if defined(__STDCPP_FLOAT16_T__) && defined(__FLT128X_MANT_DIG__) +static_assert (is_same::value); +static_assert (is_same::value); +#endif +#if defined(__STDCPP_FLOAT32_T__) && defined(__STDCPP_FLOAT64_T__) +static_assert (!is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +#endif +#if defined(__STDCPP_FLOAT32_T__) && defined(__STDCPP_FLOAT128_T__) +static_assert (!is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +#endif +#if defined(__STDCPP_FLOAT32_T__) && defined(__FLT32X_MANT_DIG__) +static_assert (is_same::value); +static_assert (is_same::value); +#endif +#if defined(__STDCPP_FLOAT32_T__) && defined(__FLT64X_MANT_DIG__) +static_assert (is_same::value); +static_assert (is_same::value); +#endif +#if defined(__STDCPP_FLOAT32_T__) && defined(__FLT128X_MANT_DIG__) +static_assert (is_same::value); +static_assert (is_same::value); +#endif +#if defined(__STDCPP_FLOAT64_T__) && defined(__STDCPP_FLOAT128_T__) +static_assert (!is_same::value); +static_assert (is_same::value); +static_assert (is_same::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::value); +static_assert (is_same::value); +#endif +#if defined(__STDCPP_FLOAT64_T__) && defined(__FLT64X_MANT_DIG__) +static_assert (is_same::value); +static_assert (is_same::value); +#endif +#if defined(__STDCPP_FLOAT64_T__) && defined(__FLT128X_MANT_DIG__) +static_assert (is_same::value); +static_assert (is_same::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::value); +static_assert (is_same::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::value); +static_assert (is_same::value); +#endif +#if defined(__STDCPP_FLOAT128_T__) && defined(__FLT128X_MANT_DIG__) +static_assert (is_same::value); +static_assert (is_same::value); +#endif +#if defined(__STDCPP_BFLOAT16_T__) && defined(__STDCPP_FLOAT32_T__) +static_assert (!is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +#endif +#if defined(__STDCPP_BFLOAT16_T__) && defined(__STDCPP_FLOAT64_T__) +static_assert (!is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +#endif +#if defined(__STDCPP_BFLOAT16_T__) && defined(__STDCPP_FLOAT128_T__) +static_assert (!is_same::value); +static_assert (is_same::value); +static_assert (is_same::value); +#endif +#ifdef __STDCPP_FLOAT16_T__ +#if __FLT_MAX_EXP__ > __FLT16_MAX_EXP__ && __FLT_MANT_DIG__ > __FLT16_MANT_DIG__ +static_assert (is_same::value); +static_assert (is_same::value); +#endif +#if __DBL_MAX_EXP__ > __FLT16_MAX_EXP__ && __DBL_MANT_DIG__ > __FLT16_MANT_DIG__ +static_assert (is_same::value); +static_assert (is_same::value); +#endif +#if __LDBL_MAX_EXP__ > __FLT16_MAX_EXP__ && __LDBL_MANT_DIG__ > __FLT16_MANT_DIG__ +static_assert (is_same::value); +static_assert (is_same::value); +#endif +#endif +#ifdef __STDCPP_FLOAT32_T__ +#if __FLT_MAX_EXP__ == __FLT32_MAX_EXP__ && __FLT_MANT_DIG__ == __FLT32_MANT_DIG__ +static_assert (is_same::value); +static_assert (is_same::value); +#endif +#if __DBL_MAX_EXP__ > __FLT32_MAX_EXP__ && __DBL_MANT_DIG__ > __FLT32_MANT_DIG__ +static_assert (is_same::value); +static_assert (is_same::value); +#endif +#if __LDBL_MAX_EXP__ > __FLT32_MAX_EXP__ && __LDBL_MANT_DIG__ > __FLT32_MANT_DIG__ +static_assert (is_same::value); +static_assert (is_same::value); +#endif +#endif +#ifdef __STDCPP_FLOAT64_T__ +#if __FLT_MAX_EXP__ < __FLT64_MAX_EXP__ && __FLT_MANT_DIG__ < __FLT64_MANT_DIG__ +static_assert (is_same::value); +static_assert (is_same::value); +#endif +#if __DBL_MAX_EXP__ == __FLT64_MAX_EXP__ && __DBL_MANT_DIG__ == __FLT64_MANT_DIG__ +static_assert (is_same::value); +static_assert (is_same::value); +#endif +#if __LDBL_MAX_EXP__ > __FLT64_MAX_EXP__ && __LDBL_MANT_DIG__ > __FLT64_MANT_DIG__ +static_assert (is_same::value); +static_assert (is_same::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::value); +static_assert (is_same::value); +#endif +#endif +#ifdef __STDCPP_FLOAT128_T__ +#if __FLT_MAX_EXP__ < __FLT128_MAX_EXP__ && __FLT_MANT_DIG__ < __FLT128_MANT_DIG__ +static_assert (is_same::value); +static_assert (is_same::value); +#endif +#if __DBL_MAX_EXP__ < __FLT128_MAX_EXP__ && __DBL_MANT_DIG__ < __FLT128_MANT_DIG__ +static_assert (is_same::value); +static_assert (is_same::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::value); +static_assert (is_same::value); +#endif +#ifdef __SIZEOF_FLOAT128__ +static_assert (is_same::value); +static_assert (is_same::value); +#endif +#endif +#ifdef __STDCPP_BFLOAT16_T__ +#if __FLT_MAX_EXP__ > __BFLT16_MAX_EXP__ && __FLT_MANT_DIG__ > __BFLT16_MANT_DIG__ +static_assert (is_same::value); +static_assert (is_same::value); +#endif +#if __DBL_MAX_EXP__ > __BFLT16_MAX_EXP__ && __DBL_MANT_DIG__ > __BFLT16_MANT_DIG__ +static_assert (is_same::value); +static_assert (is_same::value); +#endif +#if __LDBL_MAX_EXP__ > __BFLT16_MAX_EXP__ && __LDBL_MANT_DIG__ > __BFLT16_MANT_DIG__ +static_assert (is_same::value); +static_assert (is_same::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 +#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++.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/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.cc b/gcc/tree.cc index 4165cbd..756c14f 100644 --- a/gcc/tree.cc +++ b/gcc/tree.cc @@ -9461,6 +9461,7 @@ build_common_tree_nodes (bool signed_char) layout_type (FLOATN_NX_TYPE_NODE (i)); SET_TYPE_MODE (FLOATN_NX_TYPE_NODE (i), mode); } + float128t_type_node = float128_type_node; float_ptr_type_node = build_pointer_type (float_type_node); double_ptr_type_node = build_pointer_type (double_type_node); diff --git a/gcc/tree.h b/gcc/tree.h index 266e24a..95285e4 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -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] -- cgit v1.1 From 5da546d7e0561def07c783e6ec897aaa9e7837c6 Mon Sep 17 00:00:00 2001 From: Jeff Law Date: Tue, 27 Sep 2022 01:44:38 -0400 Subject: Fix ICEs due to recent jump-to-return optimization gcc/ * cfgrtl.cc (fixup_reorder_chain): Verify that simple_return and return are available before trying to use them. --- gcc/cfgrtl.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'gcc') 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); -- cgit v1.1 From 5b86d5dbe47c477daf739b82c3793a70f8cbd96c Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 27 Sep 2022 08:20:05 +0200 Subject: c++: Improve diagnostics about conflicting specifiers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Sat, Sep 17, 2022 at 01:23:59AM +0200, Jason Merrill wrote: > I wonder why we don't give an error when setting the > conflicting_specifiers_p flag in cp_parser_set_storage_class? We should be > able to give a better diagnostic at that point. I didn't have time to update the whole patch last night, but this part seems to be independent and I've managed to test it. The diagnostics then looks like: a.C:1:9: error: ‘static’ specifier conflicts with ‘typedef’ 1 | typedef static int a; | ~~~~~~~ ^~~~~~ a.C:2:8: error: ‘typedef’ specifier conflicts with ‘static’ 2 | static typedef int b; | ~~~~~~ ^~~~~~~ a.C:3:8: error: duplicate ‘static’ specifier 3 | static static int c; | ~~~~~~ ^~~~~~ a.C:4:8: error: ‘extern’ specifier conflicts with ‘static’ 4 | static extern int d; | ~~~~~~ ^~~~~~ 2022-09-27 Jakub Jelinek gcc/cp/ * 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. gcc/testsuite/ * 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. --- gcc/cp/decl.cc | 7 +- gcc/cp/parser.cc | 88 +++++++++++++++------- gcc/testsuite/g++.dg/cpp2a/constinit3.C | 2 +- .../g++.dg/diagnostic/conflicting-specifiers-1.C | 2 +- gcc/testsuite/g++.dg/other/mult-stor1.C | 2 +- gcc/testsuite/g++.dg/parse/crash39.C | 2 +- gcc/testsuite/g++.dg/parse/typedef8.C | 10 +-- 7 files changed, 71 insertions(+), 42 deletions(-) (limited to 'gcc') diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 80467c1..f4460c9 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; diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 3dedd14..d876a86 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -11729,9 +11729,6 @@ 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) - error_at (lambda_specs.locations[ds_storage_class], - "duplicate %"); } tx_qual = cp_parser_tx_qualifier_opt (parser); @@ -15731,6 +15728,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: @@ -15952,8 +15956,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, + "% specifier conflicts with %qs", + cp_storage_class_name[decl_specs->storage_class]); + decl_specs->conflicting_specifiers_p = true; + } break; /* storage-class-specifier: @@ -32845,26 +32859,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: @@ -32885,6 +32879,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); @@ -32892,8 +32918,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 %", + ridpointers[keyword]); + decl_specs->conflicting_specifiers_p = true; + } } /* Update the DECL_SPECS to reflect the TYPE_SPEC. If TYPE_DEFINITION_P 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/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" } } -- cgit v1.1 From 4790fe99f236c7f1b617722403e682ba2f82485f Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 27 Sep 2022 08:23:08 +0200 Subject: openmp: Add OpenMP assume, assumes and begin/end assumes support The following patch implements OpenMP 5.1 #pragma omp assume #pragma omp assumes and #pragma omp begin assumes #pragma omp end assumes directive support for C and C++. Currently it doesn't remember anything from the assumption clauses for later, so is mainly to support the directives and diagnose errors in their use. If the recently posted C++23 [[assume (cond)]]; support makes it in, the intent is that this can be easily adjusted at least for the #pragma omp assume directive with holds clause(s) to use the same infrastructure. Now, C++23 portable assumptions are slightly different from OpenMP 5.1 assumptions' holds clause in that C++23 assumption holds just where it appears, while OpenMP 5.1 assumptions hold everywhere in the scope of the directive. For assumes directive which can appear at file or namespace scope it is the whole TU and everything that functions from there call at runtime, for begin assumes/end assumes pair all the functions in between those directives and everything they call and for assume directive the associated (currently structured) block. I have no idea how to represents such holds to be usable for optimizers, except to make #pragma omp assume holds (cond) block; expand essentially to [[assume (cond)]]; block; or [[assume (cond)]]; block; [[assume (cond)]]; for now. Except for holds clause, the other assumptions are OpenMP related, I'd say we should brainstorm where it would be useful to optimize based on such information (I guess e.g. in target regions it easily could) and only when we come up with something like that think about how to propagate the assumptions to the optimizers. 2022-09-27 Jakub Jelinek gcc/c-family/ * 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. gcc/c/ * 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. gcc/cp/ * 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. gcc/testsuite/ * 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. --- gcc/c-family/c-common.h | 1 + gcc/c-family/c-omp.cc | 42 +-- gcc/c-family/c-pragma.cc | 5 +- gcc/c-family/c-pragma.h | 5 +- gcc/c/c-decl.cc | 4 + gcc/c/c-lang.h | 3 + gcc/c/c-parser.cc | 308 +++++++++++++++++-- gcc/cp/cp-tree.h | 5 + gcc/cp/parser.cc | 340 +++++++++++++++++++-- gcc/cp/pt.cc | 1 + gcc/cp/semantics.cc | 7 + gcc/testsuite/c-c++-common/gomp/assume-1.c | 29 ++ gcc/testsuite/c-c++-common/gomp/assume-2.c | 46 +++ gcc/testsuite/c-c++-common/gomp/assume-3.c | 27 ++ gcc/testsuite/c-c++-common/gomp/assumes-1.c | 26 ++ gcc/testsuite/c-c++-common/gomp/assumes-2.c | 23 ++ gcc/testsuite/c-c++-common/gomp/assumes-3.c | 15 + gcc/testsuite/c-c++-common/gomp/assumes-4.c | 6 + gcc/testsuite/c-c++-common/gomp/begin-assumes-1.c | 46 +++ gcc/testsuite/c-c++-common/gomp/begin-assumes-2.c | 63 ++++ gcc/testsuite/c-c++-common/gomp/begin-assumes-3.c | 2 + gcc/testsuite/c-c++-common/gomp/begin-assumes-4.c | 2 + gcc/testsuite/c-c++-common/gomp/declare-target-6.c | 2 + gcc/testsuite/g++.dg/gomp/attrs-1.C | 15 +- gcc/testsuite/g++.dg/gomp/attrs-15.C | 41 +++ gcc/testsuite/g++.dg/gomp/attrs-16.C | 26 ++ gcc/testsuite/g++.dg/gomp/attrs-17.C | 17 ++ gcc/testsuite/g++.dg/gomp/attrs-2.C | 15 +- gcc/testsuite/g++.dg/gomp/attrs-9.C | 20 ++ 29 files changed, 1075 insertions(+), 67 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/gomp/assume-1.c create mode 100644 gcc/testsuite/c-c++-common/gomp/assume-2.c create mode 100644 gcc/testsuite/c-c++-common/gomp/assume-3.c create mode 100644 gcc/testsuite/c-c++-common/gomp/assumes-1.c create mode 100644 gcc/testsuite/c-c++-common/gomp/assumes-2.c create mode 100644 gcc/testsuite/c-c++-common/gomp/assumes-3.c create mode 100644 gcc/testsuite/c-c++-common/gomp/assumes-4.c create mode 100644 gcc/testsuite/c-c++-common/gomp/begin-assumes-1.c create mode 100644 gcc/testsuite/c-c++-common/gomp/begin-assumes-2.c create mode 100644 gcc/testsuite/c-c++-common/gomp/begin-assumes-3.c create mode 100644 gcc/testsuite/c-c++-common/gomp/begin-assumes-4.c create mode 100644 gcc/testsuite/c-c++-common/gomp/declare-target-6.c create mode 100644 gcc/testsuite/g++.dg/gomp/attrs-15.C create mode 100644 gcc/testsuite/g++.dg/gomp/attrs-16.C create mode 100644 gcc/testsuite/g++.dg/gomp/attrs-17.C (limited to 'gcc') 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-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/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 % 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 %"); + 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 %"); + 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 % or %"); + 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 % and " + "% 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/cp/cp-tree.h b/gcc/cp/cp-tree.h index 8779538..51fd0cf 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1834,6 +1834,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 +1885,7 @@ struct GTY(()) saved_scope { hash_map *GTY((skip)) x_local_specializations; vec *omp_declare_target_attribute; + vec *omp_begin_assumes; struct saved_scope *prev; }; diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index d876a86..4bd3ca1 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. */ @@ -46061,6 +46062,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 % and " + "% 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. */ @@ -46510,8 +46723,41 @@ cp_parser_omp_declare_target (cp_parser *parser, cp_token *pragma_tok) "directive with only % clauses ignored"); } +/* OpenMP 5.1 + #pragma omp begin assumes clauses[optseq] new-line */ + +static void +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 %"); + 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_declare_target (cp_parser *parser, cp_token *pragma_tok) +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; @@ -46537,33 +46783,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, + "% in attribute syntax terminated " + "with % in pragma syntax"); + else + error_at (pragma_tok->location, + "% in pragma syntax terminated " + "with % in attribute syntax"); + } + } } - else + else if (strcmp (p, "assumes") == 0) { - cp_parser_error (parser, "expected %"); - 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, + "% in attribute syntax terminated " + "with % in pragma syntax"); + else + error_at (pragma_tok->location, + "% in pragma syntax terminated " + "with % 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, - "% in attribute syntax terminated " - "with % in pragma syntax"); - else - error_at (pragma_tok->location, - "% in pragma syntax terminated " - "with % in attribute syntax"); - } + cp_parser_error (parser, "expected % or %"); + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return; } } @@ -47846,6 +48117,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 (); } @@ -48449,6 +48723,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: @@ -48483,6 +48758,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; @@ -48506,8 +48792,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..1c1e573 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -11945,6 +11945,7 @@ apply_late_template_attributes (tree *decl_p, tree attributes, int attr_flags, auto o3 = make_temp_override (current_target_pragma, NULL_TREE); auto o4 = make_temp_override (scope_chain->omp_declare_target_attribute, NULL); + auto o5 = make_temp_override (scope_chain->omp_begin_assumes, NULL); cplus_decl_attributes (decl_p, late_attrs, attr_flags); 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/testsuite/c-c++-common/gomp/assume-1.c b/gcc/testsuite/c-c++-common/gomp/assume-1.c new file mode 100644 index 0000000..05c64a8 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/assume-1.c @@ -0,0 +1,29 @@ +void +foo (int i, int *a) +{ + #pragma omp assume no_openmp, absent (target, teams) holds (i < 32U) holds (i < 32U) + ; + #pragma omp assume no_openmp_routines, contains (simd) + { + #pragma omp simd + for (int j = 0; j < i; j++) + a[j] = j; + } + #pragma omp assume no_parallelism, contains (error) + { + if (i >= 32) + { + #pragma omp error at (execution) message ("Should not happen") + } + } + #pragma omp assume absent (for) + ; + #pragma omp assume absent (atomic, barrier, cancel, cancellation point) absent (critical, depobj) + ; + #pragma omp assume absent (distribute, flush, loop, masked, master, nothing, ordered) + ; + #pragma omp assume absent (parallel, scan, scope, section, sections, simd, single, task) + ; + #pragma omp assume absent (taskgroup, taskloop, taskwait, taskyield) + ; +} diff --git a/gcc/testsuite/c-c++-common/gomp/assume-2.c b/gcc/testsuite/c-c++-common/gomp/assume-2.c new file mode 100644 index 0000000..4739605 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/assume-2.c @@ -0,0 +1,46 @@ +void +foo (int i, int *a) +{ + #pragma omp assume no_openmp no_openmp /* { dg-error "too many 'no_openmp' clauses" } */ + ; + #pragma omp assume no_openmp_routines, no_openmp_routines /* { dg-error "too many 'no_openmp_routines' clauses" } */ + ; + #pragma omp assume no_parallelism, no_parallelism /* { dg-error "too many 'no_parallelism' clauses" } */ + ; + #pragma omp assume absent (target, target) /* { dg-error "'target' directive mentioned multiple times in 'absent' clauses" } */ + ; + #pragma omp assume absent (target, teams) absent (teams, parallel) /* { dg-error "'teams' directive mentioned multiple times in 'absent' clauses" } */ + ; + #pragma omp assume contains (cancellation point, cancellation point) /* { dg-error "'cancellation point' directive mentioned multiple times in 'contains' clauses" } */ + ; + #pragma omp assume contains (target enter data, target exit data) contains (target exit data, parallel) /* { dg-error "target exit data' directive mentioned multiple times in 'contains' clauses" } */ + ; + #pragma omp assume absent (target enter data, target exit data) contains (target exit data, parallel) /* { dg-error "'target exit data' directive mentioned in both 'absent' and 'contains' clauses" } */ + ; + #pragma omp assume contains (target enter data, target exit data) absent (target enter data, parallel) /* { dg-error "'target enter data' directive mentioned in both 'absent' and 'contains' clauses" } */ + ; + #pragma omp assume contains (declare target) /* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */ + ; + #pragma omp assume absent (parallel for simd) /* { dg-error "unknown OpenMP directive name in 'absent' clause argument" } */ + ; + #pragma omp assume contains (target parallel) /* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */ + ; + #pragma omp assume absent (assume) /* { dg-error "unknown OpenMP directive name in 'absent' clause argument" } */ + ; + #pragma omp assume absent (assumes) /* { dg-error "unknown OpenMP directive name in 'absent' clause argument" } */ + ; + #pragma omp assume contains (begin assumes) /* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */ + ; + #pragma omp assume contains (end assumes) /* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */ + ; + #pragma omp assume contains (foo) /* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */ + ; + #pragma omp assume absent (target enter something) /* { dg-error "unknown OpenMP directive name in 'absent' clause argument" } */ + ; + #pragma omp assume foobar /* { dg-error "expected assumption clause" } */ + ; + #pragma omp assume ext_GCC_foobarbaz, ext_GCC_baz (1, 12, 1 < 17), no_parallelism /* { dg-warning "unknown assumption clause 'ext_GCC_foobarbaz'" } */ + ; /* { dg-warning "unknown assumption clause 'ext_GCC_baz'" "" { target *-*-* } .-1 } */ + #pragma omp assume /* { dg-error "expected at least one assumption clause" } */ + ; +} diff --git a/gcc/testsuite/c-c++-common/gomp/assume-3.c b/gcc/testsuite/c-c++-common/gomp/assume-3.c new file mode 100644 index 0000000..ce38359 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/assume-3.c @@ -0,0 +1,27 @@ +/* { dg-do run } */ +/* { dg-options "-fno-openmp -fopenmp-simd" } */ + +int i, j; + +int +foo (void) +{ + j = 1; + return 1; +} + +int +main () +{ + #pragma omp assume holds (i < 42) + ; + #pragma omp assume holds (++i == 1) + ; + if (i != 0) + __builtin_abort (); + #pragma omp assume holds (foo () == 1) + ; + if (j != 0) + __builtin_abort (); + return 0; +} diff --git a/gcc/testsuite/c-c++-common/gomp/assumes-1.c b/gcc/testsuite/c-c++-common/gomp/assumes-1.c new file mode 100644 index 0000000..8b3fb37 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/assumes-1.c @@ -0,0 +1,26 @@ +int i; + +#pragma omp assumes no_openmp, absent (target, teams) holds (i < 32U) holds (i < 32U) +void +bar (void) +{ +} + +#pragma omp assumes no_openmp_routines + +#pragma omp assumes no_parallelism + +#pragma omp assumes absent (for) +void +fred (void) +{ +} + +#pragma omp assumes absent (atomic, barrier, cancel, cancellation point) absent (critical, depobj) \ + absent (distribute, flush, loop, masked, master, nothing, ordered) \ + absent (parallel, scan, scope, section, sections, simd, single, task) \ + absent (taskgroup, taskloop, taskwait, taskyield) +void +foo (void) +{ +} diff --git a/gcc/testsuite/c-c++-common/gomp/assumes-2.c b/gcc/testsuite/c-c++-common/gomp/assumes-2.c new file mode 100644 index 0000000..924f323 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/assumes-2.c @@ -0,0 +1,23 @@ +#pragma omp assumes no_openmp no_openmp /* { dg-error "too many 'no_openmp' clauses" } */ +#pragma omp assumes no_openmp_routines, no_openmp_routines /* { dg-error "too many 'no_openmp_routines' clauses" } */ +#pragma omp assumes no_parallelism, no_parallelism /* { dg-error "too many 'no_parallelism' clauses" } */ +#pragma omp assumes absent (target, target) /* { dg-error "'target' directive mentioned multiple times in 'absent' clauses" } */ +#pragma omp assumes absent (target, teams) absent (teams, parallel) /* { dg-error "'teams' directive mentioned multiple times in 'absent' clauses" } */ +#pragma omp assumes contains (cancellation point, cancellation point) /* { dg-error "'cancellation point' directive mentioned multiple times in 'contains' clauses" } */ +#pragma omp assumes contains (target enter data, target exit data) contains (target exit data, parallel) /* { dg-error "target exit data' directive mentioned multiple times in 'contains' clauses" } */ +#pragma omp assumes absent (target enter data, target exit data) contains (target exit data, parallel) /* { dg-error "'target exit data' directive mentioned in both 'absent' and 'contains' clauses" } */ +#pragma omp assumes contains (target enter data, target exit data) absent (target enter data, parallel) /* { dg-error "'target enter data' directive mentioned in both 'absent' and 'contains' clauses" } */ +#pragma omp assumes contains (declare target) /* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */ +#pragma omp assumes absent (parallel for simd) /* { dg-error "unknown OpenMP directive name in 'absent' clause argument" } */ +#pragma omp assumes contains (target parallel) /* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */ +#pragma omp assumes absent (assume) /* { dg-error "unknown OpenMP directive name in 'absent' clause argument" } */ +#pragma omp assumes absent (assumes) /* { dg-error "unknown OpenMP directive name in 'absent' clause argument" } */ +#pragma omp assumes contains (begin assumes) /* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */ +#pragma omp assumes contains (end assumes) /* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */ +#pragma omp assumes contains (foo) /* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */ +#pragma omp assumes absent (target enter something) /* { dg-error "unknown OpenMP directive name in 'absent' clause argument" } */ +#pragma omp assumes foobar /* { dg-error "expected assumption clause" } */ +#pragma omp assumes ext_GCC_foobarbaz, ext_GCC_baz (1, 12, 1 < 17), no_parallelism /* { dg-warning "unknown assumption clause 'ext_GCC_foobarbaz'" } */ + /* { dg-warning "unknown assumption clause 'ext_GCC_baz'" "" { target *-*-* } .-1 } */ +#pragma omp assumes /* { dg-error "expected at least one assumption clause" } */ +int i; diff --git a/gcc/testsuite/c-c++-common/gomp/assumes-3.c b/gcc/testsuite/c-c++-common/gomp/assumes-3.c new file mode 100644 index 0000000..0bfadac --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/assumes-3.c @@ -0,0 +1,15 @@ +#pragma omp assumes contains (simd) +#pragma omp assumes contains (error) +#pragma omp assumes contains (simd) + +void +foo (int i, int *a) +{ + #pragma omp simd + for (int j = 0; j < i; j++) + a[j] = j; + if (i >= 32) + { + #pragma omp error at (execution) message ("Should not happen") + } +} diff --git a/gcc/testsuite/c-c++-common/gomp/assumes-4.c b/gcc/testsuite/c-c++-common/gomp/assumes-4.c new file mode 100644 index 0000000..6e77adb --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/assumes-4.c @@ -0,0 +1,6 @@ +void +foo (void) +{ + #pragma omp assumes no_openmp /* { dg-error "'#pragma omp assumes' may only be used at file scope" "" { target c } } */ + ; /* { dg-error "'#pragma omp assumes' may only be used at file or namespace scope" "" { target c++ } .-1 } */ +} diff --git a/gcc/testsuite/c-c++-common/gomp/begin-assumes-1.c b/gcc/testsuite/c-c++-common/gomp/begin-assumes-1.c new file mode 100644 index 0000000..c3332b1 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/begin-assumes-1.c @@ -0,0 +1,46 @@ +int i; + +#pragma omp begin assumes no_openmp, absent (target, teams) holds (i < 32U) holds (i < 32U) +void +bar (void) +{ +} +#pragma omp end assumes + +#pragma omp begin assumes no_openmp_routines, contains (simd) +void +baz (int *a) +{ + #pragma omp simd + for (int j = 0; j < i; j++) + a[j] = j; +} +#pragma omp end assumes + +#pragma omp begin assumes no_parallelism, contains (error) +void +qux (void) +{ + if (i >= 32) + { + #pragma omp error at (execution) message ("Should not happen") + } +} +#pragma omp end assumes + +#pragma omp begin assumes absent (for) +void +fred (void) +{ +} +#pragma omp end assumes + +#pragma omp begin assumes absent (atomic, barrier, cancel, cancellation point) absent (critical, depobj) \ + absent (distribute, flush, loop, masked, master, nothing, ordered) \ + absent (parallel, scan, scope, section, sections, simd, single, task) \ + absent (taskgroup, taskloop, taskwait, taskyield) +void +foo (void) +{ +} +#pragma omp end assumes diff --git a/gcc/testsuite/c-c++-common/gomp/begin-assumes-2.c b/gcc/testsuite/c-c++-common/gomp/begin-assumes-2.c new file mode 100644 index 0000000..15dae64 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/begin-assumes-2.c @@ -0,0 +1,63 @@ +#pragma omp begin assumes no_openmp no_openmp /* { dg-error "too many 'no_openmp' clauses" } */ +void f1 (void) {} +#pragma omp end assumes +#pragma omp begin assumes no_openmp_routines, no_openmp_routines /* { dg-error "too many 'no_openmp_routines' clauses" } */ +void f2 (void) {} +#pragma omp end assumes +#pragma omp begin assumes no_parallelism, no_parallelism /* { dg-error "too many 'no_parallelism' clauses" } */ +void f3 (void) {} +#pragma omp end assumes +#pragma omp begin assumes absent (target, target) /* { dg-error "'target' directive mentioned multiple times in 'absent' clauses" } */ +void f4 (void) {} +#pragma omp end assumes +#pragma omp begin assumes absent (target, teams) absent (teams, parallel) /* { dg-error "'teams' directive mentioned multiple times in 'absent' clauses" } */ +void f5 (void) {} +#pragma omp end assumes +#pragma omp begin assumes contains (cancellation point, cancellation point) /* { dg-error "'cancellation point' directive mentioned multiple times in 'contains' clauses" } */ +void f6 (void) {} +#pragma omp end assumes +#pragma omp begin assumes contains (target enter data, target exit data) contains (target exit data, parallel) /* { dg-error "target exit data' directive mentioned multiple times in 'contains' clauses" } */ +void f7 (void) {} +#pragma omp end assumes +#pragma omp begin assumes absent (target enter data, target exit data) contains (target exit data, parallel) /* { dg-error "'target exit data' directive mentioned in both 'absent' and 'contains' clauses" } */ +void f8 (void) {} +#pragma omp end assumes +#pragma omp begin assumes contains (target enter data, target exit data) absent (target enter data, parallel) /* { dg-error "'target enter data' directive mentioned in both 'absent' and 'contains' clauses" } */ +void f9 (void) {} +#pragma omp end assumes +#pragma omp begin assumes contains (declare target) /* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */ +void f10 (void) {} +#pragma omp end assumes +#pragma omp begin assumes absent (parallel for simd) /* { dg-error "unknown OpenMP directive name in 'absent' clause argument" } */ +void f11 (void) {} +#pragma omp end assumes +#pragma omp begin assumes contains (target parallel) /* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */ +void f12 (void) {} +#pragma omp end assumes +#pragma omp begin assumes absent (assume) /* { dg-error "unknown OpenMP directive name in 'absent' clause argument" } */ +void f13 (void) {} +#pragma omp end assumes +#pragma omp begin assumes absent (assumes) /* { dg-error "unknown OpenMP directive name in 'absent' clause argument" } */ +void f14 (void) {} +#pragma omp end assumes +#pragma omp begin assumes contains (begin assumes) /* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */ +void f15 (void) {} +#pragma omp end assumes +#pragma omp begin assumes contains (end assumes) /* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */ +void f16 (void) {} +#pragma omp end assumes +#pragma omp begin assumes contains (foo) /* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */ +void f17 (void) {} +#pragma omp end assumes +#pragma omp begin assumes absent (target enter something) /* { dg-error "unknown OpenMP directive name in 'absent' clause argument" } */ +void f18 (void) {} +#pragma omp end assumes +#pragma omp begin assumes foobar /* { dg-error "expected assumption clause" } */ +void f19 (void) {} +#pragma omp end assumes +#pragma omp begin assumes ext_GCC_foobarbaz, ext_GCC_baz (1, 12, 1 < 17), no_parallelism /* { dg-warning "unknown assumption clause 'ext_GCC_foobarbaz'" } */ +void f20 (void) {} /* { dg-warning "unknown assumption clause 'ext_GCC_baz'" "" { target *-*-* } .-1 } */ +#pragma omp end assumes +#pragma omp begin assumes /* { dg-error "expected at least one assumption clause" } */ +void f21 (void) {} +#pragma omp end assumes diff --git a/gcc/testsuite/c-c++-common/gomp/begin-assumes-3.c b/gcc/testsuite/c-c++-common/gomp/begin-assumes-3.c new file mode 100644 index 0000000..202d5c7 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/begin-assumes-3.c @@ -0,0 +1,2 @@ +#pragma omp begin assumes no_openmp_routines +void foo (void); /* { dg-error "'#pragma omp begin assumes' without corresponding '#pragma omp end assumes'" } */ diff --git a/gcc/testsuite/c-c++-common/gomp/begin-assumes-4.c b/gcc/testsuite/c-c++-common/gomp/begin-assumes-4.c new file mode 100644 index 0000000..eea6f90 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/begin-assumes-4.c @@ -0,0 +1,2 @@ +#pragma omp end assumes /* { dg-error "'#pragma omp end assumes' without corresponding '#pragma omp begin assumes'" } */ +void foo (void); diff --git a/gcc/testsuite/c-c++-common/gomp/declare-target-6.c b/gcc/testsuite/c-c++-common/gomp/declare-target-6.c new file mode 100644 index 0000000..586eb50 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/declare-target-6.c @@ -0,0 +1,2 @@ +#pragma omp end declare target /* { dg-error "'#pragma omp end declare target' without corresponding '#pragma omp declare target'" } */ +void foo (void); diff --git a/gcc/testsuite/g++.dg/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))]]; -- cgit v1.1 From cb8f25c5dc9f6d5207c826c2dafe25f68458ceaf Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 27 Sep 2022 08:26:18 +0200 Subject: reassoc: Handle OFFSET_TYPE like POINTER_TYPE in optimize_range_tests_cmp_bitwise [PR107029[ As the testcase shows, OFFSET_TYPE needs the same treatment as POINTER_TYPE/REFERENCE_TYPE, otherwise we fail the same during the newly added verification. OFFSET_TYPE is signed though, so unlike POINTER_TYPE/REFERENCE_TYPE it can also trigger with the x < 0 && y < 0 && z < 0 to (x | y | z) < 0 optimization. 2022-09-27 Jakub Jelinek 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. * g++.dg/torture/pr107029.C: New test. --- gcc/testsuite/g++.dg/torture/pr107029.C | 19 +++++++++++++++++++ gcc/tree-ssa-reassoc.cc | 21 ++++++++++++++++----- 2 files changed, 35 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/g++.dg/torture/pr107029.C (limited to 'gcc') 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/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); -- cgit v1.1 From 303976a6076f2839354702fd2caa049fa7cbbdc2 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 27 Sep 2022 08:36:28 +0200 Subject: c++: Implement C++23 P1169R4 - static operator() [PR106651] The following patch attempts to implement C++23 P1169R4 - static operator() paper's compiler side (there is some small library side too not implemented yet). This allows static members as user operator() declarations and static specifier on lambdas without lambda capture. The synthetized conversion operator changes for static lambdas as it can just return the operator() static method address, doesn't need to create a thunk for it. The change in call.cc (joust) is to avoid ICEs because we assumed that len could be different only if both candidates are direct calls but it can be one direct and one indirect call, and to implement the [over.match.best.general]/1 and [over.best.ics.general] changes from the paper (implemented always as Jason is sure it doesn't make a difference in C++20 and earlier unless static member function operator() or static lambda which we accept with pedwarn in earlier standards too appears and my testing confirmed that). 2022-09-27 Jakub Jelinek PR c++/106651 gcc/c-family/ * c-cppbuiltin.cc (c_cpp_builtins): Predefine __cpp_static_call_operator=202207L for C++23. gcc/cp/ * 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. gcc/testsuite/ * 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. --- gcc/c-family/c-cppbuiltin.cc | 1 + gcc/cp/call.cc | 25 ++++-- gcc/cp/cp-tree.h | 5 ++ gcc/cp/decl.cc | 19 ++++- gcc/cp/error.cc | 8 +- gcc/cp/lambda.cc | 89 +++++++++++++++++----- gcc/cp/parser.cc | 36 +++++++-- gcc/testsuite/g++.dg/cpp1z/constexpr-lambda13.C | 2 +- gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C | 6 ++ gcc/testsuite/g++.dg/cpp23/static-operator-call1.C | 41 ++++++++++ gcc/testsuite/g++.dg/cpp23/static-operator-call2.C | 22 ++++++ gcc/testsuite/g++.dg/cpp23/static-operator-call3.C | 10 +++ gcc/testsuite/g++.dg/template/error30.C | 2 +- gcc/testsuite/g++.old-deja/g++.jason/operator.C | 2 +- 14 files changed, 235 insertions(+), 33 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp23/static-operator-call1.C create mode 100644 gcc/testsuite/g++.dg/cpp23/static-operator-call2.C create mode 100644 gcc/testsuite/g++.dg/cpp23/static-operator-call3.C (limited to 'gcc') diff --git a/gcc/c-family/c-cppbuiltin.cc b/gcc/c-family/c-cppbuiltin.cc index e3f4d3d..ca5f500 100644 --- a/gcc/c-family/c-cppbuiltin.cc +++ b/gcc/c-family/c-cppbuiltin.cc @@ -1081,6 +1081,7 @@ c_cpp_builtins (cpp_reader *pfile) cpp_define (pfile, "__cpp_constexpr=202110L"); cpp_define (pfile, "__cpp_multidimensional_subscript=202110L"); cpp_define (pfile, "__cpp_named_character_escapes=202207L"); + cpp_define (pfile, "__cpp_static_call_operator=202207L"); } if (flag_concepts) { diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 3b7e527..fc86b74 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -12261,10 +12261,14 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn, len = cand1->num_convs; if (len != cand2->num_convs) { - int static_1 = DECL_STATIC_FUNCTION_P (cand1->fn); - int static_2 = DECL_STATIC_FUNCTION_P (cand2->fn); - - if (DECL_CONSTRUCTOR_P (cand1->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 (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. */ @@ -12273,9 +12277,20 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn, gcc_assert (static_1 != static_2); if (static_1) - off2 = 1; + { + /* C++23 [over.best.ics.general] says: + When the parameter is the implicit object parameter of a static + member function, the implicit conversion sequence is a standard + conversion sequence that is neither better nor worse than any + other standard conversion sequence. */ + if (CONVERSION_RANK (cand2->convs[0]) >= cr_user) + winner = 1; + off2 = 1; + } else { + if (CONVERSION_RANK (cand1->convs[0]) >= cr_user) + winner = -1; off1 = 1; --len; } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 51fd0cf..99b486b8 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -504,6 +504,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; OVL_NESTED_P (in OVERLOAD) DECL_MODULE_EXPORT_P (in _DECL) PACK_EXPANSION_FORCE_EXTRA_ARGS_P (in *_PACK_EXPANSION) + LAMBDA_EXPR_STATIC_P (in LAMBDA_EXPR) 4: IDENTIFIER_MARKED (IDENTIFIER_NODEs) TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR, CALL_EXPR, or FIELD_DECL). @@ -1490,6 +1491,10 @@ enum cp_lambda_default_capture_mode_type { #define LAMBDA_EXPR_CAPTURE_OPTIMIZED(NODE) \ TREE_LANG_FLAG_2 (LAMBDA_EXPR_CHECK (NODE)) +/* Predicate tracking whether the lambda was declared 'static'. */ +#define LAMBDA_EXPR_STATIC_P(NODE) \ + TREE_LANG_FLAG_3 (LAMBDA_EXPR_CHECK (NODE)) + /* True if this TREE_LIST in LAMBDA_EXPR_CAPTURE_LIST is for an explicit capture. */ #define LAMBDA_CAPTURE_EXPLICIT_P(NODE) \ diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index f4460c9..fb85564 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -15300,8 +15300,25 @@ grok_op_properties (tree decl, bool complain) an enumeration, or a reference to an enumeration. 13.4.0.6 */ if (! methodp || DECL_STATIC_FUNCTION_P (decl)) { + if (operator_code == CALL_EXPR) + { + if (! DECL_STATIC_FUNCTION_P (decl)) + { + error_at (loc, "%qD must be a member function", decl); + return false; + } + if (cxx_dialect < cxx23 + /* For lambdas we diagnose static lambda specifier elsewhere. */ + && ! LAMBDA_FUNCTION_P (decl) + /* For instantiations, we have diagnosed this already. */ + && ! DECL_USE_TEMPLATE (decl)) + pedwarn (loc, OPT_Wc__23_extensions, "%qD may be a static member " + "function only with %<-std=c++23%> or %<-std=gnu++23%>", decl); + /* There are no further restrictions on the arguments to an + overloaded "operator ()". */ + return true; + } if (operator_code == TYPE_EXPR - || operator_code == CALL_EXPR || operator_code == COMPONENT_REF || operator_code == ARRAY_REF || operator_code == NOP_EXPR) diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc index 94181e7..0389f35 100644 --- a/gcc/cp/error.cc +++ b/gcc/cp/error.cc @@ -1692,7 +1692,13 @@ dump_lambda_function (cxx_pretty_printer *pp, { /* A lambda's signature is essentially its "type". */ dump_type (pp, DECL_CONTEXT (fn), flags); - if (!(TYPE_QUALS (class_of_this_parm (TREE_TYPE (fn))) & TYPE_QUAL_CONST)) + if (TREE_CODE (TREE_TYPE (fn)) == FUNCTION_TYPE) + { + pp->padding = pp_before; + pp_c_ws_string (pp, "static"); + } + else if (!(TYPE_QUALS (class_of_this_parm (TREE_TYPE (fn))) + & TYPE_QUAL_CONST)) { pp->padding = pp_before; pp_c_ws_string (pp, "mutable"); diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc index 3ee1fe9..e9d5d4d 100644 --- a/gcc/cp/lambda.cc +++ b/gcc/cp/lambda.cc @@ -1099,7 +1099,9 @@ maybe_add_lambda_conv_op (tree type) tree optype = TREE_TYPE (callop); tree fn_result = TREE_TYPE (optype); - tree thisarg = build_int_cst (TREE_TYPE (DECL_ARGUMENTS (callop)), 0); + tree thisarg = NULL_TREE; + if (TREE_CODE (optype) == METHOD_TYPE) + thisarg = build_int_cst (TREE_TYPE (DECL_ARGUMENTS (callop)), 0); if (generic_lambda_p) { ++processing_template_decl; @@ -1109,18 +1111,25 @@ maybe_add_lambda_conv_op (tree type) return expression for a deduced return call op to allow for simple implementation of the conversion operator. */ - tree instance = cp_build_fold_indirect_ref (thisarg); - tree objfn = lookup_template_function (DECL_NAME (callop), - DECL_TI_ARGS (callop)); - objfn = build_min (COMPONENT_REF, NULL_TREE, - instance, objfn, NULL_TREE); - int nargs = list_length (DECL_ARGUMENTS (callop)) - 1; + tree objfn; + int nargs = list_length (DECL_ARGUMENTS (callop)); + if (thisarg) + { + tree instance = cp_build_fold_indirect_ref (thisarg); + objfn = lookup_template_function (DECL_NAME (callop), + DECL_TI_ARGS (callop)); + objfn = build_min (COMPONENT_REF, NULL_TREE, + instance, objfn, NULL_TREE); + --nargs; + call = prepare_op_call (objfn, nargs); + } + else + objfn = callop; - call = prepare_op_call (objfn, nargs); if (type_uses_auto (fn_result)) decltype_call = prepare_op_call (objfn, nargs); } - else + else if (thisarg) { direct_argvec = make_tree_vector (); direct_argvec->quick_push (thisarg); @@ -1135,9 +1144,11 @@ maybe_add_lambda_conv_op (tree type) tree fn_args = NULL_TREE; { int ix = 0; - tree src = DECL_CHAIN (DECL_ARGUMENTS (callop)); + tree src = FUNCTION_FIRST_USER_PARM (callop); tree tgt = NULL; + if (!thisarg && !decltype_call) + src = NULL_TREE; while (src) { tree new_node = copy_node (src); @@ -1160,12 +1171,15 @@ maybe_add_lambda_conv_op (tree type) if (generic_lambda_p) { tree a = tgt; - if (DECL_PACK_P (tgt)) + if (thisarg) { - a = make_pack_expansion (a); - PACK_EXPANSION_LOCAL_P (a) = true; + if (DECL_PACK_P (tgt)) + { + a = make_pack_expansion (a); + PACK_EXPANSION_LOCAL_P (a) = true; + } + CALL_EXPR_ARG (call, ix) = a; } - CALL_EXPR_ARG (call, ix) = a; if (decltype_call) { @@ -1193,7 +1207,7 @@ maybe_add_lambda_conv_op (tree type) tf_warning_or_error); } } - else + else if (thisarg) { /* Don't warn on deprecated or unavailable lambda declarations, unless the lambda is actually called. */ @@ -1203,10 +1217,14 @@ maybe_add_lambda_conv_op (tree type) direct_argvec->address ()); } - CALL_FROM_THUNK_P (call) = 1; - SET_EXPR_LOCATION (call, UNKNOWN_LOCATION); + if (thisarg) + { + CALL_FROM_THUNK_P (call) = 1; + SET_EXPR_LOCATION (call, UNKNOWN_LOCATION); + } - tree stattype = build_function_type (fn_result, FUNCTION_ARG_CHAIN (callop)); + tree stattype + = build_function_type (fn_result, FUNCTION_FIRST_USER_PARMTYPE (callop)); stattype = (cp_build_type_attribute_variant (stattype, TYPE_ATTRIBUTES (optype))); if (flag_noexcept_type @@ -1249,6 +1267,41 @@ maybe_add_lambda_conv_op (tree type) add_method (type, fn, false); + if (thisarg == NULL_TREE) + { + /* For static lambda, just return operator(). */ + if (nested) + push_function_context (); + else + /* Still increment function_depth so that we don't GC in the + middle of an expression. */ + ++function_depth; + + /* Generate the body of the conversion op. */ + + start_preparsed_function (convfn, NULL_TREE, + SF_PRE_PARSED | SF_INCLASS_INLINE); + tree body = begin_function_body (); + tree compound_stmt = begin_compound_stmt (0); + + /* decl_needed_p needs to see that it's used. */ + TREE_USED (callop) = 1; + finish_return_stmt (decay_conversion (callop, tf_warning_or_error)); + + finish_compound_stmt (compound_stmt); + finish_function_body (body); + + fn = finish_function (/*inline_p=*/true); + if (!generic_lambda_p) + expand_or_defer_fn (fn); + + if (nested) + pop_function_context (); + else + --function_depth; + return; + } + /* Generic thunk code fails for varargs; we'll complain in mark_used if the conversion op is used. */ if (varargs_function_p (callop)) diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 4bd3ca1..d501178 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -1996,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, @@ -11731,6 +11731,18 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) LAMBDA_EXPR_MUTABLE_P (lambda_expr) = 1; quals = TYPE_UNQUALIFIED; } + 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], + "% lambda specifier with lambda capture"); + else + { + LAMBDA_EXPR_STATIC_P (lambda_expr) = 1; + quals = TYPE_UNQUALIFIED; + } + } tx_qual = cp_parser_tx_qualifier_opt (parser); if (omitted_parms_loc && tx_qual) @@ -11816,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); @@ -11839,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) @@ -16034,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); 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/feat-cxx2b.C b/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C index 0537e1d..2f6b21e 100644 --- a/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C +++ b/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C @@ -563,3 +563,9 @@ #elif __cpp_named_character_escapes != 202207 # error "__cpp_named_character_escapes != 202207" #endif + +#ifndef __cpp_static_call_operator +# error "__cpp_static_call_operator" +#elif __cpp_static_call_operator != 202207 +# error "__cpp_static_call_operator != 202207" +#endif diff --git a/gcc/testsuite/g++.dg/cpp23/static-operator-call1.C b/gcc/testsuite/g++.dg/cpp23/static-operator-call1.C new file mode 100644 index 0000000..42219bf --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/static-operator-call1.C @@ -0,0 +1,41 @@ +// P1169R4 - static operator() +// { dg-do compile { target c++11 } } +// { dg-options "" } + +template +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 {} (1, 2), ""); + +template +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 = [](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 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/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 struct A; -template class B> A::x> operator() (); // { dg-error "51:.A::x> operator\\(\\)\\(\\). must be a non-static member function" } +template class B> A::x> operator() (); // { dg-error "51:.A::x> operator\\(\\)\\(\\). must be a member function" } 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" } -- cgit v1.1 From 1db05e1a1c1ee3d8a95826d477173fb7c557c002 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Tue, 27 Sep 2022 08:00:40 +0200 Subject: Add an irange setter for wide_ints. Just the same way as we have real_value setters for franges, we should have a wide_int version for irange. This matches the irange constructor for wide_ints, and paves the way for the eventual conversion of irange to wide ints. gcc/ChangeLog: * value-range.h (irange::set): New version taking wide_int_ref. --- gcc/value-range.h | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'gcc') 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 { -- cgit v1.1 From be4a6551ed37c1e7dbdfb9400fc2e2b5d40c5be2 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Tue, 27 Sep 2022 08:05:30 +0200 Subject: irange: keep better track of powers of 2. When setting the nonzero bits to a mask containing only one bit, set the range immediately, as it can be devined from the mask. This helps us keep better track of powers of two. For example, with this patch a nonzero mask of 0x8000 is set to a range of [0,0][0x8000,0x8000] with a nonzero mask of 0x8000. gcc/ChangeLog: * value-range.cc (irange::set_nonzero_bits): Set range when known. gcc/testsuite/ChangeLog: * gcc.dg/tree-ssa/popcount6.c: New test. --- gcc/testsuite/gcc.dg/tree-ssa/popcount6.c | 12 ++++++++++++ gcc/value-range.cc | 13 +++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/popcount6.c (limited to 'gcc') 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/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)); } -- cgit v1.1 From c8dfa79c9948ce09a7b4071f8059294b1972aef6 Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Tue, 27 Sep 2022 10:43:32 +0200 Subject: d: Merge upstream dmd d579c467c1, phobos 88aa69b14. D front-end changes: - Throwing from contracts of `nothrow' functions has been deprecated, as this breaks the guarantees of `nothrow'. - Added language support for initializing the interior pointer of associative arrays using `new' keyword. Phobos changes: - The std.digest.digest module has been removed. - The std.xml module has been removed. gcc/d/ChangeLog: * 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. libphobos/ChangeLog: * 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. --- gcc/d/decl.cc | 2 +- gcc/d/dmd/MERGE | 2 +- gcc/d/dmd/aggregate.d | 13 +- gcc/d/dmd/aggregate.h | 2 +- gcc/d/dmd/apply.d | 25 +- gcc/d/dmd/arrayop.d | 12 +- gcc/d/dmd/attrib.d | 4 +- gcc/d/dmd/canthrow.d | 6 +- gcc/d/dmd/chkformat.d | 600 ++++++------------- gcc/d/dmd/clone.d | 6 +- gcc/d/dmd/cparse.d | 19 +- gcc/d/dmd/dcast.d | 4 +- gcc/d/dmd/declaration.h | 4 +- gcc/d/dmd/dimport.d | 7 +- gcc/d/dmd/dinterpret.d | 12 +- gcc/d/dmd/dmangle.d | 17 + gcc/d/dmd/doc.d | 4 +- gcc/d/dmd/dsymbol.d | 6 + gcc/d/dmd/dsymbol.h | 2 +- gcc/d/dmd/dsymbolsem.d | 48 +- gcc/d/dmd/dtemplate.d | 71 ++- gcc/d/dmd/escape.d | 5 +- gcc/d/dmd/expression.d | 20 + gcc/d/dmd/expression.h | 22 +- gcc/d/dmd/expressionsem.d | 92 +-- gcc/d/dmd/func.d | 19 +- gcc/d/dmd/iasmgcc.d | 8 +- gcc/d/dmd/id.d | 2 + gcc/d/dmd/init.d | 1 + gcc/d/dmd/init.h | 1 + gcc/d/dmd/initsem.d | 553 ++++++++++-------- gcc/d/dmd/lexer.d | 9 +- gcc/d/dmd/module.h | 2 +- gcc/d/dmd/mtype.d | 649 +++++++++++---------- gcc/d/dmd/mtype.h | 4 +- gcc/d/dmd/opover.d | 9 +- gcc/d/dmd/parse.d | 102 +++- gcc/d/dmd/root/object.h | 2 +- gcc/d/dmd/semantic3.d | 40 +- gcc/d/dmd/transitivevisitor.d | 73 ++- gcc/d/dmd/typesem.d | 18 +- gcc/d/expr.cc | 33 +- gcc/d/runtime.def | 5 +- gcc/testsuite/gdc.test/compilable/commontype.d | 20 +- .../gdc.test/compilable/imports/cimports2a.i | 4 + .../gdc.test/compilable/imports/cimports2b.i | 4 + .../gdc.test/compilable/imports/format23327.d | 7 + .../compilable/imports/format23327/write.d | 0 gcc/testsuite/gdc.test/compilable/segfaultgolf.d | 50 ++ .../gdc.test/compilable/statictemplatethis.d | 45 ++ gcc/testsuite/gdc.test/compilable/test13123.d | 38 ++ gcc/testsuite/gdc.test/compilable/test21243.d | 21 + gcc/testsuite/gdc.test/compilable/test21956.d | 16 + gcc/testsuite/gdc.test/compilable/test22674.d | 10 + gcc/testsuite/gdc.test/compilable/test23173.d | 6 + gcc/testsuite/gdc.test/compilable/test23258.d | 21 + gcc/testsuite/gdc.test/compilable/test23306.d | 7 + gcc/testsuite/gdc.test/compilable/test23327.d | 3 + gcc/testsuite/gdc.test/compilable/vararg.d | 20 + .../gdc.test/fail_compilation/diag10169.d | 2 +- .../gdc.test/fail_compilation/diag10783.d | 2 +- .../gdc.test/fail_compilation/diag13528.d | 6 +- .../gdc.test/fail_compilation/diag14145.d | 2 +- .../gdc.test/fail_compilation/diag15713.d | 2 +- .../gdc.test/fail_compilation/diag23355.d | 16 + gcc/testsuite/gdc.test/fail_compilation/diag3438.d | 5 +- .../gdc.test/fail_compilation/diag3438b.d | 9 - gcc/testsuite/gdc.test/fail_compilation/diag8894.d | 8 +- gcc/testsuite/gdc.test/fail_compilation/dip22a.d | 8 +- gcc/testsuite/gdc.test/fail_compilation/e15876_1.d | 15 +- gcc/testsuite/gdc.test/fail_compilation/e15876_3.d | 30 +- gcc/testsuite/gdc.test/fail_compilation/e15876_4.d | 26 +- .../gdc.test/fail_compilation/fail10968.d | 31 +- gcc/testsuite/gdc.test/fail_compilation/fail121.d | 4 +- .../gdc.test/fail_compilation/fail13123.d | 21 + .../gdc.test/fail_compilation/fail17646.d | 5 +- .../gdc.test/fail_compilation/fail18892.d | 4 +- .../gdc.test/fail_compilation/fail18970.d | 4 +- .../gdc.test/fail_compilation/fail18979.d | 2 +- .../gdc.test/fail_compilation/fail19103.d | 4 +- .../gdc.test/fail_compilation/fail19687.d | 2 +- .../gdc.test/fail_compilation/fail19913.d | 2 +- .../gdc.test/fail_compilation/fail21243.d | 19 + .../gdc.test/fail_compilation/fail23109.d | 4 +- gcc/testsuite/gdc.test/fail_compilation/fail7372.d | 13 + .../gdc.test/fail_compilation/faildottypeinfo.d | 2 +- .../gdc.test/fail_compilation/failoffset.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/ice10938.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/ice12174.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/ice15855.d | 24 +- gcc/testsuite/gdc.test/fail_compilation/ice18469.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/ice19755.d | 2 +- .../gdc.test/fail_compilation/imports/fail7372.d | 9 + .../fail_compilation/misc_parser_err_cov1.d | 1 - .../gdc.test/fail_compilation/mixinprop.d | 13 + .../gdc.test/fail_compilation/test15785.d | 2 +- .../gdc.test/fail_compilation/test15897.d | 2 +- .../gdc.test/fail_compilation/test16188.d | 2 +- .../gdc.test/fail_compilation/test17380spec.d | 2 +- .../gdc.test/fail_compilation/test21096.d | 6 +- .../gdc.test/fail_compilation/test22680.d | 17 + gcc/testsuite/gdc.test/runnable/newaa.d | 23 + gcc/testsuite/gdc.test/runnable/test23234.d | 22 + gcc/testsuite/gdc.test/runnable/testassign.d | 16 + 104 files changed, 1829 insertions(+), 1375 deletions(-) create mode 100644 gcc/testsuite/gdc.test/compilable/imports/cimports2a.i create mode 100644 gcc/testsuite/gdc.test/compilable/imports/cimports2b.i create mode 100644 gcc/testsuite/gdc.test/compilable/imports/format23327.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/format23327/write.d create mode 100644 gcc/testsuite/gdc.test/compilable/segfaultgolf.d create mode 100644 gcc/testsuite/gdc.test/compilable/statictemplatethis.d create mode 100644 gcc/testsuite/gdc.test/compilable/test13123.d create mode 100644 gcc/testsuite/gdc.test/compilable/test21243.d create mode 100644 gcc/testsuite/gdc.test/compilable/test21956.d create mode 100644 gcc/testsuite/gdc.test/compilable/test22674.d create mode 100644 gcc/testsuite/gdc.test/compilable/test23173.d create mode 100644 gcc/testsuite/gdc.test/compilable/test23258.d create mode 100644 gcc/testsuite/gdc.test/compilable/test23306.d create mode 100644 gcc/testsuite/gdc.test/compilable/test23327.d create mode 100644 gcc/testsuite/gdc.test/compilable/vararg.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag23355.d delete mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag3438b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail13123.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail21243.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail7372.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/fail7372.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/mixinprop.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test22680.d create mode 100644 gcc/testsuite/gdc.test/runnable/newaa.d create mode 100644 gcc/testsuite/gdc.test/runnable/test23234.d (limited to 'gcc') 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 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 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 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 *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/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 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(); -- cgit v1.1