[flang] Resolve kind parameters on literal constants
authorTim Keith <tkeith@nvidia.com>
Sat, 9 Feb 2019 00:03:23 +0000 (16:03 -0800)
committerTim Keith <tkeith@nvidia.com>
Sat, 9 Feb 2019 00:03:23 +0000 (16:03 -0800)
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
flang/lib/semantics/expression.h
flang/lib/semantics/resolve-names.cc
flang/test/semantics/CMakeLists.txt
flang/test/semantics/modfile20.f90 [new file with mode: 0644]
flang/test/semantics/resolve35.f90
flang/test/semantics/resolve41.f90 [new file with mode: 0644]

index 0984ae3..8e35261 100644 (file)
@@ -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<std::optional<parser::KindParam>>(x.t),
           context.GetDefaultKind(TypeCategory::Integer))};
   auto value{std::get<0>(x.t)};  // std::(u)int64_t
-  auto result{common::SearchTypes(
-      TypeKindVisitor<TypeCategory::Integer, Constant, std::int64_t>{
-          kind, static_cast<std::int64_t>(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<TypeCategory::Integer, Constant, std::int64_t>{
+          kind, static_cast<std::int64_t>(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<TypeCategory::Integer>(
         *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<semantics::ObjectEntityDetails>()}) {
       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<semantics::TypeParamDetails>()) {
     // A bare reference to a derived type parameter (within a parameterized
@@ -1764,12 +1758,9 @@ Expr<SubscriptInteger> ExpressionAnalysisContext::Analyze(TypeCategory category,
               Expr<SomeType> folded{
                   Fold(GetFoldingContext(), std::move(*kind))};
               if (std::optional<std::int64_t> code{ToInt64(folded)}) {
-                if (IsValidKindOfIntrinsicType(category, *code)) {
+                if (CheckIntrinsicKind(category, *code)) {
                   return Expr<SubscriptInteger>{*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<Expr<SomeInteger>>(folded)}) {
                 return ConvertToType<SubscriptInteger>(std::move(*intExpr));
               }
@@ -1779,20 +1770,10 @@ Expr<SubscriptInteger> ExpressionAnalysisContext::Analyze(TypeCategory category,
           [&](const parser::KindSelector::StarSize &x)
               -> Expr<SubscriptInteger> {
             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<SubscriptInteger>{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;
index bc80a92..4f39517 100644 (file)
@@ -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);
index 029f4b3..d6390b4 100644 (file)
@@ -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<ObjectEntityDetails>().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<parser::Integer<parser::Constant<parser::Name>>>>(
+          &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;
index 72d5918..2ec0d84 100644 (file)
@@ -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 (file)
index 0000000..df87865
--- /dev/null
@@ -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
index 4f51489..e2e74c6 100644 (file)
@@ -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 (file)
index 0000000..9f6a563
--- /dev/null
@@ -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