diff options
author | Arnaud Charlet <charlet@gcc.gnu.org> | 2015-03-02 10:24:38 +0100 |
---|---|---|
committer | Arnaud Charlet <charlet@gcc.gnu.org> | 2015-03-02 10:24:38 +0100 |
commit | c9d70ab181e531bfe069c42aeaa996ec96bca02e (patch) | |
tree | fef9e066027e89d2a1f80384805126004eb62d4f /gcc/ada/sem_attr.adb | |
parent | 95e00a3a825cb27fb9b4db7007a94462aa311561 (diff) | |
download | gcc-c9d70ab181e531bfe069c42aeaa996ec96bca02e.zip gcc-c9d70ab181e531bfe069c42aeaa996ec96bca02e.tar.gz gcc-c9d70ab181e531bfe069c42aeaa996ec96bca02e.tar.bz2 |
[multiple changes]
2015-03-02 Thomas Quinot <quinot@adacore.com>
* exp_attr.adb (Expand_N_Attribute_Reference, case Input): When
expanding a 'Input attribute reference for a class-wide type,
do not generate a separate object declaration for the controlling
tag dummy object; instead, generate the expression inline in the
dispatching call. Otherwise, the declaration (which involves a
call to String'Input, returning a dynamically sized value on the
secondary stack) will be expanded outside of proper secondary
stack mark/release operations, and will thus cause a secondary
stack leak.
2015-03-02 Hristian Kirtchev <kirtchev@adacore.com>
* checks.adb (Add_Validity_Check): Change the names of all
formal parameters to better illustrate their purpose. Update
the subprogram documentation. Update all occurrences of the
formal parameters. Generate a pre/postcondition pragma by
calling Build_Pre_Post_Condition.
(Build_PPC_Pragma): Removed.
(Build_Pre_Post_Condition): New routine.
* einfo.adb Node8 is no longer used as Postcondition_Proc. Node14
is now used as Postconditions_Proc. Flag240 is now renamed to
Has_Expanded_Contract. (First_Formal): The routine can now
operate on generic subprograms.
(First_Formal_With_Extras): The routine can now operate on generic
subprograms.
(Has_Expanded_Contract): New routine.
(Has_Postconditions): Removed.
(Postcondition_Proc): Removed.
(Postconditions_Proc): New routine.
(Set_Has_Expanded_Contract): New routine.
(Set_Has_Postconditions): Removed.
(Set_Postcondition_Proc): Removed.
(Set_Postconditions_Proc): New routine.
(Write_Entity_Flags): Remove the output of Has_Postconditions. Add
the output of Has_Expanded_Contract.
(Write_Field8_Name): Remove the output of Postcondition_Proc.
(Write_Field14_Name): Add the output of Postconditions_Proc.
* einfo.ads New attributes Has_Expanded_Contract and
Postconditions_Proc along with occurrences in entities.
Remove attributes Has_Postconditions and Postcondition_Proc
along with occurrences in entities.
(Has_Expanded_Contract): New routine along with pragma Inline.
(Has_Postconditions): Removed along with pragma Inline.
(Postcondition_Proc): Removed along with pragma Inline.
(Postconditions_Proc): New routine along with pragma Inline.
(Set_Has_Expanded_Contract): New routine along with pragma Inline.
(Set_Has_Postconditions): Removed along with pragma Inline.
(Set_Postcondition_Proc): Removed along with pragma Inline.
(Set_Postconditions_Proc): New routine along with pragma Inline.
* exp_ch6.adb (Add_Return): Code cleanup. Update the
generation of the call to the _Postconditions routine of
the procedure. (Expand_Non_Function_Return): Reformat the
comment on usage. Code cleanup. Update the generation of
the call to the _Postconditions routine of the procedure or
entry [family].
(Expand_Simple_Function_Return): Update the
generation of the _Postconditions routine of the function.
(Expand_Subprogram_Contract): Reimplemented.
* exp_ch6.ads (Expand_Subprogram_Contract): Update the parameter
profile along the comment on usage.
* exp_ch9.adb (Build_PPC_Wrapper): Code cleanup.
(Expand_N_Task_Type_Declaration): Generate pre/postconditions
wrapper when the entry [family] has a contract with
pre/postconditions.
* exp_prag.adb (Expand_Attributes_In_Consequence): New routine.
(Expand_Contract_Cases): This routine and its subsidiaries now
analyze all generated code.
(Expand_Old_In_Consequence): Removed.
* sem_attr.adb Add with and use clause for Sem_Prag.
(Analyze_Attribute): Reimplment the analysis of attribute 'Result.
(Check_Use_In_Test_Case): Use routine Test_Case_Arg to obtain
"Ensures".
* sem_ch3.adb (Analyze_Declarations): Analyze the contract of
a generic subprogram.
(Analyze_Object_Declaration): Do not create a contract node.
(Derive_Subprogram): Do not create a contract node.
* sem_ch6.adb (Analyze_Abstract_Subprogram_Declaration): Do
not create a contract node.
(Analyze_Completion_Contract): New routine.
(Analyze_Function_Return): Alphabetize.
(Analyze_Generic_Subprogram_Body): Alphabetize. Do not create a
contract node. Do not copy pre/postconditions to the original
generic template.
(Analyze_Null_Procedure): Do not create a contract node.
(Analyze_Subprogram_Body_Contract): Reimplemented.
(Analyze_Subprogram_Body_Helper): Do not mark the enclosing scope
as having postconditions. Do not create a contract node. Analyze
the subprogram body contract of a body that acts as a compilation
unit. Expand the subprogram contract after the declarations have
been analyzed.
(Analyze_Subprogram_Contract): Reimplemented.
(Analyze_Subprogram_Specification): Do not create a contract node.
(List_Inherited_Pre_Post_Aspects): Code cleanup.
* sem_ch6.adb (Analyze_Subprogram_Body_Contract): Update the
comment on usage.
(Analyze_Subprogram_Contract): Update the
parameter profile and the comment on usage.
* sem_ch7.adb (Analyze_Package_Body_Helper): Do not create a
contract node.
(Analyze_Package_Declaration): Do not create a
contract node.
(Is_Subp_Or_Const_Ref): Ensure that the prefix has an entity.
* sem_ch8.adb (Analyze_Subprogram_Renaming): Do not create a
contract node.
* sem_ch9.adb (Analyze_Entry_Declaration): Do not create a
contract node.
* sem_ch10.adb (Analyze_Compilation_Unit): Move local variables to
their proper section and alphabetize them. Analyze the contract of
a [generic] subprogram after all Pragmas_After have been analyzed.
(Analyze_Subprogram_Body_Stub_Contract): Alphabetize.
* sem_ch12.adb (Analyze_Generic_Package_Declaration): Do not
create a contract node.
(Analyze_Generic_Subprogram_Declaration):
Alphabetize local variables. Do not create a contract
node. Do not generate aspects out of pragmas for ASIS.
(Analyze_Subprogram_Instantiation): Instantiate
the contract of the subprogram. Do not create a
contract node. (Instantiate_Contract): New routine.
(Instantiate_Subprogram_Body): Alphabetize local variables.
(Save_Global_References_In_Aspects): New routine.
(Save_References): Do not save the global references found within
the aspects of a generic subprogram.
* sem_ch12.ads (Save_Global_References_In_Aspects): New routine.
* sem_ch13.adb (Analyze_Aspect_Specifications): Do not use
Original_Node for establishing linkages.
(Insert_Pragma): Insertion in a subprogram body takes precedence over
the case where the subprogram body is also a compilation unit.
* sem_prag.adb (Analyze_Contract_Cases_In_Decl_Part): Use
Get_Argument to obtain the proper expression. Install the generic
formals when the related context is a generic subprogram.
(Analyze_Depends_In_Decl_Part): Use Get_Argument to obtain
the proper expression. Use Corresponding_Spec_Of to obtain
the spec. Install the generic formal when the related context
is a generic subprogram.
(Analyze_Global_In_Decl_Part): Use Get_Argument to obtain the proper
expression. Use Corresponding_Spec_Of to obtain the spec. Install the
generic formal when the related context is a generic subprogram.
(Analyze_Initial_Condition_In_Decl_Part): Use Get_Argument
to obtain the proper expression. Remove the call to
Check_SPARK_Aspect_For_ASIS as the analysis is now done
automatically.
(Analyze_Pragma): Update all occurrences
to Original_Aspect_Name. Pragmas Contract_Cases, Depends,
Extensions_Visible, Global, Postcondition, Precondition and
Test_Case now carry generic templates when the related context
is a generic subprogram. The same pragmas are no longer
forcefully fully analyzed when the context is a subprogram
that acts as a compilation unit. Pragmas Abstract_State,
Initial_Condition, Initializes and Refined_State have been clean
up. Pragmas Post, Post_Class, Postcondition, Pre, Pre_Class
and Precondition now use the same routine for analysis. Pragma
Refined_Post does not need to check the use of 'Result or
the lack of a post-state in its expression. Reimplement the
analysis of pragma Test_Case.
(Analyze_Pre_Post_Condition): New routine.
(Analyze_Pre_Post_Condition_In_Decl_Part):
Reimplemented.
(Analyze_Refined_Depends_In_Decl_Part): Use Get_Argument to obtain the
proper expression.
(Analyze_Refined_Global_In_Decl_Part): Use Get_Argument to obtain
the proper expression.
(Analyze_Test_Case_In_Decl_Part): Reimplemented.
(Check_Pre_Post): Removed.
(Check_Precondition_Postcondition): Removed.
(Check_SPARK_Aspect_For_ASIS): Removed.
(Check_Test_Case): Removed.
(Collect_Subprogram_Inputs_Outputs): Use Get_Argument
to obtain the proper expression. Use Corresponding_Spec_Of to
find the proper spec.
(Create_Generic_Template): New routine.
(Duplication_Error): New routine.
(Expression_Function_Error): New routine.
(Find_Related_Subprogram_Or_Body): Moved to the spec
of Sem_Prag. Emit precise error messages. Account for cases of
rewritten expression functions, generic instantiations, handled
sequence of statements and pragmas from aspects.
(Get_Argument): New routine.
(Make_Aspect_For_PPC_In_Gen_Sub_Decl): Removed.
(Preanalyze_CTC_Args): Removed.
(Process_Class_Wide_Condition): New routine.
* sem_prag.ads (Analyze_Test_Case_In_Decl_Part): Update
the parameter profile along with the comment on usage.
(Find_Related_Subprogram_Or_Body): Moved from the body of Sem_Prag.
(Make_Aspect_For_PPC_In_Gen_Sub_Decl): Removed.
(Test_Case_Arg): New routine.
* sem_util.adb Add with and use clauses for Sem_Ch6.
(Add_Contract_Item): This routine now creates a contract
node the first time an item is added. Remove the duplicate
aspect/pragma checks.
(Check_Result_And_Post_State): Reimplemented.
(Corresponding_Spec_Of): New routine.
(Get_Ensures_From_CTC_Pragma): Removed.
(Get_Requires_From_CTC_Pragma): Removed.
(Has_Significant_Contract): New routine.
(Inherit_Subprogram_Contract): Inherit only if the source
has a contract.
(Install_Generic_Formals): New routine.
(Original_Aspect_Name): Removed.
(Original_Aspect_Pragma_Name): New routine.
* sem_util.ads (Check_Result_And_Post_State): Reimplemented.
(Corresponding_Spec_Of): New routine.
(Get_Ensures_From_CTC_Pragma): Removed.
(Get_Requires_From_CTC_Pragma): Removed.
(Has_Significant_Contract): New routine.
(Install_Generic_Formals): New routine.
(Original_Aspect_Name): Removed.
(Original_Aspect_Pragma_Name): New routine.
* sem_warn.adb Add with and use clauses for Sem_Prag.
(Within_Postcondition): Use Test_Case_Arg to extract "Ensures".
From-SVN: r221101
Diffstat (limited to 'gcc/ada/sem_attr.adb')
-rw-r--r-- | gcc/ada/sem_attr.adb | 487 |
1 files changed, 296 insertions, 191 deletions
diff --git a/gcc/ada/sem_attr.adb b/gcc/ada/sem_attr.adb index 36f78d1..06b9090 100644 --- a/gcc/ada/sem_attr.adb +++ b/gcc/ada/sem_attr.adb @@ -59,6 +59,7 @@ with Sem_Dist; use Sem_Dist; with Sem_Elab; use Sem_Elab; with Sem_Elim; use Sem_Elim; with Sem_Eval; use Sem_Eval; +with Sem_Prag; use Sem_Prag; with Sem_Res; use Sem_Res; with Sem_Type; use Sem_Type; with Sem_Util; use Sem_Util; @@ -4561,7 +4562,7 @@ package body Sem_Attr is ---------------------------- procedure Check_Use_In_Test_Case (Prag : Node_Id) is - Ensures : constant Node_Id := Get_Ensures_From_CTC_Pragma (Prag); + Ensures : constant Node_Id := Test_Case_Arg (Prag, Name_Ensures); Expr : Node_Id; begin @@ -4984,269 +4985,373 @@ package body Sem_Attr is ------------ when Attribute_Result => Result : declare - Post_Id : Entity_Id; - -- The entity of the _Postconditions procedure + procedure Check_Placement_In_Check (Prag : Node_Id); + -- Verify that attribute 'Result appears within pragma Check that + -- emulates a postcondition. - Prag : Node_Id; - -- During pre-analysis, Prag is the enclosing pragma node if any - - Subp_Id : Entity_Id; - -- The entity of the enclosing subprogram + procedure Check_Placement_In_Contract_Cases (Prag : Node_Id); + -- Verify that attribute 'Result appears within a consequence of + -- pragma Contract_Cases. - begin - -- Find the proper enclosing scope + procedure Check_Placement_In_Test_Case (Prag : Node_Id); + -- Verify that attribute 'Result appears within the Ensures argument + -- of pragma Test_Case. - Post_Id := Current_Scope; - while Present (Post_Id) loop + function Is_Within + (Nod : Node_Id; + Encl_Nod : Node_Id) return Boolean; + -- Subsidiary to Check_Placemenet_In_XXX_Case. Determine whether + -- arbitrary node Nod is within enclosing node Encl_Nod. - -- Skip generated loops + ------------------------------ + -- Check_Placement_In_Check -- + ------------------------------ - if Ekind (Post_Id) = E_Loop then - Post_Id := Scope (Post_Id); + procedure Check_Placement_In_Check (Prag : Node_Id) is + Args : constant List_Id := Pragma_Argument_Associations (Prag); + Nam : constant Name_Id := Chars (Get_Pragma_Arg (First (Args))); - -- Skip the special _Parent scope generated to capture references - -- to formals during the process of subprogram inlining. + begin + -- The "Name" argument of pragma Check denotes a postcondition - elsif Ekind (Post_Id) = E_Function - and then Chars (Post_Id) = Name_uParent + if Nam_In (Nam, Name_Post, + Name_Postcondition, + Name_Refined_Post) then - Post_Id := Scope (Post_Id); + null; - -- Otherwise this must be _Postconditions + -- Otherwise the placement of attribute 'Result is illegal else - exit; + Error_Attr + ("% attribute can only appear in postcondition of function", + P); end if; - end loop; + end Check_Placement_In_Check; - Subp_Id := Scope (Post_Id); + --------------------------------------- + -- Check_Placement_In_Contract_Cases -- + --------------------------------------- - -- If the enclosing subprogram is always inlined, the enclosing - -- postcondition will not be propagated to the expanded call. + procedure Check_Placement_In_Contract_Cases (Prag : Node_Id) is + Args : constant List_Id := Pragma_Argument_Associations (Prag); + Cases : constant Node_Id := Get_Pragma_Arg (First (Args)); + CCase : Node_Id; - if not In_Spec_Expression - and then Has_Pragma_Inline_Always (Subp_Id) - and then Warn_On_Redundant_Constructs - then - Error_Msg_N - ("postconditions on inlined functions not enforced?r?", N); - end if; + begin + if Present (Component_Associations (Cases)) then + CCase := First (Component_Associations (Cases)); + while Present (CCase) loop + + -- Guard against a malformed contract case. Detect whether + -- attribute 'Result appears within the consequence of the + -- current contract case. + + if Nkind (CCase) = N_Component_Association + and then Is_Within (N, Expression (CCase)) + then + return; + end if; - -- If we are in the scope of a function and in Spec_Expression mode, - -- this is likely the prescan of the postcondition (or contract case, - -- or test case) pragma, and we just set the proper type. If there is - -- an error it will be caught when the real Analyze call is done. + Next (CCase); + end loop; + end if; - if Ekind (Post_Id) = E_Function and then In_Spec_Expression then + -- Otherwise pragma Contract_Cases is either malformed in some + -- way or attribute 'Result does not appear within a consequence + -- expression. - -- Check OK prefix + Error_Attr ("% attribute misplaced inside contract cases", P); + end Check_Placement_In_Contract_Cases; - if Chars (Post_Id) /= Chars (P) then - Error_Msg_Name_1 := Name_Result; - Error_Msg_NE - ("incorrect prefix for % attribute, expected &", P, Post_Id); - Error_Attr; + ---------------------------------- + -- Check_Placement_In_Test_Case -- + ---------------------------------- + + procedure Check_Placement_In_Test_Case (Prag : Node_Id) is + begin + -- Detect whether attribute 'Result appears within the "Ensures" + -- expression of pragma Test_Case. + + if not Is_Within (N, Test_Case_Arg (Prag, Name_Ensures)) then + Error_Attr ("% attribute misplaced inside test case", P); end if; + end Check_Placement_In_Test_Case; - -- Check in postcondition, Test_Case or Contract_Cases of function + --------------- + -- Is_Within -- + --------------- - Prag := N; - while Present (Prag) - and then not Nkind_In (Prag, N_Pragma, - N_Function_Specification, - N_Aspect_Specification, - N_Subprogram_Body) - loop - Prag := Parent (Prag); - end loop; + function Is_Within + (Nod : Node_Id; + Encl_Nod : Node_Id) return Boolean + is + Par : Node_Id; - -- In ASIS mode, the aspect itself is analyzed, in addition to the - -- corresponding pragma. Do not issue errors when analyzing the - -- aspect. + begin + Par := Nod; + while Present (Par) loop + if Par = Encl_Nod then + return True; - if Nkind (Prag) = N_Aspect_Specification then - null; + -- Prevent the search from going too far - -- Must have a pragma + elsif Is_Body_Or_Package_Declaration (Par) then + exit; + end if; - elsif Nkind (Prag) /= N_Pragma then - Error_Attr - ("% attribute can only appear in postcondition of function", - P); + Par := Parent (Par); + end loop; - -- Processing depends on which pragma we have + return False; + end Is_Within; - else - case Get_Pragma_Id (Prag) is - when Pragma_Test_Case => - declare - Arg_Ens : constant Node_Id := - Get_Ensures_From_CTC_Pragma (Prag); - Arg : Node_Id; + -- Local variables - begin - Arg := N; - while Arg /= Prag and then Arg /= Arg_Ens loop - Arg := Parent (Arg); - end loop; + In_Post : Boolean := False; + Prag : Node_Id; + Prag_Id : Pragma_Id; + Pref_Id : Entity_Id; + Spec_Id : Entity_Id; + Subp_Decl : Node_Id; + Subp_Id : Entity_Id; + Subp_Spec : Node_Id; - if Arg /= Arg_Ens then - Error_Attr - ("% attribute misplaced inside test case", P); - end if; - end; + -- Start of processing for Result - when Pragma_Contract_Cases => - declare - Aggr : constant Node_Id := - Expression (First - (Pragma_Argument_Associations (Prag))); - Arg : Node_Id; + begin + -- The attribute reference is a primary. If any expressions follow, + -- then the attribute reference is an indexable object. Transform the + -- attribute into an indexed component and analyze it. - begin - Arg := N; - while Arg /= Prag - and then Parent (Parent (Arg)) /= Aggr - loop - Arg := Parent (Arg); - end loop; + if Present (E1) then + Rewrite (N, + Make_Indexed_Component (Loc, + Prefix => + Make_Attribute_Reference (Loc, + Prefix => Relocate_Node (P), + Attribute_Name => Name_Result), + Expressions => Expressions (N))); + Analyze (N); + return; + end if; - -- At this point, Parent (Arg) should be a component - -- association. Attribute Result is only allowed in - -- the expression part of this association. + -- Traverse the parent chain to find the aspect or pragma where + -- attribute 'Result resides. - if Nkind (Parent (Arg)) /= N_Component_Association - or else Arg /= Expression (Parent (Arg)) - then - Error_Attr - ("% attribute misplaced inside contract cases", - P); - end if; - end; + Prag := N; + while Present (Prag) loop + if Nkind_In (Prag, N_Aspect_Specification, N_Pragma) then + exit; - when Pragma_Postcondition | Pragma_Refined_Post => - null; + -- Prevent the search from going too far - when others => - Error_Attr - ("% attribute can only appear in postcondition " - & "of function", P); - end case; + elsif Is_Body_Or_Package_Declaration (Prag) then + exit; end if; - -- The attribute reference is a primary. If expressions follow, - -- the attribute reference is really an indexable object, so - -- rewrite and analyze as an indexed component. + Prag := Parent (Prag); + end loop; - if Present (E1) then - Rewrite (N, - Make_Indexed_Component (Loc, - Prefix => - Make_Attribute_Reference (Loc, - Prefix => Relocate_Node (Prefix (N)), - Attribute_Name => Name_Result), - Expressions => Expressions (N))); - Analyze (N); + -- Do not emit an error when preanalyzing an aspect for ASIS. If the + -- placement of attribute 'Result is illegal, the error is reported + -- when analyzing the corresponding pragma. + + if ASIS_Mode and then Nkind (Prag) = N_Aspect_Specification then + null; + + -- Attribute 'Result is allowed to appear only in postcondition-like + -- pragmas. + + elsif Nkind (Prag) = N_Pragma then + Prag_Id := Get_Pragma_Id (Prag); + + if Prag_Id = Pragma_Check then + Check_Placement_In_Check (Prag); + + elsif Prag_Id = Pragma_Contract_Cases then + Check_Placement_In_Contract_Cases (Prag); + + elsif Prag_Id = Pragma_Postcondition + or else Prag_Id = Pragma_Refined_Post + then + null; + + elsif Prag_Id = Pragma_Test_Case then + Check_Placement_In_Test_Case (Prag); + + else + Error_Attr + ("% attribute can only appear in postcondition of function", + P); return; end if; - Set_Etype (N, Etype (Post_Id)); + -- Otherwise the placement of the attribute is illegal - -- If several functions with that name are visible, the intended - -- one is the current scope. + else + Error_Attr + ("% attribute can only appear in postcondition of function", P); + return; + end if; - if Is_Overloaded (P) then - Set_Entity (P, Post_Id); - Set_Is_Overloaded (P, False); - end if; + -- Attribute 'Result appears within a postcondition-like pragma. Find + -- the related subprogram subject to the pragma. - -- Check the legality of attribute 'Result when it appears inside - -- pragma Refined_Post. These specialized checks are required only - -- when code generation is disabled. In the general case pragma - -- Refined_Post is transformed into pragma Check by Process_PPCs - -- which in turn is relocated to procedure _Postconditions. From - -- then on the legality of 'Result is determined as usual. + if Nkind (Prag) = N_Aspect_Specification then + Subp_Decl := Parent (Prag); + else + Subp_Decl := Find_Related_Subprogram_Or_Body (Prag); + end if; - elsif not Expander_Active and then In_Refined_Post then + -- The pragma where attribute 'Result appears is associated with a + -- subprogram declaration or a body. - -- Routine _Postconditions has not been generated yet, the nearest - -- enclosing subprogram is denoted by the current scope. + if Nkind_In (Subp_Decl, N_Abstract_Subprogram_Declaration, + N_Entry_Declaration, + N_Generic_Subprogram_Declaration, + N_Subprogram_Body, + N_Subprogram_Body_Stub, + N_Subprogram_Declaration) + then + Subp_Id := Defining_Entity (Subp_Decl); - if Ekind (Post_Id) /= E_Procedure - or else Chars (Post_Id) /= Name_uPostconditions - then - Subp_Id := Current_Scope; + -- Attribute 'Result is part of the _Postconditions procedure of + -- the related subprogram. Retrieve the related subprogram. + + if Chars (Subp_Id) = Name_uPostconditions then + In_Post := True; + Subp_Decl := Parent (Subp_Decl); + Subp_Id := Scope (Subp_Id); end if; - -- The prefix denotes the nearest enclosing function + -- Retrieve the entity of the spec (if any) - if Is_Entity_Name (P) - and then Ekind (Entity (P)) = E_Function - and then Entity (P) = Subp_Id + if Nkind (Subp_Decl) = N_Subprogram_Body + and then Present (Corresponding_Spec (Subp_Decl)) then - null; + Spec_Id := Corresponding_Spec (Subp_Decl); - -- Otherwise the use of 'Result is illegal + elsif Nkind (Subp_Decl) = N_Subprogram_Body_Stub + and then Present (Corresponding_Spec_Of_Stub (Subp_Decl)) + then + Spec_Id := Corresponding_Spec_Of_Stub (Subp_Decl); else - Error_Msg_Name_2 := Chars (Subp_Id); - Error_Attr ("incorrect prefix for % attribute, expected %", P); + Spec_Id := Subp_Id; end if; - Set_Etype (N, Etype (Subp_Id)); + -- When the subprogram is always inlined, the postcondition will + -- not be propagated to the expanded body. - -- Body case, where we must be inside a generated _Postconditions - -- procedure, and the prefix must be on the scope stack, or else the - -- attribute use is definitely misplaced. The postcondition itself - -- may have generated transient scopes, and is not necessarily the - -- current one. + if Warn_On_Redundant_Constructs + and then Has_Pragma_Inline_Always (Spec_Id) + then + Error_Msg_N + ("postconditions on inlined functions not enforced?r?", P); + end if; - else - while Present (Post_Id) - and then Post_Id /= Standard_Standard - loop - if Chars (Post_Id) = Name_uPostconditions then - exit; - else - Post_Id := Scope (Post_Id); + -- Ensure that the prefix of attribute 'Result denotes the related + -- subprogram. + + if Is_Entity_Name (P) then + Pref_Id := Entity (P); + + -- When a subprogram with contract assertions is imported, it + -- is encapsulated in a wrapper. In this case the scope of the + -- wrapper denotes the original imported subprogram. + + if Is_Imported (Pref_Id) then + Pref_Id := Scope (Pref_Id); end if; - end loop; - Subp_Id := Scope (Post_Id); + if Ekind_In (Pref_Id, E_Function, E_Generic_Function) then - if Chars (Post_Id) = Name_uPostconditions - and then Ekind (Subp_Id) = E_Function - then - -- Check OK prefix + -- The prefix of attribute 'Result denotes the entity of + -- some other unrelated function. - if Nkind_In (P, N_Identifier, N_Operator_Symbol) - and then Chars (P) = Chars (Subp_Id) - then - null; + if Pref_Id /= Spec_Id then + Subp_Spec := Parent (Spec_Id); - -- Within an instance, the prefix designates the local renaming - -- of the original generic. + -- Attribute 'Result appears in a postcondition of a + -- generic function that acts as a compilation unit: - elsif Is_Entity_Name (P) - and then Ekind (Entity (P)) = E_Function - and then Present (Alias (Entity (P))) - and then Chars (Alias (Entity (P))) = Chars (Subp_Id) - then - null; + -- generic + -- function Gen_Func return ... + -- with Post => Gen_Func'Result ...; + + -- When the function is instantiated, the Chars field of + -- attribute 'Result's prefix still denotes the generic + -- function. Note that any preemptive transformation is + -- impossible without a proper analysis. The structure of + -- the anonymous wrapper package is as follows: + + -- package Anon_Gen_Pack is + -- <subtypes and renamings> + -- function Subp_Decl return ...; + -- pragma Postcondition (Gen_Func'Result ...); + -- function Gen_Func ... renames Subp_Decl; + -- end Anon_Gen_Pack; + + -- Recognize this case and do not flag it as illegal + + if Nkind (Subp_Spec) = N_Function_Specification + and then Present (Generic_Parent (Subp_Spec)) + then + if Generic_Parent (Subp_Spec) = Pref_Id then + null; + + elsif Ekind (Pref_Id) = E_Function + and then Present (Alias (Pref_Id)) + and then Alias (Pref_Id) = Spec_Id + then + null; + + else + Error_Msg_Name_2 := Chars (Spec_Id); + Error_Attr + ("incorrect prefix for % attribute, expected %", + P); + end if; + + -- Otherwise the context is not a function instantiation + -- and the prefix is illegal + + else + Error_Msg_Name_2 := Chars (Spec_Id); + Error_Attr + ("incorrect prefix for % attribute, expected %", P); + end if; + end if; + + -- Otherwise the attribute's prefix denotes some other form of + -- a non-function subprogram. else - Error_Msg_Name_2 := Chars (Subp_Id); Error_Attr - ("incorrect prefix for % attribute, expected %", P); + ("% attribute can only appear in postcondition of " + & "function", P); end if; - Rewrite (N, Make_Identifier (Sloc (N), Name_uResult)); + -- Otherwise the prefix is illegal + + else + Error_Msg_Name_2 := Chars (Spec_Id); + Error_Attr ("incorrect prefix for % attribute, expected %", P); + end if; + + -- Attribute 'Result is part of the _Postconditions procedure of + -- the related subprogram. Rewrite the attribute as a reference to + -- the _Result formal parameter of _Postconditions. + + if In_Post then + Rewrite (N, Make_Identifier (Loc, Name_uResult)); Analyze_And_Resolve (N, Etype (Subp_Id)); + -- Otherwise decorate the attribute + else - Error_Attr - ("% attribute can only appear in postcondition of function", - P); + Set_Etype (N, Etype (Subp_Id)); end if; end if; end Result; |