aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog195
-rw-r--r--gcc/cp/constexpr.cc18
-rw-r--r--gcc/cp/coroutines.cc58
-rw-r--r--gcc/cp/cp-gimplify.cc27
-rw-r--r--gcc/cp/cp-objcp-common.h9
-rw-r--r--gcc/cp/cp-tree.h18
-rw-r--r--gcc/cp/decl.cc27
-rw-r--r--gcc/cp/decl2.cc9
-rw-r--r--gcc/cp/error.cc46
-rw-r--r--gcc/cp/lambda.cc28
-rw-r--r--gcc/cp/method.cc32
-rw-r--r--gcc/cp/name-lookup.h4
-rw-r--r--gcc/cp/parser.cc320
-rw-r--r--gcc/cp/pt.cc83
-rw-r--r--gcc/cp/semantics.cc195
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 "