@@ -16,25 +16,25 @@ namespace Fortran::semantics {
16
16
// Use when clause falls under 'struct OmpClause' in 'parse-tree.h'.
17
17
#define CHECK_SIMPLE_CLAUSE (X, Y ) \
18
18
void OmpStructureChecker::Enter (const parser::OmpClause::X &) { \
19
- CheckAllowed (llvm::omp::Clause::Y); \
19
+ CheckAllowedClause (llvm::omp::Clause::Y); \
20
20
}
21
21
22
22
#define CHECK_REQ_CONSTANT_SCALAR_INT_CLAUSE (X, Y ) \
23
23
void OmpStructureChecker::Enter (const parser::OmpClause::X &c) { \
24
- CheckAllowed (llvm::omp::Clause::Y); \
24
+ CheckAllowedClause (llvm::omp::Clause::Y); \
25
25
RequiresConstantPositiveParameter (llvm::omp::Clause::Y, c.v ); \
26
26
}
27
27
28
28
#define CHECK_REQ_SCALAR_INT_CLAUSE (X, Y ) \
29
29
void OmpStructureChecker::Enter (const parser::OmpClause::X &c) { \
30
- CheckAllowed (llvm::omp::Clause::Y); \
30
+ CheckAllowedClause (llvm::omp::Clause::Y); \
31
31
RequiresPositiveParameter (llvm::omp::Clause::Y, c.v ); \
32
32
}
33
33
34
34
// Use when clause don't falls under 'struct OmpClause' in 'parse-tree.h'.
35
35
#define CHECK_SIMPLE_PARSER_CLAUSE (X, Y ) \
36
36
void OmpStructureChecker::Enter (const parser::X &) { \
37
- CheckAllowed (llvm::omp::Y); \
37
+ CheckAllowedClause (llvm::omp::Y); \
38
38
}
39
39
40
40
// 'OmpWorkshareBlockChecker' is used to check the validity of the assignment
@@ -163,6 +163,43 @@ class AssociatedLoopChecker {
163
163
std::map<std::string, std::int64_t > constructNamesAndLevels_;
164
164
};
165
165
166
+ bool OmpStructureChecker::CheckAllowedClause (llvmOmpClause clause) {
167
+ unsigned version{context_.langOptions ().OpenMPVersion };
168
+ DirectiveContext &dirCtx = GetContext ();
169
+ llvm::omp::Directive dir{dirCtx.directive };
170
+
171
+ if (!llvm::omp::isAllowedClauseForDirective (dir, clause, version)) {
172
+ unsigned allowedInVersion{[&] {
173
+ for (unsigned v : {45 , 50 , 51 , 52 , 60 }) {
174
+ if (v <= version) {
175
+ continue ;
176
+ }
177
+ if (llvm::omp::isAllowedClauseForDirective (dir, clause, v)) {
178
+ return v;
179
+ }
180
+ }
181
+ return 0u ;
182
+ }()};
183
+
184
+ // Only report it if there is a later version that allows it.
185
+ // If it's not allowed at all, it will be reported by CheckAllowed.
186
+ if (allowedInVersion != 0 ) {
187
+ auto clauseName{parser::ToUpperCaseLetters (getClauseName (clause).str ())};
188
+ auto dirName{parser::ToUpperCaseLetters (getDirectiveName (dir).str ())};
189
+
190
+ std::string thisVersion{
191
+ std::to_string (version / 10 ) + " ." + std::to_string (version % 10 )};
192
+ std::string goodVersion{std::to_string (allowedInVersion)};
193
+
194
+ context_.Say (dirCtx.clauseSource ,
195
+ " %s clause is not allowed on directive %s in OpenMP v%s, "
196
+ " try -fopenmp-version=%d" _err_en_US,
197
+ clauseName, dirName, thisVersion, allowedInVersion);
198
+ }
199
+ }
200
+ return CheckAllowed (clause);
201
+ }
202
+
166
203
bool OmpStructureChecker::IsCloselyNestedRegion (const OmpDirectiveSet &set) {
167
204
// Definition of close nesting:
168
205
//
@@ -1156,7 +1193,7 @@ void OmpStructureChecker::Leave(const parser::OpenMPDeclarativeAllocate &x) {
1156
1193
}
1157
1194
1158
1195
void OmpStructureChecker::Enter (const parser::OmpClause::Allocator &x) {
1159
- CheckAllowed (llvm::omp::Clause::OMPC_allocator);
1196
+ CheckAllowedClause (llvm::omp::Clause::OMPC_allocator);
1160
1197
// Note: Predefined allocators are stored in ScalarExpr as numbers
1161
1198
// whereas custom allocators are stored as strings, so if the ScalarExpr
1162
1199
// actually has an int value, then it must be a predefined allocator
@@ -1165,7 +1202,7 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Allocator &x) {
1165
1202
}
1166
1203
1167
1204
void OmpStructureChecker::Enter (const parser::OmpClause::Allocate &x) {
1168
- CheckAllowed (llvm::omp::Clause::OMPC_allocate);
1205
+ CheckAllowedClause (llvm::omp::Clause::OMPC_allocate);
1169
1206
if (const auto &modifier{
1170
1207
std::get<std::optional<parser::OmpAllocateClause::AllocateModifier>>(
1171
1208
x.v .t )}) {
@@ -2362,7 +2399,7 @@ CHECK_REQ_CONSTANT_SCALAR_INT_CLAUSE(Simdlen, OMPC_simdlen)
2362
2399
// Restrictions specific to each clause are implemented apart from the
2363
2400
// generalized restrictions.
2364
2401
void OmpStructureChecker::Enter (const parser::OmpClause::Reduction &x) {
2365
- CheckAllowed (llvm::omp::Clause::OMPC_reduction);
2402
+ CheckAllowedClause (llvm::omp::Clause::OMPC_reduction);
2366
2403
if (CheckReductionOperators (x)) {
2367
2404
CheckReductionTypeList (x);
2368
2405
}
@@ -2686,7 +2723,7 @@ void OmpStructureChecker::CheckSharedBindingInOuterContext(
2686
2723
}
2687
2724
2688
2725
void OmpStructureChecker::Enter (const parser::OmpClause::Ordered &x) {
2689
- CheckAllowed (llvm::omp::Clause::OMPC_ordered);
2726
+ CheckAllowedClause (llvm::omp::Clause::OMPC_ordered);
2690
2727
// the parameter of ordered clause is optional
2691
2728
if (const auto &expr{x.v }) {
2692
2729
RequiresConstantPositiveParameter (llvm::omp::Clause::OMPC_ordered, *expr);
@@ -2701,17 +2738,17 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Ordered &x) {
2701
2738
}
2702
2739
2703
2740
void OmpStructureChecker::Enter (const parser::OmpClause::Shared &x) {
2704
- CheckAllowed (llvm::omp::Clause::OMPC_shared);
2741
+ CheckAllowedClause (llvm::omp::Clause::OMPC_shared);
2705
2742
CheckIsVarPartOfAnotherVar (GetContext ().clauseSource , x.v , " SHARED" );
2706
2743
}
2707
2744
void OmpStructureChecker::Enter (const parser::OmpClause::Private &x) {
2708
- CheckAllowed (llvm::omp::Clause::OMPC_private);
2745
+ CheckAllowedClause (llvm::omp::Clause::OMPC_private);
2709
2746
CheckIsVarPartOfAnotherVar (GetContext ().clauseSource , x.v , " PRIVATE" );
2710
2747
CheckIntentInPointer (x.v , llvm::omp::Clause::OMPC_private);
2711
2748
}
2712
2749
2713
2750
void OmpStructureChecker::Enter (const parser::OmpClause::Nowait &x) {
2714
- CheckAllowed (llvm::omp::Clause::OMPC_nowait);
2751
+ CheckAllowedClause (llvm::omp::Clause::OMPC_nowait);
2715
2752
if (llvm::omp::noWaitClauseNotAllowedSet.test (GetContext ().directive )) {
2716
2753
context_.Say (GetContext ().clauseSource ,
2717
2754
" %s clause is not allowed on the OMP %s directive,"
@@ -2784,7 +2821,7 @@ void OmpStructureChecker::CheckIsVarPartOfAnotherVar(
2784
2821
}
2785
2822
2786
2823
void OmpStructureChecker::Enter (const parser::OmpClause::Firstprivate &x) {
2787
- CheckAllowed (llvm::omp::Clause::OMPC_firstprivate);
2824
+ CheckAllowedClause (llvm::omp::Clause::OMPC_firstprivate);
2788
2825
2789
2826
CheckIsVarPartOfAnotherVar (GetContext ().clauseSource , x.v , " FIRSTPRIVATE" );
2790
2827
CheckIsLoopIvPartOfClause (llvmOmpClause::OMPC_firstprivate, x.v );
@@ -2871,7 +2908,7 @@ void OmpStructureChecker::Leave(const parser::OmpAtomic &) {
2871
2908
// Restrictions specific to each clause are implemented apart from the
2872
2909
// generalized restrictions.
2873
2910
void OmpStructureChecker::Enter (const parser::OmpClause::Aligned &x) {
2874
- CheckAllowed (llvm::omp::Clause::OMPC_aligned);
2911
+ CheckAllowedClause (llvm::omp::Clause::OMPC_aligned);
2875
2912
2876
2913
if (const auto &expr{
2877
2914
std::get<std::optional<parser::ScalarIntConstantExpr>>(x.v .t )}) {
@@ -2880,7 +2917,7 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Aligned &x) {
2880
2917
// 2.8.1 TODO: list-item attribute check
2881
2918
}
2882
2919
void OmpStructureChecker::Enter (const parser::OmpClause::Defaultmap &x) {
2883
- CheckAllowed (llvm::omp::Clause::OMPC_defaultmap);
2920
+ CheckAllowedClause (llvm::omp::Clause::OMPC_defaultmap);
2884
2921
using VariableCategory = parser::OmpDefaultmapClause::VariableCategory;
2885
2922
if (!std::get<std::optional<VariableCategory>>(x.v .t )) {
2886
2923
context_.Say (GetContext ().clauseSource ,
@@ -2889,7 +2926,7 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Defaultmap &x) {
2889
2926
}
2890
2927
}
2891
2928
void OmpStructureChecker::Enter (const parser::OmpClause::If &x) {
2892
- CheckAllowed (llvm::omp::Clause::OMPC_if);
2929
+ CheckAllowedClause (llvm::omp::Clause::OMPC_if);
2893
2930
using dirNameModifier = parser::OmpIfClause::DirectiveNameModifier;
2894
2931
// TODO Check that, when multiple 'if' clauses are applied to a combined
2895
2932
// construct, at most one of them applies to each directive.
@@ -2925,7 +2962,7 @@ void OmpStructureChecker::Enter(const parser::OmpClause::If &x) {
2925
2962
}
2926
2963
2927
2964
void OmpStructureChecker::Enter (const parser::OmpClause::Linear &x) {
2928
- CheckAllowed (llvm::omp::Clause::OMPC_linear);
2965
+ CheckAllowedClause (llvm::omp::Clause::OMPC_linear);
2929
2966
2930
2967
// 2.7 Loop Construct Restriction
2931
2968
if ((llvm::omp::allDoSet | llvm::omp::allSimdSet)
@@ -2959,7 +2996,7 @@ void OmpStructureChecker::CheckAllowedMapTypes(
2959
2996
}
2960
2997
2961
2998
void OmpStructureChecker::Enter (const parser::OmpClause::Map &x) {
2962
- CheckAllowed (llvm::omp::Clause::OMPC_map);
2999
+ CheckAllowedClause (llvm::omp::Clause::OMPC_map);
2963
3000
2964
3001
if (const auto &maptype{std::get<std::optional<parser::OmpMapType>>(x.v .t )}) {
2965
3002
using Type = parser::OmpMapType::Type;
@@ -3005,7 +3042,7 @@ bool OmpStructureChecker::ScheduleModifierHasType(
3005
3042
return false ;
3006
3043
}
3007
3044
void OmpStructureChecker::Enter (const parser::OmpClause::Schedule &x) {
3008
- CheckAllowed (llvm::omp::Clause::OMPC_schedule);
3045
+ CheckAllowedClause (llvm::omp::Clause::OMPC_schedule);
3009
3046
const parser::OmpScheduleClause &scheduleClause = x.v ;
3010
3047
3011
3048
// 2.7 Loop Construct Restriction
@@ -3041,7 +3078,7 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Schedule &x) {
3041
3078
}
3042
3079
3043
3080
void OmpStructureChecker::Enter (const parser::OmpClause::Device &x) {
3044
- CheckAllowed (llvm::omp::Clause::OMPC_device);
3081
+ CheckAllowedClause (llvm::omp::Clause::OMPC_device);
3045
3082
const parser::OmpDeviceClause &deviceClause = x.v ;
3046
3083
const auto &device{std::get<1 >(deviceClause.t )};
3047
3084
RequiresPositiveParameter (
@@ -3060,7 +3097,7 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Device &x) {
3060
3097
}
3061
3098
3062
3099
void OmpStructureChecker::Enter (const parser::OmpClause::Depend &x) {
3063
- CheckAllowed (llvm::omp::Clause::OMPC_depend);
3100
+ CheckAllowedClause (llvm::omp::Clause::OMPC_depend);
3064
3101
if ((std::holds_alternative<parser::OmpDependClause::Source>(x.v .u ) ||
3065
3102
std::holds_alternative<parser::OmpDependClause::Sink>(x.v .u )) &&
3066
3103
GetContext ().directive != llvm::omp::OMPD_ordered) {
@@ -3103,7 +3140,7 @@ void OmpStructureChecker::CheckCopyingPolymorphicAllocatable(
3103
3140
}
3104
3141
3105
3142
void OmpStructureChecker::Enter (const parser::OmpClause::Copyprivate &x) {
3106
- CheckAllowed (llvm::omp::Clause::OMPC_copyprivate);
3143
+ CheckAllowedClause (llvm::omp::Clause::OMPC_copyprivate);
3107
3144
CheckIntentInPointer (x.v , llvm::omp::Clause::OMPC_copyprivate);
3108
3145
SymbolSourceMap currSymbols;
3109
3146
GetSymbolsInObjectList (x.v , currSymbols);
@@ -3121,7 +3158,7 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Copyprivate &x) {
3121
3158
}
3122
3159
3123
3160
void OmpStructureChecker::Enter (const parser::OmpClause::Lastprivate &x) {
3124
- CheckAllowed (llvm::omp::Clause::OMPC_lastprivate);
3161
+ CheckAllowedClause (llvm::omp::Clause::OMPC_lastprivate);
3125
3162
3126
3163
CheckIsVarPartOfAnotherVar (GetContext ().clauseSource , x.v , " LASTPRIVATE" );
3127
3164
@@ -3145,7 +3182,7 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Lastprivate &x) {
3145
3182
}
3146
3183
3147
3184
void OmpStructureChecker::Enter (const parser::OmpClause::Copyin &x) {
3148
- CheckAllowed (llvm::omp::Clause::OMPC_copyin);
3185
+ CheckAllowedClause (llvm::omp::Clause::OMPC_copyin);
3149
3186
3150
3187
SymbolSourceMap currSymbols;
3151
3188
GetSymbolsInObjectList (x.v , currSymbols);
@@ -3180,7 +3217,7 @@ void OmpStructureChecker::CheckStructureElement(
3180
3217
3181
3218
void OmpStructureChecker::Enter (const parser::OmpClause::UseDevicePtr &x) {
3182
3219
CheckStructureElement (x.v , llvm::omp::Clause::OMPC_use_device_ptr);
3183
- CheckAllowed (llvm::omp::Clause::OMPC_use_device_ptr);
3220
+ CheckAllowedClause (llvm::omp::Clause::OMPC_use_device_ptr);
3184
3221
SymbolSourceMap currSymbols;
3185
3222
GetSymbolsInObjectList (x.v , currSymbols);
3186
3223
semantics::UnorderedSymbolSet listVars;
@@ -3213,7 +3250,7 @@ void OmpStructureChecker::Enter(const parser::OmpClause::UseDevicePtr &x) {
3213
3250
3214
3251
void OmpStructureChecker::Enter (const parser::OmpClause::UseDeviceAddr &x) {
3215
3252
CheckStructureElement (x.v , llvm::omp::Clause::OMPC_use_device_addr);
3216
- CheckAllowed (llvm::omp::Clause::OMPC_use_device_addr);
3253
+ CheckAllowedClause (llvm::omp::Clause::OMPC_use_device_addr);
3217
3254
SymbolSourceMap currSymbols;
3218
3255
GetSymbolsInObjectList (x.v , currSymbols);
3219
3256
semantics::UnorderedSymbolSet listVars;
@@ -3238,7 +3275,7 @@ void OmpStructureChecker::Enter(const parser::OmpClause::UseDeviceAddr &x) {
3238
3275
}
3239
3276
3240
3277
void OmpStructureChecker::Enter (const parser::OmpClause::IsDevicePtr &x) {
3241
- CheckAllowed (llvm::omp::Clause::OMPC_is_device_ptr);
3278
+ CheckAllowedClause (llvm::omp::Clause::OMPC_is_device_ptr);
3242
3279
SymbolSourceMap currSymbols;
3243
3280
GetSymbolsInObjectList (x.v , currSymbols);
3244
3281
semantics::UnorderedSymbolSet listVars;
@@ -3276,7 +3313,7 @@ void OmpStructureChecker::Enter(const parser::OmpClause::IsDevicePtr &x) {
3276
3313
}
3277
3314
3278
3315
void OmpStructureChecker::Enter (const parser::OmpClause::HasDeviceAddr &x) {
3279
- CheckAllowed (llvm::omp::Clause::OMPC_has_device_addr);
3316
+ CheckAllowedClause (llvm::omp::Clause::OMPC_has_device_addr);
3280
3317
SymbolSourceMap currSymbols;
3281
3318
GetSymbolsInObjectList (x.v , currSymbols);
3282
3319
semantics::UnorderedSymbolSet listVars;
@@ -3621,7 +3658,7 @@ void OmpStructureChecker::Enter(
3621
3658
}
3622
3659
3623
3660
void OmpStructureChecker::CheckAllowedRequiresClause (llvmOmpClause clause) {
3624
- CheckAllowed (clause);
3661
+ CheckAllowedClause (clause);
3625
3662
3626
3663
if (clause != llvm::omp::Clause::OMPC_atomic_default_mem_order) {
3627
3664
// Check that it does not appear after a device construct
0 commit comments