static void validate_unchecked_conversion (Node_Id);
static tree maybe_implicit_deref (tree);
static void set_expr_location_from_node (tree, Node_Id);
+static void set_expr_location_from_node1 (tree, Node_Id, bool);
+static bool Sloc_to_locus1 (Source_Ptr, location_t *, bool);
static bool set_end_locus_from_node (tree, Node_Id);
static void set_gnu_expr_location_from_node (tree, Node_Id);
static int lvalue_required_p (Node_Id, tree, bool, bool, bool);
tree gnu_result;
tree gnu_expr;
Node_Id gnat_temp;
+ /* Node providing the sloc for the cleanup actions. */
+ Node_Id gnat_cleanup_loc_node = (Present (End_Label (gnat_node)) ?
+ End_Label (gnat_node) :
+ gnat_node);
/* The GCC exception handling mechanism can handle both ZCX and SJLJ schemes
and we have our own SJLJ mechanism. To call the GCC mechanism, we call
/* When we exit this block, restore the saved value. */
add_cleanup (build_call_n_expr (set_jmpbuf_decl, 1, gnu_jmpsave_decl),
- End_Label (gnat_node));
+ gnat_cleanup_loc_node);
}
/* If we are to call a function when exiting this block, add a cleanup
so we must register this cleanup after the EH cleanup just above. */
if (at_end)
add_cleanup (build_call_n_expr (gnat_to_gnu (At_End_Proc (gnat_node)), 0),
- End_Label (gnat_node));
+ gnat_cleanup_loc_node);
/* Now build the tree for the declarations and statements inside this block.
If this is SJLJ, set our jmp_buf as the current buffer. */
/* Now make the TRY_CATCH_EXPR for the block. */
gnu_result = build2 (TRY_CATCH_EXPR, void_type_node,
gnu_inner_block, gnu_handlers);
- /* Set a location. We need to find a uniq location for the dispatching
+ /* Set a location. We need to find a unique location for the dispatching
code, otherwise we can get coverage or debugging issues. Try with
the location of the end label. */
if (Present (End_Label (gnat_node))
&& Sloc_to_locus (Sloc (End_Label (gnat_node)), &locus))
SET_EXPR_LOCATION (gnu_result, locus);
else
- set_expr_location_from_node (gnu_result, gnat_node);
+ /* Clear column information so that the exception handler of an
+ implicit transient block does not incorrectly inherit the slocs
+ of a decision, which would otherwise confuse control flow based
+ coverage analysis tools. */
+ set_expr_location_from_node1 (gnu_result, gnat_node, True);
}
else
gnu_result = gnu_inner_block;
add_stmt_with_node (build_call_n_expr (begin_handler_decl, 1,
gnu_incoming_exc_ptr),
gnat_node);
- /* ??? We don't seem to have an End_Label at hand to set the location. */
+ /* We don't have an End_Label at hand to set the location of the cleanup
+ actions, so we use that of the exception handler itself instead. */
add_cleanup (build_call_n_expr (end_handler_decl, 1, gnu_incoming_exc_ptr),
- Empty);
+ gnat_node);
add_stmt_list (Statements (gnat_node));
gnat_poplevel ();
}
/* Add GNU_CLEANUP, a cleanup action, to the current code group and
- set its location to that of GNAT_NODE if present. */
+ set its location to that of GNAT_NODE if present, but with column info
+ cleared so that conditional branches generated as part of the cleanup
+ code do not interfere with coverage analysis tools. */
static void
add_cleanup (tree gnu_cleanup, Node_Id gnat_node)
{
if (Present (gnat_node))
- set_expr_location_from_node (gnu_cleanup, gnat_node);
+ set_expr_location_from_node1 (gnu_cleanup, gnat_node, True);
append_to_statement_list (gnu_cleanup, ¤t_stmt_group->cleanups);
}
\f
/* Convert SLOC into LOCUS. Return true if SLOC corresponds to a source code
location and false if it doesn't. In the former case, set the Gigi global
- variable REF_FILENAME to the simple debug file name as given by sinput. */
+ variable REF_FILENAME to the simple debug file name as given by sinput.
+ If clear_column is True, set column information to 0. */
-bool
-Sloc_to_locus (Source_Ptr Sloc, location_t *locus)
+static bool
+Sloc_to_locus1 (Source_Ptr Sloc, location_t *locus, bool clear_column)
{
if (Sloc == No_Location)
return false;
{
Source_File_Index file = Get_Source_File_Index (Sloc);
Logical_Line_Number line = Get_Logical_Line_Number (Sloc);
- Column_Number column = Get_Column_Number (Sloc);
+ Column_Number column = (clear_column ? 0 : Get_Column_Number (Sloc));
struct line_map *map = LINEMAPS_ORDINARY_MAP_AT (line_table, file - 1);
/* We can have zero if pragma Source_Reference is in effect. */
return true;
}
+/* Similar to the above, not clearing the column information. */
+
+bool
+Sloc_to_locus (Source_Ptr Sloc, location_t *locus)
+{
+ return Sloc_to_locus1 (Sloc, locus, False);
+}
+
/* Similar to set_expr_location, but start with the Sloc of GNAT_NODE and
don't do anything if it doesn't correspond to a source location. */
static void
-set_expr_location_from_node (tree node, Node_Id gnat_node)
+set_expr_location_from_node1 (tree node, Node_Id gnat_node, bool clear_column)
{
location_t locus;
- if (!Sloc_to_locus (Sloc (gnat_node), &locus))
+ if (!Sloc_to_locus1 (Sloc (gnat_node), &locus, clear_column))
return;
SET_EXPR_LOCATION (node, locus);
}
+/* Similar to the above, not clearing the column information. */
+
+static void
+set_expr_location_from_node (tree node, Node_Id gnat_node)
+{
+ set_expr_location_from_node1 (node, gnat_node, False);
+}
+
/* More elaborate version of set_expr_location_from_node to be used in more
general contexts, for example the result of the translation of a generic
GNAT node. */