[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