cp-tree.h (omp_declare_variant_finalize, [...]): Declare.
authorJakub Jelinek <jakub@redhat.com>
Wed, 30 Oct 2019 11:58:03 +0000 (12:58 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Wed, 30 Oct 2019 11:58:03 +0000 (12:58 +0100)
* cp-tree.h (omp_declare_variant_finalize, build_local_temp): Declare.
* decl.c: Include omp-general.h.
(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.

From-SVN: r277613

14 files changed:
gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/parser.c
gcc/cp/tree.c
gcc/testsuite/ChangeLog
gcc/testsuite/c-c++-common/gomp/declare-variant-2.c
gcc/testsuite/c-c++-common/gomp/declare-variant-6.c
gcc/testsuite/g++.dg/gomp/declare-variant-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/gomp/declare-variant-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/gomp/declare-variant-3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/gomp/declare-variant-4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/gomp/declare-variant-5.C [new file with mode: 0644]

index 87a78f20b60695e20f4cc08838e36163fa80d852..55c3f0babe7709b54f7000a564ed8ca3fc53548a 100644 (file)
@@ -1,3 +1,19 @@
+2019-10-30  Jakub Jelinek  <jakub@redhat.com>
+
+       * cp-tree.h (omp_declare_variant_finalize, build_local_temp): Declare.
+       * decl.c: Include omp-general.h.
+       (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.
+
 2019-10-30  Paolo Carlini  <paolo.carlini@oracle.com>
 
        * typeck.c (cp_build_modify_expr): Prefer error + inform to
index a66c25b65be9f7f61fe899f587b1a1095d3628a7..045b2e33dbb94c99f73f12f733a7dd692700916f 100644 (file)
@@ -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))
index 37b954a6c6f33058ef4a5539a77f0ff18c55d384..42e03a31e20a2b23c9c7a8e03d519512e235c5c6 100644 (file)
@@ -6435,6 +6435,7 @@ extern tree groktypename                  (cp_decl_specifier_seq *, const cp_declarator *, bool
 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);
@@ -7293,6 +7294,7 @@ extern tree build_min_nt_call_vec (tree, vec<tree, va_gc> *);
 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);
index 95c84159d7aa1eedf8379d4431005e2243079e18..8320597c10884e82b9f98aa19bb84af0ac9b9993 100644 (file)
@@ -53,6 +53,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "asan.h"
 #include "gcc-rich-location.h"
 #include "langhooks.h"
+#include "omp-general.h"
 
 /* Possible cases of bad specifiers type used by bad_specifiers. */
 enum bad_spec_place {
@@ -7070,6 +7071,195 @@ decl_maybe_constant_destruction (tree decl, tree type)
              && 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 (!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,
@@ -7235,6 +7425,16 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
        }
     }
 
+  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;
@@ -16475,6 +16675,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)))
index b394e2e1467b0e2627a43ddde711d799713681fc..e29e99f418be40fc00677a6079bc6410ddda05fa 100644 (file)
@@ -40666,25 +40666,53 @@ cp_finish_omp_declare_variant (cp_parser *parser, cp_token *pragma_tok,
       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;
@@ -40707,8 +40735,14 @@ cp_finish_omp_declare_variant (cp_parser *parser, cp_token *pragma_tok,
   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;
     }
index 9d63736a394f645109d2e04e0205dab383c6d268..ca4d3e2a48bad424b4981fbbf6a1a1d0d2df3540 100644 (file)
@@ -43,7 +43,6 @@ static hashval_t list_hash_pieces (tree, tree, 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, tsubst_flags_t complain)
 /* 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,
index bac4d0015508c6ccf6d54479d19d8aaae36fbb7e..9bee47b692e556cf841dd14f9d27750b38996ea3 100644 (file)
@@ -1,3 +1,16 @@
+2019-10-30  Jakub Jelinek  <jakub@redhat.com>
+
+       * 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.
+
 2019-10-30  Paolo Carlini  <paolo.carlini@oracle.com>
 
        * g++.dg/conversion/ptrmem2.C: Adjust for error + inform.
index f058f57e68726f2178b38893a2a011563a0543a3..1a16a9904e3ada4eb14d4728e119a5007208ad93 100644 (file)
@@ -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);
index 67c5a00bd8ae017ea36a7b3093829717547db263..9ccfd0f39acf6f61454a232135240e32d9ee2069 100644 (file)
@@ -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);
diff --git a/gcc/testsuite/g++.dg/gomp/declare-variant-1.C b/gcc/testsuite/g++.dg/gomp/declare-variant-1.C
new file mode 100644 (file)
index 0000000..ece80d3
--- /dev/null
@@ -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);
diff --git a/gcc/testsuite/g++.dg/gomp/declare-variant-2.C b/gcc/testsuite/g++.dg/gomp/declare-variant-2.C
new file mode 100644 (file)
index 0000000..c6ec8d2
--- /dev/null
@@ -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);
+};
diff --git a/gcc/testsuite/g++.dg/gomp/declare-variant-3.C b/gcc/testsuite/g++.dg/gomp/declare-variant-3.C
new file mode 100644 (file)
index 0000000..8044cef
--- /dev/null
@@ -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 ();
+};
diff --git a/gcc/testsuite/g++.dg/gomp/declare-variant-4.C b/gcc/testsuite/g++.dg/gomp/declare-variant-4.C
new file mode 100644 (file)
index 0000000..8a2e818
--- /dev/null
@@ -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) {}
+};
diff --git a/gcc/testsuite/g++.dg/gomp/declare-variant-5.C b/gcc/testsuite/g++.dg/gomp/declare-variant-5.C
new file mode 100644 (file)
index 0000000..fa80c25
--- /dev/null
@@ -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; }
+};