Skip to content

Commit 6e0e075

Browse files
klauslerjeanPerier
authored andcommitted
[flang] Revamp C1502 checking of END INTERFACE [generic-spec]
Validation of the optional generic-spec on an END INTERFACE statement was missing many possible error cases; reimplement it. Differential Revision: https://reviews.llvm.org/D109910
1 parent b0f31df commit 6e0e075

File tree

4 files changed

+101
-96
lines changed

4 files changed

+101
-96
lines changed

flang/lib/Semantics/resolve-labels.cpp

Lines changed: 80 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -346,17 +346,11 @@ class ParseTreeAnalyzer {
346346
const auto &firstStmt{std::get<parser::Statement<FIRST>>(a.t)};
347347
if (const parser::CharBlock * firstName{GetStmtName(firstStmt)}) {
348348
if (*firstName != *name) {
349-
context_
350-
.Say(*name,
351-
parser::MessageFormattedText{
352-
"%s name mismatch"_err_en_US, constructTag})
349+
context_.Say(*name, "%s name mismatch"_err_en_US, constructTag)
353350
.Attach(*firstName, "should be"_en_US);
354351
}
355352
} else {
356-
context_
357-
.Say(*name,
358-
parser::MessageFormattedText{
359-
"%s name not allowed"_err_en_US, constructTag})
353+
context_.Say(*name, "%s name not allowed"_err_en_US, constructTag)
360354
.Attach(firstStmt.source, "in unnamed %s"_en_US, constructTag);
361355
}
362356
}
@@ -383,32 +377,51 @@ class ParseTreeAnalyzer {
383377

384378
// C1502
385379
void Post(const parser::InterfaceBlock &interfaceBlock) {
386-
auto &interfaceStmt{
387-
std::get<parser::Statement<parser::InterfaceStmt>>(interfaceBlock.t)};
388-
if (const auto *optionalGenericSpecPointer{
389-
std::get_if<std::optional<parser::GenericSpec>>(
390-
&interfaceStmt.statement.u)}) {
391-
if (*optionalGenericSpecPointer) {
392-
if (const auto *namePointer{
393-
std::get_if<parser::Name>(&(*optionalGenericSpecPointer)->u)}) {
394-
auto &optionalGenericSpec{
395-
std::get<parser::Statement<parser::EndInterfaceStmt>>(
396-
interfaceBlock.t)
397-
.statement.v};
398-
if (optionalGenericSpec) {
399-
if (const auto *otherPointer{
400-
std::get_if<parser::Name>(&optionalGenericSpec->u)}) {
401-
if (namePointer->source != otherPointer->source) {
402-
context_
403-
.Say(currentPosition_,
404-
parser::MessageFormattedText{
405-
"INTERFACE generic-name (%s) mismatch"_err_en_US,
406-
namePointer->source})
407-
.Attach(interfaceStmt.source, "mismatched INTERFACE"_en_US);
408-
}
409-
}
380+
if (const auto &endGenericSpec{
381+
std::get<parser::Statement<parser::EndInterfaceStmt>>(
382+
interfaceBlock.t)
383+
.statement.v}) {
384+
const auto &interfaceStmt{
385+
std::get<parser::Statement<parser::InterfaceStmt>>(interfaceBlock.t)};
386+
if (std::holds_alternative<parser::Abstract>(interfaceStmt.statement.u)) {
387+
context_
388+
.Say(endGenericSpec->source,
389+
"END INTERFACE generic name (%s) may not appear for ABSTRACT INTERFACE"_err_en_US,
390+
endGenericSpec->source)
391+
.Attach(
392+
interfaceStmt.source, "corresponding ABSTRACT INTERFACE"_en_US);
393+
} else if (const auto &genericSpec{
394+
std::get<std::optional<parser::GenericSpec>>(
395+
interfaceStmt.statement.u)}) {
396+
bool ok{genericSpec->source == endGenericSpec->source};
397+
if (!ok) {
398+
// Accept variant spellings of .LT. &c.
399+
const auto *endOp{
400+
std::get_if<parser::DefinedOperator>(&endGenericSpec->u)};
401+
const auto *op{std::get_if<parser::DefinedOperator>(&genericSpec->u)};
402+
if (endOp && op) {
403+
const auto *endIntrin{
404+
std::get_if<parser::DefinedOperator::IntrinsicOperator>(
405+
&endOp->u)};
406+
const auto *intrin{
407+
std::get_if<parser::DefinedOperator::IntrinsicOperator>(
408+
&op->u)};
409+
ok = endIntrin && intrin && *endIntrin == *intrin;
410410
}
411411
}
412+
if (!ok) {
413+
context_
414+
.Say(endGenericSpec->source,
415+
"END INTERFACE generic name (%s) does not match generic INTERFACE (%s)"_err_en_US,
416+
endGenericSpec->source, genericSpec->source)
417+
.Attach(genericSpec->source, "corresponding INTERFACE"_en_US);
418+
}
419+
} else {
420+
context_
421+
.Say(endGenericSpec->source,
422+
"END INTERFACE generic name (%s) may not appear for non-generic INTERFACE"_err_en_US,
423+
endGenericSpec->source)
424+
.Attach(interfaceStmt.source, "corresponding INTERFACE"_en_US);
412425
}
413426
}
414427
}
@@ -441,8 +454,7 @@ class ParseTreeAnalyzer {
441454
}
442455
} else {
443456
context_.Say(*endName,
444-
parser::MessageFormattedText{
445-
"END PROGRAM has name without PROGRAM statement"_err_en_US});
457+
"END PROGRAM has name without PROGRAM statement"_err_en_US);
446458
}
447459
}
448460
}
@@ -640,24 +652,20 @@ class ParseTreeAnalyzer {
640652
if (endName) {
641653
if (*constructName != *endName) {
642654
context_
643-
.Say(*endName,
644-
parser::MessageFormattedText{
645-
"%s construct name mismatch"_err_en_US, constructTag})
655+
.Say(*endName, "%s construct name mismatch"_err_en_US,
656+
constructTag)
646657
.Attach(*constructName, "should be"_en_US);
647658
}
648659
} else {
649660
context_
650661
.Say(endStmt.source,
651-
parser::MessageFormattedText{
652-
"%s construct name required but missing"_err_en_US,
653-
constructTag})
662+
"%s construct name required but missing"_err_en_US,
663+
constructTag)
654664
.Attach(*constructName, "should be"_en_US);
655665
}
656666
} else if (endName) {
657667
context_
658-
.Say(*endName,
659-
parser::MessageFormattedText{
660-
"%s construct name unexpected"_err_en_US, constructTag})
668+
.Say(*endName, "%s construct name unexpected"_err_en_US, constructTag)
661669
.Attach(
662670
constructStmt.source, "unnamed %s statement"_en_US, constructTag);
663671
}
@@ -737,18 +745,16 @@ class ParseTreeAnalyzer {
737745
const auto iter{std::find(constructNames_.crbegin(),
738746
constructNames_.crend(), constructName.ToString())};
739747
if (iter == constructNames_.crend()) {
740-
context_.Say(constructName,
741-
parser::MessageFormattedText{
742-
"%s construct-name is not in scope"_err_en_US, stmtString});
748+
context_.Say(constructName, "%s construct-name is not in scope"_err_en_US,
749+
stmtString);
743750
}
744751
}
745752

