[flang-commits] [flang] [flang] Get ProvenanceRange from CharBlock starting with expanded macro (PR #77791)

via flang-commits flang-commits at lists.llvm.org
Thu Jan 11 07:52:37 PST 2024


https://github.com/jeanPerier created https://github.com/llvm/llvm-project/pull/77791

When a CharBlock starts with an expanded macro but does not end in this macro expansion, GetProvenanceRange fails to return a ProvenanceRange which may cause error message to be emitted without location or lowering to emit code without source location (which is problematic if this code contains calls to procedures defined in the same file since LLVM will later crash with the error:
"inlinable function call in a function with a DISubprogram location must have a debug location"

Fix this situation by returning the ProvenanceRange starting at the replaced macro reference.

>From 05ef02004b919745b6581dca34bc9c98495e33c7 Mon Sep 17 00:00:00 2001
From: Jean Perier <jperier at nvidia.com>
Date: Thu, 11 Jan 2024 07:45:49 -0800
Subject: [PATCH] [flang] Get ProvenanceRange from CharBlock starting with
 expanded macro

When a CharBlock starts with an expanded macro but does not end in this
macro expansion, GetProvenanceRange fails to return a ProvenanceRange
which may cause error message to be emitted without location or lowering
to emit code without source location (which is problematic if this code
contains calls to procedures defined in the same file since LLVM will
later crash with the error:
"inlinable function call in a function with a DISubprogram location must
have a debug location"

Fix this situation by returning the ProvenanceRange starting at the
replaced macro reference.
---
 flang/include/flang/Parser/provenance.h   |  7 ++++++-
 flang/lib/Parser/parsing.cpp              |  3 ++-
 flang/lib/Parser/provenance.cpp           | 23 ++++++++++++++++++++---
 flang/test/Lower/macro-debug-file-loc.f90 | 14 ++++++++++++++
 flang/test/Semantics/assign15.f90         | 12 ++++++++++++
 5 files changed, 54 insertions(+), 5 deletions(-)
 create mode 100644 flang/test/Semantics/assign15.f90

diff --git a/flang/include/flang/Parser/provenance.h b/flang/include/flang/Parser/provenance.h
index 807718b1f7c35f..7f3a31cac12482 100644
--- a/flang/include/flang/Parser/provenance.h
+++ b/flang/include/flang/Parser/provenance.h
@@ -161,6 +161,10 @@ class AllSources {
       ProvenanceRange def, ProvenanceRange use, const std::string &expansion);
   ProvenanceRange AddCompilerInsertion(std::string);
 
+  // If provenance is in an expanded macro, return the starting provenance of
+  // the replaced macro. Otherwise, return the input provenance.
+  Provenance GetReplacedProvenance(Provenance) const;
+
   bool IsValid(Provenance at) const { return range_.Contains(at); }
   bool IsValid(ProvenanceRange range) const {
     return range.size() > 0 && range_.Contains(range);
@@ -229,7 +233,8 @@ class CookedSource {
   void set_number(int n) { number_ = n; }
 
   CharBlock AsCharBlock() const { return CharBlock{data_}; }
-  std::optional<ProvenanceRange> GetProvenanceRange(CharBlock) const;
+  std::optional<ProvenanceRange> GetProvenanceRange(
+      CharBlock, const AllSources &) const;
   std::optional<CharBlock> GetCharBlock(ProvenanceRange) const;
 
   // The result of a Put() is the offset that the new data
diff --git a/flang/lib/Parser/parsing.cpp b/flang/lib/Parser/parsing.cpp
index a55d33bf6b91d6..23d19eb8356eda 100644
--- a/flang/lib/Parser/parsing.cpp
+++ b/flang/lib/Parser/parsing.cpp
@@ -132,7 +132,8 @@ void Parsing::EmitPreprocessedSource(
       ++sourceLine;
       directive.clear();
     } else {
-      auto provenance{cooked().GetProvenanceRange(CharBlock{&atChar, 1})};
+      auto provenance{
+          cooked().GetProvenanceRange(CharBlock{&atChar, 1}, allSources)};
 
       // Preserves original case of the character
       const auto getOriginalChar{[&](char ch) {
diff --git a/flang/lib/Parser/provenance.cpp b/flang/lib/Parser/provenance.cpp
index b29bc4d1e6a6c1..df69d65e752f11 100644
--- a/flang/lib/Parser/provenance.cpp
+++ b/flang/lib/Parser/provenance.cpp
@@ -452,8 +452,16 @@ const AllSources::Origin &AllSources::MapToOrigin(Provenance at) const {
   return origin_[low];
 }
 
+Provenance AllSources::GetReplacedProvenance(Provenance provenance) const {
+  const Origin &origin{MapToOrigin(provenance)};
+  if (std::holds_alternative<Macro>(origin.u)) {
+    return origin.replaces.start();
+  }
+  return provenance;
+}
+
 std::optional<ProvenanceRange> CookedSource::GetProvenanceRange(
-    CharBlock cookedRange) const {
+    CharBlock cookedRange, const AllSources &allSources) const {
   if (!AsCharBlock().Contains(cookedRange)) {
     return std::nullopt;
   }
@@ -465,7 +473,16 @@ std::optional<ProvenanceRange> CookedSource::GetProvenanceRange(
   if (first.start() <= last.start()) {
     return {ProvenanceRange{first.start(), last.start() - first.start() + 1}};
   } else {
-    return std::nullopt;
+    // cookedRange may start (resp. end) in a macro expansion while it does not
+    // end (resp. start) in this macro expansion. Attempt to build a range
+    // over the replaced source.
+    Provenance firstStart = allSources.GetReplacedProvenance(first.start());
+    Provenance lastStart = allSources.GetReplacedProvenance(last.start());
+    if (firstStart <= lastStart) {
+      return {ProvenanceRange{firstStart, lastStart - firstStart + 1}};
+    } else {
+      return std::nullopt;
+    }
   }
 }
 
@@ -594,7 +611,7 @@ const CookedSource *AllCookedSources::Find(CharBlock x) const {
 std::optional<ProvenanceRange> AllCookedSources::GetProvenanceRange(
     CharBlock cb) const {
   if (const CookedSource * c{Find(cb)}) {
-    return c->GetProvenanceRange(cb);
+    return c->GetProvenanceRange(cb, allSources());
   } else {
     return std::nullopt;
   }
diff --git a/flang/test/Lower/macro-debug-file-loc.f90 b/flang/test/Lower/macro-debug-file-loc.f90
index a47c9aae178530..5e5665442d49a2 100644
--- a/flang/test/Lower/macro-debug-file-loc.f90
+++ b/flang/test/Lower/macro-debug-file-loc.f90
@@ -10,4 +10,18 @@ subroutine test()
   ! CHECK: fir.call @_QPfoo() fastmath<contract> : () -> () loc(#[[CALL_LOC:.*]])
   call CMD(foo)
 end subroutine
+
+#define IVAR i
+
+integer function ifoo()
+  ifoo = 0
+end function
+
+subroutine test2()
+  integer :: i
+  ! CHECK: fir.call @_QPifoo(){{.*}} loc(#[[IFOO_CALL_LOC:.*]])
+  IVAR = ifoo()
+end subroutine
+
 ! CHECK: #[[CALL_LOC]] = loc("{{.*}}macro-debug-file-loc.f90":11:3)
+! CHECK: #[[IFOO_CALL_LOC]] = loc("{{.*}}macro-debug-file-loc.f90":23:3)
diff --git a/flang/test/Semantics/assign15.f90 b/flang/test/Semantics/assign15.f90
new file mode 100644
index 00000000000000..7df096c5b22e76
--- /dev/null
+++ b/flang/test/Semantics/assign15.f90
@@ -0,0 +1,12 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1
+! Test error location when assignment starts with macro expansion.
+
+#define X_VAR x
+program main
+  real(4) :: x
+  character(10) :: c
+  !ERROR: No intrinsic or user-defined ASSIGNMENT(=) matches operand types REAL(4) and CHARACTER(KIND=1)
+  X_VAR = c
+  !ERROR: No intrinsic or user-defined ASSIGNMENT(=) matches operand types CHARACTER(KIND=1) and REAL(4)
+  c = X_VAR
+end



More information about the flang-commits mailing list