From cebb7d4ec25727bcdabe457f7ca8fdbc95a94801 Mon Sep 17 00:00:00 2001 From: Peter Klausler Date: Thu, 27 Jun 2024 16:49:15 -0700 Subject: [PATCH] [flang][preprocessor] Expand some keyword macros in quoted character literals To help port codes from compilers using pre-ANSI C preprocessors, which didn't care much about context when replacing macros, support the replacement of keyword macros in quoted character literals when (and only when) the name of the keyword macro constitutes the entire significant portion of a free form continuation line. See the new test case for a motivating example. Fixes https://github.com/llvm/llvm-project/issues/96781. --- flang/lib/Parser/prescan.cpp | 35 +++++++++++++++++++++++++ flang/test/Preprocessing/kw-in-char.F90 | 14 ++++++++++ 2 files changed, 49 insertions(+) create mode 100644 flang/test/Preprocessing/kw-in-char.F90 diff --git a/flang/lib/Parser/prescan.cpp b/flang/lib/Parser/prescan.cpp index 42aa829e0ed5b..668429a882291 100644 --- a/flang/lib/Parser/prescan.cpp +++ b/flang/lib/Parser/prescan.cpp @@ -820,6 +820,41 @@ void Prescanner::QuotedCharacterLiteral( } break; } + // Here's a weird edge case. When there's a two or more following + // continuation lines at this point, and the entire significant part of + // the next continuation line is the name of a keyword macro, replace + // it in the character literal with its definition. Example: + // #define FOO foo + // subroutine subr() bind(c, name="my_& + // &FOO& + // &_bar") ... + // produces a binding name of "my_foo_bar". + while (at_[1] == '&' && nextLine_ < limit_ && !InFixedFormSource()) { + const char *idStart{nextLine_}; + if (const char *amper{SkipWhiteSpace(nextLine_)}; *amper == '&') { + idStart = amper + 1; + } + if (IsLegalIdentifierStart(*idStart)) { + std::size_t idLen{1}; + for (; IsLegalInIdentifier(idStart[idLen]); ++idLen) { + } + if (idStart[idLen] == '&') { + CharBlock id{idStart, idLen}; + if (preprocessor_.IsNameDefined(id)) { + TokenSequence ppTokens; + ppTokens.Put(id, GetProvenance(idStart)); + if (auto replaced{ + preprocessor_.MacroReplacement(ppTokens, *this)}) { + tokens.Put(*replaced); + at_ = &idStart[idLen - 1]; + NextLine(); + continue; // try again on the next line + } + } + } + } + break; + } end = at_ + 1; NextChar(); if (*at_ == quote && !isEscaped) { diff --git a/flang/test/Preprocessing/kw-in-char.F90 b/flang/test/Preprocessing/kw-in-char.F90 new file mode 100644 index 0000000000000..e8f3a33b8a749 --- /dev/null +++ b/flang/test/Preprocessing/kw-in-char.F90 @@ -0,0 +1,14 @@ +! RUN: %flang -E %s 2>&1 | FileCheck %s +! CHECK: subroutine test_b_wrapper_c() bind(C, name="test_b_c_f") +#define TEMP_LETTER b +#define VAL c +subroutine test_& +TEMP_LETTER& +_wrapper_& +VAL& + () bind(C, name="test_& + &TEMP_LETTER& + &_& + &VAL& + &_f") +end