Hi!

The following patch attempts to implement the declare variant lookup.
As suggested by Jonathan and Jason, we have
#pragma omp declare variant(variant-func-id) clause new-line
function-declaration-or-definition
where variant-func-id is id-expression.  This is supposed to establish
a variant for the base function (declared or defined in the
function-declaration-or-definition), and the OpenMP spec says:
"The function variant is determined by base language standard name lookup rules 
([basic.lookup])
of variant-func-id with arguments that correspond to the argument types in the 
base function
declaration.
The variant-func-id and any expressions inside of the match clause are 
interpreted as if they
appeared at the scope of the trailing return type of the base function."
and
"The type of the function variant must be compatible with the type of the base 
function after the
implementation-defined transformation for its OpenMP context."
This implementation-defined transformation is only for simd (which the patch
doesn't handle yet, will need a target hook), otherwise the transformation
is a nop.

So, what this patch does is, because during parsing we still don't have
the base function decl, build attribute and stick into the attribute
everything we need later for the lookup as well as the context, and
later on, either in cp_finish_decl or finish_function or finish_struct,
it finalizes it by trying to construct a function call with dummy arguments
corresponding to the types.

What is unclear from the above wording is whether e.g. 
g++.dg/gomp/declare-variant-3.C
void T::fn25(int) can be a variant of void S::fn26(int) base function,
comptypes considers them different, but it is unclear if C++ considers them
to have different function type.  clang++ in their (also incomplete)
implementation accepts these unlike my patch, provided the base this type is
derived from the variant this type.  If it was meant to be supported, we'd
need to potentially adjust the this pointer, which can be offset by a
constant but with virtual bases even more difficult expression, plus not
sure if there is a way to call comptypes such that it would accept it
or say try to build pointer to members from the base (i.e. derived) class
and compare those?

Handling of the pragmas when processing_template_decl still needs work, will
do that as a follow-up.

Does this look reasonable to you?

2019-10-23  Jakub Jelinek  <ja...@redhat.com>

        * cp-tree.h (omp_declare_variant_finalize, build_local_temp): Declare.
        * decl.c (declare_simd_adjust_this): Add forward declaration.
        (omp_declare_variant_finalize_one, omp_declare_variant_finalize): New
        function.
        (cp_finish_decl, finish_function): Call omp_declare_variant_finalize.
        * parser.c (cp_finish_omp_declare_variant): Adjust parsing of the
        variant id-expression and propagate enough information to
        omp_declare_variant_finalize_one in the attribute so that it can
        finalize it.
        * class.c (finish_struct): Call omp_declare_variant_finalize.
        * tree.c (build_local_temp): No longer static, remove forward
        declaration.

        * c-c++-common/gomp/declare-variant-2.c: Add a test with , before
        match clause.
        * c-c++-common/gomp/declare-variant-6.c: Expect diagnostics also from
        C++ FE and adjust regexp so that it handles C++ pretty printing of
        function names.
        * g++.dg/gomp/declare-variant-1.C: New test.
        * g++.dg/gomp/declare-variant-2.C: New test.
        * g++.dg/gomp/declare-variant-3.C: New test.
        * g++.dg/gomp/declare-variant-4.C: New test.
        * g++.dg/gomp/declare-variant-5.C: New test.

--- gcc/cp/cp-tree.h.jj 2019-10-22 12:41:34.286018978 +0200
+++ gcc/cp/cp-tree.h    2019-10-23 12:21:48.075885842 +0200
@@ -6433,6 +6433,7 @@ extern tree groktypename                  (cp_decl_spec
 extern tree start_decl                         (const cp_declarator *, 
cp_decl_specifier_seq *, int, tree, tree, tree *);
 extern void start_decl_1                       (tree, bool);
 extern bool check_array_initializer            (tree, tree, tree);
+extern void omp_declare_variant_finalize       (tree, tree);
 extern void cp_finish_decl                     (tree, tree, bool, tree, int);
 extern tree lookup_decomp_type                 (tree);
 extern void cp_maybe_mangle_decomp             (tree, tree, unsigned int);
@@ -7290,6 +7291,7 @@ extern tree build_min_nt_call_vec (tree,
 extern tree build_min_non_dep_call_vec         (tree, tree, vec<tree, va_gc> 
*);
 extern vec<tree, va_gc>* vec_copy_and_insert    (vec<tree, va_gc>*, tree, 
unsigned);
 extern tree build_cplus_new                    (tree, tree, tsubst_flags_t);
+extern tree build_local_temp                   (tree);
 extern tree build_aggr_init_expr               (tree, tree);
 extern tree get_target_expr                    (tree);
 extern tree get_target_expr_sfinae             (tree, tsubst_flags_t);
--- gcc/cp/decl.c.jj    2019-10-22 16:52:23.416073416 +0200
+++ gcc/cp/decl.c       2019-10-23 12:59:25.740523462 +0200
@@ -7061,6 +7061,195 @@ decl_maybe_constant_destruction (tree de
              && type_has_constexpr_destructor (strip_array_types (type))));
 }
 
+static tree declare_simd_adjust_this (tree *, int *, void *);
+
+/* Helper function of omp_declare_variant_finalize.  Finalize one
+   "omp declare variant base" attribute.  Return true if it should be
+   removed.  */
+
+static bool
+omp_declare_variant_finalize_one (tree decl, tree attr)
+{
+  if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
+    walk_tree (&TREE_VALUE (TREE_VALUE (attr)), declare_simd_adjust_this,
+              DECL_ARGUMENTS (decl), NULL);
+
+  tree ctx = TREE_VALUE (TREE_VALUE (attr));
+  tree simd = c_omp_get_context_selector (ctx, "construct", "simd");
+  if (simd)
+    {
+      TREE_VALUE (simd)
+       = c_omp_declare_simd_clauses_to_numbers (DECL_ARGUMENTS (decl),
+                                                TREE_VALUE (simd));
+      /* FIXME, adjusting simd args unimplemented.  */
+      return true;
+    }
+
+  tree chain = TREE_CHAIN (TREE_VALUE (attr));
+  location_t varid_loc
+    = cp_expr_loc_or_input_loc (TREE_PURPOSE (TREE_CHAIN (chain)));
+  location_t match_loc = cp_expr_loc_or_input_loc (TREE_PURPOSE (chain));
+  cp_id_kind idk = (cp_id_kind) tree_to_uhwi (TREE_VALUE (chain));
+  tree variant = TREE_PURPOSE (TREE_VALUE (attr));
+
+  location_t save_loc = input_location;
+  input_location = varid_loc;
+
+  releasing_vec args;
+  tree parm = DECL_ARGUMENTS (decl);
+  if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
+    parm = DECL_CHAIN (parm);
+  for (; parm; parm = DECL_CHAIN (parm))
+    if (type_dependent_expression_p (parm))
+      vec_safe_push (args, build_constructor (TREE_TYPE (parm), NULL));
+    else if (MAYBE_CLASS_TYPE_P (TREE_TYPE (parm)))
+      vec_safe_push (args, build_local_temp (TREE_TYPE (parm)));
+    else
+      vec_safe_push (args, build_zero_cst (TREE_TYPE (parm)));
+
+  bool koenig_p = false;
+  if (idk == CP_ID_KIND_UNQUALIFIED || idk == CP_ID_KIND_TEMPLATE_ID)
+    {
+      if (identifier_p (variant)
+         /* In C++2A, we may need to perform ADL for a template
+            name.  */
+         || (TREE_CODE (variant) == TEMPLATE_ID_EXPR
+             && identifier_p (TREE_OPERAND (variant, 0))))
+       {
+         if (!args->is_empty ())
+           {
+             koenig_p = true;
+             if (!any_type_dependent_arguments_p (args))
+               variant = perform_koenig_lookup (variant, args,
+                                                tf_warning_or_error);
+           }
+         else
+           variant = unqualified_fn_lookup_error (variant);
+       }
+      else if (!args->is_empty () && is_overloaded_fn (variant))
+       {
+         tree fn = get_first_fn (variant);
+         fn = STRIP_TEMPLATE (fn);
+         if (!((TREE_CODE (fn) == USING_DECL && DECL_DEPENDENT_P (fn))
+                || DECL_FUNCTION_MEMBER_P (fn)
+                || DECL_LOCAL_FUNCTION_P (fn)))
+           {
+             koenig_p = true;
+             if (!any_type_dependent_arguments_p (args))
+               variant = perform_koenig_lookup (variant, args,
+                                                tf_warning_or_error);
+           }
+       }
+    }
+
+  if (idk == CP_ID_KIND_QUALIFIED)
+    variant = finish_call_expr (variant, &args, /*disallow_virtual=*/true,
+                               koenig_p, tf_warning_or_error);
+  else
+    variant = finish_call_expr (variant, &args, /*disallow_virtual=*/false,
+                               koenig_p, tf_warning_or_error);
+  if (variant == error_mark_node && !processing_template_decl)
+    return true;
+
+  variant = cp_get_callee_fndecl_nofold (variant);
+
+  input_location = save_loc;
+
+  if (variant)
+    {
+      const char *varname = IDENTIFIER_POINTER (DECL_NAME (variant));
+      if (!comptypes (TREE_TYPE (decl), TREE_TYPE (variant), 0))
+       {
+         error_at (varid_loc, "variant %qD and base %qD have incompatible "
+                              "types", variant, decl);
+         return true;
+       }
+      if (fndecl_built_in_p (variant)
+         && (strncmp (varname, "__builtin_", strlen ("__builtin_")) == 0
+             || strncmp (varname, "__sync_", strlen ("__sync_")) == 0
+             || strncmp (varname, "__atomic_", strlen ("__atomic_")) == 0))
+       {
+         error_at (varid_loc, "variant %qD is a built-in", variant);
+         return true;
+       }
+      else
+       {
+         tree construct = c_omp_get_context_selector (ctx, "construct", NULL);
+         c_omp_mark_declare_variant (match_loc, variant, construct);
+         if (!c_omp_context_selector_matches (ctx))
+           return true;
+         TREE_PURPOSE (TREE_VALUE (attr)) = variant;
+       }
+    }
+  else if (!processing_template_decl)
+    {
+      error_at (varid_loc, "could not find variant %qD declaration", variant);
+      return true;
+    }
+
+  return false;
+}
+
+/* Helper function, finish up "omp declare variant base" attribute
+   now that there is a DECL.  ATTR is the first "omp declare variant base"
+   attribute.  */
+
+void
+omp_declare_variant_finalize (tree decl, tree attr)
+{
+  size_t attr_len = strlen ("omp declare variant base");
+  tree *list = &DECL_ATTRIBUTES (decl);
+  bool remove_all = false;
+  location_t match_loc = DECL_SOURCE_LOCATION (decl);
+  if (TREE_CHAIN (TREE_VALUE (attr))
+      && TREE_PURPOSE (TREE_CHAIN (TREE_VALUE (attr)))
+      && EXPR_HAS_LOCATION (TREE_PURPOSE (TREE_CHAIN (TREE_VALUE (attr)))))
+    match_loc = EXPR_LOCATION (TREE_PURPOSE (TREE_CHAIN (TREE_VALUE (attr))));
+  if (DECL_CONSTRUCTOR_P (decl))
+    {
+      error_at (match_loc, "%<declare variant%> on constructor %qD", decl);
+      remove_all = true;
+    }
+  else if (DECL_DESTRUCTOR_P (decl))
+    {
+      error_at (match_loc, "%<declare variant%> on destructor %qD", decl);
+      remove_all = true;
+    }
+  else if (DECL_DEFAULTED_FN (decl))
+    {
+      error_at (match_loc, "%<declare variant%> on defaulted %qD", decl);
+      remove_all = true;
+    }
+  else if (DECL_DELETED_FN (decl))
+    {
+      error_at (match_loc, "%<declare variant%> on deleted %qD", decl);
+      remove_all = true;
+    }
+  else if (DECL_VIRTUAL_P (decl))
+    {
+      error_at (match_loc, "%<declare variant%> on virtual %qD", decl);
+      remove_all = true;
+    }
+  /* This loop is like private_lookup_attribute, except that it works
+     with tree * rather than tree, as we might want to remove the
+     attributes that are diagnosed as errorneous.  */
+  while (*list)
+    {
+      tree attr = get_attribute_name (*list);
+      size_t ident_len = IDENTIFIER_LENGTH (attr);
+      if (cmp_attribs ("omp declare variant base", attr_len,
+                      IDENTIFIER_POINTER (attr), ident_len))
+       {
+         if (remove_all || omp_declare_variant_finalize_one (decl, *list))
+           {
+             *list = TREE_CHAIN (*list);
+             continue;
+           }
+       }
+      list = &TREE_CHAIN (*list);
+    }
+}
+
 /* Finish processing of a declaration;
    install its line number and initial value.
    If the length of an array type is not known before,
@@ -7226,6 +7415,16 @@ cp_finish_decl (tree decl, tree init, bo
        }
     }
 
+  if (flag_openmp
+      && TREE_CODE (decl) == FUNCTION_DECL
+      /* #pragma omp declare variant on methods handled in finish_struct
+        instead.  */
+      && (!DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)
+         || COMPLETE_TYPE_P (DECL_CONTEXT (decl))))
+    if (tree attr = lookup_attribute ("omp declare variant base",
+                                     DECL_ATTRIBUTES (decl)))
+      omp_declare_variant_finalize (decl, attr);
+
   if (processing_template_decl)
     {
       bool type_dependent_p;
@@ -16432,6 +16631,11 @@ finish_function (bool inline_p)
   if (DECL_DECLARED_CONCEPT_P (fndecl))
     check_function_concept (fndecl);
 
+  if (flag_openmp)
+    if (tree attr = lookup_attribute ("omp declare variant base",
+                                     DECL_ATTRIBUTES (fndecl)))
+      omp_declare_variant_finalize (fndecl, attr);
+
   /* Lambda closure members are implicitly constexpr if possible.  */
   if (cxx_dialect >= cxx17
       && LAMBDA_TYPE_P (CP_DECL_CONTEXT (fndecl)))
--- gcc/cp/parser.c.jj  2019-10-22 16:48:03.409059099 +0200
+++ gcc/cp/parser.c     2019-10-23 10:09:10.396187586 +0200
@@ -40687,25 +40687,53 @@ cp_finish_omp_declare_variant (cp_parser
       return attrs;
     }
 
-  cp_token *token = cp_lexer_peek_token (parser->lexer);
+  bool template_p;
+  cp_id_kind idk = CP_ID_KIND_NONE;
+  cp_token *varid_token = cp_lexer_peek_token (parser->lexer);
+  cp_expr varid
+    = cp_parser_id_expression (parser, /*template_keyword_p=*/false,
+                              /*check_dependency_p=*/true,
+                              /*template_p=*/&template_p,
+                              /*declarator_p=*/false,
+                              /*optional_p=*/false);
+  parens.require_close (parser);
+
   tree variant;
-  tree name = cp_parser_id_expression (parser, /*template_p=*/false,
-                                      /*check_dependency_p=*/true,
-                                      /*template_p=*/NULL,
-                                      /*declarator_p=*/false,
-                                      /*optional_p=*/false);
-  if (identifier_p (name))
-    variant = cp_parser_lookup_name_simple (parser, name, token->location);
+  if (TREE_CODE (varid) == TEMPLATE_ID_EXPR
+      || TREE_CODE (varid) == TYPE_DECL
+      || varid == error_mark_node)
+    variant = varid;
+  else if (varid_token->type == CPP_NAME && varid_token->error_reported)
+    variant = NULL_TREE;
   else
-    variant = name;
-  if (variant == error_mark_node)
     {
-      cp_parser_name_lookup_error (parser, name, variant, NLE_NULL,
-                                  token->location);
-      variant = error_mark_node;
+      tree ambiguous_decls;
+      variant = cp_parser_lookup_name (parser, varid, none_type,
+                                      template_p, /*is_namespace=*/false,
+                                      /*check_dependency=*/true,
+                                      &ambiguous_decls,
+                                      varid.get_location ());
+      if (ambiguous_decls)
+       variant = NULL_TREE;
     }
-
-  parens.require_close (parser);
+  if (variant == NULL_TREE)
+    variant = error_mark_node;
+  else if (TREE_CODE (variant) != SCOPE_REF)
+    {
+      const char *error_msg;
+      variant
+       = finish_id_expression (varid, variant, parser->scope,
+                               &idk, false, true,
+                               &parser->non_integral_constant_expression_p,
+                               template_p, true, false, false, &error_msg,
+                               varid.get_location ());
+      if (error_msg)
+       cp_parser_error (parser, error_msg);
+    }
+  location_t caret_loc = get_pure_location (varid.get_location ());
+  location_t start_loc = get_start (varid_token->location);
+  location_t finish_loc = get_finish (varid.get_location ());
+  location_t varid_loc = make_location (caret_loc, start_loc, finish_loc);
 
   const char *clause = "";
   location_t match_loc = cp_lexer_peek_token (parser->lexer)->location;
@@ -40728,8 +40756,14 @@ cp_finish_omp_declare_variant (cp_parser
   ctx = c_omp_check_context_selector (match_loc, ctx);
   if (ctx != error_mark_node && variant != error_mark_node)
     {
+      tree match_loc_node = maybe_wrap_with_location (integer_zero_node,
+                                                     match_loc);
+      tree loc_node = maybe_wrap_with_location (integer_zero_node, varid_loc);
+      loc_node = tree_cons (match_loc_node,
+                           build_int_cst (integer_type_node, idk),
+                           build_tree_list (loc_node, integer_zero_node));
       attrs = tree_cons (get_identifier ("omp declare variant base"),
-                        build_tree_list (variant, ctx), attrs);
+                        tree_cons (variant, ctx, loc_node), attrs);
       if (processing_template_decl)
        ATTR_IS_DEPENDENT (attrs) = 1;
     }
--- gcc/cp/class.c.jj   2019-10-15 18:34:34.919008488 +0200
+++ gcc/cp/class.c      2019-10-23 12:55:14.933338943 +0200
@@ -7378,6 +7378,14 @@ finish_struct (tree t, tree attributes)
   else
     error ("trying to finish struct, but kicked out due to previous parse 
errors");
 
+  if (flag_openmp)
+    for (tree decl = TYPE_FIELDS (t); decl; decl = DECL_CHAIN (decl))
+      if (TREE_CODE (decl) == FUNCTION_DECL
+         && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl))
+       if (tree attr = lookup_attribute ("omp declare variant base",
+                                         DECL_ATTRIBUTES (decl)))
+         omp_declare_variant_finalize (decl, attr);
+
   if (processing_template_decl && at_function_scope_p ()
       /* Lambdas are defined by the LAMBDA_EXPR.  */
       && !LAMBDA_TYPE_P (t))
--- gcc/cp/tree.c.jj    2019-10-22 12:41:34.285018993 +0200
+++ gcc/cp/tree.c       2019-10-23 09:48:05.573467860 +0200
@@ -43,7 +43,6 @@ static hashval_t list_hash_pieces (tree,
 static tree build_target_expr (tree, tree, tsubst_flags_t);
 static tree count_trees_r (tree *, int *, void *);
 static tree verify_stmt_tree_r (tree *, int *, void *);
-static tree build_local_temp (tree);
 
 static tree handle_init_priority_attribute (tree *, tree, tree, int, bool *);
 static tree handle_abi_tag_attribute (tree *, tree, tree, int, bool *);
@@ -525,7 +524,7 @@ build_target_expr (tree decl, tree value
 /* Return an undeclared local temporary of type TYPE for use in building a
    TARGET_EXPR.  */
 
-static tree
+tree
 build_local_temp (tree type)
 {
   tree slot = build_decl (input_location,
--- gcc/testsuite/c-c++-common/gomp/declare-variant-2.c.jj      2019-10-12 
10:26:18.134940050 +0200
+++ gcc/testsuite/c-c++-common/gomp/declare-variant-2.c 2019-10-23 
10:37:46.252018237 +0200
@@ -149,3 +149,5 @@ void f72 (void);
 void f73 (void);
 #pragma omp declare variant (f1) match(construct={requires})   /* { dg-error 
"selector 'requires' not allowed for context selector set 'construct'" } */
 void f74 (void);
+#pragma omp declare variant (f1),match(construct={parallel})   /* { dg-error 
"expected 'match' before ','" } */
+void f75 (void);
--- gcc/testsuite/c-c++-common/gomp/declare-variant-6.c.jj      2019-10-12 
10:26:18.134940050 +0200
+++ gcc/testsuite/c-c++-common/gomp/declare-variant-6.c 2019-10-23 
10:32:11.274130405 +0200
@@ -7,29 +7,29 @@ double f4 (int, long, float);
 double f5 (int, long, float);
 #pragma omp declare variant (f5) match (user={condition(0)})
 double f6 (int, long, float);
-#pragma omp declare variant (f5) match 
(construct={parallel},user={condition(score(1):1)})     /* { dg-error "'f5' 
used as a variant with incompatible 'constructor' selector sets" "" { target c 
} } */
+#pragma omp declare variant (f5) match 
(construct={parallel},user={condition(score(1):1)})     /* { dg-error 
"'\[^'\n\r]*f5\[^'\n\r]*' used as a variant with incompatible 'constructor' 
selector sets" } */
 double f7 (int, long, float);
 double f8 (int, long, float);
 #pragma omp declare variant (f8) match (user={condition(0)},construct={for})
 double f9 (int, long, float);
-#pragma omp declare variant (f8) match (user={condition(1)})                   
                /* { dg-error "'f8' used as a variant with incompatible 
'constructor' selector sets" "" { target c } } */
+#pragma omp declare variant (f8) match (user={condition(1)})                   
                /* { dg-error "'\[^'\n\r]*f8\[^'\n\r]*' used as a variant with 
incompatible 'constructor' selector sets" } */
 double f10 (int, long, float);
 double f11 (int, long, float);
 #pragma omp declare variant (f11) match (construct={target,teams,parallel,for})
 double f12 (int, long, float);
 #pragma omp declare variant (f11) match 
(user={condition(score(1):1)},construct={target,teams,parallel,for})
 double f13 (int, long, float);
-#pragma omp declare variant (f11) match 
(implementation={vendor(gnu)},construct={target,teams,parallel})       /* { 
dg-error "'f11' used as a variant with incompatible 'constructor' selector 
sets" "" { target c } } */
+#pragma omp declare variant (f11) match 
(implementation={vendor(gnu)},construct={target,teams,parallel})       /* { 
dg-error "'\[^'\n\r]*f11\[^'\n\r]*' used as a variant with incompatible 
'constructor' selector sets" } */
 double f14 (int, long, float);
-#pragma omp declare variant (f11) match 
(device={kind(any)},construct={teams,parallel})                /* { dg-error 
"'f11' used as a variant with incompatible 'constructor' selector sets" "" { 
target c } } */
+#pragma omp declare variant (f11) match 
(device={kind(any)},construct={teams,parallel})                /* { dg-error 
"'\[^'\n\r]*f11\[^'\n\r]*' used as a variant with incompatible 'constructor' 
selector sets" } */
 double f15 (int, long, float);
 double f16 (int, long, float);
 #pragma omp declare variant (f16) match (construct={teams,parallel})
 double f17 (int, long, float);
-#pragma omp declare variant (f16) match(construct={teams,parallel,for})        
                        /* { dg-error "'f16' used as a variant with 
incompatible 'constructor' selector sets" "" { target c } } */
+#pragma omp declare variant (f16) match(construct={teams,parallel,for})        
                        /* { dg-error "'\[^'\n\r]*f16\[^'\n\r]*' used as a 
variant with incompatible 'constructor' selector sets" } */
 double f18 (int, long, float);
 double f19 (int, long, float);
 #pragma omp declare variant (f19) match (construct={parallel})
 double f20 (int, long, float);
-#pragma omp declare variant (f19) match 
(construct={for},implementation={vendor(gnu,llvm)})    /* { dg-error "'f19' 
used as a variant with incompatible 'constructor' selector sets" "" { target c 
} } */
+#pragma omp declare variant (f19) match 
(construct={for},implementation={vendor(gnu,llvm)})    /* { dg-error 
"'\[^'\n\r]*f19\[^'\n\r]*' used as a variant with incompatible 'constructor' 
selector sets" } */
 double f21 (int, long, float);
--- gcc/testsuite/g++.dg/gomp/declare-variant-1.C.jj    2019-10-22 
18:58:58.316075917 +0200
+++ gcc/testsuite/g++.dg/gomp/declare-variant-1.C       2019-10-22 
18:58:58.316075917 +0200
@@ -0,0 +1,28 @@
+struct S
+{
+  void foo ();
+  void bar (const S &x);
+#if __cplusplus >= 201103L
+  S &baz (const S &x);
+  S &qux (S &&x);
+#endif
+  void quux (int x);
+  #pragma omp declare variant (foo) match (user={condition(0)})        // { 
dg-error "'declare variant' on constructor" }
+  S ();
+  #pragma omp declare variant (foo) match (user={condition(0)})        // { 
dg-error "'declare variant' on destructor" }
+  ~S ();
+  #pragma omp declare variant (bar) match (user={condition(0)})        // { 
dg-error "'declare variant' on constructor" }
+  S (const S &x);
+  #pragma omp declare variant (quux) match (user={condition(0)})       // { 
dg-error "'declare variant' on constructor" }
+  S (int x);
+#if __cplusplus >= 201103L
+  #pragma omp declare variant (baz) match (user={condition(0)})        // { 
dg-error "'declare variant' on defaulted" "" { target c++11 } }
+  S &operator= (const S &x) = default;
+  #pragma omp declare variant (qux) match (user={condition(0)})        // { 
dg-error "'declare variant' on deleted" "" { target c++11 } }
+  S &operator= (S &&) = delete;
+#endif
+  int s;
+};
+void corge (int);
+#pragma omp declare variant (corge) match (user={condition(0)})
+void grault (int x);
--- gcc/testsuite/g++.dg/gomp/declare-variant-2.C.jj    2019-10-22 
18:58:58.317075902 +0200
+++ gcc/testsuite/g++.dg/gomp/declare-variant-2.C       2019-10-23 
11:27:59.606071534 +0200
@@ -0,0 +1,45 @@
+struct S { int a, b, c, d; };
+void f1 (int);
+void f1 (double);
+template <typename T> void f2 (T);
+void f3 (int);
+#pragma omp declare variant (f1) match (user={condition(false)})
+void f4 (int);
+#pragma omp declare variant (::f1) match (user={condition(false)})
+void f5 (const double);
+#pragma omp declare variant (f2) match (user={condition(false)})
+void f6 (int);
+#pragma omp declare variant (f2) match (user={condition(false)})
+void f6 (double);
+#pragma omp declare variant (f2<long>) match (user={condition(false)})
+void f6 (long);
+#pragma omp declare variant (f3) match (user={condition(false)})
+void f7 (int);
+void f8 (int);
+namespace N
+{
+  void f8 (int);
+  #pragma omp declare variant (f3) match (user={condition(false)})
+  void f9 (int);
+  #pragma omp declare variant (f8) match (user={condition(false)})
+  void f10 (int);
+}
+#pragma omp declare variant (f8) match (user={condition(false)})
+void f11 (int);
+void f12 (S, S &, int);
+#pragma omp declare variant (f12) match (implementation={vendor(gnu)})
+void f13 (const S, S &, const int);
+// Try ADL
+namespace M
+{
+  struct T { int a; };
+  void f14 (T &, int);
+}
+#pragma omp declare variant (f14) match (implementation={vendor(gnu)})
+void f15 (M::T &, int);
+struct U
+{
+  void f16 (int, long);
+  #pragma omp declare variant (f16) match (user={condition(false)})
+  void f17 (int, long);
+};
--- gcc/testsuite/g++.dg/gomp/declare-variant-3.C.jj    2019-10-22 
18:58:58.317075902 +0200
+++ gcc/testsuite/g++.dg/gomp/declare-variant-3.C       2019-10-23 
13:56:53.911144363 +0200
@@ -0,0 +1,139 @@
+// Test parsing of #pragma omp declare variant
+// { dg-do compile }
+
+int fn0 (int);
+int fn20 (int);
+
+#pragma omp declare variant (fn0) match (user={condition(0)})
+int a; // { dg-error "not immediately followed by function declaration or 
definition" }
+
+#pragma omp declare variant (fn0) match (user={condition(0)})
+int fn1 (int a), fn2 (int a);  // { dg-error "not immediately followed by a 
single function declaration or definition" }
+
+#pragma omp declare variant (fn0) match (user={condition(0)})
+int b, fn3 (int a);    // { dg-error "not immediately followed by function 
declaration or definition" }
+
+#pragma omp declare variant (fn0) match (user={condition(0)})
+int fn4 (int a), c;    // { dg-error "not immediately followed by function 
declaration or definition" }
+
+#pragma omp declare variant (fn0) match (user={condition(0)})
+extern "C"             // { dg-error "not immediately followed by function 
declaration or definition" }
+{
+  int fn5 (int a);
+}
+
+#pragma omp declare variant (fn0) match (user={condition(0)}) // { dg-error 
"not immediately followed by function declaration or definition" }
+namespace N1
+{
+  int fn6 (int a);
+}
+
+#pragma omp declare variant (fn0) match (user={condition(0)})
+struct A
+{                      // { dg-error "not immediately followed by function 
declaration or definition" }
+  int fn7 (int a);
+};
+
+#pragma omp declare variant (fn0) match (user={condition(0)})
+template <typename T>
+struct B
+{                      // { dg-error "not immediately followed by function 
declaration or definition" }
+  int fn8 (int a);
+};
+
+struct C
+{
+#pragma omp declare variant (fn0) match (user={condition(0)}) // { dg-error 
"not immediately followed by function declaration or definition" }
+  public:               // { dg-error "expected unqualified-id before" }
+    int fn9 (int a);
+};
+
+int t;
+
+#pragma omp declare variant (fn0) match (user={condition(0)})
+#pragma omp declare variant (fn20) match (implementation={vendor(unknown)})
+#pragma omp threadprivate(t)   // { dg-error "not immediately followed by 
function declaration or definition" }
+int fn10 (int a);
+
+struct D
+{
+  int d;
+  int fn11 (int a);
+  #pragma omp declare variant (fn11) match (user={condition(sizeof (e) == 
sizeof (this->e))}) // { dg-error "has no member named" }
+  template <int N>     // { dg-error "was not declared" "" { target *-*-* } 
.-1 }
+  int fn12 (int a);
+  int e;
+};
+
+#pragma omp declare variant (1 + 2) match (user={condition(0)}) // { dg-error 
"before numeric constant" }
+int fn13 (int);
+
+#pragma omp declare variant (t) match (user={condition(0)})    // { dg-error 
"'t' cannot be used as a function" }
+int fn14 (int);
+
+long fn15 (char, short);
+
+#pragma omp declare variant (fn15) match (implementation={vendor(unknown)})    
  // { dg-error "variant 'long int fn15\\\(char, short int\\\)' and base 'int 
