[flang] Enforce constraint C911

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

Differential Revision: https://reviews.llvm.org/D136902
This commit is contained in:
Peter Klausler 2022-10-11 12:45:05 -07:00
parent 39f6d83345
commit 4052c50122
3 changed files with 70 additions and 18 deletions

View File

@ -324,6 +324,8 @@ private:
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 &&);

View File

@ -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 *

View File

@ -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