@@ -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_;
@@ -3695,11 +3696,12 @@ std::optional<characteristics::Procedure> ExpressionAnalyzer::CheckCall(
36953696
36963697MaybeExpr ExpressionAnalyzer::Analyze (const parser::Expr::Parentheses &x) {
36973698 if (MaybeExpr operand{Analyze (x.v .value ())}) {
3698- if (const semantics::Symbol *symbol{GetLastSymbol (*operand)}) {
3699+ if (IsNullPointerOrAllocatable (&*operand)) {
3700+ Say (" NULL() may not be parenthesized" _err_en_US);
3701+ } else if (const semantics::Symbol *symbol{GetLastSymbol (*operand)}) {
36993702 if (const semantics::Symbol *result{FindFunctionResult (*symbol)}) {
37003703 if (semantics::IsProcedurePointer (*result)) {
3701- Say (" A function reference that returns a procedure "
3702- " pointer may not be parenthesized" _err_en_US); // C1003
3704+ Say (" A function reference that returns a procedure pointer may not be parenthesized" _err_en_US); // C1003
37033705 }
37043706 }
37053707 }
@@ -3788,7 +3790,7 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::DefinedUnary &x) {
37883790 ArgumentAnalyzer analyzer{*this , name.source };
37893791 analyzer.Analyze (std::get<1 >(x.t ));
37903792 return analyzer.TryDefinedOp (name.source .ToString ().c_str (),
3791- " No operator %s defined for %s" _err_en_US, true );
3793+ " No operator %s defined for %s" _err_en_US, /* isUserOp= */ true );
37923794}
37933795
37943796// Binary (dyadic) operations
@@ -4176,15 +4178,23 @@ MaybeExpr ExpressionAnalyzer::IterativelyAnalyzeSubexpressions(
41764178 } while (!queue.empty ());
41774179 // Analyze the collected subexpressions in bottom-up order.
41784180 // On an error, bail out and leave partial results in place.
4179- MaybeExpr result;
4180- for (auto riter{finish.rbegin ()}; riter != finish.rend (); ++riter) {
4181- const parser::Expr &expr{**riter};
4182- result = ExprOrVariable (expr, expr.source );
4183- if (!result) {
4184- return result;
4181+ if (finish.size () == 1 ) {
4182+ const parser::Expr &expr{DEREF (finish.front ())};
4183+ return ExprOrVariable (expr, expr.source );
4184+ } else {
4185+ // NULL() operand catching is deferred to operation analysis so
4186+ // that they can be accepted by defined operators.
4187+ auto restorer{AllowNullPointer ()};
4188+ MaybeExpr result;
4189+ for (auto riter{finish.rbegin ()}; riter != finish.rend (); ++riter) {
4190+ const parser::Expr &expr{**riter};
4191+ result = ExprOrVariable (expr, expr.source );
4192+ if (!result) {
4193+ return result;
4194+ }
41854195 }
4196+ return result; // last value was from analysis of "top"
41864197 }
4187- return result; // last value was from analysis of "top"
41884198}
41894199
41904200MaybeExpr ExpressionAnalyzer::Analyze (const parser::Expr &expr) {
@@ -4681,7 +4691,7 @@ bool ArgumentAnalyzer::AnyCUDADeviceData() const {
46814691// attribute.
46824692bool ArgumentAnalyzer::HasDeviceDefinedIntrinsicOpOverride (
46834693 const char *opr) const {
4684- if (AnyCUDADeviceData () && !AnyUntypedOrMissingOperand ()) {
4694+ if (AnyCUDADeviceData () && !AnyUntypedOperand () && ! AnyMissingOperand ()) {
46854695 std::string oprNameString{" operator(" s + opr + ' )' };
46864696 parser::CharBlock oprName{oprNameString};
46874697 parser::Messages buffer;
@@ -4709,9 +4719,9 @@ bool ArgumentAnalyzer::HasDeviceDefinedIntrinsicOpOverride(
47094719 return false ;
47104720}
47114721
4712- MaybeExpr ArgumentAnalyzer::TryDefinedOp (
4713- const char *opr, parser::MessageFixedText error, bool isUserOp) {
4714- if (AnyUntypedOrMissingOperand ()) {
4722+ MaybeExpr ArgumentAnalyzer::TryDefinedOp (const char *opr,
4723+ parser::MessageFixedText error, bool isUserOp, bool checkForNullPointer ) {
4724+ if (AnyMissingOperand ()) {
47154725 context_.Say (error, ToUpperCase (opr), TypeAsFortran (0 ), TypeAsFortran (1 ));
47164726 return std::nullopt ;
47174727 }
@@ -4790,7 +4800,9 @@ MaybeExpr ArgumentAnalyzer::TryDefinedOp(
47904800 context_.Say (
47914801 " Operands of %s are not conformable; have rank %d and rank %d" _err_en_US,
47924802 ToUpperCase (opr), actuals_[0 ]->Rank (), actuals_[1 ]->Rank ());
4793- } else if (CheckForNullPointer () && CheckForAssumedRank ()) {
4803+ } else if (!CheckForAssumedRank ()) {
4804+ } else if (checkForNullPointer && !CheckForNullPointer ()) {
4805+ } else { // use the supplied error
47944806 context_.Say (error, ToUpperCase (opr), TypeAsFortran (0 ), TypeAsFortran (1 ));
47954807 }
47964808 return result;
@@ -4808,15 +4820,16 @@ MaybeExpr ArgumentAnalyzer::TryDefinedOp(
48084820 for (std::size_t i{0 }; i < oprs.size (); ++i) {
48094821 parser::Messages buffer;
48104822 auto restorer{context_.GetContextualMessages ().SetMessages (buffer)};
4811- if (MaybeExpr thisResult{TryDefinedOp (oprs[i], error)}) {
4823+ if (MaybeExpr thisResult{TryDefinedOp (oprs[i], error, /* isUserOp=*/ false ,
4824+ /* checkForNullPointer=*/ false )}) {
48124825 result = std::move (thisResult);
48134826 hit.push_back (oprs[i]);
48144827 hitBuffer = std::move (buffer);
48154828 }
48164829 }
48174830 }
4818- if (hit.empty ()) { // for the error
4819- result = TryDefinedOp (oprs[0 ], error);
4831+ if (hit.empty ()) { // run TryDefinedOp() again just to emit errors
4832+ CHECK (! TryDefinedOp (oprs[0 ], error). has_value () );
48204833 } else if (hit.size () > 1 ) {
48214834 context_.Say (
48224835 " Matching accessible definitions were found with %zd variant spellings of the generic operator ('%s', '%s')" _err_en_US,
@@ -5232,10 +5245,19 @@ std::string ArgumentAnalyzer::TypeAsFortran(std::size_t i) {
52325245 }
52335246}
52345247
5235- bool ArgumentAnalyzer::AnyUntypedOrMissingOperand () const {
5248+ bool ArgumentAnalyzer::AnyUntypedOperand () const {
5249+ for (const auto &actual : actuals_) {
5250+ if (actual && !actual->GetType () &&
5251+ !IsBareNullPointer (actual->UnwrapExpr ())) {
5252+ return true ;
5253+ }
5254+ }
5255+ return false ;
5256+ }
5257+
5258+ bool ArgumentAnalyzer::AnyMissingOperand () const {
52365259 for (const auto &actual : actuals_) {
5237- if (!actual ||
5238- (!actual->GetType () && !IsBareNullPointer (actual->UnwrapExpr ()))) {
5260+ if (!actual) {
52395261 return true ;
52405262 }
52415263 }
0 commit comments