thakis created this revision.
thakis added a reviewer: rsmith.
thakis added a subscriber: cfe-commits.

This is useful for creating reproducible builds. Defining these via -D triggers 
warnings, and can cause bugs (presently, e.g. PR29119). It makes it also 
impossible to override __DATE__ and __TIME__ and forget __TIMESTAMP__.

__TIMESTAMP__ has slightly different semantics in that it's the timestamp of 
the current TU, not the time of compilation, but either meaning is bad for 
reproducible builds.

https://reviews.llvm.org/D23934

Files:
  include/clang/Driver/Options.td
  include/clang/Lex/PreprocessorOptions.h
  lib/Driver/Tools.cpp
  lib/Frontend/CompilerInvocation.cpp
  lib/Lex/PPMacroExpansion.cpp
  test/Preprocessor/fixed-date-time.cc

Index: test/Preprocessor/fixed-date-time.cc
===================================================================
--- test/Preprocessor/fixed-date-time.cc
+++ test/Preprocessor/fixed-date-time.cc
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -ffixed-date-time=2008-09-02T14:30:27 -std=c++11 %s -verify
+// RUN: not %clang_cc1 -ffixed-date-time=2008-09-02T14:30:27asdf -std=c++11 %s 2>&1 | FileCheck %s
+// expected-no-diagnostics
+
+// CHECK: error: invalid value '2008-09-02T14:30:27asdf' in '-ffixed-date-time=2008-09-02T14:30:27asdf'
+
+constexpr int constexpr_strcmp(const char *p, const char *q) {
+  return *p != *q ? *p - *q : !*p ? 0 : constexpr_strcmp(p + 1, q + 1);
+}
+
+static_assert(!constexpr_strcmp(__DATE__, "Sep  2 2008"), "");
+static_assert(!constexpr_strcmp(__TIME__, "14:30:27"), "");
+static_assert(!constexpr_strcmp(__TIMESTAMP__, "Tue Sep  2 14:30:27 2008"), "");
Index: include/clang/Driver/Options.td
===================================================================
--- include/clang/Driver/Options.td
+++ include/clang/Driver/Options.td
@@ -785,6 +785,9 @@
 def fexec_charset_EQ : Joined<["-"], "fexec-charset=">, Group<f_Group>;
 def finstrument_functions : Flag<["-"], "finstrument-functions">, Group<f_Group>, Flags<[CC1Option]>,
   HelpText<"Generate calls to instrument function entry and exit">;
+def ffixed_date_time_EQ : Joined<["-"], "ffixed-date-time=">, Group<f_Group>,
+  Flags<[CC1Option, CoreOption]>,
+  HelpText<"Set a fixed value for __DATE__, __TIME__, __TIMESTAMP__, formatted as 1969-12-31T23:59:59 (RFC3339 without fractional seconds and timezone)">;
 
 def fxray_instrument : Flag<["-"], "fxray-instrument">, Group<f_Group>,
   Flags<[CC1Option]>,
Index: include/clang/Lex/PreprocessorOptions.h
===================================================================
--- include/clang/Lex/PreprocessorOptions.h
+++ include/clang/Lex/PreprocessorOptions.h
@@ -12,11 +12,13 @@
 
 #include "clang/Basic/SourceLocation.h"
 #include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/Optional.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/StringSet.h"
 #include <cassert>
 #include <set>
 #include <string>
+#include <ctime>
 #include <utility>
 #include <vector>
 
@@ -138,6 +140,9 @@
   /// build it again.
   IntrusiveRefCntPtr<FailedModulesSet> FailedModules;
 
+  /// If set, a fixed time that __DATE__, __TIME__, __TIMESTAMP__ expand to.
+  llvm::Optional<tm> FixedDateTime;
+
 public:
   PreprocessorOptions() : UsePredefines(true), DetailedRecord(false),
                           DisablePCHValidation(false),
Index: lib/Lex/PPMacroExpansion.cpp
===================================================================
--- lib/Lex/PPMacroExpansion.cpp
+++ lib/Lex/PPMacroExpansion.cpp
@@ -21,6 +21,7 @@
 #include "clang/Lex/MacroArgs.h"
 #include "clang/Lex/MacroInfo.h"
 #include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessorOptions.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringSwitch.h"
