Skip to content

Commit f3c227b

Browse files
authored
[flang] Support BIND(C, NAME="...", CDEFINED) extension (#94402)
This CDEFINED keyword extension to a language-binding-spec signifies that static storage for an interoperable variable will be allocated outside of Fortran, probably by a C/C++ external object definition.
1 parent 0f286f8 commit f3c227b

File tree

8 files changed

+58
-10
lines changed

8 files changed

+58
-10
lines changed

flang/docs/Extensions.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,9 @@ end
374374
required, with warnings, even if it lacks the BIND(C) attribute.
375375
* A "mult-operand" in an expression can be preceded by a unary
376376
`+` or `-` operator.
377+
* `BIND(C, NAME="...", CDEFINED)` signifies that the storage for an
378+
interoperable variable will be allocated outside of Fortran,
379+
probably by a C or C++ external definition.
377380

378381
### Extensions supported when enabled by options
379382

flang/include/flang/Parser/parse-tree.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1296,10 +1296,13 @@ struct AcImpliedDo {
12961296
};
12971297

12981298
// R808 language-binding-spec ->
1299-
// BIND ( C [, NAME = scalar-default-char-constant-expr] )
1299+
// BIND ( C [, NAME = scalar-default-char-constant-expr ]
1300+
// [, CDEFINED ] )
13001301
// R1528 proc-language-binding-spec -> language-binding-spec
1301-
WRAPPER_CLASS(
1302-
LanguageBindingSpec, std::optional<ScalarDefaultCharConstantExpr>);
1302+
struct LanguageBindingSpec {
1303+
TUPLE_CLASS_BOILERPLATE(LanguageBindingSpec);
1304+
std::tuple<std::optional<ScalarDefaultCharConstantExpr>, bool> t;
1305+
};
13031306

13041307
// R852 named-constant-def -> named-constant = constant-expr
13051308
struct NamedConstantDef {

flang/include/flang/Semantics/symbol.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,13 @@ class WithBindName {
115115
bool isExplicitBindName() const { return isExplicitBindName_; }
116116
void set_bindName(std::string &&name) { bindName_ = std::move(name); }
117117
void set_isExplicitBindName(bool yes) { isExplicitBindName_ = yes; }
118+
bool isCDefined() const { return isCDefined_; }
119+
void set_isCDefined(bool yes) { isCDefined_ = yes; }
118120

119121
private:
120122
std::optional<std::string> bindName_;
121123
bool isExplicitBindName_{false};
124+
bool isCDefined_{false};
122125
};
123126

124127
// Device type specific OpenACC routine information
@@ -814,6 +817,7 @@ class Symbol {
814817
void SetBindName(std::string &&);
815818
bool GetIsExplicitBindName() const;
816819
void SetIsExplicitBindName(bool);
820+
void SetIsCDefined(bool);
817821
bool IsFuncResult() const;
818822
bool IsObjectArray() const;
819823
const ArraySpec *GetShape() const;

flang/lib/Parser/Fortran-parsers.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -735,7 +735,8 @@ TYPE_PARSER(construct<AccessSpec>("PUBLIC" >> pure(AccessSpec::Kind::Public)) ||
735735
// BIND ( C [, NAME = scalar-default-char-constant-expr] )
736736
// R1528 proc-language-binding-spec -> language-binding-spec
737737
TYPE_PARSER(construct<LanguageBindingSpec>(
738-
"BIND ( C" >> maybe(", NAME =" >> scalarDefaultCharConstantExpr) / ")"))
738+
"BIND ( C" >> maybe(", NAME =" >> scalarDefaultCharConstantExpr),
739+
(", CDEFINED" >> pure(true) || pure(false)) / ")"))
739740

740741
// R809 coarray-spec -> deferred-coshape-spec-list | explicit-coshape-spec
741742
// N.B. Bracketed here rather than around references, for consistency with

flang/lib/Parser/unparse.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,13 @@ class UnparseVisitor {
524524
Word("NULL()");
525525
}
526526
void Unparse(const LanguageBindingSpec &x) { // R808 & R1528
527-
Word("BIND(C"), Walk(", NAME=", x.v), Put(')');
527+
Word("BIND(C");
528+
Walk(
529+
", NAME=", std::get<std::optional<ScalarDefaultCharConstantExpr>>(x.t));
530+
if (std::get<bool>(x.t)) {
531+
Word(", CDEFINED");
532+
}
533+
Put(')');
528534
}
529535
void Unparse(const CoarraySpec &x) { // R809
530536
common::visit(common::visitors{

flang/lib/Semantics/resolve-names.cpp

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@ class AttrsVisitor : public virtual BaseVisitor {
315315
bool IsConflictingAttr(Attr);
316316

317317
MaybeExpr bindName_; // from BIND(C, NAME="...")
318+
bool isCDefined_{false}; // BIND(C, NAME="...", CDEFINED) extension
318319
std::optional<SourceName> passName_; // from PASS(...)
319320
};
320321

@@ -1762,6 +1763,7 @@ Attrs AttrsVisitor::EndAttrs() {
17621763
cudaDataAttr_.reset();
17631764
passName_ = std::nullopt;
17641765
bindName_.reset();
1766+
isCDefined_ = false;
17651767
return result;
17661768
}
17671769

@@ -1783,6 +1785,7 @@ void AttrsVisitor::SetBindNameOn(Symbol &symbol) {
17831785
!symbol.attrs().test(Attr::BIND_C)) {
17841786
return;
17851787
}
1788+
symbol.SetIsCDefined(isCDefined_);
17861789
std::optional<std::string> label{
17871790
evaluate::GetScalarConstantValue<evaluate::Ascii>(bindName_)};
17881791
// 18.9.2(2): discard leading and trailing blanks
@@ -1820,9 +1823,12 @@ void AttrsVisitor::SetBindNameOn(Symbol &symbol) {
18201823

18211824
void AttrsVisitor::Post(const parser::LanguageBindingSpec &x) {
18221825
if (CheckAndSet(Attr::BIND_C)) {
1823-
if (x.v) {
1824-
bindName_ = EvaluateExpr(*x.v);
1826+
if (const auto &name{
1827+
std::get<std::optional<parser::ScalarDefaultCharConstantExpr>>(
1828+
x.t)}) {
1829+
bindName_ = EvaluateExpr(*name);
18251830
}
1831+
isCDefined_ = std::get<bool>(x.t);
18261832
}
18271833
}
18281834
bool AttrsVisitor::Pre(const parser::IntentSpec &x) {
@@ -4056,7 +4062,9 @@ void SubprogramVisitor::CreateEntry(
40564062
Attrs attrs;
40574063
const auto &suffix{std::get<std::optional<parser::Suffix>>(stmt.t)};
40584064
bool hasGlobalBindingName{outer.IsGlobal() && suffix && suffix->binding &&
4059-
suffix->binding->v.has_value()};
4065+
std::get<std::optional<parser::ScalarDefaultCharConstantExpr>>(
4066+
suffix->binding->t)
4067+
.has_value()};
40604068
if (!hasGlobalBindingName) {
40614069
if (Symbol * extant{FindSymbol(outer, entryName)}) {
40624070
if (!HandlePreviousCalls(entryName, *extant, subpFlag)) {
@@ -4440,7 +4448,10 @@ Symbol &SubprogramVisitor::PushSubprogramScope(const parser::Name &name,
44404448
bool hasModulePrefix) {
44414449
Symbol *symbol{GetSpecificFromGeneric(name)};
44424450
if (!symbol) {
4443-
if (bindingSpec && currScope().IsGlobal() && bindingSpec->v) {
4451+
if (bindingSpec && currScope().IsGlobal() &&
4452+
std::get<std::optional<parser::ScalarDefaultCharConstantExpr>>(
4453+
bindingSpec->t)
4454+
.has_value()) {
44444455
// Create this new top-level subprogram with a binding label
44454456
// in a new global scope, so that its symbol's name won't clash
44464457
// with another symbol that has a distinct binding label.
@@ -5670,7 +5681,9 @@ bool DeclarationVisitor::Pre(const parser::ProcedureDeclarationStmt &x) {
56705681
const auto &procAttrSpec{std::get<std::list<parser::ProcAttrSpec>>(x.t)};
56715682
for (const parser::ProcAttrSpec &procAttr : procAttrSpec) {
56725683
if (auto *bindC{std::get_if<parser::LanguageBindingSpec>(&procAttr.u)}) {
5673-
if (bindC->v.has_value()) {
5684+
if (std::get<std::optional<parser::ScalarDefaultCharConstantExpr>>(
5685+
bindC->t)
5686+
.has_value()) {
56745687
if (std::get<std::list<parser::ProcDecl>>(x.t).size() > 1) {
56755688
Say(context().location().value(),
56765689
"A procedure declaration statement with a binding name may not declare multiple procedures"_err_en_US);

flang/lib/Semantics/symbol.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,18 @@ void Symbol::SetIsExplicitBindName(bool yes) {
375375
details_);
376376
}
377377

378+
void Symbol::SetIsCDefined(bool yes) {
379+
common::visit(
380+
[&](auto &x) {
381+
if constexpr (HasBindName<decltype(&x)>) {
382+
x.set_isCDefined(yes);
383+
} else {
384+
DIE("CDEFINED not allowed on this kind of symbol");
385+
}
386+
},
387+
details_);
388+
}
389+
378390
bool Symbol::IsFuncResult() const {
379391
return common::visit(
380392
common::visitors{[](const EntityDetails &x) { return x.isFuncResult(); },
@@ -422,6 +434,7 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const EntityDetails &x) {
422434
os << " type: " << *x.type();
423435
}
424436
DumpOptional(os, "bindName", x.bindName());
437+
DumpBool(os, "CDEFINED", x.isCDefined());
425438
return os;
426439
}
427440

flang/test/Semantics/bind-c16.f90

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,8 @@ subroutine s3() bind(c,name='foo')
8484
end
8585
end interface
8686
end
87+
88+
!CHECK: cdef01, BIND(C), PUBLIC size=4 offset=0: ObjectEntity type: REAL(4) bindName:cDef01 CDEFINED
89+
module m4
90+
real, bind(c, name='cDef01', cdefined) :: cdef01
91+
end

0 commit comments

Comments
 (0)