aboutsummaryrefslogtreecommitdiff
path: root/flang
diff options
context:
space:
mode:
authorPeter Klausler <pklausler@nvidia.com>2023-07-18 16:14:49 -0700
committerPeter Klausler <pklausler@nvidia.com>2023-07-21 13:00:04 -0700
commitfe33374fbff267e54e543745b98f826e05c8bab8 (patch)
tree8e80dbf50ffa5ea62a16c3878c83a53ea04c3c81 /flang
parent8c33630e15c8c630804058f0820b8876e5674d71 (diff)
downloadllvm-fe33374fbff267e54e543745b98f826e05c8bab8.zip
llvm-fe33374fbff267e54e543745b98f826e05c8bab8.tar.gz
llvm-fe33374fbff267e54e543745b98f826e05c8bab8.tar.bz2
[flang] Preserve errors from generic matching
When searching for a matching specific procedure for a set of actual arguments in a type-bound generic interface for a defined operator, don't discard any error messages that may have been produced for the specific that was found. Tweak the code to preserve those messages and add them to the context's messages, and add a test. Differential Revision: https://reviews.llvm.org/D155966
Diffstat (limited to 'flang')
-rw-r--r--flang/lib/Semantics/expression.cpp33
-rw-r--r--flang/test/Semantics/pure01.f9019
2 files changed, 42 insertions, 10 deletions
diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index f1087c7d..be67ae8 100644
--- a/flang/lib/Semantics/expression.cpp
+++ b/flang/lib/Semantics/expression.cpp
@@ -3038,14 +3038,14 @@ std::optional<characteristics::Procedure> ExpressionAnalyzer::CheckCall(
ok &= semantics::CheckArguments(*chars, arguments, context_,
context_.FindScope(callSite), treatExternalAsImplicit,
specificIntrinsic);
- if (procSymbol && !IsPureProcedure(*procSymbol)) {
- if (const semantics::Scope *
- pure{semantics::FindPureProcedureContaining(
- context_.FindScope(callSite))}) {
- Say(callSite,
- "Procedure '%s' referenced in pure subprogram '%s' must be pure too"_err_en_US,
- procSymbol->name(), DEREF(pure->symbol()).name());
- }
+ }
+ if (procSymbol && !IsPureProcedure(*procSymbol)) {
+ if (const semantics::Scope *
+ pure{semantics::FindPureProcedureContaining(
+ context_.FindScope(callSite))}) {
+ Say(callSite,
+ "Procedure '%s' referenced in pure subprogram '%s' must be pure too"_err_en_US,
+ procSymbol->name(), DEREF(pure->symbol()).name());
}
}
if (ok && !treatExternalAsImplicit && procSymbol &&
@@ -4010,8 +4010,10 @@ MaybeExpr ArgumentAnalyzer::TryDefinedOp(
std::string oprNameString{
isUserOp ? std::string{opr} : "operator("s + opr + ')'};
parser::CharBlock oprName{oprNameString};
+ parser::Messages hitBuffer;
{
- auto restorer{context_.GetContextualMessages().DiscardMessages()};
+ parser::Messages buffer;
+ auto restorer{context_.GetContextualMessages().SetMessages(buffer)};
const auto &scope{context_.context().FindScope(source_)};
if (Symbol *symbol{scope.FindSymbol(oprName)}) {
anyPossibilities = true;
@@ -4023,10 +4025,12 @@ MaybeExpr ArgumentAnalyzer::TryDefinedOp(
result.reset();
} else {
hit.push_back(symbol);
+ hitBuffer = std::move(buffer);
}
}
}
for (std::size_t passIndex{0}; passIndex < actuals_.size(); ++passIndex) {
+ buffer.clear();
const Symbol *generic{nullptr};
if (const Symbol *binding{
FindBoundOp(oprName, passIndex, generic, false)}) {
@@ -4038,6 +4042,7 @@ MaybeExpr ArgumentAnalyzer::TryDefinedOp(
} else {
result = std::move(thisResult);
hit.push_back(binding);
+ hitBuffer = std::move(buffer);
}
}
}
@@ -4053,6 +4058,9 @@ MaybeExpr ArgumentAnalyzer::TryDefinedOp(
}
}
}
+ if (auto *msgs{context_.GetContextualMessages().messages()}) {
+ msgs->Annex(std::move(hitBuffer));
+ }
} else if (inaccessible) {
context_.Say(source_, std::move(*inaccessible));
} else if (anyPossibilities) {
@@ -4074,12 +4082,15 @@ MaybeExpr ArgumentAnalyzer::TryDefinedOp(
}
MaybeExpr result;
std::vector<const char *> hit;
+ parser::Messages hitBuffer;
{
- auto restorer{context_.GetContextualMessages().DiscardMessages()};
for (std::size_t i{0}; i < oprs.size(); ++i) {
+ parser::Messages buffer;
+ auto restorer{context_.GetContextualMessages().SetMessages(buffer)};
if (MaybeExpr thisResult{TryDefinedOp(oprs[i], error)}) {
result = std::move(thisResult);
hit.push_back(oprs[i]);
+ hitBuffer = std::move(buffer);
}
}
}
@@ -4089,6 +4100,8 @@ MaybeExpr ArgumentAnalyzer::TryDefinedOp(
context_.Say(
"Matching accessible definitions were found with %zd variant spellings of the generic operator ('%s', '%s')"_err_en_US,
hit.size(), ToUpperCase(hit[0]), ToUpperCase(hit[1]));
+ } else { // one hit; preserve errors
+ context_.context().messages().Annex(std::move(hitBuffer));
}
return result;
}
diff --git a/flang/test/Semantics/pure01.f90 b/flang/test/Semantics/pure01.f90
new file mode 100644
index 0000000..e0911ef
--- /dev/null
+++ b/flang/test/Semantics/pure01.f90
@@ -0,0 +1,19 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1
+! Ensure that an impure bound operator can't be called
+! from a pure context.
+module m
+ type t
+ contains
+ procedure :: binding => func
+ generic :: operator(.not.) => binding
+ end type
+ contains
+ impure integer function func(x)
+ class(t), intent(in) :: x
+ func = 0
+ end
+ pure integer function test
+ !ERROR: Procedure 'func' referenced in pure subprogram 'test' must be pure too
+ test = .not. t()
+ end
+end