746753
// 6.2.5, paragraph 2
747754
void CheckLabelInRange(parser::Label label) {
748755
if (label < 1 || label > 99999) {
749-
context_.Say(currentPosition_,
750-
parser::MessageFormattedText{
751-
"Label '%u' is out of range"_err_en_US, SayLabel(label)});
756+
context_.Say(currentPosition_, "Label '%u' is out of range"_err_en_US,
757+
SayLabel(label));
752758
}
753759
}
754760

@@ -761,9 +767,8 @@ class ParseTreeAnalyzer {
761767
LabeledStatementInfoTuplePOD{scope, currentPosition_,
762768
labeledStmtClassificationSet, isExecutableConstructEndStmt})};
763769
if (!pair.second) {
764-
context_.Say(currentPosition_,
765-
parser::MessageFormattedText{
766-
"Label '%u' is not distinct"_err_en_US, SayLabel(label)});
770+
context_.Say(currentPosition_, "Label '%u' is not distinct"_err_en_US,
771+
SayLabel(label));
767772
}
768773
}
769774

@@ -799,7 +804,7 @@ class ParseTreeAnalyzer {
799804

800805
std::vector<UnitAnalysis> programUnits_;
801806
SemanticsContext &context_;
802-
parser::CharBlock currentPosition_{nullptr};
807+
parser::CharBlock currentPosition_;
803808
ProxyForScope currentScope_;
804809
std::vector<std::string> constructNames_;
805810
};
@@ -904,15 +909,13 @@ void CheckLabelDoConstraints(const SourceStmtList &dos,
904909
auto doTarget{GetLabel(labels, label)};
905910
if (!HasScope(doTarget.proxyForScope)) {
906911
// C1133
907-
context.Say(position,
908-
parser::MessageFormattedText{
909-
"Label '%u' cannot be found"_err_en_US, SayLabel(label)});
912+
context.Say(
913+
position, "Label '%u' cannot be found"_err_en_US, SayLabel(label));
910914
} else if (doTarget.parserCharBlock.begin() < position.begin()) {
911915
// R1119
912916
context.Say(position,
913-
parser::MessageFormattedText{
914-
"Label '%u' doesn't lexically follow DO stmt"_err_en_US,
915-
SayLabel(label)});
917+
"Label '%u' doesn't lexically follow DO stmt"_err_en_US,
918+
SayLabel(label));
916919

917920
} else if ((InInclusiveScope(scopes, scope, doTarget.proxyForScope) &&
918921
doTarget.labeledStmtClassificationSet.test(
@@ -924,20 +927,17 @@ void CheckLabelDoConstraints(const SourceStmtList &dos,
924927
common::LanguageFeature::OldLabelDoEndStatements)) {
925928
context
926929
.Say(position,
927-
parser::MessageFormattedText{
928-
"A DO loop should terminate with an END DO or CONTINUE"_en_US})
930+
"A DO loop should terminate with an END DO or CONTINUE"_en_US)
929931
.Attach(doTarget.parserCharBlock,
930932
"DO loop currently ends at statement:"_en_US);
931933
}
932934
} else if (!InInclusiveScope(scopes, scope, doTarget.proxyForScope)) {
933-
context.Say(position,
934-
parser::MessageFormattedText{
935-
"Label '%u' is not in DO loop scope"_err_en_US, SayLabel(label)});
935+
context.Say(position, "Label '%u' is not in DO loop scope"_err_en_US,
936+
SayLabel(label));
936937
} else if (!doTarget.labeledStmtClassificationSet.test(
937938
TargetStatementEnum::Do)) {
938939
context.Say(doTarget.parserCharBlock,
939-
parser::MessageFormattedText{
940-
"A DO loop should terminate with an END DO or CONTINUE"_err_en_US});
940+
"A DO loop should terminate with an END DO or CONTINUE"_err_en_US);
941941
} else {
942942
loopBodies.emplace_back(SkipLabel(position), doTarget.parserCharBlock);
943943
}
@@ -957,19 +957,17 @@ void CheckScopeConstraints(const SourceStmtList &stmts,
957957
const auto &position{stmt.parserCharBlock};
958958
auto target{GetLabel(labels, label)};
959959
if (!HasScope(target.proxyForScope)) {
960-
context.Say(position,
961-
parser::MessageFormattedText{
962-
"Label '%u' was not found"_err_en_US, SayLabel(label)});
960+
context.Say(
961+
position, "Label '%u' was not found"_err_en_US, SayLabel(label));
963962
} else if (!InInclusiveScope(scopes, scope, target.proxyForScope)) {
964963
// Clause 11.1.2.1 prohibits transfer of control to the interior of a
965964
// block from outside the block, but this does not apply to formats.
966965
if (target.labeledStmtClassificationSet.test(
967966
TargetStatementEnum::Format)) {
968967
continue;
969968
}
970-
context.Say(position,
971-
parser::MessageFormattedText{
972-
"Label '%u' is not in scope"_en_US, SayLabel(label)});
969+
context.Say(
970+
position, "Label '%u' is not in scope"_en_US, SayLabel(label));
973971
}
974972
}
975973
}
@@ -986,21 +984,16 @@ void CheckBranchTargetConstraints(const SourceStmtList &stmts,
986984
TargetStatementEnum::CompatibleBranch)) { // error
987985
context
988986
.Say(branchTarget.parserCharBlock,
989-
parser::MessageFormattedText{
990-
"Label '%u' is not a branch target"_err_en_US,
991-
SayLabel(label)})
992-
.Attach(stmt.parserCharBlock,
993-
parser::MessageFormattedText{
994-
"Control flow use of '%u'"_en_US, SayLabel(label)});
987+
"Label '%u' is not a branch target"_err_en_US, SayLabel(label))
988+
.Attach(stmt.parserCharBlock, "Control flow use of '%u'"_en_US,
989+
SayLabel(label));
995990
} else if (!branchTarget.labeledStmtClassificationSet.test(
996991
TargetStatementEnum::Branch)) { // warning
997992
context
998993
.Say(branchTarget.parserCharBlock,
999-
parser::MessageFormattedText{
1000-
"Label '%u' is not a branch target"_en_US, SayLabel(label)})
1001-
.Attach(stmt.parserCharBlock,
1002-
parser::MessageFormattedText{
1003-
"Control flow use of '%u'"_en_US, SayLabel(label)});
994+
"Label '%u' is not a branch target"_en_US, SayLabel(label))
995+
.Attach(stmt.parserCharBlock, "Control flow use of '%u'"_en_US,
996+
SayLabel(label));
1004997
}
1005998
}
1006999
}
@@ -1022,12 +1015,10 @@ void CheckDataXferTargetConstraints(const SourceStmtList &stmts,
10221015
if (!ioTarget.labeledStmtClassificationSet.test(
10231016
TargetStatementEnum::Format)) {
10241017
context
1025-
.Say(ioTarget.parserCharBlock,
1026-
parser::MessageFormattedText{
1027-
"'%u' not a FORMAT"_err_en_US, SayLabel(label)})
1028-
.Attach(stmt.parserCharBlock,
1029-
parser::MessageFormattedText{
1030-
"data transfer use of '%u'"_en_US, SayLabel(label)});
1018+
.Say(ioTarget.parserCharBlock, "'%u' not a FORMAT"_err_en_US,
1019+
SayLabel(label))
1020+
.Attach(stmt.parserCharBlock, "data transfer use of '%u'"_en_US,
1021+
SayLabel(label));
10311022
}
10321023
}
10331024
}

