[flang-commits] [flang] [flang][OpenMP] Allow "Reason" messages to not have source locations (PR #187555)

Krzysztof Parzyszek via flang-commits flang-commits at lists.llvm.org
Thu Mar 19 11:52:44 PDT 2026


https://github.com/kparzysz created https://github.com/llvm/llvm-project/pull/187555

When explanatory messages are generated there may be cases when there is no satisfactory source location to apply them to. This patch allows storing such messages without a source location.
The messages will be equipped with a source location at the time when they are attached to the main error message (usually it will be the same location as used for the main message).

Issue: https://github.com/llvm/llvm-project/issues/185287

>From 7d3379ca600347797a945feb6270963def5d5a5d Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Tue, 17 Mar 2026 13:08:46 -0500
Subject: [PATCH] [flang][OpenMP] Allow "Reason" messages to not have source
 locations

When explanatory messages are generated there may be cases when there
is no satisfactory source location to apply them to. This patch allows
storing such messages without a source location.
The messages will be equipped with a source location at the time when
they are attached to the main error message (usually it will be the
same location as used for the main message).

Issue: https://github.com/llvm/llvm-project/issues/185287
---
 flang/include/flang/Semantics/openmp-utils.h | 17 ++++++++++++++---
 flang/lib/Semantics/check-omp-loop.cpp       | 18 +++++++++---------
 flang/lib/Semantics/openmp-utils.cpp         | 16 ++++++++++++++--
 3 files changed, 37 insertions(+), 14 deletions(-)

diff --git a/flang/include/flang/Semantics/openmp-utils.h b/flang/include/flang/Semantics/openmp-utils.h
index d7f46cbc7bd62..66bbbeb4ee0e7 100644
--- a/flang/include/flang/Semantics/openmp-utils.h
+++ b/flang/include/flang/Semantics/openmp-utils.h
@@ -23,6 +23,7 @@
 #include "flang/Semantics/tools.h"
 
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseSet.h"
 
 #include <optional>
 #include <string>
@@ -116,12 +117,22 @@ MaybeExpr MakeEvaluateExpr(const parser::OmpStylizedInstance &inp);
 struct Reason {
   parser::Messages msgs;
 
-  template <typename... Ts> Reason &Say(Ts &&...args) {
-    msgs.Say(std::forward<Ts>(args)...);
+  // Allow messages without a source location. They will acquire a location
+  // during AttachTo.
+  template <typename... Ts>
+  Reason &Say(parser::CharBlock source, Ts &&...args) {
+    auto &msg{msgs.Say(source, std::forward<Ts>(args)...)};
+    if (source.empty()) {
+      unsourced_.insert(&msg);
+    }
     return *this;
   }
   operator bool() const { return !msgs.empty(); }
-  parser::Message &AttachTo(parser::Message &msg);
+  parser::Message &AttachTo(parser::CharBlock source, parser::Message &msg);
+
+private:
+  // Set of messages without a source location.
+  llvm::DenseSet<const parser::Message *> unsourced_;
 };
 
 std::pair<std::optional<int64_t>, Reason> GetArgumentValueWithReason(
diff --git a/flang/lib/Semantics/check-omp-loop.cpp b/flang/lib/Semantics/check-omp-loop.cpp
index 8f360daf4cfdc..f09b5f315dcc2 100644
--- a/flang/lib/Semantics/check-omp-loop.cpp
+++ b/flang/lib/Semantics/check-omp-loop.cpp
@@ -247,6 +247,7 @@ void OmpStructureChecker::CheckNestedConstruct(
   const parser::OmpDirectiveSpecification &beginSpec{x.BeginDir()};
   llvm::omp::Directive dir{beginSpec.DirId()};
   unsigned version{context_.langOptions().OpenMPVersion};
+  parser::CharBlock beginSource{beginSpec.DirName().source};
 
   // End-directive is not allowed in such cases:
   //   do 100 i = ...
@@ -257,7 +258,6 @@ void OmpStructureChecker::CheckNestedConstruct(
   auto &flags{std::get<parser::OmpDirectiveSpecification::Flags>(beginSpec.t)};
   if (flags.test(parser::OmpDirectiveSpecification::Flag::CrossesLabelDo)) {
     if (auto &endSpec{x.EndDir()}) {
-      parser::CharBlock beginSource{beginSpec.DirName().source};
       context_
           .Say(endSpec->DirName().source,
               "END %s directive is not allowed when the construct does not contain all loops that share a loop-terminating statement"_err_en_US,
@@ -297,12 +297,12 @@ void OmpStructureChecker::CheckNestedConstruct(
 
   if (std::optional<int64_t> numLoops{sequence.length()}) {
     if (*numLoops == 0) {
-      context_.Say(beginSpec.DirName().source,
+      context_.Say(beginSource,
           "This construct should contain a DO-loop or a loop-nest-generating OpenMP construct"_err_en_US);
     } else {
       auto assoc{llvm::omp::getDirectiveAssociation(dir)};
       if (*numLoops > 1 && assoc == llvm::omp::Association::LoopNest) {
-        context_.Say(beginSpec.DirName().source,
+        context_.Say(beginSource,
             "This construct applies to a loop nest, but has a loop sequence of "
             "length %" PRId64 ""_err_en_US,
             *numLoops);
@@ -310,12 +310,12 @@ void OmpStructureChecker::CheckNestedConstruct(
       if (assoc == llvm::omp::Association::LoopSeq) {
         if (auto requiredCount{GetRequiredCount(needFirst, needCount)}) {
           if (*requiredCount > 0 && *numLoops < *requiredCount) {
-            auto &msg{context_.Say(beginSpec.DirName().source,
+            auto &msg{context_.Say(beginSource,
                 "This construct requires a sequence of %" PRId64
                 " loops, but the loop sequence has a length of %" PRId64
                 ""_err_en_US,
                 *requiredCount, *numLoops)};
-            rangeReason.AttachTo(msg);
+            rangeReason.AttachTo(beginSource, msg);
           }
         }
       }
@@ -334,18 +334,18 @@ void OmpStructureChecker::CheckNestedConstruct(
     if (needDepth && haveDepth && *haveDepth > 0) {
       if (*needDepth > *haveDepth) {
         if (needPerfect) {
-          auto &msg{context_.Say(beginSpec.DirName().source,
+          auto &msg{context_.Say(beginSource,
               "This construct requires a perfect nest of depth %" PRId64
               ", but the associated nest is a perfect nest of depth %" PRId64
               ""_err_en_US,
               *needDepth, *haveDepth)};
-          depthReason.AttachTo(msg);
+          depthReason.AttachTo(beginSource, msg);
         } else {
-          auto &msg{context_.Say(beginSpec.DirName().source,
+          auto &msg{context_.Say(beginSource,
               "This construct requires a nest of depth %" PRId64
               ", but the associated nest has a depth of %" PRId64 ""_err_en_US,
               *needDepth, *haveDepth)};
-          depthReason.AttachTo(msg);
+          depthReason.AttachTo(beginSource, msg);
         }
       }
     }
diff --git a/flang/lib/Semantics/openmp-utils.cpp b/flang/lib/Semantics/openmp-utils.cpp
index e104096cb3af1..116d04cf93968 100644
--- a/flang/lib/Semantics/openmp-utils.cpp
+++ b/flang/lib/Semantics/openmp-utils.cpp
@@ -532,8 +532,20 @@ MaybeExpr MakeEvaluateExpr(const parser::OmpStylizedInstance &inp) {
       instance.u);
 }
 
-parser::Message &Reason::AttachTo(parser::Message &msg) {
-  msgs.AttachTo(msg);
+parser::Message &Reason::AttachTo(
+    parser::CharBlock source, parser::Message &msg) {
+  parser::Messages sourced;
+  for (auto &&msg : msgs.messages()) {
+    if (unsourced_.contains(&msg)) {
+      llvm::StringRef fmt{"%s"};
+      sourced.Say(source,
+          parser::MessageFixedText(fmt.data(), fmt.size(), msg.severity()),
+          msg.ToString());
+    } else {
+      sourced.Say(std::move(msg));
+    }
+  }
+  sourced.AttachTo(msg);
   return msg;
 }
 



More information about the flang-commits mailing list