@@ -51,6 +51,30 @@ std::string TryVersion(unsigned version) {
5151 return " try -fopenmp-version=" + std::to_string (version);
5252}
5353
54+ static const parser::Designator *GetDesignatorFromObj (
55+ const parser::OmpObject &object) {
56+ return std::get_if<parser::Designator>(&object.u );
57+ }
58+
59+ static const parser::DataRef *GetDataRefFromObj (
60+ const parser::OmpObject &object) {
61+ if (auto *desg{GetDesignatorFromObj (object)}) {
62+ return std::get_if<parser::DataRef>(&desg->u );
63+ }
64+ return nullptr ;
65+ }
66+
67+ static const parser::ArrayElement *GetArrayElementFromObj (
68+ const parser::OmpObject &object) {
69+ if (auto *dataRef{GetDataRefFromObj (object)}) {
70+ using ElementIndirection = common::Indirection<parser::ArrayElement>;
71+ if (auto *ind{std::get_if<ElementIndirection>(&dataRef->u )}) {
72+ return &ind->value ();
73+ }
74+ }
75+ return nullptr ;
76+ }
77+
5478// 'OmpWorkshareBlockChecker' is used to check the validity of the assignment
5579// statements and the expressions enclosed in an OpenMP Workshare construct
5680class OmpWorkshareBlockChecker {
@@ -222,6 +246,10 @@ bool OmpStructureChecker::CheckAllowedClause(llvmOmpClause clause) {
222246 return CheckAllowed (clause);
223247}
224248
249+ bool OmpStructureChecker::IsCommonBlock (const Symbol &sym) {
250+ return sym.detailsIf <CommonBlockDetails>() != nullptr ;
251+ }
252+
225253bool OmpStructureChecker::IsVariableListItem (const Symbol &sym) {
226254 return evaluate::IsVariable (sym) || sym.attrs ().test (Attr::POINTER);
227255}
@@ -2895,6 +2923,8 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Reduction &x) {
28952923 CheckReductionModifier (*maybeModifier);
28962924 }
28972925 }
2926+ CheckReductionObjects (std::get<parser::OmpObjectList>(x.v .t ),
2927+ llvm::omp::Clause::OMPC_reduction);
28982928}
28992929
29002930bool OmpStructureChecker::CheckReductionOperators (
@@ -2963,6 +2993,69 @@ bool OmpStructureChecker::CheckIntrinsicOperator(
29632993 return false ;
29642994}
29652995
2996+ // / Check restrictions on objects that are common to all reduction clauses.
2997+ void OmpStructureChecker::CheckReductionObjects (
2998+ const parser::OmpObjectList &objects, llvm::omp::Clause clauseId) {
2999+ unsigned version{context_.langOptions ().OpenMPVersion };
3000+ SymbolSourceMap symbols;
3001+ GetSymbolsInObjectList (objects, symbols);
3002+
3003+ // Array sections must be a contiguous storage, have non-zero length.
3004+ for (const parser::OmpObject &object : objects.v ) {
3005+ CheckIfContiguous (object);
3006+ }
3007+ CheckReductionArraySection (objects);
3008+ // An object must be definable.
3009+ CheckDefinableObjects (symbols, clauseId);
3010+ // Procedure pointers are not allowed.
3011+ CheckProcedurePointer (symbols, clauseId);
3012+ // Pointers must not have INTENT(IN).
3013+ CheckIntentInPointer (symbols, clauseId);
3014+
3015+ // Disallow common blocks.
3016+ // Iterate on objects because `GetSymbolsInObjectList` expands common block
3017+ // names into the lists of their members.
3018+ for (const parser::OmpObject &object : objects.v ) {
3019+ auto *symbol{GetObjectSymbol (object)};
3020+ assert (symbol && " Expecting a symbol for object" );
3021+ if (IsCommonBlock (*symbol)) {
3022+ auto source{GetObjectSource (object)};
3023+ context_.Say (source ? *source : GetContext ().clauseSource ,
3024+ " Common block names are not allowed in %s clause" _err_en_US,
3025+ parser::ToUpperCaseLetters (getClauseName (clauseId).str ()));
3026+ }
3027+ }
3028+
3029+ if (version >= 50 ) {
3030+ // Object cannot be a part of another object (except array elements)
3031+ CheckStructureComponent (objects, clauseId);
3032+ // If object is an array section or element, the base expression must be
3033+ // a language identifier.
3034+ for (const parser::OmpObject &object : objects.v ) {
3035+ if (auto *elem{GetArrayElementFromObj (object)}) {
3036+ const parser::DataRef &base = elem->base ;
3037+ if (!std::holds_alternative<parser::Name>(base.u )) {
3038+ auto source{GetObjectSource (object)};
3039+ context_.Say (source ? *source : GetContext ().clauseSource ,
3040+ " The base expression of an array element in %s clause must be an identifier" _err_en_US,
3041+ parser::ToUpperCaseLetters (getClauseName (clauseId).str ()));
3042+ }
3043+ }
3044+ }
3045+ // Type parameter inquiries are not allowed.
3046+ for (const parser::OmpObject &object : objects.v ) {
3047+ if (auto *dataRef{GetDataRefFromObj (object)}) {
3048+ if (IsDataRefTypeParamInquiry (dataRef)) {
3049+ auto source{GetObjectSource (object)};
3050+ context_.Say (source ? *source : GetContext ().clauseSource ,
3051+ " Type parameter inquiry is not permitted in %s clause" _err_en_US,
3052+ parser::ToUpperCaseLetters (getClauseName (clauseId).str ()));
3053+ }
3054+ }
3055+ }
3056+ }
3057+ }
3058+
29663059static bool IsReductionAllowedForType (
29673060 const parser::OmpClause::Reduction &x, const DeclTypeSpec &type) {
29683061 auto &modifiers{OmpGetModifiers (x.v )};
@@ -3052,26 +3145,25 @@ static bool IsReductionAllowedForType(
30523145void OmpStructureChecker::CheckReductionTypeList (
30533146 const parser::OmpClause::Reduction &x) {
30543147 const auto &ompObjectList{std::get<parser::OmpObjectList>(x.v .t )};
3055- CheckIntentInPointerAndDefinable (
3056- ompObjectList, llvm::omp::Clause::OMPC_reduction);
3148+ SymbolSourceMap symbols;
3149+ GetSymbolsInObjectList (ompObjectList, symbols);
3150+
30573151 CheckReductionArraySection (ompObjectList);
30583152 // If this is a worksharing construct then ensure the reduction variable
30593153 // is not private in the parallel region that it binds to.
30603154 if (llvm::omp::nestedReduceWorkshareAllowedSet.test (GetContext ().directive )) {
30613155 CheckSharedBindingInOuterContext (ompObjectList);
30623156 }
30633157
3064- SymbolSourceMap symbols;
3065- GetSymbolsInObjectList (ompObjectList, symbols);
30663158 for (auto &[symbol, source] : symbols) {
3067- if (IsProcedurePointer (* symbol) ) {
3068- context_. Say (source,
3069- " A procedure pointer '%s' must not appear in a REDUCTION clause. " _err_en_US ,
3070- symbol-> name ());
3071- } else if (! IsReductionAllowedForType (x, DEREF ( symbol->GetType ()))) {
3072- context_. Say (source,
3073- " The type of '%s' is incompatible with the reduction operator. " _err_en_US,
3074- symbol-> name () );
3159+ if (auto *type{ symbol-> GetType ()} ) {
3160+ if (! IsReductionAllowedForType (x, *type)) {
3161+ context_. Say (source ,
3162+ " The type of '%s' is incompatible with the reduction operator. " _err_en_US,
3163+ symbol->name ());
3164+ }
3165+ } else {
3166+ assert ( IsProcedurePointer (*symbol) && " Unexpected symbol properties " );
30753167 }
30763168 }
30773169}
@@ -3127,43 +3219,14 @@ void OmpStructureChecker::CheckReductionModifier(
31273219 }
31283220}
31293221
3130- void OmpStructureChecker::CheckIntentInPointerAndDefinable (
3131- const parser::OmpObjectList &objectList, const llvm::omp::Clause clause) {
3132- for (const auto &ompObject : objectList.v ) {
3133- if (const auto *name{parser::Unwrap<parser::Name>(ompObject)}) {
3134- if (const auto *symbol{name->symbol }) {
3135- if (IsPointer (symbol->GetUltimate ()) &&
3136- IsIntentIn (symbol->GetUltimate ())) {
3137- context_.Say (GetContext ().clauseSource ,
3138- " Pointer '%s' with the INTENT(IN) attribute may not appear "
3139- " in a %s clause" _err_en_US,
3140- symbol->name (),
3141- parser::ToUpperCaseLetters (getClauseName (clause).str ()));
3142- } else if (auto msg{WhyNotDefinable (name->source ,
3143- context_.FindScope (name->source ), DefinabilityFlags{},
3144- *symbol)}) {
3145- context_
3146- .Say (GetContext ().clauseSource ,
3147- " Variable '%s' on the %s clause is not definable" _err_en_US,
3148- symbol->name (),
3149- parser::ToUpperCaseLetters (getClauseName (clause).str ()))
3150- .Attach (std::move (msg->set_severity (parser::Severity::Because)));
3151- }
3152- }
3153- }
3154- }
3155- }
3156-
31573222void OmpStructureChecker::CheckReductionArraySection (
31583223 const parser::OmpObjectList &ompObjectList) {
31593224 for (const auto &ompObject : ompObjectList.v ) {
31603225 if (const auto *dataRef{parser::Unwrap<parser::DataRef>(ompObject)}) {
31613226 if (const auto *arrayElement{
31623227 parser::Unwrap<parser::ArrayElement>(ompObject)}) {
3163- if (arrayElement) {
3164- CheckArraySection (*arrayElement, GetLastName (*dataRef),
3165- llvm::omp::Clause::OMPC_reduction);
3166- }
3228+ CheckArraySection (*arrayElement, GetLastName (*dataRef),
3229+ llvm::omp::Clause::OMPC_reduction);
31673230 }
31683231 }
31693232 }
@@ -3232,9 +3295,11 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Shared &x) {
32323295 CheckIsVarPartOfAnotherVar (GetContext ().clauseSource , x.v , " SHARED" );
32333296}
32343297void OmpStructureChecker::Enter (const parser::OmpClause::Private &x) {
3298+ SymbolSourceMap symbols;
3299+ GetSymbolsInObjectList (x.v , symbols);
32353300 CheckAllowedClause (llvm::omp::Clause::OMPC_private);
32363301 CheckIsVarPartOfAnotherVar (GetContext ().clauseSource , x.v , " PRIVATE" );
3237- CheckIntentInPointer (x. v , llvm::omp::Clause::OMPC_private);
3302+ CheckIntentInPointer (symbols , llvm::omp::Clause::OMPC_private);
32383303}
32393304
32403305void OmpStructureChecker::Enter (const parser::OmpClause::Nowait &x) {
@@ -3891,11 +3956,11 @@ void OmpStructureChecker::CheckCopyingPolymorphicAllocatable(
38913956
38923957void OmpStructureChecker::Enter (const parser::OmpClause::Copyprivate &x) {
38933958 CheckAllowedClause (llvm::omp::Clause::OMPC_copyprivate);
3894- CheckIntentInPointer (x. v , llvm::omp::Clause::OMPC_copyprivate) ;
3895- SymbolSourceMap currSymbols ;
3896- GetSymbolsInObjectList (x. v , currSymbols );
3959+ SymbolSourceMap symbols ;
3960+ GetSymbolsInObjectList (x. v , symbols) ;
3961+ CheckIntentInPointer (symbols, llvm::omp::Clause::OMPC_copyprivate );
38973962 CheckCopyingPolymorphicAllocatable (
3898- currSymbols , llvm::omp::Clause::OMPC_copyprivate);
3963+ symbols , llvm::omp::Clause::OMPC_copyprivate);
38993964 if (GetContext ().directive == llvm::omp::Directive::OMPD_single) {
39003965 context_.Say (GetContext ().clauseSource ,
39013966 " %s clause is not allowed on the OMP %s directive,"
@@ -3945,29 +4010,26 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Copyin &x) {
39454010 currSymbols, llvm::omp::Clause::OMPC_copyin);
39464011}
39474012
3948- void OmpStructureChecker::CheckStructureElement (
3949- const parser::OmpObjectList &ompObjectList,
3950- const llvm::omp::Clause clause) {
3951- for (const auto &ompObject : ompObjectList.v ) {
4013+ void OmpStructureChecker::CheckStructureComponent (
4014+ const parser::OmpObjectList &objects, llvm::omp::Clause clauseId) {
4015+ auto CheckComponent{[&](const parser::Designator &designator) {
4016+ if (auto *desg{std::get_if<parser::DataRef>(&designator.u )}) {
4017+ if (auto *comp{parser::Unwrap<parser::StructureComponent>(*desg)}) {
4018+ context_.Say (comp->component .source ,
4019+ " A variable that is part of another variable cannot appear on the %s clause" _err_en_US,
4020+ parser::ToUpperCaseLetters (getClauseName (clauseId).str ()));
4021+ }
4022+ }
4023+ }};
4024+
4025+ for (const auto &object : objects.v ) {
39524026 common::visit (
39534027 common::visitors{
3954- [&](const parser::Designator &designator) {
3955- if (std::get_if<parser::DataRef>(&designator.u )) {
3956- if (parser::Unwrap<parser::StructureComponent>(ompObject)) {
3957- context_.Say (GetContext ().clauseSource ,
3958- " A variable that is part of another variable "
3959- " (structure element) cannot appear on the %s "
3960- " %s clause" _err_en_US,
3961- ContextDirectiveAsFortran (),
3962- parser::ToUpperCaseLetters (getClauseName (clause).str ()));
3963- }
3964- }
3965- },
4028+ CheckComponent,
39664029 [&](const parser::Name &name) {},
39674030 },
3968- ompObject .u );
4031+ object .u );
39694032 }
3970- return ;
39714033}
39724034
39734035void OmpStructureChecker::Enter (const parser::OmpClause::Update &x) {
@@ -4009,7 +4071,7 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Update &x) {
40094071}
40104072
40114073void OmpStructureChecker::Enter (const parser::OmpClause::UseDevicePtr &x) {
4012- CheckStructureElement (x.v , llvm::omp::Clause::OMPC_use_device_ptr);
4074+ CheckStructureComponent (x.v , llvm::omp::Clause::OMPC_use_device_ptr);
40134075 CheckAllowedClause (llvm::omp::Clause::OMPC_use_device_ptr);
40144076 SymbolSourceMap currSymbols;
40154077 GetSymbolsInObjectList (x.v , currSymbols);
@@ -4038,7 +4100,7 @@ void OmpStructureChecker::Enter(const parser::OmpClause::UseDevicePtr &x) {
40384100}
40394101
40404102void OmpStructureChecker::Enter (const parser::OmpClause::UseDeviceAddr &x) {
4041- CheckStructureElement (x.v , llvm::omp::Clause::OMPC_use_device_addr);
4103+ CheckStructureComponent (x.v , llvm::omp::Clause::OMPC_use_device_addr);
40424104 CheckAllowedClause (llvm::omp::Clause::OMPC_use_device_addr);
40434105 SymbolSourceMap currSymbols;
40444106 GetSymbolsInObjectList (x.v , currSymbols);
@@ -4214,6 +4276,26 @@ llvm::StringRef OmpStructureChecker::getDirectiveName(
42144276 return llvm::omp::getOpenMPDirectiveName (directive);
42154277}
42164278
4279+ const Symbol *OmpStructureChecker::GetObjectSymbol (
4280+ const parser::OmpObject &object) {
4281+ if (auto *name{std::get_if<parser::Name>(&object.u )}) {
4282+ return &name->symbol ->GetUltimate ();
4283+ } else if (auto *desg{std::get_if<parser::Designator>(&object.u )}) {
4284+ return &GetLastName (*desg).symbol ->GetUltimate ();
4285+ }
4286+ return nullptr ;
4287+ }
4288+
4289+ std::optional<parser::CharBlock> OmpStructureChecker::GetObjectSource (
4290+ const parser::OmpObject &object) {
4291+ if (auto *name{std::get_if<parser::Name>(&object.u )}) {
4292+ return name->source ;
4293+ } else if (auto *desg{std::get_if<parser::Designator>(&object.u )}) {
4294+ return GetLastName (*desg).source ;
4295+ }
4296+ return std::nullopt ;
4297+ }
4298+
42174299void OmpStructureChecker::CheckDependList (const parser::DataRef &d) {
42184300 common::visit (
42194301 common::visitors{
@@ -4267,15 +4349,6 @@ void OmpStructureChecker::CheckArraySection(
42674349 " DEPEND "
42684350 " clause" _err_en_US);
42694351 }
4270- const auto stride{GetIntValue (strideExpr)};
4271- if ((stride && stride != 1 )) {
4272- context_.Say (GetContext ().clauseSource ,
4273- " A list item that appears in a REDUCTION clause"
4274- " should have a contiguous storage array "
4275- " section." _err_en_US,
4276- ContextDirectiveAsFortran ());
4277- break ;
4278- }
42794352 }
42804353 }
42814354 }
@@ -4286,14 +4359,23 @@ void OmpStructureChecker::CheckArraySection(
42864359}
42874360
42884361void OmpStructureChecker::CheckIntentInPointer (
4289- const parser::OmpObjectList &objectList, const llvm::omp::Clause clause) {
4290- SymbolSourceMap symbols;
4291- GetSymbolsInObjectList (objectList, symbols);
4362+ SymbolSourceMap &symbols, llvm::omp::Clause clauseId) {
42924363 for (auto &[symbol, source] : symbols) {
42934364 if (IsPointer (*symbol) && IsIntentIn (*symbol)) {
42944365 context_.Say (source,
4295- " Pointer '%s' with the INTENT(IN) attribute may not appear "
4296- " in a %s clause" _err_en_US,
4366+ " Pointer '%s' with the INTENT(IN) attribute may not appear in a %s clause" _err_en_US,
4367+ symbol->name (),
4368+ parser::ToUpperCaseLetters (getClauseName (clauseId).str ()));
4369+ }
4370+ }
4371+ }
4372+
4373+ void OmpStructureChecker::CheckProcedurePointer (
4374+ SymbolSourceMap &symbols, llvm::omp::Clause clause) {
4375+ for (const auto &[symbol, source] : symbols) {
4376+ if (IsProcedurePointer (*symbol)) {
4377+ context_.Say (source,
4378+ " Procedure pointer '%s' may not appear in a %s clause" _err_en_US,
42974379 symbol->name (),
42984380 parser::ToUpperCaseLetters (getClauseName (clause).str ()));
42994381 }
0 commit comments