[flang-commits] [flang] [flang][preprocessor] Support __TIMESTAMP__ (PR #98057)

Peter Klausler via flang-commits flang-commits at lists.llvm.org
Mon Jul 8 10:40:43 PDT 2024


https://github.com/klausler created https://github.com/llvm/llvm-project/pull/98057

Support the predefined macro __TIMESTAMP__ as interpreted by GCC. It expands to a character literal with the time of last modification of the top-level source file in asctime(3) format, e.g. "Tue Jul  4 10:18:05 1776".

>From 954e402b7fd275b3d9e7fd2c9888e29b5a339a2b Mon Sep 17 00:00:00 2001
From: Peter Klausler <pklausler at nvidia.com>
Date: Mon, 8 Jul 2024 10:34:30 -0700
Subject: [PATCH] [flang][preprocessor] Support __TIMESTAMP__

Support the predefined macro __TIMESTAMP__ as interpreted by GCC.
It expands to a character literal with the time of last modification
of the top-level source file in asctime(3) format, e.g.
"Tue Jul  4 10:18:05 1776".
---
 flang/include/flang/Parser/provenance.h |  4 ++--
 flang/lib/Parser/preprocessor.cpp       | 15 +++++++++++++++
 flang/lib/Parser/provenance.cpp         | 17 +++++++++++------
 flang/test/Preprocessing/timestamp.F90  | 12 ++++++++++++
 4 files changed, 40 insertions(+), 8 deletions(-)
 create mode 100644 flang/test/Preprocessing/timestamp.F90

diff --git a/flang/include/flang/Parser/provenance.h b/flang/include/flang/Parser/provenance.h
index 42c5b3de2cbe2..3189e012cd495 100644
--- a/flang/include/flang/Parser/provenance.h
+++ b/flang/include/flang/Parser/provenance.h
@@ -176,11 +176,11 @@ class AllSources {
       const std::string &message, const std::string &prefix,
       llvm::raw_ostream::Colors color, bool echoSourceLine = false) const;
   const SourceFile *GetSourceFile(
-      Provenance, std::size_t *offset = nullptr) const;
+      Provenance, std::size_t *offset = nullptr, bool topLevel = false) const;
   const char *GetSource(ProvenanceRange) const;
   std::optional<SourcePosition> GetSourcePosition(Provenance) const;
   std::optional<ProvenanceRange> GetFirstFileProvenance() const;
-  std::string GetPath(Provenance) const; // __FILE__
+  std::string GetPath(Provenance, bool topLevel = false) const; // __FILE__
   int GetLineNumber(Provenance) const; // __LINE__
   Provenance CompilerInsertionProvenance(char ch);
   ProvenanceRange IntersectionWithSourceFiles(ProvenanceRange) const;
diff --git a/flang/lib/Parser/preprocessor.cpp b/flang/lib/Parser/preprocessor.cpp
index 8896980bf4bbf..7d3130cd66ed9 100644
--- a/flang/lib/Parser/preprocessor.cpp
+++ b/flang/lib/Parser/preprocessor.cpp
@@ -12,6 +12,7 @@
 #include "flang/Common/idioms.h"
 #include "flang/Parser/characters.h"
 #include "flang/Parser/message.h"
+#include "llvm/Support/FileSystem.h"
 #include "llvm/Support/raw_ostream.h"
 #include <algorithm>
 #include <cinttypes>
