@@ -51,6 +51,30 @@ std::string TryVersion(unsigned version) {
51
51
return " try -fopenmp-version=" + std::to_string (version);
52
52
}
53
53
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
+
54
78
// 'OmpWorkshareBlockChecker' is used to check the validity of the assignment
55
79
// statements and the expressions enclosed in an OpenMP Workshare construct
56
80
class OmpWorkshareBlockChecker {
@@ -222,6 +246,10 @@ bool OmpStructureChecker::CheckAllowedClause(llvmOmpClause clause) {
222
246
return CheckAllowed (clause);
223
247
}
224
248
249
+ bool OmpStructureChecker::IsCommonBlock (const Symbol &sym) {
250
+ return sym.detailsIf <CommonBlockDetails>() != nullptr ;
251
+ }
252
+
225
253
bool OmpStructureChecker::IsVariableListItem (const Symbol &sym) {
226
254
return evaluate::IsVariable (sym) || sym.attrs ().test (Attr::POINTER);
227
255
}
@@ -2895,6 +2923,8 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Reduction &x) {
2895
2923
CheckReductionModifier (*maybeModifier);
2896
2924
}
2897
2925
}
2926
+ CheckReductionObjects (std::get<parser::OmpObjectList>(x.v .t ),
2927
+ llvm::omp::Clause::OMPC_reduction);
2898
2928
}
2899
2929
2900
2930
bool OmpStructureChecker::CheckReductionOperators (
@@ -2963,6 +2993,69 @@ bool OmpStructureChecker::CheckIntrinsicOperator(
2963
2993
return false ;
2964
2994
}
2965
2995
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
+
2966
3059
static bool IsReductionAllowedForType (
2967
3060
const parser::OmpClause::Reduction &x, const DeclTypeSpec &type) {
2968
3061
auto &modifiers{OmpGetModifiers (x.v )};
@@ -3052,26 +3145,25 @@ static bool IsReductionAllowedForType(
3052
3145
void OmpStructureChecker::CheckReductionTypeList (
3053
3146
const parser::OmpClause::Reduction &x) {
3054
3147
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
+
3057
3151
CheckReductionArraySection (ompObjectList);
3058
3152
// If this is a worksharing construct then ensure the reduction variable
3059
3153
// is not private in the parallel region that it binds to.
3060
3154
if (llvm::omp::nestedReduceWorkshareAllowedSet.test (GetContext ().directive )) {
3061
3155
CheckSharedBindingInOuterContext (ompObjectList);
3062
3156
}
3063
3157
3064
- SymbolSourceMap symbols;
3065
- GetSymbolsInObjectList (ompObjectList, symbols);
3066
3158
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 " );
3075
3167
}
3076
3168
}
3077
3169
}
@@ -3127,43 +3219,14 @@ void OmpStructureChecker::CheckReductionModifier(
3127
3219
}
3128
3220
}
3129
3221
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
-
3157
3222
void OmpStructureChecker::CheckReductionArraySection (
3158
3223
const parser::OmpObjectList &ompObjectList) {
3159
3224
for (const auto &ompObject : ompObjectList.v ) {
3160
3225
if (const auto *dataRef{parser::Unwrap<parser::DataRef>(ompObject)}) {
3161
3226
if (const auto *arrayElement{
3162
3227
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);
3167
3230
}
3168
3231
}
3169
3232
}
@@ -3232,9 +3295,11 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Shared &x) {
3232
3295
CheckIsVarPartOfAnotherVar (GetContext ().clauseSource , x.v , " SHARED" );
3233
3296
}
3234
3297
void OmpStructureChecker::Enter (const parser::OmpClause::Private &x) {
3298
+ SymbolSourceMap symbols;
3299
+ GetSymbolsInObjectList (x.v , symbols);
3235
3300
CheckAllowedClause (llvm::omp::Clause::OMPC_private);
3236
3301
CheckIsVarPartOfAnotherVar (GetContext ().clauseSource , x.v , " PRIVATE" );
3237
- CheckIntentInPointer (x. v , llvm::omp::Clause::OMPC_private);
3302
+ CheckIntentInPointer (symbols , llvm::omp::Clause::OMPC_private);
3238
3303
}
3239
3304
3240
3305
void OmpStructureChecker::Enter (const parser::OmpClause::Nowait &x) {
@@ -3891,11 +3956,11 @@ void OmpStructureChecker::CheckCopyingPolymorphicAllocatable(
3891
3956
3892
3957
void OmpStructureChecker::Enter (const parser::OmpClause::Copyprivate &x) {
3893
3958
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 );
3897
3962
CheckCopyingPolymorphicAllocatable (
3898
- currSymbols , llvm::omp::Clause::OMPC_copyprivate);
3963
+ symbols , llvm::omp::Clause::OMPC_copyprivate);
3899
3964
if (GetContext ().directive == llvm::omp::Directive::OMPD_single) {
3900
3965
context_.Say (GetContext ().clauseSource ,
3901
3966
" %s clause is not allowed on the OMP %s directive,"
@@ -3945,29 +4010,26 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Copyin &x) {
3945
4010
currSymbols, llvm::omp::Clause::OMPC_copyin);
3946
4011
}
3947
4012
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 ) {
3952
4026
common::visit (
3953
4027
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,
3966
4029
[&](const parser::Name &name) {},
3967
4030
},
3968
- ompObject .u );
4031
+ object .u );
3969
4032
}
3970
- return ;
3971
4033
}
3972
4034
3973
4035
void OmpStructureChecker::Enter (const parser::OmpClause::Update &x) {
@@ -4009,7 +4071,7 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Update &x) {
4009
4071
}
4010
4072
4011
4073
void 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);
4013
4075
CheckAllowedClause (llvm::omp::Clause::OMPC_use_device_ptr);
4014
4076
SymbolSourceMap currSymbols;
4015
4077
GetSymbolsInObjectList (x.v , currSymbols);
@@ -4038,7 +4100,7 @@ void OmpStructureChecker::Enter(const parser::OmpClause::UseDevicePtr &x) {
4038
4100
}
4039
4101
4040
4102
void 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);
4042
4104
CheckAllowedClause (llvm::omp::Clause::OMPC_use_device_addr);
4043
4105
SymbolSourceMap currSymbols;
4044
4106
GetSymbolsInObjectList (x.v , currSymbols);
@@ -4214,6 +4276,26 @@ llvm::StringRef OmpStructureChecker::getDirectiveName(
4214
4276
return llvm::omp::getOpenMPDirectiveName (directive);
4215
4277
}
4216
4278
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
+
4217
4299
void OmpStructureChecker::CheckDependList (const parser::DataRef &d) {
4218
4300
common::visit (
4219
4301
common::visitors{
@@ -4267,15 +4349,6 @@ void OmpStructureChecker::CheckArraySection(
4267
4349
" DEPEND "
4268
4350
" clause" _err_en_US);
4269
4351
}
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
- }
4279
4352
}
4280
4353
}
4281
4354
}
@@ -4286,14 +4359,23 @@ void OmpStructureChecker::CheckArraySection(
4286
4359
}
4287
4360
4288
4361
void 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) {
4292
4363
for (auto &[symbol, source] : symbols) {
4293
4364
if (IsPointer (*symbol) && IsIntentIn (*symbol)) {
4294
4365
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,
4297
4379
symbol->name (),
4298
4380
parser::ToUpperCaseLetters (getClauseName (clause).str ()));
4299
4381
}
0 commit comments