Skip to content

Commit 900b32a

Browse files
committed
[flang] Add options -W[no-]unused-dummy-argument and -W[no-]unused-variable
1 parent 2077d40 commit 900b32a

File tree

14 files changed

+311
-6
lines changed

14 files changed

+311
-6
lines changed

flang/include/flang/Semantics/symbol.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,10 +293,13 @@ class EntityDetails : public WithBindName {
293293
void set_isDummy(bool value = true) { isDummy_ = value; }
294294
bool isFuncResult() const { return isFuncResult_; }
295295
void set_funcResult(bool x) { isFuncResult_ = x; }
296+
bool isUsed() const { return isUsed_; }
297+
void set_isUsed() { isUsed_ = true; }
296298

297299
private:
298300
bool isDummy_{false};
299301
bool isFuncResult_{false};
302+
bool isUsed_{false};
300303
const DeclTypeSpec *type_{nullptr};
301304
friend llvm::raw_ostream &operator<<(
302305
llvm::raw_ostream &, const EntityDetails &);

flang/include/flang/Support/Fortran-features.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ ENUM_CLASS(LanguageFeature, BackslashEscapes, OldDebugLines,
5454
PolymorphicActualAllocatableOrPointerToMonomorphicDummy, RelaxedPureDummy,
5555
UndefinableAsynchronousOrVolatileActual, AutomaticInMainProgram, PrintCptr,
5656
SavedLocalInSpecExpr, PrintNamelist, AssumedRankPassedToNonAssumedRank,
57-
IgnoreIrrelevantAttributes, Unsigned)
57+
IgnoreIrrelevantAttributes, Unsigned, UnusedDummyArgument, UnusedVariable)
5858

5959
// Portability and suspicious usage warnings
6060
ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable,