@@ -1012,8 +1013,14 @@
 /// the identifier tokens inserted.
 static void ComputeDATE_TIME(SourceLocation &DATELoc, SourceLocation &TIMELoc,
                              Preprocessor &PP) {
-  time_t TT = time(nullptr);
-  struct tm *TM = localtime(&TT);
+  struct tm *TM;
+  PreprocessorOptions &PO = PP.getPreprocessorOpts();
+  if (PO.FixedDateTime.hasValue())
+    TM = PO.FixedDateTime.getPointer();
+  else {
+    time_t TT = time(nullptr);
+    TM = localtime(&TT);
+  }
 
   static const char * const Months[] = {
     "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"
@@ -1644,21 +1651,26 @@
     // MSVC, ICC, GCC, VisualAge C++ extension.  The generated string should be
     // of the form "Ddd Mmm dd hh::mm::ss yyyy", which is returned by asctime.
 
-    // Get the file that we are lexing out of.  If we're currently lexing from
-    // a macro, dig into the include stack.
-    const FileEntry *CurFile = nullptr;
-    PreprocessorLexer *TheLexer = getCurrentFileLexer();
-
-    if (TheLexer)
-      CurFile = SourceMgr.getFileEntryForID(TheLexer->getFileID());
-
     const char *Result;
-    if (CurFile) {
-      time_t TT = CurFile->getModificationTime();
-      struct tm *TM = localtime(&TT);
-      Result = asctime(TM);
+    PreprocessorOptions &PO = getPreprocessorOpts();
+    if (PO.FixedDateTime.hasValue()) {
+      Result = asctime(PO.FixedDateTime.getPointer());
     } else {
-      Result = "??? ??? ?? ??:??:?? ????\n";
+      // Get the file that we are lexing out of.  If we're currently lexing from
+      // a macro, dig into the include stack.
+      const FileEntry *CurFile = nullptr;
+      PreprocessorLexer *TheLexer = getCurrentFileLexer();
+
+      if (TheLexer)
+        CurFile = SourceMgr.getFileEntryForID(TheLexer->getFileID());
+
+      if (CurFile) {
+        time_t TT = CurFile->getModificationTime();
+        struct tm *TM = localtime(&TT);
+        Result = asctime(TM);
+      } else {
+        Result = "??? ??? ?? ??:??:?? ????\n";
+      }
     }
     // Surround the string with " and strip the trailing newline.
     OS << '"' << StringRef(Result).drop_back() << '"';
Index: lib/Frontend/CompilerInvocation.cpp
===================================================================
--- lib/Frontend/CompilerInvocation.cpp
+++ lib/Frontend/CompilerInvocation.cpp
@@ -44,6 +44,7 @@
 #include "llvm/Target/TargetOptions.h"
 #include "llvm/Support/ScopedPrinter.h"
 #include <atomic>
+#include <ctime>
 #include <memory>
 #include <sys/stat.h>
 #include <system_error>
@@ -2237,6 +2238,21 @@
     else
       Opts.ObjCXXARCStandardLibrary = (ObjCXXARCStandardLibraryKind)Library;
   }
+
+  if (Arg *A = Args.getLastArg(OPT_ffixed_date_time_EQ)) {
+    StringRef DateTime = A->getValue();
+    tm TM = {};
+    char *Rest = strptime(DateTime.str().c_str(), "%Y-%m-%dT%T", &TM);
+    if (!Rest || *Rest)
+      Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args)
+                                                << DateTime;
+    else {
+      // Fill in tm_wday.
+      TM.tm_isdst = -1;
+      mktime(&TM);
+      Opts.FixedDateTime = TM;
+    }
+  }
 }
 
 static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts,
Index: lib/Driver/Tools.cpp
===================================================================
--- lib/Driver/Tools.cpp
+++ lib/Driver/Tools.cpp
@@ -4681,6 +4681,11 @@
     CmdArgs.push_back("-generate-type-units");
   }
 
+  if (Arg *A = Args.getLastArg(options::OPT_ffixed_date_time_EQ)) {
+    StringRef DateTime = A->getValue();
+    CmdArgs.push_back(Args.MakeArgString("-ffixed-date-time=" + DateTime));
+  }
+
   // CloudABI and WebAssembly use -ffunction-sections and -fdata-sections by
   // default.
   bool UseSeparateSections = Triple.getOS() == llvm::Triple::CloudABI ||
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to