ABataev updated this revision to Diff 233375.
ABataev added a comment.

Fixed formatting


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D70973/new/

https://reviews.llvm.org/D70973

Files:
  clang/include/clang/AST/Decl.h
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/DiagnosticParseKinds.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Basic/OpenMPKinds.h
  clang/include/clang/Sema/Sema.h
  clang/lib/AST/Decl.cpp
  clang/lib/Basic/OpenMPKinds.cpp
  clang/lib/CodeGen/CGOpenMPRuntime.cpp
  clang/lib/Parse/ParseOpenMP.cpp
  clang/lib/Sema/SemaOpenMP.cpp
  clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
  clang/test/OpenMP/declare_variant_ast_print.c
  clang/test/OpenMP/declare_variant_ast_print.cpp
  clang/test/OpenMP/declare_variant_device_kind_codegen.cpp
  clang/test/OpenMP/declare_variant_implementation_vendor_codegen.cpp
  clang/test/OpenMP/declare_variant_messages.c
  clang/test/OpenMP/declare_variant_messages.cpp
  clang/test/OpenMP/declare_variant_mixed_codegen.cpp

Index: clang/test/OpenMP/declare_variant_mixed_codegen.cpp
===================================================================
--- clang/test/OpenMP/declare_variant_mixed_codegen.cpp
+++ clang/test/OpenMP/declare_variant_mixed_codegen.cpp
@@ -1,7 +1,8 @@
 // RUN: %clang_cc1 -verify -fopenmp -x c++ -triple x86_64-unknown-linux -emit-llvm %s -fexceptions -fcxx-exceptions -o - -fsanitize-address-use-after-scope | FileCheck %s
-// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple x86_64-unknown-linux -fexceptions -fcxx-exceptions -emit-pch -o %t -fopenmp-version=50 %s
-// RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-unknown-linux -fexceptions -fcxx-exceptions -std=c++11 -include-pch %t -verify %s -emit-llvm -o - -fopenmp-version=50 | FileCheck %s
-// expected-no-diagnostics
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -triple x86_64-unknown-linux -fexceptions -fcxx-exceptions -emit-pch -o %t -fopenmp-version=50 %s
+// RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-unknown-linux -fexceptions -fcxx-exceptions -std=c++11 -include-pch %t %s -emit-llvm -o - -fopenmp-version=50 | FileCheck %s
+
+// expected-warning@141 {{unknown 'ccpu' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga', set ignored}}
 
 // CHECK-NOT: ret i32 {{1|4|81|84}}
 // CHECK-DAG: @_Z3barv = {{.*}}alias i32 (), i32 ()* @_Z3foov
@@ -39,17 +40,17 @@
 int bar() { return 1; }
 
 int bazzz();
-#pragma omp declare variant(bazzz) match(implementation = {vendor(llvm)}, device={kind(host)})
+#pragma omp declare variant(bazzz) match(implementation = {vendor(llvm)}, device={kind("host")})
 int baz() { return 1; }
 
 int test();
-#pragma omp declare variant(test) match(implementation = {vendor(llvm)}, device={kind(cpu)})
+#pragma omp declare variant(test) match(implementation = {vendor("llvm")}, device={kind(cpu)})
 int call() { return 1; }
 
 static int stat_unused_no_emit() { return 1; }
 static int stat_unused_();
 #pragma omp declare variant(stat_unused_) match(implementation = {vendor(llvm)}, device={kind(cpu)})
-#pragma omp declare variant(stat_unused_no_emit) match(implementation = {vendor(xxx)}, device={kind(gpu)})
+#pragma omp declare variant(stat_unused_) match(implementation = {vendor("llvm")}, device={kind("cpu")})
 static int stat_unused() { return 1; }
 
 static int stat_used_();
@@ -137,6 +138,9 @@
 #pragma omp declare variant(fn_variant2) match(implementation = {vendor(llvm)}, device={kind(fpga)})
 int fn2() { return 87; }
 
+#pragma omp declare variant(fn_variant2) match(device = {kind("ccpu")})
+int wrong_kind() { return 87; }
+
 #pragma omp declare variant(stat_unused_no_emit) match(implementation = {vendor(xxx)}, device={kind(gpu)})
 template <typename T>
 static T stat_unused_T() { return 88; }
Index: clang/test/OpenMP/declare_variant_messages.cpp
===================================================================
--- clang/test/OpenMP/declare_variant_messages.cpp
+++ clang/test/OpenMP/declare_variant_messages.cpp
@@ -30,25 +30,25 @@
 #pragma omp declare variant(foofoo <int>) match(xxx = {vvv} xxx) // expected-error {{expected ','}} expected-error {{expected '=' after 'xxx' context selector set name on 'omp declare variant' directive}} expected-error {{context selector set 'xxx' is used already in the same 'omp declare variant' directive}} expected-note {{previously context selector set 'xxx' used here}}
 #pragma omp declare variant(foofoo <int>) match(xxx = {vvv}) xxx // expected-warning {{extra tokens at the end of '#pragma omp declare variant' are ignored}}
 #pragma omp declare variant(foofoo <int>) match(implementation={xxx}) // expected-warning {{unknown context selector in 'implementation' context selector set of 'omp declare variant' directive, ignored}}
-#pragma omp declare variant(foofoo <int>) match(implementation={vendor}) // expected-error {{expected '(' after 'vendor'}} expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-error {{expected ')' or ',' after 'vendor name'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
-#pragma omp declare variant(foofoo <int>) match(implementation={vendor(}) // expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-error {{expected ')' or ',' after 'vendor name'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
-#pragma omp declare variant(foofoo <int>) match(implementation={vendor()}) // expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}}
+#pragma omp declare variant(foofoo <int>) match(implementation={vendor}) // expected-error {{expected '(' after 'vendor'}} expected-error {{expected ')' or ',' after 'vendor name'}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{expected expression}} expected-note {{expected context trait string expression or identifier in 'vendor' context selector}}
+#pragma omp declare variant(foofoo <int>) match(implementation={vendor(}) // expected-error {{expected ')' or ',' after 'vendor name'}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{expected expression}} expected-note {{expected context trait string expression or identifier in 'vendor' context selector}}
+#pragma omp declare variant(foofoo <int>) match(implementation={vendor()}) // expected-error {{expected expression}} expected-note {{expected context trait string expression or identifier in 'vendor' context selector}}
 #pragma omp declare variant(foofoo <int>) match(implementation={vendor(score ibm)}) // expected-error {{expected '(' after 'score'}} expected-warning {{missing ':' after context selector score clause - ignoring}}
-#pragma omp declare variant(foofoo <int>) match(implementation={vendor(score( ibm)}) // expected-error {{expected ')' or ',' after 'vendor name'}} expected-error {{expected ')'}} expected-error {{use of undeclared identifier 'ibm'}} expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-warning {{missing ':' after context selector score clause - ignoring}} expected-note {{to match this '('}}
-#pragma omp declare variant(foofoo <int>) match(implementation={vendor(score(2 ibm)}) // expected-error {{expected ')' or ',' after 'vendor name'}} expected-error 2 {{expected ')'}} expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-warning {{missing ':' after context selector score clause - ignoring}} expected-note 2 {{to match this '('}}
+#pragma omp declare variant(foofoo <int>) match(implementation={vendor(score( ibm)}) // expected-error {{expected ')' or ',' after 'vendor name'}} expected-error {{expected ')'}} expected-error {{use of undeclared identifier 'ibm'}} expected-warning {{missing ':' after context selector score clause - ignoring}} expected-note {{to match this '('}} expected-error {{expected expression}} expected-note {{expected context trait string expression or identifier in 'vendor' context selector}}
+#pragma omp declare variant(foofoo <int>) match(implementation={vendor(score(2 ibm)}) // expected-error {{expected ')' or ',' after 'vendor name'}} expected-error 2 {{expected ')'}} expected-warning {{missing ':' after context selector score clause - ignoring}} expected-note 2 {{to match this '('}} expected-error {{expected expression}} expected-note {{expected context trait string expression or identifier in 'vendor' context selector}}
 #pragma omp declare variant(foofoo <int>) match(implementation={vendor(score(foofoo <int>()) ibm)}) // expected-warning {{missing ':' after context selector score clause - ignoring}} expected-error {{expression is not an integral constant expression}} expected-note {{non-constexpr function 'foofoo<int>' cannot be used in a constant expression}}
 #pragma omp declare variant(foofoo <int>) match(implementation={vendor(score(5): ibm), vendor(llvm)}) // expected-error {{context trait selector 'vendor' is used already in the same 'implementation' context selector set of 'omp declare variant' directive}} expected-note {{previously context trait selector 'vendor' used here}}
 #pragma omp declare variant(foofoo <int>) match(implementation={vendor(score(5): ibm), kind(cpu)}) // expected-warning {{unknown context selector in 'implementation' context selector set of 'omp declare variant' directive, ignored}}
 #pragma omp declare variant(foofoo <int>) match(device={xxx}) // expected-warning {{unknown context selector in 'device' context selector set of 'omp declare variant' directive, ignored}}
-#pragma omp declare variant(foofoo <int>) match(device={kind}) // expected-error {{expected '(' after 'kind'}} expected-error {{expected 'host', 'nohost', 'cpu', 'gpu', or 'fpga' in 'kind' context selector of 'device' selector set of 'omp declare variant' directive}} expected-error {{expected ')'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
-#pragma omp declare variant(foofoo <int>) match(device={kind(}) // expected-error {{expected 'host', 'nohost', 'cpu', 'gpu', or 'fpga' in 'kind' context selector of 'device' selector set of 'omp declare variant' directive}} expected-error 2 {{expected ')'}} expected-note {{to match this '('}}
-#pragma omp declare variant(foofoo <int>) match(device={kind()}) // expected-error {{expected 'host', 'nohost', 'cpu', 'gpu', or 'fpga' in 'kind' context selector of 'device' selector set of 'omp declare variant' directive}}
-#pragma omp declare variant(foofoo <int>) match(device={kind(score cpu)}) // expected-error {{expected ')' or ',' after 'score'}} expected-error {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}}
-#pragma omp declare variant(foofoo <int>) match(device={kind(score( ibm)}) // expected-error 2 {{expected ')'}} expected-note {{to match this '('}} expected-error {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}}
-#pragma omp declare variant(foofoo <int>) match(device={kind(score(2 gpu)}) // expected-error 2 {{expected ')'}} expected-note {{to match this '('}} expected-error {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}}
-#pragma omp declare variant(foofoo <int>) match(device={kind(score(foofoo <int>()) ibm)}) // expected-error {{expected ')' or ',' after 'score'}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}}
-#pragma omp declare variant(foofoo <int>) match(device={kind(score(5): host), kind(llvm)}) // expected-error {{context trait selector 'kind' is used already in the same 'device' context selector set of 'omp declare variant' directive}} expected-note {{previously context trait selector 'kind' used here}} expected-error {{expected ')' or ',' after 'score'}} expected-note {{to match this '('}} expected-error {{expected ')'}} expected-error {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}} expected-error {{unknown 'llvm' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}}
-#pragma omp declare variant(foofoo <int>) match(device={kind(score(5): nohost), vendor(llvm)}) // expected-warning {{unknown context selector in 'device' context selector set of 'omp declare variant' directive, ignored}} expected-error {{expected ')' or ',' after 'score'}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}}
+#pragma omp declare variant(foofoo <int>) match(device={kind}) // expected-error {{expected '(' after 'kind'}} expected-error {{expected ')'}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{expected expression}} expected-note {{expected context trait string expression or identifier in 'kind' context selector}}
+#pragma omp declare variant(foofoo <int>) match(device={kind(}) // expected-error 2 {{expected ')'}} expected-note {{to match this '('}} expected-error {{expected expression}} expected-note {{expected context trait string expression or identifier in 'kind' context selector}}
+#pragma omp declare variant(foofoo <int>) match(device={kind()}) // expected-error {{expected expression}} expected-note {{expected context trait string expression or identifier in 'kind' context selector}}
+#pragma omp declare variant(foofoo <int>) match(device={kind(score cpu)}) // expected-error {{expected ')' or ',' after 'kind of device'}} expected-warning {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga', set ignored}}
+#pragma omp declare variant(foofoo <int>) match(device={kind(score( ibm)}) // expected-error 2 {{expected ')' or ',' after 'kind of device'}} expected-error 2 {{expected ')'}} expected-note {{to match this '('}} expected-error {{expected expression}} expected-error {{use of undeclared identifier 'ibm'}} expected-note 2 {{expected context trait string expression or identifier in 'kind' context selector}} expected-warning {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga', set ignored}}
+#pragma omp declare variant(foofoo <int>) match(device={kind(score(2 gpu)}) // expected-error 2 {{expected ')' or ',' after 'kind of device'}} expected-error 3 {{expected ')'}} expected-note 2 {{to match this '('}} expected-error {{expected expression}} expected-error {{trait expression must have a string type, not 'int'}} expected-error {{trait expression must be a constant string expression}} expected-note {{expected context trait string expression or identifier in 'kind' context selector}} expected-warning {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga', set ignored}}
+#pragma omp declare variant(foofoo <int>) match(device={kind(score(foofoo <int>()) ibm)}) // expected-error 2 {{expected ')' or ',' after 'kind of device'}} expected-error {{trait expression must have a string type, not 'int'}} expected-error {{trait expression must be a constant string expression}} expected-warning {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga', set ignored}} expected-warning {{unknown 'ibm' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga', set ignored}}
+#pragma omp declare variant(foofoo <int>) match(device={kind(score(5): host), kind(llvm)}) // expected-error {{context trait selector 'kind' is used already in the same 'device' context selector set of 'omp declare variant' directive}} expected-note {{previously context trait selector 'kind' used here}} expected-note {{to match this '('}} expected-error 2 {{expected ')' or ',' after 'kind of device'}} expected-error 2 {{expected ')'}} expected-error {{expected expression}} expected-error {{trait expression must have a string type, not 'int'}} expected-error {{trait expression must be a constant string expression}} expected-note {{expected context trait string expression or identifier in 'kind' context selector}} expected-warning {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga', set ignored}} expected-warning {{unknown 'llvm' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga', set ignored}}
+#pragma omp declare variant(foofoo <int>) match(device={kind(score(5): nohost), vendor(llvm)}) // expected-error 2 {{expected ')' or ',' after 'kind of device'}} expected-warning {{unknown context selector in 'device' context selector set of 'omp declare variant' directive, ignored}} expected-error 2 {{expected ')'}} expected-note {{to match this '('}} expected-error {{expected expression}} expected-error {{trait expression must have a string type, not 'int'}} expected-error {{trait expression must be a constant string expression}} expected-note {{expected context trait string expression or identifier in 'kind' context selector}} expected-warning {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga', set ignored}}
 int bar();
 
 #pragma omp declare variant                            // expected-error {{expected '(' after 'declare variant'}}
