diff --git a/flang/lib/Parser/parsing.cpp b/flang/lib/Parser/parsing.cpp --- a/flang/lib/Parser/parsing.cpp +++ b/flang/lib/Parser/parsing.cpp @@ -65,7 +65,7 @@ } currentCooked_ = &allCooked_.NewCookedSource(); Prescanner prescanner{ - messages_, *currentCooked_, allSources, preprocessor, options.features}; + messages_, *currentCooked_, preprocessor, options.features}; prescanner.set_fixedForm(options.isFixedForm) .set_fixedFormColumnLimit(options.fixedFormColumns) .AddCompilerDirectiveSentinel("dir$"); diff --git a/flang/lib/Parser/preprocessor.h b/flang/lib/Parser/preprocessor.h --- a/flang/lib/Parser/preprocessor.h +++ b/flang/lib/Parser/preprocessor.h @@ -28,6 +28,7 @@ namespace Fortran::parser { class Prescanner; +class Preprocessor; // Defines a macro class Definition { @@ -46,7 +47,7 @@ bool set_isDisabled(bool disable); - TokenSequence Apply(const std::vector &args, AllSources &); + TokenSequence Apply(const std::vector &args, Prescanner &); private: static TokenSequence Tokenize(const std::vector &argNames, @@ -65,12 +66,16 @@ public: explicit Preprocessor(AllSources &); + const AllSources &allSources() const { return allSources_; } + AllSources &allSources() { return allSources_; } + void Define(std::string macro, std::string value); void Undefine(std::string macro); bool IsNameDefined(const CharBlock &); std::optional MacroReplacement( - const TokenSequence &, const Prescanner &); + const TokenSequence &, Prescanner &); + TokenSequence Stringify(const TokenSequence &, Prescanner &); // Implements a preprocessor directive. void Directive(const TokenSequence &, Prescanner *); @@ -80,7 +85,7 @@ enum class CanDeadElseAppear { No, Yes }; CharBlock SaveTokenAsName(const CharBlock &); - TokenSequence ReplaceMacros(const TokenSequence &, const Prescanner &); + TokenSequence ReplaceMacros(const TokenSequence &, Prescanner &); void SkipDisabledConditionalCode( const std::string &, IsElseActive, Prescanner *, ProvenanceRange); bool IsIfPredicateTrue(const TokenSequence &expr, std::size_t first, diff --git a/flang/lib/Parser/preprocessor.cpp b/flang/lib/Parser/preprocessor.cpp --- a/flang/lib/Parser/preprocessor.cpp +++ b/flang/lib/Parser/preprocessor.cpp @@ -82,17 +82,18 @@ return 0; } -static TokenSequence Stringify( - const TokenSequence &tokens, AllSources &allSources) { +TokenSequence Preprocessor::Stringify( + const TokenSequence &tokens, Prescanner &prescanner) { TokenSequence result; - Provenance quoteProvenance{allSources.CompilerInsertionProvenance('"')}; + Provenance quoteProvenance{allSources_.CompilerInsertionProvenance('"')}; result.PutNextTokenChar('"', quoteProvenance); - for (std::size_t j{0}; j < tokens.SizeInTokens(); ++j) { - const CharBlock &token{tokens.TokenAt(j)}; + TokenSequence replacement{ReplaceMacros(tokens, prescanner)}; + for (std::size_t j{0}; j < replacement.SizeInTokens(); ++j) { + const CharBlock &token{replacement.TokenAt(j)}; std::size_t bytes{token.size()}; for (std::size_t k{0}; k < bytes; ++k) { char ch{token[k]}; - Provenance from{tokens.GetTokenProvenance(j, k)}; + Provenance from{replacement.GetTokenProvenance(j, k)}; if (ch == '"' || ch == '\\') { result.PutNextTokenChar(ch, from); } @@ -105,7 +106,7 @@ } TokenSequence Definition::Apply( - const std::vector &args, AllSources &allSources) { + const std::vector &args, Prescanner &prescanner) { TokenSequence result; bool pasting{false}; bool skipping{false}; @@ -136,7 +137,8 @@ while (result.SizeInTokens() >= afterLastNonBlank) { result.pop_back(); } - result.Put(Stringify(args[index], allSources)); + result.Put( + prescanner.preprocessor().Stringify(args[index], prescanner)); } else { std::size_t argTokens{args[index].SizeInTokens()}; for (std::size_t k{0}; k < argTokens; ++k) { @@ -161,7 +163,9 @@ // Delete whitespace immediately following ## in the body. } else if (bytes == 11 && isVariadic_ && token.ToString() == "__VA_ARGS__") { - Provenance commaProvenance{allSources.CompilerInsertionProvenance(',')}; + Provenance commaProvenance{ + prescanner.preprocessor().allSources().CompilerInsertionProvenance( + ',')}; for (std::size_t k{argumentCount_}; k < args.size(); ++k) { if (k > argumentCount_) { result.Put(","s, commaProvenance); @@ -218,7 +222,7 @@ void Preprocessor::Undefine(std::string macro) { definitions_.erase(macro); } std::optional Preprocessor::MacroReplacement( - const TokenSequence &input, const Prescanner &prescanner) { + const TokenSequence &input, Prescanner &prescanner) { // Do quick scan for any use of a defined name. std::size_t tokens{input.SizeInTokens()}; std::size_t j; @@ -333,7 +337,7 @@ } def.set_isDisabled(true); TokenSequence replaced{ - ReplaceMacros(def.Apply(args, allSources_), prescanner)}; + ReplaceMacros(def.Apply(args, prescanner), prescanner)}; def.set_isDisabled(false); if (!replaced.empty()) { ProvenanceRange from{def.replacement().GetProvenanceRange()}; @@ -348,7 +352,7 @@ } TokenSequence Preprocessor::ReplaceMacros( - const TokenSequence &tokens, const Prescanner &prescanner) { + const TokenSequence &tokens, Prescanner &prescanner) { if (std::optional repl{MacroReplacement(tokens, prescanner)}) { return std::move(*repl); } diff --git a/flang/lib/Parser/prescan.h b/flang/lib/Parser/prescan.h --- a/flang/lib/Parser/prescan.h +++ b/flang/lib/Parser/prescan.h @@ -33,11 +33,16 @@ class Prescanner { public: - Prescanner(Messages &, CookedSource &, AllSources &, Preprocessor &, + Prescanner(Messages &, CookedSource &, Preprocessor &, common::LanguageFeatureControl); Prescanner(const Prescanner &); - Messages &messages() const { return messages_; } + const AllSources &allSources() const { return allSources_; } + AllSources &allSources() { return allSources_; } + const Messages &messages() const { return messages_; } + Messages &messages() { return messages_; } + const Preprocessor &preprocessor() const { return preprocessor_; } + Preprocessor &preprocessor() { return preprocessor_; } Prescanner &set_fixedForm(bool yes) { inFixedForm_ = yes; @@ -181,8 +186,8 @@ Messages &messages_; CookedSource &cooked_; - AllSources &allSources_; Preprocessor &preprocessor_; + AllSources &allSources_; common::LanguageFeatureControl features_; bool inFixedForm_{false}; int fixedFormColumnLimit_{72}; diff --git a/flang/lib/Parser/prescan.cpp b/flang/lib/Parser/prescan.cpp --- a/flang/lib/Parser/prescan.cpp +++ b/flang/lib/Parser/prescan.cpp @@ -26,15 +26,14 @@ static constexpr int maxPrescannerNesting{100}; Prescanner::Prescanner(Messages &messages, CookedSource &cooked, - AllSources &allSources, Preprocessor &preprocessor, - common::LanguageFeatureControl lfc) - : messages_{messages}, cooked_{cooked}, allSources_{allSources}, - preprocessor_{preprocessor}, features_{lfc}, + Preprocessor &preprocessor, common::LanguageFeatureControl lfc) + : messages_{messages}, cooked_{cooked}, preprocessor_{preprocessor}, + allSources_{preprocessor_.allSources()}, features_{lfc}, encoding_{allSources_.encoding()} {} Prescanner::Prescanner(const Prescanner &that) : messages_{that.messages_}, cooked_{that.cooked_}, - allSources_{that.allSources_}, preprocessor_{that.preprocessor_}, + preprocessor_{that.preprocessor_}, allSources_{that.allSources_}, features_{that.features_}, inFixedForm_{that.inFixedForm_}, fixedFormColumnLimit_{that.fixedFormColumnLimit_}, encoding_{that.encoding_}, prescannerNesting_{that.prescannerNesting_ + diff --git a/flang/test/Preprocessing/assert.F90 b/flang/test/Preprocessing/assert.F90 new file mode 100644 --- /dev/null +++ b/flang/test/Preprocessing/assert.F90 @@ -0,0 +1,8 @@ +!RUN: %f18 -E %s 2>&1 | FileCheck %s +!CHECK: if(.not.(.true.)) error stop "assert(" // ".TRUE." // ") failed at " // +!CHECK: assert.F90" +!CHECK: // ":" // "7" +#define STR(x) #x +#define assert(x) if(.not.(x)) error stop "assert(" // #x // ") failed at " // __FILE__ // ":" // STR(__LINE__) +assert(.TRUE.) +end