
Adds a hint to the warning message to disable a warning and updates the tests to expect this. Also fixes a bug in the storage of canonical spelling of error flags so that they are not used after free.
266 lines
10 KiB
C++
266 lines
10 KiB
C++
//===-- 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 <string>
|
|
#include <string_view>
|
|
|
|
namespace Fortran::common {
|
|
|
|
static std::vector<std::string_view> SplitCamelCase(std::string_view x) {
|
|
std::vector<std::string_view> 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<std::string_view> 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);
|
|
// 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);
|
|
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);
|
|
// New warnings, on by default
|
|
warnLanguage_.set(LanguageFeature::SavedLocalInSpecExpr);
|
|
warnLanguage_.set(LanguageFeature::NullActualForAllocatable);
|
|
}
|
|
|
|
std::optional<LanguageControlFlag> 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<const char *> LanguageFeatureControl::GetNames(
|
|
LogicalOperator opr) const {
|
|
std::vector<const char *> 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<const char *> 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
|