+/* Create nonlocal debug decls for nonlocal VLA array bounds. */
+
+static void
+note_nonlocal_vla_type (struct nesting_info *info, tree type)
+{
+ while (POINTER_TYPE_P (type) && !TYPE_NAME (type))
+ type = TREE_TYPE (type);
+
+ if (TYPE_NAME (type)
+ && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
+ && DECL_ORIGINAL_TYPE (TYPE_NAME (type)))
+ type = DECL_ORIGINAL_TYPE (TYPE_NAME (type));
+
+ while (POINTER_TYPE_P (type)
+ || TREE_CODE (type) == VECTOR_TYPE
+ || TREE_CODE (type) == FUNCTION_TYPE
+ || TREE_CODE (type) == METHOD_TYPE)
+ type = TREE_TYPE (type);
+
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ tree domain, t;
+
+ note_nonlocal_vla_type (info, TREE_TYPE (type));
+ domain = TYPE_DOMAIN (type);
+ if (domain)
+ {
+ t = TYPE_MIN_VALUE (domain);
+ if (t && (TREE_CODE (t) == VAR_DECL || TREE_CODE (t) == PARM_DECL)
+ && decl_function_context (t) != info->context)
+ get_nonlocal_debug_decl (info, t);
+ t = TYPE_MAX_VALUE (domain);
+ if (t && (TREE_CODE (t) == VAR_DECL || TREE_CODE (t) == PARM_DECL)
+ && decl_function_context (t) != info->context)
+ get_nonlocal_debug_decl (info, t);
+ }
+ }
+}
+
+/* Create nonlocal debug decls for nonlocal VLA array bounds for VLAs
+ in BLOCK. */
+
+static void
+note_nonlocal_block_vlas (struct nesting_info *info, tree block)
+{
+ tree var;
+
+ for (var = BLOCK_VARS (block); var; var = TREE_CHAIN (var))
+ if (TREE_CODE (var) == VAR_DECL
+ && variably_modified_type_p (TREE_TYPE (var), NULL)
+ && DECL_HAS_VALUE_EXPR_P (var)
+ && decl_function_context (var) != info->context)
+ note_nonlocal_vla_type (info, TREE_TYPE (var));
+}
+
+/* Callback for walk_gimple_stmt. Rewrite all references to VAR and
+ PARM_DECLs that belong to outer functions. This handles statements
+ that are not handled via the standard recursion done in
+ walk_gimple_stmt. STMT is the statement to examine, DATA is as in
+ convert_nonlocal_reference_op. Set *HANDLED_OPS_P to true if all the
+ operands of STMT have been handled by this function. */
+
+static tree
+convert_nonlocal_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p,
+ struct walk_stmt_info *wi)
+{
+ struct nesting_info *info = (struct nesting_info *) wi->info;
+ tree save_local_var_chain;
+ bitmap save_suppress;
+ gimple stmt = gsi_stmt (*gsi);
+
+ switch (gimple_code (stmt))
+ {
+ case GIMPLE_GOTO:
+ /* Don't walk non-local gotos for now. */
+ if (TREE_CODE (gimple_goto_dest (stmt)) != LABEL_DECL)
+ {
+ wi->val_only = true;
+ wi->is_lhs = false;
+ *handled_ops_p = true;
+ return NULL_TREE;
+ }
+ break;
+
+ case GIMPLE_OMP_PARALLEL:
+ case GIMPLE_OMP_TASK:
+ save_suppress = info->suppress_expansion;
+ if (convert_nonlocal_omp_clauses (gimple_omp_taskreg_clauses_ptr (stmt),
+ wi))
+ {
+ tree c, decl;
+ decl = get_chain_decl (info);
+ c = build_omp_clause (gimple_location (stmt),
+ OMP_CLAUSE_FIRSTPRIVATE);
+ OMP_CLAUSE_DECL (c) = decl;
+ OMP_CLAUSE_CHAIN (c) = gimple_omp_taskreg_clauses (stmt);
+ gimple_omp_taskreg_set_clauses (stmt, c);
+ }
+
+ save_local_var_chain = info->new_local_var_chain;
+ info->new_local_var_chain = NULL;
+
+ walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op,
+ info, gimple_omp_body (stmt));
+
+ if (info->new_local_var_chain)
+ declare_vars (info->new_local_var_chain,
+ gimple_seq_first_stmt (gimple_omp_body (stmt)),
+ false);
+ info->new_local_var_chain = save_local_var_chain;
+ info->suppress_expansion = save_suppress;
+ break;
+
+ case GIMPLE_OMP_FOR:
+ save_suppress = info->suppress_expansion;
+ convert_nonlocal_omp_clauses (gimple_omp_for_clauses_ptr (stmt), wi);
+ walk_gimple_omp_for (stmt, convert_nonlocal_reference_stmt,
+ convert_nonlocal_reference_op, info);
+ walk_body (convert_nonlocal_reference_stmt,
+ convert_nonlocal_reference_op, info, gimple_omp_body (stmt));
+ info->suppress_expansion = save_suppress;
+ break;
+
+ case GIMPLE_OMP_SECTIONS:
+ save_suppress = info->suppress_expansion;
+ convert_nonlocal_omp_clauses (gimple_omp_sections_clauses_ptr (stmt), wi);
+ walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op,
+ info, gimple_omp_body (stmt));
+ info->suppress_expansion = save_suppress;
+ break;
+
+ case GIMPLE_OMP_SINGLE:
+ save_suppress = info->suppress_expansion;
+ convert_nonlocal_omp_clauses (gimple_omp_single_clauses_ptr (stmt), wi);
+ walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op,
+ info, gimple_omp_body (stmt));
+ info->suppress_expansion = save_suppress;
+ break;
+
+ case GIMPLE_OMP_SECTION:
+ case GIMPLE_OMP_MASTER:
+ case GIMPLE_OMP_ORDERED:
+ walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op,
+ info, gimple_omp_body (stmt));
+ break;
+
+ case GIMPLE_BIND:
+ if (!optimize && gimple_bind_block (stmt))
+ note_nonlocal_block_vlas (info, gimple_bind_block (stmt));
+
+ *handled_ops_p = false;
+ return NULL_TREE;
+
+ case GIMPLE_COND:
+ wi->val_only = true;
+ wi->is_lhs = false;
+ *handled_ops_p = false;
+ return NULL_TREE;
+
+ default:
+ /* For every other statement that we are not interested in
+ handling here, let the walker traverse the operands. */
+ *handled_ops_p = false;
+ return NULL_TREE;
+ }
+
+ /* We have handled all of STMT operands, no need to traverse the operands. */
+ *handled_ops_p = true;
+ return NULL_TREE;
+}
+
+