[flang][preprocessor] Support __TIMESTAMP__ (#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".
This commit is contained in:
Peter Klausler 2024-07-11 12:53:43 -07:00 committed by GitHub
parent 60c90336b6
commit 5024a6ec97
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 40 additions and 8 deletions

View File

@ -176,11 +176,11 @@ public:
const std::string &message, const std::string &prefix, const std::string &message, const std::string &prefix,
llvm::raw_ostream::Colors color, bool echoSourceLine = false) const; llvm::raw_ostream::Colors color, bool echoSourceLine = false) const;
const SourceFile *GetSourceFile( 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; const char *GetSource(ProvenanceRange) const;
std::optional<SourcePosition> GetSourcePosition(Provenance) const; std::optional<SourcePosition> GetSourcePosition(Provenance) const;
std::optional<ProvenanceRange> GetFirstFileProvenance() 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__ int GetLineNumber(Provenance) const; // __LINE__
Provenance CompilerInsertionProvenance(char ch); Provenance CompilerInsertionProvenance(char ch);
ProvenanceRange IntersectionWithSourceFiles(ProvenanceRange) const; ProvenanceRange IntersectionWithSourceFiles(ProvenanceRange) const;

View File

@ -12,6 +12,7 @@
#include "flang/Common/idioms.h" #include "flang/Common/idioms.h"
#include "flang/Parser/characters.h" #include "flang/Parser/characters.h"
#include "flang/Parser/message.h" #include "flang/Parser/message.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/raw_ostream.h" #include "llvm/Support/raw_ostream.h"
#include <algorithm> #include <algorithm>
#include <cinttypes> #include <cinttypes>
@ -289,6 +290,7 @@ void Preprocessor::DefineStandardMacros() {
// The values of these predefined macros depend on their invocation sites. // The values of these predefined macros depend on their invocation sites.
Define("__FILE__"s, "__FILE__"s); Define("__FILE__"s, "__FILE__"s);
Define("__LINE__"s, "__LINE__"s); Define("__LINE__"s, "__LINE__"s);
Define("__TIMESTAMP__"s, "__TIMESTAMP__"s);
} }
void Preprocessor::Define(const std::string &macro, const std::string &value) { 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}; llvm::raw_string_ostream ss{buf};
ss << allSources_.GetLineNumber(prescanner.GetCurrentProvenance()); ss << allSources_.GetLineNumber(prescanner.GetCurrentProvenance());
repl = ss.str(); 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()) { if (!repl.empty()) {
ProvenanceRange insert{allSources_.AddCompilerInsertion(repl)}; ProvenanceRange insert{allSources_.AddCompilerInsertion(repl)};

View File

@ -321,14 +321,19 @@ void AllSources::EmitMessage(llvm::raw_ostream &o,
} }
const SourceFile *AllSources::GetSourceFile( 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)}; const Origin &origin{MapToOrigin(at)};
return common::visit(common::visitors{ return common::visit(common::visitors{
[&](const Inclusion &inc) { [&](const Inclusion &inc) {
if (offset) { if (topLevel && !origin.replaces.empty()) {
*offset = origin.covers.MemberOffset(at); return GetSourceFile(
origin.replaces.start(), offset, topLevel);
} else {
if (offset) {
*offset = origin.covers.MemberOffset(at);
}
return &inc.source;
} }
return &inc.source;
}, },
[&](const Macro &) { [&](const Macro &) {
return GetSourceFile( return GetSourceFile(
@ -380,9 +385,9 @@ std::optional<ProvenanceRange> AllSources::GetFirstFileProvenance() const {
return std::nullopt; return std::nullopt;
} }
std::string AllSources::GetPath(Provenance at) const { std::string AllSources::GetPath(Provenance at, bool topLevel) const {
std::size_t offset{0}; 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; return source ? *source->GetSourcePosition(offset).path : ""s;
} }

View File

@ -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