//===-- lib/Support/Fortran-features.cpp ------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "flang/Support/Fortran-features.h" #include "flang/Common/idioms.h" #include "flang/Parser/characters.h" #include "flang/Support/Fortran.h" #include #include namespace Fortran::common { static std::vector SplitCamelCase(std::string_view x) { std::vector result; // NB, we start at 1 because the first character is never a word boundary. size_t xSize{x.size()}, wordStart{0}, wordEnd{1}; for (; wordEnd < xSize; ++wordEnd) { // Identify when wordEnd is at the start of a new word. if ((!parser::IsUpperCaseLetter(x[wordEnd - 1]) && parser::IsUpperCaseLetter(x[wordEnd])) || // ACCUsage => ACC-Usage, CComment => C-Comment, etc. (parser::IsUpperCaseLetter(x[wordEnd]) && wordEnd + 1 < xSize && parser::IsLowerCaseLetter(x[wordEnd + 1]))) { result.push_back(x.substr(wordStart, wordEnd - wordStart)); wordStart = wordEnd; } } // We went one past the end of the last word. result.push_back(x.substr(wordStart, wordEnd - wordStart)); return result; } // Namespace for helper functions for parsing Cli options used instead of static // so that there can be unit tests for this function. namespace details { std::string CamelCaseToLowerCaseHyphenated(std::string_view x) { std::vector words{SplitCamelCase(x)}; std::string result{}; result.reserve(x.size() + words.size() + 1); for (size_t i{0}; i < words.size(); ++i) { std::string word{parser::ToLowerCaseLetters(words[i])}; result += i == 0 ? "" : "-"; result += word; } return result; } } // namespace details LanguageFeatureControl::LanguageFeatureControl() { // Initialize the bidirectional maps with the default spellings. cliOptions_.reserve(LanguageFeature_enumSize + UsageWarning_enumSize); ForEachLanguageFeature([&](auto feature) { std::string_view name{Fortran::common::EnumToString(feature)}; std::string cliOption{details::CamelCaseToLowerCaseHyphenated(name)}; cliOptions_.insert({cliOption, {feature}}); languageFeatureCliCanonicalSpelling_[EnumToInt(feature)] = std::move(cliOption); }); ForEachUsageWarning([&](auto warning) { std::string_view name{Fortran::common::EnumToString(warning)}; std::string cliOption{details::CamelCaseToLowerCaseHyphenated(name)}; cliOptions_.insert({cliOption, {warning}}); usageWarningCliCanonicalSpelling_[EnumToInt(warning)] = std::move(cliOption); }); // These features must be explicitly enabled by command line options. disable_.set(LanguageFeature::OldDebugLines); disable_.set(LanguageFeature::OpenACC); disable_.set(LanguageFeature::OpenMP); disable_.set(LanguageFeature::CUDA); // !@cuf disable_.set(LanguageFeature::CudaManaged); disable_.set(LanguageFeature::CudaUnified); disable_.set(LanguageFeature::ImplicitNoneTypeNever); disable_.set(LanguageFeature::ImplicitNoneTypeAlways); disable_.set(LanguageFeature::ImplicitNoneExternal); disable_.set(LanguageFeature::DefaultSave); disable_.set(LanguageFeature::SaveMainProgram); // These features, if enabled, conflict with valid standard usage, // so there are disabled here by default. disable_.set(LanguageFeature::BackslashEscapes); disable_.set(LanguageFeature::LogicalAbbreviations); disable_.set(LanguageFeature::XOROperator); disable_.set(LanguageFeature::OldStyleParameter); // Possibly an accidental "feature" of nvfortran. disable_.set(LanguageFeature::AssumedRankPassedToNonAssumedRank); disable_.set(LanguageFeature::Coarray); // These warnings are enabled by default, but only because they used // to be unconditional. TODO: prune this list warnLanguage_.set(LanguageFeature::ExponentMatchingKindParam); warnLanguage_.set(LanguageFeature::RedundantAttribute); warnLanguage_.set(LanguageFeature::SubroutineAndFunctionSpecifics); warnLanguage_.set(LanguageFeature::EmptySequenceType); warnLanguage_.set(LanguageFeature::NonSequenceCrayPointee); warnLanguage_.set(LanguageFeature::BranchIntoConstruct); warnLanguage_.set(LanguageFeature::BadBranchTarget); warnLanguage_.set(LanguageFeature::HollerithPolymorphic); warnLanguage_.set(LanguageFeature::ListDirectedSize); warnLanguage_.set(LanguageFeature::IgnoreIrrelevantAttributes); warnLanguage_.set(LanguageFeature::AmbiguousStructureConstructor); warnLanguage_.set(LanguageFeature::TransferBOZ); warnUsage_.set(UsageWarning::ShortArrayActual); warnUsage_.set(UsageWarning::FoldingException); warnUsage_.set(UsageWarning::FoldingAvoidsRuntimeCrash); warnUsage_.set(UsageWarning::FoldingValueChecks); warnUsage_.set(UsageWarning::FoldingFailure); warnUsage_.set(UsageWarning::FoldingLimit); warnUsage_.set(UsageWarning::Interoperability); // CharacterInteroperability warnings about length are off by default warnUsage_.set(UsageWarning::Bounds); warnUsage_.set(UsageWarning::Preprocessing); warnUsage_.set(UsageWarning::Scanning); warnUsage_.set(UsageWarning::OpenAccUsage); warnUsage_.set(UsageWarning::ProcPointerCompatibility); warnUsage_.set(UsageWarning::VoidMold); warnUsage_.set(UsageWarning::KnownBadImplicitInterface); warnUsage_.set(UsageWarning::EmptyCase); warnUsage_.set(UsageWarning::CaseOverflow); warnUsage_.set(UsageWarning::CUDAUsage); warnUsage_.set(UsageWarning::IgnoreTKRUsage); warnUsage_.set(UsageWarning::ExternalInterfaceMismatch); warnUsage_.set(UsageWarning::DefinedOperatorArgs); warnUsage_.set(UsageWarning::Final); warnUsage_.set(UsageWarning::ZeroDoStep); warnUsage_.set(UsageWarning::UnusedForallIndex); warnUsage_.set(UsageWarning::OpenMPUsage); warnUsage_.set(UsageWarning::DataLength); warnUsage_.set(UsageWarning::IgnoredDirective); warnUsage_.set(UsageWarning::HomonymousSpecific); warnUsage_.set(UsageWarning::HomonymousResult); warnUsage_.set(UsageWarning::IgnoredIntrinsicFunctionType); warnUsage_.set(UsageWarning::PreviousScalarUse); warnUsage_.set(UsageWarning::RedeclaredInaccessibleComponent); warnUsage_.set(UsageWarning::ImplicitShared); warnUsage_.set(UsageWarning::IndexVarRedefinition); warnUsage_.set(UsageWarning::IncompatibleImplicitInterfaces); warnUsage_.set(UsageWarning::VectorSubscriptFinalization); warnUsage_.set(UsageWarning::UndefinedFunctionResult); warnUsage_.set(UsageWarning::UselessIomsg); warnUsage_.set(UsageWarning::UnsignedLiteralTruncation); warnUsage_.set(UsageWarning::NullActualForDefaultIntentAllocatable); warnUsage_.set(UsageWarning::UseAssociationIntoSameNameSubprogram); warnUsage_.set(UsageWarning::HostAssociatedIntentOutInSpecExpr); warnUsage_.set(UsageWarning::NonVolatilePointerToVolatile); warnUsage_.set(UsageWarning::RealConstantWidening); // New warnings, on by default warnLanguage_.set(LanguageFeature::SavedLocalInSpecExpr); warnLanguage_.set(LanguageFeature::NullActualForAllocatable); } std::optional LanguageFeatureControl::FindWarning( std::string_view input) { bool negated{false}; if (input.size() > 3 && input.substr(0, 3) == "no-") { negated = true; input = input.substr(3); } if (auto it{cliOptions_.find(std::string{input})}; it != cliOptions_.end()) { return std::make_pair(it->second, !negated); } return std::nullopt; } bool LanguageFeatureControl::EnableWarning(std::string_view input) { if (auto warningAndEnabled{FindWarning(input)}) { EnableWarning(warningAndEnabled->first, warningAndEnabled->second); return true; } return false; } void LanguageFeatureControl::ReplaceCliCanonicalSpelling( LanguageFeature f, std::string input) { cliOptions_.erase(languageFeatureCliCanonicalSpelling_[EnumToInt(f)]); cliOptions_.insert({input, {f}}); languageFeatureCliCanonicalSpelling_[EnumToInt(f)] = std::move(input); } void LanguageFeatureControl::ReplaceCliCanonicalSpelling( UsageWarning w, std::string input) { cliOptions_.erase(usageWarningCliCanonicalSpelling_[EnumToInt(w)]); cliOptions_.insert({input, {w}}); usageWarningCliCanonicalSpelling_[EnumToInt(w)] = std::move(input); } std::vector LanguageFeatureControl::GetNames( LogicalOperator opr) const { std::vector result; result.push_back(AsFortran(opr)); if (opr == LogicalOperator::Neqv && IsEnabled(LanguageFeature::XOROperator)) { result.push_back(".xor."); } if (IsEnabled(LanguageFeature::LogicalAbbreviations)) { switch (opr) { SWITCH_COVERS_ALL_CASES case LogicalOperator::And: result.push_back(".a."); break; case LogicalOperator::Or: result.push_back(".o."); break; case LogicalOperator::Not: result.push_back(".n."); break; case LogicalOperator::Neqv: if (IsEnabled(LanguageFeature::XOROperator)) { result.push_back(".x."); } break; case LogicalOperator::Eqv: break; } } return result; } std::vector LanguageFeatureControl::GetNames( RelationalOperator opr) const { switch (opr) { SWITCH_COVERS_ALL_CASES case RelationalOperator::LT: return {".lt.", "<"}; case RelationalOperator::LE: return {".le.", "<="}; case RelationalOperator::EQ: return {".eq.", "=="}; case RelationalOperator::GE: return {".ge.", ">="}; case RelationalOperator::GT: return {".gt.", ">"}; case RelationalOperator::NE: if (IsEnabled(LanguageFeature::AlternativeNE)) { return {".ne.", "/=", "<>"}; } else { return {".ne.", "/="}; } } } void LanguageFeatureControl::WarnOnAllNonstandard(bool yes) { warnAllLanguage_ = yes; warnLanguage_.reset(); if (yes) { disableAllWarnings_ = false; warnLanguage_.flip(); // These three features do not need to be warned about, // but we do want their feature flags. warnLanguage_.set(LanguageFeature::OpenMP, false); warnLanguage_.set(LanguageFeature::OpenACC, false); warnLanguage_.set(LanguageFeature::CUDA, false); } } void LanguageFeatureControl::WarnOnAllUsage(bool yes) { warnAllUsage_ = yes; warnUsage_.reset(); if (yes) { disableAllWarnings_ = false; warnUsage_.flip(); } } } // namespace Fortran::common