@@ -74,21 +74,22 @@
 #pragma omp declare variant(foofoo <T>) match(xxx = {vvv} xxx) // expected-error {{expected ','}} expected-error {{expected '=' after 'xxx' context selector set name on 'omp declare variant' directive}} expected-error {{context selector set 'xxx' is used already in the same 'omp declare variant' directive}} expected-note {{previously context selector set 'xxx' used here}}
 #pragma omp declare variant(foofoo <T>) match(xxx = {vvv}) xxx // expected-warning {{extra tokens at the end of '#pragma omp declare variant' are ignored}}
 #pragma omp declare variant(foofoo <int>) match(implementation={vendor(score ibm)}) // expected-error {{expected '(' after 'score'}} expected-warning {{missing ':' after context selector score clause - ignoring}}
-#pragma omp declare variant(foofoo <int>) match(implementation={vendor(score( ibm)}) // expected-error {{expected ')' or ',' after 'vendor name'}} expected-error {{expected ')'}} expected-error {{use of undeclared identifier 'ibm'}} expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-warning {{missing ':' after context selector score clause - ignoring}} expected-note {{to match this '('}}
-#pragma omp declare variant(foofoo <int>) match(implementation={vendor(score(C ibm)}) // expected-error {{expected ')' or ',' after 'vendor name'}} expected-error 2 {{expected ')'}} expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-warning {{missing ':' after context selector score clause - ignoring}} expected-note 2 {{to match this '('}}
+#pragma omp declare variant(foofoo <int>) match(implementation={vendor(score( ibm)}) // expected-error {{expected ')' or ',' after 'vendor name'}} expected-error {{expected ')'}} expected-error {{use of undeclared identifier 'ibm'}} expected-warning {{missing ':' after context selector score clause - ignoring}} expected-note {{to match this '('}} expected-error {{expected expression}} expected-note {{expected context trait string expression or identifier in 'vendor' context selector}}
+#pragma omp declare variant(foofoo <int>) match(implementation={vendor(score(C ibm)}) // expected-error {{expected ')' or ',' after 'vendor name'}} expected-error 2 {{expected ')'}} expected-warning {{missing ':' after context selector score clause - ignoring}} expected-note 2 {{to match this '('}} expected-error {{expected expression}} expected-note {{expected context trait string expression or identifier in 'vendor' context selector}}
 #pragma omp declare variant(foofoo <int>) match(implementation={vendor(score(foofoo <int>()) ibm)}) // expected-warning {{missing ':' after context selector score clause - ignoring}} expected-error {{expression is not an integral constant expression}} expected-note {{non-constexpr function 'foofoo<int>' cannot be used in a constant expression}}
 #pragma omp declare variant(foofoo <int>) match(implementation={vendor(score(C+5): ibm), vendor(llvm)}) // expected-error {{context trait selector 'vendor' is used already in the same 'implementation' context selector set of 'omp declare variant' directive}} expected-note {{previously context trait selector 'vendor' used here}}
 #pragma omp declare variant(foofoo <int>) match(implementation={vendor(score(5): ibm), kind(cpu)}) // expected-warning {{unknown context selector in 'implementation' context selector set of 'omp declare variant' directive, ignored}}
 #pragma omp declare variant(foofoo <int>) match(device={xxx}) // expected-warning {{unknown context selector in 'device' context selector set of 'omp declare variant' directive, ignored}}
-#pragma omp declare variant(foofoo <int>) match(device={kind}) // expected-error {{expected '(' after 'kind'}} expected-error {{expected 'host', 'nohost', 'cpu', 'gpu', or 'fpga' in 'kind' context selector of 'device' selector set of 'omp declare variant' directive}} expected-error {{expected ')'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
-#pragma omp declare variant(foofoo <int>) match(device={kind(}) // expected-error {{expected 'host', 'nohost', 'cpu', 'gpu', or 'fpga' in 'kind' context selector of 'device' selector set of 'omp declare variant' directive}} expected-error 2 {{expected ')'}} expected-note {{to match this '('}}
-#pragma omp declare variant(foofoo <int>) match(device={kind()}) // expected-error {{expected 'host', 'nohost', 'cpu', 'gpu', or 'fpga' in 'kind' context selector of 'device' selector set of 'omp declare variant' directive}}
-#pragma omp declare variant(foofoo <int>) match(device={kind(score cpu)}) // expected-error {{expected ')' or ',' after 'score'}} expected-error {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}}
-#pragma omp declare variant(foofoo <int>) match(device={kind(score( ibm)}) // expected-error 2 {{expected ')'}} expected-note {{to match this '('}} expected-error {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}}
-#pragma omp declare variant(foofoo <int>) match(device={kind(score(C gpu)}) // expected-error 2 {{expected ')'}} expected-note {{to match this '('}} expected-error {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}}
-#pragma omp declare variant(foofoo <int>) match(device={kind(score(foofoo <int>()) ibm)}) // expected-error {{expected ')' or ',' after 'score'}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}}
-#pragma omp declare variant(foofoo <int>) match(device={kind(score(C+5): host), kind(llvm)}) // expected-error {{context trait selector 'kind' is used already in the same 'device' context selector set of 'omp declare variant' directive}} expected-note {{previously context trait selector 'kind' used here}} expected-error {{expected ')' or ',' after 'score'}} expected-note {{to match this '('}} expected-error {{expected ')'}} expected-error {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}} expected-error {{unknown 'llvm' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}}
-#pragma omp declare variant(foofoo <int>) match(device={kind(score(C+5): nohost), vendor(llvm)}) // expected-warning {{unknown context selector in 'device' context selector set of 'omp declare variant' directive, ignored}} expected-error {{expected ')' or ',' after 'score'}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}}
+#pragma omp declare variant(foofoo <int>) match(device={kind}) // expected-error {{expected '(' after 'kind'}} expected-error {{expected ')'}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{expected expression}} expected-note {{expected context trait string expression or identifier in 'kind' context selector}}
+#pragma omp declare variant(foofoo <int>) match(device={kind(}) // expected-error 2 {{expected ')'}} expected-note {{to match this '('}} expected-error {{expected expression}} expected-note {{expected context trait string expression or identifier in 'kind' context selector}}
+#pragma omp declare variant(foofoo <int>) match(device={kind()}) // expected-error {{expected expression}} expected-note {{expected context trait string expression or identifier in 'kind' context selector}}
+#pragma omp declare variant(foofoo <int>) match(device={kind((C))})
+#pragma omp declare variant(foofoo <int>) match(device={kind(score cpu)}) // expected-error {{expected ')' or ',' after 'kind of device'}} expected-warning {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga', set ignored}}
+#pragma omp declare variant(foofoo <int>) match(device={kind(score( ibm)}) // expected-error 2 {{expected ')' or ',' after 'kind of device'}} expected-error 2 {{expected ')'}} expected-note {{to match this '('}} expected-error {{expected expression}} expected-error {{use of undeclared identifier 'ibm'}} expected-note 2 {{expected context trait string expression or identifier in 'kind' context selector}} expected-warning {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga', set ignored}}
+#pragma omp declare variant(foofoo <int>) match(device={kind(score(C gpu)}) // expected-error 2 {{expected ')' or ',' after 'kind of device'}} expected-error 3 {{expected ')'}} expected-note 2 {{to match this '('}} expected-error {{expected expression}} expected-error {{unknown type name 'C'}} expected-note 2 {{expected context trait string expression or identifier in 'kind' context selector}} expected-warning {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga', set ignored}}
+#pragma omp declare variant(foofoo <int>) match(device={kind(score(foofoo <int>()) ibm)}) // expected-error 2 {{expected ')' or ',' after 'kind of device'}} expected-error {{trait expression must have a string type, not 'int'}} expected-error {{trait expression must be a constant string expression}} expected-warning {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga', set ignored}} expected-warning {{unknown 'ibm' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga', set ignored}}
+#pragma omp declare variant(foofoo <int>) match(device={kind(score(C+5): host), kind(llvm)}) // expected-error {{context trait selector 'kind' is used already in the same 'device' context selector set of 'omp declare variant' directive}} expected-note {{previously context trait selector 'kind' used here}} expected-note {{to match this '('}} expected-error 2 {{expected ')' or ',' after 'kind of device'}} expected-error 2 {{expected ')'}} expected-error {{expected expression}} expected-note {{expected context trait string expression or identifier in 'kind' context selector}} expected-warning {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga', set ignored}} expected-warning {{unknown 'llvm' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga', set ignored}}
+#pragma omp declare variant(foofoo <int>) match(device={kind(score(C+5): nohost), vendor((C)}) // expected-error 2 {{expected ')' or ',' after 'kind of device'}} expected-warning {{unknown context selector in 'device' context selector set of 'omp declare variant' directive, ignored}} expected-error 2 {{expected ')'}} expected-note {{to match this '('}} expected-error {{expected expression}} expected-note {{expected context trait string expression or identifier in 'kind' context selector}} expected-warning {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga', set ignored}}
 template <typename T, int C>
 T barbar();
 
Index: clang/test/OpenMP/declare_variant_messages.c
===================================================================
--- clang/test/OpenMP/declare_variant_messages.c
+++ clang/test/OpenMP/declare_variant_messages.c
@@ -27,25 +27,25 @@
 #pragma omp declare variant(foo) match(xxx={vvv} xxx) // expected-error {{expected ','}} expected-error {{expected '=' after 'xxx' context selector set name on 'omp declare variant' directive}} expected-error {{context selector set 'xxx' is used already in the same 'omp declare variant' directive}} expected-note {{previously context selector set 'xxx' used here}}
 #pragma omp declare variant(foo) match(xxx={vvv}) xxx // expected-warning {{extra tokens at the end of '#pragma omp declare variant' are ignored}}
 #pragma omp declare variant(foo) match(implementation={xxx}) // expected-warning {{unknown context selector in 'implementation' context selector set of 'omp declare variant' directive, ignored}}
-#pragma omp declare variant(foo) match(implementation={vendor}) // expected-error {{expected '(' after 'vendor'}} expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-error {{expected ')' or ',' after 'vendor name'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
-#pragma omp declare variant(foo) match(implementation={vendor(}) // expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-error {{expected ')' or ',' after 'vendor name'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
-#pragma omp declare variant(foo) match(implementation={vendor()}) // expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}}
+#pragma omp declare variant(foo) match(implementation={vendor}) // expected-error {{expected '(' after 'vendor'}} expected-error {{expected expression}} expected-error {{expected ')' or ',' after 'vendor name'}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-note {{expected context trait string expression or identifier in 'vendor' context selector}}
+#pragma omp declare variant(foo) match(implementation={vendor(}) // expected-error {{expected expression}} expected-error {{expected ')' or ',' after 'vendor name'}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-note {{expected context trait string expression or identifier in 'vendor' context selector}}
+#pragma omp declare variant(foo) match(implementation={vendor()}) // expected-error {{expected expression}} expected-note {{expected context trait string expression or identifier in 'vendor' context selector}}
 #pragma omp declare variant(foo) match(implementation={vendor(score ibm)}) // expected-error {{expected '(' after 'score'}} expected-warning {{missing ':' after context selector score clause - ignoring}}
