Hi,
In Ada, we support all sorts of data structure layout, including on strict-
alignment targets, and the compiler must generate glue code if necessary.
The problem here is a function returning a structure by invisible reference
into a field which is not sufficient aligned because the enclosing object is
packed: in this case, the caller passes an address that is not correctly
aligned to the callee, which can result in an unaligned access in the callee.
Tested on x86_64-suse-linux and SPARC/Solaris, OK for the mainline.
2014-10-06 Eric Botcazou <ebotca...@adacore.com>
* calls.c (expand_call): Do not use the target as the return slot if
it is not sufficiently aligned.
2014-10-06 Eric Botcazou <ebotca...@adacore.com>
* gnat.dg/return4.adb: New test.
* gnat.dg/return4_pkg.ad[sb]: New helper.
--
Eric Botcazou
Index: calls.c
===================================================================
--- calls.c (revision 215843)
+++ calls.c (working copy)
@@ -2377,7 +2377,14 @@ expand_call (tree exp, rtx target, int i
{
struct_value_size = int_size_in_bytes (rettype);
- if (target && MEM_P (target) && CALL_EXPR_RETURN_SLOT_OPT (exp))
+ /* Even if it is semantically safe to use the target as the return
+ slot, it may be not sufficiently aligned for the return type. */
+ if (CALL_EXPR_RETURN_SLOT_OPT (exp)
+ && target
+ && MEM_P (target)
+ && !(MEM_ALIGN (target) < TYPE_ALIGN (rettype)
+ && SLOW_UNALIGNED_ACCESS (TYPE_MODE (rettype),
+ MEM_ALIGN (target))))
structure_value_addr = XEXP (target, 0);
else
{
package Return4_Pkg is
type Rec is record
I1, I2, I3 : Integer;
end record;
function Get_Value (I : Integer) return Rec;
end Return4_Pkg;
package body Return4_Pkg is
function Get_Value (I : Integer) return Rec is
Value : Rec := (I1 => I, I2 => I, I3 => I);
begin
return Value;
end;
end Return4_Pkg;
-- { dg-do run }
-- { dg-options "-O" }
with Return4_Pkg; use Return4_Pkg;
procedure Return4 is
type Local_Rec is record
C : Character;
R : Rec;
end record;
pragma Pack (Local_Rec);
L : Local_Rec;
for L'Alignment use 2;
begin
L.R := Get_Value (0);
if L.R.I1 /= 0 then
raise Program_Error;
end if;
end;