Skip to content

[flang] Process pointer component default initializers sooner #145601

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

klausler
Copy link
Contributor

Name resolution defers the analysis of all object pointer initializers to the end of a specification part, including the default initializers of derived type data pointer components. This deferment allows object pointer initializers to contain forward references to objects whose declarations appear later.

However, this deferment has the unfortunate effect of causing NULL default initialization of such object pointer components when they do not appear in structure constructors that are used as default initializers, and their default initializers are required. So handle object pointer default initializers of components as they appear, as before.

Name resolution defers the analysis of all object pointer initializers
to the end of a specification part, including the default initializers
of derived type data pointer components.  This deferment allows object
pointer initializers to contain forward references to objects whose
declarations appear later.

However, this deferment has the unfortunate effect of causing NULL default
initialization of such object pointer components when they do not appear
in structure constructors that are used as default initializers, and their
default initializers are required.  So handle object pointer default
initializers of components as they appear, as before.
@llvmbot llvmbot added flang Flang issues not falling into any other category flang:semantics labels Jun 24, 2025
@llvmbot
Copy link
Member

llvmbot commented Jun 24, 2025

@llvm/pr-subscribers-flang-semantics

Author: Peter Klausler (klausler)

Changes

Name resolution defers the analysis of all object pointer initializers to the end of a specification part, including the default initializers of derived type data pointer components. This deferment allows object pointer initializers to contain forward references to objects whose declarations appear later.

However, this deferment has the unfortunate effect of causing NULL default initialization of such object pointer components when they do not appear in structure constructors that are used as default initializers, and their default initializers are required. So handle object pointer default initializers of components as they appear, as before.


Full diff: https://github.com/llvm/llvm-project/pull/145601.diff

5 Files Affected:

  • (modified) flang/docs/Extensions.md (+7)
  • (modified) flang/lib/Semantics/resolve-names.cpp (+9-10)
  • (added) flang/test/Semantics/bug1056.f90 (+13)
  • (modified) flang/test/Semantics/symbol15.f90 (+11-8)
  • (added) t.f90 (+11)
diff --git a/flang/docs/Extensions.md b/flang/docs/Extensions.md
index 871749934810c..6720fdc0a2448 100644
--- a/flang/docs/Extensions.md
+++ b/flang/docs/Extensions.md
@@ -868,6 +868,13 @@ print *, [(j,j=1,10)]
   the elements for each component before proceeding to the next component.
   A program using defined assignment might be able to detect the difference.
 
+* Forward references to target objects are allowed to appear
+  in the initializers of data pointer declarationss.
+  Forward references to target objects are not accepted in the default
+  initializers of derived type component declarations, however,
+  since these default values need to be available to process incomplete
+  structure constructors.
+
 ## De Facto Standard Features
 
 * `EXTENDS_TYPE_OF()` returns `.TRUE.` if both of its arguments have the
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 9e465f8ff3e1e..987824f0fcee8 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -5383,7 +5383,7 @@ void DeclarationVisitor::Post(const parser::EntityDecl &x) {
     ConvertToObjectEntity(symbol) || ConvertToProcEntity(symbol);
     symbol.set(
         Symbol::Flag::EntryDummyArgument, false); // forestall excessive errors
-    Initialization(name, *init, false);
+    Initialization(name, *init, /*inComponentDecl=*/false);
   } else if (attrs.test(Attr::PARAMETER)) { // C882, C883
     Say(name, "Missing initialization for parameter '%s'"_err_en_US);
   }
