From 48ff383f0d9e917bcb7bcc091af413bcae07b440 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Fri, 12 Mar 2021 00:16:29 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 06c6dfa..6fb7bcf 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,21 @@ +2021-03-11 Nathan Sidwell + + PR c++/99248 + * name-lookup.c (lookup_elaborated_type_1): Access slot not bind + when there's a binding vector. + * ptree.c (cxx_print_xnode): Lazy flags are no longer a thing. + +2021-03-11 Nathan Sidwell + + PR c++/99528 + * module.cc (enum merge_kind): Delete MK_type_tmpl_spec, + MK_decl_tmpl_spec. + (trees_in::decl_value): Adjust add_mergeable_specialization call. + (trees_out::get_merge_kind): Adjust detecting a partial template + instantiation. + (trees_out::key_mergeable): Adjust handling same. + (trees_in::key_mergeabvle): Likewise. + 2021-03-10 Nathan Sidwell PR c++/99423 -- cgit v1.1 From 425afe1f0c907e6469cef1672160c9c95177e71a Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 12 Mar 2021 10:11:24 +0100 Subject: c++: Fix up calls to immediate functions returning reference [PR99507] build_cxx_call calls convert_from_reference at the end, so if an immediate function returns a reference, we were constant evaluating not just that call, but that call wrapped in an INDIRECT_REF. That unfortunately means it can constant evaluate to something non-addressable, so if code later needs to take its address it will fail. The following patch fixes that by undoing the convert_from_reference wrapping for the cxx_constant_value evaluation and readdding it ad the end. 2021-03-12 Jakub Jelinek PR c++/99507 * call.c (build_over_call): For immediate evaluation of functions that return references, undo convert_from_reference effects before calling cxx_constant_value and call convert_from_reference afterwards. * g++.dg/cpp2a/consteval19.C: New test. --- gcc/cp/call.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 7d12fea..33278b5 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -9504,6 +9504,9 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) if (immediate_invocation_p (fndecl, nargs)) { tree obj_arg = NULL_TREE; + /* Undo convert_from_reference called by build_cxx_call. */ + if (REFERENCE_REF_P (call)) + call = TREE_OPERAND (call, 0); if (DECL_CONSTRUCTOR_P (fndecl)) obj_arg = cand->first_arg ? cand->first_arg : (*args)[0]; if (obj_arg && is_dummy_object (obj_arg)) @@ -9527,6 +9530,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) call = cxx_constant_value (call, obj_arg); if (obj_arg && !error_operand_p (call)) call = build2 (INIT_EXPR, void_type_node, obj_arg, call); + call = convert_from_reference (call); } } return call; -- cgit v1.1 From 6e885ad3287388192e52e9b524dbaa408507c0a4 Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Fri, 12 Mar 2021 09:02:41 -0800 Subject: c++: ICE with using-decl [PR 99238] This ICE was caused by a stray TREE_VISITED marker. The lookup machinery was leaving it there due to the way I'd arranged for it to be cleared. That was presuming the name_lookup::value field didn't change, and that wasn't always true in the using-decl processing. I took the opportunity to break out a helper, and then call it immediately after lookups, rather than wait until destructor time. Added some asserts the module machinery to catch further cases of this. PR c++/99238 gcc/cp/ * module.cc (depset::hash::add_binding_entity): Assert not visited. (depset::add::add_specializations): Likewise. * name-lookup.c (name_lookup::dedup): New. (name_lookup::~name_lookup): Assert not deduping. (name_lookup::restore_state): Likewise. (name_lookup::add_overload): Replace outlined code with dedup call. (name_lookup::add_value): Likewise. (name_lookup::search_namespace_only): Likewise. (name_lookup::adl_namespace_fns): Likewise. (name_lookup::adl_class_fns): Likewise. (name_lookup::search_adl): Likewise. Add clearing dedup call. (name_lookup::search_qualified): Likewise. (name_lookup::search_unqualified): Likewise. gcc/testsuite/ * g++.dg/modules/pr99238.h: New. * g++.dg/modules/pr99238_a.H: New. * g++.dg/modules/pr99238_b.H: New. --- gcc/cp/module.cc | 5 ++++ gcc/cp/name-lookup.c | 79 ++++++++++++++++++++++------------------------------ 2 files changed, 39 insertions(+), 45 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 03359db..19bdfc7 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -12706,6 +12706,9 @@ depset::hash::add_binding_entity (tree decl, WMB_Flags flags, void *data_) *slot = data->binding; } + /* Make sure nobody left a tree visited lying about. */ + gcc_checking_assert (!TREE_VISITED (decl)); + if (flags & WMB_Using) { decl = ovl_make (decl, NULL_TREE); @@ -13000,6 +13003,8 @@ depset::hash::add_specializations (bool decl_p) have_spec:; #endif + /* Make sure nobody left a tree visited lying about. */ + gcc_checking_assert (!TREE_VISITED (spec)); depset *dep = make_dependency (spec, depset::EK_SPECIALIZATION); if (dep->is_special ()) { diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index d8839e2..9382a47 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -464,6 +464,7 @@ public: } ~name_lookup () { + gcc_checking_assert (!deduping); restore_state (); } @@ -471,6 +472,17 @@ private: /* Uncopyable, unmovable, unassignable. I am a rock. */ name_lookup (const name_lookup &); name_lookup &operator= (const name_lookup &); + public: + /* Turn on or off deduping mode. */ + void dedup (bool state) + { + if (deduping != state) + { + deduping = state; + lookup_mark (value, state); + } + } + protected: static bool seen_p (tree scope) { @@ -605,8 +617,7 @@ name_lookup::preserve_state () void name_lookup::restore_state () { - if (deduping) - lookup_mark (value, false); + gcc_checking_assert (!deduping); /* Unmark and empty this lookup's scope stack. */ for (unsigned ix = vec_safe_length (scopes); ix--;) @@ -703,12 +714,9 @@ name_lookup::add_overload (tree fns) probe = ovl_skip_hidden (probe); if (probe && TREE_CODE (probe) == OVERLOAD && OVL_DEDUP_P (probe)) - { - /* We're about to add something found by multiple paths, so - need to engage deduping mode. */ - lookup_mark (value, true); - deduping = true; - } + /* We're about to add something found by multiple paths, so need to + engage deduping mode. */ + dedup (true); } value = lookup_maybe_add (fns, value, deduping); @@ -737,12 +745,8 @@ name_lookup::add_value (tree new_val) value = ORIGINAL_NAMESPACE (value); else { - if (deduping) - { - /* Disengage deduping mode. */ - lookup_mark (value, false); - deduping = false; - } + /* Disengage deduping mode. */ + dedup (false); value = ambiguous (new_val, value); } } @@ -951,10 +955,7 @@ name_lookup::search_namespace_only (tree scope) if ((hit & 1 && BINDING_VECTOR_GLOBAL_DUPS_P (val)) || (hit & 2 && BINDING_VECTOR_PARTITION_DUPS_P (val))) - { - lookup_mark (value, true); - deduping = true; - } + dedup (true); } dup_detect |= dup; } @@ -1076,6 +1077,8 @@ name_lookup::search_qualified (tree scope, bool usings) found = search_usings (scope); } + dedup (false); + return found; } @@ -1177,6 +1180,8 @@ name_lookup::search_unqualified (tree scope, cp_binding_level *level) break; } + dedup (false); + /* Restore to incoming length. */ vec_safe_truncate (queue, length); @@ -1284,15 +1289,10 @@ name_lookup::adl_namespace_fns (tree scope, bitmap imports) else if (MODULE_BINDING_PARTITION_P (bind)) dup = 2; if (unsigned hit = dup_detect & dup) - { - if ((hit & 1 && BINDING_VECTOR_GLOBAL_DUPS_P (val)) - || (hit & 2 - && BINDING_VECTOR_PARTITION_DUPS_P (val))) - { - lookup_mark (value, true); - deduping = true; - } - } + if ((hit & 1 && BINDING_VECTOR_GLOBAL_DUPS_P (val)) + || (hit & 2 + && BINDING_VECTOR_PARTITION_DUPS_P (val))) + dedup (true); dup_detect |= dup; } @@ -1328,11 +1328,7 @@ name_lookup::adl_class_fns (tree type) if (CP_DECL_CONTEXT (fn) != context) continue; - if (!deduping) - { - lookup_mark (value, true); - deduping = true; - } + dedup (true); /* Template specializations are never found by name lookup. (Templates themselves can be found, but not template @@ -1634,12 +1630,9 @@ name_lookup::search_adl (tree fns, vec *args) if (vec_safe_length (scopes)) { /* Now do the lookups. */ - if (fns) - { - deduping = true; - lookup_mark (fns, true); - } value = fns; + if (fns) + dedup (true); /* INST_PATH will be NULL, if this is /not/ 2nd-phase ADL. */ bitmap inst_path = NULL; @@ -1697,14 +1690,9 @@ name_lookup::search_adl (tree fns, vec *args) if (tree bind = *mslot) { - if (!deduping) - { - /* We must turn on deduping, because some - other class from this module might also - be in this namespace. */ - deduping = true; - lookup_mark (value, true); - } + /* We must turn on deduping, because some other class + from this module might also be in this namespace. */ + dedup (true); /* Add the exported fns */ if (STAT_HACK_P (bind)) @@ -1715,6 +1703,7 @@ name_lookup::search_adl (tree fns, vec *args) } fns = value; + dedup (false); } return fns; -- cgit v1.1 From 6da2762a3b1c496bebe8334f6e68a834fe6a1055 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sat, 13 Mar 2021 00:16:20 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 6fb7bcf..370e725 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,30 @@ +2021-03-12 Nathan Sidwell + + PR c++/99238 + * module.cc (depset::hash::add_binding_entity): Assert not + visited. + (depset::add::add_specializations): Likewise. + * name-lookup.c (name_lookup::dedup): New. + (name_lookup::~name_lookup): Assert not deduping. + (name_lookup::restore_state): Likewise. + (name_lookup::add_overload): Replace outlined code with dedup + call. + (name_lookup::add_value): Likewise. + (name_lookup::search_namespace_only): Likewise. + (name_lookup::adl_namespace_fns): Likewise. + (name_lookup::adl_class_fns): Likewise. + (name_lookup::search_adl): Likewise. Add clearing dedup call. + (name_lookup::search_qualified): Likewise. + (name_lookup::search_unqualified): Likewise. + +2021-03-12 Jakub Jelinek + + PR c++/99507 + * call.c (build_over_call): For immediate evaluation of functions + that return references, undo convert_from_reference effects before + calling cxx_constant_value and call convert_from_reference + afterwards. + 2021-03-11 Nathan Sidwell PR c++/99248 -- cgit v1.1 From f20fe2cb213dffba47ec1b62c625590b5bbe50d7 Mon Sep 17 00:00:00 2001 From: Tobias Burnus Date: Mon, 15 Mar 2021 10:12:58 +0100 Subject: OpenMP: Fix 'omp declare target' handling for vars [PR99509] For variables with 'declare target' attribute, varpool_node::get_create marks variables as offload; however, if the node already exists, it is not updated. C/C++ may tag decl with 'declare target implicit', which may only be after varpool creation turned into 'declare target' or 'declare target link'; in this case, the tagging has to happen in the FE. gcc/c/ChangeLog: PR c++/99509 * c-decl.c (finish_decl): For 'omp declare target implicit' vars, ensure that the varpool node is marked as offloadable. gcc/cp/ChangeLog: PR c++/99509 * decl.c (cp_finish_decl): For 'omp declare target implicit' vars, ensure that the varpool node is marked as offloadable. libgomp/ChangeLog: PR c++/99509 * testsuite/libgomp.c-c++-common/declare_target-1.c: New test. --- gcc/cp/decl.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 9c7f6e5..1b671ce 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -53,7 +53,9 @@ along with GCC; see the file COPYING3. If not see #include "asan.h" #include "gcc-rich-location.h" #include "langhooks.h" +#include "context.h" /* For 'g'. */ #include "omp-general.h" +#include "omp-offload.h" /* For offload_vars. */ /* Possible cases of bad specifiers type used by bad_specifiers. */ enum bad_spec_place { @@ -8176,9 +8178,22 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, DECL_ATTRIBUTES (decl)) && !lookup_attribute ("omp declare target link", DECL_ATTRIBUTES (decl))) - DECL_ATTRIBUTES (decl) - = tree_cons (get_identifier ("omp declare target"), - NULL_TREE, DECL_ATTRIBUTES (decl)); + { + DECL_ATTRIBUTES (decl) + = tree_cons (get_identifier ("omp declare target"), + NULL_TREE, DECL_ATTRIBUTES (decl)); + symtab_node *node = symtab_node::get (decl); + if (node != NULL) + { + node->offloadable = 1; + if (ENABLE_OFFLOADING) + { + g->have_offload = true; + if (is_a (node)) + vec_safe_push (offload_vars, decl); + } + } + } } /* This is the last point we can lower alignment so give the target the -- cgit v1.1 From ed8198461735f9b5b3c2cbe50f9913690ce4b4ca Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Tue, 2 Mar 2021 10:12:58 +0000 Subject: coroutines : Avoid generating empty statements [PR96749]. In the compiler-only idiom: " a = (target expr creats temp, op uses temp) " the target expression variable needs to be promoted to a frame one (if the expression has a suspend point). However, the only uses of the var are in the second part of the compound expression - and we were creating an empty statement corresponding to the (now unused) first arm. This then produces the spurious warnings noted. Fixed by avoiding generation of a separate variable nest for isolated target expressions (or similarly isolated co_awaits used in a function call). gcc/cp/ChangeLog: PR c++/96749 * coroutines.cc (flatten_await_stmt): Allow for the case where a target expression variable only has uses in the second part of a compound expression. (maybe_promote_temps): Avoid emiting empty statements. gcc/testsuite/ChangeLog: PR c++/96749 * g++.dg/coroutines/pr96749-1.C: New test. * g++.dg/coroutines/pr96749-2.C: New test. --- gcc/cp/coroutines.cc | 64 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 20 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index c5aeb66..7124315 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -2955,7 +2955,9 @@ flatten_await_stmt (var_nest_node *n, hash_set *promoted, break; case TARGET_EXPR: { - /* We have a temporary; promote it. */ + /* We have a temporary; promote it, but allow for the idiom in code + generated by the compiler like + a = (target_expr produces temp, op uses temp). */ tree init = t; temps_used->add (init); tree var_type = TREE_TYPE (init); @@ -2976,20 +2978,35 @@ flatten_await_stmt (var_nest_node *n, hash_set *promoted, } else init = build2 (INIT_EXPR, var_type, var, init); - var_nest_node *ins - = new var_nest_node (var, init, n->prev, n); - /* We have to replace the target expr... */ - *v.entry = var; - /* ... and any uses of its var. */ - proxy_replace pr = {TREE_OPERAND (t, 0), var}; - cp_walk_tree (&n->init, replace_proxy, &pr, NULL); - /* Compiler-generated temporaries can also have uses in following - arms of compound expressions, which will be listed in 'replace_in' - if present. */ - if (replace_in) - cp_walk_tree (replace_in, replace_proxy, &pr, NULL); - flatten_await_stmt (ins, promoted, temps_used, NULL); - flatten_await_stmt (n, promoted, temps_used, NULL); + /* Simplify for the case that we have an init containing the temp + alone. */ + if (t == n->init && n->var == NULL_TREE) + { + n->var = var; + proxy_replace pr = {TREE_OPERAND (t, 0), var}; + cp_walk_tree (&init, replace_proxy, &pr, NULL); + n->init = init; + if (replace_in) + cp_walk_tree (replace_in, replace_proxy, &pr, NULL); + flatten_await_stmt (n, promoted, temps_used, NULL); + } + else + { + var_nest_node *ins + = new var_nest_node (var, init, n->prev, n); + /* We have to replace the target expr... */ + *v.entry = var; + /* ... and any uses of its var. */ + proxy_replace pr = {TREE_OPERAND (t, 0), var}; + cp_walk_tree (&n->init, replace_proxy, &pr, NULL); + /* Compiler-generated temporaries can also have uses in + following arms of compound expressions, which will be listed + in 'replace_in' if present. */ + if (replace_in) + cp_walk_tree (replace_in, replace_proxy, &pr, NULL); + flatten_await_stmt (ins, promoted, temps_used, NULL); + flatten_await_stmt (n, promoted, temps_used, NULL); + } return; } break; @@ -3178,7 +3195,6 @@ maybe_promote_temps (tree *stmt, void *d) gcc_checking_assert (root->next == NULL); tree vlist = NULL_TREE; var_nest_node *t = root; - gcc_checking_assert (!t->var); /* We build the bind scope expression from the bottom-up. EXPR_LIST holds the inner expression nest at the current cleanup level (becoming the final expression list when we've exhausted the @@ -3214,9 +3230,12 @@ maybe_promote_temps (tree *stmt, void *d) add_stmt (cl); /* push this onto the level above. */ } else if (expr_list) - add_stmt (expr_list); - else - gcc_unreachable (); + { + if (TREE_CODE (expr_list) != STATEMENT_LIST) + add_stmt (expr_list); + else if (!tsi_end_p (tsi_start (expr_list))) + add_stmt (expr_list); + } } else { @@ -3225,7 +3244,12 @@ maybe_promote_temps (tree *stmt, void *d) else finish_expr_stmt (t->init); if (expr_list) - add_stmt (expr_list); + { + if (TREE_CODE (expr_list) != STATEMENT_LIST) + add_stmt (expr_list); + else if (!tsi_end_p (tsi_start (expr_list))) + add_stmt (expr_list); + } } expr_list = pop_stmt_list (new_list); var_nest_node *old = t; -- cgit v1.1 From 26e0eb1071e318728bcd33f28d055729ac48792c Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Thu, 11 Mar 2021 14:22:37 +0000 Subject: coroutines : Handle for await expressions in for stmts [PR98480]. The handling of await expressions in the init, condition and iteration expressions of for loops had been omitted. Fixed thus. gcc/cp/ChangeLog: PR c++/98480 * coroutines.cc (replace_continue): Rewrite continue into 'goto label'. (await_statement_walker): Handle await expressions in the initializer, condition and iteration expressions of for loops. gcc/testsuite/ChangeLog: PR c++/98480 * g++.dg/coroutines/pr98480.C: New test. * g++.dg/coroutines/torture/co-await-24-for-init.C: New test. * g++.dg/coroutines/torture/co-await-25-for-condition.C: New test. * g++.dg/coroutines/torture/co-await-26-for-iteration-expr.C: New test. --- gcc/cp/coroutines.cc | 126 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 7124315..438538a 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -3431,6 +3431,50 @@ coro_build_add_if_not_cond_break (tree cond) finish_if_stmt (if_stmt); } +/* Tree walk callback to replace continue statements with goto label. */ +static tree +replace_continue (tree *stmt, int *do_subtree, void *d) +{ + tree expr = *stmt; + if (TREE_CODE (expr) == CLEANUP_POINT_EXPR) + expr = TREE_OPERAND (expr, 0); + if (CONVERT_EXPR_P (expr) && VOID_TYPE_P (expr)) + expr = TREE_OPERAND (expr, 0); + STRIP_NOPS (expr); + if (!STATEMENT_CLASS_P (expr)) + return NULL_TREE; + + switch (TREE_CODE (expr)) + { + /* Unless it's a special case, just walk the subtrees as usual. */ + default: return NULL_TREE; + + case CONTINUE_STMT: + { + tree *label = (tree *)d; + location_t loc = EXPR_LOCATION (expr); + /* re-write a continue to goto label. */ + *stmt = build_stmt (loc, GOTO_EXPR, *label); + *do_subtree = 0; + return NULL_TREE; + } + + /* Statements that do not require recursion. */ + case DECL_EXPR: + case BREAK_STMT: + case GOTO_EXPR: + case LABEL_EXPR: + case CASE_LABEL_EXPR: + case ASM_EXPR: + /* These must break recursion. */ + case FOR_STMT: + case WHILE_STMT: + case DO_STMT: + *do_subtree = 0; + return NULL_TREE; + } +} + /* Tree walk callback to analyze, register and pre-process statements that contain await expressions. */ @@ -3534,6 +3578,88 @@ await_statement_walker (tree *stmt, int *do_subtree, void *d) return res; } break; + case FOR_STMT: + { + /* for loops only need special treatment if the condition or the + iteration expression contain a co_await. */ + tree for_stmt = *stmt; + /* Sanity check. */ + if ((res = cp_walk_tree (&FOR_INIT_STMT (for_stmt), + analyze_expression_awaits, d, &visited))) + return res; + gcc_checking_assert (!awpts->saw_awaits); + + if ((res = cp_walk_tree (&FOR_COND (for_stmt), + analyze_expression_awaits, d, &visited))) + return res; + bool for_cond_await = awpts->saw_awaits != 0; + unsigned save_awaits = awpts->saw_awaits; + + if ((res = cp_walk_tree (&FOR_EXPR (for_stmt), + analyze_expression_awaits, d, &visited))) + return res; + bool for_expr_await = awpts->saw_awaits > save_awaits; + + /* If the condition has an await, then we will need to rewrite the + loop as + for (init expression;true;iteration expression) { + condition = await expression; + if (condition) + break; + ... + } + */ + if (for_cond_await) + { + tree insert_list = push_stmt_list (); + /* This will be expanded when the revised body is handled. */ + coro_build_add_if_not_cond_break (FOR_COND (for_stmt)); + /* .. add the original for body. */ + add_stmt (FOR_BODY (for_stmt)); + /* To make the new for body. */ + FOR_BODY (for_stmt) = pop_stmt_list (insert_list); + FOR_COND (for_stmt) = boolean_true_node; + } + /* If the iteration expression has an await, it's a bit more + tricky. + for (init expression;condition;) { + ... + iteration_expr_label: + iteration expression with await; + } + but, then we will need to re-write any continue statements into + 'goto iteration_expr_label:'. + */ + if (for_expr_await) + { + location_t sloc = EXPR_LOCATION (FOR_EXPR (for_stmt)); + tree insert_list = push_stmt_list (); + /* The original for body. */ + add_stmt (FOR_BODY (for_stmt)); + char *buf = xasprintf ("for.iter.expr.%u", awpts->cond_number++); + tree it_expr_label + = create_named_label_with_ctx (sloc, buf, NULL_TREE); + free (buf); + add_stmt (build_stmt (sloc, LABEL_EXPR, it_expr_label)); + add_stmt (FOR_EXPR (for_stmt)); + FOR_EXPR (for_stmt) = NULL_TREE; + FOR_BODY (for_stmt) = pop_stmt_list (insert_list); + /* rewrite continue statements to goto label. */ + hash_set visited_continue; + if ((res = cp_walk_tree (&FOR_BODY (for_stmt), + replace_continue, &it_expr_label, &visited_continue))) + return res; + } + + /* So now walk the body statement (list), if there were no await + expressions, then this handles the original body - and either + way we will have finished with this statement. */ + res = cp_walk_tree (&FOR_BODY (for_stmt), + await_statement_walker, d, NULL); + *do_subtree = 0; /* Done subtrees. */ + return res; + } + break; case WHILE_STMT: { /* We turn 'while (cond with awaits) stmt' into -- cgit v1.1 From 020b286c769f4dc8a6b45491351f6bc2e69d7a7f Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Thu, 11 Mar 2021 17:04:14 +0000 Subject: coroutines : Handle rethrow from unhandled_exception [PR98704]. Although there is still some discussion in CWG 2451 on this, the implementors are agreed on the intent. When promise.unhandled_exception () is entered, the coroutine is considered to be still running - returning from the method will cause the final await expression to be evaluated. If the method throws, that action is considered to make the coroutine suspend (since, otherwise, it would be impossible to reclaim its resources, since one cannot destroy a running coro). The wording issue is to do with how to represent the place at which the coroutine should be considered suspended. For the implementation here, that place is immediately before the promise life-time ends. A handler for the rethrown exception, can thus call xxxx.destroy() which will run DTORs for the promise and any parameter copies [as needed] then the coroutine frame will be deallocated. At present, we also set "done=true" in this case (for compatibility with other current implementations). One might consider 'done()' to be misleading in the case of an abnormal termination - that is also part of the CWG 2451 discussion. gcc/cp/ChangeLog: PR c++/98704 * coroutines.cc (build_actor_fn): Make destroy index 1 correspond to the abnormal unhandled_exception() exit. Substitute the proxy for the resume index. (coro_rewrite_function_body): Arrange to reset the resume index and make done = true for a rethrown exception from unhandled_exception (). (morph_fn_to_coro): Adjust calls to build_actor_fn and coro_rewrite_function_body. gcc/testsuite/ChangeLog: PR c++/98704 * g++.dg/coroutines/torture/pr98704.C: New test. --- gcc/cp/coroutines.cc | 75 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 21 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 438538a..ea714da 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -2145,7 +2145,7 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, tree orig, hash_map *param_uses, hash_map *local_var_uses, vec *param_dtor_list, tree resume_fn_field, - unsigned body_count, tree frame_size) + tree resume_idx_field, unsigned body_count, tree frame_size) { verify_stmt_tree (fnbody); /* Some things we inherit from the original function. */ @@ -2267,6 +2267,17 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, b = coro_build_cvt_void_expr_stmt (b, loc); add_stmt (b); + /* The destroy point numbered #1 is special, in that it is reached from a + coroutine that is suspended after re-throwing from unhandled_exception(). + This label just invokes the cleanup of promise, param copies and the + frame itself. */ + tree del_promise_label + = create_named_label_with_ctx (loc, "coro.delete.promise", actor); + b = build_case_label (build_int_cst (short_unsigned_type_node, 1), NULL_TREE, + create_anon_label_with_ctx (loc, actor)); + add_stmt (b); + add_stmt (build_stmt (loc, GOTO_EXPR, del_promise_label)); + short unsigned lab_num = 3; for (unsigned destr_pt = 0; destr_pt < body_count; destr_pt++) { @@ -2371,9 +2382,10 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, p_data.to = ap; cp_walk_tree (&fnbody, replace_proxy, &p_data, NULL); - /* Set the actor pointer to null, so that 'done' will work. - Resume from here is UB anyway - although a 'ready' await will - branch to the final resume, and fall through to the destroy. */ + /* The rewrite of the function adds code to set the __resume field to + nullptr when the coroutine is done and also the index to zero when + calling an unhandled exception. These are represented by two proxies + in the function, so rewrite them to the proper frame access. */ tree resume_m = lookup_member (coro_frame_type, get_identifier ("__resume"), /*protect=*/1, /*want_type=*/0, tf_warning_or_error); @@ -2383,12 +2395,14 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, p_data.to = res_x; cp_walk_tree (&fnbody, replace_proxy, &p_data, NULL); + p_data.from = resume_idx_field; + p_data.to = rat; + cp_walk_tree (&fnbody, replace_proxy, &p_data, NULL); + /* Add in our function body with the co_returns rewritten to final form. */ add_stmt (fnbody); /* now do the tail of the function. */ - tree del_promise_label - = create_named_label_with_ctx (loc, "coro.delete.promise", actor); r = build_stmt (loc, LABEL_EXPR, del_promise_label); add_stmt (r); @@ -4022,9 +4036,9 @@ act_des_fn (tree orig, tree fn_type, tree coro_frame_ptr, const char* name) /* Re-write the body as per [dcl.fct.def.coroutine] / 5. */ static tree -coro_rewrite_function_body (location_t fn_start, tree fnbody, - tree orig, tree resume_fn_ptr_type, - tree& resume_fn_field, tree& fs_label) +coro_rewrite_function_body (location_t fn_start, tree fnbody, tree orig, + tree resume_fn_ptr_type, tree& resume_fn_field, + tree& resume_idx_field, tree& fs_label) { /* This will be our new outer scope. */ tree update_body = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL); @@ -4068,6 +4082,25 @@ coro_rewrite_function_body (location_t fn_start, tree fnbody, tree return_void = get_coroutine_return_void_expr (current_function_decl, fn_start, false); + /* We will need to be able to set the resume function pointer to nullptr + to signal that the coroutine is 'done'. */ + resume_fn_field + = build_lang_decl (VAR_DECL, get_identifier ("resume.fn.ptr.proxy"), + resume_fn_ptr_type); + DECL_ARTIFICIAL (resume_fn_field) = true; + tree zero_resume + = build1 (CONVERT_EXPR, resume_fn_ptr_type, integer_zero_node); + zero_resume + = build2 (INIT_EXPR, resume_fn_ptr_type, resume_fn_field, zero_resume); + /* Likewise, the resume index needs to be reset. */ + resume_idx_field + = build_lang_decl (VAR_DECL, get_identifier ("resume.index.proxy"), + short_unsigned_type_node); + DECL_ARTIFICIAL (resume_idx_field) = true; + tree zero_resume_idx = build_int_cst (short_unsigned_type_node, 0); + zero_resume_idx = build2 (INIT_EXPR, short_unsigned_type_node, + resume_idx_field, zero_resume_idx); + if (flag_exceptions) { /* Build promise.unhandled_exception(); */ @@ -4126,7 +4159,13 @@ coro_rewrite_function_body (location_t fn_start, tree fnbody, IF_SCOPE (not_iarc_if) = NULL; not_iarc_if = do_poplevel (iarc_scope); add_stmt (not_iarc_if); - /* ... else call the promise unhandled exception method. */ + /* ... else call the promise unhandled exception method + but first we set done = true and the resume index to 0. + If the unhandled exception method returns, then we continue + to the final await expression (which duplicates the clearing of + the field). */ + finish_expr_stmt (zero_resume); + finish_expr_stmt (zero_resume_idx); ueh = maybe_cleanup_point_expr_void (ueh); add_stmt (ueh); finish_handler (handler); @@ -4163,14 +4202,6 @@ coro_rewrite_function_body (location_t fn_start, tree fnbody, /* Before entering the final suspend point, we signal that this point has been reached by setting the resume function pointer to zero (this is what the 'done()' builtin tests) as per the current ABI. */ - resume_fn_field - = build_lang_decl (VAR_DECL, get_identifier ("resume.fn.ptr.proxy"), - resume_fn_ptr_type); - DECL_ARTIFICIAL (resume_fn_field) = true; - tree zero_resume - = build1 (CONVERT_EXPR, resume_fn_ptr_type, integer_zero_node); - zero_resume - = build2 (INIT_EXPR, resume_fn_ptr_type, resume_fn_field, zero_resume); finish_expr_stmt (zero_resume); finish_expr_stmt (build_init_or_final_await (fn_start, true)); BIND_EXPR_BODY (update_body) = pop_stmt_list (BIND_EXPR_BODY (update_body)); @@ -4314,9 +4345,11 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) the requirements for the coroutine frame. */ tree resume_fn_field = NULL_TREE; + tree resume_idx_field = NULL_TREE; tree fs_label = NULL_TREE; - fnbody = coro_rewrite_function_body (fn_start, fnbody, orig, act_des_fn_ptr, - resume_fn_field, fs_label); + fnbody = coro_rewrite_function_body (fn_start, fnbody, orig, + act_des_fn_ptr, resume_fn_field, + resume_idx_field, fs_label); /* Build our dummy coro frame layout. */ coro_frame_type = begin_class_definition (coro_frame_type); @@ -5198,7 +5231,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) /* Build the actor... */ build_actor_fn (fn_start, coro_frame_type, actor, fnbody, orig, param_uses, &local_var_uses, param_dtor_list, resume_fn_field, - body_aw_points.await_number, frame_size); + resume_idx_field, body_aw_points.await_number, frame_size); /* Destroyer ... */ build_destroy_fn (fn_start, coro_frame_type, destroy, actor); -- cgit v1.1 From 541840b891d61ea70cddd046c96698bb70d7f52c Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Sun, 14 Mar 2021 14:42:52 +0000 Subject: coroutines : Convert await_ready () expressions to bool [PR99047]. The awaiter.await_ready() should be converted per [expr.await]/3 (3.6) await-ready is the expression e.await_ready(), contextually converted to bool. gcc/cp/ChangeLog: PR c++/99047 * coroutines.cc (expand_one_await_expression): If the await_ready() expression is not a boolean then convert it as required. gcc/testsuite/ChangeLog: PR c++/99047 * g++.dg/coroutines/pr99047.C: New test. --- gcc/cp/coroutines.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index ea714da..51984ef 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -1586,7 +1586,13 @@ expand_one_await_expression (tree *stmt, tree *await_expr, void *d) /* Use the await_ready() call to test if we need to suspend. */ tree ready_cond = TREE_VEC_ELT (awaiter_calls, 0); /* await_ready(). */ - ready_cond = build1_loc (loc, TRUTH_NOT_EXPR, boolean_type_node, ready_cond); + /* Convert to bool, if necessary. */ + if (TREE_CODE (TREE_TYPE (ready_cond)) != BOOLEAN_TYPE) + ready_cond = cp_convert (boolean_type_node, ready_cond, + tf_warning_or_error); + /* Be aggressive in folding here, since there are a significant number of + cases where the ready condition is constant. */ + ready_cond = invert_truthvalue_loc (loc, ready_cond); ready_cond = build1_loc (loc, CLEANUP_POINT_EXPR, boolean_type_node, ready_cond); -- cgit v1.1 From 3c5b6d24e664f951c6b4e42738aa1ef5489e5f66 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Tue, 16 Mar 2021 10:55:35 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 370e725..5dcdebd 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,45 @@ +2021-03-15 Iain Sandoe + + PR c++/99047 + * coroutines.cc (expand_one_await_expression): If the + await_ready() expression is not a boolean then convert it + as required. + +2021-03-15 Iain Sandoe + + PR c++/98704 + * coroutines.cc (build_actor_fn): Make destroy index 1 + correspond to the abnormal unhandled_exception() exit. + Substitute the proxy for the resume index. + (coro_rewrite_function_body): Arrange to reset the resume + index and make done = true for a rethrown exception from + unhandled_exception (). + (morph_fn_to_coro): Adjust calls to build_actor_fn and + coro_rewrite_function_body. + +2021-03-15 Iain Sandoe + + PR c++/98480 + * coroutines.cc (replace_continue): Rewrite continue into + 'goto label'. + (await_statement_walker): Handle await expressions in the + initializer, condition and iteration expressions of for + loops. + +2021-03-15 Iain Sandoe + + PR c++/96749 + * coroutines.cc (flatten_await_stmt): Allow for the case + where a target expression variable only has uses in the + second part of a compound expression. + (maybe_promote_temps): Avoid emiting empty statements. + +2021-03-15 Tobias Burnus + + PR c++/99509 + * decl.c (cp_finish_decl): For 'omp declare target implicit' vars, + ensure that the varpool node is marked as offloadable. + 2021-03-12 Nathan Sidwell PR c++/99238 -- cgit v1.1 From 7b900dca607dceaae2db372365f682a4979c7826 Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Mon, 15 Mar 2021 11:25:46 -0700 Subject: c++: Incorrect type equivalence [PR 99496] This bug was caused by not marking dependent template aliases correctly -- these things look like typedefs, but are not (necessarily) equivalent to the canonical type. We need to record that. PR c++/99496 gcc/cp/ * module.cc (trees_out::decl_value): Adjust typedef streaming, indicate whether it is a dependent alias. (trees_in::decl_value): Likewise. Set as dependent alias, if it is one. gcc/testsuite/ * g++.dg/modules/pr99496_a.H: New. * g++.dg/modules/pr99496_b.C: New. --- gcc/cp/module.cc | 64 ++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 48 insertions(+), 16 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 19bdfc7..6dbdc92 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -7719,18 +7719,35 @@ trees_out::decl_value (tree decl, depset *dep) } } - bool is_typedef = (!type && inner - && TREE_CODE (inner) == TYPE_DECL - && DECL_ORIGINAL_TYPE (inner) - && TYPE_NAME (TREE_TYPE (inner)) == inner); - if (is_typedef) + bool is_typedef = false; + if (!type && inner && TREE_CODE (inner) == TYPE_DECL) { - /* A typedef type. */ - int type_tag = insert (TREE_TYPE (inner)); + tree t = TREE_TYPE (inner); + unsigned tdef_flags = 0; + if (DECL_ORIGINAL_TYPE (inner) + && TYPE_NAME (TREE_TYPE (inner)) == inner) + { + tdef_flags |= 1; + if (TYPE_STRUCTURAL_EQUALITY_P (t) + && TYPE_DEPENDENT_P_VALID (t) + && TYPE_DEPENDENT_P (t)) + tdef_flags |= 2; + } if (streaming_p ()) - dump (dumper::TREE) - && dump ("Cloned:%d typedef %C:%N", type_tag, - TREE_CODE (TREE_TYPE (inner)), TREE_TYPE (inner)); + u (tdef_flags); + + if (tdef_flags & 1) + { + /* A typedef type. */ + int type_tag = insert (t); + if (streaming_p ()) + dump (dumper::TREE) + && dump ("Cloned:%d %s %C:%N", type_tag, + tdef_flags & 2 ? "depalias" : "typedef", + TREE_CODE (t), t); + + is_typedef = true; + } } if (streaming_p () && DECL_MAYBE_IN_CHARGE_CDTOR_P (decl)) @@ -7993,12 +8010,6 @@ trees_in::decl_value () dump (dumper::TREE) && dump ("Read:%d %C:%N", tag, TREE_CODE (decl), decl); - /* Regular typedefs will have a NULL TREE_TYPE at this point. */ - bool is_typedef = (!type && inner - && TREE_CODE (inner) == TYPE_DECL - && DECL_ORIGINAL_TYPE (inner) - && !TREE_TYPE (inner)); - existing = back_refs[~tag]; bool installed = install_entity (existing); bool is_new = existing == decl; @@ -8030,6 +8041,16 @@ trees_in::decl_value () } } + /* Regular typedefs will have a NULL TREE_TYPE at this point. */ + unsigned tdef_flags = 0; + bool is_typedef = false; + if (!type && inner && TREE_CODE (inner) == TYPE_DECL) + { + tdef_flags = u (); + if (tdef_flags & 1) + is_typedef = true; + } + if (is_new) { /* A newly discovered node. */ @@ -8076,6 +8097,14 @@ trees_in::decl_value () TREE_TYPE (inner) = DECL_ORIGINAL_TYPE (inner); DECL_ORIGINAL_TYPE (inner) = NULL_TREE; set_underlying_type (inner); + if (tdef_flags & 2) + { + /* Match instantiate_alias_template's handling. */ + tree type = TREE_TYPE (inner); + TYPE_DEPENDENT_P (type) = true; + TYPE_DEPENDENT_P_VALID (type) = true; + SET_TYPE_STRUCTURAL_EQUALITY (type); + } } if (inner_tag) @@ -10661,6 +10690,9 @@ trees_in::key_mergeable (int tag, merge_kind mk, tree decl, tree inner, spec.tmpl = tree_node (); spec.args = tree_node (); + if (get_overrun ()) + return error_mark_node; + DECL_NAME (decl) = DECL_NAME (spec.tmpl); DECL_CONTEXT (decl) = DECL_CONTEXT (spec.tmpl); DECL_NAME (inner) = DECL_NAME (decl); -- cgit v1.1 From 1c7bec8bfbc5457c1b57d0e3b67f5d6bc8812e57 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Wed, 3 Mar 2021 09:38:55 +0100 Subject: c++: support target attr for DECL_LOCAL_DECL_P fns [PR99108] We crash when target attribute get_function_versions_dispatcher is called for a function that is not registered in call graph. This was happening because we were calling it for the function-local decls that aren't in the symbol table, instead of the corresponding namespace-scope decls that are. gcc/cp/ChangeLog: PR c++/99108 * call.c (get_function_version_dispatcher): Handle DECL_LOCAL_DECL_P. * decl.c (maybe_version_functions): Likewise. (maybe_mark_function_versioned): New. * name-lookup.c (push_local_extern_decl_alias): No longer static. * name-lookup.h (push_local_extern_decl_alias): Adjust. gcc/testsuite/ChangeLog: PR c++/99108 * g++.target/i386/pr99108.C: New test. Co-authored-by: Jason Merrill --- gcc/cp/call.c | 3 +++ gcc/cp/decl.c | 35 +++++++++++++++++++++++++++-------- gcc/cp/name-lookup.c | 4 ++-- gcc/cp/name-lookup.h | 1 + 4 files changed, 33 insertions(+), 10 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 33278b5..29f4b50 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -8469,6 +8469,9 @@ get_function_version_dispatcher (tree fn) { tree dispatcher_decl = NULL; + if (DECL_LOCAL_DECL_P (fn)) + fn = DECL_LOCAL_DECL_ALIAS (fn); + gcc_assert (TREE_CODE (fn) == FUNCTION_DECL && DECL_FUNCTION_VERSIONED (fn)); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 1b671ce..56092eb 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -1110,6 +1110,21 @@ decls_match (tree newdecl, tree olddecl, bool record_versions /* = true */) return types_match; } +/* Mark DECL as versioned if it isn't already. */ + +static void +maybe_mark_function_versioned (tree decl) +{ + if (!DECL_FUNCTION_VERSIONED (decl)) + { + DECL_FUNCTION_VERSIONED (decl) = 1; + /* If DECL_ASSEMBLER_NAME has already been set, re-mangle + to include the version marker. */ + if (DECL_ASSEMBLER_NAME_SET_P (decl)) + mangle_decl (decl); + } +} + /* NEWDECL and OLDDECL have identical signatures. If they are different versions adjust them and return true. If RECORD is set to true, record function versions. */ @@ -1120,18 +1135,22 @@ maybe_version_functions (tree newdecl, tree olddecl, bool record) if (!targetm.target_option.function_versions (newdecl, olddecl)) return false; - if (!DECL_FUNCTION_VERSIONED (olddecl)) + maybe_mark_function_versioned (olddecl); + if (DECL_LOCAL_DECL_P (olddecl)) { - DECL_FUNCTION_VERSIONED (olddecl) = 1; - if (DECL_ASSEMBLER_NAME_SET_P (olddecl)) - mangle_decl (olddecl); + olddecl = DECL_LOCAL_DECL_ALIAS (olddecl); + maybe_mark_function_versioned (olddecl); } - if (!DECL_FUNCTION_VERSIONED (newdecl)) + maybe_mark_function_versioned (newdecl); + if (DECL_LOCAL_DECL_P (newdecl)) { - DECL_FUNCTION_VERSIONED (newdecl) = 1; - if (DECL_ASSEMBLER_NAME_SET_P (newdecl)) - mangle_decl (newdecl); + /* Unfortunately, we can get here before pushdecl naturally calls + push_local_extern_decl_alias, so we need to call it directly. */ + if (!DECL_LOCAL_DECL_ALIAS (newdecl)) + push_local_extern_decl_alias (newdecl); + newdecl = DECL_LOCAL_DECL_ALIAS (newdecl); + maybe_mark_function_versioned (newdecl); } if (record) diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 9382a47..a6257f5 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -3374,7 +3374,7 @@ set_decl_context_in_fn (tree ctx, tree decl) /* DECL is a local extern decl. Find or create the namespace-scope decl that it aliases. Also, determines the linkage of DECL. */ -static void +void push_local_extern_decl_alias (tree decl) { if (dependent_type_p (TREE_TYPE (decl))) @@ -3408,7 +3408,7 @@ push_local_extern_decl_alias (tree decl) if (binding && TREE_CODE (binding) != TREE_LIST) for (ovl_iterator iter (binding); iter; ++iter) - if (decls_match (*iter, decl)) + if (decls_match (decl, *iter, /*record_versions*/false)) { alias = *iter; break; diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h index 67e923f..f63c4f5 100644 --- a/gcc/cp/name-lookup.h +++ b/gcc/cp/name-lookup.h @@ -453,6 +453,7 @@ extern void cp_emit_debug_info_for_using (tree, tree); extern void finish_nonmember_using_decl (tree scope, tree name); extern void finish_using_directive (tree target, tree attribs); +void push_local_extern_decl_alias (tree decl); extern tree pushdecl (tree, bool hiding = false); extern tree pushdecl_outermost_localscope (tree); extern tree pushdecl_top_level (tree); -- cgit v1.1 From 0251051db64f13c9a31a05c8133c31dc50b2b235 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 16 Mar 2021 21:17:44 +0100 Subject: c++: Ensure correct destruction order of local statics [PR99613] As mentioned in the PR, if end of two constructions of local statics is strongly ordered, their destructors should be run in the reverse order. As we run __cxa_guard_release before calling __cxa_atexit, it is possible that we have two threads that access two local statics in the same order for the first time, one thread wins the __cxa_guard_acquire on the first one but is rescheduled in between the __cxa_guard_release and __cxa_atexit calls, then the other thread is scheduled and wins __cxa_guard_acquire on the second one and calls __cxa_quard_release and __cxa_atexit and only afterwards the first thread calls its __cxa_atexit. This means a variable whose completion of the constructor strongly happened after the completion of the other one will be destructed after the other variable is destructed. The following patch fixes that by swapping the __cxa_guard_release and __cxa_atexit calls. 2021-03-16 Jakub Jelinek PR c++/99613 * decl.c (expand_static_init): For thread guards, call __cxa_atexit before calling __cxa_guard_release rather than after it. Formatting fixes. --- gcc/cp/decl.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 56092eb..8e8f37d 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -9265,17 +9265,25 @@ expand_static_init (tree decl, tree init) /* Do the initialization itself. */ init = add_stmt_to_compound (begin, init); - init = add_stmt_to_compound - (init, build2 (MODIFY_EXPR, void_type_node, flag, boolean_true_node)); - init = add_stmt_to_compound - (init, build_call_n (release_fn, 1, guard_addr)); + init = add_stmt_to_compound (init, + build2 (MODIFY_EXPR, void_type_node, + flag, boolean_true_node)); + + /* Use atexit to register a function for destroying this static + variable. Do this before calling __cxa_guard_release. */ + init = add_stmt_to_compound (init, register_dtor_fn (decl)); + + init = add_stmt_to_compound (init, build_call_n (release_fn, 1, + guard_addr)); } else - init = add_stmt_to_compound (init, set_guard (guard)); + { + init = add_stmt_to_compound (init, set_guard (guard)); - /* Use atexit to register a function for destroying this static - variable. */ - init = add_stmt_to_compound (init, register_dtor_fn (decl)); + /* Use atexit to register a function for destroying this static + variable. */ + init = add_stmt_to_compound (init, register_dtor_fn (decl)); + } finish_expr_stmt (init); -- cgit v1.1 From a4101e5aafc512dc32b8d529b2bafb116a3612de Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 16 Mar 2021 16:06:27 -0400 Subject: c++: Fix NaN as C++20 template argument C++20 allows floating-point types for non-type template parameters; floating-point values are considered to be equivalent template arguments if they are "identical", which conveniently seems to map onto an existing GCC predicate. gcc/cp/ChangeLog: * tree.c (cp_tree_equal): Use real_identical. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/nontype-float1.C: New test. --- gcc/cp/tree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 3c46975..3acb643 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -3740,7 +3740,7 @@ cp_tree_equal (tree t1, tree t2) return tree_int_cst_equal (t1, t2); case REAL_CST: - return real_equal (&TREE_REAL_CST (t1), &TREE_REAL_CST (t2)); + return real_identical (&TREE_REAL_CST (t1), &TREE_REAL_CST (t2)); case STRING_CST: return TREE_STRING_LENGTH (t1) == TREE_STRING_LENGTH (t2) -- cgit v1.1 From bc2127767a0076afdbc9075fda29f97f82ef7ec6 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Wed, 17 Mar 2021 00:16:25 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 5dcdebd..0f91414 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,33 @@ +2021-03-16 Jason Merrill + + * tree.c (cp_tree_equal): Use real_identical. + +2021-03-16 Jakub Jelinek + + PR c++/99613 + * decl.c (expand_static_init): For thread guards, call __cxa_atexit + before calling __cxa_guard_release rather than after it. Formatting + fixes. + +2021-03-16 Martin Liska + Jason Merrill + + PR c++/99108 + * call.c (get_function_version_dispatcher): Handle + DECL_LOCAL_DECL_P. + * decl.c (maybe_version_functions): Likewise. + (maybe_mark_function_versioned): New. + * name-lookup.c (push_local_extern_decl_alias): No longer static. + * name-lookup.h (push_local_extern_decl_alias): Adjust. + +2021-03-16 Nathan Sidwell + + PR c++/99496 + * module.cc (trees_out::decl_value): Adjust typedef streaming, + indicate whether it is a dependent alias. + (trees_in::decl_value): Likewise. Set as dependent alias, if it + is one. + 2021-03-15 Iain Sandoe PR c++/99047 -- cgit v1.1