-#pragma omp declare variant(foo) match(implementation={vendor(score( ibm)}) // expected-error {{expected ')' or ',' after 'vendor name'}} expected-error {{expected ')'}} expected-error {{use of undeclared identifier 'ibm'}} expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-warning {{missing ':' after context selector score clause - ignoring}} expected-note {{to match this '('}}
-#pragma omp declare variant(foo) match(implementation={vendor(score(2 ibm)}) // expected-error {{expected ')' or ',' after 'vendor name'}} expected-error 2 {{expected ')'}} expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-warning {{missing ':' after context selector score clause - ignoring}} expected-note 2 {{to match this '('}}
+#pragma omp declare variant(foo) match(implementation={vendor(score( ibm)}) // expected-error {{expected ')' or ',' after 'vendor name'}} expected-error {{expected ')'}} expected-error {{use of undeclared identifier 'ibm'}} expected-error {{expected expression}} expected-warning {{missing ':' after context selector score clause - ignoring}} expected-note {{to match this '('}} expected-note {{expected context trait string expression or identifier in 'vendor' context selector}}
+#pragma omp declare variant(foo) match(implementation={vendor(score(2 ibm)}) // expected-error {{expected ')' or ',' after 'vendor name'}} expected-error 2 {{expected ')'}} expected-error {{expected expression}} expected-warning {{missing ':' after context selector score clause - ignoring}} expected-note 2 {{to match this '('}} expected-note {{expected context trait string expression or identifier in 'vendor' context selector}}
 #pragma omp declare variant(foo) match(implementation={vendor(score(foo()) ibm)}) // expected-warning {{missing ':' after context selector score clause - ignoring}} expected-error {{expression is not an integer constant expression}}
 #pragma omp declare variant(foo) match(implementation={vendor(score(5): ibm), vendor(llvm)}) // expected-error {{context trait selector 'vendor' is used already in the same 'implementation' context selector set of 'omp declare variant' directive}} expected-note {{previously context trait selector 'vendor' used here}}
 #pragma omp declare variant(foo) match(implementation={vendor(score(5): ibm), kind(cpu)}) // expected-warning {{unknown context selector in 'implementation' context selector set of 'omp declare variant' directive, ignored}}
 #pragma omp declare variant(foo) match(device={xxx}) // expected-warning {{unknown context selector in 'device' context selector set of 'omp declare variant' directive, ignored}}
-#pragma omp declare variant(foo) match(device={kind}) // expected-error {{expected '(' after 'kind'}} expected-error {{expected 'host', 'nohost', 'cpu', 'gpu', or 'fpga' in 'kind' context selector of 'device' selector set of 'omp declare variant' directive}} expected-error {{expected ')'}} expected-error {{expected ')'}} expected-note {{to match this '('}}
-#pragma omp declare variant(foo) match(device={kind(}) // expected-error {{expected 'host', 'nohost', 'cpu', 'gpu', or 'fpga' in 'kind' context selector of 'device' selector set of 'omp declare variant' directive}} expected-error 2 {{expected ')'}} expected-note {{to match this '('}}
-#pragma omp declare variant(foo) match(device={kind()}) // expected-error {{expected 'host', 'nohost', 'cpu', 'gpu', or 'fpga' in 'kind' context selector of 'device' selector set of 'omp declare variant' directive}}
-#pragma omp declare variant(foo) match(device={kind(score cpu)}) // expected-error {{expected ')' or ',' after 'score'}} expected-error {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}}
-#pragma omp declare variant(foo) match(device={kind(score( ibm)}) // expected-error 2 {{expected ')'}} expected-note {{to match this '('}} expected-error {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}}
-#pragma omp declare variant(foo) match(device={kind(score(2 gpu)}) // expected-error 2 {{expected ')'}} expected-note {{to match this '('}} expected-error {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}}
-#pragma omp declare variant(foo) match(device={kind(score(foo()) ibm)}) // expected-error {{expected ')' or ',' after 'score'}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}}
-#pragma omp declare variant(foo) match(device={kind(score(5): host), kind(llvm)}) // expected-error {{context trait selector 'kind' is used already in the same 'device' context selector set of 'omp declare variant' directive}} expected-note {{previously context trait selector 'kind' used here}} expected-error {{expected ')' or ',' after 'score'}} expected-note {{to match this '('}} expected-error {{expected ')'}} expected-error {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}} expected-error {{unknown 'llvm' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}}
-#pragma omp declare variant(foo) match(device={kind(score(5): nohost), vendor(llvm)}) // expected-warning {{unknown context selector in 'device' context selector set of 'omp declare variant' directive, ignored}} expected-error {{expected ')' or ',' after 'score'}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}}}
+#pragma omp declare variant(foo) match(device={kind}) // expected-error {{expected '(' after 'kind'}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-note {{expected context trait string expression or identifier in 'kind' context selector}}
+#pragma omp declare variant(foo) match(device={kind(}) // expected-error {{expected expression}} expected-error 2 {{expected ')'}} expected-note {{to match this '('}} expected-note {{expected context trait string expression or identifier in 'kind' context selector}}
+#pragma omp declare variant(foo) match(device={kind()}) // expected-error {{expected expression}} expected-note {{expected context trait string expression or identifier in 'kind' context selector}}
+#pragma omp declare variant(foo) match(device={kind(score cpu)}) // expected-error {{expected ')' or ',' after 'kind of device'}} expected-warning {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga', set ignored}}
+#pragma omp declare variant(foo) match(device={kind(score( ibm)}) // expected-error 4 {{expected ')'}} expected-note {{to match this '('}} expected-note 2 {{expected context trait string expression or identifier in 'kind' context selector}} expected-error {{use of undeclared identifier 'ibm'}} expected-error {{expected expression}} expected-warning {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga', set ignored}}
+#pragma omp declare variant(foo) match(device={kind(score(2 gpu)}) // expected-error 2 {{expected ')' or ',' after 'kind of device'}} expected-error 3 {{expected ')'}} expected-note 2 {{to match this '('}} expected-error {{trait expression must be a constant string expression}} expected-error {{trait expression must have a string type, not 'int'}} expected-note {{expected context trait string expression or identifier in 'kind' context selector}} expected-error {{expected expression}} expected-warning {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga', set ignored}}
+#pragma omp declare variant(foo) match(device={kind(score(foo()) ibm)}) // expected-error {{expected ')' or ',' after 'kind of device'}} expected-error {{expected ')'}} expected-error {{trait expression must have a string type, not 'int'}} expected-error {{trait expression must be a constant string expression}} expected-warning {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga', set ignored}} expected-warning {{unknown 'ibm' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga', set ignored}}
+#pragma omp declare variant(foo) match(device={kind(score(5): host), kind(llvm)}) // expected-error 2 {{expected ')' or ',' after 'kind of device'}} expected-error {{expected expression}} expected-error {{context trait selector 'kind' is used already in the same 'device' context selector set of 'omp declare variant' directive}} expected-note {{previously context trait selector 'kind' used here}} expected-note {{to match this '('}} expected-error 2 {{expected ')'}} expected-note {{expected context trait string expression or identifier in 'kind' context selector}} expected-error {{trait expression must have a string type, not 'int'}} expected-error {{trait expression must be a constant string expression}} expected-warning {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga', set ignored}} expected-warning {{unknown 'llvm' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga', set ignored}}
+#pragma omp declare variant(foo) match(device={kind(score(5): nohost), vendor(llvm)}) // expected-error 2 {{expected ')' or ',' after 'kind of device'}} expected-warning {{unknown context selector in 'device' context selector set of 'omp declare variant' directive, ignored}} expected-error 2 {{expected ')'}} expected-note {{to match this '('}} expected-note {{expected context trait string expression or identifier in 'kind' context selector}} expected-error {{expected expression}} expected-error {{trait expression must have a string type, not 'int'}} expected-error {{trait expression must be a constant string expression}} expected-warning {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga', set ignored}}
 int bar(void);
 
 // expected-error@+2 {{'#pragma omp declare variant' can only be applied to functions}}
Index: clang/test/OpenMP/declare_variant_implementation_vendor_codegen.cpp
===================================================================
--- clang/test/OpenMP/declare_variant_implementation_vendor_codegen.cpp
+++ clang/test/OpenMP/declare_variant_implementation_vendor_codegen.cpp
@@ -38,7 +38,7 @@
 int bar() { return 1; }
 
 int bazzz();
-#pragma omp declare variant(bazzz) match(implementation = {vendor(llvm)})
+#pragma omp declare variant(bazzz) match(implementation = {vendor("llvm")})
 int baz() { return 1; }
 
 int test();
@@ -101,7 +101,7 @@
 int prio1() { return 82; }
 
 #pragma omp declare variant(prio) match(implementation = {vendor(llvm)})
-#pragma omp declare variant(prio1) match(implementation = {vendor(score(1): llvm)})
+#pragma omp declare variant(prio1) match(implementation = {vendor(score(1): "llvm")})
 int prio_() { return 1; }
 
 static int prio2() { return 83; }
Index: clang/test/OpenMP/declare_variant_device_kind_codegen.cpp
===================================================================
--- clang/test/OpenMP/declare_variant_device_kind_codegen.cpp
+++ clang/test/OpenMP/declare_variant_device_kind_codegen.cpp
@@ -76,14 +76,14 @@
 #define WRONG host, nohost
 #endif // HOST
 #ifdef CPU
-#define CORRECT cpu
+#define CORRECT "cpu"
 #define SUBSET host, cpu
 #define WRONG cpu, gpu
 #endif // CPU
 #ifdef NOHOST
 #define CORRECT nohost
 #define SUBSET nohost, cpu
-#define WRONG nohost, host
+#define WRONG nohost, "host"
 #endif // NOHOST
 
 int foo() { return 2; }
Index: clang/test/OpenMP/declare_variant_ast_print.cpp
===================================================================
--- clang/test/OpenMP/declare_variant_ast_print.cpp
+++ clang/test/OpenMP/declare_variant_ast_print.cpp
@@ -17,9 +17,9 @@
 // CHECK-NEXT: return int();
 // CHECK-NEXT: }
 
-// CHECK:      #pragma omp declare variant(foofoo<int>) match(implementation={vendor(score(5):ibm)},device={kind(fpga)})
-// CHECK-NEXT: #pragma omp declare variant(foofoo<int>) match(implementation={vendor(score(0):unknown)})
-// CHECK-NEXT: #pragma omp declare variant(foofoo<int>) match(implementation={vendor(score(0):llvm)},device={kind(cpu)})
+// CHECK:      #pragma omp declare variant(foofoo<int>) match(implementation={vendor(score(5):"ibm")},device={kind("fpga")})
+// CHECK-NEXT: #pragma omp declare variant(foofoo<int>) match(implementation={vendor(score(0):"unknown")})
+// CHECK-NEXT: #pragma omp declare variant(foofoo<int>) match(implementation={vendor(score(0):"llvm")},device={kind("cpu")})
 // CHECK-NEXT: int bar();
 #pragma omp declare variant(foofoo <int>) match(xxx = {})
 #pragma omp declare variant(foofoo <int>) match(xxx = {vvv})
@@ -28,9 +28,9 @@
 #pragma omp declare variant(foofoo <int>) match(implementation={vendor(score(5): ibm)}, device={kind(fpga)})
 int bar();
 
-// CHECK:      #pragma omp declare variant(foofoo<T>) match(implementation={vendor(score(C + 5):ibm, xxx)},device={kind(cpu, host)})
-// CHECK-NEXT: #pragma omp declare variant(foofoo<T>) match(implementation={vendor(score(0):unknown)})
-// CHECK-NEXT: #pragma omp declare variant(foofoo<T>) match(implementation={vendor(score(0):llvm)},device={kind(cpu)})
+// CHECK:      #pragma omp declare variant(foofoo<T>) match(implementation={vendor(score(C + 5):"ibm", "xxx", "ibm")},device={kind("cpu", "host")})
+// CHECK-NEXT: #pragma omp declare variant(foofoo<T>) match(implementation={vendor(score(0):"unknown")})
+// CHECK-NEXT: #pragma omp declare variant(foofoo<T>) match(implementation={vendor(score(0):"llvm")},device={kind("cpu")})
 // CHECK-NEXT: template <typename T, int C> T barbar();
 #pragma omp declare variant(foofoo <T>) match(xxx = {})
 #pragma omp declare variant(foofoo <T>) match(xxx = {vvv})
@@ -44,9 +44,9 @@
 template <typename T, int C>
 T barbar();
 
