@@ -113,6 +113,7 @@ class CheckHelper {
113
113
return msg;
114
114
}
115
115
bool IsResultOkToDiffer (const FunctionResult &);
116
+ void CheckGlobalName (const Symbol &);
116
117
void CheckBindC (const Symbol &);
117
118
void CheckBindCFunctionResult (const Symbol &);
118
119
// Check functions for defined I/O procedures
@@ -154,11 +155,11 @@ class CheckHelper {
154
155
// Cache of calls to Procedure::Characterize(Symbol)
155
156
std::map<SymbolRef, std::optional<Procedure>, SymbolAddressCompare>
156
157
characterizeCache_;
157
- // Collection of symbols with BIND(C) names
158
- std::map<std::string, SymbolRef> bindC_;
159
158
// Collection of module procedure symbols with non-BIND(C)
160
159
// global names, qualified by their module.
161
160
std::map<std::pair<SourceName, const Symbol *>, SymbolRef> moduleProcs_;
161
+ // Collection of symbols with global names, BIND(C) or otherwise
162
+ std::map<std::string, SymbolRef> globalNames_;
162
163
// Derived types that have defined input/output procedures
163
164
std::vector<TypeWithDefinedIo> seenDefinedIoTypes_;
164
165
};
@@ -253,6 +254,7 @@ void CheckHelper::Check(const Symbol &symbol) {
253
254
CheckVolatile (symbol, derived);
254
255
}
255
256
CheckBindC (symbol);
257
+ CheckGlobalName (symbol);
256
258
if (isDone) {
257
259
return ; // following checks do not apply
258
260
}
@@ -316,7 +318,9 @@ void CheckHelper::Check(const Symbol &symbol) {
316
318
if (type) { // Section 7.2, paragraph 7
317
319
bool canHaveAssumedParameter{IsNamedConstant (symbol) ||
318
320
(IsAssumedLengthCharacter (symbol) && // C722
319
- IsExternal (symbol)) ||
321
+ (IsExternal (symbol) ||
322
+ ClassifyProcedure (symbol) ==
323
+ ProcedureDefinitionClass::Dummy)) ||
320
324
symbol.test (Symbol::Flag::ParentComp)};
321
325
if (!IsStmtFunctionDummy (symbol)) { // C726
322
326
if (const auto *object{symbol.detailsIf <ObjectEntityDetails>()}) {
@@ -351,7 +355,7 @@ void CheckHelper::Check(const Symbol &symbol) {
351
355
}
352
356
}
353
357
}
354
- if (IsAssumedLengthCharacter (symbol) && IsExternal (symbol)) { // C723
358
+ if (IsAssumedLengthCharacter (symbol) && IsFunction (symbol)) { // C723
355
359
if (symbol.attrs ().test (Attr::RECURSIVE)) {
356
360
messages_.Say (
357
361
" An assumed-length CHARACTER(*) function cannot be RECURSIVE" _err_en_US);
@@ -360,21 +364,24 @@ void CheckHelper::Check(const Symbol &symbol) {
360
364
messages_.Say (
361
365
" An assumed-length CHARACTER(*) function cannot return an array" _err_en_US);
362
366
}
363
- if (IsElementalProcedure (symbol)) {
364
- messages_.Say (
365
- " An assumed-length CHARACTER(*) function cannot be ELEMENTAL" _err_en_US);
366
- } else if (IsPureProcedure (symbol)) {
367
- messages_.Say (
368
- " An assumed-length CHARACTER(*) function cannot be PURE" _err_en_US);
367
+ if (!IsStmtFunction (symbol)) {
368
+ if (IsElementalProcedure (symbol)) {
369
+ messages_.Say (
370
+ " An assumed-length CHARACTER(*) function cannot be ELEMENTAL" _err_en_US);
371
+ } else if (IsPureProcedure (symbol)) {
372
+ messages_.Say (
373
+ " An assumed-length CHARACTER(*) function cannot be PURE" _err_en_US);
374
+ }
369
375
}
370
376
if (const Symbol *result{FindFunctionResult (symbol)}) {
371
377
if (IsPointer (*result)) {
372
378
messages_.Say (
373
379
" An assumed-length CHARACTER(*) function cannot return a POINTER" _err_en_US);
374
380
}
375
- } else if (IsPointer (symbol)) {
381
+ } else if (IsProcedurePointer (symbol) && IsDummy (symbol)) {
376
382
messages_.Say (
377
- " A procedure pointer should not have assumed-length CHARACTER(*) result type" _port_en_US);
383
+ " A dummy procedure pointer should not have assumed-length CHARACTER(*) result type" _port_en_US);
384
+ // The non-dummy case is a hard error that's caught elsewhere.
378
385
}
379
386
}
380
387
if (symbol.attrs ().test (Attr::VALUE)) {
@@ -420,7 +427,10 @@ void CheckHelper::Check(const Symbol &symbol) {
420
427
}
421
428
}
422
429
423
- void CheckHelper::CheckCommonBlock (const Symbol &symbol) { CheckBindC (symbol); }
430
+ void CheckHelper::CheckCommonBlock (const Symbol &symbol) {
431
+ CheckGlobalName (symbol);
432
+ CheckBindC (symbol);
433
+ }
424
434
425
435
void CheckHelper::CheckBindCFunctionResult (const Symbol &symbol) { // C1553
426
436
if (!innermostSymbol_ || !IsBindCProcedure (*innermostSymbol_)) {
@@ -1060,7 +1070,7 @@ void CheckHelper::CheckSubprogram(
1060
1070
}
1061
1071
1062
1072
void CheckHelper::CheckLocalVsGlobal (const Symbol &symbol) {
1063
- if (IsProcedure (symbol) && IsExternal (symbol)) {
1073
+ if (IsExternal (symbol)) {
1064
1074
if (const Symbol *global{FindGlobal (symbol)}; global && global != &symbol) {
1065
1075
std::string interfaceName{symbol.name ().ToString ()};
1066
1076
if (const auto *bind{symbol.GetBindName ()}) {
@@ -1095,8 +1105,13 @@ void CheckHelper::CheckLocalVsGlobal(const Symbol &symbol) {
1095
1105
}
1096
1106
}
1097
1107
}
1098
- evaluate::AttachDeclaration (msg, *global);
1099
- evaluate::AttachDeclaration (msg, symbol);
1108
+ if (msg) {
1109
+ if (msg->IsFatal ()) {
1110
+ context_.SetError (symbol);
1111
+ }
1112
+ evaluate::AttachDeclaration (msg, *global);
1113
+ evaluate::AttachDeclaration (msg, symbol);
1114
+ }
1100
1115
}
1101
1116
}
1102
1117
}
@@ -2080,14 +2095,75 @@ void CheckHelper::CheckGenericOps(const Scope &scope) {
2080
2095
helper.Check (scope);
2081
2096
}
2082
2097
2083
- static const std::string * DefinesBindCName (const Symbol &symbol) {
2098
+ static bool IsSubprogramDefinition (const Symbol &symbol) {
2084
2099
const auto *subp{symbol.detailsIf <SubprogramDetails>()};
2085
- if ((subp && !subp->isInterface ()) || symbol.has <ObjectEntityDetails>() ||
2086
- symbol.has <CommonBlockDetails>()) {
2087
- // Symbol defines data or entry point
2088
- return symbol.GetBindName ();
2100
+ return subp && !subp->isInterface () && symbol.scope () &&
2101
+ symbol.scope ()->kind () == Scope::Kind::Subprogram;
2102
+ }
2103
+
2104
+ static bool IsBlockData (const Symbol &symbol) {
2105
+ return symbol.scope () && symbol.scope ()->kind () == Scope::Kind::BlockData;
2106
+ }
2107
+
2108
+ static bool IsExternalProcedureDefinition (const Symbol &symbol) {
2109
+ return IsBlockData (symbol) ||
2110
+ (IsSubprogramDefinition (symbol) &&
2111
+ (IsExternal (symbol) || symbol.GetBindName ()));
2112
+ }
2113
+
2114
+ static std::optional<std::string> DefinesGlobalName (const Symbol &symbol) {
2115
+ if (const auto *module {symbol.detailsIf <ModuleDetails>()}) {
2116
+ if (!module ->isSubmodule () && !symbol.owner ().IsIntrinsicModules ()) {
2117
+ return symbol.name ().ToString ();
2118
+ }
2119
+ } else if (IsBlockData (symbol)) {
2120
+ return symbol.name ().ToString ();
2089
2121
} else {
2090
- return nullptr ;
2122
+ const std::string *bindC{symbol.GetBindName ()};
2123
+ if (symbol.has <CommonBlockDetails>() ||
2124
+ IsExternalProcedureDefinition (symbol)) {
2125
+ return bindC ? *bindC : symbol.name ().ToString ();
2126
+ } else if (bindC &&
2127
+ (symbol.has <ObjectEntityDetails>() || IsModuleProcedure (symbol))) {
2128
+ return *bindC;
2129
+ }
2130
+ }
2131
+ return std::nullopt;
2132
+ }
2133
+
2134
+ // 19.2 p2
2135
+ void CheckHelper::CheckGlobalName (const Symbol &symbol) {
2136
+ if (auto global{DefinesGlobalName (symbol)}) {
2137
+ auto pair{globalNames_.emplace (std::move (*global), symbol)};
2138
+ if (!pair.second ) {
2139
+ const Symbol &other{*pair.first ->second };
2140
+ if (context_.HasError (symbol) || context_.HasError (other)) {
2141
+ // don't pile on
2142
+ } else if (symbol.has <CommonBlockDetails>() &&
2143
+ other.has <CommonBlockDetails>() && symbol.name () == other.name ()) {
2144
+ // Two common blocks can have the same global name so long as
2145
+ // they're not in the same scope.
2146
+ } else if ((IsProcedure (symbol) || IsBlockData (symbol)) &&
2147
+ (IsProcedure (other) || IsBlockData (other)) &&
2148
+ (!IsExternalProcedureDefinition (symbol) ||
2149
+ !IsExternalProcedureDefinition (other))) {
2150
+ // both are procedures/BLOCK DATA, not both definitions
2151
+ } else if (symbol.has <ModuleDetails>()) {
2152
+ messages_.Say (symbol.name (),
2153
+ " Module '%s' conflicts with a global name" _port_en_US,
2154
+ pair.first ->first );
2155
+ } else if (other.has <ModuleDetails>()) {
2156
+ messages_.Say (symbol.name (),
2157
+ " Global name '%s' conflicts with a module" _port_en_US,
2158
+ pair.first ->first );
2159
+ } else if (auto *msg{messages_.Say (symbol.name (),
2160
+ " Two entities have the same global name '%s'" _err_en_US,
2161
+ pair.first ->first )}) {
2162
+ msg->Attach (other.name (), " Conflicting declaration" _en_US);
2163
+ context_.SetError (symbol);
2164
+ context_.SetError (other);
2165
+ }
2166
+ }
2091
2167
}
2092
2168
}
2093
2169
@@ -2102,25 +2178,6 @@ void CheckHelper::CheckBindC(const Symbol &symbol) {
2102
2178
" A variable with BIND(C) attribute may only appear in the specification part of a module" _err_en_US);
2103
2179
context_.SetError (symbol);
2104
2180
}
2105
- if (const std::string *name{DefinesBindCName (symbol)}) {
2106
- auto pair{bindC_.emplace (*name, symbol)};
2107
- if (!pair.second ) {
2108
- const Symbol &other{*pair.first ->second };
2109
- if (symbol.has <CommonBlockDetails>() && other.has <CommonBlockDetails>() &&
2110
- symbol.name () == other.name ()) {
2111
- // Two common blocks can have the same BIND(C) name so long as
2112
- // they're not in the same scope.
2113
- } else if (!context_.HasError (other)) {
2114
- if (auto *msg{messages_.Say (symbol.name (),
2115
- " Two entities have the same BIND(C) name '%s'" _err_en_US,
2116
- *name)}) {
2117
- msg->Attach (other.name (), " Conflicting declaration" _en_US);
2118
- }
2119
- context_.SetError (symbol);
2120
- context_.SetError (other);
2121
- }
2122
- }
2123
- }
2124
2181
if (const auto *proc{symbol.detailsIf <ProcEntityDetails>()}) {
2125
2182
if (!proc->procInterface () ||
2126
2183
!proc->procInterface ()->attrs ().test (Attr::BIND_C)) {
0 commit comments