diff --git a/flang/include/flang/Semantics/tools.h b/flang/include/flang/Semantics/tools.h --- a/flang/include/flang/Semantics/tools.h +++ b/flang/include/flang/Semantics/tools.h @@ -117,7 +117,7 @@ bool HasDeclarationInitializer(const Symbol &); // Is the symbol explicitly or implicitly initialized in any way? bool IsInitialized(const Symbol &, bool ignoreDATAstatements = false, - bool ignoreAllocatable = false); + bool ignoreAllocatable = false, bool ignorePointer = true); // Is the symbol a component subject to deallocation or finalization? bool IsDestructible(const Symbol &, const Symbol *derivedType = nullptr); bool HasIntrinsicTypeName(const Symbol &); diff --git a/flang/include/flang/Semantics/type.h b/flang/include/flang/Semantics/type.h --- a/flang/include/flang/Semantics/type.h +++ b/flang/include/flang/Semantics/type.h @@ -266,7 +266,8 @@ bool MightBeParameterized() const; bool IsForwardReferenced() const; - bool HasDefaultInitialization(bool ignoreAllocatable = false) const; + bool HasDefaultInitialization( + bool ignoreAllocatable = false, bool ignorePointer = true) const; bool HasDestruction() const; // The "raw" type parameter list is a simple transcription from the diff --git a/flang/lib/Semantics/check-data.cpp b/flang/lib/Semantics/check-data.cpp --- a/flang/lib/Semantics/check-data.cpp +++ b/flang/lib/Semantics/check-data.cpp @@ -63,7 +63,8 @@ : IsFunctionResult(symbol) ? "Function result" : IsAllocatable(symbol) ? "Allocatable" : IsInitialized(symbol, true /*ignore DATA*/, - true /*ignore allocatable components*/) + true /*ignore allocatable components*/, + true /*ignore uninitialized pointer components*/) ? "Default-initialized" : IsProcedure(symbol) && !IsPointer(symbol) ? "Procedure" // remaining checks don't apply to components diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp --- a/flang/lib/Semantics/expression.cpp +++ b/flang/lib/Semantics/expression.cpp @@ -2066,13 +2066,15 @@ if (!symbol.test(Symbol::Flag::ParentComp) && unavailable.find(symbol.name()) == unavailable.cend()) { if (IsAllocatable(symbol)) { - // Set all remaining allocatables to explicit NULL() + // Set all remaining allocatables to explicit NULL(). result.Add(symbol, Expr{NullPointer{}}); - } else if (const auto *details{ - symbol.detailsIf()}) { - if (details->init()) { - result.Add(symbol, common::Clone(*details->init())); - } else { // C799 + } else { + const auto *object{symbol.detailsIf()}; + if (object && object->init()) { + result.Add(symbol, common::Clone(*object->init())); + } else if (IsPointer(symbol)) { + result.Add(symbol, Expr{NullPointer{}}); + } else if (object) { // C799 AttachDeclaration(Say(typeName, "Structure constructor lacks a value for " "component '%s'"_err_en_US, diff --git a/flang/lib/Semantics/runtime-type-info.cpp b/flang/lib/Semantics/runtime-type-info.cpp --- a/flang/lib/Semantics/runtime-type-info.cpp +++ b/flang/lib/Semantics/runtime-type-info.cpp @@ -626,8 +626,8 @@ // instances without any initialized components, analyze the type // and set a flag if there's nothing to do for it at run time. AddValue(dtValues, derivedTypeSchema_, "noinitializationneeded"s, - IntExpr<1>( - derivedTypeSpec && !derivedTypeSpec->HasDefaultInitialization())); + IntExpr<1>(derivedTypeSpec && + !derivedTypeSpec->HasDefaultInitialization(false, false))); // Similarly, a flag to short-circuit destruction when not needed. AddValue(dtValues, derivedTypeSchema_, "nodestructionneeded"s, IntExpr<1>(isAbstractType || diff --git a/flang/lib/Semantics/tools.cpp b/flang/lib/Semantics/tools.cpp --- a/flang/lib/Semantics/tools.cpp +++ b/flang/lib/Semantics/tools.cpp @@ -642,21 +642,23 @@ } } -bool IsInitialized( - const Symbol &symbol, bool ignoreDataStatements, bool ignoreAllocatable) { +bool IsInitialized(const Symbol &symbol, bool ignoreDataStatements, + bool ignoreAllocatable, bool ignorePointer) { if (!ignoreAllocatable && IsAllocatable(symbol)) { return true; } else if (!ignoreDataStatements && symbol.test(Symbol::Flag::InDataStmt)) { return true; } else if (HasDeclarationInitializer(symbol)) { return true; - } else if (IsNamedConstant(symbol) || IsFunctionResult(symbol) || - IsPointer(symbol)) { + } else if (IsPointer(symbol)) { + return !ignorePointer; + } else if (IsNamedConstant(symbol) || IsFunctionResult(symbol)) { return false; } else if (const auto *object{symbol.detailsIf()}) { if (!object->isDummy() && object->type()) { if (const auto *derived{object->type()->AsDerived()}) { - return derived->HasDefaultInitialization(ignoreAllocatable); + return derived->HasDefaultInitialization( + ignoreAllocatable, ignorePointer); } } } diff --git a/flang/lib/Semantics/type.cpp b/flang/lib/Semantics/type.cpp --- a/flang/lib/Semantics/type.cpp +++ b/flang/lib/Semantics/type.cpp @@ -179,11 +179,13 @@ return typeSymbol_.get().isForwardReferenced(); } -bool DerivedTypeSpec::HasDefaultInitialization(bool ignoreAllocatable) const { +bool DerivedTypeSpec::HasDefaultInitialization( + bool ignoreAllocatable, bool ignorePointer) const { DirectComponentIterator components{*this}; return bool{std::find_if( components.begin(), components.end(), [&](const Symbol &component) { - return IsInitialized(component, true, ignoreAllocatable); + return IsInitialized(component, /*ignoreDataStatements=*/true, + ignoreAllocatable, ignorePointer); })}; } diff --git a/flang/runtime/derived.cpp b/flang/runtime/derived.cpp --- a/flang/runtime/derived.cpp +++ b/flang/runtime/derived.cpp @@ -58,6 +58,16 @@ char *ptr{instance.ZeroBasedIndexedElement(j) + comp.offset()}; std::memcpy(ptr, init, bytes); } + } else if (comp.genre() == typeInfo::Component::Genre::Pointer) { + // Data pointers without explicit initialization are established + // so that they are valid right-hand side targets of pointer + // assignment statements. + for (std::size_t j{0}; j < elements; ++j) { + Descriptor &ptrDesc{*instance.OffsetElement( + j * byteStride + comp.offset())}; + comp.EstablishDescriptor(ptrDesc, instance, terminator); + ptrDesc.raw().attribute = CFI_attribute_pointer; + } } else if (comp.genre() == typeInfo::Component::Genre::Data && comp.derivedType() && !comp.derivedType()->noInitializationNeeded()) { // Default initialization of non-pointer non-allocatable/automatic diff --git a/flang/runtime/type-info.cpp b/flang/runtime/type-info.cpp --- a/flang/runtime/type-info.cpp +++ b/flang/runtime/type-info.cpp @@ -112,7 +112,7 @@ } else { descriptor.Establish(cat, kind_, nullptr, rank_, nullptr, attribute); } - if (rank_ && genre_ != Genre::Allocatable) { + if (rank_ && genre_ != Genre::Allocatable && genre_ != Genre::Pointer) { const typeInfo::Value *boundValues{bounds()}; RUNTIME_CHECK(terminator, boundValues != nullptr); auto byteStride{static_cast(descriptor.ElementBytes())}; diff --git a/flang/test/Semantics/canondo01.f90 b/flang/test/Semantics/canondo01.f90 --- a/flang/test/Semantics/canondo01.f90 +++ b/flang/test/Semantics/canondo01.f90 @@ -1,4 +1,3 @@ - ! RUN: %flang_fc1 -fdebug-unparse-with-symbols %s 2>&1 | FileCheck %s ! CHECK: end do diff --git a/flang/test/Semantics/structconst07.f90 b/flang/test/Semantics/structconst07.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/structconst07.f90 @@ -0,0 +1,9 @@ +! RUN: %flang_fc1 -fdebug-unparse %s 2>&1 | FileCheck %s +type :: hasPointer + class(*), pointer :: sp +end type +type(hasPointer) hp +!CHECK: hp=haspointer(sp=NULL()) +hp = hasPointer() +end + diff --git a/flang/test/Semantics/structconst07.f90# b/flang/test/Semantics/structconst07.f90# deleted file mode 100644 --- a/flang/test/Semantics/structconst07.f90# +++ /dev/null @@ -1,5 +0,0 @@ -! RUN: %python %S/test_errors.py %s %flang_fc1 -! C1594(4) -module m - type t1 - diff --git a/flang/test/Semantics/typeinfo03.f90 b/flang/test/Semantics/typeinfo03.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/typeinfo03.f90 @@ -0,0 +1,9 @@ +!RUN: bbc --dump-symbols %s | FileCheck %s +!RUN: %flang_fc1 -fdebug-dump-symbols %s | FileCheck %s +!Ensure that type with pointer component(s) has "noinitializationneeded=0" +module m + type hasPointer + class(*), pointer :: sp, ap(:) + end type +end module +!CHECK: .dt.haspointer, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.haspointer,sizeinbytes=104_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.haspointer,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)