[flang-commits] [flang] 4052c50 - [flang] Enforce constraint C911

Peter Klausler via flang-commits flang-commits at lists.llvm.org
Sat Oct 29 15:00:21 PDT 2022


Author: Peter Klausler
Date: 2022-10-29T14:08:44-07:00
New Revision: 4052c50122a1f7e64a65e1b391cc37b5cccb2662

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

LOG: [flang] Enforce constraint C911

Diagnose attempts to use an non-polymorphic instance of an
abstract derived type.

Differential Revision: https://reviews.llvm.org/D136902

Added: 
    flang/test/Semantics/abstract01.f90

Modified: 
    flang/include/flang/Semantics/expression.h
    flang/lib/Semantics/expression.cpp

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Semantics/expression.h b/flang/include/flang/Semantics/expression.h
index 042ffec9e6833..0b170cf79ca74 100644
--- a/flang/include/flang/Semantics/expression.h
+++ b/flang/include/flang/Semantics/expression.h
@@ -324,6 +324,8 @@ class ExpressionAnalyzer {
   MaybeExpr CompleteSubscripts(ArrayRef &&);
   MaybeExpr ApplySubscripts(DataRef &&, std::vector<Subscript> &&);
   bool CheckRanks(const DataRef &); // Return false if error exists.
+  bool CheckPolymorphic(const DataRef &); // ditto
+  bool CheckDataRef(const DataRef &); // ditto
   std::optional<Expr<SubscriptInteger>> GetSubstringBound(
       const std::optional<parser::ScalarIntExpr> &);
   MaybeExpr AnalyzeDefinedOp(const parser::Name &, ActualArguments &&);

diff  --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index fcf3664b0c69f..6fa48277d0131 100644
--- a/flang/lib/Semantics/expression.cpp
+++ b/flang/lib/Semantics/expression.cpp
@@ -336,6 +336,30 @@ bool ExpressionAnalyzer::CheckRanks(const DataRef &dataRef) {
       dataRef.u);
 }
 
+// C911 - if the last name in a data-ref has an abstract derived type,
+// it must also be polymorphic.
+bool ExpressionAnalyzer::CheckPolymorphic(const DataRef &dataRef) {
+  if (auto type{DynamicType::From(dataRef.GetLastSymbol())}) {
+    if (type->category() == TypeCategory::Derived && !type->IsPolymorphic()) {
+      const Symbol &typeSymbol{
+          type->GetDerivedTypeSpec().typeSymbol().GetUltimate()};
+      if (typeSymbol.attrs().test(semantics::Attr::ABSTRACT)) {
+        AttachDeclaration(
+            Say("Reference to object with abstract derived type '%s' must be polymorphic"_err_en_US,
+                typeSymbol.name()),
+            typeSymbol);
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+bool ExpressionAnalyzer::CheckDataRef(const DataRef &dataRef) {
+  // '&' here prevents short-circuiting
+  return CheckRanks(dataRef) & CheckPolymorphic(dataRef);
+}
+
 // Parse tree correction after a substring S(j:k) was misparsed as an
 // array section.  Fortran substrings must have a range, not a
 // single index.
@@ -407,26 +431,21 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::Designator &d) {
   }
   // These checks have to be deferred to these "top level" data-refs where
   // we can be sure that there are no following subscripts (yet).
-  if (MaybeExpr result{Analyze(d.u)}) {
-    if (std::optional<DataRef> dataRef{ExtractDataRef(std::move(result))}) {
-      if (!CheckRanks(std::move(*dataRef))) {
-        return std::nullopt;
-      }
-      return Designate(std::move(*dataRef));
-    } else if (std::optional<DataRef> dataRef{
-                   ExtractDataRef(std::move(result), /*intoSubstring=*/true)}) {
-      if (!CheckRanks(std::move(*dataRef))) {
-        return std::nullopt;
-      }
-    } else if (std::optional<DataRef> dataRef{ExtractDataRef(std::move(result),
-                   /*intoSubstring=*/false, /*intoComplexPart=*/true)}) {
-      if (!CheckRanks(std::move(*dataRef))) {
-        return std::nullopt;
+  MaybeExpr result{Analyze(d.u)};
+  if (result) {
+    std::optional<DataRef> dataRef{ExtractDataRef(std::move(result))};
+    if (!dataRef) {
+      dataRef = ExtractDataRef(std::move(result), /*intoSubstring=*/true);
+      if (!dataRef) {
+        dataRef = ExtractDataRef(std::move(result),
+            /*intoSubstring=*/false, /*intoComplexPart=*/true);
       }
     }
-    return result;
+    if (dataRef && !CheckDataRef(*dataRef)) {
+      result.reset();
+    }
   }
-  return std::nullopt;
+  return result;
 }
 
 // A utility subroutine to repackage optional expressions of various levels
@@ -2025,7 +2044,7 @@ auto ExpressionAnalyzer::AnalyzeProcedureComponentRef(
           }
         }
         std::optional<DataRef> dataRef{ExtractDataRef(std::move(*dtExpr))};
-        if (dataRef.has_value() && !CheckRanks(std::move(*dataRef))) {
+        if (dataRef && !CheckDataRef(*dataRef)) {
           return std::nullopt;
         }
         if (const Symbol *

diff  --git a/flang/test/Semantics/abstract01.f90 b/flang/test/Semantics/abstract01.f90
new file mode 100644
index 0000000000000..42db4b42eff89
--- /dev/null
+++ b/flang/test/Semantics/abstract01.f90
@@ -0,0 +1,31 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1
+! C911 - abstract derived type can be used only when polymorphic
+program test
+  type, abstract :: abstract
+    integer :: j
+  end type
+  type, extends(abstract) :: concrete
+    integer :: k
+    class(concrete), allocatable :: a(:)
+  end type
+  type(concrete) :: x(2)
+  call sub1(x(1)) ! ok
+  call sub2(x) ! ok
+  call sub1(x(1)%a(1)) ! ok
+  call sub2(x(1)%a) ! ok
+  !ERROR: Reference to object with abstract derived type 'abstract' must be polymorphic
+  call sub1(x(1)%abstract) ! bad
+  !ERROR: Reference to object with abstract derived type 'abstract' must be polymorphic
+  call sub2(x%abstract) ! bad
+  !ERROR: Reference to object with abstract derived type 'abstract' must be polymorphic
+  call sub1(x(1)%a(1)%abstract) ! bad
+  !ERROR: Reference to object with abstract derived type 'abstract' must be polymorphic
+  call sub2(x(1)%a%abstract) ! bad
+ contains
+  subroutine sub1(d)
+    class(abstract) d
+  end subroutine
+  subroutine sub2(d)
+    class(abstract) d(:)
+  end subroutine
+end


        


More information about the flang-commits mailing list