Skip to content

[flang][cli] Add diagnostic flags to the CLI #142022

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions flang/include/flang/Common/enum-class.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
#define FORTRAN_COMMON_ENUM_CLASS_H_

#include <array>
#include <string>

#include <functional>
#include <string_view>
namespace Fortran::common {

constexpr std::size_t CountEnumNames(const char *p) {
Expand Down Expand Up @@ -62,11 +62,19 @@ constexpr std::array<std::string_view, ITEMS> EnumNames(const char *p) {
enum class NAME { __VA_ARGS__ }; \
[[maybe_unused]] static constexpr std::size_t NAME##_enumSize{ \
::Fortran::common::CountEnumNames(#__VA_ARGS__)}; \
[[maybe_unused]] static constexpr std::array<std::string_view, \
NAME##_enumSize> NAME##_names{ \
::Fortran::common::EnumNames<NAME##_enumSize>(#__VA_ARGS__)}; \
[[maybe_unused]] static inline std::size_t EnumToInt(NAME e) { \
return static_cast<std::size_t>(e); \
} \
[[maybe_unused]] static inline std::string_view EnumToString(NAME e) { \
static const constexpr auto names{ \
::Fortran::common::EnumNames<NAME##_enumSize>(#__VA_ARGS__)}; \
return names[static_cast<std::size_t>(e)]; \
return NAME##_names[static_cast<std::size_t>(e)]; \
} \
[[maybe_unused]] inline void ForEach##NAME(std::function<void(NAME)> f) { \
for (std::size_t i{0}; i < NAME##_enumSize; ++i) { \
f(static_cast<NAME>(i)); \
} \
}

} // namespace Fortran::common
#endif // FORTRAN_COMMON_ENUM_CLASS_H_
1 change: 0 additions & 1 deletion flang/include/flang/Common/optional.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@

#include "api-attrs.h"
#include <optional>
#include <type_traits>

#if !defined(STD_OPTIONAL_UNSUPPORTED) && \
(defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__)
Expand Down
51 changes: 37 additions & 14 deletions flang/include/flang/Support/Fortran-features.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@

#include "Fortran.h"
#include "flang/Common/enum-set.h"
#include "flang/Common/idioms.h"
#include <optional>
#include <string_view>
#include <vector>

namespace Fortran::common {
Expand Down Expand Up @@ -83,9 +82,6 @@ ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable,
using LanguageFeatures = EnumSet<LanguageFeature, LanguageFeature_enumSize>;
using UsageWarnings = EnumSet<UsageWarning, UsageWarning_enumSize>;

std::optional<LanguageFeature> FindLanguageFeature(const char *);
std::optional<UsageWarning> FindUsageWarning(const char *);

class LanguageFeatureControl {
public:
LanguageFeatureControl();
Expand All @@ -98,8 +94,10 @@ class LanguageFeatureControl {
void EnableWarning(UsageWarning w, bool yes = true) {
warnUsage_.set(w, yes);
}
void WarnOnAllNonstandard(bool yes = true) { warnAllLanguage_ = yes; }
void WarnOnAllUsage(bool yes = true) { warnAllUsage_ = yes; }
void WarnOnAllNonstandard(bool yes = true);
bool IsWarnOnAllNonstandard() const { return warnAllLanguage_; }
void WarnOnAllUsage(bool yes = true);
bool IsWarnOnAllUsage() const { return warnAllUsage_; }
void DisableAllNonstandardWarnings() {
warnAllLanguage_ = false;
warnLanguage_.clear();
Expand All @@ -108,26 +106,51 @@ class LanguageFeatureControl {
warnAllUsage_ = false;
warnUsage_.clear();
}

void DisableAllWarnings() {
disableAllWarnings_ = true;
DisableAllNonstandardWarnings();
DisableAllUsageWarnings();
}
bool AreWarningsDisabled() const { return disableAllWarnings_; }
bool IsEnabled(LanguageFeature f) const { return !disable_.test(f); }
bool ShouldWarn(LanguageFeature f) const {
return (warnAllLanguage_ && f != LanguageFeature::OpenMP &&
f != LanguageFeature::OpenACC && f != LanguageFeature::CUDA) ||
warnLanguage_.test(f);
bool ShouldWarn(LanguageFeature f) const { return warnLanguage_.test(f); }
bool ShouldWarn(UsageWarning w) const { return warnUsage_.test(w); }
// Cli options
bool ApplyCliOption(std::string input);
void AddAlternativeCliSpelling(LanguageFeature f, std::string input) {
cliOptions_.insert({input, {f}});
}
bool ShouldWarn(UsageWarning w) const {
return warnAllUsage_ || warnUsage_.test(w);
void AddAlternativeCliSpelling(UsageWarning w, std::string input) {
cliOptions_.insert({input, {w}});
}
void ReplaceCliCanonicalSpelling(LanguageFeature f, std::string input);
void ReplaceCliCanonicalSpelling(UsageWarning w, std::string input);
std::string_view getDefaultCliSpelling(LanguageFeature f) const {
return languageFeatureCliCanonicalSpelling_[EnumToInt(f)];
};
std::string_view getDefaultCliSpelling(UsageWarning w) const {
return usageWarningCliCanonicalSpelling_[EnumToInt(w)];
};
// Return all spellings of operators names, depending on features enabled
std::vector<const char *> GetNames(LogicalOperator) const;
std::vector<const char *> GetNames(RelationalOperator) const;

private:
// Map from Cli syntax of language features and usage warnings to their enum
// values.
std::unordered_map<std::string, std::variant<LanguageFeature, UsageWarning>>
cliOptions_;
// These two arrays map the enum values to their cannonical Cli spellings.
std::array<std::string_view, LanguageFeature_enumSize>
languageFeatureCliCanonicalSpelling_;
std::array<std::string_view, UsageWarning_enumSize>
usageWarningCliCanonicalSpelling_;
LanguageFeatures disable_;
LanguageFeatures warnLanguage_;
bool warnAllLanguage_{false};
UsageWarnings warnUsage_;
bool warnAllUsage_{false};
bool disableAllWarnings_{false};
};
} // namespace Fortran::common
#endif // FORTRAN_SUPPORT_FORTRAN_FEATURES_H_
64 changes: 30 additions & 34 deletions flang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,9 @@
#include "flang/Support/Version.h"
#include "flang/Tools/TargetSetup.h"
#include "flang/Version.inc"
#include "clang/Basic/AllDiagnostics.h"
#include "clang/Basic/DiagnosticDriver.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/OptionUtils.h"
#include "clang/Driver/Options.h"
#include "llvm/ADT/StringRef.h"
Expand All @@ -35,7 +33,6 @@
#include "llvm/Option/OptTable.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/raw_ostream.h"
Expand Down Expand Up @@ -985,10 +982,23 @@ static bool parseSemaArgs(CompilerInvocation &res, llvm::opt::ArgList &args,

/// Parses all diagnostics related arguments and populates the variables
/// options accordingly. Returns false if new errors are generated.
/// FC1 driver entry point for parsing diagnostic arguments.
static bool parseDiagArgs(CompilerInvocation &res, llvm::opt::ArgList &args,
clang::DiagnosticsEngine &diags) {
unsigned numErrorsBefore = diags.getNumErrors();

auto &features{res.getFrontendOpts().features};
// The order of these flags (-pedantic -W<feature> -w) is important and is
// chosen to match clang's behavior.

// -pedantic
if (args.hasArg(clang::driver::options::OPT_pedantic)) {
features.WarnOnAllNonstandard();
features.WarnOnAllUsage();
res.setEnableConformanceChecks();
res.setEnableUsageChecks();
}

// -Werror option
// TODO: Currently throws a Diagnostic for anything other than -W<error>,
// this has to change when other -W<opt>'s are supported.
Expand All @@ -998,22 +1008,26 @@ static bool parseDiagArgs(CompilerInvocation &res, llvm::opt::ArgList &args,
for (const auto &wArg : wArgs) {
if (wArg == "error") {
res.setWarnAsErr(true);
} else {
const unsigned diagID =
diags.getCustomDiagID(clang::DiagnosticsEngine::Error,
"Only `-Werror` is supported currently.");
diags.Report(diagID);
// -W(no-)<feature>
} else if (!features.ApplyCliOption(wArg)) {
const unsigned diagID = diags.getCustomDiagID(
clang::DiagnosticsEngine::Error, "Unknown diagnostic option: -W%0");
diags.Report(diagID) << wArg;
}
}
}

// Default to off for `flang -fc1`.
res.getFrontendOpts().showColors =
parseShowColorsArgs(args, /*defaultDiagColor=*/false);

// Honor color diagnostics.
res.getDiagnosticOpts().ShowColors = res.getFrontendOpts().showColors;
// -w
if (args.hasArg(clang::driver::options::OPT_w)) {
features.DisableAllWarnings();
res.setDisableWarnings();
}

// Default to off for `flang -fc1`.
bool showColors{parseShowColorsArgs(args, false)};
diags.getDiagnosticOptions().ShowColors = showColors;
res.getDiagnosticOpts().ShowColors = showColors;
res.getFrontendOpts().showColors = showColors;
return diags.getNumErrors() == numErrorsBefore;
}

Expand Down Expand Up @@ -1088,16 +1102,6 @@ static bool parseDialectArgs(CompilerInvocation &res, llvm::opt::ArgList &args,
Fortran::common::LanguageFeature::OpenACC);
}

// -pedantic
if (args.hasArg(clang::driver::options::OPT_pedantic)) {
res.setEnableConformanceChecks();
res.setEnableUsageChecks();
}

// -w
if (args.hasArg(clang::driver::options::OPT_w))
res.setDisableWarnings();

// -std=f2018
// TODO: Set proper options when more fortran standards
// are supported.
Expand All @@ -1106,6 +1110,7 @@ static bool parseDialectArgs(CompilerInvocation &res, llvm::opt::ArgList &args,
// We only allow f2018 as the given standard
if (standard == "f2018") {
res.setEnableConformanceChecks();
res.getFrontendOpts().features.WarnOnAllNonstandard();
} else {
const unsigned diagID =
diags.getCustomDiagID(clang::DiagnosticsEngine::Error,
Expand Down Expand Up @@ -1712,16 +1717,7 @@ void CompilerInvocation::setFortranOpts() {
if (frontendOptions.needProvenanceRangeToCharBlockMappings)
fortranOptions.needProvenanceRangeToCharBlockMappings = true;

if (getEnableConformanceChecks())
fortranOptions.features.WarnOnAllNonstandard();

if (getEnableUsageChecks())
fortranOptions.features.WarnOnAllUsage();

if (getDisableWarnings()) {
fortranOptions.features.DisableAllNonstandardWarnings();
fortranOptions.features.DisableAllUsageWarnings();
}
fortranOptions.features = frontendOptions.features;
}

std::unique_ptr<Fortran::semantics::SemanticsContext>
Expand Down
Loading