fn16\\\(int, long long int\\\)' have incompatible types" }
+int fn16 (int, long long);
+
+#pragma omp declare variant (memcpy) match (implementation={vendor(llvm)})     
 // { dg-error "'memcpy' was not declared in this scope" }
+void *fn17 (void *, const void *, __SIZE_TYPE__);
+
+#pragma omp declare variant (__builtin_memmove) match 
(implementation={vendor(gnu)})    // { dg-error "variant '\[^'\n\r]*' is a 
built-in" }
+void *fn18 (void *, const void *, __SIZE_TYPE__);
+
+struct E { int e; };
+
+void fn19 (E, int);
+
+#pragma omp declare variant (fn19)match(user={condition(0)})   // { dg-error 
"could not convert '0' from 'int' to 'E'" }
+void fn20 (int, E);
+
+struct F { operator int () const { return 42; } int f; };
+void fn21 (int, F);
+
+#pragma omp declare variant ( fn21 ) match (user = { condition ( 1 - 1 ) } )   
// { dg-error "variant 'void fn21\\\(int, F\\\)' and base 'void fn22\\\(F, 
F\\\)' have incompatible types" }
+void fn22 (F, F);
+
+#pragma omp declare variant (fn19) match (user={condition(0)})         // { 
dg-error "could not convert '<anonymous>' from 'F' to 'E'" }
+void fn23 (F, int);
+
+void fn24 (int);
+struct U { int u; };
+struct T
+{
+  void fn25 (int);
+  int t;
+};
+struct S : public U, T
+{
+  #pragma omp declare variant (fn25) match (user={condition(true)})    // { 
dg-error "variant 'void T::fn25\\\(int\\\)' and base 'void S::fn26\\\(int\\\)' 
have incompatible types" }
+  void fn26 (int);
+  #pragma omp declare variant (fn24) match (user={condition(true)})    // { 
dg-error "variant 'void fn24\\\(int\\\)' and base 'void S::fn27\\\(int\\\)' 
have incompatible types" }
+  void fn27 (int);
+  struct s;
+};
+
+void fn30 (int) throw ();
+#pragma omp declare variant (fn30) match (user={condition(true)})      // { 
dg-error "variant 'void fn30\\\(int\\\)' and base 'void fn31\\\(int\\\)' have 
incompatible types" "" { target c++17 } }
+void fn31 (int);
+
+struct W
+{
+  int fn32 (int) const;
+  #pragma omp declare variant (fn32) match (user={condition(true)})    // { 
dg-error "variant 'int W::fn32\\\(int\\\) const' and base 'int 
W::fn33\\\(int\\\)' have incompatible types" }
+  int fn33 (int);
+  int fn34 (int) volatile;
+  #pragma omp declare variant (fn34) match (user={condition(true)})    // { 
dg-error "variant 'int W::fn34\\\(int\\\) volatile' and base 'int 
W::fn35\\\(int\\\) const volatile' have incompatible types" }
+  int fn35 (int) const volatile;                                       // { 
dg-error "passing 'const volatile W' as 'this' argument discards qualifiers" "" 
{ target *-*-* } .-1 }
+  int fn36 (int);
+  #pragma omp declare variant (fn36) match (user={condition(true)})    // { 
dg-error "variant 'int W::fn36\\\(int\\\)' and base 'int W::fn37\\\(int\\\) 
volatile' have incompatible types" }
+  int fn37 (int) volatile;                                             // { 
dg-error "passing 'volatile W' as 'this' argument discards qualifiers" "" { 
target *-*-* } .-1 }
+  int fn38 (int) throw ();
+  #pragma omp declare variant (fn38) match (user={condition(true)})    // { 
dg-error "variant 'int W::fn38\\\(int\\\)' and base 'int W::fn39\\\(int\\\)' 
have incompatible types" "" { target c++17 } }
+
+  int fn39 (int);
+  int fn40 (int);
+  #pragma omp declare variant (fn40) match (user={condition(true)})    // { 
dg-error "variant 'int W::fn40\\\(int\\\)' and base 'int W::fn41\\\(int\\\)' 
have incompatible types" "" { target c++17 } }
+  int fn41 (int) throw ();
+};
--- gcc/testsuite/g++.dg/gomp/declare-variant-4.C.jj    2019-10-23 
12:49:28.728605706 +0200
+++ gcc/testsuite/g++.dg/gomp/declare-variant-4.C       2019-10-23 
12:50:00.997114809 +0200
@@ -0,0 +1,45 @@
+struct S { int a, b, c, d; };
+void f1 (int) {}
+void f1 (double) {}
+template <typename T> void f2 (T) {}
+void f3 (int) {}
+#pragma omp declare variant (f1) match (user={condition(false)})
+void f4 (int) {}
+#pragma omp declare variant (::f1) match (user={condition(false)})
+void f5 (const double) {}
+#pragma omp declare variant (f2) match (user={condition(false)})
+void f6 (int) {}
+#pragma omp declare variant (f2) match (user={condition(false)})
+void f6 (double) {}
+#pragma omp declare variant (f2<long>) match (user={condition(false)})
+void f6 (long) {}
+#pragma omp declare variant (f3) match (user={condition(false)})
+void f7 (int) {}
+void f8 (int) {}
+namespace N
+{
+  void f8 (int) {}
+  #pragma omp declare variant (f3) match (user={condition(false)})
+  void f9 (int) {}
+  #pragma omp declare variant (f8) match (user={condition(false)})
+  void f10 (int) {}
+}
+#pragma omp declare variant (f8) match (user={condition(false)})
+void f11 (int) {}
+void f12 (S, S &, int) {}
+#pragma omp declare variant (f12) match (implementation={vendor(gnu)})
+void f13 (const S, S &, const int) {}
+// Try ADL
+namespace M
+{
+  struct T { int a; };
+  void f14 (T &, int) {}
+}
+#pragma omp declare variant (f14) match (implementation={vendor(gnu)})
+void f15 (M::T &, int) {}
+struct U
+{
+  void f16 (int, long) {}
+  #pragma omp declare variant (f16) match (user={condition(false)})
+  void f17 (int, long) {}
+};
--- gcc/testsuite/g++.dg/gomp/declare-variant-5.C.jj    2019-10-23 
12:50:32.101641623 +0200
+++ gcc/testsuite/g++.dg/gomp/declare-variant-5.C       2019-10-23 
13:59:08.726096251 +0200
@@ -0,0 +1,131 @@
+// Test parsing of #pragma omp declare variant
+// { dg-do compile }
+
+int fn0 (int) { return 0; }
+int fn20 (int) { return 0; }
+
+#pragma omp declare variant (fn0) match (user={condition(0)})
+extern "C"             // { dg-error "not immediately followed by function 
declaration or definition" }
+{
+  int fn5 (int a) { return 0; }
+}
+
+#pragma omp declare variant (fn0) match (user={condition(0)}) // { dg-error 
"not immediately followed by function declaration or definition" }
+namespace N1
+{
+  int fn6 (int a) { return 0; }
+}
+
+#pragma omp declare variant (fn0) match (user={condition(0)})
+struct A
+{                      // { dg-error "not immediately followed by function 
declaration or definition" }
+  int fn7 (int a) { return 0; }
+};
+
+#pragma omp declare variant (fn0) match (user={condition(0)})
+template <typename T>
+struct B
+{                      // { dg-error "not immediately followed by function 
declaration or definition" }
+  int fn8 (int a) { return 0; }
+};
+
+struct C
+{
+#pragma omp declare variant (fn0) match (user={condition(0)}) // { dg-error 
"not immediately followed by function declaration or definition" }
+  public:               // { dg-error "expected unqualified-id before" }
+    int fn9 (int a) { return 0; }
+};
+
+int t;
+
+#pragma omp declare variant (fn0) match (user={condition(0)})
+#pragma omp declare variant (fn20) match (implementation={vendor(unknown)})
+#pragma omp threadprivate(t)   // { dg-error "not immediately followed by 
function declaration or definition" }
+int fn10 (int a) { return 0; }
+
+struct D
+{
+  int d;
+  int fn11 (int a) { return 0; }
+  #pragma omp declare variant (fn11) match (user={condition(sizeof (e) == 
sizeof (this->e))}) // { dg-error "has no member named" }
+  template <int N>     // { dg-error "was not declared" "" { target *-*-* } 
.-1 }
+  int fn12 (int a) { return 0; }
+  int e;
+};
+
+#pragma omp declare variant (1 + 2) match (user={condition(0)}) // { dg-error 
"before numeric constant" }
+int fn13 (int) { return 0; }
+
+#pragma omp declare variant (t) match (user={condition(0)})    // { dg-error 
"'t' cannot be used as a function" }
+int fn14 (int) { return 0; }
+
+long fn15 (char, short) { return 0; }
+
+#pragma omp declare variant (fn15) match (implementation={vendor(unknown)})    
  // { dg-error "variant 'long int fn15\\\(char, short int\\\)' and base 'int 
