Skip to content

Commit 7b42bbe

Browse files
committed
[flang][OpenMP] Issue a warning when parsing future directive spelling
OpenMP 6.0 introduced alternative spelling for some directives, with the previous spellings still allowed. Warn the user when a new spelling is encountered with OpenMP version set to an older value.
1 parent a69ffba commit 7b42bbe

File tree

5 files changed

+278
-3
lines changed

5 files changed

+278
-3
lines changed

flang/include/flang/Parser/parse-tree.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4612,7 +4612,7 @@ struct OmpDirectiveSpecification {
46124612

46134613
struct OmpMetadirectiveDirective {
46144614
TUPLE_CLASS_BOILERPLATE(OmpMetadirectiveDirective);
4615-
std::tuple<OmpClauseList> t;
4615+
std::tuple<Verbatim, OmpClauseList> t;
46164616
CharBlock source;
46174617
};
46184618

flang/lib/Parser/openmp-parsers.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1194,7 +1194,7 @@ TYPE_PARSER(sourced(construct<OpenMPUtilityConstruct>(
11941194
sourced(Parser<OmpNothingDirective>{}))))))
11951195

11961196
TYPE_PARSER(sourced(construct<OmpMetadirectiveDirective>(
1197-
"METADIRECTIVE" >> Parser<OmpClauseList>{})))
1197+
verbatim("METADIRECTIVE"_tok), Parser<OmpClauseList>{})))
11981198

