HOST_WIDE_INT extract_sec_implicit_index_arg (location_t location, tree fn) { tree fn_arg; HOST_WIDE_INT return_int = 0; if (TREE_CODE (fn) == CALL_EXPR) { fn_arg = CALL_EXPR_ARG (fn, 0); if (TREE_CODE (fn_arg) == INTEGER_CST) return_int = int_cst_value (fn_arg); else { /* If the location is unknown, and if fn has a location, then use that information so that the user has a better idea where the error could be. */ if (location == UNKNOWN_LOCATION && EXPR_HAS_LOCATION (fn)) location = EXPR_LOCATION (fn); error_at (location, "__sec_implicit_index parameter must be an " "integer constant expression"); return -1; } } return return_int; }
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_) then_ = build_empty_stmt (); if (!else_) else_ = build_empty_stmt (); 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_); if (CAN_HAVE_LOCATION_P (stmt) && !EXPR_HAS_LOCATION (stmt)) SET_EXPR_LOCATION (stmt, locus); *stmt_p = stmt; }
static tree cpp_validate_cilk_plus_loop_aux (tree *tp, int *walk_subtrees, void *data) { bool *valid = (bool *) data; location_t loc = EXPR_HAS_LOCATION (*tp) ? EXPR_LOCATION (*tp) : UNKNOWN_LOCATION; if (!tp || !*tp) return NULL_TREE; if (TREE_CODE (*tp) == THROW_EXPR) { error_at (loc, "throw expressions are not allowed inside loops " "marked with pragma simd"); *walk_subtrees = 0; *valid = false; } else if (TREE_CODE (*tp) == TRY_BLOCK) { error_at (loc, "try statements are not allowed inside loops marked " "with #pragma simd"); *valid = false; *walk_subtrees = 0; } return NULL_TREE; }
static void append_stmt (tree stmt) { if (!EXPR_HAS_LOCATION (stmt)) SET_EXPR_LOCATION (stmt, input_location); TREE_SIDE_EFFECTS (stmt) = true; append_to_statement_list (stmt, &cur_stmts); }
static void lower_stmt (tree_stmt_iterator *tsi, struct lower_data *data) { tree stmt = tsi_stmt (*tsi); if (EXPR_HAS_LOCATION (stmt) && data) TREE_BLOCK (stmt) = data->block; switch (TREE_CODE (stmt)) { case BIND_EXPR: lower_bind_expr (tsi, data); return; case COND_EXPR: lower_cond_expr (tsi, data); return; case RETURN_EXPR: lower_return_expr (tsi, data); return; case TRY_FINALLY_EXPR: case TRY_CATCH_EXPR: lower_stmt_body (TREE_OPERAND (stmt, 0), data); lower_stmt_body (TREE_OPERAND (stmt, 1), data); break; case CATCH_EXPR: lower_stmt_body (CATCH_BODY (stmt), data); break; case EH_FILTER_EXPR: lower_stmt_body (EH_FILTER_FAILURE (stmt), data); break; case NOP_EXPR: case ASM_EXPR: case MODIFY_EXPR: case CALL_EXPR: case GOTO_EXPR: case LABEL_EXPR: case SWITCH_EXPR: break; default: #ifdef ENABLE_CHECKING print_node_brief (stderr, "", stmt, 0); internal_error ("unexpected node"); #endif case COMPOUND_EXPR: gcc_unreachable (); } tsi_next (tsi); }
bool find_rank (location_t loc, tree orig_expr, tree expr, bool ignore_builtin_fn, size_t *rank) { tree ii_tree; size_t ii = 0, current_rank = 0; if (TREE_CODE (expr) == ARRAY_NOTATION_REF) { ii_tree = expr; while (ii_tree) { if (TREE_CODE (ii_tree) == ARRAY_NOTATION_REF) { current_rank++; ii_tree = ARRAY_NOTATION_ARRAY (ii_tree); } else if (handled_component_p (ii_tree) || TREE_CODE (ii_tree) == INDIRECT_REF) ii_tree = TREE_OPERAND (ii_tree, 0); else if (TREE_CODE (ii_tree) == PARM_DECL || TREE_CODE (ii_tree) == VAR_DECL) break; else gcc_unreachable (); } if (*rank == 0) /* In this case, all the expressions this function has encountered thus far have been scalars or expressions with zero rank. Please see header comment for examples of such expression. */ *rank = current_rank; else if (*rank != current_rank) { /* In this case, find rank is being recursed through a set of expression of the form A <OPERATION> B, where A and B both have array notations in them and the rank of A is not equal to rank of B. A simple example of such case is the following: X[:] + Y[:][:] */ *rank = current_rank; return false; } } else if (TREE_CODE (expr) == STATEMENT_LIST) { tree_stmt_iterator ii_tsi; for (ii_tsi = tsi_start (expr); !tsi_end_p (ii_tsi); tsi_next (&ii_tsi)) if (!find_rank (loc, orig_expr, *tsi_stmt_ptr (ii_tsi), ignore_builtin_fn, rank)) return false; } else { if (TREE_CODE (expr) == CALL_EXPR) { tree func_name = CALL_EXPR_FN (expr); tree prev_arg = NULL_TREE, arg; call_expr_arg_iterator iter; size_t prev_rank = 0; if (TREE_CODE (func_name) == ADDR_EXPR) if (!ignore_builtin_fn) if (is_cilkplus_reduce_builtin (func_name)) /* If it is a built-in function, then we know it returns a scalar. */ return true; if (!find_rank (loc, orig_expr, func_name, ignore_builtin_fn, rank)) return false; FOR_EACH_CALL_EXPR_ARG (arg, iter, expr) { if (!find_rank (loc, orig_expr, arg, ignore_builtin_fn, rank)) { if (prev_arg && EXPR_HAS_LOCATION (prev_arg) && prev_rank != *rank) error_at (EXPR_LOCATION (prev_arg), "rank mismatch between %qE and %qE", prev_arg, arg); else if (prev_arg && prev_rank != *rank) /* Here the original expression is printed as a "heads-up" to the programmer. This is because since there is no location information for the offending argument, the error could be in some internally generated code that is not visible for the programmer. Thus, the correct fix may lie in the original expression. */ error_at (loc, "rank mismatch in expression %qE", orig_expr); return false; } prev_arg = arg; prev_rank = *rank; } } else {
void dump_stmt (dump_info_p di, tree t) { if (EXPR_HAS_LOCATION (t)) dump_int (di, "line", EXPR_LINENO (t)); }
tree c_finish_omp_for (location_t locus, tree decl, tree init, tree cond, tree incr, tree body, tree pre_body) { location_t elocus = locus; bool fail = false; if (EXPR_HAS_LOCATION (init)) elocus = EXPR_LOCATION (init); /* Validate the iteration variable. */ if (!INTEGRAL_TYPE_P (TREE_TYPE (decl))) { error ("%Hinvalid type for iteration variable %qE", &elocus, decl); fail = true; } if (TYPE_UNSIGNED (TREE_TYPE (decl))) warning (0, "%Hiteration variable %qE is unsigned", &elocus, decl); /* In the case of "for (int i = 0...)", init will be a decl. It should have a DECL_INITIAL that we can turn into an assignment. */ if (init == decl) { elocus = DECL_SOURCE_LOCATION (decl); init = DECL_INITIAL (decl); if (init == NULL) { error ("%H%qE is not initialized", &elocus, decl); init = integer_zero_node; fail = true; } init = build_modify_expr (decl, NOP_EXPR, init); SET_EXPR_LOCATION (init, elocus); } gcc_assert (TREE_CODE (init) == MODIFY_EXPR); gcc_assert (TREE_OPERAND (init, 0) == decl); if (cond == NULL_TREE) { error ("%Hmissing controlling predicate", &elocus); fail = true; } else { bool cond_ok = false; if (EXPR_HAS_LOCATION (cond)) elocus = EXPR_LOCATION (cond); if (TREE_CODE (cond) == LT_EXPR || TREE_CODE (cond) == LE_EXPR || TREE_CODE (cond) == GT_EXPR || TREE_CODE (cond) == GE_EXPR) { tree op0 = TREE_OPERAND (cond, 0); tree op1 = TREE_OPERAND (cond, 1); /* 2.5.1. The comparison in the condition is computed in the type of DECL, otherwise the behavior is undefined. For example: long n; int i; i < n; according to ISO will be evaluated as: (long)i < n; We want to force: i < (int)n; */ if (TREE_CODE (op0) == NOP_EXPR && decl == TREE_OPERAND (op0, 0)) { TREE_OPERAND (cond, 0) = TREE_OPERAND (op0, 0); TREE_OPERAND (cond, 1) = fold_build1 (NOP_EXPR, TREE_TYPE (decl), TREE_OPERAND (cond, 1)); } else if (TREE_CODE (op1) == NOP_EXPR && decl == TREE_OPERAND (op1, 0)) { TREE_OPERAND (cond, 1) = TREE_OPERAND (op1, 0); TREE_OPERAND (cond, 0) = fold_build1 (NOP_EXPR, TREE_TYPE (decl), TREE_OPERAND (cond, 0)); } if (decl == TREE_OPERAND (cond, 0)) cond_ok = true; else if (decl == TREE_OPERAND (cond, 1)) { TREE_SET_CODE (cond, swap_tree_comparison (TREE_CODE (cond))); TREE_OPERAND (cond, 1) = TREE_OPERAND (cond, 0); TREE_OPERAND (cond, 0) = decl; cond_ok = true; } } if (!cond_ok) { error ("%Hinvalid controlling predicate", &elocus); fail = true; } } if (incr == NULL_TREE) { error ("%Hmissing increment expression", &elocus); fail = true; } else { bool incr_ok = false; if (EXPR_HAS_LOCATION (incr)) elocus = EXPR_LOCATION (incr); /* Check all the valid increment expressions: v++, v--, ++v, --v, v = v + incr, v = incr + v and v = v - incr. */ switch (TREE_CODE (incr)) { case POSTINCREMENT_EXPR: case PREINCREMENT_EXPR: case POSTDECREMENT_EXPR: case PREDECREMENT_EXPR: incr_ok = (TREE_OPERAND (incr, 0) == decl); break; case MODIFY_EXPR: if (TREE_OPERAND (incr, 0) != decl) break; if (TREE_OPERAND (incr, 1) == decl) break; if (TREE_CODE (TREE_OPERAND (incr, 1)) == PLUS_EXPR && (TREE_OPERAND (TREE_OPERAND (incr, 1), 0) == decl || TREE_OPERAND (TREE_OPERAND (incr, 1), 1) == decl)) incr_ok = true; else if (TREE_CODE (TREE_OPERAND (incr, 1)) == MINUS_EXPR && TREE_OPERAND (TREE_OPERAND (incr, 1), 0) == decl) incr_ok = true; else { tree t = check_omp_for_incr_expr (TREE_OPERAND (incr, 1), decl); if (t != error_mark_node) { incr_ok = true; t = build2 (PLUS_EXPR, TREE_TYPE (decl), decl, t); incr = build2 (MODIFY_EXPR, void_type_node, decl, t); } } break; default: break; } if (!incr_ok) { error ("%Hinvalid increment expression", &elocus); fail = true; } } if (fail) return NULL; else { tree t = make_node (OMP_FOR); TREE_TYPE (t) = void_type_node; OMP_FOR_INIT (t) = init; OMP_FOR_COND (t) = cond; OMP_FOR_INCR (t) = incr; OMP_FOR_BODY (t) = body; OMP_FOR_PRE_BODY (t) = pre_body; SET_EXPR_LOCATION (t, locus); return add_stmt (t); } }
static tree expand_array_notations (tree *tp, int *walk_subtrees, void *) { if (!contains_array_notation_expr (*tp)) { *walk_subtrees = 0; return NULL_TREE; } *walk_subtrees = 1; switch (TREE_CODE (*tp)) { case TRUTH_ORIF_EXPR: case TRUTH_ANDIF_EXPR: case TRUTH_OR_EXPR: case TRUTH_AND_EXPR: case TRUTH_XOR_EXPR: case TRUTH_NOT_EXPR: case COND_EXPR: *tp = fix_conditional_array_notations (*tp); break; case MODIFY_EXPR: { location_t loc = EXPR_HAS_LOCATION (*tp) ? EXPR_LOCATION (*tp) : UNKNOWN_LOCATION; tree lhs = TREE_OPERAND (*tp, 0); tree rhs = TREE_OPERAND (*tp, 1); location_t rhs_loc = EXPR_HAS_LOCATION (rhs) ? EXPR_LOCATION (rhs) : UNKNOWN_LOCATION; *tp = build_array_notation_expr (loc, lhs, TREE_TYPE (lhs), NOP_EXPR, rhs_loc, rhs, TREE_TYPE (rhs)); } break; case DECL_EXPR: { tree x = DECL_EXPR_DECL (*tp); if (DECL_INITIAL (x)) { location_t loc = DECL_SOURCE_LOCATION (x); tree lhs = x; tree rhs = DECL_INITIAL (x); DECL_INITIAL (x) = NULL; tree new_modify_expr = build_modify_expr (loc, lhs, TREE_TYPE (lhs), NOP_EXPR, loc, rhs, TREE_TYPE(rhs)); expand_array_notations (&new_modify_expr, walk_subtrees, NULL); *tp = new_modify_expr; } } break; case CALL_EXPR: *tp = fix_array_notation_call_expr (*tp); break; case RETURN_EXPR: *tp = fix_return_expr (*tp); break; case COMPOUND_EXPR: if (TREE_CODE (TREE_OPERAND (*tp, 0)) == SAVE_EXPR) { /* In here we are calling expand_array_notations because we need to be able to catch the return value and check if it is an error_mark_node. */ expand_array_notations (&TREE_OPERAND (*tp, 1), walk_subtrees, NULL); /* SAVE_EXPR cannot have an error_mark_node inside it. This check will make sure that if there is an error in expanding of array notations (e.g. rank mismatch) then replace the entire SAVE_EXPR with an error_mark_node. */ if (TREE_OPERAND (*tp, 1) == error_mark_node) *tp = error_mark_node; } break; case ARRAY_NOTATION_REF: /* If we are here, then we are dealing with cases like this: A[:]; A[x:y:z]; A[x:y]; Replace those with just void zero node. */ *tp = void_node; default: break; } return NULL_TREE; }
tree c_finish_omp_for (location_t locus, enum tree_code code, tree declv, tree orig_declv, tree initv, tree condv, tree incrv, tree body, tree pre_body) { location_t elocus; bool fail = false; int i; if ((code == CILK_SIMD || code == CILK_FOR) && !c_check_cilk_loop (locus, TREE_VEC_ELT (declv, 0))) fail = true; gcc_assert (TREE_VEC_LENGTH (declv) == TREE_VEC_LENGTH (initv)); gcc_assert (TREE_VEC_LENGTH (declv) == TREE_VEC_LENGTH (condv)); gcc_assert (TREE_VEC_LENGTH (declv) == TREE_VEC_LENGTH (incrv)); for (i = 0; i < TREE_VEC_LENGTH (declv); i++) { tree decl = TREE_VEC_ELT (declv, i); tree init = TREE_VEC_ELT (initv, i); tree cond = TREE_VEC_ELT (condv, i); tree incr = TREE_VEC_ELT (incrv, i); elocus = locus; if (EXPR_HAS_LOCATION (init)) elocus = EXPR_LOCATION (init); /* Validate the iteration variable. */ if (!INTEGRAL_TYPE_P (TREE_TYPE (decl)) && TREE_CODE (TREE_TYPE (decl)) != POINTER_TYPE) { error_at (elocus, "invalid type for iteration variable %qE", decl); fail = true; } /* In the case of "for (int i = 0...)", init will be a decl. It should have a DECL_INITIAL that we can turn into an assignment. */ if (init == decl) { elocus = DECL_SOURCE_LOCATION (decl); init = DECL_INITIAL (decl); if (init == NULL) { error_at (elocus, "%qE is not initialized", decl); init = integer_zero_node; fail = true; } DECL_INITIAL (decl) = NULL_TREE; init = build_modify_expr (elocus, decl, NULL_TREE, NOP_EXPR, /* FIXME diagnostics: This should be the location of the INIT. */ elocus, init, NULL_TREE); } if (init != error_mark_node) { gcc_assert (TREE_CODE (init) == MODIFY_EXPR); gcc_assert (TREE_OPERAND (init, 0) == decl); } if (cond == NULL_TREE) { error_at (elocus, "missing controlling predicate"); fail = true; } else { bool cond_ok = false; if (EXPR_HAS_LOCATION (cond)) elocus = EXPR_LOCATION (cond); if (TREE_CODE (cond) == LT_EXPR || TREE_CODE (cond) == LE_EXPR || TREE_CODE (cond) == GT_EXPR || TREE_CODE (cond) == GE_EXPR || TREE_CODE (cond) == NE_EXPR || TREE_CODE (cond) == EQ_EXPR) { tree op0 = TREE_OPERAND (cond, 0); tree op1 = TREE_OPERAND (cond, 1); /* 2.5.1. The comparison in the condition is computed in the type of DECL, otherwise the behavior is undefined. For example: long n; int i; i < n; according to ISO will be evaluated as: (long)i < n; We want to force: i < (int)n; */ if (TREE_CODE (op0) == NOP_EXPR && decl == TREE_OPERAND (op0, 0)) { TREE_OPERAND (cond, 0) = TREE_OPERAND (op0, 0); TREE_OPERAND (cond, 1) = fold_build1_loc (elocus, NOP_EXPR, TREE_TYPE (decl), TREE_OPERAND (cond, 1)); } else if (TREE_CODE (op1) == NOP_EXPR && decl == TREE_OPERAND (op1, 0)) { TREE_OPERAND (cond, 1) = TREE_OPERAND (op1, 0); TREE_OPERAND (cond, 0) = fold_build1_loc (elocus, NOP_EXPR, TREE_TYPE (decl), TREE_OPERAND (cond, 0)); } if (decl == TREE_OPERAND (cond, 0)) cond_ok = true; else if (decl == TREE_OPERAND (cond, 1)) { TREE_SET_CODE (cond, swap_tree_comparison (TREE_CODE (cond))); TREE_OPERAND (cond, 1) = TREE_OPERAND (cond, 0); TREE_OPERAND (cond, 0) = decl; cond_ok = true; } if (TREE_CODE (cond) == NE_EXPR || TREE_CODE (cond) == EQ_EXPR) { if (!INTEGRAL_TYPE_P (TREE_TYPE (decl))) { if (code != CILK_SIMD && code != CILK_FOR) cond_ok = false; } else if (operand_equal_p (TREE_OPERAND (cond, 1), TYPE_MIN_VALUE (TREE_TYPE (decl)), 0)) TREE_SET_CODE (cond, TREE_CODE (cond) == NE_EXPR ? GT_EXPR : LE_EXPR); else if (operand_equal_p (TREE_OPERAND (cond, 1), TYPE_MAX_VALUE (TREE_TYPE (decl)), 0)) TREE_SET_CODE (cond, TREE_CODE (cond) == NE_EXPR ? LT_EXPR : GE_EXPR); else if (code != CILK_SIMD && code != CILK_FOR) cond_ok = false; } } if (!cond_ok) { error_at (elocus, "invalid controlling predicate"); fail = true; } } if (incr == NULL_TREE) { error_at (elocus, "missing increment expression"); fail = true; } else { bool incr_ok = false; if (EXPR_HAS_LOCATION (incr)) elocus = EXPR_LOCATION (incr); /* Check all the valid increment expressions: v++, v--, ++v, --v, v = v + incr, v = incr + v and v = v - incr. */ switch (TREE_CODE (incr)) { case POSTINCREMENT_EXPR: case PREINCREMENT_EXPR: case POSTDECREMENT_EXPR: case PREDECREMENT_EXPR: if (TREE_OPERAND (incr, 0) != decl) break; incr_ok = true; incr = c_omp_for_incr_canonicalize_ptr (elocus, decl, incr); break; case COMPOUND_EXPR: if (TREE_CODE (TREE_OPERAND (incr, 0)) != SAVE_EXPR || TREE_CODE (TREE_OPERAND (incr, 1)) != MODIFY_EXPR) break; incr = TREE_OPERAND (incr, 1); /* FALLTHRU */ case MODIFY_EXPR: if (TREE_OPERAND (incr, 0) != decl) break; if (TREE_OPERAND (incr, 1) == decl) break; if (TREE_CODE (TREE_OPERAND (incr, 1)) == PLUS_EXPR && (TREE_OPERAND (TREE_OPERAND (incr, 1), 0) == decl || TREE_OPERAND (TREE_OPERAND (incr, 1), 1) == decl)) incr_ok = true; else if ((TREE_CODE (TREE_OPERAND (incr, 1)) == MINUS_EXPR || (TREE_CODE (TREE_OPERAND (incr, 1)) == POINTER_PLUS_EXPR)) && TREE_OPERAND (TREE_OPERAND (incr, 1), 0) == decl) incr_ok = true; else { tree t = check_omp_for_incr_expr (elocus, TREE_OPERAND (incr, 1), decl); if (t != error_mark_node) { incr_ok = true; t = build2 (PLUS_EXPR, TREE_TYPE (decl), decl, t); incr = build2 (MODIFY_EXPR, void_type_node, decl, t); } } break; default: break; } if (!incr_ok) { error_at (elocus, "invalid increment expression"); fail = true; } } TREE_VEC_ELT (initv, i) = init; TREE_VEC_ELT (incrv, i) = incr; } if (fail) return NULL; else { tree t = make_node (code); TREE_TYPE (t) = void_type_node; OMP_FOR_INIT (t) = initv; OMP_FOR_COND (t) = condv; OMP_FOR_INCR (t) = incrv; OMP_FOR_BODY (t) = body; OMP_FOR_PRE_BODY (t) = pre_body; if (code == OMP_FOR) OMP_FOR_ORIG_DECLS (t) = orig_declv; SET_EXPR_LOCATION (t, locus); return add_stmt (t); } }
void process_stmt (tree stmt) { tree_stmt_iterator si; switch (TREE_CODE(stmt)) { case STATEMENT_LIST: // this is a statement list printf("statement_list\n"); for (si = tsi_start (stmt); !tsi_end_p (si); tsi_next (&si)) { process_stmt(tsi_stmt(si)); } break; case BIND_EXPR: // this is a bind expression printf("bind_expr\n"); process_stmt((BIND_EXPR_BODY(stmt))); break; case DECL_EXPR: // this is a desclare expression printf("decl_expr\n"); num_statements++; num_local_var++; break; case MODIFY_EXPR: // this is a modify expression printf("modify_expr\n"); num_statements++; break; case CALL_EXPR: // this is a function call expression printf("call_expr\n"); num_statements++; break; case RETURN_EXPR: // this is a return value expression printf("return_expr\n"); num_statements++; break; case COND_EXPR: // this is a conditional branch expression printf("cond_expr\n"); tree then_node = COND_EXPR_THEN(stmt); tree else_node = COND_EXPR_ELSE(stmt); if (!(then_node && TREE_CODE(then_node) == GOTO_EXPR && !EXPR_HAS_LOCATION(then_node) && else_node && TREE_CODE(else_node) == GOTO_EXPR && !EXPR_HAS_LOCATION(else_node))) { num_statements++; } process_stmt(COND_EXPR_THEN(stmt)); if (COND_EXPR_ELSE(stmt)) process_stmt(COND_EXPR_ELSE(stmt)); break; case SWITCH_EXPR: // this is a switch branch expression printf("switch_expr\n"); num_statements++; process_stmt(SWITCH_BODY(stmt)); break; case CASE_LABEL_EXPR: // this is a case label expression printf("case_label_expr\n"); break; case GOTO_EXPR: // this is a jump expression printf("goto_expr\n"); // if (!DECL_IS_BUILTIN(GOTO_DESTINATION (stmt))) // num_statements++; if (EXPR_HAS_LOCATION(stmt)) { num_statements++; } break; case LABEL_EXPR: // this is a jump destination label expression printf("label_expr\n"); break; default: printf("default\n"); break; } // printf("number of statements: %d\n", num_statements); }
static void check_init (tree exp, words before) { tree tmp; location_t save_location = input_location; again: if (EXPR_HAS_LOCATION (exp)) input_location = EXPR_LOCATION (exp); switch (TREE_CODE (exp)) { case VAR_DECL: case PARM_DECL: if (! FIELD_STATIC (exp) && DECL_NAME (exp) != NULL_TREE && DECL_NAME (exp) != this_identifier_node) { int index = DECL_BIT_INDEX (exp); /* We don't want to report and mark as non initialized class initialization flags. */ if (! LOCAL_CLASS_INITIALIZATION_FLAG_P (exp) && index >= 0 && ! ASSIGNED_P (before, index)) { error ("variable %qD may not have been initialized", exp); DECL_BIT_INDEX (exp) = -2; } } break; case COMPONENT_REF: check_init (TREE_OPERAND (exp, 0), before); if ((tmp = get_variable_decl (exp)) != NULL_TREE) { int index = DECL_BIT_INDEX (tmp); if (index >= 0 && ! ASSIGNED_P (before, index)) { error ("variable %qD may not have been initialized", tmp); /* Suppress further errors. */ DECL_BIT_INDEX (tmp) = -2; } } break; case MODIFY_EXPR: tmp = TREE_OPERAND (exp, 0); /* We're interested in variable declaration and parameter declaration when they're declared with the `final' modifier. */ if ((tmp = get_variable_decl (tmp)) != NULL_TREE) { int index; check_init (TREE_OPERAND (exp, 1), before); check_final_reassigned (tmp, before); index = DECL_BIT_INDEX (tmp); if (index >= 0) { SET_ASSIGNED (before, index); CLEAR_UNASSIGNED (before, index); } /* Minor optimization. See comment for start_current_locals. If we're optimizing for class initialization, we keep this information to check whether the variable is definitely assigned when once we checked the whole function. */ if (! STATIC_CLASS_INIT_OPT_P () /* FIXME */ && ! DECL_FINAL (tmp) && index >= start_current_locals && index == num_current_locals - 1) { num_current_locals--; DECL_BIT_INDEX (tmp) = -1; } break; } else if (TREE_CODE (tmp = TREE_OPERAND (exp, 0)) == COMPONENT_REF) { tree decl; check_init (tmp, before); check_init (TREE_OPERAND (exp, 1), before); decl = TREE_OPERAND (tmp, 1); if (DECL_FINAL (decl)) final_assign_error (DECL_NAME (decl)); break; } else if (TREE_CODE (tmp) == COMPONENT_REF && IS_ARRAY_LENGTH_ACCESS (tmp)) { /* We can't emit a more specific message here, because when compiling to bytecodes we don't get here. */ final_assign_error (length_identifier_node); } else goto binop; case BLOCK: if (BLOCK_EXPR_BODY (exp)) { tree decl = BLOCK_EXPR_DECLS (exp); int words_needed; word* tmp; int i; int save_start_current_locals = start_current_locals; int save_num_current_words = num_current_words; start_current_locals = num_current_locals; for (; decl != NULL_TREE; decl = TREE_CHAIN (decl)) { DECL_BIT_INDEX (decl) = num_current_locals++; } words_needed = WORDS_NEEDED (2 * num_current_locals); if (words_needed > num_current_words) { tmp = ALLOC_WORDS (words_needed); COPY (tmp, before); num_current_words = words_needed; } else tmp = before; for (i = start_current_locals; i < num_current_locals; i++) { CLEAR_ASSIGNED (tmp, i); SET_UNASSIGNED (tmp, i); } check_init (BLOCK_EXPR_BODY (exp), tmp); /* Re-set DECL_BIT_INDEX since it is also DECL_POINTER_ALIAS_SET. */ for (decl = BLOCK_EXPR_DECLS (exp); decl != NULL_TREE; decl = TREE_CHAIN (decl)) { if (LOCAL_CLASS_INITIALIZATION_FLAG_P (decl)) { int index = DECL_BIT_INDEX (decl); tree fndecl = DECL_CONTEXT (decl); if (fndecl && METHOD_STATIC (fndecl) && (DECL_INITIAL (decl) == boolean_true_node || (index >= 0 && ASSIGNED_P (tmp, index)))) *(htab_find_slot (DECL_FUNCTION_INITIALIZED_CLASS_TABLE (fndecl), DECL_FUNCTION_INIT_TEST_CLASS (decl), INSERT)) = DECL_FUNCTION_INIT_TEST_CLASS (decl); } DECL_BIT_INDEX (decl) = -1; } num_current_locals = start_current_locals; start_current_locals = save_start_current_locals; if (tmp != before) { num_current_words = save_num_current_words; COPY (before, tmp); FREE_WORDS (tmp); } } break; case LOOP_EXPR: { /* The JLS 2nd edition discusses a complication determining definite unassignment of loop statements. They define a "hypothetical" analysis model. We do something much simpler: We just disallow assignments inside loops to final variables declared outside the loop. This means we may disallow some contrived assignments that the JLS, but I can't see how anything except a very contrived testcase (a do-while whose condition is false?) would care. */ struct alternatives alt; int save_loop_current_locals = loop_current_locals; int save_start_current_locals = start_current_locals; loop_current_locals = num_current_locals; start_current_locals = num_current_locals; BEGIN_ALTERNATIVES (before, alt); alt.block = exp; check_init (TREE_OPERAND (exp, 0), before); END_ALTERNATIVES (before, alt); loop_current_locals = save_loop_current_locals; start_current_locals = save_start_current_locals; break; } case EXIT_EXPR: { struct alternatives *alt = alternatives; DECLARE_BUFFERS(when_true, 2); words when_false = when_true + num_current_words; #ifdef ENABLE_JC1_CHECKING gcc_assert (TREE_CODE (alt->block) == LOOP_EXPR); #endif check_bool_init (TREE_OPERAND (exp, 0), before, when_false, when_true); done_alternative (when_true, alt); COPY (before, when_false); RELEASE_BUFFERS(when_true); break; } case LABELED_BLOCK_EXPR: { struct alternatives alt; BEGIN_ALTERNATIVES (before, alt); alt.block = exp; if (LABELED_BLOCK_BODY (exp)) check_init (LABELED_BLOCK_BODY (exp), before); done_alternative (before, &alt); END_ALTERNATIVES (before, alt); break; } case EXIT_BLOCK_EXPR: { tree block = TREE_OPERAND (exp, 0); struct alternatives *alt = alternatives; while (alt->block != block) alt = alt->outer; done_alternative (before, alt); SET_ALL (before); break; } case SWITCH_EXPR: { struct alternatives alt; word buf[2]; check_init (TREE_OPERAND (exp, 0), before); BEGIN_ALTERNATIVES (before, alt); alt.saved = ALLOC_BUFFER(buf, num_current_words); COPY (alt.saved, before); alt.block = exp; check_init (TREE_OPERAND (exp, 1), before); done_alternative (before, &alt); if (! SWITCH_HAS_DEFAULT (exp)) done_alternative (alt.saved, &alt); FREE_BUFFER(alt.saved, buf); END_ALTERNATIVES (before, alt); break; } case CASE_EXPR: case DEFAULT_EXPR: { int i; struct alternatives *alt = alternatives; while (TREE_CODE (alt->block) != SWITCH_EXPR) alt = alt->outer; COPYN (before, alt->saved, WORDS_NEEDED (2 * alt->num_locals)); for (i = alt->num_locals; i < num_current_locals; i++) CLEAR_ASSIGNED (before, i); break; } case TRY_EXPR: { tree try_clause = TREE_OPERAND (exp, 0); tree clause = TREE_OPERAND (exp, 1); word buf[2*2]; words tmp = (num_current_words <= 2 ? buf : ALLOC_WORDS (2 * num_current_words)); words save = tmp + num_current_words; struct alternatives alt; BEGIN_ALTERNATIVES (before, alt); COPY (save, before); COPY (tmp, save); check_init (try_clause, tmp); done_alternative (tmp, &alt); for ( ; clause != NULL_TREE; clause = TREE_CHAIN (clause)) { tree catch_clause = TREE_OPERAND (clause, 0); COPY (tmp, save); check_init (catch_clause, tmp); done_alternative (tmp, &alt); } if (tmp != buf) { FREE_WORDS (tmp); } END_ALTERNATIVES (before, alt); } break; case TRY_FINALLY_EXPR: { DECLARE_BUFFERS(tmp, 1); COPY (tmp, before); check_init (TREE_OPERAND (exp, 0), before); check_init (TREE_OPERAND (exp, 1), tmp); UNION (before, before, tmp); RELEASE_BUFFERS(tmp); } break; case RETURN_EXPR: case THROW_EXPR: if (TREE_OPERAND (exp, 0)) check_init (TREE_OPERAND (exp, 0), before); goto never_continues; case ERROR_MARK: never_continues: SET_ALL (before); break; case COND_EXPR: case TRUTH_ANDIF_EXPR: case TRUTH_ORIF_EXPR: { DECLARE_BUFFERS(when_true, 2); words when_false = when_true + num_current_words; check_bool_init (exp, before, when_false, when_true); INTERSECT (before, when_false, when_true); RELEASE_BUFFERS(when_true); } break; case NOP_EXPR: if (IS_EMPTY_STMT (exp)) break; /* ... else fall through ... */ case UNARY_PLUS_EXPR: case NEGATE_EXPR: case TRUTH_AND_EXPR: case TRUTH_OR_EXPR: case TRUTH_XOR_EXPR: case TRUTH_NOT_EXPR: case BIT_NOT_EXPR: case CONVERT_EXPR: case VIEW_CONVERT_EXPR: case BIT_FIELD_REF: case FLOAT_EXPR: case FIX_TRUNC_EXPR: case INDIRECT_REF: case ADDR_EXPR: case NON_LVALUE_EXPR: case INSTANCEOF_EXPR: case FIX_CEIL_EXPR: case FIX_FLOOR_EXPR: case FIX_ROUND_EXPR: case ABS_EXPR: /* Avoid needless recursion. */ exp = TREE_OPERAND (exp, 0); goto again; case PREDECREMENT_EXPR: case PREINCREMENT_EXPR: case POSTDECREMENT_EXPR: case POSTINCREMENT_EXPR: tmp = get_variable_decl (TREE_OPERAND (exp, 0)); if (tmp != NULL_TREE && DECL_FINAL (tmp)) final_assign_error (DECL_NAME (tmp)); else if (TREE_CODE (tmp = TREE_OPERAND (exp, 0)) == COMPONENT_REF) { /* Take care of array length accesses too. */ tree decl = TREE_OPERAND (tmp, 1); if (DECL_FINAL (decl)) final_assign_error (DECL_NAME (decl)); } /* Avoid needless recursion. */ exp = TREE_OPERAND (exp, 0); goto again; case SAVE_EXPR: if (IS_INIT_CHECKED (exp)) break; IS_INIT_CHECKED (exp) = 1; exp = TREE_OPERAND (exp, 0); goto again; case COMPOUND_EXPR: case PLUS_EXPR: case MINUS_EXPR: case MULT_EXPR: case TRUNC_DIV_EXPR: case TRUNC_MOD_EXPR: case RDIV_EXPR: case LSHIFT_EXPR: case RSHIFT_EXPR: case URSHIFT_EXPR: case BIT_AND_EXPR: case BIT_XOR_EXPR: case BIT_IOR_EXPR: case EQ_EXPR: case NE_EXPR: case GT_EXPR: case GE_EXPR: case LT_EXPR: case LE_EXPR: case MAX_EXPR: case MIN_EXPR: case ARRAY_REF: case LROTATE_EXPR: case RROTATE_EXPR: case CEIL_DIV_EXPR: case FLOOR_DIV_EXPR: case ROUND_DIV_EXPR: case CEIL_MOD_EXPR: case FLOOR_MOD_EXPR: case ROUND_MOD_EXPR: case EXACT_DIV_EXPR: case UNLT_EXPR: case UNLE_EXPR: case UNGT_EXPR: case UNGE_EXPR: case UNEQ_EXPR: case LTGT_EXPR: binop: check_init (TREE_OPERAND (exp, 0), before); /* Avoid needless recursion, especially for COMPOUND_EXPR. */ exp = TREE_OPERAND (exp, 1); goto again; case RESULT_DECL: case FUNCTION_DECL: case INTEGER_CST: case REAL_CST: case STRING_CST: case DECL_EXPR: case JAVA_EXC_OBJ_EXPR: break; case NEW_CLASS_EXPR: case CALL_EXPR: { tree func = TREE_OPERAND (exp, 0); tree x = TREE_OPERAND (exp, 1); if (TREE_CODE (func) == ADDR_EXPR) func = TREE_OPERAND (func, 0); check_init (func, before); for ( ; x != NULL_TREE; x = TREE_CHAIN (x)) check_init (TREE_VALUE (x), before); if (func == throw_node) goto never_continues; } break; case NEW_ARRAY_INIT: { tree value; unsigned HOST_WIDE_INT idx; FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (TREE_OPERAND (exp, 0)), idx, value) check_init (value, before); } break; case EXPR_WITH_FILE_LOCATION: { location_t saved_location = input_location; tree body = EXPR_WFL_NODE (exp); if (IS_EMPTY_STMT (body)) break; #ifdef USE_MAPPED_LOCATION input_location = EXPR_LOCATION (exp); #else input_filename = EXPR_WFL_FILENAME (exp); input_line = EXPR_WFL_LINENO (exp); #endif check_init (body, before); input_location = saved_location; } break; default: internal_error ("internal error in check-init: tree code not implemented: %s", tree_code_name [(int) TREE_CODE (exp)]); } input_location = save_location; }
int cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) { int saved_stmts_are_full_exprs_p = 0; 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 PTRMEM_CST: *expr_p = cplus_expand_constant (*expr_p); ret = GS_OK; break; 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); cp_genericize_tree (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: if (fn_contains_cilk_spawn_p (cfun) && cilk_detect_spawn_and_unwrap (expr_p) && !seen_error ()) return (enum gimplify_status) gimplify_cilk_spawn (expr_p); cp_gimplify_init_expr (expr_p); if (TREE_CODE (*expr_p) != INIT_EXPR) return GS_OK; /* Otherwise fall through. */ case MODIFY_EXPR: { if (fn_contains_cilk_spawn_p (cfun) && cilk_detect_spawn_and_unwrap (expr_p) && !seen_error ()) return (enum gimplify_status) gimplify_cilk_spawn (expr_p); /* 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 ((is_gimple_lvalue (op1) || INDIRECT_REF_P (op1) || (TREE_CODE (op1) == CONSTRUCTOR && CONSTRUCTOR_NELTS (op1) == 0 && !TREE_CLOBBER_P (op1)) || (TREE_CODE (op1) == CALL_EXPR && !CALL_EXPR_RETURN_SLOT_OPT (op1))) && is_really_empty_class (TREE_TYPE (op0))) { /* Remove any copies of empty classes. We check that the RHS 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 (FIXME so it shouldn't be represented as one). Also drop volatile variables on the RHS to avoid infinite recursion from gimplify_expr trying to load the value. */ if (!TREE_SIDE_EFFECTS (op1) || (DECL_P (op1) && TREE_THIS_VOLATILE (op1))) *expr_p = op0; else if (TREE_CODE (op1) == MEM_REF && TREE_THIS_VOLATILE (op1)) { /* Similarly for volatile MEM_REFs on the RHS. */ if (!TREE_SIDE_EFFECTS (TREE_OPERAND (op1, 0))) *expr_p = op0; else *expr_p = build2 (COMPOUND_EXPR, TREE_TYPE (*expr_p), TREE_OPERAND (op1, 0), op0); } else *expr_p = build2 (COMPOUND_EXPR, TREE_TYPE (*expr_p), op0, op1); } } 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: 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 CILK_SPAWN_STMT: gcc_assert (fn_contains_cilk_spawn_p (cfun) && cilk_detect_spawn_and_unwrap (expr_p)); /* If errors are seen, then just process it as a CALL_EXPR. */ if (!seen_error ()) return (enum gimplify_status) gimplify_cilk_spawn (expr_p); case CALL_EXPR: if (fn_contains_cilk_spawn_p (cfun) && cilk_detect_spawn_and_unwrap (expr_p) && !seen_error ()) return (enum gimplify_status) gimplify_cilk_spawn (expr_p); 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; }
void gcc_dump_stmt (dump_info_p di, const_tree t) { if (EXPR_HAS_LOCATION (t)) gcc_dump_int (di, "line", EXPR_LINENO (t)); }