1//===-- lib/Support/Fortran-features.cpp ------------------------*- C++ -*-===//
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//===----------------------------------------------------------------------===//
8
9#include "flang/Support/Fortran-features.h"
10#include "flang/Common/idioms.h"
11#include "flang/Parser/characters.h"
12#include "flang/Support/Fortran.h"
13#include <string>
14#include <string_view>
15
16namespace Fortran::common {
17
18static std::vector<std::string_view> SplitCamelCase(std::string_view x) {
19 std::vector<std::string_view> result;
20 // NB, we start at 1 because the first character is never a word boundary.
21 size_t xSize{x.size()}, wordStart{0}, wordEnd{1};
22 for (; wordEnd < xSize; ++wordEnd) {
23 // Identify when wordEnd is at the start of a new word.
24 if ((!parser::IsUpperCaseLetter(x[wordEnd - 1]) &&
25 parser::IsUpperCaseLetter(x[wordEnd])) ||
26 // ACCUsage => ACC-Usage, CComment => C-Comment, etc.
27 (parser::IsUpperCaseLetter(x[wordEnd]) && wordEnd + 1 < xSize &&
28 parser::IsLowerCaseLetter(x[wordEnd + 1]))) {
29 result.push_back(x.substr(wordStart, wordEnd - wordStart));
30 wordStart = wordEnd;
31 }
32 }
33 // We went one past the end of the last word.
34 result.push_back(x.substr(wordStart, wordEnd - wordStart));
35 return result;
36}
37
38// Namespace for helper functions for parsing Cli options used instead of static
39// so that there can be unit tests for this function.
40namespace details {
41std::string CamelCaseToLowerCaseHyphenated(std::string_view x) {
42 std::vector<std::string_view> words{SplitCamelCase(x)};
43 std::string result{};
44 result.reserve(x.size() + words.size() + 1);
45 for (size_t i{0}; i < words.size(); ++i) {
46 std::string word{parser::ToLowerCaseLetters(words[i])};
47 result += i == 0 ? "" : "-";
48 result += word;
49 }
50 return result;
51}
52} // namespace details
53
54LanguageFeatureControl::LanguageFeatureControl() {
55 // Initialize the bidirectional maps with the default spellings.
56 cliOptions_.reserve(LanguageFeature_enumSize + UsageWarning_enumSize);
57 ForEachLanguageFeature([&](auto feature) {
58 std::string_view name{Fortran::common::EnumToString(feature)};
59 std::string cliOption{details::CamelCaseToLowerCaseHyphenated(name)};
60 cliOptions_.insert({cliOption, {feature}});
61 languageFeatureCliCanonicalSpelling_[EnumToInt(feature)] =
62 std::string_view{cliOption};
63 });
64
65 ForEachUsageWarning([&](auto warning) {
66 std::string_view name{Fortran::common::EnumToString(warning)};
67 std::string cliOption{details::CamelCaseToLowerCaseHyphenated(name)};
68 cliOptions_.insert({cliOption, {warning}});
69 usageWarningCliCanonicalSpelling_[EnumToInt(warning)] =
70 std::string_view{cliOption};
71 });
72
73 // These features must be explicitly enabled by command line options.
74 disable_.set(LanguageFeature::OldDebugLines);
75 disable_.set(LanguageFeature::OpenACC);
76 disable_.set(LanguageFeature::OpenMP);
77 disable_.set(LanguageFeature::CUDA); // !@cuf
78 disable_.set(LanguageFeature::CudaManaged);
79 disable_.set(LanguageFeature::CudaUnified);
80 disable_.set(LanguageFeature::ImplicitNoneTypeNever);
81 disable_.set(LanguageFeature::ImplicitNoneTypeAlways);
82 disable_.set(LanguageFeature::ImplicitNoneExternal);
83 disable_.set(LanguageFeature::DefaultSave);
84 disable_.set(LanguageFeature::SaveMainProgram);
85 // These features, if enabled, conflict with valid standard usage,
86 // so there are disabled here by default.
87 disable_.set(LanguageFeature::BackslashEscapes);
88 disable_.set(LanguageFeature::LogicalAbbreviations);
89 disable_.set(LanguageFeature::XOROperator);
90 disable_.set(LanguageFeature::OldStyleParameter);
91 // Possibly an accidental "feature" of nvfortran.
92 disable_.set(LanguageFeature::AssumedRankPassedToNonAssumedRank);
93 // These warnings are enabled by default, but only because they used
94 // to be unconditional. TODO: prune this list
95 warnLanguage_.set(LanguageFeature::ExponentMatchingKindParam);
96 warnLanguage_.set(LanguageFeature::RedundantAttribute);
97 warnLanguage_.set(LanguageFeature::SubroutineAndFunctionSpecifics);
98 warnLanguage_.set(LanguageFeature::EmptySequenceType);
99 warnLanguage_.set(LanguageFeature::NonSequenceCrayPointee);
100 warnLanguage_.set(LanguageFeature::BranchIntoConstruct);
101 warnLanguage_.set(LanguageFeature::BadBranchTarget);
102 warnLanguage_.set(LanguageFeature::HollerithPolymorphic);
103 warnLanguage_.set(LanguageFeature::ListDirectedSize);
104 warnLanguage_.set(LanguageFeature::IgnoreIrrelevantAttributes);
105 warnLanguage_.set(LanguageFeature::AmbiguousStructureConstructor);
106 warnUsage_.set(UsageWarning::ShortArrayActual);
107 warnUsage_.set(UsageWarning::FoldingException);
108 warnUsage_.set(UsageWarning::FoldingAvoidsRuntimeCrash);
109 warnUsage_.set(UsageWarning::FoldingValueChecks);
110 warnUsage_.set(UsageWarning::FoldingFailure);
111 warnUsage_.set(UsageWarning::FoldingLimit);
112 warnUsage_.set(UsageWarning::Interoperability);
113 // CharacterInteroperability warnings about length are off by default
114 warnUsage_.set(UsageWarning::Bounds);
115 warnUsage_.set(UsageWarning::Preprocessing);
116 warnUsage_.set(UsageWarning::Scanning);
117 warnUsage_.set(UsageWarning::OpenAccUsage);
118 warnUsage_.set(UsageWarning::ProcPointerCompatibility);
119 warnUsage_.set(UsageWarning::VoidMold);
120 warnUsage_.set(UsageWarning::KnownBadImplicitInterface);
121 warnUsage_.set(UsageWarning::EmptyCase);
122 warnUsage_.set(UsageWarning::CaseOverflow);
123 warnUsage_.set(UsageWarning::CUDAUsage);
124 warnUsage_.set(UsageWarning::IgnoreTKRUsage);
125 warnUsage_.set(UsageWarning::ExternalInterfaceMismatch);
126 warnUsage_.set(UsageWarning::DefinedOperatorArgs);
127 warnUsage_.set(UsageWarning::Final);
128 warnUsage_.set(UsageWarning::ZeroDoStep);
129 warnUsage_.set(UsageWarning::UnusedForallIndex);
130 warnUsage_.set(UsageWarning::OpenMPUsage);
131 warnUsage_.set(UsageWarning::DataLength);
132 warnUsage_.set(UsageWarning::IgnoredDirective);
133 warnUsage_.set(UsageWarning::HomonymousSpecific);
134 warnUsage_.set(UsageWarning::HomonymousResult);
135 warnUsage_.set(UsageWarning::IgnoredIntrinsicFunctionType);
136 warnUsage_.set(UsageWarning::PreviousScalarUse);
137 warnUsage_.set(UsageWarning::RedeclaredInaccessibleComponent);
138 warnUsage_.set(UsageWarning::ImplicitShared);
139 warnUsage_.set(UsageWarning::IndexVarRedefinition);
140 warnUsage_.set(UsageWarning::IncompatibleImplicitInterfaces);
141 warnUsage_.set(UsageWarning::VectorSubscriptFinalization);
142 warnUsage_.set(UsageWarning::UndefinedFunctionResult);
143 warnUsage_.set(UsageWarning::UselessIomsg);
144 warnUsage_.set(UsageWarning::UnsignedLiteralTruncation);
145 warnUsage_.set(UsageWarning::NullActualForDefaultIntentAllocatable);
146 warnUsage_.set(UsageWarning::UseAssociationIntoSameNameSubprogram);
147 warnUsage_.set(UsageWarning::HostAssociatedIntentOutInSpecExpr);
148 warnUsage_.set(UsageWarning::NonVolatilePointerToVolatile);
149 // New warnings, on by default
150 warnLanguage_.set(LanguageFeature::SavedLocalInSpecExpr);
151 warnLanguage_.set(LanguageFeature::NullActualForAllocatable);
152}
153
154// Take a string from the Cli and apply it to the LanguageFeatureControl.
155bool LanguageFeatureControl::ApplyCliOption(std::string input) {
156 bool negated{false};
157 if (input.size() > 3 && input.substr(0, 3) == "no-") {
158 negated = true;
159 input = input.substr(3);
160 }
161 if (auto it{cliOptions_.find(input)}; it != cliOptions_.end()) {
162 if (std::holds_alternative<LanguageFeature>(it->second)) {
163 EnableWarning(std::get<LanguageFeature>(it->second), !negated);
164 return true;
165 }
166 if (std::holds_alternative<UsageWarning>(it->second)) {
167 EnableWarning(std::get<UsageWarning>(it->second), !negated);
168 return true;
169 }
170 }
171 return false;
172}
173
174void LanguageFeatureControl::ReplaceCliCanonicalSpelling(
175 LanguageFeature f, std::string input) {
176 std::string_view &old{languageFeatureCliCanonicalSpelling_[EnumToInt(f)]};
177 cliOptions_.erase(std::string{old});
178 languageFeatureCliCanonicalSpelling_[EnumToInt(f)] = input;
179 cliOptions_.insert({input, {f}});
180}
181
182void LanguageFeatureControl::ReplaceCliCanonicalSpelling(
183 UsageWarning w, std::string input) {
184 std::string_view &old{usageWarningCliCanonicalSpelling_[EnumToInt(w)]};
185 cliOptions_.erase(std::string{old});
186 usageWarningCliCanonicalSpelling_[EnumToInt(w)] = input;
187 cliOptions_.insert({input, {w}});
188}
189
190std::vector<const char *> LanguageFeatureControl::GetNames(
191 LogicalOperator opr) const {
192 std::vector<const char *> result;
193 result.push_back(AsFortran(opr));
194 if (opr == LogicalOperator::Neqv && IsEnabled(LanguageFeature::XOROperator)) {
195 result.push_back(".xor.");
196 }
197 if (IsEnabled(LanguageFeature::LogicalAbbreviations)) {
198 switch (opr) {
199 SWITCH_COVERS_ALL_CASES
200 case LogicalOperator::And:
201 result.push_back(".a.");
202 break;
203 case LogicalOperator::Or:
204 result.push_back(".o.");
205 break;
206 case LogicalOperator::Not:
207 result.push_back(".n.");
208 break;
209 case LogicalOperator::Neqv:
210 if (IsEnabled(LanguageFeature::XOROperator)) {
211 result.push_back(".x.");
212 }
213 break;
214 case LogicalOperator::Eqv:
215 break;
216 }
217 }
218 return result;
219}
220
221std::vector<const char *> LanguageFeatureControl::GetNames(
222 RelationalOperator opr) const {
223 switch (opr) {
224 SWITCH_COVERS_ALL_CASES
225 case RelationalOperator::LT:
226 return {".lt.", "<"};
227 case RelationalOperator::LE:
228 return {".le.", "<="};
229 case RelationalOperator::EQ:
230 return {".eq.", "=="};
231 case RelationalOperator::GE:
232 return {".ge.", ">="};
233 case RelationalOperator::GT:
234 return {".gt.", ">"};
235 case RelationalOperator::NE:
236 if (IsEnabled(LanguageFeature::AlternativeNE)) {
237 return {".ne.", "/=", "<>"};
238 } else {
239 return {".ne.", "/="};
240 }
241 }
242}
243
244void LanguageFeatureControl::WarnOnAllNonstandard(bool yes) {
245 warnAllLanguage_ = yes;
246 warnLanguage_.reset();
247 if (yes) {
248 disableAllWarnings_ = false;
249 warnLanguage_.flip();
250 // These three features do not need to be warned about,
251 // but we do want their feature flags.
252 warnLanguage_.set(LanguageFeature::OpenMP, false);
253 warnLanguage_.set(LanguageFeature::OpenACC, false);
254 warnLanguage_.set(LanguageFeature::CUDA, false);
255 }
256}
257
258void LanguageFeatureControl::WarnOnAllUsage(bool yes) {
259 warnAllUsage_ = yes;
260 warnUsage_.reset();
261 if (yes) {
262 disableAllWarnings_ = false;
263 warnUsage_.flip();
264 }
265}
266} // namespace Fortran::common
267

source code of flang/lib/Support/Fortran-features.cpp