forked from OSchip/llvm-project
[flang] Support coarrays in name resolution
A coarray is represented as a `Symbol` with `ObjectEntityDetails` that has a non-empty coshape. The coshape is represented using the same type (`ArrayShape`) as the shape is, so the fact that it is a coshape is determined from context. Move code for analyzing shapes to `resolve-names-utils.cc` and generalize it for coshapes. In `symbol.cc` add dumping of coshapes. Simplify some of the functions by adding some `Dump*` functions to handle common cases. In `mod-file.cc` generalize the code for writing shapes to also write coshapes. Fix a bug in `PutShapeSpec()`. Original-commit: flang-compiler/f18@9d2482c40c Reviewed-on: https://github.com/flang-compiler/f18/pull/384 Tree-same-pre-rewrite: false
This commit is contained in:
parent
924c38356c
commit
b7efa8b77b
|
@ -424,7 +424,7 @@ void PutEntity(std::ostream &os, const Symbol &symbol) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PutShapeSpec(std::ostream &os, const ShapeSpec &x) {
|
void PutShapeSpec(std::ostream &os, const ShapeSpec &x) {
|
||||||
if (x.ubound().isAssumed()) {
|
if (x.lbound().isAssumed()) {
|
||||||
CHECK(x.ubound().isAssumed());
|
CHECK(x.ubound().isAssumed());
|
||||||
os << "..";
|
os << "..";
|
||||||
} else {
|
} else {
|
||||||
|
@ -437,9 +437,9 @@ void PutShapeSpec(std::ostream &os, const ShapeSpec &x) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void PutShape(std::ostream &os, const ArraySpec &shape) {
|
void PutShape(std::ostream &os, const ArraySpec &shape, char open, char close) {
|
||||||
if (!shape.empty()) {
|
if (!shape.empty()) {
|
||||||
os << '(';
|
os << open;
|
||||||
bool first{true};
|
bool first{true};
|
||||||
for (const auto &shapeSpec : shape) {
|
for (const auto &shapeSpec : shape) {
|
||||||
if (first) {
|
if (first) {
|
||||||
|
@ -449,7 +449,7 @@ void PutShape(std::ostream &os, const ArraySpec &shape) {
|
||||||
}
|
}
|
||||||
PutShapeSpec(os, shapeSpec);
|
PutShapeSpec(os, shapeSpec);
|
||||||
}
|
}
|
||||||
os << ')';
|
os << close;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -460,7 +460,8 @@ void PutObjectEntity(std::ostream &os, const Symbol &symbol) {
|
||||||
CHECK(type);
|
CHECK(type);
|
||||||
PutLower(os, *type);
|
PutLower(os, *type);
|
||||||
});
|
});
|
||||||
PutShape(os, details.shape());
|
PutShape(os, details.shape(), '(', ')');
|
||||||
|
PutShape(os, details.coshape(), '[', ']');
|
||||||
PutInit(os, details.init());
|
PutInit(os, details.init());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -816,6 +817,10 @@ void SubprogramSymbolCollector::DoSymbol(const Symbol &symbol) {
|
||||||
DoBound(spec.lbound());
|
DoBound(spec.lbound());
|
||||||
DoBound(spec.ubound());
|
DoBound(spec.ubound());
|
||||||
}
|
}
|
||||||
|
for (const ShapeSpec &spec : details.coshape()) {
|
||||||
|
DoBound(spec.lbound());
|
||||||
|
DoBound(spec.ubound());
|
||||||
|
}
|
||||||
if (const Symbol * commonBlock{details.commonBlock()}) {
|
if (const Symbol * commonBlock{details.commonBlock()}) {
|
||||||
DoSymbol(*commonBlock);
|
DoSymbol(*commonBlock);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,10 +13,12 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include "resolve-names-utils.h"
|
#include "resolve-names-utils.h"
|
||||||
|
#include "expression.h"
|
||||||
#include "semantics.h"
|
#include "semantics.h"
|
||||||
#include "symbol.h"
|
|
||||||
#include "type.h"
|
|
||||||
#include "../common/idioms.h"
|
#include "../common/idioms.h"
|
||||||
|
#include "../evaluate/fold.h"
|
||||||
|
#include "../evaluate/tools.h"
|
||||||
|
#include "../evaluate/type.h"
|
||||||
#include "../parser/char-block.h"
|
#include "../parser/char-block.h"
|
||||||
#include "../parser/features.h"
|
#include "../parser/features.h"
|
||||||
#include "../parser/parse-tree.h"
|
#include "../parser/parse-tree.h"
|
||||||
|
@ -163,4 +165,114 @@ static GenericKind MapIntrinsicOperator(IntrinsicOperator op) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ArraySpecAnalyzer {
|
||||||
|
public:
|
||||||
|
ArraySpecAnalyzer(ArraySpec &arraySpec, SemanticsContext &context)
|
||||||
|
: context_{context}, arraySpec_{arraySpec} {
|
||||||
|
CHECK(arraySpec.empty());
|
||||||
|
}
|
||||||
|
void Analyze(const parser::ArraySpec &);
|
||||||
|
void Analyze(const parser::CoarraySpec &);
|
||||||
|
|
||||||
|
private:
|
||||||
|
SemanticsContext &context_;
|
||||||
|
ArraySpec &arraySpec_;
|
||||||
|
|
||||||
|
template<typename T> void Analyze(const std::list<T> &list) {
|
||||||
|
for (const auto &elem : list) {
|
||||||
|
Analyze(elem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Analyze(const parser::AssumedShapeSpec &);
|
||||||
|
void Analyze(const parser::ExplicitShapeSpec &);
|
||||||
|
void Analyze(const parser::AssumedImpliedSpec &);
|
||||||
|
void Analyze(const parser::AssumedRankSpec &);
|
||||||
|
void MakeExplicit(const std::optional<parser::SpecificationExpr> &,
|
||||||
|
const parser::SpecificationExpr &);
|
||||||
|
void MakeImplied(const std::optional<parser::SpecificationExpr> &);
|
||||||
|
void MakeDeferred(int);
|
||||||
|
Bound GetBound(const std::optional<parser::SpecificationExpr> &);
|
||||||
|
Bound GetBound(const parser::SpecificationExpr &);
|
||||||
|
};
|
||||||
|
|
||||||
|
void AnalyzeArraySpec(ArraySpec &result, SemanticsContext &context,
|
||||||
|
const parser::ArraySpec &arraySpec) {
|
||||||
|
ArraySpecAnalyzer{result, context}.Analyze(arraySpec);
|
||||||
|
}
|
||||||
|
void AnalyzeCoarraySpec(ArraySpec &result, SemanticsContext &context,
|
||||||
|
const parser::CoarraySpec &coarraySpec) {
|
||||||
|
ArraySpecAnalyzer{result, context}.Analyze(coarraySpec);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArraySpecAnalyzer::Analyze(const parser::ArraySpec &x) {
|
||||||
|
std::visit(
|
||||||
|
common::visitors{
|
||||||
|
[&](const parser::DeferredShapeSpecList &y) { MakeDeferred(y.v); },
|
||||||
|
[&](const parser::AssumedSizeSpec &y) {
|
||||||
|
Analyze(std::get<std::list<parser::ExplicitShapeSpec>>(y.t));
|
||||||
|
Analyze(std::get<parser::AssumedImpliedSpec>(y.t));
|
||||||
|
},
|
||||||
|
[&](const parser::ImpliedShapeSpec &y) { Analyze(y.v); },
|
||||||
|
[&](const auto &y) { Analyze(y); },
|
||||||
|
},
|
||||||
|
x.u);
|
||||||
|
}
|
||||||
|
void ArraySpecAnalyzer::Analyze(const parser::CoarraySpec &x) {
|
||||||
|
std::visit(
|
||||||
|
common::visitors{
|
||||||
|
[&](const parser::DeferredCoshapeSpecList &y) { MakeDeferred(y.v); },
|
||||||
|
[&](const parser::ExplicitCoshapeSpec &y) {
|
||||||
|
Analyze(std::get<std::list<parser::ExplicitShapeSpec>>(y.t));
|
||||||
|
MakeImplied(
|
||||||
|
std::get<std::optional<parser::SpecificationExpr>>(y.t));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
x.u);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArraySpecAnalyzer::Analyze(const parser::AssumedShapeSpec &x) {
|
||||||
|
arraySpec_.push_back(ShapeSpec::MakeAssumed(GetBound(x.v)));
|
||||||
|
}
|
||||||
|
void ArraySpecAnalyzer::Analyze(const parser::ExplicitShapeSpec &x) {
|
||||||
|
MakeExplicit(std::get<std::optional<parser::SpecificationExpr>>(x.t),
|
||||||
|
std::get<parser::SpecificationExpr>(x.t));
|
||||||
|
}
|
||||||
|
void ArraySpecAnalyzer::Analyze(const parser::AssumedImpliedSpec &x) {
|
||||||
|
MakeImplied(x.v);
|
||||||
|
}
|
||||||
|
void ArraySpecAnalyzer::Analyze(const parser::AssumedRankSpec &) {
|
||||||
|
arraySpec_.push_back(ShapeSpec::MakeAssumedRank());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArraySpecAnalyzer::MakeExplicit(
|
||||||
|
const std::optional<parser::SpecificationExpr> &lb,
|
||||||
|
const parser::SpecificationExpr &ub) {
|
||||||
|
arraySpec_.push_back(ShapeSpec::MakeExplicit(GetBound(lb), GetBound(ub)));
|
||||||
|
}
|
||||||
|
void ArraySpecAnalyzer::MakeImplied(
|
||||||
|
const std::optional<parser::SpecificationExpr> &lb) {
|
||||||
|
arraySpec_.push_back(ShapeSpec::MakeImplied(GetBound(lb)));
|
||||||
|
}
|
||||||
|
void ArraySpecAnalyzer::MakeDeferred(int n) {
|
||||||
|
for (int i = 0; i < n; ++i) {
|
||||||
|
arraySpec_.push_back(ShapeSpec::MakeDeferred());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Bound ArraySpecAnalyzer::GetBound(
|
||||||
|
const std::optional<parser::SpecificationExpr> &x) {
|
||||||
|
return x ? GetBound(*x) : Bound{1};
|
||||||
|
}
|
||||||
|
Bound ArraySpecAnalyzer::GetBound(const parser::SpecificationExpr &x) {
|
||||||
|
MaybeSubscriptIntExpr expr;
|
||||||
|
if (MaybeExpr maybeExpr{AnalyzeExpr(context_, x.v)}) {
|
||||||
|
if (auto *intExpr{evaluate::UnwrapExpr<SomeIntExpr>(*maybeExpr)}) {
|
||||||
|
expr = evaluate::Fold(context_.foldingContext(),
|
||||||
|
evaluate::ConvertToType<evaluate::SubscriptInteger>(
|
||||||
|
std::move(*intExpr)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Bound{std::move(expr)};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,10 +18,13 @@
|
||||||
// Utility functions and class for use in resolve-names.cc.
|
// Utility functions and class for use in resolve-names.cc.
|
||||||
|
|
||||||
#include "symbol.h"
|
#include "symbol.h"
|
||||||
|
#include "type.h"
|
||||||
#include "../parser/message.h"
|
#include "../parser/message.h"
|
||||||
|
|
||||||
namespace Fortran::parser {
|
namespace Fortran::parser {
|
||||||
class CharBlock;
|
class CharBlock;
|
||||||
|
struct ArraySpec;
|
||||||
|
struct CoarraySpec;
|
||||||
struct DefinedOpName;
|
struct DefinedOpName;
|
||||||
struct GenericSpec;
|
struct GenericSpec;
|
||||||
struct Name;
|
struct Name;
|
||||||
|
@ -30,6 +33,7 @@ struct Name;
|
||||||
namespace Fortran::semantics {
|
namespace Fortran::semantics {
|
||||||
|
|
||||||
using SourceName = parser::CharBlock;
|
using SourceName = parser::CharBlock;
|
||||||
|
class SemanticsContext;
|
||||||
|
|
||||||
// Record that a Name has been resolved to a Symbol
|
// Record that a Name has been resolved to a Symbol
|
||||||
Symbol &Resolve(const parser::Name &, Symbol &);
|
Symbol &Resolve(const parser::Name &, Symbol &);
|
||||||
|
@ -64,6 +68,12 @@ private:
|
||||||
void Analyze(const parser::GenericSpec &);
|
void Analyze(const parser::GenericSpec &);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Analyze a parser::ArraySpec or parser::CoarraySpec into the provide ArraySpec
|
||||||
|
void AnalyzeArraySpec(
|
||||||
|
ArraySpec &, SemanticsContext &, const parser::ArraySpec &);
|
||||||
|
void AnalyzeCoarraySpec(
|
||||||
|
ArraySpec &, SemanticsContext &, const parser::CoarraySpec &);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // FORTRAN_SEMANTICS_RESOLVE_NAMES_H_
|
#endif // FORTRAN_SEMANTICS_RESOLVE_NAMES_H_
|
||||||
|
|
|
@ -353,30 +353,29 @@ private:
|
||||||
// 6. TODO: BasedPointerStmt
|
// 6. TODO: BasedPointerStmt
|
||||||
class ArraySpecVisitor : public virtual BaseVisitor {
|
class ArraySpecVisitor : public virtual BaseVisitor {
|
||||||
public:
|
public:
|
||||||
bool Pre(const parser::ArraySpec &);
|
void Post(const parser::ArraySpec &);
|
||||||
|
void Post(const parser::CoarraySpec &);
|
||||||
void Post(const parser::AttrSpec &) { PostAttrSpec(); }
|
void Post(const parser::AttrSpec &) { PostAttrSpec(); }
|
||||||
void Post(const parser::ComponentAttrSpec &) { PostAttrSpec(); }
|
void Post(const parser::ComponentAttrSpec &) { PostAttrSpec(); }
|
||||||
void Post(const parser::DeferredShapeSpecList &);
|
|
||||||
void Post(const parser::AssumedShapeSpec &);
|
|
||||||
void Post(const parser::ExplicitShapeSpec &);
|
|
||||||
void Post(const parser::AssumedImpliedSpec &);
|
|
||||||
void Post(const parser::AssumedRankSpec &);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const ArraySpec &arraySpec();
|
const ArraySpec &arraySpec();
|
||||||
|
const ArraySpec &coarraySpec();
|
||||||
void BeginArraySpec();
|
void BeginArraySpec();
|
||||||
void EndArraySpec();
|
void EndArraySpec();
|
||||||
void ClearArraySpec() { arraySpec_.clear(); }
|
void ClearArraySpec() { arraySpec_.clear(); }
|
||||||
|
void ClearCoarraySpec() { coarraySpec_.clear(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// arraySpec_ is populated by any ArraySpec
|
// arraySpec_/coarraySpec_ are populated from any ArraySpec/CoarraySpec
|
||||||
ArraySpec arraySpec_;
|
ArraySpec arraySpec_;
|
||||||
|
ArraySpec coarraySpec_;
|
||||||
// When an ArraySpec is under an AttrSpec or ComponentAttrSpec, it is moved
|
// When an ArraySpec is under an AttrSpec or ComponentAttrSpec, it is moved
|
||||||
// into attrArraySpec_
|
// into attrArraySpec_
|
||||||
ArraySpec attrArraySpec_;
|
ArraySpec attrArraySpec_;
|
||||||
|
ArraySpec attrCoarraySpec_;
|
||||||
|
|
||||||
void PostAttrSpec();
|
void PostAttrSpec();
|
||||||
Bound GetBound(const parser::SpecificationExpr &);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Manage a stack of Scopes
|
// Manage a stack of Scopes
|
||||||
|
@ -649,7 +648,6 @@ class DeclarationVisitor : public ArraySpecVisitor,
|
||||||
public virtual ScopeHandler {
|
public virtual ScopeHandler {
|
||||||
public:
|
public:
|
||||||
using ArraySpecVisitor::Post;
|
using ArraySpecVisitor::Post;
|
||||||
using ArraySpecVisitor::Pre;
|
|
||||||
using ScopeHandler::Post;
|
using ScopeHandler::Post;
|
||||||
using ScopeHandler::Pre;
|
using ScopeHandler::Pre;
|
||||||
|
|
||||||
|
@ -681,6 +679,7 @@ public:
|
||||||
}
|
}
|
||||||
void Post(const parser::TargetStmt &) { objectDeclAttr_ = std::nullopt; }
|
void Post(const parser::TargetStmt &) { objectDeclAttr_ = std::nullopt; }
|
||||||
void Post(const parser::DimensionStmt::Declaration &);
|
void Post(const parser::DimensionStmt::Declaration &);
|
||||||
|
void Post(const parser::CodimensionDecl &);
|
||||||
bool Pre(const parser::TypeDeclarationStmt &) { return BeginDecl(); }
|
bool Pre(const parser::TypeDeclarationStmt &) { return BeginDecl(); }
|
||||||
void Post(const parser::TypeDeclarationStmt &) { EndDecl(); }
|
void Post(const parser::TypeDeclarationStmt &) { EndDecl(); }
|
||||||
void Post(const parser::IntegerTypeSpec &);
|
void Post(const parser::IntegerTypeSpec &);
|
||||||
|
@ -952,7 +951,6 @@ class ResolveNamesVisitor : public virtual ScopeHandler,
|
||||||
public ConstructVisitor {
|
public ConstructVisitor {
|
||||||
public:
|
public:
|
||||||
using ArraySpecVisitor::Post;
|
using ArraySpecVisitor::Post;
|
||||||
using ArraySpecVisitor::Pre;
|
|
||||||
using ConstructVisitor::Post;
|
using ConstructVisitor::Post;
|
||||||
using ConstructVisitor::Pre;
|
using ConstructVisitor::Pre;
|
||||||
using DeclarationVisitor::Post;
|
using DeclarationVisitor::Post;
|
||||||
|
@ -1420,65 +1418,42 @@ bool ImplicitRulesVisitor::HandleImplicitNone(
|
||||||
|
|
||||||
// ArraySpecVisitor implementation
|
// ArraySpecVisitor implementation
|
||||||
|
|
||||||
bool ArraySpecVisitor::Pre(const parser::ArraySpec &x) {
|
void ArraySpecVisitor::Post(const parser::ArraySpec &x) {
|
||||||
CHECK(arraySpec_.empty());
|
AnalyzeArraySpec(arraySpec_, context(), x);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
void ArraySpecVisitor::Post(const parser::CoarraySpec &x) {
|
||||||
void ArraySpecVisitor::Post(const parser::DeferredShapeSpecList &x) {
|
AnalyzeCoarraySpec(coarraySpec_, context(), x);
|
||||||
for (int i = 0; i < x.v; ++i) {
|
|
||||||
arraySpec_.push_back(ShapeSpec::MakeDeferred());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ArraySpecVisitor::Post(const parser::AssumedShapeSpec &x) {
|
|
||||||
const auto &lb{x.v};
|
|
||||||
arraySpec_.push_back(
|
|
||||||
lb ? ShapeSpec::MakeAssumed(GetBound(*lb)) : ShapeSpec::MakeAssumed());
|
|
||||||
}
|
|
||||||
|
|
||||||
void ArraySpecVisitor::Post(const parser::ExplicitShapeSpec &x) {
|
|
||||||
auto &&ub{GetBound(std::get<parser::SpecificationExpr>(x.t))};
|
|
||||||
if (const auto &lb{std::get<std::optional<parser::SpecificationExpr>>(x.t)}) {
|
|
||||||
arraySpec_.push_back(ShapeSpec::MakeExplicit(GetBound(*lb), std::move(ub)));
|
|
||||||
} else {
|
|
||||||
arraySpec_.push_back(ShapeSpec::MakeExplicit(Bound{1}, std::move(ub)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ArraySpecVisitor::Post(const parser::AssumedImpliedSpec &x) {
|
|
||||||
const auto &lb{x.v};
|
|
||||||
arraySpec_.push_back(
|
|
||||||
lb ? ShapeSpec::MakeImplied(GetBound(*lb)) : ShapeSpec::MakeImplied());
|
|
||||||
}
|
|
||||||
|
|
||||||
void ArraySpecVisitor::Post(const parser::AssumedRankSpec &) {
|
|
||||||
arraySpec_.push_back(ShapeSpec::MakeAssumedRank());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ArraySpec &ArraySpecVisitor::arraySpec() {
|
const ArraySpec &ArraySpecVisitor::arraySpec() {
|
||||||
return !arraySpec_.empty() ? arraySpec_ : attrArraySpec_;
|
return !arraySpec_.empty() ? arraySpec_ : attrArraySpec_;
|
||||||
}
|
}
|
||||||
|
const ArraySpec &ArraySpecVisitor::coarraySpec() {
|
||||||
|
return !coarraySpec_.empty() ? coarraySpec_ : attrCoarraySpec_;
|
||||||
|
}
|
||||||
void ArraySpecVisitor::BeginArraySpec() {
|
void ArraySpecVisitor::BeginArraySpec() {
|
||||||
CHECK(arraySpec_.empty());
|
CHECK(arraySpec_.empty());
|
||||||
|
CHECK(coarraySpec_.empty());
|
||||||
CHECK(attrArraySpec_.empty());
|
CHECK(attrArraySpec_.empty());
|
||||||
|
CHECK(attrCoarraySpec_.empty());
|
||||||
}
|
}
|
||||||
void ArraySpecVisitor::EndArraySpec() {
|
void ArraySpecVisitor::EndArraySpec() {
|
||||||
CHECK(arraySpec_.empty());
|
CHECK(arraySpec_.empty());
|
||||||
|
CHECK(coarraySpec_.empty());
|
||||||
attrArraySpec_.clear();
|
attrArraySpec_.clear();
|
||||||
|
attrCoarraySpec_.clear();
|
||||||
}
|
}
|
||||||
void ArraySpecVisitor::PostAttrSpec() {
|
void ArraySpecVisitor::PostAttrSpec() {
|
||||||
|
// Save dimension/codimension from attrs so we can process array/coarray-spec
|
||||||
|
// on the entity-decl
|
||||||
if (!arraySpec_.empty()) {
|
if (!arraySpec_.empty()) {
|
||||||
// Example: integer, dimension(<1>) :: x(<2>)
|
|
||||||
// This saves <1> in attrArraySpec_ so we can process <2> into arraySpec_
|
|
||||||
CHECK(attrArraySpec_.empty());
|
CHECK(attrArraySpec_.empty());
|
||||||
attrArraySpec_.splice(attrArraySpec_.cbegin(), arraySpec_);
|
attrArraySpec_.splice(attrArraySpec_.cbegin(), arraySpec_);
|
||||||
CHECK(arraySpec_.empty());
|
|
||||||
}
|
}
|
||||||
}
|
if (!coarraySpec_.empty()) {
|
||||||
|
CHECK(attrCoarraySpec_.empty());
|
||||||
Bound ArraySpecVisitor::GetBound(const parser::SpecificationExpr &x) {
|
attrCoarraySpec_.splice(attrCoarraySpec_.cbegin(), coarraySpec_);
|
||||||
return Bound{EvaluateSubscriptIntExpr(x.v)};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScopeHandler implementation
|
// ScopeHandler implementation
|
||||||
|
@ -2554,6 +2529,11 @@ void DeclarationVisitor::Post(const parser::DimensionStmt::Declaration &x) {
|
||||||
const auto &name{std::get<parser::Name>(x.t)};
|
const auto &name{std::get<parser::Name>(x.t)};
|
||||||
DeclareObjectEntity(name, Attrs{});
|
DeclareObjectEntity(name, Attrs{});
|
||||||
}
|
}
|
||||||
|
void DeclarationVisitor::Post(const parser::CodimensionDecl &x) {
|
||||||
|
const auto &name{std::get<parser::Name>(x.t)};
|
||||||
|
DeclareObjectEntity(name, Attrs{});
|
||||||
|
}
|
||||||
|
//TODO: ChangeTeamStmt also uses CodimensionDecl
|
||||||
|
|
||||||
void DeclarationVisitor::Post(const parser::EntityDecl &x) {
|
void DeclarationVisitor::Post(const parser::EntityDecl &x) {
|
||||||
// TODO: may be under StructureStmt
|
// TODO: may be under StructureStmt
|
||||||
|
@ -2703,7 +2683,7 @@ void DeclarationVisitor::Post(const parser::ObjectDecl &x) {
|
||||||
// Declare an entity not yet known to be an object or proc.
|
// Declare an entity not yet known to be an object or proc.
|
||||||
Symbol &DeclarationVisitor::DeclareUnknownEntity(
|
Symbol &DeclarationVisitor::DeclareUnknownEntity(
|
||||||
const parser::Name &name, Attrs attrs) {
|
const parser::Name &name, Attrs attrs) {
|
||||||
if (!arraySpec().empty()) {
|
if (!arraySpec().empty() || !coarraySpec().empty()) {
|
||||||
return DeclareObjectEntity(name, attrs);
|
return DeclareObjectEntity(name, attrs);
|
||||||
} else {
|
} else {
|
||||||
Symbol &symbol{DeclareEntity<EntityDetails>(name, attrs)};
|
Symbol &symbol{DeclareEntity<EntityDetails>(name, attrs)};
|
||||||
|
@ -2752,6 +2732,15 @@ Symbol &DeclarationVisitor::DeclareObjectEntity(
|
||||||
}
|
}
|
||||||
ClearArraySpec();
|
ClearArraySpec();
|
||||||
}
|
}
|
||||||
|
if (!coarraySpec().empty()) {
|
||||||
|
if (details->IsCoarray()) {
|
||||||
|
Say(name,
|
||||||
|
"The codimensions of '%s' have already been declared"_err_en_US);
|
||||||
|
} else {
|
||||||
|
details->set_coshape(coarraySpec());
|
||||||
|
}
|
||||||
|
ClearCoarraySpec();
|
||||||
|
}
|
||||||
SetBindNameOn(symbol);
|
SetBindNameOn(symbol);
|
||||||
}
|
}
|
||||||
return symbol;
|
return symbol;
|
||||||
|
@ -3110,6 +3099,7 @@ void DeclarationVisitor::Post(const parser::ComponentDecl &x) {
|
||||||
currScope().symbol()->get<DerivedTypeDetails>().add_component(symbol);
|
currScope().symbol()->get<DerivedTypeDetails>().add_component(symbol);
|
||||||
}
|
}
|
||||||
ClearArraySpec();
|
ClearArraySpec();
|
||||||
|
ClearCoarraySpec();
|
||||||
}
|
}
|
||||||
bool DeclarationVisitor::Pre(const parser::ProcedureDeclarationStmt &) {
|
bool DeclarationVisitor::Pre(const parser::ProcedureDeclarationStmt &) {
|
||||||
CHECK(!interfaceName_);
|
CHECK(!interfaceName_);
|
||||||
|
@ -3414,6 +3404,7 @@ void DeclarationVisitor::Post(const parser::CommonBlockObject &x) {
|
||||||
const auto &name{std::get<parser::Name>(x.t)};
|
const auto &name{std::get<parser::Name>(x.t)};
|
||||||
auto &symbol{DeclareObjectEntity(name, Attrs{})};
|
auto &symbol{DeclareObjectEntity(name, Attrs{})};
|
||||||
ClearArraySpec();
|
ClearArraySpec();
|
||||||
|
ClearCoarraySpec();
|
||||||
auto *details{symbol.detailsIf<ObjectEntityDetails>()};
|
auto *details{symbol.detailsIf<ObjectEntityDetails>()};
|
||||||
if (!details) {
|
if (!details) {
|
||||||
return; // error was reported
|
return; // error was reported
|
||||||
|
|
|
@ -26,6 +26,52 @@ std::ostream &operator<<(std::ostream &os, const parser::CharBlock &name) {
|
||||||
return os << name.ToString();
|
return os << name.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static void DumpOptional(
|
||||||
|
std::ostream &os, const char *label, const std::optional<T> &x) {
|
||||||
|
if (x) {
|
||||||
|
os << ' ' << label << ':' << *x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DumpBool(std::ostream &os, const char *label, bool x) {
|
||||||
|
if (x) {
|
||||||
|
os << ' ' << label;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DumpSymbolList(std::ostream &os, const SymbolList &list) {
|
||||||
|
char sep{' '};
|
||||||
|
for (const auto *elem : list) {
|
||||||
|
os << sep << elem->name();
|
||||||
|
sep = ',';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DumpType(std::ostream &os, const Symbol &symbol) {
|
||||||
|
if (const auto *type{symbol.GetType()}) {
|
||||||
|
os << *type << ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void DumpType(std::ostream &os, const DeclTypeSpec *type) {
|
||||||
|
if (type) {
|
||||||
|
os << ' ' << *type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static void DumpList(
|
||||||
|
std::ostream &os, const char *label, const std::list<T> &list) {
|
||||||
|
if (!list.empty()) {
|
||||||
|
os << ' ' << label << ':';
|
||||||
|
char sep{' '};
|
||||||
|
for (const auto &elem : list) {
|
||||||
|
os << sep << elem;
|
||||||
|
sep = ',';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const Scope *ModuleDetails::parent() const {
|
const Scope *ModuleDetails::parent() const {
|
||||||
return isSubmodule_ && scope_ ? &scope_->parent() : nullptr;
|
return isSubmodule_ && scope_ ? &scope_->parent() : nullptr;
|
||||||
}
|
}
|
||||||
|
@ -49,12 +95,8 @@ void ModuleDetails::set_scope(const Scope *scope) {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream &operator<<(std::ostream &os, const SubprogramDetails &x) {
|
std::ostream &operator<<(std::ostream &os, const SubprogramDetails &x) {
|
||||||
if (x.isInterface_) {
|
DumpBool(os, "isInterface", x.isInterface_);
|
||||||
os << " isInterface";
|
DumpOptional(os, "bindName", x.bindName_);
|
||||||
}
|
|
||||||
if (x.bindName_) {
|
|
||||||
os << " bindName:" << x.bindName_;
|
|
||||||
}
|
|
||||||
if (x.result_) {
|
if (x.result_) {
|
||||||
os << " result:" << x.result_->name();
|
os << " result:" << x.result_->name();
|
||||||
if (!x.result_->attrs().empty()) {
|
if (!x.result_->attrs().empty()) {
|
||||||
|
@ -86,6 +128,12 @@ void ObjectEntityDetails::set_shape(const ArraySpec &shape) {
|
||||||
shape_.push_back(shapeSpec);
|
shape_.push_back(shapeSpec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void ObjectEntityDetails::set_coshape(const ArraySpec &coshape) {
|
||||||
|
CHECK(coshape_.empty());
|
||||||
|
for (const auto &shapeSpec : coshape) {
|
||||||
|
coshape_.push_back(shapeSpec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ProcEntityDetails::ProcEntityDetails(EntityDetails &&d) : EntityDetails(d) {
|
ProcEntityDetails::ProcEntityDetails(EntityDetails &&d) : EntityDetails(d) {
|
||||||
if (type()) {
|
if (type()) {
|
||||||
|
@ -268,75 +316,43 @@ ObjectEntityDetails::ObjectEntityDetails(EntityDetails &&d)
|
||||||
: EntityDetails(d) {}
|
: EntityDetails(d) {}
|
||||||
|
|
||||||
std::ostream &operator<<(std::ostream &os, const EntityDetails &x) {
|
std::ostream &operator<<(std::ostream &os, const EntityDetails &x) {
|
||||||
if (x.isDummy()) {
|
DumpBool(os, "dummy", x.isDummy());
|
||||||
os << " dummy";
|
DumpBool(os, "funcResult", x.isFuncResult());
|
||||||
}
|
|
||||||
if (x.isFuncResult()) {
|
|
||||||
os << " funcResult";
|
|
||||||
}
|
|
||||||
if (x.type()) {
|
if (x.type()) {
|
||||||
os << " type: " << *x.type();
|
os << " type: " << *x.type();
|
||||||
}
|
}
|
||||||
if (x.bindName_) {
|
DumpOptional(os, "bindName", x.bindName_);
|
||||||
os << " bindName:" << x.bindName_;
|
|
||||||
}
|
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream &operator<<(std::ostream &os, const ObjectEntityDetails &x) {
|
std::ostream &operator<<(std::ostream &os, const ObjectEntityDetails &x) {
|
||||||
os << *static_cast<const EntityDetails *>(&x);
|
os << *static_cast<const EntityDetails *>(&x);
|
||||||
if (!x.shape().empty()) {
|
DumpList(os, "shape", x.shape());
|
||||||
os << " shape:";
|
DumpList(os, "coshape", x.coshape());
|
||||||
for (const auto &s : x.shape()) {
|
DumpOptional(os, "init", x.init_);
|
||||||
os << ' ' << s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (x.init_) {
|
|
||||||
os << " init:" << x.init_;
|
|
||||||
}
|
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream &operator<<(std::ostream &os, const AssocEntityDetails &x) {
|
std::ostream &operator<<(std::ostream &os, const AssocEntityDetails &x) {
|
||||||
os << *static_cast<const EntityDetails *>(&x);
|
os << *static_cast<const EntityDetails *>(&x);
|
||||||
if (x.expr().has_value()) {
|
DumpOptional(os, "expr", x.expr());
|
||||||
os << ' ' << x.expr();
|
|
||||||
}
|
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream &operator<<(std::ostream &os, const ProcEntityDetails &x) {
|
std::ostream &operator<<(std::ostream &os, const ProcEntityDetails &x) {
|
||||||
if (auto *symbol{x.interface_.symbol()}) {
|
if (auto *symbol{x.interface_.symbol()}) {
|
||||||
os << ' ' << symbol->name();
|
os << ' ' << symbol->name();
|
||||||
} else if (auto *type{x.interface_.type()}) {
|
} else {
|
||||||
os << ' ' << *type;
|
DumpType(os, x.interface_.type());
|
||||||
}
|
|
||||||
if (x.bindName()) {
|
|
||||||
os << " bindName:" << x.bindName();
|
|
||||||
}
|
|
||||||
if (x.passName_) {
|
|
||||||
os << " passName:" << *x.passName_;
|
|
||||||
}
|
}
|
||||||
|
DumpOptional(os, "bindName", x.bindName());
|
||||||
|
DumpOptional(os, "passName", x.passName());
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream &operator<<(std::ostream &os, const DerivedTypeDetails &x) {
|
std::ostream &operator<<(std::ostream &os, const DerivedTypeDetails &x) {
|
||||||
if (x.sequence_) {
|
DumpBool(os, "sequence", x.sequence_);
|
||||||
os << " sequence";
|
DumpList(os, "components", x.componentNames_);
|
||||||
}
|
|
||||||
if (!x.componentNames_.empty()) {
|
|
||||||
os << " components:";
|
|
||||||
for (auto name : x.componentNames_) {
|
|
||||||
os << ' ' << name.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::ostream &DumpType(std::ostream &os, const Symbol &symbol) {
|
|
||||||
if (const auto *type{symbol.GetType()}) {
|
|
||||||
os << *type << ' ';
|
|
||||||
}
|
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -371,17 +387,13 @@ std::ostream &operator<<(std::ostream &os, const Details &details) {
|
||||||
os << dummy->name();
|
os << dummy->name();
|
||||||
}
|
}
|
||||||
os << ')';
|
os << ')';
|
||||||
if (x.bindName()) {
|
DumpOptional(os, "bindName", x.bindName());
|
||||||
os << " bindName:" << x.bindName();
|
|
||||||
}
|
|
||||||
if (x.isFunction()) {
|
if (x.isFunction()) {
|
||||||
os << " result(";
|
os << " result(";
|
||||||
DumpType(os, x.result());
|
DumpType(os, x.result());
|
||||||
os << x.result().name() << ')';
|
os << x.result().name() << ')';
|
||||||
}
|
}
|
||||||
if (x.isInterface()) {
|
DumpBool(os, "interface", x.isInterface());
|
||||||
os << " interface";
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
[&](const SubprogramNameDetails &x) {
|
[&](const SubprogramNameDetails &x) {
|
||||||
os << ' ' << EnumToString(x.kind());
|
os << ' ' << EnumToString(x.kind());
|
||||||
|
@ -398,29 +410,19 @@ std::ostream &operator<<(std::ostream &os, const Details &details) {
|
||||||
[](const HostAssocDetails &) {},
|
[](const HostAssocDetails &) {},
|
||||||
[&](const GenericDetails &x) {
|
[&](const GenericDetails &x) {
|
||||||
os << ' ' << EnumToString(x.kind());
|
os << ' ' << EnumToString(x.kind());
|
||||||
for (const auto *proc : x.specificProcs()) {
|
DumpSymbolList(os, x.specificProcs());
|
||||||
os << ' ' << proc->name();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
[&](const ProcBindingDetails &x) {
|
[&](const ProcBindingDetails &x) {
|
||||||
os << " => " << x.symbol().name();
|
os << " => " << x.symbol().name();
|
||||||
if (x.passName()) {
|
DumpOptional(os, "passName", x.passName());
|
||||||
os << " passName:" << *x.passName();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
[&](const GenericBindingDetails &x) {
|
[&](const GenericBindingDetails &x) {
|
||||||
os << " =>";
|
os << " =>";
|
||||||
char sep{' '};
|
DumpSymbolList(os, x.specificProcs());
|
||||||
for (const auto *proc : x.specificProcs()) {
|
|
||||||
os << sep << proc->name();
|
|
||||||
sep = ',';
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
[&](const NamelistDetails &x) {
|
[&](const NamelistDetails &x) {
|
||||||
os << ':';
|
os << ':';
|
||||||
for (const auto *object : x.objects()) {
|
DumpSymbolList(os, x.objects());
|
||||||
os << ' ' << object->name();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
[&](const CommonBlockDetails &x) {
|
[&](const CommonBlockDetails &x) {
|
||||||
os << ':';
|
os << ':';
|
||||||
|
@ -434,9 +436,7 @@ std::ostream &operator<<(std::ostream &os, const Details &details) {
|
||||||
os << ' ' << *x.type();
|
os << ' ' << *x.type();
|
||||||
}
|
}
|
||||||
os << ' ' << common::EnumToString(x.attr());
|
os << ' ' << common::EnumToString(x.attr());
|
||||||
if (x.init()) {
|
DumpOptional(os, "init", x.init());
|
||||||
os << " init:" << x.init();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
[&](const MiscDetails &x) {
|
[&](const MiscDetails &x) {
|
||||||
os << ' ' << MiscDetails::EnumToString(x.kind());
|
os << ' ' << MiscDetails::EnumToString(x.kind());
|
||||||
|
@ -512,22 +512,12 @@ std::ostream &DumpForUnparse(
|
||||||
if (!symbol.attrs().empty()) {
|
if (!symbol.attrs().empty()) {
|
||||||
os << ' ' << symbol.attrs();
|
os << ' ' << symbol.attrs();
|
||||||
}
|
}
|
||||||
if (symbol.test(Symbol::Flag::Implicit)) {
|
DumpBool(os, "(implicit)", symbol.test(Symbol::Flag::Implicit));
|
||||||
os << " (implicit)";
|
DumpBool(os, "(local)", symbol.test(Symbol::Flag::LocalityLocal));
|
||||||
}
|
DumpBool(os, "(local_init)", symbol.test(Symbol::Flag::LocalityLocalInit));
|
||||||
if (symbol.test(Symbol::Flag::LocalityLocal)) {
|
DumpBool(os, "(shared)", symbol.test(Symbol::Flag::LocalityShared));
|
||||||
os << " (local)";
|
|
||||||
}
|
|
||||||
if (symbol.test(Symbol::Flag::LocalityLocalInit)) {
|
|
||||||
os << " (local_init)";
|
|
||||||
}
|
|
||||||
if (symbol.test(Symbol::Flag::LocalityShared)) {
|
|
||||||
os << " (shared)";
|
|
||||||
}
|
|
||||||
os << ' ' << symbol.GetDetailsName();
|
os << ' ' << symbol.GetDetailsName();
|
||||||
if (const auto *type{symbol.GetType()}) {
|
DumpType(os, symbol.GetType());
|
||||||
os << ' ' << *type;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
@ -591,7 +581,16 @@ Symbol &Symbol::Instantiate(
|
||||||
foldingContext, std::move(dim.ubound().GetExplicit())));
|
foldingContext, std::move(dim.ubound().GetExplicit())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: fold cobounds too once we can represent them
|
for (ShapeSpec &dim : details.coshape()) {
|
||||||
|
if (dim.lbound().isExplicit()) {
|
||||||
|
dim.lbound().SetExplicit(Fold(
|
||||||
|
foldingContext, std::move(dim.lbound().GetExplicit())));
|
||||||
|
}
|
||||||
|
if (dim.ubound().isExplicit()) {
|
||||||
|
dim.ubound().SetExplicit(Fold(
|
||||||
|
foldingContext, std::move(dim.ubound().GetExplicit())));
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[&](const ProcBindingDetails &that) { symbol.details_ = that; },
|
[&](const ProcBindingDetails &that) { symbol.details_ = that; },
|
||||||
[&](const GenericBindingDetails &that) { symbol.details_ = that; },
|
[&](const GenericBindingDetails &that) { symbol.details_ = that; },
|
||||||
|
@ -698,4 +697,5 @@ void TypeParamDetails::set_type(const DeclTypeSpec &type) {
|
||||||
CHECK(type_ == nullptr);
|
CHECK(type_ == nullptr);
|
||||||
type_ = &type;
|
type_ = &type;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,10 +150,14 @@ public:
|
||||||
void set_init(MaybeExpr &&expr) { init_ = std::move(expr); }
|
void set_init(MaybeExpr &&expr) { init_ = std::move(expr); }
|
||||||
ArraySpec &shape() { return shape_; }
|
ArraySpec &shape() { return shape_; }
|
||||||
const ArraySpec &shape() const { return shape_; }
|
const ArraySpec &shape() const { return shape_; }
|
||||||
void set_shape(const ArraySpec &shape);
|
ArraySpec &coshape() { return coshape_; }
|
||||||
|
const ArraySpec &coshape() const { return coshape_; }
|
||||||
|
void set_shape(const ArraySpec &);
|
||||||
|
void set_coshape(const ArraySpec &);
|
||||||
const Symbol *commonBlock() const { return commonBlock_; }
|
const Symbol *commonBlock() const { return commonBlock_; }
|
||||||
void set_commonBlock(const Symbol &commonBlock) { commonBlock_ = &commonBlock; }
|
void set_commonBlock(const Symbol &commonBlock) { commonBlock_ = &commonBlock; }
|
||||||
bool IsArray() const { return !shape_.empty(); }
|
bool IsArray() const { return !shape_.empty(); }
|
||||||
|
bool IsCoarray() const { return !coshape_.empty(); }
|
||||||
bool IsAssumedShape() const {
|
bool IsAssumedShape() const {
|
||||||
return isDummy() && IsArray() && shape_.back().ubound().isDeferred() &&
|
return isDummy() && IsArray() && shape_.back().ubound().isDeferred() &&
|
||||||
!shape_.back().lbound().isDeferred();
|
!shape_.back().lbound().isDeferred();
|
||||||
|
@ -174,6 +178,7 @@ public:
|
||||||
private:
|
private:
|
||||||
MaybeExpr init_;
|
MaybeExpr init_;
|
||||||
ArraySpec shape_;
|
ArraySpec shape_;
|
||||||
|
ArraySpec coshape_;
|
||||||
const Symbol *commonBlock_{nullptr}; // common block this object is in
|
const Symbol *commonBlock_{nullptr}; // common block this object is in
|
||||||
friend std::ostream &operator<<(std::ostream &, const ObjectEntityDetails &);
|
friend std::ostream &operator<<(std::ostream &, const ObjectEntityDetails &);
|
||||||
};
|
};
|
||||||
|
@ -529,11 +534,7 @@ public:
|
||||||
return std::visit(
|
return std::visit(
|
||||||
common::visitors{
|
common::visitors{
|
||||||
[](const SubprogramDetails &sd) {
|
[](const SubprogramDetails &sd) {
|
||||||
if (sd.isFunction()) {
|
return sd.isFunction() ? sd.result().Rank() : 0;
|
||||||
return sd.result().Rank();
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
[](const GenericDetails &) {
|
[](const GenericDetails &) {
|
||||||
return 0; /*TODO*/
|
return 0; /*TODO*/
|
||||||
|
@ -548,6 +549,25 @@ public:
|
||||||
details_);
|
details_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Corank() const {
|
||||||
|
return std::visit(
|
||||||
|
common::visitors{
|
||||||
|
[](const SubprogramDetails &sd) {
|
||||||
|
return sd.isFunction() ? sd.result().Corank() : 0;
|
||||||
|
},
|
||||||
|
[](const GenericDetails &) {
|
||||||
|
return 0; /*TODO*/
|
||||||
|
},
|
||||||
|
[](const UseDetails &x) { return x.symbol().Corank(); },
|
||||||
|
[](const HostAssocDetails &x) { return x.symbol().Corank(); },
|
||||||
|
[](const ObjectEntityDetails &oed) {
|
||||||
|
return static_cast<int>(oed.coshape().size());
|
||||||
|
},
|
||||||
|
[](const auto &) { return 0; },
|
||||||
|
},
|
||||||
|
details_);
|
||||||
|
}
|
||||||
|
|
||||||
// Clones the Symbol in the context of a parameterized derived type instance
|
// Clones the Symbol in the context of a parameterized derived type instance
|
||||||
Symbol &Instantiate(Scope &, SemanticsContext &) const;
|
Symbol &Instantiate(Scope &, SemanticsContext &) const;
|
||||||
|
|
||||||
|
|
|
@ -134,6 +134,7 @@ set(MODFILE_TESTS
|
||||||
modfile21.f90
|
modfile21.f90
|
||||||
modfile22.f90
|
modfile22.f90
|
||||||
modfile23.f90
|
modfile23.f90
|
||||||
|
modfile24.f90
|
||||||
)
|
)
|
||||||
|
|
||||||
set(LABEL_TESTS
|
set(LABEL_TESTS
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
! 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.
|
||||||
|
|
||||||
|
! Test declarations with coarray-spec
|
||||||
|
|
||||||
|
! Different ways of declaring the same coarray.
|
||||||
|
module m1
|
||||||
|
real :: a(1:5)[1:10,1:*]
|
||||||
|
real, dimension(5) :: b[1:10,1:*]
|
||||||
|
real, codimension[1:10,1:*] :: c(5)
|
||||||
|
real, codimension[1:10,1:*], dimension(5) :: d
|
||||||
|
codimension :: e[1:10,1:*]
|
||||||
|
dimension :: e(5)
|
||||||
|
real :: e
|
||||||
|
end
|
||||||
|
!Expect: m1.mod
|
||||||
|
!module m1
|
||||||
|
! real(4)::a(1_8:5_8)[1_8:10_8,1_8:*]
|
||||||
|
! real(4)::b(1_8:5_8)[1_8:10_8,1_8:*]
|
||||||
|
! real(4)::c(1_8:5_8)[1_8:10_8,1_8:*]
|
||||||
|
! real(4)::d(1_8:5_8)[1_8:10_8,1_8:*]
|
||||||
|
! real(4)::e(1_8:5_8)[1_8:10_8,1_8:*]
|
||||||
|
!end
|
||||||
|
|
||||||
|
! coarray-spec in codimension and target statements.
|
||||||
|
module m2
|
||||||
|
codimension :: a[10,*], b[*]
|
||||||
|
target :: c[10,*], d[*]
|
||||||
|
end
|
||||||
|
!Expect: m2.mod
|
||||||
|
!module m2
|
||||||
|
! real(4)::a[1_8:10_8,1_8:*]
|
||||||
|
! real(4)::b[1_8:*]
|
||||||
|
! real(4),target::c[1_8:10_8,1_8:*]
|
||||||
|
! real(4),target::d[1_8:*]
|
||||||
|
!end
|
||||||
|
|
||||||
|
! coarray-spec in components and with non-constants bounds
|
||||||
|
module m3
|
||||||
|
type t
|
||||||
|
real :: c(1:5)[1:10,1:*]
|
||||||
|
complex, codimension[5,*] :: d
|
||||||
|
end type
|
||||||
|
real, allocatable :: e[:,:,:]
|
||||||
|
contains
|
||||||
|
subroutine s(a, b, n)
|
||||||
|
integer(8) :: n
|
||||||
|
real :: a[1:n,2:*]
|
||||||
|
real, codimension[1:n,2:*] :: b
|
||||||
|
end
|
||||||
|
end
|
||||||
|
!Expect: m3.mod
|
||||||
|
!module m3
|
||||||
|
! type::t
|
||||||
|
! real(4)::c[1_8:10_8,1_8:*]
|
||||||
|
! complex(4)::d[1_8:5_8,1_8:*]
|
||||||
|
! end type
|
||||||
|
! real(4),allocatable::e[:,:,:]
|
||||||
|
!contains
|
||||||
|
! subroutine s(a,b,n)
|
||||||
|
! integer(8)::n
|
||||||
|
! real(4)::a[1_8:n,2_8:*]
|
||||||
|
! real(4)::b[1_8:n,2_8:*]
|
||||||
|
! end
|
||||||
|
!end
|
||||||
|
|
||||||
|
! coarray-spec in both attributes and entity-decl
|
||||||
|
module m4
|
||||||
|
real, codimension[2:*], dimension(2:5) :: a, b(4,4), c[10,*], d(4,4)[10,*]
|
||||||
|
end
|
||||||
|
!Expect: m4.mod
|
||||||
|
!module m4
|
||||||
|
! real(4)::a(2_8:5_8)[2_8:*]
|
||||||
|
! real(4)::b(1_8:4_8,1_8:4_8)[2_8:*]
|
||||||
|
! real(4)::c(2_8:5_8)[1_8:10_8,1_8:*]
|
||||||
|
! real(4)::d(1_8:4_8,1_8:4_8)[1_8:10_8,1_8:*]
|
||||||
|
!end
|
|
@ -16,18 +16,27 @@ subroutine s1
|
||||||
integer :: x(2)
|
integer :: x(2)
|
||||||
!ERROR: The dimensions of 'x' have already been declared
|
!ERROR: The dimensions of 'x' have already been declared
|
||||||
allocatable :: x(:)
|
allocatable :: x(:)
|
||||||
|
real :: y[1:*]
|
||||||
|
!ERROR: The codimensions of 'y' have already been declared
|
||||||
|
allocatable :: y[:]
|
||||||
end
|
end
|
||||||
|
|
||||||
subroutine s2
|
subroutine s2
|
||||||
target :: x(1)
|
target :: x(1)
|
||||||
!ERROR: The dimensions of 'x' have already been declared
|
!ERROR: The dimensions of 'x' have already been declared
|
||||||
integer :: x(2)
|
integer :: x(2)
|
||||||
|
target :: y[1:*]
|
||||||
|
!ERROR: The codimensions of 'y' have already been declared
|
||||||
|
integer :: y[2:*]
|
||||||
end
|
end
|
||||||
|
|
||||||
subroutine s3
|
subroutine s3
|
||||||
dimension :: x(4), y(8)
|
dimension :: x(4), x2(8)
|
||||||
!ERROR: The dimensions of 'x' have already been declared
|
!ERROR: The dimensions of 'x' have already been declared
|
||||||
allocatable :: x(:)
|
allocatable :: x(:)
|
||||||
|
codimension :: y[*], y2[1:2,2:*]
|
||||||
|
!ERROR: The codimensions of 'y' have already been declared
|
||||||
|
allocatable :: y[:]
|
||||||
end
|
end
|
||||||
|
|
||||||
subroutine s4
|
subroutine s4
|
||||||
|
|
Loading…
Reference in New Issue