Description: set ALI timestamps from SOURCE_DATE_EPOCH if available.
 When the SOURCE_DATE_EPOCH environment variable is set,
 replace timestamps more recent than its value with its value
 when writing Ada Library Information (ALI) files.
 This allow reproducible builds from generated or patched Ada sources.
 https://reproducible-builds.org/specs/source-date-epoch/
 .
 Also see debian/ada/test_ada_source_date_epoch.sh.
 .
 c1d276b0e2cb60140389aa4c23ac3addb7a77af3 shortens this diff but
 modifies libgnat/*.  Such changes must wait a new GCC version because
 they invalidate the checksums in the .ali files.
 https://bugs.debian.org/954681 shows why this must be avoided.
Author: Nicolas Boulenguez <nicolas@debian.org>

--- a/src/gcc/ada/osint.adb
+++ b/src/gcc/ada/osint.adb
@@ -63,6 +63,10 @@
    --  Used in Locate_File as a fake directory when Name is already an
    --  absolute path.
 
+   Source_Date_Epoch : OS_Time := Invalid_Time;
+   --  Set at startup by the Initialize procedure.
+   --  See the specification of the File_Time_Stamp functions.
+
    -------------------------------------
    -- Use of Name_Find and Name_Enter --
    -------------------------------------
@@ -1094,8 +1098,15 @@ package body Osint is
    is
       function Internal (N : C_File_Name; A : System.Address) return OS_Time;
       pragma Import (C, Internal, "__gnat_file_time_name_attr");
+      T : OS_Time;
    begin
-      return Internal (Name, Attr.all'Address);
+      T := Internal (Name, Attr.all'Address);
+      if Source_Date_Epoch /= Invalid_Time and then T /= Invalid_Time
+        and then Source_Date_Epoch < T
+      then
+         T := Source_Date_Epoch;
+      end if;
+      return T;
    end File_Time_Stamp;
 
    function File_Time_Stamp
@@ -1118,6 +1129,7 @@ package body Osint is
    ----------------
 
    function File_Stamp (Name : File_Name_Type) return Time_Stamp_Type is
+      T : OS_Time;
    begin
       if Name = No_File then
          return Empty_Time_Stamp;
@@ -1129,9 +1141,13 @@ package body Osint is
       --  not exist, and OS_Time_To_GNAT_Time will convert this value to
       --  Empty_Time_Stamp. Therefore we do not need to first test whether
       --  the file actually exists, which saves a system call.
-
-      return OS_Time_To_GNAT_Time
-               (File_Time_Stamp (Name_Buffer (1 .. Name_Len)));
+      T := File_Time_Stamp (Name_Buffer (1 .. Name_Len));
+      if Source_Date_Epoch /= Invalid_Time and then T /= Invalid_Time
+        and then Source_Date_Epoch < T
+      then
+         T := Source_Date_Epoch;
+      end if;
+      return OS_Time_To_GNAT_Time (T);
    end File_Stamp;
 
    function File_Stamp (Name : Path_Name_Type) return Time_Stamp_Type is
@@ -1660,7 +1676,16 @@ package body Osint is
    ----------------
 
    procedure Initialize is
+      SDE_Env_Var : String_Access;
+      Get_OK      : Boolean;
    begin
+      SDE_Env_Var := Getenv ("SOURCE_DATE_EPOCH");
+      Get_OS_Time_From_String (SDE_Env_Var.all, Get_OK, Source_Date_Epoch);
+      if not Get_OK then
+         Source_Date_Epoch := Invalid_Time;
+      end if;
+      Free (SDE_Env_Var);
+
       Number_File_Names       := 0;
       Current_File_Name_Index := 0;
 
--- a/src/gcc/ada/osint.ads
+++ b/src/gcc/ada/osint.ads
@@ -189,6 +189,7 @@
    --  information in order to locate it. If the source file cannot be opened,
    --  or Name = No_File, and all blank time stamp is returned (this is not an
    --  error situation).
+   --  Handles SOURCE_DATE_EPOCH like File_Time_Stamp functions below.
 
    function File_Stamp (Name : Path_Name_Type) return Time_Stamp_Type;
    --  Same as above for a path name
@@ -293,6 +294,11 @@
      (Name : Path_Name_Type;
       Attr : access File_Attributes) return Time_Stamp_Type;
    --  Return the time stamp of the file
+   --  If the SOURCE_DATE_EPOCH environment variable exists and represents
+   --  an OS_Type value, any more recent file time stamp is truncated.
+   --  This ensures that gnat1 writes deterministic .ali files even in
+   --  the presence of patched or generated sources.  See
+   --  https://reproducible-builds.org/specs/source-date-epoch.
 
    function Is_Readable_File
      (Name : C_File_Name;
--- a/src/gcc/ada/libgnat/s-os_lib.adb
+++ b/src/gcc/ada/libgnat/s-os_lib.adb
@@ -1146,6 +1146,41 @@ package body System.OS_Lib is
       return Result;
    end Get_Object_Suffix;
 
+   -----------------------------
+   -- Get_OS_Time_From_String --
+   -----------------------------
+
+   procedure Get_OS_Time_From_String (Arg     : String;
+                                      Success : out Boolean;
+                                      Result  : out OS_Time) is
+      --  Calling System.Val_LLI breaks the bootstrap sequence.
+      Digit : OS_Time;
+   begin
+      Result := 0;
+      if Arg'Length = 0 then
+         Success := False;
+         return;
+      end if;
+      for I in Arg'Range loop
+         if Arg (I) not in '0' .. '9' then
+            Success := False;
+            return;
+         end if;
+         Digit := OS_Time (Character'Pos (Arg (I)) - Character'Pos ('0'));
+         if OS_Time'Last / 10 < Result then
+            Success := False;
+            return;
+         end if;
+         Result := Result * 10;
+         if OS_Time'Last - Digit < Result then
+            Success := False;
+            return;
+         end if;
+         Result := Result + Digit;
+      end loop;
+      Success := True;
+   end Get_OS_Time_From_String;
+
    ----------------------------------
    -- Get_Target_Debuggable_Suffix --
    ----------------------------------
--- a/src/gcc/ada/libgnat/s-os_lib.ads
+++ b/src/gcc/ada/libgnat/s-os_lib.ads
@@ -164,6 +164,13 @@ package System.OS_Lib is
    --  component parts to be interpreted in the local time zone, and returns
    --  an OS_Time. Returns Invalid_Time if the creation fails.
 
+   procedure Get_OS_Time_From_String (Arg     : String;
+                                      Success : out Boolean;
+                                      Result  : out OS_Time);
+   --  Success is set if Arg is not empty, only contains decimal
+   --  digits and represents an integer within OS_Time range.  Result
+   --  is then affected with the represented value.
+
    ----------------
    -- File Stuff --
    ----------------
