[flang] Better error reporting, with test
authorpeter klausler <pklausler@nvidia.com>
Fri, 28 Jun 2019 00:16:29 +0000 (17:16 -0700)
committerpeter klausler <pklausler@nvidia.com>
Fri, 28 Jun 2019 16:21:04 +0000 (09:21 -0700)
Original-commit: flang-compiler/f18@85e8b64d3e86c3b8670790687ff1ea7f0857e41e
Reviewed-on: https://github.com/flang-compiler/f18/pull/531

flang/lib/evaluate/fold.cc
flang/lib/semantics/resolve-names.cc
flang/test/semantics/CMakeLists.txt
flang/test/semantics/init01.f90 [new file with mode: 0644]

index 87c131e..950cc9b 100644 (file)
@@ -2291,10 +2291,20 @@ template<typename A> bool IsInitialDataTarget(const A &) { return false; }
 template<typename... A> bool IsInitialDataTarget(const std::variant<A...> &);
 bool IsInitialDataTarget(const DataRef &);
 template<typename T> bool IsInitialDataTarget(const Expr<T> &);
-bool IsInitialDataTarget(const semantics::Symbol *s) { return true; }
+bool IsInitialDataTarget(const semantics::Symbol &s) { return true; }
+bool IsInitialDataTarget(const semantics::Symbol *s) {
+  return IsInitialDataTarget(*s);
+}
 bool IsInitialDataTarget(const Component &x) {
   return IsInitialDataTarget(x.base());
 }
