From d396a8845b2486ab5285e1c11c2f2f72e58bb4fe Mon Sep 17 00:00:00 2001 From: Tim Keith Date: Fri, 8 Feb 2019 16:03:23 -0800 Subject: [PATCH] [flang] Resolve kind parameters on literal constants When the kind parameter is a constant name, that name must be resolved. Add `CheckIntrinsicKind` and `CheckIntrinsicSize` for common checking of valid intrinsic kinds. Previous we had different forms of the error message depending on the context ( "unsupported INTEGER(KIND=47)" and "INTEGER(KIND=47) is not a supported type"). Report error for parameters without initialization where are they declared (in `Post(EntityDecl)`) rather than where they are referenced (in `AnalyzeExpr`). Remove error message from `AnalyzeKindParam`: `AnalyzeExpr` will report the error (e.g. not integer, not constant, etc.). Remove "name was not resolved" error from `AnalyzeExpr`: it should be reported by name resolution. Original-commit: flang-compiler/f18@9b0a99ce6696fe7db7708ea0362e103faa509968 Reviewed-on: https://github.com/flang-compiler/f18/pull/281 Tree-same-pre-rewrite: false --- flang/lib/semantics/expression.cc | 67 ++++++++++++++++++++---------------- flang/lib/semantics/expression.h | 4 +++ flang/lib/semantics/resolve-names.cc | 15 ++++++++ flang/test/semantics/CMakeLists.txt | 2 ++ flang/test/semantics/modfile20.f90 | 35 +++++++++++++++++++ flang/test/semantics/resolve35.f90 | 2 +- flang/test/semantics/resolve41.f90 | 39 +++++++++++++++++++++ 7 files changed, 133 insertions(+), 31 deletions(-) create mode 100644 flang/test/semantics/modfile20.f90 create mode 100644 flang/test/semantics/resolve41.f90 diff --git a/flang/lib/semantics/expression.cc b/flang/lib/semantics/expression.cc index 0984ae3..8e35261 100644 --- a/flang/lib/semantics/expression.cc +++ b/flang/lib/semantics/expression.cc @@ -504,8 +504,6 @@ static int AnalyzeKindParam(ExpressionAnalysisContext &context, } } } - context.Say("KIND type parameter on literal must be a scalar " - "integer constant"_err_en_US); return defaultKind; }, [&](parser::KindParam::Kanji) { @@ -527,13 +525,12 @@ MaybeExpr IntLiteralConstant( AnalyzeKindParam(context, std::get>(x.t), context.GetDefaultKind(TypeCategory::Integer))}; auto value{std::get<0>(x.t)}; // std::(u)int64_t - auto result{common::SearchTypes( - TypeKindVisitor{ - kind, static_cast(value)})}; - if (!result.has_value()) { - context.Say("unsupported INTEGER(KIND=%d)"_err_en_US, kind); + if (!context.CheckIntrinsicKind(TypeCategory::Integer, kind)) { + return std::nullopt; } - return result; + return common::SearchTypes( + TypeKindVisitor{ + kind, static_cast(value)}); } static MaybeExpr AnalyzeExpr( @@ -653,8 +650,7 @@ static MaybeExpr AnalyzeExpr(ExpressionAnalysisContext &context, // CHARACTER literal processing. static MaybeExpr AnalyzeString( ExpressionAnalysisContext &context, std::string &&string, int kind) { - if (!IsValidKindOfIntrinsicType(TypeCategory::Character, kind)) { - context.Say("unsupported CHARACTER(KIND=%d)"_err_en_US, kind); + if (!context.CheckIntrinsicKind(TypeCategory::Character, kind)) { return std::nullopt; } if (kind == 1) { @@ -775,15 +771,13 @@ static MaybeExpr AnalyzeExpr( return AsMaybeExpr(ConvertToKind( *kind, AsExpr(ImpliedDoIndex{n.source}))); } else if (n.symbol == nullptr) { - context.Say( - n.source, "TODO INTERNAL: name was not resolved to a symbol"_err_en_US); + // error should have been reported in name resolution } else if (n.symbol->attrs().test(semantics::Attr::PARAMETER)) { if (auto *details{n.symbol->detailsIf()}) { if (auto &init{details->init()}) { return init; } } - context.Say(n.source, "parameter does not have a value"_err_en_US); // TODO: enumerators, do they have the PARAMETER attribute? } else if (n.symbol->detailsIf()) { // A bare reference to a derived type parameter (within a parameterized @@ -1764,12 +1758,9 @@ Expr ExpressionAnalysisContext::Analyze(TypeCategory category, Expr folded{ Fold(GetFoldingContext(), std::move(*kind))}; if (std::optional code{ToInt64(folded)}) { - if (IsValidKindOfIntrinsicType(category, *code)) { + if (CheckIntrinsicKind(category, *code)) { return Expr{*code}; } - SayAt(x, "%s(KIND=%jd) is not a supported type"_err_en_US, - parser::ToUpperCaseLetters(EnumToString(category)).data(), - *code); } else if (auto *intExpr{UnwrapExpr>(folded)}) { return ConvertToType(std::move(*intExpr)); } @@ -1779,20 +1770,10 @@ Expr ExpressionAnalysisContext::Analyze(TypeCategory category, [&](const parser::KindSelector::StarSize &x) -> Expr { std::intmax_t size = x.v; - if (category == TypeCategory::Complex) { - // COMPLEX*16 == COMPLEX(KIND=8) - if ((size % 2) == 0 && - evaluate::IsValidKindOfIntrinsicType(category, size / 2)) { - size /= 2; - } else { - Say("COMPLEX*%jd is not a supported type"_err_en_US, size); - size = defaultKind; - } - } else if (!evaluate::IsValidKindOfIntrinsicType(category, size)) { - Say("%s*%jd is not a supported type"_err_en_US, - parser::ToUpperCaseLetters(EnumToString(category)).data(), - size); + if (!CheckIntrinsicSize(category, size)) { size = defaultKind; + } else if (category == TypeCategory::Complex) { + size /= 2; } return Expr{size}; }, @@ -1809,6 +1790,32 @@ DynamicType ExpressionAnalysisContext::GetDefaultKindOfType( return {category, GetDefaultKind(category)}; } +bool ExpressionAnalysisContext::CheckIntrinsicKind( + TypeCategory category, std::int64_t kind) { + if (IsValidKindOfIntrinsicType(category, kind)) { + return true; + } else { + Say("%s(KIND=%jd) is not a supported type"_err_en_US, + parser::ToUpperCaseLetters(EnumToString(category)).data(), kind); + return false; + } +} + +bool ExpressionAnalysisContext::CheckIntrinsicSize( + TypeCategory category, std::int64_t size) { + if (category == TypeCategory::Complex) { + // COMPLEX*16 == COMPLEX(KIND=8) + if (size % 2 == 0 && IsValidKindOfIntrinsicType(category, size / 2)) { + return true; + } + } else if (IsValidKindOfIntrinsicType(category, size)) { + return true; + } + Say("%s*%jd is not a supported type"_err_en_US, + parser::ToUpperCaseLetters(EnumToString(category)).data(), size); + return false; +} + bool ExpressionAnalysisContext::AddAcImpliedDo( parser::CharBlock name, int kind) { return acImpliedDos_.insert(std::make_pair(name, kind)).second; diff --git a/flang/lib/semantics/expression.h b/flang/lib/semantics/expression.h index bc80a92..4f39517 100644 --- a/flang/lib/semantics/expression.h +++ b/flang/lib/semantics/expression.h @@ -100,6 +100,10 @@ public: int GetDefaultKind(common::TypeCategory); DynamicType GetDefaultKindOfType(common::TypeCategory); + // Return false and emit error if these checks fail: + bool CheckIntrinsicKind(TypeCategory, std::int64_t kind); + bool CheckIntrinsicSize(TypeCategory, std::int64_t size); + // Manage a set of active array constructor implied DO loops. bool AddAcImpliedDo(parser::CharBlock, int); void RemoveAcImpliedDo(parser::CharBlock); diff --git a/flang/lib/semantics/resolve-names.cc b/flang/lib/semantics/resolve-names.cc index 029f4b3..d6390b4 100644 --- a/flang/lib/semantics/resolve-names.cc +++ b/flang/lib/semantics/resolve-names.cc @@ -656,6 +656,7 @@ public: void Post(const parser::CharSelector::LengthAndKind &); void Post(const parser::CharLength &); void Post(const parser::LengthSelector &); + bool Pre(const parser::KindParam &); bool Pre(const parser::DeclarationTypeSpec::Type &); bool Pre(const parser::DeclarationTypeSpec::Class &); bool Pre(const parser::DeclarationTypeSpec::Record &); @@ -2393,6 +2394,8 @@ void DeclarationVisitor::Post(const parser::EntityDecl &x) { symbol.get().set_init(EvaluateExpr(*expr)); } } + } else if (attrs.test(Attr::PARAMETER)) { + Say(name, "Missing initialization for parameter '%s'"_err_en_US); } } @@ -2606,6 +2609,18 @@ void DeclarationVisitor::Post(const parser::LengthSelector &x) { } } +bool DeclarationVisitor::Pre(const parser::KindParam &x) { + if (const auto *kind{std::get_if< + parser::Scalar>>>( + &x.u)}) { + const parser::Name &name{kind->thing.thing.thing}; + if (!FindSymbol(name)) { + Say(name, "Parameter '%s' not found"_err_en_US); + } + } + return false; +} + bool DeclarationVisitor::Pre(const parser::DeclarationTypeSpec::Type &x) { CHECK(GetDeclTypeSpecCategory() == DeclTypeSpec::Category::TypeDerived); return true; diff --git a/flang/test/semantics/CMakeLists.txt b/flang/test/semantics/CMakeLists.txt index 72d5918..2ec0d84 100644 --- a/flang/test/semantics/CMakeLists.txt +++ b/flang/test/semantics/CMakeLists.txt @@ -66,6 +66,7 @@ set(ERROR_TESTS resolve38.f90 resolve39.f90 resolve40.f90 + resolve41.f90 ) # These test files have expected symbols in the source @@ -106,6 +107,7 @@ set(MODFILE_TESTS modfile17.f90 modfile18.f90 modfile19.f90 + modfile20.f90 ) set(LABEL_TESTS diff --git a/flang/test/semantics/modfile20.f90 b/flang/test/semantics/modfile20.f90 new file mode 100644 index 0000000..df87865 --- /dev/null +++ b/flang/test/semantics/modfile20.f90 @@ -0,0 +1,35 @@ +! Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. +! +! Licensed under the Apache License, Version 2.0 (the "License"); +! you may not use this file except in compliance with the License. +! You may obtain a copy of the License at +! +! http://www.apache.org/licenses/LICENSE-2.0 +! +! Unless required by applicable law or agreed to in writing, software +! distributed under the License is distributed on an "AS IS" BASIS, +! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +! See the License for the specific language governing permissions and +! limitations under the License. + +! Check modfile generation for generic interfaces +module m + integer, parameter :: k8 = 8 + integer(8), parameter :: k4 = k8/2 + integer, parameter :: k1 = 1 + integer(k8), parameter :: i = 2_k8 + real :: r = 2.0_k4 + character(10, kind=k1) :: c = k1_"asdf" + complex*16 :: z = (1.0_k8, 2.0_k8) +end + +!Expect: m.mod +!module m +! integer(4),parameter::k8=8_4 +! integer(8),parameter::k4=4_4 +! integer(4),parameter::k1=1_4 +! integer(8),parameter::i=2_8 +! real(4)::r=2._4 +! character(10_4,1)::c=1_"asdf" +! complex(8)::z=(1._8,2._8) +!end diff --git a/flang/test/semantics/resolve35.f90 b/flang/test/semantics/resolve35.f90 index 4f51489..e2e74c6 100644 --- a/flang/test/semantics/resolve35.f90 +++ b/flang/test/semantics/resolve35.f90 @@ -103,7 +103,7 @@ end subroutine s9 external bad1 - real, parameter :: bad2 + real, parameter :: bad2 = 1.0 x = cos(0.) do concurrent(i=1:2) & !ERROR: Locality attribute not allowed on 'bad1' diff --git a/flang/test/semantics/resolve41.f90 b/flang/test/semantics/resolve41.f90 new file mode 100644 index 0000000..9f6a563 --- /dev/null +++ b/flang/test/semantics/resolve41.f90 @@ -0,0 +1,39 @@ +! Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. +! +! Licensed under the Apache License, Version 2.0 (the "License"); +! you may not use this file except in compliance with the License. +! You may obtain a copy of the License at +! +! http://www.apache.org/licenses/LICENSE-2.0 +! +! Unless required by applicable law or agreed to in writing, software +! distributed under the License is distributed on an "AS IS" BASIS, +! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +! See the License for the specific language governing permissions and +! limitations under the License. +module m + implicit none + real, parameter :: a = 8.0 + !ERROR: Must have INTEGER type + integer :: aa = 2_a + integer :: b = 8 + !ERROR: Must be a constant value + integer :: bb = 2_b + !TODO: should get error -- not scalar + !integer, parameter :: c(10) = 8 + !integer :: cc = 2_c + integer, parameter :: d = 47 + !ERROR: INTEGER(KIND=47) is not a supported type + integer :: dd = 2_d + !ERROR: Parameter 'e' not found + integer :: ee = 2_e + !ERROR: Missing initialization for parameter 'f' + integer, parameter :: f + integer :: ff = 2_f + !ERROR: REAL(KIND=23) is not a supported type + real(d/2) :: g + !ERROR: REAL*47 is not a supported type + real*47 :: h + !ERROR: COMPLEX*47 is not a supported type + complex*47 :: i +end -- 2.7.4