diff options
author | Ian Lance Taylor <iant@golang.org> | 2021-09-17 08:46:39 -0700 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2021-09-17 08:46:39 -0700 |
commit | a0791d0ed4f147ef347e83f4aedc7ad03f1a2008 (patch) | |
tree | 7b3526910798e4cff7a7200d684383046bac6225 /gcc/cp | |
parent | e252b51ccde010cbd2a146485d8045103cd99533 (diff) | |
parent | 89be17a1b231ade643f28fbe616d53377e069da8 (diff) | |
download | gcc-a0791d0ed4f147ef347e83f4aedc7ad03f1a2008.zip gcc-a0791d0ed4f147ef347e83f4aedc7ad03f1a2008.tar.gz gcc-a0791d0ed4f147ef347e83f4aedc7ad03f1a2008.tar.bz2 |
Merge from trunk revision 89be17a1b231ade643f28fbe616d53377e069da8.
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/ChangeLog | 156 | ||||
-rw-r--r-- | gcc/cp/call.c | 17 | ||||
-rw-r--r-- | gcc/cp/constexpr.c | 37 | ||||
-rw-r--r-- | gcc/cp/constraint.cc | 8 | ||||
-rw-r--r-- | gcc/cp/coroutines.cc | 655 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 9 | ||||
-rw-r--r-- | gcc/cp/decl.c | 60 | ||||
-rw-r--r-- | gcc/cp/method.c | 1 | ||||
-rw-r--r-- | gcc/cp/name-lookup.c | 7 | ||||
-rw-r--r-- | gcc/cp/parser.c | 486 | ||||
-rw-r--r-- | gcc/cp/pt.c | 56 | ||||
-rw-r--r-- | gcc/cp/rtti.c | 95 | ||||
-rw-r--r-- | gcc/cp/semantics.c | 31 | ||||
-rw-r--r-- | gcc/cp/typeck2.c | 15 |
14 files changed, 1189 insertions, 444 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 8d1ec5d..4061a85 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,159 @@ +2021-09-16 Patrick Palka <ppalka@redhat.com> + + PR c++/98486 + * constraint.cc (get_normalized_constraints_from_decl): Always + look up constraints using the most general template. + * decl.c (grokdeclarator): Set constraints on a static data + member template. + * pt.c (determine_specialization): Check constraints on a + variable template. + +2021-09-16 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (await_statement_walker): Code cleanups. + +2021-09-16 Jason Merrill <jason@redhat.com> + + * constexpr.c (cxx_eval_outermost_constant_expr): Use + protected_set_expr_location. + +2021-09-15 Patrick Palka <ppalka@redhat.com> + + PR c++/101904 + * call.c (build_user_type_conversion_1): Add tf_conv to complain. + (add_candidates): When in a SFINAE context, instead of adding a + candidate to bad_fns just mark it unviable. + +2021-09-15 Jason Merrill <jason@redhat.com> + + * cp-tree.h (parsing_function_declarator): Declare. + * name-lookup.c (set_decl_context_in_fn): Use it. + * parser.c (cp_parser_direct_declarator): Use it. + (parsing_function_declarator): New. + +2021-09-15 Jakub Jelinek <jakub@redhat.com> + + PR c++/88578 + PR c++/102295 + * typeck2.c (split_nonconstant_init_1): Don't throw away empty + initializers of flexible array members if they have non-zero type + size. + +2021-09-15 Patrick Palka <ppalka@redhat.com> + + PR c++/102050 + * decl.c (grok_special_member_properties): Set + TYPE_HAS_COPY_CTOR, TYPE_HAS_DEFAULT_CONSTRUCTOR + and TYPE_HAS_LIST_CTOR independently from each other. + +2021-09-15 Jason Merrill <jason@redhat.com> + + * decl.c (cxx_init_decl_processing): Only warn about odd + interference sizes if they were specified with --param. + +2021-09-15 Jason Merrill <jason@redhat.com> + + PR c++/48396 + * cp-tree.h (enum cp_tree_index): Remove CPTI_TYPE_INFO_PTR_TYPE. + (type_info_ptr_type): Remove. + * rtti.c (init_rtti_processing): Don't predeclare std::type_info. + (typeid_ok_p): Check for null const_type_info_type_node. + (type_info_ptr_type, get_void_tinfo_ptr): New fns. + (get_tinfo_decl_dynamic, get_tinfo_ptr): Use them. + (ptr_initializer, ptm_initializer, get_pseudo_ti_init): Use them. + (get_tinfo_desc): Use const_ptr_type_node. + +2021-09-15 Jason Merrill <jason@redhat.com> + + * parser.c (cp_parser_template_name): Move object type. + (cp_parser_pre_parsed_nested_name_specifier): Likewise. + +2021-09-15 Jason Merrill <jason@redhat.com> + + * parser.c (cp_parser_unqualified_id): Only complain about ~A<T> in + a declarator. + +2021-09-14 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (struct param_info): Add copy_var. + (build_actor_fn): Use simplified param references. + (register_param_uses): Likewise. + (rewrite_param_uses): Likewise. + (analyze_fn_parms): New function. + (coro_rewrite_function_body): Add proxies for the fn + parameters to the outer bind scope of the rewritten code. + (morph_fn_to_coro): Use simplified version of param ref. + +2021-09-14 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (coro_resume_fn_id, coro_destroy_fn_id, + coro_promise_id, coro_frame_needs_free_id, coro_resume_index_id, + coro_self_handle_id, coro_actor_continue_id, + coro_frame_i_a_r_c_id): New. + (coro_init_identifiers): Initialize new name identifiers. + (coro_promise_type_found_p): Use pre-built identifiers. + (struct await_xform_data): Remove unused fields. + (transform_await_expr): Delete code that is now unused. + (build_actor_fn): Simplify interface, use pre-built identifiers and + remove transforms that are no longer needed. + (build_destroy_fn): Use revised field names. + (register_local_var_uses): Use pre-built identifiers. + (coro_rewrite_function_body): Simplify interface, use pre-built + identifiers. Generate proxy vars in the outer bind expr scope for the + implementation state that we wish to expose. + (morph_fn_to_coro): Adjust comments for new variable names, use pre- + built identifiers. Remove unused code to generate frame entries for + the implementation state. Adjust call for build_actor_fn. + +2021-09-14 Patrick Palka <ppalka@redhat.com> + + PR c++/102163 + * constexpr.c (cxx_eval_call_expression): After evaluating a + subobject constructor call for an empty union member, produce a + side effect that makes sure the member gets activated. + +2021-09-14 Jakub Jelinek <jakub@redhat.com> + + PR c++/102295 + * decl.c (layout_var_decl): For aggregates ending with a flexible + array member, add the size of the initializer for that member to + DECL_SIZE and DECL_SIZE_UNIT. + +2021-09-14 Jakub Jelinek <jakub@redhat.com> + + PR c++/102305 + * method.c (is_xible_helper): Call complete_type on to. + +2021-09-14 Jason Merrill <jason@redhat.com> + + * decl.c (cxx_init_decl_processing): Don't warn if L1 cache line + size is smaller than maxalign. + +2021-09-13 Jason Merrill <jason@redhat.com> + + * constexpr.c (maybe_warn_about_constant_value): + Complain about std::hardware_destructive_interference_size. + (cxx_eval_constant_expression): Call it. + * decl.c (cxx_init_decl_processing): Check + --param *-interference-size values. + +2021-09-13 Patrick Palka <ppalka@redhat.com> + + PR c++/101764 + * cp-tree.h (PACK_EXPANSION_FORCE_EXTRA_ARGS_P): New accessor + macro. + * pt.c (has_extra_args_mechanism_p): New function. + (find_parameter_pack_data::found_extra_args_tree_p): New data + member. + (find_parameter_packs_r): Set ppd->found_extra_args_tree_p + appropriately. + (make_pack_expansion): Set PACK_EXPANSION_FORCE_EXTRA_ARGS_P if + ppd.found_extra_args_tree_p. + (use_pack_expansion_extra_args_p): Return true if there were + unsubstituted packs and PACK_EXPANSION_FORCE_EXTRA_ARGS_P. + (tsubst_pack_expansion): Pass the pack expansion to + use_pack_expansion_extra_args_p. + 2021-09-10 Jakub Jelinek <jakub@redhat.com> * parser.c (cp_parser_omp_atomic): Allow acq_rel on atomic read/write diff --git a/gcc/cp/call.c b/gcc/cp/call.c index b6011c1..c5601d9 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -4175,6 +4175,9 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags, flags |= LOOKUP_NO_CONVERSION; if (BRACE_ENCLOSED_INITIALIZER_P (expr)) flags |= LOOKUP_NO_NARROWING; + /* Prevent add_candidates from treating a non-strictly viable candidate + as unviable. */ + complain |= tf_conv; /* It's OK to bind a temporary for converting constructor arguments, but not in converting the return value of a conversion operator. */ @@ -6232,8 +6235,18 @@ add_candidates (tree fns, tree first_arg, const vec<tree, va_gc> *args, stopped at the first bad conversion). Add the function to BAD_FNS to fully reconsider later if we don't find any strictly viable candidates. */ - bad_fns = lookup_add (fn, bad_fns); - *candidates = (*candidates)->next; + if (complain & (tf_error | tf_conv)) + { + bad_fns = lookup_add (fn, bad_fns); + *candidates = (*candidates)->next; + } + else + /* But if we're in a SFINAE context, just mark this candidate as + unviable outright and avoid potentially reconsidering it. + This is safe to do because in a SFINAE context, performing a bad + conversion is always an error (even with -fpermissive), so a + non-strictly viable candidate is effectively unviable anyway. */ + cand->viable = 0; } } if (which == non_templates && !seen_perfect) diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 0c2498a..8a5dd06 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -2787,12 +2787,34 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, &jump_target); 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 - value by evaluating *this, but we don't bother; there's - no need to put such a call in the hash table. */ - result = lval ? ctx->object : ctx->ctor; + { + /* 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 + value by evaluating *this, but we don't bother; there's + no need to put such a call in the hash table. */ + result = lval ? ctx->object : ctx->ctor; + + /* If we've just evaluated a subobject constructor call for an + empty union member, it might not have produced a side effect + that actually activated the union member. So produce such a + side effect now to ensure the union appears initialized. */ + if (!result && new_obj + && TREE_CODE (new_obj) == COMPONENT_REF + && TREE_CODE (TREE_TYPE + (TREE_OPERAND (new_obj, 0))) == UNION_TYPE + && is_really_empty_class (TREE_TYPE (new_obj), + /*ignore_vptr*/false)) + { + tree activate = build2 (MODIFY_EXPR, TREE_TYPE (new_obj), + new_obj, + build_constructor (TREE_TYPE (new_obj), + NULL)); + cxx_eval_constant_expression (ctx, activate, lval, + non_constant_p, overflow_p); + ggc_free (activate); + } + } else if (VOID_TYPE_P (TREE_TYPE (res))) result = void_node; else @@ -7480,8 +7502,7 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, /* Remember the original location if that wouldn't need a wrapper. */ if (location_t loc = EXPR_LOCATION (t)) - if (CAN_HAVE_LOCATION_P (r)) - SET_EXPR_LOCATION (r, loc); + protected_set_expr_location (r, loc); return r; } diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 1aaf1e2..2896efd 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -918,20 +918,22 @@ get_normalized_constraints_from_decl (tree d, bool diag = false) tmpl = most_general_template (tmpl); } + d = tmpl ? tmpl : decl; + /* If we're not diagnosing errors, use cached constraints, if any. */ if (!diag) - if (tree *p = hash_map_safe_get (normalized_map, tmpl)) + if (tree *p = hash_map_safe_get (normalized_map, d)) return *p; tree norm = NULL_TREE; - if (tree ci = get_constraints (decl)) + if (tree ci = get_constraints (d)) { push_access_scope_guard pas (decl); norm = get_normalized_constraints_from_info (ci, tmpl, diag); } if (!diag) - hash_map_safe_put<hm_ggc> (normalized_map, tmpl, norm); + hash_map_safe_put<hm_ggc> (normalized_map, d, norm); return norm; } diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 9ab2be0..fbd5c49 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -215,7 +215,19 @@ static GTY(()) tree coro_await_ready_identifier; static GTY(()) tree coro_await_suspend_identifier; static GTY(()) tree coro_await_resume_identifier; -/* Create the identifiers used by the coroutines library interfaces. */ +/* Accessors for the coroutine frame state used by the implementation. */ + +static GTY(()) tree coro_resume_fn_id; +static GTY(()) tree coro_destroy_fn_id; +static GTY(()) tree coro_promise_id; +static GTY(()) tree coro_frame_needs_free_id; +static GTY(()) tree coro_resume_index_id; +static GTY(()) tree coro_self_handle_id; +static GTY(()) tree coro_actor_continue_id; +static GTY(()) tree coro_frame_i_a_r_c_id; + +/* Create the identifiers used by the coroutines library interfaces and + the implementation frame state. */ static void coro_init_identifiers () @@ -241,6 +253,16 @@ coro_init_identifiers () coro_await_ready_identifier = get_identifier ("await_ready"); coro_await_suspend_identifier = get_identifier ("await_suspend"); coro_await_resume_identifier = get_identifier ("await_resume"); + + /* Coroutine state frame field accessors. */ + coro_resume_fn_id = get_identifier ("_Coro_resume_fn"); + coro_destroy_fn_id = get_identifier ("_Coro_destroy_fn"); + coro_promise_id = get_identifier ("_Coro_promise"); + coro_frame_needs_free_id = get_identifier ("_Coro_frame_needs_free"); + coro_frame_i_a_r_c_id = get_identifier ("_Coro_initial_await_resume_called"); + coro_resume_index_id = get_identifier ("_Coro_resume_index"); + coro_self_handle_id = get_identifier ("_Coro_self_handle"); + coro_actor_continue_id = get_identifier ("_Coro_actor_continue"); } /* Trees we only need to set up once. */ @@ -513,12 +535,12 @@ coro_promise_type_found_p (tree fndecl, location_t loc) /* Build a proxy for a handle to "self" as the param to await_suspend() calls. */ coro_info->self_h_proxy - = build_lang_decl (VAR_DECL, get_identifier ("self_h.proxy"), + = build_lang_decl (VAR_DECL, coro_self_handle_id, coro_info->handle_type); /* Build a proxy for the promise so that we can perform lookups. */ coro_info->promise_proxy - = build_lang_decl (VAR_DECL, get_identifier ("promise.proxy"), + = build_lang_decl (VAR_DECL, coro_promise_id, coro_info->promise_type); /* Note where we first saw a coroutine keyword. */ @@ -1864,10 +1886,6 @@ struct await_xform_data { tree actor_fn; /* Decl for context. */ tree actor_frame; - tree promise_proxy; - tree real_promise; - tree self_h_proxy; - tree real_self_h; }; /* When we built the await expressions, we didn't know the coro frame @@ -1888,7 +1906,6 @@ transform_await_expr (tree await_expr, await_xform_data *xform) /* So, on entry, we have: in : CO_AWAIT_EXPR (a, e_proxy, o, awr_call_vector, mode) We no longer need a [it had diagnostic value, maybe?] - We need to replace the promise proxy in all elements We need to replace the e_proxy in the awr_call. */ tree coro_frame_type = TREE_TYPE (xform->actor_frame); @@ -1914,16 +1931,6 @@ transform_await_expr (tree await_expr, await_xform_data *xform) TREE_OPERAND (await_expr, 1) = as; } - /* Now do the self_handle. */ - data.from = xform->self_h_proxy; - data.to = xform->real_self_h; - cp_walk_tree (&await_expr, replace_proxy, &data, NULL); - - /* Now do the promise. */ - data.from = xform->promise_proxy; - data.to = xform->real_promise; - cp_walk_tree (&await_expr, replace_proxy, &data, NULL); - return await_expr; } @@ -1957,6 +1964,7 @@ transform_await_wrapper (tree *stmt, int *do_subtree, void *d) struct param_info { tree field_id; /* The name of the copy in the coroutine frame. */ + tree copy_var; /* The local var proxy for the frame copy. */ vec<tree *> *body_uses; /* Worklist of uses, void if there are none. */ tree frame_type; /* The type used to represent this parm in the frame. */ tree orig_type; /* The original type of the parm (not as passed). */ @@ -2110,15 +2118,13 @@ coro_get_frame_dtor (tree coro_fp, tree orig, tree frame_size, static void 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, - tree resume_idx_field, unsigned body_count, tree frame_size) + tree orig, hash_map<tree, local_var_info> *local_var_uses, + vec<tree, va_gc> *param_dtor_list, + tree resume_idx_var, unsigned body_count, tree frame_size) { verify_stmt_tree (fnbody); /* Some things we inherit from the original function. */ tree handle_type = get_coroutine_handle_type (orig); - tree self_h_proxy = get_coroutine_self_handle_proxy (orig); tree promise_type = get_coroutine_promise_type (orig); tree promise_proxy = get_coroutine_promise_proxy (orig); @@ -2136,11 +2142,12 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, tree top_block = make_node (BLOCK); BIND_EXPR_BLOCK (actor_bind) = top_block; - tree continuation = coro_build_artificial_var (loc, "_Coro_actor_continue", + tree continuation = coro_build_artificial_var (loc, coro_actor_continue_id, void_coro_handle_type, actor, NULL_TREE); BIND_EXPR_VARS (actor_bind) = continuation; + BLOCK_VARS (top_block) = BIND_EXPR_VARS (actor_bind) ; /* Link in the block associated with the outer scope of the re-written function body. */ @@ -2163,44 +2170,13 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, /* Declare the continuation handle. */ add_decl_expr (continuation); - /* Re-write param references in the body, no code should be generated - here. */ - if (DECL_ARGUMENTS (orig)) - { - tree arg; - for (arg = DECL_ARGUMENTS (orig); arg != NULL; arg = DECL_CHAIN (arg)) - { - bool existed; - param_info &parm = param_uses->get_or_insert (arg, &existed); - if (!parm.body_uses) - continue; /* Wasn't used in the original function body. */ - - tree fld_ref = lookup_member (coro_frame_type, parm.field_id, - /*protect=*/1, /*want_type=*/0, - tf_warning_or_error); - tree fld_idx = build3_loc (loc, COMPONENT_REF, parm.frame_type, - actor_frame, fld_ref, NULL_TREE); - - /* We keep these in the frame as a regular pointer, so convert that - back to the type expected. */ - if (parm.pt_ref) - fld_idx = build1_loc (loc, CONVERT_EXPR, TREE_TYPE (arg), fld_idx); - - int i; - tree *puse; - FOR_EACH_VEC_ELT (*parm.body_uses, i, puse) - *puse = fld_idx; - } - } - /* Re-write local vars, similarly. */ local_vars_transform xform_vars_data = {actor, actor_frame, coro_frame_type, loc, local_var_uses}; cp_walk_tree (&fnbody, transform_local_var_uses, &xform_vars_data, NULL); - tree resume_idx_name = get_identifier ("__resume_at"); - tree rat_field = lookup_member (coro_frame_type, resume_idx_name, 1, 0, - tf_warning_or_error); + tree rat_field = lookup_member (coro_frame_type, coro_resume_index_id, + 1, 0, tf_warning_or_error); tree rat = build3 (COMPONENT_REF, short_unsigned_type_node, actor_frame, rat_field, NULL_TREE); @@ -2302,14 +2278,8 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, tree r = build_stmt (loc, LABEL_EXPR, actor_begin_label); add_stmt (r); - /* actor's version of the promise. */ - tree ap_m = lookup_member (coro_frame_type, get_identifier ("__p"), 1, 0, - tf_warning_or_error); - tree ap = build_class_member_access_expr (actor_frame, ap_m, NULL_TREE, false, - tf_warning_or_error); - /* actor's coroutine 'self handle'. */ - tree ash_m = lookup_member (coro_frame_type, get_identifier ("__self_h"), 1, + tree ash_m = lookup_member (coro_frame_type, coro_self_handle_id, 1, 0, tf_warning_or_error); tree ash = build_class_member_access_expr (actor_frame, ash_m, NULL_TREE, false, tf_warning_or_error); @@ -2329,37 +2299,13 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, /* Now we know the real promise, and enough about the frame layout to decide where to put things. */ - await_xform_data xform - = {actor, actor_frame, promise_proxy, ap, self_h_proxy, ash}; + await_xform_data xform = {actor, actor_frame}; /* Transform the await expressions in the function body. Only do each await tree once! */ hash_set<tree> pset; cp_walk_tree (&fnbody, transform_await_wrapper, &xform, &pset); - /* Now replace the promise proxy with its real value. */ - proxy_replace p_data; - p_data.from = promise_proxy; - p_data.to = ap; - cp_walk_tree (&fnbody, replace_proxy, &p_data, NULL); - - /* 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); - tree res_x = build_class_member_access_expr (actor_frame, resume_m, NULL_TREE, - false, tf_warning_or_error); - p_data.from = resume_fn_field; - 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); @@ -2368,7 +2314,7 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, add_stmt (r); /* Destructors for the things we built explicitly. */ - r = build_special_member_call (ap, complete_dtor_identifier, NULL, + r = build_special_member_call (promise_proxy, complete_dtor_identifier, NULL, promise_type, LOOKUP_NORMAL, tf_warning_or_error); add_stmt (r); @@ -2381,7 +2327,7 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, /* Here deallocate the frame (if we allocated it), which we will have at present. */ tree fnf_m - = lookup_member (coro_frame_type, get_identifier ("__frame_needs_free"), 1, + = lookup_member (coro_frame_type, coro_frame_needs_free_id, 1, 0, tf_warning_or_error); tree fnf2_x = build_class_member_access_expr (actor_frame, fnf_m, NULL_TREE, false, tf_warning_or_error); @@ -2460,18 +2406,10 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, gcc_checking_assert (maybe_cleanup_point_expr_void (r) == r); add_stmt (r); - /* We will need to know which resume point number should be encoded. */ - tree res_idx_m - = lookup_member (coro_frame_type, resume_idx_name, - /*protect=*/1, /*want_type=*/0, tf_warning_or_error); - tree resume_pt_number - = build_class_member_access_expr (actor_frame, res_idx_m, NULL_TREE, false, - tf_warning_or_error); - /* We've now rewritten the tree and added the initial and final co_awaits. Now pass over the tree and expand the co_awaits. */ - coro_aw_data data = {actor, actor_fp, resume_pt_number, NULL_TREE, + coro_aw_data data = {actor, actor_fp, resume_idx_var, NULL_TREE, ash, del_promise_label, ret_label, continue_label, continuation, 2}; cp_walk_tree (&actor_body, await_statement_expander, &data, NULL); @@ -2485,7 +2423,7 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, } /* The prototype 'destroy' function : - frame->__resume_at |= 1; + frame->__Coro_resume_index |= 1; actor (frame); */ static void @@ -2504,11 +2442,10 @@ build_destroy_fn (location_t loc, tree coro_frame_type, tree destroy, tree destr_frame = build1 (INDIRECT_REF, coro_frame_type, destr_fp); - tree resume_idx_name = get_identifier ("__resume_at"); - tree rat_field = lookup_member (coro_frame_type, resume_idx_name, 1, 0, - tf_warning_or_error); - tree rat = build3 (COMPONENT_REF, short_unsigned_type_node, destr_frame, - rat_field, NULL_TREE); + tree rat_field = lookup_member (coro_frame_type, coro_resume_index_id, + 1, 0, tf_warning_or_error); + tree rat = build3 (COMPONENT_REF, short_unsigned_type_node, + destr_frame, rat_field, NULL_TREE); /* _resume_at |= 1 */ tree dstr_idx = build2 (BIT_IOR_EXPR, short_unsigned_type_node, rat, @@ -3475,16 +3412,11 @@ await_statement_walker (tree *stmt, int *do_subtree, void *d) return NULL_TREE; } - /* We have something to be handled as a single statement. */ - bool has_cleanup_wrapper = TREE_CODE (*stmt) == CLEANUP_POINT_EXPR; - hash_set<tree> visited; - awpts->saw_awaits = 0; - hash_set<tree> truth_aoif_to_expand; - awpts->truth_aoif_to_expand = &truth_aoif_to_expand; - awpts->needs_truth_if_exp = false; - awpts->has_awaiter_init = false; + /* We have something to be handled as a single statement. We have to handle + a few statements specially where await statements have to be moved out of + constructs. */ tree expr = *stmt; - if (has_cleanup_wrapper) + if (TREE_CODE (*stmt) == CLEANUP_POINT_EXPR) expr = TREE_OPERAND (expr, 0); STRIP_NOPS (expr); @@ -3500,6 +3432,8 @@ await_statement_walker (tree *stmt, int *do_subtree, void *d) transforms can be implemented. */ case IF_STMT: { + tree *await_ptr; + hash_set<tree> visited; /* Transform 'if (cond with awaits) then stmt1 else stmt2' into bool cond = cond with awaits. if (cond) then stmt1 else stmt2. */ @@ -3507,10 +3441,8 @@ await_statement_walker (tree *stmt, int *do_subtree, void *d) /* We treat the condition as if it was a stand-alone statement, to see if there are any await expressions which will be analyzed and registered. */ - if ((res = cp_walk_tree (&IF_COND (if_stmt), - analyze_expression_awaits, d, &visited))) - return res; - if (!awpts->saw_awaits) + if (!(cp_walk_tree (&IF_COND (if_stmt), + find_any_await, &await_ptr, &visited))) return NULL_TREE; /* Nothing special to do here. */ gcc_checking_assert (!awpts->bind_stack->is_empty()); @@ -3526,7 +3458,7 @@ await_statement_walker (tree *stmt, int *do_subtree, void *d) /* We want to initialize the new variable with the expression that contains the await(s) and potentially also needs to have truth_if expressions expanded. */ - tree new_s = build2_loc (sloc, MODIFY_EXPR, boolean_type_node, + tree new_s = build2_loc (sloc, INIT_EXPR, boolean_type_node, newvar, cond_inner); finish_expr_stmt (new_s); IF_COND (if_stmt) = newvar; @@ -3540,25 +3472,27 @@ await_statement_walker (tree *stmt, int *do_subtree, void *d) break; case FOR_STMT: { + tree *await_ptr; + hash_set<tree> visited; /* 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; + /* At present, the FE always generates a separate initializer for + the FOR_INIT_STMT, when the expression has an await. Check that + this assumption holds in the future. */ + gcc_checking_assert + (!(cp_walk_tree (&FOR_INIT_STMT (for_stmt), find_any_await, + &await_ptr, &visited))); + + visited.empty (); + bool for_cond_await + = cp_walk_tree (&FOR_COND (for_stmt), find_any_await, + &await_ptr, &visited); + + visited.empty (); + bool for_expr_await + = cp_walk_tree (&FOR_EXPR (for_stmt), find_any_await, + &await_ptr, &visited); /* If the condition has an await, then we will need to rewrite the loop as @@ -3601,7 +3535,12 @@ await_statement_walker (tree *stmt, int *do_subtree, void *d) = 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)); + tree for_expr = FOR_EXPR (for_stmt); + /* Present the iteration expression as a statement. */ + if (TREE_CODE (for_expr) == CLEANUP_POINT_EXPR) + for_expr = TREE_OPERAND (for_expr, 0); + STRIP_NOPS (for_expr); + finish_expr_stmt (for_expr); FOR_EXPR (for_stmt) = NULL_TREE; FOR_BODY (for_stmt) = pop_stmt_list (insert_list); /* rewrite continue statements to goto label. */ @@ -3628,11 +3567,11 @@ await_statement_walker (tree *stmt, int *do_subtree, void *d) break; stmt.. } */ + tree *await_ptr; + hash_set<tree> visited; tree while_stmt = *stmt; - if ((res = cp_walk_tree (&WHILE_COND (while_stmt), - analyze_expression_awaits, d, &visited))) - return res; - if (!awpts->saw_awaits) + if (!(cp_walk_tree (&WHILE_COND (while_stmt), + find_any_await, &await_ptr, &visited))) return NULL_TREE; /* Nothing special to do here. */ tree insert_list = push_stmt_list (); @@ -3658,10 +3597,10 @@ await_statement_walker (tree *stmt, int *do_subtree, void *d) break; } while (true); */ tree do_stmt = *stmt; - if ((res = cp_walk_tree (&DO_COND (do_stmt), - analyze_expression_awaits, d, &visited))) - return res; - if (!awpts->saw_awaits) + tree *await_ptr; + hash_set<tree> visited; + if (!(cp_walk_tree (&DO_COND (do_stmt), + find_any_await, &await_ptr, &visited))) return NULL_TREE; /* Nothing special to do here. */ tree insert_list = push_stmt_list (); @@ -3684,10 +3623,10 @@ await_statement_walker (tree *stmt, int *do_subtree, void *d) switch_type cond = cond with awaits switch (cond) stmt. */ tree sw_stmt = *stmt; - if ((res = cp_walk_tree (&SWITCH_STMT_COND (sw_stmt), - analyze_expression_awaits, d, &visited))) - return res; - if (!awpts->saw_awaits) + tree *await_ptr; + hash_set<tree> visited; + if (!(cp_walk_tree (&SWITCH_STMT_COND (sw_stmt), + find_any_await, &await_ptr, &visited))) return NULL_TREE; /* Nothing special to do here. */ gcc_checking_assert (!awpts->bind_stack->is_empty()); @@ -3728,9 +3667,6 @@ await_statement_walker (tree *stmt, int *do_subtree, void *d) { expr; p.return_void(); goto final_suspend;} - for co_return [non void expr]; { p.return_value(expr); goto final_suspend; } */ - if ((res = cp_walk_tree (stmt, analyze_expression_awaits, - d, &visited))) - return res; location_t loc = EXPR_LOCATION (expr); tree call = TREE_OPERAND (expr, 1); expr = TREE_OPERAND (expr, 0); @@ -3738,39 +3674,33 @@ await_statement_walker (tree *stmt, int *do_subtree, void *d) /* [stmt.return.coroutine], 2.2 If expr is present and void, it is placed immediately before the call for return_void; */ - tree *maybe_await_stmt = NULL; if (expr && VOID_TYPE_P (TREE_TYPE (expr))) - { - finish_expr_stmt (expr); - /* If the return argument was a void expression, then any - awaits must be contained in that. */ - maybe_await_stmt = tsi_stmt_ptr (tsi_last (ret_list)); - } + finish_expr_stmt (expr); /* Insert p.return_{void,value(expr)}. */ finish_expr_stmt (call); - /* Absent a return of a void expression, any awaits must be in - the parameter to return_value(). */ - if (!maybe_await_stmt) - maybe_await_stmt = tsi_stmt_ptr (tsi_last (ret_list)); TREE_USED (awpts->fs_label) = 1; add_stmt (build_stmt (loc, GOTO_EXPR, awpts->fs_label)); *stmt = pop_stmt_list (ret_list); + res = cp_walk_tree (stmt, await_statement_walker, d, NULL); /* Once this is complete, we will have processed subtrees. */ *do_subtree = 0; - if (awpts->saw_awaits) - { - gcc_checking_assert (maybe_await_stmt); - res = cp_walk_tree (maybe_await_stmt, await_statement_walker, - d, NULL); - if (res) - return res; - } - return NULL_TREE; /* Done. */ + return res; } break; } else if (EXPR_P (expr)) { + hash_set<tree> visited; + tree *await_ptr; + if (!(cp_walk_tree (stmt, find_any_await, &await_ptr, &visited))) + return NULL_TREE; /* Nothing special to do here. */ + + visited.empty (); + awpts->saw_awaits = 0; + hash_set<tree> truth_aoif_to_expand; + awpts->truth_aoif_to_expand = &truth_aoif_to_expand; + awpts->needs_truth_if_exp = false; + awpts->has_awaiter_init = false; if ((res = cp_walk_tree (stmt, analyze_expression_awaits, d, &visited))) return res; *do_subtree = 0; /* Done subtrees. */ @@ -3805,11 +3735,11 @@ struct param_frame_data bool param_seen; }; -/* A tree-walk callback that records the use of parameters (to allow for - optimizations where handling unused parameters may be omitted). */ +/* A tree walk callback that rewrites each parm use to the local variable + that represents its copy in the frame. */ static tree -register_param_uses (tree *stmt, int *do_subtree ATTRIBUTE_UNUSED, void *d) +rewrite_param_uses (tree *stmt, int *do_subtree ATTRIBUTE_UNUSED, void *d) { param_frame_data *data = (param_frame_data *) d; @@ -3817,7 +3747,7 @@ register_param_uses (tree *stmt, int *do_subtree ATTRIBUTE_UNUSED, void *d) if (TREE_CODE (*stmt) == VAR_DECL && DECL_HAS_VALUE_EXPR_P (*stmt)) { tree t = DECL_VALUE_EXPR (*stmt); - return cp_walk_tree (&t, register_param_uses, d, NULL); + return cp_walk_tree (&t, rewrite_param_uses, d, NULL); } if (TREE_CODE (*stmt) != PARM_DECL) @@ -3831,16 +3761,88 @@ register_param_uses (tree *stmt, int *do_subtree ATTRIBUTE_UNUSED, void *d) param_info &parm = data->param_uses->get_or_insert (*stmt, &existed); gcc_checking_assert (existed); - if (!parm.body_uses) + *stmt = parm.copy_var; + return NULL_TREE; +} + +/* Build up a set of info that determines how each param copy will be + handled. */ + +static hash_map<tree, param_info> * +analyze_fn_parms (tree orig) +{ + if (!DECL_ARGUMENTS (orig)) + return NULL; + + hash_map<tree, param_info> *param_uses = new hash_map<tree, param_info>; + + /* Build a hash map with an entry for each param. + The key is the param tree. + Then we have an entry for the frame field name. + Then a cache for the field ref when we come to use it. + Then a tree list of the uses. + The second two entries start out empty - and only get populated + when we see uses. */ + bool lambda_p = LAMBDA_FUNCTION_P (orig); + + unsigned no_name_parm = 0; + for (tree arg = DECL_ARGUMENTS (orig); arg != NULL; arg = DECL_CHAIN (arg)) { - vec_alloc (parm.body_uses, 4); - parm.body_uses->quick_push (stmt); - data->param_seen = true; + bool existed; + param_info &parm = param_uses->get_or_insert (arg, &existed); + gcc_checking_assert (!existed); + parm.body_uses = NULL; + tree actual_type = TREE_TYPE (arg); + actual_type = complete_type_or_else (actual_type, orig); + if (actual_type == NULL_TREE) + actual_type = error_mark_node; + parm.orig_type = actual_type; + parm.by_ref = parm.pt_ref = parm.rv_ref = false; + if (TREE_CODE (actual_type) == REFERENCE_TYPE) + { + /* If the user passes by reference, then we will save the + pointer to the original. As noted in + [dcl.fct.def.coroutine] / 13, if the lifetime of the + referenced item ends and then the coroutine is resumed, + we have UB; well, the user asked for it. */ + if (TYPE_REF_IS_RVALUE (actual_type)) + parm.rv_ref = true; + else + parm.pt_ref = true; + } + else if (TYPE_REF_P (DECL_ARG_TYPE (arg))) + parm.by_ref = true; + + parm.frame_type = actual_type; + + parm.this_ptr = is_this_parameter (arg); + parm.lambda_cobj = lambda_p && DECL_NAME (arg) == closure_identifier; + + tree name = DECL_NAME (arg); + if (!name) + { + char *buf = xasprintf ("_Coro_unnamed_parm_%d", no_name_parm++); + name = get_identifier (buf); + free (buf); + } + parm.field_id = name; + + if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (parm.frame_type)) + { + char *buf = xasprintf ("_Coro_%s_live", IDENTIFIER_POINTER (name)); + parm.guard_var = build_lang_decl (VAR_DECL, get_identifier (buf), + boolean_type_node); + free (buf); + DECL_ARTIFICIAL (parm.guard_var) = true; + DECL_CONTEXT (parm.guard_var) = orig; + DECL_INITIAL (parm.guard_var) = boolean_false_node; + parm.trivial_dtor = false; + } + else + parm.trivial_dtor = true; } - else - parm.body_uses->safe_push (stmt); - return NULL_TREE; + return param_uses; } /* Small helper for the repetitive task of adding a new field to the coro @@ -3927,6 +3929,7 @@ register_local_var_uses (tree *stmt, int *do_subtree, void *d) identify them in the coroutine frame. */ tree lvname = DECL_NAME (lvar); char *buf; + /* The outermost bind scope contains the artificial variables that we inject to implement the coro state machine. We want to be able to inspect these in debugging. */ @@ -3936,7 +3939,7 @@ register_local_var_uses (tree *stmt, int *do_subtree, void *d) buf = xasprintf ("%s_%u_%u", IDENTIFIER_POINTER (lvname), lvd->nest_depth, lvd->bind_indx); else - buf = xasprintf ("_D%u.%u.%u", DECL_UID (lvar), lvd->nest_depth, + buf = xasprintf ("_D%u_%u_%u", DECL_UID (lvar), lvd->nest_depth, lvd->bind_indx); /* TODO: Figure out if we should build a local type that has any excess alignment or size from the original decl. */ @@ -4023,8 +4026,9 @@ coro_build_actor_or_destroy_function (tree orig, tree fn_type, static tree 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) + hash_map<tree, param_info> *param_uses, + tree resume_fn_ptr_type, + tree& resume_idx_var, tree& fs_label) { /* This will be our new outer scope. */ tree update_body = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL); @@ -4057,7 +4061,6 @@ coro_rewrite_function_body (location_t fn_start, tree fnbody, tree orig, /* Wrap the function body in a try {} catch (...) {} block, if exceptions are enabled. */ - tree promise = get_coroutine_promise_proxy (orig); tree var_list = NULL_TREE; tree initial_await = build_init_or_final_await (fn_start, false); @@ -4068,24 +4071,94 @@ coro_rewrite_function_body (location_t fn_start, tree fnbody, tree orig, tree return_void = get_coroutine_return_void_expr (current_function_decl, fn_start, false); + /* The pointer to the resume function. */ + tree resume_fn_ptr + = coro_build_artificial_var (fn_start, coro_resume_fn_id, + resume_fn_ptr_type, orig, NULL_TREE); + DECL_CHAIN (resume_fn_ptr) = var_list; + var_list = resume_fn_ptr; + add_decl_expr (resume_fn_ptr); + /* 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); + + /* The pointer to the destroy function. */ + tree var = coro_build_artificial_var (fn_start, coro_destroy_fn_id, + resume_fn_ptr_type, orig, NULL_TREE); + DECL_CHAIN (var) = var_list; + var_list = var; + add_decl_expr (var); + + /* The promise was created on demand when parsing we now link it into + our scope. */ + tree promise = get_coroutine_promise_proxy (orig); + DECL_CONTEXT (promise) = orig; + DECL_SOURCE_LOCATION (promise) = fn_start; + DECL_CHAIN (promise) = var_list; + var_list = promise; + add_decl_expr (promise); + + /* We need a handle to this coroutine, which is passed to every + await_suspend(). This was created on demand when parsing we now link it + into our scope. */ + var = get_coroutine_self_handle_proxy (orig); + DECL_CONTEXT (var) = orig; + DECL_SOURCE_LOCATION (var) = fn_start; + DECL_CHAIN (var) = var_list; + var_list = var; + add_decl_expr (var); + + /* If we have function parms, then these will be copied to the coroutine + frame. Create a local (proxy) variable for each parm, since the original + parms will be out of scope once the ramp has finished. The proxy vars will + get DECL_VALUE_EXPRs pointing to the frame copies, so that we can interact + with them in the debugger. */ + if (param_uses) + { + gcc_checking_assert (DECL_ARGUMENTS (orig)); + /* Add a local var for each parm. */ + for (tree arg = DECL_ARGUMENTS (orig); arg != NULL; + arg = DECL_CHAIN (arg)) + { + param_info *parm_i = param_uses->get (arg); + gcc_checking_assert (parm_i); + parm_i->copy_var + = build_lang_decl (VAR_DECL, parm_i->field_id, TREE_TYPE (arg)); + DECL_SOURCE_LOCATION (parm_i->copy_var) = DECL_SOURCE_LOCATION (arg); + DECL_CONTEXT (parm_i->copy_var) = orig; + DECL_ARTIFICIAL (parm_i->copy_var) = true; + DECL_CHAIN (parm_i->copy_var) = var_list; + var_list = parm_i->copy_var; + add_decl_expr (parm_i->copy_var); + } + + /* Now replace all uses of the parms in the function body with the proxy + vars. We want to this to apply to every instance of param's use, so + don't include a 'visited' hash_set on the tree walk, however we will + arrange to visit each containing expression only once. */ + hash_set<tree *> visited; + param_frame_data param_data = {NULL, param_uses, + &visited, fn_start, false}; + cp_walk_tree (&fnbody, rewrite_param_uses, ¶m_data, NULL); + } + + /* We create a resume index, this is initialized in the ramp. */ + resume_idx_var + = coro_build_artificial_var (fn_start, coro_resume_index_id, + short_unsigned_type_node, orig, NULL_TREE); + DECL_CHAIN (resume_idx_var) = var_list; + var_list = resume_idx_var; + add_decl_expr (resume_idx_var); + + /* If the coroutine has a frame that needs to be freed, this will be set by + the ramp. */ + var = coro_build_artificial_var (fn_start, coro_frame_needs_free_id, + boolean_type_node, orig, NULL_TREE); + DECL_CHAIN (var) = var_list; + var_list = var; + add_decl_expr (var); if (flag_exceptions) { @@ -4097,8 +4170,7 @@ coro_rewrite_function_body (location_t fn_start, tree fnbody, tree orig, /* Create and initialize the initial-await-resume-called variable per [dcl.fct.def.coroutine] / 5.3. */ tree i_a_r_c - = coro_build_artificial_var (fn_start, - "_Coro_initial_await_resume_called", + = coro_build_artificial_var (fn_start, coro_frame_i_a_r_c_id, boolean_type_node, orig, boolean_false_node); DECL_CHAIN (i_a_r_c) = var_list; @@ -4151,10 +4223,14 @@ coro_rewrite_function_body (location_t fn_start, tree fnbody, tree orig, 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); + tree r = build2 (MODIFY_EXPR, resume_fn_ptr_type, resume_fn_ptr, + zero_resume); + finish_expr_stmt (r); + tree short_zero = build_int_cst (short_unsigned_type_node, 0); + r = build2 (MODIFY_EXPR, short_unsigned_type_node, resume_idx_var, + short_zero); + finish_expr_stmt (r); + finish_expr_stmt (ueh); finish_handler (handler); TRY_HANDLERS (tcb) = pop_stmt_list (TRY_HANDLERS (tcb)); } @@ -4189,6 +4265,8 @@ coro_rewrite_function_body (location_t fn_start, tree fnbody, tree orig, /* 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. */ + zero_resume = build2 (MODIFY_EXPR, resume_fn_ptr_type, resume_fn_ptr, + 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)); @@ -4216,15 +4294,15 @@ coro_rewrite_function_body (location_t fn_start, tree fnbody, tree orig, declare a dummy coro frame. struct _R_frame { using handle_type = coro::coroutine_handle<coro1::promise_type>; - void (*__resume)(_R_frame *); - void (*__destroy)(_R_frame *); - coro1::promise_type __p; - bool frame_needs_free; free the coro frame mem if set. - bool i_a_r_c; [dcl.fct.def.coroutine] / 5.3 - short __resume_at; - handle_type self_handle; - (maybe) parameter copies. - (maybe) local variables saved (including awaitables) + void (*_Coro_resume_fn)(_R_frame *); + void (*_Coro_destroy_fn)(_R_frame *); + coro1::promise_type _Coro_promise; + bool _Coro_frame_needs_free; free the coro frame mem if set. + bool _Coro_i_a_r_c; [dcl.fct.def.coroutine] / 5.3 + short _Coro_resume_index; + handle_type _Coro_self_handle; + parameter copies (were required). + local variables saved (including awaitables) (maybe) trailing space. }; */ @@ -4316,7 +4394,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) /* 2. Types we need to define or look up. */ - tree fr_name = get_fn_local_identifier (orig, "frame"); + tree fr_name = get_fn_local_identifier (orig, "Frame"); tree coro_frame_type = xref_tag (record_type, fr_name); DECL_CONTEXT (TYPE_NAME (coro_frame_type)) = current_scope (); tree coro_frame_ptr = build_pointer_type (coro_frame_type); @@ -4333,121 +4411,18 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) /* Construct the wrapped function body; we will analyze this to determine the requirements for the coroutine frame. */ - tree resume_fn_field = NULL_TREE; - tree resume_idx_field = NULL_TREE; + tree resume_idx_var = NULL_TREE; tree fs_label = NULL_TREE; - fnbody = coro_rewrite_function_body (fn_start, fnbody, orig, - act_des_fn_ptr, resume_fn_field, - resume_idx_field, fs_label); + hash_map<tree, param_info> *param_uses = analyze_fn_parms (orig); + + fnbody = coro_rewrite_function_body (fn_start, fnbody, orig, param_uses, + act_des_fn_ptr, + resume_idx_var, fs_label); /* Build our dummy coro frame layout. */ coro_frame_type = begin_class_definition (coro_frame_type); + /* The fields for the coro frame. */ tree field_list = NULL_TREE; - tree resume_name - = coro_make_frame_entry (&field_list, "__resume", - act_des_fn_ptr, fn_start); - tree destroy_name - = coro_make_frame_entry (&field_list, "__destroy", - act_des_fn_ptr, fn_start); - tree promise_name - = coro_make_frame_entry (&field_list, "__p", promise_type, fn_start); - tree fnf_name = coro_make_frame_entry (&field_list, "__frame_needs_free", - boolean_type_node, fn_start); - tree resume_idx_name - = coro_make_frame_entry (&field_list, "__resume_at", - short_unsigned_type_node, fn_start); - - /* We need a handle to this coroutine, which is passed to every - await_suspend(). There's no point in creating it over and over. */ - (void) coro_make_frame_entry (&field_list, "__self_h", handle_type, fn_start); - - /* Now add in fields for function params (if there are any). - We do not attempt elision of copies at this stage, we do analyze the - uses and build worklists to replace those when the state machine is - lowered. */ - - hash_map<tree, param_info> *param_uses = NULL; - if (DECL_ARGUMENTS (orig)) - { - /* Build a hash map with an entry for each param. - The key is the param tree. - Then we have an entry for the frame field name. - Then a cache for the field ref when we come to use it. - Then a tree list of the uses. - The second two entries start out empty - and only get populated - when we see uses. */ - param_uses = new hash_map<tree, param_info>; - bool lambda_p = LAMBDA_FUNCTION_P (orig); - - unsigned no_name_parm = 0; - for (tree arg = DECL_ARGUMENTS (orig); arg != NULL; - arg = DECL_CHAIN (arg)) - { - bool existed; - param_info &parm = param_uses->get_or_insert (arg, &existed); - gcc_checking_assert (!existed); - parm.body_uses = NULL; - tree actual_type = TREE_TYPE (arg); - actual_type = complete_type_or_else (actual_type, orig); - if (actual_type == NULL_TREE) - actual_type = error_mark_node; - parm.orig_type = actual_type; - parm.by_ref = parm.pt_ref = parm.rv_ref = false; - if (TREE_CODE (actual_type) == REFERENCE_TYPE) - { - /* If the user passes by reference, then we will save the - pointer to the original. As noted in - [dcl.fct.def.coroutine] / 13, if the lifetime of the - referenced item ends and then the coroutine is resumed, - we have UB; well, the user asked for it. */ - if (TYPE_REF_IS_RVALUE (actual_type)) - parm.rv_ref = true; - else - parm.pt_ref = true; - } - else if (TYPE_REF_P (DECL_ARG_TYPE (arg))) - parm.by_ref = true; - - parm.frame_type = actual_type; - - parm.this_ptr = is_this_parameter (arg); - parm.lambda_cobj = lambda_p && DECL_NAME (arg) == closure_identifier; - - char *buf; - if (DECL_NAME (arg)) - { - tree pname = DECL_NAME (arg); - buf = xasprintf ("__parm.%s", IDENTIFIER_POINTER (pname)); - } - else - buf = xasprintf ("__unnamed_parm.%d", no_name_parm++); - - if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (parm.frame_type)) - { - char *gbuf = xasprintf ("%s.live", buf); - parm.guard_var - = build_lang_decl (VAR_DECL, get_identifier (gbuf), - boolean_type_node); - free (gbuf); - DECL_ARTIFICIAL (parm.guard_var) = true; - DECL_INITIAL (parm.guard_var) = boolean_false_node; - parm.trivial_dtor = false; - } - else - parm.trivial_dtor = true; - parm.field_id = coro_make_frame_entry - (&field_list, buf, actual_type, DECL_SOURCE_LOCATION (arg)); - free (buf); - } - - /* We want to record every instance of param's use, so don't include - a 'visited' hash_set on the tree walk, but only record a containing - expression once. */ - hash_set<tree *> visited; - param_frame_data param_data - = {&field_list, param_uses, &visited, fn_start, false}; - cp_walk_tree (&fnbody, register_param_uses, ¶m_data, NULL); - } /* We need to know, and inspect, each suspend point in the function in several places. It's convenient to place this map out of line @@ -4761,8 +4736,8 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) /* For now, once allocation has succeeded we always assume that this needs destruction, there's no impl. for frame allocation elision. */ - tree fnf_m - = lookup_member (coro_frame_type, fnf_name, 1, 0, tf_warning_or_error); + tree fnf_m = lookup_member (coro_frame_type, coro_frame_needs_free_id, + 1, 0,tf_warning_or_error); tree fnf_x = build_class_member_access_expr (deref_fp, fnf_m, NULL_TREE, false, tf_warning_or_error); r = build2 (INIT_EXPR, boolean_type_node, fnf_x, boolean_true_node); @@ -4773,24 +4748,22 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) tree actor_addr = build1 (ADDR_EXPR, act_des_fn_ptr, actor); tree resume_m - = lookup_member (coro_frame_type, resume_name, + = lookup_member (coro_frame_type, coro_resume_fn_id, /*protect=*/1, /*want_type=*/0, tf_warning_or_error); tree resume_x = build_class_member_access_expr (deref_fp, resume_m, NULL_TREE, false, tf_warning_or_error); r = build2_loc (fn_start, INIT_EXPR, act_des_fn_ptr, resume_x, actor_addr); - r = coro_build_cvt_void_expr_stmt (r, fn_start); - add_stmt (r); + finish_expr_stmt (r); tree destroy_addr = build1 (ADDR_EXPR, act_des_fn_ptr, destroy); tree destroy_m - = lookup_member (coro_frame_type, destroy_name, + = lookup_member (coro_frame_type, coro_destroy_fn_id, /*protect=*/1, /*want_type=*/0, tf_warning_or_error); tree destroy_x = build_class_member_access_expr (deref_fp, destroy_m, NULL_TREE, false, tf_warning_or_error); r = build2_loc (fn_start, INIT_EXPR, act_des_fn_ptr, destroy_x, destroy_addr); - r = coro_build_cvt_void_expr_stmt (r, fn_start); - add_stmt (r); + finish_expr_stmt (r); /* [dcl.fct.def.coroutine] /13 When a coroutine is invoked, a copy is created for each coroutine @@ -4881,7 +4854,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) /* Set up the promise. */ tree promise_m - = lookup_member (coro_frame_type, promise_name, + = lookup_member (coro_frame_type, coro_promise_id, /*protect=*/1, /*want_type=*/0, tf_warning_or_error); tree p = build_class_member_access_expr (deref_fp, promise_m, NULL_TREE, @@ -5027,9 +5000,9 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) boolean_type_node); finish_expr_stmt (r); } - /* Initialize the resume_idx_name to 0, meaning "not started". */ + /* Initialize the resume_idx_var to 0, meaning "not started". */ tree resume_idx_m - = lookup_member (coro_frame_type, resume_idx_name, + = lookup_member (coro_frame_type, coro_resume_index_id, /*protect=*/1, /*want_type=*/0, tf_warning_or_error); tree resume_idx = build_class_member_access_expr (deref_fp, resume_idx_m, NULL_TREE, false, @@ -5172,9 +5145,9 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) push_deferring_access_checks (dk_no_check); /* 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, - resume_idx_field, body_aw_points.await_number, frame_size); + build_actor_fn (fn_start, coro_frame_type, actor, fnbody, orig, + &local_var_uses, param_dtor_list, + resume_idx_var, body_aw_points.await_number, frame_size); /* Destroyer ... */ build_destroy_fn (fn_start, coro_frame_type, destroy, actor); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index a82747c..fb0d5ec 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -204,12 +204,11 @@ enum cp_tree_index /* These are created at init time, but the library/headers provide definitions. */ CPTI_ALIGN_TYPE, - CPTI_CONST_TYPE_INFO_TYPE, - CPTI_TYPE_INFO_PTR_TYPE, CPTI_TERMINATE_FN, CPTI_CALL_UNEXPECTED_FN, /* These are lazily inited. */ + CPTI_CONST_TYPE_INFO_TYPE, CPTI_GET_EXCEPTION_PTR_FN, CPTI_BEGIN_CATCH_FN, CPTI_END_CATCH_FN, @@ -251,7 +250,6 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; #define abi_node cp_global_trees[CPTI_ABI] #define global_namespace cp_global_trees[CPTI_GLOBAL] #define const_type_info_type_node cp_global_trees[CPTI_CONST_TYPE_INFO_TYPE] -#define type_info_ptr_type cp_global_trees[CPTI_TYPE_INFO_PTR_TYPE] #define conv_op_marker cp_global_trees[CPTI_CONV_OP_MARKER] #define abort_fndecl cp_global_trees[CPTI_ABORT_FNDECL] #define current_aggr cp_global_trees[CPTI_AGGR_TAG] @@ -7138,6 +7136,7 @@ extern void cp_convert_omp_range_for (tree &, vec<tree, va_gc> *, tree &, tree &, tree &, tree &, tree &, tree &); extern void cp_finish_omp_range_for (tree, tree); extern bool parsing_nsdmi (void); +extern bool parsing_function_declarator (); extern bool parsing_default_capturing_generic_lambda_in_template (void); extern void inject_this_parameter (tree, cp_cv_quals); extern location_t defparse_location (tree); @@ -7583,8 +7582,8 @@ extern tree finish_omp_for (location_t, enum tree_code, extern tree finish_omp_for_block (tree, tree); extern void finish_omp_atomic (location_t, enum tree_code, enum tree_code, tree, tree, - tree, tree, tree, tree, - enum omp_memory_order); + tree, tree, tree, tree, tree, + enum omp_memory_order, bool); extern void finish_omp_barrier (void); extern void finish_omp_depobj (location_t, tree, enum omp_clause_depend_kind, diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index c206502..58ddc6a 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -4756,7 +4756,7 @@ cxx_init_decl_processing (void) /* Check that the hardware interference sizes are at least alignof(max_align_t), as required by the standard. */ const int max_align = max_align_t_align () / BITS_PER_UNIT; - if (param_destruct_interfere_size) + if (global_options_set.x_param_destruct_interfere_size) { if (param_destruct_interfere_size < max_align) error ("%<--param destructive-interference-size=%d%> is less than " @@ -4767,21 +4767,26 @@ cxx_init_decl_processing (void) "is less than %<--param l1-cache-line-size=%d%>", param_destruct_interfere_size, param_l1_cache_line_size); } + else if (param_destruct_interfere_size) + /* Assume the internal value is OK. */; else if (param_l1_cache_line_size >= max_align) param_destruct_interfere_size = param_l1_cache_line_size; /* else leave it unset. */ - if (param_construct_interfere_size) + if (global_options_set.x_param_construct_interfere_size) { if (param_construct_interfere_size < max_align) error ("%<--param constructive-interference-size=%d%> is less than " "%d", param_construct_interfere_size, max_align); - else if (param_construct_interfere_size > param_l1_cache_line_size) + else if (param_construct_interfere_size > param_l1_cache_line_size + && param_l1_cache_line_size >= max_align) warning (OPT_Winterference_size, "%<--param constructive-interference-size=%d%> " "is greater than %<--param l1-cache-line-size=%d%>", param_construct_interfere_size, param_l1_cache_line_size); } + else if (param_construct_interfere_size) + /* Assume the internal value is OK. */; else if (param_l1_cache_line_size >= max_align) param_construct_interfere_size = param_l1_cache_line_size; } @@ -6123,6 +6128,38 @@ layout_var_decl (tree decl) error_at (DECL_SOURCE_LOCATION (decl), "storage size of %qD isn%'t constant", decl); TREE_TYPE (decl) = error_mark_node; + type = error_mark_node; + } + } + + /* If the final element initializes a flexible array field, add the size of + that initializer to DECL's size. */ + if (type != error_mark_node + && DECL_INITIAL (decl) + && TREE_CODE (DECL_INITIAL (decl)) == CONSTRUCTOR + && !vec_safe_is_empty (CONSTRUCTOR_ELTS (DECL_INITIAL (decl))) + && DECL_SIZE (decl) != NULL_TREE + && TREE_CODE (DECL_SIZE (decl)) == INTEGER_CST + && TYPE_SIZE (type) != NULL_TREE + && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST + && tree_int_cst_equal (DECL_SIZE (decl), TYPE_SIZE (type))) + { + constructor_elt &elt = CONSTRUCTOR_ELTS (DECL_INITIAL (decl))->last (); + if (elt.index) + { + tree itype = TREE_TYPE (elt.index); + tree vtype = TREE_TYPE (elt.value); + if (TREE_CODE (itype) == ARRAY_TYPE + && TYPE_DOMAIN (itype) == NULL + && TREE_CODE (vtype) == ARRAY_TYPE + && COMPLETE_TYPE_P (vtype)) + { + DECL_SIZE (decl) + = size_binop (PLUS_EXPR, DECL_SIZE (decl), TYPE_SIZE (vtype)); + DECL_SIZE_UNIT (decl) + = size_binop (PLUS_EXPR, DECL_SIZE_UNIT (decl), + TYPE_SIZE_UNIT (vtype)); + } } } } @@ -13943,6 +13980,17 @@ grokdeclarator (const cp_declarator *declarator, if (declspecs->gnu_thread_keyword_p) SET_DECL_GNU_TLS_P (decl); } + + /* Set the constraints on the declaration. */ + bool memtmpl = (processing_template_decl + > template_class_depth (current_class_type)); + if (memtmpl) + { + tree tmpl_reqs + = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms); + tree ci = build_constraints (tmpl_reqs, NULL_TREE); + set_constraints (decl, ci); + } } else { @@ -14810,9 +14858,11 @@ grok_special_member_properties (tree decl) if (ctor > 1) TYPE_HAS_CONST_COPY_CTOR (class_type) = 1; } - else if (sufficient_parms_p (FUNCTION_FIRST_USER_PARMTYPE (decl))) + + if (sufficient_parms_p (FUNCTION_FIRST_USER_PARMTYPE (decl))) TYPE_HAS_DEFAULT_CONSTRUCTOR (class_type) = 1; - else if (is_list_ctor (decl)) + + if (is_list_ctor (decl)) TYPE_HAS_LIST_CTOR (class_type) = 1; if (DECL_DECLARED_CONSTEXPR_P (decl) diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 353046d..32f7186 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -2081,6 +2081,7 @@ constructible_expr (tree to, tree from) static tree is_xible_helper (enum tree_code code, tree to, tree from, bool trivial) { + to = complete_type (to); deferring_access_check_sentinel acs (dk_no_deferred); if (VOID_TYPE_P (to) || ABSTRACT_CLASS_TYPE_P (to) || (from && FUNC_OR_METHOD_TYPE_P (from) diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 8e9c61e..ddee8b3 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -3363,12 +3363,9 @@ set_decl_context_in_fn (tree ctx, tree decl) if (!DECL_CONTEXT (decl) /* When parsing the parameter list of a function declarator, - don't set DECL_CONTEXT to an enclosing function. When we - push the PARM_DECLs in order to process the function body, - current_binding_level->this_entity will be set. */ + don't set DECL_CONTEXT to an enclosing function. */ && !(TREE_CODE (decl) == PARM_DECL - && current_binding_level->kind == sk_function_parms - && current_binding_level->this_entity == NULL)) + && parsing_function_declarator ())) DECL_CONTEXT (decl) = ctx; } diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index e44c5c6..20f949e 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -6379,7 +6379,8 @@ cp_parser_unqualified_id (cp_parser* parser, /* DR 2237 (C++20 only): A simple-template-id is no longer valid as the declarator-id of a constructor or destructor. */ - if (token->type == CPP_TEMPLATE_ID && cxx_dialect >= cxx20) + if (token->type == CPP_TEMPLATE_ID && declarator_p + && cxx_dialect >= cxx20) { if (!cp_parser_simulate_error (parser)) error_at (tilde_loc, "template-id not allowed for destructor"); @@ -18404,6 +18405,7 @@ cp_parser_template_name (cp_parser* parser, { /* We're optimizing away the call to cp_parser_lookup_name, but we still need to do this. */ + parser->object_scope = parser->context->object_type; parser->context->object_type = NULL_TREE; return identifier; } @@ -23105,7 +23107,7 @@ cp_parser_direct_declarator (cp_parser* parser, else if (!cp_parser_uncommitted_to_tentative_parse_p (parser)) /* Let compute_array_index_type diagnose this. */; else if (!parser->in_function_body - || current_binding_level->kind == sk_function_parms) + || parsing_function_declarator ()) { /* Normally, the array bound must be an integral constant expression. However, as an extension, we allow VLAs @@ -23829,6 +23831,17 @@ parsing_nsdmi (void) return false; } +/* True if we're parsing a function declarator. */ + +bool +parsing_function_declarator () +{ + /* this_entity is NULL for a function parameter scope while parsing the + declarator; it is set when parsing the body of the function. */ + return (current_binding_level->kind == sk_function_parms + && !current_binding_level->this_entity); +} + /* Parse a late-specified return type, if any. This is not a separate non-terminal, but part of a function declarator, which looks like @@ -33574,7 +33587,8 @@ cp_parser_pre_parsed_nested_name_specifier (cp_parser *parser) /* Set the scope from the stored value. */ parser->scope = saved_checks_value (check_value); parser->qualifying_scope = check_value->qualifying_scope; - parser->object_scope = NULL_TREE; + parser->object_scope = parser->context->object_type; + parser->context->object_type = NULL_TREE; } /* Consume tokens up through a non-nested END token. Returns TRUE if we @@ -40068,19 +40082,56 @@ cp_parser_omp_allocate (cp_parser *parser, cp_token *pragma_tok) capture-block: { v = x; update-stmt; } | { update-stmt; v = x; } | { v = x; x = expr; } - where x and v are lvalue expressions with scalar type. */ + OpenMP 5.1: + # pragma omp atomic compare new-line + conditional-update-atomic + + # pragma omp atomic compare capture new-line + conditional-update-capture-atomic + + conditional-update-atomic: + cond-expr-stmt | cond-update-stmt + cond-expr-stmt: + x = expr ordop x ? expr : x; + x = x ordop expr ? expr : x; + x = x == e ? d : x; + cond-update-stmt: + if (expr ordop x) { x = expr; } + if (x ordop expr) { x = expr; } + if (x == e) { x = d; } + ordop: + <, > + conditional-update-capture-atomic: + v = cond-expr-stmt + { v = x; cond-expr-stmt } + { cond-expr-stmt v = x; } + { v = x; cond-update-stmt } + { cond-update-stmt v = x; } + if (x == e) { x = d; } else { v = x; } + { r = x == e; if (r) { x = d; } } + { r = x == e; if (r) { x = d; } else { v = x; } } + + where x, r and v are lvalue expressions with scalar type, + expr, e and d are expressions with scalar type and e might be + the same as v. */ static void cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok, bool openacc) { tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE, lhs1 = NULL_TREE; - tree rhs1 = NULL_TREE, orig_lhs; + tree rhs1 = NULL_TREE, orig_lhs, r = NULL_TREE; location_t loc = pragma_tok->location; enum tree_code code = ERROR_MARK, opcode = NOP_EXPR; enum omp_memory_order memory_order = OMP_MEMORY_ORDER_UNSPECIFIED; bool structured_block = false; bool first = true; tree clauses = NULL_TREE; + bool capture = false; + bool compare = false; + bool weak = false; + enum omp_memory_order fail = OMP_MEMORY_ORDER_UNSPECIFIED; + bool no_semicolon = false; + bool extra_scope = false; while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)) { @@ -40100,6 +40151,10 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok, bool openacc) enum tree_code new_code = ERROR_MARK; enum omp_memory_order new_memory_order = OMP_MEMORY_ORDER_UNSPECIFIED; + bool new_capture = false; + bool new_compare = false; + bool new_weak = false; + enum omp_memory_order new_fail = OMP_MEMORY_ORDER_UNSPECIFIED; if (!strcmp (p, "read")) new_code = OMP_ATOMIC_READ; @@ -40107,7 +40162,7 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok, bool openacc) new_code = NOP_EXPR; else if (!strcmp (p, "update")) new_code = OMP_ATOMIC; - else if (!strcmp (p, "capture")) + else if (openacc && !strcmp (p, "capture")) new_code = OMP_ATOMIC_CAPTURE_NEW; else if (openacc) { @@ -40115,6 +40170,52 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok, bool openacc) error_at (cloc, "expected %<read%>, %<write%>, %<update%>, " "or %<capture%> clause"); } + else if (!strcmp (p, "capture")) + new_capture = true; + else if (!strcmp (p, "compare")) + new_compare = true; + else if (!strcmp (p, "weak")) + new_weak = true; + else if (!strcmp (p, "fail")) + { + matching_parens parens; + + cp_lexer_consume_token (parser->lexer); + if (!parens.require_open (parser)) + continue; + + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *q = IDENTIFIER_POINTER (id); + + if (!strcmp (q, "seq_cst")) + new_fail = OMP_MEMORY_ORDER_SEQ_CST; + else if (!strcmp (q, "acquire")) + new_fail = OMP_MEMORY_ORDER_ACQUIRE; + else if (!strcmp (q, "relaxed")) + new_fail = OMP_MEMORY_ORDER_RELAXED; + } + + if (new_fail != OMP_MEMORY_ORDER_UNSPECIFIED) + { + cp_lexer_consume_token (parser->lexer); + if (fail != OMP_MEMORY_ORDER_UNSPECIFIED) + error_at (cloc, "too many %qs clauses", "fail"); + else + fail = new_fail; + } + else + cp_parser_error (parser, "expected %<seq_cst%>, %<acquire%> " + "or %<relaxed%>"); + if (new_fail == OMP_MEMORY_ORDER_UNSPECIFIED + || !parens.require_close (parser)) + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + continue; + } else if (!strcmp (p, "seq_cst")) new_memory_order = OMP_MEMORY_ORDER_SEQ_CST; else if (!strcmp (p, "acq_rel")) @@ -40135,8 +40236,9 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok, bool openacc) { p = NULL; error_at (cloc, "expected %<read%>, %<write%>, %<update%>, " - "%<capture%>, %<seq_cst%>, %<acq_rel%>, " - "%<release%>, %<relaxed%> or %<hint%> clause"); + "%<capture%>, %<compare%>, %<weak%>, %<fail%>, " + "%<seq_cst%>, %<acq_rel%>, %<release%>, " + "%<relaxed%> or %<hint%> clause"); } if (p) { @@ -40159,6 +40261,27 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok, bool openacc) else memory_order = new_memory_order; } + else if (new_capture) + { + if (capture) + error_at (cloc, "too many %qs clauses", "capture"); + else + capture = true; + } + else if (new_compare) + { + if (compare) + error_at (cloc, "too many %qs clauses", "compare"); + else + compare = true; + } + else if (new_weak) + { + if (weak) + error_at (cloc, "too many %qs clauses", "weak"); + else + weak = true; + } cp_lexer_consume_token (parser->lexer); continue; } @@ -40169,6 +40292,30 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok, bool openacc) if (code == ERROR_MARK) code = OMP_ATOMIC; + if (capture) + { + if (code != OMP_ATOMIC) + error_at (loc, "%qs clause is incompatible with %<read%> or %<write%> " + "clauses", "capture"); + else + code = OMP_ATOMIC_CAPTURE_NEW; + } + if (compare && code != OMP_ATOMIC && code != OMP_ATOMIC_CAPTURE_NEW) + { + error_at (loc, "%qs clause is incompatible with %<read%> or %<write%> " + "clauses", "compare"); + compare = false; + } + if (fail != OMP_MEMORY_ORDER_UNSPECIFIED && !compare) + { + error_at (loc, "%qs clause requires %qs clause", "fail", "compare"); + fail = OMP_MEMORY_ORDER_UNSPECIFIED; + } + if (weak && !compare) + { + error_at (loc, "%qs clause requires %qs clause", "weak", "compare"); + weak = false; + } if (openacc) memory_order = OMP_MEMORY_ORDER_RELAXED; else if (memory_order == OMP_MEMORY_ORDER_UNSPECIFIED) @@ -40230,6 +40377,10 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok, bool openacc) default: break; } + if (fail != OMP_MEMORY_ORDER_UNSPECIFIED) + memory_order + = (enum omp_memory_order) (memory_order + | (fail << OMP_FAIL_MEMORY_ORDER_SHIFT)); switch (code) { @@ -40262,6 +40413,9 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok, bool openacc) cp_lexer_consume_token (parser->lexer); structured_block = true; } + else if (compare + && cp_lexer_next_token_is_keyword (parser->lexer, RID_IF)) + break; else { v = cp_parser_unary_expression (parser); @@ -40269,12 +40423,179 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok, bool openacc) goto saw_error; if (!cp_parser_require (parser, CPP_EQ, RT_EQ)) goto saw_error; + if (compare + && cp_lexer_next_token_is_keyword (parser->lexer, RID_IF)) + { + location_t eloc = cp_lexer_peek_token (parser->lexer)->location; + error_at (eloc, "expected expression"); + goto saw_error; + } } default: break; } restart: + if (compare && cp_lexer_next_token_is_keyword (parser->lexer, RID_IF)) + { + cp_lexer_consume_token (parser->lexer); + + matching_parens parens; + if (!parens.require_open (parser)) + goto saw_error; + location_t eloc = cp_lexer_peek_token (parser->lexer)->location; + tree cmp_expr; + if (r) + cmp_expr = cp_parser_unary_expression (parser); + else + cmp_expr = cp_parser_binary_expression (parser, false, true, + PREC_NOT_OPERATOR, NULL); + if (!parens.require_close (parser)) + cp_parser_skip_to_closing_parenthesis (parser, true, false, true); + if (cmp_expr == error_mark_node) + goto saw_error; + if (r) + { + if (!cp_tree_equal (cmp_expr, r)) + goto bad_if; + cmp_expr = rhs; + rhs = NULL_TREE; + gcc_assert (TREE_CODE (cmp_expr) == EQ_EXPR); + } + if (TREE_CODE (cmp_expr) == EQ_EXPR) + ; + else if (!structured_block && code == OMP_ATOMIC_CAPTURE_NEW) + { + error_at (EXPR_LOC_OR_LOC (cmp_expr, eloc), + "expected %<==%> comparison in %<if%> condition"); + goto saw_error; + } + else if (TREE_CODE (cmp_expr) != GT_EXPR + && TREE_CODE (cmp_expr) != LT_EXPR) + { + error_at (EXPR_LOC_OR_LOC (cmp_expr, eloc), + "expected %<==%>, %<<%> or %<>%> comparison in %<if%> " + "condition"); + goto saw_error; + } + if (!cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE)) + goto saw_error; + + extra_scope = true; + eloc = cp_lexer_peek_token (parser->lexer)->location; + lhs = cp_parser_unary_expression (parser); + orig_lhs = lhs; + if (lhs == error_mark_node) + goto saw_error; + if (!cp_lexer_next_token_is (parser->lexer, CPP_EQ)) + { + cp_parser_error (parser, "expected %<=%>"); + goto saw_error; + } + cp_lexer_consume_token (parser->lexer); + eloc = cp_lexer_peek_token (parser->lexer)->location; + if (TREE_CODE (cmp_expr) == EQ_EXPR) + rhs1 = cp_parser_expression (parser); + else + rhs1 = cp_parser_simple_cast_expression (parser); + + if (!cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON)) + goto saw_error; + + if (!cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE)) + goto saw_error; + + extra_scope = false; + no_semicolon = true; + + if (cp_tree_equal (TREE_OPERAND (cmp_expr, 0), lhs)) + { + if (TREE_CODE (cmp_expr) == EQ_EXPR) + { + opcode = COND_EXPR; + rhs = TREE_OPERAND (cmp_expr, 1); + } + else if (cp_tree_equal (TREE_OPERAND (cmp_expr, 1), rhs1)) + { + opcode = (TREE_CODE (cmp_expr) == GT_EXPR + ? MIN_EXPR : MAX_EXPR); + rhs = rhs1; + rhs1 = TREE_OPERAND (cmp_expr, 0); + } + else + goto bad_if; + } + else if (TREE_CODE (cmp_expr) == EQ_EXPR) + goto bad_if; + else if (cp_tree_equal (TREE_OPERAND (cmp_expr, 1), lhs) + && cp_tree_equal (TREE_OPERAND (cmp_expr, 0), rhs1)) + { + opcode = (TREE_CODE (cmp_expr) == GT_EXPR + ? MAX_EXPR : MIN_EXPR); + rhs = rhs1; + rhs1 = TREE_OPERAND (cmp_expr, 1); + } + else + { + bad_if: + cp_parser_error (parser, + "invalid form of %<#pragma omp atomic compare%>"); + goto saw_error; + } + + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_ELSE)) + { + if (code != OMP_ATOMIC_CAPTURE_NEW + || (structured_block && r == NULL_TREE) + || TREE_CODE (cmp_expr) != EQ_EXPR) + { + eloc = cp_lexer_peek_token (parser->lexer)->location; + error_at (eloc, "unexpected %<else%>"); + goto saw_error; + } + + cp_lexer_consume_token (parser->lexer); + + if (!cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE)) + goto saw_error; + + extra_scope = true; + v = cp_parser_unary_expression (parser); + if (v == error_mark_node) + goto saw_error; + if (!cp_parser_require (parser, CPP_EQ, RT_EQ)) + goto saw_error; + + tree expr = cp_parser_simple_cast_expression (parser); + + if (!cp_tree_equal (expr, lhs)) + goto bad_if; + + if (!cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON)) + goto saw_error; + + if (!cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE)) + goto saw_error; + + extra_scope = false; + code = OMP_ATOMIC_CAPTURE_OLD; + if (r == NULL_TREE) + /* Signal to c_finish_omp_atomic that in + if (x == e) { x = d; } else { v = x; } + case the store to v should be conditional. */ + r = void_list_node; + } + else if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block) + { + cp_parser_error (parser, "expected %<else%>"); + goto saw_error; + } + else if (code == OMP_ATOMIC_CAPTURE_NEW + && r != NULL_TREE + && v == NULL_TREE) + code = OMP_ATOMIC; + goto stmt_done; + } lhs = cp_parser_unary_expression (parser); orig_lhs = lhs; switch (TREE_CODE (lhs)) @@ -40290,6 +40611,8 @@ restart: lhs = TREE_OPERAND (lhs, 0); opcode = PLUS_EXPR; rhs = integer_one_node; + if (compare) + goto invalid_compare; break; case POSTDECREMENT_EXPR: @@ -40300,6 +40623,8 @@ restart: lhs = TREE_OPERAND (lhs, 0); opcode = MINUS_EXPR; rhs = integer_one_node; + if (compare) + goto invalid_compare; break; case COMPOUND_EXPR: @@ -40328,11 +40653,18 @@ restart: && !structured_block && TREE_CODE (orig_lhs) == COMPOUND_EXPR) code = OMP_ATOMIC_CAPTURE_OLD; + if (compare) + goto invalid_compare; break; } } /* FALLTHRU */ default: + if (compare && !cp_lexer_next_token_is (parser->lexer, CPP_EQ)) + { + cp_parser_error (parser, "expected %<=%>"); + goto saw_error; + } switch (cp_lexer_peek_token (parser->lexer)->type) { case CPP_MULT_EQ: @@ -40400,6 +40732,8 @@ restart: case BIT_AND_EXPR: case BIT_IOR_EXPR: case BIT_XOR_EXPR: + if (compare) + break; if (cp_tree_equal (lhs, TREE_OPERAND (rhs, 1))) { if (cp_parser_parse_definitely (parser)) @@ -40413,11 +40747,91 @@ restart: goto saw_error; } break; + case EQ_EXPR: + if (!compare + || code != OMP_ATOMIC_CAPTURE_NEW + || !structured_block + || v + || r) + break; + if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON) + && cp_lexer_nth_token_is_keyword (parser->lexer, + 2, RID_IF)) + { + if (cp_parser_parse_definitely (parser)) + { + r = lhs; + lhs = NULL_TREE; + rhs1 = NULL_TREE; + cp_lexer_consume_token (parser->lexer); + goto restart; + } + } + break; + case GT_EXPR: + case LT_EXPR: + if (compare + && cp_lexer_next_token_is (parser->lexer, CPP_QUERY) + && cp_tree_equal (lhs, TREE_OPERAND (rhs, 1)) + && cp_parser_parse_definitely (parser)) + { + opcode = TREE_CODE (rhs); + rhs1 = TREE_OPERAND (rhs, 0); + rhs = TREE_OPERAND (rhs, 1); + cond_expr: + cp_lexer_consume_token (parser->lexer); + bool saved_colon_corrects_to_scope_p + = parser->colon_corrects_to_scope_p; + parser->colon_corrects_to_scope_p = false; + tree e1 = cp_parser_expression (parser); + parser->colon_corrects_to_scope_p + = saved_colon_corrects_to_scope_p; + cp_parser_require (parser, CPP_COLON, RT_COLON); + tree e2 = cp_parser_simple_cast_expression (parser); + if (cp_tree_equal (lhs, e2)) + { + if (cp_tree_equal (lhs, rhs1)) + { + if (opcode == EQ_EXPR) + { + opcode = COND_EXPR; + rhs1 = e1; + goto stmt_done; + } + if (cp_tree_equal (rhs, e1)) + { + opcode + = opcode == GT_EXPR ? MIN_EXPR : MAX_EXPR; + rhs = e1; + goto stmt_done; + } + } + else + { + gcc_assert (opcode != EQ_EXPR); + if (cp_tree_equal (rhs1, e1)) + { + opcode + = opcode == GT_EXPR ? MAX_EXPR : MIN_EXPR; + rhs1 = rhs; + rhs = e1; + goto stmt_done; + } + } + } + cp_parser_error (parser, + "invalid form of " + "%<#pragma omp atomic compare%>"); + goto saw_error; + } + break; default: break; } cp_parser_abort_tentative_parse (parser); - if (structured_block && code == OMP_ATOMIC_CAPTURE_OLD) + if (structured_block + && code == OMP_ATOMIC_CAPTURE_OLD + && !compare) { rhs = cp_parser_expression (parser); if (rhs == error_mark_node) @@ -40445,7 +40859,7 @@ restart: cp_lexer_consume_token (parser->lexer); goto restart; } - else if (structured_block) + else if (structured_block && !compare) { opcode = NOP_EXPR; rhs = rhs1; @@ -40482,11 +40896,28 @@ restart: case CPP_XOR: opcode = BIT_XOR_EXPR; break; + case CPP_EQ_EQ: + opcode = EQ_EXPR; + break; + case CPP_GREATER: + opcode = GT_EXPR; + break; + case CPP_LESS: + opcode = LT_EXPR; + break; default: cp_parser_error (parser, "invalid operator for %<#pragma omp atomic%>"); goto saw_error; } + if (compare + && TREE_CODE_CLASS (opcode) != tcc_comparison) + { + cp_parser_error (parser, + "invalid form of " + "%<#pragma omp atomic compare%>"); + goto saw_error; + } oprec = TOKEN_PRECEDENCE (token); gcc_assert (oprec != PREC_NOT_OPERATOR); if (commutative_tree_code (opcode)) @@ -40496,8 +40927,18 @@ restart: oprec, NULL); if (rhs == error_mark_node) goto saw_error; + if (compare) + { + if (!cp_lexer_next_token_is (parser->lexer, CPP_QUERY)) + { + cp_parser_error (parser, + "invalid form of " + "%<#pragma omp atomic compare%>"); + goto saw_error; + } + goto cond_expr; + } goto stmt_done; - /* FALLTHROUGH */ default: cp_parser_error (parser, "invalid operator for %<#pragma omp atomic%>"); @@ -40511,10 +40952,12 @@ restart: break; } stmt_done: - if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW) + if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW && r == NULL_TREE) { - if (!cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON)) + if (!no_semicolon + && !cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON)) goto saw_error; + no_semicolon = false; v = cp_parser_unary_expression (parser); if (v == error_mark_node) goto saw_error; @@ -40526,19 +40969,30 @@ stmt_done: } if (structured_block) { - cp_parser_consume_semicolon_at_end_of_statement (parser); + if (!no_semicolon) + cp_parser_consume_semicolon_at_end_of_statement (parser); cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE); } done: + if (weak && opcode != COND_EXPR) + { + error_at (loc, "%<weak%> clause requires atomic equality comparison"); + weak = false; + } clauses = finish_omp_clauses (clauses, C_ORT_OMP); finish_omp_atomic (pragma_tok->location, code, opcode, lhs, rhs, v, lhs1, - rhs1, clauses, memory_order); - if (!structured_block) + rhs1, r, clauses, memory_order, weak); + if (!structured_block && !no_semicolon) cp_parser_consume_semicolon_at_end_of_statement (parser); return; + invalid_compare: + error ("invalid form of %<pragma omp atomic compare%>"); + /* FALLTHRU */ saw_error: cp_parser_skip_to_end_of_block_or_statement (parser); + if (extra_scope && cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE)) + cp_lexer_consume_token (parser->lexer); if (structured_block) { if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE)) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 224dd9e..12c8812 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -2218,7 +2218,8 @@ determine_specialization (tree template_id, targs = coerce_template_parms (parms, explicit_targs, fns, tf_warning_or_error, /*req_all*/true, /*use_defarg*/true); - if (targs != error_mark_node) + if (targs != error_mark_node + && constraints_satisfied_p (fns, targs)) templates = tree_cons (targs, fns, templates); } else for (lkp_iterator iter (fns); iter; ++iter) @@ -19029,23 +19030,42 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, { tree op1 = TREE_OPERAND (t, 1); tree rhs1 = NULL_TREE; + tree r = NULL_TREE; tree lhs, rhs; if (TREE_CODE (op1) == COMPOUND_EXPR) { rhs1 = RECUR (TREE_OPERAND (op1, 0)); op1 = TREE_OPERAND (op1, 1); } - lhs = RECUR (TREE_OPERAND (op1, 0)); - rhs = RECUR (TREE_OPERAND (op1, 1)); + if (TREE_CODE (op1) == COND_EXPR) + { + gcc_assert (rhs1 == NULL_TREE); + tree c = TREE_OPERAND (op1, 0); + if (TREE_CODE (c) == MODIFY_EXPR) + { + r = RECUR (TREE_OPERAND (c, 0)); + c = TREE_OPERAND (c, 1); + } + gcc_assert (TREE_CODE (c) == EQ_EXPR); + rhs = RECUR (TREE_OPERAND (c, 1)); + lhs = RECUR (TREE_OPERAND (op1, 2)); + rhs1 = RECUR (TREE_OPERAND (op1, 1)); + } + else + { + lhs = RECUR (TREE_OPERAND (op1, 0)); + rhs = RECUR (TREE_OPERAND (op1, 1)); + } finish_omp_atomic (EXPR_LOCATION (t), OMP_ATOMIC, TREE_CODE (op1), - lhs, rhs, NULL_TREE, NULL_TREE, rhs1, tmp, - OMP_ATOMIC_MEMORY_ORDER (t)); + lhs, rhs, NULL_TREE, NULL_TREE, rhs1, r, + tmp, OMP_ATOMIC_MEMORY_ORDER (t), + OMP_ATOMIC_WEAK (t)); } else { tree op1 = TREE_OPERAND (t, 1); tree v = NULL_TREE, lhs, rhs = NULL_TREE, lhs1 = NULL_TREE; - tree rhs1 = NULL_TREE; + tree rhs1 = NULL_TREE, r = NULL_TREE; enum tree_code code = TREE_CODE (TREE_OPERAND (op1, 1)); enum tree_code opcode = NOP_EXPR; if (code == OMP_ATOMIC_READ) @@ -19064,8 +19084,25 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, rhs1 = RECUR (TREE_OPERAND (op11, 0)); op11 = TREE_OPERAND (op11, 1); } - lhs = RECUR (TREE_OPERAND (op11, 0)); - rhs = RECUR (TREE_OPERAND (op11, 1)); + if (TREE_CODE (op11) == COND_EXPR) + { + gcc_assert (rhs1 == NULL_TREE); + tree c = TREE_OPERAND (op11, 0); + if (TREE_CODE (c) == MODIFY_EXPR) + { + r = RECUR (TREE_OPERAND (c, 0)); + c = TREE_OPERAND (c, 1); + } + gcc_assert (TREE_CODE (c) == EQ_EXPR); + rhs = RECUR (TREE_OPERAND (c, 1)); + lhs = RECUR (TREE_OPERAND (op11, 2)); + rhs1 = RECUR (TREE_OPERAND (op11, 1)); + } + else + { + lhs = RECUR (TREE_OPERAND (op11, 0)); + rhs = RECUR (TREE_OPERAND (op11, 1)); + } opcode = TREE_CODE (op11); if (opcode == MODIFY_EXPR) opcode = NOP_EXPR; @@ -19077,7 +19114,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, rhs = RECUR (TREE_OPERAND (op1, 1)); } finish_omp_atomic (EXPR_LOCATION (t), code, opcode, lhs, rhs, v, - lhs1, rhs1, tmp, OMP_ATOMIC_MEMORY_ORDER (t)); + lhs1, rhs1, r, tmp, + OMP_ATOMIC_MEMORY_ORDER (t), OMP_ATOMIC_WEAK (t)); } break; diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c index fcb3308..9c5066b 100644 --- a/gcc/cp/rtti.c +++ b/gcc/cp/rtti.c @@ -125,7 +125,6 @@ static tree tinfo_name (tree, bool); static tree build_dynamic_cast_1 (location_t, tree, tree, tsubst_flags_t); static tree throw_bad_cast (void); static tree throw_bad_typeid (void); -static tree get_tinfo_ptr (tree); static bool typeid_ok_p (void); static int qualifier_flags (tree); static bool target_incomplete_p (tree); @@ -142,22 +141,11 @@ static bool typeinfo_in_lib_p (tree); static int doing_runtime = 0; -/* Declare language defined type_info type and a pointer to const - type_info. This is incomplete here, and will be completed when - the user #includes <typeinfo>. There are language defined - restrictions on what can be done until that is included. Create - the internal versions of the ABI types. */ +/* Create the internal versions of the ABI types. */ void init_rtti_processing (void) { - push_nested_namespace (std_node); - tree type_info_type = xref_tag (class_type, get_identifier ("type_info")); - pop_nested_namespace (std_node); - const_type_info_type_node - = cp_build_qualified_type (type_info_type, TYPE_QUAL_CONST); - type_info_ptr_type = build_pointer_type (const_type_info_type_node); - vec_alloc (unemitted_tinfo_decls, 124); create_tinfo_types (); @@ -238,6 +226,33 @@ throw_bad_typeid (void) return build_cxx_call (fn, 0, NULL, tf_warning_or_error); } +/* const type_info*. */ + +inline tree +type_info_ptr_type () +{ + return build_pointer_type (const_type_info_type_node); +} + +/* Return a pointer to a type_info object describing TYPE, suitably + cast to the language defined type (for typeid) or void (for building + up the descriptors). */ + +static tree +get_tinfo_ptr (tree type, bool voidp = false) +{ + tree decl = get_tinfo_decl (type); + mark_used (decl); + + tree ptype = voidp ? const_ptr_type_node : type_info_ptr_type (); + return build_nop (ptype, build_address (decl)); +} +static inline tree +get_void_tinfo_ptr (tree type) +{ + return get_tinfo_ptr (type, true); +} + /* Return an lvalue expression whose type is "const std::type_info" and whose value indicates the type of the expression EXP. If EXP is a reference to a polymorphic class, return the dynamic type; @@ -278,7 +293,7 @@ get_tinfo_decl_dynamic (tree exp, tsubst_flags_t complain) index = build_int_cst (NULL_TREE, -1 * TARGET_VTABLE_DATA_ENTRY_DISTANCE); t = build_vtbl_ref (exp, index); - t = convert (type_info_ptr_type, t); + t = convert (type_info_ptr_type (), t); } else /* Otherwise return the type_info for the static type of the expr. */ @@ -296,15 +311,22 @@ typeid_ok_p (void) return false; } - if (!COMPLETE_TYPE_P (const_type_info_type_node)) + if (!const_type_info_type_node) { - gcc_rich_location richloc (input_location); - maybe_add_include_fixit (&richloc, "<typeinfo>", false); - error_at (&richloc, - "must %<#include <typeinfo>%> before using" - " %<typeid%>"); + tree name = get_identifier ("type_info"); + tree decl = lookup_qualified_name (std_node, name); + if (TREE_CODE (decl) != TYPE_DECL) + { + gcc_rich_location richloc (input_location); + maybe_add_include_fixit (&richloc, "<typeinfo>", false); + error_at (&richloc, + "must %<#include <typeinfo>%> before using" + " %<typeid%>"); - return false; + return false; + } + const_type_info_type_node + = cp_build_qualified_type (TREE_TYPE (decl), TYPE_QUAL_CONST); } tree pseudo = TYPE_MAIN_VARIANT (get_tinfo_desc (TK_TYPE_INFO_TYPE)->type); @@ -471,19 +493,6 @@ get_tinfo_decl_direct (tree type, tree name, int pseudo_ix) return d; } -/* Return a pointer to a type_info object describing TYPE, suitably - cast to the language defined type. */ - -static tree -get_tinfo_ptr (tree type) -{ - tree decl = get_tinfo_decl (type); - - mark_used (decl); - return build_nop (type_info_ptr_type, - build_address (decl)); -} - /* Return the type_info object for TYPE. */ tree @@ -1032,7 +1041,7 @@ ptr_initializer (tinfo_s *ti, tree target) CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, init); CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, flags)); CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, - get_tinfo_ptr (TYPE_MAIN_VARIANT (to))); + get_void_tinfo_ptr (TYPE_MAIN_VARIANT (to))); init = build_constructor (init_list_type_node, v); TREE_CONSTANT (init) = 1; @@ -1063,8 +1072,8 @@ ptm_initializer (tinfo_s *ti, tree target) CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, init); CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, flags)); CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, - get_tinfo_ptr (TYPE_MAIN_VARIANT (to))); - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, get_tinfo_ptr (klass)); + get_void_tinfo_ptr (TYPE_MAIN_VARIANT (to))); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, get_void_tinfo_ptr (klass)); init = build_constructor (init_list_type_node, v); TREE_CONSTANT (init) = 1; @@ -1156,7 +1165,7 @@ get_pseudo_ti_init (tree type, unsigned tk_index) case TK_SI_CLASS_TYPE: { tree base_binfo = BINFO_BASE_BINFO (TYPE_BINFO (type), 0); - tree tinfo = get_tinfo_ptr (BINFO_TYPE (base_binfo)); + tree tinfo = get_void_tinfo_ptr (BINFO_TYPE (base_binfo)); /* get_tinfo_ptr might have reallocated the tinfo_descs vector. */ ti = &(*tinfo_descs)[tk_index]; @@ -1187,7 +1196,7 @@ get_pseudo_ti_init (tree type, unsigned tk_index) if ((*base_accesses)[ix] == access_public_node) flags |= 2; - tinfo = get_tinfo_ptr (BINFO_TYPE (base_binfo)); + tinfo = get_void_tinfo_ptr (BINFO_TYPE (base_binfo)); if (BINFO_VIRTUAL_P (base_binfo)) { /* We store the vtable offset at which the virtual @@ -1360,7 +1369,7 @@ get_tinfo_desc (unsigned ix) /* Base class internal helper. Pointer to base type, offset to base, flags. */ tree fld_ptr = build_decl (BUILTINS_LOCATION, FIELD_DECL, - NULL_TREE, type_info_ptr_type); + NULL_TREE, const_ptr_type_node); DECL_CHAIN (fld_ptr) = fields; fields = fld_ptr; @@ -1396,7 +1405,7 @@ get_tinfo_desc (unsigned ix) fields = fld_mask; tree fld_ptr = build_decl (BUILTINS_LOCATION, FIELD_DECL, - NULL_TREE, type_info_ptr_type); + NULL_TREE, const_ptr_type_node); DECL_CHAIN (fld_ptr) = fields; fields = fld_ptr; @@ -1404,7 +1413,7 @@ get_tinfo_desc (unsigned ix) { /* Add a pointer to the class too. */ tree fld_cls = build_decl (BUILTINS_LOCATION, FIELD_DECL, - NULL_TREE, type_info_ptr_type); + NULL_TREE, const_ptr_type_node); DECL_CHAIN (fld_cls) = fields; fields = fld_cls; } @@ -1421,7 +1430,7 @@ get_tinfo_desc (unsigned ix) class. This is really a descendant of __class_type_info. */ tree fld_ptr = build_decl (BUILTINS_LOCATION, FIELD_DECL, - NULL_TREE, type_info_ptr_type); + NULL_TREE, const_ptr_type_node); DECL_CHAIN (fld_ptr) = fields; fields = fld_ptr; break; diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 94e6b18..35a7b9f 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -9877,14 +9877,15 @@ finish_omp_for_block (tree bind, tree omp_for) void finish_omp_atomic (location_t loc, enum tree_code code, enum tree_code opcode, - tree lhs, tree rhs, tree v, tree lhs1, tree rhs1, - tree clauses, enum omp_memory_order mo) + tree lhs, tree rhs, tree v, tree lhs1, tree rhs1, tree r, + tree clauses, enum omp_memory_order mo, bool weak) { tree orig_lhs; tree orig_rhs; tree orig_v; tree orig_lhs1; tree orig_rhs1; + tree orig_r; bool dependent_p; tree stmt; @@ -9893,6 +9894,7 @@ finish_omp_atomic (location_t loc, enum tree_code code, enum tree_code opcode, orig_v = v; orig_lhs1 = lhs1; orig_rhs1 = rhs1; + orig_r = r; dependent_p = false; stmt = NULL_TREE; @@ -9904,7 +9906,10 @@ finish_omp_atomic (location_t loc, enum tree_code code, enum tree_code opcode, || (rhs && type_dependent_expression_p (rhs)) || (v && type_dependent_expression_p (v)) || (lhs1 && type_dependent_expression_p (lhs1)) - || (rhs1 && type_dependent_expression_p (rhs1))); + || (rhs1 && type_dependent_expression_p (rhs1)) + || (r + && r != void_list_node + && type_dependent_expression_p (r))); if (clauses) { gcc_assert (TREE_CODE (clauses) == OMP_CLAUSE @@ -9925,17 +9930,19 @@ finish_omp_atomic (location_t loc, enum tree_code code, enum tree_code opcode, lhs1 = build_non_dependent_expr (lhs1); if (rhs1) rhs1 = build_non_dependent_expr (rhs1); + if (r && r != void_list_node) + r = build_non_dependent_expr (r); } } if (!dependent_p) { bool swapped = false; - if (rhs1 && cp_tree_equal (lhs, rhs)) + if (rhs1 && opcode != COND_EXPR && cp_tree_equal (lhs, rhs)) { std::swap (rhs, rhs1); swapped = !commutative_tree_code (opcode); } - if (rhs1 && !cp_tree_equal (lhs, rhs1)) + if (rhs1 && opcode != COND_EXPR && !cp_tree_equal (lhs, rhs1)) { if (code == OMP_ATOMIC) error ("%<#pragma omp atomic update%> uses two different " @@ -9956,7 +9963,7 @@ finish_omp_atomic (location_t loc, enum tree_code code, enum tree_code opcode, return; } stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, - v, lhs1, rhs1, NULL_TREE, swapped, mo, false, + v, lhs1, rhs1, r, swapped, mo, weak, processing_template_decl != 0); if (stmt == error_mark_node) return; @@ -9973,6 +9980,16 @@ finish_omp_atomic (location_t loc, enum tree_code code, enum tree_code opcode, { if (opcode == NOP_EXPR) stmt = build2 (MODIFY_EXPR, void_type_node, orig_lhs, orig_rhs); + else if (opcode == COND_EXPR) + { + stmt = build2 (EQ_EXPR, boolean_type_node, orig_lhs, orig_rhs); + if (orig_r) + stmt = build2 (MODIFY_EXPR, boolean_type_node, orig_r, + stmt); + stmt = build3 (COND_EXPR, void_type_node, stmt, orig_rhs1, + orig_lhs); + orig_rhs1 = NULL_TREE; + } else stmt = build2 (opcode, void_type_node, orig_lhs, orig_rhs); if (orig_rhs1) @@ -9982,12 +9999,14 @@ finish_omp_atomic (location_t loc, enum tree_code code, enum tree_code opcode, { stmt = build_min_nt_loc (loc, code, orig_lhs1, stmt); OMP_ATOMIC_MEMORY_ORDER (stmt) = mo; + OMP_ATOMIC_WEAK (stmt) = weak; stmt = build2 (MODIFY_EXPR, void_type_node, orig_v, stmt); } } stmt = build2 (OMP_ATOMIC, void_type_node, clauses ? clauses : integer_zero_node, stmt); OMP_ATOMIC_MEMORY_ORDER (stmt) = mo; + OMP_ATOMIC_WEAK (stmt) = weak; SET_EXPR_LOCATION (stmt, loc); } diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index f78dbf2..abfd7da 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -524,7 +524,20 @@ split_nonconstant_init_1 (tree dest, tree init, bool nested) sub = build3 (COMPONENT_REF, inner_type, dest, field_index, NULL_TREE); - if (!split_nonconstant_init_1 (sub, value, true)) + if (!split_nonconstant_init_1 (sub, value, true) + /* For flexible array member with initializer we + can't remove the initializer, because only the + initializer determines how many elements the + flexible array member has. */ + || (!array_type_p + && TREE_CODE (inner_type) == ARRAY_TYPE + && TYPE_DOMAIN (inner_type) == NULL + && TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE + && COMPLETE_TYPE_P (TREE_TYPE (value)) + && !integer_zerop (TYPE_SIZE (TREE_TYPE (value))) + && idx == CONSTRUCTOR_NELTS (init) - 1 + && TYPE_HAS_TRIVIAL_DESTRUCTOR + (strip_array_types (inner_type)))) complete_p = false; else { |