summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ada/ChangeLog18
-rw-r--r--gcc/ada/gcc-interface/decl.c38
-rw-r--r--gcc/ada/gcc-interface/gigi.h10
-rw-r--r--gcc/ada/gcc-interface/trans.c164
-rw-r--r--gcc/ada/gcc-interface/utils.c18
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gnat.dg/warn6.adb13
-rw-r--r--gcc/testsuite/gnat.dg/warn6.ads15
8 files changed, 156 insertions, 124 deletions
diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog
index 68219cc05b1..e8421391e63 100644
--- a/gcc/ada/ChangeLog
+++ b/gcc/ada/ChangeLog
@@ -1,3 +1,21 @@
+2012-04-30 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gcc-interface/gigi.h (mark_out_of_scope): Delete.
+ (destroy_gnat_to_gnu): Declare.
+ (destroy_dummy_type): Likewise.
+ * gcc-interface/decl.c (mark_out_of_scope): Delete.
+ * gcc-interface/utils.c (destroy_gnat_to_gnu): New function.
+ (destroy_dummy_type): Likewise.
+ * gcc-interface/trans.c (gnat_validate_uc_list): New variable.
+ (gigi): Call validate_unchecked_conversion on gnat_validate_uc_list
+ after the translation is completed.  Call destroy_gnat_to_gnu and
+ destroy_dummy_type at the end.
+ (Subprogram_Body_to_gnu): Do not call mark_out_of_scope.
+ (gnat_to_gnu) <N_Block_Statement>: Likewise.
+ <N_Validate_Unchecked_Conversion>: Do not process the node, only push
+ it onto gnat_validate_uc_list.
+ (validate_unchecked_conversion): New function.
+
2012-04-26 Tristan Gingold <gingold@adacore.com>
* gcc-interface/Make-lang.in: Update dependencies.
diff --git a/gcc/ada/gcc-interface/decl.c b/gcc/ada/gcc-interface/decl.c
index dac9942237f..6f351d3db2e 100644
--- a/gcc/ada/gcc-interface/decl.c
+++ b/gcc/ada/gcc-interface/decl.c
@@ -5838,44 +5838,6 @@ elaborate_entity (Entity_Id gnat_entity)
}
}
-/* Mark GNAT_ENTITY as going out of scope at this point. Recursively mark
- any entities on its entity chain similarly. */
-
-void
-mark_out_of_scope (Entity_Id gnat_entity)
-{
- Entity_Id gnat_sub_entity;
- unsigned int kind = Ekind (gnat_entity);
-
- /* If this has an entity list, process all in the list. */
- if (IN (kind, Class_Wide_Kind) || IN (kind, Concurrent_Kind)
- || IN (kind, Private_Kind)
- || kind == E_Block || kind == E_Entry || kind == E_Entry_Family
- || kind == E_Function || kind == E_Generic_Function
- || kind == E_Generic_Package || kind == E_Generic_Procedure
- || kind == E_Loop || kind == E_Operator || kind == E_Package
- || kind == E_Package_Body || kind == E_Procedure
- || kind == E_Record_Type || kind == E_Record_Subtype
- || kind == E_Subprogram_Body || kind == E_Subprogram_Type)
- for (gnat_sub_entity = First_Entity (gnat_entity);
- Present (gnat_sub_entity);
- gnat_sub_entity = Next_Entity (gnat_sub_entity))
- if (Scope (gnat_sub_entity) == gnat_entity
- && gnat_sub_entity != gnat_entity)
- mark_out_of_scope (gnat_sub_entity);
-
- /* Now clear this if it has been defined, but only do so if it isn't
- a subprogram or parameter. We could refine this, but it isn't
- worth it. If this is statically allocated, it is supposed to
- hang around out of cope. */
- if (present_gnu_tree (gnat_entity) && !Is_Statically_Allocated (gnat_entity)
- && kind != E_Procedure && kind != E_Function && !IN (kind, Formal_Kind))
- {
- save_gnu_tree (gnat_entity, NULL_TREE, true);
- save_gnu_tree (gnat_entity, error_mark_node, true);
- }
-}
-
/* Relate the alias sets of GNU_NEW_TYPE and GNU_OLD_TYPE according to OP.
If this is a multi-dimensional array type, do this recursively.
diff --git a/gcc/ada/gcc-interface/gigi.h b/gcc/ada/gcc-interface/gigi.h
index c507615fbfd..fb1106f793e 100644
--- a/gcc/ada/gcc-interface/gigi.h
+++ b/gcc/ada/gcc-interface/gigi.h
@@ -108,10 +108,6 @@ extern Entity_Id Gigi_Equivalent_Type (Entity_Id gnat_entity);
be elaborated at the point of its definition, but do nothing else. */
extern void elaborate_entity (Entity_Id gnat_entity);
-/* Mark GNAT_ENTITY as going out of scope at this point. Recursively mark
- any entities on its entity chain similarly. */
-extern void mark_out_of_scope (Entity_Id gnat_entity);
-
/* Get the unpadded version of a GNAT type. */
extern tree get_unpadded_type (Entity_Id gnat_entity);
@@ -504,6 +500,9 @@ extern tree convert_to_index_type (tree expr);
/* Initialize the association of GNAT nodes to GCC trees. */
extern void init_gnat_to_gnu (void);
+/* Destroy the association of GNAT nodes to GCC trees. */
+extern void destroy_gnat_to_gnu (void);
+
/* GNAT_ENTITY is a GNAT tree node for a defining identifier.
GNU_DECL is the GCC tree which is to be associated with
GNAT_ENTITY. Such gnu tree node is always an ..._DECL node.
@@ -523,6 +522,9 @@ extern bool present_gnu_tree (Entity_Id gnat_entity);
/* Initialize the association of GNAT nodes to GCC trees as dummies. */
extern void init_dummy_type (void);
+/* Destroy the association of GNAT nodes to GCC trees as dummies. */
+extern void destroy_dummy_type (void);
+
/* Make a dummy type corresponding to GNAT_TYPE. */
extern tree make_dummy_type (Entity_Id gnat_type);
diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c
index cdcc2172275..3698dcaf2a4 100644
--- a/gcc/ada/gcc-interface/trans.c
+++ b/gcc/ada/gcc-interface/trans.c
@@ -109,6 +109,12 @@ bool type_annotate_only;
/* Current filename without path. */
const char *ref_filename;
+DEF_VEC_I(Node_Id);
+DEF_VEC_ALLOC_I(Node_Id,heap);
+
+/* List of N_Validate_Unchecked_Conversion nodes in the unit. */
+static VEC(Node_Id,heap) *gnat_validate_uc_list;
+
/* When not optimizing, we cache the 'First, 'Last and 'Length attributes
of unconstrained array IN parameters to avoid emitting a great deal of
redundant instructions to recompute them each time. */
@@ -251,6 +257,7 @@ static bool addressable_p (tree, tree);
static tree assoc_to_constructor (Entity_Id, Node_Id, tree);
static tree extract_values (tree, tree);
static tree pos_to_constructor (Node_Id, tree, Entity_Id);
+static void validate_unchecked_conversion (Node_Id);
static tree maybe_implicit_deref (tree);
static void set_expr_location_from_node (tree, Node_Id);
static bool set_end_locus_from_node (tree, Node_Id);
@@ -278,6 +285,7 @@ gigi (Node_Id gnat_root, int max_gnat_node, int number_name ATTRIBUTE_UNUSED,
Entity_Id standard_character, Entity_Id standard_long_long_float,
Entity_Id standard_exception_type, Int gigi_operating_mode)
{
+ Node_Id gnat_iter;
Entity_Id gnat_literal;
tree long_long_float_type, exception_type, t, ftype;
tree int64_type = gnat_type_for_size (64, 0);
@@ -648,6 +656,13 @@ gigi (Node_Id gnat_root, int max_gnat_node, int number_name ATTRIBUTE_UNUSED,
/* Now translate the compilation unit proper. */
Compilation_Unit_to_gnu (gnat_root);
+ /* Then process the N_Validate_Unchecked_Conversion nodes. We do this at
+ the very end to avoid having to second-guess the front-end when we run
+ into dummy nodes during the regular processing. */
+ for (i = 0; VEC_iterate (Node_Id, gnat_validate_uc_list, i, gnat_iter); i++)
+ validate_unchecked_conversion (gnat_iter);
+ VEC_free (Node_Id, heap, gnat_validate_uc_list);
+
/* Finally see if we have any elaboration procedures to deal with. */
for (info = elab_info_list; info; info = info->next)
{
@@ -669,6 +684,10 @@ gigi (Node_Id gnat_root, int max_gnat_node, int number_name ATTRIBUTE_UNUSED,
}
}
+ /* Destroy ourselves. */
+ destroy_gnat_to_gnu ();
+ destroy_dummy_type ();
+
/* We cannot track the location of errors past this point. */
error_gnat_node = Empty;
}
@@ -3480,8 +3499,6 @@ Subprogram_Body_to_gnu (Node_Id gnat_node)
/* If there is a stub associated with the function, build it now. */
if (DECL_FUNCTION_STUB (gnu_subprog_decl))
build_function_stub (gnu_subprog_decl, gnat_subprog_id);
-
- mark_out_of_scope (Defining_Unit_Name (Specification (gnat_node)));
}
/* Return true if GNAT_NODE requires atomic synchronization. */
@@ -6036,9 +6053,6 @@ gnat_to_gnu (Node_Id gnat_node)
add_stmt (gnat_to_gnu (Handled_Statement_Sequence (gnat_node)));
gnat_poplevel ();
gnu_result = end_stmt_group ();
-
- if (Present (Identifier (gnat_node)))
- mark_out_of_scope (Entity (Identifier (gnat_node)));
break;
case N_Exit_Statement:
@@ -6760,83 +6774,10 @@ gnat_to_gnu (Node_Id gnat_node)
break;
case N_Validate_Unchecked_Conversion:
- {
- Entity_Id gnat_target_type = Target_Type (gnat_node);
- tree gnu_source_type = gnat_to_gnu_type (Source_Type (gnat_node));
- tree gnu_target_type = gnat_to_gnu_type (gnat_target_type);
-
- /* No need for any warning in this case. */
- if (!flag_strict_aliasing)
- ;
-
- /* If the result is a pointer type, see if we are either converting
- from a non-pointer or from a pointer to a type with a different
- alias set and warn if so. If the result is defined in the same
- unit as this unchecked conversion, we can allow this because we
- can know to make the pointer type behave properly. */
- else if (POINTER_TYPE_P (gnu_target_type)
- && !In_Same_Source_Unit (gnat_target_type, gnat_node)
- && !No_Strict_Aliasing (Underlying_Type (gnat_target_type)))
- {
- tree gnu_source_desig_type = POINTER_TYPE_P (gnu_source_type)
- ? TREE_TYPE (gnu_source_type)
- : NULL_TREE;
- tree gnu_target_desig_type = TREE_TYPE (gnu_target_type);
-
- if ((TYPE_IS_DUMMY_P (gnu_target_desig_type)
- || get_alias_set (gnu_target_desig_type) != 0)
- && (!POINTER_TYPE_P (gnu_source_type)
- || (TYPE_IS_DUMMY_P (gnu_source_desig_type)
- != TYPE_IS_DUMMY_P (gnu_target_desig_type))
- || (TYPE_IS_DUMMY_P (gnu_source_desig_type)
- && gnu_source_desig_type != gnu_target_desig_type)
- || !alias_sets_conflict_p
- (get_alias_set (gnu_source_desig_type),
- get_alias_set (gnu_target_desig_type))))
- {
- post_error_ne
- ("?possible aliasing problem for type&",
- gnat_node, Target_Type (gnat_node));
- post_error
- ("\\?use -fno-strict-aliasing switch for references",
- gnat_node);
- post_error_ne
- ("\\?or use `pragma No_Strict_Aliasing (&);`",
- gnat_node, Target_Type (gnat_node));
- }
- }
-
- /* But if the result is a fat pointer type, we have no mechanism to
- do that, so we unconditionally warn in problematic cases. */
- else if (TYPE_IS_FAT_POINTER_P (gnu_target_type))
- {
- tree gnu_source_array_type
- = TYPE_IS_FAT_POINTER_P (gnu_source_type)
- ? TREE_TYPE (TREE_TYPE (TYPE_FIELDS (gnu_source_type)))
- : NULL_TREE;
- tree gnu_target_array_type
- = TREE_TYPE (TREE_TYPE (TYPE_FIELDS (gnu_target_type)));
-
- if ((TYPE_IS_DUMMY_P (gnu_target_array_type)
- || get_alias_set (gnu_target_array_type) != 0)
- && (!TYPE_IS_FAT_POINTER_P (gnu_source_type)
- || (TYPE_IS_DUMMY_P (gnu_source_array_type)
- != TYPE_IS_DUMMY_P (gnu_target_array_type))
- || (TYPE_IS_DUMMY_P (gnu_source_array_type)
- && gnu_source_array_type != gnu_target_array_type)
- || !alias_sets_conflict_p
- (get_alias_set (gnu_source_array_type),
- get_alias_set (gnu_target_array_type))))
- {
- post_error_ne
- ("?possible aliasing problem for type&",
- gnat_node, Target_Type (gnat_node));
- post_error
- ("\\?use -fno-strict-aliasing switch for references",
- gnat_node);
- }
- }
- }
+ /* The only validation we currently do on an unchecked conversion is
+ that of aliasing assumptions. */
+ if (flag_strict_aliasing)
+ VEC_safe_push (Node_Id, heap, gnat_validate_uc_list, gnat_node);
gnu_result = alloc_stmt_list ();
break;
@@ -8723,6 +8664,65 @@ extract_values (tree values, tree record_type)
return gnat_build_constructor (record_type, v);
}
+/* Process a N_Validate_Unchecked_Conversion node. */
+
+static void
+validate_unchecked_conversion (Node_Id gnat_node)
+{
+ tree gnu_source_type = gnat_to_gnu_type (Source_Type (gnat_node));
+ tree gnu_target_type = gnat_to_gnu_type (Target_Type (gnat_node));
+
+ /* If the target is a pointer type, see if we are either converting from a
+ non-pointer or from a pointer to a type with a different alias set and
+ warn if so, unless the pointer has been marked to alias everything. */
+ if (POINTER_TYPE_P (gnu_target_type)
+ && !TYPE_REF_CAN_ALIAS_ALL (gnu_target_type))
+ {
+ tree gnu_source_desig_type = POINTER_TYPE_P (gnu_source_type)
+ ? TREE_TYPE (gnu_source_type)
+ : NULL_TREE;
+ tree gnu_target_desig_type = TREE_TYPE (gnu_target_type);
+ alias_set_type target_alias_set = get_alias_set (gnu_target_desig_type);
+
+ if (target_alias_set != 0
+ && (!POINTER_TYPE_P (gnu_source_type)
+ || !alias_sets_conflict_p (get_alias_set (gnu_source_desig_type),
+ target_alias_set)))
+ {
+ post_error_ne ("?possible aliasing problem for type&",
+ gnat_node, Target_Type (gnat_node));
+ post_error ("\\?use -fno-strict-aliasing switch for references",
+ gnat_node);
+ post_error_ne ("\\?or use `pragma No_Strict_Aliasing (&);`",
+ gnat_node, Target_Type (gnat_node));
+ }
+ }
+
+ /* Likewise if the target is a fat pointer type, but we have no mechanism to
+ mitigate the problem in this case, so we unconditionally warn. */
+ else if (TYPE_IS_FAT_POINTER_P (gnu_target_type))
+ {
+ tree gnu_source_desig_type
+ = TYPE_IS_FAT_POINTER_P (gnu_source_type)
+ ? TREE_TYPE (TREE_TYPE (TYPE_FIELDS (gnu_source_type)))
+ : NULL_TREE;
+ tree gnu_target_desig_type
+ = TREE_TYPE (TREE_TYPE (TYPE_FIELDS (gnu_target_type)));
+ alias_set_type target_alias_set = get_alias_set (gnu_target_desig_type);
+
+ if (target_alias_set != 0
+ && (!TYPE_IS_FAT_POINTER_P (gnu_source_type)
+ || !alias_sets_conflict_p (get_alias_set (gnu_source_desig_type),
+ target_alias_set)))
+ {
+ post_error_ne ("?possible aliasing problem for type&",
+ gnat_node, Target_Type (gnat_node));
+ post_error ("\\?use -fno-strict-aliasing switch for references",
+ gnat_node);
+ }
+ }
+}
+
/* EXP is to be treated as an array or record. Handle the cases when it is
an access object and perform the required dereferences. */
diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c
index 41f83bfbe8a..123c3a5705c 100644
--- a/gcc/ada/gcc-interface/utils.c
+++ b/gcc/ada/gcc-interface/utils.c
@@ -231,6 +231,15 @@ init_gnat_to_gnu (void)
associate_gnat_to_gnu = ggc_alloc_cleared_vec_tree (max_gnat_nodes);
}
+/* Destroy the association of GNAT nodes to GCC trees. */
+
+void
+destroy_gnat_to_gnu (void)
+{
+ ggc_free (associate_gnat_to_gnu);
+ associate_gnat_to_gnu = NULL;
+}
+
/* GNAT_ENTITY is a GNAT tree node for an entity. Associate GNU_DECL, a GCC
tree node, with GNAT_ENTITY. If GNU_DECL is not a ..._DECL node, abort.
If NO_CHECK is true, the latter check is suppressed.
@@ -280,6 +289,15 @@ init_dummy_type (void)
dummy_node_table = ggc_alloc_cleared_vec_tree (max_gnat_nodes);
}
+/* Destroy the association of GNAT nodes to GCC trees as dummies. */
+
+void
+destroy_dummy_type (void)
+{
+ ggc_free (dummy_node_table);
+ dummy_node_table = NULL;
+}
+
/* Make a dummy type corresponding to GNAT_TYPE. */
tree
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 532c335d926..45bda58a079 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2012-04-30 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gnat.dg/warn6.ad[sb]: New test.
+
2012-04-29 Manuel López-Ibáñez <manu@gcc.gnu.org>
PR 53149
diff --git a/gcc/testsuite/gnat.dg/warn6.adb b/gcc/testsuite/gnat.dg/warn6.adb
new file mode 100644
index 00000000000..0a388f14844
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/warn6.adb
@@ -0,0 +1,13 @@
+-- { dg-do compile }
+-- { dg-options "-O2" }
+
+with Unchecked_Conversion;
+with System;
+
+package body Warn6 is
+
+ function Conv is new Unchecked_Conversion (System.Address, Q_T);
+
+ procedure Dummy is begin null; end;
+
+end Warn6;
diff --git a/gcc/testsuite/gnat.dg/warn6.ads b/gcc/testsuite/gnat.dg/warn6.ads
new file mode 100644
index 00000000000..e7495ead101
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/warn6.ads
@@ -0,0 +1,15 @@
+package Warn6 is
+
+ package Q is
+ type T is private; -- this is the trigger
+ private
+ type T is access Integer;
+ pragma No_Strict_Aliasing (T);
+
+ end Q;
+
+ subtype Q_T is Q.T;
+
+ procedure Dummy;
+
+end Warn6;