Skip to content

Commit

Permalink
[flang][preprocessing] Allow keyword macro to rename a function-like …
Browse files Browse the repository at this point in the history
…macro

 #define FOO(x) ((x)+1)
 #define BAR FOO
 print *, BAR(1)

should work as one would expect.

Fixes #47162.

Differential Revision: https://reviews.llvm.org/D151154
  • Loading branch information
klausler committed May 22, 2023
1 parent d54ad0b commit 9efe158
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 23 deletions.
67 changes: 44 additions & 23 deletions flang/lib/Parser/preprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ std::optional<TokenSequence> Preprocessor::MacroReplacement(
}
TokenSequence result{input, 0, j};
for (; j < tokens; ++j) {
const CharBlock &token{input.TokenAt(j)};
CharBlock token{input.TokenAt(j)};
if (token.IsBlank() || !IsLegalIdentifierStart(token[0])) {
result.Put(input, j);
continue;
Expand All @@ -283,14 +283,15 @@ std::optional<TokenSequence> Preprocessor::MacroReplacement(
result.Put(input, j);
continue;
}
Definition &def{it->second};
if (def.isDisabled()) {
Definition *def{&it->second};
if (def->isDisabled()) {
result.Put(input, j);
continue;
}
if (!def.isFunctionLike()) {
if (def.isPredefined()) {
std::string name{def.replacement().TokenAt(0).ToString()};
if (!def->isFunctionLike()) {
bool isRenaming{false};
if (def->isPredefined()) {
std::string name{def->replacement().TokenAt(0).ToString()};
std::string repl;
if (name == "__FILE__") {
repl = "\""s +
Expand All @@ -309,18 +310,38 @@ std::optional<TokenSequence> Preprocessor::MacroReplacement(
continue;
}
}
def.set_isDisabled(true);
def->set_isDisabled(true);
TokenSequence replaced{
TokenPasting(ReplaceMacros(def.replacement(), prescanner))};
def.set_isDisabled(false);
if (!replaced.empty()) {
ProvenanceRange from{def.replacement().GetProvenanceRange()};
ProvenanceRange use{input.GetTokenProvenanceRange(j)};
ProvenanceRange newRange{
allSources_.AddMacroCall(from, use, replaced.ToString())};
result.Put(replaced, newRange);
TokenPasting(ReplaceMacros(def->replacement(), prescanner))};
def->set_isDisabled(false);
// Allow a keyword-like macro replacement to be the name of
// a function-like macro, possibly surrounded by blanks.
std::size_t k{0}, repTokens{replaced.SizeInTokens()};
for (; k < repTokens && replaced.TokenAt(k).IsBlank(); ++k) {
}
if (k < repTokens) {
token = replaced.TokenAt(k);
for (++k; k < repTokens && replaced.TokenAt(k).IsBlank(); ++k) {
}
if (k == repTokens && IsLegalIdentifierStart(token[0])) {
auto it{definitions_.find(token)};
if (it != definitions_.end() && !it->second.isDisabled() &&
it->second.isFunctionLike()) {
def = &it->second;
isRenaming = true;
}
}
}
if (!isRenaming) {
if (!replaced.empty()) {
ProvenanceRange from{def->replacement().GetProvenanceRange()};
ProvenanceRange use{input.GetTokenProvenanceRange(j)};
ProvenanceRange newRange{
allSources_.AddMacroCall(from, use, replaced.ToString())};
result.Put(replaced, newRange);
}
continue;
}
continue;
}
// Possible function-like macro call. Skip spaces and newlines to see
// whether '(' is next.
Expand Down Expand Up @@ -354,13 +375,13 @@ std::optional<TokenSequence> Preprocessor::MacroReplacement(
}
}
}
if (argStart.size() == 1 && k == argStart[0] && def.argumentCount() == 0) {
if (argStart.size() == 1 && k == argStart[0] && def->argumentCount() == 0) {
// Subtle: () is zero arguments, not one empty argument,
// unless one argument was expected.
argStart.clear();
}
if (k >= tokens || argStart.size() < def.argumentCount() ||
(argStart.size() > def.argumentCount() && !def.isVariadic())) {
if (k >= tokens || argStart.size() < def->argumentCount() ||
(argStart.size() > def->argumentCount() && !def->isVariadic())) {
result.Put(input, j);
continue;
}
Expand All @@ -371,12 +392,12 @@ std::optional<TokenSequence> Preprocessor::MacroReplacement(
(n + 1 == argStart.size() ? k : argStart[n + 1] - 1) - at};
args.emplace_back(TokenSequence(input, at, count));
}
def.set_isDisabled(true);
def->set_isDisabled(true);
TokenSequence replaced{
ReplaceMacros(def.Apply(args, prescanner), prescanner)};
def.set_isDisabled(false);
ReplaceMacros(def->Apply(args, prescanner), prescanner)};
def->set_isDisabled(false);
if (!replaced.empty()) {
ProvenanceRange from{def.replacement().GetProvenanceRange()};
ProvenanceRange from{def->replacement().GetProvenanceRange()};
ProvenanceRange use{input.GetIntervalProvenanceRange(j, k - j)};
ProvenanceRange newRange{
allSources_.AddMacroCall(from, use, replaced.ToString())};
Expand Down
8 changes: 8 additions & 0 deletions flang/test/Preprocessing/renaming.F
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
! RUN: %flang -E %s | FileCheck %s
! CHECK: ((1)*10000+(11)*100)
! Ensure that a keyword-like macro can be used to rename a
! function-like macro.
#define TO_VERSION2(MAJOR, MINOR) ((MAJOR) * 10000 + (MINOR) * 100)
#define TO_VERSION TO_VERSION2
print *, TO_VERSION(1,11)
end

0 comments on commit 9efe158

Please sign in to comment.