[flang-commits] [flang] 1894250 - [flang] Revamp C1502 checking of END INTERFACE [generic-spec]
peter klausler via flang-commits
flang-commits at lists.llvm.org
Fri Sep 17 08:13:19 PDT 2021
Author: peter klausler
Date: 2021-09-17T08:13:10-07:00
New Revision: 1894250291ea654bf589bef1b809dc1e15011eec
URL: https://github.com/llvm/llvm-project/commit/1894250291ea654bf589bef1b809dc1e15011eec
DIFF: https://github.com/llvm/llvm-project/commit/1894250291ea654bf589bef1b809dc1e15011eec.diff
LOG: [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
Added:
Modified:
flang/lib/Semantics/resolve-labels.cpp
flang/lib/Semantics/resolve-names-utils.h
flang/lib/Semantics/resolve-names.cpp
flang/test/Semantics/label11.f90
Removed:
################################################################################
diff --git a/flang/lib/Semantics/resolve-labels.cpp b/flang/lib/Semantics/resolve-labels.cpp
index 9560a34c539c..767fe66666a2 100644
--- a/flang/lib/Semantics/resolve-labels.cpp
+++ b/flang/lib/Semantics/resolve-labels.cpp
@@ -346,17 +346,11 @@ class ParseTreeAnalyzer {
const auto &firstStmt{std::get<parser::Statement<FIRST>>(a.t)};
if (const parser::CharBlock * firstName{GetStmtName(firstStmt)}) {
if (*firstName != *name) {
- context_
- .Say(*name,
- parser::MessageFormattedText{
- "%s name mismatch"_err_en_US, constructTag})
+ context_.Say(*name, "%s name mismatch"_err_en_US, constructTag)
.Attach(*firstName, "should be"_en_US);
}
} else {
- context_
- .Say(*name,
- parser::MessageFormattedText{
- "%s name not allowed"_err_en_US, constructTag})
+ context_.Say(*name, "%s name not allowed"_err_en_US, constructTag)
.Attach(firstStmt.source, "in unnamed %s"_en_US, constructTag);
}
}
@@ -383,32 +377,51 @@ class ParseTreeAnalyzer {
// C1502
void Post(const parser::InterfaceBlock &interfaceBlock) {
- auto &interfaceStmt{
- std::get<parser::Statement<parser::InterfaceStmt>>(interfaceBlock.t)};
- if (const auto *optionalGenericSpecPointer{
- std::get_if<std::optional<parser::GenericSpec>>(
- &interfaceStmt.statement.u)}) {
- if (*optionalGenericSpecPointer) {
- if (const auto *namePointer{
- std::get_if<parser::Name>(&(*optionalGenericSpecPointer)->u)}) {
- auto &optionalGenericSpec{
- std::get<parser::Statement<parser::EndInterfaceStmt>>(
- interfaceBlock.t)
- .statement.v};
- if (optionalGenericSpec) {
- if (const auto *otherPointer{
- std::get_if<parser::Name>(&optionalGenericSpec->u)}) {
- if (namePointer->source != otherPointer->source) {
- context_
- .Say(currentPosition_,
- parser::MessageFormattedText{
- "INTERFACE generic-name (%s) mismatch"_err_en_US,
- namePointer->source})
- .Attach(interfaceStmt.source, "mismatched INTERFACE"_en_US);
- }
- }
+ if (const auto &endGenericSpec{
+ std::get<parser::Statement<parser::EndInterfaceStmt>>(
+ interfaceBlock.t)
+ .statement.v}) {
+ const auto &interfaceStmt{
+ std::get<parser::Statement<parser::InterfaceStmt>>(interfaceBlock.t)};
+ if (std::holds_alternative<parser::Abstract>(interfaceStmt.statement.u)) {
+ context_
+ .Say(endGenericSpec->source,
+ "END INTERFACE generic name (%s) may not appear for ABSTRACT INTERFACE"_err_en_US,
+ endGenericSpec->source)
+ .Attach(
+ interfaceStmt.source, "corresponding ABSTRACT INTERFACE"_en_US);
+ } else if (const auto &genericSpec{
+ std::get<std::optional<parser::GenericSpec>>(
+ interfaceStmt.statement.u)}) {
+ bool ok{genericSpec->source == endGenericSpec->source};
+ if (!ok) {
+ // Accept variant spellings of .LT. &c.
+ const auto *endOp{
+ std::get_if<parser::DefinedOperator>(&endGenericSpec->u)};
+ const auto *op{std::get_if<parser::DefinedOperator>(&genericSpec->u)};
+ if (endOp && op) {
+ const auto *endIntrin{
+ std::get_if<parser::DefinedOperator::IntrinsicOperator>(
+ &endOp->u)};
+ const auto *intrin{
+ std::get_if<parser::DefinedOperator::IntrinsicOperator>(
+ &op->u)};
+ ok = endIntrin && intrin && *endIntrin == *intrin;
}
}
+ if (!ok) {
+ context_
+ .Say(endGenericSpec->source,
+ "END INTERFACE generic name (%s) does not match generic INTERFACE (%s)"_err_en_US,
+ endGenericSpec->source, genericSpec->source)
+ .Attach(genericSpec->source, "corresponding INTERFACE"_en_US);
+ }
+ } else {
+ context_
+ .Say(endGenericSpec->source,
+ "END INTERFACE generic name (%s) may not appear for non-generic INTERFACE"_err_en_US,
+ endGenericSpec->source)
+ .Attach(interfaceStmt.source, "corresponding INTERFACE"_en_US);
}
}
}
@@ -441,8 +454,7 @@ class ParseTreeAnalyzer {
}
} else {
context_.Say(*endName,
- parser::MessageFormattedText{
- "END PROGRAM has name without PROGRAM statement"_err_en_US});
+ "END PROGRAM has name without PROGRAM statement"_err_en_US);
}
}
}
@@ -640,24 +652,20 @@ class ParseTreeAnalyzer {
if (endName) {
if (*constructName != *endName) {
context_
- .Say(*endName,
- parser::MessageFormattedText{
- "%s construct name mismatch"_err_en_US, constructTag})
+ .Say(*endName, "%s construct name mismatch"_err_en_US,
+ constructTag)
.Attach(*constructName, "should be"_en_US);
}
} else {
context_
.Say(endStmt.source,
- parser::MessageFormattedText{
- "%s construct name required but missing"_err_en_US,
- constructTag})
+ "%s construct name required but missing"_err_en_US,
+ constructTag)
.Attach(*constructName, "should be"_en_US);
}
} else if (endName) {
context_
- .Say(*endName,
- parser::MessageFormattedText{
- "%s construct name unexpected"_err_en_US, constructTag})
+ .Say(*endName, "%s construct name unexpected"_err_en_US, constructTag)
.Attach(
constructStmt.source, "unnamed %s statement"_en_US, constructTag);
}
@@ -737,18 +745,16 @@ class ParseTreeAnalyzer {
const auto iter{std::find(constructNames_.crbegin(),
constructNames_.crend(), constructName.ToString())};
if (iter == constructNames_.crend()) {
- context_.Say(constructName,
- parser::MessageFormattedText{
- "%s construct-name is not in scope"_err_en_US, stmtString});
+ context_.Say(constructName, "%s construct-name is not in scope"_err_en_US,
+ stmtString);
}
}
// 6.2.5, paragraph 2
void CheckLabelInRange(parser::Label label) {
if (label < 1 || label > 99999) {
- context_.Say(currentPosition_,
- parser::MessageFormattedText{
- "Label '%u' is out of range"_err_en_US, SayLabel(label)});
+ context_.Say(currentPosition_, "Label '%u' is out of range"_err_en_US,
+ SayLabel(label));
}
}
@@ -761,9 +767,8 @@ class ParseTreeAnalyzer {
LabeledStatementInfoTuplePOD{scope, currentPosition_,
labeledStmtClassificationSet, isExecutableConstructEndStmt})};
if (!pair.second) {
- context_.Say(currentPosition_,
- parser::MessageFormattedText{
- "Label '%u' is not distinct"_err_en_US, SayLabel(label)});
+ context_.Say(currentPosition_, "Label '%u' is not distinct"_err_en_US,
+ SayLabel(label));
}
}
@@ -799,7 +804,7 @@ class ParseTreeAnalyzer {
std::vector<UnitAnalysis> programUnits_;
SemanticsContext &context_;
- parser::CharBlock currentPosition_{nullptr};
+ parser::CharBlock currentPosition_;
ProxyForScope currentScope_;
std::vector<std::string> constructNames_;
};
@@ -904,15 +909,13 @@ void CheckLabelDoConstraints(const SourceStmtList &dos,
auto doTarget{GetLabel(labels, label)};
if (!HasScope(doTarget.proxyForScope)) {
// C1133
- context.Say(position,
- parser::MessageFormattedText{
- "Label '%u' cannot be found"_err_en_US, SayLabel(label)});
+ context.Say(
+ position, "Label '%u' cannot be found"_err_en_US, SayLabel(label));
} else if (doTarget.parserCharBlock.begin() < position.begin()) {
// R1119
context.Say(position,
- parser::MessageFormattedText{
- "Label '%u' doesn't lexically follow DO stmt"_err_en_US,
- SayLabel(label)});
+ "Label '%u' doesn't lexically follow DO stmt"_err_en_US,
+ SayLabel(label));
} else if ((InInclusiveScope(scopes, scope, doTarget.proxyForScope) &&
doTarget.labeledStmtClassificationSet.test(
@@ -924,20 +927,17 @@ void CheckLabelDoConstraints(const SourceStmtList &dos,
common::LanguageFeature::OldLabelDoEndStatements)) {
context
.Say(position,
- parser::MessageFormattedText{
- "A DO loop should terminate with an END DO or CONTINUE"_en_US})
+ "A DO loop should terminate with an END DO or CONTINUE"_en_US)
.Attach(doTarget.parserCharBlock,
"DO loop currently ends at statement:"_en_US);
}
} else if (!InInclusiveScope(scopes, scope, doTarget.proxyForScope)) {
- context.Say(position,
- parser::MessageFormattedText{
- "Label '%u' is not in DO loop scope"_err_en_US, SayLabel(label)});
+ context.Say(position, "Label '%u' is not in DO loop scope"_err_en_US,
+ SayLabel(label));
} else if (!doTarget.labeledStmtClassificationSet.test(
TargetStatementEnum::Do)) {
context.Say(doTarget.parserCharBlock,
- parser::MessageFormattedText{
- "A DO loop should terminate with an END DO or CONTINUE"_err_en_US});
+ "A DO loop should terminate with an END DO or CONTINUE"_err_en_US);
} else {
loopBodies.emplace_back(SkipLabel(position), doTarget.parserCharBlock);
}
@@ -957,9 +957,8 @@ void CheckScopeConstraints(const SourceStmtList &stmts,
const auto &position{stmt.parserCharBlock};
auto target{GetLabel(labels, label)};
if (!HasScope(target.proxyForScope)) {
- context.Say(position,
- parser::MessageFormattedText{
- "Label '%u' was not found"_err_en_US, SayLabel(label)});
+ context.Say(
+ position, "Label '%u' was not found"_err_en_US, SayLabel(label));
} else if (!InInclusiveScope(scopes, scope, target.proxyForScope)) {
// Clause 11.1.2.1 prohibits transfer of control to the interior of a
// block from outside the block, but this does not apply to formats.
@@ -967,9 +966,8 @@ void CheckScopeConstraints(const SourceStmtList &stmts,
TargetStatementEnum::Format)) {
continue;
}
- context.Say(position,
- parser::MessageFormattedText{
- "Label '%u' is not in scope"_en_US, SayLabel(label)});
+ context.Say(
+ position, "Label '%u' is not in scope"_en_US, SayLabel(label));
}
}
}
@@ -986,21 +984,16 @@ void CheckBranchTargetConstraints(const SourceStmtList &stmts,
TargetStatementEnum::CompatibleBranch)) { // error
context
.Say(branchTarget.parserCharBlock,
- parser::MessageFormattedText{
- "Label '%u' is not a branch target"_err_en_US,
- SayLabel(label)})
- .Attach(stmt.parserCharBlock,
- parser::MessageFormattedText{
- "Control flow use of '%u'"_en_US, SayLabel(label)});
+ "Label '%u' is not a branch target"_err_en_US, SayLabel(label))
+ .Attach(stmt.parserCharBlock, "Control flow use of '%u'"_en_US,
+ SayLabel(label));
} else if (!branchTarget.labeledStmtClassificationSet.test(
TargetStatementEnum::Branch)) { // warning
context
.Say(branchTarget.parserCharBlock,
- parser::MessageFormattedText{
- "Label '%u' is not a branch target"_en_US, SayLabel(label)})
- .Attach(stmt.parserCharBlock,
- parser::MessageFormattedText{
- "Control flow use of '%u'"_en_US, SayLabel(label)});
+ "Label '%u' is not a branch target"_en_US, SayLabel(label))
+ .Attach(stmt.parserCharBlock, "Control flow use of '%u'"_en_US,
+ SayLabel(label));
}
}
}
@@ -1022,12 +1015,10 @@ void CheckDataXferTargetConstraints(const SourceStmtList &stmts,
if (!ioTarget.labeledStmtClassificationSet.test(
TargetStatementEnum::Format)) {
context
- .Say(ioTarget.parserCharBlock,
- parser::MessageFormattedText{
- "'%u' not a FORMAT"_err_en_US, SayLabel(label)})
- .Attach(stmt.parserCharBlock,
- parser::MessageFormattedText{
- "data transfer use of '%u'"_en_US, SayLabel(label)});
+ .Say(ioTarget.parserCharBlock, "'%u' not a FORMAT"_err_en_US,
+ SayLabel(label))
+ .Attach(stmt.parserCharBlock, "data transfer use of '%u'"_en_US,
+ SayLabel(label));
}
}
}
diff --git a/flang/lib/Semantics/resolve-names-utils.h b/flang/lib/Semantics/resolve-names-utils.h
index ce1673e681b4..f77145a841be 100644
--- a/flang/lib/Semantics/resolve-names-utils.h
+++ b/flang/lib/Semantics/resolve-names-utils.h
@@ -76,8 +76,8 @@ std::optional<std::int64_t> EvaluateInt64(
// Analyze a generic-spec and generate a symbol name and GenericKind for it.
class GenericSpecInfo {
public:
- GenericSpecInfo(const parser::DefinedOpName &x) { Analyze(x); }
- GenericSpecInfo(const parser::GenericSpec &x) { Analyze(x); }
+ explicit GenericSpecInfo(const parser::DefinedOpName &x) { Analyze(x); }
+ explicit GenericSpecInfo(const parser::GenericSpec &x) { Analyze(x); }
GenericKind kind() const { return kind_; }
const SourceName &symbolName() const { return symbolName_.value(); }
@@ -88,12 +88,12 @@ class GenericSpecInfo {
llvm::raw_ostream &, const GenericSpecInfo &);
private:
+ void Analyze(const parser::DefinedOpName &);
+ void Analyze(const parser::GenericSpec &);
+
GenericKind kind_;
const parser::Name *parseName_{nullptr};
std::optional<SourceName> symbolName_;
-
- void Analyze(const parser::DefinedOpName &);
- void Analyze(const parser::GenericSpec &);
};
// Analyze a parser::ArraySpec or parser::CoarraySpec
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 56c890592e1d..7a8b0b5daffa 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -2423,7 +2423,7 @@ void ScopeHandler::MakeExternal(Symbol &symbol) {
bool ModuleVisitor::Pre(const parser::Only &x) {
std::visit(common::visitors{
[&](const Indirection<parser::GenericSpec> &generic) {
- const GenericSpecInfo &genericSpecInfo{generic.value()};
+ GenericSpecInfo genericSpecInfo{generic.value()};
AddUseOnly(genericSpecInfo.symbolName());
AddUse(genericSpecInfo);
},
diff --git a/flang/test/Semantics/label11.f90 b/flang/test/Semantics/label11.f90
index ebd743a6dbc7..8071163c823d 100644
--- a/flang/test/Semantics/label11.f90
+++ b/flang/test/Semantics/label11.f90
@@ -41,8 +41,22 @@ end program t14
module t5
interface t7
- !ERROR: INTERFACE generic-name (t7) mismatch
+ !ERROR: END INTERFACE generic name (t8) does not match generic INTERFACE (t7)
end interface t8
+ abstract interface
+ !ERROR: END INTERFACE generic name (t19) may not appear for ABSTRACT INTERFACE
+ end interface t19
+ interface
+ !ERROR: END INTERFACE generic name (t20) may not appear for non-generic INTERFACE
+ end interface t20
+ interface
+ !ERROR: END INTERFACE generic name (assignment(=)) may not appear for non-generic INTERFACE
+ end interface assignment(=)
+ interface operator(<)
+ end interface operator(.LT.) ! not an error
+ interface operator(.EQ.)
+ end interface operator(==) ! not an error
+
type t17
!ERROR: derived type definition name mismatch
end type t18
More information about the flang-commits
mailing list