-// CHECK:      #pragma omp declare variant(foofoo<int>) match(implementation={vendor(score(3 + 5):ibm, xxx)},device={kind(cpu, host)})
-// CHECK-NEXT: #pragma omp declare variant(foofoo<int>) match(implementation={vendor(score(0):unknown)})
-// CHECK-NEXT: #pragma omp declare variant(foofoo<int>) match(implementation={vendor(score(0):llvm)},device={kind(cpu)})
+// CHECK:      #pragma omp declare variant(foofoo<int>) match(implementation={vendor(score(3 + 5):"ibm", "xxx", "ibm")},device={kind("cpu", "host")})
+// CHECK-NEXT: #pragma omp declare variant(foofoo<int>) match(implementation={vendor(score(0):"unknown")})
+// CHECK-NEXT: #pragma omp declare variant(foofoo<int>) match(implementation={vendor(score(0):"llvm")},device={kind("cpu")})
 // CHECK-NEXT: template<> int barbar<int, 3>();
 
 // CHECK-NEXT: int baz() {
@@ -66,8 +66,8 @@
 void h_ref(C *hp, C *hp2, C *hq, C *lin) {
 }
 
-// CHECK:      #pragma omp declare variant(h_ref<C>) match(implementation={vendor(score(0):unknown)},device={kind(nohost)})
-// CHECK-NEXT: #pragma omp declare variant(h_ref<C>) match(implementation={vendor(score(0):llvm)},device={kind(gpu)})
+// CHECK:      #pragma omp declare variant(h_ref<C>) match(implementation={vendor(score(0):"unknown")},device={kind("nohost")})
+// CHECK-NEXT: #pragma omp declare variant(h_ref<C>) match(implementation={vendor(score(0):"llvm")},device={kind("gpu")})
 // CHECK-NEXT: template <class C> void h(C *hp, C *hp2, C *hq, C *lin) {
 // CHECK-NEXT: }
 #pragma omp declare variant(h_ref <C>) match(xxx = {})
@@ -77,8 +77,8 @@
 void h(C *hp, C *hp2, C *hq, C *lin) {
 }
 
-// CHECK:      #pragma omp declare variant(h_ref<float>) match(implementation={vendor(score(0):unknown)},device={kind(nohost)})
-// CHECK-NEXT: #pragma omp declare variant(h_ref<float>) match(implementation={vendor(score(0):llvm)},device={kind(gpu)})
+// CHECK:      #pragma omp declare variant(h_ref<float>) match(implementation={vendor(score(0):"unknown")},device={kind("nohost")})
+// CHECK-NEXT: #pragma omp declare variant(h_ref<float>) match(implementation={vendor(score(0):"llvm")},device={kind("gpu")})
 // CHECK-NEXT: template<> void h<float>(float *hp, float *hp2, float *hq, float *lin) {
 // CHECK-NEXT: }
 
@@ -86,8 +86,8 @@
 // CHECK-NEXT:   h((float *)hp, (float *)hp2, (float *)hq, (float *)lin);
 // CHECK-NEXT: }
 #pragma omp declare variant(h_ref <double>) match(xxx = {})
-#pragma omp declare variant(h_ref <double>) match(implementation={vendor(ibm)},device={kind(cpu,gpu)})
-#pragma omp declare variant(h_ref <double>) match(implementation={vendor(unknown)})
+#pragma omp declare variant(h_ref <double>) match(implementation={vendor(ibm)},device={kind("cpu","gpu")})
+#pragma omp declare variant(h_ref <double>) match(implementation={vendor("unknown")})
 template <>
 void h(double *hp, double *hp2, double *hq, double *lin) {
   h((float *)hp, (float *)hp2, (float *)hq, (float *)lin);
@@ -97,20 +97,20 @@
 int fn();
 // CHECK: int fn(int);
 int fn(int);
-// CHECK:      #pragma omp declare variant(fn) match(implementation={vendor(score(0):unknown)},device={kind(cpu, gpu)})
-// CHECK-NEXT: #pragma omp declare variant(fn) match(implementation={vendor(score(0):llvm)})
+// CHECK:      #pragma omp declare variant(fn) match(implementation={vendor(score(0):"unknown")},device={kind("cpu", "gpu")})
+// CHECK-NEXT: #pragma omp declare variant(fn) match(implementation={vendor(score(0):"llvm")})
 // CHECK-NEXT: int overload();
 #pragma omp declare variant(fn) match(xxx = {})
 #pragma omp declare variant(fn) match(implementation={vendor(llvm)})
-#pragma omp declare variant(fn) match(implementation={vendor(unknown)},device={kind(cpu,gpu)})
+#pragma omp declare variant(fn) match(implementation={vendor(unknown)},device={kind(cpu,"gpu""")})
 int overload(void);
 
 // CHECK:      int fn_deduced_variant() {
 // CHECK-NEXT: return 0;
 // CHECK-NEXT: }
 auto fn_deduced_variant() { return 0; }
-// CHECK:      #pragma omp declare variant(fn_deduced_variant) match(implementation={vendor(score(0):unknown)},device={kind(gpu, nohost)})
-// CHECK-NEXT: #pragma omp declare variant(fn_deduced_variant) match(implementation={vendor(score(0):llvm)},device={kind(cpu, host)})
+// CHECK:      #pragma omp declare variant(fn_deduced_variant) match(implementation={vendor(score(0):"unknown")},device={kind("gpu", "nohost")})
+// CHECK-NEXT: #pragma omp declare variant(fn_deduced_variant) match(implementation={vendor(score(0):"llvm")},device={kind("cpu", "host")})
 // CHECK-NEXT: int fn_deduced();
 #pragma omp declare variant(fn_deduced_variant) match(xxx = {})
 #pragma omp declare variant(fn_deduced_variant) match(implementation={vendor(llvm)},device={kind(cpu,host)})
@@ -119,8 +119,8 @@
 
 // CHECK: int fn_deduced_variant1();
 int fn_deduced_variant1();
-// CHECK:      #pragma omp declare variant(fn_deduced_variant1) match(implementation={vendor(score(0):unknown)},device={kind(cpu, host)})
-// CHECK-NEXT: #pragma omp declare variant(fn_deduced_variant1) match(implementation={vendor(score(0):ibm)},device={kind(gpu, nohost)})
+// CHECK:      #pragma omp declare variant(fn_deduced_variant1) match(implementation={vendor(score(0):"unknown")},device={kind("cpu", "host")})
+// CHECK-NEXT: #pragma omp declare variant(fn_deduced_variant1) match(implementation={vendor(score(0):"ibm")},device={kind("gpu", "nohost")})
 // CHECK-NEXT: int fn_deduced1() {
 // CHECK-NEXT: return 0;
 // CHECK-NEXT: }
@@ -140,11 +140,11 @@
 // CHECK-NEXT: }
 // CHECK-NEXT: void bar(int) {
 // CHECK-NEXT: }
-// CHECK-NEXT: #pragma omp declare variant(SpecialFuncs::baz) match(implementation={vendor(score(0):unknown)},device={kind(nohost)})
-// CHECK-NEXT: #pragma omp declare variant(SpecialFuncs::bar) match(implementation={vendor(score(0):ibm)},device={kind(cpu)})
+// CHECK-NEXT: #pragma omp declare variant(SpecialFuncs::baz) match(implementation={vendor(score(0):"unknown")},device={kind("nohost")})
+// CHECK-NEXT: #pragma omp declare variant(SpecialFuncs::bar) match(implementation={vendor(score(0):"ibm")},device={kind("cpu")})
 // CHECK-NEXT: void foo1() {
 // CHECK-NEXT: }
-// CHECK-NEXT: #pragma omp declare variant(SpecialFuncs::baz) match(implementation={vendor(score(0):unknown)},device={kind(cpu, host)})
+// CHECK-NEXT: #pragma omp declare variant(SpecialFuncs::baz) match(implementation={vendor(score(0):"unknown")},device={kind("cpu", "host")})
 // CHECK-NEXT: void xxx();
 // CHECK-NEXT: } s;
 struct SpecialFuncs {
@@ -164,7 +164,7 @@
   void xxx();
 } s;
 
-// CHECK:      #pragma omp declare variant(SpecialFuncs::baz) match(implementation={vendor(score(0):unknown)},device={kind(cpu, host)})
+// CHECK:      #pragma omp declare variant(SpecialFuncs::baz) match(implementation={vendor(score(0):"unknown")},device={kind("cpu", "host")})
 // CHECK-NEXT: void SpecialFuncs::xxx() {
 // CHECK-NEXT: }
 void SpecialFuncs::xxx() {}
@@ -172,8 +172,8 @@
 // CHECK:      static void static_f_variant() {
 // CHECK-NEXT: }
 static void static_f_variant() {}
-// CHECK:      #pragma omp declare variant(static_f_variant) match(implementation={vendor(score(0):unknown)})
-// CHECK-NEXT: #pragma omp declare variant(static_f_variant) match(implementation={vendor(score(0):llvm)},device={kind(fpga)})
+// CHECK:      #pragma omp declare variant(static_f_variant) match(implementation={vendor(score(0):"unknown")})
+// CHECK-NEXT: #pragma omp declare variant(static_f_variant) match(implementation={vendor(score(0):"llvm")},device={kind("fpga")})
 // CHECK-NEXT: static void static_f() {
 // CHECK-NEXT: }
 #pragma omp declare variant(static_f_variant) match(xxx = {})
@@ -192,7 +192,7 @@
 
 // CHECK: int fn_linkage_variant();
 // CHECK: extern "C" {
-// CHECK:     #pragma omp declare variant(fn_linkage_variant) match(implementation={vendor(score(0):xxx)},device={kind(cpu, host)})
+// CHECK:     #pragma omp declare variant(fn_linkage_variant) match(implementation={vendor(score(0):"xxx")},device={kind("cpu", "host")})
 // CHECK:     int fn_linkage();
 // CHECK: }
 int fn_linkage_variant();
@@ -202,9 +202,9 @@
 }
 
 // CHECK: extern "C" int fn_linkage_variant1()
-// CHECK: #pragma omp declare variant(fn_linkage_variant1) match(implementation={vendor(score(0):xxx)},device={kind(cpu, host)})
+// CHECK: #pragma omp declare variant(fn_linkage_variant1) match(implementation={vendor(score(0):"xxx")},device={kind("cpu", "host")})
 // CHECK: int fn_linkage1();
 extern "C" int fn_linkage_variant1();
-#pragma omp declare variant(fn_linkage_variant1) match(implementation = {vendor(xxx)},device={kind(cpu,host)})
+#pragma omp declare variant(fn_linkage_variant1) match(implementation = {vendor(xxx)},device={kind("cpu","host")})
 int fn_linkage1();
 
Index: clang/test/OpenMP/declare_variant_ast_print.c
===================================================================
--- clang/test/OpenMP/declare_variant_ast_print.c
+++ clang/test/OpenMP/declare_variant_ast_print.c
@@ -10,17 +10,17 @@
 #pragma omp declare variant(foo) match(xxx={vvv})
 #pragma omp declare variant(foo) match(implementation={vendor(llvm)}, device={kind(fpga)})
 #pragma omp declare variant(foo) match(implementation={vendor(llvm), xxx})
-#pragma omp declare variant(foo) match(implementation={vendor(unknown)}, device={kind(gpu)})
-#pragma omp declare variant(foo) match(implementation={vendor(score(5): ibm, xxx, ibm)}, device={kind(cpu, nohost)})
+#pragma omp declare variant(foo) match(implementation={vendor(unknown)}, device={kind("gpu")})
+#pragma omp declare variant(foo) match(implementation={vendor(score(5): ibm, "xxx", ibm)}, device={kind(cpu, nohost)})
 #pragma omp declare variant(foo) match(device={kind(host)})
-#pragma omp declare variant(foo) match(device={kind(nohost), xxx})
+#pragma omp declare variant(foo) match(device={kind("nohost"), xxx})
 int bar(void);
 
 // CHECK:      int foo();
-// CHECK-NEXT: #pragma omp declare variant(foo) match(device={kind(nohost)})
-// CHECK-NEXT: #pragma omp declare variant(foo) match(device={kind(host)})
-// CHECK-NEXT: #pragma omp declare variant(foo) match(implementation={vendor(score(5):ibm, xxx)},device={kind(cpu, nohost)})
-// CHECK-NEXT: #pragma omp declare variant(foo) match(implementation={vendor(score(0):unknown)},device={kind(gpu)})
-// CHECK-NEXT: #pragma omp declare variant(foo) match(implementation={vendor(score(0):llvm)})
-// CHECK-NEXT: #pragma omp declare variant(foo) match(implementation={vendor(score(0):llvm)},device={kind(fpga)})
+// CHECK-NEXT: #pragma omp declare variant(foo) match(device={kind("nohost")})
+// CHECK-NEXT: #pragma omp declare variant(foo) match(device={kind("host")})
+// CHECK-NEXT: #pragma omp declare variant(foo) match(implementation={vendor(score(5):"ibm", "xxx", "ibm")},device={kind("cpu", "nohost")})
+// CHECK-NEXT: #pragma omp declare variant(foo) match(implementation={vendor(score(0):"unknown")},device={kind("gpu")})
+// CHECK-NEXT: #pragma omp declare variant(foo) match(implementation={vendor(score(0):"llvm")})
+// CHECK-NEXT: #pragma omp declare variant(foo) match(implementation={vendor(score(0):"llvm")},device={kind("fpga")})
 // CHECK-NEXT: int bar();
Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -409,30 +409,30 @@
         *std::next(Attr.ctxSelectorSets_begin(), I));
     auto Ctx = static_cast<OpenMPContextSelectorKind>(
         *std::next(Attr.ctxSelectors_begin(), I));
