From 42ceec0607f3235904c68d3ede1aaddb70eb06aa Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Wed, 30 Oct 2019 12:58:03 +0100 Subject: [PATCH] cp-tree.h (omp_declare_variant_finalize, [...]): Declare. * 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 --- gcc/cp/ChangeLog | 16 ++ gcc/cp/class.c | 8 + gcc/cp/cp-tree.h | 2 + gcc/cp/decl.c | 205 ++++++++++++++++++ gcc/cp/parser.c | 66 ++++-- gcc/cp/tree.c | 3 +- gcc/testsuite/ChangeLog | 13 ++ .../c-c++-common/gomp/declare-variant-2.c | 2 + .../c-c++-common/gomp/declare-variant-6.c | 12 +- gcc/testsuite/g++.dg/gomp/declare-variant-1.C | 28 +++ gcc/testsuite/g++.dg/gomp/declare-variant-2.C | 45 ++++ gcc/testsuite/g++.dg/gomp/declare-variant-3.C | 139 ++++++++++++ gcc/testsuite/g++.dg/gomp/declare-variant-4.C | 45 ++++ gcc/testsuite/g++.dg/gomp/declare-variant-5.C | 131 +++++++++++ 14 files changed, 691 insertions(+), 24 deletions(-) create mode 100644 gcc/testsuite/g++.dg/gomp/declare-variant-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/declare-variant-2.C create mode 100644 gcc/testsuite/g++.dg/gomp/declare-variant-3.C create mode 100644 gcc/testsuite/g++.dg/gomp/declare-variant-4.C create mode 100644 gcc/testsuite/g++.dg/gomp/declare-variant-5.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 87a78f20b60..55c3f0babe7 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,19 @@ +2019-10-30 Jakub Jelinek + + * 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 * typeck.c (cp_build_modify_expr): Prefer error + inform to diff --git a/gcc/cp/class.c b/gcc/cp/class.c index a66c25b65be..045b2e33dbb 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -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)) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 37b954a6c6f..42e03a31e20 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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 *); extern tree build_min_non_dep_call_vec (tree, tree, vec *); extern vec* vec_copy_and_insert (vec*, 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); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 95c84159d7a..8320597c108 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -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, "% on constructor %qD", decl); + remove_all = true; + } + else if (DECL_DESTRUCTOR_P (decl)) + { + error_at (match_loc, "% on destructor %qD", decl); + remove_all = true; + } + else if (DECL_DEFAULTED_FN (decl)) + { + error_at (match_loc, "% on defaulted %qD", decl); + remove_all = true; + } + else if (DECL_DELETED_FN (decl)) + { + error_at (match_loc, "% on deleted %qD", decl); + remove_all = true; + } + else if (DECL_VIRTUAL_P (decl)) + { + error_at (match_loc, "% 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))) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index b394e2e1467..e29e99f418b 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -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; } diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 9d63736a394..ca4d3e2a48b 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -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, diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index bac4d001550..9bee47b692e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,16 @@ +2019-10-30 Jakub Jelinek + + * 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 * g++.dg/conversion/ptrmem2.C: Adjust for error + inform. diff --git a/gcc/testsuite/c-c++-common/gomp/declare-variant-2.c b/gcc/testsuite/c-c++-common/gomp/declare-variant-2.c index f058f57e687..1a16a9904e3 100644 --- a/gcc/testsuite/c-c++-common/gomp/declare-variant-2.c +++ b/gcc/testsuite/c-c++-common/gomp/declare-variant-2.c @@ -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); diff --git a/gcc/testsuite/c-c++-common/gomp/declare-variant-6.c b/gcc/testsuite/c-c++-common/gomp/declare-variant-6.c index 67c5a00bd8a..9ccfd0f39ac 100644 --- a/gcc/testsuite/c-c++-common/gomp/declare-variant-6.c +++ b/gcc/testsuite/c-c++-common/gomp/declare-variant-6.c @@ -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 index 00000000000..ece80d35dd7 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/declare-variant-1.C @@ -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 index 00000000000..c6ec8d2be44 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/declare-variant-2.C @@ -0,0 +1,45 @@ +struct S { int a, b, c, d; }; +void f1 (int); +void f1 (double); +template 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) 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 index 00000000000..8044cef91f2 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/declare-variant-3.C @@ -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 +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 // { 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 '' 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 index 00000000000..8a2e8181a0c --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/declare-variant-4.C @@ -0,0 +1,45 @@ +struct S { int a, b, c, d; }; +void f1 (int) {} +void f1 (double) {} +template 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) 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 index 00000000000..fa80c255c81 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/declare-variant-5.C @@ -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 +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 // { 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 '' 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; } +}; -- 2.30.2