diff options
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/ChangeLog | 195 | ||||
-rw-r--r-- | gcc/cp/constexpr.cc | 18 | ||||
-rw-r--r-- | gcc/cp/coroutines.cc | 58 | ||||
-rw-r--r-- | gcc/cp/cp-gimplify.cc | 27 | ||||
-rw-r--r-- | gcc/cp/cp-objcp-common.h | 9 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 18 | ||||
-rw-r--r-- | gcc/cp/decl.cc | 27 | ||||
-rw-r--r-- | gcc/cp/decl2.cc | 9 | ||||
-rw-r--r-- | gcc/cp/error.cc | 46 | ||||
-rw-r--r-- | gcc/cp/lambda.cc | 28 | ||||
-rw-r--r-- | gcc/cp/method.cc | 32 | ||||
-rw-r--r-- | gcc/cp/name-lookup.h | 4 | ||||
-rw-r--r-- | gcc/cp/parser.cc | 320 | ||||
-rw-r--r-- | gcc/cp/pt.cc | 83 | ||||
-rw-r--r-- | gcc/cp/semantics.cc | 195 |
15 files changed, 966 insertions, 103 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index db79783..f10cf46 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,198 @@ +2025-06-04 Jason Merrill <jason@redhat.com> + + PR c++/120502 + * cp-gimplify.cc (cp_fold_r) [TARGET_EXPR]: Do constexpr evaluation + before genericize. + * constexpr.cc (cxx_eval_store_expression): Add comment. + +2025-06-03 Jason Merrill <jason@redhat.com> + + * name-lookup.h (operator|, operator|=): Define for WMB_Flags. + +2025-06-02 Jason Merrill <jason@redhat.com> + + PR c++/107600 + * method.cc (destructible_expr): Fix refs and arrays of unknown + bound. + +2025-06-02 Jason Merrill <jason@redhat.com> + + PR c++/120506 + * constexpr.cc (cxx_eval_outermost_constant_expr): Always check + CONSTRUCTOR_NO_CLEARING. + +2025-06-02 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (build_actor_fn): Remove an unused + label, guard the frame deallocation correctly, use + simpler APIs to build if and return statements. + +2025-06-02 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/118903 + * constexpr.cc (potential_constant_expression_1): Emit + an error when co_await et. al. are used in constexpr + contexts. + +2025-06-02 Iain Sandoe <iain@sandoe.co.uk> + + * error.cc (dump_expr): Add co_await, co_yield and co_return. + +2025-06-02 Jason Merrill <jason@redhat.com> + + PR c++/107600 + * method.cc (destructible_expr): Handle non-classes. + (constructible_expr): Check for abstract class here... + (is_xible_helper): ...not here. + +2025-06-02 Jason Merrill <jason@redhat.com> + + PR c++/107600 + * semantics.cc (trait_expr_value) [CPTK_HAS_TRIVIAL_DESTRUCTOR]: + Add cp_unevaluated. + +2025-06-02 Sandra Loosemore <sloosemore@baylibre.com> + + * cp-tree.h (maybe_convert_cond): Declare. + * parser.cc (cp_parser_omp_context_selector): Call + maybe_convert_cond and fold_build_cleanup_point_expr on the + expression for OMP_TRAIT_PROPERTY_BOOL_EXPR. + * pt.cc (tsubst_omp_context_selector): Likewise. + * semantics.cc (maybe_convert_cond): Remove static declaration. + +2025-05-30 Jason Merrill <jason@redhat.com> + + PR c++/113563 + * lambda.cc (lambda_capture_field_type): Handle 'this' normally. + (build_capture_proxy): Special-case 'this' by-ref capture more. + (nonlambda_method_basetype): Look through xobj lambdas. + +2025-05-30 Julian Brown <julian@codesourcery.com> + Tobias Burnus <tburnus@baylibre.com> + + * constexpr.cc (reduced_constant_expression_p): Add OMP_DECLARE_MAPPER + case. + (cxx_eval_constant_expression, potential_constant_expression_1): + Likewise. + * cp-gimplify.cc (cxx_omp_finish_mapper_clauses): New function. + * cp-objcp-common.h (LANG_HOOKS_OMP_FINISH_MAPPER_CLAUSES, + LANG_HOOKS_OMP_MAPPER_LOOKUP, LANG_HOOKS_OMP_EXTRACT_MAPPER_DIRECTIVE, + LANG_HOOKS_OMP_MAP_ARRAY_SECTION): Define langhooks. + * cp-tree.h (lang_decl_base): Add omp_declare_mapper_p field. Recount + spare bits comment. + (DECL_OMP_DECLARE_MAPPER_P): New macro. + (omp_mapper_id): Add prototype. + (cp_check_omp_declare_mapper): Add prototype. + (omp_instantiate_mappers): Add prototype. + (cxx_omp_finish_mapper_clauses): Add prototype. + (cxx_omp_mapper_lookup): Add prototype. + (cxx_omp_extract_mapper_directive): Add prototype. + (cxx_omp_map_array_section): Add prototype. + * decl.cc (check_initializer): Add OpenMP declare mapper support. + (cp_finish_decl): Set DECL_INITIAL for OpenMP declare mapper var decls + as appropriate. + * decl2.cc (mark_used): Instantiate OpenMP "declare mapper" magic var + decls. + * error.cc (dump_omp_declare_mapper): New function. + (dump_simple_decl): Use above. + * parser.cc (cp_parser_omp_clause_map): Add KIND parameter. Support + "mapper" modifier. + (cp_parser_omp_all_clauses): Add KIND argument to + cp_parser_omp_clause_map call. + (cp_parser_omp_target): Call omp_instantiate_mappers before + finish_omp_clauses. + (cp_parser_omp_declare_mapper): New function. + (cp_parser_omp_declare): Add "declare mapper" support. + * pt.cc (tsubst_decl): Adjust name of "declare mapper" magic var decls + once we know their type. + (tsubst_omp_clauses): Call omp_instantiate_mappers before + finish_omp_clauses, for target regions. + (tsubst_expr): Support OMP_DECLARE_MAPPER nodes. + (instantiate_decl): Instantiate initialiser (i.e definition) for OpenMP + declare mappers. + * semantics.cc (gimplify.h): Include. + (omp_mapper_id, omp_mapper_lookup, omp_extract_mapper_directive, + cxx_omp_map_array_section, cp_check_omp_declare_mapper): New functions. + (finish_omp_clauses): Delete GOMP_MAP_PUSH_MAPPER_NAME and + GOMP_MAP_POP_MAPPER_NAME artificial clauses. + (omp_target_walk_data): Add MAPPERS field. + (finish_omp_target_clauses_r): Scan for uses of struct/union/class type + variables. + (finish_omp_target_clauses): Create artificial mapper binding clauses + for used structs/unions/classes in offload region. + +2025-05-29 David Malcolm <dmalcolm@redhat.com> + + * error.cc (cxx_format_postprocessor::clone): Update to use + unique_ptr. + (cxx_dump_pretty_printer::cxx_dump_pretty_printer): Likewise. + (cxx_initialize_diagnostics): Likewise. + +2025-05-29 Jason Merrill <jason@redhat.com> + + PR c++/113563 + * lambda.cc (build_capture_proxy): Check pointerness of the + member, not the proxy type. + (lambda_expr_this_capture): Don't assume current_class_ref. + (nonlambda_method_basetype): Likewise. + * semantics.cc (finish_non_static_data_member): Don't assume + TREE_TYPE (object) is set. + (finish_this_expr): Check current_class_type for lambda, + not current_class_ref. + +2025-05-29 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/109283 + * coroutines.cc (find_any_await): Only save the statement + pointer if the caller passes a place for it. + (flatten_await_stmt): When checking that ternary expressions + have been handled, also check that they contain a co_await. + +2025-05-29 Jason Merrill <jason@redhat.com> + + * decl.cc (start_decl): Also set invalid_constexpr + for maybe_constexpr_fn. + * parser.cc (cp_parser_jump_statement): Likewise. + * constexpr.cc (potential_constant_expression_1): Ignore + goto to an artificial label. + +2025-05-29 Sandra Loosemore <sloosemore@baylibre.com> + + * parser.cc (cp_parser_omp_metadirective): Do not call + cp_parser_skip_to_end_of_block_or_statement after an error. + +2025-05-29 Sandra Loosemore <sloosemore@baylibre.com> + + PR c/120180 + * parser.cc (cp_parser_omp_metadirective): Only consume the + token if it is the expected close paren. + +2025-05-29 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (analyze_fn_parms): No longer + create a parameter copy guard var. + * coroutines.h (struct param_info): Remove the + entry for the parameter copy destructor guard. + +2025-05-29 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/120453 + * cp-tree.h (DECL_RAMP_P): New. + * typeck.cc (check_return_expr): Use DECL_RAMP_P instead + of DECL_RAMP_FN. + +2025-05-29 Jason Merrill <jason@redhat.com> + + PR c++/107600 + * cp-trait.def (IS_DESTRUCTIBLE, IS_NOTHROW_DESTRUCTIBLE) + (IS_TRIVIALLY_DESTRUCTIBLE): New. + * constraint.cc (diagnose_trait_expr): Explain them. + * method.cc (destructible_expr): New. + (is_xible_helper): Use it. + * semantics.cc (finish_trait_expr): Handle new traits. + (trait_expr_value): Likewise. Complain about asking + whether a deleted dtor is trivial. + 2025-05-28 Jason Merrill <jason@redhat.com> * module.cc (module_state::write_namespaces): Write diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index 272fab3..c0e37b2 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -3529,6 +3529,9 @@ reduced_constant_expression_p (tree t) /* Even if we can't lower this yet, it's constant. */ return true; + case OMP_DECLARE_MAPPER: + return true; + case CONSTRUCTOR: /* And we need to handle PTRMEM_CST wrapped in a CONSTRUCTOR. */ tree field; @@ -6410,7 +6413,8 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, if (TREE_CLOBBER_P (init) && CLOBBER_KIND (init) < CLOBBER_OBJECT_END) - /* Only handle clobbers ending the lifetime of objects. */ + /* Only handle clobbers ending the lifetime of objects. + ??? We should probably set CONSTRUCTOR_NO_CLEARING. */ return void_node; /* First we figure out where we're storing to. */ @@ -7838,6 +7842,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, case LABEL_EXPR: case CASE_LABEL_EXPR: case PREDICT_EXPR: + case OMP_DECLARE_MAPPER: return t; case PARM_DECL: @@ -9274,8 +9279,7 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, /* After verify_constant because reduced_constant_expression_p can unset CONSTRUCTOR_NO_CLEARING. */ - if (!non_constant_p - && TREE_CODE (r) == CONSTRUCTOR && CONSTRUCTOR_NO_CLEARING (r)) + if (TREE_CODE (r) == CONSTRUCTOR && CONSTRUCTOR_NO_CLEARING (r)) { if (!allow_non_constant) error ("%qE is not a constant expression because it refers to " @@ -10532,6 +10536,11 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, "expression", t); return false; + case OMP_DECLARE_MAPPER: + /* This can be used to initialize VAR_DECLs: it's treated as a magic + constant. */ + return true; + case ASM_EXPR: if (flags & tf_error) inline_asm_in_constexpr_error (loc, fundef_p); @@ -11015,6 +11024,9 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, case CO_AWAIT_EXPR: case CO_YIELD_EXPR: case CO_RETURN_EXPR: + if (flags & tf_error) + constexpr_error (cp_expr_loc_or_loc (t, input_location), fundef_p, + "%qE is not a constant expression", t); return false; /* Assume a TU-local entity is not constant, we'll error later when diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 5815a8c..7f5d30c 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -2543,8 +2543,8 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, /* Finish the resume dispatcher. */ finish_switch_stmt (dispatcher); - finish_else_clause (lsb_if); + finish_else_clause (lsb_if); finish_if_stmt (lsb_if); /* If we reach here then we've hit UB. */ @@ -2583,69 +2583,53 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, /* Add in our function body with the co_returns rewritten to final form. */ add_stmt (fnbody); - /* now do the tail of the function. */ + /* Now do the tail of the function; first cleanups. */ r = build_stmt (loc, LABEL_EXPR, del_promise_label); add_stmt (r); - /* Destructors for the things we built explicitly. */ + /* Destructors for the things we built explicitly. + promise... */ if (tree c = cxx_maybe_build_cleanup (promise_proxy, tf_warning_or_error)) - add_stmt (c); - - tree del_frame_label - = create_named_label_with_ctx (loc, "coro.delete.frame", actor); - r = build_stmt (loc, LABEL_EXPR, del_frame_label); - add_stmt (r); - - /* Here deallocate the frame (if we allocated it), which we will have at - present. */ - tree fnf2_x - = coro_build_frame_access_expr (actor_frame, coro_frame_needs_free_id, - false, tf_warning_or_error); + finish_expr_stmt (c); - tree need_free_if = begin_if_stmt (); - fnf2_x = build1 (CONVERT_EXPR, integer_type_node, fnf2_x); - tree cmp = build2 (NE_EXPR, integer_type_node, fnf2_x, integer_zero_node); - finish_if_stmt_cond (cmp, need_free_if); + /* Argument copies ... */ while (!param_dtor_list->is_empty ()) { tree parm_id = param_dtor_list->pop (); tree a = coro_build_frame_access_expr (actor_frame, parm_id, false, tf_warning_or_error); if (tree dtor = cxx_maybe_build_cleanup (a, tf_warning_or_error)) - add_stmt (dtor); + finish_expr_stmt (dtor); } + /* Here deallocate the frame (if we allocated it), which we will have at + present. */ + tree fnf2_x + = coro_build_frame_access_expr (actor_frame, coro_frame_needs_free_id, + false, tf_warning_or_error); + tree need_free_if = begin_if_stmt (); + finish_if_stmt_cond (fnf2_x, need_free_if); + /* Build the frame DTOR. */ tree del_coro_fr = build_coroutine_frame_delete_expr (actor_fp, frame_size, promise_type, loc); finish_expr_stmt (del_coro_fr); finish_then_clause (need_free_if); - tree scope = IF_SCOPE (need_free_if); - IF_SCOPE (need_free_if) = NULL; - r = do_poplevel (scope); - add_stmt (r); + finish_if_stmt (need_free_if); - /* done. */ - r = build_stmt (loc, RETURN_EXPR, NULL); - suppress_warning (r); /* We don't want a warning about this. */ - r = maybe_cleanup_point_expr_void (r); - add_stmt (r); + /* Done. */ + finish_return_stmt (NULL_TREE); /* This is the suspend return point. */ - r = build_stmt (loc, LABEL_EXPR, ret_label); - add_stmt (r); + add_stmt (build_stmt (loc, LABEL_EXPR, ret_label)); - r = build_stmt (loc, RETURN_EXPR, NULL); - suppress_warning (r); /* We don't want a warning about this. */ - r = maybe_cleanup_point_expr_void (r); - add_stmt (r); + finish_return_stmt (NULL_TREE); /* This is the 'continuation' return point. For such a case we have a coro handle (from the await_suspend() call) and we want handle.resume() to execute as a tailcall allowing arbitrary chaining of coroutines. */ - r = build_stmt (loc, LABEL_EXPR, continue_label); - add_stmt (r); + add_stmt (build_stmt (loc, LABEL_EXPR, continue_label)); /* Should have been set earlier by the coro_initialized code. */ gcc_assert (void_coro_handle_address); diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc index 03d5352..0fcfa16 100644 --- a/gcc/cp/cp-gimplify.cc +++ b/gcc/cp/cp-gimplify.cc @@ -1473,6 +1473,19 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data_) break; case TARGET_EXPR: + if (!flag_no_inline) + if (tree &init = TARGET_EXPR_INITIAL (stmt)) + { + tree folded = maybe_constant_init (init, TARGET_EXPR_SLOT (stmt), + (data->flags & ff_mce_false + ? mce_false : mce_unknown)); + if (folded != init && TREE_CONSTANT (folded)) + init = folded; + } + + /* This needs to happen between the constexpr evaluation (which wants + pre-generic trees) and fold (which wants the cp_genericize_init + transformations). */ if (data->flags & ff_genericize) cp_genericize_target_expr (stmt_p); @@ -1481,14 +1494,6 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data_) cp_walk_tree (&init, cp_fold_r, data, NULL); cp_walk_tree (&TARGET_EXPR_CLEANUP (stmt), cp_fold_r, data, NULL); *walk_subtrees = 0; - if (!flag_no_inline) - { - tree folded = maybe_constant_init (init, TARGET_EXPR_SLOT (stmt), - (data->flags & ff_mce_false - ? mce_false : mce_unknown)); - if (folded != init && TREE_CONSTANT (folded)) - init = folded; - } /* Folding might replace e.g. a COND_EXPR with a TARGET_EXPR; in that case, strip it in favor of this one. */ if (TREE_CODE (init) == TARGET_EXPR) @@ -2809,6 +2814,12 @@ cxx_omp_finish_clause (tree c, gimple_seq *, bool /* openacc */) } } +tree +cxx_omp_finish_mapper_clauses (tree clauses) +{ + return finish_omp_clauses (clauses, C_ORT_OMP); +} + /* Return true if DECL's DECL_VALUE_EXPR (if any) should be disregarded in OpenMP construct, because it is going to be remapped during OpenMP lowering. SHARED is true if DECL diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h index 13fb80c..ff35428 100644 --- a/gcc/cp/cp-objcp-common.h +++ b/gcc/cp/cp-objcp-common.h @@ -190,6 +190,15 @@ static const scoped_attribute_specs *const cp_objcp_attribute_table[] = #define LANG_HOOKS_OMP_CLAUSE_DTOR cxx_omp_clause_dtor #undef LANG_HOOKS_OMP_FINISH_CLAUSE #define LANG_HOOKS_OMP_FINISH_CLAUSE cxx_omp_finish_clause +#undef LANG_HOOKS_OMP_FINISH_MAPPER_CLAUSES +#define LANG_HOOKS_OMP_FINISH_MAPPER_CLAUSES cxx_omp_finish_mapper_clauses +#undef LANG_HOOKS_OMP_MAPPER_LOOKUP +#define LANG_HOOKS_OMP_MAPPER_LOOKUP cxx_omp_mapper_lookup +#undef LANG_HOOKS_OMP_EXTRACT_MAPPER_DIRECTIVE +#define LANG_HOOKS_OMP_EXTRACT_MAPPER_DIRECTIVE \ + cxx_omp_extract_mapper_directive +#undef LANG_HOOKS_OMP_MAP_ARRAY_SECTION +#define LANG_HOOKS_OMP_MAP_ARRAY_SECTION cxx_omp_map_array_section #undef LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE #define LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE cxx_omp_privatize_by_reference #undef LANG_HOOKS_OMP_DISREGARD_VALUE_EXPR diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index d9fc80b..3cf4a76 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -2975,7 +2975,10 @@ struct GTY(()) lang_decl_base { unsigned module_keyed_decls_p : 1; /* has keys, applies to all decls */ - /* 11 spare bits. */ + /* VAR_DECL being used to represent an OpenMP declared mapper. */ + unsigned omp_declare_mapper_p : 1; + + /* 10 spare bits. */ }; /* True for DECL codes which have template info and access. */ @@ -4530,6 +4533,11 @@ get_vec_init_expr (tree t) #define DECL_OMP_DECLARE_REDUCTION_P(NODE) \ (LANG_DECL_FN_CHECK (DECL_COMMON_CHECK (NODE))->omp_declare_reduction_p) +/* Nonzero if NODE is an artificial FUNCTION_DECL for + #pragma omp declare mapper. */ +#define DECL_OMP_DECLARE_MAPPER_P(NODE) \ + (DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE))->u.base.omp_declare_mapper_p) + /* Nonzero if DECL has been declared threadprivate by #pragma omp threadprivate. */ #define CP_DECL_THREADPRIVATE_P(DECL) \ @@ -7948,6 +7956,7 @@ extern bool perform_deferred_access_checks (tsubst_flags_t); extern bool perform_or_defer_access_check (tree, tree, tree, tsubst_flags_t, access_failure_info *afi = NULL); +extern tree maybe_convert_cond (tree); /* RAII sentinel to ensures that deferred access checks are popped before a function returns. */ @@ -8096,11 +8105,14 @@ extern tree finish_qualified_id_expr (tree, tree, bool, bool, extern void simplify_aggr_init_expr (tree *); extern void finalize_nrv (tree, tree); extern tree omp_reduction_id (enum tree_code, tree, tree); +extern tree omp_mapper_id (tree, tree); extern tree cp_remove_omp_priv_cleanup_stmt (tree *, int *, void *); extern bool cp_check_omp_declare_reduction (tree); +extern bool cp_check_omp_declare_mapper (tree); extern void finish_omp_declare_simd_methods (tree); extern tree cp_finish_omp_init_prefer_type (tree); extern tree finish_omp_clauses (tree, enum c_omp_region_type); +extern tree omp_instantiate_mappers (tree); extern tree push_omp_privatization_clauses (bool); extern void pop_omp_privatization_clauses (tree); extern void save_omp_privatization_clauses (vec<tree> &); @@ -8696,6 +8708,10 @@ extern tree cxx_omp_clause_copy_ctor (tree, tree, tree); extern tree cxx_omp_clause_assign_op (tree, tree, tree); extern tree cxx_omp_clause_dtor (tree, tree); extern void cxx_omp_finish_clause (tree, gimple_seq *, bool); +extern tree cxx_omp_finish_mapper_clauses (tree); +extern tree cxx_omp_mapper_lookup (tree, tree); +extern tree cxx_omp_extract_mapper_directive (tree); +extern tree cxx_omp_map_array_section (location_t, tree); extern bool cxx_omp_privatize_by_reference (const_tree); extern bool cxx_omp_disregard_value_expr (tree, bool); extern void cp_fold_function (tree); diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index ec4b629..9a20ed6 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -7877,6 +7877,12 @@ check_initializer (tree decl, tree init, int flags, vec<tree, va_gc> **cleanups) } else if (!init && DECL_REALLY_EXTERN (decl)) ; + else if (flag_openmp + && VAR_P (decl) + && DECL_LANG_SPECIFIC (decl) + && DECL_OMP_DECLARE_MAPPER_P (decl) + && TREE_CODE (init) == OMP_DECLARE_MAPPER) + return NULL_TREE; else if (init || type_build_ctor_call (type) || TYPE_REF_P (type)) { @@ -9197,14 +9203,23 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, varpool_node::get_create (decl); } + if (flag_openmp + && VAR_P (decl) + && DECL_LANG_SPECIFIC (decl) + && DECL_OMP_DECLARE_MAPPER_P (decl) + && init) + { + gcc_assert (TREE_CODE (init) == OMP_DECLARE_MAPPER); + DECL_INITIAL (decl) = init; + } /* Convert the initializer to the type of DECL, if we have not already initialized DECL. */ - if (!DECL_INITIALIZED_P (decl) - /* If !DECL_EXTERNAL then DECL is being defined. In the - case of a static data member initialized inside the - class-specifier, there can be an initializer even if DECL - is *not* defined. */ - && (!DECL_EXTERNAL (decl) || init)) + else if (!DECL_INITIALIZED_P (decl) + /* If !DECL_EXTERNAL then DECL is being defined. In the + case of a static data member initialized inside the + class-specifier, there can be an initializer even if DECL + is *not* defined. */ + && (!DECL_EXTERNAL (decl) || init)) { cleanups = make_tree_vector (); init = check_initializer (decl, init, flags, &cleanups); diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc index 666ab78..e3fbc40 100644 --- a/gcc/cp/decl2.cc +++ b/gcc/cp/decl2.cc @@ -6408,12 +6408,17 @@ mark_used (tree decl, tsubst_flags_t complain /* = tf_warning_or_error */) /* If DECL has a deduced return type, we need to instantiate it now to find out its type. For OpenMP user defined reductions, we need them - instantiated for reduction clauses which inline them by hand directly. */ + instantiated for reduction clauses which inline them by hand directly. + OpenMP declared mappers are used implicitly so must be instantiated + before they can be detected. */ if (undeduced_auto_decl (decl) || (VAR_P (decl) && VAR_HAD_UNKNOWN_BOUND (decl)) || (TREE_CODE (decl) == FUNCTION_DECL - && DECL_OMP_DECLARE_REDUCTION_P (decl))) + && DECL_OMP_DECLARE_REDUCTION_P (decl)) + || (TREE_CODE (decl) == VAR_DECL + && DECL_LANG_SPECIFIC (decl) + && DECL_OMP_DECLARE_MAPPER_P (decl))) maybe_instantiate_decl (decl); if (!decl_dependent_p (decl) diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc index a6a4a8c..69da381 100644 --- a/gcc/cp/error.cc +++ b/gcc/cp/error.cc @@ -1282,12 +1282,37 @@ dump_global_iord (cxx_pretty_printer *pp, tree t) pp_printf (pp, p, DECL_SOURCE_FILE (t)); } +/* Write a representation of OpenMP "declare mapper" T to PP in a manner + suitable for error messages. */ + +static void +dump_omp_declare_mapper (cxx_pretty_printer *pp, tree t, int flags) +{ + pp_string (pp, "#pragma omp declare mapper"); + if (t == NULL_TREE || t == error_mark_node) + return; + pp_space (pp); + pp_cxx_left_paren (pp); + if (OMP_DECLARE_MAPPER_ID (t)) + { + pp_cxx_tree_identifier (pp, OMP_DECLARE_MAPPER_ID (t)); + pp_colon (pp); + } + dump_type (pp, TREE_TYPE (t), flags); + pp_cxx_right_paren (pp); +} + static void dump_simple_decl (cxx_pretty_printer *pp, tree t, tree type, int flags) { if (VAR_P (t) && DECL_NTTP_OBJECT_P (t)) return dump_expr (pp, DECL_INITIAL (t), flags); + if (TREE_CODE (t) == VAR_DECL + && DECL_LANG_SPECIFIC (t) + && DECL_OMP_DECLARE_MAPPER_P (t)) + return dump_omp_declare_mapper (pp, DECL_INITIAL (t), flags); + if (flags & TFF_DECL_SPECIFIERS) { if (concept_definition_p (t)) @@ -3244,6 +3269,27 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags) break; } + case CO_AWAIT_EXPR: + pp_cxx_ws_string (pp, "co_await"); + pp_cxx_whitespace (pp); + dump_expr (pp, TREE_OPERAND (t, 0), flags); + break; + + case CO_YIELD_EXPR: + pp_cxx_ws_string (pp, "co_yield"); + pp_cxx_whitespace (pp); + dump_expr (pp, TREE_OPERAND (t, 0), flags); + break; + + case CO_RETURN_EXPR: + pp_cxx_ws_string (pp, "co_return"); + if (TREE_OPERAND (t, 0)) + { + pp_cxx_whitespace (pp); + dump_expr (pp, TREE_OPERAND (t, 0), flags); + } + break; + /* This list is incomplete, but should suffice for now. It is very important that `sorry' does not call `report_error_function'. That could cause an infinite loop. */ diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc index 34c7def..2a9061a 100644 --- a/gcc/cp/lambda.cc +++ b/gcc/cp/lambda.cc @@ -218,9 +218,7 @@ lambda_capture_field_type (tree expr, bool explicit_init_p, tree type; bool is_this = is_this_parameter (tree_strip_nop_conversions (expr)); - if (is_this) - type = TREE_TYPE (expr); - else if (explicit_init_p) + if (explicit_init_p) { tree auto_node = make_auto (); @@ -259,7 +257,7 @@ lambda_capture_field_type (tree expr, bool explicit_init_p, type = non_reference (unlowered_expr_type (expr)); - if (by_reference_p || TREE_CODE (type) == FUNCTION_TYPE) + if ((by_reference_p && !is_this) || TREE_CODE (type) == FUNCTION_TYPE) type = build_reference_type (type); } @@ -440,13 +438,21 @@ build_capture_proxy (tree member, tree init) else name = get_identifier (IDENTIFIER_POINTER (DECL_NAME (member)) + 2); - type = lambda_proxy_type (object); - - if (name == this_identifier && !INDIRECT_TYPE_P (TREE_TYPE (member))) + if (name == this_identifier && TYPE_PTR_P (TREE_TYPE (member))) + /* Avoid DECLTYPE_TYPE for by-ref 'this' capture in an xobj lambda; the + constness of the closure doesn't matter just like it doesn't matter to + other by-ref capture. It's simpler to handle this special case here + than in lambda_proxy_type. */ + type = TREE_TYPE (member); + else { - type = build_pointer_type (type); - type = cp_build_qualified_type (type, TYPE_QUAL_CONST); - object = build_fold_addr_expr_with_type (object, type); + type = lambda_proxy_type (object); + if (name == this_identifier) + { + type = build_pointer_type (type); + type = cp_build_qualified_type (type, TYPE_QUAL_CONST); + object = build_fold_addr_expr_with_type (object, type); + } } if (DECL_VLA_CAPTURE_P (member)) @@ -1052,7 +1058,7 @@ nonlambda_method_basetype (void) tree fn = TYPE_CONTEXT (type); if (!fn || TREE_CODE (fn) != FUNCTION_DECL - || !DECL_IOBJ_MEMBER_FUNCTION_P (fn)) + || !DECL_OBJECT_MEMBER_FUNCTION_P (fn)) /* No enclosing non-lambda method. */ return NULL_TREE; if (!LAMBDA_FUNCTION_P (fn)) diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc index 3a675d9..67a80a3 100644 --- a/gcc/cp/method.cc +++ b/gcc/cp/method.cc @@ -2251,6 +2251,8 @@ constructible_expr (tree to, tree from) const int len = TREE_VEC_LENGTH (from); if (CLASS_TYPE_P (to)) { + if (ABSTRACT_CLASS_TYPE_P (to)) + return error_mark_node; tree ctype = to; vec<tree, va_gc> *args = NULL; if (!TYPE_REF_P (to)) @@ -2330,17 +2332,35 @@ constructible_expr (tree to, tree from) return expr; } -/* Return declval<T>().~T() treated as an unevaluated operand. */ +/* Valid if "Either T is a reference type, or T is a complete object type for + which the expression declval<U&>().~U() is well-formed when treated as an + unevaluated operand ([expr.context]), where U is remove_all_extents_t<T>." + + For a class U, return the destructor call; otherwise return void_node if + valid or error_mark_node if not. */ static tree destructible_expr (tree to) { cp_unevaluated cp_uneval_guard; int flags = LOOKUP_NORMAL|LOOKUP_DESTRUCTOR; - to = build_trait_object (to); - tree r = build_delete (input_location, TREE_TYPE (to), to, - sfk_complete_destructor, flags, 0, tf_none); - return r; + if (TYPE_REF_P (to)) + return void_node; + if (!COMPLETE_TYPE_P (complete_type (to))) + return error_mark_node; + to = strip_array_types (to); + if (CLASS_TYPE_P (to)) + { + to = build_trait_object (to); + return build_delete (input_location, TREE_TYPE (to), to, + sfk_complete_destructor, flags, 0, tf_none); + } + /* [expr.prim.id.dtor] If the id-expression names a pseudo-destructor, T + shall be a scalar type.... */ + else if (scalarish_type_p (to)) + return void_node; + else + return error_mark_node; } /* Returns a tree iff TO is assignable (if CODE is MODIFY_EXPR) or @@ -2352,7 +2372,7 @@ 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) + if (VOID_TYPE_P (to) || (from && FUNC_OR_METHOD_TYPE_P (from) && (TYPE_READONLY (from) || FUNCTION_REF_QUALIFIED (from)))) return error_mark_node; diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h index 4216a51..2fa736b 100644 --- a/gcc/cp/name-lookup.h +++ b/gcc/cp/name-lookup.h @@ -501,6 +501,10 @@ enum WMB_Flags WMB_Hidden = 1 << 3, WMB_Purview = 1 << 4, }; +inline WMB_Flags operator|(WMB_Flags x, WMB_Flags y) +{ return WMB_Flags(+x|y); } +inline WMB_Flags& operator|=(WMB_Flags& x, WMB_Flags y) +{ return x = x|y; } extern unsigned walk_module_binding (tree binding, bitmap partitions, bool (*)(tree decl, WMB_Flags, void *data), diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 091873c..8633763 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -42424,13 +42424,13 @@ cp_parser_omp_clause_from_to (cp_parser *parser, enum omp_clause_code kind, map ( [map-type-modifier[,] ...] map-kind: variable-list ) map-type-modifier: - always | close */ + always | close | mapper ( mapper-name ) */ static tree -cp_parser_omp_clause_map (cp_parser *parser, tree list) +cp_parser_omp_clause_map (cp_parser *parser, tree list, bool declare_mapper_p) { tree nlist, c; - enum gomp_map_kind kind = GOMP_MAP_TOFROM; + enum gomp_map_kind kind = declare_mapper_p ? GOMP_MAP_UNSET : GOMP_MAP_TOFROM; if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) return list; @@ -42448,12 +42448,17 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list) if (cp_lexer_peek_nth_token (parser->lexer, pos + 1)->type == CPP_COMMA) pos++; + else if (cp_lexer_peek_nth_token (parser->lexer, pos + 1)->type + == CPP_OPEN_PAREN) + pos = cp_parser_skip_balanced_tokens (parser, pos + 1); pos++; } bool always_modifier = false; bool close_modifier = false; bool present_modifier = false; + bool mapper_modifier = false; + tree mapper_name = NULL_TREE; for (int pos = 1; pos < map_kind_pos; ++pos) { cp_token *tok = cp_lexer_peek_token (parser->lexer); @@ -42476,6 +42481,7 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list) return list; } always_modifier = true; + cp_lexer_consume_token (parser->lexer); } else if (strcmp ("close", p) == 0) { @@ -42489,6 +42495,77 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list) return list; } close_modifier = true; + cp_lexer_consume_token (parser->lexer); + } + else if (strcmp ("mapper", p) == 0) + { + cp_lexer_consume_token (parser->lexer); + + matching_parens parens; + if (parens.require_open (parser)) + { + if (mapper_modifier) + { + cp_parser_error (parser, "too many %<mapper%> modifiers"); + /* Assume it's a well-formed mapper modifier, even if it + seems to be in the wrong place. */ + cp_lexer_consume_token (parser->lexer); + parens.require_close (parser); + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/ + true); + return list; + } + + tok = cp_lexer_peek_token (parser->lexer); + switch (tok->type) + { + case CPP_NAME: + { + cp_expr e = cp_parser_identifier (parser); + if (e != error_mark_node) + mapper_name = e; + else + goto err; + if (declare_mapper_p) + { + error_at (e.get_location (), + "in %<declare mapper%> directives, parameter " + "to %<mapper%> modifier must be %<default%>"); + } + } + break; + + case CPP_KEYWORD: + if (tok->keyword == RID_DEFAULT) + { + cp_lexer_consume_token (parser->lexer); + break; + } + /* Fallthrough. */ + + default: + err: + cp_parser_error (parser, + "expected identifier or %<default%>"); + return list; + } + + if (!parens.require_close (parser)) + { + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/ + true); + return list; + } + + mapper_modifier = true; + pos += 3; + } } else if (strcmp ("present", p) == 0) { @@ -42502,19 +42579,19 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list) return list; } present_modifier = true; - } + cp_lexer_consume_token (parser->lexer); + } else { - cp_parser_error (parser, "%<map%> clause with map-type modifier other" - " than %<always%>, %<close%> or %<present%>"); + cp_parser_error (parser, "%<map%> clause with map-type modifier " + "other than %<always%>, %<close%>, " + "%<mapper%> or %<present%>"); cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, /*or_comma=*/false, /*consume_paren=*/true); return list; } - - cp_lexer_consume_token (parser->lexer); } if (cp_lexer_next_token_is (parser->lexer, CPP_NAME) @@ -42570,8 +42647,30 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list) NULL, true); finish_scope (); + tree last_new = NULL_TREE; + for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) - OMP_CLAUSE_SET_MAP_KIND (c, kind); + { + OMP_CLAUSE_SET_MAP_KIND (c, kind); + last_new = c; + } + + if (mapper_name) + { + tree name = build_omp_clause (input_location, OMP_CLAUSE_MAP); + OMP_CLAUSE_SET_MAP_KIND (name, GOMP_MAP_PUSH_MAPPER_NAME); + OMP_CLAUSE_DECL (name) = mapper_name; + OMP_CLAUSE_CHAIN (name) = nlist; + nlist = name; + + gcc_assert (last_new); + + name = build_omp_clause (input_location, OMP_CLAUSE_MAP); + OMP_CLAUSE_SET_MAP_KIND (name, GOMP_MAP_POP_MAPPER_NAME); + OMP_CLAUSE_DECL (name) = null_pointer_node; + OMP_CLAUSE_CHAIN (name) = OMP_CLAUSE_CHAIN (last_new); + OMP_CLAUSE_CHAIN (last_new) = name; + } return nlist; } @@ -43899,7 +43998,8 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, c_name = "detach"; break; case PRAGMA_OMP_CLAUSE_MAP: - clauses = cp_parser_omp_clause_map (parser, clauses); + clauses = cp_parser_omp_clause_map (parser, clauses, + /*mapper=*/false); c_name = "map"; break; case PRAGMA_OMP_CLAUSE_DEVICE: @@ -48905,6 +49005,8 @@ cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok, OMP_CLAUSE_CHAIN (nc) = OMP_CLAUSE_CHAIN (c); OMP_CLAUSE_CHAIN (c) = nc; } + if (!processing_template_decl) + clauses = c_omp_instantiate_mappers (clauses); clauses = finish_omp_clauses (clauses, C_ORT_OMP_TARGET); c_omp_adjust_map_clauses (clauses, true); @@ -49884,12 +49986,25 @@ cp_parser_omp_context_selector (cp_parser *parser, enum omp_tss_code set, && !value_dependent_expression_p (t)) { t = fold_non_dependent_expr (t); - if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + if (property_kind == OMP_TRAIT_PROPERTY_BOOL_EXPR) { - error_at (token->location, - "property must be integer expression"); - return error_mark_node; + t = maybe_convert_cond (t); + if (t == error_mark_node) + return error_mark_node; + } + else + { + t = convert_from_reference (t); + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error_at (token->location, + "property must be integer expression"); + return error_mark_node; + } } + if (!processing_template_decl + && TREE_CODE (t) != CLEANUP_POINT_EXPR) + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); } properties = make_trait_property (NULL_TREE, t, properties); break; @@ -52179,6 +52294,175 @@ cp_parser_omp_declare_reduction (cp_parser *parser, cp_token *pragma_tok, obstack_free (&declarator_obstack, p); } +/* OpenMP 5.0 + #pragma omp declare mapper([mapper-identifier:]type var) \ + [clause[[,] clause] ... ] new-line */ + +static void +cp_parser_omp_declare_mapper (cp_parser *parser, cp_token *pragma_tok, + enum pragma_context) +{ + cp_token *token = NULL; + tree type = NULL_TREE, vardecl = NULL_TREE, block = NULL_TREE; + bool block_scope = false; + /* Don't create location wrapper nodes within "declare mapper" + directives. */ + auto_suppress_location_wrappers sentinel; + tree mapper_name = NULL_TREE; + tree mapper_id, id, placeholder, mapper, maplist = NULL_TREE; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + goto fail; + + if (current_function_decl) + block_scope = true; + + token = cp_lexer_peek_token (parser->lexer); + + if (cp_lexer_nth_token_is (parser->lexer, 2, CPP_COLON)) + { + switch (token->type) + { + case CPP_NAME: + { + cp_expr e = cp_parser_identifier (parser); + if (e != error_mark_node) + mapper_name = e; + else + goto fail; + } + break; + + case CPP_KEYWORD: + if (token->keyword == RID_DEFAULT) + { + mapper_name = NULL_TREE; + cp_lexer_consume_token (parser->lexer); + break; + } + /* Fallthrough. */ + + default: + cp_parser_error (parser, "expected identifier or %<default%>"); + } + + if (!cp_parser_require (parser, CPP_COLON, RT_COLON)) + goto fail; + } + + { + const char *saved_message = parser->type_definition_forbidden_message; + parser->type_definition_forbidden_message + = G_("types may not be defined within %<declare mapper%>"); + type_id_in_expr_sentinel s (parser); + type = cp_parser_type_id (parser); + parser->type_definition_forbidden_message = saved_message; + } + + if (type == error_mark_node) + goto fail; + if (dependent_type_p (type)) + mapper_id = omp_mapper_id (mapper_name, NULL_TREE); + else + mapper_id = omp_mapper_id (mapper_name, type); + + vardecl = build_lang_decl (VAR_DECL, mapper_id, type); + DECL_ARTIFICIAL (vardecl) = 1; + TREE_STATIC (vardecl) = 1; + TREE_PUBLIC (vardecl) = 0; + DECL_EXTERNAL (vardecl) = 0; + DECL_DECLARED_CONSTEXPR_P (vardecl) = 1; + DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (vardecl) = 1; + DECL_OMP_DECLARE_MAPPER_P (vardecl) = 1; + + keep_next_level (true); + block = begin_omp_structured_block (); + + if (block_scope) + DECL_CONTEXT (vardecl) = current_function_decl; + else if (current_class_type) + DECL_CONTEXT (vardecl) = current_class_type; + else + DECL_CONTEXT (vardecl) = current_namespace; + + if (processing_template_decl) + vardecl = push_template_decl (vardecl); + + if ((id = cp_parser_declarator_id (parser, false)) == error_mark_node) + goto fail; + + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + { + finish_omp_structured_block (block); + goto fail; + } + + placeholder = build_lang_decl (VAR_DECL, id, type); + DECL_CONTEXT (placeholder) = DECL_CONTEXT (vardecl); + if (processing_template_decl) + placeholder = push_template_decl (placeholder); + pushdecl (placeholder); + cp_finish_decl (placeholder, NULL_TREE, 0, NULL_TREE, 0); + DECL_ARTIFICIAL (placeholder) = 1; + TREE_USED (placeholder) = 1; + + while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)) + { + pragma_omp_clause c_kind = cp_parser_omp_clause_name (parser); + if (c_kind != PRAGMA_OMP_CLAUSE_MAP) + { + if (c_kind != PRAGMA_OMP_CLAUSE_NONE) + cp_parser_error (parser, "unexpected clause"); + finish_omp_structured_block (block); + goto fail; + } + maplist = cp_parser_omp_clause_map (parser, maplist, /*mapper=*/true); + if (maplist == NULL_TREE) + break; + } + + if (maplist == NULL_TREE) + { + cp_parser_error (parser, "missing %<map%> clause"); + finish_omp_structured_block (block); + goto fail; + } + + mapper = make_node (OMP_DECLARE_MAPPER); + TREE_TYPE (mapper) = type; + OMP_DECLARE_MAPPER_ID (mapper) = mapper_name; + OMP_DECLARE_MAPPER_DECL (mapper) = placeholder; + OMP_DECLARE_MAPPER_CLAUSES (mapper) = maplist; + + finish_omp_structured_block (block); + + DECL_INITIAL (vardecl) = mapper; + + if (current_class_type) + { + if (processing_template_decl) + { + retrofit_lang_decl (vardecl); + SET_DECL_VAR_DECLARED_INLINE_P (vardecl); + } + finish_static_data_member_decl (vardecl, mapper, + /*init_const_expr_p=*/true, NULL_TREE, 0); + finish_member_declaration (vardecl); + } + else if (processing_template_decl && block_scope) + add_decl_expr (vardecl); + else + pushdecl (vardecl); + + cp_check_omp_declare_mapper (vardecl); + + cp_parser_require_pragma_eol (parser, pragma_tok); + return; + +fail: + cp_parser_skip_to_pragma_eol (parser, pragma_tok); +} + /* OpenMP 4.0 #pragma omp declare simd declare-simd-clauses[optseq] new-line #pragma omp declare reduction (reduction-id : typename-list : expression) \ @@ -52223,6 +52507,12 @@ cp_parser_omp_declare (cp_parser *parser, cp_token *pragma_tok, context); return false; } + if (strcmp (p, "mapper") == 0) + { + cp_lexer_consume_token (parser->lexer); + cp_parser_omp_declare_mapper (parser, pragma_tok, context); + return false; + } if (!flag_openmp) /* flag_openmp_simd */ { cp_parser_skip_to_pragma_eol (parser, pragma_tok); @@ -52236,7 +52526,7 @@ cp_parser_omp_declare (cp_parser *parser, cp_token *pragma_tok, } } cp_parser_error (parser, "expected %<simd%>, %<reduction%>, " - "%<target%> or %<variant%>"); + "%<target%>, %<mapper%> or %<variant%>"); cp_parser_require_pragma_eol (parser, pragma_tok); return false; } diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index c687fdc..c5a3abe 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -15989,7 +15989,10 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain, = remove_attribute ("visibility", DECL_ATTRIBUTES (r)); } determine_visibility (r); - if ((!local_p || TREE_STATIC (t)) && DECL_SECTION_NAME (t)) + if ((!local_p || TREE_STATIC (t)) + && !(flag_openmp && DECL_LANG_SPECIFIC (t) + && DECL_OMP_DECLARE_MAPPER_P (t)) + && DECL_SECTION_NAME (t)) set_decl_section_name (r, t); } @@ -16041,6 +16044,13 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain, SET_TYPE_STRUCTURAL_EQUALITY (TREE_TYPE (r)); } + if (flag_openmp + && VAR_P (t) + && DECL_LANG_SPECIFIC (t) + && DECL_OMP_DECLARE_MAPPER_P (t) + && strchr (IDENTIFIER_POINTER (DECL_NAME (t)), '~') == NULL) + DECL_NAME (r) = omp_mapper_id (DECL_NAME (t), TREE_TYPE (r)); + layout_decl (r, 0); } break; @@ -18313,8 +18323,10 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort, } new_clauses = nreverse (new_clauses); - if (ort != C_ORT_OMP_DECLARE_SIMD) + if (ort != C_ORT_OMP_DECLARE_SIMD && ort != C_ORT_OMP_DECLARE_MAPPER) { + if (ort == C_ORT_OMP_TARGET) + new_clauses = c_omp_instantiate_mappers (new_clauses); new_clauses = finish_omp_clauses (new_clauses, ort); if (linear_no_step) for (nc = new_clauses; nc; nc = OMP_CLAUSE_CHAIN (nc)) @@ -18368,7 +18380,9 @@ tsubst_omp_context_selector (tree ctx, tree args, tsubst_flags_t complain, } } - switch (omp_ts_map[OMP_TS_CODE (sel)].tp_type) + enum omp_tp_type property_kind + = omp_ts_map[OMP_TS_CODE (sel)].tp_type; + switch (property_kind) { case OMP_TRAIT_PROPERTY_DEV_NUM_EXPR: case OMP_TRAIT_PROPERTY_BOOL_EXPR: @@ -18376,12 +18390,26 @@ tsubst_omp_context_selector (tree ctx, tree args, tsubst_flags_t complain, args, complain, in_decl); t = fold_non_dependent_expr (t); if (!value_dependent_expression_p (t) - && !type_dependent_expression_p (t) - && !INTEGRAL_TYPE_P (TREE_TYPE (t))) - error_at (cp_expr_loc_or_input_loc (t), - "property must be integer expression"); - else - properties = make_trait_property (NULL_TREE, t, NULL_TREE); + && !type_dependent_expression_p (t)) + { + if (property_kind == OMP_TRAIT_PROPERTY_BOOL_EXPR) + t = maybe_convert_cond (t); + else + { + t = convert_from_reference (t); + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error_at (cp_expr_loc_or_input_loc (t), + "property must be integer expression"); + t = error_mark_node; + } + } + } + if (t != error_mark_node + && !processing_template_decl + && TREE_CODE (t) != CLEANUP_POINT_EXPR) + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + properties = make_trait_property (NULL_TREE, t, NULL_TREE); break; case OMP_TRAIT_PROPERTY_CLAUSE_LIST: if (OMP_TS_CODE (sel) == OMP_TRAIT_CONSTRUCT_SIMD) @@ -20034,6 +20062,22 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl) break; } + case OMP_DECLARE_MAPPER: + { + t = copy_node (t); + + tree decl = OMP_DECLARE_MAPPER_DECL (t); + decl = tsubst (decl, args, complain, in_decl); + tree type = tsubst (TREE_TYPE (t), args, complain, in_decl); + tree clauses = OMP_DECLARE_MAPPER_CLAUSES (t); + clauses = tsubst_omp_clauses (clauses, C_ORT_OMP_DECLARE_MAPPER, args, + complain, in_decl); + TREE_TYPE (t) = type; + OMP_DECLARE_MAPPER_DECL (t) = decl; + OMP_DECLARE_MAPPER_CLAUSES (t) = clauses; + RETURN (t); + } + case TRANSACTION_EXPR: { int flags = 0; @@ -21093,6 +21137,23 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) RETURN (build_omp_array_section (EXPR_LOCATION (t), op0, op1, op2)); } + case OMP_DECLARE_MAPPER: + { + t = copy_node (t); + + tree decl = OMP_DECLARE_MAPPER_DECL (t); + DECL_OMP_DECLARE_MAPPER_P (decl) = 1; + decl = tsubst (decl, args, complain, in_decl); + tree type = tsubst (TREE_TYPE (t), args, complain, in_decl); + tree clauses = OMP_DECLARE_MAPPER_CLAUSES (t); + clauses = tsubst_omp_clauses (clauses, C_ORT_OMP_DECLARE_MAPPER, args, + complain, in_decl); + TREE_TYPE (t) = type; + OMP_DECLARE_MAPPER_DECL (t) = decl; + OMP_DECLARE_MAPPER_CLAUSES (t) = clauses; + RETURN (t); + } + case SIZEOF_EXPR: if (PACK_EXPANSION_P (TREE_OPERAND (t, 0)) || ARGUMENT_PACK_P (TREE_OPERAND (t, 0))) @@ -28036,7 +28097,9 @@ instantiate_decl (tree d, bool defer_ok, bool expl_inst_class_mem_p) || (external_p && VAR_P (d)) /* Handle here a deleted function too, avoid generating its body (c++/61080). */ - || deleted_p) + || deleted_p + /* We need the initializer for an OpenMP declare mapper. */ + || (VAR_P (d) && DECL_LANG_SPECIFIC (d) && DECL_OMP_DECLARE_MAPPER_P (d))) { /* The definition of the static data member is now required so we must substitute the initializer. */ diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 1279d78..7bc346b 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -45,13 +45,13 @@ along with GCC; see the file COPYING3. If not see #include "gomp-constants.h" #include "predict.h" #include "memmodel.h" +#include "gimplify.h" /* There routines provide a modular interface to perform many parsing operations. They may therefore be used during actual parsing, or during template instantiation, which may be regarded as a degenerate form of parsing. */ -static tree maybe_convert_cond (tree); static tree finalize_nrv_r (tree *, int *, void *); /* Used for OpenMP non-static data member privatization. */ @@ -1116,7 +1116,7 @@ annotate_saver::restore (tree new_inner) statement. Convert it to a boolean value, if appropriate. In addition, verify sequence points if -Wsequence-point is enabled. */ -static tree +tree maybe_convert_cond (tree cond) { /* Empty conditions remain empty. */ @@ -6740,6 +6740,97 @@ omp_reduction_lookup (location_t loc, tree id, tree type, tree *baselinkp, return id; } +/* Return identifier to look up for omp declare mapper. */ + +tree +omp_mapper_id (tree mapper_id, tree type) +{ + const char *p = NULL; + const char *m = NULL; + + if (mapper_id == NULL_TREE) + p = ""; + else if (TREE_CODE (mapper_id) == IDENTIFIER_NODE) + p = IDENTIFIER_POINTER (mapper_id); + else + return error_mark_node; + + if (type != NULL_TREE) + m = mangle_type_string (TYPE_MAIN_VARIANT (type)); + + const char prefix[] = "omp declare mapper "; + size_t lenp = sizeof (prefix); + if (strncmp (p, prefix, lenp - 1) == 0) + lenp = 1; + size_t len = strlen (p); + size_t lenm = m ? strlen (m) + 1 : 0; + char *name = XALLOCAVEC (char, lenp + len + lenm); + memcpy (name, prefix, lenp - 1); + memcpy (name + lenp - 1, p, len + 1); + if (m) + { + name[lenp + len - 1] = '~'; + memcpy (name + lenp + len, m, lenm); + } + return get_identifier (name); +} + +tree +cxx_omp_mapper_lookup (tree id, tree type) +{ + if (!RECORD_OR_UNION_TYPE_P (type)) + return NULL_TREE; + id = omp_mapper_id (id, type); + return lookup_name (id); +} + +tree +cxx_omp_extract_mapper_directive (tree vardecl) +{ + gcc_assert (TREE_CODE (vardecl) == VAR_DECL); + + /* Instantiate the decl if we haven't already. */ + mark_used (vardecl); + tree body = DECL_INITIAL (vardecl); + + if (TREE_CODE (body) == STATEMENT_LIST) + { + tree_stmt_iterator tsi = tsi_start (body); + gcc_assert (TREE_CODE (tsi_stmt (tsi)) == DECL_EXPR); + tsi_next (&tsi); + body = tsi_stmt (tsi); + } + + gcc_assert (TREE_CODE (body) == OMP_DECLARE_MAPPER); + + return body; +} + +/* For now we can handle singleton OMP_ARRAY_SECTIONs with custom mappers, but + nothing more complicated. */ + +tree +cxx_omp_map_array_section (location_t loc, tree t) +{ + tree low = TREE_OPERAND (t, 1); + tree len = TREE_OPERAND (t, 2); + + if (len && integer_onep (len)) + { + t = TREE_OPERAND (t, 0); + + if (!low) + low = integer_zero_node; + + if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE) + t = convert_from_reference (t); + + t = build_array_ref (loc, t, low); + } + + return t; +} + /* Helper function for cp_parser_omp_declare_reduction_exprs and tsubst_omp_udr. Remove CLEANUP_STMT for data (omp_priv variable). @@ -7221,6 +7312,33 @@ finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor) return false; } +/* Check an instance of an "omp declare mapper" function. */ + +bool +cp_check_omp_declare_mapper (tree udm) +{ + tree type = TREE_TYPE (udm); + location_t loc = DECL_SOURCE_LOCATION (udm); + + if (type == error_mark_node) + return false; + + if (!processing_template_decl && !RECORD_OR_UNION_TYPE_P (type)) + { + error_at (loc, "%qT is not a struct, union or class type in " + "%<#pragma omp declare mapper%>", type); + return false; + } + if (!processing_template_decl && CLASSTYPE_VBASECLASSES (type)) + { + error_at (loc, "%qT must not be a virtual base class in " + "%<#pragma omp declare mapper%>", type); + return false; + } + + return true; +} + /* Called from finish_struct_1. linear(this) or linear(this:step) clauses might not be finalized yet because the class has been incomplete when parsing #pragma omp declare simd methods. Fix those up now. */ @@ -8865,6 +8983,12 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) case OMP_CLAUSE_MAP: if (OMP_CLAUSE_MAP_IMPLICIT (c) && !implicit_moved) goto move_implicit; + if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_PUSH_MAPPER_NAME + || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POP_MAPPER_NAME) + { + remove = true; + break; + } /* FALLTHRU */ case OMP_CLAUSE_TO: case OMP_CLAUSE_FROM: @@ -10484,6 +10608,8 @@ struct omp_target_walk_data /* Local variables declared inside a BIND_EXPR, used to filter out such variables when recording lambda_objects_accessed. */ hash_set<tree> local_decls; + + omp_mapper_list<tree> *mappers; }; /* Helper function of finish_omp_target_clauses, called via @@ -10497,6 +10623,7 @@ finish_omp_target_clauses_r (tree *tp, int *walk_subtrees, void *ptr) struct omp_target_walk_data *data = (struct omp_target_walk_data *) ptr; tree current_object = data->current_object; tree current_closure = data->current_closure; + omp_mapper_list<tree> *mlist = data->mappers; /* References inside of these expression codes shouldn't incur any form of mapping, so return early. */ @@ -10510,6 +10637,27 @@ finish_omp_target_clauses_r (tree *tp, int *walk_subtrees, void *ptr) if (TREE_CODE (t) == OMP_CLAUSE) return NULL_TREE; + if (!processing_template_decl) + { + tree aggr_type = NULL_TREE; + + if (TREE_CODE (t) == COMPONENT_REF + && RECORD_OR_UNION_TYPE_P (TREE_TYPE (TREE_OPERAND (t, 0)))) + aggr_type = TREE_TYPE (TREE_OPERAND (t, 0)); + else if ((TREE_CODE (t) == VAR_DECL + || TREE_CODE (t) == PARM_DECL + || TREE_CODE (t) == RESULT_DECL) + && RECORD_OR_UNION_TYPE_P (TREE_TYPE (t))) + aggr_type = TREE_TYPE (t); + + if (aggr_type) + { + tree mapper_fn = cxx_omp_mapper_lookup (NULL_TREE, aggr_type); + if (mapper_fn) + mlist->add_mapper (NULL_TREE, aggr_type, mapper_fn); + } + } + if (current_object) { tree this_expr = TREE_OPERAND (current_object, 0); @@ -10612,10 +10760,48 @@ finish_omp_target_clauses (location_t loc, tree body, tree *clauses_ptr) else data.current_closure = NULL_TREE; - cp_walk_tree_without_duplicates (&body, finish_omp_target_clauses_r, &data); - auto_vec<tree, 16> new_clauses; + if (!processing_template_decl) + { + hash_set<omp_name_type<tree> > seen_types; + auto_vec<tree> mapper_fns; + omp_mapper_list<tree> mlist (&seen_types, &mapper_fns); + data.mappers = &mlist; + + cp_walk_tree_without_duplicates (&body, finish_omp_target_clauses_r, + &data); + + unsigned int i; + tree mapper_fn; + FOR_EACH_VEC_ELT (mapper_fns, i, mapper_fn) + c_omp_find_nested_mappers (&mlist, mapper_fn); + + FOR_EACH_VEC_ELT (mapper_fns, i, mapper_fn) + { + tree mapper = cxx_omp_extract_mapper_directive (mapper_fn); + if (mapper == error_mark_node) + continue; + tree mapper_name = OMP_DECLARE_MAPPER_ID (mapper); + tree decl = OMP_DECLARE_MAPPER_DECL (mapper); + if (BASELINK_P (mapper_fn)) + mapper_fn = BASELINK_FUNCTIONS (mapper_fn); + + tree c = build_omp_clause (loc, OMP_CLAUSE__MAPPER_BINDING_); + OMP_CLAUSE__MAPPER_BINDING__ID (c) = mapper_name; + OMP_CLAUSE__MAPPER_BINDING__DECL (c) = decl; + OMP_CLAUSE__MAPPER_BINDING__MAPPER (c) = mapper_fn; + + new_clauses.safe_push (c); + } + } + else + { + data.mappers = NULL; + cp_walk_tree_without_duplicates (&body, finish_omp_target_clauses_r, + &data); + } + tree omp_target_this_expr = NULL_TREE; tree *explicit_this_deref_map = NULL; if (data.this_expr_accessed) @@ -13233,6 +13419,7 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2) if (CLASS_TYPE_P (type1) && type_build_dtor_call (type1)) { deferring_access_check_sentinel dacs (dk_no_check); + cp_unevaluated un; tree fn = get_dtor (type1, tf_none); if (!fn && !seen_error ()) warning (0, "checking %qs for type %qT with a destructor that " |