[flang] Handle structure constructors with forward references to PDTs

We were not correctly handling structure constructors that had forward
references to parameterized derived types.  I harvested the code that checks
for forward references that was used during analysis of function call
expressions and called it from there and also called it during the
analysis of structure constructors.

I also added a test that will produce an internal error without this change.

Differential Revision: https://reviews.llvm.org/D101330
This commit is contained in:
Peter Steinfeld 2021-04-26 15:20:22 -07:00
parent 9c552d27ee
commit 8b550af7a9
3 changed files with 34 additions and 6 deletions

View file

@ -382,6 +382,7 @@ private:
template <typename T> T Fold(T &&expr) {
return evaluate::Fold(foldingContext_, std::move(expr));
}
bool CheckIsValidForwardReference(const semantics::DerivedTypeSpec &);
semantics::SemanticsContext &context_;
FoldingContext &foldingContext_{context_.foldingContext()};

View file

@ -1463,7 +1463,16 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::ArrayConstructor &array) {
MaybeExpr ExpressionAnalyzer::Analyze(
const parser::StructureConstructor &structure) {
auto &parsedType{std::get<parser::DerivedTypeSpec>(structure.t)};
parser::CharBlock typeName{std::get<parser::Name>(parsedType.t).source};
parser::Name structureType{std::get<parser::Name>(parsedType.t)};
parser::CharBlock &typeName{structureType.source};
if (semantics::Symbol * typeSymbol{structureType.symbol}) {
if (typeSymbol->has<semantics::DerivedTypeDetails>()) {
semantics::DerivedTypeSpec dtSpec{typeName, typeSymbol->GetUltimate()};
if (!CheckIsValidForwardReference(dtSpec)) {
return std::nullopt;
}
}
}
if (!parsedType.derivedTypeSpec) {
return std::nullopt;
}
@ -2182,6 +2191,17 @@ const Symbol *AssumedTypeDummy<parser::PointerObject>(
return AssumedTypePointerOrAllocatableDummy(x);
}
bool ExpressionAnalyzer::CheckIsValidForwardReference(
const semantics::DerivedTypeSpec &dtSpec) {
if (dtSpec.IsForwardReferenced()) {
Say("Cannot construct value for derived type '%s' "
"before it is defined"_err_en_US,
dtSpec.name());
return false;
}
return true;
}
MaybeExpr ExpressionAnalyzer::Analyze(const parser::FunctionReference &funcRef,
std::optional<parser::StructureConstructor> *structureConstructor) {
const parser::Call &call{funcRef.v};
@ -2209,11 +2229,7 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::FunctionReference &funcRef,
semantics::Scope &scope{context_.FindScope(name->source)};
semantics::DerivedTypeSpec dtSpec{
name->source, derivedType.GetUltimate()};
if (dtSpec.IsForwardReferenced()) {
Say(call.source,
"Cannot construct value for derived type '%s' "
"before it is defined"_err_en_US,
name->source);
if (!CheckIsValidForwardReference(dtSpec)) {
return std::nullopt;
}
const semantics::DeclTypeSpec &type{

View file

@ -79,3 +79,14 @@ subroutine s8
real :: c
end type
end subroutine
subroutine s9
type con
Type(t(3)), pointer :: y
end type
!ERROR: Cannot construct value for derived type 't' before it is defined
Integer :: nn = Size(Transfer(t(3)(666),[0]))
type :: t(n)
integer, kind :: n = 3
end type
end subroutine s9