-    switch (CtxSet) {
-    case OMP_CTX_SET_implementation:
-      switch (Ctx) {
-      case OMP_CTX_vendor:
-        Data.emplace_back(CtxSet, Ctx, Score, Attr.implVendors());
-        break;
-      case OMP_CTX_kind:
-      case OMP_CTX_unknown:
-        llvm_unreachable("Unexpected context selector kind.");
+    SmallVector<ExprResult, 4> Values;
+    switch (Ctx) {
+    case OMP_CTX_vendor:
+      assert(CtxSet == OMP_CTX_SET_implementation &&
+             "Expected implementation context selector set.");
+      for (Expr *Val : Attr.implVendors()) {
+        ExprResult ER = Subst(Val);
+        if (ER.isUsable())
+          Values.push_back(ER);
       }
       break;
-    case OMP_CTX_SET_device:
-      switch (Ctx) {
-      case OMP_CTX_kind:
-        Data.emplace_back(CtxSet, Ctx, Score, Attr.deviceKinds());
-        break;
-      case OMP_CTX_vendor:
-      case OMP_CTX_unknown:
-        llvm_unreachable("Unexpected context selector kind.");
+    case OMP_CTX_kind:
+      assert(CtxSet == OMP_CTX_SET_device &&
+             "Expected device context selector set.");
+      for (Expr *Val : Attr.deviceKinds()) {
+        ExprResult ER = Subst(Val);
+        if (ER.isUsable())
+          Values.push_back(ER);
       }
       break;
-    case OMP_CTX_SET_unknown:
-      llvm_unreachable("Unexpected context selector set kind.");
+    case OMP_CTX_unknown:
+      llvm_unreachable("Unexpected context selector kind.");
     }
+    Data.emplace_back(CtxSet, Ctx, Score, Values);
   }
   S.ActOnOpenMPDeclareVariantDirective(DeclVarData.getValue().first,
                                        DeclVarData.getValue().second,
Index: clang/lib/Sema/SemaOpenMP.cpp
===================================================================
--- clang/lib/Sema/SemaOpenMP.cpp
+++ clang/lib/Sema/SemaOpenMP.cpp
@@ -30,7 +30,9 @@
 #include "clang/Sema/SemaInternal.h"
 #include "llvm/ADT/IndexedMap.h"
 #include "llvm/ADT/PointerEmbeddedInt.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/Frontend/OpenMP/OMPConstants.h"
+#include "llvm/Support/ConvertUTF.h"
 using namespace clang;
 using namespace llvm::omp;
 
@@ -5393,6 +5395,136 @@
   return std::make_pair(FD, cast<Expr>(DRE));
 }
 
+static llvm::Optional<std::string>
+tryConverStringLiteralToString(const StringLiteral *SL) {
+  std::string Name;
+  switch (SL->getKind()) {
+  case StringLiteral::Ascii:
+  case StringLiteral::UTF8:
+    Name = SL->getString();
+    break;
+  case StringLiteral::UTF16:
+    if (!llvm::convertUTF16ToUTF8String(
+            llvm::makeArrayRef(SL->getBytes().begin(), SL->getBytes().end()),
+            Name))
+      return llvm::None;
+    break;
+  case StringLiteral::UTF32:
+    llvm_unreachable("UTF32 is unsupported.");
+  case StringLiteral::Wide: {
+    std::wstring WideString;
+    for (int I = 0, E = SL->getLength(); I < E; ++I)
+      WideString += static_cast<wchar_t>(SL->getCodeUnit(I));
+    if (!llvm::convertWideToUTF8(WideString, Name))
+      return llvm::None;
+    break;
+  }
+  }
+  return Name;
+}
+
+static ExprResult performImplicitStringConversion(
+    Sema &S, Expr *E,
+    llvm::function_ref<bool(Sema &S, StringRef)> Checker =
+        [](Sema &S, StringRef) { return true; }) {
+  if (E->isTypeDependent() || E->isValueDependent() ||
+      E->isInstantiationDependent())
+    return E;
+  E = S.DefaultFunctionArrayLvalueConversion(E).get();
+  if (!E)
+    return ExprError();
+  class StringConverter : public Sema::ContextualImplicitConverter {
+  public:
+    StringConverter()
+        : Sema::ContextualImplicitConverter(/*Suppress=*/false,
+                                            /*SuppressConversion=*/true) {}
+
+    bool match(QualType ConvType) override {
+      if (ConvType->isArrayType() || ConvType->isPointerType()) {
+        const Type *ElTy = ConvType->getPointeeOrArrayElementType();
+        return ElTy->isWideCharType() || ElTy->isCharType() ||
+               ElTy->isChar8Type() || ElTy->isChar16Type();
+      }
+      return false;
+    }
+
+    Sema::SemaDiagnosticBuilder diagnoseNoMatch(Sema &S, SourceLocation Loc,
+                                                QualType T) override {
+      return S.Diag(Loc, diag::err_omp_trait_not_string) << T;
+    }
+
+    Sema::SemaDiagnosticBuilder diagnoseIncomplete(Sema &S, SourceLocation Loc,
+                                                   QualType T) override {
+      return S.Diag(Loc, diag::err_omp_incomplete_type) << T;
+    }
+
+    Sema::SemaDiagnosticBuilder diagnoseExplicitConv(Sema &S,
+                                                     SourceLocation Loc,
+                                                     QualType T,
+                                                     QualType ConvTy) override {
+      return S.Diag(Loc, diag::err_omp_explicit_conversion) << T << ConvTy;
+    }
+
+    Sema::SemaDiagnosticBuilder noteExplicitConv(Sema &S,
+                                                 CXXConversionDecl *Conv,
+                                                 QualType ConvTy) override {
+      return S.Diag(Conv->getLocation(), diag::note_omp_trait_conversion_here)
+             << ConvTy;
+    }
+
+    Sema::SemaDiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc,
+                                                  QualType T) override {
+      return S.Diag(Loc, diag::err_omp_trait_ambiguous_conversion) << T;
+    }
+
+    Sema::SemaDiagnosticBuilder noteAmbiguous(Sema &S, CXXConversionDecl *Conv,
+                                              QualType ConvTy) override {
+      return S.Diag(Conv->getLocation(), diag::note_omp_trait_conversion_here)
+             << ConvTy;
+    }
+
+    Sema::SemaDiagnosticBuilder diagnoseConversion(Sema &S, SourceLocation Loc,
+                                                   QualType T,
+                                                   QualType ConvTy) override {
+      llvm_unreachable("conversion functions are permitted");
+    }
+  } Converter;
+
+  ExprResult ER =
+      S.PerformContextualImplicitConversion(E->getBeginLoc(), E, Converter);
+  if (!ER.isUsable())
+    return ExprError();
+  E = ER.get();
+  Expr::EvalResult Res;
+  if (!E->EvaluateAsRValue(Res, S.Context) || !Res.Val.isLValue()) {
+    S.Diag(E->getExprLoc(), diag::err_omp_trait_not_constant_string)
+        << E->getSourceRange();
+    return ExprError();
+  }
+  const auto *SL = dyn_cast_or_null<StringLiteral>(
+      Res.Val.getLValueBase().dyn_cast<const Expr *>());
+  if (!SL) {
+    S.Diag(E->getExprLoc(), diag::err_omp_trait_not_constant_string)
+        << E->getSourceRange();
+    return ExprError();
+  }
+  llvm::Optional<std::string> Value = tryConverStringLiteralToString(SL);
+  if (!Value) {
+    S.Diag(E->getExprLoc(), diag::err_omp_trait_not_constant_string)
+        << E->getSourceRange();
+    return ExprError();
+  }
+  // Normalize.
+  std::string ResString = StringRef(*Value).lower();
+  if (!Checker(S, ResString))
+    return ExprError();
+  return StringLiteral::Create(S.Context, ResString, StringLiteral::Ascii,
+                               /*Pascal=*/false,
+                               S.getASTContext().getStringLiteralArrayType(
+                                   S.getASTContext().CharTy, (*Value).length()),
+                               E->getExprLoc());
+}
+
 void Sema::ActOnOpenMPDeclareVariantDirective(
     FunctionDecl *FD, Expr *VariantRef, SourceRange SR,
     ArrayRef<OMPCtxSelectorData> Data) {
@@ -5401,7 +5533,7 @@
   SmallVector<Expr *, 4> CtxScores;
   SmallVector<unsigned, 4> CtxSets;
   SmallVector<unsigned, 4> Ctxs;
-  SmallVector<StringRef, 4> ImplVendors, DeviceKinds;
+  SmallVector<Expr *, 4> ImplVendors, DeviceKinds;
   bool IsError = false;
   for (const OMPCtxSelectorData &D : Data) {
     OpenMPContextSelectorSetKind CtxSet = D.CtxSet;
@@ -5435,19 +5567,46 @@
       else
         Score = ActOnIntegerConstant(SourceLocation(), 0).get();
     }
-    switch (Ctx) {
-    case OMP_CTX_vendor:
-      assert(CtxSet == OMP_CTX_SET_implementation &&
-             "Expected implementation context selector set.");
-      ImplVendors.append(D.Names.begin(), D.Names.end());
-      break;
-    case OMP_CTX_kind:
-      assert(CtxSet == OMP_CTX_SET_device &&
-             "Expected device context selector set.");
-      DeviceKinds.append(D.Names.begin(), D.Names.end());
-      break;
-    case OMP_CTX_unknown:
-      llvm_unreachable("Unknown context selector kind.");
+    for (ExprResult ER : D.Names) {
+      switch (Ctx) {
+      case OMP_CTX_vendor:
+        assert(CtxSet == OMP_CTX_SET_implementation &&
+               "Expected implementation context selector set.");
+        ER = performImplicitStringConversion(*this, ER.get());
+        if (!ER.isUsable()) {
+          IsError = true;
+          continue;
+        }
+        ImplVendors.push_back(ER.get());
+        break;
+      case OMP_CTX_kind:
+        assert(CtxSet == OMP_CTX_SET_device &&
+               "Expected device context selector set.");
+        ER = performImplicitStringConversion(
+            *this, ER.get(), [ER](Sema &S, StringRef Name) {
+              if (llvm::StringSwitch<bool>(Name)
+                      .Case("host", false)
+                      .Case("nohost", false)
+                      .Case("cpu", false)
+                      .Case("gpu", false)
+                      .Case("fpga", false)
+                      .Default(true)) {
+                S.Diag(ER.get()->getExprLoc(),
+                       diag::warn_omp_wrong_device_kind_trait)
+                    << Name << ER.get()->getSourceRange();
+                return false;
+              }
+              return true;
+            });
+        if (!ER.isUsable()) {
+          IsError = true;
+          continue;
+        }
+        DeviceKinds.push_back(ER.get());
+        break;
+      case OMP_CTX_unknown:
+        llvm_unreachable("Unknown context selector kind.");
+      }
     }
     IsError = IsError || !Score;
     CtxSets.push_back(CtxSet);
@@ -5464,6 +5623,12 @@
   }
 }
 
+ExprResult Sema::ActOnOpenMPTraitId(SourceLocation Loc, StringRef TraitName) {
+  return StringLiteral::Create(
+      Context, TraitName, StringLiteral::Ascii, /*Pascal=*/false,
+      Context.getStringLiteralArrayType(Context.CharTy, TraitName.size()), Loc);
+}
+
 void Sema::markOpenMPDeclareVariantFuncsReferenced(SourceLocation Loc,
                                                    FunctionDecl *Func,
                                                    bool MightBeOdrUse) {
Index: clang/lib/Parse/ParseOpenMP.cpp
===================================================================
--- clang/lib/Parse/ParseOpenMP.cpp
+++ clang/lib/Parse/ParseOpenMP.cpp
@@ -824,6 +824,52 @@
   return ScoreExpr;
 }
 
+/// Tries to parse trait constraint as an identifier or constant string literal
+/// expression.
+/// '(' [ 'score' '(' <score _expr> ')' ':' ] <trait> { ',' <trait> } ')'
+static void
+parseTraitStringExpression(Parser &P, OpenMPContextSelectorSetKind CSSKind,
+                           OpenMPContextSelectorKind CSKind, bool WithScore,
+                           StringRef FullDescriptionForPuncMsg,
+                           SmallVectorImpl<Sema::OMPCtxSelectorData> &Data) {
+  // Parse '('.
+  BalancedDelimiterTracker T(P, tok::l_paren, tok::annot_pragma_openmp_end);
+  (void)T.expectAndConsume(diag::err_expected_lparen_after,
+                           getOpenMPContextSelectorName(CSKind).data());
+  ExprResult Score;
+  if (WithScore)
+    Score = parseContextScore(P);
+  SmallVector<ExprResult, 4> Traits;
+  const Token &Tok = P.getCurToken();
+  SourceLocation PrevLoc;
+  do {
+    PrevLoc = Tok.getLocation();
+    // Parse trait value, which is constant expression of string type or
+    // identifier.
+    ExprResult Trait;
+    if (Tok.isAnyIdentifier()) {
+      Sema::OMPCtxStringType Buffer;
+      StringRef TraitName = P.getPreprocessor().getSpelling(Tok, Buffer);
+      (void)P.ConsumeToken();
+      Trait = P.getActions().ActOnOpenMPTraitId(PrevLoc, TraitName);
+    } else {
+      Trait = P.ParseConstantExpression();
+    }
+    if (!Trait.isUsable())
+      P.Diag(PrevLoc, diag::note_omp_expected_context_selector_trait_string)
+          << getOpenMPContextSelectorName(CSKind);
+    else
+      Traits.push_back(Trait);
+    if (!P.TryConsumeToken(tok::comma) && Tok.isNot(tok::r_paren))
+      P.Diag(Tok, diag::err_expected_punc) << FullDescriptionForPuncMsg;
+  } while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end) &&
+           PrevLoc.getRawEncoding() != Tok.getLocation().getRawEncoding());
+  // Parse ')'.
+  (void)T.consumeClose();
+  if (!Traits.empty())
+    Data.emplace_back(CSSKind, CSKind, Score, Traits);
+}
+
 /// Parse context selector for 'implementation' selector set:
 /// 'vendor' '(' [ 'score' '(' <score _expr> ')' ':' ] <vendor> { ',' <vendor> }
 /// ')'
