aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2021-03-17 12:19:01 -0700
committerIan Lance Taylor <iant@golang.org>2021-03-17 12:19:01 -0700
commitf10c7c4596dda99d2ee872c995ae4aeda65adbdf (patch)
treea3451277603bc8fbe2eddce5f4ad63f790129a01 /gcc/cp
parentbc636c218f2b28da06cd1404d5b35d1f8cc43fd1 (diff)
parentf3e9c98a9f40fc24bb4ecef6aaa94ff799c8d587 (diff)
downloadgcc-f10c7c4596dda99d2ee872c995ae4aeda65adbdf.zip
gcc-f10c7c4596dda99d2ee872c995ae4aeda65adbdf.tar.gz
gcc-f10c7c4596dda99d2ee872c995ae4aeda65adbdf.tar.bz2
Merge from trunk revision f3e9c98a9f40fc24bb4ecef6aaa94ff799c8d587.
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog117
-rw-r--r--gcc/cp/call.c7
-rw-r--r--gcc/cp/coroutines.cc273
-rw-r--r--gcc/cp/decl.c80
-rw-r--r--gcc/cp/module.cc69
-rw-r--r--gcc/cp/name-lookup.c83
-rw-r--r--gcc/cp/name-lookup.h1
-rw-r--r--gcc/cp/tree.c2
8 files changed, 507 insertions, 125 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 06c6dfa..0f91414 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,120 @@
+2021-03-16 Jason Merrill <jason@redhat.com>
+
+ * tree.c (cp_tree_equal): Use real_identical.
+
+2021-03-16 Jakub Jelinek <jakub@redhat.com>
+
+ 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 <mliska@suse.cz>
+ Jason Merrill <jason@redhat.com>
+
+ 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 <nathan@acm.org>
+
+ 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 <iain@sandoe.co.uk>
+
+ 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 <iain@sandoe.co.uk>
+
+ 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 <iain@sandoe.co.uk>
+
+ 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 <iain@sandoe.co.uk>
+
+ 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 <tobias@codesourcery.com>
+
+ 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 <nathan@acm.org>
+
+ 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 <jakub@redhat.com>
+
+ 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 <nathan@acm.org>
+
+ 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 <nathan@acm.org>
+
+ 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 <nathan@acm.org>
PR c++/99423
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 7d12fea..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));
@@ -9504,6 +9507,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 +9533,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;
diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index c5aeb66..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);
@@ -2145,7 +2151,7 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody,
tree orig, hash_map<tree, param_info> *param_uses,
hash_map<tree, local_var_info> *local_var_uses,
vec<tree, va_gc> *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 +2273,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 +2388,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 +2401,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);
@@ -2955,7 +2975,9 @@ flatten_await_stmt (var_nest_node *n, hash_set<tree> *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 +2998,35 @@ flatten_await_stmt (var_nest_node *n, hash_set<tree> *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 +3215,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 +3250,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 +3264,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;
@@ -3407,6 +3451,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. */
@@ -3510,6 +3598,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<tree> 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
@@ -3872,9 +4042,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);
@@ -3918,6 +4088,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(); */
@@ -3976,7 +4165,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);
@@ -4013,14 +4208,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));
@@ -4164,9 +4351,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);
@@ -5048,7 +5237,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);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 9c7f6e5..8e8f37d 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 {
@@ -1108,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. */
@@ -1118,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)
@@ -8176,9 +8197,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 <varpool_node *> (node))
+ vec_safe_push (offload_vars, decl);
+ }
+ }
+ }
}
/* This is the last point we can lower alignment so give the target the
@@ -9231,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);
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 03359db..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);
@@ -12706,6 +12738,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 +13035,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..a6257f5 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<tree, va_gc> *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<tree, va_gc> *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<tree, va_gc> *args)
}
fns = value;
+ dedup (false);
}
return fns;
@@ -3385,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)))
@@ -3419,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);
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)