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