@@ -176,8 +176,8 @@ class ArgumentAnalyzer {
176176
177177 // Find and return a user-defined operator or report an error.
178178 // The provided message is used if there is no such operator.
179- MaybeExpr TryDefinedOp (
180- const char *, parser::MessageFixedText , bool isUserOp = false );
179+ MaybeExpr TryDefinedOp (const char *, parser::MessageFixedText,
180+ bool isUserOp = false , bool checkForNullPointer = true );
181181 template <typename E>
182182 MaybeExpr TryDefinedOp (E opr, parser::MessageFixedText msg) {
183183 return TryDefinedOp (
@@ -211,7 +211,8 @@ class ArgumentAnalyzer {
211211 void SayNoMatch (
212212 const std::string &, bool isAssignment = false , bool isAmbiguous = false );
213213 std::string TypeAsFortran (std::size_t );
214- bool AnyUntypedOrMissingOperand () const ;
214+ bool AnyUntypedOperand () const ;
215+ bool AnyMissingOperand () const ;
215216
216217 ExpressionAnalyzer &context_;
217218 ActualArguments actuals_;
@@ -3696,11 +3697,12 @@ std::optional<characteristics::Procedure> ExpressionAnalyzer::CheckCall(
36963697
36973698MaybeExpr ExpressionAnalyzer::Analyze (const parser::Expr::Parentheses &x) {
36983699 if (MaybeExpr operand{Analyze (x.v .value ())}) {
3699- if (const semantics::Symbol *symbol{GetLastSymbol (*operand)}) {
3700+ if (IsNullPointerOrAllocatable (&*operand)) {
3701+ Say (" NULL() may not be parenthesized" _err_en_US);
3702+ } else if (const semantics::Symbol *symbol{GetLastSymbol (*operand)}) {
37003703 if (const semantics::Symbol *result{FindFunctionResult (*symbol)}) {
37013704 if (semantics::IsProcedurePointer (*result)) {
3702- Say (" A function reference that returns a procedure "
3703- " pointer may not be parenthesized" _err_en_US); // C1003
3705+ Say (" A function reference that returns a procedure pointer may not be parenthesized" _err_en_US); // C1003
37043706 }
37053707 }
37063708 }
@@ -3789,7 +3791,7 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::DefinedUnary &x) {
37893791 ArgumentAnalyzer analyzer{*this , name.source };
37903792 analyzer.Analyze (std::get<1 >(x.t ));
37913793 return analyzer.TryDefinedOp (name.source .ToString ().c_str (),
3792- " No operator %s defined for %s" _err_en_US, true );
3794+ " No operator %s defined for %s" _err_en_US, /* isUserOp= */ true );
37933795}
37943796
37953797// Binary (dyadic) operations
@@ -4181,15 +4183,23 @@ MaybeExpr ExpressionAnalyzer::IterativelyAnalyzeSubexpressions(
41814183 } while (!queue.empty ());
41824184 // Analyze the collected subexpressions in bottom-up order.
41834185 // On an error, bail out and leave partial results in place.
4184- MaybeExpr result;
4185- for (auto riter{finish.rbegin ()}; riter != finish.rend (); ++riter) {
4186- const parser::Expr &expr{**riter};
4187- result = ExprOrVariable (expr, expr.source );
4188- if (!result) {
4189- return result;
4186+ if (finish.size () == 1 ) {
4187+ const parser::Expr &expr{DEREF (finish.front ())};
4188+ return ExprOrVariable (expr, expr.source );
4189+ } else {
4190+ // NULL() operand catching is deferred to operation analysis so
4191+ // that they can be accepted by defined operators.
4192+ auto restorer{AllowNullPointer ()};
4193+ MaybeExpr result;
4194+ for (auto riter{finish.rbegin ()}; riter != finish.rend (); ++riter) {
4195+ const parser::Expr &expr{**riter};
4196+ result = ExprOrVariable (expr, expr.source );
4197+ if (!result) {
4198+ return result;
4199+ }
41904200 }
4201+ return result; // last value was from analysis of "top"
41914202 }
4192- return result; // last value was from analysis of "top"
41934203}
41944204
41954205MaybeExpr ExpressionAnalyzer::Analyze (const parser::Expr &expr) {
@@ -4686,7 +4696,7 @@ bool ArgumentAnalyzer::AnyCUDADeviceData() const {
46864696// attribute.
46874697bool ArgumentAnalyzer::HasDeviceDefinedIntrinsicOpOverride (
46884698 const char *opr) const {
4689- if (AnyCUDADeviceData () && !AnyUntypedOrMissingOperand ()) {
4699+ if (AnyCUDADeviceData () && !AnyUntypedOperand () && ! AnyMissingOperand ()) {
46904700 std::string oprNameString{" operator(" s + opr + ' )' };
46914701 parser::CharBlock oprName{oprNameString};
46924702 parser::Messages buffer;
@@ -4714,9 +4724,9 @@ bool ArgumentAnalyzer::HasDeviceDefinedIntrinsicOpOverride(
47144724 return false ;
47154725}
47164726
4717- MaybeExpr ArgumentAnalyzer::TryDefinedOp (
4718- const char *opr, parser::MessageFixedText error, bool isUserOp) {
4719- if (AnyUntypedOrMissingOperand ()) {
4727+ MaybeExpr ArgumentAnalyzer::TryDefinedOp (const char *opr,
4728+ parser::MessageFixedText error, bool isUserOp, bool checkForNullPointer ) {
4729+ if (AnyMissingOperand ()) {
47204730 context_.Say (error, ToUpperCase (opr), TypeAsFortran (0 ), TypeAsFortran (1 ));
47214731 return std::nullopt ;
47224732 }
@@ -4795,7 +4805,9 @@ MaybeExpr ArgumentAnalyzer::TryDefinedOp(
47954805 context_.Say (
47964806 " Operands of %s are not conformable; have rank %d and rank %d" _err_en_US,
47974807 ToUpperCase (opr), actuals_[0 ]->Rank (), actuals_[1 ]->Rank ());
4798- } else if (CheckForNullPointer () && CheckForAssumedRank ()) {
4808+ } else if (!CheckForAssumedRank ()) {
4809+ } else if (checkForNullPointer && !CheckForNullPointer ()) {
4810+ } else { // use the supplied error
47994811 context_.Say (error, ToUpperCase (opr), TypeAsFortran (0 ), TypeAsFortran (1 ));
48004812 }
48014813 return result;
@@ -4813,15 +4825,16 @@ MaybeExpr ArgumentAnalyzer::TryDefinedOp(
48134825 for (std::size_t i{0 }; i < oprs.size (); ++i) {
48144826 parser::Messages buffer;
48154827 auto restorer{context_.GetContextualMessages ().SetMessages (buffer)};
4816- if (MaybeExpr thisResult{TryDefinedOp (oprs[i], error)}) {
4828+ if (MaybeExpr thisResult{TryDefinedOp (oprs[i], error, /* isUserOp=*/ false ,
4829+ /* checkForNullPointer=*/ false )}) {
48174830 result = std::move (thisResult);
48184831 hit.push_back (oprs[i]);
48194832 hitBuffer = std::move (buffer);
48204833 }
48214834 }
48224835 }
4823- if (hit.empty ()) { // for the error
4824- result = TryDefinedOp (oprs[0 ], error);
4836+ if (hit.empty ()) { // run TryDefinedOp() again just to emit errors
4837+ CHECK (! TryDefinedOp (oprs[0 ], error). has_value () );
48254838 } else if (hit.size () > 1 ) {
48264839 context_.Say (
48274840 " Matching accessible definitions were found with %zd variant spellings of the generic operator ('%s', '%s')" _err_en_US,
@@ -5237,10 +5250,19 @@ std::string ArgumentAnalyzer::TypeAsFortran(std::size_t i) {
52375250 }
52385251}
52395252
5240- bool ArgumentAnalyzer::AnyUntypedOrMissingOperand () const {
5253+ bool ArgumentAnalyzer::AnyUntypedOperand () const {
5254+ for (const auto &actual : actuals_) {
5255+ if (actual && !actual->GetType () &&
5256+ !IsBareNullPointer (actual->UnwrapExpr ())) {
5257+ return true ;
5258+ }
5259+ }
5260+ return false ;
5261+ }
5262+
5263+ bool ArgumentAnalyzer::AnyMissingOperand () const {
52415264 for (const auto &actual : actuals_) {
5242- if (!actual ||
5243- (!actual->GetType () && !IsBareNullPointer (actual->UnwrapExpr ()))) {
5265+ if (!actual) {
52445266 return true ;
52455267 }
52465268 }
0 commit comments