@@ -130,6 +130,7 @@ class CheckHelper {
130
130
}
131
131
bool IsResultOkToDiffer (const FunctionResult &);
132
132
void CheckGlobalName (const Symbol &);
133
+ void CheckProcedureAssemblyName (const Symbol &symbol);
133
134
void CheckExplicitSave (const Symbol &);
134
135
void CheckBindC (const Symbol &);
135
136
void CheckBindCFunctionResult (const Symbol &);
@@ -178,6 +179,9 @@ class CheckHelper {
178
179
std::map<std::string, SymbolRef> globalNames_;
179
180
// Collection of external procedures without global definitions
180
181
std::map<std::string, SymbolRef> externalNames_;
182
+ // Collection of target dependent assembly names of external and BIND(C)
183
+ // procedures.
184
+ std::map<std::string, SymbolRef> procedureAssemblyNames_;
181
185
};
182
186
183
187
class DistinguishabilityHelper {
@@ -277,6 +281,7 @@ void CheckHelper::Check(const Symbol &symbol) {
277
281
CheckContiguous (symbol);
278
282
}
279
283
CheckGlobalName (symbol);
284
+ CheckProcedureAssemblyName (symbol);
280
285
if (symbol.attrs ().test (Attr::ASYNCHRONOUS) &&
281
286
!evaluate::IsVariable (symbol)) {
282
287
messages_.Say (
@@ -2623,6 +2628,43 @@ void CheckHelper::CheckGlobalName(const Symbol &symbol) {
2623
2628
}
2624
2629
}
2625
2630
2631
+ void CheckHelper::CheckProcedureAssemblyName (const Symbol &symbol) {
2632
+ if (!IsProcedure (symbol) || symbol != symbol.GetUltimate ())
2633
+ return ;
2634
+ const std::string *bindName{symbol.GetBindName ()};
2635
+ const bool hasExplicitBindingLabel{
2636
+ symbol.GetIsExplicitBindName () && bindName};
2637
+ if (hasExplicitBindingLabel || IsExternal (symbol)) {
2638
+ const std::string assemblyName{hasExplicitBindingLabel
2639
+ ? *bindName
2640
+ : common::GetExternalAssemblyName (
2641
+ symbol.name ().ToString (), context_.underscoring ())};
2642
+ auto pair{procedureAssemblyNames_.emplace (std::move (assemblyName), symbol)};
2643
+ if (!pair.second ) {
2644
+ const Symbol &other{*pair.first ->second };
2645
+ const bool otherHasExplicitBindingLabel{
2646
+ other.GetIsExplicitBindName () && other.GetBindName ()};
2647
+ if (otherHasExplicitBindingLabel != hasExplicitBindingLabel) {
2648
+ // The BIND(C,NAME="...") binding label is the same as the name that
2649
+ // will be used in LLVM IR for an external procedure declared without
2650
+ // BIND(C) in the same file. While this is not forbidden by the
2651
+ // standard, this name collision would lead to a crash when producing
2652
+ // the IR.
2653
+ if (auto *msg{messages_.Say (symbol.name (),
2654
+ " %s procedure assembly name conflicts with %s procedure assembly name" _err_en_US,
2655
+ hasExplicitBindingLabel ? " BIND(C)" : " Non BIND(C)" ,
2656
+ hasExplicitBindingLabel ? " non BIND(C)" : " BIND(C)" )}) {
2657
+ msg->Attach (other.name (), " Conflicting declaration" _en_US);
2658
+ }
2659
+ context_.SetError (symbol);
2660
+ context_.SetError (other);
2661
+ }
2662
+ // Otherwise, the global names also match and the conflict is analyzed
2663
+ // by CheckGlobalName.
2664
+ }
2665
+ }
2666
+ }
2667
+
2626
2668
void CheckHelper::CheckBindC (const Symbol &symbol) {
2627
2669
bool isExplicitBindC{symbol.attrs ().test (Attr::BIND_C)};
2628
2670
if (isExplicitBindC) {
0 commit comments