@@ -268,6 +268,41 @@ bool OmpStructureChecker::CheckAllowedClause(llvmOmpClause clause) {
268
268
return CheckAllowed (clause);
269
269
}
270
270
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
+
271
306
bool OmpStructureChecker::IsCloselyNestedRegion (const OmpDirectiveSet &set) {
272
307
// Definition of close nesting:
273
308
//
@@ -2697,8 +2732,9 @@ void OmpStructureChecker::Leave(const parser::OmpClauseList &) {
2697
2732
void OmpStructureChecker::Enter (const parser::OmpClause &x) {
2698
2733
SetContextClause (x);
2699
2734
2735
+ llvm::omp::Clause id{x.Id ()};
2700
2736
// The visitors for these clauses do their own checks.
2701
- switch (x. Id () ) {
2737
+ switch (id ) {
2702
2738
case llvm::omp::Clause::OMPC_copyprivate:
2703
2739
case llvm::omp::Clause::OMPC_enter:
2704
2740
case llvm::omp::Clause::OMPC_lastprivate:
@@ -2712,7 +2748,7 @@ void OmpStructureChecker::Enter(const parser::OmpClause &x) {
2712
2748
// Named constants are OK to be used within 'shared' and 'firstprivate'
2713
2749
// clauses. The check for this happens a few lines below.
2714
2750
bool SharedOrFirstprivate = false ;
2715
- switch (x. Id () ) {
2751
+ switch (id ) {
2716
2752
case llvm::omp::Clause::OMPC_shared:
2717
2753
case llvm::omp::Clause::OMPC_firstprivate:
2718
2754
SharedOrFirstprivate = true ;
@@ -2722,6 +2758,7 @@ void OmpStructureChecker::Enter(const parser::OmpClause &x) {
2722
2758
}
2723
2759
2724
2760
if (const parser::OmpObjectList *objList{GetOmpObjectList (x)}) {
2761
+ AnalyzeObjects (*objList);
2725
2762
SymbolSourceMap symbols;
2726
2763
GetSymbolsInObjectList (*objList, symbols);
2727
2764
for (const auto &[symbol, source] : symbols) {
0 commit comments