@@ -1462,6 +1462,37 @@ static bool CheckMaxMinArgument(std::optional<parser::CharBlock> keyword,
1462
1462
return true ;
1463
1463
}
1464
1464
1465
+ static void CheckMaxMinA1A2Argument (const ActualArguments &arguments,
1466
+ std::set<parser::CharBlock> &set, parser::ContextualMessages &messages) {
1467
+ parser::CharBlock kwA1{" a1" , 2 };
1468
+ parser::CharBlock kwA2{" a2" , 2 };
1469
+ bool missingA1{set.find (kwA1) == set.end ()};
1470
+ bool missingA2{set.find (kwA2) == set.end ()};
1471
+
1472
+ if (arguments.size () > 1 ) {
1473
+ if (arguments.at (0 )->keyword ()) {
1474
+ // If the keyword is specified in the first argument, the following
1475
+ // arguments must have the keywords.
1476
+ if (missingA1 && missingA2) {
1477
+ messages.Say (" missing mandatory '%s=' and '%s=' arguments" _err_en_US,
1478
+ kwA1.ToString (), kwA2.ToString ());
1479
+ } else if (missingA1 && !missingA2) {
1480
+ messages.Say (
1481
+ " missing mandatory '%s=' argument" _err_en_US, kwA1.ToString ());
1482
+ } else if (!missingA1 && missingA2) {
1483
+ messages.Say (
1484
+ " missing mandatory '%s=' argument" _err_en_US, kwA2.ToString ());
1485
+ }
1486
+ } else if (arguments.at (1 )->keyword ()) {
1487
+ // No keyword is specified in the first argument.
1488
+ if (missingA1 && missingA2) {
1489
+ messages.Say (
1490
+ " missing mandatory '%s=' argument" _err_en_US, kwA2.ToString ());
1491
+ }
1492
+ }
1493
+ }
1494
+ }
1495
+
1465
1496
static bool CheckAtomicKind (const ActualArgument &arg,
1466
1497
const semantics::Scope *builtinsScope,
1467
1498
parser::ContextualMessages &messages) {
@@ -1570,6 +1601,17 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
1570
1601
}
1571
1602
}
1572
1603
1604
+ if (isMaxMin) {
1605
+ int nArgs{0 };
1606
+ // max() / max(x) is invalid
1607
+ while ((arguments.size () + nArgs) < 2 ) {
1608
+ actualForDummy.push_back (nullptr );
1609
+ nArgs++;
1610
+ }
1611
+
1612
+ CheckMaxMinA1A2Argument (arguments, maxMinKeywords, messages);
1613
+ }
1614
+
1573
1615
std::size_t dummies{actualForDummy.size ()};
1574
1616
1575
1617
// Check types and kinds of the actual arguments against the intrinsic's
@@ -1590,7 +1632,23 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
1590
1632
const ActualArgument *arg{actualForDummy[j]};
1591
1633
if (!arg) {
1592
1634
if (d.optionality == Optionality::required) {
1593
- messages.Say (" missing mandatory '%s=' argument" _err_en_US, d.keyword );
1635
+ std::string kw{d.keyword };
1636
+ if (isMaxMin && maxMinKeywords.size () == 1 ) {
1637
+ // max(a1=x) or max(a2=x)
1638
+ const auto kwA1{dummy[0 ].keyword };
1639
+ const auto kwA2{dummy[1 ].keyword };
1640
+ if (maxMinKeywords.begin ()->ToString ().compare (kwA1) == 0 ) {
1641
+ messages.Say (" missing mandatory 'a2=' argument" _err_en_US);
1642
+ } else if (maxMinKeywords.begin ()->ToString ().compare (kwA2) == 0 ) {
1643
+ messages.Say (" missing mandatory 'a1=' argument" _err_en_US);
1644
+ } else {
1645
+ messages.Say (
1646
+ " missing mandatory 'a1=' and 'a2=' arguments" _err_en_US);
1647
+ }
1648
+ } else {
1649
+ messages.Say (
1650
+ " missing mandatory '%s=' argument" _err_en_US, kw.c_str ());
1651
+ }
1594
1652
return std::nullopt; // missing non-OPTIONAL argument
1595
1653
} else {
1596
1654
continue ;
0 commit comments