[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:53:05 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-semantics

@llvm/pr-subscribers-flang-fir-hlfir

Author: None (jeanPerier)

<details>
<summary>Changes</summary>

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.

---
Full diff: https://github.com/llvm/llvm-project/pull/77791.diff


5 Files Affected:

- (modified) flang/include/flang/Parser/provenance.h (+6-1) 
- (modified) flang/lib/Parser/parsing.cpp (+2-1) 
- (modified) flang/lib/Parser/provenance.cpp (+20-3) 
- (modified) flang/test/Lower/macro-debug-file-loc.f90 (+14) 
- (added) flang/test/Semantics/assign15.f90 (+12) 


``````````diff
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

``````````

</details>


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


More information about the flang-commits mailing list