Skip to content

Commit 066b7ec

Browse files
committed
[flang] Soften interoperability error when standard allows
The standard doesn't require that an interoperable procedure's dummy arguments have interoperable derived types in some cases. Although nearly all extant Fortran compilers emit errors, some don't, and things should work; so reduce the current fatal error message to an optional portability warning. Fixes #115010.
1 parent 850d42f commit 066b7ec

File tree

3 files changed

+30
-8
lines changed

3 files changed

+30
-8
lines changed

flang/include/flang/Evaluate/tools.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,8 +1103,7 @@ extern template semantics::UnorderedSymbolSet CollectCudaSymbols(
11031103
bool HasVectorSubscript(const Expr<SomeType> &);
11041104

11051105
// Utilities for attaching the location of the declaration of a symbol
1106-
// of interest to a message, if both pointers are non-null. Handles
1107-
// the case of USE association gracefully.
1106+
// of interest to a message. Handles the case of USE association gracefully.
11081107
parser::Message *AttachDeclaration(parser::Message &, const Symbol &);
11091108
parser::Message *AttachDeclaration(parser::Message *, const Symbol &);
11101109
template <typename MESSAGES, typename... A>

flang/lib/Semantics/check-declarations.cpp

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,8 @@ class CheckHelper {
147147
void CheckProcedureAssemblyName(const Symbol &symbol);
148148
void CheckExplicitSave(const Symbol &);
149149
parser::Messages WhyNotInteroperableDerivedType(const Symbol &);
150-
parser::Messages WhyNotInteroperableObject(const Symbol &);
150+
parser::Messages WhyNotInteroperableObject(
151+
const Symbol &, bool allowNonInteroperableType = false);
151152
parser::Messages WhyNotInteroperableFunctionResult(const Symbol &);
152153
parser::Messages WhyNotInteroperableProcedure(const Symbol &, bool isError);
153154
void CheckBindC(const Symbol &);
@@ -2999,7 +3000,8 @@ parser::Messages CheckHelper::WhyNotInteroperableDerivedType(
29993000
return msgs;
30003001
}
30013002

3002-
parser::Messages CheckHelper::WhyNotInteroperableObject(const Symbol &symbol) {
3003+
parser::Messages CheckHelper::WhyNotInteroperableObject(
3004+
const Symbol &symbol, bool allowNonInteroperableType) {
30033005
parser::Messages msgs;
30043006
if (examinedByWhyNotInteroperable_.find(symbol) !=
30053007
examinedByWhyNotInteroperable_.end()) {
@@ -3035,14 +3037,19 @@ parser::Messages CheckHelper::WhyNotInteroperableObject(const Symbol &symbol) {
30353037
if (const auto *type{symbol.GetType()}) {
30363038
const auto *derived{type->AsDerived()};
30373039
if (derived && !derived->typeSymbol().attrs().test(Attr::BIND_C)) {
3038-
if (!context_.IsEnabled(
3039-
common::LanguageFeature::NonBindCInteroperability)) {
3040+
if (allowNonInteroperableType) { // portability warning only
3041+
evaluate::AttachDeclaration(
3042+
context_.Warn(common::UsageWarning::Portability, symbol.name(),
3043+
"The derived type of this interoperable object should be BIND(C)"_port_en_US),
3044+
derived->typeSymbol());
3045+
} else if (!context_.IsEnabled(
3046+
common::LanguageFeature::NonBindCInteroperability)) {
30403047
msgs.Say(symbol.name(),
30413048
"The derived type of an interoperable object must be BIND(C)"_err_en_US)
30423049
.Attach(derived->typeSymbol().name(), "Non-BIND(C) type"_en_US);
30433050
} else if (auto bad{
30443051
WhyNotInteroperableDerivedType(derived->typeSymbol())};
3045-
bad.AnyFatalError()) {
3052+
bad.AnyFatalError()) {
30463053
bad.AttachTo(
30473054
msgs.Say(symbol.name(),
30483055
"The derived type of an interoperable object must be interoperable, but is not"_err_en_US)
@@ -3176,7 +3183,13 @@ parser::Messages CheckHelper::WhyNotInteroperableProcedure(
31763183
"A dummy procedure of an interoperable procedure should be BIND(C)"_warn_en_US);
31773184
}
31783185
} else if (dummy->has<ObjectEntityDetails>()) {
3179-
dummyMsgs = WhyNotInteroperableObject(*dummy);
3186+
// Emit only optional portability warnings for non-interoperable
3187+
// types when the dummy argument is not VALUE and will be implemented
3188+
// on the C side by either a cdesc_t * or a void *. F'2023 18.3.7 (5)
3189+
bool allowNonInteroperableType{!dummy->attrs().test(Attr::VALUE) &&
3190+
(IsDescriptor(*dummy) || IsAssumedType(*dummy))};
3191+
dummyMsgs =
3192+
WhyNotInteroperableObject(*dummy, allowNonInteroperableType);
31803193
} else {
31813194
CheckBindC(*dummy);
31823195
}

flang/test/Semantics/bind-c17.f90

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
! RUN: %python %S/test_errors.py %s %flang_fc1 -pedantic -Werror
2+
module m
3+
type a ! not BIND(C)
4+
end type
5+
contains
6+
subroutine sub(x) bind(c)
7+
!PORTABILITY: The derived type of this interoperable object should be BIND(C)
8+
type(a), pointer, intent(in) :: x
9+
end
10+
end

0 commit comments

Comments
 (0)