Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions flang/include/flang/Common/enum-set.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,16 @@ template <typename ENUM, std::size_t BITS> class EnumSet {
private:
bitsetType bitset_{};
};

namespace detail {
template <typename...> struct IsEnumSetTest {
static constexpr bool value{false};
};
template <typename E, size_t B> struct IsEnumSetTest<EnumSet<E, B>> {
static constexpr bool value{true};
};
} // namespace detail
template <typename T> constexpr bool IsEnumSet{detail::IsEnumSetTest<T>::value};
} // namespace Fortran::common

template <typename ENUM, std::size_t values>
Expand Down
18 changes: 17 additions & 1 deletion flang/include/flang/Parser/dump-parse-tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@
#include "parse-tree.h"
#include "tools.h"
#include "unparse.h"
#include "flang/Common/enum-set.h"
#include "flang/Common/idioms.h"
#include "flang/Common/indirection.h"
#include "flang/Support/Fortran.h"
#include "llvm/Frontend/OpenMP/OMP.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h"
#include <string>
#include <type_traits>
Expand All @@ -35,6 +37,19 @@ class ParseTreeDumper {
: out_(out), asFortran_{asFortran} {}

static constexpr const char *GetNodeName(const char *) { return "char *"; }

template <typename T, typename E, size_t B>
static std::string GetMemberNames(const common::EnumSet<E, B> &x) {
llvm::ListSeparator sep;
std::string s;
llvm::raw_string_ostream stream(s);
x.IterateOverMembers([&](E e) { stream << sep << T::EnumToString(e); });
return stream.str();
}
#define NODE_ENUMSET(T, S) \
static std::string GetNodeName(const T::S &x) { \
return #S " = {"s + GetMemberNames<T>(x) + "}"s; \
}
#define NODE_NAME(T, N) \
static constexpr const char *GetNodeName(const T &) { return N; }
#define NODE_ENUM(T, E) \
Expand Down Expand Up @@ -572,7 +587,8 @@ class ParseTreeDumper {
NODE_ENUM(OmpDeviceTypeClause, DeviceTypeDescription)
NODE(parser, OmpDirectiveName)
NODE(parser, OmpDirectiveSpecification)
NODE_ENUM(OmpDirectiveSpecification, Flags)
NODE_ENUM(OmpDirectiveSpecification, Flag)
NODE_ENUMSET(OmpDirectiveSpecification, Flags)
NODE(parser, OmpDoacross)
NODE(OmpDoacross, Sink)
NODE(OmpDoacross, Source)
Expand Down
3 changes: 2 additions & 1 deletion flang/include/flang/Parser/parse-tree-visitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#define FORTRAN_PARSER_PARSE_TREE_VISITOR_H_

#include "parse-tree.h"
#include "flang/Common/enum-set.h"
#include "flang/Common/visit.h"
#include <cstddef>
#include <optional>
Expand Down Expand Up @@ -41,7 +42,7 @@ struct ParseTreeVisitorLookupScope {
// Default case for visitation of non-class data members, strings, and
// any other non-decomposable values.
template <typename A, typename V>
static std::enable_if_t<!std::is_class_v<A> ||
static std::enable_if_t<!std::is_class_v<A> || common::IsEnumSet<A> ||
std::is_same_v<std::string, A> || std::is_same_v<CharBlock, A>>
Walk(const A &x, V &visitor) {
if (visitor.Pre(x)) {
Expand Down
5 changes: 4 additions & 1 deletion flang/include/flang/Parser/parse-tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "format-specification.h"
#include "message.h"
#include "provenance.h"
#include "flang/Common/enum-set.h"
#include "flang/Common/idioms.h"
#include "flang/Common/indirection.h"
#include "flang/Common/reference.h"
Expand Down Expand Up @@ -4975,7 +4976,9 @@ struct OmpClauseList {
// --- Directives and constructs

struct OmpDirectiveSpecification {
ENUM_CLASS(Flags, None, DeprecatedSyntax);
ENUM_CLASS(Flag, DeprecatedSyntax, CrossesLabelDo)
using Flags = common::EnumSet<Flag, Flag_enumSize>;

TUPLE_CLASS_BOILERPLATE(OmpDirectiveSpecification);
const OmpDirectiveName &DirName() const {
return std::get<OmpDirectiveName>(t);
Expand Down
7 changes: 4 additions & 3 deletions flang/lib/Parser/openmp-parsers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1633,7 +1633,8 @@ TYPE_PARSER(
maybe(Parser<OmpClauseList>{}),
maybe(parenthesized(
OmpArgumentListParser<llvm::omp::Directive::OMPD_flush>{})),
pure(OmpDirectiveSpecification::Flags::DeprecatedSyntax)))) ||
pure(OmpDirectiveSpecification::Flags(
{OmpDirectiveSpecification::Flag::DeprecatedSyntax}))))) ||
// Parse DECLARE_VARIANT individually, because the "[base:]variant"
// argument will conflict with DECLARE_REDUCTION's "ident:types...".
predicated(Parser<OmpDirectiveName>{},
Expand All @@ -1643,13 +1644,13 @@ TYPE_PARSER(
maybe(parenthesized(OmpArgumentListParser<
llvm::omp::Directive::OMPD_declare_variant>{})),
maybe(Parser<OmpClauseList>{}),
pure(OmpDirectiveSpecification::Flags::None))) ||
pure(OmpDirectiveSpecification::Flags()))) ||
// Parse the standard syntax: directive [(arguments)] [clauses]
sourced(construct<OmpDirectiveSpecification>( //
sourced(OmpDirectiveNameParser{}),
maybe(parenthesized(OmpArgumentListParser<>{})),
maybe(Parser<OmpClauseList>{}),
pure(OmpDirectiveSpecification::Flags::None))))
pure(OmpDirectiveSpecification::Flags()))))

