269 lines · cpp
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-exception6//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 static39// 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 details53 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::move(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::move(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); // !@cuf78 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 disable_.set(LanguageFeature::Coarray);94 // These warnings are enabled by default, but only because they used95 // to be unconditional. TODO: prune this list96 warnLanguage_.set(LanguageFeature::ExponentMatchingKindParam);97 warnLanguage_.set(LanguageFeature::RedundantAttribute);98 warnLanguage_.set(LanguageFeature::SubroutineAndFunctionSpecifics);99 warnLanguage_.set(LanguageFeature::EmptySequenceType);100 warnLanguage_.set(LanguageFeature::NonSequenceCrayPointee);101 warnLanguage_.set(LanguageFeature::BranchIntoConstruct);102 warnLanguage_.set(LanguageFeature::BadBranchTarget);103 warnLanguage_.set(LanguageFeature::HollerithPolymorphic);104 warnLanguage_.set(LanguageFeature::ListDirectedSize);105 warnLanguage_.set(LanguageFeature::IgnoreIrrelevantAttributes);106 warnLanguage_.set(LanguageFeature::AmbiguousStructureConstructor);107 warnLanguage_.set(LanguageFeature::TransferBOZ);108 warnUsage_.set(UsageWarning::ShortArrayActual);109 warnUsage_.set(UsageWarning::FoldingException);110 warnUsage_.set(UsageWarning::FoldingAvoidsRuntimeCrash);111 warnUsage_.set(UsageWarning::FoldingValueChecks);112 warnUsage_.set(UsageWarning::FoldingFailure);113 warnUsage_.set(UsageWarning::FoldingLimit);114 warnUsage_.set(UsageWarning::Interoperability);115 // CharacterInteroperability warnings about length are off by default116 warnUsage_.set(UsageWarning::Bounds);117 warnUsage_.set(UsageWarning::Preprocessing);118 warnUsage_.set(UsageWarning::Scanning);119 warnUsage_.set(UsageWarning::OpenAccUsage);120 warnUsage_.set(UsageWarning::ProcPointerCompatibility);121 warnUsage_.set(UsageWarning::VoidMold);122 warnUsage_.set(UsageWarning::KnownBadImplicitInterface);123 warnUsage_.set(UsageWarning::EmptyCase);124 warnUsage_.set(UsageWarning::CaseOverflow);125 warnUsage_.set(UsageWarning::CUDAUsage);126 warnUsage_.set(UsageWarning::IgnoreTKRUsage);127 warnUsage_.set(UsageWarning::ExternalInterfaceMismatch);128 warnUsage_.set(UsageWarning::DefinedOperatorArgs);129 warnUsage_.set(UsageWarning::Final);130 warnUsage_.set(UsageWarning::ZeroDoStep);131 warnUsage_.set(UsageWarning::UnusedForallIndex);132 warnUsage_.set(UsageWarning::OpenMPUsage);133 warnUsage_.set(UsageWarning::DataLength);134 warnUsage_.set(UsageWarning::IgnoredDirective);135 warnUsage_.set(UsageWarning::HomonymousSpecific);136 warnUsage_.set(UsageWarning::HomonymousResult);137 warnUsage_.set(UsageWarning::IgnoredIntrinsicFunctionType);138 warnUsage_.set(UsageWarning::PreviousScalarUse);139 warnUsage_.set(UsageWarning::RedeclaredInaccessibleComponent);140 warnUsage_.set(UsageWarning::ImplicitShared);141 warnUsage_.set(UsageWarning::IndexVarRedefinition);142 warnUsage_.set(UsageWarning::IncompatibleImplicitInterfaces);143 warnUsage_.set(UsageWarning::VectorSubscriptFinalization);144 warnUsage_.set(UsageWarning::UndefinedFunctionResult);145 warnUsage_.set(UsageWarning::UselessIomsg);146 warnUsage_.set(UsageWarning::UnsignedLiteralTruncation);147 warnUsage_.set(UsageWarning::NullActualForDefaultIntentAllocatable);148 warnUsage_.set(UsageWarning::UseAssociationIntoSameNameSubprogram);149 warnUsage_.set(UsageWarning::HostAssociatedIntentOutInSpecExpr);150 warnUsage_.set(UsageWarning::NonVolatilePointerToVolatile);151 warnUsage_.set(UsageWarning::RealConstantWidening);152 // New warnings, on by default153 warnLanguage_.set(LanguageFeature::SavedLocalInSpecExpr);154 warnLanguage_.set(LanguageFeature::NullActualForAllocatable);155}156 157std::optional<LanguageControlFlag> LanguageFeatureControl::FindWarning(158 std::string_view input) {159 bool negated{false};160 if (input.size() > 3 && input.substr(0, 3) == "no-") {161 negated = true;162 input = input.substr(3);163 }164 if (auto it{cliOptions_.find(std::string{input})}; it != cliOptions_.end()) {165 return std::make_pair(it->second, !negated);166 }167 return std::nullopt;168}169 170bool LanguageFeatureControl::EnableWarning(std::string_view input) {171 if (auto warningAndEnabled{FindWarning(input)}) {172 EnableWarning(warningAndEnabled->first, warningAndEnabled->second);173 return true;174 }175 return false;176}177 178void LanguageFeatureControl::ReplaceCliCanonicalSpelling(179 LanguageFeature f, std::string input) {180 cliOptions_.erase(languageFeatureCliCanonicalSpelling_[EnumToInt(f)]);181 cliOptions_.insert({input, {f}});182 languageFeatureCliCanonicalSpelling_[EnumToInt(f)] = std::move(input);183}184 185void LanguageFeatureControl::ReplaceCliCanonicalSpelling(186 UsageWarning w, std::string input) {187 cliOptions_.erase(usageWarningCliCanonicalSpelling_[EnumToInt(w)]);188 cliOptions_.insert({input, {w}});189 usageWarningCliCanonicalSpelling_[EnumToInt(w)] = std::move(input);190}191 192std::vector<const char *> LanguageFeatureControl::GetNames(193 LogicalOperator opr) const {194 std::vector<const char *> result;195 result.push_back(AsFortran(opr));196 if (opr == LogicalOperator::Neqv && IsEnabled(LanguageFeature::XOROperator)) {197 result.push_back(".xor.");198 }199 if (IsEnabled(LanguageFeature::LogicalAbbreviations)) {200 switch (opr) {201 SWITCH_COVERS_ALL_CASES202 case LogicalOperator::And:203 result.push_back(".a.");204 break;205 case LogicalOperator::Or:206 result.push_back(".o.");207 break;208 case LogicalOperator::Not:209 result.push_back(".n.");210 break;211 case LogicalOperator::Neqv:212 if (IsEnabled(LanguageFeature::XOROperator)) {213 result.push_back(".x.");214 }215 break;216 case LogicalOperator::Eqv:217 break;218 }219 }220 return result;221}222 223std::vector<const char *> LanguageFeatureControl::GetNames(224 RelationalOperator opr) const {225 switch (opr) {226 SWITCH_COVERS_ALL_CASES227 case RelationalOperator::LT:228 return {".lt.", "<"};229 case RelationalOperator::LE:230 return {".le.", "<="};231 case RelationalOperator::EQ:232 return {".eq.", "=="};233 case RelationalOperator::GE:234 return {".ge.", ">="};235 case RelationalOperator::GT:236 return {".gt.", ">"};237 case RelationalOperator::NE:238 if (IsEnabled(LanguageFeature::AlternativeNE)) {239 return {".ne.", "/=", "<>"};240 } else {241 return {".ne.", "/="};242 }243 }244}245 246void LanguageFeatureControl::WarnOnAllNonstandard(bool yes) {247 warnAllLanguage_ = yes;248 warnLanguage_.reset();249 if (yes) {250 disableAllWarnings_ = false;251 warnLanguage_.flip();252 // These three features do not need to be warned about,253 // but we do want their feature flags.254 warnLanguage_.set(LanguageFeature::OpenMP, false);255 warnLanguage_.set(LanguageFeature::OpenACC, false);256 warnLanguage_.set(LanguageFeature::CUDA, false);257 }258}259 260void LanguageFeatureControl::WarnOnAllUsage(bool yes) {261 warnAllUsage_ = yes;262 warnUsage_.reset();263 if (yes) {264 disableAllWarnings_ = false;265 warnUsage_.flip();266 }267}268} // namespace Fortran::common269