Skip to content

Commit b797a6a

Browse files
authored
[flang] Lower special bind(c) cases without binding labels (#65758)
1. Deal with BIND(C,NAME="") BIND(C,NAME="") is different from BIND(C). The latter implies that there us a binding label which is the Fortran symbol name (no Fortran mangling must be added like underscores). The former implies there is no binding label (the name in the object file must be the same as if it there was no BIND(C) attribute at all). This is correctly implemented in the front-end, but lowering mistakenly overrode this in the code dealing with the case where BIND(C) is inherited from a procedure interface. Handling of this last case is moved into name resolution. 2. Deal with BIND(C) internal procedure Also according to 18.10.2, BIND(C) does not give a p prevent name resolution from adding a label to them, otherwise, bindc_internal_proc.f90 was not going through semantics (bogus error about conflicting global names). Nothing TODO in lowering other than removing the TODO.
1 parent 2a20712 commit b797a6a

File tree

6 files changed

+133
-27
lines changed

6 files changed

+133
-27
lines changed

flang/lib/Lower/CallInterface.cpp

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,6 @@
2323
#include "flang/Semantics/tools.h"
2424
#include <optional>
2525

26-
//===----------------------------------------------------------------------===//
27-
// BIND(C) mangling helpers
28-
//===----------------------------------------------------------------------===//
29-
30-
// Return the binding label (from BIND(C...)) or the mangled name of a symbol.
31-
static std::string getMangledName(Fortran::lower::AbstractConverter &converter,
32-
const Fortran::semantics::Symbol &symbol) {
33-
const std::string *bindName = symbol.GetBindName();
34-
// TODO: update GetBindName so that it does not return a label for internal
35-
// procedures.
36-
if (bindName && Fortran::semantics::ClassifyProcedure(symbol) ==
37-
Fortran::semantics::ProcedureDefinitionClass::Internal)
38-
TODO(converter.getCurrentLocation(), "BIND(C) internal procedures");
39-
return bindName ? *bindName : converter.mangleName(symbol);
40-
}
41-
4226
mlir::Type Fortran::lower::getUntypedBoxProcType(mlir::MLIRContext *context) {
4327
llvm::SmallVector<mlir::Type> resultTys;
4428
llvm::SmallVector<mlir::Type> inputTys;
@@ -72,8 +56,10 @@ bool Fortran::lower::CallerInterface::hasAlternateReturns() const {
7256

7357
std::string Fortran::lower::CallerInterface::getMangledName() const {
7458
const Fortran::evaluate::ProcedureDesignator &proc = procRef.proc();
59+
// Return the binding label (from BIND(C...)) or the mangled name of the
60+
// symbol.
7561
if (const Fortran::semantics::Symbol *symbol = proc.GetSymbol())
76-
return ::getMangledName(converter, symbol->GetUltimate());
62+
return converter.mangleName(symbol->GetUltimate());
7763
assert(proc.GetSpecificIntrinsic() &&
7864
"expected intrinsic procedure in designator");
7965
return proc.GetName();
@@ -420,7 +406,7 @@ bool Fortran::lower::CalleeInterface::hasAlternateReturns() const {
420406
std::string Fortran::lower::CalleeInterface::getMangledName() const {
421407
if (funit.isMainProgram())
422408
return fir::NameUniquer::doProgramEntry().str();
423-
return ::getMangledName(converter, funit.getSubprogramSymbol());
409+
return converter.mangleName(funit.getSubprogramSymbol());
424410
}
425411

426412
const Fortran::semantics::Symbol *

flang/lib/Lower/Mangler.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -96,14 +96,6 @@ std::string Fortran::lower::mangle::mangleName(
9696
if (auto *overrideName = ultimateSymbol.GetBindName())
9797
return *overrideName;
9898

99-
// TODO: A procedure that inherits BIND(C) through another interface
100-
// (procedure(iface)) should be dealt with in GetBindName() or some wrapper.
101-
if (!Fortran::semantics::IsPointer(ultimateSymbol) &&
102-
Fortran::semantics::IsBindCProcedure(ultimateSymbol) &&
103-
Fortran::semantics::ClassifyProcedure(symbol) !=
104-
Fortran::semantics::ProcedureDefinitionClass::Internal)
105-
return ultimateSymbol.name().ToString();
106-
10799
llvm::StringRef symbolName = toStringRef(ultimateSymbol.name());
108100
llvm::SmallVector<llvm::StringRef> modules;
109101
llvm::SmallVector<llvm::StringRef> procs;

flang/lib/Semantics/resolve-names.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1739,9 +1739,11 @@ bool AttrsVisitor::SetPassNameOn(Symbol &symbol) {
17391739
}
17401740

17411741
void AttrsVisitor::SetBindNameOn(Symbol &symbol) {
1742-
if (!attrs_ || !attrs_->test(Attr::BIND_C)) {
1742+
if ((!attrs_ || !attrs_->test(Attr::BIND_C)) &&
1743+
!symbol.attrs().test(Attr::BIND_C)) {
17431744
return;
17441745
}
1746+
17451747
std::optional<std::string> label{
17461748
evaluate::GetScalarConstantValue<evaluate::Ascii>(bindName_)};
17471749
// 18.9.2(2): discard leading and trailing blanks
@@ -1754,6 +1756,9 @@ void AttrsVisitor::SetBindNameOn(Symbol &symbol) {
17541756
}
17551757
auto last{label->find_last_not_of(" ")};
17561758
label = label->substr(first, last - first + 1);
1759+
} else if (ClassifyProcedure(symbol) == ProcedureDefinitionClass::Internal) {
1760+
// BIND(C) does not give an implicit binding label to internal procedures.
1761+
return;
17571762
} else {
17581763
label = symbol.name().ToString();
17591764
}
@@ -4834,6 +4839,13 @@ Symbol &DeclarationVisitor::DeclareProcEntity(
48344839
} else if (interface->test(Symbol::Flag::Subroutine)) {
48354840
symbol.set(Symbol::Flag::Subroutine);
48364841
}
4842+
if (IsBindCProcedure(*interface) && !IsPointer(symbol) &&
4843+
!IsDummy(symbol)) {
4844+
// Inherit BIND_C attribute from the interface, but not the NAME="..."
4845+
// if any. This is not clearly described in the standard, but matches
4846+
// the behavior of other compilers.
4847+
SetImplicitAttr(symbol, Attr::BIND_C);
4848+
}
48374849
} else if (auto *type{GetDeclTypeSpec()}) {
48384850
SetType(name, *type);
48394851
symbol.set(Symbol::Flag::Function);
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
! Test mangling with BIND(C) inherited from procedure interface.
2+
! RUN: bbc -emit-hlfir -o - %s | FileCheck %s
3+
4+
subroutine test()
5+
interface
6+
subroutine iface_notbindc()
7+
end subroutine
8+
subroutine iface_bindc() bind(c)
9+
end subroutine
10+
subroutine iface_explicit_name() bind(c, name="explicit_name")
11+
end subroutine
12+
subroutine iface_nobinding() bind(c, name="")
13+
end subroutine
14+
end interface
15+
16+
procedure(iface_bindc) :: foo_iface_bindc
17+
procedure(iface_explicit_name) :: foo_iface_explicit_name
18+
procedure(iface_nobinding) :: foo_iface_nobinding
19+
20+
procedure(iface_bindc), bind(c) :: extra_bindc_iface_bindc
21+
procedure(iface_explicit_name), bind(c) :: extra_bindc_iface_explicit_name
22+
procedure(iface_nobinding), bind(c) :: extra_bindc_iface_nobinding
23+
24+
procedure(iface_bindc), bind(c, name="bar_iface_bindc_2") :: bar_iface_bindc
25+
procedure(iface_explicit_name), bind(c,name="bar_iface_explicit_name_2") :: bar_iface_explicit_name
26+
procedure(iface_nobinding), bind(c, name="bar_iface_nobinding_2") :: bar_iface_nobinding
27+
28+
procedure(iface_bindc), bind(c, name="") :: nobinding_iface_bindc
29+
procedure(iface_explicit_name), bind(c, name="") :: nobinding_iface_explicit_name
30+
procedure(iface_nobinding), bind(c, name="") :: nobinding_iface_nobinding
31+
32+
call iface_notbindc()
33+
call iface_bindc()
34+
call iface_explicit_name()
35+
call iface_nobinding()
36+
37+
call foo_iface_bindc()
38+
call foo_iface_explicit_name()
39+
call foo_iface_nobinding()
40+
41+
call extra_bindc_iface_bindc()
42+
call extra_bindc_iface_explicit_name()
43+
call extra_bindc_iface_nobinding()
44+
45+
call bar_iface_bindc()
46+
call bar_iface_explicit_name()
47+
call bar_iface_nobinding()
48+
49+
call nobinding_iface_bindc()
50+
call nobinding_iface_explicit_name()
51+
call nobinding_iface_nobinding()
52+
53+
! CHECK: fir.call @_QPiface_notbindc()
54+
! CHECK: fir.call @iface_bindc()
55+
! CHECK: fir.call @explicit_name()
56+
! CHECK: fir.call @_QPiface_nobinding()
57+
! CHECK: fir.call @foo_iface_bindc()
58+
! CHECK: fir.call @foo_iface_explicit_name()
59+
! CHECK: fir.call @foo_iface_nobinding()
60+
! CHECK: fir.call @extra_bindc_iface_bindc()
61+
! CHECK: fir.call @extra_bindc_iface_explicit_name()
62+
! CHECK: fir.call @extra_bindc_iface_nobinding()
63+
! CHECK: fir.call @bar_iface_bindc_2()
64+
! CHECK: fir.call @bar_iface_explicit_name_2()
65+
! CHECK: fir.call @bar_iface_nobinding_2()
66+
! CHECK: fir.call @_QPnobinding_iface_bindc()
67+
! CHECK: fir.call @_QPnobinding_iface_explicit_name()
68+
! CHECK: fir.call @_QPnobinding_iface_nobinding()
69+
end subroutine
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
! Test that lowering makes a difference between NAME="" and no NAME
2+
! in BIND(C). See Fortran 2018 standard 18.10.2 point 2.
3+
! BIND(C, NAME="") implies there is no binding label, meaning that
4+
! the Fortran mangled name has to be used.
5+
! RUN: bbc -emit-hlfir %s -o - | FileCheck %s
6+
7+
!CHECK: func.func @_QPfoo(%{{.*}}: !fir.ref<i16>
8+
subroutine foo(x) bind(c, name="")
9+
integer(2) :: x
10+
end subroutine
11+
12+
!CHECK: func.func @bar(%{{.*}}: !fir.ref<i32>
13+
subroutine foo(x) bind(c, name="bar")
14+
integer(4) :: x
15+
end subroutine
16+
17+
!CHECK: func.func @_QMinamodule1Pfoo(%{{.*}}: !fir.ref<i64>
18+
module inamodule1
19+
contains
20+
subroutine foo(x) bind(c, name="")
21+
integer(8) :: x
22+
end subroutine
23+
end module
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
! Test that internal procedure with BIND(C) do not have binding labels,
2+
! that is, that they are generated using usual flang mangling for non BIND(C)
3+
! internal procedures.
4+
! RUN: bbc -emit-hlfir %s -o - | FileCheck %s
5+
6+
!CHECK: func.func @_QFsub1Pfoo(%{{.*}}: i32
7+
subroutine sub1()
8+
call foo(42)
9+
contains
10+
subroutine foo(i) bind(c)
11+
integer, value :: i
12+
print *, i
13+
end subroutine
14+
end subroutine
15+
16+
!CHECK: func.func @_QFsub2Pfoo(%{{.*}}: i64
17+
subroutine sub2()
18+
call foo(42_8)
19+
contains
20+
subroutine foo(i) bind(c)
21+
integer(8), value :: i
22+
print *, i
23+
end subroutine
24+
end subroutine

0 commit comments

Comments
 (0)