2020-02-25 23:11:52 +08:00
|
|
|
//===-- lib/Evaluate/check-expression.cpp ---------------------------------===//
|
2019-09-19 06:43:12 +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-09-19 06:43:12 +08:00
|
|
|
//
|
2020-01-11 04:12:03 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2019-09-19 06:43:12 +08:00
|
|
|
|
2020-02-25 23:11:52 +08:00
|
|
|
#include "flang/Evaluate/check-expression.h"
|
[flang] Improve initializer semantics, esp. for component default values
This patch plugs many holes in static initializer semantics, improves error
messages for default initial values and other component properties in
parameterized derived type instantiations, and cleans up several small
issues noticed during development. We now do proper scalar expansion,
folding, and type, rank, and shape conformance checking for component
default initializers in derived types and PDT instantiations.
The initial values of named constants are now guaranteed to have been folded
when installed in the symbol table, and are no longer folded or
scalar-expanded at each use in expression folding. Semantics documentation
was extended with information about the various kinds of initializations
in Fortran and when each of them are processed in the compiler.
Some necessary concomitant changes have bulked this patch out a bit:
* contextual messages attachments, which are now produced for parameterized
derived type instantiations so that the user can figure out which
instance caused a problem with a component, have been added as part
of ContextualMessages, and their implementation was debugged
* several APIs in evaluate::characteristics was changed so that a FoldingContext
is passed as an argument rather than just its intrinsic procedure table;
this affected client call sites in many files
* new tools in Evaluate/check-expression.cpp to determine when an Expr
actually is a single constant value and to validate a non-pointer
variable initializer or object component default value
* shape conformance checking has additional arguments that control
whether scalar expansion is allowed
* several now-unused functions and data members noticed and removed
* several crashes and bogus errors exposed by testing this new code
were fixed
* a -fdebug-stack-trace option to enable LLVM's stack tracing on
a crash, which might be useful in the future
TL;DR: Initialization processing does more and takes place at the right
times for all of the various kinds of things that can be initialized.
Differential Review: https://reviews.llvm.org/D92783
2020-12-08 04:08:58 +08:00
|
|
|
#include "flang/Evaluate/characteristics.h"
|
[flang] New implementation for checks for constraints C741 through C750
Summary:
Most of these checks were already implemented, and I just added references to
them to the code and tests. Also, much of this code was already
reviewed in the old flang/f18 GitHub repository, but I didn't get to
merge it before we switched repositories.
I implemented the check for C747 to not allow coarray components in derived
types that are of type C_PTR, C_FUNPTR, or type TEAM_TYPE.
I implemented the check for C748 that requires a data component whose type has
a coarray ultimate component to be a nonpointer, nonallocatable scalar and not
be a coarray.
I implemented the check for C750 that adds additional restrictions to the
bounds expressions of a derived type component that's an array.
These bounds expressions are sepcification expressions as defined in
10.1.11. There was already code in lib/Evaluate/check-expression.cpp to
check semantics for specification expressions, but it did not check for
the extra requirements of C750.
C750 prohibits specification functions, the intrinsic functions
ALLOCATED, ASSOCIATED, EXTENDS_TYPE_OF, PRESENT, and SAME_TYPE_AS. It
also requires every specification inquiry reference to be a constant
expression, and requires that the value of the bound not depend on the
value of a variable.
To implement these additional checks, I added code to the intrinsic proc
table to get the intrinsic class of a procedure. I also added an
enumeration to distinguish between specification expressions for
derived type component bounds versus for type parameters. I then
changed the code to pass an enumeration value to
"CheckSpecificationExpr()" to indicate that the expression was a bounds
expression and used this value to determine whether to emit an error
message when violations of C750 are found.
I changed the implementation of IsPureProcedure() to handle statement
functions and changed some references in the code that tested for the
PURE attribute to call IsPureProcedure().
I also fixed some unrelated tests that got new errors when I implemented these
new checks.
Reviewers: tskeith, DavidTruby, sscalpone
Subscribers: jfb, llvm-commits
Tags: #llvm, #flang
Differential Revision: https://reviews.llvm.org/D79263
2020-05-02 04:00:28 +08:00
|
|
|
#include "flang/Evaluate/intrinsics.h"
|
2020-02-25 23:11:52 +08:00
|
|
|
#include "flang/Evaluate/traverse.h"
|
|
|
|
#include "flang/Evaluate/type.h"
|
|
|
|
#include "flang/Semantics/symbol.h"
|
|
|
|
#include "flang/Semantics/tools.h"
|
[flang] New implementation for checks for constraints C741 through C750
Summary:
Most of these checks were already implemented, and I just added references to
them to the code and tests. Also, much of this code was already
reviewed in the old flang/f18 GitHub repository, but I didn't get to
merge it before we switched repositories.
I implemented the check for C747 to not allow coarray components in derived
types that are of type C_PTR, C_FUNPTR, or type TEAM_TYPE.
I implemented the check for C748 that requires a data component whose type has
a coarray ultimate component to be a nonpointer, nonallocatable scalar and not
be a coarray.
I implemented the check for C750 that adds additional restrictions to the
bounds expressions of a derived type component that's an array.
These bounds expressions are sepcification expressions as defined in
10.1.11. There was already code in lib/Evaluate/check-expression.cpp to
check semantics for specification expressions, but it did not check for
the extra requirements of C750.
C750 prohibits specification functions, the intrinsic functions
ALLOCATED, ASSOCIATED, EXTENDS_TYPE_OF, PRESENT, and SAME_TYPE_AS. It
also requires every specification inquiry reference to be a constant
expression, and requires that the value of the bound not depend on the
value of a variable.
To implement these additional checks, I added code to the intrinsic proc
table to get the intrinsic class of a procedure. I also added an
enumeration to distinguish between specification expressions for
derived type component bounds versus for type parameters. I then
changed the code to pass an enumeration value to
"CheckSpecificationExpr()" to indicate that the expression was a bounds
expression and used this value to determine whether to emit an error
message when violations of C750 are found.
I changed the implementation of IsPureProcedure() to handle statement
functions and changed some references in the code that tested for the
PURE attribute to call IsPureProcedure().
I also fixed some unrelated tests that got new errors when I implemented these
new checks.
Reviewers: tskeith, DavidTruby, sscalpone
Subscribers: jfb, llvm-commits
Tags: #llvm, #flang
Differential Revision: https://reviews.llvm.org/D79263
2020-05-02 04:00:28 +08:00
|
|
|
#include <set>
|
|
|
|
#include <string>
|
2019-09-19 06:43:12 +08:00
|
|
|
|
|
|
|
namespace Fortran::evaluate {
|
|
|
|
|
2021-11-02 07:24:01 +08:00
|
|
|
// Constant expression predicates IsConstantExpr() & IsScopeInvariantExpr().
|
2019-09-19 06:43:12 +08:00
|
|
|
// This code determines whether an expression is a "constant expression"
|
|
|
|
// in the sense of section 10.1.12. This is not the same thing as being
|
|
|
|
// able to fold it (yet) into a known constant value; specifically,
|
|
|
|
// the expression may reference derived type kind parameters whose values
|
|
|
|
// are not yet known.
|
2021-11-02 07:24:01 +08:00
|
|
|
//
|
|
|
|
// The variant form (IsScopeInvariantExpr()) also accepts symbols that are
|
|
|
|
// INTENT(IN) dummy arguments without the VALUE attribute.
|
|
|
|
template <bool INVARIANT>
|
|
|
|
class IsConstantExprHelper
|
|
|
|
: public AllTraverse<IsConstantExprHelper<INVARIANT>, true> {
|
2019-09-19 06:43:12 +08:00
|
|
|
public:
|
2019-10-23 01:34:05 +08:00
|
|
|
using Base = AllTraverse<IsConstantExprHelper, true>;
|
2019-09-20 06:49:13 +08:00
|
|
|
IsConstantExprHelper() : Base{*this} {}
|
|
|
|
using Base::operator();
|
2019-09-19 06:43:12 +08:00
|
|
|
|
[flang] Fix classification of shape inquiries in specification exprs
In some contexts, including the motivating case of determining whether
the expressions that define the shape of a variable are "constant expressions"
in the sense of the Fortran standard, expression rewriting via Fold()
is not necessary, and should not be required. The inquiry intrinsics LBOUND,
UBOUND, and SIZE work correctly now in specification expressions and are
classified correctly as being constant expressions (or not). Getting this right
led to a fair amount of API clean-up as a consequence, including the
folding of shapes and TypeAndShape objects, and new APIs for shapes
that do not fold for those cases where folding isn't needed. Further,
the symbol-testing predicate APIs in Evaluate/tools.h now all resolve any
associations of their symbols and work transparently on use-, host-, and
construct-association symbols; the tools used to resolve those associations have
been defined and documented more precisely, and their clients adjusted as needed.
Differential Revision: https://reviews.llvm.org/D94561
2021-01-13 07:36:45 +08:00
|
|
|
// A missing expression is not considered to be constant.
|
|
|
|
template <typename A> bool operator()(const std::optional<A> &x) const {
|
|
|
|
return x && (*this)(*x);
|
|
|
|
}
|
|
|
|
|
2020-08-26 00:40:20 +08:00
|
|
|
bool operator()(const TypeParamInquiry &inq) const {
|
2021-11-02 07:24:01 +08:00
|
|
|
return INVARIANT || semantics::IsKindTypeParameter(inq.parameter());
|
2019-09-20 06:49:13 +08:00
|
|
|
}
|
|
|
|
bool operator()(const semantics::Symbol &symbol) const {
|
2021-04-01 00:12:28 +08:00
|
|
|
const auto &ultimate{GetAssociationRoot(symbol)};
|
2020-06-19 08:17:04 +08:00
|
|
|
return IsNamedConstant(ultimate) || IsImpliedDoIndex(ultimate) ||
|
2021-11-02 07:24:01 +08:00
|
|
|
IsInitialProcedureTarget(ultimate) ||
|
|
|
|
ultimate.has<semantics::TypeParamDetails>() ||
|
|
|
|
(INVARIANT && IsIntentIn(symbol) &&
|
|
|
|
!symbol.attrs().test(semantics::Attr::VALUE));
|
2019-09-19 06:43:12 +08:00
|
|
|
}
|
2019-09-20 06:49:13 +08:00
|
|
|
bool operator()(const CoarrayRef &) const { return false; }
|
|
|
|
bool operator()(const semantics::ParamValue ¶m) const {
|
|
|
|
return param.isExplicit() && (*this)(param.GetExplicit());
|
2019-09-19 06:43:12 +08:00
|
|
|
}
|
[flang] Fix classification of shape inquiries in specification exprs
In some contexts, including the motivating case of determining whether
the expressions that define the shape of a variable are "constant expressions"
in the sense of the Fortran standard, expression rewriting via Fold()
is not necessary, and should not be required. The inquiry intrinsics LBOUND,
UBOUND, and SIZE work correctly now in specification expressions and are
classified correctly as being constant expressions (or not). Getting this right
led to a fair amount of API clean-up as a consequence, including the
folding of shapes and TypeAndShape objects, and new APIs for shapes
that do not fold for those cases where folding isn't needed. Further,
the symbol-testing predicate APIs in Evaluate/tools.h now all resolve any
associations of their symbols and work transparently on use-, host-, and
construct-association symbols; the tools used to resolve those associations have
been defined and documented more precisely, and their clients adjusted as needed.
Differential Revision: https://reviews.llvm.org/D94561
2021-01-13 07:36:45 +08:00
|
|
|
bool operator()(const ProcedureRef &) const;
|
Rework DATA statement semantics to use typed expressions
Summary:
Updates recent work on DATA statement semantic checking in
flang/lib/Semantics/check-data.{h,cpp} to use the compiler's
internal representation for typed expressions rather than working
on the raw parse tree. Saves the analyzed expressions for DATA
statement values as parse tree decorations because they'll soon be
needed in lowering. Corrects wording of some error messages.
Fixes a bug in constant expression checking: structure constructors
are not constant expressions if they set an allocatable component
to anything other than NULL.
Includes infrastructure changes to make this work, some renaming
to reflect the fact that the implied DO loop indices tracked by
expression analysis are not (just) from array constructors, remove
some dead code, and improve some comments.
Reviewers: tskeith, sscalpone, jdoerfert, DavidTruby, anchu-rajendran, schweitz
Reviewed By: tskeith, anchu-rajendran, schweitz
Subscribers: llvm-commits, flang-commits
Tags: #flang, #llvm
Differential Revision: https://reviews.llvm.org/D78834
2020-04-25 04:54:11 +08:00
|
|
|
bool operator()(const StructureConstructor &constructor) const {
|
|
|
|
for (const auto &[symRef, expr] : constructor) {
|
2020-06-19 08:17:04 +08:00
|
|
|
if (!IsConstantStructureConstructorComponent(*symRef, expr.value())) {
|
Rework DATA statement semantics to use typed expressions
Summary:
Updates recent work on DATA statement semantic checking in
flang/lib/Semantics/check-data.{h,cpp} to use the compiler's
internal representation for typed expressions rather than working
on the raw parse tree. Saves the analyzed expressions for DATA
statement values as parse tree decorations because they'll soon be
needed in lowering. Corrects wording of some error messages.
Fixes a bug in constant expression checking: structure constructors
are not constant expressions if they set an allocatable component
to anything other than NULL.
Includes infrastructure changes to make this work, some renaming
to reflect the fact that the implied DO loop indices tracked by
expression analysis are not (just) from array constructors, remove
some dead code, and improve some comments.
Reviewers: tskeith, sscalpone, jdoerfert, DavidTruby, anchu-rajendran, schweitz
Reviewed By: tskeith, anchu-rajendran, schweitz
Subscribers: llvm-commits, flang-commits
Tags: #flang, #llvm
Differential Revision: https://reviews.llvm.org/D78834
2020-04-25 04:54:11 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2020-06-03 12:56:10 +08:00
|
|
|
bool operator()(const Component &component) const {
|
|
|
|
return (*this)(component.base());
|
|
|
|
}
|
2019-09-19 06:43:12 +08:00
|
|
|
// Forbid integer division by zero in constants.
|
2020-03-29 12:00:16 +08:00
|
|
|
template <int KIND>
|
2019-09-20 06:49:13 +08:00
|
|
|
bool operator()(
|
|
|
|
const Divide<Type<TypeCategory::Integer, KIND>> &division) const {
|
2019-09-19 06:43:12 +08:00
|
|
|
using T = Type<TypeCategory::Integer, KIND>;
|
|
|
|
if (const auto divisor{GetScalarConstantValue<T>(division.right())}) {
|
2020-06-04 15:41:28 +08:00
|
|
|
return !divisor->IsZero() && (*this)(division.left());
|
2019-09-20 06:49:13 +08:00
|
|
|
} else {
|
|
|
|
return false;
|
2019-09-19 06:43:12 +08:00
|
|
|
}
|
|
|
|
}
|
2020-06-19 08:17:04 +08:00
|
|
|
|
|
|
|
bool operator()(const Constant<SomeDerived> &) const { return true; }
|
2021-11-02 07:24:01 +08:00
|
|
|
bool operator()(const DescriptorInquiry &x) const {
|
|
|
|
const Symbol &sym{x.base().GetLastSymbol()};
|
|
|
|
return INVARIANT && !IsAllocatable(sym) &&
|
|
|
|
(!IsDummy(sym) ||
|
|
|
|
(IsIntentIn(sym) && !sym.attrs().test(semantics::Attr::VALUE)));
|
|
|
|
}
|
2020-06-19 08:17:04 +08:00
|
|
|
|
|
|
|
private:
|
|
|
|
bool IsConstantStructureConstructorComponent(
|
[flang] Fix classification of shape inquiries in specification exprs
In some contexts, including the motivating case of determining whether
the expressions that define the shape of a variable are "constant expressions"
in the sense of the Fortran standard, expression rewriting via Fold()
is not necessary, and should not be required. The inquiry intrinsics LBOUND,
UBOUND, and SIZE work correctly now in specification expressions and are
classified correctly as being constant expressions (or not). Getting this right
led to a fair amount of API clean-up as a consequence, including the
folding of shapes and TypeAndShape objects, and new APIs for shapes
that do not fold for those cases where folding isn't needed. Further,
the symbol-testing predicate APIs in Evaluate/tools.h now all resolve any
associations of their symbols and work transparently on use-, host-, and
construct-association symbols; the tools used to resolve those associations have
been defined and documented more precisely, and their clients adjusted as needed.
Differential Revision: https://reviews.llvm.org/D94561
2021-01-13 07:36:45 +08:00
|
|
|
const Symbol &, const Expr<SomeType> &) const;
|
|
|
|
bool IsConstantExprShape(const Shape &) const;
|
|
|
|
};
|
|
|
|
|
2021-11-02 07:24:01 +08:00
|
|
|
template <bool INVARIANT>
|
|
|
|
bool IsConstantExprHelper<INVARIANT>::IsConstantStructureConstructorComponent(
|
[flang] Fix classification of shape inquiries in specification exprs
In some contexts, including the motivating case of determining whether
the expressions that define the shape of a variable are "constant expressions"
in the sense of the Fortran standard, expression rewriting via Fold()
is not necessary, and should not be required. The inquiry intrinsics LBOUND,
UBOUND, and SIZE work correctly now in specification expressions and are
classified correctly as being constant expressions (or not). Getting this right
led to a fair amount of API clean-up as a consequence, including the
folding of shapes and TypeAndShape objects, and new APIs for shapes
that do not fold for those cases where folding isn't needed. Further,
the symbol-testing predicate APIs in Evaluate/tools.h now all resolve any
associations of their symbols and work transparently on use-, host-, and
construct-association symbols; the tools used to resolve those associations have
been defined and documented more precisely, and their clients adjusted as needed.
Differential Revision: https://reviews.llvm.org/D94561
2021-01-13 07:36:45 +08:00
|
|
|
const Symbol &component, const Expr<SomeType> &expr) const {
|
|
|
|
if (IsAllocatable(component)) {
|
|
|
|
return IsNullPointer(expr);
|
|
|
|
} else if (IsPointer(component)) {
|
|
|
|
return IsNullPointer(expr) || IsInitialDataTarget(expr) ||
|
|
|
|
IsInitialProcedureTarget(expr);
|
|
|
|
} else {
|
|
|
|
return (*this)(expr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-02 07:24:01 +08:00
|
|
|
template <bool INVARIANT>
|
|
|
|
bool IsConstantExprHelper<INVARIANT>::operator()(
|
|
|
|
const ProcedureRef &call) const {
|
2021-10-01 06:58:38 +08:00
|
|
|
// LBOUND, UBOUND, and SIZE with DIM= arguments will have been rewritten
|
[flang] Fix classification of shape inquiries in specification exprs
In some contexts, including the motivating case of determining whether
the expressions that define the shape of a variable are "constant expressions"
in the sense of the Fortran standard, expression rewriting via Fold()
is not necessary, and should not be required. The inquiry intrinsics LBOUND,
UBOUND, and SIZE work correctly now in specification expressions and are
classified correctly as being constant expressions (or not). Getting this right
led to a fair amount of API clean-up as a consequence, including the
folding of shapes and TypeAndShape objects, and new APIs for shapes
that do not fold for those cases where folding isn't needed. Further,
the symbol-testing predicate APIs in Evaluate/tools.h now all resolve any
associations of their symbols and work transparently on use-, host-, and
construct-association symbols; the tools used to resolve those associations have
been defined and documented more precisely, and their clients adjusted as needed.
Differential Revision: https://reviews.llvm.org/D94561
2021-01-13 07:36:45 +08:00
|
|
|
// into DescriptorInquiry operations.
|
|
|
|
if (const auto *intrinsic{std::get_if<SpecificIntrinsic>(&call.proc().u)}) {
|
|
|
|
if (intrinsic->name == "kind" ||
|
|
|
|
intrinsic->name == IntrinsicProcTable::InvalidName) {
|
|
|
|
// kind is always a constant, and we avoid cascading errors by considering
|
|
|
|
// invalid calls to intrinsics to be constant
|
|
|
|
return true;
|
|
|
|
} else if (intrinsic->name == "lbound" && call.arguments().size() == 1) {
|
|
|
|
// LBOUND(x) without DIM=
|
|
|
|
auto base{ExtractNamedEntity(call.arguments()[0]->UnwrapExpr())};
|
2022-03-10 05:43:54 +08:00
|
|
|
return base && IsConstantExprShape(GetLBOUNDs(*base));
|
[flang] Fix classification of shape inquiries in specification exprs
In some contexts, including the motivating case of determining whether
the expressions that define the shape of a variable are "constant expressions"
in the sense of the Fortran standard, expression rewriting via Fold()
is not necessary, and should not be required. The inquiry intrinsics LBOUND,
UBOUND, and SIZE work correctly now in specification expressions and are
classified correctly as being constant expressions (or not). Getting this right
led to a fair amount of API clean-up as a consequence, including the
folding of shapes and TypeAndShape objects, and new APIs for shapes
that do not fold for those cases where folding isn't needed. Further,
the symbol-testing predicate APIs in Evaluate/tools.h now all resolve any
associations of their symbols and work transparently on use-, host-, and
construct-association symbols; the tools used to resolve those associations have
been defined and documented more precisely, and their clients adjusted as needed.
Differential Revision: https://reviews.llvm.org/D94561
2021-01-13 07:36:45 +08:00
|
|
|
} else if (intrinsic->name == "ubound" && call.arguments().size() == 1) {
|
|
|
|
// UBOUND(x) without DIM=
|
|
|
|
auto base{ExtractNamedEntity(call.arguments()[0]->UnwrapExpr())};
|
2022-03-24 16:06:59 +08:00
|
|
|
return base && IsConstantExprShape(GetUBOUNDs(*base));
|
[flang] Fix classification of shape inquiries in specification exprs
In some contexts, including the motivating case of determining whether
the expressions that define the shape of a variable are "constant expressions"
in the sense of the Fortran standard, expression rewriting via Fold()
is not necessary, and should not be required. The inquiry intrinsics LBOUND,
UBOUND, and SIZE work correctly now in specification expressions and are
classified correctly as being constant expressions (or not). Getting this right
led to a fair amount of API clean-up as a consequence, including the
folding of shapes and TypeAndShape objects, and new APIs for shapes
that do not fold for those cases where folding isn't needed. Further,
the symbol-testing predicate APIs in Evaluate/tools.h now all resolve any
associations of their symbols and work transparently on use-, host-, and
construct-association symbols; the tools used to resolve those associations have
been defined and documented more precisely, and their clients adjusted as needed.
Differential Revision: https://reviews.llvm.org/D94561
2021-01-13 07:36:45 +08:00
|
|
|
} else if (intrinsic->name == "shape") {
|
|
|
|
auto shape{GetShape(call.arguments()[0]->UnwrapExpr())};
|
|
|
|
return shape && IsConstantExprShape(*shape);
|
|
|
|
} else if (intrinsic->name == "size" && call.arguments().size() == 1) {
|
|
|
|
// SIZE(x) without DIM
|
|
|
|
auto shape{GetShape(call.arguments()[0]->UnwrapExpr())};
|
|
|
|
return shape && IsConstantExprShape(*shape);
|
2020-06-19 08:17:04 +08:00
|
|
|
}
|
[flang] Fix classification of shape inquiries in specification exprs
In some contexts, including the motivating case of determining whether
the expressions that define the shape of a variable are "constant expressions"
in the sense of the Fortran standard, expression rewriting via Fold()
is not necessary, and should not be required. The inquiry intrinsics LBOUND,
UBOUND, and SIZE work correctly now in specification expressions and are
classified correctly as being constant expressions (or not). Getting this right
led to a fair amount of API clean-up as a consequence, including the
folding of shapes and TypeAndShape objects, and new APIs for shapes
that do not fold for those cases where folding isn't needed. Further,
the symbol-testing predicate APIs in Evaluate/tools.h now all resolve any
associations of their symbols and work transparently on use-, host-, and
construct-association symbols; the tools used to resolve those associations have
been defined and documented more precisely, and their clients adjusted as needed.
Differential Revision: https://reviews.llvm.org/D94561
2021-01-13 07:36:45 +08:00
|
|
|
// TODO: STORAGE_SIZE
|
2020-06-19 08:17:04 +08:00
|
|
|
}
|
[flang] Fix classification of shape inquiries in specification exprs
In some contexts, including the motivating case of determining whether
the expressions that define the shape of a variable are "constant expressions"
in the sense of the Fortran standard, expression rewriting via Fold()
is not necessary, and should not be required. The inquiry intrinsics LBOUND,
UBOUND, and SIZE work correctly now in specification expressions and are
classified correctly as being constant expressions (or not). Getting this right
led to a fair amount of API clean-up as a consequence, including the
folding of shapes and TypeAndShape objects, and new APIs for shapes
that do not fold for those cases where folding isn't needed. Further,
the symbol-testing predicate APIs in Evaluate/tools.h now all resolve any
associations of their symbols and work transparently on use-, host-, and
construct-association symbols; the tools used to resolve those associations have
been defined and documented more precisely, and their clients adjusted as needed.
Differential Revision: https://reviews.llvm.org/D94561
2021-01-13 07:36:45 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-11-02 07:24:01 +08:00
|
|
|
template <bool INVARIANT>
|
|
|
|
bool IsConstantExprHelper<INVARIANT>::IsConstantExprShape(
|
|
|
|
const Shape &shape) const {
|
[flang] Fix classification of shape inquiries in specification exprs
In some contexts, including the motivating case of determining whether
the expressions that define the shape of a variable are "constant expressions"
in the sense of the Fortran standard, expression rewriting via Fold()
is not necessary, and should not be required. The inquiry intrinsics LBOUND,
UBOUND, and SIZE work correctly now in specification expressions and are
classified correctly as being constant expressions (or not). Getting this right
led to a fair amount of API clean-up as a consequence, including the
folding of shapes and TypeAndShape objects, and new APIs for shapes
that do not fold for those cases where folding isn't needed. Further,
the symbol-testing predicate APIs in Evaluate/tools.h now all resolve any
associations of their symbols and work transparently on use-, host-, and
construct-association symbols; the tools used to resolve those associations have
been defined and documented more precisely, and their clients adjusted as needed.
Differential Revision: https://reviews.llvm.org/D94561
2021-01-13 07:36:45 +08:00
|
|
|
for (const auto &extent : shape) {
|
|
|
|
if (!(*this)(extent)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2019-09-19 06:43:12 +08:00
|
|
|
|
2020-03-29 12:00:16 +08:00
|
|
|
template <typename A> bool IsConstantExpr(const A &x) {
|
2021-11-02 07:24:01 +08:00
|
|
|
return IsConstantExprHelper<false>{}(x);
|
2019-09-19 06:43:12 +08:00
|
|
|
}
|
2019-09-20 06:49:13 +08:00
|
|
|
template bool IsConstantExpr(const Expr<SomeType> &);
|
2019-09-17 07:58:13 +08:00
|
|
|
template bool IsConstantExpr(const Expr<SomeInteger> &);
|
2020-03-14 03:19:44 +08:00
|
|
|
template bool IsConstantExpr(const Expr<SubscriptInteger> &);
|
2020-06-19 08:17:04 +08:00
|
|
|
template bool IsConstantExpr(const StructureConstructor &);
|
2019-09-19 06:43:12 +08:00
|
|
|
|
2021-11-02 07:24:01 +08:00
|
|
|
// IsScopeInvariantExpr()
|
|
|
|
template <typename A> bool IsScopeInvariantExpr(const A &x) {
|
|
|
|
return IsConstantExprHelper<true>{}(x);
|
|
|
|
}
|
|
|
|
template bool IsScopeInvariantExpr(const Expr<SomeType> &);
|
|
|
|
template bool IsScopeInvariantExpr(const Expr<SomeInteger> &);
|
|
|
|
template bool IsScopeInvariantExpr(const Expr<SubscriptInteger> &);
|
|
|
|
|
[flang] Improve initializer semantics, esp. for component default values
This patch plugs many holes in static initializer semantics, improves error
messages for default initial values and other component properties in
parameterized derived type instantiations, and cleans up several small
issues noticed during development. We now do proper scalar expansion,
folding, and type, rank, and shape conformance checking for component
default initializers in derived types and PDT instantiations.
The initial values of named constants are now guaranteed to have been folded
when installed in the symbol table, and are no longer folded or
scalar-expanded at each use in expression folding. Semantics documentation
was extended with information about the various kinds of initializations
in Fortran and when each of them are processed in the compiler.
Some necessary concomitant changes have bulked this patch out a bit:
* contextual messages attachments, which are now produced for parameterized
derived type instantiations so that the user can figure out which
instance caused a problem with a component, have been added as part
of ContextualMessages, and their implementation was debugged
* several APIs in evaluate::characteristics was changed so that a FoldingContext
is passed as an argument rather than just its intrinsic procedure table;
this affected client call sites in many files
* new tools in Evaluate/check-expression.cpp to determine when an Expr
actually is a single constant value and to validate a non-pointer
variable initializer or object component default value
* shape conformance checking has additional arguments that control
whether scalar expansion is allowed
* several now-unused functions and data members noticed and removed
* several crashes and bogus errors exposed by testing this new code
were fixed
* a -fdebug-stack-trace option to enable LLVM's stack tracing on
a crash, which might be useful in the future
TL;DR: Initialization processing does more and takes place at the right
times for all of the various kinds of things that can be initialized.
Differential Review: https://reviews.llvm.org/D92783
2020-12-08 04:08:58 +08:00
|
|
|
// IsActuallyConstant()
|
|
|
|
struct IsActuallyConstantHelper {
|
|
|
|
template <typename A> bool operator()(const A &) { return false; }
|
|
|
|
template <typename T> bool operator()(const Constant<T> &) { return true; }
|
|
|
|
template <typename T> bool operator()(const Parentheses<T> &x) {
|
|
|
|
return (*this)(x.left());
|
|
|
|
}
|
|
|
|
template <typename T> bool operator()(const Expr<T> &x) {
|
2022-03-24 05:05:50 +08:00
|
|
|
return common::visit([=](const auto &y) { return (*this)(y); }, x.u);
|
[flang] Improve initializer semantics, esp. for component default values
This patch plugs many holes in static initializer semantics, improves error
messages for default initial values and other component properties in
parameterized derived type instantiations, and cleans up several small
issues noticed during development. We now do proper scalar expansion,
folding, and type, rank, and shape conformance checking for component
default initializers in derived types and PDT instantiations.
The initial values of named constants are now guaranteed to have been folded
when installed in the symbol table, and are no longer folded or
scalar-expanded at each use in expression folding. Semantics documentation
was extended with information about the various kinds of initializations
in Fortran and when each of them are processed in the compiler.
Some necessary concomitant changes have bulked this patch out a bit:
* contextual messages attachments, which are now produced for parameterized
derived type instantiations so that the user can figure out which
instance caused a problem with a component, have been added as part
of ContextualMessages, and their implementation was debugged
* several APIs in evaluate::characteristics was changed so that a FoldingContext
is passed as an argument rather than just its intrinsic procedure table;
this affected client call sites in many files
* new tools in Evaluate/check-expression.cpp to determine when an Expr
actually is a single constant value and to validate a non-pointer
variable initializer or object component default value
* shape conformance checking has additional arguments that control
whether scalar expansion is allowed
* several now-unused functions and data members noticed and removed
* several crashes and bogus errors exposed by testing this new code
were fixed
* a -fdebug-stack-trace option to enable LLVM's stack tracing on
a crash, which might be useful in the future
TL;DR: Initialization processing does more and takes place at the right
times for all of the various kinds of things that can be initialized.
Differential Review: https://reviews.llvm.org/D92783
2020-12-08 04:08:58 +08:00
|
|
|
}
|
2022-03-01 02:24:58 +08:00
|
|
|
bool operator()(const Expr<SomeType> &x) {
|
|
|
|
if (IsNullPointer(x)) {
|
|
|
|
return true;
|
|
|
|
}
|
2022-03-24 05:05:50 +08:00
|
|
|
return common::visit([this](const auto &y) { return (*this)(y); }, x.u);
|
2022-03-01 02:24:58 +08:00
|
|
|
}
|
[flang] Improve initializer semantics, esp. for component default values
This patch plugs many holes in static initializer semantics, improves error
messages for default initial values and other component properties in
parameterized derived type instantiations, and cleans up several small
issues noticed during development. We now do proper scalar expansion,
folding, and type, rank, and shape conformance checking for component
default initializers in derived types and PDT instantiations.
The initial values of named constants are now guaranteed to have been folded
when installed in the symbol table, and are no longer folded or
scalar-expanded at each use in expression folding. Semantics documentation
was extended with information about the various kinds of initializations
in Fortran and when each of them are processed in the compiler.
Some necessary concomitant changes have bulked this patch out a bit:
* contextual messages attachments, which are now produced for parameterized
derived type instantiations so that the user can figure out which
instance caused a problem with a component, have been added as part
of ContextualMessages, and their implementation was debugged
* several APIs in evaluate::characteristics was changed so that a FoldingContext
is passed as an argument rather than just its intrinsic procedure table;
this affected client call sites in many files
* new tools in Evaluate/check-expression.cpp to determine when an Expr
actually is a single constant value and to validate a non-pointer
variable initializer or object component default value
* shape conformance checking has additional arguments that control
whether scalar expansion is allowed
* several now-unused functions and data members noticed and removed
* several crashes and bogus errors exposed by testing this new code
were fixed
* a -fdebug-stack-trace option to enable LLVM's stack tracing on
a crash, which might be useful in the future
TL;DR: Initialization processing does more and takes place at the right
times for all of the various kinds of things that can be initialized.
Differential Review: https://reviews.llvm.org/D92783
2020-12-08 04:08:58 +08:00
|
|
|
template <typename A> bool operator()(const A *x) { return x && (*this)(*x); }
|
|
|
|
template <typename A> bool operator()(const std::optional<A> &x) {
|
|
|
|
return x && (*this)(*x);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename A> bool IsActuallyConstant(const A &x) {
|
|
|
|
return IsActuallyConstantHelper{}(x);
|
|
|
|
}
|
|
|
|
|
|
|
|
template bool IsActuallyConstant(const Expr<SomeType> &);
|
2022-04-04 15:47:03 +08:00
|
|
|
template bool IsActuallyConstant(const Expr<SomeInteger> &);
|
|
|
|
template bool IsActuallyConstant(const Expr<SubscriptInteger> &);
|
[flang] Improve initializer semantics, esp. for component default values
This patch plugs many holes in static initializer semantics, improves error
messages for default initial values and other component properties in
parameterized derived type instantiations, and cleans up several small
issues noticed during development. We now do proper scalar expansion,
folding, and type, rank, and shape conformance checking for component
default initializers in derived types and PDT instantiations.
The initial values of named constants are now guaranteed to have been folded
when installed in the symbol table, and are no longer folded or
scalar-expanded at each use in expression folding. Semantics documentation
was extended with information about the various kinds of initializations
in Fortran and when each of them are processed in the compiler.
Some necessary concomitant changes have bulked this patch out a bit:
* contextual messages attachments, which are now produced for parameterized
derived type instantiations so that the user can figure out which
instance caused a problem with a component, have been added as part
of ContextualMessages, and their implementation was debugged
* several APIs in evaluate::characteristics was changed so that a FoldingContext
is passed as an argument rather than just its intrinsic procedure table;
this affected client call sites in many files
* new tools in Evaluate/check-expression.cpp to determine when an Expr
actually is a single constant value and to validate a non-pointer
variable initializer or object component default value
* shape conformance checking has additional arguments that control
whether scalar expansion is allowed
* several now-unused functions and data members noticed and removed
* several crashes and bogus errors exposed by testing this new code
were fixed
* a -fdebug-stack-trace option to enable LLVM's stack tracing on
a crash, which might be useful in the future
TL;DR: Initialization processing does more and takes place at the right
times for all of the various kinds of things that can be initialized.
Differential Review: https://reviews.llvm.org/D92783
2020-12-08 04:08:58 +08:00
|
|
|
|
2019-09-19 06:43:12 +08:00
|
|
|
// Object pointer initialization checking predicate IsInitialDataTarget().
|
|
|
|
// This code determines whether an expression is allowable as the static
|
|
|
|
// data address used to initialize a pointer with "=> x". See C765.
|
Rework DATA statement semantics to use typed expressions
Summary:
Updates recent work on DATA statement semantic checking in
flang/lib/Semantics/check-data.{h,cpp} to use the compiler's
internal representation for typed expressions rather than working
on the raw parse tree. Saves the analyzed expressions for DATA
statement values as parse tree decorations because they'll soon be
needed in lowering. Corrects wording of some error messages.
Fixes a bug in constant expression checking: structure constructors
are not constant expressions if they set an allocatable component
to anything other than NULL.
Includes infrastructure changes to make this work, some renaming
to reflect the fact that the implied DO loop indices tracked by
expression analysis are not (just) from array constructors, remove
some dead code, and improve some comments.
Reviewers: tskeith, sscalpone, jdoerfert, DavidTruby, anchu-rajendran, schweitz
Reviewed By: tskeith, anchu-rajendran, schweitz
Subscribers: llvm-commits, flang-commits
Tags: #flang, #llvm
Differential Revision: https://reviews.llvm.org/D78834
2020-04-25 04:54:11 +08:00
|
|
|
class IsInitialDataTargetHelper
|
2020-03-29 12:00:16 +08:00
|
|
|
: public AllTraverse<IsInitialDataTargetHelper, true> {
|
Rework DATA statement semantics to use typed expressions
Summary:
Updates recent work on DATA statement semantic checking in
flang/lib/Semantics/check-data.{h,cpp} to use the compiler's
internal representation for typed expressions rather than working
on the raw parse tree. Saves the analyzed expressions for DATA
statement values as parse tree decorations because they'll soon be
needed in lowering. Corrects wording of some error messages.
Fixes a bug in constant expression checking: structure constructors
are not constant expressions if they set an allocatable component
to anything other than NULL.
Includes infrastructure changes to make this work, some renaming
to reflect the fact that the implied DO loop indices tracked by
expression analysis are not (just) from array constructors, remove
some dead code, and improve some comments.
Reviewers: tskeith, sscalpone, jdoerfert, DavidTruby, anchu-rajendran, schweitz
Reviewed By: tskeith, anchu-rajendran, schweitz
Subscribers: llvm-commits, flang-commits
Tags: #flang, #llvm
Differential Revision: https://reviews.llvm.org/D78834
2020-04-25 04:54:11 +08:00
|
|
|
public:
|
2019-10-23 01:34:05 +08:00
|
|
|
using Base = AllTraverse<IsInitialDataTargetHelper, true>;
|
2019-09-19 07:47:25 +08:00
|
|
|
using Base::operator();
|
Rework DATA statement semantics to use typed expressions
Summary:
Updates recent work on DATA statement semantic checking in
flang/lib/Semantics/check-data.{h,cpp} to use the compiler's
internal representation for typed expressions rather than working
on the raw parse tree. Saves the analyzed expressions for DATA
statement values as parse tree decorations because they'll soon be
needed in lowering. Corrects wording of some error messages.
Fixes a bug in constant expression checking: structure constructors
are not constant expressions if they set an allocatable component
to anything other than NULL.
Includes infrastructure changes to make this work, some renaming
to reflect the fact that the implied DO loop indices tracked by
expression analysis are not (just) from array constructors, remove
some dead code, and improve some comments.
Reviewers: tskeith, sscalpone, jdoerfert, DavidTruby, anchu-rajendran, schweitz
Reviewed By: tskeith, anchu-rajendran, schweitz
Subscribers: llvm-commits, flang-commits
Tags: #flang, #llvm
Differential Revision: https://reviews.llvm.org/D78834
2020-04-25 04:54:11 +08:00
|
|
|
explicit IsInitialDataTargetHelper(parser::ContextualMessages *m)
|
2020-03-29 12:00:16 +08:00
|
|
|
: Base{*this}, messages_{m} {}
|
2019-09-19 07:47:25 +08:00
|
|
|
|
2020-06-19 08:17:04 +08:00
|
|
|
bool emittedMessage() const { return emittedMessage_; }
|
|
|
|
|
2019-09-19 07:47:25 +08:00
|
|
|
bool operator()(const BOZLiteralConstant &) const { return false; }
|
|
|
|
bool operator()(const NullPointer &) const { return true; }
|
2020-03-29 12:00:16 +08:00
|
|
|
template <typename T> bool operator()(const Constant<T> &) const {
|
2019-09-19 07:47:25 +08:00
|
|
|
return false;
|
2019-09-19 06:43:12 +08:00
|
|
|
}
|
2020-06-19 08:17:04 +08:00
|
|
|
bool operator()(const semantics::Symbol &symbol) {
|
2021-04-01 00:12:28 +08:00
|
|
|
// This function checks only base symbols, not components.
|
2019-09-17 07:58:13 +08:00
|
|
|
const Symbol &ultimate{symbol.GetUltimate()};
|
2021-04-01 00:12:28 +08:00
|
|
|
if (const auto *assoc{
|
|
|
|
ultimate.detailsIf<semantics::AssocEntityDetails>()}) {
|
|
|
|
if (const auto &expr{assoc->expr()}) {
|
|
|
|
if (IsVariable(*expr)) {
|
|
|
|
return (*this)(*expr);
|
|
|
|
} else if (messages_) {
|
|
|
|
messages_->Say(
|
|
|
|
"An initial data target may not be an associated expression ('%s')"_err_en_US,
|
|
|
|
ultimate.name());
|
|
|
|
emittedMessage_ = true;
|
|
|
|
}
|
Rework DATA statement semantics to use typed expressions
Summary:
Updates recent work on DATA statement semantic checking in
flang/lib/Semantics/check-data.{h,cpp} to use the compiler's
internal representation for typed expressions rather than working
on the raw parse tree. Saves the analyzed expressions for DATA
statement values as parse tree decorations because they'll soon be
needed in lowering. Corrects wording of some error messages.
Fixes a bug in constant expression checking: structure constructors
are not constant expressions if they set an allocatable component
to anything other than NULL.
Includes infrastructure changes to make this work, some renaming
to reflect the fact that the implied DO loop indices tracked by
expression analysis are not (just) from array constructors, remove
some dead code, and improve some comments.
Reviewers: tskeith, sscalpone, jdoerfert, DavidTruby, anchu-rajendran, schweitz
Reviewed By: tskeith, anchu-rajendran, schweitz
Subscribers: llvm-commits, flang-commits
Tags: #flang, #llvm
Differential Revision: https://reviews.llvm.org/D78834
2020-04-25 04:54:11 +08:00
|
|
|
}
|
2020-06-19 08:17:04 +08:00
|
|
|
return false;
|
2019-09-17 07:58:13 +08:00
|
|
|
} else if (!ultimate.attrs().test(semantics::Attr::TARGET)) {
|
Rework DATA statement semantics to use typed expressions
Summary:
Updates recent work on DATA statement semantic checking in
flang/lib/Semantics/check-data.{h,cpp} to use the compiler's
internal representation for typed expressions rather than working
on the raw parse tree. Saves the analyzed expressions for DATA
statement values as parse tree decorations because they'll soon be
needed in lowering. Corrects wording of some error messages.
Fixes a bug in constant expression checking: structure constructors
are not constant expressions if they set an allocatable component
to anything other than NULL.
Includes infrastructure changes to make this work, some renaming
to reflect the fact that the implied DO loop indices tracked by
expression analysis are not (just) from array constructors, remove
some dead code, and improve some comments.
Reviewers: tskeith, sscalpone, jdoerfert, DavidTruby, anchu-rajendran, schweitz
Reviewed By: tskeith, anchu-rajendran, schweitz
Subscribers: llvm-commits, flang-commits
Tags: #flang, #llvm
Differential Revision: https://reviews.llvm.org/D78834
2020-04-25 04:54:11 +08:00
|
|
|
if (messages_) {
|
|
|
|
messages_->Say(
|
|
|
|
"An initial data target may not be a reference to an object '%s' that lacks the TARGET attribute"_err_en_US,
|
|
|
|
ultimate.name());
|
2020-06-19 08:17:04 +08:00
|
|
|
emittedMessage_ = true;
|
Rework DATA statement semantics to use typed expressions
Summary:
Updates recent work on DATA statement semantic checking in
flang/lib/Semantics/check-data.{h,cpp} to use the compiler's
internal representation for typed expressions rather than working
on the raw parse tree. Saves the analyzed expressions for DATA
statement values as parse tree decorations because they'll soon be
needed in lowering. Corrects wording of some error messages.
Fixes a bug in constant expression checking: structure constructors
are not constant expressions if they set an allocatable component
to anything other than NULL.
Includes infrastructure changes to make this work, some renaming
to reflect the fact that the implied DO loop indices tracked by
expression analysis are not (just) from array constructors, remove
some dead code, and improve some comments.
Reviewers: tskeith, sscalpone, jdoerfert, DavidTruby, anchu-rajendran, schweitz
Reviewed By: tskeith, anchu-rajendran, schweitz
Subscribers: llvm-commits, flang-commits
Tags: #flang, #llvm
Differential Revision: https://reviews.llvm.org/D78834
2020-04-25 04:54:11 +08:00
|
|
|
}
|
2020-06-19 08:17:04 +08:00
|
|
|
return false;
|
2019-09-17 07:58:13 +08:00
|
|
|
} else if (!IsSaved(ultimate)) {
|
Rework DATA statement semantics to use typed expressions
Summary:
Updates recent work on DATA statement semantic checking in
flang/lib/Semantics/check-data.{h,cpp} to use the compiler's
internal representation for typed expressions rather than working
on the raw parse tree. Saves the analyzed expressions for DATA
statement values as parse tree decorations because they'll soon be
needed in lowering. Corrects wording of some error messages.
Fixes a bug in constant expression checking: structure constructors
are not constant expressions if they set an allocatable component
to anything other than NULL.
Includes infrastructure changes to make this work, some renaming
to reflect the fact that the implied DO loop indices tracked by
expression analysis are not (just) from array constructors, remove
some dead code, and improve some comments.
Reviewers: tskeith, sscalpone, jdoerfert, DavidTruby, anchu-rajendran, schweitz
Reviewed By: tskeith, anchu-rajendran, schweitz
Subscribers: llvm-commits, flang-commits
Tags: #flang, #llvm
Differential Revision: https://reviews.llvm.org/D78834
2020-04-25 04:54:11 +08:00
|
|
|
if (messages_) {
|
|
|
|
messages_->Say(
|
|
|
|
"An initial data target may not be a reference to an object '%s' that lacks the SAVE attribute"_err_en_US,
|
|
|
|
ultimate.name());
|
2020-06-19 08:17:04 +08:00
|
|
|
emittedMessage_ = true;
|
Rework DATA statement semantics to use typed expressions
Summary:
Updates recent work on DATA statement semantic checking in
flang/lib/Semantics/check-data.{h,cpp} to use the compiler's
internal representation for typed expressions rather than working
on the raw parse tree. Saves the analyzed expressions for DATA
statement values as parse tree decorations because they'll soon be
needed in lowering. Corrects wording of some error messages.
Fixes a bug in constant expression checking: structure constructors
are not constant expressions if they set an allocatable component
to anything other than NULL.
Includes infrastructure changes to make this work, some renaming
to reflect the fact that the implied DO loop indices tracked by
expression analysis are not (just) from array constructors, remove
some dead code, and improve some comments.
Reviewers: tskeith, sscalpone, jdoerfert, DavidTruby, anchu-rajendran, schweitz
Reviewed By: tskeith, anchu-rajendran, schweitz
Subscribers: llvm-commits, flang-commits
Tags: #flang, #llvm
Differential Revision: https://reviews.llvm.org/D78834
2020-04-25 04:54:11 +08:00
|
|
|
}
|
2020-06-19 08:17:04 +08:00
|
|
|
return false;
|
2021-04-01 00:12:28 +08:00
|
|
|
} else {
|
|
|
|
return CheckVarOrComponent(ultimate);
|
2019-09-17 07:58:13 +08:00
|
|
|
}
|
|
|
|
}
|
2019-09-19 07:47:25 +08:00
|
|
|
bool operator()(const StaticDataObject &) const { return false; }
|
2020-08-26 00:40:20 +08:00
|
|
|
bool operator()(const TypeParamInquiry &) const { return false; }
|
2019-09-19 07:47:25 +08:00
|
|
|
bool operator()(const Triplet &x) const {
|
|
|
|
return IsConstantExpr(x.lower()) && IsConstantExpr(x.upper()) &&
|
|
|
|
IsConstantExpr(x.stride());
|
|
|
|
}
|
|
|
|
bool operator()(const Subscript &x) const {
|
2022-03-24 05:05:50 +08:00
|
|
|
return common::visit(common::visitors{
|
|
|
|
[&](const Triplet &t) { return (*this)(t); },
|
|
|
|
[&](const auto &y) {
|
|
|
|
return y.value().Rank() == 0 &&
|
|
|
|
IsConstantExpr(y.value());
|
|
|
|
},
|
|
|
|
},
|
2019-09-19 07:47:25 +08:00
|
|
|
x.u);
|
|
|
|
}
|
|
|
|
bool operator()(const CoarrayRef &) const { return false; }
|
2021-04-01 00:12:28 +08:00
|
|
|
bool operator()(const Component &x) {
|
|
|
|
return CheckVarOrComponent(x.GetLastSymbol()) && (*this)(x.base());
|
|
|
|
}
|
2019-09-19 07:47:25 +08:00
|
|
|
bool operator()(const Substring &x) const {
|
|
|
|
return IsConstantExpr(x.lower()) && IsConstantExpr(x.upper()) &&
|
|
|
|
(*this)(x.parent());
|
|
|
|
}
|
|
|
|
bool operator()(const DescriptorInquiry &) const { return false; }
|
2020-03-29 12:00:16 +08:00
|
|
|
template <typename T> bool operator()(const ArrayConstructor<T> &) const {
|
2019-09-19 07:47:25 +08:00
|
|
|
return false;
|
2019-09-19 06:43:12 +08:00
|
|
|
}
|
2019-09-19 07:47:25 +08:00
|
|
|
bool operator()(const StructureConstructor &) const { return false; }
|
2020-03-29 12:00:16 +08:00
|
|
|
template <typename D, typename R, typename... O>
|
2019-09-19 07:47:25 +08:00
|
|
|
bool operator()(const Operation<D, R, O...> &) const {
|
|
|
|
return false;
|
2019-09-19 06:43:12 +08:00
|
|
|
}
|
2020-03-29 12:00:16 +08:00
|
|
|
template <typename T> bool operator()(const Parentheses<T> &x) const {
|
2019-09-19 07:47:25 +08:00
|
|
|
return (*this)(x.left());
|
|
|
|
}
|
2022-02-08 07:34:54 +08:00
|
|
|
bool operator()(const ProcedureRef &x) const {
|
|
|
|
if (const SpecificIntrinsic * intrinsic{x.proc().GetSpecificIntrinsic()}) {
|
|
|
|
return intrinsic->characteristics.value().attrs.test(
|
|
|
|
characteristics::Procedure::Attr::NullPointer);
|
|
|
|
}
|
2020-11-18 05:15:34 +08:00
|
|
|
return false;
|
|
|
|
}
|
2019-09-19 07:47:25 +08:00
|
|
|
bool operator()(const Relational<SomeType> &) const { return false; }
|
[flang] New implementation for checks for constraints C741 through C750
Summary:
Most of these checks were already implemented, and I just added references to
them to the code and tests. Also, much of this code was already
reviewed in the old flang/f18 GitHub repository, but I didn't get to
merge it before we switched repositories.
I implemented the check for C747 to not allow coarray components in derived
types that are of type C_PTR, C_FUNPTR, or type TEAM_TYPE.
I implemented the check for C748 that requires a data component whose type has
a coarray ultimate component to be a nonpointer, nonallocatable scalar and not
be a coarray.
I implemented the check for C750 that adds additional restrictions to the
bounds expressions of a derived type component that's an array.
These bounds expressions are sepcification expressions as defined in
10.1.11. There was already code in lib/Evaluate/check-expression.cpp to
check semantics for specification expressions, but it did not check for
the extra requirements of C750.
C750 prohibits specification functions, the intrinsic functions
ALLOCATED, ASSOCIATED, EXTENDS_TYPE_OF, PRESENT, and SAME_TYPE_AS. It
also requires every specification inquiry reference to be a constant
expression, and requires that the value of the bound not depend on the
value of a variable.
To implement these additional checks, I added code to the intrinsic proc
table to get the intrinsic class of a procedure. I also added an
enumeration to distinguish between specification expressions for
derived type component bounds versus for type parameters. I then
changed the code to pass an enumeration value to
"CheckSpecificationExpr()" to indicate that the expression was a bounds
expression and used this value to determine whether to emit an error
message when violations of C750 are found.
I changed the implementation of IsPureProcedure() to handle statement
functions and changed some references in the code that tested for the
PURE attribute to call IsPureProcedure().
I also fixed some unrelated tests that got new errors when I implemented these
new checks.
Reviewers: tskeith, DavidTruby, sscalpone
Subscribers: jfb, llvm-commits
Tags: #llvm, #flang
Differential Revision: https://reviews.llvm.org/D79263
2020-05-02 04:00:28 +08:00
|
|
|
|
2019-09-17 07:58:13 +08:00
|
|
|
private:
|
2021-04-01 00:12:28 +08:00
|
|
|
bool CheckVarOrComponent(const semantics::Symbol &symbol) {
|
|
|
|
const Symbol &ultimate{symbol.GetUltimate()};
|
|
|
|
if (IsAllocatable(ultimate)) {
|
|
|
|
if (messages_) {
|
|
|
|
messages_->Say(
|
|
|
|
"An initial data target may not be a reference to an ALLOCATABLE '%s'"_err_en_US,
|
|
|
|
ultimate.name());
|
|
|
|
emittedMessage_ = true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
} else if (ultimate.Corank() > 0) {
|
|
|
|
if (messages_) {
|
|
|
|
messages_->Say(
|
|
|
|
"An initial data target may not be a reference to a coarray '%s'"_err_en_US,
|
|
|
|
ultimate.name());
|
|
|
|
emittedMessage_ = true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
Rework DATA statement semantics to use typed expressions
Summary:
Updates recent work on DATA statement semantic checking in
flang/lib/Semantics/check-data.{h,cpp} to use the compiler's
internal representation for typed expressions rather than working
on the raw parse tree. Saves the analyzed expressions for DATA
statement values as parse tree decorations because they'll soon be
needed in lowering. Corrects wording of some error messages.
Fixes a bug in constant expression checking: structure constructors
are not constant expressions if they set an allocatable component
to anything other than NULL.
Includes infrastructure changes to make this work, some renaming
to reflect the fact that the implied DO loop indices tracked by
expression analysis are not (just) from array constructors, remove
some dead code, and improve some comments.
Reviewers: tskeith, sscalpone, jdoerfert, DavidTruby, anchu-rajendran, schweitz
Reviewed By: tskeith, anchu-rajendran, schweitz
Subscribers: llvm-commits, flang-commits
Tags: #flang, #llvm
Differential Revision: https://reviews.llvm.org/D78834
2020-04-25 04:54:11 +08:00
|
|
|
parser::ContextualMessages *messages_;
|
2020-06-19 08:17:04 +08:00
|
|
|
bool emittedMessage_{false};
|
2019-09-19 07:47:25 +08:00
|
|
|
};
|
2019-09-19 06:43:12 +08:00
|
|
|
|
2019-09-17 07:58:13 +08:00
|
|
|
bool IsInitialDataTarget(
|
Rework DATA statement semantics to use typed expressions
Summary:
Updates recent work on DATA statement semantic checking in
flang/lib/Semantics/check-data.{h,cpp} to use the compiler's
internal representation for typed expressions rather than working
on the raw parse tree. Saves the analyzed expressions for DATA
statement values as parse tree decorations because they'll soon be
needed in lowering. Corrects wording of some error messages.
Fixes a bug in constant expression checking: structure constructors
are not constant expressions if they set an allocatable component
to anything other than NULL.
Includes infrastructure changes to make this work, some renaming
to reflect the fact that the implied DO loop indices tracked by
expression analysis are not (just) from array constructors, remove
some dead code, and improve some comments.
Reviewers: tskeith, sscalpone, jdoerfert, DavidTruby, anchu-rajendran, schweitz
Reviewed By: tskeith, anchu-rajendran, schweitz
Subscribers: llvm-commits, flang-commits
Tags: #flang, #llvm
Differential Revision: https://reviews.llvm.org/D78834
2020-04-25 04:54:11 +08:00
|
|
|
const Expr<SomeType> &x, parser::ContextualMessages *messages) {
|
2020-06-19 08:17:04 +08:00
|
|
|
IsInitialDataTargetHelper helper{messages};
|
|
|
|
bool result{helper(x)};
|
|
|
|
if (!result && messages && !helper.emittedMessage()) {
|
|
|
|
messages->Say(
|
|
|
|
"An initial data target must be a designator with constant subscripts"_err_en_US);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsInitialProcedureTarget(const semantics::Symbol &symbol) {
|
|
|
|
const auto &ultimate{symbol.GetUltimate()};
|
2022-03-24 05:05:50 +08:00
|
|
|
return common::visit(
|
2020-06-19 08:17:04 +08:00
|
|
|
common::visitors{
|
2021-07-23 05:53:50 +08:00
|
|
|
[](const semantics::SubprogramDetails &subp) {
|
|
|
|
return !subp.isDummy();
|
|
|
|
},
|
2020-06-19 08:17:04 +08:00
|
|
|
[](const semantics::SubprogramNameDetails &) { return true; },
|
|
|
|
[&](const semantics::ProcEntityDetails &proc) {
|
|
|
|
return !semantics::IsPointer(ultimate) && !proc.isDummy();
|
|
|
|
},
|
|
|
|
[](const auto &) { return false; },
|
|
|
|
},
|
|
|
|
ultimate.details());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsInitialProcedureTarget(const ProcedureDesignator &proc) {
|
|
|
|
if (const auto *intrin{proc.GetSpecificIntrinsic()}) {
|
|
|
|
return !intrin->isRestrictedSpecific;
|
|
|
|
} else if (proc.GetComponent()) {
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
return IsInitialProcedureTarget(DEREF(proc.GetSymbol()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsInitialProcedureTarget(const Expr<SomeType> &expr) {
|
|
|
|
if (const auto *proc{std::get_if<ProcedureDesignator>(&expr.u)}) {
|
|
|
|
return IsInitialProcedureTarget(*proc);
|
|
|
|
} else {
|
|
|
|
return IsNullPointer(expr);
|
|
|
|
}
|
2019-09-19 06:43:12 +08:00
|
|
|
}
|
|
|
|
|
2021-01-27 00:20:57 +08:00
|
|
|
class ArrayConstantBoundChanger {
|
[flang] Improve initializer semantics, esp. for component default values
This patch plugs many holes in static initializer semantics, improves error
messages for default initial values and other component properties in
parameterized derived type instantiations, and cleans up several small
issues noticed during development. We now do proper scalar expansion,
folding, and type, rank, and shape conformance checking for component
default initializers in derived types and PDT instantiations.
The initial values of named constants are now guaranteed to have been folded
when installed in the symbol table, and are no longer folded or
scalar-expanded at each use in expression folding. Semantics documentation
was extended with information about the various kinds of initializations
in Fortran and when each of them are processed in the compiler.
Some necessary concomitant changes have bulked this patch out a bit:
* contextual messages attachments, which are now produced for parameterized
derived type instantiations so that the user can figure out which
instance caused a problem with a component, have been added as part
of ContextualMessages, and their implementation was debugged
* several APIs in evaluate::characteristics was changed so that a FoldingContext
is passed as an argument rather than just its intrinsic procedure table;
this affected client call sites in many files
* new tools in Evaluate/check-expression.cpp to determine when an Expr
actually is a single constant value and to validate a non-pointer
variable initializer or object component default value
* shape conformance checking has additional arguments that control
whether scalar expansion is allowed
* several now-unused functions and data members noticed and removed
* several crashes and bogus errors exposed by testing this new code
were fixed
* a -fdebug-stack-trace option to enable LLVM's stack tracing on
a crash, which might be useful in the future
TL;DR: Initialization processing does more and takes place at the right
times for all of the various kinds of things that can be initialized.
Differential Review: https://reviews.llvm.org/D92783
2020-12-08 04:08:58 +08:00
|
|
|
public:
|
2021-01-27 00:20:57 +08:00
|
|
|
ArrayConstantBoundChanger(ConstantSubscripts &&lbounds)
|
|
|
|
: lbounds_{std::move(lbounds)} {}
|
|
|
|
|
|
|
|
template <typename A> A ChangeLbounds(A &&x) const {
|
|
|
|
return std::move(x); // default case
|
|
|
|
}
|
|
|
|
template <typename T> Constant<T> ChangeLbounds(Constant<T> &&x) {
|
|
|
|
x.set_lbounds(std::move(lbounds_));
|
|
|
|
return std::move(x);
|
|
|
|
}
|
|
|
|
template <typename T> Expr<T> ChangeLbounds(Parentheses<T> &&x) {
|
|
|
|
return ChangeLbounds(
|
|
|
|
std::move(x.left())); // Constant<> can be parenthesized
|
|
|
|
}
|
|
|
|
template <typename T> Expr<T> ChangeLbounds(Expr<T> &&x) {
|
2022-03-24 05:05:50 +08:00
|
|
|
return common::visit(
|
2021-01-27 00:20:57 +08:00
|
|
|
[&](auto &&x) { return Expr<T>{ChangeLbounds(std::move(x))}; },
|
|
|
|
std::move(x.u)); // recurse until we hit a constant
|
[flang] Improve initializer semantics, esp. for component default values
This patch plugs many holes in static initializer semantics, improves error
messages for default initial values and other component properties in
parameterized derived type instantiations, and cleans up several small
issues noticed during development. We now do proper scalar expansion,
folding, and type, rank, and shape conformance checking for component
default initializers in derived types and PDT instantiations.
The initial values of named constants are now guaranteed to have been folded
when installed in the symbol table, and are no longer folded or
scalar-expanded at each use in expression folding. Semantics documentation
was extended with information about the various kinds of initializations
in Fortran and when each of them are processed in the compiler.
Some necessary concomitant changes have bulked this patch out a bit:
* contextual messages attachments, which are now produced for parameterized
derived type instantiations so that the user can figure out which
instance caused a problem with a component, have been added as part
of ContextualMessages, and their implementation was debugged
* several APIs in evaluate::characteristics was changed so that a FoldingContext
is passed as an argument rather than just its intrinsic procedure table;
this affected client call sites in many files
* new tools in Evaluate/check-expression.cpp to determine when an Expr
actually is a single constant value and to validate a non-pointer
variable initializer or object component default value
* shape conformance checking has additional arguments that control
whether scalar expansion is allowed
* several now-unused functions and data members noticed and removed
* several crashes and bogus errors exposed by testing this new code
were fixed
* a -fdebug-stack-trace option to enable LLVM's stack tracing on
a crash, which might be useful in the future
TL;DR: Initialization processing does more and takes place at the right
times for all of the various kinds of things that can be initialized.
Differential Review: https://reviews.llvm.org/D92783
2020-12-08 04:08:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2021-01-27 00:20:57 +08:00
|
|
|
ConstantSubscripts &&lbounds_;
|
[flang] Improve initializer semantics, esp. for component default values
This patch plugs many holes in static initializer semantics, improves error
messages for default initial values and other component properties in
parameterized derived type instantiations, and cleans up several small
issues noticed during development. We now do proper scalar expansion,
folding, and type, rank, and shape conformance checking for component
default initializers in derived types and PDT instantiations.
The initial values of named constants are now guaranteed to have been folded
when installed in the symbol table, and are no longer folded or
scalar-expanded at each use in expression folding. Semantics documentation
was extended with information about the various kinds of initializations
in Fortran and when each of them are processed in the compiler.
Some necessary concomitant changes have bulked this patch out a bit:
* contextual messages attachments, which are now produced for parameterized
derived type instantiations so that the user can figure out which
instance caused a problem with a component, have been added as part
of ContextualMessages, and their implementation was debugged
* several APIs in evaluate::characteristics was changed so that a FoldingContext
is passed as an argument rather than just its intrinsic procedure table;
this affected client call sites in many files
* new tools in Evaluate/check-expression.cpp to determine when an Expr
actually is a single constant value and to validate a non-pointer
variable initializer or object component default value
* shape conformance checking has additional arguments that control
whether scalar expansion is allowed
* several now-unused functions and data members noticed and removed
* several crashes and bogus errors exposed by testing this new code
were fixed
* a -fdebug-stack-trace option to enable LLVM's stack tracing on
a crash, which might be useful in the future
TL;DR: Initialization processing does more and takes place at the right
times for all of the various kinds of things that can be initialized.
Differential Review: https://reviews.llvm.org/D92783
2020-12-08 04:08:58 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
// Converts, folds, and then checks type, rank, and shape of an
|
|
|
|
// initialization expression for a named constant, a non-pointer
|
2022-01-05 01:25:40 +08:00
|
|
|
// variable static initialization, a component default initializer,
|
[flang] Improve initializer semantics, esp. for component default values
This patch plugs many holes in static initializer semantics, improves error
messages for default initial values and other component properties in
parameterized derived type instantiations, and cleans up several small
issues noticed during development. We now do proper scalar expansion,
folding, and type, rank, and shape conformance checking for component
default initializers in derived types and PDT instantiations.
The initial values of named constants are now guaranteed to have been folded
when installed in the symbol table, and are no longer folded or
scalar-expanded at each use in expression folding. Semantics documentation
was extended with information about the various kinds of initializations
in Fortran and when each of them are processed in the compiler.
Some necessary concomitant changes have bulked this patch out a bit:
* contextual messages attachments, which are now produced for parameterized
derived type instantiations so that the user can figure out which
instance caused a problem with a component, have been added as part
of ContextualMessages, and their implementation was debugged
* several APIs in evaluate::characteristics was changed so that a FoldingContext
is passed as an argument rather than just its intrinsic procedure table;
this affected client call sites in many files
* new tools in Evaluate/check-expression.cpp to determine when an Expr
actually is a single constant value and to validate a non-pointer
variable initializer or object component default value
* shape conformance checking has additional arguments that control
whether scalar expansion is allowed
* several now-unused functions and data members noticed and removed
* several crashes and bogus errors exposed by testing this new code
were fixed
* a -fdebug-stack-trace option to enable LLVM's stack tracing on
a crash, which might be useful in the future
TL;DR: Initialization processing does more and takes place at the right
times for all of the various kinds of things that can be initialized.
Differential Review: https://reviews.llvm.org/D92783
2020-12-08 04:08:58 +08:00
|
|
|
// a type parameter default value, or instantiated type parameter value.
|
|
|
|
std::optional<Expr<SomeType>> NonPointerInitializationExpr(const Symbol &symbol,
|
|
|
|
Expr<SomeType> &&x, FoldingContext &context,
|
|
|
|
const semantics::Scope *instantiation) {
|
|
|
|
CHECK(!IsPointer(symbol));
|
|
|
|
if (auto symTS{
|
|
|
|
characteristics::TypeAndShape::Characterize(symbol, context)}) {
|
|
|
|
auto xType{x.GetType()};
|
2022-01-05 01:25:40 +08:00
|
|
|
auto converted{ConvertToType(symTS->type(), Expr<SomeType>{x})};
|
|
|
|
if (!converted &&
|
|
|
|
symbol.owner().context().IsEnabled(
|
|
|
|
common::LanguageFeature::LogicalIntegerAssignment)) {
|
|
|
|
converted = DataConstantConversionExtension(context, symTS->type(), x);
|
|
|
|
if (converted &&
|
|
|
|
symbol.owner().context().ShouldWarn(
|
|
|
|
common::LanguageFeature::LogicalIntegerAssignment)) {
|
|
|
|
context.messages().Say(
|
2022-03-08 05:57:37 +08:00
|
|
|
"nonstandard usage: initialization of %s with %s"_port_en_US,
|
2022-01-05 01:25:40 +08:00
|
|
|
symTS->type().AsFortran(), x.GetType().value().AsFortran());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (converted) {
|
[flang] Improve initializer semantics, esp. for component default values
This patch plugs many holes in static initializer semantics, improves error
messages for default initial values and other component properties in
parameterized derived type instantiations, and cleans up several small
issues noticed during development. We now do proper scalar expansion,
folding, and type, rank, and shape conformance checking for component
default initializers in derived types and PDT instantiations.
The initial values of named constants are now guaranteed to have been folded
when installed in the symbol table, and are no longer folded or
scalar-expanded at each use in expression folding. Semantics documentation
was extended with information about the various kinds of initializations
in Fortran and when each of them are processed in the compiler.
Some necessary concomitant changes have bulked this patch out a bit:
* contextual messages attachments, which are now produced for parameterized
derived type instantiations so that the user can figure out which
instance caused a problem with a component, have been added as part
of ContextualMessages, and their implementation was debugged
* several APIs in evaluate::characteristics was changed so that a FoldingContext
is passed as an argument rather than just its intrinsic procedure table;
this affected client call sites in many files
* new tools in Evaluate/check-expression.cpp to determine when an Expr
actually is a single constant value and to validate a non-pointer
variable initializer or object component default value
* shape conformance checking has additional arguments that control
whether scalar expansion is allowed
* several now-unused functions and data members noticed and removed
* several crashes and bogus errors exposed by testing this new code
were fixed
* a -fdebug-stack-trace option to enable LLVM's stack tracing on
a crash, which might be useful in the future
TL;DR: Initialization processing does more and takes place at the right
times for all of the various kinds of things that can be initialized.
Differential Review: https://reviews.llvm.org/D92783
2020-12-08 04:08:58 +08:00
|
|
|
auto folded{Fold(context, std::move(*converted))};
|
|
|
|
if (IsActuallyConstant(folded)) {
|
|
|
|
int symRank{GetRank(symTS->shape())};
|
|
|
|
if (IsImpliedShape(symbol)) {
|
|
|
|
if (folded.Rank() == symRank) {
|
|
|
|
return {std::move(folded)};
|
|
|
|
} else {
|
|
|
|
context.messages().Say(
|
|
|
|
"Implied-shape parameter '%s' has rank %d but its initializer has rank %d"_err_en_US,
|
|
|
|
symbol.name(), symRank, folded.Rank());
|
|
|
|
}
|
|
|
|
} else if (auto extents{AsConstantExtents(context, symTS->shape())}) {
|
2021-01-27 00:20:57 +08:00
|
|
|
if (folded.Rank() == 0 && symRank == 0) {
|
|
|
|
// symbol and constant are both scalars
|
|
|
|
return {std::move(folded)};
|
|
|
|
} else if (folded.Rank() == 0 && symRank > 0) {
|
|
|
|
// expand the scalar constant to an array
|
[flang] Improve initializer semantics, esp. for component default values
This patch plugs many holes in static initializer semantics, improves error
messages for default initial values and other component properties in
parameterized derived type instantiations, and cleans up several small
issues noticed during development. We now do proper scalar expansion,
folding, and type, rank, and shape conformance checking for component
default initializers in derived types and PDT instantiations.
The initial values of named constants are now guaranteed to have been folded
when installed in the symbol table, and are no longer folded or
scalar-expanded at each use in expression folding. Semantics documentation
was extended with information about the various kinds of initializations
in Fortran and when each of them are processed in the compiler.
Some necessary concomitant changes have bulked this patch out a bit:
* contextual messages attachments, which are now produced for parameterized
derived type instantiations so that the user can figure out which
instance caused a problem with a component, have been added as part
of ContextualMessages, and their implementation was debugged
* several APIs in evaluate::characteristics was changed so that a FoldingContext
is passed as an argument rather than just its intrinsic procedure table;
this affected client call sites in many files
* new tools in Evaluate/check-expression.cpp to determine when an Expr
actually is a single constant value and to validate a non-pointer
variable initializer or object component default value
* shape conformance checking has additional arguments that control
whether scalar expansion is allowed
* several now-unused functions and data members noticed and removed
* several crashes and bogus errors exposed by testing this new code
were fixed
* a -fdebug-stack-trace option to enable LLVM's stack tracing on
a crash, which might be useful in the future
TL;DR: Initialization processing does more and takes place at the right
times for all of the various kinds of things that can be initialized.
Differential Review: https://reviews.llvm.org/D92783
2020-12-08 04:08:58 +08:00
|
|
|
return ScalarConstantExpander{std::move(*extents),
|
|
|
|
AsConstantExtents(
|
2022-03-10 05:43:54 +08:00
|
|
|
context, GetRawLowerBounds(context, NamedEntity{symbol}))}
|
[flang] Improve initializer semantics, esp. for component default values
This patch plugs many holes in static initializer semantics, improves error
messages for default initial values and other component properties in
parameterized derived type instantiations, and cleans up several small
issues noticed during development. We now do proper scalar expansion,
folding, and type, rank, and shape conformance checking for component
default initializers in derived types and PDT instantiations.
The initial values of named constants are now guaranteed to have been folded
when installed in the symbol table, and are no longer folded or
scalar-expanded at each use in expression folding. Semantics documentation
was extended with information about the various kinds of initializations
in Fortran and when each of them are processed in the compiler.
Some necessary concomitant changes have bulked this patch out a bit:
* contextual messages attachments, which are now produced for parameterized
derived type instantiations so that the user can figure out which
instance caused a problem with a component, have been added as part
of ContextualMessages, and their implementation was debugged
* several APIs in evaluate::characteristics was changed so that a FoldingContext
is passed as an argument rather than just its intrinsic procedure table;
this affected client call sites in many files
* new tools in Evaluate/check-expression.cpp to determine when an Expr
actually is a single constant value and to validate a non-pointer
variable initializer or object component default value
* shape conformance checking has additional arguments that control
whether scalar expansion is allowed
* several now-unused functions and data members noticed and removed
* several crashes and bogus errors exposed by testing this new code
were fixed
* a -fdebug-stack-trace option to enable LLVM's stack tracing on
a crash, which might be useful in the future
TL;DR: Initialization processing does more and takes place at the right
times for all of the various kinds of things that can be initialized.
Differential Review: https://reviews.llvm.org/D92783
2020-12-08 04:08:58 +08:00
|
|
|
.Expand(std::move(folded));
|
|
|
|
} else if (auto resultShape{GetShape(context, folded)}) {
|
|
|
|
if (CheckConformance(context.messages(), symTS->shape(),
|
2021-06-04 06:48:16 +08:00
|
|
|
*resultShape, CheckConformanceFlags::None,
|
|
|
|
"initialized object", "initialization expression")
|
|
|
|
.value_or(false /*fail if not known now to conform*/)) {
|
2021-01-27 00:20:57 +08:00
|
|
|
// make a constant array with adjusted lower bounds
|
|
|
|
return ArrayConstantBoundChanger{
|
2022-03-10 05:43:54 +08:00
|
|
|
std::move(*AsConstantExtents(context,
|
|
|
|
GetRawLowerBounds(context, NamedEntity{symbol})))}
|
2021-01-27 00:20:57 +08:00
|
|
|
.ChangeLbounds(std::move(folded));
|
[flang] Improve initializer semantics, esp. for component default values
This patch plugs many holes in static initializer semantics, improves error
messages for default initial values and other component properties in
parameterized derived type instantiations, and cleans up several small
issues noticed during development. We now do proper scalar expansion,
folding, and type, rank, and shape conformance checking for component
default initializers in derived types and PDT instantiations.
The initial values of named constants are now guaranteed to have been folded
when installed in the symbol table, and are no longer folded or
scalar-expanded at each use in expression folding. Semantics documentation
was extended with information about the various kinds of initializations
in Fortran and when each of them are processed in the compiler.
Some necessary concomitant changes have bulked this patch out a bit:
* contextual messages attachments, which are now produced for parameterized
derived type instantiations so that the user can figure out which
instance caused a problem with a component, have been added as part
of ContextualMessages, and their implementation was debugged
* several APIs in evaluate::characteristics was changed so that a FoldingContext
is passed as an argument rather than just its intrinsic procedure table;
this affected client call sites in many files
* new tools in Evaluate/check-expression.cpp to determine when an Expr
actually is a single constant value and to validate a non-pointer
variable initializer or object component default value
* shape conformance checking has additional arguments that control
whether scalar expansion is allowed
* several now-unused functions and data members noticed and removed
* several crashes and bogus errors exposed by testing this new code
were fixed
* a -fdebug-stack-trace option to enable LLVM's stack tracing on
a crash, which might be useful in the future
TL;DR: Initialization processing does more and takes place at the right
times for all of the various kinds of things that can be initialized.
Differential Review: https://reviews.llvm.org/D92783
2020-12-08 04:08:58 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (IsNamedConstant(symbol)) {
|
|
|
|
if (IsExplicitShape(symbol)) {
|
|
|
|
context.messages().Say(
|
|
|
|
"Named constant '%s' array must have constant shape"_err_en_US,
|
|
|
|
symbol.name());
|
|
|
|
} else {
|
|
|
|
// Declaration checking handles other cases
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
context.messages().Say(
|
|
|
|
"Shape of initialized object '%s' must be constant"_err_en_US,
|
|
|
|
symbol.name());
|
|
|
|
}
|
|
|
|
} else if (IsErrorExpr(folded)) {
|
|
|
|
} else if (IsLenTypeParameter(symbol)) {
|
|
|
|
return {std::move(folded)};
|
|
|
|
} else if (IsKindTypeParameter(symbol)) {
|
|
|
|
if (instantiation) {
|
|
|
|
context.messages().Say(
|
|
|
|
"Value of kind type parameter '%s' (%s) must be a scalar INTEGER constant"_err_en_US,
|
|
|
|
symbol.name(), folded.AsFortran());
|
|
|
|
} else {
|
|
|
|
return {std::move(folded)};
|
|
|
|
}
|
|
|
|
} else if (IsNamedConstant(symbol)) {
|
|
|
|
context.messages().Say(
|
|
|
|
"Value of named constant '%s' (%s) cannot be computed as a constant value"_err_en_US,
|
|
|
|
symbol.name(), folded.AsFortran());
|
|
|
|
} else {
|
|
|
|
context.messages().Say(
|
|
|
|
"Initialization expression for '%s' (%s) cannot be computed as a constant value"_err_en_US,
|
|
|
|
symbol.name(), folded.AsFortran());
|
|
|
|
}
|
|
|
|
} else if (xType) {
|
|
|
|
context.messages().Say(
|
|
|
|
"Initialization expression cannot be converted to declared type of '%s' from %s"_err_en_US,
|
|
|
|
symbol.name(), xType->AsFortran());
|
|
|
|
} else {
|
|
|
|
context.messages().Say(
|
|
|
|
"Initialization expression cannot be converted to declared type of '%s'"_err_en_US,
|
|
|
|
symbol.name());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
2019-09-19 06:43:12 +08:00
|
|
|
// Specification expression validation (10.1.11(2), C1010)
|
2019-09-21 05:28:15 +08:00
|
|
|
class CheckSpecificationExprHelper
|
2020-03-29 12:00:16 +08:00
|
|
|
: public AnyTraverse<CheckSpecificationExprHelper,
|
|
|
|
std::optional<std::string>> {
|
2019-09-21 05:28:15 +08:00
|
|
|
public:
|
2019-09-21 00:46:00 +08:00
|
|
|
using Result = std::optional<std::string>;
|
|
|
|
using Base = AnyTraverse<CheckSpecificationExprHelper, Result>;
|
2020-05-13 00:53:58 +08:00
|
|
|
explicit CheckSpecificationExprHelper(
|
[flang] Improve initializer semantics, esp. for component default values
This patch plugs many holes in static initializer semantics, improves error
messages for default initial values and other component properties in
parameterized derived type instantiations, and cleans up several small
issues noticed during development. We now do proper scalar expansion,
folding, and type, rank, and shape conformance checking for component
default initializers in derived types and PDT instantiations.
The initial values of named constants are now guaranteed to have been folded
when installed in the symbol table, and are no longer folded or
scalar-expanded at each use in expression folding. Semantics documentation
was extended with information about the various kinds of initializations
in Fortran and when each of them are processed in the compiler.
Some necessary concomitant changes have bulked this patch out a bit:
* contextual messages attachments, which are now produced for parameterized
derived type instantiations so that the user can figure out which
instance caused a problem with a component, have been added as part
of ContextualMessages, and their implementation was debugged
* several APIs in evaluate::characteristics was changed so that a FoldingContext
is passed as an argument rather than just its intrinsic procedure table;
this affected client call sites in many files
* new tools in Evaluate/check-expression.cpp to determine when an Expr
actually is a single constant value and to validate a non-pointer
variable initializer or object component default value
* shape conformance checking has additional arguments that control
whether scalar expansion is allowed
* several now-unused functions and data members noticed and removed
* several crashes and bogus errors exposed by testing this new code
were fixed
* a -fdebug-stack-trace option to enable LLVM's stack tracing on
a crash, which might be useful in the future
TL;DR: Initialization processing does more and takes place at the right
times for all of the various kinds of things that can be initialized.
Differential Review: https://reviews.llvm.org/D92783
2020-12-08 04:08:58 +08:00
|
|
|
const semantics::Scope &s, FoldingContext &context)
|
|
|
|
: Base{*this}, scope_{s}, context_{context} {}
|
2019-09-19 06:43:12 +08:00
|
|
|
using Base::operator();
|
|
|
|
|
2019-09-21 00:46:00 +08:00
|
|
|
Result operator()(const CoarrayRef &) const { return "coindexed reference"; }
|
2019-09-19 06:43:12 +08:00
|
|
|
|
2019-09-21 00:46:00 +08:00
|
|
|
Result operator()(const semantics::Symbol &symbol) const {
|
2020-11-12 03:05:23 +08:00
|
|
|
const auto &ultimate{symbol.GetUltimate()};
|
2021-04-01 00:12:28 +08:00
|
|
|
if (const auto *assoc{
|
|
|
|
ultimate.detailsIf<semantics::AssocEntityDetails>()}) {
|
|
|
|
return (*this)(assoc->expr());
|
|
|
|
} else if (semantics::IsNamedConstant(ultimate) ||
|
|
|
|
ultimate.owner().IsModule() || ultimate.owner().IsSubmodule()) {
|
2019-09-21 00:46:00 +08:00
|
|
|
return std::nullopt;
|
2020-11-12 03:05:23 +08:00
|
|
|
} else if (scope_.IsDerivedType() &&
|
|
|
|
IsVariableName(ultimate)) { // C750, C754
|
2020-05-13 00:53:58 +08:00
|
|
|
return "derived type component or type parameter value not allowed to "
|
|
|
|
"reference variable '"s +
|
2020-11-12 03:05:23 +08:00
|
|
|
ultimate.name().ToString() + "'";
|
|
|
|
} else if (IsDummy(ultimate)) {
|
|
|
|
if (ultimate.attrs().test(semantics::Attr::OPTIONAL)) {
|
2019-09-21 00:46:00 +08:00
|
|
|
return "reference to OPTIONAL dummy argument '"s +
|
2020-11-12 03:05:23 +08:00
|
|
|
ultimate.name().ToString() + "'";
|
|
|
|
} else if (ultimate.attrs().test(semantics::Attr::INTENT_OUT)) {
|
2019-09-21 00:46:00 +08:00
|
|
|
return "reference to INTENT(OUT) dummy argument '"s +
|
2020-11-12 03:05:23 +08:00
|
|
|
ultimate.name().ToString() + "'";
|
|
|
|
} else if (ultimate.has<semantics::ObjectEntityDetails>()) {
|
2019-09-21 00:46:00 +08:00
|
|
|
return std::nullopt;
|
2019-09-19 06:43:12 +08:00
|
|
|
} else {
|
2019-09-21 00:46:00 +08:00
|
|
|
return "dummy procedure argument";
|
2019-09-19 06:43:12 +08:00
|
|
|
}
|
2022-02-09 02:08:23 +08:00
|
|
|
} else if (&symbol.owner() != &scope_ || &ultimate.owner() != &scope_) {
|
|
|
|
return std::nullopt; // host association is in play
|
2019-09-19 06:43:12 +08:00
|
|
|
} else if (const auto *object{
|
2020-11-12 03:05:23 +08:00
|
|
|
ultimate.detailsIf<semantics::ObjectEntityDetails>()}) {
|
2019-11-10 01:29:31 +08:00
|
|
|
if (object->commonBlock()) {
|
2019-09-21 00:46:00 +08:00
|
|
|
return std::nullopt;
|
2019-09-19 06:43:12 +08:00
|
|
|
}
|
|
|
|
}
|
2020-11-12 03:05:23 +08:00
|
|
|
return "reference to local entity '"s + ultimate.name().ToString() + "'";
|
2019-09-19 06:43:12 +08:00
|
|
|
}
|
|
|
|
|
2019-09-21 00:46:00 +08:00
|
|
|
Result operator()(const Component &x) const {
|
2019-09-19 06:43:12 +08:00
|
|
|
// Don't look at the component symbol.
|
|
|
|
return (*this)(x.base());
|
|
|
|
}
|
2019-09-21 05:28:15 +08:00
|
|
|
Result operator()(const DescriptorInquiry &) const {
|
|
|
|
// Subtle: Uses of SIZE(), LBOUND(), &c. that are valid in specification
|
|
|
|
// expressions will have been converted to expressions over descriptor
|
|
|
|
// inquiries by Fold().
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
2019-09-19 06:43:12 +08:00
|
|
|
|
2020-08-26 00:40:20 +08:00
|
|
|
Result operator()(const TypeParamInquiry &inq) const {
|
[flang] New implementation for checks for constraints C741 through C750
Summary:
Most of these checks were already implemented, and I just added references to
them to the code and tests. Also, much of this code was already
reviewed in the old flang/f18 GitHub repository, but I didn't get to
merge it before we switched repositories.
I implemented the check for C747 to not allow coarray components in derived
types that are of type C_PTR, C_FUNPTR, or type TEAM_TYPE.
I implemented the check for C748 that requires a data component whose type has
a coarray ultimate component to be a nonpointer, nonallocatable scalar and not
be a coarray.
I implemented the check for C750 that adds additional restrictions to the
bounds expressions of a derived type component that's an array.
These bounds expressions are sepcification expressions as defined in
10.1.11. There was already code in lib/Evaluate/check-expression.cpp to
check semantics for specification expressions, but it did not check for
the extra requirements of C750.
C750 prohibits specification functions, the intrinsic functions
ALLOCATED, ASSOCIATED, EXTENDS_TYPE_OF, PRESENT, and SAME_TYPE_AS. It
also requires every specification inquiry reference to be a constant
expression, and requires that the value of the bound not depend on the
value of a variable.
To implement these additional checks, I added code to the intrinsic proc
table to get the intrinsic class of a procedure. I also added an
enumeration to distinguish between specification expressions for
derived type component bounds versus for type parameters. I then
changed the code to pass an enumeration value to
"CheckSpecificationExpr()" to indicate that the expression was a bounds
expression and used this value to determine whether to emit an error
message when violations of C750 are found.
I changed the implementation of IsPureProcedure() to handle statement
functions and changed some references in the code that tested for the
PURE attribute to call IsPureProcedure().
I also fixed some unrelated tests that got new errors when I implemented these
new checks.
Reviewers: tskeith, DavidTruby, sscalpone
Subscribers: jfb, llvm-commits
Tags: #llvm, #flang
Differential Revision: https://reviews.llvm.org/D79263
2020-05-02 04:00:28 +08:00
|
|
|
if (scope_.IsDerivedType() && !IsConstantExpr(inq) &&
|
2020-09-01 02:54:48 +08:00
|
|
|
inq.base() /* X%T, not local T */) { // C750, C754
|
2020-05-13 00:53:58 +08:00
|
|
|
return "non-constant reference to a type parameter inquiry not "
|
|
|
|
"allowed for derived type components or type parameter values";
|
[flang] New implementation for checks for constraints C741 through C750
Summary:
Most of these checks were already implemented, and I just added references to
them to the code and tests. Also, much of this code was already
reviewed in the old flang/f18 GitHub repository, but I didn't get to
merge it before we switched repositories.
I implemented the check for C747 to not allow coarray components in derived
types that are of type C_PTR, C_FUNPTR, or type TEAM_TYPE.
I implemented the check for C748 that requires a data component whose type has
a coarray ultimate component to be a nonpointer, nonallocatable scalar and not
be a coarray.
I implemented the check for C750 that adds additional restrictions to the
bounds expressions of a derived type component that's an array.
These bounds expressions are sepcification expressions as defined in
10.1.11. There was already code in lib/Evaluate/check-expression.cpp to
check semantics for specification expressions, but it did not check for
the extra requirements of C750.
C750 prohibits specification functions, the intrinsic functions
ALLOCATED, ASSOCIATED, EXTENDS_TYPE_OF, PRESENT, and SAME_TYPE_AS. It
also requires every specification inquiry reference to be a constant
expression, and requires that the value of the bound not depend on the
value of a variable.
To implement these additional checks, I added code to the intrinsic proc
table to get the intrinsic class of a procedure. I also added an
enumeration to distinguish between specification expressions for
derived type component bounds versus for type parameters. I then
changed the code to pass an enumeration value to
"CheckSpecificationExpr()" to indicate that the expression was a bounds
expression and used this value to determine whether to emit an error
message when violations of C750 are found.
I changed the implementation of IsPureProcedure() to handle statement
functions and changed some references in the code that tested for the
PURE attribute to call IsPureProcedure().
I also fixed some unrelated tests that got new errors when I implemented these
new checks.
Reviewers: tskeith, DavidTruby, sscalpone
Subscribers: jfb, llvm-commits
Tags: #llvm, #flang
Differential Revision: https://reviews.llvm.org/D79263
2020-05-02 04:00:28 +08:00
|
|
|
}
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
2022-02-08 07:34:54 +08:00
|
|
|
Result operator()(const ProcedureRef &x) const {
|
2019-09-19 06:43:12 +08:00
|
|
|
if (const auto *symbol{x.proc().GetSymbol()}) {
|
2021-01-16 03:52:10 +08:00
|
|
|
const Symbol &ultimate{symbol->GetUltimate()};
|
|
|
|
if (!semantics::IsPureProcedure(ultimate)) {
|
|
|
|
return "reference to impure function '"s + ultimate.name().ToString() +
|
2019-09-21 00:46:00 +08:00
|
|
|
"'";
|
2019-09-19 06:43:12 +08:00
|
|
|
}
|
2021-01-16 03:52:10 +08:00
|
|
|
if (semantics::IsStmtFunction(ultimate)) {
|
[flang] New implementation for checks for constraints C741 through C750
Summary:
Most of these checks were already implemented, and I just added references to
them to the code and tests. Also, much of this code was already
reviewed in the old flang/f18 GitHub repository, but I didn't get to
merge it before we switched repositories.
I implemented the check for C747 to not allow coarray components in derived
types that are of type C_PTR, C_FUNPTR, or type TEAM_TYPE.
I implemented the check for C748 that requires a data component whose type has
a coarray ultimate component to be a nonpointer, nonallocatable scalar and not
be a coarray.
I implemented the check for C750 that adds additional restrictions to the
bounds expressions of a derived type component that's an array.
These bounds expressions are sepcification expressions as defined in
10.1.11. There was already code in lib/Evaluate/check-expression.cpp to
check semantics for specification expressions, but it did not check for
the extra requirements of C750.
C750 prohibits specification functions, the intrinsic functions
ALLOCATED, ASSOCIATED, EXTENDS_TYPE_OF, PRESENT, and SAME_TYPE_AS. It
also requires every specification inquiry reference to be a constant
expression, and requires that the value of the bound not depend on the
value of a variable.
To implement these additional checks, I added code to the intrinsic proc
table to get the intrinsic class of a procedure. I also added an
enumeration to distinguish between specification expressions for
derived type component bounds versus for type parameters. I then
changed the code to pass an enumeration value to
"CheckSpecificationExpr()" to indicate that the expression was a bounds
expression and used this value to determine whether to emit an error
message when violations of C750 are found.
I changed the implementation of IsPureProcedure() to handle statement
functions and changed some references in the code that tested for the
PURE attribute to call IsPureProcedure().
I also fixed some unrelated tests that got new errors when I implemented these
new checks.
Reviewers: tskeith, DavidTruby, sscalpone
Subscribers: jfb, llvm-commits
Tags: #llvm, #flang
Differential Revision: https://reviews.llvm.org/D79263
2020-05-02 04:00:28 +08:00
|
|
|
return "reference to statement function '"s +
|
2021-01-16 03:52:10 +08:00
|
|
|
ultimate.name().ToString() + "'";
|
[flang] New implementation for checks for constraints C741 through C750
Summary:
Most of these checks were already implemented, and I just added references to
them to the code and tests. Also, much of this code was already
reviewed in the old flang/f18 GitHub repository, but I didn't get to
merge it before we switched repositories.
I implemented the check for C747 to not allow coarray components in derived
types that are of type C_PTR, C_FUNPTR, or type TEAM_TYPE.
I implemented the check for C748 that requires a data component whose type has
a coarray ultimate component to be a nonpointer, nonallocatable scalar and not
be a coarray.
I implemented the check for C750 that adds additional restrictions to the
bounds expressions of a derived type component that's an array.
These bounds expressions are sepcification expressions as defined in
10.1.11. There was already code in lib/Evaluate/check-expression.cpp to
check semantics for specification expressions, but it did not check for
the extra requirements of C750.
C750 prohibits specification functions, the intrinsic functions
ALLOCATED, ASSOCIATED, EXTENDS_TYPE_OF, PRESENT, and SAME_TYPE_AS. It
also requires every specification inquiry reference to be a constant
expression, and requires that the value of the bound not depend on the
value of a variable.
To implement these additional checks, I added code to the intrinsic proc
table to get the intrinsic class of a procedure. I also added an
enumeration to distinguish between specification expressions for
derived type component bounds versus for type parameters. I then
changed the code to pass an enumeration value to
"CheckSpecificationExpr()" to indicate that the expression was a bounds
expression and used this value to determine whether to emit an error
message when violations of C750 are found.
I changed the implementation of IsPureProcedure() to handle statement
functions and changed some references in the code that tested for the
PURE attribute to call IsPureProcedure().
I also fixed some unrelated tests that got new errors when I implemented these
new checks.
Reviewers: tskeith, DavidTruby, sscalpone
Subscribers: jfb, llvm-commits
Tags: #llvm, #flang
Differential Revision: https://reviews.llvm.org/D79263
2020-05-02 04:00:28 +08:00
|
|
|
}
|
2020-05-13 00:53:58 +08:00
|
|
|
if (scope_.IsDerivedType()) { // C750, C754
|
2021-01-16 03:52:10 +08:00
|
|
|
return "reference to function '"s + ultimate.name().ToString() +
|
2020-05-13 00:53:58 +08:00
|
|
|
"' not allowed for derived type components or type parameter"
|
|
|
|
" values";
|
[flang] New implementation for checks for constraints C741 through C750
Summary:
Most of these checks were already implemented, and I just added references to
them to the code and tests. Also, much of this code was already
reviewed in the old flang/f18 GitHub repository, but I didn't get to
merge it before we switched repositories.
I implemented the check for C747 to not allow coarray components in derived
types that are of type C_PTR, C_FUNPTR, or type TEAM_TYPE.
I implemented the check for C748 that requires a data component whose type has
a coarray ultimate component to be a nonpointer, nonallocatable scalar and not
be a coarray.
I implemented the check for C750 that adds additional restrictions to the
bounds expressions of a derived type component that's an array.
These bounds expressions are sepcification expressions as defined in
10.1.11. There was already code in lib/Evaluate/check-expression.cpp to
check semantics for specification expressions, but it did not check for
the extra requirements of C750.
C750 prohibits specification functions, the intrinsic functions
ALLOCATED, ASSOCIATED, EXTENDS_TYPE_OF, PRESENT, and SAME_TYPE_AS. It
also requires every specification inquiry reference to be a constant
expression, and requires that the value of the bound not depend on the
value of a variable.
To implement these additional checks, I added code to the intrinsic proc
table to get the intrinsic class of a procedure. I also added an
enumeration to distinguish between specification expressions for
derived type component bounds versus for type parameters. I then
changed the code to pass an enumeration value to
"CheckSpecificationExpr()" to indicate that the expression was a bounds
expression and used this value to determine whether to emit an error
message when violations of C750 are found.
I changed the implementation of IsPureProcedure() to handle statement
functions and changed some references in the code that tested for the
PURE attribute to call IsPureProcedure().
I also fixed some unrelated tests that got new errors when I implemented these
new checks.
Reviewers: tskeith, DavidTruby, sscalpone
Subscribers: jfb, llvm-commits
Tags: #llvm, #flang
Differential Revision: https://reviews.llvm.org/D79263
2020-05-02 04:00:28 +08:00
|
|
|
}
|
2021-09-16 08:25:15 +08:00
|
|
|
if (auto procChars{
|
|
|
|
characteristics::Procedure::Characterize(x.proc(), context_)}) {
|
|
|
|
const auto iter{std::find_if(procChars->dummyArguments.begin(),
|
|
|
|
procChars->dummyArguments.end(),
|
|
|
|
[](const characteristics::DummyArgument &dummy) {
|
|
|
|
return std::holds_alternative<characteristics::DummyProcedure>(
|
|
|
|
dummy.u);
|
|
|
|
})};
|
|
|
|
if (iter != procChars->dummyArguments.end()) {
|
|
|
|
return "reference to function '"s + ultimate.name().ToString() +
|
|
|
|
"' with dummy procedure argument '" + iter->name + '\'';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// References to internal functions are caught in expression semantics.
|
2019-09-19 06:43:12 +08:00
|
|
|
// TODO: other checks for standard module procedures
|
|
|
|
} else {
|
|
|
|
const SpecificIntrinsic &intrin{DEREF(x.proc().GetSpecificIntrinsic())};
|
2020-05-13 00:53:58 +08:00
|
|
|
if (scope_.IsDerivedType()) { // C750, C754
|
[flang] Improve initializer semantics, esp. for component default values
This patch plugs many holes in static initializer semantics, improves error
messages for default initial values and other component properties in
parameterized derived type instantiations, and cleans up several small
issues noticed during development. We now do proper scalar expansion,
folding, and type, rank, and shape conformance checking for component
default initializers in derived types and PDT instantiations.
The initial values of named constants are now guaranteed to have been folded
when installed in the symbol table, and are no longer folded or
scalar-expanded at each use in expression folding. Semantics documentation
was extended with information about the various kinds of initializations
in Fortran and when each of them are processed in the compiler.
Some necessary concomitant changes have bulked this patch out a bit:
* contextual messages attachments, which are now produced for parameterized
derived type instantiations so that the user can figure out which
instance caused a problem with a component, have been added as part
of ContextualMessages, and their implementation was debugged
* several APIs in evaluate::characteristics was changed so that a FoldingContext
is passed as an argument rather than just its intrinsic procedure table;
this affected client call sites in many files
* new tools in Evaluate/check-expression.cpp to determine when an Expr
actually is a single constant value and to validate a non-pointer
variable initializer or object component default value
* shape conformance checking has additional arguments that control
whether scalar expansion is allowed
* several now-unused functions and data members noticed and removed
* several crashes and bogus errors exposed by testing this new code
were fixed
* a -fdebug-stack-trace option to enable LLVM's stack tracing on
a crash, which might be useful in the future
TL;DR: Initialization processing does more and takes place at the right
times for all of the various kinds of things that can be initialized.
Differential Review: https://reviews.llvm.org/D92783
2020-12-08 04:08:58 +08:00
|
|
|
if ((context_.intrinsics().IsIntrinsic(intrin.name) &&
|
[flang] New implementation for checks for constraints C741 through C750
Summary:
Most of these checks were already implemented, and I just added references to
them to the code and tests. Also, much of this code was already
reviewed in the old flang/f18 GitHub repository, but I didn't get to
merge it before we switched repositories.
I implemented the check for C747 to not allow coarray components in derived
types that are of type C_PTR, C_FUNPTR, or type TEAM_TYPE.
I implemented the check for C748 that requires a data component whose type has
a coarray ultimate component to be a nonpointer, nonallocatable scalar and not
be a coarray.
I implemented the check for C750 that adds additional restrictions to the
bounds expressions of a derived type component that's an array.
These bounds expressions are sepcification expressions as defined in
10.1.11. There was already code in lib/Evaluate/check-expression.cpp to
check semantics for specification expressions, but it did not check for
the extra requirements of C750.
C750 prohibits specification functions, the intrinsic functions
ALLOCATED, ASSOCIATED, EXTENDS_TYPE_OF, PRESENT, and SAME_TYPE_AS. It
also requires every specification inquiry reference to be a constant
expression, and requires that the value of the bound not depend on the
value of a variable.
To implement these additional checks, I added code to the intrinsic proc
table to get the intrinsic class of a procedure. I also added an
enumeration to distinguish between specification expressions for
derived type component bounds versus for type parameters. I then
changed the code to pass an enumeration value to
"CheckSpecificationExpr()" to indicate that the expression was a bounds
expression and used this value to determine whether to emit an error
message when violations of C750 are found.
I changed the implementation of IsPureProcedure() to handle statement
functions and changed some references in the code that tested for the
PURE attribute to call IsPureProcedure().
I also fixed some unrelated tests that got new errors when I implemented these
new checks.
Reviewers: tskeith, DavidTruby, sscalpone
Subscribers: jfb, llvm-commits
Tags: #llvm, #flang
Differential Revision: https://reviews.llvm.org/D79263
2020-05-02 04:00:28 +08:00
|
|
|
badIntrinsicsForComponents_.find(intrin.name) !=
|
|
|
|
badIntrinsicsForComponents_.end()) ||
|
|
|
|
IsProhibitedFunction(intrin.name)) {
|
|
|
|
return "reference to intrinsic '"s + intrin.name +
|
2020-05-13 00:53:58 +08:00
|
|
|
"' not allowed for derived type components or type parameter"
|
|
|
|
" values";
|
[flang] New implementation for checks for constraints C741 through C750
Summary:
Most of these checks were already implemented, and I just added references to
them to the code and tests. Also, much of this code was already
reviewed in the old flang/f18 GitHub repository, but I didn't get to
merge it before we switched repositories.
I implemented the check for C747 to not allow coarray components in derived
types that are of type C_PTR, C_FUNPTR, or type TEAM_TYPE.
I implemented the check for C748 that requires a data component whose type has
a coarray ultimate component to be a nonpointer, nonallocatable scalar and not
be a coarray.
I implemented the check for C750 that adds additional restrictions to the
bounds expressions of a derived type component that's an array.
These bounds expressions are sepcification expressions as defined in
10.1.11. There was already code in lib/Evaluate/check-expression.cpp to
check semantics for specification expressions, but it did not check for
the extra requirements of C750.
C750 prohibits specification functions, the intrinsic functions
ALLOCATED, ASSOCIATED, EXTENDS_TYPE_OF, PRESENT, and SAME_TYPE_AS. It
also requires every specification inquiry reference to be a constant
expression, and requires that the value of the bound not depend on the
value of a variable.
To implement these additional checks, I added code to the intrinsic proc
table to get the intrinsic class of a procedure. I also added an
enumeration to distinguish between specification expressions for
derived type component bounds versus for type parameters. I then
changed the code to pass an enumeration value to
"CheckSpecificationExpr()" to indicate that the expression was a bounds
expression and used this value to determine whether to emit an error
message when violations of C750 are found.
I changed the implementation of IsPureProcedure() to handle statement
functions and changed some references in the code that tested for the
PURE attribute to call IsPureProcedure().
I also fixed some unrelated tests that got new errors when I implemented these
new checks.
Reviewers: tskeith, DavidTruby, sscalpone
Subscribers: jfb, llvm-commits
Tags: #llvm, #flang
Differential Revision: https://reviews.llvm.org/D79263
2020-05-02 04:00:28 +08:00
|
|
|
}
|
[flang] Improve initializer semantics, esp. for component default values
This patch plugs many holes in static initializer semantics, improves error
messages for default initial values and other component properties in
parameterized derived type instantiations, and cleans up several small
issues noticed during development. We now do proper scalar expansion,
folding, and type, rank, and shape conformance checking for component
default initializers in derived types and PDT instantiations.
The initial values of named constants are now guaranteed to have been folded
when installed in the symbol table, and are no longer folded or
scalar-expanded at each use in expression folding. Semantics documentation
was extended with information about the various kinds of initializations
in Fortran and when each of them are processed in the compiler.
Some necessary concomitant changes have bulked this patch out a bit:
* contextual messages attachments, which are now produced for parameterized
derived type instantiations so that the user can figure out which
instance caused a problem with a component, have been added as part
of ContextualMessages, and their implementation was debugged
* several APIs in evaluate::characteristics was changed so that a FoldingContext
is passed as an argument rather than just its intrinsic procedure table;
this affected client call sites in many files
* new tools in Evaluate/check-expression.cpp to determine when an Expr
actually is a single constant value and to validate a non-pointer
variable initializer or object component default value
* shape conformance checking has additional arguments that control
whether scalar expansion is allowed
* several now-unused functions and data members noticed and removed
* several crashes and bogus errors exposed by testing this new code
were fixed
* a -fdebug-stack-trace option to enable LLVM's stack tracing on
a crash, which might be useful in the future
TL;DR: Initialization processing does more and takes place at the right
times for all of the various kinds of things that can be initialized.
Differential Review: https://reviews.llvm.org/D92783
2020-12-08 04:08:58 +08:00
|
|
|
if (context_.intrinsics().GetIntrinsicClass(intrin.name) ==
|
[flang] New implementation for checks for constraints C741 through C750
Summary:
Most of these checks were already implemented, and I just added references to
them to the code and tests. Also, much of this code was already
reviewed in the old flang/f18 GitHub repository, but I didn't get to
merge it before we switched repositories.
I implemented the check for C747 to not allow coarray components in derived
types that are of type C_PTR, C_FUNPTR, or type TEAM_TYPE.
I implemented the check for C748 that requires a data component whose type has
a coarray ultimate component to be a nonpointer, nonallocatable scalar and not
be a coarray.
I implemented the check for C750 that adds additional restrictions to the
bounds expressions of a derived type component that's an array.
These bounds expressions are sepcification expressions as defined in
10.1.11. There was already code in lib/Evaluate/check-expression.cpp to
check semantics for specification expressions, but it did not check for
the extra requirements of C750.
C750 prohibits specification functions, the intrinsic functions
ALLOCATED, ASSOCIATED, EXTENDS_TYPE_OF, PRESENT, and SAME_TYPE_AS. It
also requires every specification inquiry reference to be a constant
expression, and requires that the value of the bound not depend on the
value of a variable.
To implement these additional checks, I added code to the intrinsic proc
table to get the intrinsic class of a procedure. I also added an
enumeration to distinguish between specification expressions for
derived type component bounds versus for type parameters. I then
changed the code to pass an enumeration value to
"CheckSpecificationExpr()" to indicate that the expression was a bounds
expression and used this value to determine whether to emit an error
message when violations of C750 are found.
I changed the implementation of IsPureProcedure() to handle statement
functions and changed some references in the code that tested for the
PURE attribute to call IsPureProcedure().
I also fixed some unrelated tests that got new errors when I implemented these
new checks.
Reviewers: tskeith, DavidTruby, sscalpone
Subscribers: jfb, llvm-commits
Tags: #llvm, #flang
Differential Revision: https://reviews.llvm.org/D79263
2020-05-02 04:00:28 +08:00
|
|
|
IntrinsicClass::inquiryFunction &&
|
|
|
|
!IsConstantExpr(x)) {
|
|
|
|
return "non-constant reference to inquiry intrinsic '"s +
|
2020-05-13 00:53:58 +08:00
|
|
|
intrin.name +
|
|
|
|
"' not allowed for derived type components or type"
|
|
|
|
" parameter values";
|
[flang] New implementation for checks for constraints C741 through C750
Summary:
Most of these checks were already implemented, and I just added references to
them to the code and tests. Also, much of this code was already
reviewed in the old flang/f18 GitHub repository, but I didn't get to
merge it before we switched repositories.
I implemented the check for C747 to not allow coarray components in derived
types that are of type C_PTR, C_FUNPTR, or type TEAM_TYPE.
I implemented the check for C748 that requires a data component whose type has
a coarray ultimate component to be a nonpointer, nonallocatable scalar and not
be a coarray.
I implemented the check for C750 that adds additional restrictions to the
bounds expressions of a derived type component that's an array.
These bounds expressions are sepcification expressions as defined in
10.1.11. There was already code in lib/Evaluate/check-expression.cpp to
check semantics for specification expressions, but it did not check for
the extra requirements of C750.
C750 prohibits specification functions, the intrinsic functions
ALLOCATED, ASSOCIATED, EXTENDS_TYPE_OF, PRESENT, and SAME_TYPE_AS. It
also requires every specification inquiry reference to be a constant
expression, and requires that the value of the bound not depend on the
value of a variable.
To implement these additional checks, I added code to the intrinsic proc
table to get the intrinsic class of a procedure. I also added an
enumeration to distinguish between specification expressions for
derived type component bounds versus for type parameters. I then
changed the code to pass an enumeration value to
"CheckSpecificationExpr()" to indicate that the expression was a bounds
expression and used this value to determine whether to emit an error
message when violations of C750 are found.
I changed the implementation of IsPureProcedure() to handle statement
functions and changed some references in the code that tested for the
PURE attribute to call IsPureProcedure().
I also fixed some unrelated tests that got new errors when I implemented these
new checks.
Reviewers: tskeith, DavidTruby, sscalpone
Subscribers: jfb, llvm-commits
Tags: #llvm, #flang
Differential Revision: https://reviews.llvm.org/D79263
2020-05-02 04:00:28 +08:00
|
|
|
}
|
|
|
|
} else if (intrin.name == "present") {
|
2020-03-29 12:00:16 +08:00
|
|
|
return std::nullopt; // no need to check argument(s)
|
2019-09-19 06:43:12 +08:00
|
|
|
}
|
|
|
|
if (IsConstantExpr(x)) {
|
2019-09-21 05:28:15 +08:00
|
|
|
// inquiry functions may not need to check argument(s)
|
|
|
|
return std::nullopt;
|
2019-09-19 06:43:12 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return (*this)(x.arguments());
|
|
|
|
}
|
2019-09-21 05:28:15 +08:00
|
|
|
|
|
|
|
private:
|
|
|
|
const semantics::Scope &scope_;
|
[flang] Improve initializer semantics, esp. for component default values
This patch plugs many holes in static initializer semantics, improves error
messages for default initial values and other component properties in
parameterized derived type instantiations, and cleans up several small
issues noticed during development. We now do proper scalar expansion,
folding, and type, rank, and shape conformance checking for component
default initializers in derived types and PDT instantiations.
The initial values of named constants are now guaranteed to have been folded
when installed in the symbol table, and are no longer folded or
scalar-expanded at each use in expression folding. Semantics documentation
was extended with information about the various kinds of initializations
in Fortran and when each of them are processed in the compiler.
Some necessary concomitant changes have bulked this patch out a bit:
* contextual messages attachments, which are now produced for parameterized
derived type instantiations so that the user can figure out which
instance caused a problem with a component, have been added as part
of ContextualMessages, and their implementation was debugged
* several APIs in evaluate::characteristics was changed so that a FoldingContext
is passed as an argument rather than just its intrinsic procedure table;
this affected client call sites in many files
* new tools in Evaluate/check-expression.cpp to determine when an Expr
actually is a single constant value and to validate a non-pointer
variable initializer or object component default value
* shape conformance checking has additional arguments that control
whether scalar expansion is allowed
* several now-unused functions and data members noticed and removed
* several crashes and bogus errors exposed by testing this new code
were fixed
* a -fdebug-stack-trace option to enable LLVM's stack tracing on
a crash, which might be useful in the future
TL;DR: Initialization processing does more and takes place at the right
times for all of the various kinds of things that can be initialized.
Differential Review: https://reviews.llvm.org/D92783
2020-12-08 04:08:58 +08:00
|
|
|
FoldingContext &context_;
|
[flang] New implementation for checks for constraints C741 through C750
Summary:
Most of these checks were already implemented, and I just added references to
them to the code and tests. Also, much of this code was already
reviewed in the old flang/f18 GitHub repository, but I didn't get to
merge it before we switched repositories.
I implemented the check for C747 to not allow coarray components in derived
types that are of type C_PTR, C_FUNPTR, or type TEAM_TYPE.
I implemented the check for C748 that requires a data component whose type has
a coarray ultimate component to be a nonpointer, nonallocatable scalar and not
be a coarray.
I implemented the check for C750 that adds additional restrictions to the
bounds expressions of a derived type component that's an array.
These bounds expressions are sepcification expressions as defined in
10.1.11. There was already code in lib/Evaluate/check-expression.cpp to
check semantics for specification expressions, but it did not check for
the extra requirements of C750.
C750 prohibits specification functions, the intrinsic functions
ALLOCATED, ASSOCIATED, EXTENDS_TYPE_OF, PRESENT, and SAME_TYPE_AS. It
also requires every specification inquiry reference to be a constant
expression, and requires that the value of the bound not depend on the
value of a variable.
To implement these additional checks, I added code to the intrinsic proc
table to get the intrinsic class of a procedure. I also added an
enumeration to distinguish between specification expressions for
derived type component bounds versus for type parameters. I then
changed the code to pass an enumeration value to
"CheckSpecificationExpr()" to indicate that the expression was a bounds
expression and used this value to determine whether to emit an error
message when violations of C750 are found.
I changed the implementation of IsPureProcedure() to handle statement
functions and changed some references in the code that tested for the
PURE attribute to call IsPureProcedure().
I also fixed some unrelated tests that got new errors when I implemented these
new checks.
Reviewers: tskeith, DavidTruby, sscalpone
Subscribers: jfb, llvm-commits
Tags: #llvm, #flang
Differential Revision: https://reviews.llvm.org/D79263
2020-05-02 04:00:28 +08:00
|
|
|
const std::set<std::string> badIntrinsicsForComponents_{
|
|
|
|
"allocated", "associated", "extends_type_of", "present", "same_type_as"};
|
|
|
|
static bool IsProhibitedFunction(std::string name) { return false; }
|
2019-09-19 06:43:12 +08:00
|
|
|
};
|
|
|
|
|
2020-03-29 12:00:16 +08:00
|
|
|
template <typename A>
|
[flang] Improve initializer semantics, esp. for component default values
This patch plugs many holes in static initializer semantics, improves error
messages for default initial values and other component properties in
parameterized derived type instantiations, and cleans up several small
issues noticed during development. We now do proper scalar expansion,
folding, and type, rank, and shape conformance checking for component
default initializers in derived types and PDT instantiations.
The initial values of named constants are now guaranteed to have been folded
when installed in the symbol table, and are no longer folded or
scalar-expanded at each use in expression folding. Semantics documentation
was extended with information about the various kinds of initializations
in Fortran and when each of them are processed in the compiler.
Some necessary concomitant changes have bulked this patch out a bit:
* contextual messages attachments, which are now produced for parameterized
derived type instantiations so that the user can figure out which
instance caused a problem with a component, have been added as part
of ContextualMessages, and their implementation was debugged
* several APIs in evaluate::characteristics was changed so that a FoldingContext
is passed as an argument rather than just its intrinsic procedure table;
this affected client call sites in many files
* new tools in Evaluate/check-expression.cpp to determine when an Expr
actually is a single constant value and to validate a non-pointer
variable initializer or object component default value
* shape conformance checking has additional arguments that control
whether scalar expansion is allowed
* several now-unused functions and data members noticed and removed
* several crashes and bogus errors exposed by testing this new code
were fixed
* a -fdebug-stack-trace option to enable LLVM's stack tracing on
a crash, which might be useful in the future
TL;DR: Initialization processing does more and takes place at the right
times for all of the various kinds of things that can be initialized.
Differential Review: https://reviews.llvm.org/D92783
2020-12-08 04:08:58 +08:00
|
|
|
void CheckSpecificationExpr(
|
|
|
|
const A &x, const semantics::Scope &scope, FoldingContext &context) {
|
|
|
|
if (auto why{CheckSpecificationExprHelper{scope, context}(x)}) {
|
|
|
|
context.messages().Say(
|
|
|
|
"Invalid specification expression: %s"_err_en_US, *why);
|
2019-09-19 06:43:12 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[flang] Improve initializer semantics, esp. for component default values
This patch plugs many holes in static initializer semantics, improves error
messages for default initial values and other component properties in
parameterized derived type instantiations, and cleans up several small
issues noticed during development. We now do proper scalar expansion,
folding, and type, rank, and shape conformance checking for component
default initializers in derived types and PDT instantiations.
The initial values of named constants are now guaranteed to have been folded
when installed in the symbol table, and are no longer folded or
scalar-expanded at each use in expression folding. Semantics documentation
was extended with information about the various kinds of initializations
in Fortran and when each of them are processed in the compiler.
Some necessary concomitant changes have bulked this patch out a bit:
* contextual messages attachments, which are now produced for parameterized
derived type instantiations so that the user can figure out which
instance caused a problem with a component, have been added as part
of ContextualMessages, and their implementation was debugged
* several APIs in evaluate::characteristics was changed so that a FoldingContext
is passed as an argument rather than just its intrinsic procedure table;
this affected client call sites in many files
* new tools in Evaluate/check-expression.cpp to determine when an Expr
actually is a single constant value and to validate a non-pointer
variable initializer or object component default value
* shape conformance checking has additional arguments that control
whether scalar expansion is allowed
* several now-unused functions and data members noticed and removed
* several crashes and bogus errors exposed by testing this new code
were fixed
* a -fdebug-stack-trace option to enable LLVM's stack tracing on
a crash, which might be useful in the future
TL;DR: Initialization processing does more and takes place at the right
times for all of the various kinds of things that can be initialized.
Differential Review: https://reviews.llvm.org/D92783
2020-12-08 04:08:58 +08:00
|
|
|
template void CheckSpecificationExpr(
|
|
|
|
const Expr<SomeType> &, const semantics::Scope &, FoldingContext &);
|
|
|
|
template void CheckSpecificationExpr(
|
|
|
|
const Expr<SomeInteger> &, const semantics::Scope &, FoldingContext &);
|
|
|
|
template void CheckSpecificationExpr(
|
|
|
|
const Expr<SubscriptInteger> &, const semantics::Scope &, FoldingContext &);
|
2020-03-14 03:19:44 +08:00
|
|
|
template void CheckSpecificationExpr(const std::optional<Expr<SomeType>> &,
|
[flang] Improve initializer semantics, esp. for component default values
This patch plugs many holes in static initializer semantics, improves error
messages for default initial values and other component properties in
parameterized derived type instantiations, and cleans up several small
issues noticed during development. We now do proper scalar expansion,
folding, and type, rank, and shape conformance checking for component
default initializers in derived types and PDT instantiations.
The initial values of named constants are now guaranteed to have been folded
when installed in the symbol table, and are no longer folded or
scalar-expanded at each use in expression folding. Semantics documentation
was extended with information about the various kinds of initializations
in Fortran and when each of them are processed in the compiler.
Some necessary concomitant changes have bulked this patch out a bit:
* contextual messages attachments, which are now produced for parameterized
derived type instantiations so that the user can figure out which
instance caused a problem with a component, have been added as part
of ContextualMessages, and their implementation was debugged
* several APIs in evaluate::characteristics was changed so that a FoldingContext
is passed as an argument rather than just its intrinsic procedure table;
this affected client call sites in many files
* new tools in Evaluate/check-expression.cpp to determine when an Expr
actually is a single constant value and to validate a non-pointer
variable initializer or object component default value
* shape conformance checking has additional arguments that control
whether scalar expansion is allowed
* several now-unused functions and data members noticed and removed
* several crashes and bogus errors exposed by testing this new code
were fixed
* a -fdebug-stack-trace option to enable LLVM's stack tracing on
a crash, which might be useful in the future
TL;DR: Initialization processing does more and takes place at the right
times for all of the various kinds of things that can be initialized.
Differential Review: https://reviews.llvm.org/D92783
2020-12-08 04:08:58 +08:00
|
|
|
const semantics::Scope &, FoldingContext &);
|
2019-09-21 05:28:15 +08:00
|
|
|
template void CheckSpecificationExpr(const std::optional<Expr<SomeInteger>> &,
|
[flang] Improve initializer semantics, esp. for component default values
This patch plugs many holes in static initializer semantics, improves error
messages for default initial values and other component properties in
parameterized derived type instantiations, and cleans up several small
issues noticed during development. We now do proper scalar expansion,
folding, and type, rank, and shape conformance checking for component
default initializers in derived types and PDT instantiations.
The initial values of named constants are now guaranteed to have been folded
when installed in the symbol table, and are no longer folded or
scalar-expanded at each use in expression folding. Semantics documentation
was extended with information about the various kinds of initializations
in Fortran and when each of them are processed in the compiler.
Some necessary concomitant changes have bulked this patch out a bit:
* contextual messages attachments, which are now produced for parameterized
derived type instantiations so that the user can figure out which
instance caused a problem with a component, have been added as part
of ContextualMessages, and their implementation was debugged
* several APIs in evaluate::characteristics was changed so that a FoldingContext
is passed as an argument rather than just its intrinsic procedure table;
this affected client call sites in many files
* new tools in Evaluate/check-expression.cpp to determine when an Expr
actually is a single constant value and to validate a non-pointer
variable initializer or object component default value
* shape conformance checking has additional arguments that control
whether scalar expansion is allowed
* several now-unused functions and data members noticed and removed
* several crashes and bogus errors exposed by testing this new code
were fixed
* a -fdebug-stack-trace option to enable LLVM's stack tracing on
a crash, which might be useful in the future
TL;DR: Initialization processing does more and takes place at the right
times for all of the various kinds of things that can be initialized.
Differential Review: https://reviews.llvm.org/D92783
2020-12-08 04:08:58 +08:00
|
|
|
const semantics::Scope &, FoldingContext &);
|
2019-09-19 06:43:12 +08:00
|
|
|
template void CheckSpecificationExpr(
|
[flang] Improve initializer semantics, esp. for component default values
This patch plugs many holes in static initializer semantics, improves error
messages for default initial values and other component properties in
parameterized derived type instantiations, and cleans up several small
issues noticed during development. We now do proper scalar expansion,
folding, and type, rank, and shape conformance checking for component
default initializers in derived types and PDT instantiations.
The initial values of named constants are now guaranteed to have been folded
when installed in the symbol table, and are no longer folded or
scalar-expanded at each use in expression folding. Semantics documentation
was extended with information about the various kinds of initializations
in Fortran and when each of them are processed in the compiler.
Some necessary concomitant changes have bulked this patch out a bit:
* contextual messages attachments, which are now produced for parameterized
derived type instantiations so that the user can figure out which
instance caused a problem with a component, have been added as part
of ContextualMessages, and their implementation was debugged
* several APIs in evaluate::characteristics was changed so that a FoldingContext
is passed as an argument rather than just its intrinsic procedure table;
this affected client call sites in many files
* new tools in Evaluate/check-expression.cpp to determine when an Expr
actually is a single constant value and to validate a non-pointer
variable initializer or object component default value
* shape conformance checking has additional arguments that control
whether scalar expansion is allowed
* several now-unused functions and data members noticed and removed
* several crashes and bogus errors exposed by testing this new code
were fixed
* a -fdebug-stack-trace option to enable LLVM's stack tracing on
a crash, which might be useful in the future
TL;DR: Initialization processing does more and takes place at the right
times for all of the various kinds of things that can be initialized.
Differential Review: https://reviews.llvm.org/D92783
2020-12-08 04:08:58 +08:00
|
|
|
const std::optional<Expr<SubscriptInteger>> &, const semantics::Scope &,
|
|
|
|
FoldingContext &);
|
2019-09-17 07:58:13 +08:00
|
|
|
|
|
|
|
// IsSimplyContiguous() -- 9.5.4
|
|
|
|
class IsSimplyContiguousHelper
|
2020-03-29 12:00:16 +08:00
|
|
|
: public AnyTraverse<IsSimplyContiguousHelper, std::optional<bool>> {
|
2019-09-17 07:58:13 +08:00
|
|
|
public:
|
2020-03-29 12:00:16 +08:00
|
|
|
using Result = std::optional<bool>; // tri-state
|
2019-09-17 07:58:13 +08:00
|
|
|
using Base = AnyTraverse<IsSimplyContiguousHelper, Result>;
|
[flang] Improve initializer semantics, esp. for component default values
This patch plugs many holes in static initializer semantics, improves error
messages for default initial values and other component properties in
parameterized derived type instantiations, and cleans up several small
issues noticed during development. We now do proper scalar expansion,
folding, and type, rank, and shape conformance checking for component
default initializers in derived types and PDT instantiations.
The initial values of named constants are now guaranteed to have been folded
when installed in the symbol table, and are no longer folded or
scalar-expanded at each use in expression folding. Semantics documentation
was extended with information about the various kinds of initializations
in Fortran and when each of them are processed in the compiler.
Some necessary concomitant changes have bulked this patch out a bit:
* contextual messages attachments, which are now produced for parameterized
derived type instantiations so that the user can figure out which
instance caused a problem with a component, have been added as part
of ContextualMessages, and their implementation was debugged
* several APIs in evaluate::characteristics was changed so that a FoldingContext
is passed as an argument rather than just its intrinsic procedure table;
this affected client call sites in many files
* new tools in Evaluate/check-expression.cpp to determine when an Expr
actually is a single constant value and to validate a non-pointer
variable initializer or object component default value
* shape conformance checking has additional arguments that control
whether scalar expansion is allowed
* several now-unused functions and data members noticed and removed
* several crashes and bogus errors exposed by testing this new code
were fixed
* a -fdebug-stack-trace option to enable LLVM's stack tracing on
a crash, which might be useful in the future
TL;DR: Initialization processing does more and takes place at the right
times for all of the various kinds of things that can be initialized.
Differential Review: https://reviews.llvm.org/D92783
2020-12-08 04:08:58 +08:00
|
|
|
explicit IsSimplyContiguousHelper(FoldingContext &c)
|
|
|
|
: Base{*this}, context_{c} {}
|
2019-09-17 07:58:13 +08:00
|
|
|
using Base::operator();
|
|
|
|
|
|
|
|
Result operator()(const semantics::Symbol &symbol) const {
|
2021-04-01 00:12:28 +08:00
|
|
|
const auto &ultimate{symbol.GetUltimate()};
|
2021-10-13 01:17:02 +08:00
|
|
|
if (ultimate.attrs().test(semantics::Attr::CONTIGUOUS)) {
|
|
|
|
return true;
|
|
|
|
} else if (ultimate.Rank() == 0) {
|
|
|
|
// Extension: accept scalars as a degenerate case of
|
|
|
|
// simple contiguity to allow their use in contexts like
|
|
|
|
// data targets in pointer assignments with remapping.
|
2019-09-17 07:58:13 +08:00
|
|
|
return true;
|
2021-11-27 05:26:50 +08:00
|
|
|
} else if (semantics::IsPointer(ultimate) ||
|
|
|
|
semantics::IsAssumedShape(ultimate)) {
|
2019-09-17 07:58:13 +08:00
|
|
|
return false;
|
|
|
|
} else if (const auto *details{
|
2021-04-01 00:12:28 +08:00
|
|
|
ultimate.detailsIf<semantics::ObjectEntityDetails>()}) {
|
2021-11-27 05:26:50 +08:00
|
|
|
return !details->IsAssumedRank();
|
2021-04-01 00:12:28 +08:00
|
|
|
} else if (auto assoc{Base::operator()(ultimate)}) {
|
|
|
|
return assoc;
|
2019-09-17 07:58:13 +08:00
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Result operator()(const ArrayRef &x) const {
|
2020-01-29 07:06:03 +08:00
|
|
|
const auto &symbol{x.GetLastSymbol()};
|
2021-07-21 08:06:19 +08:00
|
|
|
if (!(*this)(symbol).has_value()) {
|
2020-01-29 07:06:03 +08:00
|
|
|
return false;
|
|
|
|
} else if (auto rank{CheckSubscripts(x.subscript())}) {
|
2021-11-18 01:18:05 +08:00
|
|
|
if (x.Rank() == 0) {
|
|
|
|
return true;
|
|
|
|
} else if (*rank > 0) {
|
|
|
|
// a(1)%b(:,:) is contiguous if an only if a(1)%b is contiguous.
|
|
|
|
return (*this)(x.base());
|
|
|
|
} else {
|
|
|
|
// a(:)%b(1,1) is not contiguous.
|
|
|
|
return false;
|
|
|
|
}
|
2020-01-29 07:06:03 +08:00
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
2019-09-17 07:58:13 +08:00
|
|
|
}
|
|
|
|
Result operator()(const CoarrayRef &x) const {
|
2020-01-29 07:06:03 +08:00
|
|
|
return CheckSubscripts(x.subscript()).has_value();
|
2019-09-17 07:58:13 +08:00
|
|
|
}
|
2020-01-27 02:42:34 +08:00
|
|
|
Result operator()(const Component &x) const {
|
2021-07-21 08:06:19 +08:00
|
|
|
return x.base().Rank() == 0 && (*this)(x.GetLastSymbol()).value_or(false);
|
2020-01-27 02:42:34 +08:00
|
|
|
}
|
2019-09-17 07:58:13 +08:00
|
|
|
Result operator()(const ComplexPart &) const { return false; }
|
|
|
|
Result operator()(const Substring &) const { return false; }
|
|
|
|
|
2022-02-08 07:34:54 +08:00
|
|
|
Result operator()(const ProcedureRef &x) const {
|
2019-09-17 07:58:13 +08:00
|
|
|
if (auto chars{
|
[flang] Improve initializer semantics, esp. for component default values
This patch plugs many holes in static initializer semantics, improves error
messages for default initial values and other component properties in
parameterized derived type instantiations, and cleans up several small
issues noticed during development. We now do proper scalar expansion,
folding, and type, rank, and shape conformance checking for component
default initializers in derived types and PDT instantiations.
The initial values of named constants are now guaranteed to have been folded
when installed in the symbol table, and are no longer folded or
scalar-expanded at each use in expression folding. Semantics documentation
was extended with information about the various kinds of initializations
in Fortran and when each of them are processed in the compiler.
Some necessary concomitant changes have bulked this patch out a bit:
* contextual messages attachments, which are now produced for parameterized
derived type instantiations so that the user can figure out which
instance caused a problem with a component, have been added as part
of ContextualMessages, and their implementation was debugged
* several APIs in evaluate::characteristics was changed so that a FoldingContext
is passed as an argument rather than just its intrinsic procedure table;
this affected client call sites in many files
* new tools in Evaluate/check-expression.cpp to determine when an Expr
actually is a single constant value and to validate a non-pointer
variable initializer or object component default value
* shape conformance checking has additional arguments that control
whether scalar expansion is allowed
* several now-unused functions and data members noticed and removed
* several crashes and bogus errors exposed by testing this new code
were fixed
* a -fdebug-stack-trace option to enable LLVM's stack tracing on
a crash, which might be useful in the future
TL;DR: Initialization processing does more and takes place at the right
times for all of the various kinds of things that can be initialized.
Differential Review: https://reviews.llvm.org/D92783
2020-12-08 04:08:58 +08:00
|
|
|
characteristics::Procedure::Characterize(x.proc(), context_)}) {
|
2019-11-10 01:29:31 +08:00
|
|
|
if (chars->functionResult) {
|
2019-09-17 07:58:13 +08:00
|
|
|
const auto &result{*chars->functionResult};
|
|
|
|
return !result.IsProcedurePointer() &&
|
|
|
|
result.attrs.test(characteristics::FunctionResult::Attr::Pointer) &&
|
|
|
|
result.attrs.test(
|
|
|
|
characteristics::FunctionResult::Attr::Contiguous);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2020-01-29 07:06:03 +08:00
|
|
|
// If the subscripts can possibly be on a simply-contiguous array reference,
|
|
|
|
// return the rank.
|
|
|
|
static std::optional<int> CheckSubscripts(
|
|
|
|
const std::vector<Subscript> &subscript) {
|
2019-09-17 07:58:13 +08:00
|
|
|
bool anyTriplet{false};
|
2020-01-29 07:06:03 +08:00
|
|
|
int rank{0};
|
2019-09-17 07:58:13 +08:00
|
|
|
for (auto j{subscript.size()}; j-- > 0;) {
|
|
|
|
if (const auto *triplet{std::get_if<Triplet>(&subscript[j].u)}) {
|
|
|
|
if (!triplet->IsStrideOne()) {
|
2020-01-29 07:06:03 +08:00
|
|
|
return std::nullopt;
|
2019-09-17 07:58:13 +08:00
|
|
|
} else if (anyTriplet) {
|
2019-11-10 01:29:31 +08:00
|
|
|
if (triplet->lower() || triplet->upper()) {
|
2020-01-29 07:06:03 +08:00
|
|
|
// all triplets before the last one must be just ":"
|
|
|
|
return std::nullopt;
|
2019-09-17 07:58:13 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
anyTriplet = true;
|
|
|
|
}
|
2020-01-29 07:06:03 +08:00
|
|
|
++rank;
|
2019-09-17 07:58:13 +08:00
|
|
|
} else if (anyTriplet || subscript[j].Rank() > 0) {
|
2020-01-29 07:06:03 +08:00
|
|
|
return std::nullopt;
|
2019-09-17 07:58:13 +08:00
|
|
|
}
|
|
|
|
}
|
2020-01-29 07:06:03 +08:00
|
|
|
return rank;
|
2019-09-17 07:58:13 +08:00
|
|
|
}
|
|
|
|
|
[flang] Improve initializer semantics, esp. for component default values
This patch plugs many holes in static initializer semantics, improves error
messages for default initial values and other component properties in
parameterized derived type instantiations, and cleans up several small
issues noticed during development. We now do proper scalar expansion,
folding, and type, rank, and shape conformance checking for component
default initializers in derived types and PDT instantiations.
The initial values of named constants are now guaranteed to have been folded
when installed in the symbol table, and are no longer folded or
scalar-expanded at each use in expression folding. Semantics documentation
was extended with information about the various kinds of initializations
in Fortran and when each of them are processed in the compiler.
Some necessary concomitant changes have bulked this patch out a bit:
* contextual messages attachments, which are now produced for parameterized
derived type instantiations so that the user can figure out which
instance caused a problem with a component, have been added as part
of ContextualMessages, and their implementation was debugged
* several APIs in evaluate::characteristics was changed so that a FoldingContext
is passed as an argument rather than just its intrinsic procedure table;
this affected client call sites in many files
* new tools in Evaluate/check-expression.cpp to determine when an Expr
actually is a single constant value and to validate a non-pointer
variable initializer or object component default value
* shape conformance checking has additional arguments that control
whether scalar expansion is allowed
* several now-unused functions and data members noticed and removed
* several crashes and bogus errors exposed by testing this new code
were fixed
* a -fdebug-stack-trace option to enable LLVM's stack tracing on
a crash, which might be useful in the future
TL;DR: Initialization processing does more and takes place at the right
times for all of the various kinds of things that can be initialized.
Differential Review: https://reviews.llvm.org/D92783
2020-12-08 04:08:58 +08:00
|
|
|
FoldingContext &context_;
|
2019-09-17 07:58:13 +08:00
|
|
|
};
|
|
|
|
|
2020-03-29 12:00:16 +08:00
|
|
|
template <typename A>
|
[flang] Improve initializer semantics, esp. for component default values
This patch plugs many holes in static initializer semantics, improves error
messages for default initial values and other component properties in
parameterized derived type instantiations, and cleans up several small
issues noticed during development. We now do proper scalar expansion,
folding, and type, rank, and shape conformance checking for component
default initializers in derived types and PDT instantiations.
The initial values of named constants are now guaranteed to have been folded
when installed in the symbol table, and are no longer folded or
scalar-expanded at each use in expression folding. Semantics documentation
was extended with information about the various kinds of initializations
in Fortran and when each of them are processed in the compiler.
Some necessary concomitant changes have bulked this patch out a bit:
* contextual messages attachments, which are now produced for parameterized
derived type instantiations so that the user can figure out which
instance caused a problem with a component, have been added as part
of ContextualMessages, and their implementation was debugged
* several APIs in evaluate::characteristics was changed so that a FoldingContext
is passed as an argument rather than just its intrinsic procedure table;
this affected client call sites in many files
* new tools in Evaluate/check-expression.cpp to determine when an Expr
actually is a single constant value and to validate a non-pointer
variable initializer or object component default value
* shape conformance checking has additional arguments that control
whether scalar expansion is allowed
* several now-unused functions and data members noticed and removed
* several crashes and bogus errors exposed by testing this new code
were fixed
* a -fdebug-stack-trace option to enable LLVM's stack tracing on
a crash, which might be useful in the future
TL;DR: Initialization processing does more and takes place at the right
times for all of the various kinds of things that can be initialized.
Differential Review: https://reviews.llvm.org/D92783
2020-12-08 04:08:58 +08:00
|
|
|
bool IsSimplyContiguous(const A &x, FoldingContext &context) {
|
2019-09-17 07:58:13 +08:00
|
|
|
if (IsVariable(x)) {
|
[flang] Improve initializer semantics, esp. for component default values
This patch plugs many holes in static initializer semantics, improves error
messages for default initial values and other component properties in
parameterized derived type instantiations, and cleans up several small
issues noticed during development. We now do proper scalar expansion,
folding, and type, rank, and shape conformance checking for component
default initializers in derived types and PDT instantiations.
The initial values of named constants are now guaranteed to have been folded
when installed in the symbol table, and are no longer folded or
scalar-expanded at each use in expression folding. Semantics documentation
was extended with information about the various kinds of initializations
in Fortran and when each of them are processed in the compiler.
Some necessary concomitant changes have bulked this patch out a bit:
* contextual messages attachments, which are now produced for parameterized
derived type instantiations so that the user can figure out which
instance caused a problem with a component, have been added as part
of ContextualMessages, and their implementation was debugged
* several APIs in evaluate::characteristics was changed so that a FoldingContext
is passed as an argument rather than just its intrinsic procedure table;
this affected client call sites in many files
* new tools in Evaluate/check-expression.cpp to determine when an Expr
actually is a single constant value and to validate a non-pointer
variable initializer or object component default value
* shape conformance checking has additional arguments that control
whether scalar expansion is allowed
* several now-unused functions and data members noticed and removed
* several crashes and bogus errors exposed by testing this new code
were fixed
* a -fdebug-stack-trace option to enable LLVM's stack tracing on
a crash, which might be useful in the future
TL;DR: Initialization processing does more and takes place at the right
times for all of the various kinds of things that can be initialized.
Differential Review: https://reviews.llvm.org/D92783
2020-12-08 04:08:58 +08:00
|
|
|
auto known{IsSimplyContiguousHelper{context}(x)};
|
2020-01-08 05:39:42 +08:00
|
|
|
return known && *known;
|
|
|
|
} else {
|
2020-03-29 12:00:16 +08:00
|
|
|
return true; // not a variable
|
2019-09-17 07:58:13 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[flang] Improve initializer semantics, esp. for component default values
This patch plugs many holes in static initializer semantics, improves error
messages for default initial values and other component properties in
parameterized derived type instantiations, and cleans up several small
issues noticed during development. We now do proper scalar expansion,
folding, and type, rank, and shape conformance checking for component
default initializers in derived types and PDT instantiations.
The initial values of named constants are now guaranteed to have been folded
when installed in the symbol table, and are no longer folded or
scalar-expanded at each use in expression folding. Semantics documentation
was extended with information about the various kinds of initializations
in Fortran and when each of them are processed in the compiler.
Some necessary concomitant changes have bulked this patch out a bit:
* contextual messages attachments, which are now produced for parameterized
derived type instantiations so that the user can figure out which
instance caused a problem with a component, have been added as part
of ContextualMessages, and their implementation was debugged
* several APIs in evaluate::characteristics was changed so that a FoldingContext
is passed as an argument rather than just its intrinsic procedure table;
this affected client call sites in many files
* new tools in Evaluate/check-expression.cpp to determine when an Expr
actually is a single constant value and to validate a non-pointer
variable initializer or object component default value
* shape conformance checking has additional arguments that control
whether scalar expansion is allowed
* several now-unused functions and data members noticed and removed
* several crashes and bogus errors exposed by testing this new code
were fixed
* a -fdebug-stack-trace option to enable LLVM's stack tracing on
a crash, which might be useful in the future
TL;DR: Initialization processing does more and takes place at the right
times for all of the various kinds of things that can be initialized.
Differential Review: https://reviews.llvm.org/D92783
2020-12-08 04:08:58 +08:00
|
|
|
template bool IsSimplyContiguous(const Expr<SomeType> &, FoldingContext &);
|
|
|
|
|
|
|
|
// IsErrorExpr()
|
|
|
|
struct IsErrorExprHelper : public AnyTraverse<IsErrorExprHelper, bool> {
|
|
|
|
using Result = bool;
|
|
|
|
using Base = AnyTraverse<IsErrorExprHelper, Result>;
|
|
|
|
IsErrorExprHelper() : Base{*this} {}
|
|
|
|
using Base::operator();
|
|
|
|
|
|
|
|
bool operator()(const SpecificIntrinsic &x) {
|
|
|
|
return x.name == IntrinsicProcTable::InvalidName;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename A> bool IsErrorExpr(const A &x) {
|
|
|
|
return IsErrorExprHelper{}(x);
|
|
|
|
}
|
|
|
|
|
|
|
|
template bool IsErrorExpr(const Expr<SomeType> &);
|
2019-09-17 07:58:13 +08:00
|
|
|
|
2020-03-29 12:00:16 +08:00
|
|
|
} // namespace Fortran::evaluate
|