[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.
|
required, with warnings, even if it lacks the BIND(C) attribute.
|
||||||
* A "mult-operand" in an expression can be preceded by a unary
|
* A "mult-operand" in an expression can be preceded by a unary
|
||||||
`+` or `-` operator.
|
`+` 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
|
### Extensions supported when enabled by options
|
||||||
|
|
||||||
|
@ -1296,10 +1296,13 @@ struct AcImpliedDo {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// R808 language-binding-spec ->
|
// 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
|
// R1528 proc-language-binding-spec -> language-binding-spec
|
||||||
WRAPPER_CLASS(
|
struct LanguageBindingSpec {
|
||||||
LanguageBindingSpec, std::optional<ScalarDefaultCharConstantExpr>);
|
TUPLE_CLASS_BOILERPLATE(LanguageBindingSpec);
|
||||||
|
std::tuple<std::optional<ScalarDefaultCharConstantExpr>, bool> t;
|
||||||
|
};
|
||||||
|
|
||||||
// R852 named-constant-def -> named-constant = constant-expr
|
// R852 named-constant-def -> named-constant = constant-expr
|
||||||
struct NamedConstantDef {
|
struct NamedConstantDef {
|
||||||
|
@ -115,10 +115,13 @@ public:
|
|||||||
bool isExplicitBindName() const { return isExplicitBindName_; }
|
bool isExplicitBindName() const { return isExplicitBindName_; }
|
||||||
void set_bindName(std::string &&name) { bindName_ = std::move(name); }
|
void set_bindName(std::string &&name) { bindName_ = std::move(name); }
|
||||||
void set_isExplicitBindName(bool yes) { isExplicitBindName_ = yes; }
|
void set_isExplicitBindName(bool yes) { isExplicitBindName_ = yes; }
|
||||||
|
bool isCDefined() const { return isCDefined_; }
|
||||||
|
void set_isCDefined(bool yes) { isCDefined_ = yes; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::optional<std::string> bindName_;
|
std::optional<std::string> bindName_;
|
||||||
bool isExplicitBindName_{false};
|
bool isExplicitBindName_{false};
|
||||||
|
bool isCDefined_{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Device type specific OpenACC routine information
|
// Device type specific OpenACC routine information
|
||||||
@ -814,6 +817,7 @@ public:
|
|||||||
void SetBindName(std::string &&);
|
void SetBindName(std::string &&);
|
||||||
bool GetIsExplicitBindName() const;
|
bool GetIsExplicitBindName() const;
|
||||||
void SetIsExplicitBindName(bool);
|
void SetIsExplicitBindName(bool);
|
||||||
|
void SetIsCDefined(bool);
|
||||||
bool IsFuncResult() const;
|
bool IsFuncResult() const;
|
||||||
bool IsObjectArray() const;
|
bool IsObjectArray() const;
|
||||||
const ArraySpec *GetShape() 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] )
|
// BIND ( C [, NAME = scalar-default-char-constant-expr] )
|
||||||
// R1528 proc-language-binding-spec -> language-binding-spec
|
// R1528 proc-language-binding-spec -> language-binding-spec
|
||||||
TYPE_PARSER(construct<LanguageBindingSpec>(
|
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
|
// R809 coarray-spec -> deferred-coshape-spec-list | explicit-coshape-spec
|
||||||
// N.B. Bracketed here rather than around references, for consistency with
|
// N.B. Bracketed here rather than around references, for consistency with
|
||||||
|
@ -524,7 +524,13 @@ public:
|
|||||||
Word("NULL()");
|
Word("NULL()");
|
||||||
}
|
}
|
||||||
void Unparse(const LanguageBindingSpec &x) { // R808 & R1528
|
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
|
void Unparse(const CoarraySpec &x) { // R809
|
||||||
common::visit(common::visitors{
|
common::visit(common::visitors{
|
||||||
|
@ -315,6 +315,7 @@ private:
|
|||||||
bool IsConflictingAttr(Attr);
|
bool IsConflictingAttr(Attr);
|
||||||
|
|
||||||
MaybeExpr bindName_; // from BIND(C, NAME="...")
|
MaybeExpr bindName_; // from BIND(C, NAME="...")
|
||||||
|
bool isCDefined_{false}; // BIND(C, NAME="...", CDEFINED) extension
|
||||||
std::optional<SourceName> passName_; // from PASS(...)
|
std::optional<SourceName> passName_; // from PASS(...)
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1762,6 +1763,7 @@ Attrs AttrsVisitor::EndAttrs() {
|
|||||||
cudaDataAttr_.reset();
|
cudaDataAttr_.reset();
|
||||||
passName_ = std::nullopt;
|
passName_ = std::nullopt;
|
||||||
bindName_.reset();
|
bindName_.reset();
|
||||||
|
isCDefined_ = false;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1783,6 +1785,7 @@ void AttrsVisitor::SetBindNameOn(Symbol &symbol) {
|
|||||||
!symbol.attrs().test(Attr::BIND_C)) {
|
!symbol.attrs().test(Attr::BIND_C)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
symbol.SetIsCDefined(isCDefined_);
|
||||||
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
|
// 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) {
|
void AttrsVisitor::Post(const parser::LanguageBindingSpec &x) {
|
||||||
if (CheckAndSet(Attr::BIND_C)) {
|
if (CheckAndSet(Attr::BIND_C)) {
|
||||||
if (x.v) {
|
if (const auto &name{
|
||||||
bindName_ = EvaluateExpr(*x.v);
|
std::get<std::optional<parser::ScalarDefaultCharConstantExpr>>(
|
||||||
|
x.t)}) {
|
||||||
|
bindName_ = EvaluateExpr(*name);
|
||||||
}
|
}
|
||||||
|
isCDefined_ = std::get<bool>(x.t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool AttrsVisitor::Pre(const parser::IntentSpec &x) {
|
bool AttrsVisitor::Pre(const parser::IntentSpec &x) {
|
||||||
@ -4056,7 +4062,9 @@ void SubprogramVisitor::CreateEntry(
|
|||||||
Attrs attrs;
|
Attrs attrs;
|
||||||
const auto &suffix{std::get<std::optional<parser::Suffix>>(stmt.t)};
|
const auto &suffix{std::get<std::optional<parser::Suffix>>(stmt.t)};
|
||||||
bool hasGlobalBindingName{outer.IsGlobal() && suffix && suffix->binding &&
|
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 (!hasGlobalBindingName) {
|
||||||
if (Symbol * extant{FindSymbol(outer, entryName)}) {
|
if (Symbol * extant{FindSymbol(outer, entryName)}) {
|
||||||
if (!HandlePreviousCalls(entryName, *extant, subpFlag)) {
|
if (!HandlePreviousCalls(entryName, *extant, subpFlag)) {
|
||||||
@ -4440,7 +4448,10 @@ Symbol &SubprogramVisitor::PushSubprogramScope(const parser::Name &name,
|
|||||||
bool hasModulePrefix) {
|
bool hasModulePrefix) {
|
||||||
Symbol *symbol{GetSpecificFromGeneric(name)};
|
Symbol *symbol{GetSpecificFromGeneric(name)};
|
||||||
if (!symbol) {
|
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
|
// Create this new top-level subprogram with a binding label
|
||||||
// in a new global scope, so that its symbol's name won't clash
|
// in a new global scope, so that its symbol's name won't clash
|
||||||
// with another symbol that has a distinct binding label.
|
// 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)};
|
const auto &procAttrSpec{std::get<std::list<parser::ProcAttrSpec>>(x.t)};
|
||||||
for (const parser::ProcAttrSpec &procAttr : procAttrSpec) {
|
for (const parser::ProcAttrSpec &procAttr : procAttrSpec) {
|
||||||
if (auto *bindC{std::get_if<parser::LanguageBindingSpec>(&procAttr.u)}) {
|
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) {
|
if (std::get<std::list<parser::ProcDecl>>(x.t).size() > 1) {
|
||||||
Say(context().location().value(),
|
Say(context().location().value(),
|
||||||
"A procedure declaration statement with a binding name may not declare multiple procedures"_err_en_US);
|
"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_);
|
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 {
|
bool Symbol::IsFuncResult() const {
|
||||||
return common::visit(
|
return common::visit(
|
||||||
common::visitors{[](const EntityDetails &x) { return x.isFuncResult(); },
|
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();
|
os << " type: " << *x.type();
|
||||||
}
|
}
|
||||||
DumpOptional(os, "bindName", x.bindName());
|
DumpOptional(os, "bindName", x.bindName());
|
||||||
|
DumpBool(os, "CDEFINED", x.isCDefined());
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,3 +84,8 @@ module m3
|
|||||||
end
|
end
|
||||||
end interface
|
end interface
|
||||||
end
|
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