Skip to content

Commit 539a6b5

Browse files
authored
[flang] Detect use-before-decl errors on type parameters (#99947)
Ensure that type parameters are declared as such before being referenced within the derived type definition. (Previously, such references would resolve to symbols in the enclosing scope.) This change causes the symbols for the type parameters to be created when the TYPE statement is processed in name resolution. They are TypeParamDetails symbols with no KIND/LEN attribute set, and they shadow any symbols of the same name in the enclosing scope. When the type parameter declarations are processed, the KIND/LEN attributes are set. Any earlier reference to a type parameter with no KIND/LEN attribute elicits an error. Some members of TypeParamDetails have been retyped &/or renamed.
1 parent 33c27f2 commit 539a6b5

File tree

10 files changed

+127
-92
lines changed

10 files changed

+127
-92
lines changed

flang/include/flang/Semantics/symbol.h

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -460,15 +460,19 @@ class ProcEntityDetails : public EntityDetails, public WithPassArg {
460460
// and specialized for each distinct set of type parameter values.
461461
class DerivedTypeDetails {
462462
public:
463-
const std::list<SourceName> &paramNames() const { return paramNames_; }
464-
const SymbolVector &paramDecls() const { return paramDecls_; }
463+
const SymbolVector &paramNameOrder() const { return paramNameOrder_; }
464+
const SymbolVector &paramDeclOrder() const { return paramDeclOrder_; }
465465
bool sequence() const { return sequence_; }
466466
bool isDECStructure() const { return isDECStructure_; }
467467
std::map<SourceName, SymbolRef> &finals() { return finals_; }
468468
const std::map<SourceName, SymbolRef> &finals() const { return finals_; }
469469
bool isForwardReferenced() const { return isForwardReferenced_; }
470-
void add_paramName(const SourceName &name) { paramNames_.push_back(name); }
471-
void add_paramDecl(const Symbol &symbol) { paramDecls_.push_back(symbol); }
470+
void add_paramNameOrder(const Symbol &symbol) {
471+
paramNameOrder_.push_back(symbol);
472+
}
473+
void add_paramDeclOrder(const Symbol &symbol) {
474+
paramDeclOrder_.push_back(symbol);
475+
}
472476
void add_component(const Symbol &);
473477
void set_sequence(bool x = true) { sequence_ = x; }
474478
void set_isDECStructure(bool x = true) { isDECStructure_ = x; }
@@ -491,12 +495,12 @@ class DerivedTypeDetails {
491495
const Symbol *GetFinalForRank(int) const;
492496

493497
private:
494-
// These are (1) the names of the derived type parameters in the order
498+
// These are (1) the symbols of the derived type parameters in the order
495499
// in which they appear on the type definition statement(s), and (2) the
496500
// symbols that correspond to those names in the order in which their
497501
// declarations appear in the derived type definition(s).
498-
std::list<SourceName> paramNames_;
499-
SymbolVector paramDecls_;
502+
SymbolVector paramNameOrder_;
503+
SymbolVector paramDeclOrder_;
500504
// These are the names of the derived type's components in component
501505
// order. A parent component, if any, appears first in this list.
502506
std::list<SourceName> componentNames_;
@@ -565,18 +569,19 @@ class MiscDetails {
565569

566570
class TypeParamDetails {
567571
public:
568-
explicit TypeParamDetails(common::TypeParamAttr attr) : attr_{attr} {}
572+
TypeParamDetails() = default;
569573
TypeParamDetails(const TypeParamDetails &) = default;
570-
common::TypeParamAttr attr() const { return attr_; }
574+
std::optional<common::TypeParamAttr> attr() const { return attr_; }
575+
TypeParamDetails &set_attr(common::TypeParamAttr);
571576
MaybeIntExpr &init() { return init_; }
572577
const MaybeIntExpr &init() const { return init_; }
573578
void set_init(MaybeIntExpr &&expr) { init_ = std::move(expr); }
574579
const DeclTypeSpec *type() const { return type_; }
575-
void set_type(const DeclTypeSpec &);
580+
TypeParamDetails &set_type(const DeclTypeSpec &);
576581
void ReplaceType(const DeclTypeSpec &);
577582

578583
private:
579-
common::TypeParamAttr attr_;
584+
std::optional<common::TypeParamAttr> attr_;
580585
MaybeIntExpr init_;
581586
const DeclTypeSpec *type_{nullptr};
582587
};

flang/include/flang/Semantics/tools.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ std::optional<parser::MessageFixedText> GetImageControlStmtCoarrayMsg(
260260
SymbolVector OrderParameterDeclarations(const Symbol &);
261261
// Returns the complete list of derived type parameter names in the
262262
// order defined by 7.5.3.2.
263-
std::list<SourceName> OrderParameterNames(const Symbol &);
263+
SymbolVector OrderParameterNames(const Symbol &);
264264

265265
// Return an existing or new derived type instance
266266
const DeclTypeSpec &FindOrInstantiateDerivedType(Scope &, DerivedTypeSpec &&,

flang/lib/Semantics/check-declarations.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2919,7 +2919,7 @@ parser::Messages CheckHelper::WhyNotInteroperableDerivedType(
29192919
if (derived->sequence()) { // C1801
29202920
msgs.Say(symbol.name(),
29212921
"An interoperable derived type cannot have the SEQUENCE attribute"_err_en_US);
2922-
} else if (!derived->paramDecls().empty()) { // C1802
2922+
} else if (!derived->paramNameOrder().empty()) { // C1802
29232923
msgs.Say(symbol.name(),
29242924
"An interoperable derived type cannot have a type parameter"_err_en_US);
29252925
} else if (const auto *parent{

flang/lib/Semantics/mod-file.cpp

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -410,15 +410,14 @@ bool ModFileWriter::PutComponents(const Symbol &typeSymbol) {
410410
llvm::raw_string_ostream typeBindings{buf};
411411
UnorderedSymbolSet emitted;
412412
SymbolVector symbols{scope.GetSymbols()};
413-
// Emit type parameters first
414-
for (const Symbol &symbol : symbols) {
415-
if (symbol.has<TypeParamDetails>()) {
416-
PutSymbol(typeBindings, symbol);
417-
emitted.emplace(symbol);
418-
}
419-
}
420-
// Emit components in component order.
413+
// Emit type parameter declarations first, in order
421414
const auto &details{typeSymbol.get<DerivedTypeDetails>()};
415+
for (const Symbol &symbol : details.paramDeclOrder()) {
416+
CHECK(symbol.has<TypeParamDetails>());
417+
PutSymbol(typeBindings, symbol);
418+
emitted.emplace(symbol);
419+
}
420+
// Emit actual components in component order.
422421
for (SourceName name : details.componentNames()) {
423422
auto iter{scope.find(name)};
424423
if (iter != scope.end()) {
@@ -549,10 +548,10 @@ void ModFileWriter::PutDerivedType(
549548
decls_ << ",extends(" << extends->name() << ')';
550549
}
551550
decls_ << "::" << typeSymbol.name();
552-
if (!details.paramNames().empty()) {
551+
if (!details.paramNameOrder().empty()) {
553552
char sep{'('};
554-
for (const auto &name : details.paramNames()) {
555-
decls_ << sep << name;
553+
for (const SymbolRef &ref : details.paramNameOrder()) {
554+
decls_ << sep << ref->name();
556555
sep = ',';
557556
}
558557
decls_ << ')';
@@ -1046,7 +1045,7 @@ void ModFileWriter::PutTypeParam(llvm::raw_ostream &os, const Symbol &symbol) {
10461045
os, symbol,
10471046
[&]() {
10481047
PutType(os, DEREF(symbol.GetType()));
1049-
PutLower(os << ',', common::EnumToString(details.attr()));
1048+
PutLower(os << ',', common::EnumToString(details.attr().value()));
10501049
},
10511050
symbol.attrs());
10521051
PutInit(os, details.init());

flang/lib/Semantics/resolve-names.cpp

Lines changed: 47 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -5456,34 +5456,14 @@ bool DeclarationVisitor::Pre(const parser::DerivedTypeDef &x) {
54565456
CHECK(scope.symbol());
54575457
CHECK(scope.symbol()->scope() == &scope);
54585458
auto &details{scope.symbol()->get<DerivedTypeDetails>()};
5459-
std::set<SourceName> paramNames;
54605459
for (auto &paramName : std::get<std::list<parser::Name>>(stmt.statement.t)) {
5461-
details.add_paramName(paramName.source);
5462-
auto *symbol{FindInScope(scope, paramName)};
5463-
if (!symbol) {
5464-
Say(paramName,
5465-
"No definition found for type parameter '%s'"_err_en_US); // C742
5466-
// No symbol for a type param. Create one and mark it as containing an
5467-
// error to improve subsequent semantic processing
5468-
BeginAttrs();
5469-
Symbol *typeParam{MakeTypeSymbol(
5470-
paramName, TypeParamDetails{common::TypeParamAttr::Len})};
5471-
context().SetError(*typeParam);
5472-
EndAttrs();
5473-
} else if (!symbol->has<TypeParamDetails>()) {
5474-
Say2(paramName, "'%s' is not defined as a type parameter"_err_en_US,
5475-
*symbol, "Definition of '%s'"_en_US); // C741
5476-
}
5477-
if (!paramNames.insert(paramName.source).second) {
5478-
Say(paramName,
5479-
"Duplicate type parameter name: '%s'"_err_en_US); // C731
5480-
}
5481-
}
5482-
for (const auto &[name, symbol] : currScope()) {
5483-
if (symbol->has<TypeParamDetails>() && !paramNames.count(name)) {
5484-
SayDerivedType(name,
5485-
"'%s' is not a type parameter of this derived type"_err_en_US,
5486-
currScope()); // C741
5460+
if (auto *symbol{FindInScope(scope, paramName)}) {
5461+
if (auto *details{symbol->detailsIf<TypeParamDetails>()}) {
5462+
if (!details->attr()) {
5463+
Say(paramName,
5464+
"No definition found for type parameter '%s'"_err_en_US); // C742
5465+
}
5466+
}
54875467
}
54885468
}
54895469
Walk(std::get<std::list<parser::Statement<parser::PrivateOrSequence>>>(x.t));
@@ -5499,7 +5479,7 @@ bool DeclarationVisitor::Pre(const parser::DerivedTypeDef &x) {
54995479
"A sequence type should have at least one component"_warn_en_US);
55005480
}
55015481
}
5502-
if (!details.paramNames().empty()) { // C740
5482+
if (!details.paramDeclOrder().empty()) { // C740
55035483
Say(stmt.source,
55045484
"A sequence type may not have type parameters"_err_en_US);
55055485
}
@@ -5559,24 +5539,50 @@ void DeclarationVisitor::Post(const parser::DerivedTypeStmt &x) {
55595539
details.add_component(comp);
55605540
}
55615541
}
5542+
// Create symbols now for type parameters so that they shadow names
5543+
// from the enclosing specification part.
5544+
if (auto *details{symbol.detailsIf<DerivedTypeDetails>()}) {
5545+
for (const auto &name : std::get<std::list<parser::Name>>(x.t)) {
5546+
if (Symbol * symbol{MakeTypeSymbol(name, TypeParamDetails{})}) {
5547+
details->add_paramNameOrder(*symbol);
5548+
}
5549+
}
5550+
}
55625551
EndAttrs();
55635552
}
55645553

55655554
void DeclarationVisitor::Post(const parser::TypeParamDefStmt &x) {
55665555
auto *type{GetDeclTypeSpec()};
5556+
DerivedTypeDetails *derivedDetails{nullptr};
5557+
if (Symbol * dtSym{currScope().symbol()}) {
5558+
derivedDetails = dtSym->detailsIf<DerivedTypeDetails>();
5559+
}
55675560
auto attr{std::get<common::TypeParamAttr>(x.t)};
55685561
for (auto &decl : std::get<std::list<parser::TypeParamDecl>>(x.t)) {
55695562
auto &name{std::get<parser::Name>(decl.t)};
5570-
if (Symbol * symbol{MakeTypeSymbol(name, TypeParamDetails{attr})}) {
5571-
SetType(name, *type);
5572-
if (auto &init{
5573-
std::get<std::optional<parser::ScalarIntConstantExpr>>(decl.t)}) {
5574-
if (auto maybeExpr{AnalyzeExpr(context(), *init)}) {
5575-
if (auto *intExpr{std::get_if<SomeIntExpr>(&maybeExpr->u)}) {
5576-
symbol->get<TypeParamDetails>().set_init(std::move(*intExpr));
5563+
if (Symbol * symbol{FindInScope(currScope(), name)}) {
5564+
if (auto *paramDetails{symbol->detailsIf<TypeParamDetails>()}) {
5565+
if (!paramDetails->attr()) {
5566+
paramDetails->set_attr(attr);
5567+
SetType(name, *type);
5568+
if (auto &init{std::get<std::optional<parser::ScalarIntConstantExpr>>(
5569+
decl.t)}) {
5570+
if (auto maybeExpr{AnalyzeExpr(context(), *init)}) {
5571+
if (auto *intExpr{std::get_if<SomeIntExpr>(&maybeExpr->u)}) {
5572+
paramDetails->set_init(std::move(*intExpr));
5573+
}
5574+
}
5575+
}
5576+
if (derivedDetails) {
5577+
derivedDetails->add_paramDeclOrder(*symbol);
55775578
}
5579+
} else {
5580+
Say(name,
5581+
"Type parameter '%s' was already declared in this derived type"_err_en_US);
55785582
}
55795583
}
5584+
} else {
5585+
Say(name, "'%s' is not a parameter of this derived type"_err_en_US);
55805586
}
55815587
}
55825588
EndDecl();
@@ -6779,9 +6785,6 @@ Symbol *DeclarationVisitor::MakeTypeSymbol(
67796785
}
67806786
Symbol &result{MakeSymbol(name, attrs, std::move(details))};
67816787
SetCUDADataAttr(name, result, cudaDataAttr());
6782-
if (result.has<TypeParamDetails>()) {
6783-
derivedType.symbol()->get<DerivedTypeDetails>().add_paramDecl(result);
6784-
}
67856788
return &result;
67866789
}
67876790
}
@@ -7830,6 +7833,12 @@ const parser::Name *DeclarationVisitor::ResolveName(const parser::Name &name) {
78307833
CheckEntryDummyUse(name.source, symbol);
78317834
ConvertToObjectEntity(*symbol);
78327835
ApplyImplicitRules(*symbol);
7836+
} else if (const auto *tpd{symbol->detailsIf<TypeParamDetails>()};
7837+
tpd && !tpd->attr()) {
7838+
Say(name,
7839+
"Type parameter '%s' was referenced before being declared"_err_en_US,
7840+
name.source);
7841+
context().SetError(*symbol);
78337842
}
78347843
if (checkIndexUseInOwnBounds_ &&
78357844
*checkIndexUseInOwnBounds_ == name.source && !InModuleFile()) {

flang/lib/Semantics/runtime-type-info.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ static int FindLenParameterIndex(
4242
if (&*ref == &symbol) {
4343
return lenIndex;
4444
}
45-
if (ref->get<TypeParamDetails>().attr() == common::TypeParamAttr::Len) {
45+
if (auto attr{ref->get<TypeParamDetails>().attr()};
46+
attr && *attr == common::TypeParamAttr::Len) {
4647
++lenIndex;
4748
}
4849
}
@@ -371,7 +372,7 @@ static std::optional<std::string> GetSuffixIfTypeKindParameters(
371372
std::optional<std::string> suffix;
372373
for (SymbolRef ref : *parameters) {
373374
const auto &tpd{ref->get<TypeParamDetails>()};
374-
if (tpd.attr() == common::TypeParamAttr::Kind) {
375+
if (tpd.attr() && *tpd.attr() == common::TypeParamAttr::Kind) {
375376
if (const auto *pv{derivedTypeSpec.FindParameter(ref->name())}) {
376377
if (pv->GetExplicit()) {
377378
if (auto instantiatedValue{evaluate::ToInt64(*pv->GetExplicit())}) {
@@ -497,7 +498,7 @@ const Symbol *RuntimeTableBuilder::DescribeType(Scope &dtScope) {
497498
for (SymbolRef ref : *parameters) {
498499
if (const auto *inst{dtScope.FindComponent(ref->name())}) {
499500
const auto &tpd{inst->get<TypeParamDetails>()};
500-
if (tpd.attr() == common::TypeParamAttr::Kind) {
501+
if (tpd.attr() && *tpd.attr() == common::TypeParamAttr::Kind) {
501502
auto value{evaluate::ToInt64(tpd.init()).value_or(0)};
502503
if (derivedTypeSpec) {
503504
if (const auto *pv{derivedTypeSpec->FindParameter(inst->name())}) {
@@ -799,7 +800,7 @@ evaluate::StructureConstructor RuntimeTableBuilder::DescribeComponent(
799800
specParams{GetTypeParameters(spec.typeSymbol())}) {
800801
for (SymbolRef ref : *specParams) {
801802
const auto &tpd{ref->get<TypeParamDetails>()};
802-
if (tpd.attr() == common::TypeParamAttr::Len) {
803+
if (tpd.attr() && *tpd.attr() == common::TypeParamAttr::Len) {
803804
if (const ParamValue *
804805
paramValue{spec.FindParameter(ref->name())}) {
805806
lenParams.emplace_back(GetValue(*paramValue, parameters));

flang/lib/Semantics/symbol.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,11 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Details &details) {
588588
},
589589
[&](const TypeParamDetails &x) {
590590
DumpOptional(os, "type", x.type());
591-
os << ' ' << common::EnumToString(x.attr());
591+
if (auto attr{x.attr()}) {
592+
os << ' ' << common::EnumToString(*attr);
593+
} else {
594+
os << " (no attr)";
595+
}
592596
DumpExpr(os, "init", x.init());
593597
},
594598
[&](const MiscDetails &x) {
@@ -739,9 +743,16 @@ const Symbol *DerivedTypeDetails::GetFinalForRank(int rank) const {
739743
return nullptr;
740744
}
741745

742-
void TypeParamDetails::set_type(const DeclTypeSpec &type) {
746+
TypeParamDetails &TypeParamDetails::set_attr(common::TypeParamAttr attr) {
747+
CHECK(!attr_);
748+
attr_ = attr;
749+
return *this;
750+
}
751+
752+
TypeParamDetails &TypeParamDetails::set_type(const DeclTypeSpec &type) {
743753
CHECK(!type_);
744754
type_ = &type;
755+
return *this;
745756
}
746757

747758
bool GenericKind::IsIntrinsicOperator() const {

flang/lib/Semantics/tools.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1135,12 +1135,12 @@ std::optional<parser::MessageFormattedText> CheckAccessibleSymbol(
11351135
return std::nullopt;
11361136
}
11371137

1138-
std::list<SourceName> OrderParameterNames(const Symbol &typeSymbol) {
1139-
std::list<SourceName> result;
1138+
SymbolVector OrderParameterNames(const Symbol &typeSymbol) {
1139+
SymbolVector result;
11401140
if (const DerivedTypeSpec * spec{typeSymbol.GetParentTypeSpec()}) {
11411141
result = OrderParameterNames(spec->typeSymbol());
11421142
}
1143-
const auto &paramNames{typeSymbol.get<DerivedTypeDetails>().paramNames()};
1143+
const auto &paramNames{typeSymbol.get<DerivedTypeDetails>().paramNameOrder()};
11441144
result.insert(result.end(), paramNames.begin(), paramNames.end());
11451145
return result;
11461146
}
@@ -1150,7 +1150,7 @@ SymbolVector OrderParameterDeclarations(const Symbol &typeSymbol) {
11501150
if (const DerivedTypeSpec * spec{typeSymbol.GetParentTypeSpec()}) {
11511151
result = OrderParameterDeclarations(spec->typeSymbol());
11521152
}
1153-
const auto &paramDecls{typeSymbol.get<DerivedTypeDetails>().paramDecls()};
1153+
const auto &paramDecls{typeSymbol.get<DerivedTypeDetails>().paramDeclOrder()};
11541154
result.insert(result.end(), paramDecls.begin(), paramDecls.end());
11551155
return result;
11561156
}

0 commit comments

Comments
 (0)