[flang] More fixes; tests now all pass (with updates to some)

Original-commit: flang-compiler/f18@236ff3a3db
Reviewed-on: https://github.com/flang-compiler/f18/pull/638
Tree-same-pre-rewrite: false
This commit is contained in:
peter klausler 2019-08-08 15:06:51 -07:00
parent da6445198a
commit e071162e04
8 changed files with 92 additions and 97 deletions

View File

@ -763,6 +763,7 @@ public:
const parser::Name &, const parser::InitialDataTarget &); const parser::Name &, const parser::InitialDataTarget &);
void PointerInitialization( void PointerInitialization(
const parser::Name &, const parser::ProcPointerInit &); const parser::Name &, const parser::ProcPointerInit &);
void CheckExplicitInterface(const parser::Name &);
void CheckBindings(const parser::TypeBoundProcedureStmt::WithoutInterface &); void CheckBindings(const parser::TypeBoundProcedureStmt::WithoutInterface &);
protected: protected:
@ -799,8 +800,6 @@ protected:
const parser::Name *ResolveName(const parser::Name &); const parser::Name *ResolveName(const parser::Name &);
bool PassesSharedLocalityChecks(const parser::Name &name, Symbol &symbol); bool PassesSharedLocalityChecks(const parser::Name &name, Symbol &symbol);
Symbol *NoteInterfaceName(const parser::Name &); Symbol *NoteInterfaceName(const parser::Name &);
void CheckExplicitInterface(Symbol &);
void CheckBinding(Symbol &);
private: private:
// The attribute corresponding to the statement containing an ObjectDecl // The attribute corresponding to the statement containing an ObjectDecl
@ -845,7 +844,6 @@ private:
Symbol &DeclareProcEntity(const parser::Name &, Attrs, const ProcInterface &); Symbol &DeclareProcEntity(const parser::Name &, Attrs, const ProcInterface &);
void SetType(const parser::Name &, const DeclTypeSpec &); void SetType(const parser::Name &, const DeclTypeSpec &);
const Symbol *ResolveDerivedType(const parser::Name &); const Symbol *ResolveDerivedType(const parser::Name &);
bool CanBeTypeBoundProc(const Symbol &);
Symbol *MakeTypeSymbol(const SourceName &, Details &&); Symbol *MakeTypeSymbol(const SourceName &, Details &&);
Symbol *MakeTypeSymbol(const parser::Name &, Details &&); Symbol *MakeTypeSymbol(const parser::Name &, Details &&);
bool OkToAddComponent(const parser::Name &, const Symbol * = nullptr); bool OkToAddComponent(const parser::Name &, const Symbol * = nullptr);
@ -1660,7 +1658,8 @@ void ScopeHandler::PopScope() {
// assumed to be objects. // assumed to be objects.
// TODO: Statement functions // TODO: Statement functions
for (auto &pair : currScope()) { for (auto &pair : currScope()) {
ConvertToObjectEntity(*pair.second); Symbol &symbol{*pair.second};
ConvertToObjectEntity(symbol);
} }
SetScope(currScope_->parent()); SetScope(currScope_->parent());
} }
@ -3435,13 +3434,21 @@ void DeclarationVisitor::CheckBindings(
auto &bindingName{std::get<parser::Name>(declaration.t)}; auto &bindingName{std::get<parser::Name>(declaration.t)};
if (Symbol * binding{FindInScope(currScope(), bindingName)}) { if (Symbol * binding{FindInScope(currScope(), bindingName)}) {
if (auto *details{binding->detailsIf<ProcBindingDetails>()}) { if (auto *details{binding->detailsIf<ProcBindingDetails>()}) {
const Symbol &procedure{details->symbol().GetUltimate()}; const Symbol *procedure{FindSubprogram(details->symbol())};
if (!CanBeTypeBoundProc(procedure)) { if (!CanBeTypeBoundProc(procedure)) {
auto &optName{std::get<std::optional<parser::Name>>(declaration.t)}; if (details->symbol().name() != binding->name()) {
const parser::Name &procedureName{optName ? *optName : bindingName}; Say(binding->name(),
SayWithDecl(procedureName, const_cast<Symbol &>(procedure), "The binding of '%s' ('%s') must be either an accessible "
"'%s' is not a module procedure or external procedure" "module procedure or an external procedure with "
" with explicit interface"_err_en_US); "an explicit interface"_err_en_US,
binding->name(), details->symbol().name());
} else {
Say(binding->name(),
"'%s' must be either an accessible module procedure "
"or an external procedure with an explicit interface"_err_en_US,
binding->name());
}
context().SetError(*binding);
} }
} }
} }
@ -4067,55 +4074,23 @@ const Symbol *DeclarationVisitor::ResolveDerivedType(const parser::Name &name) {
return symbol; return symbol;
} }
// Check this symbol suitable as a type-bound procedure - C769
bool DeclarationVisitor::CanBeTypeBoundProc(const Symbol &symbol) {
if (symbol.has<SubprogramNameDetails>()) {
return symbol.owner().kind() == Scope::Kind::Module;
} else if (auto *details{symbol.detailsIf<SubprogramDetails>()}) {
return symbol.owner().kind() == Scope::Kind::Module ||
details->isInterface();
} else if (auto *proc{symbol.detailsIf<ProcEntityDetails>()}) {
return !symbol.IsDummy() && !symbol.attrs().test(Attr::POINTER) &&
proc->HasExplicitInterface();
} else {
return false;
}
}
Symbol *DeclarationVisitor::NoteInterfaceName(const parser::Name &name) { Symbol *DeclarationVisitor::NoteInterfaceName(const parser::Name &name) {
// The symbol is checked later by CheckExplicitInterface() or // The symbol is checked later by CheckExplicitInterface() and
// CheckBinding() to ensure that it defines an explicit interface // CheckBindings(). It can be a forward reference.
// or binds to a procedure. The name can be a forward reference.
if (!NameIsKnownOrIntrinsic(name)) { if (!NameIsKnownOrIntrinsic(name)) {
Resolve(name, MakeSymbol(InclusiveScope(), name.source, Attrs{})); Symbol &symbol{MakeSymbol(InclusiveScope(), name.source, Attrs{})};
Resolve(name, symbol);
} }
return name.symbol; return name.symbol;
} }
void DeclarationVisitor::CheckExplicitInterface(Symbol &symbol) { void DeclarationVisitor::CheckExplicitInterface(const parser::Name &name) {
if (const Symbol * interface{FindInterface(symbol)}) { if (const Symbol * symbol{name.symbol}) {
const Symbol *subp{FindSubprogram(*interface)}; if (!symbol->HasExplicitInterface()) {
if (subp == nullptr || !subp->HasExplicitInterface()) { Say(name,
Say(symbol.name(), "'%s' must be an abstract interface or a procedure with "
"The interface of '%s' ('%s') is not an abstract interface or a " "an explicit interface"_err_en_US,
"procedure with an explicit interface"_err_en_US, symbol->name());
symbol.name(), interface->name());
context().SetError(symbol);
}
}
}
void DeclarationVisitor::CheckBinding(Symbol &symbol) {
if (const auto *details{symbol.detailsIf<ProcBindingDetails>()}) {
const Symbol &binding{details->symbol()};
const Symbol *subp{FindSubprogram(binding)};
if (subp == nullptr || !subp->HasExplicitInterface() || IsDummy(*subp) ||
IsProcedurePointer(*subp)) {
Say(symbol.name(),
"The binding of '%s' ('%s') is not a "
"procedure with an explicit interface"_err_en_US,
symbol.name(), binding.name());
context().SetError(symbol);
} }
} }
} }
@ -4764,11 +4739,6 @@ const parser::Name *DeclarationVisitor::ResolveName(const parser::Name &name) {
} }
return &name; return &name;
} }
// TODO pmk: if in a variable or component initialization with deferred
// semantic analysis, just MakeSymbol() for now and don't apply any
// implicit typing rules. Then do object conversion and implicit
// typing (or not) in DeferredInitializationHelper (taking Pointer
// out of the name). Still not sure how to deal with PDT components.
if (isImplicitNoneType()) { if (isImplicitNoneType()) {
Say(name, "No explicit type declared for '%s'"_err_en_US); Say(name, "No explicit type declared for '%s'"_err_en_US);
return nullptr; return nullptr;
@ -5027,7 +4997,7 @@ void DeclarationVisitor::PointerInitialization(
details.set_init(*targetName->symbol); details.set_init(*targetName->symbol);
} }
} else { } else {
details.set_init(nullptr); // NULL() details.set_init(nullptr); // explicit NULL()
} }
} else { } else {
Say(name, Say(name,
@ -5074,9 +5044,7 @@ void ResolveNamesVisitor::HandleProcedureName(
} }
MakeExternal(*symbol); MakeExternal(*symbol);
} }
if (!symbol->has<ProcEntityDetails>()) { ConvertToProcEntity(*symbol);
ConvertToProcEntity(*symbol);
}
SetProcFlag(name, *symbol, flag); SetProcFlag(name, *symbol, flag);
} else if (symbol->has<UnknownDetails>()) { } else if (symbol->has<UnknownDetails>()) {
CHECK(!"unexpected UnknownDetails"); CHECK(!"unexpected UnknownDetails");
@ -5525,12 +5493,13 @@ bool ResolveNamesVisitor::BeginScope(const ProgramTree &node) {
} }
} }
// The processing of initializers of pointers is deferred until all of // Some analyses and checks, such as the processing of initializers of
// the pertinent specification parts have been visited. This deferred // pointers, is deferred until all of the pertinent specification parts
// processing enables the use of forward references in those initializers. // have been visited. This deferred processing enables the use of forward
class DeferredPointerInitializationVisitor { // references in these circumstances.
class DeferredCheckVisitor {
public: public:
explicit DeferredPointerInitializationVisitor(ResolveNamesVisitor &resolver) explicit DeferredCheckVisitor(ResolveNamesVisitor &resolver)
: resolver_{resolver} {} : resolver_{resolver} {}
template<typename A> void Walk(const A &x) { parser::Walk(x, *this); } template<typename A> void Walk(const A &x) { parser::Walk(x, *this); }
@ -5539,7 +5508,7 @@ public:
template<typename A> void Post(const A &) {} template<typename A> void Post(const A &) {}
void Post(const parser::DerivedTypeStmt &x) { void Post(const parser::DerivedTypeStmt &x) {
auto &name{std::get<parser::Name>(x.t)}; const auto &name{std::get<parser::Name>(x.t)};
if (Symbol * symbol{name.symbol}) { if (Symbol * symbol{name.symbol}) {
if (Scope * scope{symbol->scope()}) { if (Scope * scope{symbol->scope()}) {
if (scope->kind() == Scope::Kind::DerivedType) { if (scope->kind() == Scope::Kind::DerivedType) {
@ -5556,6 +5525,11 @@ public:
} }
} }
void Post(const parser::ProcInterface &pi) {
if (const auto *name{std::get_if<parser::Name>(&pi.u)}) {
resolver_.CheckExplicitInterface(*name);
}
}
bool Pre(const parser::EntityDecl &decl) { bool Pre(const parser::EntityDecl &decl) {
Init(std::get<parser::Name>(decl.t), Init(std::get<parser::Name>(decl.t),
std::get<std::optional<parser::Initialization>>(decl.t)); std::get<std::optional<parser::Initialization>>(decl.t));
@ -5573,6 +5547,9 @@ public:
} }
return false; return false;
} }
void Post(const parser::TypeBoundProcedureStmt::WithInterface &tbps) {
resolver_.CheckExplicitInterface(tbps.interfaceName);
}
void Post(const parser::TypeBoundProcedureStmt::WithoutInterface &tbps) { void Post(const parser::TypeBoundProcedureStmt::WithoutInterface &tbps) {
if (pushedScope_) { if (pushedScope_) {
resolver_.CheckBindings(tbps); resolver_.CheckBindings(tbps);
@ -5605,14 +5582,12 @@ void ResolveNamesVisitor::FinishSpecificationParts(const ProgramTree &node) {
// type-bound procedure bindings have not yet been traversed. // type-bound procedure bindings have not yet been traversed.
// We do that now, when any (formerly) forward references that appear // We do that now, when any (formerly) forward references that appear
// in those initializers will resolve to the right symbols. // in those initializers will resolve to the right symbols.
DeferredPointerInitializationVisitor{*this}.Walk(node.spec()); DeferredCheckVisitor{*this}.Walk(node.spec());
DeferredPointerInitializationVisitor{*this}.Walk(node.exec()); // for BLOCK DeferredCheckVisitor{*this}.Walk(node.exec()); // for BLOCK
for (auto &pair : currScope()) { for (auto &pair : currScope()) {
Symbol &symbol{*pair.second}; Symbol &symbol{*pair.second};
if (const auto *details{symbol.detailsIf<GenericDetails>()}) { if (const auto *details{symbol.detailsIf<GenericDetails>()}) {
CheckSpecificsAreDistinguishable(symbol, details->specificProcs()); CheckSpecificsAreDistinguishable(symbol, details->specificProcs());
} else if (symbol.has<ProcEntityDetails>()) {
CheckExplicitInterface(symbol);
} }
} }
// Finish the definitions of derived types and parameterized derived // Finish the definitions of derived types and parameterized derived
@ -5643,7 +5618,7 @@ static int FindIndexOfName(
return -1; return -1;
} }
// Perform checks on procedure bindings of this type // Perform final checks on a derived type and set the pass arguments.
void ResolveNamesVisitor::FinishDerivedTypeDefinition(Scope &scope) { void ResolveNamesVisitor::FinishDerivedTypeDefinition(Scope &scope) {
CHECK(scope.IsDerivedType() && scope.symbol()); CHECK(scope.IsDerivedType() && scope.symbol());
for (auto &pair : scope) { for (auto &pair : scope) {
@ -5652,12 +5627,8 @@ void ResolveNamesVisitor::FinishDerivedTypeDefinition(Scope &scope) {
common::visitors{ common::visitors{
[&](ProcEntityDetails &x) { [&](ProcEntityDetails &x) {
SetPassArg(comp, x.interface().symbol(), x); SetPassArg(comp, x.interface().symbol(), x);
CheckExplicitInterface(comp);
},
[&](ProcBindingDetails &x) {
SetPassArg(comp, &x.symbol(), x);
CheckBinding(comp);
}, },
[&](ProcBindingDetails &x) { SetPassArg(comp, &x.symbol(), x); },
[](auto &) {}, [](auto &) {},
}, },
comp.details()); comp.details());

View File

@ -216,7 +216,7 @@ void Scope::add_importName(const SourceName &name) {
// true if name can be imported or host-associated from parent scope. // true if name can be imported or host-associated from parent scope.
bool Scope::CanImport(const SourceName &name) const { bool Scope::CanImport(const SourceName &name) const {
if (IsGlobal()) { if (IsGlobal() || parent_.IsGlobal()) {
return false; return false;
} }
switch (GetImportKind()) { switch (GetImportKind()) {

View File

@ -418,6 +418,23 @@ bool IsSaved(const Symbol &symbol) {
} }
} }
// Check this symbol suitable as a type-bound procedure - C769
bool CanBeTypeBoundProc(const Symbol *symbol) {
if (symbol == nullptr || IsDummy(*symbol) || IsProcedurePointer(*symbol)) {
return false;
} else if (symbol->has<SubprogramNameDetails>()) {
return symbol->owner().kind() == Scope::Kind::Module;
} else if (auto *details{symbol->detailsIf<SubprogramDetails>()}) {
return symbol->owner().kind() == Scope::Kind::Module ||
details->isInterface();
} else if (const auto *proc{symbol->detailsIf<ProcEntityDetails>()}) {
return !symbol->attrs().test(Attr::INTRINSIC) &&
proc->HasExplicitInterface();
} else {
return false;
}
}
bool IsFinalizable(const Symbol &symbol) { bool IsFinalizable(const Symbol &symbol) {
if (const DeclTypeSpec * type{symbol.GetType()}) { if (const DeclTypeSpec * type{symbol.GetType()}) {
if (const DerivedTypeSpec * derived{type->AsDerived()}) { if (const DerivedTypeSpec * derived{type->AsDerived()}) {

View File

@ -84,6 +84,7 @@ const Symbol *HasEventOrLockPotentialComponent(const DerivedTypeSpec &);
bool IsOrContainsEventOrLockComponent(const Symbol &); bool IsOrContainsEventOrLockComponent(const Symbol &);
// Has an explicit or implied SAVE attribute // Has an explicit or implied SAVE attribute
bool IsSaved(const Symbol &); bool IsSaved(const Symbol &);
bool CanBeTypeBoundProc(const Symbol *);
// Return an ultimate component of type that matches predicate, or nullptr. // Return an ultimate component of type that matches predicate, or nullptr.
const Symbol *FindUltimateComponent( const Symbol *FindUltimateComponent(

View File

@ -119,6 +119,12 @@ end function
program test_typeless program test_typeless
class(*), allocatable :: x class(*), allocatable :: x
interface
subroutine sub
end subroutine
real function func()
end function
end interface
procedure (sub), pointer :: subp => sub procedure (sub), pointer :: subp => sub
procedure (func), pointer :: funcp => func procedure (func), pointer :: funcp => func

View File

@ -25,12 +25,6 @@
! C1120 -- DO variable (and associated expressions) must be INTEGER. ! C1120 -- DO variable (and associated expressions) must be INTEGER.
! This is extended by allowing REAL and DOUBLE PRECISION ! This is extended by allowing REAL and DOUBLE PRECISION
SUBROUTINE sub()
END SUBROUTINE sub
FUNCTION ifunc()
END FUNCTION ifunc
MODULE share MODULE share
INTEGER :: intvarshare INTEGER :: intvarshare
REAL :: realvarshare REAL :: realvarshare
@ -56,6 +50,12 @@ PROGRAM do_issue_458
REAL, POINTER :: prvar REAL, POINTER :: prvar
DOUBLE PRECISION, POINTER :: pdvar DOUBLE PRECISION, POINTER :: pdvar
LOGICAL, POINTER :: plvar LOGICAL, POINTER :: plvar
INTERFACE
SUBROUTINE sub()
END SUBROUTINE sub
FUNCTION ifunc()
END FUNCTION ifunc
END INTERFACE
PROCEDURE(ifunc), POINTER :: pifunc => NULL() PROCEDURE(ifunc), POINTER :: pifunc => NULL()
! DO variables ! DO variables

View File

@ -22,20 +22,20 @@ module m
procedure(integer) :: b procedure(integer) :: b
procedure(foo) :: c procedure(foo) :: c
procedure(bar) :: d procedure(bar) :: d
!ERROR: The interface of 'e' ('missing') is not an abstract interface or a procedure with an explicit interface !ERROR: 'missing' must be an abstract interface or a procedure with an explicit interface
procedure(missing) :: e procedure(missing) :: e
!ERROR: The interface of 'f' ('b') is not an abstract interface or a procedure with an explicit interface !ERROR: 'b' must be an abstract interface or a procedure with an explicit interface
procedure(b) :: f procedure(b) :: f
procedure(c) :: g procedure(c) :: g
external :: h external :: h
!ERROR: The interface of 'i' ('h') is not an abstract interface or a procedure with an explicit interface !ERROR: 'h' must be an abstract interface or a procedure with an explicit interface
procedure(h) :: i procedure(h) :: i
procedure(forward) :: j procedure(forward) :: j
!ERROR: The interface of 'k1' ('bad1') is not an abstract interface or a procedure with an explicit interface !ERROR: 'bad1' must be an abstract interface or a procedure with an explicit interface
procedure(bad1) :: k1 procedure(bad1) :: k1
!ERROR: The interface of 'k2' ('bad2') is not an abstract interface or a procedure with an explicit interface !ERROR: 'bad2' must be an abstract interface or a procedure with an explicit interface
procedure(bad2) :: k2 procedure(bad2) :: k2
!ERROR: The interface of 'k3' ('bad3') is not an abstract interface or a procedure with an explicit interface !ERROR: 'bad3' must be an abstract interface or a procedure with an explicit interface
procedure(bad3) :: k3 procedure(bad3) :: k3
abstract interface abstract interface

View File

@ -35,21 +35,21 @@ module m
type t1 type t1
integer :: c integer :: c
contains contains
!ERROR: Procedure 'missing' not found !ERROR: The binding of 'a' ('missing') must be either an accessible module procedure or an external procedure with an explicit interface
procedure, nopass :: a => missing procedure, nopass :: a => missing
procedure, nopass :: b => s, s2 procedure, nopass :: b => s, s2
!ERROR: 'c' is not a module procedure or external procedure with explicit interface !ERROR: Type parameter, component, or procedure binding 'c' already defined in this type
procedure, nopass :: c procedure, nopass :: c
!ERROR: DEFERRED is only allowed when an interface-name is provided !ERROR: DEFERRED is only allowed when an interface-name is provided
procedure, nopass, deferred :: d => s procedure, nopass, deferred :: d => s
!Note: s3 not found because it's not accessible -- should we issue a message !Note: s3 not found because it's not accessible -- should we issue a message
!to that effect? !to that effect?
!ERROR: Procedure 's3' not found !ERROR: 's3' must be either an accessible module procedure or an external procedure with an explicit interface
procedure, nopass :: s3 procedure, nopass :: s3
procedure, nopass :: foo procedure, nopass :: foo
!ERROR: 'bar' is not a module procedure or external procedure with explicit interface !ERROR: 'bar' must be either an accessible module procedure or an external procedure with an explicit interface
procedure, nopass :: bar procedure, nopass :: bar
!ERROR: 'i' is not a module procedure or external procedure with explicit interface !ERROR: 'i' must be either an accessible module procedure or an external procedure with an explicit interface
procedure, nopass :: i procedure, nopass :: i
!ERROR: Type parameter, component, or procedure binding 'b' already defined in this type !ERROR: Type parameter, component, or procedure binding 'b' already defined in this type
procedure, nopass :: b => s4 procedure, nopass :: b => s4
@ -59,7 +59,7 @@ module m
procedure(foo), nopass, deferred :: f procedure(foo), nopass, deferred :: f
!ERROR: DEFERRED is required when an interface-name is provided !ERROR: DEFERRED is required when an interface-name is provided
procedure(foo), nopass :: g procedure(foo), nopass :: g
!ERROR: The interface of 'h' ('bar') is not an abstract interface or a procedure with an explicit interface !ERROR: 'bar' must be an abstract interface or a procedure with an explicit interface
procedure(bar), nopass, deferred :: h procedure(bar), nopass, deferred :: h
end type end type
type t2 type t2