[flang-commits] [flang] fe33374 - [flang] Preserve errors from generic matching

Peter Klausler via flang-commits flang-commits at lists.llvm.org
Fri Jul 21 13:00:25 PDT 2023


Author: Peter Klausler
Date: 2023-07-21T13:00:04-07:00
New Revision: fe33374fbff267e54e543745b98f826e05c8bab8

URL: https://github.com/llvm/llvm-project/commit/fe33374fbff267e54e543745b98f826e05c8bab8
DIFF: https://github.com/llvm/llvm-project/commit/fe33374fbff267e54e543745b98f826e05c8bab8.diff

LOG: [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

Added: 
    flang/test/Semantics/pure01.f90

Modified: 
    flang/lib/Semantics/expression.cpp

Removed: 
    


################################################################################
diff  --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index f1087c7d423373..be67ae822d9b72 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 00000000000000..e0911efd77c603
--- /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


        


More information about the flang-commits mailing list