[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 def, ProvenanceRange use, const std::string &expansion);
ProvenanceRange AddCompilerInsertion(std::string); 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(Provenance at) const { return range_.Contains(at); }
bool IsValid(ProvenanceRange range) const { bool IsValid(ProvenanceRange range) const {
return range.size() > 0 && range_.Contains(range); return range.size() > 0 && range_.Contains(range);
@ -225,6 +229,8 @@ private:
// single instances of CookedSource. // single instances of CookedSource.
class CookedSource { class CookedSource {
public: public:
explicit CookedSource(AllSources &allSources) : allSources_{allSources} {};
int number() const { return number_; } int number() const { return number_; }
void set_number(int n) { number_ = n; } void set_number(int n) { number_ = n; }
@ -256,6 +262,7 @@ public:
llvm::raw_ostream &Dump(llvm::raw_ostream &) const; llvm::raw_ostream &Dump(llvm::raw_ostream &) const;
private: private:
AllSources &allSources_;
int number_{0}; // for sorting purposes int number_{0}; // for sorting purposes
CharBuffer buffer_; // before Marshal() CharBuffer buffer_; // before Marshal()
std::string data_; // all of it, prescanned and preprocessed 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]; 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( std::optional<ProvenanceRange> CookedSource::GetProvenanceRange(
CharBlock cookedRange) const { CharBlock cookedRange) const {
if (!AsCharBlock().Contains(cookedRange)) { if (!AsCharBlock().Contains(cookedRange)) {
@ -465,7 +473,16 @@ std::optional<ProvenanceRange> CookedSource::GetProvenanceRange(
if (first.start() <= last.start()) { if (first.start() <= last.start()) {
return {ProvenanceRange{first.start(), last.start() - first.start() + 1}}; return {ProvenanceRange{first.start(), last.start() - first.start() + 1}};
} else { } 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() {} AllCookedSources::~AllCookedSources() {}
CookedSource &AllCookedSources::NewCookedSource() { CookedSource &AllCookedSources::NewCookedSource() {
return cooked_.emplace_back(); return cooked_.emplace_back(allSources_);
} }
const CookedSource *AllCookedSources::Find(CharBlock x) const { const CookedSource *AllCookedSources::Find(CharBlock x) const {

View File

@ -10,4 +10,18 @@ subroutine test()
! CHECK: fir.call @_QPfoo() fastmath<contract> : () -> () loc(#[[CALL_LOC:.*]]) ! CHECK: fir.call @_QPfoo() fastmath<contract> : () -> () loc(#[[CALL_LOC:.*]])
call CMD(foo) call CMD(foo)
end subroutine 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: #[[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