flang/lib/Semantics/resolve-names-utils.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@ std::optional<std::int64_t> EvaluateInt64(
7676
// Analyze a generic-spec and generate a symbol name and GenericKind for it.
7777
class GenericSpecInfo {
7878
public:
79-
GenericSpecInfo(const parser::DefinedOpName &x) { Analyze(x); }
80-
GenericSpecInfo(const parser::GenericSpec &x) { Analyze(x); }
79+
explicit GenericSpecInfo(const parser::DefinedOpName &x) { Analyze(x); }
80+
explicit GenericSpecInfo(const parser::GenericSpec &x) { Analyze(x); }
8181

8282
GenericKind kind() const { return kind_; }
8383
const SourceName &symbolName() const { return symbolName_.value(); }
@@ -88,12 +88,12 @@ class GenericSpecInfo {
8888
llvm::raw_ostream &, const GenericSpecInfo &);
8989

9090
private:
91+
void Analyze(const parser::DefinedOpName &);
92+
void Analyze(const parser::GenericSpec &);
93+
9194
GenericKind kind_;
9295
const parser::Name *parseName_{nullptr};
9396
std::optional<SourceName> symbolName_;
94-
95-
void Analyze(const parser::DefinedOpName &);
96-
void Analyze(const parser::GenericSpec &);
9797
};
9898

9999
// Analyze a parser::ArraySpec or parser::CoarraySpec

flang/lib/Semantics/resolve-names.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2422,7 +2422,7 @@ void ScopeHandler::MakeExternal(Symbol &symbol) {
24222422
bool ModuleVisitor::Pre(const parser::Only &x) {
24232423
std::visit(common::visitors{
24242424
[&](const Indirection<parser::GenericSpec> &generic) {
2425-
const GenericSpecInfo &genericSpecInfo{generic.value()};
2425+
GenericSpecInfo genericSpecInfo{generic.value()};
24262426
AddUseOnly(genericSpecInfo.symbolName());
24272427
AddUse(genericSpecInfo);
24282428
},

flang/test/Semantics/label11.f90

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,22 @@ end program t14
4141

4242
module t5
4343
interface t7
44-
!ERROR: INTERFACE generic-name (t7) mismatch
44+
!ERROR: END INTERFACE generic name (t8) does not match generic INTERFACE (t7)
4545
end interface t8
46+
abstract interface
47+
!ERROR: END INTERFACE generic name (t19) may not appear for ABSTRACT INTERFACE
48+
end interface t19
49+
interface
50+
!ERROR: END INTERFACE generic name (t20) may not appear for non-generic INTERFACE
51+
end interface t20
52+
interface
53+
!ERROR: END INTERFACE generic name (assignment(=)) may not appear for non-generic INTERFACE
54+
end interface assignment(=)
55+
interface operator(<)
56+
end interface operator(.LT.) ! not an error
57+
interface operator(.EQ.)
58+
end interface operator(==) ! not an error
59+
4660
type t17
4761
!ERROR: derived type definition name mismatch
4862
end type t18

0 commit comments

Comments
 (0)