[flang] Semantic checks for C702
C702 (R701) A colon shall not be used as a type-param-value except in the declaration of an entity that has the POINTER or ALLOCATABLE attribute. I added code to the visitor for a TypeDeclarationStmt to check for the 'LEN' type parameter for strings and to loop over the type parameters for derived types. I also ran into a few situations where previous tests had erroneously used a colon for type parameters without either the POINTER or ALLOCATABLE attribute and fixed them up. Original-commit: flang-compiler/f18@a1a95bfcd1 Reviewed-on: https://github.com/flang-compiler/f18/pull/973
This commit is contained in:
parent
f90404e59c
commit
05f44aff45
|
@ -720,7 +720,7 @@ public:
|
||||||
void Post(const parser::DimensionStmt::Declaration &);
|
void Post(const parser::DimensionStmt::Declaration &);
|
||||||
void Post(const parser::CodimensionDecl &);
|
void Post(const parser::CodimensionDecl &);
|
||||||
bool Pre(const parser::TypeDeclarationStmt &) { return BeginDecl(); }
|
bool Pre(const parser::TypeDeclarationStmt &) { return BeginDecl(); }
|
||||||
void Post(const parser::TypeDeclarationStmt &) { EndDecl(); }
|
void Post(const parser::TypeDeclarationStmt &);
|
||||||
void Post(const parser::IntegerTypeSpec &);
|
void Post(const parser::IntegerTypeSpec &);
|
||||||
void Post(const parser::IntrinsicTypeSpec::Real &);
|
void Post(const parser::IntrinsicTypeSpec::Real &);
|
||||||
void Post(const parser::IntrinsicTypeSpec::Complex &);
|
void Post(const parser::IntrinsicTypeSpec::Complex &);
|
||||||
|
@ -2889,6 +2889,29 @@ bool DeclarationVisitor::CheckAccessibleComponent(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DeclarationVisitor::Post(const parser::TypeDeclarationStmt &) {
|
||||||
|
if (!GetAttrs().HasAny({Attr::POINTER, Attr::ALLOCATABLE})) { // C702
|
||||||
|
if (const auto *typeSpec{GetDeclTypeSpec()}) {
|
||||||
|
if (typeSpec->category() == DeclTypeSpec::Character) {
|
||||||
|
if (typeSpec->characterTypeSpec().length().isDeferred()) {
|
||||||
|
Say("The type parameter LEN cannot be deferred without"
|
||||||
|
" the POINTER or ALLOCATABLE attribute"_err_en_US);
|
||||||
|
}
|
||||||
|
} else if (const DerivedTypeSpec * derivedSpec{typeSpec->AsDerived()}) {
|
||||||
|
for (const auto &pair : derivedSpec->parameters()) {
|
||||||
|
if (pair.second.isDeferred()) {
|
||||||
|
Say(currStmtSource().value(),
|
||||||
|
"The value of type parameter '%s' cannot be deferred"
|
||||||
|
" without the POINTER or ALLOCATABLE attribute"_err_en_US,
|
||||||
|
pair.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EndDecl();
|
||||||
|
}
|
||||||
|
|
||||||
void DeclarationVisitor::Post(const parser::DimensionStmt::Declaration &x) {
|
void DeclarationVisitor::Post(const parser::DimensionStmt::Declaration &x) {
|
||||||
const auto &name{std::get<parser::Name>(x.t)};
|
const auto &name{std::get<parser::Name>(x.t)};
|
||||||
DeclareObjectEntity(name, Attrs{});
|
DeclareObjectEntity(name, Attrs{});
|
||||||
|
@ -3522,7 +3545,7 @@ bool DeclarationVisitor::Pre(const parser::DataComponentDefStmt &x) {
|
||||||
// so POINTER & ALLOCATABLE enable forward references to derived types.
|
// so POINTER & ALLOCATABLE enable forward references to derived types.
|
||||||
Walk(std::get<std::list<parser::ComponentAttrSpec>>(x.t));
|
Walk(std::get<std::list<parser::ComponentAttrSpec>>(x.t));
|
||||||
set_allowForwardReferenceToDerivedType(
|
set_allowForwardReferenceToDerivedType(
|
||||||
GetAttrs().test(Attr::POINTER) || GetAttrs().test(Attr::ALLOCATABLE));
|
GetAttrs().HasAny({Attr::POINTER, Attr::ALLOCATABLE}));
|
||||||
Walk(std::get<parser::DeclarationTypeSpec>(x.t));
|
Walk(std::get<parser::DeclarationTypeSpec>(x.t));
|
||||||
set_allowForwardReferenceToDerivedType(false);
|
set_allowForwardReferenceToDerivedType(false);
|
||||||
Walk(std::get<std::list<parser::ComponentDecl>>(x.t));
|
Walk(std::get<std::list<parser::ComponentDecl>>(x.t));
|
||||||
|
|
Binary file not shown.
|
@ -99,6 +99,7 @@ set(ERROR_TESTS
|
||||||
resolve66.f90
|
resolve66.f90
|
||||||
resolve67.f90
|
resolve67.f90
|
||||||
resolve68.f90
|
resolve68.f90
|
||||||
|
resolve69.f90
|
||||||
stop01.f90
|
stop01.f90
|
||||||
structconst01.f90
|
structconst01.f90
|
||||||
structconst02.f90
|
structconst02.f90
|
||||||
|
|
|
@ -34,7 +34,7 @@ subroutine C933_a(b1, ca3, ca4, cp3, cp3mold, cp4, cp7, cp8, bsrc)
|
||||||
type(SomeType(1, l1=3)), pointer :: cp9, cp10(:)
|
type(SomeType(1, l1=3)), pointer :: cp9, cp10(:)
|
||||||
|
|
||||||
type(B(*)) b1
|
type(B(*)) b1
|
||||||
type(B(:)) b2
|
type(B(:)), allocatable :: b2
|
||||||
type(B(5)) b3
|
type(B(5)) b3
|
||||||
|
|
||||||
type(SomeType(4, *, 8)) bsrc
|
type(SomeType(4, *, 8)) bsrc
|
||||||
|
|
|
@ -26,12 +26,12 @@ subroutine C946(param_ca_4_assumed, param_ta_4_assumed, param_ca_4_deferred)
|
||||||
real(kind=8) srcx8, srcx8_array(10)
|
real(kind=8) srcx8, srcx8_array(10)
|
||||||
class(WithParam(4, 2)) src_a_4_2
|
class(WithParam(4, 2)) src_a_4_2
|
||||||
type(WithParam(8, 2)) src_a_8_2
|
type(WithParam(8, 2)) src_a_8_2
|
||||||
class(WithParam(4, :)) src_a_4_def
|
class(WithParam(4, :)), allocatable :: src_a_4_def
|
||||||
class(WithParam(8, :)) src_a_8_def
|
class(WithParam(8, :)), allocatable :: src_a_8_def
|
||||||
type(WithParamExtent(4, 2, 8, 3)) src_b_4_2_8_3
|
type(WithParamExtent(4, 2, 8, 3)) src_b_4_2_8_3
|
||||||
class(WithParamExtent(4, :, 8, 3)) src_b_4_def_8_3
|
class(WithParamExtent(4, :, 8, 3)), allocatable :: src_b_4_def_8_3
|
||||||
type(WithParamExtent(8, 2, 8, 3)) src_b_8_2_8_3
|
type(WithParamExtent(8, 2, 8, 3)) src_b_8_2_8_3
|
||||||
class(WithParamExtent(8, :, 8, 3)) src_b_8_def_8_3
|
class(WithParamExtent(8, :, 8, 3)), allocatable :: src_b_8_def_8_3
|
||||||
type(WithParamExtent2(k1=4, l1=5, k2=5, l2=6, l3=8 )) src_c_4_5_5_6_8_8
|
type(WithParamExtent2(k1=4, l1=5, k2=5, l2=6, l3=8 )) src_c_4_5_5_6_8_8
|
||||||
class(WithParamExtent2(k1=4, l1=2, k2=5, l2=6, k3=5, l3=8)) src_c_4_2_5_6_5_8
|
class(WithParamExtent2(k1=4, l1=2, k2=5, l2=6, k3=5, l3=8)) src_c_4_2_5_6_5_8
|
||||||
class(WithParamExtent2(k2=5, l2=6, k3=5, l3=8)) src_c_1_2_5_6_5_8
|
class(WithParamExtent2(k2=5, l2=6, k3=5, l3=8)) src_c_1_2_5_6_5_8
|
||||||
|
|
|
@ -3,20 +3,20 @@
|
||||||
! Note: Module files are encoded in UTF-8.
|
! Note: Module files are encoded in UTF-8.
|
||||||
|
|
||||||
module m
|
module m
|
||||||
character(kind=4,len=:), parameter :: c4 = 4_"Hi! 你好!"
|
character(kind=4,len=*), parameter :: c4 = 4_"Hi! 你好!"
|
||||||
! In CHARACTER(1) literals, codepoints > 0xff are serialized into UTF-8;
|
! In CHARACTER(1) literals, codepoints > 0xff are serialized into UTF-8;
|
||||||
! each of those bytes then gets encoded into UTF-8 for the module file.
|
! each of those bytes then gets encoded into UTF-8 for the module file.
|
||||||
character(kind=1,len=:), parameter :: c1 = 1_"Hi! 你好!"
|
character(kind=1,len=*), parameter :: c1 = 1_"Hi! 你好!"
|
||||||
character(kind=4,len=:), parameter :: c4a(*) = [4_"一", 4_"二", 4_"三", 4_"四", 4_"五"]
|
character(kind=4,len=*), parameter :: c4a(*) = [4_"一", 4_"二", 4_"三", 4_"四", 4_"五"]
|
||||||
integer, parameter :: lc4 = len(c4)
|
integer, parameter :: lc4 = len(c4)
|
||||||
integer, parameter :: lc1 = len(c1)
|
integer, parameter :: lc1 = len(c1)
|
||||||
end module m
|
end module m
|
||||||
|
|
||||||
!Expect: m.mod
|
!Expect: m.mod
|
||||||
!module m
|
!module m
|
||||||
!character(:,4),parameter::c4=4_"Hi! \344\275\240\345\245\275!"
|
!character(*,4),parameter::c4=4_"Hi! \344\275\240\345\245\275!"
|
||||||
!character(:,1),parameter::c1=1_"Hi! \344\275\240\345\245\275!"
|
!character(*,1),parameter::c1=1_"Hi! \344\275\240\345\245\275!"
|
||||||
!character(:,4),parameter::c4a(1_8:*)=[CHARACTER(KIND=4,LEN=1)::4_"\344\270\200",4_"\344\272\214",4_"\344\270\211",4_"\345\233\233",4_"\344\272\224"]
|
!character(*,4),parameter::c4a(1_8:*)=[CHARACTER(KIND=4,LEN=1)::4_"\344\270\200",4_"\344\272\214",4_"\344\270\211",4_"\345\233\233",4_"\344\272\224"]
|
||||||
!integer(4),parameter::lc4=7_4
|
!integer(4),parameter::lc4=7_4
|
||||||
!intrinsic::len
|
!intrinsic::len
|
||||||
!integer(4),parameter::lc1=11_4
|
!integer(4),parameter::lc1=11_4
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
! C701 The type-param-value for a kind type parameter shall be a constant
|
||||||
|
! expression. This constraint looks like a mistake in the standard.
|
||||||
integer, parameter :: k = 8
|
integer, parameter :: k = 8
|
||||||
real, parameter :: l = 8.0
|
real, parameter :: l = 8.0
|
||||||
integer :: n = 2
|
integer :: n = 2
|
||||||
|
|
45
flang/test/semantics/resolve69.f90
Normal file
45
flang/test/semantics/resolve69.f90
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
subroutine s1()
|
||||||
|
! C701 (R701) The type-param-value for a kind type parameter shall be a
|
||||||
|
! constant expression.
|
||||||
|
! C702 (R701) A colon shall not be used as a type-param-value except in the
|
||||||
|
! declaration of an entity that has the POINTER or ALLOCATABLE attribute.
|
||||||
|
integer, parameter :: constVal = 1
|
||||||
|
integer :: nonConstVal = 1
|
||||||
|
!ERROR: Invalid specification expression: reference to local entity 'nonconstval'
|
||||||
|
character(nonConstVal) :: colonString1
|
||||||
|
character(len=20, kind=constVal + 1) :: constKindString
|
||||||
|
character(len=:, kind=constVal + 1), pointer :: constKindString1
|
||||||
|
!ERROR: The type parameter LEN cannot be deferred without the POINTER or ALLOCATABLE attribute
|
||||||
|
character(len=:, kind=constVal + 1) :: constKindString2
|
||||||
|
!ERROR: Must be a constant value
|
||||||
|
character(len=20, kind=nonConstVal) :: nonConstKindString
|
||||||
|
!ERROR: The type parameter LEN cannot be deferred without the POINTER or ALLOCATABLE attribute
|
||||||
|
character(len=:) :: deferredString
|
||||||
|
!ERROR: The type parameter LEN cannot be deferred without the POINTER or ALLOCATABLE attribute
|
||||||
|
character(:) :: colonString2
|
||||||
|
!OK because of the allocatable attribute
|
||||||
|
character(:), allocatable :: colonString3
|
||||||
|
|
||||||
|
type derived(typeKind, typeLen)
|
||||||
|
integer, kind :: typeKind
|
||||||
|
integer, len :: typeLen
|
||||||
|
end type derived
|
||||||
|
|
||||||
|
type (derived(constVal, 3)) :: constDerivedKind
|
||||||
|
!ERROR: Value of kind type parameter 'typekind' (nonconstval) is not a scalar INTEGER constant
|
||||||
|
!ERROR: Invalid specification expression: reference to local entity 'nonconstval'
|
||||||
|
type (derived(nonConstVal, 3)) :: nonConstDerivedKind
|
||||||
|
|
||||||
|
!OK because all type-params are constants
|
||||||
|
type (derived(3, constVal)) :: constDerivedLen
|
||||||
|
|
||||||
|
!ERROR: Invalid specification expression: reference to local entity 'nonconstval'
|
||||||
|
type (derived(3, nonConstVal)) :: nonConstDerivedLen
|
||||||
|
!ERROR: The value of type parameter 'typelen' cannot be deferred without the POINTER or ALLOCATABLE attribute
|
||||||
|
type (derived(3, :)) :: colonDerivedLen
|
||||||
|
!ERROR: The value of type parameter 'typekind' cannot be deferred without the POINTER or ALLOCATABLE attribute
|
||||||
|
!ERROR: The value of type parameter 'typelen' cannot be deferred without the POINTER or ALLOCATABLE attribute
|
||||||
|
type (derived( :, :)) :: colonDerivedLen1
|
||||||
|
type (derived( :, :)), pointer :: colonDerivedLen2
|
||||||
|
type (derived(4, :)), pointer :: colonDerivedLen3
|
||||||
|
end subroutine s1
|
Loading…
Reference in a new issue