Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions flang/include/flang/Common/Fortran.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,5 +114,12 @@ bool AreCompatibleCUDADataAttrs(

static constexpr char blankCommonObjectName[] = "__BLNK__";

// Get the assembly name for a non BIND(C) external symbol other than the blank
// common block.
inline std::string GetExternalAssemblyName(
std::string symbolName, bool underscoring) {
return underscoring ? std::move(symbolName) + "_" : std::move(symbolName);
}

} // namespace Fortran::common
#endif // FORTRAN_COMMON_FORTRAN_H_
7 changes: 2 additions & 5 deletions flang/lib/Optimizer/Transforms/ExternalNameConversion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,8 @@ mangleExternalName(const std::pair<fir::NameUniquer::NameKind,
if (result.first == fir::NameUniquer::NameKind::COMMON &&
result.second.name.empty())
return Fortran::common::blankCommonObjectName;

if (appendUnderscore)
return result.second.name + "_";

return result.second.name;
return Fortran::common::GetExternalAssemblyName(result.second.name,
appendUnderscore);
}

/// Update the early outlining parent name
Expand Down
42 changes: 42 additions & 0 deletions flang/lib/Semantics/check-declarations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ class CheckHelper {
}
bool IsResultOkToDiffer(const FunctionResult &);
void CheckGlobalName(const Symbol &);
void CheckProcedureAssemblyName(const Symbol &symbol);
void CheckExplicitSave(const Symbol &);
void CheckBindC(const Symbol &);
void CheckBindCFunctionResult(const Symbol &);
Expand Down Expand Up @@ -178,6 +179,9 @@ class CheckHelper {
std::map<std::string, SymbolRef> globalNames_;
// Collection of external procedures without global definitions
std::map<std::string, SymbolRef> externalNames_;
// Collection of target dependent assembly names of external and BIND(C)
// procedures.
std::map<std::string, SymbolRef> procedureAssemblyNames_;
};

class DistinguishabilityHelper {
Expand Down Expand Up @@ -277,6 +281,7 @@ void CheckHelper::Check(const Symbol &symbol) {
CheckContiguous(symbol);
}
CheckGlobalName(symbol);
CheckProcedureAssemblyName(symbol);
if (symbol.attrs().test(Attr::ASYNCHRONOUS) &&
!evaluate::IsVariable(symbol)) {
messages_.Say(
Expand Down Expand Up @@ -2623,6 +2628,43 @@ void CheckHelper::CheckGlobalName(const Symbol &symbol) {
}
}

void CheckHelper::CheckProcedureAssemblyName(const Symbol &symbol) {
if (!IsProcedure(symbol) || symbol != symbol.GetUltimate())
return;
const std::string *bindName{symbol.GetBindName()};
const bool hasExplicitBindingLabel{
symbol.GetIsExplicitBindName() && bindName};
if (hasExplicitBindingLabel || IsExternal(symbol)) {
const std::string assemblyName{hasExplicitBindingLabel
? *bindName
: common::GetExternalAssemblyName(
symbol.name().ToString(), context_.underscoring())};
auto pair{procedureAssemblyNames_.emplace(std::move(assemblyName), symbol)};
if (!pair.second) {
const Symbol &other{*pair.first->second};
const bool otherHasExplicitBindingLabel{
other.GetIsExplicitBindName() && other.GetBindName()};
if (otherHasExplicitBindingLabel != hasExplicitBindingLabel) {
// The BIND(C,NAME="...") binding label is the same as the name that
// will be used in LLVM IR for an external procedure declared without
// BIND(C) in the same file. While this is not forbidden by the
// standard, this name collision would lead to a crash when producing
// the IR.
if (auto *msg{messages_.Say(symbol.name(),
"%s procedure assembly name conflicts with %s procedure assembly name"_err_en_US,
hasExplicitBindingLabel ? "BIND(C)" : "Non BIND(C)",
hasExplicitBindingLabel ? "non BIND(C)" : "BIND(C)")}) {
msg->Attach(other.name(), "Conflicting declaration"_en_US);
}
context_.SetError(symbol);
context_.SetError(other);
}
// Otherwise, the global names also match and the conflict is analyzed
// by CheckGlobalName.
}
}
}

void CheckHelper::CheckBindC(const Symbol &symbol) {
bool isExplicitBindC{symbol.attrs().test(Attr::BIND_C)};
if (isExplicitBindC) {
Expand Down
9 changes: 9 additions & 0 deletions flang/test/Semantics/bind-c14.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
! RUN: %python %S/test_errors.py %s %flang_fc1 -funderscoring

subroutine conflict()
end subroutine

!ERROR: BIND(C) procedure assembly name conflicts with non BIND(C) procedure assembly name
subroutine foo(x) bind(c, name="conflict_")
real :: x
end subroutine