fn16\\\(int, long long int\\\)' have incompatible types" }
+int fn16 (int, long long) { return 0; }
+
+#pragma omp declare variant (memcpy) match (implementation={vendor(llvm)})     
 // { dg-error "'memcpy' was not declared in this scope" }
+void *fn17 (void *, const void *, __SIZE_TYPE__) { return (void *) 0; }
+
+#pragma omp declare variant (__builtin_memmove) match 
(implementation={vendor(gnu)})    // { dg-error "variant '\[^'\n\r]*' is a 
built-in" }
+void *fn18 (void *, const void *, __SIZE_TYPE__) { return (void *) 0; }
+
+struct E { int e; };
+
+void fn19 (E, int) {}
+
+#pragma omp declare variant (fn19)match(user={condition(0)})   // { dg-error 
"could not convert '0' from 'int' to 'E'" }
+void fn20 (int, E) {}
+
+struct F { operator int () const { return 42; } int f; };
+void fn21 (int, F) {}
+
+#pragma omp declare variant ( fn21 ) match (user = { condition ( 1 - 1 ) } )   
// { dg-error "variant 'void fn21\\\(int, F\\\)' and base 'void fn22\\\(F, 
F\\\)' have incompatible types" }
+void fn22 (F, F) {}
+
+#pragma omp declare variant (fn19) match (user={condition(0)})         // { 
dg-error "could not convert '<anonymous>' from 'F' to 'E'" }
+void fn23 (F, int) {}
+
+void fn24 (int);
+struct U { int u; };
+struct T
+{
+  void fn25 (int) {}
+  int t;
+};
+struct S : public U, T
+{
+  #pragma omp declare variant (fn25) match (user={condition(true)})    // { 
dg-error "variant 'void T::fn25\\\(int\\\)' and base 'void S::fn26\\\(int\\\)' 
have incompatible types" }
+  void fn26 (int) {}
+  #pragma omp declare variant (fn24) match (user={condition(true)})    // { 
dg-error "variant 'void fn24\\\(int\\\)' and base 'void S::fn27\\\(int\\\)' 
have incompatible types" }
+  void fn27 (int) {}
+  void fn28 (int);
+  struct s;
+};
+#pragma omp declare variant (fn25) match (user={condition(true)})      // { 
dg-error "variant 'void T::fn25\\\(int\\\)' and base 'void S::fn28\\\(int\\\)' 
have incompatible types" }
+void S::fn28 (int)
+{
+}
+
+void fn30 (int) throw () {}
+#pragma omp declare variant (fn30) match (user={condition(true)})      // { 
dg-error "variant 'void fn30\\\(int\\\)' and base 'void fn31\\\(int\\\)' have 
incompatible types" "" { target c++17 } }
+void fn31 (int) {}
+
+struct W
+{
+  int fn32 (int) const { return 0; }
+  #pragma omp declare variant (fn32) match (user={condition(true)})    // { 
dg-error "variant 'int W::fn32\\\(int\\\) const' and base 'int 
W::fn33\\\(int\\\)' have incompatible types" }
+  int fn33 (int) { return 0; }
+  int fn34 (int) volatile { return 0; }
+  #pragma omp declare variant (fn34) match (user={condition(true)})    // { 
dg-error "variant 'int W::fn34\\\(int\\\) volatile' and base 'int 
W::fn35\\\(int\\\) const volatile' have incompatible types" }
+  int fn35 (int) const volatile { return 0; }                          // { 
dg-error "passing 'const volatile W' as 'this' argument discards qualifiers" "" 
{ target *-*-* } .-1 }
+  int fn36 (int) { return 0; }
+  #pragma omp declare variant (fn36) match (user={condition(true)})    // { 
dg-error "variant 'int W::fn36\\\(int\\\)' and base 'int W::fn37\\\(int\\\) 
volatile' have incompatible types" }
+  int fn37 (int) volatile { return 0; }                                        
// { dg-error "passing 'volatile W' as 'this' argument discards qualifiers" "" 
{ target *-*-* } .-1 }
+  int fn38 (int) throw () { return 0; }
+  #pragma omp declare variant (fn38) match (user={condition(true)})    // { 
dg-error "variant 'int W::fn38\\\(int\\\)' and base 'int W::fn39\\\(int\\\)' 
have incompatible types" "" { target c++17 } }
+  int fn39 (int) { return 0; }
+  int fn40 (int) { return 0; }
+  #pragma omp declare variant (fn40) match (user={condition(true)})    // { 
dg-error "variant 'int W::fn40\\\(int\\\)' and base 'int W::fn41\\\(int\\\)' 
have incompatible types" "" { target c++17 } }
+  int fn41 (int) throw () { return 0; }
+};

        Jakub

Reply via email to