[flang-commits] [flang] [flang] Warn about undefined function results (PR #99533)
via flang-commits
flang-commits at lists.llvm.org
Thu Jul 18 10:38:44 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-semantics
Author: Peter Klausler (klausler)
<details>
<summary>Changes</summary>
When the result of a function never appears in a variable definition context, emit a warning.
If the function has multiple result variables due to alternate ENTRY statements, any definition will suffice.
The implementation of this check is tied to the general variable definability checking utility in semantics. Every variable definition context uses it to ensure that no undefinable variable is being defined. A set of defined variables is maintained in the SemanticsContext and, when the warning is enabled and no fatal error has been reported, the scope tree is traversed and all the function subprograms' results are tested for membership in that set.
---
Full diff: https://github.com/llvm/llvm-project/pull/99533.diff
11 Files Affected:
- (modified) flang/include/flang/Common/Fortran-features.h (+2-1)
- (modified) flang/include/flang/Semantics/semantics.h (+4)
- (modified) flang/include/flang/Semantics/tools.h (-1)
- (modified) flang/lib/Semantics/check-purity.cpp (+1-1)
- (modified) flang/lib/Semantics/definable.cpp (+4)
- (modified) flang/lib/Semantics/semantics.cpp (+39)
- (modified) flang/test/Evaluate/folding08.f90 (+5-3)
- (modified) flang/test/Semantics/call02.f90 (+2)
- (modified) flang/test/Semantics/call05.f90 (+2)
- (modified) flang/test/Semantics/contiguous01.f90 (+2)
- (modified) flang/test/Semantics/resolve53.f90 (+6)
``````````diff
diff --git a/flang/include/flang/Common/Fortran-features.h b/flang/include/flang/Common/Fortran-features.h
index 7346d702b073d..938da08e19d6b 100644
--- a/flang/include/flang/Common/Fortran-features.h
+++ b/flang/include/flang/Common/Fortran-features.h
@@ -70,7 +70,7 @@ ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable,
IgnoredIntrinsicFunctionType, PreviousScalarUse,
RedeclaredInaccessibleComponent, ImplicitShared, IndexVarRedefinition,
IncompatibleImplicitInterfaces, BadTypeForTarget,
- VectorSubscriptFinalization)
+ VectorSubscriptFinalization, UndefinedFunctionResult)
using LanguageFeatures = EnumSet<LanguageFeature, LanguageFeature_enumSize>;
using UsageWarnings = EnumSet<UsageWarning, UsageWarning_enumSize>;
@@ -144,6 +144,7 @@ class LanguageFeatureControl {
warnUsage_.set(UsageWarning::IncompatibleImplicitInterfaces);
warnUsage_.set(UsageWarning::BadTypeForTarget);
warnUsage_.set(UsageWarning::VectorSubscriptFinalization);
+ warnUsage_.set(UsageWarning::UndefinedFunctionResult);
}
LanguageFeatureControl(const LanguageFeatureControl &) = default;
diff --git a/flang/include/flang/Semantics/semantics.h b/flang/include/flang/Semantics/semantics.h
index 3ee71fe485524..ec8d12b0f9865 100644
--- a/flang/include/flang/Semantics/semantics.h
+++ b/flang/include/flang/Semantics/semantics.h
@@ -254,6 +254,9 @@ class SemanticsContext {
// behavior.
CommonBlockList GetCommonBlocks() const;
+ void NoteDefinedSymbol(const Symbol &);
+ bool IsSymbolDefined(const Symbol &) const;
+
private:
struct ScopeIndexComparator {
bool operator()(parser::CharBlock, parser::CharBlock) const;
@@ -303,6 +306,7 @@ class SemanticsContext {
std::unique_ptr<CommonBlockMap> commonBlockMap_;
ModuleDependences moduleDependences_;
std::map<const Symbol *, SourceName> moduleFileOutputRenamings_;
+ UnorderedSymbolSet isDefined_;
};
class Semantics {
diff --git a/flang/include/flang/Semantics/tools.h b/flang/include/flang/Semantics/tools.h
index 0b5308d9242de..2654804307826 100644
--- a/flang/include/flang/Semantics/tools.h
+++ b/flang/include/flang/Semantics/tools.h
@@ -52,7 +52,6 @@ const Symbol *FindPointerComponent(const DeclTypeSpec &);
const Symbol *FindPointerComponent(const Symbol &);
const Symbol *FindInterface(const Symbol &);
const Symbol *FindSubprogram(const Symbol &);
-const Symbol *FindFunctionResult(const Symbol &);
const Symbol *FindOverriddenBinding(
const Symbol &, bool &isInaccessibleDeferred);
const Symbol *FindGlobal(const Symbol &);
diff --git a/flang/lib/Semantics/check-purity.cpp b/flang/lib/Semantics/check-purity.cpp
index 55a9a2f107388..1046f363e9485 100644
--- a/flang/lib/Semantics/check-purity.cpp
+++ b/flang/lib/Semantics/check-purity.cpp
@@ -31,7 +31,7 @@ void PurityChecker::Enter(const parser::FunctionSubprogram &func) {
stmt.source, std::get<std::list<parser::PrefixSpec>>(stmt.statement.t));
}
-void PurityChecker::Leave(const parser::FunctionSubprogram &) { Left(); }
+void PurityChecker::Leave(const parser::FunctionSubprogram &func) { Left(); }
bool PurityChecker::InPureSubprogram() const {
return pureDepth_ >= 0 && depth_ >= pureDepth_;
diff --git a/flang/lib/Semantics/definable.cpp b/flang/lib/Semantics/definable.cpp
index 96af46abd6180..7def2f5dbb398 100644
--- a/flang/lib/Semantics/definable.cpp
+++ b/flang/lib/Semantics/definable.cpp
@@ -127,6 +127,10 @@ static std::optional<parser::Message> WhyNotDefinableBase(parser::CharBlock at,
(!IsPointer(ultimate) || (isWholeSymbol && isPointerDefinition))) {
return BlameSymbol(
at, "'%s' is an INTENT(IN) dummy argument"_en_US, original);
+ } else if (acceptAllocatable) {
+ // allocating a function result doesn't count as a def'n
+ } else {
+ scope.context().NoteDefinedSymbol(ultimate);
}
if (const Scope * pure{FindPureProcedureContaining(scope)}) {
// Additional checking for pure subprograms.
diff --git a/flang/lib/Semantics/semantics.cpp b/flang/lib/Semantics/semantics.cpp
index c09734e5676f3..16f5b53b07be6 100644
--- a/flang/lib/Semantics/semantics.cpp
+++ b/flang/lib/Semantics/semantics.cpp
@@ -168,6 +168,27 @@ using StatementSemanticsPass2 = SemanticsVisitor<AllocateChecker,
ReturnStmtChecker, SelectRankConstructChecker, SelectTypeChecker,
StopChecker>;
+static void WarnUndefinedFunctionResult(
+ SemanticsContext &context, const Scope &scope) {
+ if (const Symbol * symbol{scope.symbol()}) {
+ if (const auto *subp{symbol->detailsIf<SubprogramDetails>()}) {
+ if (!subp->isInterface() && !subp->stmtFunction()) {
+ if (const Symbol * result{FindFunctionResult(*symbol)}) {
+ if (!context.IsSymbolDefined(*result)) {
+ context.Say(
+ symbol->name(), "Function result is never defined"_warn_en_US);
+ }
+ }
+ }
+ }
+ }
+ if (!scope.IsModuleFile()) {
+ for (const Scope &child : scope.children()) {
+ WarnUndefinedFunctionResult(context, child);
+ }
+ }
+}
+
static bool PerformStatementSemantics(
SemanticsContext &context, parser::Program &program) {
ResolveNames(context, program, context.globalScope());
@@ -187,6 +208,9 @@ static bool PerformStatementSemantics(
SemanticsVisitor<CUDAChecker>{context}.Walk(program);
}
if (!context.AnyFatalError()) {
+ if (context.ShouldWarn(common::UsageWarning::UndefinedFunctionResult)) {
+ WarnUndefinedFunctionResult(context, context.globalScope());
+ }
pass2.CompileDataInitializationsIntoInitializers();
}
return !context.AnyFatalError();
@@ -712,4 +736,19 @@ CommonBlockList SemanticsContext::GetCommonBlocks() const {
return {};
}
+void SemanticsContext::NoteDefinedSymbol(const Symbol &symbol) {
+ isDefined_.insert(symbol);
+ if (IsFunctionResult(symbol)) { // FUNCTION or ENTRY
+ if (const Symbol * func{symbol.owner().symbol()}) {
+ if (const Symbol * result{FindFunctionResult(*func)}) {
+ isDefined_.insert(*result);
+ }
+ }
+ }
+}
+
+bool SemanticsContext::IsSymbolDefined(const Symbol &symbol) const {
+ return isDefined_.find(symbol) != isDefined_.end();
+}
+
} // namespace Fortran::semantics
diff --git a/flang/test/Evaluate/folding08.f90 b/flang/test/Evaluate/folding08.f90
index 1b2e5605e85d4..53603474fe1c8 100644
--- a/flang/test/Evaluate/folding08.f90
+++ b/flang/test/Evaluate/folding08.f90
@@ -11,6 +11,11 @@ module m
end type
type(t) :: ta(0:2)
character(len=2) :: ca(-1:1)
+ interface
+ function foo()
+ real :: foo(2:3,4:6)
+ end function
+ end interface
integer, parameter :: lbtadim = lbound(ta,1)
logical, parameter :: test_lbtadim = lbtadim == 0
integer, parameter :: ubtadim = ubound(ta,1)
@@ -47,9 +52,6 @@ module m
logical, parameter :: test_lb_empty_dim = lbound(empty, 1) == 1
logical, parameter :: test_ub_empty_dim = ubound(empty, 1) == 0
contains
- function foo()
- real :: foo(2:3,4:6)
- end function
subroutine test(n1,a1,a2)
integer, intent(in) :: n1
real, intent(in) :: a1(1:n1), a2(0:*)
diff --git a/flang/test/Semantics/call02.f90 b/flang/test/Semantics/call02.f90
index bc3dd6075969c..0ec5530f98089 100644
--- a/flang/test/Semantics/call02.f90
+++ b/flang/test/Semantics/call02.f90
@@ -72,6 +72,7 @@ subroutine callme(f)
contains
elemental real function elem03(x)
real, value :: x
+ elem03 = 0.
end function
subroutine test
intrinsic :: cos
@@ -87,6 +88,7 @@ subroutine test
contains
elemental real function elem04(x)
real, value :: x
+ elem04 = 0.
end function
end subroutine
end module
diff --git a/flang/test/Semantics/call05.f90 b/flang/test/Semantics/call05.f90
index 8a4386e28e2bc..a06fe4f196c8c 100644
--- a/flang/test/Semantics/call05.f90
+++ b/flang/test/Semantics/call05.f90
@@ -155,11 +155,13 @@ subroutine smb(b)
function return_deferred_length_ptr()
character(len=:), pointer :: return_deferred_length_ptr
+ return_deferred_length_ptr => p2
end function
function return_explicit_length_ptr(n)
integer :: n
character(len=n), pointer :: return_explicit_length_ptr
+ return_explicit_length_ptr => p2(1:n)
end function
subroutine test()
diff --git a/flang/test/Semantics/contiguous01.f90 b/flang/test/Semantics/contiguous01.f90
index 0f086624a20ae..89382775261b8 100644
--- a/flang/test/Semantics/contiguous01.f90
+++ b/flang/test/Semantics/contiguous01.f90
@@ -30,8 +30,10 @@ function func(ashape,arank) result(r)
contiguous r2
!PORTABILITY: CONTIGUOUS entity 'e' should be an array pointer, assumed-shape, or assumed-rank
entry e() result(r2)
+ r2 = 0
end
function fp()
real, pointer, contiguous :: fp(:) ! ok
+ nullify(fp)
end
end
diff --git a/flang/test/Semantics/resolve53.f90 b/flang/test/Semantics/resolve53.f90
index 1b0f3f8f8e385..0ab4b7c4d303e 100644
--- a/flang/test/Semantics/resolve53.f90
+++ b/flang/test/Semantics/resolve53.f90
@@ -227,14 +227,17 @@ module m14
real function f1(x, y)
real, intent(in) :: x
logical, intent(in) :: y
+ f1 = 0.
end
integer function f2(x, y)
integer, intent(in) :: x
logical, intent(in) :: y
+ f2 = 0.
end
real function f3(x, y)
real, value :: x
logical, value :: y
+ f3 = 0.
end
end module
@@ -447,12 +450,15 @@ module m19
contains
integer function f1(i)
integer, intent(in) :: i
+ f1 = 0
end
integer function f2(i, j)
integer, value :: i, j
+ f2 = 0
end
integer function f3(i, j)
integer, intent(in) :: i, j
+ f3 = 0
end
end
``````````
</details>
https://github.com/llvm/llvm-project/pull/99533
More information about the flang-commits
mailing list