[flang] Miscellaneous name resolution

Handle BIND statement and PARAMETER statement. They are different from
other attribute-setting statements so some refactoring of
HandleAttributeStmt is required. And for PARAMETER, SetType needs to
report an error if the implicitly determined type is changed later. This
requires operator== on DeclTypeSpec.

Resolve names in allocate statements, pointer assignment statements,
substring expressions, and type parameter values.

Original-commit: flang-compiler/f18@79ad96b976
Reviewed-on: https://github.com/flang-compiler/f18/pull/177
This commit is contained in:
Tim Keith 2018-09-10 12:20:42 -07:00
parent 7ebbe7dca4
commit 7227cfe026
3 changed files with 93 additions and 28 deletions

View File

@ -150,11 +150,13 @@ public:
bool Pre(const parser::IntrinsicTypeSpec::Real &);
bool Pre(const parser::IntrinsicTypeSpec::Complex &);
bool Pre(const parser::IntrinsicTypeSpec::DoublePrecision &);
bool Pre(const parser::IntrinsicTypeSpec::DoubleComplex &);
void Post(const parser::IntrinsicTypeSpec::Character &);
bool Pre(const parser::DeclarationTypeSpec::ClassStar &);
bool Pre(const parser::DeclarationTypeSpec::TypeStar &);
bool Pre(const parser::DeclarationTypeSpec::Record &);
void Post(const parser::TypeParamSpec &);
bool Pre(const parser::TypeParamValue &);
void Post(const parser::TypeParamValue &);
void Post(const parser::StructureConstructor &);
bool Pre(const parser::AllocateStmt &);
void Post(const parser::AllocateStmt &);
@ -500,6 +502,11 @@ public:
void Post(const parser::EntityDecl &);
void Post(const parser::ObjectDecl &);
bool Pre(const parser::BindStmt &) { return BeginAttrs(); }
void Post(const parser::BindStmt &) { EndAttrs(); }
bool Pre(const parser::BindEntity &);
bool Pre(const parser::NamedConstantDef &);
bool Pre(const parser::AsynchronousStmt &);
bool Pre(const parser::ContiguousStmt &);
bool Pre(const parser::ExternalStmt &);
@ -571,6 +578,7 @@ private:
// Handle a statement that sets an attribute on a list of names.
bool HandleAttributeStmt(Attr, const std::list<parser::Name> &);
Symbol &HandleAttributeStmt(Attr, const SourceName &);
void DeclareObjectEntity(const parser::Name &, Attrs);
void DeclareProcEntity(const parser::Name &, Attrs, const ProcInterface &);
bool ConvertToProcEntity(Symbol &);
@ -654,6 +662,12 @@ public:
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));
@ -833,7 +847,7 @@ bool DeclTypeSpecVisitor::Pre(const parser::DeclarationTypeSpec::TypeStar &x) {
void DeclTypeSpecVisitor::Post(const parser::TypeParamSpec &x) {
typeParamValue_.reset();
}
bool DeclTypeSpecVisitor::Pre(const parser::TypeParamValue &x) {
void DeclTypeSpecVisitor::Post(const parser::TypeParamValue &x) {
typeParamValue_ = std::make_unique<ParamValue>(std::visit(
common::visitors{
// TODO: create IntExpr from ScalarIntExpr
@ -844,7 +858,6 @@ bool DeclTypeSpecVisitor::Pre(const parser::TypeParamValue &x) {
},
},
x.u));
return false;
}
bool DeclTypeSpecVisitor::Pre(const parser::DeclarationTypeSpec::Record &x) {
@ -879,6 +892,9 @@ bool DeclTypeSpecVisitor::Pre(const parser::IntegerTypeSpec &x) {
MakeIntrinsic(IntegerTypeSpec::Make(GetKindParamValue(x.v)));
return false;
}
void DeclTypeSpecVisitor::Post(const parser::IntrinsicTypeSpec::Character &x) {
CHECK(!"TODO: character");
}
bool DeclTypeSpecVisitor::Pre(const parser::IntrinsicTypeSpec::Logical &x) {
MakeIntrinsic(LogicalTypeSpec::Make(GetKindParamValue(x.kind)));
return false;
@ -896,6 +912,11 @@ bool DeclTypeSpecVisitor::Pre(
CHECK(!"TODO: double precision");
return false;
}
bool DeclTypeSpecVisitor::Pre(
const parser::IntrinsicTypeSpec::DoubleComplex &) {
CHECK(!"TODO: double complex");
return false;
}
void DeclTypeSpecVisitor::MakeIntrinsic(
const IntrinsicTypeSpec &intrinsicTypeSpec) {
SetDeclTypeSpec(DeclTypeSpec{intrinsicTypeSpec});
@ -1901,6 +1922,24 @@ void DeclarationVisitor::Post(const parser::EntityDecl &x) {
}
}
bool DeclarationVisitor::Pre(const parser::BindEntity &x) {
auto &name{std::get<parser::Name>(x.t)};
if (std::get<parser::BindEntity::Kind>(x.t) ==
parser::BindEntity::Kind::Object) {
HandleAttributeStmt(Attr::BIND_C, name.source);
} else {
// TODO: name is common block
}
return false;
}
bool DeclarationVisitor::Pre(const parser::NamedConstantDef &x) {
auto &name{std::get<parser::NamedConstant>(x.t).v.source};
// TODO: auto &expr{std::get<parser::ConstantExpr>(x.t)};
// TODO: old-style parameters: type based on expr
auto &symbol{HandleAttributeStmt(Attr::PARAMETER, name)};
ApplyImplicitRules(name, symbol);
return false;
}
bool DeclarationVisitor::Pre(const parser::AsynchronousStmt &x) {
return HandleAttributeStmt(Attr::ASYNCHRONOUS, x.v);
}
@ -1941,23 +1980,29 @@ bool DeclarationVisitor::Pre(const parser::VolatileStmt &x) {
bool DeclarationVisitor::HandleAttributeStmt(
Attr attr, const std::list<parser::Name> &names) {
for (const auto &name : names) {
const auto pair{currScope().try_emplace(name.source, Attrs{attr})};
if (!pair.second) {
// symbol was already there: set attribute on it
Symbol &symbol{*pair.first->second};
if (attr == Attr::ASYNCHRONOUS || attr == Attr::VOLATILE) {
// TODO: if in a BLOCK, attribute should only be set while in the block
} else if (symbol.has<UseDetails>()) {
Say(*currStmtSource(),
"Cannot change %s attribute on use-associated '%s'"_err_en_US,
EnumToString(attr), name.source);
}
symbol.attrs().set(attr);
symbol.add_occurrence(name.source);
}
HandleAttributeStmt(attr, name.source);
}
return false;
}
Symbol &DeclarationVisitor::HandleAttributeStmt(
Attr attr, const SourceName &name) {
const auto pair{currScope().try_emplace(name, Attrs{attr})};
Symbol &symbol{*pair.first->second};
if (!pair.second) {
// symbol was already there: set attribute on it
if (attr == Attr::ASYNCHRONOUS || attr == Attr::VOLATILE) {
// TODO: if in a BLOCK, attribute should only be set while in the block
} else if (symbol.has<UseDetails>()) {
Say(*currStmtSource(),
"Cannot change %s attribute on use-associated '%s'"_err_en_US,
EnumToString(attr), name);
}
symbol.attrs().set(attr);
symbol.add_occurrence(name);
}
return symbol;
}
// Convert symbol to be a ProcEntity or return false if it can't be.
bool DeclarationVisitor::ConvertToProcEntity(Symbol &symbol) {
if (symbol.has<ProcEntityDetails>()) {
@ -1999,11 +2044,7 @@ void DeclarationVisitor::DeclareObjectEntity(
Symbol &symbol{DeclareEntity<ObjectEntityDetails>(name, attrs)};
if (auto *details{symbol.detailsIf<ObjectEntityDetails>()}) {
if (auto &type{GetDeclTypeSpec()}) {
if (details->type()) {
Say(name, "The type of '%s' has already been declared"_err_en_US);
} else {
details->set_type(*type);
}
SetType(name.source, symbol, *type);
}
if (!arraySpec().empty()) {
if (!details->shape().empty()) {
@ -2242,11 +2283,17 @@ void DeclarationVisitor::Post(const parser::FinalProcedureStmt &x) {
void DeclarationVisitor::SetType(
const SourceName &name, Symbol &symbol, const DeclTypeSpec &type) {
if (symbol.GetType()) {
auto *prevType{symbol.GetType()};
if (!prevType) {
symbol.SetType(type);
} else if (!symbol.test(Symbol::Flag::Implicit)) {
Say(name, "The type of '%s' has already been declared"_err_en_US);
return;
} else if (type != *prevType) {
Say(name,
"The type of '%s' has already been implicitly declared"_err_en_US);
} else {
symbol.set(Symbol::Flag::Implicit, false);
}
symbol.SetType(type);
}
// Find the Symbol for this derived type.
@ -2392,7 +2439,7 @@ bool ResolveNamesVisitor::Pre(const parser::ImportStmt &x) {
bool ResolveNamesVisitor::Pre(const parser::StructureComponent &x) {
ResolveStructureComponent(x);
return false;
return true;
}
const Symbol *ResolveNamesVisitor::ResolveStructureComponent(
@ -2733,8 +2780,8 @@ const parser::Name *ResolveNamesVisitor::GetVariableName(
common::visitors{
[](const parser::ObjectName &x) { return &x; },
[&](const parser::DataRef &x) { return GetVariableName(x); },
[](const auto &) {
return static_cast<const parser::Name *>(nullptr);
[&](const parser::Substring &x) {
return GetVariableName(std::get<parser::DataRef>(x.t));
},
},
x.u);

View File

@ -140,6 +140,19 @@ public:
DeclTypeSpec(Category);
DeclTypeSpec() = delete;
bool operator==(const DeclTypeSpec &that) const {
if (category_ != that.category_) {
return false;
}
switch (category_) {
case Intrinsic: return typeSpec_.intrinsic == that.typeSpec_.intrinsic;
case TypeDerived:
case ClassDerived: return typeSpec_.derived == that.typeSpec_.derived;
default: return true;
}
}
bool operator!=(const DeclTypeSpec &that) const { return !operator==(that); }
Category category() const { return category_; }
const IntrinsicTypeSpec &intrinsicTypeSpec() const;
DerivedTypeSpec &derivedTypeSpec();

View File

@ -15,4 +15,9 @@
integer :: x
!ERROR: The type of 'x' has already been declared
real :: x
integer(8) :: i
parameter(i=1,j=2,k=3)
integer :: j
!ERROR: The type of 'k' has already been implicitly declared
real :: k
end