From be246ac2d26e1cb072f205bf97d5eac150220f3f Mon Sep 17 00:00:00 2001 From: Anthony Sharp Date: Wed, 10 Mar 2021 20:36:03 +0000 Subject: c++: Private parent access check for using decls [PR19377] This bug was already mostly fixed by the patch for PR17314. This patch continues that by ensuring that where a using decl is used, causing an access failure to a child class because the using decl is private, the compiler correctly points to the using decl as the source of the problem. gcc/cp/ChangeLog: 2021-03-10 Anthony Sharp * semantics.c (get_class_access_diagnostic_decl): New function that examines special cases when a parent class causes a private access failure. (enforce_access): Slightly modified to call function above. gcc/testsuite/ChangeLog: 2021-03-10 Anthony Sharp * g++.dg/cpp1z/using9.C: New using decl test. Co-authored-by: Jason Merrill --- gcc/cp/semantics.c | 101 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 83 insertions(+), 18 deletions(-) (limited to 'gcc/cp/semantics.c') diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 30dd206..b02596f 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -256,6 +256,72 @@ pop_to_parent_deferring_access_checks (void) } } +/* Called from enforce_access. A class has attempted (but failed) to access + DECL. It is already established that a baseclass of that class, + PARENT_BINFO, has private access to DECL. Examine certain special cases + to find a decl that accurately describes the source of the problem. If + none of the special cases apply, simply return DECL as the source of the + problem. */ + +static tree +get_class_access_diagnostic_decl (tree parent_binfo, tree decl) +{ + /* When a class is denied access to a decl in a baseclass, most of the + time it is because the decl itself was declared as private at the point + of declaration. + + However, in C++, there are (at least) two situations in which a decl + can be private even though it was not originally defined as such. + These two situations only apply if a baseclass had private access to + DECL (this function is only called if that is the case). */ + + /* We should first check whether the reason the parent had private access + to DECL was simply because DECL was created and declared as private in + the parent. If it was, then DECL is definitively the source of the + problem. */ + if (SAME_BINFO_TYPE_P (context_for_name_lookup (decl), + BINFO_TYPE (parent_binfo))) + return decl; + + /* 1. If the "using" keyword is used to inherit DECL within the parent, + this may cause DECL to be private, so we should return the using + statement as the source of the problem. + + Scan the fields of PARENT_BINFO and see if there are any using decls. If + there are, see if they inherit DECL. If they do, that's where DECL must + have been declared private. */ + + for (tree parent_field = TYPE_FIELDS (BINFO_TYPE (parent_binfo)); + parent_field; + parent_field = DECL_CHAIN (parent_field)) + /* Not necessary, but also check TREE_PRIVATE for the sake of + eliminating obviously non-relevant using decls. */ + if (TREE_CODE (parent_field) == USING_DECL + && TREE_PRIVATE (parent_field)) + { + tree decl_stripped = strip_using_decl (parent_field); + + /* The using statement might be overloaded. If so, we need to + check all of the overloads. */ + for (ovl_iterator iter (decl_stripped); iter; ++iter) + /* If equal, the using statement inherits DECL, and so is the + source of the access failure, so return it. */ + if (*iter == decl) + return parent_field; + } + + /* 2. If DECL was privately inherited by the parent class, then DECL will + be inaccessible, even though it may originally have been accessible to + deriving classes. In that case, the fault lies with the parent, since it + used a private inheritance, so we return the parent as the source of the + problem. + + Since this is the last check, we just assume it's true. At worst, it + will simply point to the class that failed to give access, which is + technically true. */ + return TYPE_NAME (BINFO_TYPE (parent_binfo)); +} + /* If the current scope isn't allowed to access DECL along BASETYPE_PATH, give an error, or if we're parsing a function or class template, defer the access check to be performed at instantiation time. @@ -317,34 +383,33 @@ enforce_access (tree basetype_path, tree decl, tree diag_decl, diag_decl = strip_inheriting_ctors (diag_decl); if (complain & tf_error) { - /* We will usually want to point to the same place as - diag_decl but not always. */ + access_kind access_failure_reason = ak_none; + + /* By default, using the decl as the source of the problem will + usually give correct results. */ tree diag_location = diag_decl; - access_kind parent_access = ak_none; - /* See if any of BASETYPE_PATH's parents had private access - to DECL. If they did, that will tell us why we don't. */ + /* However, if a parent of BASETYPE_PATH had private access to decl, + then it actually might be the case that the source of the problem + is not DECL. */ tree parent_binfo = get_parent_with_private_access (decl, basetype_path); - /* If a parent had private access, then the diagnostic - location DECL should be that of the parent class, since it - failed to give suitable access by using a private - inheritance. But if DECL was actually defined in the parent, - it wasn't privately inherited, and so we don't need to do - this, and complain_about_access will figure out what to - do. */ - if (parent_binfo != NULL_TREE - && (context_for_name_lookup (decl) - != BINFO_TYPE (parent_binfo))) + /* So if a parent did have private access, then we need to do + special checks to obtain the best diagnostic location decl. */ + if (parent_binfo != NULL_TREE) { - diag_location = TYPE_NAME (BINFO_TYPE (parent_binfo)); - parent_access = ak_private; + diag_location = get_class_access_diagnostic_decl (parent_binfo, + diag_decl); + + /* We also at this point know that the reason access failed was + because decl was private. */ + access_failure_reason = ak_private; } /* Finally, generate an error message. */ complain_about_access (decl, diag_decl, diag_location, true, - parent_access); + access_failure_reason); } if (afi) afi->record_access_failure (basetype_path, decl, diag_decl); -- cgit v1.1 From cf25e27faef75e265e659f39ef6b7d0f1695dfeb Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Fri, 2 Apr 2021 19:47:09 -0400 Subject: c++: Refine check for CTAD placeholder [PR99586] In the below testcase, during finish_compound_literal for A{}, type_uses_auto finds and returns the CTAD placeholder for B{V}, which tricks us into attempting CTAD on A{} and leads to bogus errors. AFAICT 'type' will always be a bare 'auto' in the CTAD case so we don't need to look deeply to find it; checking template_placeholder_p instead should suffice here. gcc/cp/ChangeLog: PR c++/99586 * semantics.c (finish_compound_literal): Check template_placeholder_p instead of type_uses_auto. gcc/testsuite/ChangeLog: PR c++/99586 * g++.dg/cpp2a/nontype-class42.C: New test. --- gcc/cp/semantics.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'gcc/cp/semantics.c') diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index b02596f..8eaaaef 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -3036,14 +3036,13 @@ finish_compound_literal (tree type, tree compound_literal, return error_mark_node; } - if (tree anode = type_uses_auto (type)) - if (CLASS_PLACEHOLDER_TEMPLATE (anode)) - { - type = do_auto_deduction (type, compound_literal, anode, complain, - adc_variable_type); - if (type == error_mark_node) - return error_mark_node; - } + if (template_placeholder_p (type)) + { + type = do_auto_deduction (type, compound_literal, type, complain, + adc_variable_type); + if (type == error_mark_node) + return error_mark_node; + } /* Used to hold a copy of the compound literal in a template. */ tree orig_cl = NULL_TREE; -- cgit v1.1 From 006783f4b165dff25aae3697920fcf54754dddd4 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 13 Apr 2021 16:18:54 -0400 Subject: c++: debug location of variable cleanups [PR88742] PR49951 complained about the debugger jumping back to the declaration of a local variable when we run its destructor. That was fixed in 4.7, but broke again in 4.8. PR58123 fixed an inconsistency in the behavior, but not the jumping around. This patch addresses the issue by setting EXPR_LOCATION on a cleanup destructor call to the location of the closing brace of the compound-statement, or whatever token ends the scope of the variable. The change to cp_parser_compound_statement is so input_location is the } rather than the ; of the last substatement. gcc/cp/ChangeLog: PR c++/88742 PR c++/49951 PR c++/58123 * semantics.c (set_cleanup_locs): New. (do_poplevel): Call it. * parser.c (cp_parser_compound_statement): Consume the } before finish_compound_stmt. gcc/testsuite/ChangeLog: PR c++/88742 * g++.dg/debug/cleanup1.C: New test. * c-c++-common/Wimplicit-fallthrough-6.c: Adjust diagnostic line. * c-c++-common/Wimplicit-fallthrough-7.c: Likewise. * g++.dg/cpp2a/constexpr-dtor3.C: Likewise. * g++.dg/ext/constexpr-attr-cleanup1.C: Likewise. * g++.dg/tm/inherit2.C: Likewise. * g++.dg/tm/unsafe1.C: Likewise. * g++.dg/warn/Wimplicit-fallthrough-1.C: Likewise. * g++.dg/gcov/gcov-2.C: Adjust coverage counts. --- gcc/cp/semantics.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'gcc/cp/semantics.c') diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 8eaaaef..1257722 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -602,6 +602,22 @@ add_decl_expr (tree decl) add_stmt (r); } +/* Set EXPR_LOCATION of the cleanups of any CLEANUP_STMT in STMTS to LOC. */ + +static void +set_cleanup_locs (tree stmts, location_t loc) +{ + if (TREE_CODE (stmts) == CLEANUP_STMT) + { + protected_set_expr_location (CLEANUP_EXPR (stmts), loc); + set_cleanup_locs (CLEANUP_BODY (stmts), loc); + } + else if (TREE_CODE (stmts) == STATEMENT_LIST) + for (tree_stmt_iterator i = tsi_start (stmts); + !tsi_end_p (i); tsi_next (&i)) + set_cleanup_locs (tsi_stmt (i), loc); +} + /* Finish a scope. */ tree @@ -614,6 +630,9 @@ do_poplevel (tree stmt_list) stmt_list = pop_stmt_list (stmt_list); + /* input_location is the last token of the scope, usually a }. */ + set_cleanup_locs (stmt_list, input_location); + if (!processing_template_decl) { stmt_list = c_build_bind_expr (input_location, block, stmt_list); -- cgit v1.1 From 9b53edc796d284b6adec7f2996772dbddf4c341e Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 14 Apr 2021 09:30:05 -0400 Subject: c++: non-static member, array bound, sizeof [PR93314] N2253 allowed referring to non-static data members without an object in unevaluated operands like that of sizeof, but in a constant-expression context like an array bound or template argument within such an unevaluated operand we do actually need a value, so that permission cannot apply. gcc/cp/ChangeLog: PR c++/93314 * semantics.c (finish_id_expression_1): Clear cp_unevaluated_operand for a non-static data member in a constant-expression. gcc/testsuite/ChangeLog: PR c++/93314 * g++.dg/parse/uneval1.C: New test. --- gcc/cp/semantics.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'gcc/cp/semantics.c') diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 1257722..4520181 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -4093,6 +4093,12 @@ finish_id_expression_1 (tree id_expression, cp_warn_deprecated_use_scopes (scope); + /* In a constant-expression context, turn off cp_unevaluated_operand + so finish_non_static_data_member will complain (93314). */ + auto eval = make_temp_override (cp_unevaluated_operand); + if (integral_constant_expression_p && TREE_CODE (decl) == FIELD_DECL) + cp_unevaluated_operand = 0; + if (TYPE_P (scope)) decl = finish_qualified_id_expr (scope, decl, @@ -4106,6 +4112,10 @@ finish_id_expression_1 (tree id_expression, } else if (TREE_CODE (decl) == FIELD_DECL) { + auto eval = make_temp_override (cp_unevaluated_operand); + if (integral_constant_expression_p) + cp_unevaluated_operand = 0; + /* Since SCOPE is NULL here, this is an unqualified name. Access checking has been performed during name lookup already. Turn off checking to avoid duplicate errors. */ -- cgit v1.1 From 1b462deabf70e0f4bebb1f85118827d9c2eeffb5 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 29 Apr 2021 11:11:37 +0200 Subject: c++: Fix up detach clause vs. data-sharing clause checking [PR100319] The standard says that "The event-handle will be considered as if it was specified on a firstprivate clause." which means that it can't be explicitly specified in some other data-sharing clause. The checking is implemented correctly for C, but for C++ when detach_seen is true (i.e. the construct had detach clause) we were comparing OMP_CLAUSE_DECL (c) with t, which was previously initialized to OMP_CLAUSE_DECL (c), which means it complained about any explicit data-sharing clause on the same construct with a detach clause. Fixed by remembering the detach clause in detach_seen (instead of a boolean flag) and comparing against its OMP_CLAUSE_DECL. 2021-04-29 Jakub Jelinek PR c++/100319 * semantics.c (finish_omp_clauses): Fix up check that variable mentioned in detach clause doesn't appear in data-sharing clauses. * c-c++-common/gomp/task-detach-3.c: New test. --- gcc/cp/semantics.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'gcc/cp/semantics.c') diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 4520181..3a6468f 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -6527,7 +6527,7 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) has been seen, -2 if mixed inscan/normal reduction diagnosed. */ int reduction_seen = 0; bool allocate_seen = false; - bool detach_seen = false; + tree detach_seen = NULL_TREE; bool mergeable_seen = false; bitmap_obstack_initialize (NULL); @@ -7578,7 +7578,7 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) type); remove = true; } - detach_seen = true; + detach_seen = c; cxx_mark_addressable (t); } break; @@ -8548,7 +8548,7 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE) - && OMP_CLAUSE_DECL (c) == t) + && OMP_CLAUSE_DECL (c) == OMP_CLAUSE_DECL (detach_seen)) { error_at (OMP_CLAUSE_LOCATION (c), "the event handle of a % clause " -- cgit v1.1 From 3f0de4dd51fd9a1e9628411b4fd728f5841256fe Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Thu, 15 Apr 2021 17:04:24 -0400 Subject: c++: unset COMPOUND_LITERAL_P [PR100079] Once a CONSTRUCTOR has been digested and used as an initializer, it no longer represents a compound literal by itself, so we can clear the flag, letting us use it consistently to distinguish between digested and undigested initializer-lists. gcc/cp/ChangeLog: * cp-tree.h: Clarify comments. * pt.c (get_template_parm_object): Add assert. * semantics.c (finish_compound_literal): Clear TREE_HAS_CONSTRUCTOR. * tree.c (zero_init_expr_p): Check TREE_HAS_CONSTRUCTOR. * typeck2.c (store_init_value): Likewise. --- gcc/cp/semantics.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'gcc/cp/semantics.c') diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 3a6468f..319a3a8 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -3177,9 +3177,13 @@ finish_compound_literal (tree type, tree compound_literal, } /* Represent other compound literals with TARGET_EXPR so we produce - an lvalue, but can elide copies. */ + a prvalue, and can elide copies. */ if (!VECTOR_TYPE_P (type)) - compound_literal = get_target_expr_sfinae (compound_literal, complain); + { + /* The CONSTRUCTOR is now an initializer, not a compound literal. */ + TREE_HAS_CONSTRUCTOR (compound_literal) = false; + compound_literal = get_target_expr_sfinae (compound_literal, complain); + } return compound_literal; } -- cgit v1.1 From a9fc64d8120937c5c37e1cacb2f55ae196e8897d Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 14 Apr 2021 11:24:50 -0400 Subject: c++: constant expressions are evaluated [PR93314] My GCC 11 patch for PR93314 turned off cp_unevaluated_operand while processing an id-expression that names a non-static data member, but the broader issue is that in general, a constant-expression is evaluated even in an unevaluated operand. gcc/cp/ChangeLog: * cp-tree.h (cp_evaluated): Add reset parm to constructor. * parser.c (cp_parser_constant_expression): Change allow_non_constant_p to int. Use cp_evaluated. (cp_parser_initializer_clause): Pass 2 to allow_non_constant_p. * semantics.c (finish_id_expression_1): Don't mess with cp_unevaluated_operand here. --- gcc/cp/semantics.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'gcc/cp/semantics.c') diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 319a3a8..6224f49 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -4097,12 +4097,6 @@ finish_id_expression_1 (tree id_expression, cp_warn_deprecated_use_scopes (scope); - /* In a constant-expression context, turn off cp_unevaluated_operand - so finish_non_static_data_member will complain (93314). */ - auto eval = make_temp_override (cp_unevaluated_operand); - if (integral_constant_expression_p && TREE_CODE (decl) == FIELD_DECL) - cp_unevaluated_operand = 0; - if (TYPE_P (scope)) decl = finish_qualified_id_expr (scope, decl, @@ -4116,10 +4110,6 @@ finish_id_expression_1 (tree id_expression, } else if (TREE_CODE (decl) == FIELD_DECL) { - auto eval = make_temp_override (cp_unevaluated_operand); - if (integral_constant_expression_p) - cp_unevaluated_operand = 0; - /* Since SCOPE is NULL here, this is an unqualified name. Access checking has been performed during name lookup already. Turn off checking to avoid duplicate errors. */ -- cgit v1.1 From 1580fc764423bf89e9b853aaa8c65999e37ccb8b Mon Sep 17 00:00:00 2001 From: Tobias Burnus Date: Tue, 4 May 2021 13:38:03 +0200 Subject: OpenMP: Support complex/float in && and || reduction C/C++ permit logical AND and logical OR also with floating-point or complex arguments by doing an unequal zero comparison; the result is an 'int' with value one or zero. Hence, those are also permitted as reduction variable, even though it is not the most sensible thing to do. gcc/c/ChangeLog: * c-typeck.c (c_finish_omp_clauses): Accept float + complex for || and && reductions. gcc/cp/ChangeLog: * semantics.c (finish_omp_reduction_clause): Accept float + complex for || and && reductions. gcc/ChangeLog: * omp-low.c (lower_rec_input_clauses, lower_reduction_clauses): Handle && and || with floating-point and complex arguments. gcc/testsuite/ChangeLog: * gcc.dg/gomp/clause-1.c: Use 'reduction(&:..)' instead of '...(&&:..)'. libgomp/ChangeLog: * testsuite/libgomp.c-c++-common/reduction-1.c: New test. * testsuite/libgomp.c-c++-common/reduction-2.c: New test. * testsuite/libgomp.c-c++-common/reduction-3.c: New test. --- gcc/cp/semantics.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'gcc/cp/semantics.c') diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 6224f49..0d590c3 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -6032,6 +6032,8 @@ finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor) case PLUS_EXPR: case MULT_EXPR: case MINUS_EXPR: + case TRUTH_ANDIF_EXPR: + case TRUTH_ORIF_EXPR: predefined = true; break; case MIN_EXPR: @@ -6047,12 +6049,6 @@ finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor) break; predefined = true; break; - case TRUTH_ANDIF_EXPR: - case TRUTH_ORIF_EXPR: - if (FLOAT_TYPE_P (type)) - break; - predefined = true; - break; default: break; } -- cgit v1.1 From b5c1c7a96bc8d7062d2c35675f48131667498182 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 21 May 2021 21:16:21 +0200 Subject: openmp: Fix up firstprivate+lastprivate clause handling [PR99928] The C/C++ clause splitting happens very early during construct parsing, but only the FEs later on handle possible instantiations, non-static member handling and array section lowering. In the OpenMP 5.0/5.1 rules, whether firstprivate is added to combined target depends on whether it isn't also mentioned in lastprivate or map clauses, but unfortunately I think such checks are much better done only when the FEs perform all the above mentioned changes. So, this patch arranges for the firstprivate clause to be copied or moved to combined target construct (as before), but sets flags on that clause, which tell the FE *finish_omp_clauses and the gimplifier it has been added only conditionally and let the FEs and gimplifier DTRT for these. 2021-05-21 Jakub Jelinek PR middle-end/99928 gcc/ * tree.h (OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT_TARGET): Define. * gimplify.c (enum gimplify_omp_var_data): Fix up GOVD_MAP_HAS_ATTACHMENTS value, add GOVD_FIRSTPRIVATE_IMPLICIT. (omp_lastprivate_for_combined_outer_constructs): If combined target has GOVD_FIRSTPRIVATE_IMPLICIT set for the decl, change it to GOVD_MAP | GOVD_SEEN. (gimplify_scan_omp_clauses): Set GOVD_FIRSTPRIVATE_IMPLICIT for firstprivate clauses with OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT. (gimplify_adjust_omp_clauses): For firstprivate clauses with OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT either clear that bit and OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT_TARGET too, or remove it and let it be replaced by implicit map clause. gcc/c-family/ * c-omp.c (c_omp_split_clauses): Set OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT on firstprivate clause copy going to target construct, and for target simd set also OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT_TARGET bit. gcc/c/ * c-typeck.c (c_finish_omp_clauses): Move firstprivate clauses with OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT to the end of the chain. Don't error if a decl is mentioned both in map clause and in such firstprivate clause unless OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT_TARGET is also set. gcc/cp/ * semantics.c (finish_omp_clauses): Move firstprivate clauses with OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT to the end of the chain. Don't error if a decl is mentioned both in map clause and in such firstprivate clause unless OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT_TARGET is also set. gcc/testsuite/ * c-c++-common/gomp/pr99928-3.c: Remove all xfails. * c-c++-common/gomp/pr99928-15.c: New test. --- gcc/cp/semantics.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'gcc/cp/semantics.c') diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 0d590c3..fffbe40 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -6519,6 +6519,7 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) bool allocate_seen = false; tree detach_seen = NULL_TREE; bool mergeable_seen = false; + bool firstprivate_implicit_moved = false; bitmap_obstack_initialize (NULL); bitmap_initialize (&generic_head, &bitmap_default_obstack); @@ -6843,6 +6844,29 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) break; case OMP_CLAUSE_FIRSTPRIVATE: + if (OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT (c) + && !firstprivate_implicit_moved) + { + firstprivate_implicit_moved = true; + /* Move firstprivate clauses with + OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT set to the end of + clauses chain. */ + tree cl = NULL, *pc1 = pc, *pc2 = &cl; + while (*pc1) + if (OMP_CLAUSE_CODE (*pc1) == OMP_CLAUSE_FIRSTPRIVATE + && OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT (*pc1)) + { + *pc2 = *pc1; + pc2 = &OMP_CLAUSE_CHAIN (*pc2); + *pc1 = OMP_CLAUSE_CHAIN (*pc1); + } + else + pc1 = &OMP_CLAUSE_CHAIN (*pc1); + *pc2 = NULL; + *pc1 = cl; + if (pc1 != pc) + continue; + } t = omp_clause_decl_field (OMP_CLAUSE_DECL (c)); if (t) omp_note_field_privatization (t, OMP_CLAUSE_DECL (c)); @@ -6884,6 +6908,9 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) if (ort == C_ORT_ACC) error_at (OMP_CLAUSE_LOCATION (c), "%qD appears more than once in data clauses", t); + else if (OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT (c) + && !OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT_TARGET (c)) + /* Silently drop the clause. */; else error_at (OMP_CLAUSE_LOCATION (c), "%qD appears both in data and map clauses", t); -- cgit v1.1 From 9a5de4d5af1c10a8c097de30ee4c71457216e975 Mon Sep 17 00:00:00 2001 From: Tobias Burnus Date: Fri, 28 May 2021 10:01:19 +0200 Subject: OpenMP: Add iterator support to Fortran's depend; add affinity clause gcc/c-family/ChangeLog: * c-pragma.h (enum pragma_omp_clause): Add PRAGMA_OMP_CLAUSE_AFFINITY. gcc/c/ChangeLog: * c-parser.c (c_parser_omp_clause_affinity): New. (c_parser_omp_clause_name, c_parser_omp_variable_list, c_parser_omp_all_clauses, OMP_TASK_CLAUSE_MASK): Handle affinity clause. * c-typeck.c (handle_omp_array_sections_1, handle_omp_array_sections, c_finish_omp_clauses): Likewise. gcc/cp/ChangeLog: * parser.c (cp_parser_omp_clause_affinity): New. (cp_parser_omp_clause_name, cp_parser_omp_var_list_no_open, cp_parser_omp_all_clauses, OMP_TASK_CLAUSE_MASK): Handle affinity clause. * semantics.c (handle_omp_array_sections_1, handle_omp_array_sections, finish_omp_clauses): Likewise. gcc/fortran/ChangeLog: * dump-parse-tree.c (show_iterator): New. (show_omp_namelist): Handle iterators. (show_omp_clauses): Handle affinity. * gfortran.h (gfc_free_omp_namelist): New union with 'udr' and new 'ns'. * match.c (gfc_free_omp_namelist): Add are to choose union element. * openmp.c (gfc_free_omp_clauses, gfc_match_omp_detach, gfc_match_omp_clause_reduction, gfc_match_omp_flush): Update call to gfc_free_omp_namelist. (gfc_match_omp_variable_list): Likewise; permit preceeding whitespace. (enum omp_mask1): Add OMP_CLAUSE_AFFINITY. (gfc_match_iterator): New. (gfc_match_omp_clauses): Use it; update call to gfc_free_omp_namelist. (OMP_TASK_CLAUSES): Add OMP_CLAUSE_AFFINITY. (gfc_match_omp_taskwait): Match depend clause. (resolve_omp_clauses): Handle affinity; update for udr/union change. (gfc_resolve_omp_directive): Resolve clauses of taskwait. * st.c (gfc_free_statement): Update gfc_free_omp_namelist call. * trans-openmp.c (gfc_trans_omp_array_reduction_or_udr): Likewise (handle_iterator): New. (gfc_trans_omp_clauses): Handle iterators for depend/affinity clause. (gfc_trans_omp_taskwait): Handle depend clause. (gfc_trans_omp_directive): Update call. gcc/ChangeLog: * gimplify.c (gimplify_omp_affinity): New. (gimplify_scan_omp_clauses): Call it; remove affinity clause afterwards. * tree-core.h (enum omp_clause_code): Add OMP_CLAUSE_AFFINITY. * tree-pretty-print.c (dump_omp_clause): Handle OMP_CLAUSE_AFFINITY. * tree.c (omp_clause_num_ops, omp_clause_code_name): Add clause. (walk_tree_1): Handle OMP_CLAUSE_AFFINITY. libgomp/ChangeLog: * testsuite/libgomp.fortran/depend-iterator-2.f90: New test. gcc/testsuite/ChangeLog: * c-c++-common/gomp/affinity-1.c: New test. * c-c++-common/gomp/affinity-2.c: New test. * c-c++-common/gomp/affinity-3.c: New test. * c-c++-common/gomp/affinity-4.c: New test. * c-c++-common/gomp/affinity-5.c: New test. * c-c++-common/gomp/affinity-6.c: New test. * c-c++-common/gomp/affinity-7.c: New test. * gfortran.dg/gomp/affinity-clause-1.f90: New test. * gfortran.dg/gomp/affinity-clause-2.f90: New test. * gfortran.dg/gomp/affinity-clause-3.f90: New test. * gfortran.dg/gomp/affinity-clause-4.f90: New test. * gfortran.dg/gomp/affinity-clause-5.f90: New test. * gfortran.dg/gomp/affinity-clause-6.f90: New test. * gfortran.dg/gomp/depend-iterator-1.f90: New test. * gfortran.dg/gomp/depend-iterator-2.f90: New test. * gfortran.dg/gomp/depend-iterator-3.f90: New test. * gfortran.dg/gomp/taskwait.f90: New test. --- gcc/cp/semantics.c | 53 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 17 deletions(-) (limited to 'gcc/cp/semantics.c') diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index fffbe40..6fafd06 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -4993,7 +4993,8 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, " clauses"); return error_mark_node; } - else if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND + else if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_AFFINITY + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND && VAR_P (t) && CP_DECL_THREAD_LOCAL_P (t)) { error_at (OMP_CLAUSE_LOCATION (c), @@ -5080,7 +5081,8 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, { if (!integer_nonzerop (length)) { - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_AFFINITY + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TASK_REDUCTION) @@ -5148,7 +5150,8 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, } if (tree_int_cst_equal (size, low_bound)) { - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_AFFINITY + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TASK_REDUCTION) @@ -5169,7 +5172,8 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, } else if (length == NULL_TREE) { - if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_AFFINITY + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_IN_REDUCTION && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_TASK_REDUCTION) @@ -5207,7 +5211,8 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, } else if (length == NULL_TREE) { - if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_AFFINITY + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_IN_REDUCTION && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_TASK_REDUCTION) @@ -5251,7 +5256,8 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, } /* If there is a pointer type anywhere but in the very first array-section-subscript, the array section can't be contiguous. */ - if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_AFFINITY + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND && TREE_CODE (TREE_CHAIN (t)) == TREE_LIST) { error_at (OMP_CLAUSE_LOCATION (c), @@ -5299,7 +5305,8 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort) unsigned int first_non_one = 0; auto_vec types; tree *tp = &OMP_CLAUSE_DECL (c); - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_AFFINITY) && TREE_CODE (*tp) == TREE_LIST && TREE_PURPOSE (*tp) && TREE_CODE (TREE_PURPOSE (*tp)) == TREE_VEC) @@ -5311,7 +5318,8 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort) return true; if (first == NULL_TREE) return false; - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_AFFINITY) { tree t = *tp; tree tem = NULL_TREE; @@ -7445,6 +7453,7 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) } goto handle_field_decl; + case OMP_CLAUSE_AFFINITY: case OMP_CLAUSE_DEPEND: t = OMP_CLAUSE_DECL (c); if (t == NULL_TREE) @@ -7453,7 +7462,8 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) == OMP_CLAUSE_DEPEND_SOURCE); break; } - if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + && OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK) { if (cp_finish_omp_clause_depend_sink (c)) remove = true; @@ -7478,7 +7488,9 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) { if (handle_omp_array_sections (c, ort)) remove = true; - else if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_DEPOBJ) + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + && (OMP_CLAUSE_DEPEND_KIND (c) + == OMP_CLAUSE_DEPEND_DEPOBJ)) { error_at (OMP_CLAUSE_LOCATION (c), "% clause with % dependence " @@ -7503,22 +7515,28 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) if (DECL_P (t)) error_at (OMP_CLAUSE_LOCATION (c), "%qD is not lvalue expression nor array section " - "in % clause", t); + "in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); else error_at (OMP_CLAUSE_LOCATION (c), "%qE is not lvalue expression nor array section " - "in % clause", t); + "in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); remove = true; } else if (TREE_CODE (t) == COMPONENT_REF && TREE_CODE (TREE_OPERAND (t, 1)) == FIELD_DECL && DECL_BIT_FIELD (TREE_OPERAND (t, 1))) { + gcc_assert (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_AFFINITY); error_at (OMP_CLAUSE_LOCATION (c), - "bit-field %qE in %qs clause", t, "depend"); + "bit-field %qE in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); remove = true; } - else if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_DEPOBJ) + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + && OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_DEPOBJ) { if (!c_omp_depend_t_p (TYPE_REF_P (TREE_TYPE (t)) ? TREE_TYPE (TREE_TYPE (t)) @@ -7531,9 +7549,10 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) remove = true; } } - else if (c_omp_depend_t_p (TYPE_REF_P (TREE_TYPE (t)) - ? TREE_TYPE (TREE_TYPE (t)) - : TREE_TYPE (t))) + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + && c_omp_depend_t_p (TYPE_REF_P (TREE_TYPE (t)) + ? TREE_TYPE (TREE_TYPE (t)) + : TREE_TYPE (t))) { error_at (OMP_CLAUSE_LOCATION (c), "%qE should not have % type in " -- cgit v1.1 From c94424b0ed786ec92b6904da69af8b5243b34fdc Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 28 May 2021 11:26:48 +0200 Subject: openmp: Fix up handling of reduction clause on constructs combined with target [PR99928] The reduction clause should be copied as map (tofrom: ) to combined target if present, but as we need different handling of array sections between map and reduction, doing that during gimplification would be harder. So, this patch adds them during splitting, and similarly to firstprivate adds them with a new flag that they should be just ignored/removed if an explicit map clause of the same list item is present. The exact rules are to be decided in https://github.com/OpenMP/spec/issues/2766 so this patch just implements something that is IMHO reasonable and exact detailed testcases for the cornercases will follow once it is clarified. 2021-05-28 Jakub Jelinek PR middle-end/99928 gcc/ * tree.h (OMP_CLAUSE_MAP_IMPLICIT): Define. gcc/c-family/ * c-omp.c (c_omp_split_clauses): For reduction clause if combined with target add a map tofrom clause with OMP_CLAUSE_MAP_IMPLICIT. gcc/c/ * c-typeck.c (handle_omp_array_sections): Copy OMP_CLAUSE_MAP_IMPLICIT. (c_finish_omp_clauses): Move not just OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT marked clauses last, but also OMP_CLAUSE_MAP_IMPLICIT. Add map_firstprivate_head bitmap, set it for GOMP_MAP_FIRSTPRIVATE_POINTER maps and silently remove OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT if it is present too. For OMP_CLAUSE_MAP_IMPLICIT silently remove the clause if present in map_head, map_field_head or map_firstprivate_head bitmaps. gcc/cp/ * semantics.c (handle_omp_array_sections): Copy OMP_CLAUSE_MAP_IMPLICIT. (finish_omp_clauses): Move not just OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT marked clauses last, but also OMP_CLAUSE_MAP_IMPLICIT. Add map_firstprivate_head bitmap, set it for GOMP_MAP_FIRSTPRIVATE_POINTER maps and silently remove OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT if it is present too. For OMP_CLAUSE_MAP_IMPLICIT silently remove the clause if present in map_head, map_field_head or map_firstprivate_head bitmaps. gcc/testsuite/ * c-c++-common/gomp/pr99928-8.c: Remove all xfails. * c-c++-common/gomp/pr99928-9.c: Likewise. * c-c++-common/gomp/pr99928-10.c: Likewise. * c-c++-common/gomp/pr99928-16.c: New test. --- gcc/cp/semantics.c | 65 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 52 insertions(+), 13 deletions(-) (limited to 'gcc/cp/semantics.c') diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 6fafd06..fe370a2 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -5548,6 +5548,7 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort) } else OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_FIRSTPRIVATE_POINTER); + OMP_CLAUSE_MAP_IMPLICIT (c2) = OMP_CLAUSE_MAP_IMPLICIT (c); if (OMP_CLAUSE_MAP_KIND (c2) != GOMP_MAP_FIRSTPRIVATE_POINTER && !cxx_mark_addressable (t)) return false; @@ -5574,6 +5575,7 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort) tree c3 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); OMP_CLAUSE_SET_MAP_KIND (c3, OMP_CLAUSE_MAP_KIND (c2)); + OMP_CLAUSE_MAP_IMPLICIT (c2) = OMP_CLAUSE_MAP_IMPLICIT (c); OMP_CLAUSE_DECL (c3) = ptr; if (OMP_CLAUSE_MAP_KIND (c2) == GOMP_MAP_ALWAYS_POINTER || OMP_CLAUSE_MAP_KIND (c2) == GOMP_MAP_ATTACH_DETACH) @@ -6510,7 +6512,8 @@ tree finish_omp_clauses (tree clauses, enum c_omp_region_type ort) { bitmap_head generic_head, firstprivate_head, lastprivate_head; - bitmap_head aligned_head, map_head, map_field_head, oacc_reduction_head; + bitmap_head aligned_head, map_head, map_field_head, map_firstprivate_head; + bitmap_head oacc_reduction_head; tree c, t, *pc; tree safelen = NULL_TREE; bool branch_seen = false; @@ -6527,7 +6530,7 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) bool allocate_seen = false; tree detach_seen = NULL_TREE; bool mergeable_seen = false; - bool firstprivate_implicit_moved = false; + bool implicit_moved = false; bitmap_obstack_initialize (NULL); bitmap_initialize (&generic_head, &bitmap_default_obstack); @@ -6537,6 +6540,7 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) /* If ort == C_ORT_OMP_DECLARE_SIMD used as uniform_head instead. */ bitmap_initialize (&map_head, &bitmap_default_obstack); bitmap_initialize (&map_field_head, &bitmap_default_obstack); + bitmap_initialize (&map_firstprivate_head, &bitmap_default_obstack); /* If ort == C_ORT_OMP used as nontemporal_head or use_device_xxx_head instead. */ bitmap_initialize (&oacc_reduction_head, &bitmap_default_obstack); @@ -6852,28 +6856,36 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) break; case OMP_CLAUSE_FIRSTPRIVATE: - if (OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT (c) - && !firstprivate_implicit_moved) + if (OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT (c) && !implicit_moved) { - firstprivate_implicit_moved = true; - /* Move firstprivate clauses with - OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT set to the end of + move_implicit: + implicit_moved = true; + /* Move firstprivate and map clauses with + OMP_CLAUSE_{FIRSTPRIVATE,MAP}_IMPLICIT set to the end of clauses chain. */ - tree cl = NULL, *pc1 = pc, *pc2 = &cl; + tree cl1 = NULL_TREE, cl2 = NULL_TREE; + tree *pc1 = pc, *pc2 = &cl1, *pc3 = &cl2; while (*pc1) if (OMP_CLAUSE_CODE (*pc1) == OMP_CLAUSE_FIRSTPRIVATE && OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT (*pc1)) { + *pc3 = *pc1; + pc3 = &OMP_CLAUSE_CHAIN (*pc3); + *pc1 = OMP_CLAUSE_CHAIN (*pc1); + } + else if (OMP_CLAUSE_CODE (*pc1) == OMP_CLAUSE_MAP + && OMP_CLAUSE_MAP_IMPLICIT (*pc1)) + { *pc2 = *pc1; pc2 = &OMP_CLAUSE_CHAIN (*pc2); *pc1 = OMP_CLAUSE_CHAIN (*pc1); } else pc1 = &OMP_CLAUSE_CHAIN (*pc1); - *pc2 = NULL; - *pc1 = cl; - if (pc1 != pc) - continue; + *pc3 = NULL; + *pc2 = cl2; + *pc1 = cl1; + continue; } t = omp_clause_decl_field (OMP_CLAUSE_DECL (c)); if (t) @@ -6904,6 +6916,10 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) t); remove = true; } + else if (OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT (c) + && !OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT_TARGET (c) + && bitmap_bit_p (&map_firstprivate_head, DECL_UID (t))) + remove = true; else if (bitmap_bit_p (&generic_head, DECL_UID (t)) || bitmap_bit_p (&firstprivate_head, DECL_UID (t))) { @@ -7620,6 +7636,9 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) break; case OMP_CLAUSE_MAP: + if (OMP_CLAUSE_MAP_IMPLICIT (c) && !implicit_moved) + goto move_implicit; + /* FALLTHRU */ case OMP_CLAUSE_TO: case OMP_CLAUSE_FROM: case OMP_CLAUSE__CACHE_: @@ -7651,6 +7670,16 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) t = TREE_OPERAND (t, 0); if (REFERENCE_REF_P (t)) t = TREE_OPERAND (t, 0); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP + && OMP_CLAUSE_MAP_IMPLICIT (c) + && (bitmap_bit_p (&map_head, DECL_UID (t)) + || bitmap_bit_p (&map_field_head, DECL_UID (t)) + || bitmap_bit_p (&map_firstprivate_head, + DECL_UID (t)))) + { + remove = true; + break; + } if (bitmap_bit_p (&map_field_head, DECL_UID (t))) break; if (bitmap_bit_p (&map_head, DECL_UID (t))) @@ -7832,6 +7861,13 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) remove = true; } else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP + && OMP_CLAUSE_MAP_IMPLICIT (c) + && (bitmap_bit_p (&map_head, DECL_UID (t)) + || bitmap_bit_p (&map_field_head, DECL_UID (t)) + || bitmap_bit_p (&map_firstprivate_head, + DECL_UID (t)))) + remove = true; + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER) { if (bitmap_bit_p (&generic_head, DECL_UID (t)) @@ -7852,7 +7888,10 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) remove = true; } else - bitmap_set_bit (&generic_head, DECL_UID (t)); + { + bitmap_set_bit (&generic_head, DECL_UID (t)); + bitmap_set_bit (&map_firstprivate_head, DECL_UID (t)); + } } else if (bitmap_bit_p (&map_head, DECL_UID (t)) && !bitmap_bit_p (&map_field_head, DECL_UID (t))) -- cgit v1.1 From 0f54cc9c63842ddfa921530cb499743cafc9b177 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 2 Apr 2021 22:20:43 -0400 Subject: tree-iterator: C++11 range-for and tree_stmt_iterator Like my recent patch to add ovl_range and lkp_range in the C++ front end, this patch adds the tsi_range adaptor for using C++11 range-based 'for' with a STATEMENT_LIST, e.g. for (tree stmt : tsi_range (stmt_list)) { ... } This also involves adding some operators to tree_stmt_iterator that are needed for range-for iterators, and should also be useful in code that uses the iterators directly. The patch updates the suitable loops in the C++ front end, but does not touch any loops elsewhere in the compiler. gcc/ChangeLog: * tree-iterator.h (struct tree_stmt_iterator): Add operator++, operator--, operator*, operator==, and operator!=. (class tsi_range): New. gcc/cp/ChangeLog: * constexpr.c (build_data_member_initialization): Use tsi_range. (build_constexpr_constructor_member_initializers): Likewise. (constexpr_fn_retval, cxx_eval_statement_list): Likewise. (potential_constant_expression_1): Likewise. * coroutines.cc (await_statement_expander): Likewise. (await_statement_walker): Likewise. * module.cc (trees_out::core_vals): Likewise. * pt.c (tsubst_expr): Likewise. * semantics.c (set_cleanup_locs): Likewise. --- gcc/cp/semantics.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'gcc/cp/semantics.c') diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index fe370a2..e40462d 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -613,9 +613,8 @@ set_cleanup_locs (tree stmts, location_t loc) set_cleanup_locs (CLEANUP_BODY (stmts), loc); } else if (TREE_CODE (stmts) == STATEMENT_LIST) - for (tree_stmt_iterator i = tsi_start (stmts); - !tsi_end_p (i); tsi_next (&i)) - set_cleanup_locs (tsi_stmt (i), loc); + for (tree stmt : tsi_range (stmts)) + set_cleanup_locs (stmt, loc); } /* Finish a scope. */ -- cgit v1.1 From 098f4e989beb1a1be1157430c56ea4f158c1d538 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 3 Jun 2021 10:38:08 +0200 Subject: openmp: Assorted depend/affinity/iterator related fixes [PR100859] The depend-iterator-3.C testcases shows various bugs. 1) tsubst_omp_clauses didn't handle OMP_CLAUSE_AFFINITY (should be handled like OMP_CLAUSE_DEPEND) 2) because locators can be arbitrary lvalue expressions, we need to allow for C++ array section base (especially when array section is just an array reference) FIELD_DECLs, handle them as this->member, but don't need to privatize in any way 3) similarly for this as base 4) depend(inout: this) is invalid, but for different reason than the reported one, again this is an expression, but not lvalue expression, so that should be reported 5) the ctor/dtor cloning in the C++ FE (which is using walk_tree with copy_tree_body_r) didn't handle iterators correctly, walk_tree normally doesn't walk TREE_PURPOSE of TREE_LIST, and in the iterator case that TREE_VEC contains also a BLOCK that needs special handling during copy_tree_body_r 2021-06-03 Jakub Jelinek PR c++/100859 gcc/ * tree-inline.c (copy_tree_body_r): Handle iterators on OMP_CLAUSE_AFFINITY or OMP_CLAUSE_DEPEND. gcc/c/ * c-typeck.c (c_finish_omp_clauses): Move OMP_CLAUSE_AFFINITY after depend only cases. gcc/cp/ * semantics.c (handle_omp_array_sections_1): For OMP_CLAUSE_{AFFINITY,DEPEND} handle FIELD_DECL base using finish_non_static_data_member and allow this as base. (finish_omp_clauses): Move OMP_CLAUSE_AFFINITY after depend only cases. Let this be diagnosed by !lvalue_p case for OMP_CLAUSE_{AFFINITY,DEPEND} and remove useless assert. * pt.c (tsubst_omp_clauses): Handle OMP_CLAUSE_AFFINITY. gcc/testsuite/ * g++.dg/gomp/depend-iterator-3.C: New test. * g++.dg/gomp/this-1.C: Don't expect any diagnostics for this as base expression of depend array section, expect a different error wording for this as depend locator and add testcases for affinity clauses. --- gcc/cp/semantics.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) (limited to 'gcc/cp/semantics.c') diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index e40462d..d08c1dd 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -4968,7 +4968,11 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, if (REFERENCE_REF_P (t)) t = TREE_OPERAND (t, 0); } - if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) + if (TREE_CODE (t) == FIELD_DECL + && (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_AFFINITY + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND)) + ret = finish_non_static_data_member (t, NULL_TREE, NULL_TREE); + else if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) { if (processing_template_decl && TREE_CODE (t) != OVERLOAD) return NULL_TREE; @@ -4985,7 +4989,9 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, else if (ort == C_ORT_OMP && TREE_CODE (t) == PARM_DECL && DECL_ARTIFICIAL (t) - && DECL_NAME (t) == this_identifier) + && DECL_NAME (t) == this_identifier + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_AFFINITY + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND) { error_at (OMP_CLAUSE_LOCATION (c), "% allowed in OpenMP only in %" @@ -7468,7 +7474,6 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) } goto handle_field_decl; - case OMP_CLAUSE_AFFINITY: case OMP_CLAUSE_DEPEND: t = OMP_CLAUSE_DECL (c); if (t == NULL_TREE) @@ -7477,13 +7482,15 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) == OMP_CLAUSE_DEPEND_SOURCE); break; } - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND - && OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK) + if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK) { if (cp_finish_omp_clause_depend_sink (c)) remove = true; break; } + /* FALLTHRU */ + case OMP_CLAUSE_AFFINITY: + t = OMP_CLAUSE_DECL (c); if (TREE_CODE (t) == TREE_LIST && TREE_PURPOSE (t) && TREE_CODE (TREE_PURPOSE (t)) == TREE_VEC) @@ -7516,13 +7523,6 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) } if (t == error_mark_node) remove = true; - else if (ort != C_ORT_ACC && t == current_class_ptr) - { - error_at (OMP_CLAUSE_LOCATION (c), - "% allowed in OpenMP only in %" - " clauses"); - remove = true; - } else if (processing_template_decl && TREE_CODE (t) != OVERLOAD) break; else if (!lvalue_p (t)) @@ -7543,11 +7543,9 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) && TREE_CODE (TREE_OPERAND (t, 1)) == FIELD_DECL && DECL_BIT_FIELD (TREE_OPERAND (t, 1))) { - gcc_assert (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_AFFINITY); error_at (OMP_CLAUSE_LOCATION (c), "bit-field %qE in %qs clause", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); remove = true; } else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND -- cgit v1.1 From f07edb5d7f3e77218ec846a9382f7c1d23e67b71 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 16 Apr 2021 11:13:40 -0400 Subject: c++: alias with same name as base fn [PR91706] This is a bit complex. Looking up c in the definition of D::c finds C::c, OK. Looking up c in the definition of E finds D::c, OK. Since the alias is not dependent, we strip it from the template argument, leaving using E = A())>; where 'c' still refers to C::c. But instantiating E looks up 'c' again and finds D::c, which isn't a function, and sadness ensues. I think the bug here is looking up 'c' in D at instantiation time; the declaration we found before is not dependent. This seems to happen because baselink_for_fns gets BASELINK_BINFO wrong; it is supposed to be the base where lookup found the functions, C in this case. gcc/cp/ChangeLog: PR c++/91706 * semantics.c (baselink_for_fns): Fix BASELINK_BINFO. gcc/testsuite/ChangeLog: PR c++/91706 * g++.dg/template/lookup17.C: New test. --- gcc/cp/semantics.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'gcc/cp/semantics.c') diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index d08c1dd..f506a23 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -3663,8 +3663,10 @@ baselink_for_fns (tree fns) cl = currently_open_derived_class (scope); if (!cl) cl = scope; - cl = TYPE_BINFO (cl); - return build_baselink (cl, cl, fns, /*optype=*/NULL_TREE); + tree access_path = TYPE_BINFO (cl); + tree conv_path = (cl == scope ? access_path + : lookup_base (cl, scope, ba_any, NULL, tf_none)); + return build_baselink (conv_path, access_path, fns, /*optype=*/NULL_TREE); } /* Returns true iff DECL is a variable from a function outside -- cgit v1.1 From 26dbe85a3781af913639b17bc966f4a0b8209f3b Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Wed, 9 Jun 2021 15:18:39 -0400 Subject: c++: Extend std::is_constant_evaluated in if warning [PR100995] Jakub pointed me at which shows that our existing warning could be extended to handle more cases. This patch implements that. A minor annoyance was handling macros, in libstdc++ we have reference operator[](size_type __pos) { __glibcxx_assert(__pos <= size()); ... } wherein __glibcxx_assert expands to if (__builtin_is_constant_evaluated() && !bool(__pos <= size()) ... but I'm of a mind to not warn on that. Once consteval if makes it in, we should tweak this warning one more time. PR c++/100995 gcc/cp/ChangeLog: * constexpr.c (maybe_constexpr_fn): New. * cp-tree.h (maybe_constexpr_fn): Declare. * semantics.c (find_std_constant_evaluated_r): New. (maybe_warn_for_constant_evaluated): New. (finish_if_stmt_cond): Call it. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/is-constant-evaluated9.C: Add dg-warning. * g++.dg/cpp2a/is-constant-evaluated12.C: New test. --- gcc/cp/semantics.c | 82 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 68 insertions(+), 14 deletions(-) (limited to 'gcc/cp/semantics.c') diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index f506a23..384c54b 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -927,6 +927,71 @@ is_std_constant_evaluated_p (tree fn) return name && id_equal (name, "is_constant_evaluated"); } +/* Callback function for maybe_warn_for_constant_evaluated that looks + for calls to std::is_constant_evaluated in TP. */ + +static tree +find_std_constant_evaluated_r (tree *tp, int *walk_subtrees, void *) +{ + tree t = *tp; + + if (TYPE_P (t) || TREE_CONSTANT (t)) + { + *walk_subtrees = false; + return NULL_TREE; + } + + switch (TREE_CODE (t)) + { + case CALL_EXPR: + if (is_std_constant_evaluated_p (t)) + return t; + break; + case EXPR_STMT: + /* Don't warn in statement expressions. */ + *walk_subtrees = false; + return NULL_TREE; + default: + break; + } + + return NULL_TREE; +} + +/* In certain contexts, std::is_constant_evaluated() is always true (for + instance, in a consteval function or in a constexpr if), or always false + (e.g., in a non-constexpr non-consteval function) so give the user a clue. */ + +static void +maybe_warn_for_constant_evaluated (tree cond, bool constexpr_if) +{ + if (!warn_tautological_compare) + return; + + /* Suppress warning for std::is_constant_evaluated if the conditional + comes from a macro. */ + if (from_macro_expansion_at (EXPR_LOCATION (cond))) + return; + + cond = cp_walk_tree_without_duplicates (&cond, find_std_constant_evaluated_r, + NULL); + if (cond) + { + if (constexpr_if) + warning_at (EXPR_LOCATION (cond), OPT_Wtautological_compare, + "% always evaluates to " + "true in %"); + else if (!maybe_constexpr_fn (current_function_decl)) + warning_at (EXPR_LOCATION (cond), OPT_Wtautological_compare, + "% always evaluates to " + "false in a non-% function"); + else if (DECL_IMMEDIATE_FUNCTION_P (current_function_decl)) + warning_at (EXPR_LOCATION (cond), OPT_Wtautological_compare, + "% always evaluates to " + "true in a % function"); + } +} + /* Process the COND of an if-statement, which may be given by IF_STMT. */ @@ -942,23 +1007,12 @@ finish_if_stmt_cond (tree cond, tree if_stmt) converted to bool. */ && TYPE_MAIN_VARIANT (TREE_TYPE (cond)) == boolean_type_node) { - /* if constexpr (std::is_constant_evaluated()) is always true, - so give the user a clue. */ - if (warn_tautological_compare) - { - tree t = cond; - if (TREE_CODE (t) == CLEANUP_POINT_EXPR) - t = TREE_OPERAND (t, 0); - if (TREE_CODE (t) == CALL_EXPR - && is_std_constant_evaluated_p (t)) - warning_at (EXPR_LOCATION (cond), OPT_Wtautological_compare, - "%qs always evaluates to true in %", - "std::is_constant_evaluated"); - } - + maybe_warn_for_constant_evaluated (cond, /*constexpr_if=*/true); cond = instantiate_non_dependent_expr (cond); cond = cxx_constant_value (cond, NULL_TREE); } + else + maybe_warn_for_constant_evaluated (cond, /*constexpr_if=*/false); finish_cond (&IF_COND (if_stmt), cond); add_stmt (if_stmt); THEN_CLAUSE (if_stmt) = push_stmt_list (); -- cgit v1.1 From 7619d33471c10fe3d149dcbb701d99ed3dd23528 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 24 Jun 2021 11:25:34 +0200 Subject: openmp: in_reduction clause support on target construct This patch adds support for in_reduction clause on target construct, though for now only for synchronous targets (without nowait clause). The encountering thread in that case runs the target task and blocks until the target region ends, so it is implemented by remapping it before entering the target, initializing the private copy if not yet initialized for the current thread and then using the remapped addresses for the mapping addresses. For nowait combined with in_reduction the patch contains a hack where the nowait clause is ignored. To implement it correctly, I think we would need to create a new private variable for the in_reduction and initialize it before doing the async target and adjust the map addresses to that private variable and then pass a function pointer to the library routine with code where the callback would remap the address to the current threads private variable and use in_reduction combiner to combine the private variable we've created into the thread's copy. The library would then need to make sure that the routine is called in some thread participating in the parallel (and not in an unshackeled thread). 2021-06-24 Jakub Jelinek gcc/ * tree.h (OMP_CLAUSE_MAP_IN_REDUCTION): Document meaning for OpenMP. * gimplify.c (gimplify_scan_omp_clauses): For OpenMP map clauses with OMP_CLAUSE_MAP_IN_REDUCTION flag partially defer gimplification of non-decl OMP_CLAUSE_DECL. For OMP_CLAUSE_IN_REDUCTION on OMP_TARGET user outer_ctx instead of ctx for placeholders and initializer/combiner gimplification. * omp-low.c (scan_sharing_clauses): Handle OMP_CLAUSE_MAP_IN_REDUCTION on target constructs. (lower_rec_input_clauses): Likewise. (lower_omp_target): Likewise. * omp-expand.c (expand_omp_target): Temporarily ignore nowait clause on target if in_reduction is present. gcc/c-family/ * c-common.h (enum c_omp_region_type): Add C_ORT_TARGET and C_ORT_OMP_TARGET. * c-omp.c (c_omp_split_clauses): For OMP_CLAUSE_IN_REDUCTION on combined target constructs also add map (always, tofrom:) clause. gcc/c/ * c-parser.c (omp_split_clauses): Pass C_ORT_OMP_TARGET instead of C_ORT_OMP for clauses on target construct. (OMP_TARGET_CLAUSE_MASK): Add in_reduction clause. (c_parser_omp_target): For non-combined target add map (always, tofrom:) clauses for OMP_CLAUSE_IN_REDUCTION. Pass C_ORT_OMP_TARGET to c_finish_omp_clauses. * c-typeck.c (handle_omp_array_sections): Adjust ort handling for addition of C_ORT_OMP_TARGET and simplify, mapping clauses are never present on C_ORT_*DECLARE_SIMD. (c_finish_omp_clauses): Likewise. Handle OMP_CLAUSE_IN_REDUCTION on C_ORT_OMP_TARGET, set OMP_CLAUSE_MAP_IN_REDUCTION on corresponding map clauses. gcc/cp/ * parser.c (cp_omp_split_clauses): Pass C_ORT_OMP_TARGET instead of C_ORT_OMP for clauses on target construct. (OMP_TARGET_CLAUSE_MASK): Add in_reduction clause. (cp_parser_omp_target): For non-combined target add map (always, tofrom:) clauses for OMP_CLAUSE_IN_REDUCTION. Pass C_ORT_OMP_TARGET to finish_omp_clauses. * semantics.c (handle_omp_array_sections_1): Adjust ort handling for addition of C_ORT_OMP_TARGET and simplify, mapping clauses are never present on C_ORT_*DECLARE_SIMD. (handle_omp_array_sections): Likewise. (finish_omp_clauses): Likewise. Handle OMP_CLAUSE_IN_REDUCTION on C_ORT_OMP_TARGET, set OMP_CLAUSE_MAP_IN_REDUCTION on corresponding map clauses. * pt.c (tsubst_expr): Pass C_ORT_OMP_TARGET instead of C_ORT_OMP for clauses on target construct. gcc/testsuite/ * c-c++-common/gomp/target-in-reduction-1.c: New test. * c-c++-common/gomp/clauses-1.c: Add in_reduction clauses on target or combined target constructs. libgomp/ * testsuite/libgomp.c-c++-common/target-in-reduction-1.c: New test. * testsuite/libgomp.c-c++-common/target-in-reduction-2.c: New test. * testsuite/libgomp.c++/target-in-reduction-1.C: New test. * testsuite/libgomp.c++/target-in-reduction-2.C: New test. --- gcc/cp/semantics.c | 111 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 68 insertions(+), 43 deletions(-) (limited to 'gcc/cp/semantics.c') diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 384c54b..fbaabf6 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -5042,7 +5042,7 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); return error_mark_node; } - else if (ort == C_ORT_OMP + else if ((ort & C_ORT_OMP_DECLARE_SIMD) == C_ORT_OMP && TREE_CODE (t) == PARM_DECL && DECL_ARTIFICIAL (t) && DECL_NAME (t) == this_identifier @@ -5069,7 +5069,7 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, return ret; } - if (ort == C_ORT_OMP + if ((ort & C_ORT_OMP_DECLARE_SIMD) == C_ORT_OMP && (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TASK_REDUCTION) @@ -5571,33 +5571,30 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort) || (TREE_CODE (t) == COMPONENT_REF && TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)) return false; - if (ort == C_ORT_OMP || ort == C_ORT_ACC) - switch (OMP_CLAUSE_MAP_KIND (c)) - { - case GOMP_MAP_ALLOC: - case GOMP_MAP_IF_PRESENT: - case GOMP_MAP_TO: - case GOMP_MAP_FROM: - case GOMP_MAP_TOFROM: - case GOMP_MAP_ALWAYS_TO: - case GOMP_MAP_ALWAYS_FROM: - case GOMP_MAP_ALWAYS_TOFROM: - case GOMP_MAP_RELEASE: - case GOMP_MAP_DELETE: - case GOMP_MAP_FORCE_TO: - case GOMP_MAP_FORCE_FROM: - case GOMP_MAP_FORCE_TOFROM: - case GOMP_MAP_FORCE_PRESENT: - OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION (c) = 1; - break; - default: - break; - } + switch (OMP_CLAUSE_MAP_KIND (c)) + { + case GOMP_MAP_ALLOC: + case GOMP_MAP_IF_PRESENT: + case GOMP_MAP_TO: + case GOMP_MAP_FROM: + case GOMP_MAP_TOFROM: + case GOMP_MAP_ALWAYS_TO: + case GOMP_MAP_ALWAYS_FROM: + case GOMP_MAP_ALWAYS_TOFROM: + case GOMP_MAP_RELEASE: + case GOMP_MAP_DELETE: + case GOMP_MAP_FORCE_TO: + case GOMP_MAP_FORCE_FROM: + case GOMP_MAP_FORCE_TOFROM: + case GOMP_MAP_FORCE_PRESENT: + OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION (c) = 1; + break; + default: + break; + } tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); - if ((ort & C_ORT_OMP_DECLARE_SIMD) != C_ORT_OMP && ort != C_ORT_ACC) - OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_POINTER); - else if (TREE_CODE (t) == COMPONENT_REF) + if (TREE_CODE (t) == COMPONENT_REF) OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_ATTACH_DETACH); else if (REFERENCE_REF_P (t) && TREE_CODE (TREE_OPERAND (t, 0)) == COMPONENT_REF) @@ -6592,6 +6589,7 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) tree detach_seen = NULL_TREE; bool mergeable_seen = false; bool implicit_moved = false; + bool target_in_reduction_seen = false; bitmap_obstack_initialize (NULL); bitmap_initialize (&generic_head, &bitmap_default_obstack); @@ -6603,7 +6601,7 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) bitmap_initialize (&map_field_head, &bitmap_default_obstack); bitmap_initialize (&map_firstprivate_head, &bitmap_default_obstack); /* If ort == C_ORT_OMP used as nontemporal_head or use_device_xxx_head - instead. */ + instead and for ort == C_ORT_OMP_TARGET used as in_reduction_head. */ bitmap_initialize (&oacc_reduction_head, &bitmap_default_obstack); if (ort & C_ORT_ACC) @@ -6866,8 +6864,22 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) || (ort == C_ORT_OMP && (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_USE_DEVICE_PTR || (OMP_CLAUSE_CODE (c) - == OMP_CLAUSE_USE_DEVICE_ADDR)))) + == OMP_CLAUSE_USE_DEVICE_ADDR))) + || (ort == C_ORT_OMP_TARGET + && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION)) { + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION + && (bitmap_bit_p (&generic_head, DECL_UID (t)) + || bitmap_bit_p (&firstprivate_head, DECL_UID (t)))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD appears more than once in data-sharing " + "clauses", t); + remove = true; + break; + } + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION) + target_in_reduction_seen = true; if (bitmap_bit_p (&oacc_reduction_head, DECL_UID (t))) { error_at (OMP_CLAUSE_LOCATION (c), @@ -6882,7 +6894,8 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) } else if (bitmap_bit_p (&generic_head, DECL_UID (t)) || bitmap_bit_p (&firstprivate_head, DECL_UID (t)) - || bitmap_bit_p (&lastprivate_head, DECL_UID (t))) + || bitmap_bit_p (&lastprivate_head, DECL_UID (t)) + || bitmap_bit_p (&map_firstprivate_head, DECL_UID (t))) { error_at (OMP_CLAUSE_LOCATION (c), "%qD appears more than once in data clauses", t); @@ -6982,7 +6995,8 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) && bitmap_bit_p (&map_firstprivate_head, DECL_UID (t))) remove = true; else if (bitmap_bit_p (&generic_head, DECL_UID (t)) - || bitmap_bit_p (&firstprivate_head, DECL_UID (t))) + || bitmap_bit_p (&firstprivate_head, DECL_UID (t)) + || bitmap_bit_p (&map_firstprivate_head, DECL_UID (t))) { error_at (OMP_CLAUSE_LOCATION (c), "%qD appears more than once in data clauses", t); @@ -7795,13 +7809,10 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) t = TREE_OPERAND (t, 0); OMP_CLAUSE_DECL (c) = t; } - if ((ort == C_ORT_ACC || ort == C_ORT_OMP) - && TREE_CODE (t) == COMPONENT_REF + if (TREE_CODE (t) == COMPONENT_REF && TREE_CODE (TREE_OPERAND (t, 0)) == INDIRECT_REF) t = TREE_OPERAND (TREE_OPERAND (t, 0), 0); if (TREE_CODE (t) == COMPONENT_REF - && ((ort & C_ORT_OMP_DECLARE_SIMD) == C_ORT_OMP - || ort == C_ORT_ACC) && OMP_CLAUSE_CODE (c) != OMP_CLAUSE__CACHE_) { if (type_dependent_expression_p (t)) @@ -7842,7 +7853,7 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) if (VAR_P (t) || TREE_CODE (t) == PARM_DECL) { if (bitmap_bit_p (&map_field_head, DECL_UID (t)) - || (ort == C_ORT_OMP + || (ort != C_ORT_ACC && bitmap_bit_p (&map_head, DECL_UID (t)))) goto handle_map_references; } @@ -7924,7 +7935,8 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER) { if (bitmap_bit_p (&generic_head, DECL_UID (t)) - || bitmap_bit_p (&firstprivate_head, DECL_UID (t))) + || bitmap_bit_p (&firstprivate_head, DECL_UID (t)) + || bitmap_bit_p (&map_firstprivate_head, DECL_UID (t))) { error_at (OMP_CLAUSE_LOCATION (c), "%qD appears more than once in data clauses", t); @@ -7941,10 +7953,7 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) remove = true; } else - { - bitmap_set_bit (&generic_head, DECL_UID (t)); - bitmap_set_bit (&map_firstprivate_head, DECL_UID (t)); - } + bitmap_set_bit (&map_firstprivate_head, DECL_UID (t)); } else if (bitmap_bit_p (&map_head, DECL_UID (t)) && !bitmap_bit_p (&map_field_head, DECL_UID (t))) @@ -7960,8 +7969,8 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) "%qD appears more than once in map clauses", t); remove = true; } - else if (bitmap_bit_p (&generic_head, DECL_UID (t)) - && ort == C_ORT_ACC) + else if (ort == C_ORT_ACC + && bitmap_bit_p (&generic_head, DECL_UID (t))) { error_at (OMP_CLAUSE_LOCATION (c), "%qD appears more than once in data clauses", t); @@ -8511,6 +8520,22 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) } pc = &OMP_CLAUSE_CHAIN (c); continue; + case OMP_CLAUSE_MAP: + if (target_in_reduction_seen && !processing_template_decl) + { + t = OMP_CLAUSE_DECL (c); + while (handled_component_p (t) + || TREE_CODE (t) == INDIRECT_REF + || TREE_CODE (t) == ADDR_EXPR + || TREE_CODE (t) == MEM_REF + || TREE_CODE (t) == NON_LVALUE_EXPR) + t = TREE_OPERAND (t, 0); + if (DECL_P (t) + && bitmap_bit_p (&oacc_reduction_head, DECL_UID (t))) + OMP_CLAUSE_MAP_IN_REDUCTION (c) = 1; + } + pc = &OMP_CLAUSE_CHAIN (c); + continue; case OMP_CLAUSE_NOWAIT: if (copyprivate_seen) { -- cgit v1.1 From 65870e75616ee4359d1c13b99be794e6a577bc65 Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Thu, 24 Jun 2021 17:29:34 -0600 Subject: cp: add support for per-location warning groups. gcc/cp/ChangeLog: * call.c (build_over_call): Replace direct uses of TREE_NO_WARNING with warning_suppressed_p, suppress_warning, and copy_no_warning, or nothing if not necessary. (set_up_extended_ref_temp): Same. * class.c (layout_class_type): Same. * constraint.cc (constraint_satisfaction_value): Same. * coroutines.cc (finish_co_await_expr): Same. (finish_co_yield_expr): Same. (finish_co_return_stmt): Same. (build_actor_fn): Same. (coro_rewrite_function_body): Same. (morph_fn_to_coro): Same. * cp-gimplify.c (genericize_eh_spec_block): Same. (gimplify_expr_stmt): Same. (cp_genericize_r): Same. (cp_fold): Same. * cp-ubsan.c (cp_ubsan_instrument_vptr): Same. * cvt.c (cp_fold_convert): Same. (convert_to_void): Same. * decl.c (wrapup_namespace_globals): Same. (grokdeclarator): Same. (finish_function): Same. (require_deduced_type): Same. * decl2.c (no_linkage_error): Same. (c_parse_final_cleanups): Same. * except.c (expand_end_catch_block): Same. * init.c (build_new_1): Same. (build_new): Same. (build_vec_delete_1): Same. (build_vec_init): Same. (build_delete): Same. * method.c (defaultable_fn_check): Same. * parser.c (cp_parser_fold_expression): Same. (cp_parser_primary_expression): Same. * pt.c (push_tinst_level_loc): Same. (tsubst_copy): Same. (tsubst_omp_udr): Same. (tsubst_copy_and_build): Same. * rtti.c (build_if_nonnull): Same. * semantics.c (maybe_convert_cond): Same. (finish_return_stmt): Same. (finish_parenthesized_expr): Same. (cp_check_omp_declare_reduction): Same. * tree.c (build_cplus_array_type): Same. * typeck.c (build_ptrmemfunc_access_expr): Same. (cp_build_indirect_ref_1): Same. (cp_build_function_call_vec): Same. (warn_for_null_address): Same. (cp_build_binary_op): Same. (unary_complex_lvalue): Same. (cp_build_modify_expr): Same. (build_x_modify_expr): Same. (convert_for_assignment): Same. --- gcc/cp/semantics.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'gcc/cp/semantics.c') diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index fbaabf6..b080259 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -835,12 +835,12 @@ maybe_convert_cond (tree cond) cond = convert_from_reference (cond); if (TREE_CODE (cond) == MODIFY_EXPR - && !TREE_NO_WARNING (cond) && warn_parentheses + && !warning_suppressed_p (cond, OPT_Wparentheses) && warning_at (cp_expr_loc_or_input_loc (cond), OPT_Wparentheses, "suggest parentheses around " "assignment used as truth value")) - TREE_NO_WARNING (cond) = 1; + suppress_warning (cond, OPT_Wparentheses); return condition_conversion (cond); } @@ -1197,7 +1197,7 @@ finish_return_stmt (tree expr) { /* Suppress -Wreturn-type for this function. */ if (warn_return_type) - TREE_NO_WARNING (current_function_decl) = true; + suppress_warning (current_function_decl, OPT_Wreturn_type); return error_mark_node; } @@ -1219,7 +1219,8 @@ finish_return_stmt (tree expr) } r = build_stmt (input_location, RETURN_EXPR, expr); - TREE_NO_WARNING (r) |= no_warning; + if (no_warning) + suppress_warning (r, OPT_Wreturn_type); r = maybe_cleanup_point_expr_void (r); r = add_stmt (r); @@ -2105,7 +2106,7 @@ finish_parenthesized_expr (cp_expr expr) { if (EXPR_P (expr)) /* This inhibits warnings in c_common_truthvalue_conversion. */ - TREE_NO_WARNING (expr) = 1; + suppress_warning (expr, OPT_Wparentheses); if (TREE_CODE (expr) == OFFSET_REF || TREE_CODE (expr) == SCOPE_REF) @@ -5979,12 +5980,12 @@ cp_check_omp_declare_reduction (tree udr) { gcc_assert (TREE_CODE (data.stmts[0]) == DECL_EXPR && TREE_CODE (data.stmts[1]) == DECL_EXPR); - if (TREE_NO_WARNING (DECL_EXPR_DECL (data.stmts[0]))) + if (warning_suppressed_p (DECL_EXPR_DECL (data.stmts[0]) /* What warning? */)) return true; data.combiner_p = true; if (cp_walk_tree (&data.stmts[2], cp_check_omp_declare_reduction_r, &data, NULL)) - TREE_NO_WARNING (DECL_EXPR_DECL (data.stmts[0])) = 1; + suppress_warning (DECL_EXPR_DECL (data.stmts[0]) /* What warning? */); } if (i >= 6) { @@ -5995,7 +5996,7 @@ cp_check_omp_declare_reduction (tree udr) &data, NULL) || cp_walk_tree (&DECL_INITIAL (DECL_EXPR_DECL (data.stmts[3])), cp_check_omp_declare_reduction_r, &data, NULL)) - TREE_NO_WARNING (DECL_EXPR_DECL (data.stmts[0])) = 1; + suppress_warning (DECL_EXPR_DECL (data.stmts[0]) /* Wat warning? */); if (i == 7) gcc_assert (TREE_CODE (data.stmts[6]) == DECL_EXPR); } -- cgit v1.1 From 91bb571d200e551f427e337e00494e0b4f229876 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 13 Jul 2021 14:42:09 -0400 Subject: vec: use auto_vec in a few more places The uses of vec in get_all_loop_exits and process_conditional were memory leaks, as .release() was never called for them. The other changes are some cases that did have proper release handling, but it's simpler to leave releasing to the auto_vec destructor. gcc/ChangeLog: * sel-sched-ir.h (get_all_loop_exits): Use auto_vec. gcc/cp/ChangeLog: * class.c (struct find_final_overrider_data): Use auto_vec. (find_final_overrider): Remove explicit release. * coroutines.cc (process_conditional): Use auto_vec. * cp-gimplify.c (struct cp_genericize_data): Use auto_vec. (cp_genericize_tree): Remove explicit release. * parser.c (cp_parser_objc_at_property_declaration): Use auto_delete_vec. * semantics.c (omp_reduction_lookup): Use auto_vec. --- gcc/cp/semantics.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'gcc/cp/semantics.c') diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index b080259..b97dc1f 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -5774,7 +5774,7 @@ omp_reduction_lookup (location_t loc, tree id, tree type, tree *baselinkp, if (!id && CLASS_TYPE_P (type) && TYPE_BINFO (type)) { - vec ambiguous = vNULL; + auto_vec ambiguous; tree binfo = TYPE_BINFO (type), base_binfo, ret = NULL_TREE; unsigned int ix; if (ambiguousp == NULL) @@ -5811,7 +5811,6 @@ omp_reduction_lookup (location_t loc, tree id, tree type, tree *baselinkp, if (idx == 0) str = get_spaces (str); } - ambiguous.release (); ret = error_mark_node; baselink = NULL_TREE; } -- cgit v1.1 From aea199f96cf116ba4c81426207acde371556610c Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Wed, 21 Jul 2021 09:38:59 +0200 Subject: c++: Ensure OpenMP reduction with reference type references complete type [PR101516] The following testcase ICEs because we haven't verified if reduction decl has reference type that TREE_TYPE of the reference is a complete type, require_complete_type on the decl doesn't ensure that. 2021-07-21 Jakub Jelinek PR c++/101516 * semantics.c (finish_omp_reduction_clause): Also call complete_type_or_else and return true if it fails. * g++.dg/gomp/pr101516.C: New test. --- gcc/cp/semantics.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'gcc/cp/semantics.c') diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index b97dc1f..331daf8 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -6070,7 +6070,8 @@ finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor) if (!processing_template_decl) { t = require_complete_type (t); - if (t == error_mark_node) + if (t == error_mark_node + || !complete_type_or_else (oatype, NULL_TREE)) return true; tree size = size_binop (EXACT_DIV_EXPR, TYPE_SIZE_UNIT (oatype), TYPE_SIZE_UNIT (type)); -- cgit v1.1 From a61f6afbee370785cf091fe46e2e022748528307 Mon Sep 17 00:00:00 2001 From: Thomas Schwinge Date: Wed, 21 Jul 2021 18:30:00 +0200 Subject: OpenACC 'nohost' clause Do not "compile a version of this procedure for the host". gcc/ * tree-core.h (omp_clause_code): Add 'OMP_CLAUSE_NOHOST'. * tree.c (omp_clause_num_ops, omp_clause_code_name, walk_tree_1): Handle it. * tree-pretty-print.c (dump_omp_clause): Likewise. * omp-general.c (oacc_verify_routine_clauses): Likewise. * gimplify.c (gimplify_scan_omp_clauses) (gimplify_adjust_omp_clauses): Likewise. * tree-nested.c (convert_nonlocal_omp_clauses) (convert_local_omp_clauses): Likewise. * omp-low.c (scan_sharing_clauses): Likewise. * omp-offload.c (execute_oacc_device_lower): Update. gcc/c-family/ * c-pragma.h (pragma_omp_clause): Add 'PRAGMA_OACC_CLAUSE_NOHOST'. gcc/c/ * c-parser.c (c_parser_omp_clause_name): Handle 'nohost'. (c_parser_oacc_all_clauses): Handle 'PRAGMA_OACC_CLAUSE_NOHOST'. (OACC_ROUTINE_CLAUSE_MASK): Add 'PRAGMA_OACC_CLAUSE_NOHOST'. * c-typeck.c (c_finish_omp_clauses): Handle 'OMP_CLAUSE_NOHOST'. gcc/cp/ * parser.c (cp_parser_omp_clause_name): Handle 'nohost'. (cp_parser_oacc_all_clauses): Handle 'PRAGMA_OACC_CLAUSE_NOHOST'. (OACC_ROUTINE_CLAUSE_MASK): Add 'PRAGMA_OACC_CLAUSE_NOHOST'. * pt.c (tsubst_omp_clauses): Handle 'OMP_CLAUSE_NOHOST'. * semantics.c (finish_omp_clauses): Likewise. gcc/fortran/ * dump-parse-tree.c (show_attr): Update. * gfortran.h (symbol_attribute): Add 'oacc_routine_nohost' member. (gfc_omp_clauses): Add 'nohost' member. * module.c (ab_attribute): Add 'AB_OACC_ROUTINE_NOHOST'. (attr_bits, mio_symbol_attribute): Update. * openmp.c (omp_mask2): Add 'OMP_CLAUSE_NOHOST'. (gfc_match_omp_clauses): Handle 'OMP_CLAUSE_NOHOST'. (OACC_ROUTINE_CLAUSES): Add 'OMP_CLAUSE_NOHOST'. (gfc_match_oacc_routine): Update. * trans-decl.c (add_attributes_to_decl): Update. * trans-openmp.c (gfc_trans_omp_clauses): Likewise. gcc/testsuite/ * c-c++-common/goacc/classify-routine-nohost.c: New file. * c-c++-common/goacc/classify-routine.c: Update. * c-c++-common/goacc/routine-2.c: Likewise. * c-c++-common/goacc/routine-nohost-1.c: New file. * c-c++-common/goacc/routine-nohost-2.c: Likewise. * g++.dg/goacc/template.C: Update. * gfortran.dg/goacc/classify-routine-nohost.f95: New file. * gfortran.dg/goacc/classify-routine.f95: Update. * gfortran.dg/goacc/pure-elemental-procedures-2.f90: Likewise. * gfortran.dg/goacc/routine-6.f90: Likewise. * gfortran.dg/goacc/routine-intrinsic-2.f: Likewise. * gfortran.dg/goacc/routine-module-1.f90: Likewise. * gfortran.dg/goacc/routine-module-2.f90: Likewise. * gfortran.dg/goacc/routine-module-3.f90: Likewise. * gfortran.dg/goacc/routine-module-mod-1.f90: Likewise. * gfortran.dg/goacc/routine-multiple-directives-1.f90: Likewise. * gfortran.dg/goacc/routine-multiple-directives-2.f90: Likewise. libgomp/ * testsuite/libgomp.oacc-c-c++-common/routine-nohost-1.c: New file. * testsuite/libgomp.oacc-c-c++-common/routine-nohost-2.c: Likewise. * testsuite/libgomp.oacc-c-c++-common/routine-nohost-2_2.c: Likewise. * testsuite/libgomp.oacc-fortran/routine-nohost-1.f90: Likewise. Co-Authored-By: Joseph Myers Co-Authored-By: Cesar Philippidis --- gcc/cp/semantics.c | 1 + 1 file changed, 1 insertion(+) (limited to 'gcc/cp/semantics.c') diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 331daf8..f64b084 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -8267,6 +8267,7 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) case OMP_CLAUSE_SEQ: case OMP_CLAUSE_IF_PRESENT: case OMP_CLAUSE_FINALIZE: + case OMP_CLAUSE_NOHOST: break; case OMP_CLAUSE_MERGEABLE: -- cgit v1.1 From 6cd005a255f15c1b4b3eaae71c844ea2592c9dce Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 30 Jul 2021 18:38:41 +0200 Subject: c++: Implement P0466R5 __cpp_lib_is_pointer_interconvertible compiler helpers [PR101539] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The following patch attempts to implement the compiler helpers for libstdc++ std::is_pointer_interconvertible_base_of trait and std::is_pointer_interconvertible_with_class template function. For the former __is_pointer_interconvertible_base_of trait that checks first whether base and derived aren't non-union class types that are the same ignoring toplevel cv-qualifiers, otherwise if derived is unambiguously derived from base without cv-qualifiers, derived being a complete type, and if so, my limited understanding of any derived object being pointer-interconvertible with base subobject IMHO implies (because one can't inherit from unions or unions can't inherit) that we check if derived is standard layout type and we walk bases of derived recursively, stopping on a class that has any non-static data members and check if any of the bases is base. On class with non-static data members no bases are compared already. Upon discussions, this is something that maybe should have been changed in the standard with CWG 2254 and the patch no longer performs this and assumes all base subobjects of standard-layout class types are pointer-interconvertible with the whole class objects. The latter is implemented using a FE __builtin_is_pointer_interconvertible_with_class, but because on the library side it will be a template function, the builtin takes ... arguments and only during folding verifies it has a single argument with pointer to member type. The initial errors IMHO can only happen if one uses the builtin incorrectly by hand, the template function should ensure that it has exactly a single argument that has pointer to member type. Otherwise, again with my limited understanding of what the template function should do and pointer-interconvertibility, it folds to false for pointer-to-member-function, errors if basetype of the OFFSET_TYPE is incomplete, folds to false for non-std-layout non-union basetype, then finds the first non-static data member in the basetype or its bases (by ignoring DECL_FIELD_IS_BASE FIELD_DECLs that are empty, recursing into DECL_FIELD_IS_BASE FIELD_DECLs type that are non-empty (I think std layout should ensure there is at most one), for unions checks if membertype is same type as any of the union FIELD_DECLs, for non-unions the first other FIELD_DECL only, and for anonymous aggregates similarly (union vs. non-union) but recurses into the anon aggr types with std layout check for anon structures. If membertype doesn't match the type of first non-static data member (or for unions any of the members), then the builtin folds to false, otherwise the built folds to a check whether the argument is equal to OFFSET_TYPE of 0 or not, either at compile time if it is constant (e.g. for constexpr folding) or at runtime otherwise. As I wrote in the PR, I've tried my testcases with MSVC on godbolt that claims to implement it, and https://godbolt.org/z/3PnjM33vM for the first testcase shows it disagrees with my expectations on static_assert (std::is_pointer_interconvertible_base_of_v); static_assert (std::is_pointer_interconvertible_base_of_v); static_assert (!std::is_pointer_interconvertible_base_of_v); static_assert (!std::is_pointer_interconvertible_base_of_v); static_assert (std::is_pointer_interconvertible_base_of_v); Is that a bug in my patch or is MSVC buggy on these (or mix thereof)? https://godbolt.org/z/aYeYnne9d shows the second testcase, here it differs on: static_assert (std::is_pointer_interconvertible_with_class (&F::b)); static_assert (std::is_pointer_interconvertible_with_class (&I::g)); static_assert (std::is_pointer_interconvertible_with_class (&L::b)); static_assert (std::is_pointer_interconvertible_with_class (&V::a)); static_assert (std::is_pointer_interconvertible_with_class (&V::b)); Again, my bug, MSVC bug, mix thereof? According to Jason the , case are the subject of the CWG 2254 above discussed change and the rest are likely MSVC bugs. Oh, and there is another thing, the standard has an example: struct A { int a; }; // a standard-layout class struct B { int b; }; // a standard-layout class struct C: public A, public B { }; // not a standard-layout class static_assert( is_pointer_interconvertible_with_class( &C::b ) ); // Succeeds because, despite its appearance, &C::b has type // “pointer to member of B of type int”. static_assert( is_pointer_interconvertible_with_class( &C::b ) ); // Forces the use of class C, and fails. It seems to work as written with MSVC (second assertion fails), but fails with GCC with the patch: /tmp/1.C:22:57: error: no matching function for call to ‘is_pointer_interconvertible_with_class(int B::*)’ 22 | static_assert( is_pointer_interconvertible_with_class( &C::b ) ); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~ /tmp/1.C:8:1: note: candidate: ‘template constexpr bool std::is_pointer_interconvertible_with_class(M S::*)’ 8 | is_pointer_interconvertible_with_class (M S::*m) noexcept | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /tmp/1.C:8:1: note: template argument deduction/substitution failed: /tmp/1.C:22:57: note: mismatched types ‘C’ and ‘B’ 22 | static_assert( is_pointer_interconvertible_with_class( &C::b ) ); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~ the second int argument isn't deduced. This boils down to: template bool foo (M S::*m) noexcept; struct A { int a; }; struct B { int b; }; struct C : public A, public B {}; bool a = foo (&C::b); bool b = foo (&C::b); bool c = foo (&C::b); which with /std:c++20 or -std=c++20 is accepted by latest MSVC and ICC but rejected by GCC and clang (in both cases on the last line). Is this a GCC/clang bug in argument deduction (in that case I think we want a separate PR), or a bug in ICC/MSVC and the standard itself that should specify in the examples both template arguments instead of just the first? And this has been raised with the CWG. 2021-07-30 Jakub Jelinek PR c++/101539 gcc/c-family/ * c-common.h (enum rid): Add RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF. * c-common.c (c_common_reswords): Add __is_pointer_interconvertible_base_of. gcc/cp/ * cp-tree.h (enum cp_trait_kind): Add CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF. (enum cp_built_in_function): Add CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS. (fold_builtin_is_pointer_inverconvertible_with_class): Declare. * parser.c (cp_parser_primary_expression): Handle RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF. (cp_parser_trait_expr): Likewise. * cp-objcp-common.c (names_builtin_p): Likewise. * constraint.cc (diagnose_trait_expr): Handle CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF. * decl.c (cxx_init_decl_processing): Register __builtin_is_pointer_interconvertible_with_class builtin. * constexpr.c (cxx_eval_builtin_function_call): Handle CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS builtin. * semantics.c (pointer_interconvertible_base_of_p, first_nonstatic_data_member_p, fold_builtin_is_pointer_inverconvertible_with_class): New functions. (trait_expr_value): Handle CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF. (finish_trait_expr): Likewise. Formatting fix. * cp-gimplify.c (cp_gimplify_expr): Fold CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS. Call fndecl_built_in_p just once. (cp_fold): Likewise. * tree.c (builtin_valid_in_constant_expr_p): Handle CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS. Call fndecl_built_in_p just once. * cxx-pretty-print.c (pp_cxx_trait_expression): Handle CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF. gcc/testsuite/ * g++.dg/cpp2a/is-pointer-interconvertible-base-of1.C: New test. * g++.dg/cpp2a/is-pointer-interconvertible-with-class1.C: New test. * g++.dg/cpp2a/is-pointer-interconvertible-with-class2.C: New test. * g++.dg/cpp2a/is-pointer-interconvertible-with-class3.C: New test. * g++.dg/cpp2a/is-pointer-interconvertible-with-class4.C: New test. * g++.dg/cpp2a/is-pointer-interconvertible-with-class5.C: New test. * g++.dg/cpp2a/is-pointer-interconvertible-with-class6.C: New test. --- gcc/cp/semantics.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 111 insertions(+), 3 deletions(-) (limited to 'gcc/cp/semantics.c') diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index f64b084..34e5d76 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -10566,6 +10566,110 @@ classtype_has_nothrow_assign_or_copy_p (tree type, bool assign_p) return saw_copy; } +/* Return true if DERIVED is pointer interconvertible base of BASE. */ + +static bool +pointer_interconvertible_base_of_p (tree base, tree derived) +{ + if (base == error_mark_node || derived == error_mark_node) + return false; + base = TYPE_MAIN_VARIANT (base); + derived = TYPE_MAIN_VARIANT (derived); + if (!NON_UNION_CLASS_TYPE_P (base) + || !NON_UNION_CLASS_TYPE_P (derived)) + return false; + + if (same_type_p (base, derived)) + return true; + + if (!std_layout_type_p (derived)) + return false; + + return uniquely_derived_from_p (base, derived); +} + +/* Helper function for fold_builtin_is_pointer_inverconvertible_with_class, + return true if MEMBERTYPE is the type of the first non-static data member + of TYPE or for unions of any members. */ +static bool +first_nonstatic_data_member_p (tree type, tree membertype) +{ + for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) + { + if (TREE_CODE (field) != FIELD_DECL) + continue; + if (DECL_FIELD_IS_BASE (field) && is_empty_field (field)) + continue; + if (DECL_FIELD_IS_BASE (field)) + return first_nonstatic_data_member_p (TREE_TYPE (field), membertype); + if (ANON_AGGR_TYPE_P (TREE_TYPE (field))) + { + if ((TREE_CODE (TREE_TYPE (field)) == UNION_TYPE + || std_layout_type_p (TREE_TYPE (field))) + && first_nonstatic_data_member_p (TREE_TYPE (field), membertype)) + return true; + } + else if (same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (field), + membertype)) + return true; + if (TREE_CODE (type) != UNION_TYPE) + return false; + } + return false; +} + +/* Fold __builtin_is_pointer_interconvertible_with_class call. */ + +tree +fold_builtin_is_pointer_inverconvertible_with_class (location_t loc, int nargs, + tree *args) +{ + /* Unless users call the builtin directly, the following 3 checks should be + ensured from std::is_pointer_interconvertible_with_class function + template. */ + if (nargs != 1) + { + error_at (loc, "%<__builtin_is_pointer_interconvertible_with_class%> " + "needs a single argument"); + return boolean_false_node; + } + tree arg = args[0]; + if (error_operand_p (arg)) + return boolean_false_node; + if (!TYPE_PTRMEM_P (TREE_TYPE (arg))) + { + error_at (loc, "%<__builtin_is_pointer_interconvertible_with_class%> " + "argument is not pointer to member"); + return boolean_false_node; + } + + if (!TYPE_PTRDATAMEM_P (TREE_TYPE (arg))) + return boolean_false_node; + + tree membertype = TREE_TYPE (TREE_TYPE (arg)); + tree basetype = TYPE_OFFSET_BASETYPE (TREE_TYPE (arg)); + if (!complete_type_or_else (basetype, NULL_TREE)) + return boolean_false_node; + + if (TREE_CODE (basetype) != UNION_TYPE + && !std_layout_type_p (basetype)) + return boolean_false_node; + + if (!first_nonstatic_data_member_p (basetype, membertype)) + return boolean_false_node; + + if (TREE_CODE (arg) == PTRMEM_CST) + arg = cplus_expand_constant (arg); + + if (integer_nonzerop (arg)) + return boolean_false_node; + if (integer_zerop (arg)) + return boolean_true_node; + + return fold_build2 (EQ_EXPR, boolean_type_node, arg, + build_zero_cst (TREE_TYPE (arg))); +} + /* Actually evaluates the trait. */ static bool @@ -10659,6 +10763,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2) case CPTK_IS_LITERAL_TYPE: return literal_type_p (type1); + case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF: + return pointer_interconvertible_base_of_p (type1, type2); + case CPTK_IS_POD: return pod_type_p (type1); @@ -10786,6 +10893,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2) break; case CPTK_IS_BASE_OF: + case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF: if (NON_UNION_CLASS_TYPE_P (type1) && NON_UNION_CLASS_TYPE_P (type2) && !same_type_ignoring_top_level_qualifiers_p (type1, type2) && !complete_type_or_else (type2, NULL_TREE)) @@ -10803,9 +10911,9 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2) gcc_unreachable (); } -tree val = (trait_expr_value (kind, type1, type2) - ? boolean_true_node : boolean_false_node); - return maybe_wrap_with_location (val, loc); + tree val = (trait_expr_value (kind, type1, type2) + ? boolean_true_node : boolean_false_node); + return maybe_wrap_with_location (val, loc); } /* Do-nothing variants of functions to handle pragma FLOAT_CONST_DECIMAL64, -- cgit v1.1 From 01f8a8b48e50cbaa68b878d9f8a330b8c0736bed Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 12 Aug 2021 09:26:27 +0200 Subject: openmp: Diagnose syntax mismatches between declare target and end declare target OpenMP 5.1 says: For any directive that has a paired end directive, including those with a begin and end pair, both directives must use either the attribute syntax or the pragma syntax. The following patch enforces it with the only pair so far recognized in C++ (Fortran has many, but on the other side doesn't have attribute syntax). While I initially wanted to use vec *member; in there, that unfortunately doesn't work, one gets linker errors and I guess it is fixable, but for begin declare target we'll need a struct anyway to store device_type etc. 2021-08-12 Jakub Jelinek * cp-tree.h (omp_declare_target_attr): New type. (struct saved_scope): Change type of omp_declare_target_attribute from int to vec * and move it. * parser.c (cp_parser_omp_declare_target): Instead of incrementing scope_chain->omp_declare_target_attribute, push a struct containing parser->lexer->in_omp_attribute_pragma to the vector. (cp_parser_omp_end_declare_target): Instead of decrementing scope_chain->omp_declare_target_attribute, pop a structure from it. Diagnose mismatching declare target vs. end declare target syntax. * semantics.c (finish_translation_unit): Use vec_safe_length and vec_safe_truncate on scope_chain->omp_declare_target_attributes. * decl2.c (cplus_decl_attributes): Use vec_safe_length on scope_chain->omp_declare_target_attributes. * g++.dg/gomp/attrs-12.C: New test. --- gcc/cp/semantics.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'gcc/cp/semantics.c') diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 34e5d76..2e23818 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -3271,12 +3271,12 @@ finish_translation_unit (void) /* Do file scope __FUNCTION__ et al. */ finish_fname_decls (); - if (scope_chain->omp_declare_target_attribute) + if (vec_safe_length (scope_chain->omp_declare_target_attribute)) { if (!errorcount) error ("%<#pragma omp declare target%> without corresponding " "%<#pragma omp end declare target%>"); - scope_chain->omp_declare_target_attribute = 0; + vec_safe_truncate (scope_chain->omp_declare_target_attribute, 0); } } -- cgit v1.1 From d0befed793b94f3f407be44e6f69f81a02f5f073 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 12 Aug 2021 22:41:17 +0200 Subject: openmp: Add support for OpenMP 5.1 masked construct This construct has been introduced as a replacement for master construct, but unlike that construct is slightly more general, has an optional clause which allows to choose which thread will be the one running the region, it can be some other thread than the master (primary) thread with number 0, or it could be no threads or multiple threads (then of course one needs to be careful about data races). It is way too early to deprecate the master construct though, we don't even have OpenMP 5.0 fully implemented, it has been deprecated in 5.1, will be also in 5.2 and removed in 6.0. But even then it will likely be a good idea to just -Wdeprecated warn about it and still accept it. The patch also contains something I should have done much earlier, for clauses that accept some integral expression where we only care about the value, forces during gimplification that value into either a min invariant (as before), SSA_NAME or a fresh temporary, but never e.g. a user VAR_DECL, so that for those clauses we don't need to worry about adjusting it. 2021-08-12 Jakub Jelinek gcc/ * tree.def (OMP_MASKED): New tree code. * tree-core.h (enum omp_clause_code): Add OMP_CLAUSE_FILTER. * tree.h (OMP_MASKED_BODY, OMP_MASKED_CLAUSES, OMP_MASKED_COMBINED, OMP_CLAUSE_FILTER_EXPR): Define. * tree.c (omp_clause_num_ops): Add OMP_CLAUSE_FILTER entry. (omp_clause_code_name): Likewise. (walk_tree_1): Handle OMP_CLAUSE_FILTER. * tree-nested.c (convert_nonlocal_omp_clauses, convert_local_omp_clauses): Handle OMP_CLAUSE_FILTER. (convert_nonlocal_reference_stmt, convert_local_reference_stmt, convert_gimple_call): Handle GIMPLE_OMP_MASTER. * tree-pretty-print.c (dump_omp_clause): Handle OMP_CLAUSE_FILTER. (dump_generic_node): Handle OMP_MASTER. * gimple.def (GIMPLE_OMP_MASKED): New gimple code. * gimple.c (gimple_build_omp_masked): New function. (gimple_copy): Handle GIMPLE_OMP_MASKED. * gimple.h (gimple_build_omp_masked): Declare. (gimple_has_substatements): Handle GIMPLE_OMP_MASKED. (gimple_omp_masked_clauses, gimple_omp_masked_clauses_ptr, gimple_omp_masked_set_clauses): New inline functions. (CASE_GIMPLE_OMP): Add GIMPLE_OMP_MASKED. * gimple-pretty-print.c (dump_gimple_omp_masked): New function. (pp_gimple_stmt_1): Handle GIMPLE_OMP_MASKED. * gimple-walk.c (walk_gimple_stmt): Likewise. * gimple-low.c (lower_stmt): Likewise. * gimplify.c (is_gimple_stmt): Handle OMP_MASTER. (gimplify_scan_omp_clauses): Handle OMP_CLAUSE_FILTER. For clauses that take one expression rather than decl or constant, force gimplification of that into a SSA_NAME or temporary unless min invariant. (gimplify_adjust_omp_clauses): Handle OMP_CLAUSE_FILTER. (gimplify_expr): Handle OMP_MASKED. * tree-inline.c (remap_gimple_stmt): Handle GIMPLE_OMP_MASKED. (estimate_num_insns): Likewise. * omp-low.c (scan_sharing_clauses): Handle OMP_CLAUSE_FILTER. (check_omp_nesting_restrictions): Handle GIMPLE_OMP_MASKED. Adjust diagnostics for existence of masked construct. (scan_omp_1_stmt, lower_omp_master, lower_omp_1, diagnose_sb_1, diagnose_sb_2): Handle GIMPLE_OMP_MASKED. * omp-expand.c (expand_omp_synch, expand_omp, omp_make_gimple_edges): Likewise. gcc/c-family/ * c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_MASKED. (enum pragma_omp_clause): Add PRAGMA_OMP_CLAUSE_FILTER. * c-pragma.c (omp_pragmas_simd): Add masked construct. * c-common.h (enum c_omp_clause_split): Add C_OMP_CLAUSE_SPLIT_MASKED enumerator. (c_finish_omp_masked): Declare. * c-omp.c (c_finish_omp_masked): New function. (c_omp_split_clauses): Handle combined masked constructs. gcc/c/ * c-parser.c (c_parser_omp_clause_name): Parse filter clause name. (c_parser_omp_clause_filter): New function. (c_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_FILTER. (OMP_MASKED_CLAUSE_MASK): Define. (c_parser_omp_masked): New function. (c_parser_omp_parallel): Handle parallel masked. (c_parser_omp_construct): Handle PRAGMA_OMP_MASKED. * c-typeck.c (c_finish_omp_clauses): Handle OMP_CLAUSE_FILTER. gcc/cp/ * parser.c (cp_parser_omp_clause_name): Parse filter clause name. (cp_parser_omp_clause_filter): New function. (cp_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_FILTER. (OMP_MASKED_CLAUSE_MASK): Define. (cp_parser_omp_masked): New function. (cp_parser_omp_parallel): Handle parallel masked. (cp_parser_omp_construct, cp_parser_pragma): Handle PRAGMA_OMP_MASKED. * semantics.c (finish_omp_clauses): Handle OMP_CLAUSE_FILTER. * pt.c (tsubst_omp_clauses): Likewise. (tsubst_expr): Handle OMP_MASKED. gcc/testsuite/ * c-c++-common/gomp/clauses-1.c (bar): Add tests for combined masked constructs with clauses. * c-c++-common/gomp/clauses-5.c (foo): Add testcase for filter clause. * c-c++-common/gomp/clause-dups-1.c (f1): Likewise. * c-c++-common/gomp/masked-1.c: New test. * c-c++-common/gomp/masked-2.c: New test. * c-c++-common/gomp/masked-combined-1.c: New test. * c-c++-common/gomp/masked-combined-2.c: New test. * c-c++-common/goacc/uninit-if-clause.c: Remove xfails. * g++.dg/gomp/block-11.C: New test. * g++.dg/gomp/tpl-masked-1.C: New test. * g++.dg/gomp/attrs-1.C (bar): Add tests for masked construct and combined masked constructs with clauses in attribute syntax. * g++.dg/gomp/attrs-2.C (bar): Likewise. * gcc.dg/gomp/nesting-1.c (f1, f2): Add tests for masked construct nesting. * gfortran.dg/goacc/host_data-tree.f95: Allow also SSA_NAMEs in if clause. * gfortran.dg/goacc/kernels-tree.f95: Likewise. libgomp/ * testsuite/libgomp.c-c++-common/masked-1.c: New test. --- gcc/cp/semantics.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'gcc/cp/semantics.c') diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 2e23818..0198d2d 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -8204,6 +8204,29 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) } break; + case OMP_CLAUSE_FILTER: + t = OMP_CLAUSE_FILTER_EXPR (c); + if (t == error_mark_node) + remove = true; + else if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "% expression must be integral"); + remove = true; + } + else + { + t = mark_rvalue_use (t); + if (!processing_template_decl) + { + t = maybe_constant_value (t); + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + } + OMP_CLAUSE_FILTER_EXPR (c) = t; + } + break; + case OMP_CLAUSE_IS_DEVICE_PTR: case OMP_CLAUSE_USE_DEVICE_PTR: field_ok = (ort & C_ORT_OMP_DECLARE_SIMD) == C_ORT_OMP; -- cgit v1.1 From 32c3a75390623a0470df52af13f78baddd562981 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 17 Aug 2021 21:06:39 +0200 Subject: c++: Implement P0466R5 __cpp_lib_is_layout_compatible compiler helpers [PR101539] The following patch implements __is_layout_compatible trait and __builtin_is_corresponding_member helper function for the std::is_corresponding_member template function. As the current definition of layout compatible type has various problems, which result e.g. in corresponding members in layout compatible types having different member offsets, the patch anticipates some changes to the C++ standard: 1) class or enumeral types aren't layout compatible if they have different alignment or size 2) if two members have different offsets, they can't be corresponding members ([[no_unique_address]] with empty types can change that, or alignas on the member decls) 3) in unions, bitfields can't correspond to non-unions, or bitfields can't correspond to bitfields with different widths, or members with [[no_unique_address]] can't correspond to members without that attribute __builtin_is_corresponding_member for anonymous structs (GCC extension) will recurse into the anonymous structs. For anonymous unions it will emit a sorry if it can't prove such member types can't appear in the anonymous unions or anonymous aggregates in that union, because corresponding member is defined only using common initial sequence which is only defined for std-layout non-union class types and so I have no idea what to do otherwise in that case. 2021-08-17 Jakub Jelinek PR c++/101539 gcc/c-family/ * c-common.h (enum rid): Add RID_IS_LAYOUT_COMPATIBLE. * c-common.c (c_common_reswords): Add __is_layout_compatible. gcc/cp/ * cp-tree.h (enum cp_trait_kind): Add CPTK_IS_LAYOUT_COMPATIBLE. (enum cp_built_in_function): Add CP_BUILT_IN_IS_CORRESPONDING_MEMBER. (fold_builtin_is_corresponding_member, next_common_initial_seqence, layout_compatible_type_p): Declare. * parser.c (cp_parser_primary_expression): Handle RID_IS_LAYOUT_COMPATIBLE. (cp_parser_trait_expr): Likewise. * cp-objcp-common.c (names_builtin_p): Likewise. * constraint.cc (diagnose_trait_expr): Handle CPTK_IS_LAYOUT_COMPATIBLE. * decl.c (cxx_init_decl_processing): Register __builtin_is_corresponding_member builtin. * constexpr.c (cxx_eval_builtin_function_call): Handle CP_BUILT_IN_IS_CORRESPONDING_MEMBER builtin. * semantics.c (is_corresponding_member_union, is_corresponding_member_aggr, fold_builtin_is_corresponding_member): New functions. (trait_expr_value): Handle CPTK_IS_LAYOUT_COMPATIBLE. (finish_trait_expr): Likewise. * typeck.c (next_common_initial_seqence, layout_compatible_type_p): New functions. * cp-gimplify.c (cp_gimplify_expr): Fold CP_BUILT_IN_IS_CORRESPONDING_MEMBER. (cp_fold): Likewise. * tree.c (builtin_valid_in_constant_expr_p): Handle CP_BUILT_IN_IS_CORRESPONDING_MEMBER. * cxx-pretty-print.c (pp_cxx_trait_expression): Handle CPTK_IS_LAYOUT_COMPATIBLE. * class.c (remove_zero_width_bit_fields): Remove. (layout_class_type): Don't call it. gcc/testsuite/ * g++.dg/cpp2a/is-corresponding-member1.C: New test. * g++.dg/cpp2a/is-corresponding-member2.C: New test. * g++.dg/cpp2a/is-corresponding-member3.C: New test. * g++.dg/cpp2a/is-corresponding-member4.C: New test. * g++.dg/cpp2a/is-corresponding-member5.C: New test. * g++.dg/cpp2a/is-corresponding-member6.C: New test. * g++.dg/cpp2a/is-corresponding-member7.C: New test. * g++.dg/cpp2a/is-corresponding-member8.C: New test. * g++.dg/cpp2a/is-layout-compatible1.C: New test. * g++.dg/cpp2a/is-layout-compatible2.C: New test. * g++.dg/cpp2a/is-layout-compatible3.C: New test. --- gcc/cp/semantics.c | 268 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 268 insertions(+) (limited to 'gcc/cp/semantics.c') diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 0198d2d..e191aa3 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -10693,6 +10693,258 @@ fold_builtin_is_pointer_inverconvertible_with_class (location_t loc, int nargs, build_zero_cst (TREE_TYPE (arg))); } +/* Helper function for is_corresponding_member_aggr. Return true if + MEMBERTYPE pointer-to-data-member ARG can be found in anonymous + union or structure BASETYPE. */ + +static bool +is_corresponding_member_union (tree basetype, tree membertype, tree arg) +{ + for (tree field = TYPE_FIELDS (basetype); field; field = DECL_CHAIN (field)) + if (TREE_CODE (field) != FIELD_DECL || DECL_BIT_FIELD_TYPE (field)) + continue; + else if (same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (field), + membertype)) + { + if (TREE_CODE (arg) != INTEGER_CST + || tree_int_cst_equal (arg, byte_position (field))) + return true; + } + else if (ANON_AGGR_TYPE_P (TREE_TYPE (field))) + { + tree narg = arg; + if (TREE_CODE (basetype) != UNION_TYPE + && TREE_CODE (narg) == INTEGER_CST) + narg = size_binop (MINUS_EXPR, arg, byte_position (field)); + if (is_corresponding_member_union (TREE_TYPE (field), + membertype, narg)) + return true; + } + return false; +} + +/* Helper function for fold_builtin_is_corresponding_member call. + Return boolean_false_node if MEMBERTYPE1 BASETYPE1::*ARG1 and + MEMBERTYPE2 BASETYPE2::*ARG2 aren't corresponding members, + boolean_true_node if they are corresponding members, or for + non-constant ARG2 the highest member offset for corresponding + members. */ + +static tree +is_corresponding_member_aggr (location_t loc, tree basetype1, tree membertype1, + tree arg1, tree basetype2, tree membertype2, + tree arg2) +{ + tree field1 = TYPE_FIELDS (basetype1); + tree field2 = TYPE_FIELDS (basetype2); + tree ret = boolean_false_node; + while (1) + { + bool r = next_common_initial_seqence (field1, field2); + if (field1 == NULL_TREE || field2 == NULL_TREE) + break; + if (r + && same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (field1), + membertype1) + && same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (field2), + membertype2)) + { + tree pos = byte_position (field1); + if (TREE_CODE (arg1) == INTEGER_CST + && tree_int_cst_equal (arg1, pos)) + { + if (TREE_CODE (arg2) == INTEGER_CST) + return boolean_true_node; + return pos; + } + else if (TREE_CODE (arg1) != INTEGER_CST) + ret = pos; + } + else if (ANON_AGGR_TYPE_P (TREE_TYPE (field1)) + && ANON_AGGR_TYPE_P (TREE_TYPE (field2))) + { + if ((!lookup_attribute ("no_unique_address", + DECL_ATTRIBUTES (field1))) + != !lookup_attribute ("no_unique_address", + DECL_ATTRIBUTES (field2))) + break; + if (!tree_int_cst_equal (bit_position (field1), + bit_position (field2))) + break; + bool overlap = true; + tree pos = byte_position (field1); + if (TREE_CODE (arg1) == INTEGER_CST) + { + tree off1 = fold_convert (sizetype, arg1); + tree sz1 = TYPE_SIZE_UNIT (TREE_TYPE (field1)); + if (tree_int_cst_lt (off1, pos) + || tree_int_cst_le (size_binop (PLUS_EXPR, pos, sz1), off1)) + overlap = false; + } + if (TREE_CODE (arg2) == INTEGER_CST) + { + tree off2 = fold_convert (sizetype, arg2); + tree sz2 = TYPE_SIZE_UNIT (TREE_TYPE (field2)); + if (tree_int_cst_lt (off2, pos) + || tree_int_cst_le (size_binop (PLUS_EXPR, pos, sz2), off2)) + overlap = false; + } + if (overlap + && NON_UNION_CLASS_TYPE_P (TREE_TYPE (field1)) + && NON_UNION_CLASS_TYPE_P (TREE_TYPE (field2))) + { + tree narg1 = arg1; + if (TREE_CODE (arg1) == INTEGER_CST) + narg1 = size_binop (MINUS_EXPR, + fold_convert (sizetype, arg1), pos); + tree narg2 = arg2; + if (TREE_CODE (arg2) == INTEGER_CST) + narg2 = size_binop (MINUS_EXPR, + fold_convert (sizetype, arg2), pos); + tree t1 = TREE_TYPE (field1); + tree t2 = TREE_TYPE (field2); + tree nret = is_corresponding_member_aggr (loc, t1, membertype1, + narg1, t2, membertype2, + narg2); + if (nret != boolean_false_node) + { + if (nret == boolean_true_node) + return nret; + if (TREE_CODE (arg1) == INTEGER_CST) + return size_binop (PLUS_EXPR, nret, pos); + ret = size_binop (PLUS_EXPR, nret, pos); + } + } + else if (overlap + && TREE_CODE (TREE_TYPE (field1)) == UNION_TYPE + && TREE_CODE (TREE_TYPE (field2)) == UNION_TYPE) + { + tree narg1 = arg1; + if (TREE_CODE (arg1) == INTEGER_CST) + narg1 = size_binop (MINUS_EXPR, + fold_convert (sizetype, arg1), pos); + tree narg2 = arg2; + if (TREE_CODE (arg2) == INTEGER_CST) + narg2 = size_binop (MINUS_EXPR, + fold_convert (sizetype, arg2), pos); + if (is_corresponding_member_union (TREE_TYPE (field1), + membertype1, narg1) + && is_corresponding_member_union (TREE_TYPE (field2), + membertype2, narg2)) + { + sorry_at (loc, "%<__builtin_is_corresponding_member%> " + "not well defined for anonymous unions"); + return boolean_false_node; + } + } + } + if (!r) + break; + field1 = DECL_CHAIN (field1); + field2 = DECL_CHAIN (field2); + } + return ret; +} + +/* Fold __builtin_is_corresponding_member call. */ + +tree +fold_builtin_is_corresponding_member (location_t loc, int nargs, + tree *args) +{ + /* Unless users call the builtin directly, the following 3 checks should be + ensured from std::is_corresponding_member function template. */ + if (nargs != 2) + { + error_at (loc, "%<__builtin_is_corresponding_member%> " + "needs two arguments"); + return boolean_false_node; + } + tree arg1 = args[0]; + tree arg2 = args[1]; + if (error_operand_p (arg1) || error_operand_p (arg2)) + return boolean_false_node; + if (!TYPE_PTRMEM_P (TREE_TYPE (arg1)) + || !TYPE_PTRMEM_P (TREE_TYPE (arg2))) + { + error_at (loc, "%<__builtin_is_corresponding_member%> " + "argument is not pointer to member"); + return boolean_false_node; + } + + if (!TYPE_PTRDATAMEM_P (TREE_TYPE (arg1)) + || !TYPE_PTRDATAMEM_P (TREE_TYPE (arg2))) + return boolean_false_node; + + tree membertype1 = TREE_TYPE (TREE_TYPE (arg1)); + tree basetype1 = TYPE_OFFSET_BASETYPE (TREE_TYPE (arg1)); + if (!complete_type_or_else (basetype1, NULL_TREE)) + return boolean_false_node; + + tree membertype2 = TREE_TYPE (TREE_TYPE (arg2)); + tree basetype2 = TYPE_OFFSET_BASETYPE (TREE_TYPE (arg2)); + if (!complete_type_or_else (basetype2, NULL_TREE)) + return boolean_false_node; + + if (!NON_UNION_CLASS_TYPE_P (basetype1) + || !NON_UNION_CLASS_TYPE_P (basetype2) + || !std_layout_type_p (basetype1) + || !std_layout_type_p (basetype2)) + return boolean_false_node; + + /* If the member types aren't layout compatible, then they + can't be corresponding members. */ + if (!layout_compatible_type_p (membertype1, membertype2)) + return boolean_false_node; + + if (TREE_CODE (arg1) == PTRMEM_CST) + arg1 = cplus_expand_constant (arg1); + if (TREE_CODE (arg2) == PTRMEM_CST) + arg2 = cplus_expand_constant (arg2); + + if (null_member_pointer_value_p (arg1) + || null_member_pointer_value_p (arg2)) + return boolean_false_node; + + if (TREE_CODE (arg1) == INTEGER_CST + && TREE_CODE (arg2) == INTEGER_CST + && !tree_int_cst_equal (arg1, arg2)) + return boolean_false_node; + + if (TREE_CODE (arg2) == INTEGER_CST + && TREE_CODE (arg1) != INTEGER_CST) + { + std::swap (arg1, arg2); + std::swap (membertype1, membertype2); + std::swap (basetype1, basetype2); + } + + tree ret = is_corresponding_member_aggr (loc, basetype1, membertype1, arg1, + basetype2, membertype2, arg2); + if (TREE_TYPE (ret) == boolean_type_node) + return ret; + /* If both arg1 and arg2 are INTEGER_CSTs, is_corresponding_member_aggr + already returns boolean_{true,false}_node whether those particular + members are corresponding members or not. Otherwise, if only + one of them is INTEGER_CST (canonicalized to first being INTEGER_CST + above), it returns boolean_false_node if it is certainly not a + corresponding member and otherwise we need to do a runtime check that + those two OFFSET_TYPE offsets are equal. + If neither of the operands is INTEGER_CST, is_corresponding_member_aggr + returns the largest offset at which the members would be corresponding + members, so perform arg1 <= ret && arg1 == arg2 runtime check. */ + gcc_assert (TREE_CODE (arg2) != INTEGER_CST); + if (TREE_CODE (arg1) == INTEGER_CST) + return fold_build2 (EQ_EXPR, boolean_type_node, arg1, + fold_convert (TREE_TYPE (arg1), arg2)); + ret = fold_build2 (LE_EXPR, boolean_type_node, + fold_convert (pointer_sized_int_node, arg1), + fold_convert (pointer_sized_int_node, ret)); + return fold_build2 (TRUTH_AND_EXPR, boolean_type_node, ret, + fold_build2 (EQ_EXPR, boolean_type_node, arg1, + fold_convert (TREE_TYPE (arg1), arg2))); +} + /* Actually evaluates the trait. */ static bool @@ -10783,6 +11035,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2) case CPTK_IS_FINAL: return CLASS_TYPE_P (type1) && CLASSTYPE_FINAL (type1); + case CPTK_IS_LAYOUT_COMPATIBLE: + return layout_compatible_type_p (type1, type2); + case CPTK_IS_LITERAL_TYPE: return literal_type_p (type1); @@ -10930,6 +11185,19 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2) case CPTK_IS_SAME_AS: break; + case CPTK_IS_LAYOUT_COMPATIBLE: + if (!array_of_unknown_bound_p (type1) + && TREE_CODE (type1) != VOID_TYPE + && !complete_type_or_else (type1, NULL_TREE)) + /* We already issued an error. */ + return error_mark_node; + if (!array_of_unknown_bound_p (type2) + && TREE_CODE (type2) != VOID_TYPE + && !complete_type_or_else (type2, NULL_TREE)) + /* We already issued an error. */ + return error_mark_node; + break; + default: gcc_unreachable (); } -- cgit v1.1 From 03be3cfeef7b3811acb6c4a8da2fc5c1e25d3e4c Mon Sep 17 00:00:00 2001 From: Marcel Vollweiler Date: Tue, 31 Aug 2021 06:09:40 -0700 Subject: Add support for device-modifiers for 'omp target device'. 'device_num' and 'ancestor' are now parsed on target device constructs for C, C++, and Fortran (see OpenMP specification 5.0, p. 170). When 'ancestor' is used, then 'sorry, not supported' is output. Moreover, the restrictions for 'ancestor' are implemented (see OpenMP specification 5.0, p. 174f). gcc/c/ChangeLog: * c-parser.c (c_parser_omp_clause_device): Parse device-modifiers 'device_num' and 'ancestor' in 'target device' clauses. gcc/cp/ChangeLog: * parser.c (cp_parser_omp_clause_device): Parse device-modifiers 'device_num' and 'ancestor' in 'target device' clauses. * semantics.c (finish_omp_clauses): Error handling. Constant device ids must evaluate to '1' if 'ancestor' is used. gcc/fortran/ChangeLog: * gfortran.h: Add variable for 'ancestor' in struct gfc_omp_clauses. * openmp.c (gfc_match_omp_clauses): Parse device-modifiers 'device_num' and 'ancestor' in 'target device' clauses. * trans-openmp.c (gfc_trans_omp_clauses): Set OMP_CLAUSE_DEVICE_ANCESTOR. gcc/ChangeLog: * gimplify.c (gimplify_scan_omp_clauses): Error handling. 'ancestor' only allowed on target constructs and only with particular other clauses. * omp-expand.c (expand_omp_target): Output of 'sorry, not supported' if 'ancestor' is used. * omp-low.c (check_omp_nesting_restrictions): Error handling. No nested OpenMP structs when 'ancestor' is used. (scan_omp_1_stmt): No usage of OpenMP runtime routines in a target region when 'ancestor' is used. * tree-pretty-print.c (dump_omp_clause): Append 'ancestor'. * tree.h (OMP_CLAUSE_DEVICE_ANCESTOR): Define macro. gcc/testsuite/ChangeLog: * c-c++-common/gomp/target-device-1.c: New test. * c-c++-common/gomp/target-device-2.c: New test. * c-c++-common/gomp/target-device-ancestor-1.c: New test. * c-c++-common/gomp/target-device-ancestor-2.c: New test. * c-c++-common/gomp/target-device-ancestor-3.c: New test. * c-c++-common/gomp/target-device-ancestor-4.c: New test. * gfortran.dg/gomp/target-device-1.f90: New test. * gfortran.dg/gomp/target-device-2.f90: New test. * gfortran.dg/gomp/target-device-ancestor-1.f90: New test. * gfortran.dg/gomp/target-device-ancestor-2.f90: New test. * gfortran.dg/gomp/target-device-ancestor-3.f90: New test. * gfortran.dg/gomp/target-device-ancestor-4.f90: New test. --- gcc/cp/semantics.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'gcc/cp/semantics.c') diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index e191aa3..f4b042f 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -7334,6 +7334,15 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) "% id must be integral"); remove = true; } + else if (OMP_CLAUSE_DEVICE_ANCESTOR (c) + && TREE_CODE (t) == INTEGER_CST + && !integer_onep (t)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "the % clause expression must evaluate to " + "%<1%>"); + remove = true; + } else { t = mark_rvalue_use (t); -- cgit v1.1 From ba1cc6956b956eb5b92c45af79a8b1fe426ec4d3 Mon Sep 17 00:00:00 2001 From: Marcel Vollweiler Date: Tue, 7 Sep 2021 03:46:28 -0700 Subject: C, C++, Fortran, OpenMP: Add support for 'flush seq_cst' construct. This patch adds support for the 'seq_cst' memory order clause on the 'flush' directive which was introduced in OpenMP 5.1. gcc/c-family/ChangeLog: * c-omp.c (c_finish_omp_flush): Handle MEMMODEL_SEQ_CST. gcc/c/ChangeLog: * c-parser.c (c_parser_omp_flush): Parse 'seq_cst' clause on 'flush' directive. gcc/cp/ChangeLog: * parser.c (cp_parser_omp_flush): Parse 'seq_cst' clause on 'flush' directive. * semantics.c (finish_omp_flush): Handle MEMMODEL_SEQ_CST. gcc/fortran/ChangeLog: * openmp.c (gfc_match_omp_flush): Parse 'seq_cst' clause on 'flush' directive. * trans-openmp.c (gfc_trans_omp_flush): Handle OMP_MEMORDER_SEQ_CST. gcc/testsuite/ChangeLog: * c-c++-common/gomp/flush-1.c: Add test case for 'seq_cst'. * c-c++-common/gomp/flush-2.c: Add test case for 'seq_cst'. * g++.dg/gomp/attrs-1.C: Adapt test to handle all flush clauses. * g++.dg/gomp/attrs-2.C: Adapt test to handle all flush clauses. * gfortran.dg/gomp/flush-1.f90: Add test case for 'seq_cst'. * gfortran.dg/gomp/flush-2.f90: Add test case for 'seq_cst'. --- gcc/cp/semantics.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/cp/semantics.c') diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index f4b042f..8b78e89 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -10039,7 +10039,7 @@ finish_omp_flush (int mo) { tree fn = builtin_decl_explicit (BUILT_IN_SYNC_SYNCHRONIZE); releasing_vec vec; - if (mo != MEMMODEL_LAST) + if (mo != MEMMODEL_LAST && mo != MEMMODEL_SEQ_CST) { fn = builtin_decl_explicit (BUILT_IN_ATOMIC_THREAD_FENCE); vec->quick_push (build_int_cst (integer_type_node, mo)); -- cgit v1.1 From 716a5836928ee6d8fb884d9a2fbc1b1386ec8994 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Wed, 8 Sep 2021 10:39:27 +0200 Subject: c++/102228 - make lookup_anon_field O(1) For the testcase in PR101555 lookup_anon_field takes the majority of parsing time followed by get_class_binding_direct/fields_linear_search which is PR83309. The situation with anon aggregates is particularly dire when we need to build accesses to their members and the anon aggregates are nested. There for each such access we recursively build sub-accesses to the anon aggregate FIELD_DECLs bottom-up, DFS searching for them. That's inefficient since as I believe there's a 1:1 relationship between anon aggregate types and the FIELD_DECL used to place them. The patch below does away with the search in lookup_anon_field and instead records the single FIELD_DECL in the anon aggregate types lang-specific data, re-using the RTTI typeinfo_var field. That speeds up the compile of the testcase with -fsyntax-only from about 4.5s to slightly less than 1s. I tried to poke holes into the 1:1 relationship idea with my C++ knowledge but failed (which might not say much). It also leaves a hole for the case when the C++ FE itself duplicates such type and places it at a semantically different position. I've tried to poke holes into it with the duplication mechanism I understand (templates) but failed. 2021-09-08 Richard Biener PR c++/102228 gcc/cp/ * cp-tree.h (ANON_AGGR_TYPE_FIELD): New define. * decl.c (fixup_anonymous_aggr): Wipe RTTI info put in place on invalid code. * decl2.c (reset_type_linkage): Guard CLASSTYPE_TYPEINFO_VAR access. * module.cc (trees_in::read_class_def): Likewise. Reconstruct ANON_AGGR_TYPE_FIELD. * semantics.c (finish_member_declaration): Populate ANON_AGGR_TYPE_FIELD for anon aggregate typed members. * typeck.c (lookup_anon_field): Remove DFS search and return ANON_AGGR_TYPE_FIELD directly. --- gcc/cp/semantics.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'gcc/cp/semantics.c') diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 8b78e89..4b7f4ac 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -3489,6 +3489,14 @@ finish_member_declaration (tree decl) if (TREE_CODE (decl) != CONST_DECL) DECL_CONTEXT (decl) = current_class_type; + /* Remember the single FIELD_DECL an anonymous aggregate type is used for. */ + if (TREE_CODE (decl) == FIELD_DECL + && ANON_AGGR_TYPE_P (TREE_TYPE (decl))) + { + gcc_assert (!ANON_AGGR_TYPE_FIELD (TYPE_MAIN_VARIANT (TREE_TYPE (decl)))); + ANON_AGGR_TYPE_FIELD (TYPE_MAIN_VARIANT (TREE_TYPE (decl))) = decl; + } + if (TREE_CODE (decl) == USING_DECL) /* For now, ignore class-scope USING_DECLS, so that debugging backends do not see them. */ -- cgit v1.1 From 8122fbff770bcff183a9c3c72e8092c0ca32150b Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 10 Sep 2021 20:41:33 +0200 Subject: openmp: Implement OpenMP 5.1 atomics, so far for C only This patch implements OpenMP 5.1 atomics (with clarifications from upcoming 5.2). The most important changes are that it is now possible to write (for C/C++, for Fortran it was possible before already) min/max atomics and more importantly compare and exchange in various forms. Also, acq_rel is now allowed on read/write and acq_rel/acquire are allowed on update, and there are new compare, weak and fail clauses. 2021-09-10 Jakub Jelinek gcc/ * tree-core.h (enum omp_memory_order): Add OMP_MEMORY_ORDER_MASK, OMP_FAIL_MEMORY_ORDER_UNSPECIFIED, OMP_FAIL_MEMORY_ORDER_RELAXED, OMP_FAIL_MEMORY_ORDER_ACQUIRE, OMP_FAIL_MEMORY_ORDER_RELEASE, OMP_FAIL_MEMORY_ORDER_ACQ_REL, OMP_FAIL_MEMORY_ORDER_SEQ_CST and OMP_FAIL_MEMORY_ORDER_MASK enumerators. (OMP_FAIL_MEMORY_ORDER_SHIFT): Define. * gimple-pretty-print.c (dump_gimple_omp_atomic_load, dump_gimple_omp_atomic_store): Print [weak] for weak atomic load/store. * gimple.h (enum gf_mask): Change GF_OMP_ATOMIC_MEMORY_ORDER to 6-bit mask, adjust GF_OMP_ATOMIC_NEED_VALUE value and add GF_OMP_ATOMIC_WEAK. (gimple_omp_atomic_weak_p, gimple_omp_atomic_set_weak): New inline functions. * tree.h (OMP_ATOMIC_WEAK): Define. * tree-pretty-print.c (dump_omp_atomic_memory_order): Adjust for fail memory order being encoded in the same enum and also print fail clause if present. (dump_generic_node): Print weak clause if OMP_ATOMIC_WEAK. * gimplify.c (goa_stabilize_expr): Add target_expr and rhs arguments, handle pre_p == NULL case as a test mode that only returns value but doesn't change gimplify nor change anything otherwise, adjust recursive calls, add MODIFY_EXPR, ADDR_EXPR, COND_EXPR, TARGET_EXPR and CALL_EXPR handling, adjust COMPOUND_EXPR handling for __builtin_clear_padding calls, for !rhs gimplify as lvalue rather than rvalue. (gimplify_omp_atomic): Adjust goa_stabilize_expr caller. Handle COND_EXPR rhs. Set weak flag on gimple load/store for OMP_ATOMIC_WEAK. * omp-expand.c (omp_memory_order_to_fail_memmodel): New function. (omp_memory_order_to_memmodel): Adjust for fail clause encoded in the same enum. (expand_omp_atomic_cas): New function. (expand_omp_atomic_pipeline): Use omp_memory_order_to_fail_memmodel function. (expand_omp_atomic): Attempt to optimize atomic compare and exchange using expand_omp_atomic_cas. gcc/c-family/ * c-common.h (c_finish_omp_atomic): Add r and weak arguments. * c-omp.c: Include gimple-fold.h. (c_finish_omp_atomic): Add r and weak arguments. Add support for OpenMP 5.1 atomics. gcc/c/ * c-parser.c (c_parser_conditional_expression): If omp_atomic_lhs and cond.value is >, < or == with omp_atomic_lhs as one of the operands, don't call build_conditional_expr, instead build a COND_EXPR directly. (c_parser_binary_expression): Avoid calling parser_build_binary_op if omp_atomic_lhs even in more cases for >, < or ==. (c_parser_omp_atomic): Update function comment for OpenMP 5.1 atomics, parse OpenMP 5.1 atomics and fail, compare and weak clauses, allow acq_rel on atomic read/write and acq_rel/acquire clauses on update. * c-typeck.c (build_binary_op): For flag_openmp only handle MIN_EXPR/MAX_EXPR. gcc/cp/ * parser.c (cp_parser_omp_atomic): Allow acq_rel on atomic read/write and acq_rel/acquire clauses on update. * semantics.c (finish_omp_atomic): Adjust c_finish_omp_atomic caller. gcc/testsuite/ * c-c++-common/gomp/atomic-17.c (foo): Add tests for atomic read, write or update with acq_rel clause and atomic update with acquire clause. * c-c++-common/gomp/atomic-18.c (foo): Adjust expected diagnostics wording, remove tests moved to atomic-17.c. * c-c++-common/gomp/atomic-21.c: Expect only 2 omp atomic release and 2 omp atomic acq_rel directives instead of 4 omp atomic release. * c-c++-common/gomp/atomic-25.c: New test. * c-c++-common/gomp/atomic-26.c: New test. * c-c++-common/gomp/atomic-27.c: New test. * c-c++-common/gomp/atomic-28.c: New test. * c-c++-common/gomp/atomic-29.c: New test. * c-c++-common/gomp/atomic-30.c: New test. * c-c++-common/goacc-gomp/atomic.c: Expect 1 omp atomic release and 1 omp atomic_acq_rel instead of 2 omp atomic release directives. * gcc.dg/gomp/atomic-5.c: Adjust expected error diagnostic wording. * g++.dg/gomp/atomic-18.C:Expect 4 omp atomic release and 1 omp atomic_acq_rel instead of 5 omp atomic release directives. libgomp/ * testsuite/libgomp.c-c++-common/atomic-19.c: New test. * testsuite/libgomp.c-c++-common/atomic-20.c: New test. * testsuite/libgomp.c-c++-common/atomic-21.c: New test. --- gcc/cp/semantics.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/cp/semantics.c') diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 4b7f4ac..94e6b18 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -9956,7 +9956,7 @@ finish_omp_atomic (location_t loc, enum tree_code code, enum tree_code opcode, return; } stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, - v, lhs1, rhs1, swapped, mo, + v, lhs1, rhs1, NULL_TREE, swapped, mo, false, processing_template_decl != 0); if (stmt == error_mark_node) return; -- cgit v1.1