llvm-project/flang/lib/Semantics/symbol.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

612 lines
18 KiB
C++
Raw Normal View History

//===-- lib/Semantics/symbol.cpp ------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "flang/Semantics/symbol.h"
#include "flang/Common/idioms.h"
#include "flang/Evaluate/expression.h"
#include "flang/Semantics/scope.h"
#include "flang/Semantics/semantics.h"
#include "flang/Semantics/tools.h"
#include "llvm/Support/raw_ostream.h"
[flang] Change when symbol is set in parser::Name Rework how `parser::Name` is resolved to contain a `Symbol`. so that constants in types can be evaluated. For example: ``` integer, parameter :: k = 8 integer(k) :: i ``` The old approach of collecting the symbols at the end of name resolution and filling in the `parser::Name` does not work because the type of `i` needs to be set in the symbol table. The symbol field in `parser::Name` is now mutable so that we can set it during name resolution. `RewriteParseTree` no longer needs to do that (it still warns about unresolved ones), so it does not need to collect symbols and fill them in. Consequently, we can eliminate "occurrences" from symbols -- we just need the name where each is first defined. This requires a lot of refactoring in `resolve-names.cc` to pass around `parser::Name` rather than `SourceName` so that we can resolve the name to a symbol. Fix some bugs where we stored `SourceName *` instead of `SourceName` in the symbol table. The pointers were into the parse tree, so they were only valid as long as the parse tree was around. The symbol table needs to remain valid longer than that, so the names need to be copied. `parser::Name` is not used in the symbol table. Eliminate `GenericSpec`. Currently all we need to do is to resolve the kinds of GenericSpec that contain names. Add `ScopeName` kind of `MiscDetails` for when we need a symbol in the scope to match the name of the scope. For example, `module m` cannot contain a declaration of a new `m`. Subprograms need real details because they can be called recursively. Fix output of partially resolved modules where we know it is a submodule but have not yet resolved the ancestor. Original-commit: flang-compiler/f18@5c1a4b99d2421f5b32e83426488d3fdf7951cfba Reviewed-on: https://github.com/flang-compiler/f18/pull/238 Tree-same-pre-rewrite: false
2018-11-17 04:43:08 +08:00
#include <string>
[flang] Partial implementation of Symbols and Scopes. A Symbol consists of a common part (in class Symbol) containing name, owner, attributes. Information for a specific kind of symbol is in a variant containing one of the *Details classes. So the kind of symbol is determined by the type of details class stored in the details_ variant. For scopes there is a single Scope class with an enum indicating the kind. So far there isn't a need for extra kind-specific details as with Symbols but that could change. Symbols defined in a Scope are stored there in a simple map. resolve-names.cc is a partial implementation of a parse-tree walker that resolves names to Symbols. Currently is only handles functions (which introduce a new Scope) and entity-decls. The test-type executable was reused as a driver for this to avoid the need for a new one. Sample output is below. When each "end function" is encountered the scope is dumped, which shows the symbols defined in it. $ cat a.f90 pure integer(8) function foo(arg1, arg2) result(res) integer :: arg1 real :: arg2 contains function bar(arg1) real :: bar real :: arg1 end function end function $ Debug/tools/f18/test-type a.f90 Subprogram scope: 0 children arg1: Entity type: REAL bar: Entity type: REAL Subprogram scope: 1 children arg1: Entity type: INTEGER arg2: Entity type: REAL bar: Subprogram (arg1) foo: Subprogram (arg1, arg2) result(res) res: Entity type: INTEGER(8) Original-commit: flang-compiler/f18@1cd2fbc04da1d6bb2ef5bc1cf07c808460ea7547 Reviewed-on: https://github.com/flang-compiler/f18/pull/30 Tree-same-pre-rewrite: false
2018-03-23 08:08:20 +08:00
namespace Fortran::semantics {
[flang] Partial implementation of Symbols and Scopes. A Symbol consists of a common part (in class Symbol) containing name, owner, attributes. Information for a specific kind of symbol is in a variant containing one of the *Details classes. So the kind of symbol is determined by the type of details class stored in the details_ variant. For scopes there is a single Scope class with an enum indicating the kind. So far there isn't a need for extra kind-specific details as with Symbols but that could change. Symbols defined in a Scope are stored there in a simple map. resolve-names.cc is a partial implementation of a parse-tree walker that resolves names to Symbols. Currently is only handles functions (which introduce a new Scope) and entity-decls. The test-type executable was reused as a driver for this to avoid the need for a new one. Sample output is below. When each "end function" is encountered the scope is dumped, which shows the symbols defined in it. $ cat a.f90 pure integer(8) function foo(arg1, arg2) result(res) integer :: arg1 real :: arg2 contains function bar(arg1) real :: bar real :: arg1 end function end function $ Debug/tools/f18/test-type a.f90 Subprogram scope: 0 children arg1: Entity type: REAL bar: Entity type: REAL Subprogram scope: 1 children arg1: Entity type: INTEGER arg2: Entity type: REAL bar: Subprogram (arg1) foo: Subprogram (arg1, arg2) result(res) res: Entity type: INTEGER(8) Original-commit: flang-compiler/f18@1cd2fbc04da1d6bb2ef5bc1cf07c808460ea7547 Reviewed-on: https://github.com/flang-compiler/f18/pull/30 Tree-same-pre-rewrite: false
2018-03-23 08:08:20 +08:00
template <typename T>
static void DumpOptional(llvm::raw_ostream &os, const char *label, const T &x) {
if (x) {
os << ' ' << label << ':' << *x;
}
}
template <typename T>
static void DumpExpr(llvm::raw_ostream &os, const char *label,
const std::optional<evaluate::Expr<T>> &x) {
if (x) {
x->AsFortran(os << ' ' << label << ':');
}
}
static void DumpBool(llvm::raw_ostream &os, const char *label, bool x) {
if (x) {
os << ' ' << label;
}
}
static void DumpSymbolVector(llvm::raw_ostream &os, const SymbolVector &list) {
char sep{' '};
for (const Symbol &elem : list) {
os << sep << elem.name();
sep = ',';
}
}
static void DumpType(llvm::raw_ostream &os, const Symbol &symbol) {
if (const auto *type{symbol.GetType()}) {
os << *type << ' ';
}
}
static void DumpType(llvm::raw_ostream &os, const DeclTypeSpec *type) {
if (type) {
os << ' ' << *type;
}
}
template <typename T>
static void DumpList(llvm::raw_ostream &os, const char *label, const T &list) {
if (!list.empty()) {
os << ' ' << label << ':';
char sep{' '};
for (const auto &elem : list) {
os << sep << elem;
sep = ',';
}
}
}
const Scope *ModuleDetails::parent() const {
[flang] Change when symbol is set in parser::Name Rework how `parser::Name` is resolved to contain a `Symbol`. so that constants in types can be evaluated. For example: ``` integer, parameter :: k = 8 integer(k) :: i ``` The old approach of collecting the symbols at the end of name resolution and filling in the `parser::Name` does not work because the type of `i` needs to be set in the symbol table. The symbol field in `parser::Name` is now mutable so that we can set it during name resolution. `RewriteParseTree` no longer needs to do that (it still warns about unresolved ones), so it does not need to collect symbols and fill them in. Consequently, we can eliminate "occurrences" from symbols -- we just need the name where each is first defined. This requires a lot of refactoring in `resolve-names.cc` to pass around `parser::Name` rather than `SourceName` so that we can resolve the name to a symbol. Fix some bugs where we stored `SourceName *` instead of `SourceName` in the symbol table. The pointers were into the parse tree, so they were only valid as long as the parse tree was around. The symbol table needs to remain valid longer than that, so the names need to be copied. `parser::Name` is not used in the symbol table. Eliminate `GenericSpec`. Currently all we need to do is to resolve the kinds of GenericSpec that contain names. Add `ScopeName` kind of `MiscDetails` for when we need a symbol in the scope to match the name of the scope. For example, `module m` cannot contain a declaration of a new `m`. Subprograms need real details because they can be called recursively. Fix output of partially resolved modules where we know it is a submodule but have not yet resolved the ancestor. Original-commit: flang-compiler/f18@5c1a4b99d2421f5b32e83426488d3fdf7951cfba Reviewed-on: https://github.com/flang-compiler/f18/pull/238 Tree-same-pre-rewrite: false
2018-11-17 04:43:08 +08:00
return isSubmodule_ && scope_ ? &scope_->parent() : nullptr;
}
const Scope *ModuleDetails::ancestor() const {
return isSubmodule_ && scope_ ? FindModuleContaining(*scope_) : nullptr;
}
void ModuleDetails::set_scope(const Scope *scope) {
CHECK(!scope_);
bool scopeIsSubmodule{scope->parent().kind() == Scope::Kind::Module};
CHECK(isSubmodule_ == scopeIsSubmodule);
scope_ = scope;
}
llvm::raw_ostream &operator<<(
llvm::raw_ostream &os, const SubprogramDetails &x) {
DumpBool(os, "isInterface", x.isInterface_);
DumpExpr(os, "bindName", x.bindName_);
if (x.result_) {
DumpType(os << " result:", x.result());
os << x.result_->name();
if (!x.result_->attrs().empty()) {
os << ", " << x.result_->attrs();
}
}
if (x.entryScope_) {
os << " entry";
if (x.entryScope_->symbol()) {
os << " in " << x.entryScope_->symbol()->name();
}
}
char sep{'('};
os << ' ';
for (const Symbol *arg : x.dummyArgs_) {
os << sep;
sep = ',';
if (arg) {
DumpType(os, *arg);
os << arg->name();
} else {
os << '*';
}
}
os << (sep == '(' ? "()" : ")");
if (x.stmtFunction_) {
os << " -> " << x.stmtFunction_->AsFortran();
}
return os;
}
void EntityDetails::set_type(const DeclTypeSpec &type) {
CHECK(!type_);
type_ = &type;
}
void AssocEntityDetails::set_rank(int rank) { rank_ = rank; }
[flang] Resolve names in ASSOCIATE and SELECT TYPE Create `AssocEntityDetails` for symbols that represent entities identified by the associate-name in ASSOCIATE and SELECT TYPE constructs. For ASSOCIATE, create a new scope for the associated entity. For SELECT TYPE, create a new scope for each of type guard blocks. Each one contains an associated entity with the appropriate type. For SELECT TYPE, also create a place-holder symbol for the associate-name in the SELECT TYPE statement. The real symbols are in the new scopes and none of them is uniquely identified with the associate-name. Handling of `Selector` is common between these, with `associate-name => expr | variable` recorded in `ConstructVisitor::association_`. When the selector is an expression, derive the type of the associated entity from the type of the expression. This required some refactoring of how `DeclTypeSpec`s are created. The `DerivedTypeSpec` that comes from and expression is const so we can only create const `DeclTypeSpec`s from it. But there were times during name resolution when we needed to set type parameters in the current `DeclTypeSpec`. Now the non-const `DerivedTypeSpec` is saved separately from the const `DeclTypeSpec` while we are processing a declaration type spec. This makes it unnecessary to save the derived type name. Add a type alias for `common::Indirection` to reduce verbosity. Original-commit: flang-compiler/f18@b7668cebe49a122ea23c89c81eafdeba243bbfaf Reviewed-on: https://github.com/flang-compiler/f18/pull/261 Tree-same-pre-rewrite: false
2019-01-16 08:59:20 +08:00
void EntityDetails::ReplaceType(const DeclTypeSpec &type) { type_ = &type; }
void ObjectEntityDetails::set_shape(const ArraySpec &shape) {
CHECK(shape_.empty());
for (const auto &shapeSpec : shape) {
shape_.push_back(shapeSpec);
}
}
void ObjectEntityDetails::set_coshape(const ArraySpec &coshape) {
CHECK(coshape_.empty());
for (const auto &shapeSpec : coshape) {
coshape_.push_back(shapeSpec);
}
}
ProcEntityDetails::ProcEntityDetails(EntityDetails &&d) : EntityDetails(d) {
if (type()) {
interface_.set_type(*type());
}
}
UseErrorDetails::UseErrorDetails(const UseDetails &useDetails) {
add_occurrence(useDetails.location(), *GetUsedModule(useDetails).scope());
}
UseErrorDetails &UseErrorDetails::add_occurrence(
const SourceName &location, const Scope &module) {
[flang] Change when symbol is set in parser::Name Rework how `parser::Name` is resolved to contain a `Symbol`. so that constants in types can be evaluated. For example: ``` integer, parameter :: k = 8 integer(k) :: i ``` The old approach of collecting the symbols at the end of name resolution and filling in the `parser::Name` does not work because the type of `i` needs to be set in the symbol table. The symbol field in `parser::Name` is now mutable so that we can set it during name resolution. `RewriteParseTree` no longer needs to do that (it still warns about unresolved ones), so it does not need to collect symbols and fill them in. Consequently, we can eliminate "occurrences" from symbols -- we just need the name where each is first defined. This requires a lot of refactoring in `resolve-names.cc` to pass around `parser::Name` rather than `SourceName` so that we can resolve the name to a symbol. Fix some bugs where we stored `SourceName *` instead of `SourceName` in the symbol table. The pointers were into the parse tree, so they were only valid as long as the parse tree was around. The symbol table needs to remain valid longer than that, so the names need to be copied. `parser::Name` is not used in the symbol table. Eliminate `GenericSpec`. Currently all we need to do is to resolve the kinds of GenericSpec that contain names. Add `ScopeName` kind of `MiscDetails` for when we need a symbol in the scope to match the name of the scope. For example, `module m` cannot contain a declaration of a new `m`. Subprograms need real details because they can be called recursively. Fix output of partially resolved modules where we know it is a submodule but have not yet resolved the ancestor. Original-commit: flang-compiler/f18@5c1a4b99d2421f5b32e83426488d3fdf7951cfba Reviewed-on: https://github.com/flang-compiler/f18/pull/238 Tree-same-pre-rewrite: false
2018-11-17 04:43:08 +08:00
occurrences_.push_back(std::make_pair(location, &module));
return *this;
}
void GenericDetails::AddSpecificProc(
const Symbol &proc, SourceName bindingName) {
specificProcs_.push_back(proc);
bindingNames_.push_back(bindingName);
}
[flang] Name resolution for derived types. This consists of: - a new kind of symbols to represent them with DerivedTypeDetails - creating symbols for derived types when they are declared - creating a new kind of scope for the type to hold component symbols - resolving entity declarations of objects of derived type - resolving references to objects of derived type and to components - handling derived types with same name as generic Type parameters are not yet implemented. Refactor DeclTypeSpec to be a value class wrapping an IntrinsicTypeSpec or a DerivedTypeSpec (or neither in the TypeStar and ClassStar cases). Store DerivedTypeSpec objects in a new structure the current scope MakeDerivedTypeSpec so that DeclTypeSpec can just contain a pointer to them, as it currently does for intrinsic types. In GenericDetails, add derivedType field to handle case where generic and derived type have the same name. The generic is in the scope and the derived type is referenced from the generic, similar to the case where a generic and specific have the same name. When one of these names is mis-recognized, we sometimes have to fix up the 'occurrences' lists of the symbols. Assign implicit types as soon as an entity is encountered that requires one. Otherwise implicit derived types won't work. When we see 'x%y' we have to know the type of x in order to resolve y. Add an Implicit flag to mark symbols that were implicitly typed For symbols that introduce a new scope, include a pointer back to that scope. Add CurrNonTypeScope() for the times when we want the current scope but ignoring derived type scopes. For example, that happens when looking for types or parameters, or creating implicit symbols. Original-commit: flang-compiler/f18@9bd16da020b64b78ed3928e0244765cd2e2d8068 Reviewed-on: https://github.com/flang-compiler/f18/pull/109
2018-06-22 23:21:19 +08:00
void GenericDetails::set_specific(Symbol &specific) {
CHECK(!specific_);
2019-07-31 06:29:50 +08:00
CHECK(!derivedType_);
[flang] Name resolution for derived types. This consists of: - a new kind of symbols to represent them with DerivedTypeDetails - creating symbols for derived types when they are declared - creating a new kind of scope for the type to hold component symbols - resolving entity declarations of objects of derived type - resolving references to objects of derived type and to components - handling derived types with same name as generic Type parameters are not yet implemented. Refactor DeclTypeSpec to be a value class wrapping an IntrinsicTypeSpec or a DerivedTypeSpec (or neither in the TypeStar and ClassStar cases). Store DerivedTypeSpec objects in a new structure the current scope MakeDerivedTypeSpec so that DeclTypeSpec can just contain a pointer to them, as it currently does for intrinsic types. In GenericDetails, add derivedType field to handle case where generic and derived type have the same name. The generic is in the scope and the derived type is referenced from the generic, similar to the case where a generic and specific have the same name. When one of these names is mis-recognized, we sometimes have to fix up the 'occurrences' lists of the symbols. Assign implicit types as soon as an entity is encountered that requires one. Otherwise implicit derived types won't work. When we see 'x%y' we have to know the type of x in order to resolve y. Add an Implicit flag to mark symbols that were implicitly typed For symbols that introduce a new scope, include a pointer back to that scope. Add CurrNonTypeScope() for the times when we want the current scope but ignoring derived type scopes. For example, that happens when looking for types or parameters, or creating implicit symbols. Original-commit: flang-compiler/f18@9bd16da020b64b78ed3928e0244765cd2e2d8068 Reviewed-on: https://github.com/flang-compiler/f18/pull/109
2018-06-22 23:21:19 +08:00
specific_ = &specific;
}
void GenericDetails::set_derivedType(Symbol &derivedType) {
2019-07-31 06:29:50 +08:00
CHECK(!specific_);
[flang] Name resolution for derived types. This consists of: - a new kind of symbols to represent them with DerivedTypeDetails - creating symbols for derived types when they are declared - creating a new kind of scope for the type to hold component symbols - resolving entity declarations of objects of derived type - resolving references to objects of derived type and to components - handling derived types with same name as generic Type parameters are not yet implemented. Refactor DeclTypeSpec to be a value class wrapping an IntrinsicTypeSpec or a DerivedTypeSpec (or neither in the TypeStar and ClassStar cases). Store DerivedTypeSpec objects in a new structure the current scope MakeDerivedTypeSpec so that DeclTypeSpec can just contain a pointer to them, as it currently does for intrinsic types. In GenericDetails, add derivedType field to handle case where generic and derived type have the same name. The generic is in the scope and the derived type is referenced from the generic, similar to the case where a generic and specific have the same name. When one of these names is mis-recognized, we sometimes have to fix up the 'occurrences' lists of the symbols. Assign implicit types as soon as an entity is encountered that requires one. Otherwise implicit derived types won't work. When we see 'x%y' we have to know the type of x in order to resolve y. Add an Implicit flag to mark symbols that were implicitly typed For symbols that introduce a new scope, include a pointer back to that scope. Add CurrNonTypeScope() for the times when we want the current scope but ignoring derived type scopes. For example, that happens when looking for types or parameters, or creating implicit symbols. Original-commit: flang-compiler/f18@9bd16da020b64b78ed3928e0244765cd2e2d8068 Reviewed-on: https://github.com/flang-compiler/f18/pull/109
2018-06-22 23:21:19 +08:00
CHECK(!derivedType_);
derivedType_ = &derivedType;
}
const Symbol *GenericDetails::CheckSpecific() const {
[flang] Continue semantic checking after name resolution error When an error occurs in name resolution, continue semantic processing in order to detect other errors. This means we can no longer assume that every `parser::Name` has a symbol even after name resolution completes. In `RewriteMutator`, only report internal error for unresolved symbol if there have been no fatal errors. Add `Error` flag to `Symbol` to indicate that an error occcurred related to it. Once we report an error about a symbol we should avoid reporting any more to prevent cascading errors. Add `HasError()` and `SetError()` to simplify working with this flag. Change some places that we assume that a `parser::Name` has a non-null symbol. There are probably more. `resolve-names.cc`: Set the `Error` flag when we report a fatal error related to a symbol. (This requires making some symbols non-const.) Remove `CheckScalarIntegerType()` as `ExprChecker` will take care of those constraints if they are expressed in the parse tree. One exception to that is the name in a `ConcurrentControl`. Explicitly perform that check using `EvaluateExpr()` and constraint classes so we get consistent error messages. In expression analysis, when a constraint is violated (like `Scalar<>` or `Integer<>`), reset the wrapped expression so that we don't assume it is valid. A `GenericExprWrapper` holding a std::nullopt indicates error. Change `EnforceTypeConstraint()` to return false when the constraint fails to enable this. check-do-concurrent.cc: Reorganize the Gather*VariableNames functions into one to simplify the task of filtering out unresolved names. Remove `CheckNoDuplicates()` and `CheckNoCollisions()` as those checks is already done in name resolution when the names are added to the scope. Original-commit: flang-compiler/f18@bcdb679405906575f36d3314f17da89e3e89d45c Reviewed-on: https://github.com/flang-compiler/f18/pull/429 Tree-same-pre-rewrite: false
2019-04-26 04:18:33 +08:00
return const_cast<GenericDetails *>(this)->CheckSpecific();
}
Symbol *GenericDetails::CheckSpecific() {
[flang] Change how memory for Symbol instances is managed. With this change, all instances Symbol are stored in class Symbols. Scope.symbols_, which used to own the symbol memory, now maps names to Symbol* instead. This causes a bunch of reference-to-pointer changes because of the change in type of key-value pairs. It also requires a default constructor for Symbol, which means owner_ can't be a reference. Symbols manages Symbol instances by allocating a block of them at a time and returning the next one when needed. They are never freed. The reason for the change is that there are a few cases where we need to have a two symbols with the same name, so they can't both live in the map in Scope. Those are: 1. When there is an erroneous redeclaration of a name we may delete the first symbol and replace it with a new one. If we have saved a pointer to the first one it is now dangling. This can be seen by running `f18 -fdebug-dump-symbols -fparse-only test/semantics/resolve19.f90` under valgrind. Subroutine s is declared twice: each results in a scope that contains a pointer back to the symbol for the subroutine. After the second symbol for s is created the first is gone so the pointer in the scope is invalid. 2. A generic and one of its specifics can have the same name. We currently handle that by moving the symbol for the specific into a unique_ptr in the generic. So in that case the symbol is owned by another symbol instead of by the scope. It is simpler if we only have to deal with moving the raw pointer around. 3. A generic and a derived type can have the same name. This case isn't handled yet, but it can be done like flang-compiler/f18#2 above. It's more complicated because the derived type and the generic can be declared in either order. Original-commit: flang-compiler/f18@55a68cf0235c8a3ac855de7dc0e2b08690866be0 Reviewed-on: https://github.com/flang-compiler/f18/pull/107
2018-06-20 07:06:41 +08:00
if (specific_) {
for (const Symbol &proc : specificProcs_) {
if (&proc == specific_) {
return nullptr;
}
}
[flang] Change how memory for Symbol instances is managed. With this change, all instances Symbol are stored in class Symbols. Scope.symbols_, which used to own the symbol memory, now maps names to Symbol* instead. This causes a bunch of reference-to-pointer changes because of the change in type of key-value pairs. It also requires a default constructor for Symbol, which means owner_ can't be a reference. Symbols manages Symbol instances by allocating a block of them at a time and returning the next one when needed. They are never freed. The reason for the change is that there are a few cases where we need to have a two symbols with the same name, so they can't both live in the map in Scope. Those are: 1. When there is an erroneous redeclaration of a name we may delete the first symbol and replace it with a new one. If we have saved a pointer to the first one it is now dangling. This can be seen by running `f18 -fdebug-dump-symbols -fparse-only test/semantics/resolve19.f90` under valgrind. Subroutine s is declared twice: each results in a scope that contains a pointer back to the symbol for the subroutine. After the second symbol for s is created the first is gone so the pointer in the scope is invalid. 2. A generic and one of its specifics can have the same name. We currently handle that by moving the symbol for the specific into a unique_ptr in the generic. So in that case the symbol is owned by another symbol instead of by the scope. It is simpler if we only have to deal with moving the raw pointer around. 3. A generic and a derived type can have the same name. This case isn't handled yet, but it can be done like flang-compiler/f18#2 above. It's more complicated because the derived type and the generic can be declared in either order. Original-commit: flang-compiler/f18@55a68cf0235c8a3ac855de7dc0e2b08690866be0 Reviewed-on: https://github.com/flang-compiler/f18/pull/107
2018-06-20 07:06:41 +08:00
return specific_;
} else {
return nullptr;
}
}
void GenericDetails::CopyFrom(const GenericDetails &from) {
CHECK(specificProcs_.size() == bindingNames_.size());
CHECK(from.specificProcs_.size() == from.bindingNames_.size());
if (from.specific_) {
CHECK(!specific_ || specific_ == from.specific_);
specific_ = from.specific_;
}
if (from.derivedType_) {
CHECK(!derivedType_ || derivedType_ == from.derivedType_);
derivedType_ = from.derivedType_;
}
for (std::size_t i{0}; i < from.specificProcs_.size(); ++i) {
if (std::find_if(specificProcs_.begin(), specificProcs_.end(),
[&](const Symbol &mySymbol) {
return &mySymbol == &*from.specificProcs_[i];
}) == specificProcs_.end()) {
specificProcs_.push_back(from.specificProcs_[i]);
bindingNames_.push_back(from.bindingNames_[i]);
}
}
}
// The name of the kind of details for this symbol.
// This is primarily for debugging.
[flang] Support writing interfaces in module files. Write symbols for external subprogram interfaces as interface-stmts. Those go in the decls part of the module file, as opposed to contained subprograms which go in the contains part. See modfile06.f90. Write symbols with GenericDetails to module files. The specific procedures of a generic interface are always written as procedure-stmts. If they also have specific interfaces those are written in a separate interface-stmt. See modfile07.f90. Fix a bug where `real, external :: f` was not written like `real f; external f`. We have to notice the EXTERNAL attribute on the type-declaration-stmt and convert the entity to a procedure entity. See modfile08.f90. Fix a bug where a use-associated symbol is referenced in a procedure-designator. We were not resolving that correctly. Change ModFileWriter::PutEntity to include the kind of Details when it reports an internal error due to a kind it can't handle. Make DetailsToString public to support that. Change test_errors.sh to fail if the f18 command exits due to a signal. We were missing bugs where the correct errors were written out but then module file writing crashed (due to failure to handle generics mentioned above). Non-zero exit status is okay because we are expecting compilation errors. Change test_modfile.sh to allow for the expected module file contents to be indented so the tests are easier to read. Original-commit: flang-compiler/f18@82a7931e51c63ba21f17261727e1e9dc4167dcc9 Reviewed-on: https://github.com/flang-compiler/f18/pull/132 Tree-same-pre-rewrite: false
2018-07-20 04:28:24 +08:00
std::string DetailsToString(const Details &details) {
return std::visit(
common::visitors{
[](const UnknownDetails &) { return "Unknown"; },
[](const MainProgramDetails &) { return "MainProgram"; },
[](const ModuleDetails &) { return "Module"; },
[](const SubprogramDetails &) { return "Subprogram"; },
[](const SubprogramNameDetails &) { return "SubprogramName"; },
[](const EntityDetails &) { return "Entity"; },
[](const ObjectEntityDetails &) { return "ObjectEntity"; },
[](const ProcEntityDetails &) { return "ProcEntity"; },
[flang] Name resolution for derived types. This consists of: - a new kind of symbols to represent them with DerivedTypeDetails - creating symbols for derived types when they are declared - creating a new kind of scope for the type to hold component symbols - resolving entity declarations of objects of derived type - resolving references to objects of derived type and to components - handling derived types with same name as generic Type parameters are not yet implemented. Refactor DeclTypeSpec to be a value class wrapping an IntrinsicTypeSpec or a DerivedTypeSpec (or neither in the TypeStar and ClassStar cases). Store DerivedTypeSpec objects in a new structure the current scope MakeDerivedTypeSpec so that DeclTypeSpec can just contain a pointer to them, as it currently does for intrinsic types. In GenericDetails, add derivedType field to handle case where generic and derived type have the same name. The generic is in the scope and the derived type is referenced from the generic, similar to the case where a generic and specific have the same name. When one of these names is mis-recognized, we sometimes have to fix up the 'occurrences' lists of the symbols. Assign implicit types as soon as an entity is encountered that requires one. Otherwise implicit derived types won't work. When we see 'x%y' we have to know the type of x in order to resolve y. Add an Implicit flag to mark symbols that were implicitly typed For symbols that introduce a new scope, include a pointer back to that scope. Add CurrNonTypeScope() for the times when we want the current scope but ignoring derived type scopes. For example, that happens when looking for types or parameters, or creating implicit symbols. Original-commit: flang-compiler/f18@9bd16da020b64b78ed3928e0244765cd2e2d8068 Reviewed-on: https://github.com/flang-compiler/f18/pull/109
2018-06-22 23:21:19 +08:00
[](const DerivedTypeDetails &) { return "DerivedType"; },
[](const UseDetails &) { return "Use"; },
[](const UseErrorDetails &) { return "UseError"; },
[flang] More name resolution for construct entities Push a new scope for constructs and statements that require one (DataStmt, DO CONCURRENT, ForallConstruct, ForallStmt -- there are more to do). Currently we use the Block kind of scope because there is no difference. Perhaps that kind should be renamed to Construct, though it does apply to statements as well as constructs. Add DeclareConstructEntity to create a construct or statement entity. When the type is not specified it can come from the type of a symbol in the enclosing scope with the same name. Change DeclareObjectEntity et al. to return the symbol declared, for the benefit of DeclareConstructEntity. Use DeclareConstructEntity for DO CONCURRENT index-name, LOCAL, and LOCAL_INIT variables and the data-i-do-variable in DataImpliedDo Names in SHARED locality spec need special handling: create a new kinds of symbol with HostAssocDetails to represent the host-association of the shared variables within the construct scope. That symbol gets the LocalityShared flag without affecting the symbol in the outer scope. HostAssoc symbols may be useful in other contexts, e.g. up-level references to local variables. Add parser::DoConstruct::IsDoConcurrent() because DO CONCURRENT loops introduce a construct scope while other DO loops do not. Move CanonicalizeDo to before name resolution so that name resolution doesn't have to deal with labeled DO CONCURRENT loops. Allow for type of index name to be specified in ConcurrentHeader. Resolve the derived type name in an AllocateStmt, StructureConstructor Original-commit: flang-compiler/f18@bc7b9891367f3174c9b5018ce5636a36a5a76c1c Reviewed-on: https://github.com/flang-compiler/f18/pull/214
2018-10-18 22:55:48 +08:00
[](const HostAssocDetails &) { return "HostAssoc"; },
[](const GenericDetails &) { return "Generic"; },
[](const ProcBindingDetails &) { return "ProcBinding"; },
[](const NamelistDetails &) { return "Namelist"; },
[](const CommonBlockDetails &) { return "CommonBlockDetails"; },
[](const FinalProcDetails &) { return "FinalProc"; },
[](const TypeParamDetails &) { return "TypeParam"; },
[](const MiscDetails &) { return "Misc"; },
[flang] Resolve names in ASSOCIATE and SELECT TYPE Create `AssocEntityDetails` for symbols that represent entities identified by the associate-name in ASSOCIATE and SELECT TYPE constructs. For ASSOCIATE, create a new scope for the associated entity. For SELECT TYPE, create a new scope for each of type guard blocks. Each one contains an associated entity with the appropriate type. For SELECT TYPE, also create a place-holder symbol for the associate-name in the SELECT TYPE statement. The real symbols are in the new scopes and none of them is uniquely identified with the associate-name. Handling of `Selector` is common between these, with `associate-name => expr | variable` recorded in `ConstructVisitor::association_`. When the selector is an expression, derive the type of the associated entity from the type of the expression. This required some refactoring of how `DeclTypeSpec`s are created. The `DerivedTypeSpec` that comes from and expression is const so we can only create const `DeclTypeSpec`s from it. But there were times during name resolution when we needed to set type parameters in the current `DeclTypeSpec`. Now the non-const `DerivedTypeSpec` is saved separately from the const `DeclTypeSpec` while we are processing a declaration type spec. This makes it unnecessary to save the derived type name. Add a type alias for `common::Indirection` to reduce verbosity. Original-commit: flang-compiler/f18@b7668cebe49a122ea23c89c81eafdeba243bbfaf Reviewed-on: https://github.com/flang-compiler/f18/pull/261 Tree-same-pre-rewrite: false
2019-01-16 08:59:20 +08:00
[](const AssocEntityDetails &) { return "AssocEntity"; },
},
details);
}
const std::string Symbol::GetDetailsName() const {
return DetailsToString(details_);
}
void Symbol::set_details(Details &&details) {
CHECK(CanReplaceDetails(details));
details_ = std::move(details);
}
bool Symbol::CanReplaceDetails(const Details &details) const {
if (has<UnknownDetails>()) {
return true; // can always replace UnknownDetails
} else {
return std::visit(
common::visitors{
[](const UseErrorDetails &) { return true; },
[&](const ObjectEntityDetails &) { return has<EntityDetails>(); },
[&](const ProcEntityDetails &) { return has<EntityDetails>(); },
[&](const SubprogramDetails &) {
return has<SubprogramNameDetails>() || has<EntityDetails>();
},
[&](const DerivedTypeDetails &) {
auto *derived{this->detailsIf<DerivedTypeDetails>()};
return derived && derived->isForwardReferenced();
},
[](const auto &) { return false; },
},
details);
}
}
// Usually a symbol's name is the first occurrence in the source, but sometimes
// we want to replace it with one at a different location (but same characters).
void Symbol::ReplaceName(const SourceName &name) {
CHECK(name == name_);
name_ = name;
}
void Symbol::SetType(const DeclTypeSpec &type) {
std::visit(common::visitors{
[&](EntityDetails &x) { x.set_type(type); },
[&](ObjectEntityDetails &x) { x.set_type(type); },
[&](AssocEntityDetails &x) { x.set_type(type); },
[&](ProcEntityDetails &x) { x.interface().set_type(type); },
[&](TypeParamDetails &x) { x.set_type(type); },
[](auto &) {},
},
details_);
}
bool Symbol::IsFuncResult() const {
return std::visit(
common::visitors{[](const EntityDetails &x) { return x.isFuncResult(); },
[](const ObjectEntityDetails &x) { return x.isFuncResult(); },
[](const ProcEntityDetails &x) { return x.isFuncResult(); },
[](const HostAssocDetails &x) { return x.symbol().IsFuncResult(); },
[](const auto &) { return false; }},
details_);
}
bool Symbol::IsObjectArray() const {
const auto *details{std::get_if<ObjectEntityDetails>(&details_)};
return details && details->IsArray();
}
bool Symbol::IsSubprogram() const {
return std::visit(
common::visitors{
[](const SubprogramDetails &) { return true; },
[](const SubprogramNameDetails &) { return true; },
[](const GenericDetails &) { return true; },
[](const UseDetails &x) { return x.symbol().IsSubprogram(); },
[](const auto &) { return false; },
},
details_);
}
[flang] Merge pull request flang-compiler/f18#539 from flang-compiler/tsk1 Check that procedures of a generic are distinguishable Original-commit: flang-compiler/f18@a24701e313019dbf84179b79e234f92d61de0fa6 Reviewed-on: https://github.com/flang-compiler/f18/pull/539 Due to a conflicting rebase during the linearizing of flang-compiler/f18, this commit squashes a number of other commits: flang-compiler/f18@9b1343af36bd27b110f31dab39c3a18a657a5760 Some cleanup in characteristics.{h,cc} flang-compiler/f18@ddb70e53d2b4e2bba12686e4ac3c26052758fcc3 Merge branch 'master' of github.com:flang-compiler/f18 into tsk1 flang-compiler/f18@d1eef9506610a427f992180f6b59cafe09abb9b9 Merge branch 'master' of github.com:flang-compiler/f18 into tsk1 flang-compiler/f18@24a6d3ffbf4d26d92222b27faa155bb5b3f517f4 Make test_folding.sh stricter in test for warnings flang-compiler/f18@c2c5b640604acceb45823de8cb5716d6921da7d4 Replace SymbolList with SymbolVector flang-compiler/f18@c8499584dff12381c2ce6d4718761cd225b4d97a Add CopyAttrs to copy attributes from Symbol flang-compiler/f18@0573ffd8b2ed5757e06a4fc6d5ffc4401e800c32 Replace cascading detailsIf calls with std::visit flang-compiler/f18@28ec62b3ffeec1d25fde330069b050655bb52a5d Add name to characteristics::DummyArgument flang-compiler/f18@568eaf01145d4ee979423d06f2a65d07222f6841 Add name to CopySymbol() flang-compiler/f18@8c557b09e752da205cd300f63b5ca69806fb2e78 Check that procedures of a generic are distinguishable flang-compiler/f18@50515fd987fd5479567e1b497f6ba93974ffde76 Merge branch 'master' of github.com:flang-compiler/f18 into tsk1 flang-compiler/f18@a7963e98a4aedc97784b99903d04cdc48fd4c346 Address review comments flang-compiler/f18@edd65b3962dbaa1121c166d47c90730e39c25a04 Merge branch 'master' of github.com:flang-compiler/f18 into tsk1
2019-07-03 05:00:44 +08:00
bool Symbol::IsFromModFile() const {
return test(Flag::ModFile) ||
(!owner_->IsGlobal() && owner_->symbol()->IsFromModFile());
[flang] Merge pull request flang-compiler/f18#539 from flang-compiler/tsk1 Check that procedures of a generic are distinguishable Original-commit: flang-compiler/f18@a24701e313019dbf84179b79e234f92d61de0fa6 Reviewed-on: https://github.com/flang-compiler/f18/pull/539 Due to a conflicting rebase during the linearizing of flang-compiler/f18, this commit squashes a number of other commits: flang-compiler/f18@9b1343af36bd27b110f31dab39c3a18a657a5760 Some cleanup in characteristics.{h,cc} flang-compiler/f18@ddb70e53d2b4e2bba12686e4ac3c26052758fcc3 Merge branch 'master' of github.com:flang-compiler/f18 into tsk1 flang-compiler/f18@d1eef9506610a427f992180f6b59cafe09abb9b9 Merge branch 'master' of github.com:flang-compiler/f18 into tsk1 flang-compiler/f18@24a6d3ffbf4d26d92222b27faa155bb5b3f517f4 Make test_folding.sh stricter in test for warnings flang-compiler/f18@c2c5b640604acceb45823de8cb5716d6921da7d4 Replace SymbolList with SymbolVector flang-compiler/f18@c8499584dff12381c2ce6d4718761cd225b4d97a Add CopyAttrs to copy attributes from Symbol flang-compiler/f18@0573ffd8b2ed5757e06a4fc6d5ffc4401e800c32 Replace cascading detailsIf calls with std::visit flang-compiler/f18@28ec62b3ffeec1d25fde330069b050655bb52a5d Add name to characteristics::DummyArgument flang-compiler/f18@568eaf01145d4ee979423d06f2a65d07222f6841 Add name to CopySymbol() flang-compiler/f18@8c557b09e752da205cd300f63b5ca69806fb2e78 Check that procedures of a generic are distinguishable flang-compiler/f18@50515fd987fd5479567e1b497f6ba93974ffde76 Merge branch 'master' of github.com:flang-compiler/f18 into tsk1 flang-compiler/f18@a7963e98a4aedc97784b99903d04cdc48fd4c346 Address review comments flang-compiler/f18@edd65b3962dbaa1121c166d47c90730e39c25a04 Merge branch 'master' of github.com:flang-compiler/f18 into tsk1
2019-07-03 05:00:44 +08:00
}
ObjectEntityDetails::ObjectEntityDetails(EntityDetails &&d)
: EntityDetails(d) {}
llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const EntityDetails &x) {
DumpBool(os, "dummy", x.isDummy());
DumpBool(os, "funcResult", x.isFuncResult());
if (x.type()) {
os << " type: " << *x.type();
}
DumpExpr(os, "bindName", x.bindName_);
return os;
}
llvm::raw_ostream &operator<<(
llvm::raw_ostream &os, const ObjectEntityDetails &x) {
os << *static_cast<const EntityDetails *>(&x);
DumpList(os, "shape", x.shape());
DumpList(os, "coshape", x.coshape());
DumpExpr(os, "init", x.init_);
return os;
}
llvm::raw_ostream &operator<<(
llvm::raw_ostream &os, const AssocEntityDetails &x) {
[flang] Resolve names in ASSOCIATE and SELECT TYPE Create `AssocEntityDetails` for symbols that represent entities identified by the associate-name in ASSOCIATE and SELECT TYPE constructs. For ASSOCIATE, create a new scope for the associated entity. For SELECT TYPE, create a new scope for each of type guard blocks. Each one contains an associated entity with the appropriate type. For SELECT TYPE, also create a place-holder symbol for the associate-name in the SELECT TYPE statement. The real symbols are in the new scopes and none of them is uniquely identified with the associate-name. Handling of `Selector` is common between these, with `associate-name => expr | variable` recorded in `ConstructVisitor::association_`. When the selector is an expression, derive the type of the associated entity from the type of the expression. This required some refactoring of how `DeclTypeSpec`s are created. The `DerivedTypeSpec` that comes from and expression is const so we can only create const `DeclTypeSpec`s from it. But there were times during name resolution when we needed to set type parameters in the current `DeclTypeSpec`. Now the non-const `DerivedTypeSpec` is saved separately from the const `DeclTypeSpec` while we are processing a declaration type spec. This makes it unnecessary to save the derived type name. Add a type alias for `common::Indirection` to reduce verbosity. Original-commit: flang-compiler/f18@b7668cebe49a122ea23c89c81eafdeba243bbfaf Reviewed-on: https://github.com/flang-compiler/f18/pull/261 Tree-same-pre-rewrite: false
2019-01-16 08:59:20 +08:00
os << *static_cast<const EntityDetails *>(&x);
if (auto assocRank{x.rank()}) {
os << " rank: " << *assocRank;
}
DumpExpr(os, "expr", x.expr());
[flang] Resolve names in ASSOCIATE and SELECT TYPE Create `AssocEntityDetails` for symbols that represent entities identified by the associate-name in ASSOCIATE and SELECT TYPE constructs. For ASSOCIATE, create a new scope for the associated entity. For SELECT TYPE, create a new scope for each of type guard blocks. Each one contains an associated entity with the appropriate type. For SELECT TYPE, also create a place-holder symbol for the associate-name in the SELECT TYPE statement. The real symbols are in the new scopes and none of them is uniquely identified with the associate-name. Handling of `Selector` is common between these, with `associate-name => expr | variable` recorded in `ConstructVisitor::association_`. When the selector is an expression, derive the type of the associated entity from the type of the expression. This required some refactoring of how `DeclTypeSpec`s are created. The `DerivedTypeSpec` that comes from and expression is const so we can only create const `DeclTypeSpec`s from it. But there were times during name resolution when we needed to set type parameters in the current `DeclTypeSpec`. Now the non-const `DerivedTypeSpec` is saved separately from the const `DeclTypeSpec` while we are processing a declaration type spec. This makes it unnecessary to save the derived type name. Add a type alias for `common::Indirection` to reduce verbosity. Original-commit: flang-compiler/f18@b7668cebe49a122ea23c89c81eafdeba243bbfaf Reviewed-on: https://github.com/flang-compiler/f18/pull/261 Tree-same-pre-rewrite: false
2019-01-16 08:59:20 +08:00
return os;
}
llvm::raw_ostream &operator<<(
llvm::raw_ostream &os, const ProcEntityDetails &x) {
if (auto *symbol{x.interface_.symbol()}) {
os << ' ' << symbol->name();
} else {
DumpType(os, x.interface_.type());
}
DumpExpr(os, "bindName", x.bindName());
DumpOptional(os, "passName", x.passName());
if (x.init()) {
if (const Symbol * target{*x.init()}) {
os << " => " << target->name();
} else {
os << " => NULL()";
}
}
return os;
}
llvm::raw_ostream &operator<<(
llvm::raw_ostream &os, const DerivedTypeDetails &x) {
DumpBool(os, "sequence", x.sequence_);
DumpList(os, "components", x.componentNames_);
return os;
}
llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Details &details) {
os << DetailsToString(details);
std::visit( //
common::visitors{
[&](const UnknownDetails &) {},
[&](const MainProgramDetails &) {},
[&](const ModuleDetails &x) {
if (x.isSubmodule()) {
[flang] Change when symbol is set in parser::Name Rework how `parser::Name` is resolved to contain a `Symbol`. so that constants in types can be evaluated. For example: ``` integer, parameter :: k = 8 integer(k) :: i ``` The old approach of collecting the symbols at the end of name resolution and filling in the `parser::Name` does not work because the type of `i` needs to be set in the symbol table. The symbol field in `parser::Name` is now mutable so that we can set it during name resolution. `RewriteParseTree` no longer needs to do that (it still warns about unresolved ones), so it does not need to collect symbols and fill them in. Consequently, we can eliminate "occurrences" from symbols -- we just need the name where each is first defined. This requires a lot of refactoring in `resolve-names.cc` to pass around `parser::Name` rather than `SourceName` so that we can resolve the name to a symbol. Fix some bugs where we stored `SourceName *` instead of `SourceName` in the symbol table. The pointers were into the parse tree, so they were only valid as long as the parse tree was around. The symbol table needs to remain valid longer than that, so the names need to be copied. `parser::Name` is not used in the symbol table. Eliminate `GenericSpec`. Currently all we need to do is to resolve the kinds of GenericSpec that contain names. Add `ScopeName` kind of `MiscDetails` for when we need a symbol in the scope to match the name of the scope. For example, `module m` cannot contain a declaration of a new `m`. Subprograms need real details because they can be called recursively. Fix output of partially resolved modules where we know it is a submodule but have not yet resolved the ancestor. Original-commit: flang-compiler/f18@5c1a4b99d2421f5b32e83426488d3fdf7951cfba Reviewed-on: https://github.com/flang-compiler/f18/pull/238 Tree-same-pre-rewrite: false
2018-11-17 04:43:08 +08:00
os << " (";
if (x.ancestor()) {
auto ancestor{x.ancestor()->GetName().value()};
[flang] Change when symbol is set in parser::Name Rework how `parser::Name` is resolved to contain a `Symbol`. so that constants in types can be evaluated. For example: ``` integer, parameter :: k = 8 integer(k) :: i ``` The old approach of collecting the symbols at the end of name resolution and filling in the `parser::Name` does not work because the type of `i` needs to be set in the symbol table. The symbol field in `parser::Name` is now mutable so that we can set it during name resolution. `RewriteParseTree` no longer needs to do that (it still warns about unresolved ones), so it does not need to collect symbols and fill them in. Consequently, we can eliminate "occurrences" from symbols -- we just need the name where each is first defined. This requires a lot of refactoring in `resolve-names.cc` to pass around `parser::Name` rather than `SourceName` so that we can resolve the name to a symbol. Fix some bugs where we stored `SourceName *` instead of `SourceName` in the symbol table. The pointers were into the parse tree, so they were only valid as long as the parse tree was around. The symbol table needs to remain valid longer than that, so the names need to be copied. `parser::Name` is not used in the symbol table. Eliminate `GenericSpec`. Currently all we need to do is to resolve the kinds of GenericSpec that contain names. Add `ScopeName` kind of `MiscDetails` for when we need a symbol in the scope to match the name of the scope. For example, `module m` cannot contain a declaration of a new `m`. Subprograms need real details because they can be called recursively. Fix output of partially resolved modules where we know it is a submodule but have not yet resolved the ancestor. Original-commit: flang-compiler/f18@5c1a4b99d2421f5b32e83426488d3fdf7951cfba Reviewed-on: https://github.com/flang-compiler/f18/pull/238 Tree-same-pre-rewrite: false
2018-11-17 04:43:08 +08:00
os << ancestor;
if (x.parent()) {
auto parent{x.parent()->GetName().value()};
[flang] Change when symbol is set in parser::Name Rework how `parser::Name` is resolved to contain a `Symbol`. so that constants in types can be evaluated. For example: ``` integer, parameter :: k = 8 integer(k) :: i ``` The old approach of collecting the symbols at the end of name resolution and filling in the `parser::Name` does not work because the type of `i` needs to be set in the symbol table. The symbol field in `parser::Name` is now mutable so that we can set it during name resolution. `RewriteParseTree` no longer needs to do that (it still warns about unresolved ones), so it does not need to collect symbols and fill them in. Consequently, we can eliminate "occurrences" from symbols -- we just need the name where each is first defined. This requires a lot of refactoring in `resolve-names.cc` to pass around `parser::Name` rather than `SourceName` so that we can resolve the name to a symbol. Fix some bugs where we stored `SourceName *` instead of `SourceName` in the symbol table. The pointers were into the parse tree, so they were only valid as long as the parse tree was around. The symbol table needs to remain valid longer than that, so the names need to be copied. `parser::Name` is not used in the symbol table. Eliminate `GenericSpec`. Currently all we need to do is to resolve the kinds of GenericSpec that contain names. Add `ScopeName` kind of `MiscDetails` for when we need a symbol in the scope to match the name of the scope. For example, `module m` cannot contain a declaration of a new `m`. Subprograms need real details because they can be called recursively. Fix output of partially resolved modules where we know it is a submodule but have not yet resolved the ancestor. Original-commit: flang-compiler/f18@5c1a4b99d2421f5b32e83426488d3fdf7951cfba Reviewed-on: https://github.com/flang-compiler/f18/pull/238 Tree-same-pre-rewrite: false
2018-11-17 04:43:08 +08:00
if (ancestor != parent) {
os << ':' << parent;
}
}
}
os << ")";
}
},
[&](const SubprogramNameDetails &x) {
os << ' ' << EnumToString(x.kind());
[flang] Partial implementation of Symbols and Scopes. A Symbol consists of a common part (in class Symbol) containing name, owner, attributes. Information for a specific kind of symbol is in a variant containing one of the *Details classes. So the kind of symbol is determined by the type of details class stored in the details_ variant. For scopes there is a single Scope class with an enum indicating the kind. So far there isn't a need for extra kind-specific details as with Symbols but that could change. Symbols defined in a Scope are stored there in a simple map. resolve-names.cc is a partial implementation of a parse-tree walker that resolves names to Symbols. Currently is only handles functions (which introduce a new Scope) and entity-decls. The test-type executable was reused as a driver for this to avoid the need for a new one. Sample output is below. When each "end function" is encountered the scope is dumped, which shows the symbols defined in it. $ cat a.f90 pure integer(8) function foo(arg1, arg2) result(res) integer :: arg1 real :: arg2 contains function bar(arg1) real :: bar real :: arg1 end function end function $ Debug/tools/f18/test-type a.f90 Subprogram scope: 0 children arg1: Entity type: REAL bar: Entity type: REAL Subprogram scope: 1 children arg1: Entity type: INTEGER arg2: Entity type: REAL bar: Subprogram (arg1) foo: Subprogram (arg1, arg2) result(res) res: Entity type: INTEGER(8) Original-commit: flang-compiler/f18@1cd2fbc04da1d6bb2ef5bc1cf07c808460ea7547 Reviewed-on: https://github.com/flang-compiler/f18/pull/30 Tree-same-pre-rewrite: false
2018-03-23 08:08:20 +08:00
},
[&](const UseDetails &x) {
os << " from " << x.symbol().name() << " in "
<< GetUsedModule(x).name();
},
[&](const UseErrorDetails &x) {
os << " uses:";
[flang] Change when symbol is set in parser::Name Rework how `parser::Name` is resolved to contain a `Symbol`. so that constants in types can be evaluated. For example: ``` integer, parameter :: k = 8 integer(k) :: i ``` The old approach of collecting the symbols at the end of name resolution and filling in the `parser::Name` does not work because the type of `i` needs to be set in the symbol table. The symbol field in `parser::Name` is now mutable so that we can set it during name resolution. `RewriteParseTree` no longer needs to do that (it still warns about unresolved ones), so it does not need to collect symbols and fill them in. Consequently, we can eliminate "occurrences" from symbols -- we just need the name where each is first defined. This requires a lot of refactoring in `resolve-names.cc` to pass around `parser::Name` rather than `SourceName` so that we can resolve the name to a symbol. Fix some bugs where we stored `SourceName *` instead of `SourceName` in the symbol table. The pointers were into the parse tree, so they were only valid as long as the parse tree was around. The symbol table needs to remain valid longer than that, so the names need to be copied. `parser::Name` is not used in the symbol table. Eliminate `GenericSpec`. Currently all we need to do is to resolve the kinds of GenericSpec that contain names. Add `ScopeName` kind of `MiscDetails` for when we need a symbol in the scope to match the name of the scope. For example, `module m` cannot contain a declaration of a new `m`. Subprograms need real details because they can be called recursively. Fix output of partially resolved modules where we know it is a submodule but have not yet resolved the ancestor. Original-commit: flang-compiler/f18@5c1a4b99d2421f5b32e83426488d3fdf7951cfba Reviewed-on: https://github.com/flang-compiler/f18/pull/238 Tree-same-pre-rewrite: false
2018-11-17 04:43:08 +08:00
for (const auto &[location, module] : x.occurrences()) {
os << " from " << module->GetName().value() << " at " << location;
}
},
[flang] More name resolution for construct entities Push a new scope for constructs and statements that require one (DataStmt, DO CONCURRENT, ForallConstruct, ForallStmt -- there are more to do). Currently we use the Block kind of scope because there is no difference. Perhaps that kind should be renamed to Construct, though it does apply to statements as well as constructs. Add DeclareConstructEntity to create a construct or statement entity. When the type is not specified it can come from the type of a symbol in the enclosing scope with the same name. Change DeclareObjectEntity et al. to return the symbol declared, for the benefit of DeclareConstructEntity. Use DeclareConstructEntity for DO CONCURRENT index-name, LOCAL, and LOCAL_INIT variables and the data-i-do-variable in DataImpliedDo Names in SHARED locality spec need special handling: create a new kinds of symbol with HostAssocDetails to represent the host-association of the shared variables within the construct scope. That symbol gets the LocalityShared flag without affecting the symbol in the outer scope. HostAssoc symbols may be useful in other contexts, e.g. up-level references to local variables. Add parser::DoConstruct::IsDoConcurrent() because DO CONCURRENT loops introduce a construct scope while other DO loops do not. Move CanonicalizeDo to before name resolution so that name resolution doesn't have to deal with labeled DO CONCURRENT loops. Allow for type of index name to be specified in ConcurrentHeader. Resolve the derived type name in an AllocateStmt, StructureConstructor Original-commit: flang-compiler/f18@bc7b9891367f3174c9b5018ce5636a36a5a76c1c Reviewed-on: https://github.com/flang-compiler/f18/pull/214
2018-10-18 22:55:48 +08:00
[](const HostAssocDetails &) {},
[&](const GenericDetails &x) {
os << ' ' << x.kind().ToString();
2019-07-31 06:29:50 +08:00
DumpBool(os, "(specific)", x.specific() != nullptr);
DumpBool(os, "(derivedType)", x.derivedType() != nullptr);
os << " procs:";
[flang] Merge pull request flang-compiler/f18#539 from flang-compiler/tsk1 Check that procedures of a generic are distinguishable Original-commit: flang-compiler/f18@a24701e313019dbf84179b79e234f92d61de0fa6 Reviewed-on: https://github.com/flang-compiler/f18/pull/539 Due to a conflicting rebase during the linearizing of flang-compiler/f18, this commit squashes a number of other commits: flang-compiler/f18@9b1343af36bd27b110f31dab39c3a18a657a5760 Some cleanup in characteristics.{h,cc} flang-compiler/f18@ddb70e53d2b4e2bba12686e4ac3c26052758fcc3 Merge branch 'master' of github.com:flang-compiler/f18 into tsk1 flang-compiler/f18@d1eef9506610a427f992180f6b59cafe09abb9b9 Merge branch 'master' of github.com:flang-compiler/f18 into tsk1 flang-compiler/f18@24a6d3ffbf4d26d92222b27faa155bb5b3f517f4 Make test_folding.sh stricter in test for warnings flang-compiler/f18@c2c5b640604acceb45823de8cb5716d6921da7d4 Replace SymbolList with SymbolVector flang-compiler/f18@c8499584dff12381c2ce6d4718761cd225b4d97a Add CopyAttrs to copy attributes from Symbol flang-compiler/f18@0573ffd8b2ed5757e06a4fc6d5ffc4401e800c32 Replace cascading detailsIf calls with std::visit flang-compiler/f18@28ec62b3ffeec1d25fde330069b050655bb52a5d Add name to characteristics::DummyArgument flang-compiler/f18@568eaf01145d4ee979423d06f2a65d07222f6841 Add name to CopySymbol() flang-compiler/f18@8c557b09e752da205cd300f63b5ca69806fb2e78 Check that procedures of a generic are distinguishable flang-compiler/f18@50515fd987fd5479567e1b497f6ba93974ffde76 Merge branch 'master' of github.com:flang-compiler/f18 into tsk1 flang-compiler/f18@a7963e98a4aedc97784b99903d04cdc48fd4c346 Address review comments flang-compiler/f18@edd65b3962dbaa1121c166d47c90730e39c25a04 Merge branch 'master' of github.com:flang-compiler/f18 into tsk1
2019-07-03 05:00:44 +08:00
DumpSymbolVector(os, x.specificProcs());
},
[&](const ProcBindingDetails &x) {
os << " => " << x.symbol().name();
DumpOptional(os, "passName", x.passName());
},
[&](const NamelistDetails &x) {
os << ':';
[flang] Merge pull request flang-compiler/f18#539 from flang-compiler/tsk1 Check that procedures of a generic are distinguishable Original-commit: flang-compiler/f18@a24701e313019dbf84179b79e234f92d61de0fa6 Reviewed-on: https://github.com/flang-compiler/f18/pull/539 Due to a conflicting rebase during the linearizing of flang-compiler/f18, this commit squashes a number of other commits: flang-compiler/f18@9b1343af36bd27b110f31dab39c3a18a657a5760 Some cleanup in characteristics.{h,cc} flang-compiler/f18@ddb70e53d2b4e2bba12686e4ac3c26052758fcc3 Merge branch 'master' of github.com:flang-compiler/f18 into tsk1 flang-compiler/f18@d1eef9506610a427f992180f6b59cafe09abb9b9 Merge branch 'master' of github.com:flang-compiler/f18 into tsk1 flang-compiler/f18@24a6d3ffbf4d26d92222b27faa155bb5b3f517f4 Make test_folding.sh stricter in test for warnings flang-compiler/f18@c2c5b640604acceb45823de8cb5716d6921da7d4 Replace SymbolList with SymbolVector flang-compiler/f18@c8499584dff12381c2ce6d4718761cd225b4d97a Add CopyAttrs to copy attributes from Symbol flang-compiler/f18@0573ffd8b2ed5757e06a4fc6d5ffc4401e800c32 Replace cascading detailsIf calls with std::visit flang-compiler/f18@28ec62b3ffeec1d25fde330069b050655bb52a5d Add name to characteristics::DummyArgument flang-compiler/f18@568eaf01145d4ee979423d06f2a65d07222f6841 Add name to CopySymbol() flang-compiler/f18@8c557b09e752da205cd300f63b5ca69806fb2e78 Check that procedures of a generic are distinguishable flang-compiler/f18@50515fd987fd5479567e1b497f6ba93974ffde76 Merge branch 'master' of github.com:flang-compiler/f18 into tsk1 flang-compiler/f18@a7963e98a4aedc97784b99903d04cdc48fd4c346 Address review comments flang-compiler/f18@edd65b3962dbaa1121c166d47c90730e39c25a04 Merge branch 'master' of github.com:flang-compiler/f18 into tsk1
2019-07-03 05:00:44 +08:00
DumpSymbolVector(os, x.objects());
},
[&](const CommonBlockDetails &x) {
if (x.alignment()) {
os << " alignment=" << x.alignment();
}
os << ':';
for (const auto &object : x.objects()) {
os << ' ' << object->name();
}
},
[&](const FinalProcDetails &) {},
[&](const TypeParamDetails &x) {
DumpOptional(os, "type", x.type());
os << ' ' << common::EnumToString(x.attr());
DumpExpr(os, "init", x.init());
},
[&](const MiscDetails &x) {
os << ' ' << MiscDetails::EnumToString(x.kind());
},
[flang] Resolve names in ASSOCIATE and SELECT TYPE Create `AssocEntityDetails` for symbols that represent entities identified by the associate-name in ASSOCIATE and SELECT TYPE constructs. For ASSOCIATE, create a new scope for the associated entity. For SELECT TYPE, create a new scope for each of type guard blocks. Each one contains an associated entity with the appropriate type. For SELECT TYPE, also create a place-holder symbol for the associate-name in the SELECT TYPE statement. The real symbols are in the new scopes and none of them is uniquely identified with the associate-name. Handling of `Selector` is common between these, with `associate-name => expr | variable` recorded in `ConstructVisitor::association_`. When the selector is an expression, derive the type of the associated entity from the type of the expression. This required some refactoring of how `DeclTypeSpec`s are created. The `DerivedTypeSpec` that comes from and expression is const so we can only create const `DeclTypeSpec`s from it. But there were times during name resolution when we needed to set type parameters in the current `DeclTypeSpec`. Now the non-const `DerivedTypeSpec` is saved separately from the const `DeclTypeSpec` while we are processing a declaration type spec. This makes it unnecessary to save the derived type name. Add a type alias for `common::Indirection` to reduce verbosity. Original-commit: flang-compiler/f18@b7668cebe49a122ea23c89c81eafdeba243bbfaf Reviewed-on: https://github.com/flang-compiler/f18/pull/261 Tree-same-pre-rewrite: false
2019-01-16 08:59:20 +08:00
[&](const auto &x) { os << x; },
[flang] Partial implementation of Symbols and Scopes. A Symbol consists of a common part (in class Symbol) containing name, owner, attributes. Information for a specific kind of symbol is in a variant containing one of the *Details classes. So the kind of symbol is determined by the type of details class stored in the details_ variant. For scopes there is a single Scope class with an enum indicating the kind. So far there isn't a need for extra kind-specific details as with Symbols but that could change. Symbols defined in a Scope are stored there in a simple map. resolve-names.cc is a partial implementation of a parse-tree walker that resolves names to Symbols. Currently is only handles functions (which introduce a new Scope) and entity-decls. The test-type executable was reused as a driver for this to avoid the need for a new one. Sample output is below. When each "end function" is encountered the scope is dumped, which shows the symbols defined in it. $ cat a.f90 pure integer(8) function foo(arg1, arg2) result(res) integer :: arg1 real :: arg2 contains function bar(arg1) real :: bar real :: arg1 end function end function $ Debug/tools/f18/test-type a.f90 Subprogram scope: 0 children arg1: Entity type: REAL bar: Entity type: REAL Subprogram scope: 1 children arg1: Entity type: INTEGER arg2: Entity type: REAL bar: Subprogram (arg1) foo: Subprogram (arg1, arg2) result(res) res: Entity type: INTEGER(8) Original-commit: flang-compiler/f18@1cd2fbc04da1d6bb2ef5bc1cf07c808460ea7547 Reviewed-on: https://github.com/flang-compiler/f18/pull/30 Tree-same-pre-rewrite: false
2018-03-23 08:08:20 +08:00
},
details);
return os;
}
llvm::raw_ostream &operator<<(llvm::raw_ostream &o, Symbol::Flag flag) {
return o << Symbol::EnumToString(flag);
}
llvm::raw_ostream &operator<<(
llvm::raw_ostream &o, const Symbol::Flags &flags) {
std::size_t n{flags.count()};
std::size_t seen{0};
for (std::size_t j{0}; seen < n; ++j) {
Symbol::Flag flag{static_cast<Symbol::Flag>(j)};
if (flags.test(flag)) {
if (seen++ > 0) {
o << ", ";
}
o << flag;
}
}
return o;
}
llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Symbol &symbol) {
os << symbol.name();
if (!symbol.attrs().empty()) {
os << ", " << symbol.attrs();
}
if (!symbol.flags().empty()) {
os << " (" << symbol.flags() << ')';
}
if (symbol.size_) {
os << " size=" << symbol.size_ << " offset=" << symbol.offset_;
}
os << ": " << symbol.details_;
[flang] Partial implementation of Symbols and Scopes. A Symbol consists of a common part (in class Symbol) containing name, owner, attributes. Information for a specific kind of symbol is in a variant containing one of the *Details classes. So the kind of symbol is determined by the type of details class stored in the details_ variant. For scopes there is a single Scope class with an enum indicating the kind. So far there isn't a need for extra kind-specific details as with Symbols but that could change. Symbols defined in a Scope are stored there in a simple map. resolve-names.cc is a partial implementation of a parse-tree walker that resolves names to Symbols. Currently is only handles functions (which introduce a new Scope) and entity-decls. The test-type executable was reused as a driver for this to avoid the need for a new one. Sample output is below. When each "end function" is encountered the scope is dumped, which shows the symbols defined in it. $ cat a.f90 pure integer(8) function foo(arg1, arg2) result(res) integer :: arg1 real :: arg2 contains function bar(arg1) real :: bar real :: arg1 end function end function $ Debug/tools/f18/test-type a.f90 Subprogram scope: 0 children arg1: Entity type: REAL bar: Entity type: REAL Subprogram scope: 1 children arg1: Entity type: INTEGER arg2: Entity type: REAL bar: Subprogram (arg1) foo: Subprogram (arg1, arg2) result(res) res: Entity type: INTEGER(8) Original-commit: flang-compiler/f18@1cd2fbc04da1d6bb2ef5bc1cf07c808460ea7547 Reviewed-on: https://github.com/flang-compiler/f18/pull/30 Tree-same-pre-rewrite: false
2018-03-23 08:08:20 +08:00
return os;
}
// Output a unique name for a scope by qualifying it with the names of
// parent scopes. For scopes without corresponding symbols, use the kind
// with an index (e.g. Block1, Block2, etc.).
static void DumpUniqueName(llvm::raw_ostream &os, const Scope &scope) {
if (!scope.IsGlobal()) {
DumpUniqueName(os, scope.parent());
os << '/';
if (auto *scopeSymbol{scope.symbol()};
scopeSymbol && !scopeSymbol->name().empty()) {
os << scopeSymbol->name();
} else {
int index{1};
for (auto &child : scope.parent().children()) {
if (child == scope) {
break;
}
if (child.kind() == scope.kind()) {
++index;
}
}
os << Scope::EnumToString(scope.kind()) << index;
}
}
}
// Dump a symbol for UnparseWithSymbols. This will be used for tests so the
// format should be reasonably stable.
llvm::raw_ostream &DumpForUnparse(
llvm::raw_ostream &os, const Symbol &symbol, bool isDef) {
DumpUniqueName(os, symbol.owner());
os << '/' << symbol.name();
if (isDef) {
if (!symbol.attrs().empty()) {
os << ' ' << symbol.attrs();
}
if (!symbol.flags().empty()) {
os << " (" << symbol.flags() << ')';
}
os << ' ' << symbol.GetDetailsName();
DumpType(os, symbol.GetType());
}
return os;
}
const DerivedTypeSpec *Symbol::GetParentTypeSpec(const Scope *scope) const {
if (const Symbol * parentComponent{GetParentComponent(scope)}) {
const auto &object{parentComponent->get<ObjectEntityDetails>()};
return &object.type()->derivedTypeSpec();
} else {
return nullptr;
}
}
const Symbol *Symbol::GetParentComponent(const Scope *scope) const {
if (const auto *dtDetails{detailsIf<DerivedTypeDetails>()}) {
if (const Scope * localScope{scope ? scope : scope_}) {
return dtDetails->GetParentComponent(DEREF(localScope));
}
}
return nullptr;
}
void DerivedTypeDetails::add_component(const Symbol &symbol) {
if (symbol.test(Symbol::Flag::ParentComp)) {
CHECK(componentNames_.empty());
}
componentNames_.push_back(symbol.name());
}
const Symbol *DerivedTypeDetails::GetParentComponent(const Scope &scope) const {
if (auto extends{GetParentComponentName()}) {
if (auto iter{scope.find(*extends)}; iter != scope.cend()) {
if (const Symbol & symbol{*iter->second};
symbol.test(Symbol::Flag::ParentComp)) {
return &symbol;
}
}
}
return nullptr;
}
void TypeParamDetails::set_type(const DeclTypeSpec &type) {
CHECK(!type_);
type_ = &type;
}
bool GenericKind::IsIntrinsicOperator() const {
return Is(OtherKind::Concat) || Has<common::LogicalOperator>() ||
Has<common::NumericOperator>() || Has<common::RelationalOperator>();
}
bool GenericKind::IsOperator() const {
return IsDefinedOperator() || IsIntrinsicOperator();
}
std::string GenericKind::ToString() const {
return std::visit(
common::visitors {
[](const OtherKind &x) { return EnumToString(x); },
[](const DefinedIo &x) { return EnumToString(x); },
#if !__clang__ && __GNUC__ == 7 && __GNUC_MINOR__ == 2
[](const common::NumericOperator &x) {
return common::EnumToString(x);
},
[](const common::LogicalOperator &x) {
return common::EnumToString(x);
},
[](const common::RelationalOperator &x) {
return common::EnumToString(x);
},
#else
[](const auto &x) { return common::EnumToString(x); },
#endif
},
u);
}
bool GenericKind::Is(GenericKind::OtherKind x) const {
const OtherKind *y{std::get_if<OtherKind>(&u)};
return y && *y == x;
}
} // namespace Fortran::semantics