From f937238d4220f18975601e5087931160620b7886 Mon Sep 17 00:00:00 2001 From: peter klausler Date: Thu, 27 Jun 2019 17:16:29 -0700 Subject: [PATCH] [flang] Better error reporting, with test Original-commit: flang-compiler/f18@85e8b64d3e86c3b8670790687ff1ea7f0857e41e Reviewed-on: https://github.com/flang-compiler/f18/pull/531 --- flang/lib/evaluate/fold.cc | 16 ++++++++--- flang/lib/semantics/resolve-names.cc | 56 ++++++++++++++++++++++++++---------- flang/test/semantics/CMakeLists.txt | 1 + flang/test/semantics/init01.f90 | 39 +++++++++++++++++++++++++ 4 files changed, 93 insertions(+), 19 deletions(-) create mode 100644 flang/test/semantics/init01.f90 diff --git a/flang/lib/evaluate/fold.cc b/flang/lib/evaluate/fold.cc index 87c131e..950cc9b 100644 --- a/flang/lib/evaluate/fold.cc +++ b/flang/lib/evaluate/fold.cc @@ -2291,10 +2291,20 @@ template bool IsInitialDataTarget(const A &) { return false; } template bool IsInitialDataTarget(const std::variant &); bool IsInitialDataTarget(const DataRef &); template bool IsInitialDataTarget(const Expr &); -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()); } diff --git a/flang/lib/semantics/resolve-names.cc b/flang/lib/semantics/resolve-names.cc index fe3b14c..8197dc3 100644 --- a/flang/lib/semantics/resolve-names.cc +++ b/flang/lib/semantics/resolve-names.cc @@ -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)); } }, diff --git a/flang/test/semantics/CMakeLists.txt b/flang/test/semantics/CMakeLists.txt index cd3fe61..1827227 100644 --- a/flang/test/semantics/CMakeLists.txt +++ b/flang/test/semantics/CMakeLists.txt @@ -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 index 0000000..a751437 --- /dev/null +++ b/flang/test/semantics/init01.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. + +! 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 -- 2.7.4