Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
47 changes: 42 additions & 5 deletions flang/include/flang/Common/enum-class.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@
#define FORTRAN_COMMON_ENUM_CLASS_H_

#include <array>
#include <string>

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

constexpr std::size_t CountEnumNames(const char *p) {
Expand Down Expand Up @@ -58,15 +59,51 @@ constexpr std::array<std::string_view, ITEMS> EnumNames(const char *p) {
return result;
}

template <typename F, typename T>
std::optional<T> inline fmap(std::optional<F> x, std::function<T(const F)> f) {
return x ? std::optional<T>{f(*x)} : std::nullopt;
}

using Predicate = std::function<bool(const std::string_view)>;
// Finds the first index for which the predicate returns true.
std::optional<int> FindEnumIndex(
Predicate pred, int size, const std::string_view *names);

using FindEnumIndexType = std::optional<int>(
Predicate, int, const std::string_view *);

template <typename NAME>
std::optional<NAME> inline FindEnum(
Predicate pred, std::function<std::optional<int>(Predicate)> find) {
std::function<NAME(int)> f = [](int x) { return static_cast<NAME>(x); };
return fmap(find(pred), f);
}

#define ENUM_CLASS(NAME, ...) \
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::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)]; \
}

#define ENUM_CLASS_EXTRA(NAME) \
[[maybe_unused]] inline std::optional<int> Find##NAME##Index( \
::Fortran::common::Predicate p) { \
return ::Fortran::common::FindEnumIndex( \
p, NAME##_enumSize, NAME##_names.data()); \
} \
[[maybe_unused]] inline std::optional<NAME> Find##NAME( \
::Fortran::common::Predicate p) { \
return ::Fortran::common::FindEnum<NAME>(p, Find##NAME##Index); \
} \
[[maybe_unused]] inline std::optional<NAME> StringTo##NAME( \
const std::string_view name) { \
return Find##NAME( \
[name](const std::string_view s) -> bool { return name == s; }); \
}
} // namespace Fortran::common
#endif // FORTRAN_COMMON_ENUM_CLASS_H_
51 changes: 36 additions & 15 deletions flang/include/flang/Support/Fortran-features.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

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

Expand Down Expand Up @@ -79,12 +79,13 @@ ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable,
NullActualForDefaultIntentAllocatable, UseAssociationIntoSameNameSubprogram,
HostAssociatedIntentOutInSpecExpr, NonVolatilePointerToVolatile)

// Generate default String -> Enum mapping.
ENUM_CLASS_EXTRA(LanguageFeature)
ENUM_CLASS_EXTRA(UsageWarning)

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 @@ -97,8 +98,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 @@ -107,16 +110,16 @@ class LanguageFeatureControl {
warnAllUsage_ = false;
warnUsage_.clear();
}

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(UsageWarning w) const {
return warnAllUsage_ || warnUsage_.test(w);
void DisableAllWarnings() {
disableAllWarnings_ = true;
DisableAllNonstandardWarnings();
DisableAllUsageWarnings();
}
bool applyCLIOption(llvm::StringRef input);
bool AreWarningsDisabled() const { return disableAllWarnings_; }
bool IsEnabled(LanguageFeature f) const { return !disable_.test(f); }
bool ShouldWarn(LanguageFeature f) const { return warnLanguage_.test(f); }
bool ShouldWarn(UsageWarning w) const { return warnUsage_.test(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;
Expand All @@ -127,6 +130,24 @@ class LanguageFeatureControl {
bool warnAllLanguage_{false};
UsageWarnings warnUsage_;
bool warnAllUsage_{false};
bool disableAllWarnings_{false};
};

// Parse a CLI enum option return the enum index and whether it should be
// enabled (true) or disabled (false). Just exposed for the template below.
std::optional<std::pair<bool, int>> parseCLIEnumIndex(
llvm::StringRef input, std::function<std::optional<int>(Predicate)> find);

template <typename ENUM>
std::optional<std::pair<bool, ENUM>> parseCLIEnum(
llvm::StringRef input, std::function<std::optional<int>(Predicate)> find) {
using To = std::pair<bool, ENUM>;
using From = std::pair<bool, int>;
static std::function<To(From)> cast = [](From x) {
return std::pair{x.first, static_cast<ENUM>(x.second)};
};
return fmap(parseCLIEnumIndex(input, find), cast);
}

} // namespace Fortran::common
#endif // FORTRAN_SUPPORT_FORTRAN_FEATURES_H_
63 changes: 31 additions & 32 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 @@ -971,10 +968,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 @@ -984,21 +994,27 @@ 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;
}
}
}

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

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

// Honor color diagnostics.
res.getDiagnosticOpts().ShowColors = res.getFrontendOpts().showColors;
diags.getDiagnosticOptions().ShowColors = showColors;
res.getDiagnosticOpts().ShowColors = showColors;
res.getFrontendOpts().showColors = showColors;

return diags.getNumErrors() == numErrorsBefore;
}
Expand Down Expand Up @@ -1074,16 +1090,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 @@ -1092,13 +1098,15 @@ 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,
"Only -std=f2018 is allowed currently.");
diags.Report(diagID);
}
}

return diags.getNumErrors() == numErrorsBefore;
}

Expand Down Expand Up @@ -1694,16 +1702,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
1 change: 1 addition & 0 deletions flang/lib/Support/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ endif()

add_flang_library(FortranSupport
default-kinds.cpp
enum-class.cpp
Flags.cpp
Fortran.cpp
Fortran-features.cpp
Expand Down
Loading
Loading