From da2ebb606320aac2343a68d515e1035695786cb3 Mon Sep 17 00:00:00 2001 From: peter klausler Date: Mon, 4 Mar 2019 16:28:35 -0800 Subject: [PATCH] [flang] Improve error messages Original-commit: flang-compiler/f18@40461345124b95de1f35828885e95d8bf0a235f1 Reviewed-on: https://github.com/flang-compiler/f18/pull/311 Tree-same-pre-rewrite: false --- flang/lib/semantics/expression.cc | 19 +++++-- flang/lib/semantics/tools.cc | 64 ++++++++++++++--------- flang/lib/semantics/tools.h | 32 +++++++----- flang/test/semantics/structconst03.f90 | 71 +++++++++++--------------- 4 files changed, 101 insertions(+), 85 deletions(-) diff --git a/flang/lib/semantics/expression.cc b/flang/lib/semantics/expression.cc index 735d08e00032..802a426924a1 100644 --- a/flang/lib/semantics/expression.cc +++ b/flang/lib/semantics/expression.cc @@ -1490,10 +1490,21 @@ static MaybeExpr AnalyzeExpr(ExpressionAnalysisContext &context, const auto &innermost{context.context().FindScope(expr.source)}; if (const auto *pureFunc{ semantics::FindPureFunctionContaining(&innermost)}) { - if (semantics::IsOrHasPointerComponent(*symbol) && - semantics::IsExternallyVisibleObject(*value, *pureFunc)) { - context.Say(expr.source, - "Externally visible object must not be associated with a pointer in a PURE function"_err_en_US); + if (const Symbol * + pointer{semantics::FindPointerComponent(*symbol)}) { + if (const Symbol * + object{semantics::FindExternallyVisibleObject( + *value, *pureFunc)}) { + if (auto *msg{context.Say(expr.source, + "Externally visible object '%s' must not be " + "associated with pointer component '%s' in a " + "PURE function"_err_en_US, + object->name().ToString().data(), + pointer->name().ToString().data())}) { + msg->Attach(object->name(), "Object declaration"_en_US) + .Attach(pointer->name(), "Pointer declaration"_en_US); + } + } } } } diff --git a/flang/lib/semantics/tools.cc b/flang/lib/semantics/tools.cc index 90d539b1bee4..9418c219370d 100644 --- a/flang/lib/semantics/tools.cc +++ b/flang/lib/semantics/tools.cc @@ -143,70 +143,84 @@ bool IsPureFunction(const Scope &scope) { } } -static bool HasPointerComponent( +static const Symbol *FindPointerComponent( const Scope &scope, std::set &visited) { if (scope.kind() != Scope::Kind::DerivedType) { - return false; + return nullptr; } if (!visited.insert(&scope).second) { - return false; + return nullptr; } + // If there's a top-level pointer component, return it for clearer error + // messaging. for (const auto &pair : scope) { const Symbol &symbol{*pair.second}; if (symbol.attrs().test(Attr::POINTER)) { - return true; + return &symbol; } + } + for (const auto &pair : scope) { + const Symbol &symbol{*pair.second}; if (const auto *details{symbol.detailsIf()}) { if (const DeclTypeSpec * type{details->type()}) { if (const DerivedTypeSpec * derived{type->AsDerived()}) { if (const Scope * nested{derived->scope()}) { - if (HasPointerComponent(*nested, visited)) { - return true; + if (const Symbol * + pointer{FindPointerComponent(*nested, visited)}) { + return pointer; } } } } } } - return false; + return nullptr; } -bool HasPointerComponent(const Scope &scope) { +const Symbol *FindPointerComponent(const Scope &scope) { std::set visited; - return HasPointerComponent(scope, visited); + return FindPointerComponent(scope, visited); } -bool HasPointerComponent(const DerivedTypeSpec &derived) { +const Symbol *FindPointerComponent(const DerivedTypeSpec &derived) { if (const Scope * scope{derived.scope()}) { - return HasPointerComponent(*scope); + return FindPointerComponent(*scope); } else { - return false; + return nullptr; } } -bool HasPointerComponent(const DeclTypeSpec &type) { +const Symbol *FindPointerComponent(const DeclTypeSpec &type) { if (const DerivedTypeSpec * derived{type.AsDerived()}) { - return HasPointerComponent(*derived); + return FindPointerComponent(*derived); } else { - return false; + return nullptr; } } -bool HasPointerComponent(const DeclTypeSpec *type) { - return type != nullptr && HasPointerComponent(*type); +const Symbol *FindPointerComponent(const DeclTypeSpec *type) { + return type ? FindPointerComponent(*type) : nullptr; } -bool IsOrHasPointerComponent(const Symbol &symbol) { - return symbol.attrs().test(Attr::POINTER) || - HasPointerComponent(symbol.GetType()); +const Symbol *FindPointerComponent(const Symbol &symbol) { + return symbol.attrs().test(Attr::POINTER) + ? &symbol + : FindPointerComponent(symbol.GetType()); } // C1594 specifies several ways by which an object might be globally visible. -bool IsExternallyVisibleObject(const Symbol &object, const Scope &scope) { - return IsUseAssociated(object, scope) || IsHostAssociated(object, scope) || +const Symbol *FindExternallyVisibleObject( + const Symbol &object, const Scope &scope) { + // TODO: Storage association with any object for which this predicate holds, + // once EQUIVALENCE is supported. + if (IsUseAssociated(object, scope) || IsHostAssociated(object, scope) || (IsPureFunction(scope) && IsPointerDummy(object)) || - (object.attrs().test(Attr::INTENT_IN) && IsDummy(object)) || - FindCommonBlockContaining(object) != nullptr; - // TODO: Storage association with any object for which this predicate holds + (object.attrs().test(Attr::INTENT_IN) && IsDummy(object))) { + return &object; + } else if (const Symbol * block{FindCommonBlockContaining(object)}) { + return block; + } else { + return nullptr; + } } } diff --git a/flang/lib/semantics/tools.h b/flang/lib/semantics/tools.h index f9b04bbbe580..49638bd4b36d 100644 --- a/flang/lib/semantics/tools.h +++ b/flang/lib/semantics/tools.h @@ -29,6 +29,10 @@ const Symbol *FindCommonBlockContaining(const Symbol &object); const Scope *FindProgramUnitContaining(const Scope &); const Scope *FindProgramUnitContaining(const Symbol &); const Scope *FindPureFunctionContaining(const Scope *); +const Symbol *FindPointerComponent(const Scope &); +const Symbol *FindPointerComponent(const DerivedTypeSpec &); +const Symbol *FindPointerComponent(const DeclTypeSpec &); +const Symbol *FindPointerComponent(const Symbol &); bool IsCommonBlockContaining(const Symbol &block, const Symbol &object); bool IsAncestor(const Scope *maybeAncestor, const Scope &maybeDescendent); @@ -39,35 +43,35 @@ bool IsPointerDummy(const Symbol &); bool IsFunction(const Symbol &); bool IsPureFunction(const Symbol &); bool IsPureFunction(const Scope &); -bool HasPointerComponent(const Scope &); -bool HasPointerComponent(const DerivedTypeSpec &); -bool HasPointerComponent(const DeclTypeSpec &); -bool IsOrHasPointerComponent(const Symbol &); // Determines whether an object might be visible outside a -// PURE function (C1594) -bool IsExternallyVisibleObject(const Symbol &, const Scope &); +// PURE function (C1594); returns a non-null Symbol pointer for +// diagnostic purposes if so. +const Symbol *FindExternallyVisibleObject(const Symbol &, const Scope &); -template bool IsExternallyVisibleObject(const A &, const Scope &) { - return false; // default base case +template +const Symbol *FindExternallyVisibleObject(const A &, const Scope &) { + return nullptr; // default base case } template -bool IsExternallyVisibleObject( +const Symbol *FindExternallyVisibleObject( const evaluate::Designator &designator, const Scope &scope) { if (const Symbol * symbol{designator.GetBaseObject().symbol()}) { - return IsExternallyVisibleObject(*symbol, scope); - } else { + return FindExternallyVisibleObject(*symbol, scope); + } else if (std::holds_alternative(designator.u)) { // Coindexed values are visible even if their image-local objects are not. - return std::holds_alternative(designator.u); + return designator.GetBaseObject().symbol(); + } else { + return nullptr; } } template -bool IsExternallyVisibleObject( +const Symbol *FindExternallyVisibleObject( const evaluate::Expr &expr, const Scope &scope) { return std::visit( - [&](const auto &x) { return IsExternallyVisibleObject(x, scope); }, + [&](const auto &x) { return FindExternallyVisibleObject(x, scope); }, expr.u); } } diff --git a/flang/test/semantics/structconst03.f90 b/flang/test/semantics/structconst03.f90 index c518382b676c..8166cb1da07d 100644 --- a/flang/test/semantics/structconst03.f90 +++ b/flang/test/semantics/structconst03.f90 @@ -23,11 +23,11 @@ module module1 use usefrom implicit none type :: has_pointer1 - real, pointer :: p - type(has_pointer1), allocatable :: link1 + real, pointer :: ptop + type(has_pointer1), allocatable :: link1 ! don't loop during analysis end type has_pointer1 type :: has_pointer2 - type(has_pointer1) :: p + type(has_pointer1) :: pnested type(has_pointer2), allocatable :: link2 end type has_pointer2 type, extends(has_pointer2) :: has_pointer3 @@ -35,7 +35,7 @@ module module1 end type has_pointer3 type :: t1(k) integer, kind :: k - real, pointer :: p + real, pointer :: pt1 type(t1(k)), allocatable :: link end type t1 type :: t2(k) @@ -54,11 +54,9 @@ module module1 type(t4(k)), allocatable :: link end type t4 real :: modulevar1 - real :: commonvar1 - type(has_pointer1) :: modulevar2, commonvar2 - type(has_pointer2) :: modulevar3, commonvar3 - type(has_pointer3) :: modulevar4, commonvar4 - common /cblock/ commonvar1 + type(has_pointer1) :: modulevar2 + type(has_pointer2) :: modulevar3 + type(has_pointer3) :: modulevar4 contains @@ -72,35 +70,31 @@ module module1 real, intent(inout) :: dummy2 real, pointer :: dummy3 real, intent(inout) :: dummy4[*] + real :: commonvar1 + common /cblock/ commonvar1 pf1 = 0. x1 = t1(0)(local1) - !ERROR: Externally visible object must not be associated with a pointer in a PURE function + !ERROR: Externally visible object 'usedfrom1' must not be associated with pointer component 'pt1' in a PURE function x1 = t1(0)(usedfrom1) - !ERROR: Externally visible object must not be associated with a pointer in a PURE function + !ERROR: Externally visible object 'modulevar1' must not be associated with pointer component 'pt1' in a PURE function x1 = t1(0)(modulevar1) - !ERROR: Externally visible object must not be associated with a pointer in a PURE function + !ERROR: Externally visible object 'cblock' must not be associated with pointer component 'pt1' in a PURE function x1 = t1(0)(commonvar1) - !ERROR: Externally visible object must not be associated with a pointer in a PURE function + !ERROR: Externally visible object 'dummy1' must not be associated with pointer component 'pt1' in a PURE function x1 = t1(0)(dummy1) x1 = t1(0)(dummy2) - !ERROR: Externally visible object must not be associated with a pointer in a PURE function + !ERROR: Externally visible object 'dummy3' must not be associated with pointer component 'pt1' in a PURE function x1 = t1(0)(dummy3) ! TODO when semantics handles coindexing: ! TODO !ERROR: Externally visible object must not be associated with a pointer in a PURE function ! TODO x1 = t1(0)(dummy4[0]) x1 = t1(0)(dummy4) - !ERROR: Externally visible object must not be associated with a pointer in a PURE function + !ERROR: Externally visible object 'modulevar2' must not be associated with pointer component 'ptop' in a PURE function x2 = t2(0)(modulevar2) - !ERROR: Externally visible object must not be associated with a pointer in a PURE function - x2 = t2(0)(commonvar2) - !ERROR: Externally visible object must not be associated with a pointer in a PURE function + !ERROR: Externally visible object 'modulevar3' must not be associated with pointer component 'ptop' in a PURE function x3 = t3(0)(modulevar3) - !ERROR: Externally visible object must not be associated with a pointer in a PURE function - x3 = t3(0)(commonvar3) - !ERROR: Externally visible object must not be associated with a pointer in a PURE function + !ERROR: Externally visible object 'modulevar4' must not be associated with pointer component 'ptop' in a PURE function x4 = t4(0)(modulevar4) - !ERROR: Externally visible object must not be associated with a pointer in a PURE function - x4 = t4(0)(commonvar4) contains subroutine subr(dummy1a, dummy2a, dummy3a, dummy4a) real :: local1a @@ -113,37 +107,31 @@ module module1 real, pointer :: dummy3a real, intent(inout) :: dummy4a[*] x1a = t1(0)(local1a) - !ERROR: Externally visible object must not be associated with a pointer in a PURE function + !ERROR: Externally visible object 'usedfrom1' must not be associated with pointer component 'pt1' in a PURE function x1a = t1(0)(usedfrom1) - !ERROR: Externally visible object must not be associated with a pointer in a PURE function + !ERROR: Externally visible object 'modulevar1' must not be associated with pointer component 'pt1' in a PURE function x1a = t1(0)(modulevar1) - !ERROR: Externally visible object must not be associated with a pointer in a PURE function + !ERROR: Externally visible object 'cblock' must not be associated with pointer component 'pt1' in a PURE function x1a = t1(0)(commonvar1) - !ERROR: Externally visible object must not be associated with a pointer in a PURE function + !ERROR: Externally visible object 'dummy1' must not be associated with pointer component 'pt1' in a PURE function x1a = t1(0)(dummy1) - !ERROR: Externally visible object must not be associated with a pointer in a PURE function + !ERROR: Externally visible object 'dummy1a' must not be associated with pointer component 'pt1' in a PURE function x1a = t1(0)(dummy1a) x1a = t1(0)(dummy2a) - !ERROR: Externally visible object must not be associated with a pointer in a PURE function + !ERROR: Externally visible object 'dummy3' must not be associated with pointer component 'pt1' in a PURE function x1a = t1(0)(dummy3) - !ERROR: Externally visible object must not be associated with a pointer in a PURE function + !ERROR: Externally visible object 'dummy3a' must not be associated with pointer component 'pt1' in a PURE function x1a = t1(0)(dummy3a) ! TODO when semantics handles coindexing: ! TODO !ERROR: Externally visible object must not be associated with a pointer in a PURE function ! TODO x1a = t1(0)(dummy4a[0]) x1a = t1(0)(dummy4a) - !ERROR: Externally visible object must not be associated with a pointer in a PURE function + !ERROR: Externally visible object 'modulevar2' must not be associated with pointer component 'ptop' in a PURE function x2a = t2(0)(modulevar2) - !ERROR: Externally visible object must not be associated with a pointer in a PURE function - x2a = t2(0)(commonvar2) - !ERROR: Externally visible object must not be associated with a pointer in a PURE function + !ERROR: Externally visible object 'modulevar3' must not be associated with pointer component 'ptop' in a PURE function x3a = t3(0)(modulevar3) - !ERROR: Externally visible object must not be associated with a pointer in a PURE function - x3a = t3(0)(commonvar3) - !ERROR: Externally visible object must not be associated with a pointer in a PURE function + !ERROR: Externally visible object 'modulevar4' must not be associated with pointer component 'ptop' in a PURE function x4a = t4(0)(modulevar4) - !ERROR: Externally visible object must not be associated with a pointer in a PURE function - x4a = t4(0)(commonvar4) end subroutine subr end function pf1 @@ -157,6 +145,8 @@ module module1 real, intent(inout) :: dummy2 real, pointer :: dummy3 real, intent(inout) :: dummy4[*] + real :: commonvar1 + common /cblock/ commonvar1 ipf1 = 0. x1 = t1(0)(local1) x1 = t1(0)(usedfrom1) @@ -169,10 +159,7 @@ module module1 ! TODO x1 = t1(0)(dummy4[0]) x1 = t1(0)(dummy4) x2 = t2(0)(modulevar2) - x2 = t2(0)(commonvar2) x3 = t3(0)(modulevar3) - x3 = t3(0)(commonvar3) x4 = t4(0)(modulevar4) - x4 = t4(0)(commonvar4) end function ipf1 end module module1