[flang] Improve error messages

Original-commit: flang-compiler/f18@4046134512
Reviewed-on: https://github.com/flang-compiler/f18/pull/311
Tree-same-pre-rewrite: false
This commit is contained in:
peter klausler
2019-03-04 16:28:35 -08:00
parent 6acfa11fda
commit da2ebb6063
4 changed files with 101 additions and 85 deletions

View File

@@ -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);
}
}
}
}
}

View File

@@ -143,70 +143,84 @@ bool IsPureFunction(const Scope &scope) {
}
}
static bool HasPointerComponent(
static const Symbol *FindPointerComponent(
const Scope &scope, std::set<const Scope *> &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<ObjectEntityDetails>()}) {
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<const Scope *> 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;
}
}
}

View File

@@ -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<typename A> bool IsExternallyVisibleObject(const A &, const Scope &) {
return false; // default base case
template<typename A>
const Symbol *FindExternallyVisibleObject(const A &, const Scope &) {
return nullptr; // default base case
}
template<typename T>
bool IsExternallyVisibleObject(
const Symbol *FindExternallyVisibleObject(
const evaluate::Designator<T> &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<evaluate::CoarrayRef>(designator.u)) {
// Coindexed values are visible even if their image-local objects are not.
return std::holds_alternative<evaluate::CoarrayRef>(designator.u);
return designator.GetBaseObject().symbol();
} else {
return nullptr;
}
}
template<typename T>
bool IsExternallyVisibleObject(
const Symbol *FindExternallyVisibleObject(
const evaluate::Expr<T> &expr, const Scope &scope) {
return std::visit(
[&](const auto &x) { return IsExternallyVisibleObject(x, scope); },
[&](const auto &x) { return FindExternallyVisibleObject(x, scope); },
expr.u);
}
}

View File

@@ -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