diff options
Diffstat (limited to 'gcc/ada/trans.c')
-rw-r--r-- | gcc/ada/trans.c | 71 |
1 files changed, 38 insertions, 33 deletions
diff --git a/gcc/ada/trans.c b/gcc/ada/trans.c index f3dc87d..82aaa99 100644 --- a/gcc/ada/trans.c +++ b/gcc/ada/trans.c @@ -4832,34 +4832,41 @@ gnat_to_gnu (Node_Id gnat_node) || CONTAINS_PLACEHOLDER_P (TYPE_SIZE (gnu_result_type)))) gnu_result = gnat_stabilize_reference (gnu_result, false); - /* Now convert the result to the proper type. If the type is void or if - we have no result, return error_mark_node to show we have no result. - If the type of the result is correct or if we have a label (which doesn't - have any well-defined type), return our result. Also don't do the - conversion if the "desired" type involves a PLACEHOLDER_EXPR in its size - since those are the cases where the front end may have the type wrong due - to "instantiating" the unconstrained record with discriminant values - or if this is a FIELD_DECL. If this is the Name of an assignment - statement or a parameter of a procedure call, return what we have since - the RHS has to be converted to our type there in that case, unless - GNU_RESULT_TYPE has a simpler size. Similarly, if the two types are - record types with the same name and GNU_RESULT_TYPE has BLKmode, don't - convert. This will be the case when we are converting from a packable - type to its actual type and we need those conversions to be NOPs in - order for assignments into these types to work properly. Finally, - don't convert integral types that are the operand of an unchecked - conversion since we need to ignore those conversions (for 'Valid). - Otherwise, convert the result to the proper type. */ + /* Now convert the result to the result type, unless we are in one of the + following cases: + + 1. If this is the Name of an assignment statement or a parameter of + a procedure call, return the result almost unmodified since the + RHS will have to be converted to our type in that case, unless + the result type has a simpler size. Similarly, don't convert + integral types that are the operands of an unchecked conversion + since we need to ignore those conversions (for 'Valid). + + 2. If we have a label (which doesn't have any well-defined type), a + field or an error, return the result almost unmodified. Also don't + do the conversion if the result type involves a PLACEHOLDER_EXPR in + its size since those are the cases where the front end may have the + type wrong due to "instantiating" the unconstrained record with + discriminant values. Similarly, if the two types are record types + with the same name and the result type has BLKmode, don't convert. + This will be the case when we are converting from a packed version + of a type to its original type and we need those conversions to be + NOPs in order for assignments into these types to work properly. + + 3. If the type is void or if we have no result, return error_mark_node + to show we have no result. + + 4. Finally, if the type of the result is already correct. */ if (Present (Parent (gnat_node)) && ((Nkind (Parent (gnat_node)) == N_Assignment_Statement && Name (Parent (gnat_node)) == gnat_node) || (Nkind (Parent (gnat_node)) == N_Procedure_Call_Statement && Name (Parent (gnat_node)) != gnat_node) + || Nkind (Parent (gnat_node)) == N_Parameter_Association || (Nkind (Parent (gnat_node)) == N_Unchecked_Type_Conversion && !AGGREGATE_TYPE_P (gnu_result_type) - && !AGGREGATE_TYPE_P (TREE_TYPE (gnu_result))) - || Nkind (Parent (gnat_node)) == N_Parameter_Association) + && !AGGREGATE_TYPE_P (TREE_TYPE (gnu_result)))) && !(TYPE_SIZE (gnu_result_type) && TYPE_SIZE (TREE_TYPE (gnu_result)) && (AGGREGATE_TYPE_P (gnu_result_type) @@ -4874,16 +4881,14 @@ gnat_to_gnu (Node_Id gnat_node) && !(TREE_CODE (gnu_result_type) == RECORD_TYPE && TYPE_JUSTIFIED_MODULAR_P (gnu_result_type)))) { - /* In this case remove padding only if the inner object type is the - same as gnu_result_type or is of self-referential size (in that later - case it must be an object of unconstrained type with a default - discriminant). We want to avoid copying too much data. */ + /* Remove padding only if the inner object is of self-referential + size: in that case it must be an object of unconstrained type + with a default discriminant and we want to avoid copying too + much data. */ if (TREE_CODE (TREE_TYPE (gnu_result)) == RECORD_TYPE && TYPE_IS_PADDING_P (TREE_TYPE (gnu_result)) - && (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (gnu_result))) - == gnu_result_type - || CONTAINS_PLACEHOLDER_P (TYPE_SIZE (TREE_TYPE (TYPE_FIELDS - (TREE_TYPE (gnu_result))))))) + && CONTAINS_PLACEHOLDER_P (TYPE_SIZE (TREE_TYPE (TYPE_FIELDS + (TREE_TYPE (gnu_result)))))) gnu_result = convert (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (gnu_result))), gnu_result); } @@ -4901,20 +4906,20 @@ gnat_to_gnu (Node_Id gnat_node) && TREE_CODE (TREE_TYPE (gnu_result)) == RECORD_TYPE && TYPE_MODE (gnu_result_type) == BLKmode)) { - /* Remove any padding record, but do nothing more in this case. */ + /* Remove any padding. */ if (TREE_CODE (TREE_TYPE (gnu_result)) == RECORD_TYPE && TYPE_IS_PADDING_P (TREE_TYPE (gnu_result))) gnu_result = convert (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (gnu_result))), gnu_result); } - else if (gnu_result == error_mark_node - || gnu_result_type == void_type_node) - gnu_result = error_mark_node; + else if (gnu_result == error_mark_node || gnu_result_type == void_type_node) + gnu_result = error_mark_node; + else if (gnu_result_type != TREE_TYPE (gnu_result)) gnu_result = convert (gnu_result_type, gnu_result); - /* We don't need any NOP_EXPR or NON_LVALUE_EXPR on GNU_RESULT. */ + /* We don't need any NOP_EXPR or NON_LVALUE_EXPR on the result. */ while ((TREE_CODE (gnu_result) == NOP_EXPR || TREE_CODE (gnu_result) == NON_LVALUE_EXPR) && TREE_TYPE (TREE_OPERAND (gnu_result, 0)) == TREE_TYPE (gnu_result)) |