2020-02-25 23:11:52 +08:00
|
|
|
//===-- lib/Semantics/resolve-names-utils.h ---------------------*- C++ -*-===//
|
2019-03-19 02:48:02 +08:00
|
|
|
//
|
2019-12-21 04:52:07 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2019-03-19 02:48:02 +08:00
|
|
|
//
|
2020-01-11 04:12:03 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2019-03-19 02:48:02 +08:00
|
|
|
|
|
|
|
#ifndef FORTRAN_SEMANTICS_RESOLVE_NAMES_UTILS_H_
|
|
|
|
#define FORTRAN_SEMANTICS_RESOLVE_NAMES_UTILS_H_
|
|
|
|
|
2020-01-28 10:18:45 +08:00
|
|
|
// Utility functions and class for use in resolve-names.cpp.
|
2019-03-19 02:48:02 +08:00
|
|
|
|
2020-07-29 07:38:34 +08:00
|
|
|
#include "flang/Evaluate/fold.h"
|
2020-02-25 23:11:52 +08:00
|
|
|
#include "flang/Parser/message.h"
|
2020-07-29 07:38:34 +08:00
|
|
|
#include "flang/Parser/tools.h"
|
|
|
|
#include "flang/Semantics/expression.h"
|
2020-02-25 23:11:52 +08:00
|
|
|
#include "flang/Semantics/scope.h"
|
2020-07-29 07:38:34 +08:00
|
|
|
#include "flang/Semantics/semantics.h"
|
2020-02-25 23:11:52 +08:00
|
|
|
#include "flang/Semantics/symbol.h"
|
|
|
|
#include "flang/Semantics/type.h"
|
2020-12-16 23:06:53 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
[flang] Handle alternative names for relational operators
10.1.6.2 says:
> The operators <, <=, >, >=, ==, and /= always have the same interpretations
> as the operators .LT., .LE., .GT., .GE., .EQ., and .NE., respectively.
That means we have to treat `operator(<)` like `operator(.lt.)`,
for example. `<>` is a third alias for `.NE.`.
We can't just choose always to use one form (e.g. replacing `operator(.lt.)`
with `operator(<)`). This is because all symbols names are `CharBlock`s
referring to the cooked character stream so that they have proper source
provenance. Also, if a user prefers one style and uses it consistently,
that's the form they should see in messages.
So the fix is to use whatever form is found in the source, but also to
look up symbols by the other names when necessary. To assist this, add
`GenericSpecInfo::GetAllNames()` to return all of the names of a generic
spec. Each place a generic spec can occur we have to use these to look
for the symbol.
Also reorganize the `AddUse()` overloads to work with this change.
Fixes flang-compiler/f18#746.
Original-commit: flang-compiler/f18@7f06f175d5033f0728f67b1be25ecd53df1f8de5
Reviewed-on: https://github.com/flang-compiler/f18/pull/752
2019-09-18 07:57:09 +08:00
|
|
|
#include <forward_list>
|
2019-05-07 01:12:27 +08:00
|
|
|
|
|
|
|
namespace Fortran::parser {
|
|
|
|
class CharBlock;
|
|
|
|
struct ArraySpec;
|
|
|
|
struct CoarraySpec;
|
2019-06-12 09:26:48 +08:00
|
|
|
struct ComponentArraySpec;
|
|
|
|
struct DataRef;
|
2019-05-07 01:12:27 +08:00
|
|
|
struct DefinedOpName;
|
2019-06-12 09:26:48 +08:00
|
|
|
struct Designator;
|
|
|
|
struct Expr;
|
2019-05-07 01:12:27 +08:00
|
|
|
struct GenericSpec;
|
|
|
|
struct Name;
|
2020-03-29 12:00:16 +08:00
|
|
|
} // namespace Fortran::parser
|
2019-03-19 02:48:02 +08:00
|
|
|
|
|
|
|
namespace Fortran::semantics {
|
|
|
|
|
|
|
|
using SourceName = parser::CharBlock;
|
2019-04-05 05:46:40 +08:00
|
|
|
class SemanticsContext;
|
2019-03-19 02:48:02 +08:00
|
|
|
|
|
|
|
// Record that a Name has been resolved to a Symbol
|
|
|
|
Symbol &Resolve(const parser::Name &, Symbol &);
|
|
|
|
Symbol *Resolve(const parser::Name &, Symbol *);
|
|
|
|
|
|
|
|
// Create a copy of msg with a new isFatal value.
|
|
|
|
parser::MessageFixedText WithIsFatal(
|
|
|
|
const parser::MessageFixedText &msg, bool isFatal);
|
|
|
|
|
2019-06-27 06:30:53 +08:00
|
|
|
bool IsIntrinsicOperator(const SemanticsContext &, const SourceName &);
|
2019-03-19 02:48:02 +08:00
|
|
|
bool IsLogicalConstant(const SemanticsContext &, const SourceName &);
|
|
|
|
|
2020-12-16 23:06:53 +08:00
|
|
|
// Some intrinsic operators have more than one name (e.g. `operator(.eq.)` and
|
|
|
|
// `operator(==)`). GetAllNames() returns them all, including symbolName.
|
|
|
|
std::forward_list<std::string> GetAllNames(
|
|
|
|
const SemanticsContext &, const SourceName &);
|
|
|
|
|
2020-07-29 07:38:34 +08:00
|
|
|
template <typename T>
|
|
|
|
MaybeIntExpr EvaluateIntExpr(SemanticsContext &context, const T &expr) {
|
|
|
|
if (MaybeExpr maybeExpr{
|
|
|
|
Fold(context.foldingContext(), AnalyzeExpr(context, expr))}) {
|
|
|
|
if (auto *intExpr{evaluate::UnwrapExpr<SomeIntExpr>(*maybeExpr)}) {
|
|
|
|
return std::move(*intExpr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
std::optional<std::int64_t> EvaluateInt64(
|
|
|
|
SemanticsContext &context, const T &expr) {
|
|
|
|
return evaluate::ToInt64(EvaluateIntExpr(context, expr));
|
|
|
|
}
|
|
|
|
|
2019-03-19 02:48:02 +08:00
|
|
|
// Analyze a generic-spec and generate a symbol name and GenericKind for it.
|
|
|
|
class GenericSpecInfo {
|
|
|
|
public:
|
2021-09-10 06:23:48 +08:00
|
|
|
explicit GenericSpecInfo(const parser::DefinedOpName &x) { Analyze(x); }
|
|
|
|
explicit GenericSpecInfo(const parser::GenericSpec &x) { Analyze(x); }
|
2019-03-19 02:48:02 +08:00
|
|
|
|
[flang] Handle alternative names for relational operators
10.1.6.2 says:
> The operators <, <=, >, >=, ==, and /= always have the same interpretations
> as the operators .LT., .LE., .GT., .GE., .EQ., and .NE., respectively.
That means we have to treat `operator(<)` like `operator(.lt.)`,
for example. `<>` is a third alias for `.NE.`.
We can't just choose always to use one form (e.g. replacing `operator(.lt.)`
with `operator(<)`). This is because all symbols names are `CharBlock`s
referring to the cooked character stream so that they have proper source
provenance. Also, if a user prefers one style and uses it consistently,
that's the form they should see in messages.
So the fix is to use whatever form is found in the source, but also to
look up symbols by the other names when necessary. To assist this, add
`GenericSpecInfo::GetAllNames()` to return all of the names of a generic
spec. Each place a generic spec can occur we have to use these to look
for the symbol.
Also reorganize the `AddUse()` overloads to work with this change.
Fixes flang-compiler/f18#746.
Original-commit: flang-compiler/f18@7f06f175d5033f0728f67b1be25ecd53df1f8de5
Reviewed-on: https://github.com/flang-compiler/f18/pull/752
2019-09-18 07:57:09 +08:00
|
|
|
GenericKind kind() const { return kind_; }
|
2019-08-21 20:33:03 +08:00
|
|
|
const SourceName &symbolName() const { return symbolName_.value(); }
|
2019-03-19 02:48:02 +08:00
|
|
|
// Set the GenericKind in this symbol and resolve the corresponding
|
|
|
|
// name if there is one
|
[flang] Handle alternative names for relational operators
10.1.6.2 says:
> The operators <, <=, >, >=, ==, and /= always have the same interpretations
> as the operators .LT., .LE., .GT., .GE., .EQ., and .NE., respectively.
That means we have to treat `operator(<)` like `operator(.lt.)`,
for example. `<>` is a third alias for `.NE.`.
We can't just choose always to use one form (e.g. replacing `operator(.lt.)`
with `operator(<)`). This is because all symbols names are `CharBlock`s
referring to the cooked character stream so that they have proper source
provenance. Also, if a user prefers one style and uses it consistently,
that's the form they should see in messages.
So the fix is to use whatever form is found in the source, but also to
look up symbols by the other names when necessary. To assist this, add
`GenericSpecInfo::GetAllNames()` to return all of the names of a generic
spec. Each place a generic spec can occur we have to use these to look
for the symbol.
Also reorganize the `AddUse()` overloads to work with this change.
Fixes flang-compiler/f18#746.
Original-commit: flang-compiler/f18@7f06f175d5033f0728f67b1be25ecd53df1f8de5
Reviewed-on: https://github.com/flang-compiler/f18/pull/752
2019-09-18 07:57:09 +08:00
|
|
|
void Resolve(Symbol *) const;
|
2020-12-16 23:06:53 +08:00
|
|
|
friend llvm::raw_ostream &operator<<(
|
|
|
|
llvm::raw_ostream &, const GenericSpecInfo &);
|
2019-03-19 02:48:02 +08:00
|
|
|
|
|
|
|
private:
|
2021-09-10 06:23:48 +08:00
|
|
|
void Analyze(const parser::DefinedOpName &);
|
|
|
|
void Analyze(const parser::GenericSpec &);
|
|
|
|
|
2019-03-19 02:48:02 +08:00
|
|
|
GenericKind kind_;
|
|
|
|
const parser::Name *parseName_{nullptr};
|
2019-08-21 20:33:03 +08:00
|
|
|
std::optional<SourceName> symbolName_;
|
2019-03-19 02:48:02 +08:00
|
|
|
};
|
|
|
|
|
2019-04-05 07:32:37 +08:00
|
|
|
// Analyze a parser::ArraySpec or parser::CoarraySpec
|
|
|
|
ArraySpec AnalyzeArraySpec(SemanticsContext &, const parser::ArraySpec &);
|
2019-04-26 06:05:41 +08:00
|
|
|
ArraySpec AnalyzeArraySpec(
|
|
|
|
SemanticsContext &, const parser::ComponentArraySpec &);
|
2021-01-21 04:34:08 +08:00
|
|
|
ArraySpec AnalyzeDeferredShapeSpecList(
|
|
|
|
SemanticsContext &, const parser::DeferredShapeSpecList &);
|
2019-04-05 07:32:37 +08:00
|
|
|
ArraySpec AnalyzeCoarraySpec(
|
|
|
|
SemanticsContext &context, const parser::CoarraySpec &);
|
2019-04-05 05:46:40 +08:00
|
|
|
|
2019-06-12 09:26:48 +08:00
|
|
|
// Perform consistency checks on equivalence sets
|
|
|
|
class EquivalenceSets {
|
|
|
|
public:
|
|
|
|
EquivalenceSets(SemanticsContext &context) : context_{context} {}
|
|
|
|
std::vector<EquivalenceSet> &sets() { return sets_; };
|
|
|
|
// Resolve this designator and add to the current equivalence set
|
|
|
|
void AddToSet(const parser::Designator &);
|
|
|
|
// Finish the current equivalence set: determine if it overlaps
|
|
|
|
// with any of the others and perform necessary merges if it does.
|
|
|
|
void FinishSet(const parser::CharBlock &);
|
|
|
|
|
|
|
|
private:
|
|
|
|
bool CheckCanEquivalence(
|
|
|
|
const parser::CharBlock &, const Symbol &, const Symbol &);
|
|
|
|
void MergeInto(const parser::CharBlock &, EquivalenceSet &, std::size_t);
|
|
|
|
const EquivalenceObject *Find(const EquivalenceSet &, const Symbol &);
|
|
|
|
bool CheckDesignator(const parser::Designator &);
|
|
|
|
bool CheckDataRef(const parser::CharBlock &, const parser::DataRef &);
|
|
|
|
bool CheckObject(const parser::Name &);
|
2019-06-13 03:38:04 +08:00
|
|
|
bool CheckArrayBound(const parser::Expr &);
|
|
|
|
bool CheckSubstringBound(const parser::Expr &, bool);
|
2019-06-12 09:26:48 +08:00
|
|
|
bool IsCharacterSequenceType(const DeclTypeSpec *);
|
|
|
|
bool IsDefaultKindNumericType(const IntrinsicTypeSpec &);
|
2022-02-10 08:32:58 +08:00
|
|
|
bool IsDefaultNumericSequenceType(const DeclTypeSpec *);
|
|
|
|
static bool IsAnyNumericSequenceType(const DeclTypeSpec *);
|
|
|
|
static bool IsSequenceType(
|
2019-06-12 09:26:48 +08:00
|
|
|
const DeclTypeSpec *, std::function<bool(const IntrinsicTypeSpec &)>);
|
|
|
|
|
|
|
|
SemanticsContext &context_;
|
2020-03-29 12:00:16 +08:00
|
|
|
std::vector<EquivalenceSet> sets_; // all equivalence sets in this scope
|
2019-06-12 09:26:48 +08:00
|
|
|
// Map object to index of set it is in
|
|
|
|
std::map<EquivalenceObject, std::size_t> objectToSet_;
|
2020-03-29 12:00:16 +08:00
|
|
|
EquivalenceSet currSet_; // equivalence set currently being constructed
|
2019-06-12 09:26:48 +08:00
|
|
|
struct {
|
|
|
|
Symbol *symbol{nullptr};
|
|
|
|
std::vector<ConstantSubscript> subscripts;
|
2019-06-13 03:38:04 +08:00
|
|
|
std::optional<ConstantSubscript> substringStart;
|
2020-03-29 12:00:16 +08:00
|
|
|
} currObject_; // equivalence object currently being constructed
|
2019-06-12 09:26:48 +08:00
|
|
|
};
|
|
|
|
|
2020-03-29 12:00:16 +08:00
|
|
|
} // namespace Fortran::semantics
|
|
|
|
#endif // FORTRAN_SEMANTICS_RESOLVE_NAMES_H_
|