diff options
author | Ian Lance Taylor <iant@golang.org> | 2022-02-11 15:02:44 -0800 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2022-02-11 15:02:44 -0800 |
commit | 9a510fb0970d3d9a4201bce8965cabe67850386b (patch) | |
tree | 43d7fd2bbfd7ad8c9625a718a5e8718889351994 /gcc/cp/cp-gimplify.c | |
parent | a6d3012b274f38b20e2a57162106f625746af6c6 (diff) | |
parent | 8dc2499aa62f768c6395c9754b8cabc1ce25c494 (diff) | |
download | gcc-9a510fb0970d3d9a4201bce8965cabe67850386b.zip gcc-9a510fb0970d3d9a4201bce8965cabe67850386b.tar.gz gcc-9a510fb0970d3d9a4201bce8965cabe67850386b.tar.bz2 |
Merge from trunk revision 8dc2499aa62f768c6395c9754b8cabc1ce25c494
Diffstat (limited to 'gcc/cp/cp-gimplify.c')
-rw-r--r-- | gcc/cp/cp-gimplify.c | 3105 |
1 files changed, 0 insertions, 3105 deletions
diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c deleted file mode 100644 index c86a5fe..0000000 --- a/gcc/cp/cp-gimplify.c +++ /dev/null @@ -1,3105 +0,0 @@ -/* C++-specific tree lowering bits; see also c-gimplify.c and gimple.c. - - Copyright (C) 2002-2021 Free Software Foundation, Inc. - Contributed by Jason Merrill <jason@redhat.com> - -This file is part of GCC. - -GCC is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 3, or (at your option) any later -version. - -GCC is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "target.h" -#include "basic-block.h" -#include "cp-tree.h" -#include "gimple.h" -#include "predict.h" -#include "stor-layout.h" -#include "tree-iterator.h" -#include "gimplify.h" -#include "c-family/c-ubsan.h" -#include "stringpool.h" -#include "attribs.h" -#include "asan.h" -#include "gcc-rich-location.h" -#include "memmodel.h" -#include "tm_p.h" -#include "output.h" -#include "file-prefix-map.h" -#include "cgraph.h" -#include "omp-general.h" - -/* Forward declarations. */ - -static tree cp_genericize_r (tree *, int *, void *); -static tree cp_fold_r (tree *, int *, void *); -static void cp_genericize_tree (tree*, bool); -static tree cp_fold (tree); - -/* Genericize a TRY_BLOCK. */ - -static void -genericize_try_block (tree *stmt_p) -{ - tree body = TRY_STMTS (*stmt_p); - tree cleanup = TRY_HANDLERS (*stmt_p); - - *stmt_p = build2 (TRY_CATCH_EXPR, void_type_node, body, cleanup); -} - -/* Genericize a HANDLER by converting to a CATCH_EXPR. */ - -static void -genericize_catch_block (tree *stmt_p) -{ - tree type = HANDLER_TYPE (*stmt_p); - tree body = HANDLER_BODY (*stmt_p); - - /* FIXME should the caught type go in TREE_TYPE? */ - *stmt_p = build2 (CATCH_EXPR, void_type_node, type, body); -} - -/* A terser interface for building a representation of an exception - specification. */ - -static tree -build_gimple_eh_filter_tree (tree body, tree allowed, tree failure) -{ - tree t; - - /* FIXME should the allowed types go in TREE_TYPE? */ - t = build2 (EH_FILTER_EXPR, void_type_node, allowed, NULL_TREE); - append_to_statement_list (failure, &EH_FILTER_FAILURE (t)); - - t = build2 (TRY_CATCH_EXPR, void_type_node, NULL_TREE, t); - append_to_statement_list (body, &TREE_OPERAND (t, 0)); - - return t; -} - -/* Genericize an EH_SPEC_BLOCK by converting it to a - TRY_CATCH_EXPR/EH_FILTER_EXPR pair. */ - -static void -genericize_eh_spec_block (tree *stmt_p) -{ - tree body = EH_SPEC_STMTS (*stmt_p); - tree allowed = EH_SPEC_RAISES (*stmt_p); - tree failure = build_call_n (call_unexpected_fn, 1, build_exc_ptr ()); - - *stmt_p = build_gimple_eh_filter_tree (body, allowed, failure); - suppress_warning (*stmt_p); - suppress_warning (TREE_OPERAND (*stmt_p, 1)); -} - -/* Return the first non-compound statement in STMT. */ - -tree -first_stmt (tree stmt) -{ - switch (TREE_CODE (stmt)) - { - case STATEMENT_LIST: - if (tree_statement_list_node *p = STATEMENT_LIST_HEAD (stmt)) - return first_stmt (p->stmt); - return void_node; - - case BIND_EXPR: - return first_stmt (BIND_EXPR_BODY (stmt)); - - default: - return stmt; - } -} - -/* Genericize an IF_STMT by turning it into a COND_EXPR. */ - -static void -genericize_if_stmt (tree *stmt_p) -{ - tree stmt, cond, then_, else_; - location_t locus = EXPR_LOCATION (*stmt_p); - - stmt = *stmt_p; - cond = IF_COND (stmt); - then_ = THEN_CLAUSE (stmt); - else_ = ELSE_CLAUSE (stmt); - - if (then_ && else_) - { - tree ft = first_stmt (then_); - tree fe = first_stmt (else_); - br_predictor pr; - if (TREE_CODE (ft) == PREDICT_EXPR - && TREE_CODE (fe) == PREDICT_EXPR - && (pr = PREDICT_EXPR_PREDICTOR (ft)) == PREDICT_EXPR_PREDICTOR (fe) - && (pr == PRED_HOT_LABEL || pr == PRED_COLD_LABEL)) - { - gcc_rich_location richloc (EXPR_LOC_OR_LOC (ft, locus)); - richloc.add_range (EXPR_LOC_OR_LOC (fe, locus)); - warning_at (&richloc, OPT_Wattributes, - "both branches of %<if%> statement marked as %qs", - pr == PRED_HOT_LABEL ? "likely" : "unlikely"); - } - } - - if (!then_) - then_ = build_empty_stmt (locus); - if (!else_) - else_ = build_empty_stmt (locus); - - /* consteval if has been verified not to have the then_/else_ blocks - entered by gotos/case labels from elsewhere, and as then_ block - can contain unfolded immediate function calls, we have to discard - the then_ block regardless of whether else_ has side-effects or not. */ - if (IF_STMT_CONSTEVAL_P (stmt)) - stmt = else_; - else if (integer_nonzerop (cond) && !TREE_SIDE_EFFECTS (else_)) - stmt = then_; - else if (integer_zerop (cond) && !TREE_SIDE_EFFECTS (then_)) - stmt = else_; - else - stmt = build3 (COND_EXPR, void_type_node, cond, then_, else_); - protected_set_expr_location_if_unset (stmt, locus); - *stmt_p = stmt; -} - -/* Hook into the middle of gimplifying an OMP_FOR node. */ - -static enum gimplify_status -cp_gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) -{ - tree for_stmt = *expr_p; - gimple_seq seq = NULL; - - /* Protect ourselves from recursion. */ - if (OMP_FOR_GIMPLIFYING_P (for_stmt)) - return GS_UNHANDLED; - OMP_FOR_GIMPLIFYING_P (for_stmt) = 1; - - gimplify_and_add (for_stmt, &seq); - gimple_seq_add_seq (pre_p, seq); - - OMP_FOR_GIMPLIFYING_P (for_stmt) = 0; - - return GS_ALL_DONE; -} - -/* Gimplify an EXPR_STMT node. */ - -static void -gimplify_expr_stmt (tree *stmt_p) -{ - tree stmt = EXPR_STMT_EXPR (*stmt_p); - - if (stmt == error_mark_node) - stmt = NULL; - - /* Gimplification of a statement expression will nullify the - statement if all its side effects are moved to *PRE_P and *POST_P. - - In this case we will not want to emit the gimplified statement. - However, we may still want to emit a warning, so we do that before - gimplification. */ - if (stmt && warn_unused_value) - { - if (!TREE_SIDE_EFFECTS (stmt)) - { - if (!IS_EMPTY_STMT (stmt) - && !VOID_TYPE_P (TREE_TYPE (stmt)) - && !warning_suppressed_p (stmt, OPT_Wunused_value)) - warning (OPT_Wunused_value, "statement with no effect"); - } - else - warn_if_unused_value (stmt, input_location); - } - - if (stmt == NULL_TREE) - stmt = alloc_stmt_list (); - - *stmt_p = stmt; -} - -/* Gimplify initialization from an AGGR_INIT_EXPR. */ - -static void -cp_gimplify_init_expr (tree *expr_p) -{ - tree from = TREE_OPERAND (*expr_p, 1); - tree to = TREE_OPERAND (*expr_p, 0); - tree t; - - /* What about code that pulls out the temp and uses it elsewhere? I - think that such code never uses the TARGET_EXPR as an initializer. If - I'm wrong, we'll abort because the temp won't have any RTL. In that - case, I guess we'll need to replace references somehow. */ - if (TREE_CODE (from) == TARGET_EXPR && TARGET_EXPR_INITIAL (from)) - from = TARGET_EXPR_INITIAL (from); - - /* Look through any COMPOUND_EXPRs, since build_compound_expr pushes them - inside the TARGET_EXPR. */ - for (t = from; t; ) - { - tree sub = TREE_CODE (t) == COMPOUND_EXPR ? TREE_OPERAND (t, 0) : t; - - /* If we are initializing from an AGGR_INIT_EXPR, drop the INIT_EXPR and - replace the slot operand with our target. - - Should we add a target parm to gimplify_expr instead? No, as in this - case we want to replace the INIT_EXPR. */ - if (TREE_CODE (sub) == AGGR_INIT_EXPR - || TREE_CODE (sub) == VEC_INIT_EXPR) - { - if (TREE_CODE (sub) == AGGR_INIT_EXPR) - AGGR_INIT_EXPR_SLOT (sub) = to; - else - VEC_INIT_EXPR_SLOT (sub) = to; - *expr_p = from; - - /* The initialization is now a side-effect, so the container can - become void. */ - if (from != sub) - TREE_TYPE (from) = void_type_node; - } - - /* Handle aggregate NSDMI. */ - replace_placeholders (sub, to); - - if (t == sub) - break; - else - t = TREE_OPERAND (t, 1); - } - -} - -/* Gimplify a MUST_NOT_THROW_EXPR. */ - -static enum gimplify_status -gimplify_must_not_throw_expr (tree *expr_p, gimple_seq *pre_p) -{ - tree stmt = *expr_p; - tree temp = voidify_wrapper_expr (stmt, NULL); - tree body = TREE_OPERAND (stmt, 0); - gimple_seq try_ = NULL; - gimple_seq catch_ = NULL; - gimple *mnt; - - gimplify_and_add (body, &try_); - mnt = gimple_build_eh_must_not_throw (terminate_fn); - gimple_seq_add_stmt_without_update (&catch_, mnt); - mnt = gimple_build_try (try_, catch_, GIMPLE_TRY_CATCH); - - gimple_seq_add_stmt_without_update (pre_p, mnt); - if (temp) - { - *expr_p = temp; - return GS_OK; - } - - *expr_p = NULL; - return GS_ALL_DONE; -} - -/* Return TRUE if an operand (OP) of a given TYPE being copied is - really just an empty class copy. - - Check that the operand has a simple form so that TARGET_EXPRs and - non-empty CONSTRUCTORs get reduced properly, and we leave the - return slot optimization alone because it isn't a copy. */ - -bool -simple_empty_class_p (tree type, tree op, tree_code code) -{ - if (TREE_CODE (op) == COMPOUND_EXPR) - return simple_empty_class_p (type, TREE_OPERAND (op, 1), code); - if (SIMPLE_TARGET_EXPR_P (op) - && TYPE_HAS_TRIVIAL_DESTRUCTOR (type)) - /* The TARGET_EXPR is itself a simple copy, look through it. */ - return simple_empty_class_p (type, TARGET_EXPR_INITIAL (op), code); - - if (TREE_CODE (op) == PARM_DECL - && TREE_ADDRESSABLE (TREE_TYPE (op))) - { - tree fn = DECL_CONTEXT (op); - if (DECL_THUNK_P (fn) - || lambda_static_thunk_p (fn)) - /* In a thunk, we pass through invisible reference parms, so this isn't - actually a copy. */ - return false; - } - - return - (TREE_CODE (op) == EMPTY_CLASS_EXPR - || code == MODIFY_EXPR - || is_gimple_lvalue (op) - || INDIRECT_REF_P (op) - || (TREE_CODE (op) == CONSTRUCTOR - && CONSTRUCTOR_NELTS (op) == 0) - || (TREE_CODE (op) == CALL_EXPR - && !CALL_EXPR_RETURN_SLOT_OPT (op))) - && !TREE_CLOBBER_P (op) - && is_really_empty_class (type, /*ignore_vptr*/true); -} - -/* Returns true if evaluating E as an lvalue has side-effects; - specifically, a volatile lvalue has TREE_SIDE_EFFECTS, but it doesn't really - have side-effects until there is a read or write through it. */ - -static bool -lvalue_has_side_effects (tree e) -{ - if (!TREE_SIDE_EFFECTS (e)) - return false; - while (handled_component_p (e)) - { - if (TREE_CODE (e) == ARRAY_REF - && TREE_SIDE_EFFECTS (TREE_OPERAND (e, 1))) - return true; - e = TREE_OPERAND (e, 0); - } - if (DECL_P (e)) - /* Just naming a variable has no side-effects. */ - return false; - else if (INDIRECT_REF_P (e)) - /* Similarly, indirection has no side-effects. */ - return TREE_SIDE_EFFECTS (TREE_OPERAND (e, 0)); - else - /* For anything else, trust TREE_SIDE_EFFECTS. */ - return TREE_SIDE_EFFECTS (e); -} - -/* Gimplify *EXPR_P as rvalue into an expression that can't be modified - by expressions with side-effects in other operands. */ - -static enum gimplify_status -gimplify_to_rvalue (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, - bool (*gimple_test_f) (tree)) -{ - enum gimplify_status t - = gimplify_expr (expr_p, pre_p, post_p, gimple_test_f, fb_rvalue); - if (t == GS_ERROR) - return GS_ERROR; - else if (is_gimple_variable (*expr_p) && TREE_CODE (*expr_p) != SSA_NAME) - *expr_p = get_initialized_tmp_var (*expr_p, pre_p); - return t; -} - -/* Do C++-specific gimplification. Args are as for gimplify_expr. */ - -int -cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) -{ - int saved_stmts_are_full_exprs_p = 0; - location_t loc = cp_expr_loc_or_input_loc (*expr_p); - enum tree_code code = TREE_CODE (*expr_p); - enum gimplify_status ret; - - if (STATEMENT_CODE_P (code)) - { - saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p (); - current_stmt_tree ()->stmts_are_full_exprs_p - = STMT_IS_FULL_EXPR_P (*expr_p); - } - - switch (code) - { - case AGGR_INIT_EXPR: - simplify_aggr_init_expr (expr_p); - ret = GS_OK; - break; - - case VEC_INIT_EXPR: - { - location_t loc = input_location; - tree init = VEC_INIT_EXPR_INIT (*expr_p); - int from_array = (init && TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE); - gcc_assert (EXPR_HAS_LOCATION (*expr_p)); - input_location = EXPR_LOCATION (*expr_p); - *expr_p = build_vec_init (VEC_INIT_EXPR_SLOT (*expr_p), NULL_TREE, - init, VEC_INIT_EXPR_VALUE_INIT (*expr_p), - from_array, - tf_warning_or_error); - hash_set<tree> pset; - cp_walk_tree (expr_p, cp_fold_r, &pset, NULL); - cp_genericize_tree (expr_p, false); - copy_if_shared (expr_p); - ret = GS_OK; - input_location = loc; - } - break; - - case THROW_EXPR: - /* FIXME communicate throw type to back end, probably by moving - THROW_EXPR into ../tree.def. */ - *expr_p = TREE_OPERAND (*expr_p, 0); - ret = GS_OK; - break; - - case MUST_NOT_THROW_EXPR: - ret = gimplify_must_not_throw_expr (expr_p, pre_p); - break; - - /* We used to do this for MODIFY_EXPR as well, but that's unsafe; the - LHS of an assignment might also be involved in the RHS, as in bug - 25979. */ - case INIT_EXPR: - cp_gimplify_init_expr (expr_p); - if (TREE_CODE (*expr_p) != INIT_EXPR) - return GS_OK; - /* Fall through. */ - case MODIFY_EXPR: - modify_expr_case: - { - /* If the back end isn't clever enough to know that the lhs and rhs - types are the same, add an explicit conversion. */ - tree op0 = TREE_OPERAND (*expr_p, 0); - tree op1 = TREE_OPERAND (*expr_p, 1); - - if (!error_operand_p (op0) - && !error_operand_p (op1) - && (TYPE_STRUCTURAL_EQUALITY_P (TREE_TYPE (op0)) - || TYPE_STRUCTURAL_EQUALITY_P (TREE_TYPE (op1))) - && !useless_type_conversion_p (TREE_TYPE (op1), TREE_TYPE (op0))) - TREE_OPERAND (*expr_p, 1) = build1 (VIEW_CONVERT_EXPR, - TREE_TYPE (op0), op1); - - else if (simple_empty_class_p (TREE_TYPE (op0), op1, code)) - { - while (TREE_CODE (op1) == TARGET_EXPR) - /* We're disconnecting the initializer from its target, - don't create a temporary. */ - op1 = TARGET_EXPR_INITIAL (op1); - - /* Remove any copies of empty classes. Also drop volatile - variables on the RHS to avoid infinite recursion from - gimplify_expr trying to load the value. */ - if (TREE_SIDE_EFFECTS (op1)) - { - if (TREE_THIS_VOLATILE (op1) - && (REFERENCE_CLASS_P (op1) || DECL_P (op1))) - op1 = build_fold_addr_expr (op1); - - gimplify_and_add (op1, pre_p); - } - gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, - is_gimple_lvalue, fb_lvalue); - *expr_p = TREE_OPERAND (*expr_p, 0); - if (code == RETURN_EXPR && REFERENCE_CLASS_P (*expr_p)) - /* Avoid 'return *<retval>;' */ - *expr_p = TREE_OPERAND (*expr_p, 0); - } - /* P0145 says that the RHS is sequenced before the LHS. - gimplify_modify_expr gimplifies the RHS before the LHS, but that - isn't quite strong enough in two cases: - - 1) gimplify.c wants to leave a CALL_EXPR on the RHS, which would - mean it's evaluated after the LHS. - - 2) the value calculation of the RHS is also sequenced before the - LHS, so for scalar assignment we need to preevaluate if the - RHS could be affected by LHS side-effects even if it has no - side-effects of its own. We don't need this for classes because - class assignment takes its RHS by reference. */ - else if (flag_strong_eval_order > 1 - && TREE_CODE (*expr_p) == MODIFY_EXPR - && lvalue_has_side_effects (op0) - && (TREE_CODE (op1) == CALL_EXPR - || (SCALAR_TYPE_P (TREE_TYPE (op1)) - && !TREE_CONSTANT (op1)))) - TREE_OPERAND (*expr_p, 1) = get_initialized_tmp_var (op1, pre_p); - } - ret = GS_OK; - break; - - case EMPTY_CLASS_EXPR: - /* We create an empty CONSTRUCTOR with RECORD_TYPE. */ - *expr_p = build_constructor (TREE_TYPE (*expr_p), NULL); - ret = GS_OK; - break; - - case BASELINK: - *expr_p = BASELINK_FUNCTIONS (*expr_p); - ret = GS_OK; - break; - - case TRY_BLOCK: - genericize_try_block (expr_p); - ret = GS_OK; - break; - - case HANDLER: - genericize_catch_block (expr_p); - ret = GS_OK; - break; - - case EH_SPEC_BLOCK: - genericize_eh_spec_block (expr_p); - ret = GS_OK; - break; - - case USING_STMT: - gcc_unreachable (); - - case FOR_STMT: - case WHILE_STMT: - case DO_STMT: - case SWITCH_STMT: - case CONTINUE_STMT: - case BREAK_STMT: - gcc_unreachable (); - - case OMP_FOR: - case OMP_SIMD: - case OMP_DISTRIBUTE: - case OMP_LOOP: - case OMP_TASKLOOP: - ret = cp_gimplify_omp_for (expr_p, pre_p); - break; - - case EXPR_STMT: - gimplify_expr_stmt (expr_p); - ret = GS_OK; - break; - - case UNARY_PLUS_EXPR: - { - tree arg = TREE_OPERAND (*expr_p, 0); - tree type = TREE_TYPE (*expr_p); - *expr_p = (TREE_TYPE (arg) != type) ? fold_convert (type, arg) - : arg; - ret = GS_OK; - } - break; - - case CALL_EXPR: - ret = GS_OK; - if (flag_strong_eval_order == 2 - && CALL_EXPR_FN (*expr_p) - && !CALL_EXPR_OPERATOR_SYNTAX (*expr_p) - && cp_get_callee_fndecl_nofold (*expr_p) == NULL_TREE) - { - tree fnptrtype = TREE_TYPE (CALL_EXPR_FN (*expr_p)); - enum gimplify_status t - = gimplify_to_rvalue (&CALL_EXPR_FN (*expr_p), pre_p, NULL, - is_gimple_call_addr); - if (t == GS_ERROR) - ret = GS_ERROR; - /* GIMPLE considers most pointer conversion useless, but for - calls we actually care about the exact function pointer type. */ - else if (TREE_TYPE (CALL_EXPR_FN (*expr_p)) != fnptrtype) - CALL_EXPR_FN (*expr_p) - = build1 (NOP_EXPR, fnptrtype, CALL_EXPR_FN (*expr_p)); - } - if (!CALL_EXPR_FN (*expr_p)) - /* Internal function call. */; - else if (CALL_EXPR_REVERSE_ARGS (*expr_p)) - { - /* This is a call to a (compound) assignment operator that used - the operator syntax; gimplify the RHS first. */ - gcc_assert (call_expr_nargs (*expr_p) == 2); - gcc_assert (!CALL_EXPR_ORDERED_ARGS (*expr_p)); - enum gimplify_status t - = gimplify_arg (&CALL_EXPR_ARG (*expr_p, 1), pre_p, loc); - if (t == GS_ERROR) - ret = GS_ERROR; - } - else if (CALL_EXPR_ORDERED_ARGS (*expr_p)) - { - /* Leave the last argument for gimplify_call_expr, to avoid problems - with __builtin_va_arg_pack(). */ - int nargs = call_expr_nargs (*expr_p) - 1; - for (int i = 0; i < nargs; ++i) - { - enum gimplify_status t - = gimplify_arg (&CALL_EXPR_ARG (*expr_p, i), pre_p, loc); - if (t == GS_ERROR) - ret = GS_ERROR; - } - } - else if (flag_strong_eval_order - && !CALL_EXPR_OPERATOR_SYNTAX (*expr_p)) - { - /* If flag_strong_eval_order, evaluate the object argument first. */ - tree fntype = TREE_TYPE (CALL_EXPR_FN (*expr_p)); - if (INDIRECT_TYPE_P (fntype)) - fntype = TREE_TYPE (fntype); - if (TREE_CODE (fntype) == METHOD_TYPE) - { - enum gimplify_status t - = gimplify_arg (&CALL_EXPR_ARG (*expr_p, 0), pre_p, loc); - if (t == GS_ERROR) - ret = GS_ERROR; - } - } - if (ret != GS_ERROR) - { - tree decl = cp_get_callee_fndecl_nofold (*expr_p); - if (decl && fndecl_built_in_p (decl, BUILT_IN_FRONTEND)) - switch (DECL_FE_FUNCTION_CODE (decl)) - { - case CP_BUILT_IN_IS_CONSTANT_EVALUATED: - *expr_p = boolean_false_node; - break; - case CP_BUILT_IN_SOURCE_LOCATION: - *expr_p - = fold_builtin_source_location (EXPR_LOCATION (*expr_p)); - break; - case CP_BUILT_IN_IS_CORRESPONDING_MEMBER: - *expr_p - = fold_builtin_is_corresponding_member - (EXPR_LOCATION (*expr_p), call_expr_nargs (*expr_p), - &CALL_EXPR_ARG (*expr_p, 0)); - break; - case CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS: - *expr_p - = fold_builtin_is_pointer_inverconvertible_with_class - (EXPR_LOCATION (*expr_p), call_expr_nargs (*expr_p), - &CALL_EXPR_ARG (*expr_p, 0)); - break; - default: - break; - } - } - break; - - case TARGET_EXPR: - /* A TARGET_EXPR that expresses direct-initialization should have been - elided by cp_gimplify_init_expr. */ - gcc_checking_assert (!TARGET_EXPR_DIRECT_INIT_P (*expr_p)); - ret = GS_UNHANDLED; - break; - - case PTRMEM_CST: - *expr_p = cplus_expand_constant (*expr_p); - if (TREE_CODE (*expr_p) == PTRMEM_CST) - ret = GS_ERROR; - else - ret = GS_OK; - break; - - case RETURN_EXPR: - if (TREE_OPERAND (*expr_p, 0) - && (TREE_CODE (TREE_OPERAND (*expr_p, 0)) == INIT_EXPR - || TREE_CODE (TREE_OPERAND (*expr_p, 0)) == MODIFY_EXPR)) - { - expr_p = &TREE_OPERAND (*expr_p, 0); - /* Avoid going through the INIT_EXPR case, which can - degrade INIT_EXPRs into AGGR_INIT_EXPRs. */ - goto modify_expr_case; - } - /* Fall through. */ - - default: - ret = (enum gimplify_status) c_gimplify_expr (expr_p, pre_p, post_p); - break; - } - - /* Restore saved state. */ - if (STATEMENT_CODE_P (code)) - current_stmt_tree ()->stmts_are_full_exprs_p - = saved_stmts_are_full_exprs_p; - - return ret; -} - -static inline bool -is_invisiref_parm (const_tree t) -{ - return ((TREE_CODE (t) == PARM_DECL || TREE_CODE (t) == RESULT_DECL) - && DECL_BY_REFERENCE (t)); -} - -/* A stable comparison routine for use with splay trees and DECLs. */ - -static int -splay_tree_compare_decl_uid (splay_tree_key xa, splay_tree_key xb) -{ - tree a = (tree) xa; - tree b = (tree) xb; - - return DECL_UID (a) - DECL_UID (b); -} - -/* OpenMP context during genericization. */ - -struct cp_genericize_omp_taskreg -{ - bool is_parallel; - bool default_shared; - struct cp_genericize_omp_taskreg *outer; - splay_tree variables; -}; - -/* Return true if genericization should try to determine if - DECL is firstprivate or shared within task regions. */ - -static bool -omp_var_to_track (tree decl) -{ - tree type = TREE_TYPE (decl); - if (is_invisiref_parm (decl)) - type = TREE_TYPE (type); - else if (TYPE_REF_P (type)) - type = TREE_TYPE (type); - while (TREE_CODE (type) == ARRAY_TYPE) - type = TREE_TYPE (type); - if (type == error_mark_node || !CLASS_TYPE_P (type)) - return false; - if (VAR_P (decl) && CP_DECL_THREAD_LOCAL_P (decl)) - return false; - if (cxx_omp_predetermined_sharing (decl) != OMP_CLAUSE_DEFAULT_UNSPECIFIED) - return false; - return true; -} - -/* Note DECL use in OpenMP region OMP_CTX during genericization. */ - -static void -omp_cxx_notice_variable (struct cp_genericize_omp_taskreg *omp_ctx, tree decl) -{ - splay_tree_node n = splay_tree_lookup (omp_ctx->variables, - (splay_tree_key) decl); - if (n == NULL) - { - int flags = OMP_CLAUSE_DEFAULT_SHARED; - if (omp_ctx->outer) - omp_cxx_notice_variable (omp_ctx->outer, decl); - if (!omp_ctx->default_shared) - { - struct cp_genericize_omp_taskreg *octx; - - for (octx = omp_ctx->outer; octx; octx = octx->outer) - { - n = splay_tree_lookup (octx->variables, (splay_tree_key) decl); - if (n && n->value != OMP_CLAUSE_DEFAULT_SHARED) - { - flags = OMP_CLAUSE_DEFAULT_FIRSTPRIVATE; - break; - } - if (octx->is_parallel) - break; - } - if (octx == NULL - && (TREE_CODE (decl) == PARM_DECL - || (!(TREE_STATIC (decl) || DECL_EXTERNAL (decl)) - && DECL_CONTEXT (decl) == current_function_decl))) - flags = OMP_CLAUSE_DEFAULT_FIRSTPRIVATE; - if (flags == OMP_CLAUSE_DEFAULT_FIRSTPRIVATE) - { - /* DECL is implicitly determined firstprivate in - the current task construct. Ensure copy ctor and - dtor are instantiated, because during gimplification - it will be already too late. */ - tree type = TREE_TYPE (decl); - if (is_invisiref_parm (decl)) - type = TREE_TYPE (type); - else if (TYPE_REF_P (type)) - type = TREE_TYPE (type); - while (TREE_CODE (type) == ARRAY_TYPE) - type = TREE_TYPE (type); - get_copy_ctor (type, tf_none); - get_dtor (type, tf_none); - } - } - splay_tree_insert (omp_ctx->variables, (splay_tree_key) decl, flags); - } -} - -/* Genericization context. */ - -struct cp_genericize_data -{ - hash_set<tree> *p_set; - auto_vec<tree> bind_expr_stack; - struct cp_genericize_omp_taskreg *omp_ctx; - tree try_block; - bool no_sanitize_p; - bool handle_invisiref_parm_p; -}; - -/* Perform any pre-gimplification folding of C++ front end trees to - GENERIC. - Note: The folding of none-omp cases is something to move into - the middle-end. As for now we have most foldings only on GENERIC - in fold-const, we need to perform this before transformation to - GIMPLE-form. */ - -static tree -cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data) -{ - tree stmt; - enum tree_code code; - - *stmt_p = stmt = cp_fold (*stmt_p); - - if (((hash_set<tree> *) data)->add (stmt)) - { - /* Don't walk subtrees of stmts we've already walked once, otherwise - we can have exponential complexity with e.g. lots of nested - SAVE_EXPRs or TARGET_EXPRs. cp_fold uses a cache and will return - always the same tree, which the first time cp_fold_r has been - called on it had the subtrees walked. */ - *walk_subtrees = 0; - return NULL; - } - - code = TREE_CODE (stmt); - if (code == OMP_FOR || code == OMP_SIMD || code == OMP_DISTRIBUTE - || code == OMP_LOOP || code == OMP_TASKLOOP || code == OACC_LOOP) - { - tree x; - int i, n; - - cp_walk_tree (&OMP_FOR_BODY (stmt), cp_fold_r, data, NULL); - cp_walk_tree (&OMP_FOR_CLAUSES (stmt), cp_fold_r, data, NULL); - cp_walk_tree (&OMP_FOR_INIT (stmt), cp_fold_r, data, NULL); - x = OMP_FOR_COND (stmt); - if (x && TREE_CODE_CLASS (TREE_CODE (x)) == tcc_comparison) - { - cp_walk_tree (&TREE_OPERAND (x, 0), cp_fold_r, data, NULL); - cp_walk_tree (&TREE_OPERAND (x, 1), cp_fold_r, data, NULL); - } - else if (x && TREE_CODE (x) == TREE_VEC) - { - n = TREE_VEC_LENGTH (x); - for (i = 0; i < n; i++) - { - tree o = TREE_VEC_ELT (x, i); - if (o && TREE_CODE_CLASS (TREE_CODE (o)) == tcc_comparison) - cp_walk_tree (&TREE_OPERAND (o, 1), cp_fold_r, data, NULL); - } - } - x = OMP_FOR_INCR (stmt); - if (x && TREE_CODE (x) == TREE_VEC) - { - n = TREE_VEC_LENGTH (x); - for (i = 0; i < n; i++) - { - tree o = TREE_VEC_ELT (x, i); - if (o && TREE_CODE (o) == MODIFY_EXPR) - o = TREE_OPERAND (o, 1); - if (o && (TREE_CODE (o) == PLUS_EXPR || TREE_CODE (o) == MINUS_EXPR - || TREE_CODE (o) == POINTER_PLUS_EXPR)) - { - cp_walk_tree (&TREE_OPERAND (o, 0), cp_fold_r, data, NULL); - cp_walk_tree (&TREE_OPERAND (o, 1), cp_fold_r, data, NULL); - } - } - } - cp_walk_tree (&OMP_FOR_PRE_BODY (stmt), cp_fold_r, data, NULL); - *walk_subtrees = 0; - } - - return NULL; -} - -/* Fold ALL the trees! FIXME we should be able to remove this, but - apparently that still causes optimization regressions. */ - -void -cp_fold_function (tree fndecl) -{ - hash_set<tree> pset; - cp_walk_tree (&DECL_SAVED_TREE (fndecl), cp_fold_r, &pset, NULL); -} - -/* Turn SPACESHIP_EXPR EXPR into GENERIC. */ - -static tree genericize_spaceship (tree expr) -{ - iloc_sentinel s (cp_expr_location (expr)); - tree type = TREE_TYPE (expr); - tree op0 = TREE_OPERAND (expr, 0); - tree op1 = TREE_OPERAND (expr, 1); - return genericize_spaceship (input_location, type, op0, op1); -} - -/* If EXPR involves an anonymous VLA type, prepend a DECL_EXPR for that type - to trigger gimplify_type_sizes; otherwise a cast to pointer-to-VLA confuses - the middle-end (c++/88256). If EXPR is a DECL, use add_stmt and return - NULL_TREE; otherwise return a COMPOUND_STMT of the DECL_EXPR and EXPR. */ - -tree -predeclare_vla (tree expr) -{ - tree type = TREE_TYPE (expr); - if (type == error_mark_node) - return expr; - if (is_typedef_decl (expr)) - type = DECL_ORIGINAL_TYPE (expr); - - /* We need to strip pointers for gimplify_type_sizes. */ - tree vla = type; - while (POINTER_TYPE_P (vla)) - { - if (TYPE_NAME (vla)) - return expr; - vla = TREE_TYPE (vla); - } - if (vla == type || TYPE_NAME (vla) - || !variably_modified_type_p (vla, NULL_TREE)) - return expr; - - tree decl = build_decl (input_location, TYPE_DECL, NULL_TREE, vla); - DECL_ARTIFICIAL (decl) = 1; - TYPE_NAME (vla) = decl; - tree dexp = build_stmt (input_location, DECL_EXPR, decl); - if (DECL_P (expr)) - { - add_stmt (dexp); - return NULL_TREE; - } - else - { - expr = build2 (COMPOUND_EXPR, type, dexp, expr); - return expr; - } -} - -/* Perform any pre-gimplification lowering of C++ front end trees to - GENERIC. */ - -static tree -cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) -{ - tree stmt = *stmt_p; - struct cp_genericize_data *wtd = (struct cp_genericize_data *) data; - hash_set<tree> *p_set = wtd->p_set; - - /* If in an OpenMP context, note var uses. */ - if (__builtin_expect (wtd->omp_ctx != NULL, 0) - && (VAR_P (stmt) - || TREE_CODE (stmt) == PARM_DECL - || TREE_CODE (stmt) == RESULT_DECL) - && omp_var_to_track (stmt)) - omp_cxx_notice_variable (wtd->omp_ctx, stmt); - - /* Don't dereference parms in a thunk, pass the references through. */ - if ((TREE_CODE (stmt) == CALL_EXPR && call_from_lambda_thunk_p (stmt)) - || (TREE_CODE (stmt) == AGGR_INIT_EXPR && AGGR_INIT_FROM_THUNK_P (stmt))) - { - *walk_subtrees = 0; - return NULL; - } - - /* Dereference invisible reference parms. */ - if (wtd->handle_invisiref_parm_p && is_invisiref_parm (stmt)) - { - *stmt_p = convert_from_reference (stmt); - p_set->add (*stmt_p); - *walk_subtrees = 0; - return NULL; - } - - /* Map block scope extern declarations to visible declarations with the - same name and type in outer scopes if any. */ - if (VAR_OR_FUNCTION_DECL_P (stmt) && DECL_LOCAL_DECL_P (stmt)) - if (tree alias = DECL_LOCAL_DECL_ALIAS (stmt)) - { - if (alias != error_mark_node) - { - *stmt_p = alias; - TREE_USED (alias) |= TREE_USED (stmt); - } - *walk_subtrees = 0; - return NULL; - } - - if (TREE_CODE (stmt) == INTEGER_CST - && TYPE_REF_P (TREE_TYPE (stmt)) - && (flag_sanitize & (SANITIZE_NULL | SANITIZE_ALIGNMENT)) - && !wtd->no_sanitize_p) - { - ubsan_maybe_instrument_reference (stmt_p); - if (*stmt_p != stmt) - { - *walk_subtrees = 0; - return NULL_TREE; - } - } - - /* Other than invisiref parms, don't walk the same tree twice. */ - if (p_set->contains (stmt)) - { - *walk_subtrees = 0; - return NULL_TREE; - } - - switch (TREE_CODE (stmt)) - { - case ADDR_EXPR: - if (is_invisiref_parm (TREE_OPERAND (stmt, 0))) - { - /* If in an OpenMP context, note var uses. */ - if (__builtin_expect (wtd->omp_ctx != NULL, 0) - && omp_var_to_track (TREE_OPERAND (stmt, 0))) - omp_cxx_notice_variable (wtd->omp_ctx, TREE_OPERAND (stmt, 0)); - *stmt_p = fold_convert (TREE_TYPE (stmt), TREE_OPERAND (stmt, 0)); - *walk_subtrees = 0; - } - break; - - case RETURN_EXPR: - if (TREE_OPERAND (stmt, 0) && is_invisiref_parm (TREE_OPERAND (stmt, 0))) - /* Don't dereference an invisiref RESULT_DECL inside a RETURN_EXPR. */ - *walk_subtrees = 0; - break; - - case OMP_CLAUSE: - switch (OMP_CLAUSE_CODE (stmt)) - { - case OMP_CLAUSE_LASTPRIVATE: - /* Don't dereference an invisiref in OpenMP clauses. */ - if (is_invisiref_parm (OMP_CLAUSE_DECL (stmt))) - { - *walk_subtrees = 0; - if (OMP_CLAUSE_LASTPRIVATE_STMT (stmt)) - cp_walk_tree (&OMP_CLAUSE_LASTPRIVATE_STMT (stmt), - cp_genericize_r, data, NULL); - } - break; - case OMP_CLAUSE_PRIVATE: - /* Don't dereference an invisiref in OpenMP clauses. */ - if (is_invisiref_parm (OMP_CLAUSE_DECL (stmt))) - *walk_subtrees = 0; - else if (wtd->omp_ctx != NULL) - { - /* Private clause doesn't cause any references to the - var in outer contexts, avoid calling - omp_cxx_notice_variable for it. */ - struct cp_genericize_omp_taskreg *old = wtd->omp_ctx; - wtd->omp_ctx = NULL; - cp_walk_tree (&OMP_CLAUSE_DECL (stmt), cp_genericize_r, - data, NULL); - wtd->omp_ctx = old; - *walk_subtrees = 0; - } - break; - case OMP_CLAUSE_SHARED: - case OMP_CLAUSE_FIRSTPRIVATE: - case OMP_CLAUSE_COPYIN: - case OMP_CLAUSE_COPYPRIVATE: - case OMP_CLAUSE_INCLUSIVE: - case OMP_CLAUSE_EXCLUSIVE: - /* Don't dereference an invisiref in OpenMP clauses. */ - if (is_invisiref_parm (OMP_CLAUSE_DECL (stmt))) - *walk_subtrees = 0; - break; - case OMP_CLAUSE_REDUCTION: - case OMP_CLAUSE_IN_REDUCTION: - case OMP_CLAUSE_TASK_REDUCTION: - /* Don't dereference an invisiref in reduction clause's - OMP_CLAUSE_DECL either. OMP_CLAUSE_REDUCTION_{INIT,MERGE} - still needs to be genericized. */ - if (is_invisiref_parm (OMP_CLAUSE_DECL (stmt))) - { - *walk_subtrees = 0; - if (OMP_CLAUSE_REDUCTION_INIT (stmt)) - cp_walk_tree (&OMP_CLAUSE_REDUCTION_INIT (stmt), - cp_genericize_r, data, NULL); - if (OMP_CLAUSE_REDUCTION_MERGE (stmt)) - cp_walk_tree (&OMP_CLAUSE_REDUCTION_MERGE (stmt), - cp_genericize_r, data, NULL); - } - break; - default: - break; - } - break; - - /* Due to the way voidify_wrapper_expr is written, we don't get a chance - to lower this construct before scanning it, so we need to lower these - before doing anything else. */ - case CLEANUP_STMT: - *stmt_p = build2_loc (EXPR_LOCATION (stmt), - CLEANUP_EH_ONLY (stmt) ? TRY_CATCH_EXPR - : TRY_FINALLY_EXPR, - void_type_node, - CLEANUP_BODY (stmt), - CLEANUP_EXPR (stmt)); - break; - - case IF_STMT: - genericize_if_stmt (stmt_p); - /* *stmt_p has changed, tail recurse to handle it again. */ - return cp_genericize_r (stmt_p, walk_subtrees, data); - - /* COND_EXPR might have incompatible types in branches if one or both - arms are bitfields. Fix it up now. */ - case COND_EXPR: - { - tree type_left - = (TREE_OPERAND (stmt, 1) - ? is_bitfield_expr_with_lowered_type (TREE_OPERAND (stmt, 1)) - : NULL_TREE); - tree type_right - = (TREE_OPERAND (stmt, 2) - ? is_bitfield_expr_with_lowered_type (TREE_OPERAND (stmt, 2)) - : NULL_TREE); - if (type_left - && !useless_type_conversion_p (TREE_TYPE (stmt), - TREE_TYPE (TREE_OPERAND (stmt, 1)))) - { - TREE_OPERAND (stmt, 1) - = fold_convert (type_left, TREE_OPERAND (stmt, 1)); - gcc_assert (useless_type_conversion_p (TREE_TYPE (stmt), - type_left)); - } - if (type_right - && !useless_type_conversion_p (TREE_TYPE (stmt), - TREE_TYPE (TREE_OPERAND (stmt, 2)))) - { - TREE_OPERAND (stmt, 2) - = fold_convert (type_right, TREE_OPERAND (stmt, 2)); - gcc_assert (useless_type_conversion_p (TREE_TYPE (stmt), - type_right)); - } - } - break; - - case BIND_EXPR: - if (__builtin_expect (wtd->omp_ctx != NULL, 0)) - { - tree decl; - for (decl = BIND_EXPR_VARS (stmt); decl; decl = DECL_CHAIN (decl)) - if (VAR_P (decl) - && !DECL_EXTERNAL (decl) - && omp_var_to_track (decl)) - { - splay_tree_node n - = splay_tree_lookup (wtd->omp_ctx->variables, - (splay_tree_key) decl); - if (n == NULL) - splay_tree_insert (wtd->omp_ctx->variables, - (splay_tree_key) decl, - TREE_STATIC (decl) - ? OMP_CLAUSE_DEFAULT_SHARED - : OMP_CLAUSE_DEFAULT_PRIVATE); - } - } - if (sanitize_flags_p (SANITIZE_NULL | SANITIZE_ALIGNMENT | SANITIZE_VPTR)) - { - /* The point here is to not sanitize static initializers. */ - bool no_sanitize_p = wtd->no_sanitize_p; - wtd->no_sanitize_p = true; - for (tree decl = BIND_EXPR_VARS (stmt); - decl; - decl = DECL_CHAIN (decl)) - if (VAR_P (decl) - && TREE_STATIC (decl) - && DECL_INITIAL (decl)) - cp_walk_tree (&DECL_INITIAL (decl), cp_genericize_r, data, NULL); - wtd->no_sanitize_p = no_sanitize_p; - } - wtd->bind_expr_stack.safe_push (stmt); - cp_walk_tree (&BIND_EXPR_BODY (stmt), - cp_genericize_r, data, NULL); - wtd->bind_expr_stack.pop (); - break; - - case USING_STMT: - { - tree block = NULL_TREE; - - /* Get the innermost inclosing GIMPLE_BIND that has a non NULL - BLOCK, and append an IMPORTED_DECL to its - BLOCK_VARS chained list. */ - if (wtd->bind_expr_stack.exists ()) - { - int i; - for (i = wtd->bind_expr_stack.length () - 1; i >= 0; i--) - if ((block = BIND_EXPR_BLOCK (wtd->bind_expr_stack[i]))) - break; - } - if (block) - { - tree decl = TREE_OPERAND (stmt, 0); - gcc_assert (decl); - - if (undeduced_auto_decl (decl)) - /* Omit from the GENERIC, the back-end can't handle it. */; - else - { - tree using_directive = make_node (IMPORTED_DECL); - TREE_TYPE (using_directive) = void_type_node; - DECL_CONTEXT (using_directive) = current_function_decl; - - IMPORTED_DECL_ASSOCIATED_DECL (using_directive) = decl; - DECL_CHAIN (using_directive) = BLOCK_VARS (block); - BLOCK_VARS (block) = using_directive; - } - } - /* The USING_STMT won't appear in GENERIC. */ - *stmt_p = build1 (NOP_EXPR, void_type_node, integer_zero_node); - *walk_subtrees = 0; - } - break; - - case DECL_EXPR: - if (TREE_CODE (DECL_EXPR_DECL (stmt)) == USING_DECL) - { - /* Using decls inside DECL_EXPRs are just dropped on the floor. */ - *stmt_p = build1 (NOP_EXPR, void_type_node, integer_zero_node); - *walk_subtrees = 0; - } - else - { - tree d = DECL_EXPR_DECL (stmt); - if (VAR_P (d)) - gcc_assert (CP_DECL_THREAD_LOCAL_P (d) == DECL_THREAD_LOCAL_P (d)); - } - break; - - case OMP_PARALLEL: - case OMP_TASK: - case OMP_TASKLOOP: - { - struct cp_genericize_omp_taskreg omp_ctx; - tree c, decl; - splay_tree_node n; - - *walk_subtrees = 0; - cp_walk_tree (&OMP_CLAUSES (stmt), cp_genericize_r, data, NULL); - omp_ctx.is_parallel = TREE_CODE (stmt) == OMP_PARALLEL; - omp_ctx.default_shared = omp_ctx.is_parallel; - omp_ctx.outer = wtd->omp_ctx; - omp_ctx.variables = splay_tree_new (splay_tree_compare_decl_uid, 0, 0); - wtd->omp_ctx = &omp_ctx; - for (c = OMP_CLAUSES (stmt); c; c = OMP_CLAUSE_CHAIN (c)) - switch (OMP_CLAUSE_CODE (c)) - { - case OMP_CLAUSE_SHARED: - case OMP_CLAUSE_PRIVATE: - case OMP_CLAUSE_FIRSTPRIVATE: - case OMP_CLAUSE_LASTPRIVATE: - decl = OMP_CLAUSE_DECL (c); - if (decl == error_mark_node || !omp_var_to_track (decl)) - break; - n = splay_tree_lookup (omp_ctx.variables, (splay_tree_key) decl); - if (n != NULL) - break; - splay_tree_insert (omp_ctx.variables, (splay_tree_key) decl, - OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SHARED - ? OMP_CLAUSE_DEFAULT_SHARED - : OMP_CLAUSE_DEFAULT_PRIVATE); - if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_PRIVATE && omp_ctx.outer) - omp_cxx_notice_variable (omp_ctx.outer, decl); - break; - case OMP_CLAUSE_DEFAULT: - if (OMP_CLAUSE_DEFAULT_KIND (c) == OMP_CLAUSE_DEFAULT_SHARED) - omp_ctx.default_shared = true; - default: - break; - } - if (TREE_CODE (stmt) == OMP_TASKLOOP) - c_genericize_control_stmt (stmt_p, walk_subtrees, data, - cp_genericize_r, cp_walk_subtrees); - else - cp_walk_tree (&OMP_BODY (stmt), cp_genericize_r, data, NULL); - wtd->omp_ctx = omp_ctx.outer; - splay_tree_delete (omp_ctx.variables); - } - break; - - case OMP_TARGET: - cfun->has_omp_target = true; - break; - - case TRY_BLOCK: - { - *walk_subtrees = 0; - tree try_block = wtd->try_block; - wtd->try_block = stmt; - cp_walk_tree (&TRY_STMTS (stmt), cp_genericize_r, data, NULL); - wtd->try_block = try_block; - cp_walk_tree (&TRY_HANDLERS (stmt), cp_genericize_r, data, NULL); - } - break; - - case MUST_NOT_THROW_EXPR: - /* MUST_NOT_THROW_COND might be something else with TM. */ - if (MUST_NOT_THROW_COND (stmt) == NULL_TREE) - { - *walk_subtrees = 0; - tree try_block = wtd->try_block; - wtd->try_block = stmt; - cp_walk_tree (&TREE_OPERAND (stmt, 0), cp_genericize_r, data, NULL); - wtd->try_block = try_block; - } - break; - - case THROW_EXPR: - { - location_t loc = location_of (stmt); - if (warning_suppressed_p (stmt /* What warning? */)) - /* Never mind. */; - else if (wtd->try_block) - { - if (TREE_CODE (wtd->try_block) == MUST_NOT_THROW_EXPR) - { - auto_diagnostic_group d; - if (warning_at (loc, OPT_Wterminate, - "%<throw%> will always call %<terminate%>") - && cxx_dialect >= cxx11 - && DECL_DESTRUCTOR_P (current_function_decl)) - inform (loc, "in C++11 destructors default to %<noexcept%>"); - } - } - else - { - if (warn_cxx11_compat && cxx_dialect < cxx11 - && DECL_DESTRUCTOR_P (current_function_decl) - && (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)) - == NULL_TREE) - && (get_defaulted_eh_spec (current_function_decl) - == empty_except_spec)) - warning_at (loc, OPT_Wc__11_compat, - "in C++11 this %<throw%> will call %<terminate%> " - "because destructors default to %<noexcept%>"); - } - } - break; - - case CONVERT_EXPR: - gcc_assert (!CONVERT_EXPR_VBASE_PATH (stmt)); - break; - - case SPACESHIP_EXPR: - *stmt_p = genericize_spaceship (*stmt_p); - break; - - case PTRMEM_CST: - /* By the time we get here we're handing off to the back end, so we don't - need or want to preserve PTRMEM_CST anymore. */ - *stmt_p = cplus_expand_constant (stmt); - *walk_subtrees = 0; - break; - - case MEM_REF: - /* For MEM_REF, make sure not to sanitize the second operand even - if it has reference type. It is just an offset with a type - holding other information. There is no other processing we - need to do for INTEGER_CSTs, so just ignore the second argument - unconditionally. */ - cp_walk_tree (&TREE_OPERAND (stmt, 0), cp_genericize_r, data, NULL); - *walk_subtrees = 0; - break; - - case NOP_EXPR: - *stmt_p = predeclare_vla (*stmt_p); - if (!wtd->no_sanitize_p - && sanitize_flags_p (SANITIZE_NULL | SANITIZE_ALIGNMENT) - && TYPE_REF_P (TREE_TYPE (stmt))) - ubsan_maybe_instrument_reference (stmt_p); - break; - - case CALL_EXPR: - /* Evaluate function concept checks instead of treating them as - normal functions. */ - if (concept_check_p (stmt)) - { - *stmt_p = evaluate_concept_check (stmt); - * walk_subtrees = 0; - break; - } - - if (tree fndecl = cp_get_callee_fndecl_nofold (stmt)) - if (DECL_IMMEDIATE_FUNCTION_P (fndecl)) - { - gcc_assert (source_location_current_p (fndecl)); - *stmt_p = cxx_constant_value (stmt); - break; - } - - if (!wtd->no_sanitize_p - && sanitize_flags_p ((SANITIZE_NULL - | SANITIZE_ALIGNMENT | SANITIZE_VPTR))) - { - tree fn = CALL_EXPR_FN (stmt); - if (fn != NULL_TREE - && !error_operand_p (fn) - && INDIRECT_TYPE_P (TREE_TYPE (fn)) - && TREE_CODE (TREE_TYPE (TREE_TYPE (fn))) == METHOD_TYPE) - { - bool is_ctor - = TREE_CODE (fn) == ADDR_EXPR - && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL - && DECL_CONSTRUCTOR_P (TREE_OPERAND (fn, 0)); - if (sanitize_flags_p (SANITIZE_NULL | SANITIZE_ALIGNMENT)) - ubsan_maybe_instrument_member_call (stmt, is_ctor); - if (sanitize_flags_p (SANITIZE_VPTR) && !is_ctor) - cp_ubsan_maybe_instrument_member_call (stmt); - } - else if (fn == NULL_TREE - && CALL_EXPR_IFN (stmt) == IFN_UBSAN_NULL - && TREE_CODE (CALL_EXPR_ARG (stmt, 0)) == INTEGER_CST - && TYPE_REF_P (TREE_TYPE (CALL_EXPR_ARG (stmt, 0)))) - *walk_subtrees = 0; - } - /* Fall through. */ - case AGGR_INIT_EXPR: - /* For calls to a multi-versioned function, overload resolution - returns the function with the highest target priority, that is, - the version that will checked for dispatching first. If this - version is inlinable, a direct call to this version can be made - otherwise the call should go through the dispatcher. */ - { - tree fn = cp_get_callee_fndecl_nofold (stmt); - if (fn && DECL_FUNCTION_VERSIONED (fn) - && (current_function_decl == NULL - || !targetm.target_option.can_inline_p (current_function_decl, - fn))) - if (tree dis = get_function_version_dispatcher (fn)) - { - mark_versions_used (dis); - dis = build_address (dis); - if (TREE_CODE (stmt) == CALL_EXPR) - CALL_EXPR_FN (stmt) = dis; - else - AGGR_INIT_EXPR_FN (stmt) = dis; - } - } - break; - - case TARGET_EXPR: - if (TARGET_EXPR_INITIAL (stmt) - && TREE_CODE (TARGET_EXPR_INITIAL (stmt)) == CONSTRUCTOR - && CONSTRUCTOR_PLACEHOLDER_BOUNDARY (TARGET_EXPR_INITIAL (stmt))) - TARGET_EXPR_NO_ELIDE (stmt) = 1; - break; - - case TEMPLATE_ID_EXPR: - gcc_assert (concept_check_p (stmt)); - /* Emit the value of the concept check. */ - *stmt_p = evaluate_concept_check (stmt); - walk_subtrees = 0; - break; - - case OMP_DISTRIBUTE: - /* Need to explicitly instantiate copy ctors on class iterators of - composite distribute parallel for. */ - if (OMP_FOR_INIT (*stmt_p) == NULL_TREE) - { - tree *data[4] = { NULL, NULL, NULL, NULL }; - tree inner = walk_tree (&OMP_FOR_BODY (*stmt_p), - find_combined_omp_for, data, NULL); - if (inner != NULL_TREE - && TREE_CODE (inner) == OMP_FOR) - { - for (int i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (inner)); i++) - if (OMP_FOR_ORIG_DECLS (inner) - && TREE_CODE (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner), - i)) == TREE_LIST - && TREE_PURPOSE (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner), - i))) - { - tree orig = TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner), i); - /* Class iterators aren't allowed on OMP_SIMD, so the only - case we need to solve is distribute parallel for. */ - gcc_assert (TREE_CODE (inner) == OMP_FOR - && data[1]); - tree orig_decl = TREE_PURPOSE (orig); - tree c, cl = NULL_TREE; - for (c = OMP_FOR_CLAUSES (inner); - c; c = OMP_CLAUSE_CHAIN (c)) - if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE) - && OMP_CLAUSE_DECL (c) == orig_decl) - { - cl = c; - break; - } - if (cl == NULL_TREE) - { - for (c = OMP_PARALLEL_CLAUSES (*data[1]); - c; c = OMP_CLAUSE_CHAIN (c)) - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE - && OMP_CLAUSE_DECL (c) == orig_decl) - { - cl = c; - break; - } - } - if (cl) - { - orig_decl = require_complete_type (orig_decl); - tree inner_type = TREE_TYPE (orig_decl); - if (orig_decl == error_mark_node) - continue; - if (TYPE_REF_P (TREE_TYPE (orig_decl))) - inner_type = TREE_TYPE (inner_type); - - while (TREE_CODE (inner_type) == ARRAY_TYPE) - inner_type = TREE_TYPE (inner_type); - get_copy_ctor (inner_type, tf_warning_or_error); - } - } - } - } - /* FALLTHRU */ - - case FOR_STMT: - case WHILE_STMT: - case DO_STMT: - case SWITCH_STMT: - case CONTINUE_STMT: - case BREAK_STMT: - case OMP_FOR: - case OMP_SIMD: - case OMP_LOOP: - case OACC_LOOP: - case STATEMENT_LIST: - /* These cases are handled by shared code. */ - c_genericize_control_stmt (stmt_p, walk_subtrees, data, - cp_genericize_r, cp_walk_subtrees); - break; - - case BIT_CAST_EXPR: - *stmt_p = build1_loc (EXPR_LOCATION (stmt), VIEW_CONVERT_EXPR, - TREE_TYPE (stmt), TREE_OPERAND (stmt, 0)); - break; - - default: - if (IS_TYPE_OR_DECL_P (stmt)) - *walk_subtrees = 0; - break; - } - - p_set->add (*stmt_p); - - return NULL; -} - -/* Lower C++ front end trees to GENERIC in T_P. */ - -static void -cp_genericize_tree (tree* t_p, bool handle_invisiref_parm_p) -{ - struct cp_genericize_data wtd; - - wtd.p_set = new hash_set<tree>; - wtd.bind_expr_stack.create (0); - wtd.omp_ctx = NULL; - wtd.try_block = NULL_TREE; - wtd.no_sanitize_p = false; - wtd.handle_invisiref_parm_p = handle_invisiref_parm_p; - cp_walk_tree (t_p, cp_genericize_r, &wtd, NULL); - delete wtd.p_set; - if (sanitize_flags_p (SANITIZE_VPTR)) - cp_ubsan_instrument_member_accesses (t_p); -} - -/* If a function that should end with a return in non-void - function doesn't obviously end with return, add ubsan - instrumentation code to verify it at runtime. If -fsanitize=return - is not enabled, instrument __builtin_unreachable. */ - -static void -cp_maybe_instrument_return (tree fndecl) -{ - if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (fndecl))) - || DECL_CONSTRUCTOR_P (fndecl) - || DECL_DESTRUCTOR_P (fndecl) - || !targetm.warn_func_return (fndecl)) - return; - - if (!sanitize_flags_p (SANITIZE_RETURN, fndecl) - /* Don't add __builtin_unreachable () if not optimizing, it will not - improve any optimizations in that case, just break UB code. - Don't add it if -fsanitize=unreachable -fno-sanitize=return either, - UBSan covers this with ubsan_instrument_return above where sufficient - information is provided, while the __builtin_unreachable () below - if return sanitization is disabled will just result in hard to - understand runtime error without location. */ - && (!optimize - || sanitize_flags_p (SANITIZE_UNREACHABLE, fndecl))) - return; - - tree t = DECL_SAVED_TREE (fndecl); - while (t) - { - switch (TREE_CODE (t)) - { - case BIND_EXPR: - t = BIND_EXPR_BODY (t); - continue; - case TRY_FINALLY_EXPR: - case CLEANUP_POINT_EXPR: - t = TREE_OPERAND (t, 0); - continue; - case STATEMENT_LIST: - { - tree_stmt_iterator i = tsi_last (t); - while (!tsi_end_p (i)) - { - tree p = tsi_stmt (i); - if (TREE_CODE (p) != DEBUG_BEGIN_STMT) - break; - tsi_prev (&i); - } - if (!tsi_end_p (i)) - { - t = tsi_stmt (i); - continue; - } - } - break; - case RETURN_EXPR: - return; - default: - break; - } - break; - } - if (t == NULL_TREE) - return; - tree *p = &DECL_SAVED_TREE (fndecl); - if (TREE_CODE (*p) == BIND_EXPR) - p = &BIND_EXPR_BODY (*p); - - location_t loc = DECL_SOURCE_LOCATION (fndecl); - if (sanitize_flags_p (SANITIZE_RETURN, fndecl)) - t = ubsan_instrument_return (loc); - else - { - tree fndecl = builtin_decl_explicit (BUILT_IN_UNREACHABLE); - t = build_call_expr_loc (BUILTINS_LOCATION, fndecl, 0); - } - - append_to_statement_list (t, p); -} - -void -cp_genericize (tree fndecl) -{ - tree t; - - /* Fix up the types of parms passed by invisible reference. */ - for (t = DECL_ARGUMENTS (fndecl); t; t = DECL_CHAIN (t)) - if (TREE_ADDRESSABLE (TREE_TYPE (t))) - { - /* If a function's arguments are copied to create a thunk, - then DECL_BY_REFERENCE will be set -- but the type of the - argument will be a pointer type, so we will never get - here. */ - gcc_assert (!DECL_BY_REFERENCE (t)); - gcc_assert (DECL_ARG_TYPE (t) != TREE_TYPE (t)); - TREE_TYPE (t) = DECL_ARG_TYPE (t); - DECL_BY_REFERENCE (t) = 1; - TREE_ADDRESSABLE (t) = 0; - relayout_decl (t); - } - - /* Do the same for the return value. */ - if (TREE_ADDRESSABLE (TREE_TYPE (DECL_RESULT (fndecl)))) - { - t = DECL_RESULT (fndecl); - TREE_TYPE (t) = build_reference_type (TREE_TYPE (t)); - DECL_BY_REFERENCE (t) = 1; - TREE_ADDRESSABLE (t) = 0; - relayout_decl (t); - if (DECL_NAME (t)) - { - /* Adjust DECL_VALUE_EXPR of the original var. */ - tree outer = outer_curly_brace_block (current_function_decl); - tree var; - - if (outer) - for (var = BLOCK_VARS (outer); var; var = DECL_CHAIN (var)) - if (VAR_P (var) - && DECL_NAME (t) == DECL_NAME (var) - && DECL_HAS_VALUE_EXPR_P (var) - && DECL_VALUE_EXPR (var) == t) - { - tree val = convert_from_reference (t); - SET_DECL_VALUE_EXPR (var, val); - break; - } - } - } - - /* If we're a clone, the body is already GIMPLE. */ - if (DECL_CLONED_FUNCTION_P (fndecl)) - return; - - /* Allow cp_genericize calls to be nested. */ - bc_state_t save_state; - save_bc_state (&save_state); - - /* We do want to see every occurrence of the parms, so we can't just use - walk_tree's hash functionality. */ - cp_genericize_tree (&DECL_SAVED_TREE (fndecl), true); - - cp_maybe_instrument_return (fndecl); - - /* Do everything else. */ - c_genericize (fndecl); - restore_bc_state (&save_state); -} - -/* Build code to apply FN to each member of ARG1 and ARG2. FN may be - NULL if there is in fact nothing to do. ARG2 may be null if FN - actually only takes one argument. */ - -static tree -cxx_omp_clause_apply_fn (tree fn, tree arg1, tree arg2) -{ - tree defparm, parm, t; - int i = 0; - int nargs; - tree *argarray; - - if (fn == NULL) - return NULL; - - nargs = list_length (DECL_ARGUMENTS (fn)); - argarray = XALLOCAVEC (tree, nargs); - - defparm = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (fn))); - if (arg2) - defparm = TREE_CHAIN (defparm); - - bool is_method = TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE; - if (TREE_CODE (TREE_TYPE (arg1)) == ARRAY_TYPE) - { - tree inner_type = TREE_TYPE (arg1); - tree start1, end1, p1; - tree start2 = NULL, p2 = NULL; - tree ret = NULL, lab; - - start1 = arg1; - start2 = arg2; - do - { - inner_type = TREE_TYPE (inner_type); - start1 = build4 (ARRAY_REF, inner_type, start1, - size_zero_node, NULL, NULL); - if (arg2) - start2 = build4 (ARRAY_REF, inner_type, start2, - size_zero_node, NULL, NULL); - } - while (TREE_CODE (inner_type) == ARRAY_TYPE); - start1 = build_fold_addr_expr_loc (input_location, start1); - if (arg2) - start2 = build_fold_addr_expr_loc (input_location, start2); - - end1 = TYPE_SIZE_UNIT (TREE_TYPE (arg1)); - end1 = fold_build_pointer_plus (start1, end1); - - p1 = create_tmp_var (TREE_TYPE (start1)); - t = build2 (MODIFY_EXPR, TREE_TYPE (p1), p1, start1); - append_to_statement_list (t, &ret); - - if (arg2) - { - p2 = create_tmp_var (TREE_TYPE (start2)); - t = build2 (MODIFY_EXPR, TREE_TYPE (p2), p2, start2); - append_to_statement_list (t, &ret); - } - - lab = create_artificial_label (input_location); - t = build1 (LABEL_EXPR, void_type_node, lab); - append_to_statement_list (t, &ret); - - argarray[i++] = p1; - if (arg2) - argarray[i++] = p2; - /* Handle default arguments. */ - for (parm = defparm; parm && parm != void_list_node; - parm = TREE_CHAIN (parm), i++) - argarray[i] = convert_default_arg (TREE_VALUE (parm), - TREE_PURPOSE (parm), fn, - i - is_method, tf_warning_or_error); - t = build_call_a (fn, i, argarray); - t = fold_convert (void_type_node, t); - t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); - append_to_statement_list (t, &ret); - - t = fold_build_pointer_plus (p1, TYPE_SIZE_UNIT (inner_type)); - t = build2 (MODIFY_EXPR, TREE_TYPE (p1), p1, t); - append_to_statement_list (t, &ret); - - if (arg2) - { - t = fold_build_pointer_plus (p2, TYPE_SIZE_UNIT (inner_type)); - t = build2 (MODIFY_EXPR, TREE_TYPE (p2), p2, t); - append_to_statement_list (t, &ret); - } - - t = build2 (NE_EXPR, boolean_type_node, p1, end1); - t = build3 (COND_EXPR, void_type_node, t, build_and_jump (&lab), NULL); - append_to_statement_list (t, &ret); - - return ret; - } - else - { - argarray[i++] = build_fold_addr_expr_loc (input_location, arg1); - if (arg2) - argarray[i++] = build_fold_addr_expr_loc (input_location, arg2); - /* Handle default arguments. */ - for (parm = defparm; parm && parm != void_list_node; - parm = TREE_CHAIN (parm), i++) - argarray[i] = convert_default_arg (TREE_VALUE (parm), - TREE_PURPOSE (parm), fn, - i - is_method, tf_warning_or_error); - t = build_call_a (fn, i, argarray); - t = fold_convert (void_type_node, t); - return fold_build_cleanup_point_expr (TREE_TYPE (t), t); - } -} - -/* Return code to initialize DECL with its default constructor, or - NULL if there's nothing to do. */ - -tree -cxx_omp_clause_default_ctor (tree clause, tree decl, tree /*outer*/) -{ - tree info = CP_OMP_CLAUSE_INFO (clause); - tree ret = NULL; - - if (info) - ret = cxx_omp_clause_apply_fn (TREE_VEC_ELT (info, 0), decl, NULL); - - return ret; -} - -/* Return code to initialize DST with a copy constructor from SRC. */ - -tree -cxx_omp_clause_copy_ctor (tree clause, tree dst, tree src) -{ - tree info = CP_OMP_CLAUSE_INFO (clause); - tree ret = NULL; - - if (info) - ret = cxx_omp_clause_apply_fn (TREE_VEC_ELT (info, 0), dst, src); - if (ret == NULL) - ret = build2 (MODIFY_EXPR, TREE_TYPE (dst), dst, src); - - return ret; -} - -/* Similarly, except use an assignment operator instead. */ - -tree -cxx_omp_clause_assign_op (tree clause, tree dst, tree src) -{ - tree info = CP_OMP_CLAUSE_INFO (clause); - tree ret = NULL; - - if (info) - ret = cxx_omp_clause_apply_fn (TREE_VEC_ELT (info, 2), dst, src); - if (ret == NULL) - ret = build2 (MODIFY_EXPR, TREE_TYPE (dst), dst, src); - - return ret; -} - -/* Return code to destroy DECL. */ - -tree -cxx_omp_clause_dtor (tree clause, tree decl) -{ - tree info = CP_OMP_CLAUSE_INFO (clause); - tree ret = NULL; - - if (info) - ret = cxx_omp_clause_apply_fn (TREE_VEC_ELT (info, 1), decl, NULL); - - return ret; -} - -/* True if OpenMP should privatize what this DECL points to rather - than the DECL itself. */ - -bool -cxx_omp_privatize_by_reference (const_tree decl) -{ - return (TYPE_REF_P (TREE_TYPE (decl)) - || is_invisiref_parm (decl)); -} - -/* Return true if DECL is const qualified var having no mutable member. */ -bool -cxx_omp_const_qual_no_mutable (tree decl) -{ - tree type = TREE_TYPE (decl); - if (TYPE_REF_P (type)) - { - if (!is_invisiref_parm (decl)) - return false; - type = TREE_TYPE (type); - - if (TREE_CODE (decl) == RESULT_DECL && DECL_NAME (decl)) - { - /* NVR doesn't preserve const qualification of the - variable's type. */ - tree outer = outer_curly_brace_block (current_function_decl); - tree var; - - if (outer) - for (var = BLOCK_VARS (outer); var; var = DECL_CHAIN (var)) - if (VAR_P (var) - && DECL_NAME (decl) == DECL_NAME (var) - && (TYPE_MAIN_VARIANT (type) - == TYPE_MAIN_VARIANT (TREE_TYPE (var)))) - { - if (TYPE_READONLY (TREE_TYPE (var))) - type = TREE_TYPE (var); - break; - } - } - } - - if (type == error_mark_node) - return false; - - /* Variables with const-qualified type having no mutable member - are predetermined shared. */ - if (TYPE_READONLY (type) && !cp_has_mutable_p (type)) - return true; - - return false; -} - -/* OMP_CLAUSE_DEFAULT_UNSPECIFIED unless OpenMP sharing attribute - of DECL is predetermined. */ - -enum omp_clause_default_kind -cxx_omp_predetermined_sharing_1 (tree decl) -{ - /* Static data members are predetermined shared. */ - if (TREE_STATIC (decl)) - { - tree ctx = CP_DECL_CONTEXT (decl); - if (TYPE_P (ctx) && MAYBE_CLASS_TYPE_P (ctx)) - return OMP_CLAUSE_DEFAULT_SHARED; - - if (c_omp_predefined_variable (decl)) - return OMP_CLAUSE_DEFAULT_SHARED; - } - - /* this may not be specified in data-sharing clauses, still we need - to predetermined it firstprivate. */ - if (decl == current_class_ptr) - return OMP_CLAUSE_DEFAULT_FIRSTPRIVATE; - - return OMP_CLAUSE_DEFAULT_UNSPECIFIED; -} - -/* Likewise, but also include the artificial vars. We don't want to - disallow the artificial vars being mentioned in explicit clauses, - as we use artificial vars e.g. for loop constructs with random - access iterators other than pointers, but during gimplification - we want to treat them as predetermined. */ - -enum omp_clause_default_kind -cxx_omp_predetermined_sharing (tree decl) -{ - enum omp_clause_default_kind ret = cxx_omp_predetermined_sharing_1 (decl); - if (ret != OMP_CLAUSE_DEFAULT_UNSPECIFIED) - return ret; - - /* Predetermine artificial variables holding integral values, those - are usually result of gimplify_one_sizepos or SAVE_EXPR - gimplification. */ - if (VAR_P (decl) - && DECL_ARTIFICIAL (decl) - && INTEGRAL_TYPE_P (TREE_TYPE (decl)) - && !(DECL_LANG_SPECIFIC (decl) - && DECL_OMP_PRIVATIZED_MEMBER (decl))) - return OMP_CLAUSE_DEFAULT_SHARED; - - /* Similarly for typeinfo symbols. */ - if (VAR_P (decl) && DECL_ARTIFICIAL (decl) && DECL_TINFO_P (decl)) - return OMP_CLAUSE_DEFAULT_SHARED; - - return OMP_CLAUSE_DEFAULT_UNSPECIFIED; -} - -enum omp_clause_defaultmap_kind -cxx_omp_predetermined_mapping (tree decl) -{ - /* Predetermine artificial variables holding integral values, those - are usually result of gimplify_one_sizepos or SAVE_EXPR - gimplification. */ - if (VAR_P (decl) - && DECL_ARTIFICIAL (decl) - && INTEGRAL_TYPE_P (TREE_TYPE (decl)) - && !(DECL_LANG_SPECIFIC (decl) - && DECL_OMP_PRIVATIZED_MEMBER (decl))) - return OMP_CLAUSE_DEFAULTMAP_FIRSTPRIVATE; - - if (c_omp_predefined_variable (decl)) - return OMP_CLAUSE_DEFAULTMAP_TO; - - return OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED; -} - -/* Finalize an implicitly determined clause. */ - -void -cxx_omp_finish_clause (tree c, gimple_seq *, bool /* openacc */) -{ - tree decl, inner_type; - bool make_shared = false; - - if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_FIRSTPRIVATE - && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_PRIVATE - && (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_LASTPRIVATE - || !OMP_CLAUSE_LASTPRIVATE_LOOP_IV (c))) - return; - - decl = OMP_CLAUSE_DECL (c); - decl = require_complete_type (decl); - inner_type = TREE_TYPE (decl); - if (decl == error_mark_node) - make_shared = true; - else if (TYPE_REF_P (TREE_TYPE (decl))) - inner_type = TREE_TYPE (inner_type); - - /* We're interested in the base element, not arrays. */ - while (TREE_CODE (inner_type) == ARRAY_TYPE) - inner_type = TREE_TYPE (inner_type); - - /* Check for special function availability by building a call to one. - Save the results, because later we won't be in the right context - for making these queries. */ - bool first = OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE; - bool last = OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE; - if (!make_shared - && CLASS_TYPE_P (inner_type) - && cxx_omp_create_clause_info (c, inner_type, !first, first, last, - true)) - make_shared = true; - - if (make_shared) - { - OMP_CLAUSE_CODE (c) = OMP_CLAUSE_SHARED; - OMP_CLAUSE_SHARED_FIRSTPRIVATE (c) = 0; - OMP_CLAUSE_SHARED_READONLY (c) = 0; - } -} - -/* 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 - is going to be shared, false if it is going to be privatized. */ - -bool -cxx_omp_disregard_value_expr (tree decl, bool shared) -{ - if (shared) - return false; - if (VAR_P (decl) - && DECL_HAS_VALUE_EXPR_P (decl) - && DECL_ARTIFICIAL (decl) - && DECL_LANG_SPECIFIC (decl) - && DECL_OMP_PRIVATIZED_MEMBER (decl)) - return true; - if (VAR_P (decl) && DECL_CONTEXT (decl) && is_capture_proxy (decl)) - return true; - return false; -} - -/* Fold expression X which is used as an rvalue if RVAL is true. */ - -tree -cp_fold_maybe_rvalue (tree x, bool rval) -{ - while (true) - { - x = cp_fold (x); - if (rval) - x = mark_rvalue_use (x); - if (rval && DECL_P (x) - && !TYPE_REF_P (TREE_TYPE (x))) - { - tree v = decl_constant_value (x); - if (v != x && v != error_mark_node) - { - x = v; - continue; - } - } - break; - } - return x; -} - -/* Fold expression X which is used as an rvalue. */ - -tree -cp_fold_rvalue (tree x) -{ - return cp_fold_maybe_rvalue (x, true); -} - -/* Perform folding on expression X. */ - -tree -cp_fully_fold (tree x) -{ - if (processing_template_decl) - return x; - /* FIXME cp_fold ought to be a superset of maybe_constant_value so we don't - have to call both. */ - if (cxx_dialect >= cxx11) - { - x = maybe_constant_value (x); - /* Sometimes we are given a CONSTRUCTOR but the call above wraps it into - a TARGET_EXPR; undo that here. */ - if (TREE_CODE (x) == TARGET_EXPR) - x = TARGET_EXPR_INITIAL (x); - else if (TREE_CODE (x) == VIEW_CONVERT_EXPR - && TREE_CODE (TREE_OPERAND (x, 0)) == CONSTRUCTOR - && TREE_TYPE (TREE_OPERAND (x, 0)) == TREE_TYPE (x)) - x = TREE_OPERAND (x, 0); - } - return cp_fold_rvalue (x); -} - -/* Likewise, but also fold recursively, which cp_fully_fold doesn't perform - in some cases. */ - -tree -cp_fully_fold_init (tree x) -{ - if (processing_template_decl) - return x; - x = cp_fully_fold (x); - hash_set<tree> pset; - cp_walk_tree (&x, cp_fold_r, &pset, NULL); - return x; -} - -/* c-common interface to cp_fold. If IN_INIT, this is in a static initializer - and certain changes are made to the folding done. Or should be (FIXME). We - never touch maybe_const, as it is only used for the C front-end - C_MAYBE_CONST_EXPR. */ - -tree -c_fully_fold (tree x, bool /*in_init*/, bool */*maybe_const*/, bool lval) -{ - return cp_fold_maybe_rvalue (x, !lval); -} - -static GTY((deletable)) hash_map<tree, tree> *fold_cache; - -/* Dispose of the whole FOLD_CACHE. */ - -void -clear_fold_cache (void) -{ - if (fold_cache != NULL) - fold_cache->empty (); -} - -/* This function tries to fold an expression X. - To avoid combinatorial explosion, folding results are kept in fold_cache. - If X is invalid, we don't fold at all. - For performance reasons we don't cache expressions representing a - declaration or constant. - Function returns X or its folded variant. */ - -static tree -cp_fold (tree x) -{ - tree op0, op1, op2, op3; - tree org_x = x, r = NULL_TREE; - enum tree_code code; - location_t loc; - bool rval_ops = true; - - if (!x || x == error_mark_node) - return x; - - if (EXPR_P (x) && (!TREE_TYPE (x) || TREE_TYPE (x) == error_mark_node)) - return x; - - /* Don't bother to cache DECLs or constants. */ - if (DECL_P (x) || CONSTANT_CLASS_P (x)) - return x; - - if (fold_cache == NULL) - fold_cache = hash_map<tree, tree>::create_ggc (101); - - if (tree *cached = fold_cache->get (x)) - return *cached; - - uid_sensitive_constexpr_evaluation_checker c; - - code = TREE_CODE (x); - switch (code) - { - case CLEANUP_POINT_EXPR: - /* Strip CLEANUP_POINT_EXPR if the expression doesn't have side - effects. */ - r = cp_fold_rvalue (TREE_OPERAND (x, 0)); - if (!TREE_SIDE_EFFECTS (r)) - x = r; - break; - - case SIZEOF_EXPR: - x = fold_sizeof_expr (x); - break; - - case VIEW_CONVERT_EXPR: - rval_ops = false; - /* FALLTHRU */ - case CONVERT_EXPR: - case NOP_EXPR: - case NON_LVALUE_EXPR: - - if (VOID_TYPE_P (TREE_TYPE (x))) - { - /* This is just to make sure we don't end up with casts to - void from error_mark_node. If we just return x, then - cp_fold_r might fold the operand into error_mark_node and - leave the conversion in the IR. STRIP_USELESS_TYPE_CONVERSION - during gimplification doesn't like such casts. - Don't create a new tree if op0 != TREE_OPERAND (x, 0), the - folding of the operand should be in the caches and if in cp_fold_r - it will modify it in place. */ - op0 = cp_fold (TREE_OPERAND (x, 0)); - if (op0 == error_mark_node) - x = error_mark_node; - break; - } - - loc = EXPR_LOCATION (x); - op0 = cp_fold_maybe_rvalue (TREE_OPERAND (x, 0), rval_ops); - - if (code == CONVERT_EXPR - && SCALAR_TYPE_P (TREE_TYPE (x)) - && op0 != void_node) - /* During parsing we used convert_to_*_nofold; re-convert now using the - folding variants, since fold() doesn't do those transformations. */ - x = fold (convert (TREE_TYPE (x), op0)); - else if (op0 != TREE_OPERAND (x, 0)) - { - if (op0 == error_mark_node) - x = error_mark_node; - else - x = fold_build1_loc (loc, code, TREE_TYPE (x), op0); - } - else - x = fold (x); - - /* Conversion of an out-of-range value has implementation-defined - behavior; the language considers it different from arithmetic - overflow, which is undefined. */ - if (TREE_CODE (op0) == INTEGER_CST - && TREE_OVERFLOW_P (x) && !TREE_OVERFLOW_P (op0)) - TREE_OVERFLOW (x) = false; - - break; - - case INDIRECT_REF: - /* We don't need the decltype(auto) obfuscation anymore. */ - if (REF_PARENTHESIZED_P (x)) - { - tree p = maybe_undo_parenthesized_ref (x); - return cp_fold (p); - } - goto unary; - - case ADDR_EXPR: - loc = EXPR_LOCATION (x); - op0 = cp_fold_maybe_rvalue (TREE_OPERAND (x, 0), false); - - /* Cope with user tricks that amount to offsetof. */ - if (op0 != error_mark_node - && !FUNC_OR_METHOD_TYPE_P (TREE_TYPE (op0))) - { - tree val = get_base_address (op0); - if (val - && INDIRECT_REF_P (val) - && COMPLETE_TYPE_P (TREE_TYPE (val)) - && TREE_CONSTANT (TREE_OPERAND (val, 0))) - { - val = TREE_OPERAND (val, 0); - STRIP_NOPS (val); - val = maybe_constant_value (val); - if (TREE_CODE (val) == INTEGER_CST) - return fold_offsetof (op0, TREE_TYPE (x)); - } - } - goto finish_unary; - - case REALPART_EXPR: - case IMAGPART_EXPR: - rval_ops = false; - /* FALLTHRU */ - case CONJ_EXPR: - case FIX_TRUNC_EXPR: - case FLOAT_EXPR: - case NEGATE_EXPR: - case ABS_EXPR: - case ABSU_EXPR: - case BIT_NOT_EXPR: - case TRUTH_NOT_EXPR: - case FIXED_CONVERT_EXPR: - unary: - - loc = EXPR_LOCATION (x); - op0 = cp_fold_maybe_rvalue (TREE_OPERAND (x, 0), rval_ops); - - finish_unary: - if (op0 != TREE_OPERAND (x, 0)) - { - if (op0 == error_mark_node) - x = error_mark_node; - else - { - x = fold_build1_loc (loc, code, TREE_TYPE (x), op0); - if (code == INDIRECT_REF - && (INDIRECT_REF_P (x) || TREE_CODE (x) == MEM_REF)) - { - TREE_READONLY (x) = TREE_READONLY (org_x); - TREE_SIDE_EFFECTS (x) = TREE_SIDE_EFFECTS (org_x); - TREE_THIS_VOLATILE (x) = TREE_THIS_VOLATILE (org_x); - } - } - } - else - x = fold (x); - - gcc_assert (TREE_CODE (x) != COND_EXPR - || !VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (x, 0)))); - break; - - case UNARY_PLUS_EXPR: - op0 = cp_fold_rvalue (TREE_OPERAND (x, 0)); - if (op0 == error_mark_node) - x = error_mark_node; - else - x = fold_convert (TREE_TYPE (x), op0); - break; - - case POSTDECREMENT_EXPR: - case POSTINCREMENT_EXPR: - case INIT_EXPR: - case PREDECREMENT_EXPR: - case PREINCREMENT_EXPR: - case COMPOUND_EXPR: - case MODIFY_EXPR: - rval_ops = false; - /* FALLTHRU */ - case POINTER_PLUS_EXPR: - case PLUS_EXPR: - case POINTER_DIFF_EXPR: - case MINUS_EXPR: - case MULT_EXPR: - case TRUNC_DIV_EXPR: - case CEIL_DIV_EXPR: - case FLOOR_DIV_EXPR: - case ROUND_DIV_EXPR: - case TRUNC_MOD_EXPR: - case CEIL_MOD_EXPR: - case ROUND_MOD_EXPR: - case RDIV_EXPR: - case EXACT_DIV_EXPR: - case MIN_EXPR: - case MAX_EXPR: - case LSHIFT_EXPR: - case RSHIFT_EXPR: - case LROTATE_EXPR: - case RROTATE_EXPR: - case BIT_AND_EXPR: - case BIT_IOR_EXPR: - case BIT_XOR_EXPR: - case TRUTH_AND_EXPR: - case TRUTH_ANDIF_EXPR: - case TRUTH_OR_EXPR: - case TRUTH_ORIF_EXPR: - case TRUTH_XOR_EXPR: - case LT_EXPR: case LE_EXPR: - case GT_EXPR: case GE_EXPR: - case EQ_EXPR: case NE_EXPR: - case UNORDERED_EXPR: case ORDERED_EXPR: - case UNLT_EXPR: case UNLE_EXPR: - case UNGT_EXPR: case UNGE_EXPR: - case UNEQ_EXPR: case LTGT_EXPR: - case RANGE_EXPR: case COMPLEX_EXPR: - - loc = EXPR_LOCATION (x); - op0 = cp_fold_maybe_rvalue (TREE_OPERAND (x, 0), rval_ops); - op1 = cp_fold_rvalue (TREE_OPERAND (x, 1)); - - /* decltype(nullptr) has only one value, so optimize away all comparisons - with that type right away, keeping them in the IL causes troubles for - various optimizations. */ - if (COMPARISON_CLASS_P (org_x) - && TREE_CODE (TREE_TYPE (op0)) == NULLPTR_TYPE - && TREE_CODE (TREE_TYPE (op1)) == NULLPTR_TYPE) - { - switch (code) - { - case EQ_EXPR: - x = constant_boolean_node (true, TREE_TYPE (x)); - break; - case NE_EXPR: - x = constant_boolean_node (false, TREE_TYPE (x)); - break; - default: - gcc_unreachable (); - } - return omit_two_operands_loc (loc, TREE_TYPE (x), x, - op0, op1); - } - - if (op0 != TREE_OPERAND (x, 0) || op1 != TREE_OPERAND (x, 1)) - { - if (op0 == error_mark_node || op1 == error_mark_node) - x = error_mark_node; - else - x = fold_build2_loc (loc, code, TREE_TYPE (x), op0, op1); - } - else - x = fold (x); - - /* This is only needed for -Wnonnull-compare and only if - TREE_NO_WARNING (org_x), but to avoid that option affecting code - generation, we do it always. */ - if (COMPARISON_CLASS_P (org_x)) - { - if (x == error_mark_node || TREE_CODE (x) == INTEGER_CST) - ; - else if (COMPARISON_CLASS_P (x)) - { - if (warn_nonnull_compare - && warning_suppressed_p (org_x, OPT_Wnonnull_compare)) - suppress_warning (x, OPT_Wnonnull_compare); - } - /* Otherwise give up on optimizing these, let GIMPLE folders - optimize those later on. */ - else if (op0 != TREE_OPERAND (org_x, 0) - || op1 != TREE_OPERAND (org_x, 1)) - { - x = build2_loc (loc, code, TREE_TYPE (org_x), op0, op1); - if (warn_nonnull_compare - && warning_suppressed_p (org_x, OPT_Wnonnull_compare)) - suppress_warning (x, OPT_Wnonnull_compare); - } - else - x = org_x; - } - - break; - - case VEC_COND_EXPR: - case COND_EXPR: - loc = EXPR_LOCATION (x); - op0 = cp_fold_rvalue (TREE_OPERAND (x, 0)); - op1 = cp_fold (TREE_OPERAND (x, 1)); - op2 = cp_fold (TREE_OPERAND (x, 2)); - - if (TREE_CODE (TREE_TYPE (x)) == BOOLEAN_TYPE) - { - warning_sentinel s (warn_int_in_bool_context); - if (!VOID_TYPE_P (TREE_TYPE (op1))) - op1 = cp_truthvalue_conversion (op1, tf_warning_or_error); - if (!VOID_TYPE_P (TREE_TYPE (op2))) - op2 = cp_truthvalue_conversion (op2, tf_warning_or_error); - } - else if (VOID_TYPE_P (TREE_TYPE (x))) - { - if (TREE_CODE (op0) == INTEGER_CST) - { - /* If the condition is constant, fold can fold away - the COND_EXPR. If some statement-level uses of COND_EXPR - have one of the branches NULL, avoid folding crash. */ - if (!op1) - op1 = build_empty_stmt (loc); - if (!op2) - op2 = build_empty_stmt (loc); - } - else - { - /* Otherwise, don't bother folding a void condition, since - it can't produce a constant value. */ - if (op0 != TREE_OPERAND (x, 0) - || op1 != TREE_OPERAND (x, 1) - || op2 != TREE_OPERAND (x, 2)) - x = build3_loc (loc, code, TREE_TYPE (x), op0, op1, op2); - break; - } - } - - if (op0 != TREE_OPERAND (x, 0) - || op1 != TREE_OPERAND (x, 1) - || op2 != TREE_OPERAND (x, 2)) - { - if (op0 == error_mark_node - || op1 == error_mark_node - || op2 == error_mark_node) - x = error_mark_node; - else - x = fold_build3_loc (loc, code, TREE_TYPE (x), op0, op1, op2); - } - else - x = fold (x); - - /* A COND_EXPR might have incompatible types in branches if one or both - arms are bitfields. If folding exposed such a branch, fix it up. */ - if (TREE_CODE (x) != code - && x != error_mark_node - && !useless_type_conversion_p (TREE_TYPE (org_x), TREE_TYPE (x))) - x = fold_convert (TREE_TYPE (org_x), x); - - break; - - case CALL_EXPR: - { - int sv = optimize, nw = sv; - tree callee = get_callee_fndecl (x); - - /* Some built-in function calls will be evaluated at compile-time in - fold (). Set optimize to 1 when folding __builtin_constant_p inside - a constexpr function so that fold_builtin_1 doesn't fold it to 0. */ - if (callee && fndecl_built_in_p (callee) && !optimize - && DECL_IS_BUILTIN_CONSTANT_P (callee) - && current_function_decl - && DECL_DECLARED_CONSTEXPR_P (current_function_decl)) - nw = 1; - - if (callee && fndecl_built_in_p (callee, BUILT_IN_FRONTEND)) - { - switch (DECL_FE_FUNCTION_CODE (callee)) - { - /* Defer folding __builtin_is_constant_evaluated. */ - case CP_BUILT_IN_IS_CONSTANT_EVALUATED: - break; - case CP_BUILT_IN_SOURCE_LOCATION: - x = fold_builtin_source_location (EXPR_LOCATION (x)); - break; - case CP_BUILT_IN_IS_CORRESPONDING_MEMBER: - x = fold_builtin_is_corresponding_member - (EXPR_LOCATION (x), call_expr_nargs (x), - &CALL_EXPR_ARG (x, 0)); - break; - case CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS: - x = fold_builtin_is_pointer_inverconvertible_with_class - (EXPR_LOCATION (x), call_expr_nargs (x), - &CALL_EXPR_ARG (x, 0)); - break; - default: - break; - } - break; - } - - if (callee - && fndecl_built_in_p (callee, CP_BUILT_IN_SOURCE_LOCATION, - BUILT_IN_FRONTEND)) - { - x = fold_builtin_source_location (EXPR_LOCATION (x)); - break; - } - - bool changed = false; - int m = call_expr_nargs (x); - for (int i = 0; i < m; i++) - { - r = cp_fold (CALL_EXPR_ARG (x, i)); - if (r != CALL_EXPR_ARG (x, i)) - { - if (r == error_mark_node) - { - x = error_mark_node; - break; - } - if (!changed) - x = copy_node (x); - CALL_EXPR_ARG (x, i) = r; - changed = true; - } - } - if (x == error_mark_node) - break; - - optimize = nw; - r = fold (x); - optimize = sv; - - if (TREE_CODE (r) != CALL_EXPR) - { - x = cp_fold (r); - break; - } - - optimize = nw; - - /* Invoke maybe_constant_value for functions declared - constexpr and not called with AGGR_INIT_EXPRs. - TODO: - Do constexpr expansion of expressions where the call itself is not - constant, but the call followed by an INDIRECT_REF is. */ - if (callee && DECL_DECLARED_CONSTEXPR_P (callee) - && !flag_no_inline) - r = maybe_constant_value (x); - optimize = sv; - - if (TREE_CODE (r) != CALL_EXPR) - { - if (DECL_CONSTRUCTOR_P (callee)) - { - loc = EXPR_LOCATION (x); - tree s = build_fold_indirect_ref_loc (loc, - CALL_EXPR_ARG (x, 0)); - r = build2_loc (loc, INIT_EXPR, TREE_TYPE (s), s, r); - } - x = r; - break; - } - - break; - } - - case CONSTRUCTOR: - { - unsigned i; - constructor_elt *p; - vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (x); - vec<constructor_elt, va_gc> *nelts = NULL; - FOR_EACH_VEC_SAFE_ELT (elts, i, p) - { - tree op = cp_fold (p->value); - if (op != p->value) - { - if (op == error_mark_node) - { - x = error_mark_node; - vec_free (nelts); - break; - } - if (nelts == NULL) - nelts = elts->copy (); - (*nelts)[i].value = op; - } - } - if (nelts) - { - x = build_constructor (TREE_TYPE (x), nelts); - CONSTRUCTOR_PLACEHOLDER_BOUNDARY (x) - = CONSTRUCTOR_PLACEHOLDER_BOUNDARY (org_x); - } - if (VECTOR_TYPE_P (TREE_TYPE (x))) - x = fold (x); - break; - } - case TREE_VEC: - { - bool changed = false; - int n = TREE_VEC_LENGTH (x); - - for (int i = 0; i < n; i++) - { - tree op = cp_fold (TREE_VEC_ELT (x, i)); - if (op != TREE_VEC_ELT (x, i)) - { - if (!changed) - x = copy_node (x); - TREE_VEC_ELT (x, i) = op; - changed = true; - } - } - } - - break; - - case ARRAY_REF: - case ARRAY_RANGE_REF: - - loc = EXPR_LOCATION (x); - op0 = cp_fold (TREE_OPERAND (x, 0)); - op1 = cp_fold (TREE_OPERAND (x, 1)); - op2 = cp_fold (TREE_OPERAND (x, 2)); - op3 = cp_fold (TREE_OPERAND (x, 3)); - - if (op0 != TREE_OPERAND (x, 0) - || op1 != TREE_OPERAND (x, 1) - || op2 != TREE_OPERAND (x, 2) - || op3 != TREE_OPERAND (x, 3)) - { - if (op0 == error_mark_node - || op1 == error_mark_node - || op2 == error_mark_node - || op3 == error_mark_node) - x = error_mark_node; - else - { - x = build4_loc (loc, code, TREE_TYPE (x), op0, op1, op2, op3); - TREE_READONLY (x) = TREE_READONLY (org_x); - TREE_SIDE_EFFECTS (x) = TREE_SIDE_EFFECTS (org_x); - TREE_THIS_VOLATILE (x) = TREE_THIS_VOLATILE (org_x); - } - } - - x = fold (x); - break; - - case SAVE_EXPR: - /* A SAVE_EXPR might contain e.g. (0 * i) + (0 * j), which, after - folding, evaluates to an invariant. In that case no need to wrap - this folded tree with a SAVE_EXPR. */ - r = cp_fold (TREE_OPERAND (x, 0)); - if (tree_invariant_p (r)) - x = r; - break; - - case REQUIRES_EXPR: - x = evaluate_requires_expr (x); - break; - - default: - return org_x; - } - - if (EXPR_P (x) && TREE_CODE (x) == code) - { - TREE_THIS_VOLATILE (x) = TREE_THIS_VOLATILE (org_x); - copy_warning (x, org_x); - } - - if (!c.evaluation_restricted_p ()) - { - fold_cache->put (org_x, x); - /* Prevent that we try to fold an already folded result again. */ - if (x != org_x) - fold_cache->put (x, x); - } - - return x; -} - -/* Look up either "hot" or "cold" in attribute list LIST. */ - -tree -lookup_hotness_attribute (tree list) -{ - for (; list; list = TREE_CHAIN (list)) - { - tree name = get_attribute_name (list); - if (is_attribute_p ("hot", name) - || is_attribute_p ("cold", name) - || is_attribute_p ("likely", name) - || is_attribute_p ("unlikely", name)) - break; - } - return list; -} - -/* Remove both "hot" and "cold" attributes from LIST. */ - -static tree -remove_hotness_attribute (tree list) -{ - list = remove_attribute ("hot", list); - list = remove_attribute ("cold", list); - list = remove_attribute ("likely", list); - list = remove_attribute ("unlikely", list); - return list; -} - -/* If [[likely]] or [[unlikely]] appear on this statement, turn it into a - PREDICT_EXPR. */ - -tree -process_stmt_hotness_attribute (tree std_attrs, location_t attrs_loc) -{ - if (std_attrs == error_mark_node) - return std_attrs; - if (tree attr = lookup_hotness_attribute (std_attrs)) - { - tree name = get_attribute_name (attr); - bool hot = (is_attribute_p ("hot", name) - || is_attribute_p ("likely", name)); - tree pred = build_predict_expr (hot ? PRED_HOT_LABEL : PRED_COLD_LABEL, - hot ? TAKEN : NOT_TAKEN); - SET_EXPR_LOCATION (pred, attrs_loc); - add_stmt (pred); - if (tree other = lookup_hotness_attribute (TREE_CHAIN (attr))) - warning (OPT_Wattributes, "ignoring attribute %qE after earlier %qE", - get_attribute_name (other), name); - std_attrs = remove_hotness_attribute (std_attrs); - } - return std_attrs; -} - -/* Helper of fold_builtin_source_location, return the - std::source_location::__impl type after performing verification - on it. LOC is used for reporting any errors. */ - -static tree -get_source_location_impl_type (location_t loc) -{ - tree name = get_identifier ("source_location"); - tree decl = lookup_qualified_name (std_node, name); - if (TREE_CODE (decl) != TYPE_DECL) - { - auto_diagnostic_group d; - if (decl == error_mark_node || TREE_CODE (decl) == TREE_LIST) - qualified_name_lookup_error (std_node, name, decl, loc); - else - error_at (loc, "%qD is not a type", decl); - return error_mark_node; - } - name = get_identifier ("__impl"); - tree type = TREE_TYPE (decl); - decl = lookup_qualified_name (type, name); - if (TREE_CODE (decl) != TYPE_DECL) - { - auto_diagnostic_group d; - if (decl == error_mark_node || TREE_CODE (decl) == TREE_LIST) - qualified_name_lookup_error (type, name, decl, loc); - else - error_at (loc, "%qD is not a type", decl); - return error_mark_node; - } - type = TREE_TYPE (decl); - if (TREE_CODE (type) != RECORD_TYPE) - { - error_at (loc, "%qD is not a class type", decl); - return error_mark_node; - } - - int cnt = 0; - for (tree field = TYPE_FIELDS (type); - (field = next_initializable_field (field)) != NULL_TREE; - field = DECL_CHAIN (field)) - { - if (DECL_NAME (field) != NULL_TREE) - { - const char *n = IDENTIFIER_POINTER (DECL_NAME (field)); - if (strcmp (n, "_M_file_name") == 0 - || strcmp (n, "_M_function_name") == 0) - { - if (TREE_TYPE (field) != const_string_type_node) - { - error_at (loc, "%qD does not have %<const char *%> type", - field); - return error_mark_node; - } - cnt++; - continue; - } - else if (strcmp (n, "_M_line") == 0 || strcmp (n, "_M_column") == 0) - { - if (TREE_CODE (TREE_TYPE (field)) != INTEGER_TYPE) - { - error_at (loc, "%qD does not have integral type", field); - return error_mark_node; - } - cnt++; - continue; - } - } - cnt = 0; - break; - } - if (cnt != 4) - { - error_at (loc, "%<std::source_location::__impl%> does not contain only " - "non-static data members %<_M_file_name%>, " - "%<_M_function_name%>, %<_M_line%> and %<_M_column%>"); - return error_mark_node; - } - return build_qualified_type (type, TYPE_QUAL_CONST); -} - -/* Type for source_location_table hash_set. */ -struct GTY((for_user)) source_location_table_entry { - location_t loc; - unsigned uid; - tree var; -}; - -/* Traits class for function start hash maps below. */ - -struct source_location_table_entry_hash - : ggc_remove <source_location_table_entry> -{ - typedef source_location_table_entry value_type; - typedef source_location_table_entry compare_type; - - static hashval_t - hash (const source_location_table_entry &ref) - { - inchash::hash hstate (0); - hstate.add_int (ref.loc); - hstate.add_int (ref.uid); - return hstate.end (); - } - - static bool - equal (const source_location_table_entry &ref1, - const source_location_table_entry &ref2) - { - return ref1.loc == ref2.loc && ref1.uid == ref2.uid; - } - - static void - mark_deleted (source_location_table_entry &ref) - { - ref.loc = UNKNOWN_LOCATION; - ref.uid = -1U; - ref.var = NULL_TREE; - } - - static const bool empty_zero_p = true; - - static void - mark_empty (source_location_table_entry &ref) - { - ref.loc = UNKNOWN_LOCATION; - ref.uid = 0; - ref.var = NULL_TREE; - } - - static bool - is_deleted (const source_location_table_entry &ref) - { - return (ref.loc == UNKNOWN_LOCATION - && ref.uid == -1U - && ref.var == NULL_TREE); - } - - static bool - is_empty (const source_location_table_entry &ref) - { - return (ref.loc == UNKNOWN_LOCATION - && ref.uid == 0 - && ref.var == NULL_TREE); - } - - static void - pch_nx (source_location_table_entry &p) - { - extern void gt_pch_nx (source_location_table_entry &); - gt_pch_nx (p); - } - - static void - pch_nx (source_location_table_entry &p, gt_pointer_operator op, void *cookie) - { - extern void gt_pch_nx (source_location_table_entry *, gt_pointer_operator, - void *); - gt_pch_nx (&p, op, cookie); - } -}; - -static GTY(()) hash_table <source_location_table_entry_hash> - *source_location_table; -static GTY(()) unsigned int source_location_id; - -/* Fold __builtin_source_location () call. LOC is the location - of the call. */ - -tree -fold_builtin_source_location (location_t loc) -{ - if (source_location_impl == NULL_TREE) - { - auto_diagnostic_group d; - source_location_impl = get_source_location_impl_type (loc); - if (source_location_impl == error_mark_node) - inform (loc, "evaluating %qs", "__builtin_source_location"); - } - if (source_location_impl == error_mark_node) - return build_zero_cst (const_ptr_type_node); - if (source_location_table == NULL) - source_location_table - = hash_table <source_location_table_entry_hash>::create_ggc (64); - const line_map_ordinary *map; - source_location_table_entry entry; - entry.loc - = linemap_resolve_location (line_table, loc, LRK_MACRO_EXPANSION_POINT, - &map); - entry.uid = current_function_decl ? DECL_UID (current_function_decl) : -1; - entry.var = error_mark_node; - source_location_table_entry *entryp - = source_location_table->find_slot (entry, INSERT); - tree var; - if (entryp->var) - var = entryp->var; - else - { - char tmp_name[32]; - ASM_GENERATE_INTERNAL_LABEL (tmp_name, "Lsrc_loc", source_location_id++); - var = build_decl (loc, VAR_DECL, get_identifier (tmp_name), - source_location_impl); - TREE_STATIC (var) = 1; - TREE_PUBLIC (var) = 0; - DECL_ARTIFICIAL (var) = 1; - DECL_IGNORED_P (var) = 1; - DECL_EXTERNAL (var) = 0; - DECL_DECLARED_CONSTEXPR_P (var) = 1; - DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (var) = 1; - layout_decl (var, 0); - - vec<constructor_elt, va_gc> *v = NULL; - vec_alloc (v, 4); - for (tree field = TYPE_FIELDS (source_location_impl); - (field = next_initializable_field (field)) != NULL_TREE; - field = DECL_CHAIN (field)) - { - const char *n = IDENTIFIER_POINTER (DECL_NAME (field)); - tree val = NULL_TREE; - if (strcmp (n, "_M_file_name") == 0) - { - if (const char *fname = LOCATION_FILE (loc)) - { - fname = remap_macro_filename (fname); - val = build_string_literal (strlen (fname) + 1, fname); - } - else - val = build_string_literal (1, ""); - } - else if (strcmp (n, "_M_function_name") == 0) - { - const char *name = ""; - - if (current_function_decl) - name = cxx_printable_name (current_function_decl, 2); - - val = build_string_literal (strlen (name) + 1, name); - } - else if (strcmp (n, "_M_line") == 0) - val = build_int_cst (TREE_TYPE (field), LOCATION_LINE (loc)); - else if (strcmp (n, "_M_column") == 0) - val = build_int_cst (TREE_TYPE (field), LOCATION_COLUMN (loc)); - else - gcc_unreachable (); - CONSTRUCTOR_APPEND_ELT (v, field, val); - } - - tree ctor = build_constructor (source_location_impl, v); - TREE_CONSTANT (ctor) = 1; - TREE_STATIC (ctor) = 1; - DECL_INITIAL (var) = ctor; - varpool_node::finalize_decl (var); - *entryp = entry; - entryp->var = var; - } - - return build_fold_addr_expr_with_type_loc (loc, var, const_ptr_type_node); -} - -#include "gt-cp-cp-gimplify.h" |