flang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -932,10 +932,24 @@ static bool parseDiagArgs(CompilerInvocation &res, llvm::opt::ArgList &args,
932932
for (const auto &wArg : wArgs) {
933933
if (wArg == "error") {
934934
res.setWarnAsErr(true);
935+
} else if (wArg == "unused-dummy-argument") {
936+
res.getFrontendOpts().features.Enable(
937+
Fortran::common::LanguageFeature::UnusedDummyArgument);
938+
} else if (wArg == "no-unused-dummy-argument") {
939+
res.getFrontendOpts().features.Enable(
940+
Fortran::common::LanguageFeature::UnusedDummyArgument, false);
941+
} else if (wArg == "unused-variable") {
942+
res.getFrontendOpts().features.Enable(
943+
Fortran::common::LanguageFeature::UnusedVariable);
944+
} else if (wArg == "no-unused-variable") {
945+
res.getFrontendOpts().features.Enable(
946+
Fortran::common::LanguageFeature::UnusedVariable, false);
935947
} else {
936-
const unsigned diagID =
937-
diags.getCustomDiagID(clang::DiagnosticsEngine::Error,
938-
"Only `-Werror` is supported currently.");
948+
const unsigned diagID = diags.getCustomDiagID(
949+
clang::DiagnosticsEngine::Error,
950+
"Only `-Werror`, `-W[no]unused-dummy-argument` "
951+
"and `-W[no]unused-variable` are supported "
952+
"currently.");
939953
diags.Report(diagID);
940954
}
941955
}

flang/lib/Semantics/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ add_flang_library(FortranSemantics
2626
check-select-rank.cpp
2727
check-select-type.cpp
2828
check-stop.cpp
29+
check-warning.cpp
2930
compute-offsets.cpp
3031
data-to-inits.cpp
3132
definable.cpp

flang/lib/Semantics/check-warning.cpp

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
//===-- lib/Semantics/check-warning.cpp
2+
//-----------------------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#include "check-warning.h"
11+
#include "flang/Semantics/tools.h"
12+
13+
namespace Fortran::semantics {
14+
15+
void WarningChecker::Enter(const parser::FunctionStmt &stmt) {
16+
if (Wunused_dummy_argument) {
17+
for (const auto &dummyName : std::get<std::list<parser::Name>>(stmt.t)) {
18+
if (auto *detail = dummyName.symbol->detailsIf<ObjectEntityDetails>()) {
19+
const Symbol *ownerSymbol{dummyName.symbol->owner().symbol()};
20+
const auto *ownerSubp{ownerSymbol->detailsIf<SubprogramDetails>()};
21+
bool inInterface{ownerSubp && ownerSubp->isInterface()};
22+
23+
if (!inInterface && !detail->isUsed()) {
24+
context_.Say(dummyName.symbol->GetUltimate().name(),
25+
"Unused dummy argument '%s' [-Wunused-dummy-argument]"_warn_en_US,
26+
dummyName.ToString());
27+
}
28+
}
29+
}
30+
}
31+
if (Wunused_variable) {
32+
if (const auto &suffix{std::get<std::optional<parser::Suffix>>(stmt.t)}) {
33+
if (suffix->resultName.has_value()) {
34+
if (auto *detail =
35+
suffix->resultName->symbol->detailsIf<ObjectEntityDetails>()) {
36+
const Symbol *ownerSymbol{
37+
suffix->resultName->symbol->owner().symbol()};
38+
const auto *ownerSubp{ownerSymbol->detailsIf<SubprogramDetails>()};
39+
bool inInterface{ownerSubp && ownerSubp->isInterface()};
40+
if (!inInterface && !detail->isUsed()) {
41+
context_.Say(suffix->resultName->source,
42+
"Unused variable '%s' [-Wunused-variable]"_warn_en_US,
43+
suffix->resultName->ToString());
44+
}
45+
}
46+
}
47+
}
48+
}
49+
}
50+
51+
void WarningChecker::Enter(const parser::SubroutineStmt &stmt) {
52+
if (!Wunused_dummy_argument) {
53+
return;
54+
}
55+
for (const auto &dummyArg : std::get<std::list<parser::DummyArg>>(stmt.t)) {
56+
if (const auto *dummyName{std::get_if<parser::Name>(&dummyArg.u)}) {
57+
if (const auto *symbol = dummyName->symbol) {
58+
59+
const Symbol *ownerSymbol{symbol->owner().symbol()};
60+
const auto *ownerSubp{ownerSymbol->detailsIf<SubprogramDetails>()};
61+
bool inInterface{ownerSubp && ownerSubp->isInterface()};
62+
63+
if (auto *detail = symbol->detailsIf<ObjectEntityDetails>()) {
64+
if (!inInterface && !detail->isUsed()) {
65+
context_.Say(symbol->GetUltimate().name(),
66+
"Unused dummy argument '%s' [-Wunused-dummy-argument]"_warn_en_US,
67+
dummyName->ToString());
68+
}
69+
}
70+
}
71+
}
72+
}
73+
}
74+
75+
void WarningChecker::Enter(const parser::EntityDecl &decl) {
76+
if (!Wunused_variable) {
77+
return;
78+
}
79+
80+
const auto &name{std::get<parser::ObjectName>(decl.t)};
81+
if (const auto *symbol = name.symbol) {
82+
const Symbol *ownerSymbol{symbol->owner().symbol()};
83+
const auto *ownerSubp{ownerSymbol->detailsIf<SubprogramDetails>()};
84+
bool inInterface{ownerSubp && ownerSubp->isInterface()};
85+
bool inModule{ownerSymbol && ownerSymbol->scope() &&
86+
ownerSymbol->scope()->IsModule()};
87+
88+
if (auto *detail = symbol->detailsIf<ObjectEntityDetails>()) {
89+
if (!inInterface && !inModule && !detail->isDummy() &&
90+
!detail->isFuncResult() && !detail->isUsed()) {
91+
context_.Say(symbol->name(),
92+
"Unused variable '%s' [-Wunused-variable]"_warn_en_US,
93+
name.ToString());
94+
}
95+
}
96+
}
97+
}
98+
99+
} // namespace Fortran::semantics

flang/lib/Semantics/check-warning.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//===-- lib/Semantics/check-warning.h ---------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef FORTRAN_SEMANTICS_CHECK_WARNING_H_
10+
#define FORTRAN_SEMANTICS_CHECK_WARNING_H_
11+
12+
#include "flang/Semantics/semantics.h"
13+
14+
namespace Fortran::parser {
15+
struct FunctionStmt;
16+
struct InterfaceBody;
17+
struct SubroutineStmt;
18+
struct EntityDecl;
19+
} // namespace Fortran::parser
20+
21+
namespace Fortran::semantics {
22+
23+
// Perform semantic checks on DummyArg on Function and Subroutine
24+
// TODO: Add checks for future warning options
25+
class WarningChecker : public virtual BaseChecker {
26+
public:
27+
explicit WarningChecker(SemanticsContext &context) : context_{context} {}
28+
void Enter(const parser::FunctionStmt &);
29+
void Enter(const parser::SubroutineStmt &);
30+
void Enter(const parser::EntityDecl &);
31+
32+
private:
33+
SemanticsContext &context_;
34+
const bool Wunused_dummy_argument = context_.languageFeatures().IsEnabled(
35+
common::LanguageFeature::UnusedDummyArgument);
36+
const bool Wunused_variable = context_.languageFeatures().IsEnabled(
37+
common::LanguageFeature::UnusedVariable);
38+
};
39+
} // namespace Fortran::semantics
40+
#endif

flang/lib/Semantics/expression.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,13 @@ MaybeExpr ExpressionAnalyzer::FixMisparsedSubstring(
590590
}
591591

592592
MaybeExpr ExpressionAnalyzer::Analyze(const parser::Designator &d) {
593+
const auto &name = GetFirstName(d);
594+
if (name.symbol) {
595+
if (auto *detail =
596+
name.symbol->detailsIf<Fortran::semantics::ObjectEntityDetails>()) {
597+
detail->set_isUsed();
598+
}
599+
}
593600
auto restorer{GetContextualMessages().SetLocation(d.source)};
594601
if (auto substringInquiry{FixMisparsedSubstring(d)}) {
595602
return substringInquiry;

flang/lib/Semantics/resolve-names.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6693,6 +6693,11 @@ bool DeclarationVisitor::Pre(const parser::CommonBlockObject &) {
66936693
void DeclarationVisitor::Post(const parser::CommonBlockObject &x) {
66946694
const auto &name{std::get<parser::Name>(x.t)};
66956695
DeclareObjectEntity(name);
6696+
if (name.symbol) {
6697+
if (auto *detail{name.symbol->detailsIf<ObjectEntityDetails>()}) {
6698+
detail->set_isUsed();
6699+
}
6700+
}
66966701
auto pair{specPartState_.commonBlockObjects.insert(name.source)};
66976702
if (!pair.second) {
66986703
const SourceName &prev{*pair.first};

flang/lib/Semantics/semantics.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "check-select-rank.h"
3333
#include "check-select-type.h"
3434
#include "check-stop.h"
35+
#include "check-warning.h"
3536
#include "compute-offsets.h"
3637
#include "mod-file.h"
3738
#include "resolve-labels.h"
@@ -202,6 +203,7 @@ using StatementSemanticsPass2 = SemanticsVisitor<AllocateChecker,
202203
MiscChecker, NamelistChecker, NullifyChecker, PurityChecker,
203204
ReturnStmtChecker, SelectRankConstructChecker, SelectTypeChecker,
204205
StopChecker>;
206+
using StatementSemanticsPass3 = SemanticsVisitor<WarningChecker>;
205207

206208
static bool PerformStatementSemantics(
207209
SemanticsContext &context, parser::Program &program) {
@@ -221,6 +223,12 @@ static bool PerformStatementSemantics(
221223
if (context.languageFeatures().IsEnabled(common::LanguageFeature::CUDA)) {
222224
SemanticsVisitor<CUDAChecker>{context}.Walk(program);
223225
}
226+
if (context.languageFeatures().IsEnabled(
227+
common::LanguageFeature::UnusedDummyArgument) ||
228+
context.languageFeatures().IsEnabled(
229+
common::LanguageFeature::UnusedVariable)) {
230+
StatementSemanticsPass3{context}.Walk(program);
231+
}
224232
if (!context.messages().AnyFatalError()) {
225233
WarnUndefinedFunctionResult(context, context.globalScope());
226234
}

flang/lib/Support/Fortran-features.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ LanguageFeatureControl::LanguageFeatureControl() {
3131
disable_.set(LanguageFeature::LogicalAbbreviations);
3232
disable_.set(LanguageFeature::XOROperator);
3333
disable_.set(LanguageFeature::OldStyleParameter);
34+
disable_.set(LanguageFeature::UnusedDummyArgument);
35+
disable_.set(LanguageFeature::UnusedVariable);
3436
// Possibly an accidental "feature" of nvfortran.
3537
disable_.set(LanguageFeature::AssumedRankPassedToNonAssumedRank);
3638
// These warnings are enabled by default, but only because they used

flang/test/Driver/werror-wrong.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
! RUN: not %flang_fc1 -fsyntax-only -Wall %s 2>&1 | FileCheck %s --check-prefix=WRONG
44
! RUN: not %flang_fc1 -fsyntax-only -WX %s 2>&1 | FileCheck %s --check-prefix=WRONG
55

6-
! WRONG: Only `-Werror` is supported currently.
6+
! WRONG: Only `-Werror`, `-W[no]unused-dummy-argument` and `-W[no]unused-variable` are supported currently.

flang/test/Driver/wextra-ok.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
! RUN: not %flang -std=f2018 -Wblah -Wextra %s -c 2>&1 | FileCheck %s --check-prefix=WRONG
66

77
! CHECK-OK: the warning option '-Wextra' is not supported
8-
! WRONG: Only `-Werror` is supported currently.
8+
! WRONG: Only `-Werror`, `-W[no]unused-dummy-argument` and `-W[no]unused-variable` are supported currently.
99

1010
program wextra_ok
1111
end program wextra_ok
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
! RUN: %flang_fc1 -Wunused-dummy-argument %s 2>&1 | FileCheck %s
2+
! RUN: not %flang_fc1 -Wunused-dummy-argument -Werror %s
3+
! RUN: %flang_fc1 -Wno-unused-dummy-argument %s 2>&1 | FileCheck %s --check-prefix=NOWARN
4+
5+
! CHECK: warning: Unused dummy argument 'a4' [-Wunused-dummy-argument]
6+
! CHECK: warning: Unused dummy argument 'b4' [-Wunused-dummy-argument]
7+
! CHECK: warning: Unused dummy argument 'a6' [-Wunused-dummy-argument]
8+
! CHECK: warning: Unused dummy argument 'b6' [-Wunused-dummy-argument]
9+
10+
! NOWARN-NOT: warning: Unused dummy argument 'a4' [-Wunused-dummy-argument]
11+
! NOWARN-NOT: warning: Unused dummy argument 'b4' [-Wunused-dummy-argument]
12+
! NOWARN-NOT: warning: Unused dummy argument 'a6' [-Wunused-dummy-argument]
13+
! NOWARN-NOT: warning: Unused dummy argument 'b6' [-Wunused-dummy-argument]
14+
15+
program main
16+
type :: my_type
17+
integer :: val
18+
end type
19+
integer :: not_dummy_arg
20+
interface
21+
subroutine subroutine_interface(a)
22+
integer, intent(in) :: a
23+
end subroutine
24+
25+
function function_interface(a2)
26+
integer, intent(in) :: a2
27+
end function
28+
end interface
29+
contains
30+
subroutine subroutine_all_used(a3, b3)
31+
integer, intent(inout) :: a3, b3
32+
a3 = a3 + b3
33+
end subroutine
34+
35+
subroutine subroutine_unused_both(a4, b4)
36+
integer, intent(inout) :: a4(10)
37+
type(my_type) :: b4
38+
end subroutine
39+
40+
41+
function function_used_all(a5, b5) result(c1)
42+
integer, intent(inout) :: a5(10)
43+
type(my_type), intent(in) :: b5
44+
integer :: c1
45+
a5(1) = b5%val
46+
c1 = a5(2)
47+
end function
48+
49+
function function_unused_both(a6, b6) result(c2)
50+
integer, intent(inout) :: a6(10)
51+
type(my_type) :: b6
52+
integer :: c2
53+
end function
54+
end program

0 commit comments

Comments
 (0)