@@ -268,6 +268,41 @@ bool OmpStructureChecker::CheckAllowedClause(llvmOmpClause clause) {
268268 return CheckAllowed (clause);
269269}
270270
271+ void OmpStructureChecker::AnalyzeObject (const parser::OmpObject &object) {
272+ if (std::holds_alternative<parser::Name>(object.u )) {
273+ // Do not analyze common block names. The analyzer will flag an error
274+ // on those.
275+ return ;
276+ }
277+ if (auto *symbol{GetObjectSymbol (object)}) {
278+ // Eliminate certain kinds of symbols before running the analyzer to
279+ // avoid confusing error messages. The analyzer assumes that the context
280+ // of the object use is an expression, and some diagnostics are tailored
281+ // to that.
282+ if (symbol->has <DerivedTypeDetails>() || symbol->has <MiscDetails>()) {
283+ // Type names, construct names, etc.
284+ return ;
285+ }
286+ if (auto *typeSpec{symbol->GetType ()}) {
287+ if (typeSpec->category () == DeclTypeSpec::Category::Character) {
288+ // Don't pass character objects to the analyzer, it can emit somewhat
289+ // cryptic errors (e.g. "'obj' is not an array"). Substrings are
290+ // checked elsewhere in OmpStructureChecker.
291+ return ;
292+ }
293+ }
294+ }
295+ evaluate::ExpressionAnalyzer ea{context_};
296+ auto restore{ea.AllowWholeAssumedSizeArray (true )};
297+ common::visit ([&](auto &&s) { ea.Analyze (s); }, object.u );
298+ }
299+
300+ void OmpStructureChecker::AnalyzeObjects (const parser::OmpObjectList &objects) {
301+ for (const parser::OmpObject &object : objects.v ) {
302+ AnalyzeObject (object);
303+ }
304+ }
305+
271306bool OmpStructureChecker::IsCloselyNestedRegion (const OmpDirectiveSet &set) {
272307 // Definition of close nesting:
273308 //
@@ -2697,8 +2732,9 @@ void OmpStructureChecker::Leave(const parser::OmpClauseList &) {
26972732void OmpStructureChecker::Enter (const parser::OmpClause &x) {
26982733 SetContextClause (x);
26992734
2735+ llvm::omp::Clause id{x.Id ()};
27002736 // The visitors for these clauses do their own checks.
2701- switch (x. Id () ) {
2737+ switch (id ) {
27022738 case llvm::omp::Clause::OMPC_copyprivate:
27032739 case llvm::omp::Clause::OMPC_enter:
27042740 case llvm::omp::Clause::OMPC_lastprivate:
@@ -2712,7 +2748,7 @@ void OmpStructureChecker::Enter(const parser::OmpClause &x) {
27122748 // Named constants are OK to be used within 'shared' and 'firstprivate'
27132749 // clauses. The check for this happens a few lines below.
27142750 bool SharedOrFirstprivate = false ;
2715- switch (x. Id () ) {
2751+ switch (id ) {
27162752 case llvm::omp::Clause::OMPC_shared:
27172753 case llvm::omp::Clause::OMPC_firstprivate:
27182754 SharedOrFirstprivate = true ;
@@ -2722,6 +2758,7 @@ void OmpStructureChecker::Enter(const parser::OmpClause &x) {
27222758 }
27232759
27242760 if (const parser::OmpObjectList *objList{GetOmpObjectList (x)}) {
2761+ AnalyzeObjects (*objList);
27252762 SymbolSourceMap symbols;
27262763 GetSymbolsInObjectList (*objList, symbols);
27272764 for (const auto &[symbol, source] : symbols) {
0 commit comments