[flang] Plug error recovery hole for erroneous subscripts
authorpeter klausler <pklausler@nvidia.com>
Fri, 30 Oct 2020 21:18:20 +0000 (14:18 -0700)
committerpeter klausler <pklausler@nvidia.com>
Sat, 31 Oct 2020 00:32:27 +0000 (17:32 -0700)
Avoid a crash in folding an empty vector of subscripts
that resulted from a semantic error.

Differential revision: https://reviews.llvm.org/D90499

flang/lib/Semantics/expression.cpp
flang/test/Semantics/expr-errors03.f90 [new file with mode: 0644]

index 21b7687..73534c3 100644 (file)
@@ -205,11 +205,10 @@ MaybeExpr ExpressionAnalyzer::Designate(DataRef &&ref) {
 // subscripts are in hand.
 MaybeExpr ExpressionAnalyzer::CompleteSubscripts(ArrayRef &&ref) {
   const Symbol &symbol{ref.GetLastSymbol().GetUltimate()};
-  const auto *object{symbol.detailsIf<semantics::ObjectEntityDetails>()};
   int symbolRank{symbol.Rank()};
   int subscripts{static_cast<int>(ref.size())};
   if (subscripts == 0) {
-    // nothing to check
+    return std::nullopt; // error recovery
   } else if (subscripts != symbolRank) {
     if (symbolRank != 0) {
       Say("Reference to rank-%d object '%s' has %d subscripts"_err_en_US,
@@ -230,7 +229,8 @@ MaybeExpr ExpressionAnalyzer::CompleteSubscripts(ArrayRef &&ref) {
         return std::nullopt;
       }
     }
-  } else if (object) {
+  } else if (const auto *object{
+                 symbol.detailsIf<semantics::ObjectEntityDetails>()}) {
     // C928 & C1002
     if (Triplet * last{std::get_if<Triplet>(&ref.subscript().back().u)}) {
       if (!last->upper() && object->IsAssumedSize()) {
@@ -240,6 +240,11 @@ MaybeExpr ExpressionAnalyzer::CompleteSubscripts(ArrayRef &&ref) {
         return std::nullopt;
       }
     }
+  } else {
+    // Shouldn't get here from Analyze(ArrayElement) without a valid base,
+    // which, if not an object, must be a construct entity from
+    // SELECT TYPE/RANK or ASSOCIATE.
+    CHECK(symbol.has<semantics::AssocEntityDetails>());
   }
   return Designate(DataRef{std::move(ref)});
 }
@@ -247,6 +252,9 @@ MaybeExpr ExpressionAnalyzer::CompleteSubscripts(ArrayRef &&ref) {
 // Applies subscripts to a data reference.
 MaybeExpr ExpressionAnalyzer::ApplySubscripts(
     DataRef &&dataRef, std::vector<Subscript> &&subscripts) {
+  if (subscripts.empty()) {
+    return std::nullopt; // error recovery
+  }
   return std::visit(
       common::visitors{
           [&](SymbolRef &&symbol) {
@@ -902,7 +910,6 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::ArrayElement &ae) {
   if (baseExpr) {
     if (ae.subscripts.empty()) {
       // will be converted to function call later or error reported
-      return std::nullopt;
     } else if (baseExpr->Rank() == 0) {
       if (const Symbol * symbol{GetLastSymbol(*baseExpr)}) {
         if (!context_.HasError(symbol)) {
diff --git a/flang/test/Semantics/expr-errors03.f90 b/flang/test/Semantics/expr-errors03.f90
new file mode 100644 (file)
index 0000000..059e80a
--- /dev/null
@@ -0,0 +1,20 @@
+! RUN: %S/test_errors.sh %s %t %f18
+! Regression test for subscript error recovery
+module m
+  implicit none
+  integer, parameter :: n = 3
+  integer, parameter :: pc(n) = [0, 5, 6]
+ contains
+  logical function f(u)
+    integer :: u
+    !ERROR: No explicit type declared for 'i'
+    do i = 1, n
+      !ERROR: No explicit type declared for 'i'
+      if (pc(i) == u) then
+        f = .true.
+        return
+      end if
+    end do
+    f = .false.
+  end
+end module