[flang] Use reference_wrapper in vectors and sets

Convert some CharBlock references to values

Replace more pointers with reference wrappers

Restore object references that were converted to value semantics in an earlier commit

Use Reference<> in Scope

Fix new component iterator

Document pitfall that bit me

final tweaks before rebasing and merging

Rebasing

Original-commit: flang-compiler/f18@87874af934
Reviewed-on: https://github.com/flang-compiler/f18/pull/788
This commit is contained in:
peter klausler 2019-10-22 16:53:29 -07:00
parent 2839cb3835
commit afd39cd49c
33 changed files with 609 additions and 551 deletions

View File

@ -159,10 +159,14 @@ class.
clear. Consider reworking any code that uses `malloc()` or a (non-placement)
`operator new`.
See the section on Pointers below for some suggested options.
1. Use references for `const` arguments; prefer `const` references to values for
all but small types that are trivially copyable (e.g., use `const std::string &`
and `int`). Use non-`const` pointers for output arguments. Put output arguments
last (_pace_ the standard C library conventions for `memcpy()` & al.).
1. When defining argument types, use values when object semantics are
not required and the value is small and copyable without allocation
(e.g., `int`);
use `const` or rvalue references for larger values (e.g., `std::string`);
use `const` references to rather than pointers to immutable objects;
and use non-`const` references for mutable objects, including "output" arguments
when they can't be function results.
Put such output arguments last (_pace_ the standard C library conventions for `memcpy()` & al.).
1. Prefer `typename` to `class` in template argument declarations.
1. Prefer `enum class` to plain `enum` wherever `enum class` will work.
We have an `ENUM_CLASS` macro that helps capture the names of constants.
@ -206,18 +210,29 @@ data in this project.
Some of these are standard C++ language and library features,
while others are local inventions in `lib/common`:
* Bare pointers (`Foo *p`): these are obviously nullable, non-owning,
undefined when uninitialized, shallowly copyable, reassignable, and almost
never the right abstraction to use in this project.
undefined when uninitialized, shallowly copyable, reassignable, and often
not the right abstraction to use in this project.
But they can be the right choice to represent an optional
non-owning reference, as in a function result.
Use the `DEREF()` macro to convert a pointer to a reference that isn't
already protected by an explicit test for null.
* References (`Foo &r`, `const Foo &r`): non-nullable, not owning,
shallowly copyable, and not reassignable.
References are great for invisible indirection to objects whose lifetimes are
broader than that of the reference.
(Sometimes when a class data member should be a reference, but we also need
reassignability, it will be declared as a pointer, and its accessor
will be defined to return a reference.)
Take care when initializing a reference with another reference to ensure
that a copy is not made because only one of the references is `const`;
this is a pernicious C++ language pitfall!
* Rvalue references (`Foo &&r`): These are non-nullable references
*with* ownership, and they are ubiquitously used for formal arguments
wherever appropriate.
* `std::reference_wrapper<>`: non-nullable, not owning, shallowly
copyable, and (unlike bare references) reassignable, so suitable for
use in STL containers and for data members in classes that need to be
copyable or assignable.
* `common::Reference<>`: like `std::reference_wrapper<>`, but also supports
move semantics, member access, and comparison for equality; suitable for use in
`std::variant<>`.
* `std::unique_ptr<>`: A nullable pointer with ownership, null by default,
not copyable, reassignable.
F18 has a helpful `Deleter<>` class template that makes `unique_ptr<>`
@ -240,14 +255,17 @@ of that standard feature is prohibitive.
A feature matrix:
| pointer | nullable | default null | owning | reassignable | copyable | undefined type ok? |
| ------- | -------- | ------------ | ------ | ------------ | -------- | ------------------ |
| `*p` | yes | no | no | yes | shallowly | yes |
| `&r` | no | n/a | no | no | shallowly | yes |
| `unique_ptr<>` | yes | yes | yes | yes | no | yes, with work |
| `shared_ptr<>` | yes | yes | yes | yes | shallowly | no |
| `Indirection<>` | no | n/a | yes | yes | optionally deeply | yes, with work |
| `CountedReference<>` | yes | yes | yes | yes | shallowly | no |
| indirection | nullable | default null | owning | reassignable | copyable | undefined type ok? |
| ----------- | -------- | ------------ | ------ | ------------ | -------- | ------------------ |
| `*p` | yes | no | no | yes | shallowly | yes |
| `&r` | no | n/a | no | no | shallowly | yes |
| `&&r` | no | n/a | yes | no | shallowly | yes |
| `reference_wrapper<>` | no | n/a | no | yes | shallowly | yes |
| `Reference<>` | no | n/a | no | yes | shallowly | yes |
| `unique_ptr<>` | yes | yes | yes | yes | no | yes, with work |
| `shared_ptr<>` | yes | yes | yes | yes | shallowly | no |
| `Indirection<>` | no | n/a | yes | yes | optionally deeply | yes, with work |
| `CountedReference<>` | yes | yes | yes | yes | shallowly | no |
### Overall design preferences
Don't use dynamic solutions to solve problems that can be solved at

View File

@ -0,0 +1,62 @@
// Copyright (c) 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.
// Implements a better std::reference_wrapper<> template class with
// move semantics, equality testing, and member access.
// Use Reference<A> in place of a real A& reference when assignability is
// required; safer than a bare pointer because it's guaranteed to not be null.
#ifndef FORTRAN_COMMON_REFERENCE_H_
#define FORTRAN_COMMON_REFERENCE_H_
#include <type_traits>
namespace Fortran::common {
template<typename A> class Reference {
public:
using type = A;
Reference(type &x) : p_{&x} {}
Reference(const Reference &that) : p_{that.p_} {}
Reference(Reference &&that) : p_{that.p_} {}
Reference &operator=(const Reference &that) {
p_ = that.p_;
return *this;
}
Reference &operator=(Reference &&that) {
p_ = that.p_;
return *this;
}
// Implicit conversions to references are supported only for
// const-qualified types in order to avoid any pernicious
// creation of a temporary copy in cases like:
// Reference<type> ref;
// const Type &x{ref}; // creates ref to temp copy!
operator std::conditional_t<std::is_const_v<type>, type &, void>() const
noexcept {
if constexpr (std::is_const_v<type>) {
return *p_;
}
}
type &get() const noexcept { return *p_; }
type *operator->() const { return p_; }
type &operator*() const { return *p_; }
bool operator==(Reference that) const { return *p_ == *that.p_; }
bool operator!=(Reference that) const { return *p_ != *that.p_; }
private:
type *p_; // never null
};
template<typename A> Reference(A &)->Reference<A>;
}
#endif

View File