11991199
// Omp directives enclosing do loop
12001200
TYPE_PARSER(sourced(construct<OmpLoopDirective>(first(
@@ -1687,7 +1687,7 @@ TYPE_PARSER(sourced(construct<OmpAssumeDirective>(
16871687
verbatim("ASSUME"_tok), Parser<OmpClauseList>{})))
16881688

16891689
TYPE_PARSER(sourced(construct<OmpEndAssumeDirective>(
1690-
verbatim(startOmpLine >> "END ASSUME"_tok))))
1690+
startOmpLine >> verbatim("END ASSUME"_tok))))
16911691

16921692
TYPE_PARSER(sourced(
16931693
construct<OpenMPAssumeConstruct>(Parser<OmpAssumeDirective>{} / endOmpLine,

flang/lib/Semantics/check-omp-structure.cpp

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,55 @@ void OmpStructureChecker::CheckVariableListItem(
259259
}
260260
}
261261

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 (auto it{n.begin()}; it != n.end();) {
274+
it = isspace(*it) ? n.erase(it) : std::next(it);
275+
}
276+
return n;
277+
};
278+
279+
std::string lowerNoWS{removeSpaces(
280+
parser::ToLowerCaseLetters({spelling.begin(), spelling.size()}))};
281+
llvm::StringRef ref(lowerNoWS);
282+
if (ref.starts_with("end")) {
283+
ref = ref.drop_front(3);
284+
}
285+
286+
unsigned version{context_.langOptions().OpenMPVersion};
287+
288+
// For every "future" version v, check if the check if the corresponding
289+
// spelling of id was introduced later than the current version. If so,
290+
// and if that spelling matches the source spelling, issue a warning.
291+
for (unsigned v : llvm::omp::getOpenMPVersions()) {
292+
if (v <= version) {
293+
continue;
294+
}
295+
llvm::StringRef name{llvm::omp::getOpenMPDirectiveName(id, v)};
296+
auto [kind, versions]{llvm::omp::getOpenMPDirectiveKindAndVersions(name)};
297+
assert(kind == id && "Directive kind mismatch");
298+
299+
if (static_cast<int>(version) >= versions.Min) {
300+
continue;
301+
}
302+
if (ref == removeSpaces(name)) {
303+
context_.Say(spelling,
304+
"Directive spelling '%s' is introduced in a later OpenMP version, %s"_warn_en_US,
305+
parser::ToUpperCaseLetters(ref), TryVersion(versions.Min));
306+
break;
307+
}
308+
}
309+
}
310+
262311
void OmpStructureChecker::CheckMultipleOccurrence(
263312
semantics::UnorderedSymbolSet &listVars,
264313
const std::list<parser::Name> &nameList, const parser::CharBlock &item,
@@ -436,7 +485,133 @@ void OmpStructureChecker::Leave(const parser::OmpDirectiveSpecification &) {
436485
}
437486
}
438487

488+
template <typename Checker> struct DirectiveSpellingVisitor {
489+
using Directive = llvm::omp::Directive;
490+
491+
DirectiveSpellingVisitor(Checker &&checker) : checker_(std::move(checker)) {}
492+
493+
template <typename T> bool Pre(const T &) { return true; }
494+
template <typename T> void Post(const T &) {}
495+
496+
bool Pre(const parser::OmpSectionsDirective &x) {
497+
checker_(x.source, x.v);
498+
return false;
499+
}
500+
bool Pre(const parser::OpenMPDeclarativeAllocate &x) {
501+
checker_(std::get<parser::Verbatim>(x.t).source, Directive::OMPD_allocate);
502+
return false;
503+
}
504+
bool Pre(const parser::OmpDispatchDirective &x) {
505+
checker_(std::get<parser::Verbatim>(x.t).source, Directive::OMPD_dispatch);
506+
return false;
507+
}
508+
bool Pre(const parser::OmpErrorDirective &x) {
509+
checker_(std::get<parser::Verbatim>(x.t).source, Directive::OMPD_error);
510+
return false;
511+
}
512+
bool Pre(const parser::OmpNothingDirective &x) {
513+
checker_(x.source, Directive::OMPD_nothing);
514+
return false;
515+
}
516+
bool Pre(const parser::OpenMPExecutableAllocate &x) {
517+
checker_(std::get<parser::Verbatim>(x.t).source, Directive::OMPD_allocate);
518+
return false;
519+
}
520+
bool Pre(const parser::OpenMPAllocatorsConstruct &x) {
521+
checker_(
522+
std::get<parser::Verbatim>(x.t).source, Directive::OMPD_allocators);
523+
return false;
524+
}
525+
bool Pre(const parser::OmpAssumeDirective &x) {
526+
checker_(std::get<parser::Verbatim>(x.t).source, Directive::OMPD_assume);
527+
return false;
528+
}
529+
bool Pre(const parser::OmpEndAssumeDirective &x) {
530+
checker_(x.v.source, Directive::OMPD_assume);
531+
return false;
532+
}
533+
bool Pre(const parser::OmpCriticalDirective &x) {
534+
checker_(std::get<parser::Verbatim>(x.t).source, Directive::OMPD_critical);
535+
return false;
536+
}
537+
bool Pre(const parser::OmpEndCriticalDirective &x) {
538+
checker_(std::get<parser::Verbatim>(x.t).source, Directive::OMPD_critical);
539+
return false;
540+
}
541+
bool Pre(const parser::OmpMetadirectiveDirective &x) {
542+
checker_(
543+
std::get<parser::Verbatim>(x.t).source, Directive::OMPD_metadirective);
544+
return false;
545+
}
546+
bool Pre(const parser::OpenMPDeclarativeAssumes &x) {
547+
checker_(std::get<parser::Verbatim>(x.t).source, Directive::OMPD_assumes);
548+
return false;
549+
}
550+
bool Pre(const parser::OpenMPDeclareMapperConstruct &x) {
551+
checker_(
552+
std::get<parser::Verbatim>(x.t).source, Directive::OMPD_declare_mapper);
553+
return false;
554+
}
555+
bool Pre(const parser::OpenMPDeclareReductionConstruct &x) {
556+
checker_(std::get<parser::Verbatim>(x.t).source,
557+
Directive::OMPD_declare_reduction);
558+
return false;
559+
}
560+
bool Pre(const parser::OpenMPDeclareSimdConstruct &x) {
561+
checker_(
562+
std::get<parser::Verbatim>(x.t).source, Directive::OMPD_declare_simd);
563+
return false;
564+
}
565+
bool Pre(const parser::OpenMPDeclareTargetConstruct &x) {
566+
checker_(
567+
std::get<parser::Verbatim>(x.t).source, Directive::OMPD_declare_target);
568+
return false;
569+
}
570+
bool Pre(const parser::OmpDeclareVariantDirective &x) {
571+
checker_(std::get<parser::Verbatim>(x.t).source,
572+
Directive::OMPD_declare_variant);
573+
return false;
574+
}
575+
bool Pre(const parser::OpenMPThreadprivate &x) {
576+
checker_(
577+
std::get<parser::Verbatim>(x.t).source, Directive::OMPD_threadprivate);
578+
return false;
579+
}
580+
bool Pre(const parser::OpenMPRequiresConstruct &x) {
581+
checker_(std::get<parser::Verbatim>(x.t).source, Directive::OMPD_requires);
582+
return false;
583+
}
584+
585+
bool Pre(const parser::OmpBlockDirective &x) {
586+
checker_(x.source, x.v);
587+
return false;
588+
}
589+
590+
bool Pre(const parser::OmpLoopDirective &x) {
591+
checker_(x.source, x.v);
592+
return false;
593+
}
594+
595+
bool Pre(const parser::OmpDirectiveSpecification &x) {
596+
auto &name = std::get<parser::OmpDirectiveName>(x.t);
597+
checker_(name.source, name.v);
598+
return false;
599+
}
600+
601+
private:
602+
Checker checker_;
603+
};
604+
605+
template <typename T>
606+
DirectiveSpellingVisitor(T &&) -> DirectiveSpellingVisitor<T>;
607+
439608
void OmpStructureChecker::Enter(const parser::OpenMPConstruct &x) {
609+
DirectiveSpellingVisitor visitor(
610+
[this](parser::CharBlock source, llvm::omp::Directive id) {
611+
return CheckDirectiveSpelling(source, id);
612+
});
613+
parser::Walk(x, visitor);
614+
440615
// Simd Construct with Ordered Construct Nesting check
441616
// We cannot use CurrentDirectiveIsNested() here because
442617
// PushContextAndClauseSets() has not been called yet, it is
@@ -461,6 +636,12 @@ void OmpStructureChecker::Leave(const parser::OpenMPConstruct &) {
461636
}
462637

463638
void OmpStructureChecker::Enter(const parser::OpenMPDeclarativeConstruct &x) {
639+
DirectiveSpellingVisitor visitor(
640+
[this](parser::CharBlock source, llvm::omp::Directive id) {
641+
return CheckDirectiveSpelling(source, id);
642+
});
643+
parser::Walk(x, visitor);
644+
464645
EnterDirectiveNest(DeclarativeNest);
465646
}
466647

flang/lib/Semantics/check-omp-structure.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,8 @@ class OmpStructureChecker
163163
private:
164164
bool CheckAllowedClause(llvmOmpClause clause);
165165
void CheckVariableListItem(const SymbolSourceMap &symbols);
166+
void CheckDirectiveSpelling(
167+
parser::CharBlock spelling, llvm::omp::Directive id);
166168
void CheckMultipleOccurrence(semantics::UnorderedSymbolSet &listVars,
167169
const std::list<parser::Name> &nameList, const parser::CharBlock &item,
168170
const std::string &clauseName);
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
!RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=52 -Werror
2+
3+
! The directives to check:
4+
! cancellation_point
5+
! declare_mapper
6+
! declare_reduction
7+
! declare_simd
8+
! declare_target
9+
! declare_variant
10+
! target_data
11+
! target_enter_data
12+
! target_exit_data
13+
! target_update
14+
15+
subroutine f00
16+
implicit none
17+
integer :: i
18+
19+
!$omp parallel
20+
do i = 1, 10
21+
!WARNING: Directive spelling 'CANCELLATION_POINT' is introduced in a later OpenMP version, try -fopenmp-version=60
22+
!$omp cancellation_point parallel
23+
enddo
24+
!$omp end parallel
25+
end
26+
27+
subroutine f01
28+
type :: t
29+
integer :: x
30+
end type
31+
!WARNING: Directive spelling 'DECLARE_MAPPER' is introduced in a later OpenMP version, try -fopenmp-version=60
32+
!$omp declare_mapper(t :: v) map(v%x)
33+
end
34+
35+
subroutine f02
36+
type :: t
37+
integer :: x
38+
end type
39+
!WARNING: Directive spelling 'DECLARE_REDUCTION' is introduced in a later OpenMP version, try -fopenmp-version=60
40+
!$omp declare_reduction(+ : t : omp_out%x = omp_out%x + omp_in%x)
41+
end
42+
43+
subroutine f03
44+
!WARNING: Directive spelling 'DECLARE_SIMD' is introduced in a later OpenMP version, try -fopenmp-version=60
45+
!$omp declare_simd
46+
end
47+
48+
subroutine f04
49+
!WARNING: Directive spelling 'DECLARE_TARGET' is introduced in a later OpenMP version, try -fopenmp-version=60
50+
!$omp declare_target
51+
end
52+
53+
subroutine f05
54+
implicit none
55+
interface
56+
subroutine g05
57+
end
58+
end interface
59+
!WARNING: Directive spelling 'DECLARE_VARIANT' is introduced in a later OpenMP version, try -fopenmp-version=60
60+
!$omp declare_variant(g05) match(user={condition(.true.)})
61+
end
62+
63+
subroutine f06
64+
implicit none
65+
integer :: i
66+
!WARNING: Directive spelling 'TARGET_DATA' is introduced in a later OpenMP version, try -fopenmp-version=60
67+
!$omp target_data map(tofrom: i)
68+
i = 0
69+
!WARNING: Directive spelling 'TARGET_DATA' is introduced in a later OpenMP version, try -fopenmp-version=60
70+
!$omp end target_data
71+
end
72+
73+
subroutine f07
74+
implicit none
75+
integer :: i
76+
!WARNING: Directive spelling 'TARGET_ENTER_DATA' is introduced in a later OpenMP version, try -fopenmp-version=60
77+
!$omp target_enter_data map(to: i)
78+
end
79+
80+
subroutine f08
81+
implicit none
82+
integer :: i
83+
!WARNING: Directive spelling 'TARGET_EXIT_DATA' is introduced in a later OpenMP version, try -fopenmp-version=60
84+
!$omp target_exit_data map(from: i)
85+
end
86+
87+
subroutine f09
88+
implicit none
89+
integer :: i
90+
!WARNING: Directive spelling 'TARGET_UPDATE' is introduced in a later OpenMP version, try -fopenmp-version=60
91+
!$omp target_update to(i)
92+
end

0 commit comments

Comments
 (0)