@@ -6398,7 +6398,7 @@ void DeclarationVisitor::Post(const parser::ComponentDecl &x) {
     SetCUDADataAttr(name.source, symbol, cudaDataAttr());
     if (symbol.has<ObjectEntityDetails>()) {
       if (auto &init{std::get<std::optional<parser::Initialization>>(x.t)}) {
-        Initialization(name, *init, true);
+        Initialization(name, *init, /*inComponentDecl=*/true);
       }
     }
     currScope().symbol()->get<DerivedTypeDetails>().add_component(symbol);
@@ -8933,9 +8933,13 @@ void DeclarationVisitor::Initialization(const parser::Name &name,
             // Defer analysis to the end of the specification part
             // so that forward references and attribute checks like SAVE
             // work better.
-            auto restorer{common::ScopedSet(deferImplicitTyping_, true)};
-            Walk(target);
-            ultimate.set(Symbol::Flag::InDataStmt);
+            if (inComponentDecl) {
+              PointerInitialization(name, target);
+            } else {
+              auto restorer{common::ScopedSet(deferImplicitTyping_, true)};
+              Walk(target);
+              ultimate.set(Symbol::Flag::InDataStmt);
+            }
           },
           [&](const std::list<Indirection<parser::DataStmtValue>> &values) {
             // Handled later in data-to-inits conversion
@@ -10355,11 +10359,6 @@ class DeferredCheckVisitor {
         std::get<std::optional<parser::Initialization>>(decl.t));
     return false;
   }
-  bool Pre(const parser::ComponentDecl &decl) {
-    Init(std::get<parser::Name>(decl.t),
-        std::get<std::optional<parser::Initialization>>(decl.t));
-    return false;
-  }
   bool Pre(const parser::ProcDecl &decl) {
     if (const auto &init{
             std::get<std::optional<parser::ProcPointerInit>>(decl.t)}) {
diff --git a/flang/test/Semantics/bug1056.f90 b/flang/test/Semantics/bug1056.f90
new file mode 100644
index 0000000000000..b32270dab8f71
--- /dev/null
+++ b/flang/test/Semantics/bug1056.f90
@@ -0,0 +1,13 @@
+! RUN: %flang_fc1 -fdebug-unparse %s | FileCheck %s
+program bug
+  integer, target :: ita(2) = [1,2], itb(2) = [3,4], itc(2) = [5,6]
+  type t1
+    integer, pointer :: p1(:) => ita, p2(:) => itb
+  end type
+  type t2
+    !CHECK: TYPE(t1) :: comp = t1(p1=itc,p2=itb)
+    type(t1) :: comp = t1(itc)
+  end type
+  integer, pointer :: p3(:) => itd
+  integer, target :: itd(2) = [7,8]
+end
diff --git a/flang/test/Semantics/symbol15.f90 b/flang/test/Semantics/symbol15.f90
index 97dc50a23845f..df10942e6af2d 100644
--- a/flang/test/Semantics/symbol15.f90
+++ b/flang/test/Semantics/symbol15.f90
@@ -43,6 +43,9 @@ subroutine iface
  !DEF: /m/pp6 EXTERNAL, POINTER, PUBLIC (Subroutine) ProcEntity
  !DEF: /m/modproc1 PUBLIC (Subroutine) Subprogram
  procedure(iface), pointer :: pp6 => modproc1
+ !DEF: /m/xx PUBLIC, TARGET ObjectEntity REAL(4)
+ !DEF: /m/yy PUBLIC, TARGET ObjectEntity REAL(4)
+ real, target :: xx, yy(2)
  !DEF: /m/t1 PUBLIC DerivedType
  type :: t1
   !DEF: /m/t1/opc1 POINTER ObjectEntity REAL(4)
@@ -51,11 +54,11 @@ subroutine iface
   !REF: /m/null
   real, pointer :: opc2 => null()
   !DEF: /m/t1/opc3 POINTER ObjectEntity REAL(4)
-  !REF: /m/x
-  real, pointer :: opc3 => x
+  !REF: /m/xx
+  real, pointer :: opc3 => xx
   !DEF: /m/t1/opc4 POINTER ObjectEntity REAL(4)
-  !REF: /m/y
-  real, pointer :: opc4 => y(1)
+  !REF: /m/yy
+  real, pointer :: opc4 => yy(1)
   !REF: /m/iface
   !DEF: /m/t1/ppc1 NOPASS, POINTER (Subroutine) ProcEntity
   procedure(iface), nopass, pointer :: ppc1
@@ -101,12 +104,12 @@ subroutine iface
   !REF: /m/null
   real, pointer :: opc2 => null()
   !DEF: /m/pdt1/opc3 POINTER ObjectEntity REAL(4)
-  !REF: /m/x
-  real, pointer :: opc3 => x
+  !REF: /m/xx
+  real, pointer :: opc3 => xx
   !DEF: /m/pdt1/opc4 POINTER ObjectEntity REAL(4)
-  !REF: /m/y
+  !REF: /m/yy
   !REF: /m/pdt1/k
-  real, pointer :: opc4 => y(k)
+  real, pointer :: opc4 => yy(k)
   !REF: /m/iface
   !DEF: /m/pdt1/ppc1 NOPASS, POINTER (Subroutine) ProcEntity
   procedure(iface), nopass, pointer :: ppc1
diff --git a/t.f90 b/t.f90
new file mode 100644
index 0000000000000..2b8f7129ca666
--- /dev/null
+++ b/t.f90
@@ -0,0 +1,11 @@
+integer, target :: ita(2) = [1,2], itb(2) = [3,4], itc(2) = [5,6]
+type t1
+  integer, pointer :: p1(:) => ita, p2(:) => itb
+end type
+type t2
+  type(t1) :: comp = t1(itc)
+end type
+type(t2) :: var
+print *, var%comp%p2
+var%comp = t1(itc)
+end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang:semantics flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants