[flang] Apply default module accessibility rules a second time (bug#62598)
authorPeter Klausler <pklausler@nvidia.com>
Wed, 10 May 2023 20:26:01 +0000 (13:26 -0700)
committerPeter Klausler <pklausler@nvidia.com>
Tue, 16 May 2023 17:19:00 +0000 (10:19 -0700)
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

flang/docs/Extensions.md
flang/include/flang/Semantics/symbol.h
flang/lib/Semantics/resolve-names.cpp
flang/lib/Semantics/symbol.cpp
flang/test/Semantics/symbol26.f90 [new file with mode: 0644]

index cf6b65c..a915967 100644 (file)
@@ -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
index 3e029c9..02d7136 100644 (file)
@@ -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};
 };
 
index 57870a7..321f819 100644 (file)
@@ -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);
index ca91753..d359389 100644 (file)
@@ -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());
diff --git a/flang/test/Semantics/symbol26.f90 b/flang/test/Semantics/symbol26.f90
new file mode 100644 (file)
index 0000000..f5e9585
--- /dev/null
@@ -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