diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index a2ff381e0c1..70c0e1828ca 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -24016,16 +24016,6 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
     }
 }
 
-static const char *const omp_construct_selectors[] = {
-  "simd", "target", "teams", "parallel", "for", NULL };
-static const char *const omp_device_selectors[] = {
-  "kind", "isa", "arch", NULL };
-static const char *const omp_implementation_selectors[] = {
-  "vendor", "extension", "atomic_default_mem_order", "unified_address",
-  "unified_shared_memory", "dynamic_allocators", "reverse_offload", NULL };
-static const char *const omp_user_selectors[] = {
-  "condition", NULL };
-
 /* OpenMP 5.0:
 
    trait-selector:
@@ -24038,7 +24028,8 @@ static const char *const omp_user_selectors[] = {
    trait-selector-set SET.  */
 
 static tree
-c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
+c_parser_omp_context_selector (c_parser *parser, enum omp_tss_code set,
+			       tree parms)
 {
   tree ret = NULL_TREE;
   do
@@ -24052,80 +24043,52 @@ c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
 	  c_parser_error (parser, "expected trait selector name");
 	  return error_mark_node;
 	}
+      enum omp_ts_code sel
+	= omp_lookup_ts_code (set, IDENTIFIER_POINTER (selector));
 
-      tree properties = NULL_TREE;
-      tree scoreval = NULL_TREE;
-      const char *const *selectors = NULL;
-      bool allow_score = true;
-      bool allow_user = false;
-      int property_limit = 0;
-      enum { CTX_PROPERTY_NONE, CTX_PROPERTY_USER, CTX_PROPERTY_NAME_LIST,
-	     CTX_PROPERTY_ID, CTX_PROPERTY_EXPR,
-	     CTX_PROPERTY_SIMD } property_kind = CTX_PROPERTY_NONE;
-      switch (IDENTIFIER_POINTER (set)[0])
-	{
-	case 'c': /* construct */
-	  selectors = omp_construct_selectors;
-	  allow_score = false;
-	  property_limit = 1;
-	  property_kind = CTX_PROPERTY_SIMD;
-	  break;
-	case 'd': /* device */
-	  selectors = omp_device_selectors;
-	  allow_score = false;
-	  allow_user = true;
-	  property_limit = 3;
-	  property_kind = CTX_PROPERTY_NAME_LIST;
-	  break;
-	case 'i': /* implementation */
-	  selectors = omp_implementation_selectors;
-	  allow_user = true;
-	  property_limit = 3;
-	  property_kind = CTX_PROPERTY_NAME_LIST;
-	  break;
-	case 'u': /* user */
-	  selectors = omp_user_selectors;
-	  property_limit = 1;
-	  property_kind = CTX_PROPERTY_EXPR;
-	  break;
-	default:
-	  gcc_unreachable ();
-	}
-      for (int i = 0; ; i++)
+      if (sel == OMP_TRAIT_INVALID)
 	{
-	  if (selectors[i] == NULL)
+	  /* Some trait sets permit extension traits which are supposed
+	     to be ignored if the implementation doesn't support them.
+	     GCC does not support any extension traits, and if it did, they
+	     would have their own identifiers.  */
+	  if (set == OMP_TRAIT_SET_IMPLEMENTATION
+	      || set == OMP_TRAIT_SET_DEVICE
+	      || set == OMP_TRAIT_SET_TARGET_DEVICE)
 	    {
-	      if (allow_user)
-		{
-		  property_kind = CTX_PROPERTY_USER;
-		  break;
-		}
-	      else
+	      c_parser_consume_token (parser);
+	      if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+		c_parser_balanced_token_sequence (parser);
+	      if (c_parser_next_token_is (parser, CPP_COMMA))
 		{
-		  error_at (c_parser_peek_token (parser)->location,
-			    "selector %qs not allowed for context selector "
-			    "set %qs", IDENTIFIER_POINTER (selector),
-			    IDENTIFIER_POINTER (set));
 		  c_parser_consume_token (parser);
-		  return error_mark_node;
+		  continue;
 		}
+	      else
+		break;
+	    }
+	  else
+	    {
+	      error_at (c_parser_peek_token (parser)->location,
+			"selector %qs not allowed for context selector "
+			"set %qs", IDENTIFIER_POINTER (selector),
+			omp_tss_map[set]);
+	      c_parser_consume_token (parser);
+	      return error_mark_node;
 	    }
-	  if (i == property_limit)
-	    property_kind = CTX_PROPERTY_NONE;
-	  if (strcmp (selectors[i], IDENTIFIER_POINTER (selector)) == 0)
-	    break;
 	}
-      if (property_kind == CTX_PROPERTY_NAME_LIST
-	  && IDENTIFIER_POINTER (set)[0] == 'i'
-	  && strcmp (IDENTIFIER_POINTER (selector),
-		     "atomic_default_mem_order") == 0)
-	property_kind = CTX_PROPERTY_ID;
 
       c_parser_consume_token (parser);
 
