@@ -259,6 +259,57 @@ void OmpStructureChecker::CheckVariableListItem(
259
259
}
260
260
}
261
261
262
+ void OmpStructureChecker::CheckDirectiveSpelling (
263
+ parser::CharBlock spelling, llvm::omp::Directive id) {
264
+ // Directive names that contain spaces can be spelled in the source without
265
+ // any of the spaces. Because of that getOpenMPKind* is not guaranteed to
266
+ // work with the source spelling as the argument.
267
+ //
268
+ // To verify the source spellings, we have to get the spelling for a given
269
+ // version, remove spaces and compare it with the source spelling (also
270
+ // with spaces removed).
271
+ auto removeSpaces = [](llvm::StringRef s) {
272
+ std::string n{s.str ()};
273
+ for (size_t idx{n.size ()}; idx > 0 ; --idx) {
274
+ if (isspace (n[idx - 1 ])) {
275
+ n.erase (idx - 1 , 1 );
276
+ }
277
+ }
278
+ return n;
279
+ };
280
+
281
+ std::string lowerNoWS{removeSpaces (
282
+ parser::ToLowerCaseLetters ({spelling.begin (), spelling.size ()}))};
283
+ llvm::StringRef ref (lowerNoWS);
284
+ if (ref.starts_with (" end" )) {
285
+ ref = ref.drop_front (3 );
286
+ }
287
+
288
+ unsigned version{context_.langOptions ().OpenMPVersion };
289
+
290
+ // For every "future" version v, check if the check if the corresponding
291
+ // spelling of id was introduced later than the current version. If so,
292
+ // and if that spelling matches the source spelling, issue a warning.
293
+ for (unsigned v : llvm::omp::getOpenMPVersions ()) {
294
+ if (v <= version) {
295
+ continue ;
296
+ }
297
+ llvm::StringRef name{llvm::omp::getOpenMPDirectiveName (id, v)};
298
+ auto [kind, versions]{llvm::omp::getOpenMPDirectiveKindAndVersions (name)};
299
+ assert (kind == id && " Directive kind mismatch" );
300
+
301
+ if (static_cast <int >(version) >= versions.Min ) {
302
+ continue ;
303
+ }
304
+ if (ref == removeSpaces (name)) {
305
+ context_.Say (spelling,
306
+ " Directive spelling '%s' is introduced in a later OpenMP version, %s" _warn_en_US,
307
+ parser::ToUpperCaseLetters (ref), TryVersion (versions.Min ));
308
+ break ;
309
+ }
310
+ }
311
+ }
312
+
262
313
void OmpStructureChecker::CheckMultipleOccurrence (
263
314
semantics::UnorderedSymbolSet &listVars,
264
315
const std::list<parser::Name> &nameList, const parser::CharBlock &item,
@@ -436,7 +487,133 @@ void OmpStructureChecker::Leave(const parser::OmpDirectiveSpecification &) {
436
487
}
437
488
}
438
489
490
+ template <typename Checker> struct DirectiveSpellingVisitor {
491
+ using Directive = llvm::omp::Directive;
492
+
493
+ DirectiveSpellingVisitor (Checker &&checker) : checker_(std::move(checker)) {}
494
+
495
+ template <typename T> bool Pre (const T &) { return true ; }
496
+ template <typename T> void Post (const T &) {}
497
+
498
+ bool Pre (const parser::OmpSectionsDirective &x) {
499
+ checker_ (x.source , x.v );
500
+ return false ;
501
+ }
502
+ bool Pre (const parser::OpenMPDeclarativeAllocate &x) {
503
+ checker_ (std::get<parser::Verbatim>(x.t ).source , Directive::OMPD_allocate);
504
+ return false ;
505
+ }
506
+ bool Pre (const parser::OmpDispatchDirective &x) {
507
+ checker_ (std::get<parser::Verbatim>(x.t ).source , Directive::OMPD_dispatch);
508
+ return false ;
509
+ }
510
+ bool Pre (const parser::OmpErrorDirective &x) {
511
+ checker_ (std::get<parser::Verbatim>(x.t ).source , Directive::OMPD_error);
512
+ return false ;
513
+ }
514
+ bool Pre (const parser::OmpNothingDirective &x) {
515
+ checker_ (x.source , Directive::OMPD_nothing);
516
+ return false ;
517
+ }
518
+ bool Pre (const parser::OpenMPExecutableAllocate &x) {
519
+ checker_ (std::get<parser::Verbatim>(x.t ).source , Directive::OMPD_allocate);
520
+ return false ;
521
+ }
522
+ bool Pre (const parser::OpenMPAllocatorsConstruct &x) {
523
+ checker_ (
524
+ std::get<parser::Verbatim>(x.t ).source , Directive::OMPD_allocators);
525
+ return false ;
526
+ }
527
+ bool Pre (const parser::OmpAssumeDirective &x) {
528
+ checker_ (std::get<parser::Verbatim>(x.t ).source , Directive::OMPD_assume);
529
+ return false ;
530
+ }
531
+ bool Pre (const parser::OmpEndAssumeDirective &x) {
532
+ checker_ (x.v .source , Directive::OMPD_assume);
533
+ return false ;
534
+ }
535
+ bool Pre (const parser::OmpCriticalDirective &x) {
536
+ checker_ (std::get<parser::Verbatim>(x.t ).source , Directive::OMPD_critical);
537
+ return false ;
538
+ }
539
+ bool Pre (const parser::OmpEndCriticalDirective &x) {
540
+ checker_ (std::get<parser::Verbatim>(x.t ).source , Directive::OMPD_critical);
541
+ return false ;
542
+ }
543
+ bool Pre (const parser::OmpMetadirectiveDirective &x) {
544
+ checker_ (
545
+ std::get<parser::Verbatim>(x.t ).source , Directive::OMPD_metadirective);
546
+ return false ;
547
+ }
548
+ bool Pre (const parser::OpenMPDeclarativeAssumes &x) {
549
+ checker_ (std::get<parser::Verbatim>(x.t ).source , Directive::OMPD_assumes);
550
+ return false ;
551
+ }
552
+ bool Pre (const parser::OpenMPDeclareMapperConstruct &x) {
553
+ checker_ (
554
+ std::get<parser::Verbatim>(x.t ).source , Directive::OMPD_declare_mapper);
555
+ return false ;
556
+ }
557
+ bool Pre (const parser::OpenMPDeclareReductionConstruct &x) {
558
+ checker_ (std::get<parser::Verbatim>(x.t ).source ,
559
+ Directive::OMPD_declare_reduction);
560
+ return false ;
561
+ }
562
+ bool Pre (const parser::OpenMPDeclareSimdConstruct &x) {
563
+ checker_ (
564
+ std::get<parser::Verbatim>(x.t ).source , Directive::OMPD_declare_simd);
565
+ return false ;
566
+ }
567
+ bool Pre (const parser::OpenMPDeclareTargetConstruct &x) {
568
+ checker_ (
569
+ std::get<parser::Verbatim>(x.t ).source , Directive::OMPD_declare_target);
570
+ return false ;
571
+ }
572
+ bool Pre (const parser::OmpDeclareVariantDirective &x) {
573
+ checker_ (std::get<parser::Verbatim>(x.t ).source ,
574
+ Directive::OMPD_declare_variant);
575
+ return false ;
576
+ }
577
+ bool Pre (const parser::OpenMPThreadprivate &x) {
578
+ checker_ (
579
+ std::get<parser::Verbatim>(x.t ).source , Directive::OMPD_threadprivate);
580
+ return false ;
581
+ }
582
+ bool Pre (const parser::OpenMPRequiresConstruct &x) {
583
+ checker_ (std::get<parser::Verbatim>(x.t ).source , Directive::OMPD_requires);
584
+ return false ;
585
+ }
586
+
587
+ bool Pre (const parser::OmpBlockDirective &x) {
588
+ checker_ (x.source , x.v );
589
+ return false ;
590
+ }
591
+
592
+ bool Pre (const parser::OmpLoopDirective &x) {
593
+ checker_ (x.source , x.v );
594
+ return false ;
595
+ }
596
+
597
+ bool Pre (const parser::OmpDirectiveSpecification &x) {
598
+ auto &name = std::get<parser::OmpDirectiveName>(x.t );
599
+ checker_ (name.source , name.v );
600
+ return false ;
601
+ }
602
+
603
+ private:
604
+ Checker checker_;
605
+ };
606
+
607
+ template <typename T>
608
+ DirectiveSpellingVisitor (T &&) -> DirectiveSpellingVisitor<T>;
609
+
439
610
void OmpStructureChecker::Enter (const parser::OpenMPConstruct &x) {
611
+ DirectiveSpellingVisitor visitor (
612
+ [this ](parser::CharBlock source, llvm::omp::Directive id) {
613
+ return CheckDirectiveSpelling (source, id);
614
+ });
615
+ parser::Walk (x, visitor);
616
+
440
617
// Simd Construct with Ordered Construct Nesting check
441
618
// We cannot use CurrentDirectiveIsNested() here because
442
619
// PushContextAndClauseSets() has not been called yet, it is
@@ -461,6 +638,12 @@ void OmpStructureChecker::Leave(const parser::OpenMPConstruct &) {
461
638
}
462
639
463
640
void OmpStructureChecker::Enter (const parser::OpenMPDeclarativeConstruct &x) {
641
+ DirectiveSpellingVisitor visitor (
642
+ [this ](parser::CharBlock source, llvm::omp::Directive id) {
643
+ return CheckDirectiveSpelling (source, id);
644
+ });
645
+ parser::Walk (x, visitor);
646
+
464
647
EnterDirectiveNest (DeclarativeNest);
465
648
}
466
649
0 commit comments