diff --git a/flang/include/flang/Parser/provenance.h b/flang/include/flang/Parser/provenance.h index 807718b1f7c35..a5a5211144285 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); @@ -225,6 +229,8 @@ class AllSources { // single instances of CookedSource. class CookedSource { public: + explicit CookedSource(AllSources &allSources) : allSources_{allSources} {}; + int number() const { return number_; } void set_number(int n) { number_ = n; } @@ -256,6 +262,7 @@ class CookedSource { llvm::raw_ostream &Dump(llvm::raw_ostream &) const; private: + AllSources &allSources_; int number_{0}; // for sorting purposes CharBuffer buffer_; // before Marshal() std::string data_; // all of it, prescanned and preprocessed diff --git a/flang/lib/Parser/provenance.cpp b/flang/lib/Parser/provenance.cpp index b29bc4d1e6a6c..3f185ffeb1b11 100644 --- a/flang/lib/Parser/provenance.cpp +++ b/flang/lib/Parser/provenance.cpp @@ -452,6 +452,14 @@ 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(origin.u)) { + return origin.replaces.start(); + } + return provenance; +} + std::optional CookedSource::GetProvenanceRange( CharBlock cookedRange) const { if (!AsCharBlock().Contains(cookedRange)) { @@ -465,7 +473,16 @@ std::optional 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; + } } } @@ -578,7 +595,7 @@ AllCookedSources::AllCookedSources(AllSources &s) : allSources_{s} {} AllCookedSources::~AllCookedSources() {} CookedSource &AllCookedSources::NewCookedSource() { - return cooked_.emplace_back(); + return cooked_.emplace_back(allSources_); } const CookedSource *AllCookedSources::Find(CharBlock x) const { diff --git a/flang/test/Lower/macro-debug-file-loc.f90 b/flang/test/Lower/macro-debug-file-loc.f90 index a47c9aae17853..5e5665442d49a 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 : () -> () 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 0000000000000..7df096c5b22e7 --- /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