Skip to content

Commit 8115454

Browse files
authored
[flang] Extension: accept "var*length(bounds)" (#117399)
A character length specifier in an entity declaration or a component declaration is required by the standard to follow any array bounds or coarray bounds that are present. Several Fortran compilers allow the character length specifier to follow the name and appear before the bounds. Fixes #117372.
1 parent c1c9929 commit 8115454

File tree

5 files changed

+65
-15
lines changed

5 files changed

+65
-15
lines changed

flang/docs/Extensions.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,9 @@ end
391391
has the SAVE attribute and was initialized.
392392
* `PRINT namelistname` is accepted and interpreted as
393393
`WRITE(*,NML=namelistname)`, a near-universal extension.
394+
* A character length specifier in a component or entity declaration
395+
is accepted before an array specification (`ch*3(2)`) as well
396+
as afterwards.
394397

395398
### Extensions supported when enabled by options
396399

flang/include/flang/Parser/parse-tree.h

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,10 +1024,18 @@ struct Initialization {
10241024

10251025
// R739 component-decl ->
10261026
// component-name [( component-array-spec )]
1027-
// [lbracket coarray-spec rbracket] [* char-length]
1028-
// [component-initialization]
1027+
// [lbracket coarray-spec rbracket] [* char-length]
1028+
// [component-initialization] |
1029+
// component-name *char-length [( component-array-spec )]
1030+
// [lbracket coarray-spec rbracket] [component-initialization]
10291031
struct ComponentDecl {
10301032
TUPLE_CLASS_BOILERPLATE(ComponentDecl);
1033+
ComponentDecl(Name &&name, CharLength &&length,
1034+
std::optional<ComponentArraySpec> &&aSpec,
1035+
std::optional<CoarraySpec> &&coaSpec,
1036+
std::optional<Initialization> &&init)
1037+
: t{std::move(name), std::move(aSpec), std::move(coaSpec),
1038+
std::move(length), std::move(init)} {}
10311039
std::tuple<Name, std::optional<ComponentArraySpec>,
10321040
std::optional<CoarraySpec>, std::optional<CharLength>,
10331041
std::optional<Initialization>>
@@ -1381,9 +1389,16 @@ struct AttrSpec {
13811389
// R803 entity-decl ->
13821390
// object-name [( array-spec )] [lbracket coarray-spec rbracket]
13831391
// [* char-length] [initialization] |
1384-
// function-name [* char-length]
1392+
// function-name [* char-length] |
1393+
// (ext.) object-name *char-length [( array-spec )]
1394+
// [lbracket coarray-spec rbracket] [initialization]
13851395
struct EntityDecl {
13861396
TUPLE_CLASS_BOILERPLATE(EntityDecl);
1397+
EntityDecl(ObjectName &&name, CharLength &&length,
1398+
std::optional<ArraySpec> &&aSpec, std::optional<CoarraySpec> &&coaSpec,
1399+
std::optional<Initialization> &&init)
1400+
: t{std::move(name), std::move(aSpec), std::move(coaSpec),
1401+
std::move(length), std::move(init)} {}
13871402
std::tuple<ObjectName, std::optional<ArraySpec>, std::optional<CoarraySpec>,
13881403
std::optional<CharLength>, std::optional<Initialization>>
13891404
t;

flang/lib/Parser/Fortran-parsers.cpp

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ TYPE_PARSER(construct<ComponentAttrSpec>(accessSpec) ||
460460
construct<ComponentAttrSpec>(allocatable) ||
461461
construct<ComponentAttrSpec>("CODIMENSION" >> coarraySpec) ||
462462
construct<ComponentAttrSpec>(contiguous) ||
463-
construct<ComponentAttrSpec>("DIMENSION" >> Parser<ComponentArraySpec>{}) ||
463+
construct<ComponentAttrSpec>("DIMENSION" >> componentArraySpec) ||
464464
construct<ComponentAttrSpec>(pointer) ||
465465
extension<LanguageFeature::CUDA>(
466466
construct<ComponentAttrSpec>(Parser<common::CUDADataAttr>{})) ||
@@ -471,17 +471,23 @@ TYPE_PARSER(construct<ComponentAttrSpec>(accessSpec) ||
471471

472472
// R739 component-decl ->
473473
// component-name [( component-array-spec )]
474-
// [lbracket coarray-spec rbracket] [* char-length]
475-
// [component-initialization]
474+
// [lbracket coarray-spec rbracket] [* char-length]
475+
// [component-initialization] |
476+
// (ext.) component-name *char-length [(component-array-spec)]
477+
// [lbracket coarray-spec rbracket] [* char-length]
478+
// [component-initialization]
476479
TYPE_CONTEXT_PARSER("component declaration"_en_US,
477-
construct<ComponentDecl>(name, maybe(Parser<ComponentArraySpec>{}),
478-
maybe(coarraySpec), maybe("*" >> charLength), maybe(initialization)))
480+
construct<ComponentDecl>(name, "*" >> charLength, maybe(componentArraySpec),
481+
maybe(coarraySpec), maybe(initialization)) ||
482+
construct<ComponentDecl>(name, maybe(componentArraySpec),
483+
maybe(coarraySpec), maybe("*" >> charLength),
484+
maybe(initialization)))
479485
// The source field of the Name will be replaced with a distinct generated name.
480486
TYPE_CONTEXT_PARSER("%FILL item"_en_US,
481487
extension<LanguageFeature::DECStructures>(
482488
"nonstandard usage: %FILL"_port_en_US,
483489
construct<FillDecl>(space >> sourced("%FILL" >> construct<Name>()),
484-
maybe(Parser<ComponentArraySpec>{}), maybe("*" >> charLength))))
490+
maybe(componentArraySpec), maybe("*" >> charLength))))
485491
TYPE_PARSER(construct<ComponentOrFill>(Parser<ComponentDecl>{}) ||
486492
construct<ComponentOrFill>(Parser<FillDecl>{}))
487493

@@ -658,9 +664,13 @@ TYPE_PARSER(recovery("END ENUM"_tok, constructEndStmtErrorRecovery) >>
658664

659665
// R801 type-declaration-stmt ->
660666
// declaration-type-spec [[, attr-spec]... ::] entity-decl-list
661-
constexpr auto entityDeclWithoutEqInit{construct<EntityDecl>(name,
662-
maybe(arraySpec), maybe(coarraySpec), maybe("*" >> charLength),
663-
!"="_tok >> maybe(initialization))}; // old-style REAL A/0/ still works
667+
constexpr auto entityDeclWithoutEqInit{
668+
construct<EntityDecl>(name, "*" >> charLength, maybe(arraySpec),
669+
maybe(coarraySpec), !"="_tok >> maybe(initialization)) ||
670+
construct<EntityDecl>(name, maybe(arraySpec), maybe(coarraySpec),
671+
maybe("*" >> charLength),
672+
!"="_tok >>
673+
maybe(initialization) /* old-style REAL A/0/ still works */)};
664674
TYPE_PARSER(
665675
construct<TypeDeclarationStmt>(declarationTypeSpec,
666676
defaulted("," >> nonemptyList(Parser<AttrSpec>{})) / "::",
@@ -720,9 +730,13 @@ constexpr auto objectName{name};
720730
// R803 entity-decl ->
721731
// object-name [( array-spec )] [lbracket coarray-spec rbracket]
722732
// [* char-length] [initialization] |
723-
// function-name [* char-length]
724-
TYPE_PARSER(construct<EntityDecl>(objectName, maybe(arraySpec),
725-
maybe(coarraySpec), maybe("*" >> charLength), maybe(initialization)))
733+
// function-name [* char-length] |
734+
// (ext.) object-name *char-length [(array-spec)]
735+
// [lbracket coarray-spec rbracket] [initialization]
736+
TYPE_PARSER(construct<EntityDecl>(objectName, "*" >> charLength,
737+
maybe(arraySpec), maybe(coarraySpec), maybe(initialization)) ||
738+
construct<EntityDecl>(objectName, maybe(arraySpec), maybe(coarraySpec),
739+
maybe("*" >> charLength), maybe(initialization)))
726740

727741
// R806 null-init -> function-reference ... which must resolve to NULL()
728742
TYPE_PARSER(lookAhead(name / "( )") >> construct<NullInit>(expr))

flang/lib/Parser/type-parsers.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ constexpr Parser<LanguageBindingSpec> languageBindingSpec; // R808, R1528
7272
constexpr Parser<EntityDecl> entityDecl; // R803
7373
constexpr Parser<CoarraySpec> coarraySpec; // R809
7474
constexpr Parser<ArraySpec> arraySpec; // R815
75+
constexpr Parser<ComponentArraySpec> componentArraySpec;
7576
constexpr Parser<ExplicitShapeSpec> explicitShapeSpec; // R816
7677
constexpr Parser<DeferredShapeSpecList> deferredShapeSpecList; // R820
7778
constexpr Parser<AssumedImpliedSpec> assumedImpliedSpec; // R821
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
! RUN: %flang_fc1 -fdebug-unparse %s 2>&1 | FileCheck %s
2+
! Test parsing of alternative order of char-length in an
3+
! entity-decl or component-decl.
4+
program p
5+
type t
6+
!CHECK: CHARACTER c1(2_4)*3/"abc", "def"/
7+
character c1*3(2)/'abc','def'/
8+
end type
9+
integer, parameter :: n=3
10+
!CHECK: CHARACTER v1(2_4)*(3_4)/"ghi", "jkl"/
11+
character v1*(n)(2)/'ghi','jkl'/
12+
!CHECK: CHARACTER :: v2(1_4)*2 = "mn"
13+
character::v2*2(1)='mn'
14+
end
15+
16+
17+

0 commit comments

Comments
 (0)