@@ -289,6 +290,7 @@ void Preprocessor::DefineStandardMacros() {
   // The values of these predefined macros depend on their invocation sites.
   Define("__FILE__"s, "__FILE__"s);
   Define("__LINE__"s, "__LINE__"s);
+  Define("__TIMESTAMP__"s, "__TIMESTAMP__"s);
 }
 
 void Preprocessor::Define(const std::string &macro, const std::string &value) {
@@ -377,6 +379,19 @@ std::optional<TokenSequence> Preprocessor::MacroReplacement(
           llvm::raw_string_ostream ss{buf};
           ss << allSources_.GetLineNumber(prescanner.GetCurrentProvenance());
           repl = ss.str();
+        } else if (name == "__TIMESTAMP__") {
+          auto path{allSources_.GetPath(
+              prescanner.GetCurrentProvenance(), /*topLevel=*/true)};
+          llvm::sys::fs::file_status status;
+          repl = "??? ??? ?? ??:??:?? ????";
+          if (!llvm::sys::fs::status(path, status)) {
+            auto modTime{llvm::sys::toTimeT(status.getLastModificationTime())};
+            if (std::string time{std::asctime(std::localtime(&modTime))};
+                time.size() > 1 && time[time.size() - 1] == '\n') {
+              time.erase(time.size() - 1); // clip terminal '\n'
+              repl = "\""s + time + '"';
+            }
+          }
         }
         if (!repl.empty()) {
           ProvenanceRange insert{allSources_.AddCompilerInsertion(repl)};
diff --git a/flang/lib/Parser/provenance.cpp b/flang/lib/Parser/provenance.cpp
index 6e2e7326e2167..c67ddd22f0968 100644
--- a/flang/lib/Parser/provenance.cpp
+++ b/flang/lib/Parser/provenance.cpp
@@ -321,14 +321,19 @@ void AllSources::EmitMessage(llvm::raw_ostream &o,
 }
 
 const SourceFile *AllSources::GetSourceFile(
-    Provenance at, std::size_t *offset) const {
+    Provenance at, std::size_t *offset, bool topLevel) const {
   const Origin &origin{MapToOrigin(at)};
   return common::visit(common::visitors{
                            [&](const Inclusion &inc) {
-                             if (offset) {
-                               *offset = origin.covers.MemberOffset(at);
+                             if (topLevel && !origin.replaces.empty()) {
+                               return GetSourceFile(
+                                   origin.replaces.start(), offset, topLevel);
+                             } else {
+                               if (offset) {
+                                 *offset = origin.covers.MemberOffset(at);
+                               }
+                               return &inc.source;
                              }
-                             return &inc.source;
                            },
                            [&](const Macro &) {
                              return GetSourceFile(
@@ -380,9 +385,9 @@ std::optional<ProvenanceRange> AllSources::GetFirstFileProvenance() const {
   return std::nullopt;
 }
 
-std::string AllSources::GetPath(Provenance at) const {
+std::string AllSources::GetPath(Provenance at, bool topLevel) const {
   std::size_t offset{0};
-  const SourceFile *source{GetSourceFile(at, &offset)};
+  const SourceFile *source{GetSourceFile(at, &offset, topLevel)};
   return source ? *source->GetSourcePosition(offset).path : ""s;
 }
 
diff --git a/flang/test/Preprocessing/timestamp.F90 b/flang/test/Preprocessing/timestamp.F90
new file mode 100644
index 0000000000000..b8f431c3022b8
--- /dev/null
+++ b/flang/test/Preprocessing/timestamp.F90
@@ -0,0 +1,12 @@
+!RUN: %flang_fc1 -fdebug-unparse %s 2>&1 | FileCheck %s
+!CHECK: INTEGER, PARAMETER :: tslen = 24_4
+!CHECK: LOGICAL, PARAMETER :: tsspaces = .true._4
+!CHECK: LOGICAL, PARAMETER :: tscolons = .true._4
+
+integer, parameter :: tsLen = len(__TIMESTAMP__)
+character(tsLen), parameter :: ts = __TIMESTAMP__
+integer, parameter :: spaces(*) = [4, 8, 11, 20]
+integer, parameter :: colons(*) = [14, 17]
+logical, parameter :: tsSpaces = all([character(1)::(ts(spaces(j):spaces(j)),j=1,size(spaces))] == ' ')
+logical, parameter :: tsColons = all([character(1)::(ts(colons(j):colons(j)),j=1,size(colons))] == ':')
+end



More information about the flang-commits mailing list