@@ -856,39 +902,10 @@
   OpenMPContextSelectorKind CSKind = getOpenMPContextSelector(CtxSelectorName);
   (void)P.ConsumeToken();
   switch (CSKind) {
-  case OMP_CTX_vendor: {
-    // Parse '('.
-    BalancedDelimiterTracker T(P, tok::l_paren, tok::annot_pragma_openmp_end);
-    (void)T.expectAndConsume(diag::err_expected_lparen_after,
-                             CtxSelectorName.data());
-    ExprResult Score = parseContextScore(P);
-    llvm::UniqueVector<Sema::OMPCtxStringType> Vendors;
-    do {
-      // Parse <vendor>.
-      StringRef VendorName;
-      if (Tok.is(tok::identifier)) {
-        Buffer.clear();
-        VendorName = P.getPreprocessor().getSpelling(P.getCurToken(), Buffer);
-        (void)P.ConsumeToken();
-        if (!VendorName.empty())
-          Vendors.insert(VendorName);
-      } else {
-        P.Diag(Tok.getLocation(), diag::err_omp_declare_variant_item_expected)
-            << "vendor identifier"
-            << "vendor"
-            << "implementation";
-      }
-      if (!P.TryConsumeToken(tok::comma) && Tok.isNot(tok::r_paren)) {
-        P.Diag(Tok, diag::err_expected_punc)
-            << (VendorName.empty() ? "vendor name" : VendorName);
-      }
-    } while (Tok.is(tok::identifier));
-    // Parse ')'.
-    (void)T.consumeClose();
-    if (!Vendors.empty())
-      Data.emplace_back(OMP_CTX_SET_implementation, CSKind, Score, Vendors);
+  case OMP_CTX_vendor:
+    parseTraitStringExpression(P, OMP_CTX_SET_implementation, CSKind,
+                               /*WithScore=*/true, "vendor name", Data);
     break;
-  }
   case OMP_CTX_kind:
   case OMP_CTX_unknown:
     P.Diag(Tok.getLocation(), diag::warn_omp_declare_variant_cs_name_expected)
@@ -932,48 +949,10 @@
   OpenMPContextSelectorKind CSKind = getOpenMPContextSelector(CtxSelectorName);
   (void)P.ConsumeToken();
   switch (CSKind) {
-  case OMP_CTX_kind: {
-    // Parse '('.
-    BalancedDelimiterTracker T(P, tok::l_paren, tok::annot_pragma_openmp_end);
-    (void)T.expectAndConsume(diag::err_expected_lparen_after,
-                             CtxSelectorName.data());
-    llvm::UniqueVector<Sema::OMPCtxStringType> Kinds;
-    do {
-      // Parse <kind>.
-      StringRef KindName;
-      if (Tok.is(tok::identifier)) {
-        Buffer.clear();
-        KindName = P.getPreprocessor().getSpelling(P.getCurToken(), Buffer);
-        SourceLocation SLoc = P.getCurToken().getLocation();
-        (void)P.ConsumeToken();
-        if (llvm::StringSwitch<bool>(KindName)
-                .Case("host", false)
-                .Case("nohost", false)
-                .Case("cpu", false)
-                .Case("gpu", false)
-                .Case("fpga", false)
-                .Default(true)) {
-          P.Diag(SLoc, diag::err_omp_wrong_device_kind_trait) << KindName;
-        } else {
-          Kinds.insert(KindName);
-        }
-      } else {
-        P.Diag(Tok.getLocation(), diag::err_omp_declare_variant_item_expected)
-            << "'host', 'nohost', 'cpu', 'gpu', or 'fpga'"
-            << "kind"
-            << "device";
-      }
-      if (!P.TryConsumeToken(tok::comma) && Tok.isNot(tok::r_paren)) {
-        P.Diag(Tok, diag::err_expected_punc)
-            << (KindName.empty() ? "kind of device" : KindName);
-      }
-    } while (Tok.is(tok::identifier));
-    // Parse ')'.
-    (void)T.consumeClose();
-    if (!Kinds.empty())
-      Data.emplace_back(OMP_CTX_SET_device, CSKind, ExprResult(), Kinds);
+  case OMP_CTX_kind:
+    parseTraitStringExpression(P, OMP_CTX_SET_device, CSKind,
+                               /*WithScore=*/false, "kind of device", Data);
     break;
-  }
   case OMP_CTX_vendor:
   case OMP_CTX_unknown:
     P.Diag(Tok.getLocation(), diag::warn_omp_declare_variant_cs_name_expected)
Index: clang/lib/CodeGen/CGOpenMPRuntime.cpp
===================================================================
--- clang/lib/CodeGen/CGOpenMPRuntime.cpp
+++ clang/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -11044,259 +11044,6 @@
   return Address(Addr, Align);
 }
 
-namespace {
-using OMPContextSelectorData =
-    OpenMPCtxSelectorData<ArrayRef<StringRef>, llvm::APSInt>;
-using CompleteOMPContextSelectorData = SmallVector<OMPContextSelectorData, 4>;
-} // anonymous namespace
-
-/// Checks current context and returns true if it matches the context selector.
-template <OpenMPContextSelectorSetKind CtxSet, OpenMPContextSelectorKind Ctx,
-          typename... Arguments>
-static bool checkContext(const OMPContextSelectorData &Data,
-                         Arguments... Params) {
-  assert(Data.CtxSet != OMP_CTX_SET_unknown && Data.Ctx != OMP_CTX_unknown &&
-         "Unknown context selector or context selector set.");
-  return false;
-}
-
-/// Checks for implementation={vendor(<vendor>)} context selector.
-/// \returns true iff <vendor>="llvm", false otherwise.
-template <>
-bool checkContext<OMP_CTX_SET_implementation, OMP_CTX_vendor>(
-    const OMPContextSelectorData &Data) {
-  return llvm::all_of(Data.Names,
-                      [](StringRef S) { return !S.compare_lower("llvm"); });
-}
-
-/// Checks for device={kind(<kind>)} context selector.
-/// \returns true if <kind>="host" and compilation is for host.
-/// true if <kind>="nohost" and compilation is for device.
-/// true if <kind>="cpu" and compilation is for Arm, X86 or PPC CPU.
-/// true if <kind>="gpu" and compilation is for NVPTX or AMDGCN.
-/// false otherwise.
-template <>
-bool checkContext<OMP_CTX_SET_device, OMP_CTX_kind, CodeGenModule &>(
-    const OMPContextSelectorData &Data, CodeGenModule &CGM) {
-  for (StringRef Name : Data.Names) {
-    if (!Name.compare_lower("host")) {
-      if (CGM.getLangOpts().OpenMPIsDevice)
-        return false;
-      continue;
-    }
-    if (!Name.compare_lower("nohost")) {
-      if (!CGM.getLangOpts().OpenMPIsDevice)
-        return false;
-      continue;
-    }
-    switch (CGM.getTriple().getArch()) {
-    case llvm::Triple::arm:
-    case llvm::Triple::armeb:
-    case llvm::Triple::aarch64:
-    case llvm::Triple::aarch64_be:
-    case llvm::Triple::aarch64_32:
-    case llvm::Triple::ppc:
-    case llvm::Triple::ppc64:
-    case llvm::Triple::ppc64le:
-    case llvm::Triple::x86:
-    case llvm::Triple::x86_64:
-      if (Name.compare_lower("cpu"))
-        return false;
-      break;
-    case llvm::Triple::amdgcn:
-    case llvm::Triple::nvptx:
-    case llvm::Triple::nvptx64:
-      if (Name.compare_lower("gpu"))
-        return false;
-      break;
-    case llvm::Triple::UnknownArch:
-    case llvm::Triple::arc:
-    case llvm::Triple::avr:
-    case llvm::Triple::bpfel:
-    case llvm::Triple::bpfeb:
-    case llvm::Triple::hexagon:
-    case llvm::Triple::mips:
-    case llvm::Triple::mipsel:
-    case llvm::Triple::mips64:
-    case llvm::Triple::mips64el:
-    case llvm::Triple::msp430:
-    case llvm::Triple::r600:
-    case llvm::Triple::riscv32:
-    case llvm::Triple::riscv64:
-    case llvm::Triple::sparc:
-    case llvm::Triple::sparcv9:
-    case llvm::Triple::sparcel:
-    case llvm::Triple::systemz:
-    case llvm::Triple::tce:
-    case llvm::Triple::tcele:
-    case llvm::Triple::thumb:
-    case llvm::Triple::thumbeb:
-    case llvm::Triple::xcore:
-    case llvm::Triple::le32:
-    case llvm::Triple::le64:
-    case llvm::Triple::amdil:
-    case llvm::Triple::amdil64:
-    case llvm::Triple::hsail:
-    case llvm::Triple::hsail64:
-    case llvm::Triple::spir:
-    case llvm::Triple::spir64:
-    case llvm::Triple::kalimba:
-    case llvm::Triple::shave:
-    case llvm::Triple::lanai:
-    case llvm::Triple::wasm32:
-    case llvm::Triple::wasm64:
-    case llvm::Triple::renderscript32:
-    case llvm::Triple::renderscript64:
-      return false;
-    }
-  }
-  return true;
-}
-
-bool matchesContext(CodeGenModule &CGM,
-                    const CompleteOMPContextSelectorData &ContextData) {
-  for (const OMPContextSelectorData &Data : ContextData) {
-    switch (Data.Ctx) {
-    case OMP_CTX_vendor:
-      assert(Data.CtxSet == OMP_CTX_SET_implementation &&
-             "Expected implementation context selector set.");
-      if (!checkContext<OMP_CTX_SET_implementation, OMP_CTX_vendor>(Data))
-        return false;
-      break;
-    case OMP_CTX_kind:
-      assert(Data.CtxSet == OMP_CTX_SET_device &&
-             "Expected device context selector set.");
-      if (!checkContext<OMP_CTX_SET_device, OMP_CTX_kind, CodeGenModule &>(Data,
-                                                                           CGM))
-        return false;
-      break;
-    case OMP_CTX_unknown:
-      llvm_unreachable("Unknown context selector kind.");
-    }
-  }
-  return true;
-}
-
-static CompleteOMPContextSelectorData
-translateAttrToContextSelectorData(ASTContext &C,
-                                   const OMPDeclareVariantAttr *A) {
-  CompleteOMPContextSelectorData Data;
-  for (unsigned I = 0, E = A->scores_size(); I < E; ++I) {
-    Data.emplace_back();
-    auto CtxSet = static_cast<OpenMPContextSelectorSetKind>(
-        *std::next(A->ctxSelectorSets_begin(), I));
-    auto Ctx = static_cast<OpenMPContextSelectorKind>(
-        *std::next(A->ctxSelectors_begin(), I));
-    Data.back().CtxSet = CtxSet;
-    Data.back().Ctx = Ctx;
-    const Expr *Score = *std::next(A->scores_begin(), I);
-    Data.back().Score = Score->EvaluateKnownConstInt(C);
-    switch (Ctx) {
-    case OMP_CTX_vendor:
-      assert(CtxSet == OMP_CTX_SET_implementation &&
-             "Expected implementation context selector set.");
-      Data.back().Names =
-          llvm::makeArrayRef(A->implVendors_begin(), A->implVendors_end());
-      break;
-    case OMP_CTX_kind:
-      assert(CtxSet == OMP_CTX_SET_device &&
-             "Expected device context selector set.");
-      Data.back().Names =
-          llvm::makeArrayRef(A->deviceKinds_begin(), A->deviceKinds_end());
-      break;
-    case OMP_CTX_unknown:
-      llvm_unreachable("Unknown context selector kind.");
-    }
-  }
-  return Data;
-}
-
-static bool isStrictSubset(const CompleteOMPContextSelectorData &LHS,
-                           const CompleteOMPContextSelectorData &RHS) {
-  llvm::SmallDenseMap<std::pair<int, int>, llvm::StringSet<>, 4> RHSData;
-  for (const OMPContextSelectorData &D : RHS) {
-    auto &Pair = RHSData.FindAndConstruct(std::make_pair(D.CtxSet, D.Ctx));
-    Pair.getSecond().insert(D.Names.begin(), D.Names.end());
-  }
-  bool AllSetsAreEqual = true;
-  for (const OMPContextSelectorData &D : LHS) {
-    auto It = RHSData.find(std::make_pair(D.CtxSet, D.Ctx));
-    if (It == RHSData.end())
-      return false;
-    if (D.Names.size() > It->getSecond().size())
-      return false;
-    if (llvm::set_union(It->getSecond(), D.Names))
-      return false;
-    AllSetsAreEqual =
-        AllSetsAreEqual && (D.Names.size() == It->getSecond().size());
-  }
-
-  return LHS.size() != RHS.size() || !AllSetsAreEqual;
-}
-
-static bool greaterCtxScore(const CompleteOMPContextSelectorData &LHS,
-                            const CompleteOMPContextSelectorData &RHS) {
-  // Score is calculated as sum of all scores + 1.
-  llvm::APSInt LHSScore(llvm::APInt(64, 1), /*isUnsigned=*/false);
-  bool RHSIsSubsetOfLHS = isStrictSubset(RHS, LHS);
-  if (RHSIsSubsetOfLHS) {
-    LHSScore = llvm::APSInt::get(0);
-  } else {
-    for (const OMPContextSelectorData &Data : LHS) {
-      if (Data.Score.getBitWidth() > LHSScore.getBitWidth()) {
-        LHSScore = LHSScore.extend(Data.Score.getBitWidth()) + Data.Score;
-      } else if (Data.Score.getBitWidth() < LHSScore.getBitWidth()) {
-        LHSScore += Data.Score.extend(LHSScore.getBitWidth());
-      } else {
-        LHSScore += Data.Score;
-      }
-    }
-  }
-  llvm::APSInt RHSScore(llvm::APInt(64, 1), /*isUnsigned=*/false);
-  if (!RHSIsSubsetOfLHS && isStrictSubset(LHS, RHS)) {
-    RHSScore = llvm::APSInt::get(0);
-  } else {
-    for (const OMPContextSelectorData &Data : RHS) {
-      if (Data.Score.getBitWidth() > RHSScore.getBitWidth()) {
-        RHSScore = RHSScore.extend(Data.Score.getBitWidth()) + Data.Score;
-      } else if (Data.Score.getBitWidth() < RHSScore.getBitWidth()) {
-        RHSScore += Data.Score.extend(RHSScore.getBitWidth());
-      } else {
-        RHSScore += Data.Score;
-      }
-    }
-  }
-  return llvm::APSInt::compareValues(LHSScore, RHSScore) >= 0;
-}
-
-/// Finds the variant function that matches current context with its context
-/// selector.
-static const FunctionDecl *getDeclareVariantFunction(CodeGenModule &CGM,
-                                                     const FunctionDecl *FD) {
-  if (!FD->hasAttrs() || !FD->hasAttr<OMPDeclareVariantAttr>())
-    return FD;
-  // Iterate through all DeclareVariant attributes and check context selectors.
-  const OMPDeclareVariantAttr *TopMostAttr = nullptr;
-  CompleteOMPContextSelectorData TopMostData;
-  for (const auto *A : FD->specific_attrs<OMPDeclareVariantAttr>()) {
-    CompleteOMPContextSelectorData Data =
-        translateAttrToContextSelectorData(CGM.getContext(), A);
-    if (!matchesContext(CGM, Data))
-      continue;
-    // If the attribute matches the context, find the attribute with the highest
-    // score.
-    if (!TopMostAttr || !greaterCtxScore(TopMostData, Data)) {
-      TopMostAttr = A;
-      TopMostData.swap(Data);
-    }
-  }
-  if (!TopMostAttr)
-    return FD;
-  return cast<FunctionDecl>(
-      cast<DeclRefExpr>(TopMostAttr->getVariantFuncRef()->IgnoreParenImpCasts())
-          ->getDecl());
-}
-
 bool CGOpenMPRuntime::emitDeclareVariant(GlobalDecl GD, bool IsForDefinition) {
   const auto *D = cast<FunctionDecl>(GD.getDecl());
   // If the original function is defined already, use its definition.
@@ -11304,7 +11051,7 @@
   llvm::GlobalValue *Orig = CGM.GetGlobalValue(MangledName);
   if (Orig && !Orig->isDeclaration())
     return false;
-  const FunctionDecl *NewFD = getDeclareVariantFunction(CGM, D);
+  const FunctionDecl *NewFD = D->getOpenMPDeclareVariantFunction();
   // Emit original function if it does not have declare variant attribute or the
   // context does not match.
   if (NewFD == D)
Index: clang/lib/Basic/OpenMPKinds.cpp
===================================================================
--- clang/lib/Basic/OpenMPKinds.cpp
+++ clang/lib/Basic/OpenMPKinds.cpp
@@ -12,7 +12,11 @@
 
 #include "clang/Basic/OpenMPKinds.h"
 #include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/LangOptions.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SetOperations.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
 #include "llvm/ADT/StringSwitch.h"
 #include "llvm/Support/ErrorHandling.h"
 #include <cassert>
@@ -63,6 +67,194 @@
   llvm_unreachable("Invalid OpenMP context selector kind");
 }
 
+/// Checks current context and returns true if it matches the context selector.
+template <OpenMPContextSelectorSetKind CtxSet, OpenMPContextSelectorKind Ctx,
+          typename... Arguments>
+static bool checkContext(const OMPContextSelectorData &Data,
+                         Arguments... Params) {
+  assert(Data.CtxSet != OMP_CTX_SET_unknown && Data.Ctx != OMP_CTX_unknown &&
+         "Unknown context selector or context selector set.");
+  return false;
+}
+
+/// Checks for implementation={vendor(<vendor>)} context selector.
+/// \returns true iff <vendor>="llvm", false otherwise.
+template <>
+bool checkContext<OMP_CTX_SET_implementation, OMP_CTX_vendor>(
+    const OMPContextSelectorData &Data) {
+  return llvm::all_of(Data.Names,
+                      [](StringRef Name) { return !Name.compare("llvm"); });
+}
+
+/// Checks for device={kind(<kind>)} context selector.
+/// \returns true if <kind>="host" and compilation is for host.
+/// true if <kind>="nohost" and compilation is for device.
+/// true if <kind>="cpu" and compilation is for Arm, X86 or PPC CPU.
+/// true if <kind>="gpu" and compilation is for NVPTX or AMDGCN.
+/// false otherwise.
+template <>
+bool checkContext<OMP_CTX_SET_device, OMP_CTX_kind, bool, const llvm::Triple &>(
+    const OMPContextSelectorData &Data, bool IsOpenMPDevice,
+    const llvm::Triple &Triple) {
+  for (StringRef Name : Data.Names) {
+    if (!Name.compare("host")) {
+      if (IsOpenMPDevice)
+        return false;
+      continue;
+    }
+    if (!Name.compare_lower("nohost")) {
+      if (!IsOpenMPDevice)
+        return false;
+      continue;
+    }
+    switch (Triple.getArch()) {
+    case llvm::Triple::arm:
+    case llvm::Triple::armeb:
+    case llvm::Triple::aarch64:
+    case llvm::Triple::aarch64_be:
+    case llvm::Triple::aarch64_32:
+    case llvm::Triple::ppc:
+    case llvm::Triple::ppc64:
+    case llvm::Triple::ppc64le:
+    case llvm::Triple::x86:
+    case llvm::Triple::x86_64:
+      if (Name.compare_lower("cpu"))
+        return false;
+      break;
+    case llvm::Triple::amdgcn:
+    case llvm::Triple::nvptx:
+    case llvm::Triple::nvptx64:
+      if (Name.compare_lower("gpu"))
+        return false;
+      break;
+    case llvm::Triple::UnknownArch:
+    case llvm::Triple::arc:
+    case llvm::Triple::avr:
+    case llvm::Triple::bpfel:
+    case llvm::Triple::bpfeb:
+    case llvm::Triple::hexagon:
+    case llvm::Triple::mips:
+    case llvm::Triple::mipsel:
+    case llvm::Triple::mips64:
+    case llvm::Triple::mips64el:
+    case llvm::Triple::msp430:
+    case llvm::Triple::r600:
+    case llvm::Triple::riscv32:
+    case llvm::Triple::riscv64:
+    case llvm::Triple::sparc:
+    case llvm::Triple::sparcv9:
+    case llvm::Triple::sparcel:
+    case llvm::Triple::systemz:
+    case llvm::Triple::tce:
+    case llvm::Triple::tcele:
+    case llvm::Triple::thumb:
+    case llvm::Triple::thumbeb:
+    case llvm::Triple::xcore:
+    case llvm::Triple::le32:
+    case llvm::Triple::le64:
+    case llvm::Triple::amdil:
+    case llvm::Triple::amdil64:
+    case llvm::Triple::hsail:
+    case llvm::Triple::hsail64:
+    case llvm::Triple::spir:
+    case llvm::Triple::spir64:
+    case llvm::Triple::kalimba:
+    case llvm::Triple::shave:
+    case llvm::Triple::lanai:
+    case llvm::Triple::wasm32:
+    case llvm::Triple::wasm64:
+    case llvm::Triple::renderscript32:
+    case llvm::Triple::renderscript64:
+      return false;
+    }
+  }
+  return true;
+}
+
+bool clang::matchesOpenMPContext(
+    const CompleteOMPContextSelectorData &ContextData, const LangOptions &LO,
+    const llvm::Triple &Triple) {
+  for (const OMPContextSelectorData &Data : ContextData) {
+    switch (Data.Ctx) {
+    case OMP_CTX_vendor:
+      assert(Data.CtxSet == OMP_CTX_SET_implementation &&
+             "Expected implementation context selector set.");
+      if (!checkContext<OMP_CTX_SET_implementation, OMP_CTX_vendor>(Data))
+        return false;
+      break;
+    case OMP_CTX_kind:
+      assert(Data.CtxSet == OMP_CTX_SET_device &&
+             "Expected device context selector set.");
+      if (!checkContext<OMP_CTX_SET_device, OMP_CTX_kind, bool,
+                        const llvm::Triple &>(Data, LO.OpenMPIsDevice, Triple))
+        return false;
+      break;
+    case OMP_CTX_unknown:
+      llvm_unreachable("Unknown context selector kind.");
+    }
+  }
+  return true;
+}
+
+static bool isStrictSubset(const CompleteOMPContextSelectorData &LHS,
+                           const CompleteOMPContextSelectorData &RHS) {
+  llvm::SmallDenseMap<std::pair<int, int>, llvm::StringSet<>, 4> RHSData;
+  for (const OMPContextSelectorData &D : RHS) {
+    auto &Pair = RHSData.FindAndConstruct(std::make_pair(D.CtxSet, D.Ctx));
+    Pair.getSecond().insert(D.Names.begin(), D.Names.end());
+  }
+  bool AllSetsAreEqual = true;
+  for (const OMPContextSelectorData &D : LHS) {
+    auto It = RHSData.find(std::make_pair(D.CtxSet, D.Ctx));
+    if (It == RHSData.end())
+      return false;
+    if (D.Names.size() > It->getSecond().size())
+      return false;
+    if (llvm::set_union(It->getSecond(), D.Names))
+      return false;
+    AllSetsAreEqual =
+        AllSetsAreEqual && (D.Names.size() == It->getSecond().size());
+  }
+
+  return LHS.size() != RHS.size() || !AllSetsAreEqual;
+}
+
+bool clang::greaterOpenMPContextScore(
+    const CompleteOMPContextSelectorData &LHS,
+    const CompleteOMPContextSelectorData &RHS) {
+  // Score is calculated as sum of all scores + 1.
+  llvm::APSInt LHSScore(llvm::APInt(64, 1), /*isUnsigned=*/false);
+  bool RHSIsSubsetOfLHS = isStrictSubset(RHS, LHS);
+  if (RHSIsSubsetOfLHS) {
+    LHSScore = llvm::APSInt::get(0);
+  } else {
+    for (const OMPContextSelectorData &Data : LHS) {
+      if (Data.Score.getBitWidth() > LHSScore.getBitWidth()) {
+        LHSScore = LHSScore.extend(Data.Score.getBitWidth()) + Data.Score;
+      } else if (Data.Score.getBitWidth() < LHSScore.getBitWidth()) {
+        LHSScore += Data.Score.extend(LHSScore.getBitWidth());
+      } else {
+        LHSScore += Data.Score;
+      }
+    }
+  }
+  llvm::APSInt RHSScore(llvm::APInt(64, 1), /*isUnsigned=*/false);
+  if (!RHSIsSubsetOfLHS && isStrictSubset(LHS, RHS)) {
+    RHSScore = llvm::APSInt::get(0);
+  } else {
+    for (const OMPContextSelectorData &Data : RHS) {
+      if (Data.Score.getBitWidth() > RHSScore.getBitWidth()) {
+        RHSScore = RHSScore.extend(Data.Score.getBitWidth()) + Data.Score;
+      } else if (Data.Score.getBitWidth() < RHSScore.getBitWidth()) {
+        RHSScore += Data.Score.extend(RHSScore.getBitWidth());
+      } else {
+        RHSScore += Data.Score;
+      }
+    }
+  }
+  return llvm::APSInt::compareValues(LHSScore, RHSScore) >= 0;
+}
+
 OpenMPClauseKind clang::getOpenMPClauseKind(StringRef Str) {
   // 'flush' clause cannot be specified explicitly, because this is an implicit
   // clause for 'flush' directive. If the 'flush' clause is explicitly specified
Index: clang/lib/AST/Decl.cpp
===================================================================
--- clang/lib/AST/Decl.cpp
+++ clang/lib/AST/Decl.cpp
@@ -2878,6 +2878,77 @@
   return false;
 }
 
+template <typename T>
+static void
+convertTraitsToUniqueStringsVector(T &&Range,
+                                   SmallVectorImpl<StringRef> &Values) {
+  llvm::StringSet<> UniqueStrings;
+  for (const Expr *Trait : Range) {
+    const auto *SL = cast<StringLiteral>(Trait);
+    if (!UniqueStrings.insert(SL->getString()).second)
+      continue;
+    Values.push_back(SL->getString());
+  }
+}
+
+static CompleteOMPContextSelectorData
+translateAttrToContextSelectorData(ASTContext &C,
+                                   const OMPDeclareVariantAttr &A) {
+  CompleteOMPContextSelectorData Data;
+  for (unsigned I = 0, E = A.scores_size(); I < E; ++I) {
+    auto CtxSet = static_cast<OpenMPContextSelectorSetKind>(
+        *std::next(A.ctxSelectorSets_begin(), I));
+    auto Ctx = static_cast<OpenMPContextSelectorKind>(
+        *std::next(A.ctxSelectors_begin(), I));
+    const Expr *Score = *std::next(A.scores_begin(), I);
+    SmallVector<StringRef, 8> Values;
+    switch (Ctx) {
+    case OMP_CTX_vendor:
+      assert(CtxSet == OMP_CTX_SET_implementation &&
+             "Expected implementation context selector set.");
+      convertTraitsToUniqueStringsVector(A.implVendors(), Values);
+      break;
+    case OMP_CTX_kind:
+      assert(CtxSet == OMP_CTX_SET_device &&
+             "Expected device context selector set.");
+      convertTraitsToUniqueStringsVector(A.deviceKinds(), Values);
+      break;
+    case OMP_CTX_unknown:
+      llvm_unreachable("Unknown context selector kind.");
+    }
+    Data.emplace_back(CtxSet, Ctx, Score->EvaluateKnownConstInt(C), Values);
+  }
+  return Data;
+}
+
+FunctionDecl *FunctionDecl::getOpenMPDeclareVariantFunction() {
+  FunctionDecl *FD = this;
+  if (!FD->hasAttrs() || !FD->hasAttr<OMPDeclareVariantAttr>())
+    return FD;
+  // Iterate through all DeclareVariant attributes and check context selectors.
+  const OMPDeclareVariantAttr *TopMostAttr = nullptr;
+  CompleteOMPContextSelectorData BestData;
+  for (const auto *A : FD->specific_attrs<OMPDeclareVariantAttr>()) {
+    CompleteOMPContextSelectorData Data =
+        translateAttrToContextSelectorData(getASTContext(), *A);
+    // Check if the attribute does not match the context.
+    if (!matchesOpenMPContext(Data, getASTContext().getLangOpts(),
+                              getASTContext().getTargetInfo().getTriple()))
+      continue;
+    // If the attribute matches the context, find the attribute with the highest
+    // score.
+    if (!TopMostAttr || !greaterOpenMPContextScore(BestData, Data)) {
+      TopMostAttr = A;
+      BestData.swap(Data);
+    }
+  }
+  if (!TopMostAttr)
+    return FD;
+  return cast<FunctionDecl>(
+      cast<DeclRefExpr>(TopMostAttr->getVariantFuncRef()->IgnoreParenImpCasts())
+          ->getDecl());
+}
+
 Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const {
   if (!hasBody(Definition))
     return nullptr;
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -9434,7 +9434,7 @@
   /// Struct to store the context selectors info for declare variant directive.
   using OMPCtxStringType = SmallString<8>;
   using OMPCtxSelectorData =
-      OpenMPCtxSelectorData<SmallVector<OMPCtxStringType, 4>, ExprResult>;
+      OpenMPCtxSelectorData<SmallVector<ExprResult, 4>, ExprResult>;
 
   /// Checks if the variant/multiversion functions are compatible.
   bool areMultiversionVariantFunctionsCompatible(
@@ -9445,6 +9445,9 @@
       const PartialDiagnosticAt &DiffDiagIDAt, bool TemplatesSupported,
       bool ConstexprSupported, bool CLinkageMayDiffer);
 
+  /// Builds StringLiteral out of the specified trait name.
+  ExprResult ActOnOpenMPTraitId(SourceLocation Loc, StringRef TraitName);
+
   /// Function tries to capture lambda's captured variables in the OpenMP region
   /// before the original lambda is captured.
   void tryCaptureOpenMPLambdas(ValueDecl *V);
Index: clang/include/clang/Basic/OpenMPKinds.h
===================================================================
--- clang/include/clang/Basic/OpenMPKinds.h
+++ clang/include/clang/Basic/OpenMPKinds.h
@@ -14,10 +14,17 @@
 #ifndef LLVM_CLANG_BASIC_OPENMPKINDS_H
 #define LLVM_CLANG_BASIC_OPENMPKINDS_H
 
+#include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Frontend/OpenMP/OMPConstants.h"
 
+namespace llvm {
+class Triple;
+} // namespace llvm
+
 namespace clang {
+class LangOptions;
 
 /// OpenMP context selector sets.
 enum OpenMPContextSelectorSetKind {
@@ -58,6 +65,22 @@
         Names(Names.begin(), Names.end()) {}
 };
 
+/// Data types for handling context selectors.
+using OMPContextSelectorData =
+    OpenMPCtxSelectorData<llvm::SmallVector<llvm::StringRef, 4>, llvm::APSInt>;
+using CompleteOMPContextSelectorData =
+    llvm::SmallVector<OMPContextSelectorData, 4>;
+
+/// Analyzes current context and returns true if it matches specified set of
+/// context traits, false otherwise.
+bool matchesOpenMPContext(const CompleteOMPContextSelectorData &ContextData,
+                          const LangOptions &LO, const llvm::Triple &Triple);
+
+/// Compares two context selector sets and returns true if the score of the \p
+/// LHS is greater or equal than the scoe of \p RHS.
+bool greaterOpenMPContextScore(const CompleteOMPContextSelectorData &LHS,
+                               const CompleteOMPContextSelectorData &RHS);
+
 /// OpenMP directives.
 using OpenMPDirectiveKind = llvm::omp::Directive;
 
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -9718,6 +9718,18 @@
 def note_omp_marked_declare_variant_here : Note<"marked as 'declare variant' here">;
 def err_omp_one_defaultmap_each_category: Error<
   "at most one defaultmap clause for each variable-category can appear on the directive">;
+def err_omp_trait_not_string : Error<
+  "trait expression must have a string type, not %0">;
+def note_omp_trait_conversion_here : Note<
+  "conversion to a string type %0 declared here">;
+def err_omp_trait_ambiguous_conversion : Error<
+  "ambiguous conversion from type %0 to a string type">;
+def err_omp_trait_not_constant_string : Error<
+  "trait expression must be a constant string expression">;
+def warn_omp_wrong_device_kind_trait: Warning<
+  "unknown '%0' device kind trait in the 'device' context selector "
+  "set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga', set "
+  "ignored">, InGroup<SourceUsesOpenMP>;
 } // end of OpenMP category
 
 let CategoryName = "Related Result Type Issue" in {
Index: clang/include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticParseKinds.td
+++ clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1218,8 +1218,6 @@
 def warn_omp_declare_variant_cs_name_expected : Warning<
   "unknown context selector in '%0' context selector set of 'omp declare variant' directive, ignored">,
   InGroup<OpenMPClauses>;
-def err_omp_declare_variant_item_expected : Error<
-  "expected %0 in '%1' context selector of '%2' selector set of 'omp declare variant' directive">;
 def err_omp_declare_variant_ctx_set_mutiple_use : Error<
   "context selector set '%0' is used already in the same 'omp declare variant' directive">;
 def note_omp_declare_variant_ctx_set_used_here : Note<
@@ -1232,9 +1230,8 @@
 def warn_omp_more_one_device_type_clause : Warning<
   "more than one 'device_type' clause is specified">,
   InGroup<OpenMPClauses>;
-def err_omp_wrong_device_kind_trait : Error<
-  "unknown '%0' device kind trait in the 'device' context selector set, expected"
-  " one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'">;
+def note_omp_expected_context_selector_trait_string : Note<
+  "expected context trait string expression or identifier in '%0' context selector">;
 
 // Pragma loop support.
 def err_pragma_loop_missing_argument : Error<
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -3318,8 +3318,8 @@
     VariadicExprArgument<"Scores">,
     VariadicUnsignedArgument<"CtxSelectorSets">,
     VariadicUnsignedArgument<"CtxSelectors">,
-    VariadicStringArgument<"ImplVendors">,
-    VariadicStringArgument<"DeviceKinds">
+    VariadicExprArgument<"ImplVendors">,
+    VariadicExprArgument<"DeviceKinds">
   ];
   let AdditionalMembers = [{
     void printScore(raw_ostream & OS, const PrintingPolicy &Policy, unsigned I) const {
@@ -3373,9 +3373,11 @@
             OS << "vendor(";
             printScore(OS, Policy, K);
             if (implVendors_size() > 0) {
-              OS << *implVendors(). begin();
-              for (StringRef VendorName : llvm::drop_begin(implVendors(), 1))
-                OS << ", " << VendorName;
+              (*implVendors().begin())->printPretty(OS, nullptr, Policy);
+              for (const Expr *VE : llvm::drop_begin(implVendors(), 1)) {
+                OS << ", ";
+                VE->printPretty(OS, nullptr, Policy);
+              }
             }
             OS << ")";
             break;
@@ -3384,9 +3386,11 @@
                    "Expected device context selector set.");
             OS << "kind(";
             if (deviceKinds_size() > 0) {
-              OS << *deviceKinds().begin();
-              for (StringRef KindName : llvm::drop_begin(deviceKinds(), 1))
-                OS << ", " << KindName;
+              (*deviceKinds().begin())->printPretty(OS, nullptr, Policy);
+              for (const Expr *KE : llvm::drop_begin(deviceKinds(), 1)) {
+                OS << ", ";
+                KE->printPretty(OS, nullptr, Policy);
+              }
             }
             OS << ")";
             break;
Index: clang/include/clang/AST/Decl.h
===================================================================
--- clang/include/clang/AST/Decl.h
+++ clang/include/clang/AST/Decl.h
@@ -2052,6 +2052,13 @@
     return const_cast<FunctionDecl *>(this)->getDefinition();
   }
 
+  /// Gets matching OpenMP variant function for the associated declare variant
+  /// attributes.
+  FunctionDecl *getOpenMPDeclareVariantFunction();
+  const FunctionDecl *getOpenMPDeclareVariantFunction() const {
+    return const_cast<FunctionDecl *>(this)->getOpenMPDeclareVariantFunction();
+  }
+
   /// Retrieve the body (definition) of the function. The function body might be
   /// in any of the (re-)declarations of this function. The variant that accepts
   /// a FunctionDecl pointer will set that function declaration to the actual
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to