Skip to content

Commit 114723a

Browse files
klauslerbanach-space
authored andcommitted
[flang] Produce proper "preprocessor output" for -E option
Rename the current -E option to "-E -Xflang -fno-reformat". Add a new Parsing::EmitPreprocessedSource() routine to convert the cooked character stream output of the prescanner back to something more closely resembling output from a traditional preprocessor; call this new routine when -E appears. The new -E output is suitable for use as fixed form Fortran source to compilation by (one hopes) any Fortran compiler. If the original top-level source file had been free form source, the output will be suitable for use as free form source as well; otherwise there may be diagnostics about missing spaces if they were indeed absent in the original fixed form source. Unless the -P option appears, #line directives are interspersed with the output (but be advised, f18 will ignore these if presented with them in a later compilation). An effort has been made to preserve original alphabetic character case and source indentation. Add -P and -fno-reformat to the new drivers. Tweak test options to avoid confusion with prior -E output; use -fno-reformat where needed, but prefer to keep -E, sometimes in concert with -P, on most, updating expected results accordingly. Differential Revision: https://reviews.llvm.org/D106727
1 parent b1f5cfd commit 114723a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+341
-197
lines changed

clang/include/clang/Driver/Options.td

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -701,7 +701,7 @@ def ObjC : Flag<["-"], "ObjC">, Flags<[NoXarchOption]>,
701701
def O : Joined<["-"], "O">, Group<O_Group>, Flags<[CC1Option]>;
702702
def O_flag : Flag<["-"], "O">, Flags<[CC1Option]>, Alias<O>, AliasArgs<["1"]>;
703703
def Ofast : Joined<["-"], "Ofast">, Group<O_Group>, Flags<[CC1Option]>;
704-
def P : Flag<["-"], "P">, Flags<[CC1Option]>, Group<Preprocessor_Group>,
704+
def P : Flag<["-"], "P">, Flags<[CC1Option,FlangOption,FC1Option]>, Group<Preprocessor_Group>,
705705
HelpText<"Disable linemarker output in -E mode">,
706706
MarshallingInfoNegativeFlag<PreprocessorOutputOpts<"ShowLineMarkers">>;
707707
def Qy : Flag<["-"], "Qy">, Flags<[CC1Option]>,
@@ -4514,7 +4514,7 @@ def fdebug_measure_parse_tree : Flag<["-"], "fdebug-measure-parse-tree">, Group<
45144514
HelpText<"Measure the parse tree">;
45154515
def fdebug_pre_fir_tree : Flag<["-"], "fdebug-pre-fir-tree">, Group<Action_Group>,
45164516
HelpText<"Dump the pre-FIR tree">;
4517-
def fdebug_module_writer : Flag<["-"],"fdebug-module-writer">,
4517+
def fdebug_module_writer : Flag<["-"],"fdebug-module-writer">,
45184518
HelpText<"Enable debug messages while writing module files">;
45194519
def fget_symbols_sources : Flag<["-"], "fget-symbols-sources">, Group<Action_Group>,
45204520
HelpText<"Dump symbols and their source code locations">;
@@ -4526,7 +4526,8 @@ def fanalyzed_objects_for_unparse : Flag<["-"],
45264526
def fno_analyzed_objects_for_unparse : Flag<["-"],
45274527
"fno-analyzed-objects-for-unparse">, Group<f_Group>,
45284528
HelpText<"Do not use the analyzed objects when unparsing">;
4529-
4529+
def fno_reformat : Flag<["-"], "fno-reformat">, Group<Preprocessor_Group>,
4530+
HelpText<"Dump the cooked character stream in -E mode">;
45304531
}
45314532

45324533
//===----------------------------------------------------------------------===//

