[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.
This commit is contained in:
parent
0f286f8a36
commit
f3c227b797
@ -374,6 +374,9 @@ end
|
||||
required, with warnings, even if it lacks the BIND(C) attribute.
|
||||
* A "mult-operand" in an expression can be preceded by a unary
|
||||
`+` or `-` operator.
|
||||
* `BIND(C, NAME="...", CDEFINED)` signifies that the storage for an
|
||||
interoperable variable will be allocated outside of Fortran,
|
||||
probably by a C or C++ external definition.
|
||||
|
||||
### Extensions supported when enabled by options
|
||||
|
||||
|
@ -1296,10 +1296,13 @@ struct AcImpliedDo {
|
||||
};
|
||||
|
||||
// R808 language-binding-spec ->
|
||||
// BIND ( C [, NAME = scalar-default-char-constant-expr] )
|
||||
// BIND ( C [, NAME = scalar-default-char-constant-expr ]
|
||||
// [, CDEFINED ] )
|
||||
// R1528 proc-language-binding-spec -> language-binding-spec
|
||||
WRAPPER_CLASS(
|
||||
LanguageBindingSpec, std::optional<ScalarDefaultCharConstantExpr>);
|
||||
struct LanguageBindingSpec {
|
||||
TUPLE_CLASS_BOILERPLATE(LanguageBindingSpec);
|
||||
std::tuple<std::optional<ScalarDefaultCharConstantExpr>, bool> t;
|
||||
};
|
||||
|
||||
// R852 named-constant-def -> named-constant = constant-expr
|
||||
struct NamedConstantDef {
|
||||
|
@ -115,10 +115,13 @@ public:
|
||||
bool isExplicitBindName() const { return isExplicitBindName_; }
|
||||
void set_bindName(std::string &&name) { bindName_ = std::move(name); }
|
||||
void set_isExplicitBindName(bool yes) { isExplicitBindName_ = yes; }
|
||||
bool isCDefined() const { return isCDefined_; }
|
||||
void set_isCDefined(bool yes) { isCDefined_ = yes; }
|
||||
|
||||
private:
|
||||
std::optional<std::string> bindName_;
|
||||
bool isExplicitBindName_{false};
|
||||
bool isCDefined_{false};
|
||||
};
|
||||
|
||||
// Device type specific OpenACC routine information
|
||||
@ -814,6 +817,7 @@ public:
|
||||
void SetBindName(std::string &&);
|
||||
bool GetIsExplicitBindName() const;
|
||||
void SetIsExplicitBindName(bool);
|
||||
void SetIsCDefined(bool);
|
||||
bool IsFuncResult() const;
|
||||
bool IsObjectArray() const;
|
||||
const ArraySpec *GetShape() const;
|
||||
|
@ -735,7 +735,8 @@ TYPE_PARSER(construct<AccessSpec>("PUBLIC" >> pure(AccessSpec::Kind::Public)) ||
|
||||
// BIND ( C [, NAME = scalar-default-char-constant-expr] )
|
||||
// R1528 proc-language-binding-spec -> language-binding-spec
|
||||
TYPE_PARSER(construct<LanguageBindingSpec>(
|
||||
"BIND ( C" >> maybe(", NAME =" >> scalarDefaultCharConstantExpr) / ")"))
|
||||
"BIND ( C" >> maybe(", NAME =" >> scalarDefaultCharConstantExpr),
|
||||
(", CDEFINED" >> pure(true) || pure(false)) / ")"))
|
||||
|
||||
// R809 coarray-spec -> deferred-coshape-spec-list | explicit-coshape-spec
|
||||
// N.B. Bracketed here rather than around references, for consistency with
|
||||
|
@ -524,7 +524,13 @@ public:
|
||||
Word("NULL()");
|
||||
}
|
||||
void Unparse(const LanguageBindingSpec &x) { // R808 & R1528
|
||||
Word("BIND(C"), Walk(", NAME=", x.v), Put(')');
|
||||
Word("BIND(C");
|
||||
Walk(
|
||||
", NAME=", std::get<std::optional<ScalarDefaultCharConstantExpr>>(x.t));
|
||||
if (std::get<bool>(x.t)) {
|
||||
Word(", CDEFINED");
|
||||
}
|
||||
Put(')');
|
||||
}
|
||||
void Unparse(const CoarraySpec &x) { // R809
|
||||
common::visit(common::visitors{
|
||||
|
@ -315,6 +315,7 @@ private:
|
||||
bool IsConflictingAttr(Attr);
|
||||
|
||||
MaybeExpr bindName_; // from BIND(C, NAME="...")
|
||||
bool isCDefined_{false}; // BIND(C, NAME="...", CDEFINED) extension
|
||||
std::optional<SourceName> passName_; // from PASS(...)
|
||||
};
|
||||
|
||||
@ -1762,6 +1763,7 @@ Attrs AttrsVisitor::EndAttrs() {
|
||||
cudaDataAttr_.reset();
|
||||
passName_ = std::nullopt;
|
||||
bindName_.reset();
|
||||
isCDefined_ = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1783,6 +1785,7 @@ void AttrsVisitor::SetBindNameOn(Symbol &symbol) {
|
||||
!symbol.attrs().test(Attr::BIND_C)) {
|
||||
return;
|
||||
}
|
||||
symbol.SetIsCDefined(isCDefined_);
|
||||
std::optional<std::string> label{
|
||||
evaluate::GetScalarConstantValue<evaluate::Ascii>(bindName_)};
|
||||
// 18.9.2(2): discard leading and trailing blanks
|
||||
@ -1820,9 +1823,12 @@ void AttrsVisitor::SetBindNameOn(Symbol &symbol) {
|
||||
|
||||
void AttrsVisitor::Post(const parser::LanguageBindingSpec &x) {
|
||||
if (CheckAndSet(Attr::BIND_C)) {
|
||||
if (x.v) {
|
||||
bindName_ = EvaluateExpr(*x.v);
|
||||
if (const auto &name{
|
||||
std::get<std::optional<parser::ScalarDefaultCharConstantExpr>>(
|
||||
x.t)}) {
|
||||
bindName_ = EvaluateExpr(*name);
|
||||
}
|
||||
isCDefined_ = std::get<bool>(x.t);
|
||||
}
|
||||
}
|
||||
bool AttrsVisitor::Pre(const parser::IntentSpec &x) {
|
||||
@ -4056,7 +4062,9 @@ void SubprogramVisitor::CreateEntry(
|
||||
Attrs attrs;
|
||||
const auto &suffix{std::get<std::optional<parser::Suffix>>(stmt.t)};
|
||||
bool hasGlobalBindingName{outer.IsGlobal() && suffix && suffix->binding &&
|
||||
suffix->binding->v.has_value()};
|
||||
std::get<std::optional<parser::ScalarDefaultCharConstantExpr>>(
|
||||
suffix->binding->t)
|
||||
.has_value()};
|
||||
if (!hasGlobalBindingName) {
|
||||
if (Symbol * extant{FindSymbol(outer, entryName)}) {
|
||||
if (!HandlePreviousCalls(entryName, *extant, subpFlag)) {
|
||||
@ -4440,7 +4448,10 @@ Symbol &SubprogramVisitor::PushSubprogramScope(const parser::Name &name,
|
||||
bool hasModulePrefix) {
|
||||
Symbol *symbol{GetSpecificFromGeneric(name)};
|
||||
if (!symbol) {
|
||||
if (bindingSpec && currScope().IsGlobal() && bindingSpec->v) {
|
||||
if (bindingSpec && currScope().IsGlobal() &&
|
||||
std::get<std::optional<parser::ScalarDefaultCharConstantExpr>>(
|
||||
bindingSpec->t)
|
||||
.has_value()) {
|
||||
// Create this new top-level subprogram with a binding label
|
||||
// in a new global scope, so that its symbol's name won't clash
|
||||
// with another symbol that has a distinct binding label.
|
||||
@ -5670,7 +5681,9 @@ bool DeclarationVisitor::Pre(const parser::ProcedureDeclarationStmt &x) {
|
||||
const auto &procAttrSpec{std::get<std::list<parser::ProcAttrSpec>>(x.t)};
|
||||
for (const parser::ProcAttrSpec &procAttr : procAttrSpec) {
|
||||
if (auto *bindC{std::get_if<parser::LanguageBindingSpec>(&procAttr.u)}) {
|
||||
if (bindC->v.has_value()) {
|
||||
if (std::get<std::optional<parser::ScalarDefaultCharConstantExpr>>(
|
||||
bindC->t)
|
||||
.has_value()) {
|
||||
if (std::get<std::list<parser::ProcDecl>>(x.t).size() > 1) {
|
||||
Say(context().location().value(),
|
||||
"A procedure declaration statement with a binding name may not declare multiple procedures"_err_en_US);
|
||||
|
@ -375,6 +375,18 @@ void Symbol::SetIsExplicitBindName(bool yes) {
|
||||
details_);
|
||||
}
|
||||
|
||||
void Symbol::SetIsCDefined(bool yes) {
|
||||
common::visit(
|
||||
[&](auto &x) {
|
||||
if constexpr (HasBindName<decltype(&x)>) {
|
||||
x.set_isCDefined(yes);
|
||||
} else {
|
||||
DIE("CDEFINED not allowed on this kind of symbol");
|
||||
}
|
||||
},
|
||||
details_);
|
||||
}
|
||||
|
||||
bool Symbol::IsFuncResult() const {
|
||||
return common::visit(
|
||||
common::visitors{[](const EntityDetails &x) { return x.isFuncResult(); },
|
||||
@ -422,6 +434,7 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const EntityDetails &x) {
|
||||
os << " type: " << *x.type();
|
||||
}
|
||||
DumpOptional(os, "bindName", x.bindName());
|
||||
DumpBool(os, "CDEFINED", x.isCDefined());
|
||||
return os;
|
||||
}
|
||||
|
||||
|
@ -84,3 +84,8 @@ module m3
|
||||
end
|
||||
end interface
|
||||
end
|
||||
|
||||
!CHECK: cdef01, BIND(C), PUBLIC size=4 offset=0: ObjectEntity type: REAL(4) bindName:cDef01 CDEFINED
|
||||
module m4
|
||||
real, bind(c, name='cDef01', cdefined) :: cdef01
|
||||
end
|
||||
|
Loading…
x
Reference in New Issue
Block a user