[flang] More miscellaneous name resolution
Resolve the index name in a FORALL, DO, or DO CONCURRENT. Handle pointer-stmt. Add DeclareUnknownEntity() to declare an entity that is not yet know to be an object or procedure. This is used in the EntityDecl and PointerDecl cases. When an array element assignment is mistakenly parsed as a statement function, ensure the index names are resolved. Detect erroneous use-association with local name that matches the name of the containing subprogram. Cleanup: Eliminate GetVariableName() and CheckImplicitSymbol() in favor of using the Resolve* functions consistently. Add ResolveName() to do what CheckImplicitSymbol() used to do. Disable warnings about unresolved names for some categories of constructs that are not yet implemented: common blocks, namelist statements, etc. These will be turned back on when they are implemented. Original-commit: flang-compiler/f18@9a41bf37fd Reviewed-on: https://github.com/flang-compiler/f18/pull/210
This commit is contained in:
parent
7db04a4c05
commit
edf9eec265
|
@ -343,8 +343,7 @@ public:
|
|||
derivedType = &currScope().MakeSymbol(name, attrs, details);
|
||||
d->set_derivedType(*derivedType);
|
||||
} else {
|
||||
Say2(name, "'%s' is already declared in this scoping unit"_err_en_US,
|
||||
derivedType->name(), "Previous declaration of '%s'"_en_US);
|
||||
SayAlreadyDeclared(name, *derivedType);
|
||||
}
|
||||
return *derivedType;
|
||||
}
|
||||
|
@ -468,7 +467,7 @@ private:
|
|||
|
||||
class SubprogramVisitor : public InterfaceVisitor {
|
||||
public:
|
||||
bool Pre(const parser::StmtFunctionStmt &);
|
||||
bool HandleStmtFunction(const parser::StmtFunctionStmt &);
|
||||
void Post(const parser::StmtFunctionStmt &);
|
||||
bool Pre(const parser::SubroutineStmt &);
|
||||
void Post(const parser::SubroutineStmt &);
|
||||
|
@ -508,6 +507,7 @@ public:
|
|||
|
||||
void Post(const parser::EntityDecl &);
|
||||
void Post(const parser::ObjectDecl &);
|
||||
void Post(const parser::PointerDecl &);
|
||||
|
||||
bool Pre(const parser::BindStmt &) { return BeginAttrs(); }
|
||||
void Post(const parser::BindStmt &) { EndAttrs(); }
|
||||
|
@ -584,6 +584,7 @@ private:
|
|||
|
||||
bool HandleAttributeStmt(Attr, const std::list<parser::Name> &);
|
||||
Symbol &HandleAttributeStmt(Attr, const SourceName &);
|
||||
void DeclareUnknownEntity(const SourceName &, Attrs);
|
||||
void DeclareObjectEntity(const SourceName &, Attrs);
|
||||
void DeclareProcEntity(const SourceName &, Attrs, const ProcInterface &);
|
||||
void SetType(const SourceName &, Symbol &, const DeclTypeSpec &);
|
||||
|
@ -719,46 +720,32 @@ public:
|
|||
bool Pre(const parser::BlockStmt &);
|
||||
bool Pre(const parser::EndBlockStmt &);
|
||||
bool Pre(const parser::ImplicitStmt &);
|
||||
|
||||
void Post(const parser::AllocateObject &x) {
|
||||
CheckImplicitSymbol(std::get_if<parser::Name>(&x.u));
|
||||
}
|
||||
void Post(const parser::PointerAssignmentStmt &x) {
|
||||
ResolveDataRef(std::get<parser::DataRef>(x.t));
|
||||
}
|
||||
void Post(const parser::Expr &x) { CheckImplicitSymbol(GetVariableName(x)); }
|
||||
void Post(const parser::Variable &x) {
|
||||
CheckImplicitSymbol(GetVariableName(x));
|
||||
}
|
||||
template<typename T> void Post(const parser::LoopBounds<T> &x) {
|
||||
CheckImplicitSymbol(&x.name.thing.thing);
|
||||
}
|
||||
bool Pre(const parser::StructureComponent &);
|
||||
void Post(const parser::PointerObject &);
|
||||
void Post(const parser::AllocateObject &);
|
||||
void Post(const parser::PointerAssignmentStmt &);
|
||||
void Post(const parser::Designator &);
|
||||
template<typename T> void Post(const parser::LoopBounds<T> &);
|
||||
void Post(const parser::ConcurrentControl &);
|
||||
void Post(const parser::ProcComponentRef &);
|
||||
void Post(const parser::ProcedureDesignator &);
|
||||
bool Pre(const parser::FunctionReference &);
|
||||
void Post(const parser::FunctionReference &);
|
||||
bool Pre(const parser::CallStmt &);
|
||||
void Post(const parser::CallStmt &);
|
||||
bool Pre(const parser::ImportStmt &);
|
||||
void Post(const parser::TypeGuardStmt &x) {
|
||||
DeclTypeSpecVisitor::Post(x);
|
||||
ConstructNamesVisitor::Post(x);
|
||||
}
|
||||
void Post(const parser::TypeGuardStmt &);
|
||||
bool Pre(const parser::StmtFunctionStmt &);
|
||||
|
||||
private:
|
||||
// Kind of procedure we are expecting to see in a ProcedureDesignator
|
||||
std::optional<Symbol::Flag> expectedProcFlag_;
|
||||
const SourceName *prevImportStmt_{nullptr};
|
||||
|
||||
const parser::Name *GetVariableName(const parser::DataRef &);
|
||||
const parser::Name *GetVariableName(const parser::Designator &);
|
||||
const parser::Name *GetVariableName(const parser::Expr &);
|
||||
const parser::Name *GetVariableName(const parser::Variable &);
|
||||
const Symbol *CheckImplicitSymbol(const parser::Name *);
|
||||
Symbol *ResolveStructureComponent(const parser::StructureComponent &);
|
||||
Symbol *ResolveArrayElement(const parser::ArrayElement &);
|
||||
Symbol *ResolveCoindexedNamedObject(const parser::CoindexedNamedObject &);
|
||||
Symbol *ResolveDataRef(const parser::DataRef &);
|
||||
Symbol *ResolveName(const SourceName &);
|
||||
Symbol *FindComponent(Symbol &, const SourceName &);
|
||||
Symbol *FindComponent(const Scope &, const SourceName &);
|
||||
bool CheckAccessibleComponent(const Symbol &);
|
||||
|
@ -930,6 +917,7 @@ bool DeclTypeSpecVisitor::Pre(const parser::DeclarationTypeSpec::Record &x) {
|
|||
|
||||
void DeclTypeSpecVisitor::Post(const parser::StructureConstructor &) {
|
||||
// TODO: StructureConstructor
|
||||
// TODO: name in derived type spec must be resolved
|
||||
derivedTypeSpec_ = nullptr;
|
||||
}
|
||||
bool DeclTypeSpecVisitor::Pre(const parser::AllocateStmt &) {
|
||||
|
@ -1290,15 +1278,26 @@ void ScopeHandler::EraseSymbol(const SourceName &name) {
|
|||
currScope().erase(name);
|
||||
}
|
||||
|
||||
static bool NeedsType(const Symbol &symbol) {
|
||||
if (symbol.GetType()) {
|
||||
return false;
|
||||
}
|
||||
if (auto *details{symbol.detailsIf<ProcEntityDetails>()}) {
|
||||
if (details->interface().symbol()) {
|
||||
return false; // the interface determines the type
|
||||
}
|
||||
if (!symbol.test(Symbol::Flag::Function)) {
|
||||
return false; // not known to be a function
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void ScopeHandler::ApplyImplicitRules(Symbol &symbol) {
|
||||
ConvertToObjectEntity(symbol);
|
||||
if (symbol.GetType()) {
|
||||
// already has a type
|
||||
} else if (symbol.has<ProcEntityDetails>() &&
|
||||
!symbol.test(Symbol::Flag::Function)) {
|
||||
// a procedure that is not known to be a function
|
||||
} else if (const auto type{GetImplicitType(symbol)}) {
|
||||
symbol.SetType(*type);
|
||||
if (NeedsType(symbol)) {
|
||||
if (const auto type{GetImplicitType(symbol)}) {
|
||||
symbol.SetType(*type);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::optional<const DeclTypeSpec> ScopeHandler::GetImplicitType(
|
||||
|
@ -1451,8 +1450,14 @@ void ModuleVisitor::AddUse(const SourceName &location,
|
|||
}
|
||||
} else if (auto *details{localSymbol.detailsIf<UseErrorDetails>()}) {
|
||||
details->add_occurrence(location, *useModuleScope_);
|
||||
} else if (!localSymbol.has<UnknownDetails>()) {
|
||||
auto name{localName.ToString()};
|
||||
Say(location,
|
||||
"Cannot use-associate '%s'; it is already declared in this scope"_err_en_US,
|
||||
name.c_str())
|
||||
.Attach(localSymbol.name(), "Previous declaration of '%s'"_en_US,
|
||||
name.c_str());
|
||||
} else {
|
||||
CHECK(localSymbol.has<UnknownDetails>());
|
||||
localSymbol.set_details(UseDetails{location, useSymbol});
|
||||
}
|
||||
}
|
||||
|
@ -1754,23 +1759,28 @@ void InterfaceVisitor::CheckGenericProcedures(Symbol &generic) {
|
|||
|
||||
// SubprogramVisitor implementation
|
||||
|
||||
bool SubprogramVisitor::Pre(const parser::StmtFunctionStmt &x) {
|
||||
void SubprogramVisitor::Post(const parser::StmtFunctionStmt &x) {
|
||||
if (badStmtFuncFound_) {
|
||||
return; // This wasn't really a stmt function so no scope was created
|
||||
}
|
||||
PopScope();
|
||||
}
|
||||
// Return false if it is actually an assignment statement.
|
||||
bool SubprogramVisitor::HandleStmtFunction(const parser::StmtFunctionStmt &x) {
|
||||
const auto &name{std::get<parser::Name>(x.t)};
|
||||
std::optional<SourceName> occurrence;
|
||||
std::optional<DeclTypeSpec> resultType;
|
||||
// Look up name: provides return type or tells us if it's an array
|
||||
if (auto *symbol{FindSymbol(name.source)}) {
|
||||
if (auto *details{symbol->detailsIf<EntityDetails>()}) {
|
||||
// TODO: check that attrs are compatible with stmt func
|
||||
resultType = details->type();
|
||||
occurrence = symbol->name();
|
||||
EraseSymbol(symbol->name());
|
||||
} else if (symbol->has<ObjectEntityDetails>()) {
|
||||
// not a stmt-func at all but an array; do nothing
|
||||
symbol->add_occurrence(name.source);
|
||||
auto *details{symbol->detailsIf<EntityDetails>()};
|
||||
if (!details) {
|
||||
badStmtFuncFound_ = true;
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
// TODO: check that attrs are compatible with stmt func
|
||||
resultType = details->type();
|
||||
occurrence = symbol->name();
|
||||
EraseSymbol(symbol->name());
|
||||
}
|
||||
if (badStmtFuncFound_) {
|
||||
Say(name, "'%s' has not been declared as an array"_err_en_US);
|
||||
|
@ -1802,13 +1812,6 @@ bool SubprogramVisitor::Pre(const parser::StmtFunctionStmt &x) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void SubprogramVisitor::Post(const parser::StmtFunctionStmt &x) {
|
||||
if (badStmtFuncFound_) {
|
||||
return; // This wasn't really a stmt function so no scope was created
|
||||
}
|
||||
PopScope();
|
||||
}
|
||||
|
||||
bool SubprogramVisitor::Pre(const parser::Suffix &suffix) {
|
||||
if (suffix.resultName) {
|
||||
funcResultName_ = &suffix.resultName.value();
|
||||
|
@ -2020,17 +2023,12 @@ void DeclarationVisitor::Post(const parser::EntityDecl &x) {
|
|||
const auto &name{std::get<parser::ObjectName>(x.t).source};
|
||||
// TODO: CoarraySpec, CharLength, Initialization
|
||||
Attrs attrs{attrs_ ? *attrs_ : Attrs{}};
|
||||
if (!arraySpec().empty()) {
|
||||
DeclareObjectEntity(name, attrs);
|
||||
} else {
|
||||
Symbol &symbol{DeclareEntity<EntityDetails>(name, attrs)};
|
||||
if (auto &type{GetDeclTypeSpec()}) {
|
||||
SetType(name, symbol, *type);
|
||||
}
|
||||
if (symbol.attrs().test(Attr::EXTERNAL)) {
|
||||
ConvertToProcEntity(symbol);
|
||||
}
|
||||
}
|
||||
DeclareUnknownEntity(name, attrs);
|
||||
}
|
||||
|
||||
void DeclarationVisitor::Post(const parser::PointerDecl &x) {
|
||||
const auto &name{std::get<parser::Name>(x.t).source};
|
||||
DeclareUnknownEntity(name, Attrs{Attr::POINTER});
|
||||
}
|
||||
|
||||
bool DeclarationVisitor::Pre(const parser::BindEntity &x) {
|
||||
|
@ -2121,6 +2119,22 @@ void DeclarationVisitor::Post(const parser::ObjectDecl &x) {
|
|||
DeclareObjectEntity(name.source, Attrs{*objectDeclAttr_});
|
||||
}
|
||||
|
||||
// Declare an entity not yet known to be an object or proc.
|
||||
void DeclarationVisitor::DeclareUnknownEntity(
|
||||
const SourceName &name, Attrs attrs) {
|
||||
if (!arraySpec().empty()) {
|
||||
DeclareObjectEntity(name, attrs);
|
||||
} else {
|
||||
Symbol &symbol{DeclareEntity<EntityDetails>(name, attrs)};
|
||||
if (auto &type{GetDeclTypeSpec()}) {
|
||||
SetType(name, symbol, *type);
|
||||
}
|
||||
if (symbol.attrs().test(Attr::EXTERNAL)) {
|
||||
ConvertToProcEntity(symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DeclarationVisitor::DeclareProcEntity(
|
||||
const SourceName &name, Attrs attrs, const ProcInterface &interface) {
|
||||
Symbol &symbol{DeclareEntity<ProcEntityDetails>(name, attrs)};
|
||||
|
@ -2599,11 +2613,6 @@ bool ResolveNamesVisitor::Pre(const parser::ImportStmt &x) {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool ResolveNamesVisitor::Pre(const parser::StructureComponent &x) {
|
||||
ResolveStructureComponent(x);
|
||||
return false;
|
||||
}
|
||||
|
||||
Symbol *ResolveNamesVisitor::ResolveStructureComponent(
|
||||
const parser::StructureComponent &x) {
|
||||
Symbol *dataRef{ResolveDataRef(x.base)};
|
||||
|
@ -2611,6 +2620,10 @@ Symbol *ResolveNamesVisitor::ResolveStructureComponent(
|
|||
}
|
||||
Symbol *ResolveNamesVisitor::ResolveArrayElement(
|
||||
const parser::ArrayElement &x) {
|
||||
// TODO: need to resolve these
|
||||
// for (auto &subscript : x.subscripts) {
|
||||
// ResolveSectionSubscript(subscript);
|
||||
//}
|
||||
return ResolveDataRef(x.base);
|
||||
}
|
||||
Symbol *ResolveNamesVisitor::ResolveCoindexedNamedObject(
|
||||
|
@ -2621,20 +2634,7 @@ Symbol *ResolveNamesVisitor::ResolveCoindexedNamedObject(
|
|||
Symbol *ResolveNamesVisitor::ResolveDataRef(const parser::DataRef &x) {
|
||||
return std::visit(
|
||||
common::visitors{
|
||||
[=](const parser::Name &y) {
|
||||
auto *symbol{FindSymbol(y.source)};
|
||||
if (!symbol) {
|
||||
if (isImplicitNoneType()) {
|
||||
Say(y.source, "No explicit type declared for '%s'"_err_en_US);
|
||||
} else {
|
||||
auto pair{InclusiveScope().try_emplace(y.source)};
|
||||
CHECK(pair.second);
|
||||
symbol = pair.first->second;
|
||||
ApplyImplicitRules(*symbol);
|
||||
}
|
||||
}
|
||||
return symbol;
|
||||
},
|
||||
[=](const parser::Name &y) { return ResolveName(y.source); },
|
||||
[=](const common::Indirection<parser::StructureComponent> &y) {
|
||||
return ResolveStructureComponent(*y);
|
||||
},
|
||||
|
@ -2648,6 +2648,31 @@ Symbol *ResolveNamesVisitor::ResolveDataRef(const parser::DataRef &x) {
|
|||
x.u);
|
||||
}
|
||||
|
||||
// If implicit types are allowed, ensure name is in the symbol table.
|
||||
// Otherwise, report an error if it hasn't been declared.
|
||||
Symbol *ResolveNamesVisitor::ResolveName(const SourceName &name) {
|
||||
if (auto *symbol{FindSymbol(name)}) {
|
||||
if (CheckUseError(name, *symbol)) {
|
||||
return nullptr; // reported an error
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
if (isImplicitNoneType()) {
|
||||
Say(name, "No explicit type declared for '%s'"_err_en_US);
|
||||
return nullptr;
|
||||
}
|
||||
// Create the symbol then ensure it is accessible
|
||||
InclusiveScope().try_emplace(name);
|
||||
auto *symbol{FindSymbol(name)};
|
||||
if (!symbol) {
|
||||
Say(name,
|
||||
"'%s' from host scoping unit is not accessible due to IMPORT"_err_en_US);
|
||||
return nullptr;
|
||||
}
|
||||
ApplyImplicitRules(*symbol);
|
||||
return symbol;
|
||||
}
|
||||
|
||||
// base is a part-ref of a derived type; find the named component in its type.
|
||||
Symbol *ResolveNamesVisitor::FindComponent(
|
||||
Symbol &base, const SourceName &component) {
|
||||
|
@ -2960,81 +2985,64 @@ bool ResolveNamesVisitor::Pre(const parser::ImplicitStmt &x) {
|
|||
}
|
||||
return ImplicitRulesVisitor::Pre(x);
|
||||
}
|
||||
|
||||
const parser::Name *ResolveNamesVisitor::GetVariableName(
|
||||
const parser::DataRef &x) {
|
||||
return std::visit(
|
||||
void ResolveNamesVisitor::Post(const parser::PointerObject &x) {
|
||||
std::visit(
|
||||
common::visitors{
|
||||
[](const parser::Name &x) { return &x; },
|
||||
[&](const common::Indirection<parser::ArrayElement> &x) {
|
||||
return GetVariableName(x->base);
|
||||
},
|
||||
[](const auto &) {
|
||||
return static_cast<const parser::Name *>(nullptr);
|
||||
[&](const parser::Name &x) { ResolveName(x.source); },
|
||||
[&](const parser::StructureComponent &x) {
|
||||
ResolveStructureComponent(x);
|
||||
},
|
||||
},
|
||||
x.u);
|
||||
}
|
||||
|
||||
const parser::Name *ResolveNamesVisitor::GetVariableName(
|
||||
const parser::Designator &x) {
|
||||
return std::visit(
|
||||
void ResolveNamesVisitor::Post(const parser::AllocateObject &x) {
|
||||
std::visit(
|
||||
common::visitors{
|
||||
[](const parser::ObjectName &x) { return &x; },
|
||||
[&](const parser::DataRef &x) { return GetVariableName(x); },
|
||||
[&](const parser::Name &x) { ResolveName(x.source); },
|
||||
[&](const parser::StructureComponent &x) {
|
||||
ResolveStructureComponent(x);
|
||||
},
|
||||
},
|
||||
x.u);
|
||||
}
|
||||
void ResolveNamesVisitor::Post(const parser::PointerAssignmentStmt &x) {
|
||||
ResolveDataRef(std::get<parser::DataRef>(x.t));
|
||||
}
|
||||
void ResolveNamesVisitor::Post(const parser::Designator &x) {
|
||||
std::visit(
|
||||
common::visitors{
|
||||
[&](const parser::ObjectName &x) { ResolveName(x.source); },
|
||||
[&](const parser::DataRef &x) { ResolveDataRef(x); },
|
||||
[&](const parser::Substring &x) {
|
||||
return GetVariableName(std::get<parser::DataRef>(x.t));
|
||||
ResolveDataRef(std::get<parser::DataRef>(x.t));
|
||||
// TODO: SubstringRange
|
||||
},
|
||||
},
|
||||
x.u);
|
||||
}
|
||||
const parser::Name *ResolveNamesVisitor::GetVariableName(
|
||||
const parser::Expr &x) {
|
||||
if (const auto *designator{
|
||||
std::get_if<common::Indirection<parser::Designator>>(&x.u)}) {
|
||||
return GetVariableName(**designator);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
template<typename T>
|
||||
void ResolveNamesVisitor::Post(const parser::LoopBounds<T> &x) {
|
||||
ResolveName(x.name.thing.thing.source);
|
||||
}
|
||||
const parser::Name *ResolveNamesVisitor::GetVariableName(
|
||||
const parser::Variable &x) {
|
||||
if (const auto *designator{
|
||||
std::get_if<common::Indirection<parser::Designator>>(&x.u)}) {
|
||||
return GetVariableName(**designator);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
void ResolveNamesVisitor::Post(const parser::ProcComponentRef &x) {
|
||||
ResolveStructureComponent(x.v.thing);
|
||||
}
|
||||
|
||||
// If implicit types are allowed, ensure name is in the symbol table.
|
||||
// Otherwise, report an error if it hasn't been declared.
|
||||
const Symbol *ResolveNamesVisitor::CheckImplicitSymbol(
|
||||
const parser::Name *name) {
|
||||
if (!name) {
|
||||
return nullptr;
|
||||
}
|
||||
if (const auto *symbol{FindSymbol(name->source)}) {
|
||||
if (CheckUseError(name->source, *symbol) ||
|
||||
!symbol->has<UnknownDetails>()) {
|
||||
return nullptr; // reported an error or symbol is declared
|
||||
void ResolveNamesVisitor::Post(const parser::TypeGuardStmt &x) {
|
||||
DeclTypeSpecVisitor::Post(x);
|
||||
ConstructNamesVisitor::Post(x);
|
||||
}
|
||||
bool ResolveNamesVisitor::Pre(const parser::StmtFunctionStmt &x) {
|
||||
if (!HandleStmtFunction(x)) {
|
||||
// This is an array element assignment: resolve names of indices
|
||||
const auto &names{std::get<std::list<parser::Name>>(x.t)};
|
||||
for (auto &name : names) {
|
||||
ResolveName(name.source);
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
if (isImplicitNoneType()) {
|
||||
Say(*name, "No explicit type declared for '%s'"_err_en_US);
|
||||
return nullptr;
|
||||
}
|
||||
// Create the symbol then ensure it is accessible
|
||||
InclusiveScope().try_emplace(name->source);
|
||||
auto *symbol{FindSymbol(name->source)};
|
||||
if (!symbol) {
|
||||
Say(name->source,
|
||||
"'%s' from host scoping unit is not accessible due to IMPORT"_err_en_US);
|
||||
return nullptr;
|
||||
}
|
||||
ApplyImplicitRules(*symbol);
|
||||
return symbol;
|
||||
return true;
|
||||
}
|
||||
void ResolveNamesVisitor::Post(const parser::ConcurrentControl &x) {
|
||||
ResolveName(std::get<parser::Name>(x.t).source);
|
||||
}
|
||||
|
||||
void ResolveNamesVisitor::Post(const parser::Program &) {
|
||||
|
|
|
@ -44,6 +44,16 @@ public:
|
|||
void Post(parser::Variable &x) { ConvertFunctionRef(x); }
|
||||
void Post(parser::Expr &x) { ConvertFunctionRef(x); }
|
||||
|
||||
// Name resolution yet implemented:
|
||||
bool Pre(parser::CommonStmt &) { return false; }
|
||||
bool Pre(parser::NamelistStmt &) { return false; }
|
||||
bool Pre(parser::EquivalenceStmt &) { return false; }
|
||||
bool Pre(parser::BindEntity &) { return false; }
|
||||
bool Pre(parser::Keyword &) { return false; }
|
||||
bool Pre(parser::DataStmtValue &) { return false; }
|
||||
bool Pre(parser::SavedEntity &) { return false; }
|
||||
bool Pre(parser::EntryStmt &) { return false; }
|
||||
|
||||
// Don't bother resolving names in end statements.
|
||||
bool Pre(parser::EndBlockDataStmt &) { return false; }
|
||||
bool Pre(parser::EndFunctionStmt &) { return false; }
|
||||
|
|
|
@ -71,6 +71,7 @@ set(SYMBOL_TESTS
|
|||
symbol05.f90
|
||||
symbol06.f90
|
||||
symbol07.f90
|
||||
symbol08.f90
|
||||
)
|
||||
|
||||
# These test files have expected .mod file contents in the source
|
||||
|
|
|
@ -33,3 +33,13 @@ contains
|
|||
integer :: i
|
||||
end subroutine
|
||||
end module
|
||||
|
||||
subroutine foo
|
||||
!ERROR: Cannot use-associate 'foo'; it is already declared in this scope
|
||||
use m1
|
||||
end
|
||||
|
||||
subroutine bar
|
||||
!ERROR: Cannot use-associate 'bar'; it is already declared in this scope
|
||||
use m1, bar => foo
|
||||
end
|
||||
|
|
26
flang/test/semantics/symbol08.f90
Normal file
26
flang/test/semantics/symbol08.f90
Normal file
|
@ -0,0 +1,26 @@
|
|||
! Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
|
||||
!
|
||||
! Licensed under the Apache License, Version 2.0 (the "License");
|
||||
! you may not use this file except in compliance with the License.
|
||||
! You may obtain a copy of the License at
|
||||
!
|
||||
! http://www.apache.org/licenses/LICENSE-2.0
|
||||
!
|
||||
! Unless required by applicable law or agreed to in writing, software
|
||||
! distributed under the License is distributed on an "AS IS" BASIS,
|
||||
! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
! See the License for the specific language governing permissions and
|
||||
! limitations under the License.
|
||||
|
||||
!DEF: /main MainProgram
|
||||
program main
|
||||
!DEF: /main/x POINTER ObjectEntity REAL(4)
|
||||
pointer :: x
|
||||
real x
|
||||
!DEF: /main/y EXTERNAL, POINTER ProcEntity REAL(4)
|
||||
pointer :: y
|
||||
procedure (real) :: y
|
||||
!DEF: /main/z (implicit) ObjectEntity REAL(4)
|
||||
!REF: /main/y
|
||||
z = y()
|
||||
end program
|
|
@ -39,7 +39,10 @@ diffs=$temp/diffs
|
|||
|
||||
cmd="$CMD $src"
|
||||
( cd $temp; $cmd ) > $log 2>&1
|
||||
[[ $? -ge 128 ]] && exit 1
|
||||
if [[ $? -ge 128 ]]; then
|
||||
cat $log
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# $actual has errors from the compiler; $expect has them from !ERROR comments in source
|
||||
# Format both as "<line>: <text>" so they can be diffed.
|
||||
|
|
Loading…
Reference in a new issue