[flang] Enforce C1552, no binding labels allowed for internal procedures

If BIND(C) appears on an internal procedure, it must have a null binding
label, i.e. BIND(C,NAME="").

Also address conflicts with D127725 which was merged during development.

Differential Revision: https://reviews.llvm.org/D128676
This commit is contained in:
Peter Klausler 2022-06-15 09:18:25 -07:00
parent eab2a06f0f
commit cfd474e0d0
7 changed files with 43 additions and 23 deletions

View File

@ -1869,10 +1869,8 @@ void CheckHelper::CheckGenericOps(const Scope &scope) {
static const std::string *DefinesBindCName(const Symbol &symbol) { static const std::string *DefinesBindCName(const Symbol &symbol) {
const auto *subp{symbol.detailsIf<SubprogramDetails>()}; const auto *subp{symbol.detailsIf<SubprogramDetails>()};
if ((subp && !subp->isInterface() && if ((subp && !subp->isInterface()) || symbol.has<ObjectEntityDetails>() ||
ClassifyProcedure(symbol) != ProcedureDefinitionClass::Internal) || symbol.has<CommonBlockDetails>()) {
symbol.has<ObjectEntityDetails>() || symbol.has<CommonBlockDetails>() ||
symbol.has<ProcEntityDetails>()) {
// Symbol defines data or entry point // Symbol defines data or entry point
return symbol.GetBindName(); return symbol.GetBindName();
} else { } else {
@ -1893,14 +1891,15 @@ void CheckHelper::CheckBindC(const Symbol &symbol) {
auto pair{bindC_.emplace(*name, symbol)}; auto pair{bindC_.emplace(*name, symbol)};
if (!pair.second) { if (!pair.second) {
const Symbol &other{*pair.first->second}; const Symbol &other{*pair.first->second};
// Two common blocks with the same name can have the same BIND(C) name. if (symbol.has<CommonBlockDetails>() && other.has<CommonBlockDetails>() &&
if ((!symbol.has<CommonBlockDetails>() || symbol.name() == other.name()) {
symbol.name() != other.name()) && // Two common blocks can have the same BIND(C) name so long as
DefinesBindCName(other) && !context_.HasError(other)) { // they're not in the same scope.
} else if (!context_.HasError(other)) {
if (auto *msg{messages_.Say(symbol.name(), if (auto *msg{messages_.Say(symbol.name(),
"Two symbols have the same BIND(C) name '%s'"_err_en_US, "Two entities have the same BIND(C) name '%s'"_err_en_US,
*name)}) { *name)}) {
msg->Attach(other.name(), "Conflicting symbol"_en_US); msg->Attach(other.name(), "Conflicting declaration"_en_US);
} }
context_.SetError(symbol); context_.SetError(symbol);
context_.SetError(other); context_.SetError(other);

View File

@ -1662,12 +1662,18 @@ void AttrsVisitor::SetBindNameOn(Symbol &symbol) {
} }
std::optional<std::string> label{ std::optional<std::string> label{
evaluate::GetScalarConstantValue<evaluate::Ascii>(bindName_)}; evaluate::GetScalarConstantValue<evaluate::Ascii>(bindName_)};
// 18.9.2(2): discard leading and trailing blanks, ignore if all blank if (ClassifyProcedure(symbol) == ProcedureDefinitionClass::Internal) {
if (label) { // C1552: no NAME= allowed even if null
Say(symbol.name(),
"An internal procedure may not have a BIND(C,NAME=) binding label"_err_en_US);
}
return;
}
// 18.9.2(2): discard leading and trailing blanks
if (label) { if (label) {
auto first{label->find_first_not_of(" ")}; auto first{label->find_first_not_of(" ")};
if (first == std::string::npos) { if (first == std::string::npos) {
// Empty NAME= means no binding at all (18.10.2p2) // Empty NAME= means no binding at all (18.10.2p2)
Say(currStmtSource().value(), "Blank binding label ignored"_warn_en_US);
return; return;
} }
auto last{label->find_last_not_of(" ")}; auto last{label->find_last_not_of(" ")};
@ -4172,10 +4178,10 @@ Symbol &DeclarationVisitor::DeclareUnknownEntity(
SetType(name, *type); SetType(name, *type);
} }
charInfo_.length.reset(); charInfo_.length.reset();
SetBindNameOn(symbol);
if (symbol.attrs().test(Attr::EXTERNAL)) { if (symbol.attrs().test(Attr::EXTERNAL)) {
ConvertToProcEntity(symbol); ConvertToProcEntity(symbol);
} }
SetBindNameOn(symbol);
return symbol; return symbol;
} }
} }

View File

@ -1091,7 +1091,9 @@ const Symbol *FindSeparateModuleSubprogramInterface(const Symbol *proc) {
ProcedureDefinitionClass ClassifyProcedure(const Symbol &symbol) { // 15.2.2 ProcedureDefinitionClass ClassifyProcedure(const Symbol &symbol) { // 15.2.2
const Symbol &ultimate{symbol.GetUltimate()}; const Symbol &ultimate{symbol.GetUltimate()};
if (ultimate.attrs().test(Attr::INTRINSIC)) { if (!IsProcedure(ultimate)) {
return ProcedureDefinitionClass::None;
} else if (ultimate.attrs().test(Attr::INTRINSIC)) {
return ProcedureDefinitionClass::Intrinsic; return ProcedureDefinitionClass::Intrinsic;
} else if (ultimate.attrs().test(Attr::EXTERNAL)) { } else if (ultimate.attrs().test(Attr::EXTERNAL)) {
return ProcedureDefinitionClass::External; return ProcedureDefinitionClass::External;

View File

@ -3,14 +3,14 @@
module m1 module m1
integer, bind(c, name="x1") :: x1 integer, bind(c, name="x1") :: x1
!ERROR: Two symbols have the same BIND(C) name 'x1' !ERROR: Two entities have the same BIND(C) name 'x1'
integer, bind(c, name=" x1 ") :: x2 integer, bind(c, name=" x1 ") :: x2
contains contains
subroutine x3() bind(c, name="x3") subroutine x3() bind(c, name="x3")
end subroutine end subroutine
end module end module
!ERROR: Two symbols have the same BIND(C) name 'x3' !ERROR: Two entities have the same BIND(C) name 'x3'
subroutine x4() bind(c, name=" x3 ") subroutine x4() bind(c, name=" x3 ")
end subroutine end subroutine

View File

@ -11,7 +11,7 @@ subroutine sub(x, y)
end end
end interface end interface
!ERROR: Two symbols have the same BIND(C) name 'aaa' !Acceptable (as an extension)
procedure(proc), bind(c, name="aaa") :: pc1, pc2 procedure(proc), bind(c, name="aaa") :: pc1, pc2
!ERROR: BIND(C) procedure with NAME= specified can neither have POINTER attribute nor be a dummy procedure !ERROR: BIND(C) procedure with NAME= specified can neither have POINTER attribute nor be a dummy procedure

View File

@ -0,0 +1,13 @@
! RUN: %python %S/test_errors.py %s %flang_fc1
! Check for C1552
program main
contains
subroutine internal1() bind(c) ! ok
end subroutine
!ERROR: An internal procedure may not have a BIND(C,NAME=) binding label
subroutine internal2() bind(c,name="internal2")
end subroutine
!ERROR: An internal procedure may not have a BIND(C,NAME=) binding label
subroutine internal3() bind(c,name="")
end subroutine
end

View File

@ -5,17 +5,17 @@ module m
integer :: x, y, z, w, i, j, k integer :: x, y, z, w, i, j, k
!ERROR: Two symbols have the same BIND(C) name 'aa' !ERROR: Two entities have the same BIND(C) name 'aa'
common /blk1/ x, /blk2/ y common /blk1/ x, /blk2/ y
bind(c, name="aa") :: /blk1/, /blk2/ bind(c, name="aa") :: /blk1/, /blk2/
integer :: t integer :: t
!ERROR: Two symbols have the same BIND(C) name 'bb' !ERROR: Two entities have the same BIND(C) name 'bb'
common /blk3/ z common /blk3/ z
bind(c, name="bb") :: /blk3/, t bind(c, name="bb") :: /blk3/, t
integer :: t2 integer :: t2
!ERROR: Two symbols have the same BIND(C) name 'cc' !ERROR: Two entities have the same BIND(C) name 'cc'
common /blk4/ w common /blk4/ w
bind(c, name="cc") :: t2, /blk4/ bind(c, name="cc") :: t2, /blk4/
@ -24,7 +24,7 @@ module m
bind(c, name="dd") :: /blk5/ bind(c, name="dd") :: /blk5/
bind(c, name="ee") :: /blk5/ bind(c, name="ee") :: /blk5/
!ERROR: Two symbols have the same BIND(C) name 'ff' !ERROR: Two entities have the same BIND(C) name 'ff'
common /blk6/ j, /blk7/ k common /blk6/ j, /blk7/ k
bind(c, name="ff") :: /blk6/ bind(c, name="ff") :: /blk6/
bind(c, name="ff") :: /blk7/ bind(c, name="ff") :: /blk7/
@ -34,7 +34,7 @@ module m
bind(c, name="gg") :: s1 bind(c, name="gg") :: s1
bind(c, name="hh") :: s1 bind(c, name="hh") :: s1
!ERROR: Two symbols have the same BIND(C) name 'ii' !ERROR: Two entities have the same BIND(C) name 'ii'
integer :: s2, s3 integer :: s2, s3
bind(c, name="ii") :: s2 bind(c, name="ii") :: s2
bind(c, name="ii") :: s3 bind(c, name="ii") :: s3
@ -66,6 +66,6 @@ module a
end module end module
module b module b
!ERROR: Two symbols have the same BIND(C) name 'int' !ERROR: Two entities have the same BIND(C) name 'int'
integer, bind(c, name="int") :: i integer, bind(c, name="int") :: i
end module end module