|
|
|
|
@@ -2069,23 +2069,9 @@ static MaybeExpr ImplicitConvertTo(const semantics::Symbol &sym,
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MaybeExpr ExpressionAnalyzer::Analyze(
|
|
|
|
|
const parser::StructureConstructor &structure) {
|
|
|
|
|
auto &parsedType{std::get<parser::DerivedTypeSpec>(structure.t)};
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
const auto &spec{*parsedType.derivedTypeSpec};
|
|
|
|
|
MaybeExpr ExpressionAnalyzer::CheckStructureConstructor(
|
|
|
|
|
parser::CharBlock typeName, const semantics::DerivedTypeSpec &spec,
|
|
|
|
|
std::list<ComponentSpec> &&componentSpecs) {
|
|
|
|
|
const Symbol &typeSymbol{spec.typeSymbol()};
|
|
|
|
|
if (!spec.scope() || !typeSymbol.has<semantics::DerivedTypeDetails>()) {
|
|
|
|
|
return std::nullopt; // error recovery
|
|
|
|
|
@@ -2096,10 +2082,10 @@ MaybeExpr ExpressionAnalyzer::Analyze(
|
|
|
|
|
const Symbol *parentComponent{typeDetails.GetParentComponent(*spec.scope())};
|
|
|
|
|
|
|
|
|
|
if (typeSymbol.attrs().test(semantics::Attr::ABSTRACT)) { // C796
|
|
|
|
|
AttachDeclaration(Say(typeName,
|
|
|
|
|
"ABSTRACT derived type '%s' may not be used in a "
|
|
|
|
|
"structure constructor"_err_en_US,
|
|
|
|
|
typeName),
|
|
|
|
|
AttachDeclaration(
|
|
|
|
|
Say(typeName,
|
|
|
|
|
"ABSTRACT derived type '%s' may not be used in a structure constructor"_err_en_US,
|
|
|
|
|
typeName),
|
|
|
|
|
typeSymbol); // C7114
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -2129,22 +2115,19 @@ MaybeExpr ExpressionAnalyzer::Analyze(
|
|
|
|
|
bool checkConflicts{true}; // until we hit one
|
|
|
|
|
auto &messages{GetContextualMessages()};
|
|
|
|
|
|
|
|
|
|
// NULL() can be a valid component
|
|
|
|
|
auto restorer{AllowNullPointer()};
|
|
|
|
|
|
|
|
|
|
for (const auto &component :
|
|
|
|
|
std::get<std::list<parser::ComponentSpec>>(structure.t)) {
|
|
|
|
|
const parser::Expr &expr{
|
|
|
|
|
std::get<parser::ComponentDataSource>(component.t).v.value()};
|
|
|
|
|
parser::CharBlock source{expr.source};
|
|
|
|
|
for (ComponentSpec &componentSpec : componentSpecs) {
|
|
|
|
|
parser::CharBlock source{componentSpec.source};
|
|
|
|
|
parser::CharBlock exprSource{componentSpec.exprSource};
|
|
|
|
|
auto restorer{messages.SetLocation(source)};
|
|
|
|
|
const Symbol *symbol{nullptr};
|
|
|
|
|
MaybeExpr value{Analyze(expr)};
|
|
|
|
|
const Symbol *symbol{componentSpec.keywordSymbol};
|
|
|
|
|
MaybeExpr &maybeValue{componentSpec.expr};
|
|
|
|
|
if (!maybeValue.has_value()) {
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
Expr<SomeType> &value{*maybeValue};
|
|
|
|
|
std::optional<DynamicType> valueType{DynamicType::From(value)};
|
|
|
|
|
if (const auto &kw{std::get<std::optional<parser::Keyword>>(component.t)}) {
|
|
|
|
|
if (componentSpec.hasKeyword) {
|
|
|
|
|
anyKeyword = true;
|
|
|
|
|
source = kw->v.source;
|
|
|
|
|
symbol = kw->v.symbol;
|
|
|
|
|
if (!symbol) {
|
|
|
|
|
// Skip overridden inaccessible parent components in favor of
|
|
|
|
|
// their later overrides.
|
|
|
|
|
@@ -2196,9 +2179,9 @@ MaybeExpr ExpressionAnalyzer::Analyze(
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (symbol) {
|
|
|
|
|
const semantics::Scope &innermost{context_.FindScope(expr.source)};
|
|
|
|
|
const semantics::Scope &innermost{context_.FindScope(exprSource)};
|
|
|
|
|
if (auto msg{CheckAccessibleSymbol(innermost, *symbol)}) {
|
|
|
|
|
Say(expr.source, std::move(*msg));
|
|
|
|
|
Say(exprSource, std::move(*msg));
|
|
|
|
|
}
|
|
|
|
|
if (checkConflicts) {
|
|
|
|
|
auto componentIter{
|
|
|
|
|
@@ -2206,8 +2189,7 @@ MaybeExpr ExpressionAnalyzer::Analyze(
|
|
|
|
|
if (unavailable.find(symbol->name()) != unavailable.cend()) {
|
|
|
|
|
// C797, C798
|
|
|
|
|
Say(source,
|
|
|
|
|
"Component '%s' conflicts with another component earlier in "
|
|
|
|
|
"this structure constructor"_err_en_US,
|
|
|
|
|
"Component '%s' conflicts with another component earlier in this structure constructor"_err_en_US,
|
|
|
|
|
symbol->name());
|
|
|
|
|
} else if (symbol->test(Symbol::Flag::ParentComp)) {
|
|
|
|
|
// Make earlier components unavailable once a whole parent appears.
|
|
|
|
|
@@ -2225,143 +2207,136 @@ MaybeExpr ExpressionAnalyzer::Analyze(
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
unavailable.insert(symbol->name());
|
|
|
|
|
if (value) {
|
|
|
|
|
if (symbol->has<semantics::TypeParamDetails>()) {
|
|
|
|
|
Say(expr.source,
|
|
|
|
|
"Type parameter '%s' may not appear as a component of a structure constructor"_err_en_US,
|
|
|
|
|
symbol->name());
|
|
|
|
|
}
|
|
|
|
|
if (!(symbol->has<semantics::ProcEntityDetails>() ||
|
|
|
|
|
symbol->has<semantics::ObjectEntityDetails>())) {
|
|
|
|
|
continue; // recovery
|
|
|
|
|
}
|
|
|
|
|
if (IsPointer(*symbol)) { // C7104, C7105, C1594(4)
|
|
|
|
|
semantics::CheckStructConstructorPointerComponent(
|
|
|
|
|
context_, *symbol, *value, innermost);
|
|
|
|
|
result.Add(*symbol, Fold(std::move(*value)));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (IsNullPointer(&*value)) {
|
|
|
|
|
if (IsAllocatable(*symbol)) {
|
|
|
|
|
if (IsBareNullPointer(&*value)) {
|
|
|
|
|
// NULL() with no arguments allowed by 7.5.10 para 6 for
|
|
|
|
|
// ALLOCATABLE.
|
|
|
|
|
result.Add(*symbol, Expr<SomeType>{NullPointer{}});
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (IsNullObjectPointer(&*value)) {
|
|
|
|
|
AttachDeclaration(
|
|
|
|
|
Warn(common::LanguageFeature::
|
|
|
|
|
NullMoldAllocatableComponentValue,
|
|
|
|
|
expr.source,
|
|
|
|
|
"NULL() with arguments is not standard conforming as the value for allocatable component '%s'"_port_en_US,
|
|
|
|
|
symbol->name()),
|
|
|
|
|
*symbol);
|
|
|
|
|
// proceed to check type & shape
|
|
|
|
|
} else {
|
|
|
|
|
AttachDeclaration(
|
|
|
|
|
Say(expr.source,
|
|
|
|
|
"A NULL procedure pointer may not be used as the value for component '%s'"_err_en_US,
|
|
|
|
|
symbol->name()),
|
|
|
|
|
*symbol);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (symbol->has<semantics::TypeParamDetails>()) {
|
|
|
|
|
Say(exprSource,
|
|
|
|
|
"Type parameter '%s' may not appear as a component of a structure constructor"_err_en_US,
|
|
|
|
|
symbol->name());
|
|
|
|
|
}
|
|
|
|
|
if (!(symbol->has<semantics::ProcEntityDetails>() ||
|
|
|
|
|
symbol->has<semantics::ObjectEntityDetails>())) {
|
|
|
|
|
continue; // recovery
|
|
|
|
|
}
|
|
|
|
|
if (IsPointer(*symbol)) { // C7104, C7105, C1594(4)
|
|
|
|
|
semantics::CheckStructConstructorPointerComponent(
|
|
|
|
|
context_, *symbol, value, innermost);
|
|
|
|
|
result.Add(*symbol, Fold(std::move(value)));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (IsNullPointer(&value)) {
|
|
|
|
|
if (IsAllocatable(*symbol)) {
|
|
|
|
|
if (IsBareNullPointer(&value)) {
|
|
|
|
|
// NULL() with no arguments allowed by 7.5.10 para 6 for
|
|
|
|
|
// ALLOCATABLE.
|
|
|
|
|
result.Add(*symbol, Expr<SomeType>{NullPointer{}});
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (IsNullObjectPointer(&value)) {
|
|
|
|
|
AttachDeclaration(
|
|
|
|
|
Warn(common::LanguageFeature::NullMoldAllocatableComponentValue,
|
|
|
|
|
exprSource,
|
|
|
|
|
"NULL() with arguments is not standard conforming as the value for allocatable component '%s'"_port_en_US,
|
|
|
|
|
symbol->name()),
|
|
|
|
|
*symbol);
|
|
|
|
|
// proceed to check type & shape
|
|
|
|
|
} else {
|
|
|
|
|
AttachDeclaration(
|
|
|
|
|
Say(expr.source,
|
|
|
|
|
"A NULL pointer may not be used as the value for component '%s'"_err_en_US,
|
|
|
|
|
Say(exprSource,
|
|
|
|
|
"A NULL procedure pointer may not be used as the value for component '%s'"_err_en_US,
|
|
|
|
|
symbol->name()),
|
|
|
|
|
*symbol);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
} else if (IsNullAllocatable(&*value) && IsAllocatable(*symbol)) {
|
|
|
|
|
result.Add(*symbol, Expr<SomeType>{NullPointer{}});
|
|
|
|
|
} else {
|
|
|
|
|
AttachDeclaration(
|
|
|
|
|
Say(exprSource,
|
|
|
|
|
"A NULL pointer may not be used as the value for component '%s'"_err_en_US,
|
|
|
|
|
symbol->name()),
|
|
|
|
|
*symbol);
|
|
|
|
|
continue;
|
|
|
|
|
} else if (auto *derived{evaluate::GetDerivedTypeSpec(
|
|
|
|
|
evaluate::DynamicType::From(*symbol))}) {
|
|
|
|
|
if (auto iter{FindPointerPotentialComponent(*derived)};
|
|
|
|
|
iter && pureContext) { // F'2023 C15104(4)
|
|
|
|
|
if (const Symbol *
|
|
|
|
|
visible{semantics::FindExternallyVisibleObject(
|
|
|
|
|
*value, *pureContext)}) {
|
|
|
|
|
Say(expr.source,
|
|
|
|
|
"The externally visible object '%s' may not be used in a pure procedure as the value for component '%s' which has the pointer component '%s'"_err_en_US,
|
|
|
|
|
visible->name(), symbol->name(),
|
|
|
|
|
iter.BuildResultDesignatorName());
|
|
|
|
|
} else if (ExtractCoarrayRef(*value)) {
|
|
|
|
|
Say(expr.source,
|
|
|
|
|
"A coindexed object may not be used in a pure procedure as the value for component '%s' which has the pointer component '%s'"_err_en_US,
|
|
|
|
|
symbol->name(), iter.BuildResultDesignatorName());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (IsNullAllocatable(&value) && IsAllocatable(*symbol)) {
|
|
|
|
|
result.Add(*symbol, Expr<SomeType>{NullPointer{}});
|
|
|
|
|
continue;
|
|
|
|
|
} else if (auto *derived{evaluate::GetDerivedTypeSpec(
|
|
|
|
|
evaluate::DynamicType::From(*symbol))}) {
|
|
|
|
|
if (auto iter{FindPointerPotentialComponent(*derived)};
|
|
|
|
|
iter && pureContext) { // F'2023 C15104(4)
|
|
|
|
|
if (const Symbol *
|
|
|
|
|
visible{semantics::FindExternallyVisibleObject(
|
|
|
|
|
value, *pureContext)}) {
|
|
|
|
|
Say(exprSource,
|
|
|
|
|
"The externally visible object '%s' may not be used in a pure procedure as the value for component '%s' which has the pointer component '%s'"_err_en_US,
|
|
|
|
|
visible->name(), symbol->name(),
|
|
|
|
|
iter.BuildResultDesignatorName());
|
|
|
|
|
} else if (ExtractCoarrayRef(value)) {
|
|
|
|
|
Say(exprSource,
|
|
|
|
|
"A coindexed object may not be used in a pure procedure as the value for component '%s' which has the pointer component '%s'"_err_en_US,
|
|
|
|
|
symbol->name(), iter.BuildResultDesignatorName());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Make implicit conversion explicit to allow folding of the structure
|
|
|
|
|
// constructors and help semantic checking, unless the component is
|
|
|
|
|
// allocatable, in which case the value could be an unallocated
|
|
|
|
|
// allocatable (see Fortran 2018 7.5.10 point 7). The explicit
|
|
|
|
|
// convert would cause a segfault. Lowering will deal with
|
|
|
|
|
// conditionally converting and preserving the lower bounds in this
|
|
|
|
|
// case.
|
|
|
|
|
if (MaybeExpr converted{ImplicitConvertTo(
|
|
|
|
|
*symbol, std::move(*value), IsAllocatable(*symbol))}) {
|
|
|
|
|
if (auto componentShape{GetShape(GetFoldingContext(), *symbol)}) {
|
|
|
|
|
if (auto valueShape{GetShape(GetFoldingContext(), *converted)}) {
|
|
|
|
|
if (GetRank(*componentShape) == 0 && GetRank(*valueShape) > 0) {
|
|
|
|
|
AttachDeclaration(
|
|
|
|
|
Say(expr.source,
|
|
|
|
|
"Rank-%d array value is not compatible with scalar component '%s'"_err_en_US,
|
|
|
|
|
GetRank(*valueShape), symbol->name()),
|
|
|
|
|
*symbol);
|
|
|
|
|
} else {
|
|
|
|
|
auto checked{
|
|
|
|
|
CheckConformance(messages, *componentShape, *valueShape,
|
|
|
|
|
CheckConformanceFlags::RightIsExpandableDeferred,
|
|
|
|
|
"component", "value")};
|
|
|
|
|
if (checked && *checked && GetRank(*componentShape) > 0 &&
|
|
|
|
|
GetRank(*valueShape) == 0 &&
|
|
|
|
|
(IsDeferredShape(*symbol) ||
|
|
|
|
|
!IsExpandableScalar(*converted, GetFoldingContext(),
|
|
|
|
|
*componentShape, true /*admit PURE call*/))) {
|
|
|
|
|
AttachDeclaration(
|
|
|
|
|
Say(expr.source,
|
|
|
|
|
"Scalar value cannot be expanded to shape of array component '%s'"_err_en_US,
|
|
|
|
|
symbol->name()),
|
|
|
|
|
*symbol);
|
|
|
|
|
}
|
|
|
|
|
if (checked.value_or(true)) {
|
|
|
|
|
result.Add(*symbol, std::move(*converted));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Make implicit conversion explicit to allow folding of the structure
|
|
|
|
|
// constructors and help semantic checking, unless the component is
|
|
|
|
|
// allocatable, in which case the value could be an unallocated
|
|
|
|
|
// allocatable (see Fortran 2018 7.5.10 point 7). The explicit
|
|
|
|
|
// convert would cause a segfault. Lowering will deal with
|
|
|
|
|
// conditionally converting and preserving the lower bounds in this
|
|
|
|
|
// case.
|
|
|
|
|
if (MaybeExpr converted{ImplicitConvertTo(
|
|
|
|
|
*symbol, std::move(value), IsAllocatable(*symbol))}) {
|
|
|
|
|
if (auto componentShape{GetShape(GetFoldingContext(), *symbol)}) {
|
|
|
|
|
if (auto valueShape{GetShape(GetFoldingContext(), *converted)}) {
|
|
|
|
|
if (GetRank(*componentShape) == 0 && GetRank(*valueShape) > 0) {
|
|
|
|
|
AttachDeclaration(
|
|
|
|
|
Say(exprSource,
|
|
|
|
|
"Rank-%d array value is not compatible with scalar component '%s'"_err_en_US,
|
|
|
|
|
GetRank(*valueShape), symbol->name()),
|
|
|
|
|
*symbol);
|
|
|
|
|
} else {
|
|
|
|
|
Say(expr.source, "Shape of value cannot be determined"_err_en_US);
|
|
|
|
|
auto checked{CheckConformance(messages, *componentShape,
|
|
|
|
|
*valueShape, CheckConformanceFlags::RightIsExpandableDeferred,
|
|
|
|
|
"component", "value")};
|
|
|
|
|
if (checked && *checked && GetRank(*componentShape) > 0 &&
|
|
|
|
|
GetRank(*valueShape) == 0 &&
|
|
|
|
|
(IsDeferredShape(*symbol) ||
|
|
|
|
|
!IsExpandableScalar(*converted, GetFoldingContext(),
|
|
|
|
|
*componentShape, true /*admit PURE call*/))) {
|
|
|
|
|
AttachDeclaration(
|
|
|
|
|
Say(exprSource,
|
|
|
|
|
"Scalar value cannot be expanded to shape of array component '%s'"_err_en_US,
|
|
|
|
|
symbol->name()),
|
|
|
|
|
*symbol);
|
|
|
|
|
}
|
|
|
|
|
if (checked.value_or(true)) {
|
|
|
|
|
result.Add(*symbol, std::move(*converted));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
AttachDeclaration(
|
|
|
|
|
Say(expr.source,
|
|
|
|
|
"Shape of component '%s' cannot be determined"_err_en_US,
|
|
|
|
|
symbol->name()),
|
|
|
|
|
*symbol);
|
|
|
|
|
}
|
|
|
|
|
} else if (auto symType{DynamicType::From(symbol)}) {
|
|
|
|
|
if (IsAllocatable(*symbol) && symType->IsUnlimitedPolymorphic() &&
|
|
|
|
|
valueType) {
|
|
|
|
|
// ok
|
|
|
|
|
} else if (valueType) {
|
|
|
|
|
AttachDeclaration(
|
|
|
|
|
Say(expr.source,
|
|
|
|
|
"Value in structure constructor of type '%s' is "
|
|
|
|
|
"incompatible with component '%s' of type '%s'"_err_en_US,
|
|
|
|
|
valueType->AsFortran(), symbol->name(),
|
|
|
|
|
symType->AsFortran()),
|
|
|
|
|
*symbol);
|
|
|
|
|
} else {
|
|
|
|
|
AttachDeclaration(
|
|
|
|
|
Say(expr.source,
|
|
|
|
|
"Value in structure constructor is incompatible with "
|
|
|
|
|
"component '%s' of type %s"_err_en_US,
|
|
|
|
|
symbol->name(), symType->AsFortran()),
|
|
|
|
|
*symbol);
|
|
|
|
|
Say(exprSource, "Shape of value cannot be determined"_err_en_US);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
AttachDeclaration(
|
|
|
|
|
Say(exprSource,
|
|
|
|
|
"Shape of component '%s' cannot be determined"_err_en_US,
|
|
|
|
|
symbol->name()),
|
|
|
|
|
*symbol);
|
|
|
|
|
}
|
|
|
|
|
} else if (auto symType{DynamicType::From(symbol)}) {
|
|
|
|
|
if (IsAllocatable(*symbol) && symType->IsUnlimitedPolymorphic() &&
|
|
|
|
|
valueType) {
|
|
|
|
|
// ok
|
|
|
|
|
} else if (valueType) {
|
|
|
|
|
AttachDeclaration(
|
|
|
|
|
Say(exprSource,
|
|
|
|
|
"Value in structure constructor of type '%s' is incompatible with component '%s' of type '%s'"_err_en_US,
|
|
|
|
|
valueType->AsFortran(), symbol->name(), symType->AsFortran()),
|
|
|
|
|
*symbol);
|
|
|
|
|
} else {
|
|
|
|
|
AttachDeclaration(
|
|
|
|
|
Say(exprSource,
|
|
|
|
|
"Value in structure constructor is incompatible with component '%s' of type %s"_err_en_US,
|
|
|
|
|
symbol->name(), symType->AsFortran()),
|
|
|
|
|
*symbol);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -2381,10 +2356,10 @@ MaybeExpr ExpressionAnalyzer::Analyze(
|
|
|
|
|
} else if (IsPointer(symbol)) {
|
|
|
|
|
result.Add(symbol, Expr<SomeType>{NullPointer{}});
|
|
|
|
|
} else if (object) { // C799
|
|
|
|
|
AttachDeclaration(Say(typeName,
|
|
|
|
|
"Structure constructor lacks a value for "
|
|
|
|
|
"component '%s'"_err_en_US,
|
|
|
|
|
symbol.name()),
|
|
|
|
|
AttachDeclaration(
|
|
|
|
|
Say(typeName,
|
|
|
|
|
"Structure constructor lacks a value for component '%s'"_err_en_US,
|
|
|
|
|
symbol.name()),
|
|
|
|
|
symbol);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -2394,6 +2369,45 @@ MaybeExpr ExpressionAnalyzer::Analyze(
|
|
|
|
|
return AsMaybeExpr(Expr<SomeDerived>{std::move(result)});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MaybeExpr ExpressionAnalyzer::Analyze(
|
|
|
|
|
const parser::StructureConstructor &structure) {
|
|
|
|
|
const auto &parsedType{std::get<parser::DerivedTypeSpec>(structure.t)};
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
auto restorer{AllowNullPointer()}; // NULL() can be a valid component
|
|
|
|
|
std::list<ComponentSpec> componentSpecs;
|
|
|
|
|
for (const auto &component :
|
|
|
|
|
std::get<std::list<parser::ComponentSpec>>(structure.t)) {
|
|
|
|
|
const parser::Expr &expr{
|
|
|
|
|
std::get<parser::ComponentDataSource>(component.t).v.value()};
|
|
|
|
|
auto restorer{GetContextualMessages().SetLocation(expr.source)};
|
|
|
|
|
ComponentSpec compSpec;
|
|
|
|
|
compSpec.exprSource = expr.source;
|
|
|
|
|
compSpec.expr = Analyze(expr);
|
|
|
|
|
if (const auto &kw{std::get<std::optional<parser::Keyword>>(component.t)}) {
|
|
|
|
|
compSpec.source = kw->v.source;
|
|
|
|
|
compSpec.hasKeyword = true;
|
|
|
|
|
compSpec.keywordSymbol = kw->v.symbol;
|
|
|
|
|
} else {
|
|
|
|
|
compSpec.source = expr.source;
|
|
|
|
|
}
|
|
|
|
|
componentSpecs.emplace_back(std::move(compSpec));
|
|
|
|
|
}
|
|
|
|
|
return CheckStructureConstructor(
|
|
|
|
|
typeName, DEREF(parsedType.derivedTypeSpec), std::move(componentSpecs));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static std::optional<parser::CharBlock> GetPassName(
|
|
|
|
|
const semantics::Symbol &proc) {
|
|
|
|
|
return common::visit(
|
|
|
|
|
@@ -2841,24 +2855,26 @@ std::pair<const Symbol *, bool> ExpressionAnalyzer::ResolveGeneric(
|
|
|
|
|
const Symbol &symbol, const ActualArguments &actuals,
|
|
|
|
|
const AdjustActuals &adjustActuals, bool isSubroutine,
|
|
|
|
|
bool mightBeStructureConstructor) {
|
|
|
|
|
const Symbol *elemental{nullptr}; // matching elemental specific proc
|
|
|
|
|
const Symbol *nonElemental{nullptr}; // matching non-elemental specific
|
|
|
|
|
const Symbol &ultimate{symbol.GetUltimate()};
|
|
|
|
|
int crtMatchingDistance{cudaInfMatchingValue};
|
|
|
|
|
// Check for a match with an explicit INTRINSIC
|
|
|
|
|
const Symbol *explicitIntrinsic{nullptr};
|
|
|
|
|
if (ultimate.attrs().test(semantics::Attr::INTRINSIC)) {
|
|
|
|
|
parser::Messages buffer;
|
|
|
|
|
auto restorer{foldingContext_.messages().SetMessages(buffer)};
|
|
|
|
|
auto restorer{GetContextualMessages().SetMessages(buffer)};
|
|
|
|
|
ActualArguments localActuals{actuals};
|
|
|
|
|
if (context_.intrinsics().Probe(
|
|
|
|
|
CallCharacteristics{ultimate.name().ToString(), isSubroutine},
|
|
|
|
|
localActuals, foldingContext_) &&
|
|
|
|
|
!buffer.AnyFatalError()) {
|
|
|
|
|
return {&ultimate, false};
|
|
|
|
|
explicitIntrinsic = &ultimate;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (const auto *details{ultimate.detailsIf<semantics::GenericDetails>()}) {
|
|
|
|
|
for (const Symbol &specific0 : details->specificProcs()) {
|
|
|
|
|
const Symbol *elemental{nullptr}; // matching elemental specific proc
|
|
|
|
|
const Symbol *nonElemental{nullptr}; // matching non-elemental specific
|
|
|
|
|
const auto *genericDetails{ultimate.detailsIf<semantics::GenericDetails>()};
|
|
|
|
|
if (genericDetails && !explicitIntrinsic) {
|
|
|
|
|
int crtMatchingDistance{cudaInfMatchingValue};
|
|
|
|
|
for (const Symbol &specific0 : genericDetails->specificProcs()) {
|
|
|
|
|
const Symbol &specific1{BypassGeneric(specific0)};
|
|
|
|
|
if (isSubroutine != !IsFunction(specific1)) {
|
|
|
|
|
continue;
|
|
|
|
|
@@ -2911,24 +2927,92 @@ std::pair<const Symbol *, bool> ExpressionAnalyzer::ResolveGeneric(
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (nonElemental) {
|
|
|
|
|
return {&AccessSpecific(symbol, *nonElemental), false};
|
|
|
|
|
} else if (elemental) {
|
|
|
|
|
return {&AccessSpecific(symbol, *elemental), false};
|
|
|
|
|
}
|
|
|
|
|
// Check parent derived type
|
|
|
|
|
if (const auto *parentScope{symbol.owner().GetDerivedTypeParent()}) {
|
|
|
|
|
if (const Symbol *extended{parentScope->FindComponent(symbol.name())}) {
|
|
|
|
|
auto pair{ResolveGeneric(
|
|
|
|
|
*extended, actuals, adjustActuals, isSubroutine, false)};
|
|
|
|
|
if (pair.first) {
|
|
|
|
|
return pair;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Is there a derived type of the same name?
|
|
|
|
|
const Symbol *derivedType{nullptr};
|
|
|
|
|
if (mightBeStructureConstructor && !isSubroutine && genericDetails) {
|
|
|
|
|
if (const Symbol * dt{genericDetails->derivedType()}) {
|
|
|
|
|
const Symbol &ultimate{dt->GetUltimate()};
|
|
|
|
|
if (ultimate.has<semantics::DerivedTypeDetails>()) {
|
|
|
|
|
derivedType = &ultimate;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (mightBeStructureConstructor && details->derivedType()) {
|
|
|
|
|
return {details->derivedType(), false};
|
|
|
|
|
}
|
|
|
|
|
// F'2023 C7108 checking. No Fortran compiler actually enforces this
|
|
|
|
|
// constraint, so it's just a portability warning here.
|
|
|
|
|
if (derivedType && (explicitIntrinsic || nonElemental || elemental) &&
|
|
|
|
|
context_.ShouldWarn(
|
|
|
|
|
common::LanguageFeature::AmbiguousStructureConstructor)) {
|
|
|
|
|
// See whethr there's ambiguity with a structure constructor.
|
|
|
|
|
bool possiblyAmbiguous{true};
|
|
|
|
|
if (const semantics::Scope * dtScope{derivedType->scope()}) {
|
|
|
|
|
parser::Messages buffer;
|
|
|
|
|
auto restorer{GetContextualMessages().SetMessages(buffer)};
|
|
|
|
|
std::list<ComponentSpec> componentSpecs;
|
|
|
|
|
for (const auto &actual : actuals) {
|
|
|
|
|
if (actual) {
|
|
|
|
|
ComponentSpec compSpec;
|
|
|
|
|
if (const Expr<SomeType> *expr{actual->UnwrapExpr()}) {
|
|
|
|
|
compSpec.expr = *expr;
|
|
|
|
|
} else {
|
|
|
|
|
possiblyAmbiguous = false;
|
|
|
|
|
}
|
|
|
|
|
if (auto loc{actual->sourceLocation()}) {
|
|
|
|
|
compSpec.source = compSpec.exprSource = *loc;
|
|
|
|
|
}
|
|
|
|
|
if (auto kw{actual->keyword()}) {
|
|
|
|
|
compSpec.hasKeyword = true;
|
|
|
|
|
compSpec.keywordSymbol = dtScope->FindComponent(*kw);
|
|
|
|
|
}
|
|
|
|
|
componentSpecs.emplace_back(std::move(compSpec));
|
|
|
|
|
} else {
|
|
|
|
|
possiblyAmbiguous = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
semantics::DerivedTypeSpec dtSpec{derivedType->name(), *derivedType};
|
|
|
|
|
dtSpec.set_scope(*dtScope);
|
|
|
|
|
possiblyAmbiguous = possiblyAmbiguous &&
|
|
|
|
|
CheckStructureConstructor(
|
|
|
|
|
derivedType->name(), dtSpec, std::move(componentSpecs))
|
|
|
|
|
.has_value() &&
|
|
|
|
|
!buffer.AnyFatalError();
|
|
|
|
|
}
|
|
|
|
|
if (possiblyAmbiguous) {
|
|
|
|
|
if (explicitIntrinsic) {
|
|
|
|
|
Warn(common::LanguageFeature::AmbiguousStructureConstructor,
|
|
|
|
|
"Reference to the intrinsic function '%s' is ambiguous with a structure constructor of the same name"_port_en_US,
|
|
|
|
|
symbol.name());
|
|
|
|
|
} else {
|
|
|
|
|
Warn(common::LanguageFeature::AmbiguousStructureConstructor,
|
|
|
|
|
"Reference to generic function '%s' (resolving to specific '%s') is ambiguous with a structure constructor of the same name"_port_en_US,
|
|
|
|
|
symbol.name(),
|
|
|
|
|
nonElemental ? nonElemental->name() : elemental->name());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Return the right resolution, if there is one. Explicit intrinsics
|
|
|
|
|
// are preferred, then non-elements specifics, then elementals, and
|
|
|
|
|
// lastly structure constructors.
|
|
|
|
|
if (explicitIntrinsic) {
|
|
|
|
|
return {explicitIntrinsic, false};
|
|
|
|
|
} else if (nonElemental) {
|
|
|
|
|
return {&AccessSpecific(symbol, *nonElemental), false};
|
|
|
|
|
} else if (elemental) {
|
|
|
|
|
return {&AccessSpecific(symbol, *elemental), false};
|
|
|
|
|
}
|
|
|
|
|
// Check parent derived type
|
|
|
|
|
if (const auto *parentScope{symbol.owner().GetDerivedTypeParent()}) {
|
|
|
|
|
if (const Symbol * extended{parentScope->FindComponent(symbol.name())}) {
|
|
|
|
|
auto pair{ResolveGeneric(
|
|
|
|
|
*extended, actuals, adjustActuals, isSubroutine, false)};
|
|
|
|
|
if (pair.first) {
|
|
|
|
|
return pair;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Structure constructor?
|
|
|
|
|
if (derivedType) {
|
|
|
|
|
return {derivedType, false};
|
|
|
|
|
}
|
|
|
|
|
// Check for generic or explicit INTRINSIC of the same name in outer scopes.
|
|
|
|
|
// See 15.5.5.2 for details.
|
|
|
|
|
|