@@ -165,10 +165,17 @@ class ArgumentAnalyzer {
165165 bool CheckForNullPointer (const char *where = " as an operand here" );
166166 bool CheckForAssumedRank (const char *where = " as an operand here" );
167167
168+ bool AnyCUDADeviceData () const ;
169+ // Returns true if an interface has been defined for an intrinsic operator
170+ // with one or more device operands.
171+ bool HasDeviceDefinedIntrinsicOpOverride (const char *) const ;
172+ template <typename E> bool HasDeviceDefinedIntrinsicOpOverride (E opr) const {
173+ return HasDeviceDefinedIntrinsicOpOverride (
174+ context_.context ().languageFeatures ().GetNames (opr));
175+ }
176+
168177 // Find and return a user-defined operator or report an error.
169178 // The provided message is used if there is no such operator.
170- // If a definedOpSymbolPtr is provided, the caller must check
171- // for its accessibility.
172179 MaybeExpr TryDefinedOp (
173180 const char *, parser::MessageFixedText, bool isUserOp = false );
174181 template <typename E>
@@ -183,6 +190,8 @@ class ArgumentAnalyzer {
183190 void Dump (llvm::raw_ostream &);
184191
185192private:
193+ bool HasDeviceDefinedIntrinsicOpOverride (
194+ const std::vector<const char *> &) const ;
186195 MaybeExpr TryDefinedOp (
187196 const std::vector<const char *> &, parser::MessageFixedText);
188197 MaybeExpr TryBoundOp (const Symbol &, int passIndex);
@@ -202,7 +211,7 @@ class ArgumentAnalyzer {
202211 void SayNoMatch (
203212 const std::string &, bool isAssignment = false , bool isAmbiguous = false );
204213 std::string TypeAsFortran (std::size_t );
205- bool AnyUntypedOrMissingOperand ();
214+ bool AnyUntypedOrMissingOperand () const ;
206215
207216 ExpressionAnalyzer &context_;
208217 ActualArguments actuals_;
@@ -4497,13 +4506,20 @@ void ArgumentAnalyzer::Analyze(
44974506bool ArgumentAnalyzer::IsIntrinsicRelational (RelationalOperator opr,
44984507 const DynamicType &leftType, const DynamicType &rightType) const {
44994508 CHECK (actuals_.size () == 2 );
4500- return semantics::IsIntrinsicRelational (
4501- opr, leftType, GetRank (0 ), rightType, GetRank (1 ));
4509+ return !(context_.context ().languageFeatures ().IsEnabled (
4510+ common::LanguageFeature::CUDA) &&
4511+ HasDeviceDefinedIntrinsicOpOverride (opr)) &&
4512+ semantics::IsIntrinsicRelational (
4513+ opr, leftType, GetRank (0 ), rightType, GetRank (1 ));
45024514}
45034515
45044516bool ArgumentAnalyzer::IsIntrinsicNumeric (NumericOperator opr) const {
45054517 std::optional<DynamicType> leftType{GetType (0 )};
4506- if (actuals_.size () == 1 ) {
4518+ if (context_.context ().languageFeatures ().IsEnabled (
4519+ common::LanguageFeature::CUDA) &&
4520+ HasDeviceDefinedIntrinsicOpOverride (AsFortran (opr))) {
4521+ return false ;
4522+ } else if (actuals_.size () == 1 ) {
45074523 if (IsBOZLiteral (0 )) {
45084524 return opr == NumericOperator::Add; // unary '+'
45094525 } else {
@@ -4617,6 +4633,53 @@ bool ArgumentAnalyzer::CheckForAssumedRank(const char *where) {
46174633 return true ;
46184634}
46194635
4636+ bool ArgumentAnalyzer::AnyCUDADeviceData () const {
4637+ for (const std::optional<ActualArgument> &arg : actuals_) {
4638+ if (arg) {
4639+ if (const Expr<SomeType> *expr{arg->UnwrapExpr ()}) {
4640+ if (HasCUDADeviceAttrs (*expr)) {
4641+ return true ;
4642+ }
4643+ }
4644+ }
4645+ }
4646+ return false ;
4647+ }
4648+
4649+ // Some operations can be defined with explicit non-type-bound interfaces
4650+ // that would erroneously conflict with intrinsic operations in their
4651+ // types and ranks but have one or more dummy arguments with the DEVICE
4652+ // attribute.
4653+ bool ArgumentAnalyzer::HasDeviceDefinedIntrinsicOpOverride (
4654+ const char *opr) const {
4655+ if (AnyCUDADeviceData () && !AnyUntypedOrMissingOperand ()) {
4656+ std::string oprNameString{" operator(" s + opr + ' )' };
4657+ parser::CharBlock oprName{oprNameString};
4658+ parser::Messages buffer;
4659+ auto restorer{context_.GetContextualMessages ().SetMessages (buffer)};
4660+ const auto &scope{context_.context ().FindScope (source_)};
4661+ if (Symbol * generic{scope.FindSymbol (oprName)}) {
4662+ parser::Name name{generic->name (), generic};
4663+ const Symbol *resultSymbol{nullptr };
4664+ if (context_.AnalyzeDefinedOp (
4665+ name, ActualArguments{actuals_}, resultSymbol)) {
4666+ return true ;
4667+ }
4668+ }
4669+ }
4670+ return false ;
4671+ }
4672+
4673+ bool ArgumentAnalyzer::HasDeviceDefinedIntrinsicOpOverride (
4674+ const std::vector<const char *> &oprNames) const {
4675+ for (const char *opr : oprNames) {
4676+ if (HasDeviceDefinedIntrinsicOpOverride (opr)) {
4677+ return true ;
4678+ }
4679+ }
4680+ return false ;
4681+ }
4682+
46204683MaybeExpr ArgumentAnalyzer::TryDefinedOp (
46214684 const char *opr, parser::MessageFixedText error, bool isUserOp) {
46224685 if (AnyUntypedOrMissingOperand ()) {
@@ -5135,7 +5198,7 @@ std::string ArgumentAnalyzer::TypeAsFortran(std::size_t i) {
51355198 }
51365199}
51375200
5138- bool ArgumentAnalyzer::AnyUntypedOrMissingOperand () {
5201+ bool ArgumentAnalyzer::AnyUntypedOrMissingOperand () const {
51395202 for (const auto &actual : actuals_) {
51405203 if (!actual ||
51415204 (!actual->GetType () && !IsBareNullPointer (actual->UnwrapExpr ()))) {
0 commit comments