+ -- If the return object's declaration does not include an expression,
+ -- then we use its subtype for the allocation. Likewise in the case
+ -- of a degenerate expression like a raise expression.
+
+ if No (Expr)
+ or else Nkind (Original_Node (Expr)) = N_Raise_Expression
+ then
+ Alloc_Typ := Typ;
+
+ -- If the return object's declaration includes an expression, then
+ -- there are two cases: either the nominal subtype of the object is
+ -- definite and we can use it for the allocation directly, or it is
+ -- not and Analyze_Object_Declaration should have built an actual
+ -- subtype from the expression.
+
+ -- However, there are exceptions in the latter case for interfaces
+ -- (see Analyze_Object_Declaration), as well as class-wide types and
+ -- types with unknown discriminants if they are additionally limited
+ -- (see Expand_Subtype_From_Expr), so we must cope with them.
+
+ elsif Is_Interface (Typ) then
+ pragma Assert (Is_Class_Wide_Type (Typ));
+
+ -- For interfaces, we use the type of the expression, except if
+ -- we need to put back a conversion that we have removed earlier
+ -- in the processing.
+
+ if Is_Class_Wide_Type (Etype (Expr)) then
+ Alloc_Typ := Typ;
+ else
+ Alloc_Typ := Etype (Expr);
+ end if;
+
+ elsif Is_Class_Wide_Type (Typ) then
+
+ -- For class-wide types, we have to make sure that we use the
+ -- dynamic type of the expression for the allocation, either by
+ -- means of its (static) subtype or through the actual subtype.
+
+ if Has_Tag_Of_Type (Expr) then
+ Alloc_Typ := Etype (Expr);
+
+ else pragma Assert (Ekind (Typ) = E_Class_Wide_Subtype
+ and then Present (Equivalent_Type (Typ)));
+
+ Alloc_Typ := Typ;
+ end if;
+
+ else pragma Assert (Is_Definite_Subtype (Typ)
+ or else (Has_Unknown_Discriminants (Typ)
+ and then Is_Limited_View (Typ)));
+
+ Alloc_Typ := Typ;
+ end if;
+