[flang] Fix scope accessibility check

The check for whether a private component is accessible was depending on
determining whether the source range of the current scope was within the
source range of the module that the component was declared in. This
could fail if the current scope was of kind `ImpliedDos` and had no
source range.

The fix is to add `Scope::Contains` to check the relationship by
traversing the parent links. These are created when the Scope is so are
always reliable. The source range of a scope is built up over time.

Original-commit: flang-compiler/f18@d787108637
Reviewed-on: https://github.com/flang-compiler/f18/pull/1060
This commit is contained in:
Tim Keith 2020-03-10 15:31:02 -07:00
parent 749be7993e
commit 6ab50745c0
4 changed files with 30 additions and 12 deletions

View File

@ -85,15 +85,8 @@ public:
const Symbol *GetSymbol() const;
const Scope *GetDerivedTypeParent() const;
std::optional<SourceName> GetName() const {
if (const auto *sym{GetSymbol()}) {
return sym->name();
} else {
return std::nullopt;
}
}
std::optional<SourceName> GetName() const;
bool Contains(const Scope &) const;
/// Make a scope nested in this one
Scope &MakeScope(Kind kind, Symbol *symbol = nullptr);

View File

@ -91,6 +91,25 @@ Symbol *Scope::FindComponent(SourceName name) const {
}
}
std::optional<SourceName> Scope::GetName() const {
if (const auto *sym{GetSymbol()}) {
return sym->name();
} else {
return std::nullopt;
}
}
bool Scope::Contains(const Scope &that) const {
for (const Scope *scope{&that};; scope = &scope->parent()) {
if (*scope == *this) {
return true;
}
if (scope->IsGlobal()) {
return false;
}
}
}
const std::list<EquivalenceSet> &Scope::equivalenceSets() const {
return equivalenceSets_;
}
@ -244,8 +263,7 @@ Scope *Scope::FindScope(parser::CharBlock source) {
}
void Scope::AddSourceRange(const parser::CharBlock &source) {
for (auto *scope = this; !scope->IsGlobal();
scope = &scope->parent()) {
for (auto *scope = this; !scope->IsGlobal(); scope = &scope->parent()) {
scope->sourceRange_.ExtendToCover(source);
}
}

View File

@ -960,7 +960,7 @@ std::optional<parser::MessageFormattedText> CheckAccessibleComponent(
CHECK(symbol.owner().IsDerivedType()); // symbol must be a component
if (symbol.attrs().test(Attr::PRIVATE)) {
if (const Scope * moduleScope{FindModuleContaining(symbol.owner())}) {
if (!moduleScope->sourceRange().Contains(scope.sourceRange())) {
if (!moduleScope->Contains(scope)) {
return parser::MessageFormattedText{
"PRIVATE component '%s' is only accessible within module '%s'"_err_en_US,
symbol.name(), moduleScope->GetName().value()};

View File

@ -98,11 +98,16 @@ module m8
integer :: i1
integer, private :: i2
end type
type(t) :: y
integer :: a(1)
contains
subroutine s0
type(t) :: x
x = t(i1=2, i2=5) !OK
end
subroutine s1
a = [y%i2] !OK
end subroutine
end
subroutine s8
use m8
@ -111,6 +116,8 @@ subroutine s8
x = t(2, 5)
!ERROR: PRIVATE component 'i2' is only accessible within module 'm8'
x = t(i1=2, i2=5)
!ERROR: PRIVATE component 'i2' is only accessible within module 'm8'
a = [y%i2]
end
! 7.5.4.8(2)