diff options
Diffstat (limited to 'gcc')
163 files changed, 7111 insertions, 1966 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0ac20fd..9f241a2 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,205 @@ +2025-07-10 Richard Sandiford <richard.sandiford@arm.com> + + * config/aarch64/aarch64.cc (aarch64_vector_costs::add_stmt_cost): + Guard VF-based costing with !m_costing_for_scalar. + +2025-07-10 Qing Zhao <qing.zhao@oracle.com> + + * internal-fn.cc (expand_ACCESS_WITH_SIZE): Update comments. + * internal-fn.def (ACCESS_WITH_SIZE): Update comments. + * tree-object-size.cc (access_with_size_object_size): Update comments. + Adjust the arguments per the new design. + +2025-07-10 Qing Zhao <qing.zhao@oracle.com> + + PR middle-end/121000 + * internal-fn.cc (expand_ACCESS_WITH_SIZE): Update comments. + * internal-fn.def (ACCESS_WITH_SIZE): Update comments. + * tree-object-size.cc (access_with_size_object_size): Update comments. + Get the element_size from the 6th argument directly. + +2025-07-10 Richard Sandiford <richard.sandiford@arm.com> + + * config/aarch64/aarch64-sve2.md (aarch64_gather_ld1q): Replace with... + (@aarch64_gather_ld1q<mode>): ...this, parameterizing based on mode. + * config/aarch64/aarch64-sve-builtins-sve2.cc + (svld1q_gather_impl::expand): Update accordingly. + (svst1q_scatter_impl::expand): Use aarch64_sve_reinterpret + instead of force_lowpart_subreg. + +2025-07-10 Jan Hubicka <hubicka@ucw.cz> + + * auto-profile.cc: Include output.h. + (function_instance::set_call_location): Also sanity check + that location is known. + (raw_symbol_name): Two new static functions. + (dump_inline_stack): Use it. + (string_table::get_index_by_decl): Likewise. + (function_instance::get_cgraph_node): Likewise. + (function_instance::get_function_instance_by_decl): Fix typo + in warning; use raw names; fix lineno decoding. + (match_with_target): Add containing funciton parameter; + correctly output function and call location in warning. + (function_instance::lookup_count): Fix warning locations. + (function_instance::match): Fix warning locations; avoid + crash with mismatched callee; do not warn about broken callsites + twice. + (autofdo_source_profile::offline_external_functions): Use + raw_assembler_name. + (walk_block): Use raw_assembler_name. + +2025-07-10 Robin Dapp <rdapp@ventanamicro.com> + + PR target/121014 + * cfgexpand.cc (expand_debug_expr): Assert FLOAT_MODE_P. + * optabs-tree.cc (optab_for_tree_code): Assert FLOAT_TYPE_P. + * tree-vect-loop.cc (vect_get_loop_len): Use EXACT_DIV_EXPR. + +2025-07-10 Robin Dapp <rdapp@ventanamicro.com> + + PR target/118734 + * config/riscv/constraints.md (Wdm): Use tunable for Wdm + constraint. + * config/riscv/riscv-protos.h (emit_avltype_insn): Declare. + (can_be_broadcasted_p): Rename to... + (can_be_broadcast_p): ...this. + * config/riscv/predicates.md: Use renamed function. + (strided_load_broadcast_p): Declare. + * config/riscv/riscv-selftests.cc (run_broadcast_selftests): + Only run broadcast selftest if strided broadcasts are OK. + * config/riscv/riscv-v.cc (emit_avltype_insn): New function. + (sew64_scalar_helper): Only emit a pred_broadcast if the new + tunable says so. + (can_be_broadcasted_p): Rename to... + (can_be_broadcast_p): ...this and use new tunable. + * config/riscv/riscv.cc (struct riscv_tune_param): Add strided + broad tunable. + (strided_load_broadcast_p): Implement. + * config/riscv/vector.md: Use strided_load_broadcast_p () and + work around 64-bit broadcast on rv32 targets. + +2025-07-10 Co-authored-by: Jeff Law <jlaw@ventanamicro.com> + + * config/riscv/riscv.cc (riscv_fusion_pairs): Add new cases. + (riscv_set_is_add): New function. + (riscv_set_is_addi, riscv_set_is_adduw, riscv_set_is_shNadd): Likewise. + (riscv_set_is_shNadduw): Likewise. + (riscv_macro_fusion_pair_p): Add new fusion cases. + +2025-07-10 Richard Biener <rguenther@suse.de> + + * tree-vect-slp.cc (vect_analyze_slp): Fail for non-canonical + gconds. + +2025-07-10 Richard Biener <rguenther@suse.de> + + * tree-vect-slp.cc (vect_build_slp_instance): Do not use + SLP_TREE_VECTYPE to determine the conversion back to the + reduction IV. + +2025-07-10 Richard Biener <rguenther@suse.de> + + * tree-vect-loop.cc (vectorizable_reduction): Avoid + vect_is_simple_use and record a vector type if we come + up with one. + +2025-07-10 Richard Biener <rguenther@suse.de> + + * tree-vect-stmts.cc (get_load_store_type): Do not use + vect_is_simple_use to fill gather/scatter offset operand + vectype and dt. + +2025-07-10 Richard Biener <rguenther@suse.de> + + * tree-vect-loop.cc (vect_model_reduction_cost): Get SLP + node instead of stmt_info and use that when recording costs. + +2025-07-10 Kyrylo Tkachov <ktkachov@nvidia.com> + + PR target/120999 + * config/aarch64/aarch64-sve2.md (*aarch64_sve2_nor<mode>): + Adjust movprfx alternative. + +2025-07-10 Richard Sandiford <richard.sandiford@arm.com> + + * doc/sourcebuild.texi (aarch64_sve2_hw, aarch64_sve2p1_hw): Document. + * config/aarch64/aarch64.cc (aarch64_evpc_hvla): Extend to + BYTES_BIG_ENDIAN. + +2025-07-10 Richard Biener <rguenther@suse.de> + + * tree-vectorizer.h (vect_analyze_stmt): Remove stmt-info + and need_to_vectorize arguments. + * tree-vect-slp.cc (vect_slp_analyze_node_operations_1): + Adjust. + * tree-vect-stmts.cc (can_vectorize_live_stmts): Remove + stmt_info argument and remove non-SLP path. + (vect_analyze_stmt): Remove stmt_info and need_to_vectorize + argument and prune paths no longer reachable. + (vect_transform_stmt): Adjust. + +2025-07-10 Jakub Jelinek <jakub@redhat.com> + + * config/i386/x86-tune.def: Change "Tunning the" to "tuning" in + comment and use semicolon instead of dot in comment. + * loop-unroll.cc (decide_unroll_stupid): Comment spelling fix, + tunning -> tuning. + +2025-07-10 Jakub Jelinek <jakub@redhat.com> + + * tree-vect-loop.cc (scale_profile_for_vect_loop): Comment + spelling fix: bellow -> below. + * ipa-polymorphic-call.cc (record_known_type): Likewise. + * config/i386/x86-tune.def: Likewise. + * config/riscv/vector.md (*vsetvldi_no_side_effects_si_extend): + Likewise. + * tree-scalar-evolution.cc (iv_can_overflow_p): Likewise. + * ipa-devirt.cc (add_type_duplicate): Likewise. + * tree-ssa-loop-niter.cc (maybe_lower_iteration_bound): Likewise. + * gimple-ssa-sccopy.cc: Likewise. + * cgraphunit.cc: Likewise. + * graphite.h (struct poly_dr): Likewise. + * ipa-reference.cc (ignore_edge_p): Likewise. + * tree-ssa-alias.cc (ao_compare::compare_ao_refs): Likewise. + * profile-count.h (profile_probability::probably_reliable_p): + Likewise. + * ipa-inline-transform.cc (inline_call): Likewise. + +2025-07-10 Richard Biener <rguenther@suse.de> + + * tree-vect-loop.cc (vect_dissolve_slp_only_groups): Remove. + (vect_analyze_loop_2): Do not call it. + +2025-07-10 Richard Biener <rguenther@suse.de> + + * tree-vect-loop.cc (vect_active_double_reduction_p): Remove. + (vect_analyze_loop_operations): Remove. + (vect_analyze_loop_2): Do not call it. + +2025-07-10 Richard Biener <rguenther@suse.de> + + * tree-vect-loop.cc (vect_determine_vf_for_stmt_1): Rename + to ... + (vect_determine_vectype_for_stmt_1): ... this and only set + STMT_VINFO_VECTYPE. Fail for single-element vector types. + (vect_determine_vf_for_stmt): Rename to ... + (vect_determine_vectype_for_stmt): ... this and only set + STMT_VINFO_VECTYPE. Fail for single-element vector types. + (vect_determine_vectorization_factor): Rename to ... + (vect_set_stmts_vectype): ... this and only set STMT_VINFO_VECTYPE. + (vect_update_vf_for_slp): Remove. + (vect_analyze_loop_operations): Remove walk over stmts. + (vect_analyze_loop_2): Call vect_set_stmts_vectype instead of + vect_determine_vectorization_factor. Set vectorization factor + from LOOP_VINFO_SLP_UNROLLING_FACTOR. Fail if vect_detect_hybrid_slp + detects hybrid stmts or when vect_make_slp_decision finds + nothing to SLP. + * tree-vect-slp.cc (vect_detect_hybrid_slp): Move check + whether we have any hybrid stmts here from vect_update_vf_for_slp + * tree-vect-stmts.cc (vect_analyze_stmt): Remove loop over + stmts. + * tree-vectorizer.h (vect_detect_hybrid_slp): Update. + 2025-07-09 Richard Sandiford <richard.sandiford@arm.com> * config/aarch64/aarch64.cc (aarch64_simd_valid_imm): Account diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 12032ce..26b40b2 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20250710 +20250711 diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index d88e73f..49b4b95 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,8 @@ +2025-07-10 Jakub Jelinek <jakub@redhat.com> + + * par-load.adb: Comment spelling fix: bellow -> below. + * libgnarl/s-taskin.ads: Likewise. + 2025-07-04 Eric Botcazou <ebotcazou@adacore.com> * gcc-interface/Make-lang.in (ACATSDIR): Change to acats-4. diff --git a/gcc/auto-profile.cc b/gcc/auto-profile.cc index 2196760..5226e455 100644 --- a/gcc/auto-profile.cc +++ b/gcc/auto-profile.cc @@ -53,6 +53,7 @@ along with GCC; see the file COPYING3. If not see #include "auto-profile.h" #include "tree-pretty-print.h" #include "gimple-pretty-print.h" +#include "output.h" /* The following routines implements AutoFDO optimization. @@ -430,7 +431,8 @@ public: void set_call_location (location_t l) { - gcc_checking_assert (call_location_ == UNKNOWN_LOCATION); + gcc_checking_assert (call_location_ == UNKNOWN_LOCATION + && l != UNKNOWN_LOCATION); call_location_= l; } @@ -685,6 +687,26 @@ dump_afdo_loc (FILE *f, unsigned loc) fprintf (f, "%i", loc >> 16); } +/* Return assembler name as in symbol table and DW_AT_linkage_name. */ + +static const char * +raw_symbol_name (const char *asmname) +{ + /* If we start supporting user_label_prefixes, add_linkage_attr will also + need to be fixed. */ + if (strlen (user_label_prefix)) + sorry ("auto-profile is not supported for targets with user label prefix"); + return asmname + (asmname[0] == '*'); +} + +/* Convenience wrapper that looks up assembler name. */ + +static const char * +raw_symbol_name (tree decl) +{ + return raw_symbol_name (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl))); +} + /* Dump STACK to F. */ static void @@ -695,7 +717,7 @@ dump_inline_stack (FILE *f, inline_stack *stack) { fprintf (f, "%s%s:", first ? "" : "; ", - IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (p.decl))); + raw_symbol_name (p.decl)); dump_afdo_loc (f, p.afdo_loc); first = false; } @@ -817,7 +839,7 @@ string_table::get_index (const char *name) const int string_table::get_index_by_decl (tree decl) const { - const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); + const char *name = raw_symbol_name (decl); int ret = get_index (name); if (ret != -1) return ret; @@ -880,10 +902,9 @@ function_instance::~function_instance () cgraph_node * function_instance::get_cgraph_node () { - for (symtab_node *n = cgraph_node::get_for_asmname - (get_identifier - (afdo_string_table->get_name (name ()))); - n; n = n->next_sharing_asm_name) + const char *sname = afdo_string_table->get_name (name ()); + symtab_node *n = cgraph_node::get_for_asmname (get_identifier (sname)); + for (;n; n = n->next_sharing_asm_name) if (cgraph_node *cn = dyn_cast <cgraph_node *> (n)) if (cn->definition && cn->has_gimple_body_p ()) return cn; @@ -921,10 +942,10 @@ function_instance::get_function_instance_by_decl (unsigned lineno, dump_printf_loc (MSG_NOTE | MSG_PRIORITY_INTERNALS, dump_user_location_t::from_location_t (location), "auto-profile has mismatched function name %s" - " instaed of %s at loc %i:%i", + " insteed of %s at loc %i:%i", afdo_string_table->get_name (iter.first.second), - IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), - lineno << 16, + raw_symbol_name (decl), + lineno >> 16, lineno & 65535); } @@ -1127,10 +1148,13 @@ function_instance::offline_if_in_set (name_index_set &seen, Return non-zero if it correspons and 2 if renaming was done. */ static int -match_with_target (gimple *stmt, function_instance *inlined_fn, cgraph_node *n) +match_with_target (cgraph_node *n, + gimple *stmt, + function_instance *inlined_fn, + cgraph_node *orig_callee) { - const char *symbol_name = IDENTIFIER_POINTER - (DECL_ASSEMBLER_NAME (n->decl)); + cgraph_node *callee = orig_callee->ultimate_alias_target (); + const char *symbol_name = raw_symbol_name (callee->decl); const char *name = afdo_string_table->get_name (inlined_fn->name ()); if (strcmp (name, symbol_name)) { @@ -1144,8 +1168,8 @@ match_with_target (gimple *stmt, function_instance *inlined_fn, cgraph_node *n) in_suffix = true; } /* Accept dwarf names and stripped suffixes. */ - if (!strcmp (lang_hooks.dwarf_name (n->decl, 0), - afdo_string_table->get_name (inlined_fn->name ())) + if (!strcmp (lang_hooks.dwarf_name (callee->decl, 0), + afdo_string_table->get_name (inlined_fn->name ())) || (!name[i] && symbol_name[i] == '.') || in_suffix) { @@ -1159,10 +1183,14 @@ match_with_target (gimple *stmt, function_instance *inlined_fn, cgraph_node *n) inlined_fn->set_name (index); return 2; } - warning_at (gimple_location (stmt), OPT_Wauto_profile, - "auto-profile contains inlined " - "function with symbol name %s instead of symbol name %s", - name, symbol_name); + /* Only warn about declarations. It is possible that the function is + declared as alias in other module and we inlined cross-module. */ + if (callee->definition + && warning (OPT_Wauto_profile, + "auto-profile of %q+F contains inlined " + "function with symbol name %s instead of symbol name %s", + n->decl, name, symbol_name)) + inform (gimple_location (stmt), "corresponding call"); return 0; } return 1; @@ -1205,13 +1233,14 @@ function_instance::lookup_count (location_t loc, inline_stack &stack, if (stack.length ()) { int c = pos_counts.count (stack[0].afdo_loc); - if (c > 1) - warning_at (loc, OPT_Wauto_profile, - "duplicated count information" - " in auto-profile of %q+F" - " with relative location %i discriminator %i", - node->decl, stack[0].afdo_loc >> 16, - stack[0].afdo_loc & 65535); + if (c > 1 + && warning (OPT_Wauto_profile, + "duplicated count information" + " in auto-profile of %q+F" + " with relative location %i discriminator %i", + node->decl, stack[0].afdo_loc >> 16, + stack[0].afdo_loc & 65535)) + inform (loc, "corresponding source location"); if (c) return &pos_counts[stack[0].afdo_loc]; } @@ -1273,6 +1302,7 @@ function_instance::match (cgraph_node *node, hash_set<const count_info *> counts; hash_set<const count_info *> targets; hash_set<const function_instance *> functions; + hash_set<const function_instance *> functions_to_offline; /* We try to fill in lost disciminator if there is unique call with given line number. This map is used to record them. */ @@ -1376,20 +1406,23 @@ function_instance::match (cgraph_node *node, inlined_fn_nodisc = iter.second; cnodis++; } - if (c > 1 || cnodis > 1) - warning_at (gimple_location (stmt), OPT_Wauto_profile, - "duplicated callsite in auto-profile of %q+F" - " with relative location %i, discriminator %i", - node->decl, stack[0].afdo_loc >> 16, - stack[0].afdo_loc & 65535); - if (inlined_fn && info && info->targets.size ()) - warning_at (gimple_location (stmt), OPT_Wauto_profile, - "both call targets and inline callsite" - " information is present in auto-profile" - " of function %q+F with relative location" - " %i, discriminator %i", - node->decl, stack[0].afdo_loc >> 16, - stack[0].afdo_loc & 65535); + if ((c > 1 || (!c && cnodis > 1)) + && warning (OPT_Wauto_profile, + "duplicated callsite in auto-profile of %q+F" + " with relative location %i," + " discriminator %i", + node->decl, stack[0].afdo_loc >> 16, + stack[0].afdo_loc & 65535)) + inform (gimple_location (stmt), "corresponding call"); + if (inlined_fn && info && info->targets.size () + && warning (OPT_Wauto_profile, + "both call targets and inline callsite" + " information is present in auto-profile" + " of function %q+F with relative location" + " %i, discriminator %i", + node->decl, stack[0].afdo_loc >> 16, + stack[0].afdo_loc & 65535)) + inform (gimple_location (stmt), "corresponding call"); tree callee = gimple_call_fndecl (stmt); cgraph_node *callee_node; unsigned int loc = stack[0].afdo_loc; @@ -1422,11 +1455,17 @@ function_instance::match (cgraph_node *node, if (lineno_to_call.get (stack[0].afdo_loc >> 16)->length () == 1) { - warning_at (gimple_location (stmt), OPT_Wauto_profile, - "auto-profile of %q+F seem to contain" - " lost discriminator %i for call at" - " relative location %i", - node->decl, loc & 65535, loc >> 16); + if (warning (OPT_Wauto_profile, + "auto-profile of %q+F seem to contain" + " lost discriminator %i for" + " call of %s at relative location %i", + node->decl, + loc & 65535, + afdo_string_table->get_name + (inlined_fn_nodisc->name ()), + loc >> 16)) + inform (gimple_location (stmt), + "corresponding call"); inlined_fn = inlined_fn_nodisc; if (dump_file) fprintf (dump_file, " Lost discriminator %i\n", @@ -1437,11 +1476,10 @@ function_instance::match (cgraph_node *node, } if (callee && (callee_node = cgraph_node::get (callee))) { - callee_node = callee_node->ultimate_alias_target (); if (inlined_fn) { int old_name = inlined_fn->name (); - int r = match_with_target (stmt, inlined_fn, + int r = match_with_target (node, stmt, inlined_fn, callee_node); if (r == 2) { @@ -1458,6 +1496,8 @@ function_instance::match (cgraph_node *node, } if (r) functions.add (inlined_fn); + else + functions_to_offline.add (inlined_fn); } if (info && info->targets.size () > 1) @@ -1475,19 +1515,24 @@ function_instance::match (cgraph_node *node, { if (inlined_fn && inlined_fn->get_call_location () - != UNKNOWN_LOCATION - && warning_at (gimple_location (stmt), - OPT_Wauto_profile, - "%q+F contains two calls of the same" - " relative location +%i," - " discrimnator %i," - " that leads to lost auto-profile", - node->decl, - loc << 16, - loc & 65535)) + != UNKNOWN_LOCATION) { - inform (inlined_fn->get_call_location (), - "location of the earlier call"); + if (warning (OPT_Wauto_profile, + "function contains two calls of the same" + " relative location +%i," + " discrimnator %i," + " that leads to lost auto-profile", + loc >> 16, + loc & 65535)) + { + inform (gimple_location (stmt), + "location of the first call"); + inform (inlined_fn->get_call_location (), + "location of the second call"); + } + if (dump_file) + fprintf (dump_file, + " Duplicated call location\n"); inlined_fn = NULL; } if (inlined_fn) @@ -1561,11 +1606,18 @@ function_instance::match (cgraph_node *node, (DECL_STRUCT_FUNCTION (node->decl)->function_end_locus, node->decl); unsigned int start_location = get_combined_location (DECL_STRUCT_FUNCTION (node->decl)->function_start_locus, node->decl); + /* When outputting code to builtins location we use line number 0. + craeate_gcov is stupid and hapilly computes offsets across files. + Silently ignore it. */ + unsigned int zero_location + = ((unsigned)(1-DECL_SOURCE_LINE (node->decl))) << 16; for (position_count_map::const_iterator iter = pos_counts.begin (); iter != pos_counts.end ();) if (!counts.contains (&iter->second)) { - if (iter->first != end_location && iter->first != start_location + if (iter->first != end_location + && iter->first != start_location + && (iter->first & 65535) != zero_location && iter->first) { if (!warned) @@ -1603,28 +1655,42 @@ function_instance::match (cgraph_node *node, iter != callsites.end ();) if (!functions.contains (iter->second)) { - if (!warned) - warned = warning_at (DECL_SOURCE_LOCATION (node->decl), - OPT_Wauto_profile, - "auto-profile of %q+F contains extra callsites", - node->decl); - if (warned) - inform (DECL_SOURCE_LOCATION (node->decl), - "call of %s with relative location +%i, discriminator %i", - afdo_string_table->get_name (iter->first.second), - iter->first.first >> 16, iter->first.first & 65535); - if ((iter->first.first >> 16) > (end_location >> 16) && warned) - inform (DECL_SOURCE_LOCATION (node->decl), - "location is after end of function"); - warned = true; function_instance *f = iter->second; - if (dump_file) + /* If we did not see the corresponding statement, warn. */ + if (!functions_to_offline.contains (iter->second)) + { + if (!warned) + warned = warning_at (DECL_SOURCE_LOCATION (node->decl), + OPT_Wauto_profile, + "auto-profile of %q+F contains" + " extra callsites", + node->decl); + if (warned) + inform (DECL_SOURCE_LOCATION (node->decl), + "call of %s with total count %" PRId64 + ", relative location +%i, discriminator %i", + afdo_string_table->get_name (iter->first.second), + iter->second->total_count (), + iter->first.first >> 16, iter->first.first & 65535); + if ((iter->first.first >> 16) > (end_location >> 16) && warned) + inform (DECL_SOURCE_LOCATION (node->decl), + "location is after end of function"); + if (dump_file) + { + fprintf (dump_file, + "Offlining inline with no corresponding gimple stmt "); + f->dump_inline_stack (dump_file); + fprintf (dump_file, "\n"); + } + } + else if (dump_file) { fprintf (dump_file, - "Offlining inline with no corresponding gimple stmt "); + "Offlining mismatched inline "); f->dump_inline_stack (dump_file); fprintf (dump_file, "\n"); } + warned = true; callsites.erase (iter); offline (f, new_functions); iter = callsites.begin (); @@ -1923,7 +1989,7 @@ autofdo_source_profile::offline_external_functions () FOR_EACH_DEFINED_FUNCTION (node) { const char *name - = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->decl)); + = raw_symbol_name (node->decl); const char *dwarf_name = lang_hooks.dwarf_name (node->decl, 0); int index = afdo_string_table->get_index (name); @@ -2105,8 +2171,7 @@ walk_block (tree fn, function_instance *s, tree block) fprintf (dump_file, ":"); dump_afdo_loc (dump_file, loc); fprintf (dump_file, " %s\n", - IDENTIFIER_POINTER - (DECL_ASSEMBLER_NAME (BLOCK_ABSTRACT_ORIGIN (block)))); + raw_symbol_name (BLOCK_ABSTRACT_ORIGIN (block))); } return; } @@ -2464,7 +2529,7 @@ autofdo_source_profile::get_callsite_total_count ( { if (dump_file) fprintf (dump_file, "Mismatched name of callee %s and profile %s\n", - IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (edge->callee->decl)), + raw_symbol_name (edge->callee->decl), afdo_string_table->get_name (s->name ())); return 0; } @@ -2558,8 +2623,7 @@ autofdo_source_profile::get_function_instance_by_inline_stack ( { if (dump_file) fprintf (dump_file, "No offline instance for %s\n", - IDENTIFIER_POINTER - (DECL_ASSEMBLER_NAME (stack[stack.length () - 1].decl))); + raw_symbol_name (stack[stack.length () - 1].decl)); return NULL; } function_instance *s = iter->second; @@ -2581,8 +2645,7 @@ autofdo_source_profile::get_function_instance_by_inline_stack ( "auto-profile has no inlined function instance " "for inlined call of %s at relative " " locaction +%i, discriminator %i\n", - IDENTIFIER_POINTER - (DECL_ASSEMBLER_NAME (stack[i - 1].decl)), + raw_symbol_name (stack[i - 1].decl), stack[i].afdo_loc >> 16, stack[i].afdo_loc & 65535); return NULL; diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 54dcb52..a95cc34 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,14 @@ +2025-07-10 Jakub Jelinek <jakub@redhat.com> + + PR c++/117785 + * c-cppbuiltin.cc (c_cpp_builtins): Predefine + __cpp_constexpr_exceptions=202411L for C++26. + +2025-07-10 Qing Zhao <qing.zhao@oracle.com> + + * c-ubsan.cc (get_bound_from_access_with_size): Adjust the position + of the arguments per the new design. + 2025-07-07 Qing Zhao <qing.zhao@oracle.com> Revert: diff --git a/gcc/c-family/c-cppbuiltin.cc b/gcc/c-family/c-cppbuiltin.cc index 459fd86..0c84020 100644 --- a/gcc/c-family/c-cppbuiltin.cc +++ b/gcc/c-family/c-cppbuiltin.cc @@ -1087,6 +1087,7 @@ c_cpp_builtins (cpp_reader *pfile) { /* Set feature test macros for C++26. */ cpp_define (pfile, "__cpp_constexpr=202406L"); + cpp_define (pfile, "__cpp_constexpr_exceptions=202411L"); cpp_define (pfile, "__cpp_static_assert=202306L"); cpp_define (pfile, "__cpp_placeholder_variables=202306L"); cpp_define (pfile, "__cpp_structured_bindings=202403L"); diff --git a/gcc/c-family/c-ubsan.cc b/gcc/c-family/c-ubsan.cc index 78b7868..a4dc310 100644 --- a/gcc/c-family/c-ubsan.cc +++ b/gcc/c-family/c-ubsan.cc @@ -397,8 +397,7 @@ get_bound_from_access_with_size (tree call) return NULL_TREE; tree ref_to_size = CALL_EXPR_ARG (call, 1); - unsigned int class_of_size = TREE_INT_CST_LOW (CALL_EXPR_ARG (call, 2)); - tree type = TREE_TYPE (CALL_EXPR_ARG (call, 3)); + tree type = TREE_TYPE (TREE_TYPE (CALL_EXPR_ARG (call, 2))); tree size = fold_build2 (MEM_REF, type, unshare_expr (ref_to_size), build_int_cst (ptr_type_node, 0)); /* If size is negative value, treat it as zero. */ @@ -410,12 +409,7 @@ get_bound_from_access_with_size (tree call) build_zero_cst (type), size); } - /* Only when class_of_size is 1, i.e, the number of the elements of - the object type, return the size. */ - if (class_of_size != 1) - return NULL_TREE; - else - size = fold_convert (sizetype, size); + size = fold_convert (sizetype, size); return size; } diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index dcef284..bd139a7 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,14 @@ +2025-07-10 Qing Zhao <qing.zhao@oracle.com> + + * c-typeck.cc (build_access_with_size_for_counted_by): Update comments. + Adjust the arguments per the new design. + +2025-07-10 Qing Zhao <qing.zhao@oracle.com> + + PR middle-end/121000 + * c-typeck.cc (build_access_with_size_for_counted_by): Update comments. + Pass TYPE_SIZE_UNIT of the element as the 6th argument. + 2025-07-07 Qing Zhao <qing.zhao@oracle.com> Revert: diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index e24629b..9a5eb0d 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -2982,8 +2982,8 @@ build_counted_by_ref (tree datum, tree subdatum, tree *counted_by_type) to: - (*.ACCESS_WITH_SIZE (REF, COUNTED_BY_REF, 1, (TYPE_OF_SIZE)0, -1, - (TYPE_OF_ARRAY *)0)) + (*.ACCESS_WITH_SIZE (REF, COUNTED_BY_REF, (* TYPE_OF_SIZE)0, + TYPE_SIZE_UNIT for element) NOTE: The return type of this function is the POINTER type pointing to the original flexible array type. @@ -2992,11 +2992,11 @@ build_counted_by_ref (tree datum, tree subdatum, tree *counted_by_type) The type of the first argument of this function is a POINTER type to the original flexible array type. - The 4th argument of the call is a constant 0 with the TYPE of the - object pointed by COUNTED_BY_REF. + The 3rd argument of the call is a constant 0 with the pointer TYPE whose + pointee type is the TYPE of the object pointed by COUNTED_BY_REF. - The 6th argument of the call is a constant 0 with the pointer TYPE - to the original flexible array type. + The 4th argument of the call is the TYPE_SIZE_UNIT of the element TYPE + of the array. */ static tree @@ -3007,20 +3007,22 @@ build_access_with_size_for_counted_by (location_t loc, tree ref, gcc_assert (c_flexible_array_member_type_p (TREE_TYPE (ref))); /* The result type of the call is a pointer to the flexible array type. */ tree result_type = c_build_pointer_type (TREE_TYPE (ref)); + tree element_size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (ref))); + tree first_param = c_fully_fold (array_to_pointer_conversion (loc, ref), false, NULL); tree second_param = c_fully_fold (counted_by_ref, false, NULL); + tree third_param = build_int_cst (build_pointer_type (counted_by_type), 0); tree call = build_call_expr_internal_loc (loc, IFN_ACCESS_WITH_SIZE, - result_type, 6, + result_type, 4, first_param, second_param, - build_int_cst (integer_type_node, 1), - build_int_cst (counted_by_type, 0), - build_int_cst (integer_type_node, -1), - build_int_cst (result_type, 0)); + third_param, + element_size); + /* Wrap the call with an INDIRECT_REF with the flexible array type. */ call = build1 (INDIRECT_REF, TREE_TYPE (ref), call); SET_EXPR_LOCATION (call, loc); diff --git a/gcc/cfgexpand.cc b/gcc/cfgexpand.cc index 33649d4..a656cce 100644 --- a/gcc/cfgexpand.cc +++ b/gcc/cfgexpand.cc @@ -5358,6 +5358,8 @@ expand_debug_expr (tree exp) return simplify_gen_binary (MULT, mode, op0, op1); case RDIV_EXPR: + gcc_assert (FLOAT_MODE_P (mode)); + /* Fall through. */ case TRUNC_DIV_EXPR: case EXACT_DIV_EXPR: if (unsignedp) diff --git a/gcc/cobol/ChangeLog b/gcc/cobol/ChangeLog index 6c3e1bd..5affc84 100644 --- a/gcc/cobol/ChangeLog +++ b/gcc/cobol/ChangeLog @@ -1,3 +1,62 @@ +2025-07-10 James K. Lowden <jklowden@cobolworx.com> + + PR cobol/120765 + * cdf.y: Extend grammar for new CDF syntax, relocate dictionary. + * cdfval.h (cdf_dictionary): Use new CDF dictionary. + * dts.h: Remove useless assignment, note incorrect behavior. + * except.cc: Remove obsolete EC state. + * gcobol.1: Document CDF in its own section. + * genapi.cc (parser_statement_begin): Use new EC state function. + (parser_file_merge): Same. + (parser_check_fatal_exception): Same. + * genutil.cc (get_and_check_refstart_and_reflen): Same. + (get_depending_on_value_from_odo): Same. + (get_data_offset): Same. + (process_this_exception): Same. + * lexio.cc (check_push_pop_directive): New function. + (check_source_format_directive): Restrict regex search to 1 line. + (cdftext::free_form_reference_format): Use new function. + * parse.y: Define new CDF tokens, use new CDF state. + * parse_ante.h (cdf_tokens): Use new CDF state. + (redefined_token): Same. + (class prog_descr_t): Remove obsolete CDF state. + (class program_stack_t): Same. + (current_call_convention): Same. + * scan.l: Recognize new CDF tokens. + * scan_post.h (is_cdf_token): Same. + * symbols.h (cdf_current_tokens): Change current_call_convention to return void. + * token_names.h: Regenerate. + * udf/stored-char-length.cbl: Use new PUSH/POP CDF functionality. + * util.cc (class cdf_directives_t): Define cdf_directives_t. + (current_call_convention): Same. + (cdf_current_tokens): Same. + (cdf_dictionary): Same. + (cdf_enabled_exceptions): Same. + (cdf_push): Same. + (cdf_push_call_convention): Same. + (cdf_push_current_tokens): Same. + (cdf_push_dictionary): Same. + (cdf_push_enabled_exceptions): Same. + (cdf_push_source_format): Same. + (cdf_pop): Same. + (cdf_pop_call_convention): Same. + (cdf_pop_current_tokens): Same. + (cdf_pop_dictionary): Same. + (cdf_pop_enabled_exceptions): Same. + (cdf_pop_source_format): Same. + * util.h (cdf_push): Declare cdf_directives_t. + (cdf_push_call_convention): Same. + (cdf_push_current_tokens): Same. + (cdf_push_dictionary): Same. + (cdf_push_enabled_exceptions): Same. + (cdf_push_source_format): Same. + (cdf_pop): Same. + (cdf_pop_call_convention): Same. + (cdf_pop_current_tokens): Same. + (cdf_pop_dictionary): Same. + (cdf_pop_source_format): Same. + (cdf_pop_enabled_exceptions): Same. + 2025-07-09 Robert Dubner <rdubner@symas.com> James K. Lowden <jklowden@cobolworx.com> diff --git a/gcc/cobol/cdf.y b/gcc/cobol/cdf.y index f1a7912..840eb50 100644 --- a/gcc/cobol/cdf.y +++ b/gcc/cobol/cdf.y @@ -105,14 +105,14 @@ void input_file_status_notify(); using std::map; - static map<std::string, cdfval_t> dictionary; - #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-function" static bool cdfval_add( const char name[], const cdfval_t& value, bool override = false ) { + cdf_values_t& dictionary( cdf_dictionary() ); + if( scanner_parsing() ) { if( ! override ) { if( dictionary.find(name) != dictionary.end() ) return false; @@ -123,6 +123,8 @@ void input_file_status_notify(); } static void cdfval_off( const char name[] ) { + cdf_values_t& dictionary( cdf_dictionary() ); + if( scanner_parsing() ) { auto p = dictionary.find(name); if( p == dictionary.end() ) { @@ -159,6 +161,8 @@ exception_turn_t exception_turn; bool apply_cdf_turn( const exception_turn_t& turn ) { + cbl_enabled_exceptions_t& enabled_exceptions( cdf_enabled_exceptions() ); + for( auto elem : turn.exception_files() ) { std::set<size_t> files(elem.second.begin(), elem.second.end()); enabled_exceptions.turn_on_off(turn.enabled, @@ -204,15 +208,17 @@ apply_cdf_turn( const exception_turn_t& turn ) { %type <file> filename %type <files> filenames -%token BY 482 +%type <number> cdf_stackable + +%token BY 486 %token COPY 362 %token CDF_DISPLAY 384 ">>DISPLAY" -%token IN 601 +%token IN 605 %token NAME 286 %token NUMSTR 305 "numeric literal" -%token OF 682 -%token PSEUDOTEXT 717 -%token REPLACING 739 +%token OF 686 +%token PSEUDOTEXT 721 +%token REPLACING 743 %token LITERAL 298 %token SUPPRESS 376 @@ -227,25 +233,32 @@ apply_cdf_turn( const exception_turn_t& turn ) { %token CDF_WHEN 389 ">>WHEN" %token CDF_END_EVALUATE 390 ">>END-EVALUATE" -%token AS 464 CONSTANT 361 DEFINED 363 +%token ALL 450 +%token CALL_CONVENTION 391 ">>CALL-CONVENTION" +%token COBOL_WORDS 380 ">>COBOL-WORDS" +%token CDF_PUSH 394 ">>PUSH" +%token CDF_POP 395 ">>POP" +%token SOURCE_FORMAT 396 ">>SOURCE FORMAT" + +%token AS 468 CONSTANT 361 DEFINED 363 %type <boolean> DEFINED -%token OTHER 694 PARAMETER_kw 368 "PARAMETER" -%token OFF 683 OVERRIDE 369 -%token THRU 935 -%token TRUE_kw 809 "True" +%token OTHER 698 PARAMETER_kw 368 "PARAMETER" +%token OFF 687 OVERRIDE 369 +%token THRU 939 +%token TRUE_kw 813 "True" -%token CALL_COBOL 391 "CALL" -%token CALL_VERBATIM 392 "CALL (as C)" +%token CALL_COBOL 392 "CALL" +%token CALL_VERBATIM 393 "CALL (as C)" -%token TURN 811 CHECKING 492 LOCATION 645 ON 685 WITH 837 +%token TURN 815 CHECKING 496 LOCATION 649 ON 689 WITH 841 -%left OR 936 -%left AND 937 -%right NOT 938 -%left '<' '>' '=' NE 939 LE 940 GE 941 +%left OR 940 +%left AND 941 +%right NOT 942 +%left '<' '>' '=' NE 943 LE 944 GE 945 %left '-' '+' %left '*' '/' -%right NEG 943 +%right NEG 947 %define api.prefix {ydf} %define api.token.prefix{YDF_} @@ -277,6 +290,8 @@ complete: cdf_define | cdf_display | cdf_turn | cdf_call_convention + | cdf_push + | cdf_pop ; /* @@ -328,6 +343,7 @@ cdf_define: CDF_DEFINE cdf_constant NAME as cdf_expr[value] override } if( !cdfval_add( $NAME, cdfval_t($value), $override) ) { error_msg(@NAME, "name already in dictionary: %s", $NAME); + cdf_values_t& dictionary( cdf_dictionary() ); const cdfval_t& entry = dictionary[$NAME]; if( entry.filename ) { error_msg(@NAME, "%s previously defined in %s:%d", @@ -357,7 +373,7 @@ cdf_define: CDF_DEFINE cdf_constant NAME as cdf_expr[value] override * available regardless. */ { - if( 0 == dictionary.count($NAME) ) { + if( 0 == cdf_dictionary().count($NAME) ) { yywarn("CDF: '%s' is defined AS PARAMETER " "but was not defined", $NAME); } @@ -400,6 +416,35 @@ cdf_call_convention: } ; +cdf_push: CDF_PUSH cdf_stackable { + switch( $cdf_stackable ) { + case YDF_ALL: cdf_push(); break; + case YDF_CALL_CONVENTION: cdf_push_call_convention(); break; + case YDF_CDF_DEFINE: cdf_push_dictionary(); break; + case YDF_COBOL_WORDS: cdf_push_current_tokens(); break; + case YDF_SOURCE_FORMAT: cdf_push_source_format(); break; + default: gcc_unreachable(); + } + } + ; +cdf_pop: CDF_POP cdf_stackable { + switch( $cdf_stackable ) { + case YDF_ALL: cdf_pop(); break; + case YDF_CALL_CONVENTION: cdf_pop_call_convention(); break; + case YDF_CDF_DEFINE: cdf_pop_dictionary(); break; + case YDF_COBOL_WORDS: cdf_pop_current_tokens(); break; + case YDF_SOURCE_FORMAT: cdf_pop_source_format(); break; + default: gcc_unreachable(); + } + } + ; + +cdf_stackable: ALL { $$ = YDF_ALL; } + | CALL_CONVENTION { $$ = YDF_CALL_CONVENTION; } + | COBOL_WORDS { $$ = YDF_COBOL_WORDS; } + | CDF_DEFINE { $$ = YDF_CDF_DEFINE; } + | SOURCE_FORMAT { $$ = YDF_SOURCE_FORMAT; } + ; except_names: except_name | except_names except_name @@ -471,6 +516,7 @@ cdf_eval_obj: cdf_cond_expr cdf_cond_expr: BOOL | NAME DEFINED { + cdf_values_t& dictionary( cdf_dictionary() ); auto p = dictionary.find($1); bool found = p != dictionary.end(); if( !$DEFINED ) found = ! found; @@ -552,6 +598,7 @@ cdf_expr: cdf_expr '+' cdf_expr { $$ = $1(@1) + $3(@3); } ; cdf_factor: NAME { + cdf_values_t& dictionary( cdf_dictionary() ); auto that = dictionary.find($1); if( that != dictionary.end() ) { $$ = that->second; @@ -651,6 +698,7 @@ name_any: namelit name_one: NAME { + cdf_values_t& dictionary( cdf_dictionary() ); cdf_arg_t arg = { YDF_NAME, $1 }; auto p = dictionary.find($1); @@ -665,6 +713,7 @@ name_one: NAME namelit: name { + cdf_values_t& dictionary( cdf_dictionary() ); cdf_arg_t arg = { YDF_NAME, $1 }; auto p = dictionary.find($1); @@ -745,6 +794,7 @@ location_set( const YYLTYPE& loc ) { bool // used by cobol1.cc defined_cmd( const char arg[] ) { + cdf_values_t& dictionary( cdf_dictionary() ); cdfval_t value(1); char *name = xstrdup(arg); @@ -868,6 +918,7 @@ static int ydflex(void) { bool cdf_value( const char name[], const cdfval_t& value ) { + cdf_values_t& dictionary( cdf_dictionary() ); auto p = dictionary.find(name); if( p != dictionary.end() ) return false; @@ -878,6 +929,7 @@ cdf_value( const char name[], const cdfval_t& value ) { const cdfval_t * cdf_value( const char name[] ) { + cdf_values_t& dictionary( cdf_dictionary() ); auto p = dictionary.find(name); if( p == dictionary.end() ) return NULL; diff --git a/gcc/cobol/cdfval.h b/gcc/cobol/cdfval.h index 465bdbb..cc474a2 100644 --- a/gcc/cobol/cdfval.h +++ b/gcc/cobol/cdfval.h @@ -126,4 +126,8 @@ cdf_value( const char name[] ); bool cdf_value( const char name[], const cdfval_t& value ); +typedef std::map<std::string, cdfval_t> cdf_values_t; + +cdf_values_t& cdf_dictionary(); + #endif diff --git a/gcc/cobol/dts.h b/gcc/cobol/dts.h index aa3fa58..e12b979 100644 --- a/gcc/cobol/dts.h +++ b/gcc/cobol/dts.h @@ -86,18 +86,24 @@ namespace dts { #if __cpp_exceptions static const char msg[] = "input not NUL-terminated"; throw std::domain_error( msg ); -#else - // eoinput terminates input - eoinput = strchr(input, '\0'); // cppcheck-suppress uselessAssignmentPtrArg #endif } auto ncm = re.size(); cm.resize(ncm); std::vector <regmatch_t> cms(ncm); - int erc = regexec( &re, input, ncm, cms.data(), 0 ); if( erc != 0 ) return false; +#if __cpp_exceptions + // This is not correct at all, but current use depends on current behavior. + // The following line is excluded from the GCC build, which is compiled + // without __cpp_exceptions. parse_copy_directive (for one) depends on + // regex_search returning true even if the match is beyond eoinput. + if( eoinput < cm[0].second ) return false; + // Correct behavior would return match only between input and eoinput. + // Because regex(3) uses a NUL terminator, it may match text between + // eoinput and the NUL. +#endif std::transform( cms.begin(), cms.end(), cm.begin(), [input]( const regmatch_t& m ) { return csub_match( input, m ); diff --git a/gcc/cobol/except.cc b/gcc/cobol/except.cc index 60b8416..e42aea2 100644 --- a/gcc/cobol/except.cc +++ b/gcc/cobol/except.cc @@ -84,8 +84,6 @@ cbl_enabled_exception_t::dump( int i ) const { file ); } -cbl_enabled_exceptions_t enabled_exceptions; - void cbl_enabled_exceptions_t::dump() const { extern int yydebug; diff --git a/gcc/cobol/gcobol.1 b/gcc/cobol/gcobol.1 index 6db5400..ebb833c 100644 --- a/gcc/cobol/gcobol.1 +++ b/gcc/cobol/gcobol.1 @@ -587,6 +587,21 @@ statement, regardless of compile-time constants. .. . .Ss Implemented Exception Conditions +By default, per ISO, no EC is enabled. Implemented ECs may be enabled +on the command line or via the +.Sy TURN +directive. Any attempt to enable an EC that is not implemented is +treated as an error. +.Pp +An enabled EC not handled by a +.Sy DECLARATIVE +is written to the system log and to standard error. (The authors +intend to make that an option.) A fatal EC not handled with +.Sy RESUME +ends with a call to +.Xr abort 3 +and process termination. +.Pp Not all Exception Conditions are implemented. Any attempt to enable an EC that that is not implemented produces a warning message. The following are implemented: @@ -913,11 +928,90 @@ or has no effect; the two are interchangeable. .. . -.Ss Compiler-Directing Facility (CDF) +.Sh COMPILER-DIRECTING FACILITY The CDF should be used with caution because no comprehensive test -suite has been identified. +suite has been identified. . -.Ss Conditional Compilation +.Ss CDF Text Manipulation +.Bl -tag -width >>DEFINE +.It Sy COPY Ar copybook Li Oo OF|BY Ar library Oc Oo Sy REPLACING ... Oc +If +.Ar copybook +is a literal, it treated a literal filename, which either does or does not exist. If +.Ar copybook +is a \*[lang] word, +.Nm +looks first for an environment variable named +.Va copybook +and, if found, uses the contents of that variable as the name of the +copybook file. If that file does not exist, it continues looking for +a file named one of: +.sp +.Bl -bullet -compact -offset 5n +.It +.Pa copybook +(literally) +.It +.Pa copybook.cpy +.It +.Pa copybook.CPY +.It +.Pa copybook.cbl +.It +.Pa copybook.CBL +.It +.Pa copybook.cob +.It +.Pa copybook.COB +.El +.sp +in that order. It looks first in the same directory as the source +code file, and then in any +.Ar copybook-path +named with the +.Fl I +option. +. +.\" FIXME: need escape mechanism for directories with ':' in the name. +.Ar copybook-path +may (like the shell's +.Ev PATH +variable) be a colon-separated list. +The +.Fl I +option may occur multiple times on the command line. Each successive +.Ar copybook-path +is concatenated to previous ones. +Relative paths (having no leading +.Ql / Ns +\&) +are searched relative to the compiler's current working directory. +.Pp +For example, +.D1 \& +.D1 Fl I Li /usr/local/include:include +.D1 \& +searches first the directory where the \*[lang] program is found, next in +.Pa /usr/local/include , +and finally in an +.Pa include +subdirectory of the directory from which +.Nm +was invoked. +.Pp +For the +.Sy REPLACING +phrase, both the modern pseudo-text and the \*[lang]/85 forms are +recognized. (The older forms are used in the NIST CCVS/85 test suite.) +.It Sy REPLACE ... +.Nm +supports the full ISO +.Sy REPLACE +syntax. +.El +. +.Ss CDF Directives +.\"Bl -tag -width >>PROPAGATE .Bl -tag -width >>DEFINE .It >> Ns Sy DEFINE Ar name Sy AS Bro Ar expression Li | Sy PARAMETER Brc Op Sy OVERRIDE Define @@ -959,10 +1053,6 @@ is supported. Boolean literals are not supported. . .It >> Ns Sy EVALUATE Not implemented. -.El -. -.Ss Other CDF Directives -.Bl -tag -width >>PROPAGATE .It >> Ns Sy CALL-CONVENTION Ar convention .Ar convention may be one of: @@ -1036,6 +1126,24 @@ Not implemented. Not implemented. .It >> Ns Sy PROPAGATE Not implemented. +.It >> Ns Sy PUSH Ar directive +.It >> Ns Sy POP Ar directive +With +.Sy PUSH , +push CDF state onto a stack. +With +.Sy POP , +return to the prior pushed state. +.Ar directive +may be one of +.Bl -tag -compact +.It Sy CALL-CONVENTION +.It Sy COBOL-WORDS +.It Sy DEFINE +.It Sy SOURCE FORMAT +.It Sy TURN +.El +. .It >> Ns Sy TURN Oo .Ar ec Oo Ar file Li ... Oc ... .Oc Sy CHECKING Bro Oo Sy ON Oc Oo Oo Sy WITH Oc Sy LOCATION Oc | Sy OFF Brc @@ -1087,76 +1195,6 @@ the directive must appear before To test a feature-set variable, use .Dl >>IF Ar feature Li DEFINED . -.Ss Copybooks -.Nm -supports the CDF -.Sy COPY -statement, with or without its -.Sy REPLACING -component. For any statement -.sp -.D1 COPY Ar copybook -.sp -.Nm -looks first for an environment variable named -.Va copybook -and, if found, uses the contents of that variable as the name of the -copybook file. If that file does not exist, it continues looking for -a file named one of: -.sp -.Bl -bullet -compact -offset 5n -.It -.Pa copybook -(literally) -.It -.Pa copybook.cpy -.It -.Pa copybook.CPY -.It -.Pa copybook.cbl -.It -.Pa copybook.CBL -.It -.Pa copybook.cob -.It -.Pa copybook.COB -.El -.sp -in that order. It looks first in the same directory as the source -code file, and then in any -.Ar copybook-path -named with the -.Fl I -option. -. -.\" FIXME: need escape mechanism for directories with ':' in the name. -.Ar copybook-path -may (like the shell's -.Ev PATH -variable) be a colon-separated list. -. -The -.Fl I -option may occur multiple times on the command line. Each successive -.Ar copybook-path -is concatenated to previous ones. -Relative paths (having no leading -.Ql / Ns -\&) -are searched relative to the compiler's current working directory. -.Pp -For example, -.D1 \& -.D1 Fl I Li /usr/local/include:include -.D1 \& -searches first the directory where the \*[lang] program is found, next in -.Pa /usr/local/include , -and finally in an -.Pa include -subdirectory of the directory from which -.Nm -was invoked. -. .Ss Intrinsic functions .Nm implements all intrinsic functions defined by \*[isostd], plus a few diff --git a/gcc/cobol/genapi.cc b/gcc/cobol/genapi.cc index 55db870..3c4e9a9 100644 --- a/gcc/cobol/genapi.cc +++ b/gcc/cobol/genapi.cc @@ -1166,7 +1166,7 @@ parser_statement_begin( const cbl_name_t statement_name, // the execution time of a program doing two-billion simple adds in an inner // loop dropped from 3.8 seconds to 0.175 seconds. - bool exception_processing = enabled_exceptions.size() ; + bool exception_processing = cdf_enabled_exceptions().size() ; if( !exception_processing ) { @@ -12236,6 +12236,8 @@ parser_file_merge( cbl_file_t *workfile, ELSE ENDIF + cbl_enabled_exceptions_t& enabled_exceptions( cdf_enabled_exceptions() ); + for(size_t i=0; i<ninputs; i++) { if( process_this_exception(ec_sort_merge_file_open_e) ) @@ -13905,7 +13907,7 @@ parser_check_fatal_exception() // in its innermost loop had an execution time of 19.5 seconds. By putting in // the if() statement, that was reduced to 3.8 seconds. - if( enabled_exceptions.size() || sv_is_i_o ) + if( cdf_enabled_exceptions().size() || sv_is_i_o ) { gg_call(VOID, "__gg__check_fatal_exception", diff --git a/gcc/cobol/genutil.cc b/gcc/cobol/genutil.cc index 1d921a3..e09b1bf 100644 --- a/gcc/cobol/genutil.cc +++ b/gcc/cobol/genutil.cc @@ -307,6 +307,8 @@ get_and_check_refstart_and_reflen( tree refstart,// LONG returned value tree reflen, // LONG returned value cbl_refer_t &refer) { + cbl_enabled_exceptions_t& enabled_exceptions( cdf_enabled_exceptions() ); + if( !enabled_exceptions.match(ec_bound_ref_mod_e) ) { // This is normal operation -- no exception checking. Thus, we won't @@ -458,6 +460,7 @@ get_depending_on_value_from_odo(tree retval, cbl_field_t *odo) declarative with a RESUME NEXT STATEMENT, or before the default_condition processing can do a controlled exit. */ + cbl_enabled_exceptions_t& enabled_exceptions( cdf_enabled_exceptions() ); cbl_field_t *depending_on; depending_on = cbl_field_of(symbol_at(odo->occurs.depending_on)); @@ -601,6 +604,7 @@ get_data_offset(cbl_refer_t &refer, } else { + cbl_enabled_exceptions_t& enabled_exceptions( cdf_enabled_exceptions() ); if( !enabled_exceptions.match(ec_bound_subscript_e) ) { // With no exception testing, just pick up the value @@ -657,6 +661,8 @@ get_data_offset(cbl_refer_t &refer, // Although we strictly don't need to look at the ODO value at this point, // we do want it checked for the purposes of ec-bound-odo + cbl_enabled_exceptions_t& enabled_exceptions( cdf_enabled_exceptions() ); + if( enabled_exceptions.match(ec_bound_odo_e) ) { if( parent->occurs.depending_on ) @@ -1669,6 +1675,7 @@ set_exception_code_func(ec_type_t ec, int /*line*/, int from_raise_statement) bool process_this_exception(ec_type_t ec) { + cbl_enabled_exceptions_t& enabled_exceptions( cdf_enabled_exceptions() ); bool retval; if( enabled_exceptions.match(ec) || !skip_exception_processing ) { diff --git a/gcc/cobol/lexio.cc b/gcc/cobol/lexio.cc index 4a50441..0aebe52 100644 --- a/gcc/cobol/lexio.cc +++ b/gcc/cobol/lexio.cc @@ -321,7 +321,69 @@ recognize_replacements( filespan_t mfile, std::list<replace_t>& pending_replacem } static void +check_push_pop_directive( filespan_t& mfile ) { + char eol = '\0'; + const char *p = std::find(mfile.cur, mfile.eol, '>'); + if( ! (p < mfile.eol && p[1] == *p ) ) return; + + const char pattern[] = + ">>[[:blank:]]*(push|pop)[[:blank:]]+" + "(" + "all|" + "call-convention|" + "cobol-words|" + "define|" + "source[[:blank:]]+format|" + "turn" + ")"; + static regex re(pattern, extended_icase); + + // show contents of marked subexpressions within each match + cmatch cm; + + std::swap(*mfile.eol, eol); // see implementation for excuses + bool ok = regex_search(p, const_cast<const char *>(mfile.eol), cm, re); + std::swap(*mfile.eol, eol); + + if( ok ) { + gcc_assert(cm.size() > 1); + bool push = TOUPPER(cm[1].first[1]) == 'U'; + switch( TOUPPER(cm[2].first[0]) ) { + case 'A': // ALL + push? cdf_push() : cdf_pop(); + break; + case 'C': + switch( TOUPPER(cm[2].first[1]) ) { + case 'A': // CALL-CONVENTION + push? cdf_push_call_convention() : cdf_pop_call_convention(); + break; + case 'O': // COBOL-WORDS + push? cdf_push_current_tokens() : cdf_pop_current_tokens(); + break; + default: + gcc_unreachable(); + } + break; + case 'D': // DEFINE + push? cdf_push_dictionary() : cdf_pop_dictionary(); + break; + case 'S': // SOURCE FORMAT + push? cdf_push_source_format() : cdf_pop_source_format(); + break; + case 'T': // TURN + push? cdf_push_enabled_exceptions() : cdf_pop_enabled_exceptions(); + break; + default: + gcc_unreachable(); + } + erase_line(const_cast<char*>(cm[0].first), + const_cast<char*>(cm[0].second)); + } +} + +static void check_source_format_directive( filespan_t& mfile ) { + char eol = '\0'; const char *p = std::find(mfile.cur, mfile.eol, '>'); if( ! (p < mfile.eol && p[1] == *p ) ) return; @@ -334,7 +396,12 @@ check_source_format_directive( filespan_t& mfile ) { // show contents of marked subexpressions within each match cmatch cm; - if( regex_search(p, const_cast<const char *>(mfile.eol), cm, re) ) { + + std::swap(*mfile.eol, eol); // see implementation for excuses + bool ok = regex_search(p, const_cast<const char *>(mfile.eol), cm, re); + std::swap(*mfile.eol, eol); + + if( ok ) { gcc_assert(cm.size() > 1); switch( cm[3].length() ) { case 4: @@ -353,8 +420,8 @@ check_source_format_directive( filespan_t& mfile ) { cdf_source_format().description(), (fmt_size_t)mfile.lineno() ); char *bol = cdf_source_format().is_fixed()? mfile.cur : const_cast<char*>(cm[0].first); + gcc_assert(cm[0].second <= mfile.eol); erase_line(bol, const_cast<char*>(cm[0].second)); - mfile.cur = const_cast<char*>(cm[0].second); } } @@ -1688,6 +1755,7 @@ cdftext::free_form_reference_format( int input ) { } while( mfile.next_line() ) { + check_push_pop_directive(mfile); check_source_format_directive(mfile); remove_inline_comment(mfile.cur, mfile.eol); diff --git a/gcc/cobol/parse.y b/gcc/cobol/parse.y index 2212acc..83bffdf 100644 --- a/gcc/cobol/parse.y +++ b/gcc/cobol/parse.y @@ -386,7 +386,10 @@ CDF_EVALUATE ">>EVALUATE" CDF_WHEN ">>WHEN" CDF_END_EVALUATE ">>END-EVALUATE" + CALL_CONVENTION ">>CALL-CONVENTION" CALL_COBOL "CALL" CALL_VERBATIM "CALL (as C)" + CDF_PUSH ">>PUSH" CDF_POP ">>POP" + SOURCE_FORMAT ">>SOURCE FORMAT" IF THEN ELSE SENTENCE @@ -1469,16 +1472,16 @@ cobol_words: cobol_words1 | cobol_words cobol_words1 ; cobol_words1: COBOL_WORDS EQUATE NAME[keyword] WITH NAME[name] { - if( ! tokens.equate(@keyword, $keyword, $name) ) { YYERROR; } + if( ! cdf_tokens.equate(@keyword, $keyword, $name) ) { YYERROR; } } | COBOL_WORDS UNDEFINE NAME[keyword] { - if( ! tokens.undefine(@keyword, $keyword) ) { YYERROR; } + if( ! cdf_tokens.undefine(@keyword, $keyword) ) { YYERROR; } } | COBOL_WORDS SUBSTITUTE NAME[keyword] BY NAME[name] { - if( ! tokens.substitute(@keyword, $keyword, $name) ) { YYERROR; } + if( ! cdf_tokens.substitute(@keyword, $keyword, $name) ) { YYERROR; } } | COBOL_WORDS RESERVE NAME[name] { - if( ! tokens.reserve(@name, $name) ) { YYERROR; } + if( ! cdf_tokens.reserve(@name, $name) ) { YYERROR; } } ; @@ -4915,6 +4918,7 @@ by_value_arg: scalar declaratives: %empty | DECLARATIVES '.' <label>{ + cbl_enabled_exceptions_t& enabled_exceptions( cdf_enabled_exceptions() ); current.enabled_exception_cache = enabled_exceptions; enabled_exceptions.clear(); current.doing_declaratives(true); @@ -4933,6 +4937,7 @@ declaratives: %empty * forward reference, because we haven't yet begun to parse * nondeclarative procedures. */ + cbl_enabled_exceptions_t& enabled_exceptions( cdf_enabled_exceptions() ); parser_label_label($label); enabled_exceptions = current.enabled_exception_cache; current.enabled_exception_cache.clear(); @@ -11433,6 +11438,7 @@ void ast_call( const YYLTYPE& loc, cbl_refer_t name, const cbl_refer_t& returnin */ static bool possible_ec() { + cbl_enabled_exceptions_t& enabled_exceptions( cdf_enabled_exceptions() ); bool format_1 = current.declaratives.has_format_1(); bool enabled = 0xFF < (current.declaratives.status() @@ -11455,6 +11461,7 @@ possible_ec() { */ static void statement_epilog( int token ) { + cbl_enabled_exceptions_t& enabled_exceptions( cdf_enabled_exceptions() ); if( possible_ec() && token != CONTINUE ) { if( enabled_exceptions.size() ) { current.declaratives_evaluate(); @@ -11517,7 +11524,7 @@ keyword_str( int token ) { return ascii; } - return tokens.name_of(token); + return cdf_tokens.name_of(token); } bool iso_cobol_word( const std::string& name, bool include_context ); @@ -11589,7 +11596,7 @@ current_tokens_t::tokenset_t::find( const cbl_name_t name, bool include_intrinsi int keyword_tok( const char * text, bool include_intrinsics ) { - return tokens.find(text, include_intrinsics); + return cdf_tokens.find(text, include_intrinsics); } static inline size_t @@ -13131,7 +13138,7 @@ cobol_dialect_set( cbl_dialect_t dialect ) { break; case dialect_gnu_e: if( 0 == (cbl_dialects & dialect) ) { // first time - tokens.equate(YYLTYPE(), "BINARY-DOUBLE", "BINARY-C-LONG"); + cdf_tokens.equate(YYLTYPE(), "BINARY-DOUBLE", "BINARY-C-LONG"); } break; } diff --git a/gcc/cobol/parse_ante.h b/gcc/cobol/parse_ante.h index 3543a00..fa06e6c 100644 --- a/gcc/cobol/parse_ante.h +++ b/gcc/cobol/parse_ante.h @@ -935,11 +935,11 @@ teed_up_names() { return name_queue_t::namelist_of( name_queue.peek() ); } -current_tokens_t tokens; +#define cdf_tokens cdf_current_tokens() int redefined_token( const cbl_name_t name ) { - return tokens.redefined_as(name); + return cdf_tokens.redefined_as(name); } struct file_list_t { @@ -1321,7 +1321,6 @@ class prog_descr_t { } } } locale; - cbl_call_convention_t call_convention; cbl_options_t options; explicit prog_descr_t( size_t isymbol ) @@ -1330,9 +1329,7 @@ class prog_descr_t { , paragraph(NULL) , section(NULL) , collating_sequence(NULL) - { - call_convention = current_call_convention(); - } + {} std::set<std::string> external_targets() { std::set<std::string> externals; @@ -1421,24 +1418,13 @@ static cbl_label_t * implicit_section(); class program_stack_t : protected std::stack<prog_descr_t> { struct pending_t { - cbl_call_convention_t call_convention; bool initial; - pending_t() - : call_convention(cbl_call_convention_t(0)) - , initial(false) - {} + pending_t() : initial(false) {} } pending; public: - cbl_call_convention_t - pending_call_convention( cbl_call_convention_t convention ) { - return pending.call_convention = convention; - } bool pending_initial() { return pending.initial = true; } void push( prog_descr_t descr ) { - cbl_call_convention_t call_convention = cbl_call_cobol_e; - if( !empty() ) call_convention = top().call_convention; - descr.call_convention = call_convention; std::stack<prog_descr_t>& me(*this); me.push(descr); } @@ -1464,9 +1450,6 @@ class program_stack_t : protected std::stack<prog_descr_t> { } void apply_pending() { - if( size() == 1 && 0 != pending.call_convention ) { - top().call_convention = pending.call_convention; - } if( pending.initial ) { auto e = symbol_at(top().program_index); auto prog(cbl_label_of(e)); @@ -1873,19 +1856,6 @@ static class current_t { return programs.top().options.default_round = mode; } - cbl_call_convention_t - call_convention() { - return programs.empty()? cbl_call_cobol_e : programs.top().call_convention; - } - cbl_call_convention_t - call_convention( cbl_call_convention_t convention) { - if( programs.empty() ) { - return programs.pending_call_convention(convention); - } - auto& prog( programs.top() ); - return prog.call_convention = convention; - } - const char * locale() { return programs.empty()? NULL : programs.top().locale.os_name; @@ -1983,6 +1953,7 @@ static class current_t { * ISO, in new_program. */ std::set<std::string> end_program() { + cbl_enabled_exceptions_t& enabled_exceptions( cdf_enabled_exceptions() ); if( enabled_exceptions.size() ) { declaratives_evaluate(); } @@ -2273,15 +2244,6 @@ current_rounded_mode( cbl_round_t rounded) { #endif static cbl_round_t current_rounded_mode( int token ); -cbl_call_convention_t -current_call_convention() { - return current.call_convention(); -} -cbl_call_convention_t -current_call_convention( cbl_call_convention_t convention) { - return current.call_convention(convention); -} - size_t program_level() { return current.program_level(); } static size_t constant_index( int token ); diff --git a/gcc/cobol/scan.l b/gcc/cobol/scan.l index 3c12eda..8b5dc25 100644 --- a/gcc/cobol/scan.l +++ b/gcc/cobol/scan.l @@ -2095,15 +2095,28 @@ BASIS { yy_push_state(basis); return BASIS; } ^[ ]*>>{OBLANK}TURN { yy_push_state(exception); return TURN; } ^[ ]*>>{OBLANK}COBOL-WORDS { yy_push_state(cobol_words); return COBOL_WORDS; } + ^[ ]*>>{OBLANK}SOURCE{BLANK}FORMAT { return SOURCE_FORMAT; } + + ^[ ]*>>{OBLANK}PUSH { return CDF_PUSH; } + ^[ ]*>>{OBLANK}POP { return CDF_POP; } + ^[ ]*>>{OBLANK}{NAME} { error_msg(yylloc, "unknown CDF token: %s", yytext); } + OTHER { return OTHER; } OVERRIDE { return OVERRIDE; } PARAMETER { return PARAMETER_kw; } THRU { return THRU; } TRUE { return TRUE_kw; } + + ALL { return ALL; } + CALL-CONVENTION { return CALL_CONVENTION; } + COBOL-WORDS { return COBOL_WORDS; } + DEFINE { return CDF_DEFINE; } + SOURCE{BLANK}FORMAT { return SOURCE_FORMAT; } + } <cobol_words>{ diff --git a/gcc/cobol/scan_post.h b/gcc/cobol/scan_post.h index fd70ea9..7cf2b98 100644 --- a/gcc/cobol/scan_post.h +++ b/gcc/cobol/scan_post.h @@ -158,6 +158,8 @@ is_cdf_token( int token ) { case CDF_DISPLAY: case CDF_IF: case CDF_ELSE: case CDF_END_IF: case CDF_EVALUATE: case CDF_WHEN: case CDF_END_EVALUATE: + case CDF_PUSH: + case CDF_POP: return true; case CALL_COBOL: case CALL_VERBATIM: diff --git a/gcc/cobol/symbols.h b/gcc/cobol/symbols.h index f96f1ec..c3de0aa 100644 --- a/gcc/cobol/symbols.h +++ b/gcc/cobol/symbols.h @@ -2551,8 +2551,9 @@ class current_tokens_t { }; cbl_call_convention_t current_call_convention(); +current_tokens_t& cdf_current_tokens(); -cbl_call_convention_t +void current_call_convention( cbl_call_convention_t convention); class procref_base_t { diff --git a/gcc/cobol/token_names.h b/gcc/cobol/token_names.h index d35b706..ca51510 100644 --- a/gcc/cobol/token_names.h +++ b/gcc/cobol/token_names.h @@ -1,5 +1,5 @@ // generated by ./token_names.h.gen ../../build/gcc/cobol/parse.h -// Fri Jul 4 12:35:01 EDT 2025 +// Tue Jul 8 19:21:28 EDT 2025 tokens = { { "identification", IDENTIFICATION_DIV }, // 258 { "environment", ENVIRONMENT_DIV }, // 259 @@ -137,562 +137,566 @@ tokens = { { "cdf-evaluate", CDF_EVALUATE }, // 388 { "cdf-when", CDF_WHEN }, // 389 { "cdf-end-evaluate", CDF_END_EVALUATE }, // 390 - { "call-cobol", CALL_COBOL }, // 391 - { "call-verbatim", CALL_VERBATIM }, // 392 - { "if", IF }, // 393 - { "then", THEN }, // 394 - { "else", ELSE }, // 395 - { "sentence", SENTENCE }, // 396 - { "accept", ACCEPT }, // 397 - { "add", ADD }, // 398 - { "alter", ALTER }, // 399 - { "call", CALL }, // 400 - { "cancel", CANCEL }, // 401 - { "close", CLOSE }, // 402 - { "compute", COMPUTE }, // 403 - { "continue", CONTINUE }, // 404 - { "delete", DELETE }, // 405 - { "display", DISPLAY }, // 406 - { "divide", DIVIDE }, // 407 - { "evaluate", EVALUATE }, // 408 - { "exit", EXIT }, // 409 - { "filler", FILLER_kw }, // 410 - { "goback", GOBACK }, // 411 - { "goto", GOTO }, // 412 - { "initialize", INITIALIZE }, // 413 - { "inspect", INSPECT }, // 414 - { "merge", MERGE }, // 415 - { "move", MOVE }, // 416 - { "multiply", MULTIPLY }, // 417 - { "open", OPEN }, // 418 - { "paragraph", PARAGRAPH }, // 419 - { "read", READ }, // 420 - { "release", RELEASE }, // 421 - { "return", RETURN }, // 422 - { "rewrite", REWRITE }, // 423 - { "search", SEARCH }, // 424 - { "set", SET }, // 425 - { "select", SELECT }, // 426 - { "sort", SORT }, // 427 - { "sort-merge", SORT_MERGE }, // 428 - { "string", STRING_kw }, // 429 - { "stop", STOP }, // 430 - { "subtract", SUBTRACT }, // 431 - { "start", START }, // 432 - { "unstring", UNSTRING }, // 433 - { "write", WRITE }, // 434 - { "when", WHEN }, // 435 - { "argument-number", ARGUMENT_NUMBER }, // 436 - { "argument-value", ARGUMENT_VALUE }, // 437 - { "environment-name", ENVIRONMENT_NAME }, // 438 - { "environment-value", ENVIRONMENT_VALUE }, // 439 - { "abs", ABS }, // 440 - { "access", ACCESS }, // 441 - { "acos", ACOS }, // 442 - { "actual", ACTUAL }, // 443 - { "advancing", ADVANCING }, // 444 - { "after", AFTER }, // 445 - { "all", ALL }, // 446 - { "allocate", ALLOCATE }, // 447 - { "alphabet", ALPHABET }, // 448 - { "alphabetic", ALPHABETIC }, // 449 - { "alphabetic-lower", ALPHABETIC_LOWER }, // 450 - { "alphabetic-upper", ALPHABETIC_UPPER }, // 451 - { "alphanumeric", ALPHANUMERIC }, // 452 - { "alphanumeric-edited", ALPHANUMERIC_EDITED }, // 453 - { "also", ALSO }, // 454 - { "alternate", ALTERNATE }, // 455 - { "annuity", ANNUITY }, // 456 - { "anum", ANUM }, // 457 - { "any", ANY }, // 458 - { "anycase", ANYCASE }, // 459 - { "apply", APPLY }, // 460 - { "are", ARE }, // 461 - { "area", AREA }, // 462 - { "areas", AREAS }, // 463 - { "as", AS }, // 464 - { "ascending", ASCENDING }, // 465 - { "activating", ACTIVATING }, // 466 - { "asin", ASIN }, // 467 - { "assign", ASSIGN }, // 468 - { "at", AT }, // 469 - { "atan", ATAN }, // 470 - { "based", BASED }, // 471 - { "baseconvert", BASECONVERT }, // 472 - { "before", BEFORE }, // 473 - { "binary", BINARY }, // 474 - { "bit", BIT }, // 475 - { "bit-of", BIT_OF }, // 476 - { "bit-to-char", BIT_TO_CHAR }, // 477 - { "blank", BLANK }, // 478 - { "block", BLOCK_kw }, // 479 - { "boolean-of-integer", BOOLEAN_OF_INTEGER }, // 480 - { "bottom", BOTTOM }, // 481 - { "by", BY }, // 482 - { "byte", BYTE }, // 483 - { "byte-length", BYTE_LENGTH }, // 484 - { "cf", CF }, // 485 - { "ch", CH }, // 486 - { "changed", CHANGED }, // 487 - { "char", CHAR }, // 488 - { "char-national", CHAR_NATIONAL }, // 489 - { "character", CHARACTER }, // 490 - { "characters", CHARACTERS }, // 491 - { "checking", CHECKING }, // 492 - { "class", CLASS }, // 493 - { "cobol", COBOL }, // 494 - { "code", CODE }, // 495 - { "code-set", CODESET }, // 496 - { "collating", COLLATING }, // 497 - { "column", COLUMN }, // 498 - { "combined-datetime", COMBINED_DATETIME }, // 499 - { "comma", COMMA }, // 500 - { "command-line", COMMAND_LINE }, // 501 - { "command-line-count", COMMAND_LINE_COUNT }, // 502 - { "commit", COMMIT }, // 503 - { "common", COMMON }, // 504 - { "concat", CONCAT }, // 505 - { "condition", CONDITION }, // 506 - { "configuration", CONFIGURATION_SECT }, // 507 - { "contains", CONTAINS }, // 508 - { "content", CONTENT }, // 509 - { "control", CONTROL }, // 510 - { "controls", CONTROLS }, // 511 - { "convert", CONVERT }, // 512 - { "converting", CONVERTING }, // 513 - { "corresponding", CORRESPONDING }, // 514 - { "cos", COS }, // 515 - { "count", COUNT }, // 516 - { "currency", CURRENCY }, // 517 - { "current", CURRENT }, // 518 - { "current-date", CURRENT_DATE }, // 519 - { "data", DATA }, // 520 - { "date", DATE }, // 521 - { "date-compiled", DATE_COMPILED }, // 522 - { "date-of-integer", DATE_OF_INTEGER }, // 523 - { "date-to-yyyymmdd", DATE_TO_YYYYMMDD }, // 524 - { "date-written", DATE_WRITTEN }, // 525 - { "day", DAY }, // 526 - { "day-of-integer", DAY_OF_INTEGER }, // 527 - { "day-of-week", DAY_OF_WEEK }, // 528 - { "day-to-yyyyddd", DAY_TO_YYYYDDD }, // 529 - { "dbcs", DBCS }, // 530 - { "de", DE }, // 531 - { "debugging", DEBUGGING }, // 532 - { "decimal-point", DECIMAL_POINT }, // 533 - { "declaratives", DECLARATIVES }, // 534 - { "default", DEFAULT }, // 535 - { "delimited", DELIMITED }, // 536 - { "delimiter", DELIMITER }, // 537 - { "depending", DEPENDING }, // 538 - { "descending", DESCENDING }, // 539 - { "detail", DETAIL }, // 540 - { "direct", DIRECT }, // 541 - { "direct-access", DIRECT_ACCESS }, // 542 - { "down", DOWN }, // 543 - { "duplicates", DUPLICATES }, // 544 - { "dynamic", DYNAMIC }, // 545 - { "e", E }, // 546 - { "ebcdic", EBCDIC }, // 547 - { "ec", EC }, // 548 - { "egcs", EGCS }, // 549 - { "entry", ENTRY }, // 550 - { "environment", ENVIRONMENT }, // 551 - { "equal", EQUAL }, // 552 - { "every", EVERY }, // 553 - { "examine", EXAMINE }, // 554 - { "exhibit", EXHIBIT }, // 555 - { "exp", EXP }, // 556 - { "exp10", EXP10 }, // 557 - { "extend", EXTEND }, // 558 - { "external", EXTERNAL }, // 559 - { "exception-file", EXCEPTION_FILE }, // 560 - { "exception-file-n", EXCEPTION_FILE_N }, // 561 - { "exception-location", EXCEPTION_LOCATION }, // 562 - { "exception-location-n", EXCEPTION_LOCATION_N }, // 563 - { "exception-statement", EXCEPTION_STATEMENT }, // 564 - { "exception-status", EXCEPTION_STATUS }, // 565 - { "factorial", FACTORIAL }, // 566 - { "false", FALSE_kw }, // 567 - { "fd", FD }, // 568 - { "file-control", FILE_CONTROL }, // 569 - { "file", FILE_KW }, // 570 - { "file-limit", FILE_LIMIT }, // 571 - { "final", FINAL }, // 572 - { "finally", FINALLY }, // 573 - { "find-string", FIND_STRING }, // 574 - { "first", FIRST }, // 575 - { "fixed", FIXED }, // 576 - { "footing", FOOTING }, // 577 - { "for", FOR }, // 578 - { "formatted-current-date", FORMATTED_CURRENT_DATE }, // 579 - { "formatted-date", FORMATTED_DATE }, // 580 - { "formatted-datetime", FORMATTED_DATETIME }, // 581 - { "formatted-time", FORMATTED_TIME }, // 582 - { "form-overflow", FORM_OVERFLOW }, // 583 - { "free", FREE }, // 584 - { "fraction-part", FRACTION_PART }, // 585 - { "from", FROM }, // 586 - { "function", FUNCTION }, // 587 - { "generate", GENERATE }, // 588 - { "giving", GIVING }, // 589 - { "global", GLOBAL }, // 590 - { "go", GO }, // 591 - { "group", GROUP }, // 592 - { "heading", HEADING }, // 593 - { "hex", HEX }, // 594 - { "hex-of", HEX_OF }, // 595 - { "hex-to-char", HEX_TO_CHAR }, // 596 - { "high-values", HIGH_VALUES }, // 597 - { "highest-algebraic", HIGHEST_ALGEBRAIC }, // 598 - { "hold", HOLD }, // 599 - { "ibm-360", IBM_360 }, // 600 - { "in", IN }, // 601 - { "include", INCLUDE }, // 602 - { "index", INDEX }, // 603 - { "indexed", INDEXED }, // 604 - { "indicate", INDICATE }, // 605 - { "initial", INITIAL_kw }, // 606 - { "initiate", INITIATE }, // 607 - { "input", INPUT }, // 608 - { "installation", INSTALLATION }, // 609 - { "interface", INTERFACE }, // 610 - { "integer", INTEGER }, // 611 - { "integer-of-boolean", INTEGER_OF_BOOLEAN }, // 612 - { "integer-of-date", INTEGER_OF_DATE }, // 613 - { "integer-of-day", INTEGER_OF_DAY }, // 614 - { "integer-of-formatted-date", INTEGER_OF_FORMATTED_DATE }, // 615 - { "integer-part", INTEGER_PART }, // 616 - { "into", INTO }, // 617 - { "intrinsic", INTRINSIC }, // 618 - { "invoke", INVOKE }, // 619 - { "i-o", IO }, // 620 - { "i-o-control", IO_CONTROL }, // 621 - { "is", IS }, // 622 - { "isnt", ISNT }, // 623 - { "kanji", KANJI }, // 624 - { "key", KEY }, // 625 - { "label", LABEL }, // 626 - { "last", LAST }, // 627 - { "leading", LEADING }, // 628 - { "left", LEFT }, // 629 - { "length", LENGTH }, // 630 - { "length-of", LENGTH_OF }, // 631 - { "limit", LIMIT }, // 632 - { "limits", LIMITS }, // 633 - { "line", LINE }, // 634 - { "lines", LINES }, // 635 - { "line-counter", LINE_COUNTER }, // 636 - { "linage", LINAGE }, // 637 - { "linkage", LINKAGE }, // 638 - { "locale", LOCALE }, // 639 - { "locale-compare", LOCALE_COMPARE }, // 640 - { "locale-date", LOCALE_DATE }, // 641 - { "locale-time", LOCALE_TIME }, // 642 - { "locale-time-from-seconds", LOCALE_TIME_FROM_SECONDS }, // 643 - { "local-storage", LOCAL_STORAGE }, // 644 - { "location", LOCATION }, // 645 - { "lock", LOCK }, // 646 - { "lock-on", LOCK_ON }, // 647 - { "log", LOG }, // 648 - { "log10", LOG10 }, // 649 - { "lower-case", LOWER_CASE }, // 650 - { "low-values", LOW_VALUES }, // 651 - { "lowest-algebraic", LOWEST_ALGEBRAIC }, // 652 - { "lparen", LPAREN }, // 653 - { "manual", MANUAL }, // 654 - { "maxx", MAXX }, // 655 - { "mean", MEAN }, // 656 - { "median", MEDIAN }, // 657 - { "midrange", MIDRANGE }, // 658 - { "minn", MINN }, // 659 - { "multiple", MULTIPLE }, // 660 - { "mod", MOD }, // 661 - { "mode", MODE }, // 662 - { "module-name", MODULE_NAME }, // 663 - { "named", NAMED }, // 664 - { "nat", NAT }, // 665 - { "national", NATIONAL }, // 666 - { "national-edited", NATIONAL_EDITED }, // 667 - { "national-of", NATIONAL_OF }, // 668 - { "native", NATIVE }, // 669 - { "nested", NESTED }, // 670 - { "next", NEXT }, // 671 - { "no", NO }, // 672 - { "note", NOTE }, // 673 - { "nulls", NULLS }, // 674 - { "null", NULLS }, // 674 - { "nullptr", NULLPTR }, // 675 - { "numeric", NUMERIC }, // 676 - { "numeric-edited", NUMERIC_EDITED }, // 677 - { "numval", NUMVAL }, // 678 - { "numval-c", NUMVAL_C }, // 679 - { "numval-f", NUMVAL_F }, // 680 - { "occurs", OCCURS }, // 681 - { "of", OF }, // 682 - { "off", OFF }, // 683 - { "omitted", OMITTED }, // 684 - { "on", ON }, // 685 - { "only", ONLY }, // 686 - { "optional", OPTIONAL }, // 687 - { "options", OPTIONS }, // 688 - { "ord", ORD }, // 689 - { "order", ORDER }, // 690 - { "ord-max", ORD_MAX }, // 691 - { "ord-min", ORD_MIN }, // 692 - { "organization", ORGANIZATION }, // 693 - { "other", OTHER }, // 694 - { "otherwise", OTHERWISE }, // 695 - { "output", OUTPUT }, // 696 - { "packed-decimal", PACKED_DECIMAL }, // 697 - { "padding", PADDING }, // 698 - { "page", PAGE }, // 699 - { "page-counter", PAGE_COUNTER }, // 700 - { "pf", PF }, // 701 - { "ph", PH }, // 702 - { "pi", PI }, // 703 - { "pic", PIC }, // 704 - { "picture", PICTURE }, // 705 - { "plus", PLUS }, // 706 - { "present-value", PRESENT_VALUE }, // 707 - { "print-switch", PRINT_SWITCH }, // 708 - { "procedure", PROCEDURE }, // 709 - { "procedures", PROCEDURES }, // 710 - { "proceed", PROCEED }, // 711 - { "process", PROCESS }, // 712 - { "program-id", PROGRAM_ID }, // 713 - { "program", PROGRAM_kw }, // 714 - { "property", PROPERTY }, // 715 - { "prototype", PROTOTYPE }, // 716 - { "pseudotext", PSEUDOTEXT }, // 717 - { "quotes", QUOTES }, // 718 - { "quote", QUOTES }, // 718 - { "random", RANDOM }, // 719 - { "random-seed", RANDOM_SEED }, // 720 - { "range", RANGE }, // 721 - { "raise", RAISE }, // 722 - { "raising", RAISING }, // 723 - { "rd", RD }, // 724 - { "record", RECORD }, // 725 - { "recording", RECORDING }, // 726 - { "records", RECORDS }, // 727 - { "recursive", RECURSIVE }, // 728 - { "redefines", REDEFINES }, // 729 - { "reel", REEL }, // 730 - { "reference", REFERENCE }, // 731 - { "relative", RELATIVE }, // 732 - { "rem", REM }, // 733 - { "remainder", REMAINDER }, // 734 - { "remarks", REMARKS }, // 735 - { "removal", REMOVAL }, // 736 - { "renames", RENAMES }, // 737 - { "replace", REPLACE }, // 738 - { "replacing", REPLACING }, // 739 - { "report", REPORT }, // 740 - { "reporting", REPORTING }, // 741 - { "reports", REPORTS }, // 742 - { "repository", REPOSITORY }, // 743 - { "rerun", RERUN }, // 744 - { "reserve", RESERVE }, // 745 - { "restricted", RESTRICTED }, // 746 - { "resume", RESUME }, // 747 - { "reverse", REVERSE }, // 748 - { "reversed", REVERSED }, // 749 - { "rewind", REWIND }, // 750 - { "rf", RF }, // 751 - { "rh", RH }, // 752 - { "right", RIGHT }, // 753 - { "rounded", ROUNDED }, // 754 - { "run", RUN }, // 755 - { "same", SAME }, // 756 - { "screen", SCREEN }, // 757 - { "sd", SD }, // 758 - { "seconds-from-formatted-time", SECONDS_FROM_FORMATTED_TIME }, // 759 - { "seconds-past-midnight", SECONDS_PAST_MIDNIGHT }, // 760 - { "security", SECURITY }, // 761 - { "separate", SEPARATE }, // 762 - { "sequence", SEQUENCE }, // 763 - { "sequential", SEQUENTIAL }, // 764 - { "sharing", SHARING }, // 765 - { "simple-exit", SIMPLE_EXIT }, // 766 - { "sign", SIGN }, // 767 - { "sin", SIN }, // 768 - { "size", SIZE }, // 769 - { "smallest-algebraic", SMALLEST_ALGEBRAIC }, // 770 - { "source", SOURCE }, // 771 - { "source-computer", SOURCE_COMPUTER }, // 772 - { "special-names", SPECIAL_NAMES }, // 773 - { "sqrt", SQRT }, // 774 - { "stack", STACK }, // 775 - { "standard", STANDARD }, // 776 - { "standard-1", STANDARD_1 }, // 777 - { "standard-deviation", STANDARD_DEVIATION }, // 778 - { "standard-compare", STANDARD_COMPARE }, // 779 - { "status", STATUS }, // 780 - { "strong", STRONG }, // 781 - { "substitute", SUBSTITUTE }, // 782 - { "sum", SUM }, // 783 - { "symbol", SYMBOL }, // 784 - { "symbolic", SYMBOLIC }, // 785 - { "synchronized", SYNCHRONIZED }, // 786 - { "tally", TALLY }, // 787 - { "tallying", TALLYING }, // 788 - { "tan", TAN }, // 789 - { "terminate", TERMINATE }, // 790 - { "test", TEST }, // 791 - { "test-date-yyyymmdd", TEST_DATE_YYYYMMDD }, // 792 - { "test-day-yyyyddd", TEST_DAY_YYYYDDD }, // 793 - { "test-formatted-datetime", TEST_FORMATTED_DATETIME }, // 794 - { "test-numval", TEST_NUMVAL }, // 795 - { "test-numval-c", TEST_NUMVAL_C }, // 796 - { "test-numval-f", TEST_NUMVAL_F }, // 797 - { "than", THAN }, // 798 - { "time", TIME }, // 799 - { "times", TIMES }, // 800 - { "to", TO }, // 801 - { "top", TOP }, // 802 - { "top-level", TOP_LEVEL }, // 803 - { "tracks", TRACKS }, // 804 - { "track-area", TRACK_AREA }, // 805 - { "trailing", TRAILING }, // 806 - { "transform", TRANSFORM }, // 807 - { "trim", TRIM }, // 808 - { "true", TRUE_kw }, // 809 - { "try", TRY }, // 810 - { "turn", TURN }, // 811 - { "type", TYPE }, // 812 - { "typedef", TYPEDEF }, // 813 - { "ulength", ULENGTH }, // 814 - { "unbounded", UNBOUNDED }, // 815 - { "unit", UNIT }, // 816 - { "units", UNITS }, // 817 - { "unit-record", UNIT_RECORD }, // 818 - { "until", UNTIL }, // 819 - { "up", UP }, // 820 - { "upon", UPON }, // 821 - { "upos", UPOS }, // 822 - { "upper-case", UPPER_CASE }, // 823 - { "usage", USAGE }, // 824 - { "using", USING }, // 825 - { "usubstr", USUBSTR }, // 826 - { "usupplementary", USUPPLEMENTARY }, // 827 - { "utility", UTILITY }, // 828 - { "uuid4", UUID4 }, // 829 - { "uvalid", UVALID }, // 830 - { "uwidth", UWIDTH }, // 831 - { "value", VALUE }, // 832 - { "variance", VARIANCE }, // 833 - { "varying", VARYING }, // 834 - { "volatile", VOLATILE }, // 835 - { "when-compiled", WHEN_COMPILED }, // 836 - { "with", WITH }, // 837 - { "working-storage", WORKING_STORAGE }, // 838 - { "xml", XML }, // 839 - { "xmlgenerate", XMLGENERATE }, // 840 - { "xmlparse", XMLPARSE }, // 841 - { "year-to-yyyy", YEAR_TO_YYYY }, // 842 - { "yyyyddd", YYYYDDD }, // 843 - { "yyyymmdd", YYYYMMDD }, // 844 - { "arithmetic", ARITHMETIC }, // 845 - { "attribute", ATTRIBUTE }, // 846 - { "auto", AUTO }, // 847 - { "automatic", AUTOMATIC }, // 848 - { "away-from-zero", AWAY_FROM_ZERO }, // 849 - { "background-color", BACKGROUND_COLOR }, // 850 - { "bell", BELL }, // 851 - { "binary-encoding", BINARY_ENCODING }, // 852 - { "blink", BLINK }, // 853 - { "capacity", CAPACITY }, // 854 - { "center", CENTER }, // 855 - { "classification", CLASSIFICATION }, // 856 - { "cycle", CYCLE }, // 857 - { "decimal-encoding", DECIMAL_ENCODING }, // 858 - { "entry-convention", ENTRY_CONVENTION }, // 859 - { "eol", EOL }, // 860 - { "eos", EOS }, // 861 - { "erase", ERASE }, // 862 - { "expands", EXPANDS }, // 863 - { "float-binary", FLOAT_BINARY }, // 864 - { "float-decimal", FLOAT_DECIMAL }, // 865 - { "foreground-color", FOREGROUND_COLOR }, // 866 - { "forever", FOREVER }, // 867 - { "full", FULL }, // 868 - { "highlight", HIGHLIGHT }, // 869 - { "high-order-left", HIGH_ORDER_LEFT }, // 870 - { "high-order-right", HIGH_ORDER_RIGHT }, // 871 - { "ignoring", IGNORING }, // 872 - { "implements", IMPLEMENTS }, // 873 - { "initialized", INITIALIZED }, // 874 - { "intermediate", INTERMEDIATE }, // 875 - { "lc-all", LC_ALL_kw }, // 876 - { "lc-collate", LC_COLLATE_kw }, // 877 - { "lc-ctype", LC_CTYPE_kw }, // 878 - { "lc-messages", LC_MESSAGES_kw }, // 879 - { "lc-monetary", LC_MONETARY_kw }, // 880 - { "lc-numeric", LC_NUMERIC_kw }, // 881 - { "lc-time", LC_TIME_kw }, // 882 - { "lowlight", LOWLIGHT }, // 883 - { "nearest-away-from-zero", NEAREST_AWAY_FROM_ZERO }, // 884 - { "nearest-even", NEAREST_EVEN }, // 885 - { "nearest-toward-zero", NEAREST_TOWARD_ZERO }, // 886 - { "none", NONE }, // 887 - { "normal", NORMAL }, // 888 - { "numbers", NUMBERS }, // 889 - { "prefixed", PREFIXED }, // 890 - { "previous", PREVIOUS }, // 891 - { "prohibited", PROHIBITED }, // 892 - { "relation", RELATION }, // 893 - { "required", REQUIRED }, // 894 - { "reverse-video", REVERSE_VIDEO }, // 895 - { "rounding", ROUNDING }, // 896 - { "seconds", SECONDS }, // 897 - { "secure", SECURE }, // 898 - { "short", SHORT }, // 899 - { "signed", SIGNED_kw }, // 900 - { "standard-binary", STANDARD_BINARY }, // 901 - { "standard-decimal", STANDARD_DECIMAL }, // 902 - { "statement", STATEMENT }, // 903 - { "step", STEP }, // 904 - { "structure", STRUCTURE }, // 905 - { "toward-greater", TOWARD_GREATER }, // 906 - { "toward-lesser", TOWARD_LESSER }, // 907 - { "truncation", TRUNCATION }, // 908 - { "ucs-4", UCS_4 }, // 909 - { "underline", UNDERLINE }, // 910 - { "unsigned", UNSIGNED_kw }, // 911 - { "utf-16", UTF_16 }, // 912 - { "utf-8", UTF_8 }, // 913 - { "address", ADDRESS }, // 914 - { "end-accept", END_ACCEPT }, // 915 - { "end-add", END_ADD }, // 916 - { "end-call", END_CALL }, // 917 - { "end-compute", END_COMPUTE }, // 918 - { "end-delete", END_DELETE }, // 919 - { "end-display", END_DISPLAY }, // 920 - { "end-divide", END_DIVIDE }, // 921 - { "end-evaluate", END_EVALUATE }, // 922 - { "end-multiply", END_MULTIPLY }, // 923 - { "end-perform", END_PERFORM }, // 924 - { "end-read", END_READ }, // 925 - { "end-return", END_RETURN }, // 926 - { "end-rewrite", END_REWRITE }, // 927 - { "end-search", END_SEARCH }, // 928 - { "end-start", END_START }, // 929 - { "end-string", END_STRING }, // 930 - { "end-subtract", END_SUBTRACT }, // 931 - { "end-unstring", END_UNSTRING }, // 932 - { "end-write", END_WRITE }, // 933 - { "end-if", END_IF }, // 934 - { "thru", THRU }, // 935 - { "through", THRU }, // 935 - { "or", OR }, // 936 - { "and", AND }, // 937 - { "not", NOT }, // 938 - { "ne", NE }, // 939 - { "le", LE }, // 940 - { "ge", GE }, // 941 - { "pow", POW }, // 942 - { "neg", NEG }, // 943 + { "call-convention", CALL_CONVENTION }, // 391 + { "call-cobol", CALL_COBOL }, // 392 + { "call-verbatim", CALL_VERBATIM }, // 393 + { "cdf-push", CDF_PUSH }, // 394 + { "cdf-pop", CDF_POP }, // 395 + { "source-format", SOURCE_FORMAT }, // 396 + { "if", IF }, // 397 + { "then", THEN }, // 398 + { "else", ELSE }, // 399 + { "sentence", SENTENCE }, // 400 + { "accept", ACCEPT }, // 401 + { "add", ADD }, // 402 + { "alter", ALTER }, // 403 + { "call", CALL }, // 404 + { "cancel", CANCEL }, // 405 + { "close", CLOSE }, // 406 + { "compute", COMPUTE }, // 407 + { "continue", CONTINUE }, // 408 + { "delete", DELETE }, // 409 + { "display", DISPLAY }, // 410 + { "divide", DIVIDE }, // 411 + { "evaluate", EVALUATE }, // 412 + { "exit", EXIT }, // 413 + { "filler", FILLER_kw }, // 414 + { "goback", GOBACK }, // 415 + { "goto", GOTO }, // 416 + { "initialize", INITIALIZE }, // 417 + { "inspect", INSPECT }, // 418 + { "merge", MERGE }, // 419 + { "move", MOVE }, // 420 + { "multiply", MULTIPLY }, // 421 + { "open", OPEN }, // 422 + { "paragraph", PARAGRAPH }, // 423 + { "read", READ }, // 424 + { "release", RELEASE }, // 425 + { "return", RETURN }, // 426 + { "rewrite", REWRITE }, // 427 + { "search", SEARCH }, // 428 + { "set", SET }, // 429 + { "select", SELECT }, // 430 + { "sort", SORT }, // 431 + { "sort-merge", SORT_MERGE }, // 432 + { "string", STRING_kw }, // 433 + { "stop", STOP }, // 434 + { "subtract", SUBTRACT }, // 435 + { "start", START }, // 436 + { "unstring", UNSTRING }, // 437 + { "write", WRITE }, // 438 + { "when", WHEN }, // 439 + { "argument-number", ARGUMENT_NUMBER }, // 440 + { "argument-value", ARGUMENT_VALUE }, // 441 + { "environment-name", ENVIRONMENT_NAME }, // 442 + { "environment-value", ENVIRONMENT_VALUE }, // 443 + { "abs", ABS }, // 444 + { "access", ACCESS }, // 445 + { "acos", ACOS }, // 446 + { "actual", ACTUAL }, // 447 + { "advancing", ADVANCING }, // 448 + { "after", AFTER }, // 449 + { "all", ALL }, // 450 + { "allocate", ALLOCATE }, // 451 + { "alphabet", ALPHABET }, // 452 + { "alphabetic", ALPHABETIC }, // 453 + { "alphabetic-lower", ALPHABETIC_LOWER }, // 454 + { "alphabetic-upper", ALPHABETIC_UPPER }, // 455 + { "alphanumeric", ALPHANUMERIC }, // 456 + { "alphanumeric-edited", ALPHANUMERIC_EDITED }, // 457 + { "also", ALSO }, // 458 + { "alternate", ALTERNATE }, // 459 + { "annuity", ANNUITY }, // 460 + { "anum", ANUM }, // 461 + { "any", ANY }, // 462 + { "anycase", ANYCASE }, // 463 + { "apply", APPLY }, // 464 + { "are", ARE }, // 465 + { "area", AREA }, // 466 + { "areas", AREAS }, // 467 + { "as", AS }, // 468 + { "ascending", ASCENDING }, // 469 + { "activating", ACTIVATING }, // 470 + { "asin", ASIN }, // 471 + { "assign", ASSIGN }, // 472 + { "at", AT }, // 473 + { "atan", ATAN }, // 474 + { "based", BASED }, // 475 + { "baseconvert", BASECONVERT }, // 476 + { "before", BEFORE }, // 477 + { "binary", BINARY }, // 478 + { "bit", BIT }, // 479 + { "bit-of", BIT_OF }, // 480 + { "bit-to-char", BIT_TO_CHAR }, // 481 + { "blank", BLANK }, // 482 + { "block", BLOCK_kw }, // 483 + { "boolean-of-integer", BOOLEAN_OF_INTEGER }, // 484 + { "bottom", BOTTOM }, // 485 + { "by", BY }, // 486 + { "byte", BYTE }, // 487 + { "byte-length", BYTE_LENGTH }, // 488 + { "cf", CF }, // 489 + { "ch", CH }, // 490 + { "changed", CHANGED }, // 491 + { "char", CHAR }, // 492 + { "char-national", CHAR_NATIONAL }, // 493 + { "character", CHARACTER }, // 494 + { "characters", CHARACTERS }, // 495 + { "checking", CHECKING }, // 496 + { "class", CLASS }, // 497 + { "cobol", COBOL }, // 498 + { "code", CODE }, // 499 + { "code-set", CODESET }, // 500 + { "collating", COLLATING }, // 501 + { "column", COLUMN }, // 502 + { "combined-datetime", COMBINED_DATETIME }, // 503 + { "comma", COMMA }, // 504 + { "command-line", COMMAND_LINE }, // 505 + { "command-line-count", COMMAND_LINE_COUNT }, // 506 + { "commit", COMMIT }, // 507 + { "common", COMMON }, // 508 + { "concat", CONCAT }, // 509 + { "condition", CONDITION }, // 510 + { "configuration", CONFIGURATION_SECT }, // 511 + { "contains", CONTAINS }, // 512 + { "content", CONTENT }, // 513 + { "control", CONTROL }, // 514 + { "controls", CONTROLS }, // 515 + { "convert", CONVERT }, // 516 + { "converting", CONVERTING }, // 517 + { "corresponding", CORRESPONDING }, // 518 + { "cos", COS }, // 519 + { "count", COUNT }, // 520 + { "currency", CURRENCY }, // 521 + { "current", CURRENT }, // 522 + { "current-date", CURRENT_DATE }, // 523 + { "data", DATA }, // 524 + { "date", DATE }, // 525 + { "date-compiled", DATE_COMPILED }, // 526 + { "date-of-integer", DATE_OF_INTEGER }, // 527 + { "date-to-yyyymmdd", DATE_TO_YYYYMMDD }, // 528 + { "date-written", DATE_WRITTEN }, // 529 + { "day", DAY }, // 530 + { "day-of-integer", DAY_OF_INTEGER }, // 531 + { "day-of-week", DAY_OF_WEEK }, // 532 + { "day-to-yyyyddd", DAY_TO_YYYYDDD }, // 533 + { "dbcs", DBCS }, // 534 + { "de", DE }, // 535 + { "debugging", DEBUGGING }, // 536 + { "decimal-point", DECIMAL_POINT }, // 537 + { "declaratives", DECLARATIVES }, // 538 + { "default", DEFAULT }, // 539 + { "delimited", DELIMITED }, // 540 + { "delimiter", DELIMITER }, // 541 + { "depending", DEPENDING }, // 542 + { "descending", DESCENDING }, // 543 + { "detail", DETAIL }, // 544 + { "direct", DIRECT }, // 545 + { "direct-access", DIRECT_ACCESS }, // 546 + { "down", DOWN }, // 547 + { "duplicates", DUPLICATES }, // 548 + { "dynamic", DYNAMIC }, // 549 + { "e", E }, // 550 + { "ebcdic", EBCDIC }, // 551 + { "ec", EC }, // 552 + { "egcs", EGCS }, // 553 + { "entry", ENTRY }, // 554 + { "environment", ENVIRONMENT }, // 555 + { "equal", EQUAL }, // 556 + { "every", EVERY }, // 557 + { "examine", EXAMINE }, // 558 + { "exhibit", EXHIBIT }, // 559 + { "exp", EXP }, // 560 + { "exp10", EXP10 }, // 561 + { "extend", EXTEND }, // 562 + { "external", EXTERNAL }, // 563 + { "exception-file", EXCEPTION_FILE }, // 564 + { "exception-file-n", EXCEPTION_FILE_N }, // 565 + { "exception-location", EXCEPTION_LOCATION }, // 566 + { "exception-location-n", EXCEPTION_LOCATION_N }, // 567 + { "exception-statement", EXCEPTION_STATEMENT }, // 568 + { "exception-status", EXCEPTION_STATUS }, // 569 + { "factorial", FACTORIAL }, // 570 + { "false", FALSE_kw }, // 571 + { "fd", FD }, // 572 + { "file-control", FILE_CONTROL }, // 573 + { "file", FILE_KW }, // 574 + { "file-limit", FILE_LIMIT }, // 575 + { "final", FINAL }, // 576 + { "finally", FINALLY }, // 577 + { "find-string", FIND_STRING }, // 578 + { "first", FIRST }, // 579 + { "fixed", FIXED }, // 580 + { "footing", FOOTING }, // 581 + { "for", FOR }, // 582 + { "formatted-current-date", FORMATTED_CURRENT_DATE }, // 583 + { "formatted-date", FORMATTED_DATE }, // 584 + { "formatted-datetime", FORMATTED_DATETIME }, // 585 + { "formatted-time", FORMATTED_TIME }, // 586 + { "form-overflow", FORM_OVERFLOW }, // 587 + { "free", FREE }, // 588 + { "fraction-part", FRACTION_PART }, // 589 + { "from", FROM }, // 590 + { "function", FUNCTION }, // 591 + { "generate", GENERATE }, // 592 + { "giving", GIVING }, // 593 + { "global", GLOBAL }, // 594 + { "go", GO }, // 595 + { "group", GROUP }, // 596 + { "heading", HEADING }, // 597 + { "hex", HEX }, // 598 + { "hex-of", HEX_OF }, // 599 + { "hex-to-char", HEX_TO_CHAR }, // 600 + { "high-values", HIGH_VALUES }, // 601 + { "highest-algebraic", HIGHEST_ALGEBRAIC }, // 602 + { "hold", HOLD }, // 603 + { "ibm-360", IBM_360 }, // 604 + { "in", IN }, // 605 + { "include", INCLUDE }, // 606 + { "index", INDEX }, // 607 + { "indexed", INDEXED }, // 608 + { "indicate", INDICATE }, // 609 + { "initial", INITIAL_kw }, // 610 + { "initiate", INITIATE }, // 611 + { "input", INPUT }, // 612 + { "installation", INSTALLATION }, // 613 + { "interface", INTERFACE }, // 614 + { "integer", INTEGER }, // 615 + { "integer-of-boolean", INTEGER_OF_BOOLEAN }, // 616 + { "integer-of-date", INTEGER_OF_DATE }, // 617 + { "integer-of-day", INTEGER_OF_DAY }, // 618 + { "integer-of-formatted-date", INTEGER_OF_FORMATTED_DATE }, // 619 + { "integer-part", INTEGER_PART }, // 620 + { "into", INTO }, // 621 + { "intrinsic", INTRINSIC }, // 622 + { "invoke", INVOKE }, // 623 + { "i-o", IO }, // 624 + { "i-o-control", IO_CONTROL }, // 625 + { "is", IS }, // 626 + { "isnt", ISNT }, // 627 + { "kanji", KANJI }, // 628 + { "key", KEY }, // 629 + { "label", LABEL }, // 630 + { "last", LAST }, // 631 + { "leading", LEADING }, // 632 + { "left", LEFT }, // 633 + { "length", LENGTH }, // 634 + { "length-of", LENGTH_OF }, // 635 + { "limit", LIMIT }, // 636 + { "limits", LIMITS }, // 637 + { "line", LINE }, // 638 + { "lines", LINES }, // 639 + { "line-counter", LINE_COUNTER }, // 640 + { "linage", LINAGE }, // 641 + { "linkage", LINKAGE }, // 642 + { "locale", LOCALE }, // 643 + { "locale-compare", LOCALE_COMPARE }, // 644 + { "locale-date", LOCALE_DATE }, // 645 + { "locale-time", LOCALE_TIME }, // 646 + { "locale-time-from-seconds", LOCALE_TIME_FROM_SECONDS }, // 647 + { "local-storage", LOCAL_STORAGE }, // 648 + { "location", LOCATION }, // 649 + { "lock", LOCK }, // 650 + { "lock-on", LOCK_ON }, // 651 + { "log", LOG }, // 652 + { "log10", LOG10 }, // 653 + { "lower-case", LOWER_CASE }, // 654 + { "low-values", LOW_VALUES }, // 655 + { "lowest-algebraic", LOWEST_ALGEBRAIC }, // 656 + { "lparen", LPAREN }, // 657 + { "manual", MANUAL }, // 658 + { "maxx", MAXX }, // 659 + { "mean", MEAN }, // 660 + { "median", MEDIAN }, // 661 + { "midrange", MIDRANGE }, // 662 + { "minn", MINN }, // 663 + { "multiple", MULTIPLE }, // 664 + { "mod", MOD }, // 665 + { "mode", MODE }, // 666 + { "module-name", MODULE_NAME }, // 667 + { "named", NAMED }, // 668 + { "nat", NAT }, // 669 + { "national", NATIONAL }, // 670 + { "national-edited", NATIONAL_EDITED }, // 671 + { "national-of", NATIONAL_OF }, // 672 + { "native", NATIVE }, // 673 + { "nested", NESTED }, // 674 + { "next", NEXT }, // 675 + { "no", NO }, // 676 + { "note", NOTE }, // 677 + { "nulls", NULLS }, // 678 + { "null", NULLS }, // 678 + { "nullptr", NULLPTR }, // 679 + { "numeric", NUMERIC }, // 680 + { "numeric-edited", NUMERIC_EDITED }, // 681 + { "numval", NUMVAL }, // 682 + { "numval-c", NUMVAL_C }, // 683 + { "numval-f", NUMVAL_F }, // 684 + { "occurs", OCCURS }, // 685 + { "of", OF }, // 686 + { "off", OFF }, // 687 + { "omitted", OMITTED }, // 688 + { "on", ON }, // 689 + { "only", ONLY }, // 690 + { "optional", OPTIONAL }, // 691 + { "options", OPTIONS }, // 692 + { "ord", ORD }, // 693 + { "order", ORDER }, // 694 + { "ord-max", ORD_MAX }, // 695 + { "ord-min", ORD_MIN }, // 696 + { "organization", ORGANIZATION }, // 697 + { "other", OTHER }, // 698 + { "otherwise", OTHERWISE }, // 699 + { "output", OUTPUT }, // 700 + { "packed-decimal", PACKED_DECIMAL }, // 701 + { "padding", PADDING }, // 702 + { "page", PAGE }, // 703 + { "page-counter", PAGE_COUNTER }, // 704 + { "pf", PF }, // 705 + { "ph", PH }, // 706 + { "pi", PI }, // 707 + { "pic", PIC }, // 708 + { "picture", PICTURE }, // 709 + { "plus", PLUS }, // 710 + { "present-value", PRESENT_VALUE }, // 711 + { "print-switch", PRINT_SWITCH }, // 712 + { "procedure", PROCEDURE }, // 713 + { "procedures", PROCEDURES }, // 714 + { "proceed", PROCEED }, // 715 + { "process", PROCESS }, // 716 + { "program-id", PROGRAM_ID }, // 717 + { "program", PROGRAM_kw }, // 718 + { "property", PROPERTY }, // 719 + { "prototype", PROTOTYPE }, // 720 + { "pseudotext", PSEUDOTEXT }, // 721 + { "quotes", QUOTES }, // 722 + { "quote", QUOTES }, // 722 + { "random", RANDOM }, // 723 + { "random-seed", RANDOM_SEED }, // 724 + { "range", RANGE }, // 725 + { "raise", RAISE }, // 726 + { "raising", RAISING }, // 727 + { "rd", RD }, // 728 + { "record", RECORD }, // 729 + { "recording", RECORDING }, // 730 + { "records", RECORDS }, // 731 + { "recursive", RECURSIVE }, // 732 + { "redefines", REDEFINES }, // 733 + { "reel", REEL }, // 734 + { "reference", REFERENCE }, // 735 + { "relative", RELATIVE }, // 736 + { "rem", REM }, // 737 + { "remainder", REMAINDER }, // 738 + { "remarks", REMARKS }, // 739 + { "removal", REMOVAL }, // 740 + { "renames", RENAMES }, // 741 + { "replace", REPLACE }, // 742 + { "replacing", REPLACING }, // 743 + { "report", REPORT }, // 744 + { "reporting", REPORTING }, // 745 + { "reports", REPORTS }, // 746 + { "repository", REPOSITORY }, // 747 + { "rerun", RERUN }, // 748 + { "reserve", RESERVE }, // 749 + { "restricted", RESTRICTED }, // 750 + { "resume", RESUME }, // 751 + { "reverse", REVERSE }, // 752 + { "reversed", REVERSED }, // 753 + { "rewind", REWIND }, // 754 + { "rf", RF }, // 755 + { "rh", RH }, // 756 + { "right", RIGHT }, // 757 + { "rounded", ROUNDED }, // 758 + { "run", RUN }, // 759 + { "same", SAME }, // 760 + { "screen", SCREEN }, // 761 + { "sd", SD }, // 762 + { "seconds-from-formatted-time", SECONDS_FROM_FORMATTED_TIME }, // 763 + { "seconds-past-midnight", SECONDS_PAST_MIDNIGHT }, // 764 + { "security", SECURITY }, // 765 + { "separate", SEPARATE }, // 766 + { "sequence", SEQUENCE }, // 767 + { "sequential", SEQUENTIAL }, // 768 + { "sharing", SHARING }, // 769 + { "simple-exit", SIMPLE_EXIT }, // 770 + { "sign", SIGN }, // 771 + { "sin", SIN }, // 772 + { "size", SIZE }, // 773 + { "smallest-algebraic", SMALLEST_ALGEBRAIC }, // 774 + { "source", SOURCE }, // 775 + { "source-computer", SOURCE_COMPUTER }, // 776 + { "special-names", SPECIAL_NAMES }, // 777 + { "sqrt", SQRT }, // 778 + { "stack", STACK }, // 779 + { "standard", STANDARD }, // 780 + { "standard-1", STANDARD_1 }, // 781 + { "standard-deviation", STANDARD_DEVIATION }, // 782 + { "standard-compare", STANDARD_COMPARE }, // 783 + { "status", STATUS }, // 784 + { "strong", STRONG }, // 785 + { "substitute", SUBSTITUTE }, // 786 + { "sum", SUM }, // 787 + { "symbol", SYMBOL }, // 788 + { "symbolic", SYMBOLIC }, // 789 + { "synchronized", SYNCHRONIZED }, // 790 + { "tally", TALLY }, // 791 + { "tallying", TALLYING }, // 792 + { "tan", TAN }, // 793 + { "terminate", TERMINATE }, // 794 + { "test", TEST }, // 795 + { "test-date-yyyymmdd", TEST_DATE_YYYYMMDD }, // 796 + { "test-day-yyyyddd", TEST_DAY_YYYYDDD }, // 797 + { "test-formatted-datetime", TEST_FORMATTED_DATETIME }, // 798 + { "test-numval", TEST_NUMVAL }, // 799 + { "test-numval-c", TEST_NUMVAL_C }, // 800 + { "test-numval-f", TEST_NUMVAL_F }, // 801 + { "than", THAN }, // 802 + { "time", TIME }, // 803 + { "times", TIMES }, // 804 + { "to", TO }, // 805 + { "top", TOP }, // 806 + { "top-level", TOP_LEVEL }, // 807 + { "tracks", TRACKS }, // 808 + { "track-area", TRACK_AREA }, // 809 + { "trailing", TRAILING }, // 810 + { "transform", TRANSFORM }, // 811 + { "trim", TRIM }, // 812 + { "true", TRUE_kw }, // 813 + { "try", TRY }, // 814 + { "turn", TURN }, // 815 + { "type", TYPE }, // 816 + { "typedef", TYPEDEF }, // 817 + { "ulength", ULENGTH }, // 818 + { "unbounded", UNBOUNDED }, // 819 + { "unit", UNIT }, // 820 + { "units", UNITS }, // 821 + { "unit-record", UNIT_RECORD }, // 822 + { "until", UNTIL }, // 823 + { "up", UP }, // 824 + { "upon", UPON }, // 825 + { "upos", UPOS }, // 826 + { "upper-case", UPPER_CASE }, // 827 + { "usage", USAGE }, // 828 + { "using", USING }, // 829 + { "usubstr", USUBSTR }, // 830 + { "usupplementary", USUPPLEMENTARY }, // 831 + { "utility", UTILITY }, // 832 + { "uuid4", UUID4 }, // 833 + { "uvalid", UVALID }, // 834 + { "uwidth", UWIDTH }, // 835 + { "value", VALUE }, // 836 + { "variance", VARIANCE }, // 837 + { "varying", VARYING }, // 838 + { "volatile", VOLATILE }, // 839 + { "when-compiled", WHEN_COMPILED }, // 840 + { "with", WITH }, // 841 + { "working-storage", WORKING_STORAGE }, // 842 + { "xml", XML }, // 843 + { "xmlgenerate", XMLGENERATE }, // 844 + { "xmlparse", XMLPARSE }, // 845 + { "year-to-yyyy", YEAR_TO_YYYY }, // 846 + { "yyyyddd", YYYYDDD }, // 847 + { "yyyymmdd", YYYYMMDD }, // 848 + { "arithmetic", ARITHMETIC }, // 849 + { "attribute", ATTRIBUTE }, // 850 + { "auto", AUTO }, // 851 + { "automatic", AUTOMATIC }, // 852 + { "away-from-zero", AWAY_FROM_ZERO }, // 853 + { "background-color", BACKGROUND_COLOR }, // 854 + { "bell", BELL }, // 855 + { "binary-encoding", BINARY_ENCODING }, // 856 + { "blink", BLINK }, // 857 + { "capacity", CAPACITY }, // 858 + { "center", CENTER }, // 859 + { "classification", CLASSIFICATION }, // 860 + { "cycle", CYCLE }, // 861 + { "decimal-encoding", DECIMAL_ENCODING }, // 862 + { "entry-convention", ENTRY_CONVENTION }, // 863 + { "eol", EOL }, // 864 + { "eos", EOS }, // 865 + { "erase", ERASE }, // 866 + { "expands", EXPANDS }, // 867 + { "float-binary", FLOAT_BINARY }, // 868 + { "float-decimal", FLOAT_DECIMAL }, // 869 + { "foreground-color", FOREGROUND_COLOR }, // 870 + { "forever", FOREVER }, // 871 + { "full", FULL }, // 872 + { "highlight", HIGHLIGHT }, // 873 + { "high-order-left", HIGH_ORDER_LEFT }, // 874 + { "high-order-right", HIGH_ORDER_RIGHT }, // 875 + { "ignoring", IGNORING }, // 876 + { "implements", IMPLEMENTS }, // 877 + { "initialized", INITIALIZED }, // 878 + { "intermediate", INTERMEDIATE }, // 879 + { "lc-all", LC_ALL_kw }, // 880 + { "lc-collate", LC_COLLATE_kw }, // 881 + { "lc-ctype", LC_CTYPE_kw }, // 882 + { "lc-messages", LC_MESSAGES_kw }, // 883 + { "lc-monetary", LC_MONETARY_kw }, // 884 + { "lc-numeric", LC_NUMERIC_kw }, // 885 + { "lc-time", LC_TIME_kw }, // 886 + { "lowlight", LOWLIGHT }, // 887 + { "nearest-away-from-zero", NEAREST_AWAY_FROM_ZERO }, // 888 + { "nearest-even", NEAREST_EVEN }, // 889 + { "nearest-toward-zero", NEAREST_TOWARD_ZERO }, // 890 + { "none", NONE }, // 891 + { "normal", NORMAL }, // 892 + { "numbers", NUMBERS }, // 893 + { "prefixed", PREFIXED }, // 894 + { "previous", PREVIOUS }, // 895 + { "prohibited", PROHIBITED }, // 896 + { "relation", RELATION }, // 897 + { "required", REQUIRED }, // 898 + { "reverse-video", REVERSE_VIDEO }, // 899 + { "rounding", ROUNDING }, // 900 + { "seconds", SECONDS }, // 901 + { "secure", SECURE }, // 902 + { "short", SHORT }, // 903 + { "signed", SIGNED_kw }, // 904 + { "standard-binary", STANDARD_BINARY }, // 905 + { "standard-decimal", STANDARD_DECIMAL }, // 906 + { "statement", STATEMENT }, // 907 + { "step", STEP }, // 908 + { "structure", STRUCTURE }, // 909 + { "toward-greater", TOWARD_GREATER }, // 910 + { "toward-lesser", TOWARD_LESSER }, // 911 + { "truncation", TRUNCATION }, // 912 + { "ucs-4", UCS_4 }, // 913 + { "underline", UNDERLINE }, // 914 + { "unsigned", UNSIGNED_kw }, // 915 + { "utf-16", UTF_16 }, // 916 + { "utf-8", UTF_8 }, // 917 + { "address", ADDRESS }, // 918 + { "end-accept", END_ACCEPT }, // 919 + { "end-add", END_ADD }, // 920 + { "end-call", END_CALL }, // 921 + { "end-compute", END_COMPUTE }, // 922 + { "end-delete", END_DELETE }, // 923 + { "end-display", END_DISPLAY }, // 924 + { "end-divide", END_DIVIDE }, // 925 + { "end-evaluate", END_EVALUATE }, // 926 + { "end-multiply", END_MULTIPLY }, // 927 + { "end-perform", END_PERFORM }, // 928 + { "end-read", END_READ }, // 929 + { "end-return", END_RETURN }, // 930 + { "end-rewrite", END_REWRITE }, // 931 + { "end-search", END_SEARCH }, // 932 + { "end-start", END_START }, // 933 + { "end-string", END_STRING }, // 934 + { "end-subtract", END_SUBTRACT }, // 935 + { "end-unstring", END_UNSTRING }, // 936 + { "end-write", END_WRITE }, // 937 + { "end-if", END_IF }, // 938 + { "thru", THRU }, // 939 + { "through", THRU }, // 939 + { "or", OR }, // 940 + { "and", AND }, // 941 + { "not", NOT }, // 942 + { "ne", NE }, // 943 + { "le", LE }, // 944 + { "ge", GE }, // 945 + { "pow", POW }, // 946 + { "neg", NEG }, // 947 }; // cppcheck-suppress useInitializationList @@ -830,557 +834,561 @@ token_names = { "CDF-EVALUATE", // 130 (388) "CDF-WHEN", // 131 (389) "CDF-END-EVALUATE", // 132 (390) - "CALL-COBOL", // 133 (391) - "CALL-VERBATIM", // 134 (392) - "IF", // 135 (393) - "THEN", // 136 (394) - "ELSE", // 137 (395) - "SENTENCE", // 138 (396) - "ACCEPT", // 139 (397) - "ADD", // 140 (398) - "ALTER", // 141 (399) - "CALL", // 142 (400) - "CANCEL", // 143 (401) - "CLOSE", // 144 (402) - "COMPUTE", // 145 (403) - "CONTINUE", // 146 (404) - "DELETE", // 147 (405) - "DISPLAY", // 148 (406) - "DIVIDE", // 149 (407) - "EVALUATE", // 150 (408) - "EXIT", // 151 (409) - "FILLER", // 152 (410) - "GOBACK", // 153 (411) - "GOTO", // 154 (412) - "INITIALIZE", // 155 (413) - "INSPECT", // 156 (414) - "MERGE", // 157 (415) - "MOVE", // 158 (416) - "MULTIPLY", // 159 (417) - "OPEN", // 160 (418) - "PARAGRAPH", // 161 (419) - "READ", // 162 (420) - "RELEASE", // 163 (421) - "RETURN", // 164 (422) - "REWRITE", // 165 (423) - "SEARCH", // 166 (424) - "SET", // 167 (425) - "SELECT", // 168 (426) - "SORT", // 169 (427) - "SORT-MERGE", // 170 (428) - "STRING", // 171 (429) - "STOP", // 172 (430) - "SUBTRACT", // 173 (431) - "START", // 174 (432) - "UNSTRING", // 175 (433) - "WRITE", // 176 (434) - "WHEN", // 177 (435) - "ARGUMENT-NUMBER", // 178 (436) - "ARGUMENT-VALUE", // 179 (437) - "ENVIRONMENT-NAME", // 180 (438) - "ENVIRONMENT-VALUE", // 181 (439) - "ABS", // 182 (440) - "ACCESS", // 183 (441) - "ACOS", // 184 (442) - "ACTUAL", // 185 (443) - "ADVANCING", // 186 (444) - "AFTER", // 187 (445) - "ALL", // 188 (446) - "ALLOCATE", // 189 (447) - "ALPHABET", // 190 (448) - "ALPHABETIC", // 191 (449) - "ALPHABETIC-LOWER", // 192 (450) - "ALPHABETIC-UPPER", // 193 (451) - "ALPHANUMERIC", // 194 (452) - "ALPHANUMERIC-EDITED", // 195 (453) - "ALSO", // 196 (454) - "ALTERNATE", // 197 (455) - "ANNUITY", // 198 (456) - "ANUM", // 199 (457) - "ANY", // 200 (458) - "ANYCASE", // 201 (459) - "APPLY", // 202 (460) - "ARE", // 203 (461) - "AREA", // 204 (462) - "AREAS", // 205 (463) - "AS", // 206 (464) - "ASCENDING", // 207 (465) - "ACTIVATING", // 208 (466) - "ASIN", // 209 (467) - "ASSIGN", // 210 (468) - "AT", // 211 (469) - "ATAN", // 212 (470) - "BASED", // 213 (471) - "BASECONVERT", // 214 (472) - "BEFORE", // 215 (473) - "BINARY", // 216 (474) - "BIT", // 217 (475) - "BIT-OF", // 218 (476) - "BIT-TO-CHAR", // 219 (477) - "BLANK", // 220 (478) - "BLOCK", // 221 (479) - "BOOLEAN-OF-INTEGER", // 222 (480) - "BOTTOM", // 223 (481) - "BY", // 224 (482) - "BYTE", // 225 (483) - "BYTE-LENGTH", // 226 (484) - "CF", // 227 (485) - "CH", // 228 (486) - "CHANGED", // 229 (487) - "CHAR", // 230 (488) - "CHAR-NATIONAL", // 231 (489) - "CHARACTER", // 232 (490) - "CHARACTERS", // 233 (491) - "CHECKING", // 234 (492) - "CLASS", // 235 (493) - "COBOL", // 236 (494) - "CODE", // 237 (495) - "CODE-SET", // 238 (496) - "COLLATING", // 239 (497) - "COLUMN", // 240 (498) - "COMBINED-DATETIME", // 241 (499) - "COMMA", // 242 (500) - "COMMAND-LINE", // 243 (501) - "COMMAND-LINE-COUNT", // 244 (502) - "COMMIT", // 245 (503) - "COMMON", // 246 (504) - "CONCAT", // 247 (505) - "CONDITION", // 248 (506) - "CONFIGURATION", // 249 (507) - "CONTAINS", // 250 (508) - "CONTENT", // 251 (509) - "CONTROL", // 252 (510) - "CONTROLS", // 253 (511) - "CONVERT", // 254 (512) - "CONVERTING", // 255 (513) - "CORRESPONDING", // 256 (514) - "COS", // 257 (515) - "COUNT", // 258 (516) - "CURRENCY", // 259 (517) - "CURRENT", // 260 (518) - "CURRENT-DATE", // 261 (519) - "DATA", // 262 (520) - "DATE", // 263 (521) - "DATE-COMPILED", // 264 (522) - "DATE-OF-INTEGER", // 265 (523) - "DATE-TO-YYYYMMDD", // 266 (524) - "DATE-WRITTEN", // 267 (525) - "DAY", // 268 (526) - "DAY-OF-INTEGER", // 269 (527) - "DAY-OF-WEEK", // 270 (528) - "DAY-TO-YYYYDDD", // 271 (529) - "DBCS", // 272 (530) - "DE", // 273 (531) - "DEBUGGING", // 274 (532) - "DECIMAL-POINT", // 275 (533) - "DECLARATIVES", // 276 (534) - "DEFAULT", // 277 (535) - "DELIMITED", // 278 (536) - "DELIMITER", // 279 (537) - "DEPENDING", // 280 (538) - "DESCENDING", // 281 (539) - "DETAIL", // 282 (540) - "DIRECT", // 283 (541) - "DIRECT-ACCESS", // 284 (542) - "DOWN", // 285 (543) - "DUPLICATES", // 286 (544) - "DYNAMIC", // 287 (545) - "E", // 288 (546) - "EBCDIC", // 289 (547) - "EC", // 290 (548) - "EGCS", // 291 (549) - "ENTRY", // 292 (550) - "ENVIRONMENT", // 293 (551) - "EQUAL", // 294 (552) - "EVERY", // 295 (553) - "EXAMINE", // 296 (554) - "EXHIBIT", // 297 (555) - "EXP", // 298 (556) - "EXP10", // 299 (557) - "EXTEND", // 300 (558) - "EXTERNAL", // 301 (559) - "EXCEPTION-FILE", // 302 (560) - "EXCEPTION-FILE-N", // 303 (561) - "EXCEPTION-LOCATION", // 304 (562) - "EXCEPTION-LOCATION-N", // 305 (563) - "EXCEPTION-STATEMENT", // 306 (564) - "EXCEPTION-STATUS", // 307 (565) - "FACTORIAL", // 308 (566) - "FALSE", // 309 (567) - "FD", // 310 (568) - "FILE-CONTROL", // 311 (569) - "FILE", // 312 (570) - "FILE-LIMIT", // 313 (571) - "FINAL", // 314 (572) - "FINALLY", // 315 (573) - "FIND-STRING", // 316 (574) - "FIRST", // 317 (575) - "FIXED", // 318 (576) - "FOOTING", // 319 (577) - "FOR", // 320 (578) - "FORMATTED-CURRENT-DATE", // 321 (579) - "FORMATTED-DATE", // 322 (580) - "FORMATTED-DATETIME", // 323 (581) - "FORMATTED-TIME", // 324 (582) - "FORM-OVERFLOW", // 325 (583) - "FREE", // 326 (584) - "FRACTION-PART", // 327 (585) - "FROM", // 328 (586) - "FUNCTION", // 329 (587) - "GENERATE", // 330 (588) - "GIVING", // 331 (589) - "GLOBAL", // 332 (590) - "GO", // 333 (591) - "GROUP", // 334 (592) - "HEADING", // 335 (593) - "HEX", // 336 (594) - "HEX-OF", // 337 (595) - "HEX-TO-CHAR", // 338 (596) - "HIGH-VALUES", // 339 (597) - "HIGHEST-ALGEBRAIC", // 340 (598) - "HOLD", // 341 (599) - "IBM-360", // 342 (600) - "IN", // 343 (601) - "INCLUDE", // 344 (602) - "INDEX", // 345 (603) - "INDEXED", // 346 (604) - "INDICATE", // 347 (605) - "INITIAL", // 348 (606) - "INITIATE", // 349 (607) - "INPUT", // 350 (608) - "INSTALLATION", // 351 (609) - "INTERFACE", // 352 (610) - "INTEGER", // 353 (611) - "INTEGER-OF-BOOLEAN", // 354 (612) - "INTEGER-OF-DATE", // 355 (613) - "INTEGER-OF-DAY", // 356 (614) - "INTEGER-OF-FORMATTED-DATE", // 357 (615) - "INTEGER-PART", // 358 (616) - "INTO", // 359 (617) - "INTRINSIC", // 360 (618) - "INVOKE", // 361 (619) - "I-O", // 362 (620) - "I-O-CONTROL", // 363 (621) - "IS", // 364 (622) - "ISNT", // 365 (623) - "KANJI", // 366 (624) - "KEY", // 367 (625) - "LABEL", // 368 (626) - "LAST", // 369 (627) - "LEADING", // 370 (628) - "LEFT", // 371 (629) - "LENGTH", // 372 (630) - "LENGTH-OF", // 373 (631) - "LIMIT", // 374 (632) - "LIMITS", // 375 (633) - "LINE", // 376 (634) - "LINES", // 377 (635) - "LINE-COUNTER", // 378 (636) - "LINAGE", // 379 (637) - "LINKAGE", // 380 (638) - "LOCALE", // 381 (639) - "LOCALE-COMPARE", // 382 (640) - "LOCALE-DATE", // 383 (641) - "LOCALE-TIME", // 384 (642) - "LOCALE-TIME-FROM-SECONDS", // 385 (643) - "LOCAL-STORAGE", // 386 (644) - "LOCATION", // 387 (645) - "LOCK", // 388 (646) - "LOCK-ON", // 389 (647) - "LOG", // 390 (648) - "LOG10", // 391 (649) - "LOWER-CASE", // 392 (650) - "LOW-VALUES", // 393 (651) - "LOWEST-ALGEBRAIC", // 394 (652) - "LPAREN", // 395 (653) - "MANUAL", // 396 (654) - "MAXX", // 397 (655) - "MEAN", // 398 (656) - "MEDIAN", // 399 (657) - "MIDRANGE", // 400 (658) - "MINN", // 401 (659) - "MULTIPLE", // 402 (660) - "MOD", // 403 (661) - "MODE", // 404 (662) - "MODULE-NAME", // 405 (663) - "NAMED", // 406 (664) - "NAT", // 407 (665) - "NATIONAL", // 408 (666) - "NATIONAL-EDITED", // 409 (667) - "NATIONAL-OF", // 410 (668) - "NATIVE", // 411 (669) - "NESTED", // 412 (670) - "NEXT", // 413 (671) - "NO", // 414 (672) - "NOTE", // 415 (673) - "NULLS", // 416 (674) - "NULLPTR", // 417 (675) - "NUMERIC", // 418 (676) - "NUMERIC-EDITED", // 419 (677) - "NUMVAL", // 420 (678) - "NUMVAL-C", // 421 (679) - "NUMVAL-F", // 422 (680) - "OCCURS", // 423 (681) - "OF", // 424 (682) - "OFF", // 425 (683) - "OMITTED", // 426 (684) - "ON", // 427 (685) - "ONLY", // 428 (686) - "OPTIONAL", // 429 (687) - "OPTIONS", // 430 (688) - "ORD", // 431 (689) - "ORDER", // 432 (690) - "ORD-MAX", // 433 (691) - "ORD-MIN", // 434 (692) - "ORGANIZATION", // 435 (693) - "OTHER", // 436 (694) - "OTHERWISE", // 437 (695) - "OUTPUT", // 438 (696) - "PACKED-DECIMAL", // 439 (697) - "PADDING", // 440 (698) - "PAGE", // 441 (699) - "PAGE-COUNTER", // 442 (700) - "PF", // 443 (701) - "PH", // 444 (702) - "PI", // 445 (703) - "PIC", // 446 (704) - "PICTURE", // 447 (705) - "PLUS", // 448 (706) - "PRESENT-VALUE", // 449 (707) - "PRINT-SWITCH", // 450 (708) - "PROCEDURE", // 451 (709) - "PROCEDURES", // 452 (710) - "PROCEED", // 453 (711) - "PROCESS", // 454 (712) - "PROGRAM-ID", // 455 (713) - "PROGRAM", // 456 (714) - "PROPERTY", // 457 (715) - "PROTOTYPE", // 458 (716) - "PSEUDOTEXT", // 459 (717) - "QUOTES", // 460 (718) - "RANDOM", // 461 (719) - "RANDOM-SEED", // 462 (720) - "RANGE", // 463 (721) - "RAISE", // 464 (722) - "RAISING", // 465 (723) - "RD", // 466 (724) - "RECORD", // 467 (725) - "RECORDING", // 468 (726) - "RECORDS", // 469 (727) - "RECURSIVE", // 470 (728) - "REDEFINES", // 471 (729) - "REEL", // 472 (730) - "REFERENCE", // 473 (731) - "RELATIVE", // 474 (732) - "REM", // 475 (733) - "REMAINDER", // 476 (734) - "REMARKS", // 477 (735) - "REMOVAL", // 478 (736) - "RENAMES", // 479 (737) - "REPLACE", // 480 (738) - "REPLACING", // 481 (739) - "REPORT", // 482 (740) - "REPORTING", // 483 (741) - "REPORTS", // 484 (742) - "REPOSITORY", // 485 (743) - "RERUN", // 486 (744) - "RESERVE", // 487 (745) - "RESTRICTED", // 488 (746) - "RESUME", // 489 (747) - "REVERSE", // 490 (748) - "REVERSED", // 491 (749) - "REWIND", // 492 (750) - "RF", // 493 (751) - "RH", // 494 (752) - "RIGHT", // 495 (753) - "ROUNDED", // 496 (754) - "RUN", // 497 (755) - "SAME", // 498 (756) - "SCREEN", // 499 (757) - "SD", // 500 (758) - "SECONDS-FROM-FORMATTED-TIME", // 501 (759) - "SECONDS-PAST-MIDNIGHT", // 502 (760) - "SECURITY", // 503 (761) - "SEPARATE", // 504 (762) - "SEQUENCE", // 505 (763) - "SEQUENTIAL", // 506 (764) - "SHARING", // 507 (765) - "SIMPLE-EXIT", // 508 (766) - "SIGN", // 509 (767) - "SIN", // 510 (768) - "SIZE", // 511 (769) - "SMALLEST-ALGEBRAIC", // 512 (770) - "SOURCE", // 513 (771) - "SOURCE-COMPUTER", // 514 (772) - "SPECIAL-NAMES", // 515 (773) - "SQRT", // 516 (774) - "STACK", // 517 (775) - "STANDARD", // 518 (776) - "STANDARD-1", // 519 (777) - "STANDARD-DEVIATION", // 520 (778) - "STANDARD-COMPARE", // 521 (779) - "STATUS", // 522 (780) - "STRONG", // 523 (781) - "SUBSTITUTE", // 524 (782) - "SUM", // 525 (783) - "SYMBOL", // 526 (784) - "SYMBOLIC", // 527 (785) - "SYNCHRONIZED", // 528 (786) - "TALLY", // 529 (787) - "TALLYING", // 530 (788) - "TAN", // 531 (789) - "TERMINATE", // 532 (790) - "TEST", // 533 (791) - "TEST-DATE-YYYYMMDD", // 534 (792) - "TEST-DAY-YYYYDDD", // 535 (793) - "TEST-FORMATTED-DATETIME", // 536 (794) - "TEST-NUMVAL", // 537 (795) - "TEST-NUMVAL-C", // 538 (796) - "TEST-NUMVAL-F", // 539 (797) - "THAN", // 540 (798) - "TIME", // 541 (799) - "TIMES", // 542 (800) - "TO", // 543 (801) - "TOP", // 544 (802) - "TOP-LEVEL", // 545 (803) - "TRACKS", // 546 (804) - "TRACK-AREA", // 547 (805) - "TRAILING", // 548 (806) - "TRANSFORM", // 549 (807) - "TRIM", // 550 (808) - "TRUE", // 551 (809) - "TRY", // 552 (810) - "TURN", // 553 (811) - "TYPE", // 554 (812) - "TYPEDEF", // 555 (813) - "ULENGTH", // 556 (814) - "UNBOUNDED", // 557 (815) - "UNIT", // 558 (816) - "UNITS", // 559 (817) - "UNIT-RECORD", // 560 (818) - "UNTIL", // 561 (819) - "UP", // 562 (820) - "UPON", // 563 (821) - "UPOS", // 564 (822) - "UPPER-CASE", // 565 (823) - "USAGE", // 566 (824) - "USING", // 567 (825) - "USUBSTR", // 568 (826) - "USUPPLEMENTARY", // 569 (827) - "UTILITY", // 570 (828) - "UUID4", // 571 (829) - "UVALID", // 572 (830) - "UWIDTH", // 573 (831) - "VALUE", // 574 (832) - "VARIANCE", // 575 (833) - "VARYING", // 576 (834) - "VOLATILE", // 577 (835) - "WHEN-COMPILED", // 578 (836) - "WITH", // 579 (837) - "WORKING-STORAGE", // 580 (838) - "XML", // 581 (839) - "XMLGENERATE", // 582 (840) - "XMLPARSE", // 583 (841) - "YEAR-TO-YYYY", // 584 (842) - "YYYYDDD", // 585 (843) - "YYYYMMDD", // 586 (844) - "ARITHMETIC", // 587 (845) - "ATTRIBUTE", // 588 (846) - "AUTO", // 589 (847) - "AUTOMATIC", // 590 (848) - "AWAY-FROM-ZERO", // 591 (849) - "BACKGROUND-COLOR", // 592 (850) - "BELL", // 593 (851) - "BINARY-ENCODING", // 594 (852) - "BLINK", // 595 (853) - "CAPACITY", // 596 (854) - "CENTER", // 597 (855) - "CLASSIFICATION", // 598 (856) - "CYCLE", // 599 (857) - "DECIMAL-ENCODING", // 600 (858) - "ENTRY-CONVENTION", // 601 (859) - "EOL", // 602 (860) - "EOS", // 603 (861) - "ERASE", // 604 (862) - "EXPANDS", // 605 (863) - "FLOAT-BINARY", // 606 (864) - "FLOAT-DECIMAL", // 607 (865) - "FOREGROUND-COLOR", // 608 (866) - "FOREVER", // 609 (867) - "FULL", // 610 (868) - "HIGHLIGHT", // 611 (869) - "HIGH-ORDER-LEFT", // 612 (870) - "HIGH-ORDER-RIGHT", // 613 (871) - "IGNORING", // 614 (872) - "IMPLEMENTS", // 615 (873) - "INITIALIZED", // 616 (874) - "INTERMEDIATE", // 617 (875) - "LC-ALL", // 618 (876) - "LC-COLLATE", // 619 (877) - "LC-CTYPE", // 620 (878) - "LC-MESSAGES", // 621 (879) - "LC-MONETARY", // 622 (880) - "LC-NUMERIC", // 623 (881) - "LC-TIME", // 624 (882) - "LOWLIGHT", // 625 (883) - "NEAREST-AWAY-FROM-ZERO", // 626 (884) - "NEAREST-EVEN", // 627 (885) - "NEAREST-TOWARD-ZERO", // 628 (886) - "NONE", // 629 (887) - "NORMAL", // 630 (888) - "NUMBERS", // 631 (889) - "PREFIXED", // 632 (890) - "PREVIOUS", // 633 (891) - "PROHIBITED", // 634 (892) - "RELATION", // 635 (893) - "REQUIRED", // 636 (894) - "REVERSE-VIDEO", // 637 (895) - "ROUNDING", // 638 (896) - "SECONDS", // 639 (897) - "SECURE", // 640 (898) - "SHORT", // 641 (899) - "SIGNED", // 642 (900) - "STANDARD-BINARY", // 643 (901) - "STANDARD-DECIMAL", // 644 (902) - "STATEMENT", // 645 (903) - "STEP", // 646 (904) - "STRUCTURE", // 647 (905) - "TOWARD-GREATER", // 648 (906) - "TOWARD-LESSER", // 649 (907) - "TRUNCATION", // 650 (908) - "UCS-4", // 651 (909) - "UNDERLINE", // 652 (910) - "UNSIGNED", // 653 (911) - "UTF-16", // 654 (912) - "UTF-8", // 655 (913) - "ADDRESS", // 656 (914) - "END-ACCEPT", // 657 (915) - "END-ADD", // 658 (916) - "END-CALL", // 659 (917) - "END-COMPUTE", // 660 (918) - "END-DELETE", // 661 (919) - "END-DISPLAY", // 662 (920) - "END-DIVIDE", // 663 (921) - "END-EVALUATE", // 664 (922) - "END-MULTIPLY", // 665 (923) - "END-PERFORM", // 666 (924) - "END-READ", // 667 (925) - "END-RETURN", // 668 (926) - "END-REWRITE", // 669 (927) - "END-SEARCH", // 670 (928) - "END-START", // 671 (929) - "END-STRING", // 672 (930) - "END-SUBTRACT", // 673 (931) - "END-UNSTRING", // 674 (932) - "END-WRITE", // 675 (933) - "END-IF", // 676 (934) - "THRU", // 677 (935) - "OR", // 678 (936) - "AND", // 679 (937) - "NOT", // 680 (938) - "NE", // 681 (939) - "LE", // 682 (940) - "GE", // 683 (941) - "POW", // 684 (942) - "NEG", // 685 (943) + "CALL-CONVENTION", // 133 (391) + "CALL-COBOL", // 134 (392) + "CALL-VERBATIM", // 135 (393) + "CDF-PUSH", // 136 (394) + "CDF-POP", // 137 (395) + "SOURCE-FORMAT", // 138 (396) + "IF", // 139 (397) + "THEN", // 140 (398) + "ELSE", // 141 (399) + "SENTENCE", // 142 (400) + "ACCEPT", // 143 (401) + "ADD", // 144 (402) + "ALTER", // 145 (403) + "CALL", // 146 (404) + "CANCEL", // 147 (405) + "CLOSE", // 148 (406) + "COMPUTE", // 149 (407) + "CONTINUE", // 150 (408) + "DELETE", // 151 (409) + "DISPLAY", // 152 (410) + "DIVIDE", // 153 (411) + "EVALUATE", // 154 (412) + "EXIT", // 155 (413) + "FILLER", // 156 (414) + "GOBACK", // 157 (415) + "GOTO", // 158 (416) + "INITIALIZE", // 159 (417) + "INSPECT", // 160 (418) + "MERGE", // 161 (419) + "MOVE", // 162 (420) + "MULTIPLY", // 163 (421) + "OPEN", // 164 (422) + "PARAGRAPH", // 165 (423) + "READ", // 166 (424) + "RELEASE", // 167 (425) + "RETURN", // 168 (426) + "REWRITE", // 169 (427) + "SEARCH", // 170 (428) + "SET", // 171 (429) + "SELECT", // 172 (430) + "SORT", // 173 (431) + "SORT-MERGE", // 174 (432) + "STRING", // 175 (433) + "STOP", // 176 (434) + "SUBTRACT", // 177 (435) + "START", // 178 (436) + "UNSTRING", // 179 (437) + "WRITE", // 180 (438) + "WHEN", // 181 (439) + "ARGUMENT-NUMBER", // 182 (440) + "ARGUMENT-VALUE", // 183 (441) + "ENVIRONMENT-NAME", // 184 (442) + "ENVIRONMENT-VALUE", // 185 (443) + "ABS", // 186 (444) + "ACCESS", // 187 (445) + "ACOS", // 188 (446) + "ACTUAL", // 189 (447) + "ADVANCING", // 190 (448) + "AFTER", // 191 (449) + "ALL", // 192 (450) + "ALLOCATE", // 193 (451) + "ALPHABET", // 194 (452) + "ALPHABETIC", // 195 (453) + "ALPHABETIC-LOWER", // 196 (454) + "ALPHABETIC-UPPER", // 197 (455) + "ALPHANUMERIC", // 198 (456) + "ALPHANUMERIC-EDITED", // 199 (457) + "ALSO", // 200 (458) + "ALTERNATE", // 201 (459) + "ANNUITY", // 202 (460) + "ANUM", // 203 (461) + "ANY", // 204 (462) + "ANYCASE", // 205 (463) + "APPLY", // 206 (464) + "ARE", // 207 (465) + "AREA", // 208 (466) + "AREAS", // 209 (467) + "AS", // 210 (468) + "ASCENDING", // 211 (469) + "ACTIVATING", // 212 (470) + "ASIN", // 213 (471) + "ASSIGN", // 214 (472) + "AT", // 215 (473) + "ATAN", // 216 (474) + "BASED", // 217 (475) + "BASECONVERT", // 218 (476) + "BEFORE", // 219 (477) + "BINARY", // 220 (478) + "BIT", // 221 (479) + "BIT-OF", // 222 (480) + "BIT-TO-CHAR", // 223 (481) + "BLANK", // 224 (482) + "BLOCK", // 225 (483) + "BOOLEAN-OF-INTEGER", // 226 (484) + "BOTTOM", // 227 (485) + "BY", // 228 (486) + "BYTE", // 229 (487) + "BYTE-LENGTH", // 230 (488) + "CF", // 231 (489) + "CH", // 232 (490) + "CHANGED", // 233 (491) + "CHAR", // 234 (492) + "CHAR-NATIONAL", // 235 (493) + "CHARACTER", // 236 (494) + "CHARACTERS", // 237 (495) + "CHECKING", // 238 (496) + "CLASS", // 239 (497) + "COBOL", // 240 (498) + "CODE", // 241 (499) + "CODE-SET", // 242 (500) + "COLLATING", // 243 (501) + "COLUMN", // 244 (502) + "COMBINED-DATETIME", // 245 (503) + "COMMA", // 246 (504) + "COMMAND-LINE", // 247 (505) + "COMMAND-LINE-COUNT", // 248 (506) + "COMMIT", // 249 (507) + "COMMON", // 250 (508) + "CONCAT", // 251 (509) + "CONDITION", // 252 (510) + "CONFIGURATION", // 253 (511) + "CONTAINS", // 254 (512) + "CONTENT", // 255 (513) + "CONTROL", // 256 (514) + "CONTROLS", // 257 (515) + "CONVERT", // 258 (516) + "CONVERTING", // 259 (517) + "CORRESPONDING", // 260 (518) + "COS", // 261 (519) + "COUNT", // 262 (520) + "CURRENCY", // 263 (521) + "CURRENT", // 264 (522) + "CURRENT-DATE", // 265 (523) + "DATA", // 266 (524) + "DATE", // 267 (525) + "DATE-COMPILED", // 268 (526) + "DATE-OF-INTEGER", // 269 (527) + "DATE-TO-YYYYMMDD", // 270 (528) + "DATE-WRITTEN", // 271 (529) + "DAY", // 272 (530) + "DAY-OF-INTEGER", // 273 (531) + "DAY-OF-WEEK", // 274 (532) + "DAY-TO-YYYYDDD", // 275 (533) + "DBCS", // 276 (534) + "DE", // 277 (535) + "DEBUGGING", // 278 (536) + "DECIMAL-POINT", // 279 (537) + "DECLARATIVES", // 280 (538) + "DEFAULT", // 281 (539) + "DELIMITED", // 282 (540) + "DELIMITER", // 283 (541) + "DEPENDING", // 284 (542) + "DESCENDING", // 285 (543) + "DETAIL", // 286 (544) + "DIRECT", // 287 (545) + "DIRECT-ACCESS", // 288 (546) + "DOWN", // 289 (547) + "DUPLICATES", // 290 (548) + "DYNAMIC", // 291 (549) + "E", // 292 (550) + "EBCDIC", // 293 (551) + "EC", // 294 (552) + "EGCS", // 295 (553) + "ENTRY", // 296 (554) + "ENVIRONMENT", // 297 (555) + "EQUAL", // 298 (556) + "EVERY", // 299 (557) + "EXAMINE", // 300 (558) + "EXHIBIT", // 301 (559) + "EXP", // 302 (560) + "EXP10", // 303 (561) + "EXTEND", // 304 (562) + "EXTERNAL", // 305 (563) + "EXCEPTION-FILE", // 306 (564) + "EXCEPTION-FILE-N", // 307 (565) + "EXCEPTION-LOCATION", // 308 (566) + "EXCEPTION-LOCATION-N", // 309 (567) + "EXCEPTION-STATEMENT", // 310 (568) + "EXCEPTION-STATUS", // 311 (569) + "FACTORIAL", // 312 (570) + "FALSE", // 313 (571) + "FD", // 314 (572) + "FILE-CONTROL", // 315 (573) + "FILE", // 316 (574) + "FILE-LIMIT", // 317 (575) + "FINAL", // 318 (576) + "FINALLY", // 319 (577) + "FIND-STRING", // 320 (578) + "FIRST", // 321 (579) + "FIXED", // 322 (580) + "FOOTING", // 323 (581) + "FOR", // 324 (582) + "FORMATTED-CURRENT-DATE", // 325 (583) + "FORMATTED-DATE", // 326 (584) + "FORMATTED-DATETIME", // 327 (585) + "FORMATTED-TIME", // 328 (586) + "FORM-OVERFLOW", // 329 (587) + "FREE", // 330 (588) + "FRACTION-PART", // 331 (589) + "FROM", // 332 (590) + "FUNCTION", // 333 (591) + "GENERATE", // 334 (592) + "GIVING", // 335 (593) + "GLOBAL", // 336 (594) + "GO", // 337 (595) + "GROUP", // 338 (596) + "HEADING", // 339 (597) + "HEX", // 340 (598) + "HEX-OF", // 341 (599) + "HEX-TO-CHAR", // 342 (600) + "HIGH-VALUES", // 343 (601) + "HIGHEST-ALGEBRAIC", // 344 (602) + "HOLD", // 345 (603) + "IBM-360", // 346 (604) + "IN", // 347 (605) + "INCLUDE", // 348 (606) + "INDEX", // 349 (607) + "INDEXED", // 350 (608) + "INDICATE", // 351 (609) + "INITIAL", // 352 (610) + "INITIATE", // 353 (611) + "INPUT", // 354 (612) + "INSTALLATION", // 355 (613) + "INTERFACE", // 356 (614) + "INTEGER", // 357 (615) + "INTEGER-OF-BOOLEAN", // 358 (616) + "INTEGER-OF-DATE", // 359 (617) + "INTEGER-OF-DAY", // 360 (618) + "INTEGER-OF-FORMATTED-DATE", // 361 (619) + "INTEGER-PART", // 362 (620) + "INTO", // 363 (621) + "INTRINSIC", // 364 (622) + "INVOKE", // 365 (623) + "I-O", // 366 (624) + "I-O-CONTROL", // 367 (625) + "IS", // 368 (626) + "ISNT", // 369 (627) + "KANJI", // 370 (628) + "KEY", // 371 (629) + "LABEL", // 372 (630) + "LAST", // 373 (631) + "LEADING", // 374 (632) + "LEFT", // 375 (633) + "LENGTH", // 376 (634) + "LENGTH-OF", // 377 (635) + "LIMIT", // 378 (636) + "LIMITS", // 379 (637) + "LINE", // 380 (638) + "LINES", // 381 (639) + "LINE-COUNTER", // 382 (640) + "LINAGE", // 383 (641) + "LINKAGE", // 384 (642) + "LOCALE", // 385 (643) + "LOCALE-COMPARE", // 386 (644) + "LOCALE-DATE", // 387 (645) + "LOCALE-TIME", // 388 (646) + "LOCALE-TIME-FROM-SECONDS", // 389 (647) + "LOCAL-STORAGE", // 390 (648) + "LOCATION", // 391 (649) + "LOCK", // 392 (650) + "LOCK-ON", // 393 (651) + "LOG", // 394 (652) + "LOG10", // 395 (653) + "LOWER-CASE", // 396 (654) + "LOW-VALUES", // 397 (655) + "LOWEST-ALGEBRAIC", // 398 (656) + "LPAREN", // 399 (657) + "MANUAL", // 400 (658) + "MAXX", // 401 (659) + "MEAN", // 402 (660) + "MEDIAN", // 403 (661) + "MIDRANGE", // 404 (662) + "MINN", // 405 (663) + "MULTIPLE", // 406 (664) + "MOD", // 407 (665) + "MODE", // 408 (666) + "MODULE-NAME", // 409 (667) + "NAMED", // 410 (668) + "NAT", // 411 (669) + "NATIONAL", // 412 (670) + "NATIONAL-EDITED", // 413 (671) + "NATIONAL-OF", // 414 (672) + "NATIVE", // 415 (673) + "NESTED", // 416 (674) + "NEXT", // 417 (675) + "NO", // 418 (676) + "NOTE", // 419 (677) + "NULLS", // 420 (678) + "NULLPTR", // 421 (679) + "NUMERIC", // 422 (680) + "NUMERIC-EDITED", // 423 (681) + "NUMVAL", // 424 (682) + "NUMVAL-C", // 425 (683) + "NUMVAL-F", // 426 (684) + "OCCURS", // 427 (685) + "OF", // 428 (686) + "OFF", // 429 (687) + "OMITTED", // 430 (688) + "ON", // 431 (689) + "ONLY", // 432 (690) + "OPTIONAL", // 433 (691) + "OPTIONS", // 434 (692) + "ORD", // 435 (693) + "ORDER", // 436 (694) + "ORD-MAX", // 437 (695) + "ORD-MIN", // 438 (696) + "ORGANIZATION", // 439 (697) + "OTHER", // 440 (698) + "OTHERWISE", // 441 (699) + "OUTPUT", // 442 (700) + "PACKED-DECIMAL", // 443 (701) + "PADDING", // 444 (702) + "PAGE", // 445 (703) + "PAGE-COUNTER", // 446 (704) + "PF", // 447 (705) + "PH", // 448 (706) + "PI", // 449 (707) + "PIC", // 450 (708) + "PICTURE", // 451 (709) + "PLUS", // 452 (710) + "PRESENT-VALUE", // 453 (711) + "PRINT-SWITCH", // 454 (712) + "PROCEDURE", // 455 (713) + "PROCEDURES", // 456 (714) + "PROCEED", // 457 (715) + "PROCESS", // 458 (716) + "PROGRAM-ID", // 459 (717) + "PROGRAM", // 460 (718) + "PROPERTY", // 461 (719) + "PROTOTYPE", // 462 (720) + "PSEUDOTEXT", // 463 (721) + "QUOTES", // 464 (722) + "RANDOM", // 465 (723) + "RANDOM-SEED", // 466 (724) + "RANGE", // 467 (725) + "RAISE", // 468 (726) + "RAISING", // 469 (727) + "RD", // 470 (728) + "RECORD", // 471 (729) + "RECORDING", // 472 (730) + "RECORDS", // 473 (731) + "RECURSIVE", // 474 (732) + "REDEFINES", // 475 (733) + "REEL", // 476 (734) + "REFERENCE", // 477 (735) + "RELATIVE", // 478 (736) + "REM", // 479 (737) + "REMAINDER", // 480 (738) + "REMARKS", // 481 (739) + "REMOVAL", // 482 (740) + "RENAMES", // 483 (741) + "REPLACE", // 484 (742) + "REPLACING", // 485 (743) + "REPORT", // 486 (744) + "REPORTING", // 487 (745) + "REPORTS", // 488 (746) + "REPOSITORY", // 489 (747) + "RERUN", // 490 (748) + "RESERVE", // 491 (749) + "RESTRICTED", // 492 (750) + "RESUME", // 493 (751) + "REVERSE", // 494 (752) + "REVERSED", // 495 (753) + "REWIND", // 496 (754) + "RF", // 497 (755) + "RH", // 498 (756) + "RIGHT", // 499 (757) + "ROUNDED", // 500 (758) + "RUN", // 501 (759) + "SAME", // 502 (760) + "SCREEN", // 503 (761) + "SD", // 504 (762) + "SECONDS-FROM-FORMATTED-TIME", // 505 (763) + "SECONDS-PAST-MIDNIGHT", // 506 (764) + "SECURITY", // 507 (765) + "SEPARATE", // 508 (766) + "SEQUENCE", // 509 (767) + "SEQUENTIAL", // 510 (768) + "SHARING", // 511 (769) + "SIMPLE-EXIT", // 512 (770) + "SIGN", // 513 (771) + "SIN", // 514 (772) + "SIZE", // 515 (773) + "SMALLEST-ALGEBRAIC", // 516 (774) + "SOURCE", // 517 (775) + "SOURCE-COMPUTER", // 518 (776) + "SPECIAL-NAMES", // 519 (777) + "SQRT", // 520 (778) + "STACK", // 521 (779) + "STANDARD", // 522 (780) + "STANDARD-1", // 523 (781) + "STANDARD-DEVIATION", // 524 (782) + "STANDARD-COMPARE", // 525 (783) + "STATUS", // 526 (784) + "STRONG", // 527 (785) + "SUBSTITUTE", // 528 (786) + "SUM", // 529 (787) + "SYMBOL", // 530 (788) + "SYMBOLIC", // 531 (789) + "SYNCHRONIZED", // 532 (790) + "TALLY", // 533 (791) + "TALLYING", // 534 (792) + "TAN", // 535 (793) + "TERMINATE", // 536 (794) + "TEST", // 537 (795) + "TEST-DATE-YYYYMMDD", // 538 (796) + "TEST-DAY-YYYYDDD", // 539 (797) + "TEST-FORMATTED-DATETIME", // 540 (798) + "TEST-NUMVAL", // 541 (799) + "TEST-NUMVAL-C", // 542 (800) + "TEST-NUMVAL-F", // 543 (801) + "THAN", // 544 (802) + "TIME", // 545 (803) + "TIMES", // 546 (804) + "TO", // 547 (805) + "TOP", // 548 (806) + "TOP-LEVEL", // 549 (807) + "TRACKS", // 550 (808) + "TRACK-AREA", // 551 (809) + "TRAILING", // 552 (810) + "TRANSFORM", // 553 (811) + "TRIM", // 554 (812) + "TRUE", // 555 (813) + "TRY", // 556 (814) + "TURN", // 557 (815) + "TYPE", // 558 (816) + "TYPEDEF", // 559 (817) + "ULENGTH", // 560 (818) + "UNBOUNDED", // 561 (819) + "UNIT", // 562 (820) + "UNITS", // 563 (821) + "UNIT-RECORD", // 564 (822) + "UNTIL", // 565 (823) + "UP", // 566 (824) + "UPON", // 567 (825) + "UPOS", // 568 (826) + "UPPER-CASE", // 569 (827) + "USAGE", // 570 (828) + "USING", // 571 (829) + "USUBSTR", // 572 (830) + "USUPPLEMENTARY", // 573 (831) + "UTILITY", // 574 (832) + "UUID4", // 575 (833) + "UVALID", // 576 (834) + "UWIDTH", // 577 (835) + "VALUE", // 578 (836) + "VARIANCE", // 579 (837) + "VARYING", // 580 (838) + "VOLATILE", // 581 (839) + "WHEN-COMPILED", // 582 (840) + "WITH", // 583 (841) + "WORKING-STORAGE", // 584 (842) + "XML", // 585 (843) + "XMLGENERATE", // 586 (844) + "XMLPARSE", // 587 (845) + "YEAR-TO-YYYY", // 588 (846) + "YYYYDDD", // 589 (847) + "YYYYMMDD", // 590 (848) + "ARITHMETIC", // 591 (849) + "ATTRIBUTE", // 592 (850) + "AUTO", // 593 (851) + "AUTOMATIC", // 594 (852) + "AWAY-FROM-ZERO", // 595 (853) + "BACKGROUND-COLOR", // 596 (854) + "BELL", // 597 (855) + "BINARY-ENCODING", // 598 (856) + "BLINK", // 599 (857) + "CAPACITY", // 600 (858) + "CENTER", // 601 (859) + "CLASSIFICATION", // 602 (860) + "CYCLE", // 603 (861) + "DECIMAL-ENCODING", // 604 (862) + "ENTRY-CONVENTION", // 605 (863) + "EOL", // 606 (864) + "EOS", // 607 (865) + "ERASE", // 608 (866) + "EXPANDS", // 609 (867) + "FLOAT-BINARY", // 610 (868) + "FLOAT-DECIMAL", // 611 (869) + "FOREGROUND-COLOR", // 612 (870) + "FOREVER", // 613 (871) + "FULL", // 614 (872) + "HIGHLIGHT", // 615 (873) + "HIGH-ORDER-LEFT", // 616 (874) + "HIGH-ORDER-RIGHT", // 617 (875) + "IGNORING", // 618 (876) + "IMPLEMENTS", // 619 (877) + "INITIALIZED", // 620 (878) + "INTERMEDIATE", // 621 (879) + "LC-ALL", // 622 (880) + "LC-COLLATE", // 623 (881) + "LC-CTYPE", // 624 (882) + "LC-MESSAGES", // 625 (883) + "LC-MONETARY", // 626 (884) + "LC-NUMERIC", // 627 (885) + "LC-TIME", // 628 (886) + "LOWLIGHT", // 629 (887) + "NEAREST-AWAY-FROM-ZERO", // 630 (888) + "NEAREST-EVEN", // 631 (889) + "NEAREST-TOWARD-ZERO", // 632 (890) + "NONE", // 633 (891) + "NORMAL", // 634 (892) + "NUMBERS", // 635 (893) + "PREFIXED", // 636 (894) + "PREVIOUS", // 637 (895) + "PROHIBITED", // 638 (896) + "RELATION", // 639 (897) + "REQUIRED", // 640 (898) + "REVERSE-VIDEO", // 641 (899) + "ROUNDING", // 642 (900) + "SECONDS", // 643 (901) + "SECURE", // 644 (902) + "SHORT", // 645 (903) + "SIGNED", // 646 (904) + "STANDARD-BINARY", // 647 (905) + "STANDARD-DECIMAL", // 648 (906) + "STATEMENT", // 649 (907) + "STEP", // 650 (908) + "STRUCTURE", // 651 (909) + "TOWARD-GREATER", // 652 (910) + "TOWARD-LESSER", // 653 (911) + "TRUNCATION", // 654 (912) + "UCS-4", // 655 (913) + "UNDERLINE", // 656 (914) + "UNSIGNED", // 657 (915) + "UTF-16", // 658 (916) + "UTF-8", // 659 (917) + "ADDRESS", // 660 (918) + "END-ACCEPT", // 661 (919) + "END-ADD", // 662 (920) + "END-CALL", // 663 (921) + "END-COMPUTE", // 664 (922) + "END-DELETE", // 665 (923) + "END-DISPLAY", // 666 (924) + "END-DIVIDE", // 667 (925) + "END-EVALUATE", // 668 (926) + "END-MULTIPLY", // 669 (927) + "END-PERFORM", // 670 (928) + "END-READ", // 671 (929) + "END-RETURN", // 672 (930) + "END-REWRITE", // 673 (931) + "END-SEARCH", // 674 (932) + "END-START", // 675 (933) + "END-STRING", // 676 (934) + "END-SUBTRACT", // 677 (935) + "END-UNSTRING", // 678 (936) + "END-WRITE", // 679 (937) + "END-IF", // 680 (938) + "THRU", // 681 (939) + "OR", // 682 (940) + "AND", // 683 (941) + "NOT", // 684 (942) + "NE", // 685 (943) + "LE", // 686 (944) + "GE", // 687 (945) + "POW", // 688 (946) + "NEG", // 689 (947) }; diff --git a/gcc/cobol/udf/stored-char-length.cbl b/gcc/cobol/udf/stored-char-length.cbl index 9ab3b14..66889d0 100644 --- a/gcc/cobol/udf/stored-char-length.cbl +++ b/gcc/cobol/udf/stored-char-length.cbl @@ -1,3 +1,6 @@ + >> PUSH source format + >>SOURCE format is fixed + * This function is in public domain. * Contributed by James K. Lowden of Cobolworx in August 2024 @@ -13,3 +16,4 @@ to Output-Value. End Function STORED-CHAR-LENGTH. + >> pop source format
\ No newline at end of file diff --git a/gcc/cobol/util.cc b/gcc/cobol/util.cc index 0076fc4..c85b4cb 100644 --- a/gcc/cobol/util.cc +++ b/gcc/cobol/util.cc @@ -121,35 +121,76 @@ gb4( size_t input ) { * command-line option. A push to a stack pushes the default value onto it; a * pop copies the top of the stack to the default value. * + * Supported: + * CALL-CONVENTION + * COBOL-WORDS + * DEFINE + * DISPLAY + * IF + * POP + * PUSH + * SOURCE FORMAT + * TURN + * not supported + * EVALUATE + * FLAG-02 + * FLAG-14 + * LEAP-SECOND + * LISTING + * PAGE + * PROPAGATE + * REF-MOD-ZERO-LENGTH + * * >>PUSH ALL calls the class's push() method. * >>POP ALL calls the class's pop() method. */ class cdf_directives_t { - typedef std::map<std::string, cdfval_t> cdf_values_t; - template <typename T> class cdf_stack_t : private std::stack<T> { T default_value; + const T& top() const { return std::stack<T>::top(); } + bool empty() const { return std::stack<T>::empty(); } public: void value( const T& value ) { - T& output( std::stack<T>::empty()? default_value : std::stack<T>::top() ); + T& output( empty()? default_value : std::stack<T>::top() ); output = value; + dbgmsg("cdf_directives_t::%s: %s", __func__, str(output).c_str()); } T& value() { - return std::stack<T>::empty()? default_value : std::stack<T>::top(); + return empty()? default_value : std::stack<T>::top(); } void push() { std::stack<T>::push(value()); + dbgmsg("cdf_directives_t::%s: %s", __func__, str(top()).c_str()); } void pop() { - if( std::stack<T>::empty() ) { + if( empty() ) { error_msg(YYLTYPE(), "CDF stack empty"); return; } - default_value = std::stack<T>::top(); + default_value = top(); std::stack<T>::pop(); + dbgmsg("cdf_directives_t::%s: %s", __func__, str(default_value).c_str()); + } + protected: + static std::string str(cbl_call_convention_t arg) { + char output[2] = { static_cast<char>(arg) }; + return std::string("call-convention ") + output; + } + static std::string str(current_tokens_t) { + return "<cobol-words>"; + } + static std::string str(cdf_values_t) { + return "<dictionary>"; + } + static std::string str(source_format_t arg) { + return arg.description(); } + static std::string str(cbl_enabled_exceptions_t) { + return "<enabled_exceptions>"; + } + }; public: @@ -181,6 +222,25 @@ class cdf_directives_t static cdf_directives_t cdf_directives; void +current_call_convention( cbl_call_convention_t convention) { + cdf_directives.call_convention.value(convention); +} +cbl_call_convention_t +current_call_convention() { + return cdf_directives.call_convention.value(); +} + +current_tokens_t& +cdf_current_tokens() { + return cdf_directives.cobol_words.value(); +} + +cdf_values_t& +cdf_dictionary() { + return cdf_directives.dictionary.value(); +} + +void cobol_set_indicator_column( int column ) { cdf_directives.source_format.value().indicator_column_set(column); } @@ -188,6 +248,24 @@ source_format_t& cdf_source_format() { return cdf_directives.source_format.value(); } +cbl_enabled_exceptions_t& +cdf_enabled_exceptions() { + return cdf_directives.enabled_exceptions.value(); +} + +void cdf_push() { cdf_directives.push(); } +void cdf_push_call_convention() { cdf_directives.call_convention.push(); } +void cdf_push_current_tokens() { cdf_directives.cobol_words.push(); } +void cdf_push_dictionary() { cdf_directives.dictionary.push(); } +void cdf_push_enabled_exceptions() { cdf_directives.enabled_exceptions.push(); } +void cdf_push_source_format() { cdf_directives.source_format.push(); } + +void cdf_pop() { cdf_directives.pop(); } +void cdf_pop_call_convention() { cdf_directives.call_convention.pop(); } +void cdf_pop_current_tokens() { cdf_directives.cobol_words.pop(); } +void cdf_pop_dictionary() { cdf_directives.dictionary.pop(); } +void cdf_pop_enabled_exceptions() { cdf_directives.enabled_exceptions.pop(); } +void cdf_pop_source_format() { cdf_directives.source_format.pop(); } const char * symbol_type_str( enum symbol_type_t type ) diff --git a/gcc/cobol/util.h b/gcc/cobol/util.h index 2881809..d07b669 100644 --- a/gcc/cobol/util.h +++ b/gcc/cobol/util.h @@ -110,4 +110,19 @@ public: } }; + +void cdf_push(); +void cdf_push_call_convention(); +void cdf_push_current_tokens(); +void cdf_push_dictionary(); +void cdf_push_enabled_exceptions(); +void cdf_push_source_format(); + +void cdf_pop(); +void cdf_pop_call_convention(); +void cdf_pop_current_tokens(); +void cdf_pop_dictionary(); +void cdf_pop_source_format(); +void cdf_pop_enabled_exceptions(); + #endif diff --git a/gcc/config/aarch64/aarch64-sve-builtins-sve2.cc b/gcc/config/aarch64/aarch64-sve-builtins-sve2.cc index d9922de..abe21a8 100644 --- a/gcc/config/aarch64/aarch64-sve-builtins-sve2.cc +++ b/gcc/config/aarch64/aarch64-sve-builtins-sve2.cc @@ -316,7 +316,8 @@ public: expand (function_expander &e) const override { e.prepare_gather_address_operands (1, false); - return e.use_exact_insn (CODE_FOR_aarch64_gather_ld1q); + auto icode = code_for_aarch64_gather_ld1q (e.tuple_mode (0)); + return e.use_exact_insn (icode); } }; @@ -722,7 +723,7 @@ public: expand (function_expander &e) const override { rtx data = e.args.last (); - e.args.last () = force_lowpart_subreg (VNx2DImode, data, GET_MODE (data)); + e.args.last () = aarch64_sve_reinterpret (VNx2DImode, data); e.prepare_gather_address_operands (1, false); return e.use_exact_insn (CODE_FOR_aarch64_scatter_st1q); } diff --git a/gcc/config/aarch64/aarch64-sve2.md b/gcc/config/aarch64/aarch64-sve2.md index 789ec0d..660901d 100644 --- a/gcc/config/aarch64/aarch64-sve2.md +++ b/gcc/config/aarch64/aarch64-sve2.md @@ -334,12 +334,21 @@ ;; - LD1Q (SVE2p1) ;; ------------------------------------------------------------------------- -;; Model this as operating on the largest valid element size, which is DI. -;; This avoids having to define move patterns & more for VNx1TI, which would -;; be difficult without a non-gather form of LD1Q. -(define_insn "aarch64_gather_ld1q" - [(set (match_operand:VNx2DI 0 "register_operand") - (unspec:VNx2DI +;; For little-endian targets, it would be enough to use a single pattern, +;; with a subreg to bitcast the result to whatever mode is needed. +;; However, on big-endian targets, the bitcast would need to be an +;; aarch64_sve_reinterpret instruction. That would interact badly +;; with the "&" and "?" constraints in this pattern: if the result +;; of the reinterpret needs to be in the same register as the index, +;; the RA would tend to prefer to allocate a separate register for the +;; intermediate (uncast) result, even if the reinterpret prefers tying. +;; +;; The index is logically VNx1DI rather than VNx2DI, but introducing +;; and using VNx1DI would just create more bitcasting. The ACLE intrinsic +;; uses svuint64_t, which corresponds to VNx2DI. +(define_insn "@aarch64_gather_ld1q<mode>" + [(set (match_operand:SVE_FULL 0 "register_operand") + (unspec:SVE_FULL [(match_operand:VNx2BI 1 "register_operand") (match_operand:DI 2 "aarch64_reg_or_zero") (match_operand:VNx2DI 3 "register_operand") diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc index 27c315f..10b8ed5 100644 --- a/gcc/config/aarch64/aarch64.cc +++ b/gcc/config/aarch64/aarch64.cc @@ -17932,7 +17932,7 @@ aarch64_vector_costs::add_stmt_cost (int count, vect_cost_for_stmt kind, /* Do one-time initialization based on the vinfo. */ loop_vec_info loop_vinfo = dyn_cast<loop_vec_info> (m_vinfo); - if (!m_analyzed_vinfo) + if (!m_analyzed_vinfo && !m_costing_for_scalar) { if (loop_vinfo) analyze_loop_vinfo (loop_vinfo); diff --git a/gcc/config/riscv/constraints.md b/gcc/config/riscv/constraints.md index ccab1a2..5ecaa19 100644 --- a/gcc/config/riscv/constraints.md +++ b/gcc/config/riscv/constraints.md @@ -237,10 +237,11 @@ (and (match_code "const_vector") (match_test "rtx_equal_p (op, riscv_vector::gen_scalar_move_mask (GET_MODE (op)))"))) -(define_memory_constraint "Wdm" +(define_constraint "Wdm" "Vector duplicate memory operand" - (and (match_code "mem") - (match_code "reg" "0"))) + (and (match_test "strided_load_broadcast_p ()") + (and (match_code "mem") + (match_code "reg" "0")))) ;; Vendor ISA extension constraints. diff --git a/gcc/config/riscv/predicates.md b/gcc/config/riscv/predicates.md index 8baad2f..1f9a6b5 100644 --- a/gcc/config/riscv/predicates.md +++ b/gcc/config/riscv/predicates.md @@ -617,7 +617,7 @@ ;; The scalar operand can be directly broadcast by RVV instructions. (define_predicate "direct_broadcast_operand" - (match_test "riscv_vector::can_be_broadcasted_p (op)")) + (match_test "riscv_vector::can_be_broadcast_p (op)")) ;; A CONST_INT operand that has exactly two bits cleared. (define_predicate "const_nottwobits_operand" diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h index 38f63ea..a41c4c2 100644 --- a/gcc/config/riscv/riscv-protos.h +++ b/gcc/config/riscv/riscv-protos.h @@ -604,6 +604,7 @@ void emit_vlmax_vsetvl (machine_mode, rtx); void emit_hard_vlmax_vsetvl (machine_mode, rtx); void emit_vlmax_insn (unsigned, unsigned, rtx *); void emit_nonvlmax_insn (unsigned, unsigned, rtx *, rtx); +void emit_avltype_insn (unsigned, unsigned, rtx *, avl_type, rtx = nullptr); void emit_vlmax_insn_lra (unsigned, unsigned, rtx *, rtx); enum vlmul_type get_vlmul (machine_mode); rtx get_vlmax_rtx (machine_mode); @@ -760,7 +761,7 @@ uint8_t get_sew (rtx_insn *); enum vlmul_type get_vlmul (rtx_insn *); int count_regno_occurrences (rtx_insn *, unsigned int); bool imm_avl_p (machine_mode); -bool can_be_broadcasted_p (rtx); +bool can_be_broadcast_p (rtx); bool gather_scatter_valid_offset_p (machine_mode); HOST_WIDE_INT estimated_poly_value (poly_int64, unsigned int); bool whole_reg_to_reg_move_p (rtx *, machine_mode, int); @@ -813,6 +814,7 @@ extern const char *th_output_move (rtx, rtx); extern bool th_print_operand_address (FILE *, machine_mode, rtx); #endif +extern bool strided_load_broadcast_p (void); extern bool riscv_use_divmod_expander (void); void riscv_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree, int); extern bool diff --git a/gcc/config/riscv/riscv-selftests.cc b/gcc/config/riscv/riscv-selftests.cc index 34d01ac..9ca1ffe 100644 --- a/gcc/config/riscv/riscv-selftests.cc +++ b/gcc/config/riscv/riscv-selftests.cc @@ -342,9 +342,13 @@ run_broadcast_selftests (void) expand_vector_broadcast (mode, mem); \ insn = get_last_insn (); \ src = SET_SRC (PATTERN (insn)); \ - ASSERT_TRUE (MEM_P (XEXP (src, 0))); \ - ASSERT_TRUE ( \ - rtx_equal_p (src, gen_rtx_VEC_DUPLICATE (mode, XEXP (src, 0)))); \ + if (strided_load_broadcast_p ()) \ + { \ + ASSERT_TRUE (MEM_P (XEXP (src, 0))); \ + ASSERT_TRUE ( \ + rtx_equal_p (src, \ + gen_rtx_VEC_DUPLICATE (mode, XEXP (src, 0)))); \ + } \ end_sequence (); \ /* Test vmv.v.x or vfmv.v.f. */ \ start_sequence (); \ diff --git a/gcc/config/riscv/riscv-v.cc b/gcc/config/riscv/riscv-v.cc index 2efe56a..242ac08 100644 --- a/gcc/config/riscv/riscv-v.cc +++ b/gcc/config/riscv/riscv-v.cc @@ -437,6 +437,26 @@ emit_nonvlmax_insn (unsigned icode, unsigned insn_flags, rtx *ops, rtx vl) e.emit_insn ((enum insn_code) icode, ops); } +/* Emit either a VLMAX insn or a non-VLMAX insn depending on TYPE. For a + non-VLMAX insn, the length must be specified in VL. */ + +void +emit_avltype_insn (unsigned icode, unsigned insn_flags, rtx *ops, + avl_type type, rtx vl) +{ + if (type != avl_type::VLMAX && vl != NULL_RTX) + { + insn_expander<RVV_INSN_OPERANDS_MAX> e (insn_flags, false); + e.set_vl (vl); + e.emit_insn ((enum insn_code) icode, ops); + } + else + { + insn_expander<RVV_INSN_OPERANDS_MAX> e (insn_flags, true); + e.emit_insn ((enum insn_code) icode, ops); + } +} + /* Return true if the vector duplicated by a super element which is the fusion of consecutive elements. @@ -2144,21 +2164,40 @@ sew64_scalar_helper (rtx *operands, rtx *scalar_op, rtx vl, return false; } + bool avoid_strided_broadcast = false; if (CONST_INT_P (*scalar_op)) { if (maybe_gt (GET_MODE_SIZE (scalar_mode), GET_MODE_SIZE (Pmode))) - *scalar_op = force_const_mem (scalar_mode, *scalar_op); + { + if (strided_load_broadcast_p ()) + *scalar_op = force_const_mem (scalar_mode, *scalar_op); + else + avoid_strided_broadcast = true; + } else *scalar_op = force_reg (scalar_mode, *scalar_op); } rtx tmp = gen_reg_rtx (vector_mode); - rtx ops[] = {tmp, *scalar_op}; - if (type == VLMAX) - emit_vlmax_insn (code_for_pred_broadcast (vector_mode), UNARY_OP, ops); + if (!avoid_strided_broadcast) + { + rtx ops[] = {tmp, *scalar_op}; + emit_avltype_insn (code_for_pred_broadcast (vector_mode), UNARY_OP, ops, + type, vl); + } else - emit_nonvlmax_insn (code_for_pred_broadcast (vector_mode), UNARY_OP, ops, - vl); + { + /* Load scalar as V1DI and broadcast via vrgather.vi. */ + rtx tmp1 = gen_reg_rtx (V1DImode); + emit_move_insn (tmp1, lowpart_subreg (V1DImode, *scalar_op, + scalar_mode)); + tmp1 = lowpart_subreg (vector_mode, tmp1, V1DImode); + + rtx ops[] = {tmp, tmp1, CONST0_RTX (Pmode)}; + emit_vlmax_insn (code_for_pred_gather_scalar (vector_mode), + BINARY_OP, ops); + } + emit_vector_func (operands, tmp); return true; @@ -5769,9 +5808,9 @@ count_regno_occurrences (rtx_insn *rinsn, unsigned int regno) return count; } -/* Return true if the OP can be directly broadcasted. */ +/* Return true if the OP can be directly broadcast. */ bool -can_be_broadcasted_p (rtx op) +can_be_broadcast_p (rtx op) { machine_mode mode = GET_MODE (op); /* We don't allow RA (register allocation) reload generate @@ -5783,7 +5822,8 @@ can_be_broadcasted_p (rtx op) return false; if (satisfies_constraint_K (op) || register_operand (op, mode) - || satisfies_constraint_Wdm (op) || rtx_equal_p (op, CONST0_RTX (mode))) + || (strided_load_broadcast_p () && satisfies_constraint_Wdm (op)) + || rtx_equal_p (op, CONST0_RTX (mode))) return true; return can_create_pseudo_p () && nonmemory_operand (op, mode); diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index b868a50..a4428f0 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -283,6 +283,10 @@ enum riscv_fusion_pairs RISCV_FUSE_AUIPC_LD = (1 << 7), RISCV_FUSE_LDPREINCREMENT = (1 << 8), RISCV_FUSE_ALIGNED_STD = (1 << 9), + RISCV_FUSE_CACHE_ALIGNED_STD = (1 << 10), + RISCV_FUSE_BFEXT = (1 << 11), + RISCV_FUSE_EXPANDED_LD = (1 << 12), + RISCV_FUSE_B_ALUI = (1 << 13), }; /* Costs of various operations on the different architectures. */ @@ -302,6 +306,7 @@ struct riscv_tune_param bool vector_unaligned_access; bool use_divmod_expansion; bool overlap_op_by_pieces; + bool use_zero_stride_load; bool speculative_sched_vsetvl; unsigned int fusible_ops; const struct cpu_vector_cost *vec_costs; @@ -465,6 +470,7 @@ static const struct riscv_tune_param generic_tune_info = { false, /* vector_unaligned_access */ false, /* use_divmod_expansion */ false, /* overlap_op_by_pieces */ + true, /* use_zero_stride_load */ false, /* speculative_sched_vsetvl */ RISCV_FUSE_NOTHING, /* fusible_ops */ NULL, /* vector cost */ @@ -488,6 +494,7 @@ static const struct riscv_tune_param rocket_tune_info = { false, /* vector_unaligned_access */ false, /* use_divmod_expansion */ false, /* overlap_op_by_pieces */ + true, /* use_zero_stride_load */ false, /* speculative_sched_vsetvl */ RISCV_FUSE_NOTHING, /* fusible_ops */ NULL, /* vector cost */ @@ -511,6 +518,7 @@ static const struct riscv_tune_param sifive_7_tune_info = { false, /* vector_unaligned_access */ false, /* use_divmod_expansion */ false, /* overlap_op_by_pieces */ + true, /* use_zero_stride_load */ false, /* speculative_sched_vsetvl */ RISCV_FUSE_NOTHING, /* fusible_ops */ NULL, /* vector cost */ @@ -534,6 +542,7 @@ static const struct riscv_tune_param sifive_p400_tune_info = { false, /* vector_unaligned_access */ false, /* use_divmod_expansion */ false, /* overlap_op_by_pieces */ + true, /* use_zero_stride_load */ false, /* speculative_sched_vsetvl */ RISCV_FUSE_LUI_ADDI | RISCV_FUSE_AUIPC_ADDI, /* fusible_ops */ &generic_vector_cost, /* vector cost */ @@ -557,6 +566,7 @@ static const struct riscv_tune_param sifive_p600_tune_info = { false, /* vector_unaligned_access */ false, /* use_divmod_expansion */ false, /* overlap_op_by_pieces */ + true, /* use_zero_stride_load */ false, /* speculative_sched_vsetvl */ RISCV_FUSE_LUI_ADDI | RISCV_FUSE_AUIPC_ADDI, /* fusible_ops */ &generic_vector_cost, /* vector cost */ @@ -580,6 +590,7 @@ static const struct riscv_tune_param thead_c906_tune_info = { false, /* vector_unaligned_access */ false, /* use_divmod_expansion */ false, /* overlap_op_by_pieces */ + true, /* use_zero_stride_load */ false, /* speculative_sched_vsetvl */ RISCV_FUSE_NOTHING, /* fusible_ops */ NULL, /* vector cost */ @@ -603,6 +614,7 @@ static const struct riscv_tune_param xiangshan_nanhu_tune_info = { false, /* vector_unaligned_access */ false, /* use_divmod_expansion */ false, /* overlap_op_by_pieces */ + true, /* use_zero_stride_load */ false, /* speculative_sched_vsetvl */ RISCV_FUSE_ZEXTW | RISCV_FUSE_ZEXTH, /* fusible_ops */ NULL, /* vector cost */ @@ -626,6 +638,7 @@ static const struct riscv_tune_param generic_ooo_tune_info = { true, /* vector_unaligned_access */ false, /* use_divmod_expansion */ true, /* overlap_op_by_pieces */ + true, /* use_zero_stride_load */ false, /* speculative_sched_vsetvl */ RISCV_FUSE_NOTHING, /* fusible_ops */ &generic_vector_cost, /* vector cost */ @@ -649,6 +662,7 @@ static const struct riscv_tune_param tt_ascalon_d8_tune_info = { true, /* vector_unaligned_access */ true, /* use_divmod_expansion */ true, /* overlap_op_by_pieces */ + true, /* use_zero_stride_load */ false, /* speculative_sched_vsetvl */ RISCV_FUSE_NOTHING, /* fusible_ops */ &generic_vector_cost, /* vector cost */ @@ -672,6 +686,7 @@ static const struct riscv_tune_param optimize_size_tune_info = { false, /* vector_unaligned_access */ false, /* use_divmod_expansion */ false, /* overlap_op_by_pieces */ + true, /* use_zero_stride_load */ false, /* speculative_sched_vsetvl */ RISCV_FUSE_NOTHING, /* fusible_ops */ NULL, /* vector cost */ @@ -695,6 +710,7 @@ static const struct riscv_tune_param mips_p8700_tune_info = { false, /* vector_unaligned_access */ true, /* use_divmod_expansion */ false, /* overlap_op_by_pieces */ + true, /* use_zero_stride_load */ false, /* speculative_sched_vsetvl */ RISCV_FUSE_NOTHING, /* fusible_ops */ NULL, /* vector cost */ @@ -10205,6 +10221,81 @@ riscv_fusion_enabled_p(enum riscv_fusion_pairs op) return tune_param->fusible_ops & op; } +/* Matches an add: + (set (reg:DI rd) (plus:SI (reg:SI rs1) (reg:SI rs2))) */ + +static bool +riscv_set_is_add (rtx set) +{ + return (GET_CODE (SET_SRC (set)) == PLUS + && REG_P (XEXP (SET_SRC (set), 0)) + && REG_P (XEXP (SET_SRC (set), 1)) + && REG_P (SET_DEST (set))); +} + +/* Matches an addi: + (set (reg:DI rd) (plus:SI (reg:SI rs1) (const_int imm))) */ + +static bool +riscv_set_is_addi (rtx set) +{ + return (GET_CODE (SET_SRC (set)) == PLUS + && REG_P (XEXP (SET_SRC (set), 0)) + && CONST_INT_P (XEXP (SET_SRC (set), 1)) + && REG_P (SET_DEST (set))); +} + +/* Matches an add.uw: + (set (reg:DI rd) + (plus:DI (zero_extend:DI (reg:SI rs1)) (reg:DI rs2))) */ + +static bool +riscv_set_is_adduw (rtx set) +{ + return (GET_CODE (SET_SRC (set)) == PLUS + && GET_CODE (XEXP (SET_SRC (set), 0)) == ZERO_EXTEND + && REG_P (XEXP (XEXP (SET_SRC (set), 0), 0)) + && REG_P (XEXP (SET_SRC (set), 1)) + && REG_P (SET_DEST (set))); +} + +/* Matches a shNadd: + (set (reg:DI rd) + (plus:DI (ashift:DI (reg:DI rs1) (const_int N)) (reg:DI rS2)) */ + +static bool +riscv_set_is_shNadd (rtx set) +{ + return (GET_CODE (SET_SRC (set)) == PLUS + && GET_CODE (XEXP (SET_SRC (set), 0)) == ASHIFT + && REG_P (XEXP (XEXP (SET_SRC (set), 0), 0)) + && CONST_INT_P (XEXP (XEXP (SET_SRC (set), 0), 1)) + && (INTVAL (XEXP (XEXP (SET_SRC (set), 0), 1)) == 1 + || INTVAL (XEXP (XEXP (SET_SRC (set), 0), 1)) == 2 + || INTVAL (XEXP (XEXP (SET_SRC (set), 0), 1)) == 3) + && REG_P (SET_DEST (set))); +} + +/* Matches a shNadd.uw: + (set (reg:DI rd) + (plus:DI (and:DI (ashift:DI (reg:DI rs1) (const_int N)) + (const_int N)) + (reg:DI rs2)) */ + +static bool +riscv_set_is_shNadduw (rtx set) +{ + return (GET_CODE (SET_SRC (set)) == PLUS + && GET_CODE (XEXP (SET_SRC (set), 0)) == AND + && GET_CODE (XEXP (XEXP (SET_SRC (set), 0), 0)) == ASHIFT + && REG_P (XEXP (XEXP (XEXP (SET_SRC (set), 0), 0), 0)) + && CONST_INT_P (XEXP (XEXP (XEXP (SET_SRC (set), 0), 0), 1)) + && (INTVAL (XEXP (XEXP (XEXP (SET_SRC (set), 0), 0), 1)) == 1 + || INTVAL (XEXP (XEXP (XEXP (SET_SRC (set), 0), 0), 1)) == 2 + || INTVAL (XEXP (XEXP (XEXP (SET_SRC (set), 0), 0), 1)) == 3) + && REG_P (SET_DEST (set))); +} + /* Implement TARGET_SCHED_MACRO_FUSION_PAIR_P. Return true if PREV and CURR should be kept together during scheduling. */ @@ -10334,6 +10425,139 @@ riscv_macro_fusion_pair_p (rtx_insn *prev, rtx_insn *curr) } } + if (simple_sets_p && riscv_fusion_enabled_p (RISCV_FUSE_EXPANDED_LD) + && (sched1 || prev_dest_regno == curr_dest_regno)) + { + /* For the "expanded add/load fusion" family we have 2 main + categories: memory loads with displacement (i.e. with imm offset) + and loads without displacement (i.e. with offset = x0). + + For loads without displacement we'll need: + - add + ld (done in RISCV_FUSE_LDINDEXED) + - addi + ld (done in RISCV_FUSE_LDPREINCREMENT) + - shNadd + ld + - add.uw + lw + - shNadd.uw + lw + + For loads with displacement/immediates: + with lw with immediate): + - add + ld with displacement + - addi + ld with displacement + - shNadd + ld with displacement + - add.uw + lw with displacement + - shNadd.uw + lw with displacement */ + + /* We're trying to match a curr_set ld with displacement: + prev (add|addi) = (set (reg:DI rd) (...)) + curr (ld) == (set (reg:DI rD) + (mem:DI (plus:DI (reg:DI rD) (const_int IMM12)))) */ + if (MEM_P (SET_SRC (curr_set)) + && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set))) + && GET_CODE (XEXP (SET_SRC (curr_set), 0)) == PLUS + && REGNO (XEXP (XEXP (SET_SRC (curr_set), 0), 0)) == prev_dest_regno) + { + if (riscv_set_is_add (prev_set)) + { + if (dump_file) + fprintf (dump_file, "RISCV_FUSE_EXPANDED_LD\n"); + return true; + } + + if (riscv_set_is_addi (prev_set)) + { + if (dump_file) + fprintf (dump_file, "RISCV_FUSE_EXPANDED_LD\n"); + return true; + } + + if (riscv_set_is_shNadd (prev_set)) + { + if (dump_file) + fprintf (dump_file, "RISCV_FUSE_EXPANDED_LD\n"); + return true; + } + } + + /* We're trying to match a ld without displacement: + prev (addi|shNadd) = (reg:DI rD) (...)) + curr (ld) == (set (reg:DI rD) + (mem:DI (reg:DI rD))) */ + if (MEM_P (SET_SRC (curr_set)) + && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set))) + && REG_P (XEXP (SET_SRC (curr_set), 0)) + && REGNO (XEXP (SET_SRC (curr_set), 0)) == prev_dest_regno) + { + if (riscv_set_is_addi (prev_set)) + { + if (dump_file) + fprintf (dump_file, "RISCV_FUSE_EXPANDED_LD\n"); + return true; + } + + if (riscv_set_is_shNadd (prev_set)) + { + if (dump_file) + fprintf (dump_file, "RISCV_FUSE_EXPANDED_LD\n"); + return true; + } + } + + /* We're trying to match a curr_set lw with displacement: + prev (add.uw|shNadd.uw) = (set (reg:DI rd) (...)) + curr (lw) == (set (reg:DI rd) + (any_extend:DI (mem:SUBX (plus:DI ((reg:DI rd) + (const_int IMM)))) */ + if ((GET_CODE (SET_SRC (curr_set)) == SIGN_EXTEND + || (GET_CODE (SET_SRC (curr_set)) == ZERO_EXTEND)) + && MEM_P (XEXP (SET_SRC (curr_set), 0)) + && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set))) + && GET_CODE (XEXP (XEXP (SET_SRC (curr_set), 0), 0)) == PLUS + && REG_P (XEXP (XEXP (XEXP (SET_SRC (curr_set), 0), 0),0)) + && (REGNO (XEXP (XEXP (XEXP (SET_SRC (curr_set), 0), 0),0)) + == prev_dest_regno)) + { + if (riscv_set_is_adduw (prev_set)) + { + if (dump_file) + fprintf (dump_file, "RISCV_FUSE_EXPANDED_LD\n"); + return true; + } + + if (riscv_set_is_shNadduw (prev_set)) + { + if (dump_file) + fprintf (dump_file, "RISCV_FUSE_EXPANDED_LD\n"); + return true; + } + } + + /* We're trying to match a curr_set lw without displacement: + prev (add.uw|shNadd.uw) = (set (reg:DI rd) (...)) + curr (ld|lh|lw) == (set (reg:DI rd) + (any_extend:DI (mem:SUBX (reg:DI rsd)))) */ + if ((GET_CODE (SET_SRC (curr_set)) == SIGN_EXTEND + || (GET_CODE (SET_SRC (curr_set)) == ZERO_EXTEND)) + && MEM_P (XEXP (SET_SRC (curr_set), 0)) + && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set))) + && REG_P (XEXP (XEXP (SET_SRC (curr_set), 0), 0)) + && REGNO (XEXP (XEXP (SET_SRC (curr_set), 0), 0)) == prev_dest_regno) + { + if (riscv_set_is_adduw (prev_set)) + { + if (dump_file) + fprintf (dump_file, "RISCV_FUSE_EXPANDED_LD\n"); + return true; + } + + if (riscv_set_is_shNadduw (prev_set)) + { + if (dump_file) + fprintf (dump_file, "RISCV_FUSE_EXPANDED_LD\n"); + return true; + } + } + } + if (simple_sets_p && riscv_fusion_enabled_p (RISCV_FUSE_LDPREINCREMENT) && (sched1 || prev_dest_regno == curr_dest_regno)) { @@ -10474,7 +10698,7 @@ riscv_macro_fusion_pair_p (rtx_insn *prev, rtx_insn *curr) } } - if (simple_sets_p && riscv_fusion_enabled_p (RISCV_FUSE_ALIGNED_STD)) + if (simple_sets_p && riscv_fusion_enabled_p (RISCV_FUSE_CACHE_ALIGNED_STD)) { /* We are trying to match the following: prev (sd) == (set (mem (plus (reg sp|fp) (const_int))) @@ -10528,6 +10752,175 @@ riscv_macro_fusion_pair_p (rtx_insn *prev, rtx_insn *curr) } } + /* More general form of the RISCV_FUSE_CACHE_ALIGNED_STD. The + major difference is the dependency on the stores being opposite + halves of a cache line is dropped. Instead the lowest address + needs 2X the alignment of the object and the higher address + immediately followed the first object. */ + if (simple_sets_p && riscv_fusion_enabled_p (RISCV_FUSE_ALIGNED_STD)) + { + /* We are trying to match the following: + prev (sd) == (set (mem (plus (reg rS1) (const_int))) + (reg rS2)) + curr (sd) == (set (mem (plus (reg rS1) (const_int))) + (reg rS3)) */ + + if (MEM_P (SET_DEST (prev_set)) + && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set))) + && MEM_P (SET_DEST (curr_set)) + /* Stores must have the same width */ + && GET_MODE (SET_DEST (curr_set)) == GET_MODE (SET_DEST (prev_set))) + { + rtx base_prev, base_curr, offset_prev, offset_curr; + unsigned mode_size; + + extract_base_offset_in_addr (SET_DEST (prev_set), + &base_prev, &offset_prev); + extract_base_offset_in_addr (SET_DEST (curr_set), + &base_curr, &offset_curr); + + /* Proceed only if we find both bases, both bases + are registers and bases are the same register. */ + if (base_prev != NULL_RTX && base_curr != NULL_RTX + && REG_P (base_prev) && REG_P (base_curr) + && REGNO (base_prev) == REGNO (base_curr)) + { + machine_mode mode = GET_MODE (SET_DEST (curr_set)); + mode_size = estimated_poly_value (GET_MODE_SIZE (mode)); + + HOST_WIDE_INT offset_prev_int = INTVAL (offset_prev); + HOST_WIDE_INT offset_curr_int = INTVAL (offset_curr); + + /* Get the smaller offset into OFFSET_PREV_INT. */ + if (offset_prev_int > offset_curr_int) + std::swap (offset_prev_int, offset_curr_int); + + /* We've normalized, so we need to check that the lower + address is aligned to 2X the size of the object. The + higher address must be the lower address plus the + size of the object. */ + if (((offset_prev_int % (2 * mode_size)) == 0) + && offset_prev_int + mode_size == offset_curr_int) + { + if (dump_file) + fprintf (dump_file, "RISCV_FUSE_ALIGNED_STD\n"); + return true; + } + } + } + } + + if (simple_sets_p && riscv_fusion_enabled_p (RISCV_FUSE_BFEXT) + && (sched1 || prev_dest_regno == curr_dest_regno)) + { + /* We are trying to match the following: + prev (slli) == (set (reg:DI rD) + (ashift:DI (reg:DI rS) (const_int))) + curr (srli) == (set (reg:DI rD) + (lshiftrt:DI (reg:DI rD) (const_int))) */ + + if (GET_CODE (SET_SRC (prev_set)) == ASHIFT + && (GET_CODE (SET_SRC (curr_set)) == LSHIFTRT + || GET_CODE (SET_SRC (curr_set)) == ASHIFTRT) + && REG_P (SET_DEST (prev_set)) + && REG_P (SET_DEST (curr_set)) + && REGNO (XEXP (SET_SRC (curr_set), 0)) == prev_dest_regno + && CONST_INT_P (XEXP (SET_SRC (prev_set), 1)) + && CONST_INT_P (XEXP (SET_SRC (curr_set), 1))) + { + if (dump_file) + fprintf (dump_file, "RISCV_FUSE_BFEXT\n"); + return true; + } + } + + if (simple_sets_p && riscv_fusion_enabled_p (RISCV_FUSE_B_ALUI) + && (sched1 || prev_dest_regno == curr_dest_regno)) + { + /* We are trying to match the following: + prev (orc.b) == (set (reg rD) + (unspec (reg rS1))) + curr (not) == (set (reg rD2) (not (reg rD))) */ + + if (GET_CODE (SET_SRC (prev_set)) == UNSPEC + && GET_CODE (SET_SRC (curr_set)) == NOT + && XINT (SET_SRC (prev_set), 1) == UNSPEC_ORC_B + && REG_P (SET_DEST (prev_set)) + && REG_P (SET_DEST (curr_set)) + && REG_P (XEXP (SET_SRC (curr_set), 0)) + && REGNO (XEXP (SET_SRC (curr_set), 0)) == prev_dest_regno) + { + if (dump_file) + fprintf (dump_file, "RISCV_FUSE_B_ALUI\n"); + return true; + } + + /* We are trying to match the following: + prev (ctz) == (set (reg rD) (ctz (reg rS1))) + curr (andi) == (set (reg rD) + (and (reg rD) (const_int 63))) */ + + if (GET_CODE (SET_SRC (prev_set)) == CTZ + && GET_CODE (SET_SRC (curr_set)) == AND + && CONST_INT_P (XEXP (SET_SRC (curr_set), 1)) + && INTVAL (XEXP (SET_SRC (curr_set), 1)) == 63 + && REG_P (SET_DEST (prev_set)) + && REG_P (SET_DEST (curr_set)) + && REG_P (XEXP (SET_SRC (curr_set), 0)) + && REGNO (XEXP (SET_SRC (curr_set), 0)) == prev_dest_regno) + { + if (dump_file) + fprintf (dump_file, "RISCV_FUSE_B_ALUI\n"); + return true; + } + + /* We are trying to match the following: + prev (sub) == (set (reg rD) + (minus (const_int 0) (reg rS2)) + curr (max) == (set (reg rD) + (smax (reg rD) (reg rS2))) */ + + if (GET_CODE (SET_SRC (prev_set)) == MINUS + && (XEXP (SET_SRC (prev_set), 0) + == CONST0_RTX (GET_MODE (SET_SRC (prev_set)))) + && CONST_INT_P (XEXP (SET_SRC (prev_set), 0)) + && GET_CODE (SET_SRC (curr_set)) == SMAX + && REG_P (SET_DEST (prev_set)) + && REG_P (SET_DEST (curr_set)) + && REG_P (XEXP (SET_SRC (curr_set), 0)) + && REGNO (XEXP (SET_SRC (curr_set), 0)) == prev_dest_regno + && REG_P (XEXP (SET_SRC (prev_set), 1)) + && REG_P (XEXP (SET_SRC (curr_set), 1)) + && (REGNO (XEXP (SET_SRC (prev_set), 1)) + == REGNO (XEXP (SET_SRC (curr_set), 1)))) + { + if (dump_file) + fprintf (dump_file, "RISCV_FUSE_B_ALUI\n"); + return true; + } + + /* We are trying to match the following: + prev (neg) == (set (reg rD) (neg (reg rS1))) + curr (max) == (set (reg rD) + (smax (reg rD) (reg rS1))) */ + + if (GET_CODE (SET_SRC (prev_set)) == NEG + && GET_CODE (SET_SRC (curr_set)) == SMAX + && REG_P (SET_DEST (prev_set)) + && REG_P (SET_DEST (curr_set)) + && REG_P (XEXP (SET_SRC (curr_set), 0)) + && REGNO (XEXP (SET_SRC (curr_set), 0)) == prev_dest_regno + && REG_P (XEXP (SET_SRC (prev_set), 0)) + && REG_P (XEXP (SET_SRC (curr_set), 1)) + && (REGNO (XEXP (SET_SRC (prev_set), 0)) + == REGNO (XEXP (SET_SRC (curr_set), 1)))) + { + if (dump_file) + fprintf (dump_file, "RISCV_FUSE_B_ALUI\n"); + return true; + } + } + return false; } @@ -12384,6 +12777,14 @@ riscv_lshift_subword (machine_mode mode ATTRIBUTE_UNUSED, rtx value, rtx shift, gen_lowpart (QImode, shift))); } +/* Return TRUE if we should use the zero stride load, FALSE otherwise. */ + +bool +strided_load_broadcast_p () +{ + return tune_param->use_zero_stride_load; +} + /* Return TRUE if we should use the divmod expander, FALSE otherwise. This allows the behavior to be tuned for specific implementations as well as when optimizing for size. */ diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md index 2046f04..c5b23b3 100644 --- a/gcc/config/riscv/vector.md +++ b/gcc/config/riscv/vector.md @@ -1580,8 +1580,22 @@ "&& 1" [(const_int 0)] { - riscv_vector::emit_vlmax_insn (code_for_pred_broadcast (<MODE>mode), - riscv_vector::UNARY_OP, operands); + if (!strided_load_broadcast_p () + && TARGET_ZVFHMIN && !TARGET_ZVFH && <VEL>mode == HFmode) + { + /* For Float16, reinterpret as HImode, broadcast and reinterpret + back. */ + poly_uint64 nunits = GET_MODE_NUNITS (<MODE>mode); + machine_mode vmodehi + = riscv_vector::get_vector_mode (HImode, nunits).require (); + rtx ops[] = {lowpart_subreg (vmodehi, operands[0], <MODE>mode), + lowpart_subreg (HImode, operands[1], HFmode)}; + riscv_vector::emit_vlmax_insn (code_for_pred_broadcast (vmodehi), + riscv_vector::UNARY_OP, ops); + } + else + riscv_vector::emit_vlmax_insn (code_for_pred_broadcast (<MODE>mode), + riscv_vector::UNARY_OP, operands); DONE; } [(set_attr "type" "vector")] @@ -2171,7 +2185,7 @@ } } else if (GET_MODE_BITSIZE (<VEL>mode) > GET_MODE_BITSIZE (Pmode) - && (immediate_operand (operands[3], Pmode) + && (immediate_operand (operands[3], Pmode) || (CONST_POLY_INT_P (operands[3]) && known_ge (rtx_to_poly_int64 (operands[3]), 0U) && known_le (rtx_to_poly_int64 (operands[3]), GET_MODE_SIZE (<MODE>mode))))) @@ -2224,12 +2238,7 @@ "(register_operand (operands[3], <VEL>mode) || CONST_POLY_INT_P (operands[3])) && GET_MODE_BITSIZE (<VEL>mode) > GET_MODE_BITSIZE (Pmode)" - [(set (match_dup 0) - (if_then_else:V_VLSI (unspec:<VM> [(match_dup 1) (match_dup 4) - (match_dup 5) (match_dup 6) (match_dup 7) - (reg:SI VL_REGNUM) (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE) - (vec_duplicate:V_VLSI (match_dup 3)) - (match_dup 2)))] + [(const_int 0)] { gcc_assert (can_create_pseudo_p ()); if (CONST_POLY_INT_P (operands[3])) @@ -2238,12 +2247,6 @@ emit_move_insn (tmp, operands[3]); operands[3] = tmp; } - rtx m = assign_stack_local (<VEL>mode, GET_MODE_SIZE (<VEL>mode), - GET_MODE_ALIGNMENT (<VEL>mode)); - m = validize_mem (m); - emit_move_insn (m, operands[3]); - m = gen_rtx_MEM (<VEL>mode, force_reg (Pmode, XEXP (m, 0))); - operands[3] = m; /* For SEW = 64 in RV32 system, we expand vmv.s.x: andi a2,a2,1 @@ -2254,6 +2257,35 @@ operands[4] = riscv_vector::gen_avl_for_scalar_move (operands[4]); operands[1] = CONSTM1_RTX (<VM>mode); } + + /* If the target doesn't want a strided-load broadcast we go with a regular + V1DImode load and a broadcast gather. */ + if (strided_load_broadcast_p ()) + { + rtx mem = assign_stack_local (<VEL>mode, GET_MODE_SIZE (<VEL>mode), + GET_MODE_ALIGNMENT (<VEL>mode)); + mem = validize_mem (mem); + emit_move_insn (mem, operands[3]); + mem = gen_rtx_MEM (<VEL>mode, force_reg (Pmode, XEXP (mem, 0))); + + emit_insn + (gen_pred_broadcast<mode> + (operands[0], operands[1], operands[2], mem, + operands[4], operands[5], operands[6], operands[7])); + } + else + { + rtx tmp = gen_reg_rtx (V1DImode); + emit_move_insn (tmp, lowpart_subreg (V1DImode, operands[3], + <VEL>mode)); + tmp = lowpart_subreg (<MODE>mode, tmp, V1DImode); + + emit_insn + (gen_pred_gather<mode>_scalar + (operands[0], operands[1], operands[2], tmp, CONST0_RTX (Pmode), + operands[4], operands[5], operands[6], operands[7])); + } + DONE; } [(set_attr "type" "vimov,vimov,vlds,vlds,vlds,vlds,vimovxv,vimovxv") (set_attr "mode" "<MODE>")]) @@ -2293,9 +2325,9 @@ (reg:SI VL_REGNUM) (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE) (vec_duplicate:V_VLSF_ZVFHMIN - (match_operand:<VEL> 3 "direct_broadcast_operand" "Wdm, Wdm, Wdm, Wdm")) + (match_operand:<VEL> 3 "direct_broadcast_operand" " A, A, A, A")) (match_operand:V_VLSF_ZVFHMIN 2 "vector_merge_operand" " vu, 0, vu, 0")))] - "TARGET_VECTOR" + "TARGET_VECTOR && strided_load_broadcast_p ()" "@ vlse<sew>.v\t%0,%3,zero,%1.t vlse<sew>.v\t%0,%3,zero,%1.t diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 79873a2..2944f22 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,224 @@ +2025-07-10 Jakub Jelinek <jakub@redhat.com> + + * cp-tree.h (struct lang_type): Add comment before key_method. + Remove lambda_expr. + (CLASSTYPE_KEY_METHOD): Give NULL_TREE if not TYPE_POLYMORPHIC_P. + (SET_CLASSTYPE_KEY_METHOD): Define. + (CLASSTYPE_LAMBDA_EXPR): Give NULL_TREE if TYPE_POLYMORPHIC_P. + Use key_method member instead of lambda_expr. + (SET_CLASSTYPE_LAMBDA_EXPR): Define. + * class.cc (determine_key_method): Use SET_CLASSTYPE_KEY_METHOD + macro. + * decl.cc (xref_tag): Use SET_CLASSTYPE_LAMBDA_EXPR macro. + * lambda.cc (begin_lambda_type): Likewise. + * module.cc (trees_in::read_class_def): Use SET_CLASSTYPE_LAMBDA_EXPR + and SET_CLASSTYPE_KEY_METHOD macros, assert lambda is NULL if + TYPE_POLYMORPHIC_P and otherwise assert key_method is NULL. + +2025-07-10 Jakub Jelinek <jakub@redhat.com> + + PR c++/120628 + * parser.cc (cp_parser_elaborated_type_specifier): Use + cp_parser_nth_token_starts_class_definition_p with extra argument 1 + instead of cp_parser_next_token_starts_class_definition_p. + (cp_parser_class_property_specifier_seq_opt): For final conditional + keyword in C++98 check if the token after it isn't + cp_parser_nth_token_starts_class_definition_p nor CPP_NAME and in + that case break without consuming it nor warning. + (cp_parser_class_head): Use + cp_parser_nth_token_starts_class_definition_p with extra argument 1 + instead of cp_parser_next_token_starts_class_definition_p. + (cp_parser_next_token_starts_class_definition_p): Renamed to ... + (cp_parser_nth_token_starts_class_definition_p): ... this. Add N + argument. Use cp_lexer_peek_nth_token instead of cp_lexer_peek_token. + +2025-07-10 Jakub Jelinek <jakub@redhat.com> + + PR c++/120569 + * parser.cc (cp_parser_class_property_specifier_seq_opt): New + function. + (cp_parser_class_head): Use it instead of + cp_parser_property_specifier_seq_opt. Don't diagnose + VIRT_SPEC_OVERRIDE here. Formatting fix. + +2025-07-10 Jakub Jelinek <jakub@redhat.com> + + PR c++/117785 + * constexpr.cc: Implement C++26 P3068R5 - constexpr exceptions. + (class constexpr_global_ctx): Add caught_exceptions and + uncaught_exceptions members. + (constexpr_global_ctx::constexpr_global_ctx): Initialize + uncaught_exceptions. + (returns, breaks, continues, switches): Move earlier. + (throws): New function. + (exception_what_str, diagnose_std_terminate, + diagnose_uncaught_exception): New functions. + (enum cxa_builtin): New type. + (cxx_cxa_builtin_fn_p, cxx_eval_cxa_builtin_fn): New functions. + (cxx_eval_builtin_function_call): Add jump_target argument. Call + cxx_eval_cxa_builtin_fn for __builtin_eh_ptr_adjust_ref. Adjust + cxx_eval_constant_expression calls, if it results in jmp_target, + set *jump_target to it and return. + (cxx_bind_parameters_in_call): Add jump_target argument. Pass + it through to cxx_eval_constant_expression. If it sets *jump_target, + break. + (fold_operand): Adjust cxx_eval_constant_expression caller. + (cxx_eval_assert): Likewise. If it set jmp_target, return true. + (cxx_eval_internal_function): Add jump_target argument. Pass it + through to cxx_eval_constant_expression. Return early if *jump_target + after recursing on args. + (cxx_eval_dynamic_cast_fn): Likewise. Don't set reference_p for + C++26 with -fexceptions. + (cxx_eval_thunk_call): Add jump_target argument. Pass it through + to cxx_eval_constant_expression. + (cxx_set_object_constness): Likewise. Don't set TREE_READONLY if + throws (jump_target). + (cxx_eval_call_expression): Add jump_target argument. Pass it + through to cxx_eval_internal_function, cxx_eval_builtin_function_call, + cxx_eval_thunk_call, cxx_eval_dynamic_cast_fn and + cxx_set_object_constness. Pass it through also + cxx_eval_constant_expression on arguments, cxx_bind_parameters_in_call + and cxx_fold_indirect_ref and for those cases return early + if *jump_target. Call cxx_eval_cxa_builtin_fn for cxx_cxa_builtin_fn_p + functions. For cxx_eval_constant_expression on body, pass address of + cleared jmp_target automatic variable, if it throws propagate + to *jump_target and make it non-cacheable. For C++26 don't diagnose + calls to non-constexpr functions before cxx_bind_parameters_in_call + could report some argument throwing an exception. + (cxx_eval_unary_expression): Add jump_target argument. Pass it + through to cxx_eval_constant_expression and return early + if *jump_target after the call. + (cxx_fold_pointer_plus_expression): Likewise. + (cxx_eval_binary_expression): Likewise and similarly for + cxx_fold_pointer_plus_expression call. + (cxx_eval_conditional_expression): Pass jump_target to + cxx_eval_constant_expression on first operand and return early + if *jump_target after the call. + (cxx_eval_vector_conditional_expression): Add jump_target argument. + Pass it through to cxx_eval_constant_expression for all 3 arguments + and return early if *jump_target after any of those calls. + (get_array_or_vector_nelts): Add jump_target argument. Pass it + through to cxx_eval_constant_expression. + (eval_and_check_array_index): Add jump_target argument. Pass it + through to cxx_eval_constant_expression calls and return early after + each of them if *jump_target. + (cxx_eval_array_reference): Likewise. + (cxx_eval_component_reference): Likewise. + (cxx_eval_bit_field_ref): Likewise. + (cxx_eval_bit_cast): Likewise. Assert CHECKING_P call doesn't + throw or return. + (cxx_eval_logical_expression): Add jump_target argument. Pass it + through to cxx_eval_constant_expression calls and return early after + each of them if *jump_target. + (cxx_eval_bare_aggregate): Likewise. + (cxx_eval_vec_init_1): Add jump_target argument. Pass it through + to cxx_eval_bare_aggregate and recursive call. Pass it through + to get_array_or_vector_nelts and cxx_eval_constant_expression + and return early after it if *jump_target. + (cxx_eval_vec_init): Add jump_target argument. Pass it through + to cxx_eval_constant_expression and cxx_eval_vec_init_1. + (cxx_union_active_member): Add jump_target argument. Pass it + through to cxx_eval_constant_expression and return early after it + if *jump_target. + (cxx_fold_indirect_ref_1): Add jump_target argument. Pass it + through to cxx_union_active_member and recursive calls. + (cxx_eval_indirect_ref): Add jump_target argument. Pass it through + to cxx_fold_indirect_ref_1 calls and to recursive call, in which + case return early after it if *jump_target. + (cxx_fold_indirect_ref): Add jump_target argument. Pass it through + to cxx_fold_indirect_ref and cxx_eval_constant_expression calls and + return early after those if *jump_target. + (cxx_eval_trinary_expression): Add jump_target argument. Pass it + through to cxx_eval_constant_expression calls and return early after + those if *jump_target. + (cxx_eval_store_expression): Add jump_target argument. Pass it + through to cxx_eval_constant_expression and eval_and_check_array_index + calls and return early after those if *jump_target. + (cxx_eval_increment_expression): Add jump_target argument. Pass it + through to cxx_eval_constant_expression calls and return early after + those if *jump_target. + (label_matches): Handle VAR_DECL case. + (cxx_eval_statement_list): Remove local_target variable and + !jump_target handling. Handle throws (jump_target) like returns or + breaks. + (cxx_eval_loop_expr): Remove local_target variable and !jump_target + handling. Pass it through to cxx_eval_constant_expression. Handle + throws (jump_target) like returns. + (cxx_eval_switch_expr): Pass jump_target through to + cxx_eval_constant_expression on cond, return early after it + if *jump_target. + (build_new_constexpr_heap_type): Add jump_target argument. Pass it + through to cxx_eval_constant_expression calls, return early after + those if *jump_target. + (merge_jump_target): New function. + (cxx_eval_constant_expression): Make jump_target argument no longer + defaulted, don't test jump_target for NULL. Pass jump_target + through to recursive calls, cxx_eval_call_expression, + cxx_eval_store_expression, cxx_eval_indirect_ref, + cxx_eval_unary_expression, cxx_eval_binary_expression, + cxx_eval_logical_expression, cxx_eval_array_reference, + cxx_eval_component_reference, cxx_eval_bit_field_ref, + cxx_eval_vector_conditional_expression, cxx_eval_bare_aggregate, + cxx_eval_vec_init, cxx_eval_trinary_expression, cxx_fold_indirect_ref, + build_new_constexpr_heap_type, cxx_eval_increment_expression, + cxx_eval_bit_cast and return earlyu after some of those + if *jump_target as needed. + (cxx_eval_constant_expression) <case TARGET_EXPR>: For C++26 push + also CLEANUP_EH_ONLY cleanups, with NULL_TREE marker after them. + (cxx_eval_constant_expression) <case RETURN_EXPR>: Don't + override *jump_target if throws (jump_target). + (cxx_eval_constant_expression) <case TRY_CATCH_EXPR, case TRY_BLOCK, + case MUST_NOT_THROW_EXPR, case TRY_FINALLY_EXPR, case CLEANUP_STMT>: + Handle C++26 constant expressions. + (cxx_eval_constant_expression) <case CLEANUP_POINT_EXPR>: For C++26 + with throws (jump_target) evaluate the CLEANUP_EH_ONLY cleanups as + well, and if not throws (jump_target) skip those. Set *jump_target + if some of the cleanups threw. + (cxx_eval_constant_expression) <case THROW_EXPR>: Recurse on operand + for C++26. + (cxx_eval_outermost_constant_expr): Diagnose uncaught exceptions both + from main expression and cleanups, diagnose also + break/continue/returns from the main expression. Handle + CLEANUP_EH_ONLY cleanup markers. Don't diagnose mutable poison stuff + if non_constant_p. Use different diagnostics for non-deleted heap + allocations if they were allocated by __cxa_allocate_exception. + (callee_might_throw): New function. + (struct check_for_return_continue_data): Add could_throw field. + (check_for_return_continue): Handle AGGR_INIT_EXPR and CALL_EXPR and + set d->could_throw if they could throw. + (potential_constant_expression_1): For CALL_EXPR allow + cxx_dynamic_cast_fn_p calls. For C++26 set *jump_target to void_node + for calls that could throw. For C++26 if call to non-constexpr call + is seen, try to evaluate arguments first and if they could throw, + don't diagnose call to non-constexpr function nor return false. + Adjust check_for_return_continue_data initializers and + set *jump_target to void_node if data.could_throw_p. For C++26 + recurse on THROW_EXPR argument. Add comment explaining TRY_BLOCK + handling with C++26 exceptions. Handle throws like returns in some + cases. + * cp-tree.h (MUST_NOT_THROW_NOEXCEPT_P, MUST_NOT_THROW_THROW_P, + MUST_NOT_THROW_CATCH_P, DECL_EXCEPTION_REFCOUNT): Define. + (DECL_LOCAL_DECL_P): Fix comment typo, VARIABLE_DECL -> VAR_DECL. + (enum cp_built_in_function): Add CP_BUILT_IN_EH_PTR_ADJUST_REF, + (handler_match_for_exception_type): Declare. + * call.cc (handler_match_for_exception_type): New function. + * except.cc (initialize_handler_parm): Set MUST_NOT_THROW_CATCH_P + on newly created MUST_NOT_THROW_EXPR. + (begin_eh_spec_block): Set MUST_NOT_THROW_NOEXCEPT_P. + (wrap_cleanups_r): Set MUST_NOT_THROW_THROW_P. + (build_throw): Add another TARGET_EXPR whose scope spans + until after the __cxa_throw call and copy pointer value from ptr + to it and use it in __cxa_throw argument. + * tree.cc (builtin_valid_in_constant_expr_p): Handle + CP_BUILT_IN_EH_PTR_ADJUST_REF. + * decl.cc (cxx_init_decl_processing): Initialize + __builtin_eh_ptr_adjust_ref FE builtin. + * pt.cc (tsubst_stmt) <case MUST_NOT_THROW_EXPR>: Copy the + MUST_NOT_THROW_NOEXCEPT_P, MUST_NOT_THROW_THROW_P and + MUST_NOT_THROW_CATCH_P flags. + * cp-gimplify.cc (cp_gimplify_expr) <case CALL_EXPR>: Error on + non-folded CP_BUILT_IN_EH_PTR_ADJUST_REF calls. + 2025-07-09 Jason Merrill <jason@redhat.com> PR c++/121012 diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 2c3ef3d..2629625 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -1723,6 +1723,56 @@ involves_qualification_conversion_p (tree to, tree from) return false; } +/* Return true if HANDLER is a match for exception object with EXCEPT_TYPE as + per [except.handle]/3. */ + +bool +handler_match_for_exception_type (tree handler, tree except_type) +{ + tree handler_type = HANDLER_TYPE (handler); + if (handler_type == NULL_TREE) + return true; /* ... */ + if (same_type_ignoring_top_level_qualifiers_p (handler_type, except_type)) + return true; + if (CLASS_TYPE_P (except_type) && CLASS_TYPE_P (handler_type)) + { + base_kind b_kind; + tree binfo = lookup_base (except_type, handler_type, ba_check, &b_kind, + tf_none); + if (binfo && binfo != error_mark_node) + return true; + } + if (TYPE_PTR_P (handler_type) || TYPE_PTRDATAMEM_P (handler_type)) + { + if (TREE_CODE (except_type) == NULLPTR_TYPE) + return true; + if ((TYPE_PTR_P (handler_type) && TYPE_PTR_P (except_type)) + || (TYPE_PTRDATAMEM_P (handler_type) + && TYPE_PTRDATAMEM_P (except_type))) + { + conversion *conv + = standard_conversion (handler_type, except_type, NULL_TREE, + /*c_cast_p=*/false, 0, tf_none); + if (conv && !conv->bad_p) + { + for (conversion *t = conv; t; t = next_conversion (t)) + switch (t->kind) + { + case ck_ptr: + case ck_fnptr: + case ck_qual: + case ck_identity: + break; + default: + return false; + } + return true; + } + } + } + return false; +} + /* A reference of the indicated TYPE is being bound directly to the expression represented by the implicit conversion sequence CONV. Return a conversion sequence for this binding. */ diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc index 9a41c00..151ee2b 100644 --- a/gcc/cp/class.cc +++ b/gcc/cp/class.cc @@ -7452,7 +7452,7 @@ determine_key_method (tree type) && ! DECL_DECLARED_INLINE_P (method) && ! DECL_PURE_VIRTUAL_P (method)) { - CLASSTYPE_KEY_METHOD (type) = method; + SET_CLASSTYPE_KEY_METHOD (type, method); break; } diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index f9066bc..eb19784 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -1184,6 +1184,10 @@ public: /* Heap VAR_DECLs created during the evaluation of the outermost constant expression. */ auto_vec<tree, 16> heap_vars; + /* Vector of caught exceptions, including exceptions still not active at + the start of a handler (those are immediately followed up by HANDLER_TYPE + until __cxa_begin_catch finishes). */ + auto_vec<tree, 2> caught_exceptions; /* Cleanups that need to be evaluated at the end of CLEANUP_POINT_EXPR. */ vec<tree> *cleanups; /* If non-null, only allow modification of existing values of the variables @@ -1191,10 +1195,13 @@ public: hash_set<tree> *modifiable; /* Number of heap VAR_DECL deallocations. */ unsigned heap_dealloc_count; + /* Number of uncaught exceptions. */ + unsigned uncaught_exceptions; + /* Constructor. */ constexpr_global_ctx () : constexpr_ops_count (0), cleanups (NULL), modifiable (nullptr), - heap_dealloc_count (0) {} + heap_dealloc_count (0), uncaught_exceptions (0) {} bool is_outside_lifetime (tree t) { @@ -1308,6 +1315,48 @@ struct constexpr_ctx { mce_value manifestly_const_eval; }; +/* Predicates for the meaning of *jump_target. */ + +static bool +returns (tree *jump_target) +{ + return *jump_target && TREE_CODE (*jump_target) == RETURN_EXPR; +} + +static bool +breaks (tree *jump_target) +{ + return (*jump_target + && ((TREE_CODE (*jump_target) == LABEL_DECL + && LABEL_DECL_BREAK (*jump_target)) + || TREE_CODE (*jump_target) == BREAK_STMT + || TREE_CODE (*jump_target) == EXIT_EXPR)); +} + +static bool +continues (tree *jump_target) +{ + return (*jump_target + && ((TREE_CODE (*jump_target) == LABEL_DECL + && LABEL_DECL_CONTINUE (*jump_target)) + || TREE_CODE (*jump_target) == CONTINUE_STMT)); +} + +static bool +switches (tree *jump_target) +{ + return *jump_target && TREE_CODE (*jump_target) == INTEGER_CST; +} + +static bool +throws (tree *jump_target) +{ + /* void_node is for use in potential_constant_expression_1, otherwise + it should an artificial VAR_DECL created by constant evaluation + of __cxa_allocate_exception (). */ + return (*jump_target && (VAR_P (*jump_target) || *jump_target == void_node)); +} + /* True if the constexpr relaxations afforded by P2280R4 for unknown references and objects are in effect. */ @@ -1543,13 +1592,672 @@ enum value_cat { }; static tree cxx_eval_constant_expression (const constexpr_ctx *, tree, - value_cat, bool *, bool *, tree * = NULL); + value_cat, bool *, bool *, tree *); static tree cxx_eval_bare_aggregate (const constexpr_ctx *, tree, - value_cat, bool *, bool *); + value_cat, bool *, bool *, tree *); static tree cxx_fold_indirect_ref (const constexpr_ctx *, location_t, tree, tree, - bool * = NULL); + bool *, tree *); static tree find_heap_var_refs (tree *, int *, void *); +/* For exception object EXC if it has class type and usable what () method + which returns cv char * return the xmalloced string literal which it returns + if possible, otherwise return NULL. */ + +static char * +exception_what_str (const constexpr_ctx *ctx, tree exc) +{ + tree type = strip_array_types (TREE_TYPE (exc)); + if (!CLASS_TYPE_P (type)) + return NULL; + tree std_exception = lookup_qualified_name (std_node, "exception", + LOOK_want::NORMAL, false); + if (TREE_CODE (std_exception) != TYPE_DECL) + return NULL; + if (!CLASS_TYPE_P (TREE_TYPE (std_exception))) + return NULL; + base_kind b_kind; + tree binfo = lookup_base (type, TREE_TYPE (std_exception), ba_check, &b_kind, + tf_none); + if (binfo == NULL_TREE || binfo == error_mark_node) + return NULL; + if (type != TREE_TYPE (exc)) + exc = build4 (ARRAY_REF, type, exc, size_zero_node, NULL, NULL); + tree call + = finish_class_member_access_expr (exc, get_identifier ("what"), false, + tf_none); + if (call == error_mark_node) + return NULL; + releasing_vec what_args; + call = finish_call_expr (call, &what_args, false, false, tf_none); + if (call == error_mark_node) + return NULL; + if (TREE_CODE (TREE_TYPE (call)) != POINTER_TYPE + || !INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (call))) + || !COMPLETE_TYPE_P (TREE_TYPE (TREE_TYPE (call))) + || !tree_int_cst_equal (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (call))), + TYPE_SIZE_UNIT (char_type_node)) + || TYPE_PRECISION (TREE_TYPE (TREE_TYPE (call))) != BITS_PER_UNIT) + return NULL; + if (!potential_constant_expression (call)) + return NULL; + bool non_constant_p = false, overflow_p = false; + tree jmp_target = NULL; + tree ptr = cxx_eval_constant_expression (ctx, call, vc_prvalue, + &non_constant_p, &overflow_p, + &jmp_target); + if (throws (&jmp_target) || non_constant_p) + return NULL; + if (reduced_constant_expression_p (ptr)) + if (const char *msg = c_getstr (ptr)) + return xstrdup (msg); + auto_vec <char, 32> v; + for (unsigned i = 0; i < INT_MAX; ++i) + { + tree t = call; + if (i) + t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (ptr), ptr, size_int (i)); + t = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (t)), t); + non_constant_p = false; + overflow_p = false; + jmp_target = NULL; + tree t2 = cxx_eval_constant_expression (ctx, t, vc_prvalue, + &non_constant_p, &overflow_p, + &jmp_target); + if (throws (&jmp_target) + || non_constant_p + || !tree_fits_shwi_p (t2)) + return NULL; + char c = tree_to_shwi (t2); + v.safe_push (c); + if (c == '\0') + break; + } + return xstrdup (v.address ()); +} + +/* Diagnose constant expression evaluation encountering call to + std::terminate due to exception EXC. */ + +static void +diagnose_std_terminate (location_t loc, const constexpr_ctx *ctx, tree exc) +{ + tree type = strip_array_types (TREE_TYPE (exc)); + if (char *str = exception_what_str (ctx, exc)) + { + error_at (loc, "%qs called after throwing an exception of type %qT; " + "%<what()%>: %qs", "std::terminate", type, str); + free (str); + } + else + { + if (type != TREE_TYPE (exc)) + exc = build4 (ARRAY_REF, type, exc, size_zero_node, NULL, NULL); + bool non_constant_p = false, overflow_p = false; + tree jmp_target = NULL; + tree val = cxx_eval_constant_expression (ctx, exc, vc_prvalue, + &non_constant_p, &overflow_p, + &jmp_target); + gcc_assert (!throws (&jmp_target) && !non_constant_p); + if (reduced_constant_expression_p (val)) + error_at (loc, "%qs called after throwing an exception %qE", + "std::terminate", val); + else + error_at (loc, "%qs called after throwing an exception of type %qT", + "std::terminate", type); + } +} + +/* Diagnose constant expression evaluation encountering call to + uncaught exception EXC. */ + +static void +diagnose_uncaught_exception (location_t loc, const constexpr_ctx *ctx, tree exc) +{ + tree type = strip_array_types (TREE_TYPE (exc)); + if (char *str = exception_what_str (ctx, exc)) + { + error_at (loc, "uncaught exception of type %qT; %<what()%>: %qs", type, str); + free (str); + } + else + { + if (type != TREE_TYPE (exc)) + exc = build4 (ARRAY_REF, type, exc, size_zero_node, NULL, NULL); + bool non_constant_p = false, overflow_p = false; + tree jmp_target = NULL; + tree val = cxx_eval_constant_expression (ctx, exc, vc_prvalue, + &non_constant_p, &overflow_p, + &jmp_target); + gcc_assert (!throws (&jmp_target) && !non_constant_p); + if (reduced_constant_expression_p (val)) + error_at (loc, "uncaught exception %qE", val); + else + error_at (loc, "uncaught exception of type %qT", type); + } +} + +/* Kinds of __cxa_* functions (and a few other EH related ones) we handle as + magic constexpr functions for C++26. */ + +enum cxa_builtin { + CXA_NONE = 0, + CXA_ALLOCATE_EXCEPTION = 1, + CXA_FREE_EXCEPTION = 2, + CXA_THROW = 3, + CXA_BEGIN_CATCH = 4, + CXA_END_CATCH = 5, + CXA_RETHROW = 6, + CXA_GET_EXCEPTION_PTR = 7, + CXA_BAD_CAST = 8, + CXA_BAD_TYPEID = 9, + CXA_THROW_BAD_ARRAY_NEW_LENGTH = 10, + STD_UNCAUGHT_EXCEPTIONS = 11, + STD_CURRENT_EXCEPTION = 12, + STD_RETHROW_EXCEPTION = 13, + BUILTIN_EH_PTR_ADJUST_REF = 14 +}; + +/* Return cxa_builtin if FNDECL is a __cxa_* function handled as + magic constexpr function for C++26. Return CXA_NONE otherwise. */ + +static enum cxa_builtin +cxx_cxa_builtin_fn_p (tree fndecl) +{ + if (cxx_dialect < cxx26) + return CXA_NONE; + if (DECL_LANGUAGE (fndecl) != lang_c) + { + if (!decl_in_std_namespace_p (fndecl)) + return CXA_NONE; + if (id_equal (DECL_NAME (fndecl), "uncaught_exceptions")) + return STD_UNCAUGHT_EXCEPTIONS; + if (id_equal (DECL_NAME (fndecl), "current_exception")) + return STD_CURRENT_EXCEPTION; + if (id_equal (DECL_NAME (fndecl), "rethrow_exception")) + return STD_RETHROW_EXCEPTION; + return CXA_NONE; + } + if (!startswith (IDENTIFIER_POINTER (DECL_NAME (fndecl)), "__cxa_")) + return CXA_NONE; + if (id_equal (DECL_NAME (fndecl), "__cxa_allocate_exception")) + return CXA_ALLOCATE_EXCEPTION; + if (id_equal (DECL_NAME (fndecl), "__cxa_free_exception")) + return CXA_FREE_EXCEPTION; + if (id_equal (DECL_NAME (fndecl), "__cxa_throw")) + return CXA_THROW; + if (id_equal (DECL_NAME (fndecl), "__cxa_begin_catch")) + return CXA_BEGIN_CATCH; + if (id_equal (DECL_NAME (fndecl), "__cxa_end_catch")) + return CXA_END_CATCH; + if (id_equal (DECL_NAME (fndecl), "__cxa_rethrow")) + return CXA_RETHROW; + if (id_equal (DECL_NAME (fndecl), "__cxa_get_exception_ptr")) + return CXA_GET_EXCEPTION_PTR; + if (id_equal (DECL_NAME (fndecl), "__cxa_bad_cast")) + return CXA_BAD_CAST; + if (id_equal (DECL_NAME (fndecl), "__cxa_bad_typeid")) + return CXA_BAD_TYPEID; + if (id_equal (DECL_NAME (fndecl), "__cxa_throw_bad_array_new_length")) + return CXA_THROW_BAD_ARRAY_NEW_LENGTH; + return CXA_NONE; +} + +/* Helper function for cxx_eval_cxa_builtin_fn. + Check if ARG is a valid first argument of __cxa_throw or + __cxa_free_exception or __builtin_eh_ptr_adjust_ref. Return NULL_TREE if + not, otherwise return the artificial __cxa_allocate_exception allocated + VAR_DECL. FREE_EXC is true for __cxa_free_exception, false otherwise. */ + +static tree +cxa_check_throw_arg (tree arg, bool free_exc) +{ + STRIP_NOPS (arg); + if (TREE_CODE (arg) != ADDR_EXPR) + return NULL_TREE; + arg = TREE_OPERAND (arg, 0); + if (!VAR_P (arg) + || !DECL_ARTIFICIAL (arg) + || ((!free_exc || DECL_NAME (arg) != heap_uninit_identifier) + && DECL_NAME (arg) != heap_identifier) + || !DECL_LANG_SPECIFIC (arg)) + return NULL_TREE; + return arg; +} + +/* Helper function for cxx_eval_cxa_builtin_fn. + "Allocate" on the constexpr heap an exception object of TYPE + with REFCOUNT. */ + +static tree +cxa_allocate_exception (location_t loc, const constexpr_ctx *ctx, tree type, + tree refcount) +{ + tree var = build_decl (loc, VAR_DECL, heap_uninit_identifier, type); + DECL_ARTIFICIAL (var) = 1; + retrofit_lang_decl (var); + DECL_EXCEPTION_REFCOUNT (var) = refcount; + ctx->global->heap_vars.safe_push (var); + return var; +} + +/* Evaluate various __cxa_* calls as magic constexpr builtins for + C++26 constexpr exception support (P3068R5). */ + +static tree +cxx_eval_cxa_builtin_fn (const constexpr_ctx *ctx, tree call, + enum cxa_builtin kind, tree fndecl, + bool *non_constant_p, bool *overflow_p, + tree *jump_target) +{ + int nargs = call_expr_nargs (call); + location_t loc = cp_expr_loc_or_input_loc (call); + tree args[4], arg; + if (nargs > 4) + { + invalid_nargs: + if (!ctx->quiet) + error_at (loc, "call to %qD function with incorrect" + "number of arguments", fndecl); + *non_constant_p = true; + return call; + } + if ((kind == CXA_BEGIN_CATCH || kind == CXA_GET_EXCEPTION_PTR) + && nargs == 1 + && (arg = CALL_EXPR_ARG (call, 0)) + && TREE_CODE (arg) == CALL_EXPR + && call_expr_nargs (arg) == 1 + && integer_zerop (CALL_EXPR_ARG (arg, 0))) + if (tree fun = get_function_named_in_call (arg)) + if (fndecl_built_in_p (fun, BUILT_IN_EH_POINTER)) + { + if (ctx->global->caught_exceptions.length () < 2) + { + no_caught_exceptions: + if (!ctx->quiet) + error_at (loc, "%qD called with no caught exceptions pending", + fndecl); + *non_constant_p = true; + return call; + } + /* Both __cxa_get_exception_ptr (__builtin_eh_pointer (0)) + and __cxa_begin_catch (__builtin_eh_pointer (0)) calls expect + ctx->global->caught_exceptions vector to end with + __cxa_allocate_exception created artificial VAR_DECL (the + exception object) followed by handler type, pushed by TRY_BLOCK + evaluation. The only difference between the functions is that + __cxa_begin_catch pops the handler type from the vector and keeps + the VAR_DECL last and decreases uncaught_exceptions. The + VAR_DECL after __cxa_begin_catch serves as the current exception + and is then popped in __cxa_end_catch evaluation. */ + tree handler_type = ctx->global->caught_exceptions.last (); + if (handler_type && VAR_P (handler_type)) + goto no_caught_exceptions; + unsigned idx = ctx->global->caught_exceptions.length () - 2; + arg = ctx->global->caught_exceptions[idx]; + gcc_assert (VAR_P (arg)); + if (kind == CXA_BEGIN_CATCH) + { + ctx->global->caught_exceptions.pop (); + --ctx->global->uncaught_exceptions; + } + if (handler_type == NULL_TREE) + /* Used for catch (...). Just return void. */ + return void_node; + else if (POINTER_TYPE_P (handler_type)) + { + /* Used for catch of a pointer. */ + if (TREE_CODE (TREE_TYPE (arg)) == ARRAY_TYPE) + arg = build4 (ARRAY_REF, TREE_TYPE (TREE_TYPE (arg)), arg, + size_zero_node, NULL_TREE, NULL_TREE); + arg = cp_convert (handler_type, arg, + ctx->quiet ? tf_none : tf_warning_or_error); + if (arg == error_mark_node) + { + *non_constant_p = true; + return call; + } + } + else + { + /* Used for catch of a non-pointer type. */ + tree exc_type = strip_array_types (TREE_TYPE (arg)); + tree exc_ptr_type = build_pointer_type (exc_type); + arg = build_fold_addr_expr_with_type (arg, exc_ptr_type); + if (CLASS_TYPE_P (handler_type)) + { + tree ptr_type = build_pointer_type (handler_type); + arg = cp_convert (ptr_type, arg, + ctx->quiet ? tf_none + : tf_warning_or_error); + if (arg == error_mark_node) + { + *non_constant_p = true; + return call; + } + } + } + return cxx_eval_constant_expression (ctx, arg, vc_prvalue, + non_constant_p, overflow_p, + jump_target); + } + for (int i = 0; i < nargs; ++i) + { + args[i] = cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (call, i), + vc_prvalue, non_constant_p, + overflow_p, jump_target); + if (*non_constant_p) + return call; + if (*jump_target) + return NULL_TREE; + } + switch (kind) + { + case CXA_ALLOCATE_EXCEPTION: + if (nargs != 1) + goto invalid_nargs; + if (!tree_fits_uhwi_p (args[0])) + { + if (!ctx->quiet) + error_at (loc, "cannot allocate exception: size not constant"); + *non_constant_p = true; + return call; + } + else + { + tree type = build_array_type_nelts (char_type_node, + tree_to_uhwi (args[0])); + tree var = cxa_allocate_exception (loc, ctx, type, size_zero_node); + ctx->global->put_value (var, NULL_TREE); + return fold_convert (ptr_type_node, build_address (var)); + } + case CXA_FREE_EXCEPTION: + if (nargs != 1) + goto invalid_nargs; + arg = cxa_check_throw_arg (args[0], true); + if (arg == NULL_TREE) + { + invalid_ptr: + if (!ctx->quiet) + error_at (loc, "first argument to %qD function not result of " + "%<__cxa_allocate_exception%>", fndecl); + *non_constant_p = true; + return call; + } + DECL_NAME (arg) = heap_deleted_identifier; + ctx->global->destroy_value (arg); + ctx->global->heap_dealloc_count++; + return void_node; + case CXA_THROW: + if (nargs != 3) + goto invalid_nargs; + arg = cxa_check_throw_arg (args[0], false); + if (arg == NULL_TREE) + goto invalid_ptr; + DECL_EXCEPTION_REFCOUNT (arg) + = size_binop (PLUS_EXPR, DECL_EXCEPTION_REFCOUNT (arg), + size_one_node); + ++ctx->global->uncaught_exceptions; + *jump_target = arg; + return void_node; + case CXA_BEGIN_CATCH: + case CXA_GET_EXCEPTION_PTR: + goto invalid_nargs; + case CXA_END_CATCH: + if (nargs != 0) + goto invalid_nargs; + if (ctx->global->caught_exceptions.is_empty ()) + { + no_active_exc: + if (!ctx->quiet) + error_at (loc, "%qD called with no caught exceptions active", + fndecl); + *non_constant_p = true; + return call; + } + else + { + arg = ctx->global->caught_exceptions.pop (); + if (arg == NULL_TREE || !VAR_P (arg)) + goto no_active_exc; + free_except: + DECL_EXCEPTION_REFCOUNT (arg) + = size_binop (MINUS_EXPR, DECL_EXCEPTION_REFCOUNT (arg), + size_one_node); + if (integer_zerop (DECL_EXCEPTION_REFCOUNT (arg))) + { + if (type_build_dtor_call (TREE_TYPE (arg))) + { + tree cleanup + = cxx_maybe_build_cleanup (arg, (ctx->quiet ? tf_none + : tf_warning_or_error)); + if (cleanup == error_mark_node) + *non_constant_p = true; + tree jmp_target = NULL_TREE; + cxx_eval_constant_expression (ctx, cleanup, vc_discard, + non_constant_p, overflow_p, + &jmp_target); + if (throws (&jmp_target)) + *jump_target = jmp_target; + } + DECL_NAME (arg) = heap_deleted_identifier; + ctx->global->destroy_value (arg); + ctx->global->heap_dealloc_count++; + } + } + return void_node; + case CXA_RETHROW: + if (nargs != 0) + goto invalid_nargs; + unsigned idx; + FOR_EACH_VEC_ELT_REVERSE (ctx->global->caught_exceptions, idx, arg) + if (arg == NULL_TREE || !VAR_P (arg)) + --idx; + else + break; + if (arg == NULL_TREE) + { + if (!ctx->quiet) + error_at (loc, "%qD called with no caught exceptions active", + fndecl); + *non_constant_p = true; + return call; + } + DECL_EXCEPTION_REFCOUNT (arg) + = size_binop (PLUS_EXPR, DECL_EXCEPTION_REFCOUNT (arg), size_one_node); + ++ctx->global->uncaught_exceptions; + *jump_target = arg; + return void_node; + case CXA_BAD_CAST: + case CXA_BAD_TYPEID: + case CXA_THROW_BAD_ARRAY_NEW_LENGTH: + if (nargs != 0) + goto invalid_nargs; + else + { + tree name; + switch (kind) + { + case CXA_BAD_CAST: + name = get_identifier ("bad_cast"); + break; + case CXA_BAD_TYPEID: + name = get_identifier ("bad_typeid"); + break; + case CXA_THROW_BAD_ARRAY_NEW_LENGTH: + name = get_identifier ("bad_array_new_length"); + break; + default: + gcc_unreachable (); + } + tree decl = lookup_qualified_name (std_node, name); + if (TREE_CODE (decl) != TYPE_DECL + || !CLASS_TYPE_P (TREE_TYPE (decl)) + || !type_build_ctor_call (TREE_TYPE (decl))) + { + if (!ctx->quiet) + error_at (loc, "%qD called without %<std::%D%> being defined", + fndecl, name); + *non_constant_p = true; + return call; + } + tree type = TREE_TYPE (decl); + tree var = cxa_allocate_exception (loc, ctx, type, size_one_node); + tree ctor + = build_special_member_call (var, complete_ctor_identifier, + NULL, type, LOOKUP_NORMAL, + ctx->quiet ? tf_none + : tf_warning_or_error); + if (ctor == error_mark_node) + { + *non_constant_p = true; + return call; + } + if (TREE_CONSTANT (ctor)) + ctx->global->put_value (var, ctor); + else + { + ctx->global->put_value (var, NULL_TREE); + cxx_eval_constant_expression (ctx, ctor, vc_discard, + non_constant_p, overflow_p, + jump_target); + if (*non_constant_p) + return call; + if (throws (jump_target)) + return NULL_TREE; + } + ++ctx->global->uncaught_exceptions; + *jump_target = var; + } + return void_node; + case STD_UNCAUGHT_EXCEPTIONS: + if (nargs != 0) + goto invalid_nargs; + /* Similarly to __builtin_is_constant_evaluated (), we don't + want to give a definite answer during mce_unknown evaluation, + because that might prevent evaluation later on when some + exceptions might be uncaught. But unlike that, we don't + want to constant fold it even during cp_fold, because at runtime + std::uncaught_exceptions () might still be non-zero. */ + if (ctx->manifestly_const_eval != mce_true) + { + *non_constant_p = true; + return call; + } + return build_int_cst (integer_type_node, + ctx->global->uncaught_exceptions); + case STD_CURRENT_EXCEPTION: + if (nargs != 0) + goto invalid_nargs; + else + { + tree name = get_identifier ("exception_ptr"); + tree decl = lookup_qualified_name (std_node, name); + tree fld; + if (TREE_CODE (decl) != TYPE_DECL + || !CLASS_TYPE_P (TREE_TYPE (decl)) + || !COMPLETE_TYPE_P (TREE_TYPE (decl)) + || !(fld = next_aggregate_field (TYPE_FIELDS (TREE_TYPE (decl)))) + || DECL_ARTIFICIAL (fld) + || TREE_CODE (TREE_TYPE (fld)) != POINTER_TYPE + || next_aggregate_field (DECL_CHAIN (fld)) + || !tree_int_cst_equal (TYPE_SIZE (TREE_TYPE (decl)), + TYPE_SIZE (TREE_TYPE (fld)))) + { + if (!ctx->quiet) + error_at (loc, "%qD called without supportable %qs", + fndecl, "std::exception_ptr"); + *non_constant_p = true; + return call; + } + FOR_EACH_VEC_ELT_REVERSE (ctx->global->caught_exceptions, idx, arg) + if (arg == NULL_TREE || !VAR_P (arg)) + --idx; + else + break; + /* Similarly to __builtin_is_constant_evaluated (), we don't + want to give a definite answer during mce_unknown evaluation, + because that might prevent evaluation later on when some + exceptions might be current. But unlike that, we don't + want to constant fold it to null even during cp_fold, because + at runtime std::current_exception () might still be non-null. */ + if (ctx->manifestly_const_eval != mce_true && arg == NULL_TREE) + { + *non_constant_p = true; + return call; + } + if (arg == NULL_TREE) + arg = build_zero_cst (TREE_TYPE (fld)); + else + { + DECL_EXCEPTION_REFCOUNT (arg) + = size_binop (PLUS_EXPR, DECL_EXCEPTION_REFCOUNT (arg), + size_one_node); + arg = fold_convert (ptr_type_node, build_address (arg)); + } + return build_constructor_single (TREE_TYPE (decl), fld, arg); + } + case STD_RETHROW_EXCEPTION: + if (nargs != 1) + goto invalid_nargs; + if (TYPE_REF_P (TREE_TYPE (args[0]))) + { + arg = args[0]; + STRIP_NOPS (arg); + if (TREE_CODE (arg) == ADDR_EXPR) + { + args[0] + = cxx_eval_constant_expression (ctx, TREE_OPERAND (arg, 0), + vc_prvalue, non_constant_p, + overflow_p, jump_target); + if (*non_constant_p) + return call; + if (*jump_target) + return NULL_TREE; + } + } + if (TREE_CODE (args[0]) != CONSTRUCTOR + || CONSTRUCTOR_NELTS (args[0]) != 1) + { + invalid_std_rethrow: + if (!ctx->quiet) + error_at (loc, "%qD called with unexpected %qs argument", + fndecl, "std::exception_ptr"); + *non_constant_p = true; + return void_node; + } + arg = cxa_check_throw_arg (CONSTRUCTOR_ELT (args[0], 0)->value, false); + if (arg == NULL_TREE) + goto invalid_std_rethrow; + DECL_EXCEPTION_REFCOUNT (arg) + = size_binop (PLUS_EXPR, DECL_EXCEPTION_REFCOUNT (arg), size_one_node); + ++ctx->global->uncaught_exceptions; + *jump_target = arg; + return void_node; + case BUILTIN_EH_PTR_ADJUST_REF: + if (nargs != 2) + goto invalid_nargs; + arg = cxa_check_throw_arg (args[0], false); + if (arg == NULL_TREE) + goto invalid_ptr; + if (integer_onep (args[1])) + DECL_EXCEPTION_REFCOUNT (arg) + = size_binop (PLUS_EXPR, DECL_EXCEPTION_REFCOUNT (arg), + size_one_node); + else if (integer_minus_onep (args[1])) + goto free_except; + else + { + if (!ctx->quiet) + error_at (loc, "%qD called with second argument " + "other than 1 or -1", fndecl); + *non_constant_p = true; + } + return void_node; + default: + gcc_unreachable (); + } +} + /* Attempt to evaluate T which represents a call to a builtin function. We assume here that all builtin functions evaluate to scalar types represented by _CST nodes. */ @@ -1557,7 +2265,8 @@ static tree find_heap_var_refs (tree *, int *, void *); static tree cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun, value_cat lval, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { const int nargs = call_expr_nargs (t); tree *args = (tree *) alloca (nargs * sizeof (tree)); @@ -1603,6 +2312,12 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun, return fold_builtin_source_location (t); } + if (fndecl_built_in_p (fun, CP_BUILT_IN_EH_PTR_ADJUST_REF, + BUILT_IN_FRONTEND)) + return cxx_eval_cxa_builtin_fn (ctx, t, BUILTIN_EH_PTR_ADJUST_REF, + fun, non_constant_p, overflow_p, + jump_target); + int strops = 0; int strret = 0; if (fndecl_built_in_p (fun, BUILT_IN_NORMAL)) @@ -1677,8 +2392,14 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun, || potential_constant_expression (arg)) { bool dummy1 = false, dummy2 = false; + tree jmp_target = NULL_TREE; arg = cxx_eval_constant_expression (&new_ctx, arg, vc_prvalue, - &dummy1, &dummy2); + &dummy1, &dummy2, &jmp_target); + if (jmp_target) + { + *jump_target = jmp_target; + return NULL_TREE; + } } if (bi_const_p) @@ -1767,7 +2488,8 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun, } return cxx_eval_constant_expression (&new_ctx, new_call, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); } /* TEMP is the constant value of a temporary object of type TYPE. Adjust @@ -1882,7 +2604,8 @@ addr_of_non_const_var (tree *tp, int *walk_subtrees, void *data) static tree cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t, tree fun, tree orig_fun, bool *non_constant_p, - bool *overflow_p, bool *non_constant_args) + bool *overflow_p, bool *non_constant_args, + tree *jump_target) { int nargs = call_expr_nargs (t); tree parms = DECL_ARGUMENTS (fun); @@ -1958,14 +2681,16 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t, tree fun, /* Undo convert_for_arg_passing work here. */ x = convert_from_reference (x); arg = cxx_eval_constant_expression (ctx, x, vc_glvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); } else /* Normally we would strip a TARGET_EXPR in an initialization context such as this, but here we do the elision differently: we keep the TARGET_EXPR, and use its CONSTRUCTOR as the value of the parm. */ arg = cxx_eval_constant_expression (ctx, x, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); /* Check we aren't dereferencing a null pointer when calling a non-static member function, which is undefined behaviour. */ if (i == 0 && DECL_OBJECT_MEMBER_FUNCTION_P (fun) @@ -1983,6 +2708,8 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t, tree fun, /* Don't VERIFY_CONSTANT here. */ if (*non_constant_p && ctx->quiet) break; + if (*jump_target) + break; /* Just discard ellipsis args after checking their constantitude. */ if (!parms) continue; @@ -2094,9 +2821,10 @@ fold_operand (tree e, const constexpr_ctx *ctx) if (ctx) { bool new_non_constant_p = false, new_overflow_p = false; + tree jmp_target = NULL_TREE; e = cxx_eval_constant_expression (ctx, e, vc_prvalue, &new_non_constant_p, - &new_overflow_p); + &new_overflow_p, &jmp_target); } else e = fold_non_dependent_expr (e, tf_none, /*manifestly_const_eval=*/true); @@ -2183,7 +2911,7 @@ cxx_eval_assert (const constexpr_ctx *ctx, tree arg, const char *msg, if (*non_constant_p) return true; - tree eval; + tree eval, jmp_target = NULL_TREE; if (!evaluated) { if (!potential_rvalue_constant_expression (arg)) @@ -2196,12 +2924,15 @@ cxx_eval_assert (const constexpr_ctx *ctx, tree arg, const char *msg, modifiable_tracker ms (new_ctx.global); eval = cxx_eval_constant_expression (&new_ctx, arg, vc_prvalue, &new_non_constant_p, - &new_overflow_p); + &new_overflow_p, &jmp_target); } else eval = cxx_eval_constant_expression (ctx, arg, vc_prvalue, non_constant_p, - overflow_p); + overflow_p, &jmp_target); + if (jmp_target) + return true; + if (!*non_constant_p && integer_zerop (eval)) { if (!ctx->quiet) @@ -2233,7 +2964,8 @@ cxx_eval_assert (const constexpr_ctx *ctx, tree arg, const char *msg, static tree cxx_eval_internal_function (const constexpr_ctx *ctx, tree t, value_cat lval, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { enum tree_code opcode = ERROR_MARK; @@ -2266,13 +2998,15 @@ cxx_eval_internal_function (const constexpr_ctx *ctx, tree t, case IFN_LAUNDER: return cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, 0), vc_prvalue, non_constant_p, - overflow_p); + overflow_p, jump_target); case IFN_VEC_CONVERT: { tree arg = cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, 0), vc_prvalue, non_constant_p, - overflow_p); + overflow_p, jump_target); + if (*jump_target) + return NULL_TREE; if (TREE_CODE (arg) == VECTOR_CST) if (tree r = fold_const_call (CFN_VEC_CONVERT, TREE_TYPE (t), arg)) return r; @@ -2290,10 +3024,13 @@ cxx_eval_internal_function (const constexpr_ctx *ctx, tree t, /* Evaluate constant arguments using OPCODE and return a complex number containing the result and the overflow bit. */ tree arg0 = cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, 0), lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); tree arg1 = cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, 1), lval, - non_constant_p, overflow_p); - + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST) { location_t loc = cp_expr_loc_or_input_loc (t); @@ -2566,7 +3303,8 @@ get_component_with_type (tree path, tree type, tree stop) static tree cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { /* T will be something like __dynamic_cast ((B*) b, &_ZTI1B, &_ZTI1D, 8) @@ -2585,19 +3323,26 @@ cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call, /* TYPE can only be either T* or T&. We can't know which of these it is by looking at TYPE, but OBJ will be "(T*) x" in the first case, - and something like "(T*)(T&)(T*) x" in the second case. */ - bool reference_p = false; + and something like "(T*)(T&)(T*) x" in the second case. + This is true for the reference cases in C++ < 26 or when exceptions + aren't enabled, in that case we should diagnose errors. For C++26 + with exceptions we should silently evaluate to null pointer and + let the callers call __cxa_bad_cast () later to throw an exception. */ + bool fail_for_non_constant_p = false; while (CONVERT_EXPR_P (obj) || TREE_CODE (obj) == SAVE_EXPR) { - reference_p |= TYPE_REF_P (TREE_TYPE (obj)); + if (cxx_dialect < cxx26 || !flag_exceptions) + fail_for_non_constant_p |= TYPE_REF_P (TREE_TYPE (obj)); obj = TREE_OPERAND (obj, 0); } /* Evaluate the object so that we know its dynamic type. */ obj = cxx_eval_constant_expression (ctx, obj, vc_prvalue, non_constant_p, - overflow_p); + overflow_p, jump_target); if (*non_constant_p) return call; + if (*jump_target) + return NULL_TREE; /* For dynamic_cast from classes with virtual bases we can get something like (virt_base *)(&d + 16) as OBJ. Try to convert that into @@ -2609,7 +3354,7 @@ cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call, if (TREE_CODE (objo) == POINTER_PLUS_EXPR) { objo = cxx_fold_indirect_ref (ctx, loc, TREE_TYPE (TREE_TYPE (obj)), - obj); + obj, NULL, jump_target); if (objo) obj = build_fold_addr_expr (objo); } @@ -2625,7 +3370,7 @@ cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call, ? TREE_OPERAND (obj, 1) : obj)) if (TREE_CODE (t) != FIELD_DECL || !DECL_FIELD_IS_BASE (t)) { - if (reference_p) + if (fail_for_non_constant_p) { if (!ctx->quiet) { @@ -2647,9 +3392,12 @@ cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call, constructor or destructor's class. */ tree vtable = build_vfield_ref (obj, objtype); vtable = cxx_eval_constant_expression (ctx, vtable, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); if (*non_constant_p) return call; + if (*jump_target) + return NULL_TREE; /* With -fsanitize=vptr, we initialize all vtable pointers to null, so it's possible that we got a null pointer now. */ if (integer_zerop (vtable)) @@ -2681,7 +3429,7 @@ cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call, /* If not accessible, give an error. */ if (t == error_mark_node) { - if (reference_p) + if (fail_for_non_constant_p) { if (!ctx->quiet) { @@ -2714,7 +3462,7 @@ cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call, obj = get_component_with_type (obj, mdtype, NULL_TREE); if (obj == error_mark_node) { - if (reference_p) + if (fail_for_non_constant_p) { if (!ctx->quiet) { @@ -2736,7 +3484,7 @@ cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call, tree binfo = lookup_base (mdtype, type, ba_check, &b_kind, tf_none); if (!binfo || binfo == error_mark_node) { - if (reference_p) + if (fail_for_non_constant_p) { if (!ctx->quiet) { @@ -2832,7 +3580,7 @@ replace_decl (tree *tp, tree decl, tree replacement) static tree cxx_eval_thunk_call (const constexpr_ctx *ctx, tree t, tree thunk_fndecl, value_cat lval, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, tree *jump_target) { tree function = THUNK_TARGET (thunk_fndecl); @@ -2875,7 +3623,8 @@ cxx_eval_thunk_call (const constexpr_ctx *ctx, tree t, tree thunk_fndecl, new_call, offset); return cxx_eval_constant_expression (ctx, new_call, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); } /* If OBJECT is of const class type, evaluate it to a CONSTRUCTOR and set @@ -2885,7 +3634,7 @@ cxx_eval_thunk_call (const constexpr_ctx *ctx, tree t, tree thunk_fndecl, static void cxx_set_object_constness (const constexpr_ctx *ctx, tree object, bool readonly_p, bool *non_constant_p, - bool *overflow_p) + bool *overflow_p, tree *jump_target) { if (CLASS_TYPE_P (TREE_TYPE (object)) && CP_TYPE_CONST_P (TREE_TYPE (object))) @@ -2893,8 +3642,11 @@ cxx_set_object_constness (const constexpr_ctx *ctx, tree object, /* Subobjects might not be stored in ctx->global->values but we can get its CONSTRUCTOR by evaluating *this. */ tree e = cxx_eval_constant_expression (ctx, object, vc_prvalue, - non_constant_p, overflow_p); - if (TREE_CODE (e) == CONSTRUCTOR && !*non_constant_p) + non_constant_p, overflow_p, + jump_target); + if (!*non_constant_p + && !throws (jump_target) + && TREE_CODE (e) == CONSTRUCTOR) TREE_READONLY (e) = readonly_p; } } @@ -2906,20 +3658,25 @@ cxx_set_object_constness (const constexpr_ctx *ctx, tree object, static tree cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, value_cat lval, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { location_t loc = cp_expr_loc_or_input_loc (t); tree fun = get_function_named_in_call (t); if (fun == NULL_TREE) return cxx_eval_internal_function (ctx, t, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); if (TREE_CODE (fun) != FUNCTION_DECL) { /* Might be a constexpr function pointer. */ fun = cxx_eval_constant_expression (ctx, fun, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; STRIP_NOPS (fun); if (TREE_CODE (fun) == ADDR_EXPR) fun = TREE_OPERAND (fun, 0); @@ -2971,9 +3728,12 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, if (fndecl_built_in_p (fun)) return cxx_eval_builtin_function_call (ctx, t, fun, - lval, non_constant_p, overflow_p); + lval, non_constant_p, overflow_p, + jump_target); if (DECL_THUNK_P (fun)) - return cxx_eval_thunk_call (ctx, t, fun, lval, non_constant_p, overflow_p); + return cxx_eval_thunk_call (ctx, t, fun, lval, non_constant_p, overflow_p, + jump_target); + bool non_constexpr_call = false; if (!maybe_constexpr_fn (fun)) { if (TREE_CODE (t) == CALL_EXPR @@ -2988,7 +3748,10 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, { tree arg = CALL_EXPR_ARG (t, i); arg = cxx_eval_constant_expression (ctx, arg, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; /* Deleting a non-constant pointer has a better error message below. */ if (new_op_p || i != 0) @@ -3103,7 +3866,10 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, { tree arg = CALL_EXPR_ARG (t, i); arg = cxx_eval_constant_expression (ctx, arg, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; if (i == 1) arg1 = arg; else @@ -3113,16 +3879,31 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, return arg1; } else if (cxx_dynamic_cast_fn_p (fun)) - return cxx_eval_dynamic_cast_fn (ctx, t, non_constant_p, overflow_p); + return cxx_eval_dynamic_cast_fn (ctx, t, non_constant_p, overflow_p, + jump_target); + else if (enum cxa_builtin kind = cxx_cxa_builtin_fn_p (fun)) + return cxx_eval_cxa_builtin_fn (ctx, t, kind, fun, + non_constant_p, overflow_p, + jump_target); - if (!ctx->quiet) + /* Calls to non-constexpr functions can be diagnosed right away + before C++26, though in C++26 evaluation of the arguments might + throw and if caught it could be still constant expression. + So for C++26 this is diagnosed only after + cxx_bind_parameters_in_call. */ + if (cxx_dialect >= cxx26) + non_constexpr_call = true; + else { - if (!lambda_static_thunk_p (fun)) - error_at (loc, "call to non-%<constexpr%> function %qD", fun); - explain_invalid_constexpr_fn (fun); + if (!ctx->quiet) + { + if (!lambda_static_thunk_p (fun)) + error_at (loc, "call to non-%<constexpr%> function %qD", fun); + explain_invalid_constexpr_fn (fun); + } + *non_constant_p = true; + return t; } - *non_constant_p = true; - return t; } constexpr_ctx new_ctx = *ctx; @@ -3158,7 +3939,8 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, constexpr_call new_call; new_call.bindings = cxx_bind_parameters_in_call (ctx, t, fun, orig_fun, non_constant_p, - overflow_p, &non_constant_args); + overflow_p, &non_constant_args, + jump_target); /* We build up the bindings list before we know whether we already have this call cached. If we don't end up saving these bindings, ggc_free them when @@ -3172,8 +3954,21 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, void preserve () { bindings = NULL; } } fb (new_call.bindings); + if (*jump_target) + return NULL_TREE; if (*non_constant_p) return t; + if (non_constexpr_call) + { + if (!ctx->quiet) + { + if (!lambda_static_thunk_p (fun)) + error_at (loc, "call to non-%<constexpr%> function %qD", fun); + explain_invalid_constexpr_fn (fun); + } + *non_constant_p = true; + return t; + } /* We can't defer instantiating the function any longer. */ if (!DECL_INITIAL (fun) @@ -3246,7 +4041,9 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, new_obj = TREE_VEC_ELT (new_call.bindings, 0); bool empty_base = false; new_obj = cxx_fold_indirect_ref (ctx, loc, DECL_CONTEXT (fun), new_obj, - &empty_base); + &empty_base, jump_target); + if (*jump_target) + return NULL_TREE; /* If we're initializing an empty class, don't set constness, because cxx_fold_indirect_ref will return the wrong object to set constness of. */ @@ -3395,7 +4192,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, semantics are no longer in effect; see [class.dtor]p5. */ if (new_obj && DECL_DESTRUCTOR_P (fun)) cxx_set_object_constness (ctx, new_obj, /*readonly_p=*/false, - non_constant_p, overflow_p); + non_constant_p, overflow_p, jump_target); /* If this is a constructor, we are beginning the lifetime of the object we are initializing. */ @@ -3409,16 +4206,25 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, build_constructor (TREE_TYPE (new_obj), NULL)); cxx_eval_constant_expression (ctx, activate, - lval, non_constant_p, overflow_p); + lval, non_constant_p, overflow_p, + jump_target); ggc_free (activate); + if (*jump_target) + return NULL_TREE; } - tree jump_target = NULL_TREE; + tree jmp_target = NULL_TREE; cxx_eval_constant_expression (&call_ctx, body, vc_discard, non_constant_p, overflow_p, - &jump_target); + &jmp_target); - if (DECL_CONSTRUCTOR_P (fun)) + if (!*non_constant_p && throws (&jmp_target)) + { + result = NULL_TREE; + cacheable = false; + *jump_target = jmp_target; + } + else if (DECL_CONSTRUCTOR_P (fun)) /* This can be null for a subobject constructor call, in which case what we care about is the initialization side-effects rather than the value. We could get at the @@ -3446,7 +4252,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, marking the CONSTRUCTOR TREE_READONLY. */ if (new_obj && DECL_CONSTRUCTOR_P (fun)) cxx_set_object_constness (ctx, new_obj, /*readonly_p=*/true, - non_constant_p, overflow_p); + non_constant_p, overflow_p, jump_target); /* Remove the parms/result from the values map. */ destroy_value_checked (ctx, res, non_constant_p); @@ -3506,7 +4312,13 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, cacheable = false; result = cxx_eval_constant_expression (ctx, result, lval, non_constant_p, - overflow_p); + overflow_p, + jump_target); + if (*jump_target) + { + cacheable = false; + result = NULL_TREE; + } } } @@ -3864,12 +4676,16 @@ cxx_eval_check_shift_p (location_t loc, const constexpr_ctx *ctx, static tree cxx_eval_unary_expression (const constexpr_ctx *ctx, tree t, bool /*lval*/, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { tree r; tree orig_arg = TREE_OPERAND (t, 0); tree arg = cxx_eval_constant_expression (ctx, orig_arg, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; VERIFY_CONSTANT (arg); location_t loc = EXPR_LOCATION (t); enum tree_code code = TREE_CODE (t); @@ -3893,7 +4709,7 @@ cxx_eval_unary_expression (const constexpr_ctx *ctx, tree t, static tree cxx_fold_pointer_plus_expression (const constexpr_ctx *ctx, tree t, tree lhs, tree rhs, bool *non_constant_p, - bool *overflow_p) + bool *overflow_p, tree *jump_target) { STRIP_NOPS (lhs); if (TREE_CODE (lhs) != ADDR_EXPR) @@ -3915,9 +4731,12 @@ cxx_fold_pointer_plus_expression (const constexpr_ctx *ctx, tree t, t = fold_convert_loc (loc, ssizetype, TREE_OPERAND (lhs, 1)); tree nelts = array_type_nelts_top (TREE_TYPE (TREE_OPERAND (lhs, 0))); nelts = cxx_eval_constant_expression (ctx, nelts, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); if (*non_constant_p) return NULL_TREE; + if (*jump_target) + return NULL_TREE; /* Don't fold an out-of-bound access. */ if (!tree_int_cst_le (t, nelts)) return NULL_TREE; @@ -3937,7 +4756,8 @@ cxx_fold_pointer_plus_expression (const constexpr_ctx *ctx, tree t, t = cp_build_addr_expr (t, tf_warning_or_error); t = cp_fold_convert (orig_type, t); return cxx_eval_constant_expression (ctx, t, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); } return NULL_TREE; @@ -3981,22 +4801,29 @@ cxx_maybe_fold_addr_pointer_plus (tree t) static tree cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t, value_cat lval, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { tree r = NULL_TREE; tree orig_lhs = TREE_OPERAND (t, 0); tree orig_rhs = TREE_OPERAND (t, 1); tree lhs, rhs; lhs = cxx_eval_constant_expression (ctx, orig_lhs, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); /* Don't VERIFY_CONSTANT here, it's unnecessary and will break pointer subtraction. */ if (*non_constant_p) return t; + if (*jump_target) + return NULL_TREE; rhs = cxx_eval_constant_expression (ctx, orig_rhs, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); if (*non_constant_p) return t; + if (*jump_target) + return NULL_TREE; location_t loc = EXPR_LOCATION (t); enum tree_code code = TREE_CODE (t); @@ -4052,13 +4879,17 @@ cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t, return t; } else if (code == POINTER_PLUS_EXPR) - r = cxx_fold_pointer_plus_expression (ctx, t, lhs, rhs, non_constant_p, - overflow_p); + { + r = cxx_fold_pointer_plus_expression (ctx, t, lhs, rhs, non_constant_p, + overflow_p, jump_target); + if (*jump_target) + return NULL_TREE; + } else if (code == SPACESHIP_EXPR) { r = genericize_spaceship (loc, type, lhs, rhs); return cxx_eval_constant_expression (ctx, r, lval, non_constant_p, - overflow_p); + overflow_p, jump_target); } if (r == NULL_TREE) @@ -4117,7 +4948,10 @@ cxx_eval_conditional_expression (const constexpr_ctx *ctx, tree t, { tree val = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; VERIFY_CONSTANT (val); if (TREE_CODE (t) == IF_STMT && IF_STMT_CONSTEVAL_P (t)) { @@ -4178,19 +5012,29 @@ cxx_eval_conditional_expression (const constexpr_ctx *ctx, tree t, static tree cxx_eval_vector_conditional_expression (const constexpr_ctx *ctx, tree t, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { tree arg1 = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; VERIFY_CONSTANT (arg1); tree arg2 = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; VERIFY_CONSTANT (arg2); tree arg3 = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 2), vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; VERIFY_CONSTANT (arg3); location_t loc = EXPR_LOCATION (t); tree type = TREE_TYPE (t); @@ -4578,7 +5422,8 @@ diag_array_subscript (location_t loc, const constexpr_ctx *ctx, tree array, tree static tree get_array_or_vector_nelts (const constexpr_ctx *ctx, tree type, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { tree nelts; if (TREE_CODE (type) == ARRAY_TYPE) @@ -4595,7 +5440,8 @@ get_array_or_vector_nelts (const constexpr_ctx *ctx, tree type, /* For VLAs, the number of elements won't be an integer constant. */ nelts = cxx_eval_constant_expression (ctx, nelts, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); return nelts; } @@ -4626,13 +5472,17 @@ extract_string_elt (tree string, unsigned chars_per_elt, unsigned index) static tree eval_and_check_array_index (const constexpr_ctx *ctx, tree t, bool allow_one_past, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { location_t loc = cp_expr_loc_or_input_loc (t); tree ary = TREE_OPERAND (t, 0); t = TREE_OPERAND (t, 1); tree index = cxx_eval_constant_expression (ctx, t, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; VERIFY_CONSTANT (index); if (!tree_fits_shwi_p (index) @@ -4644,7 +5494,9 @@ eval_and_check_array_index (const constexpr_ctx *ctx, } tree nelts = get_array_or_vector_nelts (ctx, TREE_TYPE (ary), non_constant_p, - overflow_p); + overflow_p, jump_target); + if (*jump_target) + return NULL_TREE; VERIFY_CONSTANT (nelts); if (allow_one_past ? !tree_int_cst_le (index, nelts) @@ -4664,14 +5516,18 @@ eval_and_check_array_index (const constexpr_ctx *ctx, static tree cxx_eval_array_reference (const constexpr_ctx *ctx, tree t, value_cat lval, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { tree oldary = TREE_OPERAND (t, 0); tree ary = cxx_eval_constant_expression (ctx, oldary, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); if (*non_constant_p) return t; + if (*jump_target) + return NULL_TREE; if (!lval && TREE_CODE (ary) == VIEW_CONVERT_EXPR && VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (ary, 0))) @@ -4681,9 +5537,12 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t, tree oldidx = TREE_OPERAND (t, 1); tree index = eval_and_check_array_index (ctx, t, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); if (*non_constant_p) return t; + if (*jump_target) + return NULL_TREE; if (lval && ary == oldary && index == oldidx) return t; @@ -4801,7 +5660,7 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t, ctx = &new_ctx; } t = cxx_eval_constant_expression (ctx, val, lval, non_constant_p, - overflow_p); + overflow_p, jump_target); if (new_ctor && t != ctx->ctor) free_constructor (ctx->ctor); return t; @@ -4813,7 +5672,8 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t, static tree cxx_eval_component_reference (const constexpr_ctx *ctx, tree t, value_cat lval, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { unsigned HOST_WIDE_INT i; tree field; @@ -4822,9 +5682,12 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t, tree orig_whole = TREE_OPERAND (t, 0); tree whole = cxx_eval_constant_expression (ctx, orig_whole, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); if (*non_constant_p) return t; + if (*jump_target) + return NULL_TREE; if (INDIRECT_REF_P (whole) && integer_zerop (TREE_OPERAND (whole, 0))) { @@ -4933,7 +5796,8 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t, value = build_value_init (TREE_TYPE (t), tf_warning_or_error); return cxx_eval_constant_expression (ctx, value, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); } /* Subroutine of cxx_eval_constant_expression. @@ -4943,7 +5807,8 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t, static tree cxx_eval_bit_field_ref (const constexpr_ctx *ctx, tree t, value_cat lval, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { tree orig_whole = TREE_OPERAND (t, 0); tree retval, fldval, utype, mask; @@ -4951,10 +5816,13 @@ cxx_eval_bit_field_ref (const constexpr_ctx *ctx, tree t, HOST_WIDE_INT istart, isize; tree whole = cxx_eval_constant_expression (ctx, orig_whole, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); tree start, field, value; unsigned HOST_WIDE_INT i; + if (*jump_target) + return NULL_TREE; if (whole == orig_whole) return t; /* Don't VERIFY_CONSTANT here; we only want to check that we got a @@ -5235,7 +6103,7 @@ clear_uchar_or_std_byte_in_mask (location_t loc, tree t, unsigned char *mask) static tree cxx_eval_bit_cast (const constexpr_ctx *ctx, tree t, bool *non_constant_p, - bool *overflow_p) + bool *overflow_p, tree *jump_target) { if (check_bit_cast_type (ctx, EXPR_LOCATION (t), TREE_TYPE (t), TREE_TYPE (t)) @@ -5249,9 +6117,12 @@ cxx_eval_bit_cast (const constexpr_ctx *ctx, tree t, bool *non_constant_p, } tree op = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); if (*non_constant_p) return t; + if (*jump_target) + return NULL_TREE; location_t loc = EXPR_LOCATION (t); if (BITS_PER_UNIT != 8 || CHAR_BIT != 8) @@ -5329,8 +6200,9 @@ cxx_eval_bit_cast (const constexpr_ctx *ctx, tree t, bool *non_constant_p, if (CHECKING_P) { tree e = cxx_eval_bare_aggregate (ctx, r, vc_prvalue, - non_constant_p, overflow_p); - gcc_checking_assert (e == r); + non_constant_p, overflow_p, + jump_target); + gcc_checking_assert (e == r && !*jump_target); r = e; } } @@ -5371,19 +6243,24 @@ cxx_eval_bit_cast (const constexpr_ctx *ctx, tree t, bool *non_constant_p, static tree cxx_eval_logical_expression (const constexpr_ctx *ctx, tree t, tree bailout_value, tree continue_value, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { tree r; tree lhs = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), vc_prvalue, non_constant_p, - overflow_p); + overflow_p, jump_target); + if (*jump_target) + return NULL_TREE; VERIFY_CONSTANT (lhs); if (tree_int_cst_equal (lhs, bailout_value)) return lhs; gcc_assert (tree_int_cst_equal (lhs, continue_value)); r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), vc_prvalue, non_constant_p, - overflow_p); + overflow_p, jump_target); + if (*jump_target) + return NULL_TREE; VERIFY_CONSTANT (r); return r; } @@ -5540,7 +6417,8 @@ verify_ctor_sanity (const constexpr_ctx *ctx, tree type) static tree cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t, value_cat lval, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (t); bool changed = false; @@ -5593,7 +6471,10 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t, get_or_insert_ctor_field (ctx->ctor, index); tree elt = cxx_eval_constant_expression (&new_ctx, value, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; /* Don't VERIFY_CONSTANT here. */ if (ctx->quiet && *non_constant_p) break; @@ -5683,7 +6564,8 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t, static tree cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init, bool value_init, value_cat lval, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { tree elttype = TREE_TYPE (atype); verify_ctor_sanity (ctx, atype); @@ -5694,7 +6576,7 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init, if (init && TREE_CODE (init) == CONSTRUCTOR) return cxx_eval_bare_aggregate (ctx, init, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, jump_target); /* For the default constructor, build up a call to the default constructor of the element type. We only need to handle class types @@ -5731,7 +6613,9 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init, } tree nelts = get_array_or_vector_nelts (ctx, atype, non_constant_p, - overflow_p); + overflow_p, jump_target); + if (*jump_target) + return NULL_TREE; unsigned HOST_WIDE_INT max = tree_to_uhwi (nelts); for (i = 0; i < max; ++i) { @@ -5757,9 +6641,9 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init, } else eltinit = cp_build_array_ref (input_location, init, idx, complain); - eltinit = cxx_eval_vec_init_1 (&new_ctx, elttype, eltinit, value_init, - lval, - non_constant_p, overflow_p); + eltinit = cxx_eval_vec_init_1 (&new_ctx, elttype, eltinit, + value_init, lval, non_constant_p, + overflow_p, jump_target); } else if (pre_init) { @@ -5773,7 +6657,8 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init, /* Clarify what object is being initialized (118285). */ eltinit = build2 (INIT_EXPR, elttype, new_ctx.object, eltinit); eltinit = cxx_eval_constant_expression (&new_ctx, eltinit, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); reuse = i == 0; } else @@ -5789,8 +6674,11 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init, /* Clarify what object is being initialized (118285). */ eltinit = build2 (INIT_EXPR, elttype, new_ctx.object, eltinit); eltinit = cxx_eval_constant_expression (&new_ctx, eltinit, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); } + if (*jump_target) + return NULL_TREE; if (*non_constant_p) break; if (no_slot) @@ -5840,7 +6728,7 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init, static tree cxx_eval_vec_init (const constexpr_ctx *ctx, tree t, value_cat lval, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, tree *jump_target) { tree atype = TREE_TYPE (t); tree init = VEC_INIT_EXPR_INIT (t); @@ -5872,10 +6760,10 @@ cxx_eval_vec_init (const constexpr_ctx *ctx, tree t, } init = expand_vec_init_expr (ctx->object, t, complain); return cxx_eval_constant_expression (ctx, init, lval, non_constant_p, - overflow_p); + overflow_p, jump_target); } tree r = cxx_eval_vec_init_1 (ctx, atype, init, value_init, - lval, non_constant_p, overflow_p); + lval, non_constant_p, overflow_p, jump_target); if (*non_constant_p) return t; else @@ -5904,14 +6792,16 @@ same_type_ignoring_tlq_and_bounds_p (tree type1, tree type2) otherwise return NULL_TREE. */ static tree -cxx_union_active_member (const constexpr_ctx *ctx, tree t) +cxx_union_active_member (const constexpr_ctx *ctx, tree t, tree *jump_target) { constexpr_ctx new_ctx = *ctx; new_ctx.quiet = true; bool non_constant_p = false, overflow_p = false; tree ctor = cxx_eval_constant_expression (&new_ctx, t, vc_prvalue, &non_constant_p, - &overflow_p); + &overflow_p, jump_target); + if (*jump_target) + return NULL_TREE; if (TREE_CODE (ctor) == CONSTRUCTOR && CONSTRUCTOR_NELTS (ctor) == 1 && CONSTRUCTOR_ELT (ctor, 0)->index @@ -5924,7 +6814,8 @@ cxx_union_active_member (const constexpr_ctx *ctx, tree t) static tree cxx_fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type, - tree op, unsigned HOST_WIDE_INT off, bool *empty_base) + tree op, unsigned HOST_WIDE_INT off, bool *empty_base, + tree *jump_target) { tree optype = TREE_TYPE (op); unsigned HOST_WIDE_INT const_nunits; @@ -5941,7 +6832,8 @@ cxx_fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type, than pointer type. */ if (tree ret = cxx_fold_indirect_ref_1 (ctx, loc, strip_array_types (optype), - op, off, empty_base)) + op, off, empty_base, + jump_target)) return fold_convert (type, ret); } else if (TREE_CODE (optype) == COMPLEX_TYPE @@ -5987,7 +6879,7 @@ cxx_fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type, op = build4_loc (loc, ARRAY_REF, TREE_TYPE (optype), op, index, NULL_TREE, NULL_TREE); return cxx_fold_indirect_ref_1 (ctx, loc, type, op, rem, - empty_base); + empty_base, jump_target); } } /* ((foo *)&struct_with_foo_field)[x] => COMPONENT_REF */ @@ -5996,7 +6888,7 @@ cxx_fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type, { if (TREE_CODE (optype) == UNION_TYPE) /* For unions prefer the currently active member. */ - if (tree field = cxx_union_active_member (ctx, op)) + if (tree field = cxx_union_active_member (ctx, op, jump_target)) { unsigned HOST_WIDE_INT el_sz = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (field))); @@ -6005,7 +6897,8 @@ cxx_fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type, tree cop = build3 (COMPONENT_REF, TREE_TYPE (field), op, field, NULL_TREE); if (tree ret = cxx_fold_indirect_ref_1 (ctx, loc, type, cop, - off, empty_base)) + off, empty_base, + jump_target)) return ret; } } @@ -6050,7 +6943,8 @@ cxx_fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type, op, field, NULL_TREE); if (tree ret = cxx_fold_indirect_ref_1 (ctx, loc, type, cop, off - upos, - empty_base)) + empty_base, + jump_target)) return ret; } } @@ -6070,7 +6964,7 @@ cxx_fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type, static tree cxx_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type, - tree op0, bool *empty_base /* = NULL*/) + tree op0, bool *empty_base, tree *jump_target) { tree sub = op0; tree subtype; @@ -6152,7 +7046,8 @@ cxx_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type, tree off = integer_zero_node; canonicalize_obj_off (op, off); return cxx_fold_indirect_ref_1 (ctx, loc, type, op, - tree_to_uhwi (off), empty_base); + tree_to_uhwi (off), empty_base, + jump_target); } } else if (TREE_CODE (sub) == POINTER_PLUS_EXPR @@ -6167,7 +7062,8 @@ cxx_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type, tree obj = TREE_OPERAND (op00, 0); canonicalize_obj_off (obj, off); return cxx_fold_indirect_ref_1 (ctx, loc, type, obj, - tree_to_uhwi (off), empty_base); + tree_to_uhwi (off), empty_base, + jump_target); } } /* *(foo *)fooarrptr => (*fooarrptr)[0] */ @@ -6177,7 +7073,10 @@ cxx_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type, tree type_domain; tree min_val = size_zero_node; tree newsub - = cxx_fold_indirect_ref (ctx, loc, TREE_TYPE (subtype), sub, NULL); + = cxx_fold_indirect_ref (ctx, loc, TREE_TYPE (subtype), sub, NULL, + jump_target); + if (*jump_target) + return NULL_TREE; if (newsub) sub = newsub; else @@ -6195,7 +7094,8 @@ cxx_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type, static tree cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t, value_cat lval, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { tree orig_op0 = TREE_OPERAND (t, 0); bool empty_base = false; @@ -6213,13 +7113,17 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t, /* First try to simplify it directly. */ tree r = cxx_fold_indirect_ref (ctx, EXPR_LOCATION (t), TREE_TYPE (t), - orig_op0, &empty_base); + orig_op0, &empty_base, jump_target); + if (*jump_target) + return NULL_TREE; if (!r) { /* If that didn't work, evaluate the operand first. */ tree op0 = cxx_eval_constant_expression (ctx, orig_op0, vc_prvalue, non_constant_p, - overflow_p); + overflow_p, jump_target); + if (*jump_target) + return NULL_TREE; /* Don't VERIFY_CONSTANT here. */ if (*non_constant_p) return t; @@ -6233,7 +7137,9 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t, } r = cxx_fold_indirect_ref (ctx, EXPR_LOCATION (t), TREE_TYPE (t), op0, - &empty_base); + &empty_base, jump_target); + if (*jump_target) + return NULL_TREE; if (r == NULL_TREE) { /* We couldn't fold to a constant value. Make sure it's not @@ -6263,7 +7169,10 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t, } r = cxx_eval_constant_expression (ctx, r, - lval, non_constant_p, overflow_p); + lval, non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; if (*non_constant_p) return t; @@ -6373,7 +7282,8 @@ non_const_var_error (location_t loc, tree r, bool fundef_p) static tree cxx_eval_trinary_expression (const constexpr_ctx *ctx, tree t, value_cat lval, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { int i; tree args[3]; @@ -6383,7 +7293,10 @@ cxx_eval_trinary_expression (const constexpr_ctx *ctx, tree t, { args[i] = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, i), lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; VERIFY_CONSTANT (args[i]); } @@ -6505,7 +7418,8 @@ modifying_const_object_p (tree_code code, tree obj, bool mutable_p) static tree cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, value_cat lval, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { constexpr_ctx new_ctx = *ctx; @@ -6531,7 +7445,10 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, if (!SCALAR_TYPE_P (type)) new_ctx.ctor = new_ctx.object = NULL_TREE; init = cxx_eval_constant_expression (&new_ctx, init, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; if (*non_constant_p) return t; } @@ -6543,8 +7460,11 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, as a whole; otherwise, only evaluate the innermost piece to avoid building up unnecessary *_REFs. */ target = cxx_eval_constant_expression (ctx, target, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); evaluated = true; + if (*jump_target) + return NULL_TREE; if (*non_constant_p) return t; } @@ -6570,7 +7490,10 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, if (TREE_CODE (probe) == ARRAY_REF) { elt = eval_and_check_array_index (ctx, probe, false, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; if (*non_constant_p) return t; } @@ -6627,8 +7550,11 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, break; } probe = cxx_eval_constant_expression (ctx, probe, vc_glvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); evaluated = true; + if (*jump_target) + return NULL_TREE; if (*non_constant_p) return t; } @@ -6972,7 +7898,10 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, if (tree tinit = TARGET_EXPR_INITIAL (init)) init = tinit; init = cxx_eval_constant_expression (&new_ctx, init, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; /* The hash table might have moved since the get earlier, and the initializer might have mutated the underlying CONSTRUCTORs, so we must recompute VALP. */ @@ -7098,7 +8027,8 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, static tree cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t, value_cat lval, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { enum tree_code code = TREE_CODE (t); tree type = TREE_TYPE (t); @@ -7112,12 +8042,18 @@ cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t, /* The operand as an lvalue. */ op = cxx_eval_constant_expression (ctx, op, vc_glvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; /* The operand as an rvalue. */ tree val = cxx_eval_constant_expression (ctx, op, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; /* Don't VERIFY_CONSTANT if this might be dealing with a pointer to a local array in a constexpr function. */ bool ptr = INDIRECT_TYPE_P (TREE_TYPE (val)); @@ -7156,8 +8092,11 @@ cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t, tree store = build2_loc (cp_expr_loc_or_loc (t, input_location), MODIFY_EXPR, type, op, mod); mod = cxx_eval_constant_expression (ctx, store, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); ggc_free (store); + if (*jump_target) + return NULL_TREE; if (*non_constant_p) return t; @@ -7171,42 +8110,6 @@ cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t, return val; } -/* Predicates for the meaning of *jump_target. */ - -static bool -returns (tree *jump_target) -{ - return *jump_target - && TREE_CODE (*jump_target) == RETURN_EXPR; -} - -static bool -breaks (tree *jump_target) -{ - return *jump_target - && ((TREE_CODE (*jump_target) == LABEL_DECL - && LABEL_DECL_BREAK (*jump_target)) - || TREE_CODE (*jump_target) == BREAK_STMT - || TREE_CODE (*jump_target) == EXIT_EXPR); -} - -static bool -continues (tree *jump_target) -{ - return *jump_target - && ((TREE_CODE (*jump_target) == LABEL_DECL - && LABEL_DECL_CONTINUE (*jump_target)) - || TREE_CODE (*jump_target) == CONTINUE_STMT); - -} - -static bool -switches (tree *jump_target) -{ - return *jump_target - && TREE_CODE (*jump_target) == INTEGER_CST; -} - /* Subroutine of cxx_eval_statement_list. Determine whether the statement STMT matches *jump_target. If we're looking for a case label and we see the default label, note it in ctx->css_state. */ @@ -7254,6 +8157,11 @@ label_matches (const constexpr_ctx *ctx, tree *jump_target, tree stmt) breaks (jump_target) or continues (jump_target). */ break; + case VAR_DECL: + /* Uncaught exception. This is handled by TRY_BLOCK evaluation + and other places by testing throws (jump_target). */ + break; + default: gcc_unreachable (); } @@ -7268,15 +8176,9 @@ cxx_eval_statement_list (const constexpr_ctx *ctx, tree t, bool *non_constant_p, bool *overflow_p, tree *jump_target) { - tree local_target; /* In a statement-expression we want to return the last value. For empty statement expression return void_node. */ tree r = void_node; - if (!jump_target) - { - local_target = NULL_TREE; - jump_target = &local_target; - } for (tree_stmt_iterator i = tsi_start (t); !tsi_end_p (i); ++i) { tree stmt = *i; @@ -7304,18 +8206,11 @@ cxx_eval_statement_list (const constexpr_ctx *ctx, tree t, jump_target); if (*non_constant_p) break; - if (returns (jump_target) || breaks (jump_target)) + if (returns (jump_target) + || breaks (jump_target) + || throws (jump_target)) break; } - if (*jump_target && jump_target == &local_target) - { - /* We aren't communicating the jump to our caller, so give up. We don't - need to support evaluation of jumps out of statement-exprs. */ - if (!ctx->quiet) - error_at (cp_expr_loc_or_input_loc (r), - "statement is not a constant expression"); - *non_constant_p = true; - } return r; } @@ -7327,13 +8222,6 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t, bool *non_constant_p, bool *overflow_p, tree *jump_target) { - tree local_target; - if (!jump_target) - { - local_target = NULL_TREE; - jump_target = &local_target; - } - tree body, cond = NULL_TREE, expr = NULL_TREE; tree cond_prep = NULL_TREE, cond_cleanup = NULL_TREE; unsigned cond_cleanup_depth = 0; @@ -7389,7 +8277,7 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t, tree c; FOR_EACH_VEC_ELT_REVERSE (cleanups, i, c) cxx_eval_constant_expression (ctx, c, vc_discard, non_constant_p, - overflow_p); + overflow_p, jump_target); } if (cond_prep) for (tree decl = BIND_EXPR_VARS (cond_prep); @@ -7484,7 +8372,8 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t, if (*non_constant_p || returns (jump_target) || breaks (jump_target) - || continues (jump_target)) + || continues (jump_target) + || throws (jump_target)) { depth = 1; break; @@ -7531,6 +8420,7 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t, && !breaks (jump_target) && !continues (jump_target) && (!switches (jump_target) || count == 0) + && !throws (jump_target) && !*non_constant_p); cleanup_cond (); @@ -7549,7 +8439,10 @@ cxx_eval_switch_expr (const constexpr_ctx *ctx, tree t, tree cond = TREE_CODE (t) == SWITCH_STMT ? SWITCH_STMT_COND (t) : SWITCH_COND (t); cond = cxx_eval_constant_expression (ctx, cond, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; VERIFY_CONSTANT (cond); if (TREE_CODE (cond) != INTEGER_CST) { @@ -7682,7 +8575,8 @@ maybe_warn_about_constant_value (location_t loc, tree decl) static tree build_new_constexpr_heap_type (const constexpr_ctx *ctx, tree elt_type, tree cookie_size, tree full_size, tree arg_size, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { gcc_assert (cookie_size == NULL_TREE || tree_fits_uhwi_p (cookie_size)); gcc_assert (tree_fits_uhwi_p (full_size)); @@ -7718,13 +8612,17 @@ build_new_constexpr_heap_type (const constexpr_ctx *ctx, tree elt_type, if (integer_zerop (op0)) arg_size = cxx_eval_constant_expression (ctx, op1, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); else if (integer_zerop (op1)) arg_size = cxx_eval_constant_expression (ctx, op0, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); else arg_size = NULL_TREE; + if (*jump_target) + return NULL_TREE; } else arg_size = NULL_TREE; @@ -7745,6 +8643,38 @@ build_new_constexpr_heap_type (const constexpr_ctx *ctx, tree elt_type, return build_new_constexpr_heap_type (elt_type, cookie_size, itype2); } +/* Handle the case when a cleanup of some expression throws. JMP_TARGET + indicates whether the cleanup threw or not, *JUMP_TARGET indicates whether + the expression which needed the cleanup threw. If both threw, diagnose + it and return NULL, otherwise return R. If only the cleanup threw, set + *JUMP_TARGET to the exception object from the cleanup. */ + +static tree +merge_jump_target (location_t loc, const constexpr_ctx *ctx, tree r, + bool *non_constant_p, tree *jump_target, tree jmp_target) +{ + if (!throws (&jmp_target)) + return r; + if (throws (jump_target)) + { + /* [except.throw]/9 - If the exception handling mechanism + handling an uncaught exception directly invokes a function + that exits via an exception, the function std::terminate is + invoked. */ + if (!ctx->quiet) + { + auto_diagnostic_group d; + diagnose_std_terminate (loc, ctx, *jump_target); + inform (loc, "destructor exited with an exception"); + } + *non_constant_p = true; + *jump_target = NULL_TREE; + return NULL_TREE; + } + *jump_target = jmp_target; + return r; +} + /* Attempt to reduce the expression T to a constant value. On failure, issue diagnostic and return error_mark_node. */ /* FIXME unify with c_fully_fold */ @@ -7754,9 +8684,9 @@ static tree cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, value_cat lval, bool *non_constant_p, bool *overflow_p, - tree *jump_target /* = NULL */) + tree *jump_target) { - if (jump_target && *jump_target) + if (*jump_target) { /* If we are jumping, ignore all statements/expressions except those that could have LABEL_EXPR or CASE_LABEL_EXPR in their bodies. */ @@ -7880,7 +8810,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, r = convert_from_reference (r); } return cxx_eval_constant_expression (ctx, r, lval, non_constant_p, - overflow_p); + overflow_p, jump_target); } /* fall through */ case CONST_DECL: @@ -7958,7 +8888,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, r = v; if (TREE_ADDRESSABLE (TREE_TYPE (t))) r = cxx_eval_constant_expression (ctx, r, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; } else if (lval) /* Defer in case this is only used for its type. */; @@ -7991,7 +8924,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, case CALL_EXPR: case AGGR_INIT_EXPR: r = cxx_eval_call_expression (ctx, t, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, jump_target); break; case DECL_EXPR: @@ -8055,7 +8988,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, if (tree init = DECL_INITIAL (r)) { init = cxx_eval_constant_expression (ctx, init, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; /* Don't share a CONSTRUCTOR that might be changed. */ init = unshare_constructor (init); /* Remember that a constant object's constructor has already @@ -8125,9 +9061,12 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, /* Pass vc_prvalue because this indicates initialization of a temporary. */ r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); if (*non_constant_p) break; + if (*jump_target) + return NULL_TREE; if (!is_complex) { r = unshare_constructor (r); @@ -8135,8 +9074,15 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, r = adjust_temp_type (type, r); ctx->global->put_value (slot, r); } - if (TARGET_EXPR_CLEANUP (t) && !CLEANUP_EH_ONLY (t)) - ctx->global->cleanups->safe_push (TARGET_EXPR_CLEANUP (t)); + if (TARGET_EXPR_CLEANUP (t) + && (!CLEANUP_EH_ONLY (t) || cxx_dialect >= cxx26)) + { + ctx->global->cleanups->safe_push (TARGET_EXPR_CLEANUP (t)); + /* Mark CLEANUP_EH_ONLY cleanups by pushing NULL_TREE after + them. */ + if (CLEANUP_EH_ONLY (t)) + ctx->global->cleanups->safe_push (NULL_TREE); + } if (ctx->save_exprs) ctx->save_exprs->safe_push (slot); if (lval) @@ -8150,33 +9096,28 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, case MODIFY_EXPR: gcc_assert (jump_target == NULL || *jump_target == NULL_TREE); r = cxx_eval_store_expression (ctx, t, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, jump_target); break; case SCOPE_REF: r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); break; case RETURN_EXPR: if (TREE_OPERAND (t, 0) != NULL_TREE) r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), lval, - non_constant_p, overflow_p); - /* FALLTHRU */ + non_constant_p, overflow_p, + jump_target); + if (!throws (jump_target)) + *jump_target = t; + break; case BREAK_STMT: case CONTINUE_STMT: - if (jump_target) - *jump_target = t; - else - { - /* Can happen with ({ return true; }) && false; passed to - maybe_constant_value. There is nothing to jump over in this - case, and the bug will be diagnosed later. */ - gcc_assert (ctx->quiet); - *non_constant_p = true; - } + *jump_target = t; break; case SAVE_EXPR: @@ -8185,9 +9126,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, r = v; else { - r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), vc_prvalue, - non_constant_p, overflow_p); - if (*non_constant_p) + r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), + vc_prvalue, non_constant_p, + overflow_p, jump_target); + if (*non_constant_p || *jump_target) break; ctx->global->put_value (t, r); if (ctx->save_exprs) @@ -8195,16 +9137,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, } break; - case TRY_CATCH_EXPR: - if (TREE_OPERAND (t, 0) == NULL_TREE) - { - r = void_node; - break; - } - /* FALLTHRU */ case NON_LVALUE_EXPR: - case TRY_BLOCK: - case MUST_NOT_THROW_EXPR: case EXPR_STMT: case EH_SPEC_BLOCK: r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), @@ -8213,6 +9146,42 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, jump_target); break; + case TRY_BLOCK: + r = cxx_eval_constant_expression (ctx, TRY_STMTS (t), lval, + non_constant_p, overflow_p, + jump_target); + if (!*non_constant_p && throws (jump_target)) + if (tree h = TRY_HANDLERS (t)) + { + tree type = strip_array_types (TREE_TYPE (*jump_target)); + if (TREE_CODE (h) == STATEMENT_LIST) + { + for (tree stmt : tsi_range (h)) + if (TREE_CODE (stmt) == HANDLER + && handler_match_for_exception_type (stmt, type)) + { + h = stmt; + break; + } + if (TREE_CODE (h) == STATEMENT_LIST) + h = NULL_TREE; + } + else if (TREE_CODE (h) != HANDLER + || !handler_match_for_exception_type (h, type)) + h = NULL_TREE; + if (h) + { + gcc_assert (VAR_P (*jump_target)); + ctx->global->caught_exceptions.safe_push (*jump_target); + ctx->global->caught_exceptions.safe_push (HANDLER_TYPE (h)); + *jump_target = NULL_TREE; + r = cxx_eval_constant_expression (ctx, HANDLER_BODY (h), + vc_discard, non_constant_p, + overflow_p, jump_target); + } + } + break; + case CLEANUP_POINT_EXPR: { auto_vec<tree, 2> cleanups; @@ -8230,47 +9199,132 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, ctx->global->cleanups = prev_cleanups; unsigned int i; - tree cleanup; + tree cleanup, jmp_target = NULL_TREE; + bool eh = throws (jump_target); /* Evaluate the cleanups. */ FOR_EACH_VEC_ELT_REVERSE (cleanups, i, cleanup) - cxx_eval_constant_expression (&new_ctx, cleanup, vc_discard, - non_constant_p, overflow_p); + if (cleanup == NULL_TREE) + { + /* NULL_TREE cleanup is a marker that before it is + CLEANUP_EH_ONLY cleanup. Skip the cleanup before it + if the body didn't throw. */ + if (!eh) + --i; + } + else + cxx_eval_constant_expression (&new_ctx, cleanup, vc_discard, + non_constant_p, overflow_p, + &jmp_target); /* Forget SAVE_EXPRs and TARGET_EXPRs created by this full-expression. */ for (tree save_expr : save_exprs) destroy_value_checked (ctx, save_expr, non_constant_p); + if (throws (&jmp_target)) + *jump_target = jmp_target; } break; + case MUST_NOT_THROW_EXPR: + r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), + lval, + non_constant_p, overflow_p, + jump_target); + if (throws (jump_target)) + { + /* [except.handle]/7 - If the search for a handler exits the + function body of a function with a non-throwing exception + specification, the function std::terminate is invoked. */ + if (!ctx->quiet) + { + auto_diagnostic_group d; + diagnose_std_terminate (loc, ctx, *jump_target); + if (MUST_NOT_THROW_NOEXCEPT_P (t) + && ctx->call + && ctx->call->fundef) + inform (loc, "uncaught exception exited from %<noexcept%> " + "function %qD", + ctx->call->fundef->decl); + else if (MUST_NOT_THROW_THROW_P (t)) + inform (loc, "destructor exited with an exception after " + "initializing the exception object"); + else if (MUST_NOT_THROW_CATCH_P (t)) + inform (loc, "constructor exited with another exception while " + "entering handler"); + } + *non_constant_p = true; + *jump_target = NULL_TREE; + r = NULL_TREE; + } + break; + + case TRY_CATCH_EXPR: + if (TREE_OPERAND (t, 0) == NULL_TREE) + { + r = void_node; + break; + } + r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), lval, + non_constant_p, overflow_p, + jump_target); + if (!*non_constant_p && throws (jump_target)) + { + tree jmp_target = NULL_TREE; + cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), vc_discard, + non_constant_p, overflow_p, + &jmp_target); + r = merge_jump_target (loc, ctx, r, non_constant_p, jump_target, + jmp_target); + } + break; + case TRY_FINALLY_EXPR: r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), lval, non_constant_p, overflow_p, jump_target); if (!*non_constant_p) - /* Also evaluate the cleanup. */ - cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), vc_discard, - non_constant_p, overflow_p); + { + tree jmp_target = NULL_TREE; + /* Also evaluate the cleanup. */ + if (TREE_CODE (TREE_OPERAND (t, 1)) == EH_ELSE_EXPR + && throws (jump_target)) + cxx_eval_constant_expression (ctx, + TREE_OPERAND (TREE_OPERAND (t, 1), + 1), vc_discard, + non_constant_p, overflow_p, + &jmp_target); + else + cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), vc_discard, + non_constant_p, overflow_p, + &jmp_target); + r = merge_jump_target (loc, ctx, r, non_constant_p, jump_target, + jmp_target); + } break; case EH_ELSE_EXPR: /* Evaluate any cleanup that applies to non-EH exits. */ cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), vc_discard, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); - /* We do not have constexpr exceptions yet, so skip the EH path. */ + /* The EH path is handled in TRY_FINALLY_EXPR handling above. */ break; case CLEANUP_STMT: r = cxx_eval_constant_expression (ctx, CLEANUP_BODY (t), lval, non_constant_p, overflow_p, jump_target); - if (!CLEANUP_EH_ONLY (t) && !*non_constant_p) + if ((!CLEANUP_EH_ONLY (t) || throws (jump_target)) && !*non_constant_p) { iloc_sentinel ils (loc); + tree jmp_target = NULL_TREE; /* Also evaluate the cleanup. */ cxx_eval_constant_expression (ctx, CLEANUP_EXPR (t), vc_discard, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + &jmp_target); + r = merge_jump_target (loc, ctx, r, non_constant_p, jump_target, + jmp_target); } break; @@ -8280,14 +9334,18 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, case MEM_REF: case INDIRECT_REF: r = cxx_eval_indirect_ref (ctx, t, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); break; case ADDR_EXPR: { tree oldop = TREE_OPERAND (t, 0); tree op = cxx_eval_constant_expression (ctx, oldop, vc_glvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; /* Don't VERIFY_CONSTANT here. */ if (*non_constant_p) return t; @@ -8307,7 +9365,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, if (lval) { r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; if (r == error_mark_node) ; else if (r == TREE_OPERAND (t, 0) || lval == vc_discard) @@ -8328,7 +9389,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, case FIXED_CONVERT_EXPR: case VEC_DUPLICATE_EXPR: r = cxx_eval_unary_expression (ctx, t, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); break; case SIZEOF_EXPR: @@ -8366,6 +9428,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, cxx_eval_constant_expression (ctx, op0, vc_discard, non_constant_p, overflow_p, jump_target); + if (*jump_target) + return NULL_TREE; if (*non_constant_p) return t; op1 = TREE_OPERAND (t, 1); @@ -8418,7 +9482,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, case RANGE_EXPR: case COMPLEX_EXPR: r = cxx_eval_binary_expression (ctx, t, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); break; /* fold can introduce non-IF versions of these; still treat them as @@ -8427,19 +9492,22 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, case TRUTH_ANDIF_EXPR: r = cxx_eval_logical_expression (ctx, t, boolean_false_node, boolean_true_node, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); break; case TRUTH_OR_EXPR: case TRUTH_ORIF_EXPR: r = cxx_eval_logical_expression (ctx, t, boolean_true_node, boolean_false_node, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); break; case ARRAY_REF: r = cxx_eval_array_reference (ctx, t, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); break; case COMPONENT_REF: @@ -8454,17 +9522,19 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, return t; } r = cxx_eval_component_reference (ctx, t, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); break; case BIT_FIELD_REF: r = cxx_eval_bit_field_ref (ctx, t, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); break; case COND_EXPR: case IF_STMT: - if (jump_target && *jump_target) + if (*jump_target) { tree orig_jump = *jump_target; tree arg = ((TREE_CODE (t) != IF_STMT || TREE_OPERAND (t, 1)) @@ -8502,7 +9572,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, break; case VEC_COND_EXPR: r = cxx_eval_vector_conditional_expression (ctx, t, non_constant_p, - overflow_p); + overflow_p, jump_target); break; case CONSTRUCTOR: @@ -8514,7 +9584,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, return t; } r = cxx_eval_bare_aggregate (ctx, t, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, jump_target); break; case VEC_INIT_EXPR: @@ -8524,12 +9594,13 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, or xvalue of the same type, meaning direct-initialization from the corresponding member. */ r = cxx_eval_vec_init (ctx, t, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, jump_target); break; case VEC_PERM_EXPR: r = cxx_eval_trinary_expression (ctx, t, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); break; case PAREN_EXPR: @@ -8537,7 +9608,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, /* A PAREN_EXPR resulting from __builtin_assoc_barrier has no effect in constant expressions since it's unaffected by -fassociative-math. */ r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); break; case NOP_EXPR: @@ -8561,7 +9633,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, ? vc_discard : tcode == VIEW_CONVERT_EXPR ? lval : vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; if (*non_constant_p) return t; tree type = TREE_TYPE (t); @@ -8618,7 +9693,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, { if (integer_zerop (sop)) return build_int_cst (type, 0); - r = cxx_fold_indirect_ref (ctx, loc, TREE_TYPE (type), sop); + r = cxx_fold_indirect_ref (ctx, loc, TREE_TYPE (type), sop, + NULL, jump_target); + if (*jump_target) + return NULL_TREE; if (r) { r = build1 (ADDR_EXPR, type, r); @@ -8745,10 +9823,14 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, if (cxx_replaceable_global_alloc_fn (fun) && IDENTIFIER_NEW_OP_P (DECL_NAME (fun))) arg_size = CALL_EXPR_ARG (oldop, 0); - TREE_TYPE (var) + tree new_type = build_new_constexpr_heap_type (ctx, elt_type, cookie_size, var_size, arg_size, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; + TREE_TYPE (var) = new_type; TREE_TYPE (TREE_OPERAND (op, 0)) = build_pointer_type (TREE_TYPE (var)); } @@ -8787,7 +9869,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, tree op = cxx_eval_constant_expression (ctx, oldop, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; if (*non_constant_p) return t; r = fold_convert (TREE_TYPE (t), op); @@ -8824,14 +9909,20 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, case PREDECREMENT_EXPR: case POSTDECREMENT_EXPR: return cxx_eval_increment_expression (ctx, t, - lval, non_constant_p, overflow_p); + lval, non_constant_p, overflow_p, + jump_target); + case THROW_EXPR: + if (cxx_dialect >= cxx26) + return cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), lval, + non_constant_p, overflow_p, + jump_target); + /* FALLTHROUGH */ case LAMBDA_EXPR: case NEW_EXPR: case VEC_NEW_EXPR: case DELETE_EXPR: case VEC_DELETE_EXPR: - case THROW_EXPR: case MODOP_EXPR: /* GCC internal stuff. */ case VA_ARG_EXPR: @@ -8845,7 +9936,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, case OBJ_TYPE_REF: /* Virtual function lookup. We don't need to do anything fancy. */ return cxx_eval_constant_expression (ctx, OBJ_TYPE_REF_EXPR (t), - lval, non_constant_p, overflow_p); + lval, non_constant_p, overflow_p, + jump_target); case PLACEHOLDER_EXPR: /* Use of the value or address of the current object. */ @@ -8855,7 +9947,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, return ctor; else return cxx_eval_constant_expression (ctx, ctor, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); } /* A placeholder without a referent. We can get here when checking whether NSDMIs are noexcept, or in massage_init_elt; @@ -8868,7 +9961,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, { tree cond = TREE_OPERAND (t, 0); cond = cxx_eval_constant_expression (ctx, cond, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; VERIFY_CONSTANT (cond); if (integer_nonzerop (cond)) *jump_target = t; @@ -8980,7 +10076,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, *non_constant_p = true; return t; } - r = cxx_eval_bit_cast (ctx, t, non_constant_p, overflow_p); + r = cxx_eval_bit_cast (ctx, t, non_constant_p, overflow_p, jump_target); break; case OMP_PARALLEL: @@ -9299,8 +10395,34 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, if (manifestly_const_eval == mce_true) instantiate_constexpr_fns (r); + tree jmp_target = NULL_TREE; r = cxx_eval_constant_expression (&ctx, r, vc_prvalue, - &non_constant_p, &overflow_p); + &non_constant_p, &overflow_p, + &jmp_target); + if (throws (&jmp_target) && !non_constant_p) + { + if (!ctx.quiet) + diagnose_uncaught_exception (input_location, &ctx, jmp_target); + non_constant_p = true; + jmp_target = NULL_TREE; + r = t; + } + else if (!non_constant_p && jmp_target) + { + non_constant_p = true; + if (!ctx.quiet) + { + if (breaks (&jmp_target)) + error ("%<break%> outside of a loop or %<switch%>"); + else if (continues (&jmp_target)) + error ("%<continue%> outside of a loop"); + else if (returns (&jmp_target)) + error ("%<return%> in a statement expression"); + else + gcc_unreachable (); + } + r = t; + } /* If we got a non-simple TARGET_EXPR, the initializer was a sequence of statements, and the result ought to be stored in ctx.ctor. */ @@ -9309,15 +10431,31 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, unsigned int i; tree cleanup; + jmp_target = NULL_TREE; /* Evaluate the cleanups. */ FOR_EACH_VEC_ELT_REVERSE (cleanups, i, cleanup) - cxx_eval_constant_expression (&ctx, cleanup, vc_discard, - &non_constant_p, &overflow_p); + if (cleanup == NULL_TREE) + /* NULL_TREE cleanup is a marker that before it is + CLEANUP_EH_ONLY cleanup. Skip the cleanup before it. */ + --i; + else + cxx_eval_constant_expression (&ctx, cleanup, vc_discard, + &non_constant_p, &overflow_p, + &jmp_target); + if (throws (&jmp_target) && !non_constant_p) + { + if (!ctx.quiet) + diagnose_uncaught_exception (input_location, &ctx, jmp_target); + non_constant_p = true; + r = t; + } /* Mutable logic is a bit tricky: we want to allow initialization of constexpr variables with mutable members, but we can't copy those members to another constexpr variable. */ - if (TREE_CODE (r) == CONSTRUCTOR && CONSTRUCTOR_MUTABLE_POISON (r)) + if (!non_constant_p + && TREE_CODE (r) == CONSTRUCTOR + && CONSTRUCTOR_MUTABLE_POISON (r)) { if (!allow_non_constant) error ("%qE is not a constant expression because it refers to " @@ -9335,8 +10473,13 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, { if (!allow_non_constant && !non_constant_p) { - error ("%qE is not a constant expression because it refers to " - "a result of %<operator new%>", t); + if (DECL_LANG_SPECIFIC (heap_var)) + error ("%qE is not a constant expression because it refers to " + "exception object allocated with " + "%<__cxa_allocate_exception%>", t); + else + error ("%qE is not a constant expression because it refers to " + "a result of %<operator new%>", t); inform (DECL_SOURCE_LOCATION (heap_var), "allocated here"); } r = t; @@ -9917,6 +11060,24 @@ cxx_constant_init (tree t, tree decl) return maybe_constant_init_1 (t, decl, false, mce_true); } +/* Return true if CALL_EXPR T might throw during constant evaluation. */ + +static bool +callee_might_throw (tree t) +{ + if (cxx_dialect < cxx26 || !flag_exceptions) + return false; + tree callee = cp_get_callee (t); + if (callee == NULL_TREE) + return false; + tree callee_fn = cp_get_fndecl_from_callee (callee, false); + return (!flag_enforce_eh_specs + || type_dependent_expression_p (callee) + || !POINTER_TYPE_P (TREE_TYPE (callee)) + || (!type_noexcept_p (TREE_TYPE (TREE_TYPE (callee))) + && (callee_fn == NULL_TREE || !TREE_NOTHROW (callee_fn)))); +} + #if 0 /* FIXME see ADDR_EXPR section in potential_constant_expression_1. */ /* Return true if the object referred to by REF has automatic or thread @@ -9949,11 +11110,13 @@ struct check_for_return_continue_data { hash_set<tree> *pset; tree continue_stmt; tree break_stmt; + bool could_throw; }; /* Helper function for potential_constant_expression_1 SWITCH_STMT handling, called through cp_walk_tree. Return the first RETURN_EXPR found, or note - the first CONTINUE_STMT and/or BREAK_STMT if RETURN_EXPR is not found. */ + the first CONTINUE_STMT and/or BREAK_STMT if RETURN_EXPR is not found. + For C++26 also note presence of possibly throwing calls. */ static tree check_for_return_continue (tree *tp, int *walk_subtrees, void *data) { @@ -10038,6 +11201,13 @@ check_for_return_continue (tree *tp, int *walk_subtrees, void *data) case CONSTRUCTOR: break; + case AGGR_INIT_EXPR: + case CALL_EXPR: + /* In C++26 a function could throw. */ + if (callee_might_throw (t)) + d->could_throw = true; + break; + default: if (!EXPR_P (t)) *walk_subtrees = 0; @@ -10243,8 +11413,27 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, || TREE_CODE (t) != CALL_EXPR || current_function_decl == NULL_TREE || !is_std_construct_at (current_function_decl)) - && !cxx_dynamic_cast_fn_p (fun)) + && !cxx_dynamic_cast_fn_p (fun) + && !cxx_cxa_builtin_fn_p (fun)) { + /* In C++26 evaluation of the function arguments might + throw and in that case it is irrelevant whether + fun is constexpr or not. */ + if (cxx_dialect >= cxx26) + for (; i < nargs; ++i) + { + tree x = get_nth_callarg (t, i); + bool rv = processing_template_decl ? any : rval; + bool sub_now = false; + if (!potential_constant_expression_1 (x, rv, strict, + sub_now, + fundef_p, + flags, + jump_target)) + return false; + if (throws (jump_target)) + return true; + } if ((flags & tf_error) && constexpr_error (loc, fundef_p, "call to non-%<constexpr%> " @@ -10289,7 +11478,12 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, sub_now, fundef_p, flags, jump_target)) return false; + if (throws (jump_target)) + return true; } + /* In C++26 a function could throw. */ + if (*jump_target == NULL_TREE && callee_might_throw (t)) + *jump_target = void_node; return true; } @@ -10512,11 +11706,13 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, a return. */ hash_set<tree> pset; check_for_return_continue_data data = { &pset, NULL_TREE, - NULL_TREE }; + NULL_TREE, false }; if (tree ret_expr = cp_walk_tree (&FOR_BODY (t), check_for_return_continue, &data, &pset)) *jump_target = ret_expr; + if (data.could_throw) + *jump_target = void_node; return true; } } @@ -10556,11 +11752,13 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, a return. */ hash_set<tree> pset; check_for_return_continue_data data = { &pset, NULL_TREE, - NULL_TREE }; + NULL_TREE, false }; if (tree ret_expr = cp_walk_tree (&WHILE_BODY (t), check_for_return_continue, &data, &pset)) *jump_target = ret_expr; + if (data.could_throw) + *jump_target = void_node; return true; } if (!RECUR (WHILE_BODY (t), any)) @@ -10584,7 +11782,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, { hash_set<tree> pset; check_for_return_continue_data data = { &pset, NULL_TREE, - NULL_TREE }; + NULL_TREE, false }; if (tree ret_expr = cp_walk_tree (&SWITCH_STMT_BODY (t), check_for_return_continue, &data, &pset)) @@ -10593,6 +11791,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, else if (data.continue_stmt) /* The switch can't return, but might continue. */ *jump_target = data.continue_stmt; + if (data.could_throw) + *jump_target = void_node; } return true; @@ -10622,7 +11822,6 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, case DYNAMIC_CAST_EXPR: case PSEUDO_DTOR_EXPR: - case THROW_EXPR: case OMP_PARALLEL: case OMP_TASK: case OMP_FOR: @@ -10678,6 +11877,11 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, constant. */ return true; + case THROW_EXPR: + if (cxx_dialect < cxx26) + goto fail; + return RECUR (TREE_OPERAND (t, 0), rval); + case ASM_EXPR: if (flags & tf_error) inline_asm_in_constexpr_error (loc, fundef_p); @@ -10806,6 +12010,22 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, case CLEANUP_POINT_EXPR: case MUST_NOT_THROW_EXPR: case TRY_CATCH_EXPR: + /* Even for C++26 handle TRY_BLOCK conservatively, if we detect the + body could throw, even with catch (...) among handlers we'd need + to analyze them in detail if they couldn't rethrow it. More + importantly though, throws (jump_target) is just conservative, + and there could be e.g. + try + { + possibly_throwing_fn (args); + break; + } + catch (...) + { + } + or continue or return instead of break. So, clearing *jump_target + because we see catch (...) handler might mean we missed break + etc. */ case TRY_BLOCK: case EH_SPEC_BLOCK: case EXPR_STMT: @@ -11047,9 +12267,9 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, want_rval, strict, now, fundef_p, tf_none, &this_jump_target)) { - if (returns (&this_jump_target)) + if (returns (&this_jump_target) || throws (&this_jump_target)) *jump_target = this_jump_target; - else if (!returns (jump_target)) + else if (!returns (jump_target) && !throws (jump_target)) { if (breaks (&this_jump_target) || continues (&this_jump_target)) @@ -11061,7 +12281,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, couldn't return, break or continue. */ hash_set<tree> pset; check_for_return_continue_data data = { &pset, NULL_TREE, - NULL_TREE }; + NULL_TREE, + false }; if (tree ret_expr = cp_walk_tree (&TREE_OPERAND (t, 2), check_for_return_continue, &data, @@ -11074,6 +12295,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, else if (data.break_stmt) *jump_target = data.break_stmt; } + if (data.could_throw) + *jump_target = void_node; } } return true; diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc index ce69bd6..882a943 100644 --- a/gcc/cp/cp-gimplify.cc +++ b/gcc/cp/cp-gimplify.cc @@ -889,6 +889,12 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) (EXPR_LOCATION (*expr_p), call_expr_nargs (*expr_p), &CALL_EXPR_ARG (*expr_p, 0)); break; + case CP_BUILT_IN_EH_PTR_ADJUST_REF: + error_at (EXPR_LOCATION (*expr_p), + "%qs used outside of constant expressions", + "__builtin_eh_ptr_adjust_ref"); + *expr_p = void_node; + break; default: break; } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 3b92d9a..9081628 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -452,6 +452,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; contract_semantic (in ASSERTION_, PRECONDITION_, POSTCONDITION_STMT) RETURN_EXPR_LOCAL_ADDR_P (in RETURN_EXPR) PACK_INDEX_PARENTHESIZED_P (in PACK_INDEX_*) + MUST_NOT_THROW_NOEXCEPT_P (in MUST_NOT_THROW_EXPR) 1: IDENTIFIER_KIND_BIT_1 (in IDENTIFIER_NODE) TI_PENDING_TEMPLATE_FLAG. TEMPLATE_PARMS_FOR_INLINE. @@ -472,6 +473,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; BIND_EXPR_VEC_DTOR (in BIND_EXPR) ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (in ATOMIC_CONSTR) STATIC_INIT_DECOMP_BASE_P (in the TREE_LIST for {static,tls}_aggregates) + MUST_NOT_THROW_THROW_P (in MUST_NOT_THROW_EXPR) 2: IDENTIFIER_KIND_BIT_2 (in IDENTIFIER_NODE) ICS_THIS_FLAG (in _CONV) DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL) @@ -493,6 +495,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; contract_semantic (in ASSERTION_, PRECONDITION_, POSTCONDITION_STMT) STATIC_INIT_DECOMP_NONBASE_P (in the TREE_LIST for {static,tls}_aggregates) + MUST_NOT_THROW_CATCH_P (in MUST_NOT_THROW_EXPR) 3: IMPLICIT_RVALUE_P (in NON_LVALUE_EXPR or STATIC_CAST_EXPR) ICS_BAD_FLAG (in _CONV) FN_TRY_BLOCK_P (in TRY_BLOCK) @@ -2516,11 +2519,11 @@ struct GTY(()) lang_type { vec<tree, va_gc> *pure_virtuals; tree friend_classes; vec<tree, va_gc> * GTY((reorder ("resort_type_member_vec"))) members; + /* CLASSTYPE_KEY_METHOD for TYPE_POLYMORPHIC_P types, CLASSTYPE_LAMBDA_EXPR + otherwise. */ tree key_method; tree decl_list; tree befriending_classes; - /* FIXME reuse another field? */ - tree lambda_expr; union maybe_objc_info { /* If not c_dialect_objc, this part is not even allocated. */ char GTY((tag ("0"))) non_objc; @@ -2643,7 +2646,13 @@ struct GTY(()) lang_type { /* The member function with which the vtable will be emitted: the first noninline non-pure-virtual member function. NULL_TREE if there is no key function or if this is a class template */ -#define CLASSTYPE_KEY_METHOD(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->key_method) +#define CLASSTYPE_KEY_METHOD(NODE) \ + (TYPE_POLYMORPHIC_P (NODE) \ + ? LANG_TYPE_CLASS_CHECK (NODE)->key_method \ + : NULL_TREE) +#define SET_CLASSTYPE_KEY_METHOD(NODE, VALUE) \ + (gcc_checking_assert (TYPE_POLYMORPHIC_P (NODE)), \ + LANG_TYPE_CLASS_CHECK (NODE)->key_method = (VALUE)) /* Vector of members. During definition, it is unordered and only member functions are present. After completion it is sorted and @@ -2775,7 +2784,12 @@ struct GTY(()) lang_type { /* The associated LAMBDA_EXPR that made this class. */ #define CLASSTYPE_LAMBDA_EXPR(NODE) \ - (LANG_TYPE_CLASS_CHECK (NODE)->lambda_expr) + (TYPE_POLYMORPHIC_P (NODE) \ + ? NULL_TREE \ + : LANG_TYPE_CLASS_CHECK (NODE)->key_method) +#define SET_CLASSTYPE_LAMBDA_EXPR(NODE, VALUE) \ + (gcc_checking_assert (!TYPE_POLYMORPHIC_P (NODE)), \ + LANG_TYPE_CLASS_CHECK (NODE)->key_method = (VALUE)) /* The extra mangling scope for this closure type. */ #define LAMBDA_TYPE_EXTRA_SCOPE(NODE) \ (LAMBDA_EXPR_EXTRA_SCOPE (CLASSTYPE_LAMBDA_EXPR (NODE))) @@ -3016,6 +3030,8 @@ struct GTY(()) lang_decl_min { In a lambda-capture proxy VAR_DECL, this is DECL_CAPTURED_VARIABLE. In a function-scope TREE_STATIC VAR_DECL or IMPLICIT_TYPEDEF_P TYPE_DECL, this is DECL_DISCRIMINATOR. + In constexpr exception artificial VAR_DECL, this is + DECL_EXCEPTION_REFCOUNT. In a DECL_LOCAL_DECL_P decl, this is the namespace decl it aliases. Otherwise, in a class-scope DECL, this is DECL_ACCESS. */ tree access; @@ -4470,6 +4486,23 @@ get_vec_init_expr (tree t) #define MUST_NOT_THROW_COND(NODE) \ TREE_OPERAND (MUST_NOT_THROW_EXPR_CHECK (NODE), 1) +/* Reasons why MUST_NOT_THROW_EXPR has been created. */ + +/* Indicates MUST_NOT_THROW_EXPR has been created to wrap body of + a noexcept function. */ +#define MUST_NOT_THROW_NOEXCEPT_P(NODE) \ + TREE_LANG_FLAG_0 (MUST_NOT_THROW_EXPR_CHECK (NODE)) + +/* Indicates MUST_NOT_THROW_EXPR has been created to wrap construction of + exception object during throw. */ +#define MUST_NOT_THROW_THROW_P(NODE) \ + TREE_LANG_FLAG_1 (MUST_NOT_THROW_EXPR_CHECK (NODE)) + +/* Indicates MUST_NOT_THROW_EXPR has been created to wrap construction of + handler parameter during catch. */ +#define MUST_NOT_THROW_CATCH_P(NODE) \ + TREE_LANG_FLAG_2 (MUST_NOT_THROW_EXPR_CHECK (NODE)) + /* The TYPE_MAIN_DECL for a class template type is a TYPE_DECL, not a TEMPLATE_DECL. This macro determines whether or not a given class type is really a template type, as opposed to an instantiation or @@ -4512,7 +4545,7 @@ get_vec_init_expr (tree t) #define TYPE_CONTAINS_VPTR_P(NODE) \ (TYPE_POLYMORPHIC_P (NODE) || CLASSTYPE_VBASECLASSES (NODE)) -/* Nonzero if NODE is a FUNCTION_DECL or VARIABLE_DECL (for a decl +/* Nonzero if NODE is a FUNCTION_DECL or VAR_DECL (for a decl with namespace scope) declared in a local scope. */ #define DECL_LOCAL_DECL_P(NODE) \ DECL_LANG_FLAG_0 (VAR_OR_FUNCTION_DECL_CHECK (NODE)) @@ -5153,6 +5186,10 @@ get_vec_init_expr (tree t) protected_access_node will appear in the DECL_ACCESS for the node. */ #define DECL_ACCESS(NODE) (LANG_DECL_MIN_CHECK (NODE)->access) +/* In artificial VAR_DECL created by cxa_allocate_exception + this is reference count. */ +#define DECL_EXCEPTION_REFCOUNT(NODE) (LANG_DECL_MIN_CHECK (NODE)->access) + /* Nonzero if the FUNCTION_DECL is a global constructor. */ #define DECL_GLOBAL_CTOR_P(NODE) \ (LANG_DECL_FN_CHECK (NODE)->global_ctor_p) @@ -6813,6 +6850,7 @@ enum cp_built_in_function { CP_BUILT_IN_IS_CORRESPONDING_MEMBER, CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS, CP_BUILT_IN_SOURCE_LOCATION, + CP_BUILT_IN_EH_PTR_ADJUST_REF, CP_BUILT_IN_LAST }; @@ -6993,6 +7031,7 @@ extern bool type_has_extended_temps (tree); extern tree strip_top_quals (tree); extern bool reference_related_p (tree, tree); extern bool reference_compatible_p (tree, tree); +extern bool handler_match_for_exception_type (tree, tree); extern int remaining_arguments (tree); extern tree build_implicit_conv_flags (tree, tree, int); extern tree perform_implicit_conversion (tree, tree, tsubst_flags_t); diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 0e6afbe..843f0e4 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -5082,6 +5082,18 @@ cxx_init_decl_processing (void) BUILT_IN_FRONTEND, NULL, NULL_TREE); set_call_expr_flags (decl, ECF_CONST | ECF_NOTHROW | ECF_LEAF); + if (cxx_dialect >= cxx26) + { + tree void_ptrintftype + = build_function_type_list (void_type_node, ptr_type_node, + integer_type_node, NULL_TREE); + decl = add_builtin_function ("__builtin_eh_ptr_adjust_ref", + void_ptrintftype, + CP_BUILT_IN_EH_PTR_ADJUST_REF, + BUILT_IN_FRONTEND, NULL, NULL_TREE); + set_call_expr_flags (decl, ECF_NOTHROW | ECF_LEAF); + } + integer_two_node = build_int_cst (NULL_TREE, 2); /* Guess at the initial static decls size. */ @@ -17277,7 +17289,7 @@ xref_tag (enum tag_types tag_code, tree name, if (IDENTIFIER_LAMBDA_P (name)) /* Mark it as a lambda type right now. Our caller will correct the value. */ - CLASSTYPE_LAMBDA_EXPR (t) = error_mark_node; + SET_CLASSTYPE_LAMBDA_EXPR (t, error_mark_node); t = pushtag (name, t, how); } else diff --git a/gcc/cp/except.cc b/gcc/cp/except.cc index a9d8e2f..a7f35e4 100644 --- a/gcc/cp/except.cc +++ b/gcc/cp/except.cc @@ -367,6 +367,8 @@ initialize_handler_parm (tree decl, tree exp) MUST_NOT_THROW_EXPR. */ init = fold_build_cleanup_point_expr (TREE_TYPE (init), init); init = build_must_not_throw_expr (init, NULL_TREE); + if (init && TREE_CODE (init) == MUST_NOT_THROW_EXPR) + MUST_NOT_THROW_CATCH_P (init) = 1; } decl = pushdecl (decl); @@ -523,6 +525,7 @@ begin_eh_spec_block (void) r = build_stmt (spec_location, MUST_NOT_THROW_EXPR, NULL_TREE, NULL_TREE); TREE_SIDE_EFFECTS (r) = 1; + MUST_NOT_THROW_NOEXCEPT_P (r) = 1; } else r = build_stmt (spec_location, EH_SPEC_BLOCK, NULL_TREE, NULL_TREE); @@ -614,6 +617,7 @@ wrap_cleanups_r (tree *tp, int *walk_subtrees, void * /*data*/) { cleanup = build2 (MUST_NOT_THROW_EXPR, void_type_node, cleanup, NULL_TREE); + MUST_NOT_THROW_THROW_P (cleanup) = 1; TARGET_EXPR_CLEANUP (exp) = cleanup; } @@ -712,6 +716,11 @@ build_throw (location_t loc, tree exp, tsubst_flags_t complain) allocate_expr = do_allocate_exception (temp_type); if (allocate_expr == error_mark_node) return error_mark_node; + /* Copy ptr inside of the CLEANUP_POINT_EXPR + added below to a TARGET_EXPR slot added outside of it, + otherwise during constant evaluation of throw expression + we'd diagnose accessing ptr outside of its lifetime. */ + tree ptr_copy = get_internal_target_expr (null_pointer_node); allocate_expr = get_internal_target_expr (allocate_expr); ptr = TARGET_EXPR_SLOT (allocate_expr); TARGET_EXPR_CLEANUP (allocate_expr) = do_free_exception (ptr); @@ -763,10 +772,17 @@ build_throw (location_t loc, tree exp, tsubst_flags_t complain) /* Prepend the allocation. */ exp = build2 (COMPOUND_EXPR, TREE_TYPE (exp), allocate_expr, exp); + exp = build2 (COMPOUND_EXPR, void_type_node, exp, + build2 (MODIFY_EXPR, void_type_node, + TARGET_EXPR_SLOT (ptr_copy), ptr)); + ptr = TARGET_EXPR_SLOT (ptr_copy); + /* Force all the cleanups to be evaluated here so that we don't have to do them during unwinding. */ exp = build1 (CLEANUP_POINT_EXPR, void_type_node, exp); + exp = build2 (COMPOUND_EXPR, TREE_TYPE (exp), ptr_copy, exp); + throw_type = build_eh_type_type (prepare_eh_type (TREE_TYPE (object))); cleanup = NULL_TREE; diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc index 182cffa..525e8ef 100644 --- a/gcc/cp/lambda.cc +++ b/gcc/cp/lambda.cc @@ -150,7 +150,7 @@ begin_lambda_type (tree lambda) /* Cross-reference the expression and the type. */ LAMBDA_EXPR_CLOSURE (lambda) = type; - CLASSTYPE_LAMBDA_EXPR (type) = lambda; + SET_CLASSTYPE_LAMBDA_EXPR (type, lambda); /* In C++17, assume the closure is literal; we'll clear the flag later if necessary. */ diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 6b5a60a..689319a 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -13393,13 +13393,19 @@ trees_in::read_class_def (tree defn, tree maybe_template) if (TYPE_LANG_SPECIFIC (type)) { - CLASSTYPE_LAMBDA_EXPR (type) = lambda; + if (!TYPE_POLYMORPHIC_P (type)) + SET_CLASSTYPE_LAMBDA_EXPR (type, lambda); + else + gcc_checking_assert (lambda == NULL_TREE); CLASSTYPE_MEMBER_VEC (type) = member_vec; CLASSTYPE_PURE_VIRTUALS (type) = pure_virts; CLASSTYPE_VCALL_INDICES (type) = vcall_indices; - CLASSTYPE_KEY_METHOD (type) = key_method; + if (TYPE_POLYMORPHIC_P (type)) + SET_CLASSTYPE_KEY_METHOD (type, key_method); + else + gcc_checking_assert (key_method == NULL_TREE); CLASSTYPE_VBASECLASSES (type) = vbase_vec; diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index d96fdf8..21bec72c 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -3091,8 +3091,8 @@ static cp_token *cp_parser_require_keyword (cp_parser *, enum rid, required_token); static bool cp_parser_token_starts_function_definition_p (cp_token *); -static bool cp_parser_next_token_starts_class_definition_p - (cp_parser *); +static bool cp_parser_nth_token_starts_class_definition_p + (cp_parser *, size_t); static bool cp_parser_next_token_ends_template_argument_p (cp_parser *); static bool cp_parser_nth_token_starts_template_argument_list_p @@ -22031,7 +22031,7 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, bool template_p = (template_parm_lists_apply - && (cp_parser_next_token_starts_class_definition_p (parser) + && (cp_parser_nth_token_starts_class_definition_p (parser, 1) || cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))); /* An unqualified name was used to reference this type, so there were no qualifying templates. */ @@ -28068,6 +28068,64 @@ cp_parser_class_specifier (cp_parser* parser) return type; } +/* Parse an (optional) class-property-specifier-seq. + + class-property-specifier-seq: + class-property-specifier class-property-specifier-seq [opt] + + class-property-specifier: + final + + Returns a bitmask representing the class-property-specifiers. */ + +static cp_virt_specifiers +cp_parser_class_property_specifier_seq_opt (cp_parser *parser) +{ + cp_virt_specifiers virt_specifiers = VIRT_SPEC_UNSPECIFIED; + + while (true) + { + cp_token *token; + cp_virt_specifiers virt_specifier; + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* See if it's a class-property-specifier. */ + if (token->type != CPP_NAME) + break; + if (id_equal (token->u.value, "final")) + { + /* For C++98, quietly ignore final in e.g. + struct S final = 24; */ + if (cxx_dialect == cxx98 + && virt_specifiers == VIRT_SPEC_UNSPECIFIED + && !cp_parser_nth_token_starts_class_definition_p (parser, 2) + && !cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)) + break; + maybe_warn_cpp0x (CPP0X_OVERRIDE_CONTROLS); + virt_specifier = VIRT_SPEC_FINAL; + } + else if (id_equal (token->u.value, "__final")) + virt_specifier = VIRT_SPEC_FINAL; + else + break; + + if (virt_specifiers & virt_specifier) + { + gcc_rich_location richloc (token->location); + richloc.add_fixit_remove (); + error_at (&richloc, "duplicate %qD specifier", token->u.value); + cp_lexer_purge_token (parser->lexer); + } + else + { + cp_lexer_consume_token (parser->lexer); + virt_specifiers |= virt_specifier; + } + } + return virt_specifiers; +} + /* Parse a class-head. class-head: @@ -28258,18 +28316,16 @@ cp_parser_class_head (cp_parser* parser, pop_deferring_access_checks (); if (id) - { - cp_parser_check_for_invalid_template_id (parser, id, - class_key, - type_start_token->location); - } - virt_specifiers = cp_parser_virt_specifier_seq_opt (parser); + cp_parser_check_for_invalid_template_id (parser, id, + class_key, + type_start_token->location); + virt_specifiers = cp_parser_class_property_specifier_seq_opt (parser); /* If it's not a `:' or a `{' then we can't really be looking at a class-head, since a class-head only appears as part of a class-specifier. We have to detect this situation before calling xref_tag, since that has irreversible side-effects. */ - if (!cp_parser_next_token_starts_class_definition_p (parser)) + if (!cp_parser_nth_token_starts_class_definition_p (parser, 1)) { cp_parser_error (parser, "expected %<{%> or %<:%>"); type = error_mark_node; @@ -28279,13 +28335,6 @@ cp_parser_class_head (cp_parser* parser, /* At this point, we're going ahead with the class-specifier, even if some other problem occurs. */ cp_parser_commit_to_tentative_parse (parser); - if (virt_specifiers & VIRT_SPEC_OVERRIDE) - { - cp_parser_error (parser, - "cannot specify %<override%> for a class"); - type = error_mark_node; - goto out; - } /* Issue the error about the overly-qualified name now. */ if (qualified_p) { @@ -35654,15 +35703,15 @@ cp_parser_token_starts_function_definition_p (cp_token* token) || token->keyword == RID_RETURN); } -/* Returns TRUE iff the next token is the ":" or "{" beginning a class +/* Returns TRUE iff the Nth token is the ":" or "{" beginning a class definition. */ static bool -cp_parser_next_token_starts_class_definition_p (cp_parser *parser) +cp_parser_nth_token_starts_class_definition_p (cp_parser *parser, size_t n) { cp_token *token; - token = cp_lexer_peek_token (parser->lexer); + token = cp_lexer_peek_nth_token (parser->lexer, n); return (token->type == CPP_OPEN_BRACE || (token->type == CPP_COLON && !parser->colon_doesnt_start_class_def_p)); diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 40ce987..8f3822c 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -20147,7 +20147,14 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl) { tree op0 = RECUR (TREE_OPERAND (t, 0)); tree cond = RECUR (MUST_NOT_THROW_COND (t)); - RETURN (build_must_not_throw_expr (op0, cond)); + stmt = build_must_not_throw_expr (op0, cond); + if (stmt && TREE_CODE (stmt) == MUST_NOT_THROW_EXPR) + { + MUST_NOT_THROW_NOEXCEPT_P (stmt) = MUST_NOT_THROW_NOEXCEPT_P (t); + MUST_NOT_THROW_THROW_P (stmt) = MUST_NOT_THROW_THROW_P (t); + MUST_NOT_THROW_CATCH_P (stmt) = MUST_NOT_THROW_CATCH_P (t); + } + RETURN (stmt); } case EXPR_PACK_EXPANSION: diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc index 5863b68..accce0e 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -488,6 +488,7 @@ builtin_valid_in_constant_expr_p (const_tree decl) case CP_BUILT_IN_SOURCE_LOCATION: case CP_BUILT_IN_IS_CORRESPONDING_MEMBER: case CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS: + case CP_BUILT_IN_EH_PTR_ADJUST_REF: return true; default: break; diff --git a/gcc/internal-fn.cc b/gcc/internal-fn.cc index ed6ef0e..044bdc2 100644 --- a/gcc/internal-fn.cc +++ b/gcc/internal-fn.cc @@ -3442,25 +3442,23 @@ expand_DEFERRED_INIT (internal_fn, gcall *stmt) } /* Expand the IFN_ACCESS_WITH_SIZE function: - ACCESS_WITH_SIZE (REF_TO_OBJ, REF_TO_SIZE, CLASS_OF_SIZE, - TYPE_OF_SIZE, ACCESS_MODE) + ACCESS_WITH_SIZE (REF_TO_OBJ, REF_TO_SIZE, + TYPE_OF_SIZE + ACCESS_MODE, TYPE_SIZE_UNIT for element) which returns the REF_TO_OBJ same as the 1st argument; 1st argument REF_TO_OBJ: The reference to the object; 2nd argument REF_TO_SIZE: The reference to the size of the object, - 3rd argument CLASS_OF_SIZE: The size referenced by the REF_TO_SIZE represents - 0: the number of bytes. - 1: the number of the elements of the object type; - 4th argument TYPE_OF_SIZE: A constant 0 with its TYPE being the same as the TYPE - of the object referenced by REF_TO_SIZE - 5th argument ACCESS_MODE: - -1: Unknown access semantics - 0: none - 1: read_only - 2: write_only - 3: read_write - 6th argument: A constant 0 with the pointer TYPE to the original flexible - array type. + 3rd argument TYPE_OF_SIZE + ACCESS_MODE: An integer constant with a pointer + TYPE. + The pointee TYPE of the pointer TYPE is the TYPE of the object referenced + by REF_TO_SIZE. + The integer constant value represents the ACCESS_MODE: + 0: none + 1: read_only + 2: write_only + 3: read_write + + 4th argument: The TYPE_SIZE_UNIT of the element TYPE of the array. Both the return type and the type of the first argument of this function have been converted from the incomplete array type to diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def index 914ee9f2..d2480a1 100644 --- a/gcc/internal-fn.def +++ b/gcc/internal-fn.def @@ -525,7 +525,7 @@ DEF_INTERNAL_FN (DEFERRED_INIT, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL) /* A function to associate the access size and access mode information with the corresponding reference to an object. It only reads from the - 2nd argument. */ + 2nd and the 4th arguments. */ DEF_INTERNAL_FN (ACCESS_WITH_SIZE, ECF_PURE | ECF_LEAF | ECF_NOTHROW, NULL) /* DIM_SIZE and DIM_POS return the size of a particular compute diff --git a/gcc/optabs-tree.cc b/gcc/optabs-tree.cc index 6dfe8ee..9308a6d 100644 --- a/gcc/optabs-tree.cc +++ b/gcc/optabs-tree.cc @@ -82,6 +82,8 @@ optab_for_tree_code (enum tree_code code, const_tree type, return unknown_optab; /* FALLTHRU */ case RDIV_EXPR: + gcc_assert (FLOAT_TYPE_P (type)); + /* FALLTHRU */ case TRUNC_DIV_EXPR: case EXACT_DIV_EXPR: if (TYPE_SATURATING (type)) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 7cb2440..4aceccb 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,383 @@ +2025-07-10 Jakub Jelinek <jakub@redhat.com> + + PR c++/120628 + * g++.dg/cpp0x/final1.C: New test. + * g++.dg/cpp0x/final2.C: New test. + * g++.dg/cpp0x/override6.C: New test. + +2025-07-10 Jakub Jelinek <jakub@redhat.com> + + PR c++/120569 + * g++.dg/cpp0x/override2.C: Expect different diagnostics with + override or duplicate final. + * g++.dg/cpp0x/override5.C: New test. + * g++.dg/cpp0x/duplicate1.C: Expect different diagnostics with + duplicate final. + +2025-07-10 Jakub Jelinek <jakub@redhat.com> + + PR c++/117785 + * g++.dg/cpp0x/constexpr-ellipsis2.C: Expect different diagnostics for + C++26. + * g++.dg/cpp0x/constexpr-throw.C: Likewise. + * g++.dg/cpp1y/constexpr-84192.C: Expect different diagnostics. + * g++.dg/cpp1y/constexpr-throw.C: Expect different diagnostics for + C++26. + * g++.dg/cpp1z/constexpr-asm-5.C: Likewise. + * g++.dg/cpp26/constexpr-eh1.C: New test. + * g++.dg/cpp26/constexpr-eh2.C: New test. + * g++.dg/cpp26/constexpr-eh3.C: New test. + * g++.dg/cpp26/constexpr-eh4.C: New test. + * g++.dg/cpp26/constexpr-eh5.C: New test. + * g++.dg/cpp26/constexpr-eh6.C: New test. + * g++.dg/cpp26/constexpr-eh7.C: New test. + * g++.dg/cpp26/constexpr-eh8.C: New test. + * g++.dg/cpp26/constexpr-eh9.C: New test. + * g++.dg/cpp26/constexpr-eh10.C: New test. + * g++.dg/cpp26/constexpr-eh11.C: New test. + * g++.dg/cpp26/constexpr-eh12.C: New test. + * g++.dg/cpp26/constexpr-eh13.C: New test. + * g++.dg/cpp26/constexpr-eh14.C: New test. + * g++.dg/cpp26/constexpr-eh15.C: New test. + * g++.dg/cpp26/feat-cxx26.C: Change formatting in __cpp_pack_indexing + and __cpp_pp_embed test. Add __cpp_constexpr_exceptions test. + * g++.dg/cpp26/static_assert1.C: Expect different diagnostics for + C++26. + * g++.dg/cpp2a/consteval34.C: Likewise. + * g++.dg/cpp2a/consteval-memfn1.C: Likewise. + * g++.dg/cpp2a/constexpr-dynamic4.C: For C++26 add std::exception and + std::bad_cast definitions and expect different diagnostics. + * g++.dg/cpp2a/constexpr-dynamic6.C: Likewise. + * g++.dg/cpp2a/constexpr-dynamic7.C: Likewise. + * g++.dg/cpp2a/constexpr-dynamic8.C: Likewise. + * g++.dg/cpp2a/constexpr-dynamic9.C: Likewise. + * g++.dg/cpp2a/constexpr-dynamic11.C: Likewise. + * g++.dg/cpp2a/constexpr-dynamic14.C: Likewise. + * g++.dg/cpp2a/constexpr-dynamic18.C: Likewise. + * g++.dg/cpp2a/constexpr-new27.C: New test. + * g++.dg/cpp2a/constexpr-typeid5.C: New test. + +2025-07-10 Qing Zhao <qing.zhao@oracle.com> + + PR middle-end/121000 + * gcc.dg/flex-array-counted-by-pr121000.c: New test. + +2025-07-10 Mikael Morin <mikael@gcc.gnu.org> + + * gfortran.dg/asan/array_constructor_1.f90: Allocate array + before using it. + +2025-07-10 Jan Hubicka <hubicka@ucw.cz> + + * gcc.dg/tree-prof/afdo-inline.c: Add user symbol names. + +2025-07-10 Richard Sandiford <richard.sandiford@arm.com> + + * gcc.target/aarch64/sve/pfalse-binary.c: Add -funwind-tables. + * gcc.target/aarch64/sve/pfalse-binary_int_opt_n.c: Likewise. + * gcc.target/aarch64/sve/pfalse-binary_opt_n.c: Likewise. + * gcc.target/aarch64/sve/pfalse-binary_opt_single_n.c: Likewise. + * gcc.target/aarch64/sve/pfalse-binary_rotate.c: Likewise. + * gcc.target/aarch64/sve/pfalse-binary_uint64_opt_n.c: Likewise. + * gcc.target/aarch64/sve/pfalse-binary_uint_opt_n.c: Likewise. + * gcc.target/aarch64/sve/pfalse-binaryxn.c: Likewise. + * gcc.target/aarch64/sve/pfalse-clast.c: Likewise. + * gcc.target/aarch64/sve/pfalse-compare_opt_n.c: Likewise. + * gcc.target/aarch64/sve/pfalse-compare_wide_opt_n.c: Likewise. + * gcc.target/aarch64/sve/pfalse-count_pred.c: Likewise. + * gcc.target/aarch64/sve/pfalse-fold_left.c: Likewise. + * gcc.target/aarch64/sve/pfalse-load.c: Likewise. + * gcc.target/aarch64/sve/pfalse-load_ext.c: Likewise. + * gcc.target/aarch64/sve/pfalse-load_ext_gather_index.c: Likewise. + * gcc.target/aarch64/sve/pfalse-load_ext_gather_offset.c: Likewise. + * gcc.target/aarch64/sve/pfalse-load_gather_sv.c: Likewise. + * gcc.target/aarch64/sve/pfalse-load_gather_vs.c: Likewise. + * gcc.target/aarch64/sve/pfalse-load_replicate.c: Likewise. + * gcc.target/aarch64/sve/pfalse-prefetch.c: Likewise. + * gcc.target/aarch64/sve/pfalse-prefetch_gather_index.c: Likewise. + * gcc.target/aarch64/sve/pfalse-prefetch_gather_offset.c: Likewise. + * gcc.target/aarch64/sve/pfalse-ptest.c: Likewise. + * gcc.target/aarch64/sve/pfalse-rdffr.c: Likewise. + * gcc.target/aarch64/sve/pfalse-reduction.c: Likewise. + * gcc.target/aarch64/sve/pfalse-reduction_wide.c: Likewise. + * gcc.target/aarch64/sve/pfalse-shift_right_imm.c: Likewise. + * gcc.target/aarch64/sve/pfalse-store.c: Likewise. + * gcc.target/aarch64/sve/pfalse-store_scatter_index.c: Likewise. + * gcc.target/aarch64/sve/pfalse-store_scatter_offset.c: Likewise. + * gcc.target/aarch64/sve/pfalse-storexn.c: Likewise. + * gcc.target/aarch64/sve/pfalse-ternary_opt_n.c: Likewise. + * gcc.target/aarch64/sve/pfalse-ternary_rotate.c: Likewise. + * gcc.target/aarch64/sve/pfalse-unary.c: Likewise. + * gcc.target/aarch64/sve/pfalse-unary_convert_narrowt.c: Likewise. + * gcc.target/aarch64/sve/pfalse-unary_convertxn.c: Likewise. + * gcc.target/aarch64/sve/pfalse-unary_n.c: Likewise. + * gcc.target/aarch64/sve/pfalse-unary_pred.c: Likewise. + * gcc.target/aarch64/sve/pfalse-unary_to_uint.c: Likewise. + * gcc.target/aarch64/sve/pfalse-unaryxn.c: Likewise. + * gcc.target/aarch64/sve2/pfalse-binary.c: Likewise. + * gcc.target/aarch64/sve2/pfalse-binary_int_opt_n.c: Likewise. + * gcc.target/aarch64/sve2/pfalse-binary_int_opt_single_n.c: Likewise. + * gcc.target/aarch64/sve2/pfalse-binary_opt_n.c: Likewise. + * gcc.target/aarch64/sve2/pfalse-binary_opt_single_n.c: Likewise. + * gcc.target/aarch64/sve2/pfalse-binary_to_uint.c: Likewise. + * gcc.target/aarch64/sve2/pfalse-binary_uint_opt_n.c: Likewise. + * gcc.target/aarch64/sve2/pfalse-binary_wide.c: Likewise. + * gcc.target/aarch64/sve2/pfalse-compare.c: Likewise. + * gcc.target/aarch64/sve2/pfalse-load_ext_gather_index_restricted.c, + * gcc.target/aarch64/sve2/pfalse-load_ext_gather_offset_restricted.c, + * gcc.target/aarch64/sve2/pfalse-load_gather_sv_restricted.c: Likewise. + * gcc.target/aarch64/sve2/pfalse-load_gather_vs.c: Likewise. + * gcc.target/aarch64/sve2/pfalse-shift_left_imm_to_uint.c: Likewise. + * gcc.target/aarch64/sve2/pfalse-shift_right_imm.c: Likewise. + * gcc.target/aarch64/sve2/pfalse-store_scatter_index_restricted.c, + * gcc.target/aarch64/sve2/pfalse-store_scatter_offset_restricted.c, + * gcc.target/aarch64/sve2/pfalse-unary.c: Likewise. + * gcc.target/aarch64/sve2/pfalse-unary_convert.c: Likewise. + * gcc.target/aarch64/sve2/pfalse-unary_convert_narrowt.c: Likewise. + * gcc.target/aarch64/sve2/pfalse-unary_to_int.c: Likewise. + +2025-07-10 Kyrylo Tkachov <ktkachov@nvidia.com> + + PR target/120999 + * gcc.target/aarch64/sve2/pr120999.c: New test. + +2025-07-10 Richard Sandiford <richard.sandiford@arm.com> + + * lib/target-supports.exp (check_effective_target_aarch64_sve2p1_hw): + New proc. + * gcc.target/aarch64/sve2/dupq_1.c: Extend to big-endian. Add + noipa attributes. + * gcc.target/aarch64/sve2/extq_1.c: Likewise. + * gcc.target/aarch64/sve2/uzpq_1.c: Likewise. + * gcc.target/aarch64/sve2/zipq_1.c: Likewise. + * gcc.target/aarch64/sve2/dupq_1_run.c: New test. + * gcc.target/aarch64/sve2/extq_1_run.c: Likewise. + * gcc.target/aarch64/sve2/uzpq_1_run.c: Likewise. + * gcc.target/aarch64/sve2/zipq_1_run.c: Likewise. + +2025-07-10 Jakub Jelinek <jakub@redhat.com> + + * gfortran.dg/g77/980310-3.f: Comment spelling fix: bellow -> below. + * jit.dg/test-debuginfo.c: Likewise. + +2025-07-10 Pan Li <pan2.li@intel.com> + + * gcc.target/riscv/sat/sat_s_add-run-1-i16.c: Take rv32 || rv64 + instead of riscv_v for scalar run test. + * gcc.target/riscv/sat/sat_s_add-run-1-i32.c: Ditto. + * gcc.target/riscv/sat/sat_s_add-run-1-i64.c: Ditto. + * gcc.target/riscv/sat/sat_s_add-run-1-i8.c: Ditto. + * gcc.target/riscv/sat/sat_s_add-run-2-i16.c: Ditto. + * gcc.target/riscv/sat/sat_s_add-run-2-i32.c: Ditto. + * gcc.target/riscv/sat/sat_s_add-run-2-i64.c: Ditto. + * gcc.target/riscv/sat/sat_s_add-run-2-i8.c: Ditto. + * gcc.target/riscv/sat/sat_s_add-run-3-i16.c: Ditto. + * gcc.target/riscv/sat/sat_s_add-run-3-i32.c: Ditto. + * gcc.target/riscv/sat/sat_s_add-run-3-i64.c: Ditto. + * gcc.target/riscv/sat/sat_s_add-run-3-i8.c: Ditto. + * gcc.target/riscv/sat/sat_s_add-run-4-i16.c: Ditto. + * gcc.target/riscv/sat/sat_s_add-run-4-i32.c: Ditto. + * gcc.target/riscv/sat/sat_s_add-run-4-i64.c: Ditto. + * gcc.target/riscv/sat/sat_s_add-run-4-i8.c: Ditto. + * gcc.target/riscv/sat/sat_s_sub-run-1-i16.c: Ditto. + * gcc.target/riscv/sat/sat_s_sub-run-1-i32.c: Ditto. + * gcc.target/riscv/sat/sat_s_sub-run-1-i64.c: Ditto. + * gcc.target/riscv/sat/sat_s_sub-run-1-i8.c: Ditto. + * gcc.target/riscv/sat/sat_s_sub-run-2-i16.c: Ditto. + * gcc.target/riscv/sat/sat_s_sub-run-2-i32.c: Ditto. + * gcc.target/riscv/sat/sat_s_sub-run-2-i64.c: Ditto. + * gcc.target/riscv/sat/sat_s_sub-run-2-i8.c: Ditto. + * gcc.target/riscv/sat/sat_s_sub-run-3-i16.c: Ditto. + * gcc.target/riscv/sat/sat_s_sub-run-3-i32.c: Ditto. + * gcc.target/riscv/sat/sat_s_sub-run-3-i64.c: Ditto. + * gcc.target/riscv/sat/sat_s_sub-run-3-i8.c: Ditto. + * gcc.target/riscv/sat/sat_s_sub-run-4-i16.c: Ditto. + * gcc.target/riscv/sat/sat_s_sub-run-4-i32.c: Ditto. + * gcc.target/riscv/sat/sat_s_sub-run-4-i64.c: Ditto. + * gcc.target/riscv/sat/sat_s_sub-run-4-i8.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-1-i16-to-i8.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-1-i32-to-i16.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-1-i32-to-i8.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-1-i64-to-i16.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-1-i64-to-i32.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-1-i64-to-i8.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-2-i16-to-i8.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-2-i32-to-i16.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-2-i32-to-i8.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-2-i64-to-i16.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-2-i64-to-i32.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-2-i64-to-i8.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-3-i16-to-i8.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-3-i32-to-i16.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-3-i32-to-i8.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-3-i64-to-i16.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-3-i64-to-i32.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-3-i64-to-i8.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-4-i16-to-i8.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-4-i32-to-i16.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-4-i32-to-i8.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-4-i64-to-i16.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-4-i64-to-i32.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-4-i64-to-i8.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-5-i16-to-i8.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-5-i32-to-i16.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-5-i32-to-i8.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-5-i64-to-i16.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-5-i64-to-i32.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-5-i64-to-i8.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-6-i16-to-i8.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-6-i32-to-i16.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-6-i32-to-i8.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-6-i64-to-i16.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-6-i64-to-i32.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-6-i64-to-i8.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-7-i16-to-i8.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-7-i32-to-i16.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-7-i32-to-i8.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-7-i64-to-i16.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-7-i64-to-i32.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-7-i64-to-i8.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-8-i16-to-i8.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-8-i32-to-i16.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-8-i32-to-i8.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-8-i64-to-i16.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-8-i64-to-i32.c: Ditto. + * gcc.target/riscv/sat/sat_s_trunc-run-8-i64-to-i8.c: Ditto. + * gcc.target/riscv/sat/sat_u_add-run-1-u16.c: Ditto. + * gcc.target/riscv/sat/sat_u_add-run-1-u32.c: Ditto. + * gcc.target/riscv/sat/sat_u_add-run-1-u64.c: Ditto. + * gcc.target/riscv/sat/sat_u_add-run-1-u8.c: Ditto. + * gcc.target/riscv/sat/sat_u_add-run-2-u16.c: Ditto. + * gcc.target/riscv/sat/sat_u_add-run-2-u32.c: Ditto. + * gcc.target/riscv/sat/sat_u_add-run-2-u64.c: Ditto. + * gcc.target/riscv/sat/sat_u_add-run-2-u8.c: Ditto. + * gcc.target/riscv/sat/sat_u_add-run-3-u16.c: Ditto. + * gcc.target/riscv/sat/sat_u_add-run-3-u32.c: Ditto. + * gcc.target/riscv/sat/sat_u_add-run-3-u64.c: Ditto. + * gcc.target/riscv/sat/sat_u_add-run-3-u8.c: Ditto. + * gcc.target/riscv/sat/sat_u_add-run-4-u16.c: Ditto. + * gcc.target/riscv/sat/sat_u_add-run-4-u32.c: Ditto. + * gcc.target/riscv/sat/sat_u_add-run-4-u64.c: Ditto. + * gcc.target/riscv/sat/sat_u_add-run-4-u8.c: Ditto. + * gcc.target/riscv/sat/sat_u_add-run-5-u16.c: Ditto. + * gcc.target/riscv/sat/sat_u_add-run-5-u32.c: Ditto. + * gcc.target/riscv/sat/sat_u_add-run-5-u64.c: Ditto. + * gcc.target/riscv/sat/sat_u_add-run-5-u8.c: Ditto. + * gcc.target/riscv/sat/sat_u_add-run-6-u16.c: Ditto. + * gcc.target/riscv/sat/sat_u_add-run-6-u32.c: Ditto. + * gcc.target/riscv/sat/sat_u_add-run-6-u64.c: Ditto. + * gcc.target/riscv/sat/sat_u_add-run-6-u8.c: Ditto. + * gcc.target/riscv/sat/sat_u_add-run-7-u16-from-u32.c: Ditto. + * gcc.target/riscv/sat/sat_u_add-run-7-u16-from-u64.c: Ditto. + * gcc.target/riscv/sat/sat_u_add-run-7-u32-from-u64.c: Ditto. + * gcc.target/riscv/sat/sat_u_add-run-7-u8-from-u16.c: Ditto. + * gcc.target/riscv/sat/sat_u_add-run-7-u8-from-u32.c: Ditto. + * gcc.target/riscv/sat/sat_u_add-run-7-u8-from-u64.c: Ditto. + * gcc.target/riscv/sat/sat_u_add_imm-run-1-u16.c: Ditto. + * gcc.target/riscv/sat/sat_u_add_imm-run-1-u32.c: Ditto. + * gcc.target/riscv/sat/sat_u_add_imm-run-1-u64.c: Ditto. + * gcc.target/riscv/sat/sat_u_add_imm-run-1-u8.c: Ditto. + * gcc.target/riscv/sat/sat_u_add_imm-run-2-u16.c: Ditto. + * gcc.target/riscv/sat/sat_u_add_imm-run-2-u32.c: Ditto. + * gcc.target/riscv/sat/sat_u_add_imm-run-2-u64.c: Ditto. + * gcc.target/riscv/sat/sat_u_add_imm-run-2-u8.c: Ditto. + * gcc.target/riscv/sat/sat_u_add_imm-run-3-u16.c: Ditto. + * gcc.target/riscv/sat/sat_u_add_imm-run-3-u32.c: Ditto. + * gcc.target/riscv/sat/sat_u_add_imm-run-3-u64.c: Ditto. + * gcc.target/riscv/sat/sat_u_add_imm-run-3-u8.c: Ditto. + * gcc.target/riscv/sat/sat_u_add_imm-run-4-u16.c: Ditto. + * gcc.target/riscv/sat/sat_u_add_imm-run-4-u32.c: Ditto. + * gcc.target/riscv/sat/sat_u_add_imm-run-4-u64.c: Ditto. + * gcc.target/riscv/sat/sat_u_add_imm-run-4-u8.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-1-u16.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-1-u32.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-1-u64.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-1-u8.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-10-u16.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-10-u32.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-10-u64.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-10-u8.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-11-u16.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-11-u32.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-11-u64.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-11-u8.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-12-u16.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-12-u32.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-12-u64.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-12-u8.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-2-u16.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-2-u32.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-2-u64.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-2-u8.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-3-u16.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-3-u32.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-3-u64.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-3-u8.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-4-u16.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-4-u32.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-4-u64.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-4-u8.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-5-u16.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-5-u32.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-5-u64.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-5-u8.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-6-u16.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-6-u32.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-6-u64.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-6-u8.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-7-u16.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-7-u32.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-7-u64.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-7-u8.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-8-u16.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-8-u32.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-8-u64.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-8-u8.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-9-u16.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-9-u32.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-9-u64.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub-run-9-u8.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub_imm-run-1-u16.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub_imm-run-1-u32.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub_imm-run-1-u64.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub_imm-run-1-u8.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub_imm-run-2-u16.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub_imm-run-2-u32.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub_imm-run-2-u64.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub_imm-run-2-u8.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub_imm-run-3-u16.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub_imm-run-3-u32.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub_imm-run-3-u64.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub_imm-run-3-u8.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub_imm-run-4-u16.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub_imm-run-4-u32.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub_imm-run-4-u64.c: Ditto. + * gcc.target/riscv/sat/sat_u_sub_imm-run-4-u8.c: Ditto. + * gcc.target/riscv/sat/sat_u_trunc-run-1-u16.c: Ditto. + * gcc.target/riscv/sat/sat_u_trunc-run-1-u32.c: Ditto. + * gcc.target/riscv/sat/sat_u_trunc-run-1-u64.c: Ditto. + * gcc.target/riscv/sat/sat_u_trunc-run-1-u8.c: Ditto. + * gcc.target/riscv/sat/sat_u_trunc-run-2-u16.c: Ditto. + * gcc.target/riscv/sat/sat_u_trunc-run-2-u32.c: Ditto. + * gcc.target/riscv/sat/sat_u_trunc-run-2-u64.c: Ditto. + * gcc.target/riscv/sat/sat_u_trunc-run-2-u8.c: Ditto. + * gcc.target/riscv/sat/sat_u_trunc-run-3-u16.c: Ditto. + * gcc.target/riscv/sat/sat_u_trunc-run-3-u32.c: Ditto. + * gcc.target/riscv/sat/sat_u_trunc-run-3-u64.c: Ditto. + * gcc.target/riscv/sat/sat_u_trunc-run-3-u8.c: Ditto. + * gcc.target/riscv/sat/sat_u_trunc-run-4-u16.c: Ditto. + * gcc.target/riscv/sat/sat_u_trunc-run-4-u32.c: Ditto. + * gcc.target/riscv/sat/sat_u_trunc-run-4-u64.c: Ditto. + * gcc.target/riscv/sat/sat_u_trunc-run-4-u8.c: Ditto. + * gcc.target/riscv/sat/sat_u_trunc-run-5-u16.c: Ditto. + * gcc.target/riscv/sat/sat_u_trunc-run-5-u32.c: Ditto. + * gcc.target/riscv/sat/sat_u_trunc-run-5-u64.c: Ditto. + * gcc.target/riscv/sat/sat_u_trunc-run-5-u8.c: Ditto. + * gcc.target/riscv/sat/sat_u_trunc-run-6-u16.c: Ditto. + * gcc.target/riscv/sat/sat_u_trunc-run-6-u32.c: Ditto. + * gcc.target/riscv/sat/sat_u_trunc-run-6-u64.c: Ditto. + * gcc.target/riscv/sat/sat_u_trunc-run-6-u8.c: Ditto. + 2025-07-09 Jason Merrill <jason@redhat.com> PR c++/120243 diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ellipsis2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ellipsis2.C index b6a5323..c473257 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-ellipsis2.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ellipsis2.C @@ -9,4 +9,6 @@ struct A constexpr int ellipsis(...) { return 1; } -static_assert(ellipsis(A().empty()), "Error"); // { dg-error "non-constant condition|empty" } +static_assert(ellipsis(A().empty()), "Error"); // { dg-error "non-constant condition" } +// { dg-error "call to non-'constexpr' function 'bool A::empty\\\(\\\)'" "" { target c++23_down } .-1 } +// { dg-error "temporary of non-literal type 'A' in a constant expression" "" { target c++26 } .-2 } diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-throw.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-throw.C index 9c49fa4..9abf4a3 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-throw.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-throw.C @@ -2,8 +2,8 @@ // Explicit { dg-require-effective-target exceptions_enabled } to avoid verify compiler messages FAILs for '-fno-exceptions'. constexpr int may_throw(bool decide) { - return decide ? 42 : throw -1; // { dg-error "throw" } + return decide ? 42 : throw -1; // { dg-error "throw" "" { target c++23_down } } } -constexpr int x = may_throw(false); // { dg-message "may_throw" } -constexpr int y = may_throw(true); +constexpr int x = may_throw(false); // { dg-message "may_throw" "" { target c++23_down } } +constexpr int y = may_throw(true); // { dg-error "uncaught exception '-1'" "" { target c++26 } .-1 } diff --git a/gcc/testsuite/g++.dg/cpp0x/duplicate1.C b/gcc/testsuite/g++.dg/cpp0x/duplicate1.C index 1545e1c..4e85edc 100644 --- a/gcc/testsuite/g++.dg/cpp0x/duplicate1.C +++ b/gcc/testsuite/g++.dg/cpp0x/duplicate1.C @@ -6,7 +6,7 @@ struct A virtual void foo() const; }; -struct B final final : A /* { dg-error "duplicate virt-specifier" } +struct B final final : A /* { dg-error "duplicate 'final' specifier" } { dg-begin-multiline-output "" } struct B final final : A ^~~~~ diff --git a/gcc/testsuite/g++.dg/cpp0x/final1.C b/gcc/testsuite/g++.dg/cpp0x/final1.C new file mode 100644 index 0000000..1d64095 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/final1.C @@ -0,0 +1,11 @@ +// PR c++/120628 +// { dg-do compile { target c++98_only } } + +namespace A { + struct B {}; + struct B final = {}; +} +namespace C { + struct D { D (int, int); }; + struct D final (42, 0); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/final2.C b/gcc/testsuite/g++.dg/cpp0x/final2.C new file mode 100644 index 0000000..d8d5866 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/final2.C @@ -0,0 +1,26 @@ +// PR c++/120628 +// { dg-do compile } +// { dg-options "" } +// { dg-additional-options "-pedantic" { target c++14 } } + +namespace U { + struct A {}; + struct A final = {}; +} +namespace V { + template <int N> + struct B {}; + template <int N> + struct B<N> final = {}; // { dg-warning "variable templates only available with" "" { target c++11_down } } +} +struct C { + struct D {}; + static D foo (); + struct D final = foo (); // { dg-warning "non-static data member initializers only available with" "" { target c++98_only } } +}; +namespace W { + struct E { struct F {}; }; + struct E::F final = {}; +} +template <int N> +struct V::B<N> final = {}; // { dg-warning "variable templates only available with" "" { target c++11_down } } diff --git a/gcc/testsuite/g++.dg/cpp0x/override2.C b/gcc/testsuite/g++.dg/cpp0x/override2.C index ab4dec4..d7f542e 100644 --- a/gcc/testsuite/g++.dg/cpp0x/override2.C +++ b/gcc/testsuite/g++.dg/cpp0x/override2.C @@ -23,9 +23,9 @@ struct D5 : B3<D5> {}; struct D6 : B4<D6> {}; // { dg-error "cannot derive from 'final' base" } -struct B6 final final {}; // { dg-error "duplicate virt-specifier" } +struct B6 final final {}; // { dg-error "duplicate 'final' specifier" } -struct B7 override {}; // { dg-error "cannot specify 'override' for a class" } +struct B7 override {}; // { dg-error "variable 'B7 override' has initializer but incomplete type" } namespace N { @@ -45,7 +45,7 @@ int main() struct B2 final; // { dg-error "redeclaration" } struct B2 override; // { dg-message "previously declared here" } struct B2 final {}; // { dg-error "redefinition" } - struct B2 override {}; // { dg-error "cannot specify 'override' for a class" } + struct B2 override {}; // { dg-error "redeclaration of 'main\\\(\\\)::B2 override'" } B2 override{}; // { dg-error "redeclaration" } struct foo final {}; // { dg-message "previous definition" } struct foo final {}; // { dg-error "redefinition" } diff --git a/gcc/testsuite/g++.dg/cpp0x/override5.C b/gcc/testsuite/g++.dg/cpp0x/override5.C new file mode 100644 index 0000000..3382c14 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/override5.C @@ -0,0 +1,26 @@ +// PR c++/120569 +// { dg-do compile } +// { dg-options "" } +// { dg-additional-options "-pedantic" { target c++14 } } + +namespace U { + struct A {}; + struct A override {}; // { dg-warning "extended initializer lists only available with" "" { target c++98_only } } +} +namespace V { + template <int N> + struct B {}; + template <int N> + struct B<N> override {}; // { dg-warning "extended initializer lists only available with" "" { target c++98_only } } +} // { dg-warning "variable templates only available with" "" { target c++11_down } .-1 } +struct C { + struct D {}; + struct D override {}; // { dg-warning "extended initializer lists only available with" "" { target c++98_only } } +}; // { dg-warning "non-static data member initializers only available with" "" { target c++98_only } .-1 } +namespace W { + struct E { struct F {}; }; + struct E::F override {}; // { dg-warning "extended initializer lists only available with" "" { target c++98_only } } +} +template <int N> +struct V::B<N> override {}; // { dg-warning "extended initializer lists only available with" "" { target c++98_only } } + // { dg-warning "variable templates only available with" "" { target c++11_down } .-1 } diff --git a/gcc/testsuite/g++.dg/cpp0x/override6.C b/gcc/testsuite/g++.dg/cpp0x/override6.C new file mode 100644 index 0000000..601e91d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/override6.C @@ -0,0 +1,26 @@ +// PR c++/120628 +// { dg-do compile } +// { dg-options "" } +// { dg-additional-options "-pedantic" { target c++14 } } + +namespace U { + struct A {}; + struct A override = {}; +} +namespace V { + template <int N> + struct B {}; + template <int N> + struct B<N> override = {}; // { dg-warning "variable templates only available with" "" { target c++11_down } } +} +struct C { + struct D {}; + static D foo (); + struct D override = foo (); // { dg-warning "non-static data member initializers only available with" "" { target c++98_only } } +}; +namespace W { + struct E { struct F {}; }; + struct E::F override = {}; +} +template <int N> +struct V::B<N> override = {}; // { dg-warning "variable templates only available with" "" { target c++11_down } } diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-84192.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-84192.C index f7439d8..18efd23 100644 --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-84192.C +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-84192.C @@ -12,7 +12,7 @@ void f2 () { for (;;) - constexpr bool b = ({ break; false; }) && false; // { dg-error "is not a constant expression" } + constexpr bool b = ({ break; false; }) && false; // { dg-error "'break' outside of a loop or 'switch'" } } constexpr bool diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-throw.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-throw.C index b5fa6ca..75e2fb8 100644 --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-throw.C +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-throw.C @@ -27,8 +27,8 @@ constexpr int fun(int n) { case 0: return 1; default: - throw; // { dg-error "not a constant expression" } - } + throw; // { dg-error "not a constant expression" "" { target c++23_down } } + } // { dg-error "'void __cxa_rethrow\\\(\\\)' called with no caught exceptions active" "" { target c++26 } .-1 } } static_assert(fun(0), ""); diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-asm-5.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-asm-5.C index 35beb27..2c69b3b 100644 --- a/gcc/testsuite/g++.dg/cpp1z/constexpr-asm-5.C +++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-asm-5.C @@ -18,7 +18,7 @@ struct H { short size () const { return 0; } constexpr const char *data () const { return ""; } }; struct I { constexpr signed char size () const { return 0; } const char *data () const { return ""; } }; -struct J { constexpr int size () const { return j ? throw 1 : 0; } // { dg-error "expression '<throw-expression>' is not a constant expression" } +struct J { constexpr int size () const { return j ? throw 1 : 0; } // { dg-error "expression '<throw-expression>' is not a constant expression" "" { target c++23_down } } constexpr const char *data () const { return ""; }; constexpr J (int x) : j (x) {} int j; }; @@ -114,6 +114,7 @@ foo () asm ((J (0))); asm ("" :: (J (1)) (1)); // { dg-error "constexpr string 'size\\\(\\\)' must be a constant expression" } + // { dg-error "uncaught exception '1'" "" { target c++26 } .-1 } asm ((M {})); #if __cpp_constexpr_dynamic_alloc >= 201907L asm ((N {})); // { dg-error "constexpr string 'data\\\(\\\)\\\[0\\\]' must be a constant expression" "" { target c++20 } } @@ -188,6 +189,7 @@ bar () asm ((J (0))); asm ("" :: (J (1)) (1)); // { dg-error "constexpr string 'size\\\(\\\)' must be a constant expression" } + // { dg-error "uncaught exception '1'" "" { target c++26 } .-1 } asm ((M {})); #if __cpp_constexpr_dynamic_alloc >= 201907L asm ((N {})); // { dg-error "constexpr string 'data\\\(\\\)\\\[0\\\]' must be a constant expression" "" { target c++20 } } @@ -272,7 +274,7 @@ namespace NN #if __cplusplus >= 201402L struct J { static constexpr int size () { return 0; } - static constexpr const char *data (int x = 0) { if (x) return nullptr; else throw 1; } }; // { dg-error "expression '<throw-expression>' is not a constant expression" "" { target c++14 } } + static constexpr const char *data (int x = 0) { if (x) return nullptr; else throw 1; } }; // { dg-error "expression '<throw-expression>' is not a constant expression" "" { target { c++14 && c++23_down } } } #endif #if __cpp_if_consteval >= 202106L struct K { @@ -284,12 +286,12 @@ namespace NN static constexpr const char *data () { if consteval { return "test"; } else { throw 1; } } }; struct M { - static constexpr int size () { if consteval { throw 1; } else { return 4; } } // { dg-error "expression '<throw-expression>' is not a constant expression" "" { target c++23 } } + static constexpr int size () { if consteval { throw 1; } else { return 4; } } // { dg-error "expression '<throw-expression>' is not a constant expression" "" { target c++23_only } } static constexpr const char *data () { return "test"; } }; struct N { static constexpr int size () { return 4; } - static constexpr const char *data () { if consteval { throw 1; } else { return "test"; } } // { dg-error "expression '<throw-expression>' is not a constant expression" "" { target c++23 } } + static constexpr const char *data () { if consteval { throw 1; } else { return "test"; } } // { dg-error "expression '<throw-expression>' is not a constant expression" "" { target c++23_only } } }; #endif struct O { constexpr int operator () () const { return 12; } }; @@ -318,12 +320,15 @@ namespace NN asm ((I {})); #if __cplusplus >= 201402L asm ((J {})); // { dg-error "constexpr string 'data\\\(\\\)' must be a core constant expression" "" { target c++14 } } + // { dg-error "uncaught exception '1'" "" { target c++26 } .-1 } #endif #if __cpp_if_consteval >= 202106L asm ((K {})); asm ((L {})); asm ((M {})); // { dg-error "constexpr string 'size\\\(\\\)' must be a constant expression" "" { target c++23 } } + // { dg-error "uncaught exception '1'" "" { target c++26 } .-1 } asm ((N {})); // { dg-error "constexpr string 'data\\\(\\\)\\\[0\\\]' must be a constant expression" "" { target c++23 } } + // { dg-error "uncaught exception '1'" "" { target c++26 } .-1 } #endif asm ((Q {})); asm ((R {})); @@ -348,12 +353,15 @@ namespace NN asm ((I {})); #if __cplusplus >= 201402L asm ((J {})); // { dg-error "constexpr string 'data\\\(\\\)' must be a core constant expression" "" { target c++14 } } + // { dg-error "uncaught exception '1'" "" { target c++26 } .-1 } #endif #if __cpp_if_consteval >= 202106L asm ((K {})); asm ((L {})); asm ((M {})); // { dg-error "constexpr string 'size\\\(\\\)' must be a constant expression" "" { target c++23 } } + // { dg-error "uncaught exception '1'" "" { target c++26 } .-1 } asm ((N {})); // { dg-error "constexpr string 'data\\\(\\\)\\\[0\\\]' must be a constant expression" "" { target c++23 } } + // { dg-error "uncaught exception '1'" "" { target c++26 } .-1 } #endif asm ((Q {})); asm ((R {})); diff --git a/gcc/testsuite/g++.dg/cpp26/constexpr-eh1.C b/gcc/testsuite/g++.dg/cpp26/constexpr-eh1.C new file mode 100644 index 0000000..9eed3aa --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/constexpr-eh1.C @@ -0,0 +1,140 @@ +// C++26 P3068R5 - Allowing exception throwing in constant-evaluation +// { dg-do compile { target c++26 } } +// { dg-require-effective-target exceptions_enabled } + +struct S { + constexpr S () : s (new int (0)) {} + constexpr S (int x) : s (new int (x)) {} + constexpr S (const S &x) : s (new int (*x.s)) {} + constexpr ~S () { delete s; } + int *s; +}; +struct T : public S { + constexpr T () : S () {} + constexpr T (int x) : S (x) {} + constexpr T (const T &x) : S (*x.s) {} + constexpr ~T () {} +}; +struct U : public T { + constexpr U () : T () {} + constexpr U (int x) : T (x) {} + constexpr U (const U &x) : T (*x.s) {} + constexpr ~U () {} +}; +struct V : public T { + constexpr V () : T () {} + constexpr V (int x) : T (x) {} + constexpr V (const U &x) : T (*x.s) {} + constexpr ~V () {} +}; + +template <typename X> +constexpr int +foo (X x) +{ + try { throw x; } + catch (int &a) { return 42 + a; } + catch (const unsigned b) { return 43 + b; } + catch (const long &c) { return 44 + c; } + catch (bool d) { return 45 + d; } + catch (const U &e) { return 46 + *e.s; } + catch (const T &f) { return 47 + *f.s; } + catch (S g) { return 48 + *g.s; } + catch (int *const &h) { return 49; } + catch (long long *) { return 50; } + catch (const S *const &) { return 51; } + catch (...) { return 52; } +} + +template <typename X> +constexpr int +bar (const X &x) +{ + throw x; +} + +template <typename X> +constexpr int +baz (const X &x) +{ + try + { + try { bar (x); } + catch (int &a) { a += 80; throw; } + catch (long b) { b += 80; throw; } + catch (U &c) { c.s[0] += 82; throw; } + catch (V d) { d.s[0] += 83; throw; } + } + catch (int a) { return 42 + a; } + catch (const long &b) { return 43 + b; } + catch (S &c) { return 44 + c.s[0]; } + catch (long long d) { return 45 + d; } + catch (...) { return -1; } +} + +constexpr int +qux (int x, bool y = true) +{ + try + { + switch (x) + { + case 0: throw 42; break; + case 1: x = y ? throw 43 : 5; break; + case 2: x = -(throw 44, 6); break; + case 3: x = x + (throw 45, 7); break; + case 4: x = (throw 46, 8) + x; break; + case 5: x = (throw 47, y) ? 4 : 5; break; + case 6: x += (throw 48, y); break; + case 7: x = (double) (throw 49, y); break; + case 8: x = foo ((throw 50, x)); break; + default: break; + } + } + catch (int a) { return a; } + return -1; +} + +constexpr int +corge () +{ + try { throw 0; } + catch (int *const &h) { return 49; } + catch (long long *) { return 50; } + catch (const S *const &) { return 51; } + catch (...) { return 52; } +} + +static_assert (foo (12) == 54); +static_assert (foo (12U) == 55); +static_assert (foo (12L) == 56); +static_assert (foo (false) == 45); +static_assert (foo (true) == 46); +static_assert (foo (U (12)) == 58); +static_assert (foo (T (20)) == 67); +static_assert (foo (S (30)) == 78); +static_assert (foo (nullptr) == 49); +static_assert (foo ((int *)nullptr) == 49); +static_assert (foo ((long long *)nullptr) == 50); +static_assert (foo ((const S *)nullptr) == 51); +static_assert (foo ((const T *)nullptr) == 51); +static_assert (foo ((const U *)nullptr) == 51); +static_assert (foo (12ULL) == 52); +static_assert (baz (5) == 127); +static_assert (baz (6L) == 49); +static_assert (baz (U (25)) == 151); +static_assert (baz (V (26)) == 70); +static_assert (baz (T (27)) == 71); +static_assert (baz (S (28)) == 72); +static_assert (baz (7LL) == 52); +static_assert (baz (8ULL) == -1); +static_assert (qux (0) == 42); +static_assert (qux (1) == 43); +static_assert (qux (2) == 44); +static_assert (qux (3) == 45); +static_assert (qux (4) == 46); +static_assert (qux (5) == 47); +static_assert (qux (6) == 48); +static_assert (qux (7) == 49); +static_assert (qux (8) == 50); +static_assert (corge () == 52); diff --git a/gcc/testsuite/g++.dg/cpp26/constexpr-eh10.C b/gcc/testsuite/g++.dg/cpp26/constexpr-eh10.C new file mode 100644 index 0000000..a86cc4d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/constexpr-eh10.C @@ -0,0 +1,110 @@ +// C++26 P3068R5 - Allowing exception throwing in constant-evaluation +// { dg-do compile { target c++26 } } +// { dg-require-effective-target exceptions_enabled } + +struct S { +}; +struct T { + constexpr ~T () noexcept (false) { throw S {}; } +}; +struct U { + int u; +}; +struct V { + int v; + constexpr V (int x) + try : v { x } + { + if (v > 42) + throw U { 42 }; + } + catch (U &u) + { + --u.u; + } +}; +struct W { + constexpr ~W () { ++w; } + int &w; +}; +struct X : public V { + constexpr X (int x) + try : V(x) + { + } + catch (U &u) + { + --u.u; + } +}; + +constexpr int +foo (bool x) +{ + try + { + T t; // { dg-error "'std::terminate' called after throwing an exception '42'" } + if (x) // { dg-message "destructor exited with an exception" "" { target *-*-* } .-1 } + throw 42; + return 10; + } + catch (S) + { + return 11; + } +} + +constexpr int +bar () +{ + V v { 42 }; + try + { + V w { 43 }; + } + catch (const U &u) + { + if (u.u == 41) + return 44; + } + return -1; +} + +constexpr int +baz () +{ + int i = 42; + try + { + W w { i }; + throw S (); + } + catch (...) + { + if (i == 43) + return 42; + } + return -1; +} + +constexpr int +qux () +{ + X v { 42 }; + try + { + X w { 43 }; + } + catch (const U &u) + { + if (u.u == 40) + return 48; + } + return -1; +} + +static_assert (foo (false) == 11); +constexpr int a = foo (true); // { dg-message "in 'constexpr' expansion of" } +static_assert (bar () == 44); +static_assert (baz () == 42); +static_assert (qux () == 48); diff --git a/gcc/testsuite/g++.dg/cpp26/constexpr-eh11.C b/gcc/testsuite/g++.dg/cpp26/constexpr-eh11.C new file mode 100644 index 0000000..287e066 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/constexpr-eh11.C @@ -0,0 +1,69 @@ +// C++26 P3068R5 - Allowing exception throwing in constant-evaluation +// { dg-do compile { target c++26 } } +// { dg-require-effective-target exceptions_enabled } + +struct A { + explicit constexpr A (int x) noexcept : a (x) {} + constexpr virtual int foo () const noexcept { return a; } + constexpr virtual ~A () {} + int a; +}; +struct B : public A { + explicit constexpr B (int x) noexcept : A (x) {} + constexpr int foo () const noexcept override { return a | 0x10; } +}; +struct C : public A { + explicit constexpr C (int x) noexcept : A (x) {} +}; +struct D : public A { + explicit constexpr D (int x) noexcept : A (x) {} +}; +struct E { + constexpr E () noexcept : e (0) {} + explicit constexpr E (int x) noexcept : e (x) {} + int e; +}; +struct F : public E, public B { + explicit constexpr F (int x) noexcept : B (x) {} +}; +struct G : public E, public C { + explicit constexpr G (int x) noexcept : C (x) {} +}; +struct H : public E, public D { + explicit constexpr H (int x) noexcept : D (x) {} +}; + +consteval int +bar (void (*fn) ()) +{ + try + { + fn (); + } + catch (C &a) + { + return a.foo () | 0x20; + } + catch (const C &b) // { dg-warning "exception of type 'C' will be caught by earlier handler" } + { + return b.foo () | 0x60; + } + catch (A &c) + { + return c.foo (); + } + catch (const A &d) // { dg-warning "exception of type 'A' will be caught by earlier handler" } + { + return d.foo () | 0x40; + } + return -1; +} + +static_assert (bar ([] { throw A { 1 }; }) == 1); +static_assert (bar ([] { throw B { 2 }; }) == 0x12); +static_assert (bar ([] { throw C { 3 }; }) == 0x23); +static_assert (bar ([] { throw D { 4 }; }) == 4); +constexpr int a = bar ([] { throw E { 5 }; }); // { dg-error "uncaught exception 'E\\\{5\\\}'" } +static_assert (bar ([] { throw F { 6 }; }) == 0x16); +static_assert (bar ([] { throw G { 7 }; }) == 0x27); +static_assert (bar ([] { throw H { 8 }; }) == 8); diff --git a/gcc/testsuite/g++.dg/cpp26/constexpr-eh12.C b/gcc/testsuite/g++.dg/cpp26/constexpr-eh12.C new file mode 100644 index 0000000..4a85f15 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/constexpr-eh12.C @@ -0,0 +1,74 @@ +// C++26 P3068R5 - Allowing exception throwing in constant-evaluation +// { dg-do compile { target c++26 } } +// { dg-require-effective-target exceptions_enabled } + +struct A { + explicit constexpr A (int x) noexcept : a (x) {} + constexpr virtual int foo () const noexcept { return a; } + constexpr virtual ~A () {} + int a; +}; +struct B : public A { + explicit constexpr B (int x) noexcept : A (x) {} + constexpr int foo () const noexcept override { return a | 0x10; } +}; +struct C : public A { + explicit constexpr C (int x) noexcept : A (x) {} +}; +struct D : public A { + explicit constexpr D (int x) noexcept : A (x) {} +}; +struct E { + constexpr E () noexcept : e (0) {} + explicit constexpr E (int x) noexcept : e (x) {} + int e; +}; +struct F : public E, public B { + explicit constexpr F (int x) noexcept : B (x) {} +}; +struct G : public E, public C { + explicit constexpr G (int x) noexcept : C (x) {} +}; +struct H : public E, public D { + explicit constexpr H (int x) noexcept : D (x) {} +}; + +consteval int +bar (void (*fn) ()) +{ + int r = 0; + try + { + fn (); + } + catch (C *a) + { + r = a->foo () | 0x20; + delete a; + } + catch (const C *b) + { + r = b->foo () | 0x60; + delete b; + } + catch (A *c) + { + r = c->foo (); + delete c; + } + catch (const A *d) + { + r = d->foo () | 0x40; + delete d; + } + return r; +} + +static_assert (bar ([] { throw new A { 1 }; }) == 1); +static_assert (bar ([] { throw new B { 2 }; }) == 0x12); +static_assert (bar ([] { throw new C { 3 }; }) == 0x23); +static_assert (bar ([] { throw new D { 4 }; }) == 4); +constexpr int a = bar ([] { throw new E { 5 }; }); // { dg-error "uncaught exception of type 'E\\\*'" } +static_assert (bar ([] { throw new F { 6 }; }) == 0x16); +static_assert (bar ([] { throw new G { 7 }; }) == 0x27); +static_assert (bar ([] { throw new H { 8 }; }) == 8); diff --git a/gcc/testsuite/g++.dg/cpp26/constexpr-eh13.C b/gcc/testsuite/g++.dg/cpp26/constexpr-eh13.C new file mode 100644 index 0000000..d62771c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/constexpr-eh13.C @@ -0,0 +1,36 @@ +// C++26 P3068R5 - Allowing exception throwing in constant-evaluation +// { dg-do compile { target c++26 } } +// { dg-require-effective-target exceptions_enabled } + +template <typename T> +consteval T +foo (T x) +{ + try + { + throw &x; + } + catch (void *ptr) // { dg-message "for type 'void\\\*'" } + { + return *static_cast<T *> (ptr) | 0x10; + } + catch (const void *ptr) // { dg-message "for type 'const void\\\*'" } + { + return *static_cast<const T *> (ptr) | 0x20; + } + catch (T *ptr) // { dg-warning "exception of type 'T\\\*' will be caught by earlier handler" } + { // { dg-warning "exception of type 'int\\\*' will be caught by earlier handler" "" { target *-*-* } .-1 } + return *ptr | 0x30; // { dg-warning "exception of type 'long long unsigned int\\\*' will be caught by earlier handler" "" { target *-*-* } .-2 } + } + catch (const T *ptr) + { + return *ptr | 0x40; + } + catch (...) + { + return -1; + } +} + +static_assert (foo (1) == 0x11); +static_assert (foo (2ULL) == 0x12ULL); diff --git a/gcc/testsuite/g++.dg/cpp26/constexpr-eh14.C b/gcc/testsuite/g++.dg/cpp26/constexpr-eh14.C new file mode 100644 index 0000000..3e52f2b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/constexpr-eh14.C @@ -0,0 +1,42 @@ +// C++26 P3068R5 - Allowing exception throwing in constant-evaluation +// { dg-do compile { target c++26 } } +// { dg-require-effective-target exceptions_enabled } + +template <typename T> +constexpr T +foo (T x, auto... y) +{ + const T z[] = { x, y... }; + try + { + throw z; + } + catch (const T (&a)[4]) + { + return T (); + } + catch (const T *b) + { + return b[0]; + } + catch (...) + { + return T (); + } +} + +void +bar () +{ +} + +void +baz () +{ +} + +static_assert (foo (42, 43, 44, 45, 46) == 42); +static_assert (foo (43U, 44U, 45U, 46U) == 43U); +static_assert (foo (44LL, 45LL) == 44LL); +static_assert (foo (bar, baz, bar, baz) == bar); +static_assert (foo (baz, bar) == baz); diff --git a/gcc/testsuite/g++.dg/cpp26/constexpr-eh15.C b/gcc/testsuite/g++.dg/cpp26/constexpr-eh15.C new file mode 100644 index 0000000..3dea461 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/constexpr-eh15.C @@ -0,0 +1,39 @@ +// C++26 P3068R5 - Allowing exception throwing in constant-evaluation +// { dg-do compile { target c++26 } } +// { dg-require-effective-target exceptions_enabled } + +int +foo (int x, int y) +{ + return x + y; +} + +constexpr int +bar (int x) +{ + if (x < 0) + throw x; + return x; +} + +constexpr int +baz (int x, int y) +{ + return foo (bar (x), bar (y)); +} + +constexpr int +qux (int x, int y) +{ + try + { + return baz (x, y); + } + catch (int) + { + return 42; + } +} + +static_assert (qux (12, -1) == 42); +static_assert (qux (-7, 12) == 42); diff --git a/gcc/testsuite/g++.dg/cpp26/constexpr-eh2.C b/gcc/testsuite/g++.dg/cpp26/constexpr-eh2.C new file mode 100644 index 0000000..8bd6b6f --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/constexpr-eh2.C @@ -0,0 +1,112 @@ +// C++26 P3068R5 - Allowing exception throwing in constant-evaluation +// { dg-do compile { target c++26 } } +// { dg-require-effective-target exceptions_enabled } + +struct S { + constexpr S () : s (0) {} + constexpr S (int x) : s (x) { if (x == 42) throw 42; } + constexpr S (const S &x) : s (x.s) {} + constexpr ~S () noexcept (false) { if (s == 41) throw 41; } + constexpr const char *what () const noexcept { return "S"; } + int s; +}; +struct T : public S { + constexpr T () {} + constexpr T (int x) : S (x) {} + constexpr T (const T &x) : S (x.s) {} + constexpr ~T () {} + constexpr const char *what () const noexcept { return "T"; } +}; +struct U { + constexpr U () : u (0) {} + constexpr U (int x) : u (x) {} + constexpr U (const S &x) : u (0) {} + constexpr U (const U &x) : u (x.u) { if (u == 42) throw 43; } + constexpr ~U () {} + constexpr const char *what () const noexcept { return "U"; } + int u; +}; + +constexpr int +foo (int x) +{ + if (x == 1) + throw 43; + return x; +} + +constexpr int +bar (int x) noexcept // { dg-error "'std::terminate' called" } +{ // { dg-message "uncaught exception exited from 'noexcept' function 'constexpr int bar\\\(int\\\)'" "" { target *-*-* } .-1 } + return foo (x); +} + +constexpr int +baz (int x) +{ + switch (x) + { + case 0: throw 1; break; + case 1: try { x = bar (x); } catch (...) {} break; // { dg-message "in 'constexpr' expansion of" } + case 2: throw S (2); break; + case 3: try { throw S (42); } catch (int a) { if (a != 42) throw -1; } break; + case 4: try { S s (41); throw 2; } catch (...) {} break; // { dg-error "'std::terminate' called" } + case 5: return 5; // { dg-message "destructor exited with an exception" "" { target *-*-* } .-1 } + case 6: + try + { + throw S (5); + } + catch (const T &) {} + catch (int) {} + catch (const bool &) {} + catch (const T **const &) {} + break; + case 7: try { constexpr int y = foo (2); } catch (...) {} break; + case 8: + try + { + try + { + throw U (); + } + catch (U &u) + { + u.u = 42; + throw; + } + } + catch (U u) // { dg-error "'std::terminate' called" } + { // { dg-message "constructor exited with another exception while entering handler" "" { target *-*-* } .-1 } + } + break; + case 9: + try + { + throw U (S (41)); // { dg-error "'std::terminate' called" } + } // { dg-message "destructor exited with an exception" "" { target *-*-* } .-1 } + catch (...) + { + } + break; + } + return -1; +} + +constexpr int +qux (int x) +{ + try { constexpr int y = foo (1); } catch (...) {} // { dg-error "uncaught exception" } + return 0; +} + +constexpr int a = baz (0); // { dg-error "uncaught exception" } +constexpr int b = baz (1); // { dg-message "in 'constexpr' expansion of" } +constexpr int c = baz (2); // { dg-error "uncaught exception" } +constexpr int d = baz (3); +constexpr int e = baz (4); // { dg-message "in 'constexpr' expansion of" } +constexpr int f = baz (5); +constexpr int g = baz (6); // { dg-error "uncaught exception" } +constexpr int h = baz (7); +constexpr int i = baz (8); // { dg-message "in 'constexpr' expansion of" } +constexpr int j = baz (9); // { dg-message "in 'constexpr' expansion of" } diff --git a/gcc/testsuite/g++.dg/cpp26/constexpr-eh3.C b/gcc/testsuite/g++.dg/cpp26/constexpr-eh3.C new file mode 100644 index 0000000..f844d11 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/constexpr-eh3.C @@ -0,0 +1,442 @@ +// C++26 P3068R5 - Allowing exception throwing in constant-evaluation +// { dg-do compile { target c++26 } } +// { dg-require-effective-target exceptions_enabled } + +#include <exception> +#include <new> +#include <typeinfo> + +constexpr std::exception a; +constexpr const char *b = a.what (); +constexpr std::bad_exception c; +constexpr const char *d = c.what (); +constexpr std::bad_alloc e; +constexpr const char *f = e.what (); +constexpr std::bad_array_new_length g; +constexpr const char *h = g.what (); +constexpr std::bad_cast i; +constexpr const char *j = i.what (); +constexpr std::bad_typeid k; +constexpr const char *l = k.what (); +constexpr std::exception_ptr m = nullptr; +static_assert (m == nullptr); +constexpr std::exception_ptr n = std::current_exception (); +static_assert (n == nullptr); +constexpr std::exception_ptr o; +static_assert (o == nullptr); +constexpr std::nested_exception p; +static_assert (p.nested_ptr () == nullptr); + +struct A { virtual ~A () {} }; +struct B { virtual void b (); }; +struct C { virtual void c (); }; +struct D : private B { virtual void d (); }; +struct E { virtual void e (); }; +struct F : D, E, private C { virtual void f (); }; +struct G { constexpr G () { if (std::uncaught_exceptions () != 0) asm (""); } }; +struct H { constexpr H () : h (0) {} constexpr ~H () { if (std::uncaught_exceptions () != h) asm (""); } int h; }; +struct I : std::nested_exception { }; +struct J { virtual ~J () noexcept = default; }; +struct K final { }; +struct L : J, std::nested_exception { }; +struct M { }; +struct N : I, L { }; +struct O : private std::nested_exception { }; + +constexpr int +foo (int x) +{ + if (std::uncaught_exceptions () != 0) + return -1; + switch (x) + { + case 0: + try + { + const std::type_info &s = typeid (*(A *) 0); + return -1; + } + catch (const std::bad_typeid &x) + { + if (std::uncaught_exceptions () != 0) + return -1; + const char *p = x.what (); + return 1; + } + catch (...) + { + return -1; + } + break; + case 1: + try + { + static constexpr F f; + D &d = dynamic_cast<D &>((B &) f); + return -1; + } + catch (std::bad_cast x) + { + const char *p = x.what (); + return 2; + } + catch (...) + { + return -1; + } + break; + case 2: + try + { + H h; + h.h = 1; + if (std::current_exception () != nullptr) + return -1; + throw G (); + } + catch (const G &g) + { + if (std::uncaught_exceptions () != 0) + return -1; + if (std::current_exception () == nullptr) + return -1; + return 3; + } + catch (...) + { + return -1; + } + break; + case 3: + try + { + decltype (sizeof 0) x = -64; + char (*a)[2] = new char[x][2]; + delete[] a; + } + catch (std::bad_array_new_length x) + { + return 4; + } + break; + case 4: + try + { + int y = -1; + int *a = new int[y]; + delete[] a; + } + catch (const std::bad_array_new_length &) + { + return 5; + } + break; + case 5: + try + { + int z = 1; + int *a = new int[z]{1, 2, 3}; + delete[] a; + } + catch (std::bad_array_new_length &) + { + return 6; + } + break; + case 6: + { + std::exception_ptr b, d; + if (b != nullptr || d != nullptr) + return -1; + try + { + throw 1; + } + catch (int a) + { + if (a != 1) + return -1; + b = std::current_exception (); + if (b == nullptr) + return -1; + try + { + throw 2L; + } + catch (long int c) + { + if (c != 2L) + return -1; + d = std::current_exception (); + if (d == nullptr || b == d) + return -1; + } + if (std::current_exception () != b) + return -1; + } + if (std::current_exception () != nullptr) + return -1; + try + { + std::rethrow_exception (d); + } + catch (long int &e) + { + if (e != 2L) + return -1; + try + { + std::rethrow_exception (b); + } + catch (const int &f) + { + if (f != 1) + return -1; + try + { + std::rethrow_exception (d); + } + catch (const long int g) + { + if (g != 2L) + return -1; + try + { + std::rethrow_exception (b); + } + catch (int h) + { + if (h != 1) + return -1; + std::exception_ptr i (b); + std::exception_ptr j; + if (j != nullptr || i == nullptr || i != b || bool (j)) + return -1; + j = i; + if (j != b || !bool (j)) + return -1; + j = nullptr; + std::swap (i, j); + if (j == nullptr || j != b || i != nullptr) + return -1; + } + } + } + } + return 7; + } + case 7: + { + std::exception_ptr a = std::make_exception_ptr (42); + std::exception_ptr b = std::make_exception_ptr (std::exception ()); + std::exception_ptr c + = std::make_exception_ptr (std::bad_array_new_length ()); + try + { + std::rethrow_exception (a); + } + catch (int d) + { + if (d != 42) + return -1; + try + { + std::rethrow_exception (b); + } + catch (const std::exception &e) + { + const char *f = e.what (); + try + { + std::rethrow_exception (c); + } + catch (const std::bad_alloc &g) + { + try + { + throw; + } + catch (const std::bad_array_new_length &h) + { + const char *i = h.what (); + const char *j = g.what (); + } + } + } + } + return 8; + } + case 8: + { + std::nested_exception a; + if (a.nested_ptr () != nullptr) + return -1; + try + { + std::nested_exception b; + if (b.nested_ptr () != nullptr) + return -1; + throw 42; + } + catch (...) + { + std::nested_exception c; + if (c.nested_ptr () != std::current_exception ()) + return -1; + std::nested_exception d = c; + if (d.nested_ptr () != c.nested_ptr ()) + return -1; + c = d; + try + { + c.rethrow_nested (); + } + catch (const int &e) + { + if (e != 42) + return -1; + } + } + return 9; + } + case 9: + try + { + std::throw_with_nested (I ()); + } + catch (const std::nested_exception &a) + { + if (a.nested_ptr () != nullptr) + return -1; + try + { + throw; + } + catch (const I &) + { + return 10; + } + } + return -1; + case 10: + try + { + std::throw_with_nested (J ()); + } + catch (const std::nested_exception &a) + { + if (a.nested_ptr () != nullptr) + return -1; + try + { + throw; + } + catch (const J &) + { + return 11; + } + } + return -1; + case 11: + try + { + std::throw_with_nested (K ()); + } + catch (const std::nested_exception &) + { + return -1; + } + catch (const K &) + { + return 12; + } + return -1; + case 12: + try + { + throw 42; + } + catch (...) + { + I a; + try + { + std::rethrow_if_nested (a); + } + catch (const int &b) + { + if (b == 42) + return 13; + } + } + return -1; + case 13: + try + { + throw J (); + } + catch (const J &a) + { + std::rethrow_if_nested (a); + return 14; + } + return -1; + case 14: + try + { + throw 42; + } + catch (...) + { + try + { + throw L (); + } + catch (const J &a) + { + try + { + std::rethrow_if_nested (a); + } + catch (const int &b) + { + if (b == 42) + return 15; + } + } + } + return -1; + case 15: + { + std::rethrow_if_nested (1); + M m; + std::rethrow_if_nested (m); + N n; + std::rethrow_if_nested (n); + O o; + std::rethrow_if_nested (o); + return 16; + } + default: + break; + } + return -1; +} + +static_assert (foo (0) == 1); +static_assert (foo (1) == 2); +static_assert (foo (2) == 3); +static_assert (foo (3) == 4); +static_assert (foo (4) == 5); +static_assert (foo (5) == 6); +static_assert (foo (6) == 7); +static_assert (foo (7) == 8); +static_assert (foo (8) == 9); +static_assert (foo (9) == 10); +static_assert (foo (10) == 11); +static_assert (foo (11) == 12); +static_assert (foo (12) == 13); +static_assert (foo (13) == 14); +static_assert (foo (14) == 15); +static_assert (foo (15) == 16); +static_assert (std::uncaught_exceptions () == 0); diff --git a/gcc/testsuite/g++.dg/cpp26/constexpr-eh4.C b/gcc/testsuite/g++.dg/cpp26/constexpr-eh4.C new file mode 100644 index 0000000..24118ca --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/constexpr-eh4.C @@ -0,0 +1,72 @@ +// C++26 P3068R5 - Allowing exception throwing in constant-evaluation +// { dg-do compile { target c++26 } } +// { dg-require-effective-target exceptions_enabled } + +struct A { virtual ~A () {} }; +struct B { virtual void b (); }; +struct C { virtual void c (); }; +struct D : private B { virtual void d (); }; +struct E { virtual void e (); }; +struct F : D, E, private C { virtual void f (); }; + +constexpr int +foo (int x) +{ + switch (x) + { + case 1: + try + { + static constexpr F f; + D &d = dynamic_cast<D &>((B &) f); // { dg-error "called without 'std::bad_cast' being defined" } + return -1; + } + catch (...) + { + return -1; + } + break; + case 3: + try + { + decltype (sizeof 0) x = -64; + char (*a)[2] = new char[x][2]; // { dg-error "called without 'std::bad_array_new_length' being defined" } + delete[] a; + } + catch (...) + { + return -1; + } + break; + case 4: + try + { + int y = -1; + int *a = new int[y]; // { dg-error "called without 'std::bad_array_new_length' being defined" } + delete[] a; + } + catch (...) + { + return -1; + } + break; + case 5: + try + { + int z = 1; + int *a = new int[z]{1, 2, 3}; // { dg-error "called without 'std::bad_array_new_length' being defined" } + delete[] a; + } + catch (...) + { + return -1; + } + break; + } + return -1; +} + +constexpr int a = foo (1); // { dg-message "in 'constexpr' expansion of" } +constexpr int b = foo (3); // { dg-message "in 'constexpr' expansion of" } +constexpr int c = foo (4); // { dg-message "in 'constexpr' expansion of" } +constexpr int d = foo (5); // { dg-message "in 'constexpr' expansion of" } diff --git a/gcc/testsuite/g++.dg/cpp26/constexpr-eh5.C b/gcc/testsuite/g++.dg/cpp26/constexpr-eh5.C new file mode 100644 index 0000000..512aa34 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/constexpr-eh5.C @@ -0,0 +1,55 @@ +// C++26 P3068R5 - Allowing exception throwing in constant-evaluation +// { dg-do compile { target c++26 } } +// { dg-require-effective-target exceptions_enabled } + +constexpr void +foo () +{ + throw 1; +} + +void +bar () +{ +} + +constexpr void +baz () +{ + foo (); + bar (); +} + +constexpr void +qux () +{ + if consteval { + throw 2; + } + bar (); +} + +constexpr bool +corge () +{ + try + { + baz (); + } + catch (int a) + { + if (a != 1) + return false; + try + { + qux (); + } + catch (int b) + { + return b == 2; + } + } + return false; +} + +static_assert (corge ()); diff --git a/gcc/testsuite/g++.dg/cpp26/constexpr-eh6.C b/gcc/testsuite/g++.dg/cpp26/constexpr-eh6.C new file mode 100644 index 0000000..6fd9462 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/constexpr-eh6.C @@ -0,0 +1,134 @@ +// C++26 P3068R5 - Allowing exception throwing in constant-evaluation +// { dg-do compile { target c++26 } } +// { dg-require-effective-target exceptions_enabled } + +struct S { + constexpr S () : s (0) {} + constexpr S (int x) : s (x) {} + constexpr S (const S &x) : s (x.s) {} + constexpr ~S () {} + int s; +}; +struct T { + constexpr T () : t (0) {} + constexpr T (int x) : t (x) {} + constexpr T (const T &x) : t (x.t) {} + constexpr ~T () {} + int t; +}; +struct U : public S, public T { + constexpr U () : S (0), T (0) {} + constexpr U (int x, int y) : S (x), T (y) {} + constexpr U (const U &x) : S (x.s), T (x.t) {} + constexpr ~U () {} +}; + +constexpr bool +foo () +{ + try + { + throw U (1, 2); + } + catch (const U &x) + { + if (x.s != 1 || x.t != 2) + return false; + try + { + throw; + } + catch (const S &y) + { + if (y.s != 1) + return false; + try + { + throw; + } + catch (const T &z) + { + if (z.t != 2) + return false; + return true; + } + } + } + return false; +} + +constexpr bool +bar () +{ + try + { + throw U (1, 2); + } + catch (U &x) + { + if (x.s != 1 || x.t != 2) + return false; + try + { + x.s = 3; + x.t = 4; + throw; + } + catch (S &y) + { + if (y.s != 3) + return false; + try + { + throw; + } + catch (T &z) + { + if (z.t != 4) + return false; + return true; + } + } + } + return false; +} + +constexpr bool +baz () +{ + try + { + throw U (1, 2); + } + catch (U x) + { + if (x.s != 1 || x.t != 2) + return false; + try + { + x.s = 3; + x.t = 4; + throw; + } + catch (S y) + { + if (y.s != 1) + return false; + try + { + throw; + } + catch (T z) + { + if (z.t != 2) + return false; + return true; + } + } + } + return false; +} + +static_assert (foo ()); +static_assert (bar ()); +static_assert (baz ()); diff --git a/gcc/testsuite/g++.dg/cpp26/constexpr-eh7.C b/gcc/testsuite/g++.dg/cpp26/constexpr-eh7.C new file mode 100644 index 0000000..6bdf0c3 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/constexpr-eh7.C @@ -0,0 +1,151 @@ +// C++26 P3068R5 - Allowing exception throwing in constant-evaluation +// { dg-do compile { target c++26 } } +// { dg-require-effective-target exceptions_enabled } + +constexpr char p[] = "hello"; +constexpr const char *q[] = { &p[0], &p[3] }; +constexpr const char *const *r = &q[0]; +const char *s[] = { &p[0], &p[3] }; +constexpr const char **t = &s[0]; + +constexpr bool +foo () +{ + try + { + throw t; + } + catch (const char **const &x) + { + if (x != t) + return false; + try + { + throw; + } + catch (const char **&y) + { + if (y != t) + return false; + try + { + throw; + } + catch (const char **z) + { + if (z != t) + return false; + try + { + throw; + } + catch (const char *const *const &v) + { + if (v != (const char *const *) t) + return false; + try + { + throw; + } + catch (const char *const *w) + { + if (w != (const char *const *) t) + return false; + return true; + } + } + } + } + } + return false; +} + +constexpr bool +bar () +{ + try + { + throw nullptr; + } + catch (const char **const &x) + { + if (x != nullptr) + return false; + try + { + throw; + } + catch (const char **&y) + { + if (y != nullptr) + return false; + try + { + throw; + } + catch (const char **z) + { + if (z != nullptr) + return false; + try + { + throw; + } + catch (const char *const *const &v) + { + if (v != nullptr) + return false; + try + { + throw; + } + catch (const char *const *w) + { + if (w != nullptr) + return false; + return true; + } + } + } + } + } + return false; +} + +constexpr bool +baz () +{ + try + { + throw r; + } + catch (const char *const *const &x) + { + if (x != r || **x != 'h') + return false; + try + { + throw; + } + catch (const char *const *&y) + { + if (y != r || **y != 'h') + return false; + try + { + throw; + } + catch (const char *const *z) + { + if (z != r || **z != 'h') + return false; + return true; + } + } + } + return false; +} + +static_assert (foo ()); +static_assert (bar ()); +static_assert (baz ()); diff --git a/gcc/testsuite/g++.dg/cpp26/constexpr-eh8.C b/gcc/testsuite/g++.dg/cpp26/constexpr-eh8.C new file mode 100644 index 0000000..2560364 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/constexpr-eh8.C @@ -0,0 +1,36 @@ +// C++26 P3068R5 - Allowing exception throwing in constant-evaluation +// { dg-do compile { target c++26 } } +// { dg-require-effective-target exceptions_enabled } + +#include <exception> + +constexpr std::exception_ptr +foo () +{ + try + { + throw 42; + } + catch (...) + { + return std::current_exception (); + } +} + +constexpr bool +bar () +{ + try + { + std::rethrow_exception (foo ()); + } + catch (const int &a) + { + return a == 42; + } + return false; +} + +static_assert (bar ()); +constexpr std::exception_ptr a = foo (); // { dg-error "is not a constant expression because it refers to exception object allocated with '__cxa_allocate_exception'" } +constexpr std::exception_ptr b = std::make_exception_ptr (42ULL); // { dg-error "is not a constant expression because it refers to exception object allocated with '__cxa_allocate_exception'" } diff --git a/gcc/testsuite/g++.dg/cpp26/constexpr-eh9.C b/gcc/testsuite/g++.dg/cpp26/constexpr-eh9.C new file mode 100644 index 0000000..fd39fe0 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/constexpr-eh9.C @@ -0,0 +1,127 @@ +// C++26 P3068R5 - Allowing exception throwing in constant-evaluation +// { dg-do compile { target c++26 } } +// { dg-require-effective-target exceptions_enabled } + +namespace std +{ + struct exception + { + constexpr exception () noexcept { } + constexpr virtual ~exception () noexcept {} + constexpr exception (const exception &) = default; + constexpr exception &operator= (const exception &) = default; + constexpr exception (exception &&) = default; + constexpr exception &operator= (exception &&) = default; + constexpr virtual const char *what () const noexcept + { return "std::exception"; } + }; +} + +struct S : public std::exception { + constexpr S () : s (0) {} + constexpr S (int x) : s (x) {} + constexpr S (const S &x) : s (x.s) {} + constexpr virtual ~S () {} + constexpr virtual const char *what () noexcept { return "this is S"; } + int s; +}; +struct T : public std::exception { + constexpr T () : s (new char[1]), t (0) { s[0] = '\0'; } + constexpr T (const char *p, int q) : s (new char[q + 1]), t (q) + { + for (int i = 0; i <= t; ++i) + s[i] = p[i]; + } + constexpr T (const T &x) : s (new char[x.t + 1]), t (x.t) + { + for (int i = 0; i <= t; ++i) + s[i] = x.s[i]; + } + constexpr virtual ~T () { delete[] s; } + constexpr virtual const char *what () noexcept { return s; } + char *s; + int t; +}; +struct U { + constexpr U () : x (0), y (0), z (0) {} + constexpr U (int a, long b, unsigned long long c) : x (a), y (b), z (c) {} + constexpr U (const U &u) = default; + int x; + long y; + unsigned long long z; +}; +struct V { + constexpr V () : v (0) {} + constexpr V (int x) : v (x) {} + constexpr V (const V &x) : v (x.v) {} + constexpr virtual ~V () {} + constexpr virtual const char *what () noexcept { return "this is V"; } + int v; +}; + +constexpr int +foo (int x) +{ + if (x == 1) + throw S (42); + else if (x == 2) + throw T ("hello, world", sizeof ("hello, world") - 1); + else if (x == 3) + throw U (1, -2L, 42ULL); + else if (x == 4) + throw 42; + else if (x == 5) + throw 1.0; + else if (x == 6) + throw V (42); + else + return 42; +} + +constexpr int +bar (int x) noexcept +// { dg-error "'std::terminate' called after throwing an exception of type 'S'; 'what\\\(\\\)': 'this is S'" "" { target *-*-* } .-1 } +// { dg-message "uncaught exception exited from 'noexcept' function 'constexpr int bar\\\(int\\\)'" "" { target *-*-* } .-2 } +// { dg-error "'std::terminate' called after throwing an exception of type 'T'; 'what\\\(\\\)': 'hello, world'" "" { target *-*-* } .-3 } +// { dg-error "'std::terminate' called after throwing an exception 'U\\\{1, -2, 42\\\}'" "" { target *-*-* } .-4 } +// { dg-error "'std::terminate' called after throwing an exception '42'" "" { target *-*-* } .-5 } +// { dg-error "'std::terminate' called after throwing an exception '1\\\.0e\\\+0'" "" { target *-*-* } .-6 } +// { dg-error "'std::terminate' called after throwing an exception 'V\\\{\[^\n\r]*42\\\}" "" { target *-*-* } .-7 } +{ + return foo (x); +} + +constexpr int +baz (int x) +{ + try + { + return foo (x); + } + catch (...) + { + return -1; + } +} + +static_assert (bar (0) == 42); +constexpr int a = bar (1); // { dg-message "in 'constexpr' expansion of" } +constexpr int b = bar (2); // { dg-message "in 'constexpr' expansion of" } +constexpr int c = bar (3); // { dg-message "in 'constexpr' expansion of" } +constexpr int d = bar (4); // { dg-message "in 'constexpr' expansion of" } +constexpr int e = bar (5); // { dg-message "in 'constexpr' expansion of" } +constexpr int f = bar (6); // { dg-message "in 'constexpr' expansion of" } +static_assert (baz (0) == 42); +static_assert (baz (1) == -1); +static_assert (baz (2) == -1); +static_assert (baz (3) == -1); +static_assert (baz (4) == -1); +static_assert (baz (5) == -1); +static_assert (baz (6) == -1); +static_assert (foo (0) == 42); +constexpr int g = foo (1); // { dg-error "uncaught exception of type 'S'; 'what\\\(\\\)': 'this is S'" } +constexpr int h = foo (2); // { dg-error "uncaught exception of type 'T'; 'what\\\(\\\)': 'hello, world'" } +constexpr int i = foo (3); // { dg-error "uncaught exception 'U\\\{1, -2, 42\\\}'" } +constexpr int j = foo (4); // { dg-error "uncaught exception '42'" } +constexpr int k = foo (5); // { dg-error "uncaught exception '1\\\.0e\\\+0'" } +constexpr int l = foo (6); // { dg-error "uncaught exception 'V\\\{\[^\n\r]*42\\\}'" } diff --git a/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C b/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C index e4ffc35..97bd36b 100644 --- a/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C +++ b/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C @@ -624,19 +624,25 @@ #endif #ifndef __cpp_pack_indexing -# error "__cpp_pack_indexing" +# error "__cpp_pack_indexing" #elif __cpp_pack_indexing != 202311 # error "__cpp_pack_indexing != 202311" #endif #ifndef __cpp_pp_embed -# error "__cpp_pp_embed" +# error "__cpp_pp_embed" #elif __cpp_pp_embed != 202502 # error "__cpp_pp_embed != 202502" #endif #ifndef __cpp_constexpr_virtual_inheritance -# error "__cpp_constexpr_virtual_inheritance" +# error "__cpp_constexpr_virtual_inheritance" #elif __cpp_constexpr_virtual_inheritance != 202506 # error "__cpp_constexpr_virtual_inheritance != 202506" #endif + +#ifndef __cpp_constexpr_exceptions +# error "__cpp_constexpr_exceptions" +#elif __cpp_constexpr_exceptions != 202411 +# error "__cpp_constexpr_exceptions != 202411" +#endif diff --git a/gcc/testsuite/g++.dg/cpp26/static_assert1.C b/gcc/testsuite/g++.dg/cpp26/static_assert1.C index 1d0e6f2..a6eab3c 100644 --- a/gcc/testsuite/g++.dg/cpp26/static_assert1.C +++ b/gcc/testsuite/g++.dg/cpp26/static_assert1.C @@ -51,7 +51,7 @@ static_assert (true, H {}); // { dg-warning "'static_assert' with non-string mes struct I { constexpr signed char size () const { return 0; } const char *data () const { return ""; } }; static_assert (true, I {}); // { dg-warning "'static_assert' with non-string message only available with" "" { target c++23_down } } -struct J { constexpr int size () const { return j ? throw 1 : 0; } // { dg-error "expression '<throw-expression>' is not a constant expression" } +struct J { constexpr int size () const { return j ? throw 1 : 0; } // { dg-error "expression '<throw-expression>' is not a constant expression" "" { target c++23_down } } constexpr const char *data () const { return ""; }; constexpr J (int x) : j (x) {} int j; }; @@ -60,6 +60,7 @@ static_assert (false, J (0)); // { dg-warning "'static_assert' with non-string m // { dg-error "static assertion failed" "" { target *-*-* } .-1 } static_assert (false, J (1)); // { dg-warning "'static_assert' with non-string message only available with" "" { target c++23_down } } // { dg-error "constexpr string 'size\\\(\\\)' must be a constant expression" "" { target *-*-* } .-1 } + // { dg-error "uncaught exception '1'" "" { target c++26 } .-2 } struct K { constexpr operator int () { return 4; } }; struct L { constexpr operator const char * () { return "test"; } }; struct M { constexpr K size () const { return {}; } @@ -261,10 +262,11 @@ namespace NN #if __cplusplus >= 201402L struct J { static constexpr int size () { return 0; } - static constexpr const char *data (int x = 0) { if (x) return nullptr; else throw 1; } }; // { dg-error "expression '<throw-expression>' is not a constant expression" "" { target c++14 } } + static constexpr const char *data (int x = 0) { if (x) return nullptr; else throw 1; } }; // { dg-error "expression '<throw-expression>' is not a constant expression" "" { target { c++14 && c++23_down } } } static_assert (true, J{}); // { dg-warning "'static_assert' with non-string message only available with" "" { target { c++14 && c++23_down } } } static_assert (false, J{}); // { dg-warning "'static_assert' with non-string message only available with" "" { target { c++14 && c++23_down } } } // { dg-error "constexpr string 'data\\\(\\\)' must be a core constant expression" "" { target c++14 } .-1 } + // { dg-error "uncaught exception '1'" "" { target c++26 } .-2 } #endif #if __cpp_if_consteval >= 202106L struct K { @@ -282,19 +284,21 @@ namespace NN static_assert (false, L{}); // { dg-warning "'static_assert' with non-string message only available with" "" { target c++23_only } } // { dg-error "static assertion failed: test" "" { target c++23 } .-1 } struct M { - static constexpr int size () { if consteval { throw 1; } else { return 4; } } // { dg-error "expression '<throw-expression>' is not a constant expression" "" { target c++23 } } + static constexpr int size () { if consteval { throw 1; } else { return 4; } } // { dg-error "expression '<throw-expression>' is not a constant expression" "" { target c++23_only } } static constexpr const char *data () { return "test"; } }; static_assert (true, M{}); // { dg-warning "'static_assert' with non-string message only available with" "" { target c++23_only } } static_assert (false, M{}); // { dg-warning "'static_assert' with non-string message only available with" "" { target c++23_only } } // { dg-error "constexpr string 'size\\\(\\\)' must be a constant expression" "" { target c++23 } .-1 } + // { dg-error "uncaught exception '1'" "" { target c++26 } .-2 } struct N { static constexpr int size () { return 4; } - static constexpr const char *data () { if consteval { throw 1; } else { return "test"; } } // { dg-error "expression '<throw-expression>' is not a constant expression" "" { target c++23 } } + static constexpr const char *data () { if consteval { throw 1; } else { return "test"; } } // { dg-error "expression '<throw-expression>' is not a constant expression" "" { target c++23_only } } }; static_assert (true, N{}); // { dg-warning "'static_assert' with non-string message only available with" "" { target c++23_only } } static_assert (false, N{}); // { dg-warning "'static_assert' with non-string message only available with" "" { target c++23_only } } // { dg-error "constexpr string 'data\\\(\\\)\\\[0\\\]' must be a constant expression" "" { target c++23 } .-1 } + // { dg-error "uncaught exception '1'" "" { target c++26 } .-2 } #endif struct O { constexpr int operator () () const { return 12; } }; struct P { constexpr const char *operator () () const { return "another test"; } }; diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval-memfn1.C b/gcc/testsuite/g++.dg/cpp2a/consteval-memfn1.C index ca92351..17a391b 100644 --- a/gcc/testsuite/g++.dg/cpp2a/consteval-memfn1.C +++ b/gcc/testsuite/g++.dg/cpp2a/consteval-memfn1.C @@ -4,13 +4,13 @@ struct fixed_string { consteval int size(int n) const { - if (n < 0) throw; // { dg-error "not a constant" } - return n; + if (n < 0) throw; // { dg-error "not a constant" "" { target c++23_down } } + return n; // { dg-error "'void __cxa_rethrow\\\(\\\)' called with no caught exceptions active" "" { target c++26 } .-1 } } static consteval int size_static(int n) { - if (n < 0) throw; // { dg-error "not a constant" } - return n; + if (n < 0) throw; // { dg-error "not a constant" "" { target c++23_down } } + return n; // { dg-error "'void __cxa_rethrow\\\(\\\)' called with no caught exceptions active" "" { target c++26 } .-1 } } consteval void operator()() const { } diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval34.C b/gcc/testsuite/g++.dg/cpp2a/consteval34.C index 7562f40..73bcf77 100644 --- a/gcc/testsuite/g++.dg/cpp2a/consteval34.C +++ b/gcc/testsuite/g++.dg/cpp2a/consteval34.C @@ -1,42 +1,51 @@ // { dg-do compile { target c++20 } } // Explicit { dg-require-effective-target exceptions_enabled } to avoid verify compiler messages FAILs for '-fno-exceptions'. -consteval int bar (int i) { if (i != 1) throw 1; return 0; } // { dg-error "is not a constant expression" } +consteval int bar (int i) { if (i != 1) throw 1; return 0; } // { dg-error "is not a constant expression" "" { target c++23_down } } constexpr int foo (bool b) { - return b ? bar (3) : 2; // { dg-message "in .constexpr. expansion" } + return b ? bar (3) : 2; // { dg-message "in .constexpr. expansion" "" { target c++23_down } } // { dg-error "call to consteval function" "" { target *-*-* } .-1 } -} +} // { dg-error "uncaught exception '1'" "" { target c++26 } } static_assert (foo (false) == 2); -__extension__ constexpr int g1 = false ?: bar (2); // { dg-message "in .constexpr. expansion" } -__extension__ constexpr int g2 = false ?: (1 + bar (2)); // { dg-message "in .constexpr. expansion" } +__extension__ constexpr int g1 = false ?: bar (2); // { dg-message "in .constexpr. expansion" "" { target c++23_down } } +// { dg-error "uncaught exception '1'" "" { target c++26 } .-1 } +__extension__ constexpr int g2 = false ?: (1 + bar (2)); // { dg-message "in .constexpr. expansion" "" { target c++23_down } } +// { dg-error "uncaught exception '1'" "" { target c++26 } .-1 } __extension__ constexpr int g3 = true ?: bar (2); __extension__ constexpr int g4 = true ?: (1 + bar (2)); -constexpr int g5 = bar (2) ? 1 : 2; // { dg-message "in .constexpr. expansion" } -constexpr int g6 = bar (2) - 1 ? 1 : 2; // { dg-message "in .constexpr. expansion" } +constexpr int g5 = bar (2) ? 1 : 2; // { dg-message "in .constexpr. expansion" "" { target c++23_down } } +// { dg-error "uncaught exception '1'" "" { target c++26 } .-1 } +constexpr int g6 = bar (2) - 1 ? 1 : 2; // { dg-message "in .constexpr. expansion" "" { target c++23_down } } +// { dg-error "uncaught exception '1'" "" { target c++26 } .-1 } void g () { - __extension__ int a1[bar(3)]; // { dg-message "in .constexpr. expansion" } + __extension__ int a1[bar(3)]; // { dg-message "in .constexpr. expansion" "" { target c++23_down } } // { dg-error "call to consteval function" "" { target *-*-* } .-1 } int a2[sizeof (bar(3))]; - int a3 = false ? (1 + bar (8)) : 1; // { dg-message "in .constexpr. expansion" } + int a3 = false ? (1 + bar (8)) : 1; // { dg-message "in .constexpr. expansion" "" { target c++23_down } } // { dg-error "call to consteval function" "" { target *-*-* } .-1 } - a3 += false ? (1 + bar (8)) : 1; // { dg-message "in .constexpr. expansion" } +// { dg-error "uncaught exception '1'" "" { target c++26 } .-2 } + a3 += false ? (1 + bar (8)) : 1; // { dg-message "in .constexpr. expansion" "" { target c++23_down } } // { dg-error "call to consteval function" "" { target *-*-* } .-1 } - __extension__ int a4 = false ?: (1 + bar (8)); // { dg-message "in .constexpr. expansion" } + __extension__ int a4 = false ?: (1 + bar (8)); // { dg-message "in .constexpr. expansion" "" { target c++23_down } } // { dg-error "call to consteval function" "" { target *-*-* } .-1 } - __extension__ int a5 = true ?: (1 + bar (8)); // { dg-message "in .constexpr. expansion" } +// { dg-error "uncaught exception '1'" "" { target c++26 } .-2 } + __extension__ int a5 = true ?: (1 + bar (8)); // { dg-message "in .constexpr. expansion" "" { target c++23_down } } // { dg-error "call to consteval function" "" { target *-*-* } .-1 } - int a6 = bar (2) ? 1 : 2; // { dg-message "in .constexpr. expansion" } +// { dg-error "uncaught exception '1'" "" { target c++26 } .-2 } + int a6 = bar (2) ? 1 : 2; // { dg-message "in .constexpr. expansion" "" { target c++23_down } } // { dg-error "call to consteval function" "" { target *-*-* } .-1 } - int a7 = bar (2) - 1 ? 1 : 2; // { dg-message "in .constexpr. expansion" } +// { dg-error "uncaught exception '1'" "" { target c++26 } .-2 } + int a7 = bar (2) - 1 ? 1 : 2; // { dg-message "in .constexpr. expansion" "" { target c++23_down } } // { dg-error "call to consteval function" "" { target *-*-* } .-1 } -} +// { dg-error "uncaught exception '1'" "" { target c++26 } .-2 } +} // { dg-error "uncaught exception '1'" "" { target c++26 } } diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic11.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic11.C index 9ee93c3..12a071a 100644 --- a/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic11.C +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic11.C @@ -8,6 +8,22 @@ // a pointer to or object of the constructor or destructor's own class or one // of its bases, the dynamic_cast results in undefined behavior. +#if __cpp_constexpr_exceptions >= 202411L +namespace std { + struct exception { + constexpr exception () noexcept {} + constexpr virtual ~exception () noexcept {} + constexpr exception (const exception &) = default; + constexpr exception &operator= (const exception &) = default; + constexpr virtual const char *what () const noexcept { return "std::exception"; } + }; + struct bad_cast : public exception { + constexpr virtual ~bad_cast () noexcept {} + constexpr virtual const char *what () const noexcept { return "std::bad_cast"; } + }; +} +#endif + struct V { virtual void f(); }; @@ -19,7 +35,7 @@ struct B : V { }; struct D : A, B { - constexpr D() : B((A*)this, this) { } // { dg-message "in 'constexpr' expansion of" } + constexpr D() : B((A*)this, this) { } // { dg-message "in 'constexpr' expansion of" "" { target c++23_down } } }; constexpr B::B(V* v, A* a) @@ -29,8 +45,9 @@ constexpr B::B(V* v, A* a) if (b != nullptr) __builtin_abort (); - B& br = dynamic_cast<B&>(*v); // { dg-error "reference .dynamic_cast. failed" } -// { dg-message "dynamic type .A. of its operand does not have an unambiguous public base class .B." "" { target *-*-* } .-1 } + B& br = dynamic_cast<B&>(*v); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } } +// { dg-message "dynamic type .A. of its operand does not have an unambiguous public base class .B." "" { target c++23_down } .-1 } } -constexpr D d; // { dg-message "in 'constexpr' expansion of" } +constexpr D d; // { dg-message "in 'constexpr' expansion of" "" { target c++23_down } } +// { dg-error "uncaught exception" "" { target c++26 } .-1 } diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic14.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic14.C index cc1cada..f966db4 100644 --- a/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic14.C +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic14.C @@ -4,6 +4,22 @@ // Adopted from g++.old-deja/g++.other/dyncast1.C. // But use reference dynamic_cast. +#if __cpp_constexpr_exceptions >= 202411L +namespace std { + struct exception { + constexpr exception () noexcept {} + constexpr virtual ~exception () noexcept {} + constexpr exception (const exception &) = default; + constexpr exception &operator= (const exception &) = default; + constexpr virtual const char *what () const noexcept { return "std::exception"; } + }; + struct bad_cast : public exception { + constexpr virtual ~bad_cast () noexcept {} + constexpr virtual const char *what () const noexcept { return "std::bad_cast"; } + }; +} +#endif + // 1. downcast // 1.1. single inheritance case @@ -21,27 +37,35 @@ class CCC : protected B {}; class DDD : protected CCC {}; constexpr D d; -constexpr bool b01 = (dynamic_cast<D&> ((A&)d), true); // { dg-error "reference .dynamic_cast. failed" } -// { dg-message "static type .const A. of its operand is a non-public base class of dynamic type .D." "" { target *-*-* } .-1 } -constexpr bool b02 = (dynamic_cast<D&> ((B&)d), true); // { dg-error "reference .dynamic_cast. failed" } -// { dg-message "static type .const B. of its operand is a non-public base class of dynamic type .D." "" { target *-*-* } .-1 } +constexpr bool b01 = (dynamic_cast<D&> ((A&)d), true); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } } +// { dg-message "static type .const A. of its operand is a non-public base class of dynamic type .D." "" { target c++23_down } .-1 } +// { dg-error "uncaught exception" "" { target c++26 } .-2 } +constexpr bool b02 = (dynamic_cast<D&> ((B&)d), true); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } } +// { dg-message "static type .const B. of its operand is a non-public base class of dynamic type .D." "" { target c++23_down } .-1 } +// { dg-error "uncaught exception" "" { target c++26 } .-2 } static_assert (&d == &dynamic_cast<const D&> ((C&)d)); -constexpr bool b03 = (dynamic_cast<C&> ((B&)d), true); // { dg-error "reference .dynamic_cast. failed" } -// { dg-message "static type .const B. of its operand is a non-public base class of dynamic type .D." "" { target *-*-* } .-1 } +constexpr bool b03 = (dynamic_cast<C&> ((B&)d), true); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } } +// { dg-message "static type .const B. of its operand is a non-public base class of dynamic type .D." "" { target c++23_down } .-1 } +// { dg-error "uncaught exception" "" { target c++26 } .-2 } constexpr DD dd; -constexpr bool b04 = (dynamic_cast<DD&> ((A&)dd), true); // { dg-error "reference .dynamic_cast. failed" } -// { dg-message "static type .const A. of its operand is a non-public base class of dynamic type .DD." "" { target *-*-* } .-1 } -constexpr bool b05 = (dynamic_cast<DD&> ((B&)dd), true); // { dg-error "reference .dynamic_cast. failed" } -// { dg-message "static type .const B. of its operand is a non-public base class of dynamic type .DD." "" { target *-*-* } .-1 } +constexpr bool b04 = (dynamic_cast<DD&> ((A&)dd), true); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } } +// { dg-message "static type .const A. of its operand is a non-public base class of dynamic type .DD." "" { target c++23_down } .-1 } +// { dg-error "uncaught exception" "" { target c++26 } .-2 } +constexpr bool b05 = (dynamic_cast<DD&> ((B&)dd), true); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } } +// { dg-message "static type .const B. of its operand is a non-public base class of dynamic type .DD." "" { target c++23_down } .-1 } +// { dg-error "uncaught exception" "" { target c++26 } .-2 } constexpr DDD ddd; -constexpr bool b06 = (dynamic_cast<DDD&> ((A&)ddd), true); // { dg-error "reference .dynamic_cast. failed" } -// { dg-message "static type .const A. of its operand is a non-public base class of dynamic type .DDD." "" { target *-*-* } .-1 } -constexpr bool b07 = (dynamic_cast<DDD&> ((B&)ddd), true); // { dg-error "reference .dynamic_cast. failed" } -// { dg-message "static type .const B. of its operand is a non-public base class of dynamic type .DDD." "" { target *-*-* } .-1 } -constexpr bool b08 = (dynamic_cast<CCC&> ((B&)ddd), true); // { dg-error "reference .dynamic_cast. failed" } -// { dg-message "static type .const B. of its operand is a non-public base class of dynamic type .DDD." "" { target *-*-* } .-1 } +constexpr bool b06 = (dynamic_cast<DDD&> ((A&)ddd), true); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } } +// { dg-message "static type .const A. of its operand is a non-public base class of dynamic type .DDD." "" { target c++23_down } .-1 } +// { dg-error "uncaught exception" "" { target c++26 } .-2 } +constexpr bool b07 = (dynamic_cast<DDD&> ((B&)ddd), true); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } } +// { dg-message "static type .const B. of its operand is a non-public base class of dynamic type .DDD." "" { target c++23_down } .-1 } +// { dg-error "uncaught exception" "" { target c++26 } .-2 } +constexpr bool b08 = (dynamic_cast<CCC&> ((B&)ddd), true); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } } +// { dg-message "static type .const B. of its operand is a non-public base class of dynamic type .DDD." "" { target c++23_down } .-1 } +// { dg-error "uncaught exception" "" { target c++26 } .-2 } // 1.2. multiple inheritance case // 1.2.1. all bases are public @@ -50,19 +74,23 @@ struct E : D, CC {}; struct EE : CC, D {}; //Will search in reverse order. constexpr E e; -constexpr bool b09 = (dynamic_cast<E&> ((A&)(D&)e), true); // { dg-error "reference .dynamic_cast. failed" } -// { dg-message "static type .A. of its operand is a non-public base class of dynamic type .E." "" { target *-*-* } .-1 } -constexpr bool b10 = (dynamic_cast<E&> ((B&)(D&)e), true); // { dg-error "reference .dynamic_cast. failed" } -// { dg-message "static type .B. of its operand is a non-public base class of dynamic type .E." "" { target *-*-* } .-1 } +constexpr bool b09 = (dynamic_cast<E&> ((A&)(D&)e), true); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } } +// { dg-message "static type .A. of its operand is a non-public base class of dynamic type .E." "" { target c++23_down } .-1 } +// { dg-error "uncaught exception" "" { target c++26 } .-2 } +constexpr bool b10 = (dynamic_cast<E&> ((B&)(D&)e), true); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } } +// { dg-message "static type .B. of its operand is a non-public base class of dynamic type .E." "" { target c++23_down } .-1 } +// { dg-error "uncaught exception" "" { target c++26 } .-2 } static_assert (&e == &dynamic_cast<E&> ((C&)(D&)e)); static_assert (&e == &dynamic_cast<E&> ((B&)(CC&)e)); static_assert (&(CC&)e == &dynamic_cast<CC&> ((B&)(CC&)e)); constexpr EE ee; -constexpr bool b11 = (dynamic_cast<EE&> ((A&)(D&)ee), true); // { dg-error "reference .dynamic_cast. failed" } -// { dg-message "static type .A. of its operand is a non-public base class of dynamic type .EE." "" { target *-*-* } .-1 } -constexpr bool b12 = (dynamic_cast<EE&> ((B&)(D&)ee), true); // { dg-error "reference .dynamic_cast. failed" } -// { dg-message "static type .B. of its operand is a non-public base class of dynamic type .EE." "" { target *-*-* } .-1 } +constexpr bool b11 = (dynamic_cast<EE&> ((A&)(D&)ee), true); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } } +// { dg-message "static type .A. of its operand is a non-public base class of dynamic type .EE." "" { target c++23_down } .-1 } +// { dg-error "uncaught exception" "" { target c++26 } .-2 } +constexpr bool b12 = (dynamic_cast<EE&> ((B&)(D&)ee), true); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } } +// { dg-message "static type .B. of its operand is a non-public base class of dynamic type .EE." "" { target c++23_down } .-1 } +// { dg-error "uncaught exception" "" { target c++26 } .-2 } static_assert (&ee == &dynamic_cast<EE&> ((C&)(D&)ee)); static_assert (&ee == &dynamic_cast<EE&> ((B&)(CC&)ee)); static_assert (&(CC&)ee == &dynamic_cast<CC&> ((B&)(CC&)ee)); @@ -78,14 +106,17 @@ constexpr X x; static_assert (&x == &dynamic_cast<X&>((B&)(CC&)(E&)x)); constexpr XX xx; -constexpr bool b13 = (dynamic_cast<XX&>((B&)(CC&)(E&)xx), true); // { dg-error "reference .dynamic_cast. failed" } -// { dg-message "static type .B. of its operand is a non-public base class of dynamic type .XX." "" { target *-*-* } .-1 } +constexpr bool b13 = (dynamic_cast<XX&>((B&)(CC&)(E&)xx), true); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } } +// { dg-message "static type .B. of its operand is a non-public base class of dynamic type .XX." "" { target c++23_down } .-1 } +// { dg-error "uncaught exception" "" { target c++26 } .-2 } constexpr Y y; -constexpr bool b14 = (dynamic_cast<Y&>((B&)y), true); // { dg-error "reference .dynamic_cast. failed" } -// { dg-message "static type .const B. of its operand is a non-public base class of dynamic type .Y." "" { target *-*-* } .-1 } -constexpr bool b15 = (dynamic_cast<Y&>((A&)(B&)y), true); // { dg-error "reference .dynamic_cast. failed" } -// { dg-message "static type .A. of its operand is a non-public base class of dynamic type .Y." "" { target *-*-* } .-1 } +constexpr bool b14 = (dynamic_cast<Y&>((B&)y), true); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } } +// { dg-message "static type .const B. of its operand is a non-public base class of dynamic type .Y." "" { target c++23_down } .-1 } +// { dg-error "uncaught exception" "" { target c++26 } .-2 } +constexpr bool b15 = (dynamic_cast<Y&>((A&)(B&)y), true); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } } +// { dg-message "static type .A. of its operand is a non-public base class of dynamic type .Y." "" { target c++23_down } .-1 } +// { dg-error "uncaught exception" "" { target c++26 } .-2 } // 2. crosscast @@ -93,13 +124,16 @@ struct J { virtual void j(); }; struct K : CC, private J {}; class KK : J, CC{}; -constexpr bool b16 = (dynamic_cast<CC&> ((B&)(D&)e), true); // { dg-error "reference .dynamic_cast. failed" } -// { dg-message "static type .B. of its operand is a non-public base class of dynamic type .CC." "" { target *-*-* } .-1 } +constexpr bool b16 = (dynamic_cast<CC&> ((B&)(D&)e), true); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } } +// { dg-message "static type .B. of its operand is a non-public base class of dynamic type .CC." "" { target c++23_down } .-1 } +// { dg-error "uncaught exception" "" { target c++26 } .-2 } static_assert (&(CC&)e == &dynamic_cast<CC&> ((C&)(D&)e)); constexpr K k; -constexpr bool b17 = (dynamic_cast<J&> ((B&)k), true); // { dg-error "reference .dynamic_cast. failed" } -// { dg-message "dynamic type .K. of its operand does not have an unambiguous public base class .J." "" { target *-*-* } .-1 } +constexpr bool b17 = (dynamic_cast<J&> ((B&)k), true); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } } +// { dg-message "dynamic type .K. of its operand does not have an unambiguous public base class .J." "" { target c++23_down } .-1 } +// { dg-error "uncaught exception" "" { target c++26 } .-2 } constexpr KK kk; -constexpr bool b18 = (dynamic_cast<J&> ((CC&)kk), true); // { dg-error "reference .dynamic_cast. failed" } -// { dg-message "static type .const CC. of its operand is a non-public base class of dynamic type .KK." "" { target *-*-* } .-1 } +constexpr bool b18 = (dynamic_cast<J&> ((CC&)kk), true); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } } +// { dg-message "static type .const CC. of its operand is a non-public base class of dynamic type .KK." "" { target c++23_down } .-1 } +// { dg-error "uncaught exception" "" { target c++26 } .-2 } diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic18.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic18.C index 25d98c2..112ff8a 100644 --- a/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic18.C +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic18.C @@ -2,6 +2,22 @@ // { dg-do compile { target c++20 } } // Here 'b' doesn't point/refer to a public base of Derived. +#if __cpp_constexpr_exceptions >= 202411L +namespace std { + struct exception { + constexpr exception () noexcept {} + constexpr virtual ~exception () noexcept {} + constexpr exception (const exception &) = default; + constexpr exception &operator= (const exception &) = default; + constexpr virtual const char *what () const noexcept { return "std::exception"; } + }; + struct bad_cast : public exception { + constexpr virtual ~bad_cast () noexcept {} + constexpr virtual const char *what () const noexcept { return "std::bad_cast"; } + }; +} +#endif + struct Base { constexpr virtual ~Base(){} }; @@ -11,12 +27,12 @@ struct Derived: Base { }; constexpr const Derived& cast(const Base& b) { - return dynamic_cast<const Derived&>(b); // { dg-error "reference .dynamic_cast. failed" } -// { dg-message "dynamic type .const Base. of its operand does not have a base class of type .Derived." "" { target *-*-* } .-1 } + return dynamic_cast<const Derived&>(b); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } } +// { dg-message "dynamic type .const Base. of its operand does not have a base class of type .Derived." "" { target c++23_down } .-1 } } auto test() { static constexpr Base b; - constexpr auto res = cast(b); + constexpr auto res = cast(b); // { dg-error "uncaught exception" "" { target c++26 } } return res; } diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic4.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic4.C index da647bf..a237134 100644 --- a/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic4.C +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic4.C @@ -4,6 +4,22 @@ // From clang's constant-expression-cxx2a.cpp. +#if __cpp_constexpr_exceptions >= 202411L +namespace std { + struct exception { + constexpr exception () noexcept {} + constexpr virtual ~exception () noexcept {} + constexpr exception (const exception &) = default; + constexpr exception &operator= (const exception &) = default; + constexpr virtual const char *what () const noexcept { return "std::exception"; } + }; + struct bad_cast : public exception { + constexpr virtual ~bad_cast () noexcept {} + constexpr virtual const char *what () const noexcept { return "std::bad_cast"; } + }; +} +#endif + struct A2 { virtual void a2(); }; struct A : A2 { virtual void a(); }; struct B : A {}; @@ -26,31 +42,36 @@ static_assert(dynamic_cast<const A*>(static_cast<const C2*>(&g)) == nullptr); static_assert(g.f == (void*)(F*)&g); static_assert(dynamic_cast<const void*>(static_cast<const D*>(&g)) == &g); -constexpr int d_a = (dynamic_cast<const A&>(static_cast<const D&>(g)), 0); // { dg-error "reference .dynamic_cast. failed" } -// { dg-message ".A. is an ambiguous base class of dynamic type .G." "" { target *-*-* } .-1 } - +constexpr int d_a = (dynamic_cast<const A&>(static_cast<const D&>(g)), 0); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } } +// { dg-message ".A. is an ambiguous base class of dynamic type .G." "" { target c++23_down } .-1 } +// { dg-error "uncaught exception" "" { target c++26 } .-2 } // Can navigate from A2 to its A... static_assert(&dynamic_cast<A&>((A2&)(B&)g) == &(A&)(B&)g); // ... and from B to its A ... static_assert(&dynamic_cast<A&>((B&)g) == &(A&)(B&)g); // ... but not from D. -static_assert(&dynamic_cast<A&>((D&)g) == &(A&)(B&)g); // { dg-error "non-constant condition for static assertion|reference .dynamic_cast. failed" } -// { dg-message ".A. is an ambiguous base class of dynamic type .G." "" { target *-*-* } .-1 } - +static_assert(&dynamic_cast<A&>((D&)g) == &(A&)(B&)g); // { dg-error "non-constant condition for static assertion" } +// { dg-message ".A. is an ambiguous base class of dynamic type .G." "" { target c++23_down } .-1 } +// { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } .-2 } +// { dg-error "uncaught exception" "" { target c++26 } .-3 } // Can cast from A2 to sibling class D. static_assert(&dynamic_cast<D&>((A2&)(B&)g) == &(D&)g); // Cannot cast from private base E to derived class F. -constexpr int e_f = (dynamic_cast<F&>((E&)g), 0); // { dg-error "reference .dynamic_cast. failed" } -// { dg-message "static type .const E. of its operand is a non-public base class of dynamic type .G." "" { target *-*-* } .-1 } +constexpr int e_f = (dynamic_cast<F&>((E&)g), 0); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } } +// { dg-message "static type .const E. of its operand is a non-public base class of dynamic type .G." "" { target c++23_down } .-1 } +// { dg-error "uncaught exception" "" { target c++26 } .-2 } // Cannot cast from B to private sibling E. -constexpr int b_e = (dynamic_cast<E&>((B&)g), 0); // { dg-error "reference .dynamic_cast. failed" } -// { dg-message "dynamic type .G. of its operand does not have an unambiguous public base class .E." "" { target *-*-* } .-1 } +constexpr int b_e = (dynamic_cast<E&>((B&)g), 0); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } } +// { dg-message "dynamic type .G. of its operand does not have an unambiguous public base class .E." "" { target c++23_down } .-1 } +// { dg-error "uncaught exception" "" { target c++26 } .-2 } struct Unrelated { virtual void unrelated(); }; -constexpr int b_unrelated = (dynamic_cast<Unrelated&>((B&)g), 0); // { dg-error "reference .dynamic_cast. failed" } -// { dg-message "dynamic type .G. of its operand does not have an unambiguous public base class .Unrelated." "" { target *-*-* } .-1 } -constexpr int e_unrelated = (dynamic_cast<Unrelated&>((E&)g), 0); // { dg-error "reference .dynamic_cast. failed" } -// { dg-message "static type .const E. of its operand is a non-public base class of dynamic type .G." "" { target *-*-* } .-1 } +constexpr int b_unrelated = (dynamic_cast<Unrelated&>((B&)g), 0); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } } +// { dg-message "dynamic type .G. of its operand does not have an unambiguous public base class .Unrelated." "" { target c++23_down } .-1 } +// { dg-error "uncaught exception" "" { target c++26 } .-2 } +constexpr int e_unrelated = (dynamic_cast<Unrelated&>((E&)g), 0); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } } +// { dg-message "static type .const E. of its operand is a non-public base class of dynamic type .G." "" { target c++23_down } .-1 } +// { dg-error "uncaught exception" "" { target c++26 } .-2 } diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic6.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic6.C index d67c307..4434a1a 100644 --- a/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic6.C +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic6.C @@ -1,6 +1,22 @@ // PR c++/88337 - Implement P1327R1: Allow dynamic_cast/typeid in constexpr. // { dg-do compile { target c++20 } } +#if __cpp_constexpr_exceptions >= 202411L +namespace std { + struct exception { + constexpr exception () noexcept {} + constexpr virtual ~exception () noexcept {} + constexpr exception (const exception &) = default; + constexpr exception &operator= (const exception &) = default; + constexpr virtual const char *what () const noexcept { return "std::exception"; } + }; + struct bad_cast : public exception { + constexpr virtual ~bad_cast () noexcept {} + constexpr virtual const char *what () const noexcept { return "std::bad_cast"; } + }; +} +#endif + // Private base. struct P1 { virtual void p1(); }; @@ -12,14 +28,16 @@ struct A : B, C, private P2 { virtual void a(); }; constexpr A a; // P1 is a non-public base of A. -constexpr bool b1 = (dynamic_cast<B&>((P1&)a), false); // { dg-error "reference .dynamic_cast. failed" } -// { dg-message "static type .const P1. of its operand is a non-public base class of dynamic type .A." "" { target *-*-* } .-1 } +constexpr bool b1 = (dynamic_cast<B&>((P1&)a), false); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } } +// { dg-message "static type .const P1. of its operand is a non-public base class of dynamic type .A." "" { target c++23_down } .-1 } +// { dg-error "uncaught exception" "" { target c++26 } .-2 } // Don't error here. static_assert (dynamic_cast<B*>((P1*)&a) == nullptr); -constexpr bool b2 = (dynamic_cast<C&>((P2&)a), false); // { dg-error "reference .dynamic_cast. failed" } -// { dg-message "static type .const P2. of its operand is a non-public base class of dynamic type .A." "" { target *-*-* } .-1 } +constexpr bool b2 = (dynamic_cast<C&>((P2&)a), false); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } } +// { dg-message "static type .const P2. of its operand is a non-public base class of dynamic type .A." "" { target c++23_down } .-1 } +// { dg-error "uncaught exception" "" { target c++26 } .-2 } static_assert (dynamic_cast<C*>((P1*)&a) == nullptr); static_assert (dynamic_cast<C*>((P2*)&a) == nullptr); diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic7.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic7.C index bc3efd0..d504efd 100644 --- a/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic7.C +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic7.C @@ -1,6 +1,22 @@ // PR c++/88337 - Implement P1327R1: Allow dynamic_cast/typeid in constexpr. // { dg-do compile { target c++20 } } +#if __cpp_constexpr_exceptions >= 202411L +namespace std { + struct exception { + constexpr exception () noexcept {} + constexpr virtual ~exception () noexcept {} + constexpr exception (const exception &) = default; + constexpr exception &operator= (const exception &) = default; + constexpr virtual const char *what () const noexcept { return "std::exception"; } + }; + struct bad_cast : public exception { + constexpr virtual ~bad_cast () noexcept {} + constexpr virtual const char *what () const noexcept { return "std::bad_cast"; } + }; +} +#endif + // Protected base. struct P1 { virtual void p1(); }; @@ -12,14 +28,16 @@ struct A : B, C, protected P2 { virtual void a(); }; constexpr A a; // P1 is a non-public base of A. -constexpr bool b1 = (dynamic_cast<B&>((P1&)a), false); // { dg-error "reference .dynamic_cast. failed" } -// { dg-message "static type .const P1. of its operand is a non-public base class of dynamic type .A." "" { target *-*-* } .-1 } +constexpr bool b1 = (dynamic_cast<B&>((P1&)a), false); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } } +// { dg-message "static type .const P1. of its operand is a non-public base class of dynamic type .A." "" { target c++23_down } .-1 } +// { dg-error "uncaught exception" "" { target c++26 } .-2 } // Don't error here. static_assert (dynamic_cast<B*>((P1*)&a) == nullptr); -constexpr bool b2 = (dynamic_cast<C&>((P2&)a), false); // { dg-error "reference .dynamic_cast. failed" } -// { dg-message "static type .const P2. of its operand is a non-public base class of dynamic type .A." "" { target *-*-* } .-1 } +constexpr bool b2 = (dynamic_cast<C&>((P2&)a), false); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } } +// { dg-message "static type .const P2. of its operand is a non-public base class of dynamic type .A." "" { target c++23_down } .-1 } +// { dg-error "uncaught exception" "" { target c++26 } .-2 } static_assert (dynamic_cast<C*>((P1*)&a) == nullptr); static_assert (dynamic_cast<C*>((P2*)&a) == nullptr); diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic8.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic8.C index 1958cae4..2fc8242 100644 --- a/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic8.C +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic8.C @@ -1,6 +1,22 @@ // PR c++/88337 - Implement P1327R1: Allow dynamic_cast/typeid in constexpr. // { dg-do compile { target c++20 } } +#if __cpp_constexpr_exceptions >= 202411L +namespace std { + struct exception { + constexpr exception () noexcept {} + constexpr virtual ~exception () noexcept {} + constexpr exception (const exception &) = default; + constexpr exception &operator= (const exception &) = default; + constexpr virtual const char *what () const noexcept { return "std::exception"; } + }; + struct bad_cast : public exception { + constexpr virtual ~bad_cast () noexcept {} + constexpr virtual const char *what () const noexcept { return "std::bad_cast"; } + }; +} +#endif + // Unrelated type. struct B { virtual void b(); }; @@ -12,12 +28,15 @@ constexpr A a; struct U { virtual void u(); }; -constexpr bool b1 = (dynamic_cast<U&>((B&)a), 0); // { dg-error "reference .dynamic_cast. failed" } -// { dg-message "dynamic type .A. of its operand does not have an unambiguous public base class .U." "" { target *-*-* } .-1 } -constexpr bool b2 = (dynamic_cast<U&>((P1&)a), 0); // { dg-error "reference .dynamic_cast. failed" } -// { dg-message "static type .const P1. of its operand is a non-public base class of dynamic type .A." "" { target *-*-* } .-1 } -constexpr bool b3 = (dynamic_cast<U&>((P2&)a), 0); // { dg-error "reference .dynamic_cast. failed" } -// { dg-message "static type .const P2. of its operand is a non-public base class of dynamic type .A." "" { target *-*-* } .-1 } +constexpr bool b1 = (dynamic_cast<U&>((B&)a), 0); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } } +// { dg-message "dynamic type .A. of its operand does not have an unambiguous public base class .U." "" { target c++23_down } .-1 } +// { dg-error "uncaught exception" "" { target c++26 } .-2 } +constexpr bool b2 = (dynamic_cast<U&>((P1&)a), 0); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } } +// { dg-message "static type .const P1. of its operand is a non-public base class of dynamic type .A." "" { target c++23_down } .-1 } +// { dg-error "uncaught exception" "" { target c++26 } .-2 } +constexpr bool b3 = (dynamic_cast<U&>((P2&)a), 0); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } } +// { dg-message "static type .const P2. of its operand is a non-public base class of dynamic type .A." "" { target c++23_down } .-1 } +// { dg-error "uncaught exception" "" { target c++26 } .-2 } static_assert (dynamic_cast<U*>((B*)&a) == nullptr); static_assert (dynamic_cast<U*>((P1*)&a) == nullptr); diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic9.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic9.C index 7d42ffa..3a50dde 100644 --- a/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic9.C +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic9.C @@ -1,6 +1,22 @@ // PR c++/88337 - Implement P1327R1: Allow dynamic_cast/typeid in constexpr. // { dg-do compile { target c++20 } } +#if __cpp_constexpr_exceptions >= 202411L +namespace std { + struct exception { + constexpr exception () noexcept {} + constexpr virtual ~exception () noexcept {} + constexpr exception (const exception &) = default; + constexpr exception &operator= (const exception &) = default; + constexpr virtual const char *what () const noexcept { return "std::exception"; } + }; + struct bad_cast : public exception { + constexpr virtual ~bad_cast () noexcept {} + constexpr virtual const char *what () const noexcept { return "std::bad_cast"; } + }; +} +#endif + // Ambiguous base. struct A { virtual void a(); }; @@ -11,7 +27,8 @@ struct E : B, C, D { virtual void d(); }; constexpr E e; -constexpr bool b1 = (dynamic_cast<A&>((D&)e), false); // { dg-error "reference .dynamic_cast. failed" } -// { dg-message ".A. is an ambiguous base class of dynamic type .E. of its operand" "" { target *-*-* } .-1 } +constexpr bool b1 = (dynamic_cast<A&>((D&)e), false); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } } +// { dg-message ".A. is an ambiguous base class of dynamic type .E. of its operand" "" { target c++23_down } .-1 } +// { dg-error "uncaught exception" "" { target c++26 } .-2 } static_assert (dynamic_cast<A*>((D*)&e) == nullptr); diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new27.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new27.C new file mode 100644 index 0000000..a26fc7e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new27.C @@ -0,0 +1,41 @@ +// { dg-do compile { target c++20 } } + +#if __cpp_constexpr_exceptions >= 202411L +namespace std { + struct exception { + constexpr exception () noexcept {} + constexpr virtual ~exception () noexcept {} + constexpr exception (const exception &) = default; + constexpr exception &operator= (const exception &) = default; + constexpr virtual const char *what () const noexcept { return "std::exception"; } + }; + struct bad_alloc : public exception { + constexpr virtual ~bad_alloc () noexcept {} + constexpr virtual const char *what () const noexcept { return "std::bad_alloc"; } + }; + struct bad_array_new_length : public bad_alloc { + constexpr virtual ~bad_array_new_length () noexcept {} + constexpr virtual const char *what () const noexcept { return "std::bad_array_new_length"; } + }; +} +#endif + +constexpr int +foo (__SIZE_TYPE__ x, int y, int z) +{ + char (*a)[2] = new char[x][2]; // { dg-error "call to non-'constexpr' function 'void __cxa_throw_bad_array_new_length\\\(\\\)'" "" { target c++23_down } } + delete[] a; // { dg-message "declared here" "" { target c++23_down } .-1 } + int *b = new int[y]; // { dg-error "call to non-'constexpr' function 'void __cxa_throw_bad_array_new_length\\\(\\\)'" "" { target c++23_down } } + delete[] b; + int *c = new int[z]{1, 2, 3}; // { dg-error "call to non-'constexpr' function 'void __cxa_throw_bad_array_new_length\\\(\\\)'" "" { target c++23_down } } + delete[] c; + return 0; +} + +constexpr int a = foo (16, 2, 3); +constexpr int b = foo (-64, 2, 3); // { dg-message "in 'constexpr' expansion of" "" { target c++23_down } } + // { dg-error "uncaught exception" "" { target c++26 } .-1 } +constexpr int c = foo (16, -1, 3); // { dg-message "in 'constexpr' expansion of" "" { target c++23_down } } + // { dg-error "uncaught exception" "" { target c++26 } .-1 } +constexpr int d = foo (16, 2, 1); // { dg-message "in 'constexpr' expansion of" "" { target c++23_down } } + // { dg-error "uncaught exception" "" { target c++26 } .-1 } diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-typeid5.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-typeid5.C new file mode 100644 index 0000000..567383d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-typeid5.C @@ -0,0 +1,20 @@ +// PR c++/88337 - Implement P1327R1: Allow dynamic_cast/typeid in constexpr. +// { dg-do compile { target c++17 } } + +#include <typeinfo> + +template <class T> +constexpr bool foo () +{ + bool r = false; + const std::type_info &s = typeid( (r = true), *(T *) 0); // { dg-error "call to non-'constexpr' function 'void __cxa_bad_typeid\\\(\\\)'" "" { target c++23_down } } + return r; // { dg-message "declared here" "" { target c++23_down } .-1 } +} + +struct A {}; +struct B { virtual ~B () {} }; + +static_assert (!foo <int> ()); +static_assert (!foo <A> ()); +constexpr bool a = foo <B> (); // { dg-message "in 'constexpr' expansion of" "" { target c++23_down } } +// { dg-error "uncaught exception" "" { target c++26 } .-1 } diff --git a/gcc/testsuite/gcc.dg/flex-array-counted-by-pr121000.c b/gcc/testsuite/gcc.dg/flex-array-counted-by-pr121000.c new file mode 100644 index 0000000..5b9a2c6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/flex-array-counted-by-pr121000.c @@ -0,0 +1,43 @@ +/* PR middle-end/121000 */ +/* { dg-do run } */ +/* { dg-options "-O" } */ + +#include "builtin-object-size-common.h" + +/* The parameter m must be const qualified to avoid the m is + marked as TREE_SIDE_EFFECTS in IR. + The __builtin_dynamic_object_size will be folded as -1 by + fold_builtin_object_size when m is NOT const qualified. */ + +void +foo (int n, const int m) +{ + typedef int A[m]; + struct S { int n, m; A a[2]; A b[] __attribute__((counted_by (n))); } *p; + p = __builtin_malloc (sizeof (struct S) + sizeof (A) * n); + p->n = n; + p->m = m; + EXPECT (__builtin_dynamic_object_size (p->b, 1), sizeof (A) * n); +} + +/* The parameter m1, m2 must be const qualified to avoid the m is + marked as TREE_SIDE_EFFECTS in IR. + The __builtin_dynamic_object_size will be folded as -1 by + fold_builtin_object_size when m1 or m2 is NOT const qualified. */ +void +foo_1 (int n, const int m1, const int m2) +{ + typedef int A[m1][m2]; + struct S { int n; A a[2]; A b[] __attribute__((counted_by (n))); } *p; + p = __builtin_malloc (sizeof (struct S) + sizeof (A) * n); + p->n = n; + EXPECT (__builtin_dynamic_object_size (p->b, 1), sizeof (A) * n); +} + +int +main () +{ + foo (2, 10); + foo_1 (2, 10, 20); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/tree-prof/afdo-inline.c b/gcc/testsuite/gcc.dg/tree-prof/afdo-inline.c index b67b3cb..ded4068 100644 --- a/gcc/testsuite/gcc.dg/tree-prof/afdo-inline.c +++ b/gcc/testsuite/gcc.dg/tree-prof/afdo-inline.c @@ -1,6 +1,15 @@ /* { dg-options "-O2 -fdump-tree-einline-details --param early-inlining-insns=1" } */ /* { dg-require-profiling "-fauto-profile" } */ volatile int a[1000]; + +#define STR1(X) #X +#define STR2(X) STR1(X) + +int reta (int i) +asm(STR2(__USER_LABEL_PREFIX__) "renamed_reta"); +int test () +asm(STR2(__USER_LABEL_PREFIX__) "renamed_test"); + int reta (int i) { if (a[i]) diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-binary.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-binary.c index a8fd4c8..4708d57 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-binary.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-binary.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include "../pfalse-binary_0.h" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-binary_int_opt_n.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-binary_int_opt_n.c index 08cd6a0..4530b18 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-binary_int_opt_n.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-binary_int_opt_n.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include "../pfalse-binary_0.h" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-binary_opt_n.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-binary_opt_n.c index f5c9cbf..3097459 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-binary_opt_n.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-binary_opt_n.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include "../pfalse-binary_0.h" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-binary_opt_single_n.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-binary_opt_single_n.c index 91ae3c8..5e9d21c 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-binary_opt_single_n.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-binary_opt_single_n.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include "../pfalse-binary_0.h" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-binary_rotate.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-binary_rotate.c index 12368ce..768a740 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-binary_rotate.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-binary_rotate.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include <arm_sve.h> diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-binary_uint64_opt_n.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-binary_uint64_opt_n.c index dd52a58..ce14abb 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-binary_uint64_opt_n.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-binary_uint64_opt_n.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include "../pfalse-binary_0.h" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-binary_uint_opt_n.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-binary_uint_opt_n.c index e55ddfb..ceeb5ae 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-binary_uint_opt_n.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-binary_uint_opt_n.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include "../pfalse-binary_0.h" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-binaryxn.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-binaryxn.c index 6796229..f8b6b82 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-binaryxn.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-binaryxn.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include <arm_sve.h> diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-clast.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-clast.c index 7f2ec4a..45f74ed 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-clast.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-clast.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include "../pfalse-binary_0.h" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-compare_opt_n.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-compare_opt_n.c index d18427b..fc601a1 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-compare_opt_n.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-compare_opt_n.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include "../pfalse-binary_0.h" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-compare_wide_opt_n.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-compare_wide_opt_n.c index 983ab5c..4959f1d 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-compare_wide_opt_n.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-compare_wide_opt_n.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include "../pfalse-binary_0.h" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-count_pred.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-count_pred.c index de36b66..d8a8a81 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-count_pred.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-count_pred.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include "../pfalse-unary_0.h" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-fold_left.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-fold_left.c index 333140d..6cf2683 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-fold_left.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-fold_left.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include "../pfalse-binary_0.h" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-load.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-load.c index 93d6693..a32b636 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-load.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-load.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include <arm_sve.h> diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-load_ext.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-load_ext.c index c88686a..72e743b 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-load_ext.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-load_ext.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include <arm_sve.h> diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-load_ext_gather_index.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-load_ext_gather_index.c index 5f4b562fc..1178104 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-load_ext_gather_index.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-load_ext_gather_index.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include <arm_sve.h> diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-load_ext_gather_offset.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-load_ext_gather_offset.c index 0fe8ab3..ebd313a 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-load_ext_gather_offset.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-load_ext_gather_offset.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include <arm_sve.h> diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-load_gather_sv.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-load_gather_sv.c index 758f00f..d531987 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-load_gather_sv.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-load_gather_sv.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include <arm_sve.h> diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-load_gather_vs.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-load_gather_vs.c index f82471f..55c9cef 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-load_gather_vs.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-load_gather_vs.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include <arm_sve.h> diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-load_replicate.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-load_replicate.c index ba500b6..5532232 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-load_replicate.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-load_replicate.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2 -march=armv8.2-a+sve+f64mm" } */ +/* { dg-options "-O2 -march=armv8.2-a+sve+f64mm -funwind-tables" } */ #include <arm_sve.h> diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-prefetch.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-prefetch.c index 71894c4..78bdb0b 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-prefetch.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-prefetch.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include <arm_sve.h> diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-prefetch_gather_index.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-prefetch_gather_index.c index 1b7cc42..e219007 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-prefetch_gather_index.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-prefetch_gather_index.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include <arm_sve.h> diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-prefetch_gather_offset.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-prefetch_gather_offset.c index 7f4ff2d..98897e9 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-prefetch_gather_offset.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-prefetch_gather_offset.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include <arm_sve.h> diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-ptest.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-ptest.c index 0a587fc..c6fe6b9 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-ptest.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-ptest.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include "../pfalse-unary_0.h" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-rdffr.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-rdffr.c index d795f8e..7e2c1b9 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-rdffr.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-rdffr.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include <arm_sve.h> diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-reduction.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-reduction.c index 42b37ae..f7f75f6 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-reduction.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-reduction.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2 -fdump-tree-optimized" } */ +/* { dg-options "-O2 -fdump-tree-optimized -funwind-tables" } */ #include "../pfalse-unary_0.h" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-reduction_wide.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-reduction_wide.c index bd9a980..54b6197 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-reduction_wide.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-reduction_wide.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include "../pfalse-unary_0.h" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-shift_right_imm.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-shift_right_imm.c index 62a0755..e8b8a55 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-shift_right_imm.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-shift_right_imm.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include <arm_sve.h> diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-store.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-store.c index 751e60e..1539f58 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-store.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-store.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include <arm_sve.h> diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-store_scatter_index.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-store_scatter_index.c index 44792d3..21c8f6b 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-store_scatter_index.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-store_scatter_index.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include <arm_sve.h> diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-store_scatter_offset.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-store_scatter_offset.c index f3820e0..a908289 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-store_scatter_offset.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-store_scatter_offset.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include <arm_sve.h> diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-storexn.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-storexn.c index e49266d..12b5e14 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-storexn.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-storexn.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include <arm_sve.h> diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-ternary_opt_n.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-ternary_opt_n.c index acdd141..89873fc 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-ternary_opt_n.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-ternary_opt_n.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include <arm_sve.h> diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-ternary_rotate.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-ternary_rotate.c index 7698045..c6d2cfb 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-ternary_rotate.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-ternary_rotate.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include <arm_sve.h> diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-unary.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-unary.c index 037376b..8a3b3e0 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-unary.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-unary.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include "../pfalse-unary_0.h" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-unary_convert_narrowt.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-unary_convert_narrowt.c index 1287a70..04bc049 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-unary_convert_narrowt.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-unary_convert_narrowt.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2 -march=armv8.2-a+sve+bf16" } */ +/* { dg-options "-O2 -march=armv8.2-a+sve+bf16 -funwind-tables" } */ #include <arm_sve.h> diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-unary_convertxn.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-unary_convertxn.c index f519266..f39d2c5 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-unary_convertxn.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-unary_convertxn.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2 -march=armv8.2-a+sve+bf16" } */ +/* { dg-options "-O2 -march=armv8.2-a+sve+bf16 -funwind-tables" } */ #include <arm_sve.h> diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-unary_n.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-unary_n.c index fabde3e..4403e50 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-unary_n.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-unary_n.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include <arm_sve.h> diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-unary_pred.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-unary_pred.c index 46c9592..f06b067 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-unary_pred.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-unary_pred.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include "../pfalse-unary_0.h" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-unary_to_uint.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-unary_to_uint.c index b820bde..a851c4a 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-unary_to_uint.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-unary_to_uint.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include "../pfalse-unary_0.h" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-unaryxn.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-unaryxn.c index 1e99b7f..dde812b 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-unaryxn.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-unaryxn.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include "../pfalse-unary_0.h" diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-binary.c b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-binary.c index 94470a5..977fa39 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-binary.c +++ b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-binary.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include "../pfalse-binary_0.h" diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-binary_int_opt_n.c b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-binary_int_opt_n.c index b8747b8..b816fa1 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-binary_int_opt_n.c +++ b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-binary_int_opt_n.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include "../pfalse-binary_0.h" diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-binary_int_opt_single_n.c b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-binary_int_opt_single_n.c index 7cb7ee5..0e4427a 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-binary_int_opt_single_n.c +++ b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-binary_int_opt_single_n.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include "../pfalse-binary_0.h" diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-binary_opt_n.c b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-binary_opt_n.c index 787126f..81d0c82 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-binary_opt_n.c +++ b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-binary_opt_n.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include "../pfalse-binary_0.h" diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-binary_opt_single_n.c b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-binary_opt_single_n.c index 6b2b0a42..3920bdb 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-binary_opt_single_n.c +++ b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-binary_opt_single_n.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2 -march=armv8.2-a+sve2+faminmax" } */ +/* { dg-options "-O2 -march=armv8.2-a+sve2+faminmax -funwind-tables" } */ #include "../pfalse-binary_0.h" diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-binary_to_uint.c b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-binary_to_uint.c index a0a7f80..c7d10b3 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-binary_to_uint.c +++ b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-binary_to_uint.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include "../pfalse-binary_0.h" diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-binary_uint_opt_n.c b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-binary_uint_opt_n.c index c13db48..122fba7 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-binary_uint_opt_n.c +++ b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-binary_uint_opt_n.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include "../pfalse-binary_0.h" diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-binary_wide.c b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-binary_wide.c index 145b077..7f35859 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-binary_wide.c +++ b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-binary_wide.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include "../pfalse-binary_0.h" diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-compare.c b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-compare.c index da175db..b079a56 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-compare.c +++ b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-compare.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include "../pfalse-binary_0.h" diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-load_ext_gather_index_restricted.c b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-load_ext_gather_index_restricted.c index c0476ce..14e77c00 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-load_ext_gather_index_restricted.c +++ b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-load_ext_gather_index_restricted.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include <arm_sve.h> diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-load_ext_gather_offset_restricted.c b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-load_ext_gather_offset_restricted.c index f644024..b680548 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-load_ext_gather_offset_restricted.c +++ b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-load_ext_gather_offset_restricted.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include <arm_sve.h> diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-load_gather_sv_restricted.c b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-load_gather_sv_restricted.c index a48a8a9..6d1a356 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-load_gather_sv_restricted.c +++ b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-load_gather_sv_restricted.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include <arm_sve.h> diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-load_gather_vs.c b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-load_gather_vs.c index 1fc08a3..9cb4471 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-load_gather_vs.c +++ b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-load_gather_vs.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include <arm_sve.h> diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-shift_left_imm_to_uint.c b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-shift_left_imm_to_uint.c index bd2c937..e57a650 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-shift_left_imm_to_uint.c +++ b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-shift_left_imm_to_uint.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include <arm_sve.h> diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-shift_right_imm.c b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-shift_right_imm.c index f4994de..710ca73 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-shift_right_imm.c +++ b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-shift_right_imm.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include <arm_sve.h> diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-store_scatter_index_restricted.c b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-store_scatter_index_restricted.c index 6bec3b3..dc9cf46 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-store_scatter_index_restricted.c +++ b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-store_scatter_index_restricted.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include <arm_sve.h> diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-store_scatter_offset_restricted.c b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-store_scatter_offset_restricted.c index bcb4a14..2728c9b 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-store_scatter_offset_restricted.c +++ b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-store_scatter_offset_restricted.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include <arm_sve.h> diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-unary.c b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-unary.c index ba7e931..9f33295 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-unary.c +++ b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-unary.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2 -march=armv9.2-a+sve+sme" } */ +/* { dg-options "-O2 -march=armv9.2-a+sve+sme -funwind-tables" } */ #include "../pfalse-unary_0.h" diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-unary_convert.c b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-unary_convert.c index 7aa59ff..68769fe 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-unary_convert.c +++ b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-unary_convert.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include <arm_sve.h> diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-unary_convert_narrowt.c b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-unary_convert_narrowt.c index 1a4525c..692891f 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-unary_convert_narrowt.c +++ b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-unary_convert_narrowt.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include <arm_sve.h> diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-unary_to_int.c b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-unary_to_int.c index b64bfc3..7dffa1c 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-unary_to_int.c +++ b/gcc/testsuite/gcc.target/aarch64/sve2/pfalse-unary_to_int.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target elf } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -funwind-tables" } */ #include "../pfalse-unary_0.h" diff --git a/gcc/testsuite/gfortran.dg/asan/array_constructor_1.f90 b/gcc/testsuite/gfortran.dg/asan/array_constructor_1.f90 index 45eafac..a0c5507 100644 --- a/gcc/testsuite/gfortran.dg/asan/array_constructor_1.f90 +++ b/gcc/testsuite/gfortran.dg/asan/array_constructor_1.f90 @@ -9,6 +9,8 @@ program grow_type_array type(container), allocatable :: list(:) + allocate(list(0)) + list = [list, new_elem(5)] deallocate(list) diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc index 2d13ab7..8545eff 100644 --- a/gcc/tree-object-size.cc +++ b/gcc/tree-object-size.cc @@ -851,37 +851,32 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, /* Compute __builtin_object_size for a CALL to .ACCESS_WITH_SIZE, OBJECT_SIZE_TYPE is the second argument from __builtin_object_size. - The 2nd, 3rd, and the 4th parameters of the call determine the size of + + The 2nd, 3rd, and 4th parameters of the call determine the size of the CALL: 2nd argument REF_TO_SIZE: The reference to the size of the object, - 3rd argument CLASS_OF_SIZE: The size referenced by the REF_TO_SIZE represents - 0: the number of bytes; - 1: the number of the elements of the object type; - 4th argument TYPE_OF_SIZE: A constant 0 with its TYPE being the same as the TYPE - of the object referenced by REF_TO_SIZE - 6th argument: A constant 0 with the pointer TYPE to the original flexible - array type. - - The size of the element can be retrived from the TYPE of the 6th argument - of the call, which is the pointer to the array type. */ + 3rd argument TYPE_OF_SIZE + ACCESS_MODE: An integer constant with a pointer + TYPE. + The pointee TYPE of this pointer TYPE is the TYPE of the object referenced + by REF_TO_SIZE. + + 4th argument: The TYPE_SIZE_UNIT of the element TYPE of the array. */ + static tree access_with_size_object_size (const gcall *call, int object_size_type) { /* If not for dynamic object size, return. */ if ((object_size_type & OST_DYNAMIC) == 0) return size_unknown (object_size_type); - gcc_assert (gimple_call_internal_p (call, IFN_ACCESS_WITH_SIZE)); - /* The type of the 6th argument type is the pointer TYPE to the original - flexible array type. */ - tree pointer_to_array_type = TREE_TYPE (gimple_call_arg (call, 5)); - gcc_assert (POINTER_TYPE_P (pointer_to_array_type)); - tree element_type = TREE_TYPE (TREE_TYPE (pointer_to_array_type)); - tree element_size = TYPE_SIZE_UNIT (element_type); + tree ref_to_size = gimple_call_arg (call, 1); - unsigned int class_of_size = TREE_INT_CST_LOW (gimple_call_arg (call, 2)); - tree type = TREE_TYPE (gimple_call_arg (call, 3)); + tree type = TREE_TYPE (TREE_TYPE (gimple_call_arg (call, 2))); + + /* The 4th argument is the TYPE_SIZE_UNIT for the element of the original + flexible array. */ + tree element_size = gimple_call_arg (call, 3); tree size = fold_build2 (MEM_REF, type, ref_to_size, build_int_cst (ptr_type_node, 0)); @@ -895,12 +890,9 @@ access_with_size_object_size (const gcall *call, int object_size_type) build_zero_cst (type), size); } - if (class_of_size == 1) - size = size_binop (MULT_EXPR, - fold_convert (sizetype, size), - fold_convert (sizetype, element_size)); - else - size = fold_convert (sizetype, size); + size = size_binop (MULT_EXPR, + fold_convert (sizetype, size), + fold_convert (sizetype, element_size)); if (!todo) todo = TODO_update_ssa_only_virtuals; diff --git a/gcc/tree-vect-loop.cc b/gcc/tree-vect-loop.cc index 8ea0f45..56f80db 100644 --- a/gcc/tree-vect-loop.cc +++ b/gcc/tree-vect-loop.cc @@ -11079,7 +11079,7 @@ vect_get_loop_len (loop_vec_info loop_vinfo, gimple_stmt_iterator *gsi, factor = exact_div (nunits1, nunits2).to_constant (); tree iv_type = LOOP_VINFO_RGROUP_IV_TYPE (loop_vinfo); gimple_seq seq = NULL; - loop_len = gimple_build (&seq, RDIV_EXPR, iv_type, loop_len, + loop_len = gimple_build (&seq, EXACT_DIV_EXPR, iv_type, loop_len, build_int_cst (iv_type, factor)); if (seq) gsi_insert_seq_before (gsi, seq, GSI_SAME_STMT); diff --git a/gcc/tree-vect-slp.cc b/gcc/tree-vect-slp.cc index 5ef45fd..ad753869 100644 --- a/gcc/tree-vect-slp.cc +++ b/gcc/tree-vect-slp.cc @@ -5068,9 +5068,15 @@ vect_analyze_slp (vec_info *vinfo, unsigned max_tree_size, tree args0 = gimple_cond_lhs (stmt); tree args1 = gimple_cond_rhs (stmt); - /* These should be enforced by cond lowering. */ - gcc_assert (gimple_cond_code (stmt) == NE_EXPR); - gcc_assert (zerop (args1)); + /* These should be enforced by cond lowering, but if it failed + bail. */ + if (gimple_cond_code (stmt) != NE_EXPR + || TREE_TYPE (args0) != boolean_type_node + || !integer_zerop (args1)) + { + roots.release (); + continue; + } /* An argument without a loop def will be codegened from vectorizing the root gcond itself. As such we don't need to try to build an SLP tree |