diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index aedc4c16d4e9d5..607ff47a857b8f 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -6898,6 +6898,8 @@ def module_suffix : Separate<["-"], "module-suffix">, Group, MetaVarNa HelpText<"Use as the suffix for module files (the default value is `.mod`)">; def fno_reformat : Flag<["-"], "fno-reformat">, Group, HelpText<"Dump the cooked character stream in -E mode">; +def fpreprocess_include_lines : Flag<["-"], "fpreprocess-include-lines">, Group, + HelpText<"Treat INCLUDE lines like #include directives in -E mode">; defm analyzed_objects_for_unparse : OptOutFC1FFlag<"analyzed-objects-for-unparse", "", "Do not use the analyzed objects when unparsing">; def emit_fir : Flag<["-"], "emit-fir">, Group, diff --git a/flang/include/flang/Frontend/PreprocessorOptions.h b/flang/include/flang/Frontend/PreprocessorOptions.h index 13a91ee9a184f8..2de9dabb1b3722 100644 --- a/flang/include/flang/Frontend/PreprocessorOptions.h +++ b/flang/include/flang/Frontend/PreprocessorOptions.h @@ -56,6 +56,9 @@ struct PreprocessorOptions { // -fno-reformat: Emit cooked character stream as -E output bool noReformat{false}; + // -fpreprocess-include-lines: Treat INCLUDE as #include for -E output + bool preprocessIncludeLines{false}; + // -dM: Show macro definitions with -dM -E bool showMacros{false}; diff --git a/flang/include/flang/Parser/parsing.h b/flang/include/flang/Parser/parsing.h index 4d329c189cb80e..0c774decb16d31 100644 --- a/flang/include/flang/Parser/parsing.h +++ b/flang/include/flang/Parser/parsing.h @@ -40,6 +40,7 @@ struct Options { bool needProvenanceRangeToCharBlockMappings{false}; Fortran::parser::Encoding encoding{Fortran::parser::Encoding::UTF_8}; bool prescanAndReformat{false}; // -E + bool expandIncludeLinesInPreprocessedOutput{true}; bool showColors{false}; }; diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp index d68534d5509fe9..2154b9ab2fbf47 100644 --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -820,6 +820,8 @@ static void parsePreprocessorArgs(Fortran::frontend::PreprocessorOptions &opts, : PPMacrosFlag::Exclude; opts.noReformat = args.hasArg(clang::driver::options::OPT_fno_reformat); + opts.preprocessIncludeLines = + args.hasArg(clang::driver::options::OPT_fpreprocess_include_lines); opts.noLineDirectives = args.hasArg(clang::driver::options::OPT_P); opts.showMacros = args.hasArg(clang::driver::options::OPT_dM); } @@ -1486,6 +1488,10 @@ void CompilerInvocation::setFortranOpts() { } fortranOptions.fixedFormColumns = frontendOptions.fixedFormColumns; + // -E + fortranOptions.prescanAndReformat = + frontendOptions.programAction == PrintPreprocessedInput; + fortranOptions.features = frontendOptions.features; fortranOptions.encoding = frontendOptions.encoding; diff --git a/flang/lib/Frontend/FrontendAction.cpp b/flang/lib/Frontend/FrontendAction.cpp index 42a614fe46be5b..041182bdf61781 100644 --- a/flang/lib/Frontend/FrontendAction.cpp +++ b/flang/lib/Frontend/FrontendAction.cpp @@ -95,6 +95,10 @@ bool FrontendAction::beginSourceFile(CompilerInstance &ci, getCurrentInput().getIsCUDAFortran()); } + // -fpreprocess-include-lines + invoc.getFortranOpts().expandIncludeLinesInPreprocessedOutput = + invoc.getPreprocessorOpts().preprocessIncludeLines; + // Decide between fixed and free form (if the user didn't express any // preference, use the file extension to decide) if (invoc.getFrontendOpts().fortranForm == FortranForm::Unknown) { diff --git a/flang/lib/Parser/parsing.cpp b/flang/lib/Parser/parsing.cpp index 37dc113436aa0e..d8448e4c527ac7 100644 --- a/flang/lib/Parser/parsing.cpp +++ b/flang/lib/Parser/parsing.cpp @@ -75,6 +75,8 @@ const SourceFile *Parsing::Prescan(const std::string &path, Options options) { messages_, *currentCooked_, preprocessor_, options.features}; prescanner.set_fixedForm(options.isFixedForm) .set_fixedFormColumnLimit(options.fixedFormColumns) + .set_expandIncludeLines(!options.prescanAndReformat || + options.expandIncludeLinesInPreprocessedOutput) .AddCompilerDirectiveSentinel("dir$"); if (options.features.IsEnabled(LanguageFeature::OpenACC)) { prescanner.AddCompilerDirectiveSentinel("$acc"); diff --git a/flang/lib/Parser/prescan.cpp b/flang/lib/Parser/prescan.cpp index b231c5859cf873..eabfcc244001ad 100644 --- a/flang/lib/Parser/prescan.cpp +++ b/flang/lib/Parser/prescan.cpp @@ -1031,6 +1031,9 @@ const char *Prescanner::IsFreeFormComment(const char *p) const { } std::optional Prescanner::IsIncludeLine(const char *start) const { + if (!expandIncludeLines_) { + return std::nullopt; + } const char *p{SkipWhiteSpace(start)}; if (*p == '0' && inFixedForm_ && p == start + 5) { // Accept " 0INCLUDE" in fixed form. diff --git a/flang/lib/Parser/prescan.h b/flang/lib/Parser/prescan.h index 9d4f7c0c302a1a..c50bf231e3c705 100644 --- a/flang/lib/Parser/prescan.h +++ b/flang/lib/Parser/prescan.h @@ -48,6 +48,10 @@ class Prescanner { Preprocessor &preprocessor() { return preprocessor_; } common::LanguageFeatureControl &features() { return features_; } + Prescanner &set_expandIncludeLines(bool yes) { + expandIncludeLines_ = yes; + return *this; + } Prescanner &set_fixedForm(bool yes) { inFixedForm_ = yes; return *this; @@ -209,6 +213,7 @@ class Prescanner { Preprocessor &preprocessor_; AllSources &allSources_; common::LanguageFeatureControl features_; + bool expandIncludeLines_{true}; bool isNestedInIncludeDirective_{false}; bool backslashFreeFormContinuation_{false}; bool inFixedForm_{false}; diff --git a/flang/test/Parser/include.f b/flang/test/Parser/include.f index 8a7fe3a2ecd9d0..6e16afd92ad0ce 100644 --- a/flang/test/Parser/include.f +++ b/flang/test/Parser/include.f @@ -1,4 +1,4 @@ -! RUN: %flang_fc1 -E -I %S/Inputs %s 2>&1 | FileCheck %s +! RUN: %flang_fc1 -E -fpreprocess-include-lines -I %S/Inputs %s 2>&1 | FileCheck %s include 'include-file' include "include-file" include 1_'include-file'