|
10 | 10 |
|
11 | 11 | #include "check-directive-structure.h" |
12 | 12 | #include "definable.h" |
13 | | -#include "openmp-utils.h" |
14 | 13 | #include "resolve-names-utils.h" |
15 | 14 |
|
16 | 15 | #include "flang/Common/idioms.h" |
|
27 | 26 | #include "flang/Semantics/expression.h" |
28 | 27 | #include "flang/Semantics/openmp-directive-sets.h" |
29 | 28 | #include "flang/Semantics/openmp-modifiers.h" |
| 29 | +#include "flang/Semantics/openmp-utils.h" |
30 | 30 | #include "flang/Semantics/scope.h" |
31 | 31 | #include "flang/Semantics/semantics.h" |
32 | 32 | #include "flang/Semantics/symbol.h" |
@@ -537,14 +537,6 @@ template <typename Checker> struct DirectiveSpellingVisitor { |
537 | 537 | checker_(x.v.source, Directive::OMPD_assume); |
538 | 538 | return false; |
539 | 539 | } |
540 | | - bool Pre(const parser::OmpCriticalDirective &x) { |
541 | | - checker_(std::get<parser::Verbatim>(x.t).source, Directive::OMPD_critical); |
542 | | - return false; |
543 | | - } |
544 | | - bool Pre(const parser::OmpEndCriticalDirective &x) { |
545 | | - checker_(std::get<parser::Verbatim>(x.t).source, Directive::OMPD_critical); |
546 | | - return false; |
547 | | - } |
548 | 540 | bool Pre(const parser::OmpMetadirectiveDirective &x) { |
549 | 541 | checker_( |
550 | 542 | std::get<parser::Verbatim>(x.t).source, Directive::OMPD_metadirective); |
@@ -2034,41 +2026,87 @@ void OmpStructureChecker::Leave(const parser::OpenMPCancelConstruct &) { |
2034 | 2026 | } |
2035 | 2027 |
|
2036 | 2028 | void OmpStructureChecker::Enter(const parser::OpenMPCriticalConstruct &x) { |
2037 | | - const auto &dir{std::get<parser::OmpCriticalDirective>(x.t)}; |
2038 | | - const auto &dirSource{std::get<parser::Verbatim>(dir.t).source}; |
2039 | | - const auto &endDir{std::get<parser::OmpEndCriticalDirective>(x.t)}; |
2040 | | - PushContextAndClauseSets(dirSource, llvm::omp::Directive::OMPD_critical); |
| 2029 | + const parser::OmpBeginDirective &beginSpec{x.BeginDir()}; |
| 2030 | + const std::optional<parser::OmpEndDirective> &endSpec{x.EndDir()}; |
| 2031 | + PushContextAndClauseSets(beginSpec.DirName().source, beginSpec.DirName().v); |
| 2032 | + |
2041 | 2033 | const auto &block{std::get<parser::Block>(x.t)}; |
2042 | | - CheckNoBranching(block, llvm::omp::Directive::OMPD_critical, dir.source); |
2043 | | - const auto &dirName{std::get<std::optional<parser::Name>>(dir.t)}; |
2044 | | - const auto &endDirName{std::get<std::optional<parser::Name>>(endDir.t)}; |
2045 | | - const auto &ompClause{std::get<parser::OmpClauseList>(dir.t)}; |
2046 | | - if (dirName && endDirName && |
2047 | | - dirName->ToString().compare(endDirName->ToString())) { |
2048 | | - context_ |
2049 | | - .Say(endDirName->source, |
2050 | | - parser::MessageFormattedText{ |
2051 | | - "CRITICAL directive names do not match"_err_en_US}) |
2052 | | - .Attach(dirName->source, "should be "_en_US); |
2053 | | - } else if (dirName && !endDirName) { |
2054 | | - context_ |
2055 | | - .Say(dirName->source, |
2056 | | - parser::MessageFormattedText{ |
2057 | | - "CRITICAL directive names do not match"_err_en_US}) |
2058 | | - .Attach(dirName->source, "should be NULL"_en_US); |
2059 | | - } else if (!dirName && endDirName) { |
2060 | | - context_ |
2061 | | - .Say(endDirName->source, |
2062 | | - parser::MessageFormattedText{ |
2063 | | - "CRITICAL directive names do not match"_err_en_US}) |
2064 | | - .Attach(endDirName->source, "should be NULL"_en_US); |
2065 | | - } |
2066 | | - if (!dirName && !ompClause.source.empty() && |
2067 | | - ompClause.source.NULTerminatedToString() != "hint(omp_sync_hint_none)") { |
2068 | | - context_.Say(dir.source, |
2069 | | - parser::MessageFormattedText{ |
2070 | | - "Hint clause other than omp_sync_hint_none cannot be specified for " |
2071 | | - "an unnamed CRITICAL directive"_err_en_US}); |
| 2034 | + CheckNoBranching( |
| 2035 | + block, llvm::omp::Directive::OMPD_critical, beginSpec.DirName().source); |
| 2036 | + |
| 2037 | + auto getNameFromArg{[](const parser::OmpArgument &arg) { |
| 2038 | + if (auto *object{parser::Unwrap<parser::OmpObject>(arg.u)}) { |
| 2039 | + if (auto *designator{omp::GetDesignatorFromObj(*object)}) { |
| 2040 | + return getDesignatorNameIfDataRef(*designator); |
| 2041 | + } |
| 2042 | + } |
| 2043 | + return static_cast<const parser::Name *>(nullptr); |
| 2044 | + }}; |
| 2045 | + |
| 2046 | + auto checkArgumentList{[&](const parser::OmpArgumentList &args) { |
| 2047 | + if (args.v.size() > 1) { |
| 2048 | + context_.Say(args.source, |
| 2049 | + "Only a single argument is allowed in CRITICAL directive"_err_en_US); |
| 2050 | + } else if (!args.v.empty()) { |
| 2051 | + if (!getNameFromArg(args.v.front())) { |
| 2052 | + context_.Say(args.v.front().source, |
| 2053 | + "CRITICAL argument should be a name"_err_en_US); |
| 2054 | + } |
| 2055 | + } |
| 2056 | + }}; |
| 2057 | + |
| 2058 | + const parser::Name *beginName{nullptr}; |
| 2059 | + const parser::Name *endName{nullptr}; |
| 2060 | + |
| 2061 | + auto &beginArgs{beginSpec.Arguments()}; |
| 2062 | + checkArgumentList(beginArgs); |
| 2063 | + |
| 2064 | + if (!beginArgs.v.empty()) { |
| 2065 | + beginName = getNameFromArg(beginArgs.v.front()); |
| 2066 | + } |
| 2067 | + |
| 2068 | + if (endSpec) { |
| 2069 | + auto &endArgs{endSpec->Arguments()}; |
| 2070 | + checkArgumentList(endArgs); |
| 2071 | + |
| 2072 | + if (beginArgs.v.empty() != endArgs.v.empty()) { |
| 2073 | + parser::CharBlock source{ |
| 2074 | + beginArgs.v.empty() ? endArgs.source : beginArgs.source}; |
| 2075 | + context_.Say(source, |
| 2076 | + "Either both CRITICAL and END CRITICAL should have an argument, or none of them should"_err_en_US); |
| 2077 | + } else if (!beginArgs.v.empty()) { |
| 2078 | + endName = getNameFromArg(endArgs.v.front()); |
| 2079 | + if (beginName && endName) { |
| 2080 | + if (beginName->ToString() != endName->ToString()) { |
| 2081 | + context_.Say(endName->source, |
| 2082 | + "The names on CRITICAL and END CRITICAL must match"_err_en_US); |
| 2083 | + } |
| 2084 | + } |
| 2085 | + } |
| 2086 | + } |
| 2087 | + |
| 2088 | + for (auto &clause : beginSpec.Clauses().v) { |
| 2089 | + auto *hint{std::get_if<parser::OmpClause::Hint>(&clause.u)}; |
| 2090 | + if (!hint) { |
| 2091 | + continue; |
| 2092 | + } |
| 2093 | + const int64_t OmpSyncHintNone = 0; // omp_sync_hint_none |
| 2094 | + std::optional<int64_t> hintValue{GetIntValue(hint->v.v)}; |
| 2095 | + if (hintValue && *hintValue != OmpSyncHintNone) { |
| 2096 | + // Emit a diagnostic if the name is missing, and point to the directive |
| 2097 | + // with a missing name. |
| 2098 | + parser::CharBlock source; |
| 2099 | + if (!beginName) { |
| 2100 | + source = beginSpec.DirName().source; |
| 2101 | + } else if (endSpec && !endName) { |
| 2102 | + source = endSpec->DirName().source; |
| 2103 | + } |
| 2104 | + |
| 2105 | + if (!source.empty()) { |
| 2106 | + context_.Say(source, |
| 2107 | + "When HINT other than 'omp_sync_hint_none' is present, CRITICAL directive should have a name"_err_en_US); |
| 2108 | + } |
| 2109 | + } |
2072 | 2110 | } |
2073 | 2111 | } |
2074 | 2112 |
|
|
0 commit comments