Skip to content

Commit 99a54b8

Browse files
authored
[flang] Lower PRIVATE component names safely (llvm#66076)
It is possible for a derived type extending a type with private components to define components with the same name as the private components. This was not properly handled by lowering where several fir.record type component names could end-up being the same, leading to bad generated code (only the first component was accessed via fir.field_index, leading to bad generated code). This patch handles the situation by adding the derived type mangled name to private component.
1 parent 4491f0b commit 99a54b8

File tree

14 files changed

+153
-77
lines changed

14 files changed

+153
-77
lines changed

flang/include/flang/Lower/AbstractConverter.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,11 @@ class AbstractConverter {
250250
mangleName(const Fortran::semantics::DerivedTypeSpec &) = 0;
251251
/// Unique a compiler generated name (add a containing scope specific prefix)
252252
virtual std::string mangleName(std::string &) = 0;
253+
/// Return the field name for a derived type component inside a fir.record
254+
/// type.
255+
virtual std::string
256+
getRecordTypeFieldName(const Fortran::semantics::Symbol &component) = 0;
257+
253258
/// Get the KindMap.
254259
virtual const fir::KindMapping &getKindMap() = 0;
255260

flang/include/flang/Lower/Mangler.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,13 @@ inline std::string mangleArrayLiteral(
9696
/// Return the compiler-generated name of a static namelist variable descriptor.
9797
std::string globalNamelistDescriptorName(const Fortran::semantics::Symbol &sym);
9898

99+
/// Return the field name for a derived type component inside a fir.record type.
100+
/// It is the component name if the component is not private. Otherwise it is
101+
/// mangled with the component parent type to avoid any name clashes in type
102+
/// extensions.
103+
std::string getRecordTypeFieldName(const Fortran::semantics::Symbol &component,
104+
ScopeBlockIdMap &);
105+
99106
} // namespace lower::mangle
100107
} // namespace Fortran
101108

flang/lib/Lower/Bridge.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -856,6 +856,11 @@ class FirConverter : public Fortran::lower::AbstractConverter {
856856
return Fortran::lower::mangle::mangleName(name, getCurrentScope(),
857857
scopeBlockIdMap);
858858
}
859+
std::string getRecordTypeFieldName(
860+
const Fortran::semantics::Symbol &component) override final {
861+
return Fortran::lower::mangle::getRecordTypeFieldName(component,
862+
scopeBlockIdMap);
863+
}
859864
const fir::KindMapping &getKindMap() override final {
860865
return bridge.getKindMap();
861866
}

flang/lib/Lower/ConvertConstant.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,8 +362,9 @@ static mlir::Value genInlinedStructureCtorLitImpl(
362362
if (sym->test(Fortran::semantics::Symbol::Flag::ParentComp))
363363
TODO(loc, "parent component in structure constructor");
364364

365-
llvm::StringRef name = toStringRef(sym->name());
365+
std::string name = converter.getRecordTypeFieldName(sym);
366366
mlir::Type componentTy = recTy.getType(name);
367+
assert(componentTy && "failed to retrieve component");
367368
// FIXME: type parameters must come from the derived-type-spec
368369
auto field = builder.create<fir::FieldIndexOp>(
369370
loc, fieldTy, name, type,

flang/lib/Lower/ConvertExpr.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -937,7 +937,7 @@ class ScalarExprLowering {
937937
if (isDerivedTypeWithLenParameters(sym))
938938
TODO(loc, "component with length parameters in structure constructor");
939939

940-
llvm::StringRef name = toStringRef(sym.name());
940+
std::string name = converter.getRecordTypeFieldName(sym);
941941
// FIXME: type parameters must come from the derived-type-spec
942942
mlir::Value field = builder.create<fir::FieldIndexOp>(
943943
loc, fieldTy, name, ty,
@@ -1476,7 +1476,7 @@ class ScalarExprLowering {
14761476
for (const Fortran::evaluate::Component *field : list) {
14771477
auto recTy = ty.cast<fir::RecordType>();
14781478
const Fortran::semantics::Symbol &sym = getLastSym(*field);
1479-
llvm::StringRef name = toStringRef(sym.name());
1479+
std::string name = converter.getRecordTypeFieldName(sym);
14801480
coorArgs.push_back(builder.create<fir::FieldIndexOp>(
14811481
loc, fldTy, name, recTy, fir::getTypeParams(obj)));
14821482
ty = recTy.getType(name);
@@ -6745,7 +6745,8 @@ class ArrayExprLowering {
67456745
},
67466746
[&](const Fortran::evaluate::Component *x) {
67476747
auto fieldTy = fir::FieldType::get(builder.getContext());
6748-
llvm::StringRef name = toStringRef(getLastSym(*x).name());
6748+
std::string name =
6749+
converter.getRecordTypeFieldName(getLastSym(*x));
67496750
if (auto recTy = ty.dyn_cast<fir::RecordType>()) {
67506751
ty = recTy.getType(name);
67516752
auto fld = builder.create<fir::FieldIndexOp>(

flang/lib/Lower/ConvertExprToHLFIR.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -742,7 +742,7 @@ class HlfirDesignatorBuilder {
742742
assert(
743743
!componentSym.test(Fortran::semantics::Symbol::Flag::ParentComp) &&
744744
"parent components are skipped and must not reach visitComponentImpl");
745-
partInfo.componentName = componentSym.name().ToString();
745+
partInfo.componentName = converter.getRecordTypeFieldName(componentSym);
746746
auto recordType =
747747
hlfir::getFortranElementType(baseType).cast<fir::RecordType>();
748748
if (recordType.isDependentType())
@@ -1721,7 +1721,7 @@ class HlfirBuilder {
17211721
for (const auto &value : ctor.values()) {
17221722
const Fortran::semantics::Symbol &sym = *value.first;
17231723
const Fortran::lower::SomeExpr &expr = value.second.value();
1724-
llvm::StringRef name = toStringRef(sym.name());
1724+
std::string name = converter.getRecordTypeFieldName(sym);
17251725
if (sym.test(Fortran::semantics::Symbol::Flag::ParentComp)) {
17261726
const Fortran::semantics::DeclTypeSpec *declTypeSpec = sym.GetType();
17271727
assert(declTypeSpec && declTypeSpec->AsDerived() &&

flang/lib/Lower/ConvertType.cpp

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -382,23 +382,25 @@ struct TypeBuilderImpl {
382382

383383
// Gather the record type fields.
384384
// (1) The data components.
385-
for (const auto &field :
385+
for (const auto &component :
386386
Fortran::semantics::OrderedComponentIterator(tySpec)) {
387387
// Lowering is assuming non deferred component lower bounds are always 1.
388388
// Catch any situations where this is not true for now.
389389
if (!converter.getLoweringOptions().getLowerToHighLevelFIR() &&
390-
componentHasNonDefaultLowerBounds(field))
391-
TODO(converter.genLocation(field.name()),
390+
componentHasNonDefaultLowerBounds(component))
391+
TODO(converter.genLocation(component.name()),
392392
"derived type components with non default lower bounds");
393-
if (IsProcedure(field))
394-
TODO(converter.genLocation(field.name()), "procedure components");
395-
mlir::Type ty = genSymbolType(field);
393+
if (IsProcedure(component))
394+
TODO(converter.genLocation(component.name()), "procedure components");
395+
mlir::Type ty = genSymbolType(component);
396396
// Do not add the parent component (component of the parents are
397397
// added and should be sufficient, the parent component would
398-
// duplicate the fields).
399-
if (field.test(Fortran::semantics::Symbol::Flag::ParentComp))
398+
// duplicate the fields). Note that genSymbolType must be called above on
399+
// it so that the dispatch table for the parent type still gets emitted
400+
// as needed.
401+
if (component.test(Fortran::semantics::Symbol::Flag::ParentComp))
400402
continue;
401-
cs.emplace_back(field.name().ToString(), ty);
403+
cs.emplace_back(converter.getRecordTypeFieldName(component), ty);
402404
}
403405

404406
// (2) The LEN type parameters.

flang/lib/Lower/ConvertVariable.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ static mlir::Value genDefaultInitializerValue(
324324
if (component.test(Fortran::semantics::Symbol::Flag::ParentComp))
325325
continue;
326326
mlir::Value componentValue;
327-
llvm::StringRef name = toStringRef(component.name());
327+
std::string name = converter.getRecordTypeFieldName(component);
328328
mlir::Type componentTy = recTy.getType(name);
329329
assert(componentTy && "component not found in type");
330330
if (const auto *object{

flang/lib/Lower/Mangler.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,25 @@ std::string Fortran::lower::mangle::mangleName(
230230
return fir::NameUniquer::doType(modules, procs, blockId, symbolName, kinds);
231231
}
232232

233+
std::string Fortran::lower::mangle::getRecordTypeFieldName(
234+
const Fortran::semantics::Symbol &component,
235+
ScopeBlockIdMap &scopeBlockIdMap) {
236+
if (!component.attrs().test(Fortran::semantics::Attr::PRIVATE))
237+
return component.name().ToString();
238+
const Fortran::semantics::DerivedTypeSpec *componentParentType =
239+
component.owner().derivedTypeSpec();
240+
assert(componentParentType &&
241+
"failed to retrieve private component parent type");
242+
// Do not mangle Iso C C_PTR and C_FUNPTR components. This type cannot be
243+
// extended as per Fortran 2018 7.5.7.1, mangling them makes the IR unreadable
244+
// when using ISO C modules, and lowering needs to know the component way
245+
// without access to semantics::Symbol.
246+
if (Fortran::semantics::IsIsoCType(componentParentType))
247+
return component.name().ToString();
248+
return mangleName(*componentParentType, scopeBlockIdMap) + "." +
249+
component.name().ToString();
250+
}
251+
233252
std::string Fortran::lower::mangle::demangleName(llvm::StringRef name) {
234253
auto result = fir::NameUniquer::deconstruct(name);
235254
return result.second.name;
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
! Test that private component names are mangled inside fir.record
2+
! in a way that allow components with the same name to be added in
3+
! type extensions.
4+
! RUN: bbc -emit-hlfir -o - %s | FileCheck %s
5+
6+
module name_clash
7+
type:: t
8+
integer, private :: i
9+
end type
10+
type(t), parameter :: cst = t(42)
11+
end module
12+
13+
!CHECK-LABEL: func.func @_QPuser_clash(
14+
!CHECK-SAME: !fir.ref<!fir.type<_QFuser_clashTt2{_QMname_clashTt.i:i32,i:i32}>>
15+
!CHECK-SAME: !fir.ref<!fir.type<_QMname_clashTt{_QMname_clashTt.i:i32}>>
16+
subroutine user_clash(a, at)
17+
use name_clash
18+
type,extends(t) :: t2
19+
integer :: i = 2
20+
end type
21+
type(t2) :: a, b
22+
type(t) :: at
23+
print *, a%i
24+
print *, t2(t=at)
25+
a = b
26+
end subroutine
27+
28+
! CHECK-LABEL: func.func @_QPclash_with_intrinsic_module(
29+
! CHECK-SAME: !fir.ref<!fir.type<_QFclash_with_intrinsic_moduleTmy_class{_QMieee_arithmeticTieee_class_type.which:i8,which:i8}>>
30+
subroutine clash_with_intrinsic_module(a)
31+
use ieee_arithmetic
32+
type, extends(ieee_class_type) :: my_class
33+
integer(1) :: which
34+
end type
35+
type(my_class) :: a
36+
end subroutine

0 commit comments

Comments
 (0)