static bool IsStandaloneOrdered(const OmpDirectiveSpecification &dirSpec) {
// An ORDERED construct is standalone if it has DOACROSS or DEPEND clause.
Expand Down
10 changes: 5 additions & 5 deletions flang/lib/Parser/unparse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2142,7 +2142,7 @@ class UnparseVisitor {

Walk(std::get<OmpDirectiveName>(x.t));
auto flags{std::get<OmpDirectiveSpecification::Flags>(x.t)};
if (flags == OmpDirectiveSpecification::Flags::DeprecatedSyntax) {
if (flags.test(OmpDirectiveSpecification::Flag::DeprecatedSyntax)) {
if (x.DirId() == llvm::omp::Directive::OMPD_flush) {
// FLUSH clause arglist
unparseClauses();
Expand Down Expand Up @@ -2539,8 +2539,8 @@ class UnparseVisitor {
void Unparse(const OpenMPInteropConstruct &x) {
BeginOpenMP();
Word("!$OMP INTEROP");
using Flags = OmpDirectiveSpecification::Flags;
if (std::get<Flags>(x.v.t) == Flags::DeprecatedSyntax) {
auto flags{std::get<OmpDirectiveSpecification::Flags>(x.v.t)};
if (flags.test(OmpDirectiveSpecification::Flag::DeprecatedSyntax)) {
Walk("(", std::get<std::optional<OmpArgumentList>>(x.v.t), ")");
Walk(" ", std::get<std::optional<OmpClauseList>>(x.v.t));
} else {
Expand Down Expand Up @@ -2679,8 +2679,8 @@ class UnparseVisitor {
void Unparse(const OpenMPFlushConstruct &x) {
BeginOpenMP();
Word("!$OMP FLUSH");
using Flags = OmpDirectiveSpecification::Flags;
if (std::get<Flags>(x.v.t) == Flags::DeprecatedSyntax) {
auto flags{std::get<OmpDirectiveSpecification::Flags>(x.v.t)};
if (flags.test(OmpDirectiveSpecification::Flag::DeprecatedSyntax)) {
Walk("(", std::get<std::optional<OmpArgumentList>>(x.v.t), ")");
Walk(" ", std::get<std::optional<OmpClauseList>>(x.v.t));
} else {
Expand Down
32 changes: 27 additions & 5 deletions flang/lib/Semantics/canonicalize-do.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,11 @@ class CanonicalizationOfDoLoops {
[&](common::Indirection<OpenMPConstruct> &construct) {
// If the body of the OpenMP construct ends with a label,
// treat the label as ending the construct itself.
CanonicalizeIfMatch(
block, stack, i, omp::GetFinalLabel(construct.value()));
OpenMPConstruct &omp{construct.value()};
if (CanonicalizeIfMatch(
block, stack, i, omp::GetFinalLabel(omp))) {
MarkOpenMPConstruct(omp);
}
},
},
executableConstruct->u);
Expand All @@ -103,12 +106,12 @@ class CanonicalizationOfDoLoops {

private:
template <typename T>
void CanonicalizeIfMatch(Block &originalBlock, std::vector<LabelInfo> &stack,
bool CanonicalizeIfMatch(Block &originalBlock, std::vector<LabelInfo> &stack,
Block::iterator &i, Statement<T> &statement) {
CanonicalizeIfMatch(originalBlock, stack, i, statement.label);
return CanonicalizeIfMatch(originalBlock, stack, i, statement.label);
}

void CanonicalizeIfMatch(Block &originalBlock, std::vector<LabelInfo> &stack,
bool CanonicalizeIfMatch(Block &originalBlock, std::vector<LabelInfo> &stack,
Block::iterator &i, std::optional<Label> label) {
if (!stack.empty() && label && stack.back().label == *label) {
auto currentLabel{stack.back().label};
Expand Down Expand Up @@ -141,8 +144,27 @@ class CanonicalizationOfDoLoops {
stack.pop_back();
} while (!stack.empty() && stack.back().label == currentLabel);
i = --next;
return true;
} else {
return false;
}
}

void MarkOpenMPConstruct(OpenMPConstruct &omp) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: this can currently only mark as CrossesLabelDo and it does that unconditionally - which doesn't really fit the name. How about having an argument for the flag which should be set? (in this case, always CrossesLabelDo). I think that would make the calling code a bit easier to read as well.

common::visit(
[](const auto &s) {
using S = std::decay_t<decltype(s)>;
if constexpr (std::is_base_of_v<OmpBlockConstruct, S> ||
std::is_same_v<OpenMPLoopConstruct, S>) {
const OmpDirectiveSpecification &beginSpec{s.BeginDir()};
auto &flags{
std::get<OmpDirectiveSpecification::Flags>(beginSpec.t)};
const_cast<OmpDirectiveSpecification::Flags &>(flags).set(
OmpDirectiveSpecification::Flag::CrossesLabelDo);
}
},
omp.u);
}
};

bool CanonicalizeDo(Program &program) {
Expand Down
17 changes: 17 additions & 0 deletions flang/lib/Semantics/check-omp-loop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,23 @@ void OmpStructureChecker::CheckNestedBlock(const parser::OpenMPLoopConstruct &x,
void OmpStructureChecker::CheckNestedConstruct(
const parser::OpenMPLoopConstruct &x) {
size_t nestedCount{0};
unsigned version{context_.langOptions().OpenMPVersion};

if (version <= 50) {
const parser::OmpDirectiveSpecification &beginSpec{x.BeginDir()};
auto &flags{
std::get<parser::OmpDirectiveSpecification::Flags>(beginSpec.t)};
if (flags.test(parser::OmpDirectiveSpecification::Flag::CrossesLabelDo)) {
if (auto &endSpec{x.EndDir()}) {
parser::CharBlock beginSource{beginSpec.DirName().source};
context_
.Say(endSpec->DirName().source,
"END %s directive is not allowed when the construct does not contain all loops that shares a loop-terminating statement"_err_en_US,
parser::ToUpperCaseLetters(beginSource.ToString()))
.Attach(beginSource, "The construct starts here"_en_US);
}
}
}

auto &body{std::get<parser::Block>(x.t)};
if (body.empty()) {
Expand Down
4 changes: 2 additions & 2 deletions flang/lib/Semantics/check-omp-structure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2748,8 +2748,8 @@ void OmpStructureChecker::Leave(const parser::OpenMPFlushConstruct &x) {

unsigned version{context_.langOptions().OpenMPVersion};
if (version >= 52) {
using Flags = parser::OmpDirectiveSpecification::Flags;
if (std::get<Flags>(x.v.t) == Flags::DeprecatedSyntax) {
auto &flags{std::get<parser::OmpDirectiveSpecification::Flags>(x.v.t)};
if (flags.test(parser::OmpDirectiveSpecification::Flag::DeprecatedSyntax)) {
context_.Say(x.source,
"The syntax \"FLUSH clause (object, ...)\" has been deprecated, use \"FLUSH(object, ...) clause\" instead"_warn_en_US);
}
Expand Down
4 changes: 2 additions & 2 deletions flang/test/Parser/OpenMP/allocate-align-tree.f90
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ end program allocate_align_tree
!CHECK-NEXT: | | OmpArgumentList -> OmpArgument -> OmpLocator -> OmpObject -> Designator -> DataRef -> Name = 'j'
!CHECK-NEXT: | | OmpClauseList -> OmpClause -> Align -> OmpAlignClause -> Scalar -> Integer -> Constant -> Expr = '16_4'
!CHECK-NEXT: | | | LiteralConstant -> IntLiteralConstant = '16'
!CHECK-NEXT: | | Flags = None
!CHECK-NEXT: | | Flags = {}
!CHECK-NEXT: | Block
!CHECK-NEXT: | | ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OmpAllocateDirective
!CHECK-NEXT: | | | OmpBeginDirective
Expand All @@ -38,7 +38,7 @@ end program allocate_align_tree
!CHECK-NEXT: | | | | | LiteralConstant -> IntLiteralConstant = '32'
!CHECK-NEXT: | | | | OmpClause -> Allocator -> Scalar -> Integer -> Expr = '2_8'
!CHECK-NEXT: | | | | | Designator -> DataRef -> Name = 'omp_large_cap_mem_alloc'
!CHECK-NEXT: | | | | Flags = None
!CHECK-NEXT: | | | | Flags = {}
!CHECK-NEXT: | | | Block
!CHECK-NEXT: | | | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> AllocateStmt

Expand Down
10 changes: 5 additions & 5 deletions flang/test/Parser/OpenMP/allocate-tree-spec-part.f90
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ end program allocate_tree
!CHECK-NEXT: | | | | OmpArgumentList -> OmpArgument -> OmpLocator -> OmpObject -> Designator -> DataRef -> Name = 'f'
!CHECK-NEXT: | | | | OmpClauseList -> OmpClause -> Allocator -> Scalar -> Integer -> Expr = '1_8'
!CHECK-NEXT: | | | | | Designator -> DataRef -> Name = 'omp_default_mem_alloc'
!CHECK-NEXT: | | | | Flags = None
!CHECK-NEXT: | | | | Flags = {}
!CHECK-NEXT: | | | Block
!CHECK-NEXT: | ExecutionPart -> Block
!CHECK-NEXT: | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> AssignmentStmt = 'f=2_4'
Expand All @@ -37,28 +37,28 @@ end program allocate_tree
!CHECK-NEXT: | | | | OmpArgumentList -> OmpArgument -> OmpLocator -> OmpObject -> Designator -> DataRef -> Name = 'w'
!CHECK-NEXT: | | | | OmpClauseList -> OmpClause -> Allocator -> Scalar -> Integer -> Expr = '3_8'
!CHECK-NEXT: | | | | | Designator -> DataRef -> Name = 'omp_const_mem_alloc'
!CHECK-NEXT: | | | | Flags = None
!CHECK-NEXT: | | | | Flags = {}
!CHECK-NEXT: | | | Block
!CHECK-NEXT: | | | | ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OmpAllocateDirective
!CHECK-NEXT: | | | | | OmpBeginDirective
!CHECK-NEXT: | | | | | | OmpDirectiveName -> llvm::omp::Directive = allocate
!CHECK-NEXT: | | | | | | OmpArgumentList -> OmpArgument -> OmpLocator -> OmpObject -> Designator -> DataRef -> Name = 'xarray'
!CHECK-NEXT: | | | | | | OmpClauseList -> OmpClause -> Allocator -> Scalar -> Integer -> Expr = '2_8'
!CHECK-NEXT: | | | | | | | Designator -> DataRef -> Name = 'omp_large_cap_mem_alloc'
!CHECK-NEXT: | | | | | | Flags = None
!CHECK-NEXT: | | | | | | Flags = {}
!CHECK-NEXT: | | | | | Block
!CHECK-NEXT: | | | | | | ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OmpAllocateDirective
!CHECK-NEXT: | | | | | | | OmpBeginDirective
!CHECK-NEXT: | | | | | | | | OmpDirectiveName -> llvm::omp::Directive = allocate
!CHECK-NEXT: | | | | | | | | OmpArgumentList -> OmpArgument -> OmpLocator -> OmpObject -> Designator -> DataRef -> Name = 'zarray'
!CHECK-NEXT: | | | | | | | | OmpClauseList -> OmpClause -> Allocator -> Scalar -> Integer -> Expr = '1_8'
!CHECK-NEXT: | | | | | | | | | Designator -> DataRef -> Name = 'omp_default_mem_alloc'
!CHECK-NEXT: | | | | | | | | Flags = None
!CHECK-NEXT: | | | | | | | | Flags = {}
!CHECK-NEXT: | | | | | | | Block
!CHECK-NEXT: | | | | | | | | ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OmpAllocateDirective
!CHECK-NEXT: | | | | | | | | | OmpBeginDirective
!CHECK-NEXT: | | | | | | | | | | OmpDirectiveName -> llvm::omp::Directive = allocate
!CHECK-NEXT: | | | | | | | | | | OmpClauseList ->
!CHECK-NEXT: | | | | | | | | | | Flags = None
!CHECK-NEXT: | | | | | | | | | | Flags = {}
!CHECK-NEXT: | | | | | | | | | Block
!CHECK-NEXT: | | | | | | | | | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> AllocateStmt
8 changes: 4 additions & 4 deletions flang/test/Parser/OpenMP/allocate-tree.f90
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ end program allocate_tree
!CHECK-NEXT: | | OmpArgumentList -> OmpArgument -> OmpLocator -> OmpObject -> Designator -> DataRef -> Name = 'w'
!CHECK-NEXT: | | OmpClauseList -> OmpClause -> Allocator -> Scalar -> Integer -> Expr = '3_8'
!CHECK-NEXT: | | | Designator -> DataRef -> Name = 'omp_const_mem_alloc'
!CHECK-NEXT: | | Flags = None
!CHECK-NEXT: | | Flags = {}
!CHECK-NEXT: | Block

!CHECK: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OmpAllocateDirective
Expand All @@ -33,21 +33,21 @@ end program allocate_tree
!CHECK-NEXT: | | OmpArgumentList -> OmpArgument -> OmpLocator -> OmpObject -> Designator -> DataRef -> Name = 'xarray'
!CHECK-NEXT: | | OmpClauseList -> OmpClause -> Allocator -> Scalar -> Integer -> Expr = '2_8'
!CHECK-NEXT: | | | Designator -> DataRef -> Name = 'omp_large_cap_mem_alloc'
!CHECK-NEXT: | | Flags = None
!CHECK-NEXT: | | Flags = {}
!CHECK-NEXT: | Block
!CHECK-NEXT: | | ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OmpAllocateDirective
!CHECK-NEXT: | | | OmpBeginDirective
!CHECK-NEXT: | | | | OmpDirectiveName -> llvm::omp::Directive = allocate
!CHECK-NEXT: | | | | OmpArgumentList -> OmpArgument -> OmpLocator -> OmpObject -> Designator -> DataRef -> Name = 'zarray'
!CHECK-NEXT: | | | | OmpClauseList -> OmpClause -> Allocator -> Scalar -> Integer -> Expr = '1_8'
!CHECK-NEXT: | | | | | Designator -> DataRef -> Name = 'omp_default_mem_alloc'
!CHECK-NEXT: | | | | Flags = None
!CHECK-NEXT: | | | | Flags = {}
!CHECK-NEXT: | | | Block
!CHECK-NEXT: | | | | ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OmpAllocateDirective
!CHECK-NEXT: | | | | | OmpBeginDirective
!CHECK-NEXT: | | | | | | OmpDirectiveName -> llvm::omp::Directive = allocate
!CHECK-NEXT: | | | | | | OmpClauseList ->
!CHECK-NEXT: | | | | | | Flags = None
!CHECK-NEXT: | | | | | | Flags = {}
!CHECK-NEXT: | | | | | Block
!CHECK-NEXT: | | | | | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> AllocateStmt

Expand Down
8 changes: 4 additions & 4 deletions flang/test/Parser/OpenMP/allocators-unparse.f90
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ end subroutine allocate
!PARSE-TREE-NEXT: | | OmpClauseList -> OmpClause -> Allocate -> OmpAllocateClause
!PARSE-TREE-NEXT: | | | Modifier -> OmpAllocatorSimpleModifier -> Scalar -> Integer -> Expr -> Designator -> DataRef -> Name = 'omp_default_mem_alloc'
!PARSE-TREE-NEXT: | | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'arr1'
!PARSE-TREE-NEXT: | | Flags = None
!PARSE-TREE-NEXT: | | Flags = {}
!PARSE-TREE-NEXT: | Block
!PARSE-TREE-NEXT: | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> AllocateStmt
!PARSE-TREE-NEXT: | | | Allocation
Expand All @@ -49,7 +49,7 @@ end subroutine allocate
!PARSE-TREE-NEXT: | | OmpClause -> Allocate -> OmpAllocateClause
!PARSE-TREE-NEXT: | | | Modifier -> OmpAllocatorSimpleModifier -> Scalar -> Integer -> Expr -> Designator -> DataRef -> Name = 'omp_default_mem_alloc'
!PARSE-TREE-NEXT: | | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'arr2'
!PARSE-TREE-NEXT: | | Flags = None
!PARSE-TREE-NEXT: | | Flags = {}
!PARSE-TREE-NEXT: | Block
!PARSE-TREE-NEXT: | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> AllocateStmt
!PARSE-TREE-NEXT: | | | Allocation
Expand All @@ -61,7 +61,7 @@ end subroutine allocate
!PARSE-TREE-NEXT: | | OmpClauseList -> OmpClause -> Allocate -> OmpAllocateClause
!PARSE-TREE-NEXT: | | | Modifier -> OmpAlignModifier -> Scalar -> Integer -> Expr -> LiteralConstant -> IntLiteralConstant = '32'
!PARSE-TREE-NEXT: | | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'arr2'
!PARSE-TREE-NEXT: | | Flags = None
!PARSE-TREE-NEXT: | | Flags = {}
!PARSE-TREE-NEXT: | Block
!PARSE-TREE-NEXT: | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> AllocateStmt
!PARSE-TREE-NEXT: | | | Allocation
Expand All @@ -73,4 +73,4 @@ end subroutine allocate
!PARSE-TREE-NEXT: | OmpEndDirective
!PARSE-TREE-NEXT: | | OmpDirectiveName -> llvm::omp::Directive = allocators
!PARSE-TREE-NEXT: | | OmpClauseList ->
!PARSE-TREE-NEXT: | | Flags = None
!PARSE-TREE-NEXT: | | Flags = {}
Loading