MaskRay created this revision.
MaskRay added reviewers: clang-language-wg, aaron.ballman, appcs, efriedma, 
emaste.
Herald added a subscriber: StephenFan.
Herald added a project: All.
MaskRay requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

See https://reproducible-builds.org/docs/source-date-epoch/ . The environment
variable has ``SOURCE_DATE_EPOCH`` been recognized by many compilers.

In GCC, if `SOURCE_DATE_EPOCH` is set, it specifies a UNIX timestamp to be used
in replacement of the current date and time in the `__DATE__` and `__TIME__`
macros. Note: `__TIMESTAMP__` uses the modification time of the current source
file, which is unaffected by `SOURCE_DATE_EPOCH`.

The patch implements the GCC behavior.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D135045

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/DiagnosticFrontendKinds.td
  clang/include/clang/Lex/PreprocessorOptions.h
  clang/lib/Frontend/CompilerInvocation.cpp
  clang/lib/Lex/PPMacroExpansion.cpp
  clang/test/Preprocessor/SOURCE_DATE_EPOCH.c

Index: clang/test/Preprocessor/SOURCE_DATE_EPOCH.c
===================================================================
--- /dev/null
+++ clang/test/Preprocessor/SOURCE_DATE_EPOCH.c
@@ -0,0 +1,29 @@
+// RUN: env SOURCE_DATE_EPOCH=0 %clang_cc1 -E %s | FileCheck %s --check-prefix=19700101
+
+// 19700101:      const char date[] = "Jan  1 1970";
+// 19700101-NEXT: const char time[] = "00:00:00";
+
+// RUN: env SOURCE_DATE_EPOCH=1609459200 %clang_cc1 -E %s | FileCheck %s --check-prefix=20210101
+
+// 20210101:      const char date[] = "Jan  1 2021";
+// 20210101-NEXT: const char time[] = "00:00:00";
+// 20210101-NEXT: const char timestamp[] = "
+/// __TIMESTAMP__ is unaffected like GCC.
+// 20210101-NOT:  2021";
+
+// RUN: env SOURCE_DATE_EPOCH=253402300799 %clang_cc1 -E %s | FileCheck %s --check-prefix=99991231
+
+// 99991231:      const char date[] = "Dec 31 9999";
+// 99991231-NEXT: const char time[] = "23:59:59";
+
+// RUN: env SOURCE_DATE_EPOCH=253402300800 not %clang_cc1 -E %s 2>&1 | FileCheck %s --check-prefix=TOOBIG
+
+// TOOBIG: error: environment variable 'SOURCE_DATE_EPOCH' ('253402300800') must be a non-negative integer <= 253402300799
+
+// RUN: env SOURCE_DATE_EPOCH=0x0 not %clang_cc1 -E %s 2>&1 | FileCheck %s --check-prefix=NOTDECIMAL
+
+// NOTDECIMAL: error: environment variable 'SOURCE_DATE_EPOCH' ('0x0') must be a non-negative integer <= 253402300799
+
+const char date[] = __DATE__;
+const char time[] = __TIME__;
+const char timestamp[] = __TIMESTAMP__;
Index: clang/lib/Lex/PPMacroExpansion.cpp
===================================================================
--- clang/lib/Lex/PPMacroExpansion.cpp
+++ clang/lib/Lex/PPMacroExpansion.cpp
@@ -1085,8 +1085,15 @@
 /// the identifier tokens inserted.
 static void ComputeDATE_TIME(SourceLocation &DATELoc, SourceLocation &TIMELoc,
                              Preprocessor &PP) {
-  time_t TT = time(nullptr);
-  struct tm *TM = localtime(&TT);
+  time_t TT;
+  std::tm *TM;
+  if (PP.getPreprocessorOpts().SourceDateEpoch) {
+    TT = *PP.getPreprocessorOpts().SourceDateEpoch;
+    TM = std::gmtime(&TT);
+  } else {
+    TT = std::time(nullptr);
+    TM = std::localtime(&TT);
+  }
 
   static const char * const Months[] = {
     "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"
Index: clang/lib/Frontend/CompilerInvocation.cpp
===================================================================
--- clang/lib/Frontend/CompilerInvocation.cpp
+++ clang/lib/Frontend/CompilerInvocation.cpp
@@ -4307,6 +4307,15 @@
     Opts.addRemappedFile(Split.first, Split.second);
   }
 
+  if (const char *Epoch = std::getenv("SOURCE_DATE_EPOCH")) {
+    uint64_t V;
+    // 253402300799 is the UNIX timestamp of 9999-12-31T23:59:59Z.
+    if (StringRef(Epoch).getAsInteger(10, V) || V > 253402300799)
+      Diags.Report(diag::err_fe_invalid_source_date_epoch) << Epoch;
+    else
+      Opts.SourceDateEpoch = V;
+  }
+
   // Always avoid lexing editor placeholders when we're just running the
   // preprocessor as we never want to emit the
   // "editor placeholder in source file" error in PP only mode.
Index: clang/include/clang/Lex/PreprocessorOptions.h
===================================================================
--- clang/include/clang/Lex/PreprocessorOptions.h
+++ clang/include/clang/Lex/PreprocessorOptions.h
@@ -220,6 +220,9 @@
   /// Prevents intended crashes when using #pragma clang __debug. For testing.
   bool DisablePragmaDebugCrash = false;
 
+  /// If set, the UNIX timestamp specified by SOURCE_DATE_EPOCH.
+  Optional<uint64_t> SourceDateEpoch;
+
 public:
   PreprocessorOptions() : PrecompiledPreambleBytes(0, false) {}
 
Index: clang/include/clang/Basic/DiagnosticFrontendKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -130,6 +130,8 @@
 def warn_fe_concepts_ts_flag : Warning<
   "-fconcepts-ts is deprecated - use '-std=c++20' for Concepts support">,
   InGroup<Deprecated>;
+def err_fe_invalid_source_date_epoch : Error<
+    "environment variable 'SOURCE_DATE_EPOCH' ('%0') must be a non-negative integer <= 253402300799">;
 
 def err_fe_unable_to_load_basic_block_sections_file : Error<
     "unable to load basic block sections function list: '%0'">;
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -257,6 +257,10 @@
   is the target triple and `driver` first tries the canonical name
   for the driver (respecting ``--driver-mode=``), and then the name found
   in the executable.
+- If the environment variable ``SOURCE_DATE_EPOCH`` is set, it specifies a UNIX
+  timestamp to be used in replacement of the current date and time in
+  the ``__DATE__`` and ``__TIME__`` macros. See
+  `<https://reproducible-builds.org/docs/source-date-epoch/>`_.
 
 New Compiler Flags
 ------------------
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to