[LoopReroll] Add an extra defensive check to avoid SCEV assertion.
[llvm-project.git] / flang / lib / Parser / parsing.cpp
blob0afa2a94ac40c7fb36735beedd47b36e5cfac0db
1 //===-- lib/Parser/parsing.cpp --------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "flang/Parser/parsing.h"
10 #include "preprocessor.h"
11 #include "prescan.h"
12 #include "type-parsers.h"
13 #include "flang/Parser/message.h"
14 #include "flang/Parser/provenance.h"
15 #include "flang/Parser/source.h"
16 #include "llvm/Support/raw_ostream.h"
18 namespace Fortran::parser {
20 Parsing::Parsing(AllCookedSources &allCooked) : allCooked_{allCooked} {}
21 Parsing::~Parsing() {}
23 const SourceFile *Parsing::Prescan(const std::string &path, Options options) {
24 options_ = options;
25 AllSources &allSources{allCooked_.allSources()};
26 if (options.isModuleFile) {
27 for (const auto &path : options.searchDirectories) {
28 allSources.AppendSearchPathDirectory(path);
32 std::string buf;
33 llvm::raw_string_ostream fileError{buf};
34 const SourceFile *sourceFile;
35 if (path == "-") {
36 sourceFile = allSources.ReadStandardInput(fileError);
37 } else {
38 std::optional<std::string> currentDirectory{"."};
39 sourceFile = allSources.Open(path, fileError, std::move(currentDirectory));
41 if (!fileError.str().empty()) {
42 ProvenanceRange range{allSources.AddCompilerInsertion(path)};
43 messages_.Say(range, "%s"_err_en_US, fileError.str());
44 return sourceFile;
46 CHECK(sourceFile);
48 if (!options.isModuleFile) {
49 // For .mod files we always want to look in the search directories.
50 // For normal source files we don't add them until after the primary
51 // source file has been opened. If foo.f is missing from the current
52 // working directory, we don't want to accidentally read another foo.f
53 // from another directory that's on the search path.
54 for (const auto &path : options.searchDirectories) {
55 allSources.AppendSearchPathDirectory(path);
59 Preprocessor preprocessor{allSources};
60 if (!options.predefinitions.empty()) {
61 preprocessor.DefineStandardMacros();
62 for (const auto &predef : options.predefinitions) {
63 if (predef.second) {
64 preprocessor.Define(predef.first, *predef.second);
65 } else {
66 preprocessor.Undefine(predef.first);
70 currentCooked_ = &allCooked_.NewCookedSource();
71 Prescanner prescanner{
72 messages_, *currentCooked_, preprocessor, options.features};
73 prescanner.set_fixedForm(options.isFixedForm)
74 .set_fixedFormColumnLimit(options.fixedFormColumns)
75 .AddCompilerDirectiveSentinel("dir$");
76 if (options.features.IsEnabled(LanguageFeature::OpenACC)) {
77 prescanner.AddCompilerDirectiveSentinel("$acc");
79 if (options.features.IsEnabled(LanguageFeature::OpenMP)) {
80 prescanner.AddCompilerDirectiveSentinel("$omp");
81 prescanner.AddCompilerDirectiveSentinel("$"); // OMP conditional line
83 ProvenanceRange range{allSources.AddIncludedFile(
84 *sourceFile, ProvenanceRange{}, options.isModuleFile)};
85 prescanner.Prescan(range);
86 if (currentCooked_->BufferedBytes() == 0 && !options.isModuleFile) {
87 // Input is empty. Append a newline so that any warning
88 // message about nonstandard usage will have provenance.
89 currentCooked_->Put('\n', range.start());
91 currentCooked_->Marshal(allCooked_);
92 if (options.needProvenanceRangeToCharBlockMappings) {
93 currentCooked_->CompileProvenanceRangeToOffsetMappings(allSources);
95 return sourceFile;
98 void Parsing::DumpCookedChars(llvm::raw_ostream &out) const {
99 UserState userState{allCooked_, common::LanguageFeatureControl{}};
100 ParseState parseState{cooked()};
101 parseState.set_inFixedForm(options_.isFixedForm).set_userState(&userState);
102 while (std::optional<const char *> p{parseState.GetNextChar()}) {
103 out << **p;
107 void Parsing::DumpProvenance(llvm::raw_ostream &out) const {
108 allCooked_.Dump(out);
111 void Parsing::DumpParsingLog(llvm::raw_ostream &out) const {
112 log_.Dump(out, allCooked_);
115 void Parsing::Parse(llvm::raw_ostream &out) {
116 UserState userState{allCooked_, options_.features};
117 userState.set_debugOutput(out)
118 .set_instrumentedParse(options_.instrumentedParse)
119 .set_log(&log_);
120 ParseState parseState{cooked()};
121 parseState.set_inFixedForm(options_.isFixedForm).set_userState(&userState);
122 parseTree_ = program.Parse(parseState);
123 CHECK(
124 !parseState.anyErrorRecovery() || parseState.messages().AnyFatalError());
125 consumedWholeFile_ = parseState.IsAtEnd();
126 messages_.Annex(std::move(parseState.messages()));
127 finalRestingPlace_ = parseState.GetLocation();
130 void Parsing::ClearLog() { log_.clear(); }
132 } // namespace Fortran::parser