[OPENMP50]Do not allow multiple same context traits in the same context
selector.

According to OpenMP 5.0, 2.3.2 Context Selectors, Restrictions, each
trait-selector-name can only be specified once. Added check for this
restriction.

llvm-svn: 374093
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index e487e0a..f667b83 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -815,7 +815,7 @@
 /// 'vendor' '(' [ 'score' '(' <score _expr> ')' ':' ] <vendor> { ',' <vendor> }
 /// ')'
 static void parseImplementationSelector(
-    Parser &P, SourceLocation Loc,
+    Parser &P, SourceLocation Loc, llvm::StringMap<SourceLocation> &UsedCtx,
     llvm::function_ref<void(SourceRange,
                             const Sema::OpenMPDeclareVariantCtsSelectorData &)>
         Callback) {
@@ -832,6 +832,15 @@
   }
   SmallString<16> Buffer;
   StringRef CtxSelectorName = P.getPreprocessor().getSpelling(Tok, Buffer);
+  auto Res = UsedCtx.try_emplace(CtxSelectorName, Tok.getLocation());
+  if (!Res.second) {
+    // OpenMP 5.0, 2.3.2 Context Selectors, Restrictions.
+    // Each trait-selector-name can only be specified once.
+    P.Diag(Tok.getLocation(), diag::err_omp_declare_variant_ctx_mutiple_use)
+        << CtxSelectorName << "implementation";
+    P.Diag(Res.first->getValue(), diag::note_omp_declare_variant_ctx_used_here)
+        << CtxSelectorName;
+  }
   OMPDeclareVariantAttr::CtxSelectorType CSKind =
       OMPDeclareVariantAttr::CtxUnknown;
   (void)OMPDeclareVariantAttr::ConvertStrToCtxSelectorType(CtxSelectorName,
@@ -932,17 +941,25 @@
           OMPDeclareVariantAttr::CtxSetUnknown;
       (void)OMPDeclareVariantAttr::ConvertStrToCtxSelectorSetType(
           CtxSelectorSetName, CSSKind);
-      switch (CSSKind) {
-      case OMPDeclareVariantAttr::CtxSetImplementation:
-        parseImplementationSelector(*this, Loc, Callback);
-        break;
-      case OMPDeclareVariantAttr::CtxSetUnknown:
-        // Skip until either '}', ')', or end of directive.
-        while (!SkipUntil(tok::r_brace, tok::r_paren,
-                          tok::annot_pragma_openmp_end, StopBeforeMatch))
-          ;
-        break;
-      }
+      llvm::StringMap<SourceLocation> UsedCtx;
+      do {
+        switch (CSSKind) {
+        case OMPDeclareVariantAttr::CtxSetImplementation:
+          parseImplementationSelector(*this, Loc, UsedCtx, Callback);
+          break;
+        case OMPDeclareVariantAttr::CtxSetUnknown:
+          // Skip until either '}', ')', or end of directive.
+          while (!SkipUntil(tok::r_brace, tok::r_paren,
+                            tok::annot_pragma_openmp_end, StopBeforeMatch))
+            ;
+          break;
+        }
+        const Token PrevTok = Tok;
+        if (!TryConsumeToken(tok::comma) && Tok.isNot(tok::r_brace))
+          Diag(Tok, diag::err_omp_expected_comma_brace)
+              << (PrevTok.isAnnotation() ? "context selector trait"
+                                         : PP.getSpelling(PrevTok));
+      } while (Tok.is(tok::identifier));
       // Parse '}'.
       (void)TBr.consumeClose();
     }