llvm/flang/lib/semantics/semantics.cc

217 lines
6.7 KiB
C++
Raw Normal View History

[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 01:59:20 +01:00
// Copyright (c) 2018-2019, 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.
#include "semantics.h"
#include "assignment.h"
#include "canonicalize-do.h"
#include "check-allocate.h"
#include "check-arithmeticif.h"
#include "check-coarray.h"
#include "check-deallocate.h"
[flang] These changes are for issue 458, to perform semantic checks on DO variable and initial, final, and step expressions. As a new extension, we want to allow REAL and DOUBLE PRECISION values for them by default. Here's a summary of the changes: - There already existed infrastructure for semantic checking of DO loops that was partially specific to DO CONCURRENT loops. Because I re-used some of this infrastructure, I renamed some files and classes from "concurrent" to "stmt". - I added some functions to distinguish among the different kinds of DO statements. - I added the functions to check-do-stmt.cc to produce the necessary warnins and errors. Note that there are no tests for the warnings since the necessary testing infrastructure does not yet exist. - I changed test-errors.sh so that additional compilation options can be specified in the test source. - I added two new tests to test for the various kinds of values that can be used for the DO variables and control expressions. The two tests are identical except for the use of different compilation options. dosemantics03.f90 specifies the options "-Mstandard -Werror" to produce error messages for the use of REAL and DOUBLE PRECISION DO variables and controls. dosemantics04.f90 uses the default options and only produces error messages for contructs that are erroneous by default. Original-commit: flang-compiler/f18@f484660c75941b5af93bd8bc7aabe73ab958769c Reviewed-on: https://github.com/flang-compiler/f18/pull/478 Tree-same-pre-rewrite: false
2019-06-05 00:14:34 +02:00
#include "check-do-stmt.h"
#include "check-if-stmt.h"
#include "check-io.h"
#include "check-nullify.h"
#include "check-return.h"
#include "check-stop.h"
#include "expression.h"
#include "mod-file.h"
#include "resolve-labels.h"
#include "resolve-names.h"
#include "rewrite-parse-tree.h"
#include "scope.h"
#include "symbol.h"
#include "../common/default-kinds.h"
[flang] Create framework for checking statement semantics Add `SemanticsVisitor` as the visitor class to perform statement semantics checks. Its template parameters are "checker" classes that perform the checks. They have `Enter` and `Leave` functions that are called for the corresponding parse tree nodes (`Enter` before the children, `Leave` after). Unlike `Pre` and `Post` in visitors they cannot prevent the parse tree walker from visiting child nodes. Existing checks have been incorporated into this framework: - `ExprChecker` replaces `AnalyzeExpressions()` - `AssignmentChecker` replaces `AnalyzeAssignments()` - `DoConcurrentChecker` replaces `CheckDoConcurrentConstraints()` Adding a new checker requires: - defining the checker class: - with BaseChecker as virtual base class - constructible from `SemanticsContext` - with Enter/Leave functions for nodes of interest - add the checker class to the template parameters of `StatementSemantics` Because these checkers and also `ResolveNamesVisitor` require tracking the current statement source location, that has been moved into `SemanticsContext`. `ResolveNamesVisitor` and `SemanticsVisitor` update the location when `Statement` nodes are encountered, making it available for error messages. `AnalyzeKindSelector()` now has access to the current statement through the context and so no longer needs to have it passed in. Test `assign01.f90` was added to verify that `AssignmentChecker` is actually doing something. Original-commit: flang-compiler/f18@3a222c36731029fabf026e5301dc60f0587595be Reviewed-on: https://github.com/flang-compiler/f18/pull/315 Tree-same-pre-rewrite: false
2019-03-06 01:52:50 +01:00
#include "../parser/parse-tree-visitor.h"
namespace Fortran::semantics {
static void DoDumpSymbols(std::ostream &, const Scope &, int indent = 0);
static void PutIndent(std::ostream &, int indent);
[flang] Create framework for checking statement semantics Add `SemanticsVisitor` as the visitor class to perform statement semantics checks. Its template parameters are "checker" classes that perform the checks. They have `Enter` and `Leave` functions that are called for the corresponding parse tree nodes (`Enter` before the children, `Leave` after). Unlike `Pre` and `Post` in visitors they cannot prevent the parse tree walker from visiting child nodes. Existing checks have been incorporated into this framework: - `ExprChecker` replaces `AnalyzeExpressions()` - `AssignmentChecker` replaces `AnalyzeAssignments()` - `DoConcurrentChecker` replaces `CheckDoConcurrentConstraints()` Adding a new checker requires: - defining the checker class: - with BaseChecker as virtual base class - constructible from `SemanticsContext` - with Enter/Leave functions for nodes of interest - add the checker class to the template parameters of `StatementSemantics` Because these checkers and also `ResolveNamesVisitor` require tracking the current statement source location, that has been moved into `SemanticsContext`. `ResolveNamesVisitor` and `SemanticsVisitor` update the location when `Statement` nodes are encountered, making it available for error messages. `AnalyzeKindSelector()` now has access to the current statement through the context and so no longer needs to have it passed in. Test `assign01.f90` was added to verify that `AssignmentChecker` is actually doing something. Original-commit: flang-compiler/f18@3a222c36731029fabf026e5301dc60f0587595be Reviewed-on: https://github.com/flang-compiler/f18/pull/315 Tree-same-pre-rewrite: false
2019-03-06 01:52:50 +01:00
// A parse tree visitor that calls Enter/Leave functions from each checker
// class C supplied as template parameters. Enter is called before the node's
// children are visited, Leave is called after. No two checkers may have the
// same Enter or Leave function. Each checker must be constructible from
// SemanticsContext and have BaseChecker as a virtual base class.
template<typename... C> class SemanticsVisitor : public virtual C... {
public:
[flang] Create framework for checking statement semantics Add `SemanticsVisitor` as the visitor class to perform statement semantics checks. Its template parameters are "checker" classes that perform the checks. They have `Enter` and `Leave` functions that are called for the corresponding parse tree nodes (`Enter` before the children, `Leave` after). Unlike `Pre` and `Post` in visitors they cannot prevent the parse tree walker from visiting child nodes. Existing checks have been incorporated into this framework: - `ExprChecker` replaces `AnalyzeExpressions()` - `AssignmentChecker` replaces `AnalyzeAssignments()` - `DoConcurrentChecker` replaces `CheckDoConcurrentConstraints()` Adding a new checker requires: - defining the checker class: - with BaseChecker as virtual base class - constructible from `SemanticsContext` - with Enter/Leave functions for nodes of interest - add the checker class to the template parameters of `StatementSemantics` Because these checkers and also `ResolveNamesVisitor` require tracking the current statement source location, that has been moved into `SemanticsContext`. `ResolveNamesVisitor` and `SemanticsVisitor` update the location when `Statement` nodes are encountered, making it available for error messages. `AnalyzeKindSelector()` now has access to the current statement through the context and so no longer needs to have it passed in. Test `assign01.f90` was added to verify that `AssignmentChecker` is actually doing something. Original-commit: flang-compiler/f18@3a222c36731029fabf026e5301dc60f0587595be Reviewed-on: https://github.com/flang-compiler/f18/pull/315 Tree-same-pre-rewrite: false
2019-03-06 01:52:50 +01:00
using C::Enter...;
using C::Leave...;
using BaseChecker::Enter;
using BaseChecker::Leave;
SemanticsVisitor(SemanticsContext &context)
: C{context}..., context_{context} {}
[flang] Create framework for checking statement semantics Add `SemanticsVisitor` as the visitor class to perform statement semantics checks. Its template parameters are "checker" classes that perform the checks. They have `Enter` and `Leave` functions that are called for the corresponding parse tree nodes (`Enter` before the children, `Leave` after). Unlike `Pre` and `Post` in visitors they cannot prevent the parse tree walker from visiting child nodes. Existing checks have been incorporated into this framework: - `ExprChecker` replaces `AnalyzeExpressions()` - `AssignmentChecker` replaces `AnalyzeAssignments()` - `DoConcurrentChecker` replaces `CheckDoConcurrentConstraints()` Adding a new checker requires: - defining the checker class: - with BaseChecker as virtual base class - constructible from `SemanticsContext` - with Enter/Leave functions for nodes of interest - add the checker class to the template parameters of `StatementSemantics` Because these checkers and also `ResolveNamesVisitor` require tracking the current statement source location, that has been moved into `SemanticsContext`. `ResolveNamesVisitor` and `SemanticsVisitor` update the location when `Statement` nodes are encountered, making it available for error messages. `AnalyzeKindSelector()` now has access to the current statement through the context and so no longer needs to have it passed in. Test `assign01.f90` was added to verify that `AssignmentChecker` is actually doing something. Original-commit: flang-compiler/f18@3a222c36731029fabf026e5301dc60f0587595be Reviewed-on: https://github.com/flang-compiler/f18/pull/315 Tree-same-pre-rewrite: false
2019-03-06 01:52:50 +01:00
template<typename N> bool Pre(const N &node) {
Enter(node);
return true;
}
template<typename N> void Post(const N &node) { Leave(node); }
template<typename T> bool Pre(const parser::Statement<T> &node) {
context_.set_location(&node.source);
Enter(node);
return true;
}
template<typename T> void Post(const parser::Statement<T> &node) {
Leave(node);
context_.set_location(nullptr);
}
bool Walk(const parser::Program &program) {
parser::Walk(program, *this);
return !context_.AnyFatalError();
}
private:
SemanticsContext &context_;
[flang] Create framework for checking statement semantics Add `SemanticsVisitor` as the visitor class to perform statement semantics checks. Its template parameters are "checker" classes that perform the checks. They have `Enter` and `Leave` functions that are called for the corresponding parse tree nodes (`Enter` before the children, `Leave` after). Unlike `Pre` and `Post` in visitors they cannot prevent the parse tree walker from visiting child nodes. Existing checks have been incorporated into this framework: - `ExprChecker` replaces `AnalyzeExpressions()` - `AssignmentChecker` replaces `AnalyzeAssignments()` - `DoConcurrentChecker` replaces `CheckDoConcurrentConstraints()` Adding a new checker requires: - defining the checker class: - with BaseChecker as virtual base class - constructible from `SemanticsContext` - with Enter/Leave functions for nodes of interest - add the checker class to the template parameters of `StatementSemantics` Because these checkers and also `ResolveNamesVisitor` require tracking the current statement source location, that has been moved into `SemanticsContext`. `ResolveNamesVisitor` and `SemanticsVisitor` update the location when `Statement` nodes are encountered, making it available for error messages. `AnalyzeKindSelector()` now has access to the current statement through the context and so no longer needs to have it passed in. Test `assign01.f90` was added to verify that `AssignmentChecker` is actually doing something. Original-commit: flang-compiler/f18@3a222c36731029fabf026e5301dc60f0587595be Reviewed-on: https://github.com/flang-compiler/f18/pull/315 Tree-same-pre-rewrite: false
2019-03-06 01:52:50 +01:00
};
using StatementSemanticsPass1 = ExprChecker;
using StatementSemanticsPass2 = SemanticsVisitor<AllocateChecker,
ArithmeticIfStmtChecker, AssignmentChecker, CoarrayChecker,
[flang] These changes are for issue 458, to perform semantic checks on DO variable and initial, final, and step expressions. As a new extension, we want to allow REAL and DOUBLE PRECISION values for them by default. Here's a summary of the changes: - There already existed infrastructure for semantic checking of DO loops that was partially specific to DO CONCURRENT loops. Because I re-used some of this infrastructure, I renamed some files and classes from "concurrent" to "stmt". - I added some functions to distinguish among the different kinds of DO statements. - I added the functions to check-do-stmt.cc to produce the necessary warnins and errors. Note that there are no tests for the warnings since the necessary testing infrastructure does not yet exist. - I changed test-errors.sh so that additional compilation options can be specified in the test source. - I added two new tests to test for the various kinds of values that can be used for the DO variables and control expressions. The two tests are identical except for the use of different compilation options. dosemantics03.f90 specifies the options "-Mstandard -Werror" to produce error messages for the use of REAL and DOUBLE PRECISION DO variables and controls. dosemantics04.f90 uses the default options and only produces error messages for contructs that are erroneous by default. Original-commit: flang-compiler/f18@f484660c75941b5af93bd8bc7aabe73ab958769c Reviewed-on: https://github.com/flang-compiler/f18/pull/478 Tree-same-pre-rewrite: false
2019-06-05 00:14:34 +02:00
DeallocateChecker, DoStmtChecker, IfStmtChecker, IoChecker,
NullifyChecker, ReturnStmtChecker, StopChecker>;
[flang] Create framework for checking statement semantics Add `SemanticsVisitor` as the visitor class to perform statement semantics checks. Its template parameters are "checker" classes that perform the checks. They have `Enter` and `Leave` functions that are called for the corresponding parse tree nodes (`Enter` before the children, `Leave` after). Unlike `Pre` and `Post` in visitors they cannot prevent the parse tree walker from visiting child nodes. Existing checks have been incorporated into this framework: - `ExprChecker` replaces `AnalyzeExpressions()` - `AssignmentChecker` replaces `AnalyzeAssignments()` - `DoConcurrentChecker` replaces `CheckDoConcurrentConstraints()` Adding a new checker requires: - defining the checker class: - with BaseChecker as virtual base class - constructible from `SemanticsContext` - with Enter/Leave functions for nodes of interest - add the checker class to the template parameters of `StatementSemantics` Because these checkers and also `ResolveNamesVisitor` require tracking the current statement source location, that has been moved into `SemanticsContext`. `ResolveNamesVisitor` and `SemanticsVisitor` update the location when `Statement` nodes are encountered, making it available for error messages. `AnalyzeKindSelector()` now has access to the current statement through the context and so no longer needs to have it passed in. Test `assign01.f90` was added to verify that `AssignmentChecker` is actually doing something. Original-commit: flang-compiler/f18@3a222c36731029fabf026e5301dc60f0587595be Reviewed-on: https://github.com/flang-compiler/f18/pull/315 Tree-same-pre-rewrite: false
2019-03-06 01:52:50 +01:00
static bool PerformStatementSemantics(
[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-25 22:18:33 +02:00
SemanticsContext &context, parser::Program &program) {
ResolveNames(context, program);
RewriteParseTree(context, program);
StatementSemanticsPass1{context}.Walk(program);
return StatementSemanticsPass2{context}.Walk(program);
}
SemanticsContext::SemanticsContext(
const common::IntrinsicTypeDefaultKinds &defaultKinds,
const parser::LanguageFeatureControl &languageFeatures,
parser::AllSources &allSources)
[flang] Name resolution for defined operators Instead of tracking just genericName_ while in a generic interface block or generic statement, now we immediately create a symbol for it. A parser::Name isn't good enough because a defined-operator or defined-io-generic-spec doesn't have a name. Change the parse tree to add a source field to GenericSpec. Use these as names for symbols for defined-operator and defined-io-generic-spec (e.g. "operator(+)" or "read(formatted)"). Change the source for defined-op-name to include the dots so that they can be distinguished from normal symbols with the same name (e.g. you can have both ".foo." and "foo"). These symbols have names in the symbol table like ".foo.", not "operator(.foo.)", because references to them have that form. Add GenericKind enum to GenericDetails and GenericBindingDetails. This allows us to know a symbol is "assignment(=)", for example, without having to do a string comparison. Add GenericSpecInfo to handle analyzing the various kinds of generic-spec and generating symbol names and GenericKind for them. Add reference to LanguageFeatureControl to SemanticsContext so that they can be checked during semantics. For this change, if LogicalAbbreviations is enabled, report an error if the user tries to define an operator named ".T." or ".F.". Add resolve-name-utils.cc to hold utility functions and classes that don't have to be in the ResolveNamesVisitor class hierarchy. The goal is to reduce the size of resolve-names.cc where possible. Original-commit: flang-compiler/f18@3081f694e21dbcaef2554198a682c9af57f2e185 Reviewed-on: https://github.com/flang-compiler/f18/pull/338
2019-03-18 19:48:02 +01:00
: defaultKinds_{defaultKinds}, languageFeatures_{languageFeatures},
allSources_{allSources},
intrinsics_{evaluate::IntrinsicProcTable::Configure(defaultKinds)},
foldingContext_{evaluate::FoldingContext{
parser::ContextualMessages{parser::CharBlock{}, &messages_}}} {}
SemanticsContext::~SemanticsContext() {}
[flang] Name resolution for defined operators Instead of tracking just genericName_ while in a generic interface block or generic statement, now we immediately create a symbol for it. A parser::Name isn't good enough because a defined-operator or defined-io-generic-spec doesn't have a name. Change the parse tree to add a source field to GenericSpec. Use these as names for symbols for defined-operator and defined-io-generic-spec (e.g. "operator(+)" or "read(formatted)"). Change the source for defined-op-name to include the dots so that they can be distinguished from normal symbols with the same name (e.g. you can have both ".foo." and "foo"). These symbols have names in the symbol table like ".foo.", not "operator(.foo.)", because references to them have that form. Add GenericKind enum to GenericDetails and GenericBindingDetails. This allows us to know a symbol is "assignment(=)", for example, without having to do a string comparison. Add GenericSpecInfo to handle analyzing the various kinds of generic-spec and generating symbol names and GenericKind for them. Add reference to LanguageFeatureControl to SemanticsContext so that they can be checked during semantics. For this change, if LogicalAbbreviations is enabled, report an error if the user tries to define an operator named ".T." or ".F.". Add resolve-name-utils.cc to hold utility functions and classes that don't have to be in the ResolveNamesVisitor class hierarchy. The goal is to reduce the size of resolve-names.cc where possible. Original-commit: flang-compiler/f18@3081f694e21dbcaef2554198a682c9af57f2e185 Reviewed-on: https://github.com/flang-compiler/f18/pull/338
2019-03-18 19:48:02 +01:00
bool SemanticsContext::IsEnabled(parser::LanguageFeature feature) const {
return languageFeatures_.IsEnabled(feature);
}
bool SemanticsContext::ShouldWarn(parser::LanguageFeature feature) const {
return languageFeatures_.ShouldWarn(feature);
}
[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 01:59:20 +01:00
const DeclTypeSpec &SemanticsContext::MakeNumericType(
TypeCategory category, int kind) {
if (kind == 0) {
kind = defaultKinds_.GetDefaultKind(category);
}
return globalScope_.MakeNumericType(category, KindExpr{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 01:59:20 +01:00
const DeclTypeSpec &SemanticsContext::MakeLogicalType(int kind) {
if (kind == 0) {
kind = defaultKinds_.GetDefaultKind(TypeCategory::Logical);
}
return globalScope_.MakeLogicalType(KindExpr{kind});
}
bool SemanticsContext::AnyFatalError() const {
return !messages_.empty() &&
(warningsAreErrors_ || messages_.AnyFatalError());
}
bool SemanticsContext::HasError(const Symbol &symbol) {
return CheckError(symbol.test(Symbol::Flag::Error));
}
bool SemanticsContext::HasError(const Symbol *symbol) {
return CheckError(!symbol || HasError(*symbol));
}
bool SemanticsContext::HasError(const parser::Name &name) {
return HasError(name.symbol);
}
void SemanticsContext::SetError(Symbol &symbol, bool value) {
if (value) {
CHECK(AnyFatalError());
symbol.set(Symbol::Flag::Error);
}
}
bool SemanticsContext::CheckError(bool error) {
CHECK(!error || AnyFatalError());
return error;
}
const Scope &SemanticsContext::FindScope(parser::CharBlock source) const {
return const_cast<SemanticsContext *>(this)->FindScope(source);
}
Scope &SemanticsContext::FindScope(parser::CharBlock source) {
if (auto *scope{globalScope_.FindScope(source)}) {
return *scope;
} else {
common::die("invalid source location");
}
}
bool Semantics::Perform() {
return ValidateLabels(context_.messages(), program_) &&
parser::CanonicalizeDo(program_) && // force line break
PerformStatementSemantics(context_, program_) &&
ModFileWriter{context_}.WriteAll();
}
void Semantics::EmitMessages(std::ostream &os) const {
context_.messages().Emit(os, cooked_);
}
void Semantics::DumpSymbols(std::ostream &os) {
DoDumpSymbols(os, context_.globalScope());
}
void DoDumpSymbols(std::ostream &os, const Scope &scope, int indent) {
PutIndent(os, indent);
os << Scope::EnumToString(scope.kind()) << " scope:";
if (const auto *symbol{scope.symbol()}) {
os << ' ' << symbol->name().ToString();
}
os << '\n';
++indent;
for (const auto &pair : scope) {
const auto &symbol{*pair.second};
PutIndent(os, indent);
os << symbol << '\n';
if (const auto *details{symbol.detailsIf<GenericDetails>()}) {
if (const auto &type{details->derivedType()}) {
PutIndent(os, indent);
os << *type << '\n';
}
}
}
for (const auto &pair : scope.commonBlocks()) {
const auto &symbol{*pair.second};
PutIndent(os, indent);
os << symbol << '\n';
}
for (const auto &child : scope.children()) {
DoDumpSymbols(os, child, indent);
}
--indent;
}
static void PutIndent(std::ostream &os, int indent) {
for (int i = 0; i < indent; ++i) {
os << " ";
}
}
}