@@ -268,6 +268,43 @@ bool OmpStructureChecker::CheckAllowedClause(llvmOmpClause clause) {
268268 return CheckAllowed (clause);
269269}
270270
271+ void OmpStructureChecker::AnalyzeObject (
272+ const parser::OmpObject &object, bool allowAssumedSizeArrays) {
273+ if (std::holds_alternative<parser::Name>(object.u )) {
274+ // Do not analyze common block names. The analyzer will flag an error
275+ // on those.
276+ return ;
277+ }
278+ if (auto *symbol{GetObjectSymbol (object)}) {
279+ // Eliminate certain kinds of symbols before running the analyzer to
280+ // avoid confusing error messages. The analyzer assumes that the context
281+ // of the object use is an expression, and some diagnostics are tailored
282+ // to that.
283+ if (symbol->has <DerivedTypeDetails>() || symbol->has <MiscDetails>()) {
284+ // Type names, construct names, etc.
285+ return ;
286+ }
287+ if (auto *typeSpec{symbol->GetType ()}) {
288+ if (typeSpec->category () == DeclTypeSpec::Category::Character) {
289+ // Don't pass character objects to the analyzer, it can emit somewhat
290+ // cryptic errors (e.g. "'obj' is not an array"). Substrings are
291+ // checked elsewhere in OmpStructureChecker.
292+ return ;
293+ }
294+ }
295+ }
296+ evaluate::ExpressionAnalyzer ea{context_};
297+ auto restore{ea.AllowWholeAssumedSizeArray (allowAssumedSizeArrays)};
298+ common::visit ([&](auto &&s) { ea.Analyze (s); }, object.u );
299+ }
300+
301+ void OmpStructureChecker::AnalyzeObjects (
302+ const parser::OmpObjectList &objects, bool allowAssumedSizeArrays) {
303+ for (const parser::OmpObject &object : objects.v ) {
304+ AnalyzeObject (object, allowAssumedSizeArrays);
305+ }
306+ }
307+
271308bool OmpStructureChecker::IsCloselyNestedRegion (const OmpDirectiveSet &set) {
272309 // Definition of close nesting:
273310 //
@@ -2697,8 +2734,9 @@ void OmpStructureChecker::Leave(const parser::OmpClauseList &) {
26972734void OmpStructureChecker::Enter (const parser::OmpClause &x) {
26982735 SetContextClause (x);
26992736
2737+ llvm::omp::Clause id{x.Id ()};
27002738 // The visitors for these clauses do their own checks.
2701- switch (x. Id () ) {
2739+ switch (id ) {
27022740 case llvm::omp::Clause::OMPC_copyprivate:
27032741 case llvm::omp::Clause::OMPC_enter:
27042742 case llvm::omp::Clause::OMPC_lastprivate:
@@ -2712,7 +2750,7 @@ void OmpStructureChecker::Enter(const parser::OmpClause &x) {
27122750 // Named constants are OK to be used within 'shared' and 'firstprivate'
27132751 // clauses. The check for this happens a few lines below.
27142752 bool SharedOrFirstprivate = false ;
2715- switch (x. Id () ) {
2753+ switch (id ) {
27162754 case llvm::omp::Clause::OMPC_shared:
27172755 case llvm::omp::Clause::OMPC_firstprivate:
27182756 SharedOrFirstprivate = true ;
@@ -2721,7 +2759,20 @@ void OmpStructureChecker::Enter(const parser::OmpClause &x) {
27212759 break ;
27222760 }
27232761
2762+ auto allowsAssumedSizeArrays{[](llvm::omp::Clause c) {
2763+ // These clauses allow assumed-size-arrays as list items.
2764+ switch (c) {
2765+ case llvm::omp::Clause::OMPC_map:
2766+ case llvm::omp::Clause::OMPC_shared:
2767+ case llvm::omp::Clause::OMPC_use_device_addr:
2768+ return true ;
2769+ default :
2770+ return false ;
2771+ }
2772+ }};
2773+
27242774 if (const parser::OmpObjectList *objList{GetOmpObjectList (x)}) {
2775+ AnalyzeObjects (*objList, allowsAssumedSizeArrays (id));
27252776 SymbolSourceMap symbols;
27262777 GetSymbolsInObjectList (*objList, symbols);
27272778 for (const auto &[symbol, source] : symbols) {
0 commit comments