mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-04-02 13:12:09 +00:00
[flang] Prevent IR name clashes between BIND(C) and external procedures (#66777)
Defining a procedure with a BIND(C, NAME="...") where the binding label matches the assembly name of a non BIND(C) external procedure in the same file causes a failure when generating the LLVM IR because of the assembly symbol name clash. Prevent this crash with a clearer semantic error.
This commit is contained in:
parent
515a826326
commit
1062c140f8
@ -114,5 +114,12 @@ bool AreCompatibleCUDADataAttrs(
|
|||||||
|
|
||||||
static constexpr char blankCommonObjectName[] = "__BLNK__";
|
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
|
} // namespace Fortran::common
|
||||||
#endif // FORTRAN_COMMON_FORTRAN_H_
|
#endif // FORTRAN_COMMON_FORTRAN_H_
|
||||||
|
@ -38,11 +38,8 @@ mangleExternalName(const std::pair<fir::NameUniquer::NameKind,
|
|||||||
if (result.first == fir::NameUniquer::NameKind::COMMON &&
|
if (result.first == fir::NameUniquer::NameKind::COMMON &&
|
||||||
result.second.name.empty())
|
result.second.name.empty())
|
||||||
return Fortran::common::blankCommonObjectName;
|
return Fortran::common::blankCommonObjectName;
|
||||||
|
return Fortran::common::GetExternalAssemblyName(result.second.name,
|
||||||
if (appendUnderscore)
|
appendUnderscore);
|
||||||
return result.second.name + "_";
|
|
||||||
|
|
||||||
return result.second.name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the early outlining parent name
|
/// Update the early outlining parent name
|
||||||
|
@ -130,6 +130,7 @@ private:
|
|||||||
}
|
}
|
||||||
bool IsResultOkToDiffer(const FunctionResult &);
|
bool IsResultOkToDiffer(const FunctionResult &);
|
||||||
void CheckGlobalName(const Symbol &);
|
void CheckGlobalName(const Symbol &);
|
||||||
|
void CheckProcedureAssemblyName(const Symbol &symbol);
|
||||||
void CheckExplicitSave(const Symbol &);
|
void CheckExplicitSave(const Symbol &);
|
||||||
void CheckBindC(const Symbol &);
|
void CheckBindC(const Symbol &);
|
||||||
void CheckBindCFunctionResult(const Symbol &);
|
void CheckBindCFunctionResult(const Symbol &);
|
||||||
@ -178,6 +179,9 @@ private:
|
|||||||
std::map<std::string, SymbolRef> globalNames_;
|
std::map<std::string, SymbolRef> globalNames_;
|
||||||
// Collection of external procedures without global definitions
|
// Collection of external procedures without global definitions
|
||||||
std::map<std::string, SymbolRef> externalNames_;
|
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 {
|
class DistinguishabilityHelper {
|
||||||
@ -277,6 +281,7 @@ void CheckHelper::Check(const Symbol &symbol) {
|
|||||||
CheckContiguous(symbol);
|
CheckContiguous(symbol);
|
||||||
}
|
}
|
||||||
CheckGlobalName(symbol);
|
CheckGlobalName(symbol);
|
||||||
|
CheckProcedureAssemblyName(symbol);
|
||||||
if (symbol.attrs().test(Attr::ASYNCHRONOUS) &&
|
if (symbol.attrs().test(Attr::ASYNCHRONOUS) &&
|
||||||
!evaluate::IsVariable(symbol)) {
|
!evaluate::IsVariable(symbol)) {
|
||||||
messages_.Say(
|
messages_.Say(
|
||||||
@ -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) {
|
void CheckHelper::CheckBindC(const Symbol &symbol) {
|
||||||
bool isExplicitBindC{symbol.attrs().test(Attr::BIND_C)};
|
bool isExplicitBindC{symbol.attrs().test(Attr::BIND_C)};
|
||||||
if (isExplicitBindC) {
|
if (isExplicitBindC) {
|
||||||
|
35
flang/test/Semantics/bind-c14.f90
Normal file
35
flang/test/Semantics/bind-c14.f90
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
! RUN: %python %S/test_errors.py %s %flang_fc1 -funderscoring
|
||||||
|
|
||||||
|
subroutine conflict1()
|
||||||
|
end subroutine
|
||||||
|
|
||||||
|
!ERROR: BIND(C) procedure assembly name conflicts with non BIND(C) procedure assembly name
|
||||||
|
subroutine foo(x) bind(c, name="conflict1_")
|
||||||
|
real :: x
|
||||||
|
end subroutine
|
||||||
|
|
||||||
|
subroutine no_conflict1() bind(c, name="")
|
||||||
|
end subroutine
|
||||||
|
subroutine foo2() bind(c, name="conflict2_")
|
||||||
|
end subroutine
|
||||||
|
|
||||||
|
subroutine bar()
|
||||||
|
interface
|
||||||
|
subroutine no_conflict1() bind(c, name="")
|
||||||
|
end subroutine
|
||||||
|
! ERROR: Non BIND(C) procedure assembly name conflicts with BIND(C) procedure assembly name
|
||||||
|
subroutine conflict2()
|
||||||
|
end subroutine
|
||||||
|
end interface
|
||||||
|
call no_conflict1()
|
||||||
|
call conflict2
|
||||||
|
end subroutine
|
||||||
|
|
||||||
|
subroutine no_conflict2() bind(c, name="no_conflict2_")
|
||||||
|
end subroutine
|
||||||
|
|
||||||
|
subroutine _()
|
||||||
|
end subroutine
|
||||||
|
|
||||||
|
subroutine dash_no_conflict() bind(c, name="")
|
||||||
|
end subroutine
|
Loading…
x
Reference in New Issue
Block a user