[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:
parent
60c90336b6
commit
5024a6ec97
@ -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;
|
||||||
|
@ -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 ¯o, const std::string &value) {
|
void Preprocessor::Define(const std::string ¯o, 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)};
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
12
flang/test/Preprocessing/timestamp.F90
Normal file
12
flang/test/Preprocessing/timestamp.F90
Normal 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
|
Loading…
x
Reference in New Issue
Block a user