Skip to content

[flang] Tag warnings with LanguageFeature or UsageWarning #110304

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

Merged
merged 1 commit into from
Oct 2, 2024

Conversation

klausler
Copy link
Contributor

@klausler klausler commented Sep 27, 2024

(This is a big patch, but it's nearly an NFC. No test results have changed and all Fortran tests in the LLVM test suites work as expected.)

Allow a parser::Message for a warning to be marked with the common::LanguageFeature or common::UsageWarning that controls it. This will allow a later patch to add hooks whereby a driver will be able to decorate warning messages with the names of its options that enable each particular warning, and to add hooks whereby a driver can map those enumerators by name to command-line options that enable/disable the language feature and enable/disable the messages.

The default settings in the constructor for LanguageFeatureControl were moved from its header file into its C++ source file.

Hooks for a driver to use to map the name of a feature or warning to its enumerator were also added.

To simplify the tagging of warnings with their corresponding language feature or usage warning, to ensure that they are properly controlled by ShouldWarn(), and to ensure that warnings never issue at code sites in module files, two new Warn() member function templates were added to SemanticsContext and other contextual frameworks. Warn() can't be used before source locations can be mapped to scopes, but the bulk of existing code blocks testing ShouldWarn() and FindModuleFile() before calling Say() were convertible into calls to Warn(). The ones that were not convertible were extended with explicit calls to Message::set_languageFeature() and set_usageWarning().

@llvmbot llvmbot added flang Flang issues not falling into any other category flang:openmp flang:semantics flang:parser labels Sep 27, 2024
@llvmbot
Copy link
Member

llvmbot commented Sep 27, 2024

@llvm/pr-subscribers-flang-parser
@llvm/pr-subscribers-flang-openmp

@llvm/pr-subscribers-flang-semantics

Author: Peter Klausler (klausler)

Changes

Allow a parser::Message for a warning to be marked with the common::LanguageFeature or common::UsageWarning that controls it. This will allow a later patch to add hooks whereby a driver will be able to decorate warning messages with the names of its options that enable each particular warning, and to add hooks whereby a driver can map those enumerators by name to command-line options that enable/disable the language feature and enable/disable the messages.

Hooks for a driver to use to map the name of a feature or warning to its enumerator were also added.

To simplify the tagging of warnings with their corresponding language feature or usage warning, to ensure that they are properly controlled by ShouldWarn(), and to ensure that warnings never issue at code sites in module files, two new Warn() member function templates were added to SemanticsContext and other contextual frameworks. Warn() can't be used before source locations can be mapped to scopes, but the bulk of existing code blocks testing ShouldWarn() and FindModuleFile() before calling Say() were convertible into calls to Warn(). The ones that were not convertible were extended with explicit calls to Message::set_languageFeature() and set_usageWarning().


Patch is 206.89 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/110304.diff

44 Files Affected:

  • (modified) flang/include/flang/Common/Fortran-features.h (+6-73)
  • (modified) flang/include/flang/Parser/message.h (+88-2)
  • (modified) flang/include/flang/Semantics/expression.h (+10)
  • (modified) flang/include/flang/Semantics/semantics.h (+19-1)
  • (modified) flang/lib/Common/Fortran-features.cpp (+94)
  • (modified) flang/lib/Evaluate/check-expression.cpp (+36-30)
  • (modified) flang/lib/Evaluate/common.cpp (+9-7)
  • (modified) flang/lib/Evaluate/fold-character.cpp (+2-2)
  • (modified) flang/lib/Evaluate/fold-complex.cpp (+1-1)
  • (modified) flang/lib/Evaluate/fold-implementation.h (+13-13)
  • (modified) flang/lib/Evaluate/fold-integer.cpp (+22-12)
  • (modified) flang/lib/Evaluate/fold-logical.cpp (+2-1)
  • (modified) flang/lib/Evaluate/fold-matmul.h (+1-1)
  • (modified) flang/lib/Evaluate/fold-real.cpp (+23-13)
  • (modified) flang/lib/Evaluate/fold-reduction.h (+3-3)
  • (modified) flang/lib/Evaluate/host.cpp (+1-1)
  • (modified) flang/lib/Evaluate/intrinsics.cpp (+9-6)
  • (modified) flang/lib/Evaluate/variable.cpp (+2-2)
  • (modified) flang/lib/Parser/message.cpp (+18)
  • (modified) flang/lib/Parser/preprocessor.cpp (+12-6)
  • (modified) flang/lib/Parser/prescan.cpp (+17-11)
  • (modified) flang/lib/Semantics/check-acc-structure.cpp (+10-18)
  • (modified) flang/lib/Semantics/check-allocate.cpp (+2-4)
  • (modified) flang/lib/Semantics/check-call.cpp (+107-92)
  • (modified) flang/lib/Semantics/check-case.cpp (+5-9)
  • (modified) flang/lib/Semantics/check-cuda.cpp (+2-4)
  • (modified) flang/lib/Semantics/check-data.cpp (+4-6)
  • (modified) flang/lib/Semantics/check-declarations.cpp (+155-204)
  • (modified) flang/lib/Semantics/check-directive-structure.h (+10-13)
  • (modified) flang/lib/Semantics/check-do-forall.cpp (+11-15)
  • (modified) flang/lib/Semantics/check-io.cpp (+7-12)
  • (modified) flang/lib/Semantics/check-omp-structure.cpp (+25-34)
  • (modified) flang/lib/Semantics/check-return.cpp (+3-3)
  • (modified) flang/lib/Semantics/compute-offsets.cpp (+3-5)
  • (modified) flang/lib/Semantics/data-to-inits.cpp (+12-22)
  • (modified) flang/lib/Semantics/definable.cpp (+2-1)
  • (modified) flang/lib/Semantics/expression.cpp (+59-88)
  • (modified) flang/lib/Semantics/mod-file.cpp (+4-2)
  • (modified) flang/lib/Semantics/pointer-assignment.cpp (+40-23)
  • (modified) flang/lib/Semantics/resolve-directives.cpp (+2-3)
  • (modified) flang/lib/Semantics/resolve-labels.cpp (+19-9)
  • (modified) flang/lib/Semantics/resolve-names-utils.cpp (+13-15)
  • (modified) flang/lib/Semantics/resolve-names.cpp (+154-151)
  • (modified) flang/lib/Semantics/semantics.cpp (+22-19)
diff --git a/flang/include/flang/Common/Fortran-features.h b/flang/include/flang/Common/Fortran-features.h
index 86c6e02b0f2ffd..f813cbae40a57e 100644
--- a/flang/include/flang/Common/Fortran-features.h
+++ b/flang/include/flang/Common/Fortran-features.h
@@ -12,6 +12,7 @@
 #include "flang/Common/Fortran.h"
 #include "flang/Common/enum-set.h"
 #include "flang/Common/idioms.h"
+#include <optional>
 #include <vector>
 
 namespace Fortran::common {
@@ -48,7 +49,7 @@ ENUM_CLASS(LanguageFeature, BackslashEscapes, OldDebugLines,
     ImpliedDoIndexScope, DistinctCommonSizes, OddIndexVariableRestrictions,
     IndistinguishableSpecifics, SubroutineAndFunctionSpecifics,
     EmptySequenceType, NonSequenceCrayPointee, BranchIntoConstruct,
-    BadBranchTarget, ConvertedArgument, HollerithPolymorphic, ListDirectedSize,
+    BadBranchTarget, HollerithPolymorphic, ListDirectedSize,
     NonBindCInteroperability, CudaManaged, CudaUnified,
     PolymorphicActualAllocatableOrPointerToMonomorphicDummy, RelaxedPureDummy,
     UndefinableAsynchronousOrVolatileActual, AutomaticInMainProgram, PrintCptr,
@@ -76,80 +77,12 @@ 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() {
-    // 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::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);
-    // 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::ConvertedArgument);
-    warnLanguage_.set(LanguageFeature::HollerithPolymorphic);
-    warnLanguage_.set(LanguageFeature::ListDirectedSize);
-    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);
-    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::ModuleFile);
-    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::BadTypeForTarget);
-    warnUsage_.set(UsageWarning::VectorSubscriptFinalization);
-    warnUsage_.set(UsageWarning::UndefinedFunctionResult);
-    warnUsage_.set(UsageWarning::UselessIomsg);
-    // New warnings, on by default
-    warnLanguage_.set(LanguageFeature::SavedLocalInSpecExpr);
-  }
+  LanguageFeatureControl();
   LanguageFeatureControl(const LanguageFeatureControl &) = default;
 
   void Enable(LanguageFeature f, bool yes = true) { disable_.set(f, !yes); }
