@@ -303,6 +303,30 @@ void OmpStructureChecker::CheckMultListItems() {
303303 CheckMultipleOccurrence (
304304 listVars, nontempNameList, itr->second ->source , " NONTEMPORAL" );
305305 }
306+
307+ // Linear clause
308+ auto linearClauses{FindClauses (llvm::omp::Clause::OMPC_linear)};
309+ for (auto itr{linearClauses.first }; itr != linearClauses.second ; ++itr) {
310+ const auto &linearClause{
311+ std::get<parser::OmpClause::Linear>(itr->second ->u )};
312+ std::list<parser::Name> nameList;
313+ common::visit (
314+ common::visitors{
315+ [&](const parser::OmpLinearClause::WithoutModifier
316+ &withoutModifier) {
317+ for (const auto &name : withoutModifier.names ) {
318+ nameList.push_back (name);
319+ }
320+ },
321+ [&](const parser::OmpLinearClause::WithModifier &withModifier) {
322+ for (const auto &name : withModifier.names ) {
323+ nameList.push_back (name);
324+ }
325+ },
326+ },
327+ linearClause.v .u );
328+ CheckMultipleOccurrence (listVars, nameList, itr->second ->source , " LINEAR" );
329+ }
306330}
307331
308332bool OmpStructureChecker::HasInvalidWorksharingNesting (
@@ -2256,11 +2280,12 @@ void OmpStructureChecker::Leave(const parser::OmpClauseList &) {
22562280 }
22572281 }
22582282 }
2259- // Sema checks related to presence of multiple list items within the same
2260- // clause
2261- CheckMultListItems ();
22622283 } // SIMD
22632284
2285+ // Semantic checks related to presence of multiple list items within the same
2286+ // clause
2287+ CheckMultListItems ();
2288+
22642289 // 2.7.3 Single Construct Restriction
22652290 if (GetContext ().directive == llvm::omp::Directive::OMPD_end_single) {
22662291 CheckNotAllowedIfClause (
@@ -2975,16 +3000,92 @@ void OmpStructureChecker::Enter(const parser::OmpClause::If &x) {
29753000void OmpStructureChecker::Enter (const parser::OmpClause::Linear &x) {
29763001 CheckAllowedClause (llvm::omp::Clause::OMPC_linear);
29773002
3003+ parser::CharBlock source{GetContext ().clauseSource };
29783004 // 2.7 Loop Construct Restriction
29793005 if ((llvm::omp::allDoSet | llvm::omp::allSimdSet)
29803006 .test (GetContext ().directive )) {
29813007 if (std::holds_alternative<parser::OmpLinearClause::WithModifier>(x.v .u )) {
2982- context_.Say (GetContext (). clauseSource ,
3008+ context_.Say (source ,
29833009 " A modifier may not be specified in a LINEAR clause "
29843010 " on the %s directive" _err_en_US,
29853011 ContextDirectiveAsFortran ());
3012+ return ;
29863013 }
29873014 }
3015+
3016+ auto checkForValidLinearClause = [&](const parser::Name &name, bool is_ref) {
3017+ parser::CharBlock source{GetContext ().clauseSource };
3018+ std::string listItemName{name.ToString ()};
3019+ if (!is_ref && !name.symbol ->GetType ()->IsNumeric (TypeCategory::Integer)) {
3020+ context_.Say (source,
3021+ " The list item `%s` specified with other than linear-modifier `REF`"
3022+ " must be of type INTEGER" _err_en_US,
3023+ listItemName);
3024+ }
3025+ if (GetContext ().directive == llvm::omp::Directive::OMPD_declare_simd &&
3026+ !IsDummy (*name.symbol )) {
3027+ context_.Say (source,
3028+ " The list item `%s` must be a dummy argument" _err_en_US,
3029+ listItemName);
3030+ }
3031+ if (IsPointer (*name.symbol ) ||
3032+ name.symbol ->test (Symbol::Flag::CrayPointer)) {
3033+ context_.Say (source,
3034+ " The list item `%s` in a LINEAR clause must not be Cray Pointer "
3035+ " or a variable with POINTER attribute" _err_en_US,
3036+ listItemName);
3037+ }
3038+ if (FindCommonBlockContaining (*name.symbol )) {
3039+ context_.Say (source,
3040+ " '%s' is a common block name and must not appear in an "
3041+ " LINEAR clause" _err_en_US,
3042+ listItemName);
3043+ }
3044+ };
3045+
3046+ // OpenMP 5.2: Linear clause Restrictions
3047+ common::visit (
3048+ common::visitors{
3049+ [&](const parser::OmpLinearClause::WithoutModifier &withoutModifier) {
3050+ for (const auto &name : withoutModifier.names ) {
3051+ if (name.symbol ) {
3052+ checkForValidLinearClause (name, false );
3053+ }
3054+ }
3055+ },
3056+ [&](const parser::OmpLinearClause::WithModifier &withModifier) {
3057+ for (const auto &name : withModifier.names ) {
3058+ if (name.symbol ) {
3059+ checkForValidLinearClause (name,
3060+ (withModifier.modifier .v ==
3061+ parser::OmpLinearModifier::Type::Ref));
3062+ std::string listItemName{name.ToString ()};
3063+ if (withModifier.modifier .v !=
3064+ parser::OmpLinearModifier::Type::Val &&
3065+ IsDummy (*name.symbol ) && IsValue (*name.symbol )) {
3066+ context_.Say (source,
3067+ " The list item `%s` specified with the linear-modifier "
3068+ " `REF` or `UVAL` must be a dummy argument without "
3069+ " `VALUE` attribute" _err_en_US,
3070+ listItemName);
3071+ }
3072+ if (withModifier.modifier .v ==
3073+ parser::OmpLinearModifier::Type::Ref &&
3074+ !(IsAllocatable (*name.symbol ) ||
3075+ IsAssumedShape (*name.symbol ) ||
3076+ IsPolymorphic (*name.symbol ))) {
3077+ context_.Say (source,
3078+ " The list item `%s` specified with the linear-modifier "
3079+ " `REF` must be polymorphic variable, assumed-shape "
3080+ " array, "
3081+ " or a variable with the `ALLOCATABLE` attribute" _err_en_US,
3082+ listItemName);
3083+ }
3084+ }
3085+ }
3086+ },
3087+ },
3088+ x.v .u );
29883089}
29893090
29903091void OmpStructureChecker::CheckAllowedMapTypes (
0 commit comments