[flang] Get ProvenanceRange from CharBlock starting with expanded macro (#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.
This commit is contained in:
jeanPerier 2024-01-12 13:04:50 +01:00 committed by GitHub
parent a762cc2155
commit c87e94b030
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 52 additions and 2 deletions

View File

@ -161,6 +161,10 @@ public:
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 @@ private:
// 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 @@ public:
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

View File

@ -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<Macro>(origin.u)) {
return origin.replaces.start();
}
return provenance;
}
std::optional<ProvenanceRange> CookedSource::GetProvenanceRange(
CharBlock cookedRange) const {
if (!AsCharBlock().Contains(cookedRange)) {
@ -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;
}
}
}
@ -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 {

View File

@ -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)

View File

@ -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