Skip to content

Commit b0bdc7f

Browse files
authored
[flang] Fix subtle type naming bug in module file output (#108892)
A derived type specification in semantics holds both its source name (for location purposes) and its ultimate derived type symbol. But for correct module file generation of a structure constructor using that derived type spec, the original symbol may be needed so that USE association can be exposed. Save both the original symbol and its ultimate symbol in the DerivedTypeSpec, and collect the right one when traversing expressions (specifically for handling initialization in module files). Fixes #108827.
1 parent d5d1417 commit b0bdc7f

File tree

9 files changed

+88
-32
lines changed

9 files changed

+88
-32
lines changed

flang/include/flang/Evaluate/traverse.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ class Traverse {
217217
return CombineContents(x);
218218
}
219219
Result operator()(const semantics::DerivedTypeSpec &x) const {
220-
return Combine(x.typeSymbol(), x.parameters());
220+
return Combine(x.originalTypeSymbol(), x.parameters());
221221
}
222222
Result operator()(const StructureConstructorValues::value_type &x) const {
223223
return visitor_(x.second);

flang/include/flang/Semantics/type.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ class DerivedTypeSpec {
259259
DerivedTypeSpec(DerivedTypeSpec &&);
260260

261261
const SourceName &name() const { return name_; }
262+
const Symbol &originalTypeSymbol() const { return originalTypeSymbol_; }
262263
const Symbol &typeSymbol() const { return typeSymbol_; }
263264
const Scope *scope() const { return scope_; }
264265
// Return scope_ if it is set, or the typeSymbol_ scope otherwise.
@@ -319,7 +320,8 @@ class DerivedTypeSpec {
319320

320321
private:
321322
SourceName name_;
322-
const Symbol &typeSymbol_;
323+
const Symbol &originalTypeSymbol_;
324+
const Symbol &typeSymbol_; // == originalTypeSymbol_.GetUltimate()
323325
const Scope *scope_{nullptr}; // same as typeSymbol_.scope() unless PDT
324326
bool cooked_{false};
325327
bool evaluated_{false};
@@ -328,8 +330,9 @@ class DerivedTypeSpec {
328330
ParameterMapType parameters_;
329331
Category category_{Category::DerivedType};
330332
bool RawEquals(const DerivedTypeSpec &that) const {
331-
return &typeSymbol_ == &that.typeSymbol_ && cooked_ == that.cooked_ &&
332-
rawParameters_ == that.rawParameters_;
333+
return &typeSymbol_ == &that.typeSymbol_ &&
334+
&originalTypeSymbol_ == &that.originalTypeSymbol_ &&
335+
cooked_ == that.cooked_ && rawParameters_ == that.rawParameters_;
333336
}
334337
friend llvm::raw_ostream &operator<<(
335338
llvm::raw_ostream &, const DerivedTypeSpec &);

flang/lib/Evaluate/characteristics.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,9 @@ bool ShapesAreCompatible(const std::optional<Shape> &x,
6666
}
6767

6868
bool TypeAndShape::operator==(const TypeAndShape &that) const {
69-
return type_ == that.type_ && ShapesAreCompatible(shape_, that.shape_) &&
70-
attrs_ == that.attrs_ && corank_ == that.corank_;
69+
return type_.IsEquivalentTo(that.type_) &&
70+
ShapesAreCompatible(shape_, that.shape_) && attrs_ == that.attrs_ &&
71+
corank_ == that.corank_;
7172
}
7273

7374
TypeAndShape &TypeAndShape::Rewrite(FoldingContext &context) {

flang/lib/Semantics/check-declarations.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2519,7 +2519,7 @@ void CheckHelper::CheckProcBinding(
25192519
? "A NOPASS type-bound procedure may not override a passed-argument procedure"_err_en_US
25202520
: "A passed-argument type-bound procedure may not override a NOPASS procedure"_err_en_US);
25212521
} else {
2522-
const auto *bindingChars{Characterize(binding.symbol())};
2522+
const auto *bindingChars{Characterize(symbol)};
25232523
const auto *overriddenChars{Characterize(*overridden)};
25242524
if (bindingChars && overriddenChars) {
25252525
if (isNopass) {

flang/lib/Semantics/resolve-names.cpp

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3053,11 +3053,16 @@ void ModuleVisitor::DoAddUse(SourceName location, SourceName localName,
30533053
const Symbol &useUltimate{useSymbol.GetUltimate()};
30543054
const auto *useGeneric{useUltimate.detailsIf<GenericDetails>()};
30553055
if (localSymbol->has<UnknownDetails>()) {
3056-
if (useGeneric && useGeneric->specific() &&
3057-
IsProcedurePointer(*useGeneric->specific())) {
3058-
// We are use-associating a generic that shadows a procedure pointer.
3059-
// Local references that might be made to that procedure pointer should
3060-
// use a UseDetails symbol for proper data addressing. So create an
3056+
if (useGeneric &&
3057+
((useGeneric->specific() &&
3058+
IsProcedurePointer(*useGeneric->specific())) ||
3059+
(useGeneric->derivedType() &&
3060+
useUltimate.name() != localSymbol->name()))) {
3061+
// We are use-associating a generic that either shadows a procedure
3062+
// pointer or shadows a derived type of the same name.
3063+
// Local references that might be made to the procedure pointer should
3064+
// use a UseDetails symbol for proper data addressing, and a derived
3065+
// type needs to be in scope with the renamed name. So create an
30613066
// empty local generic now into which the use-associated generic may
30623067
// be copied.
30633068
localSymbol->set_details(GenericDetails{});
@@ -3153,9 +3158,15 @@ void ModuleVisitor::DoAddUse(SourceName location, SourceName localName,
31533158
if (!useDerivedType) {
31543159
combinedDerivedType = localDerivedType;
31553160
} else if (!localDerivedType) {
3156-
combinedDerivedType = useDerivedType;
3161+
if (useDerivedType->name() == localName) {
3162+
combinedDerivedType = useDerivedType;
3163+
} else {
3164+
Symbol &combined{currScope().MakeSymbol(localName,
3165+
useDerivedType->attrs(), UseDetails{localName, *useDerivedType})};
3166+
combinedDerivedType = &combined;
3167+
}
31573168
} else {
3158-
const Scope *localScope{localDerivedType->scope()};
3169+
const Scope *localScope{localDerivedType->GetUltimate().scope()};
31593170
const Scope *useScope{useDerivedType->GetUltimate().scope()};
31603171
if (localScope && useScope && localScope->derivedTypeSpec() &&
31613172
useScope->derivedTypeSpec() &&
@@ -6776,9 +6787,7 @@ std::optional<DerivedTypeSpec> DeclarationVisitor::ResolveDerivedType(
67766787
}
67776788
if (CheckUseError(name)) {
67786789
return std::nullopt;
6779-
}
6780-
symbol = &symbol->GetUltimate();
6781-
if (symbol->has<DerivedTypeDetails>()) {
6790+
} else if (symbol->GetUltimate().has<DerivedTypeDetails>()) {
67826791
return DerivedTypeSpec{name.source, *symbol};
67836792
} else {
67846793
Say(name, "'%s' is not a derived type"_err_en_US);
@@ -7120,12 +7129,10 @@ bool ConstructVisitor::Pre(const parser::DataStmtValue &x) {
71207129
auto &mutableData{const_cast<parser::DataStmtConstant &>(data)};
71217130
if (auto *elem{parser::Unwrap<parser::ArrayElement>(mutableData)}) {
71227131
if (const auto *name{std::get_if<parser::Name>(&elem->base.u)}) {
7123-
if (const Symbol * symbol{FindSymbol(*name)}) {
7124-
const Symbol &ultimate{symbol->GetUltimate()};
7125-
if (ultimate.has<DerivedTypeDetails>()) {
7126-
mutableData.u = elem->ConvertToStructureConstructor(
7127-
DerivedTypeSpec{name->source, ultimate});
7128-
}
7132+
if (const Symbol * symbol{FindSymbol(*name)};
7133+
symbol && symbol->GetUltimate().has<DerivedTypeDetails>()) {
7134+
mutableData.u = elem->ConvertToStructureConstructor(
7135+
DerivedTypeSpec{name->source, *symbol});
71297136
}
71307137
}
71317138
}

flang/lib/Semantics/type.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@
2222
namespace Fortran::semantics {
2323

2424
DerivedTypeSpec::DerivedTypeSpec(SourceName name, const Symbol &typeSymbol)
25-
: name_{name}, typeSymbol_{typeSymbol} {
26-
CHECK(typeSymbol.has<DerivedTypeDetails>());
25+
: name_{name}, originalTypeSymbol_{typeSymbol},
26+
typeSymbol_{typeSymbol.GetUltimate()} {
27+
CHECK(typeSymbol_.has<DerivedTypeDetails>());
2728
}
2829
DerivedTypeSpec::DerivedTypeSpec(const DerivedTypeSpec &that) = default;
2930
DerivedTypeSpec::DerivedTypeSpec(DerivedTypeSpec &&that) = default;
@@ -340,9 +341,7 @@ void DerivedTypeSpec::Instantiate(Scope &containingScope) {
340341
const Scope &typeScope{DEREF(typeSymbol_.scope())};
341342
if (!MightBeParameterized()) {
342343
scope_ = &typeScope;
343-
if (typeScope.derivedTypeSpec()) {
344-
CHECK(*this == *typeScope.derivedTypeSpec());
345-
} else {
344+
if (!typeScope.derivedTypeSpec() || *this != *typeScope.derivedTypeSpec()) {
346345
Scope &mutableTypeScope{const_cast<Scope &>(typeScope)};
347346
mutableTypeScope.set_derivedTypeSpec(*this);
348347
InstantiateNonPDTScope(mutableTypeScope, containingScope);
@@ -664,7 +663,7 @@ std::string DerivedTypeSpec::VectorTypeAsFortran() const {
664663
std::string DerivedTypeSpec::AsFortran() const {
665664
std::string buf;
666665
llvm::raw_string_ostream ss{buf};
667-
ss << name_;
666+
ss << originalTypeSymbol_.name();
668667
if (!rawParameters_.empty()) {
669668
CHECK(parameters_.empty());
670669
ss << '(';

flang/test/Semantics/get_team.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ program get_team_test
4949
!ERROR: repeated keyword argument to intrinsic 'get_team'
5050
result_team = get_team(level=initial_team, level=parent_team)
5151

52-
!ERROR: No intrinsic or user-defined ASSIGNMENT(=) matches operand types LOGICAL(4) and TYPE(__builtin_team_type)
52+
!ERROR: No intrinsic or user-defined ASSIGNMENT(=) matches operand types LOGICAL(4) and TYPE(team_type)
5353
wrong_result_type = get_team()
5454

5555
end program get_team_test

flang/test/Semantics/modfile68.f90

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
! RUN: %python %S/test_modfile.py %s %flang_fc1
2+
module m1
3+
use iso_c_binding, only : c_ptr, c_null_ptr
4+
private
5+
public :: t1
6+
type :: t1
7+
type(c_ptr) :: c_ptr = c_null_ptr
8+
end type
9+
end
10+
11+
!Expect: m1.mod
12+
!module m1
13+
!use,intrinsic::__fortran_builtins,only:__builtin_c_ptr
14+
!use,intrinsic::iso_c_binding,only:c_ptr
15+
!use,intrinsic::iso_c_binding,only:c_null_ptr
16+
!private::__builtin_c_ptr
17+
!private::c_ptr
18+
!private::c_null_ptr
19+
!type::t1
20+
!type(c_ptr)::c_ptr=__builtin_c_ptr(__address=0_8)
21+
!end type
22+
!end
23+
24+
module m2
25+
use m1, only : t1
26+
private
27+
public :: t2
28+
type :: t2
29+
type(t1) :: x = t1()
30+
end type
31+
end
32+
33+
!Expect: m2.mod
34+
!module m2
35+
!use,intrinsic::__fortran_builtins,only:__builtin_c_ptr
36+
!use m1,only:t1
37+
!private::__builtin_c_ptr
38+
!private::t1
39+
!type::t2
40+
!type(t1)::x=t1(c_ptr=__builtin_c_ptr(__address=0_8))
41+
!end type
42+
!end

flang/test/Semantics/modproc01.f90

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,12 @@ program test
144144
!CHECK: a1, ALLOCATABLE size=40 offset=0: ObjectEntity type: TYPE(pdt2(k2=1_4,l2=3_4))
145145
!CHECK: k1: TypeParam type:INTEGER(4) Kind init:1_4
146146
!CHECK: l1: TypeParam type:INTEGER(4) Len init:3_4
147-
!CHECK: DerivedType scope: size=1 alignment=1 instantiation of pdt2(k2=1_4,l2=3_4)
148-
!CHECK: a2: ObjectEntity type: TYPE(pdt1(k1=1_4,l1=3_4)) shape: 1_8:1_8
147+
!CHECK: DerivedType scope: size=48 alignment=8 instantiation of pdt2(k2=1_4,l2=3_4) sourceRange=0 bytes
148+
!CHECK: a2 size=40 offset=8: ObjectEntity type: TYPE(pdt1(k1=1_4,l1=3_4)) shape: 1_8:1_8
149149
!CHECK: j2 size=1 offset=0: ObjectEntity type: INTEGER(1)
150150
!CHECK: k2: TypeParam type:INTEGER(4) Kind init:1_4
151151
!CHECK: l2: TypeParam type:INTEGER(4) Len init:3_4
152+
!CHECK: DerivedType scope: size=40 alignment=8 instantiation of pdt1(k1=1_4,l1=3_4) sourceRange=0 bytes
153+
!CHECK: a1, ALLOCATABLE size=40 offset=0: ObjectEntity type: TYPE(pdt2(k2=1_4,l2=3_4))
154+
!CHECK: k1: TypeParam type:INTEGER(4) Kind init:1_4
155+
!CHECK: l1: TypeParam type:INTEGER(4) Len init:3_4

0 commit comments

Comments
 (0)