-- Wrappers of class-wide pre/postconditions reference the
-- parent primitive that has the inherited contract.
- if Is_Wrapper (Subp_Id)
- and then Present (LSP_Subprogram (Subp_Id))
- then
+ if Is_LSP_Wrapper (Subp_Id) then
Subp_Id := LSP_Subprogram (Subp_Id);
end if;
elsif Is_Thunk (Current_Scope) then
return;
+
+ -- The call to the inherited primitive in a dispatch table wrapper must
+ -- not have the class-wide precondition check since it is installed in
+ -- the caller of the wrapper. This is also required to avoid the wrong
+ -- evaluation of class-wide preconditions in Condition_Wrappers (ie.
+ -- wrappers of inherited primitives that implement additional interface
+ -- primitives that have preconditions).
+
+ -- For example:
+ -- type Typ is tagged null record;
+ -- procedure Prim (X : T) with Pre'Class => False;
+
+ -- type Iface is interface;
+ -- procedure Prim (X : Iface) is abstract with Pre'Class => True;
+
+ -- type DT is new Typ and Iface with null record;
+ -- <internally built dispatch table wrapper of inherited Prim>
+
+ -- The class-wide preconditions of the wrapper must not fail due to the
+ -- disjunction of the class-wide preconditions of subprograms Typ.Prim
+ -- and Iface.Prim. If the precondition check were placed in the
+ -- wrapper's call to the inherited parent primitive, its class-wide
+ -- condition would incorrectly be reported as failed at runtime.
+
+ elsif Is_Dispatch_Table_Wrapper (Current_Scope)
+ or else (Chars (Current_Scope) = Name_uWrapped_Statements
+ and then Is_Dispatch_Table_Wrapper (Scope (Current_Scope)))
+ then
+ return;
end if;
Subp := Entity (Name (Call_Node));
Par_Prim : Entity_Id;
Prim : Entity_Id;
- type Wrapper_Kind is (No_Wrapper, LSP_Wrapper, Postcond_Wrapper);
+ type Wrapper_Kind is (No_Wrapper, LSP_Wrapper, Condition_Wrapper);
Wrapper_Needed : Wrapper_Kind;
-- Kind of wrapper needed by a given inherited primitive of tagged
-- * No_Wrapper: No wrapper is needed.
-- * LSP_Wrapper: Wrapper that handles inherited class-wide pre/post
-- conditions that call overridden primitives.
- -- * Postcond_Wrapper: Wrapper that handles postconditions of interface
- -- primitives.
+ -- * Condition_Wrapper: Wrapper of inherited subprogram that implements
+ -- additional interface primitives of the derived type that have
+ -- class-wide pre-/postconditions.
function Build_DTW_Body
(Loc : Source_Ptr;
-- List containing identifiers of built wrappers. Used to defer building
-- and analyzing their class-wide precondition subprograms.
- Postcond_Candidates_List : Elist_Id := No_Elist;
+ Condition_Candidates_List : Elist_Id := No_Elist;
-- List containing inherited primitives of tagged type R that implement
- -- interface primitives that have postconditions.
+ -- interface primitives that have pre-/postconditions.
-- Start of processing for Check_Inherited_Conditions
-- When the primitive is an LSP wrapper we climb to the parent
-- primitive that has the inherited contract.
- if Is_Wrapper (Par_Prim)
- and then Present (LSP_Subprogram (Par_Prim))
- then
+ if Is_LSP_Wrapper (Par_Prim) then
Par_Prim := LSP_Subprogram (Par_Prim);
end if;
end loop;
-- Collect inherited primitives that may need a wrapper to handle
- -- postconditions of interface primitives; done to improve the
+ -- pre-/postconditions of interface primitives; done to improve the
-- performance when checking if postcondition wrappers are needed.
Op_Node := First_Elmt (Prim_Ops);
if Present (Interface_Alias (Prim))
and then not Comes_From_Source (Alias (Prim))
- and then Present (Class_Postconditions (Interface_Alias (Prim)))
+ and then
+ (Present (Class_Preconditions (Interface_Alias (Prim)))
+ or else
+ Present (Class_Postconditions (Interface_Alias (Prim))))
then
- if No (Postcond_Candidates_List) then
- Postcond_Candidates_List := New_Elmt_List;
+ if No (Condition_Candidates_List) then
+ Condition_Candidates_List := New_Elmt_List;
end if;
- Append_Unique_Elmt (Alias (Prim), Postcond_Candidates_List);
+ Append_Unique_Elmt (Alias (Prim), Condition_Candidates_List);
end if;
Next_Elmt (Op_Node);
-- When the primitive is an LSP wrapper we climb to the parent
-- primitive that has the inherited contract.
- if Is_Wrapper (Par_Prim)
- and then Present (LSP_Subprogram (Par_Prim))
- then
+ if Is_LSP_Wrapper (Par_Prim) then
Par_Prim := LSP_Subprogram (Par_Prim);
end if;
-- implements additional interface types, and this inherited
-- primitive covers an interface primitive of these additional
-- interface types that has class-wide postconditions, then it
- -- requires a postconditions wrapper.
+ -- requires a pre-/postconditions wrapper.
if Wrapper_Needed = No_Wrapper
and then Present (Interfaces (R))
- and then Present (Postcond_Candidates_List)
- and then Contains (Postcond_Candidates_List, Prim)
+ and then Present (Condition_Candidates_List)
+ and then Contains (Condition_Candidates_List, Prim)
then
declare
Elmt : Elmt_Id;
begin
Elmt := First_Elmt (Prim_Ops);
- while Present (Elmt) loop
+
+ Search : while Present (Elmt) loop
Ent := Node (Elmt);
-- Perform the search relying on the internal entities
if Present (Interface_Alias (Ent))
and then (Alias (Ent)) = Prim
and then
- Present (Class_Postconditions (Interface_Alias (Ent)))
+ (Present (Class_Preconditions (Interface_Alias (Ent)))
+ or else Present (Class_Postconditions
+ (Interface_Alias (Ent))))
then
Iface := Find_Dispatching_Type (Interface_Alias (Ent));
Iface_Elmt := First_Elmt (Interfaces (R));
while Present (Iface_Elmt) loop
if Node (Iface_Elmt) = Iface then
- Wrapper_Needed := Postcond_Wrapper;
- exit;
+ Wrapper_Needed := Condition_Wrapper;
+ exit Search;
end if;
Next_Elmt (Iface_Elmt);
end if;
Next_Elmt (Elmt);
- end loop;
+ end loop Search;
end;
end if;
end if;
-- LSP wrappers reference the parent primitive that has the
-- the class-wide pre/post condition that calls overridden
- -- primitives.
+ -- primitives. Condition wrappers do not have this attribute
+ -- (see predicate Is_LSP_Wrapper).
if Wrapper_Needed = LSP_Wrapper then
Set_LSP_Subprogram (DTW_Id, Par_Prim);
Set_Sloc (DTW_Id, Sloc (Prim));
- -- For inherited class-wide preconditions the DTW wrapper
- -- reuses the ICW of the parent (which checks the parent
- -- interpretation of the class-wide preconditions); the
- -- interpretation of the class-wide preconditions for the
- -- inherited subprogram is checked at the caller side.
+ -- For LSP_Wrappers of subprograms that inherit class-wide
+ -- preconditions the DTW wrapper reuses the ICW of the parent
+ -- (which checks the parent interpretation of the class-wide
+ -- preconditions); the interpretation of the class-wide
+ -- preconditions for the inherited subprogram is checked
+ -- at the caller side.
-- When the subprogram inherits class-wide postconditions
-- the DTW also checks the interpretation of the class-wide
-- the class-wide postconditions.
-- procedure Prim (F1 : T1; ...) is
- -- [ pragma Check (Postcondition, Expr); ]
+ -- [ pragma Postcondition (check => Expr); ]
-- begin
-- Par_Prim_ICW (Par_Type (F1), ...);
-- end;
- if Present (Indirect_Call_Wrapper (Par_Prim)) then
+ if Wrapper_Needed = LSP_Wrapper
+ and then Present (Indirect_Call_Wrapper (Par_Prim))
+ then
DTW_Body :=
Build_DTW_Body (Loc,
DTW_Spec => DTW_Spec,
Par_Prim => Par_Prim,
Wrapped_Subp => Indirect_Call_Wrapper (Par_Prim));
- -- For subprograms that only inherit class-wide postconditions
- -- the DTW wrapper calls the parent primitive (which on its
- -- body checks the interpretation of the class-wide post-
- -- conditions for the parent subprogram), and the DTW checks
- -- the interpretation of the class-wide postconditions for the
+ -- For LSP_Wrappers of subprograms that only inherit class-wide
+ -- postconditions, and also for Condition_Wrappers (wrappers of
+ -- inherited subprograms that implement additional interface
+ -- primitives that have class-wide pre-/postconditions), the
+ -- DTW wrapper calls the parent primitive (which on its body
+ -- checks the interpretation of the class-wide post-conditions
+ -- for the parent subprogram), and the DTW checks the
+ -- interpretation of the class-wide postconditions for the
-- inherited subprogram.
-- procedure Prim (F1 : T1; ...) is
- -- pragma Check (Postcondition, Expr);
+ -- pragma Postcondition (check => Expr);
-- begin
-- Par_Prim (Par_Type (F1), ...);
-- end;
+ -- No class-wide preconditions runtime check is generated for
+ -- this wrapper call to the parent primitive, since the check
+ -- is performed by the caller of the DTW wrapper (see routine
+ -- Install_Class_Preconditions_Check).
+
else
DTW_Body :=
Build_DTW_Body (Loc,