Skip to content

Commit 930c2d9

Browse files
authored
[flang] Adjust %REF/%VAL semantic checking (#93718)
In accordance with other compilers, don't require that a %REF() actual argument be a modifiable variable. And move the %REF/%VAL semantic checks to Semantics/check-call.cpp, where one would expect to find them. Fixes #93489.
1 parent 74f4034 commit 930c2d9

File tree

5 files changed

+42
-20
lines changed

5 files changed

+42
-20
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3212,7 +3212,7 @@ WRAPPER_CLASS(AltReturnSpec, Label);
32123212
// expr | variable | procedure-name | proc-component-ref |
32133213
// alt-return-spec
32143214
struct ActualArg {
3215-
WRAPPER_CLASS(PercentRef, Variable); // %REF(v) extension
3215+
WRAPPER_CLASS(PercentRef, Expr); // %REF(x) extension
32163216
WRAPPER_CLASS(PercentVal, Expr); // %VAL(x) extension
32173217
UNION_CLASS_BOILERPLATE(ActualArg);
32183218
ActualArg(Expr &&x) : u{common::Indirection<Expr>(std::move(x))} {}

flang/lib/Parser/program-parsers.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -472,8 +472,8 @@ TYPE_PARSER(construct<ActualArg>(expr) ||
472472
construct<ActualArg>(Parser<AltReturnSpec>{}) ||
473473
extension<LanguageFeature::PercentRefAndVal>(
474474
"nonstandard usage: %REF"_port_en_US,
475-
construct<ActualArg>(construct<ActualArg::PercentRef>(
476-
"%REF" >> parenthesized(variable)))) ||
475+
construct<ActualArg>(
476+
construct<ActualArg::PercentRef>("%REF" >> parenthesized(expr)))) ||
477477
extension<LanguageFeature::PercentRefAndVal>(
478478
"nonstandard usage: %VAL"_port_en_US,
479479
construct<ActualArg>(

flang/lib/Semantics/check-call.cpp

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ static void CheckImplicitInterfaceArg(evaluate::ActualArgument &arg,
3535
"Keyword '%s=' may not appear in a reference to a procedure with an implicit interface"_err_en_US,
3636
*kw);
3737
}
38-
if (auto type{arg.GetType()}) {
38+
auto type{arg.GetType()};
39+
if (type) {
3940
if (type->IsAssumedType()) {
4041
messages.Say(
4142
"Assumed type actual argument requires an explicit interface"_err_en_US);
@@ -49,6 +50,11 @@ static void CheckImplicitInterfaceArg(evaluate::ActualArgument &arg,
4950
}
5051
}
5152
}
53+
if (arg.isPercentVal() &&
54+
(!type || !type->IsLengthlessIntrinsicType() || arg.Rank() != 0)) {
55+
messages.Say(
56+
"%VAL argument must be a scalar numeric or logical expression"_err_en_US);
57+
}
5258
if (const auto *expr{arg.UnwrapExpr()}) {
5359
if (IsBOZLiteral(*expr)) {
5460
messages.Say("BOZ argument requires an explicit interface"_err_en_US);
@@ -314,7 +320,8 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
314320
SemanticsContext &context, evaluate::FoldingContext &foldingContext,
315321
const Scope *scope, const evaluate::SpecificIntrinsic *intrinsic,
316322
bool allowActualArgumentConversions, bool extentErrors,
317-
const characteristics::Procedure &procedure) {
323+
const characteristics::Procedure &procedure,
324+
const evaluate::ActualArgument &arg) {
318325

319326
// Basic type & rank checking
320327
parser::ContextualMessages &messages{foldingContext.messages()};
@@ -939,11 +946,25 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
939946
}
940947
}
941948

942-
// Breaking change warnings
949+
// Warning for breaking F'2023 change with character allocatables
943950
if (intrinsic && dummy.intent != common::Intent::In) {
944951
WarnOnDeferredLengthCharacterScalar(
945952
context, &actual, messages.at(), dummyName.c_str());
946953
}
954+
955+
// %VAL() and %REF() checking for explicit interface
956+
if ((arg.isPercentRef() || arg.isPercentVal()) &&
957+
dummy.IsPassedByDescriptor(procedure.IsBindC())) {
958+
messages.Say(
959+
"%VAL or %REF are not allowed for %s that must be passed by means of a descriptor"_err_en_US,
960+
dummyName);
961+
}
962+
if (arg.isPercentVal() &&
963+
(!actualType.type().IsLengthlessIntrinsicType() ||
964+
actualType.Rank() != 0)) {
965+
messages.Say(
966+
"%VAL argument must be a scalar numeric or logical expression"_err_en_US);
967+
}
947968
}
948969

949970
static void CheckProcedureArg(evaluate::ActualArgument &arg,
@@ -1152,7 +1173,7 @@ static void CheckExplicitInterfaceArg(evaluate::ActualArgument &arg,
11521173
object.type.Rank() == 0 && proc.IsElemental()};
11531174
CheckExplicitDataArg(object, dummyName, *expr, *type,
11541175
isElemental, context, foldingContext, scope, intrinsic,
1155-
allowActualArgumentConversions, extentErrors, proc);
1176+
allowActualArgumentConversions, extentErrors, proc, arg);
11561177
} else if (object.type.type().IsTypelessIntrinsicArgument() &&
11571178
IsBOZLiteral(*expr)) {
11581179
// ok

flang/lib/Semantics/expression.cpp

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4187,13 +4187,13 @@ void ArgumentAnalyzer::Analyze(
41874187
},
41884188
[&](const parser::AltReturnSpec &label) {
41894189
if (!isSubroutine) {
4190-
context_.Say("alternate return specification may not appear on"
4191-
" function reference"_err_en_US);
4190+
context_.Say(
4191+
"alternate return specification may not appear on function reference"_err_en_US);
41924192
}
41934193
actual = ActualArgument(label.v);
41944194
},
41954195
[&](const parser::ActualArg::PercentRef &percentRef) {
4196-
actual = AnalyzeVariable(percentRef.v);
4196+
actual = AnalyzeExpr(percentRef.v);
41974197
if (actual.has_value()) {
41984198
actual->set_isPercentRef();
41994199
}
@@ -4202,12 +4202,6 @@ void ArgumentAnalyzer::Analyze(
42024202
actual = AnalyzeExpr(percentVal.v);
42034203
if (actual.has_value()) {
42044204
actual->set_isPercentVal();
4205-
std::optional<DynamicType> type{actual->GetType()};
4206-
if (!type || !type->IsLengthlessIntrinsicType() ||
4207-
actual->Rank() != 0) {
4208-
context_.SayAt(percentVal.v,
4209-
"%VAL argument must be a scalar numerical or logical expression"_err_en_US);
4210-
}
42114205
}
42124206
},
42134207
},

flang/test/Semantics/call40.f90

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,22 @@ subroutine val_errors(array, string, polymorphic, derived)
99
character(*) :: string
1010
type(t) :: derived
1111
type(*) :: polymorphic
12-
!ERROR: %VAL argument must be a scalar numerical or logical expression
12+
interface
13+
subroutine foo5(a)
14+
integer a(:)
15+
end
16+
end interface
17+
!ERROR: %VAL argument must be a scalar numeric or logical expression
1318
call foo1(%val(array))
14-
!ERROR: %VAL argument must be a scalar numerical or logical expression
19+
!ERROR: %VAL argument must be a scalar numeric or logical expression
1520
call foo2(%val(string))
16-
!ERROR: %VAL argument must be a scalar numerical or logical expression
21+
!ERROR: %VAL argument must be a scalar numeric or logical expression
1722
call foo3(%val(derived))
18-
!ERROR: %VAL argument must be a scalar numerical or logical expression
1923
!ERROR: Assumed type actual argument requires an explicit interface
24+
!ERROR: %VAL argument must be a scalar numeric or logical expression
2025
call foo4(%val(polymorphic))
26+
!ERROR: %VAL or %REF are not allowed for dummy argument 'a=' that must be passed by means of a descriptor
27+
call foo5(%ref(array))
2128
end subroutine
2229

2330
subroutine val_ok()

0 commit comments

Comments
 (0)