* 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
+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
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))
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);
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);
#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 {
&& 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,
}
}
+ 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;
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)))
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;
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;
}
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 *);
/* 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,
+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.
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);
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);
--- /dev/null
+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);
--- /dev/null
+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);
+};
--- /dev/null
+// 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 ();
+};
--- /dev/null
+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) {}
+};
--- /dev/null
+// 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; }
+};