llvm/flang/lib/semantics/expression.h
peter klausler be3b765e2a [flang] basic skeleton of assignment analyzer
remove needless template<> on some function overloads

dodge bogus compiler warning from gcc 8.1.0 only

stricter typing of expressions in symbols

adjust modfile12.f90 expected test results

add Unwrap, massage folding a bit

Use Unwrap to simplify folding

Move KindSelector analysis into expression semantics

fix crash

checkpoint

updates to TypeParamInquiry

support of %KIND type parameter inquiry

equality testing for expressions

checkpoint during PDT implementation

reformat

checkpoint derived type instantiation

checkpoint

resolve merge

debugging failed tests

fix failing resolve37.f90 test

all existing tests pass

clean up all build warnings

fix bug

update copyright dates

fix copyright dates

address review comments

review comment

merge with master after peeling off changes

bugfixing new feature

fix warning from old g++s

tweaks after merging with latest head

more bugfixing

making modfile17.f90 test work

Make kinds into expressions in symbol table types

big refactor for deferring kinds in intrinsic types

modfile17.f90 test passes

clean up TODOs

Simplify types as stored in scopes

Test KIND parameter default init expressions, debug them

Update copyright dates

address comments

remove dead line

address comments

Original-commit: flang-compiler/f18@1f43d0a048
Reviewed-on: https://github.com/flang-compiler/f18/pull/260
Tree-same-pre-rewrite: false
2019-01-17 10:41:08 -08:00

252 lines
8.3 KiB
C++

// Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef FORTRAN_SEMANTICS_EXPRESSION_H_
#define FORTRAN_SEMANTICS_EXPRESSION_H_
#include "semantics.h"
#include "../common/fortran.h"
#include "../common/indirection.h"
#include "../evaluate/expression.h"
#include "../evaluate/tools.h"
#include "../evaluate/type.h"
#include "../parser/parse-tree-visitor.h"
#include "../parser/parse-tree.h"
#include <optional>
#include <variant>
using namespace Fortran::parser::literals;
namespace Fortran::parser {
struct SourceLocationFindingVisitor {
template<typename A> bool Pre(const A &) { return true; }
template<typename A> void Post(const A &) {}
bool Pre(const Expr &);
template<typename A> bool Pre(const Statement<A> &stmt) {
source = stmt.source;
return false;
}
void Post(const CharBlock &);
CharBlock source;
};
template<typename A> CharBlock FindSourceLocation(const A &x) {
SourceLocationFindingVisitor visitor;
Walk(x, visitor);
return visitor.source;
}
}
using namespace Fortran::parser::literals;
// The expression semantic analysis code has its implementation in
// namespace Fortran::evaluate, but the exposed API to it is in the
// namespace Fortran::semantics (below).
//
// The template function AnalyzeExpr() is an internal interface
// between the implementation and the API used by semantic analysis.
// This template function has a few specializations here in the header
// file to handle what semantics might want to pass in as a top-level
// expression; other specializations appear in the implementation.
//
// The ExpressionAnalysisContext wraps a SemanticsContext reference
// and implements constraint checking on expressions using the
// parse tree node wrappers that mirror the grammar annotations used
// in the Fortran standard (i.e., scalar-, constant-, &c.).
namespace Fortran::evaluate {
class ExpressionAnalysisContext {
public:
explicit ExpressionAnalysisContext(semantics::SemanticsContext &sc)
: context_{sc} {}
semantics::SemanticsContext &context() const { return context_; }
FoldingContext &GetFoldingContext() const {
return context_.foldingContext();
}
parser::ContextualMessages &GetContextualMessages() {
return GetFoldingContext().messages;
}
template<typename... A> void Say(A... args) {
GetContextualMessages().Say(std::forward<A>(args)...);
}
template<typename T, typename... A> void SayAt(const T &parsed, A... args) {
Say(parser::FindSourceLocation(parsed), std::forward<A>(args)...);
}
std::optional<Expr<SomeType>> Analyze(const parser::Expr &);
std::optional<Expr<SomeType>> Analyze(const parser::Variable &);
Expr<SubscriptInteger> Analyze(common::TypeCategory category,
const std::optional<parser::KindSelector> &);
int GetDefaultKind(common::TypeCategory);
DynamicType GetDefaultKindOfType(common::TypeCategory);
private:
semantics::SemanticsContext &context_;
};
template<typename PARSED>
std::optional<Expr<SomeType>> AnalyzeExpr(
ExpressionAnalysisContext &, const PARSED &);
inline std::optional<Expr<SomeType>> AnalyzeExpr(
ExpressionAnalysisContext &context, const parser::Expr &expr) {
return context.Analyze(expr);
}
inline std::optional<Expr<SomeType>> AnalyzeExpr(
ExpressionAnalysisContext &context, const parser::Variable &variable) {
return context.Analyze(variable);
}
// Forward declarations of exposed specializations
template<typename A>
std::optional<Expr<SomeType>> AnalyzeExpr(
ExpressionAnalysisContext &, const common::Indirection<A> &);
template<typename A>
std::optional<Expr<SomeType>> AnalyzeExpr(
ExpressionAnalysisContext &, const parser::Scalar<A> &);
template<typename A>
std::optional<Expr<SomeType>> AnalyzeExpr(
ExpressionAnalysisContext &, const parser::Constant<A> &);
template<typename A>
std::optional<Expr<SomeType>> AnalyzeExpr(
ExpressionAnalysisContext &, const parser::Integer<A> &);
template<typename A>
std::optional<Expr<SomeType>> AnalyzeExpr(
ExpressionAnalysisContext &, const parser::Logical<A> &);
template<typename A>
std::optional<Expr<SomeType>> AnalyzeExpr(
ExpressionAnalysisContext &, const parser::DefaultChar<A> &);
// Indirections are silently traversed by AnalyzeExpr().
template<typename A>
std::optional<Expr<SomeType>> AnalyzeExpr(
ExpressionAnalysisContext &context, const common::Indirection<A> &x) {
return AnalyzeExpr(context, *x);
}
// These specializations implement constraint checking.
template<typename A>
std::optional<Expr<SomeType>> AnalyzeExpr(
ExpressionAnalysisContext &context, const parser::Scalar<A> &x) {
auto result{AnalyzeExpr(context, x.thing)};
if (result.has_value()) {
if (int rank{result->Rank()}; rank != 0) {
context.SayAt(
x, "Must be a scalar value, but is a rank-%d array"_err_en_US, rank);
}
}
return result;
}
template<typename A>
std::optional<Expr<SomeType>> AnalyzeExpr(
ExpressionAnalysisContext &context, const parser::Constant<A> &x) {
auto result{AnalyzeExpr(context, x.thing)};
if (result.has_value()) {
*result = Fold(context.GetFoldingContext(), std::move(*result));
if (!IsConstantExpr(*result)) {
context.SayAt(x, "Must be a constant value"_err_en_US);
}
}
return result;
}
template<typename A>
std::optional<Expr<SomeType>> AnalyzeExpr(
ExpressionAnalysisContext &context, const parser::Integer<A> &x) {
auto result{AnalyzeExpr(context, x.thing)};
if (result.has_value()) {
if (!std::holds_alternative<Expr<SomeInteger>>(result->u)) {
context.SayAt(x, "Must have INTEGER type"_err_en_US);
}
}
return result;
}
template<typename A>
std::optional<Expr<SomeType>> AnalyzeExpr(
ExpressionAnalysisContext &context, const parser::Logical<A> &x) {
auto result{AnalyzeExpr(context, x.thing)};
if (result.has_value()) {
if (!std::holds_alternative<Expr<SomeLogical>>(result->u)) {
context.SayAt(x, "Must have LOGICAL type"_err_en_US);
}
}
return result;
}
template<typename A>
std::optional<Expr<SomeType>> AnalyzeExpr(
ExpressionAnalysisContext &context, const parser::DefaultChar<A> &x) {
auto result{AnalyzeExpr(context, x.thing)};
if (result.has_value()) {
if (auto *charExpr{std::get_if<Expr<SomeCharacter>>(&result->u)}) {
if (charExpr->GetKind() ==
context.context().defaultKinds().GetDefaultKind(
TypeCategory::Character)) {
return result;
}
}
context.SayAt(x, "Must have default CHARACTER type"_err_en_US);
}
return result;
}
template<typename L, typename R>
bool AreConformable(const L &left, const R &right) {
int leftRank{left.Rank()};
if (leftRank == 0) {
return true;
}
int rightRank{right.Rank()};
return rightRank == 0 || leftRank == rightRank;
}
template<typename L, typename R>
void ConformabilityCheck(
parser::ContextualMessages &context, const L &left, const R &right) {
if (!AreConformable(left, right)) {
context.Say("left operand has rank %d, right operand has rank %d"_err_en_US,
left.Rank(), right.Rank());
}
}
}
namespace Fortran::semantics {
// Semantic analysis of one expression.
template<typename A>
std::optional<evaluate::Expr<evaluate::SomeType>> AnalyzeExpr(
SemanticsContext &context, const A &expr) {
evaluate::ExpressionAnalysisContext exprContext{context};
return AnalyzeExpr(exprContext, expr);
}
// Semantic analysis of all expressions in a parse tree, which is
// decorated with typed representations for top-level expressions.
void AnalyzeExpressions(parser::Program &, SemanticsContext &);
// Semantic analysis of an intrinsic type's KIND parameter expression.
evaluate::Expr<evaluate::SubscriptInteger> AnalyzeKindSelector(
SemanticsContext &, parser::CharBlock, common::TypeCategory,
const std::optional<parser::KindSelector> &);
}
#endif // FORTRAN_SEMANTICS_EXPRESSION_H_