mirror of
https://github.com/intel/llvm.git
synced 2026-01-21 04:14:03 +08:00
[flang] Apply default module accessibility rules a second time (bug#62598)
Apply the default PUBLIC/PRIVATE accessibility of a module to its symbols a second time after it is known that all symbols, including implicitly typed names from NAMELIST groups and specification expressions in module subprograms, have been created in its scope. Fixes https://github.com/llvm/llvm-project/issues/62598. Differential Revision: https://reviews.llvm.org/D150307
This commit is contained in:
@@ -453,7 +453,7 @@ end
|
||||
Other Fortran compilers disagree in their interpretations of this example;
|
||||
some seem to treat the references to `m` as if they were host associations
|
||||
to an implicitly typed variable (and print `3`), while others seem to
|
||||
treat them as references to implicitly typed local variabless, and
|
||||
treat them as references to implicitly typed local variables, and
|
||||
load uninitialized values.
|
||||
|
||||
In f18, we chose to emit an error message for this case since the standard
|
||||
|
||||
@@ -54,9 +54,12 @@ public:
|
||||
const Scope *ancestor() const; // for submodule; nullptr for module
|
||||
const Scope *parent() const; // for submodule; nullptr for module
|
||||
void set_scope(const Scope *);
|
||||
bool isDefaultPrivate() const { return isDefaultPrivate_; }
|
||||
void set_isDefaultPrivate(bool yes = true) { isDefaultPrivate_ = yes; }
|
||||
|
||||
private:
|
||||
bool isSubmodule_;
|
||||
bool isDefaultPrivate_{false};
|
||||
const Scope *scope_{nullptr};
|
||||
};
|
||||
|
||||
|
||||
@@ -749,8 +749,6 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
// The default access spec for this module.
|
||||
Attr defaultAccess_{Attr::PUBLIC};
|
||||
// The location of the last AccessStmt without access-ids, if any.
|
||||
std::optional<SourceName> prevAccessStmt_;
|
||||
// The scope of the module during a UseStmt
|
||||
@@ -3119,7 +3117,6 @@ void ModuleVisitor::BeginModule(const parser::Name &name, bool isSubmodule) {
|
||||
auto &details{symbol.get<ModuleDetails>()};
|
||||
PushScope(Scope::Kind::Module, &symbol);
|
||||
details.set_scope(&currScope());
|
||||
defaultAccess_ = Attr::PUBLIC;
|
||||
prevAccessStmt_ = std::nullopt;
|
||||
}
|
||||
|
||||
@@ -3142,10 +3139,15 @@ Scope *ModuleVisitor::FindModule(const parser::Name &name,
|
||||
}
|
||||
|
||||
void ModuleVisitor::ApplyDefaultAccess() {
|
||||
const auto *moduleDetails{
|
||||
DEREF(currScope().symbol()).detailsIf<ModuleDetails>()};
|
||||
CHECK(moduleDetails);
|
||||
for (auto &pair : currScope()) {
|
||||
Symbol &symbol = *pair.second;
|
||||
Symbol &symbol{*pair.second};
|
||||
if (!symbol.attrs().HasAny({Attr::PUBLIC, Attr::PRIVATE})) {
|
||||
SetImplicitAttr(symbol, defaultAccess_);
|
||||
SetImplicitAttr(symbol,
|
||||
DEREF(moduleDetails).isDefaultPrivate() ? Attr::PRIVATE
|
||||
: Attr::PUBLIC);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7319,7 +7321,8 @@ bool ModuleVisitor::Pre(const parser::AccessStmt &x) {
|
||||
.Attach(*prevAccessStmt_, "Previous declaration"_en_US);
|
||||
}
|
||||
prevAccessStmt_ = currStmtSource();
|
||||
defaultAccess_ = accessAttr;
|
||||
auto *moduleDetails{DEREF(currScope().symbol()).detailsIf<ModuleDetails>()};
|
||||
DEREF(moduleDetails).set_isDefaultPrivate(accessAttr == Attr::PRIVATE);
|
||||
} else {
|
||||
for (const auto &accessId : accessIds) {
|
||||
GenericSpecInfo info{accessId.v.value()};
|
||||
@@ -8232,6 +8235,12 @@ void ResolveNamesVisitor::ResolveExecutionParts(const ProgramTree &node) {
|
||||
Walk(*exec);
|
||||
}
|
||||
FinishNamelists();
|
||||
if (node.IsModule()) {
|
||||
// A second final pass to catch new symbols added from implicitly
|
||||
// typed names in NAMELIST groups or the specification parts of
|
||||
// module subprograms.
|
||||
ApplyDefaultAccess();
|
||||
}
|
||||
PopScope(); // converts unclassified entities into objects
|
||||
for (const auto &child : node.children()) {
|
||||
ResolveExecutionParts(child);
|
||||
|
||||
@@ -494,6 +494,9 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Details &details) {
|
||||
}
|
||||
os << ")";
|
||||
}
|
||||
if (x.isDefaultPrivate()) {
|
||||
os << " isDefaultPrivate";
|
||||
}
|
||||
},
|
||||
[&](const SubprogramNameDetails &x) {
|
||||
os << ' ' << EnumToString(x.kind());
|
||||
|
||||
23
flang/test/Semantics/symbol26.f90
Normal file
23
flang/test/Semantics/symbol26.f90
Normal file
@@ -0,0 +1,23 @@
|
||||
! RUN: %python %S/test_symbols.py %s %flang_fc1
|
||||
! Regression test for https://github.com/llvm/llvm-project/issues/62598
|
||||
! Ensure that implicitly typed names in module NAMELIST groups receive
|
||||
! the module's default accessibility attribute.
|
||||
!DEF: /m Module
|
||||
module m
|
||||
!DEF: /m/a PUBLIC Namelist
|
||||
!DEF: /m/j PUBLIC (Implicit, InNamelist) ObjectEntity INTEGER(4)
|
||||
namelist/a/j
|
||||
end module m
|
||||
!DEF: /main MainProgram
|
||||
program main
|
||||
!DEF: /main/j (Implicit) ObjectEntity INTEGER(4)
|
||||
j = 1
|
||||
contains
|
||||
!DEF: /main/inner (Subroutine) Subprogram
|
||||
subroutine inner
|
||||
!REF: /m
|
||||
use :: m
|
||||
!DEF: /main/inner/j (Implicit, InNamelist) Use INTEGER(4)
|
||||
j = 2
|
||||
end subroutine
|
||||
end program
|
||||
Reference in New Issue
Block a user