@@ -26,8 +26,81 @@ namespace characteristics = Fortran::evaluate::characteristics;
26
26
27
27
namespace Fortran ::semantics {
28
28
29
+ // Raise warnings for some dangerous context of passing global variables
30
+ // - any variable from common blocks except
31
+ // - 1-element arrays being single member of COMMON
32
+ // - avy variable from module except
33
+ // - having attribute PARAMETER
34
+ // - being arrays having 1-D rank and is not having ALLOCATABLE or POINTER or
35
+ // VOLATILE attributes
36
+ static void CheckPassGlobalVariable (
37
+ const evaluate::Expr<evaluate::SomeType> &actual,
38
+ const parser::ContextualMessages &messages, SemanticsContext &context,
39
+ evaluate::FoldingContext &foldingContext) {
40
+ const Symbol *actualFirstSymbol{evaluate::GetFirstSymbol (actual)};
41
+ if (actualFirstSymbol) {
42
+ bool warn{false };
43
+ std::string ownerType{" " };
44
+ std::string ownerName{" " };
45
+ if (actualFirstSymbol->flags ().test (Symbol::Flag::InCommonBlock)) {
46
+ const Symbol *common{FindCommonBlockContaining (*actualFirstSymbol)};
47
+ ownerType = " COMMON" ;
48
+ ownerName = common->name ().ToString ();
49
+ if (!(actualFirstSymbol->Rank () == 1 &&
50
+ actualFirstSymbol->offset () == 0 )) {
51
+ warn |= true ;
52
+ } else if (actualFirstSymbol->Rank () == 1 ) {
53
+ bool actualIsArrayElement{IsArrayElement (actual) != nullptr };
54
+ if (!actualIsArrayElement) {
55
+ warn |= true ;
56
+ }
57
+ if (const ArraySpec *dims{actualFirstSymbol->GetShape ()};
58
+ dims && dims->IsExplicitShape ()) {
59
+ if (!((*dims)[0 ].lbound ().GetExplicit () ==
60
+ (*dims)[0 ].ubound ().GetExplicit ())) {
61
+ warn |= true ;
62
+ }
63
+ }
64
+ if (common->get <CommonBlockDetails>().objects ().size () > 1 ) {
65
+ warn |= true ;
66
+ }
67
+ }
68
+ } else if (const auto &owner{actualFirstSymbol->GetUltimate ().owner ()};
69
+ owner.IsModule () || owner.IsSubmodule ()) {
70
+ const Scope *module {FindModuleContaining (owner)};
71
+ ownerType = " MODULE" ;
72
+ ownerName = module ->GetName ()->ToString ();
73
+ if (actualFirstSymbol->attrs ().test (Attr::PARAMETER)) {
74
+ warn |= false ;
75
+ } else if (actualFirstSymbol->Rank () != 1 ) {
76
+ warn |= true ;
77
+ } else if (!actualFirstSymbol->attrs ().test (Attr::ALLOCATABLE) &&
78
+ !actualFirstSymbol->attrs ().test (Attr::POINTER) &&
79
+ !actualFirstSymbol->attrs ().test (Attr::VOLATILE)) {
80
+ bool actualIsArrayElement{IsArrayElement (actual) != nullptr };
81
+ if (!actualIsArrayElement) {
82
+ warn |= true ;
83
+ }
84
+ if (const ArraySpec *dims{actualFirstSymbol->GetShape ()};
85
+ dims && dims->IsExplicitShape ()) {
86
+ if (!((*dims)[0 ].lbound ().GetExplicit () ==
87
+ (*dims)[0 ].ubound ().GetExplicit ())) {
88
+ warn |= true ;
89
+ }
90
+ }
91
+ }
92
+ }
93
+ if (warn) {
94
+ context.Warn (common::UsageWarning::PassGlobalVariable, messages.at (),
95
+ " Passing global variable '%s' from %s '%s' as function argument" _warn_en_US,
96
+ actualFirstSymbol->name (), ownerType, ownerName);
97
+ }
98
+ }
99
+ }
100
+
29
101
static void CheckImplicitInterfaceArg (evaluate::ActualArgument &arg,
30
- parser::ContextualMessages &messages, SemanticsContext &context) {
102
+ parser::ContextualMessages &messages, SemanticsContext &context,
103
+ evaluate::FoldingContext &foldingContext) {
31
104
auto restorer{
32
105
messages.SetLocation (arg.sourceLocation ().value_or (messages.at ()))};
33
106
if (auto kw{arg.keyword ()}) {
@@ -118,6 +191,10 @@ static void CheckImplicitInterfaceArg(evaluate::ActualArgument &arg,
118
191
}
119
192
}
120
193
}
194
+
195
+ if (const auto *expr{arg.UnwrapExpr ()}) {
196
+ CheckPassGlobalVariable (*expr, messages, context, foldingContext);
197
+ }
121
198
}
122
199
123
200
// F'2023 15.5.2.12p1: "Sequence association only applies when the dummy
@@ -1153,6 +1230,8 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
1153
1230
messages.Say (
1154
1231
" %VAL argument must be a scalar numeric or logical expression" _err_en_US);
1155
1232
}
1233
+
1234
+ CheckPassGlobalVariable (actual, messages, context, foldingContext);
1156
1235
}
1157
1236
1158
1237
static void CheckProcedureArg (evaluate::ActualArgument &arg,
@@ -2409,7 +2488,7 @@ bool CheckArguments(const characteristics::Procedure &proc,
2409
2488
auto restorer{messages.SetMessages (implicitBuffer)};
2410
2489
for (auto &actual : actuals) {
2411
2490
if (actual) {
2412
- CheckImplicitInterfaceArg (*actual, messages, context);
2491
+ CheckImplicitInterfaceArg (*actual, messages, context, foldingContext );
2413
2492
}
2414
2493
}
2415
2494
}
0 commit comments