@@ -165,10 +165,17 @@ class ArgumentAnalyzer {
165
165
bool CheckForNullPointer (const char *where = " as an operand here" );
166
166
bool CheckForAssumedRank (const char *where = " as an operand here" );
167
167
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
+
168
177
// Find and return a user-defined operator or report an error.
169
178
// 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.
172
179
MaybeExpr TryDefinedOp (
173
180
const char *, parser::MessageFixedText, bool isUserOp = false );
174
181
template <typename E>
@@ -183,6 +190,8 @@ class ArgumentAnalyzer {
183
190
void Dump (llvm::raw_ostream &);
184
191
185
192
private:
193
+ bool HasDeviceDefinedIntrinsicOpOverride (
194
+ const std::vector<const char *> &) const ;
186
195
MaybeExpr TryDefinedOp (
187
196
const std::vector<const char *> &, parser::MessageFixedText);
188
197
MaybeExpr TryBoundOp (const Symbol &, int passIndex);
@@ -202,7 +211,7 @@ class ArgumentAnalyzer {
202
211
void SayNoMatch (
203
212
const std::string &, bool isAssignment = false , bool isAmbiguous = false );
204
213
std::string TypeAsFortran (std::size_t );
205
- bool AnyUntypedOrMissingOperand ();
214
+ bool AnyUntypedOrMissingOperand () const ;
206
215
207
216
ExpressionAnalyzer &context_;
208
217
ActualArguments actuals_;
@@ -4497,13 +4506,20 @@ void ArgumentAnalyzer::Analyze(
4497
4506
bool ArgumentAnalyzer::IsIntrinsicRelational (RelationalOperator opr,
4498
4507
const DynamicType &leftType, const DynamicType &rightType) const {
4499
4508
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 ));
4502
4514
}
4503
4515
4504
4516
bool ArgumentAnalyzer::IsIntrinsicNumeric (NumericOperator opr) const {
4505
4517
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 ) {
4507
4523
if (IsBOZLiteral (0 )) {
4508
4524
return opr == NumericOperator::Add; // unary '+'
4509
4525
} else {
@@ -4617,6 +4633,53 @@ bool ArgumentAnalyzer::CheckForAssumedRank(const char *where) {
4617
4633
return true ;
4618
4634
}
4619
4635
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
+
4620
4683
MaybeExpr ArgumentAnalyzer::TryDefinedOp (
4621
4684
const char *opr, parser::MessageFixedText error, bool isUserOp) {
4622
4685
if (AnyUntypedOrMissingOperand ()) {
@@ -5135,7 +5198,7 @@ std::string ArgumentAnalyzer::TypeAsFortran(std::size_t i) {
5135
5198
}
5136
5199
}
5137
5200
5138
- bool ArgumentAnalyzer::AnyUntypedOrMissingOperand () {
5201
+ bool ArgumentAnalyzer::AnyUntypedOrMissingOperand () const {
5139
5202
for (const auto &actual : actuals_) {
5140
5203
if (!actual ||
5141
5204
(!actual->GetType () && !IsBareNullPointer (actual->UnwrapExpr ()))) {
0 commit comments