clang/lib/Driver/ToolChains/Flang.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,9 @@ void Flang::AddFortranDialectOptions(const ArgList &Args,
3737

3838
void Flang::AddPreprocessingOptions(const ArgList &Args,
3939
ArgStringList &CmdArgs) const {
40-
Args.AddAllArgs(CmdArgs, {options::OPT_D, options::OPT_U, options::OPT_I,
41-
options::OPT_cpp, options::OPT_nocpp});
40+
Args.AddAllArgs(CmdArgs,
41+
{options::OPT_P, options::OPT_D, options::OPT_U,
42+
options::OPT_I, options::OPT_cpp, options::OPT_nocpp});
4243
}
4344

4445
void Flang::AddOtherOptions(const ArgList &Args, ArgStringList &CmdArgs) const {

flang/include/flang/Frontend/FrontendOptions.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ enum ActionKind {
2525
/// -test-io mode
2626
InputOutputTest,
2727

28-
/// -E mode.
28+
/// -E mode
2929
PrintPreprocessedInput,
3030

3131
/// -fsyntax-only

flang/include/flang/Frontend/PreprocessorOptions.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ class PreprocessorOptions {
4444

4545
PPMacrosFlag macrosFlag_ = PPMacrosFlag::Unknown;
4646

47+
// -P: Suppress #line directives in -E output
48+
bool noLineDirectives{false};
49+
50+
// -fno-reformat: Emit cooked character stream as -E output
51+
bool noReformat{false};
52+
4753
public:
4854
PreprocessorOptions() {}
4955

flang/include/flang/Parser/parsing.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ struct Options {
3737
bool isModuleFile{false};
3838
bool needProvenanceRangeToCharBlockMappings{false};
3939
Fortran::parser::Encoding encoding{Fortran::parser::Encoding::UTF_8};
40+
bool prescanAndReformat{false}; // -E
4041
};
4142

4243
class Parsing {
@@ -47,12 +48,15 @@ class Parsing {
4748
bool consumedWholeFile() const { return consumedWholeFile_; }
4849
const char *finalRestingPlace() const { return finalRestingPlace_; }
4950
AllCookedSources &allCooked() { return allCooked_; }
51+
const AllCookedSources &allCooked() const { return allCooked_; }
5052
Messages &messages() { return messages_; }
5153
std::optional<Program> &parseTree() { return parseTree_; }
5254

5355
const CookedSource &cooked() const { return DEREF(currentCooked_); }
5456

5557
const SourceFile *Prescan(const std::string &path, Options);
58+
void EmitPreprocessedSource(
59+
llvm::raw_ostream &, bool lineDirectives = true) const;
5660
void DumpCookedChars(llvm::raw_ostream &) const;
5761
void DumpProvenance(llvm::raw_ostream &) const;
5862
void DumpParsingLog(llvm::raw_ostream &) const;

flang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,9 @@ static void parsePreprocessorArgs(
371371
(currentArg->getOption().matches(clang::driver::options::OPT_cpp))
372372
? PPMacrosFlag::Include
373373
: PPMacrosFlag::Exclude;
374+
375+
opts.noReformat = args.hasArg(clang::driver::options::OPT_fno_reformat);
376+
opts.noLineDirectives = args.hasArg(clang::driver::options::OPT_P);
374377
}
375378

376379
/// Parses all semantic related arguments and populates the variables

flang/lib/Frontend/FrontendActions.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -208,9 +208,14 @@ void PrintPreprocessedAction::ExecuteAction() {
208208
std::string buf;
209209
llvm::raw_string_ostream outForPP{buf};
210210

211-
// Run the preprocessor
211+
// Format or dump the prescanner's output
212212
CompilerInstance &ci = this->instance();
213-
ci.parsing().DumpCookedChars(outForPP);
213+
if (ci.invocation().preprocessorOpts().noReformat) {
214+
ci.parsing().DumpCookedChars(outForPP);
215+
} else {
216+
ci.parsing().EmitPreprocessedSource(
217+
outForPP, !ci.invocation().preprocessorOpts().noLineDirectives);
218+
}
214219

215220
// If a pre-defined output stream exists, dump the preprocessed content there
216221
if (!ci.IsOutputStreamNull()) {
@@ -219,7 +224,7 @@ void PrintPreprocessedAction::ExecuteAction() {
219224
return;
220225
}
221226

222-
// Print diagnostics from the preprocessor
227+
// Print diagnostics from the prescanner
223228
ci.parsing().messages().Emit(llvm::errs(), ci.allCookedSources());
224229

225230
// Create a file and save the preprocessed output there
@@ -228,7 +233,6 @@ void PrintPreprocessedAction::ExecuteAction() {
228233
(*os) << outForPP.str();
229234
} else {
230235
llvm::errs() << "Unable to create the output file\n";
231-
return;
232236
}
233237
}
234238

flang/lib/Frontend/FrontendOptions.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "flang/Frontend/FrontendOptions.h"
10-
#include "flang/Evaluate/expression.h"
1110

1211
using namespace Fortran::frontend;
1312

flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,61 +28,43 @@ static std::unique_ptr<FrontendAction> CreateFrontendBaseAction(
2828
switch (ak) {
2929
case InputOutputTest:
3030
return std::make_unique<InputOutputTestAction>();
31-
break;
3231
case PrintPreprocessedInput:
3332
return std::make_unique<PrintPreprocessedAction>();
34-
break;
3533
case ParseSyntaxOnly:
3634
return std::make_unique<ParseSyntaxOnlyAction>();
3735
case EmitObj:
3836
return std::make_unique<EmitObjAction>();
39-
break;
4037
case DebugUnparse:
4138
return std::make_unique<DebugUnparseAction>();
42-
break;
4339
case DebugUnparseNoSema:
4440
return std::make_unique<DebugUnparseNoSemaAction>();
45-
break;
4641
case DebugUnparseWithSymbols:
4742
return std::make_unique<DebugUnparseWithSymbolsAction>();
48-
break;
4943
case DebugDumpSymbols:
5044
return std::make_unique<DebugDumpSymbolsAction>();
51-
break;
5245
case DebugDumpParseTree:
5346
return std::make_unique<DebugDumpParseTreeAction>();
54-
break;
5547
case DebugDumpParseTreeNoSema:
5648
return std::make_unique<DebugDumpParseTreeNoSemaAction>();
57-
break;
5849
case DebugDumpAll:
5950
return std::make_unique<DebugDumpAllAction>();
60-
break;
6151
case DebugDumpProvenance:
6252
return std::make_unique<DebugDumpProvenanceAction>();
63-
break;
6453
case DebugDumpParsingLog:
6554
return std::make_unique<DebugDumpParsingLogAction>();
66-
break;
6755
case DebugMeasureParseTree:
6856
return std::make_unique<DebugMeasureParseTreeAction>();
69-
break;
7057
case DebugPreFIRTree:
7158
return std::make_unique<DebugPreFIRTreeAction>();
72-
break;
7359
case GetDefinition:
7460
return std::make_unique<GetDefinitionAction>();
75-
break;
7661
case GetSymbolsSources:
7762
return std::make_unique<GetSymbolsSourcesAction>();
78-
break;
7963
case InitOnly:
8064
return std::make_unique<InitOnlyAction>();
81-
break;
8265
default:
8366
break;
8467
// TODO:
85-
// case RunPreprocessor:
8668
// case ParserSyntaxOnly:
8769
// case EmitLLVM:
8870
// case EmitLLVMOnly:

flang/lib/Parser/parsing.cpp

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,94 @@ const SourceFile *Parsing::Prescan(const std::string &path, Options options) {
9595
return sourceFile;
9696
}
9797

98+
void Parsing::EmitPreprocessedSource(
99+
llvm::raw_ostream &out, bool lineDirectives) const {
100+
const SourceFile *sourceFile{nullptr};
101+
int sourceLine{0};
102+
int column{1};
103+
bool inDirective{false};
104+
bool inContinuation{false};
105+
const AllSources &allSources{allCooked().allSources()};
106+
for (const char &atChar : cooked().AsCharBlock()) {
107+
char ch{atChar};
108+
if (ch == '\n') {
109+
out << '\n'; // TODO: DOS CR-LF line ending if necessary
110+
column = 1;
111+
inDirective = false;
112+
inContinuation = false;
113+
++sourceLine;
114+
} else {
115+
if (ch == '!') {
116+
// Other comment markers (C, *, D) in original fixed form source
117+
// input card column 1 will have been deleted or normalized to !,
118+
// which signifies a comment (directive) in both source forms.
119+
inDirective = true;
120+
}
121+
auto provenance{cooked().GetProvenanceRange(CharBlock{&atChar, 1})};
122+
std::optional<SourcePosition> position{provenance
123+
? allSources.GetSourcePosition(provenance->start())
124+
: std::nullopt};
125+
if (lineDirectives && column == 1 && position) {
126+
if (&position->file != sourceFile) {
127+
out << "#line \"" << position->file.path() << "\" " << position->line
128+
<< '\n';
129+
} else if (position->line != sourceLine) {
130+
if (sourceLine < position->line &&
131+
sourceLine + 10 >= position->line) {
132+
// Emit a few newlines to catch up when they'll likely
133+
// require fewer bytes than a #line directive would have
134+
// occupied.
135+
while (sourceLine++ < position->line) {
136+
out << '\n';
137+
}
138+
} else {
139+
out << "#line " << position->line << '\n';
140+
}
141+
}
142+
sourceFile = &position->file;
143+
sourceLine = position->line;
144+
}
145+
if (column > 72) {
146+
// Wrap long lines in a portable fashion that works in both
147+
// of the Fortran source forms. The first free-form continuation
148+
// marker ("&") lands in column 73, which begins the card commentary
149+
// field of fixed form, and the second one is put in column 6,
150+
// where it signifies fixed form line continuation.
151+
// The standard Fortran fixed form column limit (72) is used
152+
// for output, even if the input was parsed with a nonstandard
153+
// column limit override option.
154+
out << "&\n &";
155+
column = 7; // start of fixed form source field
156+
++sourceLine;
157+
inContinuation = true;
158+
} else if (!inDirective && ch != ' ' && (ch < '0' || ch > '9')) {
159+
// Put anything other than a label or directive into the
160+
// Fortran fixed form source field (columns [7:72]).
161+
for (; column < 7; ++column) {
162+
out << ' ';
163+
}
164+
}
165+
if (!inContinuation && position && position->column <= 72 && ch != ' ') {
166+
// Preserve original indentation
167+
for (; column < position->column; ++column) {
168+
out << ' ';
169+
}
170+
}
171+
if (ch >= 'a' && ch <= 'z' && provenance && provenance->size() == 1) {
172+
// Preserve original case
173+
if (const char *orig{allSources.GetSource(*provenance)}) {
174+
auto upper{static_cast<char>(ch + 'A' - 'a')};
175+
if (*orig == upper) {
176+
ch = upper;
177+
}
178+
}
179+
}
180+
out << ch;
181+
++column;
182+
}
183+
}
184+
}
185+
98186
void Parsing::DumpCookedChars(llvm::raw_ostream &out) const {
99187
UserState userState{allCooked_, common::LanguageFeatureControl{}};
100188
ParseState parseState{cooked()};

0 commit comments

Comments
 (0)