@ -17,6 +17,7 @@
#include "indirection.h"
#include "reference-counted.h"
#include "reference.h"
#include <memory>
#include <optional>
#include <type_traits>
@ -126,6 +127,11 @@ struct UnwrapperHelper {
[](const auto &x) -> std::add_const_t<A> * { return Unwrap<A>(x); }, u);
}
template<typename A, typename B>
static auto Unwrap(const Reference<B> &ref) -> Constify<A, B> * {
return Unwrap<A>(*ref);
}
template<typename A, typename B, bool COPY>
static auto Unwrap(const Indirection<B, COPY> &p) -> Constify<A, B> * {
return Unwrap<A>(*p);

View File

@ -27,8 +27,8 @@ ActualArgument::ActualArgument(common::CopyableIndirection<Expr<SomeType>> &&v)
ActualArgument::ActualArgument(AssumedType x) : u_{x} {}
ActualArgument::~ActualArgument() {}
ActualArgument::AssumedType::AssumedType(const semantics::Symbol &symbol)
: symbol_{&symbol} {
ActualArgument::AssumedType::AssumedType(const Symbol &symbol)
: symbol_{symbol} {
const semantics::DeclTypeSpec *type{symbol.GetType()};
CHECK(
type != nullptr && type->category() == semantics::DeclTypeSpec::TypeStar);
@ -110,7 +110,7 @@ int ProcedureDesignator::Rank() const {
return 0;
}
const semantics::Symbol *ProcedureDesignator::GetInterfaceSymbol() const {
const Symbol *ProcedureDesignator::GetInterfaceSymbol() const {
if (const Symbol * symbol{GetSymbol()}) {
if (const auto *details{
symbol->detailsIf<semantics::ProcEntityDetails>()}) {
@ -149,7 +149,7 @@ const Component *ProcedureDesignator::GetComponent() const {
const Symbol *ProcedureDesignator::GetSymbol() const {
return std::visit(
common::visitors{
[](const Symbol *sym) { return sym; },
[](SymbolRef symbol) { return &*symbol; },
[](const common::CopyableIndirection<Component> &c) {
return &c.value().GetLastSymbol();
},
@ -162,7 +162,7 @@ std::string ProcedureDesignator::GetName() const {
return std::visit(
common::visitors{
[](const SpecificIntrinsic &i) { return i.name; },
[](const Symbol *sym) { return sym->name().ToString(); },
[](const Symbol &symbol) { return symbol.name().ToString(); },
[](const common::CopyableIndirection<Component> &c) {
return c.value().GetLastSymbol().name().ToString();
},

View File

@ -20,6 +20,7 @@
#include "formatting.h"
#include "type.h"
#include "../common/indirection.h"
#include "../common/reference.h"
#include "../parser/char-block.h"
#include "../semantics/attr.h"
#include <optional>
@ -48,6 +49,9 @@ extern template class Fortran::common::Indirection<
namespace Fortran::evaluate {
using semantics::Symbol;
using SymbolRef = common::Reference<const Symbol>;
class ActualArgument {
public:
// Dummy arguments that are TYPE(*) can be forwarded as actual arguments.
@ -55,17 +59,17 @@ public:
// represented in expressions as a special case of an actual argument.
class AssumedType {
public:
explicit AssumedType(const semantics::Symbol &);
explicit AssumedType(const Symbol &);
DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(AssumedType)
const semantics::Symbol &symbol() const { return *symbol_; }
const Symbol &symbol() const { return symbol_; }
int Rank() const;
bool operator==(const AssumedType &that) const {
return symbol_ == that.symbol_;
return &*symbol_ == &*that.symbol_;
}
std::ostream &AsFortran(std::ostream &) const;
private:
const semantics::Symbol *symbol_;
SymbolRef symbol_;
};
explicit ActualArgument(Expr<SomeType> &&);
@ -91,7 +95,7 @@ public:
}
}
const semantics::Symbol *GetAssumedTypeDummy() const {
const Symbol *GetAssumedTypeDummy() const {
if (const AssumedType * aType{std::get_if<AssumedType>(&u_)}) {
return &aType->symbol();
} else {
@ -141,17 +145,17 @@ struct SpecificIntrinsic {
struct ProcedureDesignator {
EVALUATE_UNION_CLASS_BOILERPLATE(ProcedureDesignator)
explicit ProcedureDesignator(SpecificIntrinsic &&i) : u{std::move(i)} {}
explicit ProcedureDesignator(const semantics::Symbol &n) : u{&n} {}
explicit ProcedureDesignator(const Symbol &n) : u{n} {}
explicit ProcedureDesignator(Component &&);
// Exactly one of these will return a non-null pointer.
const SpecificIntrinsic *GetSpecificIntrinsic() const;
const semantics::Symbol *GetSymbol() const; // symbol or component symbol
const Symbol *GetSymbol() const; // symbol or component symbol
// Always null if the procedure is intrinsic.
const Component *GetComponent() const;
const semantics::Symbol *GetInterfaceSymbol() const;
const Symbol *GetInterfaceSymbol() const;
std::string GetName() const;
std::optional<DynamicType> GetType() const;
@ -161,7 +165,7 @@ struct ProcedureDesignator {
std::ostream &AsFortran(std::ostream &) const;
// TODO: When calling X%F, pass X as PASS argument unless NOPASS
std::variant<SpecificIntrinsic, const semantics::Symbol *,
std::variant<SpecificIntrinsic, SymbolRef,
common::CopyableIndirection<Component>>
u;
};

View File

@ -18,12 +18,20 @@
#include "formatting.h"
#include "type.h"
#include "../common/default-kinds.h"
#include "../common/reference.h"
#include <map>
#include <ostream>
#include <vector>
namespace Fortran::semantics {
class Symbol;
}
namespace Fortran::evaluate {
using semantics::Symbol;
using SymbolRef = common::Reference<const Symbol>;
// Wraps a constant value in a class templated by its resolved type.
// This Constant<> template class should be instantiated only for
// concrete intrinsic types and SomeDerived. There is no instance
@ -191,8 +199,8 @@ private:
};
class StructureConstructor;
using StructureConstructorValues = std::map<const semantics::Symbol *,
common::CopyableIndirection<Expr<SomeType>>>;
using StructureConstructorValues =
std::map<SymbolRef, common::CopyableIndirection<Expr<SomeType>>>;
template<>
class Constant<SomeDerived>

View File

@ -155,7 +155,7 @@ bool StructureConstructor::operator==(const StructureConstructor &that) const {
DynamicType StructureConstructor::GetType() const { return result_.GetType(); }
const Expr<SomeType> *StructureConstructor::Find(
const Symbol *component) const {
const Symbol &component) const {
if (auto iter{values_.find(component)}; iter != values_.end()) {
return &iter->second.value();
} else {
@ -165,7 +165,7 @@ const Expr<SomeType> *StructureConstructor::Find(
StructureConstructor &StructureConstructor::Add(
const Symbol &symbol, Expr<SomeType> &&expr) {
values_.emplace(&symbol, std::move(expr));
values_.emplace(symbol, std::move(expr));
return *this;
}

View File

@ -756,7 +756,7 @@ public:
return values_.end();
}
const Expr<SomeType> *Find(const Symbol *) const; // can return null
const Expr<SomeType> *Find(const Symbol &) const; // can return null
StructureConstructor &Add(const semantics::Symbol &, Expr<SomeType> &&);
int Rank() const { return 0; }

View File

@ -168,7 +168,7 @@ CoarrayRef FoldOperation(FoldingContext &context, CoarrayRef &&coarrayRef) {
DataRef FoldOperation(FoldingContext &context, DataRef &&dataRef) {
return std::visit(
common::visitors{
[&](const Symbol *symbol) { return DataRef{*symbol}; },
[&](SymbolRef symbol) { return DataRef{*symbol}; },
[&](auto &&x) {
return DataRef{FoldOperation(context, std::move(x))};
},
@ -1396,7 +1396,7 @@ std::optional<Constant<T>> ApplyComponent(FoldingContext &context,
Constant<SomeDerived> &&structures, const Symbol &component,
const std::vector<Constant<SubscriptInteger>> *subscripts = nullptr) {
if (auto scalar{structures.GetScalarValue()}) {
if (auto *expr{scalar->Find(&component)}) {
if (auto *expr{scalar->Find(component)}) {
if (const Constant<T> *value{UnwrapConstantValue<T>(*expr)}) {
if (subscripts == nullptr) {
return std::move(*value);
@ -1414,7 +1414,7 @@ std::optional<Constant<T>> ApplyComponent(FoldingContext &context,
ConstantSubscripts at{structures.lbounds()};
do {
StructureConstructor scalar{structures.At(at)};
if (auto *expr{scalar.Find(&component)}) {
if (auto *expr{scalar.Find(component)}) {
if (const Constant<T> *value{UnwrapConstantValue<T>(*expr)}) {
if (array.get() == nullptr) {
// This technique ensures that character length or derived type
@ -1478,9 +1478,9 @@ std::optional<Constant<T>> GetConstantComponent(FoldingContext &context,
const std::vector<Constant<SubscriptInteger>> *subscripts) {
if (std::optional<Constant<SomeDerived>> structures{std::visit(
common::visitors{
[&](const Symbol *symbol) {
[&](const Symbol &symbol) {
return GetFoldedNamedConstantValue<SomeDerived>(
context, *symbol);
context, symbol);
},
[&](ArrayRef &aRef) {
return FoldArrayRef<SomeDerived>(context, aRef);
@ -1518,12 +1518,10 @@ Expr<T> FoldOperation(FoldingContext &context, Designator<T> &&designator) {
}
return std::visit(
common::visitors{
[&](const Symbol *symbol) {
if (symbol != nullptr) {
if (auto constant{
GetFoldedNamedConstantValue<T>(context, *symbol)}) {
return Expr<T>{std::move(*constant)};
}
[&](SymbolRef &&symbol) {
if (auto constant{
GetFoldedNamedConstantValue<T>(context, *symbol)}) {
return Expr<T>{std::move(*constant)};
}
return Expr<T>{std::move(designator)};
},
@ -1663,9 +1661,9 @@ Expr<SomeDerived> FoldOperation(
FoldingContext &context, StructureConstructor &&structure) {
StructureConstructor result{structure.derivedTypeSpec()};
for (auto &&[symbol, value] : std::move(structure)) {
result.Add(*symbol, Fold(context, std::move(value.value())));
result.Add(symbol, Fold(context, std::move(value.value())));
}
return Expr<SomeDerived>{Constant<SomeDerived>{result}};
return Expr<SomeDerived>{Constant<SomeDerived>{std::move(result)}};
}
// Substitute a bare type parameter reference with its value if it has one now

View File

@ -480,6 +480,11 @@ template<typename A> std::ostream &EmitVar(std::ostream &o, const A &x) {
return x.AsFortran(o);
}
template<typename A>
std::ostream &EmitVar(std::ostream &o, common::Reference<A> x) {
return EmitVar(o, *x);
}
template<typename A>
std::ostream &EmitVar(std::ostream &o, const A *p, const char *kw = nullptr) {
if (p != nullptr) {
@ -534,18 +539,18 @@ std::ostream &TypeParamInquiry<KIND>::AsFortran(std::ostream &o) const {
if (base_.has_value()) {
return base_->AsFortran(o) << '%';
}
return EmitVar(o, *parameter_);
return EmitVar(o, parameter_);
}
std::ostream &Component::AsFortran(std::ostream &o) const {
base_.value().AsFortran(o);
return EmitVar(o << '%', *symbol_);
return EmitVar(o << '%', symbol_);
}
std::ostream &NamedEntity::AsFortran(std::ostream &o) const {
std::visit(
common::visitors{
[&](const Symbol *s) { EmitVar(o, *s); },
[&](SymbolRef s) { EmitVar(o, s); },
[&](const Component &c) { c.AsFortran(o); },
},
u_);
@ -575,13 +580,13 @@ std::ostream &ArrayRef::AsFortran(std::ostream &o) const {
std::ostream &CoarrayRef::AsFortran(std::ostream &o) const {
bool first{true};
for (const Symbol *part : base_) {
for (const Symbol &part : base_) {
if (first) {
first = false;
} else {
o << '%';
}
EmitVar(o, *part);
EmitVar(o, part);
}
char separator{'('};
for (const auto &sscript : subscript_) {
@ -629,7 +634,7 @@ template<typename T>
std::ostream &Designator<T>::AsFortran(std::ostream &o) const {
std::visit(
common::visitors{
[&](const Symbol *sym) { EmitVar(o, *sym); },
[&](SymbolRef symbol) { EmitVar(o, symbol); },
[&](const auto &x) { x.AsFortran(o); },
},
u);

View File

@ -27,7 +27,7 @@ namespace Fortran::evaluate {
// IsVariable()
auto IsVariableHelper::operator()(const ProcedureDesignator &x) const
-> Result {
const semantics::Symbol *symbol{x.GetSymbol()};
const Symbol *symbol{x.GetSymbol()};
return symbol && symbol->attrs().test(semantics::Attr::POINTER);
}
@ -607,7 +607,7 @@ std::optional<Expr<SomeType>> ConvertToType(
}
std::optional<Expr<SomeType>> ConvertToType(
const semantics::Symbol &symbol, Expr<SomeType> &&x) {
const Symbol &symbol, Expr<SomeType> &&x) {
if (int xRank{x.Rank()}; xRank > 0) {
if (symbol.Rank() != xRank) {
return std::nullopt;
@ -620,7 +620,7 @@ std::optional<Expr<SomeType>> ConvertToType(
}
std::optional<Expr<SomeType>> ConvertToType(
const semantics::Symbol &to, std::optional<Expr<SomeType>> &&x) {
const Symbol &to, std::optional<Expr<SomeType>> &&x) {
if (x.has_value()) {
return ConvertToType(to, std::move(*x));
} else {
@ -628,8 +628,8 @@ std::optional<Expr<SomeType>> ConvertToType(
}
}
bool IsAssumedRank(const semantics::Symbol &symbol0) {
const semantics::Symbol &symbol{ResolveAssociations(symbol0)};
bool IsAssumedRank(const Symbol &symbol0) {
const Symbol &symbol{ResolveAssociations(symbol0)};
if (const auto *details{symbol.detailsIf<semantics::ObjectEntityDetails>()}) {
return details->IsAssumedRank();
} else {
@ -641,7 +641,7 @@ bool IsAssumedRank(const ActualArgument &arg) {
if (const auto *expr{arg.UnwrapExpr()}) {
return IsAssumedRank(*expr);
} else {
const semantics::Symbol *assumedTypeDummy{arg.GetAssumedTypeDummy()};
const Symbol *assumedTypeDummy{arg.GetAssumedTypeDummy()};
CHECK(assumedTypeDummy != nullptr);
return IsAssumedRank(*assumedTypeDummy);
}
@ -677,8 +677,7 @@ bool IsNullPointer(const Expr<SomeType> &expr) {
}
// GetLastTarget()
auto GetLastTargetHelper::operator()(const semantics::Symbol &x) const
-> Result {
auto GetLastTargetHelper::operator()(const Symbol &x) const -> Result {
if (x.attrs().HasAny({semantics::Attr::POINTER, semantics::Attr::TARGET})) {
return &x;
} else {
@ -686,7 +685,7 @@ auto GetLastTargetHelper::operator()(const semantics::Symbol &x) const
}
}
auto GetLastTargetHelper::operator()(const Component &x) const -> Result {
const semantics::Symbol &symbol{x.GetLastSymbol()};
const Symbol &symbol{x.GetLastSymbol()};
if (symbol.attrs().HasAny(
{semantics::Attr::POINTER, semantics::Attr::TARGET})) {
return &symbol;
@ -697,7 +696,7 @@ auto GetLastTargetHelper::operator()(const Component &x) const -> Result {
}
}
const semantics::Symbol &ResolveAssociations(const semantics::Symbol &symbol) {
const Symbol &ResolveAssociations(const Symbol &symbol) {
if (const auto *details{symbol.detailsIf<semantics::AssocEntityDetails>()}) {
if (const Symbol * nested{UnwrapWholeSymbolDataRef(details->expr())}) {
return ResolveAssociations(*nested);
@ -707,20 +706,20 @@ const semantics::Symbol &ResolveAssociations(const semantics::Symbol &symbol) {
}
struct CollectSymbolsHelper
: public SetTraverse<CollectSymbolsHelper, SetOfSymbols> {
using Base = SetTraverse<CollectSymbolsHelper, SetOfSymbols>;
: public SetTraverse<CollectSymbolsHelper, semantics::SymbolSet> {
using Base = SetTraverse<CollectSymbolsHelper, semantics::SymbolSet>;
CollectSymbolsHelper() : Base{*this} {}
using Base::operator();
SetOfSymbols operator()(const semantics::Symbol &symbol) const {
return {&symbol};
semantics::SymbolSet operator()(const Symbol &symbol) const {
return {symbol};
}
};
template<typename A> SetOfSymbols CollectSymbols(const A &x) {
template<typename A> semantics::SymbolSet CollectSymbols(const A &x) {
return CollectSymbolsHelper{}(x);
}
template SetOfSymbols CollectSymbols(const Expr<SomeType> &);
template SetOfSymbols CollectSymbols(const Expr<SomeInteger> &);
template SetOfSymbols CollectSymbols(const Expr<SubscriptInteger> &);
template semantics::SymbolSet CollectSymbols(const Expr<SomeType> &);
template semantics::SymbolSet CollectSymbols(const Expr<SomeInteger> &);
template semantics::SymbolSet CollectSymbols(const Expr<SubscriptInteger> &);
// HasVectorSubscript()
struct HasVectorSubscriptHelper : public AnyTraverse<HasVectorSubscriptHelper> {

View File

@ -102,13 +102,12 @@ template<typename A> bool IsVariable(const A &x) {
}
// Predicate: true when an expression is assumed-rank
bool IsAssumedRank(const semantics::Symbol &);
bool IsAssumedRank(const Symbol &);
bool IsAssumedRank(const ActualArgument &);
template<typename A> bool IsAssumedRank(const A &) { return false; }
template<typename A> bool IsAssumedRank(const Designator<A> &designator) {
if (const auto *symbol{
std::get_if<const semantics::Symbol *>(&designator.u)}) {
return IsAssumedRank(*symbol);
if (const auto *symbol{std::get_if<SymbolRef>(&designator.u)}) {
return IsAssumedRank(symbol->get());
} else {
return false;
}
@ -244,8 +243,8 @@ template<typename A> std::optional<NamedEntity> ExtractNamedEntity(const A &x) {
if (auto dataRef{ExtractDataRef(x)}) {
return std::visit(
common::visitors{
[](const Symbol *symbol) -> std::optional<NamedEntity> {
return NamedEntity{*symbol};
[](SymbolRef &&symbol) -> std::optional<NamedEntity> {
return NamedEntity{symbol};
},
[](Component &&component) -> std::optional<NamedEntity> {
return NamedEntity{std::move(component)};
@ -296,8 +295,8 @@ template<typename A> std::optional<CoarrayRef> ExtractCoarrayRef(const A &x) {
// extract and return that symbol, else null.
template<typename A> const Symbol *UnwrapWholeSymbolDataRef(const A &x) {
if (auto dataRef{ExtractDataRef(x)}) {
if (const Symbol **p{std::get_if<const Symbol *>(&dataRef->u)}) {
return *p;
if (const SymbolRef * p{std::get_if<SymbolRef>(&dataRef->u)}) {
return &p->get();
}
}
return nullptr;
@ -388,10 +387,9 @@ std::optional<Expr<SomeType>> ConvertToType(
const DynamicType &, Expr<SomeType> &&);
std::optional<Expr<SomeType>> ConvertToType(
const DynamicType &, std::optional<Expr<SomeType>> &&);
std::optional<Expr<SomeType>> ConvertToType(const Symbol &, Expr<SomeType> &&);
std::optional<Expr<SomeType>> ConvertToType(
const semantics::Symbol &, Expr<SomeType> &&);
std::optional<Expr<SomeType>> ConvertToType(
const semantics::Symbol &, std::optional<Expr<SomeType>> &&);
const Symbol &, std::optional<Expr<SomeType>> &&);
// Conversions to the type of another expression
template<TypeCategory TC, int TK, typename FROM>
@ -692,13 +690,13 @@ struct TypeKindVisitor {
// GetLastSymbol() returns the rightmost symbol in an object or procedure
// designator (which has perhaps been wrapped in an Expr<>), or a null pointer
// when none is found.
struct GetLastSymbolHelper : public AnyTraverse<GetLastSymbolHelper,
std::optional<const semantics::Symbol *>> {
using Result = std::optional<const semantics::Symbol *>;
struct GetLastSymbolHelper
: public AnyTraverse<GetLastSymbolHelper, std::optional<const Symbol *>> {
using Result = std::optional<const Symbol *>;
using Base = AnyTraverse<GetLastSymbolHelper, Result>;
GetLastSymbolHelper() : Base{*this} {}
using Base::operator();
Result operator()(const semantics::Symbol &x) const { return &x; }
Result operator()(const Symbol &x) const { return &x; }
Result operator()(const Component &x) const { return &x.GetLastSymbol(); }
Result operator()(const NamedEntity &x) const { return &x.GetLastSymbol(); }
Result operator()(const ProcedureDesignator &x) const {
@ -719,7 +717,7 @@ struct GetLastSymbolHelper : public AnyTraverse<GetLastSymbolHelper,
}
};
template<typename A> const semantics::Symbol *GetLastSymbol(const A &x) {
template<typename A> const Symbol *GetLastSymbol(const A &x) {
if (auto known{GetLastSymbolHelper{}(x)}) {
return *known;
} else {
@ -730,7 +728,7 @@ template<typename A> const semantics::Symbol *GetLastSymbol(const A &x) {
// Convenience: If GetLastSymbol() succeeds on the argument, return its
// set of attributes, otherwise the empty set.
template<typename A> semantics::Attrs GetAttrs(const A &x) {
if (const semantics::Symbol * symbol{GetLastSymbol(x)}) {
if (const Symbol * symbol{GetLastSymbol(x)}) {
return symbol->attrs();
} else {
return {};
@ -770,17 +768,17 @@ bool IsNullPointer(const Expr<SomeType> &);
// GetLastTarget() returns the rightmost symbol in an object
// designator (which has perhaps been wrapped in an Expr<>) that has the
// POINTER or TARGET attribute, or a null pointer when none is found.
struct GetLastTargetHelper : public AnyTraverse<GetLastTargetHelper,
std::optional<const semantics::Symbol *>> {
using Result = std::optional<const semantics::Symbol *>;
struct GetLastTargetHelper
: public AnyTraverse<GetLastTargetHelper, std::optional<const Symbol *>> {
using Result = std::optional<const Symbol *>;
using Base = AnyTraverse<GetLastTargetHelper, Result>;
GetLastTargetHelper() : Base{*this} {}
using Base::operator();
Result operator()(const semantics::Symbol &) const;
Result operator()(const Symbol &) const;
Result operator()(const Component &) const;
};
template<typename A> const semantics::Symbol *GetLastTarget(const A &x) {
template<typename A> const Symbol *GetLastTarget(const A &x) {
if (auto known{GetLastTargetHelper{}(x)}) {
return *known;
} else {
@ -789,14 +787,14 @@ template<typename A> const semantics::Symbol *GetLastTarget(const A &x) {
}
// Resolves any whole ASSOCIATE(B=>A) associations
const semantics::Symbol &ResolveAssociations(const semantics::Symbol &);
const Symbol &ResolveAssociations(const Symbol &);
// Collects all of the Symbols in an expression
using SetOfSymbols = std::set<const semantics::Symbol *>;
template<typename A> SetOfSymbols CollectSymbols(const A &);
extern template SetOfSymbols CollectSymbols(const Expr<SomeType> &);
extern template SetOfSymbols CollectSymbols(const Expr<SomeInteger> &);
extern template SetOfSymbols CollectSymbols(const Expr<SubscriptInteger> &);
template<typename A> semantics::SymbolSet CollectSymbols(const A &);
extern template semantics::SymbolSet CollectSymbols(const Expr<SomeType> &);
extern template semantics::SymbolSet CollectSymbols(const Expr<SomeInteger> &);
extern template semantics::SymbolSet CollectSymbols(
const Expr<SubscriptInteger> &);
// Predicate: does a variable contain a vector-valued subscript (not a triplet)?
bool HasVectorSubscript(const Expr<SomeType> &);

View File

@ -58,6 +58,9 @@ public:
Result operator()(const common::Indirection<A, C> &x) const {
return visitor_(x.value());
}
template<typename A> Result operator()(SymbolRef x) const {
return visitor_(*x);
}
template<typename A> Result operator()(const std::unique_ptr<A> &x) const {
return visitor_(x.get());
}
@ -93,9 +96,7 @@ public:
template<typename T> Result operator()(const Constant<T> &) const {
return visitor_.Default();
}
Result operator()(const semantics::Symbol &) const {
return visitor_.Default();
}
Result operator()(const Symbol &) const { return visitor_.Default(); }
Result operator()(const StaticDataObject &) const {
return visitor_.Default();
}
@ -151,7 +152,7 @@ public:
Result operator()(const ProcedureDesignator &x) const {
if (const Component * component{x.GetComponent()}) {
return visitor_(*component);
} else if (const semantics::Symbol * symbol{x.GetSymbol()}) {
} else if (const Symbol * symbol{x.GetSymbol()}) {
return visitor_(*symbol);
} else {
return visitor_(DEREF(x.GetSpecificIntrinsic()));

View File

@ -47,8 +47,8 @@ static bool IsDescriptor(const ObjectEntityDetails &details) {
if (const Scope * scope{typeSpec->scope()}) {
if (const Symbol * symbol{scope->symbol()}) {
if (const auto *details{symbol->detailsIf<DerivedTypeDetails>()}) {
for (const Symbol *param : details->paramDecls()) {
if (const auto *details{param->detailsIf<TypeParamDetails>()}) {
for (const Symbol &param : details->paramDecls()) {
if (const auto *details{param.detailsIf<TypeParamDetails>()}) {
if (details->attr() == common::TypeParamAttr::Len) {
return true;
}
@ -146,7 +146,7 @@ static const semantics::Symbol *FindComponent(
if (const auto *scope{derived.scope()}) {
auto iter{scope->find(name)};
if (iter != scope->end()) {
return iter->second;
return &*iter->second;
} else if (const auto *parent{GetParentTypeSpec(derived)}) {
return FindComponent(*parent, name);
}
@ -201,8 +201,7 @@ static bool AreSameDerivedType(const semantics::DerivedTypeSpec &x,
const auto yLookup{ySymbol.scope()->find(*yComponentName)};
if (xLookup == xSymbol.scope()->end() ||
yLookup == ySymbol.scope()->end() ||
!AreSameComponent(
DEREF(xLookup->second), DEREF(yLookup->second), inProgress)) {
!AreSameComponent(*xLookup->second, *yLookup->second, inProgress)) {
return false;
}
}

View File

@ -82,14 +82,11 @@ bool Triplet::IsStrideOne() const {
}
}
CoarrayRef::CoarrayRef(std::vector<const Symbol *> &&base,
std::vector<Subscript> &&ss, std::vector<Expr<SubscriptInteger>> &&css)
CoarrayRef::CoarrayRef(SymbolVector &&base, std::vector<Subscript> &&ss,
std::vector<Expr<SubscriptInteger>> &&css)
: base_{std::move(base)}, subscript_(std::move(ss)),
cosubscript_(std::move(css)) {
CHECK(!base_.empty());
for (const Symbol *symbol : base_) {
CHECK(symbol != nullptr);
}
CHECK(!cosubscript_.empty());
}
@ -122,9 +119,9 @@ CoarrayRef &CoarrayRef::set_team(Expr<SomeInteger> &&v, bool isTeamNumber) {
return *this;
}
const Symbol &CoarrayRef::GetFirstSymbol() const { return *base_.front(); }
const Symbol &CoarrayRef::GetFirstSymbol() const { return base_.front(); }
const Symbol &CoarrayRef::GetLastSymbol() const { return *base_.back(); }
const Symbol &CoarrayRef::GetLastSymbol() const { return base_.back(); }
void Substring::SetBounds(std::optional<Expr<SubscriptInteger>> &lower,
std::optional<Expr<SubscriptInteger>> &upper) {
@ -277,7 +274,7 @@ static std::optional<Expr<SubscriptInteger>> SymbolLEN(const Symbol &sym) {
std::optional<Expr<SubscriptInteger>> BaseObject::LEN() const {
return std::visit(
common::visitors{
[](const Symbol *symbol) { return SymbolLEN(*symbol); },
[](const Symbol &symbol) { return SymbolLEN(symbol); },
[](const StaticDataObject::Pointer &object)
-> std::optional<Expr<SubscriptInteger>> {
return AsExpr(Constant<SubscriptInteger>{object->data().size()});
@ -305,7 +302,7 @@ std::optional<Expr<SubscriptInteger>> CoarrayRef::LEN() const {
std::optional<Expr<SubscriptInteger>> DataRef::LEN() const {
return std::visit(
common::visitors{
[](const Symbol *s) { return SymbolLEN(*s); },
[](SymbolRef symbol) { return SymbolLEN(symbol); },
[](const auto &x) { return x.LEN(); },
},
u);
@ -326,7 +323,7 @@ std::optional<Expr<SubscriptInteger>> Designator<T>::LEN() const {
if constexpr (T::category == TypeCategory::Character) {
return std::visit(
common::visitors{
[](const Symbol *s) { return SymbolLEN(*s); },
[](SymbolRef symbol) { return SymbolLEN(symbol); },
[](const auto &x) { return x.LEN(); },
},
u);
@ -340,7 +337,7 @@ std::optional<Expr<SubscriptInteger>> ProcedureDesignator::LEN() const {
using T = std::optional<Expr<SubscriptInteger>>;
return std::visit(
common::visitors{
[](const Symbol *s) -> T { return SymbolLEN(*s); },
[](SymbolRef symbol) -> T { return SymbolLEN(symbol); },
[](const common::CopyableIndirection<Component> &c) -> T {
return c.value().LEN();
},
@ -361,7 +358,7 @@ std::optional<Expr<SubscriptInteger>> ProcedureDesignator::LEN() const {
int BaseObject::Rank() const {
return std::visit(
common::visitors{
[](const Symbol *symbol) { return symbol->Rank(); },
[](SymbolRef symbol) { return symbol->Rank(); },
[](const StaticDataObject::Pointer &) { return 0; },
},
u);
@ -377,7 +374,7 @@ int Component::Rank() const {
int NamedEntity::Rank() const {
return std::visit(
common::visitors{
[](const Symbol *s) { return s->Rank(); },
[](const SymbolRef s) { return s->Rank(); },
[](const Component &c) { return c.Rank(); },
},
u_);
@ -422,16 +419,9 @@ int CoarrayRef::Rank() const {
int DataRef::Rank() const {
return std::visit(
// g++ 7.2 emits bogus warnings here and below when common::visitors{}
// is used with a "const auto &" catch-all member, so a constexpr type
// test has to be used instead.
[](const auto &x) {
if constexpr (std::is_same_v<std::decay_t<decltype(x)>,
const Symbol *>) {
return x->Rank();
} else {
return x.Rank();
}
common::visitors{
[](SymbolRef symbol) { return symbol->Rank(); },
[](const auto &x) { return x.Rank(); },
},
u);
}
@ -446,10 +436,11 @@ int Substring::Rank() const {
}
int ComplexPart::Rank() const { return complex_.Rank(); }
template<typename T> int Designator<T>::Rank() const {
return std::visit(
common::visitors{
[](const Symbol *sym) { return sym->Rank(); },
[](SymbolRef symbol) { return symbol->Rank(); },
[](const auto &x) { return x.Rank(); },
},
u);
@ -463,7 +454,7 @@ const Symbol &Component::GetFirstSymbol() const {
const Symbol &NamedEntity::GetFirstSymbol() const {
return std::visit(
common::visitors{
[](const Symbol *s) -> const Symbol & { return *s; },
[](SymbolRef s) -> const Symbol & { return s; },
[](const Component &c) -> const Symbol & {
return c.GetFirstSymbol();
},
@ -474,7 +465,7 @@ const Symbol &NamedEntity::GetFirstSymbol() const {
const Symbol &NamedEntity::GetLastSymbol() const {
return std::visit(
common::visitors{
[](const Symbol *s) -> const Symbol & { return *s; },
[](SymbolRef s) -> const Symbol & { return s; },
[](const Component &c) -> const Symbol & {
return c.GetLastSymbol();
},
@ -485,7 +476,7 @@ const Symbol &NamedEntity::GetLastSymbol() const {
const Component *NamedEntity::UnwrapComponent() const {
return std::visit(
common::visitors{
[](const Symbol *) -> const Component * { return nullptr; },
[](SymbolRef) -> const Component * { return nullptr; },
[](const Component &c) { return &c; },
},
u_);
@ -494,7 +485,7 @@ const Component *NamedEntity::UnwrapComponent() const {
Component *NamedEntity::UnwrapComponent() {
return std::visit(
common::visitors{
[](const Symbol *) -> Component * { return nullptr; },
[](SymbolRef &) -> Component * { return nullptr; },
[](Component &c) { return &c; },
},
u_);
@ -509,7 +500,7 @@ const Symbol &ArrayRef::GetLastSymbol() const { return base_.GetLastSymbol(); }
const Symbol &DataRef::GetFirstSymbol() const {
return *std::visit(
common::visitors{
[](const Symbol *symbol) { return symbol; },
[](SymbolRef symbol) { return &*symbol; },
[](const auto &x) { return &x.GetFirstSymbol(); },
},
u);
@ -518,7 +509,7 @@ const Symbol &DataRef::GetFirstSymbol() const {
const Symbol &DataRef::GetLastSymbol() const {
return *std::visit(
common::visitors{
[](const Symbol *symbol) { return symbol; },
[](SymbolRef symbol) { return &*symbol; },
[](const auto &x) { return &x.GetLastSymbol(); },
},
u);
@ -549,14 +540,16 @@ const Symbol *Substring::GetLastSymbol() const {
template<typename T> BaseObject Designator<T>::GetBaseObject() const {
return std::visit(
common::visitors{
[](const Symbol *symbol) { return BaseObject{*symbol}; },
[](SymbolRef symbol) { return BaseObject{symbol}; },
[](const Substring &sstring) { return sstring.GetBaseObject(); },
[](const auto &x) {
#if !__clang__ && __GNUC__ == 7 && __GNUC_MINOR__ == 2
if constexpr (std::is_same_v<std::decay_t<decltype(x)>,
Substring>) {
return x.GetBaseObject();
} else {
} else
#endif
return BaseObject{x.GetFirstSymbol()};
}
},
},
u);
@ -565,14 +558,16 @@ template<typename T> BaseObject Designator<T>::GetBaseObject() const {
template<typename T> const Symbol *Designator<T>::GetLastSymbol() const {
return std::visit(
common::visitors{
[](const Symbol *symbol) { return symbol; },
[](SymbolRef symbol) { return &*symbol; },
[](const Substring &sstring) { return sstring.GetLastSymbol(); },
[](const auto &x) {
#if !__clang__ && __GNUC__ == 7 && __GNUC_MINOR__ == 2
if constexpr (std::is_same_v<std::decay_t<decltype(x)>,
Substring>) {
return x.GetLastSymbol();
} else {
} else
#endif
return &x.GetLastSymbol();
}
},
},
u);
@ -586,14 +581,15 @@ template<typename T> std::optional<DynamicType> Designator<T>::GetType() const {
}
}
static NamedEntity AsNamedEntity(const std::vector<const Symbol *> x) {
NamedEntity result{*x.front()}; // asserts if empty()
static NamedEntity AsNamedEntity(const SymbolVector &x) {
CHECK(!x.empty());
NamedEntity result{x.front()};
int j{0};
for (const Symbol *symbol : x) {
for (const Symbol &symbol : x) {
if (j++ != 0) {
DataRef base{result.IsSymbol() ? DataRef{result.GetLastSymbol()}
: DataRef{result.GetComponent()}};
result = NamedEntity{Component{std::move(base), *symbol}};
result = NamedEntity{Component{std::move(base), symbol}};
}
}
return result;
@ -607,15 +603,19 @@ bool BaseObject::operator==(const BaseObject &that) const {
return u == that.u;
}
bool Component::operator==(const Component &that) const {
return base_ == that.base_ && symbol_ == that.symbol_;
return base_ == that.base_ && &*symbol_ == &*that.symbol_;
}
bool NamedEntity::operator==(const NamedEntity &that) const {
return u_ == that.u_;
if (&GetLastSymbol() != &that.GetLastSymbol()) {
return false;
} else {
return UnwrapComponent() == that.UnwrapComponent();
}
}
template<int KIND>
bool TypeParamInquiry<KIND>::operator==(
const TypeParamInquiry<KIND> &that) const {
return parameter_ == that.parameter_ && base_ == that.base_;
return &*parameter_ == &*that.parameter_ && base_ == that.base_;
}
bool Triplet::operator==(const Triplet &that) const {
return lower_ == that.lower_ && upper_ == that.upper_ &&

View File

@ -27,6 +27,7 @@
#include "static-data.h"
#include "type.h"
#include "../common/idioms.h"
#include "../common/reference.h"
#include "../common/template.h"
#include "../parser/char-block.h"
#include <optional>
@ -41,6 +42,8 @@ class Symbol;
namespace Fortran::evaluate {
using semantics::Symbol;
using SymbolRef = common::Reference<const Symbol>;
using SymbolVector = std::vector<SymbolRef>;
// Forward declarations
struct DataRef;
@ -50,20 +53,20 @@ template<typename A> struct Variable;
// static data (e.g., CHARACTER literal), or compiler-created temporary.
struct BaseObject {
CLASS_BOILERPLATE(BaseObject)
explicit BaseObject(const Symbol &symbol) : u{&symbol} {}
explicit BaseObject(const Symbol &symbol) : u{symbol} {}
explicit BaseObject(StaticDataObject::Pointer &&p) : u{std::move(p)} {}
int Rank() const;
std::optional<Expr<SubscriptInteger>> LEN() const;
bool operator==(const BaseObject &) const;
std::ostream &AsFortran(std::ostream &) const;
const Symbol *symbol() const {
if (const auto *result{std::get_if<const Symbol *>(&u)}) {
return *result;
if (const auto *result{std::get_if<SymbolRef>(&u)}) {
return &result->get();
} else {
return nullptr;
}
}
std::variant<const Symbol *, StaticDataObject::Pointer> u;
std::variant<SymbolRef, StaticDataObject::Pointer> u;
};
// R913 structure-component & C920: Defined to be a multi-part
@ -76,23 +79,23 @@ struct BaseObject {
class Component {
public:
CLASS_BOILERPLATE(Component)
Component(const DataRef &b, const Symbol &c) : base_{b}, symbol_{&c} {}
Component(DataRef &&b, const Symbol &c) : base_{std::move(b)}, symbol_{&c} {}
Component(const DataRef &b, const Symbol &c) : base_{b}, symbol_{c} {}
Component(DataRef &&b, const Symbol &c) : base_{std::move(b)}, symbol_{c} {}
Component(common::CopyableIndirection<DataRef> &&b, const Symbol &c)
: base_{std::move(b)}, symbol_{&c} {}
: base_{std::move(b)}, symbol_{c} {}
const DataRef &base() const { return base_.value(); }
DataRef &base() { return base_.value(); }
int Rank() const;
const Symbol &GetFirstSymbol() const;
const Symbol &GetLastSymbol() const { return *symbol_; }
const Symbol &GetLastSymbol() const { return symbol_; }
std::optional<Expr<SubscriptInteger>> LEN() const;
bool operator==(const Component &) const;
std::ostream &AsFortran(std::ostream &) const;
private:
common::CopyableIndirection<DataRef> base_;
const Symbol *symbol_;
SymbolRef symbol_;
};
// A NamedEntity is either a whole Symbol or a component in an instance
@ -102,10 +105,10 @@ private:
class NamedEntity {
public:
CLASS_BOILERPLATE(NamedEntity)
explicit NamedEntity(const Symbol &symbol) : u_{&symbol} {}
explicit NamedEntity(const Symbol &symbol) : u_{symbol} {}
explicit NamedEntity(Component &&c) : u_{std::move(c)} {}
bool IsSymbol() const { return std::holds_alternative<const Symbol *>(u_); }
bool IsSymbol() const { return std::holds_alternative<SymbolRef>(u_); }
const Symbol &GetFirstSymbol() const;
const Symbol &GetLastSymbol() const;
const Component &GetComponent() const { return std::get<Component>(u_); }
@ -119,7 +122,7 @@ public:
std::ostream &AsFortran(std::ostream &) const;
private:
std::variant<const Symbol *, Component> u_;
std::variant<SymbolRef, Component> u_;
};
// R916 type-param-inquiry
@ -134,13 +137,13 @@ public:
using Result = Type<TypeCategory::Integer, KIND>;
CLASS_BOILERPLATE(TypeParamInquiry)
TypeParamInquiry(NamedEntity &&x, const Symbol &param)
: base_{std::move(x)}, parameter_{&param} {}
: base_{std::move(x)}, parameter_{param} {}
TypeParamInquiry(std::optional<NamedEntity> &&x, const Symbol &param)
: base_{std::move(x)}, parameter_{&param} {}
: base_{std::move(x)}, parameter_{param} {}
const std::optional<NamedEntity> &base() const { return base_; }
std::optional<NamedEntity> &base() { return base_; }
const Symbol &parameter() const { return *parameter_; }
const Symbol &parameter() const { return parameter_; }
static constexpr int Rank() { return 0; } // always scalar
bool operator==(const TypeParamInquiry &) const;
@ -148,7 +151,7 @@ public:
private:
std::optional<NamedEntity> base_;
const Symbol *parameter_;
SymbolRef parameter_;
};
EXPAND_FOR_EACH_INTEGER_KIND(
@ -243,11 +246,11 @@ private:
class CoarrayRef {
public:
CLASS_BOILERPLATE(CoarrayRef)
CoarrayRef(std::vector<const Symbol *> &&, std::vector<Subscript> &&,
CoarrayRef(SymbolVector &&, std::vector<Subscript> &&,
std::vector<Expr<SubscriptInteger>> &&);
const std::vector<const Symbol *> &base() const { return base_; }
std::vector<const Symbol *> &base() { return base_; }
const SymbolVector &base() const { return base_; }
SymbolVector &base() { return base_; }
const std::vector<Subscript> &subscript() const { return subscript_; }
std::vector<Subscript> &subscript() { return subscript_; }
const std::vector<Expr<SubscriptInteger>> &cosubscript() const {
@ -272,7 +275,7 @@ public:
std::ostream &AsFortran(std::ostream &) const;
private:
std::vector<const Symbol *> base_;
SymbolVector base_;
std::vector<Subscript> subscript_;
std::vector<Expr<SubscriptInteger>> cosubscript_;
std::optional<common::CopyableIndirection<Expr<SomeInteger>>> stat_, team_;
@ -286,7 +289,7 @@ private:
// R901 designator for that.
struct DataRef {
EVALUATE_UNION_CLASS_BOILERPLATE(DataRef)
explicit DataRef(const Symbol &n) : u{&n} {}
explicit DataRef(const Symbol &n) : u{n} {}
int Rank() const;
const Symbol &GetFirstSymbol() const;
@ -294,7 +297,7 @@ struct DataRef {
std::optional<Expr<SubscriptInteger>> LEN() const;
std::ostream &AsFortran(std::ostream &) const;
std::variant<const Symbol *, Component, ArrayRef, CoarrayRef> u;
std::variant<SymbolRef, Component, ArrayRef, CoarrayRef> u;
};
// R908 substring, R909 parent-string, R910 substring-range.

View File

@ -73,22 +73,14 @@ const char *MessageFormattedText::Convert(std::string &&s) {
return conversions_.front().c_str();
}
const char *MessageFormattedText::Convert(const CharBlock &x) {
return Convert(x.ToString());
}
const char *MessageFormattedText::Convert(CharBlock &x) {
return Convert(x.ToString());
}
const char *MessageFormattedText::Convert(CharBlock &&x) {
const char *MessageFormattedText::Convert(CharBlock x) {
return Convert(x.ToString());
}
std::string MessageExpectedText::ToString() const {
return std::visit(
common::visitors{
[](const CharBlock &cb) {
[](CharBlock cb) {
return MessageFormattedText("expected '%s'"_err_en_US, cb)
.MoveString();
},
@ -145,14 +137,14 @@ bool Message::SortBefore(const Message &that) const {
// before others for sorting.
return std::visit(
common::visitors{
[](const CharBlock &cb1, const CharBlock &cb2) {
[](CharBlock cb1, CharBlock cb2) {
return cb1.begin() < cb2.begin();
},
[](const CharBlock &, const ProvenanceRange &) { return false; },
[](CharBlock, const ProvenanceRange &) { return false; },
[](const ProvenanceRange &pr1, const ProvenanceRange &pr2) {
return pr1.start() < pr2.start();
},
[](const ProvenanceRange &, const CharBlock &) { return true; },
[](const ProvenanceRange &, CharBlock) { return true; },
},
location_, that.location_);
}
@ -195,7 +187,7 @@ std::optional<ProvenanceRange> Message::GetProvenanceRange(
const CookedSource &cooked) const {
return std::visit(
common::visitors{
[&](const CharBlock &cb) { return cooked.GetProvenanceRange(cb); },
[&](CharBlock cb) { return cooked.GetProvenanceRange(cb); },
[](const ProvenanceRange &pr) { return std::make_optional(pr); },
},
location_);
@ -263,7 +255,7 @@ Message &Message::Attach(std::unique_ptr<Message> &&m) {
bool Message::AtSameLocation(const Message &that) const {
return std::visit(
common::visitors{
[](const CharBlock &cb1, const CharBlock &cb2) {
[](CharBlock cb1, CharBlock cb2) {
return cb1.begin() == cb2.begin();
},
[](const ProvenanceRange &pr1, const ProvenanceRange &pr2) {

View File

@ -47,7 +47,7 @@ public:
constexpr MessageFixedText &operator=(const MessageFixedText &) = default;
constexpr MessageFixedText &operator=(MessageFixedText &&) = default;
const CharBlock &text() const { return text_; }
CharBlock text() const { return text_; }
bool isFatal() const { return isFatal_; }
private:
@ -106,9 +106,7 @@ private:
const char *Convert(const std::string &);
const char *Convert(std::string &);
const char *Convert(std::string &&);
const char *Convert(const CharBlock &);
const char *Convert(CharBlock &);
const char *Convert(CharBlock &&);
const char *Convert(CharBlock);
bool isFatal_{false};
std::string string_;

View File

@ -123,7 +123,7 @@ static std::optional<AllocateCheckerInfo> CheckAllocateOptions(
context
.Say("Type-spec in ALLOCATE must not specify a type with a coarray"
" ultimate component"_err_en_US)
.Attach((*it)->name(),
.Attach(it->name(),
"Type '%s' has coarray ultimate component '%s' declared here"_en_US,
info.typeSpec->AsFortran(), it.BuildResultDesignatorName());
}
@ -210,7 +210,7 @@ static std::optional<AllocateCheckerInfo> CheckAllocateOptions(
context
.Say(parserSourceExpr->source,
"SOURCE or MOLD expression must not have a type with a coarray ultimate component"_err_en_US)
.Attach((*it)->name(),
.Attach(it->name(),
"Type '%s' has coarray ultimate component '%s' declared here"_en_US,
info.sourceExprType.value().AsFortran(),
it.BuildResultDesignatorName());
@ -226,7 +226,7 @@ static std::optional<AllocateCheckerInfo> CheckAllocateOptions(
"SOURCE expression type must not have potential subobject "
"component"
" of type EVENT_TYPE or LOCK_TYPE from ISO_FORTRAN_ENV"_err_en_US)
.Attach((*it)->name(),
.Attach(it->name(),
"Type '%s' has potential ultimate component '%s' declared here"_en_US,
info.sourceExprType.value().AsFortran(),
it.BuildResultDesignatorName());
@ -357,13 +357,13 @@ static std::optional<std::int64_t> GetTypeParameterInt64Value(
// type2 (except for kind type parameters)
static bool HaveCompatibleKindParameters(
const DerivedTypeSpec &derivedType1, const DerivedTypeSpec &derivedType2) {
for (const Symbol *symbol :
for (const Symbol &symbol :
OrderParameterDeclarations(derivedType1.typeSymbol())) {
if (symbol->get<TypeParamDetails>().attr() == common::TypeParamAttr::Kind) {
if (symbol.get<TypeParamDetails>().attr() == common::TypeParamAttr::Kind) {
// At this point, it should have been ensured that these contain integer
// constants, so die if this is not the case.
if (GetTypeParameterInt64Value(*symbol, derivedType1).value() !=
GetTypeParameterInt64Value(*symbol, derivedType2).value()) {
if (GetTypeParameterInt64Value(symbol, derivedType1).value() !=
GetTypeParameterInt64Value(symbol, derivedType2).value()) {
return false;
}
}

View File

@ -165,10 +165,9 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
dummyName);
}
if (const Symbol *
tbp{FindImmediateComponent(derived,
[](const Symbol &symbol) {
return symbol.has<ProcBindingDetails>();
})}) { // 15.5.2.4(2)
tbp{FindImmediateComponent(derived, [](const Symbol &symbol) {
return symbol.has<ProcBindingDetails>();
})}) { // 15.5.2.4(2)
if (auto *msg{messages.Say(
"Actual argument associated with TYPE(*) %s may not have type-bound procedure '%s'"_err_en_US,
dummyName, tbp->name())}) {
@ -176,10 +175,9 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
}
}
if (const Symbol *
finalizer{FindImmediateComponent(derived,
[](const Symbol &symbol) {
return symbol.has<FinalProcDetails>();
})}) { // 15.5.2.4(2)
finalizer{FindImmediateComponent(derived, [](const Symbol &symbol) {
return symbol.has<FinalProcDetails>();
})}) { // 15.5.2.4(2)
if (auto *msg{messages.Say(
"Actual argument associated with TYPE(*) %s may not have FINAL subroutine '%s'"_err_en_US,
dummyName, finalizer->name())}) {
@ -192,29 +190,27 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
if (actualIsCoindexed && dummy.intent != common::Intent::In &&
!dummyIsValue) {
if (auto iter{std::find_if(
ultimates.begin(), ultimates.end(), [](const Symbol *component) {
return IsAllocatable(DEREF(component));
ultimates.begin(), ultimates.end(), [](const Symbol &component) {
return IsAllocatable(component);
})}) { // 15.5.2.4(6)
if (auto *msg{messages.Say(
"Coindexed actual argument with ALLOCATABLE ultimate component '%s' must be associated with a %s with VALUE or INTENT(IN) attributes"_err_en_US,
iter.BuildResultDesignatorName(), dummyName)}) {
msg->Attach(
(*iter)->name(), "Declaration of ALLOCATABLE component"_en_US);
iter->name(), "Declaration of ALLOCATABLE component"_en_US);
}
}
}
if (actualIsVolatile != dummyIsVolatile) { // 15.5.2.4(22)
if (auto iter{std::find_if(
ultimates.begin(), ultimates.end(), [](const Symbol *component) {
const auto *object{
DEREF(component).detailsIf<ObjectEntityDetails>()};
ultimates.begin(), ultimates.end(), [](const Symbol &component) {
const auto *object{component.detailsIf<ObjectEntityDetails>()};
return object && object->IsCoarray();
})}) {
if (auto *msg{messages.Say(
"VOLATILE attribute must match for %s when actual argument has a coarray ultimate component '%s'"_err_en_US,
dummyName, iter.BuildResultDesignatorName())}) {
msg->Attach(
(*iter)->name(), "Declaration of coarray component"_en_US);
msg->Attach(iter->name(), "Declaration of coarray component"_en_US);
}
}
}

View File

@ -131,10 +131,9 @@ void CheckHelper::Check(Symbol &symbol) {
Check(object->shape());
Check(object->coshape());
if (object->isDummy() && symbol.attrs().test(Attr::INTENT_OUT)) {
if (FindUltimateComponent(symbol,
[](const Symbol &symbol) {
return IsCoarray(symbol) && IsAllocatable(symbol);
})) { // C846
if (FindUltimateComponent(symbol, [](const Symbol &symbol) {
return IsCoarray(symbol) && IsAllocatable(symbol);
})) { // C846
messages_.Say(
"An INTENT(OUT) dummy argument may not be, or contain, an ALLOCATABLE coarray"_err_en_US);
}

View File

@ -459,8 +459,8 @@ private:
static SymbolSet GatherSymbolsFromExpression(const parser::Expr &expression) {
SymbolSet result;
if (const auto *expr{GetExpr(expression)}) {
for (const Symbol *symbol : evaluate::CollectSymbols(*expr)) {
if (const Symbol * root{GetAssociationRoot(DEREF(symbol))}) {
for (const Symbol &symbol : evaluate::CollectSymbols(*expr)) {
if (const Symbol * root{GetAssociationRoot(symbol)}) {
result.insert(root);
}
}

View File

@ -163,7 +163,7 @@ MaybeExpr ExpressionAnalyzer::Designate(DataRef &&ref) {
if (auto *component{std::get_if<Component>(&ref.u)}) {
return Expr<SomeType>{ProcedureDesignator{std::move(*component)}};
} else {
CHECK(std::holds_alternative<const Symbol *>(ref.u));
CHECK(std::holds_alternative<SymbolRef>(ref.u));
return Expr<SomeType>{ProcedureDesignator{symbol}};
}
} else if (auto dyType{DynamicType::From(symbol)}) {
@ -218,8 +218,8 @@ MaybeExpr ExpressionAnalyzer::ApplySubscripts(
DataRef &&dataRef, std::vector<Subscript> &&subscripts) {
return std::visit(
common::visitors{
[&](const Symbol *symbol) {
return CompleteSubscripts(ArrayRef{*symbol, std::move(subscripts)});
[&](SymbolRef &&symbol) {
return CompleteSubscripts(ArrayRef{symbol, std::move(subscripts)});
},
[&](Component &&c) {
return CompleteSubscripts(
@ -823,7 +823,7 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::ArrayElement &ae) {
static NamedEntity IgnoreAnySubscripts(Designator<SomeDerived> &&designator) {
return std::visit(
common::visitors{
[](const Symbol *symbol) { return NamedEntity{*symbol}; },
[](SymbolRef &&symbol) { return NamedEntity{symbol}; },
[](Component &&component) {
return NamedEntity{std::move(component)};
},
@ -938,10 +938,10 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::StructureComponent &sc) {
MaybeExpr ExpressionAnalyzer::Analyze(const parser::CoindexedNamedObject &x) {
if (auto dataRef{ExtractDataRef(Analyze(x.base))}) {
std::vector<Subscript> subscripts;
std::vector<const Symbol *> reversed;
SymbolVector reversed;
if (auto *aRef{std::get_if<ArrayRef>(&dataRef->u)}) {
subscripts = std::move(aRef->subscript());
reversed.push_back(&aRef->GetLastSymbol());
reversed.push_back(aRef->GetLastSymbol());
if (Component * component{aRef->base().UnwrapComponent()}) {
*dataRef = std::move(component->base());
} else {
@ -950,10 +950,10 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::CoindexedNamedObject &x) {
}
if (dataRef.has_value()) {
while (auto *component{std::get_if<Component>(&dataRef->u)}) {
reversed.push_back(&component->GetLastSymbol());
reversed.push_back(component->GetLastSymbol());
*dataRef = std::move(component->base());
}
if (auto *baseSym{std::get_if<const Symbol *>(&dataRef->u)}) {
if (auto *baseSym{std::get_if<SymbolRef>(&dataRef->u)}) {
reversed.push_back(*baseSym);
} else {
Say("Base of coindexed named object has subscripts or cosubscripts"_err_en_US);
@ -973,7 +973,7 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::CoindexedNamedObject &x) {
}
if (cosubsOk && !reversed.empty()) {
int numCosubscripts{static_cast<int>(cosubscripts.size())};
const Symbol &symbol{*reversed.front()};
const Symbol &symbol{reversed.front()};
if (numCosubscripts != symbol.Corank()) {
Say("'%s' has corank %d, but coindexed reference has %d cosubscripts"_err_en_US,
symbol.name(), symbol.Corank(), numCosubscripts);
@ -982,9 +982,9 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::CoindexedNamedObject &x) {
// TODO: stat=/team=/team_number=
// Reverse the chain of symbols so that the base is first and coarray
// ultimate component is last.
return Designate(DataRef{CoarrayRef{
std::vector<const Symbol *>{reversed.crbegin(), reversed.crend()},
std::move(subscripts), std::move(cosubscripts)}});
return Designate(
DataRef{CoarrayRef{SymbolVector{reversed.crbegin(), reversed.crend()},
std::move(subscripts), std::move(cosubscripts)}});
}
return std::nullopt;
}
@ -1298,9 +1298,9 @@ MaybeExpr ExpressionAnalyzer::Analyze(
symbol = kw->v.symbol;
if (symbol == nullptr) {
auto componentIter{std::find_if(components.begin(), components.end(),
[=](const Symbol *symbol) { return symbol->name() == source; })};
[=](const Symbol &symbol) { return symbol.name() == source; })};
if (componentIter != components.end()) {
symbol = *componentIter;
symbol = &*componentIter;
}
}
if (symbol == nullptr) { // C7101
@ -1321,7 +1321,7 @@ MaybeExpr ExpressionAnalyzer::Analyze(
valueType == DynamicType::From(*parentComponent) &&
context().IsEnabled(parser::LanguageFeature::AnonymousParents)) {
auto iter{
std::find(components.begin(), components.end(), parentComponent)};
std::find(components.begin(), components.end(), *parentComponent)};
if (iter != components.end()) {
symbol = parentComponent;
nextAnonymous = ++iter;
@ -1334,9 +1334,10 @@ MaybeExpr ExpressionAnalyzer::Analyze(
}
}
while (symbol == nullptr && nextAnonymous != components.end()) {
const Symbol *nextSymbol{*nextAnonymous++};
if (!nextSymbol->test(Symbol::Flag::ParentComp)) {
symbol = nextSymbol;
const Symbol &next{*nextAnonymous};
++nextAnonymous;
if (!next.test(Symbol::Flag::ParentComp)) {
symbol = &next;
}
}
if (symbol == nullptr) {
@ -1346,7 +1347,7 @@ MaybeExpr ExpressionAnalyzer::Analyze(
if (symbol != nullptr) {
if (checkConflicts) {
auto componentIter{
std::find(components.begin(), components.end(), symbol)};
std::find(components.begin(), components.end(), *symbol)};
if (unavailable.find(symbol->name()) != unavailable.cend()) {
// C797, C798
Say(source,
@ -1356,14 +1357,14 @@ MaybeExpr ExpressionAnalyzer::Analyze(
} else if (symbol->test(Symbol::Flag::ParentComp)) {
// Make earlier components unavailable once a whole parent appears.
for (auto it{components.begin()}; it != componentIter; ++it) {
unavailable.insert((*it)->name());
unavailable.insert(it->name());
}
} else {
// Make whole parent components unavailable after any of their
// constituents appear.
for (auto it{componentIter}; it != components.end(); ++it) {
if ((*it)->test(Symbol::Flag::ParentComp)) {
unavailable.insert((*it)->name());
if (it->test(Symbol::Flag::ParentComp)) {
unavailable.insert(it->name());
}
}
}
@ -1439,20 +1440,20 @@ MaybeExpr ExpressionAnalyzer::Analyze(
}
// Ensure that unmentioned component objects have default initializers.
for (const Symbol *symbol : components) {
if (!symbol->test(Symbol::Flag::ParentComp) &&
unavailable.find(symbol->name()) == unavailable.cend() &&
!IsAllocatable(*symbol)) {
for (const Symbol &symbol : components) {
if (!symbol.test(Symbol::Flag::ParentComp) &&
unavailable.find(symbol.name()) == unavailable.cend() &&
!IsAllocatable(symbol)) {
if (const auto *details{
symbol->detailsIf<semantics::ObjectEntityDetails>()}) {
symbol.detailsIf<semantics::ObjectEntityDetails>()}) {
if (details->init().has_value()) {
result.Add(*symbol, common::Clone(*details->init()));
result.Add(symbol, common::Clone(*details->init()));
} else { // C799
if (auto *msg{Say(typeName,
"Structure constructor lacks a value for "
"component '%s'"_err_en_US,
symbol->name())}) {
msg->Attach(symbol->name(), "Absent component"_en_US);
symbol.name())}) {
msg->Attach(symbol.name(), "Absent component"_en_US);
}
}
}
@ -1585,18 +1586,18 @@ const Symbol *ExpressionAnalyzer::ResolveGeneric(
const Symbol &symbol, ActualArguments &actuals) {
const Symbol *elemental{nullptr}; // matching elemental specific proc
const auto &details{symbol.GetUltimate().get<semantics::GenericDetails>()};
for (const Symbol *specific : details.specificProcs()) {
for (const Symbol &specific : details.specificProcs()) {
if (std::optional<characteristics::Procedure> procedure{
characteristics::Procedure::Characterize(
ProcedureDesignator{*specific}, context_.intrinsics())}) {
ProcedureDesignator{specific}, context_.intrinsics())}) {
ActualArguments localActuals{actuals};
if (semantics::CheckInterfaceForGeneric(
*procedure, localActuals, GetFoldingContext())) {
if (CheckCompatibleArguments(*procedure, localActuals)) {
if (!procedure->IsElemental()) {
return specific; // takes priority over elemental match
return &specific; // takes priority over elemental match
}
elemental = specific;
elemental = &specific;
}
}
}
@ -2423,10 +2424,10 @@ std::optional<ActualArgument> ArgumentAnalyzer::Analyze(
if (auto ptr{semantics::FindPointerUltimateComponent(*derived)}) {
if (auto *msg{context_.Say(expr.source,
"Coindexed object '%s' with POINTER ultimate component '%s' cannot be passed as argument"_err_en_US,
coarray.name(), (*ptr)->name())}) {
msg->Attach((*ptr)->name(),
coarray.name(), ptr->name())}) {
msg->Attach(ptr->name(),
"Declaration of POINTER '%s' component of %s"_en_US,
(*ptr)->name(), type->AsFortran());
ptr->name(), type->AsFortran());
}
}
}

View File

@ -51,7 +51,7 @@ struct ModHeader {
};
static std::optional<SourceName> GetSubmoduleParent(const parser::Program &);
static std::vector<const Symbol *> CollectSymbols(const Scope &);
static SymbolVector CollectSymbols(const Scope &);
static void PutEntity(std::ostream &, const Symbol &);
static void PutObjectEntity(std::ostream &, const Symbol &);
static void PutProcEntity(std::ostream &, const Symbol &);
@ -77,10 +77,8 @@ static std::string CheckSum(const std::string_view &);
// Collect symbols needed for a subprogram interface
class SubprogramSymbolCollector {
public:
using SymbolSet = std::set<const Symbol *>;
SubprogramSymbolCollector(const Symbol &symbol)
: symbol_{symbol}, scope_{*symbol.scope()} {}
: symbol_{symbol}, scope_{DEREF(symbol.scope())} {}
const SymbolVector &symbols() const { return need_; }
const std::set<SourceName> &imports() const { return imports_; }
void Collect();
@ -102,8 +100,8 @@ private:
bool NeedImport(const SourceName &, const Symbol &);
template<typename T> void DoExpr(evaluate::Expr<T> expr) {
for (const Symbol *symbol : evaluate::CollectSymbols(expr)) {
DoSymbol(DEREF(symbol));
for (const Symbol &symbol : evaluate::CollectSymbols(expr)) {
DoSymbol(symbol);
}
}
};
@ -142,7 +140,7 @@ void ModFileWriter::Write(const Symbol &symbol) {
auto ancestorName{ancestor ? ancestor->GetName().value().ToString() : ""s};
auto path{context_.moduleDirectory() + '/' +
ModFileName(symbol.name(), ancestorName, context_.moduleFileSuffix())};
PutSymbols(*symbol.scope());
PutSymbols(DEREF(symbol.scope()));
if (int error{WriteFile(path, GetAsString(symbol))}) {
context_.Say(symbol.name(), "Error writing %s: %s"_err_en_US, path,
std::strerror(error));
@ -183,7 +181,7 @@ std::string ModFileWriter::GetAsString(const Symbol &symbol) {
// Put out the visible symbols from scope.
void ModFileWriter::PutSymbols(const Scope &scope) {
std::stringstream typeBindings; // stuff after CONTAINS in derived type
for (const auto *symbol : CollectSymbols(scope)) {
for (const Symbol &symbol : CollectSymbols(scope)) {
PutSymbol(typeBindings, symbol);
}
if (auto str{typeBindings.str()}; !str.empty()) {
@ -195,76 +193,77 @@ void ModFileWriter::PutSymbols(const Scope &scope) {
// Emit a symbol to decls_, except for bindings in a derived type (type-bound
// procedures, type-bound generics, final procedures) which go to typeBindings.
void ModFileWriter::PutSymbol(
std::stringstream &typeBindings, const Symbol *symbol) {
if (symbol == nullptr) {
return;
}
std::stringstream &typeBindings, const Symbol &symbol) {
std::visit(
common::visitors{
[&](const ModuleDetails &) { /* should be current module */ },
[&](const DerivedTypeDetails &) { PutDerivedType(*symbol); },
[&](const SubprogramDetails &) { PutSubprogram(*symbol); },
[&](const DerivedTypeDetails &) { PutDerivedType(symbol); },
[&](const SubprogramDetails &) { PutSubprogram(symbol); },
[&](const GenericDetails &x) {
PutGeneric(*symbol);
PutSymbol(typeBindings, x.specific());
PutSymbol(typeBindings, x.derivedType());
PutGeneric(symbol);
if (x.specific()) {
PutSymbol(typeBindings, *x.specific());
}
if (x.derivedType()) {
PutSymbol(typeBindings, *x.derivedType());
}
},
[&](const UseDetails &) { PutUse(*symbol); },
[&](const UseDetails &) { PutUse(symbol); },
[](const UseErrorDetails &) {},
[&](const ProcBindingDetails &x) {
bool deferred{symbol->attrs().test(Attr::DEFERRED)};
bool deferred{symbol.attrs().test(Attr::DEFERRED)};
typeBindings << "procedure";
if (deferred) {
typeBindings << '(' << x.symbol().name() << ')';
}
PutPassName(typeBindings, x.passName());
auto attrs{symbol->attrs()};
auto attrs{symbol.attrs()};
if (x.passName().has_value()) {
attrs.reset(Attr::PASS);
}
PutAttrs(typeBindings, attrs);
typeBindings << "::" << symbol->name();
if (!deferred && x.symbol().name() != symbol->name()) {
typeBindings << "::" << symbol.name();
if (!deferred && x.symbol().name() != symbol.name()) {
typeBindings << "=>" << x.symbol().name();
}
typeBindings << '\n';
},
[&](const GenericBindingDetails &x) {
for (const auto *proc : x.specificProcs()) {
typeBindings << "generic::" << symbol->name() << "=>"
<< proc->name() << '\n';
for (const Symbol &proc : x.specificProcs()) {
typeBindings << "generic::" << symbol.name() << "=>"
<< proc.name() << '\n';
}
},
[&](const NamelistDetails &x) {
decls_ << "namelist/" << symbol->name();
decls_ << "namelist/" << symbol.name();
char sep{'/'};
for (const auto *object : x.objects()) {
decls_ << sep << object->name();
for (const Symbol &object : x.objects()) {
decls_ << sep << object.name();
sep = ',';
}
decls_ << '\n';
},
[&](const CommonBlockDetails &x) {
decls_ << "common/" << symbol->name();
decls_ << "common/" << symbol.name();
char sep = '/';
for (const auto *object : x.objects()) {
decls_ << sep << object->name();
decls_ << sep << DEREF(object).name();
sep = ',';
}
decls_ << '\n';
if (symbol->attrs().test(Attr::BIND_C)) {
PutAttrs(decls_, symbol->attrs(), x.bindName(), ""s);
decls_ << "::/" << symbol->name() << "/\n";
if (symbol.attrs().test(Attr::BIND_C)) {
PutAttrs(decls_, symbol.attrs(), x.bindName(), ""s);
decls_ << "::/" << symbol.name() << "/\n";
}
},
[&](const FinalProcDetails &) {
typeBindings << "final::" << symbol->name() << '\n';
typeBindings << "final::" << symbol.name() << '\n';
},
[](const HostAssocDetails &) {},
[](const MiscDetails &) {},
[&](const auto &) { PutEntity(decls_, *symbol); },
[&](const auto &) { PutEntity(decls_, symbol); },
},
symbol->details());
symbol.details());
}
void ModFileWriter::PutDerivedType(const Symbol &typeSymbol) {
@ -342,7 +341,7 @@ void ModFileWriter::PutSubprogram(const Symbol &symbol) {
std::stringstream typeBindings;
SubprogramSymbolCollector collector{symbol};
collector.Collect();
for (const Symbol *need : collector.symbols()) {
for (const Symbol &need : collector.symbols()) {
writer.PutSymbol(typeBindings, need);
}
CHECK(typeBindings.str().empty());
@ -377,8 +376,8 @@ static std::ostream &PutGenericName(std::ostream &os, const Symbol &symbol) {
void ModFileWriter::PutGeneric(const Symbol &symbol) {
auto &details{symbol.get<GenericDetails>()};
PutGenericName(decls_ << "interface ", symbol) << '\n';
for (auto *specific : details.specificProcs()) {
decls_ << "procedure::" << specific->name() << '\n';
for (const Symbol &specific : details.specificProcs()) {
decls_ << "procedure::" << specific.name() << '\n';
}
decls_ << "end interface\n";
if (symbol.attrs().test(Attr::PRIVATE)) {
@ -413,18 +412,18 @@ void ModFileWriter::PutUseExtraAttr(
// Collect the symbols of this scope sorted by their original order, not name.
// Namelists are an exception: they are sorted after other symbols.
std::vector<const Symbol *> CollectSymbols(const Scope &scope) {
std::set<const Symbol *> symbols; // to prevent duplicates
std::vector<const Symbol *> sorted;
std::vector<const Symbol *> namelist;
std::vector<const Symbol *> common;
SymbolVector CollectSymbols(const Scope &scope) {
SymbolSet symbols; // to prevent duplicates
SymbolVector sorted;
SymbolVector namelist;
SymbolVector common;
sorted.reserve(scope.size() + scope.commonBlocks().size());
for (const auto &pair : scope) {
auto *symbol{pair.second};
if (!symbol->test(Symbol::Flag::ParentComp) &&
!symbol->attrs().test(Attr::INTRINSIC)) {
const Symbol &symbol{*pair.second};
if (!symbol.test(Symbol::Flag::ParentComp) &&
!symbol.attrs().test(Attr::INTRINSIC)) {
if (symbols.insert(symbol).second) {
if (symbol->has<NamelistDetails>()) {
if (symbol.has<NamelistDetails>()) {
namelist.push_back(symbol);
} else {
sorted.push_back(symbol);
@ -433,21 +432,18 @@ std::vector<const Symbol *> CollectSymbols(const Scope &scope) {
}
}
for (const auto &pair : scope.commonBlocks()) {
const Symbol *symbol{pair.second};
const Symbol &symbol{*pair.second};
if (symbols.insert(symbol).second) {
common.push_back(symbol);
}
}
// sort normal symbols, then namelists, then common blocks:
auto compareByOrder = [](const Symbol *x, const Symbol *y) {
return DEREF(x).name().begin() < DEREF(y).name().begin();
};
auto cursor{sorted.begin()};
std::sort(cursor, sorted.end(), compareByOrder);
std::sort(cursor, sorted.end());
cursor = sorted.insert(sorted.end(), namelist.begin(), namelist.end());
std::sort(cursor, sorted.end(), compareByOrder);
std::sort(cursor, sorted.end());
cursor = sorted.insert(sorted.end(), common.begin(), common.end());
std::sort(cursor, sorted.end(), compareByOrder);
std::sort(cursor, sorted.end());
return sorted;
}
@ -848,9 +844,9 @@ void SubprogramSymbolCollector::Collect() {
DoSymbol(details.result());
}
for (const auto &pair : scope_) {
const Symbol *symbol{pair.second};
if (const auto *useDetails{symbol->detailsIf<UseDetails>()}) {
if (useSet_.count(&useDetails->symbol()) > 0) {
const Symbol &symbol{*pair.second};
if (const auto *useDetails{symbol.detailsIf<UseDetails>()}) {
if (useSet_.count(useDetails->symbol()) > 0) {
need_.push_back(symbol);
}
}
@ -867,14 +863,14 @@ void SubprogramSymbolCollector::DoSymbol(
const auto &scope{symbol.owner()};
if (scope != scope_ && !scope.IsDerivedType()) {
if (scope != scope_.parent()) {
useSet_.insert(&symbol);
useSet_.insert(symbol);
}
if (NeedImport(name, symbol)) {
imports_.insert(name);
}
return;
}
if (!needSet_.insert(&symbol).second) {
if (!needSet_.insert(symbol).second) {
return; // already done
}
std::visit(
@ -904,7 +900,7 @@ void SubprogramSymbolCollector::DoSymbol(
DoType(symbol.GetType());
}
if (!scope.IsDerivedType()) {
need_.push_back(&symbol);
need_.push_back(symbol);
}
}
@ -928,7 +924,7 @@ void SubprogramSymbolCollector::DoType(const DeclTypeSpec *type) {
DoParamValue(pair.second);
}
for (const auto pair : *typeSymbol.scope()) {
const auto &comp{*pair.second};
const Symbol &comp{*pair.second};
DoSymbol(comp);
}
DoSymbol(derived->name(), derived->typeSymbol());

View File

@ -49,7 +49,7 @@ private:
void Write(const Symbol &);
std::string GetAsString(const Symbol &);
void PutSymbols(const Scope &);
void PutSymbol(std::stringstream &, const Symbol *);
void PutSymbol(std::stringstream &, const Symbol &);
void PutDerivedType(const Symbol &);
void PutSubprogram(const Symbol &);
void PutGeneric(const Symbol &);

View File

@ -1002,7 +1002,7 @@ private:
// expr is set in either case unless there were errors
struct Selector {
Selector() {}
Selector(const parser::CharBlock &source, MaybeExpr &&expr)
Selector(const SourceName &source, MaybeExpr &&expr)
: source{source}, expr{std::move(expr)} {}
operator bool() const { return expr.has_value(); }
parser::CharBlock source;
@ -1969,15 +1969,14 @@ Symbol *ScopeHandler::FindSymbol(const Scope &scope, const parser::Name &name) {
Symbol &ScopeHandler::MakeSymbol(
Scope &scope, const SourceName &name, Attrs attrs) {
auto *symbol{FindInScope(scope, name)};
if (symbol) {
if (Symbol * symbol{FindInScope(scope, name)}) {
symbol->attrs() |= attrs;
return *symbol;
} else {
const auto pair{scope.try_emplace(name, attrs, UnknownDetails{})};
CHECK(pair.second); // name was not found, so must be able to add
symbol = pair.first->second;
return *pair.first->second;
}
return *symbol;
}
Symbol &ScopeHandler::MakeSymbol(const SourceName &name, Attrs attrs) {
return MakeSymbol(currScope(), name, attrs);
@ -1997,7 +1996,7 @@ Symbol *ScopeHandler::FindInScope(
}
Symbol *ScopeHandler::FindInScope(const Scope &scope, const SourceName &name) {
if (auto it{scope.find(name)}; it != scope.end()) {
return it->second;
return &*it->second;
} else {
return nullptr;
}
@ -2061,9 +2060,7 @@ void ScopeHandler::ApplyImplicitRules(Symbol &symbol) {
}
}
const DeclTypeSpec *ScopeHandler::GetImplicitType(Symbol &symbol) {
auto &name{symbol.name()};
const auto *type{implicitRules().GetType(name.begin()[0])};
return type;
return implicitRules().GetType(symbol.name().begin()[0]);
}
// Convert symbol to be a ObjectEntity or return false if it can't be.
@ -2455,8 +2452,8 @@ void InterfaceVisitor::AddSpecificProcs(
void InterfaceVisitor::ResolveSpecificsInGeneric(Symbol &generic) {
auto &details{generic.get<GenericDetails>()};
std::set<SourceName> namesSeen; // to check for duplicate names
for (const auto *symbol : details.specificProcs()) {
namesSeen.insert(symbol->name());
for (const Symbol &symbol : details.specificProcs()) {
namesSeen.insert(symbol.name());
}
auto range{specificProcs_.equal_range(&generic)};
for (auto it{range.first}; it != range.second; ++it) {
@ -2529,18 +2526,18 @@ void InterfaceVisitor::CheckGenericProcedures(Symbol &generic) {
}
return;
}
auto &firstSpecific{*specifics.front()};
const Symbol &firstSpecific{specifics.front()};
bool isFunction{firstSpecific.test(Symbol::Flag::Function)};
for (const auto *specific : specifics) {
if (isFunction != specific->test(Symbol::Flag::Function)) { // C1514
for (const Symbol &specific : specifics) {
if (isFunction != specific.test(Symbol::Flag::Function)) { // C1514
auto &msg{Say(generic.name(),
"Generic interface '%s' has both a function and a subroutine"_err_en_US)};
if (isFunction) {
msg.Attach(firstSpecific.name(), "Function declaration"_en_US);
msg.Attach(specific->name(), "Subroutine declaration"_en_US);
msg.Attach(specific.name(), "Subroutine declaration"_en_US);
} else {
msg.Attach(firstSpecific.name(), "Subroutine declaration"_en_US);
msg.Attach(specific->name(), "Function declaration"_en_US);
msg.Attach(specific.name(), "Function declaration"_en_US);
}
}
}
@ -2598,11 +2595,11 @@ void InterfaceVisitor::CheckSpecificsAreDistinguishable(
: evaluate::characteristics::Distinguishable};
using evaluate::characteristics::Procedure;
std::vector<Procedure> procs;
for (const Symbol *symbol : specifics) {
if (context().HasError(*symbol)) {
for (const Symbol &symbol : specifics) {
if (context().HasError(symbol)) {
return;
}
auto proc{Procedure::Characterize(*symbol, context().intrinsics())};
auto proc{Procedure::Characterize(symbol, context().intrinsics())};
if (!proc) {
return;
}
@ -2613,7 +2610,7 @@ void InterfaceVisitor::CheckSpecificsAreDistinguishable(
for (std::size_t i2{i1 + 1}; i2 < count; ++i2) {
auto &proc2{procs[i2]};
if (!distinguishable(proc1, proc2)) {
SayNotDistinguishable(generic, *specifics[i1], *specifics[i2]);
SayNotDistinguishable(generic, specifics[i1], specifics[i2]);
context().SetError(generic);
}
}
@ -3450,13 +3447,13 @@ void DeclarationVisitor::Post(const parser::DerivedTypeSpec &x) {
seenAnyName = true;
name = optKeyword->v.source;
auto it{std::find_if(parameterDecls.begin(), parameterDecls.end(),
[&](const Symbol *symbol) { return symbol->name() == name; })};
[&](const Symbol &symbol) { return symbol.name() == name; })};
if (it == parameterDecls.end()) {
Say(name,
"'%s' is not the name of a parameter for this type"_err_en_US);
} else {
attr = (*it)->get<TypeParamDetails>().attr();
Resolve(optKeyword->v, const_cast<Symbol *>(*it));
attr = it->get().get<TypeParamDetails>().attr();
Resolve(optKeyword->v, const_cast<Symbol *>(&it->get()));
}
} else if (seenAnyName) {
Say(typeName.source, "Type parameter value must have a name"_err_en_US);
@ -3464,9 +3461,9 @@ void DeclarationVisitor::Post(const parser::DerivedTypeSpec &x) {
} else if (nextNameIter != parameterNames.end()) {
name = *nextNameIter++;
auto it{std::find_if(parameterDecls.begin(), parameterDecls.end(),
[&](const Symbol *symbol) { return symbol->name() == name; })};
[&](const Symbol &symbol) { return symbol.name() == name; })};
if (it != parameterDecls.end()) {
attr = (*it)->get<TypeParamDetails>().attr();
attr = it->get().get<TypeParamDetails>().attr();
}
} else {
Say(typeName.source,
@ -3492,9 +3489,9 @@ void DeclarationVisitor::Post(const parser::DerivedTypeSpec &x) {
for (const SourceName &name : parameterNames) {
if (!spec->FindParameter(name)) {
auto it{std::find_if(parameterDecls.begin(), parameterDecls.end(),
[&](const Symbol *symbol) { return symbol->name() == name; })};
[&](const Symbol &symbol) { return symbol.name() == name; })};
if (it != parameterDecls.end()) {
const auto *details{(*it)->detailsIf<TypeParamDetails>()};
const auto *details{it->get().detailsIf<TypeParamDetails>()};
if (details == nullptr || !details->init().has_value()) {
Say(typeName.source,
"Type parameter '%s' lacks a value and has no default"_err_en_US,

View File

@ -77,7 +77,7 @@ Scope::size_type Scope::erase(const SourceName &name) {
Symbol *Scope::FindSymbol(const SourceName &name) const {
auto it{find(name)};
if (it != end()) {
return it->second;
return &*it->second;
} else if (CanImport(name)) {
return parent_.FindSymbol(name);
} else {
@ -94,7 +94,7 @@ void Scope::add_equivalenceSet(EquivalenceSet &&set) {
void Scope::add_crayPointer(const SourceName &name, Symbol &pointer) {
CHECK(pointer.test(Symbol::Flag::CrayPointer));
crayPointers_.emplace(name, &pointer);
crayPointers_.emplace(name, pointer);
}
Symbol &Scope::MakeCommonBlock(const SourceName &name) {
@ -103,13 +103,13 @@ Symbol &Scope::MakeCommonBlock(const SourceName &name) {
return *it->second;
} else {
Symbol &symbol{MakeSymbol(name, Attrs{}, CommonBlockDetails{})};
commonBlocks_.emplace(name, &symbol);
commonBlocks_.emplace(name, symbol);
return symbol;
}
}
Symbol *Scope::FindCommonBlock(const SourceName &name) {
const auto it{commonBlocks_.find(name)};
return it != commonBlocks_.end() ? it->second : nullptr;
return it != commonBlocks_.end() ? &*it->second : nullptr;
}
Scope *Scope::FindSubmodule(const SourceName &name) const {
@ -117,11 +117,11 @@ Scope *Scope::FindSubmodule(const SourceName &name) const {
if (it == submodules_.end()) {
return nullptr;
} else {
return it->second;
return &*it->second;
}
}
bool Scope::AddSubmodule(const SourceName &name, Scope &submodule) {
return submodules_.emplace(name, &submodule).second;
return submodules_.emplace(name, submodule).second;
}
const DeclTypeSpec *Scope::FindType(const DeclTypeSpec &type) const {
@ -248,8 +248,8 @@ std::ostream &operator<<(std::ostream &os, const Scope &scope) {
}
os << scope.children_.size() << " children\n";
for (const auto &pair : scope.symbols_) {
const auto *symbol{pair.second};
os << " " << *symbol << '\n';
const Symbol &symbol{*pair.second};
os << " " << symbol << '\n';
}
if (!scope.equivalenceSets_.empty()) {
os << " Equivalence Sets:\n";
@ -262,8 +262,8 @@ std::ostream &operator<<(std::ostream &os, const Scope &scope) {
}
}
for (const auto &pair : scope.commonBlocks_) {
const auto *symbol{pair.second};
os << " " << *symbol << '\n';
const Symbol &symbol{*pair.second};
os << " " << symbol << '\n';
}
return os;
}

View File

@ -19,6 +19,7 @@
#include "symbol.h"
#include "../common/Fortran.h"
#include "../common/idioms.h"
#include "../common/reference.h"
#include "../parser/message.h"
#include "../parser/provenance.h"
#include <list>
@ -50,7 +51,7 @@ struct EquivalenceObject {
using EquivalenceSet = std::vector<EquivalenceObject>;
class Scope {
using mapType = std::map<SourceName, Symbol *>;
using mapType = std::map<SourceName, common::Reference<Symbol>>;
public:
ENUM_CLASS(Kind, Global, Module, MainProgram, Subprogram, DerivedType, Block,
@ -138,7 +139,7 @@ public:
common::IfNoLvalue<std::pair<iterator, bool>, D> try_emplace(
const SourceName &name, Attrs attrs, D &&details) {
Symbol &symbol{MakeSymbol(name, attrs, std::move(details))};
return symbols_.emplace(name, &symbol);
return symbols_.emplace(name, symbol);
}
const std::list<EquivalenceSet> &equivalenceSets() const;
@ -220,7 +221,7 @@ private:
mapType commonBlocks_;
std::list<EquivalenceSet> equivalenceSets_;
mapType crayPointers_;
std::map<SourceName, Scope *> submodules_;
std::map<SourceName, common::Reference<Scope>> submodules_;
std::list<DeclTypeSpec> declTypeSpecs_;
std::string chars_;
std::optional<ImportKind> importKind_;

View File

@ -40,17 +40,17 @@
namespace Fortran::semantics {
using NameToSymbolMap = std::map<const char *, const Symbol *>;
using NameToSymbolMap = std::map<const char *, SymbolRef>;
static void DoDumpSymbols(std::ostream &, const Scope &, int indent = 0);
static void PutIndent(std::ostream &, int indent);
static void GetSymbolNames(const Scope &scope, NameToSymbolMap &symbols) {
// Finds all symbol names in the scope without collecting duplicates.
for (const auto &pair : scope) {
symbols.emplace(pair.second->name().begin(), pair.second);
symbols.emplace(pair.second->name().begin(), *pair.second);
}
for (const auto &pair : scope.commonBlocks()) {
symbols.emplace(pair.second->name().begin(), pair.second);
symbols.emplace(pair.second->name().begin(), *pair.second);
}
for (const auto &child : scope.children()) {
GetSymbolNames(child, symbols);
@ -227,7 +227,7 @@ void Semantics::DumpSymbolsSources(std::ostream &os) const {
NameToSymbolMap symbols;
GetSymbolNames(context_.globalScope(), symbols);
for (const auto pair : symbols) {
const Symbol &symbol{*pair.second};
const Symbol &symbol{pair.second};
if (auto sourceInfo{cooked_.GetSourcePositionRange(symbol.name())}) {
os << symbol.name().ToString() << ": " << sourceInfo->first.file.path()
<< ", " << sourceInfo->first.line << ", " << sourceInfo->first.column

View File

@ -35,8 +35,8 @@ static void DumpBool(std::ostream &os, const char *label, bool x) {
static void DumpSymbolVector(std::ostream &os, const SymbolVector &list) {
char sep{' '};
for (const auto *elem : list) {
os << sep << elem->name();
for (const Symbol &elem : list) {
os << sep << elem.name();
sep = ',';
}
}
@ -166,8 +166,8 @@ const Symbol *GenericDetails::CheckSpecific() const {
}
Symbol *GenericDetails::CheckSpecific() {
if (specific_) {
for (const auto *proc : specificProcs_) {
if (proc == specific_) {
for (const Symbol &proc : specificProcs_) {
if (&proc == specific_) {
return nullptr;
}
}
@ -186,8 +186,9 @@ void GenericDetails::CopyFrom(const GenericDetails &from) {
CHECK(!derivedType_ || derivedType_ == from.derivedType_);
derivedType_ = from.derivedType_;
}
for (const Symbol *symbol : from.specificProcs_) {
if (std::find(specificProcs_.begin(), specificProcs_.end(), symbol) ==
for (const Symbol &symbol : from.specificProcs_) {
if (std::find_if(specificProcs_.begin(), specificProcs_.end(),
[&](const Symbol &mySymbol) { return &mySymbol == &symbol; }) ==
specificProcs_.end()) {
specificProcs_.push_back(symbol);
}

View File

@ -18,9 +18,10 @@
#include "type.h"
#include "../common/Fortran.h"
#include "../common/enum-set.h"
#include <functional>
#include "../common/reference.h"
#include <list>
#include <optional>
#include <set>
#include <vector>
namespace Fortran::semantics {
@ -32,7 +33,8 @@ namespace Fortran::semantics {
class Scope;
class Symbol;
using SymbolVector = std::vector<const Symbol *>;
using SymbolRef = common::Reference<const Symbol>;
using SymbolVector = std::vector<SymbolRef>;
// A module or submodule.
class ModuleDetails {
@ -227,7 +229,7 @@ public:
const SymbolVector &paramDecls() const { return paramDecls_; }
bool sequence() const { return sequence_; }
void add_paramName(const SourceName &name) { paramNames_.push_back(name); }
void add_paramDecl(const Symbol &symbol) { paramDecls_.push_back(&symbol); }
void add_paramDecl(const Symbol &symbol) { paramDecls_.push_back(symbol); }
void add_component(const Symbol &);
void set_sequence(bool x = true) { sequence_ = x; }
const std::list<SourceName> &componentNames() const {
@ -281,7 +283,7 @@ public:
GenericKind kind() const { return kind_; }
void set_kind(GenericKind kind) { kind_ = kind; }
const SymbolVector &specificProcs() const { return specificProcs_; }
void add_specificProc(const Symbol &proc) { specificProcs_.push_back(&proc); }
void add_specificProc(const Symbol &proc) { specificProcs_.push_back(proc); }
private:
GenericKind kind_{GenericKind::Name};
@ -291,7 +293,7 @@ private:
class NamelistDetails {
public:
const SymbolVector &objects() const { return objects_; }
void add_object(const Symbol &object) { objects_.push_back(&object); }
void add_object(const Symbol &object) { objects_.push_back(object); }
void add_objects(const SymbolVector &objects) {
objects_.insert(objects_.end(), objects.begin(), objects.end());
}
@ -392,7 +394,7 @@ public:
void set_kind(GenericKind kind) { kind_ = kind; }
const SymbolVector &specificProcs() const { return specificProcs_; }
void add_specificProc(const Symbol &proc) { specificProcs_.push_back(&proc); }
void add_specificProc(const Symbol &proc) { specificProcs_.push_back(proc); }
// specific and derivedType indicate a specific procedure or derived type
// with the same name as this generic. Only one of them may be set.
@ -583,6 +585,10 @@ public:
bool operator==(const Symbol &that) const { return this == &that; }
bool operator!=(const Symbol &that) const { return this != &that; }
bool operator<(const Symbol &that) const {
// For sets of symbols: collate them by source location
return name_.begin() < that.name_.begin();
}
int Rank() const {
return std::visit(
@ -699,5 +705,9 @@ inline bool ProcEntityDetails::HasExplicitInterface() const {
}
return false;
}
inline bool operator<(SymbolRef x, SymbolRef y) { return *x < *y; }
using SymbolSet = std::set<SymbolRef>;
}
#endif // FORTRAN_SEMANTICS_SYMBOL_H_

View File

@ -168,7 +168,7 @@ bool IsFunction(const Symbol &symbol) {
bool IsPureProcedure(const Symbol &symbol) {
if (const auto *procDetails{symbol.detailsIf<ProcEntityDetails>()}) {
if (const Symbol *procInterface{procDetails->interface().symbol()}) {
if (const Symbol * procInterface{procDetails->interface().symbol()}) {
// procedure component with a PURE interface
return IsPureProcedure(*procInterface);
}
@ -669,8 +669,8 @@ const parser::CharBlock GetImageControlStmtLocation(
bool HasCoarray(const parser::Expr &expression) {
if (const auto *expr{GetExpr(expression)}) {
for (const Symbol *symbol : evaluate::CollectSymbols(*expr)) {
if (const Symbol * root{GetAssociationRoot(DEREF(symbol))}) {
for (const Symbol &symbol : evaluate::CollectSymbols(*expr)) {
if (const Symbol * root{GetAssociationRoot(symbol)}) {
if (IsCoarray(*root)) {
return true;
}
@ -759,14 +759,14 @@ void InstantiateDerivedType(DerivedTypeSpec &spec, Scope &containingScope,
const Symbol &typeSymbol{spec.typeSymbol()};
const Scope *typeScope{typeSymbol.scope()};
CHECK(typeScope != nullptr);
for (const Symbol *symbol : OrderParameterDeclarations(typeSymbol)) {
const SourceName &name{symbol->name()};
if (typeScope->find(symbol->name()) != typeScope->end()) {
for (const Symbol &symbol : OrderParameterDeclarations(typeSymbol)) {
const SourceName &name{symbol.name()};
if (typeScope->find(symbol.name()) != typeScope->end()) {
// This type parameter belongs to the derived type itself, not to
// one of its parents. Put the type parameter expression value
// into the new scope as the initialization value for the parameter.
if (ParamValue * paramValue{spec.FindParameter(name)}) {
const TypeParamDetails &details{symbol->get<TypeParamDetails>()};
const TypeParamDetails &details{symbol.get<TypeParamDetails>()};
paramValue->set_attr(details.attr());
if (MaybeIntExpr expr{paramValue->GetExplicit()}) {
// Ensure that any kind type parameters with values are
@ -796,10 +796,7 @@ void InstantiateDerivedType(DerivedTypeSpec &spec, Scope &containingScope,
instanceDetails.set_type(*type);
}
instanceDetails.set_init(std::move(*expr));
Symbol *parameter{
newScope.try_emplace(name, std::move(instanceDetails))
.first->second};
CHECK(parameter != nullptr);
newScope.try_emplace(name, std::move(instanceDetails));
}
}
}
@ -821,11 +818,11 @@ void ProcessParameterExpressions(
// fold them within the scope of the derived type being instantiated;
// these expressions cannot use its type parameters. Convert the values
// of the expressions to the declared types of the type parameters.
for (const Symbol *symbol : paramDecls) {
const SourceName &name{symbol->name()};
for (const Symbol &symbol : paramDecls) {
const SourceName &name{symbol.name()};
if (ParamValue * paramValue{spec.FindParameter(name)}) {
if (const MaybeIntExpr & expr{paramValue->GetExplicit()}) {
if (auto converted{evaluate::ConvertToType(*symbol, SomeExpr{*expr})}) {
if (auto converted{evaluate::ConvertToType(symbol, SomeExpr{*expr})}) {
SomeExpr folded{
evaluate::Fold(foldingContext, std::move(*converted))};
if (auto *intExpr{std::get_if<SomeIntExpr>(&folded.u)}) {
@ -849,9 +846,9 @@ void ProcessParameterExpressions(
// parameters are available for use in the default initialization
// expressions of later parameters.
auto restorer{foldingContext.WithPDTInstance(spec)};
for (const Symbol *symbol : paramDecls) {
const SourceName &name{symbol->name()};
const TypeParamDetails &details{symbol->get<TypeParamDetails>()};
for (const Symbol &symbol : paramDecls) {
const SourceName &name{symbol.name()};
const TypeParamDetails &details{symbol.get<TypeParamDetails>()};
MaybeIntExpr expr;
ParamValue *paramValue{spec.FindParameter(name)};
if (paramValue == nullptr) {
@ -864,7 +861,7 @@ void ProcessParameterExpressions(
paramValue->SetExplicit(std::move(*expr));
} else {
spec.AddParamValue(
symbol->name(), ParamValue{std::move(*expr), details.attr()});
symbol.name(), ParamValue{std::move(*expr), details.attr()});
}
}
}
@ -959,57 +956,46 @@ typename ComponentIterator<componentKind>::const_iterator
ComponentIterator<componentKind>::const_iterator::Create(
const DerivedTypeSpec &derived) {
const_iterator it{};
const std::list<SourceName> &names{
derived.typeSymbol().get<DerivedTypeDetails>().componentNames()};
if (names.empty()) {
return it; // end iterator
} else {
it.componentPath_.emplace_back(
ComponentPathNode{nullptr, &derived, names.cbegin()});
it.Increment(); // search first relevant component (may be the end)
return it;
}
it.componentPath_.emplace_back(derived);
it.Increment(); // cue up first relevant component, if any
return it;
}
template<ComponentKind componentKind>
bool ComponentIterator<componentKind>::const_iterator::PlanComponentTraversal(
const Symbol &component) {
const DerivedTypeSpec *
ComponentIterator<componentKind>::const_iterator::PlanComponentTraversal(
const Symbol &component) const {
if (const auto *details{component.detailsIf<ObjectEntityDetails>()}) {
const DeclTypeSpec *type{details->type()};
if (!type) {
return false; // error recovery
} else if (const auto *derived{type->AsDerived()}) {
bool traverse{false};
if constexpr (componentKind == ComponentKind::Ordered) {
// Order Component (only visit parents)
traverse = component.test(Symbol::Flag::ParentComp);
} else if constexpr (componentKind == ComponentKind::Direct) {
traverse = !IsAllocatableOrPointer(component);
} else if constexpr (componentKind == ComponentKind::Ultimate) {
traverse = !IsAllocatableOrPointer(component);
} else if constexpr (componentKind == ComponentKind::Potential) {
traverse = !IsPointer(component);
}
if (traverse) {
const Symbol *newTypeSymbol{&derived->typeSymbol()};
// Avoid infinite loop if the type is already part of the types
// being visited. It is possible to have "loops in type" because
// C744 does not forbid to use not yet declared type for
// ALLOCATABLE or POINTER components.
for (const auto &node : componentPath_) {
if (newTypeSymbol == &GetTypeSymbol(node)) {
return false;
}
if (const DeclTypeSpec * type{details->type()}) {
if (const auto *derived{type->AsDerived()}) {
bool traverse{false};
if constexpr (componentKind == ComponentKind::Ordered) {
// Order Component (only visit parents)
traverse = component.test(Symbol::Flag::ParentComp);
} else if constexpr (componentKind == ComponentKind::Direct) {
traverse = !IsAllocatableOrPointer(component);
} else if constexpr (componentKind == ComponentKind::Ultimate) {
traverse = !IsAllocatableOrPointer(component);
} else if constexpr (componentKind == ComponentKind::Potential) {
traverse = !IsPointer(component);
}
if (traverse) {
const Symbol &newTypeSymbol{derived->typeSymbol()};
// Avoid infinite loop if the type is already part of the types
// being visited. It is possible to have "loops in type" because
// C744 does not forbid to use not yet declared type for
// ALLOCATABLE or POINTER components.
for (const auto &node : componentPath_) {
if (&newTypeSymbol == &node.GetTypeSymbol()) {
return nullptr;
}
}
return derived;
}
componentPath_.emplace_back(ComponentPathNode{nullptr, derived,
newTypeSymbol->get<DerivedTypeDetails>()
.componentNames()
.cbegin()});
return true;
}
} // intrinsic & unlimited polymorphic not traversable
}
return false;
return nullptr;
}
template<ComponentKind componentKind>
@ -1032,81 +1018,46 @@ static bool StopAtComponentPre(const Symbol &component) {
template<ComponentKind componentKind>
static bool StopAtComponentPost(const Symbol &component) {
if constexpr (componentKind == ComponentKind::Ordered) {
return component.test(Symbol::Flag::ParentComp);
} else {
return false;
}
return componentKind == ComponentKind::Ordered &&
component.test(Symbol::Flag::ParentComp);
}
enum class ComponentVisitState { Resume, Pre, Post };
template<ComponentKind componentKind>
void ComponentIterator<componentKind>::const_iterator::Increment() {
std::int64_t level{static_cast<std::int64_t>(componentPath_.size()) - 1};
// Need to know if this is the first incrementation or if the visit is
// resumed after a user increment.
ComponentVisitState state{
level >= 0 && GetComponentSymbol(componentPath_[level])
? ComponentVisitState::Resume
: ComponentVisitState::Pre};
while (level >= 0) {
bool descend{false};
const Scope &scope{DEREF(GetScope(componentPath_[level]))};
auto &levelIterator{GetIterator(componentPath_[level])};
const auto &levelEndIterator{GetTypeSymbol(componentPath_[level])
.template get<DerivedTypeDetails>()
.componentNames()
.cend()};
while (!descend && levelIterator != levelEndIterator) {
const Symbol *component{GetComponentSymbol(componentPath_[level])};
switch (state) {
case ComponentVisitState::Resume:
if (StopAtComponentPre<componentKind>(DEREF(component))) {
// The symbol was not yet considered for
// traversal.
descend = PlanComponentTraversal(*component);
while (!componentPath_.empty()) {
ComponentPathNode &deepest{componentPath_.back()};
if (deepest.component()) {
if (!deepest.descended()) {
deepest.set_descended(true);
if (const DerivedTypeSpec *
derived{PlanComponentTraversal(*deepest.component())}) {
componentPath_.emplace_back(*derived);
continue;
}
break;
case ComponentVisitState::Pre:
// Search iterator
if (auto iter{scope.find(*levelIterator)}; iter != scope.cend()) {
const Symbol *newComponent{iter->second};
SetComponentSymbol(componentPath_[level], newComponent);
if (StopAtComponentPre<componentKind>(*newComponent)) {
return;
}
descend = PlanComponentTraversal(*newComponent);
if (!descend && StopAtComponentPost<componentKind>(*newComponent)) {
return;
}
}
break;
case ComponentVisitState::Post:
if (StopAtComponentPost<componentKind>(DEREF(component))) {
return;
}
break;
} else if (!deepest.visited()) {
deepest.set_visited(true);
return; // this is the next component to visit, after descending
}
if (descend) {
level++;
} else {
SetComponentSymbol(componentPath_[level], nullptr); // safety
levelIterator++;
}
state = ComponentVisitState::Pre;
}
if (!descend) { // Finished level traversal
auto &nameIterator{deepest.nameIterator()};
if (nameIterator == deepest.nameEnd()) {
componentPath_.pop_back();
--level;
state = ComponentVisitState::Post;
} else {
const Scope &scope{deepest.GetScope()};
auto scopeIter{scope.find(*nameIterator++)};
if (scopeIter != scope.cend()) {
const Symbol &component{*scopeIter->second};
deepest.set_component(component);
deepest.set_descended(false);
if (StopAtComponentPre<componentKind>(component)) {
deepest.set_visited(true);
return; // this is the next component to visit, before descending
} else {
deepest.set_visited(!StopAtComponentPost<componentKind>(component));
}
}
}
}
// iterator reached end of components
}
template<ComponentKind componentKind>
@ -1115,7 +1066,7 @@ ComponentIterator<componentKind>::const_iterator::BuildResultDesignatorName()
const {
std::string designator{""};
for (const auto &node : componentPath_) {
designator += "%" + GetComponentSymbol(node)->name().ToString();
designator += "%" + DEREF(node.component()).name().ToString();
}
return designator;
}
@ -1129,23 +1080,22 @@ UltimateComponentIterator::const_iterator FindCoarrayUltimateComponent(
const DerivedTypeSpec &derived) {
UltimateComponentIterator ultimates{derived};
return std::find_if(ultimates.begin(), ultimates.end(),
[](const Symbol *component) { return DEREF(component).Corank() > 0; });
[](const Symbol &component) { return component.Corank() > 0; });
}
UltimateComponentIterator::const_iterator FindPointerUltimateComponent(
const DerivedTypeSpec &derived) {
UltimateComponentIterator ultimates{derived};
return std::find_if(ultimates.begin(), ultimates.end(),
[](const Symbol *component) { return IsPointer(DEREF(component)); });
[](const Symbol &component) { return IsPointer(component); });
}
PotentialComponentIterator::const_iterator FindEventOrLockPotentialComponent(
const DerivedTypeSpec &derived) {
PotentialComponentIterator potentials{derived};
return std::find_if(
potentials.begin(), potentials.end(), [](const Symbol *component) {
if (const auto *details{
DEREF(component).detailsIf<ObjectEntityDetails>()}) {
potentials.begin(), potentials.end(), [](const Symbol &component) {
if (const auto *details{component.detailsIf<ObjectEntityDetails>()}) {
const DeclTypeSpec *type{details->type()};
return type && IsEventTypeOrLockType(type->AsDerived());
}
@ -1157,10 +1107,10 @@ const Symbol *FindUltimateComponent(const DerivedTypeSpec &derived,
const std::function<bool(const Symbol &)> &predicate) {
UltimateComponentIterator ultimates{derived};
if (auto it{std::find_if(ultimates.begin(), ultimates.end(),
[&predicate](const Symbol *component) -> bool {
return predicate(DEREF(component));
[&predicate](const Symbol &component) -> bool {
return predicate(component);
})}) {
return *it;
return &*it;
}
return nullptr;
}
@ -1184,13 +1134,12 @@ const Symbol *FindImmediateComponent(const DerivedTypeSpec &type,
if (const Scope * scope{type.scope()}) {
const Symbol *parent{nullptr};
for (const auto &pair : *scope) {
if (const Symbol * symbol{pair.second}) {
if (predicate(*symbol)) {
return symbol;
}
if (symbol->test(Symbol::Flag::ParentComp)) {
parent = symbol;
}
const Symbol *symbol{&*pair.second};
if (predicate(*symbol)) {
return symbol;
}
if (symbol->test(Symbol::Flag::ParentComp)) {
parent = symbol;
}
}
if (parent != nullptr) {

View File

@ -238,7 +238,6 @@ template<typename T> std::optional<std::int64_t> GetIntValue(const T &x) {
// The kind of component is a template argument of the iterator factory
// ComponentIterator.
//
//
// - Ordered components are the components from the component order defined
// in 7.5.4.7, except that the parent component IS added between the parent
// component order and the components in order of declaration.
@ -300,10 +299,10 @@ public:
class const_iterator {
public:
using iterator_category = std::forward_iterator_tag;
using value_type = const Symbol *;
using value_type = SymbolRef;
using difference_type = void;
using pointer = const value_type *;
using reference = const value_type &;
using pointer = const Symbol *;
using reference = const Symbol &;
static const_iterator Create(const DerivedTypeSpec &);
@ -318,8 +317,9 @@ public:
}
reference operator*() const {
CHECK(!componentPath_.empty());
return std::get<0>(componentPath_.back());
return DEREF(componentPath_.back().component());
}
pointer operator->() const { return &**this; }
bool operator==(const const_iterator &other) const {
return componentPath_ == other.componentPath_;
@ -330,44 +330,61 @@ public:
// bool() operator indicates if the iterator can be dereferenced without
// having to check against an end() iterator.
explicit operator bool() const {
return !componentPath_.empty() &&
GetComponentSymbol(componentPath_.back());
}
explicit operator bool() const { return !componentPath_.empty(); }
// Builds a designator name of the referenced component for messages.
// The designator helps when the component referred to by the iterator
// may be "buried" into other components. This gives the full
// path inside the iterated derived type: e.g "%a%b%c%ultimate"
// when (*it)->name() only gives "ultimate". Parent components are
// when it->name() only gives "ultimate". Parent components are
// part of the path for clarity, even though they could be
// skipped.
std::string BuildResultDesignatorName() const;
private:
using name_iterator = typename std::list<SourceName>::const_iterator;
using ComponentPathNode =
std::tuple<const Symbol *, const DerivedTypeSpec *, name_iterator>;
using ComponentPath = std::vector<ComponentPathNode>;
static const Symbol *GetComponentSymbol(const ComponentPathNode &node) {
return std::get<0>(node);
}
static void SetComponentSymbol(ComponentPathNode &node, const Symbol *sym) {
std::get<0>(node) = sym;
}
static const Symbol &GetTypeSymbol(const ComponentPathNode &node) {
return std::get<1>(node)->typeSymbol();
}
static const Scope *GetScope(const ComponentPathNode &node) {
return std::get<1>(node)->scope();
}
static name_iterator &GetIterator(ComponentPathNode &node) {
return std::get<2>(node);
}
bool PlanComponentTraversal(const Symbol &component);
class ComponentPathNode {
public:
explicit ComponentPathNode(const DerivedTypeSpec &derived)
: derived_{derived} {
const std::list<SourceName> &nameList{
derived.typeSymbol().get<DerivedTypeDetails>().componentNames()};
nameIterator_ = nameList.cbegin();
nameEnd_ = nameList.cend();
}
const Symbol *component() const { return component_; }
void set_component(const Symbol &component) { component_ = &component; }
bool visited() const { return visited_; }
void set_visited(bool yes) { visited_ = yes; }
bool descended() const { return descended_; }
void set_descended(bool yes) { descended_ = yes; }
name_iterator &nameIterator() { return nameIterator_; }
name_iterator nameEnd() { return nameEnd_; }
const Symbol &GetTypeSymbol() const { return derived_->typeSymbol(); }
const Scope &GetScope() const { return DEREF(derived_->scope()); }
bool operator==(const ComponentPathNode &that) const {
return &*derived_ == &*that.derived_ &&
nameIterator_ == that.nameIterator_ &&
component_ == that.component_;
}
private:
common::Reference<const DerivedTypeSpec> derived_;
name_iterator nameEnd_;
name_iterator nameIterator_;
const Symbol *component_{nullptr}; // until Increment()
bool visited_{false};
bool descended_{false};
};
const DerivedTypeSpec *PlanComponentTraversal(
const Symbol &component) const;
// Advances to the next relevant symbol, if any. Afterwards, the
// iterator will either be at its end or contain no null component().
void Increment();
ComponentPath componentPath_;
std::vector<ComponentPathNode> componentPath_;
};
const_iterator begin() { return cbegin(); }