The expression functions introduced in Ada 2012 implicitly come with the Inline aspect in GNAT. And, for inter-unit inlining, they were handled by the inlining machinery as any other inlined subprograms, which means that they were causing the package body (if any) to be loaded and analyzed.
That's both unnecessary and inefficient, so this patch corrects it as well as streamlines the implementation of the main entry point for inlining. The change can be exhibited by the now quiet compilation of Client in: with P; procedure Client is X : Boolean := P.Foo; begin null; end Client; package P is function Foo return Boolean is (True); procedure Other; end P; package body P is procedure Other is begin Unrelated; end Other; end P; Tested on x86_64-pc-linux-gnu, committed on trunk 2016-04-27 Eric Botcazou <ebotca...@adacore.com> * inline.adb (Add_Inlined_Body): Overhaul implementation, robustify handling of -gnatn1, add special treatment for expression functions.
Index: inline.adb =================================================================== --- inline.adb (revision 235481) +++ inline.adb (working copy) @@ -6,7 +6,7 @@ -- -- -- B o d y -- -- -- --- Copyright (C) 1992-2015, Free Software Foundation, Inc. -- +-- Copyright (C) 1992-2016, Free Software Foundation, Inc. -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- @@ -390,6 +390,40 @@ return; end if; + -- Find out whether the call must be inlined. Unless the result is + -- Dont_Inline, Must_Inline also creates an edge for the call in the + -- callgraph; however, it will not be activated until after Is_Called + -- is set on the subprogram. + + Level := Must_Inline; + + if Level = Dont_Inline then + return; + end if; + + -- If the call was generated by the compiler and is to a subprogram in + -- a run-time unit, we need to suppress debugging information for it, + -- so that the code that is eventually inlined will not affect the + -- debugging of the program. We do not do it if the call comes from + -- source because, even if the call is inlined, the user may expect it + -- to be present in the debugging information. + + if not Comes_From_Source (N) + and then In_Extended_Main_Source_Unit (N) + and then + Is_Predefined_File_Name (Unit_File_Name (Get_Source_Unit (E))) + then + Set_Needs_Debug_Info (E, False); + end if; + + -- If the subprogram is an expression function, then there is no need to + -- load any package body since the body of the function is in the spec. + + if Is_Expression_Function (E) then + Set_Is_Called (E); + return; + end if; + -- Find unit containing E, and add to list of inlined bodies if needed. -- If the body is already present, no need to load any other unit. This -- is the case for an initialization procedure, which appears in the @@ -403,77 +437,48 @@ -- no enclosing package to retrieve. In this case, it is the body of -- the function that will have to be loaded. - Level := Must_Inline; + declare + Pack : constant Entity_Id := Get_Code_Unit_Entity (E); - if Level /= Dont_Inline then - declare - Pack : constant Entity_Id := Get_Code_Unit_Entity (E); + begin + if Pack = E then + Set_Is_Called (E); + Inlined_Bodies.Increment_Last; + Inlined_Bodies.Table (Inlined_Bodies.Last) := E; - begin - -- Ensure that Analyze_Inlined_Bodies will be invoked after - -- completing the analysis of the current unit. + elsif Ekind (Pack) = E_Package then + Set_Is_Called (E); - Inline_Processing_Required := True; + if Is_Generic_Instance (Pack) then + null; - if Pack = E then + -- Do not inline the package if the subprogram is an init proc + -- or other internally generated subprogram, because in that + -- case the subprogram body appears in the same unit that + -- declares the type, and that body is visible to the back end. + -- Do not inline it either if it is in the main unit. + -- Extend the -gnatn2 processing to -gnatn1 for Inline_Always + -- calls if the back-end takes care of inlining the call. - -- Library-level inlined function. Add function itself to - -- list of needed units. - - Set_Is_Called (E); + elsif (Level = Inline_Package + or else (Level = Inline_Call + and then Has_Pragma_Inline_Always (E) + and then Back_End_Inlining)) + and then not Is_Inlined (Pack) + and then not Is_Internal (E) + and then not In_Main_Unit_Or_Subunit (Pack) + then + Set_Is_Inlined (Pack); Inlined_Bodies.Increment_Last; - Inlined_Bodies.Table (Inlined_Bodies.Last) := E; - - elsif Ekind (Pack) = E_Package then - Set_Is_Called (E); - - if Is_Generic_Instance (Pack) then - null; - - -- Do not inline the package if the subprogram is an init proc - -- or other internally generated subprogram, because in that - -- case the subprogram body appears in the same unit that - -- declares the type, and that body is visible to the back end. - -- Do not inline it either if it is in the main unit. - - elsif Level = Inline_Package - and then not Is_Inlined (Pack) - and then not Is_Internal (E) - and then not In_Main_Unit_Or_Subunit (Pack) - then - Set_Is_Inlined (Pack); - Inlined_Bodies.Increment_Last; - Inlined_Bodies.Table (Inlined_Bodies.Last) := Pack; - - -- Extend the -gnatn2 processing to -gnatn1 for Inline_Always - -- calls if the back-end takes care of inlining the call. - - elsif Level = Inline_Call - and then Has_Pragma_Inline_Always (E) - and then Back_End_Inlining - then - Set_Is_Inlined (Pack); - Inlined_Bodies.Increment_Last; - Inlined_Bodies.Table (Inlined_Bodies.Last) := Pack; - end if; + Inlined_Bodies.Table (Inlined_Bodies.Last) := Pack; end if; + end if; - -- If the call was generated by the compiler and is to a function - -- in a run-time unit, we need to suppress debugging information - -- for it, so that the code that is eventually inlined will not - -- affect debugging of the program. We do not do it if the call - -- comes from source because, even if the call is inlined, the - -- user may expect it to be present in the debugging information. + -- Ensure that Analyze_Inlined_Bodies will be invoked after + -- completing the analysis of the current unit. - if not Comes_From_Source (N) - and then In_Extended_Main_Source_Unit (N) - and then - Is_Predefined_File_Name (Unit_File_Name (Get_Source_Unit (E))) - then - Set_Needs_Debug_Info (E, False); - end if; - end; - end if; + Inline_Processing_Required := True; + end; end Add_Inlined_Body; ----------------------------