Skip to content

Commit 9e7eef9

Browse files
committed
[flang] Handle parameter-dependent types in PDT initializers
For parameterized derived type component initializers whose expressions' types depend on parameter values, f18's current scheme of analyzing the initialization expression once during name resolution fails. For example, type :: pdt(k) integer, kind :: k real :: component = real(0.0, kind=k) end type To handle such cases, it is necessary to re-analyze the parse trees of these initialization expressions once for each distinct initialization of the type. This patch adds code to wipe an expression parse tree of its typed expressions, and update those of its symbol table pointers that reference type parameters, and then re-analyze that parse tree to generate the properly typed component initializers. Differential Revision: https://reviews.llvm.org/D123728
1 parent 3be3b40 commit 9e7eef9

File tree

13 files changed

+133
-35
lines changed

13 files changed

+133
-35
lines changed

flang/include/flang/Common/indirection.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -154,11 +154,14 @@ template <typename A> class ForwardOwningPointer {
154154
return result;
155155
}
156156

157-
void Reset(A *p, void (*del)(A *)) {
157+
void Reset(A *p = nullptr) {
158158
if (p_) {
159159
deleter_(p_);
160160
}
161161
p_ = p;
162+
}
163+
void Reset(A *p, void (*del)(A *)) {
164+
Reset(p);
162165
deleter_ = del;
163166
}
164167

flang/include/flang/Parser/unparse.h

+11-2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class ProcedureRef;
2727
namespace Fortran::parser {
2828

2929
struct Program;
30+
struct Expr;
3031

3132
// A function called before each Statement is unparsed.
3233
using preStatementType =
@@ -43,11 +44,19 @@ struct AnalyzedObjectsAsFortran {
4344
std::function<void(llvm::raw_ostream &, const evaluate::ProcedureRef &)> call;
4445
};
4546

46-
// Converts parsed program to out as Fortran.
47-
void Unparse(llvm::raw_ostream &out, const Program &program,
47+
// Converts parsed program (or fragment) to out as Fortran.
48+
template <typename A>
49+
void Unparse(llvm::raw_ostream &out, const A &root,
4850
Encoding encoding = Encoding::UTF_8, bool capitalizeKeywords = true,
4951
bool backslashEscapes = true, preStatementType *preStatement = nullptr,
5052
AnalyzedObjectsAsFortran * = nullptr);
53+
54+
extern template void Unparse(llvm::raw_ostream &out, const Program &program,
55+
Encoding encoding, bool capitalizeKeywords, bool backslashEscapes,
56+
preStatementType *preStatement, AnalyzedObjectsAsFortran *);
57+
extern template void Unparse(llvm::raw_ostream &out, const Expr &expr,
58+
Encoding encoding, bool capitalizeKeywords, bool backslashEscapes,
59+
preStatementType *preStatement, AnalyzedObjectsAsFortran *);
5160
} // namespace Fortran::parser
5261

5362
#endif

flang/include/flang/Semantics/expression.h

+6
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,12 @@ class ExprChecker {
480480
exprAnalyzer_.set_inWhereBody(InWhereBody());
481481
}
482482

483+
bool Pre(const parser::ComponentDefStmt &) {
484+
// Already analyzed in name resolution and PDT instantiation;
485+
// do not attempt to re-analyze now without type parameters.
486+
return false;
487+
}
488+
483489
template <typename A> bool Pre(const parser::Scalar<A> &x) {
484490
exprAnalyzer_.Analyze(x);
485491
return false;

flang/include/flang/Semantics/symbol.h

+10
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
namespace llvm {
2525
class raw_ostream;
2626
}
27+
namespace Fortran::parser {
28+
struct Expr;
29+
}
2730

2831
namespace Fortran::semantics {
2932

@@ -190,6 +193,12 @@ class ObjectEntityDetails : public EntityDetails {
190193
MaybeExpr &init() { return init_; }
191194
const MaybeExpr &init() const { return init_; }
192195
void set_init(MaybeExpr &&expr) { init_ = std::move(expr); }
196+
const parser::Expr *unanalyzedPDTComponentInit() const {
197+
return unanalyzedPDTComponentInit_;
198+
}
199+
void set_unanalyzedPDTComponentInit(const parser::Expr *expr) {
200+
unanalyzedPDTComponentInit_ = expr;
201+
}
193202
ArraySpec &shape() { return shape_; }
194203
const ArraySpec &shape() const { return shape_; }
195204
ArraySpec &coshape() { return coshape_; }
@@ -211,6 +220,7 @@ class ObjectEntityDetails : public EntityDetails {
211220

212221
private:
213222
MaybeExpr init_;
223+
const parser::Expr *unanalyzedPDTComponentInit_{nullptr};
214224
ArraySpec shape_;
215225
ArraySpec coshape_;
216226
const Symbol *commonBlock_{nullptr}; // common block this object is in

flang/lib/Parser/unparse.cpp

+8-2
Original file line numberDiff line numberDiff line change
@@ -2733,12 +2733,18 @@ void UnparseVisitor::Word(const char *str) {
27332733

27342734
void UnparseVisitor::Word(const std::string &str) { Word(str.c_str()); }
27352735

2736-
void Unparse(llvm::raw_ostream &out, const Program &program, Encoding encoding,
2736+
template <typename A>
2737+
void Unparse(llvm::raw_ostream &out, const A &root, Encoding encoding,
27372738
bool capitalizeKeywords, bool backslashEscapes,
27382739
preStatementType *preStatement, AnalyzedObjectsAsFortran *asFortran) {
27392740
UnparseVisitor visitor{out, 1, encoding, capitalizeKeywords, backslashEscapes,
27402741
preStatement, asFortran};
2741-
Walk(program, visitor);
2742+
Walk(root, visitor);
27422743
visitor.Done();
27432744
}
2745+
2746+
template void Unparse<Program>(llvm::raw_ostream &, const Program &, Encoding,
2747+
bool, bool, preStatementType *, AnalyzedObjectsAsFortran *);
2748+
template void Unparse<Expr>(llvm::raw_ostream &, const Expr &, Encoding, bool,
2749+
bool, preStatementType *, AnalyzedObjectsAsFortran *);
27442750
} // namespace Fortran::parser

flang/lib/Semantics/expression.cpp

+2-4
Original file line numberDiff line numberDiff line change
@@ -693,10 +693,8 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::Name &n) {
693693
if (std::optional<int> kind{IsImpliedDo(n.source)}) {
694694
return AsMaybeExpr(ConvertToKind<TypeCategory::Integer>(
695695
*kind, AsExpr(ImpliedDoIndex{n.source})));
696-
} else if (context_.HasError(n)) {
697-
return std::nullopt;
698-
} else if (!n.symbol) {
699-
SayAt(n, "Internal error: unresolved name '%s'"_err_en_US, n.source);
696+
}
697+
if (context_.HasError(n.symbol)) { // includes case of no symbol
700698
return std::nullopt;
701699
} else {
702700
const Symbol &ultimate{n.symbol->GetUltimate()};

flang/lib/Semantics/mod-file.cpp

+13-10
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "flang/Evaluate/tools.h"
1313
#include "flang/Parser/message.h"
1414
#include "flang/Parser/parsing.h"
15+
#include "flang/Parser/unparse.h"
1516
#include "flang/Semantics/scope.h"
1617
#include "flang/Semantics/semantics.h"
1718
#include "flang/Semantics/symbol.h"
@@ -45,7 +46,8 @@ struct ModHeader {
4546
static std::optional<SourceName> GetSubmoduleParent(const parser::Program &);
4647
static void CollectSymbols(const Scope &, SymbolVector &, SymbolVector &);
4748
static void PutPassName(llvm::raw_ostream &, const std::optional<SourceName> &);
48-
static void PutInit(llvm::raw_ostream &, const Symbol &, const MaybeExpr &);
49+
static void PutInit(llvm::raw_ostream &, const Symbol &, const MaybeExpr &,
50+
const parser::Expr *);
4951
static void PutInit(llvm::raw_ostream &, const MaybeIntExpr &);
5052
static void PutBound(llvm::raw_ostream &, const Bound &);
5153
static void PutShapeSpec(llvm::raw_ostream &, const ShapeSpec &);
@@ -399,7 +401,7 @@ void ModFileWriter::PutDECStructure(
399401
}
400402
decls_ << ref->name();
401403
PutShape(decls_, object->shape(), '(', ')');
402-
PutInit(decls_, *ref, object->init());
404+
PutInit(decls_, *ref, object->init(), nullptr);
403405
emittedDECFields_.insert(*ref);
404406
} else if (any) {
405407
break; // any later use of this structure will use RECORD/str/
@@ -661,7 +663,7 @@ void ModFileWriter::PutObjectEntity(
661663
symbol.attrs());
662664
PutShape(os, details.shape(), '(', ')');
663665
PutShape(os, details.coshape(), '[', ']');
664-
PutInit(os, symbol, details.init());
666+
PutInit(os, symbol, details.init(), details.unanalyzedPDTComponentInit());
665667
os << '\n';
666668
}
667669

@@ -715,13 +717,14 @@ void ModFileWriter::PutTypeParam(llvm::raw_ostream &os, const Symbol &symbol) {
715717
os << '\n';
716718
}
717719

718-
void PutInit(
719-
llvm::raw_ostream &os, const Symbol &symbol, const MaybeExpr &init) {
720-
if (init) {
721-
if (symbol.attrs().test(Attr::PARAMETER) ||
722-
symbol.owner().IsDerivedType()) {
723-
os << (symbol.attrs().test(Attr::POINTER) ? "=>" : "=");
724-
init->AsFortran(os);
720+
void PutInit(llvm::raw_ostream &os, const Symbol &symbol, const MaybeExpr &init,
721+
const parser::Expr *unanalyzed) {
722+
if (symbol.attrs().test(Attr::PARAMETER) || symbol.owner().IsDerivedType()) {
723+
const char *assign{symbol.attrs().test(Attr::POINTER) ? "=>" : "="};
724+
if (unanalyzed) {
725+
parser::Unparse(os << assign, *unanalyzed);
726+
} else if (init) {
727+
init->AsFortran(os << assign);
725728
}
726729
}
727730
}

flang/lib/Semantics/resolve-names.cpp

+6-7
Original file line numberDiff line numberDiff line change
@@ -6599,14 +6599,13 @@ void DeclarationVisitor::NonPointerInitialization(
65996599
CHECK(!details->init());
66006600
Walk(expr);
66016601
if (ultimate.owner().IsParameterizedDerivedType()) {
6602-
// Can't convert to type of component, which might not yet
6603-
// be known; that's done later during PDT instantiation.
6604-
if (MaybeExpr value{EvaluateExpr(expr)}) {
6605-
details->set_init(std::move(*value));
6602+
// Save the expression for per-instantiation analysis.
6603+
details->set_unanalyzedPDTComponentInit(&expr.thing.value());
6604+
} else {
6605+
if (MaybeExpr folded{EvaluateNonPointerInitializer(
6606+
ultimate, expr, expr.thing.value().source)}) {
6607+
details->set_init(std::move(*folded));
66066608
}
6607-
} else if (MaybeExpr folded{EvaluateNonPointerInitializer(
6608-
ultimate, expr, expr.thing.value().source)}) {
6609-
details->set_init(std::move(*folded));
66106609
}
66116610
}
66126611
}

flang/lib/Semantics/symbol.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,9 @@ llvm::raw_ostream &operator<<(
380380
DumpList(os, "shape", x.shape());
381381
DumpList(os, "coshape", x.coshape());
382382
DumpExpr(os, "init", x.init_);
383+
if (x.unanalyzedPDTComponentInit()) {
384+
os << " (has unanalyzedPDTComponentInit)";
385+
}
383386
return os;
384387
}
385388

flang/lib/Semantics/type.cpp

+38
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "flang/Evaluate/fold.h"
1313
#include "flang/Evaluate/tools.h"
1414
#include "flang/Parser/characters.h"
15+
#include "flang/Parser/parse-tree-visitor.h"
1516
#include "flang/Semantics/scope.h"
1617
#include "flang/Semantics/symbol.h"
1718
#include "flang/Semantics/tools.h"
@@ -378,6 +379,31 @@ void InstantiateHelper::InstantiateComponents(const Scope &fromScope) {
378379
ComputeOffsets(context(), scope_);
379380
}
380381

382+
// Walks a parsed expression to prepare it for (re)analysis;
383+
// clears out the typedExpr analysis results and re-resolves
384+
// symbol table pointers of type parameters.
385+
class ComponentInitResetHelper {
386+
public:
387+
explicit ComponentInitResetHelper(Scope &scope) : scope_{scope} {}
388+
389+
template <typename A> bool Pre(const A &) { return true; }
390+
391+
template <typename A> void Post(const A &x) {
392+
if constexpr (parser::HasTypedExpr<A>()) {
393+
x.typedExpr.Reset();
394+
}
395+
}
396+
397+
void Post(const parser::Name &name) {
398+
if (name.symbol && name.symbol->has<TypeParamDetails>()) {
399+
name.symbol = scope_.FindSymbol(name.source);
400+
}
401+
}
402+
403+
private:
404+
Scope &scope_;
405+
};
406+
381407
void InstantiateHelper::InstantiateComponent(const Symbol &oldSymbol) {
382408
auto pair{scope_.try_emplace(
383409
oldSymbol.name(), oldSymbol.attrs(), common::Clone(oldSymbol.details()))};
@@ -409,6 +435,18 @@ void InstantiateHelper::InstantiateComponent(const Symbol &oldSymbol) {
409435
dim.ubound().SetExplicit(Fold(std::move(dim.ubound().GetExplicit())));
410436
}
411437
}
438+
if (const auto *parsedExpr{details->unanalyzedPDTComponentInit()}) {
439+
// Analyze the parsed expression in this PDT instantiation context.
440+
ComponentInitResetHelper resetter{scope_};
441+
parser::Walk(*parsedExpr, resetter);
442+
auto restorer{foldingContext().messages().SetLocation(newSymbol.name())};
443+
details->set_init(evaluate::Fold(
444+
foldingContext(), AnalyzeExpr(context(), *parsedExpr)));
445+
details->set_unanalyzedPDTComponentInit(nullptr);
446+
// Remove analysis results to prevent unparsing or other use of
447+
// instantiation-specific expressions.
448+
parser::Walk(*parsedExpr, resetter);
449+
}
412450
if (MaybeExpr & init{details->init()}) {
413451
// Non-pointer components with default initializers are
414452
// processed now so that those default initializers can be used

flang/test/Semantics/init01.f90

+5-4
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ subroutine dataobjects(j)
4646
real :: x10(2,3) = reshape([real::(k,k=1,6)], [3, 2])
4747
end subroutine
4848

49-
subroutine components
49+
subroutine components(n)
50+
integer, intent(in) :: n
5051
real, target, save :: a1(3)
5152
real, target :: a2
5253
real, save :: a3
@@ -64,7 +65,7 @@ subroutine components
6465
!ERROR: Dimension 1 of initialized object has extent 2, but initialization expression has extent 3
6566
real :: x2(kind) = [1., 2., 3.]
6667
!ERROR: Dimension 1 of initialized object has extent 2, but initialization expression has extent 3
67-
!ERROR: An automatic variable or component must not be initialized
68+
!ERROR: Shape of initialized object 'x3' must be constant
6869
real :: x3(len) = [1., 2., 3.]
6970
real, pointer :: p1(:) => a1
7071
!ERROR: An initial data target may not be a reference to an object 'a2' that lacks the SAVE attribute
@@ -80,8 +81,8 @@ subroutine components
8081
!ERROR: Pointer has rank 1 but target has rank 0
8182
real, pointer :: p5(:) => a4
8283
end type
83-
type(t2(3,3)) :: o1
84-
type(t2(2,2)) :: o2
84+
type(t2(3,2)) :: o1
85+
type(t2(2,n)) :: o2
8586
type :: t3
8687
real :: x
8788
end type

flang/test/Semantics/modfile48.f90

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
! RUN: %python %S/test_modfile.py %s %flang_fc1
2+
! Ensure proper formatting of component initializers in PDTs;
3+
! they should be unparsed from their parse trees.
4+
module m
5+
type :: t(k)
6+
integer, kind :: k
7+
real(kind=k) :: x = real(0., kind=k)
8+
end type
9+
end module
10+
11+
!Expect: m.mod
12+
!module m
13+
!type::t(k)
14+
!integer(4),kind::k
15+
!real(int(int(k,kind=4),kind=8))::x=real(0., kind=k)
16+
!end type
17+
!intrinsic::real
18+
!end

flang/test/Semantics/structconst02.f90

+9-5
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ end function realfunc
1111
type :: scalar(ik,rk,zk,ck,lk,len)
1212
integer, kind :: ik = 4, rk = 4, zk = 4, ck = 1, lk = 1
1313
integer, len :: len = 1
14-
integer(kind=ik) :: ix = 0
15-
real(kind=rk) :: rx = 0.
16-
complex(kind=zk) :: zx = (0.,0.)
17-
!ERROR: An automatic variable or component must not be initialized
14+
integer(kind=ik) :: ix = int(0,kind=ik)
15+
real(kind=rk) :: rx = real(0.,kind=rk)
16+
complex(kind=zk) :: zx = cmplx(0.,0.,kind=zk)
17+
!ERROR: Initialization expression for 'cx' (%SET_LENGTH(" ",len)) cannot be computed as a constant value
1818
character(kind=ck,len=len) :: cx = ' '
1919
logical(kind=lk) :: lx = .false.
2020
real(kind=rk), pointer :: rp => NULL()
@@ -25,7 +25,11 @@ end function realfunc
2525
subroutine scalararg(x)
2626
type(scalar), intent(in) :: x
2727
end subroutine scalararg
28-
subroutine errors
28+
subroutine errors(n)
29+
integer, intent(in) :: n
30+
call scalararg(scalar(4)()) ! ok
31+
!ERROR: Structure constructor lacks a value for component 'cx'
32+
call scalararg(scalar(len=n)()) ! triggers error on 'cx'
2933
call scalararg(scalar(4)(ix=1,rx=2.,zx=(3.,4.),cx='a',lx=.true.))
3034
call scalararg(scalar(4)(1,2.,(3.,4.),'a',.true.))
3135
! call scalararg(scalar(4)(ix=5.,rx=6,zx=(7._8,8._2),cx=4_'b',lx=.true._4))

0 commit comments

Comments
 (0)