@@ -383,6 +383,21 @@ void OmpStructureChecker::CheckMultListItems() {
383383 CheckMultipleOccurrence (
384384 listVars, nontempNameList, clause->source , " NONTEMPORAL" );
385385 }
386+
387+ // Linear clause
388+ for (auto [_, clause] : FindClauses (llvm::omp::Clause::OMPC_linear)) {
389+ const auto &linearClause{std::get<parser::OmpClause::Linear>(clause->u )};
390+ std::list<parser::Name> nameList;
391+ common::visit (
392+ common::visitors{
393+ [&](const auto &u) {
394+ std::copy (
395+ u.names .begin (), u.names .end (), std::back_inserter (nameList));
396+ },
397+ },
398+ linearClause.v .u );
399+ CheckMultipleOccurrence (listVars, nameList, clause->source , " LINEAR" );
400+ }
386401}
387402
388403bool OmpStructureChecker::HasInvalidWorksharingNesting (
@@ -2686,12 +2701,12 @@ void OmpStructureChecker::Leave(const parser::OmpClauseList &) {
26862701 }
26872702 }
26882703 }
2689-
2690- // Sema checks related to presence of multiple list items within the same
2691- // clause
2692- CheckMultListItems ();
26932704 } // SIMD
26942705
2706+ // Semantic checks related to presence of multiple list items within the same
2707+ // clause
2708+ CheckMultListItems ();
2709+
26952710 // 2.7.3 Single Construct Restriction
26962711 if (GetContext ().directive == llvm::omp::Directive::OMPD_end_single) {
26972712 CheckNotAllowedIfClause (
@@ -3542,16 +3557,88 @@ void OmpStructureChecker::Enter(const parser::OmpClause::If &x) {
35423557void OmpStructureChecker::Enter (const parser::OmpClause::Linear &x) {
35433558 CheckAllowedClause (llvm::omp::Clause::OMPC_linear);
35443559
3560+ parser::CharBlock source{GetContext ().clauseSource };
35453561 // 2.7 Loop Construct Restriction
35463562 if ((llvm::omp::allDoSet | llvm::omp::allSimdSet)
35473563 .test (GetContext ().directive )) {
35483564 if (std::holds_alternative<parser::OmpLinearClause::WithModifier>(x.v .u )) {
3549- context_.Say (GetContext (). clauseSource ,
3565+ context_.Say (source ,
35503566 " A modifier may not be specified in a LINEAR clause "
35513567 " on the %s directive" _err_en_US,
35523568 ContextDirectiveAsFortran ());
3569+ return ;
35533570 }
35543571 }
3572+
3573+ auto checkForValidLinearClause_01 = [&](const parser::Name &name,
3574+ bool is_ref) {
3575+ std::string listItemName{name.ToString ()};
3576+ if (!is_ref && !name.symbol ->GetType ()->IsNumeric (TypeCategory::Integer)) {
3577+ context_.Say (source,
3578+ " The list item `%s` specified with other than linear-modifier `REF`"
3579+ " must be of type INTEGER" _err_en_US,
3580+ listItemName);
3581+ }
3582+ if (GetContext ().directive == llvm::omp::Directive::OMPD_declare_simd &&
3583+ !IsDummy (*name.symbol )) {
3584+ context_.Say (source,
3585+ " The list item `%s` must be a dummy argument" _err_en_US,
3586+ listItemName);
3587+ }
3588+ if (IsPointer (*name.symbol ) ||
3589+ name.symbol ->test (Symbol::Flag::CrayPointer)) {
3590+ context_.Say (source,
3591+ " The list item `%s` in a LINEAR clause must not be Cray Pointer "
3592+ " or a variable with POINTER attribute" _err_en_US,
3593+ listItemName);
3594+ }
3595+ if (FindCommonBlockContaining (*name.symbol )) {
3596+ context_.Say (source,
3597+ " '%s' is a common block name and must not appear in an "
3598+ " LINEAR clause" _err_en_US,
3599+ listItemName);
3600+ }
3601+ };
3602+
3603+ auto checkForValidLinearClause_02 = [&](const parser::Name &name,
3604+ const parser::OmpLinearModifier::Value
3605+ &modifierValue) {
3606+ std::string listItemName{name.ToString ()};
3607+ checkForValidLinearClause_01 (
3608+ name, (modifierValue == parser::OmpLinearModifier::Value::Ref));
3609+ if (modifierValue != parser::OmpLinearModifier::Value::Val &&
3610+ IsDummy (*name.symbol ) && IsValue (*name.symbol )) {
3611+ context_.Say (source,
3612+ " The list item `%s` specified with the linear-modifier `REF` or "
3613+ " `UVAL` must be a dummy argument without `VALUE` attribute" _err_en_US,
3614+ listItemName);
3615+ }
3616+ if (modifierValue == parser::OmpLinearModifier::Value::Ref &&
3617+ !(IsAllocatable (*name.symbol ) || IsAssumedShape (*name.symbol ) ||
3618+ IsPolymorphic (*name.symbol ))) {
3619+ context_.Say (source,
3620+ " The list item `%s` specified with the linear-modifier `REF` "
3621+ " must be polymorphic variable, assumed-shape array, or a variable"
3622+ " with the `ALLOCATABLE` attribute" _err_en_US,
3623+ listItemName);
3624+ }
3625+ };
3626+
3627+ // OpenMP 5.2: Linear clause Restrictions
3628+ common::visit (
3629+ common::visitors{
3630+ [&](const parser::OmpLinearClause::WithoutModifier &withoutModifier) {
3631+ for (const auto &name : withoutModifier.names )
3632+ if (name.symbol )
3633+ checkForValidLinearClause_01 (name, false );
3634+ },
3635+ [&](const parser::OmpLinearClause::WithModifier &withModifier) {
3636+ for (const auto &name : withModifier.names )
3637+ if (name.symbol )
3638+ checkForValidLinearClause_02 (name, withModifier.modifier .v );
3639+ },
3640+ },
3641+ x.v .u );
35553642}
35563643
35573644void OmpStructureChecker::CheckAllowedMapTypes (
0 commit comments