+      tree properties = NULL_TREE;
+      tree scoreval = NULL_TREE;
+      enum omp_tp_type property_kind = omp_ts_map[sel].tp_type;
+      bool allow_score = omp_ts_map[sel].allow_score;
+      tree t;
+
       if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
 	{
-	  if (property_kind == CTX_PROPERTY_NONE)
+	  if (property_kind == OMP_TRAIT_PROPERTY_NONE)
 	    {
 	      error_at (c_parser_peek_token (parser)->location,
 			"selector %qs does not accept any properties",
@@ -24168,38 +24131,7 @@ c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
 
 	  switch (property_kind)
 	    {
-	      tree t;
-	    case CTX_PROPERTY_USER:
-	      do
-		{
-		  t = c_parser_expr_no_commas (parser, NULL).value;
-		  if (TREE_CODE (t) == STRING_CST)
-		    properties = make_trait_property (NULL_TREE, t,
-						      properties);
-		  else if (t != error_mark_node)
-		    {
-		      mark_exp_read (t);
-		      t = c_fully_fold (t, false, NULL);
-		      if (!INTEGRAL_TYPE_P (TREE_TYPE (t))
-			  || !tree_fits_shwi_p (t))
-			error_at (token->location, "property must be "
-				  "constant integer expression or string "
-				  "literal");
-		      else
-			properties = make_trait_property (NULL_TREE, t,
-							  properties);
-		    }
-		  else
-		    return error_mark_node;
-
-		  if (c_parser_next_token_is (parser, CPP_COMMA))
-		    c_parser_consume_token (parser);
-		  else
-		    break;
-		}
-	      while (1);
-	      break;
-	    case CTX_PROPERTY_ID:
+	    case OMP_TRAIT_PROPERTY_ID:
 	      if (c_parser_next_token_is (parser, CPP_KEYWORD)
 		  || c_parser_next_token_is (parser, CPP_NAME))
 		{
@@ -24214,7 +24146,7 @@ c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
 		  return error_mark_node;
 		}
 	      break;
-	    case CTX_PROPERTY_NAME_LIST:
+	    case OMP_TRAIT_PROPERTY_NAME_LIST:
 	      do
 		{
 		  tree prop = OMP_TP_NAMELIST_NODE;
@@ -24244,12 +24176,14 @@ c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
 		}
 	      while (1);
 	      break;
-	    case CTX_PROPERTY_EXPR:
+	    case OMP_TRAIT_PROPERTY_EXPR:
 	      t = c_parser_expr_no_commas (parser, NULL).value;
 	      if (t != error_mark_node)
 		{
 		  mark_exp_read (t);
 		  t = c_fully_fold (t, false, NULL);
+		  /* FIXME: this is bogus, both device_num and
+		     condition selectors allow arbitrary expressions.  */
 		  if (!INTEGRAL_TYPE_P (TREE_TYPE (t))
 		      || !tree_fits_shwi_p (t))
 		    error_at (token->location, "property must be "
@@ -24261,7 +24195,9 @@ c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
 	      else
 		return error_mark_node;
 	      break;
-	    case CTX_PROPERTY_SIMD:
+	    case OMP_TRAIT_PROPERTY_CLAUSE_LIST:
+	      gcc_assert (sel == OMP_TRAIT_CONSTRUCT_SIMD);
+
 	      if (parms == NULL_TREE)
 		{
 		  error_at (token->location, "properties for %<simd%> "
@@ -24286,15 +24222,15 @@ c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
 	  parens.skip_until_found_close (parser);
 	  properties = nreverse (properties);
 	}
-      else if (property_kind == CTX_PROPERTY_NAME_LIST
-	       || property_kind == CTX_PROPERTY_ID
-	       || property_kind == CTX_PROPERTY_EXPR)
+      else if (property_kind != OMP_TRAIT_PROPERTY_NONE
+	       && property_kind != OMP_TRAIT_PROPERTY_CLAUSE_LIST
+	       && property_kind != OMP_TRAIT_PROPERTY_EXTENSION)
 	{
 	  c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>");
 	  return error_mark_node;
 	}
 
-      ret = make_trait_selector (selector, scoreval, properties, ret);
+      ret = make_trait_selector (sel, scoreval, properties, ret);
 
       if (c_parser_next_token_is (parser, CPP_COMMA))
 	c_parser_consume_token (parser);
@@ -24328,35 +24264,17 @@ c_parser_omp_context_selector_specification (c_parser *parser, tree parms)
       const char *setp = "";
       if (c_parser_next_token_is (parser, CPP_NAME))
 	setp = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
-      switch (setp[0])
-	{
-	case 'c':
-	  if (strcmp (setp, "construct") == 0)
-	    setp = NULL;
-	  break;
-	case 'd':
-	  if (strcmp (setp, "device") == 0)
-	    setp = NULL;
-	  break;
-	case 'i':
-	  if (strcmp (setp, "implementation") == 0)
-	    setp = NULL;
-	  break;
-	case 'u':
-	  if (strcmp (setp, "user") == 0)
-	    setp = NULL;
-	  break;
-	default:
-	  break;
-	}
-      if (setp)
+      enum omp_tss_code set = omp_lookup_tss_code (setp);
+
+      if (set == OMP_TRAIT_SET_INVALID)
 	{
+	  /* FIXME: hardwired list of names here is incomplete and
+	     liable to bit-rot.  */
 	  c_parser_error (parser, "expected %<construct%>, %<device%>, "
 				  "%<implementation%> or %<user%>");
 	  return error_mark_node;
 	}
 
-      tree set = c_parser_peek_token (parser)->value;
       c_parser_consume_token (parser);
 
       if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
@@ -24453,7 +24371,8 @@ c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms)
 	  error_at (token->location, "variant %qD is not a function", variant);
 	  variant = error_mark_node;
 	}
-      else if (omp_get_context_selector (ctx, "construct", "simd") == NULL_TREE
+      else if (!omp_get_context_selector (ctx, OMP_TRAIT_SET_CONSTRUCT,
+					  OMP_TRAIT_CONSTRUCT_SIMD)
 	       && !comptypes (TREE_TYPE (fndecl), TREE_TYPE (variant)))
 	{
 	  error_at (token->location, "variant %qD and base %qD have "
@@ -24474,7 +24393,8 @@ c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms)
       if (variant != error_mark_node)
 	{
 	  C_DECL_USED (variant) = 1;
-	  tree construct = omp_get_context_selector (ctx, "construct", NULL);
+	  tree construct
+	    = omp_get_context_selector_list (ctx, OMP_TRAIT_SET_CONSTRUCT);
 	  omp_mark_declare_variant (match_loc, variant, construct);
 	  if (omp_context_selector_matches (ctx))
 	    {
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index b8e1098d482..70693af9cc8 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -8042,12 +8042,13 @@ omp_declare_variant_finalize_one (tree decl, tree attr)
     }
 
   tree ctx = TREE_VALUE (TREE_VALUE (attr));
-  tree simd = omp_get_context_selector (ctx, "construct", "simd");
+  tree simd = omp_get_context_selector (ctx, OMP_TRAIT_SET_CONSTRUCT,
+					OMP_TRAIT_CONSTRUCT_SIMD);
   if (simd)
     {
       TREE_VALUE (simd)
 	= c_omp_declare_simd_clauses_to_numbers (DECL_ARGUMENTS (decl),
-						 TREE_VALUE (simd));
+						 OMP_TS_PROPERTIES (simd));
       /* FIXME, adjusting simd args unimplemented.  */
       return true;
     }
@@ -8140,7 +8141,8 @@ omp_declare_variant_finalize_one (tree decl, tree attr)
 	}
       else
 	{
-	  tree construct = omp_get_context_selector (ctx, "construct", NULL);
+	  tree construct
+	    = omp_get_context_selector_list (ctx, OMP_TRAIT_SET_CONSTRUCT);
 	  omp_mark_declare_variant (match_loc, variant, construct);
 	  if (!omp_context_selector_matches (ctx))
 	    return true;
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 9030365644d..6f5514d40c9 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -47255,16 +47255,6 @@ cp_parser_omp_declare_simd (cp_parser *parser, cp_token *pragma_tok,
     }
 }
 
-static const char *const omp_construct_selectors[] = {
-  "simd", "target", "teams", "parallel", "for", NULL };
-static const char *const omp_device_selectors[] = {
-  "kind", "isa", "arch", NULL };
-static const char *const omp_implementation_selectors[] = {
-  "vendor", "extension", "atomic_default_mem_order", "unified_address",
-  "unified_shared_memory", "dynamic_allocators", "reverse_offload", NULL };
-static const char *const omp_user_selectors[] = {
-  "condition", NULL };
-
 /* OpenMP 5.0:
 
    trait-selector:
@@ -47277,7 +47267,8 @@ static const char *const omp_user_selectors[] = {
    trait-selector-set SET.  */
 
 static tree
-cp_parser_omp_context_selector (cp_parser *parser, tree set, bool has_parms_p)
+cp_parser_omp_context_selector (cp_parser *parser, enum omp_tss_code set,
+				bool has_parms_p)
 {
   tree ret = NULL_TREE;
   do
@@ -47292,78 +47283,53 @@ cp_parser_omp_context_selector (cp_parser *parser, tree set, bool has_parms_p)
 	  return error_mark_node;
 	}
 
-      tree properties = NULL_TREE;
-      tree scoreval = NULL_TREE;
-      const char *const *selectors = NULL;
-      bool allow_score = true;
-      bool allow_user = false;
-      int property_limit = 0;
-      enum { CTX_PROPERTY_NONE, CTX_PROPERTY_USER, CTX_PROPERTY_NAME_LIST,
-	     CTX_PROPERTY_ID, CTX_PROPERTY_EXPR,
-	     CTX_PROPERTY_SIMD } property_kind = CTX_PROPERTY_NONE;
-      switch (IDENTIFIER_POINTER (set)[0])
-	{
-	case 'c': /* construct */
-	  selectors = omp_construct_selectors;
-	  allow_score = false;
-	  property_limit = 1;
-	  property_kind = CTX_PROPERTY_SIMD;
-	  break;
-	case 'd': /* device */
-	  selectors = omp_device_selectors;
-	  allow_score = false;
-	  allow_user = true;
-	  property_limit = 3;
-	  property_kind = CTX_PROPERTY_NAME_LIST;
-	  break;
-	case 'i': /* implementation */
-	  selectors = omp_implementation_selectors;
-	  allow_user = true;
-	  property_limit = 3;
-	  property_kind = CTX_PROPERTY_NAME_LIST;
-	  break;
-	case 'u': /* user */
-	  selectors = omp_user_selectors;
-	  property_limit = 1;
-	  property_kind = CTX_PROPERTY_EXPR;
-	  break;
-	default:
-	  gcc_unreachable ();
-	}
-      for (int i = 0; ; i++)
+      enum omp_ts_code sel
+	= omp_lookup_ts_code (set, IDENTIFIER_POINTER (selector));
+
+      if (sel == OMP_TRAIT_INVALID)
 	{
-	  if (selectors[i] == NULL)
+	  /* Some trait sets permit extension traits which are supposed
+	     to be ignored if the implementation doesn't support them.
+	     GCC does not support any extension traits, and if it did, they
+	     would have their own identifiers.  */
+	  if (set == OMP_TRAIT_SET_IMPLEMENTATION
+	      || set == OMP_TRAIT_SET_DEVICE
+	      || set == OMP_TRAIT_SET_TARGET_DEVICE)
 	    {
-	      if (allow_user)
-		{
-		  property_kind = CTX_PROPERTY_USER;
-		  break;
-		}
-	      else
+	      cp_lexer_consume_token (parser->lexer);
+	      if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
+		for (size_t n = cp_parser_skip_balanced_tokens (parser, 1) - 1;
+		     n; --n)
+		  cp_lexer_consume_token (parser->lexer);
+	      if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
 		{
-		  error ("selector %qs not allowed for context selector "
-			 "set %qs", IDENTIFIER_POINTER (selector),
-			 IDENTIFIER_POINTER (set));
 		  cp_lexer_consume_token (parser->lexer);
-		  return error_mark_node;
+		  continue;
 		}
+	      else
+		break;
+	    }
+	  else
+	    {
+	      error_at (cp_lexer_peek_token (parser->lexer)->location,
+			"selector %qs not allowed for context selector "
+			"set %qs", IDENTIFIER_POINTER (selector),
+			omp_tss_map[set]);
+	      cp_lexer_consume_token (parser->lexer);
+	      return error_mark_node;
 	    }
-	  if (i == property_limit)
-	    property_kind = CTX_PROPERTY_NONE;
-	  if (strcmp (selectors[i], IDENTIFIER_POINTER (selector)) == 0)
-	    break;
 	}
-      if (property_kind == CTX_PROPERTY_NAME_LIST
-	  && IDENTIFIER_POINTER (set)[0] == 'i'
-	  && strcmp (IDENTIFIER_POINTER (selector),
-		     "atomic_default_mem_order") == 0)
-	property_kind = CTX_PROPERTY_ID;
-
       cp_lexer_consume_token (parser->lexer);
 
+      tree properties = NULL_TREE;
+      tree scoreval = NULL_TREE;
+      enum omp_tp_type property_kind = omp_ts_map[sel].tp_type;
+      bool allow_score = omp_ts_map[sel].allow_score;
+      tree t;
+
       if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
 	{
-	  if (property_kind == CTX_PROPERTY_NONE)
+	  if (property_kind == OMP_TRAIT_PROPERTY_NONE)
 	    {
 	      error ("selector %qs does not accept any properties",
 		     IDENTIFIER_POINTER (selector));
@@ -47420,38 +47386,7 @@ cp_parser_omp_context_selector (cp_parser *parser, tree set, bool has_parms_p)
 
 	  switch (property_kind)
 	    {
-	      tree t;
-	    case CTX_PROPERTY_USER:
-	      do
-		{
-		  t = cp_parser_constant_expression (parser);
-		  if (t != error_mark_node)
-		    {
-		      t = fold_non_dependent_expr (t);
-		      if (TREE_CODE (t) == STRING_CST)
-			properties = make_trait_property (NULL_TREE, t,
-							  properties);
-		      else if (!value_dependent_expression_p (t)
-			       && (!INTEGRAL_TYPE_P (TREE_TYPE (t))
-				   || !tree_fits_shwi_p (t)))
-			error_at (token->location, "property must be "
-				  "constant integer expression or string "
-				  "literal");
-		      else
-			properties = make_trait_property (NULL_TREE, t,
-							  properties);
-		    }
-		  else
-		    return error_mark_node;
-
-		  if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
-		    cp_lexer_consume_token (parser->lexer);
-		  else
-		    break;
-		}
-	      while (1);
-	      break;
-	    case CTX_PROPERTY_ID:
+	    case OMP_TRAIT_PROPERTY_ID:
 	      if (cp_lexer_next_token_is (parser->lexer, CPP_KEYWORD)
 		  || cp_lexer_next_token_is (parser->lexer, CPP_NAME))
 		{
@@ -47466,7 +47401,7 @@ cp_parser_omp_context_selector (cp_parser *parser, tree set, bool has_parms_p)
 		  return error_mark_node;
 		}
 	      break;
-	    case CTX_PROPERTY_NAME_LIST:
+	    case OMP_TRAIT_PROPERTY_NAME_LIST:
 	      do
 		{
 		  tree prop = OMP_TP_NAMELIST_NODE;
@@ -47497,7 +47432,9 @@ cp_parser_omp_context_selector (cp_parser *parser, tree set, bool has_parms_p)
 		}
 	      while (1);
 	      break;
-	    case CTX_PROPERTY_EXPR:
+	    case OMP_TRAIT_PROPERTY_EXPR:
+	      /* FIXME: this is bogus, the expression need
+		 not be constant.  */
 	      t = cp_parser_constant_expression (parser);
 	      if (t != error_mark_node)
 		{
@@ -47514,7 +47451,9 @@ cp_parser_omp_context_selector (cp_parser *parser, tree set, bool has_parms_p)
 	      else
 		return error_mark_node;
 	      break;
-	    case CTX_PROPERTY_SIMD:
+	    case OMP_TRAIT_PROPERTY_CLAUSE_LIST:
+	      gcc_assert (sel == OMP_TRAIT_CONSTRUCT_SIMD);
+
 	      if (!has_parms_p)
 		{
 		  error_at (token->location, "properties for %<simd%> "
@@ -47536,15 +47475,15 @@ cp_parser_omp_context_selector (cp_parser *parser, tree set, bool has_parms_p)
 
 	  properties = nreverse (properties);
 	}
-      else if (property_kind == CTX_PROPERTY_NAME_LIST
-	       || property_kind == CTX_PROPERTY_ID
-	       || property_kind == CTX_PROPERTY_EXPR)
+      else if (property_kind != OMP_TRAIT_PROPERTY_NONE
+	       && property_kind != OMP_TRAIT_PROPERTY_CLAUSE_LIST
+	       && property_kind != OMP_TRAIT_PROPERTY_EXTENSION)
 	{
 	  cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN);
 	  return error_mark_node;
 	}
 
-      ret = make_trait_selector (selector, scoreval, properties, ret);
+      ret = make_trait_selector (sel, scoreval, properties, ret);
 
       if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
 	cp_lexer_consume_token (parser->lexer);
@@ -47580,35 +47519,17 @@ cp_parser_omp_context_selector_specification (cp_parser *parser,
       if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
 	setp
 	  = IDENTIFIER_POINTER (cp_lexer_peek_token (parser->lexer)->u.value);
-      switch (setp[0])
-	{
-	case 'c':
-	  if (strcmp (setp, "construct") == 0)
-	    setp = NULL;
-	  break;
-	case 'd':
-	  if (strcmp (setp, "device") == 0)
-	    setp = NULL;
-	  break;
-	case 'i':
-	  if (strcmp (setp, "implementation") == 0)
-	    setp = NULL;
-	  break;
-	case 'u':
-	  if (strcmp (setp, "user") == 0)
-	    setp = NULL;
-	  break;
-	default:
-	  break;
-	}
-      if (setp)
+      enum omp_tss_code set = omp_lookup_tss_code (setp);
+
+      if (set == OMP_TRAIT_SET_INVALID)
 	{
+	  /* FIXME: hardwired list of names here is incomplete and
+	     liable to bit-rot.  */
 	  cp_parser_error (parser, "expected %<construct%>, %<device%>, "
 				   "%<implementation%> or %<user%>");
 	  return error_mark_node;
 	}
 
-      tree set = cp_lexer_peek_token (parser->lexer)->u.value;
       cp_lexer_consume_token (parser->lexer);
 
       if (!cp_parser_require (parser, CPP_EQ, RT_EQ))
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index c3815733651..ed51a838f12 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -11841,18 +11841,20 @@ tsubst_attribute (tree t, tree *decl_p, tree args,
       tree chain = TREE_CHAIN (val);
       location_t match_loc = cp_expr_loc_or_input_loc (TREE_PURPOSE (chain));
       tree ctx = copy_list (TREE_VALUE (val));
-      tree simd = get_identifier ("simd");
-      tree condition = get_identifier ("condition");
       for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
 	{
-	  const char *set = IDENTIFIER_POINTER (OMP_TSS_ID (tss));
+	  enum omp_tss_code set = OMP_TSS_CODE (tss);
 	  tree selectors = NULL_TREE;
 	  for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts;
 	       ts = TREE_CHAIN (ts))
 	    {
 	      tree properties = NULL_TREE;
 	      tree scoreval = NULL_TREE;
-	      if (OMP_TS_ID (ts) == simd && set[0] == 'c')
+	      /* FIXME: The body of this loop should really be dispatching
+		 according to omp_ts_map[OMP_TS_CODE (TS)].tp_type instead
+		 of having hard-wired knowledge of specific selectors.  */
+	      if (OMP_TS_CODE (ts) == OMP_TRAIT_CONSTRUCT_SIMD
+		  && set == OMP_TRAIT_SET_CONSTRUCT)
 		{
 		  tree clauses = OMP_TS_PROPERTIES (ts);
 		  clauses = tsubst_omp_clauses (clauses,
@@ -11897,7 +11899,8 @@ tsubst_attribute (tree t, tree *decl_p, tree args,
 		    else if (OMP_TP_VALUE (p))
 		      {
 			bool allow_string
-			  = (OMP_TS_ID (ts) != condition || set[0] != 'u');
+			  = (OMP_TS_CODE (ts) != OMP_TRAIT_USER_CONDITION
+			     || set != OMP_TRAIT_SET_USER);
 			tree v = OMP_TP_VALUE (p);
 			if (TREE_CODE (v) == STRING_CST && allow_string)
 			  continue;
@@ -11921,7 +11924,7 @@ tsubst_attribute (tree t, tree *decl_p, tree args,
 			OMP_TP_VALUE (p) = v;
 		      }
 		}
-	      selectors = make_trait_selector (OMP_TS_ID (ts), scoreval,
+	      selectors = make_trait_selector (OMP_TS_CODE (ts), scoreval,
 					       properties, selectors);
 	    }
 	  OMP_TSS_TRAIT_SELECTORS (tss) = nreverse (selectors);
diff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc
index 60154ff3751..08e32636c9f 100644
--- a/gcc/fortran/trans-openmp.cc
+++ b/gcc/fortran/trans-openmp.cc
@@ -8208,11 +8208,34 @@ gfc_trans_omp_declare_variant (gfc_namespace *ns)
 	{
 	  tree selectors = NULL_TREE;
 	  gfc_omp_selector *os;
+	  enum omp_tss_code set
+	    = omp_lookup_tss_code (oss->trait_set_selector_name);
+	  gcc_assert (set != OMP_TRAIT_SET_INVALID);
+
 	  for (os = oss->trait_selectors; os; os = os->next)
 	    {
 	      tree scoreval = NULL_TREE;
 	      tree properties = NULL_TREE;
 	      gfc_omp_trait_property *otp;
+	      enum omp_ts_code sel;
+
+	      if (set == OMP_TRAIT_SET_CONSTRUCT
+		  && !(strcmp (os->trait_selector_name, "do")))
+		sel = OMP_TRAIT_CONSTRUCT_FOR;
+	      else
+		sel = omp_lookup_ts_code (set, os->trait_selector_name);
+
+	      /* Some trait sets permit extension traits which are supposed
+		 to be ignored if the implementation doesn't support them.
+		 GCC does not support any extension traits, and if it did,
+		 they would have their own identifiers.  */
+	      if (sel == OMP_TRAIT_INVALID
+		  && (set == OMP_TRAIT_SET_IMPLEMENTATION
+		      || set == OMP_TRAIT_SET_DEVICE
+		      || set == OMP_TRAIT_SET_TARGET_DEVICE))
+		continue;
+
+	      gcc_assert (sel != OMP_TRAIT_INVALID);
 
 	      for (otp = os->properties; otp; otp = otp->next)
 		{
@@ -8263,13 +8286,10 @@ gfc_trans_omp_declare_variant (gfc_namespace *ns)
 		  scoreval = se.expr;
 		}
 
-	      tree ts_name = get_identifier (os->trait_selector_name);
-	      selectors	= make_trait_selector (ts_name, scoreval,
+	      selectors	= make_trait_selector (sel, scoreval,
 					       properties, selectors);
 	    }
-
-	  tree tss_name = get_identifier (oss->trait_set_selector_name);
-	  set_selectors = make_trait_set_selector (tss_name, selectors,
+	  set_selectors = make_trait_set_selector (set,  selectors,
 						   set_selectors);
 	}
 
@@ -8298,8 +8318,10 @@ gfc_trans_omp_declare_variant (gfc_namespace *ns)
 			 variant_proc_name, &odv->where);
 	      variant_proc_sym = NULL;
 	    }
-	  else if (omp_get_context_selector (set_selectors, "construct",
-					     "simd") == NULL_TREE)
+	  else if (omp_get_context_selector (set_selectors,
+					     OMP_TRAIT_SET_CONSTRUCT,
+					     OMP_TRAIT_CONSTRUCT_SIMD)
+		   == NULL_TREE)
 	    {
 	      char err[256];
 	      if (!gfc_compare_interfaces (ns->proc_name, variant_proc_sym,
@@ -8316,8 +8338,9 @@ gfc_trans_omp_declare_variant (gfc_namespace *ns)
 	  if (variant_proc_sym != NULL)
 	    {
 	      gfc_set_sym_referenced (variant_proc_sym);
-	      tree construct = omp_get_context_selector (set_selectors,
-							 "construct", NULL);
+	      tree construct
+		= omp_get_context_selector_list (set_selectors,
+						 OMP_TRAIT_SET_CONSTRUCT);
 	      omp_mark_declare_variant (gfc_get_location (&odv->where),
 					gfc_get_symbol_decl (variant_proc_sym),
 					construct);
diff --git a/gcc/omp-general.cc b/gcc/omp-general.cc
index e4e3890449e..7c99b73ceec 100644
--- a/gcc/omp-general.cc
+++ b/gcc/omp-general.cc
@@ -1014,28 +1014,26 @@ omp_max_simt_vf (void)
 }
 
 /* Store the construct selectors as tree codes from last to first,
-   return their number.  */
+   return their number.  CTX is a list of trait selectors and
+   CONSTRUCTS holds the output.  */
 
 int
 omp_construct_traits_to_codes (tree ctx, enum tree_code *constructs)
 {
   int nconstructs = list_length (ctx);
   int i = nconstructs - 1;
+
+  /* Order must match the OMP_TRAIT_CONSTRUCT_* enumerators in
+     enum omp_ts_code.  */
+  static enum tree_code code_map[]
+    = { OMP_TARGET, OMP_TEAMS, OMP_PARALLEL, OMP_FOR, OMP_SIMD };
+
   for (tree ts = ctx; ts; ts = TREE_CHAIN (ts), i--)
     {
-      const char *sel = IDENTIFIER_POINTER (OMP_TS_ID (ts));
-      if (!strcmp (sel, "target"))
-	constructs[i] = OMP_TARGET;
-      else if (!strcmp (sel, "teams"))
-	constructs[i] = OMP_TEAMS;
-      else if (!strcmp (sel, "parallel"))
-	constructs[i] = OMP_PARALLEL;
-      else if (!strcmp (sel, "for") || !strcmp (sel, "do"))
-	constructs[i] = OMP_FOR;
-      else if (!strcmp (sel, "simd"))
-	constructs[i] = OMP_SIMD;
-      else
-	gcc_unreachable ();
+      enum omp_ts_code sel = OMP_TS_CODE (ts);
+      int j = (int)sel - (int)OMP_TRAIT_CONSTRUCT_TARGET;
+      gcc_assert (j >= 0 && (unsigned int) j < ARRAY_SIZE (code_map));
+      constructs[i] = code_map[j];
     }
   gcc_assert (i == -1);
   return nconstructs;
@@ -1114,6 +1112,124 @@ omp_maybe_offloaded (void)
   return false;
 }
 
+/* Lookup tables for context selectors.  */
+const char *omp_tss_map[] =
+  {
+   "construct",
+   "device",
+   "target_device",
+   "implementation",
+   "user",
+   NULL
+};
+
+/* Arrays of property candidates must be null-terminated.  */
+static const char *const kind_properties[] =
+  { "host", "nohost", "cpu", "gpu", "fpga", "any", NULL };
+static const char *const vendor_properties[] =
+  { "amd", "arm", "bsc", "cray", "fujitsu", "gnu", "ibm", "intel",
+    "llvm", "nvidia", "pgi", "ti", "unknown", NULL };
+static const char *const extension_properties[] =
+  { NULL };
+static const char *const atomic_default_mem_order_properties[] =
+  { "seq_cst", "relaxed", "acq_rel", NULL };
+
+struct omp_ts_info omp_ts_map[] =
+  {
+   { "kind",
+     (1 << OMP_TRAIT_SET_DEVICE) | (1 << OMP_TRAIT_SET_TARGET_DEVICE),
+     OMP_TRAIT_PROPERTY_NAME_LIST, false,
+     kind_properties
+   },
+   { "isa",
+     (1 << OMP_TRAIT_SET_DEVICE) | (1 << OMP_TRAIT_SET_TARGET_DEVICE),
+     OMP_TRAIT_PROPERTY_NAME_LIST, false,
+     NULL
+   },
+   { "arch",
+     (1 << OMP_TRAIT_SET_DEVICE) | (1 << OMP_TRAIT_SET_TARGET_DEVICE),
+     OMP_TRAIT_PROPERTY_NAME_LIST, false,
+     NULL
+   },
+   { "device_num",
+     (1 << OMP_TRAIT_SET_TARGET_DEVICE),
+     OMP_TRAIT_PROPERTY_EXPR, false,
+     NULL
+   },
+   { "vendor",
+     (1 << OMP_TRAIT_SET_IMPLEMENTATION),
+     OMP_TRAIT_PROPERTY_NAME_LIST, true,
+     vendor_properties,
+   },
+   { "extension",
+     (1 << OMP_TRAIT_SET_IMPLEMENTATION),
+     OMP_TRAIT_PROPERTY_NAME_LIST, true,
+     extension_properties,
+   },
+   { "atomic_default_mem_order",
+     (1 << OMP_TRAIT_SET_IMPLEMENTATION),
+     OMP_TRAIT_PROPERTY_ID, true,
+     atomic_default_mem_order_properties,
+   },
+   { "requires",
+     (1 << OMP_TRAIT_SET_IMPLEMENTATION),
+     OMP_TRAIT_PROPERTY_CLAUSE_LIST, true,
+     NULL
+   },
+   { "unified_address",
+     (1 << OMP_TRAIT_SET_IMPLEMENTATION),
+     OMP_TRAIT_PROPERTY_NONE, true,
+     NULL
+   },
+   { "unified_shared_memory",
+     (1 << OMP_TRAIT_SET_IMPLEMENTATION),
+     OMP_TRAIT_PROPERTY_NONE, true,
+     NULL
+   },
+   { "dynamic_allocators",
+     (1 << OMP_TRAIT_SET_IMPLEMENTATION),
+     OMP_TRAIT_PROPERTY_NONE, true,
+     NULL
+   },
+   { "reverse_offload",
+     (1 << OMP_TRAIT_SET_IMPLEMENTATION),
+     OMP_TRAIT_PROPERTY_NONE, true,
+     NULL
+   },
+   { "condition",
+     (1 << OMP_TRAIT_SET_USER),
+     OMP_TRAIT_PROPERTY_EXPR, true,
+     NULL
+   },
+   { "target",
+     (1 << OMP_TRAIT_SET_CONSTRUCT),
+     OMP_TRAIT_PROPERTY_NONE, false,
+     NULL
+   },
+   { "teams",
+     (1 << OMP_TRAIT_SET_CONSTRUCT),
+     OMP_TRAIT_PROPERTY_NONE, false,
+     NULL
+   },
+   { "parallel",
+     (1 << OMP_TRAIT_SET_CONSTRUCT),
+     OMP_TRAIT_PROPERTY_NONE, false,
+     NULL
+   },
+   { "for",
+     (1 << OMP_TRAIT_SET_CONSTRUCT),
+     OMP_TRAIT_PROPERTY_NONE, false,
+     NULL
+   },
+   { "simd",
+     (1 << OMP_TRAIT_SET_CONSTRUCT),
+     OMP_TRAIT_PROPERTY_CLAUSE_LIST,  false,
+     NULL
+   },
+   { NULL, 0, OMP_TRAIT_PROPERTY_NONE, false, NULL }  /* OMP_TRAIT_LAST */
+  };
+
+
 /* Return a name from PROP, a property in selectors accepting
    name lists.  */
 
@@ -1145,112 +1261,92 @@ omp_context_name_list_prop (tree prop)
 tree
 omp_check_context_selector (location_t loc, tree ctx)
 {
-  /* Each trait-set-selector-name can only be specified once.
-     There are just 4 set names.  */
-  for (tree t1 = ctx; t1; t1 = TREE_CHAIN (t1))
-    for (tree t2 = TREE_CHAIN (t1); t2; t2 = TREE_CHAIN (t2))
-      if (OMP_TSS_ID (t1) == OMP_TSS_ID (t2))
-	{
-	  error_at (loc, "selector set %qs specified more than once",
-		    IDENTIFIER_POINTER (OMP_TSS_ID (t1)));
-	  return error_mark_node;
-	}
+  bool tss_seen[OMP_TRAIT_SET_LAST], ts_seen[OMP_TRAIT_LAST];
+
+  memset (tss_seen, 0, sizeof (tss_seen));
   for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
     {
-      /* Each trait-selector-name can only be specified once.  */
-      if (list_length (OMP_TSS_TRAIT_SELECTORS (tss)) < 5)
+      enum omp_tss_code tss_code = OMP_TSS_CODE (tss);
+
+      /* Each trait-set-selector-name can only be specified once.  */
+      if (tss_seen[tss_code])
 	{
-	  for (tree ts1 = OMP_TSS_TRAIT_SELECTORS (tss); ts1;
-	       ts1 = TREE_CHAIN (ts1))
-	    for (tree ts2 = TREE_CHAIN (ts1); ts2; ts2 = TREE_CHAIN (ts2))
-	      if (OMP_TS_ID (ts1) == OMP_TS_ID (ts2))
-		{
-		  error_at (loc,
-			    "selector %qs specified more than once in set %qs",
-			    IDENTIFIER_POINTER (OMP_TS_ID (ts1)),
-			    IDENTIFIER_POINTER (OMP_TSS_ID (tss)));
-		  return error_mark_node;
-		}
+	  error_at (loc, "selector set %qs specified more than once",
+		    OMP_TSS_NAME (tss));
+	  return error_mark_node;
 	}
       else
+	tss_seen[tss_code] = true;
+
+      memset (ts_seen, 0, sizeof (ts_seen));
+      for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts; ts = TREE_CHAIN (ts))
 	{
-	  hash_set<tree> pset;
-	  for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts;
-	       ts = TREE_CHAIN (ts))
-	    if (pset.add (OMP_TS_ID (ts)))
+	  enum omp_ts_code ts_code = OMP_TS_CODE (ts);
+
+	  /* Each trait-selector-name can only be specified once.  */
+	  if (ts_seen[ts_code])
+	    {
+	      error_at (loc,
+			"selector %qs specified more than once in set %qs",
+			OMP_TS_NAME (ts),
+			OMP_TSS_NAME (tss));
+	      return error_mark_node;
+	    }
+	  else
+	    ts_seen[ts_code] = true;
+
+	  if (omp_ts_map[ts_code].valid_properties == NULL)
+	    continue;
+
+	  for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
+	    for (unsigned j = 0; ; j++)
 	      {
-		error_at (loc,
-			  "selector %qs specified more than once in set %qs",
-			  IDENTIFIER_POINTER (OMP_TS_ID (ts)),
-			  IDENTIFIER_POINTER (OMP_TSS_ID (tss)));
-		return error_mark_node;
+		const char *candidate
+		  = omp_ts_map[ts_code].valid_properties[j];
+		if (candidate == NULL)
+		  {
+		    /* We've reached the end of the candidate array.  */
+		    if (ts_code == OMP_TRAIT_IMPLEMENTATION_ADMO)
+		      /* FIXME: not sure why this is an error vs warnings
+			 for the others, + incorrect/unknown wording?  */
+		      {
+			error_at (loc,
+				  "incorrect property %qs of %qs selector",
+				  IDENTIFIER_POINTER (OMP_TP_NAME (p)),
+				  "atomic_default_mem_order");
+			return error_mark_node;
+		      }
+		    if (OMP_TP_NAME (p) == OMP_TP_NAMELIST_NODE
+			&& (TREE_CODE (OMP_TP_VALUE (p)) == STRING_CST))
+		      warning_at (loc, 0,
+				  "unknown property %qE of %qs selector",
+				  OMP_TP_VALUE (p),
+				  OMP_TS_NAME (ts));
+		    else if (OMP_TP_NAME (p) == OMP_TP_NAMELIST_NODE)
+		      warning_at (loc, 0,
+				  "unknown property %qs of %qs selector",
+				  omp_context_name_list_prop (p),
+				  OMP_TS_NAME (ts));
+		    else if (OMP_TP_NAME (p))
+		      warning_at (loc, 0,
+				  "unknown property %qs of %qs selector",
+				  IDENTIFIER_POINTER (OMP_TP_NAME (p)),
+				  OMP_TS_NAME (ts));
+		    break;
+		  }
+		else if (OMP_TP_NAME (p) == OMP_TP_NAMELIST_NODE)
+		  /* Property-list traits.  */
+		  {
+		    const char *str = omp_context_name_list_prop (p);
+		    if (str && !strcmp (str, candidate))
+		      break;
+		  }
+		else if (!strcmp (IDENTIFIER_POINTER (OMP_TP_NAME (p)),
+				  candidate))
+		  /* Identifier traits.  */
+		  break;
 	      }
 	}
-
-      static const char *const kind[] = {
-	"host", "nohost", "cpu", "gpu", "fpga", "any", NULL };
-      static const char *const vendor[] = {
-	"amd", "arm", "bsc", "cray", "fujitsu", "gnu", "ibm", "intel",
-	"llvm", "nvidia", "pgi", "ti", "unknown", NULL };
-      static const char *const extension[] = { NULL };
-      static const char *const atomic_default_mem_order[] = {
-	"seq_cst", "relaxed", "acq_rel", NULL };
-      struct known_properties { const char *set; const char *selector;
-				const char *const *props; };
-      known_properties props[] = {
-	{ "device", "kind", kind },
-	{ "implementation", "vendor", vendor },
-	{ "implementation", "extension", extension },
-	{ "implementation", "atomic_default_mem_order",
-	  atomic_default_mem_order } };
-      for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts; ts = TREE_CHAIN (ts))
-	for (unsigned i = 0; i < ARRAY_SIZE (props); i++)
-	  if (!strcmp (IDENTIFIER_POINTER (OMP_TS_ID (ts)),
-					   props[i].selector)
-	      && !strcmp (IDENTIFIER_POINTER (OMP_TSS_ID (tss)),
-					      props[i].set))
-	    for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
-	      for (unsigned j = 0; ; j++)
-		{
-		  if (props[i].props[j] == NULL)
-		    {
-		      if (props[i].props == atomic_default_mem_order)
-			{
-			  error_at (loc,
-				    "incorrect property %qs of %qs selector",
-				    IDENTIFIER_POINTER (TREE_PURPOSE (p)),
-				    "atomic_default_mem_order");
-			  return error_mark_node;
-			}
-		      else if (OMP_TP_NAME (p) == OMP_TP_NAMELIST_NODE
-			       && (TREE_CODE (OMP_TP_VALUE (p)) == STRING_CST))
-			warning_at (loc, 0,
-				    "unknown property %qE of %qs selector",
-				    OMP_TP_VALUE (p),
-				    props[i].selector);
-		      else if (OMP_TP_NAME (p) == OMP_TP_NAMELIST_NODE)
-			warning_at (loc, 0,
-				    "unknown property %qs of %qs selector",
-				    omp_context_name_list_prop (p),
-				    props[i].selector);
-		      else if (OMP_TP_NAME (p))
-			warning_at (loc, 0,
-				    "unknown property %qs of %qs selector",
-				    IDENTIFIER_POINTER (OMP_TP_NAME (p)),
-				    props[i].selector);
-		      break;
-		    }
-		  else if (OMP_TP_NAME (p) == OMP_TP_NAMELIST_NODE)
-		    /* Property-list traits.  */
-		    {
-		      const char *str = omp_context_name_list_prop (p);
-		      if (str && !strcmp (str, props[i].props[j]))
-			break;
-		    }
-		  else if (!strcmp (IDENTIFIER_POINTER (OMP_TP_NAME (p)),
-				    props[i].props[j]))
-		    break;
-		}
     }
   return ctx;
 }
@@ -1275,7 +1371,8 @@ omp_mark_declare_variant (location_t loc, tree variant, tree construct)
     }
   if ((TREE_VALUE (attr) != NULL_TREE) != (construct != NULL_TREE)
       || (construct != NULL_TREE
-	  && omp_context_selector_set_compare ("construct", TREE_VALUE (attr),
+	  && omp_context_selector_set_compare (OMP_TRAIT_SET_CONSTRUCT,
+					       TREE_VALUE (attr),
 					       construct)))
     error_at (loc, "%qD used as a variant with incompatible %<construct%> "
 		   "selector sets", variant);
@@ -1285,18 +1382,21 @@ omp_mark_declare_variant (location_t loc, tree variant, tree construct)
 /* Constructors for context selectors.  */
 
 tree
-make_trait_set_selector (tree name, tree selectors, tree chain)
+make_trait_set_selector (enum omp_tss_code code, tree selectors, tree chain)
 {
-  return tree_cons (name, selectors, chain);
+  return tree_cons (build_int_cst (integer_type_node, code),
+		    selectors, chain);
 }
 
 tree
-make_trait_selector (tree name, tree score, tree properties, tree chain)
+make_trait_selector (enum omp_ts_code code, tree score, tree properties,
+		     tree chain)
 {
   if (score == NULL_TREE)
-    return tree_cons (name, properties, chain);
+    return tree_cons (build_int_cst (integer_type_node, code),
+		      properties, chain);
   else
-    return tree_cons (name,
+    return tree_cons (build_int_cst (integer_type_node, code),
 		      tree_cons (OMP_TS_SCORE_NODE, score, properties),
 		      chain);
 }
@@ -1319,8 +1419,8 @@ omp_context_selector_matches (tree ctx)
   int ret = 1;
   for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
     {
-      char set = IDENTIFIER_POINTER (OMP_TSS_ID (tss))[0];
-      if (set == 'c')
+      enum omp_tss_code set = OMP_TSS_CODE (tss);
+      if (set == OMP_TRAIT_SET_CONSTRUCT)
 	{
 	  /* For now, ignore the construct set.  While something can be
 	     determined already during parsing, we don't know until end of TU
@@ -1335,10 +1435,12 @@ omp_context_selector_matches (tree ctx)
 	      continue;
 	    }
 
-	  enum tree_code constructs[5];
+	  tree selectors = OMP_TSS_TRAIT_SELECTORS (tss);
+	  enum tree_code *constructs
+	    = (enum tree_code *) alloca (list_length (selectors)
+					 * sizeof (enum tree_code));
 	  int nconstructs
-	    = omp_construct_traits_to_codes (OMP_TSS_TRAIT_SELECTORS (tss),
-					     constructs);
+	    = omp_construct_traits_to_codes (selectors, constructs);
 
 	  if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
 	    {
@@ -1371,11 +1473,11 @@ omp_context_selector_matches (tree ctx)
 	}
       for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts; ts = TREE_CHAIN (ts))
 	{
-	  const char *sel = IDENTIFIER_POINTER (OMP_TS_ID (ts));
-	  switch (*sel)
+	  enum omp_ts_code sel = OMP_TS_CODE (ts);
+	  switch (sel)
 	    {
-	    case 'v':
-	      if (set == 'i' && !strcmp (sel, "vendor"))
+	    case OMP_TRAIT_IMPLEMENTATION_VENDOR:
+	      if (set == OMP_TRAIT_SET_IMPLEMENTATION)
 		for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
 		  {
 		    const char *prop = omp_context_name_list_prop (p);
@@ -1386,13 +1488,13 @@ omp_context_selector_matches (tree ctx)
 		    return 0;
 		  }
 	      break;
-	    case 'e':
-	      if (set == 'i' && !strcmp (sel, "extension"))
+	    case OMP_TRAIT_IMPLEMENTATION_EXTENSION:
+	      if (set == OMP_TRAIT_SET_IMPLEMENTATION)
 		/* We don't support any extensions right now.  */
 		return 0;
 	      break;
-	    case 'a':
-	      if (set == 'i' && !strcmp (sel, "atomic_default_mem_order"))
+	    case OMP_TRAIT_IMPLEMENTATION_ADMO:
+	      if (set == OMP_TRAIT_SET_IMPLEMENTATION)
 		{
 		  if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
 		    break;
@@ -1424,7 +1526,9 @@ omp_context_selector_matches (tree ctx)
 			   && omo != OMP_MEMORY_ORDER_ACQ_REL)
 		    return 0;
 		}
-	      if (set == 'd' && !strcmp (sel, "arch"))
+	      break;
+	    case OMP_TRAIT_DEVICE_ARCH:
+	      if (set == OMP_TRAIT_SET_DEVICE)
 		for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
 		  {
 		    const char *arch = omp_context_name_list_prop (p);
@@ -1461,8 +1565,8 @@ omp_context_selector_matches (tree ctx)
 		      ret = -1;
 		  }
 	      break;
-	    case 'u':
-	      if (set == 'i' && !strcmp (sel, "unified_address"))
+	    case OMP_TRAIT_IMPLEMENTATION_UNIFIED_ADDRESS:
+	      if (set == OMP_TRAIT_SET_IMPLEMENTATION)
 		{
 		  if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
 		    break;
@@ -1474,9 +1578,10 @@ omp_context_selector_matches (tree ctx)
 		      else
 			return 0;
 		    }
-		  break;
 		}
-	      if (set == 'i' && !strcmp (sel, "unified_shared_memory"))
+	      break;
+	    case OMP_TRAIT_IMPLEMENTATION_UNIFIED_SHARED_MEMORY:
+	      if (set == OMP_TRAIT_SET_IMPLEMENTATION)
 		{
 		  if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
 		    break;
@@ -1489,11 +1594,10 @@ omp_context_selector_matches (tree ctx)
 		      else
 			return 0;
 		    }
-		  break;
 		}
 	      break;
-	    case 'd':
-	      if (set == 'i' && !strcmp (sel, "dynamic_allocators"))
+	    case OMP_TRAIT_IMPLEMENTATION_DYNAMIC_ALLOCATORS:
+	      if (set == OMP_TRAIT_SET_IMPLEMENTATION)
 		{
 		  if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
 		    break;
@@ -1506,11 +1610,10 @@ omp_context_selector_matches (tree ctx)
 		      else
 			return 0;
 		    }
-		  break;
 		}
 	      break;
-	    case 'r':
-	      if (set == 'i' && !strcmp (sel, "reverse_offload"))
+	    case OMP_TRAIT_IMPLEMENTATION_REVERSE_OFFLOAD:
+	      if (set == OMP_TRAIT_SET_IMPLEMENTATION)
 		{
 		  if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
 		    break;
@@ -1522,11 +1625,10 @@ omp_context_selector_matches (tree ctx)
 		      else
 			return 0;
 		    }
-		  break;
 		}
 	      break;
-	    case 'k':
-	      if (set == 'd' && !strcmp (sel, "kind"))
+	    case OMP_TRAIT_DEVICE_KIND:
+	      if (set == OMP_TRAIT_SET_DEVICE)
 		for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
 		  {
 		    const char *prop = omp_context_name_list_prop (p);
@@ -1586,8 +1688,8 @@ omp_context_selector_matches (tree ctx)
 		      ret = -1;
 		  }
 	      break;
-	    case 'i':
-	      if (set == 'd' && !strcmp (sel, "isa"))
+	    case OMP_TRAIT_DEVICE_ISA:
+	      if (set == OMP_TRAIT_SET_DEVICE)
 		for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
 		  {
 		    const char *isa = omp_context_name_list_prop (p);
@@ -1639,8 +1741,8 @@ omp_context_selector_matches (tree ctx)
 		      ret = -1;
 		  }
 	      break;
-	    case 'c':
-	      if (set == 'u' && !strcmp (sel, "condition"))
+	    case OMP_TRAIT_USER_CONDITION:
+	      if (set == OMP_TRAIT_SET_USER)
 		for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
 		  if (OMP_TP_NAME (p) == NULL_TREE)
 		    {
@@ -1782,7 +1884,8 @@ omp_construct_simd_compare (tree clauses1, tree clauses2)
    Unlike set names or selector names, properties can have duplicates.  */
 
 static int
-omp_context_selector_props_compare (const char *set, const char *sel,
+omp_context_selector_props_compare (enum omp_tss_code set,
+				    enum omp_ts_code sel,
 				    tree ctx1, tree ctx2)
 {
   int ret = 0;
@@ -1795,7 +1898,8 @@ omp_context_selector_props_compare (const char *set, const char *sel,
 	    {
 	      if (OMP_TP_NAME (p1) == NULL_TREE)
 		{
-		  if (set[0] == 'u' && strcmp (sel, "condition") == 0)
+		  if (set == OMP_TRAIT_SET_USER
+		      && sel == OMP_TRAIT_USER_CONDITION)
 		    {
 		      if (integer_zerop (OMP_TP_VALUE (p1))
 			  != integer_zerop (OMP_TP_VALUE (p2)))
@@ -1842,7 +1946,7 @@ omp_context_selector_props_compare (const char *set, const char *sel,
    2 if neither context is a subset of another one.  */
 
 int
-omp_context_selector_set_compare (const char *set, tree ctx1, tree ctx2)
+omp_context_selector_set_compare (enum omp_tss_code set, tree ctx1, tree ctx2)
 {
   bool swapped = false;
   int ret = 0;
@@ -1855,18 +1959,17 @@ omp_context_selector_set_compare (const char *set, tree ctx1, tree ctx2)
       std::swap (ctx1, ctx2);
       std::swap (len1, len2);
     }
-  if (set[0] == 'c')
+  if (set == OMP_TRAIT_SET_CONSTRUCT)
     {
       tree ts1;
       tree ts2 = ctx2;
-      tree simd = get_identifier ("simd");
       /* Handle construct set specially.  In this case the order
 	 of the selector matters too.  */
       for (ts1 = ctx1; ts1; ts1 = TREE_CHAIN (ts1))
-	if (OMP_TS_ID (ts1) == OMP_TS_ID (ts2))
+	if (OMP_TS_CODE (ts1) == OMP_TS_CODE (ts2))
 	  {
 	    int r = 0;
-	    if (OMP_TS_ID (ts1) == simd)
+	    if (OMP_TS_CODE (ts1) == OMP_TRAIT_CONSTRUCT_SIMD)
 	      r = omp_construct_simd_compare (OMP_TS_PROPERTIES (ts1),
 					      OMP_TS_PROPERTIES (ts2));
 	    if (r == 2 || (ret && r && (ret < 0) != (r < 0)))
@@ -1898,17 +2001,17 @@ omp_context_selector_set_compare (const char *set, tree ctx1, tree ctx2)
     }
   for (tree ts1 = ctx1; ts1; ts1 = TREE_CHAIN (ts1))
     {
+      enum omp_ts_code sel = OMP_TS_CODE (ts1);
       tree ts2;
       for (ts2 = ctx2; ts2; ts2 = TREE_CHAIN (ts2))
-	if (OMP_TS_ID (ts1) == OMP_TS_ID (ts2))
+	if (sel == OMP_TS_CODE (ts2))
 	  {
 	    tree score1 = OMP_TS_SCORE (ts1);
 	    tree score2 = OMP_TS_SCORE (ts2);
 	    if (score1 && score2 && !simple_cst_equal (score1, score2))
 	      return 2;
 
-	    const char *sel = IDENTIFIER_POINTER (OMP_TS_ID (ts1));
-	    int r = omp_context_selector_props_compare (set, sel,
+	    int r = omp_context_selector_props_compare (set, OMP_TS_CODE (ts1),
 							OMP_TS_PROPERTIES (ts1),
 							OMP_TS_PROPERTIES (ts2));
 	    if (r == 2 || (ret && r && (ret < 0) != (r < 0)))
@@ -1954,11 +2057,11 @@ omp_context_selector_compare (tree ctx1, tree ctx2)
     }
   for (tree tss1 = ctx1; tss1; tss1 = TREE_CHAIN (tss1))
     {
+      enum omp_tss_code set = OMP_TSS_CODE (tss1);
       tree tss2;
       for (tss2 = ctx2; tss2; tss2 = TREE_CHAIN (tss2))
-	if (OMP_TSS_ID (tss1) == OMP_TSS_ID (tss2))
+	if (set == OMP_TSS_CODE (tss2))
 	  {
-	    const char *set = IDENTIFIER_POINTER (OMP_TSS_ID (tss1));
 	    int r
 	      = omp_context_selector_set_compare
 		  (set, OMP_TSS_TRAIT_SELECTORS (tss1),
@@ -1985,26 +2088,51 @@ omp_context_selector_compare (tree ctx1, tree ctx2)
 }
 
 /* From context selector CTX, return trait-selector with name SEL in
-   trait-selector-set with name SET if any, or NULL_TREE if not found.
-   If SEL is NULL, return the list of trait-selectors in SET.  */
+   trait-selector-set with name SET if any, or NULL_TREE if not found.  */
+tree
+omp_get_context_selector (tree ctx, enum omp_tss_code set,
+			  enum omp_ts_code sel)
+{
+  for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
+    if (OMP_TSS_CODE (tss) == set)
+      for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts; ts = TREE_CHAIN (ts))
+	if (OMP_TS_CODE (ts) == sel)
+	  return ts;
+  return NULL_TREE;
+}
 
+/* Similar, but returns the whole trait-selector list for SET in CTX.  */
 tree
-omp_get_context_selector (tree ctx, const char *set, const char *sel)
+omp_get_context_selector_list (tree ctx, enum omp_tss_code set)
 {
-  tree setid = get_identifier (set);
-  tree selid = sel ? get_identifier (sel) : NULL_TREE;
   for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
-    if (OMP_TSS_ID (tss) == setid)
-      {
-	if (sel == NULL)
-	  return OMP_TSS_TRAIT_SELECTORS (tss);
-	for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts; ts = TREE_CHAIN (ts))
-	  if (OMP_TS_ID (ts) == selid)
-	    return ts;
-      }
+    if (OMP_TSS_CODE (tss) == set)
+      return OMP_TSS_TRAIT_SELECTORS (tss);
   return NULL_TREE;
 }
 
+/* Map string S onto a trait selector set code.  */
+enum omp_tss_code
+omp_lookup_tss_code (const char * s)
+{
+  for (int i = 0; i < OMP_TRAIT_SET_LAST; i++)
+    if (strcmp (s, omp_tss_map[i]) == 0)
+      return (enum omp_tss_code) i;
+  return OMP_TRAIT_SET_INVALID;
+}
+
+/* Map string S onto a trait selector code for set SET.  */
+enum omp_ts_code
+omp_lookup_ts_code (enum omp_tss_code set, const char *s)
+{
+  unsigned int mask = 1 << set;
+  for (int i = 0; i < OMP_TRAIT_LAST; i++)
+    if ((mask & omp_ts_map[i].tss_mask) != 0
+	&& strcmp (s, omp_ts_map[i].name) == 0)
+      return (enum omp_ts_code) i;
+  return OMP_TRAIT_INVALID;
+}
+
 /* Needs to be a GC-friendly widest_int variant, but precision is
    desirable to be the same on all targets.  */
 typedef generic_wide_int <fixed_wide_int_storage <1024> > score_wide_int;
@@ -2017,10 +2145,14 @@ typedef generic_wide_int <fixed_wide_int_storage <1024> > score_wide_int;
 static bool
 omp_context_compute_score (tree ctx, score_wide_int *score, bool declare_simd)
 {
-  tree construct = omp_get_context_selector (ctx, "construct", NULL);
-  bool has_kind = omp_get_context_selector (ctx, "device", "kind");
-  bool has_arch = omp_get_context_selector (ctx, "device", "arch");
-  bool has_isa = omp_get_context_selector (ctx, "device", "isa");
+  tree construct
+    = omp_get_context_selector_list (ctx, OMP_TRAIT_SET_CONSTRUCT);
+  bool has_kind = omp_get_context_selector (ctx, OMP_TRAIT_SET_DEVICE,
+					    OMP_TRAIT_DEVICE_KIND);
+  bool has_arch = omp_get_context_selector (ctx, OMP_TRAIT_SET_DEVICE,
+					    OMP_TRAIT_DEVICE_ARCH);
+  bool has_isa = omp_get_context_selector (ctx, OMP_TRAIT_SET_DEVICE,
+					   OMP_TRAIT_DEVICE_ISA);
   bool ret = false;
   *score = 1;
   for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
@@ -2035,15 +2167,17 @@ omp_context_compute_score (tree ctx, score_wide_int *score, bool declare_simd)
 
   if (construct || has_kind || has_arch || has_isa)
     {
-      int scores[12];
-      enum tree_code constructs[5];
-      int nconstructs = 0;
+      int nconstructs = construct ? list_length (construct) : 1;
+      enum tree_code *constructs
+	= (enum tree_code *) alloca (nconstructs * sizeof (enum tree_code));
       if (construct)
 	nconstructs = omp_construct_traits_to_codes (construct, constructs);
+      int b = declare_simd ? nconstructs + 1 : 0;
+      int *scores
+	= (int *) alloca ((b + nconstructs + 3) * sizeof (int));
       if (omp_construct_selector_matches (constructs, nconstructs, scores)
 	  == 2)
 	ret = true;
-      int b = declare_simd ? nconstructs + 1 : 0;
       if (scores[b + nconstructs] + 4U < score->get_precision ())
 	{
 	  for (int n = 0; n < nconstructs; ++n)
diff --git a/gcc/omp-general.h b/gcc/omp-general.h
index dc5e5f6ba1f..ecdd9aa9022 100644
--- a/gcc/omp-general.h
+++ b/gcc/omp-general.h
@@ -135,8 +135,83 @@ struct omp_for_data
 #define OMP_TP_VALUE(NODE) \
   TREE_VALUE (NODE)
 
-extern tree make_trait_set_selector (tree, tree, tree);
-extern tree make_trait_selector (tree, tree, tree, tree);
+/* Data structures for context selectors.  */
+
+/* Trait set selector keywords.  */
+enum omp_tss_code {
+  OMP_TRAIT_SET_CONSTRUCT,
+  OMP_TRAIT_SET_DEVICE,
+  OMP_TRAIT_SET_TARGET_DEVICE,
+  OMP_TRAIT_SET_IMPLEMENTATION,
+  OMP_TRAIT_SET_USER,
+  OMP_TRAIT_SET_LAST,
+  OMP_TRAIT_SET_INVALID = -1
+};
+
+/* Trait selector keywords.  */
+enum omp_ts_code {
+  OMP_TRAIT_DEVICE_KIND,
+  OMP_TRAIT_DEVICE_ISA,
+  OMP_TRAIT_DEVICE_ARCH,
+  OMP_TRAIT_DEVICE_NUM,
+  OMP_TRAIT_IMPLEMENTATION_VENDOR,
+  OMP_TRAIT_IMPLEMENTATION_EXTENSION,
+  OMP_TRAIT_IMPLEMENTATION_ADMO,
+  OMP_TRAIT_IMPLEMENTATION_REQUIRES,
+  OMP_TRAIT_IMPLEMENTATION_UNIFIED_ADDRESS,
+  OMP_TRAIT_IMPLEMENTATION_UNIFIED_SHARED_MEMORY,
+  OMP_TRAIT_IMPLEMENTATION_DYNAMIC_ALLOCATORS,
+  OMP_TRAIT_IMPLEMENTATION_REVERSE_OFFLOAD,
+  OMP_TRAIT_USER_CONDITION,
+  OMP_TRAIT_CONSTRUCT_TARGET,
+  OMP_TRAIT_CONSTRUCT_TEAMS,
+  OMP_TRAIT_CONSTRUCT_PARALLEL,
+  OMP_TRAIT_CONSTRUCT_FOR,
+  OMP_TRAIT_CONSTRUCT_SIMD,
+  OMP_TRAIT_LAST,
+  OMP_TRAIT_INVALID = -1
+};
+
+/* All trait property forms.  */
+enum omp_tp_type {
+  OMP_TRAIT_PROPERTY_NONE,
+  OMP_TRAIT_PROPERTY_ID,
+  OMP_TRAIT_PROPERTY_NAME_LIST,
+  OMP_TRAIT_PROPERTY_EXPR,
+  OMP_TRAIT_PROPERTY_CLAUSE_LIST,
+  OMP_TRAIT_PROPERTY_EXTENSION
+};
+
+/* Map trait set selector name keywords onto strings.  */
+extern const char *omp_tss_map [];
+
+/* Map trait selector keywords onto strings, allowed contexts, and
+   allowed property names for OMP_TRAIT_PROPERTY_NAME_LIST and
+   OMP_TRAIT_PROPERTY_ID properties.  If valid_properties is null,
+   it means that any required checking has to be done explicitly
+   somewhere instead of being driven by the table.  Otherwise it's a
+   null-terminated array of strings.  */
+struct omp_ts_info {
+  const char *name;
+  unsigned int tss_mask;
+  enum omp_tp_type tp_type;
+  bool allow_score;
+  const char * const *valid_properties;
+};
+extern struct omp_ts_info omp_ts_map[];
+
+#define OMP_TSS_CODE(t)						\
+  ((enum omp_tss_code) TREE_INT_CST_LOW (OMP_TSS_ID (t)))
+#define OMP_TSS_NAME(t)			\
+  (omp_tss_map[OMP_TSS_CODE (t)])
+
+#define OMP_TS_CODE(t)						\
+  ((enum omp_ts_code) TREE_INT_CST_LOW (OMP_TS_ID (t)))
+#define OMP_TS_NAME(t)			\
+  (omp_ts_map[OMP_TS_CODE (t)].name)
+
+extern tree make_trait_set_selector (enum omp_tss_code, tree, tree);
+extern tree make_trait_selector (enum omp_ts_code, tree, tree, tree);
 extern tree make_trait_property (tree, tree, tree);
 
 extern tree omp_find_clause (tree clauses, enum omp_clause_code kind);
@@ -158,8 +233,12 @@ extern tree omp_check_context_selector (location_t loc, tree ctx);
 extern void omp_mark_declare_variant (location_t loc, tree variant,
 				      tree construct);
 extern int omp_context_selector_matches (tree);
-extern int omp_context_selector_set_compare (const char *, tree, tree);
-extern tree omp_get_context_selector (tree, const char *, const char *);
+extern int omp_context_selector_set_compare (enum omp_tss_code, tree, tree);
+extern tree omp_get_context_selector (tree, enum omp_tss_code,
+				      enum omp_ts_code);
+extern tree omp_get_context_selector_list (tree, enum omp_tss_code);
+extern enum omp_tss_code omp_lookup_tss_code (const char *);
+extern enum omp_ts_code omp_lookup_ts_code (enum omp_tss_code, const char *);
 extern tree omp_resolve_declare_variant (tree);
 extern tree oacc_launch_pack (unsigned code, tree device, unsigned op);
 extern tree oacc_replace_fn_attrib_attr (tree attribs, tree dims);
