Skip to content

Commit

Permalink
[flang] Preserve errors from generic matching
Browse files Browse the repository at this point in the history
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
  • Loading branch information
klausler committed Jul 21, 2023
1 parent 8c33630 commit fe33374
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 10 deletions.
33 changes: 23 additions & 10 deletions flang/lib/Semantics/expression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 &&
Expand Down Expand Up @@ -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;
Expand All @@ -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)}) {
Expand All @@ -4038,6 +4042,7 @@ MaybeExpr ArgumentAnalyzer::TryDefinedOp(
} else {
result = std::move(thisResult);
hit.push_back(binding);
hitBuffer = std::move(buffer);
}
}
}
Expand All @@ -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) {
Expand All @@ -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);
}
}
}
Expand All @@ -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;
}
Expand Down
19 changes: 19 additions & 0 deletions flang/test/Semantics/pure01.f90
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit fe33374

Please sign in to comment.