+bool IsInitialDataTarget(const NamedEntity &x) {
+  if (const Component * c{x.UnwrapComponent()}) {
+    return IsInitialDataTarget(*c);
+  } else {
+    return IsInitialDataTarget(x.GetLastSymbol());
+  }
+}
 bool IsInitialDataTarget(const Triplet &x) {
   if (auto lower{x.lower()}) {
     if (!IsConstantExpr(*lower)) {
@@ -2326,9 +2336,7 @@ bool IsInitialDataTarget(const ArrayRef &x) {
   }
   return IsInitialDataTarget(x.base());
 }
-bool IsInitialDataTarget(const DataRef &x) {
-  return std::visit([](const auto &y) { return IsInitialDataTarget(y); }, x.u);
-}
+bool IsInitialDataTarget(const DataRef &x) { return IsInitialDataTarget(x.u); }
 bool IsInitialDataTarget(const Substring &x) {
   return IsConstantExpr(x.lower()) && IsConstantExpr(x.upper());
 }
index fe3b14c..8197dc3 100644 (file)
@@ -826,7 +826,7 @@ private:
   void SetSaveAttr(Symbol &);
   bool HandleUnrestrictedSpecificIntrinsicFunction(const parser::Name &);
   const parser::Name *FindComponent(const parser::Name *, const parser::Name &);
-  void CheckInitialDataTarget(const Symbol &, const SomeExpr &);
+  void CheckInitialDataTarget(const Symbol &, const SomeExpr &, SourceName);
   void Initialization(const parser::Name &, const parser::Initialization &,
       bool inComponentDecl);
 
@@ -4497,26 +4497,51 @@ const parser::Name *DeclarationVisitor::FindComponent(
 
 // C764, C765
 void DeclarationVisitor::CheckInitialDataTarget(
-    const Symbol &pointer, const SomeExpr &expr) {
+    const Symbol &pointer, const SomeExpr &expr, SourceName source) {
+  if (!evaluate::IsInitialDataTarget(expr)) {
+    Say(source,
+        "Pointer '%s' cannot be initialized with a reference to a designator with non-constant subscripts"_err_en_US,
+        pointer.name());
+    return;
+  }
+  if (pointer.Rank() != expr.Rank()) {
+    Say(source,
+        "Pointer '%s' of rank %d cannot be initialized with a target of different rank (%d)"_err_en_US,
+        pointer.name(), pointer.Rank(), expr.Rank());
+    return;
+  }
   if (auto base{evaluate::GetBaseObject(expr)}) {
     if (const Symbol * baseSym{base->symbol()}) {
       const Symbol &ultimate{baseSym->GetUltimate()};
-      if (!IsAllocatable(ultimate) && ultimate.Corank() == 0 &&
-          ultimate.attrs().HasAll({Attr::TARGET, Attr::SAVE}) &&
-          evaluate::IsInitialDataTarget(expr)) {
-        // TODO: check type compatibility
-        // TODO: check non-deferred type parameter values
-        // TODO: check contiguity if pointer is CONTIGUOUS
-        if (pointer.Rank() != expr.Rank()) {
-          Say(pointer.name(),
-              "Pointer '%s' initialized with target of different rank"_err_en_US);
-        }
+      if (IsAllocatable(ultimate)) {
+        Say(source,
+            "Pointer '%s' cannot be initialized with a reference to an allocatable '%s'"_err_en_US,
+            pointer.name(), ultimate.name());
+        return;
+      }
+      if (ultimate.Corank() > 0) {
+        Say(source,
+            "Pointer '%s' cannot be initialized with a reference to a coarray '%s'"_err_en_US,
+            pointer.name(), ultimate.name());
+        return;
+      }
+      if (!ultimate.attrs().test(Attr::TARGET)) {
+        Say(source,
+            "Pointer '%s' cannot be initialized with a reference to an object '%s' that lacks the TARGET attribute"_err_en_US,
+            pointer.name(), ultimate.name());
+        return;
+      }
+      if (!ultimate.attrs().test(Attr::SAVE)) {
+        Say(source,
+            "Pointer '%s' cannot be initialized with a reference to an object '%s' that lacks the SAVE attribute"_err_en_US,
+            pointer.name(), ultimate.name());
         return;
       }
     }
   }
-  Say(pointer.name(),
-      "Pointer '%s' initialized with invalid data target designator"_err_en_US);
+  // TODO: check type compatibility
+  // TODO: check non-deferred type parameter values
+  // TODO: check contiguity if pointer is CONTIGUOUS
 }
 
 void DeclarationVisitor::Initialization(const parser::Name &name,
@@ -4552,7 +4577,8 @@ void DeclarationVisitor::Initialization(const parser::Name &name,
             [&](const parser::InitialDataTarget &initExpr) {
               isPointer = true;
               if (MaybeExpr expr{EvaluateExpr(initExpr)}) {
-                CheckInitialDataTarget(ultimate, *expr);
+                CheckInitialDataTarget(
+                    ultimate, *expr, initExpr.value().source);
                 details->set_init(std::move(*expr));
               }
             },
index cd3fe61..1827227 100644 (file)
@@ -136,6 +136,7 @@ set(ERROR_TESTS
   omp-clause-validity01.f90
 #  omp-nested01.f90
   equivalence01.f90
+  init01.f90
 )
 
 # These test files have expected symbols in the source
diff --git a/flang/test/semantics/init01.f90 b/flang/test/semantics/init01.f90
new file mode 100644 (file)
index 0000000..a751437
--- /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.
+
+! Object pointer initializer error tests
+
+subroutine test(j)
+  integer, intent(in) :: j
+  real, allocatable, target, save :: x1
+  real, codimension[:], target, save :: x2
+  real, save :: x3
+  real, target :: x4
+  real, target, save :: x5(10)
+!ERROR: Pointer 'p1' cannot be initialized with a reference to an allocatable 'x1'
+  real, pointer :: p1 => x1
+!ERROR: Pointer 'p2' cannot be initialized with a reference to a coarray 'x2'
+  real, pointer :: p2 => x2
+!ERROR: Pointer 'p3' cannot be initialized with a reference to an object 'x3' that lacks the TARGET attribute
+  real, pointer :: p3 => x3
+!ERROR: Pointer 'p4' cannot be initialized with a reference to an object 'x4' that lacks the SAVE attribute
+  real, pointer :: p4 => x4
+!ERROR: Pointer 'p5' cannot be initialized with a reference to a designator with non-constant subscripts
+  real, pointer :: p5 => x5(j)
+!ERROR: Pointer 'p6' of rank 0 cannot be initialized with a target of different rank (1)
+  real, pointer :: p6 => x5
+
+!TODO: type incompatibility, non-deferred type parameter values, contiguity
+
+end subroutine test