-
Notifications
You must be signed in to change notification settings - Fork 14.1k
[flang] Handle forward reference to shadowing derived type from IMPLICIT #87280
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
Conversation
A derived type name in an IMPLICIT statement might be a host association or it might be a forward reference to a local derived type, which may be shadowing a host-associated name. Add a scan over the specification part in search of derived type definitions to determine the right interpretation. Fixes llvm#87215.
@llvm/pr-subscribers-flang-semantics Author: Peter Klausler (klausler) ChangesA derived type name in an IMPLICIT statement might be a host association or it might be a forward reference to a local derived type, which may be shadowing a host-associated name. Add a scan over the specification part in search of derived type definitions to determine the right interpretation. Fixes #87215. Full diff: https://github.com/llvm/llvm-project/pull/87280.diff 2 Files Affected:
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 2e88a2daff2c08..dfffb908cde2f8 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -1635,6 +1635,8 @@ class ResolveNamesVisitor : public virtual ScopeHandler,
void FinishDerivedTypeInstantiation(Scope &);
void ResolveExecutionParts(const ProgramTree &);
void UseCUDABuiltinNames();
+ void HandleDerivedTypesInImplicitStmts(const parser::ImplicitPart &,
+ const std::list<parser::DeclarationConstruct> &);
};
// ImplicitRules implementation
@@ -2035,6 +2037,7 @@ bool ImplicitRulesVisitor::Pre(const parser::ImplicitSpec &) {
}
void ImplicitRulesVisitor::Post(const parser::ImplicitSpec &) {
+ set_allowForwardReferenceToDerivedType(false);
EndDeclTypeSpec();
}
@@ -8329,6 +8332,67 @@ static bool NeedsExplicitType(const Symbol &symbol) {
}
}
+void ResolveNamesVisitor::HandleDerivedTypesInImplicitStmts(
+ const parser::ImplicitPart &implicitPart,
+ const std::list<parser::DeclarationConstruct> &decls) {
+ // Detect derived type definitions and create symbols for them now if
+ // they appear in IMPLICIT statements so that these forward-looking
+ // references will not be ambiguous with host associations.
+ std::set<SourceName> implicitDerivedTypes;
+ for (const auto &ipStmt : implicitPart.v) {
+ if (const auto *impl{std::get_if<
+ parser::Statement<common::Indirection<parser::ImplicitStmt>>>(
+ &ipStmt.u)}) {
+ if (const auto *specs{std::get_if<std::list<parser::ImplicitSpec>>(
+ &impl->statement.value().u)}) {
+ for (const auto &spec : *specs) {
+ const auto &declTypeSpec{
+ std::get<parser::DeclarationTypeSpec>(spec.t)};
+ if (const auto *dtSpec{common::visit(
+ common::visitors{
+ [](const parser::DeclarationTypeSpec::Type &x) {
+ return &x.derived;
+ },
+ [](const parser::DeclarationTypeSpec::Class &x) {
+ return &x.derived;
+ },
+ [](const auto &) -> const parser::DerivedTypeSpec * {
+ return nullptr;
+ }},
+ declTypeSpec.u)}) {
+ implicitDerivedTypes.emplace(
+ std::get<parser::Name>(dtSpec->t).source);
+ }
+ }
+ }
+ }
+ }
+ if (!implicitDerivedTypes.empty()) {
+ for (const auto &decl : decls) {
+ if (const auto *spec{
+ std::get_if<parser::SpecificationConstruct>(&decl.u)}) {
+ if (const auto *dtDef{
+ std::get_if<common::Indirection<parser::DerivedTypeDef>>(
+ &spec->u)}) {
+ const parser::DerivedTypeStmt &dtStmt{
+ std::get<parser::Statement<parser::DerivedTypeStmt>>(
+ dtDef->value().t)
+ .statement};
+ const parser::Name &name{std::get<parser::Name>(dtStmt.t)};
+ if (implicitDerivedTypes.find(name.source) !=
+ implicitDerivedTypes.end() &&
+ !FindInScope(name)) {
+ DerivedTypeDetails details;
+ details.set_isForwardReferenced(true);
+ Resolve(name, MakeSymbol(name, std::move(details)));
+ implicitDerivedTypes.erase(name.source);
+ }
+ }
+ }
+ }
+ }
+}
+
bool ResolveNamesVisitor::Pre(const parser::SpecificationPart &x) {
const auto &[accDecls, ompDecls, compilerDirectives, useStmts, importStmts,
implicitPart, decls] = x.t;
@@ -8347,6 +8411,7 @@ bool ResolveNamesVisitor::Pre(const parser::SpecificationPart &x) {
ClearUseOnly();
ClearModuleUses();
Walk(importStmts);
+ HandleDerivedTypesInImplicitStmts(implicitPart, decls);
Walk(implicitPart);
for (const auto &decl : decls) {
if (const auto *spec{
diff --git a/flang/test/Semantics/resolve29.f90 b/flang/test/Semantics/resolve29.f90
index 3e6a8a0ba69763..c6a9b036c5828d 100644
--- a/flang/test/Semantics/resolve29.f90
+++ b/flang/test/Semantics/resolve29.f90
@@ -3,6 +3,7 @@ module m1
type t1
end type
type t3
+ integer t3c
end type
interface
subroutine s1(x)
@@ -64,6 +65,17 @@ subroutine s9()
end type
type(t2) x
end
+ subroutine s10()
+ !Forward shadowing derived type in IMPLICIT
+ !(supported by all other compilers)
+ implicit type(t1) (c) ! forward shadow
+ implicit type(t3) (d) ! host associated
+ type t1
+ integer a
+ end type
+ c%a = 1
+ d%t3c = 2
+ end
end module
module m2
integer, parameter :: ck = kind('a')
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the quick fix!
All builds and tests correctly and looks good.
A derived type name in an IMPLICIT statement might be a host association or it might be a forward reference to a local derived type, which may be shadowing a host-associated name. Add a scan over the specification part in search of derived type definitions to determine the right interpretation.
Fixes #87215.