diff --git a/flang/include/flang/Parser/message.h b/flang/include/flang/Parser/message.h
index 668559aeec9478..bc38f571ca3df4 100644
--- a/flang/include/flang/Parser/message.h
+++ b/flang/include/flang/Parser/message.h
@@ -15,6 +15,7 @@
 #include "char-block.h"
 #include "char-set.h"
 #include "provenance.h"
+#include "flang/Common/Fortran-features.h"
 #include "flang/Common/idioms.h"
 #include "flang/Common/reference-counted.h"
 #include "flang/Common/restorer.h"
@@ -202,6 +203,26 @@ class Message : public common::ReferenceCounted<Message> {
   Message(ProvenanceRange pr, const MessageExpectedText &t)
       : location_{pr}, text_{t} {}
 
+  Message(common::LanguageFeature feature, ProvenanceRange pr,
+      const MessageFixedText &t)
+      : location_{pr}, text_{t}, languageFeature_{feature} {}
+  Message(common::LanguageFeature feature, ProvenanceRange pr,
+      const MessageFormattedText &s)
+      : location_{pr}, text_{s}, languageFeature_{feature} {}
+  Message(common::LanguageFeature feature, ProvenanceRange pr,
+      MessageFormattedText &&s)
+      : location_{pr}, text_{std::move(s)}, languageFeature_{feature} {}
+
+  Message(common::UsageWarning warning, ProvenanceRange pr,
+      const MessageFixedText &t)
+      : location_{pr}, text_{t}, usageWarning_{warning} {}
+  Message(common::UsageWarning warning, ProvenanceRange pr,
+      const MessageFormattedText &s)
+      : location_{pr}, text_{s}, usageWarning_{warning} {}
+  Message(common::UsageWarning warning, ProvenanceRange pr,
+      MessageFormattedText &&s)
+      : location_{pr}, text_{std::move(s)}, usageWarning_{warning} {}
+
   Message(CharBlock csr, const MessageFixedText &t)
       : location_{csr}, text_{t} {}
   Message(CharBlock csr, const MessageFormattedText &s)
@@ -211,10 +232,41 @@ class Message : public common::ReferenceCounted<Message> {
   Message(CharBlock csr, const MessageExpectedText &t)
       : location_{csr}, text_{t} {}
 
+  Message(
+      common::LanguageFeature feature, CharBlock csr, const MessageFixedText &t)
+      : location_{csr}, text_{t}, languageFeature_{feature} {}
+  Message(common::LanguageFeature feature, CharBlock csr,
+      const MessageFormattedText &s)
+      : location_{csr}, text_{s}, languageFeature_{feature} {}
+  Message(
+      common::LanguageFeature feature, CharBlock csr, MessageFormattedText &&s)
+      : location_{csr}, text_{std::move(s)}, languageFeature_{feature} {}
+
+  Message(
+      common::UsageWarning warning, CharBlock csr, const MessageFixedText &t)
+      : location_{csr}, text_{t}, usageWarning_{warning} {}
+  Message(common::UsageWarning warning, CharBlock csr,
+      const MessageFormattedText &s)
+      : location_{csr}, text_{s}, usageWarning_{warning} {}
+  Message(common::UsageWarning warning, CharBlock csr, MessageFormattedText &&s)
+      : location_{csr}, text_{std::move(s)}, usageWarning_{warning} {}
+
   template <typename RANGE, typename A, typename... As>
   Message(RANGE r, const MessageFixedText &t, A &&x, As &&...xs)
       : location_{r}, text_{MessageFormattedText{
                           t, std::forward<A>(x), std::forward<As>(xs)...}} {}
+  template <typename RANGE, typename A, typename... As>
+  Message(common::LanguageFeature feature, RANGE r, const MessageFixedText &t,
+      A &&x, As &&...xs)
+      : location_{r}, text_{MessageFormattedText{
+                          t, std::forward<A>(x), std::forward<As>(xs)...}},
+        languageFeature_{feature} {}
+  template <typename RANGE, typename A, typename... As>
+  Message(common::UsageWarning warning, RANGE r, const MessageFixedText &t,
+      A &&x, As &&...xs)
+      : location_{r}, text_{MessageFormattedText{
+                          t, std::forward<A>(x), std::forward<As>(xs)...}},
+        usageWarning_{warning} {}
 
   Reference attachment() const { return attachment_; }
 
@@ -232,6 +284,10 @@ class Message : public common::ReferenceCounted<Message> {
   bool IsFatal() const;
   Severity severity() const;
   Message &set_severity(Severity);
+  std::optional<common::LanguageFeature> languageFeature() const;
+  Message &set_languageFeature(common::LanguageFeature);
+  std::optional<common::UsageWarning> usageWarning() const;
+  Message &set_usageWarning(common::UsageWarning);
   std::string ToString() const;
   std::optional<ProvenanceRange> GetProvenanceRange(
       const AllCookedSources &) const;
@@ -256,6 +312,8 @@ class Message : public common::ReferenceCounted<Message> {
       text_;
   bool attachmentIsContext_{false};
   Reference attachment_;
+  std::optional<common::LanguageFeature> languageFeature_;
+  std::optional<common::UsageWarning> usageWarning_;
 };
 
 class Messages {
@@ -275,6 +333,16 @@ class Messages {
     return messages_.emplace_back(std::forward<A>(args)...);
   }
 
+  template <typename... A>
+  Message &Say(common::LanguageFeature feature, A &&...args) {
+    return Say(std::forward<A>(args)...).set_languageFeature(feature);
+  }
+
+  template <typename... A>
+  Message &Say(common::UsageWarning warning, A &&...args) {
+    return Say(std::forward<A>(args)...).set_usageWarning(warning);
+  }
+
   void Annex(Messages &&that) {
     messages_.splice(messages_.end(), that.messages_);
   }
@@ -330,6 +398,10 @@ class ContextualMessages {
     return common::ScopedSet(messages_, nullptr);
   }
 
+  template <typename... A> Message *Say(A &&...args) {
+    return Say(at_, std::forward<A>(args)...);
+  }
+
   template <typename... A> Message *Say(CharBlock at, A &&...args) {
     if (messages_ != nullptr) {
       auto &msg{messages_->Say(at, std::forward<A>(args)...)};
@@ -347,8 +419,22 @@ class ContextualMessages {
     return Say(at.value_or(at_), std::forward<A>(args)...);
   }
 
-  template <typename... A> Message *Say(A &&...args) {
-    return Say(at_, std::forward<A>(args)...);
+  template <typename... A>
+  Message *Say(common::LanguageFeature feature, A &&...args) {
+    Message *msg{Say(std::forward<A>(args)...)};
+    if (msg) {
+      msg->set_languageFeature(feature);
+    }
+    return msg;
+  }
+
+  template <typename... A>
+  Message *Say(common::UsageWarning warning, A &&...args) {
+    Message *msg{Say(std::forward<A>(args)...)};
+    if (msg) {
+      msg->set_usageWarning(warning);
+    }
+    return msg;
   }
 
   Message *Say(Message &&msg) {
diff --git a/flang/include/flang/Semantics/expression.h b/flang/include/flang/Semantics/expression.h
index c90c8c4b3cc70f..a90801db7338cc 100644
--- a/flang/include/flang/Semantics/expression.h
+++ b/flang/include/flang/Semantics/expression.h
@@ -123,6 +123,16 @@ class ExpressionAnalyzer {
   template <typename... A> parser::Message *Say(A &&...args) {
     return GetContextualMessages().Say(std::forward<A>(args)...);
   }
+  template <typename FeatureOrUsageWarning, typename... A>
+  parser::Message *Warn(
+      FeatureOrUsageWarning warning, parser::CharBlock at, A &&...args) {
+    return context_.Warn(warning, at, std::forward<A>(args)...);
+  }
+  template <typename FeatureOrUsageWarning, typename... A>
+  parser::Message *Warn(FeatureOrUsageWarning warning, A &&...args) {
+    return Warn(
+        warning, GetContextualMessages().at(), std::forward<A>(args)...);
+  }
 
   template <typename T, typename... A>
   parser::Message *SayAt(const T &parsed, A &&...args) {
diff --git a/flang/include/flang/Semantics/semantics.h b/flang/include/flang/Semantics/semantics.h
index e73f9d2e85d589..a9b9e9f3031b57 100644
--- a/flang/include/flang/Semantics/semantics.h
+++ b/flang/include/flang/Semantics/semantics.h
@@ -185,6 +185,24 @@ class SemanticsContext {
     return message;
   }
 
+  template <typename FeatureOrUsageWarning, typename... A>
+  parser::Message *Warn(
+      FeatureOrUsageWarning warning, parser::CharBlock at, A &&...args) {
+    if (languageFeatures_.ShouldWarn(warning) && !IsInModuleFile(at)) {
+      parser::Message &msg{
+          messages_.Say(warning, at, std::forward<A>(args)...)};
+      return &msg;
+    } else {
+      return nullptr;
+    }
+  }
+
+  template <typename FeatureOrUsageWarning, typename... A>
+  parser::Message *Warn(FeatureOrUsageWarning warning, A &&...args) {
+    CHECK(location_);
+    return Warn(warning, *location_, std::forward<A>(args)...);
+  }
+
   const Scope &FindScope(parser::CharBlock) const;
   Scope &FindScope(parser::CharBlock);
   void UpdateScopeIndex(Scope &, parser::CharBlock);
@@ -267,7 +285,7 @@ class SemanticsContext {
       std::multimap<parser::CharBlock, Scope &, ScopeIndexComparator>;
   ScopeIndex::iterator SearchScopeIndex(parser::CharBlock);
 
-  void CheckIndexVarRedefine(
+  parser::Message *CheckIndexVarRedefine(
       const parser::CharBlock &, const Symbol &, parser::MessageFixedText &&);
   void CheckError(const Symbol &);
 
diff --git a/flang/lib/Common/Fortran-features.cpp b/flang/lib/Common/Fortran-features.cpp
index 25a948818e6560..8f2a96095ab853 100644
--- a/flang/lib/Common/Fortran-features.cpp
+++ b/flang/lib/Common/Fortran-features.cpp
@@ -9,9 +9,103 @@
 #include "flang/Common/Fortran-features.h"
 #include "flang/Common/Fortran.h"
 #include "flang/Common/idioms.h"
+#include <strings.h>
 
 namespace Fortran::common {
 
+LanguageFeatureControl::LanguageFeatureControl() {
+  // 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::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);
+  // 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);
+  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);
+  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::ModuleFile);
+  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::BadTypeForTarget);
+  warnUsage_.set(UsageWarning::VectorSubscriptFinalization);
+  warnUsage_.set(UsageWarning::UndefinedFunctionResult);
+  warnUsage_.set(UsageWarning::UselessIomsg);
+  // New warnings, on by default
+  warnLanguage_.set(LanguageFeature::SavedLocalInSpecExpr);
+}
+
+template <typename ENUM, std::size_t N>
+std::optional<ENUM> ScanEnum(const char *name) {
+  if (name) {
+    for (std::size_t j{0}; j < N; ++j) {
+      auto feature{static_cast<ENUM>(j)};
+      if (::strcasecmp(name, EnumToString(feature).data()) == 0) {
+        return feature;
+      }
+    }
+  }
+  return std::nullopt;
+}
+
+std::optional<LanguageFeature> FindLanguageFeature(const char *name) {
+  return ScanEnum<LanguageFeature, LanguageFeature_enumSize>(name);
+}
+
+std::optional<UsageWarning> FindUsageWarning(const char *name) {
+  return ScanEnum<UsageWarning, UsageWarning_enumSize>(name);
+}
+
 std::vector<const char *> LanguageFeatureControl::GetNames(
     LogicalOperator opr) const {
   std::vector<const char *> result;
diff --git a/flang/lib/Evaluate/check-expression.cpp b/flang/lib/Evaluate/check-expression.cpp
index a1ede7d7553bf6..38794a2d8aacc7 100644
--- a/flang/lib/Evaluate/check-expression.cpp
+++ b/flang/lib/Evaluate/check-expression.cpp
@@ -412,6 +412,7 @@ std::optional<Expr<SomeType>> NonPointerInitializationExpr(const Symbol &symbol,
           symbol.owner().context().ShouldWarn(
               common::LanguageFeature::LogicalIntegerAssignment)) {
         context.messages().Say(
+            common::LanguageFeature::LogicalIntegerAssignment,
             "nonstandard usage: initialization of %s with %s"_port_en_US,
             symTS->type().AsFortran(), x.GetType().value().AsFortran());
       }
@@ -565,7 +566,7 @@ class CheckSpecificationExprHelper
       if (!scope_.IsModuleFile() &&
           context_.languageFeatures().ShouldWarn(
               common::LanguageFeature::SavedLocalInSpecExpr)) {
-        context_.messages().Say(
+        context_.messages().Say(common::LanguageFeature::SavedLocalInSpecExpr,
             "specification expression refers to local object '%s' (initialized and saved)"_port_en_US,
             ultimate.name().ToString());
       }
@@ -1102,44 +1103,53 @@ class StmtFunctionChecker
 public:
   using Result = std::optional<parser::Me...
[truncated]

@klausler klausler force-pushed the warning-names branch 2 times, most recently from 7d407f5 to 7383943 Compare September 27, 2024 17:46
Copy link
Contributor

@clementval clementval left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great! Thanks Peter.

Copy link
Contributor

@jeanPerier jeanPerier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, looks great!

@@ -565,7 +566,7 @@ class CheckSpecificationExprHelper
if (!scope_.IsModuleFile() &&
context_.languageFeatures().ShouldWarn(
common::LanguageFeature::SavedLocalInSpecExpr)) {
context_.messages().Say(
context_.messages().Say(common::LanguageFeature::SavedLocalInSpecExpr,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it too soon to use Warn here and folding, or is it a matter of going through them again and updating them?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warn() is in Semantics and can't be used in Evaluate.

@klausler klausler force-pushed the warning-names branch 2 times, most recently from f8650db to a14f7c8 Compare October 1, 2024 18:19
@banach-space
Copy link
Contributor

It's a great addition to Flang, thank you!

I'm not really qualified to review this, but I do support this kind of development.

Hooks for a driver to use to map the name of a feature or warning to its enumerator were also added.

How about integrating this with the driver so that we can see how this works in practice?

@klausler
Copy link
Contributor Author

klausler commented Oct 1, 2024

It's a great addition to Flang, thank you!

I'm not really qualified to review this, but I do support this kind of development.

Hooks for a driver to use to map the name of a feature or warning to its enumerator were also added.

How about integrating this with the driver so that we can see how this works in practice?

That'll come next. This patch was already too large, and adds the infrastructure that will be needed for any driver work later, however that looks. And that's going to be complicated.

(This is a big patch, but it's nearly an NFC.
No test results have changed and all Fortran tests in the
LLVM test suites work as expected.)

Allow a parser::Message for a warning to be marked with the
common::LanguageFeature or common::UsageWarning that controls
it.  This will allow a later patch to add hooks whereby a driver
will be able to decorate warning messages with the names of its
options that enable each particular warning, and to add hooks
whereby a driver can map those enumerators by name to command-line
options that enable/disable the language feature and enable/disable
the messages.

The default settings in the constructor for LanguageFeatureControl
were moved from its header file into its C++ source file.

Hooks for a driver to use to map the name of a feature or warning
to its enumerator were also added.

To simplify the tagging of warnings with their corresponding
language feature or usage warning, to ensure that they are properly
controlled by ShouldWarn(), and to ensure that warnings never issue
at code sites in module files, two new Warn() member function templates
were added to SemanticsContext and other contextual frameworks.
Warn() can't be used before source locations can be mapped to scopes,
but the bulk of existing code blocks testing ShouldWarn() and
FindModuleFile() before calling Say() were convertible into calls to
Warn().  The ones that were not convertible were extended with explicit
calls to Message::set_languageFeature() and set_usageWarning().
@klausler klausler merged commit 0f973ac into llvm:main Oct 2, 2024
8 checks passed
@klausler klausler deleted the warning-names branch October 2, 2024 15:54
Sterling-Augustine pushed a commit to Sterling-Augustine/llvm-project that referenced this pull request Oct 3, 2024
(This is a big patch, but it's nearly an NFC. No test results have
changed and all Fortran tests in the LLVM test suites work as expected.)

Allow a parser::Message for a warning to be marked with the
common::LanguageFeature or common::UsageWarning that controls it. This
will allow a later patch to add hooks whereby a driver will be able to
decorate warning messages with the names of its options that enable each
particular warning, and to add hooks whereby a driver can map those
enumerators by name to command-line options that enable/disable the
language feature and enable/disable the messages.

The default settings in the constructor for LanguageFeatureControl were
moved from its header file into its C++ source file.

Hooks for a driver to use to map the name of a feature or warning to its
enumerator were also added.

To simplify the tagging of warnings with their corresponding language
feature or usage warning, to ensure that they are properly controlled by
ShouldWarn(), and to ensure that warnings never issue at code sites in
module files, two new Warn() member function templates were added to
SemanticsContext and other contextual frameworks. Warn() can't be used
before source locations can be mapped to scopes, but the bulk of
existing code blocks testing ShouldWarn() and FindModuleFile() before
calling Say() were convertible into calls to Warn(). The ones that were
not convertible were extended with explicit calls to
Message::set_languageFeature() and set_usageWarning().
@kawashima-fj
Copy link
Member

@klausler This commit moves the following program to an error from a warning. Is it intentional?

program main
  procedure(rfunc), pointer :: ptr
  ptr => null()
  if (associated(ptr, ifunc)) then
    print *, "bad"
  end if
  contains
  function ifunc(x)
    integer, intent(in) :: x
    integer :: ifunc
    ifunc = x
  end function
  function rfunc(x)
    real, intent(in) :: x
    real :: rfunc
    rfunc = x
  end function
end

Before this commit:

test.f90:4:7: warning: Function pointer 'ptr' associated with incompatible function designator 'ifunc': function results have distinct types: REAL(4) vs INTEGER(4)
    if (associated(ptr, ifunc)) then
        ^^^^^^^^^^^^^^^^^^^^^^

After this commit:

error: Semantic errors in test.f90
test.f90:4:7: error: Function pointer 'ptr' associated with incompatible function designator 'ifunc': function results have distinct types: REAL(4) vs INTEGER(4)
    if (associated(ptr, ifunc)) then
        ^^^^^^^^^^^^^^^^^^^^^^

(This is just a confirmation. No objection to making it an error.)

@klausler
Copy link
Contributor Author

klausler commented Oct 8, 2024

Yes, an error is appropriate, and many other Fortran compilers emit one for this case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang:openmp flang:parser flang:semantics flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants