https://github.com/JDPailleux updated https://github.com/llvm/llvm-project/pull/127214
>From 46f8e51564b14cba778893f999b3b496931d52f0 Mon Sep 17 00:00:00 2001 From: Jean-Didier Pailleux <jean-didier.paill...@sipearl.com> Date: Thu, 6 Mar 2025 16:32:52 +0100 Subject: [PATCH] [flang] Add options -W[no-]unused-dummy-argument and -W[no-]unused-variable Addition of two new warning options and a diagnostic system for Flang based on the Clang's diagnostics. --- clang/include/clang/Basic/Diagnostic.td | 5 +- .../clang/Basic/DiagnosticCategories.h | 3 +- clang/include/clang/Basic/DiagnosticGroups.td | 5 +- clang/include/clang/Basic/DiagnosticIDs.h | 5 + .../clang/Basic/DiagnosticSemaKinds.td | 6 ++ clang/lib/Basic/DiagnosticIDs.cpp | 14 ++- clang/lib/Basic/Warnings.cpp | 9 ++ clang/tools/diagtool/DiagnosticNames.cpp | 3 +- .../TableGen/ClangDiagnosticsEmitter.cpp | 4 + .../flang/Frontend/CompilerInvocation.h | 10 +- flang/include/flang/Semantics/semantics.h | 5 +- flang/include/flang/Semantics/symbol.h | 3 + flang/lib/Frontend/CMakeLists.txt | 1 + flang/lib/Frontend/CompilerInstance.cpp | 3 +- flang/lib/Frontend/CompilerInvocation.cpp | 50 +++++---- flang/lib/Frontend/Warnings.cpp | 102 ++++++++++++++++++ flang/lib/Semantics/CMakeLists.txt | 4 + flang/lib/Semantics/check-warning.cpp | 89 +++++++++++++++ flang/lib/Semantics/check-warning.h | 36 +++++++ flang/lib/Semantics/expression.cpp | 7 ++ flang/lib/Semantics/resolve-names.cpp | 5 + flang/lib/Semantics/semantics.cpp | 7 +- flang/test/Driver/w-arg-unknown.f90 | 7 ++ flang/test/Driver/werror-wrong.f90 | 6 -- flang/test/Driver/wextra-ok.f90 | 4 +- .../test/Semantics/wunused-dummy-argument.f90 | 54 ++++++++++ flang/test/Semantics/wunused-variable.f90 | 72 +++++++++++++ flang/tools/bbc/CMakeLists.txt | 5 + flang/tools/bbc/bbc.cpp | 14 ++- flang/tools/flang-driver/driver.cpp | 10 +- flang/tools/flang-driver/fc1_main.cpp | 19 ++-- 31 files changed, 515 insertions(+), 52 deletions(-) create mode 100644 flang/lib/Frontend/Warnings.cpp create mode 100644 flang/lib/Semantics/check-warning.cpp create mode 100644 flang/lib/Semantics/check-warning.h create mode 100644 flang/test/Driver/w-arg-unknown.f90 delete mode 100644 flang/test/Driver/werror-wrong.f90 create mode 100644 flang/test/Semantics/wunused-dummy-argument.f90 create mode 100644 flang/test/Semantics/wunused-variable.f90 diff --git a/clang/include/clang/Basic/Diagnostic.td b/clang/include/clang/Basic/Diagnostic.td index 0b8b3af939ba0..b3a2e76ddc453 100644 --- a/clang/include/clang/Basic/Diagnostic.td +++ b/clang/include/clang/Basic/Diagnostic.td @@ -55,11 +55,14 @@ class DiagCategory<string Name> { } // Diagnostic Groups. -class DiagGroup<string Name, list<DiagGroup> subgroups = [], code docs = [{}]> { +class DiagGroup<string Name, list<DiagGroup> subgroups = [], code docs = [{}], + bit clangDiag = 1, bit flangDiag = 0> { string GroupName = Name; list<DiagGroup> SubGroups = subgroups; string CategoryName = ""; code Documentation = docs; + bit IsClangDiag = clangDiag; + bit IsFlangDiag = flangDiag; } class InGroup<DiagGroup G> { DiagGroup Group = G; } //class IsGroup<string Name> { DiagGroup Group = DiagGroup<Name>; } diff --git a/clang/include/clang/Basic/DiagnosticCategories.h b/clang/include/clang/Basic/DiagnosticCategories.h index 839f8dee3ca89..5e44889a2fcd8 100644 --- a/clang/include/clang/Basic/DiagnosticCategories.h +++ b/clang/include/clang/Basic/DiagnosticCategories.h @@ -21,7 +21,8 @@ namespace clang { }; enum class Group { -#define DIAG_ENTRY(GroupName, FlagNameOffset, Members, SubGroups, Docs) \ +#define DIAG_ENTRY(GroupName, FlagNameOffset, Members, SubGroups, Docs, \ + IsClang, IsFlang) \ GroupName, #include "clang/Basic/DiagnosticGroups.inc" #undef CATEGORY diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 05e39899e6f25..edff8b3ed84cf 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -885,12 +885,13 @@ def UnevaluatedExpression : DiagGroup<"unevaluated-expression", def UnusedValue : DiagGroup<"unused-value", [UnusedComparison, UnusedResult, UnevaluatedExpression]>; def UnusedConstVariable : DiagGroup<"unused-const-variable">; -def UnusedVariable : DiagGroup<"unused-variable", - [UnusedConstVariable]>; +def UnusedVariable + : DiagGroup<"unused-variable", [UnusedConstVariable], [{}], 1, 1>; def UnusedButSetVariable : DiagGroup<"unused-but-set-variable">; def UnusedLocalTypedef : DiagGroup<"unused-local-typedef">; def UnusedPropertyIvar : DiagGroup<"unused-property-ivar">; def UnusedGetterReturnValue : DiagGroup<"unused-getter-return-value">; +def UnusedDummyArgument : DiagGroup<"unused-dummy-argument", [], [{}], 0, 1>; def UsedButMarkedUnused : DiagGroup<"used-but-marked-unused">; def UsedSearchPath : DiagGroup<"search-path-usage">; def UserDefinedLiterals : DiagGroup<"user-defined-literals">; diff --git a/clang/include/clang/Basic/DiagnosticIDs.h b/clang/include/clang/Basic/DiagnosticIDs.h index b49185c3335d8..2ae737b1a1031 100644 --- a/clang/include/clang/Basic/DiagnosticIDs.h +++ b/clang/include/clang/Basic/DiagnosticIDs.h @@ -365,6 +365,11 @@ class DiagnosticIDs : public RefCountedBase<DiagnosticIDs> { /// Given a diagnostic group ID, return its documentation. static StringRef getWarningOptionDocumentation(diag::Group GroupID); + /// Given a diagnostic group ID, return true if its a Flang warning. + static bool isFlangWarningOption(diag::Group Group); + /// Given a diagnostic group ID, return true if its a Clang warning. + static bool isClangWarningOption(diag::Group Group); + void setGroupSeverity(StringRef Group, diag::Severity); void setGroupNoWarningsAsError(StringRef Group, bool); diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 2fce5e88ba8a0..4ab94ecbb7e56 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -12966,4 +12966,10 @@ def note_acc_atomic_mismatch_compound_operand // AMDGCN builtins diagnostics def err_amdgcn_global_load_lds_size_invalid_value : Error<"invalid size value">; def note_amdgcn_global_load_lds_size_valid_value : Note<"size must be %select{1, 2, or 4|1, 2, 4, 12 or 16}0">; + +// Flang diagnostics +def warn_unused_dummy_argument : Warning<"unused dummy argument %0">, + InGroup<UnusedDummyArgument>, + DefaultIgnore; + } // end of sema component. diff --git a/clang/lib/Basic/DiagnosticIDs.cpp b/clang/lib/Basic/DiagnosticIDs.cpp index ca5b8d2da769e..e275f7165b392 100644 --- a/clang/lib/Basic/DiagnosticIDs.cpp +++ b/clang/lib/Basic/DiagnosticIDs.cpp @@ -585,6 +585,8 @@ namespace { uint16_t Members; uint16_t SubGroups; StringRef Documentation; + bool IsClangDiag; + bool IsFlangDiag; StringRef getName() const { return DiagGroupNames[NameOffset]; } }; @@ -592,8 +594,9 @@ namespace { // Second the table of options, sorted by name for fast binary lookup. static const WarningOption OptionTable[] = { -#define DIAG_ENTRY(GroupName, FlagNameOffset, Members, SubGroups, Docs) \ - {FlagNameOffset, Members, SubGroups, Docs}, +#define DIAG_ENTRY(GroupName, FlagNameOffset, Members, SubGroups, Docs, \ + IsClang, IsFlang) \ + {FlagNameOffset, Members, SubGroups, Docs, IsClang, IsFlang}, #include "clang/Basic/DiagnosticGroups.inc" #undef DIAG_ENTRY }; @@ -607,6 +610,13 @@ StringRef DiagnosticIDs::getWarningOptionForGroup(diag::Group Group) { return OptionTable[static_cast<int>(Group)].getName(); } +bool DiagnosticIDs::isFlangWarningOption(diag::Group Group) { + return OptionTable[static_cast<int>(Group)].IsFlangDiag; +} + +bool DiagnosticIDs::isClangWarningOption(diag::Group Group) { + return OptionTable[static_cast<int>(Group)].IsClangDiag; +} std::optional<diag::Group> DiagnosticIDs::getGroupForWarningOption(StringRef Name) { const auto *Found = llvm::partition_point( diff --git a/clang/lib/Basic/Warnings.cpp b/clang/lib/Basic/Warnings.cpp index 5f48e0ec81554..e6c1355650113 100644 --- a/clang/lib/Basic/Warnings.cpp +++ b/clang/lib/Basic/Warnings.cpp @@ -106,6 +106,15 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags, diag::Severity Mapping = isPositive ? diag::Severity::Warning : diag::Severity::Ignored; + // Check if the warning option is valid for Clang + std::optional<diag::Group> Group = DiagIDs->getGroupForWarningOption(Opt); + if (Group.has_value() && !DiagIDs->isClangWarningOption(Group.value())) { + const unsigned DiagID = Diags.getCustomDiagID( + DiagnosticsEngine::Error, + "Warning option \"%0\" is valid for Fortran but not for C++."); + Diags.Report(DiagID) << Opt; + } + // -Wsystem-headers is a special case, not driven by the option table. It // cannot be controlled with -Werror. if (Opt == "system-headers") { diff --git a/clang/tools/diagtool/DiagnosticNames.cpp b/clang/tools/diagtool/DiagnosticNames.cpp index 4ac9825848ef3..95b9da461599b 100644 --- a/clang/tools/diagtool/DiagnosticNames.cpp +++ b/clang/tools/diagtool/DiagnosticNames.cpp @@ -62,7 +62,8 @@ const DiagnosticRecord &diagtool::getDiagnosticForID(short DiagID) { // Second the table of options, sorted by name for fast binary lookup. static const GroupRecord OptionTable[] = { -#define DIAG_ENTRY(GroupName, FlagNameOffset, Members, SubGroups, Docs) \ +#define DIAG_ENTRY(GroupName, FlagNameOffset, Members, SubGroups, Docs, \ + IsClang, IsFlang) \ {FlagNameOffset, Members, SubGroups}, #include "clang/Basic/DiagnosticGroups.inc" #undef DIAG_ENTRY diff --git a/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp b/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp index 8f846a4744bbf..0c0962f6fceaa 100644 --- a/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp +++ b/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp @@ -1890,6 +1890,10 @@ static void emitDiagTable(DiagsInGroupTy &DiagsInGroup, OS << "R\"(" << StringRef(Documentation).trim() << ")\""; + OS << ", /*IsClangDiag*/ " + << bool(GroupInfo.Defs.back()->getValueAsBit("IsClangDiag")); + OS << ", /*IsFlangDiag*/ " + << bool(GroupInfo.Defs.back()->getValueAsBit("IsFlangDiag")); OS << ")\n"; } OS << "#endif // DIAG_ENTRY\n\n"; diff --git a/flang/include/flang/Frontend/CompilerInvocation.h b/flang/include/flang/Frontend/CompilerInvocation.h index 9e6724be33033..9fdaeac3d999a 100644 --- a/flang/include/flang/Frontend/CompilerInvocation.h +++ b/flang/include/flang/Frontend/CompilerInvocation.h @@ -33,12 +33,18 @@ class TargetMachine; namespace Fortran::frontend { +/// processWarningOptions - Initialize the diagnostic client and process the +/// warning options specified on the command line. +void processWarningOptions(clang::DiagnosticsEngine &Diags, + const clang::DiagnosticOptions &Opts); + /// Fill out Opts based on the options given in Args. /// /// When errors are encountered, return false and, if Diags is non-null, /// report the error(s). bool parseDiagnosticArgs(clang::DiagnosticOptions &opts, - llvm::opt::ArgList &args); + llvm::opt::ArgList &args, + bool defaultDiagColor = true); class CompilerInvocationBase { public: @@ -174,7 +180,7 @@ class CompilerInvocation : public CompilerInvocationBase { /// Creates and configures semantics context based on the compilation flags. std::unique_ptr<Fortran::semantics::SemanticsContext> getSemanticsCtx(Fortran::parser::AllCookedSources &allCookedSources, - const llvm::TargetMachine &); + const llvm::TargetMachine &, clang::DiagnosticsEngine &diag); std::string &getModuleDir() { return moduleDir; } const std::string &getModuleDir() const { return moduleDir; } diff --git a/flang/include/flang/Semantics/semantics.h b/flang/include/flang/Semantics/semantics.h index 730513dbe3232..72ecd046f4048 100644 --- a/flang/include/flang/Semantics/semantics.h +++ b/flang/include/flang/Semantics/semantics.h @@ -19,6 +19,7 @@ #include "flang/Parser/message.h" #include "flang/Support/Fortran-features.h" #include "flang/Support/LangOptions.h" +#include "clang/Basic/Diagnostic.h" #include <iosfwd> #include <set> #include <string> @@ -68,7 +69,7 @@ class SemanticsContext { public: SemanticsContext(const common::IntrinsicTypeDefaultKinds &, const common::LanguageFeatureControl &, const common::LangOptions &, - parser::AllCookedSources &); + parser::AllCookedSources &, clang::DiagnosticsEngine &); ~SemanticsContext(); const common::IntrinsicTypeDefaultKinds &defaultKinds() const { @@ -82,6 +83,7 @@ class SemanticsContext { int doublePrecisionKind() const { return defaultKinds_.doublePrecisionKind(); } + clang::DiagnosticsEngine &getDiagnostics() const { return diags_; } int quadPrecisionKind() const { return defaultKinds_.quadPrecisionKind(); } bool IsEnabled(common::LanguageFeature feature) const { return languageFeatures_.IsEnabled(feature); @@ -305,6 +307,7 @@ class SemanticsContext { const common::IntrinsicTypeDefaultKinds &defaultKinds_; const common::LanguageFeatureControl &languageFeatures_; const common::LangOptions &langOpts_; + clang::DiagnosticsEngine &diags_; parser::AllCookedSources &allCookedSources_; std::optional<parser::CharBlock> location_; std::vector<std::string> searchDirectories_; diff --git a/flang/include/flang/Semantics/symbol.h b/flang/include/flang/Semantics/symbol.h index 4ae2775c0f849..2c7e9bae5e652 100644 --- a/flang/include/flang/Semantics/symbol.h +++ b/flang/include/flang/Semantics/symbol.h @@ -293,10 +293,13 @@ class EntityDetails : public WithBindName { void set_isDummy(bool value = true) { isDummy_ = value; } bool isFuncResult() const { return isFuncResult_; } void set_funcResult(bool x) { isFuncResult_ = x; } + bool isUsed() const { return isUsed_; } + void set_isUsed() { isUsed_ = true; } private: bool isDummy_{false}; bool isFuncResult_{false}; + bool isUsed_{false}; const DeclTypeSpec *type_{nullptr}; friend llvm::raw_ostream &operator<<( llvm::raw_ostream &, const EntityDetails &); diff --git a/flang/lib/Frontend/CMakeLists.txt b/flang/lib/Frontend/CMakeLists.txt index 81eef2d468d8c..ac03f8ab4cce7 100644 --- a/flang/lib/Frontend/CMakeLists.txt +++ b/flang/lib/Frontend/CMakeLists.txt @@ -11,6 +11,7 @@ add_flang_library(flangFrontend TextDiagnosticPrinter.cpp TextDiagnosticBuffer.cpp TextDiagnostic.cpp + Warnings.cpp DEPENDS CUFDialect diff --git a/flang/lib/Frontend/CompilerInstance.cpp b/flang/lib/Frontend/CompilerInstance.cpp index b1fa32ecb4cfc..6374a8b0d45bd 100644 --- a/flang/lib/Frontend/CompilerInstance.cpp +++ b/flang/lib/Frontend/CompilerInstance.cpp @@ -163,7 +163,8 @@ bool CompilerInstance::executeAction(FrontendAction &act) { if (!setUpTargetMachine()) return false; // Create the semantics context - semaContext = invoc.getSemanticsCtx(*allCookedSources, getTargetMachine()); + semaContext = invoc.getSemanticsCtx(*allCookedSources, getTargetMachine(), + getDiagnostics()); // Set options controlling lowering to FIR. invoc.setLoweringOptions(); diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp index f3d9432c62d3b..4a1f73bb76fba 100644 --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -32,6 +32,7 @@ #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/OptTable.h" +#include "llvm/Option/Option.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/FileUtilities.h" @@ -118,9 +119,26 @@ static unsigned getOptimizationLevel(llvm::opt::ArgList &args, } bool Fortran::frontend::parseDiagnosticArgs(clang::DiagnosticOptions &opts, - llvm::opt::ArgList &args) { - opts.ShowColors = parseShowColorsArgs(args); - + llvm::opt::ArgList &args, + bool defaultDiagColor) { + opts.ShowColors = parseShowColorsArgs(args, defaultDiagColor); + + for (llvm::opt::Arg *A : args.filtered(clang::driver::options::OPT_W_Group)) { + if (A->getOption().getKind() == llvm::opt::Option::FlagClass) { + // The argument is a pure flag (such as OPT_Wall). + opts.Warnings.push_back( + std::string(A->getOption().getName().drop_front(1))); + } else if (A->getOption().matches( + clang::driver::options::OPT_W_value_Group)) { + // This is -Wfoo= where foo is the name of the diagnostic group. + // Add only the group name to the diagnostics. + opts.Warnings.push_back( + std::string(A->getOption().getName().drop_front(1).rtrim("=-"))); + } else { + // Otherwise, add its value for OPT_W_Joined. + opts.Warnings.push_back(A->getValue()); + } + } return true; } @@ -923,22 +941,11 @@ static bool parseDiagArgs(CompilerInvocation &res, llvm::opt::ArgList &args, clang::DiagnosticsEngine &diags) { unsigned numErrorsBefore = diags.getNumErrors(); - // -Werror option - // TODO: Currently throws a Diagnostic for anything other than -W<error>, - // this has to change when other -W<opt>'s are supported. - if (args.hasArg(clang::driver::options::OPT_W_Joined)) { - const auto &wArgs = - args.getAllArgValues(clang::driver::options::OPT_W_Joined); - 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); - } - } + // Handle warning Diagnostic for the frontend. + clang::DiagnosticOptions &diagOpts = res.getDiagnosticOpts(); + for (const auto &warning : diagOpts.Warnings) { + if (warning == "error") + res.setWarnAsErr(true); } // Default to off for `flang -fc1`. @@ -1000,6 +1007,7 @@ static bool parseDialectArgs(CompilerInvocation &res, llvm::opt::ArgList &args, if (args.hasArg(clang::driver::options::OPT_pedantic)) { res.setEnableConformanceChecks(); res.setEnableUsageChecks(); + res.getDiagnosticOpts().Pedantic = true; } // -w @@ -1620,12 +1628,12 @@ void CompilerInvocation::setFortranOpts() { std::unique_ptr<Fortran::semantics::SemanticsContext> CompilerInvocation::getSemanticsCtx( Fortran::parser::AllCookedSources &allCookedSources, - const llvm::TargetMachine &targetMachine) { + const llvm::TargetMachine &targetMachine, clang::DiagnosticsEngine &diags) { auto &fortranOptions = getFortranOpts(); auto semanticsContext = std::make_unique<semantics::SemanticsContext>( getDefaultKinds(), fortranOptions.features, getLangOpts(), - allCookedSources); + allCookedSources, diags); semanticsContext->set_moduleDirectory(getModuleDir()) .set_searchDirectories(fortranOptions.searchDirectories) diff --git a/flang/lib/Frontend/Warnings.cpp b/flang/lib/Frontend/Warnings.cpp new file mode 100644 index 0000000000000..70e93efdd866d --- /dev/null +++ b/flang/lib/Frontend/Warnings.cpp @@ -0,0 +1,102 @@ +//===--- Warnings.cpp -----------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Command line warning options handler. +// +//===----------------------------------------------------------------------===// +// +// This file is responsible for handling all warning options. This includes +// a number of -Wfoo options and their variants, which are driven by TableGen- +// generated data, and the special cases -pedantic, -pedantic-errors, -w, +// -Werror, ... +// +// Each warning option controls any number of actual warnings. +// Given a warning option 'foo', the following are valid: +// -Wfoo, -Wno-foo, -Werror=foo +// +#include "clang/Basic/AllDiagnostics.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticDriver.h" +#include "clang/Basic/DiagnosticIDs.h" +#include "clang/Basic/DiagnosticOptions.h" +#include "llvm/ADT/StringRef.h" +#include <cstring> + +namespace Fortran::frontend { + +// EmitUnknownDiagWarning - Emit a warning and typo hint for unknown warning +// opts + +static void EmitUnknownDiagWarning(clang::DiagnosticsEngine &diags, + clang::diag::Flavor flavor, + llvm::StringRef prefix, + llvm::StringRef opt) { + llvm::StringRef suggestion = + clang::DiagnosticIDs::getNearestOption(flavor, opt); + diags.Report(clang::diag::warn_unknown_diag_option) + << (flavor == clang::diag::Flavor::WarningOrError ? 0 : 1) + << (prefix.str() += std::string(opt)) << !suggestion.empty() + << (prefix.str() += std::string(suggestion)); +} + +void processWarningOptions(clang::DiagnosticsEngine &diags, + const clang::DiagnosticOptions &opts) { + diags.setIgnoreAllWarnings(opts.IgnoreWarnings); + diags.setShowColors(opts.ShowColors); + + // If -pedantic or -pedantic-errors was specified, then we want to map all + // extension diagnostics onto WARNING or ERROR. + if (opts.PedanticErrors) + diags.setExtensionHandlingBehavior(clang::diag::Severity::Error); + else if (opts.Pedantic) + diags.setExtensionHandlingBehavior(clang::diag::Severity::Warning); + else + diags.setExtensionHandlingBehavior(clang::diag::Severity::Ignored); + + llvm::SmallVector<clang::diag::kind, 10> _diags; + const llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagIDs = + diags.getDiagnosticIDs(); + for (unsigned i = 0, e = opts.Warnings.size(); i != e; ++i) { + const auto flavor = clang::diag::Flavor::WarningOrError; + llvm::StringRef opt = opts.Warnings[i]; + + // Check to see if this warning starts with "no-", if so, this is a + // negative form of the option. + bool isPositive = !opt.consume_front("no-"); + + // Figure out how this option affects the warning. If -Wfoo, map the + // diagnostic to a warning, if -Wno-foo, map it to ignore. + clang::diag::Severity mapping = isPositive ? clang::diag::Severity::Warning + : clang::diag::Severity::Ignored; + + // -Werror/-Wno-error is a special case, not controlled by the option table. + // TODO: Adding support of "specifier" form of -Werror=foo. + if (opt == "error") { + diags.setWarningsAsErrors(isPositive); + continue; + } + + if (std::optional<clang::diag::Group> group = + diagIDs->getGroupForWarningOption(opt)) { + if (!diagIDs->isFlangWarningOption(group.value())) { + // Warning option not supported by Flang + // FIXME : Updating diagnostic error message when all warning options + // will be supported + const unsigned diagID = + diags.getCustomDiagID(clang::DiagnosticsEngine::Error, + "Warning option \"%0\" not supported."); + diags.Report(diagID) << opt; + } + } else { + // Unkown warning option. + EmitUnknownDiagWarning(diags, flavor, isPositive ? "-W" : "-Wno-", opt); + } + diags.setSeverityForGroup(flavor, opt, mapping); + } +} +} // namespace Fortran::frontend diff --git a/flang/lib/Semantics/CMakeLists.txt b/flang/lib/Semantics/CMakeLists.txt index 00108dde49dbd..7182a23cb7352 100644 --- a/flang/lib/Semantics/CMakeLists.txt +++ b/flang/lib/Semantics/CMakeLists.txt @@ -26,6 +26,7 @@ add_flang_library(FortranSemantics check-select-rank.cpp check-select-type.cpp check-stop.cpp + check-warning.cpp compute-offsets.cpp data-to-inits.cpp definable.cpp @@ -62,4 +63,7 @@ add_flang_library(FortranSemantics FrontendOpenMP FrontendOpenACC TargetParser + + CLANG_LIBS + clangBasic ) diff --git a/flang/lib/Semantics/check-warning.cpp b/flang/lib/Semantics/check-warning.cpp new file mode 100644 index 0000000000000..0c30ac4367919 --- /dev/null +++ b/flang/lib/Semantics/check-warning.cpp @@ -0,0 +1,89 @@ +//===-- lib/Semantics/check-warning.cpp +//-----------------------------------------===// +// +// 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 "check-warning.h" +#include "flang/Semantics/tools.h" +#include "clang/Basic/AllDiagnostics.h" +#include "clang/Basic/DiagnosticDriver.h" +#include "clang/Basic/DiagnosticOptions.h" + +namespace Fortran::semantics { + +void WarningChecker::Enter(const parser::FunctionStmt &stmt) { + clang::DiagnosticsEngine &diags = context_.getDiagnostics(); + auto opts = diags.getDiagnosticOptions().Warnings; + for (const auto &dummyName : std::get<std::list<parser::Name>>(stmt.t)) { + if (auto *detail = dummyName.symbol->detailsIf<ObjectEntityDetails>()) { + const Symbol *ownerSymbol{dummyName.symbol->owner().symbol()}; + const auto *ownerSubp{ownerSymbol->detailsIf<SubprogramDetails>()}; + bool inInterface{ownerSubp && ownerSubp->isInterface()}; + if (!inInterface && !detail->isUsed()) { + diags.Report(clang::diag::warn_unused_dummy_argument) + << dummyName.ToString(); + } + } + } + if (const auto &suffix{std::get<std::optional<parser::Suffix>>(stmt.t)}) { + if (suffix->resultName.has_value()) { + if (auto *detail = + suffix->resultName->symbol->detailsIf<ObjectEntityDetails>()) { + const Symbol *ownerSymbol{suffix->resultName->symbol->owner().symbol()}; + const auto *ownerSubp{ownerSymbol->detailsIf<SubprogramDetails>()}; + bool inInterface{ownerSubp && ownerSubp->isInterface()}; + if (!inInterface && !detail->isUsed()) { + diags.Report(clang::diag::warn_unused_variable) + << suffix->resultName->ToString(); + } + } + } + } +} + +void WarningChecker::Enter(const parser::SubroutineStmt &stmt) { + clang::DiagnosticsEngine &diags = context_.getDiagnostics(); + for (const auto &dummyArg : std::get<std::list<parser::DummyArg>>(stmt.t)) { + if (const auto *dummyName{std::get_if<parser::Name>(&dummyArg.u)}) { + if (const auto *symbol = dummyName->symbol) { + + const Symbol *ownerSymbol{symbol->owner().symbol()}; + const auto *ownerSubp{ownerSymbol->detailsIf<SubprogramDetails>()}; + bool inInterface{ownerSubp && ownerSubp->isInterface()}; + + if (auto *detail = symbol->detailsIf<ObjectEntityDetails>()) { + if (!inInterface && !detail->isUsed()) { + diags.Report(clang::diag::warn_unused_dummy_argument) + << dummyName->ToString(); + } + } + } + } + } +} + +void WarningChecker::Enter(const parser::EntityDecl &decl) { + clang::DiagnosticsEngine &diags = context_.getDiagnostics(); + const auto &name{std::get<parser::ObjectName>(decl.t)}; + if (const auto *symbol = name.symbol) { + if (const Symbol *ownerSymbol{symbol->owner().symbol()}) { + const auto *ownerSubp{ownerSymbol->detailsIf<SubprogramDetails>()}; + bool inInterface{ownerSubp && ownerSubp->isInterface()}; + bool inModule{ownerSymbol && ownerSymbol->scope() && + ownerSymbol->scope()->IsModule()}; + + if (auto *detail = symbol->detailsIf<ObjectEntityDetails>()) { + if (!inInterface && !inModule && !detail->isDummy() && + !detail->isFuncResult() && !detail->isUsed()) { + diags.Report(clang::diag::warn_unused_variable) << name.ToString(); + } + } + } + } +} + +} // namespace Fortran::semantics diff --git a/flang/lib/Semantics/check-warning.h b/flang/lib/Semantics/check-warning.h new file mode 100644 index 0000000000000..33e9187e9c0e4 --- /dev/null +++ b/flang/lib/Semantics/check-warning.h @@ -0,0 +1,36 @@ +//===-- lib/Semantics/check-warning.h ---------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef FORTRAN_SEMANTICS_CHECK_WARNING_H_ +#define FORTRAN_SEMANTICS_CHECK_WARNING_H_ + +#include "flang/Semantics/semantics.h" + +namespace Fortran::parser { +struct FunctionStmt; +struct InterfaceBody; +struct SubroutineStmt; +struct EntityDecl; +} // namespace Fortran::parser + +namespace Fortran::semantics { + +// Perform semantic checks on DummyArg on Function and Subroutine +// TODO: Add checks for future warning options +class WarningChecker : public virtual BaseChecker { +public: + explicit WarningChecker(SemanticsContext &context) : context_{context} {} + void Enter(const parser::FunctionStmt &); + void Enter(const parser::SubroutineStmt &); + void Enter(const parser::EntityDecl &); + +private: + SemanticsContext &context_; +}; +} // namespace Fortran::semantics +#endif diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp index 6949e5693d08f..be077fdceddf4 100644 --- a/flang/lib/Semantics/expression.cpp +++ b/flang/lib/Semantics/expression.cpp @@ -590,6 +590,13 @@ MaybeExpr ExpressionAnalyzer::FixMisparsedSubstring( } MaybeExpr ExpressionAnalyzer::Analyze(const parser::Designator &d) { + const auto &name = GetFirstName(d); + if (name.symbol) { + if (auto *detail = + name.symbol->detailsIf<Fortran::semantics::ObjectEntityDetails>()) { + detail->set_isUsed(); + } + } auto restorer{GetContextualMessages().SetLocation(d.source)}; if (auto substringInquiry{FixMisparsedSubstring(d)}) { return substringInquiry; diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp index e64abe6b50e78..488b0acfee8ff 100644 --- a/flang/lib/Semantics/resolve-names.cpp +++ b/flang/lib/Semantics/resolve-names.cpp @@ -6693,6 +6693,11 @@ bool DeclarationVisitor::Pre(const parser::CommonBlockObject &) { void DeclarationVisitor::Post(const parser::CommonBlockObject &x) { const auto &name{std::get<parser::Name>(x.t)}; DeclareObjectEntity(name); + if (name.symbol) { + if (auto *detail{name.symbol->detailsIf<ObjectEntityDetails>()}) { + detail->set_isUsed(); + } + } auto pair{specPartState_.commonBlockObjects.insert(name.source)}; if (!pair.second) { const SourceName &prev{*pair.first}; diff --git a/flang/lib/Semantics/semantics.cpp b/flang/lib/Semantics/semantics.cpp index 10a01039ea0ae..4b5b31fe606ca 100644 --- a/flang/lib/Semantics/semantics.cpp +++ b/flang/lib/Semantics/semantics.cpp @@ -32,6 +32,7 @@ #include "check-select-rank.h" #include "check-select-type.h" #include "check-stop.h" +#include "check-warning.h" #include "compute-offsets.h" #include "mod-file.h" #include "resolve-labels.h" @@ -202,6 +203,7 @@ using StatementSemanticsPass2 = SemanticsVisitor<AllocateChecker, MiscChecker, NamelistChecker, NullifyChecker, PurityChecker, ReturnStmtChecker, SelectRankConstructChecker, SelectTypeChecker, StopChecker>; +using StatementSemanticsPass3 = SemanticsVisitor<WarningChecker>; static bool PerformStatementSemantics( SemanticsContext &context, parser::Program &program) { @@ -221,6 +223,7 @@ static bool PerformStatementSemantics( if (context.languageFeatures().IsEnabled(common::LanguageFeature::CUDA)) { SemanticsVisitor<CUDAChecker>{context}.Walk(program); } + StatementSemanticsPass3{context}.Walk(program); if (!context.messages().AnyFatalError()) { WarnUndefinedFunctionResult(context, context.globalScope()); } @@ -346,9 +349,9 @@ SemanticsContext::SemanticsContext( const common::IntrinsicTypeDefaultKinds &defaultKinds, const common::LanguageFeatureControl &languageFeatures, const common::LangOptions &langOpts, - parser::AllCookedSources &allCookedSources) + parser::AllCookedSources &allCookedSources, clang::DiagnosticsEngine &diags) : defaultKinds_{defaultKinds}, languageFeatures_{languageFeatures}, - langOpts_{langOpts}, allCookedSources_{allCookedSources}, + langOpts_{langOpts}, allCookedSources_{allCookedSources}, diags_{diags}, intrinsics_{evaluate::IntrinsicProcTable::Configure(defaultKinds_)}, globalScope_{*this}, intrinsicModulesScope_{globalScope_.MakeScope( Scope::Kind::IntrinsicModules, nullptr)}, diff --git a/flang/test/Driver/w-arg-unknown.f90 b/flang/test/Driver/w-arg-unknown.f90 new file mode 100644 index 0000000000000..19b39f6cb3b33 --- /dev/null +++ b/flang/test/Driver/w-arg-unknown.f90 @@ -0,0 +1,7 @@ +! Ensure that unknown warning options generate a warning message. + +! RUN: %flang_fc1 -fsyntax-only -WX %s 2>&1 | FileCheck %s --check-prefix=UNKNOWN1 +! RUN: %flang_fc1 -fsyntax-only -Werror2 %s 2>&1 | FileCheck %s --check-prefix=UNKNOWN2 + +! UNKNOWN1: unknown warning option '-WX' +! UNKNOWN2: unknown warning option '-Werror2' diff --git a/flang/test/Driver/werror-wrong.f90 b/flang/test/Driver/werror-wrong.f90 deleted file mode 100644 index 58adf6f745d5e..0000000000000 --- a/flang/test/Driver/werror-wrong.f90 +++ /dev/null @@ -1,6 +0,0 @@ -! Ensure that only argument -Werror is supported. - -! RUN: not %flang_fc1 -fsyntax-only -Wall %s 2>&1 | FileCheck %s --check-prefix=WRONG -! RUN: not %flang_fc1 -fsyntax-only -WX %s 2>&1 | FileCheck %s --check-prefix=WRONG - -! WRONG: Only `-Werror` is supported currently. diff --git a/flang/test/Driver/wextra-ok.f90 b/flang/test/Driver/wextra-ok.f90 index 441029aa0af27..63c18c3ad2b12 100644 --- a/flang/test/Driver/wextra-ok.f90 +++ b/flang/test/Driver/wextra-ok.f90 @@ -2,10 +2,10 @@ ! The first check should be changed if -Wextra is implemented ! RUN: %flang -std=f2018 -Wextra %s -c 2>&1 | FileCheck %s --check-prefix=CHECK-OK -! RUN: not %flang -std=f2018 -Wblah -Wextra %s -c 2>&1 | FileCheck %s --check-prefix=WRONG +! RUN: %flang -std=f2018 -Wblah -Wextra %s -c 2>&1 | FileCheck %s --check-prefix=WRONG ! CHECK-OK: the warning option '-Wextra' is not supported -! WRONG: Only `-Werror` is supported currently. +! WRONG: unknown warning option '-Wblah' program wextra_ok end program wextra_ok diff --git a/flang/test/Semantics/wunused-dummy-argument.f90 b/flang/test/Semantics/wunused-dummy-argument.f90 new file mode 100644 index 0000000000000..e09132aec5342 --- /dev/null +++ b/flang/test/Semantics/wunused-dummy-argument.f90 @@ -0,0 +1,54 @@ +! RUN: %flang_fc1 -Wunused-dummy-argument %s 2>&1 | FileCheck %s +! RUN: not %flang_fc1 -Wunused-dummy-argument -Werror %s +! RUN: %flang_fc1 -Wno-unused-dummy-argument %s 2>&1 | FileCheck %s --check-prefix=NOWARN + +! CHECK: warning: unused dummy argument a4 [-Wunused-dummy-argument] +! CHECK: warning: unused dummy argument b4 [-Wunused-dummy-argument] +! CHECK: warning: unused dummy argument a6 [-Wunused-dummy-argument] +! CHECK: warning: unused dummy argument b6 [-Wunused-dummy-argument] + +! NOWARN-NOT: warning: unused dummy argument a4 [-Wunused-dummy-argument] +! NOWARN-NOT: warning: unused dummy argument b4 [-Wunused-dummy-argument] +! NOWARN-NOT: warning: unused dummy argument a6 [-Wunused-dummy-argument] +! NOWARN-NOT: warning: unused dummy argument b6 [-Wunused-dummy-argument] + +program main + type :: my_type + integer :: val + end type + integer :: not_dummy_arg + interface + subroutine subroutine_interface(a) + integer, intent(in) :: a + end subroutine + + function function_interface(a2) + integer, intent(in) :: a2 + end function + end interface +contains + subroutine subroutine_all_used(a3, b3) + integer, intent(inout) :: a3, b3 + a3 = a3 + b3 + end subroutine + + subroutine subroutine_unused_both(a4, b4) + integer, intent(inout) :: a4(10) + type(my_type) :: b4 + end subroutine + + + function function_used_all(a5, b5) result(c1) + integer, intent(inout) :: a5(10) + type(my_type), intent(in) :: b5 + integer :: c1 + a5(1) = b5%val + c1 = a5(2) + end function + + function function_unused_both(a6, b6) result(c2) + integer, intent(inout) :: a6(10) + type(my_type) :: b6 + integer :: c2 + end function +end program diff --git a/flang/test/Semantics/wunused-variable.f90 b/flang/test/Semantics/wunused-variable.f90 new file mode 100644 index 0000000000000..28f1b3aacbc3f --- /dev/null +++ b/flang/test/Semantics/wunused-variable.f90 @@ -0,0 +1,72 @@ +! RUN: %flang_fc1 -Wunused-variable %s 2>&1 | FileCheck %s +! RUN: not %flang_fc1 -Wunused-variable -Werror %s +! RUN: %flang_fc1 -Wno-unused-variable %s 2>&1 | FileCheck %s --check-prefix=NOWARN + +! CHECK: warning: unused variable unused_var_in_submod_subroutine [-Wunused-variable] +! CHECK: warning: unused variable my_type_var1 [-Wunused-variable] +! CHECK: warning: unused variable not_dummy_arg [-Wunused-variable] +! CHECK: warning: unused variable in_subroutine [-Wunused-variable] +! CHECK: warning: unused variable c1 [-Wunused-variable] + +! NOWARN-NOT: warning: unused variable unused_var_in_submod_subroutine [-Wunused-variable] +! NOWARN-NOT: warning: unused variable my_type_var1 [-Wunused-variable] +! NOWARN-NOT: warning: unused variable not_dummy_arg [-Wunused-variable] +! NOWARN-NOT: warning: unused variable in_subroutine [-Wunused-variable] +! NOWARN-NOT: warning: unused variable c1 [-Wunused-variable] +module test + integer :: var_in_module + contains + subroutine module_subroutine(a) + integer :: unused_var_in_submod_subroutine + integer :: a + end subroutine +end module test + +program main + type :: my_type + integer :: val + integer :: unused_val + end type + interface + subroutine subroutine_in_interface() + integer :: w + end subroutine + function function_in_interface() result(j) + integer :: x + integer :: j + end function + end interface + type(my_type) :: my_type_var1 + type(my_type) :: my_type_var2 + integer :: not_dummy_arg + + integer :: variable_common + common variable_common + + my_type_var2%val = 12 + + + + print *, function_used_all() + + contains + subroutine subroutine_all_used(a3) + integer, intent(in) :: a3 + integer :: in_subroutine_used + in_subroutine_used = a3 + end subroutine + + subroutine subroutine_unused(a4) + integer, intent(in) :: a4 + integer :: in_subroutine + end subroutine + + function function_used_all() result(c1) + integer :: in_function + integer :: c1 + c1 = in_function + end function + + function function_unused_all() result(c1) + end function +end program diff --git a/flang/tools/bbc/CMakeLists.txt b/flang/tools/bbc/CMakeLists.txt index f950f03920d3f..7c6ac4220ca33 100644 --- a/flang/tools/bbc/CMakeLists.txt +++ b/flang/tools/bbc/CMakeLists.txt @@ -31,6 +31,11 @@ target_link_libraries(bbc PRIVATE FlangOpenMPTransforms ) +clang_target_link_libraries(bbc PRIVATE + PRIVATE + clangBasic +) + mlir_target_link_libraries(bbc PRIVATE ${dialect_libs} ${extension_libs} diff --git a/flang/tools/bbc/bbc.cpp b/flang/tools/bbc/bbc.cpp index 3b19a1c2a78d9..0a07eee2da839 100644 --- a/flang/tools/bbc/bbc.cpp +++ b/flang/tools/bbc/bbc.cpp @@ -15,7 +15,10 @@ //===----------------------------------------------------------------------===// #include "flang/Frontend/CodeGenOptions.h" +#include "flang/Frontend/CompilerInstance.h" +#include "flang/Frontend/CompilerInvocation.h" #include "flang/Frontend/TargetOptions.h" +#include "flang/Frontend/TextDiagnosticBuffer.h" #include "flang/Lower/Bridge.h" #include "flang/Lower/PFTBuilder.h" #include "flang/Lower/Support/Verifier.h" @@ -492,6 +495,15 @@ static llvm::LogicalResult convertFortranSourceToMLIR( } int main(int argc, char **argv) { + // Creating a SemanticsContext require a DiagnosticsEngine + Fortran::frontend::TextDiagnosticBuffer *diagsBuffer = + new Fortran::frontend::TextDiagnosticBuffer; + llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagID( + new clang::DiagnosticIDs()); + llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> diagOpts = + new clang::DiagnosticOptions(); + clang::DiagnosticsEngine diags(diagID, &*diagOpts, diagsBuffer); + [[maybe_unused]] llvm::InitLLVM y(argc, argv); llvm::InitializeAllTargets(); llvm::InitializeAllTargetMCs(); @@ -573,7 +585,7 @@ int main(int argc, char **argv) { Fortran::parser::AllSources allSources; Fortran::parser::AllCookedSources allCookedSources(allSources); Fortran::semantics::SemanticsContext semanticsContext{ - defaultKinds, options.features, langOpts, allCookedSources}; + defaultKinds, options.features, langOpts, allCookedSources, diags}; semanticsContext.set_moduleDirectory(moduleDir) .set_moduleFileSuffix(moduleSuffix) .set_searchDirectories(includeDirs) diff --git a/flang/tools/flang-driver/driver.cpp b/flang/tools/flang-driver/driver.cpp index ed52988feaa59..a6c616289f28a 100644 --- a/flang/tools/flang-driver/driver.cpp +++ b/flang/tools/flang-driver/driver.cpp @@ -115,12 +115,20 @@ int main(int argc, const char **argv) { // Create DiagnosticsEngine for the compiler driver llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> diagOpts = - createAndPopulateDiagOpts(args); + new clang::DiagnosticOptions(); llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagID( new clang::DiagnosticIDs()); Fortran::frontend::TextDiagnosticPrinter *diagClient = new Fortran::frontend::TextDiagnosticPrinter(llvm::errs(), &*diagOpts); + // Use the DiagnosticsEngine instance of the frontend driver + // for parsing the arguments + unsigned missingArgIndex, missingArgCount; + llvm::opt::InputArgList args2 = clang::driver::getDriverOptTable().ParseArgs( + args, missingArgIndex, missingArgCount, + llvm::opt::Visibility(clang::driver::options::FlangOption)); + Fortran::frontend::parseDiagnosticArgs(*diagOpts, args2); + diagClient->setPrefix( std::string(llvm::sys::path::stem(getExecutablePath(args[0])))); diff --git a/flang/tools/flang-driver/fc1_main.cpp b/flang/tools/flang-driver/fc1_main.cpp index 561a0dd5524e3..af98d8b0c6993 100644 --- a/flang/tools/flang-driver/fc1_main.cpp +++ b/flang/tools/flang-driver/fc1_main.cpp @@ -20,6 +20,7 @@ #include "flang/Frontend/CompilerInvocation.h" #include "flang/Frontend/TextDiagnosticBuffer.h" #include "flang/FrontendTool/Utils.h" +#include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Option/Arg.h" @@ -63,15 +64,17 @@ int fc1_main(llvm::ArrayRef<const char *> argv, const char *argv0) { // them using a well formed diagnostic object. TextDiagnosticBuffer *diagsBuffer = new TextDiagnosticBuffer; - // Create CompilerInvocation - use a dedicated instance of DiagnosticsEngine + // Use the DiagnosticsEngine instance of the frontend driver // for parsing the arguments - llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagID( - new clang::DiagnosticIDs()); - llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> diagOpts = - new clang::DiagnosticOptions(); - clang::DiagnosticsEngine diags(diagID, &*diagOpts, diagsBuffer); - bool success = CompilerInvocation::createFromArgs(flang->getInvocation(), - argv, diags, argv0); + unsigned missingArgIndex, missingArgCount; + llvm::opt::InputArgList args = clang::driver::getDriverOptTable().ParseArgs( + argv.slice(0), missingArgIndex, missingArgCount, + llvm::opt::Visibility(clang::driver::options::FC1Option)); + parseDiagnosticArgs(flang->getDiagnosticOpts(), args, false); + + bool success = CompilerInvocation::createFromArgs( + flang->getInvocation(), argv, flang->getDiagnostics(), argv0); + processWarningOptions(flang->getDiagnostics(), flang->getDiagnosticOpts()); // Initialize targets first, so that --version shows registered targets. llvm::InitializeAllTargets(); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits