forked from OSchip/llvm-project
[flang] Merge use-associated generics
When the same generic is use-associated from two different modules, they must be merged together into a symbol with GenericDetails. After that merger, if there is a use association of the same name with a non-generic we have to report an error. So save the UseDetails from the original USE in GenericDetails so we can create the appropriate UseErrorDetails. Fixes flang-compiler/f18#586. Original-commit: flang-compiler/f18@5067345f70 Reviewed-on: https://github.com/flang-compiler/f18/pull/591
This commit is contained in:
parent
7d8a0733c3
commit
64a8b9b3d3
|
@ -1931,27 +1931,61 @@ ModuleVisitor::SymbolRename ModuleVisitor::AddUse(
|
|||
return {&localSymbol, useSymbol};
|
||||
}
|
||||
|
||||
// symbol must be either a Use or a Generic formed by merging two uses.
|
||||
// Convert it to a UseError with this additional location.
|
||||
static void ConvertToUseError(
|
||||
Symbol &symbol, const SourceName &location, const Scope &module) {
|
||||
const auto *useDetails{symbol.detailsIf<UseDetails>()};
|
||||
if (!useDetails) {
|
||||
auto &genericDetails{symbol.get<GenericDetails>()};
|
||||
useDetails = &genericDetails.useDetails().value();
|
||||
}
|
||||
symbol.set_details(
|
||||
UseErrorDetails{*useDetails}.add_occurrence(location, module));
|
||||
}
|
||||
|
||||
void ModuleVisitor::AddUse(
|
||||
const SourceName &location, Symbol &localSymbol, const Symbol &useSymbol) {
|
||||
localSymbol.attrs() = useSymbol.attrs();
|
||||
localSymbol.attrs() &= ~Attrs{Attr::PUBLIC, Attr::PRIVATE};
|
||||
localSymbol.flags() = useSymbol.flags();
|
||||
if (auto *details{localSymbol.detailsIf<UseDetails>()}) {
|
||||
// check for use-associating the same symbol again:
|
||||
if (localSymbol.GetUltimate() != useSymbol.GetUltimate()) {
|
||||
localSymbol.set_details(
|
||||
UseErrorDetails{*details}.add_occurrence(location, *useModuleScope_));
|
||||
if (auto *useDetails{localSymbol.detailsIf<UseDetails>()}) {
|
||||
const Symbol &ultimate{localSymbol.GetUltimate()};
|
||||
if (ultimate == useSymbol.GetUltimate()) {
|
||||
// use-associating the same symbol again -- ok
|
||||
} else if (ultimate.has<GenericDetails>() &&
|
||||
useSymbol.has<GenericDetails>()) {
|
||||
// use-associating generics with the same names: merge them into a
|
||||
// new generic in this scope
|
||||
auto genericDetails{ultimate.get<GenericDetails>()};
|
||||
genericDetails.set_useDetails(*useDetails);
|
||||
genericDetails.AddSpecificProcsFrom(useSymbol);
|
||||
EraseSymbol(localSymbol);
|
||||
MakeSymbol(
|
||||
localSymbol.name(), ultimate.attrs(), std::move(genericDetails));
|
||||
} else {
|
||||
ConvertToUseError(localSymbol, location, *useModuleScope_);
|
||||
}
|
||||
} else if (auto *details{localSymbol.detailsIf<UseErrorDetails>()}) {
|
||||
details->add_occurrence(location, *useModuleScope_);
|
||||
} else if (!localSymbol.has<UnknownDetails>()) {
|
||||
Say(location,
|
||||
"Cannot use-associate '%s'; it is already declared in this scope"_err_en_US,
|
||||
localSymbol.name())
|
||||
.Attach(localSymbol.name(), "Previous declaration of '%s'"_en_US,
|
||||
localSymbol.name());
|
||||
} else {
|
||||
localSymbol.set_details(UseDetails{location, useSymbol});
|
||||
auto *genericDetails{localSymbol.detailsIf<GenericDetails>()};
|
||||
if (genericDetails && genericDetails->useDetails().has_value()) {
|
||||
// localSymbol came from merging two use-associated generics
|
||||
if (useSymbol.has<GenericDetails>()) {
|
||||
genericDetails->AddSpecificProcsFrom(useSymbol);
|
||||
} else {
|
||||
ConvertToUseError(localSymbol, location, *useModuleScope_);
|
||||
}
|
||||
} else if (auto *details{localSymbol.detailsIf<UseErrorDetails>()}) {
|
||||
details->add_occurrence(location, *useModuleScope_);
|
||||
} else if (!localSymbol.has<UnknownDetails>()) {
|
||||
Say(location,
|
||||
"Cannot use-associate '%s'; it is already declared in this scope"_err_en_US,
|
||||
localSymbol.name())
|
||||
.Attach(localSymbol.name(), "Previous declaration of '%s'"_en_US,
|
||||
localSymbol.name());
|
||||
} else {
|
||||
localSymbol.set_details(UseDetails{location, useSymbol});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -180,6 +180,11 @@ Symbol *GenericDetails::CheckSpecific() {
|
|||
}
|
||||
}
|
||||
|
||||
void GenericDetails::AddSpecificProcsFrom(const Symbol &generic) {
|
||||
const auto &procs{generic.get<GenericDetails>().specificProcs()};
|
||||
specificProcs_.insert(specificProcs_.end(), procs.begin(), procs.end());
|
||||
}
|
||||
|
||||
// The name of the kind of details for this symbol.
|
||||
// This is primarily for debugging.
|
||||
std::string DetailsToString(const Details &details) {
|
||||
|
|
|
@ -400,6 +400,7 @@ public:
|
|||
|
||||
const SymbolVector &specificProcs() const { return specificProcs_; }
|
||||
void add_specificProc(const Symbol &proc) { specificProcs_.push_back(&proc); }
|
||||
void AddSpecificProcsFrom(const Symbol &generic);
|
||||
|
||||
Symbol *specific() { return specific_; }
|
||||
const Symbol *specific() const { return specific_; }
|
||||
|
@ -415,6 +416,9 @@ public:
|
|||
const Symbol *CheckSpecific() const;
|
||||
Symbol *CheckSpecific();
|
||||
|
||||
const std::optional<UseDetails> &useDetails() const { return useDetails_; }
|
||||
void set_useDetails(const UseDetails &details) { useDetails_ = details; }
|
||||
|
||||
private:
|
||||
GenericKind kind_{GenericKind::Name};
|
||||
// all of the specific procedures for this generic
|
||||
|
@ -423,6 +427,9 @@ private:
|
|||
Symbol *specific_{nullptr};
|
||||
// a derived type with the same name as this generic, if any
|
||||
Symbol *derivedType_{nullptr};
|
||||
// If two USEs of generics were merged to form this one, this is the
|
||||
// UseDetails for one of them. Used for reporting USE errors.
|
||||
std::optional<UseDetails> useDetails_;
|
||||
};
|
||||
|
||||
class UnknownDetails {};
|
||||
|
|
|
@ -44,3 +44,135 @@ contains
|
|||
subroutine s2(x)
|
||||
end subroutine
|
||||
end module
|
||||
|
||||
module m4a
|
||||
interface g
|
||||
procedure s_real
|
||||
end interface
|
||||
contains
|
||||
subroutine s_real(x)
|
||||
end
|
||||
end
|
||||
module m4b
|
||||
interface g
|
||||
procedure s_int
|
||||
end interface
|
||||
contains
|
||||
subroutine s_int(i)
|
||||
end
|
||||
end
|
||||
! Generic g should merge the two use-associated ones
|
||||
subroutine s4
|
||||
use m4a
|
||||
use m4b
|
||||
call g(123)
|
||||
call g(1.2)
|
||||
end
|
||||
|
||||
module m5a
|
||||
interface g
|
||||
procedure s_real
|
||||
end interface
|
||||
contains
|
||||
subroutine s_real(x)
|
||||
end
|
||||
end
|
||||
module m5b
|
||||
interface gg
|
||||
procedure s_int
|
||||
end interface
|
||||
contains
|
||||
subroutine s_int(i)
|
||||
end
|
||||
end
|
||||
! Generic g should merge the two use-associated ones
|
||||
subroutine s5
|
||||
use m5a
|
||||
use m5b, g => gg
|
||||
call g(123)
|
||||
call g(1.2)
|
||||
end
|
||||
|
||||
module m6a
|
||||
interface gg
|
||||
procedure sa
|
||||
end interface
|
||||
contains
|
||||
subroutine sa(x)
|
||||
end
|
||||
end
|
||||
module m6b
|
||||
interface gg
|
||||
procedure sb
|
||||
end interface
|
||||
contains
|
||||
subroutine sb(y)
|
||||
end
|
||||
end
|
||||
subroutine s6
|
||||
!ERROR: Generic 'g' may not have specific procedures 'sa' and 'sb' as their interfaces are not distinguishable
|
||||
use m6a, g => gg
|
||||
use m6b, g => gg
|
||||
end
|
||||
|
||||
module m7a
|
||||
interface g
|
||||
procedure s1
|
||||
end interface
|
||||
contains
|
||||
subroutine s1(x)
|
||||
end
|
||||
end
|
||||
module m7b
|
||||
interface g
|
||||
procedure s2
|
||||
end interface
|
||||
contains
|
||||
subroutine s2(x, y)
|
||||
end
|
||||
end
|
||||
module m7c
|
||||
interface g
|
||||
procedure s3
|
||||
end interface
|
||||
contains
|
||||
subroutine s3(x, y, z)
|
||||
end
|
||||
end
|
||||
! Merge the three use-associated generics
|
||||
subroutine s7
|
||||
use m7a
|
||||
use m7b
|
||||
use m7c
|
||||
call g(1.0)
|
||||
call g(1.0, 2.0)
|
||||
call g(1.0, 2.0, 3.0)
|
||||
end
|
||||
|
||||
module m8a
|
||||
interface g
|
||||
procedure s1
|
||||
end interface
|
||||
contains
|
||||
subroutine s1(x)
|
||||
end
|
||||
end
|
||||
module m8b
|
||||
interface g
|
||||
procedure s2
|
||||
end interface
|
||||
contains
|
||||
subroutine s2(x, y)
|
||||
end
|
||||
end
|
||||
module m8c
|
||||
integer :: g
|
||||
end
|
||||
! If merged generic conflicts with another USE, it is an error (if it is referenced)
|
||||
subroutine s8
|
||||
use m8a
|
||||
use m8b
|
||||
use m8c
|
||||
!ERROR: Reference to 'g' is ambiguous
|
||||
g = 1
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue