@@ -519,8 +519,8 @@ struct AtomicAnalysis {
519519// / function references with scalar data pointer result of non-character
520520// / intrinsic type or variables that are non-polymorphic scalar pointers
521521// / and any length type parameter must be constant.
522- void OmpStructureChecker::CheckAtomicType (
523- SymbolRef sym, parser::CharBlock source, std::string_view name) {
522+ void OmpStructureChecker::CheckAtomicType (SymbolRef sym,
523+ parser::CharBlock source, std::string_view name, bool checkTypeOnPointer ) {
524524 const DeclTypeSpec *typeSpec{sym->GetType ()};
525525 if (!typeSpec) {
526526 return ;
@@ -547,6 +547,22 @@ void OmpStructureChecker::CheckAtomicType(
547547 return ;
548548 }
549549
550+ // Apply pointer-to-non-intrinsic rule only for intrinsic-assignment paths.
551+ if (checkTypeOnPointer) {
552+ using Category = DeclTypeSpec::Category;
553+ Category cat{typeSpec->category ()};
554+ if (cat != Category::Numeric && cat != Category::Logical) {
555+ std::string details = " has the POINTER attribute" ;
556+ if (const auto *derived{typeSpec->AsDerived ()}) {
557+ details += " and derived type '" s + derived->name ().ToString () + " '" ;
558+ }
559+ context_.Say (source,
560+ " ATOMIC operation requires an intrinsic scalar variable; '%s'%s" _err_en_US,
561+ sym->name (), details);
562+ return ;
563+ }
564+ }
565+
550566 // Go over all length parameters, if any, and check if they are
551567 // explicit.
552568 if (const DerivedTypeSpec *derived{typeSpec->AsDerived ()}) {
@@ -562,7 +578,7 @@ void OmpStructureChecker::CheckAtomicType(
562578}
563579
564580void OmpStructureChecker::CheckAtomicVariable (
565- const SomeExpr &atom, parser::CharBlock source) {
581+ const SomeExpr &atom, parser::CharBlock source, bool checkTypeOnPointer ) {
566582 if (atom.Rank () != 0 ) {
567583 context_.Say (source, " Atomic variable %s should be a scalar" _err_en_US,
568584 atom.AsFortran ());
@@ -572,46 +588,14 @@ void OmpStructureChecker::CheckAtomicVariable(
572588 assert (dsgs.size () == 1 && " Should have a single top-level designator" );
573589 evaluate::SymbolVector syms{evaluate::GetSymbolVector (dsgs.front ())};
574590
575- CheckAtomicType (syms.back (), source, atom.AsFortran ());
591+ CheckAtomicType (syms.back (), source, atom.AsFortran (), checkTypeOnPointer );
576592
577593 if (IsAllocatable (syms.back ()) && !IsArrayElement (atom)) {
578594 context_.Say (source, " Atomic variable %s cannot be ALLOCATABLE" _err_en_US,
579595 atom.AsFortran ());
580596 }
581597}
582598
583- void OmpStructureChecker::CheckAtomicVariable (const SomeExpr &atom,
584- parser::CharBlock source, const evaluate::Assignment &assign) {
585- // First do all the standard checks
586- CheckAtomicVariable (atom, source);
587-
588- // For intrinsic assignment, check if the variable is a pointer
589- // to a non-intrinsic type, which is not allowed in atomic operations
590- if (!IsPointerAssignment (assign)) {
591- std::vector<SomeExpr> dsgs{GetAllDesignators (atom)};
592- if (!dsgs.empty ()) {
593- evaluate::SymbolVector syms{evaluate::GetSymbolVector (dsgs.front ())};
594- if (!syms.empty () && IsPointer (syms.back ())) {
595- SymbolRef sym = syms.back ();
596- if (const DeclTypeSpec *typeSpec{sym->GetType ()}) {
597- using Category = DeclTypeSpec::Category;
598- Category cat{typeSpec->category ()};
599- if (cat != Category::Numeric && cat != Category::Logical) {
600- std::string details = " has the POINTER attribute" ;
601- if (const auto *derived{typeSpec->AsDerived ()}) {
602- details +=
603- " and derived type '" s + derived->name ().ToString () + " '" ;
604- }
605- context_.Say (source,
606- " ATOMIC operation requires an intrinsic scalar variable; '%s'%s" _err_en_US,
607- sym->name (), details);
608- }
609- }
610- }
611- }
612- }
613- }
614-
615599void OmpStructureChecker::CheckStorageOverlap (const SomeExpr &base,
616600 llvm::ArrayRef<evaluate::Expr<evaluate::SomeType>> exprs,
617601 parser::CharBlock source) {
@@ -821,7 +805,8 @@ void OmpStructureChecker::CheckAtomicCaptureAssignment(
821805 if (!IsVarOrFunctionRef (atom)) {
822806 ErrorShouldBeVariable (atom, rsrc);
823807 } else {
824- CheckAtomicVariable (atom, rsrc, capture);
808+ CheckAtomicVariable (
809+ atom, rsrc, /* checkTypeOnPointer=*/ !IsPointerAssignment (capture));
825810 // This part should have been checked prior to calling this function.
826811 assert (*GetConvertInput (capture.rhs ) == atom &&
827812 " This cannot be a capture assignment" );
@@ -840,7 +825,8 @@ void OmpStructureChecker::CheckAtomicReadAssignment(
840825 if (!IsVarOrFunctionRef (atom)) {
841826 ErrorShouldBeVariable (atom, rsrc);
842827 } else {
843- CheckAtomicVariable (atom, rsrc, read);
828+ CheckAtomicVariable (
829+ atom, rsrc, /* checkTypeOnPointer=*/ !IsPointerAssignment (read));
844830 CheckStorageOverlap (atom, {read.lhs }, source);
845831 }
846832 } else {
@@ -861,7 +847,8 @@ void OmpStructureChecker::CheckAtomicWriteAssignment(
861847 if (!IsVarOrFunctionRef (atom)) {
862848 ErrorShouldBeVariable (atom, rsrc);
863849 } else {
864- CheckAtomicVariable (atom, lsrc, write);
850+ CheckAtomicVariable (
851+ atom, lsrc, /* checkTypeOnPointer=*/ !IsPointerAssignment (write));
865852 CheckStorageOverlap (atom, {write.rhs }, source);
866853 }
867854}
@@ -886,7 +873,8 @@ OmpStructureChecker::CheckAtomicUpdateAssignment(
886873 return std::nullopt ;
887874 }
888875
889- CheckAtomicVariable (atom, lsrc, update);
876+ CheckAtomicVariable (
877+ atom, lsrc, /* checkTypeOnPointer=*/ !IsPointerAssignment (update));
890878
891879 auto [hasErrors, tryReassoc]{CheckAtomicUpdateAssignmentRhs (
892880 atom, update.rhs , source, /* suppressDiagnostics=*/ true )};
@@ -1049,7 +1037,8 @@ void OmpStructureChecker::CheckAtomicConditionalUpdateAssignment(
10491037 return ;
10501038 }
10511039
1052- CheckAtomicVariable (atom, alsrc, assign);
1040+ CheckAtomicVariable (
1041+ atom, alsrc, /* checkTypeOnPointer=*/ !IsPointerAssignment (assign));
10531042
10541043 auto top{GetTopLevelOperationIgnoreResizing (cond)};
10551044 // Missing arguments to operations would have been diagnosed by now.
0 commit comments